index.jsx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. // styled components
  2. import {
  3. Link,
  4. SingleLink,
  5. StyledAccordion,
  6. StyledAccordionDetails,
  7. StyledAccordionSummary,
  8. StyledBonus,
  9. StyledButton,
  10. StyledThemeTabs,
  11. StyledThemeTab,
  12. StyledAct,
  13. StyledRefer,
  14. StyledBlock,
  15. StyledIconLink
  16. }
  17. from './styles';
  18. // components
  19. import Logo from '@components/Logo';
  20. import {NavLink, useLocation,useNavigate} from 'react-router-dom';
  21. // hooks
  22. import {useSidebar} from '@contexts/sidebarContext';
  23. import {useWindowSize} from 'react-use';
  24. import {useEffect, useState} from 'react';
  25. // constants
  26. import LINKS from '@constants/links';
  27. import MuiDrawer from '@mui/material/Drawer';
  28. // import styled from 'styled-components/macro';
  29. import { styled, useTheme } from '@mui/material/styles';
  30. import SidebarTrigger from "@ui/SidebarTrigger";
  31. // import {useThemeProvider} from '@contexts/themeContext';
  32. import symbol from '@assets/symbol-defs.svg';
  33. import MTooltip from "@components/MTooltip";
  34. import Tabs from "@mui/material/Tabs";
  35. import Tab from "@mui/material/Tab";
  36. import Button from "@mui/material/Button";
  37. import TabScrollButton from "@mui/material/TabScrollButton";
  38. import ToggleButtonGroup from "@mui/material/ToggleButtonGroup";
  39. import {useThemeProvider} from "@contexts/themeContext";
  40. import questsimg from "@assets/activity/quests.png";
  41. import spin_1 from "@assets/activity/spin_1.png";
  42. import spin_2 from "@assets/activity/spin_2.png";
  43. import spin_3 from "@assets/activity/spin_3.png";
  44. import imgrefer from "@assets/activity/rio_refer.png";
  45. import imgrefer_f from "@assets/activity/rio_refer_f.png";
  46. import {useDispatch, useSelector} from "react-redux";
  47. import {
  48. allNavs,
  49. getBlockColumn,
  50. getRoute,
  51. getRouteStyles,
  52. isFullRoute,
  53. isLogined,
  54. logout,
  55. nBlocks
  56. } from "@features/mainSlice";
  57. import {
  58. ROUTE_TYPE_OUTLINK,
  59. ROUTE_TYPE_POP,
  60. ROUTE_TYPE_POP_OR_FULL,
  61. SIDE_TYPE_GRID,
  62. SIDE_TYPE_NOMAL,
  63. SIDE_TYPE_SPECIAL
  64. } from "@constants/routes";
  65. import SvgIcon from "@components/SvgIcon";
  66. import {reqLogout} from "@features/api";
  67. const drawWidth = 250;
  68. const drawMobieWidth=250;
  69. const i18n=global.i18n;
  70. const openedMixin = (theme,width) => ({
  71. width: width,
  72. transition: theme.transitions.create('width', {
  73. easing: theme.transitions.easing.sharp,
  74. duration: theme.transitions.duration.enteringScreen,
  75. }),
  76. // overflowX: 'hidden',
  77. overflow:'visible !important',
  78. backgroundColor:'var(--standard);',
  79. boxShadow:'var(--widget-shadow);',
  80. // position:'relative',
  81. });
  82. const closedMixin = (theme) => ({
  83. transition: theme.transitions.create('width', {
  84. easing: theme.transitions.easing.sharp,
  85. duration: theme.transitions.duration.leavingScreen,
  86. }),
  87. // overflowX: 'hidden',
  88. //spin显示
  89. overflow:'visible !important',
  90. width: `calc(${theme.spacing(7)} + 1px)`,
  91. [theme.breakpoints.up('sm')]: {
  92. width: `calc(${theme.spacing(8)} + 1px)`,
  93. },
  94. backgroundColor:'var(--standard);',
  95. boxShadow:'var(--widget-shadow);',
  96. // position:'absolute',
  97. });
  98. const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== 'open' })(
  99. ({ theme, open}) => ({
  100. width: drawWidth,
  101. flexShrink: 0,
  102. whiteSpace: 'nowrap',
  103. boxSizing: 'border-box',
  104. // overflowX:'hidden',
  105. ...(open && {
  106. ...openedMixin(theme),
  107. '& .MuiDrawer-paper': openedMixin(theme,drawWidth),
  108. }),
  109. ...(!open && {
  110. ...closedMixin(theme),
  111. '& .MuiDrawer-paper': closedMixin(theme),
  112. }),
  113. }),
  114. );
  115. const DrawerHeader = styled('div')(({ theme }) => ({
  116. display: 'flex',
  117. alignItems: 'center',
  118. padding: '0 10px',
  119. gap:'12px',
  120. // backgroundColor:'#000',
  121. boxShadow:'var(--widget-shadow)',
  122. position:'relative',
  123. '& .logo_con':{
  124. width:'80%'
  125. },
  126. '& .logo_con_m':{
  127. width:'80%'
  128. },
  129. // necessary for content to be below app bar
  130. ...theme.mixins.toolbar,
  131. }));
  132. const Sidebar = () => {
  133. // const theme = useTheme();
  134. const {open, setOpen} = useSidebar();
  135. const [expanded, setExpanded] = useState("");
  136. const {pathname,hash} = useLocation();
  137. const navigate=useNavigate();
  138. const {width} = useWindowSize();
  139. const {theme, toggleTheme} = useThemeProvider();
  140. const [isActHovered, setIsActHovered] = useState(false);
  141. const visiblecls=isActHovered?"overflow-visible":"";
  142. const navBlocks=useSelector(nBlocks);
  143. const currRoute = useSelector(getRoute(pathname));
  144. const blocksColumn=useSelector(getBlockColumn);
  145. const routeStyles=useSelector(getRouteStyles);
  146. const isLogin=useSelector(isLogined);
  147. const dispatch = useDispatch();
  148. const handleActEnter = () => {
  149. if (open)return;
  150. setIsActHovered(true);
  151. };
  152. const handleActLeave = () => {
  153. if (open)return;
  154. setIsActHovered(false);
  155. };
  156. // manually handle accordion expansion
  157. const handleChange = (panel,path) => (event, isExpanded) => {
  158. if (isExpanded)navigate(path);
  159. // setExpanded(isExpanded ? panel : false);
  160. if (!isExpanded){
  161. let arr=panel.split("_");
  162. let s=arr.length-2;
  163. if (s<0)panel="";
  164. else
  165. {
  166. arr.splice(s,1);
  167. panel=arr.join("_");
  168. }
  169. }
  170. setExpanded(panel);
  171. }
  172. const checkNavOpen=()=>{
  173. if (currRoute==null)return;
  174. let lv=currRoute.lv;
  175. setExpanded(lv);
  176. }
  177. const getOLStyles=(styleID)=>{
  178. let styles=routeStyles[styleID];
  179. if (styles==null){
  180. styles=routeStyles[1];
  181. }
  182. let style={};
  183. if (styles!=null){
  184. style=styles.style;
  185. }
  186. let thstyles=style[theme];
  187. if (thstyles==null)thstyles={};
  188. return thstyles;
  189. }
  190. // collapse opened accordion on route change when the drawer is temporary
  191. useEffect(() => {
  192. checkNavOpen();
  193. }, [pathname]);
  194. const checkCkey=(lv)=>{
  195. if (expanded==null)return false;
  196. else return expanded.startsWith(lv);
  197. }
  198. const checkPath=(link)=>{
  199. let lv=currRoute.lv;
  200. return lv===link.lv;
  201. }
  202. const renderIconLink=(link,olStyle)=>{
  203. let ispop=link.type===ROUTE_TYPE_POP||link.type===ROUTE_TYPE_POP_OR_FULL||link.type===ROUTE_TYPE_OUTLINK;
  204. let linkIcon=(<SvgIcon className={"icon"} herf={link.icon}/>);
  205. let target=link.type===ROUTE_TYPE_OUTLINK?"_blank":"";
  206. let linkA=ispop?(
  207. <a href={link.path} target={target}>
  208. {linkIcon}
  209. </a>
  210. ):(
  211. <NavLink to={link.path}>
  212. {linkIcon}
  213. </NavLink>
  214. );
  215. return (
  216. <MTooltip disableHoverListener={open} title={i18n.t(link.title)} arrow placement="right">
  217. <StyledIconLink olStyle={olStyle}>
  218. {linkA}
  219. </StyledIconLink>
  220. </MTooltip>
  221. );
  222. }
  223. const renderLink=(link)=>{
  224. let pages=link.subs||link.pages;
  225. let styles=getOLStyles(link.style);
  226. let linkItem=open?(
  227. <StyledAccordion olStyle={styles} defaultExpanded={true} square={true} key={link.lv} expanded={checkCkey(link.lv)} onChange={handleChange(`${link.lv}`,link.path)}>
  228. <StyledAccordionSummary olStyle={styles}>
  229. <Link olStyle={styles} className={`${checkPath(link) ? 'active' : ''} h4`}>
  230. <SvgIcon className={"icon"} herf={link.icon}/>
  231. {i18n.t(link.title)}
  232. </Link>
  233. <SvgIcon className={"icon-chevron-down"} herf={'icon_Arrow'}/>
  234. </StyledAccordionSummary>
  235. <StyledAccordionDetails olStyle={styles}>
  236. {
  237. pages.map((page,pindex)=>{
  238. let subs=page.subs;
  239. if (subs==null||subs.length==0)return renderRLink(page);
  240. else
  241. {
  242. return renderLink(page);
  243. }
  244. })
  245. }
  246. </StyledAccordionDetails>
  247. </StyledAccordion>
  248. ):renderIconLink(link,styles);
  249. return linkItem
  250. }
  251. const renderRLink=(link)=>{
  252. let isActive=checkPath(link);
  253. let ispop=link.type===ROUTE_TYPE_POP||link.type===ROUTE_TYPE_POP_OR_FULL||link.type===ROUTE_TYPE_OUTLINK;
  254. let clname=`${isActive?'active':''} h4`;
  255. let linktxt=(
  256. <>
  257. <SvgIcon className={"icon"} herf={link.icon}/>
  258. {i18n.t(`${link.title}`)}
  259. </>
  260. )
  261. let target=link.type===ROUTE_TYPE_OUTLINK?"_blank":"";
  262. return ispop?(<a className={clname} target={target} href={link.path}>{linktxt}</a>):(<NavLink className={clname} to={link.path}>{linktxt}</NavLink>)
  263. }
  264. const renderSingleLink=(link)=>{
  265. let styles=getOLStyles(link.style);
  266. return open?(
  267. <SingleLink olStyle={styles}>
  268. {
  269. renderRLink(link)
  270. }
  271. </SingleLink>
  272. ):renderIconLink(link,styles)
  273. }
  274. const renderLinkNav=(link)=>{
  275. let linkItem=(<></>);
  276. let subs=link.subs;
  277. let len=subs.length;
  278. if (len===0&&link.plv===""){
  279. linkItem=renderSingleLink(link);
  280. }
  281. else
  282. {
  283. linkItem=renderLink(link);
  284. }
  285. return linkItem;
  286. }
  287. const renderBlock=(block)=>{
  288. if (block==null)return (<></>);
  289. let first=block[0];
  290. if (first==null)return (<></>);
  291. let blockID=first.block;
  292. let column=1;
  293. if (blocksColumn!=null){
  294. let blockC=blocksColumn[blockID];
  295. if (blockC!=null)column=blockC.column;
  296. }
  297. return (
  298. <>
  299. <StyledBlock open={open} column={column}>
  300. {
  301. block.map((link, index) => {
  302. return renderLinkNav(link)
  303. })
  304. }
  305. </StyledBlock>
  306. {renderLine()}
  307. </>
  308. )
  309. }
  310. const renderLinkBlocks=()=>{
  311. return (
  312. <>
  313. {
  314. navBlocks.map((block,index)=>{
  315. return renderBlock(block);
  316. })
  317. }
  318. </>
  319. )
  320. }
  321. const renderBonus=()=>{
  322. let styles=getOLStyles(0);
  323. let herf="/bonus";
  324. let link={type:0,title:'links.bonus',icon:'icon_Gift',path:herf}
  325. return (
  326. <StyledBlock open={open}>
  327. <StyledBonus className="d-flex flex-column g-6" open={open}>
  328. {
  329. open?(
  330. <SingleLink olStyle={styles}>
  331. <NavLink className={`${pathname === herf ? 'active' : ''} h4`} to={herf}>
  332. <SvgIcon className={"icon"} herf={"icon_Gift"}/>
  333. {i18n.t("links.bonus")}
  334. </NavLink>
  335. </SingleLink>
  336. ):renderIconLink(link,styles)
  337. }
  338. <StyledAct open={open} enter={isActHovered} onMouseEnter={handleActEnter} onMouseLeave={handleActLeave}>
  339. <div className="bonus-item li-quests">
  340. <button className="bonus-item-btn">
  341. <img className="img-bg" src={questsimg} alt={"quests"}/>
  342. {open?i18n.t("links.quest"):""}
  343. </button>
  344. </div>
  345. <div className="bonus-item li-spin">
  346. <button className="bonus-item-btn">
  347. <div className="spin-anim active">
  348. <img className="img-spinbg" src={spin_1} alt={"spin-bg"}/>
  349. <img className="img-turntable" src={spin_2} alt={"spin-turntable"}/>
  350. <img className="img-pointer" src={spin_3} alt={"spin-pointer"}/>
  351. </div>
  352. {
  353. open?(
  354. <div className="spin-txt">
  355. {i18n.t("links.spin")}
  356. </div>
  357. ):(<></>)
  358. }
  359. </button>
  360. </div>
  361. </StyledAct>
  362. </StyledBonus>
  363. </StyledBlock>
  364. );
  365. }
  366. const renderLogout=()=>{
  367. return (
  368. <>
  369. {
  370. isLogin?(
  371. <StyledButton open={open} className="h4" onClick={()=>{
  372. dispatch(reqLogout());
  373. setOpen(false);
  374. }}>
  375. <SvgIcon className={"icon"} herf={"icon_Logout"}/>
  376. {open?i18n.t("links.log_out"):""}
  377. </StyledButton>
  378. ):(<></>)
  379. }
  380. </>
  381. )
  382. }
  383. const renderSuport=()=>{
  384. return (
  385. <StyledBlock open={open}>
  386. {renderLogout()}
  387. <MTooltip disableHoverListener={open} title={i18n.t("links.live_support")} arrow placement="right">
  388. <StyledButton open={open} className="h4" fill={"#3bc117"}>
  389. <SvgIcon className={"icon"} herf={"icon_Support"}/>
  390. {open?i18n.t("links.live_support"):""}
  391. </StyledButton>
  392. </MTooltip>
  393. </StyledBlock>
  394. )
  395. }
  396. const handleTheme = (event, value) => {
  397. if (value){
  398. toggleTheme();
  399. }
  400. else {
  401. }
  402. }
  403. const renderThemeTabs=()=>{
  404. if (open){
  405. return (
  406. <StyledBlock open={open} >
  407. <StyledThemeTabs sx={{
  408. marginTop:'16px',
  409. }} className={theme} exclusive value={theme} onChange={handleTheme}>
  410. <div className="theme-bg"/>
  411. <StyledThemeTab value={"dark"}>
  412. <SvgIcon className={"icon"} herf={"icon_Dark"}/>
  413. {i18n.t("theme.dark")}
  414. </StyledThemeTab>
  415. <StyledThemeTab value={"light"}>
  416. <SvgIcon className={"icon"} herf={"icon_Light"}/>
  417. {i18n.t("theme.light")}
  418. </StyledThemeTab>
  419. </StyledThemeTabs>
  420. </StyledBlock>
  421. )
  422. }
  423. else return(<></>);
  424. }
  425. const renderLine=(key="1")=>{
  426. // if (open)return(<></>);
  427. // else
  428. // {
  429. // return (
  430. // <div className="fold-line"></div>
  431. // )
  432. // }
  433. return (
  434. <div className="fold-line"></div>
  435. )
  436. }
  437. const renderBanner=()=>{
  438. let refimg=open?imgrefer:imgrefer_f;
  439. return (
  440. <StyledBlock open={open}>
  441. <MTooltip disableHoverListener={open} title={i18n.t("refer.title")} arrow placement="right">
  442. <StyledRefer open={open}>
  443. <img alt={"refer"} src={refimg}/>
  444. {
  445. open?(
  446. <div className={"ref-right"}>
  447. <div className={"t"}>{i18n.t("refer.title")}</div>
  448. <div className={"s"}>{i18n.t("refer.des")}</div>
  449. </div>
  450. ):(<></>)
  451. }
  452. </StyledRefer>
  453. </MTooltip>
  454. </StyledBlock>
  455. )
  456. }
  457. const renderContent=()=>{
  458. return (
  459. <>
  460. {renderBonus()}
  461. {renderBanner()}
  462. {renderLine()}
  463. {renderLinkBlocks()}
  464. {renderSuport()}
  465. {renderThemeTabs()}
  466. </>
  467. )
  468. }
  469. const renderDesktop=()=>{
  470. return (
  471. <Drawer variant="permanent" open={open} sx={{
  472. }}>
  473. <DrawerHeader>
  474. <SidebarTrigger/>
  475. {
  476. open?(
  477. <div className={'logo_con'}>
  478. <Logo/>
  479. </div>
  480. ):<></>
  481. }
  482. </DrawerHeader>
  483. <div className={`d-flex flex-column sidebar-nav ${visiblecls}`}>
  484. <div className={`d-flex flex-column g-4 ${visiblecls}`}>
  485. {
  486. renderContent()
  487. }
  488. </div>
  489. </div>
  490. </Drawer>
  491. )
  492. }
  493. const renderMobile=()=>{
  494. return (
  495. <MuiDrawer open={open} sx={{
  496. "& .MuiDrawer-paper": {
  497. width: drawMobieWidth,
  498. boxSizing: "border-box",
  499. overflow:'visible !important',
  500. backgroundColor:'var(--standard);',
  501. boxShadow:'var(--widget-shadow);',
  502. },
  503. "& .MuiModal-backdrop":{
  504. backgroundColor:'rgba(0,0,0,0)',
  505. }
  506. }} variant="temporary" onClose={()=>{
  507. setOpen(false);
  508. }}>
  509. <DrawerHeader>
  510. <SidebarTrigger/>
  511. {
  512. open?(
  513. <div className={'logo_con_m'}>
  514. <Logo/>
  515. </div>
  516. ):<></>
  517. }
  518. </DrawerHeader>
  519. <div className={`d-flex flex-column sidebar-nav ${visiblecls}`}>
  520. <div className={`d-flex flex-column g-4 ${visiblecls}`}>
  521. {
  522. renderContent()
  523. }
  524. </div>
  525. </div>
  526. </MuiDrawer>
  527. )
  528. }
  529. const {isMobile} = useThemeProvider();
  530. return (
  531. <>
  532. {
  533. isMobile()?(renderMobile()):renderDesktop()
  534. }
  535. </>
  536. )
  537. }
  538. export default Sidebar