diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 0000000..9fc721f
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,15 @@
+import tseslint from "typescript-eslint";
+import next from "@next/eslint-plugin-next";
+
+export default [
+ { ignores: [".next/**", "node_modules/**", "scripts/**", "next.config.js"] },
+ ...tseslint.configs.recommended,
+ {
+ files: ["**/*.{js,jsx,ts,tsx}"],
+ plugins: { "@next/next": next },
+ rules: {
+ ...next.configs.recommended.rules,
+ ...next.configs["core-web-vitals"].rules,
+ },
+ },
+];
diff --git a/next-env.d.ts b/next-env.d.ts
index 40c3d68..c4b7818 100644
--- a/next-env.d.ts
+++ b/next-env.d.ts
@@ -1,5 +1,6 @@
///
///
+import "./.next/dev/types/routes.d.ts";
// NOTE: This file should not be edited
-// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
+// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/next.config.js b/next.config.js
index 5722927..c10e07d 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,40 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
- async headers() {
- const isDev = process.env.NODE_ENV === "development"
- const csp = [
- "default-src 'self'",
- "base-uri 'self'",
- "frame-ancestors 'none'",
- "object-src 'none'",
- "form-action 'self'",
- "img-src 'self' data:",
- isDev
- ? "script-src 'self' 'unsafe-eval' 'unsafe-inline'"
- : "script-src 'self'",
- "style-src 'self' 'unsafe-inline'",
- "connect-src 'self'",
- ].join("; ")
-
- return [
- {
- source: "/(.*)",
- headers: [
- { key: "Content-Security-Policy", value: csp },
- { key: "X-Frame-Options", value: "DENY" },
- { key: "X-Content-Type-Options", value: "nosniff" },
- { key: "Referrer-Policy", value: "no-referrer" },
- {
- key: "Strict-Transport-Security",
- value: "max-age=63072000; includeSubDomains; preload",
- },
- { key: "Permissions-Policy", value: "geolocation=(), microphone=(), camera=()" },
- ],
- },
- ]
- },
-}
-
-module.exports = nextConfig
+};
+module.exports = nextConfig;
diff --git a/package.json b/package.json
index f15838c..71a893e 100644
--- a/package.json
+++ b/package.json
@@ -1,34 +1,38 @@
{
- "name": "cms-front",
- "private": true,
- "version": "0.1.0",
- "scripts": {
- "dev": "next dev -p 6031",
- "build": "next build",
- "start": "next start -p 6031",
- "lint": "next lint"
- },
- "dependencies": {
- "@radix-ui/react-checkbox": "^1.3.0",
- "@radix-ui/react-label": "^2.1.0",
- "@radix-ui/react-slot": "^1.2.0",
- "class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1",
- "lucide-react": "^0.468.0",
- "next": "^14.2.25",
- "react": "^18.3.1",
- "react-dom": "^18.3.1",
- "tailwind-merge": "^2.5.4"
- },
- "devDependencies": {
- "@types/node": "^20.17.16",
- "@types/react": "^18.3.18",
- "@types/react-dom": "^18.3.5",
- "autoprefixer": "^10.4.20",
- "eslint": "^8.57.1",
- "eslint-config-next": "^14.2.25",
- "postcss": "^8.5.1",
- "tailwindcss": "^3.4.17",
- "typescript": "^5.7.3"
- }
-}
\ No newline at end of file
+ "name": "cms-front",
+ "private": true,
+ "version": "0.1.0",
+ "scripts": {
+ "dev": "next dev --turbopack -p 6031",
+ "build": "next build",
+ "start": "next start -p 6031",
+ "lint": "eslint .",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@radix-ui/react-checkbox": "^1.3.0",
+ "@radix-ui/react-label": "^2.1.0",
+ "@radix-ui/react-slot": "^1.2.0",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-react": "^0.468.0",
+ "next": "^16.1.6",
+ "react": "^19.2.4",
+ "react-dom": "^19.2.4",
+ "tailwind-merge": "^3.4.0"
+ },
+ "devDependencies": {
+ "@next/eslint-plugin-next": "^16.1.6",
+ "@tailwindcss/postcss": "^4.1.18",
+ "@types/node": "^20.17.16",
+ "@types/react": "^19.2.0",
+ "@types/react-dom": "^19.2.0",
+ "autoprefixer": "^10.4.20",
+ "eslint": "^9.39.2",
+ "eslint-config-next": "^16.1.6",
+ "postcss": "^8.5.1",
+ "tailwindcss": "^4.1.18",
+ "typescript": "^5.7.3",
+ "typescript-eslint": "^8.54.0"
+ }
+}
diff --git a/postcss.config.js b/postcss.config.js
deleted file mode 100644
index 2ce518b..0000000
--- a/postcss.config.js
+++ /dev/null
@@ -1,7 +0,0 @@
-module.exports = {
- plugins: {
- tailwindcss: {},
- autoprefixer: {},
- },
-}
-
diff --git a/postcss.config.mjs b/postcss.config.mjs
new file mode 100644
index 0000000..14502dc
--- /dev/null
+++ b/postcss.config.mjs
@@ -0,0 +1,6 @@
+export default {
+ plugins: {
+ "@tailwindcss/postcss": {},
+ autoprefixer: {},
+ },
+}
diff --git a/src/app/auth-error/page.tsx b/src/app/auth-error/page.tsx
index 4d9bb91..cd53bd3 100644
--- a/src/app/auth-error/page.tsx
+++ b/src/app/auth-error/page.tsx
@@ -1,18 +1,21 @@
-export default function AuthErrorPage({
+import Link from "next/link";
+
+export default async function AuthErrorPage({
searchParams,
}: {
- searchParams?: { message?: string }
+ searchParams: Promise<{ message?: string }>
}) {
- const message = searchParams?.message ?? "认证失败"
+ const sp = await searchParams;
+ const message = sp?.message ?? "认证失败"
return (
diff --git a/src/app/globals.css b/src/app/globals.css
index 4ec32f8..3453f03 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -1,6 +1,96 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
+@import "tailwindcss";
+
+@custom-variant dark (&:where(.dark, .dark *));
+
+@theme {
+ --color-border: hsl(var(--border));
+ --color-input: hsl(var(--input));
+ --color-ring: hsl(var(--ring));
+ --color-background: hsl(var(--background));
+ --color-foreground: hsl(var(--foreground));
+
+ --color-primary: hsl(var(--primary));
+ --color-primary-foreground: hsl(var(--primary-foreground));
+
+ --color-secondary: hsl(var(--secondary));
+ --color-secondary-foreground: hsl(var(--secondary-foreground));
+
+ --color-destructive: hsl(var(--destructive));
+ --color-destructive-foreground: hsl(var(--destructive-foreground));
+
+ --color-muted: hsl(var(--muted));
+ --color-muted-foreground: hsl(var(--muted-foreground));
+
+ --color-accent: hsl(var(--accent));
+ --color-accent-foreground: hsl(var(--accent-foreground));
+
+ --color-card: hsl(var(--card));
+ --color-card-foreground: hsl(var(--card-foreground));
+
+ --radius-lg: var(--radius);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-sm: calc(var(--radius) - 4px);
+
+ /* Custom Container Max Width */
+ --container-max-width: 1200px;
+}
+
+/* Fluid Typography & Base Styles */
+@layer base {
+ html {
+ /* Mobile base size */
+ font-size: 14px;
+
+ /* Desktop base size (md breakpoint approx 768px) */
+ @media (min-width: 768px) {
+ font-size: 16px;
+ }
+ }
+
+ h1, h2, h3, h4, h5, h6 {
+ /* Fluid scaling using clamp/calc */
+ font-size: clamp(1.25rem, 1rem + 1vw, 2.5rem);
+ line-height: 1.2;
+ }
+}
+
+/* Utility for Grid System */
+@utility grid-responsive {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 1rem;
+
+ @media (min-width: 768px) {
+ grid-template-columns: repeat(8, minmax(0, 1fr));
+ }
+
+ @media (min-width: 1024px) {
+ grid-template-columns: repeat(12, minmax(0, 1fr));
+ }
+}
+
+/* Utility for Responsive Content Container */
+@utility container-responsive {
+ width: 100%;
+ margin-left: auto;
+ margin-right: auto;
+ max-width: 1200px;
+
+ /* Mobile Padding */
+ padding-left: 1rem; /* 16px */
+ padding-right: 1rem;
+
+ @media (min-width: 768px) {
+ /* Tablet/Desktop Padding */
+ padding-left: 2.5rem; /* 40px */
+ padding-right: 2.5rem;
+ }
+
+ @media (min-width: 1024px) {
+ padding-left: 3.75rem; /* 60px */
+ padding-right: 3.75rem;
+ }
+}
:root {
--background: 0 0% 100%;
@@ -27,4 +117,3 @@ body {
background: hsl(var(--background));
color: hsl(var(--foreground));
}
-
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 71ddcf4..88b4298 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,8 +1,9 @@
import { cookies } from "next/headers"
-export default function Home() {
- const tenantId = cookies().get("tenantId")?.value ?? ""
- const userId = cookies().get("userId")?.value ?? ""
+export default async function Home() {
+ const cookieStore = await cookies()
+ const tenantId = cookieStore.get("tenantId")?.value ?? ""
+ const userId = cookieStore.get("userId")?.value ?? ""
return (
diff --git a/src/middleware.ts b/src/proxy.ts
similarity index 98%
rename from src/middleware.ts
rename to src/proxy.ts
index 362b61f..92529fa 100644
--- a/src/middleware.ts
+++ b/src/proxy.ts
@@ -19,7 +19,7 @@ function isExpired(jwt: string): boolean {
}
}
-export function middleware(req: NextRequest) {
+export function proxy(req: NextRequest) {
if (process.env.NODE_ENV === "production") {
const proto = req.headers.get("x-forwarded-proto");
if (proto && proto !== "https") {
diff --git a/tailwind.config.ts b/tailwind.config.ts
deleted file mode 100644
index fc85e23..0000000
--- a/tailwind.config.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import type { Config } from "tailwindcss"
-
-const config: Config = {
- darkMode: ["class"],
- content: ["./src/**/*.{ts,tsx}"],
- theme: {
- container: {
- center: true,
- padding: "2rem",
- screens: {
- "2xl": "1400px",
- },
- },
- extend: {
- colors: {
- border: "hsl(var(--border))",
- input: "hsl(var(--input))",
- ring: "hsl(var(--ring))",
- background: "hsl(var(--background))",
- foreground: "hsl(var(--foreground))",
- primary: {
- DEFAULT: "hsl(var(--primary))",
- foreground: "hsl(var(--primary-foreground))",
- },
- secondary: {
- DEFAULT: "hsl(var(--secondary))",
- foreground: "hsl(var(--secondary-foreground))",
- },
- muted: {
- DEFAULT: "hsl(var(--muted))",
- foreground: "hsl(var(--muted-foreground))",
- },
- accent: {
- DEFAULT: "hsl(var(--accent))",
- foreground: "hsl(var(--accent-foreground))",
- },
- destructive: {
- DEFAULT: "hsl(var(--destructive))",
- foreground: "hsl(var(--destructive-foreground))",
- },
- card: {
- DEFAULT: "hsl(var(--card))",
- foreground: "hsl(var(--card-foreground))",
- },
- },
- borderRadius: {
- lg: "var(--radius)",
- md: "calc(var(--radius) - 2px)",
- sm: "calc(var(--radius) - 4px)",
- },
- },
- },
- plugins: [],
-}
-
-export default config
-
diff --git a/tsconfig.json b/tsconfig.json
index 48907b4..ac64d54 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -11,15 +11,24 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
- "jsx": "preserve",
+ "jsx": "react-jsx",
"incremental": true,
- "plugins": [{ "name": "next" }],
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts",
+ ".next/dev/types/**/*.ts"
+ ],
"exclude": ["node_modules"]
}
-