Przeglądaj źródła

feat: Supports switching between dark and bright themes

Apple\Apple 1 rok temu
rodzic
commit
6ab24312ce

+ 28 - 1
src/components/HeaderBar.js

@@ -1,7 +1,15 @@
 import { Nav, Typography } from '@douyinfe/semi-ui';
 import { IconTag } from '@douyinfe/semi-icons-lab';
+import {
+  IconGithubLogo,
+  IconMoon,
+  IconSun,
+} from '@douyinfe/semi-icons';
+import { useSetTheme, useTheme } from '../context/Theme';
 
 const HeaderBar = () => {
+  const theme = useTheme();
+  const setTheme = useSetTheme();
 
   return (
     <div
@@ -25,7 +33,26 @@ const HeaderBar = () => {
           }
         }
         footer={
-          <Typography.Text link={{ href: 'https://github.com/Calcium-Ion/neko-api-key-tool' }}>Copyright © 2024 NewAPI. All Rights Reserved.</Typography.Text>
+          <>
+            {theme === 'dark' ? (
+              <IconSun
+                size="large"
+                style={{ cursor: 'pointer', marginRight: '10px', color: 'var(--semi-color-text-2)' }}
+                onClick={() => setTheme(false)}
+              />
+            ) : (
+              <IconMoon
+                size="large"
+                style={{ cursor: 'pointer', marginRight: '10px', color: 'var(--semi-color-text-2)' }}
+                onClick={() => setTheme(true)}
+              />
+            )}
+            <IconGithubLogo
+              size="large"
+              style={{ cursor: 'pointer', marginRight: '10px', color: 'var(--semi-color-text-2)' }}
+              onClick={() => window.open('https://github.com/Calcium-Ion/neko-api-key-tool', '_blank')}
+            />
+          </>
         }
       />
     </div>

+ 2 - 2
src/components/LogsTable.js

@@ -330,7 +330,7 @@ const LogsTable = () => {
                     showClear
                     value={key}
                     onChange={(value) => setKey(value)}
-                    placeholder="请输入要查询的令牌sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+                    placeholder="请输入要查询的令牌 sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
                     prefix={<IconSearch />}
                     suffix={
                         <Button
@@ -396,7 +396,7 @@ const LogsTable = () => {
                             itemKey="2"
                             extra={
                                 <div style={{ display: 'flex', alignItems: 'center' }}>
-                                    <Tag color='green' style={{ marginRight: 5 }}>计算汇率:$1 = 50 0000 tokens</Tag>
+                                    <Tag shape='circle' color='green' style={{ marginRight: 5 }}>计算汇率:$1 = 50 0000 tokens</Tag>
                                     <Button icon={<IconDownload />} theme='borderless' type='primary' onClick={(e) => exportCSV(e)} disabled={!tokenValid || logs.length === 0}>
                                         导出为CSV文件
                                     </Button>

+ 36 - 0
src/context/Theme/index.js

@@ -0,0 +1,36 @@
+import { createContext, useCallback, useContext, useState } from 'react';
+
+const ThemeContext = createContext(null);
+export const useTheme = () => useContext(ThemeContext);
+
+const SetThemeContext = createContext(null);
+export const useSetTheme = () => useContext(SetThemeContext);
+
+export const ThemeProvider = ({ children }) => {
+  const [theme, _setTheme] = useState(() => {
+    try {
+      return localStorage.getItem('theme-mode') || null;
+    } catch {
+      return null;
+    }
+  });
+
+  const setTheme = useCallback((input) => {
+    _setTheme(input ? 'dark' : 'light');
+
+    const body = document.body;
+    if (!input) {
+      body.removeAttribute('theme-mode');
+      localStorage.setItem('theme-mode', 'light');
+    } else {
+      body.setAttribute('theme-mode', 'dark');
+      localStorage.setItem('theme-mode', 'dark');
+    }
+  }, []);
+
+  return (
+    <SetThemeContext.Provider value={setTheme}>
+      <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>
+    </SetThemeContext.Provider>
+  );
+};

+ 3 - 9
src/index.css

@@ -1,14 +1,8 @@
-/* body {
-  margin: 0;
-  padding-top: 55px;
-  overflow-y: scroll;
-  font-family: Lato, 'Helvetica Neue', Arial, Helvetica, "Microsoft YaHei", sans-serif;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-  scrollbar-width: none;
+body {
+  background-color: var(--semi-color-bg-0);
 }
 
-body::-webkit-scrollbar {
+/* body::-webkit-scrollbar {
   display: none;
 }
 

+ 11 - 8
src/index.js

@@ -6,20 +6,23 @@ import HeaderBar from './components/HeaderBar';
 import reportWebVitals from './reportWebVitals';
 import 'semantic-ui-css/semantic.min.css';
 import './index.css';
+import { ThemeProvider } from './context/Theme';
 
 const root = ReactDOM.createRoot(document.getElementById('root'));
 const { Sider, Content, Header } = Layout;
 root.render(
-  <Layout>
-    <Header>
-      <HeaderBar />
-    </Header>
+  <ThemeProvider>
     <Layout>
-      <Content style={{ padding: 24 }}>
-        <App />
-      </Content>
+      <Header>
+        <HeaderBar />
+      </Header>
+      <Layout>
+        <Content style={{ padding: 24 }}>
+          <App />
+        </Content>
+      </Layout>
     </Layout>
-  </Layout>
+  </ThemeProvider>
 );
 
 // If you want to start measuring performance in your app, pass a function