@donotdev/cli 0.0.6 → 0.0.8

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 (87) hide show
  1. package/README.md +3 -18
  2. package/dependencies-matrix.json +64 -121
  3. package/dist/bin/commands/build.js +173 -161
  4. package/dist/bin/commands/bump.js +181 -156
  5. package/dist/bin/commands/cacheout.js +188 -171
  6. package/dist/bin/commands/create-app.js +213 -156
  7. package/dist/bin/commands/create-project.js +183 -154
  8. package/dist/bin/commands/deploy.js +491 -477
  9. package/dist/bin/commands/dev.js +176 -160
  10. package/dist/bin/commands/emu.js +181 -165
  11. package/dist/bin/commands/format.js +191 -174
  12. package/dist/bin/commands/lint.js +191 -171
  13. package/dist/bin/commands/preview.js +177 -161
  14. package/dist/bin/commands/sync-secrets.js +172 -158
  15. package/dist/bin/commands/wai.d.ts +11 -0
  16. package/dist/bin/commands/wai.d.ts.map +1 -0
  17. package/dist/bin/commands/wai.js +12 -0
  18. package/dist/bin/commands/wai.js.map +1 -0
  19. package/dist/bin/dndev.js +24 -24
  20. package/dist/bin/donotdev.js +24 -24
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +661 -669
  24. package/dist/index.js.map +1 -1
  25. package/package.json +1 -1
  26. package/templates/app-demo/src/config/app.ts.example +12 -0
  27. package/templates/app-next/src/config/app.ts.example +75 -48
  28. package/templates/app-vite/index.html.example +71 -37
  29. package/templates/app-vite/src/config/app.ts.example +75 -47
  30. package/templates/app-vite/src/pages/FormPageExample.tsx.example +152 -0
  31. package/templates/app-vite/src/pages/HomePage.tsx.example +81 -134
  32. package/templates/app-vite/src/pages/ListPageExample.tsx.example +88 -0
  33. package/templates/functions-firebase/build.mjs.example +8 -1
  34. package/templates/functions-firebase/functions-firebase/build.mjs.example +8 -1
  35. package/templates/functions-firebase/functions-firebase/src/index.ts.example +19 -25
  36. package/templates/functions-firebase/functions.config.js.example +35 -0
  37. package/templates/root-consumer/entities/ExampleEntity.ts.example +223 -0
  38. package/templates/root-consumer/entities/demo.ts.example +576 -0
  39. package/templates/root-consumer/entities/index.ts.example +15 -0
  40. package/templates/root-consumer/eslint.config.js.example +2 -80
  41. package/templates/root-consumer/guides/{AGENT_START_HERE.md.example → dndev/AGENT_START_HERE.md.example} +22 -0
  42. package/templates/root-consumer/guides/dndev/COMPONENTS_CRUD.md.example +231 -0
  43. package/templates/root-consumer/guides/{SETUP_AUTH.md.example → dndev/SETUP_AUTH.md.example} +30 -0
  44. package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +539 -0
  45. package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +116 -0
  46. package/templates/root-consumer/guides/{SETUP_I18N.md.example → dndev/SETUP_I18N.md.example} +46 -0
  47. package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +404 -0
  48. package/templates/root-consumer/guides/wai-way/agents/architect.md.example +78 -0
  49. package/templates/root-consumer/guides/wai-way/agents/builder.md.example +87 -0
  50. package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +325 -0
  51. package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +100 -0
  52. package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +281 -0
  53. package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +77 -0
  54. package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +104 -0
  55. package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +124 -0
  56. package/templates/root-consumer/guides/wai-way/blueprints/4_configure.md.example +165 -0
  57. package/templates/root-consumer/guides/wai-way/context_map.json.example +95 -0
  58. package/templates/root-consumer/guides/wai-way/entity_patterns.md.example +840 -0
  59. package/templates/root-consumer/guides/wai-way/page_patterns.md.example +686 -0
  60. package/templates/root-consumer/guides/wai-way/presets_guide.md.example +217 -0
  61. package/templates/root-consumer/guides/wai-way/spec_template.md.example +312 -0
  62. package/templates/functions-firebase/functions-firebase/src/crud/createEntity.ts.example +0 -19
  63. package/templates/functions-firebase/functions-firebase/src/crud/deleteEntity.ts.example +0 -14
  64. package/templates/functions-firebase/functions-firebase/src/crud/getEntity.ts.example +0 -14
  65. package/templates/functions-firebase/functions-firebase/src/crud/index.ts.example +0 -12
  66. package/templates/functions-firebase/functions-firebase/src/crud/listEntities.ts.example +0 -14
  67. package/templates/functions-firebase/functions-firebase/src/crud/updateEntity.ts.example +0 -14
  68. package/templates/root-consumer/guides/COMPONENTS_CRUD.md.example +0 -70
  69. package/templates/root-consumer/guides/SETUP_CRUD.md.example +0 -1244
  70. package/templates/root-consumer/guides/SETUP_FUNCTIONS.md.example +0 -114
  71. /package/templates/root-consumer/guides/{COMPONENTS_ADV.md.example → dndev/COMPONENTS_ADV.md.example} +0 -0
  72. /package/templates/root-consumer/guides/{COMPONENTS_ATOMIC.md.example → dndev/COMPONENTS_ATOMIC.md.example} +0 -0
  73. /package/templates/root-consumer/guides/{COMPONENTS_UI.md.example → dndev/COMPONENTS_UI.md.example} +0 -0
  74. /package/templates/root-consumer/guides/{ENV_SETUP.md.example → dndev/ENV_SETUP.md.example} +0 -0
  75. /package/templates/root-consumer/guides/{INDEX.md.example → dndev/INDEX.md.example} +0 -0
  76. /package/templates/root-consumer/guides/{SETUP_APP_CONFIG.md.example → dndev/SETUP_APP_CONFIG.md.example} +0 -0
  77. /package/templates/root-consumer/guides/{SETUP_BILLING.md.example → dndev/SETUP_BILLING.md.example} +0 -0
  78. /package/templates/root-consumer/guides/{SETUP_LAYOUTS.md.example → dndev/SETUP_LAYOUTS.md.example} +0 -0
  79. /package/templates/root-consumer/guides/{SETUP_OAUTH.md.example → dndev/SETUP_OAUTH.md.example} +0 -0
  80. /package/templates/root-consumer/guides/{SETUP_PAGES.md.example → dndev/SETUP_PAGES.md.example} +0 -0
  81. /package/templates/root-consumer/guides/{SETUP_PWA.md.example → dndev/SETUP_PWA.md.example} +0 -0
  82. /package/templates/root-consumer/guides/{SETUP_THEMES.md.example → dndev/SETUP_THEMES.md.example} +0 -0
  83. /package/templates/root-consumer/guides/{USE_ROUTING.md.example → dndev/USE_ROUTING.md.example} +0 -0
  84. /package/templates/root-consumer/guides/{advanced → dndev/advanced}/APP_CHECK.md.example +0 -0
  85. /package/templates/root-consumer/guides/{advanced → dndev/advanced}/COOKIE_REFERENCE.md.example +0 -0
  86. /package/templates/root-consumer/guides/{advanced → dndev/advanced}/EMULATORS.md.example +0 -0
  87. /package/templates/root-consumer/guides/{advanced → dndev/advanced}/VERSION_CONTROL.md.example +0 -0
@@ -0,0 +1,686 @@
1
+ # Page Pattern Catalog
2
+
3
+ > **Don't invent page structures. Copy patterns, customize content.**
4
+
5
+ ---
6
+
7
+ ## Pattern Index
8
+
9
+ | Pattern | Use For | Key Components |
10
+ |---------|---------|----------------|
11
+ | [Dashboard](#dashboard) | Main logged-in view, stats, quick actions | Section, Grid, Card, ActionCard |
12
+ | [List Page](#list-page) | Entity CRUD table | EntityList |
13
+ | [Form Page](#form-page) | Entity create/edit | EntityFormRenderer |
14
+ | [Landing/Home](#landinghome) | Marketing, conversion | HeroSection, Section, Card, CTA |
15
+ | [Pricing](#pricing) | Plan comparison | PricingTable, Section |
16
+ | [Settings](#settings) | User preferences | Section, form components |
17
+ | [Profile](#profile) | User profile display/edit | Section, Card, Avatar |
18
+ | [Detail Page](#detail-page) | Single item display (non-edit) | Section, Card, Grid |
19
+ | [Analytics](#analytics) | Charts and metrics | Section, Grid, Card, charts |
20
+
21
+ ---
22
+
23
+ ## Dashboard
24
+
25
+ **Main logged-in view with KPIs, quick actions, alerts.**
26
+
27
+ ```tsx
28
+ import { useEffect, useState } from 'react';
29
+ import { PageContainer, Loader, useNavigate } from '@donotdev/ui';
30
+ import { Section, Card, Grid, Stack, Button, Text, Badge } from '@donotdev/components';
31
+ import type { PageMeta } from '@donotdev/core';
32
+ import { ChartBar, Plus, ArrowRight } from 'lucide-react';
33
+
34
+ export const NAMESPACE = 'dashboard';
35
+
36
+ export const meta: PageMeta = {
37
+ namespace: NAMESPACE,
38
+ icon: <ChartBar />,
39
+ auth: { required: true },
40
+ };
41
+
42
+ export default function DashboardPage() {
43
+ const navigate = useNavigate();
44
+ const [metrics, setMetrics] = useState<any>(null);
45
+ const [loading, setLoading] = useState(true);
46
+
47
+ useEffect(() => {
48
+ // Fetch dashboard metrics from API/function
49
+ fetchMetrics().then(setMetrics).finally(() => setLoading(false));
50
+ }, []);
51
+
52
+ return (
53
+ <PageContainer>
54
+ {/* Quick Actions */}
55
+ <Section title="Quick Actions" gridCols={[2, 2, 4, 4]}>
56
+ <Card
57
+ clickable
58
+ onClick={() => navigate('/items/new')}
59
+ icon={Plus}
60
+ title="Add New Item"
61
+ />
62
+ {/* More action cards... */}
63
+ </Section>
64
+
65
+ {/* KPI Cards */}
66
+ <Section title="Overview" gridCols={[1, 2, 3, 3]}>
67
+ <Card variant="glass" title="Total Items">
68
+ {loading ? <Loader /> : (
69
+ <Text level="h2">{metrics?.totalItems ?? 0}</Text>
70
+ )}
71
+ </Card>
72
+ {/* More KPI cards... */}
73
+ </Section>
74
+
75
+ {/* Alerts/Actions Needed */}
76
+ {metrics?.needsAttention > 0 && (
77
+ <Section title="Needs Attention">
78
+ <Card variant="secondary">
79
+ <Stack direction="row" justify="between" align="center">
80
+ <Text>{metrics.needsAttention} items need review</Text>
81
+ <Button variant="outline" onClick={() => navigate('/items?filter=attention')}>
82
+ View <ArrowRight size={16} />
83
+ </Button>
84
+ </Stack>
85
+ </Card>
86
+ </Section>
87
+ )}
88
+ </PageContainer>
89
+ );
90
+ }
91
+ ```
92
+
93
+ **Key patterns:**
94
+ - Quick actions at top (cards with onClick)
95
+ - KPI cards in grid
96
+ - Alert/attention sections with actions
97
+ - Loading states with `<Loader />`
98
+
99
+ ---
100
+
101
+ ## List Page
102
+
103
+ **Entity CRUD table with search, filter, pagination.**
104
+
105
+ ```tsx
106
+ import { Car } from 'lucide-react';
107
+ import { EntityList } from '@donotdev/crud';
108
+ import { useAuth } from '@donotdev/auth';
109
+ import type { PageMeta } from '@donotdev/core';
110
+ import { PageContainer } from '@donotdev/ui';
111
+ import { carEntity } from 'entities/car';
112
+
113
+ export const NAMESPACE = 'cars';
114
+
115
+ export const meta: PageMeta = {
116
+ namespace: NAMESPACE,
117
+ auth: { required: true, role: 'admin' },
118
+ route: '/cars',
119
+ icon: <Car />,
120
+ };
121
+
122
+ export default function CarsListPage() {
123
+ const user = useAuth('user');
124
+
125
+ return (
126
+ <PageContainer>
127
+ <EntityList
128
+ entity={carEntity}
129
+ userRole={user?.role}
130
+ />
131
+ </PageContainer>
132
+ );
133
+ }
134
+ ```
135
+
136
+ **Key patterns:**
137
+ - Minimal code - `EntityList` handles everything
138
+ - Pass `userRole` for column filtering
139
+ - Route matches collection (e.g., `/cars` for `cars` collection)
140
+
141
+ ---
142
+
143
+ ## Form Page
144
+
145
+ **Entity create/edit form.**
146
+
147
+ ```tsx
148
+ import { useEffect, useState } from 'react';
149
+ import { PageContainer, Link, useNavigate } from '@donotdev/ui';
150
+ import { Section, Button, Alert } from '@donotdev/components';
151
+ import { EntityFormRenderer, useCrud } from '@donotdev/crud';
152
+ import { carEntity } from 'entities/car';
153
+ import { useTranslation } from '@donotdev/core';
154
+ import type { PageMeta } from '@donotdev/core';
155
+ import { useParams } from '@donotdev/ui/routing';
156
+
157
+ export const NAMESPACE = 'car';
158
+
159
+ export const meta: PageMeta = {
160
+ namespace: NAMESPACE,
161
+ route: '/cars/:id',
162
+ auth: { required: true, role: 'admin' },
163
+ hideFromMenu: true, // Don't show in nav
164
+ };
165
+
166
+ export default function CarPage() {
167
+ const { t } = useTranslation(NAMESPACE);
168
+ const { id } = useParams<{ id: string }>();
169
+ const navigate = useNavigate();
170
+ const isNew = id === 'new';
171
+
172
+ const { get, add, update, error } = useCrud(carEntity);
173
+ const [data, setData] = useState<any>(null);
174
+
175
+ // Fetch existing data for edit mode
176
+ useEffect(() => {
177
+ if (!isNew && id) {
178
+ get(id).then(setData);
179
+ }
180
+ }, [id, isNew, get]);
181
+
182
+ const handleSubmit = async (formData: any) => {
183
+ if (isNew) {
184
+ add(formData);
185
+ } else if (id) {
186
+ update(id, formData);
187
+ }
188
+ navigate('/cars');
189
+ };
190
+
191
+ // Error state
192
+ if (!isNew && error) {
193
+ return (
194
+ <PageContainer>
195
+ <Section title="Error">
196
+ <Alert variant="error" description="Failed to load data" />
197
+ <Link path="/cars">
198
+ <Button variant="outline">Back to list</Button>
199
+ </Link>
200
+ </Section>
201
+ </PageContainer>
202
+ );
203
+ }
204
+
205
+ return (
206
+ <PageContainer>
207
+ <Section title={isNew ? 'Create Car' : 'Edit Car'}>
208
+ {isNew ? (
209
+ <EntityFormRenderer
210
+ entity={carEntity}
211
+ operation="create"
212
+ onSubmit={handleSubmit}
213
+ defaultValues={{ status: 'draft' }}
214
+ submitText="Create"
215
+ />
216
+ ) : (
217
+ <EntityFormRenderer
218
+ entity={carEntity}
219
+ operation="edit"
220
+ onSubmit={handleSubmit}
221
+ defaultValues={data}
222
+ submitText="Update"
223
+ />
224
+ )}
225
+ </Section>
226
+ </PageContainer>
227
+ );
228
+ }
229
+ ```
230
+
231
+ **Key patterns:**
232
+ - Route: `/[collection]/:id` where `id` can be "new"
233
+ - `hideFromMenu: true` - form pages don't show in nav
234
+ - Check `isNew` to determine create vs edit
235
+ - Don't mount form until data loaded (edit mode)
236
+ - Optimistic: navigate immediately, don't await
237
+
238
+ ---
239
+
240
+ ## Landing/Home
241
+
242
+ **Marketing page with hero, features, CTA.**
243
+
244
+ ```tsx
245
+ import { PageContainer, useNavigate } from '@donotdev/ui';
246
+ import { HeroSection, Section, Card, Grid, Button } from '@donotdev/components';
247
+ import type { PageMeta } from '@donotdev/core';
248
+ import { Home } from 'lucide-react';
249
+
250
+ export const NAMESPACE = 'home';
251
+
252
+ export const meta: PageMeta = {
253
+ namespace: NAMESPACE,
254
+ icon: <Home />,
255
+ // No auth - public page
256
+ };
257
+
258
+ export default function HomePage() {
259
+ const navigate = useNavigate();
260
+
261
+ return (
262
+ <PageContainer>
263
+ <HeroSection
264
+ title="Your App Name"
265
+ subtitle="One-line value proposition"
266
+ primaryAction={{
267
+ label: "Get Started",
268
+ onClick: () => navigate('/signup'),
269
+ }}
270
+ secondaryAction={{
271
+ label: "Learn More",
272
+ onClick: () => navigate('/about'),
273
+ }}
274
+ />
275
+
276
+ <Section title="Features">
277
+ <Grid cols={[1, 2, 3, 3]} gap="large">
278
+ <Card
279
+ title="Feature One"
280
+ content="Brief description of the feature and its benefit."
281
+ />
282
+ <Card
283
+ title="Feature Two"
284
+ content="Brief description of the feature and its benefit."
285
+ />
286
+ <Card
287
+ title="Feature Three"
288
+ content="Brief description of the feature and its benefit."
289
+ />
290
+ </Grid>
291
+ </Section>
292
+
293
+ <Section title="How It Works">
294
+ <Grid cols={[1, 1, 3, 3]} gap="medium">
295
+ <Card title="1. Sign Up" content="Create your account in seconds." />
296
+ <Card title="2. Configure" content="Set up your preferences." />
297
+ <Card title="3. Launch" content="Start using immediately." />
298
+ </Grid>
299
+ </Section>
300
+
301
+ <Section>
302
+ <Card variant="primary" align="center">
303
+ <Text level="h2">Ready to get started?</Text>
304
+ <Button size="large" onClick={() => navigate('/signup')}>
305
+ Start Free Trial
306
+ </Button>
307
+ </Card>
308
+ </Section>
309
+ </PageContainer>
310
+ );
311
+ }
312
+ ```
313
+
314
+ **Key patterns:**
315
+ - `HeroSection` at top with CTAs
316
+ - Feature grid with `Card` components
317
+ - Final CTA section
318
+ - HARDCODE strings first, i18n later
319
+
320
+ ---
321
+
322
+ ## Pricing
323
+
324
+ **Plan comparison page.**
325
+
326
+ ```tsx
327
+ import { PageContainer, useNavigate } from '@donotdev/ui';
328
+ import { Section, PricingTable } from '@donotdev/components';
329
+ import type { PageMeta } from '@donotdev/core';
330
+ import { DollarSign } from 'lucide-react';
331
+
332
+ export const NAMESPACE = 'pricing';
333
+
334
+ export const meta: PageMeta = {
335
+ namespace: NAMESPACE,
336
+ icon: <DollarSign />,
337
+ };
338
+
339
+ export default function PricingPage() {
340
+ const navigate = useNavigate();
341
+
342
+ const plans = [
343
+ {
344
+ name: 'Free',
345
+ price: 0,
346
+ period: 'forever',
347
+ features: ['5 projects', 'Basic support', 'Community access'],
348
+ cta: { label: 'Get Started', onClick: () => navigate('/signup') },
349
+ },
350
+ {
351
+ name: 'Pro',
352
+ price: 29,
353
+ period: 'month',
354
+ features: ['Unlimited projects', 'Priority support', 'Advanced analytics'],
355
+ cta: { label: 'Start Trial', onClick: () => navigate('/signup?plan=pro') },
356
+ highlighted: true,
357
+ },
358
+ {
359
+ name: 'Enterprise',
360
+ price: 99,
361
+ period: 'month',
362
+ features: ['Everything in Pro', 'Dedicated support', 'Custom integrations'],
363
+ cta: { label: 'Contact Sales', onClick: () => navigate('/contact') },
364
+ },
365
+ ];
366
+
367
+ return (
368
+ <PageContainer>
369
+ <Section title="Choose Your Plan" align="center">
370
+ <PricingTable plans={plans} />
371
+ </Section>
372
+ </PageContainer>
373
+ );
374
+ }
375
+ ```
376
+
377
+ ---
378
+
379
+ ## Settings
380
+
381
+ **User preferences with grouped sections.**
382
+
383
+ ```tsx
384
+ import { PageContainer } from '@donotdev/ui';
385
+ import { Section, Card, Stack, Switch, Select, Button } from '@donotdev/components';
386
+ import type { PageMeta } from '@donotdev/core';
387
+ import { Settings as SettingsIcon } from 'lucide-react';
388
+
389
+ export const NAMESPACE = 'settings';
390
+
391
+ export const meta: PageMeta = {
392
+ namespace: NAMESPACE,
393
+ icon: <SettingsIcon />,
394
+ auth: { required: true },
395
+ };
396
+
397
+ export default function SettingsPage() {
398
+ return (
399
+ <PageContainer>
400
+ <Section title="Appearance">
401
+ <Card>
402
+ <Stack direction="row" justify="between" align="center">
403
+ <Text>Theme</Text>
404
+ <Select
405
+ options={[
406
+ { value: 'light', label: 'Light' },
407
+ { value: 'dark', label: 'Dark' },
408
+ { value: 'system', label: 'System' },
409
+ ]}
410
+ defaultValue="system"
411
+ />
412
+ </Stack>
413
+ </Card>
414
+ </Section>
415
+
416
+ <Section title="Notifications">
417
+ <Card>
418
+ <Stack direction="column" gap="medium">
419
+ <Stack direction="row" justify="between" align="center">
420
+ <Text>Email notifications</Text>
421
+ <Switch defaultChecked />
422
+ </Stack>
423
+ <Stack direction="row" justify="between" align="center">
424
+ <Text>Push notifications</Text>
425
+ <Switch />
426
+ </Stack>
427
+ </Stack>
428
+ </Card>
429
+ </Section>
430
+
431
+ <Section title="Danger Zone">
432
+ <Card variant="destructive">
433
+ <Stack direction="row" justify="between" align="center">
434
+ <Text>Delete account</Text>
435
+ <Button variant="destructive">Delete</Button>
436
+ </Stack>
437
+ </Card>
438
+ </Section>
439
+ </PageContainer>
440
+ );
441
+ }
442
+ ```
443
+
444
+ ---
445
+
446
+ ## Profile
447
+
448
+ **User profile display with edit.**
449
+
450
+ ```tsx
451
+ import { PageContainer } from '@donotdev/ui';
452
+ import { Section, Card, Stack, Text, Avatar, Button } from '@donotdev/components';
453
+ import { useAuth } from '@donotdev/auth';
454
+ import type { PageMeta } from '@donotdev/core';
455
+ import { User } from 'lucide-react';
456
+
457
+ export const NAMESPACE = 'profile';
458
+
459
+ export const meta: PageMeta = {
460
+ namespace: NAMESPACE,
461
+ icon: <User />,
462
+ auth: { required: true },
463
+ };
464
+
465
+ export default function ProfilePage() {
466
+ const user = useAuth('user');
467
+
468
+ return (
469
+ <PageContainer>
470
+ <Section>
471
+ <Card>
472
+ <Stack direction="row" gap="large" align="center">
473
+ <Avatar
474
+ src={user?.photoURL}
475
+ fallback={user?.displayName?.[0] || 'U'}
476
+ size="large"
477
+ />
478
+ <Stack direction="column" gap="tight">
479
+ <Text level="h2">{user?.displayName || 'User'}</Text>
480
+ <Text variant="muted">{user?.email}</Text>
481
+ </Stack>
482
+ </Stack>
483
+ </Card>
484
+ </Section>
485
+
486
+ <Section title="Account Details">
487
+ <Card>
488
+ <Stack direction="column" gap="medium">
489
+ <Stack direction="row" justify="between">
490
+ <Text variant="muted">Email</Text>
491
+ <Text>{user?.email}</Text>
492
+ </Stack>
493
+ <Stack direction="row" justify="between">
494
+ <Text variant="muted">Member since</Text>
495
+ <Text>{user?.createdAt?.toLocaleDateString()}</Text>
496
+ </Stack>
497
+ <Stack direction="row" justify="between">
498
+ <Text variant="muted">Role</Text>
499
+ <Text>{user?.role || 'user'}</Text>
500
+ </Stack>
501
+ </Stack>
502
+ </Card>
503
+ </Section>
504
+
505
+ <Section>
506
+ <Button variant="outline">Edit Profile</Button>
507
+ </Section>
508
+ </PageContainer>
509
+ );
510
+ }
511
+ ```
512
+
513
+ ---
514
+
515
+ ## Detail Page
516
+
517
+ **Single item display (read-only).**
518
+
519
+ ```tsx
520
+ import { useEffect, useState } from 'react';
521
+ import { PageContainer, Loader, useNavigate } from '@donotdev/ui';
522
+ import { Section, Card, Grid, Stack, Text, Button, Badge } from '@donotdev/components';
523
+ import { useCrud } from '@donotdev/crud';
524
+ import { productEntity } from 'entities/product';
525
+ import type { PageMeta } from '@donotdev/core';
526
+ import { useParams } from '@donotdev/ui/routing';
527
+
528
+ export const NAMESPACE = 'product-detail';
529
+
530
+ export const meta: PageMeta = {
531
+ namespace: NAMESPACE,
532
+ route: '/products/:id',
533
+ hideFromMenu: true,
534
+ };
535
+
536
+ export default function ProductDetailPage() {
537
+ const { id } = useParams<{ id: string }>();
538
+ const navigate = useNavigate();
539
+ const { get } = useCrud(productEntity);
540
+ const [product, setProduct] = useState<any>(null);
541
+ const [loading, setLoading] = useState(true);
542
+
543
+ useEffect(() => {
544
+ if (id) {
545
+ get(id).then(setProduct).finally(() => setLoading(false));
546
+ }
547
+ }, [id, get]);
548
+
549
+ if (loading) return <PageContainer><Loader /></PageContainer>;
550
+ if (!product) return <PageContainer><Text>Product not found</Text></PageContainer>;
551
+
552
+ return (
553
+ <PageContainer>
554
+ <Section>
555
+ <Grid cols={[1, 1, 2, 2]} gap="large">
556
+ {/* Image */}
557
+ <Card>
558
+ <img src={product.image} alt={product.name} />
559
+ </Card>
560
+
561
+ {/* Details */}
562
+ <Stack direction="column" gap="medium">
563
+ <Text level="h1">{product.name}</Text>
564
+ <Badge>{product.category}</Badge>
565
+ <Text level="h2">${product.price}</Text>
566
+ <Text>{product.description}</Text>
567
+ <Button onClick={() => navigate(`/admin/products/${id}`)}>
568
+ Edit
569
+ </Button>
570
+ </Stack>
571
+ </Grid>
572
+ </Section>
573
+ </PageContainer>
574
+ );
575
+ }
576
+ ```
577
+
578
+ ---
579
+
580
+ ## Analytics
581
+
582
+ **Charts and metrics display.**
583
+
584
+ ```tsx
585
+ import { useEffect, useState } from 'react';
586
+ import { PageContainer, Loader } from '@donotdev/ui';
587
+ import { Section, Card, Grid, Stack, Text } from '@donotdev/components';
588
+ import type { PageMeta } from '@donotdev/core';
589
+ import { TrendingUp } from 'lucide-react';
590
+
591
+ export const NAMESPACE = 'analytics';
592
+
593
+ export const meta: PageMeta = {
594
+ namespace: NAMESPACE,
595
+ icon: <TrendingUp />,
596
+ auth: { required: true, role: 'admin' },
597
+ };
598
+
599
+ export default function AnalyticsPage() {
600
+ const [data, setData] = useState<any>(null);
601
+ const [loading, setLoading] = useState(true);
602
+
603
+ useEffect(() => {
604
+ fetchAnalytics().then(setData).finally(() => setLoading(false));
605
+ }, []);
606
+
607
+ if (loading) return <PageContainer><Loader /></PageContainer>;
608
+
609
+ return (
610
+ <PageContainer>
611
+ {/* Summary Cards */}
612
+ <Section gridCols={[2, 4, 4, 4]}>
613
+ <Card variant="glass">
614
+ <Stack direction="column" gap="tight">
615
+ <Text variant="muted">Total Revenue</Text>
616
+ <Text level="h2">${data?.revenue?.toLocaleString()}</Text>
617
+ </Stack>
618
+ </Card>
619
+ <Card variant="glass">
620
+ <Stack direction="column" gap="tight">
621
+ <Text variant="muted">Orders</Text>
622
+ <Text level="h2">{data?.orders}</Text>
623
+ </Stack>
624
+ </Card>
625
+ {/* More cards... */}
626
+ </Section>
627
+
628
+ {/* Charts */}
629
+ <Section title="Revenue Over Time">
630
+ <Card>
631
+ {/* Your chart component here */}
632
+ <div style={{ height: 300 }}>Chart placeholder</div>
633
+ </Card>
634
+ </Section>
635
+
636
+ <Section title="Top Products" gridCols={[1, 2, 2, 2]}>
637
+ {data?.topProducts?.map((product: any) => (
638
+ <Card key={product.id}>
639
+ <Stack direction="row" justify="between">
640
+ <Text>{product.name}</Text>
641
+ <Text level="h4">{product.sales} sales</Text>
642
+ </Stack>
643
+ </Card>
644
+ ))}
645
+ </Section>
646
+ </PageContainer>
647
+ );
648
+ }
649
+ ```
650
+
651
+ ---
652
+
653
+ ## PageMeta Reference
654
+
655
+ Every page exports `meta: PageMeta`:
656
+
657
+ ```tsx
658
+ export const meta: PageMeta = {
659
+ namespace: 'page-name', // i18n namespace, required
660
+ icon: <IconComponent />, // lucide-react icon, shown in nav
661
+
662
+ // Auth options
663
+ auth: true, // Requires login
664
+ auth: { required: true }, // Same as above
665
+ auth: { required: true, role: 'admin' }, // Requires specific role
666
+
667
+ // Route options
668
+ route: '/custom-path', // Override auto-generated route
669
+ route: '/items/:id', // Dynamic route
670
+
671
+ // Navigation options
672
+ hideFromMenu: true, // Don't show in sidebar/nav
673
+ };
674
+ ```
675
+
676
+ ---
677
+
678
+ ## Usage
679
+
680
+ 1. **Find pattern** that matches your page type
681
+ 2. **Copy** the page component
682
+ 3. **Customize** content, entity, routes
683
+ 4. **Update** PageMeta for auth/nav requirements
684
+ 5. **HARDCODE** strings first, i18n later
685
+
686
+ **Do NOT invent new page structures unless none fit.**