Просмотр исходного кода

feat: 侧边栏移动端优化

CalciumIon 1 год назад
Родитель
Сommit
3622c664b6

+ 27 - 26
web/src/components/HeaderBar.js

@@ -9,17 +9,19 @@ import '../index.css';
 import fireworks from 'react-fireworks';
 
 import {
+  IconClose,
   IconHelpCircle,
   IconHome,
-  IconHomeStroked,
-  IconKey,
+  IconHomeStroked, IconIndentLeft,
+  IconKey, IconMenu,
   IconNoteMoneyStroked,
   IconPriceTag,
   IconUser
 } from '@douyinfe/semi-icons';
-import { Avatar, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
+import { Avatar, Button, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
 import { stringToColor } from '../helpers/render';
 import Text from '@douyinfe/semi-ui/lib/es/typography/text';
+import { StyleContext } from '../context/Style/index.js';
 
 // HeaderBar Buttons
 let headerButtons = [
@@ -36,14 +38,7 @@ let buttons = [
     text: '首页',
     itemKey: 'home',
     to: '/',
-    // icon: <IconHomeStroked />,
   },
-  // {
-  //   text: 'Playground',
-  //   itemKey: 'playground',
-  //   to: '/playground',
-  //   // icon: <IconNoteMoneyStroked />,
-  // },
 ];
 
 if (localStorage.getItem('chat_link')) {
@@ -56,9 +51,9 @@ if (localStorage.getItem('chat_link')) {
 
 const HeaderBar = () => {
   const [userState, userDispatch] = useContext(UserContext);
+  const [styleState, styleDispatch] = useContext(StyleContext);
   let navigate = useNavigate();
 
-  const [showSidebar, setShowSidebar] = useState(false);
   const systemName = getSystemName();
   const logo = getLogo();
   const currentDate = new Date();
@@ -70,7 +65,6 @@ const HeaderBar = () => {
       currentDate.getDate() <= 24);
 
   async function logout() {
-    setShowSidebar(false);
     await API.get('/api/user/logout');
     showSuccess('注销成功!');
     userDispatch({ type: 'logout' });
@@ -128,16 +122,25 @@ const HeaderBar = () => {
             selectedKeys={[]}
             // items={headerButtons}
             onSelect={(key) => {}}
-            header={isMobile()?{
+            header={styleState.isMobile?{
               logo: (
-                <img src={logo} alt='logo' style={{ marginRight: '0.75em' }} />
+                <>
+                  {
+                    styleState.showSider ?
+                      <Button icon={<IconMenu />} theme="light" style={{ marginRight: 10 }} aria-label="展开侧边栏" onClick={
+                        () => styleDispatch({ type: 'SET_SIDER', payload: false })
+                      } />:
+                      <Button icon={<IconIndentLeft />} theme="light" style={{ marginRight: 10 }} aria-label="关闭侧边栏" onClick={
+                        () => styleDispatch({ type: 'SET_SIDER', payload: true })
+                      } />
+                  }
+                </>
               ),
             }:{
               logo: (
                 <img src={logo} alt='logo' />
               ),
               text: systemName,
-
             }}
             items={buttons}
             footer={
@@ -159,17 +162,15 @@ const HeaderBar = () => {
                 )}
                 <Nav.Item itemKey={'about'} icon={<IconHelpCircle />} />
                 <>
-                {!isMobile() && (
-                    <Switch
-                      checkedText='🌞'
-                      size={'large'}
-                      checked={theme === 'dark'}
-                      uncheckedText='🌙'
-                      onChange={(checked) => {
-                        setTheme(checked);
-                      }}
-                    />
-                  )}
+                  <Switch
+                    checkedText='🌞'
+                    size={'large'}
+                    checked={theme === 'dark'}
+                    uncheckedText='🌙'
+                    onChange={(checked) => {
+                      setTheme(checked);
+                    }}
+                  />
                 </>
                 {userState.user ? (
                   <>

+ 40 - 0
web/src/components/PageLayout.js

@@ -0,0 +1,40 @@
+import HeaderBar from './HeaderBar.js';
+import { Layout } from '@douyinfe/semi-ui';
+import SiderBar from './SiderBar.js';
+import App from '../App.js';
+import FooterBar from './Footer.js';
+import { ToastContainer } from 'react-toastify';
+import React, { useContext } from 'react';
+import { StyleContext } from '../context/Style/index.js';
+const { Sider, Content, Header, Footer } = Layout;
+
+
+const PageLayout = () => {
+  const [styleState, styleDispatch] = useContext(StyleContext);
+
+  return (
+    <Layout style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
+      <Header>
+        <HeaderBar />
+      </Header>
+      <Layout style={{ flex: 1, overflow: 'hidden' }}>
+        <Sider>
+          {styleState.showSider ? null : <SiderBar />}
+        </Sider>
+        <Layout>
+          <Content
+            style={{ overflowY: 'auto', padding: '24px' }}
+          >
+            <App />
+          </Content>
+          <Layout.Footer>
+            <FooterBar></FooterBar>
+          </Layout.Footer>
+        </Layout>
+      </Layout>
+      <ToastContainer />
+    </Layout>
+  )
+}
+
+export default PageLayout;

+ 3 - 15
web/src/components/SiderBar.js

@@ -31,14 +31,15 @@ import { Avatar, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
 import { setStatusData } from '../helpers/data.js';
 import { stringToColor } from '../helpers/render.js';
 import { useSetTheme, useTheme } from '../context/Theme/index.js';
+import { StyleContext } from '../context/Style/index.js';
 
 // HeaderBar Buttons
 
 const SiderBar = () => {
-  const [userState, userDispatch] = useContext(UserContext);
+  const [styleState, styleDispatch] = useContext(StyleContext);
   const [statusState, statusDispatch] = useContext(StatusContext);
   const defaultIsCollapsed =
-    isMobile() || localStorage.getItem('default_collapse_sidebar') === 'true';
+    localStorage.getItem('default_collapse_sidebar') === 'true';
 
   const [selectedKeys, setSelectedKeys] = useState(['home']);
   const [isCollapsed, setIsCollapsed] = useState(defaultIsCollapsed);
@@ -196,7 +197,6 @@ const SiderBar = () => {
   useEffect(() => {
     loadStatus().then(() => {
       setIsCollapsed(
-        isMobile() ||
           localStorage.getItem('default_collapse_sidebar') === 'true',
       );
     });
@@ -239,7 +239,6 @@ const SiderBar = () => {
       <Nav
         style={{ maxWidth: 220, height: '100%' }}
         defaultIsCollapsed={
-          isMobile() ||
           localStorage.getItem('default_collapse_sidebar') === 'true'
         }
         isCollapsed={isCollapsed}
@@ -284,17 +283,6 @@ const SiderBar = () => {
         }}
         footer={
           <>
-            {isMobile() && (
-              <Switch
-                checkedText='🌞'
-                size={'small'}
-                checked={theme === 'dark'}
-                uncheckedText='🌙'
-                onChange={(checked) => {
-                  setTheme(checked);
-                }}
-              />
-            )}
           </>
         }
       >

+ 57 - 0
web/src/context/Style/index.js

@@ -0,0 +1,57 @@
+// contexts/User/index.jsx
+
+import React, { useState, useEffect } from 'react';
+import { isMobile } from '../../helpers/index.js';
+
+export const StyleContext = React.createContext({
+  dispatch: () => null,
+});
+
+export const StyleProvider = ({ children }) => {
+  const [state, setState] = useState({
+    isMobile: false,
+    showSider: false,
+  });
+
+  const dispatch = (action) => {
+    if ('type' in action) {
+      switch (action.type) {
+        case 'TOGGLE_SIDER':
+          setState(prev => ({ ...prev, showSider: !prev.showSider }));
+          break;
+        case 'SET_SIDER':
+          setState(prev => ({ ...prev, showSider: action.payload }));
+          break;
+        case 'SET_MOBILE':
+          setState(prev => ({ ...prev, isMobile: action.payload }));
+          break;
+        default:
+          setState(prev => ({ ...prev, ...action }));
+      }
+    } else {
+      setState(prev => ({ ...prev, ...action }));
+    }
+  };
+
+  useEffect(() => {
+    const updateIsMobile = () => {
+      dispatch({ type: 'SET_MOBILE', payload: isMobile() });
+    };
+
+    updateIsMobile();
+
+    // Optionally, add event listeners to handle window resize
+    window.addEventListener('resize', updateIsMobile);
+
+    // Cleanup event listener on component unmount
+    return () => {
+      window.removeEventListener('resize', updateIsMobile);
+    };
+  }, []);
+
+  return (
+    <StyleContext.Provider value={[state, dispatch]}>
+      {children}
+    </StyleContext.Provider>
+  );
+};

+ 5 - 21
web/src/index.js

@@ -13,6 +13,8 @@ import { Layout } from '@douyinfe/semi-ui';
 import SiderBar from './components/SiderBar';
 import { ThemeProvider } from './context/Theme';
 import FooterBar from './components/Footer';
+import { StyleProvider } from './context/Style/index.js';
+import PageLayout from './components/PageLayout.js';
 
 // initialization
 
@@ -24,27 +26,9 @@ root.render(
       <UserProvider>
         <BrowserRouter>
           <ThemeProvider>
-            <Layout style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
-              <Header>
-                <HeaderBar />
-              </Header>
-              <Layout style={{ flex: 1, overflow: 'hidden' }}>
-                <Sider>
-                  <SiderBar />
-                </Sider>
-                <Layout>
-                  <Content
-                    style={{ overflowY: 'auto', padding: '24px' }}
-                  >
-                    <App />
-                  </Content>
-                  <Layout.Footer>
-                    <FooterBar></FooterBar>
-                  </Layout.Footer>
-                </Layout>
-              </Layout>
-              <ToastContainer />
-            </Layout>
+            <StyleProvider>
+              <PageLayout/>
+            </StyleProvider>
           </ThemeProvider>
         </BrowserRouter>
       </UserProvider>