@donotdev/cli 0.0.18 → 0.0.19
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/dependencies-matrix.json +55 -156
- package/dist/bin/commands/coach.js +8177 -0
- package/dist/bin/commands/create-app.js +5 -5
- package/dist/bin/commands/create-project.js +10 -7
- package/dist/bin/commands/deploy.js +81 -59
- package/dist/bin/commands/doctor.js +243 -698
- package/dist/bin/commands/emu.js +2 -2
- package/dist/bin/commands/format.js +4 -1
- package/dist/bin/commands/get-demo.js +8351 -0
- package/dist/bin/commands/make-admin.js +773 -152
- package/dist/bin/commands/setup.js +519 -1711
- package/dist/bin/commands/staging.js +17852 -0
- package/dist/bin/commands/sync-secrets.js +2 -11
- package/dist/bin/commands/type-check.js +7733 -1713
- package/dist/bin/dndev.js +913 -185
- package/dist/bin/donotdev.js +913 -185
- package/dist/index.js +96 -65
- package/package.json +1 -1
- package/templates/app-demo/index.html.example +147 -10
- package/templates/app-demo/src/App.tsx.example +7 -13
- package/templates/app-demo/src/config/app.ts.example +12 -48
- package/templates/app-demo/src/entities/product.ts.example +38 -0
- package/templates/app-demo/src/globals.css.example +5 -1
- package/templates/app-demo/src/main.tsx.example +13 -7
- package/templates/app-demo/src/pages/ChangelogPage.tsx.example +14 -0
- package/templates/app-demo/src/pages/DashboardPage.tsx.example +15 -0
- package/templates/app-demo/src/pages/HomePage.tsx.example +3 -77
- package/templates/app-demo/src/pages/PricingPage.tsx.example +14 -0
- package/templates/app-demo/src/pages/ProductsPage.tsx.example +17 -0
- package/templates/app-demo/src/pages/ProfilePage.tsx.example +16 -0
- package/templates/app-demo/src/pages/SettingsPage.tsx.example +15 -0
- package/templates/app-demo/src/pages/ShowcaseDetailPage.tsx.example +112 -0
- package/templates/app-demo/src/pages/ShowcasePage.tsx.example +91 -0
- package/templates/app-demo/src/pages/legal/LegalPage.tsx.example +14 -0
- package/templates/app-demo/src/pages/legal/PrivacyPage.tsx.example +14 -0
- package/templates/app-demo/src/pages/legal/TermsPage.tsx.example +14 -0
- package/templates/app-demo/tsconfig.json.example +1 -1
- package/templates/app-demo/vite.config.ts.example +23 -48
- package/templates/app-expo/README.md.example +1 -1
- package/templates/app-expo/app/index.tsx.example +1 -1
- package/templates/app-vite/src/pages/HomePage.tsx.example +8 -10
- package/templates/overlay-firebase/env.fragment.example +1 -1
- package/templates/overlay-firebase/env.fragment.expo.example +1 -1
- package/templates/overlay-firebase/env.fragment.nextjs.example +1 -1
- package/templates/overlay-supabase/env.fragment.example +1 -1
- package/templates/overlay-supabase/env.fragment.expo.example +1 -1
- package/templates/overlay-supabase/env.fragment.nextjs.example +1 -1
- package/templates/overlay-vercel/env.fragment.example +1 -1
- package/templates/overlay-vercel/env.fragment.nextjs.example +1 -1
- package/templates/root-consumer/AI.md.example +4 -3
- package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +21 -6
- package/templates/root-consumer/guides/dndev/COMPONENTS_ADV.md.example +16 -179
- package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +19 -21
- package/templates/root-consumer/guides/dndev/GOTCHAS.md.example +14 -3
- package/templates/root-consumer/guides/dndev/INDEX.md.example +2 -2
- package/templates/root-consumer/guides/dndev/SETUP_APP_CONFIG.md.example +3 -3
- package/templates/root-consumer/guides/dndev/SETUP_BLOG.md.example +19 -2
- package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +35 -1
- package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +17 -12
- package/templates/root-consumer/guides/dndev/SETUP_LAYOUTS.md.example +32 -0
- package/templates/root-consumer/guides/dndev/SETUP_OAUTH_PROVIDERS.md.example +1 -1
- package/templates/root-consumer/guides/dndev/SETUP_PAGES.md.example +19 -15
- package/templates/root-consumer/guides/dndev/SETUP_STRIPE.md.example +2 -2
- package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +17 -12
- package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +37 -16
- package/templates/root-consumer/guides/dndev/USE_ROUTING.md.example +18 -18
- package/templates/root-consumer/guides/dndev/essences_reference.css.example +119 -2
- package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +14 -0
- package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +6 -0
- package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +14 -0
- package/templates/root-consumer/guides/wai-way/entity_patterns.md.example +4 -5
- package/templates/root-consumer/guides/wai-way/page_patterns.md.example +2 -2
- package/dist/bin/commands/agent-setup.d.ts +0 -6
- package/dist/bin/commands/agent-setup.d.ts.map +0 -1
- package/dist/bin/commands/agent-setup.js.map +0 -1
- package/dist/bin/commands/build.d.ts +0 -11
- package/dist/bin/commands/build.d.ts.map +0 -1
- package/dist/bin/commands/build.js.map +0 -1
- package/dist/bin/commands/bump.d.ts +0 -11
- package/dist/bin/commands/bump.d.ts.map +0 -1
- package/dist/bin/commands/bump.js.map +0 -1
- package/dist/bin/commands/cacheout.d.ts +0 -11
- package/dist/bin/commands/cacheout.d.ts.map +0 -1
- package/dist/bin/commands/cacheout.js.map +0 -1
- package/dist/bin/commands/create-app.d.ts +0 -11
- package/dist/bin/commands/create-app.d.ts.map +0 -1
- package/dist/bin/commands/create-app.js.map +0 -1
- package/dist/bin/commands/create-project.d.ts +0 -11
- package/dist/bin/commands/create-project.d.ts.map +0 -1
- package/dist/bin/commands/create-project.js.map +0 -1
- package/dist/bin/commands/deploy.d.ts +0 -11
- package/dist/bin/commands/deploy.d.ts.map +0 -1
- package/dist/bin/commands/deploy.js.map +0 -1
- package/dist/bin/commands/dev.d.ts +0 -11
- package/dist/bin/commands/dev.d.ts.map +0 -1
- package/dist/bin/commands/dev.js.map +0 -1
- package/dist/bin/commands/doctor.d.ts +0 -6
- package/dist/bin/commands/doctor.d.ts.map +0 -1
- package/dist/bin/commands/doctor.js.map +0 -1
- package/dist/bin/commands/emu.d.ts +0 -11
- package/dist/bin/commands/emu.d.ts.map +0 -1
- package/dist/bin/commands/emu.js.map +0 -1
- package/dist/bin/commands/format.d.ts +0 -11
- package/dist/bin/commands/format.d.ts.map +0 -1
- package/dist/bin/commands/format.js.map +0 -1
- package/dist/bin/commands/make-admin.d.ts +0 -11
- package/dist/bin/commands/make-admin.d.ts.map +0 -1
- package/dist/bin/commands/make-admin.js.map +0 -1
- package/dist/bin/commands/preview.d.ts +0 -11
- package/dist/bin/commands/preview.d.ts.map +0 -1
- package/dist/bin/commands/preview.js.map +0 -1
- package/dist/bin/commands/setup.d.ts +0 -6
- package/dist/bin/commands/setup.d.ts.map +0 -1
- package/dist/bin/commands/setup.js.map +0 -1
- package/dist/bin/commands/sync-secrets.d.ts +0 -11
- package/dist/bin/commands/sync-secrets.d.ts.map +0 -1
- package/dist/bin/commands/sync-secrets.js.map +0 -1
- package/dist/bin/commands/type-check.d.ts +0 -14
- package/dist/bin/commands/type-check.d.ts.map +0 -1
- package/dist/bin/commands/type-check.js.map +0 -1
- package/dist/bin/commands/wai.d.ts +0 -11
- package/dist/bin/commands/wai.d.ts.map +0 -1
- package/dist/bin/commands/wai.js.map +0 -1
- package/dist/index.d.ts +0 -8
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/templates/app-demo/src/components/ThemeToggle.tsx.example +0 -48
- package/templates/app-demo/src/pages/DetailPage.tsx.example +0 -103
- package/templates/app-demo/src/pages/FullPage.tsx.example +0 -142
- package/templates/app-demo/src/pages/components/DemoLayout.tsx.example +0 -266
- package/templates/app-demo/src/pages/components/LayoutRoute.tsx.example +0 -20
|
@@ -36,6 +36,38 @@ All presets automatically include these components when applicable:
|
|
|
36
36
|
|
|
37
37
|
---
|
|
38
38
|
|
|
39
|
+
## Per-Route Layout Switching
|
|
40
|
+
|
|
41
|
+
**Override the app preset on a per-page basis via `PageMeta.preset`:**
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
// src/pages/DashboardPage.tsx
|
|
45
|
+
import type { PageMeta } from '@donotdev/core';
|
|
46
|
+
|
|
47
|
+
export const meta: PageMeta = {
|
|
48
|
+
preset: 'admin', // This route uses admin layout (sidebar, compact density)
|
|
49
|
+
auth: true,
|
|
50
|
+
};
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- If `preset` is set → that route uses the specified layout
|
|
54
|
+
- If `preset` is absent → the app's `appConfig.preset` is used
|
|
55
|
+
- The override is **transient** — navigating away restores the next route's preset or the app default
|
|
56
|
+
- No localStorage pollution — route presets are not persisted
|
|
57
|
+
|
|
58
|
+
**Common pattern (SaaS app):**
|
|
59
|
+
| Route | Preset | Purpose |
|
|
60
|
+
|-------|--------|---------|
|
|
61
|
+
| `/` | (app default: `landing`) | Marketing landing page |
|
|
62
|
+
| `/pricing` | (app default: `landing`) | Pricing page |
|
|
63
|
+
| `/dashboard` | `admin` | Dashboard with sidebar |
|
|
64
|
+
| `/products` | `admin` | CRUD with sidebar |
|
|
65
|
+
| `/changelog` | `docs` | Documentation layout |
|
|
66
|
+
|
|
67
|
+
**Reference implementation:** See `packages/cli/templates/app-demo/` for a working example of per-route switching.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
39
71
|
## Advanced: Slot Overrides
|
|
40
72
|
|
|
41
73
|
**Customize zones:**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# OAuth Provider Setup Guide
|
|
2
2
|
|
|
3
3
|
Each OAuth provider requires manual registration in their developer console.
|
|
4
|
-
`dndev
|
|
4
|
+
`dndev coach` shows the correct redirect URI and setup steps for each provider.
|
|
5
5
|
|
|
6
6
|
## Redirect URIs
|
|
7
7
|
|
|
@@ -64,32 +64,37 @@ export default function HomePage() {
|
|
|
64
64
|
export const meta: PageMeta = {
|
|
65
65
|
// Translation/SEO namespace
|
|
66
66
|
namespace: NAMESPACE,
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
// Route configuration
|
|
69
69
|
route: '/custom-url', // Override auto-generated path
|
|
70
70
|
route: { params: ['slug'] }, // Dynamic: /blog/:slug
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
// Page title (optional - auto-extracted from filename)
|
|
73
73
|
title: 'Custom Title',
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
// Navigation icon (lucide-react JSX only)
|
|
76
76
|
icon: <Rocket />, // Menu icon (default: Link)
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
// Hide from navigation menu
|
|
79
79
|
hideFromMenu: false, // Default: false (shows in nav)
|
|
80
|
-
|
|
80
|
+
|
|
81
|
+
// Layout preset override (per-route)
|
|
82
|
+
preset: 'admin', // Override app default for this route
|
|
83
|
+
|
|
81
84
|
// Authentication
|
|
82
85
|
auth: true, // Simple: auth required
|
|
83
86
|
auth: { required: true }, // Explicit: auth required
|
|
84
87
|
auth: { required: true, role: 'admin' }, // Role-based access
|
|
85
88
|
auth: { required: true, tier: 'pro' }, // Tier-based access
|
|
86
|
-
auth: {
|
|
89
|
+
auth: {
|
|
87
90
|
required: true,
|
|
88
91
|
validate: (role, tier) => role === 'admin' && tier === 'pro'
|
|
89
92
|
}, // Custom validation
|
|
90
93
|
};
|
|
91
94
|
```
|
|
92
95
|
|
|
96
|
+
**Reference implementation:** The demo app (`packages/cli/templates/app-demo/`) shows all these patterns working together — landing, admin, docs presets, auth, showcase, CRUD, legal pages.
|
|
97
|
+
|
|
93
98
|
---
|
|
94
99
|
|
|
95
100
|
## Advanced: Dynamic Routes & Navigation
|
|
@@ -141,17 +146,15 @@ import { Link } from '@donotdev/ui';
|
|
|
141
146
|
**Always import from `@donotdev/<package>` top-level.** Never use sub-paths.
|
|
142
147
|
|
|
143
148
|
```tsx
|
|
144
|
-
// CORRECT
|
|
145
149
|
import { PageContainer, Link, useNavigate } from '@donotdev/ui';
|
|
146
150
|
import { Card, Button, Input } from '@donotdev/components';
|
|
147
151
|
import { useCrud } from '@donotdev/crud';
|
|
148
|
-
|
|
149
|
-
// WRONG — sub-paths do not exist
|
|
150
|
-
import { Link } from '@donotdev/ui/routing';
|
|
151
|
-
import { Card } from '@donotdev/components/card';
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
-
**
|
|
154
|
+
**Sub-path exceptions** (server, config, and provider-specific):
|
|
155
|
+
- **Server:** `@donotdev/core/server`, `@donotdev/firebase/server`, `@donotdev/security/server`
|
|
156
|
+
- **Config:** `@donotdev/core/vite`, `@donotdev/core/next`, `@donotdev/core/functions`
|
|
157
|
+
- **Functions:** `@donotdev/functions/firebase`, `@donotdev/functions/vercel`, `@donotdev/functions/supabase`
|
|
155
158
|
|
|
156
159
|
---
|
|
157
160
|
|
|
@@ -172,8 +175,7 @@ src/pages/
|
|
|
172
175
|
|
|
173
176
|
```tsx
|
|
174
177
|
// src/pages/HomePage.tsx — SaaS pattern
|
|
175
|
-
import {
|
|
176
|
-
import { useNavigate, PageContainer } from '@donotdev/ui';
|
|
178
|
+
import { useAuthSafe, useNavigate, PageContainer } from '@donotdev/ui';
|
|
177
179
|
import { LoginForm } from '@donotdev/templates';
|
|
178
180
|
|
|
179
181
|
export const meta: PageMeta = {
|
|
@@ -182,7 +184,7 @@ export const meta: PageMeta = {
|
|
|
182
184
|
};
|
|
183
185
|
|
|
184
186
|
export default function HomePage() {
|
|
185
|
-
const
|
|
187
|
+
const user = useAuthSafe('user');
|
|
186
188
|
const navigate = useNavigate();
|
|
187
189
|
|
|
188
190
|
// Redirect authenticated users to dashboard
|
|
@@ -196,6 +198,8 @@ export default function HomePage() {
|
|
|
196
198
|
}
|
|
197
199
|
```
|
|
198
200
|
|
|
201
|
+
> **Why `useAuthSafe` instead of `useAuth`?** HomePage is public — it renders before auth is guaranteed to be initialized. `useAuthSafe` (from `@donotdev/ui`) gracefully degrades if `@donotdev/auth` isn't installed or still initializing. `useAuth` (from `@donotdev/auth`) throws if auth isn't available. Use `useAuthSafe` on any page without `auth: true` in its meta.
|
|
202
|
+
|
|
199
203
|
---
|
|
200
204
|
|
|
201
205
|
**Drop files, get routes. Framework handles the rest.**
|
|
@@ -52,8 +52,8 @@ For subscription testing without waiting for real billing cycles:
|
|
|
52
52
|
## 5. Verify
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
dndev setup
|
|
56
|
-
dndev doctor #
|
|
55
|
+
dndev setup # Validates key formats + health check
|
|
56
|
+
dndev doctor # Full health check for all providers
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
Check that:
|
|
@@ -4,29 +4,34 @@
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## Step 1: Run
|
|
7
|
+
## Step 1: Run Coach + Fill .env
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
dndev
|
|
10
|
+
dndev coach
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
This
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
- Writes `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLIC_KEY` to your app's `.env`
|
|
13
|
+
This prints a numbered checklist of what to configure. For Supabase, you'll need:
|
|
14
|
+
- **Project URL** and **public key** → paste into your app's `.env`
|
|
15
|
+
- **service_role key** → paste into `supabase/functions/.env`
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
Get these from: [Supabase Dashboard](https://supabase.com/dashboard) → your project → **Settings → API**.
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
Then run setup to validate and automate:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
dndev setup
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Setup validates your .env values are present, links the Supabase CLI, generates SQL migrations, and runs an inline health check.
|
|
21
26
|
|
|
22
27
|
---
|
|
23
28
|
|
|
24
29
|
## Step 2: Generate Tables from Entities
|
|
25
30
|
|
|
26
|
-
The framework generates PostgreSQL migrations from your entity definitions. This runs automatically as part of `dndev setup
|
|
31
|
+
The framework generates PostgreSQL migrations from your entity definitions. This runs automatically as part of `dndev setup`, or you can run it separately:
|
|
27
32
|
|
|
28
33
|
```bash
|
|
29
|
-
dndev setup
|
|
34
|
+
dndev setup
|
|
30
35
|
```
|
|
31
36
|
|
|
32
37
|
During setup, the wizard detects your entities and generates SQL migrations.
|
|
@@ -200,7 +205,7 @@ Or install the [Supabase CLI](https://supabase.com/docs/guides/cli) and run `sup
|
|
|
200
205
|
## Troubleshooting
|
|
201
206
|
|
|
202
207
|
**"Table not found" / "relation does not exist"**
|
|
203
|
-
→ Run `dndev setup
|
|
208
|
+
→ Run `dndev setup` (generates SQL) then apply migrations with `supabase db push`
|
|
204
209
|
|
|
205
210
|
**"Permission denied" / RLS errors**
|
|
206
211
|
→ Check RLS policies in Supabase Dashboard → Database → Policies
|
|
@@ -212,4 +217,4 @@ Or install the [Supabase CLI](https://supabase.com/docs/guides/cli) and run `sup
|
|
|
212
217
|
|
|
213
218
|
---
|
|
214
219
|
|
|
215
|
-
**`dndev
|
|
220
|
+
**`dndev coach` → fill .env → `dndev setup` → apply migrations → `dndev dev`. The adapter normalizes everything automatically.**
|
|
@@ -29,9 +29,32 @@ The framework scaffolds `vercel.json` with CSP headers, rewrites, and caching ru
|
|
|
29
29
|
|
|
30
30
|
---
|
|
31
31
|
|
|
32
|
-
## Step 2:
|
|
32
|
+
## Step 2: Add Credentials to `.env.local`
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
Add these 3 values to `apps/<your-app>/.env.local`:
|
|
35
|
+
|
|
36
|
+
```env
|
|
37
|
+
# Vercel Deployment Credentials (gitignored — never commit these)
|
|
38
|
+
VERCEL_TOKEN=your_vercel_token
|
|
39
|
+
VERCEL_ORG_ID=your_team_id
|
|
40
|
+
VERCEL_PROJECT_ID=your_project_id
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Where to find them:**
|
|
44
|
+
|
|
45
|
+
| Variable | Where |
|
|
46
|
+
|----------|-------|
|
|
47
|
+
| `VERCEL_TOKEN` | [vercel.com/account/tokens](https://vercel.com/account/tokens) — scope to your team |
|
|
48
|
+
| `VERCEL_ORG_ID` | Vercel Dashboard → Settings → General → **Team ID** |
|
|
49
|
+
| `VERCEL_PROJECT_ID` | Vercel Dashboard → Your Project → Settings → General → **Project ID** |
|
|
50
|
+
|
|
51
|
+
That's it. No `vercel login`, no `vercel link`, no interactive prompts.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Step 3: Set App Environment Variables
|
|
56
|
+
|
|
57
|
+
In **Vercel Dashboard → Project → Settings → Environment Variables**, add your app's env vars:
|
|
35
58
|
|
|
36
59
|
**If using Firebase:**
|
|
37
60
|
- `VITE_FIREBASE_API_KEY`
|
|
@@ -57,26 +80,20 @@ For Next.js apps, replace the `VITE_` prefix with `NEXT_PUBLIC_` (same var names
|
|
|
57
80
|
|
|
58
81
|
---
|
|
59
82
|
|
|
60
|
-
## Step
|
|
61
|
-
|
|
62
|
-
**Option A — Git push (recommended)**
|
|
63
|
-
|
|
64
|
-
Push to your connected branch. Vercel auto-deploys.
|
|
83
|
+
## Step 4: Deploy
|
|
65
84
|
|
|
66
85
|
```bash
|
|
67
|
-
|
|
86
|
+
dndev deploy
|
|
68
87
|
```
|
|
69
88
|
|
|
70
|
-
|
|
89
|
+
That's it. The CLI reads your credentials from `.env.local` and deploys to production.
|
|
71
90
|
|
|
72
|
-
|
|
73
|
-
dndev deploy
|
|
74
|
-
```
|
|
91
|
+
**Option B — Git push (auto-deploy)**
|
|
75
92
|
|
|
76
|
-
|
|
93
|
+
If your repo is connected to Vercel, pushing to your branch auto-deploys:
|
|
77
94
|
|
|
78
95
|
```bash
|
|
79
|
-
|
|
96
|
+
git push origin main
|
|
80
97
|
```
|
|
81
98
|
|
|
82
99
|
---
|
|
@@ -140,7 +157,7 @@ Available: auth (claims, status, delete account), billing (checkout, cancel, por
|
|
|
140
157
|
| File | What Goes Here | Loaded By |
|
|
141
158
|
|------|---------------|-----------|
|
|
142
159
|
| `apps/<app>/.env` | Public keys (backend config, license key, Stripe publishable) | Vite/Next.js (dev + build) |
|
|
143
|
-
| `apps/<app>/.env.local` |
|
|
160
|
+
| `apps/<app>/.env.local` | Secrets: `VERCEL_TOKEN`, `VERCEL_ORG_ID`, `VERCEL_PROJECT_ID` (gitignored) | `dndev deploy` |
|
|
144
161
|
| `apps/<app>/.env.production` | Production overrides | Vite/Next.js (build --mode production) |
|
|
145
162
|
| Vercel Dashboard | All production env vars (client + server) | Vercel runtime |
|
|
146
163
|
|
|
@@ -175,6 +192,10 @@ dndev emu start
|
|
|
175
192
|
|
|
176
193
|
## Troubleshooting
|
|
177
194
|
|
|
195
|
+
**"Missing Vercel credentials"**
|
|
196
|
+
→ Check `apps/<app>/.env.local` has all 3 vars: `VERCEL_TOKEN`, `VERCEL_ORG_ID`, `VERCEL_PROJECT_ID`
|
|
197
|
+
→ Run `dndev setup` to validate
|
|
198
|
+
|
|
178
199
|
**"Build fails on Vercel"**
|
|
179
200
|
→ Check Root Directory is set to your app directory
|
|
180
201
|
→ Ensure `package.json` has correct `build` script
|
|
@@ -190,4 +211,4 @@ dndev emu start
|
|
|
190
211
|
|
|
191
212
|
---
|
|
192
213
|
|
|
193
|
-
**
|
|
214
|
+
**3 values in `.env.local` → `dndev deploy` → done.**
|
|
@@ -13,7 +13,7 @@ import { Link, useNavigate, useParams } from 'react-router-dom'; // ❌ BREAKS F
|
|
|
13
13
|
|
|
14
14
|
**✅ CORRECT:**
|
|
15
15
|
```tsx
|
|
16
|
-
import { Link, useNavigate, useParams } from '@donotdev/ui
|
|
16
|
+
import { Link, useNavigate, useParams } from '@donotdev/ui'; // ✅ Framework routing
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
**Why?** The framework's routing components:
|
|
@@ -30,7 +30,7 @@ import { Link, useNavigate, useParams } from '@donotdev/ui/routing'; // ✅ Fram
|
|
|
30
30
|
### Components
|
|
31
31
|
|
|
32
32
|
```tsx
|
|
33
|
-
import { Link, DnDevNavigationMenu } from '@donotdev/ui
|
|
33
|
+
import { Link, DnDevNavigationMenu } from '@donotdev/ui';
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
**Link Component:**
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
useRouteParam,
|
|
56
56
|
useSearchParams,
|
|
57
57
|
useNavigationItems,
|
|
58
|
-
} from '@donotdev/ui
|
|
58
|
+
} from '@donotdev/ui';
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
---
|
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
|
|
67
67
|
**✅ Use framework Link:**
|
|
68
68
|
```tsx
|
|
69
|
-
import { Link } from '@donotdev/ui
|
|
69
|
+
import { Link } from '@donotdev/ui';
|
|
70
70
|
|
|
71
71
|
function ProductCard({ product }) {
|
|
72
72
|
return (
|
|
@@ -77,7 +77,7 @@ function ProductCard({ product }) {
|
|
|
77
77
|
|
|
78
78
|
**✅ Use framework useNavigate:**
|
|
79
79
|
```tsx
|
|
80
|
-
import { useNavigate } from '@donotdev/ui
|
|
80
|
+
import { useNavigate } from '@donotdev/ui';
|
|
81
81
|
|
|
82
82
|
function ProductForm() {
|
|
83
83
|
const navigate = useNavigate();
|
|
@@ -107,7 +107,7 @@ function ProductForm() {
|
|
|
107
107
|
|
|
108
108
|
**✅ Use framework useRouteParam:**
|
|
109
109
|
```tsx
|
|
110
|
-
import { useRouteParam } from '@donotdev/ui
|
|
110
|
+
import { useRouteParam } from '@donotdev/ui';
|
|
111
111
|
|
|
112
112
|
function ProductPage() {
|
|
113
113
|
const id = useRouteParam('id'); // ✅ Returns string | undefined
|
|
@@ -117,7 +117,7 @@ function ProductPage() {
|
|
|
117
117
|
|
|
118
118
|
**✅ Or use framework useParams:**
|
|
119
119
|
```tsx
|
|
120
|
-
import { useParams } from '@donotdev/ui
|
|
120
|
+
import { useParams } from '@donotdev/ui';
|
|
121
121
|
|
|
122
122
|
function ProductPage() {
|
|
123
123
|
const params = useParams();
|
|
@@ -136,7 +136,7 @@ import { useParams } from 'react-router-dom'; // ❌ Type issues, breaks framewo
|
|
|
136
136
|
|
|
137
137
|
**✅ Use DnDevNavigationMenu (auto-fetches routes):**
|
|
138
138
|
```tsx
|
|
139
|
-
import { DnDevNavigationMenu, DISPLAY } from '@donotdev/ui
|
|
139
|
+
import { DnDevNavigationMenu, DISPLAY } from '@donotdev/ui';
|
|
140
140
|
|
|
141
141
|
function Sidebar() {
|
|
142
142
|
return (
|
|
@@ -151,7 +151,7 @@ function Sidebar() {
|
|
|
151
151
|
|
|
152
152
|
**✅ Or use useNavigationItems for custom sidebar:**
|
|
153
153
|
```tsx
|
|
154
|
-
import { Link, useNavigationItems } from '@donotdev/ui
|
|
154
|
+
import { Link, useNavigationItems } from '@donotdev/ui';
|
|
155
155
|
|
|
156
156
|
function CustomSidebar() {
|
|
157
157
|
const menuItems = useNavigationItems(); // ✅ Auth-filtered routes
|
|
@@ -194,7 +194,7 @@ function Sidebar() {
|
|
|
194
194
|
|
|
195
195
|
**✅ Use framework useNavigate:**
|
|
196
196
|
```tsx
|
|
197
|
-
import { useNavigate } from '@donotdev/ui
|
|
197
|
+
import { useNavigate } from '@donotdev/ui';
|
|
198
198
|
|
|
199
199
|
function LoginForm() {
|
|
200
200
|
const navigate = useNavigate();
|
|
@@ -228,7 +228,7 @@ navigate('/products', {
|
|
|
228
228
|
|
|
229
229
|
**✅ Use framework useSearchParams (read-only, returns URLSearchParams directly):**
|
|
230
230
|
```tsx
|
|
231
|
-
import { useSearchParams } from '@donotdev/ui
|
|
231
|
+
import { useSearchParams } from '@donotdev/ui';
|
|
232
232
|
|
|
233
233
|
function ProductList() {
|
|
234
234
|
const searchParams = useSearchParams();
|
|
@@ -240,7 +240,7 @@ function ProductList() {
|
|
|
240
240
|
|
|
241
241
|
**✅ Or use useQueryParams helper:**
|
|
242
242
|
```tsx
|
|
243
|
-
import { useQueryParams } from '@donotdev/ui
|
|
243
|
+
import { useQueryParams } from '@donotdev/ui';
|
|
244
244
|
|
|
245
245
|
function ProductList() {
|
|
246
246
|
const { page, sort } = useQueryParams({ page: '1', sort: 'name' });
|
|
@@ -254,7 +254,7 @@ function ProductList() {
|
|
|
254
254
|
|
|
255
255
|
**✅ Use framework useMatch:**
|
|
256
256
|
```tsx
|
|
257
|
-
import { useMatch } from '@donotdev/ui
|
|
257
|
+
import { useMatch } from '@donotdev/ui';
|
|
258
258
|
|
|
259
259
|
function NavigationItem({ path }) {
|
|
260
260
|
const isActive = useMatch(path);
|
|
@@ -360,7 +360,7 @@ import { Link, useNavigate } from 'react-router-dom';
|
|
|
360
360
|
**Fix:**
|
|
361
361
|
```tsx
|
|
362
362
|
// ✅ CORRECT
|
|
363
|
-
import { Link, useNavigate } from '@donotdev/ui
|
|
363
|
+
import { Link, useNavigate } from '@donotdev/ui';
|
|
364
364
|
```
|
|
365
365
|
|
|
366
366
|
---
|
|
@@ -416,7 +416,7 @@ function Sidebar() {
|
|
|
416
416
|
**Fix:**
|
|
417
417
|
```tsx
|
|
418
418
|
// ✅ CORRECT
|
|
419
|
-
import { DnDevNavigationMenu } from '@donotdev/ui
|
|
419
|
+
import { DnDevNavigationMenu } from '@donotdev/ui';
|
|
420
420
|
|
|
421
421
|
function Sidebar() {
|
|
422
422
|
return <DnDevNavigationMenu vertical />; // Auto-fetches routes
|
|
@@ -437,7 +437,7 @@ import { Link } from 'react-router-dom';
|
|
|
437
437
|
**Fix:**
|
|
438
438
|
```tsx
|
|
439
439
|
// ✅ CORRECT
|
|
440
|
-
import { Link } from '@donotdev/ui
|
|
440
|
+
import { Link } from '@donotdev/ui';
|
|
441
441
|
|
|
442
442
|
<Link path="/products" label="Products" />
|
|
443
443
|
```
|
|
@@ -459,7 +459,7 @@ import {
|
|
|
459
459
|
useSearchParams,
|
|
460
460
|
useNavigationItems,
|
|
461
461
|
DnDevNavigationMenu,
|
|
462
|
-
} from '@donotdev/ui
|
|
462
|
+
} from '@donotdev/ui';
|
|
463
463
|
```
|
|
464
464
|
|
|
465
465
|
### Common Patterns
|
|
@@ -489,7 +489,7 @@ const menuItems = useNavigationItems(); // Auth-filtered routes
|
|
|
489
489
|
|
|
490
490
|
## Summary
|
|
491
491
|
|
|
492
|
-
1. **Always
|
|
492
|
+
1. **Always import from `@donotdev/ui`** — never `react-router-dom`
|
|
493
493
|
2. **Use `DnDevNavigationMenu`** for sidebars/headers
|
|
494
494
|
3. **Use `useNavigationItems()`** for custom navigation
|
|
495
495
|
4. **Don't use `<Outlet />` manually** - framework handles it
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Reference: Framework essences (Brutalist, Luxury).
|
|
2
|
+
* Reference: Framework essences (Brutalist, Luxury, Retro).
|
|
3
3
|
* Copy the blocks you need into your app's src/themes.css.
|
|
4
4
|
* Default essence = SaaS (Inter); these do not apply until you set the class on <html>.
|
|
5
5
|
*
|
|
6
|
-
* Fonts: Space Grotesk (Brutalist), Playfair Display (Luxury),
|
|
6
|
+
* Fonts: Space Grotesk (Brutalist), Playfair Display (Luxury), Press Start 2P (Retro),
|
|
7
|
+
* Inter, Roboto are bundled in @donotdev/ui (no external requests).
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
/** =========================================================================
|
|
@@ -172,3 +173,119 @@
|
|
|
172
173
|
--shadow-md: 0 4px 12px var(--shadow-color);
|
|
173
174
|
--shadow-xl: 0 8px 24px var(--shadow-color);
|
|
174
175
|
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
/** =========================================================================
|
|
179
|
+
* Retro — 8-bit pixel aesthetic, Press Start 2P, neon on dark, CRT vibes.
|
|
180
|
+
* Set <html class="retro"> to apply.
|
|
181
|
+
* ========================================================================= */
|
|
182
|
+
.retro {
|
|
183
|
+
--theme-icon: 'Gamepad2';
|
|
184
|
+
--theme-label: 'Retro';
|
|
185
|
+
--theme-is-dark: 1;
|
|
186
|
+
|
|
187
|
+
/* 1. Core Colors - Muted neon on zinc */
|
|
188
|
+
--background: #1c1c22;
|
|
189
|
+
--foreground: #c8e6c9;
|
|
190
|
+
--primary: #5eead4;
|
|
191
|
+
--secondary: #c084fc;
|
|
192
|
+
--accent: #fbbf24;
|
|
193
|
+
|
|
194
|
+
/* 2. Semantic */
|
|
195
|
+
--success: #6ee7b7;
|
|
196
|
+
--warning: #fbbf24;
|
|
197
|
+
--destructive: #f87171;
|
|
198
|
+
|
|
199
|
+
/* 3. Surfaces - Zinc CRT glass */
|
|
200
|
+
--muted: #27272f;
|
|
201
|
+
--muted-foreground: #8bae8b;
|
|
202
|
+
--border: #4a6a4a;
|
|
203
|
+
--input: #1c1c22;
|
|
204
|
+
--ring: #5eead4;
|
|
205
|
+
--card: #222228;
|
|
206
|
+
--card-foreground: #c8e6c9;
|
|
207
|
+
--popover: #222228;
|
|
208
|
+
--popover-foreground: #c8e6c9;
|
|
209
|
+
--surface-1: #1e1e24;
|
|
210
|
+
|
|
211
|
+
/* 4. Text on Colors */
|
|
212
|
+
--primary-foreground: #0f172a;
|
|
213
|
+
--secondary-foreground: #0f172a;
|
|
214
|
+
--accent-foreground: #0f172a;
|
|
215
|
+
--success-foreground: #0f172a;
|
|
216
|
+
--warning-foreground: #0f172a;
|
|
217
|
+
--destructive-foreground: #ffffff;
|
|
218
|
+
|
|
219
|
+
/* 5. Radius - Hard pixel corners */
|
|
220
|
+
--radius-interactive: 0;
|
|
221
|
+
--radius-surface: 0;
|
|
222
|
+
--radius-floating: 0;
|
|
223
|
+
|
|
224
|
+
/* 6. Typography - Press Start 2P (pixel font, 400 only) */
|
|
225
|
+
--font-family: 'Press Start 2P', var(--font-mono);
|
|
226
|
+
--font-headline: 'Press Start 2P', var(--font-mono);
|
|
227
|
+
--font-weight-normal: 400;
|
|
228
|
+
--font-weight-medium: 400;
|
|
229
|
+
--font-weight-semibold: 400;
|
|
230
|
+
--font-weight-bold: 400;
|
|
231
|
+
|
|
232
|
+
/* 7. Font scale - smaller base (pixel font reads large) */
|
|
233
|
+
--font-size-xs: 0.5rem;
|
|
234
|
+
--font-size-sm: 0.625rem;
|
|
235
|
+
--font-size-base: 0.75rem;
|
|
236
|
+
--font-size-lg: 0.875rem;
|
|
237
|
+
--font-size-xl: 1rem;
|
|
238
|
+
--font-size-2xl: 1.25rem;
|
|
239
|
+
--font-size-3xl: 1.5rem;
|
|
240
|
+
--line-height: 1.6;
|
|
241
|
+
|
|
242
|
+
/* 8. Borders - Chunky pixel borders */
|
|
243
|
+
--border-width: 3px;
|
|
244
|
+
--border-huge: 4px;
|
|
245
|
+
|
|
246
|
+
/* 9. Shadows — soft neon glow */
|
|
247
|
+
--shadow-color: #5eead433;
|
|
248
|
+
--shadow-sm: 0 0 4px #5eead422;
|
|
249
|
+
--shadow-md: 0 0 8px #5eead433, 0 0 16px #5eead41a;
|
|
250
|
+
--shadow-xl: 0 0 12px #5eead444, 0 0 24px #5eead42a, 0 0 48px #c084fc1a;
|
|
251
|
+
--shadow-cta: 0 0 16px #5eead444, 0 0 32px #5eead422;
|
|
252
|
+
|
|
253
|
+
/* 10. Per-variant shadows — soft neon matching */
|
|
254
|
+
--shadow-primary: 0 0 8px #5eead42a;
|
|
255
|
+
--shadow-primary-xl: 0 0 16px #5eead444, 0 0 32px #5eead422;
|
|
256
|
+
--shadow-secondary: 0 0 8px #c084fc2a;
|
|
257
|
+
--shadow-secondary-xl: 0 0 16px #c084fc44, 0 0 32px #c084fc22;
|
|
258
|
+
|
|
259
|
+
/* 11. Header padding */
|
|
260
|
+
--header-shadow-padding: 0;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* Body - subtle CRT scanlines */
|
|
264
|
+
.retro body {
|
|
265
|
+
background-color: var(--background);
|
|
266
|
+
background-image:
|
|
267
|
+
repeating-linear-gradient(
|
|
268
|
+
0deg,
|
|
269
|
+
transparent,
|
|
270
|
+
transparent 2px,
|
|
271
|
+
rgba(0, 0, 0, 0.08) 2px,
|
|
272
|
+
rgba(0, 0, 0, 0.08) 4px
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* Uppercase headings (pixel fonts look best in caps) */
|
|
277
|
+
.retro {
|
|
278
|
+
:is(h1, h2, h3, h4, h5, h6),
|
|
279
|
+
[data-level^='h'] {
|
|
280
|
+
text-transform: uppercase;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* Flat surfaces - no gradient, pixel-sharp */
|
|
285
|
+
.retro .dndev-surface { background: var(--card); }
|
|
286
|
+
.retro .dndev-surface[data-variant='outline'] { border: var(--border-width) solid var(--border); }
|
|
287
|
+
|
|
288
|
+
.retro .dndev-card[data-variant='outline'] {
|
|
289
|
+
background: transparent;
|
|
290
|
+
box-shadow: none;
|
|
291
|
+
}
|
|
@@ -37,6 +37,20 @@ Apply the chosen essence (SaaS, Luxury, Brutalist) to your `src/themes.css`.
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
+
## Reference: Demo App
|
|
41
|
+
|
|
42
|
+
**Before creating pages, study the demo app:** `packages/cli/templates/app-demo/src/pages/`
|
|
43
|
+
|
|
44
|
+
It shows the canonical pattern:
|
|
45
|
+
- Thin page wrappers (~5 lines) that import templates
|
|
46
|
+
- `PageMeta.preset` for per-route layout switching (landing → admin → docs)
|
|
47
|
+
- Component showcase with filterable grid
|
|
48
|
+
- Entity definition with `defineEntity()`
|
|
49
|
+
|
|
50
|
+
**Copy from the demo app, customize for your spec.**
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
40
54
|
## Step 3: Review Spec Pages
|
|
41
55
|
|
|
42
56
|
From your spec, you have a list of pages. Now create them.
|
|
@@ -46,6 +46,12 @@ export const productEntity = defineEntity({
|
|
|
46
46
|
});
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
> **Status field:** Auto-added with locked `type`, `visibility`, `editable`. Don't redefine those. To add custom options:
|
|
50
|
+
> ```typescript
|
|
51
|
+
> status: { validation: { options: [{ value: 'shipped', label: 'Shipped' }] } }
|
|
52
|
+
> // Merged result: [draft, available, deleted, shipped]
|
|
53
|
+
> ```
|
|
54
|
+
|
|
49
55
|
---
|
|
50
56
|
|
|
51
57
|
## Step 3: Export Entities
|
|
@@ -20,6 +20,20 @@
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
+
## Reference: Demo App
|
|
24
|
+
|
|
25
|
+
**Before composing pages, study the demo app:** `packages/cli/templates/app-demo/src/pages/`
|
|
26
|
+
|
|
27
|
+
It shows the canonical pattern:
|
|
28
|
+
- Thin page wrappers (~5 lines) that import templates
|
|
29
|
+
- `PageMeta.preset` for per-route layout switching (landing → admin → docs)
|
|
30
|
+
- CRUD with `ProductCardListTemplate` + `defineEntity()`
|
|
31
|
+
- Component showcase with filterable grid
|
|
32
|
+
|
|
33
|
+
**Copy from the demo app, customize for your spec.**
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
23
37
|
## Step 2: Read Page Patterns
|
|
24
38
|
|
|
25
39
|
**READ:** `guides/wai-way/page_patterns.md` for all patterns:
|
|
@@ -309,12 +309,9 @@ export const orderEntity = defineEntity({
|
|
|
309
309
|
visibility: 'owner',
|
|
310
310
|
editable: 'never',
|
|
311
311
|
},
|
|
312
|
+
// status is auto-added with type/visibility/editable locked.
|
|
313
|
+
// Only define validation.options — framework auto-adds [draft, available, deleted].
|
|
312
314
|
status: {
|
|
313
|
-
name: 'status',
|
|
314
|
-
label: 'status',
|
|
315
|
-
type: 'select',
|
|
316
|
-
visibility: 'owner',
|
|
317
|
-
editable: 'admin',
|
|
318
315
|
validation: {
|
|
319
316
|
options: [
|
|
320
317
|
{ value: 'pending', label: 'Pending' },
|
|
@@ -341,6 +338,8 @@ export const orderEntity = defineEntity({
|
|
|
341
338
|
});
|
|
342
339
|
```
|
|
343
340
|
|
|
341
|
+
> **Merged status options:** `[draft, available, deleted, pending, paid, shipped, delivered, cancelled]`. The three defaults are always first and cannot be removed.
|
|
342
|
+
|
|
344
343
|
---
|
|
345
344
|
|
|
346
345
|
## Review
|