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,57 @@
1
+ import {
2
+ Home,
3
+ Users,
4
+ Settings,
5
+ User,
6
+ Lock,
7
+ Palette,
8
+ BookOpen,
9
+ Github,
10
+ type LucideIcon,
11
+ } from 'lucide-vue-next'
12
+
13
+ export interface NavItem {
14
+ title: string
15
+ url: string
16
+ icon: LucideIcon
17
+ badge?: string
18
+ external?: boolean
19
+ items?: NavItem[]
20
+ }
21
+
22
+ export interface NavGroup {
23
+ title: string
24
+ items: NavItem[]
25
+ }
26
+
27
+ export const sidebarData: NavGroup[] = [
28
+ {
29
+ title: 'General',
30
+ items: [
31
+ { title: 'Dashboard', url: '/dashboard', icon: Home },
32
+ { title: 'Users', url: '/users', icon: Users },
33
+ ],
34
+ },
35
+ {
36
+ title: 'Documentation',
37
+ items: [
38
+ { title: 'Docs', url: 'https://github.com/mantiqjs/mantiq#readme', icon: BookOpen, external: true },
39
+ { title: 'GitHub', url: 'https://github.com/mantiqjs/mantiq', icon: Github, external: true },
40
+ ],
41
+ },
42
+ {
43
+ title: 'Account',
44
+ items: [
45
+ {
46
+ title: 'Settings',
47
+ url: '/account/profile',
48
+ icon: Settings,
49
+ items: [
50
+ { title: 'Profile', url: '/account/profile', icon: User },
51
+ { title: 'Security', url: '/account/security', icon: Lock },
52
+ { title: 'Preferences', url: '/account/preferences', icon: Palette },
53
+ ],
54
+ },
55
+ ],
56
+ },
57
+ ]
@@ -0,0 +1,7 @@
1
+ import type { ClassValue } from "clsx"
2
+ import { clsx } from "clsx"
3
+ import { twMerge } from "tailwind-merge"
4
+
5
+ export function cn(...inputs: ClassValue[]) {
6
+ return twMerge(clsx(inputs))
7
+ }
@@ -0,0 +1,195 @@
1
+ <script setup lang="ts">
2
+ import { AuthenticatedLayout } from '@/components/layout'
3
+ import { Header } from '@/components/layout'
4
+ import { Main } from '@/components/layout'
5
+ import { TopNav } from '@/components/layout'
6
+ import type { TopNavLink } from '@/components/layout/TopNav.vue'
7
+ import { Download } from 'lucide-vue-next'
8
+
9
+ const props = withDefaults(defineProps<{
10
+ appName?: string
11
+ currentUser?: { id: number; name: string; email: string; role: string } | null
12
+ navigate: (href: string) => void
13
+ }>(), {
14
+ appName: 'Mantiq',
15
+ })
16
+
17
+ const topNav: TopNavLink[] = [
18
+ { title: 'Overview', href: '/dashboard', isActive: true },
19
+ { title: 'Sales', href: '/dashboard', isActive: false, disabled: true },
20
+ { title: 'Tickets', href: '/dashboard', isActive: false, disabled: true },
21
+ { title: 'Performance', href: '/dashboard', isActive: false, disabled: true },
22
+ ]
23
+
24
+ const recentSales = [
25
+ { name: 'Olivia Martin', email: 'olivia.martin@email.com', amount: '+$1,999.00' },
26
+ { name: 'Jackson Lee', email: 'jackson.lee@email.com', amount: '+$39.00' },
27
+ { name: 'Isabella Nguyen', email: 'isabella.nguyen@email.com', amount: '+$299.00' },
28
+ { name: 'William Kim', email: 'will@email.com', amount: '+$99.00' },
29
+ { name: 'Sofia Davis', email: 'sofia.davis@email.com', amount: '+$39.00' },
30
+ ]
31
+
32
+ function getInitials(name: string) {
33
+ return name
34
+ .split(' ')
35
+ .map((n) => n[0])
36
+ .join('')
37
+ .toUpperCase()
38
+ .slice(0, 2)
39
+ }
40
+
41
+ const bars = [40, 30, 55, 45, 70, 60, 80, 50, 65, 45, 75, 55]
42
+ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
43
+ const maxH = 160
44
+ const barW = 32
45
+ const gap = 48
46
+ const svgW = bars.length * gap
47
+ const svgH = maxH + 30
48
+ </script>
49
+
50
+ <template>
51
+ <AuthenticatedLayout
52
+ :current-user="currentUser"
53
+ :app-name="appName"
54
+ :navigate="navigate"
55
+ active-path="/dashboard"
56
+ >
57
+ <Header :navigate="navigate">
58
+ <TopNav :links="topNav" @link-click="navigate" />
59
+ </Header>
60
+ <Main>
61
+ <div class="space-y-4">
62
+ <!-- Page title row -->
63
+ <div class="flex items-center justify-between">
64
+ <h2 class="text-3xl font-bold tracking-tight">Dashboard</h2>
65
+ <button
66
+ disabled
67
+ class="inline-flex items-center gap-2 rounded-md border border-input bg-background px-3 py-1.5 text-sm font-medium text-muted-foreground shadow-sm"
68
+ >
69
+ <Download class="h-4 w-4" />
70
+ Download
71
+ </button>
72
+ </div>
73
+
74
+ <!-- Content -->
75
+ <div class="space-y-4">
76
+ <!-- Stat cards -->
77
+ <div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
78
+ <!-- Total Revenue -->
79
+ <div class="rounded-xl border bg-card p-6 text-card-foreground shadow-sm">
80
+ <div class="flex items-center justify-between space-y-0 pb-2">
81
+ <h3 class="text-sm font-medium">Total Revenue</h3>
82
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="h-4 w-4 text-muted-foreground">
83
+ <path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
84
+ </svg>
85
+ </div>
86
+ <div class="text-2xl font-bold">$45,231.89</div>
87
+ <p class="text-xs text-muted-foreground">+20.1% from last month</p>
88
+ </div>
89
+
90
+ <!-- Subscriptions -->
91
+ <div class="rounded-xl border bg-card p-6 text-card-foreground shadow-sm">
92
+ <div class="flex items-center justify-between space-y-0 pb-2">
93
+ <h3 class="text-sm font-medium">Subscriptions</h3>
94
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="h-4 w-4 text-muted-foreground">
95
+ <path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
96
+ <circle cx="9" cy="7" r="4" />
97
+ <path d="M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75" />
98
+ </svg>
99
+ </div>
100
+ <div class="text-2xl font-bold">+2,350</div>
101
+ <p class="text-xs text-muted-foreground">+180.1% from last month</p>
102
+ </div>
103
+
104
+ <!-- Sales -->
105
+ <div class="rounded-xl border bg-card p-6 text-card-foreground shadow-sm">
106
+ <div class="flex items-center justify-between space-y-0 pb-2">
107
+ <h3 class="text-sm font-medium">Sales</h3>
108
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="h-4 w-4 text-muted-foreground">
109
+ <rect width="20" height="14" x="2" y="5" rx="2" />
110
+ <path d="M2 10h20" />
111
+ </svg>
112
+ </div>
113
+ <div class="text-2xl font-bold">+12,234</div>
114
+ <p class="text-xs text-muted-foreground">+19% from last month</p>
115
+ </div>
116
+
117
+ <!-- Active Now -->
118
+ <div class="rounded-xl border bg-card p-6 text-card-foreground shadow-sm">
119
+ <div class="flex items-center justify-between space-y-0 pb-2">
120
+ <h3 class="text-sm font-medium">Active Now</h3>
121
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="h-4 w-4 text-muted-foreground">
122
+ <path d="M22 12h-4l-3 9L9 3l-3 9H2" />
123
+ </svg>
124
+ </div>
125
+ <div class="text-2xl font-bold">+573</div>
126
+ <p class="text-xs text-muted-foreground">+201 since last hour</p>
127
+ </div>
128
+ </div>
129
+
130
+ <!-- Bottom row: chart + recent sales -->
131
+ <div class="grid gap-4 lg:grid-cols-7">
132
+ <!-- Chart card -->
133
+ <div class="rounded-xl border bg-card text-card-foreground shadow-sm lg:col-span-4">
134
+ <div class="p-6 pb-2">
135
+ <h3 class="text-lg font-semibold leading-none tracking-tight">Overview</h3>
136
+ </div>
137
+ <div class="p-6 pt-0 pl-2">
138
+ <svg
139
+ :viewBox="`0 0 ${svgW} ${svgH}`"
140
+ class="h-[350px] w-full"
141
+ preserveAspectRatio="none"
142
+ >
143
+ <g v-for="(h, i) in bars" :key="i">
144
+ <rect
145
+ :x="i * gap + (gap - barW) / 2"
146
+ :y="maxH - (h / 100) * maxH"
147
+ :width="barW"
148
+ :height="(h / 100) * maxH"
149
+ rx="4"
150
+ class="fill-foreground/15"
151
+ />
152
+ <text
153
+ :x="i * gap + gap / 2"
154
+ :y="maxH + 18"
155
+ text-anchor="middle"
156
+ class="fill-muted-foreground text-[10px]"
157
+ >
158
+ {{ months[i] }}
159
+ </text>
160
+ </g>
161
+ </svg>
162
+ </div>
163
+ </div>
164
+
165
+ <!-- Recent sales card -->
166
+ <div class="rounded-xl border bg-card text-card-foreground shadow-sm lg:col-span-3">
167
+ <div class="p-6 pb-2">
168
+ <h3 class="text-lg font-semibold leading-none tracking-tight">Recent Sales</h3>
169
+ <p class="mt-1.5 text-sm text-muted-foreground">You made 265 sales this month.</p>
170
+ </div>
171
+ <div class="p-6 pt-0">
172
+ <div class="space-y-8">
173
+ <div
174
+ v-for="sale in recentSales"
175
+ :key="sale.email"
176
+ class="flex items-center"
177
+ >
178
+ <span class="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted text-xs font-medium">
179
+ {{ getInitials(sale.name) }}
180
+ </span>
181
+ <div class="ml-4 space-y-1">
182
+ <p class="text-sm font-medium leading-none">{{ sale.name }}</p>
183
+ <p class="text-sm text-muted-foreground">{{ sale.email }}</p>
184
+ </div>
185
+ <div class="ml-auto font-medium">{{ sale.amount }}</div>
186
+ </div>
187
+ </div>
188
+ </div>
189
+ </div>
190
+ </div>
191
+ </div>
192
+ </div>
193
+ </Main>
194
+ </AuthenticatedLayout>
195
+ </template>
@@ -0,0 +1,121 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import { post } from '@/lib/api'
4
+
5
+ const props = withDefaults(defineProps<{
6
+ appName?: string
7
+ navigate: (href: string) => void
8
+ }>(), {
9
+ appName: 'Mantiq',
10
+ })
11
+
12
+ const email = ref('')
13
+ const password = ref('')
14
+ const error = ref('')
15
+ const loading = ref(false)
16
+
17
+ async function handleSubmit() {
18
+ error.value = ''
19
+ loading.value = true
20
+ const { ok, data } = await post('/login', { email: email.value, password: password.value })
21
+ if (ok) props.navigate('/dashboard')
22
+ else error.value = data?.error ?? 'Invalid email or password. Please try again.'
23
+ loading.value = false
24
+ }
25
+ </script>
26
+
27
+ <template>
28
+ <div class="min-h-screen flex bg-background">
29
+ <!-- Left brand panel -->
30
+ <div class="hidden lg:flex lg:w-[45%] bg-foreground text-background flex-col justify-between p-10">
31
+ <div class="flex items-center gap-3">
32
+ <div class="flex h-8 w-8 items-center justify-center rounded bg-background text-foreground text-xs font-bold">
33
+ M
34
+ </div>
35
+ <span class="text-lg font-semibold tracking-tight">{{ appName }}</span>
36
+ </div>
37
+
38
+ <div>
39
+ <blockquote class="text-2xl font-medium leading-snug tracking-tight">
40
+ "The framework that gets out of your way."
41
+ </blockquote>
42
+ </div>
43
+
44
+ <p class="text-sm text-background/50">
45
+ &copy; {{ new Date().getFullYear() }} {{ appName }}. All rights reserved.
46
+ </p>
47
+ </div>
48
+
49
+ <!-- Right form panel -->
50
+ <div class="flex flex-1 flex-col items-center justify-center px-6 py-12">
51
+ <!-- Mobile-only logo -->
52
+ <div class="mb-10 flex items-center gap-3 lg:hidden">
53
+ <div class="flex h-8 w-8 items-center justify-center rounded bg-foreground text-background text-xs font-bold">
54
+ M
55
+ </div>
56
+ <span class="text-lg font-semibold tracking-tight">{{ appName }}</span>
57
+ </div>
58
+
59
+ <div class="w-full max-w-sm">
60
+ <div class="mb-8">
61
+ <h1 class="text-2xl font-semibold tracking-tight">Sign in</h1>
62
+ <p class="mt-2 text-sm text-muted-foreground">
63
+ Enter your credentials to continue
64
+ </p>
65
+ </div>
66
+
67
+ <div
68
+ v-if="error"
69
+ class="mb-6 rounded-md border border-destructive px-4 py-3 text-sm text-destructive"
70
+ >
71
+ {{ error }}
72
+ </div>
73
+
74
+ <form class="space-y-4" @submit.prevent="handleSubmit">
75
+ <div class="space-y-2">
76
+ <label for="email" class="text-sm font-medium leading-none">Email</label>
77
+ <input
78
+ id="email"
79
+ v-model="email"
80
+ type="email"
81
+ required
82
+ placeholder="you@example.com"
83
+ autocomplete="email"
84
+ class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
85
+ />
86
+ </div>
87
+ <div class="space-y-2">
88
+ <label for="password" class="text-sm font-medium leading-none">Password</label>
89
+ <input
90
+ id="password"
91
+ v-model="password"
92
+ type="password"
93
+ required
94
+ placeholder="Enter your password"
95
+ autocomplete="current-password"
96
+ class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
97
+ />
98
+ </div>
99
+ <button
100
+ type="submit"
101
+ class="inline-flex h-9 w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50"
102
+ :disabled="loading"
103
+ >
104
+ {{ loading ? 'Signing in...' : 'Sign in' }}
105
+ </button>
106
+ </form>
107
+
108
+ <p class="mt-6 text-center text-sm text-muted-foreground">
109
+ Don't have an account?
110
+ <button
111
+ type="button"
112
+ class="font-medium text-foreground underline underline-offset-4"
113
+ @click="navigate('/register')"
114
+ >
115
+ Register
116
+ </button>
117
+ </p>
118
+ </div>
119
+ </div>
120
+ </div>
121
+ </template>
@@ -0,0 +1,137 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import { post } from '@/lib/api'
4
+
5
+ const props = withDefaults(defineProps<{
6
+ appName?: string
7
+ navigate: (href: string) => void
8
+ }>(), {
9
+ appName: 'Mantiq',
10
+ })
11
+
12
+ const name = ref('')
13
+ const email = ref('')
14
+ const password = ref('')
15
+ const error = ref('')
16
+ const loading = ref(false)
17
+
18
+ async function handleSubmit() {
19
+ error.value = ''
20
+ loading.value = true
21
+ const { ok, data } = await post('/register', {
22
+ name: name.value,
23
+ email: email.value,
24
+ password: password.value,
25
+ })
26
+ if (ok) props.navigate('/dashboard')
27
+ else error.value = data?.error?.message ?? data?.error ?? 'Registration failed'
28
+ loading.value = false
29
+ }
30
+ </script>
31
+
32
+ <template>
33
+ <div class="min-h-screen flex bg-background">
34
+ <!-- Left brand panel -->
35
+ <div class="hidden lg:flex lg:w-[45%] bg-foreground text-background flex-col justify-between p-10">
36
+ <div class="flex items-center gap-3">
37
+ <div class="flex h-8 w-8 items-center justify-center rounded bg-background text-foreground text-xs font-bold">
38
+ M
39
+ </div>
40
+ <span class="text-lg font-semibold tracking-tight">{{ appName }}</span>
41
+ </div>
42
+
43
+ <div>
44
+ <blockquote class="text-2xl font-medium leading-snug tracking-tight">
45
+ "The framework that gets out of your way."
46
+ </blockquote>
47
+ </div>
48
+
49
+ <p class="text-sm text-background/50">
50
+ &copy; {{ new Date().getFullYear() }} {{ appName }}. All rights reserved.
51
+ </p>
52
+ </div>
53
+
54
+ <!-- Right form panel -->
55
+ <div class="flex flex-1 flex-col items-center justify-center px-6 py-12">
56
+ <!-- Mobile-only logo -->
57
+ <div class="mb-10 flex items-center gap-3 lg:hidden">
58
+ <div class="flex h-8 w-8 items-center justify-center rounded bg-foreground text-background text-xs font-bold">
59
+ M
60
+ </div>
61
+ <span class="text-lg font-semibold tracking-tight">{{ appName }}</span>
62
+ </div>
63
+
64
+ <div class="w-full max-w-sm">
65
+ <div class="mb-8">
66
+ <h1 class="text-2xl font-semibold tracking-tight">Create an account</h1>
67
+ <p class="mt-2 text-sm text-muted-foreground">
68
+ Get started with {{ appName }}
69
+ </p>
70
+ </div>
71
+
72
+ <div
73
+ v-if="error"
74
+ class="mb-6 rounded-md border border-destructive px-4 py-3 text-sm text-destructive"
75
+ >
76
+ {{ error }}
77
+ </div>
78
+
79
+ <form class="space-y-4" @submit.prevent="handleSubmit">
80
+ <div class="space-y-2">
81
+ <label for="name" class="text-sm font-medium leading-none">Name</label>
82
+ <input
83
+ id="name"
84
+ v-model="name"
85
+ required
86
+ placeholder="Your name"
87
+ autocomplete="name"
88
+ class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
89
+ />
90
+ </div>
91
+ <div class="space-y-2">
92
+ <label for="email" class="text-sm font-medium leading-none">Email</label>
93
+ <input
94
+ id="email"
95
+ v-model="email"
96
+ type="email"
97
+ required
98
+ placeholder="you@example.com"
99
+ autocomplete="email"
100
+ class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
101
+ />
102
+ </div>
103
+ <div class="space-y-2">
104
+ <label for="password" class="text-sm font-medium leading-none">Password</label>
105
+ <input
106
+ id="password"
107
+ v-model="password"
108
+ type="password"
109
+ required
110
+ placeholder="Create a password"
111
+ autocomplete="new-password"
112
+ class="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
113
+ />
114
+ </div>
115
+ <button
116
+ type="submit"
117
+ class="inline-flex h-9 w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50"
118
+ :disabled="loading"
119
+ >
120
+ {{ loading ? 'Creating account...' : 'Create account' }}
121
+ </button>
122
+ </form>
123
+
124
+ <p class="mt-6 text-center text-sm text-muted-foreground">
125
+ Already have an account?
126
+ <button
127
+ type="button"
128
+ class="font-medium text-foreground underline underline-offset-4"
129
+ @click="navigate('/login')"
130
+ >
131
+ Sign in
132
+ </button>
133
+ </p>
134
+ </div>
135
+ </div>
136
+ </div>
137
+ </template>