@donotdev/cli 0.0.5 → 0.0.7
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 +76 -34
- package/dist/bin/commands/build.js +165 -161
- package/dist/bin/commands/bump.js +172 -160
- package/dist/bin/commands/cacheout.js +163 -157
- package/dist/bin/commands/create-app.js +205 -163
- package/dist/bin/commands/create-project.js +176 -161
- package/dist/bin/commands/deploy.js +480 -472
- package/dist/bin/commands/dev.js +164 -158
- package/dist/bin/commands/emu.js +164 -158
- package/dist/bin/commands/format.js +163 -157
- package/dist/bin/commands/lint.js +166 -157
- package/dist/bin/commands/make-admin.d.ts +11 -0
- package/dist/bin/commands/make-admin.d.ts.map +1 -0
- package/dist/bin/commands/make-admin.js +12 -0
- package/dist/bin/commands/make-admin.js.map +1 -0
- package/dist/bin/commands/preview.js +164 -158
- package/dist/bin/commands/sync-secrets.js +164 -158
- package/dist/bin/commands/wai.d.ts +11 -0
- package/dist/bin/commands/wai.d.ts.map +1 -0
- package/dist/bin/commands/wai.js +12 -0
- package/dist/bin/commands/wai.js.map +1 -0
- package/dist/bin/dndev.js +24 -8
- package/dist/bin/donotdev.js +24 -8
- package/dist/index.js +557 -514
- package/package.json +1 -1
- package/templates/app-demo/index.html.example +4 -0
- package/templates/app-demo/src/App.tsx.example +28 -10
- package/templates/app-demo/src/config/app.ts.example +68 -0
- package/templates/app-next/src/app/ClientLayout.tsx.example +4 -3
- package/templates/app-next/src/app/layout.tsx.example +17 -25
- package/templates/app-next/src/config/app.ts.example +75 -48
- package/templates/app-next/src/globals.css.example +10 -7
- package/templates/app-next/src/locales/dndev_en.json.example +68 -0
- package/templates/app-next/src/pages/locales/example_en.json.example +5 -0
- package/templates/app-vite/index.html.example +71 -34
- package/templates/app-vite/src/config/app.ts.example +75 -47
- package/templates/app-vite/src/globals.css.example +14 -6
- package/templates/app-vite/src/locales/dndev_en.json.example +68 -0
- package/templates/app-vite/src/pages/FormPageExample.tsx.example +152 -0
- package/templates/app-vite/src/pages/HomePage.tsx.example +81 -134
- package/templates/app-vite/src/pages/ListPageExample.tsx.example +88 -0
- package/templates/functions-firebase/README.md.example +25 -0
- package/templates/functions-firebase/build.mjs.example +8 -1
- package/templates/functions-firebase/functions-firebase/build.mjs.example +8 -1
- package/templates/functions-firebase/functions-firebase/src/index.ts.example +19 -25
- package/templates/functions-firebase/functions.config.js.example +35 -0
- package/templates/functions-firebase/tsconfig.json.example +3 -13
- package/templates/functions-vercel/tsconfig.json.example +1 -13
- package/templates/root-consumer/entities/ExampleEntity.ts.example +223 -0
- package/templates/root-consumer/entities/demo.ts.example +562 -0
- package/templates/root-consumer/entities/index.ts.example +15 -0
- package/templates/root-consumer/firebase.json.example +1 -1
- package/templates/root-consumer/guides/{AGENT_START_HERE.md.example → dndev/AGENT_START_HERE.md.example} +22 -0
- package/templates/root-consumer/guides/{COMPONENTS_ADV.md.example → dndev/COMPONENTS_ADV.md.example} +456 -360
- package/templates/root-consumer/guides/{COMPONENTS_ATOMIC.md.example → dndev/COMPONENTS_ATOMIC.md.example} +42 -0
- package/templates/root-consumer/guides/dndev/COMPONENTS_CRUD.md.example +231 -0
- package/templates/root-consumer/guides/{INDEX.md.example → dndev/INDEX.md.example} +3 -0
- package/templates/root-consumer/guides/{SETUP_APP_CONFIG.md.example → dndev/SETUP_APP_CONFIG.md.example} +5 -2
- package/templates/root-consumer/guides/{SETUP_AUTH.md.example → dndev/SETUP_AUTH.md.example} +30 -0
- package/templates/root-consumer/guides/{SETUP_BILLING.md.example → dndev/SETUP_BILLING.md.example} +44 -4
- package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +473 -0
- package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +116 -0
- package/templates/root-consumer/guides/{SETUP_PAGES.md.example → dndev/SETUP_PAGES.md.example} +17 -0
- package/templates/root-consumer/guides/dndev/SETUP_PWA.md.example +213 -0
- package/templates/root-consumer/guides/dndev/USE_ROUTING.md.example +503 -0
- package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +404 -0
- package/templates/root-consumer/guides/wai-way/agents/architect.md.example +78 -0
- package/templates/root-consumer/guides/wai-way/agents/builder.md.example +87 -0
- package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +325 -0
- package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +100 -0
- package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +281 -0
- package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +77 -0
- package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +104 -0
- package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +124 -0
- package/templates/root-consumer/guides/wai-way/blueprints/4_configure.md.example +165 -0
- package/templates/root-consumer/guides/wai-way/context_map.json.example +95 -0
- package/templates/root-consumer/guides/wai-way/entity_patterns.md.example +840 -0
- package/templates/root-consumer/guides/wai-way/page_patterns.md.example +686 -0
- package/templates/root-consumer/guides/wai-way/presets_guide.md.example +217 -0
- package/templates/root-consumer/guides/wai-way/spec_template.md.example +312 -0
- package/templates/root-consumer/vercel.json.example +315 -20
- package/templates/app-demo/src/Routes.tsx.example +0 -20
- package/templates/app-vite/src/Routes.tsx.example +0 -16
- package/templates/app-vite/src/pages/locales/README.md.example +0 -1
- package/templates/functions-firebase/functions-firebase/src/crud/createEntity.ts.example +0 -19
- package/templates/functions-firebase/functions-firebase/src/crud/deleteEntity.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/crud/getEntity.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/crud/index.ts.example +0 -12
- package/templates/functions-firebase/functions-firebase/src/crud/listEntities.ts.example +0 -14
- package/templates/functions-firebase/functions-firebase/src/crud/updateEntity.ts.example +0 -14
- package/templates/root-consumer/guides/COMPONENTS_CRUD.md.example +0 -70
- package/templates/root-consumer/guides/SETUP_FUNCTIONS.md.example +0 -62
- /package/templates/root-consumer/guides/{COMPONENTS_UI.md.example → dndev/COMPONENTS_UI.md.example} +0 -0
- /package/templates/root-consumer/guides/{ENV_SETUP.md.example → dndev/ENV_SETUP.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_I18N.md.example → dndev/SETUP_I18N.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_LAYOUTS.md.example → dndev/SETUP_LAYOUTS.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_OAUTH.md.example → dndev/SETUP_OAUTH.md.example} +0 -0
- /package/templates/root-consumer/guides/{SETUP_THEMES.md.example → dndev/SETUP_THEMES.md.example} +0 -0
- /package/templates/root-consumer/guides/{advanced → dndev/advanced}/APP_CHECK.md.example +0 -0
- /package/templates/root-consumer/guides/{advanced → dndev/advanced}/COOKIE_REFERENCE.md.example +0 -0
- /package/templates/root-consumer/guides/{advanced → dndev/advanced}/EMULATORS.md.example +0 -0
- /package/templates/root-consumer/guides/{advanced → dndev/advanced}/VERSION_CONTROL.md.example +0 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# PWA Setup
|
|
2
|
+
|
|
3
|
+
**For AI Agents:** Enable PWA in config, add required app metadata. Framework handles service worker, manifest, and caching.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
### 1. Add Required App Metadata
|
|
10
|
+
|
|
11
|
+
PWA requires `name`, `shortName`, and `description` in your app config:
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// src/config/app.ts
|
|
15
|
+
import type { AppConfig } from '@donotdev/core';
|
|
16
|
+
|
|
17
|
+
export const appConfig: AppConfig = {
|
|
18
|
+
app: {
|
|
19
|
+
name: 'My App', // Full app name (required for PWA)
|
|
20
|
+
shortName: 'App', // Short name for home screen (required for PWA)
|
|
21
|
+
description: 'My app description', // App description (required for PWA)
|
|
22
|
+
url: 'https://myapp.com',
|
|
23
|
+
},
|
|
24
|
+
// ... rest of config
|
|
25
|
+
};
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 2. Enable PWA in Build Config
|
|
29
|
+
|
|
30
|
+
**For Vite apps:**
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// vite.config.ts
|
|
34
|
+
import { defineViteConfig } from '@donotdev/core/vite';
|
|
35
|
+
import { appConfig } from './src/config/app';
|
|
36
|
+
|
|
37
|
+
export default defineViteConfig({
|
|
38
|
+
appConfig,
|
|
39
|
+
pwa: {
|
|
40
|
+
enabled: true, // Enable PWA in production builds
|
|
41
|
+
devEnabled: false, // Enable PWA in development (optional)
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**For Next.js apps:**
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// next.config.ts
|
|
50
|
+
import { defineNextConfig } from '@donotdev/core/next';
|
|
51
|
+
import { appConfig } from './src/config/app';
|
|
52
|
+
|
|
53
|
+
export default defineNextConfig({
|
|
54
|
+
appConfig,
|
|
55
|
+
pwa: {
|
|
56
|
+
enabled: true, // Enable PWA in production builds
|
|
57
|
+
devEnabled: false, // Enable PWA in development (optional)
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Done.** Framework automatically:
|
|
63
|
+
- Generates `manifest.json` from app metadata
|
|
64
|
+
- Creates service worker with Workbox
|
|
65
|
+
- Discovers and precaches app icons
|
|
66
|
+
- Sets up offline caching strategies
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## What Gets Auto-Generated
|
|
71
|
+
|
|
72
|
+
### Manifest (`manifest.json`)
|
|
73
|
+
- **Name & description:** From `appConfig.app.name`, `shortName`, `description`
|
|
74
|
+
- **Icons:** Auto-discovered from `public/` folder (favicon, apple-touch-icon, etc.)
|
|
75
|
+
- **Theme colors:** Defaults to white background, black theme (customizable)
|
|
76
|
+
- **Display mode:** `standalone` (app-like experience)
|
|
77
|
+
|
|
78
|
+
### Service Worker (`sw.js`)
|
|
79
|
+
- **Precaching:** All JS, CSS, HTML, icons, and fonts
|
|
80
|
+
- **Runtime caching:** Smart defaults for API calls and images
|
|
81
|
+
- **Offline support:** Navigation fallback to `/`
|
|
82
|
+
- **Update strategy:** Prompts user to update when new version available
|
|
83
|
+
|
|
84
|
+
### Icons
|
|
85
|
+
Framework discovers icons from:
|
|
86
|
+
- `public/favicon.svg` or `public/favicon.ico`
|
|
87
|
+
- `public/apple-touch-icon.png`
|
|
88
|
+
- Any icons generated by AssetPlugin
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Optional Configuration
|
|
93
|
+
|
|
94
|
+
### Custom Manifest Values
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// vite.config.ts or next.config.ts
|
|
98
|
+
export default defineViteConfig({
|
|
99
|
+
appConfig,
|
|
100
|
+
pwa: {
|
|
101
|
+
enabled: true,
|
|
102
|
+
manifest: {
|
|
103
|
+
// Override any manifest values
|
|
104
|
+
theme_color: '#667eea',
|
|
105
|
+
background_color: '#ffffff',
|
|
106
|
+
display: 'standalone',
|
|
107
|
+
orientation: 'portrait',
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Custom Workbox Configuration
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
pwa: {
|
|
117
|
+
enabled: true,
|
|
118
|
+
workbox: {
|
|
119
|
+
// Maximum file size to cache (default: 5MB)
|
|
120
|
+
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
|
|
121
|
+
|
|
122
|
+
// Custom precache patterns
|
|
123
|
+
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'],
|
|
124
|
+
globIgnores: ['**/node_modules/**'],
|
|
125
|
+
|
|
126
|
+
// Runtime caching strategies
|
|
127
|
+
runtimeCaching: [
|
|
128
|
+
{
|
|
129
|
+
urlPattern: /^https:\/\/api\.example\.com\/.*/i,
|
|
130
|
+
handler: 'NetworkFirst',
|
|
131
|
+
options: {
|
|
132
|
+
cacheName: 'api-cache',
|
|
133
|
+
expiration: {
|
|
134
|
+
maxEntries: 50,
|
|
135
|
+
maxAgeSeconds: 60 * 60, // 1 hour
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Development Mode
|
|
145
|
+
|
|
146
|
+
Enable PWA in development for testing:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
pwa: {
|
|
150
|
+
enabled: true,
|
|
151
|
+
devEnabled: true, // Enable service worker in dev mode
|
|
152
|
+
debug: true, // Enable debug logging
|
|
153
|
+
},
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Note:** Service workers require HTTPS (or localhost). Use `server: { https: true }` in Vite config for local HTTPS.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Testing PWA
|
|
161
|
+
|
|
162
|
+
1. **Build for production:**
|
|
163
|
+
```bash
|
|
164
|
+
bun run build
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
2. **Serve production build:**
|
|
168
|
+
```bash
|
|
169
|
+
bun run preview # Vite
|
|
170
|
+
# or
|
|
171
|
+
bun run start # Next.js
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
3. **Test in browser:**
|
|
175
|
+
- Open DevTools → Application → Service Workers
|
|
176
|
+
- Check "Offline" checkbox to test offline mode
|
|
177
|
+
- Verify manifest in Application → Manifest
|
|
178
|
+
- Test "Add to Home Screen" prompt
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Requirements Checklist
|
|
183
|
+
|
|
184
|
+
- [ ] `appConfig.app.name` defined
|
|
185
|
+
- [ ] `appConfig.app.shortName` defined
|
|
186
|
+
- [ ] `appConfig.app.description` defined
|
|
187
|
+
- [ ] `pwa.enabled: true` in build config
|
|
188
|
+
- [ ] Icons in `public/` folder (auto-discovered)
|
|
189
|
+
- [ ] HTTPS in production (required for service workers)
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Troubleshooting
|
|
194
|
+
|
|
195
|
+
**PWA not working:**
|
|
196
|
+
- Check browser console for service worker errors
|
|
197
|
+
- Verify HTTPS (required except localhost)
|
|
198
|
+
- Check manifest.json exists in build output
|
|
199
|
+
- Verify app metadata is complete
|
|
200
|
+
|
|
201
|
+
**Icons not showing:**
|
|
202
|
+
- Ensure icons exist in `public/` folder
|
|
203
|
+
- Check icon formats (SVG, PNG, ICO supported)
|
|
204
|
+
- Verify AssetPlugin discovered icons (check build logs)
|
|
205
|
+
|
|
206
|
+
**Service worker not registering:**
|
|
207
|
+
- Check browser console for registration errors
|
|
208
|
+
- Verify HTTPS (service workers require secure context)
|
|
209
|
+
- Clear browser cache and hard refresh
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
**Zero config. Override when needed.**
|
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
# Routing Guide
|
|
2
|
+
|
|
3
|
+
**For AI Agents:** Use framework routing components/hooks. NEVER import from `react-router-dom` directly. Framework handles SPA navigation, Outlet, and overlay closing automatically.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🚨 Critical Rule: Never Use react-router-dom Directly
|
|
8
|
+
|
|
9
|
+
**❌ WRONG:**
|
|
10
|
+
```tsx
|
|
11
|
+
import { Link, useNavigate, useParams } from 'react-router-dom'; // ❌ BREAKS FRAMEWORK
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**✅ CORRECT:**
|
|
15
|
+
```tsx
|
|
16
|
+
import { Link, useNavigate, useParams } from '@donotdev/ui/routing'; // ✅ Framework routing
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Why?** The framework's routing components:
|
|
20
|
+
- Automatically close overlays on navigation
|
|
21
|
+
- Handle SPA navigation correctly with Outlet
|
|
22
|
+
- Work with both Vite and Next.js
|
|
23
|
+
- Integrate with auth and route discovery
|
|
24
|
+
- Provide proper TypeScript types
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Framework Routing API
|
|
29
|
+
|
|
30
|
+
### Components
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { Link, DnDevNavigationMenu } from '@donotdev/ui/routing';
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Link Component:**
|
|
37
|
+
```tsx
|
|
38
|
+
<Link path="/products" label="Products" icon="Package" />
|
|
39
|
+
<Link path="/users/:id" replace prefetch={false}>User Details</Link>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**DnDevNavigationMenu (Sidebar/Header):**
|
|
43
|
+
```tsx
|
|
44
|
+
// Auto-fetches routes, handles auth filtering
|
|
45
|
+
<DnDevNavigationMenu vertical display={DISPLAY.AUTO} />
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Hooks
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import {
|
|
52
|
+
useNavigate,
|
|
53
|
+
useLocation,
|
|
54
|
+
useParams,
|
|
55
|
+
useRouteParam,
|
|
56
|
+
useSearchParams,
|
|
57
|
+
useNavigationItems,
|
|
58
|
+
} from '@donotdev/ui/routing';
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Navigation Patterns
|
|
64
|
+
|
|
65
|
+
### 1. Basic Navigation
|
|
66
|
+
|
|
67
|
+
**✅ Use framework Link:**
|
|
68
|
+
```tsx
|
|
69
|
+
import { Link } from '@donotdev/ui/routing';
|
|
70
|
+
|
|
71
|
+
function ProductCard({ product }) {
|
|
72
|
+
return (
|
|
73
|
+
<Link path={`/products/${product.id}`} label={product.name} />
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**✅ Use framework useNavigate:**
|
|
79
|
+
```tsx
|
|
80
|
+
import { useNavigate } from '@donotdev/ui/routing';
|
|
81
|
+
|
|
82
|
+
function ProductForm() {
|
|
83
|
+
const navigate = useNavigate();
|
|
84
|
+
|
|
85
|
+
const handleSubmit = async () => {
|
|
86
|
+
await saveProduct();
|
|
87
|
+
navigate('/products'); // ✅ Closes overlays automatically
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
return <form onSubmit={handleSubmit}>...</form>;
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**❌ DON'T use react-router-dom:**
|
|
95
|
+
```tsx
|
|
96
|
+
import { useNavigate } from 'react-router-dom'; // ❌ BREAKS FRAMEWORK
|
|
97
|
+
|
|
98
|
+
function ProductForm() {
|
|
99
|
+
const navigate = useNavigate(); // ❌ Doesn't close overlays, breaks SPA
|
|
100
|
+
// ...
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### 2. Route Parameters
|
|
107
|
+
|
|
108
|
+
**✅ Use framework useRouteParam:**
|
|
109
|
+
```tsx
|
|
110
|
+
import { useRouteParam } from '@donotdev/ui/routing';
|
|
111
|
+
|
|
112
|
+
function ProductPage() {
|
|
113
|
+
const id = useRouteParam('id'); // ✅ Returns string | undefined
|
|
114
|
+
// Safe: handles string | string[] | undefined automatically
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**✅ Or use framework useParams:**
|
|
119
|
+
```tsx
|
|
120
|
+
import { useParams } from '@donotdev/ui/routing';
|
|
121
|
+
|
|
122
|
+
function ProductPage() {
|
|
123
|
+
const params = useParams();
|
|
124
|
+
const id = typeof params.id === 'string' ? params.id : undefined;
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**❌ DON'T use react-router-dom:**
|
|
129
|
+
```tsx
|
|
130
|
+
import { useParams } from 'react-router-dom'; // ❌ Type issues, breaks framework
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### 3. Sidebar Navigation
|
|
136
|
+
|
|
137
|
+
**✅ Use DnDevNavigationMenu (auto-fetches routes):**
|
|
138
|
+
```tsx
|
|
139
|
+
import { DnDevNavigationMenu, DISPLAY } from '@donotdev/ui/routing';
|
|
140
|
+
|
|
141
|
+
function Sidebar() {
|
|
142
|
+
return (
|
|
143
|
+
<DnDevNavigationMenu
|
|
144
|
+
vertical
|
|
145
|
+
display={DISPLAY.AUTO} // CSS-driven collapse
|
|
146
|
+
showIcons={true}
|
|
147
|
+
/>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**✅ Or use useNavigationItems for custom sidebar:**
|
|
153
|
+
```tsx
|
|
154
|
+
import { Link, useNavigationItems } from '@donotdev/ui/routing';
|
|
155
|
+
|
|
156
|
+
function CustomSidebar() {
|
|
157
|
+
const menuItems = useNavigationItems(); // ✅ Auth-filtered routes
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<nav>
|
|
161
|
+
{menuItems.map((item) => (
|
|
162
|
+
<Link
|
|
163
|
+
key={item.path}
|
|
164
|
+
path={item.path}
|
|
165
|
+
label={item.label}
|
|
166
|
+
icon={item.icon}
|
|
167
|
+
className={item.isActive ? 'active' : ''}
|
|
168
|
+
/>
|
|
169
|
+
))}
|
|
170
|
+
</nav>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**❌ DON'T manually build navigation:**
|
|
176
|
+
```tsx
|
|
177
|
+
import { Link } from 'react-router-dom'; // ❌ BREAKS FRAMEWORK
|
|
178
|
+
|
|
179
|
+
function Sidebar() {
|
|
180
|
+
// ❌ Doesn't integrate with route discovery
|
|
181
|
+
// ❌ Doesn't handle auth filtering
|
|
182
|
+
// ❌ Doesn't work with Outlet
|
|
183
|
+
return (
|
|
184
|
+
<nav>
|
|
185
|
+
<Link to="/products">Products</Link>
|
|
186
|
+
</nav>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
### 4. Programmatic Navigation
|
|
194
|
+
|
|
195
|
+
**✅ Use framework useNavigate:**
|
|
196
|
+
```tsx
|
|
197
|
+
import { useNavigate } from '@donotdev/ui/routing';
|
|
198
|
+
|
|
199
|
+
function LoginForm() {
|
|
200
|
+
const navigate = useNavigate();
|
|
201
|
+
|
|
202
|
+
const handleLogin = async () => {
|
|
203
|
+
await signIn();
|
|
204
|
+
navigate('/dashboard', { replace: true }); // ✅ Closes overlays
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
return <form onSubmit={handleLogin}>...</form>;
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**✅ Navigate back:**
|
|
212
|
+
```tsx
|
|
213
|
+
const navigate = useNavigate();
|
|
214
|
+
navigate('back'); // ✅ Framework handles browser history
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**✅ With options:**
|
|
218
|
+
```tsx
|
|
219
|
+
navigate('/products', {
|
|
220
|
+
replace: true, // Replace history entry
|
|
221
|
+
preserveScroll: true, // Preserve scroll position
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
### 5. Query Parameters
|
|
228
|
+
|
|
229
|
+
**✅ Use framework useSearchParams:**
|
|
230
|
+
```tsx
|
|
231
|
+
import { useSearchParams } from '@donotdev/ui/routing';
|
|
232
|
+
|
|
233
|
+
function ProductList() {
|
|
234
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
235
|
+
const page = searchParams.get('page') || '1';
|
|
236
|
+
|
|
237
|
+
const handlePageChange = (newPage: string) => {
|
|
238
|
+
setSearchParams({ page: newPage });
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
return <div>Page: {page}</div>;
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**✅ Or use useQueryParams helper:**
|
|
246
|
+
```tsx
|
|
247
|
+
import { useQueryParams } from '@donotdev/ui/routing';
|
|
248
|
+
|
|
249
|
+
function ProductList() {
|
|
250
|
+
const { page, sort } = useQueryParams({ page: '1', sort: 'name' });
|
|
251
|
+
// Returns { page: string, sort: string } with defaults
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
### 6. Route Matching
|
|
258
|
+
|
|
259
|
+
**✅ Use framework useMatch:**
|
|
260
|
+
```tsx
|
|
261
|
+
import { useMatch } from '@donotdev/ui/routing';
|
|
262
|
+
|
|
263
|
+
function NavigationItem({ path }) {
|
|
264
|
+
const isActive = useMatch(path);
|
|
265
|
+
return <Link path={path} className={isActive ? 'active' : ''} />;
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Outlet and Nested Routes
|
|
272
|
+
|
|
273
|
+
**Framework handles Outlet automatically.** You don't need to manually use `<Outlet />` in most cases.
|
|
274
|
+
|
|
275
|
+
### How It Works
|
|
276
|
+
|
|
277
|
+
1. **RootLayout** wraps all routes and includes `<Outlet />`
|
|
278
|
+
2. **DnDevLayout** receives `<Outlet />` and renders it in the main content area
|
|
279
|
+
3. **Routes are discovered** from `src/pages/*Page.tsx` files automatically
|
|
280
|
+
|
|
281
|
+
**✅ Your pages just render content:**
|
|
282
|
+
```tsx
|
|
283
|
+
// src/pages/ProductsPage.tsx
|
|
284
|
+
export function ProductsPage() {
|
|
285
|
+
return <div>Products List</div>; // ✅ Rendered via Outlet automatically
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**❌ DON'T manually use Outlet:**
|
|
290
|
+
```tsx
|
|
291
|
+
import { Outlet } from 'react-router-dom'; // ❌ BREAKS FRAMEWORK
|
|
292
|
+
|
|
293
|
+
export function ProductsPage() {
|
|
294
|
+
return (
|
|
295
|
+
<div>
|
|
296
|
+
<h1>Products</h1>
|
|
297
|
+
<Outlet /> {/* ❌ Framework already handles this */}
|
|
298
|
+
</div>
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Nested Routes (Advanced)
|
|
304
|
+
|
|
305
|
+
If you need nested routes, use the framework's route discovery:
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
// src/pages/products/ProductsPage.tsx
|
|
309
|
+
export const pageMeta = {
|
|
310
|
+
route: '/products',
|
|
311
|
+
// ...
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
// src/pages/products/ProductDetailPage.tsx
|
|
315
|
+
export const pageMeta = {
|
|
316
|
+
route: '/products/:id',
|
|
317
|
+
// ...
|
|
318
|
+
};
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Framework automatically creates nested route structure.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Route Discovery
|
|
326
|
+
|
|
327
|
+
**Routes are auto-discovered from `src/pages/*Page.tsx` files.**
|
|
328
|
+
|
|
329
|
+
**✅ Define routes with PageMeta:**
|
|
330
|
+
```tsx
|
|
331
|
+
// src/pages/ProductsPage.tsx
|
|
332
|
+
import type { PageMeta } from '@donotdev/core';
|
|
333
|
+
|
|
334
|
+
export const pageMeta: PageMeta = {
|
|
335
|
+
title: 'Products',
|
|
336
|
+
route: '/products',
|
|
337
|
+
icon: 'Package',
|
|
338
|
+
auth: { required: true, roles: ['user', 'admin'] },
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
export function ProductsPage() {
|
|
342
|
+
return <div>Products</div>;
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**Framework automatically:**
|
|
347
|
+
- Discovers routes from filesystem
|
|
348
|
+
- Generates navigation menus
|
|
349
|
+
- Filters by auth permissions
|
|
350
|
+
- Handles lazy loading
|
|
351
|
+
- Creates route structure
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Common Mistakes
|
|
356
|
+
|
|
357
|
+
### ❌ Mistake 1: Importing from react-router-dom
|
|
358
|
+
|
|
359
|
+
```tsx
|
|
360
|
+
// ❌ WRONG
|
|
361
|
+
import { Link, useNavigate } from 'react-router-dom';
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Fix:**
|
|
365
|
+
```tsx
|
|
366
|
+
// ✅ CORRECT
|
|
367
|
+
import { Link, useNavigate } from '@donotdev/ui/routing';
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
### ❌ Mistake 2: Manual Outlet Usage
|
|
373
|
+
|
|
374
|
+
```tsx
|
|
375
|
+
// ❌ WRONG
|
|
376
|
+
import { Outlet } from 'react-router-dom';
|
|
377
|
+
|
|
378
|
+
export function Layout() {
|
|
379
|
+
return <Outlet />; // Framework already handles this
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
**Fix:** Don't use Outlet manually. Framework handles it.
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
### ❌ Mistake 3: Manual Route Configuration
|
|
388
|
+
|
|
389
|
+
```tsx
|
|
390
|
+
// ❌ WRONG
|
|
391
|
+
import { Routes, Route } from 'react-router-dom';
|
|
392
|
+
|
|
393
|
+
function App() {
|
|
394
|
+
return (
|
|
395
|
+
<Routes>
|
|
396
|
+
<Route path="/products" element={<ProductsPage />} />
|
|
397
|
+
</Routes>
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**Fix:** Use route discovery. Create `src/pages/ProductsPage.tsx` with `pageMeta`.
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
### ❌ Mistake 4: Manual Navigation Menu
|
|
407
|
+
|
|
408
|
+
```tsx
|
|
409
|
+
// ❌ WRONG
|
|
410
|
+
function Sidebar() {
|
|
411
|
+
return (
|
|
412
|
+
<nav>
|
|
413
|
+
<Link to="/products">Products</Link>
|
|
414
|
+
<Link to="/users">Users</Link>
|
|
415
|
+
</nav>
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Fix:**
|
|
421
|
+
```tsx
|
|
422
|
+
// ✅ CORRECT
|
|
423
|
+
import { DnDevNavigationMenu } from '@donotdev/ui/routing';
|
|
424
|
+
|
|
425
|
+
function Sidebar() {
|
|
426
|
+
return <DnDevNavigationMenu vertical />; // Auto-fetches routes
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
### ❌ Mistake 5: Not Using Framework Link
|
|
433
|
+
|
|
434
|
+
```tsx
|
|
435
|
+
// ❌ WRONG
|
|
436
|
+
import { Link } from 'react-router-dom';
|
|
437
|
+
|
|
438
|
+
<Link to="/products">Products</Link>
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
**Fix:**
|
|
442
|
+
```tsx
|
|
443
|
+
// ✅ CORRECT
|
|
444
|
+
import { Link } from '@donotdev/ui/routing';
|
|
445
|
+
|
|
446
|
+
<Link path="/products" label="Products" />
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Quick Reference
|
|
452
|
+
|
|
453
|
+
### Import Paths
|
|
454
|
+
|
|
455
|
+
```tsx
|
|
456
|
+
// ✅ Framework routing (platform-agnostic)
|
|
457
|
+
import {
|
|
458
|
+
Link,
|
|
459
|
+
useNavigate,
|
|
460
|
+
useLocation,
|
|
461
|
+
useParams,
|
|
462
|
+
useRouteParam,
|
|
463
|
+
useSearchParams,
|
|
464
|
+
useNavigationItems,
|
|
465
|
+
DnDevNavigationMenu,
|
|
466
|
+
} from '@donotdev/ui/routing';
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Common Patterns
|
|
470
|
+
|
|
471
|
+
```tsx
|
|
472
|
+
// Navigation
|
|
473
|
+
const navigate = useNavigate();
|
|
474
|
+
navigate('/products');
|
|
475
|
+
navigate('back');
|
|
476
|
+
navigate('/products', { replace: true });
|
|
477
|
+
|
|
478
|
+
// Route params
|
|
479
|
+
const id = useRouteParam('id');
|
|
480
|
+
|
|
481
|
+
// Query params
|
|
482
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
483
|
+
const page = searchParams.get('page');
|
|
484
|
+
|
|
485
|
+
// Navigation menu
|
|
486
|
+
const menuItems = useNavigationItems(); // Auth-filtered routes
|
|
487
|
+
|
|
488
|
+
// Link component
|
|
489
|
+
<Link path="/products" label="Products" icon="Package" />
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
## Summary
|
|
495
|
+
|
|
496
|
+
1. **Always use `@donotdev/ui/routing`** - never `react-router-dom`
|
|
497
|
+
2. **Use `DnDevNavigationMenu`** for sidebars/headers
|
|
498
|
+
3. **Use `useNavigationItems()`** for custom navigation
|
|
499
|
+
4. **Don't use `<Outlet />` manually** - framework handles it
|
|
500
|
+
5. **Routes are auto-discovered** from `src/pages/*Page.tsx`
|
|
501
|
+
6. **Framework closes overlays** on navigation automatically
|
|
502
|
+
|
|
503
|
+
**Framework handles SPA navigation, Outlet, and route discovery. Use framework components/hooks only.**
|