@donotdev/cli 0.0.18 → 0.0.20
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 +42 -55
- package/dist/bin/commands/bump.js +5 -2
- package/dist/bin/commands/coach.js +8177 -0
- package/dist/bin/commands/create-app.js +6 -6
- package/dist/bin/commands/create-project.js +23 -9
- package/dist/bin/commands/deploy.js +99 -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 +524 -1713
- package/dist/bin/commands/staging.js +17870 -0
- package/dist/bin/commands/sync-secrets.js +2 -11
- package/dist/bin/commands/type-check.js +7738 -1712
- package/dist/bin/dndev.js +868 -199
- package/dist/bin/donotdev.js +868 -199
- package/dist/index.js +127 -67
- package/package.json +1 -1
- package/templates/app-demo/index.html.example +147 -10
- package/templates/app-demo/public/apple-touch-icon.png.example +0 -0
- package/templates/app-demo/public/favicon.svg.example +1 -0
- package/templates/app-demo/public/icon-192x192.png.example +0 -0
- package/templates/app-demo/public/icon-512x512.png.example +0 -0
- package/templates/app-demo/src/App.tsx.example +7 -11
- package/templates/app-demo/src/config/app.ts.example +13 -48
- package/templates/app-demo/src/entities/booking.ts.example +75 -0
- package/templates/app-demo/src/entities/onboarding.ts.example +160 -0
- package/templates/app-demo/src/entities/product.ts.example +50 -0
- package/templates/app-demo/src/entities/quote.ts.example +70 -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 +41 -0
- package/templates/app-demo/src/pages/ConditionalFormPage.tsx.example +88 -0
- package/templates/app-demo/src/pages/DashboardPage.tsx.example +17 -0
- package/templates/app-demo/src/pages/HomePage.tsx.example +339 -60
- package/templates/app-demo/src/pages/OnboardingPage.tsx.example +47 -0
- package/templates/app-demo/src/pages/PricingPage.tsx.example +41 -0
- package/templates/app-demo/src/pages/ProductsPage.tsx.example +19 -0
- package/templates/app-demo/src/pages/ProfilePage.tsx.example +18 -0
- package/templates/app-demo/src/pages/SettingsPage.tsx.example +17 -0
- package/templates/app-demo/src/pages/ShowcaseDetailPage.tsx.example +118 -0
- package/templates/app-demo/src/pages/ShowcasePage.tsx.example +93 -0
- package/templates/app-demo/src/pages/components/ComponentRenderer.tsx.example +147 -51
- package/templates/app-demo/src/pages/components/ComponentsData.tsx.example +103 -21
- package/templates/app-demo/src/pages/components/componentConfig.ts.example +139 -59
- package/templates/app-demo/src/pages/legal/LegalPage.tsx.example +25 -0
- package/templates/app-demo/src/pages/legal/PrivacyPage.tsx.example +23 -0
- package/templates/app-demo/src/pages/legal/TermsPage.tsx.example +23 -0
- package/templates/app-demo/src/themes.css.example +289 -77
- package/templates/app-demo/stats.html.example +4949 -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-next/src/locales/home_en.json.example +6 -6
- package/templates/app-vite/src/locales/home_en.json.example +6 -6
- 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/advanced/COOKIE_REFERENCE.md.example +252 -252
- package/templates/root-consumer/guides/dndev/advanced/VERSION_CONTROL.md.example +174 -174
- 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
|
@@ -1,46 +1,23 @@
|
|
|
1
|
+
// apps/demo/src/config/app.ts
|
|
1
2
|
/**
|
|
2
3
|
* @fileoverview Application configuration
|
|
3
|
-
* @description Defines application metadata and feature flags
|
|
4
|
-
* @version 0.0
|
|
4
|
+
* @description Defines application metadata, layout preset, and feature flags
|
|
5
|
+
* @version 0.1.0
|
|
5
6
|
* @since 0.0.1
|
|
6
7
|
* @author AMBROISE PARK Consulting
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
import type { AppConfig } from '@donotdev/core';
|
|
10
11
|
|
|
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}}';
|
|
12
|
+
export const APP_NAME = 'DoNotDev';
|
|
13
|
+
export const APP_SHORT_NAME = 'DoNotDev';
|
|
14
|
+
export const APP_DESCRIPTION = 'DoNotDev SaaS Template';
|
|
19
15
|
|
|
20
16
|
/**
|
|
21
|
-
* Application
|
|
17
|
+
* Application configuration
|
|
22
18
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* @author AMBROISE PARK Consulting
|
|
26
|
-
*/
|
|
27
|
-
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
|
-
export const APP_DESCRIPTION = 'DoNotDev Components Demo';
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Application configuration object
|
|
40
|
-
*
|
|
41
|
-
* @version 0.0.1
|
|
42
|
-
* @since 0.0.1
|
|
43
|
-
* @author AMBROISE PARK Consulting
|
|
19
|
+
* - preset: 'landing' is the app default. Pages can override via PageMeta.preset.
|
|
20
|
+
* - auth: Configure auth routes and menu items.
|
|
44
21
|
*/
|
|
45
22
|
export const appConfig: AppConfig = {
|
|
46
23
|
app: {
|
|
@@ -48,21 +25,9 @@ export const appConfig: AppConfig = {
|
|
|
48
25
|
shortName: APP_SHORT_NAME,
|
|
49
26
|
description: APP_DESCRIPTION,
|
|
50
27
|
},
|
|
51
|
-
preset: 'landing',
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
28
|
+
preset: 'landing',
|
|
29
|
+
auth: {
|
|
30
|
+
authRoute: '/pricing',
|
|
31
|
+
profilePath: '/profile',
|
|
55
32
|
},
|
|
56
|
-
// Optional: Override query cache defaults
|
|
57
|
-
// Framework defaults (infinite cache - cost-optimized):
|
|
58
|
-
// - staleTime: Infinity (data never becomes stale)
|
|
59
|
-
// - refetchOnWindowFocus: false (no auto-refetch on focus)
|
|
60
|
-
// - refetchOnReconnect: false (no auto-refetch on reconnect)
|
|
61
|
-
// This minimizes API costs and is ideal for single-admin apps with manual refresh buttons.
|
|
62
|
-
// Uncomment below to enable auto-refetch behavior:
|
|
63
|
-
// query: {
|
|
64
|
-
// staleTime: 1000 * 60 * 5, // 5 minutes - data becomes stale after 5 minutes
|
|
65
|
-
// refetchOnWindowFocus: true, // Automatically refetch when window regains focus
|
|
66
|
-
// refetchOnReconnect: true, // Automatically refetch when network reconnects
|
|
67
|
-
// },
|
|
68
33
|
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// apps/demo/src/entities/booking.ts
|
|
2
|
+
|
|
3
|
+
import { defineEntity, when } from '@donotdev/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Booking entity — demonstrates complex conditional logic.
|
|
7
|
+
*
|
|
8
|
+
* - groupSize: visible only for group bookings
|
|
9
|
+
* - companyName: visible only for corporate bookings
|
|
10
|
+
* - invoiceAddress: visible for corporate OR group with 10+ people
|
|
11
|
+
*/
|
|
12
|
+
export const bookingEntity = defineEntity({
|
|
13
|
+
name: 'Booking',
|
|
14
|
+
collection: 'bookings',
|
|
15
|
+
fields: {
|
|
16
|
+
bookingType: {
|
|
17
|
+
name: 'bookingType',
|
|
18
|
+
type: 'select',
|
|
19
|
+
label: 'Booking Type',
|
|
20
|
+
visibility: 'user',
|
|
21
|
+
validation: {
|
|
22
|
+
required: true,
|
|
23
|
+
options: [
|
|
24
|
+
{ value: 'individual', label: 'Individual' },
|
|
25
|
+
{ value: 'group', label: 'Group (5+)' },
|
|
26
|
+
{ value: 'corporate', label: 'Corporate' },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
groupSize: {
|
|
31
|
+
name: 'groupSize',
|
|
32
|
+
type: 'number',
|
|
33
|
+
label: 'Number of People',
|
|
34
|
+
visibility: 'user',
|
|
35
|
+
conditions: {
|
|
36
|
+
visible: when('bookingType').equals('group'),
|
|
37
|
+
required: when('bookingType').equals('group'),
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
companyName: {
|
|
41
|
+
name: 'companyName',
|
|
42
|
+
type: 'text',
|
|
43
|
+
label: 'Company Name',
|
|
44
|
+
visibility: 'user',
|
|
45
|
+
conditions: {
|
|
46
|
+
visible: when('bookingType').equals('corporate'),
|
|
47
|
+
required: when('bookingType').equals('corporate'),
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
invoiceAddress: {
|
|
51
|
+
name: 'invoiceAddress',
|
|
52
|
+
type: 'address',
|
|
53
|
+
label: 'Invoice Address',
|
|
54
|
+
visibility: 'user',
|
|
55
|
+
conditions: {
|
|
56
|
+
visible: when('bookingType')
|
|
57
|
+
.equals('corporate')
|
|
58
|
+
.or(when('groupSize').greaterThan(10)),
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
date: {
|
|
62
|
+
name: 'date',
|
|
63
|
+
type: 'date',
|
|
64
|
+
label: 'Booking Date',
|
|
65
|
+
visibility: 'user',
|
|
66
|
+
validation: { required: true },
|
|
67
|
+
},
|
|
68
|
+
notes: {
|
|
69
|
+
name: 'notes',
|
|
70
|
+
type: 'textarea',
|
|
71
|
+
label: 'Special Requests',
|
|
72
|
+
visibility: 'user',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
});
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// apps/demo/src/entities/onboarding.ts
|
|
2
|
+
|
|
3
|
+
import { defineEntity, when } from '@donotdev/core';
|
|
4
|
+
import { defineWorkflow } from '@donotdev/crud';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Entities for the Customer Onboarding workflow demo.
|
|
8
|
+
* Each entity represents one step in the wizard.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export const companyEntity = defineEntity({
|
|
12
|
+
name: 'Company',
|
|
13
|
+
collection: 'companies',
|
|
14
|
+
fields: {
|
|
15
|
+
name: {
|
|
16
|
+
name: 'name',
|
|
17
|
+
type: 'text',
|
|
18
|
+
label: 'Company Name',
|
|
19
|
+
visibility: 'user',
|
|
20
|
+
validation: { required: true, minLength: 2 },
|
|
21
|
+
},
|
|
22
|
+
industry: {
|
|
23
|
+
name: 'industry',
|
|
24
|
+
type: 'select',
|
|
25
|
+
label: 'Industry',
|
|
26
|
+
visibility: 'user',
|
|
27
|
+
validation: {
|
|
28
|
+
required: true,
|
|
29
|
+
options: [
|
|
30
|
+
{ value: 'tech', label: 'Technology' },
|
|
31
|
+
{ value: 'finance', label: 'Finance' },
|
|
32
|
+
{ value: 'healthcare', label: 'Healthcare' },
|
|
33
|
+
{ value: 'retail', label: 'Retail' },
|
|
34
|
+
{ value: 'other', label: 'Other' },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
size: {
|
|
39
|
+
name: 'size',
|
|
40
|
+
type: 'number',
|
|
41
|
+
label: 'Number of Employees',
|
|
42
|
+
visibility: 'user',
|
|
43
|
+
validation: { required: true, min: 1 },
|
|
44
|
+
},
|
|
45
|
+
website: {
|
|
46
|
+
name: 'website',
|
|
47
|
+
type: 'url',
|
|
48
|
+
label: 'Website',
|
|
49
|
+
visibility: 'user',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const contactEntity = defineEntity({
|
|
55
|
+
name: 'Contact',
|
|
56
|
+
collection: 'contacts',
|
|
57
|
+
fields: {
|
|
58
|
+
firstName: {
|
|
59
|
+
name: 'firstName',
|
|
60
|
+
type: 'text',
|
|
61
|
+
label: 'First Name',
|
|
62
|
+
visibility: 'user',
|
|
63
|
+
validation: { required: true },
|
|
64
|
+
},
|
|
65
|
+
lastName: {
|
|
66
|
+
name: 'lastName',
|
|
67
|
+
type: 'text',
|
|
68
|
+
label: 'Last Name',
|
|
69
|
+
visibility: 'user',
|
|
70
|
+
validation: { required: true },
|
|
71
|
+
},
|
|
72
|
+
email: {
|
|
73
|
+
name: 'email',
|
|
74
|
+
type: 'email',
|
|
75
|
+
label: 'Email',
|
|
76
|
+
visibility: 'user',
|
|
77
|
+
validation: { required: true },
|
|
78
|
+
},
|
|
79
|
+
phone: {
|
|
80
|
+
name: 'phone',
|
|
81
|
+
type: 'tel',
|
|
82
|
+
label: 'Phone',
|
|
83
|
+
visibility: 'user',
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
export const preferencesEntity = defineEntity({
|
|
89
|
+
name: 'Preferences',
|
|
90
|
+
collection: 'preferences',
|
|
91
|
+
fields: {
|
|
92
|
+
language: {
|
|
93
|
+
name: 'language',
|
|
94
|
+
type: 'select',
|
|
95
|
+
label: 'Language',
|
|
96
|
+
visibility: 'user',
|
|
97
|
+
validation: {
|
|
98
|
+
options: [
|
|
99
|
+
{ value: 'en', label: 'English' },
|
|
100
|
+
{ value: 'fr', label: 'French' },
|
|
101
|
+
{ value: 'de', label: 'German' },
|
|
102
|
+
{ value: 'es', label: 'Spanish' },
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
notifications: {
|
|
107
|
+
name: 'notifications',
|
|
108
|
+
type: 'switch',
|
|
109
|
+
label: 'Enable Email Notifications',
|
|
110
|
+
visibility: 'user',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Customer Onboarding Workflow
|
|
117
|
+
*
|
|
118
|
+
* 4 steps:
|
|
119
|
+
* 1. Company Info (required)
|
|
120
|
+
* 2. Primary Contact (required)
|
|
121
|
+
* 3. Preferences (skippable)
|
|
122
|
+
* 4. Billing — only shown if company size > 10
|
|
123
|
+
*/
|
|
124
|
+
export const onboardingWorkflow = defineWorkflow({
|
|
125
|
+
id: 'customer-onboarding',
|
|
126
|
+
name: 'Customer Onboarding',
|
|
127
|
+
persist: true,
|
|
128
|
+
|
|
129
|
+
steps: [
|
|
130
|
+
{
|
|
131
|
+
id: 'company',
|
|
132
|
+
title: 'Company Info',
|
|
133
|
+
entity: companyEntity,
|
|
134
|
+
fields: ['name', 'industry', 'size', 'website'],
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: 'contact',
|
|
138
|
+
title: 'Primary Contact',
|
|
139
|
+
entity: contactEntity,
|
|
140
|
+
fields: ['firstName', 'lastName', 'email', 'phone'],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: 'preferences',
|
|
144
|
+
title: 'Preferences',
|
|
145
|
+
entity: preferencesEntity,
|
|
146
|
+
fields: ['language', 'notifications'],
|
|
147
|
+
allowSkip: true,
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: 'billing',
|
|
151
|
+
title: 'Billing',
|
|
152
|
+
description: 'Required for companies with more than 10 employees',
|
|
153
|
+
entity: companyEntity,
|
|
154
|
+
fields: ['website'], // placeholder — real app would have billing entity
|
|
155
|
+
conditions: {
|
|
156
|
+
visible: when('size').greaterThan(10),
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// apps/demo/src/entities/product.ts
|
|
2
|
+
|
|
3
|
+
import { defineEntity } from '@donotdev/core';
|
|
4
|
+
|
|
5
|
+
export const productEntity = defineEntity({
|
|
6
|
+
name: 'Product',
|
|
7
|
+
collection: 'products',
|
|
8
|
+
fields: {
|
|
9
|
+
name: {
|
|
10
|
+
name: 'name',
|
|
11
|
+
label: 'Name',
|
|
12
|
+
type: 'text',
|
|
13
|
+
visibility: 'user',
|
|
14
|
+
validation: { required: true, minLength: 3 },
|
|
15
|
+
},
|
|
16
|
+
description: {
|
|
17
|
+
name: 'description',
|
|
18
|
+
label: 'Description',
|
|
19
|
+
type: 'textarea',
|
|
20
|
+
visibility: 'user',
|
|
21
|
+
},
|
|
22
|
+
price: {
|
|
23
|
+
name: 'price',
|
|
24
|
+
label: 'Price',
|
|
25
|
+
type: 'number',
|
|
26
|
+
visibility: 'user',
|
|
27
|
+
validation: { required: true, min: 0 },
|
|
28
|
+
},
|
|
29
|
+
category: {
|
|
30
|
+
name: 'category',
|
|
31
|
+
label: 'Category',
|
|
32
|
+
type: 'select',
|
|
33
|
+
visibility: 'user',
|
|
34
|
+
validation: {
|
|
35
|
+
options: [
|
|
36
|
+
{ value: 'electronics', label: 'Electronics' },
|
|
37
|
+
{ value: 'clothing', label: 'Clothing' },
|
|
38
|
+
{ value: 'food', label: 'Food & Drink' },
|
|
39
|
+
{ value: 'other', label: 'Other' },
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
image: {
|
|
44
|
+
name: 'image',
|
|
45
|
+
label: 'Image',
|
|
46
|
+
type: 'image',
|
|
47
|
+
visibility: 'user',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// apps/demo/src/entities/quote.ts
|
|
2
|
+
|
|
3
|
+
import { defineEntity, when } from '@donotdev/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Insurance Quote entity — demonstrates conditional field visibility.
|
|
7
|
+
*
|
|
8
|
+
* - licensePlate: only visible when productType === 'car'
|
|
9
|
+
* - propertyAddress: only visible when productType === 'home'
|
|
10
|
+
* - estimatedValue: visible for car OR home (not health)
|
|
11
|
+
* - notes: disabled until productType is selected
|
|
12
|
+
*/
|
|
13
|
+
export const quoteEntity = defineEntity({
|
|
14
|
+
name: 'Quote',
|
|
15
|
+
collection: 'quotes',
|
|
16
|
+
fields: {
|
|
17
|
+
productType: {
|
|
18
|
+
name: 'productType',
|
|
19
|
+
type: 'select',
|
|
20
|
+
label: 'Product',
|
|
21
|
+
visibility: 'user',
|
|
22
|
+
validation: {
|
|
23
|
+
required: true,
|
|
24
|
+
options: [
|
|
25
|
+
{ value: 'health', label: 'Health Insurance' },
|
|
26
|
+
{ value: 'car', label: 'Car Insurance' },
|
|
27
|
+
{ value: 'home', label: 'Home Insurance' },
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
licensePlate: {
|
|
32
|
+
name: 'licensePlate',
|
|
33
|
+
type: 'text',
|
|
34
|
+
label: 'License Plate',
|
|
35
|
+
visibility: 'user',
|
|
36
|
+
conditions: {
|
|
37
|
+
visible: when('productType').equals('car'),
|
|
38
|
+
required: when('productType').equals('car'),
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
propertyAddress: {
|
|
42
|
+
name: 'propertyAddress',
|
|
43
|
+
type: 'address',
|
|
44
|
+
label: 'Property Address',
|
|
45
|
+
visibility: 'user',
|
|
46
|
+
conditions: {
|
|
47
|
+
visible: when('productType').equals('home'),
|
|
48
|
+
required: when('productType').equals('home'),
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
estimatedValue: {
|
|
52
|
+
name: 'estimatedValue',
|
|
53
|
+
type: 'number',
|
|
54
|
+
label: 'Estimated Value',
|
|
55
|
+
visibility: 'user',
|
|
56
|
+
conditions: {
|
|
57
|
+
visible: when('productType').in(['car', 'home']),
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
notes: {
|
|
61
|
+
name: 'notes',
|
|
62
|
+
type: 'textarea',
|
|
63
|
+
label: 'Additional Notes',
|
|
64
|
+
visibility: 'user',
|
|
65
|
+
conditions: {
|
|
66
|
+
disabled: when('productType').notExists(),
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
});
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
/* apps/demo/src/globals.css */
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/* 1. Group all imports at the top. */
|
|
4
|
+
@import '@donotdev/ui/dndev.css';
|
|
4
5
|
@import './themes.css';
|
|
6
|
+
|
|
7
|
+
/* 2. App-specific overrides — DO NOT set --font-family here,
|
|
8
|
+
it would clobber theme overrides (dark/terminal set it to mono) */
|
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
// apps/demo/src/main.tsx
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Demo application entry point
|
|
5
|
+
* @description Main entry point for the DoNotDev framework demo application
|
|
6
|
+
*
|
|
7
|
+
* Initializes React with StrictMode for development safety.
|
|
8
|
+
* Shell loader management is handled by BaseStoresInitializer for optimal timing.
|
|
9
|
+
*
|
|
10
|
+
* @version 0.0.1
|
|
11
|
+
* @since 0.0.1
|
|
12
|
+
* @author AMBROISE PARK Consulting
|
|
13
|
+
*/
|
|
14
|
+
|
|
3
15
|
import './globals.css';
|
|
4
16
|
import React from 'react';
|
|
5
17
|
import ReactDOM from 'react-dom/client';
|
|
6
18
|
|
|
7
19
|
import { App } from './App';
|
|
8
20
|
|
|
21
|
+
// Ensure the root element exists
|
|
9
22
|
const rootElement = document.getElementById('root');
|
|
10
23
|
if (!rootElement) {
|
|
11
24
|
throw new Error(
|
|
@@ -13,13 +26,6 @@ if (!rootElement) {
|
|
|
13
26
|
);
|
|
14
27
|
}
|
|
15
28
|
|
|
16
|
-
// Remove shell loader (fade out then remove)
|
|
17
|
-
const shellLoader = document.getElementById('shell-loader');
|
|
18
|
-
if (shellLoader) {
|
|
19
|
-
shellLoader.classList.add('shell-loader--fading');
|
|
20
|
-
window.setTimeout(() => shellLoader.remove(), 300);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
29
|
ReactDOM.createRoot(rootElement).render(
|
|
24
30
|
<React.StrictMode>
|
|
25
31
|
<App />
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// apps/demo/src/pages/ChangelogPage.tsx
|
|
2
|
+
|
|
3
|
+
import { History } from 'lucide-react';
|
|
4
|
+
|
|
5
|
+
import { WhatsNewTemplate } from '@donotdev/templates';
|
|
6
|
+
|
|
7
|
+
import type { PageMeta } from '@donotdev/core';
|
|
8
|
+
|
|
9
|
+
export const meta: PageMeta = {
|
|
10
|
+
icon: <History />,
|
|
11
|
+
preset: 'docs',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default function ChangelogPage() {
|
|
15
|
+
return (
|
|
16
|
+
<WhatsNewTemplate
|
|
17
|
+
changelog={[
|
|
18
|
+
{
|
|
19
|
+
version: '1.0.0',
|
|
20
|
+
date: '2026-01-15',
|
|
21
|
+
type: 'major',
|
|
22
|
+
title: 'Initial Release',
|
|
23
|
+
description: 'First public release of the demo app.',
|
|
24
|
+
changes: [
|
|
25
|
+
{
|
|
26
|
+
type: 'added',
|
|
27
|
+
items: [
|
|
28
|
+
'Condition builder with when() API',
|
|
29
|
+
'Multi-step workflow engine',
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: 'changed',
|
|
34
|
+
items: ['Entity form renderer supports dynamic fields'],
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
]}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// apps/demo/src/pages/ConditionalFormPage.tsx
|
|
2
|
+
|
|
3
|
+
import { SlidersHorizontal } from 'lucide-react';
|
|
4
|
+
|
|
5
|
+
import { Card, Tabs } from '@donotdev/components';
|
|
6
|
+
import { EntityFormRenderer } from '@donotdev/ui';
|
|
7
|
+
|
|
8
|
+
import { quoteEntity } from '../entities/quote';
|
|
9
|
+
import { bookingEntity } from '../entities/booking';
|
|
10
|
+
|
|
11
|
+
import type { PageMeta } from '@donotdev/core';
|
|
12
|
+
|
|
13
|
+
export const meta: PageMeta = {
|
|
14
|
+
icon: <SlidersHorizontal />,
|
|
15
|
+
title: 'Conditional Forms',
|
|
16
|
+
preset: 'admin',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Conditional Forms Demo — shows field visibility driven by `when()` conditions.
|
|
21
|
+
*
|
|
22
|
+
* Two examples:
|
|
23
|
+
* 1. Insurance Quote — fields appear/disappear based on product type
|
|
24
|
+
* 2. Booking — complex conditions with .or() combinator
|
|
25
|
+
*/
|
|
26
|
+
export default function ConditionalFormPage() {
|
|
27
|
+
return (
|
|
28
|
+
<div style={{ maxWidth: 640, margin: '0 auto' }}>
|
|
29
|
+
<Card
|
|
30
|
+
title="Conditional Forms"
|
|
31
|
+
content="Fields appear, hide, or become required based on other field values. Powered by when() condition builder."
|
|
32
|
+
>
|
|
33
|
+
<Tabs
|
|
34
|
+
items={[
|
|
35
|
+
{
|
|
36
|
+
value: 'quote',
|
|
37
|
+
label: 'Insurance Quote',
|
|
38
|
+
content: (
|
|
39
|
+
<Card
|
|
40
|
+
title="Insurance Quote"
|
|
41
|
+
content='Select a product type to see conditional fields appear. "Car" shows license plate, "Home" shows address, both show estimated value.'
|
|
42
|
+
>
|
|
43
|
+
<EntityFormRenderer
|
|
44
|
+
entity={quoteEntity}
|
|
45
|
+
operation="create"
|
|
46
|
+
onSubmit={async (data) => {
|
|
47
|
+
alert(
|
|
48
|
+
`Quote submitted: ${JSON.stringify(data, null, 2)}`
|
|
49
|
+
);
|
|
50
|
+
}}
|
|
51
|
+
submitText="Get Quote"
|
|
52
|
+
cancelText={null}
|
|
53
|
+
warnOnUnsavedChanges={false}
|
|
54
|
+
hideVisibilityInfo
|
|
55
|
+
/>
|
|
56
|
+
</Card>
|
|
57
|
+
),
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
value: 'booking',
|
|
61
|
+
label: 'Booking',
|
|
62
|
+
content: (
|
|
63
|
+
<Card
|
|
64
|
+
title="Booking Form"
|
|
65
|
+
content='"Group" shows group size, "Corporate" shows company name. Invoice address appears for corporate OR groups with 10+ people.'
|
|
66
|
+
>
|
|
67
|
+
<EntityFormRenderer
|
|
68
|
+
entity={bookingEntity}
|
|
69
|
+
operation="create"
|
|
70
|
+
onSubmit={async (data) => {
|
|
71
|
+
alert(
|
|
72
|
+
`Booking submitted: ${JSON.stringify(data, null, 2)}`
|
|
73
|
+
);
|
|
74
|
+
}}
|
|
75
|
+
submitText="Book Now"
|
|
76
|
+
cancelText={null}
|
|
77
|
+
warnOnUnsavedChanges={false}
|
|
78
|
+
hideVisibilityInfo
|
|
79
|
+
/>
|
|
80
|
+
</Card>
|
|
81
|
+
),
|
|
82
|
+
},
|
|
83
|
+
]}
|
|
84
|
+
/>
|
|
85
|
+
</Card>
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// apps/demo/src/pages/DashboardPage.tsx
|
|
2
|
+
|
|
3
|
+
import { LayoutDashboard } from 'lucide-react';
|
|
4
|
+
|
|
5
|
+
import { DashboardTemplate } from '@donotdev/templates';
|
|
6
|
+
|
|
7
|
+
import type { PageMeta } from '@donotdev/core';
|
|
8
|
+
|
|
9
|
+
export const meta: PageMeta = {
|
|
10
|
+
icon: <LayoutDashboard />,
|
|
11
|
+
auth: true,
|
|
12
|
+
preset: 'admin',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default function DashboardPage() {
|
|
16
|
+
return <DashboardTemplate />;
|
|
17
|
+
}
|