diff --git a/web/client/index.html b/web/client/index.html
new file mode 100644
index 0000000..4afb630
--- /dev/null
+++ b/web/client/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ 美图 Agent
+
+
+
+
+
+
diff --git a/web/client/postcss.config.js b/web/client/postcss.config.js
new file mode 100644
index 0000000..2aa7205
--- /dev/null
+++ b/web/client/postcss.config.js
@@ -0,0 +1,6 @@
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+};
diff --git a/web/client/src/index.css b/web/client/src/index.css
new file mode 100644
index 0000000..8457857
--- /dev/null
+++ b/web/client/src/index.css
@@ -0,0 +1,12 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+ body {
+ @apply bg-zinc-950 text-zinc-50;
+ }
+}
diff --git a/web/client/src/lib/utils.ts b/web/client/src/lib/utils.ts
new file mode 100644
index 0000000..2819a83
--- /dev/null
+++ b/web/client/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/web/client/src/main.tsx b/web/client/src/main.tsx
new file mode 100644
index 0000000..2339d59
--- /dev/null
+++ b/web/client/src/main.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App';
+import './index.css';
+
+ReactDOM.createRoot(document.getElementById('root')!).render(
+
+
+
+);
diff --git a/web/client/tailwind.config.ts b/web/client/tailwind.config.ts
new file mode 100644
index 0000000..05b7dfb
--- /dev/null
+++ b/web/client/tailwind.config.ts
@@ -0,0 +1,43 @@
+import type { Config } from 'tailwindcss';
+
+export default {
+ content: ['./client/src/**/*.{ts,tsx}'],
+ darkMode: 'class',
+ theme: {
+ extend: {
+ colors: {
+ border: 'hsl(240 3.7% 15.9%)',
+ input: 'hsl(240 3.7% 15.9%)',
+ ring: 'hsl(240 4.9% 83.9%)',
+ background: 'hsl(240 10% 3.9%)',
+ foreground: 'hsl(0 0% 98%)',
+ primary: {
+ DEFAULT: 'hsl(0 0% 98%)',
+ foreground: 'hsl(240 5.9% 10%)',
+ },
+ secondary: {
+ DEFAULT: 'hsl(240 3.7% 15.9%)',
+ foreground: 'hsl(0 0% 98%)',
+ },
+ muted: {
+ DEFAULT: 'hsl(240 3.7% 15.9%)',
+ foreground: 'hsl(240 5% 64.9%)',
+ },
+ accent: {
+ DEFAULT: 'hsl(240 3.7% 15.9%)',
+ foreground: 'hsl(0 0% 98%)',
+ },
+ destructive: {
+ DEFAULT: 'hsl(0 62.8% 30.6%)',
+ foreground: 'hsl(0 0% 98%)',
+ },
+ },
+ borderRadius: {
+ lg: '0.5rem',
+ md: 'calc(0.5rem - 2px)',
+ sm: 'calc(0.5rem - 4px)',
+ },
+ },
+ },
+ plugins: [],
+} satisfies Config;
diff --git a/web/client/vite.config.ts b/web/client/vite.config.ts
new file mode 100644
index 0000000..b4609d2
--- /dev/null
+++ b/web/client/vite.config.ts
@@ -0,0 +1,23 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+import path from 'path';
+
+export default defineConfig({
+ plugins: [react()],
+ root: path.resolve(__dirname),
+ resolve: {
+ alias: {
+ '@': path.resolve(__dirname, 'src'),
+ },
+ },
+ server: {
+ port: 5173,
+ proxy: {
+ '/api': 'http://localhost:3001',
+ '/ws': {
+ target: 'ws://localhost:3001',
+ ws: true,
+ },
+ },
+ },
+});