vibecarbon 0.1.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 (495) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +188 -0
  3. package/carbon/.claude/hooks/task-completed-gate.sh +19 -0
  4. package/carbon/.claude/hooks/teammate-idle-gate.sh +29 -0
  5. package/carbon/.claude/settings.json +29 -0
  6. package/carbon/.cursor/rules/vibecarbon.mdc +6 -0
  7. package/carbon/.dockerignore +57 -0
  8. package/carbon/.env.example +219 -0
  9. package/carbon/.github/copilot-instructions.md +3 -0
  10. package/carbon/.github/workflows/deploy.yml +346 -0
  11. package/carbon/.github/workflows/vibecarbon-build.yml +81 -0
  12. package/carbon/.windsurfrules +74 -0
  13. package/carbon/AGENTS.md +422 -0
  14. package/carbon/CLAUDE.md +3 -0
  15. package/carbon/DEVELOPMENT.md +187 -0
  16. package/carbon/Dockerfile +98 -0
  17. package/carbon/LICENSE +21 -0
  18. package/carbon/PRODUCTION.md +364 -0
  19. package/carbon/README.md +193 -0
  20. package/carbon/TESTING.md +138 -0
  21. package/carbon/backup/Dockerfile +75 -0
  22. package/carbon/backup/backup.sh +95 -0
  23. package/carbon/backup/compose-backup.sh +140 -0
  24. package/carbon/biome.json +83 -0
  25. package/carbon/cloud-init/docker-ce-setup.yaml +55 -0
  26. package/carbon/cloud-init/k3s/master-init.sh +215 -0
  27. package/carbon/cloud-init/k3s/supabase-init.sh +167 -0
  28. package/carbon/cloud-init/k3s/worker-init.sh +147 -0
  29. package/carbon/components.json +24 -0
  30. package/carbon/content/blog/authentication-guide.mdx +34 -0
  31. package/carbon/content/blog/getting-started.mdx +41 -0
  32. package/carbon/content/changelog/v0-1-0.mdx +40 -0
  33. package/carbon/content/docs/analytics.mdx +90 -0
  34. package/carbon/content/docs/authentication.mdx +231 -0
  35. package/carbon/content/docs/background-jobs.mdx +116 -0
  36. package/carbon/content/docs/cli.mdx +630 -0
  37. package/carbon/content/docs/database.mdx +236 -0
  38. package/carbon/content/docs/deployment.mdx +227 -0
  39. package/carbon/content/docs/development.mdx +238 -0
  40. package/carbon/content/docs/environments.mdx +84 -0
  41. package/carbon/content/docs/getting-started.mdx +112 -0
  42. package/carbon/content/docs/legal/privacy-policy.mdx +89 -0
  43. package/carbon/content/docs/legal/terms-of-service.mdx +99 -0
  44. package/carbon/content/docs/optional-services.mdx +160 -0
  45. package/carbon/db/Dockerfile +23 -0
  46. package/carbon/docker-compose.dev-init.yml +5 -0
  47. package/carbon/docker-compose.metabase.override.yml +14 -0
  48. package/carbon/docker-compose.metabase.prod.yml +28 -0
  49. package/carbon/docker-compose.metabase.yml +84 -0
  50. package/carbon/docker-compose.n8n.override.yml +14 -0
  51. package/carbon/docker-compose.n8n.prod.yml +31 -0
  52. package/carbon/docker-compose.n8n.yml +97 -0
  53. package/carbon/docker-compose.observability.override.yml +18 -0
  54. package/carbon/docker-compose.observability.prod.yml +28 -0
  55. package/carbon/docker-compose.observability.yml +125 -0
  56. package/carbon/docker-compose.override.yml +28 -0
  57. package/carbon/docker-compose.prod.yml +294 -0
  58. package/carbon/docker-compose.yml +508 -0
  59. package/carbon/docker-entrypoint.sh +12 -0
  60. package/carbon/ha/activate-standby.sh +52 -0
  61. package/carbon/ha/primary-init.sql +36 -0
  62. package/carbon/ha/standby-init.sh +74 -0
  63. package/carbon/k8s/LICENSE +99 -0
  64. package/carbon/k8s/README.md +272 -0
  65. package/carbon/k8s/base/app/deployment.yaml +130 -0
  66. package/carbon/k8s/base/app/hpa.yaml +44 -0
  67. package/carbon/k8s/base/app/kustomization.yaml +10 -0
  68. package/carbon/k8s/base/app/network-policy.yaml +124 -0
  69. package/carbon/k8s/base/app/pdb.yaml +14 -0
  70. package/carbon/k8s/base/app/rbac.yaml +36 -0
  71. package/carbon/k8s/base/app/service.yaml +16 -0
  72. package/carbon/k8s/base/backup/cronjob.yaml +120 -0
  73. package/carbon/k8s/base/backup/kustomization.yaml +7 -0
  74. package/carbon/k8s/base/backup/network-policy.yaml +31 -0
  75. package/carbon/k8s/base/backup/rbac.yaml +7 -0
  76. package/carbon/k8s/base/cluster-autoscaler/deployment.yaml +103 -0
  77. package/carbon/k8s/base/cluster-autoscaler/kustomization.yaml +17 -0
  78. package/carbon/k8s/base/cluster-autoscaler/rbac.yaml +109 -0
  79. package/carbon/k8s/base/config/configmap.yaml +48 -0
  80. package/carbon/k8s/base/config/kustomization.yaml +8 -0
  81. package/carbon/k8s/base/hetzner-ccm/kustomization.yaml +9 -0
  82. package/carbon/k8s/base/hetzner-csi/kustomization.yaml +9 -0
  83. package/carbon/k8s/base/kustomization.yaml +43 -0
  84. package/carbon/k8s/base/namespace.yaml +7 -0
  85. package/carbon/k8s/base/network-policies.yaml +95 -0
  86. package/carbon/k8s/base/registry/kustomization.yaml +5 -0
  87. package/carbon/k8s/base/registry/local-registry.yaml +193 -0
  88. package/carbon/k8s/base/traefik/certificate.yaml +21 -0
  89. package/carbon/k8s/base/traefik/configmap.yaml +13 -0
  90. package/carbon/k8s/base/traefik/deployment.yaml +165 -0
  91. package/carbon/k8s/base/traefik/ingressroute.yaml +141 -0
  92. package/carbon/k8s/base/traefik/kustomization.yaml +11 -0
  93. package/carbon/k8s/base/traefik/middleware.yaml +109 -0
  94. package/carbon/k8s/base/traefik/network-policy.yaml +92 -0
  95. package/carbon/k8s/base/traefik/service.yaml +38 -0
  96. package/carbon/k8s/flux/README.md +49 -0
  97. package/carbon/k8s/flux/clusters/primary/vibecarbon.yaml +128 -0
  98. package/carbon/k8s/flux/clusters/standby/vibecarbon.yaml +83 -0
  99. package/carbon/k8s/gitops/cert-manager-webhook-hetzner/helm-release.yaml +38 -0
  100. package/carbon/k8s/gitops/cert-manager-webhook-hetzner/helm-repository.yaml +16 -0
  101. package/carbon/k8s/gitops/cert-manager-webhook-hetzner/kustomization.yaml +10 -0
  102. package/carbon/k8s/gitops/supabase/helm-release.yaml +66 -0
  103. package/carbon/k8s/gitops/supabase/helm-repository.yaml +18 -0
  104. package/carbon/k8s/gitops/supabase/kustomization.yaml +33 -0
  105. package/carbon/k8s/infra/cert-manager-resources/cluster-issuers-cloudflare.yaml +51 -0
  106. package/carbon/k8s/infra/cert-manager-resources/cluster-issuers-hetzner.yaml +59 -0
  107. package/carbon/k8s/infra/cert-manager-resources/cluster-issuers-manual.yaml +43 -0
  108. package/carbon/k8s/infra/cert-manager-resources/kustomization.yaml +15 -0
  109. package/carbon/k8s/infra/kustomization.yaml +21 -0
  110. package/carbon/k8s/infra/traefik-crds/kustomization.yaml +10 -0
  111. package/carbon/k8s/overlays/local/configmap.yaml +23 -0
  112. package/carbon/k8s/overlays/local/ingressroute-studio.yaml +104 -0
  113. package/carbon/k8s/overlays/local/kustomization.yaml +215 -0
  114. package/carbon/k8s/overlays/local/namespace.yaml +8 -0
  115. package/carbon/k8s/overlays/local/secrets.yaml +32 -0
  116. package/carbon/k8s/overlays/production/kustomization.yaml +34 -0
  117. package/carbon/k8s/test-local.sh +318 -0
  118. package/carbon/k8s/values/supabase.values.yaml +133 -0
  119. package/carbon/package.json +154 -0
  120. package/carbon/runtime.Dockerfile +17 -0
  121. package/carbon/scripts/_dev-jwt.mjs +45 -0
  122. package/carbon/scripts/check-rls.ts +53 -0
  123. package/carbon/scripts/dev-init.js +191 -0
  124. package/carbon/scripts/dev.js +191 -0
  125. package/carbon/scripts/docker-down.js +63 -0
  126. package/carbon/scripts/docker-logs.js +59 -0
  127. package/carbon/scripts/docker-up.js +222 -0
  128. package/carbon/scripts/generate-dev-configs.sh +131 -0
  129. package/carbon/scripts/generate-rss.ts +116 -0
  130. package/carbon/scripts/generate-sitemap.ts +102 -0
  131. package/carbon/scripts/k8s-apply.js +71 -0
  132. package/carbon/scripts/k8s-delete.js +75 -0
  133. package/carbon/scripts/lib/manifest.js +176 -0
  134. package/carbon/scripts/secret-scan.mjs +278 -0
  135. package/carbon/scripts/validate-dev-configs.sh +101 -0
  136. package/carbon/src/client/App.tsx +202 -0
  137. package/carbon/src/client/assets/hyperformant-dark.svg +29 -0
  138. package/carbon/src/client/assets/hyperformant-light.svg +29 -0
  139. package/carbon/src/client/assets/logos/aider.svg +1 -0
  140. package/carbon/src/client/assets/logos/antigravity.svg +1 -0
  141. package/carbon/src/client/assets/logos/bolt.svg +1 -0
  142. package/carbon/src/client/assets/logos/claude-code.svg +1 -0
  143. package/carbon/src/client/assets/logos/copilot.svg +1 -0
  144. package/carbon/src/client/assets/logos/cursor.svg +1 -0
  145. package/carbon/src/client/assets/logos/gemini-cli.svg +1 -0
  146. package/carbon/src/client/assets/logos/lovable.svg +1 -0
  147. package/carbon/src/client/assets/logos/openai-codex.svg +1 -0
  148. package/carbon/src/client/assets/logos/v0.svg +1 -0
  149. package/carbon/src/client/assets/logos/windsurf.svg +1 -0
  150. package/carbon/src/client/assets/vibecarbon-icon.svg +19 -0
  151. package/carbon/src/client/assets/vibecarbon-logo-dark.svg +29 -0
  152. package/carbon/src/client/assets/vibecarbon-logo-light.svg +29 -0
  153. package/carbon/src/client/components/AIIntegrationSection.tsx +120 -0
  154. package/carbon/src/client/components/AppSidebar.tsx +760 -0
  155. package/carbon/src/client/components/ArchitectureSection.tsx +46 -0
  156. package/carbon/src/client/components/CTAFooter.tsx +59 -0
  157. package/carbon/src/client/components/ComparisonSection.tsx +132 -0
  158. package/carbon/src/client/components/ContentPanel.tsx +66 -0
  159. package/carbon/src/client/components/ContentSkeleton.tsx +21 -0
  160. package/carbon/src/client/components/ErrorBoundary.tsx +46 -0
  161. package/carbon/src/client/components/FAQSection.tsx +76 -0
  162. package/carbon/src/client/components/FileUpload.tsx +210 -0
  163. package/carbon/src/client/components/HeaderActions.tsx +17 -0
  164. package/carbon/src/client/components/Hero.tsx +608 -0
  165. package/carbon/src/client/components/ImpersonationBanner.tsx +31 -0
  166. package/carbon/src/client/components/LanguageSwitcher.tsx +67 -0
  167. package/carbon/src/client/components/Logo.tsx +87 -0
  168. package/carbon/src/client/components/LogoStrip.tsx +76 -0
  169. package/carbon/src/client/components/MetricsStrip.tsx +48 -0
  170. package/carbon/src/client/components/Nav.tsx +195 -0
  171. package/carbon/src/client/components/NewsletterSignup.tsx +147 -0
  172. package/carbon/src/client/components/NotificationDrawer.tsx +171 -0
  173. package/carbon/src/client/components/PageHeader.tsx +24 -0
  174. package/carbon/src/client/components/PlanGate.tsx +36 -0
  175. package/carbon/src/client/components/PricingSection.tsx +371 -0
  176. package/carbon/src/client/components/SEO.tsx +34 -0
  177. package/carbon/src/client/components/SmoothScroll.tsx +45 -0
  178. package/carbon/src/client/components/TechStackSection.tsx +165 -0
  179. package/carbon/src/client/components/WorkflowSection.tsx +604 -0
  180. package/carbon/src/client/components/admin/DockerLogs.tsx +276 -0
  181. package/carbon/src/client/components/admin/PerformanceMetrics.tsx +230 -0
  182. package/carbon/src/client/components/admin/ServiceCard.tsx +45 -0
  183. package/carbon/src/client/components/admin/ServicesStatus.tsx +296 -0
  184. package/carbon/src/client/components/architecture/ArchitectureDiagram.tsx +413 -0
  185. package/carbon/src/client/components/auth/AuthProvider.tsx +466 -0
  186. package/carbon/src/client/components/effects/FilmGrainOverlay.tsx +35 -0
  187. package/carbon/src/client/components/effects/FresnelEdge.tsx +49 -0
  188. package/carbon/src/client/components/effects/GlowTracker.tsx +46 -0
  189. package/carbon/src/client/components/effects/SparkBurst.tsx +145 -0
  190. package/carbon/src/client/components/effects/VGlowEffect.tsx +83 -0
  191. package/carbon/src/client/components/effects/index.ts +2 -0
  192. package/carbon/src/client/components/layouts/SidebarLayout.tsx +20 -0
  193. package/carbon/src/client/components/scroll/ScrollSection.tsx +76 -0
  194. package/carbon/src/client/components/scroll/ScrollytellingProvider.tsx +81 -0
  195. package/carbon/src/client/components/scroll/index.ts +2 -0
  196. package/carbon/src/client/components/ui/accordion.tsx +71 -0
  197. package/carbon/src/client/components/ui/alert-dialog.tsx +162 -0
  198. package/carbon/src/client/components/ui/alert.tsx +73 -0
  199. package/carbon/src/client/components/ui/aspect-ratio.tsx +22 -0
  200. package/carbon/src/client/components/ui/avatar.tsx +91 -0
  201. package/carbon/src/client/components/ui/badge.tsx +50 -0
  202. package/carbon/src/client/components/ui/breadcrumb.tsx +100 -0
  203. package/carbon/src/client/components/ui/button-group.tsx +78 -0
  204. package/carbon/src/client/components/ui/button.tsx +120 -0
  205. package/carbon/src/client/components/ui/calendar.tsx +182 -0
  206. package/carbon/src/client/components/ui/card.tsx +85 -0
  207. package/carbon/src/client/components/ui/carousel.tsx +227 -0
  208. package/carbon/src/client/components/ui/chart.tsx +357 -0
  209. package/carbon/src/client/components/ui/checkbox.tsx +27 -0
  210. package/carbon/src/client/components/ui/collapsible.tsx +15 -0
  211. package/carbon/src/client/components/ui/command.tsx +178 -0
  212. package/carbon/src/client/components/ui/context-menu.tsx +233 -0
  213. package/carbon/src/client/components/ui/dialog.tsx +132 -0
  214. package/carbon/src/client/components/ui/drawer.tsx +118 -0
  215. package/carbon/src/client/components/ui/dropdown-menu.tsx +242 -0
  216. package/carbon/src/client/components/ui/empty.tsx +94 -0
  217. package/carbon/src/client/components/ui/field.tsx +226 -0
  218. package/carbon/src/client/components/ui/hover-card.tsx +44 -0
  219. package/carbon/src/client/components/ui/input-group.tsx +146 -0
  220. package/carbon/src/client/components/ui/input-otp.tsx +83 -0
  221. package/carbon/src/client/components/ui/input.tsx +20 -0
  222. package/carbon/src/client/components/ui/item.tsx +188 -0
  223. package/carbon/src/client/components/ui/kbd.tsx +26 -0
  224. package/carbon/src/client/components/ui/label.tsx +21 -0
  225. package/carbon/src/client/components/ui/menubar.tsx +250 -0
  226. package/carbon/src/client/components/ui/navigation-menu.tsx +155 -0
  227. package/carbon/src/client/components/ui/pagination.tsx +102 -0
  228. package/carbon/src/client/components/ui/popover.tsx +75 -0
  229. package/carbon/src/client/components/ui/progress.tsx +66 -0
  230. package/carbon/src/client/components/ui/radio-group.tsx +36 -0
  231. package/carbon/src/client/components/ui/resizable.tsx +46 -0
  232. package/carbon/src/client/components/ui/scroll-area.tsx +48 -0
  233. package/carbon/src/client/components/ui/select.tsx +186 -0
  234. package/carbon/src/client/components/ui/separator.tsx +21 -0
  235. package/carbon/src/client/components/ui/sheet.tsx +124 -0
  236. package/carbon/src/client/components/ui/sidebar.tsx +702 -0
  237. package/carbon/src/client/components/ui/skeleton.tsx +13 -0
  238. package/carbon/src/client/components/ui/slider.tsx +57 -0
  239. package/carbon/src/client/components/ui/sonner.tsx +45 -0
  240. package/carbon/src/client/components/ui/spinner.tsx +15 -0
  241. package/carbon/src/client/components/ui/switch.tsx +30 -0
  242. package/carbon/src/client/components/ui/table.tsx +89 -0
  243. package/carbon/src/client/components/ui/tabs.tsx +73 -0
  244. package/carbon/src/client/components/ui/textarea.tsx +18 -0
  245. package/carbon/src/client/components/ui/toggle-group.tsx +87 -0
  246. package/carbon/src/client/components/ui/toggle.tsx +44 -0
  247. package/carbon/src/client/components/ui/tooltip.tsx +56 -0
  248. package/carbon/src/client/hooks/api/index.ts +14 -0
  249. package/carbon/src/client/hooks/api/useAuthSettings.ts +80 -0
  250. package/carbon/src/client/hooks/api/useSubscription.ts +87 -0
  251. package/carbon/src/client/hooks/use-mobile.ts +21 -0
  252. package/carbon/src/client/hooks/useMousePosition.ts +91 -0
  253. package/carbon/src/client/hooks/useNotifications.tsx +124 -0
  254. package/carbon/src/client/hooks/useOrganizationMembers.ts +127 -0
  255. package/carbon/src/client/hooks/useOrganizations.tsx +230 -0
  256. package/carbon/src/client/hooks/usePackageManager.ts +69 -0
  257. package/carbon/src/client/hooks/useReducedMotion.ts +20 -0
  258. package/carbon/src/client/hooks/useRunningServices.ts +114 -0
  259. package/carbon/src/client/hooks/useScrollProgress.ts +56 -0
  260. package/carbon/src/client/index.css +467 -0
  261. package/carbon/src/client/index.html +56 -0
  262. package/carbon/src/client/lib/admin-services.ts +151 -0
  263. package/carbon/src/client/lib/api.ts +32 -0
  264. package/carbon/src/client/lib/blog.ts +35 -0
  265. package/carbon/src/client/lib/changelog.ts +33 -0
  266. package/carbon/src/client/lib/docs-search.ts +101 -0
  267. package/carbon/src/client/lib/docs.ts +37 -0
  268. package/carbon/src/client/lib/i18n.ts +32 -0
  269. package/carbon/src/client/lib/supabase.ts +72 -0
  270. package/carbon/src/client/lib/tailwind-colors.ts +357 -0
  271. package/carbon/src/client/lib/theme.ts +117 -0
  272. package/carbon/src/client/lib/utils.ts +22 -0
  273. package/carbon/src/client/locales/de.json +529 -0
  274. package/carbon/src/client/locales/en.json +461 -0
  275. package/carbon/src/client/locales/es.json +529 -0
  276. package/carbon/src/client/locales/fr.json +529 -0
  277. package/carbon/src/client/locales/pt.json +529 -0
  278. package/carbon/src/client/main.tsx +56 -0
  279. package/carbon/src/client/mdx.d.ts +13 -0
  280. package/carbon/src/client/pages/ApiDocs.tsx +76 -0
  281. package/carbon/src/client/pages/AuthCallback.tsx +34 -0
  282. package/carbon/src/client/pages/Blog.tsx +167 -0
  283. package/carbon/src/client/pages/Changelog.tsx +171 -0
  284. package/carbon/src/client/pages/Charts.tsx +388 -0
  285. package/carbon/src/client/pages/Checkout.tsx +227 -0
  286. package/carbon/src/client/pages/Contact.tsx +174 -0
  287. package/carbon/src/client/pages/Dashboard.tsx +368 -0
  288. package/carbon/src/client/pages/Docs.tsx +372 -0
  289. package/carbon/src/client/pages/ForgotPassword.tsx +111 -0
  290. package/carbon/src/client/pages/Home.tsx +187 -0
  291. package/carbon/src/client/pages/Legal.tsx +100 -0
  292. package/carbon/src/client/pages/Login.tsx +408 -0
  293. package/carbon/src/client/pages/MFAVerify.tsx +156 -0
  294. package/carbon/src/client/pages/NotFound.tsx +21 -0
  295. package/carbon/src/client/pages/Onboarding.tsx +246 -0
  296. package/carbon/src/client/pages/ResetPassword.tsx +200 -0
  297. package/carbon/src/client/pages/UIComponents.tsx +390 -0
  298. package/carbon/src/client/pages/admin/ContactSubmissions.tsx +220 -0
  299. package/carbon/src/client/pages/admin/Dashboard.tsx +24 -0
  300. package/carbon/src/client/pages/admin/Infrastructure.tsx +257 -0
  301. package/carbon/src/client/pages/admin/Jobs.tsx +225 -0
  302. package/carbon/src/client/pages/admin/Logs.tsx +18 -0
  303. package/carbon/src/client/pages/admin/Newsletter.tsx +300 -0
  304. package/carbon/src/client/pages/admin/Notifications.tsx +603 -0
  305. package/carbon/src/client/pages/admin/Organizations.tsx +306 -0
  306. package/carbon/src/client/pages/admin/Settings.tsx +314 -0
  307. package/carbon/src/client/pages/admin/Theme.tsx +465 -0
  308. package/carbon/src/client/pages/admin/Users.tsx +365 -0
  309. package/carbon/src/client/pages/api-docs.css +156 -0
  310. package/carbon/src/client/pages/organizations/Details.tsx +200 -0
  311. package/carbon/src/client/pages/organizations/Members.tsx +402 -0
  312. package/carbon/src/client/pages/settings/Billing.tsx +473 -0
  313. package/carbon/src/client/pages/settings/Profile.tsx +160 -0
  314. package/carbon/src/client/pages/settings/Security.tsx +341 -0
  315. package/carbon/src/client/public/favicon.svg +19 -0
  316. package/carbon/src/client/public/robots.txt +8 -0
  317. package/carbon/src/server/billing/index.ts +104 -0
  318. package/carbon/src/server/billing/provider.ts +81 -0
  319. package/carbon/src/server/billing/providers/paddle.ts +314 -0
  320. package/carbon/src/server/billing/providers/polar.ts +325 -0
  321. package/carbon/src/server/billing/providers/stripe.ts +233 -0
  322. package/carbon/src/server/emails/templates.ts +116 -0
  323. package/carbon/src/server/index.ts +554 -0
  324. package/carbon/src/server/lib/auth.ts +6 -0
  325. package/carbon/src/server/lib/email.ts +64 -0
  326. package/carbon/src/server/lib/env.ts +112 -0
  327. package/carbon/src/server/lib/errors.ts +21 -0
  328. package/carbon/src/server/lib/logger.ts +17 -0
  329. package/carbon/src/server/lib/rate-limiter.ts +288 -0
  330. package/carbon/src/server/lib/request.ts +34 -0
  331. package/carbon/src/server/lib/stripe.ts +42 -0
  332. package/carbon/src/server/lib/supabase.ts +65 -0
  333. package/carbon/src/server/middleware/requirePlan.ts +80 -0
  334. package/carbon/src/server/routes/_internal/services-status.ts +958 -0
  335. package/carbon/src/server/routes/_internal/verify-role.ts +185 -0
  336. package/carbon/src/server/routes/health.ts +48 -0
  337. package/carbon/src/server/routes/v1/admin/contact.ts +128 -0
  338. package/carbon/src/server/routes/v1/admin/jobs.ts +171 -0
  339. package/carbon/src/server/routes/v1/admin/newsletter.ts +237 -0
  340. package/carbon/src/server/routes/v1/auth.ts +390 -0
  341. package/carbon/src/server/routes/v1/billing.ts +718 -0
  342. package/carbon/src/server/routes/v1/contact.ts +93 -0
  343. package/carbon/src/server/routes/v1/index.ts +1333 -0
  344. package/carbon/src/server/routes/v1/newsletter.ts +181 -0
  345. package/carbon/src/server/routes/v1/performance.ts +157 -0
  346. package/carbon/src/server/routes/v1/stats.ts +170 -0
  347. package/carbon/src/server/routes/v1/theme.ts +106 -0
  348. package/carbon/src/server/routes/webhooks/billing.ts +376 -0
  349. package/carbon/src/server/routes/webhooks/stripe.ts +276 -0
  350. package/carbon/src/server/types.ts +11 -0
  351. package/carbon/src/shared/pricing.ts +155 -0
  352. package/carbon/src/shared/types.ts +338 -0
  353. package/carbon/supabase/migrations/00001_init.sql +717 -0
  354. package/carbon/supabase/migrations/00002_theme_settings.sql +13 -0
  355. package/carbon/supabase/migrations/00003_pg_cron.sql +121 -0
  356. package/carbon/supabase/migrations/00004_contact_newsletter.sql +81 -0
  357. package/carbon/supabase/migrations/00005_localization_languages.sql +22 -0
  358. package/carbon/supabase/seed.sql +16 -0
  359. package/carbon/tests/_helpers/app.ts +45 -0
  360. package/carbon/tests/_helpers/env.ts +37 -0
  361. package/carbon/tests/_helpers/factories.ts +69 -0
  362. package/carbon/tests/_helpers/jwt.ts +23 -0
  363. package/carbon/tests/_helpers/setup-integration.ts +20 -0
  364. package/carbon/tests/_helpers/setup-rtl.ts +12 -0
  365. package/carbon/tests/component/ErrorBoundary.test.tsx +53 -0
  366. package/carbon/tests/component/use-auth-settings.test.tsx +119 -0
  367. package/carbon/tests/integration/server/routes/contact.test.ts +162 -0
  368. package/carbon/tests/integration/server/routes/health.test.ts +61 -0
  369. package/carbon/tests/structural/i18n-parity.test.ts +42 -0
  370. package/carbon/tests/unit/client/utils.test.ts +49 -0
  371. package/carbon/tests/unit/shared/pricing.test.ts +93 -0
  372. package/carbon/tsconfig.json +27 -0
  373. package/carbon/tsconfig.server.json +27 -0
  374. package/carbon/tsconfig.test.json +9 -0
  375. package/carbon/vite.config.ts +110 -0
  376. package/carbon/vitest.config.ts +74 -0
  377. package/carbon/volumes/db/jwt.sql +57 -0
  378. package/carbon/volumes/db/metabase-init.sh +29 -0
  379. package/carbon/volumes/db/n8n-init.sh +25 -0
  380. package/carbon/volumes/db/realtime.sql +33 -0
  381. package/carbon/volumes/db/roles.sql +93 -0
  382. package/carbon/volumes/db/set-passwords.sh +12 -0
  383. package/carbon/volumes/db/super-admin.dev.sql +113 -0
  384. package/carbon/volumes/db/super-admin.generated.sql +113 -0
  385. package/carbon/volumes/db/super-admin.sql +114 -0
  386. package/carbon/volumes/grafana/dashboards/logs.json +179 -0
  387. package/carbon/volumes/grafana/dashboards/overview.json +523 -0
  388. package/carbon/volumes/grafana/dashboards/postgresql.json +337 -0
  389. package/carbon/volumes/grafana/dashboards.dev/logs.json +179 -0
  390. package/carbon/volumes/grafana/dashboards.dev/overview.json +156 -0
  391. package/carbon/volumes/grafana/dashboards.dev/postgresql.json +337 -0
  392. package/carbon/volumes/grafana/provisioning/dashboards/dashboards.dev.yml +16 -0
  393. package/carbon/volumes/grafana/provisioning/dashboards/dashboards.yml +16 -0
  394. package/carbon/volumes/grafana/provisioning/datasources/datasources.yml +43 -0
  395. package/carbon/volumes/kong/docker-entrypoint.sh +9 -0
  396. package/carbon/volumes/kong/kong.yml +208 -0
  397. package/carbon/volumes/loki/loki-config.yml +58 -0
  398. package/carbon/volumes/n8n/hooks.js +131 -0
  399. package/carbon/volumes/n8n/scripts/setup.sh +66 -0
  400. package/carbon/volumes/prometheus/prometheus.yml +43 -0
  401. package/carbon/volumes/promtail/promtail-config.yml +64 -0
  402. package/carbon/volumes/traefik/middlewares.dev.yml +83 -0
  403. package/carbon/volumes/traefik/middlewares.yml +95 -0
  404. package/carbon/volumes/traefik/vite-dev.yml +20 -0
  405. package/package.json +95 -0
  406. package/src/access.js +354 -0
  407. package/src/activate.js +187 -0
  408. package/src/add.js +718 -0
  409. package/src/backup.js +786 -0
  410. package/src/cli.js +350 -0
  411. package/src/configure.js +967 -0
  412. package/src/console.js +155 -0
  413. package/src/create.js +1499 -0
  414. package/src/deploy.js +311 -0
  415. package/src/destroy.js +2033 -0
  416. package/src/diagnose.js +735 -0
  417. package/src/down.js +80 -0
  418. package/src/failover.js +1032 -0
  419. package/src/lib/backup-s3.js +179 -0
  420. package/src/lib/build.js +33 -0
  421. package/src/lib/checksum.js +28 -0
  422. package/src/lib/ci-setup.js +666 -0
  423. package/src/lib/cli/help.js +129 -0
  424. package/src/lib/cli/parse-flags.js +160 -0
  425. package/src/lib/cli/select-action.js +65 -0
  426. package/src/lib/cli/select-environment.js +108 -0
  427. package/src/lib/cli/tty-guard.js +75 -0
  428. package/src/lib/cloudflare.js +447 -0
  429. package/src/lib/colors.js +52 -0
  430. package/src/lib/command.js +361 -0
  431. package/src/lib/config.js +359 -0
  432. package/src/lib/cost.js +103 -0
  433. package/src/lib/deploy/bundle.js +231 -0
  434. package/src/lib/deploy/compose/acme-verify.js +121 -0
  435. package/src/lib/deploy/compose/build-args.js +78 -0
  436. package/src/lib/deploy/compose/ha.js +1874 -0
  437. package/src/lib/deploy/compose/index.js +1294 -0
  438. package/src/lib/deploy/compose/reconcile.js +74 -0
  439. package/src/lib/deploy/github.js +382 -0
  440. package/src/lib/deploy/image.js +191 -0
  441. package/src/lib/deploy/index.js +119 -0
  442. package/src/lib/deploy/k8s/LICENSE +99 -0
  443. package/src/lib/deploy/k8s/gitops-deploy.js +298 -0
  444. package/src/lib/deploy/k8s/ha/index.js +1000 -0
  445. package/src/lib/deploy/k8s/index.js +62 -0
  446. package/src/lib/deploy/k8s/k3s.js +2515 -0
  447. package/src/lib/deploy/orchestrator.js +1401 -0
  448. package/src/lib/deploy/prompts.js +545 -0
  449. package/src/lib/deploy/remote-build.js +130 -0
  450. package/src/lib/deploy/state.js +120 -0
  451. package/src/lib/deploy/utils.js +328 -0
  452. package/src/lib/deploy-logger.js +93 -0
  453. package/src/lib/dns-propagation.js +48 -0
  454. package/src/lib/environment.js +58 -0
  455. package/src/lib/fetch-retry.js +103 -0
  456. package/src/lib/github-environments.js +335 -0
  457. package/src/lib/hetzner-dns.js +377 -0
  458. package/src/lib/hetzner-guided-setup.js +275 -0
  459. package/src/lib/host-keys.js +37 -0
  460. package/src/lib/iac/cloud-init.js +52 -0
  461. package/src/lib/iac/index.js +325 -0
  462. package/src/lib/iac/programs/hetzner-compose.js +130 -0
  463. package/src/lib/iac/programs/hetzner-k8s.js +320 -0
  464. package/src/lib/kubectl.js +81 -0
  465. package/src/lib/licensing/index.js +259 -0
  466. package/src/lib/licensing/tiers.js +181 -0
  467. package/src/lib/licensing/validator.js +171 -0
  468. package/src/lib/merge-package-json.js +90 -0
  469. package/src/lib/operator-ip.js +381 -0
  470. package/src/lib/package-manager.js +111 -0
  471. package/src/lib/perf.js +71 -0
  472. package/src/lib/project-guard.js +39 -0
  473. package/src/lib/project.js +334 -0
  474. package/src/lib/providers/base.js +276 -0
  475. package/src/lib/providers/hetzner-s3.js +656 -0
  476. package/src/lib/providers/hetzner.js +755 -0
  477. package/src/lib/providers/index.js +164 -0
  478. package/src/lib/s3.js +510 -0
  479. package/src/lib/secret-scan.js +583 -0
  480. package/src/lib/secrets.js +63 -0
  481. package/src/lib/server-types.js +195 -0
  482. package/src/lib/shell.js +91 -0
  483. package/src/lib/ssh.js +241 -0
  484. package/src/lib/tracker.js +242 -0
  485. package/src/lib/upgrade-policy.js +170 -0
  486. package/src/lib/validators.js +105 -0
  487. package/src/lib/version.js +5 -0
  488. package/src/remove.js +292 -0
  489. package/src/reset.js +97 -0
  490. package/src/restore.js +871 -0
  491. package/src/scale.js +1734 -0
  492. package/src/shell.js +222 -0
  493. package/src/status.js +981 -0
  494. package/src/up.js +264 -0
  495. package/src/upgrade.js +721 -0
@@ -0,0 +1,702 @@
1
+ import { mergeProps } from '@base-ui/react/merge-props';
2
+ import { useRender } from '@base-ui/react/use-render';
3
+ import { cva, type VariantProps } from 'class-variance-authority';
4
+ import { PanelLeftIcon } from 'lucide-react';
5
+ import * as React from 'react';
6
+ import { Button } from '@/components/ui/button';
7
+ import { Input } from '@/components/ui/input';
8
+ import { Separator } from '@/components/ui/separator';
9
+ import {
10
+ Sheet,
11
+ SheetContent,
12
+ SheetDescription,
13
+ SheetHeader,
14
+ SheetTitle,
15
+ } from '@/components/ui/sheet';
16
+ import { Skeleton } from '@/components/ui/skeleton';
17
+ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
18
+ import { useIsMobile } from '@/hooks/use-mobile';
19
+ import { cn } from '@/lib/utils';
20
+
21
+ const SIDEBAR_COOKIE_NAME = 'sidebar_state';
22
+ const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
23
+ const SIDEBAR_WIDTH = '15rem';
24
+ const SIDEBAR_WIDTH_MOBILE = '18rem';
25
+ const SIDEBAR_WIDTH_ICON = '5.5rem';
26
+ const SIDEBAR_KEYBOARD_SHORTCUT = 'b';
27
+
28
+ type SidebarContextProps = {
29
+ state: 'expanded' | 'collapsed';
30
+ open: boolean;
31
+ setOpen: (open: boolean) => void;
32
+ openMobile: boolean;
33
+ setOpenMobile: (open: boolean) => void;
34
+ isMobile: boolean;
35
+ toggleSidebar: () => void;
36
+ };
37
+
38
+ const SidebarContext = React.createContext<SidebarContextProps | null>(null);
39
+
40
+ function useSidebar() {
41
+ const context = React.useContext(SidebarContext);
42
+ if (!context) {
43
+ throw new Error('useSidebar must be used within a SidebarProvider.');
44
+ }
45
+
46
+ return context;
47
+ }
48
+
49
+ function SidebarProvider({
50
+ defaultOpen = true,
51
+ open: openProp,
52
+ onOpenChange: setOpenProp,
53
+ className,
54
+ style,
55
+ children,
56
+ ...props
57
+ }: React.ComponentProps<'div'> & {
58
+ defaultOpen?: boolean;
59
+ open?: boolean;
60
+ onOpenChange?: (open: boolean) => void;
61
+ }) {
62
+ const isMobile = useIsMobile();
63
+ const [openMobile, setOpenMobile] = React.useState(false);
64
+
65
+ // Read initial state from cookie, falling back to defaultOpen
66
+ const getInitialOpen = () => {
67
+ if (typeof document === 'undefined') return defaultOpen;
68
+ const cookie = document.cookie
69
+ .split('; ')
70
+ .find((row) => row.startsWith(`${SIDEBAR_COOKIE_NAME}=`));
71
+ if (cookie) {
72
+ return cookie.split('=')[1] === 'true';
73
+ }
74
+ return defaultOpen;
75
+ };
76
+
77
+ // This is the internal state of the sidebar.
78
+ // We use openProp and setOpenProp for control from outside the component.
79
+ const [_open, _setOpen] = React.useState(getInitialOpen);
80
+ const open = openProp ?? _open;
81
+ const setOpen = React.useCallback(
82
+ (value: boolean | ((value: boolean) => boolean)) => {
83
+ const openState = typeof value === 'function' ? value(open) : value;
84
+ if (setOpenProp) {
85
+ setOpenProp(openState);
86
+ } else {
87
+ _setOpen(openState);
88
+ }
89
+
90
+ // This sets the cookie to keep the sidebar state.
91
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
92
+ },
93
+ [setOpenProp, open]
94
+ );
95
+
96
+ // Helper to toggle the sidebar.
97
+ const toggleSidebar = React.useCallback(() => {
98
+ return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
99
+ }, [isMobile, setOpen]);
100
+
101
+ // Adds a keyboard shortcut to toggle the sidebar.
102
+ React.useEffect(() => {
103
+ const handleKeyDown = (event: KeyboardEvent) => {
104
+ if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
105
+ event.preventDefault();
106
+ toggleSidebar();
107
+ }
108
+ };
109
+
110
+ window.addEventListener('keydown', handleKeyDown);
111
+ return () => window.removeEventListener('keydown', handleKeyDown);
112
+ }, [toggleSidebar]);
113
+
114
+ // We add a state so that we can do data-state="expanded" or "collapsed".
115
+ // This makes it easier to style the sidebar with Tailwind classes.
116
+ const state = open ? 'expanded' : 'collapsed';
117
+
118
+ const contextValue = React.useMemo<SidebarContextProps>(
119
+ () => ({
120
+ state,
121
+ open,
122
+ setOpen,
123
+ isMobile,
124
+ openMobile,
125
+ setOpenMobile,
126
+ toggleSidebar,
127
+ }),
128
+ [state, open, setOpen, isMobile, openMobile, toggleSidebar]
129
+ );
130
+
131
+ return (
132
+ <SidebarContext.Provider value={contextValue}>
133
+ <div
134
+ data-slot="sidebar-wrapper"
135
+ style={
136
+ {
137
+ '--sidebar-width': SIDEBAR_WIDTH,
138
+ '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
139
+ ...style,
140
+ } as React.CSSProperties
141
+ }
142
+ className={cn(
143
+ 'group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full',
144
+ className
145
+ )}
146
+ {...props}
147
+ >
148
+ {children}
149
+ </div>
150
+ </SidebarContext.Provider>
151
+ );
152
+ }
153
+
154
+ function Sidebar({
155
+ side = 'left',
156
+ variant = 'sidebar',
157
+ collapsible = 'offExamples',
158
+ className,
159
+ children,
160
+ ...props
161
+ }: React.ComponentProps<'div'> & {
162
+ side?: 'left' | 'right';
163
+ variant?: 'sidebar' | 'floating' | 'inset';
164
+ collapsible?: 'offExamples' | 'icon' | 'none';
165
+ }) {
166
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
167
+
168
+ if (collapsible === 'none') {
169
+ return (
170
+ <div
171
+ data-slot="sidebar"
172
+ className={cn(
173
+ 'bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col',
174
+ className
175
+ )}
176
+ {...props}
177
+ >
178
+ {children}
179
+ </div>
180
+ );
181
+ }
182
+
183
+ if (isMobile) {
184
+ return (
185
+ <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
186
+ <SheetContent
187
+ data-sidebar="sidebar"
188
+ data-slot="sidebar"
189
+ data-mobile="true"
190
+ className="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
191
+ style={
192
+ {
193
+ '--sidebar-width': SIDEBAR_WIDTH_MOBILE,
194
+ } as React.CSSProperties
195
+ }
196
+ side={side}
197
+ >
198
+ <SheetHeader className="sr-only">
199
+ <SheetTitle>Sidebar</SheetTitle>
200
+ <SheetDescription>Displays the mobile sidebar.</SheetDescription>
201
+ </SheetHeader>
202
+ <div className="flex h-full w-full flex-col gap-6 p-6">{children}</div>
203
+ </SheetContent>
204
+ </Sheet>
205
+ );
206
+ }
207
+
208
+ return (
209
+ <div
210
+ className="group peer text-sidebar-foreground hidden md:block"
211
+ data-state={state}
212
+ data-collapsible={state === 'collapsed' ? collapsible : ''}
213
+ data-variant={variant}
214
+ data-side={side}
215
+ data-slot="sidebar"
216
+ >
217
+ {/* This is what handles the sidebar gap on desktop */}
218
+ <div
219
+ data-slot="sidebar-gap"
220
+ className={cn(
221
+ 'transition-[width] duration-300 ease-in-out relative w-(--sidebar-width) bg-transparent will-change-[width]',
222
+ 'group-data-[collapsible=offExamples]:w-0',
223
+ 'group-data-[side=right]:rotate-180',
224
+ variant === 'floating' || variant === 'inset'
225
+ ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]'
226
+ : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)'
227
+ )}
228
+ />
229
+ <div
230
+ data-slot="sidebar-container"
231
+ className={cn(
232
+ 'fixed bottom-0 z-10 hidden w-(--sidebar-width) transition-[left,right,width] duration-300 ease-in-out md:flex will-change-[width]',
233
+ side === 'left'
234
+ ? 'left-0 group-data-[collapsible=offExamples]:left-[calc(var(--sidebar-width)*-1)]'
235
+ : 'right-0 group-data-[collapsible=offExamples]:right-[calc(var(--sidebar-width)*-1)]',
236
+ // Adjust the padding for floating and inset variants.
237
+ variant === 'floating' || variant === 'inset'
238
+ ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'
239
+ : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
240
+ className
241
+ )}
242
+ style={{ top: 'var(--notification-bar-h, 0px)' }}
243
+ {...props}
244
+ >
245
+ <div
246
+ data-sidebar="sidebar"
247
+ data-slot="sidebar-inner"
248
+ className="bg-sidebar group-data-[variant=floating]:ring-sidebar-border group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1 flex size-full flex-col gap-6 p-6"
249
+ >
250
+ {children}
251
+ </div>
252
+ </div>
253
+ </div>
254
+ );
255
+ }
256
+
257
+ function SidebarTrigger({ className, onClick, ...props }: React.ComponentProps<typeof Button>) {
258
+ const { toggleSidebar } = useSidebar();
259
+
260
+ return (
261
+ <Button
262
+ data-sidebar="trigger"
263
+ data-slot="sidebar-trigger"
264
+ variant="ghost"
265
+ size="icon-sm"
266
+ className={cn(className)}
267
+ onClick={(event) => {
268
+ onClick?.(event);
269
+ toggleSidebar();
270
+ }}
271
+ {...props}
272
+ >
273
+ <PanelLeftIcon />
274
+ <span className="sr-only">Toggle Sidebar</span>
275
+ </Button>
276
+ );
277
+ }
278
+
279
+ function SidebarRail({ className, ...props }: React.ComponentProps<'button'>) {
280
+ const { toggleSidebar } = useSidebar();
281
+
282
+ return (
283
+ <button
284
+ data-sidebar="rail"
285
+ data-slot="sidebar-rail"
286
+ aria-label="Toggle Sidebar"
287
+ tabIndex={-1}
288
+ onClick={toggleSidebar}
289
+ title="Toggle Sidebar"
290
+ className={cn(
291
+ 'hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex',
292
+ 'in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize',
293
+ '[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize',
294
+ 'hover:group-data-[collapsible=offExamples]:bg-sidebar group-data-[collapsible=offExamples]:translate-x-0 group-data-[collapsible=offExamples]:after:left-full',
295
+ '[[data-side=left][data-collapsible=offExamples]_&]:-right-2',
296
+ '[[data-side=right][data-collapsible=offExamples]_&]:-left-2',
297
+ className
298
+ )}
299
+ {...props}
300
+ />
301
+ );
302
+ }
303
+
304
+ function SidebarInset({ className, ...props }: React.ComponentProps<'main'>) {
305
+ return (
306
+ <main
307
+ data-slot="sidebar-inset"
308
+ className={cn(
309
+ 'bg-background md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2 relative flex min-w-0 flex-1 flex-col overflow-x-hidden',
310
+ className
311
+ )}
312
+ {...props}
313
+ />
314
+ );
315
+ }
316
+
317
+ function SidebarInput({ className, ...props }: React.ComponentProps<typeof Input>) {
318
+ return (
319
+ <Input
320
+ data-slot="sidebar-input"
321
+ data-sidebar="input"
322
+ className={cn('bg-background h-8 w-full shadow-none', className)}
323
+ {...props}
324
+ />
325
+ );
326
+ }
327
+
328
+ function SidebarHeader({ className, ...props }: React.ComponentProps<'div'>) {
329
+ return (
330
+ <div
331
+ data-slot="sidebar-header"
332
+ data-sidebar="header"
333
+ className={cn('gap-2 flex flex-col', className)}
334
+ {...props}
335
+ />
336
+ );
337
+ }
338
+
339
+ function SidebarFooter({ className, ...props }: React.ComponentProps<'div'>) {
340
+ return (
341
+ <div
342
+ data-slot="sidebar-footer"
343
+ data-sidebar="footer"
344
+ className={cn('gap-2 flex flex-col', className)}
345
+ {...props}
346
+ />
347
+ );
348
+ }
349
+
350
+ function SidebarSeparator({ className, ...props }: React.ComponentProps<typeof Separator>) {
351
+ return (
352
+ <Separator
353
+ data-slot="sidebar-separator"
354
+ data-sidebar="separator"
355
+ className={cn('bg-sidebar-border w-auto', className)}
356
+ {...props}
357
+ />
358
+ );
359
+ }
360
+
361
+ function SidebarContent({ className, ...props }: React.ComponentProps<'div'>) {
362
+ return (
363
+ <div
364
+ data-slot="sidebar-content"
365
+ data-sidebar="content"
366
+ className={cn(
367
+ 'no-scrollbar gap-6 flex min-h-0 flex-1 flex-col overflow-auto group-data-[collapsible=icon]:overflow-clip',
368
+ className
369
+ )}
370
+ {...props}
371
+ />
372
+ );
373
+ }
374
+
375
+ function SidebarGroup({ className, ...props }: React.ComponentProps<'div'>) {
376
+ return (
377
+ <div
378
+ data-slot="sidebar-group"
379
+ data-sidebar="group"
380
+ className={cn('relative flex w-full min-w-0 flex-col', className)}
381
+ {...props}
382
+ />
383
+ );
384
+ }
385
+
386
+ function SidebarGroupLabel({
387
+ className,
388
+ render,
389
+ ...props
390
+ }: useRender.ComponentProps<'div'> & React.ComponentProps<'div'>) {
391
+ return useRender({
392
+ defaultTagName: 'div',
393
+ props: mergeProps<'div'>(
394
+ {
395
+ className: cn(
396
+ 'text-sidebar-foreground/70 ring-sidebar-ring h-8 rounded-md px-2 text-xs font-medium transition-[margin,opacity] duration-300 ease-in-out group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 group-data-[collapsible=icon]:pointer-events-none focus-visible:ring-2 [&>svg]:size-4 flex shrink-0 items-center outline-hidden [&>svg]:shrink-0',
397
+ className
398
+ ),
399
+ },
400
+ props
401
+ ),
402
+ render,
403
+ state: {
404
+ slot: 'sidebar-group-label',
405
+ sidebar: 'group-label',
406
+ },
407
+ });
408
+ }
409
+
410
+ function SidebarGroupAction({
411
+ className,
412
+ render,
413
+ ...props
414
+ }: useRender.ComponentProps<'button'> & React.ComponentProps<'button'>) {
415
+ return useRender({
416
+ defaultTagName: 'button',
417
+ props: mergeProps<'button'>(
418
+ {
419
+ className: cn(
420
+ 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 w-5 rounded-md p-0 focus-visible:ring-2 [&>svg]:size-4 flex aspect-square items-center justify-center outline-hidden transition-[transform,background-color,color] [&>svg]:shrink-0 after:absolute after:-inset-2 md:after:hidden group-data-[collapsible=icon]:hidden',
421
+ className
422
+ ),
423
+ },
424
+ props
425
+ ),
426
+ render,
427
+ state: {
428
+ slot: 'sidebar-group-action',
429
+ sidebar: 'group-action',
430
+ },
431
+ });
432
+ }
433
+
434
+ function SidebarGroupContent({ className, ...props }: React.ComponentProps<'div'>) {
435
+ return (
436
+ <div
437
+ data-slot="sidebar-group-content"
438
+ data-sidebar="group-content"
439
+ className={cn('text-sm w-full', className)}
440
+ {...props}
441
+ />
442
+ );
443
+ }
444
+
445
+ function SidebarMenu({ className, ...props }: React.ComponentProps<'ul'>) {
446
+ return (
447
+ <ul
448
+ data-slot="sidebar-menu"
449
+ data-sidebar="menu"
450
+ className={cn('gap-2 flex w-full min-w-0 flex-col', className)}
451
+ {...props}
452
+ />
453
+ );
454
+ }
455
+
456
+ function SidebarMenuItem({ className, ...props }: React.ComponentProps<'li'>) {
457
+ return (
458
+ <li
459
+ data-slot="sidebar-menu-item"
460
+ data-sidebar="menu-item"
461
+ className={cn('group/menu-item relative', className)}
462
+ {...props}
463
+ />
464
+ );
465
+ }
466
+
467
+ const sidebarMenuButtonVariants = cva(
468
+ 'ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground gap-2 rounded-md p-2 text-left text-sm transition-[width,height,padding,background-color,color] duration-75 group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-10! group-data-[collapsible=icon]:p-0! group-data-[collapsible=icon]:justify-center focus-visible:ring-2 data-active:font-medium peer/menu-button flex w-full items-center overflow-hidden outline-hidden group/menu-button disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&_svg]:size-4 [&_svg]:shrink-0',
469
+ {
470
+ variants: {
471
+ variant: {
472
+ default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
473
+ outline:
474
+ 'bg-background hover:bg-sidebar-accent hover:text-sidebar-accent-foreground shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]',
475
+ },
476
+ size: {
477
+ default: 'h-10 text-sm',
478
+ sm: 'h-7 text-xs',
479
+ lg: 'h-12 text-sm group-data-[collapsible=icon]:p-0!',
480
+ },
481
+ },
482
+ defaultVariants: {
483
+ variant: 'default',
484
+ size: 'default',
485
+ },
486
+ }
487
+ );
488
+
489
+ function SidebarMenuButton({
490
+ render,
491
+ isActive = false,
492
+ variant = 'default',
493
+ size = 'default',
494
+ tooltip,
495
+ className,
496
+ ...props
497
+ }: useRender.ComponentProps<'button'> &
498
+ React.ComponentProps<'button'> & {
499
+ isActive?: boolean;
500
+ tooltip?: string | React.ComponentProps<typeof TooltipContent>;
501
+ } & VariantProps<typeof sidebarMenuButtonVariants>) {
502
+ const { isMobile, state } = useSidebar();
503
+ const comp = useRender({
504
+ defaultTagName: 'button',
505
+ props: mergeProps<'button'>(
506
+ {
507
+ className: cn(sidebarMenuButtonVariants({ variant, size }), className),
508
+ },
509
+ props
510
+ ),
511
+ render: !tooltip ? render : TooltipTrigger,
512
+ state: {
513
+ slot: 'sidebar-menu-button',
514
+ sidebar: 'menu-button',
515
+ size,
516
+ active: isActive,
517
+ },
518
+ });
519
+
520
+ if (!tooltip) {
521
+ return comp;
522
+ }
523
+
524
+ if (typeof tooltip === 'string') {
525
+ tooltip = {
526
+ children: tooltip,
527
+ };
528
+ }
529
+
530
+ return (
531
+ <Tooltip>
532
+ {comp}
533
+ <TooltipContent
534
+ side="right"
535
+ align="center"
536
+ hidden={state !== 'collapsed' || isMobile}
537
+ {...tooltip}
538
+ />
539
+ </Tooltip>
540
+ );
541
+ }
542
+
543
+ function SidebarMenuAction({
544
+ className,
545
+ render,
546
+ showOnHover = false,
547
+ ...props
548
+ }: useRender.ComponentProps<'button'> &
549
+ React.ComponentProps<'button'> & {
550
+ showOnHover?: boolean;
551
+ }) {
552
+ return useRender({
553
+ defaultTagName: 'button',
554
+ props: mergeProps<'button'>(
555
+ {
556
+ className: cn(
557
+ 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 aspect-square w-5 rounded-md p-0 peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 focus-visible:ring-2 [&>svg]:size-4 flex items-center justify-center outline-hidden transition-[transform,background-color,color] group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 md:after:hidden [&>svg]:shrink-0',
558
+ showOnHover &&
559
+ 'peer-data-active/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-open:opacity-100 md:opacity-0',
560
+ className
561
+ ),
562
+ },
563
+ props
564
+ ),
565
+ render,
566
+ state: {
567
+ slot: 'sidebar-menu-action',
568
+ sidebar: 'menu-action',
569
+ },
570
+ });
571
+ }
572
+
573
+ function SidebarMenuBadge({ className, ...props }: React.ComponentProps<'div'>) {
574
+ return (
575
+ <div
576
+ data-slot="sidebar-menu-badge"
577
+ data-sidebar="menu-badge"
578
+ className={cn(
579
+ 'text-sidebar-foreground peer-hover/menu-button:text-sidebar-accent-foreground peer-data-active/menu-button:text-sidebar-accent-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 rounded-md px-1 text-xs font-medium peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 flex items-center justify-center tabular-nums select-none group-data-[collapsible=icon]:hidden',
580
+ className
581
+ )}
582
+ {...props}
583
+ />
584
+ );
585
+ }
586
+
587
+ function SidebarMenuSkeleton({
588
+ className,
589
+ showIcon = false,
590
+ ...props
591
+ }: React.ComponentProps<'div'> & {
592
+ showIcon?: boolean;
593
+ }) {
594
+ // Random width between 50 to 90%.
595
+ const [width] = React.useState(() => {
596
+ return `${Math.floor(Math.random() * 40) + 50}%`;
597
+ });
598
+
599
+ return (
600
+ <div
601
+ data-slot="sidebar-menu-skeleton"
602
+ data-sidebar="menu-skeleton"
603
+ className={cn('h-8 gap-2 rounded-md px-2 flex items-center', className)}
604
+ {...props}
605
+ >
606
+ {showIcon && <Skeleton className="size-4 rounded-md" data-sidebar="menu-skeleton-icon" />}
607
+ <Skeleton
608
+ className="h-4 max-w-(--skeleton-width) flex-1"
609
+ data-sidebar="menu-skeleton-text"
610
+ style={
611
+ {
612
+ '--skeleton-width': width,
613
+ } as React.CSSProperties
614
+ }
615
+ />
616
+ </div>
617
+ );
618
+ }
619
+
620
+ function SidebarMenuSub({ className, ...props }: React.ComponentProps<'ul'>) {
621
+ return (
622
+ <ul
623
+ data-slot="sidebar-menu-sub"
624
+ data-sidebar="menu-sub"
625
+ className={cn(
626
+ 'border-sidebar-border mx-3.5 translate-x-px gap-1 border-l px-2.5 py-0.5 group-data-[collapsible=icon]:hidden flex min-w-0 flex-col',
627
+ className
628
+ )}
629
+ {...props}
630
+ />
631
+ );
632
+ }
633
+
634
+ function SidebarMenuSubItem({ className, ...props }: React.ComponentProps<'li'>) {
635
+ return (
636
+ <li
637
+ data-slot="sidebar-menu-sub-item"
638
+ data-sidebar="menu-sub-item"
639
+ className={cn('group/menu-sub-item relative', className)}
640
+ {...props}
641
+ />
642
+ );
643
+ }
644
+
645
+ function SidebarMenuSubButton({
646
+ render,
647
+ size = 'md',
648
+ isActive = false,
649
+ className,
650
+ ...props
651
+ }: useRender.ComponentProps<'a'> &
652
+ React.ComponentProps<'a'> & {
653
+ size?: 'sm' | 'md';
654
+ isActive?: boolean;
655
+ }) {
656
+ return useRender({
657
+ defaultTagName: 'a',
658
+ props: mergeProps<'a'>(
659
+ {
660
+ className: cn(
661
+ 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground h-7 gap-2 rounded-md px-2 focus-visible:ring-2 data-[size=md]:text-sm data-[size=sm]:text-xs [&>svg]:size-4 flex min-w-0 -translate-x-px items-center overflow-hidden outline-hidden transition-colors group-data-[collapsible=icon]:hidden disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:shrink-0',
662
+ className
663
+ ),
664
+ },
665
+ props
666
+ ),
667
+ render,
668
+ state: {
669
+ slot: 'sidebar-menu-sub-button',
670
+ sidebar: 'menu-sub-button',
671
+ size,
672
+ active: isActive,
673
+ },
674
+ });
675
+ }
676
+
677
+ export {
678
+ Sidebar,
679
+ SidebarContent,
680
+ SidebarFooter,
681
+ SidebarGroup,
682
+ SidebarGroupAction,
683
+ SidebarGroupContent,
684
+ SidebarGroupLabel,
685
+ SidebarHeader,
686
+ SidebarInput,
687
+ SidebarInset,
688
+ SidebarMenu,
689
+ SidebarMenuAction,
690
+ SidebarMenuBadge,
691
+ SidebarMenuButton,
692
+ SidebarMenuItem,
693
+ SidebarMenuSkeleton,
694
+ SidebarMenuSub,
695
+ SidebarMenuSubButton,
696
+ SidebarMenuSubItem,
697
+ SidebarProvider,
698
+ SidebarRail,
699
+ SidebarSeparator,
700
+ SidebarTrigger,
701
+ useSidebar,
702
+ };
@@ -0,0 +1,13 @@
1
+ import { cn } from '@/lib/utils';
2
+
3
+ function Skeleton({ className, ...props }: React.ComponentProps<'div'>) {
4
+ return (
5
+ <div
6
+ data-slot="skeleton"
7
+ className={cn('bg-muted rounded-xl animate-pulse', className)}
8
+ {...props}
9
+ />
10
+ );
11
+ }
12
+
13
+ export { Skeleton };