@adlas/create-app 1.0.49 → 1.0.51
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/package.json +1 -1
- package/templates/docs/FIGMA_TO_CODE_GUIDE.md +907 -638
|
@@ -4,86 +4,47 @@
|
|
|
4
4
|
|
|
5
5
|
This document provides comprehensive guidelines for converting Figma designs to code in this project. **You MUST strictly follow the project structure, component patterns, and coding standards defined below.**
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## 🔌 Figma MCP Server Integration
|
|
10
|
-
|
|
11
|
-
### Prerequisites
|
|
12
|
-
|
|
13
|
-
Before implementing UI from Figma designs, ensure the following:
|
|
14
|
-
|
|
15
|
-
1. **Claude Desktop App** - You must be using Claude Desktop (not web interface)
|
|
16
|
-
2. **Figma MCP Server** - Installed and configured in Claude Desktop settings
|
|
17
|
-
3. **Figma Access Token** - Valid token with read access to the design file
|
|
18
|
-
4. **File Access** - Permissions to view the specific Figma file
|
|
19
|
-
|
|
20
|
-
### Setup Verification
|
|
21
|
-
|
|
22
|
-
Before starting, verify MCP server is working:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
# Check if Figma server is connected in Claude Desktop
|
|
26
|
-
# You should see "figma" in available MCP servers
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### Figma URL Format
|
|
7
|
+
## 🔗 Working with Figma MCP Server
|
|
30
8
|
|
|
31
|
-
|
|
32
|
-
- File URL: `https://www.figma.com/file/{file-key}/{file-name}`
|
|
33
|
-
- Design URL: `https://www.figma.com/design/{file-key}/{file-name}`
|
|
34
|
-
- Specific page: Add `?node-id={page-node-id}` to URL
|
|
9
|
+
### CRITICAL: Use Figma Link, NOT Screenshots
|
|
35
10
|
|
|
36
|
-
|
|
11
|
+
**❌ NEVER use screenshots** - Screenshots lose design data, measurements, and context
|
|
37
12
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
1. Get Figma URL from user
|
|
51
|
-
↓
|
|
52
|
-
2. Use Figma MCP to fetch design structure
|
|
53
|
-
↓
|
|
54
|
-
3. Identify all pages and components
|
|
55
|
-
↓
|
|
56
|
-
4. Export icons as SVG → src/assets/icons/
|
|
57
|
-
↓
|
|
58
|
-
5. Run pnpm generate-icons
|
|
59
|
-
↓
|
|
60
|
-
6. Export logos/images → public/images/
|
|
61
|
-
↓
|
|
62
|
-
7. Create centralized image constants (src/config/images.ts)
|
|
63
|
-
↓
|
|
64
|
-
8. Map Figma components to HeroUI components
|
|
65
|
-
↓
|
|
66
|
-
9. Implement pages with proper i18n and navigation
|
|
67
|
-
↓
|
|
68
|
-
10. Test responsive behavior across breakpoints
|
|
13
|
+
**✅ ALWAYS use Figma MCP server with node links**:
|
|
14
|
+
```typescript
|
|
15
|
+
// Use get_design_context tool with node-id from Figma URL
|
|
16
|
+
// Example URL: https://figma.com/design/:fileKey/:fileName?node-id=8486-1580
|
|
17
|
+
// Extract node-id: 8486-1580 → use as: "8486:1580"
|
|
18
|
+
|
|
19
|
+
mcp__figma-dev-mode-mcp-server__get_design_context({
|
|
20
|
+
nodeId: "8486:1580",
|
|
21
|
+
clientLanguages: "typescript",
|
|
22
|
+
clientFrameworks: "react,nextjs"
|
|
23
|
+
})
|
|
69
24
|
```
|
|
70
25
|
|
|
71
|
-
**
|
|
26
|
+
**Benefits of using Figma MCP**:
|
|
27
|
+
- ✅ Get exact measurements, colors, and spacing
|
|
28
|
+
- ✅ Access design tokens and styles
|
|
29
|
+
- ✅ See component structure and hierarchy
|
|
30
|
+
- ✅ Get accurate typography settings
|
|
31
|
+
- ✅ Extract assets and icons properly
|
|
72
32
|
|
|
73
|
-
|
|
33
|
+
**Do NOT call `get_screenshot`** - The design context provides all needed information
|
|
74
34
|
|
|
75
35
|
## 🎯 Core Principles
|
|
76
36
|
|
|
77
|
-
1. **Use
|
|
78
|
-
2. **Use
|
|
79
|
-
3. **
|
|
80
|
-
4. **
|
|
81
|
-
5. **
|
|
82
|
-
6. **
|
|
83
|
-
7. **
|
|
84
|
-
8. **
|
|
85
|
-
9. **
|
|
86
|
-
10. **
|
|
37
|
+
1. **Use Figma MCP Server** - ALWAYS use `get_design_context` with Figma node links, NEVER screenshots
|
|
38
|
+
2. **Use HeroUI components first** - Always prefer HeroUI components. Only use Tailwind CSS for custom styling when HeroUI doesn't provide the component
|
|
39
|
+
3. **Use ONLY existing components** - Never create custom implementations when project components exist
|
|
40
|
+
4. **i18n for ALL text** - ALL labels, placeholders, titles, error messages MUST use translation keys
|
|
41
|
+
5. **Navigation from config** - NEVER hardcode URLs. Always use `NAVIGATION_URLS` from config
|
|
42
|
+
6. **Icons workflow** - Export SVG from Figma → Place in `src/assets/icons/` → Run `pnpm generate-icons` → Use generated TSX components
|
|
43
|
+
7. **Logos workflow** - Export SVG/PNG from Figma → Place in `public/` → Reference via path (prefer SVG over PNG)
|
|
44
|
+
8. **Use Tailwind standard classes** - Use closest Tailwind class instead of custom values (e.g., `h-10` not `h-[41px]`)
|
|
45
|
+
9. **Follow project structure** - Place files in correct locations as defined below
|
|
46
|
+
10. **Match coding patterns** - Use the same patterns found in existing code
|
|
47
|
+
11. **Type safety first** - Use TypeScript strictly, no `any` types
|
|
87
48
|
|
|
88
49
|
---
|
|
89
50
|
|
|
@@ -91,27 +52,33 @@ When you receive a Figma URL:
|
|
|
91
52
|
|
|
92
53
|
### CRITICAL: Component Styles Must Be Configured, Not Inline
|
|
93
54
|
|
|
94
|
-
**❌ WRONG - Inline
|
|
55
|
+
**❌ WRONG - Inline component styles**:
|
|
95
56
|
```tsx
|
|
96
|
-
//
|
|
57
|
+
// DON'T: Apply component-specific styles inline via className
|
|
97
58
|
<Button className="h-10 rounded-full bg-[#19ffa3] px-4 text-sm text-black">
|
|
98
59
|
Click Me
|
|
99
60
|
</Button>
|
|
100
61
|
|
|
101
|
-
//
|
|
62
|
+
// DON'T: Mix props and className for same property
|
|
63
|
+
<Button size="md" className="h-10 px-4"> {/* redundant */}
|
|
64
|
+
Click Me
|
|
65
|
+
</Button>
|
|
66
|
+
|
|
67
|
+
// DON'T: Use HTML elements when HeroUI component exists
|
|
102
68
|
<button onClick={handler}>Click</button>
|
|
103
69
|
```
|
|
104
70
|
|
|
105
|
-
**✅ CORRECT -
|
|
71
|
+
**✅ CORRECT - Use props and configured variants**:
|
|
106
72
|
```tsx
|
|
73
|
+
// Step 1: Configure variants in component wrapper
|
|
107
74
|
// File: src/components/ui/Button.tsx
|
|
108
75
|
import { extendVariants, Button as HeroUIButton } from '@heroui/react';
|
|
109
76
|
|
|
110
77
|
export const Button = extendVariants(HeroUIButton, {
|
|
111
78
|
variants: {
|
|
112
79
|
color: {
|
|
113
|
-
|
|
114
|
-
|
|
80
|
+
// ✅ Use theme colors from hero.ts, NOT custom colors
|
|
81
|
+
primary: 'bg-primary text-black',
|
|
115
82
|
},
|
|
116
83
|
size: {
|
|
117
84
|
sm: 'h-8 px-3 text-xs',
|
|
@@ -120,54 +87,104 @@ export const Button = extendVariants(HeroUIButton, {
|
|
|
120
87
|
},
|
|
121
88
|
},
|
|
122
89
|
defaultVariants: {
|
|
123
|
-
color: 'primary',
|
|
124
90
|
size: 'md',
|
|
125
|
-
radius: 'full',
|
|
126
91
|
},
|
|
127
92
|
});
|
|
128
93
|
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
<Button color="secondary" size="lg">Large Button</Button>
|
|
132
|
-
```
|
|
94
|
+
// Step 2: Use ONLY props in components (NO className for component styles)
|
|
95
|
+
import { Button } from '@/components/ui';
|
|
133
96
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
- ❌ Never inline: Component-specific styles (heights, colors, padding, text sizes, border radius)
|
|
97
|
+
<Button color="primary"> {/* size="md" not needed - it's the default */}
|
|
98
|
+
Click Me
|
|
99
|
+
</Button>
|
|
138
100
|
|
|
139
|
-
|
|
101
|
+
// ✅ className ONLY for layout utilities
|
|
102
|
+
<Button
|
|
103
|
+
color="primary" {/* Only specify non-default variants */}
|
|
104
|
+
className="mt-4 hidden lg:block" // Layout utilities only
|
|
105
|
+
>
|
|
106
|
+
Click Me
|
|
107
|
+
</Button>
|
|
140
108
|
|
|
141
|
-
|
|
109
|
+
// ✅ Override default when needed
|
|
110
|
+
<Button color="primary" size="lg"> {/* Explicitly override default size */}
|
|
111
|
+
Large Button
|
|
112
|
+
</Button>
|
|
113
|
+
```
|
|
142
114
|
|
|
115
|
+
**Component Style Rules**:
|
|
116
|
+
- ✅ **Configure in wrapper**: All component-specific styles (height, padding, colors, text size)
|
|
117
|
+
- ✅ **Set defaultVariants**: Define defaults in wrapper so you don't repeat them in usage
|
|
118
|
+
- ✅ **Use theme colors**: `bg-primary`, `bg-secondary`, `bg-success`, `bg-danger`, `bg-warning` from hero.ts
|
|
119
|
+
- ✅ **Use props**: Only specify props that differ from defaults (e.g., `color="primary"`, `size="lg"`)
|
|
120
|
+
- ✅ **Use HeroUI props for styling**: HeroUI components have built-in props like `radius`, `isRounded`, etc.
|
|
121
|
+
- ✅ **className for layout ONLY**: `mt-4`, `hidden`, `lg:block`, `justify-start`, `text-white`
|
|
122
|
+
- ❌ **NEVER use custom colors**: `bg-[#19ffa3]`, `text-[#ff0000]` - Use theme colors instead
|
|
123
|
+
- ❌ **NEVER use hover states in config**: `hover:bg-[#00e68a]` - HeroUI handles hover states
|
|
124
|
+
- ❌ **NEVER className for**: `h-10`, `px-4`, `text-sm`, `bg-[color]`, `rounded-full`
|
|
125
|
+
- ❌ **NEVER repeat defaultVariants**: Don't specify `size="md"` if `md` is already the default
|
|
126
|
+
|
|
127
|
+
**Color Usage Rules**:
|
|
143
128
|
```tsx
|
|
144
|
-
|
|
129
|
+
// ✅ CORRECT - Use theme colors from hero.ts or globals.css
|
|
130
|
+
color: {
|
|
131
|
+
primary: 'bg-primary text-black',
|
|
132
|
+
secondary: 'bg-secondary text-white',
|
|
133
|
+
success: 'bg-success text-white',
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ❌ WRONG - Custom color values or hover states
|
|
137
|
+
color: {
|
|
138
|
+
primary: 'bg-[#19ffa3] text-black hover:bg-[#00e68a]', // Don't use hex or hover
|
|
139
|
+
custom: 'bg-[rgb(25,255,163)]', // Don't use rgb
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Available theme colors (from hero.ts):
|
|
143
|
+
primary-50, primary-100, ..., primary-500, ..., primary-900
|
|
144
|
+
// And HeroUI defaults:
|
|
145
|
+
secondary, success, danger, warning, default, foreground, background
|
|
146
|
+
```
|
|
145
147
|
|
|
146
|
-
|
|
148
|
+
**What goes where**:
|
|
149
|
+
```tsx
|
|
150
|
+
// In Button.tsx configuration:
|
|
151
|
+
const Button = extendVariants(HerouiButton, {
|
|
147
152
|
variants: {
|
|
148
|
-
variant: {
|
|
149
|
-
flat: 'bg-gray-100 border-none',
|
|
150
|
-
bordered: 'border-2 border-gray-300',
|
|
151
|
-
},
|
|
152
153
|
size: {
|
|
153
|
-
sm: 'h-8 text-xs',
|
|
154
|
-
md: 'h-10 text-sm',
|
|
155
|
-
lg: 'h-12 text-base',
|
|
154
|
+
sm: 'h-8 px-3 text-xs',
|
|
155
|
+
md: 'h-10 px-4 text-sm', // Height, padding, text size
|
|
156
|
+
lg: 'h-12 px-6 text-base',
|
|
157
|
+
},
|
|
158
|
+
color: {
|
|
159
|
+
primary: 'bg-primary text-black', // Theme colors ONLY, NO hover states
|
|
156
160
|
},
|
|
157
161
|
},
|
|
158
162
|
defaultVariants: {
|
|
159
|
-
|
|
160
|
-
size: 'md',
|
|
161
|
-
radius: 'lg',
|
|
163
|
+
size: 'md', // Default size - no need to specify in usage
|
|
162
164
|
},
|
|
163
165
|
});
|
|
164
|
-
```
|
|
165
166
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
-
|
|
170
|
-
-
|
|
167
|
+
// In component usage:
|
|
168
|
+
<Button
|
|
169
|
+
color="primary" // ✅ Specify only when different from default
|
|
170
|
+
radius="full" // ✅ HeroUI built-in prop (don't configure in wrapper)
|
|
171
|
+
className="mt-4 hidden lg:block" // ✅ Layout utilities only
|
|
172
|
+
>
|
|
173
|
+
{t('navbar.bookDemo')} // ✅ i18n text
|
|
174
|
+
</Button>
|
|
175
|
+
// Note: size="md" NOT needed because it's the defaultVariant
|
|
176
|
+
|
|
177
|
+
// Using size prop when you need different size:
|
|
178
|
+
<Button color="primary" size="lg"> // ✅ Override default size
|
|
179
|
+
Large Button
|
|
180
|
+
</Button>
|
|
181
|
+
|
|
182
|
+
// Using Icon component:
|
|
183
|
+
import { Icon } from '@/components/ui';
|
|
184
|
+
|
|
185
|
+
<Icon name="ChevronDownIcon" className="size-4" /> // ✅ CORRECT - PascalCase name
|
|
186
|
+
<ChevronDownIcon className="size-4" /> // ❌ WRONG - Don't import individual icons
|
|
187
|
+
```
|
|
171
188
|
|
|
172
189
|
### Data Must Be Mapped from Constants
|
|
173
190
|
|
|
@@ -184,16 +201,13 @@ export const Input = extendVariants(HeroUIInput, {
|
|
|
184
201
|
```tsx
|
|
185
202
|
// File: src/config/menuOptions.ts
|
|
186
203
|
export const productMenuItems = [
|
|
187
|
-
{ key: 'analytics', labelKey: 'product.analytics', href:
|
|
188
|
-
{ key: 'insights', labelKey: 'product.insights', href:
|
|
189
|
-
{ key: 'reports', labelKey: 'product.reports', href:
|
|
190
|
-
]
|
|
204
|
+
{ key: 'analytics', labelKey: 'product.analytics', href: '/analytics' },
|
|
205
|
+
{ key: 'insights', labelKey: 'product.insights', href: '/insights' },
|
|
206
|
+
{ key: 'reports', labelKey: 'product.reports', href: '/reports' },
|
|
207
|
+
];
|
|
191
208
|
|
|
192
209
|
// Usage:
|
|
193
210
|
import { productMenuItems } from '@/config/menuOptions';
|
|
194
|
-
import { useTranslations } from 'next-intl';
|
|
195
|
-
|
|
196
|
-
const t = useTranslations();
|
|
197
211
|
|
|
198
212
|
<DropdownMenu>
|
|
199
213
|
{productMenuItems.map((item) => (
|
|
@@ -206,138 +220,42 @@ const t = useTranslations();
|
|
|
206
220
|
|
|
207
221
|
---
|
|
208
222
|
|
|
209
|
-
## 🎨
|
|
210
|
-
|
|
211
|
-
### Primary Colors (from hero.ts)
|
|
223
|
+
## 🎨 Component Priority & Usage Strategy
|
|
212
224
|
|
|
213
|
-
|
|
225
|
+
### 1. Check HeroUI First
|
|
226
|
+
Before creating ANY component, check if HeroUI provides it:
|
|
227
|
+
- **HeroUI Documentation**: https://heroui.com/docs/components
|
|
228
|
+
- **HeroUI Figma Kit**: https://www.figma.com/design/kFGcjHsNKZx7zh2NxEJXYt/HeroUI-Figma-Kit--Community---Community-
|
|
214
229
|
|
|
215
|
-
|
|
216
|
-
primary: {
|
|
217
|
-
DEFAULT: '#25C780', // Main primary color
|
|
218
|
-
50: '#E6FFF0', // Lightest
|
|
219
|
-
100: '#CBFFE0',
|
|
220
|
-
200: '#AEFFD1',
|
|
221
|
-
300: '#8EFFC2',
|
|
222
|
-
400: '#66FFB2',
|
|
223
|
-
500: '#19FFA3',
|
|
224
|
-
600: '#25C780', // DEFAULT
|
|
225
|
-
700: '#26915F',
|
|
226
|
-
800: '#215F40',
|
|
227
|
-
900: '#173123', // Darkest
|
|
228
|
-
}
|
|
230
|
+
### 2. Component Selection Flow
|
|
229
231
|
```
|
|
232
|
+
1. Does HeroUI have this component?
|
|
233
|
+
→ YES: Use HeroUI component (via @/components/ui wrapper if exists)
|
|
234
|
+
→ NO: Go to step 2
|
|
230
235
|
|
|
231
|
-
|
|
236
|
+
2. Does project have wrapper in src/components/ui/?
|
|
237
|
+
→ YES: Use the wrapper
|
|
238
|
+
→ NO: Go to step 3
|
|
232
239
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
<div className="bg-primary-50"> {/* Lightest shade */}
|
|
237
|
-
<div className="bg-primary-600"> {/* Same as DEFAULT */}
|
|
238
|
-
<div className="bg-primary-900"> {/* Darkest shade */}
|
|
239
|
-
|
|
240
|
-
// Text colors
|
|
241
|
-
<p className="text-primary"> {/* Uses DEFAULT */}
|
|
242
|
-
<p className="text-primary-700">
|
|
243
|
-
|
|
244
|
-
// Border colors
|
|
245
|
-
<div className="border border-primary">
|
|
246
|
-
<div className="border-2 border-primary-500">
|
|
247
|
-
|
|
248
|
-
// HeroUI component colors
|
|
249
|
-
<Button color="primary">Click</Button> {/* Uses primary palette */}
|
|
240
|
+
3. Build with Tailwind CSS utilities
|
|
241
|
+
→ Use HeroUI theme colors and patterns
|
|
242
|
+
→ Follow mobile-first responsive design
|
|
250
243
|
```
|
|
251
244
|
|
|
252
|
-
###
|
|
253
|
-
|
|
254
|
-
- **50-200**: Very light backgrounds, subtle highlights
|
|
255
|
-
- **300-400**: Hover states, light accents
|
|
256
|
-
- **500-600**: Primary actions, main brand color (DEFAULT is 600)
|
|
257
|
-
- **700-800**: Active states, darker accents
|
|
258
|
-
- **900**: Very dark accents, strong contrast
|
|
259
|
-
|
|
260
|
-
**Important**: Always use these theme colors instead of hardcoded hex values. This ensures consistency and makes theme updates easier.
|
|
261
|
-
|
|
262
|
-
---
|
|
263
|
-
|
|
264
|
-
## 🧭 Navigation Components
|
|
265
|
-
|
|
266
|
-
### Navbar Component with HeroUI
|
|
267
|
-
|
|
268
|
-
When implementing navigation from Figma, use HeroUI Navbar component:
|
|
269
|
-
|
|
245
|
+
### 3. Example Decision Tree
|
|
270
246
|
```tsx
|
|
271
|
-
|
|
247
|
+
// Need a Button?
|
|
248
|
+
import { Button } from '@/components/ui'; // ✅ Use HeroUI Button wrapper
|
|
272
249
|
|
|
273
|
-
|
|
274
|
-
import
|
|
275
|
-
import { useTranslations } from 'next-intl';
|
|
276
|
-
import { NAVIGATION_URLS } from '@/config/navigationUrls';
|
|
277
|
-
import { IMAGES } from '@/config/images';
|
|
278
|
-
|
|
279
|
-
// Define menu items in constants file
|
|
280
|
-
// File: src/config/navigationItems.ts
|
|
281
|
-
export const mainNavigationItems = [
|
|
282
|
-
{ key: 'home', labelKey: 'nav.home', href: NAVIGATION_URLS.ROOT },
|
|
283
|
-
{ key: 'about', labelKey: 'nav.about', href: NAVIGATION_URLS.ABOUT },
|
|
284
|
-
{ key: 'services', labelKey: 'nav.services', href: NAVIGATION_URLS.SERVICES },
|
|
285
|
-
{ key: 'contact', labelKey: 'nav.contact', href: NAVIGATION_URLS.CONTACT },
|
|
286
|
-
] as const;
|
|
250
|
+
// Need an Input?
|
|
251
|
+
import { Input } from '@/components/ui'; // ✅ Use HeroUI Input wrapper
|
|
287
252
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
<Navbar>
|
|
293
|
-
<NavbarBrand>
|
|
294
|
-
<Link href={NAVIGATION_URLS.ROOT}>
|
|
295
|
-
<img src={IMAGES.LOGOS.PRIMARY} alt={t('nav.logoAlt')} className="h-10 w-auto" />
|
|
296
|
-
</Link>
|
|
297
|
-
</NavbarBrand>
|
|
298
|
-
|
|
299
|
-
<NavbarContent className="hidden gap-4 sm:flex" justify="center">
|
|
300
|
-
{mainNavigationItems.map((item) => (
|
|
301
|
-
<NavbarItem key={item.key}>
|
|
302
|
-
<Link href={item.href} className="text-foreground">
|
|
303
|
-
{t(item.labelKey)}
|
|
304
|
-
</Link>
|
|
305
|
-
</NavbarItem>
|
|
306
|
-
))}
|
|
307
|
-
</NavbarContent>
|
|
308
|
-
|
|
309
|
-
<NavbarContent justify="end">
|
|
310
|
-
<NavbarItem>
|
|
311
|
-
<Button as={Link} href={NAVIGATION_URLS.AUTH.LOGIN} color="primary">
|
|
312
|
-
{t('nav.login')}
|
|
313
|
-
</Button>
|
|
314
|
-
</NavbarItem>
|
|
315
|
-
</NavbarContent>
|
|
316
|
-
|
|
317
|
-
<NavbarMenuToggle className="sm:hidden" />
|
|
318
|
-
|
|
319
|
-
<NavbarMenu>
|
|
320
|
-
{mainNavigationItems.map((item) => (
|
|
321
|
-
<NavbarMenuItem key={item.key}>
|
|
322
|
-
<Link href={item.href} className="w-full">
|
|
323
|
-
{t(item.labelKey)}
|
|
324
|
-
</Link>
|
|
325
|
-
</NavbarMenuItem>
|
|
326
|
-
))}
|
|
327
|
-
</NavbarMenu>
|
|
328
|
-
</Navbar>
|
|
329
|
-
);
|
|
330
|
-
}
|
|
253
|
+
// Need a Card?
|
|
254
|
+
// HeroUI has Card, but check if wrapper exists in project
|
|
255
|
+
// If not, use Tailwind utilities with HeroUI colors:
|
|
256
|
+
<div className="rounded-lg bg-white p-6 shadow-md"> // ✅ Custom with Tailwind
|
|
331
257
|
```
|
|
332
258
|
|
|
333
|
-
**Key points**:
|
|
334
|
-
- Use HeroUI `Navbar`, `NavbarBrand`, `NavbarContent`, etc. components
|
|
335
|
-
- Define navigation items in separate constants file
|
|
336
|
-
- Use i18n for all text (`t('nav.home')`)
|
|
337
|
-
- Use `NAVIGATION_URLS` for all links (never hardcode)
|
|
338
|
-
- Use centralized image constants for logo (`IMAGES.LOGOS.PRIMARY`)
|
|
339
|
-
- Implement responsive menu with `NavbarMenuToggle` and `NavbarMenu`
|
|
340
|
-
|
|
341
259
|
---
|
|
342
260
|
|
|
343
261
|
## 📁 Project Structure
|
|
@@ -349,103 +267,256 @@ export default function NavbarComponent() {
|
|
|
349
267
|
### Components Location
|
|
350
268
|
```
|
|
351
269
|
src/components/
|
|
352
|
-
├── ui/ # Reusable UI components (HeroUI wrappers
|
|
353
|
-
├── icons/ #
|
|
270
|
+
├── ui/ # Reusable UI components (HeroUI wrappers)
|
|
271
|
+
├── icons/ # Icon components
|
|
354
272
|
├── layout/ # Layout components (Navbar, Footer)
|
|
355
273
|
└── [feature]/ # Feature-specific components
|
|
356
274
|
```
|
|
357
275
|
|
|
358
|
-
### Configuration Files
|
|
359
|
-
```
|
|
360
|
-
src/config/
|
|
361
|
-
├── navigationUrls.ts # All navigation URLs
|
|
362
|
-
├── navigationItems.ts # Navigation menu items
|
|
363
|
-
├── menuOptions.ts # Dropdown/select options
|
|
364
|
-
└── images.ts # Centralized image paths (CRITICAL)
|
|
365
|
-
```
|
|
366
|
-
|
|
367
276
|
### Styling
|
|
368
277
|
- **Global styles**: `src/styles/globals.css`
|
|
369
|
-
- **Theme config**: `src/styles/hero.ts`
|
|
278
|
+
- **Theme config**: `src/styles/hero.ts`
|
|
370
279
|
- **Approach**: Tailwind CSS utility classes ONLY
|
|
371
280
|
- **NO CSS modules, NO styled-components, NO inline styles**
|
|
372
281
|
|
|
373
282
|
---
|
|
374
283
|
|
|
375
|
-
##
|
|
284
|
+
## 🎨 Available UI Components
|
|
376
285
|
|
|
377
|
-
###
|
|
286
|
+
### Navigation Components
|
|
378
287
|
|
|
379
|
-
|
|
288
|
+
#### Navbar (HeroUI)
|
|
289
|
+
**CRITICAL**: Always use HeroUI Navbar component for navigation bars:
|
|
380
290
|
|
|
381
291
|
```tsx
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
292
|
+
import {
|
|
293
|
+
Navbar,
|
|
294
|
+
NavbarBrand,
|
|
295
|
+
NavbarContent,
|
|
296
|
+
NavbarItem,
|
|
297
|
+
NavbarMenu,
|
|
298
|
+
NavbarMenuItem,
|
|
299
|
+
NavbarMenuToggle,
|
|
300
|
+
} from '@heroui/react';
|
|
301
|
+
import { Button } from '@/components/ui';
|
|
302
|
+
|
|
303
|
+
<Navbar maxWidth="full" className="bg-black border-b-2">
|
|
304
|
+
{/* Logo */}
|
|
305
|
+
<NavbarBrand as={Link} href="/">
|
|
306
|
+
<img src="/logo.svg" alt="Logo" />
|
|
307
|
+
</NavbarBrand>
|
|
385
308
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
309
|
+
{/* Desktop Menu */}
|
|
310
|
+
<NavbarContent className="hidden lg:flex" justify="center">
|
|
311
|
+
<NavbarItem>
|
|
312
|
+
<Button variant="light">Menu Item</Button> {/* size="md" omitted - it's default */}
|
|
313
|
+
</NavbarItem>
|
|
314
|
+
</NavbarContent>
|
|
389
315
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
316
|
+
{/* CTA */}
|
|
317
|
+
<NavbarContent className="hidden lg:flex" justify="end">
|
|
318
|
+
<NavbarItem>
|
|
319
|
+
<Button color="primary">CTA</Button> {/* size="md" omitted - it's default */}
|
|
320
|
+
</NavbarItem>
|
|
321
|
+
</NavbarContent>
|
|
394
322
|
|
|
395
|
-
|
|
396
|
-
|
|
323
|
+
{/* Mobile Toggle */}
|
|
324
|
+
<NavbarMenuToggle className="lg:hidden" />
|
|
325
|
+
|
|
326
|
+
{/* Mobile Menu */}
|
|
327
|
+
<NavbarMenu>
|
|
328
|
+
<NavbarMenuItem>
|
|
329
|
+
<Button variant="light" fullWidth>Menu Item</Button>
|
|
330
|
+
</NavbarMenuItem>
|
|
331
|
+
</NavbarMenu>
|
|
332
|
+
</Navbar>
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**Key Points**:
|
|
336
|
+
- ✅ Use `Navbar` from `@heroui/react`
|
|
337
|
+
- ✅ Use `Button` from `@/components/ui` for menu items
|
|
338
|
+
- ✅ Use props (`color`, `size`, `variant`) NOT className for styles
|
|
339
|
+
- ✅ className ONLY for layout (`hidden`, `lg:flex`, `bg-black`)
|
|
340
|
+
- ❌ DON'T use custom `<header>` or `<nav>` tags
|
|
341
|
+
|
|
342
|
+
### Form Components
|
|
343
|
+
All located in `src/components/ui/`:
|
|
344
|
+
|
|
345
|
+
#### Input Fields
|
|
346
|
+
```tsx
|
|
347
|
+
import { Input, PasswordInput, NumberInput, Textarea } from '@/components/ui';
|
|
348
|
+
|
|
349
|
+
// Text Input
|
|
350
|
+
<Input
|
|
351
|
+
label="Email"
|
|
352
|
+
placeholder="Enter your email"
|
|
353
|
+
type="email"
|
|
354
|
+
isRequired
|
|
355
|
+
/>
|
|
356
|
+
|
|
357
|
+
// Password Input (with show/hide toggle)
|
|
358
|
+
<PasswordInput
|
|
359
|
+
label="Password"
|
|
360
|
+
placeholder="Enter password"
|
|
361
|
+
isRequired
|
|
362
|
+
/>
|
|
363
|
+
|
|
364
|
+
// Number Input (with increment/decrement)
|
|
365
|
+
<NumberInput
|
|
366
|
+
label="Quantity"
|
|
367
|
+
min={1}
|
|
368
|
+
max={100}
|
|
369
|
+
defaultValue={1}
|
|
370
|
+
/>
|
|
397
371
|
|
|
398
|
-
//
|
|
399
|
-
<
|
|
400
|
-
|
|
401
|
-
|
|
372
|
+
// Textarea
|
|
373
|
+
<Textarea
|
|
374
|
+
label="Description"
|
|
375
|
+
placeholder="Enter description"
|
|
376
|
+
rows={4}
|
|
377
|
+
/>
|
|
402
378
|
```
|
|
403
379
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
- Easy to swap icons by changing name prop
|
|
408
|
-
- Consistent icon rendering
|
|
380
|
+
#### Selection Components
|
|
381
|
+
```tsx
|
|
382
|
+
import { Select, RadioGroup, Checkbox, Autocomplete } from '@/components/ui';
|
|
409
383
|
|
|
410
|
-
|
|
384
|
+
// Select Dropdown
|
|
385
|
+
<Select
|
|
386
|
+
label="Country"
|
|
387
|
+
placeholder="Select country"
|
|
388
|
+
items={countries}
|
|
389
|
+
/>
|
|
411
390
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
391
|
+
// Radio Group
|
|
392
|
+
<RadioGroup
|
|
393
|
+
label="Size"
|
|
394
|
+
options={[
|
|
395
|
+
{ value: 's', label: 'Small' },
|
|
396
|
+
{ value: 'm', label: 'Medium' },
|
|
397
|
+
{ value: 'l', label: 'Large' },
|
|
398
|
+
]}
|
|
399
|
+
/>
|
|
416
400
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
mv downloaded-icon.svg src/assets/icons/icon-name.svg
|
|
420
|
-
```
|
|
401
|
+
// Checkbox
|
|
402
|
+
<Checkbox>I agree to terms</Checkbox>
|
|
421
403
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
404
|
+
// Autocomplete (with search)
|
|
405
|
+
<Autocomplete
|
|
406
|
+
label="Search"
|
|
407
|
+
items={suggestions}
|
|
408
|
+
placeholder="Type to search..."
|
|
409
|
+
/>
|
|
410
|
+
```
|
|
426
411
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
- Auto-format and lint the generated code
|
|
431
|
-
- Update `src/components/icons/index.ts` with exports
|
|
412
|
+
#### Date & Time
|
|
413
|
+
```tsx
|
|
414
|
+
import { DatePicker } from '@/components/ui';
|
|
432
415
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
416
|
+
<DatePicker
|
|
417
|
+
label="Select Date"
|
|
418
|
+
placeholderValue={new CalendarDate(2024, 1, 1)}
|
|
419
|
+
/>
|
|
420
|
+
```
|
|
436
421
|
|
|
437
|
-
|
|
438
|
-
|
|
422
|
+
#### Buttons
|
|
423
|
+
```tsx
|
|
424
|
+
import { Button } from '@/components/ui';
|
|
439
425
|
|
|
440
|
-
|
|
426
|
+
<Button color="primary"> {/* size="md" omitted - it's default */}
|
|
427
|
+
Submit
|
|
428
|
+
</Button>
|
|
441
429
|
|
|
442
|
-
|
|
430
|
+
<Button color="secondary" variant="bordered">
|
|
431
|
+
Cancel
|
|
432
|
+
</Button>
|
|
433
|
+
|
|
434
|
+
<Button isLoading>
|
|
435
|
+
Processing...
|
|
436
|
+
</Button>
|
|
437
|
+
```
|
|
443
438
|
|
|
439
|
+
#### Other Components
|
|
444
440
|
```tsx
|
|
445
|
-
import {
|
|
441
|
+
import { Modal, Chip, Breadcrumbs, Tabs, Icon } from '@/components/ui';
|
|
446
442
|
|
|
447
|
-
|
|
448
|
-
<
|
|
443
|
+
// Modal
|
|
444
|
+
<Modal
|
|
445
|
+
isOpen={isOpen}
|
|
446
|
+
onClose={onClose}
|
|
447
|
+
title="Modal Title"
|
|
448
|
+
>
|
|
449
|
+
Modal content
|
|
450
|
+
</Modal>
|
|
451
|
+
|
|
452
|
+
// Chip (badges/tags)
|
|
453
|
+
<Chip color="success" variant="flat">
|
|
454
|
+
Active
|
|
455
|
+
</Chip>
|
|
456
|
+
|
|
457
|
+
// Breadcrumbs
|
|
458
|
+
<Breadcrumbs
|
|
459
|
+
items={[
|
|
460
|
+
{ label: 'Home', href: '/' },
|
|
461
|
+
{ label: 'Products', href: '/products' },
|
|
462
|
+
]}
|
|
463
|
+
/>
|
|
464
|
+
|
|
465
|
+
// Tabs
|
|
466
|
+
<Tabs
|
|
467
|
+
items={[
|
|
468
|
+
{ key: 'tab1', label: 'Tab 1', content: <div>Content 1</div> },
|
|
469
|
+
{ key: 'tab2', label: 'Tab 2', content: <div>Content 2</div> },
|
|
470
|
+
]}
|
|
471
|
+
/>
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### Icons
|
|
475
|
+
|
|
476
|
+
**CRITICAL WORKFLOW**: Icons must follow this exact process:
|
|
477
|
+
|
|
478
|
+
#### Step 1: Export SVG from Figma
|
|
479
|
+
1. Select the icon in Figma design
|
|
480
|
+
2. Export as SVG (not PNG/JPG)
|
|
481
|
+
3. Download the SVG file
|
|
482
|
+
|
|
483
|
+
#### Step 2: Place in Icons Folder
|
|
484
|
+
```bash
|
|
485
|
+
# Place SVG file in src/assets/icons/
|
|
486
|
+
mv downloaded-icon.svg src/assets/icons/icon-name.svg
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
#### Step 3: Generate React Components
|
|
490
|
+
```bash
|
|
491
|
+
# Run the icon generation script
|
|
492
|
+
pnpm generate-icons
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
This command will:
|
|
496
|
+
- Convert all SVG files in `src/assets/icons/` to React components
|
|
497
|
+
- Place them in `src/components/icons/`
|
|
498
|
+
- Auto-format and lint the generated code
|
|
499
|
+
- Update `src/components/icons/index.ts` with exports
|
|
500
|
+
|
|
501
|
+
#### Step 4: Use in Code
|
|
502
|
+
|
|
503
|
+
**CORRECT USAGE**: Use the `Icon` component with `name` prop (PascalCase):
|
|
504
|
+
|
|
505
|
+
```tsx
|
|
506
|
+
import { Icon } from '@/components/ui';
|
|
507
|
+
|
|
508
|
+
// ✅ CORRECT - Using Icon component with PascalCase name
|
|
509
|
+
<Icon name="ChevronDownIcon" className="size-5 text-white" />
|
|
510
|
+
<Icon name="CloseIcon" className="size-4" />
|
|
511
|
+
<Icon name="EyeIcon" className="size-6" />
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
**❌ WRONG USAGE - DO NOT import individual icon components**:
|
|
515
|
+
```tsx
|
|
516
|
+
// ❌ WRONG - Don't import and use individual icon components
|
|
517
|
+
import { ChevronDownIcon, CloseIcon } from '@/components/icons';
|
|
518
|
+
<ChevronDownIcon className="size-5" />
|
|
519
|
+
<CloseIcon className="size-4" />
|
|
449
520
|
```
|
|
450
521
|
|
|
451
522
|
**Available Icons** (auto-generated):
|
|
@@ -457,82 +528,75 @@ import { ChevronDownIcon, MenuIcon } from '@/components/icons';
|
|
|
457
528
|
- DotsVerticalIcon, FrameIcon
|
|
458
529
|
- And more...
|
|
459
530
|
|
|
531
|
+
**Icon Names**:
|
|
532
|
+
- Icon names are PascalCase with "Icon" suffix (e.g., `ChevronDownIcon`)
|
|
533
|
+
- Generated from SVG filename: `chevron-down.svg` → component `ChevronDownIcon`
|
|
534
|
+
- The Icon component uses the exact component name from `@/components/icons`
|
|
535
|
+
|
|
460
536
|
**❌ DO NOT**:
|
|
537
|
+
- Import individual icon components directly
|
|
538
|
+
- Use kebab-case names (use `ChevronDownIcon` not `chevron-down`)
|
|
461
539
|
- Use Lucide, Font Awesome, or other icon libraries
|
|
462
540
|
- Create manual icon components
|
|
463
541
|
- Use `<img>` tags for icons
|
|
464
542
|
- Hardcode SVG paths directly in components
|
|
465
|
-
- Edit files in `src/components/icons/` manually (they are auto-generated)
|
|
466
543
|
|
|
467
544
|
**✅ DO**:
|
|
545
|
+
- Always use `<Icon name="IconName" />` pattern with PascalCase
|
|
468
546
|
- Always export from Figma as SVG
|
|
469
547
|
- Use `pnpm generate-icons` to create components
|
|
470
|
-
- Use `<Icon name="IconName" />` pattern for cleaner code
|
|
471
548
|
- Use Tailwind classes for sizing (`size-4`, `size-5`, `size-6`)
|
|
472
|
-
- Organize icons in `src/assets/icons/` with descriptive names
|
|
473
549
|
|
|
474
|
-
|
|
550
|
+
### Logos & Images
|
|
475
551
|
|
|
476
|
-
|
|
552
|
+
**CRITICAL WORKFLOW**: Logos and images must be placed in `public/` directory:
|
|
477
553
|
|
|
478
|
-
|
|
554
|
+
#### Step 1: Check Existing Images First
|
|
479
555
|
|
|
480
|
-
**
|
|
556
|
+
**BEFORE implementing or exporting from Figma**:
|
|
557
|
+
1. Check `public/images/index.ts` to see if the image/logo already exists
|
|
558
|
+
2. Check `public/images/logos/` directory for available logo files
|
|
559
|
+
3. Only export from Figma if the asset doesn't exist
|
|
481
560
|
|
|
561
|
+
```bash
|
|
562
|
+
# Check what images are available
|
|
563
|
+
cat public/images/index.ts
|
|
564
|
+
ls public/images/logos/
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**Why this matters**:
|
|
568
|
+
- Avoid duplicate assets
|
|
569
|
+
- User may have already exported the assets
|
|
570
|
+
- Maintain consistency with existing naming conventions
|
|
571
|
+
|
|
572
|
+
#### Step 2: Export from Figma (if needed)
|
|
482
573
|
1. **For logos**: Export as SVG (preferred) or PNG if source is raster
|
|
483
574
|
2. **For images**: Export as PNG, JPG, or WebP based on image type
|
|
484
575
|
3. Use appropriate resolution (2x or 3x for retina displays)
|
|
485
576
|
|
|
486
|
-
|
|
487
|
-
|
|
577
|
+
#### Step 3: Place in Public Folder
|
|
488
578
|
```bash
|
|
579
|
+
# Place logo/image files in public/
|
|
489
580
|
public/
|
|
581
|
+
├── logo.svg # Main logo (SVG preferred)
|
|
582
|
+
├── logo-dark.svg # Dark mode logo
|
|
583
|
+
├── logo.png # Fallback PNG
|
|
584
|
+
├── favicon.ico
|
|
490
585
|
└── images/
|
|
491
|
-
├──
|
|
492
|
-
|
|
493
|
-
│ ├── logo-circle-secondary.svg
|
|
494
|
-
│ ├── logo-full.svg
|
|
495
|
-
│ ├── logo-full-black.svg
|
|
496
|
-
│ ├── logo-full-white.svg
|
|
497
|
-
│ └── logo-icon.svg
|
|
498
|
-
├── auth/
|
|
499
|
-
│ ├── login-background.jpg
|
|
500
|
-
│ ├── signup-background.jpg
|
|
501
|
-
│ └── reset-password.jpg
|
|
502
|
-
├── website/
|
|
503
|
-
│ ├── home-hero.webp
|
|
504
|
-
│ ├── home-newsletter.webp
|
|
505
|
-
│ ├── about-header.jpg
|
|
506
|
-
│ └── contact-map.png
|
|
507
|
-
├── services/
|
|
508
|
-
│ ├── services-header.webp
|
|
509
|
-
│ ├── feature-1.jpg
|
|
510
|
-
│ └── feature-2.jpg
|
|
511
|
-
└── products/
|
|
512
|
-
├── thumbnail-default.png
|
|
513
|
-
└── hero-banner.jpg
|
|
586
|
+
├── hero-bg.jpg
|
|
587
|
+
└── product-1.png
|
|
514
588
|
```
|
|
515
589
|
|
|
516
|
-
|
|
590
|
+
#### Step 4: Create Centralized Image Constants
|
|
517
591
|
|
|
518
|
-
**CRITICAL**:
|
|
592
|
+
**CRITICAL**: Create a centralized constants file for all image paths:
|
|
519
593
|
|
|
520
594
|
```typescript
|
|
521
595
|
// src/config/images.ts
|
|
522
596
|
|
|
523
597
|
/**
|
|
524
598
|
* Centralized image path constants
|
|
525
|
-
*
|
|
526
|
-
* CRITICAL RULES:
|
|
527
|
-
* 1. ALL image paths MUST be defined here
|
|
528
|
-
* 2. Organize by category (LOGOS, AUTH, WEBSITE, SERVICES, etc.)
|
|
529
|
-
* 3. Use descriptive UPPER_SNAKE_CASE names
|
|
530
|
-
* 4. Add `as const` for type safety
|
|
531
|
-
* 5. NEVER hardcode image paths in components
|
|
532
|
-
*
|
|
533
|
-
* Usage:
|
|
534
|
-
* import { IMAGES } from '@/config/images';
|
|
535
|
-
* <img src={IMAGES.LOGOS.PRIMARY_CIRCLE} alt="Logo" />
|
|
599
|
+
* Organize by category: LOGOS, AUTH, WEBSITE, SERVICES, etc.
|
|
536
600
|
*/
|
|
537
601
|
|
|
538
602
|
const LOGOS = {
|
|
@@ -577,13 +641,14 @@ export const IMAGES = {
|
|
|
577
641
|
} as const;
|
|
578
642
|
```
|
|
579
643
|
|
|
580
|
-
|
|
644
|
+
#### Step 5: Reference in Code
|
|
581
645
|
|
|
582
646
|
```tsx
|
|
647
|
+
// Import from centralized constants
|
|
583
648
|
import { IMAGES } from '@/config/images';
|
|
584
649
|
import Image from 'next/image';
|
|
585
650
|
|
|
586
|
-
//
|
|
651
|
+
// Using Next.js Image component (recommended)
|
|
587
652
|
<Image
|
|
588
653
|
src={IMAGES.LOGOS.FULL}
|
|
589
654
|
alt="Company Logo"
|
|
@@ -592,88 +657,147 @@ import Image from 'next/image';
|
|
|
592
657
|
priority
|
|
593
658
|
/>
|
|
594
659
|
|
|
595
|
-
//
|
|
660
|
+
// Using standard img tag (for SVGs with CSS control)
|
|
596
661
|
<img src={IMAGES.LOGOS.PRIMARY_CIRCLE} alt="Logo" className="h-10 w-auto" />
|
|
597
662
|
|
|
598
|
-
//
|
|
599
|
-
<div
|
|
600
|
-
className="bg-cover bg-center"
|
|
601
|
-
style={{ backgroundImage: `url(${IMAGES.WEBSITE.HOME_HERO})` }}
|
|
602
|
-
>
|
|
663
|
+
// Background images via Tailwind
|
|
664
|
+
<div className={`bg-[url('${IMAGES.WEBSITE.HOME_HERO}')] bg-cover bg-center`}>
|
|
603
665
|
|
|
604
|
-
//
|
|
666
|
+
// In authentication pages
|
|
605
667
|
<Image
|
|
606
668
|
src={IMAGES.AUTH.LOGIN_BG}
|
|
607
669
|
alt="Login background"
|
|
608
670
|
fill
|
|
609
671
|
className="object-cover"
|
|
610
672
|
/>
|
|
611
|
-
|
|
612
|
-
// ✅ In service pages
|
|
613
|
-
<Image
|
|
614
|
-
src={IMAGES.SERVICES.HEADER}
|
|
615
|
-
alt="Services"
|
|
616
|
-
width={1920}
|
|
617
|
-
height={600}
|
|
618
|
-
className="w-full"
|
|
619
|
-
/>
|
|
620
673
|
```
|
|
621
674
|
|
|
622
|
-
|
|
623
|
-
|
|
675
|
+
**Preference Order**:
|
|
624
676
|
1. ✅ **SVG** - Best for logos, icons, and vector graphics (scalable, small file size)
|
|
625
|
-
2. ✅ **WebP** - Modern format for photos (
|
|
677
|
+
2. ✅ **WebP** - Modern format for photos (smaller than PNG/JPG)
|
|
626
678
|
3. ✅ **PNG** - For images requiring transparency
|
|
627
679
|
4. ✅ **JPG** - For photos without transparency
|
|
628
680
|
|
|
629
|
-
### CRITICAL: Check Before Export Workflow
|
|
630
|
-
|
|
631
|
-
Before exporting any logo or image from Figma:
|
|
632
|
-
|
|
633
|
-
1. **Check if it already exists** in `public/images/`
|
|
634
|
-
2. **Check if it's already defined** in `src/config/images.ts`
|
|
635
|
-
3. **Use existing constant** if available
|
|
636
|
-
4. **Only export and add new** if it doesn't exist
|
|
637
|
-
|
|
638
|
-
This prevents:
|
|
639
|
-
- Duplicate images in the project
|
|
640
|
-
- Inconsistent image usage
|
|
641
|
-
- Bloated public folder
|
|
642
|
-
- Broken image references
|
|
643
|
-
|
|
644
|
-
**Example**:
|
|
645
|
-
```tsx
|
|
646
|
-
// ❌ WRONG - Exporting logo that already exists
|
|
647
|
-
// User asks: "Add company logo to header"
|
|
648
|
-
// You: Export logo from Figma, add to public/, create new constant
|
|
649
|
-
|
|
650
|
-
// ✅ CORRECT - Check first, then use existing
|
|
651
|
-
// 1. Check src/config/images.ts
|
|
652
|
-
// 2. See IMAGES.LOGOS.FULL already exists
|
|
653
|
-
// 3. Use it: <img src={IMAGES.LOGOS.FULL} alt="Logo" />
|
|
654
|
-
```
|
|
655
|
-
|
|
656
681
|
**❌ DO NOT**:
|
|
657
682
|
- Put images in `src/` folder
|
|
658
683
|
- Import images as modules unless necessary
|
|
659
684
|
- Use base64 encoded images inline
|
|
660
685
|
- Forget to optimize images before adding
|
|
661
|
-
-
|
|
662
|
-
- Export images that already exist in the project
|
|
686
|
+
- Hardcode image paths directly in components (use centralized constants)
|
|
663
687
|
|
|
664
688
|
**✅ DO**:
|
|
665
|
-
- Always place
|
|
666
|
-
-
|
|
667
|
-
- Organize image paths by category (LOGOS, AUTH, WEBSITE, SERVICES
|
|
689
|
+
- Always place in `public/` directory
|
|
690
|
+
- Create centralized image constants file (src/config/images.ts)
|
|
691
|
+
- Organize image paths by category (LOGOS, AUTH, WEBSITE, SERVICES)
|
|
668
692
|
- Use `as const` for type safety
|
|
669
|
-
- Import from `@/config/images` in
|
|
670
|
-
- Check if image exists before exporting from Figma
|
|
693
|
+
- Import from `@/config/images` in components
|
|
671
694
|
- Prefer SVG for logos and icons
|
|
672
695
|
- Optimize images before adding (use tools like ImageOptim, Squoosh)
|
|
673
696
|
- Use Next.js `<Image>` component for automatic optimization
|
|
674
697
|
|
|
675
698
|
---
|
|
676
699
|
|
|
700
|
+
## 🎨 Color Palette & Theme
|
|
701
|
+
|
|
702
|
+
### CRITICAL: Use Theme Colors, NOT Custom Values
|
|
703
|
+
|
|
704
|
+
**Colors are defined in two places**:
|
|
705
|
+
1. **`src/styles/hero.ts`** - HeroUI theme colors (primary, secondary, etc.)
|
|
706
|
+
2. **`src/styles/globals.css`** - Additional custom theme colors
|
|
707
|
+
|
|
708
|
+
### Available Theme Colors
|
|
709
|
+
|
|
710
|
+
#### From hero.ts (Primary Color Palette):
|
|
711
|
+
```typescript
|
|
712
|
+
// Primary green shades (defined in hero.ts)
|
|
713
|
+
primary-50 // #E6FFF0 (lightest)
|
|
714
|
+
primary-100 // #CBFFE0
|
|
715
|
+
primary-200 // #AEFFD1
|
|
716
|
+
primary-300 // #8EFFC2
|
|
717
|
+
primary-400 // #66FFB2
|
|
718
|
+
primary-500 // #19FFA3 (default primary)
|
|
719
|
+
primary-600 // #25C780
|
|
720
|
+
primary-700 // #26915F
|
|
721
|
+
primary-800 // #215F40
|
|
722
|
+
primary-900 // #173123 (darkest)
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
#### HeroUI Default Colors:
|
|
726
|
+
```tsx
|
|
727
|
+
// Semantic colors (built into HeroUI)
|
|
728
|
+
bg-primary text-primary border-primary
|
|
729
|
+
bg-secondary text-secondary border-secondary
|
|
730
|
+
bg-success text-success border-success
|
|
731
|
+
bg-danger text-danger border-danger
|
|
732
|
+
bg-warning text-warning border-warning
|
|
733
|
+
bg-default text-default border-default
|
|
734
|
+
bg-foreground text-foreground border-foreground
|
|
735
|
+
bg-background text-background border-background
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
### Color Usage Examples
|
|
739
|
+
|
|
740
|
+
**✅ CORRECT - Use theme colors**:
|
|
741
|
+
```tsx
|
|
742
|
+
// In component configuration (NO hover states)
|
|
743
|
+
color: {
|
|
744
|
+
primary: 'bg-primary text-black',
|
|
745
|
+
success: 'bg-success text-white',
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// In className (for text colors, borders, etc.)
|
|
749
|
+
className="text-primary border-primary-500"
|
|
750
|
+
className="bg-primary-50 text-primary-900"
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
**❌ WRONG - Custom color values or hover states**:
|
|
754
|
+
```tsx
|
|
755
|
+
// DON'T use hex values or hover states in config
|
|
756
|
+
color: {
|
|
757
|
+
primary: 'bg-[#19ffa3] text-black hover:bg-[#00e68a]',
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// DON'T use rgb/hsl
|
|
761
|
+
className="bg-[rgb(25,255,163)]"
|
|
762
|
+
className="text-[hsl(155,100%,56%)]"
|
|
763
|
+
|
|
764
|
+
// DON'T use hover states in component config
|
|
765
|
+
color: {
|
|
766
|
+
primary: 'bg-primary text-black hover:bg-primary-600', // HeroUI handles hover
|
|
767
|
+
}
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
### When to Add Custom Colors
|
|
771
|
+
|
|
772
|
+
**Only add custom colors to hero.ts if**:
|
|
773
|
+
1. Color is NOT in the existing palette
|
|
774
|
+
2. Color is used in multiple places (reusable)
|
|
775
|
+
3. Color is part of the design system
|
|
776
|
+
|
|
777
|
+
**Steps to add custom color**:
|
|
778
|
+
```typescript
|
|
779
|
+
// 1. Add to hero.ts theme
|
|
780
|
+
export default heroui({
|
|
781
|
+
themes: {
|
|
782
|
+
extend: {
|
|
783
|
+
colors: {
|
|
784
|
+
// Add new color palette
|
|
785
|
+
accent: {
|
|
786
|
+
50: '#...',
|
|
787
|
+
500: '#...',
|
|
788
|
+
900: '#...',
|
|
789
|
+
},
|
|
790
|
+
},
|
|
791
|
+
},
|
|
792
|
+
},
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
// 2. Use in components
|
|
796
|
+
className="bg-accent text-accent-900"
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
---
|
|
800
|
+
|
|
677
801
|
## 🎨 Tailwind CSS Guidelines
|
|
678
802
|
|
|
679
803
|
### Using Standard Tailwind Classes
|
|
@@ -723,6 +847,15 @@ auto, full, screen, fit, min, max
|
|
|
723
847
|
- No standard Tailwind class is close enough
|
|
724
848
|
- Using design tokens/CSS variables: `bg-[var(--custom-color)]`
|
|
725
849
|
|
|
850
|
+
**Examples**:
|
|
851
|
+
```tsx
|
|
852
|
+
// ✅ Good - Using standard classes
|
|
853
|
+
<div className="h-10 w-full p-6 text-sm">
|
|
854
|
+
|
|
855
|
+
// ❌ Bad - Should use standard classes
|
|
856
|
+
<div className="h-[40px] w-[100%] p-[24px] text-[14px]">
|
|
857
|
+
```
|
|
858
|
+
|
|
726
859
|
### Responsive Breakpoints (Mobile-First)
|
|
727
860
|
```css
|
|
728
861
|
/* Mobile */
|
|
@@ -743,19 +876,108 @@ xl: 1280px /* MacBook Air */
|
|
|
743
876
|
4xl: 1728px /* MacBook Pro 16" */
|
|
744
877
|
```
|
|
745
878
|
|
|
746
|
-
###
|
|
879
|
+
### Usage Example
|
|
880
|
+
```tsx
|
|
881
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
882
|
+
{/* Mobile: 1 column, Tablet: 2 columns, Desktop: 3 columns */}
|
|
883
|
+
</div>
|
|
884
|
+
```
|
|
747
885
|
|
|
886
|
+
### HeroUI Color System
|
|
748
887
|
Use these semantic colors from HeroUI theme:
|
|
749
888
|
- `bg-background` - Main background
|
|
750
889
|
- `bg-foreground` - Text color background
|
|
751
890
|
- `bg-default` / `bg-default-50` to `bg-default-900` - Gray scale
|
|
752
|
-
- `bg-primary` / `text-primary` - Primary brand color
|
|
753
|
-
- `bg-primary-50` to `bg-primary-900` - Primary color shades
|
|
891
|
+
- `bg-primary` / `text-primary` - Primary brand color
|
|
754
892
|
- `bg-secondary` - Secondary color
|
|
755
893
|
- `bg-success` - Success states
|
|
756
894
|
- `bg-warning` - Warning states
|
|
757
895
|
- `bg-danger` - Error/danger states
|
|
758
896
|
|
|
897
|
+
### Common Patterns
|
|
898
|
+
```tsx
|
|
899
|
+
// Card
|
|
900
|
+
<div className="rounded-lg bg-white p-6 shadow-md">
|
|
901
|
+
|
|
902
|
+
// Container
|
|
903
|
+
<div className="container mx-auto px-4">
|
|
904
|
+
|
|
905
|
+
// Flexbox centering
|
|
906
|
+
<div className="flex items-center justify-center">
|
|
907
|
+
|
|
908
|
+
// Grid layout
|
|
909
|
+
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
910
|
+
|
|
911
|
+
// Spacing
|
|
912
|
+
<div className="space-y-4"> {/* Vertical spacing */}
|
|
913
|
+
<div className="space-x-4"> {/* Horizontal spacing */}
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
---
|
|
917
|
+
|
|
918
|
+
## 📝 Form Implementation with Zod
|
|
919
|
+
|
|
920
|
+
### Pattern to Follow
|
|
921
|
+
```tsx
|
|
922
|
+
'use client';
|
|
923
|
+
|
|
924
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
925
|
+
import { useForm } from 'react-hook-form';
|
|
926
|
+
import { z } from 'zod';
|
|
927
|
+
|
|
928
|
+
import { Button, Input } from '@/components/ui';
|
|
929
|
+
|
|
930
|
+
// 1. Define schema
|
|
931
|
+
const schema = z.object({
|
|
932
|
+
email: z.string().email('Invalid email'),
|
|
933
|
+
password: z.string().min(8, 'Password must be at least 8 characters'),
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
type FormData = z.infer<typeof schema>;
|
|
937
|
+
|
|
938
|
+
export default function LoginForm() {
|
|
939
|
+
// 2. Setup form
|
|
940
|
+
const {
|
|
941
|
+
register,
|
|
942
|
+
handleSubmit,
|
|
943
|
+
formState: { errors, isSubmitting },
|
|
944
|
+
} = useForm<FormData>({
|
|
945
|
+
resolver: zodResolver(schema),
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
// 3. Submit handler
|
|
949
|
+
const onSubmit = async (data: FormData) => {
|
|
950
|
+
// Handle form submission
|
|
951
|
+
console.log(data);
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
// 4. Render form
|
|
955
|
+
return (
|
|
956
|
+
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
|
957
|
+
<Input
|
|
958
|
+
label="Email"
|
|
959
|
+
type="email"
|
|
960
|
+
{...register('email')}
|
|
961
|
+
errorMessage={errors.email?.message}
|
|
962
|
+
isInvalid={!!errors.email}
|
|
963
|
+
/>
|
|
964
|
+
|
|
965
|
+
<Input
|
|
966
|
+
label="Password"
|
|
967
|
+
type="password"
|
|
968
|
+
{...register('password')}
|
|
969
|
+
errorMessage={errors.password?.message}
|
|
970
|
+
isInvalid={!!errors.password}
|
|
971
|
+
/>
|
|
972
|
+
|
|
973
|
+
<Button type="submit" isLoading={isSubmitting} className="w-full">
|
|
974
|
+
Submit
|
|
975
|
+
</Button>
|
|
976
|
+
</form>
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
```
|
|
980
|
+
|
|
759
981
|
---
|
|
760
982
|
|
|
761
983
|
## 🌐 Internationalization (i18n)
|
|
@@ -792,6 +1014,24 @@ import { Link } from '@heroui/react';
|
|
|
792
1014
|
<Link href={NAVIGATION_URLS.ABOUT}>About</Link>
|
|
793
1015
|
```
|
|
794
1016
|
|
|
1017
|
+
**Using Navigation Hooks**:
|
|
1018
|
+
```tsx
|
|
1019
|
+
'use client';
|
|
1020
|
+
|
|
1021
|
+
import { usePathname, useRouter } from 'next/navigation';
|
|
1022
|
+
|
|
1023
|
+
export function MyComponent() {
|
|
1024
|
+
const pathname = usePathname();
|
|
1025
|
+
const router = useRouter();
|
|
1026
|
+
|
|
1027
|
+
const handleNavigation = () => {
|
|
1028
|
+
router.push(NAVIGATION_URLS.DASHBOARD.INDEX);
|
|
1029
|
+
};
|
|
1030
|
+
|
|
1031
|
+
return <button onClick={handleNavigation}>Go to Dashboard</button>;
|
|
1032
|
+
}
|
|
1033
|
+
```
|
|
1034
|
+
|
|
795
1035
|
### Translations for ALL text
|
|
796
1036
|
```tsx
|
|
797
1037
|
import { useTranslations } from 'next-intl';
|
|
@@ -812,33 +1052,155 @@ function MyComponent() {
|
|
|
812
1052
|
}
|
|
813
1053
|
```
|
|
814
1054
|
|
|
1055
|
+
### Form labels, placeholders, errors - ALL must use i18n
|
|
1056
|
+
```tsx
|
|
1057
|
+
import { useTranslations } from 'next-intl';
|
|
1058
|
+
|
|
1059
|
+
function LoginForm() {
|
|
1060
|
+
const t = useTranslations();
|
|
1061
|
+
|
|
1062
|
+
return (
|
|
1063
|
+
<form>
|
|
1064
|
+
{/* ✅ CORRECT */}
|
|
1065
|
+
<Input
|
|
1066
|
+
label={t('email')}
|
|
1067
|
+
placeholder={t('enterEmail')}
|
|
1068
|
+
errorMessage={errors.email?.message ? t(errors.email.message) : undefined}
|
|
1069
|
+
/>
|
|
1070
|
+
|
|
1071
|
+
{/* ❌ WRONG - Hardcoded text */}
|
|
1072
|
+
<Input
|
|
1073
|
+
label="Email"
|
|
1074
|
+
placeholder="Enter your email"
|
|
1075
|
+
errorMessage="Invalid email"
|
|
1076
|
+
/>
|
|
1077
|
+
</form>
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
### Navigation URLs Reference
|
|
1083
|
+
```tsx
|
|
1084
|
+
import { NAVIGATION_URLS } from '@/config/navigationUrls';
|
|
1085
|
+
|
|
1086
|
+
// Available URLs (based on project type):
|
|
1087
|
+
NAVIGATION_URLS.ROOT // '/'
|
|
1088
|
+
NAVIGATION_URLS.ABOUT // '/about'
|
|
1089
|
+
NAVIGATION_URLS.CONTACT // '/contact'
|
|
1090
|
+
NAVIGATION_URLS.PRODUCTS.INDEX // '/products'
|
|
1091
|
+
NAVIGATION_URLS.PRODUCTS.DETAIL('123') // '/products/123'
|
|
1092
|
+
NAVIGATION_URLS.AUTH.LOGIN // '/auth/login'
|
|
1093
|
+
NAVIGATION_URLS.DASHBOARD.INDEX // '/dashboard'
|
|
1094
|
+
|
|
1095
|
+
// ✅ ALWAYS use NAVIGATION_URLS
|
|
1096
|
+
<Link href={NAVIGATION_URLS.PRODUCTS.INDEX}>Products</Link>
|
|
1097
|
+
|
|
1098
|
+
// ❌ NEVER hardcode URLs
|
|
1099
|
+
<Link href="/products">Products</Link>
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
---
|
|
1103
|
+
|
|
1104
|
+
## 🎯 Data Fetching
|
|
1105
|
+
|
|
1106
|
+
### Using React Query
|
|
1107
|
+
```tsx
|
|
1108
|
+
'use client';
|
|
1109
|
+
|
|
1110
|
+
import { useQuery } from '@tanstack/react-query';
|
|
1111
|
+
import axios from 'axios';
|
|
1112
|
+
|
|
1113
|
+
import { QUERY_KEYS } from '@/libs/react-query';
|
|
1114
|
+
|
|
1115
|
+
export default function ProductList() {
|
|
1116
|
+
const { data, isLoading, error } = useQuery({
|
|
1117
|
+
queryKey: QUERY_KEYS.PRODUCTS.LIST,
|
|
1118
|
+
queryFn: async () => {
|
|
1119
|
+
const response = await axios.get('/api/products');
|
|
1120
|
+
return response.data;
|
|
1121
|
+
},
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1124
|
+
if (isLoading) return <div>Loading...</div>;
|
|
1125
|
+
if (error) return <div>Error loading products</div>;
|
|
1126
|
+
|
|
1127
|
+
return (
|
|
1128
|
+
<div>
|
|
1129
|
+
{data.map((product) => (
|
|
1130
|
+
<div key={product.id}>{product.name}</div>
|
|
1131
|
+
))}
|
|
1132
|
+
</div>
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
```
|
|
1136
|
+
|
|
1137
|
+
---
|
|
1138
|
+
|
|
1139
|
+
## 📐 Layout Components
|
|
1140
|
+
|
|
1141
|
+
### Using Existing Layouts
|
|
1142
|
+
```tsx
|
|
1143
|
+
// Auth pages use auth layout automatically
|
|
1144
|
+
// Location: src/app/[locale]/(auth)/login/page.tsx
|
|
1145
|
+
|
|
1146
|
+
'use client';
|
|
1147
|
+
|
|
1148
|
+
export default function LoginPage() {
|
|
1149
|
+
return (
|
|
1150
|
+
<div className="w-full max-w-md space-y-6 rounded-lg bg-white p-8 shadow-md">
|
|
1151
|
+
<h1 className="text-center text-2xl font-bold">Login</h1>
|
|
1152
|
+
{/* Your form here */}
|
|
1153
|
+
</div>
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1156
|
+
```
|
|
1157
|
+
|
|
1158
|
+
### Navbar & Footer
|
|
1159
|
+
Already implemented in `src/components/layout/`:
|
|
1160
|
+
- `Navbar.tsx` - Main navigation using HeroUI Navbar
|
|
1161
|
+
- `Footer.tsx` - Footer component
|
|
1162
|
+
|
|
1163
|
+
**CRITICAL**: Navbar uses HeroUI Navbar component:
|
|
1164
|
+
```tsx
|
|
1165
|
+
import { Navbar } from '@/components/layout';
|
|
1166
|
+
|
|
1167
|
+
// In layout:
|
|
1168
|
+
<Navbar />
|
|
1169
|
+
<main>{children}</main>
|
|
1170
|
+
```
|
|
1171
|
+
|
|
1172
|
+
**Implementation details** (see `src/components/layout/Navbar.tsx`):
|
|
1173
|
+
- ✅ Uses HeroUI `Navbar`, `NavbarBrand`, `NavbarContent`, `NavbarItem`
|
|
1174
|
+
- ✅ Uses `Button` from `@/components/ui` with props (`color`, `size`, `variant`)
|
|
1175
|
+
- ✅ All styles via props, NO className for component styles
|
|
1176
|
+
- ✅ className ONLY for layout utilities
|
|
1177
|
+
|
|
815
1178
|
---
|
|
816
1179
|
|
|
817
1180
|
## ⚠️ CRITICAL RULES
|
|
818
1181
|
|
|
819
1182
|
### ❌ DO NOT
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
6. ❌ **Logos**: Put logos/images in `src/` folder - MUST go in `public/images/`
|
|
1183
|
+
1. ❌ **Figma**: Use screenshots to implement design - MUST use Figma MCP server with `get_design_context`
|
|
1184
|
+
2. ❌ **Figma**: Call `get_screenshot` tool - Design context provides all needed information
|
|
1185
|
+
3. ❌ **Icons**: Import individual icon components (e.g., `import { ChevronDownIcon }`) - MUST use `<Icon name="ChevronDownIcon" />`
|
|
1186
|
+
4. ❌ **Icons**: Create manual icon components - MUST use `pnpm generate-icons` workflow
|
|
1187
|
+
5. ❌ **Icons**: Use non-project icons (Lucide, Font Awesome, etc.)
|
|
1188
|
+
6. ❌ **Logos**: Put logos/images in `src/` folder - MUST go in `public/`
|
|
827
1189
|
7. ❌ **Logos**: Import images as modules unless necessary
|
|
828
|
-
8. ❌ **Logos**: Hardcode image paths in components - MUST use `@/config/images`
|
|
829
|
-
9. ❌ **
|
|
830
|
-
10. ❌ **
|
|
831
|
-
11. ❌ **Colors**:
|
|
832
|
-
12. ❌ **
|
|
833
|
-
13. ❌ **
|
|
834
|
-
14. ❌ **
|
|
835
|
-
15. ❌ **
|
|
836
|
-
16. ❌ **
|
|
837
|
-
17. ❌ **Components**:
|
|
838
|
-
18. ❌ **
|
|
839
|
-
19. ❌ **Styling**:
|
|
1190
|
+
8. ❌ **Logos**: Hardcode image paths in components - MUST use centralized constants from `@/config/images`
|
|
1191
|
+
9. ❌ **Tailwind**: Use arbitrary values when standard classes exist (e.g., `h-[40px]` → use `h-10`)
|
|
1192
|
+
10. ❌ **Tailwind**: Use custom values like `w-[100%]` (use `w-full`)
|
|
1193
|
+
11. ❌ **Colors**: Use custom color values (e.g., `bg-[#19ffa3]`, `text-[#ff0000]`) - MUST use theme colors from hero.ts
|
|
1194
|
+
12. ❌ **Colors**: Use hex, rgb, or hsl values inline - Use semantic color classes instead
|
|
1195
|
+
13. ❌ **Text**: Hardcode ANY text - ALL text MUST use i18n translation keys
|
|
1196
|
+
14. ❌ **URLs**: Hardcode URLs - ALWAYS use `NAVIGATION_URLS` from config
|
|
1197
|
+
15. ❌ **Data**: Hardcode menu items, dropdown options - MUST map from constants
|
|
1198
|
+
16. ❌ **Components**: Create custom components when HeroUI provides them (e.g., use HeroUI `Navbar` not custom `<header>`)
|
|
1199
|
+
17. ❌ **Components**: Use HTML elements when HeroUI component exists (e.g., `<button>` → use HeroUI `<Button>`)
|
|
1200
|
+
18. ❌ **Styling**: Apply component styles via className - MUST use props (`color`, `size`, `variant`, `radius`)
|
|
1201
|
+
19. ❌ **Styling**: Use className for component styles (e.g., `className="h-10 px-4 bg-primary"`) - Configure in wrapper instead
|
|
840
1202
|
20. ❌ **Styling**: Use CSS modules or styled-components - ONLY Tailwind CSS
|
|
841
|
-
21. ❌ **Imports**: Import from `@heroui/react` directly (use `@/components/ui` wrappers)
|
|
1203
|
+
21. ❌ **Imports**: Import from `@heroui/react` directly (use `@/components/ui` wrappers when available)
|
|
842
1204
|
22. ❌ **Navigation**: Use HeroUI `Link` for internal navigation (use Next.js `Link` from `next/link`)
|
|
843
1205
|
23. ❌ **Navigation**: Import `usePathname`, `useRouter` from wrong source (MUST use `next/navigation`)
|
|
844
1206
|
24. ❌ **TypeScript**: Use `any` type
|
|
@@ -846,43 +1208,38 @@ function MyComponent() {
|
|
|
846
1208
|
26. ❌ **Forms**: Skip form validation (always use Zod schemas)
|
|
847
1209
|
|
|
848
1210
|
### ✅ DO
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
32. ✅ **Design**: Follow mobile-first responsive design
|
|
882
|
-
33. ✅ **Design**: Implement responsive menu with HeroUI NavbarMenuToggle
|
|
883
|
-
34. ✅ **States**: Implement proper loading and error states
|
|
884
|
-
35. ✅ **Patterns**: Follow existing code patterns and naming conventions
|
|
885
|
-
36. ✅ **Patterns**: Use `as const` for type safety in constants
|
|
1211
|
+
1. ✅ **Figma**: Use Figma MCP server with `get_design_context` and node-id from Figma URL
|
|
1212
|
+
2. ✅ **Figma**: Extract node-id from URL (e.g., `node-id=8486-1580` → `"8486:1580"`)
|
|
1213
|
+
3. ✅ **Icons**: Export SVG from Figma → `src/assets/icons/` → Run `pnpm generate-icons`
|
|
1214
|
+
4. ✅ **Icons**: Use `<Icon name="IconName" />` pattern with PascalCase - NEVER import individual icon components
|
|
1215
|
+
5. ✅ **Logos**: Check `public/images/index.ts` BEFORE exporting from Figma
|
|
1216
|
+
6. ✅ **Logos**: Check `public/images/logos/` directory for existing assets
|
|
1217
|
+
7. ✅ **Logos**: Export SVG/PNG from Figma ONLY if not existing → Place in `public/images/` with organized folders
|
|
1218
|
+
8. ✅ **Logos**: Create centralized constants file `src/config/images.ts` with LOGOS, AUTH, WEBSITE, etc.
|
|
1219
|
+
9. ✅ **Logos**: Import from `@/config/images` and use `IMAGES.LOGOS.PRIMARY`
|
|
1220
|
+
10. ✅ **Logos**: Prefer SVG over PNG when source is vector
|
|
1221
|
+
11. ✅ **Tailwind**: Use standard classes (`h-10`, `p-6`, `text-sm` instead of arbitrary values)
|
|
1222
|
+
12. ✅ **Tailwind**: Use size utilities (`size-4`, `size-5`) for icons
|
|
1223
|
+
13. ✅ **Colors**: Use theme colors from hero.ts (`bg-primary`, `text-primary-600`, `bg-success`)
|
|
1224
|
+
14. ✅ **Colors**: Check hero.ts and globals.css for available colors before using custom values
|
|
1225
|
+
15. ✅ **Navigation**: Use Next.js `Link` from `next/link` for internal navigation
|
|
1226
|
+
16. ✅ **Navigation**: Import `usePathname`, `useRouter` from `next/navigation`
|
|
1227
|
+
17. ✅ **Text**: Use i18n translation keys for ALL text (`t('key')`)
|
|
1228
|
+
18. ✅ **URLs**: Use `NAVIGATION_URLS` for ALL navigation links
|
|
1229
|
+
19. ✅ **Data**: Map menu items, dropdown options from constants (never hardcode)
|
|
1230
|
+
20. ✅ **Components**: Use HeroUI components first (e.g., use `Navbar` from `@heroui/react` for navigation)
|
|
1231
|
+
21. ✅ **Components**: Use existing wrappers from `src/components/ui/` when available (e.g., `Button`)
|
|
1232
|
+
22. ✅ **Components**: Configure component styles in wrappers using `extendVariants`
|
|
1233
|
+
23. ✅ **Components**: Set `defaultVariants` in wrapper configuration to avoid repetition
|
|
1234
|
+
24. ✅ **Styling**: Use component props for styles, but ONLY specify non-default values
|
|
1235
|
+
25. ✅ **Styling**: Omit props that match defaultVariants (e.g., don't write `size="md"` if `md` is default)
|
|
1236
|
+
26. ✅ **Styling**: Use className ONLY for layout utilities (`mt-4`, `hidden`, `lg:flex`)
|
|
1237
|
+
27. ✅ **Styling**: Use Tailwind CSS ONLY (utility classes)
|
|
1238
|
+
28. ✅ **TypeScript**: Implement strict typing with proper types
|
|
1239
|
+
29. ✅ **React**: Use `'use client'` directive for interactive components
|
|
1240
|
+
30. ✅ **Design**: Follow mobile-first responsive design
|
|
1241
|
+
31. ✅ **States**: Implement proper loading and error states
|
|
1242
|
+
32. ✅ **Patterns**: Follow existing code patterns and naming conventions
|
|
886
1243
|
|
|
887
1244
|
---
|
|
888
1245
|
|
|
@@ -890,65 +1247,43 @@ function MyComponent() {
|
|
|
890
1247
|
|
|
891
1248
|
When converting Figma to code, ensure:
|
|
892
1249
|
|
|
893
|
-
### Figma Integration
|
|
894
|
-
- [ ] Used Figma MCP server to fetch design
|
|
895
|
-
- [ ] Analyzed all pages and components in Figma file
|
|
896
|
-
- [ ] Identified design tokens (colors, spacing, typography)
|
|
897
|
-
- [ ] Mapped Figma components to HeroUI components
|
|
898
|
-
- [ ] Extracted all necessary assets (icons, images)
|
|
899
|
-
|
|
900
1250
|
### Icons & Assets
|
|
901
1251
|
- [ ] Exported icons as SVG from Figma
|
|
902
1252
|
- [ ] Placed SVG files in `src/assets/icons/`
|
|
903
1253
|
- [ ] Ran `pnpm generate-icons` to create React components
|
|
904
|
-
- [ ]
|
|
905
|
-
- [ ] Checked
|
|
906
|
-
- [ ]
|
|
1254
|
+
- [ ] Imported icons from `@/components/icons`
|
|
1255
|
+
- [ ] **BEFORE exporting**: Checked `public/images/index.ts` for existing images/logos
|
|
1256
|
+
- [ ] **BEFORE exporting**: Checked `public/images/logos/` directory
|
|
1257
|
+
- [ ] Exported logos/images as SVG (preferred) or PNG (only if not existing)
|
|
907
1258
|
- [ ] Placed logos/images in `public/images/` with organized folders (logos/, auth/, website/, services/)
|
|
908
|
-
- [ ] Created
|
|
1259
|
+
- [ ] Created centralized constants file `src/config/images.ts`
|
|
909
1260
|
- [ ] Organized image paths by category (LOGOS, AUTH, WEBSITE, SERVICES, PRODUCTS)
|
|
910
1261
|
- [ ] Used `as const` for type safety
|
|
911
|
-
- [ ] Referenced via `IMAGES.
|
|
912
|
-
|
|
913
|
-
### Colors & Theme
|
|
914
|
-
- [ ] Used primary colors from theme (`bg-primary`, `bg-primary-600`)
|
|
915
|
-
- [ ] Applied correct color shades for states (hover, active, disabled)
|
|
916
|
-
- [ ] Followed HeroUI semantic colors (background, foreground, success, danger)
|
|
917
|
-
- [ ] No hardcoded hex values when theme colors available
|
|
1262
|
+
- [ ] Referenced via `IMAGES.LOGOS.PRIMARY` (not hardcoded paths)
|
|
918
1263
|
|
|
919
1264
|
### Component & Styling
|
|
920
1265
|
- [ ] Checked HeroUI library first for component availability
|
|
921
|
-
- [ ] Used HeroUI components via `src/components/ui/` wrappers
|
|
922
|
-
- [ ]
|
|
923
|
-
- [ ] Kept component usage clean (no repetitive className props)
|
|
1266
|
+
- [ ] Used HeroUI components via `src/components/ui/` wrappers (e.g., `<Button>` not `<button>`)
|
|
1267
|
+
- [ ] Configured component styles in wrapper/theme (not inline)
|
|
924
1268
|
- [ ] Used only layout utilities inline (`mt-4`, `hidden`, `lg:block`)
|
|
925
1269
|
- [ ] Applied Tailwind CSS classes only (no custom CSS, no CSS modules)
|
|
926
|
-
- [ ] Used standard Tailwind classes instead of arbitrary values
|
|
1270
|
+
- [ ] Used standard Tailwind classes instead of arbitrary values (e.g., `h-10` not `h-[40px]`)
|
|
927
1271
|
- [ ] Followed HeroUI theme colors (bg-background, bg-primary, etc.)
|
|
928
1272
|
- [ ] Mapped all data from constants (no hardcoded menu items/dropdowns)
|
|
929
|
-
- [ ] Created constants files for navigation items and menu options
|
|
930
|
-
|
|
931
|
-
### Navigation
|
|
932
|
-
- [ ] Used Next.js `Link` from `next/link` for internal navigation
|
|
933
|
-
- [ ] Used `NAVIGATION_URLS` for ALL links (no hardcoded URLs)
|
|
934
|
-
- [ ] Imported `usePathname`, `useRouter` from `next/navigation`
|
|
935
|
-
- [ ] Implemented responsive navigation with HeroUI Navbar components
|
|
936
|
-
- [ ] Created navigation items constants in `src/config/navigationItems.ts`
|
|
937
1273
|
|
|
938
|
-
### Content &
|
|
1274
|
+
### Content & Navigation
|
|
939
1275
|
- [ ] ALL text uses i18n translation keys (no hardcoded text)
|
|
940
1276
|
- [ ] ALL labels use `t('labelKey')`
|
|
941
1277
|
- [ ] ALL placeholders use `t('placeholderKey')`
|
|
942
1278
|
- [ ] ALL error messages use `t('errorKey')`
|
|
943
1279
|
- [ ] ALL titles and headings use `t('titleKey')`
|
|
944
|
-
- [ ] ALL
|
|
1280
|
+
- [ ] ALL URLs use `NAVIGATION_URLS` from config (no hardcoded URLs)
|
|
945
1281
|
|
|
946
1282
|
### Structure & Types
|
|
947
1283
|
- [ ] Page created in correct location (`src/app/[locale]/...`)
|
|
948
1284
|
- [ ] Added TypeScript types for all data structures
|
|
949
1285
|
- [ ] Used `'use client'` for interactive components
|
|
950
1286
|
- [ ] No `any` types used
|
|
951
|
-
- [ ] Used `as const` for constants type safety
|
|
952
1287
|
|
|
953
1288
|
### Forms & Validation
|
|
954
1289
|
- [ ] Implemented forms with Zod validation schemas
|
|
@@ -961,7 +1296,6 @@ When converting Figma to code, ensure:
|
|
|
961
1296
|
- [ ] Added proper loading states
|
|
962
1297
|
- [ ] Added proper error states
|
|
963
1298
|
- [ ] Tested on multiple breakpoints (mobile, tablet, desktop)
|
|
964
|
-
- [ ] Implemented responsive navigation menu
|
|
965
1299
|
|
|
966
1300
|
---
|
|
967
1301
|
|
|
@@ -969,72 +1303,51 @@ When converting Figma to code, ensure:
|
|
|
969
1303
|
|
|
970
1304
|
Before finalizing code, verify:
|
|
971
1305
|
|
|
972
|
-
### Figma Integration
|
|
973
|
-
1. **Figma MCP used** - Design fetched via Figma MCP server (not manual)
|
|
974
|
-
2. **Design tokens extracted** - Colors, spacing, typography identified
|
|
975
|
-
3. **Component mapping** - Figma components mapped to HeroUI
|
|
976
|
-
|
|
977
1306
|
### Icons & Assets
|
|
978
1307
|
1. **Icons workflow** - All icons created via `pnpm generate-icons` (not manual)
|
|
979
|
-
2. **
|
|
980
|
-
3. **
|
|
981
|
-
4. **
|
|
982
|
-
5. **Logos location** - All logos/images in `public/images/` (not `src/`)
|
|
983
|
-
6. **Image constants** - Centralized `src/config/images.ts` exists and is used
|
|
984
|
-
7. **Image organization** - Images categorized (LOGOS, AUTH, WEBSITE, SERVICES)
|
|
985
|
-
8. **No hardcoded paths** - All images referenced via `IMAGES.CATEGORY.NAME`
|
|
986
|
-
9. **Image format** - SVG used for logos when possible (not PNG)
|
|
987
|
-
|
|
988
|
-
### Colors & Theme
|
|
989
|
-
1. **Theme colors used** - `bg-primary`, `text-primary` instead of hex values
|
|
990
|
-
2. **Primary shades** - Correct use of primary-50 to primary-900
|
|
991
|
-
3. **Semantic colors** - Using HeroUI semantic colors (success, danger, warning)
|
|
1308
|
+
2. **Icons source** - SVG files exist in `src/assets/icons/`
|
|
1309
|
+
3. **Logos location** - All logos/images in `public/` directory (not `src/`)
|
|
1310
|
+
4. **Image format** - SVG used for logos when possible (not PNG)
|
|
992
1311
|
|
|
993
1312
|
### Components & Styling
|
|
994
|
-
1. **HeroUI components first** - Verify HeroUI library was checked before custom
|
|
1313
|
+
1. **HeroUI components first** - Verify HeroUI library was checked before custom implementation
|
|
995
1314
|
2. **No direct HeroUI imports** - Only through `@/components/ui`
|
|
996
|
-
3. **Component
|
|
997
|
-
4. **
|
|
998
|
-
5. **
|
|
999
|
-
6. **Standard Tailwind classes** - No arbitrary values when standard class exists
|
|
1000
|
-
7. **Map from constants** - All menu items, dropdown options mapped from config
|
|
1001
|
-
|
|
1002
|
-
### Navigation
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1315
|
+
3. **Component reuse** - Don't duplicate existing components
|
|
1316
|
+
4. **Use HeroUI components** - No HTML elements when HeroUI component exists (e.g., use `<Button>` not `<button>`)
|
|
1317
|
+
5. **Configure, don't inline** - Component styles in wrapper/theme, not inline classNames
|
|
1318
|
+
6. **Standard Tailwind classes** - No arbitrary values when standard class exists (e.g., `h-10` not `h-[40px]`)
|
|
1319
|
+
7. **Map from constants** - All menu items, dropdown options mapped from config files
|
|
1320
|
+
|
|
1321
|
+
### i18n & Navigation
|
|
1322
|
+
5. **Zero hardcoded text** - ALL text uses `t('key')`
|
|
1323
|
+
6. **Zero hardcoded URLs** - ALL links use `NAVIGATION_URLS`
|
|
1324
|
+
7. **Form fields i18n** - Labels, placeholders, errors all use translation keys
|
|
1325
|
+
|
|
1326
|
+
### Styling & Layout
|
|
1327
|
+
8. **Tailwind only** - No CSS modules, no styled-components
|
|
1328
|
+
9. **HeroUI theme colors** - Use semantic colors, not arbitrary values
|
|
1329
|
+
10. **Consistent spacing** - Use `space-y-*` and `space-x-*` utilities
|
|
1330
|
+
11. **Mobile-first** - Base styles for mobile, then `md:`, `lg:`, etc.
|
|
1331
|
+
|
|
1332
|
+
### TypeScript & Validation
|
|
1333
|
+
12. **Proper TypeScript** - No `any`, all props typed
|
|
1334
|
+
13. **Form validation** - Zod schemas for all forms
|
|
1013
1335
|
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
3. **Client components** - `'use client'` where needed
|
|
1336
|
+
---
|
|
1337
|
+
|
|
1338
|
+
## 📚 Reference Files
|
|
1018
1339
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1340
|
+
When in doubt, check these example files:
|
|
1341
|
+
- **Form example**: `src/components/ui/form/Form.tsx`
|
|
1342
|
+
- **Page example**: `src/app/[locale]/(auth)/login/page.tsx`
|
|
1343
|
+
- **Component example**: `src/components/ui/Input.tsx`
|
|
1344
|
+
- **Styles reference**: `src/styles/globals.css`
|
|
1345
|
+
- **Theme config**: `src/styles/hero.ts`
|
|
1023
1346
|
|
|
1024
1347
|
---
|
|
1025
1348
|
|
|
1026
1349
|
## 🚀 Quick Reference Guide
|
|
1027
1350
|
|
|
1028
|
-
### Figma MCP Workflow
|
|
1029
|
-
```
|
|
1030
|
-
1. Receive Figma URL from user
|
|
1031
|
-
2. Use Figma MCP server to fetch design
|
|
1032
|
-
3. Analyze pages, frames, components
|
|
1033
|
-
4. Extract design tokens and assets
|
|
1034
|
-
5. Map components to HeroUI
|
|
1035
|
-
6. Implement with proper patterns
|
|
1036
|
-
```
|
|
1037
|
-
|
|
1038
1351
|
### Icons Workflow
|
|
1039
1352
|
```bash
|
|
1040
1353
|
# 1. Export SVG from Figma
|
|
@@ -1044,30 +1357,19 @@ mv icon.svg src/assets/icons/
|
|
|
1044
1357
|
# 3. Generate components
|
|
1045
1358
|
pnpm generate-icons
|
|
1046
1359
|
|
|
1047
|
-
# 4. Use
|
|
1048
|
-
import {
|
|
1049
|
-
<
|
|
1050
|
-
|
|
1051
|
-
# OR use direct import
|
|
1052
|
-
import { MenuIcon } from '@/components/icons';
|
|
1053
|
-
<MenuIcon className="size-6" />
|
|
1360
|
+
# 4. Use in code
|
|
1361
|
+
import { IconIcon } from '@/components/icons';
|
|
1362
|
+
<IconIcon className="size-5" />
|
|
1054
1363
|
```
|
|
1055
1364
|
|
|
1056
1365
|
### Logos/Images Workflow
|
|
1057
1366
|
```bash
|
|
1058
|
-
# 1.
|
|
1059
|
-
#
|
|
1060
|
-
|
|
1061
|
-
# 2. If doesn't exist, export from Figma
|
|
1062
|
-
# Export as SVG (preferred) or PNG
|
|
1063
|
-
|
|
1064
|
-
# 3. Place in public with organized folders
|
|
1367
|
+
# 1. Export SVG/PNG from Figma
|
|
1368
|
+
# 2. Place in public with organized folders
|
|
1065
1369
|
mv logo.svg public/images/logos/
|
|
1066
|
-
mv hero-bg.webp public/images/website/
|
|
1067
|
-
|
|
1068
|
-
# 4. Update centralized constants file
|
|
1069
|
-
# Edit src/config/images.ts
|
|
1070
1370
|
|
|
1371
|
+
# 3. Create centralized constants file
|
|
1372
|
+
# src/config/images.ts
|
|
1071
1373
|
const LOGOS = {
|
|
1072
1374
|
PRIMARY: '/images/logos/logo-primary.svg',
|
|
1073
1375
|
ICON: '/images/logos/logo-icon.svg',
|
|
@@ -1082,60 +1384,11 @@ export const IMAGES = {
|
|
|
1082
1384
|
WEBSITE,
|
|
1083
1385
|
} as const;
|
|
1084
1386
|
|
|
1085
|
-
#
|
|
1387
|
+
# 4. Use in code
|
|
1086
1388
|
import { IMAGES } from '@/config/images';
|
|
1087
1389
|
<img src={IMAGES.LOGOS.PRIMARY} alt="Logo" className="h-10 w-auto" />
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
### Component Configuration Pattern
|
|
1091
|
-
```tsx
|
|
1092
|
-
// File: src/components/ui/Button.tsx
|
|
1093
|
-
import { extendVariants, Button as HeroUIButton } from '@heroui/react';
|
|
1094
|
-
|
|
1095
|
-
export const Button = extendVariants(HeroUIButton, {
|
|
1096
|
-
variants: {
|
|
1097
|
-
color: {
|
|
1098
|
-
primary: 'bg-primary-600 text-black hover:bg-primary-500',
|
|
1099
|
-
},
|
|
1100
|
-
size: {
|
|
1101
|
-
md: 'h-10 px-4 text-sm',
|
|
1102
|
-
},
|
|
1103
|
-
},
|
|
1104
|
-
defaultVariants: {
|
|
1105
|
-
color: 'primary',
|
|
1106
|
-
size: 'md',
|
|
1107
|
-
radius: 'full',
|
|
1108
|
-
},
|
|
1109
|
-
});
|
|
1110
|
-
|
|
1111
|
-
// Usage - Clean and simple:
|
|
1112
|
-
<Button>Click Me</Button>
|
|
1113
|
-
<Button color="secondary" size="lg">Large</Button>
|
|
1114
|
-
```
|
|
1115
|
-
|
|
1116
|
-
### Navigation with HeroUI Navbar
|
|
1117
|
-
```tsx
|
|
1118
|
-
import { Navbar, NavbarBrand, NavbarContent, NavbarItem } from '@heroui/react';
|
|
1119
|
-
import Link from 'next/link';
|
|
1120
|
-
import { NAVIGATION_URLS } from '@/config/navigationUrls';
|
|
1121
|
-
import { IMAGES } from '@/config/images';
|
|
1122
|
-
import { mainNavigationItems } from '@/config/navigationItems';
|
|
1123
|
-
|
|
1124
|
-
<Navbar>
|
|
1125
|
-
<NavbarBrand>
|
|
1126
|
-
<Link href={NAVIGATION_URLS.ROOT}>
|
|
1127
|
-
<img src={IMAGES.LOGOS.PRIMARY} alt={t('logoAlt')} className="h-10" />
|
|
1128
|
-
</Link>
|
|
1129
|
-
</NavbarBrand>
|
|
1130
|
-
|
|
1131
|
-
<NavbarContent>
|
|
1132
|
-
{mainNavigationItems.map((item) => (
|
|
1133
|
-
<NavbarItem key={item.key}>
|
|
1134
|
-
<Link href={item.href}>{t(item.labelKey)}</Link>
|
|
1135
|
-
</NavbarItem>
|
|
1136
|
-
))}
|
|
1137
|
-
</NavbarContent>
|
|
1138
|
-
</Navbar>
|
|
1390
|
+
# OR
|
|
1391
|
+
<Image src={IMAGES.LOGOS.PRIMARY} alt="Logo" width={120} height={40} />
|
|
1139
1392
|
```
|
|
1140
1393
|
|
|
1141
1394
|
### Tailwind Standard Classes
|
|
@@ -1154,32 +1407,48 @@ text-base = 16px text-2xl = 24px
|
|
|
1154
1407
|
text-lg = 18px text-3xl = 30px
|
|
1155
1408
|
|
|
1156
1409
|
// Use standard class if within 2-4px of target
|
|
1410
|
+
// Only use arbitrary [value] for design tokens
|
|
1157
1411
|
```
|
|
1158
1412
|
|
|
1159
|
-
###
|
|
1413
|
+
### Common Patterns
|
|
1160
1414
|
```tsx
|
|
1161
|
-
//
|
|
1162
|
-
|
|
1163
|
-
<
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1415
|
+
// Icons (auto-generated)
|
|
1416
|
+
import { MenuIcon, CloseIcon } from '@/components/icons';
|
|
1417
|
+
<MenuIcon className="size-6 text-white" />
|
|
1418
|
+
|
|
1419
|
+
// Logos (centralized constants)
|
|
1420
|
+
import { IMAGES } from '@/config/images';
|
|
1421
|
+
<img src={IMAGES.LOGOS.PRIMARY} alt="Logo" className="h-10 w-auto" />
|
|
1422
|
+
|
|
1423
|
+
// Navigation (Next.js Link + constants)
|
|
1424
|
+
import Link from 'next/link';
|
|
1425
|
+
import { NAVIGATION_URLS } from '@/config/navigationUrls';
|
|
1426
|
+
<Link href={NAVIGATION_URLS.ABOUT}>{t('about')}</Link>
|
|
1427
|
+
|
|
1428
|
+
// Navigation hooks (from next/navigation)
|
|
1429
|
+
import { usePathname, useRouter } from 'next/navigation';
|
|
1430
|
+
const pathname = usePathname();
|
|
1431
|
+
const router = useRouter();
|
|
1432
|
+
|
|
1433
|
+
// Translation (all text)
|
|
1434
|
+
const t = useTranslations('namespace');
|
|
1435
|
+
<h1>{t('title')}</h1>
|
|
1436
|
+
|
|
1437
|
+
// Components (use HeroUI, not HTML)
|
|
1438
|
+
import { Button } from '@/components/ui';
|
|
1439
|
+
<Button color="primary">Click</Button> // ✅
|
|
1440
|
+
<button>Click</button> // ❌
|
|
1441
|
+
|
|
1442
|
+
// Data mapping (from constants)
|
|
1443
|
+
const menuItems = [
|
|
1444
|
+
{ key: 'home', labelKey: 'home', href: NAVIGATION_URLS.ROOT },
|
|
1445
|
+
];
|
|
1446
|
+
{menuItems.map(item => <Item key={item.key}>{t(item.labelKey)}</Item>)}
|
|
1447
|
+
|
|
1448
|
+
// Responsive (mobile-first)
|
|
1449
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
|
|
1171
1450
|
```
|
|
1172
1451
|
|
|
1173
1452
|
---
|
|
1174
1453
|
|
|
1175
|
-
**Remember**: This project has a well-defined structure
|
|
1176
|
-
1. **Always using Figma MCP** to fetch design details
|
|
1177
|
-
2. **Following the Icon component pattern** for cleaner code
|
|
1178
|
-
3. **Creating and maintaining centralized image constants**
|
|
1179
|
-
4. **Checking existing images before exporting** from Figma
|
|
1180
|
-
5. **Using extendVariants with defaultVariants** for component configuration
|
|
1181
|
-
6. **Using theme colors** (primary-600, primary-50, etc.) instead of hardcoded values
|
|
1182
|
-
7. **Implementing HeroUI Navbar** for navigation components
|
|
1183
|
-
8. **Mapping all data from constants** - never hardcode
|
|
1184
|
-
|
|
1185
|
-
Stay within the boundaries of the existing architecture.
|
|
1454
|
+
**Remember**: This project has a well-defined structure and component library. Your job is to use them correctly, not to reinvent them. Stay within the boundaries of the existing architecture.
|