feat: implement dark mode

This commit is contained in:
Steven 2023-09-23 01:09:45 +08:00
parent 07e0bb2d4c
commit 3488cd04c0
28 changed files with 286 additions and 220 deletions

View File

@ -87,7 +87,7 @@ func getUserSetting(ctx context.Context, s *store.Store, userID int32) (*apiv2pb
userSetting := &apiv2pb.UserSetting{ userSetting := &apiv2pb.UserSetting{
Id: userID, Id: userID,
Locale: apiv2pb.UserSetting_LOCALE_EN, Locale: apiv2pb.UserSetting_LOCALE_EN,
ColorTheme: apiv2pb.UserSetting_COLOR_THEME_LIGHT, ColorTheme: apiv2pb.UserSetting_COLOR_THEME_SYSTEM,
} }
for _, setting := range userSettings { for _, setting := range userSettings {
if setting.Key == storepb.UserSettingKey_USER_SETTING_LOCALE { if setting.Key == storepb.UserSettingKey_USER_SETTING_LOCALE {
@ -123,6 +123,8 @@ func convertUserSettingLocaleFromStore(locale storepb.LocaleUserSetting) apiv2pb
func convertUserSettingColorThemeToStore(colorTheme apiv2pb.UserSetting_ColorTheme) storepb.ColorThemeUserSetting { func convertUserSettingColorThemeToStore(colorTheme apiv2pb.UserSetting_ColorTheme) storepb.ColorThemeUserSetting {
switch colorTheme { switch colorTheme {
case apiv2pb.UserSetting_COLOR_THEME_SYSTEM:
return storepb.ColorThemeUserSetting_COLOR_THEME_USER_SETTING_SYSTEM
case apiv2pb.UserSetting_COLOR_THEME_LIGHT: case apiv2pb.UserSetting_COLOR_THEME_LIGHT:
return storepb.ColorThemeUserSetting_COLOR_THEME_USER_SETTING_LIGHT return storepb.ColorThemeUserSetting_COLOR_THEME_USER_SETTING_LIGHT
case apiv2pb.UserSetting_COLOR_THEME_DARK: case apiv2pb.UserSetting_COLOR_THEME_DARK:
@ -134,6 +136,8 @@ func convertUserSettingColorThemeToStore(colorTheme apiv2pb.UserSetting_ColorThe
func convertUserSettingColorThemeFromStore(colorTheme storepb.ColorThemeUserSetting) apiv2pb.UserSetting_ColorTheme { func convertUserSettingColorThemeFromStore(colorTheme storepb.ColorThemeUserSetting) apiv2pb.UserSetting_ColorTheme {
switch colorTheme { switch colorTheme {
case storepb.ColorThemeUserSetting_COLOR_THEME_USER_SETTING_SYSTEM:
return apiv2pb.UserSetting_COLOR_THEME_SYSTEM
case storepb.ColorThemeUserSetting_COLOR_THEME_USER_SETTING_LIGHT: case storepb.ColorThemeUserSetting_COLOR_THEME_USER_SETTING_LIGHT:
return apiv2pb.UserSetting_COLOR_THEME_LIGHT return apiv2pb.UserSetting_COLOR_THEME_LIGHT
case storepb.ColorThemeUserSetting_COLOR_THEME_USER_SETTING_DARK: case storepb.ColorThemeUserSetting_COLOR_THEME_USER_SETTING_DARK:

View File

@ -1,3 +1,4 @@
import { useColorScheme } from "@mui/joy";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Outlet } from "react-router-dom"; import { Outlet } from "react-router-dom";
import DemoBanner from "./components/DemoBanner"; import DemoBanner from "./components/DemoBanner";
@ -7,6 +8,7 @@ import useUserStore from "./stores/v1/user";
import { WorkspaceSetting } from "./types/proto/api/v2/workspace_service"; import { WorkspaceSetting } from "./types/proto/api/v2/workspace_service";
function App() { function App() {
const { mode } = useColorScheme();
const userStore = useUserStore(); const userStore = useUserStore();
const [workspaceSetting, setWorkspaceSetting] = useState<WorkspaceSetting>(WorkspaceSetting.fromPartial({})); const [workspaceSetting, setWorkspaceSetting] = useState<WorkspaceSetting>(WorkspaceSetting.fromPartial({}));
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@ -47,6 +49,39 @@ function App() {
document.body.insertAdjacentElement("beforeend", styleEl); document.body.insertAdjacentElement("beforeend", styleEl);
}, [workspaceSetting.customStyle]); }, [workspaceSetting.customStyle]);
useEffect(() => {
const root = document.documentElement;
if (mode === "light") {
root.classList.remove("dark");
} else if (mode === "dark") {
root.classList.add("dark");
} else {
const darkMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
if (darkMediaQuery.matches) {
root.classList.add("dark");
} else {
root.classList.remove("dark");
}
const handleColorSchemeChange = (e: MediaQueryListEvent) => {
if (e.matches) {
root.classList.add("dark");
} else {
root.classList.remove("dark");
}
};
try {
darkMediaQuery.addEventListener("change", handleColorSchemeChange);
} catch (error) {
console.error("failed to initial color scheme listener", error);
}
return () => {
darkMediaQuery.removeEventListener("change", handleColorSchemeChange);
};
}
}, [mode]);
return !loading ? ( return !loading ? (
<> <>
<DemoBanner /> <DemoBanner />

View File

@ -26,17 +26,17 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
{analytics ? ( {analytics ? (
<> <>
<div className="w-full"> <div className="w-full">
<p className="w-full h-8 px-2">{t("analytics.top-sources")}</p> <p className="w-full h-8 px-2 dark:text-gray-500">{t("analytics.top-sources")}</p>
<div className="w-full mt-1 overflow-hidden shadow ring-1 ring-black ring-opacity-5 rounded-lg"> <div className="w-full mt-1 overflow-hidden shadow ring-1 ring-black ring-opacity-5 rounded-lg dark:ring-zinc-800">
<div className="w-full divide-y divide-gray-300"> <div className="w-full divide-y divide-gray-300 dark:divide-zinc-700">
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
<span className="py-2 px-2 text-left font-semibold text-sm text-gray-500">{t("analytics.source")}</span> <span className="py-2 px-2 text-left font-semibold text-sm text-gray-500">{t("analytics.source")}</span>
<span className="py-2 pr-2 text-right font-semibold text-sm text-gray-500">{t("analytics.visitors")}</span> <span className="py-2 pr-2 text-right font-semibold text-sm text-gray-500">{t("analytics.visitors")}</span>
</div> </div>
<div className="w-full divide-y divide-gray-200"> <div className="w-full divide-y divide-gray-200 dark:divide-zinc-800">
{analytics.referenceData.map((reference) => ( {analytics.referenceData.map((reference) => (
<div key={reference.name} className="w-full flex flex-row justify-between items-center"> <div key={reference.name} className="w-full flex flex-row justify-between items-center">
<span className="whitespace-nowrap py-2 px-2 text-sm truncate text-gray-900"> <span className="whitespace-nowrap py-2 px-2 text-sm truncate text-gray-900 dark:text-gray-500">
{reference.name ? ( {reference.name ? (
<a className="hover:underline hover:text-blue-600" href={reference.name} target="_blank"> <a className="hover:underline hover:text-blue-600" href={reference.name} target="_blank">
{reference.name} {reference.name}
@ -55,24 +55,24 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
<div className="w-full"> <div className="w-full">
<div className="w-full h-8 px-2 flex flex-row justify-between items-center"> <div className="w-full h-8 px-2 flex flex-row justify-between items-center">
<span>{t("analytics.devices")}</span> <span className="dark:text-gray-500">{t("analytics.devices")}</span>
<div> <div>
<button <button
className={`whitespace-nowrap border-b-2 px-1 text-sm font-medium ${ className={`whitespace-nowrap border-b-2 px-1 text-sm font-medium ${
selectedDeviceTab === "browser" selectedDeviceTab === "browser"
? "border-blue-600 text-blue-600" ? "border-blue-600 text-blue-600"
: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700" : "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 dark:hover:border-zinc-700"
}`} }`}
onClick={() => setSelectedDeviceTab("browser")} onClick={() => setSelectedDeviceTab("browser")}
> >
{t("analytics.browser")} {t("analytics.browser")}
</button> </button>
<span className="text-gray-200 font-mono mx-1">/</span> <span className="text-gray-200 font-mono mx-1 dark:text-gray-500">/</span>
<button <button
className={`whitespace-nowrap border-b-2 px-1 text-sm font-medium ${ className={`whitespace-nowrap border-b-2 px-1 text-sm font-medium ${
selectedDeviceTab === "os" selectedDeviceTab === "os"
? "border-blue-600 text-blue-600" ? "border-blue-600 text-blue-600"
: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700" : "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 dark:hover:border-zinc-700"
}`} }`}
onClick={() => setSelectedDeviceTab("os")} onClick={() => setSelectedDeviceTab("os")}
> >
@ -81,17 +81,19 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
</div> </div>
</div> </div>
<div className="w-full mt-1 overflow-hidden shadow ring-1 ring-black ring-opacity-5 rounded-lg"> <div className="w-full mt-1 overflow-hidden shadow ring-1 ring-black ring-opacity-5 rounded-lg dark:ring-zinc-800">
{selectedDeviceTab === "browser" ? ( {selectedDeviceTab === "browser" ? (
<div className="w-full divide-y divide-gray-300"> <div className="w-full divide-y divide-gray-300 dark:divide-zinc-700">
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
<span className="py-2 px-2 text-left text-sm font-semibold text-gray-500">{t("analytics.browsers")}</span> <span className="py-2 px-2 text-left text-sm font-semibold text-gray-500">{t("analytics.browsers")}</span>
<span className="py-2 pr-2 text-right text-sm font-semibold text-gray-500">{t("analytics.visitors")}</span> <span className="py-2 pr-2 text-right text-sm font-semibold text-gray-500">{t("analytics.visitors")}</span>
</div> </div>
<div className="w-full divide-y divide-gray-200"> <div className="w-full divide-y divide-gray-200 dark:divide-zinc-800">
{analytics.browserData.map((reference) => ( {analytics.browserData.map((reference) => (
<div key={reference.name} className="w-full flex flex-row justify-between items-center"> <div key={reference.name} className="w-full flex flex-row justify-between items-center">
<span className="whitespace-nowrap py-2 px-2 text-sm text-gray-900 truncate">{reference.name || "Unknown"}</span> <span className="whitespace-nowrap py-2 px-2 text-sm text-gray-900 truncate dark:text-gray-500">
{reference.name || "Unknown"}
</span>
<span className="whitespace-nowrap py-2 pr-2 text-sm text-gray-500 text-right shrink-0">{reference.count}</span> <span className="whitespace-nowrap py-2 pr-2 text-sm text-gray-500 text-right shrink-0">{reference.count}</span>
</div> </div>
))} ))}

View File

@ -1,6 +1,6 @@
const BetaBadge = () => { const BetaBadge = () => {
return ( return (
<div className="text-xs border px-1 text-gray-500 bg-gray-100 rounded-full"> <div className="text-xs border px-1 text-gray-500 bg-gray-100 rounded-full dark:bg-zinc-800 dark:border-zinc-700">
<span>Beta</span> <span>Beta</span>
</div> </div>
); );

View File

@ -230,16 +230,16 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
))} ))}
</RadioGroup> </RadioGroup>
</div> </div>
<p className="mt-3 text-sm text-gray-500 w-full bg-gray-100 border border-gray-200 px-2 py-1 rounded-md"> <p className="mt-3 text-sm text-gray-500 w-full bg-gray-100 border border-gray-200 dark:bg-zinc-800 dark:border-zinc-700 dark:text-gray-400 px-2 py-1 rounded-md">
{t(`shortcut.visibility.${state.shortcutCreate.visibility.toLowerCase()}.description`)} {t(`shortcut.visibility.${state.shortcutCreate.visibility.toLowerCase()}.description`)}
</p> </p>
</div> </div>
<Divider className="text-gray-500">Optional</Divider> <Divider className="text-gray-500">Optional</Divider>
<div className="w-full flex flex-col justify-start items-start border rounded-md overflow-hidden my-3"> <div className="w-full flex flex-col justify-start items-start border rounded-md overflow-hidden my-3 dark:border-zinc-800">
<div <div
className={classnames( className={classnames(
"w-full flex flex-row justify-between items-center px-2 py-1 cursor-pointer hover:bg-gray-100", "w-full flex flex-row justify-between items-center px-2 py-1 cursor-pointer hover:bg-gray-100 dark:hover:bg-zinc-800",
showAdditionalFields ? "bg-gray-100 border-b" : "" showAdditionalFields ? "bg-gray-100 border-b dark:bg-zinc-800 dark:border-b-zinc-700" : ""
)} )}
onClick={() => setShowAdditionalFields(!showAdditionalFields)} onClick={() => setShowAdditionalFields(!showAdditionalFields)}
> >
@ -275,11 +275,12 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
</div> </div>
)} )}
</div> </div>
<div className="w-full flex flex-col justify-start items-start border rounded-md overflow-hidden"> <div className="w-full flex flex-col justify-start items-start border rounded-md overflow-hidden dark:border-zinc-800">
<div <div
className={`w-full flex flex-row justify-between items-center px-2 py-1 cursor-pointer hover:bg-gray-100 ${ className={classnames(
showOpenGraphMetadata ? "bg-gray-100 border-b" : "" "w-full flex flex-row justify-between items-center px-2 py-1 cursor-pointer hover:bg-gray-100 dark:hover:bg-zinc-800",
}`} showOpenGraphMetadata ? "bg-gray-100 border-b dark:bg-zinc-800 dark:border-b-zinc-700" : ""
)}
onClick={() => setShowOpenGraphMetadata(!showOpenGraphMetadata)} onClick={() => setShowOpenGraphMetadata(!showOpenGraphMetadata)}
> >
<span className="text-sm flex flex-row justify-start items-center"> <span className="text-sm flex flex-row justify-start items-center">

View File

@ -40,32 +40,32 @@ const ShortcutActionsDropdown = (props: Props) => {
return ( return (
<> <>
<Dropdown <Dropdown
actionsClassName="!w-32" actionsClassName="!w-32 dark:text-gray-500"
actions={ actions={
<> <>
{havePermission && ( {havePermission && (
<button <button
className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60" className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60 dark:hover:bg-zinc-800"
onClick={() => setShowEditDialog(true)} onClick={() => setShowEditDialog(true)}
> >
<Icon.Edit className="w-4 h-auto mr-2" /> {t("common.edit")} <Icon.Edit className="w-4 h-auto mr-2" /> {t("common.edit")}
</button> </button>
)} )}
<button <button
className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60" className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60 dark:hover:bg-zinc-800"
onClick={() => setShowQRCodeDialog(true)} onClick={() => setShowQRCodeDialog(true)}
> >
<Icon.QrCode className="w-4 h-auto mr-2" /> QR Code <Icon.QrCode className="w-4 h-auto mr-2" /> QR Code
</button> </button>
<button <button
className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60" className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60 dark:hover:bg-zinc-800"
onClick={gotoAnalytics} onClick={gotoAnalytics}
> >
<Icon.BarChart2 className="w-4 h-auto mr-2" /> {t("analytics.self")} <Icon.BarChart2 className="w-4 h-auto mr-2" /> {t("analytics.self")}
</button> </button>
{havePermission && ( {havePermission && (
<button <button
className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded text-red-600 hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60" className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded text-red-600 hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60 dark:hover:bg-zinc-800"
onClick={() => { onClick={() => {
handleDeleteShortcutButtonClick(shortcut); handleDeleteShortcutButtonClick(shortcut);
}} }}

View File

@ -39,7 +39,11 @@ const ShortcutView = (props: Props) => {
return ( return (
<> <>
<div className={classNames("group px-4 py-3 w-full flex flex-col justify-start items-start border rounded-lg hover:shadow")}> <div
className={classNames(
"group px-4 py-3 w-full flex flex-col justify-start items-start border rounded-lg hover:shadow dark:border-zinc-700"
)}
>
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
<div className="w-[calc(100%-16px)] flex flex-row justify-start items-center mr-1 shrink-0"> <div className="w-[calc(100%-16px)] flex flex-row justify-start items-center mr-1 shrink-0">
<Link to={`/shortcut/${shortcut.id}`} className={classNames("w-8 h-8 flex justify-center items-center overflow-clip shrink-0")}> <Link to={`/shortcut/${shortcut.id}`} className={classNames("w-8 h-8 flex justify-center items-center overflow-clip shrink-0")}>
@ -53,7 +57,7 @@ const ShortcutView = (props: Props) => {
<div className="w-full flex flex-row justify-start items-center"> <div className="w-full flex flex-row justify-start items-center">
<a <a
className={classNames( className={classNames(
"max-w-[calc(100%-36px)] flex flex-row px-1 mr-1 justify-start items-center cursor-pointer rounded-md hover:bg-gray-100 hover:shadow" "max-w-[calc(100%-36px)] flex flex-row px-1 mr-1 justify-start items-center cursor-pointer rounded-md hover:bg-gray-100 hover:shadow dark:hover:bg-zinc-800"
)} )}
target="_blank" target="_blank"
href={shortcutLink} href={shortcutLink}
@ -64,8 +68,8 @@ const ShortcutView = (props: Props) => {
<span className="text-gray-400">(s/{shortcut.name})</span> <span className="text-gray-400">(s/{shortcut.name})</span>
) : ( ) : (
<> <>
<span className="text-gray-400">s/</span> <span className="text-gray-400 dark:text-gray-500">s/</span>
<span className="truncate">{shortcut.name}</span> <span className="truncate dark:text-gray-400">{shortcut.name}</span>
</> </>
)} )}
</div> </div>
@ -75,14 +79,18 @@ const ShortcutView = (props: Props) => {
</a> </a>
<Tooltip title="Copy" variant="solid" placement="top" arrow> <Tooltip title="Copy" variant="solid" placement="top" arrow>
<button <button
className="hidden group-hover:block w-6 h-6 cursor-pointer rounded-md text-gray-500 hover:bg-gray-100 hover:shadow" className="hidden group-hover:block w-6 h-6 cursor-pointer rounded-md text-gray-500 hover:bg-gray-100 hover:shadow dark:hover:bg-zinc-800"
onClick={() => handleCopyButtonClick()} onClick={() => handleCopyButtonClick()}
> >
<Icon.Clipboard className="w-4 h-auto mx-auto" /> <Icon.Clipboard className="w-4 h-auto mx-auto" />
</button> </button>
</Tooltip> </Tooltip>
</div> </div>
<a className="pl-1 pr-4 w-full text-sm truncate text-gray-400 hover:underline" href={shortcut.link} target="_blank"> <a
className="pl-1 pr-4 w-full text-sm truncate text-gray-400 dark:text-gray-500 hover:underline"
href={shortcut.link}
target="_blank"
>
{shortcut.link} {shortcut.link}
</a> </a>
</div> </div>
@ -96,7 +104,7 @@ const ShortcutView = (props: Props) => {
return ( return (
<span <span
key={tag} key={tag}
className="max-w-[8rem] truncate text-gray-400 text-sm font-mono leading-4 cursor-pointer hover:text-gray-600" className="max-w-[8rem] truncate text-gray-400 dark:text-gray-500 text-sm font-mono leading-4 cursor-pointer hover:opacity-80"
onClick={() => viewStore.setFilter({ tag: tag })} onClick={() => viewStore.setFilter({ tag: tag })}
> >
#{tag} #{tag}
@ -107,14 +115,14 @@ const ShortcutView = (props: Props) => {
</div> </div>
<div className="w-full flex mt-2 gap-2"> <div className="w-full flex mt-2 gap-2">
<Tooltip title="Creator" variant="solid" placement="top" arrow> <Tooltip title="Creator" variant="solid" placement="top" arrow>
<div className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full text-gray-500 text-sm"> <div className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full text-gray-500 text-sm dark:border-zinc-800">
<Icon.User className="w-4 h-auto mr-1" /> <Icon.User className="w-4 h-auto mr-1" />
<span className="max-w-[4rem] sm:max-w-[6rem] truncate">{shortcut.creator.nickname}</span> <span className="max-w-[4rem] sm:max-w-[6rem] truncate">{shortcut.creator.nickname}</span>
</div> </div>
</Tooltip> </Tooltip>
<Tooltip title={t(`shortcut.visibility.${shortcut.visibility.toLowerCase()}.description`)} variant="solid" placement="top" arrow> <Tooltip title={t(`shortcut.visibility.${shortcut.visibility.toLowerCase()}.description`)} variant="solid" placement="top" arrow>
<div <div
className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full cursor-pointer text-gray-500 text-sm" className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full cursor-pointer text-gray-500 text-sm dark:border-zinc-800"
onClick={() => viewStore.setFilter({ visibility: shortcut.visibility })} onClick={() => viewStore.setFilter({ visibility: shortcut.visibility })}
> >
<VisibilityIcon className="w-4 h-auto mr-1" visibility={shortcut.visibility} /> <VisibilityIcon className="w-4 h-auto mr-1" visibility={shortcut.visibility} />
@ -124,7 +132,7 @@ const ShortcutView = (props: Props) => {
<Tooltip title="View count" variant="solid" placement="top" arrow> <Tooltip title="View count" variant="solid" placement="top" arrow>
<Link <Link
to={`/shortcut/${shortcut.id}#analytics`} to={`/shortcut/${shortcut.id}#analytics`}
className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full cursor-pointer text-gray-500 text-sm" className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full cursor-pointer text-gray-500 text-sm dark:border-zinc-800"
> >
<Icon.BarChart2 className="w-4 h-auto mr-1" /> <Icon.BarChart2 className="w-4 h-auto mr-1" />
{shortcut.view} visits {shortcut.view} visits

View File

@ -28,7 +28,7 @@ const ShortcutView = (props: Props) => {
<> <>
<div <div
className={classNames( className={classNames(
"group w-full px-3 py-2 flex flex-col justify-start items-start border rounded-lg hover:bg-gray-100 hover:shadow" "group w-full px-3 py-2 flex flex-col justify-start items-start border rounded-lg hover:bg-gray-100 hover:shadow dark:border-zinc-800 dark:hover:bg-zinc-800"
)} )}
> >
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
@ -55,8 +55,8 @@ const ShortcutView = (props: Props) => {
<span className="text-gray-400">(s/{shortcut.name})</span> <span className="text-gray-400">(s/{shortcut.name})</span>
) : ( ) : (
<> <>
<span className="text-gray-400">s/</span> <span className="text-gray-400 dark:text-gray-500">s/</span>
<span className="truncate">{shortcut.name}</span> <span className="truncate dark:text-gray-400">{shortcut.name}</span>
</> </>
)} )}
</div> </div>

View File

@ -64,8 +64,8 @@ const AccessTokenSection = () => {
<div className="w-full"> <div className="w-full">
<div className="sm:flex sm:items-center"> <div className="sm:flex sm:items-center">
<div className="sm:flex-auto"> <div className="sm:flex-auto">
<p className="text-base font-semibold leading-6 text-gray-900">Access Tokens</p> <p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">Access Tokens</p>
<p className="mt-2 text-sm text-gray-700">A list of all access tokens for your account.</p> <p className="mt-2 text-sm text-gray-700 dark:text-gray-600">A list of all access tokens for your account.</p>
</div> </div>
<div className="mt-4 sm:ml-16 sm:mt-0 sm:flex-none"> <div className="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
<Button <Button
@ -82,19 +82,19 @@ const AccessTokenSection = () => {
<div className="mt-2 flow-root"> <div className="mt-2 flow-root">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<div className="inline-block min-w-full py-2 align-middle"> <div className="inline-block min-w-full py-2 align-middle">
<table className="min-w-full divide-y divide-gray-300"> <table className="min-w-full divide-y divide-gray-300 dark:divide-zinc-700">
<thead> <thead>
<tr> <tr>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"> <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
Token Token
</th> </th>
<th scope="col" className="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900"> <th scope="col" className="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
Description Description
</th> </th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"> <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
Created At Created At
</th> </th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"> <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
Expires At Expires At
</th> </th>
<th scope="col" className="relative py-3.5 pl-3 pr-4"> <th scope="col" className="relative py-3.5 pl-3 pr-4">
@ -102,16 +102,18 @@ const AccessTokenSection = () => {
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody className="divide-y divide-gray-200"> <tbody className="divide-y divide-gray-200 dark:divide-zinc-800">
{userAccessTokens.map((userAccessToken) => ( {userAccessTokens.map((userAccessToken) => (
<tr key={userAccessToken.accessToken}> <tr key={userAccessToken.accessToken}>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-900 flex flex-row justify-start items-center gap-x-1"> <td className="whitespace-nowrap px-3 py-4 text-sm text-gray-900 flex flex-row justify-start items-center gap-x-1 dark:text-gray-500">
<span className="font-mono">{getFormatedAccessToken(userAccessToken.accessToken)}</span> <span className="font-mono">{getFormatedAccessToken(userAccessToken.accessToken)}</span>
<Button color="neutral" variant="plain" size="sm" onClick={() => copyAccessToken(userAccessToken.accessToken)}> <Button color="neutral" variant="plain" size="sm" onClick={() => copyAccessToken(userAccessToken.accessToken)}>
<Icon.Clipboard className="w-4 h-auto text-gray-500" /> <Icon.Clipboard className="w-4 h-auto text-gray-500" />
</Button> </Button>
</td> </td>
<td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm text-gray-900">{userAccessToken.description}</td> <td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm text-gray-900 dark:text-gray-500">
{userAccessToken.description}
</td>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{userAccessToken.issuedAt?.toLocaleString()}</td> <td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{userAccessToken.issuedAt?.toLocaleString()}</td>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500"> <td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
{userAccessToken.expiresAt?.toLocaleString() ?? "Never"} {userAccessToken.expiresAt?.toLocaleString() ?? "Never"}

View File

@ -15,12 +15,12 @@ const AccountSection: React.FC = () => {
return ( return (
<> <>
<div className="w-full flex flex-col justify-start items-start gap-y-2"> <div className="w-full flex flex-col justify-start items-start gap-y-2">
<p className="text-base font-semibold leading-6 text-gray-900">Account</p> <p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">Account</p>
<p className="flex flex-row justify-start items-center mt-2"> <p className="flex flex-row justify-start items-center mt-2 dark:text-gray-400">
<span className="text-xl">{currentUser.nickname}</span> <span className="text-xl">{currentUser.nickname}</span>
{isAdmin && <span className="ml-2 bg-blue-600 text-white px-2 leading-6 text-sm rounded-full">Admin</span>} {isAdmin && <span className="ml-2 bg-blue-600 text-white px-2 leading-6 text-sm rounded-full">Admin</span>}
</p> </p>
<p className="flex flex-row justify-start items-center"> <p className="flex flex-row justify-start items-center dark:text-gray-400">
<span className="mr-3 text-gray-500">{t("common.email")}: </span> <span className="mr-3 text-gray-500">{t("common.email")}: </span>
{currentUser.email} {currentUser.email}
</p> </p>

View File

@ -43,8 +43,8 @@ const MemberSection = () => {
<div className="w-full"> <div className="w-full">
<div className="sm:flex sm:items-center"> <div className="sm:flex sm:items-center">
<div className="sm:flex-auto"> <div className="sm:flex-auto">
<p className="text-base font-semibold leading-6 text-gray-900">Users</p> <p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">Users</p>
<p className="mt-2 text-sm text-gray-700"> <p className="mt-2 text-sm text-gray-700 dark:text-gray-600">
A list of all the users in your workspace including their nickname, email and role. A list of all the users in your workspace including their nickname, email and role.
</p> </p>
</div> </div>
@ -64,16 +64,16 @@ const MemberSection = () => {
<div className="mt-2 flow-root"> <div className="mt-2 flow-root">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<div className="inline-block min-w-full py-2 align-middle"> <div className="inline-block min-w-full py-2 align-middle">
<table className="min-w-full divide-y divide-gray-300"> <table className="min-w-full divide-y divide-gray-300 dark:divide-zinc-700">
<thead> <thead>
<tr> <tr>
<th scope="col" className="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900"> <th scope="col" className="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
Nickname Nickname
</th> </th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"> <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
Email Email
</th> </th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"> <th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
Role Role
</th> </th>
<th scope="col" className="relative py-3.5 pl-3 pr-4"> <th scope="col" className="relative py-3.5 pl-3 pr-4">
@ -84,7 +84,7 @@ const MemberSection = () => {
<tbody className="divide-y divide-gray-200"> <tbody className="divide-y divide-gray-200">
{userList.map((user) => ( {userList.map((user) => (
<tr key={user.email}> <tr key={user.email}>
<td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm text-gray-900">{user.nickname}</td> <td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm text-gray-900 dark:text-gray-500">{user.nickname}</td>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{user.email}</td> <td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{user.email}</td>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{user.role}</td> <td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{user.role}</td>
<td className="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm"> <td className="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm">

View File

@ -13,31 +13,31 @@ const PreferenceSection: React.FC = () => {
const languageOptions = [ const languageOptions = [
{ {
value: "LOCALE_EN", value: UserSetting_Locale.LOCALE_EN,
label: "English", label: "English",
}, },
{ {
value: "LOCALE_ZH", value: UserSetting_Locale.LOCALE_ZH,
label: "中文", label: "中文",
}, },
]; ];
const colorThemeOptions = [ const colorThemeOptions = [
{ {
value: "COLOR_THEME_LIGHT", value: UserSetting_ColorTheme.COLOR_THEME_SYSTEM,
label: "System",
},
{
value: UserSetting_ColorTheme.COLOR_THEME_LIGHT,
label: "Light", label: "Light",
}, },
{ {
value: "COLOR_THEME_DARK", value: UserSetting_ColorTheme.COLOR_THEME_DARK,
label: "Dark", label: "Dark",
}, },
]; ];
const handleSelectLanguage = async (locale: UserSetting_Locale) => { const handleSelectLanguage = async (locale: UserSetting_Locale) => {
if (!locale) {
return;
}
await userStore.updateUserSetting( await userStore.updateUserSetting(
{ {
...userSetting, ...userSetting,
@ -48,10 +48,6 @@ const PreferenceSection: React.FC = () => {
}; };
const handleSelectColorTheme = async (colorTheme: UserSetting_ColorTheme) => { const handleSelectColorTheme = async (colorTheme: UserSetting_ColorTheme) => {
if (!colorTheme) {
return;
}
await userStore.updateUserSetting( await userStore.updateUserSetting(
{ {
...userSetting, ...userSetting,
@ -64,10 +60,10 @@ const PreferenceSection: React.FC = () => {
return ( return (
<> <>
<div className="w-full flex flex-col justify-start items-start gap-y-2"> <div className="w-full flex flex-col justify-start items-start gap-y-2">
<p className="text-base font-semibold leading-6 text-gray-900">Preference</p> <p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">Preference</p>
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
<div className="flex flex-row justify-start items-center gap-x-1"> <div className="flex flex-row justify-start items-center gap-x-1">
<span>{t("common.language")}</span> <span className="dark:text-gray-400">{t("common.language")}</span>
<BetaBadge /> <BetaBadge />
</div> </div>
<Select defaultValue={language} onChange={(_, value) => handleSelectLanguage(value as UserSetting_Locale)}> <Select defaultValue={language} onChange={(_, value) => handleSelectLanguage(value as UserSetting_Locale)}>
@ -82,7 +78,7 @@ const PreferenceSection: React.FC = () => {
</div> </div>
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
<div className="flex flex-row justify-start items-center gap-x-1"> <div className="flex flex-row justify-start items-center gap-x-1">
<span>Color Theme</span> <span className="dark:text-gray-400">Color Theme</span>
<BetaBadge /> <BetaBadge />
</div> </div>
<Select defaultValue={colorTheme} onChange={(_, value) => handleSelectColorTheme(value as UserSetting_ColorTheme)}> <Select defaultValue={colorTheme} onChange={(_, value) => handleSelectColorTheme(value as UserSetting_ColorTheme)}>

View File

@ -62,9 +62,9 @@ const WorkspaceSection: React.FC = () => {
return ( return (
<div className="w-full flex flex-col justify-start items-start space-y-4"> <div className="w-full flex flex-col justify-start items-start space-y-4">
<p className="text-base font-semibold leading-6 text-gray-900">Workspace settings</p> <p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">Workspace settings</p>
<div className="w-full flex flex-col justify-start items-start"> <div className="w-full flex flex-col justify-start items-start">
<p className="mt-2">Custom style</p> <p className="mt-2 dark:text-gray-400">Custom style</p>
<Textarea <Textarea
className="w-full mt-2" className="w-full mt-2"
minRows={2} minRows={2}

View File

@ -5,7 +5,7 @@
body, body,
html, html,
#root { #root {
@apply text-base w-full h-full dark:bg-zinc-800; @apply text-base w-full h-full dark:bg-zinc-900;
} }
@layer utilities { @layer utilities {

View File

@ -1,6 +1,7 @@
import { createChannel, createClientFactory, FetchTransport } from "nice-grpc-web"; import { createChannel, createClientFactory, FetchTransport } from "nice-grpc-web";
import { SubscriptionServiceDefinition } from "./types/proto/api/v2/subscription_service"; import { SubscriptionServiceDefinition } from "./types/proto/api/v2/subscription_service";
import { UserServiceDefinition } from "./types/proto/api/v2/user_service"; import { UserServiceDefinition } from "./types/proto/api/v2/user_service";
import { UserSettingServiceDefinition } from "./types/proto/api/v2/user_setting_service";
import { WorkspaceServiceDefinition } from "./types/proto/api/v2/workspace_service"; import { WorkspaceServiceDefinition } from "./types/proto/api/v2/workspace_service";
const address = import.meta.env.MODE === "development" ? "http://localhost:8082" : window.location.origin; const address = import.meta.env.MODE === "development" ? "http://localhost:8082" : window.location.origin;
@ -19,3 +20,5 @@ export const subscriptionServiceClient = clientFactory.create(SubscriptionServic
export const workspaceServiceClient = clientFactory.create(WorkspaceServiceDefinition, channel); export const workspaceServiceClient = clientFactory.create(WorkspaceServiceDefinition, channel);
export const userServiceClient = clientFactory.create(UserServiceDefinition, channel); export const userServiceClient = clientFactory.create(UserServiceDefinition, channel);
export const userSettingServiceClient = clientFactory.create(UserSettingServiceDefinition, channel);

View File

@ -3,13 +3,14 @@ import { isEqual } from "lodash-es";
import { useEffect } from "react"; import { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Outlet, useNavigate } from "react-router-dom"; import { Outlet, useNavigate } from "react-router-dom";
import { UserSetting_ColorTheme } from "@/types/proto/api/v2/user_setting_service";
import Header from "../components/Header"; import Header from "../components/Header";
import useUserStore from "../stores/v1/user"; import useUserStore from "../stores/v1/user";
const Root: React.FC = () => { const Root: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const { i18n } = useTranslation();
const { setMode } = useColorScheme(); const { setMode } = useColorScheme();
const { i18n } = useTranslation();
const userStore = useUserStore(); const userStore = useUserStore();
const currentUser = userStore.getCurrentUser(); const currentUser = userStore.getCurrentUser();
const currentUserSetting = userStore.getCurrentUserSetting(); const currentUserSetting = userStore.getCurrentUserSetting();
@ -38,19 +39,19 @@ const Root: React.FC = () => {
i18n.changeLanguage("en"); i18n.changeLanguage("en");
} }
if (isEqual(currentUserSetting.colorTheme, "COLOR_THEME_DARK")) { if (currentUserSetting.colorTheme === UserSetting_ColorTheme.COLOR_THEME_LIGHT) {
setMode("dark");
document.documentElement.classList.add("dark");
} else {
setMode("light"); setMode("light");
document.documentElement.classList.remove("dark"); } else if (currentUserSetting.colorTheme === UserSetting_ColorTheme.COLOR_THEME_DARK) {
setMode("dark");
} else {
setMode("system");
} }
}, [currentUserSetting]); }, [currentUserSetting]);
return ( return (
<> <>
{isInitialized && ( {isInitialized && (
<div className="w-full h-auto flex flex-col justify-start items-start dark:bg-zinc-800"> <div className="w-full h-auto flex flex-col justify-start items-start dark:bg-zinc-900">
<Header /> <Header />
<Outlet /> <Outlet />
</div> </div>

View File

@ -86,8 +86,8 @@ const ShortcutDetail = () => {
<span className="text-gray-400">(s/{shortcut.name})</span> <span className="text-gray-400">(s/{shortcut.name})</span>
) : ( ) : (
<> <>
<span className="text-gray-400">s/</span> <span className="text-gray-400 dark:text-gray-500">s/</span>
<span className="truncate">{shortcut.name}</span> <span className="truncate dark:text-gray-400">{shortcut.name}</span>
</> </>
)} )}
</div> </div>
@ -98,7 +98,7 @@ const ShortcutDetail = () => {
<div className="mt-2 w-full flex flex-row justify-normal items-center space-x-2"> <div className="mt-2 w-full flex flex-row justify-normal items-center space-x-2">
<Tooltip title="Copy" variant="solid" placement="top" arrow> <Tooltip title="Copy" variant="solid" placement="top" arrow>
<button <button
className="w-8 h-8 cursor-pointer border rounded-full text-gray-500 hover:bg-gray-100 hover:shadow" className="w-8 h-8 cursor-pointer border rounded-full text-gray-500 hover:bg-gray-100 hover:shadow dark:border-zinc-800 dark:hover:bg-zinc-800"
onClick={() => handleCopyButtonClick()} onClick={() => handleCopyButtonClick()}
> >
<Icon.Clipboard className="w-4 h-auto mx-auto" /> <Icon.Clipboard className="w-4 h-auto mx-auto" />
@ -106,7 +106,7 @@ const ShortcutDetail = () => {
</Tooltip> </Tooltip>
<Tooltip title="QR Code" variant="solid" placement="top" arrow> <Tooltip title="QR Code" variant="solid" placement="top" arrow>
<button <button
className="w-8 h-8 cursor-pointer border rounded-full text-gray-500 hover:bg-gray-100 hover:shadow" className="w-8 h-8 cursor-pointer border rounded-full text-gray-500 hover:bg-gray-100 hover:shadow dark:border-zinc-800 dark:hover:bg-zinc-800"
onClick={() => setShowQRCodeDialog(true)} onClick={() => setShowQRCodeDialog(true)}
> >
<Icon.QrCode className="w-4 h-auto mx-auto" /> <Icon.QrCode className="w-4 h-auto mx-auto" />
@ -114,12 +114,12 @@ const ShortcutDetail = () => {
</Tooltip> </Tooltip>
{havePermission && ( {havePermission && (
<Dropdown <Dropdown
className="w-8 h-8 flex justify-center items-center border cursor-pointer rounded-full hover:bg-gray-100 hover:shadow" className="w-8 h-8 flex justify-center items-center border cursor-pointer rounded-full hover:bg-gray-100 hover:shadow dark:border-zinc-800 dark:hover:bg-zinc-800"
actionsClassName="!w-32 !-right-24" actionsClassName="!w-32 !-right-24 dark:text-gray-500"
actions={ actions={
<> <>
<button <button
className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60" className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60 dark:hover:bg-zinc-800"
onClick={() => { onClick={() => {
setState({ setState({
...state, ...state,
@ -130,7 +130,7 @@ const ShortcutDetail = () => {
<Icon.Edit className="w-4 h-auto mr-2" /> {t("common.edit")} <Icon.Edit className="w-4 h-auto mr-2" /> {t("common.edit")}
</button> </button>
<button <button
className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded text-red-600 hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60" className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded text-red-600 hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60 dark:hover:bg-zinc-800"
onClick={() => { onClick={() => {
handleDeleteShortcutButtonClick(shortcut); handleDeleteShortcutButtonClick(shortcut);
}} }}
@ -142,32 +142,34 @@ const ShortcutDetail = () => {
></Dropdown> ></Dropdown>
)} )}
</div> </div>
{shortcut.description && <p className="w-full break-all mt-2 text-gray-400 text-sm">{shortcut.description}</p>} {shortcut.description && <p className="w-full break-all mt-2 text-gray-400 text-sm dark:text-gray-500">{shortcut.description}</p>}
<div className="mt-4 ml-1 flex flex-row justify-start items-start flex-wrap gap-2"> <div className="mt-4 ml-1 flex flex-row justify-start items-start flex-wrap gap-2">
{shortcut.tags.map((tag) => { {shortcut.tags.map((tag) => {
return ( return (
<span key={tag} className="max-w-[8rem] truncate text-gray-400 text font-mono leading-4"> <span key={tag} className="max-w-[8rem] truncate text-gray-400 text font-mono leading-4 dark:text-gray-500">
#{tag} #{tag}
</span> </span>
); );
})} })}
{shortcut.tags.length === 0 && <span className="text-gray-400 text-sm font-mono leading-4 italic">No tags</span>} {shortcut.tags.length === 0 && (
<span className="text-gray-400 text-sm font-mono leading-4 italic dark:text-gray-500">No tags</span>
)}
</div> </div>
<div className="w-full flex mt-4 gap-2"> <div className="w-full flex mt-4 gap-2">
<Tooltip title="Creator" variant="solid" placement="top" arrow> <Tooltip title="Creator" variant="solid" placement="top" arrow>
<div className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full text-gray-500 text-sm"> <div className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full text-gray-500 text-sm dark:border-zinc-800">
<Icon.User className="w-4 h-auto mr-1" /> <Icon.User className="w-4 h-auto mr-1" />
<span className="max-w-[4rem] sm:max-w-[6rem] truncate">{shortcut.creator.nickname}</span> <span className="max-w-[4rem] sm:max-w-[6rem] truncate">{shortcut.creator.nickname}</span>
</div> </div>
</Tooltip> </Tooltip>
<Tooltip title={t(`shortcut.visibility.${shortcut.visibility.toLowerCase()}.description`)} variant="solid" placement="top" arrow> <Tooltip title={t(`shortcut.visibility.${shortcut.visibility.toLowerCase()}.description`)} variant="solid" placement="top" arrow>
<div className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full text-gray-500 text-sm"> <div className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full text-gray-500 text-sm dark:border-zinc-800">
<VisibilityIcon className="w-4 h-auto mr-1" visibility={shortcut.visibility} /> <VisibilityIcon className="w-4 h-auto mr-1" visibility={shortcut.visibility} />
{t(`shortcut.visibility.${shortcut.visibility.toLowerCase()}.self`)} {t(`shortcut.visibility.${shortcut.visibility.toLowerCase()}.self`)}
</div> </div>
</Tooltip> </Tooltip>
<Tooltip title="View count" variant="solid" placement="top" arrow> <Tooltip title="View count" variant="solid" placement="top" arrow>
<div className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full text-gray-500 text-sm"> <div className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full text-gray-500 text-sm dark:border-zinc-800">
<Icon.BarChart2 className="w-4 h-auto mr-1" /> <Icon.BarChart2 className="w-4 h-auto mr-1" />
{shortcut.view} visits {shortcut.view} visits
</div> </div>
@ -175,7 +177,7 @@ const ShortcutDetail = () => {
</div> </div>
<div className="w-full flex flex-col mt-8"> <div className="w-full flex flex-col mt-8">
<h3 id="analytics" className="pl-1 font-medium text-lg flex flex-row justify-start items-center"> <h3 id="analytics" className="pl-1 font-medium text-lg flex flex-row justify-start items-center dark:text-gray-400">
<Icon.BarChart2 className="w-6 h-auto mr-1" /> <Icon.BarChart2 className="w-6 h-auto mr-1" />
{t("analytics.self")} {t("analytics.self")}
</h3> </h3>

View File

@ -68,12 +68,12 @@ const SignIn: React.FC = () => {
}; };
return ( return (
<div className="flex flex-row justify-center items-center w-full h-auto mt-12 sm:mt-24 bg-white"> <div className="flex flex-row justify-center items-center w-full h-auto mt-12 sm:mt-24 bg-white dark:bg-zinc-900">
<div className="w-80 max-w-full h-full py-4 flex flex-col justify-start items-center"> <div className="w-80 max-w-full h-full py-4 flex flex-col justify-start items-center">
<div className="w-full py-4 grow flex flex-col justify-center items-center"> <div className="w-full py-4 grow flex flex-col justify-center items-center">
<div className="flex flex-row justify-start items-center w-auto mx-auto gap-y-2 mb-4"> <div className="flex flex-row justify-start items-center w-auto mx-auto gap-y-2 mb-4">
<img src="/logo.png" className="w-12 h-auto mr-2 -mt-1" alt="logo" /> <img src="/logo.png" className="w-12 h-auto mr-2 -mt-1" alt="logo" />
<span className="text-3xl opacity-80">Slash</span> <span className="text-3xl opacity-80 dark:text-gray-500">Slash</span>
</div> </div>
<form className="w-full mt-6" onSubmit={handleSigninBtnClick}> <form className="w-full mt-6" onSubmit={handleSigninBtnClick}>
<div className={`flex flex-col justify-start items-start w-full ${actionBtnLoadingState.isLoading ? "opacity-80" : ""}`}> <div className={`flex flex-col justify-start items-start w-full ${actionBtnLoadingState.isLoading ? "opacity-80" : ""}`}>
@ -107,7 +107,7 @@ const SignIn: React.FC = () => {
</form> </form>
{enableSignup && ( {enableSignup && (
<p className="w-full mt-4 text-sm"> <p className="w-full mt-4 text-sm">
<span>{"Don't have an account yet?"}</span> <span className="dark:text-gray-500">{"Don't have an account yet?"}</span>
<Link to="/auth/signup" className="cursor-pointer ml-2 text-blue-600 hover:underline"> <Link to="/auth/signup" className="cursor-pointer ml-2 text-blue-600 hover:underline">
Sign up Sign up
</Link> </Link>

View File

@ -75,14 +75,14 @@ const SignUp: React.FC = () => {
}; };
return ( return (
<div className="flex flex-row justify-center items-center w-full h-auto mt-12 sm:mt-24 bg-white"> <div className="flex flex-row justify-center items-center w-full h-auto mt-12 sm:mt-24 bg-white dark:bg-zinc-900">
<div className="w-80 max-w-full h-full py-4 flex flex-col justify-start items-center"> <div className="w-80 max-w-full h-full py-4 flex flex-col justify-start items-center">
<div className="w-full py-4 grow flex flex-col justify-center items-center"> <div className="w-full py-4 grow flex flex-col justify-center items-center">
<div className="flex flex-row justify-start items-center w-auto mx-auto gap-y-2 mb-4"> <div className="flex flex-row justify-start items-center w-auto mx-auto gap-y-2 mb-4">
<img src="/logo.png" className="w-12 h-auto mr-2 -mt-1" alt="logo" /> <img src="/logo.png" className="w-12 h-auto mr-2 -mt-1" alt="logo" />
<span className="text-3xl opacity-80">Slash</span> <span className="text-3xl opacity-80 dark:text-gray-500">Slash</span>
</div> </div>
<p className="w-full text-2xl mt-6">Create your account</p> <p className="w-full text-2xl mt-6 dark:text-gray-500">Create your account</p>
<form className="w-full mt-4" onSubmit={handleSignupBtnClick}> <form className="w-full mt-4" onSubmit={handleSignupBtnClick}>
<div className={`flex flex-col justify-start items-start w-full ${actionBtnLoadingState.isLoading ? "opacity-80" : ""}`}> <div className={`flex flex-col justify-start items-start w-full ${actionBtnLoadingState.isLoading ? "opacity-80" : ""}`}>
<div className="w-full flex flex-col mb-2"> <div className="w-full flex flex-col mb-2">
@ -118,7 +118,7 @@ const SignUp: React.FC = () => {
</div> </div>
</form> </form>
<p className="w-full mt-4 text-sm"> <p className="w-full mt-4 text-sm">
<span>{"Already has an account?"}</span> <span className="dark:text-gray-500">{"Already has an account?"}</span>
<Link to="/auth" className="cursor-pointer ml-2 text-blue-600 hover:underline"> <Link to="/auth" className="cursor-pointer ml-2 text-blue-600 hover:underline">
Sign in Sign in
</Link> </Link>

View File

@ -1,6 +1,6 @@
import axios from "axios";
import { create } from "zustand"; import { create } from "zustand";
import { GetUserSettingResponse, UpdateUserSettingResponse, UserSetting } from "@/types/proto/api/v2/user_setting_service"; import { userSettingServiceClient } from "@/grpcweb";
import { UserSetting } from "@/types/proto/api/v2/user_setting_service";
import * as api from "../../helpers/api"; import * as api from "../../helpers/api";
const convertResponseModelUser = (user: User): User => { const convertResponseModelUser = (user: User): User => {
@ -95,12 +95,11 @@ const useUserStore = create<UserState>()((set, get) => ({
return userMap[currentUserId as UserId]; return userMap[currentUserId as UserId];
}, },
fetchUserSetting: async (userId: UserId) => { fetchUserSetting: async (userId: UserId) => {
const { const userSetting = (
data: { userSetting }, await userSettingServiceClient.getUserSetting({
} = await axios.get<GetUserSettingResponse>(`api/v2/users/${userId}/settings`); id: userId,
if (!userSetting) { })
throw new Error(`User setting not found for user ${userId}`); ).userSetting as UserSetting;
}
const userSettingMap = get().userSettingMapById; const userSettingMap = get().userSettingMapById;
userSettingMap[userId] = userSetting; userSettingMap[userId] = userSetting;
set(userSettingMap); set(userSettingMap);
@ -108,16 +107,13 @@ const useUserStore = create<UserState>()((set, get) => ({
}, },
updateUserSetting: async (userSetting: UserSetting, updateMask: string[]) => { updateUserSetting: async (userSetting: UserSetting, updateMask: string[]) => {
const userId = userSetting.id; const userId = userSetting.id;
const { const updatedUserSetting = (
data: { userSetting: updatedUserSetting }, await userSettingServiceClient.updateUserSetting({
} = await axios.post<UpdateUserSettingResponse>(`api/v2/users/${userId}/settings`, { id: userId,
id: userId, userSetting,
userSetting, updateMask,
updateMask, })
}); ).userSetting as UserSetting;
if (!updatedUserSetting) {
throw new Error(`User setting not found for user ${userId}`);
}
const userSettingMap = get().userSettingMapById; const userSettingMap = get().userSettingMapById;
userSettingMap[userId] = updatedUserSetting; userSettingMap[userId] = updatedUserSetting;
set(userSettingMap); set(userSettingMap);

View File

@ -37,8 +37,9 @@ message UserSetting {
enum ColorTheme { enum ColorTheme {
COLOR_THEME_UNSPECIFIED = 0; COLOR_THEME_UNSPECIFIED = 0;
COLOR_THEME_LIGHT = 1; COLOR_THEME_SYSTEM = 1;
COLOR_THEME_DARK = 2; COLOR_THEME_LIGHT = 2;
COLOR_THEME_DARK = 3;
} }
// color_theme is the user color theme. // color_theme is the user color theme.
ColorTheme color_theme = 3; ColorTheme color_theme = 3;

View File

@ -835,8 +835,9 @@
| Name | Number | Description | | Name | Number | Description |
| ---- | ------ | ----------- | | ---- | ------ | ----------- |
| COLOR_THEME_UNSPECIFIED | 0 | | | COLOR_THEME_UNSPECIFIED | 0 | |
| COLOR_THEME_LIGHT | 1 | | | COLOR_THEME_SYSTEM | 1 | |
| COLOR_THEME_DARK | 2 | | | COLOR_THEME_LIGHT | 2 | |
| COLOR_THEME_DARK | 3 | |

View File

@ -74,21 +74,24 @@ type UserSetting_ColorTheme int32
const ( const (
UserSetting_COLOR_THEME_UNSPECIFIED UserSetting_ColorTheme = 0 UserSetting_COLOR_THEME_UNSPECIFIED UserSetting_ColorTheme = 0
UserSetting_COLOR_THEME_LIGHT UserSetting_ColorTheme = 1 UserSetting_COLOR_THEME_SYSTEM UserSetting_ColorTheme = 1
UserSetting_COLOR_THEME_DARK UserSetting_ColorTheme = 2 UserSetting_COLOR_THEME_LIGHT UserSetting_ColorTheme = 2
UserSetting_COLOR_THEME_DARK UserSetting_ColorTheme = 3
) )
// Enum value maps for UserSetting_ColorTheme. // Enum value maps for UserSetting_ColorTheme.
var ( var (
UserSetting_ColorTheme_name = map[int32]string{ UserSetting_ColorTheme_name = map[int32]string{
0: "COLOR_THEME_UNSPECIFIED", 0: "COLOR_THEME_UNSPECIFIED",
1: "COLOR_THEME_LIGHT", 1: "COLOR_THEME_SYSTEM",
2: "COLOR_THEME_DARK", 2: "COLOR_THEME_LIGHT",
3: "COLOR_THEME_DARK",
} }
UserSetting_ColorTheme_value = map[string]int32{ UserSetting_ColorTheme_value = map[string]int32{
"COLOR_THEME_UNSPECIFIED": 0, "COLOR_THEME_UNSPECIFIED": 0,
"COLOR_THEME_LIGHT": 1, "COLOR_THEME_SYSTEM": 1,
"COLOR_THEME_DARK": 2, "COLOR_THEME_LIGHT": 2,
"COLOR_THEME_DARK": 3,
} }
) )
@ -402,7 +405,7 @@ var file_api_v2_user_setting_service_proto_rawDesc = []byte{
0x32, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x32, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e,
0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb6, 0x02, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xce, 0x02, 0x0a, 0x0b, 0x55, 0x73, 0x65,
0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x61, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68,
@ -416,66 +419,67 @@ var file_api_v2_user_setting_service_proto_rawDesc = []byte{
0x61, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x45, 0x5f, 0x55, 0x4e, 0x61, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x45, 0x5f, 0x55, 0x4e,
0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4c,
0x4f, 0x43, 0x41, 0x4c, 0x45, 0x5f, 0x45, 0x4e, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x4f, 0x4f, 0x43, 0x41, 0x4c, 0x45, 0x5f, 0x45, 0x4e, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x4f,
0x43, 0x41, 0x4c, 0x45, 0x5f, 0x5a, 0x48, 0x10, 0x02, 0x22, 0x56, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x43, 0x41, 0x4c, 0x45, 0x5f, 0x5a, 0x48, 0x10, 0x02, 0x22, 0x6e, 0x0a, 0x0a, 0x43, 0x6f, 0x6c,
0x6f, 0x72, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x6f, 0x72, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4c, 0x4f, 0x52,
0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49,
0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x5f, 0x54, 0x48, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x5f, 0x54, 0x48,
0x45, 0x4d, 0x45, 0x5f, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x45, 0x4d, 0x45, 0x5f, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11,
0x4f, 0x4c, 0x4f, 0x52, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x44, 0x41, 0x52, 0x4b, 0x10, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x4c, 0x49, 0x47, 0x48,
0x02, 0x22, 0x27, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x54, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x5f, 0x54, 0x48, 0x45,
0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x4d, 0x45, 0x5f, 0x44, 0x41, 0x52, 0x4b, 0x10, 0x03, 0x22, 0x27, 0x0a, 0x15, 0x47, 0x65, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x22, 0x56, 0x0a, 0x16, 0x47, 0x65, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65,
0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x69, 0x64, 0x22, 0x56, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74,
0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x0c,
0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76,
0x6e, 0x67, 0x22, 0x89, 0x01, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x75,
0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x89, 0x01, 0x0a, 0x18, 0x55,
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x3c, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3c, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x5f,
0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
0x52, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65,
0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x03, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x53, 0x65,
0x28, 0x09, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x59, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f,
0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61,
0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x75, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x59, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
0x73, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x0b, 0x32, 0x19, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74,
0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x6c, 0x61, 0x73,
0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x32, 0xb0, 0x02, 0x0a, 0x12, 0x55, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74,
0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x12, 0x85, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x67, 0x32, 0xb0, 0x02, 0x0a, 0x12, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x69, 0x6e, 0x67, 0x12, 0x23, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x85, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74,
0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x23, 0x2e, 0x73, 0x6c,
0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x1a, 0x24, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e,
0xda, 0x41, 0x02, 0x69, 0x64, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x61, 0x70, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65,
0x69, 0x2f, 0x76, 0x32, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0xda, 0x41, 0x02, 0x69, 0x64, 0x82, 0xd3, 0xe4,
0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x91, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x75, 0x73, 0x65,
0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x26, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x12, 0x91, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x53,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x26, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72,
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27,
0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70,
0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0xda, 0x41, 0x02, 0x69, 0x64, 0x82, 0xd3,
0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32,
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x73, 0x65, 0x74, 0x74,
0x2b, 0xda, 0x41, 0x02, 0x69, 0x64, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x69, 0x6e, 0x67, 0x73, 0x42, 0xae, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x6c, 0x61,
0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x42, 0x17, 0x55, 0x73, 0x65, 0x72, 0x53,
0x69, 0x64, 0x7d, 0x2f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0xae, 0x01, 0x0a, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f,
0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x32, 0x42, 0x17, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x2f, 0x62, 0x6f, 0x6f, 0x6a, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2f, 0x70,
0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6f, 0x6f, 0x6a, 0x61, 0x63, 0x6b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x53, 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x53, 0x6c,
0x2f, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x61, 0x73, 0x68, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x0c, 0x53, 0x6c, 0x61,
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x73, 0x68, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x18, 0x53, 0x6c, 0x61, 0x73,
0x53, 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x68, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61,
0x56, 0x32, 0xca, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x3a, 0x3a, 0x41, 0x70,
0x32, 0xe2, 0x02, 0x18, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x53,
0x6c, 0x61, 0x73, 0x68, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@ -234,8 +234,9 @@
| Name | Number | Description | | Name | Number | Description |
| ---- | ------ | ----------- | | ---- | ------ | ----------- |
| COLOR_THEME_USER_SETTING_UNSPECIFIED | 0 | | | COLOR_THEME_USER_SETTING_UNSPECIFIED | 0 | |
| COLOR_THEME_USER_SETTING_LIGHT | 1 | | | COLOR_THEME_USER_SETTING_SYSTEM | 1 | |
| COLOR_THEME_USER_SETTING_DARK | 2 | | | COLOR_THEME_USER_SETTING_LIGHT | 2 | |
| COLOR_THEME_USER_SETTING_DARK | 3 | |

View File

@ -128,21 +128,24 @@ type ColorThemeUserSetting int32
const ( const (
ColorThemeUserSetting_COLOR_THEME_USER_SETTING_UNSPECIFIED ColorThemeUserSetting = 0 ColorThemeUserSetting_COLOR_THEME_USER_SETTING_UNSPECIFIED ColorThemeUserSetting = 0
ColorThemeUserSetting_COLOR_THEME_USER_SETTING_LIGHT ColorThemeUserSetting = 1 ColorThemeUserSetting_COLOR_THEME_USER_SETTING_SYSTEM ColorThemeUserSetting = 1
ColorThemeUserSetting_COLOR_THEME_USER_SETTING_DARK ColorThemeUserSetting = 2 ColorThemeUserSetting_COLOR_THEME_USER_SETTING_LIGHT ColorThemeUserSetting = 2
ColorThemeUserSetting_COLOR_THEME_USER_SETTING_DARK ColorThemeUserSetting = 3
) )
// Enum value maps for ColorThemeUserSetting. // Enum value maps for ColorThemeUserSetting.
var ( var (
ColorThemeUserSetting_name = map[int32]string{ ColorThemeUserSetting_name = map[int32]string{
0: "COLOR_THEME_USER_SETTING_UNSPECIFIED", 0: "COLOR_THEME_USER_SETTING_UNSPECIFIED",
1: "COLOR_THEME_USER_SETTING_LIGHT", 1: "COLOR_THEME_USER_SETTING_SYSTEM",
2: "COLOR_THEME_USER_SETTING_DARK", 2: "COLOR_THEME_USER_SETTING_LIGHT",
3: "COLOR_THEME_USER_SETTING_DARK",
} }
ColorThemeUserSetting_value = map[string]int32{ ColorThemeUserSetting_value = map[string]int32{
"COLOR_THEME_USER_SETTING_UNSPECIFIED": 0, "COLOR_THEME_USER_SETTING_UNSPECIFIED": 0,
"COLOR_THEME_USER_SETTING_LIGHT": 1, "COLOR_THEME_USER_SETTING_SYSTEM": 1,
"COLOR_THEME_USER_SETTING_DARK": 2, "COLOR_THEME_USER_SETTING_LIGHT": 2,
"COLOR_THEME_USER_SETTING_DARK": 3,
} }
) )
@ -441,26 +444,28 @@ var file_store_user_setting_proto_rawDesc = []byte{
0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x45, 0x5f, 0x55, 0x53, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x45, 0x5f, 0x55, 0x53,
0x45, 0x52, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x4e, 0x10, 0x01, 0x12, 0x45, 0x52, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x4e, 0x10, 0x01, 0x12,
0x1a, 0x0a, 0x16, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x45, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x1a, 0x0a, 0x16, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x45, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53,
0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x5a, 0x48, 0x10, 0x02, 0x2a, 0x88, 0x01, 0x0a, 0x15, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x5a, 0x48, 0x10, 0x02, 0x2a, 0xad, 0x01, 0x0a, 0x15,
0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x28, 0x0a, 0x24, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x5f, 0x54, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x28, 0x0a, 0x24, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x5f, 0x54,
0x48, 0x45, 0x4d, 0x45, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e,
0x47, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x47, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12,
0x22, 0x0a, 0x1e, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x55, 0x23, 0x0a, 0x1f, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x55,
0x53, 0x45, 0x52, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x4c, 0x49, 0x47, 0x48, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x59, 0x53, 0x54,
0x54, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x5f, 0x54, 0x48, 0x45, 0x45, 0x4d, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x5f, 0x54, 0x48,
0x4d, 0x45, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x4d, 0x45, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47,
0x44, 0x41, 0x52, 0x4b, 0x10, 0x02, 0x42, 0x9a, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x5f, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x4f, 0x4c, 0x4f,
0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x10, 0x55, 0x73, 0x65, 0x72, 0x52, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x45, 0x54,
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x28, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x41, 0x52, 0x4b, 0x10, 0x03, 0x42, 0x9a, 0x01, 0x0a, 0x0f,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6f, 0x6f, 0x6a, 0x61, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42,
0x63, 0x6b, 0x2f, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x10, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74,
0x65, 0x6e, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0xa2, 0x02, 0x03, 0x53, 0x53, 0x58, 0xaa, 0x02, 0x6f, 0x50, 0x01, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x0b, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xca, 0x02, 0x0b, 0x53, 0x62, 0x6f, 0x6f, 0x6a, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2f, 0x70, 0x72,
0x6c, 0x61, 0x73, 0x68, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xe2, 0x02, 0x17, 0x53, 0x6c, 0x61, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0xa2, 0x02, 0x03,
0x73, 0x68, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x53, 0x53, 0x58, 0xaa, 0x02, 0x0b, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x53, 0x74, 0x6f, 0x72,
0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x3a, 0x3a, 0x53, 0x74, 0x65, 0xca, 0x02, 0x0b, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xe2,
0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x02, 0x17, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x5c, 0x47, 0x50,
0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73,
0x68, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@ -47,6 +47,7 @@ enum LocaleUserSetting {
enum ColorThemeUserSetting { enum ColorThemeUserSetting {
COLOR_THEME_USER_SETTING_UNSPECIFIED = 0; COLOR_THEME_USER_SETTING_UNSPECIFIED = 0;
COLOR_THEME_USER_SETTING_LIGHT = 1; COLOR_THEME_USER_SETTING_SYSTEM = 1;
COLOR_THEME_USER_SETTING_DARK = 2; COLOR_THEME_USER_SETTING_LIGHT = 2;
COLOR_THEME_USER_SETTING_DARK = 3;
} }

View File

@ -39,7 +39,8 @@ func (s *LicenseService) LoadSubscription(ctx context.Context) (*apiv2pb.Subscri
return nil, errors.Wrap(err, "failed to get workspace setting") return nil, errors.Wrap(err, "failed to get workspace setting")
} }
subscription := &apiv2pb.Subscription{ subscription := &apiv2pb.Subscription{
Plan: apiv2pb.PlanType_FREE, // NOTE: Default to pro plan for now.
Plan: apiv2pb.PlanType_PRO,
} }
licenseKey := "" licenseKey := ""
if workspaceSetting != nil { if workspaceSetting != nil {

View File

@ -186,6 +186,8 @@ func convertUserSettingLocaleFromString(s string) storepb.LocaleUserSetting {
func convertUserSettingColorThemeFromString(s string) storepb.ColorThemeUserSetting { func convertUserSettingColorThemeFromString(s string) storepb.ColorThemeUserSetting {
switch s { switch s {
case "COLOR_THEME_USER_SETTING_SYSTEM":
return storepb.ColorThemeUserSetting_COLOR_THEME_USER_SETTING_SYSTEM
case "COLOR_THEME_USER_SETTING_LIGHT": case "COLOR_THEME_USER_SETTING_LIGHT":
return storepb.ColorThemeUserSetting_COLOR_THEME_USER_SETTING_LIGHT return storepb.ColorThemeUserSetting_COLOR_THEME_USER_SETTING_LIGHT
case "COLOR_THEME_USER_SETTING_DARK": case "COLOR_THEME_USER_SETTING_DARK":