create-mantiq 0.7.0 → 0.7.2

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.
Files changed (220) hide show
  1. package/package.json +2 -1
  2. package/skeleton/.env.example +64 -0
  3. package/skeleton/README.md +46 -0
  4. package/skeleton/app/Console/Commands/.gitkeep +0 -0
  5. package/skeleton/app/Enums/UserStatus.ts +7 -0
  6. package/skeleton/app/Http/Controllers/HomeController.ts +78 -0
  7. package/skeleton/app/Http/Middleware/.gitkeep +0 -0
  8. package/skeleton/app/Models/User.ts +7 -0
  9. package/skeleton/app/Providers/AppServiceProvider.ts +25 -0
  10. package/skeleton/app/Providers/DatabaseServiceProvider.ts +17 -0
  11. package/skeleton/bootstrap/.gitkeep +0 -0
  12. package/skeleton/config/ai.ts +51 -0
  13. package/skeleton/config/app.ts +108 -0
  14. package/skeleton/config/auth.ts +51 -0
  15. package/skeleton/config/broadcasting.ts +93 -0
  16. package/skeleton/config/cache.ts +61 -0
  17. package/skeleton/config/cors.ts +77 -0
  18. package/skeleton/config/database.ts +120 -0
  19. package/skeleton/config/filesystem.ts +58 -0
  20. package/skeleton/config/hashing.ts +47 -0
  21. package/skeleton/config/heartbeat.ts +112 -0
  22. package/skeleton/config/logging.ts +58 -0
  23. package/skeleton/config/mail.ts +93 -0
  24. package/skeleton/config/notify.ts +141 -0
  25. package/skeleton/config/queue.ts +59 -0
  26. package/skeleton/config/search.ts +96 -0
  27. package/skeleton/config/services.ts +110 -0
  28. package/skeleton/config/session.ts +84 -0
  29. package/skeleton/config/vite.ts +33 -0
  30. package/skeleton/database/factories/.gitkeep +0 -0
  31. package/skeleton/database/migrations/001_create_users_table.ts +19 -0
  32. package/skeleton/database/migrations/002_create_personal_access_tokens_table.ts +22 -0
  33. package/skeleton/database/seeders/DatabaseSeeder.ts +7 -0
  34. package/skeleton/index.ts +20 -0
  35. package/skeleton/mantiq.ts +8 -0
  36. package/skeleton/package.json +34 -0
  37. package/skeleton/public/.gitkeep +0 -0
  38. package/skeleton/routes/api.ts +8 -0
  39. package/skeleton/routes/channels.ts +23 -0
  40. package/skeleton/routes/console.ts +24 -0
  41. package/skeleton/routes/web.ts +6 -0
  42. package/skeleton/storage/cache/.gitkeep +0 -0
  43. package/skeleton/storage/framework/.gitkeep +0 -0
  44. package/skeleton/tests/feature/api.test.ts +14 -0
  45. package/skeleton/tests/feature/home.test.ts +17 -0
  46. package/skeleton/tests/unit/example.test.ts +11 -0
  47. package/skeleton/tsconfig.json +27 -0
  48. package/src/index.ts +289 -25
  49. package/src/templates.ts +141 -945
  50. package/src/terminal.ts +64 -0
  51. package/stubs/api-only/routes/api.ts.stub +24 -0
  52. package/stubs/api-only/tests/feature/token-auth.test.ts.stub +69 -0
  53. package/stubs/auth/api/app/Http/Controllers/ApiAuthController.ts.stub +57 -0
  54. package/stubs/auth/api/routes/api.ts.stub +24 -0
  55. package/stubs/auth/api/tests/feature/token-auth.test.ts.stub +69 -0
  56. package/stubs/auth/shared/app/Http/Requests/LoginRequest.ts.stub +10 -0
  57. package/stubs/auth/shared/app/Http/Requests/RegisterRequest.ts.stub +11 -0
  58. package/stubs/auth/web/app/Http/Controllers/AuthController.ts.stub +43 -0
  59. package/stubs/auth/web/app/Http/Controllers/PageController.ts.stub +66 -0
  60. package/stubs/auth/web/routes/web.ts.stub +25 -0
  61. package/stubs/auth/web/svelte/src/App.svelte.stub +77 -0
  62. package/stubs/auth/web/svelte/src/pages.ts.stub +17 -0
  63. package/stubs/auth/web/tests/feature/auth.test.ts.stub +69 -0
  64. package/stubs/auth/web/vue/src/App.vue.stub +74 -0
  65. package/stubs/auth/web/vue/src/pages.ts.stub +17 -0
  66. package/stubs/manifest.json +630 -2
  67. package/stubs/noauth/app/Http/Controllers/PageController.ts.stub +41 -0
  68. package/stubs/noauth/app/Models/User.ts.stub +5 -0
  69. package/stubs/noauth/database/migrations/001_create_users_table.ts.stub +17 -0
  70. package/stubs/noauth/routes/api.ts.stub +16 -0
  71. package/stubs/noauth/routes/web.ts.stub +15 -0
  72. package/stubs/noauth/svelte/src/App.svelte.stub +68 -0
  73. package/stubs/noauth/svelte/src/pages.ts.stub +7 -0
  74. package/stubs/noauth/vue/src/App.vue.stub +62 -0
  75. package/stubs/noauth/vue/src/pages.ts.stub +7 -0
  76. package/stubs/react/src/App.tsx.stub +4 -2
  77. package/stubs/react/src/components/layout/search-dialog.tsx.stub +2 -2
  78. package/stubs/react/src/components/layout/sidebar-data.ts.stub +2 -2
  79. package/stubs/react/src/lib/api.ts.stub +30 -6
  80. package/stubs/react/src/pages/Login.tsx.stub +3 -3
  81. package/stubs/react/src/pages/users/dialogs.tsx.stub +7 -26
  82. package/stubs/react/vite.config.ts.stub +26 -3
  83. package/stubs/shared/app/Http/Controllers/ApiAuthController.ts.stub +57 -0
  84. package/stubs/shared/app/Http/Controllers/AuthController.ts.stub +14 -38
  85. package/stubs/shared/app/Http/Controllers/PageController.ts.stub +3 -3
  86. package/stubs/shared/app/Http/Controllers/UserController.ts.stub +61 -0
  87. package/stubs/shared/app/Http/Requests/LoginRequest.ts.stub +10 -0
  88. package/stubs/shared/app/Http/Requests/RegisterRequest.ts.stub +11 -0
  89. package/stubs/shared/app/Http/Requests/StoreUserRequest.ts.stub +11 -0
  90. package/stubs/shared/app/Http/Requests/UpdateUserRequest.ts.stub +11 -0
  91. package/stubs/shared/config/app.ts.stub +36 -0
  92. package/stubs/shared/config/vite.ts.stub +8 -0
  93. package/stubs/shared/database/factories/UserFactory.ts.stub +4 -6
  94. package/stubs/shared/routes/api.ts.stub +12 -102
  95. package/stubs/shared/routes/web.ts.stub +5 -3
  96. package/stubs/shared/tests/feature/auth.test.ts.stub +69 -0
  97. package/stubs/shared/tests/feature/users.test.ts.stub +90 -0
  98. package/stubs/svelte/src/App.svelte.stub +1 -1
  99. package/stubs/svelte/src/lib/api.ts.stub +30 -6
  100. package/stubs/svelte/src/main.ts.stub +3 -1
  101. package/stubs/svelte/src/pages/Login.svelte.stub +3 -3
  102. package/stubs/svelte/vite.config.ts.stub +20 -1
  103. package/stubs/tailwind-only/react/src/components/layout/app-sidebar.tsx.stub +68 -0
  104. package/stubs/tailwind-only/react/src/components/layout/authenticated-layout.tsx.stub +57 -0
  105. package/stubs/tailwind-only/react/src/components/layout/header.tsx.stub +52 -0
  106. package/stubs/tailwind-only/react/src/components/layout/main.tsx.stub +21 -0
  107. package/stubs/tailwind-only/react/src/components/layout/nav-group.tsx.stub +185 -0
  108. package/stubs/tailwind-only/react/src/components/layout/nav-user.tsx.stub +106 -0
  109. package/stubs/tailwind-only/react/src/components/layout/sidebar-data.ts.stub +58 -0
  110. package/stubs/tailwind-only/react/src/components/layout/theme-toggle.tsx.stub +36 -0
  111. package/stubs/tailwind-only/react/src/components/layout/top-nav.tsx.stub +72 -0
  112. package/stubs/tailwind-only/react/src/lib/utils.ts.stub +6 -0
  113. package/stubs/tailwind-only/react/src/pages/Dashboard.tsx.stub +205 -0
  114. package/stubs/tailwind-only/react/src/pages/Login.tsx.stub +122 -0
  115. package/stubs/tailwind-only/react/src/pages/Register.tsx.stub +137 -0
  116. package/stubs/tailwind-only/react/src/pages/Users.tsx.stub +426 -0
  117. package/stubs/tailwind-only/react/src/pages/account/layout.tsx.stub +64 -0
  118. package/stubs/tailwind-only/react/src/pages/account/preferences.tsx.stub +80 -0
  119. package/stubs/tailwind-only/react/src/pages/account/profile.tsx.stub +67 -0
  120. package/stubs/tailwind-only/react/src/pages/account/security.tsx.stub +91 -0
  121. package/stubs/tailwind-only/react/src/style.css.stub +14 -0
  122. package/stubs/tailwind-only/svelte/src/lib/components/layout/app-sidebar.svelte.stub +104 -0
  123. package/stubs/tailwind-only/svelte/src/lib/components/layout/authenticated-layout.svelte.stub +51 -0
  124. package/stubs/tailwind-only/svelte/src/lib/components/layout/header.svelte.stub +66 -0
  125. package/stubs/tailwind-only/svelte/src/lib/components/layout/main.svelte.stub +26 -0
  126. package/stubs/tailwind-only/svelte/src/lib/components/layout/nav-group.svelte.stub +131 -0
  127. package/stubs/tailwind-only/svelte/src/lib/components/layout/nav-user.svelte.stub +104 -0
  128. package/stubs/tailwind-only/svelte/src/lib/components/layout/sidebar-data.ts.stub +57 -0
  129. package/stubs/tailwind-only/svelte/src/lib/components/layout/theme-toggle.svelte.stub +28 -0
  130. package/stubs/tailwind-only/svelte/src/lib/components/layout/top-nav.svelte.stub +99 -0
  131. package/stubs/tailwind-only/svelte/src/lib/utils.ts.stub +6 -0
  132. package/stubs/tailwind-only/svelte/src/pages/Dashboard.svelte.stub +192 -0
  133. package/stubs/tailwind-only/svelte/src/pages/Login.svelte.stub +120 -0
  134. package/stubs/tailwind-only/svelte/src/pages/Register.svelte.stub +134 -0
  135. package/stubs/tailwind-only/svelte/src/pages/Users.svelte.stub +293 -0
  136. package/stubs/tailwind-only/svelte/src/pages/account/Layout.svelte.stub +61 -0
  137. package/stubs/tailwind-only/svelte/src/pages/account/Preferences.svelte.stub +81 -0
  138. package/stubs/tailwind-only/svelte/src/pages/account/Profile.svelte.stub +76 -0
  139. package/stubs/tailwind-only/svelte/src/pages/account/Security.svelte.stub +140 -0
  140. package/stubs/tailwind-only/svelte/src/style.css.stub +127 -0
  141. package/stubs/tailwind-only/vue/src/components/layout/AppSidebar.vue.stub +60 -0
  142. package/stubs/tailwind-only/vue/src/components/layout/AuthenticatedLayout.vue.stub +73 -0
  143. package/stubs/tailwind-only/vue/src/components/layout/Header.vue.stub +54 -0
  144. package/stubs/tailwind-only/vue/src/components/layout/Main.vue.stub +22 -0
  145. package/stubs/tailwind-only/vue/src/components/layout/NavGroup.vue.stub +107 -0
  146. package/stubs/tailwind-only/vue/src/components/layout/NavUser.vue.stub +104 -0
  147. package/stubs/tailwind-only/vue/src/components/layout/ThemeToggle.vue.stub +28 -0
  148. package/stubs/tailwind-only/vue/src/components/layout/TopNav.vue.stub +86 -0
  149. package/stubs/tailwind-only/vue/src/components/layout/sidebar-data.ts.stub +57 -0
  150. package/stubs/tailwind-only/vue/src/lib/utils.ts.stub +7 -0
  151. package/stubs/tailwind-only/vue/src/pages/Dashboard.vue.stub +195 -0
  152. package/stubs/tailwind-only/vue/src/pages/Login.vue.stub +121 -0
  153. package/stubs/tailwind-only/vue/src/pages/Register.vue.stub +137 -0
  154. package/stubs/tailwind-only/vue/src/pages/Users.vue.stub +401 -0
  155. package/stubs/tailwind-only/vue/src/pages/account/Layout.vue.stub +56 -0
  156. package/stubs/tailwind-only/vue/src/pages/account/Preferences.vue.stub +81 -0
  157. package/stubs/tailwind-only/vue/src/pages/account/Profile.vue.stub +69 -0
  158. package/stubs/tailwind-only/vue/src/pages/account/Security.vue.stub +85 -0
  159. package/stubs/tailwind-only/vue/src/style.css.stub +26 -0
  160. package/stubs/themes/corporate/react/src/components/layout/app-sidebar.tsx.stub +74 -0
  161. package/stubs/themes/corporate/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
  162. package/stubs/themes/corporate/react/src/pages/Dashboard.tsx.stub +310 -0
  163. package/stubs/themes/corporate/react/src/pages/Login.tsx.stub +122 -0
  164. package/stubs/themes/corporate/react/src/pages/Register.tsx.stub +144 -0
  165. package/stubs/themes/corporate/react/src/style.css.stub +135 -0
  166. package/stubs/themes/corporate/svelte/src/pages/Dashboard.svelte.stub +271 -0
  167. package/stubs/themes/corporate/svelte/src/pages/Login.svelte.stub +117 -0
  168. package/stubs/themes/corporate/svelte/src/pages/Register.svelte.stub +138 -0
  169. package/stubs/themes/corporate/svelte/src/style.css.stub +134 -0
  170. package/stubs/themes/corporate/vue/src/pages/Dashboard.vue.stub +325 -0
  171. package/stubs/themes/corporate/vue/src/pages/Login.vue.stub +118 -0
  172. package/stubs/themes/corporate/vue/src/pages/Register.vue.stub +139 -0
  173. package/stubs/themes/corporate/vue/src/style.css.stub +134 -0
  174. package/stubs/themes/minimal/react/src/components/layout/app-sidebar.tsx.stub +68 -0
  175. package/stubs/themes/minimal/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
  176. package/stubs/themes/minimal/react/src/pages/Dashboard.tsx.stub +166 -0
  177. package/stubs/themes/minimal/react/src/pages/Login.tsx.stub +95 -0
  178. package/stubs/themes/minimal/react/src/pages/Register.tsx.stub +73 -0
  179. package/stubs/themes/minimal/react/src/style.css.stub +142 -0
  180. package/stubs/themes/minimal/svelte/src/pages/Dashboard.svelte.stub +149 -0
  181. package/stubs/themes/minimal/svelte/src/pages/Login.svelte.stub +90 -0
  182. package/stubs/themes/minimal/svelte/src/pages/Register.svelte.stub +70 -0
  183. package/stubs/themes/minimal/svelte/src/style.css.stub +142 -0
  184. package/stubs/themes/minimal/vue/src/pages/Dashboard.vue.stub +163 -0
  185. package/stubs/themes/minimal/vue/src/pages/Login.vue.stub +91 -0
  186. package/stubs/themes/minimal/vue/src/pages/Register.vue.stub +73 -0
  187. package/stubs/themes/minimal/vue/src/style.css.stub +142 -0
  188. package/stubs/themes/starter/react/src/components/layout/app-sidebar.tsx.stub +74 -0
  189. package/stubs/themes/starter/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
  190. package/stubs/themes/starter/react/src/pages/Dashboard.tsx.stub +236 -0
  191. package/stubs/themes/starter/react/src/pages/Login.tsx.stub +131 -0
  192. package/stubs/themes/starter/react/src/pages/Register.tsx.stub +145 -0
  193. package/stubs/themes/starter/react/src/style.css.stub +141 -0
  194. package/stubs/themes/starter/svelte/src/pages/Dashboard.svelte.stub +212 -0
  195. package/stubs/themes/starter/svelte/src/pages/Login.svelte.stub +126 -0
  196. package/stubs/themes/starter/svelte/src/pages/Register.svelte.stub +139 -0
  197. package/stubs/themes/starter/svelte/src/style.css.stub +141 -0
  198. package/stubs/themes/starter/vue/src/pages/Dashboard.vue.stub +228 -0
  199. package/stubs/themes/starter/vue/src/pages/Login.vue.stub +127 -0
  200. package/stubs/themes/starter/vue/src/pages/Register.vue.stub +140 -0
  201. package/stubs/themes/starter/vue/src/style.css.stub +141 -0
  202. package/stubs/themes/workspace/react/src/components/layout/app-sidebar.tsx.stub +97 -0
  203. package/stubs/themes/workspace/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
  204. package/stubs/themes/workspace/react/src/pages/Dashboard.tsx.stub +304 -0
  205. package/stubs/themes/workspace/react/src/pages/Login.tsx.stub +131 -0
  206. package/stubs/themes/workspace/react/src/pages/Register.tsx.stub +82 -0
  207. package/stubs/themes/workspace/react/src/style.css.stub +138 -0
  208. package/stubs/themes/workspace/svelte/src/pages/Dashboard.svelte.stub +215 -0
  209. package/stubs/themes/workspace/svelte/src/pages/Login.svelte.stub +124 -0
  210. package/stubs/themes/workspace/svelte/src/pages/Register.svelte.stub +76 -0
  211. package/stubs/themes/workspace/svelte/src/style.css.stub +134 -0
  212. package/stubs/themes/workspace/vue/src/pages/Dashboard.vue.stub +220 -0
  213. package/stubs/themes/workspace/vue/src/pages/Login.vue.stub +128 -0
  214. package/stubs/themes/workspace/vue/src/pages/Register.vue.stub +80 -0
  215. package/stubs/themes/workspace/vue/src/style.css.stub +134 -0
  216. package/stubs/vue/src/App.vue.stub +2 -1
  217. package/stubs/vue/src/lib/api.ts.stub +30 -6
  218. package/stubs/vue/src/main.ts.stub +3 -1
  219. package/stubs/vue/src/pages/Login.vue.stub +3 -3
  220. package/stubs/vue/vite.config.ts.stub +20 -1
@@ -0,0 +1,141 @@
1
+ @import "tailwindcss";
2
+ @custom-variant dark (&:where(.dark, .dark *));
3
+
4
+ /*
5
+ * shadcn/ui theme — Starter
6
+ *
7
+ * Bold, gradient-heavy palette with violet/purple primary.
8
+ * Dark sidebar in both light and dark modes for a two-tone SaaS feel.
9
+ */
10
+
11
+ @theme inline {
12
+ --color-background: var(--background);
13
+ --color-foreground: var(--foreground);
14
+ --color-card: var(--card);
15
+ --color-card-foreground: var(--card-foreground);
16
+ --color-popover: var(--popover);
17
+ --color-popover-foreground: var(--popover-foreground);
18
+ --color-primary: var(--primary);
19
+ --color-primary-foreground: var(--primary-foreground);
20
+ --color-secondary: var(--secondary);
21
+ --color-secondary-foreground: var(--secondary-foreground);
22
+ --color-muted: var(--muted);
23
+ --color-muted-foreground: var(--muted-foreground);
24
+ --color-accent: var(--accent);
25
+ --color-accent-foreground: var(--accent-foreground);
26
+ --color-destructive: var(--destructive);
27
+ --color-destructive-foreground: var(--destructive-foreground);
28
+ --color-border: var(--border);
29
+ --color-input: var(--input);
30
+ --color-ring: var(--ring);
31
+ --color-chart-1: var(--chart-1);
32
+ --color-chart-2: var(--chart-2);
33
+ --color-chart-3: var(--chart-3);
34
+ --color-chart-4: var(--chart-4);
35
+ --color-chart-5: var(--chart-5);
36
+ --color-sidebar: var(--sidebar);
37
+ --color-sidebar-foreground: var(--sidebar-foreground);
38
+ --color-sidebar-primary: var(--sidebar-primary);
39
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
40
+ --color-sidebar-accent: var(--sidebar-accent);
41
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
42
+ --color-sidebar-border: var(--sidebar-border);
43
+ --color-sidebar-ring: var(--sidebar-ring);
44
+ --radius-sm: calc(var(--radius) - 4px);
45
+ --radius-md: calc(var(--radius) - 2px);
46
+ --radius-lg: var(--radius);
47
+ --radius-xl: calc(var(--radius) + 4px);
48
+ }
49
+
50
+ :root {
51
+ --radius: 0.625rem;
52
+ --background: oklch(0.985 0.002 286);
53
+ --foreground: oklch(0.141 0.005 285.823);
54
+ --card: oklch(1 0 0);
55
+ --card-foreground: oklch(0.141 0.005 285.823);
56
+ --popover: oklch(1 0 0);
57
+ --popover-foreground: oklch(0.141 0.005 285.823);
58
+ --primary: oklch(0.606 0.25 292.717);
59
+ --primary-foreground: oklch(0.985 0 0);
60
+ --secondary: oklch(0.967 0.001 286.375);
61
+ --secondary-foreground: oklch(0.21 0.006 285.885);
62
+ --muted: oklch(0.967 0.001 286.375);
63
+ --muted-foreground: oklch(0.552 0.016 285.938);
64
+ --accent: oklch(0.967 0.001 286.375);
65
+ --accent-foreground: oklch(0.21 0.006 285.885);
66
+ --destructive: oklch(0.577 0.245 27.325);
67
+ --destructive-foreground: oklch(0.577 0.245 27.325);
68
+ --border: oklch(0.92 0.004 286.32);
69
+ --input: oklch(0.92 0.004 286.32);
70
+ --ring: oklch(0.606 0.25 292.717);
71
+ --chart-1: oklch(0.606 0.25 292.717);
72
+ --chart-2: oklch(0.546 0.245 262.881);
73
+ --chart-3: oklch(0.6 0.118 184.714);
74
+ --chart-4: oklch(0.828 0.189 84.429);
75
+ --chart-5: oklch(0.769 0.188 70.08);
76
+ /* Dark sidebar even in light mode */
77
+ --sidebar: oklch(0.16 0.015 286);
78
+ --sidebar-foreground: oklch(0.95 0.002 286);
79
+ --sidebar-primary: oklch(0.7 0.2 292.717);
80
+ --sidebar-primary-foreground: oklch(0.985 0 0);
81
+ --sidebar-accent: oklch(0.22 0.012 286);
82
+ --sidebar-accent-foreground: oklch(0.95 0.002 286);
83
+ --sidebar-border: oklch(0.25 0.01 286);
84
+ --sidebar-ring: oklch(0.7 0.2 292.717);
85
+ }
86
+
87
+ .dark {
88
+ --background: oklch(0.13 0.015 286);
89
+ --foreground: oklch(0.985 0 0);
90
+ --card: oklch(0.17 0.012 286);
91
+ --card-foreground: oklch(0.985 0 0);
92
+ --popover: oklch(0.17 0.012 286);
93
+ --popover-foreground: oklch(0.985 0 0);
94
+ --primary: oklch(0.7 0.2 292.717);
95
+ --primary-foreground: oklch(0.16 0.04 292.717);
96
+ --secondary: oklch(0.269 0.006 286.033);
97
+ --secondary-foreground: oklch(0.985 0 0);
98
+ --muted: oklch(0.269 0.006 286.033);
99
+ --muted-foreground: oklch(0.708 0.014 286.067);
100
+ --accent: oklch(0.269 0.006 286.033);
101
+ --accent-foreground: oklch(0.985 0 0);
102
+ --destructive: oklch(0.704 0.191 22.216);
103
+ --destructive-foreground: oklch(0.704 0.191 22.216);
104
+ --border: oklch(0.274 0.006 286.033);
105
+ --input: oklch(0.274 0.006 286.033);
106
+ --ring: oklch(0.7 0.2 292.717);
107
+ --chart-1: oklch(0.7 0.2 292.717);
108
+ --chart-2: oklch(0.623 0.214 262.881);
109
+ --chart-3: oklch(0.769 0.188 70.08);
110
+ --chart-4: oklch(0.627 0.265 303.9);
111
+ --chart-5: oklch(0.645 0.246 16.439);
112
+ --sidebar: oklch(0.13 0.015 286);
113
+ --sidebar-foreground: oklch(0.95 0.002 286);
114
+ --sidebar-primary: oklch(0.7 0.2 292.717);
115
+ --sidebar-primary-foreground: oklch(0.985 0 0);
116
+ --sidebar-accent: oklch(0.22 0.012 286);
117
+ --sidebar-accent-foreground: oklch(0.95 0.002 286);
118
+ --sidebar-border: oklch(0.25 0.01 286);
119
+ --sidebar-ring: oklch(0.7 0.2 292.717);
120
+ }
121
+
122
+ @layer base {
123
+ * {
124
+ @apply border-border;
125
+ }
126
+ body {
127
+ @apply bg-background text-foreground;
128
+ }
129
+ }
130
+
131
+ @keyframes fadeUp {
132
+ from { opacity: 0; transform: translateY(8px); }
133
+ to { opacity: 1; transform: translateY(0); }
134
+ }
135
+ .animate-fade-up { animation: fadeUp 0.4s ease-out; }
136
+
137
+ @keyframes gradient-shift {
138
+ 0%, 100% { background-position: 0% 50%; }
139
+ 50% { background-position: 100% 50%; }
140
+ }
141
+ .animate-gradient { animation: gradient-shift 6s ease infinite; background-size: 200% 200%; }
@@ -0,0 +1,97 @@
1
+ import {
2
+ Sidebar,
3
+ SidebarContent,
4
+ SidebarFooter,
5
+ SidebarHeader,
6
+ SidebarMenu,
7
+ SidebarMenuButton,
8
+ SidebarMenuItem,
9
+ SidebarRail,
10
+ SidebarSeparator,
11
+ SidebarGroup,
12
+ SidebarGroupLabel,
13
+ } from '@/components/ui/sidebar'
14
+ import { NavGroup } from './nav-group'
15
+ import { NavUser, type NavUserProps } from './nav-user'
16
+ import { sidebarData } from './sidebar-data'
17
+ import { Command, Star } from 'lucide-react'
18
+
19
+ export interface AppSidebarProps {
20
+ user: NavUserProps['user']
21
+ appName: string
22
+ activePath: string
23
+ navigate: (href: string) => void
24
+ onLogout: () => void
25
+ }
26
+
27
+ export function AppSidebar({
28
+ user,
29
+ appName,
30
+ activePath,
31
+ navigate,
32
+ onLogout,
33
+ }: AppSidebarProps) {
34
+ return (
35
+ <Sidebar variant="inset" collapsible="icon">
36
+ <SidebarHeader>
37
+ <SidebarMenu>
38
+ <SidebarMenuItem>
39
+ <SidebarMenuButton
40
+ size="lg"
41
+ className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
42
+ onClick={() => navigate('/dashboard')}
43
+ tooltip={appName}
44
+ >
45
+ <div className="flex aspect-square size-8 items-center justify-center rounded-xl bg-sidebar-primary text-sidebar-primary-foreground">
46
+ <Command className="size-4" />
47
+ </div>
48
+ <div className="grid flex-1 text-left text-sm leading-tight">
49
+ <span className="truncate font-semibold">{appName}</span>
50
+ <span className="truncate text-xs text-muted-foreground">
51
+ Workspace
52
+ </span>
53
+ </div>
54
+ </SidebarMenuButton>
55
+ </SidebarMenuItem>
56
+ </SidebarMenu>
57
+ </SidebarHeader>
58
+
59
+ <SidebarContent>
60
+ {sidebarData.map((group) => (
61
+ <NavGroup
62
+ key={group.title}
63
+ group={group}
64
+ activePath={activePath}
65
+ navigate={navigate}
66
+ />
67
+ ))}
68
+
69
+ <SidebarSeparator />
70
+
71
+ <SidebarGroup>
72
+ <SidebarGroupLabel>
73
+ <Star className="mr-1 size-3" />
74
+ Favorites
75
+ </SidebarGroupLabel>
76
+ <SidebarMenu>
77
+ <SidebarMenuItem>
78
+ <SidebarMenuButton
79
+ tooltip="Dashboard"
80
+ isActive={activePath === '/dashboard'}
81
+ onClick={() => navigate('/dashboard')}
82
+ >
83
+ <span className="text-muted-foreground">Dashboard</span>
84
+ </SidebarMenuButton>
85
+ </SidebarMenuItem>
86
+ </SidebarMenu>
87
+ </SidebarGroup>
88
+ </SidebarContent>
89
+
90
+ <SidebarFooter>
91
+ <NavUser user={user} navigate={navigate} onLogout={onLogout} />
92
+ </SidebarFooter>
93
+
94
+ <SidebarRail />
95
+ </Sidebar>
96
+ )
97
+ }
@@ -0,0 +1,42 @@
1
+ import { useCallback } from 'react'
2
+ import { post } from '@/lib/api'
3
+ import { SidebarProvider, SidebarInset } from '@/components/ui/sidebar'
4
+ import { AppSidebar } from './app-sidebar'
5
+
6
+ interface AuthenticatedLayoutProps {
7
+ children: React.ReactNode
8
+ currentUser?: { name: string; email: string; role?: string } | null
9
+ appName?: string
10
+ navigate: (href: string) => void
11
+ activePath: string
12
+ }
13
+
14
+ export function AuthenticatedLayout({
15
+ children,
16
+ currentUser,
17
+ appName = 'Mantiq',
18
+ navigate,
19
+ activePath,
20
+ }: AuthenticatedLayoutProps) {
21
+ const handleLogout = useCallback(async () => {
22
+ await post('/logout', {})
23
+ navigate('/login')
24
+ }, [navigate])
25
+
26
+ const user = currentUser ?? { name: 'User', email: 'user@example.com' }
27
+
28
+ return (
29
+ <SidebarProvider defaultOpen={true}>
30
+ <AppSidebar
31
+ user={user}
32
+ appName={appName}
33
+ activePath={activePath}
34
+ navigate={navigate}
35
+ onLogout={handleLogout}
36
+ />
37
+ <SidebarInset>
38
+ {children}
39
+ </SidebarInset>
40
+ </SidebarProvider>
41
+ )
42
+ }
@@ -0,0 +1,304 @@
1
+ import { useState } from 'react'
2
+ import { AuthenticatedLayout } from '@/components/layout/authenticated-layout'
3
+ import { Header } from '@/components/layout/header'
4
+ import { Main } from '@/components/layout/main'
5
+ import {
6
+ Card,
7
+ CardContent,
8
+ } from '@/components/ui/card'
9
+ import {
10
+ ChevronRight,
11
+ ChevronDown,
12
+ GripVertical,
13
+ ClipboardList,
14
+ Hammer,
15
+ CheckCircle2,
16
+ Lightbulb,
17
+ KanbanSquare,
18
+ FileText,
19
+ BookOpen,
20
+ Building2,
21
+ Radio,
22
+ Rocket,
23
+ StickyNote,
24
+ Hand,
25
+ } from 'lucide-react'
26
+
27
+ interface DashboardProps {
28
+ appName?: string
29
+ currentUser?: { id: number; name: string; email: string; role: string } | null
30
+ navigate: (href: string) => void
31
+ [key: string]: any
32
+ }
33
+
34
+ type Status = 'not-started' | 'in-progress' | 'done'
35
+
36
+ interface Task {
37
+ id: number
38
+ title: string
39
+ status: Status
40
+ tag?: string
41
+ }
42
+
43
+ const kanbanColumns: { status: Status; label: string; icon: typeof ClipboardList; iconClass: string }[] = [
44
+ { status: 'not-started', label: 'Not Started', icon: ClipboardList, iconClass: 'text-muted-foreground' },
45
+ { status: 'in-progress', label: 'In Progress', icon: Hammer, iconClass: 'text-amber-500' },
46
+ { status: 'done', label: 'Done', icon: CheckCircle2, iconClass: 'text-emerald-500' },
47
+ ]
48
+
49
+ const initialTasks: Task[] = [
50
+ { id: 1, title: 'Design database schema', status: 'done', tag: 'Backend' },
51
+ { id: 2, title: 'Set up authentication flow', status: 'done', tag: 'Auth' },
52
+ { id: 3, title: 'Build API endpoints', status: 'in-progress', tag: 'Backend' },
53
+ { id: 4, title: 'Create dashboard layout', status: 'in-progress', tag: 'Frontend' },
54
+ { id: 5, title: 'Write unit tests', status: 'not-started', tag: 'Testing' },
55
+ { id: 6, title: 'Set up CI/CD pipeline', status: 'not-started', tag: 'DevOps' },
56
+ { id: 7, title: 'Configure email notifications', status: 'not-started', tag: 'Backend' },
57
+ { id: 8, title: 'Deploy to staging', status: 'not-started', tag: 'DevOps' },
58
+ ]
59
+
60
+ const tagColors: Record<string, string> = {
61
+ Backend: 'bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300',
62
+ Frontend: 'bg-purple-100 text-purple-700 dark:bg-purple-900/40 dark:text-purple-300',
63
+ Auth: 'bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300',
64
+ Testing: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300',
65
+ DevOps: 'bg-rose-100 text-rose-700 dark:bg-rose-900/40 dark:text-rose-300',
66
+ }
67
+
68
+ const pageItems = [
69
+ { icon: BookOpen, title: 'Getting Started', desc: 'Quick introduction and setup guide' },
70
+ { icon: Building2, title: 'Architecture', desc: 'How the application is structured' },
71
+ { icon: Radio, title: 'API Reference', desc: 'Endpoints, params, and responses' },
72
+ { icon: Rocket, title: 'Deployment', desc: 'Deploy your app to production' },
73
+ ]
74
+
75
+ function getGreeting() {
76
+ const hour = new Date().getHours()
77
+ if (hour < 12) return 'Good morning'
78
+ if (hour < 18) return 'Good afternoon'
79
+ return 'Good evening'
80
+ }
81
+
82
+ export default function Dashboard({
83
+ appName = 'Mantiq',
84
+ currentUser,
85
+ navigate,
86
+ }: DashboardProps) {
87
+ const [tasks, setTasks] = useState<Task[]>(initialTasks)
88
+ const [expandedSections, setExpandedSections] = useState<Record<string, boolean>>({
89
+ kanban: true,
90
+ pages: true,
91
+ notes: false,
92
+ })
93
+ const [draggedId, setDraggedId] = useState<number | null>(null)
94
+ const [dropTarget, setDropTarget] = useState<Status | null>(null)
95
+
96
+ const toggle = (section: string) =>
97
+ setExpandedSections((prev) => ({ ...prev, [section]: !prev[section] }))
98
+
99
+ const handleDragStart = (e: React.DragEvent, taskId: number) => {
100
+ setDraggedId(taskId)
101
+ e.dataTransfer.effectAllowed = 'move'
102
+ if (e.currentTarget instanceof HTMLElement) {
103
+ e.currentTarget.style.opacity = '0.5'
104
+ }
105
+ }
106
+
107
+ const handleDragEnd = (e: React.DragEvent) => {
108
+ setDraggedId(null)
109
+ setDropTarget(null)
110
+ if (e.currentTarget instanceof HTMLElement) {
111
+ e.currentTarget.style.opacity = '1'
112
+ }
113
+ }
114
+
115
+ const handleDragOver = (e: React.DragEvent, status: Status) => {
116
+ e.preventDefault()
117
+ e.dataTransfer.dropEffect = 'move'
118
+ setDropTarget(status)
119
+ }
120
+
121
+ const handleDragLeave = () => {
122
+ setDropTarget(null)
123
+ }
124
+
125
+ const handleDrop = (e: React.DragEvent, targetStatus: Status) => {
126
+ e.preventDefault()
127
+ if (draggedId === null) return
128
+ setTasks((prev) =>
129
+ prev.map((t) => (t.id === draggedId ? { ...t, status: targetStatus } : t)),
130
+ )
131
+ setDraggedId(null)
132
+ setDropTarget(null)
133
+ }
134
+
135
+ return (
136
+ <AuthenticatedLayout
137
+ currentUser={currentUser}
138
+ appName={appName}
139
+ navigate={navigate}
140
+ activePath="/dashboard"
141
+ >
142
+ <Header navigate={navigate} />
143
+ <Main>
144
+ <div className="max-w-4xl mx-auto space-y-8">
145
+ {/* Cover & title */}
146
+ <div>
147
+ <div className="h-40 rounded-2xl bg-gradient-to-r from-amber-300 via-orange-300 to-rose-300 dark:from-amber-800 dark:via-orange-900 dark:to-rose-900 mb-6 shadow-sm" />
148
+ <div className="-mt-10 ml-3">
149
+ <div className="flex h-14 w-14 items-center justify-center rounded-2xl bg-card border shadow-md">
150
+ <Hand className="h-7 w-7 text-amber-500" />
151
+ </div>
152
+ </div>
153
+ <h1 className="mt-4 text-3xl font-bold tracking-tight">
154
+ {getGreeting()}, {currentUser?.name?.split(' ')[0] ?? 'there'}
155
+ </h1>
156
+ <p className="text-muted-foreground mt-1">
157
+ Here's your workspace overview. Drag tasks between columns to update their status.
158
+ </p>
159
+ </div>
160
+
161
+ {/* Callout block */}
162
+ <div className="flex gap-3 rounded-xl bg-amber-50 dark:bg-amber-950/30 border border-amber-300 dark:border-amber-700 p-4 shadow-sm">
163
+ <Lightbulb className="h-5 w-5 text-amber-500 shrink-0 mt-0.5" />
164
+ <div>
165
+ <p className="text-sm font-medium">Tip</p>
166
+ <p className="text-sm text-muted-foreground">
167
+ Customize this dashboard by editing <code className="rounded bg-muted px-1 py-0.5 text-xs font-mono">src/pages/Dashboard.tsx</code>.
168
+ Add your own widgets, data sources, and integrations.
169
+ </p>
170
+ </div>
171
+ </div>
172
+
173
+ {/* Kanban board section */}
174
+ <div>
175
+ <button
176
+ type="button"
177
+ onClick={() => toggle('kanban')}
178
+ className="flex items-center gap-1.5 mb-3 text-sm font-semibold text-muted-foreground hover:text-foreground transition-colors"
179
+ >
180
+ {expandedSections.kanban ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
181
+ <KanbanSquare className="h-4 w-4" />
182
+ Project Board
183
+ </button>
184
+
185
+ {expandedSections.kanban && (
186
+ <div className="grid gap-4 md:grid-cols-3">
187
+ {kanbanColumns.map((col) => {
188
+ const Icon = col.icon
189
+ const columnTasks = tasks.filter((t) => t.status === col.status)
190
+ const isOver = dropTarget === col.status && draggedId !== null
191
+ return (
192
+ <div
193
+ key={col.status}
194
+ onDragOver={(e) => handleDragOver(e, col.status)}
195
+ onDragLeave={handleDragLeave}
196
+ onDrop={(e) => handleDrop(e, col.status)}
197
+ className={`rounded-xl p-2 -m-2 transition-colors ${isOver ? 'bg-primary/5 ring-2 ring-primary/20' : ''}`}
198
+ >
199
+ <div className="flex items-center gap-2 mb-3 px-2">
200
+ <Icon className={`h-4 w-4 ${col.iconClass}`} />
201
+ <span className="text-sm font-medium">{col.label}</span>
202
+ <span className="ml-auto flex h-5 w-5 items-center justify-center rounded-full bg-muted text-xs text-muted-foreground">
203
+ {columnTasks.length}
204
+ </span>
205
+ </div>
206
+ <div className="space-y-2 min-h-[60px]">
207
+ {columnTasks.map((task) => (
208
+ <Card
209
+ key={task.id}
210
+ draggable
211
+ onDragStart={(e) => handleDragStart(e, task.id)}
212
+ onDragEnd={handleDragEnd}
213
+ className={`group cursor-grab active:cursor-grabbing shadow-sm hover:shadow-md transition-all border-border/60 ${
214
+ draggedId === task.id ? 'opacity-50 scale-95' : ''
215
+ }`}
216
+ >
217
+ <CardContent className="p-3">
218
+ <div className="flex items-start gap-2">
219
+ <GripVertical className="h-4 w-4 mt-0.5 text-muted-foreground/30 group-hover:text-muted-foreground/60 transition-colors shrink-0" />
220
+ <div className="flex-1 min-w-0">
221
+ <p className="text-sm">{task.title}</p>
222
+ {task.tag && (
223
+ <span className={`mt-1.5 inline-block rounded-md px-1.5 py-0.5 text-[10px] font-medium ${tagColors[task.tag] ?? 'bg-muted text-muted-foreground'}`}>
224
+ {task.tag}
225
+ </span>
226
+ )}
227
+ </div>
228
+ </div>
229
+ </CardContent>
230
+ </Card>
231
+ ))}
232
+ {columnTasks.length === 0 && (
233
+ <div className={`rounded-xl border-2 border-dashed p-6 text-center text-xs text-muted-foreground transition-colors ${isOver ? 'border-primary/40 bg-primary/5' : ''}`}>
234
+ Drop tasks here
235
+ </div>
236
+ )}
237
+ </div>
238
+ </div>
239
+ )
240
+ })}
241
+ </div>
242
+ )}
243
+ </div>
244
+
245
+ {/* Pages section */}
246
+ <div>
247
+ <button
248
+ type="button"
249
+ onClick={() => toggle('pages')}
250
+ className="flex items-center gap-1.5 mb-3 text-sm font-semibold text-muted-foreground hover:text-foreground transition-colors"
251
+ >
252
+ {expandedSections.pages ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
253
+ <FileText className="h-4 w-4" />
254
+ Pages
255
+ </button>
256
+
257
+ {expandedSections.pages && (
258
+ <div className="space-y-1">
259
+ {pageItems.map((page) => {
260
+ const Icon = page.icon
261
+ return (
262
+ <div
263
+ key={page.title}
264
+ className="flex items-center gap-3 rounded-lg px-3 py-2.5 transition-colors hover:bg-muted/50 cursor-pointer"
265
+ >
266
+ <Icon className="h-4 w-4 text-muted-foreground shrink-0" />
267
+ <div className="flex-1 min-w-0">
268
+ <p className="text-sm font-medium">{page.title}</p>
269
+ <p className="text-xs text-muted-foreground truncate">{page.desc}</p>
270
+ </div>
271
+ </div>
272
+ )
273
+ })}
274
+ </div>
275
+ )}
276
+ </div>
277
+
278
+ {/* Notes toggle */}
279
+ <div>
280
+ <button
281
+ type="button"
282
+ onClick={() => toggle('notes')}
283
+ className="flex items-center gap-1.5 mb-3 text-sm font-semibold text-muted-foreground hover:text-foreground transition-colors"
284
+ >
285
+ {expandedSections.notes ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
286
+ <StickyNote className="h-4 w-4" />
287
+ Quick Notes
288
+ </button>
289
+
290
+ {expandedSections.notes && (
291
+ <Card className="shadow-none">
292
+ <CardContent className="p-4">
293
+ <div className="rounded-lg bg-muted/30 p-4 text-sm text-muted-foreground italic">
294
+ Start typing your notes here... This is a placeholder for a rich-text editor.
295
+ </div>
296
+ </CardContent>
297
+ </Card>
298
+ )}
299
+ </div>
300
+ </div>
301
+ </Main>
302
+ </AuthenticatedLayout>
303
+ )
304
+ }