@patricio0312rev/skillset 0.1.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.
- package/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +176 -0
- package/bin/cli.js +37 -0
- package/package.json +55 -0
- package/src/commands/init.js +301 -0
- package/src/index.js +168 -0
- package/src/lib/config.js +200 -0
- package/src/lib/generator.js +166 -0
- package/src/utils/display.js +95 -0
- package/src/utils/readme.js +196 -0
- package/src/utils/tool-specific.js +233 -0
- package/templates/ai-engineering/agent-orchestration-planner/ SKILL.md +266 -0
- package/templates/ai-engineering/cost-latency-optimizer/ SKILL.md +270 -0
- package/templates/ai-engineering/doc-to-vector-dataset-generator/ SKILL.md +239 -0
- package/templates/ai-engineering/evaluation-harness/ SKILL.md +219 -0
- package/templates/ai-engineering/guardrails-safety-filter-builder/ SKILL.md +226 -0
- package/templates/ai-engineering/llm-debugger/ SKILL.md +283 -0
- package/templates/ai-engineering/prompt-regression-tester/ SKILL.md +216 -0
- package/templates/ai-engineering/prompt-template-builder/ SKILL.md +393 -0
- package/templates/ai-engineering/rag-pipeline-builder/ SKILL.md +244 -0
- package/templates/ai-engineering/tool-function-schema-designer/ SKILL.md +219 -0
- package/templates/architecture/adr-writer/ SKILL.md +250 -0
- package/templates/architecture/api-versioning-deprecation-planner/ SKILL.md +331 -0
- package/templates/architecture/domain-model-boundaries-mapper/ SKILL.md +300 -0
- package/templates/architecture/migration-planner/ SKILL.md +376 -0
- package/templates/architecture/performance-budget-setter/ SKILL.md +318 -0
- package/templates/architecture/reliability-strategy-builder/ SKILL.md +286 -0
- package/templates/architecture/rfc-generator/ SKILL.md +362 -0
- package/templates/architecture/scalability-playbook/ SKILL.md +279 -0
- package/templates/architecture/system-design-generator/ SKILL.md +339 -0
- package/templates/architecture/tech-debt-prioritizer/ SKILL.md +329 -0
- package/templates/backend/api-contract-normalizer/ SKILL.md +487 -0
- package/templates/backend/api-endpoint-generator/ SKILL.md +415 -0
- package/templates/backend/auth-module-builder/ SKILL.md +99 -0
- package/templates/backend/background-jobs-designer/ SKILL.md +166 -0
- package/templates/backend/caching-strategist/ SKILL.md +190 -0
- package/templates/backend/error-handling-standardizer/ SKILL.md +174 -0
- package/templates/backend/rate-limiting-abuse-protection/ SKILL.md +147 -0
- package/templates/backend/rbac-permissions-builder/ SKILL.md +158 -0
- package/templates/backend/service-layer-extractor/ SKILL.md +269 -0
- package/templates/backend/webhook-receiver-hardener/ SKILL.md +211 -0
- package/templates/ci-cd/artifact-sbom-publisher/ SKILL.md +236 -0
- package/templates/ci-cd/caching-strategy-optimizer/ SKILL.md +195 -0
- package/templates/ci-cd/deployment-checklist-generator/ SKILL.md +381 -0
- package/templates/ci-cd/github-actions-pipeline-creator/ SKILL.md +348 -0
- package/templates/ci-cd/monorepo-ci-optimizer/ SKILL.md +298 -0
- package/templates/ci-cd/preview-environments-builder/ SKILL.md +187 -0
- package/templates/ci-cd/quality-gates-enforcer/ SKILL.md +342 -0
- package/templates/ci-cd/release-automation-builder/ SKILL.md +281 -0
- package/templates/ci-cd/rollback-workflow-builder/ SKILL.md +372 -0
- package/templates/ci-cd/secrets-env-manager/ SKILL.md +242 -0
- package/templates/db-management/backup-restore-runbook-generator/ SKILL.md +505 -0
- package/templates/db-management/data-integrity-auditor/ SKILL.md +505 -0
- package/templates/db-management/data-retention-archiving-planner/ SKILL.md +430 -0
- package/templates/db-management/data-seeding-fixtures-builder/ SKILL.md +375 -0
- package/templates/db-management/db-performance-watchlist/ SKILL.md +425 -0
- package/templates/db-management/etl-sync-job-builder/ SKILL.md +457 -0
- package/templates/db-management/multi-tenant-safety-checker/ SKILL.md +398 -0
- package/templates/db-management/prisma-migration-assistant/ SKILL.md +379 -0
- package/templates/db-management/schema-consistency-checker/ SKILL.md +440 -0
- package/templates/db-management/sql-query-optimizer/ SKILL.md +324 -0
- package/templates/foundation/changelog-writer/ SKILL.md +431 -0
- package/templates/foundation/code-formatter-installer/ SKILL.md +320 -0
- package/templates/foundation/codebase-summarizer/ SKILL.md +360 -0
- package/templates/foundation/dependency-doctor/ SKILL.md +163 -0
- package/templates/foundation/dev-environment-bootstrapper/ SKILL.md +259 -0
- package/templates/foundation/dev-onboarding-builder/ SKILL.md +556 -0
- package/templates/foundation/docs-starter-kit/ SKILL.md +574 -0
- package/templates/foundation/explaining-code/SKILL.md +13 -0
- package/templates/foundation/git-hygiene-enforcer/ SKILL.md +455 -0
- package/templates/foundation/project-scaffolder/ SKILL.md +65 -0
- package/templates/foundation/project-scaffolder/references/templates.md +126 -0
- package/templates/foundation/repo-structure-linter/ SKILL.md +0 -0
- package/templates/foundation/repo-structure-linter/references/conventions.md +98 -0
- package/templates/frontend/animation-micro-interaction-pack/ SKILL.md +41 -0
- package/templates/frontend/component-scaffold-generator/ SKILL.md +562 -0
- package/templates/frontend/design-to-component-translator/ SKILL.md +547 -0
- package/templates/frontend/form-wizard-builder/ SKILL.md +553 -0
- package/templates/frontend/frontend-refactor-planner/ SKILL.md +37 -0
- package/templates/frontend/i18n-frontend-implementer/ SKILL.md +44 -0
- package/templates/frontend/modal-drawer-system/ SKILL.md +377 -0
- package/templates/frontend/page-layout-builder/ SKILL.md +630 -0
- package/templates/frontend/state-ux-flow-builder/ SKILL.md +23 -0
- package/templates/frontend/table-builder/ SKILL.md +350 -0
- package/templates/performance/alerting-dashboard-builder/ SKILL.md +162 -0
- package/templates/performance/backend-latency-profiler-helper/ SKILL.md +108 -0
- package/templates/performance/caching-cdn-strategy-planner/ SKILL.md +150 -0
- package/templates/performance/capacity-planning-helper/ SKILL.md +242 -0
- package/templates/performance/core-web-vitals-tuner/ SKILL.md +126 -0
- package/templates/performance/incident-runbook-generator/ SKILL.md +162 -0
- package/templates/performance/load-test-scenario-builder/ SKILL.md +256 -0
- package/templates/performance/observability-setup/ SKILL.md +232 -0
- package/templates/performance/postmortem-writer/ SKILL.md +203 -0
- package/templates/performance/structured-logging-standardizer/ SKILL.md +122 -0
- package/templates/security/auth-security-reviewer/ SKILL.md +428 -0
- package/templates/security/dependency-vulnerability-triage/ SKILL.md +495 -0
- package/templates/security/input-validation-sanitization-auditor/ SKILL.md +76 -0
- package/templates/security/pii-redaction-logging-policy-builder/ SKILL.md +65 -0
- package/templates/security/rbac-policy-tester/ SKILL.md +80 -0
- package/templates/security/secrets-scanner/ SKILL.md +462 -0
- package/templates/security/secure-headers-csp-builder/ SKILL.md +404 -0
- package/templates/security/security-incident-playbook-generator/ SKILL.md +76 -0
- package/templates/security/security-pr-checklist-skill/ SKILL.md +62 -0
- package/templates/security/threat-model-generator/ SKILL.md +394 -0
- package/templates/testing/contract-testing-builder/ SKILL.md +492 -0
- package/templates/testing/coverage-strategist/ SKILL.md +436 -0
- package/templates/testing/e2e-test-builder/ SKILL.md +382 -0
- package/templates/testing/flaky-test-detective/ SKILL.md +416 -0
- package/templates/testing/integration-test-builder/ SKILL.md +525 -0
- package/templates/testing/mocking-assistant/ SKILL.md +383 -0
- package/templates/testing/snapshot-test-refactorer/ SKILL.md +375 -0
- package/templates/testing/test-data-factory-builder/ SKILL.md +449 -0
- package/templates/testing/test-reporting-triage-skill/ SKILL.md +469 -0
- package/templates/testing/unit-test-generator/ SKILL.md +548 -0
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: page-layout-builder
|
|
3
|
+
description: Generates complete page layouts and shells for common patterns (dashboard, authentication, settings, CRUD pages) with consistent navigation, layout components, routing structure, and state management placeholders. Use when building "new page", "dashboard layout", "auth pages", or "admin panel structure".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Page Layout Builder
|
|
7
|
+
|
|
8
|
+
Generate production-ready page layouts with routing, navigation, and state patterns.
|
|
9
|
+
|
|
10
|
+
## Core Workflow
|
|
11
|
+
|
|
12
|
+
1. **Choose page type**: Dashboard, auth, settings, CRUD, landing, etc.
|
|
13
|
+
2. **Setup routing**: Create route files with proper structure
|
|
14
|
+
3. **Build layout**: Header, sidebar, main content, footer
|
|
15
|
+
4. **Add navigation**: Nav menus, breadcrumbs, tabs
|
|
16
|
+
5. **State placeholders**: Data fetching, forms, modals
|
|
17
|
+
6. **Responsive design**: Mobile-first with breakpoints
|
|
18
|
+
7. **Loading states**: Skeletons and suspense boundaries
|
|
19
|
+
|
|
20
|
+
## Common Page Patterns
|
|
21
|
+
|
|
22
|
+
### Dashboard Layout
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// app/dashboard/layout.tsx
|
|
26
|
+
import { Sidebar } from "@/components/Sidebar";
|
|
27
|
+
import { Header } from "@/components/Header";
|
|
28
|
+
|
|
29
|
+
export default function DashboardLayout({
|
|
30
|
+
children,
|
|
31
|
+
}: {
|
|
32
|
+
children: React.ReactNode;
|
|
33
|
+
}) {
|
|
34
|
+
return (
|
|
35
|
+
<div className="flex h-screen bg-gray-50">
|
|
36
|
+
{/* Sidebar - Hidden on mobile, shown on desktop */}
|
|
37
|
+
<Sidebar className="hidden lg:flex lg:w-64 lg:flex-col" />
|
|
38
|
+
|
|
39
|
+
{/* Main Content Area */}
|
|
40
|
+
<div className="flex flex-1 flex-col overflow-hidden">
|
|
41
|
+
{/* Header */}
|
|
42
|
+
<Header />
|
|
43
|
+
|
|
44
|
+
{/* Page Content */}
|
|
45
|
+
<main className="flex-1 overflow-y-auto p-4 md:p-6 lg:p-8">
|
|
46
|
+
{children}
|
|
47
|
+
</main>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// app/dashboard/page.tsx
|
|
56
|
+
import { StatsCard } from "@/components/dashboard/StatsCard";
|
|
57
|
+
import { RecentActivity } from "@/components/dashboard/RecentActivity";
|
|
58
|
+
import { Chart } from "@/components/dashboard/Chart";
|
|
59
|
+
|
|
60
|
+
export default function DashboardPage() {
|
|
61
|
+
return (
|
|
62
|
+
<div className="space-y-6">
|
|
63
|
+
<div>
|
|
64
|
+
<h1 className="text-3xl font-bold">Dashboard</h1>
|
|
65
|
+
<p className="text-gray-600">Welcome back! Here's your overview.</p>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
{/* Stats Grid */}
|
|
69
|
+
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
70
|
+
<StatsCard title="Total Users" value="2,543" change="+12%" trend="up" />
|
|
71
|
+
<StatsCard title="Revenue" value="$45,231" change="+8%" trend="up" />
|
|
72
|
+
<StatsCard
|
|
73
|
+
title="Active Sessions"
|
|
74
|
+
value="431"
|
|
75
|
+
change="-3%"
|
|
76
|
+
trend="down"
|
|
77
|
+
/>
|
|
78
|
+
<StatsCard
|
|
79
|
+
title="Conversion Rate"
|
|
80
|
+
value="3.2%"
|
|
81
|
+
change="+0.5%"
|
|
82
|
+
trend="up"
|
|
83
|
+
/>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
{/* Charts and Activity */}
|
|
87
|
+
<div className="grid gap-6 md:grid-cols-2">
|
|
88
|
+
<Chart title="Revenue Over Time" />
|
|
89
|
+
<RecentActivity title="Recent Activity" />
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Authentication Pages
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// app/(auth)/layout.tsx
|
|
100
|
+
export default function AuthLayout({
|
|
101
|
+
children,
|
|
102
|
+
}: {
|
|
103
|
+
children: React.ReactNode;
|
|
104
|
+
}) {
|
|
105
|
+
return (
|
|
106
|
+
<div className="flex min-h-screen">
|
|
107
|
+
{/* Left side - Branding (hidden on mobile) */}
|
|
108
|
+
<div className="hidden lg:flex lg:w-1/2 lg:flex-col lg:justify-center lg:bg-primary-500 lg:p-12">
|
|
109
|
+
<div className="text-white">
|
|
110
|
+
<h1 className="text-4xl font-bold">Welcome to AppName</h1>
|
|
111
|
+
<p className="mt-4 text-lg text-primary-100">
|
|
112
|
+
The best platform for managing your workflow
|
|
113
|
+
</p>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
{/* Right side - Auth form */}
|
|
118
|
+
<div className="flex flex-1 flex-col justify-center px-4 py-12 sm:px-6 lg:px-20 xl:px-24">
|
|
119
|
+
<div className="mx-auto w-full max-w-sm">{children}</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// app/(auth)/login/page.tsx
|
|
128
|
+
"use client";
|
|
129
|
+
|
|
130
|
+
import { useState } from "react";
|
|
131
|
+
import { useRouter } from "next/navigation";
|
|
132
|
+
import { Button } from "@/components/ui/button";
|
|
133
|
+
import { Input } from "@/components/ui/input";
|
|
134
|
+
import { Label } from "@/components/ui/label";
|
|
135
|
+
import Link from "next/link";
|
|
136
|
+
|
|
137
|
+
export default function LoginPage() {
|
|
138
|
+
const router = useRouter();
|
|
139
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
140
|
+
|
|
141
|
+
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
142
|
+
e.preventDefault();
|
|
143
|
+
setIsLoading(true);
|
|
144
|
+
|
|
145
|
+
// TODO: Implement authentication logic
|
|
146
|
+
try {
|
|
147
|
+
// await signIn(formData);
|
|
148
|
+
router.push("/dashboard");
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.error("Login failed:", error);
|
|
151
|
+
} finally {
|
|
152
|
+
setIsLoading(false);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<div className="space-y-6">
|
|
158
|
+
<div className="space-y-2 text-center">
|
|
159
|
+
<h1 className="text-3xl font-bold">Sign In</h1>
|
|
160
|
+
<p className="text-gray-600">
|
|
161
|
+
Enter your credentials to access your account
|
|
162
|
+
</p>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
<form onSubmit={handleSubmit} className="space-y-4">
|
|
166
|
+
<div className="space-y-2">
|
|
167
|
+
<Label htmlFor="email">Email</Label>
|
|
168
|
+
<Input
|
|
169
|
+
id="email"
|
|
170
|
+
type="email"
|
|
171
|
+
placeholder="you@example.com"
|
|
172
|
+
required
|
|
173
|
+
/>
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
<div className="space-y-2">
|
|
177
|
+
<div className="flex items-center justify-between">
|
|
178
|
+
<Label htmlFor="password">Password</Label>
|
|
179
|
+
<Link
|
|
180
|
+
href="/forgot-password"
|
|
181
|
+
className="text-sm text-primary-600 hover:underline"
|
|
182
|
+
>
|
|
183
|
+
Forgot password?
|
|
184
|
+
</Link>
|
|
185
|
+
</div>
|
|
186
|
+
<Input
|
|
187
|
+
id="password"
|
|
188
|
+
type="password"
|
|
189
|
+
placeholder="••••••••"
|
|
190
|
+
required
|
|
191
|
+
/>
|
|
192
|
+
</div>
|
|
193
|
+
|
|
194
|
+
<Button type="submit" className="w-full" isLoading={isLoading}>
|
|
195
|
+
Sign In
|
|
196
|
+
</Button>
|
|
197
|
+
</form>
|
|
198
|
+
|
|
199
|
+
<div className="text-center text-sm">
|
|
200
|
+
Don't have an account?{" "}
|
|
201
|
+
<Link href="/register" className="text-primary-600 hover:underline">
|
|
202
|
+
Sign up
|
|
203
|
+
</Link>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Settings/Profile Page
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// app/settings/layout.tsx
|
|
214
|
+
import { SettingsSidebar } from "@/components/settings/SettingsSidebar";
|
|
215
|
+
|
|
216
|
+
export default function SettingsLayout({
|
|
217
|
+
children,
|
|
218
|
+
}: {
|
|
219
|
+
children: React.ReactNode;
|
|
220
|
+
}) {
|
|
221
|
+
return (
|
|
222
|
+
<div className="container mx-auto py-6">
|
|
223
|
+
<div className="mb-6">
|
|
224
|
+
<h1 className="text-3xl font-bold">Settings</h1>
|
|
225
|
+
<p className="text-gray-600">
|
|
226
|
+
Manage your account settings and preferences
|
|
227
|
+
</p>
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
<div className="flex flex-col gap-6 lg:flex-row">
|
|
231
|
+
<SettingsSidebar className="lg:w-64" />
|
|
232
|
+
<div className="flex-1">{children}</div>
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// app/settings/profile/page.tsx
|
|
241
|
+
"use client";
|
|
242
|
+
|
|
243
|
+
import { useState } from "react";
|
|
244
|
+
import { Button } from "@/components/ui/button";
|
|
245
|
+
import { Input } from "@/components/ui/input";
|
|
246
|
+
import { Label } from "@/components/ui/label";
|
|
247
|
+
import { Card } from "@/components/ui/card";
|
|
248
|
+
|
|
249
|
+
export default function ProfileSettingsPage() {
|
|
250
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
251
|
+
|
|
252
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
253
|
+
e.preventDefault();
|
|
254
|
+
setIsSaving(true);
|
|
255
|
+
|
|
256
|
+
// TODO: Save profile changes
|
|
257
|
+
|
|
258
|
+
setIsSaving(false);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<div className="space-y-6">
|
|
263
|
+
<Card className="p-6">
|
|
264
|
+
<form onSubmit={handleSubmit} className="space-y-6">
|
|
265
|
+
<div>
|
|
266
|
+
<h2 className="text-xl font-semibold">Profile Information</h2>
|
|
267
|
+
<p className="text-sm text-gray-600">
|
|
268
|
+
Update your account's profile information and email address
|
|
269
|
+
</p>
|
|
270
|
+
</div>
|
|
271
|
+
|
|
272
|
+
<div className="space-y-4">
|
|
273
|
+
<div className="space-y-2">
|
|
274
|
+
<Label htmlFor="name">Name</Label>
|
|
275
|
+
<Input id="name" placeholder="Your name" />
|
|
276
|
+
</div>
|
|
277
|
+
|
|
278
|
+
<div className="space-y-2">
|
|
279
|
+
<Label htmlFor="email">Email</Label>
|
|
280
|
+
<Input id="email" type="email" placeholder="you@example.com" />
|
|
281
|
+
</div>
|
|
282
|
+
|
|
283
|
+
<div className="space-y-2">
|
|
284
|
+
<Label htmlFor="bio">Bio</Label>
|
|
285
|
+
<textarea
|
|
286
|
+
id="bio"
|
|
287
|
+
rows={4}
|
|
288
|
+
className="w-full rounded-md border border-gray-300 p-3"
|
|
289
|
+
placeholder="Tell us about yourself"
|
|
290
|
+
/>
|
|
291
|
+
</div>
|
|
292
|
+
</div>
|
|
293
|
+
|
|
294
|
+
<div className="flex justify-end">
|
|
295
|
+
<Button type="submit" isLoading={isSaving}>
|
|
296
|
+
Save Changes
|
|
297
|
+
</Button>
|
|
298
|
+
</div>
|
|
299
|
+
</form>
|
|
300
|
+
</Card>
|
|
301
|
+
</div>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### CRUD Page (List/Create/Edit/Delete)
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
// app/users/page.tsx
|
|
310
|
+
"use client";
|
|
311
|
+
|
|
312
|
+
import { useState } from "react";
|
|
313
|
+
import { Button } from "@/components/ui/button";
|
|
314
|
+
import { Input } from "@/components/ui/input";
|
|
315
|
+
import { Table } from "@/components/ui/table";
|
|
316
|
+
import { CreateUserModal } from "@/components/users/CreateUserModal";
|
|
317
|
+
import { DeleteConfirmDialog } from "@/components/ui/DeleteConfirmDialog";
|
|
318
|
+
|
|
319
|
+
export default function UsersPage() {
|
|
320
|
+
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
|
321
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
322
|
+
|
|
323
|
+
return (
|
|
324
|
+
<div className="space-y-6">
|
|
325
|
+
{/* Header */}
|
|
326
|
+
<div className="flex items-center justify-between">
|
|
327
|
+
<div>
|
|
328
|
+
<h1 className="text-3xl font-bold">Users</h1>
|
|
329
|
+
<p className="text-gray-600">Manage your team members</p>
|
|
330
|
+
</div>
|
|
331
|
+
<Button onClick={() => setIsCreateModalOpen(true)}>Add User</Button>
|
|
332
|
+
</div>
|
|
333
|
+
|
|
334
|
+
{/* Filters */}
|
|
335
|
+
<div className="flex gap-4">
|
|
336
|
+
<Input
|
|
337
|
+
placeholder="Search users..."
|
|
338
|
+
value={searchQuery}
|
|
339
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
340
|
+
className="max-w-sm"
|
|
341
|
+
/>
|
|
342
|
+
</div>
|
|
343
|
+
|
|
344
|
+
{/* Table */}
|
|
345
|
+
<div className="rounded-lg border">
|
|
346
|
+
{/* TODO: Implement table with data */}
|
|
347
|
+
</div>
|
|
348
|
+
|
|
349
|
+
{/* Modals */}
|
|
350
|
+
<CreateUserModal
|
|
351
|
+
isOpen={isCreateModalOpen}
|
|
352
|
+
onClose={() => setIsCreateModalOpen(false)}
|
|
353
|
+
/>
|
|
354
|
+
</div>
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Navigation Components
|
|
360
|
+
|
|
361
|
+
### Sidebar Navigation
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
// components/Sidebar.tsx
|
|
365
|
+
"use client";
|
|
366
|
+
|
|
367
|
+
import Link from "next/link";
|
|
368
|
+
import { usePathname } from "next/navigation";
|
|
369
|
+
import { cn } from "@/lib/utils";
|
|
370
|
+
import {
|
|
371
|
+
HomeIcon,
|
|
372
|
+
UsersIcon,
|
|
373
|
+
SettingsIcon,
|
|
374
|
+
ChartBarIcon,
|
|
375
|
+
} from "@/components/icons";
|
|
376
|
+
|
|
377
|
+
const navigation = [
|
|
378
|
+
{ name: "Dashboard", href: "/dashboard", icon: HomeIcon },
|
|
379
|
+
{ name: "Users", href: "/users", icon: UsersIcon },
|
|
380
|
+
{ name: "Analytics", href: "/analytics", icon: ChartBarIcon },
|
|
381
|
+
{ name: "Settings", href: "/settings", icon: SettingsIcon },
|
|
382
|
+
];
|
|
383
|
+
|
|
384
|
+
export function Sidebar({ className }: { className?: string }) {
|
|
385
|
+
const pathname = usePathname();
|
|
386
|
+
|
|
387
|
+
return (
|
|
388
|
+
<aside className={cn("border-r bg-white", className)}>
|
|
389
|
+
<div className="flex h-16 items-center px-6">
|
|
390
|
+
<span className="text-xl font-bold">AppName</span>
|
|
391
|
+
</div>
|
|
392
|
+
|
|
393
|
+
<nav className="space-y-1 px-3">
|
|
394
|
+
{navigation.map((item) => {
|
|
395
|
+
const isActive = pathname === item.href;
|
|
396
|
+
return (
|
|
397
|
+
<Link
|
|
398
|
+
key={item.name}
|
|
399
|
+
href={item.href}
|
|
400
|
+
className={cn(
|
|
401
|
+
"flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors",
|
|
402
|
+
isActive
|
|
403
|
+
? "bg-primary-50 text-primary-600"
|
|
404
|
+
: "text-gray-700 hover:bg-gray-100"
|
|
405
|
+
)}
|
|
406
|
+
>
|
|
407
|
+
<item.icon className="h-5 w-5" />
|
|
408
|
+
{item.name}
|
|
409
|
+
</Link>
|
|
410
|
+
);
|
|
411
|
+
})}
|
|
412
|
+
</nav>
|
|
413
|
+
</aside>
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Header with User Menu
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
// components/Header.tsx
|
|
422
|
+
"use client";
|
|
423
|
+
|
|
424
|
+
import { Button } from "@/components/ui/button";
|
|
425
|
+
import { Avatar } from "@/components/ui/avatar";
|
|
426
|
+
import { DropdownMenu } from "@/components/ui/dropdown-menu";
|
|
427
|
+
import { BellIcon, MenuIcon } from "@/components/icons";
|
|
428
|
+
|
|
429
|
+
export function Header() {
|
|
430
|
+
return (
|
|
431
|
+
<header className="flex h-16 items-center justify-between border-b bg-white px-4 md:px-6">
|
|
432
|
+
{/* Mobile menu button */}
|
|
433
|
+
<Button variant="ghost" size="icon" className="lg:hidden">
|
|
434
|
+
<MenuIcon className="h-6 w-6" />
|
|
435
|
+
</Button>
|
|
436
|
+
|
|
437
|
+
{/* Search (optional) */}
|
|
438
|
+
<div className="flex-1 px-4">{/* Search component */}</div>
|
|
439
|
+
|
|
440
|
+
{/* Right side actions */}
|
|
441
|
+
<div className="flex items-center gap-4">
|
|
442
|
+
<Button variant="ghost" size="icon">
|
|
443
|
+
<BellIcon className="h-5 w-5" />
|
|
444
|
+
</Button>
|
|
445
|
+
|
|
446
|
+
<DropdownMenu>
|
|
447
|
+
<Avatar src="/avatar.jpg" alt="User" />
|
|
448
|
+
</DropdownMenu>
|
|
449
|
+
</div>
|
|
450
|
+
</header>
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
## Routing Structure
|
|
456
|
+
|
|
457
|
+
### Next.js App Router
|
|
458
|
+
|
|
459
|
+
```
|
|
460
|
+
app/
|
|
461
|
+
├── (auth)/ # Auth group (no dashboard layout)
|
|
462
|
+
│ ├── layout.tsx
|
|
463
|
+
│ ├── login/
|
|
464
|
+
│ │ └── page.tsx
|
|
465
|
+
│ ├── register/
|
|
466
|
+
│ │ └── page.tsx
|
|
467
|
+
│ └── forgot-password/
|
|
468
|
+
│ └── page.tsx
|
|
469
|
+
├── dashboard/ # Dashboard section
|
|
470
|
+
│ ├── layout.tsx
|
|
471
|
+
│ └── page.tsx
|
|
472
|
+
├── users/ # CRUD section
|
|
473
|
+
│ ├── page.tsx # List
|
|
474
|
+
│ ├── [id]/
|
|
475
|
+
│ │ ├── page.tsx # Detail/Edit
|
|
476
|
+
│ │ └── loading.tsx
|
|
477
|
+
│ └── new/
|
|
478
|
+
│ └── page.tsx # Create
|
|
479
|
+
├── settings/ # Settings section
|
|
480
|
+
│ ├── layout.tsx
|
|
481
|
+
│ ├── profile/
|
|
482
|
+
│ │ └── page.tsx
|
|
483
|
+
│ ├── security/
|
|
484
|
+
│ │ └── page.tsx
|
|
485
|
+
│ └── notifications/
|
|
486
|
+
│ └── page.tsx
|
|
487
|
+
└── layout.tsx # Root layout
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## State Management Patterns
|
|
491
|
+
|
|
492
|
+
### Data Fetching Pattern
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
// app/users/page.tsx
|
|
496
|
+
import { Suspense } from "react";
|
|
497
|
+
import { UsersTable } from "@/components/users/UsersTable";
|
|
498
|
+
import { UsersTableSkeleton } from "@/components/users/UsersTableSkeleton";
|
|
499
|
+
|
|
500
|
+
async function getUsers() {
|
|
501
|
+
// Server-side data fetching
|
|
502
|
+
const res = await fetch("https://api.example.com/users", {
|
|
503
|
+
cache: "no-store",
|
|
504
|
+
});
|
|
505
|
+
return res.json();
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export default async function UsersPage() {
|
|
509
|
+
const users = await getUsers();
|
|
510
|
+
|
|
511
|
+
return (
|
|
512
|
+
<div className="space-y-6">
|
|
513
|
+
<h1 className="text-3xl font-bold">Users</h1>
|
|
514
|
+
|
|
515
|
+
<Suspense fallback={<UsersTableSkeleton />}>
|
|
516
|
+
<UsersTable data={users} />
|
|
517
|
+
</Suspense>
|
|
518
|
+
</div>
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Client-Side State
|
|
524
|
+
|
|
525
|
+
```typescript
|
|
526
|
+
"use client";
|
|
527
|
+
|
|
528
|
+
import { useState, useEffect } from "react";
|
|
529
|
+
import { useUsers } from "@/hooks/useUsers";
|
|
530
|
+
|
|
531
|
+
export default function UsersPage() {
|
|
532
|
+
const { users, isLoading, error } = useUsers();
|
|
533
|
+
const [selectedUser, setSelectedUser] = useState(null);
|
|
534
|
+
|
|
535
|
+
if (isLoading) return <LoadingState />;
|
|
536
|
+
if (error) return <ErrorState error={error} />;
|
|
537
|
+
|
|
538
|
+
return <div>{/* Page content */}</div>;
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
## Loading States
|
|
543
|
+
|
|
544
|
+
### Skeleton Screens
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
// components/dashboard/DashboardSkeleton.tsx
|
|
548
|
+
export function DashboardSkeleton() {
|
|
549
|
+
return (
|
|
550
|
+
<div className="space-y-6 animate-pulse">
|
|
551
|
+
<div className="h-8 w-48 bg-gray-200 rounded" />
|
|
552
|
+
|
|
553
|
+
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
554
|
+
{Array.from({ length: 4 }).map((_, i) => (
|
|
555
|
+
<div key={i} className="h-32 bg-gray-200 rounded-lg" />
|
|
556
|
+
))}
|
|
557
|
+
</div>
|
|
558
|
+
|
|
559
|
+
<div className="grid gap-6 md:grid-cols-2">
|
|
560
|
+
<div className="h-64 bg-gray-200 rounded-lg" />
|
|
561
|
+
<div className="h-64 bg-gray-200 rounded-lg" />
|
|
562
|
+
</div>
|
|
563
|
+
</div>
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Loading Component
|
|
569
|
+
|
|
570
|
+
```typescript
|
|
571
|
+
// app/dashboard/loading.tsx
|
|
572
|
+
import { DashboardSkeleton } from "@/components/dashboard/DashboardSkeleton";
|
|
573
|
+
|
|
574
|
+
export default function Loading() {
|
|
575
|
+
return <DashboardSkeleton />;
|
|
576
|
+
}
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
## Responsive Patterns
|
|
580
|
+
|
|
581
|
+
### Mobile Navigation
|
|
582
|
+
|
|
583
|
+
```typescript
|
|
584
|
+
"use client";
|
|
585
|
+
|
|
586
|
+
import { useState } from "react";
|
|
587
|
+
import { Sheet } from "@/components/ui/sheet";
|
|
588
|
+
|
|
589
|
+
export function MobileNav() {
|
|
590
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
591
|
+
|
|
592
|
+
return (
|
|
593
|
+
<>
|
|
594
|
+
<button onClick={() => setIsOpen(true)} className="lg:hidden">
|
|
595
|
+
<MenuIcon />
|
|
596
|
+
</button>
|
|
597
|
+
|
|
598
|
+
<Sheet isOpen={isOpen} onClose={() => setIsOpen(false)}>
|
|
599
|
+
<nav className="space-y-2 p-4">{/* Navigation items */}</nav>
|
|
600
|
+
</Sheet>
|
|
601
|
+
</>
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
## Best Practices
|
|
607
|
+
|
|
608
|
+
1. **Consistent layouts**: Use layout files for shared structure
|
|
609
|
+
2. **Route groups**: Organize related pages with (groupName)
|
|
610
|
+
3. **Loading states**: Add loading.tsx for automatic suspense
|
|
611
|
+
4. **Error boundaries**: Add error.tsx for error handling
|
|
612
|
+
5. **Mobile-first**: Design for mobile, enhance for desktop
|
|
613
|
+
6. **Accessibility**: Semantic HTML, ARIA labels, keyboard nav
|
|
614
|
+
7. **SEO**: Use metadata, proper heading hierarchy
|
|
615
|
+
8. **Performance**: Code splitting, lazy loading, optimized images
|
|
616
|
+
|
|
617
|
+
## Output Checklist
|
|
618
|
+
|
|
619
|
+
Every page layout should include:
|
|
620
|
+
|
|
621
|
+
- [ ] Proper route structure with layout files
|
|
622
|
+
- [ ] Responsive navigation (sidebar + mobile menu)
|
|
623
|
+
- [ ] Header with actions
|
|
624
|
+
- [ ] Main content area with proper spacing
|
|
625
|
+
- [ ] Loading states (skeletons)
|
|
626
|
+
- [ ] Empty states
|
|
627
|
+
- [ ] Error boundaries
|
|
628
|
+
- [ ] State management placeholders
|
|
629
|
+
- [ ] Breadcrumbs or page headers
|
|
630
|
+
- [ ] Mobile-responsive breakpoints
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: state-ux-flow-builder
|
|
3
|
+
description: Standardizes UX states for data fetching flows (loading, error, empty, success) and complex multi-view UI patterns. Provides state machine approach recommendations, loading skeletons, error boundaries, and empty state components. Use when implementing "loading states", "error handling", "empty states", or "state machines".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# State & UX Flow Builder
|
|
7
|
+
|
|
8
|
+
Create consistent UX flows for all application states: loading, error, empty, and success.
|
|
9
|
+
|
|
10
|
+
## Output Components
|
|
11
|
+
|
|
12
|
+
Every implementation includes: (1) Loading skeletons, (2) Error state with retry, (3) Empty state with action, (4) Success view, (5) Error boundary, (6) State management pattern (useState/XState/server).
|
|
13
|
+
|
|
14
|
+
## Key Patterns
|
|
15
|
+
|
|
16
|
+
**Data Fetching Flow**: Check loading → Handle error → Show empty → Display data
|
|
17
|
+
**State Machine**: XState for complex flows with multiple states and transitions
|
|
18
|
+
**Optimistic Updates**: Instant UI feedback with rollback on error
|
|
19
|
+
**Progressive Loading**: Show content incrementally as it loads
|
|
20
|
+
|
|
21
|
+
## Best Practices
|
|
22
|
+
|
|
23
|
+
Always handle all states, prefer skeletons over spinners, provide retry mechanisms, use consistent error/empty UI, add ARIA live regions, implement error boundaries.
|