From c4de3b0d6fd05f242a0f5a3d013bb06190d61e50 Mon Sep 17 00:00:00 2001 From: boojack Date: Wed, 12 Apr 2023 11:05:25 +0800 Subject: [PATCH] feat: implement dark mode (#27) * feat: implement dark mode * feat: update data table dark mode style * chore: update --- src/components/ConnectionSidebar.tsx | 34 ++++++++-------- src/components/ConversationView/Header.tsx | 6 +-- .../ConversationView/MessageTextarea.tsx | 4 +- .../ConversationView/MessageView.tsx | 14 +++---- .../ConversationView/ThreeDotsLoader.tsx | 30 ++++++++++++++ src/components/ConversationView/index.tsx | 6 +-- src/components/CreateConnectionModal.tsx | 2 +- src/components/DataStorageBanner.tsx | 2 +- src/components/EmptyView.tsx | 16 +++++--- src/components/LocaleSwitch.tsx | 7 +++- src/components/MessageLoader.tsx | 25 ------------ src/components/OpenAIApiConfigView.tsx | 2 +- src/components/QueryDrawer.tsx | 15 +++++-- src/components/SettingModal.tsx | 9 ++++- src/components/ThemeSelector.tsx | 36 +++++++++++++++++ src/components/ThemeSwitch.tsx | 23 +++++++++++ src/components/kit/Dialog.tsx | 6 +-- src/components/kit/Select.tsx | 10 +++-- src/components/kit/TextField.tsx | 2 +- src/pages/_app.tsx | 39 +++++++++++++++++++ src/pages/index.tsx | 2 +- src/store/setting.ts | 13 ++++++- src/styles/data-table.css | 13 ++++++- src/styles/global.css | 3 +- src/styles/mui.css | 3 ++ src/styles/tailwind.css | 2 +- src/types/setting.ts | 3 ++ tailwind.config.js | 1 + 28 files changed, 243 insertions(+), 85 deletions(-) create mode 100644 src/components/ConversationView/ThreeDotsLoader.tsx delete mode 100644 src/components/MessageLoader.tsx create mode 100644 src/components/ThemeSelector.tsx create mode 100644 src/components/ThemeSwitch.tsx create mode 100644 src/styles/mui.css diff --git a/src/components/ConnectionSidebar.tsx b/src/components/ConnectionSidebar.tsx index 69c5f6a..a2ae5c7 100644 --- a/src/components/ConnectionSidebar.tsx +++ b/src/components/ConnectionSidebar.tsx @@ -161,10 +161,12 @@ const ConnectionSidebar = () => { onClose={() => layoutStore.toggleSidebar(false)} >
-
+
))}
-
+
{isRequestingDatabase && ( -
+
{t("common.loading")}
)} {databaseList.length > 0 && (
{
diff --git a/src/components/EmptyView.tsx b/src/components/EmptyView.tsx index 77f5472..13aa65e 100644 --- a/src/components/EmptyView.tsx +++ b/src/components/EmptyView.tsx @@ -53,7 +53,7 @@ const EmptyView = (props: Props) => { {examples.map((example) => (
handleExampleClick(example)} > {`"${example}"`} → @@ -63,14 +63,20 @@ const EmptyView = (props: Props) => {
Capabilities -
Remembers what user said earlier in the conversation
-
Allows user to provide follow-up corrections
+
+ Remembers what user said earlier in the conversation +
+
+ Allows user to provide follow-up corrections +
Limitations -
May occasionally generate incorrect information
-
+
+ May occasionally generate incorrect information +
+
May occasionally produce harmful instructions or biased content
diff --git a/src/components/LocaleSwitch.tsx b/src/components/LocaleSwitch.tsx index eee2458..3be9c6b 100644 --- a/src/components/LocaleSwitch.tsx +++ b/src/components/LocaleSwitch.tsx @@ -14,8 +14,11 @@ const LocaleSwitch = () => { }; return ( - ); }; diff --git a/src/components/MessageLoader.tsx b/src/components/MessageLoader.tsx deleted file mode 100644 index 603baa0..0000000 --- a/src/components/MessageLoader.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { ThreeDots } from "react-loader-spinner"; -import { useConnectionStore } from "@/store"; -import EngineIcon from "./EngineIcon"; - -const MessageLoader = () => { - const connectionStore = useConnectionStore(); - const connection = connectionStore.currentConnectionCtx?.connection; - - return ( -
-
- {connection ? ( - - ) : ( - - )} -
-
- -
-
- ); -}; - -export default MessageLoader; diff --git a/src/components/OpenAIApiConfigView.tsx b/src/components/OpenAIApiConfigView.tsx index 27ef770..7e70fd2 100644 --- a/src/components/OpenAIApiConfigView.tsx +++ b/src/components/OpenAIApiConfigView.tsx @@ -28,7 +28,7 @@ const OpenAIApiConfigView = () => { return ( <>

{t("setting.openai-api-configuration.self")}

-
+
{ return ( -
+
@@ -101,7 +101,7 @@ const QueryDrawer = () => { {context.database?.name}
-
+
{ onChange={(e) => setStatement(e.target.value)} />
) : (
- +
)}
diff --git a/src/components/SettingModal.tsx b/src/components/SettingModal.tsx index dd66139..711c6a4 100644 --- a/src/components/SettingModal.tsx +++ b/src/components/SettingModal.tsx @@ -4,6 +4,7 @@ import Icon from "./Icon"; import WeChatQRCodeView from "./WeChatQRCodeView"; import ClearDataButton from "./ClearDataButton"; import LocaleSelector from "./LocaleSelector"; +import ThemeSelector from "./ThemeSelector"; import OpenAIApiConfigView from "./OpenAIApiConfigView"; interface Props { @@ -30,17 +31,21 @@ const SettingModal = (props: Props) => {

{t("setting.basic.self")}

-
+
{t("setting.basic.language")}
+
+ Theme + +

{t("setting.data.self")}

-
+
{t("setting.data.clear-all-data")} diff --git a/src/components/ThemeSelector.tsx b/src/components/ThemeSelector.tsx new file mode 100644 index 0000000..8b5207d --- /dev/null +++ b/src/components/ThemeSelector.tsx @@ -0,0 +1,36 @@ +import { useSettingStore } from "@/store"; +import { Theme } from "@/types"; +import Select from "./kit/Select"; + +interface ThemeItem { + value: Theme; + label: string; +} + +const themeItemList: ThemeItem[] = [ + { + value: "system", + label: "System", + }, + { + value: "light", + label: "Light", + }, + { + value: "dark", + label: "Dark", + }, +]; + +const ThemeSelector = () => { + const settingStore = useSettingStore(); + const theme = settingStore.setting.theme; + + const handleThemeChange = (theme: Theme) => { + settingStore.setTheme(theme); + }; + + return { + const darkMediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); + const handleColorSchemeChange = (e: MediaQueryListEvent) => { + if (settingStore.getState().setting.theme === "system") { + const theme = e.matches ? "dark" : "light"; + document.documentElement.classList.remove("dark"); + document.documentElement.classList.remove("light"); + document.documentElement.classList.add(theme); + } + }; + + try { + if (darkMediaQuery.addEventListener) { + darkMediaQuery.addEventListener("change", handleColorSchemeChange); + } else { + darkMediaQuery.addListener(handleColorSchemeChange); + } + } catch (error) { + console.error("failed to initial color scheme listener", error); + } + }, []); + useEffect(() => { const locale = settingStore.setting.locale; i18n.changeLanguage(locale); document.documentElement.setAttribute("lang", locale); }, [settingStore.setting.locale]); + useEffect(() => { + const theme = settingStore.setting.theme; + let currentAppearance = theme; + if (theme === "system") { + if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) { + currentAppearance = "dark"; + } else { + currentAppearance = "light"; + } + } + + document.documentElement.classList.remove("dark"); + document.documentElement.classList.remove("light"); + document.documentElement.classList.add(currentAppearance); + }, [settingStore.setting.theme]); + return ( <> diff --git a/src/pages/index.tsx b/src/pages/index.tsx index c702f02..120f09e 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -33,7 +33,7 @@ const IndexPage: NextPage = () => {

SQL Chat

-
+
diff --git a/src/store/setting.ts b/src/store/setting.ts index 928361d..7086e4c 100644 --- a/src/store/setting.ts +++ b/src/store/setting.ts @@ -6,6 +6,7 @@ import { Setting } from "@/types"; const getDefaultSetting = (): Setting => { return { locale: "en", + theme: "system", openAIApiConfig: { key: "", endpoint: "", @@ -15,15 +16,17 @@ const getDefaultSetting = (): Setting => { interface SettingState { setting: Setting; + getState: () => SettingState; setLocale: (locale: Setting["locale"]) => void; + setTheme: (theme: Setting["theme"]) => void; setOpenAIApiConfig: (openAIApiConfig: Setting["openAIApiConfig"]) => void; } export const useSettingStore = create()( persist( (set, get) => ({ - getState: () => get(), setting: getDefaultSetting(), + getState: () => get(), setLocale: (locale: Setting["locale"]) => { set({ setting: { @@ -32,6 +35,14 @@ export const useSettingStore = create()( }, }); }, + setTheme: (theme: Setting["theme"]) => { + set({ + setting: { + ...get().setting, + theme, + }, + }); + }, setOpenAIApiConfig: (openAIApiConfig: Setting["openAIApiConfig"]) => { set({ setting: { diff --git a/src/styles/data-table.css b/src/styles/data-table.css index 91b7b04..48e0221 100644 --- a/src/styles/data-table.css +++ b/src/styles/data-table.css @@ -1,3 +1,14 @@ .rdt_Pagination { - border-top: none !important; + @apply !border-t-0 dark:bg-zinc-800 dark:text-gray-300; +} + +.rdt_Pagination button { + @apply dark:bg-zinc-800 dark:text-gray-300 dark:fill-gray-300; +} + +.rdt_Table, +.rdt_TableHead, +.rdt_TableHeadRow, +.rdt_TableRow { + @apply dark:bg-zinc-800 dark:text-gray-300; } diff --git a/src/styles/global.css b/src/styles/global.css index 8804001..5d919ff 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -3,6 +3,5 @@ body, body > div:first-child, div#__next, div#__next > div { - width: 100%; - height: 100%; + @apply w-full h-full dark:text-gray-300; } diff --git a/src/styles/mui.css b/src/styles/mui.css new file mode 100644 index 0000000..5681eab --- /dev/null +++ b/src/styles/mui.css @@ -0,0 +1,3 @@ +.MuiPaper-root { + @apply dark:bg-zinc-800; +} diff --git a/src/styles/tailwind.css b/src/styles/tailwind.css index d875fdd..bf80933 100644 --- a/src/styles/tailwind.css +++ b/src/styles/tailwind.css @@ -19,7 +19,7 @@ } .btn-outline { - @apply border-none hover:bg-gray-100; + @apply border-none hover:bg-gray-100 dark:hover:bg-zinc-800; } .btn-error { diff --git a/src/types/setting.ts b/src/types/setting.ts index 8b0eaa4..cc2c97c 100644 --- a/src/types/setting.ts +++ b/src/types/setting.ts @@ -1,5 +1,7 @@ export type Locale = "en" | "zh"; +export type Theme = "light" | "dark" | "system"; + export interface OpenAIApiConfig { key: string; endpoint: string; @@ -7,5 +9,6 @@ export interface OpenAIApiConfig { export interface Setting { locale: Locale; + theme: Theme; openAIApiConfig: OpenAIApiConfig; } diff --git a/tailwind.config.js b/tailwind.config.js index a34a0a5..72df87b 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,6 +1,7 @@ /** @type {import('tailwindcss').Config} */ module.exports = { content: ["./src/pages/**/*.{js,ts,jsx,tsx}", "./src/components/**/*.{js,ts,jsx,tsx}"], + darkMode: "class", theme: { extend: { zIndex: {