create-kuckit-app 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/package.json +1 -1
  2. package/templates/base/apps/web/package.json +13 -0
  3. package/templates/base/apps/web/src/components/KuckitModuleRoute.tsx +47 -10
  4. package/templates/base/apps/web/src/components/dashboard/app-sidebar.tsx +120 -0
  5. package/templates/base/apps/web/src/components/dashboard/dashboard-layout.tsx +46 -0
  6. package/templates/base/apps/web/src/components/dashboard/dashboard-overview.tsx +24 -0
  7. package/templates/base/apps/web/src/components/dashboard/index.ts +2 -0
  8. package/templates/base/apps/web/src/components/dashboard/nav-user.tsx +77 -0
  9. package/templates/base/apps/web/src/components/ui/avatar.tsx +39 -0
  10. package/templates/base/apps/web/src/components/ui/breadcrumb.tsx +102 -0
  11. package/templates/base/apps/web/src/components/ui/collapsible.tsx +21 -0
  12. package/templates/base/apps/web/src/components/ui/separator.tsx +26 -0
  13. package/templates/base/apps/web/src/components/ui/sheet.tsx +130 -0
  14. package/templates/base/apps/web/src/components/ui/sidebar.tsx +694 -0
  15. package/templates/base/apps/web/src/components/ui/skeleton.tsx +13 -0
  16. package/templates/base/apps/web/src/components/ui/tooltip.tsx +55 -0
  17. package/templates/base/apps/web/src/hooks/use-mobile.ts +19 -0
  18. package/templates/base/apps/web/src/index.css +133 -0
  19. package/templates/base/apps/web/src/lib/utils.ts +6 -0
  20. package/templates/base/apps/web/src/main.tsx +1 -0
  21. package/templates/base/apps/web/src/providers/KuckitProvider.tsx +1 -25
  22. package/templates/base/apps/web/src/routes/dashboard/$.tsx +9 -0
  23. package/templates/base/apps/web/src/routes/dashboard/index.tsx +6 -0
  24. package/templates/base/apps/web/src/routes/dashboard.tsx +25 -0
  25. package/templates/base/apps/web/vite.config.ts +5 -4
  26. package/templates/base/packages/items-module/package.json +4 -0
  27. package/templates/base/packages/items-module/src/ui/index.ts +1 -0
  28. package/templates/base/apps/web/src/lib/kuckit-router.ts +0 -42
@@ -0,0 +1,55 @@
1
+ import * as React from 'react'
2
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip'
3
+
4
+ import { cn } from '@/lib/utils'
5
+
6
+ function TooltipProvider({
7
+ delayDuration = 0,
8
+ ...props
9
+ }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
10
+ return (
11
+ <TooltipPrimitive.Provider
12
+ data-slot="tooltip-provider"
13
+ delayDuration={delayDuration}
14
+ {...props}
15
+ />
16
+ )
17
+ }
18
+
19
+ function Tooltip({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
20
+ return (
21
+ <TooltipProvider>
22
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
23
+ </TooltipProvider>
24
+ )
25
+ }
26
+
27
+ function TooltipTrigger({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
28
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
29
+ }
30
+
31
+ function TooltipContent({
32
+ className,
33
+ sideOffset = 0,
34
+ children,
35
+ ...props
36
+ }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
37
+ return (
38
+ <TooltipPrimitive.Portal>
39
+ <TooltipPrimitive.Content
40
+ data-slot="tooltip-content"
41
+ sideOffset={sideOffset}
42
+ className={cn(
43
+ 'bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance',
44
+ className
45
+ )}
46
+ {...props}
47
+ >
48
+ {children}
49
+ <TooltipPrimitive.Arrow className="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
50
+ </TooltipPrimitive.Content>
51
+ </TooltipPrimitive.Portal>
52
+ )
53
+ }
54
+
55
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
@@ -0,0 +1,19 @@
1
+ import * as React from 'react'
2
+
3
+ const MOBILE_BREAKPOINT = 768
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
7
+
8
+ React.useEffect(() => {
9
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
10
+ const onChange = () => {
11
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
12
+ }
13
+ mql.addEventListener('change', onChange)
14
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
15
+ return () => mql.removeEventListener('change', onChange)
16
+ }, [])
17
+
18
+ return !!isMobile
19
+ }
@@ -0,0 +1,133 @@
1
+ @import "tailwindcss";
2
+
3
+ @custom-variant dark (&:where(.dark, .dark *));
4
+
5
+ @theme {
6
+ --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif,
7
+ "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
8
+ }
9
+
10
+ html,
11
+ body {
12
+ @apply bg-white dark:bg-gray-950;
13
+
14
+ @media (prefers-color-scheme: dark) {
15
+ color-scheme: dark;
16
+ }
17
+ }
18
+
19
+ :root {
20
+ --radius: 0.625rem;
21
+ --background: oklch(1 0 0);
22
+ --foreground: oklch(0.145 0 0);
23
+ --card: oklch(1 0 0);
24
+ --card-foreground: oklch(0.145 0 0);
25
+ --popover: oklch(1 0 0);
26
+ --popover-foreground: oklch(0.145 0 0);
27
+ --primary: oklch(0.205 0 0);
28
+ --primary-foreground: oklch(0.985 0 0);
29
+ --secondary: oklch(0.97 0 0);
30
+ --secondary-foreground: oklch(0.205 0 0);
31
+ --muted: oklch(0.97 0 0);
32
+ --muted-foreground: oklch(0.556 0 0);
33
+ --accent: oklch(0.97 0 0);
34
+ --accent-foreground: oklch(0.205 0 0);
35
+ --destructive: oklch(0.577 0.245 27.325);
36
+ --border: oklch(0.922 0 0);
37
+ --input: oklch(0.922 0 0);
38
+ --ring: oklch(0.708 0 0);
39
+ --chart-1: oklch(0.646 0.222 41.116);
40
+ --chart-2: oklch(0.6 0.118 184.704);
41
+ --chart-3: oklch(0.398 0.07 227.392);
42
+ --chart-4: oklch(0.828 0.189 84.429);
43
+ --chart-5: oklch(0.769 0.188 70.08);
44
+ --sidebar: oklch(0.985 0 0);
45
+ --sidebar-foreground: oklch(0.145 0 0);
46
+ --sidebar-primary: oklch(0.205 0 0);
47
+ --sidebar-primary-foreground: oklch(0.985 0 0);
48
+ --sidebar-accent: oklch(0.97 0 0);
49
+ --sidebar-accent-foreground: oklch(0.205 0 0);
50
+ --sidebar-border: oklch(0.922 0 0);
51
+ --sidebar-ring: oklch(0.708 0 0);
52
+ }
53
+
54
+ .dark {
55
+ --background: oklch(0.145 0 0);
56
+ --foreground: oklch(0.985 0 0);
57
+ --card: oklch(0.205 0 0);
58
+ --card-foreground: oklch(0.985 0 0);
59
+ --popover: oklch(0.205 0 0);
60
+ --popover-foreground: oklch(0.985 0 0);
61
+ --primary: oklch(0.922 0 0);
62
+ --primary-foreground: oklch(0.205 0 0);
63
+ --secondary: oklch(0.269 0 0);
64
+ --secondary-foreground: oklch(0.985 0 0);
65
+ --muted: oklch(0.269 0 0);
66
+ --muted-foreground: oklch(0.708 0 0);
67
+ --accent: oklch(0.269 0 0);
68
+ --accent-foreground: oklch(0.985 0 0);
69
+ --destructive: oklch(0.704 0.191 22.216);
70
+ --border: oklch(1 0 0 / 10%);
71
+ --input: oklch(1 0 0 / 15%);
72
+ --ring: oklch(0.556 0 0);
73
+ --chart-1: oklch(0.488 0.243 264.376);
74
+ --chart-2: oklch(0.696 0.17 162.48);
75
+ --chart-3: oklch(0.769 0.188 70.08);
76
+ --chart-4: oklch(0.627 0.265 303.9);
77
+ --chart-5: oklch(0.645 0.246 16.439);
78
+ --sidebar: oklch(0.205 0 0);
79
+ --sidebar-foreground: oklch(0.985 0 0);
80
+ --sidebar-primary: oklch(0.488 0.243 264.376);
81
+ --sidebar-primary-foreground: oklch(0.985 0 0);
82
+ --sidebar-accent: oklch(0.269 0 0);
83
+ --sidebar-accent-foreground: oklch(0.985 0 0);
84
+ --sidebar-border: oklch(1 0 0 / 10%);
85
+ --sidebar-ring: oklch(0.556 0 0);
86
+ }
87
+
88
+ @theme inline {
89
+ --radius-sm: calc(var(--radius) - 4px);
90
+ --radius-md: calc(var(--radius) - 2px);
91
+ --radius-lg: var(--radius);
92
+ --radius-xl: calc(var(--radius) + 4px);
93
+ --color-background: var(--background);
94
+ --color-foreground: var(--foreground);
95
+ --color-card: var(--card);
96
+ --color-card-foreground: var(--card-foreground);
97
+ --color-popover: var(--popover);
98
+ --color-popover-foreground: var(--popover-foreground);
99
+ --color-primary: var(--primary);
100
+ --color-primary-foreground: var(--primary-foreground);
101
+ --color-secondary: var(--secondary);
102
+ --color-secondary-foreground: var(--secondary-foreground);
103
+ --color-muted: var(--muted);
104
+ --color-muted-foreground: var(--muted-foreground);
105
+ --color-accent: var(--accent);
106
+ --color-accent-foreground: var(--accent-foreground);
107
+ --color-destructive: var(--destructive);
108
+ --color-border: var(--border);
109
+ --color-input: var(--input);
110
+ --color-ring: var(--ring);
111
+ --color-chart-1: var(--chart-1);
112
+ --color-chart-2: var(--chart-2);
113
+ --color-chart-3: var(--chart-3);
114
+ --color-chart-4: var(--chart-4);
115
+ --color-chart-5: var(--chart-5);
116
+ --color-sidebar: var(--sidebar);
117
+ --color-sidebar-foreground: var(--sidebar-foreground);
118
+ --color-sidebar-primary: var(--sidebar-primary);
119
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
120
+ --color-sidebar-accent: var(--sidebar-accent);
121
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
122
+ --color-sidebar-border: var(--sidebar-border);
123
+ --color-sidebar-ring: var(--sidebar-ring);
124
+ }
125
+
126
+ @layer base {
127
+ * {
128
+ @apply border-border outline-ring/50;
129
+ }
130
+ body {
131
+ @apply bg-background text-foreground;
132
+ }
133
+ }
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from 'clsx'
2
+ import { twMerge } from 'tailwind-merge'
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -3,6 +3,7 @@ import ReactDOM from 'react-dom/client'
3
3
  import { routeTree } from './routeTree.gen'
4
4
  import { ServicesProvider } from './providers/ServicesProvider'
5
5
  import { KuckitProvider } from './providers/KuckitProvider'
6
+ import './index.css'
6
7
 
7
8
  declare module '@tanstack/react-router' {
8
9
  interface Register {
@@ -1,10 +1,5 @@
1
1
  import { createContext, useContext, useEffect, useState, useMemo, type ReactNode } from 'react'
2
- import {
3
- RouterProvider,
4
- createRouter,
5
- createRoute,
6
- type RouteComponent,
7
- } from '@tanstack/react-router'
2
+ import { RouterProvider, createRouter } from '@tanstack/react-router'
8
3
  import {
9
4
  loadKuckitClientModules,
10
5
  KuckitNavProvider,
@@ -16,7 +11,6 @@ import {
16
11
  type SlotRegistry,
17
12
  } from '@kuckit/sdk-react'
18
13
  import { routeTree } from '../routeTree.gen'
19
- import { Route as rootRoute } from '../routes/__root'
20
14
  import { useServices } from './ServicesProvider'
21
15
  import { getClientModuleSpecs } from '../modules.client'
22
16
 
@@ -81,26 +75,8 @@ export function KuckitProvider({ children }: KuckitProviderProps) {
81
75
  }
82
76
  }, [orpc, queryClient])
83
77
 
84
- // Build router with module routes
85
78
  const router = useMemo(() => {
86
79
  if (!loadResult) return null
87
-
88
- const moduleRouteDefs = loadResult.routeRegistry.getAll()
89
- const moduleRoutes = moduleRouteDefs.map((routeDef) =>
90
- createRoute({
91
- getParentRoute: () => rootRoute,
92
- path: routeDef.path,
93
- component: routeDef.component as RouteComponent,
94
- })
95
- )
96
-
97
- if (moduleRoutes.length > 0) {
98
- console.log(
99
- `Loaded ${moduleRoutes.length} module routes:`,
100
- moduleRouteDefs.map((r) => r.path)
101
- )
102
- }
103
-
104
80
  return createRouter({
105
81
  routeTree,
106
82
  defaultPreload: 'intent',
@@ -0,0 +1,9 @@
1
+ import { createFileRoute } from '@tanstack/react-router'
2
+ import { KuckitModuleRoute } from '@/components/KuckitModuleRoute'
3
+
4
+ /**
5
+ * Catch-all route for KuckitModule routes under /dashboard.
6
+ */
7
+ export const Route = createFileRoute('/dashboard/$')({
8
+ component: KuckitModuleRoute,
9
+ })
@@ -0,0 +1,6 @@
1
+ import { createFileRoute } from '@tanstack/react-router'
2
+ import { DashboardOverview } from '@/components/dashboard/dashboard-overview'
3
+
4
+ export const Route = createFileRoute('/dashboard/')({
5
+ component: DashboardOverview,
6
+ })
@@ -0,0 +1,25 @@
1
+ import { createFileRoute, Outlet, redirect } from '@tanstack/react-router'
2
+ import { DashboardLayout } from '@/components/dashboard/dashboard-layout'
3
+ import { createAuthClientService } from '../services/auth-client'
4
+
5
+ export const Route = createFileRoute('/dashboard')({
6
+ beforeLoad: async () => {
7
+ const authClient = createAuthClientService()
8
+ const session = await authClient.getSession()
9
+ if (!session.data) {
10
+ throw redirect({
11
+ to: '/login',
12
+ })
13
+ }
14
+ return { session }
15
+ },
16
+ component: DashboardLayoutRoute,
17
+ })
18
+
19
+ function DashboardLayoutRoute() {
20
+ return (
21
+ <DashboardLayout>
22
+ <Outlet />
23
+ </DashboardLayout>
24
+ )
25
+ }
@@ -1,10 +1,11 @@
1
- import { defineConfig } from 'vite'
2
- import react from '@vitejs/plugin-react'
1
+ import tailwindcss from '@tailwindcss/vite'
3
2
  import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
4
- import path from 'path'
3
+ import react from '@vitejs/plugin-react'
4
+ import path from 'node:path'
5
+ import { defineConfig } from 'vite'
5
6
 
6
7
  export default defineConfig({
7
- plugins: [TanStackRouterVite(), react()],
8
+ plugins: [tailwindcss(), TanStackRouterVite(), react()],
8
9
  resolve: {
9
10
  alias: {
10
11
  '@': path.resolve(__dirname, './src'),
@@ -13,6 +13,10 @@
13
13
  "./client": {
14
14
  "types": "./src/client-module.ts",
15
15
  "default": "./src/client-module.ts"
16
+ },
17
+ "./ui": {
18
+ "types": "./src/ui/index.ts",
19
+ "default": "./src/ui/index.ts"
16
20
  }
17
21
  },
18
22
  "peerDependencies": {
@@ -0,0 +1 @@
1
+ export { ItemsPage } from './ItemsPage'
@@ -1,42 +0,0 @@
1
- import { createRoute, type AnyRoute, type RouteComponent } from '@tanstack/react-router'
2
- import type { QueryClient } from '@tanstack/react-query'
3
- import type { RouteRegistry, RouteDefinition } from '@kuckit/sdk-react'
4
- import type { ORPCUtils } from '../services/types'
5
-
6
- export interface KuckitRouterContext {
7
- orpc: ORPCUtils
8
- queryClient: QueryClient
9
- }
10
-
11
- /**
12
- * Build TanStack Router routes from a RouteRegistry
13
- */
14
- export function buildModuleRoutes(routeRegistry: RouteRegistry, rootRoute: AnyRoute): AnyRoute[] {
15
- const routes = routeRegistry.getAll()
16
- const routeMap = new Map<string, AnyRoute>()
17
-
18
- for (const routeDef of routes) {
19
- const route = createModuleRoute(routeDef, rootRoute)
20
- routeMap.set(routeDef.id, route)
21
- }
22
-
23
- const topLevelRoutes = routes
24
- .filter((r) => !r.parentRouteId || r.parentRouteId === '__root__')
25
- .map((r) => routeMap.get(r.id)!)
26
- .filter(Boolean)
27
-
28
- return topLevelRoutes
29
- }
30
-
31
- function createModuleRoute(routeDef: RouteDefinition, parentRoute: AnyRoute): AnyRoute {
32
- return createRoute({
33
- getParentRoute: () => parentRoute,
34
- path: routeDef.path,
35
- component: routeDef.component as RouteComponent,
36
- ...(routeDef.meta?.title && {
37
- head: () => ({
38
- meta: [{ title: routeDef.meta!.title }],
39
- }),
40
- }),
41
- })
42
- }