@minhduydev/mdpi 0.4.0 → 0.5.0

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 (48) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/template/.pi/VERSION +1 -1
  3. package/dist/template/.pi/extensions/templates-injector.ts +34 -6
  4. package/dist/template/.pi/prompts/INDEX.md +3 -9
  5. package/dist/template/.pi/skills/INDEX.md +81 -19
  6. package/dist/template/.pi/skills/accessibility-audit/SKILL.md +8 -2
  7. package/dist/template/.pi/skills/baseline-ui/SKILL.md +211 -0
  8. package/dist/template/.pi/skills/dcp-hygiene/SKILL.md +1 -1
  9. package/dist/template/.pi/skills/design-taste-frontend/SKILL.md +53 -42
  10. package/dist/template/.pi/skills/fixing-accessibility/SKILL.md +509 -0
  11. package/dist/template/.pi/skills/frontend-design/SKILL.md +60 -47
  12. package/dist/template/.pi/skills/frontend-design/references/animation/motion-advanced.md +88 -15
  13. package/dist/template/.pi/skills/frontend-design/references/animation/motion-core.md +148 -13
  14. package/dist/template/.pi/skills/frontend-design/references/shadcn/setup.md +127 -20
  15. package/dist/template/.pi/skills/frontend-ui-engineering/SKILL.md +21 -27
  16. package/dist/template/.pi/skills/nextjs-app-router/SKILL.md +334 -0
  17. package/dist/template/.pi/skills/nextjs-cache/SKILL.md +262 -0
  18. package/dist/template/.pi/skills/oklch-color-workflow/SKILL.md +426 -0
  19. package/dist/template/.pi/skills/production-hardening/SKILL.md +652 -0
  20. package/dist/template/.pi/skills/react-best-practices/SKILL.md +79 -1
  21. package/dist/template/.pi/skills/react-compiler/SKILL.md +237 -0
  22. package/dist/template/.pi/skills/react-hook-form/SKILL.md +374 -0
  23. package/dist/template/.pi/skills/react-server-actions/SKILL.md +299 -0
  24. package/dist/template/.pi/skills/shadcn-ui/SKILL.md +404 -0
  25. package/dist/template/.pi/skills/tanstack-query/SKILL.md +330 -0
  26. package/dist/template/.pi/skills/ui-craft-principles/SKILL.md +564 -0
  27. package/dist/template/.pi/skills/ui-quality-audit/SKILL.md +329 -0
  28. package/dist/template/.pi/skills/v0/SKILL.md +264 -0
  29. package/dist/template/.pi/skills/zustand/SKILL.md +333 -0
  30. package/dist/template/.pi/templates/DESIGN.md +76 -0
  31. package/dist/template/.pi/workflows/INDEX.md +2 -1
  32. package/dist/template/.pi/workflows/frontend-feature-workflow.md +343 -0
  33. package/dist/template/.pi/workflows/quality-loop.md +1 -1
  34. package/package.json +1 -1
  35. package/dist/template/.pi/prompts/loop-check.md +0 -87
  36. package/dist/template/.pi/prompts/loop-init.md +0 -157
  37. package/dist/template/.pi/prompts/loop-review.md +0 -90
  38. package/dist/template/.pi/skills/loop-audit/SKILL.md +0 -141
  39. package/dist/template/.pi/skills/loop-cost/SKILL.md +0 -130
  40. package/dist/template/.pi/skills/loop-engineering/SKILL.md +0 -175
  41. package/dist/template/.pi/templates/loop-github-action.yml +0 -162
  42. package/dist/template/.pi/templates/loop-orchestrator.sh +0 -514
  43. package/dist/template/.pi/templates/loop-orchestrator.test.ts +0 -332
  44. package/dist/template/.pi/templates/loop-orchestrator.ts +0 -936
  45. package/dist/template/.pi/templates/loop-state.json +0 -24
  46. package/dist/template/.pi/templates/loop-state.md +0 -98
  47. package/dist/template/.pi/templates/loop-vision.md +0 -110
  48. /package/dist/template/.pi/templates/{design.md → feature-design.md} +0 -0
@@ -0,0 +1,333 @@
1
+ ---
2
+ name: zustand
3
+ description: Use when implementing global or shared state management in React with Zustand v5. Covers store creation, slices pattern, middleware, selective subscriptions, React 19 + SSR integration. MUST load before any state management implementation.
4
+ ---
5
+
6
+ # Zustand v5
7
+
8
+ ## When to Use
9
+
10
+ - Managing global or shared client-side state in React
11
+ - Replacing Redux, Jotai, or Context for state management
12
+ - Creating stores that are used across multiple components
13
+ - Implementing slices for domain-separated state
14
+ - Persisting state to localStorage or sessionStorage
15
+ - Using middleware (immer, devtools, persist)
16
+
17
+ ## When NOT to Use
18
+
19
+ - Server state (use TanStack Query or Server Components)
20
+ - Form state (use React Hook Form or Server Actions)
21
+ - Single-component local state (use `useState` or `useReducer`)
22
+ - Server Components (Zustand is client-only)
23
+
24
+ ## Setup
25
+
26
+ ```bash
27
+ npm install zustand
28
+ ```
29
+
30
+ ## Basic Store
31
+
32
+ ```tsx
33
+ // stores/counter.ts
34
+ import { create } from 'zustand'
35
+
36
+ interface CounterState {
37
+ count: number
38
+ increment: () => void
39
+ decrement: () => void
40
+ reset: () => void
41
+ }
42
+
43
+ export const useCounterStore = create<CounterState>((set) => ({
44
+ count: 0,
45
+ increment: () => set((state) => ({ count: state.count + 1 })),
46
+ decrement: () => set((state) => ({ count: state.count - 1 })),
47
+ reset: () => set({ count: 0 }),
48
+ }))
49
+ ```
50
+
51
+ ```tsx
52
+ // components/Counter.tsx
53
+ 'use client'
54
+
55
+ import { useCounterStore } from '@/stores/counter'
56
+
57
+ export function Counter() {
58
+ const { count, increment, decrement } = useCounterStore()
59
+
60
+ return (
61
+ <div>
62
+ <p>Count: {count}</p>
63
+ <button onClick={increment}>+</button>
64
+ <button onClick={decrement}>-</button>
65
+ </div>
66
+ )
67
+ }
68
+ ```
69
+
70
+ ## Slices Pattern
71
+
72
+ Split store into domain slices:
73
+
74
+ ```tsx
75
+ // stores/index.ts
76
+ import { create } from 'zustand'
77
+ import { createAuthSlice, type AuthSlice } from './slices/auth'
78
+ import { createCartSlice, type CartSlice } from './slices/cart'
79
+
80
+ type Store = AuthSlice & CartSlice
81
+
82
+ export const useStore = create<Store>()((...args) => ({
83
+ ...createAuthSlice(...args),
84
+ ...createCartSlice(...args),
85
+ }))
86
+ ```
87
+
88
+ ```tsx
89
+ // stores/slices/auth.ts
90
+ import type { StateCreator } from 'zustand'
91
+
92
+ export interface AuthSlice {
93
+ user: User | null
94
+ login: (credentials: Credentials) => Promise<void>
95
+ logout: () => void
96
+ }
97
+
98
+ export const createAuthSlice: StateCreator<AuthSlice, [], [], AuthSlice> = (set) => ({
99
+ user: null,
100
+ login: async (credentials) => {
101
+ const user = await api.login(credentials)
102
+ set({ user })
103
+ },
104
+ logout: () => set({ user: null }),
105
+ })
106
+ ```
107
+
108
+ ## Selective Subscriptions
109
+
110
+ Zustand re-renders only when **used** state changes:
111
+
112
+ ```tsx
113
+ // ❌ Whole store — re-renders on any change
114
+ const { count, name } = useStore()
115
+
116
+ // ✅ Selective — re-renders only when count changes
117
+ const count = useStore((state) => state.count)
118
+ const increment = useStore((state) => state.increment) // Stable reference
119
+
120
+ // ✅ Multiple values — useShallow for objects
121
+ import { useShallow } from 'zustand/react/shallow'
122
+
123
+ const { name, email } = useStore(
124
+ useShallow((state) => ({ name: state.user.name, email: state.user.email }))
125
+ )
126
+ ```
127
+
128
+ `useShallow` does shallow equality — avoids re-render when both values are the same.
129
+
130
+ ## Middleware
131
+
132
+ ### Persist (localStorage)
133
+
134
+ ```tsx
135
+ import { create } from 'zustand'
136
+ import { persist } from 'zustand/middleware'
137
+
138
+ export const useSettingsStore = create(
139
+ persist(
140
+ (set) => ({
141
+ theme: 'light',
142
+ setTheme: (theme: 'light' | 'dark') => set({ theme }),
143
+ }),
144
+ {
145
+ name: 'app-settings', // localStorage key
146
+ partialize: (state) => ({ theme: state.theme }), // Only persist theme
147
+ }
148
+ )
149
+ )
150
+ ```
151
+
152
+ ### Immer (Immutable Updates)
153
+
154
+ ```tsx
155
+ import { create } from 'zustand'
156
+ import { immer } from 'zustand/middleware/immer'
157
+
158
+ export const useTodoStore = create(
159
+ immer((set) => ({
160
+ todos: [] as Todo[],
161
+ addTodo: (text: string) =>
162
+ set((state) => {
163
+ state.todos.push({ id: crypto.randomUUID(), text, done: false })
164
+ }),
165
+ toggleTodo: (id: string) =>
166
+ set((state) => {
167
+ const todo = state.todos.find((t) => t.id === id)
168
+ if (todo) todo.done = !todo.done
169
+ }),
170
+ }))
171
+ )
172
+ ```
173
+
174
+ ### DevTools
175
+
176
+ ```tsx
177
+ import { create } from 'zustand'
178
+ import { devtools } from 'zustand/middleware'
179
+
180
+ export const useStore = create(
181
+ devtools(
182
+ (set) => ({
183
+ count: 0,
184
+ increment: () => set((s) => ({ count: s.count + 1 }), false, 'increment'),
185
+ }),
186
+ { name: 'AppStore' } // Name in Redux DevTools
187
+ )
188
+ )
189
+ ```
190
+
191
+ ### Combining Multiple Middleware
192
+
193
+ ```tsx
194
+ import { create } from 'zustand'
195
+ import { devtools, persist, immer } from 'zustand/middleware'
196
+
197
+ export const useStore = create(
198
+ devtools(
199
+ persist(
200
+ immer((set) => ({
201
+ // store...
202
+ })),
203
+ { name: 'app-storage' }
204
+ ),
205
+ { name: 'AppStore' }
206
+ )
207
+ )
208
+ ```
209
+
210
+ ## React 19 + Server Components
211
+
212
+ Zustand is **client-only**. Pattern for Next.js App Router:
213
+
214
+ ```tsx
215
+ // stores/useStore.ts
216
+ import { create } from 'zustand'
217
+
218
+ export const useStore = create<Store>((set) => ({
219
+ // ...
220
+ }))
221
+ ```
222
+
223
+ ```tsx
224
+ // components/ClientWrapper.tsx
225
+ 'use client'
226
+
227
+ import { useStore } from '@/stores/useStore'
228
+
229
+ export function ClientWrapper({ children }) {
230
+ const data = useStore((s) => s.data)
231
+
232
+ return <div>{children}</div>
233
+ }
234
+ ```
235
+
236
+ **Rules**:
237
+ - Stores are defined outside components (module scope)
238
+ - Store consumers must be in `'use client'` components
239
+ - Server Components can import the store type but cannot `useStore()`
240
+ - Use React Context to provide a store instance if you need SSR hydration
241
+
242
+ ## SSR Hydration Pattern
243
+
244
+ ```tsx
245
+ // app/providers.tsx
246
+ 'use client'
247
+
248
+ import { type ReactNode, createContext, useContext, useRef } from 'react'
249
+ import { type StoreApi, useStore } from 'zustand'
250
+
251
+ // Create context for store
252
+ const StoreContext = createContext<StoreApi<AppStore> | null>(null)
253
+
254
+ export function StoreProvider({ children }: { children: ReactNode }) {
255
+ const storeRef = useRef<StoreApi<AppStore>>()
256
+
257
+ if (!storeRef.current) {
258
+ storeRef.current = createAppStore()
259
+ }
260
+
261
+ return (
262
+ <StoreContext.Provider value={storeRef.current}>
263
+ {children}
264
+ </StoreContext.Provider>
265
+ )
266
+ }
267
+
268
+ // Hook to use the store
269
+ export function useAppStore<T>(selector: (state: AppStore) => T): T {
270
+ const store = useContext(StoreContext)
271
+ if (!store) throw new Error('Missing StoreProvider')
272
+ return useStore(store, selector)
273
+ }
274
+ ```
275
+
276
+ ## Async Actions
277
+
278
+ ```tsx
279
+ // Async actions are just async functions in the store:
280
+ interface UserStore {
281
+ user: User | null
282
+ loading: boolean
283
+ error: Error | null
284
+ fetchUser: (id: string) => Promise<void>
285
+ }
286
+
287
+ export const useUserStore = create<UserStore>((set) => ({
288
+ user: null,
289
+ loading: false,
290
+ error: null,
291
+ fetchUser: async (id) => {
292
+ set({ loading: true, error: null })
293
+ try {
294
+ const user = await api.getUser(id)
295
+ set({ user, loading: false })
296
+ } catch (error) {
297
+ set({ error: error as Error, loading: false })
298
+ }
299
+ },
300
+ }))
301
+ ```
302
+
303
+ ## When to Use Zustand vs Context vs TanStack Query
304
+
305
+ | Tool | Best for |
306
+ |------|----------|
307
+ | **Zustand** | Global client state: theme, auth, cart, UI preferences |
308
+ | **React Context** | Dependency injection, theming, auth provider — static values that rarely change |
309
+ | **TanStack Query** | Server state: data fetching, caching, mutations |
310
+ | **useState/useReducer** | Local component state |
311
+
312
+ ## Common Pitfalls
313
+
314
+ | Pitfall | Fix |
315
+ |---------|-----|
316
+ | Using Zustand for server state | Use TanStack Query for fetched data — Zustand for client-only state |
317
+ | `useStore()` without selector — re-renders on any change | Always use selectors: `useStore(s => s.count)` |
318
+ | Multiple values returned as new object every render | Use `useShallow` for object selectors |
319
+ | Store in Server Component | Move store usage to `'use client'` |
320
+ | `getState()` in render | `getState()` is for callbacks/outside React, not render |
321
+ | Large stores with everything in one file | Use slices pattern to separate domains |
322
+ | Recreating store on every render | Define store outside component or use `useRef` for context pattern |
323
+
324
+ ## Verification
325
+
326
+ - [ ] Store defined outside component (module scope) or via `useRef` in provider
327
+ - [ ] All store consumers are in `'use client'` components
328
+ - [ ] Selectors used for granular subscriptions — no destructured `useStore()`
329
+ - [ ] `useShallow` used for multi-value object selectors
330
+ - [ ] Server state (fetched data) managed by TanStack Query, not Zustand
331
+ - [ ] Slices pattern used for stores with multiple domains
332
+ - [ ] `persist` middleware configured with `partialize` to avoid storing sensitive data
333
+ - [ ] DevTools middleware enabled (development only)
@@ -0,0 +1,76 @@
1
+ ---
2
+ purpose: Project visual identity — single source of truth for mood, color, typography, layout, elevation, shapes, components, and design constraints.
3
+ updated: 2026-06-19
4
+ ---
5
+
6
+ # DESIGN.md — Project Visual Identity
7
+
8
+ > **Aesthetic Anchor:** [One evocative sentence referencing a specific era, artifact, or scene — not adjectives. Example: "A 1970s graduate lecture handout, mimeographed on off-white paper."]
9
+
10
+ ## 1. Overview & Mood
11
+
12
+ - **Mood:** [2-3 words: e.g., "Architectural Minimalism", "Warm Editorial", "Brutalist Terminal"]
13
+ - **Specific Reference:** [A concrete scene, artifact, or era — not abstract adjectives]
14
+ - **Tone:** [Professional / Playful / Serious / Warm / Clinical]
15
+ - **Design Philosophy:** [1-2 sentences on guiding aesthetic principle]
16
+
17
+ ## 2. Colors
18
+
19
+ - **Brand Palette:** `{colors.brand.primary}` `{colors.brand.secondary}` `{colors.brand.accent}`
20
+ - **Neutral Scale:** `{colors.neutral.50}` → `{colors.neutral.950}` (50/100/200/300/400/500/600/700/800/900/950)
21
+ - **Semantic Colors:** Success `{colors.semantic.success}`, Warning `{colors.semantic.warning}`, Error `{colors.semantic.error}`, Info `{colors.semantic.info}`
22
+ - **Contrast Floor:** WCAG 2.1 AA minimum (≥ 4.5:1 for body text)
23
+ - **No Pure Black:** Use `{colors.neutral.950}` instead of `#000`
24
+
25
+ ## 3. Typography
26
+
27
+ - **Display Font:** `{typography.display.family}` — for H1, hero headings
28
+ - **Body Font:** `{typography.body.family}` — for paragraphs, UI labels
29
+ - **Mono Font:** `{typography.mono.family}` — for code, data, timestamps
30
+ - **Scale:** `{typography.scale}` (e.g., 12/14/16/18/20/24/30/36/48/60/72)
31
+ - **Weight Range:** `{typography.weights}` (e.g., 400/500/600/700)
32
+ - **Line Height:** 1.5 body, 1.2 headings
33
+
34
+ ## 4. Layout & Spacing
35
+
36
+ - **Grid Base:** `{layout.grid}` (e.g., 4px or 8px)
37
+ - **Spacing Scale:** `{layout.spacing}` (e.g., 4/8/12/16/24/32/48/64/96)
38
+ - **Max Content Width:** `{layout.maxWidth}` (e.g., 1280px)
39
+ - **Column Count:** `{layout.columns}` (e.g., 12-column grid)
40
+ - **Gutter Width:** `{layout.gutter}` (e.g., 24px)
41
+
42
+ ## 5. Elevation & Depth
43
+
44
+ - **Shadow Scale:** 5 levels (none / sm / md / lg / xl)
45
+ - **Depth Philosophy:** [Flat / Subtle depth / Heavy layering]
46
+ - **Z-Index Layers:** Base content → Overlays → Modals → Toasts → Tooltips
47
+ - **Border Usage:** When and where borders replace shadows
48
+
49
+ ## 6. Shapes & Corners
50
+
51
+ - **Border Radius Scale:** `{shapes.borderRadius}` (e.g., 0/4/8/12/16/24/full)
52
+ - **Corner Philosophy:** [Sharp / Soft / Rounded / Pill]
53
+ - **Icon Style:** [Filled / Outline / Duotone / Custom]
54
+ - **Stroke Width:** `{shapes.strokeWidth}` (e.g., 1px or 1.5px)
55
+
56
+ ## 7. Components
57
+
58
+ - **Button Hierarchy:** Primary `{components.button.primary}` / Secondary `{components.button.secondary}` / Ghost `{components.button.ghost}` / Danger `{components.button.danger}`
59
+ - **Input Style:** [Outlined / Filled / Underlined] with `{components.input.height}` height
60
+ - **Card Style:** [Elevated / Bordered / Flat] with `{components.card.padding}` padding
61
+ - **Modal Style:** [Centered / Slide-up / Fullscreen] with backdrop `{components.modal.backdrop}`
62
+ - **Navigation:** [Top bar / Sidebar / Bottom tabs] with `{components.nav.height}`
63
+
64
+ ## 8. Do's and Don'ts
65
+
66
+ ### Do's
67
+
68
+ - [Key principle 1 — with reasoning]
69
+ - [Key principle 2 — with reasoning]
70
+ - [Key principle 3 — with reasoning]
71
+
72
+ ### Don'ts
73
+
74
+ - **Pattern:** [Anti-pattern] — **Replacement:** [Correct approach] — **Because:** [Why this matters]
75
+ - **Pattern:** [Anti-pattern] — **Replacement:** [Correct approach] — **Because:** [Why this matters]
76
+ - **Pattern:** [Anti-pattern] — **Replacement:** [Correct approach] — **Because:** [Why this matters]
@@ -4,7 +4,7 @@ purpose: Index of DAG workflows with trigger, phases, and invoking command
4
4
 
5
5
  # Workflows Index
6
6
 
7
- 6 DAG workflows. All have `description` frontmatter (for `run_workflow` discovery) and use a consistent Phase format: `Agent`, `Concurrency`, `Depends on`, `Prompt`.
7
+ 7 DAG workflows. All have `description` frontmatter (for `run_workflow` discovery) and use a consistent Phase format: `Agent`, `Concurrency`, `Depends on`, `Prompt`.
8
8
 
9
9
  ## Invocation
10
10
 
@@ -24,6 +24,7 @@ Workflows may compose recursively (e.g., `development-lifecycle-workflow` Phase
24
24
  | `batch-implement` | 3 + merge | ≥5 independent tasks, no file conflicts | `/ship` Phase 3, `development-lifecycle-workflow` Phase 4 | One subagent per task in parallel, review, merge |
25
25
  | `deep-research` | 2 + synthesis | Complex/multi-angle topic | `/research` (complex mode) | Fan out web searches per angle, cross-check, cited report |
26
26
  | `development-lifecycle-workflow` | 5 | Explicit full-lifecycle multi-agent run | Manual / future `/lifecycle` | research → validate → plan → implement → verify (composes batch-implement) |
27
+ | `frontend-feature-workflow` | 7 | Frontend feature build (mockup or spec) | `run_workflow({ name: "frontend-feature-workflow", args: { feature: "..." } })` | design analysis → deslop → architecture → craft → implement → harden → audit |
27
28
  | `garbage-collection` | 5 | Manual `/gc` or scheduled cadence | `/gc` | Fallow scan → grade → prioritize → optional cleanup PRs |
28
29
  | `quality-loop` | 7 (looped) | High-risk feature, explicit quality gating | `/ship` Phase 5 (Iterative Quality Loop) | Score-gated review loop until 5/5 or escalation |
29
30