create-freakpunch 0.0.0-stage → 0.2.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 (216) hide show
  1. package/README.md +24 -3
  2. package/bin/create-freakpunch.mjs +227 -0
  3. package/files/README.md +19 -0
  4. package/files/app.config.ts +50 -0
  5. package/files/locales.ts +10 -0
  6. package/files/registry.ts +17 -0
  7. package/package.json +23 -6
  8. package/template/.dockerignore +17 -0
  9. package/template/.oxlintrc.json +9 -0
  10. package/template/AGENTS.md +6 -0
  11. package/template/BACKEND.md +108 -0
  12. package/template/CLAUDE.md +297 -0
  13. package/template/Dockerfile +19 -0
  14. package/template/_gitignore +26 -0
  15. package/template/components.json +27 -0
  16. package/template/design/COMPONENTS.md +145 -0
  17. package/template/design/DESIGN.md +212 -0
  18. package/template/design/PATTERNS.md +110 -0
  19. package/template/index.html +25 -0
  20. package/template/nginx.conf +32 -0
  21. package/template/package-lock.json +6484 -0
  22. package/template/package.json +51 -0
  23. package/template/public/favicon.svg +1 -0
  24. package/template/public/robots.txt +2 -0
  25. package/template/src/app.config.ts +50 -0
  26. package/template/src/app.roles.ts +24 -0
  27. package/template/src/components/ui/alert-dialog.tsx +181 -0
  28. package/template/src/components/ui/avatar.tsx +116 -0
  29. package/template/src/components/ui/badge.tsx +57 -0
  30. package/template/src/components/ui/breadcrumb.tsx +130 -0
  31. package/template/src/components/ui/button.tsx +58 -0
  32. package/template/src/components/ui/calendar.tsx +277 -0
  33. package/template/src/components/ui/card.tsx +99 -0
  34. package/template/src/components/ui/chart.tsx +370 -0
  35. package/template/src/components/ui/checkbox.tsx +28 -0
  36. package/template/src/components/ui/combobox.tsx +329 -0
  37. package/template/src/components/ui/command.tsx +191 -0
  38. package/template/src/components/ui/dialog.tsx +162 -0
  39. package/template/src/components/ui/dropdown-menu.tsx +271 -0
  40. package/template/src/components/ui/empty.tsx +103 -0
  41. package/template/src/components/ui/field.tsx +236 -0
  42. package/template/src/components/ui/input-group.tsx +263 -0
  43. package/template/src/components/ui/input.tsx +45 -0
  44. package/template/src/components/ui/kbd.tsx +31 -0
  45. package/template/src/components/ui/label.tsx +17 -0
  46. package/template/src/components/ui/pagination.tsx +134 -0
  47. package/template/src/components/ui/popover.tsx +87 -0
  48. package/template/src/components/ui/radio-group.tsx +35 -0
  49. package/template/src/components/ui/select.tsx +204 -0
  50. package/template/src/components/ui/separator.tsx +25 -0
  51. package/template/src/components/ui/sheet.tsx +139 -0
  52. package/template/src/components/ui/sidebar.tsx +741 -0
  53. package/template/src/components/ui/skeleton.tsx +13 -0
  54. package/template/src/components/ui/sonner.tsx +78 -0
  55. package/template/src/components/ui/spinner.tsx +42 -0
  56. package/template/src/components/ui/switch.tsx +29 -0
  57. package/template/src/components/ui/table.tsx +121 -0
  58. package/template/src/components/ui/tabs.tsx +191 -0
  59. package/template/src/components/ui/textarea.tsx +17 -0
  60. package/template/src/components/ui/toggle-group.tsx +94 -0
  61. package/template/src/components/ui/toggle.tsx +48 -0
  62. package/template/src/components/ui/tooltip.tsx +91 -0
  63. package/template/src/core/api/demo.ts +8 -0
  64. package/template/src/core/api/http.ts +76 -0
  65. package/template/src/core/api/mock.ts +88 -0
  66. package/template/src/core/api/rest.ts +67 -0
  67. package/template/src/core/api/types.ts +21 -0
  68. package/template/src/core/audit/audit.service.ts +94 -0
  69. package/template/src/core/audit/hooks.ts +19 -0
  70. package/template/src/core/auth/auth-store.ts +52 -0
  71. package/template/src/core/auth/auth.service.ts +86 -0
  72. package/template/src/core/auth/can.tsx +39 -0
  73. package/template/src/core/auth/dev-role-switcher.tsx +64 -0
  74. package/template/src/core/auth/local-credentials.ts +46 -0
  75. package/template/src/core/auth/permissions.ts +115 -0
  76. package/template/src/core/auth/require-auth.tsx +16 -0
  77. package/template/src/core/auth/require-permission.tsx +24 -0
  78. package/template/src/core/auth/roles.ts +9 -0
  79. package/template/src/core/auth/types.ts +20 -0
  80. package/template/src/core/auth/use-auth.ts +19 -0
  81. package/template/src/core/company/company.service.ts +94 -0
  82. package/template/src/core/company/hooks.ts +40 -0
  83. package/template/src/core/company/password-policy.ts +40 -0
  84. package/template/src/core/company/types.ts +46 -0
  85. package/template/src/core/company/use-app-name.ts +7 -0
  86. package/template/src/core/components/button-link.tsx +14 -0
  87. package/template/src/core/components/confirm-dialog.tsx +116 -0
  88. package/template/src/core/components/data-table/data-table.tsx +297 -0
  89. package/template/src/core/components/data-table/features.ts +24 -0
  90. package/template/src/core/components/data-table/table-header-cell.tsx +13 -0
  91. package/template/src/core/components/data-table/toolbar.tsx +100 -0
  92. package/template/src/core/components/data-table/use-list-url-state.ts +108 -0
  93. package/template/src/core/components/date-picker.tsx +71 -0
  94. package/template/src/core/components/file-attachments.tsx +84 -0
  95. package/template/src/core/components/form-error.tsx +9 -0
  96. package/template/src/core/components/form-page.tsx +93 -0
  97. package/template/src/core/components/image-upload.tsx +86 -0
  98. package/template/src/core/components/page.tsx +75 -0
  99. package/template/src/core/components/phone-input.tsx +58 -0
  100. package/template/src/core/components/search-select.tsx +57 -0
  101. package/template/src/core/components/segmented.tsx +41 -0
  102. package/template/src/core/components/states.tsx +97 -0
  103. package/template/src/core/components/status-badge.tsx +26 -0
  104. package/template/src/core/components/user-avatar.tsx +23 -0
  105. package/template/src/core/config/runtime.ts +16 -0
  106. package/template/src/core/config/types.ts +37 -0
  107. package/template/src/core/i18n/i18n.ts +69 -0
  108. package/template/src/core/i18n/i18next.d.ts +12 -0
  109. package/template/src/core/i18n/keys.ts +37 -0
  110. package/template/src/core/i18n/language-switcher.tsx +45 -0
  111. package/template/src/core/i18n/types.ts +17 -0
  112. package/template/src/core/i18n/use-format.ts +31 -0
  113. package/template/src/core/layout/app-shell.tsx +50 -0
  114. package/template/src/core/layout/app-sidebar.tsx +285 -0
  115. package/template/src/core/layout/command-menu.tsx +117 -0
  116. package/template/src/core/layout/top-bar.tsx +100 -0
  117. package/template/src/core/lib/csv.ts +27 -0
  118. package/template/src/core/lib/format.ts +87 -0
  119. package/template/src/core/lib/phone.ts +50 -0
  120. package/template/src/core/lib/storage.ts +27 -0
  121. package/template/src/core/modules/lazy-page.ts +9 -0
  122. package/template/src/core/modules/navigation.ts +39 -0
  123. package/template/src/core/modules/types.ts +55 -0
  124. package/template/src/core/notifications/hooks.ts +84 -0
  125. package/template/src/core/notifications/notification-center.tsx +251 -0
  126. package/template/src/core/notifications/notifications.service.ts +132 -0
  127. package/template/src/core/notifications/types.ts +70 -0
  128. package/template/src/core/preferences/preferences-store.ts +70 -0
  129. package/template/src/core/setup/setup-gate.tsx +20 -0
  130. package/template/src/core/setup/setup.service.ts +101 -0
  131. package/template/src/core/theme/brand-context.tsx +53 -0
  132. package/template/src/core/theme/brand.ts +29 -0
  133. package/template/src/core/theme/theme-context.tsx +62 -0
  134. package/template/src/core/theme/theme-options.ts +8 -0
  135. package/template/src/core/theme/theme-toggle.tsx +45 -0
  136. package/template/src/core/users/hooks.ts +51 -0
  137. package/template/src/core/users/types.ts +37 -0
  138. package/template/src/core/users/users.service.ts +167 -0
  139. package/template/src/hooks/use-mobile.ts +19 -0
  140. package/template/src/index.css +321 -0
  141. package/template/src/lib/utils.ts +1 -0
  142. package/template/src/locales/en/account.ts +180 -0
  143. package/template/src/locales/en/auth.ts +18 -0
  144. package/template/src/locales/en/common.ts +151 -0
  145. package/template/src/locales/en/company.ts +380 -0
  146. package/template/src/locales/en/dashboard.ts +46 -0
  147. package/template/src/locales/en/errors.ts +18 -0
  148. package/template/src/locales/en/notifications.ts +43 -0
  149. package/template/src/locales/en/settings.ts +25 -0
  150. package/template/src/locales/en/setup.ts +45 -0
  151. package/template/src/locales/index.ts +58 -0
  152. package/template/src/locales/tr/account.ts +184 -0
  153. package/template/src/locales/tr/auth.ts +22 -0
  154. package/template/src/locales/tr/common.ts +154 -0
  155. package/template/src/locales/tr/company.ts +384 -0
  156. package/template/src/locales/tr/dashboard.ts +50 -0
  157. package/template/src/locales/tr/errors.ts +22 -0
  158. package/template/src/locales/tr/notifications.ts +47 -0
  159. package/template/src/locales/tr/settings.ts +29 -0
  160. package/template/src/locales/tr/setup.ts +49 -0
  161. package/template/src/main.tsx +16 -0
  162. package/template/src/modules/locales.ts +10 -0
  163. package/template/src/modules/registry.ts +17 -0
  164. package/template/src/pages/dashboard/dashboard-page.tsx +55 -0
  165. package/template/src/pages/dashboard/quick-actions.tsx +37 -0
  166. package/template/src/pages/login-page.tsx +152 -0
  167. package/template/src/pages/no-access-page.tsx +11 -0
  168. package/template/src/pages/not-found-page.tsx +61 -0
  169. package/template/src/pages/settings/account/account.service.ts +128 -0
  170. package/template/src/pages/settings/account/components/mock-qr.tsx +50 -0
  171. package/template/src/pages/settings/account/components/password-strength.tsx +38 -0
  172. package/template/src/pages/settings/account/components/two-factor-dialog.tsx +140 -0
  173. package/template/src/pages/settings/account/hooks.ts +73 -0
  174. package/template/src/pages/settings/account/notifications-page.tsx +103 -0
  175. package/template/src/pages/settings/account/preferences-page.tsx +157 -0
  176. package/template/src/pages/settings/account/profile-page.tsx +242 -0
  177. package/template/src/pages/settings/account/security-page.tsx +364 -0
  178. package/template/src/pages/settings/account/types.ts +37 -0
  179. package/template/src/pages/settings/company/audit-log-page.tsx +126 -0
  180. package/template/src/pages/settings/company/branding-page.tsx +278 -0
  181. package/template/src/pages/settings/company/components/invite-dialog.tsx +106 -0
  182. package/template/src/pages/settings/company/components/read-only-notice.tsx +13 -0
  183. package/template/src/pages/settings/company/danger-zone-page.tsx +127 -0
  184. package/template/src/pages/settings/company/general-page.tsx +234 -0
  185. package/template/src/pages/settings/company/integrations/api-keys-panel.tsx +170 -0
  186. package/template/src/pages/settings/company/integrations/hooks.ts +37 -0
  187. package/template/src/pages/settings/company/integrations/integrations-page.tsx +57 -0
  188. package/template/src/pages/settings/company/integrations/integrations.service.ts +153 -0
  189. package/template/src/pages/settings/company/integrations/settings-forms.tsx +299 -0
  190. package/template/src/pages/settings/company/integrations/webhooks-panel.tsx +179 -0
  191. package/template/src/pages/settings/company/modules-page.tsx +65 -0
  192. package/template/src/pages/settings/company/roles-page.tsx +116 -0
  193. package/template/src/pages/settings/company/security-policies-page.tsx +164 -0
  194. package/template/src/pages/settings/company/users-page.tsx +262 -0
  195. package/template/src/pages/settings/settings-layout.tsx +57 -0
  196. package/template/src/pages/settings/settings-nav.ts +69 -0
  197. package/template/src/pages/settings/settings-routes.tsx +49 -0
  198. package/template/src/pages/setup-page.tsx +387 -0
  199. package/template/src/providers.tsx +68 -0
  200. package/template/src/router.tsx +59 -0
  201. package/template/tools/check-design.mjs +73 -0
  202. package/template/tools/new-module.mjs +90 -0
  203. package/template/tools/templates/module/api/__id__.mock.ts.tpl +17 -0
  204. package/template/tools/templates/module/api/__id__.service.ts.tpl +51 -0
  205. package/template/tools/templates/module/hooks.ts.tpl +57 -0
  206. package/template/tools/templates/module/index.ts.tpl +44 -0
  207. package/template/tools/templates/module/locales/en.ts.tpl +51 -0
  208. package/template/tools/templates/module/locales/tr.ts.tpl +55 -0
  209. package/template/tools/templates/module/pages/__id__-detail-page.tsx.tpl +103 -0
  210. package/template/tools/templates/module/pages/__id__-form-page.tsx.tpl +121 -0
  211. package/template/tools/templates/module/pages/__id__-list-page.tsx.tpl +234 -0
  212. package/template/tools/templates/module/types.ts.tpl +32 -0
  213. package/template/tsconfig.app.json +32 -0
  214. package/template/tsconfig.json +12 -0
  215. package/template/tsconfig.node.json +23 -0
  216. package/template/vite.config.ts +47 -0
@@ -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("animate-pulse rounded-2xl bg-fill-2", className)}
8
+ {...props}
9
+ />
10
+ )
11
+ }
12
+
13
+ export { Skeleton }
@@ -0,0 +1,78 @@
1
+ import { cn } from "@/lib/utils"
2
+ import { useTheme } from "next-themes"
3
+ import { Toaster as Sonner, type ToasterProps } from "sonner"
4
+ import {
5
+ CircleCheckIcon,
6
+ InfoIcon,
7
+ TriangleAlertIcon,
8
+ OctagonXIcon,
9
+ Loader2Icon,
10
+ } from "lucide-react"
11
+
12
+ const Toaster = ({
13
+ className,
14
+ style,
15
+ icons,
16
+ toastOptions,
17
+ ...props
18
+ }: ToasterProps) => {
19
+ const { theme = "system" } = useTheme()
20
+ const classNames = toastOptions?.classNames
21
+
22
+ return (
23
+ <Sonner
24
+ theme={theme as ToasterProps["theme"]}
25
+ className={cn("toaster group font-sans!", className)}
26
+ icons={{
27
+ success: <CircleCheckIcon className="size-4 text-blue-500" />,
28
+ info: <InfoIcon className="size-4 text-muted-foreground" />,
29
+ warning: <TriangleAlertIcon className="size-4 text-orange-500" />,
30
+ error: <OctagonXIcon className="size-4 text-destructive-foreground" />,
31
+ loading: (
32
+ <Loader2Icon className="size-4 animate-spin text-muted-foreground" />
33
+ ),
34
+ ...icons,
35
+ }}
36
+ style={
37
+ {
38
+ "--normal-bg": "var(--popover)",
39
+ "--normal-text": "var(--popover-foreground)",
40
+ "--normal-border": "var(--border)",
41
+ "--border-radius": "var(--radius-2xl)",
42
+ "--toast-icon-margin-start": "0px",
43
+ "--toast-icon-margin-end": "0px",
44
+ "--toast-svg-margin-start": "0px",
45
+ "--toast-svg-margin-end": "0px",
46
+ ...style,
47
+ } as React.CSSProperties
48
+ }
49
+ toastOptions={{
50
+ ...toastOptions,
51
+ classNames: {
52
+ ...classNames,
53
+ toast: cn(
54
+ "cn-toast items-start! gap-3! text-sm! data-[styled=true]:border-0! data-[styled=true]:shadow-(--shadow-popover)! data-[styled=true]:ring-1 data-[styled=true]:ring-border data-[styled=true]:focus-visible:ring-2 data-[styled=true]:focus-visible:ring-ring/30 [&[data-styled=false]_[data-title]>*]:shadow-(--shadow-popover)",
55
+ classNames?.toast
56
+ ),
57
+ title: cn("leading-5!", classNames?.title),
58
+ description: cn(
59
+ "text-sm! leading-5! text-muted-foreground!",
60
+ classNames?.description
61
+ ),
62
+ icon: cn("mt-0.5", classNames?.icon),
63
+ actionButton: cn(
64
+ "h-6! rounded-md! bg-primary! px-2! text-xs! font-medium! text-primary-foreground! hover:bg-primary/90! focus-visible:ring-2 focus-visible:ring-ring/30 [[data-cancel]+&]:-ml-1.5!",
65
+ classNames?.actionButton
66
+ ),
67
+ cancelButton: cn(
68
+ "h-6! rounded-md! bg-fill-2! px-2! text-xs! font-medium! text-foreground! hover:bg-fill-3!",
69
+ classNames?.cancelButton
70
+ ),
71
+ },
72
+ }}
73
+ {...props}
74
+ />
75
+ )
76
+ }
77
+
78
+ export { Toaster }
@@ -0,0 +1,42 @@
1
+ import { cn } from "@/lib/utils"
2
+ import { useTranslation } from "react-i18next"
3
+ import { Loader2Icon } from "lucide-react"
4
+
5
+ function Spinner({
6
+ className,
7
+ variant = "default",
8
+ ...props
9
+ }: React.ComponentProps<"svg"> & {
10
+ /** `gradient`: a closed ring whose line fades around it, 1.5px at every size. */
11
+ variant?: "default" | "gradient"
12
+ }) {
13
+ const { t } = useTranslation()
14
+ if (variant === "gradient") {
15
+ return (
16
+ <svg
17
+ data-slot="spinner"
18
+ data-variant="gradient"
19
+ role="status"
20
+ aria-label={t("a11y.loading")}
21
+ viewBox="0 0 24 24"
22
+ className={cn(
23
+ "size-4 shrink-0 animate-spin rounded-full bg-[conic-gradient(color-mix(in_oklab,currentColor_5%,transparent),color-mix(in_oklab,currentColor_50%,transparent))] mask-[radial-gradient(closest-side,transparent_calc(75%-1.25px),#000_calc(75%-0.5px),#000_calc(75%+0.5px),transparent_calc(75%+1.25px))]",
24
+ className
25
+ )}
26
+ {...props}
27
+ />
28
+ )
29
+ }
30
+
31
+ return (
32
+ <Loader2Icon
33
+ data-slot="spinner"
34
+ role="status"
35
+ aria-label={t("a11y.loading")}
36
+ className={cn("size-4 animate-spin", className)}
37
+ {...props}
38
+ />
39
+ )
40
+ }
41
+
42
+ export { Spinner }
@@ -0,0 +1,29 @@
1
+ import { Switch as SwitchPrimitive } from "@base-ui/react/switch"
2
+ import { cn } from "@/lib/utils"
3
+
4
+ function Switch({
5
+ className,
6
+ size = "default",
7
+ ...props
8
+ }: SwitchPrimitive.Root.Props & {
9
+ size?: "sm" | "default"
10
+ }) {
11
+ return (
12
+ <SwitchPrimitive.Root
13
+ data-slot="switch"
14
+ data-size={size}
15
+ className={cn(
16
+ "peer group/switch relative inline-flex shrink-0 items-center rounded-full border-2 transition-all outline-none group-has-[:focus-visible]/field-label:ring-0 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=default]:h-5 data-[size=default]:w-8 data-[size=sm]:h-4 data-[size=sm]:w-6 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary group-has-[:focus-visible]/field-label:data-checked:border-primary data-checked:focus-visible:border-primary data-unchecked:border-transparent data-unchecked:bg-fill-3 group-has-[:focus-visible]/field-label:data-unchecked:border-transparent data-disabled:cursor-not-allowed data-disabled:opacity-50",
17
+ className
18
+ )}
19
+ {...props}
20
+ >
21
+ <SwitchPrimitive.Thumb
22
+ data-slot="switch-thumb"
23
+ className="pointer-events-none block rounded-full bg-primary-foreground shadow-sm ring-0 transition-transform not-dark:bg-clip-padding group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-checked:translate-x-[calc(100%-4px)] data-unchecked:translate-x-0 data-unchecked:bg-linear-to-b data-unchecked:from-white/8 data-unchecked:to-transparent data-unchecked:to-70% dark:data-unchecked:bg-neutral-500"
24
+ />
25
+ </SwitchPrimitive.Root>
26
+ )
27
+ }
28
+
29
+ export { Switch }
@@ -0,0 +1,121 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "@/lib/utils"
5
+
6
+ function Table({ className, ...props }: React.ComponentProps<"table">) {
7
+ return (
8
+ <div
9
+ data-slot="table-container"
10
+ className="relative w-full overflow-x-auto"
11
+ >
12
+ <table
13
+ data-slot="table"
14
+ className={cn("w-full caption-bottom text-sm", className)}
15
+ {...props}
16
+ />
17
+ </div>
18
+ )
19
+ }
20
+
21
+ function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
22
+ return (
23
+ <thead
24
+ data-slot="table-header"
25
+ className={cn("[:where(&)_tr]:border-b", className)}
26
+ {...props}
27
+ />
28
+ )
29
+ }
30
+
31
+ function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
32
+ return (
33
+ <tbody
34
+ data-slot="table-body"
35
+ className={cn(
36
+ "[&_tr:last-child]:border-0 [&_tr:last-child]:[--table-divider:0px]",
37
+ className
38
+ )}
39
+ {...props}
40
+ />
41
+ )
42
+ }
43
+
44
+ function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
45
+ return (
46
+ <tfoot
47
+ data-slot="table-footer"
48
+ className={cn(
49
+ "border-t bg-fill-1 font-medium [&>tr]:last:border-b-0 [&>tr]:last:[--table-divider:0px] [&.border-t>tr:first-child]:[--table-divider-top:1px]",
50
+ className
51
+ )}
52
+ {...props}
53
+ />
54
+ )
55
+ }
56
+
57
+ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
58
+ return (
59
+ <tr
60
+ data-slot="table-row"
61
+ className={cn(
62
+ "border-b transition-colors [--table-divider-top:0px] [--table-divider:0px] hover:bg-fill-1 has-aria-expanded:bg-fill-1 data-[state=selected]:bg-fill-2 [&.border-b]:[--table-divider:1px]",
63
+ className
64
+ )}
65
+ {...props}
66
+ />
67
+ )
68
+ }
69
+
70
+ function TableHead({ className, ...props }: React.ComponentProps<"th">) {
71
+ return (
72
+ <th
73
+ data-slot="table-head"
74
+ className={cn(
75
+ "h-[calc(--spacing(10)-var(--table-divider,0px))] px-3 pt-2.5 pb-[calc(--spacing(2.5)-var(--table-divider,0px))] text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0",
76
+ className
77
+ )}
78
+ {...props}
79
+ />
80
+ )
81
+ }
82
+
83
+ function TableCell({ className, ...props }: React.ComponentProps<"td">) {
84
+ return (
85
+ <td
86
+ data-slot="table-cell"
87
+ className={cn(
88
+ "px-3 pt-[calc(--spacing(2)-var(--table-divider-top,0px))] pb-[calc(--spacing(2)-var(--table-divider,0px))] align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0",
89
+ className
90
+ )}
91
+ {...props}
92
+ />
93
+ )
94
+ }
95
+
96
+ function TableCaption({
97
+ className,
98
+ ...props
99
+ }: React.ComponentProps<"caption">) {
100
+ return (
101
+ <caption
102
+ data-slot="table-caption"
103
+ className={cn(
104
+ "mt-4 px-3 text-left text-sm text-muted-foreground",
105
+ className
106
+ )}
107
+ {...props}
108
+ />
109
+ )
110
+ }
111
+
112
+ export {
113
+ Table,
114
+ TableHeader,
115
+ TableBody,
116
+ TableFooter,
117
+ TableHead,
118
+ TableRow,
119
+ TableCell,
120
+ TableCaption,
121
+ }
@@ -0,0 +1,191 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Tabs as TabsPrimitive } from "@base-ui/react/tabs"
5
+ import { cva, type VariantProps } from "class-variance-authority"
6
+ import { cn } from "@/lib/utils"
7
+
8
+ function Tabs({
9
+ className,
10
+ orientation = "horizontal",
11
+ ...props
12
+ }: TabsPrimitive.Root.Props) {
13
+ return (
14
+ <TabsPrimitive.Root
15
+ data-slot="tabs"
16
+ orientation={orientation}
17
+ className={cn(
18
+ "group/tabs flex gap-2 data-horizontal:flex-col",
19
+ className
20
+ )}
21
+ {...props}
22
+ />
23
+ )
24
+ }
25
+
26
+ const tabsListVariants = cva(
27
+ "group/tabs-list relative isolate inline-flex w-fit items-center justify-center rounded-lg p-0.5 text-muted-foreground data-[variant=line]:rounded-none data-horizontal:h-8 data-horizontal:has-data-[layout=stacked]:h-auto data-horizontal:data-[size=lg]:h-9 data-vertical:h-fit data-vertical:flex-col",
28
+ {
29
+ variants: {
30
+ variant: {
31
+ default: "bg-fill-2",
32
+ secondary: "bg-transparent",
33
+ primary: "bg-transparent",
34
+ line: "bg-transparent",
35
+ },
36
+ size: {
37
+ default: "",
38
+ lg: "",
39
+ },
40
+ },
41
+ defaultVariants: {
42
+ variant: "default",
43
+ size: "default",
44
+ },
45
+ }
46
+ )
47
+
48
+ const tabsIndicatorVariants = cva("absolute -z-10", {
49
+ variants: {
50
+ variant: {
51
+ default:
52
+ "top-(--active-tab-top) left-(--active-tab-left) h-(--active-tab-height) w-(--active-tab-width) rounded-md bg-raised shadow-xs transition-[top,left,width,height] duration-200 ease-out motion-reduce:transition-none",
53
+ secondary:
54
+ "top-(--active-tab-top) left-(--active-tab-left) h-(--active-tab-height) w-(--active-tab-width) rounded-md bg-fill-2 transition-[top,left,width,height] duration-200 ease-out motion-reduce:transition-none",
55
+ primary:
56
+ "top-(--active-tab-top) left-(--active-tab-left) h-(--active-tab-height) w-(--active-tab-width) rounded-md bg-primary transition-[top,left,width,height] duration-200 ease-out motion-reduce:transition-none",
57
+ line: "bg-foreground [--tab-line-x:--spacing(2)] [--tab-line-y:--spacing(1)] group-has-data-[layout=stacked]/tabs-list:[--tab-line-x:--spacing(2.5)] group-has-data-[layout=stacked]/tabs-list:[--tab-line-y:--spacing(2)] group-data-[size=lg]/tabs-list:[--tab-line-x:--spacing(2.5)] group-data-[size=lg]/tabs-list:[--tab-line-y:--spacing(1.5)] data-horizontal:bottom-0 data-horizontal:left-[calc(var(--active-tab-left)+var(--tab-line-x))] data-horizontal:h-0.5 data-horizontal:w-[calc(var(--active-tab-width)-2*var(--tab-line-x))] data-vertical:top-[calc(var(--active-tab-top)+var(--tab-line-y))] data-vertical:right-0 data-vertical:h-[calc(var(--active-tab-height)-2*var(--tab-line-y))] data-vertical:w-0.5",
58
+ },
59
+ },
60
+ defaultVariants: {
61
+ variant: "default",
62
+ },
63
+ })
64
+
65
+ function TabsList({
66
+ className,
67
+ variant = "default",
68
+ size = "default",
69
+ children,
70
+ ...props
71
+ }: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
72
+ return (
73
+ <TabsPrimitive.List
74
+ data-slot="tabs-list"
75
+ data-variant={variant}
76
+ data-size={size}
77
+ className={cn(tabsListVariants({ variant, size }), className)}
78
+ {...props}
79
+ >
80
+ {children}
81
+ <TabsPrimitive.Indicator
82
+ data-slot="tabs-indicator"
83
+ renderBeforeHydration
84
+ className={tabsIndicatorVariants({ variant })}
85
+ />
86
+ </TabsPrimitive.List>
87
+ )
88
+ }
89
+
90
+ const tabsTriggerVariants = cva(
91
+ "group/tabs-trigger relative inline-flex rounded-md border border-transparent! text-xs font-medium whitespace-nowrap text-muted-foreground transition-all hover:text-foreground focus-visible:ring-3 focus-visible:ring-ring/30 focus-visible:outline-1 focus-visible:outline-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 data-vertical:w-full [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
92
+ {
93
+ variants: {
94
+ layout: {
95
+ inline:
96
+ "h-7 items-center justify-center gap-1 px-1.75 group-data-[size=lg]/tabs-list:h-8 group-data-[size=lg]/tabs-list:gap-1.5 group-data-[size=lg]/tabs-list:px-2.25 data-vertical:justify-start",
97
+ stacked:
98
+ "flex-col items-start justify-start gap-2 px-2.25 py-1.75 text-left",
99
+ },
100
+ align: {
101
+ start: "",
102
+ center: "",
103
+ },
104
+ },
105
+ compoundVariants: [
106
+ {
107
+ layout: "stacked",
108
+ align: "center",
109
+ class: "items-center text-center",
110
+ },
111
+ ],
112
+ defaultVariants: {
113
+ layout: "inline",
114
+ align: "start",
115
+ },
116
+ }
117
+ )
118
+
119
+ function TabsTrigger({
120
+ className,
121
+ layout = "inline",
122
+ align = "start",
123
+ ...props
124
+ }: TabsPrimitive.Tab.Props & VariantProps<typeof tabsTriggerVariants>) {
125
+ return (
126
+ <TabsPrimitive.Tab
127
+ data-slot="tabs-trigger"
128
+ data-layout={layout}
129
+ className={cn(
130
+ tabsTriggerVariants({ layout, align }),
131
+ "group-data-[variant=line]/tabs-list:rounded-none data-active:text-foreground group-data-[variant=primary]/tabs-list:data-active:text-primary-foreground",
132
+ className
133
+ )}
134
+ {...props}
135
+ />
136
+ )
137
+ }
138
+
139
+ /** A secondary line in a trigger: an eyebrow above the label or a description under it. */
140
+ function TabsTriggerDescription({
141
+ className,
142
+ ...props
143
+ }: React.ComponentProps<"span">) {
144
+ return (
145
+ <span
146
+ data-slot="tabs-trigger-description"
147
+ className={cn(
148
+ "text-2xs font-normal text-muted-foreground group-data-[variant=primary]/tabs-list:group-data-active/tabs-trigger:text-primary-foreground/70",
149
+ className
150
+ )}
151
+ {...props}
152
+ />
153
+ )
154
+ }
155
+
156
+ /** A count after the label. */
157
+ function TabsTriggerCount({
158
+ className,
159
+ ...props
160
+ }: React.ComponentProps<"span">) {
161
+ return (
162
+ <span
163
+ data-slot="tabs-trigger-count"
164
+ className={cn(
165
+ "font-normal text-muted-foreground tabular-nums group-data-[variant=primary]/tabs-list:group-data-active/tabs-trigger:text-primary-foreground/70",
166
+ className
167
+ )}
168
+ {...props}
169
+ />
170
+ )
171
+ }
172
+
173
+ function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
174
+ return (
175
+ <TabsPrimitive.Panel
176
+ data-slot="tabs-content"
177
+ className={cn("flex-1 text-sm outline-none", className)}
178
+ {...props}
179
+ />
180
+ )
181
+ }
182
+
183
+ export {
184
+ Tabs,
185
+ TabsList,
186
+ TabsTrigger,
187
+ TabsTriggerDescription,
188
+ TabsTriggerCount,
189
+ TabsContent,
190
+ tabsListVariants,
191
+ }
@@ -0,0 +1,17 @@
1
+ import * as React from "react"
2
+ import { cn } from "@/lib/utils"
3
+
4
+ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
5
+ return (
6
+ <textarea
7
+ data-slot="textarea"
8
+ className={cn(
9
+ "flex field-sizing-content min-h-16 w-full resize-none rounded-lg bg-field px-2.5 py-2 text-xs outline-1 -outline-offset-1 outline-field-border transition-[color,box-shadow,outline-color] duration-200 outline-solid placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring/30 focus-visible:outline-ring disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-2 aria-invalid:ring-destructive/20 aria-invalid:outline-destructive dark:aria-invalid:ring-destructive/40 dark:aria-invalid:outline-destructive/50",
10
+ className
11
+ )}
12
+ {...props}
13
+ />
14
+ )
15
+ }
16
+
17
+ export { Textarea }
@@ -0,0 +1,94 @@
1
+ import * as React from "react"
2
+ import { Toggle as TogglePrimitive } from "@base-ui/react/toggle"
3
+ import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group"
4
+ import { type VariantProps } from "class-variance-authority"
5
+ import { cn } from "@/lib/utils"
6
+
7
+ import { toggleVariants } from "@/components/ui/toggle"
8
+
9
+ const ToggleGroupContext = React.createContext<
10
+ VariantProps<typeof toggleVariants> & {
11
+ spacing?: number
12
+ orientation?: "horizontal" | "vertical"
13
+ }
14
+ >({
15
+ size: "default",
16
+ variant: "default",
17
+ spacing: 2,
18
+ orientation: "horizontal",
19
+ })
20
+
21
+ function ToggleGroup({
22
+ className,
23
+ variant,
24
+ size,
25
+ spacing = 2,
26
+ orientation = "horizontal",
27
+ style,
28
+ children,
29
+ ...props
30
+ }: ToggleGroupPrimitive.Props &
31
+ VariantProps<typeof toggleVariants> & {
32
+ spacing?: number
33
+ orientation?: "horizontal" | "vertical"
34
+ }) {
35
+ const gap = { "--gap": spacing } as React.CSSProperties
36
+ return (
37
+ <ToggleGroupPrimitive
38
+ data-slot="toggle-group"
39
+ data-variant={variant}
40
+ data-size={size}
41
+ data-spacing={spacing}
42
+ orientation={orientation}
43
+ data-orientation={orientation}
44
+ style={
45
+ typeof style === "function"
46
+ ? (state) => ({ ...gap, ...style(state) })
47
+ : { ...gap, ...style }
48
+ }
49
+ className={cn(
50
+ "group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] data-[spacing=0]:data-[variant=outline]:data-horizontal:rounded-full data-vertical:flex-col data-vertical:items-stretch data-[spacing=0]:data-[variant=outline]:data-vertical:rounded-2xl",
51
+ className
52
+ )}
53
+ {...props}
54
+ >
55
+ <ToggleGroupContext.Provider
56
+ value={{ variant, size, spacing, orientation }}
57
+ >
58
+ {children}
59
+ </ToggleGroupContext.Provider>
60
+ </ToggleGroupPrimitive>
61
+ )
62
+ }
63
+
64
+ function ToggleGroupItem({
65
+ className,
66
+ children,
67
+ variant = "default",
68
+ size = "default",
69
+ ...props
70
+ }: TogglePrimitive.Props & VariantProps<typeof toggleVariants>) {
71
+ const context = React.useContext(ToggleGroupContext)
72
+
73
+ return (
74
+ <TogglePrimitive
75
+ data-slot="toggle-group-item"
76
+ data-variant={context.variant || variant}
77
+ data-size={context.size || size}
78
+ data-spacing={context.spacing}
79
+ className={cn(
80
+ "shrink-0 group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:shadow-none focus:z-10 focus-visible:z-10 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-full group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-2xl group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-full group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-2xl group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:not-last:border-r-transparent group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:not-last:border-b-transparent",
81
+ toggleVariants({
82
+ variant: context.variant || variant,
83
+ size: context.size || size,
84
+ }),
85
+ className
86
+ )}
87
+ {...props}
88
+ >
89
+ {children}
90
+ </TogglePrimitive>
91
+ )
92
+ }
93
+
94
+ export { ToggleGroup, ToggleGroupItem }
@@ -0,0 +1,48 @@
1
+ "use client"
2
+
3
+ import { Toggle as TogglePrimitive } from "@base-ui/react/toggle"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const toggleVariants = cva(
8
+ "group/toggle inline-flex items-center justify-center rounded-lg text-sm font-medium whitespace-nowrap transition-colors outline-none hover:bg-fill-1 hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/30 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-fill-2 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: "bg-transparent",
13
+ outline: "border border-border bg-transparent",
14
+ },
15
+ size: {
16
+ default: "h-8 min-w-8 gap-1.5 px-3",
17
+ sm: "h-7 min-w-7 gap-1 rounded-md px-2.5",
18
+ lg: "h-9 min-w-9 gap-1.5 px-3.5",
19
+ },
20
+ },
21
+ compoundVariants: [
22
+ { variant: "outline", size: "default", class: "px-2.75" },
23
+ { variant: "outline", size: "sm", class: "px-2.25" },
24
+ { variant: "outline", size: "lg", class: "px-3.25" },
25
+ ],
26
+ defaultVariants: {
27
+ variant: "default",
28
+ size: "default",
29
+ },
30
+ }
31
+ )
32
+
33
+ function Toggle({
34
+ className,
35
+ variant = "default",
36
+ size = "default",
37
+ ...props
38
+ }: TogglePrimitive.Props & VariantProps<typeof toggleVariants>) {
39
+ return (
40
+ <TogglePrimitive
41
+ data-slot="toggle"
42
+ className={cn(toggleVariants({ variant, size, className }))}
43
+ {...props}
44
+ />
45
+ )
46
+ }
47
+
48
+ export { Toggle, toggleVariants }