refactor: unify theme and apperance

This commit is contained in:
Johnny 2025-08-17 11:27:59 +08:00
parent 4eb5b67baf
commit e93f3cbb8b
74 changed files with 250 additions and 942 deletions

View File

@ -399,8 +399,6 @@ message UserSetting {
message GeneralSetting {
// The preferred locale of the user.
string locale = 1 [(google.api.field_behavior) = OPTIONAL];
// The preferred appearance of the user.
string appearance = 2 [(google.api.field_behavior) = OPTIONAL];
// The default visibility of the memo.
string memo_visibility = 3 [(google.api.field_behavior) = OPTIONAL];
// The preferred theme of the user.

View File

@ -112,7 +112,6 @@ message WorkspaceSetting {
string description = 2;
string logo_url = 3;
string locale = 4;
string appearance = 5;
}
}

View File

@ -2239,8 +2239,6 @@ type UserSetting_GeneralSetting struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The preferred locale of the user.
Locale string `protobuf:"bytes,1,opt,name=locale,proto3" json:"locale,omitempty"`
// The preferred appearance of the user.
Appearance string `protobuf:"bytes,2,opt,name=appearance,proto3" json:"appearance,omitempty"`
// The default visibility of the memo.
MemoVisibility string `protobuf:"bytes,3,opt,name=memo_visibility,json=memoVisibility,proto3" json:"memo_visibility,omitempty"`
// The preferred theme of the user.
@ -2288,13 +2286,6 @@ func (x *UserSetting_GeneralSetting) GetLocale() string {
return ""
}
func (x *UserSetting_GeneralSetting) GetAppearance() string {
if x != nil {
return x.Appearance
}
return ""
}
func (x *UserSetting_GeneralSetting) GetMemoVisibility() string {
if x != nil {
return x.MemoVisibility
@ -2613,18 +2604,15 @@ const file_api_v1_user_service_proto_rawDesc = "" +
"\x11memos.api.v1/UserR\x04name\"\x19\n" +
"\x17ListAllUserStatsRequest\"I\n" +
"\x18ListAllUserStatsResponse\x12-\n" +
"\x05stats\x18\x01 \x03(\v2\x17.memos.api.v1.UserStatsR\x05stats\"\xd9\a\n" +
"\x05stats\x18\x01 \x03(\v2\x17.memos.api.v1.UserStatsR\x05stats\"\xb3\a\n" +
"\vUserSetting\x12\x17\n" +
"\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12S\n" +
"\x0fgeneral_setting\x18\x02 \x01(\v2(.memos.api.v1.UserSetting.GeneralSettingH\x00R\x0egeneralSetting\x12V\n" +
"\x10sessions_setting\x18\x03 \x01(\v2).memos.api.v1.UserSetting.SessionsSettingH\x00R\x0fsessionsSetting\x12c\n" +
"\x15access_tokens_setting\x18\x04 \x01(\v2-.memos.api.v1.UserSetting.AccessTokensSettingH\x00R\x13accessTokensSetting\x12V\n" +
"\x10webhooks_setting\x18\x05 \x01(\v2).memos.api.v1.UserSetting.WebhooksSettingH\x00R\x0fwebhooksSetting\x1a\x9b\x01\n" +
"\x10webhooks_setting\x18\x05 \x01(\v2).memos.api.v1.UserSetting.WebhooksSettingH\x00R\x0fwebhooksSetting\x1av\n" +
"\x0eGeneralSetting\x12\x1b\n" +
"\x06locale\x18\x01 \x01(\tB\x03\xe0A\x01R\x06locale\x12#\n" +
"\n" +
"appearance\x18\x02 \x01(\tB\x03\xe0A\x01R\n" +
"appearance\x12,\n" +
"\x06locale\x18\x01 \x01(\tB\x03\xe0A\x01R\x06locale\x12,\n" +
"\x0fmemo_visibility\x18\x03 \x01(\tB\x03\xe0A\x01R\x0ememoVisibility\x12\x19\n" +
"\x05theme\x18\x04 \x01(\tB\x03\xe0A\x01R\x05theme\x1aH\n" +
"\x0fSessionsSetting\x125\n" +

View File

@ -777,7 +777,6 @@ type WorkspaceSetting_GeneralSetting_CustomProfile struct {
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
LogoUrl string `protobuf:"bytes,3,opt,name=logo_url,json=logoUrl,proto3" json:"logo_url,omitempty"`
Locale string `protobuf:"bytes,4,opt,name=locale,proto3" json:"locale,omitempty"`
Appearance string `protobuf:"bytes,5,opt,name=appearance,proto3" json:"appearance,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -840,13 +839,6 @@ func (x *WorkspaceSetting_GeneralSetting_CustomProfile) GetLocale() string {
return ""
}
func (x *WorkspaceSetting_GeneralSetting_CustomProfile) GetAppearance() string {
if x != nil {
return x.Appearance
}
return ""
}
// S3 configuration for cloud storage backend.
// Reference: https://developers.cloudflare.com/r2/examples/aws/aws-sdk-go/
type WorkspaceSetting_StorageSetting_S3Config struct {
@ -943,12 +935,12 @@ const file_api_v1_workspace_service_proto_rawDesc = "" +
"\aversion\x18\x02 \x01(\tR\aversion\x12\x12\n" +
"\x04mode\x18\x03 \x01(\tR\x04mode\x12!\n" +
"\finstance_url\x18\x06 \x01(\tR\vinstanceUrl\"\x1c\n" +
"\x1aGetWorkspaceProfileRequest\"\xb8\x11\n" +
"\x1aGetWorkspaceProfileRequest\"\x97\x11\n" +
"\x10WorkspaceSetting\x12\x17\n" +
"\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12X\n" +
"\x0fgeneral_setting\x18\x02 \x01(\v2-.memos.api.v1.WorkspaceSetting.GeneralSettingH\x00R\x0egeneralSetting\x12X\n" +
"\x0fstorage_setting\x18\x03 \x01(\v2-.memos.api.v1.WorkspaceSetting.StorageSettingH\x00R\x0estorageSetting\x12e\n" +
"\x14memo_related_setting\x18\x04 \x01(\v21.memos.api.v1.WorkspaceSetting.MemoRelatedSettingH\x00R\x12memoRelatedSetting\x1a\x9a\x05\n" +
"\x14memo_related_setting\x18\x04 \x01(\v21.memos.api.v1.WorkspaceSetting.MemoRelatedSettingH\x00R\x12memoRelatedSetting\x1a\xf9\x04\n" +
"\x0eGeneralSetting\x12\x14\n" +
"\x05theme\x18\x01 \x01(\tR\x05theme\x12<\n" +
"\x1adisallow_user_registration\x18\x02 \x01(\bR\x18disallowUserRegistration\x124\n" +
@ -958,15 +950,12 @@ const file_api_v1_workspace_service_proto_rawDesc = "" +
"\x0ecustom_profile\x18\x06 \x01(\v2;.memos.api.v1.WorkspaceSetting.GeneralSetting.CustomProfileR\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\x1a\x9a\x01\n" +
"\x18disallow_change_nickname\x18\t \x01(\bR\x16disallowChangeNickname\x1az\n" +
"\rCustomProfile\x12\x14\n" +
"\x05title\x18\x01 \x01(\tR\x05title\x12 \n" +
"\vdescription\x18\x02 \x01(\tR\vdescription\x12\x19\n" +
"\blogo_url\x18\x03 \x01(\tR\alogoUrl\x12\x16\n" +
"\x06locale\x18\x04 \x01(\tR\x06locale\x12\x1e\n" +
"\n" +
"appearance\x18\x05 \x01(\tR\n" +
"appearance\x1a\xbe\x04\n" +
"\x06locale\x18\x04 \x01(\tR\x06locale\x1a\xbe\x04\n" +
"\x0eStorageSetting\x12\\\n" +
"\fstorage_type\x18\x01 \x01(\x0e29.memos.api.v1.WorkspaceSetting.StorageSetting.StorageTypeR\vstorageType\x12+\n" +
"\x11filepath_template\x18\x02 \x01(\tR\x10filepathTemplate\x12/\n" +

View File

@ -2466,8 +2466,6 @@ components:
type: string
locale:
type: string
appearance:
type: string
description: Custom profile configuration for workspace branding.
GetCurrentSessionResponse:
type: object
@ -3633,9 +3631,6 @@ components:
locale:
type: string
description: The preferred locale of the user.
appearance:
type: string
description: The preferred appearance of the user.
memoVisibility:
type: string
description: The default visibility of the memo.

View File

@ -235,13 +235,11 @@ type GeneralUserSetting struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The user's locale.
Locale string `protobuf:"bytes,1,opt,name=locale,proto3" json:"locale,omitempty"`
// The user's appearance setting.
Appearance string `protobuf:"bytes,2,opt,name=appearance,proto3" json:"appearance,omitempty"`
// The user's memo visibility setting.
MemoVisibility string `protobuf:"bytes,3,opt,name=memo_visibility,json=memoVisibility,proto3" json:"memo_visibility,omitempty"`
MemoVisibility string `protobuf:"bytes,2,opt,name=memo_visibility,json=memoVisibility,proto3" json:"memo_visibility,omitempty"`
// The user's theme preference.
// This references a CSS file in the web/public/themes/ directory.
Theme string `protobuf:"bytes,4,opt,name=theme,proto3" json:"theme,omitempty"`
Theme string `protobuf:"bytes,3,opt,name=theme,proto3" json:"theme,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -283,13 +281,6 @@ func (x *GeneralUserSetting) GetLocale() string {
return ""
}
func (x *GeneralUserSetting) GetAppearance() string {
if x != nil {
return x.Appearance
}
return ""
}
func (x *GeneralUserSetting) GetMemoVisibility() string {
if x != nil {
return x.MemoVisibility
@ -832,14 +823,11 @@ const file_store_user_setting_proto_rawDesc = "" +
"\rACCESS_TOKENS\x10\x03\x12\r\n" +
"\tSHORTCUTS\x10\x04\x12\f\n" +
"\bWEBHOOKS\x10\x05B\a\n" +
"\x05value\"\x8b\x01\n" +
"\x05value\"k\n" +
"\x12GeneralUserSetting\x12\x16\n" +
"\x06locale\x18\x01 \x01(\tR\x06locale\x12\x1e\n" +
"\n" +
"appearance\x18\x02 \x01(\tR\n" +
"appearance\x12'\n" +
"\x0fmemo_visibility\x18\x03 \x01(\tR\x0ememoVisibility\x12\x14\n" +
"\x05theme\x18\x04 \x01(\tR\x05theme\"\xf3\x03\n" +
"\x06locale\x18\x01 \x01(\tR\x06locale\x12'\n" +
"\x0fmemo_visibility\x18\x02 \x01(\tR\x0ememoVisibility\x12\x14\n" +
"\x05theme\x18\x03 \x01(\tR\x05theme\"\xf3\x03\n" +
"\x13SessionsUserSetting\x12D\n" +
"\bsessions\x18\x01 \x03(\v2(.memos.store.SessionsUserSetting.SessionR\bsessions\x1a\xfd\x01\n" +
"\aSession\x12\x1d\n" +

View File

@ -437,7 +437,6 @@ type WorkspaceCustomProfile struct {
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
LogoUrl string `protobuf:"bytes,3,opt,name=logo_url,json=logoUrl,proto3" json:"logo_url,omitempty"`
Locale string `protobuf:"bytes,4,opt,name=locale,proto3" json:"locale,omitempty"`
Appearance string `protobuf:"bytes,5,opt,name=appearance,proto3" json:"appearance,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -500,13 +499,6 @@ func (x *WorkspaceCustomProfile) GetLocale() string {
return ""
}
func (x *WorkspaceCustomProfile) GetAppearance() string {
if x != nil {
return x.Appearance
}
return ""
}
type WorkspaceStorageSetting struct {
state protoimpl.MessageState `protogen:"open.v1"`
// storage_type is the storage type.
@ -807,15 +799,12 @@ const file_store_workspace_setting_proto_rawDesc = "" +
"\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" +
"\x18disallow_change_nickname\x18\t \x01(\bR\x16disallowChangeNickname\"\x83\x01\n" +
"\x16WorkspaceCustomProfile\x12\x14\n" +
"\x05title\x18\x01 \x01(\tR\x05title\x12 \n" +
"\vdescription\x18\x02 \x01(\tR\vdescription\x12\x19\n" +
"\blogo_url\x18\x03 \x01(\tR\alogoUrl\x12\x16\n" +
"\x06locale\x18\x04 \x01(\tR\x06locale\x12\x1e\n" +
"\n" +
"appearance\x18\x05 \x01(\tR\n" +
"appearance\"\xd5\x02\n" +
"\x06locale\x18\x04 \x01(\tR\x06locale\"\xd5\x02\n" +
"\x17WorkspaceStorageSetting\x12S\n" +
"\fstorage_type\x18\x01 \x01(\x0e20.memos.store.WorkspaceStorageSetting.StorageTypeR\vstorageType\x12+\n" +
"\x11filepath_template\x18\x02 \x01(\tR\x10filepathTemplate\x12/\n" +

View File

@ -36,13 +36,11 @@ message UserSetting {
message GeneralUserSetting {
// The user's locale.
string locale = 1;
// The user's appearance setting.
string appearance = 2;
// The user's memo visibility setting.
string memo_visibility = 3;
string memo_visibility = 2;
// The user's theme preference.
// This references a CSS file in the web/public/themes/ directory.
string theme = 4;
string theme = 3;
}
message SessionsUserSetting {

View File

@ -62,7 +62,6 @@ message WorkspaceCustomProfile {
string description = 2;
string logo_url = 3;
string locale = 4;
string appearance = 5;
}
message WorkspaceStorageSetting {

View File

@ -306,7 +306,6 @@ func (s *APIV1Service) DeleteUser(ctx context.Context, request *v1pb.DeleteUserR
func getDefaultUserGeneralSetting() *v1pb.UserSetting_GeneralSetting {
return &v1pb.UserSetting_GeneralSetting{
Locale: "en",
Appearance: "system",
MemoVisibility: "PRIVATE",
Theme: "",
}
@ -394,7 +393,6 @@ func (s *APIV1Service) UpdateUserSetting(ctx context.Context, request *v1pb.Upda
// Start with existing general setting values
existingGeneral := existingUserSetting.GetGeneral()
updatedGeneral := &v1pb.UserSetting_GeneralSetting{
Appearance: existingGeneral.GetAppearance(),
MemoVisibility: existingGeneral.GetMemoVisibility(),
Locale: existingGeneral.GetLocale(),
Theme: existingGeneral.GetTheme(),
@ -404,8 +402,6 @@ func (s *APIV1Service) UpdateUserSetting(ctx context.Context, request *v1pb.Upda
incomingGeneral := request.Setting.GetGeneralSetting()
for _, field := range request.UpdateMask.Paths {
switch field {
case "appearance":
updatedGeneral.Appearance = incomingGeneral.Appearance
case "memoVisibility":
updatedGeneral.MemoVisibility = incomingGeneral.MemoVisibility
case "theme":
@ -1165,7 +1161,6 @@ func convertUserSettingFromStore(storeSetting *storepb.UserSetting, userID int32
setting.Value = &v1pb.UserSetting_GeneralSetting_{
GeneralSetting: &v1pb.UserSetting_GeneralSetting{
Locale: general.Locale,
Appearance: general.Appearance,
MemoVisibility: general.MemoVisibility,
Theme: general.Theme,
},
@ -1249,7 +1244,6 @@ func convertUserSettingToStore(apiSetting *v1pb.UserSetting, userID int32, key s
storeSetting.Value = &storepb.UserSetting_General{
General: &storepb.GeneralUserSetting{
Locale: general.Locale,
Appearance: general.Appearance,
MemoVisibility: general.MemoVisibility,
Theme: general.Theme,
},

View File

@ -171,7 +171,6 @@ func convertWorkspaceGeneralSettingFromStore(setting *storepb.WorkspaceGeneralSe
Description: setting.CustomProfile.Description,
LogoUrl: setting.CustomProfile.LogoUrl,
Locale: setting.CustomProfile.Locale,
Appearance: setting.CustomProfile.Appearance,
}
}
return generalSetting
@ -197,7 +196,6 @@ func convertWorkspaceGeneralSettingToStore(setting *v1pb.WorkspaceSetting_Genera
Description: setting.CustomProfile.Description,
LogoUrl: setting.CustomProfile.LogoUrl,
Locale: setting.CustomProfile.Locale,
Appearance: setting.CustomProfile.Appearance,
}
}
return generalSetting

View File

@ -1,8 +1,7 @@
import { observer } from "mobx-react-lite";
import { useEffect, useState } from "react";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { Outlet } from "react-router-dom";
import { getSystemColorScheme } from "./helpers/utils";
import useNavigateTo from "./hooks/useNavigateTo";
import { userStore, workspaceStore } from "./store";
import { loadTheme } from "./utils/theme";
@ -10,7 +9,6 @@ import { loadTheme } from "./utils/theme";
const App = observer(() => {
const { i18n } = useTranslation();
const navigateTo = useNavigateTo();
const [mode, setMode] = useState<"light" | "dark">("light");
const workspaceProfile = workspaceStore.state.profile;
const userGeneralSetting = userStore.state.userGeneralSetting;
const workspaceGeneralSetting = workspaceStore.state.generalSetting;
@ -22,20 +20,6 @@ const App = observer(() => {
}
}, [workspaceProfile.owner]);
useEffect(() => {
const darkMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const handleColorSchemeChange = (e: MediaQueryListEvent) => {
const mode = e.matches ? "dark" : "light";
setMode(mode);
};
try {
darkMediaQuery.addEventListener("change", handleColorSchemeChange);
} catch (error) {
console.error("failed to initial color scheme listener", error);
}
}, []);
useEffect(() => {
if (workspaceGeneralSetting.additionalStyle) {
const styleEl = document.createElement("style");
@ -76,23 +60,6 @@ const App = observer(() => {
}
}, [workspaceStore.state.locale]);
useEffect(() => {
let currentAppearance = workspaceStore.state.appearance as Appearance;
if (currentAppearance === "system") {
currentAppearance = getSystemColorScheme();
}
setMode(currentAppearance);
}, [workspaceStore.state.appearance]);
useEffect(() => {
const root = document.documentElement;
if (mode === "light") {
root.classList.remove("dark");
} else if (mode === "dark") {
root.classList.add("dark");
}
}, [mode]);
useEffect(() => {
if (!userGeneralSetting) {
return;
@ -100,16 +67,17 @@ const App = observer(() => {
workspaceStore.state.setPartial({
locale: userGeneralSetting.locale || workspaceStore.state.locale,
appearance: userGeneralSetting.appearance || workspaceStore.state.appearance,
theme: userGeneralSetting.theme || workspaceStore.state.theme,
});
}, [userGeneralSetting?.locale, userGeneralSetting?.appearance]);
}, [userGeneralSetting?.locale, userGeneralSetting?.theme]);
// Load theme when user setting changes (user theme is already backfilled with workspace theme)
// Load theme when workspace theme changes or user setting changes
useEffect(() => {
if (userGeneralSetting?.theme) {
loadTheme(userGeneralSetting.theme);
const currentTheme = userGeneralSetting?.theme || workspaceStore.state.theme;
if (currentTheme) {
loadTheme(currentTheme);
}
}, [userGeneralSetting?.theme]);
}, [userGeneralSetting?.theme, workspaceStore.state.theme]);
return <Outlet />;
});

View File

@ -1,51 +0,0 @@
import { SunIcon, MoonIcon, SmileIcon } from "lucide-react";
import { FC } from "react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { useTranslate } from "@/utils/i18n";
interface Props {
value: Appearance;
onChange: (appearance: Appearance) => void;
}
const appearanceList = ["system", "light", "dark"] as const;
const AppearanceSelect: FC<Props> = (props: Props) => {
const { onChange, value } = props;
const t = useTranslate();
const getPrefixIcon = (appearance: Appearance) => {
const className = "w-4 h-auto";
if (appearance === "light") {
return <SunIcon className={className} />;
} else if (appearance === "dark") {
return <MoonIcon className={className} />;
} else {
return <SmileIcon className={className} />;
}
};
const handleSelectChange = async (appearance: Appearance) => {
onChange(appearance);
};
return (
<Select value={value} onValueChange={handleSelectChange}>
<SelectTrigger>
<SelectValue placeholder="Select appearance" />
</SelectTrigger>
<SelectContent>
{appearanceList.map((item) => (
<SelectItem key={item} value={item} className="whitespace-nowrap">
<div className="flex items-center gap-2">
{getPrefixIcon(item)}
{t(`setting.appearance-option.${item}`)}
</div>
</SelectItem>
))}
</SelectContent>
</Select>
);
};
export default AppearanceSelect;

View File

@ -1,8 +1,8 @@
import { observer } from "mobx-react-lite";
import { cn } from "@/lib/utils";
import { workspaceStore } from "@/store";
import AppearanceSelect from "./AppearanceSelect";
import LocaleSelect from "./LocaleSelect";
import ThemeSelect from "./ThemeSelect";
interface Props {
className?: string;
@ -13,14 +13,10 @@ const AuthFooter = observer(({ className }: Props) => {
workspaceStore.state.setPartial({ locale });
};
const handleAppearanceSelectChange = (appearance: Appearance) => {
workspaceStore.state.setPartial({ appearance });
};
return (
<div className={cn("mt-4 flex flex-row items-center justify-center w-full gap-2", className)}>
<LocaleSelect value={workspaceStore.state.locale} onChange={handleLocaleSelectChange} />
<AppearanceSelect value={workspaceStore.state.appearance as Appearance} onChange={handleAppearanceSelectChange} />
<ThemeSelect />
</div>
);
});

View File

@ -37,8 +37,6 @@ const CodeBlock: React.FC<Props> = ({ language, content }: Props) => {
useEffect(() => {
const dynamicImportStyle = async () => {
const isDark = document.documentElement.classList.contains("dark");
// Remove any existing highlight.js style
const existingStyle = document.querySelector("style[data-hljs-theme]");
if (existingStyle) {
@ -46,15 +44,13 @@ const CodeBlock: React.FC<Props> = ({ language, content }: Props) => {
}
try {
// Dynamically import the appropriate CSS.
const cssModule = isDark
? await import("highlight.js/styles/atom-one-dark.css?inline")
: await import("highlight.js/styles/github.css?inline");
// Always use the github light theme
const cssModule = await import("highlight.js/styles/github.css?inline");
// Create and inject the style
const style = document.createElement("style");
style.textContent = cssModule.default;
style.setAttribute("data-hljs-theme", isDark ? "dark" : "light");
style.setAttribute("data-hljs-theme", "light");
document.head.appendChild(style);
} catch (error) {
console.warn("Failed to load highlight.js theme:", error);
@ -62,15 +58,6 @@ const CodeBlock: React.FC<Props> = ({ language, content }: Props) => {
};
dynamicImportStyle();
// Watch for changes to the dark class
const observer = new MutationObserver(dynamicImportStyle);
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["class"],
});
return () => observer.disconnect();
}, []);
const highlightedCode = useMemo(() => {

View File

@ -9,9 +9,8 @@ const MermaidBlock: React.FC<Props> = ({ content }: Props) => {
useEffect(() => {
const initializeMermaid = async () => {
const isDark = document.documentElement.classList.contains("dark");
const mermaid = (await import("mermaid")).default;
mermaid.initialize({ startOnLoad: false, theme: isDark ? "dark" : "default" });
mermaid.initialize({ startOnLoad: false, theme: "default" });
if (mermaidDockBlock.current) {
mermaid.run({
nodes: [mermaidDockBlock.current],

View File

@ -18,30 +18,11 @@ const DEFAULT_NODE_COLOR = "#a1a1aa";
const MemoRelationForceGraph = ({ className, memo, parentPage }: Props) => {
const navigateTo = useNavigateTo();
const [mode, setMode] = useState<"light" | "dark">("light");
const [mode] = useState<"light">("light");
const containerRef = useRef<HTMLDivElement>(null);
const graphRef = useRef<ForceGraphMethods<NodeObject<NodeType>, LinkObject<NodeType, LinkType>> | undefined>(undefined);
const [graphSize, setGraphSize] = useState({ width: 0, height: 0 });
// Simple dark mode detection
useEffect(() => {
const updateMode = () => {
const isDark = document.documentElement.classList.contains("dark");
setMode(isDark ? "dark" : "light");
};
updateMode();
// Watch for changes to the dark class
const observer = new MutationObserver(updateMode);
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["class"],
});
return () => observer.disconnect();
}, []);
useEffect(() => {
if (!containerRef.current) return;
setGraphSize(containerRef.current.getBoundingClientRect());

View File

@ -6,9 +6,8 @@ import { Visibility } from "@/types/proto/api/v1/memo_service";
import { UserSetting_GeneralSetting } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n";
import { convertVisibilityFromString, convertVisibilityToString } from "@/utils/memo";
import AppearanceSelect from "../AppearanceSelect";
import LocaleSelect from "../LocaleSelect";
import ThemeSelector from "../ThemeSelector";
import ThemeSelect from "../ThemeSelect";
import VisibilityIcon from "../VisibilityIcon";
import WebhookSection from "./WebhookSection";
@ -20,10 +19,6 @@ const PreferencesSection = observer(() => {
await userStore.updateUserGeneralSetting({ locale }, ["locale"]);
};
const handleAppearanceSelectChange = async (appearance: Appearance) => {
await userStore.updateUserGeneralSetting({ appearance }, ["appearance"]);
};
const handleDefaultMemoVisibilityChanged = async (value: string) => {
await userStore.updateUserGeneralSetting({ memoVisibility: value }, ["memoVisibility"]);
};
@ -35,9 +30,8 @@ const PreferencesSection = observer(() => {
// Provide default values if setting is not loaded yet
const setting: UserSetting_GeneralSetting = generalSetting || {
locale: "en",
appearance: "system",
memoVisibility: "PRIVATE",
theme: "",
theme: "default",
};
return (
@ -49,14 +43,9 @@ const PreferencesSection = observer(() => {
<LocaleSelect value={setting.locale} onChange={handleLocaleSelectChange} />
</div>
<div className="w-full flex flex-row justify-between items-center">
<span>{t("setting.preference-section.apperance")}</span>
<AppearanceSelect value={setting.appearance as Appearance} onChange={handleAppearanceSelectChange} />
</div>
<div className="w-full flex flex-row justify-between items-center">
<span>{t("setting.preference-section.theme")}</span>
<ThemeSelector value={setting.theme} onValueChange={handleThemeChange} />
<ThemeSelect value={setting.theme} onValueChange={handleThemeChange} />
</div>
<p className="font-medium text-muted-foreground">{t("setting.preference")}</p>

View File

@ -16,7 +16,7 @@ import { workspaceSettingNamePrefix } from "@/store/common";
import { IdentityProvider } from "@/types/proto/api/v1/idp_service";
import { WorkspaceSetting_GeneralSetting, WorkspaceSetting_Key } from "@/types/proto/api/v1/workspace_service";
import { useTranslate } from "@/utils/i18n";
import ThemeSelector from "../ThemeSelector";
import ThemeSelect from "../ThemeSelect";
import UpdateCustomizedProfileDialog from "../UpdateCustomizedProfileDialog";
const WorkspaceSection = observer(() => {
@ -84,9 +84,9 @@ const WorkspaceSection = observer(() => {
<p className="font-medium text-foreground">{t("setting.system-section.title")}</p>
<div className="w-full flex flex-row justify-between items-center">
<span>Theme</span>
<ThemeSelector
<ThemeSelect
value={workspaceGeneralSetting.theme || "default"}
onValueChange={(value) => updatePartialSetting({ theme: value })}
onValueChange={(value: string) => updatePartialSetting({ theme: value })}
className="min-w-fit"
/>
</div>

View File

@ -0,0 +1,52 @@
import { Moon, Palette, Sun, Wallpaper } from "lucide-react";
import { Button } from "@/components/ui/button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { workspaceStore } from "@/store";
interface ThemeSelectProps {
value?: string;
onValueChange?: (theme: string) => void;
className?: string;
}
const ThemeSelect = ({ value, onValueChange, className }: ThemeSelectProps = {}) => {
const currentTheme = value || workspaceStore.state.theme || "default";
const themeOptions: { value: Theme; icon: JSX.Element; label: string }[] = [
{ value: "default", icon: <Sun className="w-4 h-4" />, label: "Default Light" },
{ value: "default-dark", icon: <Moon className="w-4 h-4" />, label: "Default Dark" },
{ value: "paper", icon: <Palette className="w-4 h-4" />, label: "Paper" },
{ value: "whitewall", icon: <Wallpaper className="w-4 h-4" />, label: "Whitewall" },
];
const handleThemeChange = (newTheme: Theme) => {
if (onValueChange) {
onValueChange(newTheme);
} else {
workspaceStore.setTheme(newTheme);
}
};
const currentThemeOption = themeOptions.find((option) => option.value === currentTheme);
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" className={`justify-start ${className || ""}`}>
{currentThemeOption?.icon}
<span className="ml-2">{currentThemeOption?.label}</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
{themeOptions.map((option) => (
<DropdownMenuItem key={option.value} onClick={() => handleThemeChange(option.value)}>
{option.icon}
<span className="ml-2">{option.label}</span>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
);
};
export default ThemeSelect;

View File

@ -1,32 +0,0 @@
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
interface ThemeSelectorProps {
value?: string;
onValueChange: (value: string) => void;
className?: string;
}
const THEMES = [
{ value: "default", label: "Default" },
{ value: "paper", label: "Paper" },
{ value: "whitewall", label: "Whitewall" },
] as const;
export const ThemeSelector = ({ value = "default", onValueChange, className }: ThemeSelectorProps) => {
return (
<Select value={value} onValueChange={onValueChange}>
<SelectTrigger className={className}>
<SelectValue />
</SelectTrigger>
<SelectContent>
{THEMES.map((theme) => (
<SelectItem key={theme.value} value={theme.value}>
{theme.label}
</SelectItem>
))}
</SelectContent>
</Select>
);
};
export default ThemeSelector;

View File

@ -9,8 +9,8 @@ import { workspaceStore } from "@/store";
import { workspaceSettingNamePrefix } from "@/store/common";
import { WorkspaceSetting_GeneralSetting_CustomProfile, WorkspaceSetting_Key } from "@/types/proto/api/v1/workspace_service";
import { useTranslate } from "@/utils/i18n";
import AppearanceSelect from "./AppearanceSelect";
import LocaleSelect from "./LocaleSelect";
import ThemeSelect from "./ThemeSelect";
interface Props {
open: boolean;
@ -58,19 +58,12 @@ function UpdateCustomizedProfileDialog({ open, onOpenChange, onSuccess }: Props)
});
};
const handleAppearanceSelectChange = (appearance: Appearance) => {
setPartialState({
appearance: appearance,
});
};
const handleRestoreButtonClick = () => {
setPartialState({
title: "Memos",
logoUrl: "/logo.webp",
description: "",
locale: "en",
appearance: "system",
});
};
@ -140,8 +133,8 @@ function UpdateCustomizedProfileDialog({ open, onOpenChange, onSuccess }: Props)
</div>
<div className="grid gap-2">
<Label>{t("setting.system-section.customize-server.appearance")}</Label>
<AppearanceSelect value={customProfile.appearance as Appearance} onChange={handleAppearanceSelectChange} />
<Label>Theme</Label>
<ThemeSelect />
</div>
</div>

View File

@ -10,7 +10,7 @@ const badgeVariants = cva(
variant: {
default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
destructive: "border-transparent bg-destructive text-destructive-foreground [a&]:hover:bg-destructive/90 dark:bg-destructive/60",
destructive: "border-transparent bg-destructive text-destructive-foreground [a&]:hover:bg-destructive/90",
outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
},
},

View File

@ -9,11 +9,10 @@ const buttonVariants = cva(
variants: {
variant: {
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90 dark:bg-destructive/60",
outline:
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-border dark:hover:bg-input/50",
destructive: "bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90",
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {

View File

@ -8,7 +8,7 @@ function Checkbox({ className, ...props }: React.ComponentProps<typeof CheckboxP
<CheckboxPrimitive.Root
data-slot="checkbox"
className={cn(
"peer border-border dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow disabled:cursor-not-allowed disabled:opacity-50",
"peer border-border data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}

View File

@ -64,7 +64,7 @@ function DropdownMenuItem({
data-inset={inset}
data-variant={variant}
className={cn(
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className,
)}
{...props}

View File

@ -7,7 +7,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
type={type}
data-slot="input"
className={cn(
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-border flex h-8 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground border-border flex h-8 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className,
)}
{...props}

View File

@ -12,7 +12,7 @@ function RadioGroupItem({ className, ...props }: React.ComponentProps<typeof Rad
<RadioGroupPrimitive.Item
data-slot="radio-group-item"
className={cn(
"border-border text-primary dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] disabled:cursor-not-allowed disabled:opacity-50",
"border-border text-primary aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}

View File

@ -28,7 +28,7 @@ function SelectTrigger({
data-slot="select-trigger"
data-size={size}
className={cn(
"border-border data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between rounded-md border bg-transparent text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-8 data-[size=default]:gap-2 data-[size=default]:px-2 data-[size=default]:py-1 data-[size=sm]:h-7 data-[size=sm]:gap-2 data-[size=sm]:px-2 data-[size=sm]:py-1 data-[size=xs]:h-6 data-[size=xs]:gap-1 data-[size=xs]:px-1 data-[size=xs]:py-0.5 data-[size=xs]:text-xs *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"border-border data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex w-fit items-center justify-between rounded-md border bg-transparent text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-8 data-[size=default]:gap-2 data-[size=default]:px-2 data-[size=default]:py-1 data-[size=sm]:h-7 data-[size=sm]:gap-2 data-[size=sm]:px-2 data-[size=sm]:py-1 data-[size=xs]:h-6 data-[size=xs]:gap-1 data-[size=xs]:px-1 data-[size=xs]:py-0.5 data-[size=xs]:text-xs *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className,
)}
{...props}

View File

@ -7,7 +7,7 @@ function Switch({ className, ...props }: React.ComponentProps<typeof SwitchPrimi
<SwitchPrimitive.Root
data-slot="switch"
className={cn(
"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all disabled:cursor-not-allowed disabled:opacity-50",
"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
@ -15,7 +15,7 @@ function Switch({ className, ...props }: React.ComponentProps<typeof SwitchPrimi
<SwitchPrimitive.Thumb
data-slot="switch-thumb"
className={cn(
"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0",
"bg-background pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0",
)}
/>
</SwitchPrimitive.Root>

View File

@ -6,7 +6,7 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
<textarea
data-slot="textarea"
className={cn(
"border-border placeholder:text-muted-foreground dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"border-border placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className,
)}
{...props}

View File

@ -2,14 +2,10 @@
@import "tw-animate-css";
@import "./themes/default.css";
@custom-variant dark (&: is(.dark *));
@theme {
--default-transition-duration: 150ms;
}
@variant dark (&:is(.dark *));
@layer base {
* {
@apply border-border outline-none ring-0;

View File

@ -279,11 +279,6 @@
"update-information": "تحديث المعلومات",
"username-note": "تستخدم لتسجيل الدخول"
},
"appearance-option": {
"dark": "دائماً داكن",
"light": "دائماً فاتح",
"system": "اتبع النظام"
},
"member": "عضو",
"member-list": "قائمة الأعضاء",
"member-section": {
@ -380,7 +375,6 @@
"additional-style-placeholder": "كود CSS إضافي",
"allow-user-signup": "السماح بتسجيل المستخدمين",
"customize-server": {
"appearance": "مظهر الخادم",
"description": "الوصف",
"icon-url": "رابط الأيقونة",
"locale": "لغة الخادم",

View File

@ -279,11 +279,6 @@
"update-information": "Actualitza la informació",
"username-note": "Utilitzat per iniciar sessió"
},
"appearance-option": {
"dark": "Sempre fosc",
"light": "Sempre clar",
"system": "Seguir el sistema"
},
"member": "Membre",
"member-list": "Llista de membres",
"member-section": {
@ -380,7 +375,6 @@
"additional-style-placeholder": "Codi CSS addicional",
"allow-user-signup": "Permet el registre d'usuaris",
"customize-server": {
"appearance": "Aparença del servidor",
"description": "Descripció",
"icon-url": "URL de la icona",
"locale": "Llengua del servidor",

View File

@ -262,11 +262,6 @@
"update-information": "Aktualizovat informace",
"username-note": "Slouží k přihlášení"
},
"appearance-option": {
"dark": "Vždy tmavý",
"light": "Vždy světlý",
"system": "Podle systému"
},
"member": "Uživatel",
"member-list": "Seznam uživatelů",
"member-section": {
@ -363,7 +358,6 @@
"additional-style-placeholder": "Vlastní rozšíření kódu CSS",
"allow-user-signup": "Povolit registraci uživatele",
"customize-server": {
"appearance": "Vzhled serveru",
"description": "Popis",
"icon-url": "URL ikony",
"locale": "Lokalizace serveru",

View File

@ -264,11 +264,6 @@
"update-information": "Informationen ändern",
"username-note": "Zum Anmelden verwendet"
},
"appearance-option": {
"dark": "Dunkel",
"light": "Hell",
"system": "System"
},
"member": "Mitglied",
"member-list": "Mitgliederliste",
"member-section": {
@ -365,7 +360,6 @@
"additional-style-placeholder": "Zusätzlicher CSS-Code",
"allow-user-signup": "Benutzerregistrierung erlauben",
"customize-server": {
"appearance": "Server-Erscheinungsbild",
"description": "Beschreibung",
"icon-url": "Icon-URL",
"locale": "Server-Sprache",

View File

@ -281,11 +281,6 @@
"update-information": "Update Information",
"username-note": "Used to sign in"
},
"appearance-option": {
"dark": "Always dark",
"light": "Always light",
"system": "Follow system"
},
"member": "Member",
"member-list": "Member list",
"member-section": {
@ -312,7 +307,6 @@
"preference-section": {
"default-memo-sort-option": "Memo display time",
"default-memo-visibility": "Default memo visibility",
"apperance": "Appearance",
"theme": "Theme"
},
"sso": "SSO",
@ -383,7 +377,6 @@
"additional-style-placeholder": "Additional CSS code",
"allow-user-signup": "Allow user signup",
"customize-server": {
"appearance": "Server Appearance",
"description": "Description",
"icon-url": "Icon URL",
"locale": "Server Locale",
@ -446,11 +439,11 @@
"rename-tip": "All your memos with this tag will be updated."
},
"tooltip": {
"link-memo": "Link Memo",
"link-memo": "Link Memo",
"markdown-menu": "Markdown",
"select-location": "Location",
"select-visibility": "Visibility",
"select-visibility": "Visibility",
"tags": "Tags",
"upload-attachment": "Upload Attachment(s)"
"upload-attachment": "Upload Attachment(s)"
}
}
}

View File

@ -275,11 +275,6 @@
"update-information": "Actualizar información",
"username-note": "Usado para iniciar sesión"
},
"appearance-option": {
"dark": "Siempre oscuro",
"light": "Siempre claro",
"system": "Seguir el sistema"
},
"member": "Miembro",
"member-list": "Lista de miembros",
"member-section": {
@ -376,7 +371,6 @@
"additional-style-placeholder": "Código CSS adicional",
"allow-user-signup": "Permitir registro de usuarios",
"customize-server": {
"appearance": "Apariencia del servidor",
"description": "Descripción",
"icon-url": "URL del icono",
"locale": "Idioma del servidor",
@ -438,4 +432,4 @@
"rename-tag": "Renombrar etiqueta",
"rename-tip": "Todos tus memos con esta etiqueta serán actualizados."
}
}
}

View File

@ -254,11 +254,6 @@
"update-information": "بروزرسانی اطلاعات",
"username-note": "برای ورود استفاده می‌شود"
},
"appearance-option": {
"dark": "همیشه تاریک",
"light": "همیشه روشن",
"system": "مطابق سیستم"
},
"member": "عضو",
"member-list": "لیست اعضا",
"member-section": {
@ -355,7 +350,6 @@
"additional-style-placeholder": "کد CSS اضافی",
"allow-user-signup": "اجازه ثبت‌نام کاربر",
"customize-server": {
"appearance": "ظاهر سرور",
"description": "توضیحات",
"icon-url": "آدرس آیکون",
"locale": "زبان سرور",

View File

@ -279,11 +279,6 @@
"update-information": "Mettre à jour les informations",
"username-note": "Utilisé pour se connecter"
},
"appearance-option": {
"dark": "Toujours sombre",
"light": "Toujours clair",
"system": "Suivre le système"
},
"member": "Membre",
"member-list": "Liste des membres",
"member-section": {
@ -380,7 +375,6 @@
"additional-style-placeholder": "Code CSS additionnel",
"allow-user-signup": "Autoriser l'inscription des utilisateurs",
"customize-server": {
"appearance": "Apparence du serveur",
"description": "Description",
"icon-url": "URL de l'icône",
"locale": "Langue du serveur",

View File

@ -280,11 +280,6 @@
"update-information": "जानकारी अपडेट करें",
"username-note": "साइन इन के लिए उपयोग किया जाता है"
},
"appearance-option": {
"dark": "हमेशा डार्क",
"light": "हमेशा लाइट",
"system": "सिस्टम के अनुसार"
},
"member": "सदस्य",
"member-list": "सदस्य सूची",
"member-section": {
@ -311,7 +306,6 @@
"preference-section": {
"default-memo-sort-option": "मेमो प्रदर्शन समय",
"default-memo-visibility": "डिफ़ॉल्ट मेमो दृश्यता",
"apperance": "रूप",
"theme": "थीम"
},
"sso": "एसएसओ",
@ -382,7 +376,6 @@
"additional-style-placeholder": "अतिरिक्त CSS कोड",
"allow-user-signup": "यूज़र साइनअप की अनुमति दें",
"customize-server": {
"appearance": "सर्वर रूप",
"description": "विवरण",
"icon-url": "आइकन URL",
"locale": "सर्वर लोकेल",

View File

@ -279,11 +279,6 @@
"update-information": "Ažuriraj informacije",
"username-note": "Koristi se za prijavu"
},
"appearance-option": {
"dark": "Uvijek tamno",
"light": "Uvijek svijetlo",
"system": "Prema sustavu"
},
"member": "Član",
"member-list": "Popis članova",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "Vrijeme prikaza memoa",
"default-memo-visibility": "Zadana vidljivost memoa",
"apperance": "Izgled",
"theme": "Tema"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "Dodatni CSS kod",
"allow-user-signup": "Dopusti registraciju korisnika",
"customize-server": {
"appearance": "Izgled servera",
"description": "Opis",
"icon-url": "URL ikone",
"locale": "Lokalizacija servera",

View File

@ -280,11 +280,6 @@
"update-information": "Információ frissítése",
"username-note": "Bejelentkezéshez használt"
},
"appearance-option": {
"dark": "Mindig sötét",
"light": "Mindig világos",
"system": "Rendszer követése"
},
"member": "Tag",
"member-list": "Taglista",
"member-section": {
@ -309,7 +304,6 @@
"preference-section": {
"default-memo-sort-option": "Jegyzet megjelenítési ideje",
"default-memo-visibility": "Jegyzetek alapértelmezett láthatósága",
"apperance": "Megjelenés",
"theme": "Téma"
},
"sso": "SSO",
@ -380,7 +374,6 @@
"additional-style-placeholder": "Egyedi CSS kód",
"allow-user-signup": "Regisztráció engedélyezése",
"customize-server": {
"appearance": "Szerver megjelenése",
"description": "Leírás",
"icon-url": "Ikon URL",
"locale": "Szerver nyelve",

View File

@ -279,11 +279,6 @@
"update-information": "Perbarui Informasi",
"username-note": "Digunakan untuk masuk"
},
"appearance-option": {
"dark": "Selalu gelap",
"light": "Selalu terang",
"system": "Ikuti sistem"
},
"member": "Anggota",
"member-list": "Daftar Anggota",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "Waktu tampil memo",
"default-memo-visibility": "Visibilitas memo default",
"apperance": "Tampilan",
"theme": "Tema"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "Kode CSS tambahan",
"allow-user-signup": "Izinkan pendaftaran pengguna",
"customize-server": {
"appearance": "Tampilan Server",
"description": "Deskripsi",
"icon-url": "URL Ikon",
"locale": "Locale Server",

View File

@ -279,11 +279,6 @@
"update-information": "Aggiorna informazioni",
"username-note": "Usato per il login"
},
"appearance-option": {
"dark": "Sempre scuro",
"light": "Sempre chiaro",
"system": "Sistema"
},
"member": "Membri",
"member-list": "Lista membri",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "Ordinamento memo predefinito",
"default-memo-visibility": "Visibilità memo predefinita",
"apperance": "Aspetto",
"theme": "Tema"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "Codice CSS aggiuntivo",
"allow-user-signup": "Consenti registrazione utente",
"customize-server": {
"appearance": "Aspetto server",
"description": "Descrizione",
"icon-url": "URL icona",
"locale": "Locale server",

View File

@ -279,11 +279,6 @@
"update-information": "プロフィールを編集",
"username-note": "ログインに使用します"
},
"appearance-option": {
"dark": "ダークモード",
"light": "ライトモード",
"system": "システム設定に従う"
},
"member": "メンバー",
"member-list": "メンバーリスト",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "メモの表示時間",
"default-memo-visibility": "公開範囲の初期設定",
"apperance": "外観",
"theme": "テーマ"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "追加CSSコード",
"allow-user-signup": "ユーザー登録を許可",
"customize-server": {
"appearance": "サーバーの外観",
"description": "説明",
"icon-url": "アイコンURL",
"locale": "サーバーのロケール",

View File

@ -279,11 +279,6 @@
"update-information": "ინფორმაციის განახლება",
"username-note": "გამოიყენება შესასვლელად"
},
"appearance-option": {
"dark": "ყოველთვის ბნელი",
"light": "ყოველთვის ნათელი",
"system": "მიჰყვეს სისტემას"
},
"member": "წევრი",
"member-list": "წევრების სია",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "მემოს ჩვენების დრო",
"default-memo-visibility": "მემოს ნაგულისხმევი ხილვადობა",
"apperance": "გარეგნობა",
"theme": "თემა"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "დამატებითი CSS კოდი",
"allow-user-signup": "მომხმარებლის რეგისტრაციის ნებართვა",
"customize-server": {
"appearance": "სერვერის გამოჩენა",
"description": "აღწერა",
"icon-url": "ხატულას URL",
"locale": "სერვერის ლოკალიზაცია",

View File

@ -279,11 +279,6 @@
"update-information": "정보 변경",
"username-note": "로그인하는 데 사용됨"
},
"appearance-option": {
"dark": "항상 다크",
"light": "항상 라이트",
"system": "시스템 따라감"
},
"member": "멤버",
"member-list": "멤버 목록",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "메모에 표시할 시각",
"default-memo-visibility": "메모 공개 범위 기본값",
"apperance": "외관",
"theme": "테마"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "추가 CSS 코드",
"allow-user-signup": "회원가입 허용",
"customize-server": {
"appearance": "서버 외관",
"description": "설명",
"icon-url": "아이콘 URL",
"locale": "서버 언어",

View File

@ -279,11 +279,6 @@
"update-information": "माहिती अपडेट करा",
"username-note": "साइन इन करण्यासाठी वापरले जाते"
},
"appearance-option": {
"dark": "नेहमी अंधार",
"light": "नेहमी प्रकाश",
"system": "प्रणालीचे अनुसरण करा"
},
"member": "सदस्य",
"member-list": "सदस्य यादी",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "मेमो प्रदर्शन वेळ",
"default-memo-visibility": "डीफॉल्ट मेमो दृश्यमानता",
"apperance": "रूप",
"theme": "थीम"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "अतिरिक्त CSS कोड",
"allow-user-signup": "वापरकर्ता साइनअपला अनुमती द्या",
"customize-server": {
"appearance": "सर्व्हरचे स्वरूप",
"description": "वर्णन",
"icon-url": "चिन्ह URL",
"locale": "सर्व्हर लोकेल",

View File

@ -279,11 +279,6 @@
"update-information": "Oppdater informasjon",
"username-note": "Brukes til innlogging"
},
"appearance-option": {
"dark": "Alltid mørkt",
"light": "Alltid lyst",
"system": "Samme som system"
},
"member": "Medlem",
"member-list": "Medlemsliste",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "Memo visningstid",
"default-memo-visibility": "Standard synlighet for memoer",
"apperance": "Utseende",
"theme": "Tema"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "Ekstra CSS-kode",
"allow-user-signup": "Tillat registrering av brukere",
"customize-server": {
"appearance": "Serverutseende",
"description": "Beskrivelse",
"icon-url": "Ikon-URL",
"locale": "Serverlokalisering",

View File

@ -279,11 +279,6 @@
"update-information": "Informatie wijzigen",
"username-note": "Gebruikt om in te loggen"
},
"appearance-option": {
"dark": "Altijd donker",
"light": "Altijd licht",
"system": "Systeem volgen"
},
"member": "Gebruiker",
"member-list": "Gebruikers",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "Memo weergavetijd",
"default-memo-visibility": "Standaard memo zichtbaarheid",
"apperance": "Uiterlijk",
"theme": "Thema"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "Optionele CSS code",
"allow-user-signup": "Registratie toestaan",
"customize-server": {
"appearance": "Serveruiterlijk",
"description": "Beschrijving",
"icon-url": "Pictogram-URL",
"locale": "Servertaal",

View File

@ -279,11 +279,6 @@
"update-information": "Zaktualizuj informacje",
"username-note": "Używane do logowania"
},
"appearance-option": {
"dark": "Zawsze ciemny",
"light": "Zawsze jasny",
"system": "Zgodnie z systemem"
},
"member": "Członek",
"member-list": "Lista członków",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "Domyślny czas wyświetlania notatek",
"default-memo-visibility": "Domyślna widoczność notatek",
"apperance": "Wygląd",
"theme": "Motyw"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "Dodatkowy kod CSS",
"allow-user-signup": "Zezwól na rejestrację użytkowników",
"customize-server": {
"appearance": "Wygląd serwera",
"description": "Opis",
"icon-url": "URL ikony",
"locale": "Język serwera",

View File

@ -279,11 +279,6 @@
"update-information": "Atualizar informações",
"username-note": "Usado para entrar"
},
"appearance-option": {
"dark": "Sempre escuro",
"light": "Sempre claro",
"system": "Seguir sistema"
},
"member": "Membro",
"member-list": "Lista de membros",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "Exibição de tempo do memo",
"default-memo-visibility": "Visibilidade padrão do memo",
"apperance": "Aparência",
"theme": "Tema"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "Código CSS adicional",
"allow-user-signup": "Permitir registro de usuário",
"customize-server": {
"appearance": "Aparência da instância",
"description": "Descrição",
"icon-url": "URL do ícone",
"locale": "Localização da instância",

View File

@ -279,11 +279,6 @@
"update-information": "Atualizar Informações",
"username-note": "Usado para iniciar sessão"
},
"appearance-option": {
"dark": "Sempre escuro",
"light": "Sempre claro",
"system": "Seguir sistema"
},
"member": "Membro",
"member-list": "Lista de membros",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "Ordenação padrão dos memos",
"default-memo-visibility": "Visibilidade padrão dos memos",
"apperance": "Aparência",
"theme": "Tema"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "Código CSS adicional",
"allow-user-signup": "Permitir registo de utilizadores",
"customize-server": {
"appearance": "Aparência do Servidor",
"description": "Descrição",
"icon-url": "URL do Ícone",
"locale": "Localização do Servidor",

View File

@ -260,11 +260,6 @@
"update-information": "Обновить информацию",
"username-note": "Используется для входа"
},
"appearance-option": {
"dark": "Тёмная",
"light": "Светлая",
"system": "Системная"
},
"member": "Пользователи",
"member-list": "Список пользователей",
"member-section": {
@ -352,7 +347,6 @@
"additional-style-placeholder": "Напишите сюда ваш CSS код",
"allow-user-signup": "Разрешить регистрацию пользователей",
"customize-server": {
"appearance": "Тема",
"description": "Описание",
"icon-url": "URL иконки",
"locale": "Локализация",

View File

@ -279,11 +279,6 @@
"update-information": "Posodobi informacije",
"username-note": "Uporablja se za prijavo"
},
"appearance-option": {
"dark": "Vedno temna",
"light": "Vedno svetla",
"system": "Sledi sistemu"
},
"member": "Uporabnik",
"member-list": "Seznam uporabnikov",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "Čas prikaza beležke",
"default-memo-visibility": "Privzeta vidnost beležke",
"apperance": "Videz",
"theme": "Tema"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "Dodatna CSS koda",
"allow-user-signup": "Omogočite kreiranje novih uporabnikov",
"customize-server": {
"appearance": "Videz strežnika",
"description": "Opis",
"icon-url": "URL ikone",
"locale": "Jezik strežnika",

View File

@ -279,11 +279,6 @@
"update-information": "Uppdatera informationen",
"username-note": "Används för att logga in"
},
"appearance-option": {
"dark": "Alltid mörk",
"light": "Alltid ljus",
"system": "Följ systemet"
},
"member": "Medlem",
"member-list": "Medlemslista",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "Anteckning visningstid",
"default-memo-visibility": "Standard synlighet för anteckningar",
"apperance": "Utseende",
"theme": "Tema"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "Ytterligare CSS kod",
"allow-user-signup": "Tillåt användarregistrering",
"customize-server": {
"appearance": "Serverutseende",
"description": "Beskrivning",
"icon-url": "Ikon-URL",
"locale": "Serverns språk",

View File

@ -279,11 +279,6 @@
"update-information": "อัปเดทข้อมูล",
"username-note": "ใช้เพื่อเข้าสู่ระบบ"
},
"appearance-option": {
"dark": "มืดอยู่เสมอ",
"light": "สว่างอยู่เสมอ",
"system": "ทำตามระบบ"
},
"member": "สมาชิก",
"member-list": "รายชื่อสมาชิก",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "เวลาแสดงบันทึกช่วยจำ",
"default-memo-visibility": "การมองเห็นบันทึกเริ่มต้น",
"apperance": "ลักษณะ",
"theme": "ธีม"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "โค้ด CSS เพิ่มเติม",
"allow-user-signup": "อนุญาตให้ผู้ใช้ลงทะเบียน",
"customize-server": {
"appearance": "ลักษณะที่ปรากฏของเซิร์ฟเวอร์",
"description": "คำอธิบาย",
"icon-url": "Icon URL",
"locale": "ตำแหน่งเซิร์ฟเวอร์",

View File

@ -279,11 +279,6 @@
"update-information": "Bilgileri Güncelle",
"username-note": "Giriş yapmak için kullanılır"
},
"appearance-option": {
"dark": "Her zaman koyu",
"light": "Her zaman açık",
"system": "Sistemi takip et"
},
"member": "Üye",
"member-list": "Üye listesi",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "Not görüntüleme zamanı",
"default-memo-visibility": "Varsayılan not görünürlüğü",
"apperance": "Görünüm",
"theme": "Tema"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "Ek CSS kodu",
"allow-user-signup": "Kullanıcı kaydına izin ver",
"customize-server": {
"appearance": "Sunucu Görünümü",
"description": "Açıklama",
"icon-url": "İkon URL'si",
"locale": "Sunucu Yerel Ayarı",

View File

@ -279,11 +279,6 @@
"update-information": "Оновити інформацію",
"username-note": "Використовується для входу"
},
"appearance-option": {
"dark": "Завжди темний",
"light": "Завжди світлий",
"system": "Слідувати системі"
},
"member": "Учасник",
"member-list": "Список учасників",
"member-section": {
@ -310,7 +305,6 @@
"preference-section": {
"default-memo-sort-option": "Час відображення нотаток",
"default-memo-visibility": "Типова видимість нотаток",
"apperance": "Зовнішній вигляд",
"theme": "Тема"
},
"sso": "SSO",
@ -381,7 +375,6 @@
"additional-style-placeholder": "Додатковий CSS код",
"allow-user-signup": "Дозволити реєстрацію користувачів",
"customize-server": {
"appearance": "Зовнішній вигляд сервера",
"description": "Опис",
"icon-url": "URL значка",
"locale": "Мова сервера",

View File

@ -206,11 +206,6 @@
"update-information": "Cập nhật thông tin",
"username-note": "Dùng để đăng nhập"
},
"appearance-option": {
"dark": "Luôn tối",
"light": "Luôn sáng",
"system": "Theo hệ thống"
},
"member": "Thành viên",
"member-list": "Danh sách thành viên",
"member-section": {
@ -303,7 +298,6 @@
"additional-style-placeholder": "Mã CSS bổ sung",
"allow-user-signup": "Cho phép đăng ký người dùng",
"customize-server": {
"appearance": "Giao diện máy chủ",
"description": "Mô tả",
"icon-url": "URL biểu tượng",
"locale": "Ngôn ngữ máy chủ",

View File

@ -280,11 +280,6 @@
"update-information": "更新个人信息",
"username-note": "用于登录"
},
"appearance-option": {
"dark": "深色",
"light": "浅色",
"system": "跟随系统"
},
"member": "成员",
"member-list": "成员列表",
"member-section": {
@ -380,7 +375,6 @@
"additional-style-placeholder": "自定义 CSS 代码",
"allow-user-signup": "允许用户注册",
"customize-server": {
"appearance": "服务器外观",
"description": "描述",
"icon-url": "图标链接",
"locale": "服务器语言环境",

View File

@ -280,11 +280,6 @@
"update-information": "更新個人資訊",
"username-note": "用於登入"
},
"appearance-option": {
"dark": "深色",
"light": "淺色",
"system": "跟隨系統"
},
"member": "使用者",
"member-list": "使用者列表",
"member-section": {
@ -311,7 +306,6 @@
"preference-section": {
"default-memo-sort-option": "備忘錄顯示時間",
"default-memo-visibility": "備忘錄預設瀏覽權限",
"apperance": "外觀",
"theme": "主題"
},
"sso": "SSO",
@ -382,7 +376,6 @@
"additional-style-placeholder": "自訂 CSS 代碼",
"allow-user-signup": "允許使用者註冊",
"customize-server": {
"appearance": "外觀",
"description": "說明",
"icon-url": "圖示網址",
"locale": "語言",
@ -444,4 +437,4 @@
"rename-tag": "重新命名標籤",
"rename-tip": "您的標籤名稱將會被更新"
}
}
}

View File

@ -313,7 +313,7 @@ export const initialUserStore = async () => {
if (generalSetting) {
workspaceStore.state.setPartial({
locale: generalSetting.locale,
appearance: generalSetting.appearance,
theme: generalSetting.theme || "default",
});
}
} catch {

View File

@ -12,7 +12,7 @@ import { workspaceSettingNamePrefix } from "./common";
class LocalState {
locale: string = "en";
appearance: string = "system";
theme: string = "default";
profile: WorkspaceProfile = WorkspaceProfile.fromPartial({});
settings: WorkspaceSetting[] = [];
@ -42,8 +42,8 @@ class LocalState {
if (!isValidateLocale(finalState.locale)) {
finalState.locale = "en";
}
if (!["system", "light", "dark"].includes(finalState.appearance)) {
finalState.appearance = "system";
if (!["default", "default-dark", "paper", "whitewall"].includes(finalState.theme)) {
finalState.theme = "default";
}
Object.assign(this, finalState);
}
@ -72,11 +72,32 @@ const workspaceStore = (() => {
);
};
const setTheme = async (theme: string) => {
state.setPartial({ theme });
// Update the workspace setting - store theme in a custom field or handle differently
const generalSetting = state.generalSetting;
const updatedGeneralSetting = WorkspaceSetting_GeneralSetting.fromPartial({
...generalSetting,
customProfile: {
...generalSetting.customProfile,
},
});
await upsertWorkspaceSetting(
WorkspaceSetting.fromPartial({
name: `${workspaceSettingNamePrefix}${WorkspaceSetting_Key.GENERAL}`,
generalSetting: updatedGeneralSetting,
}),
);
};
return {
state,
fetchWorkspaceSetting,
upsertWorkspaceSetting,
getWorkspaceSettingByKey,
setTheme,
};
})();
@ -90,7 +111,7 @@ export const initialWorkspaceStore = async () => {
const workspaceGeneralSetting = workspaceStore.state.generalSetting;
workspaceStore.state.setPartial({
locale: workspaceGeneralSetting.customProfile?.locale,
appearance: workspaceGeneralSetting.customProfile?.appearance,
theme: "default",
profile: workspaceProfile,
});
};

View File

@ -0,0 +1,103 @@
:root {
--background: oklch(0.08 0.005 270);
--foreground: oklch(0.75 0.01 270);
--card: oklch(0.08 0.005 270);
--card-foreground: oklch(0.75 0.01 270);
--popover: oklch(0.12 0.008 270);
--popover-foreground: oklch(0.7 0.01 270);
--primary: oklch(0.65 0.12 250);
--primary-foreground: oklch(0.08 0.005 270);
--secondary: oklch(0.15 0.01 270);
--secondary-foreground: oklch(0.7 0.01 270);
--muted: oklch(0.12 0.008 270);
--muted-foreground: oklch(0.6 0.01 270);
--accent: oklch(0.18 0.015 270);
--accent-foreground: oklch(0.75 0.01 270);
--destructive: oklch(0.6 0.15 25);
--destructive-foreground: oklch(1 0 0);
--border: oklch(0.35 0.02 270);
--input: oklch(0.4 0.025 270);
--ring: oklch(0.65 0.12 250);
--chart-1: oklch(0.7 0.15 30);
--chart-2: oklch(0.7 0.15 260);
--chart-3: oklch(0.6 0.12 120);
--chart-4: oklch(0.65 0.15 300);
--chart-5: oklch(0.75 0.18 60);
--sidebar: oklch(0.06 0.003 270);
--sidebar-foreground: oklch(0.75 0.01 270);
--sidebar-primary: oklch(0.65 0.12 250);
--sidebar-primary-foreground: oklch(0.08 0.005 270);
--sidebar-accent: oklch(0.18 0.015 270);
--sidebar-accent-foreground: oklch(0.75 0.01 270);
--sidebar-border: oklch(0.35 0.02 270);
--sidebar-ring: oklch(0.65 0.12 250);
--font-sans:
ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--radius: 0.5rem;
--shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
--shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
--shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1);
--shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1);
--shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1);
--shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
--tracking-normal: 0em;
--spacing: 0.25rem;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--font-sans: var(--font-sans);
--font-mono: var(--font-mono);
--font-serif: var(--font-serif);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--shadow-2xs: var(--shadow-2xs);
--shadow-xs: var(--shadow-xs);
--shadow-sm: var(--shadow-sm);
--shadow: var(--shadow);
--shadow-md: var(--shadow-md);
--shadow-lg: var(--shadow-lg);
--shadow-xl: var(--shadow-xl);
--shadow-2xl: var(--shadow-2xl);
}

View File

@ -49,55 +49,6 @@
--spacing: 0.25rem;
}
.dark {
--background: oklch(0.2679 0.0036 106.6427);
--foreground: oklch(0.8274 0.0142 93.0137);
--card: oklch(0.2679 0.0036 106.6427);
--card-foreground: oklch(0.8518 0.0054 95.0986);
--popover: oklch(0.3085 0.0035 106.6039);
--popover-foreground: oklch(0.8411 0.004 106.4781);
--primary: oklch(0.7062 0.0156 286.3);
--primary-foreground: oklch(0.2679 0.0036 106.6427);
--secondary: oklch(0.3485 0.0045 106.8);
--secondary-foreground: oklch(0.8274 0.0142 93.0137);
--muted: oklch(0.2213 0.0038 106.707);
--muted-foreground: oklch(0.5813 0.0169 99.0657);
--accent: oklch(0.3185 0.0065 106.2);
--accent-foreground: oklch(0.8274 0.0142 93.0137);
--destructive: oklch(0.55 0.015 250);
--destructive-foreground: oklch(0.95 0.005 250);
--border: oklch(0.3618 0.0101 106.8928);
--input: oklch(0.4336 0.0113 100.2195);
--ring: oklch(0.5937 0.1673 253.063);
--chart-1: oklch(0.5583 0.1276 42.9956);
--chart-2: oklch(0.6898 0.1581 290.4107);
--chart-3: oklch(0.45 0.02 245);
--chart-4: oklch(0.3074 0.0516 289.323);
--chart-5: oklch(0.5608 0.1348 42.0584);
--sidebar: oklch(0.2357 0.0024 67.7077);
--sidebar-foreground: oklch(0.8274 0.0142 93.0137);
--sidebar-primary: oklch(0.7062 0.0156 286.3);
--sidebar-primary-foreground: oklch(0.2679 0.0036 106.6427);
--sidebar-accent: oklch(0.3185 0.0045 106.8);
--sidebar-accent-foreground: oklch(0.8274 0.0142 93.0137);
--sidebar-border: oklch(0.3618 0.0101 106.8928);
--sidebar-ring: oklch(0.5937 0.1673 253.063);
--font-sans:
ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--radius: 0.5rem;
--shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
--shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
--shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1);
--shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1);
--shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1);
--shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);

View File

@ -49,55 +49,6 @@
--spacing: 0.25rem;
}
.dark {
--background: oklch(0.1608 0.0118 68.4253);
--foreground: oklch(0.8627 0.0196 82.1456);
--card: oklch(0.1608 0.0118 68.4253);
--card-foreground: oklch(0.8824 0.0157 84.5674);
--popover: oklch(0.2118 0.0137 71.2341);
--popover-foreground: oklch(0.8706 0.0176 83.8934);
--primary: oklch(0.6863 0.0392 52.3674);
--primary-foreground: oklch(0.1608 0.0118 68.4253);
--secondary: oklch(0.2745 0.0157 72.8934);
--secondary-foreground: oklch(0.8627 0.0196 82.1456);
--muted: oklch(0.1961 0.0098 69.7823);
--muted-foreground: oklch(0.6471 0.0196 78.9456);
--accent: oklch(0.2549 0.0118 70.5674);
--accent-foreground: oklch(0.8627 0.0196 82.1456);
--destructive: oklch(0.5294 0.0314 25.6734);
--destructive-foreground: oklch(0.9647 0.0078 88.2341);
--border: oklch(0.3137 0.0157 71.8928);
--input: oklch(0.3725 0.0176 73.2195);
--ring: oklch(0.6863 0.0392 52.3674);
--chart-1: oklch(0.5686 0.0549 42.7834);
--chart-2: oklch(0.6275 0.0392 85.6723);
--chart-3: oklch(0.4706 0.0196 75.2341);
--chart-4: oklch(0.3529 0.0235 71.8934);
--chart-5: oklch(0.5412 0.0431 55.8934);
--sidebar: oklch(0.1412 0.0098 66.7077);
--sidebar-foreground: oklch(0.8627 0.0196 82.1456);
--sidebar-primary: oklch(0.6863 0.0392 52.3674);
--sidebar-primary-foreground: oklch(0.1608 0.0118 68.4253);
--sidebar-accent: oklch(0.2353 0.0118 69.8934);
--sidebar-accent-foreground: oklch(0.8627 0.0196 82.1456);
--sidebar-border: oklch(0.3137 0.0157 71.8928);
--sidebar-ring: oklch(0.6863 0.0392 52.3674);
--font-sans:
ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--radius: 0.5rem;
--shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
--shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
--shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1);
--shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1);
--shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1);
--shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
@ -149,4 +100,4 @@
--shadow-lg: var(--shadow-lg);
--shadow-xl: var(--shadow-xl);
--shadow-2xl: var(--shadow-2xl);
}
}

View File

@ -49,71 +49,6 @@
--spacing: 0.25rem;
}
.dark {
--background: oklch(0.08 0.005 270);
--foreground: oklch(0.9 0.01 270);
--card: oklch(0.08 0.005 270);
--card-foreground: oklch(0.9 0.01 270);
--popover: oklch(0.12 0.008 270);
--popover-foreground: oklch(0.85 0.01 270);
--primary: oklch(0.65 0.12 250);
--primary-foreground: oklch(0.08 0.005 270);
--secondary: oklch(0.15 0.01 270);
--secondary-foreground: oklch(0.85 0.01 270);
--muted: oklch(0.12 0.008 270);
--muted-foreground: oklch(0.6 0.01 270);
--accent: oklch(0.18 0.015 270);
--accent-foreground: oklch(0.9 0.01 270);
--destructive: oklch(0.6 0.15 25);
--destructive-foreground: oklch(1 0 0);
--border: oklch(0.35 0.02 270);
--input: oklch(0.4 0.025 270);
--ring: oklch(0.65 0.12 250);
--chart-1: oklch(0.7 0.15 30);
--chart-2: oklch(0.7 0.15 260);
--chart-3: oklch(0.6 0.12 120);
--chart-4: oklch(0.65 0.15 300);
--chart-5: oklch(0.75 0.18 60);
--sidebar: oklch(0.06 0.003 270);
--sidebar-foreground: oklch(0.9 0.01 270);
--sidebar-primary: oklch(0.65 0.12 250);
--sidebar-primary-foreground: oklch(0.08 0.005 270);
--sidebar-accent: oklch(0.18 0.015 270);
--sidebar-accent-foreground: oklch(0.9 0.01 270);
--sidebar-border: oklch(0.35 0.02 270);
--sidebar-ring: oklch(0.65 0.12 250);
--font-sans:
ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--radius: 0.5rem;
--shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
--shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
--shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1);
--shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1);
--shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1);
--shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1);
--shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
}
/* Enhanced checkbox visibility for dark mode */
.dark [data-slot="checkbox"] {
border-color: oklch(0.5 0.03 270);
background-color: oklch(0.15 0.01 270);
}
.dark [data-slot="checkbox"]:hover {
border-color: oklch(0.6 0.05 270);
background-color: oklch(0.2 0.015 270);
}
.dark [data-slot="checkbox"][data-state="checked"] {
background-color: var(--primary);
border-color: var(--primary);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);

View File

@ -1 +1 @@
type Appearance = "system" | "light" | "dark";
type Theme = "default" | "default-dark" | "paper" | "whitewall";

View File

@ -319,8 +319,6 @@ export function userSetting_KeyToNumber(object: UserSetting_Key): number {
export interface UserSetting_GeneralSetting {
/** The preferred locale of the user. */
locale: string;
/** The preferred appearance of the user. */
appearance: string;
/** The default visibility of the memo. */
memoVisibility: string;
/**
@ -1720,7 +1718,7 @@ export const UserSetting: MessageFns<UserSetting> = {
};
function createBaseUserSetting_GeneralSetting(): UserSetting_GeneralSetting {
return { locale: "", appearance: "", memoVisibility: "", theme: "" };
return { locale: "", memoVisibility: "", theme: "" };
}
export const UserSetting_GeneralSetting: MessageFns<UserSetting_GeneralSetting> = {
@ -1728,9 +1726,6 @@ export const UserSetting_GeneralSetting: MessageFns<UserSetting_GeneralSetting>
if (message.locale !== "") {
writer.uint32(10).string(message.locale);
}
if (message.appearance !== "") {
writer.uint32(18).string(message.appearance);
}
if (message.memoVisibility !== "") {
writer.uint32(26).string(message.memoVisibility);
}
@ -1755,14 +1750,6 @@ export const UserSetting_GeneralSetting: MessageFns<UserSetting_GeneralSetting>
message.locale = reader.string();
continue;
}
case 2: {
if (tag !== 18) {
break;
}
message.appearance = reader.string();
continue;
}
case 3: {
if (tag !== 26) {
break;
@ -1794,7 +1781,6 @@ export const UserSetting_GeneralSetting: MessageFns<UserSetting_GeneralSetting>
fromPartial(object: DeepPartial<UserSetting_GeneralSetting>): UserSetting_GeneralSetting {
const message = createBaseUserSetting_GeneralSetting();
message.locale = object.locale ?? "";
message.appearance = object.appearance ?? "";
message.memoVisibility = object.memoVisibility ?? "";
message.theme = object.theme ?? "";
return message;

View File

@ -127,7 +127,6 @@ export interface WorkspaceSetting_GeneralSetting_CustomProfile {
description: string;
logoUrl: string;
locale: string;
appearance: string;
}
/** Storage configuration settings for workspace attachments. */
@ -611,7 +610,7 @@ export const WorkspaceSetting_GeneralSetting: MessageFns<WorkspaceSetting_Genera
};
function createBaseWorkspaceSetting_GeneralSetting_CustomProfile(): WorkspaceSetting_GeneralSetting_CustomProfile {
return { title: "", description: "", logoUrl: "", locale: "", appearance: "" };
return { title: "", description: "", logoUrl: "", locale: "" };
}
export const WorkspaceSetting_GeneralSetting_CustomProfile: MessageFns<WorkspaceSetting_GeneralSetting_CustomProfile> =
@ -632,9 +631,6 @@ export const WorkspaceSetting_GeneralSetting_CustomProfile: MessageFns<Workspace
if (message.locale !== "") {
writer.uint32(34).string(message.locale);
}
if (message.appearance !== "") {
writer.uint32(42).string(message.appearance);
}
return writer;
},
@ -677,14 +673,6 @@ export const WorkspaceSetting_GeneralSetting_CustomProfile: MessageFns<Workspace
message.locale = reader.string();
continue;
}
case 5: {
if (tag !== 42) {
break;
}
message.appearance = reader.string();
continue;
}
}
if ((tag & 7) === 4 || tag === 0) {
break;
@ -707,7 +695,6 @@ export const WorkspaceSetting_GeneralSetting_CustomProfile: MessageFns<Workspace
message.description = object.description ?? "";
message.logoUrl = object.logoUrl ?? "";
message.locale = object.locale ?? "";
message.appearance = object.appearance ?? "";
return message;
},
};

View File

@ -128,52 +128,6 @@ export function editionToNumber(object: Edition): number {
}
}
/**
* Describes the 'visibility' of a symbol with respect to the proto import
* system. Symbols can only be imported when the visibility rules do not prevent
* it (ex: local symbols cannot be imported). Visibility modifiers can only set
* on `message` and `enum` as they are the only types available to be referenced
* from other files.
*/
export enum SymbolVisibility {
VISIBILITY_UNSET = "VISIBILITY_UNSET",
VISIBILITY_LOCAL = "VISIBILITY_LOCAL",
VISIBILITY_EXPORT = "VISIBILITY_EXPORT",
UNRECOGNIZED = "UNRECOGNIZED",
}
export function symbolVisibilityFromJSON(object: any): SymbolVisibility {
switch (object) {
case 0:
case "VISIBILITY_UNSET":
return SymbolVisibility.VISIBILITY_UNSET;
case 1:
case "VISIBILITY_LOCAL":
return SymbolVisibility.VISIBILITY_LOCAL;
case 2:
case "VISIBILITY_EXPORT":
return SymbolVisibility.VISIBILITY_EXPORT;
case -1:
case "UNRECOGNIZED":
default:
return SymbolVisibility.UNRECOGNIZED;
}
}
export function symbolVisibilityToNumber(object: SymbolVisibility): number {
switch (object) {
case SymbolVisibility.VISIBILITY_UNSET:
return 0;
case SymbolVisibility.VISIBILITY_LOCAL:
return 1;
case SymbolVisibility.VISIBILITY_EXPORT:
return 2;
case SymbolVisibility.UNRECOGNIZED:
default:
return -1;
}
}
/**
* The protocol compiler can output a FileDescriptorSet containing the .proto
* files it parses.
@ -201,11 +155,6 @@ export interface FileDescriptorProto {
* For Google-internal migration only. Do not use.
*/
weakDependency: number[];
/**
* Names of files imported by this file purely for the purpose of providing
* option extensions. These are excluded from the dependency list above.
*/
optionDependency: string[];
/** All top-level definitions in this file. */
messageType: DescriptorProto[];
enumType: EnumDescriptorProto[];
@ -260,8 +209,6 @@ export interface DescriptorProto {
* A given name may only be reserved once.
*/
reservedName: string[];
/** Support for `export` and `local` keywords on enums. */
visibility?: SymbolVisibility | undefined;
}
export interface DescriptorProto_ExtensionRange {
@ -685,8 +632,6 @@ export interface EnumDescriptorProto {
* be reserved once.
*/
reservedName: string[];
/** Support for `export` and `local` keywords on enums. */
visibility?: SymbolVisibility | undefined;
}
/**
@ -1649,7 +1594,6 @@ export interface FeatureSet {
messageEncoding?: FeatureSet_MessageEncoding | undefined;
jsonFormat?: FeatureSet_JsonFormat | undefined;
enforceNamingStyle?: FeatureSet_EnforceNamingStyle | undefined;
defaultSymbolVisibility?: FeatureSet_VisibilityFeature_DefaultSymbolVisibility | undefined;
}
export enum FeatureSet_FieldPresence {
@ -1931,72 +1875,6 @@ export function featureSet_EnforceNamingStyleToNumber(object: FeatureSet_Enforce
}
}
export interface FeatureSet_VisibilityFeature {
}
export enum FeatureSet_VisibilityFeature_DefaultSymbolVisibility {
DEFAULT_SYMBOL_VISIBILITY_UNKNOWN = "DEFAULT_SYMBOL_VISIBILITY_UNKNOWN",
/** EXPORT_ALL - Default pre-EDITION_2024, all UNSET visibility are export. */
EXPORT_ALL = "EXPORT_ALL",
/** EXPORT_TOP_LEVEL - All top-level symbols default to export, nested default to local. */
EXPORT_TOP_LEVEL = "EXPORT_TOP_LEVEL",
/** LOCAL_ALL - All symbols default to local. */
LOCAL_ALL = "LOCAL_ALL",
/**
* STRICT - All symbols local by default. Nested types cannot be exported.
* With special case caveat for message { enum {} reserved 1 to max; }
* This is the recommended setting for new protos.
*/
STRICT = "STRICT",
UNRECOGNIZED = "UNRECOGNIZED",
}
export function featureSet_VisibilityFeature_DefaultSymbolVisibilityFromJSON(
object: any,
): FeatureSet_VisibilityFeature_DefaultSymbolVisibility {
switch (object) {
case 0:
case "DEFAULT_SYMBOL_VISIBILITY_UNKNOWN":
return FeatureSet_VisibilityFeature_DefaultSymbolVisibility.DEFAULT_SYMBOL_VISIBILITY_UNKNOWN;
case 1:
case "EXPORT_ALL":
return FeatureSet_VisibilityFeature_DefaultSymbolVisibility.EXPORT_ALL;
case 2:
case "EXPORT_TOP_LEVEL":
return FeatureSet_VisibilityFeature_DefaultSymbolVisibility.EXPORT_TOP_LEVEL;
case 3:
case "LOCAL_ALL":
return FeatureSet_VisibilityFeature_DefaultSymbolVisibility.LOCAL_ALL;
case 4:
case "STRICT":
return FeatureSet_VisibilityFeature_DefaultSymbolVisibility.STRICT;
case -1:
case "UNRECOGNIZED":
default:
return FeatureSet_VisibilityFeature_DefaultSymbolVisibility.UNRECOGNIZED;
}
}
export function featureSet_VisibilityFeature_DefaultSymbolVisibilityToNumber(
object: FeatureSet_VisibilityFeature_DefaultSymbolVisibility,
): number {
switch (object) {
case FeatureSet_VisibilityFeature_DefaultSymbolVisibility.DEFAULT_SYMBOL_VISIBILITY_UNKNOWN:
return 0;
case FeatureSet_VisibilityFeature_DefaultSymbolVisibility.EXPORT_ALL:
return 1;
case FeatureSet_VisibilityFeature_DefaultSymbolVisibility.EXPORT_TOP_LEVEL:
return 2;
case FeatureSet_VisibilityFeature_DefaultSymbolVisibility.LOCAL_ALL:
return 3;
case FeatureSet_VisibilityFeature_DefaultSymbolVisibility.STRICT:
return 4;
case FeatureSet_VisibilityFeature_DefaultSymbolVisibility.UNRECOGNIZED:
default:
return -1;
}
}
/**
* A compiled specification for the defaults of a set of features. These
* messages are generated from FeatureSet extensions and can be used to seed
@ -2317,7 +2195,6 @@ function createBaseFileDescriptorProto(): FileDescriptorProto {
dependency: [],
publicDependency: [],
weakDependency: [],
optionDependency: [],
messageType: [],
enumType: [],
service: [],
@ -2350,9 +2227,6 @@ export const FileDescriptorProto: MessageFns<FileDescriptorProto> = {
writer.int32(v);
}
writer.join();
for (const v of message.optionDependency) {
writer.uint32(122).string(v!);
}
for (const v of message.messageType) {
DescriptorProto.encode(v!, writer.uint32(34).fork()).join();
}
@ -2447,14 +2321,6 @@ export const FileDescriptorProto: MessageFns<FileDescriptorProto> = {
break;
}
case 15: {
if (tag !== 122) {
break;
}
message.optionDependency.push(reader.string());
continue;
}
case 4: {
if (tag !== 34) {
break;
@ -2538,7 +2404,6 @@ export const FileDescriptorProto: MessageFns<FileDescriptorProto> = {
message.dependency = object.dependency?.map((e) => e) || [];
message.publicDependency = object.publicDependency?.map((e) => e) || [];
message.weakDependency = object.weakDependency?.map((e) => e) || [];
message.optionDependency = object.optionDependency?.map((e) => e) || [];
message.messageType = object.messageType?.map((e) => DescriptorProto.fromPartial(e)) || [];
message.enumType = object.enumType?.map((e) => EnumDescriptorProto.fromPartial(e)) || [];
message.service = object.service?.map((e) => ServiceDescriptorProto.fromPartial(e)) || [];
@ -2567,7 +2432,6 @@ function createBaseDescriptorProto(): DescriptorProto {
options: undefined,
reservedRange: [],
reservedName: [],
visibility: SymbolVisibility.VISIBILITY_UNSET,
};
}
@ -2603,9 +2467,6 @@ export const DescriptorProto: MessageFns<DescriptorProto> = {
for (const v of message.reservedName) {
writer.uint32(82).string(v!);
}
if (message.visibility !== undefined && message.visibility !== SymbolVisibility.VISIBILITY_UNSET) {
writer.uint32(88).int32(symbolVisibilityToNumber(message.visibility));
}
return writer;
},
@ -2696,14 +2557,6 @@ export const DescriptorProto: MessageFns<DescriptorProto> = {
message.reservedName.push(reader.string());
continue;
}
case 11: {
if (tag !== 88) {
break;
}
message.visibility = symbolVisibilityFromJSON(reader.int32());
continue;
}
}
if ((tag & 7) === 4 || tag === 0) {
break;
@ -2730,7 +2583,6 @@ export const DescriptorProto: MessageFns<DescriptorProto> = {
: undefined;
message.reservedRange = object.reservedRange?.map((e) => DescriptorProto_ReservedRange.fromPartial(e)) || [];
message.reservedName = object.reservedName?.map((e) => e) || [];
message.visibility = object.visibility ?? SymbolVisibility.VISIBILITY_UNSET;
return message;
},
};
@ -3291,14 +3143,7 @@ export const OneofDescriptorProto: MessageFns<OneofDescriptorProto> = {
};
function createBaseEnumDescriptorProto(): EnumDescriptorProto {
return {
name: "",
value: [],
options: undefined,
reservedRange: [],
reservedName: [],
visibility: SymbolVisibility.VISIBILITY_UNSET,
};
return { name: "", value: [], options: undefined, reservedRange: [], reservedName: [] };
}
export const EnumDescriptorProto: MessageFns<EnumDescriptorProto> = {
@ -3318,9 +3163,6 @@ export const EnumDescriptorProto: MessageFns<EnumDescriptorProto> = {
for (const v of message.reservedName) {
writer.uint32(42).string(v!);
}
if (message.visibility !== undefined && message.visibility !== SymbolVisibility.VISIBILITY_UNSET) {
writer.uint32(48).int32(symbolVisibilityToNumber(message.visibility));
}
return writer;
},
@ -3371,14 +3213,6 @@ export const EnumDescriptorProto: MessageFns<EnumDescriptorProto> = {
message.reservedName.push(reader.string());
continue;
}
case 6: {
if (tag !== 48) {
break;
}
message.visibility = symbolVisibilityFromJSON(reader.int32());
continue;
}
}
if ((tag & 7) === 4 || tag === 0) {
break;
@ -3401,7 +3235,6 @@ export const EnumDescriptorProto: MessageFns<EnumDescriptorProto> = {
message.reservedRange = object.reservedRange?.map((e) => EnumDescriptorProto_EnumReservedRange.fromPartial(e)) ||
[];
message.reservedName = object.reservedName?.map((e) => e) || [];
message.visibility = object.visibility ?? SymbolVisibility.VISIBILITY_UNSET;
return message;
},
};
@ -5166,7 +4999,6 @@ function createBaseFeatureSet(): FeatureSet {
messageEncoding: FeatureSet_MessageEncoding.MESSAGE_ENCODING_UNKNOWN,
jsonFormat: FeatureSet_JsonFormat.JSON_FORMAT_UNKNOWN,
enforceNamingStyle: FeatureSet_EnforceNamingStyle.ENFORCE_NAMING_STYLE_UNKNOWN,
defaultSymbolVisibility: FeatureSet_VisibilityFeature_DefaultSymbolVisibility.DEFAULT_SYMBOL_VISIBILITY_UNKNOWN,
};
}
@ -5207,15 +5039,6 @@ export const FeatureSet: MessageFns<FeatureSet> = {
) {
writer.uint32(56).int32(featureSet_EnforceNamingStyleToNumber(message.enforceNamingStyle));
}
if (
message.defaultSymbolVisibility !== undefined &&
message.defaultSymbolVisibility !==
FeatureSet_VisibilityFeature_DefaultSymbolVisibility.DEFAULT_SYMBOL_VISIBILITY_UNKNOWN
) {
writer.uint32(64).int32(
featureSet_VisibilityFeature_DefaultSymbolVisibilityToNumber(message.defaultSymbolVisibility),
);
}
return writer;
},
@ -5282,16 +5105,6 @@ export const FeatureSet: MessageFns<FeatureSet> = {
message.enforceNamingStyle = featureSet_EnforceNamingStyleFromJSON(reader.int32());
continue;
}
case 8: {
if (tag !== 64) {
break;
}
message.defaultSymbolVisibility = featureSet_VisibilityFeature_DefaultSymbolVisibilityFromJSON(
reader.int32(),
);
continue;
}
}
if ((tag & 7) === 4 || tag === 0) {
break;
@ -5315,42 +5128,6 @@ export const FeatureSet: MessageFns<FeatureSet> = {
message.jsonFormat = object.jsonFormat ?? FeatureSet_JsonFormat.JSON_FORMAT_UNKNOWN;
message.enforceNamingStyle = object.enforceNamingStyle ??
FeatureSet_EnforceNamingStyle.ENFORCE_NAMING_STYLE_UNKNOWN;
message.defaultSymbolVisibility = object.defaultSymbolVisibility ??
FeatureSet_VisibilityFeature_DefaultSymbolVisibility.DEFAULT_SYMBOL_VISIBILITY_UNKNOWN;
return message;
},
};
function createBaseFeatureSet_VisibilityFeature(): FeatureSet_VisibilityFeature {
return {};
}
export const FeatureSet_VisibilityFeature: MessageFns<FeatureSet_VisibilityFeature> = {
encode(_: FeatureSet_VisibilityFeature, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
return writer;
},
decode(input: BinaryReader | Uint8Array, length?: number): FeatureSet_VisibilityFeature {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseFeatureSet_VisibilityFeature();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skip(tag & 7);
}
return message;
},
create(base?: DeepPartial<FeatureSet_VisibilityFeature>): FeatureSet_VisibilityFeature {
return FeatureSet_VisibilityFeature.fromPartial(base ?? {});
},
fromPartial(_: DeepPartial<FeatureSet_VisibilityFeature>): FeatureSet_VisibilityFeature {
const message = createBaseFeatureSet_VisibilityFeature();
return message;
},
};

View File

@ -1,30 +1,22 @@
import paperThemeContent from "../themes/paper.css?raw";
import whitewallThemeContent from "../themes/whitewall.css?raw";
import defaultDarkThemeContent from "../themes/default-dark.css?raw";
const VALID_THEMES = ["default", "paper", "whitewall"] as const;
const VALID_THEMES = ["default", "default-dark", "paper", "whitewall"] as const;
type ValidTheme = (typeof VALID_THEMES)[number];
const THEME_CONTENT: Record<ValidTheme, string | null> = {
default: null,
paper: paperThemeContent,
whitewall: whitewallThemeContent,
"default-dark": defaultDarkThemeContent,
paper: null,
whitewall: null,
};
const validateTheme = (theme: string): ValidTheme => {
return VALID_THEMES.includes(theme as ValidTheme) ? (theme as ValidTheme) : "default";
};
export const getStoredTheme = (): ValidTheme => {
const stored = localStorage.getItem("workspace-theme");
return stored ? validateTheme(stored) : "default";
};
export const loadTheme = (themeName: string): void => {
const validTheme = validateTheme(themeName);
// Store theme
localStorage.setItem("workspace-theme", validTheme);
// Remove existing theme
document.getElementById("workspace-theme")?.remove();