@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
|
@@ -1,75 +1,103 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Application
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* @fileoverview Application Configuration
|
|
3
|
+
*
|
|
4
|
+
* THIS FILE IS YOUR MAIN CONFIGURATION. Update the values below.
|
|
5
|
+
*
|
|
6
|
+
* QUICK START:
|
|
7
|
+
* 1. Set APP_NAME and APP_SHORT_NAME
|
|
8
|
+
* 2. Choose your preset (see guide below)
|
|
9
|
+
* 3. Configure footer links
|
|
10
|
+
* 4. Run `bun dev` - everything else is automatic
|
|
7
11
|
*/
|
|
8
12
|
|
|
9
13
|
import type { AppConfig } from '@donotdev/core';
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* @version 0.0.1
|
|
15
|
-
* @since 0.0.1
|
|
16
|
-
* @author AMBROISE PARK Consulting
|
|
17
|
-
*/
|
|
18
|
-
export const APP_NAME = '{{appName}}';
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// APP IDENTITY - Update these values
|
|
17
|
+
// ============================================================================
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
* Application short name constant
|
|
22
|
-
*
|
|
23
|
-
* @version 0.0.1
|
|
24
|
-
* @since 0.0.1
|
|
25
|
-
* @author AMBROISE PARK Consulting
|
|
26
|
-
*/
|
|
19
|
+
export const APP_NAME = '{{appName}}';
|
|
27
20
|
export const APP_SHORT_NAME = '{{appShortName}}';
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Application description constant
|
|
31
|
-
*
|
|
32
|
-
* @version 0.0.1
|
|
33
|
-
* @since 0.0.1
|
|
34
|
-
* @author AMBROISE PARK Consulting
|
|
35
|
-
*/
|
|
36
21
|
export const APP_DESCRIPTION = 'Built with DoNotDev Framework';
|
|
37
22
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
* @since 0.0.1
|
|
43
|
-
* @author AMBROISE PARK Consulting
|
|
44
|
-
*/
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// MAIN CONFIGURATION
|
|
25
|
+
// ============================================================================
|
|
26
|
+
|
|
45
27
|
export const appConfig: AppConfig = {
|
|
46
28
|
app: {
|
|
47
29
|
name: APP_NAME,
|
|
48
30
|
shortName: APP_SHORT_NAME,
|
|
49
31
|
description: APP_DESCRIPTION,
|
|
50
|
-
//
|
|
51
|
-
|
|
32
|
+
// url: 'https://yourapp.com', // Uncomment for production
|
|
33
|
+
|
|
34
|
+
// Footer legal links - remove any you don't need
|
|
52
35
|
footer: {
|
|
53
36
|
legalLinks: [
|
|
54
37
|
{ path: '#cookie-settings', label: 'footer.legal.cookieSettings' },
|
|
55
38
|
{ path: '/legal/privacy', label: 'footer.legal.privacyPolicy' },
|
|
56
39
|
{ path: '/legal/terms', label: 'footer.legal.termsOfService' },
|
|
57
|
-
//
|
|
58
|
-
// { path: '/legal/legal-notice', label: 'footer.legal.legalNotice' },
|
|
59
|
-
// { path: '/license', label: 'License' },
|
|
40
|
+
// { path: '/legal/notice', label: 'footer.legal.legalNotice' },
|
|
60
41
|
],
|
|
61
42
|
},
|
|
62
43
|
},
|
|
63
|
-
|
|
44
|
+
|
|
45
|
+
// ==========================================================================
|
|
46
|
+
// PRESET GUIDE - Choose your layout
|
|
47
|
+
// ==========================================================================
|
|
48
|
+
//
|
|
49
|
+
// 'landing' → Marketing site. Full-width sections, centered content, no sidebar.
|
|
50
|
+
// Best for: Homepage, product pages, pricing, landing pages.
|
|
51
|
+
//
|
|
52
|
+
// 'admin' → Dashboard app. Collapsible sidebar, header with user menu.
|
|
53
|
+
// Best for: Admin panels, CRM, internal tools, CRUD apps.
|
|
54
|
+
//
|
|
55
|
+
// 'moolti' → Multi-panel. Left sidebar nav, optional right context sidebar.
|
|
56
|
+
// Best for: Complex apps with nested navigation, settings panels.
|
|
57
|
+
//
|
|
58
|
+
// 'docs' → Documentation. Left sidebar TOC, right sidebar on-page nav.
|
|
59
|
+
// Best for: Documentation sites, knowledge bases, help centers.
|
|
60
|
+
//
|
|
61
|
+
// 'blog' → Blog layout. Wide content area, optional category sidebar.
|
|
62
|
+
// Best for: Blog, news, articles, content-heavy sites.
|
|
63
|
+
//
|
|
64
|
+
// 'game' → Fullscreen. Minimal chrome, focus on content area.
|
|
65
|
+
// Best for: Games, immersive experiences, presentations.
|
|
66
|
+
//
|
|
67
|
+
// 'plain' → No layout. Just your pages, you handle everything.
|
|
68
|
+
// Best for: Custom layouts, embedded widgets, special cases.
|
|
69
|
+
//
|
|
70
|
+
preset: 'landing',
|
|
71
|
+
|
|
72
|
+
// ==========================================================================
|
|
73
|
+
// FEATURES - Uncomment to enable
|
|
74
|
+
// ==========================================================================
|
|
64
75
|
features: {
|
|
65
|
-
//
|
|
66
|
-
// debug: true,
|
|
76
|
+
// debug: true, // Enable debug tools in development
|
|
67
77
|
},
|
|
68
|
-
|
|
78
|
+
|
|
79
|
+
// ==========================================================================
|
|
80
|
+
// AUTH CONFIG - Uncomment to customize
|
|
81
|
+
// ==========================================================================
|
|
69
82
|
// auth: {
|
|
70
|
-
// authRoute: '/signin',
|
|
71
|
-
// roleRoute: '/403',
|
|
72
|
-
// tierRoute: '/pricing',
|
|
83
|
+
// authRoute: '/signin', // Redirect when auth required
|
|
84
|
+
// roleRoute: '/403', // Redirect when role insufficient
|
|
85
|
+
// tierRoute: '/pricing', // Redirect when subscription required
|
|
86
|
+
// profilePath: '/profile', // Profile page path (undefined to hide)
|
|
87
|
+
// authMenuItems: [ // Custom menu items for logged-in users
|
|
88
|
+
// { path: '/dashboard', label: 'Dashboard' },
|
|
89
|
+
// ],
|
|
90
|
+
// },
|
|
91
|
+
|
|
92
|
+
// ==========================================================================
|
|
93
|
+
// QUERY CACHE - Uncomment to enable auto-refetch
|
|
94
|
+
// ==========================================================================
|
|
95
|
+
// Default: Infinite cache (cost-optimized, manual refresh)
|
|
96
|
+
// Uncomment for auto-refetch behavior:
|
|
97
|
+
// query: {
|
|
98
|
+
// staleTime: 1000 * 60 * 5, // 5 minutes
|
|
99
|
+
// refetchOnWindowFocus: true,
|
|
100
|
+
// refetchOnReconnect: true,
|
|
73
101
|
// },
|
|
74
102
|
};
|
|
75
103
|
|
|
@@ -3,9 +3,17 @@
|
|
|
3
3
|
|
|
4
4
|
@import './themes.css';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Font configuration
|
|
8
|
+
*
|
|
9
|
+
* Framework defaults to Inter (defined in @donotdev/components/styles/variables.css).
|
|
10
|
+
* Fonts are loaded via CSS @font-face rules in @donotdev/ui/assets/fonts/fonts.css
|
|
11
|
+
* and copied to public/fonts/ by AssetDiscovery during build.
|
|
12
|
+
*
|
|
13
|
+
* To override, uncomment and customize:
|
|
14
|
+
* :root {
|
|
15
|
+
* --font-sans: 'YourFont', sans-serif;
|
|
16
|
+
* --font-mono: 'YourMonoFont', monospace;
|
|
17
|
+
* --font-family: var(--font-sans);
|
|
18
|
+
* }
|
|
19
|
+
*/
|
|
@@ -496,6 +496,10 @@
|
|
|
496
496
|
"copied": "Copied!",
|
|
497
497
|
"copyCodeToClipboard": "Copy code to clipboard"
|
|
498
498
|
},
|
|
499
|
+
"video": {
|
|
500
|
+
"clickToWatch": "Click to watch video",
|
|
501
|
+
"watchVideo": "Watch Video"
|
|
502
|
+
},
|
|
499
503
|
"inspector": {
|
|
500
504
|
"pageSource": "Page Source",
|
|
501
505
|
"inspectPageSourceCode": "Inspect page source code"
|
|
@@ -512,5 +516,69 @@
|
|
|
512
516
|
"goHome": "Go Home",
|
|
513
517
|
"goBack": "Go Back",
|
|
514
518
|
"contactSupport": "If the problem persists, please contact support."
|
|
519
|
+
},
|
|
520
|
+
"redirectOverlay": {
|
|
521
|
+
"phases": {
|
|
522
|
+
"connecting": "Connecting to secure server...",
|
|
523
|
+
"preparing": "Preparing your session...",
|
|
524
|
+
"redirecting": "Redirecting...",
|
|
525
|
+
"timeout": "Taking longer than expected..."
|
|
526
|
+
},
|
|
527
|
+
"cancel": "Cancel",
|
|
528
|
+
"doNotRefresh": "Please do not refresh or press back",
|
|
529
|
+
"default": {
|
|
530
|
+
"title": "Redirecting",
|
|
531
|
+
"message": "Please wait while we redirect you...",
|
|
532
|
+
"subtitle": "This may take a moment",
|
|
533
|
+
"ariaLabel": "Redirecting, please wait"
|
|
534
|
+
},
|
|
535
|
+
"stripe-checkout": {
|
|
536
|
+
"title": "Redirecting to Stripe",
|
|
537
|
+
"message": "Initializing secure payment...",
|
|
538
|
+
"subtitle": "This may take a moment on first load",
|
|
539
|
+
"ariaLabel": "Preparing secure checkout, please wait"
|
|
540
|
+
},
|
|
541
|
+
"stripe-portal": {
|
|
542
|
+
"title": "Redirecting to Stripe",
|
|
543
|
+
"message": "Opening billing portal...",
|
|
544
|
+
"subtitle": "Manage your subscription and invoices",
|
|
545
|
+
"ariaLabel": "Opening billing portal, please wait"
|
|
546
|
+
},
|
|
547
|
+
"oauth-google": {
|
|
548
|
+
"title": "Signing in with Google",
|
|
549
|
+
"message": "Connecting to Google...",
|
|
550
|
+
"subtitle": "You will be redirected to sign in",
|
|
551
|
+
"ariaLabel": "Signing in with Google, please wait"
|
|
552
|
+
},
|
|
553
|
+
"oauth-github": {
|
|
554
|
+
"title": "Signing in with GitHub",
|
|
555
|
+
"message": "Connecting to GitHub...",
|
|
556
|
+
"subtitle": "You will be redirected to sign in",
|
|
557
|
+
"ariaLabel": "Signing in with GitHub, please wait"
|
|
558
|
+
},
|
|
559
|
+
"oauth-apple": {
|
|
560
|
+
"title": "Signing in with Apple",
|
|
561
|
+
"message": "Connecting to Apple...",
|
|
562
|
+
"subtitle": "You will be redirected to sign in",
|
|
563
|
+
"ariaLabel": "Signing in with Apple, please wait"
|
|
564
|
+
},
|
|
565
|
+
"oauth-microsoft": {
|
|
566
|
+
"title": "Signing in with Microsoft",
|
|
567
|
+
"message": "Connecting to Microsoft...",
|
|
568
|
+
"subtitle": "You will be redirected to sign in",
|
|
569
|
+
"ariaLabel": "Signing in with Microsoft, please wait"
|
|
570
|
+
},
|
|
571
|
+
"oauth-facebook": {
|
|
572
|
+
"title": "Signing in with Facebook",
|
|
573
|
+
"message": "Connecting to Facebook...",
|
|
574
|
+
"subtitle": "You will be redirected to sign in",
|
|
575
|
+
"ariaLabel": "Signing in with Facebook, please wait"
|
|
576
|
+
},
|
|
577
|
+
"auth-email-link": {
|
|
578
|
+
"title": "Sending verification",
|
|
579
|
+
"message": "Preparing your verification link...",
|
|
580
|
+
"subtitle": "Check your email inbox",
|
|
581
|
+
"ariaLabel": "Sending verification email, please wait"
|
|
582
|
+
}
|
|
515
583
|
}
|
|
516
584
|
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Example CRUD Form Page (Create/Edit)
|
|
3
|
+
*
|
|
4
|
+
* COPY THIS FILE and rename (e.g., ProductPage.tsx, CustomerPage.tsx)
|
|
5
|
+
*
|
|
6
|
+
* HOW IT WORKS:
|
|
7
|
+
* 1. Route: /products/:id (edit) or /products/new (create)
|
|
8
|
+
* 2. EntityFormRenderer generates form from entity fields
|
|
9
|
+
* 3. useCrud provides get/add/update operations
|
|
10
|
+
* 4. Optimistic updates - navigation is instant, sync happens in background
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { useEffect, useState } from 'react';
|
|
14
|
+
|
|
15
|
+
import { Section, Button, Alert } from '@donotdev/components';
|
|
16
|
+
import { EntityFormRenderer, useCrud } from '@donotdev/crud';
|
|
17
|
+
import { useTranslation } from '@donotdev/core';
|
|
18
|
+
import type { PageMeta } from '@donotdev/core';
|
|
19
|
+
import { PageContainer, Link, useNavigate } from '@donotdev/ui';
|
|
20
|
+
|
|
21
|
+
// Import your entity from root-level entities folder
|
|
22
|
+
// import { productEntity } from 'entities/Product';
|
|
23
|
+
|
|
24
|
+
// Placeholder - replace with your entity import
|
|
25
|
+
const productEntity = null as any;
|
|
26
|
+
|
|
27
|
+
// Helper to get route param - replace with your routing solution
|
|
28
|
+
const useParam = (name: string) => {
|
|
29
|
+
// For react-router: const { id } = useParams();
|
|
30
|
+
// For TanStack Router: const { id } = Route.useParams();
|
|
31
|
+
return 'new'; // Placeholder
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// PAGE METADATA
|
|
36
|
+
// ============================================================================
|
|
37
|
+
|
|
38
|
+
export const NAMESPACE = 'product';
|
|
39
|
+
|
|
40
|
+
export const meta: PageMeta = {
|
|
41
|
+
namespace: NAMESPACE,
|
|
42
|
+
route: '/products/:id',
|
|
43
|
+
auth: { required: true, role: 'admin' },
|
|
44
|
+
hideFromMenu: true, // Don't show in navigation (accessed via list page)
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// PAGE COMPONENT
|
|
49
|
+
// ============================================================================
|
|
50
|
+
|
|
51
|
+
export default function ProductPage() {
|
|
52
|
+
const { t } = useTranslation(NAMESPACE);
|
|
53
|
+
const id = useParam('id');
|
|
54
|
+
const navigate = useNavigate();
|
|
55
|
+
const isNew = id === 'new';
|
|
56
|
+
|
|
57
|
+
// useCrud provides CRUD operations with optimistic updates
|
|
58
|
+
// backend: 'functions' uses Cloud Functions, 'firestore' uses direct Firestore
|
|
59
|
+
const { get, add, update, error } = useCrud(productEntity, { backend: 'functions' });
|
|
60
|
+
const [formData, setFormData] = useState<any>(null);
|
|
61
|
+
|
|
62
|
+
// ==========================================================================
|
|
63
|
+
// FETCH EXISTING DATA (edit mode only)
|
|
64
|
+
// ==========================================================================
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!isNew && id) {
|
|
67
|
+
get(id).then((data) => {
|
|
68
|
+
if (data) setFormData(data);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}, [id, isNew, get]);
|
|
72
|
+
|
|
73
|
+
// ==========================================================================
|
|
74
|
+
// FORM SUBMISSION - Optimistic Update Pattern
|
|
75
|
+
// ==========================================================================
|
|
76
|
+
const handleSubmit = async (data: any) => {
|
|
77
|
+
// OPTIMISTIC UPDATE: Fire and forget!
|
|
78
|
+
// We don't await the backend. We navigate immediately.
|
|
79
|
+
// CrudStore handles background sync and optimistic cache update.
|
|
80
|
+
|
|
81
|
+
if (isNew) {
|
|
82
|
+
add(data); // No await - fires in background
|
|
83
|
+
} else if (id) {
|
|
84
|
+
update(id, data); // No await - fires in background
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Instant navigation - feels incredibly fast
|
|
88
|
+
navigate('/products');
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// ==========================================================================
|
|
92
|
+
// ERROR STATE
|
|
93
|
+
// ==========================================================================
|
|
94
|
+
if (!isNew && error) {
|
|
95
|
+
return (
|
|
96
|
+
<PageContainer>
|
|
97
|
+
<Section title={t('error')}>
|
|
98
|
+
<Alert variant="error" description={t('failedToLoadData')} />
|
|
99
|
+
<Link path="/products">
|
|
100
|
+
<Button variant="outline">{t('backToList')}</Button>
|
|
101
|
+
</Link>
|
|
102
|
+
</Section>
|
|
103
|
+
</PageContainer>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ==========================================================================
|
|
108
|
+
// RENDER FORM
|
|
109
|
+
// ==========================================================================
|
|
110
|
+
return (
|
|
111
|
+
<PageContainer>
|
|
112
|
+
<Section
|
|
113
|
+
gridCols={[1, 1, 2, 2]} // Responsive: 1 col mobile, 2 cols desktop
|
|
114
|
+
title={isNew ? t('addNew') : t('edit')}
|
|
115
|
+
>
|
|
116
|
+
{isNew ? (
|
|
117
|
+
// CREATE MODE
|
|
118
|
+
<EntityFormRenderer
|
|
119
|
+
entity={productEntity}
|
|
120
|
+
operation="create"
|
|
121
|
+
onSubmit={handleSubmit}
|
|
122
|
+
defaultValues={{ status: 'draft' }} // Initial values for new items
|
|
123
|
+
submitText={t('create')}
|
|
124
|
+
/>
|
|
125
|
+
) : (
|
|
126
|
+
// EDIT MODE
|
|
127
|
+
<EntityFormRenderer
|
|
128
|
+
entity={productEntity}
|
|
129
|
+
operation="edit"
|
|
130
|
+
onSubmit={handleSubmit}
|
|
131
|
+
defaultValues={formData} // Loaded data
|
|
132
|
+
submitText={t('update')}
|
|
133
|
+
/>
|
|
134
|
+
)}
|
|
135
|
+
</Section>
|
|
136
|
+
</PageContainer>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ============================================================================
|
|
141
|
+
// i18n KEYS NEEDED (add to locales/product_en.json)
|
|
142
|
+
// ============================================================================
|
|
143
|
+
//
|
|
144
|
+
// {
|
|
145
|
+
// "addNew": "Add New Product",
|
|
146
|
+
// "edit": "Edit Product",
|
|
147
|
+
// "create": "Create Product",
|
|
148
|
+
// "update": "Update Product",
|
|
149
|
+
// "error": "Error",
|
|
150
|
+
// "failedToLoadData": "Failed to load product data",
|
|
151
|
+
// "backToList": "Back to Products"
|
|
152
|
+
// }
|
|
@@ -1,163 +1,110 @@
|
|
|
1
|
-
// apps/{{appName}}/src/pages/HomePage.tsx
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* @fileoverview Home
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* @fileoverview Home Page
|
|
3
|
+
*
|
|
4
|
+
* THIS FILE IS YOUR STARTING POINT. Modify the content below.
|
|
5
|
+
*
|
|
6
|
+
* HOW PAGES WORK:
|
|
7
|
+
* 1. Name files *Page.tsx in src/pages/ → auto-discovered as routes
|
|
8
|
+
* 2. Export `meta` for navigation, auth, icons
|
|
9
|
+
* 3. Export default function → your page component
|
|
10
|
+
* 4. Use PageContainer as wrapper → handles layout, scrolling
|
|
8
11
|
*/
|
|
9
12
|
|
|
10
13
|
import { Home } from 'lucide-react';
|
|
11
14
|
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
CallToAction,
|
|
15
|
-
Card,
|
|
16
|
-
Grid,
|
|
17
|
-
GridArea,
|
|
18
|
-
HeroSection,
|
|
19
|
-
RadioGroup,
|
|
20
|
-
Section,
|
|
21
|
-
Stack,
|
|
22
|
-
Text,
|
|
23
|
-
} from '@donotdev/components';
|
|
24
|
-
import {
|
|
25
|
-
useLayout,
|
|
26
|
-
useTranslation,
|
|
27
|
-
type LayoutPreset,
|
|
28
|
-
type PageMeta,
|
|
29
|
-
} from '@donotdev/core';
|
|
15
|
+
import { Button, HeroSection, Section, Card, Grid, Stack } from '@donotdev/components';
|
|
16
|
+
import type { PageMeta } from '@donotdev/core';
|
|
30
17
|
import { PageContainer, Link } from '@donotdev/ui';
|
|
31
18
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// PAGE METADATA - Controls routing, navigation, and access
|
|
21
|
+
// ============================================================================
|
|
22
|
+
//
|
|
23
|
+
// namespace → i18n namespace for translations (matches locales/home_en.json)
|
|
24
|
+
// icon → Navigation icon (from lucide-react)
|
|
25
|
+
// nav → Show in navigation (default: true, set false to hide)
|
|
26
|
+
// navGroup → Navigation group: 'main' | 'admin' | 'footer' (default: 'main')
|
|
27
|
+
// route → Custom route path (default: derived from filename)
|
|
28
|
+
// auth → Access control:
|
|
29
|
+
// - undefined → public (anyone can view)
|
|
30
|
+
// - true → requires login
|
|
31
|
+
// - 'admin' → requires admin role
|
|
32
|
+
// - { required: true, role: 'admin' } → full syntax
|
|
33
|
+
// tier → Subscription tier required: 'pro' | 'enterprise'
|
|
34
|
+
// hideFromMenu → Show in routing but hide from navigation menu
|
|
35
|
+
//
|
|
41
36
|
export const NAMESPACE = 'home';
|
|
42
37
|
|
|
43
38
|
export const meta: PageMeta = {
|
|
44
39
|
namespace: NAMESPACE,
|
|
45
40
|
icon: <Home />,
|
|
41
|
+
// nav: true, // Uncomment to hide from navigation
|
|
42
|
+
// navGroup: 'main', // 'main' | 'admin' | 'footer'
|
|
43
|
+
// route: '/', // Custom route (default: / for HomePage)
|
|
44
|
+
// auth: true, // Uncomment to require login
|
|
45
|
+
// auth: 'admin', // Uncomment to require admin role
|
|
46
|
+
// auth: { required: true, role: 'admin' }, // Full syntax
|
|
47
|
+
// tier: 'pro', // Uncomment to require subscription
|
|
48
|
+
// hideFromMenu: true, // Uncomment to hide from menu but keep route
|
|
46
49
|
};
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const { t } = useTranslation([NAMESPACE]);
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// PAGE COMPONENT
|
|
53
|
+
// ============================================================================
|
|
52
54
|
|
|
55
|
+
export default function HomePage() {
|
|
53
56
|
return (
|
|
54
57
|
<PageContainer>
|
|
58
|
+
{/* Hero Section - Full-width banner with title and subtitle */}
|
|
55
59
|
<HeroSection
|
|
56
|
-
title=
|
|
57
|
-
subtitle=
|
|
60
|
+
title="Welcome to Your App"
|
|
61
|
+
subtitle="Built with DoNotDev Framework. Edit this page in src/pages/HomePage.tsx"
|
|
58
62
|
variant="primary"
|
|
59
63
|
/>
|
|
60
64
|
|
|
61
|
-
{/*
|
|
62
|
-
<Section title="
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
value={currentPreset || 'landing'}
|
|
69
|
-
onValueChange={(value) => setLayoutPreset(value as LayoutPreset)}
|
|
70
|
-
gridCols={3}
|
|
71
|
-
items={LAYOUT_PRESETS.map((preset) => ({
|
|
72
|
-
value: preset,
|
|
73
|
-
label: preset.charAt(0).toUpperCase() + preset.slice(1),
|
|
74
|
-
}))}
|
|
75
|
-
/>
|
|
65
|
+
{/* Section - Content block with optional title */}
|
|
66
|
+
<Section title="Getting Started">
|
|
67
|
+
<Grid cols={[1, 1, 2, 3]} gap="medium">
|
|
68
|
+
<Card title="1. Configure" content="Edit src/config/app.ts to set your app name and preset." />
|
|
69
|
+
<Card title="2. Create Pages" content="Add *Page.tsx files in src/pages/ - they auto-route." />
|
|
70
|
+
<Card title="3. Add Content" content="Use components from @donotdev/components." />
|
|
71
|
+
</Grid>
|
|
76
72
|
</Section>
|
|
77
73
|
|
|
78
|
-
{/*
|
|
79
|
-
<Section title="Components
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
74
|
+
{/* Stack - Flexible container for buttons, inline items */}
|
|
75
|
+
<Section title="Layout Components">
|
|
76
|
+
<Stack direction="row" gap="medium" wrap>
|
|
77
|
+
<Button variant="primary">Primary Button</Button>
|
|
78
|
+
<Button variant="outline">Outline Button</Button>
|
|
79
|
+
<Button variant="ghost">Ghost Button</Button>
|
|
80
|
+
</Stack>
|
|
81
|
+
</Section>
|
|
82
|
+
|
|
83
|
+
{/* Call to Action */}
|
|
84
|
+
<Section tone="muted" align="center">
|
|
85
|
+
<Stack gap="medium" align="center">
|
|
86
|
+
<h2>Ready to Build?</h2>
|
|
87
|
+
<p>Check out the guides folder for setup instructions.</p>
|
|
86
88
|
<Stack direction="row" gap="medium">
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
<Button
|
|
90
|
+
variant="primary"
|
|
91
|
+
render={({ children, ...props }) => (
|
|
92
|
+
<Link path="https://donotdev.com" {...props}>{children}</Link>
|
|
93
|
+
)}
|
|
94
|
+
>
|
|
95
|
+
Documentation
|
|
96
|
+
</Button>
|
|
97
|
+
<Button
|
|
98
|
+
variant="outline"
|
|
99
|
+
render={({ children, ...props }) => (
|
|
100
|
+
<Link path="https://discord.gg/donotdev" {...props}>{children}</Link>
|
|
101
|
+
)}
|
|
102
|
+
>
|
|
103
|
+
Join Discord
|
|
104
|
+
</Button>
|
|
93
105
|
</Stack>
|
|
94
|
-
</
|
|
95
|
-
|
|
96
|
-
{/* Grid + GridArea Example */}
|
|
97
|
-
<Card title="Grid + GridArea Components">
|
|
98
|
-
<Text variant="muted">
|
|
99
|
-
Grid with named areas for complex layouts.
|
|
100
|
-
</Text>
|
|
101
|
-
<Grid
|
|
102
|
-
areas={`"header header"
|
|
103
|
-
"sidebar main"
|
|
104
|
-
"footer footer"`}
|
|
105
|
-
templateColumns="1fr 2fr"
|
|
106
|
-
gap="tight"
|
|
107
|
-
>
|
|
108
|
-
<GridArea name="header">
|
|
109
|
-
<Card variant="glass">
|
|
110
|
-
<Text>Header Header</Text>
|
|
111
|
-
</Card>
|
|
112
|
-
</GridArea>
|
|
113
|
-
<GridArea name="main">
|
|
114
|
-
<Card variant="glass">
|
|
115
|
-
<Text>Main 2fr</Text>
|
|
116
|
-
</Card>
|
|
117
|
-
</GridArea>
|
|
118
|
-
<GridArea name="sidebar">
|
|
119
|
-
<Card variant="glass">
|
|
120
|
-
<Text>Sidebar 1fr</Text>
|
|
121
|
-
</Card>
|
|
122
|
-
</GridArea>
|
|
123
|
-
<GridArea name="footer">
|
|
124
|
-
<Card variant="glass">
|
|
125
|
-
<Text>Footer Footer</Text>
|
|
126
|
-
</Card>
|
|
127
|
-
</GridArea>
|
|
128
|
-
</Grid>
|
|
129
|
-
</Card>
|
|
106
|
+
</Stack>
|
|
130
107
|
</Section>
|
|
131
|
-
|
|
132
|
-
{/* CallToAction */}
|
|
133
|
-
<CallToAction
|
|
134
|
-
title="Ready to Build?"
|
|
135
|
-
subtitle="Check out the guides folder for setup instructions."
|
|
136
|
-
primaryAction={
|
|
137
|
-
<Button
|
|
138
|
-
variant="primary"
|
|
139
|
-
render={({ children, ...props }) => (
|
|
140
|
-
<Link path="https://donotdev.com" {...props}>
|
|
141
|
-
{children}
|
|
142
|
-
</Link>
|
|
143
|
-
)}
|
|
144
|
-
>
|
|
145
|
-
Learn More
|
|
146
|
-
</Button>
|
|
147
|
-
}
|
|
148
|
-
secondaryAction={
|
|
149
|
-
<Button
|
|
150
|
-
variant="outline"
|
|
151
|
-
render={({ children, ...props }) => (
|
|
152
|
-
<Link path="https://discord.gg/fbeYWDak" {...props}>
|
|
153
|
-
{children}
|
|
154
|
-
</Link>
|
|
155
|
-
)}
|
|
156
|
-
>
|
|
157
|
-
Join Discord
|
|
158
|
-
</Button>
|
|
159
|
-
}
|
|
160
|
-
/>
|
|
161
108
|
</PageContainer>
|
|
162
109
|
);
|
|
163
110
|
}
|