├── CODEOWNERS
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── pnpm-lock.yaml
├── public
├── _redirects
├── favicon.svg
└── robots.txt
├── src
├── App.tsx
├── analytics
│ ├── index.ts
│ └── reportWebVitals.ts
├── assets
│ ├── images
│ │ ├── announcement_background.svg
│ │ ├── auth
│ │ │ └── AuthBackground.tsx
│ │ ├── icons
│ │ │ ├── facebook.svg
│ │ │ ├── google.svg
│ │ │ └── twitter.svg
│ │ ├── landing
│ │ │ ├── codedthemes-logo.svg
│ │ │ ├── img-footer.png
│ │ │ ├── img-soc1.svg
│ │ │ ├── img-soc2.svg
│ │ │ └── img-soc3.svg
│ │ ├── logo-dark.svg
│ │ ├── logo.png
│ │ ├── logo.svg
│ │ ├── maintenance
│ │ │ ├── Error404.png
│ │ │ ├── Error500.png
│ │ │ ├── TwoCone.png
│ │ │ ├── coming-soon-1.png
│ │ │ ├── coming-soon.png
│ │ │ ├── under-construction-2.svg
│ │ │ └── under-construction.svg
│ │ ├── mega-menu
│ │ │ ├── back.svg
│ │ │ └── chart.svg
│ │ ├── software
│ │ │ ├── clash.png
│ │ │ ├── clashx.png
│ │ │ ├── quantumultx.png
│ │ │ ├── shadowrocket.png
│ │ │ ├── stash.png
│ │ │ ├── surfboard.png
│ │ │ └── surge.png
│ │ └── users
│ │ │ ├── avatar-1.png
│ │ │ ├── avatar-2.png
│ │ │ ├── avatar-3.png
│ │ │ ├── avatar-4.png
│ │ │ └── avatar-5.png
│ └── third-party
│ │ ├── apex-chart.css
│ │ └── react-table.css
├── components
│ ├── @extended
│ │ ├── AnimateButton.tsx
│ │ ├── Avatar.tsx
│ │ ├── Breadcrumbs.tsx
│ │ ├── DataGrid.tsx
│ │ ├── Dot.tsx
│ │ ├── IconButton.tsx
│ │ ├── LoadingButton.tsx
│ │ ├── Progress
│ │ │ ├── CircularWithLabel.tsx
│ │ │ ├── LinearWithIcon.tsx
│ │ │ └── LinearWithLabel.tsx
│ │ └── Transitions.tsx
│ ├── KeyValueTable.tsx
│ ├── Loadable.tsx
│ ├── Loader.tsx
│ ├── MainCard.tsx
│ ├── RTLLayout.tsx
│ ├── ScrollTop.tsx
│ ├── ScrollX.tsx
│ ├── SecondaryAction.tsx
│ ├── cards
│ │ ├── AuthFooter.tsx
│ │ ├── ComponentHeader.tsx
│ │ ├── skeleton
│ │ │ └── ProductPlaceholder.tsx
│ │ └── statistics
│ │ │ ├── AnalyticEcommerce.tsx
│ │ │ └── AnalyticsDataCard.tsx
│ ├── logo
│ │ ├── LogoIcon.tsx
│ │ ├── LogoMain.tsx
│ │ └── index.tsx
│ └── third-party
│ │ └── SimpleBar.tsx
├── config.ts
├── contexts
│ └── ConfigContext.tsx
├── hooks
│ ├── useAuthStateDetector.ts
│ ├── useConfig.ts
│ ├── useHtmlLangSelector.ts
│ ├── useKnowledge.ts
│ ├── usePageAnalyticsEffect.ts
│ ├── useQuery.ts
│ └── useTitle.ts
├── i18n
│ ├── i18next.d.ts
│ ├── index.ts
│ └── resources
│ │ ├── en-us
│ │ ├── common.json
│ │ ├── general.json
│ │ ├── index.ts
│ │ ├── language.json
│ │ ├── notice.json
│ │ └── title.json
│ │ ├── index.ts
│ │ ├── zh-cn
│ │ ├── common.json
│ │ ├── general.json
│ │ ├── index.ts
│ │ ├── language.json
│ │ ├── notice.json
│ │ └── title.json
│ │ └── zh-tw
│ │ ├── common.json
│ │ ├── general.json
│ │ ├── index.ts
│ │ ├── language.json
│ │ ├── notice.json
│ │ └── title.json
├── index.tsx
├── layout
│ ├── CommonLayout
│ │ ├── FooterBlock.tsx
│ │ ├── Header.tsx
│ │ └── index.tsx
│ └── MainLayout
│ │ ├── Drawer
│ │ ├── DrawerContent
│ │ │ ├── Navigation
│ │ │ │ ├── NavCollapse.tsx
│ │ │ │ ├── NavGroup.tsx
│ │ │ │ ├── NavItem.tsx
│ │ │ │ └── index.tsx
│ │ │ └── index.tsx
│ │ ├── DrawerHeader
│ │ │ ├── DrawerHeaderStyled.ts
│ │ │ └── index.tsx
│ │ ├── MiniDrawerStyled.ts
│ │ └── index.tsx
│ │ ├── Footer.tsx
│ │ ├── Header
│ │ ├── AppBarStyled.tsx
│ │ ├── HeaderContent
│ │ │ ├── DarkModeSwitchButton.tsx
│ │ │ ├── I18nSwitchButton.tsx
│ │ │ ├── Profile
│ │ │ │ ├── MenuList.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── TicketMenu.tsx
│ │ │ ├── Title.tsx
│ │ │ └── index.tsx
│ │ └── index.tsx
│ │ └── index.tsx
├── menu-items
│ └── index.tsx
├── middleware
│ ├── api
│ │ └── index.ts
│ └── route-guard
│ │ ├── AuthGuard.tsx
│ │ └── GuestGuard.tsx
├── model
│ ├── api_response.ts
│ ├── commission.ts
│ ├── config.ts
│ ├── coupon.ts
│ ├── invite_data.ts
│ ├── knowledge.ts
│ ├── login.ts
│ ├── notice.ts
│ ├── order.ts
│ ├── password.ts
│ ├── payment.ts
│ ├── plan.ts
│ ├── register.ts
│ ├── reset_password.ts
│ ├── send_mail.ts
│ ├── server.ts
│ ├── subscription.ts
│ ├── telegram.ts
│ ├── ticket.ts
│ ├── traffic.ts
│ ├── user.ts
│ └── withdraw.ts
├── pages
│ ├── auth
│ │ ├── forgot-password.tsx
│ │ ├── login.tsx
│ │ └── register.tsx
│ ├── dashboard
│ │ └── index.tsx
│ ├── invite
│ │ ├── commissions.tsx
│ │ └── index.tsx
│ ├── knowledge
│ │ ├── [id].tsx
│ │ └── index.tsx
│ ├── maintenance
│ │ ├── 404.tsx
│ │ ├── 500.tsx
│ │ ├── coming-soon.tsx
│ │ └── under-construction.tsx
│ ├── node
│ │ └── status.tsx
│ ├── order
│ │ ├── [id].tsx
│ │ └── index.tsx
│ ├── plan
│ │ └── buy
│ │ │ ├── [id].tsx
│ │ │ └── index.tsx
│ ├── profile
│ │ └── index.tsx
│ ├── ticket
│ │ ├── [id].tsx
│ │ └── index.tsx
│ └── traffic
│ │ └── index.tsx
├── routes
│ ├── LoginRoutes.tsx
│ ├── MainRoutes.tsx
│ └── index.tsx
├── sections
│ ├── auth
│ │ ├── AuthCard.tsx
│ │ ├── AuthWrapper.tsx
│ │ └── auth-forms
│ │ │ ├── AuthCodeVerification.tsx
│ │ │ ├── AuthForgotPassword.tsx
│ │ │ ├── AuthLogin.tsx
│ │ │ ├── AuthRegister.tsx
│ │ │ └── SendMailButton.tsx
│ ├── dashboard
│ │ ├── alerts
│ │ │ └── orderPendingAlert.tsx
│ │ ├── index.tsx
│ │ ├── noticeCarousel.tsx
│ │ ├── shortcutCard
│ │ │ ├── index.tsx
│ │ │ ├── purchaseButton.tsx
│ │ │ ├── subscribeButton
│ │ │ │ ├── clashButton.tsx
│ │ │ │ ├── clashxButton.tsx
│ │ │ │ ├── copyLinkButton.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── quantumultxButton.tsx
│ │ │ │ ├── scanQrCodeButton.tsx
│ │ │ │ ├── shadowrocketButton.tsx
│ │ │ │ ├── stashButton.tsx
│ │ │ │ ├── surfboardButton.tsx
│ │ │ │ └── surgeButton.tsx
│ │ │ ├── ticketButton.tsx
│ │ │ └── tutorialButton.tsx
│ │ └── subscriptionCard.tsx
│ ├── invite
│ │ ├── commissionsPage
│ │ │ └── index.tsx
│ │ └── invitePage
│ │ │ ├── index.tsx
│ │ │ ├── infoCard.tsx
│ │ │ ├── inviteCodesTable.tsx
│ │ │ └── myInvitationCard.tsx
│ ├── knowledge
│ │ ├── postCard.tsx
│ │ ├── postList.tsx
│ │ └── search.tsx
│ ├── node
│ │ └── status
│ │ │ ├── index.tsx
│ │ │ ├── table.tsx
│ │ │ └── wrapper.tsx
│ ├── order
│ │ ├── checkoutPage
│ │ │ ├── billingCard.tsx
│ │ │ ├── context.ts
│ │ │ ├── index.tsx
│ │ │ ├── orderInfoCard.tsx
│ │ │ ├── paymentMethodCard.tsx
│ │ │ ├── productInfoCard.tsx
│ │ │ └── statusCard.tsx
│ │ └── listPage
│ │ │ ├── index.tsx
│ │ │ ├── table.tsx
│ │ │ └── wrapper.tsx
│ ├── profile
│ │ ├── accountInfoCard.tsx
│ │ ├── changePasswordCard.tsx
│ │ ├── index.tsx
│ │ ├── notificationCard.tsx
│ │ ├── resetSubscriptionCard.tsx
│ │ ├── telegramCard.tsx
│ │ └── walletCard.tsx
│ ├── subscription
│ │ ├── buyPage
│ │ │ ├── context.ts
│ │ │ ├── index.tsx
│ │ │ ├── products.tsx
│ │ │ ├── productsFilter.tsx
│ │ │ └── productsHeader.tsx
│ │ └── planDetailsPage
│ │ │ ├── context.ts
│ │ │ ├── couponCard.tsx
│ │ │ ├── index.tsx
│ │ │ ├── orderInfoCard.tsx
│ │ │ ├── periodSelectCard.tsx
│ │ │ └── planInfoCard.tsx
│ ├── ticket
│ │ └── detailPage
│ │ │ ├── context.ts
│ │ │ ├── createTicketButton.tsx
│ │ │ ├── createTicketTxt.tsx
│ │ │ ├── drawer.tsx
│ │ │ ├── index.tsx
│ │ │ ├── main
│ │ │ ├── chatHistory.tsx
│ │ │ ├── emojiChoose.tsx
│ │ │ ├── index.tsx
│ │ │ ├── inputArea.tsx
│ │ │ └── topBar
│ │ │ │ ├── closeButton.tsx
│ │ │ │ └── index.tsx
│ │ │ └── userList.tsx
│ └── traffic
│ │ ├── index.tsx
│ │ ├── trafficAlert.tsx
│ │ ├── trafficChart.tsx
│ │ ├── trafficInfoCard.tsx
│ │ └── trafficTable.tsx
├── store
│ ├── index.ts
│ ├── reducers
│ │ ├── auth.ts
│ │ ├── index.ts
│ │ ├── menu.ts
│ │ └── view.ts
│ └── services
│ │ └── api.ts
├── themes
│ ├── cache.ts
│ ├── hooks.ts
│ ├── index.tsx
│ ├── overrides
│ │ ├── Accordion.ts
│ │ ├── AccordionDetails.ts
│ │ ├── AccordionSummary.tsx
│ │ ├── Alert.ts
│ │ ├── AlertTitle.ts
│ │ ├── Autocomplete.ts
│ │ ├── Badge.ts
│ │ ├── Button.ts
│ │ ├── ButtonBase.ts
│ │ ├── ButtonGroup.ts
│ │ ├── CardContent.ts
│ │ ├── Checkbox.tsx
│ │ ├── Chip.ts
│ │ ├── Dialog.ts
│ │ ├── DialogContentText.ts
│ │ ├── DialogTitle.ts
│ │ ├── Fab.ts
│ │ ├── IconButton.ts
│ │ ├── InputBase.ts
│ │ ├── InputLabel.ts
│ │ ├── LinearProgress.ts
│ │ ├── Link.ts
│ │ ├── ListItemButton.tsx
│ │ ├── ListItemIcon.tsx
│ │ ├── LoadingButton.ts
│ │ ├── OutlinedInput.ts
│ │ ├── Pagination.ts
│ │ ├── PaginationItem.ts
│ │ ├── Popover.ts
│ │ ├── Radio.tsx
│ │ ├── Slider.ts
│ │ ├── Switch.ts
│ │ ├── Tab.ts
│ │ ├── TableBody.ts
│ │ ├── TableCell.ts
│ │ ├── TableFooter.ts
│ │ ├── TableHead.ts
│ │ ├── TablePagination.ts
│ │ ├── TableRow.ts
│ │ ├── Tabs.ts
│ │ ├── ToggleButton.ts
│ │ ├── TreeItem.ts
│ │ ├── Typography.ts
│ │ └── index.ts
│ ├── palette.ts
│ ├── shadows.tsx
│ ├── theme
│ │ └── index.ts
│ └── typography.ts
├── types
│ ├── auth.ts
│ ├── config.ts
│ ├── extended.ts
│ ├── menu.ts
│ ├── overrides
│ │ ├── Alert.d.ts
│ │ ├── Badge.d.ts
│ │ ├── Button.d.ts
│ │ ├── Checkbox.d.ts
│ │ ├── Chip.d.ts
│ │ ├── Pagination.d.ts
│ │ ├── Radio.d.ts
│ │ ├── Switch.d.ts
│ │ ├── createPalette.d.ts
│ │ ├── createTheme.d.ts
│ │ └── index.d.ts
│ ├── password.ts
│ ├── plan.ts
│ ├── root.ts
│ ├── snackbar.ts
│ └── theme.ts
├── utils
│ ├── crypto.ts
│ ├── getColors.ts
│ ├── getShadow.ts
│ ├── isBrowser.ts
│ ├── locales
│ │ └── en.json
│ ├── password-strength.ts
│ ├── password-validation.ts
│ └── plan.ts
└── vite-env.d.ts
├── stats.html
├── tsconfig.json
└── vite.config.ts
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # These owners will be the default owners for everything in the repo.
2 | * @AH-dark
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # v2board-theme
2 |
3 | # 为V2board提供的前后端分离主题。
4 | 此套主题是按照开源主题Mantis二次开发所得,此项目代码已修改所有bug,后续有bug或新功能会持续修改更新。\
5 | 演示站的部分功能例如:签到、充值、礼品卡等定制功能均不在源码内,如有需要请前往TG频道联系开发。\
6 | TG频道:https://t.me/maimai778
7 |
8 | ## 环境配置:
9 | nodejs v18.12.1\
10 | pnpm v9.6.0
11 |
12 | ## 打包部署:
13 | 对接修改\
14 | /src/config.ts\
15 | Logo修改\
16 | /src/components/logo/LogoMain.tsx\
17 | 服务协议/隐私协议链接修改\
18 | /src/sections/auth/auth-forms/AuthRegister.tsx\
19 | /src/layout/MainLayout/Footer.tsx\
20 | 如需添加crisp客服请在index.html中head标签内添加script\
21 | 其余修改请自行search
22 |
23 | ## 打包命令
24 | ```
25 | pnpm install
26 | pnpm build
27 | ```
28 | 打包完成后得到dist文件夹,丢到网站根目录即可。
29 |
30 | ## 关于提交BUG
31 | 可在上方频道中或Issues提问
32 |
33 | ## 关于部署完成后刷新页面出现404
34 | 如果aapanel部署可在网站URL Rewrite中填入
35 | ```
36 | location / {
37 | try_files $uri $uri/ /index.html$is_args$query_string;
38 | }
39 | ```
40 |
41 | ## 友情捐赠
42 | TRC-20 TSLZs2cJorBgMDrWLaTA2dBxWqLCLJbY3o\
43 | Polygon 0xB578cb7F5A47a9856BC20C083E9c47b5d932522E
44 |
45 |
46 | ## 更新日志
47 | 2024.10.07\
48 | 套餐详情适配json数据\
49 | 仅支持以下格式以及参数
50 | ```
51 | [{
52 | "feature":"每月 100G 流量",
53 | "support":true
54 | }
55 | ]
56 | ```
57 | 2024.10.05\
58 | 修复订单完成页的订单状态显示&套餐金额为0时的显示问题\
59 | 2024.10.03\
60 | 无关紧要的更新:修改了仪表盘订阅卡片的显示样式\
61 | 2024.09.06\
62 | 修复当后台开启邮箱后缀白名单时的限制;\
63 | 修复流量统计页面的明细显示问题\
64 | 2024.08.30\
65 | 添加进入仪表盘页面最新公告弹框,以及修改公告图片自适应\
66 | 修复注册发送验证码按钮的显示与按钮的禁用问题\
67 | 2024.08.27\
68 | 修复流量统计页面中低倍率节点流量记录的显示问题\
69 | 2024.08.25\
70 | 修复仪表盘页面未识别到设备类型导致的无法正常复制订阅链接的问题\
71 | 2024.08.06\
72 | 将Google Recaptcha更换为Cloudflare Turnstile
73 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/public/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow: /
3 | Allow: /login
4 | Allow: /register
5 | Allow: /forgot-password
6 |
--------------------------------------------------------------------------------
/src/analytics/index.ts:
--------------------------------------------------------------------------------
1 | import ReactGA from "react-ga4";
2 | import reportWebVitals from "@/analytics/reportWebVitals";
3 | import config from "@/config";
4 |
5 | if (config.googleAnalytics) {
6 | ReactGA.initialize(
7 | [
8 | {
9 | trackingId: config.googleAnalytics.measurementId
10 | }
11 | ],
12 | {
13 | testMode: import.meta.env.DEV,
14 | legacyDimensionMetric: false,
15 | gaOptions: {
16 | siteSpeedSampleRate: 100
17 | }
18 | }
19 | );
20 |
21 | reportWebVitals(({ name, delta, id }) => {
22 | ReactGA.ga("send", "event", {
23 | eventCategory: "Web Vitals",
24 | eventAction: name,
25 | eventLabel: id,
26 | eventValue: Math.round(name === "CLS" ? delta * 1000 : delta),
27 | nonInteraction: true,
28 | transport: "beacon"
29 | });
30 | });
31 | }
32 |
33 | export default ReactGA;
34 |
--------------------------------------------------------------------------------
/src/analytics/reportWebVitals.ts:
--------------------------------------------------------------------------------
1 | import { ReportHandler } from 'web-vitals';
2 |
3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
4 | if (onPerfEntry) {
5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6 | getCLS(onPerfEntry);
7 | getFID(onPerfEntry);
8 | getFCP(onPerfEntry);
9 | getLCP(onPerfEntry);
10 | getTTFB(onPerfEntry);
11 | });
12 | }
13 | };
14 |
15 | export default reportWebVitals;
16 |
--------------------------------------------------------------------------------
/src/assets/images/announcement_background.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/auth/AuthBackground.tsx:
--------------------------------------------------------------------------------
1 | // material-ui
2 | import { useTheme } from '@mui/material/styles';
3 | import { Box } from '@mui/material';
4 |
5 | // ==============================|| AUTH BLUR BACK SVG ||============================== //
6 |
7 | const AuthBackground = () => {
8 | const theme = useTheme();
9 | return (
10 |
11 |
27 |
28 | );
29 | };
30 |
31 | export default AuthBackground;
32 |
--------------------------------------------------------------------------------
/src/assets/images/icons/facebook.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/icons/google.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/assets/images/icons/twitter.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/landing/img-footer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/landing/img-footer.png
--------------------------------------------------------------------------------
/src/assets/images/landing/img-soc2.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/landing/img-soc3.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/src/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/logo.png
--------------------------------------------------------------------------------
/src/assets/images/maintenance/Error404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/maintenance/Error404.png
--------------------------------------------------------------------------------
/src/assets/images/maintenance/Error500.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/maintenance/Error500.png
--------------------------------------------------------------------------------
/src/assets/images/maintenance/TwoCone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/maintenance/TwoCone.png
--------------------------------------------------------------------------------
/src/assets/images/maintenance/coming-soon-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/maintenance/coming-soon-1.png
--------------------------------------------------------------------------------
/src/assets/images/maintenance/coming-soon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/maintenance/coming-soon.png
--------------------------------------------------------------------------------
/src/assets/images/software/clash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/software/clash.png
--------------------------------------------------------------------------------
/src/assets/images/software/clashx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/software/clashx.png
--------------------------------------------------------------------------------
/src/assets/images/software/quantumultx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/software/quantumultx.png
--------------------------------------------------------------------------------
/src/assets/images/software/shadowrocket.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/software/shadowrocket.png
--------------------------------------------------------------------------------
/src/assets/images/software/stash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/software/stash.png
--------------------------------------------------------------------------------
/src/assets/images/software/surfboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/software/surfboard.png
--------------------------------------------------------------------------------
/src/assets/images/software/surge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/software/surge.png
--------------------------------------------------------------------------------
/src/assets/images/users/avatar-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/users/avatar-1.png
--------------------------------------------------------------------------------
/src/assets/images/users/avatar-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/users/avatar-2.png
--------------------------------------------------------------------------------
/src/assets/images/users/avatar-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/users/avatar-3.png
--------------------------------------------------------------------------------
/src/assets/images/users/avatar-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/users/avatar-4.png
--------------------------------------------------------------------------------
/src/assets/images/users/avatar-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moeumwy/v2board-theme/a439d34dfb6178b60e6dde20d5b8be3cad787676/src/assets/images/users/avatar-5.png
--------------------------------------------------------------------------------
/src/assets/third-party/apex-chart.css:
--------------------------------------------------------------------------------
1 | .apexcharts-legend-series .apexcharts-legend-marker {
2 | left: -4px !important;
3 | }
4 |
--------------------------------------------------------------------------------
/src/assets/third-party/react-table.css:
--------------------------------------------------------------------------------
1 | .cell-center {
2 | text-align: center;
3 | }
4 | .cell-center > * {
5 | margin: 0 auto;
6 | }
7 |
8 | .cell-right {
9 | text-align: right;
10 | }
11 | .cell-right > * {
12 | margin: 0 0 0 auto;
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/@extended/Dot.tsx:
--------------------------------------------------------------------------------
1 | // material-ui
2 | import { CSSObject, useTheme } from "@mui/material/styles";
3 | import { Box } from "@mui/material";
4 |
5 | // project import
6 | import { ColorProps } from "@/types/extended";
7 | import getColors from "@/utils/getColors";
8 |
9 | interface Props {
10 | color?: ColorProps;
11 | size?: number;
12 | variant?: string;
13 | sx?: CSSObject;
14 | }
15 |
16 | const Dot = ({ color, size, variant, sx }: Props) => {
17 | const theme = useTheme();
18 | const colors = getColors(theme, color || "primary");
19 | const { main } = colors;
20 |
21 | return (
22 |
35 | );
36 | };
37 |
38 | export default Dot;
39 |
--------------------------------------------------------------------------------
/src/components/@extended/Progress/CircularWithLabel.tsx:
--------------------------------------------------------------------------------
1 | // material-ui
2 | import { Box, CircularProgress, CircularProgressProps, Typography } from '@mui/material';
3 |
4 | // ==============================|| PROGRESS - CIRCULAR LABEL ||============================== //
5 |
6 | export default function CircularWithLabel({ value, ...others }: CircularProgressProps) {
7 | return (
8 |
9 |
10 |
22 | {`${Math.round(value!)}%`}
23 |
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/@extended/Progress/LinearWithIcon.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react';
2 |
3 | // material-ui
4 | import { Box, LinearProgress, LinearProgressProps } from '@mui/material';
5 |
6 | // ==============================|| PROGRESS - LINEAR ICON ||============================== //
7 |
8 | export default function LinearWithIcon({ icon, value, ...others }: LinearProgressProps & { icon: ReactNode }) {
9 | return (
10 |
11 |
12 |
13 |
14 | {icon}
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/@extended/Progress/LinearWithLabel.tsx:
--------------------------------------------------------------------------------
1 | // material-ui
2 | import { Box, LinearProgress, LinearProgressProps, Typography } from '@mui/material';
3 |
4 | // ==============================|| PROGRESS - LINEAR WITH LABEL ||============================== //
5 |
6 | export default function LinearWithLabel({ value, ...others }: LinearProgressProps) {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 | {`${Math.round(value!)}%`}
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/KeyValueTable.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Grid, GridSpacing, Skeleton } from "@mui/material";
3 | import { ResponsiveStyleValue } from "@mui/system";
4 |
5 | export interface KeyValueData {
6 | key?: React.ReactNode;
7 | value?: React.ReactNode;
8 | }
9 |
10 | export interface KeyValueTableProps {
11 | data: KeyValueData[];
12 | rowSpacing?: ResponsiveStyleValue;
13 | columnSpacing?: ResponsiveStyleValue;
14 | classes?: {
15 | rowContainer?: string;
16 | rowItem?: string;
17 | columnContainer?: string;
18 | columnItemKey?: string;
19 | columnItemValue?: string;
20 | };
21 | isLoading?: boolean;
22 | isValueLoading?: boolean;
23 | }
24 |
25 | const KeyValueTable: React.FC = ({
26 | data,
27 | rowSpacing,
28 | columnSpacing,
29 | classes,
30 | isLoading,
31 | isValueLoading
32 | }) => (
33 |
34 | {data.map((item, index) => (
35 |
36 | {isLoading ? (
37 |
38 | ) : (
39 |
40 |
41 | {item.key}
42 |
43 |
44 | {isValueLoading ? : item.value}
45 |
46 |
47 | )}
48 |
49 | ))}
50 |
51 | );
52 |
53 | export default KeyValueTable;
54 |
--------------------------------------------------------------------------------
/src/components/Loadable.tsx:
--------------------------------------------------------------------------------
1 | import { ElementType, Suspense } from 'react';
2 |
3 | // project import
4 | import Loader from './Loader';
5 |
6 | // ==============================|| LOADABLE - LAZY LOADING ||============================== //
7 |
8 | const Loadable = (Component: ElementType) => (props: any) =>
9 | (
10 | }>
11 |
12 |
13 | );
14 |
15 | export default Loadable;
16 |
--------------------------------------------------------------------------------
/src/components/Loader.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | // material-ui
4 | import LinearProgress, { LinearProgressProps } from "@mui/material/LinearProgress";
5 | import { Box } from "@mui/material";
6 |
7 | // project import
8 | import { makeStyles } from "@/themes/hooks";
9 |
10 | const useStyles = makeStyles()((theme) => ({
11 | wrapper: {
12 | position: "fixed",
13 | top: 0,
14 | left: 0,
15 | zIndex: 2001,
16 | width: "100%",
17 | "& > * + *": {
18 | marginTop: theme.spacing(2)
19 | }
20 | }
21 | }));
22 |
23 | // ==============================|| Loader ||============================== //
24 |
25 | export interface LoaderProps extends LinearProgressProps {}
26 |
27 | const Loader: React.FC = (props) => {
28 | const { classes } = useStyles();
29 |
30 | return (
31 |
32 |
33 |
34 | );
35 | };
36 |
37 | export default Loader;
38 |
--------------------------------------------------------------------------------
/src/components/RTLLayout.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, ReactNode } from "react";
2 |
3 | // material-ui
4 | import { CacheProvider } from "@emotion/react";
5 | import createCache, { StylisPlugin } from "@emotion/cache";
6 |
7 | // third-party
8 | import rtlPlugin from "stylis-plugin-rtl";
9 |
10 | // project import
11 | import useConfig from "@/hooks/useConfig";
12 |
13 | // ==============================|| RTL LAYOUT ||============================== //
14 |
15 | interface Props {
16 | children: ReactNode;
17 | }
18 |
19 | const RTLLayout = ({ children }: Props) => {
20 | const { themeDirection } = useConfig();
21 |
22 | useEffect(() => {
23 | document.dir = themeDirection;
24 | }, [themeDirection]);
25 |
26 | const cacheRtl = createCache({
27 | key: themeDirection === "rtl" ? "rtl" : "css",
28 | prepend: true,
29 | stylisPlugins: themeDirection === "rtl" ? [rtlPlugin as StylisPlugin] : []
30 | });
31 |
32 | return {children};
33 | };
34 |
35 | export default RTLLayout;
36 |
--------------------------------------------------------------------------------
/src/components/ScrollTop.tsx:
--------------------------------------------------------------------------------
1 | import { ReactElement, useEffect } from 'react';
2 | import { useLocation } from 'react-router-dom';
3 |
4 | // ==============================|| NAVIGATION - SCROLL TO TOP ||============================== //
5 |
6 | const ScrollTop = ({ children }: { children: ReactElement | null }) => {
7 | const location = useLocation();
8 | const { pathname } = location;
9 |
10 | useEffect(() => {
11 | window.scrollTo({
12 | top: 0,
13 | left: 0,
14 | behavior: 'smooth'
15 | });
16 | }, [pathname]);
17 |
18 | return children || null;
19 | };
20 |
21 | export default ScrollTop;
22 |
--------------------------------------------------------------------------------
/src/components/ScrollX.tsx:
--------------------------------------------------------------------------------
1 | // material-ui
2 | import { styled } from '@mui/material/styles';
3 |
4 | const ScrollX = styled('div')({
5 | width: '100%',
6 | overflowX: 'auto',
7 | display: 'block'
8 | });
9 |
10 | export default ScrollX;
11 |
--------------------------------------------------------------------------------
/src/components/cards/ComponentHeader.tsx:
--------------------------------------------------------------------------------
1 | // material-ui
2 | import { Box, Grid, Link, Stack, Typography } from '@mui/material';
3 |
4 | // assets
5 | import { GlobalOutlined, NodeExpandOutlined } from '@ant-design/icons';
6 |
7 | // ==============================|| COMPONENTS - BREADCRUMBS ||============================== //
8 |
9 | interface Props {
10 | title: string;
11 | caption?: string;
12 | directory?: string;
13 | link?: string;
14 | }
15 |
16 | const ComponentHeader = ({ title, caption, directory, link }: Props) => (
17 |
18 |
19 | {title}
20 | {caption && (
21 |
22 | {caption}
23 |
24 | )}
25 |
26 |
27 | {directory && (
28 |
29 |
30 |
31 | {directory}
32 |
33 |
34 | )}
35 | {link && (
36 |
37 |
38 |
39 | {link}
40 |
41 |
42 | )}
43 |
44 |
45 | );
46 |
47 | export default ComponentHeader;
48 |
--------------------------------------------------------------------------------
/src/components/cards/skeleton/ProductPlaceholder.tsx:
--------------------------------------------------------------------------------
1 | // material-ui
2 | import { CardContent, Grid, Skeleton, Stack } from "@mui/material";
3 |
4 | // project import
5 | import MainCard from "@/components/MainCard";
6 |
7 | // ===========================|| SKELETON TOTAL GROWTH BAR CHART ||=========================== //
8 |
9 | const ProductPlaceholder = () => (
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | );
43 |
44 | export default ProductPlaceholder;
45 |
--------------------------------------------------------------------------------
/src/components/cards/statistics/AnalyticEcommerce.tsx:
--------------------------------------------------------------------------------
1 | // material-ui
2 | import { Box, Chip, ChipProps, Grid, Stack, Typography } from "@mui/material";
3 |
4 | // project import
5 | import MainCard from "@/components/MainCard";
6 |
7 | // assets
8 | import { RiseOutlined, FallOutlined } from "@ant-design/icons";
9 |
10 | // ==============================|| STATISTICS - ECOMMERCE CARD ||============================== //
11 |
12 | interface Props {
13 | title: string;
14 | count: string;
15 | percentage?: number;
16 | isLoss?: boolean;
17 | color?: ChipProps["color"];
18 | extra: string;
19 | }
20 |
21 | const AnalyticEcommerce = ({ color = "primary", title, count, percentage, isLoss, extra }: Props) => (
22 |
23 |
24 |
25 | {title}
26 |
27 |
28 |
29 |
30 | {count}
31 |
32 |
33 | {percentage && (
34 |
35 |
40 | {!isLoss && }
41 | {isLoss && }
42 | >
43 | }
44 | label={`${percentage}%`}
45 | sx={{ ml: 1.25, pl: 1 }}
46 | size="small"
47 | />
48 |
49 | )}
50 |
51 |
52 |
53 |
54 | You made an extra{" "}
55 |
56 | {extra}
57 | {" "}
58 | this year
59 |
60 |
61 |
62 | );
63 |
64 | export default AnalyticEcommerce;
65 |
--------------------------------------------------------------------------------
/src/components/cards/statistics/AnalyticsDataCard.tsx:
--------------------------------------------------------------------------------
1 | // material-ui
2 | import { Box, Chip, ChipProps, Stack, Typography } from "@mui/material";
3 |
4 | // project import
5 | import MainCard from "@/components/MainCard";
6 |
7 | // assets
8 | import { RiseOutlined, FallOutlined } from "@ant-design/icons";
9 |
10 | // ==============================|| STATISTICS - ECOMMERCE CARD ||============================== //
11 |
12 | interface Props {
13 | title: string;
14 | count: string;
15 | percentage?: number;
16 | isLoss?: boolean;
17 | color?: ChipProps["color"];
18 | children: any;
19 | }
20 |
21 | const AnalyticsDataCard = ({ color = "primary", title, count, percentage, isLoss, children }: Props) => (
22 |
23 |
24 |
25 |
26 | {title}
27 |
28 |
29 |
30 | {count}
31 |
32 | {percentage && (
33 |
38 | {!isLoss && }
39 | {isLoss && }
40 | >
41 | }
42 | label={`${percentage}%`}
43 | sx={{ ml: 1.25, pl: 1 }}
44 | size="small"
45 | />
46 | )}
47 |
48 |
49 |
50 | {children}
51 |
52 | );
53 |
54 | export default AnalyticsDataCard;
55 |
--------------------------------------------------------------------------------
/src/components/logo/LogoMain.tsx:
--------------------------------------------------------------------------------
1 | // material-ui
2 | import { useTheme } from '@mui/material/styles';
3 | // import logoDark from 'assets/images/logo-dark.svg';
4 | // import logo from 'assets/images/logo.svg';
5 |
6 | /**
7 | * if you want to use image instead of