@nebulit/embuilder 0.1.39 → 0.1.41
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/.claude/skills/sample-slices/SKILL.md +3 -1
- package/templates/.claude/skills/sample-slices/templates/.slices/index.json +1 -1
- package/templates/.claude/skills/ui-analyze-slices/SKILL.md +102 -0
- package/templates/.claude/skills/ui-build-slice-ui/SKILL.md +228 -0
- package/templates/.claude/skills/ui-generate-api/SKILL.md +141 -0
- package/templates/.claude/skills/ui-generate-hook/SKILL.md +118 -0
- package/templates/.claude/skills/ui-generate-types/SKILL.md +223 -0
- package/templates/.claude/skills/ui-read-ui-prompts/SKILL.md +192 -0
- package/templates/.claude/skills/ui-scaffold-component/SKILL.md +274 -0
- package/templates/.slices/Context/event/slice.json +117 -0
- package/templates/.slices/index.json +12 -0
- package/templates/backend/prompt.md +140 -0
- package/templates/config.json +133 -0
- package/templates/frontend/prompt.md +484 -0
- package/templates/prompt.md +4 -132
- package/templates/server.mjs +24 -2
- package/templates/.claude/skills/sample-slices/templates/Cart/additem/slice.json +0 -979
- package/templates/.claude/skills/sample-slices/templates/Cart/archiveitem/slice.json +0 -529
- package/templates/.claude/skills/sample-slices/templates/Cart/cartitems/slice.json +0 -1072
- package/templates/.claude/skills/sample-slices/templates/Cart/cartwithproducts/slice.json +0 -394
- package/templates/.claude/skills/sample-slices/templates/Cart/changedprices/slice.json +0 -88
- package/templates/.claude/skills/sample-slices/templates/Cart/changeinventory/slice.json +0 -264
- package/templates/.claude/skills/sample-slices/templates/Cart/changeprice/slice.json +0 -308
- package/templates/.claude/skills/sample-slices/templates/Cart/clearcart/slice.json +0 -358
- package/templates/.claude/skills/sample-slices/templates/Cart/inventories/slice.json +0 -203
- package/templates/.claude/skills/sample-slices/templates/Cart/publishcart/slice.json +0 -876
- package/templates/.claude/skills/sample-slices/templates/Cart/removeitem/slice.json +0 -560
- package/templates/.claude/skills/sample-slices/templates/Cart/submitcart/slice.json +0 -708
- package/templates/.claude/skills/sample-slices/templates/Cart/submittedcartdata/slice.json +0 -399
- package/templates/.claude/skills/sample-slices/templates/index.json +0 -108
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill_name: ui-generate-types
|
|
3
|
+
description: Generate TypeScript interfaces from slice field definitions
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: Frontend Development Team
|
|
6
|
+
tags: [ui, typescript, types, interfaces, codegen]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Type Generator Skill
|
|
10
|
+
|
|
11
|
+
Generate TypeScript interfaces from slice field definitions.
|
|
12
|
+
|
|
13
|
+
## Instructions
|
|
14
|
+
|
|
15
|
+
You will be provided with:
|
|
16
|
+
- Slice JSON file path
|
|
17
|
+
- Entity name
|
|
18
|
+
|
|
19
|
+
Your task is to:
|
|
20
|
+
|
|
21
|
+
1. **Read the slice JSON file** to understand:
|
|
22
|
+
- All fields and their types
|
|
23
|
+
- Required vs optional fields
|
|
24
|
+
- Field descriptions
|
|
25
|
+
|
|
26
|
+
2. **Generate TypeScript interfaces**:
|
|
27
|
+
- **Entity interface**: Represents the domain object (for STATE_VIEW slices)
|
|
28
|
+
- **Params interface**: Represents parameters for commands (for STATE_CHANGE slices)
|
|
29
|
+
|
|
30
|
+
3. **Map slice field types to TypeScript types**:
|
|
31
|
+
- String → `string`
|
|
32
|
+
- Int, Long, Double, Decimal → `number`
|
|
33
|
+
- Boolean → `boolean`
|
|
34
|
+
- Date, DateTime → `string` (ISO format)
|
|
35
|
+
- Time → `string`
|
|
36
|
+
- UUID → `string`
|
|
37
|
+
- Enum → `union type` or `enum`
|
|
38
|
+
|
|
39
|
+
4. **Add interfaces to** `src/types/index.ts`
|
|
40
|
+
|
|
41
|
+
## Type Mapping
|
|
42
|
+
|
|
43
|
+
| Slice Type | TypeScript Type | Notes |
|
|
44
|
+
|------------|----------------|-------|
|
|
45
|
+
| String | `string` | |
|
|
46
|
+
| Int | `number` | |
|
|
47
|
+
| Long | `number` | |
|
|
48
|
+
| Double | `number` | |
|
|
49
|
+
| Decimal | `number` | |
|
|
50
|
+
| Boolean | `boolean` | |
|
|
51
|
+
| Date | `string` | ISO date string (YYYY-MM-DD) |
|
|
52
|
+
| DateTime | `string` | ISO datetime string |
|
|
53
|
+
| Time | `string` | HH:mm format |
|
|
54
|
+
| UUID | `string` | |
|
|
55
|
+
| Enum | `'value1' \| 'value2'` | Union type |
|
|
56
|
+
|
|
57
|
+
## Interface Templates
|
|
58
|
+
|
|
59
|
+
### For STATE_VIEW (Entity Interface)
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
/**
|
|
63
|
+
* {Entity description}
|
|
64
|
+
*/
|
|
65
|
+
export interface {Entity} {
|
|
66
|
+
/** Unique identifier */
|
|
67
|
+
{id_field}: string;
|
|
68
|
+
|
|
69
|
+
/** {Field description} */
|
|
70
|
+
{field_name}: {field_type};
|
|
71
|
+
|
|
72
|
+
/** Optional field */
|
|
73
|
+
{optional_field}?: {field_type};
|
|
74
|
+
|
|
75
|
+
/** Created timestamp */
|
|
76
|
+
created_at?: string;
|
|
77
|
+
|
|
78
|
+
/** Updated timestamp */
|
|
79
|
+
updated_at?: string;
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### For STATE_CHANGE (Params Interface)
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
/**
|
|
87
|
+
* Parameters for {action} {entity}
|
|
88
|
+
*/
|
|
89
|
+
export interface {Action}{Entity}Params {
|
|
90
|
+
/** {Field description} */
|
|
91
|
+
{field_name}: {field_type};
|
|
92
|
+
|
|
93
|
+
/** Optional parameter */
|
|
94
|
+
{optional_field}?: {field_type};
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Output Format
|
|
99
|
+
|
|
100
|
+
Provide:
|
|
101
|
+
|
|
102
|
+
1. **TypeScript interfaces** formatted and documented
|
|
103
|
+
2. **Location** where to add (typically `src/types/index.ts`)
|
|
104
|
+
3. **Notes** on any special type considerations
|
|
105
|
+
|
|
106
|
+
Example:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
# Types Generated
|
|
110
|
+
|
|
111
|
+
## Add to src/types/index.ts
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Represents an event in the system
|
|
115
|
+
*/
|
|
116
|
+
export interface Event {
|
|
117
|
+
/** Unique event identifier */
|
|
118
|
+
event_id: string;
|
|
119
|
+
|
|
120
|
+
/** Event name */
|
|
121
|
+
name: string;
|
|
122
|
+
|
|
123
|
+
/** Event date in YYYY-MM-DD format */
|
|
124
|
+
date: string;
|
|
125
|
+
|
|
126
|
+
/** Start time in HH:mm format */
|
|
127
|
+
start_time: string;
|
|
128
|
+
|
|
129
|
+
/** End time in HH:mm format */
|
|
130
|
+
end_time: string;
|
|
131
|
+
|
|
132
|
+
/** Number of persons */
|
|
133
|
+
persons: number;
|
|
134
|
+
|
|
135
|
+
/** Created timestamp */
|
|
136
|
+
created_at?: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Parameters for creating a new event
|
|
141
|
+
*/
|
|
142
|
+
export interface CreateEventParams {
|
|
143
|
+
/** Event name (max 100 characters) */
|
|
144
|
+
name: string;
|
|
145
|
+
|
|
146
|
+
/** Event date in YYYY-MM-DD format */
|
|
147
|
+
date: string;
|
|
148
|
+
|
|
149
|
+
/** Start time in HH:mm format */
|
|
150
|
+
startTime: string;
|
|
151
|
+
|
|
152
|
+
/** End time in HH:mm format */
|
|
153
|
+
endTime: string;
|
|
154
|
+
|
|
155
|
+
/** Number of persons (must be positive) */
|
|
156
|
+
persons: number;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
## Notes
|
|
160
|
+
|
|
161
|
+
- Date fields use ISO string format for compatibility with HTML date inputs
|
|
162
|
+
- Time fields use HH:mm format
|
|
163
|
+
- Field names in params use camelCase (frontend convention)
|
|
164
|
+
- Field names in entity match database column names (snake_case)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Special Cases
|
|
168
|
+
|
|
169
|
+
### Optional Fields
|
|
170
|
+
|
|
171
|
+
Mark fields as optional with `?` when:
|
|
172
|
+
- The slice indicates the field is not required
|
|
173
|
+
- The field has a default value
|
|
174
|
+
- The field is generated (like timestamps, IDs)
|
|
175
|
+
|
|
176
|
+
### Enums
|
|
177
|
+
|
|
178
|
+
For enum fields, create either:
|
|
179
|
+
|
|
180
|
+
**Option 1: Union Type (preferred for simple cases)**
|
|
181
|
+
```typescript
|
|
182
|
+
export type EventStatus = 'pending' | 'confirmed' | 'cancelled';
|
|
183
|
+
|
|
184
|
+
export interface Event {
|
|
185
|
+
status: EventStatus;
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Option 2: Enum (for complex cases with values)**
|
|
190
|
+
```typescript
|
|
191
|
+
export enum EventStatus {
|
|
192
|
+
Pending = 'PENDING',
|
|
193
|
+
Confirmed = 'CONFIRMED',
|
|
194
|
+
Cancelled = 'CANCELLED',
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Nested Objects
|
|
199
|
+
|
|
200
|
+
If the slice includes nested structures:
|
|
201
|
+
```typescript
|
|
202
|
+
export interface Address {
|
|
203
|
+
street: string;
|
|
204
|
+
city: string;
|
|
205
|
+
zipCode: string;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export interface Customer {
|
|
209
|
+
id: string;
|
|
210
|
+
name: string;
|
|
211
|
+
address: Address;
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Notes
|
|
216
|
+
|
|
217
|
+
- Always add JSDoc comments for interfaces and fields
|
|
218
|
+
- Include validation constraints in comments (max length, min/max values, etc.)
|
|
219
|
+
- Keep entity interfaces separate from params interfaces
|
|
220
|
+
- For params, use camelCase field names (frontend convention)
|
|
221
|
+
- For entities, match the database schema field names
|
|
222
|
+
- Check if types already exist before adding duplicates
|
|
223
|
+
- Export all types from `src/types/index.ts`
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill_name: ui-read-ui-prompts
|
|
3
|
+
description: Find and parse UI prompts from slice definitions and related files
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: Frontend Development Team
|
|
6
|
+
tags: [ui, prompts, requirements, design, validation]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# UI Prompt Reader Skill
|
|
10
|
+
|
|
11
|
+
Find and parse UI prompts from slice definitions and related files.
|
|
12
|
+
|
|
13
|
+
## Instructions
|
|
14
|
+
|
|
15
|
+
You will be provided with:
|
|
16
|
+
- Slice JSON file path
|
|
17
|
+
- Slice folder path (e.g., `/backend/src/slices/<slice name>/`)
|
|
18
|
+
|
|
19
|
+
Your task is to:
|
|
20
|
+
|
|
21
|
+
1. **Read the slice JSON file** to extract:
|
|
22
|
+
- `codeGen.uiPrompts` array (if present)
|
|
23
|
+
- Any UI-related metadata in the slice definition
|
|
24
|
+
|
|
25
|
+
2. **Check for `ui-prompt.md`** in the slice folder:
|
|
26
|
+
- Read the file if it exists
|
|
27
|
+
- Parse its content for design requirements, validation rules, and UX flows
|
|
28
|
+
|
|
29
|
+
3. **Extract and organize UI requirements**:
|
|
30
|
+
- Design specifications (layout, styling, format)
|
|
31
|
+
- Validation rules (required fields, formats, constraints)
|
|
32
|
+
- UX flow instructions (user journey, interactions)
|
|
33
|
+
- Accessibility requirements
|
|
34
|
+
- Error handling specifications
|
|
35
|
+
|
|
36
|
+
4. **Provide structured output** that can guide component implementation
|
|
37
|
+
|
|
38
|
+
## UI Prompt Structure
|
|
39
|
+
|
|
40
|
+
UI prompts typically contain:
|
|
41
|
+
|
|
42
|
+
### Design Specifications
|
|
43
|
+
- Layout preferences (grid, cards, table, list)
|
|
44
|
+
- Styling guidelines (colors, spacing, typography)
|
|
45
|
+
- Format requirements (date formats, number formats)
|
|
46
|
+
- Responsive design considerations
|
|
47
|
+
|
|
48
|
+
### Validation Rules
|
|
49
|
+
- Required fields
|
|
50
|
+
- Field length constraints (min/max)
|
|
51
|
+
- Value constraints (min/max values, ranges)
|
|
52
|
+
- Format validations (email, phone, URL, patterns)
|
|
53
|
+
- Cross-field validations (end date > start date)
|
|
54
|
+
|
|
55
|
+
### UX Flow
|
|
56
|
+
- User journey steps
|
|
57
|
+
- Interaction patterns (click → open dialog → fill form → submit → refresh)
|
|
58
|
+
- Success/error feedback (toasts, notifications, messages)
|
|
59
|
+
- Loading states
|
|
60
|
+
- Empty states
|
|
61
|
+
|
|
62
|
+
### Accessibility
|
|
63
|
+
- ARIA labels
|
|
64
|
+
- Keyboard navigation
|
|
65
|
+
- Screen reader support
|
|
66
|
+
- Focus management
|
|
67
|
+
|
|
68
|
+
## Output Format
|
|
69
|
+
|
|
70
|
+
Provide a structured summary:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
# UI Prompts Analysis
|
|
74
|
+
|
|
75
|
+
## Source: {slice name}
|
|
76
|
+
|
|
77
|
+
### From codeGen.uiPrompts:
|
|
78
|
+
1. "{prompt text}"
|
|
79
|
+
2. "{prompt text}"
|
|
80
|
+
|
|
81
|
+
### From ui-prompt.md:
|
|
82
|
+
|
|
83
|
+
#### Design Specifications:
|
|
84
|
+
- Layout: {description}
|
|
85
|
+
- Styling: {description}
|
|
86
|
+
- Formats: {description}
|
|
87
|
+
|
|
88
|
+
#### Validation Rules:
|
|
89
|
+
| Field | Rule | Message |
|
|
90
|
+
|-------|------|---------|
|
|
91
|
+
| {field} | {rule} | {error message} |
|
|
92
|
+
|
|
93
|
+
#### UX Flow:
|
|
94
|
+
1. {step}
|
|
95
|
+
2. {step}
|
|
96
|
+
3. {step}
|
|
97
|
+
|
|
98
|
+
#### Special Requirements:
|
|
99
|
+
- {requirement}
|
|
100
|
+
- {requirement}
|
|
101
|
+
|
|
102
|
+
### Implementation Guidance:
|
|
103
|
+
|
|
104
|
+
Based on the prompts, the implementation should:
|
|
105
|
+
1. {specific action based on prompt}
|
|
106
|
+
2. {specific action based on prompt}
|
|
107
|
+
|
|
108
|
+
### Code Snippets:
|
|
109
|
+
|
|
110
|
+
{Any specific code patterns or examples from the prompts}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Example
|
|
114
|
+
|
|
115
|
+
For an events management slice with ui-prompt.md:
|
|
116
|
+
|
|
117
|
+
```markdown
|
|
118
|
+
# Events Management UI
|
|
119
|
+
|
|
120
|
+
## Design
|
|
121
|
+
- Use card layout for event list
|
|
122
|
+
- Display date in DD.MM.YYYY format
|
|
123
|
+
- Show time in 24-hour format (HH:mm)
|
|
124
|
+
- Use responsive 3-column grid on desktop, 1-column on mobile
|
|
125
|
+
|
|
126
|
+
## Validation
|
|
127
|
+
- Name: Required, max 100 characters
|
|
128
|
+
- Date: Required, cannot be in the past
|
|
129
|
+
- Start time: Required
|
|
130
|
+
- End time: Required, must be after start time
|
|
131
|
+
- Persons: Required, must be > 0
|
|
132
|
+
|
|
133
|
+
## UX Flow
|
|
134
|
+
1. User clicks "Create Event" button
|
|
135
|
+
2. Modal dialog opens with form
|
|
136
|
+
3. User fills form fields
|
|
137
|
+
4. On submit, show loading state
|
|
138
|
+
5. On success, close dialog and show success toast
|
|
139
|
+
6. Refresh event list automatically
|
|
140
|
+
7. On error, show error message in dialog
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Your output would be:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
# UI Prompts Analysis
|
|
147
|
+
|
|
148
|
+
## Source: Events Management
|
|
149
|
+
|
|
150
|
+
### From ui-prompt.md:
|
|
151
|
+
|
|
152
|
+
#### Design Specifications:
|
|
153
|
+
- Layout: Card layout for event list with 3-column grid (desktop) / 1-column (mobile)
|
|
154
|
+
- Date Format: DD.MM.YYYY
|
|
155
|
+
- Time Format: 24-hour format (HH:mm)
|
|
156
|
+
- Component: Use Bulma cards and columns
|
|
157
|
+
|
|
158
|
+
#### Validation Rules:
|
|
159
|
+
| Field | Rule | Message |
|
|
160
|
+
|-------|------|---------|
|
|
161
|
+
| name | Required, max 100 chars | "Name is required (max 100 characters)" |
|
|
162
|
+
| date | Required, not in past | "Date cannot be in the past" |
|
|
163
|
+
| start_time | Required | "Start time is required" |
|
|
164
|
+
| end_time | Required, > start_time | "End time must be after start time" |
|
|
165
|
+
| persons | Required, > 0 | "Number of persons must be positive" |
|
|
166
|
+
|
|
167
|
+
#### UX Flow:
|
|
168
|
+
1. Click "Create Event" button
|
|
169
|
+
2. Modal dialog opens with form
|
|
170
|
+
3. Fill form fields with validation
|
|
171
|
+
4. Submit → Loading state
|
|
172
|
+
5. Success → Close dialog + Success toast + Refresh list
|
|
173
|
+
6. Error → Show error in dialog
|
|
174
|
+
|
|
175
|
+
### Implementation Guidance:
|
|
176
|
+
|
|
177
|
+
1. Use Bulma modal with `is-active` class for dialog
|
|
178
|
+
2. Implement date formatting with `toLocaleDateString('de-DE')`
|
|
179
|
+
3. Add form validation before submit
|
|
180
|
+
4. Use `useMutation` onSuccess callback for toast and list refresh
|
|
181
|
+
5. Implement responsive grid with `columns is-multiline` and `column is-one-third`
|
|
182
|
+
6. Add cross-field validation for start/end time comparison
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Notes
|
|
186
|
+
|
|
187
|
+
- If no `ui-prompt.md` exists, rely solely on `codeGen.uiPrompts`
|
|
188
|
+
- If no UI prompts are found, provide general best practices
|
|
189
|
+
- Extract specific implementation details (formats, layouts, validations)
|
|
190
|
+
- Translate requirements into actionable coding tasks
|
|
191
|
+
- Identify any custom components or patterns needed
|
|
192
|
+
- Note any conflicts between prompts and suggest resolutions
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill_name: ui-scaffold-component
|
|
3
|
+
description: Scaffold React components (List, Dialog, Page) from slice definitions using Bulma CSS
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: Frontend Development Team
|
|
6
|
+
tags: [ui, components, react, bulma, scaffolding]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Component Scaffolder Skill
|
|
10
|
+
|
|
11
|
+
Scaffold React components (List, Dialog, Page) from slice definitions using Bulma CSS.
|
|
12
|
+
|
|
13
|
+
## Instructions
|
|
14
|
+
|
|
15
|
+
You will be provided with:
|
|
16
|
+
- Slice JSON file paths (one or more in the same group)
|
|
17
|
+
- Component type to scaffold (List, Dialog, Page, or Auto)
|
|
18
|
+
- Domain/entity name
|
|
19
|
+
|
|
20
|
+
Your task is to:
|
|
21
|
+
|
|
22
|
+
1. **Read all slice JSON files** to understand:
|
|
23
|
+
- Fields and their types
|
|
24
|
+
- Which slices are STATE_VIEW (for lists)
|
|
25
|
+
- Which slices are STATE_CHANGE (for forms/dialogs)
|
|
26
|
+
- UI prompts from `codeGen.uiPrompts`
|
|
27
|
+
|
|
28
|
+
2. **Scaffold appropriate components**:
|
|
29
|
+
- **List Component**: For STATE_VIEW slices (displays data in cards/table)
|
|
30
|
+
- **Dialog Component**: For STATE_CHANGE slices (forms for create/update)
|
|
31
|
+
- **Page Component**: Combines list and dialogs into a complete page
|
|
32
|
+
|
|
33
|
+
3. **Use Bulma CSS exclusively** for all styling:
|
|
34
|
+
- Layout: `columns`, `column`, `container`, `section`
|
|
35
|
+
- Components: `card`, `button`, `modal`, `box`, `table`
|
|
36
|
+
- Form elements: `field`, `control`, `label`, `input`, `select`, `textarea`
|
|
37
|
+
- Utilities: `is-primary`, `is-fullwidth`, `has-text-centered`, etc.
|
|
38
|
+
|
|
39
|
+
4. **Integrate generated hooks**:
|
|
40
|
+
- Import and use query hooks in list components
|
|
41
|
+
- Import and use mutation hooks in dialog components
|
|
42
|
+
- Handle loading and error states
|
|
43
|
+
|
|
44
|
+
## Component Templates
|
|
45
|
+
|
|
46
|
+
### List Component (for STATE_VIEW)
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import React from 'react';
|
|
50
|
+
import { use{Entity} } from '@/hooks/api';
|
|
51
|
+
import type { {Entity} } from '@/types';
|
|
52
|
+
|
|
53
|
+
export function {Entity}List() {
|
|
54
|
+
const { data: {entities}, isLoading, error } = use{Entity}();
|
|
55
|
+
|
|
56
|
+
if (isLoading) {
|
|
57
|
+
return <div className="has-text-centered p-6">Loading...</div>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (error) {
|
|
61
|
+
return (
|
|
62
|
+
<div className="notification is-danger">
|
|
63
|
+
Error loading {entities}: {error.message}
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!{entities} || {entities}.length === 0) {
|
|
69
|
+
return (
|
|
70
|
+
<div className="notification is-info">
|
|
71
|
+
No {entities} found.
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div className="columns is-multiline">
|
|
78
|
+
{{entities}.map(({entity}) => (
|
|
79
|
+
<div key={{entity}.id} className="column is-one-third">
|
|
80
|
+
<div className="card">
|
|
81
|
+
<div className="card-content">
|
|
82
|
+
<p className="title is-5">{{entity}.name}</p>
|
|
83
|
+
{/* Add more fields based on slice definition */}
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
))}
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Dialog Component (for STATE_CHANGE)
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import React, { useState } from 'react';
|
|
97
|
+
import { use{Action}{Entity} } from '@/hooks/api';
|
|
98
|
+
import type { {Action}{Entity}Params } from '@/types';
|
|
99
|
+
|
|
100
|
+
interface {Action}{Entity}DialogProps {
|
|
101
|
+
isOpen: boolean;
|
|
102
|
+
onClose: () => void;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function {Action}{Entity}Dialog({ isOpen, onClose }: {Action}{Entity}DialogProps) {
|
|
106
|
+
const { mutate: {actionCamelCase}{Entity}, isPending } = use{Action}{Entity}();
|
|
107
|
+
const [formData, setFormData] = useState<{Action}{Entity}Params>({
|
|
108
|
+
// Initialize with default values based on slice fields
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const handleSubmit = (e: React.FormEvent) => {
|
|
112
|
+
e.preventDefault();
|
|
113
|
+
{actionCamelCase}{Entity}(formData, {
|
|
114
|
+
onSuccess: () => {
|
|
115
|
+
onClose();
|
|
116
|
+
// Reset form or show success message
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
if (!isOpen) return null;
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<div className={`modal ${isOpen ? 'is-active' : ''}`}>
|
|
125
|
+
<div className="modal-background" onClick={onClose}></div>
|
|
126
|
+
<div className="modal-card">
|
|
127
|
+
<header className="modal-card-head">
|
|
128
|
+
<p className="modal-card-title">{Action} {Entity}</p>
|
|
129
|
+
<button className="delete" onClick={onClose}></button>
|
|
130
|
+
</header>
|
|
131
|
+
<section className="modal-card-body">
|
|
132
|
+
<form onSubmit={handleSubmit}>
|
|
133
|
+
{/* Generate form fields based on slice definition */}
|
|
134
|
+
<div className="field">
|
|
135
|
+
<label className="label">Field Name</label>
|
|
136
|
+
<div className="control">
|
|
137
|
+
<input
|
|
138
|
+
className="input"
|
|
139
|
+
type="text"
|
|
140
|
+
value={formData.fieldName}
|
|
141
|
+
onChange={(e) => setFormData({ ...formData, fieldName: e.target.value })}
|
|
142
|
+
required
|
|
143
|
+
/>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</form>
|
|
147
|
+
</section>
|
|
148
|
+
<footer className="modal-card-foot">
|
|
149
|
+
<button
|
|
150
|
+
className="button is-primary"
|
|
151
|
+
onClick={handleSubmit}
|
|
152
|
+
disabled={isPending}
|
|
153
|
+
>
|
|
154
|
+
{isPending ? 'Saving...' : 'Save'}
|
|
155
|
+
</button>
|
|
156
|
+
<button className="button" onClick={onClose}>
|
|
157
|
+
Cancel
|
|
158
|
+
</button>
|
|
159
|
+
</footer>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Page Component (Composition)
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import React, { useState } from 'react';
|
|
170
|
+
import { {Entity}List } from './{Entity}List';
|
|
171
|
+
import { Create{Entity}Dialog } from './Create{Entity}Dialog';
|
|
172
|
+
|
|
173
|
+
export function {Entity}Page() {
|
|
174
|
+
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<div className="container">
|
|
178
|
+
<section className="section">
|
|
179
|
+
<div className="level">
|
|
180
|
+
<div className="level-left">
|
|
181
|
+
<div className="level-item">
|
|
182
|
+
<h1 className="title">{Entities}</h1>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
<div className="level-right">
|
|
186
|
+
<div className="level-item">
|
|
187
|
+
<button
|
|
188
|
+
className="button is-primary"
|
|
189
|
+
onClick={() => setIsCreateDialogOpen(true)}
|
|
190
|
+
>
|
|
191
|
+
Create {Entity}
|
|
192
|
+
</button>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
<{Entity}List />
|
|
198
|
+
|
|
199
|
+
<Create{Entity}Dialog
|
|
200
|
+
isOpen={isCreateDialogOpen}
|
|
201
|
+
onClose={() => setIsCreateDialogOpen(false)}
|
|
202
|
+
/>
|
|
203
|
+
</section>
|
|
204
|
+
</div>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Form Field Generation
|
|
210
|
+
|
|
211
|
+
Based on field types in slice JSON, generate appropriate form inputs:
|
|
212
|
+
|
|
213
|
+
- **String**: `<input className="input" type="text" />`
|
|
214
|
+
- **Number**: `<input className="input" type="number" />`
|
|
215
|
+
- **Date**: `<input className="input" type="date" />`
|
|
216
|
+
- **Time**: `<input className="input" type="time" />`
|
|
217
|
+
- **Boolean**: `<input type="checkbox" className="checkbox" />`
|
|
218
|
+
- **Enum/Select**: `<div className="select"><select>...</select></div>`
|
|
219
|
+
- **Textarea**: `<textarea className="textarea" />`
|
|
220
|
+
|
|
221
|
+
## Output Format
|
|
222
|
+
|
|
223
|
+
Provide:
|
|
224
|
+
|
|
225
|
+
1. **Component files** with full paths
|
|
226
|
+
2. **Import statements** needed
|
|
227
|
+
3. **Integration notes** for adding to routes or parent components
|
|
228
|
+
|
|
229
|
+
Example:
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
# Components Scaffolded
|
|
233
|
+
|
|
234
|
+
## File: src/components/events/EventList.tsx
|
|
235
|
+
|
|
236
|
+
[Component code]
|
|
237
|
+
|
|
238
|
+
## File: src/components/events/CreateEventDialog.tsx
|
|
239
|
+
|
|
240
|
+
[Component code]
|
|
241
|
+
|
|
242
|
+
## File: src/components/events/EventsPage.tsx
|
|
243
|
+
|
|
244
|
+
[Component code]
|
|
245
|
+
|
|
246
|
+
## Integration
|
|
247
|
+
|
|
248
|
+
Add to routes:
|
|
249
|
+
import { EventsPage } from '@/components/events/EventsPage';
|
|
250
|
+
|
|
251
|
+
// In router configuration:
|
|
252
|
+
{ path: '/events', element: <EventsPage /> }
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Bulma CSS Guidelines
|
|
256
|
+
|
|
257
|
+
- Use `columns` and `column` for responsive grid layouts
|
|
258
|
+
- Use `card` for displaying entity items
|
|
259
|
+
- Use `modal` for dialogs (add `is-active` class when open)
|
|
260
|
+
- Use `button is-primary` for primary actions
|
|
261
|
+
- Use `notification` for messages (with `is-danger`, `is-info`, etc.)
|
|
262
|
+
- Use `field`, `control`, `label`, `input` for forms
|
|
263
|
+
- Use `level` for horizontal layouts with items on left/right
|
|
264
|
+
- Use `section` and `container` for page layout
|
|
265
|
+
|
|
266
|
+
## Notes
|
|
267
|
+
|
|
268
|
+
- Always create components in `src/components/{domain}/` directory
|
|
269
|
+
- Use TypeScript with proper types imported from `@/types`
|
|
270
|
+
- Include loading and error states
|
|
271
|
+
- Handle form validation based on required fields
|
|
272
|
+
- Close dialogs on successful mutations
|
|
273
|
+
- Use semantic HTML elements
|
|
274
|
+
- Follow React best practices (controlled components, proper event handling)
|