@create-lft-app/nextjs 3.2.0 → 3.3.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/README.md +549 -549
  2. package/package.json +48 -48
  3. package/template/.claude/skills/anti-patterns.md +150 -0
  4. package/template/.claude/skills/drizzle-schema.md +178 -0
  5. package/template/.claude/skills/formatting.md +56 -0
  6. package/template/.claude/skills/module-architecture.md +143 -0
  7. package/template/.claude/skills/supabase-server-actions.md +199 -0
  8. package/template/.claude/skills/ui-patterns.md +161 -0
  9. package/template/CLAUDE.md +114 -1239
  10. package/template/drizzle.config.ts +12 -12
  11. package/template/eslint.config.mjs +16 -16
  12. package/template/gitignore +36 -36
  13. package/template/next.config.ts +7 -7
  14. package/template/package.json +86 -86
  15. package/template/postcss.config.mjs +7 -7
  16. package/template/proxy.ts +12 -12
  17. package/template/public/logolft.svg +11 -11
  18. package/template/src/app/(auth)/dashboard/dashboard-content.tsx +124 -124
  19. package/template/src/app/(auth)/dashboard/page.tsx +9 -9
  20. package/template/src/app/(auth)/layout.tsx +7 -7
  21. package/template/src/app/(auth)/users/page.tsx +9 -9
  22. package/template/src/app/(auth)/users/users-content.tsx +26 -26
  23. package/template/src/app/(public)/layout.tsx +7 -7
  24. package/template/src/app/(public)/login/page.tsx +17 -17
  25. package/template/src/app/api/webhooks/route.ts +20 -20
  26. package/template/src/app/globals.css +249 -249
  27. package/template/src/app/layout.tsx +37 -37
  28. package/template/src/app/page.tsx +5 -5
  29. package/template/src/app/providers.tsx +27 -27
  30. package/template/src/components/layout/main-content.tsx +28 -28
  31. package/template/src/components/layout/sidebar-context.tsx +33 -33
  32. package/template/src/components/layout/sidebar.tsx +141 -141
  33. package/template/src/components/tables/data-table-column-header.tsx +68 -68
  34. package/template/src/components/tables/data-table-date-filter.tsx +203 -203
  35. package/template/src/components/tables/data-table-faceted-filter.tsx +185 -185
  36. package/template/src/components/tables/data-table-filters-dropdown.tsx +130 -130
  37. package/template/src/components/tables/data-table-number-filter.tsx +295 -295
  38. package/template/src/components/tables/data-table-pagination.tsx +99 -99
  39. package/template/src/components/tables/data-table-toolbar.tsx +140 -140
  40. package/template/src/components/tables/data-table-view-options.tsx +63 -63
  41. package/template/src/components/tables/data-table.tsx +148 -148
  42. package/template/src/components/tables/index.ts +9 -9
  43. package/template/src/components/ui/accordion.tsx +58 -58
  44. package/template/src/components/ui/alert-dialog.tsx +165 -165
  45. package/template/src/components/ui/alert.tsx +66 -66
  46. package/template/src/components/ui/animations/index.ts +44 -44
  47. package/template/src/components/ui/avatar.tsx +55 -55
  48. package/template/src/components/ui/badge.tsx +50 -50
  49. package/template/src/components/ui/button.tsx +118 -118
  50. package/template/src/components/ui/calendar.tsx +220 -220
  51. package/template/src/components/ui/card.tsx +113 -113
  52. package/template/src/components/ui/checkbox.tsx +38 -38
  53. package/template/src/components/ui/collapsible.tsx +33 -33
  54. package/template/src/components/ui/command.tsx +196 -196
  55. package/template/src/components/ui/dialog.tsx +156 -156
  56. package/template/src/components/ui/dropdown-menu.tsx +280 -280
  57. package/template/src/components/ui/form.tsx +171 -171
  58. package/template/src/components/ui/icons.tsx +167 -167
  59. package/template/src/components/ui/input.tsx +28 -28
  60. package/template/src/components/ui/label.tsx +25 -25
  61. package/template/src/components/ui/motion.tsx +197 -197
  62. package/template/src/components/ui/page-transition.tsx +166 -166
  63. package/template/src/components/ui/popover.tsx +59 -59
  64. package/template/src/components/ui/progress.tsx +32 -32
  65. package/template/src/components/ui/radio-group.tsx +45 -45
  66. package/template/src/components/ui/scroll-area.tsx +63 -63
  67. package/template/src/components/ui/select.tsx +208 -208
  68. package/template/src/components/ui/separator.tsx +28 -28
  69. package/template/src/components/ui/sheet.tsx +170 -170
  70. package/template/src/components/ui/sidebar.tsx +726 -726
  71. package/template/src/components/ui/skeleton.tsx +15 -15
  72. package/template/src/components/ui/slider.tsx +58 -58
  73. package/template/src/components/ui/sonner.tsx +47 -47
  74. package/template/src/components/ui/spinner.tsx +27 -27
  75. package/template/src/components/ui/submit-button.tsx +47 -47
  76. package/template/src/components/ui/switch.tsx +31 -31
  77. package/template/src/components/ui/table.tsx +120 -120
  78. package/template/src/components/ui/tabs.tsx +75 -75
  79. package/template/src/components/ui/textarea.tsx +26 -26
  80. package/template/src/components/ui/tooltip.tsx +70 -70
  81. package/template/src/config/navigation.ts +59 -59
  82. package/template/src/config/roles.ts +27 -27
  83. package/template/src/config/site.ts +12 -12
  84. package/template/src/db/index.ts +12 -12
  85. package/template/src/db/schema/index.ts +1 -1
  86. package/template/src/db/schema/users.ts +16 -16
  87. package/template/src/db/seed.ts +39 -39
  88. package/template/src/hooks/index.ts +3 -3
  89. package/template/src/hooks/use-mobile.ts +21 -21
  90. package/template/src/hooks/useDataTable.ts +82 -82
  91. package/template/src/hooks/useDebounce.ts +49 -49
  92. package/template/src/hooks/useMediaQuery.ts +36 -36
  93. package/template/src/lib/date/config.ts +36 -36
  94. package/template/src/lib/date/formatters.ts +127 -127
  95. package/template/src/lib/date/index.ts +26 -26
  96. package/template/src/lib/excel/exporter.ts +89 -89
  97. package/template/src/lib/excel/index.ts +14 -14
  98. package/template/src/lib/excel/parser.ts +96 -96
  99. package/template/src/lib/query-client.ts +35 -35
  100. package/template/src/lib/supabase/admin.ts +23 -23
  101. package/template/src/lib/supabase/client.ts +11 -11
  102. package/template/src/lib/supabase/proxy.ts +67 -67
  103. package/template/src/lib/supabase/server.ts +38 -38
  104. package/template/src/lib/supabase/types.ts +53 -53
  105. package/template/src/lib/utils.ts +6 -6
  106. package/template/src/lib/validations/common.ts +75 -75
  107. package/template/src/lib/validations/index.ts +20 -20
  108. package/template/src/modules/auth/actions/auth-actions.ts +59 -59
  109. package/template/src/modules/auth/components/login-form.tsx +68 -68
  110. package/template/src/modules/auth/hooks/useAuth.ts +38 -38
  111. package/template/src/modules/auth/hooks/useAuthMutations.ts +43 -43
  112. package/template/src/modules/auth/hooks/useAuthQueries.ts +43 -43
  113. package/template/src/modules/auth/index.ts +12 -12
  114. package/template/src/modules/auth/schemas/auth.schema.ts +32 -32
  115. package/template/src/modules/auth/stores/useAuthStore.ts +37 -37
  116. package/template/src/modules/users/actions/users-actions.ts +166 -166
  117. package/template/src/modules/users/columns.tsx +106 -106
  118. package/template/src/modules/users/components/users-list.tsx +48 -48
  119. package/template/src/modules/users/hooks/useUsers.ts +39 -39
  120. package/template/src/modules/users/hooks/useUsersMutations.ts +55 -55
  121. package/template/src/modules/users/hooks/useUsersQueries.ts +35 -35
  122. package/template/src/modules/users/index.ts +30 -30
  123. package/template/src/modules/users/schemas/users.schema.ts +51 -51
  124. package/template/src/modules/users/stores/useUsersStore.ts +60 -60
  125. package/template/src/modules/users/types/auth-user.types.ts +42 -42
  126. package/template/src/modules/users/utils/user-mapper.ts +32 -32
  127. package/template/src/stores/index.ts +1 -1
  128. package/template/src/stores/useUiStore.ts +55 -55
  129. package/template/src/types/api.ts +28 -28
  130. package/template/src/types/index.ts +2 -2
  131. package/template/src/types/table.ts +34 -34
  132. package/template/supabase/config.toml +94 -94
  133. package/template/tsconfig.json +42 -42
@@ -1,15 +1,15 @@
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("relative overflow-hidden rounded-md bg-muted", className)}
8
- {...props}
9
- >
10
- <div className="absolute inset-0 -translate-x-full animate-shimmer bg-gradient-to-r from-transparent via-foreground/5 to-transparent" />
11
- </div>
12
- )
13
- }
14
-
15
- export { Skeleton }
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("relative overflow-hidden rounded-md bg-muted", className)}
8
+ {...props}
9
+ >
10
+ <div className="absolute inset-0 -translate-x-full animate-shimmer bg-gradient-to-r from-transparent via-foreground/5 to-transparent" />
11
+ </div>
12
+ )
13
+ }
14
+
15
+ export { Skeleton }
@@ -1,58 +1,58 @@
1
- 'use client'
2
-
3
- import * as React from 'react'
4
- import * as SliderPrimitive from '@radix-ui/react-slider'
5
-
6
- import { cn } from '@/lib/utils'
7
-
8
- function Slider({
9
- className,
10
- defaultValue,
11
- value,
12
- min = 0,
13
- max = 100,
14
- ...props
15
- }: React.ComponentProps<typeof SliderPrimitive.Root>) {
16
- const _values = React.useMemo(
17
- () => (value ?? defaultValue ?? [min, max]),
18
- [value, defaultValue, min, max]
19
- )
20
-
21
- return (
22
- <SliderPrimitive.Root
23
- data-slot="slider"
24
- defaultValue={defaultValue}
25
- value={value}
26
- min={min}
27
- max={max}
28
- className={cn(
29
- 'relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col',
30
- className
31
- )}
32
- {...props}
33
- >
34
- <SliderPrimitive.Track
35
- data-slot="slider-track"
36
- className={cn(
37
- 'bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5'
38
- )}
39
- >
40
- <SliderPrimitive.Range
41
- data-slot="slider-range"
42
- className={cn(
43
- 'bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full'
44
- )}
45
- />
46
- </SliderPrimitive.Track>
47
- {Array.from({ length: _values.length }, (_, index) => (
48
- <SliderPrimitive.Thumb
49
- data-slot="slider-thumb"
50
- key={index}
51
- className="border-primary bg-background ring-ring/50 block size-4 shrink-0 rounded-full border shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50"
52
- />
53
- ))}
54
- </SliderPrimitive.Root>
55
- )
56
- }
57
-
58
- export { Slider }
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as SliderPrimitive from '@radix-ui/react-slider'
5
+
6
+ import { cn } from '@/lib/utils'
7
+
8
+ function Slider({
9
+ className,
10
+ defaultValue,
11
+ value,
12
+ min = 0,
13
+ max = 100,
14
+ ...props
15
+ }: React.ComponentProps<typeof SliderPrimitive.Root>) {
16
+ const _values = React.useMemo(
17
+ () => (value ?? defaultValue ?? [min, max]),
18
+ [value, defaultValue, min, max]
19
+ )
20
+
21
+ return (
22
+ <SliderPrimitive.Root
23
+ data-slot="slider"
24
+ defaultValue={defaultValue}
25
+ value={value}
26
+ min={min}
27
+ max={max}
28
+ className={cn(
29
+ 'relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col',
30
+ className
31
+ )}
32
+ {...props}
33
+ >
34
+ <SliderPrimitive.Track
35
+ data-slot="slider-track"
36
+ className={cn(
37
+ 'bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5'
38
+ )}
39
+ >
40
+ <SliderPrimitive.Range
41
+ data-slot="slider-range"
42
+ className={cn(
43
+ 'bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full'
44
+ )}
45
+ />
46
+ </SliderPrimitive.Track>
47
+ {Array.from({ length: _values.length }, (_, index) => (
48
+ <SliderPrimitive.Thumb
49
+ data-slot="slider-thumb"
50
+ key={index}
51
+ className="border-primary bg-background ring-ring/50 block size-4 shrink-0 rounded-full border shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50"
52
+ />
53
+ ))}
54
+ </SliderPrimitive.Root>
55
+ )
56
+ }
57
+
58
+ export { Slider }
@@ -1,47 +1,47 @@
1
- "use client"
2
-
3
- import {
4
- CircleCheckIcon,
5
- InfoIcon,
6
- Loader2Icon,
7
- OctagonXIcon,
8
- TriangleAlertIcon,
9
- } from "lucide-react"
10
- import { useTheme } from "next-themes"
11
- import { Toaster as Sonner, type ToasterProps } from "sonner"
12
-
13
- const Toaster = ({ ...props }: ToasterProps) => {
14
- const { theme = "system" } = useTheme()
15
-
16
- return (
17
- <Sonner
18
- theme={theme as ToasterProps["theme"]}
19
- className="toaster group"
20
- toastOptions={{
21
- classNames: {
22
- toast:
23
- "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
24
- description: "group-[.toast]:text-muted-foreground",
25
- actionButton:
26
- "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
27
- cancelButton:
28
- "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
29
- error:
30
- "group-[.toaster]:bg-destructive group-[.toaster]:text-destructive-foreground group-[.toaster]:border-destructive",
31
- success:
32
- "group-[.toaster]:bg-green-100 dark:group-[.toaster]:bg-green-950 group-[.toaster]:text-green-900 dark:group-[.toaster]:text-green-100 group-[.toaster]:border-green-200 dark:group-[.toaster]:border-green-800",
33
- },
34
- }}
35
- icons={{
36
- success: <CircleCheckIcon className="size-4" />,
37
- info: <InfoIcon className="size-4" />,
38
- warning: <TriangleAlertIcon className="size-4" />,
39
- error: <OctagonXIcon className="size-4" />,
40
- loading: <Loader2Icon className="size-4 animate-spin" />,
41
- }}
42
- {...props}
43
- />
44
- )
45
- }
46
-
47
- export { Toaster }
1
+ "use client"
2
+
3
+ import {
4
+ CircleCheckIcon,
5
+ InfoIcon,
6
+ Loader2Icon,
7
+ OctagonXIcon,
8
+ TriangleAlertIcon,
9
+ } from "lucide-react"
10
+ import { useTheme } from "next-themes"
11
+ import { Toaster as Sonner, type ToasterProps } from "sonner"
12
+
13
+ const Toaster = ({ ...props }: ToasterProps) => {
14
+ const { theme = "system" } = useTheme()
15
+
16
+ return (
17
+ <Sonner
18
+ theme={theme as ToasterProps["theme"]}
19
+ className="toaster group"
20
+ toastOptions={{
21
+ classNames: {
22
+ toast:
23
+ "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
24
+ description: "group-[.toast]:text-muted-foreground",
25
+ actionButton:
26
+ "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
27
+ cancelButton:
28
+ "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
29
+ error:
30
+ "group-[.toaster]:bg-destructive group-[.toaster]:text-destructive-foreground group-[.toaster]:border-destructive",
31
+ success:
32
+ "group-[.toaster]:bg-green-100 dark:group-[.toaster]:bg-green-950 group-[.toaster]:text-green-900 dark:group-[.toaster]:text-green-100 group-[.toaster]:border-green-200 dark:group-[.toaster]:border-green-800",
33
+ },
34
+ }}
35
+ icons={{
36
+ success: <CircleCheckIcon className="size-4" />,
37
+ info: <InfoIcon className="size-4" />,
38
+ warning: <TriangleAlertIcon className="size-4" />,
39
+ error: <OctagonXIcon className="size-4" />,
40
+ loading: <Loader2Icon className="size-4 animate-spin" />,
41
+ }}
42
+ {...props}
43
+ />
44
+ )
45
+ }
46
+
47
+ export { Toaster }
@@ -1,27 +1,27 @@
1
- import * as React from "react"
2
- import { cn } from "@/lib/utils"
3
-
4
- interface SpinnerProps extends Omit<React.SVGProps<SVGSVGElement>, "width" | "height"> {
5
- size?: number
6
- }
7
-
8
- function Spinner({ className, size = 20, style, ...props }: SpinnerProps) {
9
- return (
10
- <svg
11
- fill="none"
12
- stroke="currentColor"
13
- strokeWidth="1.5"
14
- viewBox="0 0 24 24"
15
- strokeLinecap="round"
16
- strokeLinejoin="round"
17
- xmlns="http://www.w3.org/2000/svg"
18
- className={cn("animate-spin text-muted-foreground", className)}
19
- style={{ width: size, height: size, ...style }}
20
- {...props}
21
- >
22
- <path d="M12 3v3m6.366-.366-2.12 2.12M21 12h-3m.366 6.366-2.12-2.12M12 21v-3m-6.366.366 2.12-2.12M3 12h3m-.366-6.366 2.12 2.12" />
23
- </svg>
24
- )
25
- }
26
-
27
- export { Spinner }
1
+ import * as React from "react"
2
+ import { cn } from "@/lib/utils"
3
+
4
+ interface SpinnerProps extends Omit<React.SVGProps<SVGSVGElement>, "width" | "height"> {
5
+ size?: number
6
+ }
7
+
8
+ function Spinner({ className, size = 20, style, ...props }: SpinnerProps) {
9
+ return (
10
+ <svg
11
+ fill="none"
12
+ stroke="currentColor"
13
+ strokeWidth="1.5"
14
+ viewBox="0 0 24 24"
15
+ strokeLinecap="round"
16
+ strokeLinejoin="round"
17
+ xmlns="http://www.w3.org/2000/svg"
18
+ className={cn("animate-spin text-muted-foreground", className)}
19
+ style={{ width: size, height: size, ...style }}
20
+ {...props}
21
+ >
22
+ <path d="M12 3v3m6.366-.366-2.12 2.12M21 12h-3m.366 6.366-2.12-2.12M12 21v-3m-6.366.366 2.12-2.12M3 12h3m-.366-6.366 2.12 2.12" />
23
+ </svg>
24
+ )
25
+ }
26
+
27
+ export { Spinner }
@@ -1,47 +1,47 @@
1
- 'use client'
2
-
3
- import * as React from 'react'
4
- import { useFormStatus } from 'react-dom'
5
- import { cn } from '@/lib/utils'
6
- import { Button, type buttonVariants } from './button'
7
- import { Spinner } from './spinner'
8
- import type { VariantProps } from 'class-variance-authority'
9
-
10
- interface SubmitButtonProps
11
- extends React.ComponentProps<'button'>,
12
- VariantProps<typeof buttonVariants> {
13
- isSubmitting?: boolean
14
- }
15
-
16
- function SubmitButton({
17
- children,
18
- className,
19
- disabled,
20
- isSubmitting: isSubmittingProp,
21
- variant = 'default',
22
- size = 'default',
23
- ...props
24
- }: SubmitButtonProps) {
25
- const { pending } = useFormStatus()
26
- const isSubmitting = isSubmittingProp ?? pending
27
-
28
- return (
29
- <Button
30
- type="submit"
31
- variant={variant}
32
- size={size}
33
- disabled={disabled || isSubmitting}
34
- className={cn('relative', className)}
35
- {...props}
36
- >
37
- {isSubmitting && (
38
- <span className="absolute inset-0 flex items-center justify-center">
39
- <Spinner size={16} />
40
- </span>
41
- )}
42
- <span className={cn(isSubmitting && 'invisible')}>{children}</span>
43
- </Button>
44
- )
45
- }
46
-
47
- export { SubmitButton }
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { useFormStatus } from 'react-dom'
5
+ import { cn } from '@/lib/utils'
6
+ import { Button, type buttonVariants } from './button'
7
+ import { Spinner } from './spinner'
8
+ import type { VariantProps } from 'class-variance-authority'
9
+
10
+ interface SubmitButtonProps
11
+ extends React.ComponentProps<'button'>,
12
+ VariantProps<typeof buttonVariants> {
13
+ isSubmitting?: boolean
14
+ }
15
+
16
+ function SubmitButton({
17
+ children,
18
+ className,
19
+ disabled,
20
+ isSubmitting: isSubmittingProp,
21
+ variant = 'default',
22
+ size = 'default',
23
+ ...props
24
+ }: SubmitButtonProps) {
25
+ const { pending } = useFormStatus()
26
+ const isSubmitting = isSubmittingProp ?? pending
27
+
28
+ return (
29
+ <Button
30
+ type="submit"
31
+ variant={variant}
32
+ size={size}
33
+ disabled={disabled || isSubmitting}
34
+ className={cn('relative', className)}
35
+ {...props}
36
+ >
37
+ {isSubmitting && (
38
+ <span className="absolute inset-0 flex items-center justify-center">
39
+ <Spinner size={16} />
40
+ </span>
41
+ )}
42
+ <span className={cn(isSubmitting && 'invisible')}>{children}</span>
43
+ </Button>
44
+ )
45
+ }
46
+
47
+ export { SubmitButton }
@@ -1,31 +1,31 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import * as SwitchPrimitive from "@radix-ui/react-switch"
5
-
6
- import { cn } from "@/lib/utils"
7
-
8
- function Switch({
9
- className,
10
- ...props
11
- }: React.ComponentProps<typeof SwitchPrimitive.Root>) {
12
- return (
13
- <SwitchPrimitive.Root
14
- data-slot="switch"
15
- className={cn(
16
- "peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
17
- className
18
- )}
19
- {...props}
20
- >
21
- <SwitchPrimitive.Thumb
22
- data-slot="switch-thumb"
23
- className={cn(
24
- "bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
25
- )}
26
- />
27
- </SwitchPrimitive.Root>
28
- )
29
- }
30
-
31
- export { Switch }
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as SwitchPrimitive from "@radix-ui/react-switch"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ function Switch({
9
+ className,
10
+ ...props
11
+ }: React.ComponentProps<typeof SwitchPrimitive.Root>) {
12
+ return (
13
+ <SwitchPrimitive.Root
14
+ data-slot="switch"
15
+ className={cn(
16
+ "peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
17
+ className
18
+ )}
19
+ {...props}
20
+ >
21
+ <SwitchPrimitive.Thumb
22
+ data-slot="switch-thumb"
23
+ className={cn(
24
+ "bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
25
+ )}
26
+ />
27
+ </SwitchPrimitive.Root>
28
+ )
29
+ }
30
+
31
+ export { Switch }