Spaces:
Sleeping
Sleeping
Trae Assistant commited on
Commit ·
ad893f7
0
Parent(s):
chore: pull .gitattributes from huggingface
Browse files- .gitattributes +35 -0
- .gitignore +25 -0
- README.md +57 -0
- api/app.ts +70 -0
- api/index.ts +9 -0
- api/routes/ai.ts +79 -0
- api/routes/auth.ts +33 -0
- api/server.ts +34 -0
- eslint.config.js +28 -0
- index.html +24 -0
- nodemon.json +10 -0
- package.json +59 -0
- pnpm-lock.yaml +0 -0
- postcss.config.js +10 -0
- public/favicon.svg +4 -0
- src/App.tsx +13 -0
- src/assets/react.svg +1 -0
- src/components/Empty.tsx +8 -0
- src/hooks/useTheme.ts +29 -0
- src/index.css +14 -0
- src/lib/utils.ts +6 -0
- src/main.tsx +10 -0
- src/pages/Home.tsx +89 -0
- src/vite-env.d.ts +1 -0
- tailwind.config.js +13 -0
- tsconfig.json +40 -0
- vercel.json +12 -0
- vite.config.ts +47 -0
.gitattributes
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
.vite
|
README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# React + TypeScript + Vite
|
| 2 |
+
|
| 3 |
+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
| 4 |
+
|
| 5 |
+
Currently, two official plugins are available:
|
| 6 |
+
|
| 7 |
+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
|
| 8 |
+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
| 9 |
+
|
| 10 |
+
## Expanding the ESLint configuration
|
| 11 |
+
|
| 12 |
+
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
|
| 13 |
+
|
| 14 |
+
```js
|
| 15 |
+
export default tseslint.config({
|
| 16 |
+
extends: [
|
| 17 |
+
// Remove ...tseslint.configs.recommended and replace with this
|
| 18 |
+
...tseslint.configs.recommendedTypeChecked,
|
| 19 |
+
// Alternatively, use this for stricter rules
|
| 20 |
+
...tseslint.configs.strictTypeChecked,
|
| 21 |
+
// Optionally, add this for stylistic rules
|
| 22 |
+
...tseslint.configs.stylisticTypeChecked,
|
| 23 |
+
],
|
| 24 |
+
languageOptions: {
|
| 25 |
+
// other options...
|
| 26 |
+
parserOptions: {
|
| 27 |
+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
| 28 |
+
tsconfigRootDir: import.meta.dirname,
|
| 29 |
+
},
|
| 30 |
+
},
|
| 31 |
+
})
|
| 32 |
+
```
|
| 33 |
+
|
| 34 |
+
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
|
| 35 |
+
|
| 36 |
+
```js
|
| 37 |
+
// eslint.config.js
|
| 38 |
+
import reactX from 'eslint-plugin-react-x'
|
| 39 |
+
import reactDom from 'eslint-plugin-react-dom'
|
| 40 |
+
|
| 41 |
+
export default tseslint.config({
|
| 42 |
+
extends: [
|
| 43 |
+
// other configs...
|
| 44 |
+
// Enable lint rules for React
|
| 45 |
+
reactX.configs['recommended-typescript'],
|
| 46 |
+
// Enable lint rules for React DOM
|
| 47 |
+
reactDom.configs.recommended,
|
| 48 |
+
],
|
| 49 |
+
languageOptions: {
|
| 50 |
+
// other options...
|
| 51 |
+
parserOptions: {
|
| 52 |
+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
| 53 |
+
tsconfigRootDir: import.meta.dirname,
|
| 54 |
+
},
|
| 55 |
+
},
|
| 56 |
+
})
|
| 57 |
+
```
|
api/app.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* 这是一个 API 服务端程序
|
| 3 |
+
*/
|
| 4 |
+
|
| 5 |
+
import express, {
|
| 6 |
+
type Request,
|
| 7 |
+
type Response,
|
| 8 |
+
type NextFunction,
|
| 9 |
+
} from 'express'
|
| 10 |
+
import cors from 'cors'
|
| 11 |
+
import path from 'path'
|
| 12 |
+
import dotenv from 'dotenv'
|
| 13 |
+
import { fileURLToPath } from 'url'
|
| 14 |
+
import authRoutes from './routes/auth.js'
|
| 15 |
+
import aiRoutes from './routes/ai.js'
|
| 16 |
+
|
| 17 |
+
// ESM 模式下的路径处理
|
| 18 |
+
const __filename = fileURLToPath(import.meta.url)
|
| 19 |
+
const __dirname = path.dirname(__filename)
|
| 20 |
+
|
| 21 |
+
// 加载环境变量
|
| 22 |
+
dotenv.config()
|
| 23 |
+
|
| 24 |
+
const app: express.Application = express()
|
| 25 |
+
|
| 26 |
+
app.use(cors())
|
| 27 |
+
app.use(express.json({ limit: '10mb' }))
|
| 28 |
+
app.use(express.urlencoded({ extended: true, limit: '10mb' }))
|
| 29 |
+
|
| 30 |
+
/**
|
| 31 |
+
* API 路由配置
|
| 32 |
+
*/
|
| 33 |
+
app.use('/api/auth', authRoutes)
|
| 34 |
+
app.use('/api/ai', aiRoutes)
|
| 35 |
+
|
| 36 |
+
/**
|
| 37 |
+
* 健康检查接口
|
| 38 |
+
*/
|
| 39 |
+
app.use(
|
| 40 |
+
'/api/health',
|
| 41 |
+
(req: Request, res: Response, next: NextFunction): void => {
|
| 42 |
+
res.status(200).json({
|
| 43 |
+
success: true,
|
| 44 |
+
message: '服务运行正常',
|
| 45 |
+
})
|
| 46 |
+
},
|
| 47 |
+
)
|
| 48 |
+
|
| 49 |
+
/**
|
| 50 |
+
* 错误处理中间件
|
| 51 |
+
*/
|
| 52 |
+
app.use((error: Error, req: Request, res: Response, next: NextFunction) => {
|
| 53 |
+
console.error('Server Error:', error)
|
| 54 |
+
res.status(500).json({
|
| 55 |
+
success: false,
|
| 56 |
+
error: '服务器内部错误',
|
| 57 |
+
})
|
| 58 |
+
})
|
| 59 |
+
|
| 60 |
+
/**
|
| 61 |
+
* 404 未找到处理
|
| 62 |
+
*/
|
| 63 |
+
app.use((req: Request, res: Response) => {
|
| 64 |
+
res.status(404).json({
|
| 65 |
+
success: false,
|
| 66 |
+
error: '接口不存在',
|
| 67 |
+
})
|
| 68 |
+
})
|
| 69 |
+
|
| 70 |
+
export default app
|
api/index.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Vercel deploy entry handler, for serverless deployment, please don't modify this file
|
| 3 |
+
*/
|
| 4 |
+
import type { VercelRequest, VercelResponse } from '@vercel/node';
|
| 5 |
+
import app from './app.js';
|
| 6 |
+
|
| 7 |
+
export default function handler(req: VercelRequest, res: VercelResponse) {
|
| 8 |
+
return app(req, res);
|
| 9 |
+
}
|
api/routes/ai.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* AI 生成相关接口
|
| 3 |
+
*/
|
| 4 |
+
import { Router, type Request, type Response } from 'express'
|
| 5 |
+
import axios from 'axios'
|
| 6 |
+
|
| 7 |
+
const router = Router()
|
| 8 |
+
|
| 9 |
+
/**
|
| 10 |
+
* 生成 UI 代码
|
| 11 |
+
* POST /api/ai/generate
|
| 12 |
+
*/
|
| 13 |
+
router.post('/generate', async (req: Request, res: Response): Promise<void> => {
|
| 14 |
+
const { prompt } = req.body
|
| 15 |
+
|
| 16 |
+
if (!prompt) {
|
| 17 |
+
res.status(400).json({
|
| 18 |
+
success: false,
|
| 19 |
+
error: '请输入描述内容',
|
| 20 |
+
})
|
| 21 |
+
return
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
try {
|
| 25 |
+
const apiKey = process.env.SILICONFLOW_API_KEY
|
| 26 |
+
const model = process.env.SILICONFLOW_MODEL || 'deepseek-ai/DeepSeek-V3'
|
| 27 |
+
|
| 28 |
+
const response = await axios.post(
|
| 29 |
+
'https://api.siliconflow.cn/v1/chat/completions',
|
| 30 |
+
{
|
| 31 |
+
model: model,
|
| 32 |
+
messages: [
|
| 33 |
+
{
|
| 34 |
+
role: 'system',
|
| 35 |
+
content: `你是一个专业的前端 UI 界面生成专家。
|
| 36 |
+
你的任务是根据用户的描述,生成高质量、响应式、现代化的 React 代码。
|
| 37 |
+
要求:
|
| 38 |
+
1. 使用 React (Function Components) 和 Tailwind CSS。
|
| 39 |
+
2. 代码必须是完整的、可运行的。
|
| 40 |
+
3. 只返回代码块中的内容,不要有其他解释说明。
|
| 41 |
+
4. 使用常见的库如 lucide-react 作为图标库。
|
| 42 |
+
5. 界面风格应符合现代化设计,注重用户体验。`,
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
role: 'user',
|
| 46 |
+
content: prompt,
|
| 47 |
+
},
|
| 48 |
+
],
|
| 49 |
+
stream: false,
|
| 50 |
+
},
|
| 51 |
+
{
|
| 52 |
+
headers: {
|
| 53 |
+
Authorization: `Bearer ${apiKey}`,
|
| 54 |
+
'Content-Type': 'application/json',
|
| 55 |
+
},
|
| 56 |
+
}
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
const content = response.data.choices[0].message.content
|
| 60 |
+
// 提取代码块中的内容
|
| 61 |
+
const codeMatch = content.match(/```(?:tsx|jsx|javascript|typescript|react)?\s*([\s\S]*?)```/)
|
| 62 |
+
const code = codeMatch ? codeMatch[1].trim() : content.trim()
|
| 63 |
+
|
| 64 |
+
res.status(200).json({
|
| 65 |
+
success: true,
|
| 66 |
+
data: {
|
| 67 |
+
code: code,
|
| 68 |
+
},
|
| 69 |
+
})
|
| 70 |
+
} catch (error: any) {
|
| 71 |
+
console.error('AI Generation Error:', error.response?.data || error.message)
|
| 72 |
+
res.status(500).json({
|
| 73 |
+
success: false,
|
| 74 |
+
error: 'AI 生成失败,请稍后再试',
|
| 75 |
+
})
|
| 76 |
+
}
|
| 77 |
+
})
|
| 78 |
+
|
| 79 |
+
export default router
|
api/routes/auth.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* This is a user authentication API route demo.
|
| 3 |
+
* Handle user registration, login, token management, etc.
|
| 4 |
+
*/
|
| 5 |
+
import { Router, type Request, type Response } from 'express'
|
| 6 |
+
|
| 7 |
+
const router = Router()
|
| 8 |
+
|
| 9 |
+
/**
|
| 10 |
+
* User Login
|
| 11 |
+
* POST /api/auth/register
|
| 12 |
+
*/
|
| 13 |
+
router.post('/register', async (req: Request, res: Response): Promise<void> => {
|
| 14 |
+
// TODO: Implement register logic
|
| 15 |
+
})
|
| 16 |
+
|
| 17 |
+
/**
|
| 18 |
+
* User Login
|
| 19 |
+
* POST /api/auth/login
|
| 20 |
+
*/
|
| 21 |
+
router.post('/login', async (req: Request, res: Response): Promise<void> => {
|
| 22 |
+
// TODO: Implement login logic
|
| 23 |
+
})
|
| 24 |
+
|
| 25 |
+
/**
|
| 26 |
+
* User Logout
|
| 27 |
+
* POST /api/auth/logout
|
| 28 |
+
*/
|
| 29 |
+
router.post('/logout', async (req: Request, res: Response): Promise<void> => {
|
| 30 |
+
// TODO: Implement logout logic
|
| 31 |
+
})
|
| 32 |
+
|
| 33 |
+
export default router
|
api/server.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* local server entry file, for local development
|
| 3 |
+
*/
|
| 4 |
+
import app from './app.js';
|
| 5 |
+
|
| 6 |
+
/**
|
| 7 |
+
* start server with port
|
| 8 |
+
*/
|
| 9 |
+
const PORT = process.env.PORT || 3001;
|
| 10 |
+
|
| 11 |
+
const server = app.listen(PORT, () => {
|
| 12 |
+
console.log(`Server ready on port ${PORT}`);
|
| 13 |
+
});
|
| 14 |
+
|
| 15 |
+
/**
|
| 16 |
+
* close server
|
| 17 |
+
*/
|
| 18 |
+
process.on('SIGTERM', () => {
|
| 19 |
+
console.log('SIGTERM signal received');
|
| 20 |
+
server.close(() => {
|
| 21 |
+
console.log('Server closed');
|
| 22 |
+
process.exit(0);
|
| 23 |
+
});
|
| 24 |
+
});
|
| 25 |
+
|
| 26 |
+
process.on('SIGINT', () => {
|
| 27 |
+
console.log('SIGINT signal received');
|
| 28 |
+
server.close(() => {
|
| 29 |
+
console.log('Server closed');
|
| 30 |
+
process.exit(0);
|
| 31 |
+
});
|
| 32 |
+
});
|
| 33 |
+
|
| 34 |
+
export default app;
|
eslint.config.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import js from '@eslint/js'
|
| 2 |
+
import globals from 'globals'
|
| 3 |
+
import reactHooks from 'eslint-plugin-react-hooks'
|
| 4 |
+
import reactRefresh from 'eslint-plugin-react-refresh'
|
| 5 |
+
import tseslint from 'typescript-eslint'
|
| 6 |
+
|
| 7 |
+
export default tseslint.config(
|
| 8 |
+
{ ignores: ['dist'] },
|
| 9 |
+
{
|
| 10 |
+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
| 11 |
+
files: ['**/*.{ts,tsx}'],
|
| 12 |
+
languageOptions: {
|
| 13 |
+
ecmaVersion: 2020,
|
| 14 |
+
globals: globals.browser,
|
| 15 |
+
},
|
| 16 |
+
plugins: {
|
| 17 |
+
'react-hooks': reactHooks,
|
| 18 |
+
'react-refresh': reactRefresh,
|
| 19 |
+
},
|
| 20 |
+
rules: {
|
| 21 |
+
...reactHooks.configs.recommended.rules,
|
| 22 |
+
'react-refresh/only-export-components': [
|
| 23 |
+
'warn',
|
| 24 |
+
{ allowConstantExport: true },
|
| 25 |
+
],
|
| 26 |
+
},
|
| 27 |
+
},
|
| 28 |
+
)
|
index.html
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!doctype html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
| 6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 7 |
+
<title>My Trae Project</title>
|
| 8 |
+
<script type="module">
|
| 9 |
+
if (import.meta.hot?.on) {
|
| 10 |
+
import.meta.hot.on('vite:error', (error) => {
|
| 11 |
+
if (error.err) {
|
| 12 |
+
console.error(
|
| 13 |
+
[error.err.message, error.err.frame].filter(Boolean).join('\n'),
|
| 14 |
+
)
|
| 15 |
+
}
|
| 16 |
+
})
|
| 17 |
+
}
|
| 18 |
+
</script>
|
| 19 |
+
</head>
|
| 20 |
+
<body>
|
| 21 |
+
<div id="root"></div>
|
| 22 |
+
<script type="module" src="/src/main.tsx"></script>
|
| 23 |
+
</body>
|
| 24 |
+
</html>
|
nodemon.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"watch": ["api"],
|
| 3 |
+
"ext": "ts,mts,js,json",
|
| 4 |
+
"ignore": ["api/dist/*"],
|
| 5 |
+
"exec": "tsx api/server.ts",
|
| 6 |
+
"env": {
|
| 7 |
+
"NODE_ENV": "development"
|
| 8 |
+
},
|
| 9 |
+
"delay": 1000
|
| 10 |
+
}
|
package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "generative-ui-agent",
|
| 3 |
+
"private": true,
|
| 4 |
+
"version": "0.0.0",
|
| 5 |
+
"type": "module",
|
| 6 |
+
"scripts": {
|
| 7 |
+
"client:dev": "vite",
|
| 8 |
+
"build": "tsc -b && vite build",
|
| 9 |
+
"lint": "eslint .",
|
| 10 |
+
"preview": "vite preview",
|
| 11 |
+
"check": "tsc --noEmit",
|
| 12 |
+
"server:dev": "nodemon",
|
| 13 |
+
"dev": "concurrently \"npm run client:dev\" \"npm run server:dev\""
|
| 14 |
+
},
|
| 15 |
+
"dependencies": {
|
| 16 |
+
"@ant-design/icons": "^6.1.0",
|
| 17 |
+
"@supabase/supabase-js": "^2.48.1",
|
| 18 |
+
"antd": "^5.23.0",
|
| 19 |
+
"axios": "^1.7.9",
|
| 20 |
+
"clsx": "^2.1.1",
|
| 21 |
+
"cors": "^2.8.5",
|
| 22 |
+
"dotenv": "^17.2.1",
|
| 23 |
+
"express": "^4.21.2",
|
| 24 |
+
"jsonwebtoken": "^9.0.2",
|
| 25 |
+
"lucide-react": "^0.511.0",
|
| 26 |
+
"react": "^18.3.1",
|
| 27 |
+
"react-dom": "^18.3.1",
|
| 28 |
+
"react-router-dom": "^7.3.0",
|
| 29 |
+
"tailwind-merge": "^3.0.2",
|
| 30 |
+
"zustand": "^5.0.3"
|
| 31 |
+
},
|
| 32 |
+
"devDependencies": {
|
| 33 |
+
"@eslint/js": "^9.25.0",
|
| 34 |
+
"@types/cors": "^2.8.19",
|
| 35 |
+
"@types/express": "^4.17.21",
|
| 36 |
+
"@types/jsonwebtoken": "^9.0.8",
|
| 37 |
+
"@types/node": "^22.15.30",
|
| 38 |
+
"@types/react": "^18.3.12",
|
| 39 |
+
"@types/react-dom": "^18.3.1",
|
| 40 |
+
"@vercel/node": "^5.3.6",
|
| 41 |
+
"@vitejs/plugin-react": "^4.4.1",
|
| 42 |
+
"autoprefixer": "^10.4.21",
|
| 43 |
+
"babel-plugin-react-dev-locator": "^1.0.0",
|
| 44 |
+
"concurrently": "^9.2.0",
|
| 45 |
+
"eslint": "^9.25.0",
|
| 46 |
+
"eslint-plugin-react-hooks": "^5.2.0",
|
| 47 |
+
"eslint-plugin-react-refresh": "^0.4.19",
|
| 48 |
+
"globals": "^16.0.0",
|
| 49 |
+
"nodemon": "^3.1.10",
|
| 50 |
+
"postcss": "^8.5.3",
|
| 51 |
+
"tailwindcss": "^3.4.17",
|
| 52 |
+
"tsx": "^4.20.3",
|
| 53 |
+
"typescript": "~5.8.3",
|
| 54 |
+
"typescript-eslint": "^8.30.1",
|
| 55 |
+
"vite": "^6.3.5",
|
| 56 |
+
"vite-plugin-trae-solo-badge": "^1.0.0",
|
| 57 |
+
"vite-tsconfig-paths": "^5.1.4"
|
| 58 |
+
}
|
| 59 |
+
}
|
pnpm-lock.yaml
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
postcss.config.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/** WARNING: DON'T EDIT THIS FILE */
|
| 2 |
+
/** WARNING: DON'T EDIT THIS FILE */
|
| 3 |
+
/** WARNING: DON'T EDIT THIS FILE */
|
| 4 |
+
|
| 5 |
+
export default {
|
| 6 |
+
plugins: {
|
| 7 |
+
tailwindcss: {},
|
| 8 |
+
autoprefixer: {},
|
| 9 |
+
},
|
| 10 |
+
};
|
public/favicon.svg
ADDED
|
|
src/App.tsx
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
| 2 |
+
import Home from "@/pages/Home";
|
| 3 |
+
|
| 4 |
+
export default function App() {
|
| 5 |
+
return (
|
| 6 |
+
<Router>
|
| 7 |
+
<Routes>
|
| 8 |
+
<Route path="/" element={<Home />} />
|
| 9 |
+
<Route path="/other" element={<div className="text-center text-xl">Other Page - Coming Soon</div>} />
|
| 10 |
+
</Routes>
|
| 11 |
+
</Router>
|
| 12 |
+
);
|
| 13 |
+
}
|
src/assets/react.svg
ADDED
|
|
src/components/Empty.tsx
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { cn } from '@/lib/utils'
|
| 2 |
+
|
| 3 |
+
// Empty component
|
| 4 |
+
export default function Empty() {
|
| 5 |
+
return (
|
| 6 |
+
<div className={cn('flex h-full items-center justify-center')}>Empty</div>
|
| 7 |
+
)
|
| 8 |
+
}
|
src/hooks/useTheme.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { useState, useEffect } from 'react';
|
| 2 |
+
|
| 3 |
+
type Theme = 'light' | 'dark';
|
| 4 |
+
|
| 5 |
+
export function useTheme() {
|
| 6 |
+
const [theme, setTheme] = useState<Theme>(() => {
|
| 7 |
+
const savedTheme = localStorage.getItem('theme') as Theme;
|
| 8 |
+
if (savedTheme) {
|
| 9 |
+
return savedTheme;
|
| 10 |
+
}
|
| 11 |
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
| 12 |
+
});
|
| 13 |
+
|
| 14 |
+
useEffect(() => {
|
| 15 |
+
document.documentElement.classList.remove('light', 'dark');
|
| 16 |
+
document.documentElement.classList.add(theme);
|
| 17 |
+
localStorage.setItem('theme', theme);
|
| 18 |
+
}, [theme]);
|
| 19 |
+
|
| 20 |
+
const toggleTheme = () => {
|
| 21 |
+
setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
|
| 22 |
+
};
|
| 23 |
+
|
| 24 |
+
return {
|
| 25 |
+
theme,
|
| 26 |
+
toggleTheme,
|
| 27 |
+
isDark: theme === 'dark'
|
| 28 |
+
};
|
| 29 |
+
}
|
src/index.css
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@tailwind base;
|
| 2 |
+
@tailwind components;
|
| 3 |
+
@tailwind utilities;
|
| 4 |
+
|
| 5 |
+
:root {
|
| 6 |
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
| 7 |
+
line-height: 1.5;
|
| 8 |
+
font-weight: 400;
|
| 9 |
+
|
| 10 |
+
font-synthesis: none;
|
| 11 |
+
text-rendering: optimizeLegibility;
|
| 12 |
+
-webkit-font-smoothing: antialiased;
|
| 13 |
+
-moz-osx-font-smoothing: grayscale;
|
| 14 |
+
}
|
src/lib/utils.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { clsx, type ClassValue } from "clsx"
|
| 2 |
+
import { twMerge } from "tailwind-merge"
|
| 3 |
+
|
| 4 |
+
export function cn(...inputs: ClassValue[]) {
|
| 5 |
+
return twMerge(clsx(inputs))
|
| 6 |
+
}
|
src/main.tsx
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { StrictMode } from 'react'
|
| 2 |
+
import { createRoot } from 'react-dom/client'
|
| 3 |
+
import App from './App'
|
| 4 |
+
import './index.css'
|
| 5 |
+
|
| 6 |
+
createRoot(document.getElementById('root')!).render(
|
| 7 |
+
<StrictMode>
|
| 8 |
+
<App />
|
| 9 |
+
</StrictMode>,
|
| 10 |
+
)
|
src/pages/Home.tsx
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React, { useState } from 'react';
|
| 2 |
+
import { Layout, Input, Button, Card, List, Typography, Space, Divider } from 'antd';
|
| 3 |
+
import { SendOutlined, HistoryOutlined, SettingOutlined, ProjectOutlined } from '@ant-design/icons';
|
| 4 |
+
|
| 5 |
+
const { Header, Content, Sider } = Layout;
|
| 6 |
+
const { TextArea } = Input;
|
| 7 |
+
const { Title, Text } = Typography;
|
| 8 |
+
|
| 9 |
+
export default function Home() {
|
| 10 |
+
const [input, setInput] = useState('');
|
| 11 |
+
const [history] = useState([
|
| 12 |
+
'生成一个蓝色风格的登录页面',
|
| 13 |
+
'创建一个电商首页轮播图',
|
| 14 |
+
'设计一个响应式的个人主页',
|
| 15 |
+
]);
|
| 16 |
+
|
| 17 |
+
return (
|
| 18 |
+
<Layout style={{ minHeight: '100vh' }}>
|
| 19 |
+
<Header style={{ background: '#fff', padding: '0 24px', display: 'flex', alignItems: 'center', borderBottom: '1px solid #f0f0f0' }}>
|
| 20 |
+
<Title level={4} style={{ margin: 0, color: '#1890ff' }}>Generative UI Agent</Title>
|
| 21 |
+
<div style={{ marginLeft: 'auto' }}>
|
| 22 |
+
<Space size="large">
|
| 23 |
+
<Button type="text" icon={<ProjectOutlined />}>项目管理</Button>
|
| 24 |
+
<Button type="text" icon={<SettingOutlined />}>设置</Button>
|
| 25 |
+
</Space>
|
| 26 |
+
</div>
|
| 27 |
+
</Header>
|
| 28 |
+
<Layout>
|
| 29 |
+
<Sider width={250} style={{ background: '#fff', borderRight: '1px solid #f0f0f0' }}>
|
| 30 |
+
<div style={{ padding: '16px' }}>
|
| 31 |
+
<Title level={5}><HistoryOutlined /> 历史记录</Title>
|
| 32 |
+
<List
|
| 33 |
+
dataSource={history}
|
| 34 |
+
renderItem={(item) => (
|
| 35 |
+
<List.Item style={{ cursor: 'pointer', padding: '8px 0' }}>
|
| 36 |
+
<Text ellipsis>{item}</Text>
|
| 37 |
+
</List.Item>
|
| 38 |
+
)}
|
| 39 |
+
/>
|
| 40 |
+
</div>
|
| 41 |
+
</Sider>
|
| 42 |
+
<Content style={{ padding: '24px', display: 'flex', gap: '24px' }}>
|
| 43 |
+
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
| 44 |
+
<Card title="AI 对话输入" bordered={false} style={{ boxShadow: '0 2px 8px rgba(0,0,0,0.06)' }}>
|
| 45 |
+
<TextArea
|
| 46 |
+
rows={4}
|
| 47 |
+
value={input}
|
| 48 |
+
onChange={(e) => setInput(e.target.value)}
|
| 49 |
+
placeholder="描述你想要的 UI 界面..."
|
| 50 |
+
style={{ marginBottom: '16px' }}
|
| 51 |
+
/>
|
| 52 |
+
<div style={{ textAlign: 'right' }}>
|
| 53 |
+
<Button type="primary" icon={<SendOutlined />} size="large">
|
| 54 |
+
开始生成
|
| 55 |
+
</Button>
|
| 56 |
+
</div>
|
| 57 |
+
</Card>
|
| 58 |
+
|
| 59 |
+
<Card title="系统状态" bordered={false} style={{ boxShadow: '0 2px 8px rgba(0,0,0,0.06)' }}>
|
| 60 |
+
<Space direction="vertical" style={{ width: '100%' }}>
|
| 61 |
+
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
| 62 |
+
<Text>API 状态</Text>
|
| 63 |
+
<Text type="success">已连接</Text>
|
| 64 |
+
</div>
|
| 65 |
+
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
| 66 |
+
<Text>模型版本</Text>
|
| 67 |
+
<Text>GPT-4o</Text>
|
| 68 |
+
</div>
|
| 69 |
+
</Space>
|
| 70 |
+
</Card>
|
| 71 |
+
</div>
|
| 72 |
+
|
| 73 |
+
<div style={{ flex: 2 }}>
|
| 74 |
+
<Card
|
| 75 |
+
title="实时预览"
|
| 76 |
+
extra={<Space><Button size="small">桌面端</Button><Button size="small">移动端</Button></Space>}
|
| 77 |
+
style={{ height: '100%', boxShadow: '0 2px 8px rgba(0,0,0,0.06)' }}
|
| 78 |
+
bodyStyle={{ height: 'calc(100% - 58px)', display: 'flex', alignItems: 'center', justifyCenter: 'center', background: '#f5f5f5' }}
|
| 79 |
+
>
|
| 80 |
+
<div style={{ width: '100%', height: '100%', background: '#fff', border: '1px dashed #d9d9d9', borderRadius: '4px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
| 81 |
+
<Text type="secondary">生成的 UI 将在这里实时显示</Text>
|
| 82 |
+
</div>
|
| 83 |
+
</Card>
|
| 84 |
+
</div>
|
| 85 |
+
</Content>
|
| 86 |
+
</Layout>
|
| 87 |
+
</Layout>
|
| 88 |
+
);
|
| 89 |
+
}
|
src/vite-env.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
/// <reference types="vite/client" />
|
tailwind.config.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/** @type {import('tailwindcss').Config} */
|
| 2 |
+
|
| 3 |
+
export default {
|
| 4 |
+
darkMode: "class",
|
| 5 |
+
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
| 6 |
+
theme: {
|
| 7 |
+
container: {
|
| 8 |
+
center: true,
|
| 9 |
+
},
|
| 10 |
+
extend: {},
|
| 11 |
+
},
|
| 12 |
+
plugins: [],
|
| 13 |
+
};
|
tsconfig.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"compilerOptions": {
|
| 3 |
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
| 4 |
+
"target": "ES2020",
|
| 5 |
+
"useDefineForClassFields": true,
|
| 6 |
+
"lib": [
|
| 7 |
+
"ES2020",
|
| 8 |
+
"DOM",
|
| 9 |
+
"DOM.Iterable"
|
| 10 |
+
],
|
| 11 |
+
"module": "ESNext",
|
| 12 |
+
"skipLibCheck": true,
|
| 13 |
+
"moduleResolution": "bundler",
|
| 14 |
+
"allowImportingTsExtensions": true,
|
| 15 |
+
"verbatimModuleSyntax": false,
|
| 16 |
+
"moduleDetection": "force",
|
| 17 |
+
"noEmit": true,
|
| 18 |
+
"jsx": "react-jsx",
|
| 19 |
+
"strict": false,
|
| 20 |
+
"noUnusedLocals": false,
|
| 21 |
+
"noUnusedParameters": false,
|
| 22 |
+
"noFallthroughCasesInSwitch": false,
|
| 23 |
+
"noUncheckedSideEffectImports": false,
|
| 24 |
+
"forceConsistentCasingInFileNames": false,
|
| 25 |
+
"baseUrl": "./",
|
| 26 |
+
"paths": {
|
| 27 |
+
"@/*": [
|
| 28 |
+
"./src/*"
|
| 29 |
+
]
|
| 30 |
+
},
|
| 31 |
+
"types": [
|
| 32 |
+
"node",
|
| 33 |
+
"express"
|
| 34 |
+
]
|
| 35 |
+
},
|
| 36 |
+
"include": [
|
| 37 |
+
"src",
|
| 38 |
+
"api"
|
| 39 |
+
]
|
| 40 |
+
}
|
vercel.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"rewrites": [
|
| 3 |
+
{
|
| 4 |
+
"source": "/api/(.*)",
|
| 5 |
+
"destination": "/api/index"
|
| 6 |
+
},
|
| 7 |
+
{
|
| 8 |
+
"source": "/(.*)",
|
| 9 |
+
"destination": "/index.html"
|
| 10 |
+
}
|
| 11 |
+
]
|
| 12 |
+
}
|
vite.config.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { defineConfig } from 'vite'
|
| 2 |
+
import react from '@vitejs/plugin-react'
|
| 3 |
+
import tsconfigPaths from "vite-tsconfig-paths";
|
| 4 |
+
import { traeBadgePlugin } from 'vite-plugin-trae-solo-badge';
|
| 5 |
+
|
| 6 |
+
// https://vite.dev/config/
|
| 7 |
+
export default defineConfig({
|
| 8 |
+
plugins: [
|
| 9 |
+
react({
|
| 10 |
+
babel: {
|
| 11 |
+
plugins: [
|
| 12 |
+
'react-dev-locator',
|
| 13 |
+
],
|
| 14 |
+
},
|
| 15 |
+
}),
|
| 16 |
+
traeBadgePlugin({
|
| 17 |
+
variant: 'dark',
|
| 18 |
+
position: 'bottom-right',
|
| 19 |
+
prodOnly: true,
|
| 20 |
+
clickable: true,
|
| 21 |
+
clickUrl: 'https://www.trae.ai/solo?showJoin=1',
|
| 22 |
+
autoTheme: true,
|
| 23 |
+
autoThemeTarget: '#root'
|
| 24 |
+
}),
|
| 25 |
+
tsconfigPaths(),
|
| 26 |
+
],
|
| 27 |
+
server: {
|
| 28 |
+
proxy: {
|
| 29 |
+
'/api': {
|
| 30 |
+
target: 'http://localhost:3001',
|
| 31 |
+
changeOrigin: true,
|
| 32 |
+
secure: false,
|
| 33 |
+
configure: (proxy, _options) => {
|
| 34 |
+
proxy.on('error', (err, _req, _res) => {
|
| 35 |
+
console.log('proxy error', err);
|
| 36 |
+
});
|
| 37 |
+
proxy.on('proxyReq', (proxyReq, req, _res) => {
|
| 38 |
+
console.log('Sending Request to the Target:', req.method, req.url);
|
| 39 |
+
});
|
| 40 |
+
proxy.on('proxyRes', (proxyRes, req, _res) => {
|
| 41 |
+
console.log('Received Response from the Target:', proxyRes.statusCode, req.url);
|
| 42 |
+
});
|
| 43 |
+
},
|
| 44 |
+
}
|
| 45 |
+
}
|
| 46 |
+
}
|
| 47 |
+
})
|