create-m5kdev 0.25.3 → 0.26.1
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/dist/src/create.cjs +18 -1
- package/dist/src/create.cjs.map +1 -1
- package/dist/src/fs.cjs +65 -5
- package/dist/src/fs.cjs.map +1 -1
- package/dist/src/fs.d.cts +13 -2
- package/dist/src/index.cjs +0 -0
- package/dist/src/paths.cjs +2 -2
- package/dist/src/prompts.cjs +22 -0
- package/dist/src/prompts.cjs.map +1 -1
- package/dist/src/runCli.cjs +13 -2
- package/dist/src/runCli.cjs.map +1 -1
- package/dist/src/types.d.cts +9 -1
- package/package.json +8 -6
- package/templates/minimal-app/.cursor/rules/frontend-data-guide.mdc +46 -3
- package/templates/minimal-app/.cursor/rules/module-db-guide.mdc +15 -1
- package/templates/minimal-app/.cursor/rules/module-dto-guide.mdc +60 -0
- package/templates/minimal-app/.cursor/rules/module-repository-guide.mdc +98 -193
- package/templates/minimal-app/.cursor/rules/module-schema-guide.mdc +53 -173
- package/templates/minimal-app/.cursor/rules/module-service-guide.mdc +133 -240
- package/templates/minimal-app/.cursor/rules/module-trpc-guide.mdc +71 -113
- package/templates/minimal-app/README.md.tpl +3 -3
- package/templates/minimal-app/apps/.gitignore.tpl +13 -0
- package/templates/minimal-app/apps/e2e/package.json.tpl +23 -0
- package/templates/minimal-app/apps/e2e/playwright.config.ts.tpl +39 -0
- package/templates/minimal-app/apps/e2e/playwright.expo.config.ts.tpl +38 -0
- package/templates/minimal-app/apps/e2e/servers.ts.tpl +100 -0
- package/templates/minimal-app/apps/e2e/tests/email.spec.ts.tpl +47 -0
- package/templates/minimal-app/apps/e2e/tests/expo-helpers.ts.tpl +73 -0
- package/templates/minimal-app/apps/e2e/tests/expo-standard.spec.ts.tpl +517 -0
- package/templates/minimal-app/apps/e2e/tests/expo-waitlist.spec.ts.tpl +94 -0
- package/templates/minimal-app/apps/e2e/tests/helpers.ts.tpl +289 -0
- package/templates/minimal-app/apps/e2e/tests/standard.spec.ts.tpl +516 -0
- package/templates/minimal-app/apps/e2e/tests/waitlist.spec.ts.tpl +107 -0
- package/templates/minimal-app/apps/e2e/tsconfig.json.tpl +10 -0
- package/templates/minimal-app/apps/email/package.json.tpl +34 -34
- package/templates/minimal-app/apps/email/src/emails/accountDeletionEmail.tsx.tpl +35 -34
- package/templates/minimal-app/apps/email/src/emails/organizationInviteEmail.tsx.tpl +34 -33
- package/templates/minimal-app/apps/email/src/emails/passwordResetEmail.tsx.tpl +35 -34
- package/templates/minimal-app/apps/email/src/emails/verificationEmail.tsx.tpl +37 -36
- package/templates/minimal-app/apps/email/src/emails/waitlistEmails.tsx.tpl +87 -0
- package/templates/minimal-app/apps/email/src/index.ts.tpl +72 -32
- package/templates/minimal-app/apps/email/src/resources.ts.tpl +65 -36
- package/templates/minimal-app/apps/email/tsconfig.json.tpl +16 -11
- package/templates/minimal-app/apps/expo/.gitignore.tpl +44 -0
- package/templates/minimal-app/apps/expo/.prettierignore +13 -0
- package/templates/minimal-app/apps/expo/.prettierrc.json.tpl +9 -0
- package/templates/minimal-app/apps/expo/CHANGELOG.md.tpl +156 -0
- package/templates/minimal-app/apps/expo/README.md.tpl +44 -0
- package/templates/minimal-app/apps/expo/app.json.tpl +36 -0
- package/templates/minimal-app/apps/expo/assets/images/adaptive-icon.png +0 -0
- package/templates/minimal-app/apps/expo/assets/images/favicon.png +0 -0
- package/templates/minimal-app/apps/expo/assets/images/icon.png +0 -0
- package/templates/minimal-app/apps/expo/assets/images/splash-icon.png +0 -0
- package/templates/minimal-app/apps/expo/eslint.config.js.tpl +8 -0
- package/templates/minimal-app/apps/expo/expo-env.d.ts.tpl +3 -0
- package/templates/minimal-app/apps/expo/metro.config.js.tpl +16 -0
- package/templates/minimal-app/apps/expo/package.json.tpl +59 -0
- package/templates/minimal-app/apps/expo/src/app/_layout.tsx.tpl +31 -0
- package/templates/minimal-app/apps/expo/src/app/claim-account.tsx.tpl +151 -0
- package/templates/minimal-app/apps/expo/src/app/forgot-password.tsx.tpl +53 -0
- package/templates/minimal-app/apps/expo/src/app/index.tsx.tpl +8 -0
- package/templates/minimal-app/apps/expo/src/app/login.tsx.tpl +71 -0
- package/templates/minimal-app/apps/expo/src/app/logout.tsx.tpl +19 -0
- package/templates/minimal-app/apps/expo/src/app/organization/accept-invitation.tsx.tpl +85 -0
- package/templates/minimal-app/apps/expo/src/app/posts.tsx.tpl +40 -0
- package/templates/minimal-app/apps/expo/src/app/reset-password.tsx.tpl +75 -0
- package/templates/minimal-app/apps/expo/src/app/signup.tsx.tpl +193 -0
- package/templates/minimal-app/apps/expo/src/components/AuthScaffold.tsx.tpl +34 -0
- package/templates/minimal-app/apps/expo/src/components/FormTextField.tsx.tpl +37 -0
- package/templates/minimal-app/apps/expo/src/components/LoadingScreen.tsx.tpl +10 -0
- package/templates/minimal-app/apps/expo/src/components/StatusText.tsx.tpl +22 -0
- package/templates/minimal-app/apps/expo/src/config.ts.tpl +9 -0
- package/templates/minimal-app/apps/expo/src/global.css.tpl +11 -0
- package/templates/minimal-app/apps/expo/src/lib/trpc.ts.tpl +20 -0
- package/templates/minimal-app/apps/expo/tsconfig.json.tpl +11 -0
- package/templates/minimal-app/apps/expo/uniwind-env.d.ts.tpl +1 -0
- package/templates/minimal-app/apps/expo/uniwind-types.d.ts.tpl +10 -0
- package/templates/minimal-app/apps/server/AGENTS.md.tpl +39 -39
- package/templates/minimal-app/apps/server/drizzle/0000_wealthy_absorbing_man.sql +268 -0
- package/templates/minimal-app/apps/server/drizzle/db.ts.tpl +26 -0
- package/templates/minimal-app/apps/server/drizzle/meta/0000_snapshot.json.tpl +1890 -0
- package/templates/minimal-app/apps/server/drizzle/meta/_journal.json.tpl +13 -0
- package/templates/minimal-app/apps/server/drizzle/reset.ts.tpl +33 -0
- package/templates/minimal-app/apps/server/drizzle/seed.e2e.ts.tpl +244 -0
- package/templates/minimal-app/apps/server/drizzle/seed.ts.tpl +181 -180
- package/templates/minimal-app/apps/server/drizzle/sync.ts.tpl +14 -21
- package/templates/minimal-app/apps/server/drizzle.config.ts.tpl +33 -35
- package/templates/minimal-app/apps/server/package.json.tpl +56 -52
- package/templates/minimal-app/apps/server/src/app.ts.tpl +142 -126
- package/templates/minimal-app/apps/server/src/index.ts.tpl +58 -58
- package/templates/minimal-app/apps/server/src/lib/auth.ts.tpl +12 -12
- package/templates/minimal-app/apps/server/src/modules/posts/posts.db.ts.tpl +25 -25
- package/templates/minimal-app/apps/server/src/modules/posts/posts.dto.ts.tpl +23 -0
- package/templates/minimal-app/apps/server/src/modules/posts/posts.grants.ts.tpl +30 -40
- package/templates/minimal-app/apps/server/src/modules/posts/posts.module.ts.tpl +54 -54
- package/templates/minimal-app/apps/server/src/modules/posts/posts.repository.ts.tpl +67 -112
- package/templates/minimal-app/apps/server/src/modules/posts/posts.service.ts.tpl +104 -170
- package/templates/minimal-app/apps/server/src/modules/posts/posts.trpc.ts.tpl +37 -48
- package/templates/minimal-app/apps/server/src/modules/posts/posts.utils.ts.tpl +19 -0
- package/templates/minimal-app/apps/server/src/modules/test-harness/test-harness.module.ts.tpl +279 -0
- package/templates/minimal-app/apps/server/src/schema.ts.tpl +20 -0
- package/templates/minimal-app/apps/server/src/types.ts.tpl +1 -1
- package/templates/minimal-app/apps/server/tsconfig.json.tpl +20 -14
- package/templates/minimal-app/apps/server/tsup.config.ts.tpl +9 -9
- package/templates/minimal-app/apps/shared/package.json.tpl +24 -24
- package/templates/minimal-app/apps/shared/src/modules/app/app.constants.ts.tpl +28 -2
- package/templates/minimal-app/apps/shared/src/modules/notification/notification.schema.ts.tpl +3 -3
- package/templates/minimal-app/apps/shared/src/modules/posts/posts.constants.ts.tpl +5 -5
- package/templates/minimal-app/apps/shared/src/modules/posts/posts.schema.ts.tpl +25 -76
- package/templates/minimal-app/apps/shared/tsconfig.json.tpl +16 -12
- package/templates/minimal-app/apps/webapp/index.html.tpl +22 -22
- package/templates/minimal-app/apps/webapp/package.json.tpl +53 -52
- package/templates/minimal-app/apps/webapp/public/{push-sw.js → push-sw.js.tpl} +34 -34
- package/templates/minimal-app/apps/webapp/src/App.tsx.tpl +44 -13
- package/templates/minimal-app/apps/webapp/src/Layout.tsx.tpl +18 -12
- package/templates/minimal-app/apps/webapp/src/Router.tsx.tpl +33 -40
- package/templates/minimal-app/apps/webapp/src/index.css.tpl +15 -75
- package/templates/minimal-app/apps/webapp/src/main.tsx.tpl +26 -26
- package/templates/minimal-app/apps/webapp/src/modules/posts/PostsRoute.tsx.tpl +278 -307
- package/templates/minimal-app/apps/webapp/src/modules/posts/components/PostCard.tsx.tpl +96 -138
- package/templates/minimal-app/apps/webapp/src/modules/posts/components/PostEditorModal.tsx.tpl +118 -124
- package/templates/minimal-app/apps/webapp/src/modules/posts/hooks/usePostActions.ts.tpl +108 -116
- package/templates/minimal-app/apps/webapp/src/modules/posts/hooks/usePostsList.ts.tpl +15 -9
- package/templates/minimal-app/apps/webapp/src/modules/posts/hooks/usePostsRoute.ts.tpl +13 -13
- package/templates/minimal-app/apps/webapp/src/modules/posts/posts.utils.ts.tpl +16 -16
- package/templates/minimal-app/apps/webapp/src/utils/i18n.ts.tpl +13 -13
- package/templates/minimal-app/apps/webapp/src/utils/trpc.ts.tpl +10 -6
- package/templates/minimal-app/apps/webapp/src/vite-env.d.ts.tpl +1 -1
- package/templates/minimal-app/apps/webapp/translations/{app.json.tpl → en/app.json.tpl} +7 -7
- package/templates/minimal-app/apps/webapp/translations/en/{blog-app.json.tpl → {{APP_SLUG}}.json.tpl} +135 -135
- package/templates/minimal-app/apps/webapp/tsconfig.json.tpl +17 -17
- package/templates/minimal-app/apps/webapp/vite.config.ts.tpl +31 -31
- package/templates/minimal-app/template.manifest.json +21 -0
- package/templates/minimal-app/apps/server/drizzle/generate-schema.ts.tpl +0 -31
- package/templates/minimal-app/apps/server/src/db.ts.tpl +0 -7
- package/templates/minimal-app/apps/server/src/generated/schema.ts.tpl +0 -13
- package/templates/minimal-app/apps/server/src/utils/trpc.ts.tpl +0 -8
- package/templates/minimal-app/apps/shared/src/modules/app/locale.constants.ts.tpl +0 -7
- package/templates/minimal-app/apps/shared/src/modules/app/roles.constants.ts.tpl +0 -17
- package/templates/minimal-app/apps/webapp/src/Providers.tsx.tpl +0 -36
- package/templates/minimal-app/apps/webapp/src/modules/notification/PushNotificationsPanel.tsx.tpl +0 -89
- package/templates/minimal-app/apps/webapp/src/navigation/navigation.config.tsx.tpl +0 -85
- /package/templates/minimal-app/apps/webapp/public/{logo.svg → logo.svg.tpl} +0 -0
|
@@ -1,135 +1,135 @@
|
|
|
1
|
-
{
|
|
2
|
-
"layout": {
|
|
3
|
-
"brand": {
|
|
4
|
-
"eyebrow": "Framework Starter",
|
|
5
|
-
"tagline": "Opinionated enough to ship, compact enough to understand in one sitting."
|
|
6
|
-
},
|
|
7
|
-
"workspace": {
|
|
8
|
-
"eyebrow": "Included by Default",
|
|
9
|
-
"title": "Auth, modules, and one honest feature.",
|
|
10
|
-
"body": "This starter keeps the stack visible: Better Auth, Drizzle, tRPC, React Router, HeroUI, and a single editorial posts module.",
|
|
11
|
-
"local": "Local SQLite",
|
|
12
|
-
"auth": "Better Auth"
|
|
13
|
-
},
|
|
14
|
-
"navigation": {
|
|
15
|
-
"posts": "Posts",
|
|
16
|
-
"organization": "Organization",
|
|
17
|
-
"account": "Account",
|
|
18
|
-
"members": "Members",
|
|
19
|
-
"childOrgs": "Child orgs",
|
|
20
|
-
"orgPreferences": "Org preferences",
|
|
21
|
-
"profile": "Profile",
|
|
22
|
-
"invites": "Invites",
|
|
23
|
-
"admin": "Admin"
|
|
24
|
-
},
|
|
25
|
-
"push": {
|
|
26
|
-
"eyebrow": "Browser push",
|
|
27
|
-
"body": "Enable notifications for this browser profile. Requires HTTPS in production, VAPID keys on the server, Redis for the worker, and a running server process.",
|
|
28
|
-
"cta": "Enable push for this device",
|
|
29
|
-
"enabled": "This browser is registered for push.",
|
|
30
|
-
"denied": "Notification permission was denied.",
|
|
31
|
-
"unsupported": "Push messaging is not supported in this browser.",
|
|
32
|
-
"noVapid": "Server is missing VAPID public key configuration.",
|
|
33
|
-
"badSubscription": "Could not read push subscription from the browser.",
|
|
34
|
-
"failed": "Could not enable push. Check the console and server logs.",
|
|
35
|
-
"vapidMissing": "Server did not return a VAPID key — set VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY, then restart.",
|
|
36
|
-
"blockedHint": "Notifications are blocked for this site. Enable them in the browser address bar or site settings, then try again.",
|
|
37
|
-
"permissionGranted": "Permission granted — tap below to register this browser with the server."
|
|
38
|
-
},
|
|
39
|
-
"account": {
|
|
40
|
-
"eyebrow": "Signed In As",
|
|
41
|
-
"light": "Light mode",
|
|
42
|
-
"dark": "Dark mode",
|
|
43
|
-
"signOut": "Sign out"
|
|
44
|
-
},
|
|
45
|
-
"header": {
|
|
46
|
-
"eyebrow": "Minimal Blog Platform",
|
|
47
|
-
"title": "Editorial control panel",
|
|
48
|
-
"runtime": "tRPC + URL state + HeroUI"
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
"posts": {
|
|
52
|
-
"hero": {
|
|
53
|
-
"eyebrow": "Posts Module",
|
|
54
|
-
"title": "Build, refine, and publish without losing the shape of the stack.",
|
|
55
|
-
"body": "The example module is intentionally complete: filtered list queries, modal-driven create and edit flows, publish actions, soft deletion, and a live preview pane.",
|
|
56
|
-
"new": "Create post",
|
|
57
|
-
"syncing": "Refreshing",
|
|
58
|
-
"synced": "Live against the local database"
|
|
59
|
-
},
|
|
60
|
-
"stats": {
|
|
61
|
-
"total": "Total",
|
|
62
|
-
"published": "Published",
|
|
63
|
-
"drafts": "Drafts"
|
|
64
|
-
},
|
|
65
|
-
"filters": {
|
|
66
|
-
"searchLabel": "Search posts",
|
|
67
|
-
"searchPlaceholder": "Search by title, slug, excerpt, or body",
|
|
68
|
-
"statusLabel": "Status",
|
|
69
|
-
"all": "All posts",
|
|
70
|
-
"draft": "Draft",
|
|
71
|
-
"published": "Published"
|
|
72
|
-
},
|
|
73
|
-
"meta": {
|
|
74
|
-
"updated": "Updated",
|
|
75
|
-
"published": "Published"
|
|
76
|
-
},
|
|
77
|
-
"actions": {
|
|
78
|
-
"edit": "Edit",
|
|
79
|
-
"publish": "Publish",
|
|
80
|
-
"delete": "Delete"
|
|
81
|
-
},
|
|
82
|
-
"empty": {
|
|
83
|
-
"eyebrow": "Nothing yet",
|
|
84
|
-
"title": "Your editorial desk is ready for the first post.",
|
|
85
|
-
"body": "Create a first entry to see the full loop: draft creation, inline editing, publishing, and soft deletion. Seed data appears after you run the scaffolded seed script.",
|
|
86
|
-
"action": "Write the first post"
|
|
87
|
-
},
|
|
88
|
-
"pagination": {
|
|
89
|
-
"summary": "Page {{page}} of {{pageCount}}",
|
|
90
|
-
"previous": "Previous",
|
|
91
|
-
"next": "Next"
|
|
92
|
-
},
|
|
93
|
-
"preview": {
|
|
94
|
-
"eyebrow": "Selected Draft",
|
|
95
|
-
"emptyTitle": "Preview panel",
|
|
96
|
-
"emptyBody": "Choose a post from the list to inspect the current draft or published copy.",
|
|
97
|
-
"updated": "Updated",
|
|
98
|
-
"openEditor": "Open in editor"
|
|
99
|
-
},
|
|
100
|
-
"editor": {
|
|
101
|
-
"newEyebrow": "New draft",
|
|
102
|
-
"editEyebrow": "Update draft",
|
|
103
|
-
"newTitle": "Shape a new post",
|
|
104
|
-
"editTitle": "Refine this post",
|
|
105
|
-
"fields": {
|
|
106
|
-
"title": "Title",
|
|
107
|
-
"slug": "Slug",
|
|
108
|
-
"excerpt": "Excerpt",
|
|
109
|
-
"content": "Content"
|
|
110
|
-
},
|
|
111
|
-
"cancel": "Cancel",
|
|
112
|
-
"save": "Save changes",
|
|
113
|
-
"create": "Create draft"
|
|
114
|
-
},
|
|
115
|
-
"deleteDialog": {
|
|
116
|
-
"title": "Archive this post?",
|
|
117
|
-
"body": "The post will be soft-deleted and removed from the main list.",
|
|
118
|
-
"confirm": "Archive post",
|
|
119
|
-
"cancel": "Keep it"
|
|
120
|
-
},
|
|
121
|
-
"toast": {
|
|
122
|
-
"created": "Draft created.",
|
|
123
|
-
"updated": "Post updated.",
|
|
124
|
-
"published": "Post published.",
|
|
125
|
-
"deleted": "Post archived.",
|
|
126
|
-
"validation": "Title and content are required."
|
|
127
|
-
}
|
|
128
|
-
},
|
|
129
|
-
"auth": {
|
|
130
|
-
"header": {
|
|
131
|
-
"eyebrow": "Framework Starter",
|
|
132
|
-
"tagline": "A minimal m5kdev starter with auth, tRPC, and one polished posts module."
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"layout": {
|
|
3
|
+
"brand": {
|
|
4
|
+
"eyebrow": "Framework Starter",
|
|
5
|
+
"tagline": "Opinionated enough to ship, compact enough to understand in one sitting."
|
|
6
|
+
},
|
|
7
|
+
"workspace": {
|
|
8
|
+
"eyebrow": "Included by Default",
|
|
9
|
+
"title": "Auth, modules, and one honest feature.",
|
|
10
|
+
"body": "This starter keeps the stack visible: Better Auth, Drizzle, tRPC, React Router, HeroUI, and a single editorial posts module.",
|
|
11
|
+
"local": "Local SQLite",
|
|
12
|
+
"auth": "Better Auth"
|
|
13
|
+
},
|
|
14
|
+
"navigation": {
|
|
15
|
+
"posts": "Posts",
|
|
16
|
+
"organization": "Organization",
|
|
17
|
+
"account": "Account",
|
|
18
|
+
"members": "Members",
|
|
19
|
+
"childOrgs": "Child orgs",
|
|
20
|
+
"orgPreferences": "Org preferences",
|
|
21
|
+
"profile": "Profile",
|
|
22
|
+
"invites": "Invites",
|
|
23
|
+
"admin": "Admin"
|
|
24
|
+
},
|
|
25
|
+
"push": {
|
|
26
|
+
"eyebrow": "Browser push",
|
|
27
|
+
"body": "Enable notifications for this browser profile. Requires HTTPS in production, VAPID keys on the server, Redis for the worker, and a running server process.",
|
|
28
|
+
"cta": "Enable push for this device",
|
|
29
|
+
"enabled": "This browser is registered for push.",
|
|
30
|
+
"denied": "Notification permission was denied.",
|
|
31
|
+
"unsupported": "Push messaging is not supported in this browser.",
|
|
32
|
+
"noVapid": "Server is missing VAPID public key configuration.",
|
|
33
|
+
"badSubscription": "Could not read push subscription from the browser.",
|
|
34
|
+
"failed": "Could not enable push. Check the console and server logs.",
|
|
35
|
+
"vapidMissing": "Server did not return a VAPID key — set VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY, then restart.",
|
|
36
|
+
"blockedHint": "Notifications are blocked for this site. Enable them in the browser address bar or site settings, then try again.",
|
|
37
|
+
"permissionGranted": "Permission granted — tap below to register this browser with the server."
|
|
38
|
+
},
|
|
39
|
+
"account": {
|
|
40
|
+
"eyebrow": "Signed In As",
|
|
41
|
+
"light": "Light mode",
|
|
42
|
+
"dark": "Dark mode",
|
|
43
|
+
"signOut": "Sign out"
|
|
44
|
+
},
|
|
45
|
+
"header": {
|
|
46
|
+
"eyebrow": "Minimal Blog Platform",
|
|
47
|
+
"title": "Editorial control panel",
|
|
48
|
+
"runtime": "tRPC + URL state + HeroUI"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"posts": {
|
|
52
|
+
"hero": {
|
|
53
|
+
"eyebrow": "Posts Module",
|
|
54
|
+
"title": "Build, refine, and publish without losing the shape of the stack.",
|
|
55
|
+
"body": "The example module is intentionally complete: filtered list queries, modal-driven create and edit flows, publish actions, soft deletion, and a live preview pane.",
|
|
56
|
+
"new": "Create post",
|
|
57
|
+
"syncing": "Refreshing",
|
|
58
|
+
"synced": "Live against the local database"
|
|
59
|
+
},
|
|
60
|
+
"stats": {
|
|
61
|
+
"total": "Total",
|
|
62
|
+
"published": "Published",
|
|
63
|
+
"drafts": "Drafts"
|
|
64
|
+
},
|
|
65
|
+
"filters": {
|
|
66
|
+
"searchLabel": "Search posts",
|
|
67
|
+
"searchPlaceholder": "Search by title, slug, excerpt, or body",
|
|
68
|
+
"statusLabel": "Status",
|
|
69
|
+
"all": "All posts",
|
|
70
|
+
"draft": "Draft",
|
|
71
|
+
"published": "Published"
|
|
72
|
+
},
|
|
73
|
+
"meta": {
|
|
74
|
+
"updated": "Updated",
|
|
75
|
+
"published": "Published"
|
|
76
|
+
},
|
|
77
|
+
"actions": {
|
|
78
|
+
"edit": "Edit",
|
|
79
|
+
"publish": "Publish",
|
|
80
|
+
"delete": "Delete"
|
|
81
|
+
},
|
|
82
|
+
"empty": {
|
|
83
|
+
"eyebrow": "Nothing yet",
|
|
84
|
+
"title": "Your editorial desk is ready for the first post.",
|
|
85
|
+
"body": "Create a first entry to see the full loop: draft creation, inline editing, publishing, and soft deletion. Seed data appears after you run the scaffolded seed script.",
|
|
86
|
+
"action": "Write the first post"
|
|
87
|
+
},
|
|
88
|
+
"pagination": {
|
|
89
|
+
"summary": "Page {{page}} of {{pageCount}}",
|
|
90
|
+
"previous": "Previous",
|
|
91
|
+
"next": "Next"
|
|
92
|
+
},
|
|
93
|
+
"preview": {
|
|
94
|
+
"eyebrow": "Selected Draft",
|
|
95
|
+
"emptyTitle": "Preview panel",
|
|
96
|
+
"emptyBody": "Choose a post from the list to inspect the current draft or published copy.",
|
|
97
|
+
"updated": "Updated",
|
|
98
|
+
"openEditor": "Open in editor"
|
|
99
|
+
},
|
|
100
|
+
"editor": {
|
|
101
|
+
"newEyebrow": "New draft",
|
|
102
|
+
"editEyebrow": "Update draft",
|
|
103
|
+
"newTitle": "Shape a new post",
|
|
104
|
+
"editTitle": "Refine this post",
|
|
105
|
+
"fields": {
|
|
106
|
+
"title": "Title",
|
|
107
|
+
"slug": "Slug",
|
|
108
|
+
"excerpt": "Excerpt",
|
|
109
|
+
"content": "Content"
|
|
110
|
+
},
|
|
111
|
+
"cancel": "Cancel",
|
|
112
|
+
"save": "Save changes",
|
|
113
|
+
"create": "Create draft"
|
|
114
|
+
},
|
|
115
|
+
"deleteDialog": {
|
|
116
|
+
"title": "Archive this post?",
|
|
117
|
+
"body": "The post will be soft-deleted and removed from the main list.",
|
|
118
|
+
"confirm": "Archive post",
|
|
119
|
+
"cancel": "Keep it"
|
|
120
|
+
},
|
|
121
|
+
"toast": {
|
|
122
|
+
"created": "Draft created.",
|
|
123
|
+
"updated": "Post updated.",
|
|
124
|
+
"published": "Post published.",
|
|
125
|
+
"deleted": "Post archived.",
|
|
126
|
+
"validation": "Title and content are required."
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"auth": {
|
|
130
|
+
"header": {
|
|
131
|
+
"eyebrow": "Framework Starter",
|
|
132
|
+
"tagline": "A minimal m5kdev starter with auth, tRPC, and one polished posts module."
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "@m5kdev/config/tsconfig.vite.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"baseUrl": ".",
|
|
5
|
-
"ignoreDeprecations": "6.0",
|
|
6
|
-
"rootDir": ".",
|
|
7
|
-
"outDir": "dist",
|
|
8
|
-
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
|
9
|
-
"paths": {
|
|
10
|
-
"@/components/*": ["./src/components/*"],
|
|
11
|
-
"@/modules/*": ["./src/modules/*"],
|
|
12
|
-
"@/utils/*": ["./src/utils/*"]
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
"include": ["src"],
|
|
16
|
-
"exclude": ["dist", "node_modules"]
|
|
17
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"extends": "@m5kdev/config/tsconfig.vite.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"ignoreDeprecations": "6.0",
|
|
6
|
+
"rootDir": ".",
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
|
9
|
+
"paths": {
|
|
10
|
+
"@/components/*": ["./src/components/*"],
|
|
11
|
+
"@/modules/*": ["./src/modules/*"],
|
|
12
|
+
"@/utils/*": ["./src/utils/*"]
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"include": ["src"],
|
|
16
|
+
"exclude": ["dist", "node_modules"]
|
|
17
|
+
}
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import tailwindcss from "@tailwindcss/vite";
|
|
3
|
-
import react from "@vitejs/plugin-react";
|
|
4
|
-
import { defineConfig } from "vite";
|
|
5
|
-
import i18nextLoader from "vite-plugin-i18next-loader";
|
|
6
|
-
import tsconfigPaths from "vite-tsconfig-paths";
|
|
7
|
-
|
|
8
|
-
export default defineConfig({
|
|
9
|
-
root: __dirname,
|
|
10
|
-
plugins: [
|
|
11
|
-
tailwindcss(),
|
|
12
|
-
react({
|
|
13
|
-
babel: {
|
|
14
|
-
plugins: ["babel-plugin-react-compiler"],
|
|
15
|
-
},
|
|
16
|
-
}),
|
|
17
|
-
tsconfigPaths(),
|
|
18
|
-
i18nextLoader({
|
|
19
|
-
include: ["**/*.json"],
|
|
20
|
-
paths: [
|
|
21
|
-
path.resolve(__dirname, "./node_modules/@m5kdev/web-ui/dist/translations"),
|
|
22
|
-
path.resolve(__dirname, "./translations"),
|
|
23
|
-
],
|
|
24
|
-
namespaceResolution: "basename",
|
|
25
|
-
}),
|
|
26
|
-
],
|
|
27
|
-
resolve: {
|
|
28
|
-
dedupe: ["react", "react-dom", "react-i18next", "react-router", "nuqs"],
|
|
29
|
-
},
|
|
30
|
-
envDir: "../shared",
|
|
31
|
-
});
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
3
|
+
import react from "@vitejs/plugin-react";
|
|
4
|
+
import { defineConfig } from "vite";
|
|
5
|
+
import i18nextLoader from "vite-plugin-i18next-loader";
|
|
6
|
+
import tsconfigPaths from "vite-tsconfig-paths";
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
root: __dirname,
|
|
10
|
+
plugins: [
|
|
11
|
+
tailwindcss(),
|
|
12
|
+
react({
|
|
13
|
+
babel: {
|
|
14
|
+
plugins: ["babel-plugin-react-compiler"],
|
|
15
|
+
},
|
|
16
|
+
}),
|
|
17
|
+
tsconfigPaths(),
|
|
18
|
+
i18nextLoader({
|
|
19
|
+
include: ["**/*.json"],
|
|
20
|
+
paths: [
|
|
21
|
+
path.resolve(__dirname, "./node_modules/@m5kdev/web-ui/dist/translations"),
|
|
22
|
+
path.resolve(__dirname, "./translations"),
|
|
23
|
+
],
|
|
24
|
+
namespaceResolution: "basename",
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
resolve: {
|
|
28
|
+
dedupe: ["react", "react-dom", "react-i18next", "react-router", "nuqs"],
|
|
29
|
+
},
|
|
30
|
+
envDir: "../shared",
|
|
31
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"features": {
|
|
3
|
+
"test-harness": {
|
|
4
|
+
"paths": [
|
|
5
|
+
"apps/e2e/",
|
|
6
|
+
"apps/server/src/modules/test-harness/",
|
|
7
|
+
"apps/server/drizzle/seed.e2e.ts"
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
"webapp": {
|
|
11
|
+
"paths": [
|
|
12
|
+
"apps/webapp/"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"expo": {
|
|
16
|
+
"paths": [
|
|
17
|
+
"apps/expo/"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
export async function generateSchema(): Promise<void> {
|
|
5
|
-
const outputDirectory = path.resolve(process.cwd(), "src/generated");
|
|
6
|
-
const outputPath = path.join(outputDirectory, "schema.ts");
|
|
7
|
-
|
|
8
|
-
const source = [
|
|
9
|
-
'import * as authTables from "@m5kdev/backend/modules/auth/auth.db";',
|
|
10
|
-
'import * as notificationTables from "@m5kdev/backend/modules/notification/notification.db";',
|
|
11
|
-
'import * as workflowTables from "@m5kdev/backend/modules/workflow/workflow.db";',
|
|
12
|
-
'import * as postsTables from "../modules/posts/posts.db";',
|
|
13
|
-
"",
|
|
14
|
-
"export const schema = {",
|
|
15
|
-
" ...authTables,",
|
|
16
|
-
" ...workflowTables,",
|
|
17
|
-
" ...notificationTables,",
|
|
18
|
-
" ...postsTables,",
|
|
19
|
-
"};",
|
|
20
|
-
"",
|
|
21
|
-
"export type AppDbSchema = typeof schema;",
|
|
22
|
-
"",
|
|
23
|
-
].join("\r\n");
|
|
24
|
-
|
|
25
|
-
await fs.mkdir(outputDirectory, { recursive: true });
|
|
26
|
-
await fs.writeFile(outputPath, source, "utf8");
|
|
27
|
-
|
|
28
|
-
console.info(`Generated Drizzle schema at ${outputPath}`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
void generateSchema();
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import * as authTables from "@m5kdev/backend/modules/auth/auth.db";
|
|
2
|
-
import * as notificationTables from "@m5kdev/backend/modules/notification/notification.db";
|
|
3
|
-
import * as workflowTables from "@m5kdev/backend/modules/workflow/workflow.db";
|
|
4
|
-
import * as postsTables from "../modules/posts/posts.db";
|
|
5
|
-
|
|
6
|
-
export const schema = {
|
|
7
|
-
...authTables,
|
|
8
|
-
...workflowTables,
|
|
9
|
-
...notificationTables,
|
|
10
|
-
...postsTables,
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export type AppDbSchema = typeof schema;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { builtBackendApp } from "../app";
|
|
2
|
-
|
|
3
|
-
export const router = builtBackendApp.trpc.methods.router;
|
|
4
|
-
export const publicProcedure = builtBackendApp.trpc.methods.publicProcedure;
|
|
5
|
-
export const procedure = builtBackendApp.trpc.methods.privateProcedure;
|
|
6
|
-
export const adminProcedure = builtBackendApp.trpc.methods.adminProcedure;
|
|
7
|
-
|
|
8
|
-
export const trpcObject = builtBackendApp.trpc.methods;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { defineAuthRoles } from "@m5kdev/commons/modules/auth/auth.roles";
|
|
2
|
-
|
|
3
|
-
export const APP_ROLES_CONFIG = defineAuthRoles({
|
|
4
|
-
user: {
|
|
5
|
-
roles: ["user", "admin"],
|
|
6
|
-
},
|
|
7
|
-
organization: {
|
|
8
|
-
roles: ["member", "admin", "owner"],
|
|
9
|
-
managerRoles: ["admin", "owner"],
|
|
10
|
-
assignableRoles: ["member", "admin", "owner"],
|
|
11
|
-
defaultRole: "member",
|
|
12
|
-
},
|
|
13
|
-
team: {
|
|
14
|
-
roles: ["owner"],
|
|
15
|
-
defaultRole: "owner",
|
|
16
|
-
},
|
|
17
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { AppConfigProvider } from "@m5kdev/frontend/modules/app/components/AppConfigProvider";
|
|
2
|
-
import { AppTrpcQueryProvider } from "@m5kdev/frontend/modules/app/components/AppTrpcQueryProvider";
|
|
3
|
-
import { AuthProvider } from "@m5kdev/frontend/modules/auth/components/AuthProvider";
|
|
4
|
-
import { DialogProvider } from "@m5kdev/web-ui/components/DialogProvider";
|
|
5
|
-
import { ThemeProvider } from "@m5kdev/web-ui/components/theme-provider";
|
|
6
|
-
import { AppLoader } from "@m5kdev/web-ui/modules/app/components/AppLoader";
|
|
7
|
-
import { APP_NAME } from "{{PACKAGE_SCOPE}}/shared/modules/app/app.constants";
|
|
8
|
-
import { AUTH_LOCALE_CONFIG } from "{{PACKAGE_SCOPE}}/shared/modules/app/locale.constants";
|
|
9
|
-
import { APP_ROLES_CONFIG } from "{{PACKAGE_SCOPE}}/shared/modules/app/roles.constants";
|
|
10
|
-
import { Toaster } from "sonner";
|
|
11
|
-
import { Router } from "./Router";
|
|
12
|
-
|
|
13
|
-
export function Providers() {
|
|
14
|
-
return (
|
|
15
|
-
<AppConfigProvider
|
|
16
|
-
config={{
|
|
17
|
-
appName: APP_NAME,
|
|
18
|
-
appUrl: import.meta.env.VITE_APP_URL,
|
|
19
|
-
serverUrl: import.meta.env.VITE_SERVER_URL,
|
|
20
|
-
locales: AUTH_LOCALE_CONFIG,
|
|
21
|
-
roles: APP_ROLES_CONFIG,
|
|
22
|
-
}}
|
|
23
|
-
>
|
|
24
|
-
<ThemeProvider defaultTheme="light" storageKey="m5kdev-theme">
|
|
25
|
-
<AuthProvider loader={<AppLoader />}>
|
|
26
|
-
<AppTrpcQueryProvider>
|
|
27
|
-
<DialogProvider>
|
|
28
|
-
<Router />
|
|
29
|
-
</DialogProvider>
|
|
30
|
-
<Toaster richColors closeButton />
|
|
31
|
-
</AppTrpcQueryProvider>
|
|
32
|
-
</AuthProvider>
|
|
33
|
-
</ThemeProvider>
|
|
34
|
-
</AppConfigProvider>
|
|
35
|
-
);
|
|
36
|
-
}
|
package/templates/minimal-app/apps/webapp/src/modules/notification/PushNotificationsPanel.tsx.tpl
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { Button, Chip } from "@heroui/react";
|
|
2
|
-
import { useSession } from "@m5kdev/frontend/modules/auth/hooks/useSession";
|
|
3
|
-
import { type UseWebPushOptions, useWebPush } from "@m5kdev/web-ui/hooks/useWebPush";
|
|
4
|
-
import { BellIcon } from "lucide-react";
|
|
5
|
-
import { useMemo } from "react";
|
|
6
|
-
import { useTranslation } from "react-i18next";
|
|
7
|
-
import { useTRPC } from "@/utils/trpc";
|
|
8
|
-
|
|
9
|
-
export function PushNotificationsPanel() {
|
|
10
|
-
const { data: session } = useSession();
|
|
11
|
-
const trpc = useTRPC();
|
|
12
|
-
const { t } = useTranslation("blog{{PACKAGE_SCOPE}}");
|
|
13
|
-
|
|
14
|
-
const messages = useMemo(
|
|
15
|
-
() => ({
|
|
16
|
-
unsupported: t("layout.push.unsupported"),
|
|
17
|
-
denied: t("layout.push.denied"),
|
|
18
|
-
noVapid: t("layout.push.noVapid"),
|
|
19
|
-
badSubscription: t("layout.push.badSubscription"),
|
|
20
|
-
failed: t("layout.push.failed"),
|
|
21
|
-
enabled: t("layout.push.enabled"),
|
|
22
|
-
}),
|
|
23
|
-
[t]
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
const {
|
|
27
|
-
permission,
|
|
28
|
-
isSupported,
|
|
29
|
-
subscribe,
|
|
30
|
-
flowStatus,
|
|
31
|
-
feedback,
|
|
32
|
-
isWorking,
|
|
33
|
-
canSubscribe,
|
|
34
|
-
vapidError,
|
|
35
|
-
isVapidLoading,
|
|
36
|
-
} = useWebPush({
|
|
37
|
-
enabled: Boolean(session),
|
|
38
|
-
messages,
|
|
39
|
-
vapidPublicKeyQuery:
|
|
40
|
-
trpc.notification.vapidPublicKey.queryOptions() as unknown as UseWebPushOptions["vapidPublicKeyQuery"],
|
|
41
|
-
registerDeviceMutation:
|
|
42
|
-
trpc.notification.registerDevice.mutationOptions() as unknown as UseWebPushOptions["registerDeviceMutation"],
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
if (!session) {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const disabled = isVapidLoading || vapidError || isWorking || !canSubscribe;
|
|
50
|
-
const blocked = permission === "denied";
|
|
51
|
-
|
|
52
|
-
return (
|
|
53
|
-
<div className="mt-6 rounded-[28px] border border-sky-200/80 bg-sky-50/90 p-4">
|
|
54
|
-
<div className="flex items-start gap-3">
|
|
55
|
-
<div className="rounded-2xl border border-sky-200 bg-white/90 p-2 text-sky-700">
|
|
56
|
-
<BellIcon className="h-5 w-5" />
|
|
57
|
-
</div>
|
|
58
|
-
<div className="min-w-0 flex-1">
|
|
59
|
-
<p className="text-[0.68rem] font-semibold uppercase tracking-[0.28em] text-sky-800/80">
|
|
60
|
-
{t("layout.push.eyebrow")}
|
|
61
|
-
</p>
|
|
62
|
-
<p className="mt-2 text-sm leading-6 text-ink/80">{t("layout.push.body")}</p>
|
|
63
|
-
{!isSupported ? (
|
|
64
|
-
<p className="mt-2 text-xs text-rose-700">{t("layout.push.unsupported")}</p>
|
|
65
|
-
) : null}
|
|
66
|
-
{blocked ? (
|
|
67
|
-
<p className="mt-2 text-xs text-rose-700">{t("layout.push.blockedHint")}</p>
|
|
68
|
-
) : null}
|
|
69
|
-
{vapidError ? (
|
|
70
|
-
<p className="mt-2 text-xs text-rose-700">{t("layout.push.vapidMissing")}</p>
|
|
71
|
-
) : null}
|
|
72
|
-
{permission === "granted" && flowStatus === "idle" && !vapidError ? (
|
|
73
|
-
<p className="mt-2 text-xs text-emerald-800/90">{t("layout.push.permissionGranted")}</p>
|
|
74
|
-
) : null}
|
|
75
|
-
{feedback ? (
|
|
76
|
-
<Chip
|
|
77
|
-
className={`mt-3 ${flowStatus === "error" ? "bg-danger-100 text-danger-900" : "bg-success-100 text-success-900"}`}
|
|
78
|
-
>
|
|
79
|
-
{feedback}
|
|
80
|
-
</Chip>
|
|
81
|
-
) : null}
|
|
82
|
-
<Button className="mt-3" isDisabled={disabled} size="sm" onPress={() => void subscribe()}>
|
|
83
|
-
{t("layout.push.cta")}
|
|
84
|
-
</Button>
|
|
85
|
-
</div>
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
88
|
-
);
|
|
89
|
-
}
|