Ver Fonte

no message

zhejiushizhuce há 2 anos atrás
pai
commit
8a235cff0a

+ 1 - 0
package.json

@@ -46,6 +46,7 @@
     "react": "^18.2.0",
     "react-big-calendar": "^1.6.8",
     "react-calendar": "^4.0.0",
+    "react-copy-to-clipboard": "^5.1.0",
     "react-countup": "^6.4.1",
     "react-dom": "^18.2.0",
     "react-ga4": "^2.1.0",

+ 1 - 1
public/index.html

@@ -4,7 +4,7 @@
     <meta charset="utf-8" />
     <!-- <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> -->
     <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text x=%2250%%22 y=%2250%%22 style=%22dominant-baseline:central;text-anchor:middle;font-size:110px;%22>🍒</text></svg>" />
-    <meta name="viewport" content="width=device-width, initial-scale=1" />
+    <meta name="viewport" content="width=device-width, initial-scale=1,minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
     <title>24680.com - Casino & Sports & Racing</title>
     <link rel="preconnect" href="https://fonts.googleapis.com">
     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

+ 15 - 0
src/assets/avatar_empty.svg

@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="65" height="65" viewBox="0 0 65 65" fill="none">
+    <g clip-path="url(#clip0_1729_2794)">
+        <rect x="0.5" y="0.5" width="64" height="64" rx="32" fill="white">
+        </rect>
+        <rect x="19.1667" y="11.1667" width="26.6667" height="26.6667" rx="13.3333" fill="#98A7B5">
+        </rect>
+        <rect x="-15.5" y="43.1667" width="96" height="96" rx="48" fill="#98A7B5">
+        </rect>
+    </g>
+    <defs>
+        <clipPath id="clip0_1729_2794">
+            <rect x="0.5" y="0.5" width="64" height="64" rx="32" fill="white"></rect>
+        </clipPath>
+    </defs>
+</svg>

+ 19 - 0
src/assets/gener/female.svg

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="-3 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    
+    <title>female [#1363]</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+
+</defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Dribbble-Light-Preview" transform="translate(-103.000000, -2079.000000)" fill="#000000">
+            <g id="icons" transform="translate(56.000000, 160.000000)">
+                <path d="M54.010058,1930.97067 C52.6753909,1930.97067 51.421643,1930.45194 50.4775859,1929.51025 C47.3327267,1926.36895 49.5904718,1920.99511 54.010058,1920.99511 C58.4266471,1920.99511 60.6903863,1926.36595 57.5425301,1929.51025 C56.5984729,1930.45194 55.344725,1930.97067 54.010058,1930.97067 M58.9411333,1930.92079 C63.3617184,1926.50661 60.1768991,1919 54.007061,1919 C47.8512088,1919 44.6294265,1926.50661 49.0510106,1930.92079 C50.1609021,1932.02908 51.9840813,1932.67949 52.9830836,1932.88598 L52.9830836,1935.00978 L49.9860767,1935.00978 L49.9860767,1937.00489 L52.9830836,1937.00489 L52.9830836,1939 L54.9810882,1939 L54.9810882,1937.00489 L57.9780951,1937.00489 L57.9780951,1935.00978 L54.9810882,1935.00978 L54.9810882,1932.88598 C56.9790928,1932.67949 57.8302427,1932.02908 58.9411333,1930.92079" id="female-[#1363]">
+
+</path>
+            </g>
+        </g>
+    </g>
+</svg>

+ 27 - 0
src/assets/gener/gender.svg

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg height="800px" width="800px" version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 
+	 viewBox="0 0 512 512"  xml:space="preserve">
+<g>
+	<path class="st0" d="M474.234,284.88c23.29-23.268,37.781-55.654,37.766-91.185c0.015-35.53-14.476-67.917-37.766-91.178
+		c-23.261-23.298-55.64-37.788-91.185-37.766c-35.53-0.022-67.924,14.469-91.17,37.766c-23.304,23.261-37.795,55.648-37.78,91.178
+		c-0.015,35.53,14.476,67.916,37.78,91.185c19.268,19.297,44.809,32.517,73.21,36.488v52.976h-58.486v35.944h58.486v56.766h35.937
+		v-56.766h58.486v-35.944h-58.486v-52.976C429.426,317.397,454.966,304.177,474.234,284.88z M383.049,275.921
+		c-11.413-0.008-22.172-2.301-32.002-6.454c-14.724-6.222-27.327-16.684-36.198-29.817c-8.857-13.147-14.012-28.844-14.012-45.955
+		c0-11.42,2.294-22.172,6.447-31.994c6.214-14.731,16.669-27.326,29.81-36.198c13.155-8.864,28.85-14.019,45.955-14.034
+		c11.413,0.008,22.172,2.302,32.002,6.462c14.724,6.214,27.327,16.676,36.198,29.809c8.857,13.156,14.012,28.851,14.026,45.956
+		c-0.014,11.42-2.308,22.172-6.461,31.995c-6.214,14.73-16.683,27.333-29.81,36.198
+		C415.849,270.759,400.168,275.907,383.049,275.921z"/>
+	<path class="st0" d="M146.912,202.305v-88.55l35.69,35.683l25.424-25.41l-79.075-79.082l-79.09,79.082l25.41,25.41l35.704-35.69
+		v88.557c-28.401,3.978-53.941,17.199-73.209,36.502C14.462,262.069-0.014,294.448,0,329.979
+		c-0.014,35.545,14.462,67.924,37.766,91.184c23.261,23.305,55.64,37.788,91.185,37.774c35.53,0.014,67.91-14.469,91.17-37.774
+		c23.304-23.261,37.78-55.64,37.78-91.184c0-35.53-14.476-67.91-37.78-91.171C200.854,219.505,175.313,206.283,146.912,202.305z
+		 M204.716,361.981c-6.229,14.73-16.683,27.326-29.81,36.198c-13.154,8.872-28.85,14.027-45.955,14.027
+		c-11.427,0-22.172-2.294-32.002-6.447c-14.723-6.229-27.327-16.684-36.198-29.817c-8.872-13.155-14.026-28.844-14.026-45.962
+		c0-11.412,2.294-22.164,6.446-31.987c6.229-14.723,16.684-27.326,29.824-36.198c13.14-8.864,28.836-14.011,45.955-14.026
+		c11.413,0,22.157,2.294,32.002,6.454c14.709,6.222,27.312,16.676,36.184,29.809c8.871,13.156,14.026,28.844,14.026,45.948
+		C211.163,341.405,208.868,352.165,204.716,361.981z"/>
+</g>
+</svg>

+ 19 - 0
src/assets/gener/male.svg

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    
+    <title>male [#1364]</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+
+</defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Dribbble-Light-Preview" transform="translate(-60.000000, -2079.000000)" fill="#000000">
+            <g id="icons" transform="translate(56.000000, 160.000000)">
+                <path d="M11,1937.005 C8.243,1937.005 6,1934.762 6,1932.005 C6,1929.248 8.243,1927.005 11,1927.005 C13.757,1927.005 16,1929.248 16,1932.005 C16,1934.762 13.757,1937.005 11,1937.005 L11,1937.005 Z M16,1919 L16,1921 L20.586,1921 L15.186,1926.402 C14.018,1925.527 12.572,1925.004 11,1925.004 C7.134,1925.004 4,1928.138 4,1932.004 C4,1935.87 7.134,1939.005 11,1939.005 C14.866,1939.005 18,1935.871 18,1932.005 C18,1930.433 17.475,1928.987 16.601,1927.818 L22,1922.419 L22,1927 L24,1927 L24,1919 L16,1919 Z" id="male-[#1364]">
+
+</path>
+            </g>
+        </g>
+    </g>
+</svg>

+ 2 - 0
src/components/SmallLoading/styles.module.scss

@@ -1,9 +1,11 @@
 .loading{
   display: flex;
+  position: relative;
   align-items: center;
   justify-content: center;
   flex: 1;
   height: 100%;
+  width: 100%;
   //align-self: stretch;
   box-sizing: border-box;
   svg{

+ 20 - 11
src/components/SubScreen/index.jsx

@@ -3,36 +3,45 @@ import styles from "./styles.module.scss";
 import SvgIcon from "@components/SvgIcon";
 import {animated,easings} from "@react-spring/web";
 import {useState,useEffect} from "react";
-import {useSpring} from "@react-spring/core";
+import {useSpring, useSpringRef} from "@react-spring/core";
+import {useLocation} from "react-router";
 const i18n=global.i18n;
 
 const SubScreen=({open,onClose,children,route,renderComp})=>{
     const [subOpen,setSubOpen]=useState(open);
-    const duration=230;
+    const {pathname,hash} = useLocation();
+    const duration=200;
+    const spref = useSpringRef()
+
     const delayClose=()=>{
         if (onClose)onClose();
     }
     const close=()=>{
         setSubOpen(false);
+        // spref.start({
+        //     transform:'translateX(100%) translateZ(0px)',
+        // })
         setTimeout(function () {
             delayClose();
         },duration);
     }
-    useEffect(()=>{
-        // extra.close=close;
-    },[])
+    // useEffect(()=>{
+    //     // extra.close=close;
+    //     // spref.start();
+    //     spref.start({
+    //         from: {transform: 'translateX(100%) translateZ(0px)'},
+    //         transform:subOpen?'translateX(0%) translateZ(0px)':'translateX(100%) translateZ(0px)',
+    //     })
+    // },[pathname])
+
     const showAni=useSpring({
+        // ref: spref,
         from: {transform: 'translateX(100%) translateZ(0px)'},
         transform:subOpen?'translateX(0%) translateZ(0px)':'translateX(100%) translateZ(0px)',
         config: {
             easing: easings.linear,
             duration:duration
         },
-        // onResolve: () => {
-        //     if (!subOpen){
-        //         if (onClose)onClose();
-        //     }
-        // },
     });
     const renderHeader=()=>{
         let title=route?route.title:"";
@@ -77,7 +86,7 @@ const SubScreen=({open,onClose,children,route,renderComp})=>{
 SubScreen.propTypes = {
     open: PropTypes.bool.isRequired,
     onClose: PropTypes.func.isRequired,
-    children: PropTypes.node.isRequired
+    // children: PropTypes.node.isRequired
 }
 
 export default SubScreen

+ 1 - 1
src/components/SubScreen/styles.module.scss

@@ -1,6 +1,6 @@
 .subscreen{
   display: flex;
-  position: relative;
+  position: fixed;
   width: 100%;
   height: 100%;
   background: var(--body);

+ 1 - 1
src/components/UInput/PasswordInput.jsx

@@ -21,7 +21,7 @@ const PasswordInput = ({innerRef, ...props}) => {
         <div className={`input-control ${wrapClassName}`}>
             <input
                    type={isPasswordVisible ? 'text' : 'password'}
-                   autocomplete="off"
+                   autoComplete="off"
                    ref={innerRef}
                    {...props}/>
             <button className={styles.eye_btn} onClick={togglePasswordVisibility} aria-label="Toggle password visibility">

+ 17 - 1
src/constants/routes.js

@@ -9,4 +9,20 @@ const SIDE_TYPE_NONE=0;
 const SIDE_TYPE_NOMAL=1;
 const SIDE_TYPE_SPECIAL=2;
 
-export {ROUTE_TYPE_IN,ROUTE_TYPE_POP_OR_FULL,ROUTE_TYPE_POP,ROUTE_TYPE_FULL,ROUTE_TYPE_OUTLINK,SIDE_TYPE_NONE,SIDE_TYPE_NOMAL,SIDE_TYPE_SPECIAL};
+const ROUTE_PATH={
+    SIGN_IN:"#/signin",
+    SIGN_UP:"#/signup",
+    SETTINGS:"#/settings",
+}
+
+export {
+    ROUTE_TYPE_IN,
+    ROUTE_TYPE_POP_OR_FULL,
+    ROUTE_TYPE_POP,
+    ROUTE_TYPE_FULL,
+    ROUTE_TYPE_OUTLINK,
+    SIDE_TYPE_NONE,
+    SIDE_TYPE_NOMAL,
+    SIDE_TYPE_SPECIAL,
+    ROUTE_PATH
+};

+ 6 - 0
src/features/mainSlice.js

@@ -48,6 +48,9 @@ const generateRoutes=(routes,asyncRoutes=[])=>{
                     // if (route.path==="#/signin"||route.path==="#/signup"){
                     //     route.component="Login";
                     // }
+                    if (route.path==="#/settings"){
+                        route.component="settings";
+                    }
                     allMap[route.path]=route;
                     let type=route.type;
                     if (type===ROUTE_TYPE_IN||type===ROUTE_TYPE_FULL)inRoutes.push(route);
@@ -327,6 +330,9 @@ export const getLoginStatus=(state)=>{
 export const getRegStatus=(state)=>{
     return state.main.loginStatus.register;
 }
+export const getLogoutStatus=(state)=>{
+    return state.main.loginStatus.logout;
+}
 export const isLogined=(state)=>{
     // console.log(state.main.isLogin)
     return state.main.isLogin;

+ 0 - 11
src/index.js

@@ -24,17 +24,6 @@ Sentry.init({
     replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
     replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.
 });
-const test=()=>{
-    let isCookieEnabled = (window.navigator.cookieEnabled) ? true : false;
-    if (typeof window.navigator.cookieEnabled == "undefined" && !isCookieEnabled) {
-        // 尝试设置一个测试cookie
-        document.cookie = "testcookie";
-        // 检查cookie是否已设置
-        isCookieEnabled = (document.cookie.indexOf("testcookie") != -1) ? true : false;
-    }
-
-    return isCookieEnabled;
-}
 
 const root = ReactDOM.createRoot(document.getElementById('root'));
 root.render(

+ 1 - 1
src/layout/Layout.jsx

@@ -57,7 +57,7 @@ const Layout=()=>{
                   <div className="app-hash">
                       <Suspense>
                           <CHashRouter routes={popRoutes} hlocation={{
-                              pathname: (pathname + hash),
+                              pathname: pathname,
                               search: search,
                               hash: hash
                           }} basePath={pathname}></CHashRouter>

+ 6 - 5
src/layout/Navbar/index.jsx

@@ -27,6 +27,7 @@ import {useSelector} from "react-redux";
 import {allTopNavs, getRoute, getRouteChain, getUserInfo, isLogin, isLogined} from "@features/mainSlice";
 import LazyImage from "@components/LazyImage";
 import {numFormatter} from "@utils/helpers";
+import {ROUTE_PATH} from "@constants/routes";
 const i18n=global.i18n;
 
 const StyledToggleGroup= styled(ToggleButtonGroup)`
@@ -134,10 +135,10 @@ const DesktopSignInUp=()=>{
                 !isLogin?(
                     <>
                         <Button  className={`m-button ${styles.btn_sign_in}`} onClick={()=>{
-                            navigate("#/signin");
+                            navigate(ROUTE_PATH.SIGN_IN);
                         }}>{i18n.t('sign_in')}</Button>
                         <Button className={`${styles.btn_sign_up}`} onClick={()=>{
-                            navigate("#/signup");
+                            navigate(ROUTE_PATH.SIGN_UP);
                         }}>{i18n.t('sign_up')}</Button>
                     </>
                 ):(
@@ -183,10 +184,10 @@ const MobileSignInUp=()=>{
                 !isLogin?(
                     <>
                         <Button  className={`m-button ${styles.btn_sign_in} ${styles.btn_sign_in_mobile}`} onClick={()=>{
-                            navigate("#/signin");
+                            navigate(ROUTE_PATH.SIGN_IN);
                         }}>{i18n.t('sign_in')}</Button>
                         <Button  className={`${styles.btn_sign_up} ${styles.btn_sign_up_mobile}`} onClick={()=>{
-                            navigate("#/signup");
+                            navigate(ROUTE_PATH.SIGN_UP);
                         }}>{i18n.t('sign_up')}</Button>
                     </>
                 ):(
@@ -223,7 +224,7 @@ const UserInfo=()=>{
             {
                 isLogin?(
                     <div className={`d-flex align-items-center ${styles.user_info}`} onClick={()=>{
-                        navigate('#/settings');
+                        navigate(ROUTE_PATH.SETTINGS);
                     }}>
                         <div className={styles.info}>
                             <div className={styles.nick}>{user.NickName}</div>

+ 38 - 7
src/layout/Routes/index.jsx

@@ -6,7 +6,7 @@ const RouteWrapper = lazy(() => import('@layout/Routes/RouteWrapper'));
 const PageNotFound = lazy(() => import('@pages/PageNotFound'));
 
 const createRoute=(props)=>{
-    const {route,basePath}=props;
+    const {route,path}=props;
     const component=(route.component!=null&&route.component!=="")?route.component:"ModulePage";
     const Component = AllComponents[component];
     const checkLogin=()=>{
@@ -18,7 +18,7 @@ const createRoute=(props)=>{
         <Route
             key={route.path}
             exact
-            path={basePath?(basePath+route.path):route.path}
+            path={path?path:route.path}
             element={checkLogin()}
         >
 
@@ -33,7 +33,7 @@ const CBrowserRouter=(props)=>{
             <Route path="*" element={<PageNotFound/>}/>
             {
                 routes.map((route,index)=>{
-                    return createRoute({...props,route});
+                    return createRoute({...props,route,path:route.path});
                 })
             }
         </Routes>
@@ -41,14 +41,45 @@ const CBrowserRouter=(props)=>{
 }
 const CHashRouter=(props)=>{
     const {routes,hlocation}=props;
+    //多hash 切到最后一个
+    let {pathname,hash,search}=hlocation;
+    let paths=pathname.split("#");
+    pathname=paths.shift();
+    let hashs=hash.split("#");
+    // hash="#"+hashs.pop();
+    // pathname=pathname+hash;
+    // console.log({pathname,hash,search})
+    let currpath=pathname+hash;
+    // let currhash="";
+    //多hash 切到最后一个
     return (
-        <Routes location={hlocation}>
+        <>
             {
-                routes.map((route,index)=>{
-                    return createRoute({...props,route});
+                hashs.map((item,index)=>{
+                    if (item=="")return (<></>);
+                    let hash="#"+item;
+                    return (
+                        <Routes key={index} location={{pathname:currpath,hash:hash,search}}>
+                            {
+                                routes.map((route)=>{
+                                    if (route.path===hash){
+                                        return createRoute({...props,route,path:currpath});
+                                    }
+                                    else return (<></>);
+                                })
+                            }
+                        </Routes>
+                    )
                 })
             }
-        </Routes>
+        </>
+        // <Routes location={{pathname,hash,search}}>
+        //     {
+        //         routes.map((route,index)=>{
+        //             return createRoute({...props,route});
+        //         })
+        //     }
+        // </Routes>
     )
 }
 export {CBrowserRouter,CHashRouter};

+ 13 - 13
src/layout/Sidebar/index.jsx

@@ -194,7 +194,7 @@ const Sidebar = () => {
         let lv=currRoute.lv;
         setExpanded(lv);
     }
-    const getOLStyles=(styleID)=>{
+    const getolstyles=(styleID)=>{
         let styles=routeStyles[styleID];
         if (styles==null){
             styles=routeStyles[1];
@@ -219,7 +219,7 @@ const Sidebar = () => {
         let lv=currRoute.lv;
         return lv===link.lv;
     }
-    const renderIconLink=(link,olStyle)=>{
+    const renderIconLink=(link,olstyle)=>{
         let ispop=link.type===ROUTE_TYPE_POP||link.type===ROUTE_TYPE_POP_OR_FULL||link.type===ROUTE_TYPE_OUTLINK;
         let linkIcon=(<SvgIcon className={"icon"} herf={link.icon}/>);
         let target=link.type===ROUTE_TYPE_OUTLINK?"_blank":"";
@@ -234,7 +234,7 @@ const Sidebar = () => {
         );
         return (
             <MTooltip  disableHoverListener={open} title={i18n.t(link.title)} arrow placement="right">
-                <StyledIconLink olStyle={olStyle}>
+                <StyledIconLink olstyle={olstyle}>
                     {linkA}
                 </StyledIconLink>
             </MTooltip>
@@ -242,17 +242,17 @@ const Sidebar = () => {
     }
     const renderLink=(link)=>{
         let pages=link.subs||link.pages;
-        let styles=getOLStyles(link.style);
+        let styles=getolstyles(link.style);
         let linkItem=open?(
-                <StyledAccordion olStyle={styles} defaultExpanded={true} square={true} key={link.lv} expanded={checkCkey(link.lv)} onChange={handleChange(`${link.lv}`,link.path)}>
-                    <StyledAccordionSummary olStyle={styles}>
-                        <Link olStyle={styles} className={`${checkPath(link) ? 'active' : ''} h4`}>
+                <StyledAccordion olstyle={styles} defaultExpanded={true} square={true} key={link.lv} expanded={checkCkey(link.lv)} onChange={handleChange(`${link.lv}`,link.path)}>
+                    <StyledAccordionSummary olstyle={styles}>
+                        <Link olstyle={styles} className={`${checkPath(link) ? 'active' : ''} h4`}>
                             <SvgIcon className={"icon"} herf={link.icon}/>
                             {i18n.t(link.title)}
                         </Link>
                         <SvgIcon className={"icon-chevron-down"} herf={'icon_Arrow'}/>
                     </StyledAccordionSummary>
-                    <StyledAccordionDetails olStyle={styles}>
+                    <StyledAccordionDetails olstyle={styles}>
                         {
                             pages.map((page,pindex)=>{
                                 let  subs=page.subs;
@@ -283,9 +283,9 @@ const Sidebar = () => {
         return ispop?(<a className={clname} target={target} href={link.path}>{linktxt}</a>):(<NavLink className={clname} to={link.path}>{linktxt}</NavLink>)
     }
     const renderSingleLink=(link)=>{
-        let styles=getOLStyles(link.style);
+        let styles=getolstyles(link.style);
         return open?(
-            <SingleLink olStyle={styles}>
+            <SingleLink olstyle={styles}>
                 {
                     renderRLink(link)
                 }
@@ -340,7 +340,7 @@ const Sidebar = () => {
         )
     }
     const renderBonus=()=>{
-        let styles=getOLStyles(0);
+        let styles=getolstyles(0);
         let herf="/bonus";
         let link={type:0,title:'links.bonus',icon:'icon_Gift',path:herf}
         return (
@@ -348,7 +348,7 @@ const Sidebar = () => {
                 <StyledBonus className="d-flex flex-column g-6" open={open}>
                     {
                         open?(
-                            <SingleLink olStyle={styles}>
+                            <SingleLink olstyle={styles}>
                                 <NavLink className={`${pathname === herf ? 'active' : ''} h4`} to={herf}>
                                     <SvgIcon className={"icon"} herf={"icon_Gift"}/>
                                     {i18n.t("links.bonus")}
@@ -404,7 +404,7 @@ const Sidebar = () => {
     const renderSuport=()=>{
         return (
             <StyledBlock open={open}>
-                {renderLogout()}
+                {/*{renderLogout()}*/}
                 <MTooltip disableHoverListener={open} title={i18n.t("links.live_support")} arrow placement="right">
                     <StyledButton open={open} className="h4" fill={"#3bc117"}>
                         <SvgIcon className={"icon"} herf={"icon_Support"}/>

+ 18 - 18
src/layout/Sidebar/styles.js

@@ -51,12 +51,12 @@ const StyledAccordion = styled(Accordion)`
     //     }
     //   `
     // }
-      let olStyle=props.olStyle;
-      let button=olStyle.button;
+      let olstyle=props.olstyle;
+      let button=olstyle.button;
       let bg=getColor(button,COLOR_TYPE_NOMAL);
       let bgact=getColor(button,COLOR_TYPE_ACTIVE)
       let background=bg!=""?`background-color: ${bg} !important;`:''
-      let radius=olStyle.radius?`border-radius:${olStyle.radius} !important;`:"";
+      let radius=olstyle.radius?`border-radius:${olstyle.radius} !important;`:"";
       return `
         ${background}
         ${radius}
@@ -92,9 +92,9 @@ const StyledAccordionSummary = styled(AccordionSummary)`
     }
   }
   ${(props) => {
-    let olStyle=props.olStyle;
-    if (olStyle==null)return ``;
-    const {button,icon,radius}=olStyle;
+    let olstyle=props.olstyle;
+    if (olstyle==null)return ``;
+    const {button,icon,radius}=olstyle;
     let btnHover=getColor(button,COLOR_TYPE_HONER);
     let icoNomal=getColor(icon,COLOR_TYPE_NOMAL);
     let icoHover=getColor(icon,COLOR_TYPE_HONER);
@@ -153,9 +153,9 @@ const StyledAccordionDetails = styled(AccordionDetails)`
     }
   }
   ${(props) => {
-    let olStyle=props.olStyle;
-    if (olStyle==null)return ``;
-    const {button,icon,text,radius,gap,fontsize,weight}=olStyle;
+    let olstyle=props.olstyle;
+    if (olstyle==null)return ``;
+    const {button,icon,text,radius,gap,fontsize,weight}=olstyle;
     let btnN=getColor(button,COLOR_TYPE_NOMAL);
     let btnH=getColor(button,COLOR_TYPE_HONER);
     let btnA=getColor(button,COLOR_TYPE_ACTIVE);
@@ -270,9 +270,9 @@ const SingleLink=styled.div`
     }
   }
   ${(props) => {
-    let olStyle=props.olStyle;
-    if (olStyle==null)return ``;
-    const {button,icon,text,radius,direction,gap,fontsize,weight}=olStyle;
+    let olstyle=props.olstyle;
+    if (olstyle==null)return ``;
+    const {button,icon,text,radius,direction,gap,fontsize,weight}=olstyle;
     let btnN=getColor(button,COLOR_TYPE_NOMAL);
     let btnH=getColor(button,COLOR_TYPE_HONER);
     let btnA=getColor(button,COLOR_TYPE_ACTIVE);
@@ -344,9 +344,9 @@ const Link = styled.span`
     fill: var(--text);
   }
   ${(props) => {
-    let olStyle=props.olStyle;
-    if (olStyle==null)return ``;
-    const {icon,text,gap,fontsize,weight}=olStyle;
+    let olstyle=props.olstyle;
+    if (olstyle==null)return ``;
+    const {icon,text,gap,fontsize,weight}=olstyle;
     let icoN=getColor(icon,COLOR_TYPE_NOMAL);
     let icoH=getColor(icon,COLOR_TYPE_HONER);
     let icoA=getColor(icon,COLOR_TYPE_ACTIVE);
@@ -709,9 +709,9 @@ const StyledIconLink=styled.div`
     }
   }
   ${(props) => {
-    let olStyle=props.olStyle;
-    if (olStyle==null)return ``;
-    const {button,icon}=olStyle;
+    let olstyle=props.olstyle;
+    if (olstyle==null)return ``;
+    const {button,icon}=olstyle;
     let btnN=getColor(button,COLOR_TYPE_NOMAL);
     let btnH=getColor(button,COLOR_TYPE_HONER);
     let btnA=getColor(button,COLOR_TYPE_ACTIVE);

+ 7 - 0
src/locales/index.js

@@ -9,6 +9,7 @@ import pt from './languages/pt_BR.json';
 const resources = {
     en: {
         key:"en_US",
+        name:"English",
         translation: en,
     },
     // zh: {
@@ -16,6 +17,7 @@ const resources = {
     // }
     pt:{
         key:"pt_BR",
+        name:"Portuguese",
         translation:pt
     }
 }
@@ -51,4 +53,9 @@ i18n.getCurrLang=()=>{
     if (res)return res.key;
     return "";
 }
+i18n.getCurrLangName=()=>{
+    let res=resources[i18n.language];
+    if (res)return res.name;
+    return "";
+}
 export default i18n;

+ 14 - 2
src/locales/languages/en_US.json

@@ -13,7 +13,7 @@
     "live_support": "Live Support",
     "quest": "QUEST",
     "spin": "SPIN",
-    "log_out": "Logout"
+    "log_out": "Log out"
   },
   "tab": {
     "withdraw": "Withdraw",
@@ -97,5 +97,17 @@
       "ipmax": "Same IP cannot register multiple accounts"
     },
     "success": "Registration completed successfully!"
-  }
+  },
+  "settings": {
+    "user_info": {
+      "welcome": "Welcome to 24680.com",
+      "tips": "Please Sign up or Log in first",
+      "name": "Name:",
+      "id": "User ID:"
+    },
+    "language": "Language",
+    "theme": "Theme",
+    "gender": "Gender"
+  },
+  "copy_success": "Copy successful"
 }

+ 28 - 25
src/pages/Settings.jsx

@@ -1,35 +1,38 @@
 // components
-import PageHeader from '@layout/PageHeader';
-import AppGrid from '@layout/AppGrid';
-import ProfileAvatar from '@widgets/ProfileAvatar';
-import ProfileInfo from '@widgets/ProfileInfo';
-import AccountSettings from '@widgets/AccountSettings';
-import ChangePassword from '@widgets/ChangePassword';
-import NotificationsSettings from '@widgets/NotificationsSettings';
-import NotificationsSchedule from '@widgets/NotificationsSchedule';
-import PaymentMethod from '@widgets/PaymentMethod';
-import ProfileDescription from '@widgets/ProfileDescription';
-import PrivacyPolicy from '@widgets/PrivacyPolicy';
+// import PageHeader from '@layout/PageHeader';
+// import AppGrid from '@layout/AppGrid';
+// import ProfileAvatar from '@widgets/ProfileAvatar';
+// import ProfileInfo from '@widgets/ProfileInfo';
+// import AccountSettings from '@widgets/AccountSettings';
+// import ChangePassword from '@widgets/ChangePassword';
+// import NotificationsSettings from '@widgets/NotificationsSettings';
+// import NotificationsSchedule from '@widgets/NotificationsSchedule';
+// import PaymentMethod from '@widgets/PaymentMethod';
+// import ProfileDescription from '@widgets/ProfileDescription';
+// import PrivacyPolicy from '@widgets/PrivacyPolicy';
+//
+// const widgets = {
+//     avatar: <ProfileAvatar/>,
+//     info: <ProfileInfo/>,
+//     description: <ProfileDescription/>,
+//     settings: <AccountSettings/>,
+//     payments: <PaymentMethod/>,
+//     privacy: <PrivacyPolicy/>,
+//     notifications_settings: <NotificationsSettings/>,
+//     notifications_schedule: <NotificationsSchedule/>,
+//     password: <ChangePassword/>
+// }
 
-const widgets = {
-    avatar: <ProfileAvatar/>,
-    info: <ProfileInfo/>,
-    description: <ProfileDescription/>,
-    settings: <AccountSettings/>,
-    payments: <PaymentMethod/>,
-    privacy: <PrivacyPolicy/>,
-    notifications_settings: <NotificationsSettings/>,
-    notifications_schedule: <NotificationsSchedule/>,
-    password: <ChangePassword/>
-}
+import UserSettings from "@widgets/UserSettings";
 
 const Settings = () => {
     return (
         <>
-            <PageHeader title="Settings" />
-            <AppGrid id="settings" widgets={widgets}/>
+            {/*<PageHeader title="Settings" />*/}
+            {/*<AppGrid id="settings" widgets={widgets}/>*/}
+            <UserSettings/>
         </>
     )
 }
 
-export default Settings
+export default Settings

+ 3 - 1
src/pages/index.jsx

@@ -1,9 +1,11 @@
 import {lazy} from "react";
 const ModulePage=lazy(()=>import('@pages/ModulePage'));
 const Home=lazy(()=>import('@pages/Home'));
-const Login=lazy(()=>import("@pages/Login"))
+const Login=lazy(()=>import("@pages/Login"));
+const Settings=lazy(()=>import("@pages/Settings"));
 export default {
     ModulePage:ModulePage,
     Home:Home,
     login:Login,
+    settings:Settings,
 }

+ 18 - 0
src/styles/_elements.scss

@@ -703,6 +703,7 @@ a {
     display: flex;
     align-items: center;
     justify-content: center;
+    position: relative;
     width: 100%;
     min-height: 2.75rem;
     color: #fff;
@@ -715,3 +716,20 @@ a {
     transition: transform .2s cubic-bezier(.36,.66,.04,1);
     text-transform: capitalize;
 }
+.button-gray{
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    position: relative;
+    width: 100%;
+    min-height: 2.75rem;
+    color: #fff;
+    background: #3C404A;
+    user-select: none;
+    border-radius: var(--border-radius);
+    font-weight: 700;
+    cursor: pointer;
+    transition: transform .2s cubic-bezier(.36,.66,.04,1);
+    text-transform: capitalize;
+}
+

+ 5 - 1
src/styles/theme.js

@@ -102,6 +102,10 @@ export default createGlobalStyle`
     --swiper-btn-bg: ${theme('theme',{
         light:'#FFFFFF',
         dark:'#2a2b31',
-    })}
+    })};
+    --card-bg: ${theme('theme', {
+        light: '#FFFFFF',
+        dark: '#2f3036',
+    })};
   }
 `;

+ 30 - 20
src/widgets/LoginForm/index.jsx

@@ -25,6 +25,7 @@ import {useEffect} from 'react';
 import SmallLoading from "@components/SmallLoading";
 import {REQ_STATUS} from "@api/config";
 import {reqLogin, reqRegister} from "@features/api";
+import {ROUTE_PATH} from "@constants/routes";
 
 const i18n=global.i18n;
 const TYPE_LOGIN="login";
@@ -40,6 +41,7 @@ const LoginForm = ({close}) => {
     const loginStatus=useSelector(getLoginStatus);
     const regStatus=useSelector(getRegStatus);
     const dispatch = useDispatch();
+    const navigate=useNavigate();
     const {register, handleSubmit, formState: {errors}, control} = useForm({
         defaultValues: {
             // country:'55',
@@ -52,13 +54,17 @@ const LoginForm = ({close}) => {
     });
     const {pathname,hash} = useLocation();
     useEffect(() => {
-        if (hash==="#/signin"){
+        if (hash===ROUTE_PATH.SIGN_IN){
             setShowType(TYPE_LOGIN);
         }
-        else if (hash==="#/signup"){
+        else if (hash===ROUTE_PATH.SIGN_UP){
             setShowType(TYPE_REGISTER);
         }
     }, [pathname,hash]);
+    const navigatRoute=(route)=>{
+        if (pathname.indexOf(route)==-1)navigate(route);
+        else close();
+    }
     const onCallback=(code)=>{
         if (code==200){
             if (close)close();
@@ -89,7 +95,7 @@ const LoginForm = ({close}) => {
         return (
             <Spring type="slideUp" >
                 <div className={styles.l_title}>{i18n.t("login.login_title")}</div>
-                <form autocomplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
+                <form autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
                     onSubmitLogin(data);
                 })}>
                     <Controller control={control}
@@ -129,14 +135,16 @@ const LoginForm = ({close}) => {
                             loginStatus===REQ_STATUS.LOADING?renderLoading():i18n.t("login.sign_in_btn")
                         }
                     </button>
-                    {/*<div className={styles.l_reg_new}>*/}
-                    {/*    <div>{i18n.t("login.reg_new_des")}</div>*/}
-                    {/*    <div className={styles.reg_btn} onClick={()=>{*/}
-                    {/*        setShowType(TYPE_REGISTER);*/}
-                    {/*    }}>*/}
-                    {/*        {i18n.t("login.reg_new_btn")}*/}
-                    {/*    </div>*/}
-                    {/*</div>*/}
+                    <div className={styles.l_reg_new}>
+                        <div>{i18n.t("login.reg_new_des")}</div>
+                        <div className={styles.reg_btn} onClick={()=>{
+                            // setShowType(TYPE_REGISTER);
+                            if(isMobile())navigatRoute(ROUTE_PATH.SIGN_UP)
+                            else setShowType(TYPE_REGISTER);
+                        }}>
+                            {i18n.t("login.reg_new_btn")}
+                        </div>
+                    </div>
                 </form>
             </Spring>
         )
@@ -145,7 +153,7 @@ const LoginForm = ({close}) => {
         return (
             <Spring type="slideUp">
                 <div className={styles.l_title}>{i18n.t("login.reg_title")}</div>
-                <form autocomplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
+                <form autoComplete="off" className={styles.l_form} onSubmit={handleSubmit((data) => {
                     onSubmitReg(data);
                 })}>
                     <Controller control={control}
@@ -192,14 +200,16 @@ const LoginForm = ({close}) => {
                             regStatus===REQ_STATUS.LOADING?renderLoading():i18n.t("login.sign_up_btn")
                         }
                     </button>
-                    {/*<div className={styles.l_reg_new}>*/}
-                    {/*    <div>{i18n.t("login.login_des")}</div>*/}
-                    {/*    <div className={styles.reg_btn} onClick={()=>{*/}
-                    {/*        setShowType(TYPE_LOGIN);*/}
-                    {/*    }}>*/}
-                    {/*        {i18n.t("login.sign_in_btn")}*/}
-                    {/*    </div>*/}
-                    {/*</div>*/}
+                    <div className={styles.l_reg_new}>
+                        <div>{i18n.t("login.login_des")}</div>
+                        <div className={styles.reg_btn} onClick={()=>{
+                            // setShowType(TYPE_LOGIN);
+                            if(isMobile())navigatRoute(ROUTE_PATH.SIGN_IN)
+                            else setShowType(TYPE_LOGIN);
+                        }}>
+                            {i18n.t("login.sign_in_btn")}
+                        </div>
+                    </div>
                 </form>
             </Spring>
         )

+ 225 - 0
src/widgets/UserSettings/index.jsx

@@ -0,0 +1,225 @@
+import styles from './styles.module.scss';
+import {useDispatch, useSelector} from "react-redux";
+import {ReactComponent as EmptyAvatar} from '@assets/avatar_empty.svg';
+import {getLogoutStatus, getUserInfo, isLogined} from "@features/mainSlice";
+import Spring from "@components/Spring";
+import {useNavigate} from "react-router-dom";
+import {ROUTE_PATH} from "@constants/routes";
+import LazyImage from "@components/LazyImage";
+import USD from "@assets/lvicon/USD.black.png";
+import {numFormatter} from "@utils/helpers";
+import SvgIcon from "@components/SvgIcon";
+import {ReactComponent as Male} from '@assets/gener/male.svg';
+import {ReactComponent as FeMale} from '@assets/gener/female.svg';
+import {ReactComponent as GenderIcon} from '@assets/gener/gender.svg';
+import {CopyToClipboard} from 'react-copy-to-clipboard';
+import {toast} from "react-toastify";
+import ToggleButtonGroup from "@mui/material/ToggleButtonGroup";
+import {StyledThemeTabs} from "@layout/Sidebar/styles";
+import {useThemeProvider} from "@contexts/themeContext";
+import ToggleButton from "@mui/material/ToggleButton";
+import {reqLogout} from "@features/api";
+import {REQ_STATUS} from "@api/config";
+import SmallLoading from "@components/SmallLoading";
+const i18n=global.i18n;
+const UserSettings=()=>{
+    const isLogin=useSelector(isLogined);
+    const user=useSelector(getUserInfo);
+    const logoutStatus=useSelector(getLogoutStatus);
+    const dispatch = useDispatch();
+    const navigate=useNavigate();
+    const {theme, toggleTheme} = useThemeProvider();
+    const renderEmpty=()=>{
+        return (
+            <div className={styles.wrap_item}>
+                <div className={styles.user_info}>
+                    <EmptyAvatar className={styles.avatar_empty}></EmptyAvatar>
+                    <div className={styles.empty_info}>
+                        <span className={styles.welcome}>
+                            {i18n.t("settings.user_info.welcome")}
+                        </span>
+                        <span className={styles.login_tips}>
+                            {i18n.t("settings.user_info.tips")}
+                        </span>
+                    </div>
+                </div>
+                <div className={styles.login_con}>
+                    <button className={`button-gray ${styles.button}`} onClick={()=>{
+                        navigate(ROUTE_PATH.SIGN_IN);
+                    }}>
+                        {i18n.t("sign_in")}
+                    </button>
+                    <button className={`button-green ${styles.button}`} onClick={()=>{
+                        navigate(ROUTE_PATH.SIGN_UP);
+                    }}>
+                        {i18n.t("sign_up")}
+                    </button>
+                </div>
+            </div>
+        )
+    }
+    const renderUser=()=>{
+        return (
+            <div className={styles.wrap_item}>
+                <div className={styles.user_info}>
+                    <LazyImage wrapperClassName={styles.avatar} src={user.img} alt={"avatar"}></LazyImage>
+                    <div className={`${styles.user_info} ${styles.info}`}>
+                        <div className={styles.info_item}>
+                            <div className={styles.name}>{user.NickName}</div>
+                            {
+                                user.Gender===1?(<FeMale className={styles.female}></FeMale>):(<Male className={styles.male}></Male>)
+                            }
+                        </div>
+                        <CopyToClipboard text={user.UserID} onCopy={()=>{
+                            toast.success(i18n.t("copy_success"));
+                        }}>
+                            <div className={styles.info_item}>
+                                <div className={styles.text}>{i18n.t("settings.user_info.id")}</div>
+                                <div className={styles.text}>{user.UserID}</div>
+                                <button>
+                                    <SvgIcon className={styles.icon_copy} herf={"icon_Copy"}></SvgIcon>
+                                </button>
+                            </div>
+                        </CopyToClipboard>
+                        <div className={styles.info_item}>
+                            <img className={styles.icon_golds} src={USD}/>
+                            <div className={styles.golds}>{"$"+numFormatter(user.Score)}</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        )
+    }
+    const renderUserInfo=()=>{
+        return (
+            <>
+                {
+                    isLogin?renderUser():renderEmpty()
+                }
+            </>
+        )
+    }
+    const renderItemLang=()=>{
+        return (
+            <div className={styles.action_item}>
+                <div className={styles.action_left}>
+                    <SvgIcon className={styles.icon} herf={"icon_Language"}></SvgIcon>
+                    <div>{i18n.t("settings.language")}</div>
+                </div>
+                <div className={styles.action_right}>
+                    <div>{i18n.getCurrLangName()}</div>
+                    <SvgIcon className={styles.icon} herf={"icon_Arrow"}></SvgIcon>
+                </div>
+            </div>
+        )
+    }
+    const renderItemTheme=()=>{
+        return (
+            <div className={styles.action_item}>
+                <div className={styles.action_left}>
+                    <SvgIcon className={styles.icon} herf={"icon_Exchange"}></SvgIcon>
+                    <div>{i18n.t("settings.theme")}</div>
+                </div>
+                <div className={styles.action_right}>
+                    <div className={styles.theme_con}>
+                        <ToggleButtonGroup sx={{
+                            display:"flex",
+                            position: "relative",
+                            width:"100%",
+                            height:"100%",
+                            alignItems:"center",
+                            justifyContent:"space-between"
+                        }} exclusive value={theme} onChange={()=>{
+                            toggleTheme();
+                        }}>
+                            <div className={styles.theme_bg} style={{left: `${theme == "dark" ? '0%' : '50%'}`}}/>
+                            <ToggleButton sx={{
+                                display:"flex",
+                                position: "relative",
+                                width:"100%",
+                                height:"100%",
+                                alignItems:"center",
+                                justifyContent:"center",
+                                border:"none",
+                                backgroundColor:'transparent !important;',
+                                ".Mui-selected:hover":{
+                                    backgroundColor: 'transparent !important;',
+                                }
+                            }} value={"dark"}>
+                                <SvgIcon className={`${styles.theme_icon} ${theme=="dark"?styles.active:''}`} herf={"icon_Dark"}/>
+                            </ToggleButton>
+                            <ToggleButton sx={{
+                                display:"flex",
+                                position: "relative",
+                                width:"100%",
+                                height:"100%",
+                                alignItems:"center",
+                                justifyContent:"center",
+                                border:"none",
+                                backgroundColor:'transparent !important;',
+                                ".Mui-selected:hover":{
+                                    backgroundColor: 'transparent !important;',
+                                }
+                            }} value={"light"}>
+                                <SvgIcon className={`${styles.theme_icon} ${theme=="light"?styles.active:''}`} herf={"icon_Light"}/>
+                            </ToggleButton>
+                        </ToggleButtonGroup>
+                    </div>
+                </div>
+            </div>
+        )
+    }
+    const renderItemGender=()=>{
+        return (
+            <div className={styles.action_item}>
+                <div className={styles.action_left}>
+                    <GenderIcon className={styles.icon}></GenderIcon>
+                    <div>{i18n.t("settings.gender")}</div>
+                </div>
+                <div className={styles.action_right}>
+                    {
+                        user.Gender===1?(<FeMale className={styles.gender}></FeMale>):(<Male className={styles.gender}></Male>)
+                    }
+                    <SvgIcon className={styles.icon} herf={"icon_Arrow"}></SvgIcon>
+                </div>
+            </div>
+        )
+    }
+    const renderSetting=()=>{
+        return (
+            <div className={`${styles.wrap_item} ${styles.action_wrap}`}>
+                {renderItemLang()}
+                {renderItemGender()}
+                {renderItemTheme()}
+            </div>
+        )
+    }
+    const renderLogout=()=>{
+        return (
+            <>
+                {
+                    isLogin?(
+                        <button className={`button-gray ${styles.logout}`} onClick={()=>{
+                            if (logoutStatus===REQ_STATUS.LOADING)return;
+                            dispatch(reqLogout());
+                        }}>
+                            {
+                                logoutStatus===REQ_STATUS.LOADING?(<SmallLoading fill={"#fff"} />):(<>{i18n.t("links.log_out")}</>)
+                            }
+                        </button>
+                    ):(<></>)
+                }
+            </>
+        )
+    }
+    return (
+        <div className={styles.container}>
+            <Spring type="slideUp" className={styles.content}>
+                {renderUserInfo()}
+                {renderSetting()}
+                {renderLogout()}
+            </Spring>
+        </div>
+    )
+}
+export default UserSettings;

+ 207 - 0
src/widgets/UserSettings/styles.module.scss

@@ -0,0 +1,207 @@
+.container{
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  padding: 1rem .75rem;
+  background-color: var(--widget-bg);
+}
+.content{
+  width: 100%;
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+}
+.wrap_item{
+  display: flex;
+  flex-direction: column;
+  background: var(--card-bg);
+  border-radius: var(--border-radius);
+  padding: 1rem .75rem;
+  gap: 1.2rem;
+}
+.logout{
+  background: var(--card-bg);
+  color: var(--text);
+  height: 3rem;
+}
+.user_info{
+  display: flex;
+  align-items: center;
+  width: 100%;
+  gap: 1rem;
+}
+.avatar_empty{
+  width: 4rem;
+  height: 4rem;
+}
+.empty_info{
+  display: flex;
+  flex-direction: column;
+  gap: .25rem;
+  & .welcome{
+    font-size: 1.125rem;
+    line-height: 1.375rem;
+    color: var(--header);
+    font-weight: 700;
+  }
+  & .login_tips{
+    font-size: 1rem;
+    line-height: 1.125rem;
+    color: var(--text);
+  }
+}
+.login_con{
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 1.2rem;
+  & .button{
+    font-size: 1rem;
+    height: 3.1rem;
+  }
+}
+.avatar{
+  width: 4rem;
+  img{
+    width: 4rem;
+    height: auto;
+    border-radius: 50%;
+  }
+}
+.info{
+  flex-direction: column;
+  align-items: flex-start;
+  font-size: 1rem;
+  color: var(--header);
+  font-weight: 600;
+  gap: .25rem;
+  & .info_item{
+    display: flex;
+    align-items: center;
+    gap: .4rem;
+    //justify-content: space-between;
+    width: 100%;
+    padding: 0 0.7rem 0 0;
+  }
+  & .name{
+    color: var(--header);
+    font-size: 1.125rem;
+    font-weight: 700;
+    line-height: 1.375rem;
+  }
+  & .text{
+    font-size: 1rem;
+    color: var(--text);
+    font-weight: 600;
+  }
+  & .icon_golds{
+    width: 1.2rem;
+    height: 1.2rem;
+  }
+  & .golds{
+    font-size: 1rem;
+    font-weight: 600;
+    color: #edc349;
+  }
+  & .icon_copy{
+    width: 1.2rem;
+    height: 1.2rem;
+    fill: var(--text);
+  }
+  & .male{
+    width: 1.2rem;
+    height: 1.2rem;
+    g{
+      fill: #05b0ff;
+    }
+  }
+  & .female{
+    width: 1.2rem;
+    height: 1.2rem;
+    g{
+      fill: #fa5fdb;
+    }
+  }
+}
+.action_wrap{
+  padding: 0.2rem .75rem;
+  gap: 0rem;
+}
+.action_item{
+  display: flex;
+  align-items: center;
+  height: 3.25rem;
+  justify-content: space-between;
+  & .action_left{
+    height: 100%;
+    font-size: 1rem;
+    display: flex;
+    align-items: center;
+    color: var(--header);
+    gap: 0.525rem;
+    & .icon{
+      width: 1.5rem;
+      height: 1.5rem;
+      fill: var(--text);
+      g{
+        fill: var(--text);
+      }
+    }
+  }
+  & .action_right{
+    display: flex;
+    height: 100%;
+    align-items: center;
+    font-size: 1rem;
+    color: var(--text);
+    gap: .5rem;
+    & .gender{
+      font-size: .9rem;
+      width: 1.4em;
+      height: 1.4em;
+      fill: var(--text);
+      g{
+        fill: var(--text);
+      }
+    }
+    & .icon{
+      font-size: .75rem;
+      width: 1.4em;
+      height: 1.4em;
+      fill: var(--text);
+      g{
+        fill: var(--text);
+      }
+    }
+  }
+}
+.theme_con{
+  position: relative;
+  width: 5.875rem;
+  height: 3rem;
+  transition: var(--transition);
+  background-color: var(--nav-item-bg);
+  border-radius: var(--border-radius);
+  padding: .25rem;
+}
+.theme_bg{
+  position:absolute;
+  width:50%;
+  height:100%;
+  pointer-events: none;
+  border-radius: var(--border-radius);
+  background-color: var(--nav-item-hover);
+  transition:left 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
+  left:0%;
+}
+.theme_icon{
+  font-size: .75rem;
+  width: 1.4em;
+  height: 1.4em;
+  fill: var(--text);
+  &.active{
+    fill: var(--header);
+  }
+}