create-auto-app 0.1.0 → 0.1.2

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 (187) hide show
  1. package/dist/index.js +189 -85
  2. package/dist/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/templates/shopping-app/.context/auto-ia-scheme.json +175 -0
  5. package/templates/shopping-app/.context/design-system.md +118 -0
  6. package/templates/shopping-app/.context/figma-variables.json +14448 -0
  7. package/templates/shopping-app/.context/schema.graphql +46 -0
  8. package/templates/shopping-app/.context/schema.json +583 -0
  9. package/templates/shopping-app/.context/shadcn-filter.ts +31 -0
  10. package/templates/shopping-app/.env +8 -0
  11. package/templates/shopping-app/auto.config.ts +21 -0
  12. package/templates/shopping-app/client/auto-configure.ts +107 -0
  13. package/templates/shopping-app/client/codegen.ts +16 -0
  14. package/templates/shopping-app/client/components.json +20 -0
  15. package/templates/shopping-app/client/design-system-principles.md +19 -0
  16. package/templates/shopping-app/client/eslint.config.ts +57 -0
  17. package/templates/shopping-app/client/index.html +26 -0
  18. package/templates/shopping-app/client/package.json +100 -0
  19. package/templates/shopping-app/client/postcss.config.js +6 -0
  20. package/templates/shopping-app/client/public/favicon.ico +0 -0
  21. package/templates/shopping-app/client/schema.graphql +46 -0
  22. package/templates/shopping-app/client/src/App.css +42 -0
  23. package/templates/shopping-app/client/src/App.tsx +20 -0
  24. package/templates/shopping-app/client/src/apolloClient.ts +8 -0
  25. package/templates/shopping-app/client/src/components/atoms/accordion.tsx +51 -0
  26. package/templates/shopping-app/client/src/components/atoms/alert-dialog.tsx +111 -0
  27. package/templates/shopping-app/client/src/components/atoms/alert.tsx +49 -0
  28. package/templates/shopping-app/client/src/components/atoms/aspect-ratio.tsx +7 -0
  29. package/templates/shopping-app/client/src/components/atoms/avatar.tsx +32 -0
  30. package/templates/shopping-app/client/src/components/atoms/badge.tsx +36 -0
  31. package/templates/shopping-app/client/src/components/atoms/breadcrumb.tsx +92 -0
  32. package/templates/shopping-app/client/src/components/atoms/button.tsx +50 -0
  33. package/templates/shopping-app/client/src/components/atoms/calendar.tsx +156 -0
  34. package/templates/shopping-app/client/src/components/atoms/card.tsx +56 -0
  35. package/templates/shopping-app/client/src/components/atoms/carousel.tsx +214 -0
  36. package/templates/shopping-app/client/src/components/atoms/chart.tsx +290 -0
  37. package/templates/shopping-app/client/src/components/atoms/checkbox.tsx +27 -0
  38. package/templates/shopping-app/client/src/components/atoms/collapsible.tsx +15 -0
  39. package/templates/shopping-app/client/src/components/atoms/command.tsx +135 -0
  40. package/templates/shopping-app/client/src/components/atoms/context-menu.tsx +209 -0
  41. package/templates/shopping-app/client/src/components/atoms/dialog.tsx +123 -0
  42. package/templates/shopping-app/client/src/components/atoms/drawer.tsx +106 -0
  43. package/templates/shopping-app/client/src/components/atoms/dropdown-menu.tsx +217 -0
  44. package/templates/shopping-app/client/src/components/atoms/hover-card.tsx +36 -0
  45. package/templates/shopping-app/client/src/components/atoms/input-otp.tsx +66 -0
  46. package/templates/shopping-app/client/src/components/atoms/input.tsx +21 -0
  47. package/templates/shopping-app/client/src/components/atoms/label.tsx +19 -0
  48. package/templates/shopping-app/client/src/components/atoms/logo.tsx +33 -0
  49. package/templates/shopping-app/client/src/components/atoms/menubar.tsx +234 -0
  50. package/templates/shopping-app/client/src/components/atoms/navigation-menu.tsx +142 -0
  51. package/templates/shopping-app/client/src/components/atoms/pagination.tsx +100 -0
  52. package/templates/shopping-app/client/src/components/atoms/popover.tsx +40 -0
  53. package/templates/shopping-app/client/src/components/atoms/progress.tsx +22 -0
  54. package/templates/shopping-app/client/src/components/atoms/radio-group.tsx +31 -0
  55. package/templates/shopping-app/client/src/components/atoms/resizable.tsx +46 -0
  56. package/templates/shopping-app/client/src/components/atoms/scroll-area.tsx +46 -0
  57. package/templates/shopping-app/client/src/components/atoms/select.tsx +158 -0
  58. package/templates/shopping-app/client/src/components/atoms/separator.tsx +26 -0
  59. package/templates/shopping-app/client/src/components/atoms/sheet.tsx +101 -0
  60. package/templates/shopping-app/client/src/components/atoms/sidebar.tsx +675 -0
  61. package/templates/shopping-app/client/src/components/atoms/skeleton.tsx +7 -0
  62. package/templates/shopping-app/client/src/components/atoms/slider.tsx +54 -0
  63. package/templates/shopping-app/client/src/components/atoms/sonner.tsx +23 -0
  64. package/templates/shopping-app/client/src/components/atoms/switch.tsx +26 -0
  65. package/templates/shopping-app/client/src/components/atoms/table.tsx +73 -0
  66. package/templates/shopping-app/client/src/components/atoms/tabs.tsx +40 -0
  67. package/templates/shopping-app/client/src/components/atoms/textarea.tsx +18 -0
  68. package/templates/shopping-app/client/src/components/atoms/toggle-group.tsx +65 -0
  69. package/templates/shopping-app/client/src/components/atoms/toggle.tsx +39 -0
  70. package/templates/shopping-app/client/src/components/atoms/tooltip.tsx +48 -0
  71. package/templates/shopping-app/client/src/components/molecules/QuantitySelector.tsx +8 -0
  72. package/templates/shopping-app/client/src/components/molecules/ShoppingCriteriaForm.tsx +8 -0
  73. package/templates/shopping-app/client/src/components/molecules/SuggestedItemCard.tsx +10 -0
  74. package/templates/shopping-app/client/src/components/organisms/AssistantChatInterface.tsx +14 -0
  75. package/templates/shopping-app/client/src/components/organisms/PageHeader.tsx +6 -0
  76. package/templates/shopping-app/client/src/components/organisms/SuggestedItemsList.tsx +15 -0
  77. package/templates/shopping-app/client/src/gql/fragment-masking.ts +48 -0
  78. package/templates/shopping-app/client/src/gql/gql.ts +47 -0
  79. package/templates/shopping-app/client/src/gql/graphql.ts +106 -0
  80. package/templates/shopping-app/client/src/gql/index.ts +2 -0
  81. package/templates/shopping-app/client/src/graphql/mutations.ts +13 -0
  82. package/templates/shopping-app/client/src/graphql/queries.ts +14 -0
  83. package/templates/shopping-app/client/src/hooks/use-mobile.tsx +19 -0
  84. package/templates/shopping-app/client/src/hooks/use-toast.ts +186 -0
  85. package/templates/shopping-app/client/src/index.css +153 -0
  86. package/templates/shopping-app/client/src/lib/utils.ts +6 -0
  87. package/templates/shopping-app/client/src/main.tsx +5 -0
  88. package/templates/shopping-app/client/src/mockApolloClient.ts +93 -0
  89. package/templates/shopping-app/client/src/pages/AssistantChatPage.tsx +8 -0
  90. package/templates/shopping-app/client/src/pages/Index.tsx +10 -0
  91. package/templates/shopping-app/client/src/pages/NotFound.tsx +22 -0
  92. package/templates/shopping-app/client/src/pages/SuggestedItemsPage.tsx +8 -0
  93. package/templates/shopping-app/client/tailwind.config.ts +92 -0
  94. package/templates/shopping-app/client/tsconfig.json +49 -0
  95. package/templates/shopping-app/client/vite.config.ts +17 -0
  96. package/templates/shopping-app/flows/shopping-assistant.flow.ts +369 -0
  97. package/templates/shopping-app/package.json +25 -0
  98. package/templates/shopping-app/pnpm-workspace.yaml +2 -0
  99. package/templates/shopping-app/server/package.json +25 -0
  100. package/templates/shopping-app/server/scripts/generate-schema.ts +31 -0
  101. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/commands.ts +8 -0
  102. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/decide.specs.ts +46 -0
  103. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/decide.ts +36 -0
  104. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/events.ts +10 -0
  105. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/evolve.ts +28 -0
  106. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/handle.ts +31 -0
  107. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/mutation.resolver.ts +29 -0
  108. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/register.ts +10 -0
  109. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/accepts-items-and-adds-to-their-cart/state.ts +47 -0
  110. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/creates-a-chat-session-/react.specs.ts +63 -0
  111. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/creates-a-chat-session-/react.ts +49 -0
  112. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/creates-a-chat-session-/register.ts +31 -0
  113. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/commands.ts +8 -0
  114. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/decide.specs.ts +38 -0
  115. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/decide.ts +36 -0
  116. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/events.ts +10 -0
  117. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/evolve.ts +28 -0
  118. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/handle.ts +31 -0
  119. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/mutation.resolver.ts +30 -0
  120. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/register.ts +10 -0
  121. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/enters-shopping-criteria-into-assistant/state.ts +47 -0
  122. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/commands.ts +8 -0
  123. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/decide.specs.ts +61 -0
  124. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/decide.ts +45 -0
  125. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/events.ts +14 -0
  126. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/evolve.ts +28 -0
  127. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/handle.ts +59 -0
  128. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/mutation.resolver.ts +30 -0
  129. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/register.ts +10 -0
  130. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/selects-items-relevant-to-the-shopping-criteria-/state.ts +47 -0
  131. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/views-suggested-items/projection.specs.ts +94 -0
  132. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/views-suggested-items/projection.ts +40 -0
  133. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/views-suggested-items/query.resolver.ts +59 -0
  134. package/templates/shopping-app/server/src/domain/flows/seasonal-assistant/views-suggested-items/state.ts +9 -0
  135. package/templates/shopping-app/server/src/domain/shared/ReadModel.d.ts +10 -0
  136. package/templates/shopping-app/server/src/domain/shared/ReadModel.d.ts.map +1 -0
  137. package/templates/shopping-app/server/src/domain/shared/ReadModel.js +19 -0
  138. package/templates/shopping-app/server/src/domain/shared/ReadModel.js.map +1 -0
  139. package/templates/shopping-app/server/src/domain/shared/ReadModel.ts +26 -0
  140. package/templates/shopping-app/server/src/domain/shared/index.d.ts +5 -0
  141. package/templates/shopping-app/server/src/domain/shared/index.d.ts.map +1 -0
  142. package/templates/shopping-app/server/src/domain/shared/index.js +5 -0
  143. package/templates/shopping-app/server/src/domain/shared/index.js.map +1 -0
  144. package/templates/shopping-app/server/src/domain/shared/index.ts +4 -0
  145. package/templates/shopping-app/server/src/domain/shared/reactorSpecification.d.ts +35 -0
  146. package/templates/shopping-app/server/src/domain/shared/reactorSpecification.d.ts.map +1 -0
  147. package/templates/shopping-app/server/src/domain/shared/reactorSpecification.js +155 -0
  148. package/templates/shopping-app/server/src/domain/shared/reactorSpecification.js.map +1 -0
  149. package/templates/shopping-app/server/src/domain/shared/reactorSpecification.ts +257 -0
  150. package/templates/shopping-app/server/src/domain/shared/sendCommand.d.ts +4 -0
  151. package/templates/shopping-app/server/src/domain/shared/sendCommand.d.ts.map +1 -0
  152. package/templates/shopping-app/server/src/domain/shared/sendCommand.js +17 -0
  153. package/templates/shopping-app/server/src/domain/shared/sendCommand.js.map +1 -0
  154. package/templates/shopping-app/server/src/domain/shared/sendCommand.ts +21 -0
  155. package/templates/shopping-app/server/src/domain/shared/types.d.ts +19 -0
  156. package/templates/shopping-app/server/src/domain/shared/types.d.ts.map +1 -0
  157. package/templates/shopping-app/server/src/domain/shared/types.js +39 -0
  158. package/templates/shopping-app/server/src/domain/shared/types.js.map +1 -0
  159. package/templates/shopping-app/server/src/domain/shared/types.ts +31 -0
  160. package/templates/shopping-app/server/src/integrations/ai-integration.ts +76 -0
  161. package/templates/shopping-app/server/src/integrations/cart-integration.ts +178 -0
  162. package/templates/shopping-app/server/src/integrations/index.ts +3 -0
  163. package/templates/shopping-app/server/src/integrations/product-catalogue-integration.ts +363 -0
  164. package/templates/shopping-app/server/src/server.ts +43 -0
  165. package/templates/shopping-app/server/src/utils/index.d.ts +4 -0
  166. package/templates/shopping-app/server/src/utils/index.d.ts.map +1 -0
  167. package/templates/shopping-app/server/src/utils/index.js +4 -0
  168. package/templates/shopping-app/server/src/utils/index.js.map +1 -0
  169. package/templates/shopping-app/server/src/utils/index.ts +3 -0
  170. package/templates/shopping-app/server/src/utils/loadProjections.d.ts +3 -0
  171. package/templates/shopping-app/server/src/utils/loadProjections.d.ts.map +1 -0
  172. package/templates/shopping-app/server/src/utils/loadProjections.js +23 -0
  173. package/templates/shopping-app/server/src/utils/loadProjections.js.map +1 -0
  174. package/templates/shopping-app/server/src/utils/loadProjections.ts +30 -0
  175. package/templates/shopping-app/server/src/utils/loadRegisterFiles.d.ts +6 -0
  176. package/templates/shopping-app/server/src/utils/loadRegisterFiles.d.ts.map +1 -0
  177. package/templates/shopping-app/server/src/utils/loadRegisterFiles.js +28 -0
  178. package/templates/shopping-app/server/src/utils/loadRegisterFiles.js.map +1 -0
  179. package/templates/shopping-app/server/src/utils/loadRegisterFiles.ts +41 -0
  180. package/templates/shopping-app/server/src/utils/loadResolvers.d.ts +5 -0
  181. package/templates/shopping-app/server/src/utils/loadResolvers.d.ts.map +1 -0
  182. package/templates/shopping-app/server/src/utils/loadResolvers.js +27 -0
  183. package/templates/shopping-app/server/src/utils/loadResolvers.js.map +1 -0
  184. package/templates/shopping-app/server/src/utils/loadResolvers.ts +36 -0
  185. package/templates/shopping-app/server/tsconfig.json +19 -0
  186. package/templates/shopping-app/server/vitest.config.ts +7 -0
  187. package/templates/shopping-app/tsconfig.json +21 -0
@@ -0,0 +1,66 @@
1
+ import * as React from 'react';
2
+ import { OTPInput, OTPInputContext } from 'input-otp';
3
+ import { MinusIcon } from 'lucide-react';
4
+
5
+ import { cn } from '../../lib/utils';
6
+
7
+ function InputOTP({
8
+ className,
9
+ containerClassName,
10
+ ...props
11
+ }: React.ComponentProps<typeof OTPInput> & {
12
+ containerClassName?: string;
13
+ }) {
14
+ return (
15
+ <OTPInput
16
+ data-slot="input-otp"
17
+ containerClassName={cn('flex items-center gap-2 has-disabled:opacity-50', containerClassName)}
18
+ className={cn('disabled:cursor-not-allowed', className)}
19
+ {...props}
20
+ />
21
+ );
22
+ }
23
+
24
+ function InputOTPGroup({ className, ...props }: React.ComponentProps<'div'>) {
25
+ return <div data-slot="input-otp-group" className={cn('flex items-center', className)} {...props} />;
26
+ }
27
+
28
+ function InputOTPSlot({
29
+ index,
30
+ className,
31
+ ...props
32
+ }: React.ComponentProps<'div'> & {
33
+ index: number;
34
+ }) {
35
+ const inputOTPContext = React.useContext(OTPInputContext);
36
+ const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
37
+
38
+ return (
39
+ <div
40
+ data-slot="input-otp-slot"
41
+ data-active={isActive}
42
+ className={cn(
43
+ 'data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive dark:bg-input/30 border-input relative flex h-9 w-9 items-center justify-center border-y border-r text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md data-[active=true]:z-10 data-[active=true]:ring-[3px]',
44
+ className,
45
+ )}
46
+ {...props}
47
+ >
48
+ {char}
49
+ {hasFakeCaret && (
50
+ <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
51
+ <div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
52
+ </div>
53
+ )}
54
+ </div>
55
+ );
56
+ }
57
+
58
+ function InputOTPSeparator({ ...props }: React.ComponentProps<'div'>) {
59
+ return (
60
+ <div data-slot="input-otp-separator" role="separator" {...props}>
61
+ <MinusIcon />
62
+ </div>
63
+ );
64
+ }
65
+
66
+ export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+
3
+ import { cn } from '../../lib/utils';
4
+
5
+ function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
6
+ return (
7
+ <input
8
+ type={type}
9
+ data-slot="input"
10
+ className={cn(
11
+ 'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
12
+ 'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
13
+ 'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
14
+ className,
15
+ )}
16
+ {...props}
17
+ />
18
+ );
19
+ }
20
+
21
+ export { Input };
@@ -0,0 +1,19 @@
1
+ import * as React from 'react';
2
+ import * as LabelPrimitive from '@radix-ui/react-label';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ function Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {
7
+ return (
8
+ <LabelPrimitive.Root
9
+ data-slot="label"
10
+ className={cn(
11
+ 'flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
12
+ className,
13
+ )}
14
+ {...props}
15
+ />
16
+ );
17
+ }
18
+
19
+ export { Label };
@@ -0,0 +1,33 @@
1
+ import { cn } from '../../lib/utils';
2
+
3
+ interface LogoProps {
4
+ className?: string;
5
+ size?: 'sm' | 'md' | 'lg' | 'xl';
6
+ }
7
+
8
+ const sizeClasses = {
9
+ sm: 'h-4 w-4',
10
+ md: 'h-6 w-6',
11
+ lg: 'h-8 w-8',
12
+ xl: 'h-12 w-12',
13
+ };
14
+
15
+ export function Logo({ className, size = 'md' }: LogoProps) {
16
+ return (
17
+ <svg
18
+ xmlns="http://www.w3.org/2000/svg"
19
+ viewBox="0 0 512.016 512.016"
20
+ className={cn(sizeClasses[size], className)}
21
+ id="ShoppingCart"
22
+ >
23
+ <polygon points="145.544,151.36 105.184,31.92 0.68,31.92 0.68,0 128.096,0 175.784,141.136" fill="currentColor" />
24
+ <polygon points="68.128,124.56 511.336,124.56 426.856,361.584 141.936,361.584" fill="#FFD67F" />
25
+ <circle cx="377.128" cy="450.56" r="61.456" fill="currentColor" />
26
+ <circle cx="191.752" cy="450.56" r="61.456" fill="currentColor" />
27
+ <polygon
28
+ points="325.28,52.496 451.744,180.664 325.28,308.816 203.936,308.816 330.608,180.664 203.936,52.496"
29
+ fill="#FF583E"
30
+ />
31
+ </svg>
32
+ );
33
+ }
@@ -0,0 +1,234 @@
1
+ import * as React from 'react';
2
+ import * as MenubarPrimitive from '@radix-ui/react-menubar';
3
+ import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react';
4
+
5
+ import { cn } from '../../lib/utils';
6
+
7
+ function Menubar({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Root>) {
8
+ return (
9
+ <MenubarPrimitive.Root
10
+ data-slot="menubar"
11
+ className={cn('bg-background flex h-9 items-center gap-1 rounded-md border p-1 shadow-xs', className)}
12
+ {...props}
13
+ />
14
+ );
15
+ }
16
+
17
+ function MenubarMenu({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Menu>) {
18
+ return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />;
19
+ }
20
+
21
+ function MenubarGroup({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Group>) {
22
+ return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />;
23
+ }
24
+
25
+ function MenubarPortal({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Portal>) {
26
+ return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />;
27
+ }
28
+
29
+ function MenubarRadioGroup({ ...props }: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {
30
+ return <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} />;
31
+ }
32
+
33
+ function MenubarTrigger({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Trigger>) {
34
+ return (
35
+ <MenubarPrimitive.Trigger
36
+ data-slot="menubar-trigger"
37
+ className={cn(
38
+ 'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none',
39
+ className,
40
+ )}
41
+ {...props}
42
+ />
43
+ );
44
+ }
45
+
46
+ function MenubarContent({
47
+ className,
48
+ align = 'start',
49
+ alignOffset = -4,
50
+ sideOffset = 8,
51
+ ...props
52
+ }: React.ComponentProps<typeof MenubarPrimitive.Content>) {
53
+ return (
54
+ <MenubarPortal>
55
+ <MenubarPrimitive.Content
56
+ data-slot="menubar-content"
57
+ align={align}
58
+ alignOffset={alignOffset}
59
+ sideOffset={sideOffset}
60
+ className={cn(
61
+ 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md',
62
+ className,
63
+ )}
64
+ {...props}
65
+ />
66
+ </MenubarPortal>
67
+ );
68
+ }
69
+
70
+ function MenubarItem({
71
+ className,
72
+ inset,
73
+ variant = 'default',
74
+ ...props
75
+ }: React.ComponentProps<typeof MenubarPrimitive.Item> & {
76
+ inset?: boolean;
77
+ variant?: 'default' | 'destructive';
78
+ }) {
79
+ return (
80
+ <MenubarPrimitive.Item
81
+ data-slot="menubar-item"
82
+ data-inset={inset}
83
+ data-variant={variant}
84
+ className={cn(
85
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
86
+ className,
87
+ )}
88
+ {...props}
89
+ />
90
+ );
91
+ }
92
+
93
+ function MenubarCheckboxItem({
94
+ className,
95
+ children,
96
+ checked,
97
+ ...props
98
+ }: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) {
99
+ return (
100
+ <MenubarPrimitive.CheckboxItem
101
+ data-slot="menubar-checkbox-item"
102
+ className={cn(
103
+ "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
104
+ className,
105
+ )}
106
+ checked={Boolean(checked)}
107
+ {...props}
108
+ >
109
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
110
+ <MenubarPrimitive.ItemIndicator>
111
+ <CheckIcon className="size-4" />
112
+ </MenubarPrimitive.ItemIndicator>
113
+ </span>
114
+ {children}
115
+ </MenubarPrimitive.CheckboxItem>
116
+ );
117
+ }
118
+
119
+ function MenubarRadioItem({ className, children, ...props }: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) {
120
+ return (
121
+ <MenubarPrimitive.RadioItem
122
+ data-slot="menubar-radio-item"
123
+ className={cn(
124
+ "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
125
+ className,
126
+ )}
127
+ {...props}
128
+ >
129
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
130
+ <MenubarPrimitive.ItemIndicator>
131
+ <CircleIcon className="size-2 fill-current" />
132
+ </MenubarPrimitive.ItemIndicator>
133
+ </span>
134
+ {children}
135
+ </MenubarPrimitive.RadioItem>
136
+ );
137
+ }
138
+
139
+ function MenubarLabel({
140
+ className,
141
+ inset,
142
+ ...props
143
+ }: React.ComponentProps<typeof MenubarPrimitive.Label> & {
144
+ inset?: boolean;
145
+ }) {
146
+ return (
147
+ <MenubarPrimitive.Label
148
+ data-slot="menubar-label"
149
+ data-inset={inset}
150
+ className={cn('px-2 py-1.5 text-sm font-medium data-[inset]:pl-8', className)}
151
+ {...props}
152
+ />
153
+ );
154
+ }
155
+
156
+ function MenubarSeparator({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Separator>) {
157
+ return (
158
+ <MenubarPrimitive.Separator
159
+ data-slot="menubar-separator"
160
+ className={cn('bg-border -mx-1 my-1 h-px', className)}
161
+ {...props}
162
+ />
163
+ );
164
+ }
165
+
166
+ function MenubarShortcut({ className, ...props }: React.ComponentProps<'span'>) {
167
+ return (
168
+ <span
169
+ data-slot="menubar-shortcut"
170
+ className={cn('text-muted-foreground ml-auto text-xs tracking-widest', className)}
171
+ {...props}
172
+ />
173
+ );
174
+ }
175
+
176
+ function MenubarSub({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Sub>) {
177
+ return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />;
178
+ }
179
+
180
+ function MenubarSubTrigger({
181
+ className,
182
+ inset,
183
+ children,
184
+ ...props
185
+ }: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & {
186
+ inset?: boolean;
187
+ }) {
188
+ return (
189
+ <MenubarPrimitive.SubTrigger
190
+ data-slot="menubar-sub-trigger"
191
+ data-inset={inset}
192
+ className={cn(
193
+ 'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8',
194
+ className,
195
+ )}
196
+ {...props}
197
+ >
198
+ {children}
199
+ <ChevronRightIcon className="ml-auto h-4 w-4" />
200
+ </MenubarPrimitive.SubTrigger>
201
+ );
202
+ }
203
+
204
+ function MenubarSubContent({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.SubContent>) {
205
+ return (
206
+ <MenubarPrimitive.SubContent
207
+ data-slot="menubar-sub-content"
208
+ className={cn(
209
+ 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
210
+ className,
211
+ )}
212
+ {...props}
213
+ />
214
+ );
215
+ }
216
+
217
+ export {
218
+ Menubar,
219
+ MenubarPortal,
220
+ MenubarMenu,
221
+ MenubarTrigger,
222
+ MenubarContent,
223
+ MenubarGroup,
224
+ MenubarSeparator,
225
+ MenubarLabel,
226
+ MenubarItem,
227
+ MenubarShortcut,
228
+ MenubarCheckboxItem,
229
+ MenubarRadioGroup,
230
+ MenubarRadioItem,
231
+ MenubarSub,
232
+ MenubarSubTrigger,
233
+ MenubarSubContent,
234
+ };
@@ -0,0 +1,142 @@
1
+ import * as React from 'react';
2
+ import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu';
3
+ import { cva } from 'class-variance-authority';
4
+ import { ChevronDownIcon } from 'lucide-react';
5
+
6
+ import { cn } from '../../lib/utils';
7
+
8
+ function NavigationMenu({
9
+ className,
10
+ children,
11
+ viewport = true,
12
+ ...props
13
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
14
+ viewport?: boolean;
15
+ }) {
16
+ return (
17
+ <NavigationMenuPrimitive.Root
18
+ data-slot="navigation-menu"
19
+ data-viewport={viewport}
20
+ className={cn('group/navigation-menu relative flex max-w-max flex-1 items-center justify-center', className)}
21
+ {...props}
22
+ >
23
+ {children}
24
+ {viewport && <NavigationMenuViewport />}
25
+ </NavigationMenuPrimitive.Root>
26
+ );
27
+ }
28
+
29
+ function NavigationMenuList({ className, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
30
+ return (
31
+ <NavigationMenuPrimitive.List
32
+ data-slot="navigation-menu-list"
33
+ className={cn('group flex flex-1 list-none items-center justify-center gap-1', className)}
34
+ {...props}
35
+ />
36
+ );
37
+ }
38
+
39
+ function NavigationMenuItem({ className, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
40
+ return (
41
+ <NavigationMenuPrimitive.Item data-slot="navigation-menu-item" className={cn('relative', className)} {...props} />
42
+ );
43
+ }
44
+
45
+ const navigationMenuTriggerStyle = cva(
46
+ 'group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',
47
+ );
48
+
49
+ function NavigationMenuTrigger({
50
+ className,
51
+ children,
52
+ ...props
53
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
54
+ return (
55
+ <NavigationMenuPrimitive.Trigger
56
+ data-slot="navigation-menu-trigger"
57
+ className={cn(navigationMenuTriggerStyle(), 'group', className)}
58
+ {...props}
59
+ >
60
+ {children}{' '}
61
+ <ChevronDownIcon
62
+ className="relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180"
63
+ aria-hidden="true"
64
+ />
65
+ </NavigationMenuPrimitive.Trigger>
66
+ );
67
+ }
68
+
69
+ function NavigationMenuContent({ className, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
70
+ return (
71
+ <NavigationMenuPrimitive.Content
72
+ data-slot="navigation-menu-content"
73
+ className={cn(
74
+ 'data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto',
75
+ 'group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none',
76
+ className,
77
+ )}
78
+ {...props}
79
+ />
80
+ );
81
+ }
82
+
83
+ function NavigationMenuViewport({
84
+ className,
85
+ ...props
86
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
87
+ return (
88
+ <div className={cn('absolute top-full left-0 isolate z-50 flex justify-center')}>
89
+ <NavigationMenuPrimitive.Viewport
90
+ data-slot="navigation-menu-viewport"
91
+ className={cn(
92
+ 'origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow md:w-[var(--radix-navigation-menu-viewport-width)]',
93
+ className,
94
+ )}
95
+ {...props}
96
+ />
97
+ </div>
98
+ );
99
+ }
100
+
101
+ function NavigationMenuLink({ className, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
102
+ return (
103
+ <NavigationMenuPrimitive.Link
104
+ data-slot="navigation-menu-link"
105
+ className={cn(
106
+ "data-[active=true]:focus:bg-accent data-[active=true]:hover:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring/50 [&_svg:not([class*='text-'])]:text-muted-foreground flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none focus-visible:ring-[3px] focus-visible:outline-1 [&_svg:not([class*='size-'])]:size-4",
107
+ className,
108
+ )}
109
+ {...props}
110
+ />
111
+ );
112
+ }
113
+
114
+ function NavigationMenuIndicator({
115
+ className,
116
+ ...props
117
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
118
+ return (
119
+ <NavigationMenuPrimitive.Indicator
120
+ data-slot="navigation-menu-indicator"
121
+ className={cn(
122
+ 'data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden',
123
+ className,
124
+ )}
125
+ {...props}
126
+ >
127
+ <div className="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
128
+ </NavigationMenuPrimitive.Indicator>
129
+ );
130
+ }
131
+
132
+ export {
133
+ NavigationMenu,
134
+ NavigationMenuList,
135
+ NavigationMenuItem,
136
+ NavigationMenuContent,
137
+ NavigationMenuTrigger,
138
+ NavigationMenuLink,
139
+ NavigationMenuIndicator,
140
+ NavigationMenuViewport,
141
+ navigationMenuTriggerStyle,
142
+ };
@@ -0,0 +1,100 @@
1
+ import * as React from 'react';
2
+ import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from 'lucide-react';
3
+
4
+ import { cn } from '../../lib/utils';
5
+ import { Button, buttonVariants } from './button';
6
+
7
+ function Pagination({ className, ...props }: React.ComponentProps<'nav'>) {
8
+ return (
9
+ <nav
10
+ role="navigation"
11
+ aria-label="pagination"
12
+ data-slot="pagination"
13
+ className={cn('mx-auto flex w-full justify-center', className)}
14
+ {...props}
15
+ />
16
+ );
17
+ }
18
+
19
+ function PaginationContent({ className, ...props }: React.ComponentProps<'ul'>) {
20
+ return <ul data-slot="pagination-content" className={cn('flex flex-row items-center gap-1', className)} {...props} />;
21
+ }
22
+
23
+ function PaginationItem({ ...props }: React.ComponentProps<'li'>) {
24
+ return <li data-slot="pagination-item" {...props} />;
25
+ }
26
+
27
+ type PaginationLinkProps = {
28
+ isActive?: boolean;
29
+ } & Pick<React.ComponentProps<typeof Button>, 'size'> &
30
+ React.ComponentProps<'a'>;
31
+
32
+ function PaginationLink({ className, isActive, size = 'icon', ...props }: PaginationLinkProps) {
33
+ return (
34
+ <a
35
+ aria-current={isActive ? 'page' : undefined}
36
+ data-slot="pagination-link"
37
+ data-active={isActive}
38
+ className={cn(
39
+ buttonVariants({
40
+ variant: isActive ? 'outline' : 'ghost',
41
+ size,
42
+ }),
43
+ className,
44
+ )}
45
+ {...props}
46
+ />
47
+ );
48
+ }
49
+
50
+ function PaginationPrevious({ className, ...props }: React.ComponentProps<typeof PaginationLink>) {
51
+ return (
52
+ <PaginationLink
53
+ aria-label="Go to previous page"
54
+ size="default"
55
+ className={cn('gap-1 px-2.5 sm:pl-2.5', className)}
56
+ {...props}
57
+ >
58
+ <ChevronLeftIcon />
59
+ <span className="hidden sm:block">Previous</span>
60
+ </PaginationLink>
61
+ );
62
+ }
63
+
64
+ function PaginationNext({ className, ...props }: React.ComponentProps<typeof PaginationLink>) {
65
+ return (
66
+ <PaginationLink
67
+ aria-label="Go to next page"
68
+ size="default"
69
+ className={cn('gap-1 px-2.5 sm:pr-2.5', className)}
70
+ {...props}
71
+ >
72
+ <span className="hidden sm:block">Next</span>
73
+ <ChevronRightIcon />
74
+ </PaginationLink>
75
+ );
76
+ }
77
+
78
+ function PaginationEllipsis({ className, ...props }: React.ComponentProps<'span'>) {
79
+ return (
80
+ <span
81
+ aria-hidden
82
+ data-slot="pagination-ellipsis"
83
+ className={cn('flex size-9 items-center justify-center', className)}
84
+ {...props}
85
+ >
86
+ <MoreHorizontalIcon className="size-4" />
87
+ <span className="sr-only">More pages</span>
88
+ </span>
89
+ );
90
+ }
91
+
92
+ export {
93
+ Pagination,
94
+ PaginationContent,
95
+ PaginationLink,
96
+ PaginationItem,
97
+ PaginationPrevious,
98
+ PaginationNext,
99
+ PaginationEllipsis,
100
+ };
@@ -0,0 +1,40 @@
1
+ import * as React from 'react';
2
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
7
+ return <PopoverPrimitive.Root data-slot="popover" {...props} />;
8
+ }
9
+
10
+ function PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
11
+ return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
12
+ }
13
+
14
+ function PopoverContent({
15
+ className,
16
+ align = 'center',
17
+ sideOffset = 4,
18
+ ...props
19
+ }: React.ComponentProps<typeof PopoverPrimitive.Content>) {
20
+ return (
21
+ <PopoverPrimitive.Portal>
22
+ <PopoverPrimitive.Content
23
+ data-slot="popover-content"
24
+ align={align}
25
+ sideOffset={sideOffset}
26
+ className={cn(
27
+ 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden',
28
+ className,
29
+ )}
30
+ {...props}
31
+ />
32
+ </PopoverPrimitive.Portal>
33
+ );
34
+ }
35
+
36
+ function PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
37
+ return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
38
+ }
39
+
40
+ export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
@@ -0,0 +1,22 @@
1
+ import * as React from 'react';
2
+ import * as ProgressPrimitive from '@radix-ui/react-progress';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ function Progress({ className, value, ...props }: React.ComponentProps<typeof ProgressPrimitive.Root>) {
7
+ return (
8
+ <ProgressPrimitive.Root
9
+ data-slot="progress"
10
+ className={cn('bg-primary/20 relative h-2 w-full overflow-hidden rounded-full', className)}
11
+ {...props}
12
+ >
13
+ <ProgressPrimitive.Indicator
14
+ data-slot="progress-indicator"
15
+ className="bg-primary h-full w-full flex-1 transition-all"
16
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
17
+ />
18
+ </ProgressPrimitive.Root>
19
+ );
20
+ }
21
+
22
+ export { Progress };