diff --git a/proto/api/v1/workspace_service.proto b/proto/api/v1/workspace_service.proto
index f9141ffa1..012bc5077 100644
--- a/proto/api/v1/workspace_service.proto
+++ b/proto/api/v1/workspace_service.proto
@@ -72,25 +72,28 @@ message WorkspaceSetting {
}
message WorkspaceGeneralSetting {
+ // theme is the name of the selected theme.
+ // This references a CSS file in the web/public/themes/ directory.
+ string theme = 1;
// disallow_user_registration disallows user registration.
- bool disallow_user_registration = 1;
+ bool disallow_user_registration = 2;
// disallow_password_auth disallows password authentication.
- bool disallow_password_auth = 2;
+ bool disallow_password_auth = 3;
// additional_script is the additional script.
- string additional_script = 3;
+ string additional_script = 4;
// additional_style is the additional style.
- string additional_style = 4;
+ string additional_style = 5;
// custom_profile is the custom profile.
- WorkspaceCustomProfile custom_profile = 5;
+ WorkspaceCustomProfile custom_profile = 6;
// week_start_day_offset is the week start day offset from Sunday.
// 0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday
// Default is Sunday.
- int32 week_start_day_offset = 6;
+ int32 week_start_day_offset = 7;
// disallow_change_username disallows changing username.
- bool disallow_change_username = 7;
+ bool disallow_change_username = 8;
// disallow_change_nickname disallows changing nickname.
- bool disallow_change_nickname = 8;
+ bool disallow_change_nickname = 9;
}
message WorkspaceCustomProfile {
diff --git a/proto/gen/api/v1/workspace_service.pb.go b/proto/gen/api/v1/workspace_service.pb.go
index 69530c857..96c5084f3 100644
--- a/proto/gen/api/v1/workspace_service.pb.go
+++ b/proto/gen/api/v1/workspace_service.pb.go
@@ -300,24 +300,27 @@ func (*WorkspaceSetting_MemoRelatedSetting) isWorkspaceSetting_Value() {}
type WorkspaceGeneralSetting struct {
state protoimpl.MessageState `protogen:"open.v1"`
+ // theme is the name of the selected theme.
+ // This references a CSS file in the web/public/themes/ directory.
+ Theme string `protobuf:"bytes,1,opt,name=theme,proto3" json:"theme,omitempty"`
// disallow_user_registration disallows user registration.
- DisallowUserRegistration bool `protobuf:"varint,1,opt,name=disallow_user_registration,json=disallowUserRegistration,proto3" json:"disallow_user_registration,omitempty"`
+ DisallowUserRegistration bool `protobuf:"varint,2,opt,name=disallow_user_registration,json=disallowUserRegistration,proto3" json:"disallow_user_registration,omitempty"`
// disallow_password_auth disallows password authentication.
- DisallowPasswordAuth bool `protobuf:"varint,2,opt,name=disallow_password_auth,json=disallowPasswordAuth,proto3" json:"disallow_password_auth,omitempty"`
+ DisallowPasswordAuth bool `protobuf:"varint,3,opt,name=disallow_password_auth,json=disallowPasswordAuth,proto3" json:"disallow_password_auth,omitempty"`
// additional_script is the additional script.
- AdditionalScript string `protobuf:"bytes,3,opt,name=additional_script,json=additionalScript,proto3" json:"additional_script,omitempty"`
+ AdditionalScript string `protobuf:"bytes,4,opt,name=additional_script,json=additionalScript,proto3" json:"additional_script,omitempty"`
// additional_style is the additional style.
- AdditionalStyle string `protobuf:"bytes,4,opt,name=additional_style,json=additionalStyle,proto3" json:"additional_style,omitempty"`
+ AdditionalStyle string `protobuf:"bytes,5,opt,name=additional_style,json=additionalStyle,proto3" json:"additional_style,omitempty"`
// custom_profile is the custom profile.
- CustomProfile *WorkspaceCustomProfile `protobuf:"bytes,5,opt,name=custom_profile,json=customProfile,proto3" json:"custom_profile,omitempty"`
+ CustomProfile *WorkspaceCustomProfile `protobuf:"bytes,6,opt,name=custom_profile,json=customProfile,proto3" json:"custom_profile,omitempty"`
// week_start_day_offset is the week start day offset from Sunday.
// 0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday
// Default is Sunday.
- WeekStartDayOffset int32 `protobuf:"varint,6,opt,name=week_start_day_offset,json=weekStartDayOffset,proto3" json:"week_start_day_offset,omitempty"`
+ WeekStartDayOffset int32 `protobuf:"varint,7,opt,name=week_start_day_offset,json=weekStartDayOffset,proto3" json:"week_start_day_offset,omitempty"`
// disallow_change_username disallows changing username.
- DisallowChangeUsername bool `protobuf:"varint,7,opt,name=disallow_change_username,json=disallowChangeUsername,proto3" json:"disallow_change_username,omitempty"`
+ DisallowChangeUsername bool `protobuf:"varint,8,opt,name=disallow_change_username,json=disallowChangeUsername,proto3" json:"disallow_change_username,omitempty"`
// disallow_change_nickname disallows changing nickname.
- DisallowChangeNickname bool `protobuf:"varint,8,opt,name=disallow_change_nickname,json=disallowChangeNickname,proto3" json:"disallow_change_nickname,omitempty"`
+ DisallowChangeNickname bool `protobuf:"varint,9,opt,name=disallow_change_nickname,json=disallowChangeNickname,proto3" json:"disallow_change_nickname,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -352,6 +355,13 @@ func (*WorkspaceGeneralSetting) Descriptor() ([]byte, []int) {
return file_api_v1_workspace_service_proto_rawDescGZIP(), []int{3}
}
+func (x *WorkspaceGeneralSetting) GetTheme() string {
+ if x != nil {
+ return x.Theme
+ }
+ return ""
+}
+
func (x *WorkspaceGeneralSetting) GetDisallowUserRegistration() bool {
if x != nil {
return x.DisallowUserRegistration
@@ -887,16 +897,17 @@ const file_api_v1_workspace_service_proto_rawDesc = "" +
"\x0fstorage_setting\x18\x03 \x01(\v2%.memos.api.v1.WorkspaceStorageSettingH\x00R\x0estorageSetting\x12]\n" +
"\x14memo_related_setting\x18\x04 \x01(\v2).memos.api.v1.WorkspaceMemoRelatedSettingH\x00R\x12memoRelatedSetting:f\xeaAc\n" +
"\x1eapi.memos.dev/WorkspaceSetting\x12\x1cworkspace/settings/{setting}*\x11workspaceSettings2\x10workspaceSettingB\a\n" +
- "\x05value\"\xd9\x03\n" +
- "\x17WorkspaceGeneralSetting\x12<\n" +
- "\x1adisallow_user_registration\x18\x01 \x01(\bR\x18disallowUserRegistration\x124\n" +
- "\x16disallow_password_auth\x18\x02 \x01(\bR\x14disallowPasswordAuth\x12+\n" +
- "\x11additional_script\x18\x03 \x01(\tR\x10additionalScript\x12)\n" +
- "\x10additional_style\x18\x04 \x01(\tR\x0fadditionalStyle\x12K\n" +
- "\x0ecustom_profile\x18\x05 \x01(\v2$.memos.api.v1.WorkspaceCustomProfileR\rcustomProfile\x121\n" +
- "\x15week_start_day_offset\x18\x06 \x01(\x05R\x12weekStartDayOffset\x128\n" +
- "\x18disallow_change_username\x18\a \x01(\bR\x16disallowChangeUsername\x128\n" +
- "\x18disallow_change_nickname\x18\b \x01(\bR\x16disallowChangeNickname\"\xa3\x01\n" +
+ "\x05value\"\xef\x03\n" +
+ "\x17WorkspaceGeneralSetting\x12\x14\n" +
+ "\x05theme\x18\x01 \x01(\tR\x05theme\x12<\n" +
+ "\x1adisallow_user_registration\x18\x02 \x01(\bR\x18disallowUserRegistration\x124\n" +
+ "\x16disallow_password_auth\x18\x03 \x01(\bR\x14disallowPasswordAuth\x12+\n" +
+ "\x11additional_script\x18\x04 \x01(\tR\x10additionalScript\x12)\n" +
+ "\x10additional_style\x18\x05 \x01(\tR\x0fadditionalStyle\x12K\n" +
+ "\x0ecustom_profile\x18\x06 \x01(\v2$.memos.api.v1.WorkspaceCustomProfileR\rcustomProfile\x121\n" +
+ "\x15week_start_day_offset\x18\a \x01(\x05R\x12weekStartDayOffset\x128\n" +
+ "\x18disallow_change_username\x18\b \x01(\bR\x16disallowChangeUsername\x128\n" +
+ "\x18disallow_change_nickname\x18\t \x01(\bR\x16disallowChangeNickname\"\xa3\x01\n" +
"\x16WorkspaceCustomProfile\x12\x14\n" +
"\x05title\x18\x01 \x01(\tR\x05title\x12 \n" +
"\vdescription\x18\x02 \x01(\tR\vdescription\x12\x19\n" +
diff --git a/proto/gen/apidocs.swagger.yaml b/proto/gen/apidocs.swagger.yaml
index a682accfc..2b35bab33 100644
--- a/proto/gen/apidocs.swagger.yaml
+++ b/proto/gen/apidocs.swagger.yaml
@@ -2900,6 +2900,11 @@ definitions:
apiv1WorkspaceGeneralSetting:
type: object
properties:
+ theme:
+ type: string
+ description: |-
+ theme is the name of the selected theme.
+ This references a CSS file in the web/public/themes/ directory.
disallowUserRegistration:
type: boolean
description: disallow_user_registration disallows user registration.
diff --git a/proto/gen/store/workspace_setting.pb.go b/proto/gen/store/workspace_setting.pb.go
index 9e4951ac3..ac097b341 100644
--- a/proto/gen/store/workspace_setting.pb.go
+++ b/proto/gen/store/workspace_setting.pb.go
@@ -313,24 +313,27 @@ func (x *WorkspaceBasicSetting) GetSchemaVersion() string {
type WorkspaceGeneralSetting struct {
state protoimpl.MessageState `protogen:"open.v1"`
+ // theme is the name of the selected theme.
+ // This references a CSS file in the web/public/themes/ directory.
+ Theme string `protobuf:"bytes,1,opt,name=theme,proto3" json:"theme,omitempty"`
// disallow_user_registration disallows user registration.
- DisallowUserRegistration bool `protobuf:"varint,1,opt,name=disallow_user_registration,json=disallowUserRegistration,proto3" json:"disallow_user_registration,omitempty"`
+ DisallowUserRegistration bool `protobuf:"varint,2,opt,name=disallow_user_registration,json=disallowUserRegistration,proto3" json:"disallow_user_registration,omitempty"`
// disallow_password_auth disallows password authentication.
- DisallowPasswordAuth bool `protobuf:"varint,2,opt,name=disallow_password_auth,json=disallowPasswordAuth,proto3" json:"disallow_password_auth,omitempty"`
+ DisallowPasswordAuth bool `protobuf:"varint,3,opt,name=disallow_password_auth,json=disallowPasswordAuth,proto3" json:"disallow_password_auth,omitempty"`
// additional_script is the additional script.
- AdditionalScript string `protobuf:"bytes,3,opt,name=additional_script,json=additionalScript,proto3" json:"additional_script,omitempty"`
+ AdditionalScript string `protobuf:"bytes,4,opt,name=additional_script,json=additionalScript,proto3" json:"additional_script,omitempty"`
// additional_style is the additional style.
- AdditionalStyle string `protobuf:"bytes,4,opt,name=additional_style,json=additionalStyle,proto3" json:"additional_style,omitempty"`
+ AdditionalStyle string `protobuf:"bytes,5,opt,name=additional_style,json=additionalStyle,proto3" json:"additional_style,omitempty"`
// custom_profile is the custom profile.
- CustomProfile *WorkspaceCustomProfile `protobuf:"bytes,5,opt,name=custom_profile,json=customProfile,proto3" json:"custom_profile,omitempty"`
+ CustomProfile *WorkspaceCustomProfile `protobuf:"bytes,6,opt,name=custom_profile,json=customProfile,proto3" json:"custom_profile,omitempty"`
// week_start_day_offset is the week start day offset from Sunday.
// 0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday
// Default is Sunday.
- WeekStartDayOffset int32 `protobuf:"varint,6,opt,name=week_start_day_offset,json=weekStartDayOffset,proto3" json:"week_start_day_offset,omitempty"`
+ WeekStartDayOffset int32 `protobuf:"varint,7,opt,name=week_start_day_offset,json=weekStartDayOffset,proto3" json:"week_start_day_offset,omitempty"`
// disallow_change_username disallows changing username.
- DisallowChangeUsername bool `protobuf:"varint,7,opt,name=disallow_change_username,json=disallowChangeUsername,proto3" json:"disallow_change_username,omitempty"`
+ DisallowChangeUsername bool `protobuf:"varint,8,opt,name=disallow_change_username,json=disallowChangeUsername,proto3" json:"disallow_change_username,omitempty"`
// disallow_change_nickname disallows changing nickname.
- DisallowChangeNickname bool `protobuf:"varint,8,opt,name=disallow_change_nickname,json=disallowChangeNickname,proto3" json:"disallow_change_nickname,omitempty"`
+ DisallowChangeNickname bool `protobuf:"varint,9,opt,name=disallow_change_nickname,json=disallowChangeNickname,proto3" json:"disallow_change_nickname,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -365,6 +368,13 @@ func (*WorkspaceGeneralSetting) Descriptor() ([]byte, []int) {
return file_store_workspace_setting_proto_rawDescGZIP(), []int{2}
}
+func (x *WorkspaceGeneralSetting) GetTheme() string {
+ if x != nil {
+ return x.Theme
+ }
+ return ""
+}
+
func (x *WorkspaceGeneralSetting) GetDisallowUserRegistration() bool {
if x != nil {
return x.DisallowUserRegistration
@@ -796,16 +806,17 @@ const file_store_workspace_setting_proto_rawDesc = "" +
"\x15WorkspaceBasicSetting\x12\x1d\n" +
"\n" +
"secret_key\x18\x01 \x01(\tR\tsecretKey\x12%\n" +
- "\x0eschema_version\x18\x02 \x01(\tR\rschemaVersion\"\xd8\x03\n" +
- "\x17WorkspaceGeneralSetting\x12<\n" +
- "\x1adisallow_user_registration\x18\x01 \x01(\bR\x18disallowUserRegistration\x124\n" +
- "\x16disallow_password_auth\x18\x02 \x01(\bR\x14disallowPasswordAuth\x12+\n" +
- "\x11additional_script\x18\x03 \x01(\tR\x10additionalScript\x12)\n" +
- "\x10additional_style\x18\x04 \x01(\tR\x0fadditionalStyle\x12J\n" +
- "\x0ecustom_profile\x18\x05 \x01(\v2#.memos.store.WorkspaceCustomProfileR\rcustomProfile\x121\n" +
- "\x15week_start_day_offset\x18\x06 \x01(\x05R\x12weekStartDayOffset\x128\n" +
- "\x18disallow_change_username\x18\a \x01(\bR\x16disallowChangeUsername\x128\n" +
- "\x18disallow_change_nickname\x18\b \x01(\bR\x16disallowChangeNickname\"\xa3\x01\n" +
+ "\x0eschema_version\x18\x02 \x01(\tR\rschemaVersion\"\xee\x03\n" +
+ "\x17WorkspaceGeneralSetting\x12\x14\n" +
+ "\x05theme\x18\x01 \x01(\tR\x05theme\x12<\n" +
+ "\x1adisallow_user_registration\x18\x02 \x01(\bR\x18disallowUserRegistration\x124\n" +
+ "\x16disallow_password_auth\x18\x03 \x01(\bR\x14disallowPasswordAuth\x12+\n" +
+ "\x11additional_script\x18\x04 \x01(\tR\x10additionalScript\x12)\n" +
+ "\x10additional_style\x18\x05 \x01(\tR\x0fadditionalStyle\x12J\n" +
+ "\x0ecustom_profile\x18\x06 \x01(\v2#.memos.store.WorkspaceCustomProfileR\rcustomProfile\x121\n" +
+ "\x15week_start_day_offset\x18\a \x01(\x05R\x12weekStartDayOffset\x128\n" +
+ "\x18disallow_change_username\x18\b \x01(\bR\x16disallowChangeUsername\x128\n" +
+ "\x18disallow_change_nickname\x18\t \x01(\bR\x16disallowChangeNickname\"\xa3\x01\n" +
"\x16WorkspaceCustomProfile\x12\x14\n" +
"\x05title\x18\x01 \x01(\tR\x05title\x12 \n" +
"\vdescription\x18\x02 \x01(\tR\vdescription\x12\x19\n" +
diff --git a/proto/store/workspace_setting.proto b/proto/store/workspace_setting.proto
index 9d2f3b442..73ea8fa0c 100644
--- a/proto/store/workspace_setting.proto
+++ b/proto/store/workspace_setting.proto
@@ -34,25 +34,27 @@ message WorkspaceBasicSetting {
}
message WorkspaceGeneralSetting {
+ // theme is the name of the selected theme.
+ // This references a CSS file in the web/public/themes/ directory.
+ string theme = 1;
// disallow_user_registration disallows user registration.
- bool disallow_user_registration = 1;
+ bool disallow_user_registration = 2;
// disallow_password_auth disallows password authentication.
- bool disallow_password_auth = 2;
+ bool disallow_password_auth = 3;
// additional_script is the additional script.
- string additional_script = 3;
+ string additional_script = 4;
// additional_style is the additional style.
- string additional_style = 4;
+ string additional_style = 5;
// custom_profile is the custom profile.
- WorkspaceCustomProfile custom_profile = 5;
+ WorkspaceCustomProfile custom_profile = 6;
// week_start_day_offset is the week start day offset from Sunday.
// 0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday
// Default is Sunday.
- int32 week_start_day_offset = 6;
-
+ int32 week_start_day_offset = 7;
// disallow_change_username disallows changing username.
- bool disallow_change_username = 7;
+ bool disallow_change_username = 8;
// disallow_change_nickname disallows changing nickname.
- bool disallow_change_nickname = 8;
+ bool disallow_change_nickname = 9;
}
message WorkspaceCustomProfile {
diff --git a/server/router/api/v1/workspace_service.go b/server/router/api/v1/workspace_service.go
index 614682cd7..2ca0a8d47 100644
--- a/server/router/api/v1/workspace_service.go
+++ b/server/router/api/v1/workspace_service.go
@@ -150,6 +150,7 @@ func convertWorkspaceGeneralSettingFromStore(setting *storepb.WorkspaceGeneralSe
return nil
}
generalSetting := &v1pb.WorkspaceGeneralSetting{
+ Theme: setting.Theme,
DisallowUserRegistration: setting.DisallowUserRegistration,
DisallowPasswordAuth: setting.DisallowPasswordAuth,
AdditionalScript: setting.AdditionalScript,
@@ -175,6 +176,7 @@ func convertWorkspaceGeneralSettingToStore(setting *v1pb.WorkspaceGeneralSetting
return nil
}
generalSetting := &storepb.WorkspaceGeneralSetting{
+ Theme: setting.Theme,
DisallowUserRegistration: setting.DisallowUserRegistration,
DisallowPasswordAuth: setting.DisallowPasswordAuth,
AdditionalScript: setting.AdditionalScript,
diff --git a/web/components.json b/web/components.json
index a1de0a8db..2082f482a 100644
--- a/web/components.json
+++ b/web/components.json
@@ -5,7 +5,7 @@
"tsx": true,
"tailwind": {
"config": "",
- "css": "src/style.css",
+ "css": "src/index.css",
"baseColor": "zinc",
"cssVariables": true,
"prefix": ""
diff --git a/web/src/App.tsx b/web/src/App.tsx
index 5f3547a13..0e1bf90d8 100644
--- a/web/src/App.tsx
+++ b/web/src/App.tsx
@@ -5,6 +5,7 @@ import { Outlet } from "react-router-dom";
import { getSystemColorScheme } from "./helpers/utils";
import useNavigateTo from "./hooks/useNavigateTo";
import { userStore, workspaceStore } from "./store/v2";
+import { loadTheme } from "./utils/theme";
const App = observer(() => {
const { i18n } = useTranslation();
@@ -103,6 +104,11 @@ const App = observer(() => {
});
}, [userSetting?.locale, userSetting?.appearance]);
+ // Load theme when workspace setting changes, validate API response
+ useEffect(() => {
+ loadTheme(workspaceGeneralSetting.theme);
+ }, [workspaceGeneralSetting.theme]);
+
return
{t("setting.system-section.title")}
+