diff --git a/web/src/components/Settings/PreferencesSection.tsx b/web/src/components/Settings/PreferencesSection.tsx
index f8659cade..bb9294003 100644
--- a/web/src/components/Settings/PreferencesSection.tsx
+++ b/web/src/components/Settings/PreferencesSection.tsx
@@ -8,6 +8,7 @@ import { useTranslate } from "@/utils/i18n";
import { convertVisibilityFromString, convertVisibilityToString } from "@/utils/memo";
import AppearanceSelect from "../AppearanceSelect";
import LocaleSelect from "../LocaleSelect";
+import ThemeSelector from "../ThemeSelector";
import VisibilityIcon from "../VisibilityIcon";
import WebhookSection from "./WebhookSection";
@@ -27,6 +28,10 @@ const PreferencesSection = observer(() => {
await userStore.updateUserSetting({ memoVisibility: value }, ["memo_visibility"]);
};
+ const handleThemeChange = async (theme: string) => {
+ await userStore.updateUserSetting({ theme }, ["theme"]);
+ };
+
return (
{t("common.basic")}
@@ -41,6 +46,11 @@ const PreferencesSection = observer(() => {
+
+ {t("setting.preference-section.theme")}
+
+
+
{t("setting.preference")}
diff --git a/web/src/components/UpdateCustomizedProfileDialog.tsx b/web/src/components/UpdateCustomizedProfileDialog.tsx
index 44e835955..fe0f38b2a 100644
--- a/web/src/components/UpdateCustomizedProfileDialog.tsx
+++ b/web/src/components/UpdateCustomizedProfileDialog.tsx
@@ -137,12 +137,12 @@ export function UpdateCustomizedProfileDialog({ open, onOpenChange, onSuccess }:
-
+
-
+
diff --git a/web/src/types/proto/api/v1/user_service.ts b/web/src/types/proto/api/v1/user_service.ts
index c1e923671..4ec9a0798 100644
--- a/web/src/types/proto/api/v1/user_service.ts
+++ b/web/src/types/proto/api/v1/user_service.ts
@@ -272,6 +272,12 @@ export interface UserSetting {
appearance: string;
/** The default visibility of the memo. */
memoVisibility: string;
+ /**
+ * The preferred theme of the user.
+ * This references a CSS file in the web/public/themes/ directory.
+ * If not set, the default theme will be used.
+ */
+ theme: string;
}
export interface GetUserSettingRequest {
@@ -1532,7 +1538,7 @@ export const GetUserStatsRequest: MessageFns
= {
};
function createBaseUserSetting(): UserSetting {
- return { name: "", locale: "", appearance: "", memoVisibility: "" };
+ return { name: "", locale: "", appearance: "", memoVisibility: "", theme: "" };
}
export const UserSetting: MessageFns = {
@@ -1549,6 +1555,9 @@ export const UserSetting: MessageFns = {
if (message.memoVisibility !== "") {
writer.uint32(34).string(message.memoVisibility);
}
+ if (message.theme !== "") {
+ writer.uint32(42).string(message.theme);
+ }
return writer;
},
@@ -1591,6 +1600,14 @@ export const UserSetting: MessageFns = {
message.memoVisibility = reader.string();
continue;
}
+ case 5: {
+ if (tag !== 42) {
+ break;
+ }
+
+ message.theme = reader.string();
+ continue;
+ }
}
if ((tag & 7) === 4 || tag === 0) {
break;
@@ -1609,6 +1626,7 @@ export const UserSetting: MessageFns = {
message.locale = object.locale ?? "";
message.appearance = object.appearance ?? "";
message.memoVisibility = object.memoVisibility ?? "";
+ message.theme = object.theme ?? "";
return message;
},
};