@helloleo/plugins 0.1.20 → 0.2.0-beta.0

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 (133) hide show
  1. package/dist/index.js +12364 -65
  2. package/dist/templates/tanstack-start-2026-06-18/components.json +22 -0
  3. package/dist/templates/tanstack-start-2026-06-18/drizzle.config.ts +15 -0
  4. package/dist/templates/tanstack-start-2026-06-18/package.json +103 -0
  5. package/dist/templates/tanstack-start-2026-06-18/src/api/health.ts +66 -0
  6. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/accordion.tsx +51 -0
  7. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/alert-dialog.tsx +115 -0
  8. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/alert.tsx +49 -0
  9. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/aspect-ratio.tsx +5 -0
  10. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/avatar.tsx +47 -0
  11. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/badge.tsx +32 -0
  12. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/breadcrumb.tsx +101 -0
  13. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/button.tsx +49 -0
  14. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/calendar.tsx +177 -0
  15. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/card.tsx +55 -0
  16. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/carousel.tsx +240 -0
  17. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/chart.tsx +331 -0
  18. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/checkbox.tsx +26 -0
  19. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/collapsible.tsx +11 -0
  20. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/command.tsx +143 -0
  21. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/context-menu.tsx +187 -0
  22. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/dialog.tsx +104 -0
  23. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/drawer.tsx +98 -0
  24. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/dropdown-menu.tsx +188 -0
  25. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/form.tsx +171 -0
  26. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/hover-card.tsx +27 -0
  27. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/input-otp.tsx +69 -0
  28. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/input.tsx +22 -0
  29. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/label.tsx +21 -0
  30. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/menubar.tsx +229 -0
  31. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/navigation-menu.tsx +120 -0
  32. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/pagination.tsx +98 -0
  33. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/popover.tsx +31 -0
  34. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/progress.tsx +25 -0
  35. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/radio-group.tsx +36 -0
  36. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/resizable.tsx +37 -0
  37. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/scroll-area.tsx +44 -0
  38. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/select.tsx +152 -0
  39. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/separator.tsx +24 -0
  40. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/sheet.tsx +122 -0
  41. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/sidebar.tsx +744 -0
  42. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/skeleton.tsx +7 -0
  43. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/slider.tsx +23 -0
  44. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/sonner.tsx +23 -0
  45. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/switch.tsx +27 -0
  46. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/table.tsx +94 -0
  47. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/tabs.tsx +53 -0
  48. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/textarea.tsx +21 -0
  49. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/toggle-group.tsx +57 -0
  50. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/toggle.tsx +42 -0
  51. package/dist/templates/tanstack-start-2026-06-18/src/components/ui/tooltip.tsx +32 -0
  52. package/dist/templates/tanstack-start-2026-06-18/src/db/index.ts +9 -0
  53. package/dist/templates/tanstack-start-2026-06-18/src/db/schema.ts +18 -0
  54. package/dist/templates/tanstack-start-2026-06-18/src/global.d.ts +3 -0
  55. package/dist/templates/tanstack-start-2026-06-18/src/hooks/use-mobile.tsx +19 -0
  56. package/dist/templates/tanstack-start-2026-06-18/src/lib/proxy.ts +83 -0
  57. package/dist/templates/tanstack-start-2026-06-18/src/lib/utils.ts +6 -0
  58. package/dist/templates/tanstack-start-2026-06-18/src/routeTree.gen.ts +59 -0
  59. package/dist/templates/tanstack-start-2026-06-18/src/router.tsx +33 -0
  60. package/dist/templates/tanstack-start-2026-06-18/src/routes/__root.tsx +60 -0
  61. package/dist/templates/tanstack-start-2026-06-18/src/routes/index.tsx +33 -0
  62. package/dist/templates/tanstack-start-2026-06-18/src/server.ts +32 -0
  63. package/dist/templates/tanstack-start-2026-06-18/src/styles.css +214 -0
  64. package/dist/templates/tanstack-start-2026-06-18/tsconfig.json +27 -0
  65. package/dist/templates/tanstack-start-2026-06-18/vite.config.ts +17 -0
  66. package/package.json +1 -1
  67. package/src/template-render.ts +5 -0
  68. package/src/templates/tanstack-start-2026-06-18/components.json +22 -0
  69. package/src/templates/tanstack-start-2026-06-18/drizzle.config.ts +15 -0
  70. package/src/templates/tanstack-start-2026-06-18/package.json +103 -0
  71. package/src/templates/tanstack-start-2026-06-18/src/api/health.ts +66 -0
  72. package/src/templates/tanstack-start-2026-06-18/src/components/ui/accordion.tsx +51 -0
  73. package/src/templates/tanstack-start-2026-06-18/src/components/ui/alert-dialog.tsx +115 -0
  74. package/src/templates/tanstack-start-2026-06-18/src/components/ui/alert.tsx +49 -0
  75. package/src/templates/tanstack-start-2026-06-18/src/components/ui/aspect-ratio.tsx +5 -0
  76. package/src/templates/tanstack-start-2026-06-18/src/components/ui/avatar.tsx +47 -0
  77. package/src/templates/tanstack-start-2026-06-18/src/components/ui/badge.tsx +32 -0
  78. package/src/templates/tanstack-start-2026-06-18/src/components/ui/breadcrumb.tsx +101 -0
  79. package/src/templates/tanstack-start-2026-06-18/src/components/ui/button.tsx +49 -0
  80. package/src/templates/tanstack-start-2026-06-18/src/components/ui/calendar.tsx +177 -0
  81. package/src/templates/tanstack-start-2026-06-18/src/components/ui/card.tsx +55 -0
  82. package/src/templates/tanstack-start-2026-06-18/src/components/ui/carousel.tsx +240 -0
  83. package/src/templates/tanstack-start-2026-06-18/src/components/ui/chart.tsx +331 -0
  84. package/src/templates/tanstack-start-2026-06-18/src/components/ui/checkbox.tsx +26 -0
  85. package/src/templates/tanstack-start-2026-06-18/src/components/ui/collapsible.tsx +11 -0
  86. package/src/templates/tanstack-start-2026-06-18/src/components/ui/command.tsx +143 -0
  87. package/src/templates/tanstack-start-2026-06-18/src/components/ui/context-menu.tsx +187 -0
  88. package/src/templates/tanstack-start-2026-06-18/src/components/ui/dialog.tsx +104 -0
  89. package/src/templates/tanstack-start-2026-06-18/src/components/ui/drawer.tsx +98 -0
  90. package/src/templates/tanstack-start-2026-06-18/src/components/ui/dropdown-menu.tsx +188 -0
  91. package/src/templates/tanstack-start-2026-06-18/src/components/ui/form.tsx +171 -0
  92. package/src/templates/tanstack-start-2026-06-18/src/components/ui/hover-card.tsx +27 -0
  93. package/src/templates/tanstack-start-2026-06-18/src/components/ui/input-otp.tsx +69 -0
  94. package/src/templates/tanstack-start-2026-06-18/src/components/ui/input.tsx +22 -0
  95. package/src/templates/tanstack-start-2026-06-18/src/components/ui/label.tsx +21 -0
  96. package/src/templates/tanstack-start-2026-06-18/src/components/ui/menubar.tsx +229 -0
  97. package/src/templates/tanstack-start-2026-06-18/src/components/ui/navigation-menu.tsx +120 -0
  98. package/src/templates/tanstack-start-2026-06-18/src/components/ui/pagination.tsx +98 -0
  99. package/src/templates/tanstack-start-2026-06-18/src/components/ui/popover.tsx +31 -0
  100. package/src/templates/tanstack-start-2026-06-18/src/components/ui/progress.tsx +25 -0
  101. package/src/templates/tanstack-start-2026-06-18/src/components/ui/radio-group.tsx +36 -0
  102. package/src/templates/tanstack-start-2026-06-18/src/components/ui/resizable.tsx +37 -0
  103. package/src/templates/tanstack-start-2026-06-18/src/components/ui/scroll-area.tsx +44 -0
  104. package/src/templates/tanstack-start-2026-06-18/src/components/ui/select.tsx +152 -0
  105. package/src/templates/tanstack-start-2026-06-18/src/components/ui/separator.tsx +24 -0
  106. package/src/templates/tanstack-start-2026-06-18/src/components/ui/sheet.tsx +122 -0
  107. package/src/templates/tanstack-start-2026-06-18/src/components/ui/sidebar.tsx +744 -0
  108. package/src/templates/tanstack-start-2026-06-18/src/components/ui/skeleton.tsx +7 -0
  109. package/src/templates/tanstack-start-2026-06-18/src/components/ui/slider.tsx +23 -0
  110. package/src/templates/tanstack-start-2026-06-18/src/components/ui/sonner.tsx +23 -0
  111. package/src/templates/tanstack-start-2026-06-18/src/components/ui/switch.tsx +27 -0
  112. package/src/templates/tanstack-start-2026-06-18/src/components/ui/table.tsx +94 -0
  113. package/src/templates/tanstack-start-2026-06-18/src/components/ui/tabs.tsx +53 -0
  114. package/src/templates/tanstack-start-2026-06-18/src/components/ui/textarea.tsx +21 -0
  115. package/src/templates/tanstack-start-2026-06-18/src/components/ui/toggle-group.tsx +57 -0
  116. package/src/templates/tanstack-start-2026-06-18/src/components/ui/toggle.tsx +42 -0
  117. package/src/templates/tanstack-start-2026-06-18/src/components/ui/tooltip.tsx +32 -0
  118. package/src/templates/tanstack-start-2026-06-18/src/db/index.ts +9 -0
  119. package/src/templates/tanstack-start-2026-06-18/src/db/schema.ts +18 -0
  120. package/src/templates/tanstack-start-2026-06-18/src/global.d.ts +3 -0
  121. package/src/templates/tanstack-start-2026-06-18/src/hooks/use-mobile.tsx +19 -0
  122. package/src/templates/tanstack-start-2026-06-18/src/lib/proxy.ts +83 -0
  123. package/src/templates/tanstack-start-2026-06-18/src/lib/utils.ts +6 -0
  124. package/src/templates/tanstack-start-2026-06-18/src/routeTree.gen.ts +59 -0
  125. package/src/templates/tanstack-start-2026-06-18/src/router.tsx +33 -0
  126. package/src/templates/tanstack-start-2026-06-18/src/routes/__root.tsx +60 -0
  127. package/src/templates/tanstack-start-2026-06-18/src/routes/index.tsx +33 -0
  128. package/src/templates/tanstack-start-2026-06-18/src/server.ts +32 -0
  129. package/src/templates/tanstack-start-2026-06-18/src/styles.css +214 -0
  130. package/src/templates/tanstack-start-2026-06-18/tsconfig.json +27 -0
  131. package/src/templates/tanstack-start-2026-06-18/vite.config.ts +17 -0
  132. package/src/tools/scaffold.ts +41 -43
  133. package/src/tools/setup-netsuite.ts +32 -65
@@ -0,0 +1,60 @@
1
+ import {
2
+ HeadContent,
3
+ Outlet,
4
+ Scripts,
5
+ createRootRouteWithContext,
6
+ } from '@tanstack/react-router'
7
+ import type { QueryClient } from '@tanstack/react-query'
8
+ import type { ReactNode } from 'react'
9
+
10
+ // Side-effect order matters: Tailwind needs to be linked into the SSR'd
11
+ // document. Importing the stylesheet as a URL and listing it in `head.links`
12
+ // is the Start-native way (a bare `import './styles.css'` only works client-side).
13
+ import appCss from '../styles.css?url'
14
+
15
+ export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()({
16
+ head: () => ({
17
+ meta: [
18
+ { charSet: 'utf-8' },
19
+ { name: 'viewport', content: 'width=device-width, initial-scale=1.0' },
20
+ { title: '{{LEO_NAME}}' },
21
+ { name: 'description', content: '{{LEO_DESCRIPTION}}' },
22
+ ],
23
+ links: [
24
+ { rel: 'stylesheet', href: appCss },
25
+ { rel: 'preconnect', href: 'https://fonts.googleapis.com' },
26
+ {
27
+ rel: 'preconnect',
28
+ href: 'https://fonts.gstatic.com',
29
+ crossOrigin: 'anonymous',
30
+ },
31
+ {
32
+ rel: 'stylesheet',
33
+ href: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&display=swap',
34
+ },
35
+ ],
36
+ }),
37
+ component: RootComponent,
38
+ })
39
+
40
+ function RootComponent() {
41
+ return (
42
+ <RootDocument>
43
+ <Outlet />
44
+ </RootDocument>
45
+ )
46
+ }
47
+
48
+ function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
49
+ return (
50
+ <html lang="en">
51
+ <head>
52
+ <HeadContent />
53
+ </head>
54
+ <body>
55
+ {children}
56
+ <Scripts />
57
+ </body>
58
+ </html>
59
+ )
60
+ }
@@ -0,0 +1,33 @@
1
+ import { createFileRoute } from '@tanstack/react-router'
2
+ import { createServerFn } from '@tanstack/react-start'
3
+
4
+ // Server functions run only on the server (dev: node + cf-shim; prod: the
5
+ // worker). This is the seam where you read your bindings — import { db } from
6
+ // '#/db' and query Drizzle, or import { kv, storage } from '@helloleo/runtime'.
7
+ // Keep binding access INSIDE the handler, never at module scope.
8
+ const getMessage = createServerFn({ method: 'GET' }).handler(() => {
9
+ return { message: 'Hello from the server' }
10
+ })
11
+
12
+ export const Route = createFileRoute('/')({
13
+ component: Home,
14
+ loader: () => getMessage(),
15
+ })
16
+
17
+ /**
18
+ * Do not `export default function Home()`. This breaks the default
19
+ * codesplitting by Tanstack Router.
20
+ */
21
+ function Home() {
22
+ const { message } = Route.useLoaderData()
23
+
24
+ return (
25
+ <div className="p-8">
26
+ <h1 className="text-4xl font-bold">Welcome to HelloLeo</h1>
27
+ <p className="mt-4 text-lg">{message}</p>
28
+ <p className="mt-2 text-sm text-muted-foreground">
29
+ Edit <code>src/routes/index.tsx</code> to get started.
30
+ </p>
31
+ </div>
32
+ )
33
+ }
@@ -0,0 +1,32 @@
1
+ // Cloudflare Worker entry (the Worker `main`, configured by @helloleo/vite-config).
2
+ // Wraps the TanStack Start server entry so an SSR failure renders a clean 500
3
+ // instead of a raw stack.
4
+ type ServerEntry = {
5
+ fetch: (request: Request, env: unknown, ctx: unknown) => Promise<Response> | Response
6
+ }
7
+
8
+ let serverEntryPromise: Promise<ServerEntry> | undefined
9
+
10
+ async function getServerEntry(): Promise<ServerEntry> {
11
+ if (!serverEntryPromise) {
12
+ serverEntryPromise = import('@tanstack/react-start/server-entry').then(
13
+ (m) => ((m as { default?: ServerEntry }).default ?? m) as ServerEntry,
14
+ )
15
+ }
16
+ return serverEntryPromise
17
+ }
18
+
19
+ export default {
20
+ async fetch(request: Request, env: unknown, ctx: unknown) {
21
+ try {
22
+ const handler = await getServerEntry()
23
+ return await handler.fetch(request, env, ctx)
24
+ } catch (error) {
25
+ console.error(error)
26
+ return new Response('<h1>Something went wrong</h1>', {
27
+ status: 500,
28
+ headers: { 'content-type': 'text/html; charset=utf-8' },
29
+ })
30
+ }
31
+ },
32
+ }
@@ -0,0 +1,214 @@
1
+ /*
2
+ * HelloLeo Design System -- READ BEFORE STYLING.
3
+ *
4
+ * Design tokens are the single source of truth and power the no-code Design
5
+ * panel (the user edits colors / fonts / radius visually). Conventions:
6
+ * - Raw tokens live in :root (light) and .dark (dark). The @media
7
+ * (prefers-color-scheme: dark) block mirrors .dark so apps follow the OS
8
+ * by default; adding the `dark` class still forces dark explicitly.
9
+ * - @theme inline maps each raw token to a Tailwind utility
10
+ * (bg-background, text-foreground, rounded-lg, ...). Edit the raw token,
11
+ * not the component class. Never hardcode #hex in components.
12
+ * - When you add a color token, add it to :root, .dark, AND the media block,
13
+ * or one theme breaks.
14
+ *
15
+ * UI primitives live in src/components/ui (shadcn/ui) and consume these
16
+ * tokens. One responsibility per file.
17
+ */
18
+
19
+ @import "tailwindcss" source(none);
20
+ @source "../src";
21
+ @import "tw-animate-css";
22
+
23
+ @custom-variant dark (&:is(.dark *));
24
+
25
+ @theme inline {
26
+ --radius-sm: calc(var(--radius) - 4px);
27
+ --radius-md: calc(var(--radius) - 2px);
28
+ --radius-lg: var(--radius);
29
+ --radius-xl: calc(var(--radius) + 4px);
30
+ --color-background: var(--background);
31
+ --color-foreground: var(--foreground);
32
+ --color-card: var(--card);
33
+ --color-card-foreground: var(--card-foreground);
34
+ --color-popover: var(--popover);
35
+ --color-popover-foreground: var(--popover-foreground);
36
+ --color-primary: var(--primary);
37
+ --color-primary-foreground: var(--primary-foreground);
38
+ --color-secondary: var(--secondary);
39
+ --color-secondary-foreground: var(--secondary-foreground);
40
+ --color-muted: var(--muted);
41
+ --color-muted-foreground: var(--muted-foreground);
42
+ --color-accent: var(--accent);
43
+ --color-accent-foreground: var(--accent-foreground);
44
+ --color-destructive: var(--destructive);
45
+ --color-destructive-foreground: var(--destructive-foreground);
46
+ --color-border: var(--border);
47
+ --color-input: var(--input);
48
+ --color-ring: var(--ring);
49
+ --color-chart-1: var(--chart-1);
50
+ --color-chart-2: var(--chart-2);
51
+ --color-chart-3: var(--chart-3);
52
+ --color-chart-4: var(--chart-4);
53
+ --color-chart-5: var(--chart-5);
54
+ --color-sidebar: var(--sidebar);
55
+ --color-sidebar-foreground: var(--sidebar-foreground);
56
+ --color-sidebar-primary: var(--sidebar-primary);
57
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
58
+ --color-sidebar-accent: var(--sidebar-accent);
59
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
60
+ --color-sidebar-border: var(--sidebar-border);
61
+ --color-sidebar-ring: var(--sidebar-ring);
62
+ --font-sans: "Inter", system-ui, sans-serif;
63
+ --font-display: "Space Grotesk", "Inter", sans-serif;
64
+ }
65
+
66
+ :root {
67
+ --radius: 0.625rem;
68
+ --background: oklch(1 0 0);
69
+ --foreground: oklch(0.145 0 0);
70
+ --card: oklch(1 0 0);
71
+ --card-foreground: oklch(0.145 0 0);
72
+ --popover: oklch(1 0 0);
73
+ --popover-foreground: oklch(0.145 0 0);
74
+ --primary: oklch(0.205 0 0);
75
+ --primary-foreground: oklch(0.985 0 0);
76
+ --secondary: oklch(0.97 0 0);
77
+ --secondary-foreground: oklch(0.205 0 0);
78
+ --muted: oklch(0.97 0 0);
79
+ --muted-foreground: oklch(0.556 0 0);
80
+ --accent: oklch(0.97 0 0);
81
+ --accent-foreground: oklch(0.205 0 0);
82
+ --destructive: oklch(0.577 0.245 27.325);
83
+ --destructive-foreground: oklch(0.985 0 0);
84
+ --border: oklch(0.922 0 0);
85
+ --input: oklch(0.922 0 0);
86
+ --ring: oklch(0.708 0 0);
87
+ --chart-1: oklch(0.646 0.222 41.116);
88
+ --chart-2: oklch(0.6 0.118 184.704);
89
+ --chart-3: oklch(0.398 0.07 227.392);
90
+ --chart-4: oklch(0.828 0.189 84.429);
91
+ --chart-5: oklch(0.769 0.188 70.08);
92
+ --sidebar: oklch(0.985 0 0);
93
+ --sidebar-foreground: oklch(0.145 0 0);
94
+ --sidebar-primary: oklch(0.205 0 0);
95
+ --sidebar-primary-foreground: oklch(0.985 0 0);
96
+ --sidebar-accent: oklch(0.97 0 0);
97
+ --sidebar-accent-foreground: oklch(0.205 0 0);
98
+ --sidebar-border: oklch(0.922 0 0);
99
+ --sidebar-ring: oklch(0.708 0 0);
100
+ }
101
+
102
+ /* Dark palette -- kept identical in .dark (explicit) and the media block
103
+ * (system default). Edit BOTH when changing a token. */
104
+ .dark {
105
+ --background: oklch(0.145 0 0);
106
+ --foreground: oklch(0.985 0 0);
107
+ --card: oklch(0.205 0 0);
108
+ --card-foreground: oklch(0.985 0 0);
109
+ --popover: oklch(0.205 0 0);
110
+ --popover-foreground: oklch(0.985 0 0);
111
+ --primary: oklch(0.922 0 0);
112
+ --primary-foreground: oklch(0.205 0 0);
113
+ --secondary: oklch(0.269 0 0);
114
+ --secondary-foreground: oklch(0.985 0 0);
115
+ --muted: oklch(0.269 0 0);
116
+ --muted-foreground: oklch(0.708 0 0);
117
+ --accent: oklch(0.269 0 0);
118
+ --accent-foreground: oklch(0.985 0 0);
119
+ --destructive: oklch(0.704 0.191 22.216);
120
+ --destructive-foreground: oklch(0.985 0 0);
121
+ --border: oklch(1 0 0 / 10%);
122
+ --input: oklch(1 0 0 / 15%);
123
+ --ring: oklch(0.556 0 0);
124
+ --chart-1: oklch(0.488 0.243 264.376);
125
+ --chart-2: oklch(0.696 0.17 162.48);
126
+ --chart-3: oklch(0.769 0.188 70.08);
127
+ --chart-4: oklch(0.627 0.265 303.9);
128
+ --chart-5: oklch(0.645 0.246 16.439);
129
+ --sidebar: oklch(0.205 0 0);
130
+ --sidebar-foreground: oklch(0.985 0 0);
131
+ --sidebar-primary: oklch(0.488 0.243 264.376);
132
+ --sidebar-primary-foreground: oklch(0.985 0 0);
133
+ --sidebar-accent: oklch(0.269 0 0);
134
+ --sidebar-accent-foreground: oklch(0.985 0 0);
135
+ --sidebar-border: oklch(1 0 0 / 10%);
136
+ --sidebar-ring: oklch(0.556 0 0);
137
+ }
138
+
139
+ @media (prefers-color-scheme: dark) {
140
+ :root {
141
+ --background: oklch(0.145 0 0);
142
+ --foreground: oklch(0.985 0 0);
143
+ --card: oklch(0.205 0 0);
144
+ --card-foreground: oklch(0.985 0 0);
145
+ --popover: oklch(0.205 0 0);
146
+ --popover-foreground: oklch(0.985 0 0);
147
+ --primary: oklch(0.922 0 0);
148
+ --primary-foreground: oklch(0.205 0 0);
149
+ --secondary: oklch(0.269 0 0);
150
+ --secondary-foreground: oklch(0.985 0 0);
151
+ --muted: oklch(0.269 0 0);
152
+ --muted-foreground: oklch(0.708 0 0);
153
+ --accent: oklch(0.269 0 0);
154
+ --accent-foreground: oklch(0.985 0 0);
155
+ --destructive: oklch(0.704 0.191 22.216);
156
+ --destructive-foreground: oklch(0.985 0 0);
157
+ --border: oklch(1 0 0 / 10%);
158
+ --input: oklch(1 0 0 / 15%);
159
+ --ring: oklch(0.556 0 0);
160
+ --chart-1: oklch(0.488 0.243 264.376);
161
+ --chart-2: oklch(0.696 0.17 162.48);
162
+ --chart-3: oklch(0.769 0.188 70.08);
163
+ --chart-4: oklch(0.627 0.265 303.9);
164
+ --chart-5: oklch(0.645 0.246 16.439);
165
+ --sidebar: oklch(0.205 0 0);
166
+ --sidebar-foreground: oklch(0.985 0 0);
167
+ --sidebar-primary: oklch(0.488 0.243 264.376);
168
+ --sidebar-primary-foreground: oklch(0.985 0 0);
169
+ --sidebar-accent: oklch(0.269 0 0);
170
+ --sidebar-accent-foreground: oklch(0.985 0 0);
171
+ --sidebar-border: oklch(1 0 0 / 10%);
172
+ --sidebar-ring: oklch(0.556 0 0);
173
+ }
174
+ }
175
+
176
+ @layer base {
177
+ * {
178
+ border-color: var(--color-border);
179
+ }
180
+ html,
181
+ body {
182
+ font-family: var(--font-sans);
183
+ }
184
+ body {
185
+ background-color: var(--color-background);
186
+ color: var(--color-foreground);
187
+ min-height: 100vh;
188
+ }
189
+ h1, h2, h3, h4 {
190
+ font-family: var(--font-display);
191
+ letter-spacing: -0.02em;
192
+ }
193
+ }
194
+
195
+ @layer utilities {
196
+ .prose-note {
197
+ color: var(--color-foreground);
198
+ }
199
+ .prose-note h1 { font-size: 1.875rem; font-weight: 700; margin: 1.25rem 0 0.75rem; font-family: var(--font-display); }
200
+ .prose-note h2 { font-size: 1.5rem; font-weight: 600; margin: 1rem 0 0.5rem; font-family: var(--font-display); }
201
+ .prose-note h3 { font-size: 1.25rem; font-weight: 600; margin: 0.875rem 0 0.5rem; }
202
+ .prose-note p { margin: 0.5rem 0; line-height: 1.7; }
203
+ .prose-note ul { list-style: disc; padding-left: 1.5rem; margin: 0.5rem 0; }
204
+ .prose-note ol { list-style: decimal; padding-left: 1.5rem; margin: 0.5rem 0; }
205
+ .prose-note li { margin: 0.25rem 0; }
206
+ .prose-note a { color: var(--color-primary); text-decoration: underline; }
207
+ .prose-note code { background: var(--color-muted); padding: 0.125rem 0.375rem; border-radius: 0.25rem; font-size: 0.875em; }
208
+ .prose-note pre { background: var(--color-muted); padding: 1rem; border-radius: 0.5rem; overflow-x: auto; margin: 0.75rem 0; }
209
+ .prose-note pre code { background: transparent; padding: 0; }
210
+ .prose-note blockquote { border-left: 3px solid var(--color-primary); padding-left: 1rem; margin: 0.75rem 0; color: var(--color-muted-foreground); }
211
+ .prose-note hr { border-color: var(--color-border); margin: 1.5rem 0; }
212
+ .prose-note table { border-collapse: collapse; margin: 0.75rem 0; }
213
+ .prose-note th, .prose-note td { border: 1px solid var(--color-border); padding: 0.375rem 0.75rem; }
214
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "include": ["**/*.ts", "**/*.tsx"],
3
+ "compilerOptions": {
4
+ "target": "ES2022",
5
+ "jsx": "react-jsx",
6
+ "module": "ESNext",
7
+ "paths": {
8
+ "#/*": ["./src/*"],
9
+ "@/*": ["./src/*"]
10
+ },
11
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
12
+ "types": ["@cloudflare/workers-types", "vite/client"],
13
+
14
+ /* Bundler mode */
15
+ "moduleResolution": "bundler",
16
+ "allowImportingTsExtensions": true,
17
+ "noEmit": true,
18
+
19
+ /* Linting */
20
+ "skipLibCheck": true,
21
+ "strict": true,
22
+ "noUnusedLocals": true,
23
+ "noUnusedParameters": true,
24
+ "noFallthroughCasesInSwitch": true,
25
+ "noUncheckedSideEffectImports": true
26
+ }
27
+ }
@@ -0,0 +1,17 @@
1
+ import { defineConfig } from '@helloleo/vite-config'
2
+
3
+ // @helloleo/vite-config owns the whole build/dev/sandbox pipeline: in dev it
4
+ // aliases `cloudflare:workers` -> @helloleo/runtime/cf-shim (libsql .dev.db for
5
+ // D1+KV, local disk for R2) and runs plain Vite SSR; at build it adds
6
+ // @cloudflare/vite-plugin to emit a workerd Worker bound to wrangler.jsonc. It
7
+ // also binds host:true/port:5173 itself (>=0.1.2).
8
+ //
9
+ // The one thing the wrapper doesn't set: HMR over the HelloLeo preview proxy,
10
+ // which terminates HTTPS on :443 — so point the HMR client at wss://…:443.
11
+ export default defineConfig({
12
+ vite: {
13
+ server: {
14
+ hmr: { clientPort: 443, protocol: 'wss' },
15
+ },
16
+ },
17
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helloleo/plugins",
3
- "version": "0.1.20",
3
+ "version": "0.2.0-beta.0",
4
4
  "description": "OpenCode plugins for HelloLeo",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -33,16 +33,21 @@ export async function renderTemplate(
33
33
  const root = path.join(TEMPLATES_ROOT, templateId);
34
34
  const glob = new Glob("**/*");
35
35
  const created: string[] = [];
36
+
36
37
  for await (const rel of glob.scan({
37
38
  cwd: root,
38
39
  dot: true,
39
40
  onlyFiles: true,
40
41
  })) {
41
42
  if (SKIP.test(rel)) continue;
43
+
42
44
  const raw = await Bun.file(path.join(root, rel)).text();
43
45
  const content = raw.replace(TOKEN_RE, (_m, key: string) => vars[key] ?? "");
46
+
44
47
  await Bun.write(path.join(destDir, rel), content);
48
+
45
49
  created.push(rel);
46
50
  }
51
+
47
52
  return created.sort();
48
53
  }
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "css": "src/styles.css",
8
+ "baseColor": "slate",
9
+ "cssVariables": true,
10
+ "prefix": ""
11
+ },
12
+ "iconLibrary": "lucide",
13
+ "rtl": false,
14
+ "aliases": {
15
+ "components": "@/components",
16
+ "utils": "@/lib/utils",
17
+ "ui": "@/components/ui",
18
+ "lib": "@/lib",
19
+ "hooks": "@/hooks"
20
+ },
21
+ "registries": {}
22
+ }
@@ -0,0 +1,15 @@
1
+ import { defineConfig } from 'drizzle-kit'
2
+
3
+ // src/db/schema.ts is the single source of truth for the D1 / libsql schema.
4
+ //
5
+ // In development, your database is always up-to-date. In production, we migrate
6
+ // automatically when you publish.
7
+
8
+ const devDbPath = process.env.DEV_DB_PATH ?? '.dev.db'
9
+
10
+ export default defineConfig({
11
+ dialect: 'sqlite',
12
+ schema: './src/db/schema.ts',
13
+ out: './drizzle',
14
+ dbCredentials: { url: `file:${devDbPath}` },
15
+ })
@@ -0,0 +1,103 @@
1
+ {
2
+ "name": "{{LEO_NAME}}",
3
+ "private": true,
4
+ "type": "module",
5
+ "imports": {
6
+ "#/*": "./src/*"
7
+ },
8
+ "scripts": {
9
+ "dev": "drizzle-kit push --force && vite dev",
10
+ "build": "oxlint --fix && vite build",
11
+ "preview": "vite preview",
12
+ "db:generate": "drizzle-kit generate",
13
+ "generate-routes": "tsr generate",
14
+ "db:push": "drizzle-kit push --force",
15
+ "typecheck": "tsc --noEmit",
16
+ "lint": "oxlint --fix",
17
+ "test": "vitest run"
18
+ },
19
+ "dependencies": {
20
+ "@helloleo/runtime": "^0.1.1",
21
+ "@hookform/resolvers": "^5.2.2",
22
+ "@radix-ui/react-accordion": "^1.2.12",
23
+ "@radix-ui/react-alert-dialog": "^1.1.15",
24
+ "@radix-ui/react-aspect-ratio": "^1.1.8",
25
+ "@radix-ui/react-avatar": "^1.1.11",
26
+ "@radix-ui/react-checkbox": "^1.3.3",
27
+ "@radix-ui/react-collapsible": "^1.1.12",
28
+ "@radix-ui/react-context-menu": "^2.2.16",
29
+ "@radix-ui/react-dialog": "^1.1.15",
30
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
31
+ "@radix-ui/react-hover-card": "^1.1.15",
32
+ "@radix-ui/react-label": "^2.1.8",
33
+ "@radix-ui/react-menubar": "^1.1.16",
34
+ "@radix-ui/react-navigation-menu": "^1.2.14",
35
+ "@radix-ui/react-popover": "^1.1.15",
36
+ "@radix-ui/react-progress": "^1.1.8",
37
+ "@radix-ui/react-radio-group": "^1.3.8",
38
+ "@radix-ui/react-scroll-area": "^1.2.10",
39
+ "@radix-ui/react-select": "^2.2.6",
40
+ "@radix-ui/react-separator": "^1.1.8",
41
+ "@radix-ui/react-slider": "^1.3.6",
42
+ "@radix-ui/react-slot": "^1.2.4",
43
+ "@radix-ui/react-switch": "^1.2.6",
44
+ "@radix-ui/react-tabs": "^1.1.13",
45
+ "@radix-ui/react-toggle": "^1.1.10",
46
+ "@radix-ui/react-toggle-group": "^1.1.11",
47
+ "@radix-ui/react-tooltip": "^1.2.8",
48
+ "@tailwindcss/vite": "^4.1.18",
49
+ "@tanstack/react-query": "^5.90.0",
50
+ "@tanstack/react-router": "latest",
51
+ "@tanstack/react-router-with-query": "latest",
52
+ "@tanstack/react-start": "latest",
53
+ "class-variance-authority": "^0.7.1",
54
+ "clsx": "^2.1.1",
55
+ "cmdk": "^1.1.1",
56
+ "date-fns": "^4.1.0",
57
+ "drizzle-orm": "^0.45.2",
58
+ "embla-carousel-react": "^8.6.0",
59
+ "input-otp": "^1.4.2",
60
+ "lucide-react": "^0.575.0",
61
+ "react": "^19.2.0",
62
+ "react-day-picker": "^9.14.0",
63
+ "react-dom": "^19.2.0",
64
+ "react-hook-form": "^7.71.2",
65
+ "react-resizable-panels": "^4.6.5",
66
+ "recharts": "^2.15.4",
67
+ "sonner": "^2.0.7",
68
+ "tailwind-merge": "^3.5.0",
69
+ "tailwindcss": "^4.1.18",
70
+ "tw-animate-css": "^1.3.4",
71
+ "vaul": "^1.1.2",
72
+ "zod": "^3.24.2"
73
+ },
74
+ "devDependencies": {
75
+ "@cloudflare/vite-plugin": "^1.13.0",
76
+ "@cloudflare/workers-types": "^4.20250906.0",
77
+ "@helloleo/vite-config": "^0.1.4",
78
+ "@libsql/client": "^0.14.0",
79
+ "@tailwindcss/typography": "^0.5.16",
80
+ "drizzle-kit": "^0.31.10",
81
+ "@tanstack/router-cli": "^1.167.0",
82
+ "@tanstack/router-plugin": "latest",
83
+ "@testing-library/dom": "^10.4.1",
84
+ "@testing-library/react": "^16.3.0",
85
+ "@types/node": "^22.10.2",
86
+ "@types/react": "^19.2.0",
87
+ "@types/react-dom": "^19.2.0",
88
+ "@vitejs/plugin-react": "^6.0.1",
89
+ "jsdom": "^28.1.0",
90
+ "oxlint": "^1.69.0",
91
+ "typescript": "^6.0.2",
92
+ "vite": "^8.0.0",
93
+ "vite-tsconfig-paths": "^6.0.0",
94
+ "vitest": "^4.1.5",
95
+ "wrangler": "^4.70.0"
96
+ },
97
+ "pnpm": {
98
+ "onlyBuiltDependencies": [
99
+ "esbuild",
100
+ "lightningcss"
101
+ ]
102
+ }
103
+ }
@@ -0,0 +1,66 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { supabaseAdmin } from "@/integrations/supabase/client.server";
3
+
4
+ export const Route = createFileRoute("/api/health")({
5
+ server: {
6
+ handlers: {
7
+ GET: async () => {
8
+ const startedAt = Date.now();
9
+
10
+ // Server health
11
+ const server = {
12
+ status: "ok" as const,
13
+ uptimeSeconds: Math.round(
14
+ typeof process !== "undefined" &&
15
+ typeof process.uptime === "function"
16
+ ? process.uptime()
17
+ : 0,
18
+ ),
19
+ timestamp: new Date().toISOString(),
20
+ runtime: "cloudflare-workers",
21
+ };
22
+
23
+ // Database health — lightweight query against a known table
24
+ let database: {
25
+ status: "ok" | "error";
26
+ latencyMs: number;
27
+ error: string | null;
28
+ };
29
+ const dbStart = Date.now();
30
+ try {
31
+ const { error } = await supabaseAdmin
32
+ .from("notes")
33
+ .select("id", { count: "exact", head: true })
34
+ .limit(1);
35
+ if (error) throw error;
36
+ database = {
37
+ status: "ok",
38
+ latencyMs: Date.now() - dbStart,
39
+ error: null,
40
+ };
41
+ } catch (err) {
42
+ database = {
43
+ status: "error",
44
+ latencyMs: Date.now() - dbStart,
45
+ error: err instanceof Error ? err.message : String(err),
46
+ };
47
+ }
48
+
49
+ const overall =
50
+ server.status === "ok" && database.status === "ok"
51
+ ? "ok"
52
+ : "degraded";
53
+
54
+ return Response.json(
55
+ {
56
+ status: overall,
57
+ server,
58
+ database,
59
+ checkedInMs: Date.now() - startedAt,
60
+ },
61
+ { status: overall === "ok" ? 200 : 503 },
62
+ );
63
+ },
64
+ },
65
+ },
66
+ });
@@ -0,0 +1,51 @@
1
+ import * as React from "react";
2
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
3
+ import { ChevronDown } from "lucide-react";
4
+
5
+ import { cn } from "@/lib/utils";
6
+
7
+ const Accordion = AccordionPrimitive.Root;
8
+
9
+ const AccordionItem = React.forwardRef<
10
+ React.ElementRef<typeof AccordionPrimitive.Item>,
11
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
12
+ >(({ className, ...props }, ref) => (
13
+ <AccordionPrimitive.Item ref={ref} className={cn("border-b", className)} {...props} />
14
+ ));
15
+ AccordionItem.displayName = "AccordionItem";
16
+
17
+ const AccordionTrigger = React.forwardRef<
18
+ React.ElementRef<typeof AccordionPrimitive.Trigger>,
19
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
20
+ >(({ className, children, ...props }, ref) => (
21
+ <AccordionPrimitive.Header className="flex">
22
+ <AccordionPrimitive.Trigger
23
+ ref={ref}
24
+ className={cn(
25
+ "flex flex-1 items-center justify-between py-4 text-sm font-medium cursor-pointer transition-all hover:underline text-left [&[data-state=open]>svg]:rotate-180",
26
+ className,
27
+ )}
28
+ {...props}
29
+ >
30
+ {children}
31
+ <ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
32
+ </AccordionPrimitive.Trigger>
33
+ </AccordionPrimitive.Header>
34
+ ));
35
+ AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
36
+
37
+ const AccordionContent = React.forwardRef<
38
+ React.ElementRef<typeof AccordionPrimitive.Content>,
39
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
40
+ >(({ className, children, ...props }, ref) => (
41
+ <AccordionPrimitive.Content
42
+ ref={ref}
43
+ className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
44
+ {...props}
45
+ >
46
+ <div className={cn("pb-4 pt-0", className)}>{children}</div>
47
+ </AccordionPrimitive.Content>
48
+ ));
49
+ AccordionContent.displayName = AccordionPrimitive.Content.displayName;
50
+
51
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };