commit 7cc246fbf38f3b9e32aeccae655e319a2fb6488d Author: zhilv Date: Sun Nov 16 15:00:14 2025 +0800 feat(init): init project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7f2e335 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* +pnpm-lock.yaml + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..98475b5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +pnpm test diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 0000000..2500361 --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1,64 @@ +// Prettier 配置文件(CommonJS 写法) +// 保存文件后 Prettier 插件会自动读取并格式化项目代码 +module.exports = { + // 使用的 Prettier 插件,这里启用 TailwindCSS 排序插件 + plugins: ["prettier-plugin-tailwindcss"], + + // 每行最大长度,超过后自动换行 + printWidth: 80, + + // 每个缩进层级使用的空格数 + tabWidth: 2, + + // 使用制表符(tab)而不是空格进行缩进 + useTabs: true, + + // 每句结尾加分号 + semi: true, + + // 使用单引号而不是双引号 + singleQuote: true, + + // 对象属性引号的使用规则: + // as-needed:仅在必要时添加 + // consistent:同一对象中保持一致 + // preserve:保持原样 + quoteProps: "as-needed", + + // 在 JSX 中是否使用单引号 + jsxSingleQuote: false, + + // 多行结构时是否在末尾加逗号 + // 可选值:none | es5 | all + trailingComma: "es5", + + // 在对象字面量中,是否在大括号之间加空格 + bracketSpacing: true, + + // 标签的 `>` 是否与最后一行标签同一行 + bracketSameLine: false, + + // 箭头函数参数是否总是加括号 + // always:总是加,如 (x) => x + // avoid:当只有一个参数时省略括号,如 x => x + arrowParens: "always", + + // 控制 Markdown 文本的换行策略 + // preserve:保持原样 + // never:不换行 + // always:超过 printWidth 自动换行 + proseWrap: "preserve", + + // 控制 HTML 空白敏感度 + // css:遵循 CSS 的 display 属性 + // strict:严格保留 + // ignore:忽略空白 + htmlWhitespaceSensitivity: "css", + + // 在 Vue 文件的 + + + \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..e9274fa --- /dev/null +++ b/package.json @@ -0,0 +1,51 @@ +{ + "name": "cn.kmux.navsitereact", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview", + "prepare": "husky" + }, + "dependencies": { + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.553.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-router-dom": "^6.30.2", + "tailwind-merge": "^3.4.0", + "tailwind-scrollbar": "^4.0.2", + "tailwindcss": "^4.1.17" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@tailwindcss/vite": "^4.1.17", + "@types/node": "^24.10.0", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", + "@vitejs/plugin-react": "^5.1.0", + "babel-plugin-react-compiler": "^19.1.0-rc.3", + "cz-conventional-changelog": "^3.3.0", + "eslint": "^9.39.1", + "eslint-plugin-prettier": "^5.5.4", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "husky": "^9.1.7", + "prettier": "^3.6.2", + "prettier-plugin-tailwindcss": "^0.7.1", + "tw-animate-css": "^1.4.0", + "typescript": "~5.9.3", + "typescript-eslint": "^8.46.3", + "vite": "^7.2.2" + }, + "config": { + "commitizen": { + "path": "cz-conventional-changelog" + } + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..252c802 Binary files /dev/null and b/public/favicon.ico differ diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..544badc --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,5 @@ +function App() { + return
App
; +} + +export default App; diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..1fe4301 --- /dev/null +++ b/src/index.css @@ -0,0 +1,122 @@ +@import "tailwindcss"; +@import "tw-animate-css"; +@plugin 'tailwind-scrollbar'; + +:root { + @apply flex h-full w-full items-center justify-center; + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +@custom-variant dark (&:where(.dark, .dark *)); + +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..eff7ccc --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import "./index.css"; +import App from "./App.tsx"; + +createRoot(document.getElementById("root")!).render( + + + , +); diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..2ebd347 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + }, + + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..fec8c8e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..8a67f62 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..1624a89 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,31 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import tailwind from "@tailwindcss/vite"; +import path from "path"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: [["babel-plugin-react-compiler"]], + }, + }), + tailwind(), + ], + server: { + host: true, + allowedHosts: ["local.kmux.cn"], + proxy: { + "/api": { + target: "http://local.kmux.cn:8080", + changeOrigin: true, + }, + }, + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "src"), + }, + }, +});