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.
- package/package.json +2 -1
- package/skeleton/.env.example +64 -0
- package/skeleton/README.md +46 -0
- package/skeleton/app/Console/Commands/.gitkeep +0 -0
- package/skeleton/app/Enums/UserStatus.ts +7 -0
- package/skeleton/app/Http/Controllers/HomeController.ts +78 -0
- package/skeleton/app/Http/Middleware/.gitkeep +0 -0
- package/skeleton/app/Models/User.ts +7 -0
- package/skeleton/app/Providers/AppServiceProvider.ts +25 -0
- package/skeleton/app/Providers/DatabaseServiceProvider.ts +17 -0
- package/skeleton/bootstrap/.gitkeep +0 -0
- package/skeleton/config/ai.ts +51 -0
- package/skeleton/config/app.ts +108 -0
- package/skeleton/config/auth.ts +51 -0
- package/skeleton/config/broadcasting.ts +93 -0
- package/skeleton/config/cache.ts +61 -0
- package/skeleton/config/cors.ts +77 -0
- package/skeleton/config/database.ts +120 -0
- package/skeleton/config/filesystem.ts +58 -0
- package/skeleton/config/hashing.ts +47 -0
- package/skeleton/config/heartbeat.ts +112 -0
- package/skeleton/config/logging.ts +58 -0
- package/skeleton/config/mail.ts +93 -0
- package/skeleton/config/notify.ts +141 -0
- package/skeleton/config/queue.ts +59 -0
- package/skeleton/config/search.ts +96 -0
- package/skeleton/config/services.ts +110 -0
- package/skeleton/config/session.ts +84 -0
- package/skeleton/config/vite.ts +33 -0
- package/skeleton/database/factories/.gitkeep +0 -0
- package/skeleton/database/migrations/001_create_users_table.ts +19 -0
- package/skeleton/database/migrations/002_create_personal_access_tokens_table.ts +22 -0
- package/skeleton/database/seeders/DatabaseSeeder.ts +7 -0
- package/skeleton/index.ts +20 -0
- package/skeleton/mantiq.ts +8 -0
- package/skeleton/package.json +34 -0
- package/skeleton/public/.gitkeep +0 -0
- package/skeleton/routes/api.ts +8 -0
- package/skeleton/routes/channels.ts +23 -0
- package/skeleton/routes/console.ts +24 -0
- package/skeleton/routes/web.ts +6 -0
- package/skeleton/storage/cache/.gitkeep +0 -0
- package/skeleton/storage/framework/.gitkeep +0 -0
- package/skeleton/tests/feature/api.test.ts +14 -0
- package/skeleton/tests/feature/home.test.ts +17 -0
- package/skeleton/tests/unit/example.test.ts +11 -0
- package/skeleton/tsconfig.json +27 -0
- package/src/index.ts +289 -25
- package/src/templates.ts +141 -945
- package/src/terminal.ts +64 -0
- package/stubs/api-only/routes/api.ts.stub +24 -0
- package/stubs/api-only/tests/feature/token-auth.test.ts.stub +69 -0
- package/stubs/auth/api/app/Http/Controllers/ApiAuthController.ts.stub +57 -0
- package/stubs/auth/api/routes/api.ts.stub +24 -0
- package/stubs/auth/api/tests/feature/token-auth.test.ts.stub +69 -0
- package/stubs/auth/shared/app/Http/Requests/LoginRequest.ts.stub +10 -0
- package/stubs/auth/shared/app/Http/Requests/RegisterRequest.ts.stub +11 -0
- package/stubs/auth/web/app/Http/Controllers/AuthController.ts.stub +43 -0
- package/stubs/auth/web/app/Http/Controllers/PageController.ts.stub +66 -0
- package/stubs/auth/web/routes/web.ts.stub +25 -0
- package/stubs/auth/web/svelte/src/App.svelte.stub +77 -0
- package/stubs/auth/web/svelte/src/pages.ts.stub +17 -0
- package/stubs/auth/web/tests/feature/auth.test.ts.stub +69 -0
- package/stubs/auth/web/vue/src/App.vue.stub +74 -0
- package/stubs/auth/web/vue/src/pages.ts.stub +17 -0
- package/stubs/manifest.json +630 -2
- package/stubs/noauth/app/Http/Controllers/PageController.ts.stub +41 -0
- package/stubs/noauth/app/Models/User.ts.stub +5 -0
- package/stubs/noauth/database/migrations/001_create_users_table.ts.stub +17 -0
- package/stubs/noauth/routes/api.ts.stub +16 -0
- package/stubs/noauth/routes/web.ts.stub +15 -0
- package/stubs/noauth/svelte/src/App.svelte.stub +68 -0
- package/stubs/noauth/svelte/src/pages.ts.stub +7 -0
- package/stubs/noauth/vue/src/App.vue.stub +62 -0
- package/stubs/noauth/vue/src/pages.ts.stub +7 -0
- package/stubs/react/src/App.tsx.stub +4 -2
- package/stubs/react/src/components/layout/search-dialog.tsx.stub +2 -2
- package/stubs/react/src/components/layout/sidebar-data.ts.stub +2 -2
- package/stubs/react/src/lib/api.ts.stub +30 -6
- package/stubs/react/src/pages/Login.tsx.stub +3 -3
- package/stubs/react/src/pages/users/dialogs.tsx.stub +7 -26
- package/stubs/react/vite.config.ts.stub +26 -3
- package/stubs/shared/app/Http/Controllers/ApiAuthController.ts.stub +57 -0
- package/stubs/shared/app/Http/Controllers/AuthController.ts.stub +14 -38
- package/stubs/shared/app/Http/Controllers/PageController.ts.stub +3 -3
- package/stubs/shared/app/Http/Controllers/UserController.ts.stub +61 -0
- package/stubs/shared/app/Http/Requests/LoginRequest.ts.stub +10 -0
- package/stubs/shared/app/Http/Requests/RegisterRequest.ts.stub +11 -0
- package/stubs/shared/app/Http/Requests/StoreUserRequest.ts.stub +11 -0
- package/stubs/shared/app/Http/Requests/UpdateUserRequest.ts.stub +11 -0
- package/stubs/shared/config/app.ts.stub +36 -0
- package/stubs/shared/config/vite.ts.stub +8 -0
- package/stubs/shared/database/factories/UserFactory.ts.stub +4 -6
- package/stubs/shared/routes/api.ts.stub +12 -102
- package/stubs/shared/routes/web.ts.stub +5 -3
- package/stubs/shared/tests/feature/auth.test.ts.stub +69 -0
- package/stubs/shared/tests/feature/users.test.ts.stub +90 -0
- package/stubs/svelte/src/App.svelte.stub +1 -1
- package/stubs/svelte/src/lib/api.ts.stub +30 -6
- package/stubs/svelte/src/main.ts.stub +3 -1
- package/stubs/svelte/src/pages/Login.svelte.stub +3 -3
- package/stubs/svelte/vite.config.ts.stub +20 -1
- package/stubs/tailwind-only/react/src/components/layout/app-sidebar.tsx.stub +68 -0
- package/stubs/tailwind-only/react/src/components/layout/authenticated-layout.tsx.stub +57 -0
- package/stubs/tailwind-only/react/src/components/layout/header.tsx.stub +52 -0
- package/stubs/tailwind-only/react/src/components/layout/main.tsx.stub +21 -0
- package/stubs/tailwind-only/react/src/components/layout/nav-group.tsx.stub +185 -0
- package/stubs/tailwind-only/react/src/components/layout/nav-user.tsx.stub +106 -0
- package/stubs/tailwind-only/react/src/components/layout/sidebar-data.ts.stub +58 -0
- package/stubs/tailwind-only/react/src/components/layout/theme-toggle.tsx.stub +36 -0
- package/stubs/tailwind-only/react/src/components/layout/top-nav.tsx.stub +72 -0
- package/stubs/tailwind-only/react/src/lib/utils.ts.stub +6 -0
- package/stubs/tailwind-only/react/src/pages/Dashboard.tsx.stub +205 -0
- package/stubs/tailwind-only/react/src/pages/Login.tsx.stub +122 -0
- package/stubs/tailwind-only/react/src/pages/Register.tsx.stub +137 -0
- package/stubs/tailwind-only/react/src/pages/Users.tsx.stub +426 -0
- package/stubs/tailwind-only/react/src/pages/account/layout.tsx.stub +64 -0
- package/stubs/tailwind-only/react/src/pages/account/preferences.tsx.stub +80 -0
- package/stubs/tailwind-only/react/src/pages/account/profile.tsx.stub +67 -0
- package/stubs/tailwind-only/react/src/pages/account/security.tsx.stub +91 -0
- package/stubs/tailwind-only/react/src/style.css.stub +14 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/app-sidebar.svelte.stub +104 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/authenticated-layout.svelte.stub +51 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/header.svelte.stub +66 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/main.svelte.stub +26 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/nav-group.svelte.stub +131 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/nav-user.svelte.stub +104 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/sidebar-data.ts.stub +57 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/theme-toggle.svelte.stub +28 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/top-nav.svelte.stub +99 -0
- package/stubs/tailwind-only/svelte/src/lib/utils.ts.stub +6 -0
- package/stubs/tailwind-only/svelte/src/pages/Dashboard.svelte.stub +192 -0
- package/stubs/tailwind-only/svelte/src/pages/Login.svelte.stub +120 -0
- package/stubs/tailwind-only/svelte/src/pages/Register.svelte.stub +134 -0
- package/stubs/tailwind-only/svelte/src/pages/Users.svelte.stub +293 -0
- package/stubs/tailwind-only/svelte/src/pages/account/Layout.svelte.stub +61 -0
- package/stubs/tailwind-only/svelte/src/pages/account/Preferences.svelte.stub +81 -0
- package/stubs/tailwind-only/svelte/src/pages/account/Profile.svelte.stub +76 -0
- package/stubs/tailwind-only/svelte/src/pages/account/Security.svelte.stub +140 -0
- package/stubs/tailwind-only/svelte/src/style.css.stub +127 -0
- package/stubs/tailwind-only/vue/src/components/layout/AppSidebar.vue.stub +60 -0
- package/stubs/tailwind-only/vue/src/components/layout/AuthenticatedLayout.vue.stub +73 -0
- package/stubs/tailwind-only/vue/src/components/layout/Header.vue.stub +54 -0
- package/stubs/tailwind-only/vue/src/components/layout/Main.vue.stub +22 -0
- package/stubs/tailwind-only/vue/src/components/layout/NavGroup.vue.stub +107 -0
- package/stubs/tailwind-only/vue/src/components/layout/NavUser.vue.stub +104 -0
- package/stubs/tailwind-only/vue/src/components/layout/ThemeToggle.vue.stub +28 -0
- package/stubs/tailwind-only/vue/src/components/layout/TopNav.vue.stub +86 -0
- package/stubs/tailwind-only/vue/src/components/layout/sidebar-data.ts.stub +57 -0
- package/stubs/tailwind-only/vue/src/lib/utils.ts.stub +7 -0
- package/stubs/tailwind-only/vue/src/pages/Dashboard.vue.stub +195 -0
- package/stubs/tailwind-only/vue/src/pages/Login.vue.stub +121 -0
- package/stubs/tailwind-only/vue/src/pages/Register.vue.stub +137 -0
- package/stubs/tailwind-only/vue/src/pages/Users.vue.stub +401 -0
- package/stubs/tailwind-only/vue/src/pages/account/Layout.vue.stub +56 -0
- package/stubs/tailwind-only/vue/src/pages/account/Preferences.vue.stub +81 -0
- package/stubs/tailwind-only/vue/src/pages/account/Profile.vue.stub +69 -0
- package/stubs/tailwind-only/vue/src/pages/account/Security.vue.stub +85 -0
- package/stubs/tailwind-only/vue/src/style.css.stub +26 -0
- package/stubs/themes/corporate/react/src/components/layout/app-sidebar.tsx.stub +74 -0
- package/stubs/themes/corporate/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
- package/stubs/themes/corporate/react/src/pages/Dashboard.tsx.stub +310 -0
- package/stubs/themes/corporate/react/src/pages/Login.tsx.stub +122 -0
- package/stubs/themes/corporate/react/src/pages/Register.tsx.stub +144 -0
- package/stubs/themes/corporate/react/src/style.css.stub +135 -0
- package/stubs/themes/corporate/svelte/src/pages/Dashboard.svelte.stub +271 -0
- package/stubs/themes/corporate/svelte/src/pages/Login.svelte.stub +117 -0
- package/stubs/themes/corporate/svelte/src/pages/Register.svelte.stub +138 -0
- package/stubs/themes/corporate/svelte/src/style.css.stub +134 -0
- package/stubs/themes/corporate/vue/src/pages/Dashboard.vue.stub +325 -0
- package/stubs/themes/corporate/vue/src/pages/Login.vue.stub +118 -0
- package/stubs/themes/corporate/vue/src/pages/Register.vue.stub +139 -0
- package/stubs/themes/corporate/vue/src/style.css.stub +134 -0
- package/stubs/themes/minimal/react/src/components/layout/app-sidebar.tsx.stub +68 -0
- package/stubs/themes/minimal/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
- package/stubs/themes/minimal/react/src/pages/Dashboard.tsx.stub +166 -0
- package/stubs/themes/minimal/react/src/pages/Login.tsx.stub +95 -0
- package/stubs/themes/minimal/react/src/pages/Register.tsx.stub +73 -0
- package/stubs/themes/minimal/react/src/style.css.stub +142 -0
- package/stubs/themes/minimal/svelte/src/pages/Dashboard.svelte.stub +149 -0
- package/stubs/themes/minimal/svelte/src/pages/Login.svelte.stub +90 -0
- package/stubs/themes/minimal/svelte/src/pages/Register.svelte.stub +70 -0
- package/stubs/themes/minimal/svelte/src/style.css.stub +142 -0
- package/stubs/themes/minimal/vue/src/pages/Dashboard.vue.stub +163 -0
- package/stubs/themes/minimal/vue/src/pages/Login.vue.stub +91 -0
- package/stubs/themes/minimal/vue/src/pages/Register.vue.stub +73 -0
- package/stubs/themes/minimal/vue/src/style.css.stub +142 -0
- package/stubs/themes/starter/react/src/components/layout/app-sidebar.tsx.stub +74 -0
- package/stubs/themes/starter/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
- package/stubs/themes/starter/react/src/pages/Dashboard.tsx.stub +236 -0
- package/stubs/themes/starter/react/src/pages/Login.tsx.stub +131 -0
- package/stubs/themes/starter/react/src/pages/Register.tsx.stub +145 -0
- package/stubs/themes/starter/react/src/style.css.stub +141 -0
- package/stubs/themes/starter/svelte/src/pages/Dashboard.svelte.stub +212 -0
- package/stubs/themes/starter/svelte/src/pages/Login.svelte.stub +126 -0
- package/stubs/themes/starter/svelte/src/pages/Register.svelte.stub +139 -0
- package/stubs/themes/starter/svelte/src/style.css.stub +141 -0
- package/stubs/themes/starter/vue/src/pages/Dashboard.vue.stub +228 -0
- package/stubs/themes/starter/vue/src/pages/Login.vue.stub +127 -0
- package/stubs/themes/starter/vue/src/pages/Register.vue.stub +140 -0
- package/stubs/themes/starter/vue/src/style.css.stub +141 -0
- package/stubs/themes/workspace/react/src/components/layout/app-sidebar.tsx.stub +97 -0
- package/stubs/themes/workspace/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
- package/stubs/themes/workspace/react/src/pages/Dashboard.tsx.stub +304 -0
- package/stubs/themes/workspace/react/src/pages/Login.tsx.stub +131 -0
- package/stubs/themes/workspace/react/src/pages/Register.tsx.stub +82 -0
- package/stubs/themes/workspace/react/src/style.css.stub +138 -0
- package/stubs/themes/workspace/svelte/src/pages/Dashboard.svelte.stub +215 -0
- package/stubs/themes/workspace/svelte/src/pages/Login.svelte.stub +124 -0
- package/stubs/themes/workspace/svelte/src/pages/Register.svelte.stub +76 -0
- package/stubs/themes/workspace/svelte/src/style.css.stub +134 -0
- package/stubs/themes/workspace/vue/src/pages/Dashboard.vue.stub +220 -0
- package/stubs/themes/workspace/vue/src/pages/Login.vue.stub +128 -0
- package/stubs/themes/workspace/vue/src/pages/Register.vue.stub +80 -0
- package/stubs/themes/workspace/vue/src/style.css.stub +134 -0
- package/stubs/vue/src/App.vue.stub +2 -1
- package/stubs/vue/src/lib/api.ts.stub +30 -6
- package/stubs/vue/src/main.ts.stub +3 -1
- package/stubs/vue/src/pages/Login.vue.stub +3 -3
- package/stubs/vue/vite.config.ts.stub +20 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* shadcn/ui theme — Minimal
|
|
6
|
+
*
|
|
7
|
+
* Extreme minimalism: zero shadows, hairline borders, sharp corners.
|
|
8
|
+
* Monospace numbers. Compact spacing. Inspired by Minimal.app.
|
|
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.375rem;
|
|
52
|
+
--background: oklch(1 0 0);
|
|
53
|
+
--foreground: oklch(0.145 0.004 285.823);
|
|
54
|
+
--card: oklch(1 0 0);
|
|
55
|
+
--card-foreground: oklch(0.145 0.004 285.823);
|
|
56
|
+
--popover: oklch(1 0 0);
|
|
57
|
+
--popover-foreground: oklch(0.145 0.004 285.823);
|
|
58
|
+
--primary: oklch(0.546 0.245 262.881);
|
|
59
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
60
|
+
--secondary: oklch(0.967 0.001 286.375);
|
|
61
|
+
--secondary-foreground: oklch(0.205 0.006 285.885);
|
|
62
|
+
--muted: oklch(0.967 0.001 286.375);
|
|
63
|
+
--muted-foreground: oklch(0.556 0.014 285.938);
|
|
64
|
+
--accent: oklch(0.967 0.001 286.375);
|
|
65
|
+
--accent-foreground: oklch(0.205 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.935 0.004 286.32);
|
|
69
|
+
--input: oklch(0.935 0.004 286.32);
|
|
70
|
+
--ring: oklch(0.546 0.245 262.881);
|
|
71
|
+
--chart-1: oklch(0.546 0.245 262.881);
|
|
72
|
+
--chart-2: oklch(0.6 0.118 184.714);
|
|
73
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
74
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
75
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
76
|
+
--sidebar: oklch(0.985 0.001 286.375);
|
|
77
|
+
--sidebar-foreground: oklch(0.145 0.004 285.823);
|
|
78
|
+
--sidebar-primary: oklch(0.546 0.245 262.881);
|
|
79
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
80
|
+
--sidebar-accent: oklch(0.967 0.001 286.375);
|
|
81
|
+
--sidebar-accent-foreground: oklch(0.205 0.006 285.885);
|
|
82
|
+
--sidebar-border: oklch(0.935 0.004 286.32);
|
|
83
|
+
--sidebar-ring: oklch(0.546 0.245 262.881);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.dark {
|
|
87
|
+
--background: oklch(0.13 0.004 285.823);
|
|
88
|
+
--foreground: oklch(0.985 0 0);
|
|
89
|
+
--card: oklch(0.155 0.004 285.823);
|
|
90
|
+
--card-foreground: oklch(0.985 0 0);
|
|
91
|
+
--popover: oklch(0.155 0.004 285.823);
|
|
92
|
+
--popover-foreground: oklch(0.985 0 0);
|
|
93
|
+
--primary: oklch(0.623 0.214 262.881);
|
|
94
|
+
--primary-foreground: oklch(0.13 0.004 285.823);
|
|
95
|
+
--secondary: oklch(0.22 0.006 286.033);
|
|
96
|
+
--secondary-foreground: oklch(0.985 0 0);
|
|
97
|
+
--muted: oklch(0.22 0.006 286.033);
|
|
98
|
+
--muted-foreground: oklch(0.63 0.014 286.067);
|
|
99
|
+
--accent: oklch(0.22 0.006 286.033);
|
|
100
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
101
|
+
--destructive: oklch(0.704 0.191 22.216);
|
|
102
|
+
--destructive-foreground: oklch(0.704 0.191 22.216);
|
|
103
|
+
--border: oklch(0.24 0.005 286.033);
|
|
104
|
+
--input: oklch(0.24 0.005 286.033);
|
|
105
|
+
--ring: oklch(0.623 0.214 262.881);
|
|
106
|
+
--chart-1: oklch(0.623 0.214 262.881);
|
|
107
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
108
|
+
--chart-3: oklch(0.769 0.188 70.08);
|
|
109
|
+
--chart-4: oklch(0.627 0.265 303.9);
|
|
110
|
+
--chart-5: oklch(0.645 0.246 16.439);
|
|
111
|
+
--sidebar: oklch(0.14 0.004 285.823);
|
|
112
|
+
--sidebar-foreground: oklch(0.985 0 0);
|
|
113
|
+
--sidebar-primary: oklch(0.623 0.214 262.881);
|
|
114
|
+
--sidebar-primary-foreground: oklch(0.13 0.004 285.823);
|
|
115
|
+
--sidebar-accent: oklch(0.22 0.006 286.033);
|
|
116
|
+
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
117
|
+
--sidebar-border: oklch(0.24 0.005 286.033);
|
|
118
|
+
--sidebar-ring: oklch(0.623 0.214 262.881);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@layer base {
|
|
122
|
+
* {
|
|
123
|
+
@apply border-border;
|
|
124
|
+
}
|
|
125
|
+
body {
|
|
126
|
+
@apply bg-background text-foreground;
|
|
127
|
+
font-feature-settings: "ss01", "ss02", "cv01";
|
|
128
|
+
-webkit-font-smoothing: antialiased;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Monospace tabular figures for numbers */
|
|
133
|
+
.font-mono-num {
|
|
134
|
+
font-variant-numeric: tabular-nums;
|
|
135
|
+
font-feature-settings: "tnum";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@keyframes fadeUp {
|
|
139
|
+
from { opacity: 0; transform: translateY(8px); }
|
|
140
|
+
to { opacity: 1; transform: translateY(0); }
|
|
141
|
+
}
|
|
142
|
+
.animate-fade-up { animation: fadeUp 0.3s ease-out; }
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import AuthenticatedLayout from '@/components/layout/AuthenticatedLayout.vue'
|
|
3
|
+
import Header from '@/components/layout/Header.vue'
|
|
4
|
+
import Main from '@/components/layout/Main.vue'
|
|
5
|
+
import {
|
|
6
|
+
Circle,
|
|
7
|
+
CheckCircle2,
|
|
8
|
+
ArrowUpRight,
|
|
9
|
+
Clock,
|
|
10
|
+
AlertCircle,
|
|
11
|
+
Minus,
|
|
12
|
+
} from 'lucide-vue-next'
|
|
13
|
+
|
|
14
|
+
type Priority = 'urgent' | 'high' | 'medium' | 'low' | 'none'
|
|
15
|
+
type Status = 'done' | 'in-progress' | 'todo' | 'backlog'
|
|
16
|
+
|
|
17
|
+
const props = withDefaults(defineProps<{
|
|
18
|
+
appName?: string
|
|
19
|
+
currentUser?: { id: number; name: string; email: string; role: string } | null
|
|
20
|
+
navigate?: (href: string) => void
|
|
21
|
+
}>(), {
|
|
22
|
+
appName: 'Mantiq',
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const issues: {
|
|
26
|
+
id: string
|
|
27
|
+
title: string
|
|
28
|
+
status: Status
|
|
29
|
+
priority: Priority
|
|
30
|
+
assignee: string
|
|
31
|
+
updated: string
|
|
32
|
+
}[] = [
|
|
33
|
+
{ id: 'MNT-142', title: 'Fix authentication token refresh race condition', status: 'in-progress', priority: 'urgent', assignee: 'AK', updated: '2m' },
|
|
34
|
+
{ id: 'MNT-141', title: 'Add rate limiting to public API endpoints', status: 'todo', priority: 'high', assignee: 'SC', updated: '15m' },
|
|
35
|
+
{ id: 'MNT-140', title: 'Migrate user sessions to Redis store', status: 'in-progress', priority: 'high', assignee: 'AK', updated: '1h' },
|
|
36
|
+
{ id: 'MNT-139', title: 'Update Stripe webhook handler for v2024-12', status: 'todo', priority: 'medium', assignee: 'JL', updated: '2h' },
|
|
37
|
+
{ id: 'MNT-138', title: 'Implement CSV export for analytics dashboard', status: 'done', priority: 'medium', assignee: 'NR', updated: '3h' },
|
|
38
|
+
{ id: 'MNT-137', title: 'Add OpenTelemetry tracing to queue workers', status: 'backlog', priority: 'low', assignee: 'SC', updated: '5h' },
|
|
39
|
+
{ id: 'MNT-136', title: 'Refactor notification preferences into per-channel config', status: 'done', priority: 'medium', assignee: 'AK', updated: '6h' },
|
|
40
|
+
{ id: 'MNT-135', title: 'Set up staging environment with seed data', status: 'backlog', priority: 'low', assignee: 'JL', updated: '1d' },
|
|
41
|
+
{ id: 'MNT-134', title: 'Write integration tests for payment flow', status: 'todo', priority: 'high', assignee: 'NR', updated: '1d' },
|
|
42
|
+
{ id: 'MNT-133', title: 'Audit and update npm dependencies', status: 'backlog', priority: 'none', assignee: 'SC', updated: '2d' },
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
const priorityColors: Record<Priority, string> = {
|
|
46
|
+
urgent: 'bg-red-500',
|
|
47
|
+
high: 'bg-orange-500',
|
|
48
|
+
medium: 'bg-yellow-500',
|
|
49
|
+
low: 'bg-blue-400',
|
|
50
|
+
none: 'bg-muted-foreground/30',
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isPriorityBarActive(priority: Priority, index: number): boolean {
|
|
54
|
+
return (
|
|
55
|
+
(priority === 'urgent' && index <= 3) ||
|
|
56
|
+
(priority === 'high' && index <= 2) ||
|
|
57
|
+
(priority === 'medium' && index <= 1) ||
|
|
58
|
+
(priority === 'low' && index <= 0)
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const doneCount = issues.filter((i) => i.status === 'done').length
|
|
63
|
+
const inProgressCount = issues.filter((i) => i.status === 'in-progress').length
|
|
64
|
+
const todoCount = issues.filter((i) => i.status === 'todo').length
|
|
65
|
+
const urgentCount = issues.filter((i) => i.priority === 'urgent').length
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<template>
|
|
69
|
+
<AuthenticatedLayout
|
|
70
|
+
:current-user="currentUser"
|
|
71
|
+
:app-name="appName"
|
|
72
|
+
:navigate="navigate"
|
|
73
|
+
active-path="/dashboard"
|
|
74
|
+
>
|
|
75
|
+
<Header :navigate="navigate" />
|
|
76
|
+
<Main>
|
|
77
|
+
<div class="space-y-1">
|
|
78
|
+
<!-- Compact header row -->
|
|
79
|
+
<div class="flex items-center justify-between py-3">
|
|
80
|
+
<div class="flex items-center gap-6">
|
|
81
|
+
<h2 class="text-sm font-semibold">My Issues</h2>
|
|
82
|
+
<div class="flex items-center gap-4 text-xs text-muted-foreground">
|
|
83
|
+
<span class="flex items-center gap-1.5">
|
|
84
|
+
<Clock class="h-3 w-3 text-amber-500" />
|
|
85
|
+
{{ inProgressCount }} in progress
|
|
86
|
+
</span>
|
|
87
|
+
<span class="flex items-center gap-1.5">
|
|
88
|
+
<Circle class="h-3 w-3" />
|
|
89
|
+
{{ todoCount }} todo
|
|
90
|
+
</span>
|
|
91
|
+
<span class="flex items-center gap-1.5">
|
|
92
|
+
<CheckCircle2 class="h-3 w-3 text-primary" />
|
|
93
|
+
{{ doneCount }} done
|
|
94
|
+
</span>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="flex items-center gap-2">
|
|
98
|
+
<kbd class="hidden sm:inline-flex items-center gap-0.5 rounded border bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground">
|
|
99
|
+
<span class="text-xs">⌘</span>K
|
|
100
|
+
</kbd>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<!-- Issue list — no cards, just rows -->
|
|
105
|
+
<div class="border-t">
|
|
106
|
+
<div
|
|
107
|
+
v-for="issue in issues"
|
|
108
|
+
:key="issue.id"
|
|
109
|
+
class="group flex items-center gap-3 border-b px-1 py-2 transition-colors hover:bg-muted/50 cursor-default"
|
|
110
|
+
>
|
|
111
|
+
<!-- Priority indicator -->
|
|
112
|
+
<div class="flex items-center gap-0.5" :title="issue.priority">
|
|
113
|
+
<div
|
|
114
|
+
v-for="i in 4"
|
|
115
|
+
:key="i"
|
|
116
|
+
:class="[
|
|
117
|
+
'h-2.5 w-[3px] rounded-[1px]',
|
|
118
|
+
isPriorityBarActive(issue.priority, i - 1)
|
|
119
|
+
? priorityColors[issue.priority]
|
|
120
|
+
: 'bg-muted-foreground/15',
|
|
121
|
+
]"
|
|
122
|
+
/>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<!-- Status icon -->
|
|
126
|
+
<CheckCircle2 v-if="issue.status === 'done'" class="h-3.5 w-3.5 text-primary" />
|
|
127
|
+
<Clock v-else-if="issue.status === 'in-progress'" class="h-3.5 w-3.5 text-amber-500" />
|
|
128
|
+
<Circle v-else-if="issue.status === 'todo'" class="h-3.5 w-3.5 text-muted-foreground" />
|
|
129
|
+
<Minus v-else class="h-3.5 w-3.5 text-muted-foreground/50" />
|
|
130
|
+
|
|
131
|
+
<span class="font-mono-num text-xs text-muted-foreground w-16 shrink-0">
|
|
132
|
+
{{ issue.id }}
|
|
133
|
+
</span>
|
|
134
|
+
<span
|
|
135
|
+
:class="[
|
|
136
|
+
'flex-1 text-sm truncate',
|
|
137
|
+
issue.status === 'done' ? 'line-through text-muted-foreground' : '',
|
|
138
|
+
]"
|
|
139
|
+
>
|
|
140
|
+
{{ issue.title }}
|
|
141
|
+
</span>
|
|
142
|
+
<div class="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-muted text-[10px] font-medium text-muted-foreground">
|
|
143
|
+
{{ issue.assignee }}
|
|
144
|
+
</div>
|
|
145
|
+
<span class="font-mono-num text-xs text-muted-foreground w-8 text-right shrink-0">
|
|
146
|
+
{{ issue.updated }}
|
|
147
|
+
</span>
|
|
148
|
+
<ArrowUpRight class="h-3.5 w-3.5 text-muted-foreground/0 group-hover:text-muted-foreground transition-colors shrink-0" />
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<!-- Bottom counts -->
|
|
153
|
+
<div class="flex items-center justify-between pt-2 text-xs text-muted-foreground">
|
|
154
|
+
<span>{{ issues.length }} issues</span>
|
|
155
|
+
<span class="flex items-center gap-1">
|
|
156
|
+
<AlertCircle class="h-3 w-3" />
|
|
157
|
+
{{ urgentCount }} urgent
|
|
158
|
+
</span>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
</Main>
|
|
162
|
+
</AuthenticatedLayout>
|
|
163
|
+
</template>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import { post } from '@/lib/api'
|
|
4
|
+
import { Button } from '@/components/ui/button'
|
|
5
|
+
import { Input } from '@/components/ui/input'
|
|
6
|
+
import { Label } from '@/components/ui/label'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(defineProps<{
|
|
9
|
+
appName?: string
|
|
10
|
+
navigate?: (href: string) => void
|
|
11
|
+
}>(), {
|
|
12
|
+
appName: 'Mantiq',
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const email = ref('')
|
|
16
|
+
const password = ref('')
|
|
17
|
+
const error = ref('')
|
|
18
|
+
const loading = ref(false)
|
|
19
|
+
|
|
20
|
+
async function handleSubmit() {
|
|
21
|
+
error.value = ''
|
|
22
|
+
loading.value = true
|
|
23
|
+
const { ok, data } = await post('/login', { email: email.value, password: password.value })
|
|
24
|
+
if (ok) props.navigate?.('/dashboard')
|
|
25
|
+
else error.value = data?.error ?? 'Invalid credentials.'
|
|
26
|
+
loading.value = false
|
|
27
|
+
}
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<div class="flex min-h-screen flex-col items-center justify-center bg-background px-4">
|
|
32
|
+
<div class="w-full max-w-[320px]">
|
|
33
|
+
<!-- Logo — just text, minimal -->
|
|
34
|
+
<div class="mb-10">
|
|
35
|
+
<div class="flex items-center gap-2">
|
|
36
|
+
<div class="flex h-7 w-7 items-center justify-center rounded bg-foreground text-background text-xs font-bold">
|
|
37
|
+
M
|
|
38
|
+
</div>
|
|
39
|
+
<span class="text-sm font-semibold tracking-tight">{{ appName }}</span>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<h1 class="text-sm font-medium mb-6">Sign in to continue</h1>
|
|
44
|
+
|
|
45
|
+
<div v-if="error" class="mb-4 text-sm text-destructive">
|
|
46
|
+
{{ error }}
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<form class="space-y-3" @submit.prevent="handleSubmit">
|
|
50
|
+
<div class="space-y-1.5">
|
|
51
|
+
<Label for="email" class="text-xs text-muted-foreground">Email</Label>
|
|
52
|
+
<Input
|
|
53
|
+
id="email"
|
|
54
|
+
v-model="email"
|
|
55
|
+
type="email"
|
|
56
|
+
required
|
|
57
|
+
placeholder="you@example.com"
|
|
58
|
+
autocomplete="email"
|
|
59
|
+
class="h-8 text-sm"
|
|
60
|
+
/>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="space-y-1.5">
|
|
63
|
+
<Label for="password" class="text-xs text-muted-foreground">Password</Label>
|
|
64
|
+
<Input
|
|
65
|
+
id="password"
|
|
66
|
+
v-model="password"
|
|
67
|
+
type="password"
|
|
68
|
+
required
|
|
69
|
+
placeholder="••••••••"
|
|
70
|
+
autocomplete="current-password"
|
|
71
|
+
class="h-8 text-sm"
|
|
72
|
+
/>
|
|
73
|
+
</div>
|
|
74
|
+
<Button type="submit" class="w-full h-8 text-sm" :disabled="loading">
|
|
75
|
+
{{ loading ? 'Signing in\u2026' : 'Continue' }}
|
|
76
|
+
</Button>
|
|
77
|
+
</form>
|
|
78
|
+
|
|
79
|
+
<p class="mt-4 text-xs text-muted-foreground">
|
|
80
|
+
No account?{{ ' ' }}
|
|
81
|
+
<button
|
|
82
|
+
type="button"
|
|
83
|
+
class="text-foreground hover:underline underline-offset-2"
|
|
84
|
+
@click="navigate?.('/register')"
|
|
85
|
+
>
|
|
86
|
+
Create one
|
|
87
|
+
</button>
|
|
88
|
+
</p>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</template>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import { post } from '@/lib/api'
|
|
4
|
+
import { Button } from '@/components/ui/button'
|
|
5
|
+
import { Input } from '@/components/ui/input'
|
|
6
|
+
import { Label } from '@/components/ui/label'
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(defineProps<{
|
|
9
|
+
appName?: string
|
|
10
|
+
navigate?: (href: string) => void
|
|
11
|
+
}>(), {
|
|
12
|
+
appName: 'Mantiq',
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const name = ref('')
|
|
16
|
+
const email = ref('')
|
|
17
|
+
const password = ref('')
|
|
18
|
+
const error = ref('')
|
|
19
|
+
const loading = ref(false)
|
|
20
|
+
|
|
21
|
+
async function handleSubmit() {
|
|
22
|
+
error.value = ''
|
|
23
|
+
loading.value = true
|
|
24
|
+
const { ok, data } = await post('/register', { name: name.value, email: email.value, password: password.value })
|
|
25
|
+
if (ok) props.navigate?.('/dashboard')
|
|
26
|
+
else error.value = data?.error ?? 'Registration failed.'
|
|
27
|
+
loading.value = false
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<div class="flex min-h-screen flex-col items-center justify-center bg-background px-4">
|
|
33
|
+
<div class="w-full max-w-[320px]">
|
|
34
|
+
<div class="mb-10">
|
|
35
|
+
<div class="flex items-center gap-2">
|
|
36
|
+
<div class="flex h-7 w-7 items-center justify-center rounded bg-foreground text-background text-xs font-bold">
|
|
37
|
+
M
|
|
38
|
+
</div>
|
|
39
|
+
<span class="text-sm font-semibold tracking-tight">{{ appName }}</span>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<h1 class="text-sm font-medium mb-6">Create your account</h1>
|
|
44
|
+
|
|
45
|
+
<div v-if="error" class="mb-4 text-sm text-destructive">
|
|
46
|
+
{{ error }}
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<form class="space-y-3" @submit.prevent="handleSubmit">
|
|
50
|
+
<div class="space-y-1.5">
|
|
51
|
+
<Label for="name" class="text-xs text-muted-foreground">Name</Label>
|
|
52
|
+
<Input id="name" v-model="name" required placeholder="Your name" class="h-8 text-sm" />
|
|
53
|
+
</div>
|
|
54
|
+
<div class="space-y-1.5">
|
|
55
|
+
<Label for="email" class="text-xs text-muted-foreground">Email</Label>
|
|
56
|
+
<Input id="email" v-model="email" type="email" required placeholder="you@example.com" autocomplete="email" class="h-8 text-sm" />
|
|
57
|
+
</div>
|
|
58
|
+
<div class="space-y-1.5">
|
|
59
|
+
<Label for="password" class="text-xs text-muted-foreground">Password</Label>
|
|
60
|
+
<Input id="password" v-model="password" type="password" required placeholder="••••••••" class="h-8 text-sm" />
|
|
61
|
+
</div>
|
|
62
|
+
<Button type="submit" class="w-full h-8 text-sm" :disabled="loading">
|
|
63
|
+
{{ loading ? 'Creating\u2026' : 'Create account' }}
|
|
64
|
+
</Button>
|
|
65
|
+
</form>
|
|
66
|
+
|
|
67
|
+
<p class="mt-4 text-xs text-muted-foreground">
|
|
68
|
+
Already have an account?{{ ' ' }}
|
|
69
|
+
<button type="button" class="text-foreground hover:underline underline-offset-2" @click="navigate?.('/login')">Sign in</button>
|
|
70
|
+
</p>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</template>
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* shadcn/ui theme — Minimal
|
|
6
|
+
*
|
|
7
|
+
* Extreme minimalism: zero shadows, hairline borders, sharp corners.
|
|
8
|
+
* Monospace numbers. Compact spacing. Inspired by Minimal.app.
|
|
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.375rem;
|
|
52
|
+
--background: oklch(1 0 0);
|
|
53
|
+
--foreground: oklch(0.145 0.004 285.823);
|
|
54
|
+
--card: oklch(1 0 0);
|
|
55
|
+
--card-foreground: oklch(0.145 0.004 285.823);
|
|
56
|
+
--popover: oklch(1 0 0);
|
|
57
|
+
--popover-foreground: oklch(0.145 0.004 285.823);
|
|
58
|
+
--primary: oklch(0.546 0.245 262.881);
|
|
59
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
60
|
+
--secondary: oklch(0.967 0.001 286.375);
|
|
61
|
+
--secondary-foreground: oklch(0.205 0.006 285.885);
|
|
62
|
+
--muted: oklch(0.967 0.001 286.375);
|
|
63
|
+
--muted-foreground: oklch(0.556 0.014 285.938);
|
|
64
|
+
--accent: oklch(0.967 0.001 286.375);
|
|
65
|
+
--accent-foreground: oklch(0.205 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.935 0.004 286.32);
|
|
69
|
+
--input: oklch(0.935 0.004 286.32);
|
|
70
|
+
--ring: oklch(0.546 0.245 262.881);
|
|
71
|
+
--chart-1: oklch(0.546 0.245 262.881);
|
|
72
|
+
--chart-2: oklch(0.6 0.118 184.714);
|
|
73
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
74
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
75
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
76
|
+
--sidebar: oklch(0.985 0.001 286.375);
|
|
77
|
+
--sidebar-foreground: oklch(0.145 0.004 285.823);
|
|
78
|
+
--sidebar-primary: oklch(0.546 0.245 262.881);
|
|
79
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
80
|
+
--sidebar-accent: oklch(0.967 0.001 286.375);
|
|
81
|
+
--sidebar-accent-foreground: oklch(0.205 0.006 285.885);
|
|
82
|
+
--sidebar-border: oklch(0.935 0.004 286.32);
|
|
83
|
+
--sidebar-ring: oklch(0.546 0.245 262.881);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.dark {
|
|
87
|
+
--background: oklch(0.13 0.004 285.823);
|
|
88
|
+
--foreground: oklch(0.985 0 0);
|
|
89
|
+
--card: oklch(0.155 0.004 285.823);
|
|
90
|
+
--card-foreground: oklch(0.985 0 0);
|
|
91
|
+
--popover: oklch(0.155 0.004 285.823);
|
|
92
|
+
--popover-foreground: oklch(0.985 0 0);
|
|
93
|
+
--primary: oklch(0.623 0.214 262.881);
|
|
94
|
+
--primary-foreground: oklch(0.13 0.004 285.823);
|
|
95
|
+
--secondary: oklch(0.22 0.006 286.033);
|
|
96
|
+
--secondary-foreground: oklch(0.985 0 0);
|
|
97
|
+
--muted: oklch(0.22 0.006 286.033);
|
|
98
|
+
--muted-foreground: oklch(0.63 0.014 286.067);
|
|
99
|
+
--accent: oklch(0.22 0.006 286.033);
|
|
100
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
101
|
+
--destructive: oklch(0.704 0.191 22.216);
|
|
102
|
+
--destructive-foreground: oklch(0.704 0.191 22.216);
|
|
103
|
+
--border: oklch(0.24 0.005 286.033);
|
|
104
|
+
--input: oklch(0.24 0.005 286.033);
|
|
105
|
+
--ring: oklch(0.623 0.214 262.881);
|
|
106
|
+
--chart-1: oklch(0.623 0.214 262.881);
|
|
107
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
108
|
+
--chart-3: oklch(0.769 0.188 70.08);
|
|
109
|
+
--chart-4: oklch(0.627 0.265 303.9);
|
|
110
|
+
--chart-5: oklch(0.645 0.246 16.439);
|
|
111
|
+
--sidebar: oklch(0.14 0.004 285.823);
|
|
112
|
+
--sidebar-foreground: oklch(0.985 0 0);
|
|
113
|
+
--sidebar-primary: oklch(0.623 0.214 262.881);
|
|
114
|
+
--sidebar-primary-foreground: oklch(0.13 0.004 285.823);
|
|
115
|
+
--sidebar-accent: oklch(0.22 0.006 286.033);
|
|
116
|
+
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
117
|
+
--sidebar-border: oklch(0.24 0.005 286.033);
|
|
118
|
+
--sidebar-ring: oklch(0.623 0.214 262.881);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@layer base {
|
|
122
|
+
* {
|
|
123
|
+
@apply border-border;
|
|
124
|
+
}
|
|
125
|
+
body {
|
|
126
|
+
@apply bg-background text-foreground;
|
|
127
|
+
font-feature-settings: "ss01", "ss02", "cv01";
|
|
128
|
+
-webkit-font-smoothing: antialiased;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Monospace tabular figures for numbers */
|
|
133
|
+
.font-mono-num {
|
|
134
|
+
font-variant-numeric: tabular-nums;
|
|
135
|
+
font-feature-settings: "tnum";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@keyframes fadeUp {
|
|
139
|
+
from { opacity: 0; transform: translateY(8px); }
|
|
140
|
+
to { opacity: 1; transform: translateY(0); }
|
|
141
|
+
}
|
|
142
|
+
.animate-fade-up { animation: fadeUp 0.3s ease-out; }
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Sidebar,
|
|
3
|
+
SidebarContent,
|
|
4
|
+
SidebarFooter,
|
|
5
|
+
SidebarHeader,
|
|
6
|
+
SidebarMenu,
|
|
7
|
+
SidebarMenuButton,
|
|
8
|
+
SidebarMenuItem,
|
|
9
|
+
SidebarRail,
|
|
10
|
+
} from '@/components/ui/sidebar'
|
|
11
|
+
import { NavGroup } from './nav-group'
|
|
12
|
+
import { NavUser, type NavUserProps } from './nav-user'
|
|
13
|
+
import { sidebarData } from './sidebar-data'
|
|
14
|
+
import { Command } from 'lucide-react'
|
|
15
|
+
|
|
16
|
+
export interface AppSidebarProps {
|
|
17
|
+
user: NavUserProps['user']
|
|
18
|
+
appName: string
|
|
19
|
+
activePath: string
|
|
20
|
+
navigate: (href: string) => void
|
|
21
|
+
onLogout: () => void
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function AppSidebar({
|
|
25
|
+
user,
|
|
26
|
+
appName,
|
|
27
|
+
activePath,
|
|
28
|
+
navigate,
|
|
29
|
+
onLogout,
|
|
30
|
+
}: AppSidebarProps) {
|
|
31
|
+
return (
|
|
32
|
+
<Sidebar variant="inset" collapsible="icon">
|
|
33
|
+
<SidebarHeader>
|
|
34
|
+
<SidebarMenu>
|
|
35
|
+
<SidebarMenuItem>
|
|
36
|
+
<SidebarMenuButton
|
|
37
|
+
size="lg"
|
|
38
|
+
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
|
39
|
+
onClick={() => navigate('/dashboard')}
|
|
40
|
+
tooltip={appName}
|
|
41
|
+
>
|
|
42
|
+
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
|
|
43
|
+
<Command className="size-4" />
|
|
44
|
+
</div>
|
|
45
|
+
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
46
|
+
<span className="truncate font-semibold">{appName}</span>
|
|
47
|
+
<span className="truncate text-xs text-muted-foreground">
|
|
48
|
+
Admin Panel
|
|
49
|
+
</span>
|
|
50
|
+
</div>
|
|
51
|
+
</SidebarMenuButton>
|
|
52
|
+
</SidebarMenuItem>
|
|
53
|
+
</SidebarMenu>
|
|
54
|
+
</SidebarHeader>
|
|
55
|
+
|
|
56
|
+
<SidebarContent>
|
|
57
|
+
{sidebarData.map((group) => (
|
|
58
|
+
<NavGroup
|
|
59
|
+
key={group.title}
|
|
60
|
+
group={group}
|
|
61
|
+
activePath={activePath}
|
|
62
|
+
navigate={navigate}
|
|
63
|
+
/>
|
|
64
|
+
))}
|
|
65
|
+
</SidebarContent>
|
|
66
|
+
|
|
67
|
+
<SidebarFooter>
|
|
68
|
+
<NavUser user={user} navigate={navigate} onLogout={onLogout} />
|
|
69
|
+
</SidebarFooter>
|
|
70
|
+
|
|
71
|
+
<SidebarRail />
|
|
72
|
+
</Sidebar>
|
|
73
|
+
)
|
|
74
|
+
}
|