├── .eslintignore ├── src ├── vite-env.d.ts ├── components │ ├── universal │ │ ├── Editor │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ ├── Title │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ ├── Space │ │ │ └── index.tsx │ │ ├── Color │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ ├── Button │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ ├── FloatBtn │ │ │ ├── index.tsx │ │ │ └── index.module.css │ │ ├── Tabs │ │ │ └── index.module.css │ │ ├── Loading │ │ │ └── index.tsx │ │ ├── FileContextMenu │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ ├── Toggle │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ ├── CheckBox │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ ├── Radio │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ ├── Editable │ │ │ └── index.tsx │ │ ├── Modal │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ ├── Tags │ │ │ └── index.module.css │ │ └── Calendar │ │ │ └── index.module.css │ ├── widgets │ │ ├── ThemeComponent │ │ │ ├── ThemeTextarea.tsx │ │ │ ├── ThemeSelect.tsx │ │ │ └── index.tsx │ │ ├── Footer │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ ├── Sidebar │ │ │ ├── item │ │ │ │ ├── index.module.css │ │ │ │ └── index.tsx │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ ├── ActionButtons │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ └── CommandDialog │ │ │ └── index.tsx │ └── ui │ │ ├── Collapse │ │ ├── index.tsx │ │ └── index.module.css │ │ ├── label.tsx │ │ ├── textarea.tsx │ │ ├── input.tsx │ │ ├── checkbox.tsx │ │ ├── popover.tsx │ │ ├── date-picker.tsx │ │ ├── button.tsx │ │ ├── data-table-column-header.tsx │ │ ├── calendar.tsx │ │ ├── table.tsx │ │ ├── data-table-pagination.tsx │ │ ├── select.tsx │ │ └── dialog.tsx ├── pages │ ├── Posts │ │ ├── Friends │ │ │ ├── index.module.css │ │ │ └── index.tsx │ │ └── Index │ │ │ ├── Table │ │ │ ├── data-table.tsx │ │ │ └── column.tsx │ │ │ ├── index.module.css │ │ │ └── index.tsx │ ├── Schedule │ │ ├── index.module.css │ │ └── Table │ │ │ ├── data-table.tsx │ │ │ └── column.tsx │ ├── Comments │ │ ├── index.module.css │ │ ├── Table │ │ │ ├── data-table.tsx │ │ │ └── column.tsx │ │ ├── index.tsx │ │ └── component.tsx │ ├── Themes │ │ ├── Table │ │ │ ├── data-table.tsx │ │ │ └── column.tsx │ │ └── index.module.css │ ├── Pages │ │ └── Index │ │ │ ├── Table │ │ │ ├── data-table.tsx │ │ │ └── column.tsx │ │ │ └── index.tsx │ ├── InternelServerErrorPage │ │ ├── index.tsx │ │ └── index.module.css │ ├── Friends │ │ ├── index.module.css │ │ └── Table │ │ │ └── column.tsx │ ├── Status │ │ ├── index.module.css │ │ └── index.tsx │ ├── Home │ │ ├── Table │ │ │ ├── columns.tsx │ │ │ └── data-table.tsx │ │ ├── universal.tsx │ │ └── index.module.css │ ├── Write │ │ ├── Input.tsx │ │ ├── index.module.css │ │ └── fields.tsx │ ├── Settings │ │ └── index.module.css │ ├── Files │ │ ├── index.module.css │ │ └── index.tsx │ ├── Categories │ │ └── index.module.css │ ├── Login │ │ ├── index.module.css │ │ └── index.tsx │ └── Register │ │ └── index.tsx ├── utils │ ├── path.ts │ ├── avatar.ts │ ├── mouse.ts │ ├── date.ts │ ├── env.ts │ ├── storage.ts │ ├── url.ts │ ├── mock.ts │ ├── promise.ts │ ├── cookie.ts │ └── request.ts ├── states │ ├── private.ts │ └── app.ts ├── libs │ ├── cn.ts │ └── dialogs.ts ├── types │ └── basic.ts ├── hooks │ ├── useAppCheck.ts │ ├── useInitalData.ts │ ├── useValidateUser.ts │ ├── useSeo.ts │ └── useHomeAggregateData.ts ├── types.d.ts ├── constants │ └── services.ts ├── main.tsx ├── App.tsx ├── sidebar.tsx ├── index.css ├── style.css └── router │ └── router.tsx ├── renovate.json ├── public └── background.avif ├── tsconfig.node.json ├── .gitignore ├── components.json ├── postcss.config.js ├── .eslintrc.js ├── index.html ├── vite.config.ts ├── README.md ├── tsconfig.json ├── .github └── workflows │ ├── build.yml │ └── release.yml ├── tailwind.config.js └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | tmp -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "ignoreDeps": [] 6 | } -------------------------------------------------------------------------------- /src/components/universal/Editor/index.module.css: -------------------------------------------------------------------------------- 1 | .editor { 2 | margin-top: 50px; 3 | 4 | } -------------------------------------------------------------------------------- /public/background.avif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mogland/console/HEAD/public/background.avif -------------------------------------------------------------------------------- /src/pages/Posts/Friends/index.module.css: -------------------------------------------------------------------------------- 1 | .tableItem { 2 | width: 100%; 3 | height: inherit; 4 | cursor: pointer; 5 | } -------------------------------------------------------------------------------- /src/utils/path.ts: -------------------------------------------------------------------------------- 1 | export function jump(p: string) { 2 | const base = window.MOG_BASE || ""; 3 | return `${base}${p}`; 4 | } 5 | -------------------------------------------------------------------------------- /src/states/private.ts: -------------------------------------------------------------------------------- 1 | import { proxy } from "valtio"; 2 | 3 | export const _private = proxy({ 4 | showModal: false, 5 | modalDataId: "", 6 | refreshData: false, 7 | }); 8 | -------------------------------------------------------------------------------- /src/utils/avatar.ts: -------------------------------------------------------------------------------- 1 | import md5 from "md5"; 2 | 3 | export const mailAvatar = (mail: string) => { 4 | const md5Mail = md5(mail); 5 | return `https://cravatar.cn/avatar/${md5Mail}`; 6 | }; 7 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": ["./vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /src/libs/cn.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/mouse.ts: -------------------------------------------------------------------------------- 1 | export function calculateMousePosition(e: React.MouseEvent) { 2 | const { clientX, clientY } = e; 3 | return { 4 | x: clientX, 5 | y: clientY, 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /src/pages/Schedule/index.module.css: -------------------------------------------------------------------------------- 1 | .selected { 2 | background-color: var(--background-color-quaternary) !important; 3 | } 4 | 5 | .error { 6 | color: var(--text-color-primary); 7 | font-size: 12px; 8 | font-family: monospace; 9 | } -------------------------------------------------------------------------------- /src/utils/date.ts: -------------------------------------------------------------------------------- 1 | export function getMonthDays(year: number, month: number) { 2 | return new Date(year, month, 0).getDate(); 3 | } 4 | 5 | export function getFirstDay(year: number, month: number) { 6 | return new Date(year, month - 1, 1).getDay(); 7 | } 8 | -------------------------------------------------------------------------------- /src/components/universal/Title/index.module.css: -------------------------------------------------------------------------------- 1 | .title { 2 | font-size: 1.5rem; 3 | font-weight: 600; 4 | color: #000; 5 | margin: 0; 6 | padding-bottom: 20px; 7 | } 8 | 9 | @media (prefers-color-scheme: dark) { 10 | .title { 11 | color: #fff; 12 | } 13 | } -------------------------------------------------------------------------------- /src/components/universal/Title/index.tsx: -------------------------------------------------------------------------------- 1 | import styles from "./index.module.css"; 2 | 3 | export const Title = ({ children }: { children: React.ReactNode }) => { 4 | return ( 5 |
6 |

{children}

7 |
8 | ); 9 | }; 10 | -------------------------------------------------------------------------------- /src/utils/env.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @FilePath: /nx-admin/src/utils/env.ts 3 | * @author: Wibus 4 | * @Date: 2022-07-15 20:54:24 5 | * @LastEditors: Wibus 6 | * @LastEditTime: 2022-07-15 20:54:25 7 | * Coding With IU 8 | */ 9 | export const isDev = process.env.NODE_ENV === "development"; 10 | -------------------------------------------------------------------------------- /src/types/basic.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @FilePath: /nx-admin/src/types/basic.ts 3 | * @author: Wibus 4 | * @Date: 2022-07-15 18:58:55 5 | * @LastEditors: Wibus 6 | * @LastEditTime: 2022-07-15 19:59:33 7 | * Coding With IU 8 | */ 9 | 10 | // BasicPage type 必须返回一个 jsx 元素 11 | export type BasicPage = () => JSX.Element; 12 | -------------------------------------------------------------------------------- /src/components/universal/Space/index.tsx: -------------------------------------------------------------------------------- 1 | interface Prop { 2 | height?: number | string; 3 | } 4 | 5 | export const Space: React.FC = (props) => { 6 | return ( 7 | <> 8 |
13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /src/utils/storage.ts: -------------------------------------------------------------------------------- 1 | export function getStorage(key: string) { 2 | return localStorage.getItem(key) || null; 3 | } 4 | 5 | export function setStorage(key: string, value: string) { 6 | localStorage.setItem(key, value); 7 | return value; 8 | } 9 | 10 | export function removeStorage(key: string) { 11 | localStorage.removeItem(key); 12 | } 13 | -------------------------------------------------------------------------------- /src/components/universal/Color/index.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-wrap: wrap; 4 | } 5 | .color { 6 | border-radius: 4px; 7 | display: inline-block; 8 | height: 20px; 9 | width: 50px; 10 | margin-top: 16px; 11 | margin-left: 10px; 12 | } 13 | 14 | /* 移除掉原生的边框 */ 15 | .color { 16 | background-color: initial; 17 | } -------------------------------------------------------------------------------- /src/utils/url.ts: -------------------------------------------------------------------------------- 1 | export function getQueryVariable(variable: string) { 2 | const query = window.location.search.substring(1); 3 | const vars = query.split("&"); 4 | for (let i = 0; i < vars.length; i++) { 5 | const pair = vars[i].split("="); 6 | if (pair[0] == variable) { 7 | return pair[1]; 8 | } 9 | } 10 | return false; 11 | } 12 | -------------------------------------------------------------------------------- /src/libs/dialogs.ts: -------------------------------------------------------------------------------- 1 | import { createDialogs, createDialogHooks } from "react-hook-dialog"; 2 | 3 | export const dialogs = createDialogs({ 4 | fileContextMenu: { 5 | path: "", 6 | name: "", 7 | position: { x: 0, y: 0 }, 8 | onRename: () => {}, 9 | isFile: true, 10 | }, 11 | }); 12 | 13 | export const dialog = createDialogHooks(dialogs); 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /src/pages/Comments/index.module.css: -------------------------------------------------------------------------------- 1 | .reply { 2 | margin-left: 1rem; 3 | margin-top: 1rem; 4 | border-left: 4px solid rgb(0, 166, 0); 5 | padding-left: 0.8rem; 6 | color: rgba(0, 114, 0, 0.674); 7 | } 8 | 9 | 10 | @media (prefers-color-scheme: dark) { 11 | .reply { 12 | border-left: 4px solid rgb(63, 169, 63); 13 | color: rgba(93, 255, 93, 0.674); 14 | } 15 | } -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "src/index.css", 9 | "baseColor": "slate", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@components/ui", 14 | "utils": "@libs/cn" 15 | } 16 | } -------------------------------------------------------------------------------- /src/hooks/useAppCheck.ts: -------------------------------------------------------------------------------- 1 | import { app } from "@states/app"; 2 | import { useInitialData } from "./useInitalData"; 3 | import { useValidateUser } from "./useValidateUser"; 4 | import useSWR from "swr"; 5 | 6 | export function useAppCheck() { 7 | const { error: gatewayError } = useSWR("/ping"); 8 | app.gatewayError = !!gatewayError; 9 | 10 | useInitialData(); 11 | useValidateUser(); 12 | } 13 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @FilePath: /nx-admin/postcss.config.js 3 | * @author: Wibus 4 | * @Date: 2022-07-12 16:40:21 5 | * @LastEditors: Wibus 6 | * @LastEditTime: 2022-07-14 16:30:09 7 | * Coding With IU 8 | */ 9 | module.exports = { 10 | plugins: { 11 | 'postcss-import': {}, 12 | // 'postcss-nested': {}, 13 | 'tailwindcss/nesting': {}, 14 | 'tailwindcss': {}, 15 | 'autoprefixer': {}, 16 | }, 17 | } -------------------------------------------------------------------------------- /src/utils/mock.ts: -------------------------------------------------------------------------------- 1 | export function generagteRandomEchartCategory(number: number) { 2 | const result: string[] = []; 3 | for (let i = 0; i < number; i++) { 4 | result.push(`Day${i}`); 5 | } 6 | return result; 7 | } 8 | 9 | export function generateRandomEchartData(number: number) { 10 | const result: number[] = []; 11 | for (let i = 0; i < number; i++) { 12 | result.push(Math.floor(Math.random() * 100)); 13 | } 14 | return result; 15 | } 16 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@innei/eslint-config-react-ts'], 3 | rules: { 4 | '@typescript-eslint/no-empty-function': 'off', 5 | '@typescript-eslint/no-empty-interface': 'off', 6 | '@typescript-eslint/no-non-null-assertion': 'off', 7 | 'no-restricted-globals': ['error', 'close', 'open', 'name', 'event'], 8 | 'react-hooks/rules-of-hooks': 'off', 9 | }, 10 | settings: { 11 | react: { 12 | version: 'detect', 13 | }, 14 | } 15 | } -------------------------------------------------------------------------------- /src/types.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | export interface History { 3 | backPath: string[]; 4 | } 5 | export interface Window { 6 | MOG_API: string; 7 | MOG_BASE: string; 8 | version: string; 9 | PATTERN: "CORE" | "STANDALONE"; 10 | } 11 | } 12 | 13 | interface HTMLFormElement extends HTMLElement { 14 | elements: HTMLFormControlsCollection; 15 | } 16 | 17 | interface HTMLInputElement extends HTMLElement { 18 | value: string; 19 | } 20 | 21 | export {}; 22 | -------------------------------------------------------------------------------- /src/components/universal/Button/index.module.css: -------------------------------------------------------------------------------- 1 | .button { 2 | @apply inline-flex justify-center rounded-md border border-transparent px-4 py-2 text-sm font-medium; 3 | color: var(--modal-text-color); 4 | background-color: var(--modal-background-color) !important; 5 | transition: background-color 0.2s ease; 6 | user-select: none; 7 | } 8 | 9 | .button:hover { 10 | background-color: var(--modal-hover-background-color) !important; 11 | } 12 | 13 | .button:not(last-child) { 14 | @apply mr-2; 15 | } 16 | -------------------------------------------------------------------------------- /src/pages/Themes/Table/data-table.tsx: -------------------------------------------------------------------------------- 1 | import type { AnyListDataTableProps } from "@components/widgets/AnyListDataTable/table"; 2 | import { AnyListDataTable } from "@components/widgets/AnyListDataTable/table"; 3 | 4 | export function ThemesListDataTable({ 5 | columns, 6 | data, 7 | header, 8 | }: AnyListDataTableProps) { 9 | return ( 10 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/components/widgets/ThemeComponent/ThemeTextarea.tsx: -------------------------------------------------------------------------------- 1 | import type { TextareaProps } from "@components/ui/textarea"; 2 | import { Textarea } from "@components/ui/textarea"; 3 | import { Label } from "@components/ui/label"; 4 | 5 | export const ThemeTextarea: React.FC< 6 | TextareaProps & { 7 | label: string; 8 | } 9 | > = (props) => { 10 | return ( 11 |
12 | 13 |