@nebulit/embuilder 0.1.40 → 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.
Files changed (24) hide show
  1. package/package.json +1 -1
  2. package/templates/.claude/skills/sample-slices/templates/.slices/index.json +1 -1
  3. package/templates/.claude/skills/ui-analyze-slices/SKILL.md +102 -0
  4. package/templates/.claude/skills/ui-build-slice-ui/SKILL.md +228 -0
  5. package/templates/.claude/skills/ui-generate-api/SKILL.md +141 -0
  6. package/templates/.claude/skills/ui-generate-hook/SKILL.md +118 -0
  7. package/templates/.claude/skills/ui-generate-types/SKILL.md +223 -0
  8. package/templates/.claude/skills/ui-read-ui-prompts/SKILL.md +192 -0
  9. package/templates/.claude/skills/ui-scaffold-component/SKILL.md +274 -0
  10. package/templates/frontend/prompt.md +250 -90
  11. package/templates/.claude/skills/sample-slices/templates/Cart/additem/slice.json +0 -979
  12. package/templates/.claude/skills/sample-slices/templates/Cart/archiveitem/slice.json +0 -529
  13. package/templates/.claude/skills/sample-slices/templates/Cart/cartitems/slice.json +0 -1072
  14. package/templates/.claude/skills/sample-slices/templates/Cart/cartwithproducts/slice.json +0 -394
  15. package/templates/.claude/skills/sample-slices/templates/Cart/changedprices/slice.json +0 -88
  16. package/templates/.claude/skills/sample-slices/templates/Cart/changeinventory/slice.json +0 -264
  17. package/templates/.claude/skills/sample-slices/templates/Cart/changeprice/slice.json +0 -308
  18. package/templates/.claude/skills/sample-slices/templates/Cart/clearcart/slice.json +0 -358
  19. package/templates/.claude/skills/sample-slices/templates/Cart/inventories/slice.json +0 -203
  20. package/templates/.claude/skills/sample-slices/templates/Cart/publishcart/slice.json +0 -876
  21. package/templates/.claude/skills/sample-slices/templates/Cart/removeitem/slice.json +0 -560
  22. package/templates/.claude/skills/sample-slices/templates/Cart/submitcart/slice.json +0 -708
  23. package/templates/.claude/skills/sample-slices/templates/Cart/submittedcartdata/slice.json +0 -399
  24. package/templates/.claude/skills/sample-slices/templates/index.json +0 -108
@@ -4,6 +4,22 @@ Build React + TypeScript UI components from slice JSON definitions using establi
4
4
 
5
5
  ---
6
6
 
7
+ ## 0. Available Skills (Use These!)
8
+
9
+ This project has custom skills available in `.claude/skills/` that automate common tasks:
10
+
11
+ - **`/ui-build-slice-ui`**: Complete orchestrator - builds entire UI from slice definitions (types → API → hooks → components)
12
+ - **`/ui-analyze-slices`**: Analyze slice JSON files to identify grouping, dependencies, and implementation strategy
13
+ - **`/ui-read-ui-prompts`**: Find and parse UI prompts from slice definitions and `ui-prompt.md`
14
+ - **`/ui-generate-types`**: Generate TypeScript interfaces from slice field definitions
15
+ - **`/ui-generate-api`**: Generate API layer functions for queries (Supabase) and commands (POST)
16
+ - **`/ui-generate-hook`**: Generate React Query hooks for STATE_VIEW (queries) and STATE_CHANGE (mutations)
17
+ - **`/ui-scaffold-component`**: Scaffold React components (List, Dialog, Page) using Bulma CSS
18
+
19
+ **IMPORTANT**: When asked to build UI from slices, USE the `/ui-build-slice-ui` skill first! It will orchestrate all other skills in the correct order. Only use individual skills when you need to regenerate or modify a specific part.
20
+
21
+ ---
22
+
7
23
  ## 1. Slice Composition (CRITICAL)
8
24
 
9
25
  ### Slice Types
@@ -25,8 +41,8 @@ Slice C: { groupId: "123", sliceType: "STATE_CHANGE", title: "Cancel Event" }
25
41
 
26
42
  ### UI Prompts Priority
27
43
 
28
- 1. Check `ui-prompt.md` (detailed specs)
29
- 2. Check `codeGen.uiPrompts` array (high-level guidance)
44
+ 1. Check `ui-prompt.md` (detailed specs) - Use `/ui-read-ui-prompts` skill
45
+ 2. Check `codeGen.uiPrompts` array (high-level guidance) - Use `/ui-read-ui-prompts` skill
30
46
  3. Follow this prompt (standard patterns)
31
47
  4. Keep it simple if no guidance
32
48
 
@@ -56,10 +72,10 @@ import { useQuery } from "@tanstack/react-query";
56
72
  import * as api from "@/lib/api";
57
73
 
58
74
  export function useEvents() {
59
- return useQuery({
60
- queryKey: ["events"],
61
- queryFn: () => api.fetchEvents(),
62
- });
75
+ return useQuery({
76
+ queryKey: ["events"],
77
+ queryFn: () => api.fetchEvents(),
78
+ });
63
79
  }
64
80
  ```
65
81
 
@@ -67,15 +83,15 @@ export function useEvents() {
67
83
 
68
84
  ```typescript
69
85
  export function useCreateEvent() {
70
- const ctx = useApiContext();
71
- const queryClient = useQueryClient();
72
-
73
- return useMutation({
74
- mutationFn: (params: api.CreateEventParams) => api.createEvent(params, ctx),
75
- onSuccess: () => {
76
- queryClient.invalidateQueries({ queryKey: ["events"] });
77
- },
78
- });
86
+ const ctx = useApiContext();
87
+ const queryClient = useQueryClient();
88
+
89
+ return useMutation({
90
+ mutationFn: (params: api.CreateEventParams) => api.createEvent(params, ctx),
91
+ onSuccess: () => {
92
+ queryClient.invalidateQueries({ queryKey: ["events"] });
93
+ },
94
+ });
79
95
  }
80
96
  ```
81
97
 
@@ -88,11 +104,11 @@ export function useCreateEvent() {
88
104
  ```typescript
89
105
  // src/lib/api.ts
90
106
  export async function fetchEvents(): Promise<Event[]> {
91
- const { data, error } = await supabase
92
- .from("events_for_planning") // Read model table
93
- .select("*");
94
- if (error) throw new Error(error.message);
95
- return data || [];
107
+ const { data, error } = await supabase
108
+ .from("events_for_planning") // Read model table
109
+ .select("*");
110
+ if (error) throw new Error(error.message);
111
+ return data || [];
96
112
  }
97
113
  ```
98
114
 
@@ -100,21 +116,21 @@ export async function fetchEvents(): Promise<Event[]> {
100
116
 
101
117
  ```typescript
102
118
  export async function createEvent(params: CreateEventParams, ctx: ApiContext) {
103
- const response = await apiRequest(
104
- commandEndpoints.createEvent, // /api/createevent
105
- ctx,
106
- { method: "POST", body: { ...params } }
107
- );
108
- if (!response.ok) throw new Error(response.error);
109
- return response.data;
119
+ const response = await apiRequest(
120
+ commandEndpoints.createEvent, // /api/createevent
121
+ ctx,
122
+ { method: "POST", body: { ...params } }
123
+ );
124
+ if (!response.ok) throw new Error(response.error);
125
+ return response.data;
110
126
  }
111
127
  ```
112
128
 
113
129
  **Add endpoint in `src/lib/api-client.ts`**:
114
130
  ```typescript
115
131
  export const commandEndpoints = {
116
- createEvent: "/api/createevent",
117
- // ...
132
+ createEvent: "/api/createevent",
133
+ // ...
118
134
  };
119
135
  ```
120
136
 
@@ -130,22 +146,22 @@ import { Skeleton } from "@/components/ui/skeleton";
130
146
  import { useEvents } from "@/hooks/api/useEvents";
131
147
 
132
148
  export function EventList() {
133
- const { data: events = [], isLoading } = useEvents();
134
-
135
- if (isLoading) {
136
- return <Skeleton className="h-20 w-full" />;
137
- }
138
-
139
- return (
140
- <div className="grid gap-4 md:grid-cols-2">
141
- {events.map(event => (
142
- <Card key={event.id}>
143
- <CardHeader><CardTitle>{event.name}</CardTitle></CardHeader>
144
- <CardContent>{event.date}</CardContent>
145
- </Card>
146
- ))}
149
+ const { data: events = [], isLoading } = useEvents();
150
+
151
+ if (isLoading) {
152
+ return <Skeleton className="h-20 w-full" />;
153
+ }
154
+
155
+ return (
156
+ <div className="grid gap-4 md:grid-cols-2">
157
+ {events.map(event => (
158
+ <Card key={event.id}>
159
+ <CardHeader><CardTitle>{event.name}</CardTitle></CardHeader>
160
+ <CardContent>{event.date}</CardContent>
161
+ </Card>
162
+ ))}
147
163
  </div>
148
- );
164
+ );
149
165
  }
150
166
  ```
151
167
 
@@ -161,36 +177,36 @@ import { useCreateEvent } from "@/hooks/api/useEvents";
161
177
  import { toast } from "sonner";
162
178
 
163
179
  export function CreateEventDialog({ open, onOpenChange }) {
164
- const createEvent = useCreateEvent();
165
- const [form, setForm] = useState({ name: "", date: "" });
166
-
167
- const handleSubmit = async () => {
168
- if (!form.name) return toast.error("Name required");
169
- try {
170
- await createEvent.mutateAsync(form);
171
- toast.success("Created");
172
- onOpenChange(false);
173
- } catch (err) {
174
- toast.error(`Error: ${err.message}`);
175
- }
176
- };
177
-
178
- return (
179
- <Dialog open={open} onOpenChange={onOpenChange}>
180
- <DialogContent>
181
- <DialogHeader><DialogTitle>Create Event</DialogTitle></DialogHeader>
182
- <div className="space-y-4">
183
- <div>
180
+ const createEvent = useCreateEvent();
181
+ const [form, setForm] = useState({ name: "", date: "" });
182
+
183
+ const handleSubmit = async () => {
184
+ if (!form.name) return toast.error("Name required");
185
+ try {
186
+ await createEvent.mutateAsync(form);
187
+ toast.success("Created");
188
+ onOpenChange(false);
189
+ } catch (err) {
190
+ toast.error(`Error: ${err.message}`);
191
+ }
192
+ };
193
+
194
+ return (
195
+ <Dialog open={open} onOpenChange={onOpenChange}>
196
+ <DialogContent>
197
+ <DialogHeader><DialogTitle>Create Event</DialogTitle></DialogHeader>
198
+ <div className="space-y-4">
199
+ <div>
184
200
  <Label>Name</Label>
185
- <Input value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} />
186
- </div>
187
- <Button onClick={handleSubmit} disabled={createEvent.isPending}>
188
- Create
189
- </Button>
201
+ <Input value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} />
202
+ </div>
203
+ <Button onClick={handleSubmit} disabled={createEvent.isPending}>
204
+ Create
205
+ </Button>
190
206
  </div>
191
- </DialogContent>
192
- </Dialog>
193
- );
207
+ </DialogContent>
208
+ </Dialog>
209
+ );
194
210
  }
195
211
  ```
196
212
 
@@ -198,19 +214,19 @@ export function CreateEventDialog({ open, onOpenChange }) {
198
214
 
199
215
  ```typescript
200
216
  export function EventsPage() {
201
- const [dialogOpen, setDialogOpen] = useState(false);
217
+ const [dialogOpen, setDialogOpen] = useState(false);
202
218
 
203
- return (
204
- <div className="p-6">
205
- <div className="flex justify-between mb-6">
219
+ return (
220
+ <div className="p-6">
221
+ <div className="flex justify-between mb-6">
206
222
  <h1 className="text-2xl font-bold">Events</h1>
207
- <Button onClick={() => setDialogOpen(true)}>Create Event</Button>
208
- </div>
223
+ <Button onClick={() => setDialogOpen(true)}>Create Event</Button>
224
+ </div>
209
225
 
210
- <EventList />
211
- <CreateEventDialog open={dialogOpen} onOpenChange={setDialogOpen} />
226
+ <EventList />
227
+ <CreateEventDialog open={dialogOpen} onOpenChange={setDialogOpen} />
212
228
  </div>
213
- );
229
+ );
214
230
  }
215
231
  ```
216
232
 
@@ -218,6 +234,33 @@ export function EventsPage() {
218
234
 
219
235
  ## 6. Implementation Workflow
220
236
 
237
+ ### Recommended Approach: Use Skills!
238
+
239
+ **For complete UI generation from slices:**
240
+ ```bash
241
+ # Use the orchestrator skill - it handles everything
242
+ /ui-build-slice-ui <slice-file-paths>
243
+ ```
244
+
245
+ This will automatically:
246
+ 1. Analyze slices (`/ui-analyze-slices`)
247
+ 2. Read UI prompts (`/ui-read-ui-prompts`)
248
+ 3. Generate types (`/ui-generate-types`)
249
+ 4. Generate API functions (`/ui-generate-api`)
250
+ 5. Generate hooks (`/ui-generate-hook`)
251
+ 6. Scaffold components (`/ui-scaffold-component`)
252
+ 7. Verify integration
253
+
254
+ **For individual tasks:**
255
+ - **Analyze before coding**: `/ui-analyze-slices <slice-files>` - Understand grouping and dependencies
256
+ - **Read requirements**: `/ui-read-ui-prompts <slice-folder>` - Extract design specs and validation rules
257
+ - **Generate types only**: `/ui-generate-types <slice-file>` - Create TypeScript interfaces
258
+ - **Generate API only**: `/ui-generate-api <slice-file>` - Create Supabase queries or POST commands
259
+ - **Generate hook only**: `/ui-generate-hook <slice-file>` - Create React Query hooks
260
+ - **Generate component only**: `/ui-scaffold-component <slice-files>` - Create React components with Bulma CSS
261
+
262
+ ### Manual Workflow (If not using skills)
263
+
221
264
  ### Step 0: Analyze Grouping
222
265
  - Find all slices with same `groupId`
223
266
  - Check `codeGen.uiPrompts` and `ui-prompt.md`
@@ -227,14 +270,14 @@ export function EventsPage() {
227
270
  ```typescript
228
271
  // src/types/index.ts
229
272
  export interface Event {
230
- event_id: string;
231
- name: string;
232
- date: string;
273
+ event_id: string;
274
+ name: string;
275
+ date: string;
233
276
  }
234
277
 
235
278
  export interface CreateEventParams {
236
- name: string;
237
- date: string;
279
+ name: string;
280
+ date: string;
238
281
  }
239
282
  ```
240
283
 
@@ -273,10 +316,10 @@ export interface CreateEventParams {
273
316
  **Error Handling**:
274
317
  ```typescript
275
318
  try {
276
- await mutation.mutateAsync(params);
277
- toast.success("Success");
319
+ await mutation.mutateAsync(params);
320
+ toast.success("Success");
278
321
  } catch (err) {
279
- toast.error(`Error: ${err.message}`);
322
+ toast.error(`Error: ${err.message}`);
280
323
  }
281
324
  ```
282
325
 
@@ -286,7 +329,21 @@ try {
286
329
 
287
330
  ---
288
331
 
289
- ## 9. UI Components (shadcn/ui)
332
+ ## 9. UI Components
333
+
334
+ **NOTE**: The skills in `.claude/skills/` are configured to use **Bulma CSS** for styling. If you're using the skills (especially `/scaffold-component`), components will be generated with Bulma classes.
335
+
336
+ ### Bulma CSS (Used by Skills)
337
+
338
+ When using skills, components use Bulma classes:
339
+ - Layout: `container`, `section`, `columns`, `column`
340
+ - Components: `card`, `modal`, `button`, `notification`, `box`
341
+ - Forms: `field`, `control`, `label`, `input`, `select`, `textarea`
342
+ - Modifiers: `is-primary`, `is-active`, `is-fullwidth`, `has-text-centered`
343
+
344
+ ### shadcn/ui (Alternative)
345
+
346
+ If manually implementing (not using skills), you can use shadcn/ui components:
290
347
 
291
348
  Import from `@/components/ui/*`:
292
349
  - `Button`, `Input`, `Label`, `Textarea`, `Select`
@@ -295,6 +352,8 @@ Import from `@/components/ui/*`:
295
352
  - `Table`, `Tabs`, `Skeleton`
296
353
  - `toast` from `sonner`
297
354
 
355
+ **Recommendation**: Use the skills with Bulma CSS for consistency with project configuration.
356
+
298
357
  ---
299
358
 
300
359
  ## Checklist
@@ -322,3 +381,104 @@ Import from `@/components/ui/*`:
322
381
  ✅ **STATE_CHANGE** = Command → Mutation hook → Form/Dialog
323
382
  ✅ **Keep modular** = Sub-components for each slice capability
324
383
  ✅ **Keep simple** = Follow existing patterns, don't over-engineer
384
+
385
+ ---
386
+
387
+ ## 10. Skills Usage Examples
388
+
389
+ ### Example 1: Building Complete UI from Scratch
390
+
391
+ **User Request**: "Build the UI for the events management slices"
392
+
393
+ **Your Response**:
394
+ ```bash
395
+ # First, analyze what we're working with
396
+ /ui-analyze-slices src/slices/events/*.json
397
+
398
+ # Then build everything at once
399
+ /ui-build-slice-ui src/slices/events/ViewEvents.json src/slices/events/CreateEvent.json
400
+ ```
401
+
402
+ ### Example 2: Just Need to Understand Slices
403
+
404
+ **User Request**: "What slices are in the orders group?"
405
+
406
+ **Your Response**:
407
+ ```bash
408
+ # Use ui-analyze-slices to understand the grouping
409
+ /ui-analyze-slices src/slices/orders/*.json
410
+ ```
411
+
412
+ ### Example 3: Regenerating Just Types
413
+
414
+ **User Request**: "The Event interface is wrong, regenerate it from the slice"
415
+
416
+ **Your Response**:
417
+ ```bash
418
+ # Use ui-generate-types to recreate just the TypeScript interfaces
419
+ /ui-generate-types src/slices/events/ViewEvents.json
420
+ ```
421
+
422
+ ### Example 4: Adding New API Endpoint
423
+
424
+ **User Request**: "Add the API function for the CancelEvent command"
425
+
426
+ **Your Response**:
427
+ ```bash
428
+ # Use ui-generate-api to create the API layer
429
+ /ui-generate-api src/slices/events/CancelEvent.json
430
+ ```
431
+
432
+ ### Example 5: Understanding UI Requirements
433
+
434
+ **User Request**: "What are the validation rules for the event form?"
435
+
436
+ **Your Response**:
437
+ ```bash
438
+ # Use ui-read-ui-prompts to extract requirements
439
+ /ui-read-ui-prompts src/slices/events/
440
+ ```
441
+
442
+ ### Example 6: Fixing Component Styling
443
+
444
+ **User Request**: "The EventList component doesn't look right, regenerate it with proper Bulma styling"
445
+
446
+ **Your Response**:
447
+ ```bash
448
+ # Use ui-scaffold-component to regenerate with Bulma CSS
449
+ /ui-scaffold-component src/slices/events/ViewEvents.json
450
+ ```
451
+
452
+ ### Decision Tree: Which Skill to Use?
453
+
454
+ ```
455
+ Need to build complete UI from slices?
456
+ └─> /ui-build-slice-ui (orchestrates everything)
457
+
458
+ Just exploring/understanding?
459
+ └─> /ui-analyze-slices (analysis only)
460
+
461
+ Just need to understand UI requirements?
462
+ └─> /ui-read-ui-prompts (extract specs)
463
+
464
+ Need to fix/regenerate specific layer?
465
+ ├─> Types wrong? → /ui-generate-types
466
+ ├─> API functions wrong? → /ui-generate-api
467
+ ├─> Hooks wrong? → /ui-generate-hook
468
+ └─> Components wrong? → /ui-scaffold-component
469
+
470
+ Don't know which skill to use?
471
+ └─> Start with /ui-analyze-slices, then use /ui-build-slice-ui
472
+ ```
473
+
474
+ ---
475
+
476
+ ## Remember
477
+
478
+ **ALWAYS** prefer using the skills over manual implementation! They ensure:
479
+ - Consistency across the codebase
480
+ - Proper use of Bulma CSS
481
+ - Correct CQRS patterns
482
+ - Proper TypeScript types
483
+ - React Query best practices
484
+ - Adherence to UI prompts and validation rules