trae-starter 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/bin/cli.js +33 -0
- package/package.json +25 -0
- package/public/app.js +263 -0
- package/public/index.html +123 -0
- package/server/api.js +181 -0
- package/server/index.js +38 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/SKILL.md +659 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/_sync_all.py +414 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/app-interface.csv +31 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/colors.csv +162 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/design.csv +1776 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/draft.csv +1779 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/google-fonts.csv +1924 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/icons.csv +106 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/landing.csv +35 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/products.csv +162 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/styles.csv +85 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/typography.csv +74 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/ui-reasoning.csv +162 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/scripts/core.py +247 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/templates/proto/.agents/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/templates/proto/.trae/skills/preview-manager/SKILL.md +37 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/SKILL.md +659 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/_sync_all.py +414 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/app-interface.csv +31 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/colors.csv +162 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/design.csv +1776 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/draft.csv +1779 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/google-fonts.csv +1924 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/icons.csv +106 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/landing.csv +35 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/products.csv +162 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/styles.csv +85 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/typography.csv +74 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/ui-reasoning.csv +162 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/scripts/core.py +247 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/templates/proto/.trae/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/templates/proto/README.md +77 -0
- package/templates/proto/agent.md +361 -0
- package/templates/proto/eslint.config.js +23 -0
- package/templates/proto/index.html +13 -0
- package/templates/proto/package.json +39 -0
- package/templates/proto/pnpm-lock.yaml +2401 -0
- package/templates/proto/postcss.config.js +6 -0
- package/templates/proto/public/favicon.svg +1 -0
- package/templates/proto/public/icons.svg +24 -0
- package/templates/proto/skills-lock.json +10 -0
- package/templates/proto/src/App.css +184 -0
- package/templates/proto/src/App.tsx +15 -0
- package/templates/proto/src/assets/hero.png +0 -0
- package/templates/proto/src/assets/react.svg +1 -0
- package/templates/proto/src/assets/vite.svg +1 -0
- package/templates/proto/src/components/ui/SampleButton/sampleButton.css +4 -0
- package/templates/proto/src/components/ui/SampleButton/sampleButton.tsx +14 -0
- package/templates/proto/src/data/mock/products.csv +4 -0
- package/templates/proto/src/data/mock/users.json +16 -0
- package/templates/proto/src/data/types.ts +17 -0
- package/templates/proto/src/index.css +64 -0
- package/templates/proto/src/main.tsx +13 -0
- package/templates/proto/src/pages/Demo/components/DemoHeader/demoHeader.tsx +20 -0
- package/templates/proto/src/pages/Demo/components/FeatureGrid/featureGrid.tsx +18 -0
- package/templates/proto/src/pages/Demo/index.tsx +29 -0
- package/templates/proto/src/pages/Home/components/FeatureCard/featureCard.tsx +15 -0
- package/templates/proto/src/pages/Home/components/HeroSection/heroSection.tsx +28 -0
- package/templates/proto/src/pages/Home/components/InteractiveControls/interactiveControls.tsx +27 -0
- package/templates/proto/src/pages/Home/index.tsx +39 -0
- package/templates/proto/src/utils/format.ts +7 -0
- package/templates/proto/tailwind.config.js +11 -0
- package/templates/proto/tsconfig.app.json +28 -0
- package/templates/proto/tsconfig.json +7 -0
- package/templates/proto/tsconfig.node.json +26 -0
- package/templates/proto/vite.config.ts +10 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
UI/UX Pro Max Search - BM25 search engine for UI/UX style guides
|
|
5
|
+
Usage: python search.py "<query>" [--domain <domain>] [--stack <stack>] [--max-results 3]
|
|
6
|
+
python search.py "<query>" --design-system [-p "Project Name"]
|
|
7
|
+
python search.py "<query>" --design-system --persist [-p "Project Name"] [--page "dashboard"]
|
|
8
|
+
|
|
9
|
+
Domains: style, prompt, color, chart, landing, product, ux, typography, google-fonts
|
|
10
|
+
Stacks: html-tailwind, react, nextjs
|
|
11
|
+
|
|
12
|
+
Persistence (Master + Overrides pattern):
|
|
13
|
+
--persist Save design system to design-system/MASTER.md
|
|
14
|
+
--page Also create a page-specific override file in design-system/pages/
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import sys
|
|
19
|
+
import io
|
|
20
|
+
from core import CSV_CONFIG, AVAILABLE_STACKS, MAX_RESULTS, search, search_stack
|
|
21
|
+
from design_system import generate_design_system, persist_design_system
|
|
22
|
+
|
|
23
|
+
# Force UTF-8 for stdout/stderr to handle emojis on Windows (cp1252 default)
|
|
24
|
+
if sys.stdout.encoding and sys.stdout.encoding.lower() != 'utf-8':
|
|
25
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
26
|
+
if sys.stderr.encoding and sys.stderr.encoding.lower() != 'utf-8':
|
|
27
|
+
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def format_output(result):
|
|
31
|
+
"""Format results for Claude consumption (token-optimized)"""
|
|
32
|
+
if "error" in result:
|
|
33
|
+
return f"Error: {result['error']}"
|
|
34
|
+
|
|
35
|
+
output = []
|
|
36
|
+
if result.get("stack"):
|
|
37
|
+
output.append(f"## UI Pro Max Stack Guidelines")
|
|
38
|
+
output.append(f"**Stack:** {result['stack']} | **Query:** {result['query']}")
|
|
39
|
+
else:
|
|
40
|
+
output.append(f"## UI Pro Max Search Results")
|
|
41
|
+
output.append(f"**Domain:** {result['domain']} | **Query:** {result['query']}")
|
|
42
|
+
output.append(f"**Source:** {result['file']} | **Found:** {result['count']} results\n")
|
|
43
|
+
|
|
44
|
+
for i, row in enumerate(result['results'], 1):
|
|
45
|
+
output.append(f"### Result {i}")
|
|
46
|
+
for key, value in row.items():
|
|
47
|
+
value_str = str(value)
|
|
48
|
+
if len(value_str) > 300:
|
|
49
|
+
value_str = value_str[:300] + "..."
|
|
50
|
+
output.append(f"- **{key}:** {value_str}")
|
|
51
|
+
output.append("")
|
|
52
|
+
|
|
53
|
+
return "\n".join(output)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if __name__ == "__main__":
|
|
57
|
+
parser = argparse.ArgumentParser(description="UI Pro Max Search")
|
|
58
|
+
parser.add_argument("query", help="Search query")
|
|
59
|
+
parser.add_argument("--domain", "-d", choices=list(CSV_CONFIG.keys()), help="Search domain")
|
|
60
|
+
parser.add_argument("--stack", "-s", choices=AVAILABLE_STACKS, help="Stack-specific search (html-tailwind, react, nextjs)")
|
|
61
|
+
parser.add_argument("--max-results", "-n", type=int, default=MAX_RESULTS, help="Max results (default: 3)")
|
|
62
|
+
parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
63
|
+
# Design system generation
|
|
64
|
+
parser.add_argument("--design-system", "-ds", action="store_true", help="Generate complete design system recommendation")
|
|
65
|
+
parser.add_argument("--project-name", "-p", type=str, default=None, help="Project name for design system output")
|
|
66
|
+
parser.add_argument("--format", "-f", choices=["ascii", "markdown"], default="ascii", help="Output format for design system")
|
|
67
|
+
# Persistence (Master + Overrides pattern)
|
|
68
|
+
parser.add_argument("--persist", action="store_true", help="Save design system to design-system/MASTER.md (creates hierarchical structure)")
|
|
69
|
+
parser.add_argument("--page", type=str, default=None, help="Create page-specific override file in design-system/pages/")
|
|
70
|
+
parser.add_argument("--output-dir", "-o", type=str, default=None, help="Output directory for persisted files (default: current directory)")
|
|
71
|
+
|
|
72
|
+
args = parser.parse_args()
|
|
73
|
+
|
|
74
|
+
# Design system takes priority
|
|
75
|
+
if args.design_system:
|
|
76
|
+
result = generate_design_system(
|
|
77
|
+
args.query,
|
|
78
|
+
args.project_name,
|
|
79
|
+
args.format,
|
|
80
|
+
persist=args.persist,
|
|
81
|
+
page=args.page,
|
|
82
|
+
output_dir=args.output_dir
|
|
83
|
+
)
|
|
84
|
+
print(result)
|
|
85
|
+
|
|
86
|
+
# Print persistence confirmation
|
|
87
|
+
if args.persist:
|
|
88
|
+
project_slug = args.project_name.lower().replace(' ', '-') if args.project_name else "default"
|
|
89
|
+
print("\n" + "=" * 60)
|
|
90
|
+
print(f"✅ Design system persisted to design-system/{project_slug}/")
|
|
91
|
+
print(f" 📄 design-system/{project_slug}/MASTER.md (Global Source of Truth)")
|
|
92
|
+
if args.page:
|
|
93
|
+
page_filename = args.page.lower().replace(' ', '-')
|
|
94
|
+
print(f" 📄 design-system/{project_slug}/pages/{page_filename}.md (Page Overrides)")
|
|
95
|
+
print("")
|
|
96
|
+
print(f"📖 Usage: When building a page, check design-system/{project_slug}/pages/[page].md first.")
|
|
97
|
+
print(f" If exists, its rules override MASTER.md. Otherwise, use MASTER.md.")
|
|
98
|
+
print("=" * 60)
|
|
99
|
+
# Stack search
|
|
100
|
+
elif args.stack:
|
|
101
|
+
result = search_stack(args.query, args.stack, args.max_results)
|
|
102
|
+
if args.json:
|
|
103
|
+
import json
|
|
104
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
105
|
+
else:
|
|
106
|
+
print(format_output(result))
|
|
107
|
+
# Domain search
|
|
108
|
+
else:
|
|
109
|
+
result = search(args.query, args.domain, args.max_results)
|
|
110
|
+
if args.json:
|
|
111
|
+
import json
|
|
112
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
113
|
+
else:
|
|
114
|
+
print(format_output(result))
|
|
@@ -0,0 +1,77 @@
|
|
|
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
|
+
## Project Conventions
|
|
6
|
+
|
|
7
|
+
- **Demo Directory**: The `Demo` page (`src/pages/Demo`) is an example directory for the project. **Do not delete or modify it** unless the intent explicitly states to add or modify a demo.
|
|
8
|
+
|
|
9
|
+
Currently, two official plugins are available:
|
|
10
|
+
|
|
11
|
+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
|
|
12
|
+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
|
|
13
|
+
|
|
14
|
+
## React Compiler
|
|
15
|
+
|
|
16
|
+
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
|
17
|
+
|
|
18
|
+
## Expanding the ESLint configuration
|
|
19
|
+
|
|
20
|
+
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
export default defineConfig([
|
|
24
|
+
globalIgnores(['dist']),
|
|
25
|
+
{
|
|
26
|
+
files: ['**/*.{ts,tsx}'],
|
|
27
|
+
extends: [
|
|
28
|
+
// Other configs...
|
|
29
|
+
|
|
30
|
+
// Remove tseslint.configs.recommended and replace with this
|
|
31
|
+
tseslint.configs.recommendedTypeChecked,
|
|
32
|
+
// Alternatively, use this for stricter rules
|
|
33
|
+
tseslint.configs.strictTypeChecked,
|
|
34
|
+
// Optionally, add this for stylistic rules
|
|
35
|
+
tseslint.configs.stylisticTypeChecked,
|
|
36
|
+
|
|
37
|
+
// Other configs...
|
|
38
|
+
],
|
|
39
|
+
languageOptions: {
|
|
40
|
+
parserOptions: {
|
|
41
|
+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
|
42
|
+
tsconfigRootDir: import.meta.dirname,
|
|
43
|
+
},
|
|
44
|
+
// other options...
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
])
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
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:
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
// eslint.config.js
|
|
54
|
+
import reactX from 'eslint-plugin-react-x'
|
|
55
|
+
import reactDom from 'eslint-plugin-react-dom'
|
|
56
|
+
|
|
57
|
+
export default defineConfig([
|
|
58
|
+
globalIgnores(['dist']),
|
|
59
|
+
{
|
|
60
|
+
files: ['**/*.{ts,tsx}'],
|
|
61
|
+
extends: [
|
|
62
|
+
// Other configs...
|
|
63
|
+
// Enable lint rules for React
|
|
64
|
+
reactX.configs['recommended-typescript'],
|
|
65
|
+
// Enable lint rules for React DOM
|
|
66
|
+
reactDom.configs.recommended,
|
|
67
|
+
],
|
|
68
|
+
languageOptions: {
|
|
69
|
+
parserOptions: {
|
|
70
|
+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
|
71
|
+
tsconfigRootDir: import.meta.dirname,
|
|
72
|
+
},
|
|
73
|
+
// other options...
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
])
|
|
77
|
+
```
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
# Project Overview
|
|
2
|
+
|
|
3
|
+
This is a modern React web application built with Vite and TypeScript.
|
|
4
|
+
|
|
5
|
+
## Technology Stack
|
|
6
|
+
|
|
7
|
+
- **Framework**: React 19
|
|
8
|
+
- **Routing**: React Router v7
|
|
9
|
+
- **Language**: TypeScript (v5.9)
|
|
10
|
+
- **Build Tool**: Vite (v8)
|
|
11
|
+
- **Styling**: Tailwind CSS (v4) with PostCSS and Autoprefixer
|
|
12
|
+
- **Linting**: ESLint (v9) with Flat Config (`eslint.config.js`)
|
|
13
|
+
- **Package Manager**: pnpm
|
|
14
|
+
|
|
15
|
+
## Project Structure
|
|
16
|
+
|
|
17
|
+
- `/src` - Source code directory
|
|
18
|
+
- `/assets` - Static assets like images and SVGs
|
|
19
|
+
- `/components` - Global reusable UI components
|
|
20
|
+
- `/ui` - Atomic UI components (purely for rendering)
|
|
21
|
+
- `ComponentName/` - Component directory (PascalCase, e.g., `SampleButton/`)
|
|
22
|
+
- `componentName.tsx` - Component file (camelCase)
|
|
23
|
+
- `componentName.css` - Component specific styles
|
|
24
|
+
- `/features` - Functional UI components
|
|
25
|
+
- `/data` - Mock data and type definitions for demo purposes
|
|
26
|
+
- `types.ts` - TypeScript interfaces/types for the mock data
|
|
27
|
+
- `/mock` - JSON and CSV files containing the mock data
|
|
28
|
+
- `/pages` - Page components for routing
|
|
29
|
+
- `PageName/` - Directory for a specific page (e.g., `Home/`, `Demo/`)
|
|
30
|
+
- `index.tsx` - Main entry file for the page
|
|
31
|
+
- `components/` - Logical components specific to this page template
|
|
32
|
+
- `/utils` - Utility functions and helpers
|
|
33
|
+
- `App.tsx` - Main application component with routing setup
|
|
34
|
+
- `main.tsx` - Application entry point
|
|
35
|
+
- `index.css` - Global styles and Tailwind directives
|
|
36
|
+
- `/public` - Static assets served directly (e.g., favicons)
|
|
37
|
+
|
|
38
|
+
## Development Guidelines
|
|
39
|
+
|
|
40
|
+
1. **Architecture & Layering**:
|
|
41
|
+
- The project strictly separates UI and logic.
|
|
42
|
+
- **UI Components**: Responsible only for rendering. Placed in `src/components/ui` (atomic) or `src/components/features` (functional).
|
|
43
|
+
- **Logical Components**: Specific to a page template, placed in `src/pages/[PageName]/components/`.
|
|
44
|
+
- **Pages**: A page is composed of multiple logical components. Layout components that combine them can be written directly within the page's `index.tsx`.
|
|
45
|
+
2. **Naming Conventions**: Component directories must be PascalCase (e.g., `SampleButton`), and files inside them must be camelCase (e.g., `sampleButton.tsx`, `sampleButton.css`). Pages use `index.tsx` as their entry.
|
|
46
|
+
3. **Data Management (Demo First)**:
|
|
47
|
+
- The project is primarily used for demo presentations.
|
|
48
|
+
- All mock data should be placed in the `src/data/mock/` directory (supports `.json` and `.csv` formats).
|
|
49
|
+
- Strict TypeScript types must be defined for all mock data in `src/data/types.ts` to ensure type safety across the application.
|
|
50
|
+
4. **Styling**: Use Tailwind CSS utility classes for styling. For component-specific custom CSS, place it in the component's directory.
|
|
51
|
+
5. **TypeScript**: Use strict typing. Avoid using `any` type; define interfaces or types for props and state.
|
|
52
|
+
6. **Routing**: Use React Router v7 for any navigation or new pages. Place new page components in `src/pages/`.
|
|
53
|
+
7. **State Management**: Use React built-in hooks (`useState`, `useReducer`, `useContext`) for state management.
|
|
54
|
+
8. **Linting**: Ensure code passes ESLint rules defined in the project.
|
|
55
|
+
9. **Demo Directory Convention**: The `Demo` page (`src/pages/Demo`) serves as an example directory for the project. **Do not delete or modify it** unless the intent explicitly states to add or modify a demo.
|
|
56
|
+
|
|
57
|
+
<br />
|
|
58
|
+
|
|
59
|
+
**React and TypeScript guidance**
|
|
60
|
+
|
|
61
|
+
Your task is to generate a React single-page application (SPA) using TypeScript. Adhere strictly to the following guidelines:
|
|
62
|
+
|
|
63
|
+
**TypeScript & Type Safety**
|
|
64
|
+
|
|
65
|
+
- **Type Imports:**
|
|
66
|
+
- All `import` statements **MUST** be placed at the top level of the module (alongside other imports).
|
|
67
|
+
- **MUST NOT** use `import` inline within other type annotations or code structures.
|
|
68
|
+
- **MUST** use named import; do *not* use object destructuring.
|
|
69
|
+
- Correct Example: `import { BarChart } from 'recharts';`
|
|
70
|
+
- Incorrect Example: `const { BarChart } = Recharts;`
|
|
71
|
+
- **MUST NOT** use `import type` to import enum type and use its value; use `import {...}` instead.
|
|
72
|
+
- Correct Example
|
|
73
|
+
```
|
|
74
|
+
// types.ts
|
|
75
|
+
export enum CarType {
|
|
76
|
+
SUV = 'SUV',
|
|
77
|
+
SEDAN = 'SEDAN',
|
|
78
|
+
TRUCK = 'TRUCK'
|
|
79
|
+
}
|
|
80
|
+
// car.ts
|
|
81
|
+
import {CarType} from './types'
|
|
82
|
+
const carType = CarType.SUV; // Can use the enum value because it is using `import` directly.
|
|
83
|
+
```
|
|
84
|
+
- Incorrect Example
|
|
85
|
+
```
|
|
86
|
+
// types.ts
|
|
87
|
+
export enum CarType {
|
|
88
|
+
SUV = 'SUV',
|
|
89
|
+
SEDAN = 'SEDAN',
|
|
90
|
+
TRUCK = 'TRUCK'
|
|
91
|
+
}
|
|
92
|
+
// car.ts
|
|
93
|
+
import type {CarType} from './types'
|
|
94
|
+
const carType = CarType.SUV; // Cannot use the enum value during runtime because it is using `import type`.
|
|
95
|
+
```
|
|
96
|
+
- **CRITICAL:** When using any constants or types defined in the modules (e.g., `constants`, `types`), you **MUST** explicitly import them from their respective source module at the top of the file before using them. Do not assume they are globally available.
|
|
97
|
+
- **Enums:**
|
|
98
|
+
- **MUST** use standard `enum` declarations (e.g., `enum MyEnum { Value1, Value2 }`).
|
|
99
|
+
- **MUST NOT** use `const enum`. Use standard `enum` instead to ensure the enum definition is preserved in the compiled output.
|
|
100
|
+
|
|
101
|
+
**Styling**
|
|
102
|
+
|
|
103
|
+
- **Method:** Use **Tailwind CSS ONLY**.
|
|
104
|
+
- **Restrictions:** **DO NOT** use separate CSS files (`.css`, `.module.css`), CSS-in-JS libraries (styled-components, emotion, etc.), or inline `style` attributes.
|
|
105
|
+
- **Guidance:** Implement layout, color palette, and specific styles based on the web app's features.
|
|
106
|
+
|
|
107
|
+
**Responsive Design**
|
|
108
|
+
|
|
109
|
+
- **Cross-Device Support:** Ensure the application provides an optimal and consistent user experience across a wide range of devices, including desktops, tablets, and mobile phones.
|
|
110
|
+
- **Mobile-First Approach:** Adhere to Tailwind's mobile-first principle. Design and style for the smallest screen size by default, then use breakpoint prefixes (e.g., sm:, md:, lg:) to progressively enhance the layout for larger screens. This ensures a functional baseline experience on all devices and leads to cleaner, more maintainable code.
|
|
111
|
+
\*. **Persistent Call-to-Action:** Make primary controls sticky to ensure they are always readily accessible, regardless of scroll position.
|
|
112
|
+
|
|
113
|
+
**React & TSX Syntax Rules**
|
|
114
|
+
|
|
115
|
+
- **Rendering:** Use the `createRoot` API for rendering the application. **MUST NOT** use the legacy `ReactDOM.render`.
|
|
116
|
+
- **Correct** **`index.tsx`** **Example (React 18+):**
|
|
117
|
+
```tsx
|
|
118
|
+
import React from 'react';
|
|
119
|
+
import ReactDOM from 'react-dom/client'; // <--- Use 'react-dom/client'
|
|
120
|
+
import App from './App'; // Assuming App is in App.tsx
|
|
121
|
+
|
|
122
|
+
const rootElement = document.getElementById('root');
|
|
123
|
+
if (!rootElement) {
|
|
124
|
+
throw new Error("Could not find root element to mount to");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const root = ReactDOM.createRoot(rootElement);
|
|
128
|
+
root.render(
|
|
129
|
+
<React.StrictMode>
|
|
130
|
+
<App />
|
|
131
|
+
</React.StrictMode>
|
|
132
|
+
);
|
|
133
|
+
```
|
|
134
|
+
- **TSX Expressions:** Use standard JavaScript expressions inside curly braces `{}`.
|
|
135
|
+
- **Template Literals (Backticks)**: Must *not* escape the outer delimiting backticks; you must escape the inner literal backticks.
|
|
136
|
+
- Outer delimiting backticks: The backticks that start and end the template literal string must *not* be escaped. These define the template literal.
|
|
137
|
+
**Correct usage:**
|
|
138
|
+
```
|
|
139
|
+
const simpleGreeting = `Hello, ${name}!`; // Outer backticks are NOT escaped
|
|
140
|
+
|
|
141
|
+
const multiLinePrompt = `
|
|
142
|
+
This is a multi-line prompt
|
|
143
|
+
for ${name}.
|
|
144
|
+
---
|
|
145
|
+
Keep it simple.
|
|
146
|
+
---
|
|
147
|
+
`; // Outer backticks are NOT escaped
|
|
148
|
+
|
|
149
|
+
alert(`got error ${error}`); // The outer backticks in a function argument are not escaped
|
|
150
|
+
```
|
|
151
|
+
**Incorrect usage:**
|
|
152
|
+
```
|
|
153
|
+
// INCORRECT - Escaping the outer backticks
|
|
154
|
+
const simpleGreeting = \`Hello, ${name}!\`;
|
|
155
|
+
|
|
156
|
+
// INCORRECT - Escaping the outer backticks in a function argument
|
|
157
|
+
alert(\`got error ${error}\`);
|
|
158
|
+
|
|
159
|
+
// INCORRECT - Escaping the outer backticks
|
|
160
|
+
const multiLinePrompt = \`
|
|
161
|
+
This is a multi-line prompt
|
|
162
|
+
...
|
|
163
|
+
\`;
|
|
164
|
+
```
|
|
165
|
+
- Inner literal backticks: When including a backtick character inside the string, you must escape the inner literal backtick.
|
|
166
|
+
**Correct usage**
|
|
167
|
+
```
|
|
168
|
+
const commandInstruction = `To run the script, type \`npm start\` in your terminal.`; // Inner backticks are escaped
|
|
169
|
+
const markdownCodeBlock = `
|
|
170
|
+
Here's an example in JSON:
|
|
171
|
+
\`\`\`json
|
|
172
|
+
{
|
|
173
|
+
"key": "value"
|
|
174
|
+
}
|
|
175
|
+
\`\`\`
|
|
176
|
+
This is how you include a literal code block.
|
|
177
|
+
`; // Inner backticks are escaped
|
|
178
|
+
```
|
|
179
|
+
**Incorrect usage:**
|
|
180
|
+
```
|
|
181
|
+
// INCORRECT - If you want `npm start` to have literal backticks
|
|
182
|
+
const commandInstruction = `To run the script, type `npm start` in your terminal.`;
|
|
183
|
+
// This would likely cause a syntax error because the second ` would end the template literal prematurely.
|
|
184
|
+
```
|
|
185
|
+
- **Generics in Arrow Functions:** For generic arrow functions in TSX, a trailing comma **MUST** be added after the type parameter(s) to avoid parsing ambiguity. Only use Generics when the code is truly reusable.
|
|
186
|
+
- **Correct:** `const processData = <T,>(data: T): T => { ... };` (Note the comma after `T`)
|
|
187
|
+
- **Incorrect:** `const processData = <T>(data: T): T => { ... };`
|
|
188
|
+
- **MUST NOT** use `<style jsx>` which doesn't work in standard React.
|
|
189
|
+
- **React Router:** The app will run in an environment where it cannot update the URL path, except for the hash string. As such, do not generate any code that depends on manipulating the URL path, such as using React's `BrowserRouter`. But you may use React's `HashRouter`, as it only manipulates the hash string.
|
|
190
|
+
- **MUST NOT** use `react-dropzone` for file upload; use a file input element instead, for example, `<input type="file">`.
|
|
191
|
+
|
|
192
|
+
**Code Quality & Patterns**
|
|
193
|
+
|
|
194
|
+
- **Components:** Use **Functional Components** and **React Hooks** (e.g., `useState`, `useEffect`, `useCallback`).
|
|
195
|
+
- **Readability:** Prioritize clean, readable, and well-organized code.
|
|
196
|
+
- **Performance:** Write performant code where applicable.
|
|
197
|
+
- **Accessibility:** Ensure sufficient color contrast between text and its background for readability.
|
|
198
|
+
|
|
199
|
+
**Libraries**
|
|
200
|
+
|
|
201
|
+
- Use popular and existing libraries for improving functionality and visual appeal. Do not use mock or made-up libraries.
|
|
202
|
+
- Use `d3` for data visualization.
|
|
203
|
+
- Use `recharts` for charts.
|
|
204
|
+
|
|
205
|
+
**React common pitfalls**
|
|
206
|
+
|
|
207
|
+
You must avoid the common pitfalls below when generating the code.
|
|
208
|
+
|
|
209
|
+
- **React Hook Infinite Loop:** When using `useEffect` and `useCallback` together, be cautious to avoid infinite re-render loops.
|
|
210
|
+
- **The Pitfall:** A common loop occurs when:
|
|
211
|
+
1. A `useEffect` hook includes a memoized function (from `useCallback`) in its dependency array.
|
|
212
|
+
2. The `useCallback` hook includes a state variable (e.g., `count`) in *its* dependency array.
|
|
213
|
+
3. The function *inside* `useCallback` updates that same state variable (`setCount`) based on its current value (`count + 1`).
|
|
214
|
+
- *Resulting Cycle:* `setCount` updates `count` -> Component re-renders -> `useCallback` sees new `count`, creates a *new* function instance -> `useEffect` sees the function changed, runs again -> Calls `setCount`... loop!
|
|
215
|
+
- When using `useEffect`, if you want to run only once when the component mounts (and clean up when it unmounts), an empty dependency array \[] is the correct pattern.
|
|
216
|
+
- **Incorrect Code Example:**
|
|
217
|
+
```
|
|
218
|
+
const [count, setCount] = useState(0);
|
|
219
|
+
const [message, setMessage] = useState('Loading...');
|
|
220
|
+
|
|
221
|
+
// This function's identity changes whenever 'count' changes
|
|
222
|
+
const incrementAndLog = useCallback(() => {
|
|
223
|
+
console.log('incrementAndLog called, current count:', count);
|
|
224
|
+
const newCount = count + 1;
|
|
225
|
+
setMessage(`Loading count ${newCount}...`); // Simulate work
|
|
226
|
+
// Simulate async operation like fetching
|
|
227
|
+
setTimeout(() => {
|
|
228
|
+
console.log('Setting count to:', newCount);
|
|
229
|
+
setCount(newCount); // <-- This state update triggers the useCallback dependency change
|
|
230
|
+
setMessage(`Count is ${newCount}`);
|
|
231
|
+
}, 500);
|
|
232
|
+
}, [count]); // <-- Depends on 'count'
|
|
233
|
+
|
|
234
|
+
// This effect runs whenever 'incrementAndLog' changes identity
|
|
235
|
+
useEffect(() => {
|
|
236
|
+
console.log("Effect running because incrementAndLog changed");
|
|
237
|
+
incrementAndLog(); // Call the function
|
|
238
|
+
}, [incrementAndLog]); // <-- Depends on the function that depends on 'count'
|
|
239
|
+
```
|
|
240
|
+
- **Correct Code Example:**
|
|
241
|
+
```
|
|
242
|
+
const [count, setCount] = useState(0);
|
|
243
|
+
const [message, setMessage] = useState('Loading...');
|
|
244
|
+
|
|
245
|
+
const incrementAndLog = useCallback(() => {
|
|
246
|
+
// Use functional update to avoid direct dependency on 'count' in useCallback
|
|
247
|
+
// OR keep the dependency but fix the useEffect call
|
|
248
|
+
setCount(prevCount => {
|
|
249
|
+
console.log('incrementAndLog called, previous count:', prevCount);
|
|
250
|
+
const newCount = prevCount + 1;
|
|
251
|
+
setMessage(`Loading count ${newCount}...`);
|
|
252
|
+
// Simulate async operation
|
|
253
|
+
setTimeout(() => {
|
|
254
|
+
console.log('Setting count (functional update) to:', newCount);
|
|
255
|
+
setMessage(`Count is ${newCount}`);
|
|
256
|
+
}, 500);
|
|
257
|
+
return newCount; // Return the new count for the functional update
|
|
258
|
+
});
|
|
259
|
+
}, [count]);
|
|
260
|
+
|
|
261
|
+
// This effect runs ONLY ONCE on mount
|
|
262
|
+
useEffect(() => {
|
|
263
|
+
console.log("Effect running ONCE on mount to set initial state");
|
|
264
|
+
setMessage('Setting initial count...');
|
|
265
|
+
// Simulate initial load
|
|
266
|
+
setTimeout(() => {
|
|
267
|
+
setCount(1); // Set initial count
|
|
268
|
+
setMessage('Count is 1');
|
|
269
|
+
}, 500);
|
|
270
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
271
|
+
}, []); // <-- Empty array fixes the loop. Runs only once.
|
|
272
|
+
```
|
|
273
|
+
- **Incorrect Code Example:**
|
|
274
|
+
```
|
|
275
|
+
useEffect(() => {
|
|
276
|
+
fetchScenario();
|
|
277
|
+
}, [fetchScenario]); // Infinite initialize data.
|
|
278
|
+
```
|
|
279
|
+
- **Correct Code Example:**
|
|
280
|
+
```
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
fetchScenario();
|
|
283
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
284
|
+
}, []); // Only initialize data once
|
|
285
|
+
```
|
|
286
|
+
The correct code will very likely cause the `eslint-plugin-react-hooks` to raise a warning. Add `eslint-disable-next-line react-hooks/exhaustive-deps` to suppress the warning.
|
|
287
|
+
- **Be Explicit About Component Scope:**
|
|
288
|
+
- Ensure helper components are defined outside the main component function body to prevent re-rendering issues.
|
|
289
|
+
- Define components outside parent components to avoid unnecessary unmounting and remounting, which can lead to loss of input state and focus.
|
|
290
|
+
- **Incorrect Code Example:**
|
|
291
|
+
```
|
|
292
|
+
function ParentComponent() {
|
|
293
|
+
const [text, setText] = useState('');
|
|
294
|
+
// !! BAD: ChildInput is defined INSIDE ParentComponent !!
|
|
295
|
+
const ChildInput: React.FC = () => {
|
|
296
|
+
return (
|
|
297
|
+
<input
|
|
298
|
+
type="text"
|
|
299
|
+
value={text} // Gets value from parent state
|
|
300
|
+
onChange={(e) => setText(e.target.value)} // Updates parent state
|
|
301
|
+
placeholder="Type here..."
|
|
302
|
+
className="border p-2"
|
|
303
|
+
/>
|
|
304
|
+
);
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
return (
|
|
308
|
+
<div className="p-4 border border-red-500">
|
|
309
|
+
<h2 className="text-lg font-bold mb-2">Bad Example</h2>
|
|
310
|
+
<p className="mb-2">Parent State: {text}</p>
|
|
311
|
+
<ChildInput /> {/* Rendering the locally defined component */}
|
|
312
|
+
</div>
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
export default ParentComponent;
|
|
316
|
+
```
|
|
317
|
+
- **Correct Code Example:**
|
|
318
|
+
```
|
|
319
|
+
interface ChildInputProps {
|
|
320
|
+
value: string;
|
|
321
|
+
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const ChildInput: React.FC<ChildInputProps> = ({ value, onChange }) => {
|
|
325
|
+
return (
|
|
326
|
+
<input
|
|
327
|
+
type="text"
|
|
328
|
+
value={value} // Gets value from props
|
|
329
|
+
onChange={onChange} // Uses handler from props
|
|
330
|
+
placeholder="Type here..."
|
|
331
|
+
className="border p-2"
|
|
332
|
+
/>
|
|
333
|
+
);
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
function ParentComponent() {
|
|
337
|
+
const [text, setText] = useState('');
|
|
338
|
+
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
339
|
+
setText(e.target.value);
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
return (
|
|
343
|
+
<div className="p-4 border border-green-500">
|
|
344
|
+
<h2 className="text-lg font-bold mb-2">Good Example</h2>
|
|
345
|
+
<p className="mb-2">Parent State: {text}</p>
|
|
346
|
+
{/* Pass state and handler down as props */}
|
|
347
|
+
<ChildInput value={text} onChange={handleInputChange} />
|
|
348
|
+
</div>
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export default ParentComponent;
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Scripts
|
|
356
|
+
|
|
357
|
+
- `pnpm dev` - Start the development server
|
|
358
|
+
- `pnpm build` - Type check and build the application for production
|
|
359
|
+
- `pnpm lint` - Run ESLint on the codebase
|
|
360
|
+
- `pnpm preview` - Preview the production build locally
|
|
361
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
import { defineConfig, globalIgnores } from 'eslint/config'
|
|
7
|
+
|
|
8
|
+
export default defineConfig([
|
|
9
|
+
globalIgnores(['dist']),
|
|
10
|
+
{
|
|
11
|
+
files: ['**/*.{ts,tsx}'],
|
|
12
|
+
extends: [
|
|
13
|
+
js.configs.recommended,
|
|
14
|
+
tseslint.configs.recommended,
|
|
15
|
+
reactHooks.configs.flat.recommended,
|
|
16
|
+
reactRefresh.configs.vite,
|
|
17
|
+
],
|
|
18
|
+
languageOptions: {
|
|
19
|
+
ecmaVersion: 2020,
|
|
20
|
+
globals: globals.browser,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
])
|
|
@@ -0,0 +1,13 @@
|
|
|
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-vue-app</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "proto",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build": "tsc -b && vite build",
|
|
8
|
+
"lint": "eslint .",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"clsx": "^2.1.1",
|
|
13
|
+
"framer-motion": "^12.38.0",
|
|
14
|
+
"lucide-react": "^0.577.0",
|
|
15
|
+
"react": "^19.2.4",
|
|
16
|
+
"react-dom": "^19.2.4",
|
|
17
|
+
"react-router-dom": "^7.13.1",
|
|
18
|
+
"recharts": "^3.8.0",
|
|
19
|
+
"tailwind-merge": "^3.5.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@eslint/js": "^9.39.4",
|
|
23
|
+
"@tailwindcss/postcss": "^4.2.1",
|
|
24
|
+
"@types/node": "^24.12.0",
|
|
25
|
+
"@types/react": "^19.2.14",
|
|
26
|
+
"@types/react-dom": "^19.2.3",
|
|
27
|
+
"@vitejs/plugin-react": "^6.0.0",
|
|
28
|
+
"autoprefixer": "^10.4.27",
|
|
29
|
+
"eslint": "^9.39.4",
|
|
30
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
31
|
+
"eslint-plugin-react-refresh": "^0.5.2",
|
|
32
|
+
"globals": "^17.4.0",
|
|
33
|
+
"postcss": "^8.5.8",
|
|
34
|
+
"tailwindcss": "^4.2.1",
|
|
35
|
+
"typescript": "~5.9.3",
|
|
36
|
+
"typescript-eslint": "^8.56.1",
|
|
37
|
+
"vite": "^8.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|