diff --git a/.biomeignore b/.biomeignore
index 06c526d..25e04f8 100644
--- a/.biomeignore
+++ b/.biomeignore
@@ -1,2 +1,4 @@
+**/*.css
+
**/*.module.css
diff --git a/biome.json b/biome.json
index 652a73a..7c037d0 100644
--- a/biome.json
+++ b/biome.json
@@ -9,6 +9,10 @@
"ignoreUnknown": false
},
"css": {
+ "parser": {
+ "cssModules": true,
+ "tailwindDirectives": true
+ },
"linter": {
"enabled": false
},
diff --git a/bun.lock b/bun.lock
index daf99ad..20ae0a0 100644
--- a/bun.lock
+++ b/bun.lock
@@ -13,6 +13,7 @@
"devDependencies": {
"@biomejs/biome": "2.3.11",
"@tailwindcss/postcss": "^4.1.18",
+ "@types/node": "^25.0.10",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@types/react-router-dom": "^5.3.3",
@@ -242,6 +243,8 @@
"@types/history": ["@types/history@4.7.11", "https://registry.npmmirror.com/@types/history/-/history-4.7.11.tgz", {}, "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA=="],
+ "@types/node": ["@types/node@25.0.10", "https://registry.npmmirror.com/@types/node/-/node-25.0.10.tgz", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="],
+
"@types/react": ["@types/react@19.2.9", "https://registry.npmmirror.com/@types/react/-/react-19.2.9.tgz", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA=="],
"@types/react-dom": ["@types/react-dom@19.2.3", "https://registry.npmmirror.com/@types/react-dom/-/react-dom-19.2.3.tgz", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
@@ -432,6 +435,8 @@
"typescript": ["typescript@5.7.3", "https://registry.npmmirror.com/typescript/-/typescript-5.7.3.tgz", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="],
+ "undici-types": ["undici-types@7.16.0", "https://registry.npmmirror.com/undici-types/-/undici-types-7.16.0.tgz", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+
"update-browserslist-db": ["update-browserslist-db@1.2.3", "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
"vite": ["vite@6.4.1", "https://registry.npmmirror.com/vite/-/vite-6.4.1.tgz", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
diff --git a/package.json b/package.json
index be5ed11..be48288 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
"devDependencies": {
"@biomejs/biome": "2.3.11",
"@tailwindcss/postcss": "^4.1.18",
+ "@types/node": "^25.0.10",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@types/react-router-dom": "^5.3.3",
diff --git a/src/App.module.css b/src/App.module.css
deleted file mode 100644
index 099cbe6..0000000
--- a/src/App.module.css
+++ /dev/null
@@ -1,10 +0,0 @@
-@reference "tailwindcss";
-
-.app {
- @apply min-h-screen flex flex-col;
-}
-
-.main {
- @apply flex-1 p-8;
-}
-
diff --git a/src/App.tsx b/src/App.tsx
index 3121946..dc3ae56 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,13 +1,12 @@
import { Outlet } from "react-router-dom";
-import styles from "./App.module.css";
import { Navigation } from "./components/business";
-import { cn } from "./lib/utils.ts";
+import { cn } from "./utils";
function App() {
return (
-
+
-
+
diff --git a/src/components/business/Navigation/Navigation.tsx b/src/components/business/Navigation/Navigation.tsx
index d55188c..00cdcd2 100644
--- a/src/components/business/Navigation/Navigation.tsx
+++ b/src/components/business/Navigation/Navigation.tsx
@@ -1,5 +1,5 @@
import { Link, useLocation } from "react-router-dom";
-import { cn } from "../../../lib/utils.ts";
+import { cn } from "@/utils";
import styles from "./Navigation.module.css";
interface NavItem {
diff --git a/src/components/common/Button/Button.tsx b/src/components/common/Button/Button.tsx
index 4faebf1..c3b6efa 100644
--- a/src/components/common/Button/Button.tsx
+++ b/src/components/common/Button/Button.tsx
@@ -1,5 +1,5 @@
import { type ButtonHTMLAttributes, forwardRef } from "react";
-import { cn } from "../../../lib/utils.ts";
+import { cn } from "@/utils";
import styles from "./Button.module.css";
export interface ButtonProps extends ButtonHTMLAttributes
{
diff --git a/src/pages/About/About.module.css b/src/pages/About/About.module.css
deleted file mode 100644
index f55f205..0000000
--- a/src/pages/About/About.module.css
+++ /dev/null
@@ -1,18 +0,0 @@
-@reference "tailwindcss";
-
-.container {
- @apply text-center;
-}
-
-.title {
- @apply text-4xl font-bold mb-4;
-}
-
-.description {
- @apply text-lg mb-4;
-}
-
-.actions {
- @apply flex gap-4 justify-center;
-}
-
diff --git a/src/pages/About/About.tsx b/src/pages/About/About.tsx
index af86390..cc8ac3f 100644
--- a/src/pages/About/About.tsx
+++ b/src/pages/About/About.tsx
@@ -1,13 +1,12 @@
import { Link } from "react-router-dom";
-import { Button } from "../../components/common";
-import styles from "./About.module.css";
+import { Button } from "@/components/common";
export function About() {
return (
-
-
关于我们
-
这是关于页面
-
+
+
关于我们
+
这是关于页面
+
diff --git a/src/pages/Home/Home.module.css b/src/pages/Home/Home.module.css
deleted file mode 100644
index 457b3af..0000000
--- a/src/pages/Home/Home.module.css
+++ /dev/null
@@ -1,22 +0,0 @@
-.container {
- text-align: center;
-}
-
-.title {
- margin-bottom: 1rem;
- font-size: 2.25rem;
- line-height: 2.5rem;
- font-weight: 700;
-}
-
-.description {
- margin-bottom: 1rem;
- font-size: 1.125rem;
- line-height: 1.75rem;
-}
-
-.actions {
- display: flex;
- gap: 1rem;
- justify-content: center;
-}
diff --git a/src/pages/Home/Home.tsx b/src/pages/Home/Home.tsx
index dfdd0b0..3b473dd 100644
--- a/src/pages/Home/Home.tsx
+++ b/src/pages/Home/Home.tsx
@@ -1,13 +1,12 @@
import { Link } from "react-router-dom";
-import { Button } from "../../components/common";
-import styles from "./Home.module.css";
+import { Button } from "@/components/common";
export function Home() {
return (
-
-
首页
-
欢迎来到首页
-
+
+
首页
+
欢迎来到首页
+
diff --git a/src/utils/assets.ts b/src/utils/assets.ts
new file mode 100644
index 0000000..7172e02
--- /dev/null
+++ b/src/utils/assets.ts
@@ -0,0 +1,49 @@
+// 图片资源映射 - 使用静态导入确保构建时包含所有图片
+const imageModules = import.meta.glob(
+ "../assets/images/**/*.{png,jpg,jpeg,gif,svg,webp}",
+ {
+ eager: true,
+ },
+);
+
+// 访问静态图片 - 使用静态导入确保构建后路径正确
+export const getStaticImage = (path: string) => {
+ try {
+ // 确保路径以正确的格式结尾
+ const imagePath =
+ path.endsWith(".png") ||
+ path.endsWith(".jpg") ||
+ path.endsWith(".jpeg") ||
+ path.endsWith(".gif") ||
+ path.endsWith(".svg") ||
+ path.endsWith(".webp")
+ ? `../assets/images/${path}`
+ : `../assets/images/${path}.png`;
+
+ // 使用静态导入的模块
+ const module = imageModules[imagePath];
+ if (module && typeof module === "object" && "default" in module) {
+ return (module as { default: string }).default;
+ }
+
+ // 回退到 URL 方式
+ return new URL(imagePath, import.meta.url).href;
+ } catch (error) {
+ console.error("Failed to load image:", path, error);
+ return "";
+ }
+};
+
+// 获取背景图片的专用函数
+export const getBackgroundImage = (path: string) => {
+ const imageUrl = getStaticImage(path);
+ return imageUrl ? `url(${imageUrl})` : "none";
+};
+
+// 获取 public 文件夹中的资源路径(用于 Word 文档等)
+export const getPublicPath = (path: string) => {
+ // 移除开头的斜杠(如果有)
+ const cleanPath = path.startsWith("/") ? path.slice(1) : path;
+ // 使用 Vite 的 BASE_URL 环境变量来处理基础路径
+ return `${import.meta.env.BASE_URL}${cleanPath}`;
+};
diff --git a/src/utils/index.ts b/src/utils/index.ts
new file mode 100644
index 0000000..b10ebca
--- /dev/null
+++ b/src/utils/index.ts
@@ -0,0 +1,2 @@
+export * from "./assets";
+export * from "./tailwind";
diff --git a/src/lib/utils.ts b/src/utils/tailwind.ts
similarity index 100%
rename from src/lib/utils.ts
rename to src/utils/tailwind.ts
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..f7de5e9
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,8 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+};
diff --git a/tsconfig.app.json b/tsconfig.app.json
index 7c5e039..999894e 100644
--- a/tsconfig.app.json
+++ b/tsconfig.app.json
@@ -20,7 +20,11 @@
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true
+ "noFallthroughCasesInSwitch": true,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["src/*"]
+ }
},
"include": ["src"]
}
diff --git a/tsconfig.node.json b/tsconfig.node.json
index db22aa9..fab4b26 100644
--- a/tsconfig.node.json
+++ b/tsconfig.node.json
@@ -14,6 +14,9 @@
"moduleDetection": "force",
"noEmit": true,
+ /* Node typings for config files */
+ "types": ["node"],
+
/* Linting */
"strict": true,
"noUnusedLocals": true,
diff --git a/vite.config.ts b/vite.config.ts
index 4ff91eb..d8d5151 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,7 +1,13 @@
+import { fileURLToPath } from "node:url";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
+ resolve: {
+ alias: {
+ "@": fileURLToPath(new URL("./src", import.meta.url)),
+ },
+ },
});