create-auto-app 1.34.0 → 1.36.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 (156) hide show
  1. package/package.json +2 -2
  2. package/templates/typical/.gitignore +1 -1
  3. package/templates/typical/auto.config.ts +85 -80
  4. package/templates/typical/client/.gitignore +0 -4
  5. package/templates/typical/client/.storybook/main.ts +0 -66
  6. package/templates/typical/client/.storybook/manager-head.html +0 -154
  7. package/templates/typical/client/.storybook/manager.ts +0 -164
  8. package/templates/typical/client/.storybook/preview-head.html +0 -31
  9. package/templates/typical/client/.storybook/preview.tsx +0 -120
  10. package/templates/typical/client/codegen.ts +0 -17
  11. package/templates/typical/client/components.json +0 -29
  12. package/templates/typical/client/index.html +0 -12
  13. package/templates/typical/client/package.json +0 -69
  14. package/templates/typical/client/pnpm-lock.yaml +0 -7868
  15. package/templates/typical/client/public/blank.svg +0 -1
  16. package/templates/typical/client/public/mockServiceWorker.js +0 -336
  17. package/templates/typical/client/src/App.tsx +0 -29
  18. package/templates/typical/client/src/components/.gitkeep +0 -0
  19. package/templates/typical/client/src/components/ui/Accordion.stories.tsx +0 -49
  20. package/templates/typical/client/src/components/ui/Accordion.tsx +0 -55
  21. package/templates/typical/client/src/components/ui/Alert.stories.tsx +0 -29
  22. package/templates/typical/client/src/components/ui/Alert.tsx +0 -56
  23. package/templates/typical/client/src/components/ui/AlertDialog.stories.tsx +0 -67
  24. package/templates/typical/client/src/components/ui/AlertDialog.tsx +0 -178
  25. package/templates/typical/client/src/components/ui/AspectRatio.stories.tsx +0 -35
  26. package/templates/typical/client/src/components/ui/AspectRatio.tsx +0 -13
  27. package/templates/typical/client/src/components/ui/Avatar.stories.tsx +0 -45
  28. package/templates/typical/client/src/components/ui/Avatar.tsx +0 -98
  29. package/templates/typical/client/src/components/ui/Badge.stories.tsx +0 -41
  30. package/templates/typical/client/src/components/ui/Badge.tsx +0 -45
  31. package/templates/typical/client/src/components/ui/Breadcrumb.stories.tsx +0 -54
  32. package/templates/typical/client/src/components/ui/Breadcrumb.tsx +0 -104
  33. package/templates/typical/client/src/components/ui/Button.stories.tsx +0 -102
  34. package/templates/typical/client/src/components/ui/Button.tsx +0 -67
  35. package/templates/typical/client/src/components/ui/ButtonGroup.stories.tsx +0 -32
  36. package/templates/typical/client/src/components/ui/ButtonGroup.tsx +0 -81
  37. package/templates/typical/client/src/components/ui/Calendar.stories.tsx +0 -40
  38. package/templates/typical/client/src/components/ui/Calendar.tsx +0 -165
  39. package/templates/typical/client/src/components/ui/Card.stories.tsx +0 -44
  40. package/templates/typical/client/src/components/ui/Card.tsx +0 -66
  41. package/templates/typical/client/src/components/ui/Carousel.stories.tsx +0 -56
  42. package/templates/typical/client/src/components/ui/Carousel.tsx +0 -225
  43. package/templates/typical/client/src/components/ui/Chart.stories.tsx +0 -39
  44. package/templates/typical/client/src/components/ui/Chart.tsx +0 -305
  45. package/templates/typical/client/src/components/ui/Checkbox.stories.tsx +0 -35
  46. package/templates/typical/client/src/components/ui/Checkbox.tsx +0 -30
  47. package/templates/typical/client/src/components/ui/Collapsible.stories.tsx +0 -58
  48. package/templates/typical/client/src/components/ui/Collapsible.tsx +0 -18
  49. package/templates/typical/client/src/components/ui/Combobox.stories.tsx +0 -75
  50. package/templates/typical/client/src/components/ui/Combobox.tsx +0 -296
  51. package/templates/typical/client/src/components/ui/Command.stories.tsx +0 -71
  52. package/templates/typical/client/src/components/ui/Command.tsx +0 -157
  53. package/templates/typical/client/src/components/ui/ContextMenu.stories.tsx +0 -68
  54. package/templates/typical/client/src/components/ui/ContextMenu.tsx +0 -231
  55. package/templates/typical/client/src/components/ui/DesignSystem-Colors.mdx +0 -68
  56. package/templates/typical/client/src/components/ui/DesignSystem-Colors.stories.tsx +0 -117
  57. package/templates/typical/client/src/components/ui/DesignSystem-Layout.mdx +0 -64
  58. package/templates/typical/client/src/components/ui/DesignSystem-Layout.stories.tsx +0 -167
  59. package/templates/typical/client/src/components/ui/DesignSystem-Overview.stories.tsx +0 -748
  60. package/templates/typical/client/src/components/ui/DesignSystem-Typography.mdx +0 -31
  61. package/templates/typical/client/src/components/ui/DesignSystem-Typography.stories.tsx +0 -80
  62. package/templates/typical/client/src/components/ui/Dialog.stories.tsx +0 -74
  63. package/templates/typical/client/src/components/ui/Dialog.tsx +0 -154
  64. package/templates/typical/client/src/components/ui/Direction.stories.tsx +0 -38
  65. package/templates/typical/client/src/components/ui/Direction.tsx +0 -24
  66. package/templates/typical/client/src/components/ui/Drawer.stories.tsx +0 -70
  67. package/templates/typical/client/src/components/ui/Drawer.tsx +0 -124
  68. package/templates/typical/client/src/components/ui/DropdownMenu.stories.tsx +0 -74
  69. package/templates/typical/client/src/components/ui/DropdownMenu.tsx +0 -239
  70. package/templates/typical/client/src/components/ui/Empty.stories.tsx +0 -37
  71. package/templates/typical/client/src/components/ui/Empty.tsx +0 -98
  72. package/templates/typical/client/src/components/ui/Field.stories.tsx +0 -50
  73. package/templates/typical/client/src/components/ui/Field.tsx +0 -251
  74. package/templates/typical/client/src/components/ui/Form.stories.tsx +0 -45
  75. package/templates/typical/client/src/components/ui/Form.tsx +0 -148
  76. package/templates/typical/client/src/components/ui/HoverCard.stories.tsx +0 -49
  77. package/templates/typical/client/src/components/ui/HoverCard.tsx +0 -39
  78. package/templates/typical/client/src/components/ui/Input.stories.tsx +0 -42
  79. package/templates/typical/client/src/components/ui/Input.tsx +0 -22
  80. package/templates/typical/client/src/components/ui/InputGroup.stories.tsx +0 -53
  81. package/templates/typical/client/src/components/ui/InputGroup.tsx +0 -153
  82. package/templates/typical/client/src/components/ui/InputOTP.stories.tsx +0 -42
  83. package/templates/typical/client/src/components/ui/InputOTP.tsx +0 -72
  84. package/templates/typical/client/src/components/ui/Item.stories.tsx +0 -64
  85. package/templates/typical/client/src/components/ui/Item.tsx +0 -168
  86. package/templates/typical/client/src/components/ui/Kbd.stories.tsx +0 -59
  87. package/templates/typical/client/src/components/ui/Kbd.tsx +0 -22
  88. package/templates/typical/client/src/components/ui/Label.stories.tsx +0 -90
  89. package/templates/typical/client/src/components/ui/Label.tsx +0 -44
  90. package/templates/typical/client/src/components/ui/Menubar.stories.tsx +0 -78
  91. package/templates/typical/client/src/components/ui/Menubar.tsx +0 -251
  92. package/templates/typical/client/src/components/ui/NativeSelect.stories.tsx +0 -45
  93. package/templates/typical/client/src/components/ui/NativeSelect.tsx +0 -50
  94. package/templates/typical/client/src/components/ui/NavigationMenu.stories.tsx +0 -80
  95. package/templates/typical/client/src/components/ui/NavigationMenu.tsx +0 -152
  96. package/templates/typical/client/src/components/ui/Pagination.stories.tsx +0 -77
  97. package/templates/typical/client/src/components/ui/Pagination.tsx +0 -108
  98. package/templates/typical/client/src/components/ui/Popover.stories.tsx +0 -53
  99. package/templates/typical/client/src/components/ui/Popover.tsx +0 -57
  100. package/templates/typical/client/src/components/ui/Progress.stories.tsx +0 -32
  101. package/templates/typical/client/src/components/ui/Progress.tsx +0 -25
  102. package/templates/typical/client/src/components/ui/RadioGroup.stories.tsx +0 -50
  103. package/templates/typical/client/src/components/ui/RadioGroup.tsx +0 -36
  104. package/templates/typical/client/src/components/ui/Resizable.stories.tsx +0 -72
  105. package/templates/typical/client/src/components/ui/Resizable.tsx +0 -54
  106. package/templates/typical/client/src/components/ui/ScrollArea.stories.tsx +0 -45
  107. package/templates/typical/client/src/components/ui/ScrollArea.tsx +0 -51
  108. package/templates/typical/client/src/components/ui/Select.stories.tsx +0 -59
  109. package/templates/typical/client/src/components/ui/Select.tsx +0 -171
  110. package/templates/typical/client/src/components/ui/Separator.stories.tsx +0 -42
  111. package/templates/typical/client/src/components/ui/Separator.tsx +0 -27
  112. package/templates/typical/client/src/components/ui/Sheet.stories.tsx +0 -68
  113. package/templates/typical/client/src/components/ui/Sheet.tsx +0 -115
  114. package/templates/typical/client/src/components/ui/Sidebar.stories.tsx +0 -96
  115. package/templates/typical/client/src/components/ui/Sidebar.tsx +0 -695
  116. package/templates/typical/client/src/components/ui/Skeleton.stories.tsx +0 -40
  117. package/templates/typical/client/src/components/ui/Skeleton.tsx +0 -11
  118. package/templates/typical/client/src/components/ui/Slider.stories.tsx +0 -24
  119. package/templates/typical/client/src/components/ui/Slider.tsx +0 -55
  120. package/templates/typical/client/src/components/ui/Sonner.stories.tsx +0 -45
  121. package/templates/typical/client/src/components/ui/Sonner.tsx +0 -38
  122. package/templates/typical/client/src/components/ui/Spinner.stories.tsx +0 -26
  123. package/templates/typical/client/src/components/ui/Spinner.tsx +0 -13
  124. package/templates/typical/client/src/components/ui/Switch.stories.tsx +0 -39
  125. package/templates/typical/client/src/components/ui/Switch.tsx +0 -35
  126. package/templates/typical/client/src/components/ui/Table.stories.tsx +0 -67
  127. package/templates/typical/client/src/components/ui/Table.tsx +0 -86
  128. package/templates/typical/client/src/components/ui/Tabs.stories.tsx +0 -53
  129. package/templates/typical/client/src/components/ui/Tabs.tsx +0 -75
  130. package/templates/typical/client/src/components/ui/Textarea.stories.tsx +0 -27
  131. package/templates/typical/client/src/components/ui/Textarea.tsx +0 -22
  132. package/templates/typical/client/src/components/ui/Toast.stories.tsx +0 -116
  133. package/templates/typical/client/src/components/ui/Toast.tsx +0 -123
  134. package/templates/typical/client/src/components/ui/Toaster.tsx +0 -32
  135. package/templates/typical/client/src/components/ui/Toggle.stories.tsx +0 -44
  136. package/templates/typical/client/src/components/ui/Toggle.tsx +0 -42
  137. package/templates/typical/client/src/components/ui/ToggleGroup.stories.tsx +0 -61
  138. package/templates/typical/client/src/components/ui/ToggleGroup.tsx +0 -83
  139. package/templates/typical/client/src/components/ui/Tooltip.stories.tsx +0 -42
  140. package/templates/typical/client/src/components/ui/Tooltip.tsx +0 -48
  141. package/templates/typical/client/src/gql/execute.ts +0 -11
  142. package/templates/typical/client/src/gql/fragment-masking.ts +0 -83
  143. package/templates/typical/client/src/gql/gql.ts +0 -9
  144. package/templates/typical/client/src/gql/graphql.ts +0 -182
  145. package/templates/typical/client/src/gql/index.ts +0 -2
  146. package/templates/typical/client/src/graphql/mutations.ts +0 -0
  147. package/templates/typical/client/src/graphql/queries.ts +0 -0
  148. package/templates/typical/client/src/hooks/.gitkeep +0 -0
  149. package/templates/typical/client/src/hooks/use-mobile.ts +0 -19
  150. package/templates/typical/client/src/hooks/use-toast.ts +0 -186
  151. package/templates/typical/client/src/index.css +0 -121
  152. package/templates/typical/client/src/lib/utils.ts +0 -6
  153. package/templates/typical/client/src/main.tsx +0 -5
  154. package/templates/typical/client/tsconfig.app.json +0 -26
  155. package/templates/typical/client/tsconfig.json +0 -10
  156. package/templates/typical/client/vite.config.ts +0 -50
@@ -1,178 +0,0 @@
1
- 'use client';
2
-
3
- import * as React from 'react';
4
- import { AlertDialog as AlertDialogPrimitive } from 'radix-ui';
5
-
6
- import { cn } from '@/lib/utils';
7
- import { Button } from '@/components/ui/Button';
8
-
9
- /** A confirmation modal requiring explicit user action. Unlike Dialog, cannot be dismissed by clicking outside. */
10
- function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
11
- return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
12
- }
13
-
14
- /** The element that opens the AlertDialog when clicked. */
15
- function AlertDialogTrigger({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
16
- return <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />;
17
- }
18
-
19
- /** Portals the dialog content into document.body to avoid z-index and overflow issues. */
20
- function AlertDialogPortal({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
21
- return <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />;
22
- }
23
-
24
- /** The semi-transparent backdrop rendered behind the dialog content. */
25
- function AlertDialogOverlay({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
26
- return (
27
- <AlertDialogPrimitive.Overlay
28
- data-slot="alert-dialog-overlay"
29
- className={cn(
30
- 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50',
31
- className,
32
- )}
33
- {...props}
34
- />
35
- );
36
- }
37
-
38
- /**
39
- * The centered modal panel containing the dialog's content. Automatically renders overlay and portal.
40
- * @param size - Controls the max-width: `"default"` for standard dialogs, `"sm"` for compact confirmations.
41
- */
42
- function AlertDialogContent({
43
- className,
44
- size = 'default',
45
- ...props
46
- }: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {
47
- size?: 'default' | 'sm';
48
- }) {
49
- return (
50
- <AlertDialogPortal>
51
- <AlertDialogOverlay />
52
- <AlertDialogPrimitive.Content
53
- data-slot="alert-dialog-content"
54
- data-size={size}
55
- className={cn(
56
- 'bg-background 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 group/alert-dialog-content fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-lg',
57
- className,
58
- )}
59
- {...props}
60
- />
61
- </AlertDialogPortal>
62
- );
63
- }
64
-
65
- /** Layout container for the dialog's title, description, and optional media icon. */
66
- function AlertDialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
67
- return (
68
- <div
69
- data-slot="alert-dialog-header"
70
- className={cn(
71
- 'grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]',
72
- className,
73
- )}
74
- {...props}
75
- />
76
- );
77
- }
78
-
79
- /** Layout container for the dialog's action buttons, typically Cancel and a primary action. */
80
- function AlertDialogFooter({ className, ...props }: React.ComponentProps<'div'>) {
81
- return (
82
- <div
83
- data-slot="alert-dialog-footer"
84
- className={cn(
85
- 'flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end',
86
- className,
87
- )}
88
- {...props}
89
- />
90
- );
91
- }
92
-
93
- /** The accessible title of the dialog, announced by screen readers when the dialog opens. */
94
- function AlertDialogTitle({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
95
- return (
96
- <AlertDialogPrimitive.Title
97
- data-slot="alert-dialog-title"
98
- className={cn(
99
- 'text-lg font-semibold sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2',
100
- className,
101
- )}
102
- {...props}
103
- />
104
- );
105
- }
106
-
107
- /** The accessible description providing additional context about the dialog's purpose. */
108
- function AlertDialogDescription({
109
- className,
110
- ...props
111
- }: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
112
- return (
113
- <AlertDialogPrimitive.Description
114
- data-slot="alert-dialog-description"
115
- className={cn('text-muted-foreground text-sm', className)}
116
- {...props}
117
- />
118
- );
119
- }
120
-
121
- /** An optional icon or image slot displayed alongside the title in the dialog header. */
122
- function AlertDialogMedia({ className, ...props }: React.ComponentProps<'div'>) {
123
- return (
124
- <div
125
- data-slot="alert-dialog-media"
126
- className={cn(
127
- "bg-muted mb-2 inline-flex size-16 items-center justify-center rounded-md sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8",
128
- className,
129
- )}
130
- {...props}
131
- />
132
- );
133
- }
134
-
135
- /** The primary confirmation button that closes the dialog and triggers the intended action. Renders as a Button. */
136
- function AlertDialogAction({
137
- className,
138
- variant = 'default',
139
- size = 'default',
140
- ...props
141
- }: React.ComponentProps<typeof AlertDialogPrimitive.Action> &
142
- Pick<React.ComponentProps<typeof Button>, 'variant' | 'size'>) {
143
- return (
144
- <Button variant={variant} size={size} asChild>
145
- <AlertDialogPrimitive.Action data-slot="alert-dialog-action" className={cn(className)} {...props} />
146
- </Button>
147
- );
148
- }
149
-
150
- /** The cancel button that dismisses the dialog without taking action. Renders as an outline Button by default. */
151
- function AlertDialogCancel({
152
- className,
153
- variant = 'outline',
154
- size = 'default',
155
- ...props
156
- }: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &
157
- Pick<React.ComponentProps<typeof Button>, 'variant' | 'size'>) {
158
- return (
159
- <Button variant={variant} size={size} asChild>
160
- <AlertDialogPrimitive.Cancel data-slot="alert-dialog-cancel" className={cn(className)} {...props} />
161
- </Button>
162
- );
163
- }
164
-
165
- export {
166
- AlertDialog,
167
- AlertDialogAction,
168
- AlertDialogCancel,
169
- AlertDialogContent,
170
- AlertDialogDescription,
171
- AlertDialogFooter,
172
- AlertDialogHeader,
173
- AlertDialogMedia,
174
- AlertDialogOverlay,
175
- AlertDialogPortal,
176
- AlertDialogTitle,
177
- AlertDialogTrigger,
178
- };
@@ -1,35 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { AspectRatio } from '@/components/ui/AspectRatio';
3
-
4
- const meta: Meta<typeof AspectRatio> = {
5
- title: 'UI Components/AspectRatio',
6
- component: AspectRatio,
7
- };
8
- export default meta;
9
- type Story = StoryObj<typeof AspectRatio>;
10
-
11
- /** Shows a 16:9 widescreen aspect ratio container. */
12
- export const Default: Story = {
13
- render: () => (
14
- <div className="w-[450px]">
15
- <AspectRatio ratio={16 / 9}>
16
- <div className="flex h-full w-full items-center justify-center rounded-md bg-slate-200 dark:bg-slate-800">
17
- <span className="text-sm text-slate-500">16:9 Aspect Ratio</span>
18
- </div>
19
- </AspectRatio>
20
- </div>
21
- ),
22
- };
23
-
24
- /** Shows a 1:1 square aspect ratio container. */
25
- export const Square: Story = {
26
- render: () => (
27
- <div className="w-[300px]">
28
- <AspectRatio ratio={1}>
29
- <div className="flex h-full w-full items-center justify-center rounded-md bg-slate-200 dark:bg-slate-800">
30
- <span className="text-sm text-slate-500">1:1 Square</span>
31
- </div>
32
- </AspectRatio>
33
- </div>
34
- ),
35
- };
@@ -1,13 +0,0 @@
1
- 'use client';
2
-
3
- import { AspectRatio as AspectRatioPrimitive } from 'radix-ui';
4
-
5
- /**
6
- * Constrains its child element to a specified width-to-height ratio (e.g., 16/9, 1/1).
7
- * Useful for responsive images, videos, and media containers that must maintain proportions.
8
- */
9
- function AspectRatio({ ...props }: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
10
- return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />;
11
- }
12
-
13
- export { AspectRatio };
@@ -1,45 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/Avatar';
3
-
4
- const meta: Meta<typeof Avatar> = {
5
- title: 'UI Components/Avatar',
6
- component: Avatar,
7
- };
8
- export default meta;
9
- type Story = StoryObj<typeof Avatar>;
10
-
11
- /** Shows an avatar with a loaded profile image and fallback initials. */
12
- export const WithImage: Story = {
13
- render: () => (
14
- <Avatar>
15
- <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
16
- <AvatarFallback>CN</AvatarFallback>
17
- </Avatar>
18
- ),
19
- };
20
-
21
- /** Shows an avatar displaying only fallback initials without an image. */
22
- export const FallbackOnly: Story = {
23
- render: () => (
24
- <Avatar>
25
- <AvatarFallback>AB</AvatarFallback>
26
- </Avatar>
27
- ),
28
- };
29
-
30
- /** Demonstrates the three available avatar sizes: sm, default, and lg. */
31
- export const Sizes: Story = {
32
- render: () => (
33
- <div className="flex items-center gap-4">
34
- <Avatar size="sm">
35
- <AvatarFallback>SM</AvatarFallback>
36
- </Avatar>
37
- <Avatar size="default">
38
- <AvatarFallback>MD</AvatarFallback>
39
- </Avatar>
40
- <Avatar size="lg">
41
- <AvatarFallback>LG</AvatarFallback>
42
- </Avatar>
43
- </div>
44
- ),
45
- };
@@ -1,98 +0,0 @@
1
- import * as React from 'react';
2
- import { Avatar as AvatarPrimitive } from 'radix-ui';
3
-
4
- import { cn } from '@/lib/utils';
5
-
6
- /**
7
- * Displays a user profile image with a fallback for missing photos.
8
- * Compose with AvatarImage, AvatarFallback, and optionally AvatarBadge.
9
- * Use AvatarGroup to render overlapping stacks of avatars.
10
- */
11
- function Avatar({
12
- className,
13
- /** Controls the avatar dimensions: `"sm"` (24px), `"default"` (32px), or `"lg"` (40px). */
14
- size = 'default',
15
- ...props
16
- }: React.ComponentProps<typeof AvatarPrimitive.Root> & {
17
- size?: 'default' | 'sm' | 'lg';
18
- }) {
19
- return (
20
- <AvatarPrimitive.Root
21
- data-slot="avatar"
22
- data-size={size}
23
- className={cn(
24
- 'group/avatar relative flex size-8 shrink-0 overflow-hidden rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6',
25
- className,
26
- )}
27
- {...props}
28
- />
29
- );
30
- }
31
-
32
- /** The profile image rendered inside an Avatar. Automatically hidden if the image fails to load. */
33
- function AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Image>) {
34
- return (
35
- <AvatarPrimitive.Image data-slot="avatar-image" className={cn('aspect-square size-full', className)} {...props} />
36
- );
37
- }
38
-
39
- /** Fallback content shown when AvatarImage is loading or unavailable, typically initials or an icon. */
40
- function AvatarFallback({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
41
- return (
42
- <AvatarPrimitive.Fallback
43
- data-slot="avatar-fallback"
44
- className={cn(
45
- 'bg-muted text-muted-foreground flex size-full items-center justify-center rounded-full text-sm group-data-[size=sm]/avatar:text-xs',
46
- className,
47
- )}
48
- {...props}
49
- />
50
- );
51
- }
52
-
53
- /** A small status indicator (e.g., online/offline dot) positioned at the bottom-right corner of an Avatar. */
54
- function AvatarBadge({ className, ...props }: React.ComponentProps<'span'>) {
55
- return (
56
- <span
57
- data-slot="avatar-badge"
58
- className={cn(
59
- 'bg-primary text-primary-foreground ring-background absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full ring-2 select-none',
60
- 'group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden',
61
- 'group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2',
62
- 'group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2',
63
- className,
64
- )}
65
- {...props}
66
- />
67
- );
68
- }
69
-
70
- /** Renders multiple Avatars in an overlapping horizontal stack with ring borders. */
71
- function AvatarGroup({ className, ...props }: React.ComponentProps<'div'>) {
72
- return (
73
- <div
74
- data-slot="avatar-group"
75
- className={cn(
76
- '*:data-[slot=avatar]:ring-background group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2',
77
- className,
78
- )}
79
- {...props}
80
- />
81
- );
82
- }
83
-
84
- /** Displays a count of additional avatars not shown in the group (e.g., "+5"). */
85
- function AvatarGroupCount({ className, ...props }: React.ComponentProps<'div'>) {
86
- return (
87
- <div
88
- data-slot="avatar-group-count"
89
- className={cn(
90
- 'bg-muted text-muted-foreground ring-background relative flex size-8 shrink-0 items-center justify-center rounded-full text-sm ring-2 group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3',
91
- className,
92
- )}
93
- {...props}
94
- />
95
- );
96
- }
97
-
98
- export { Avatar, AvatarImage, AvatarFallback, AvatarBadge, AvatarGroup, AvatarGroupCount };
@@ -1,41 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { Badge } from '@/components/ui/Badge';
3
-
4
- const meta: Meta<typeof Badge> = {
5
- title: 'UI Components/Badge',
6
- component: Badge,
7
- };
8
- export default meta;
9
- type Story = StoryObj<typeof Badge>;
10
-
11
- /** Shows the primary filled badge variant. */
12
- export const Default: Story = {
13
- render: () => <Badge>Default</Badge>,
14
- };
15
-
16
- /** Shows the secondary badge variant with muted background. */
17
- export const Secondary: Story = {
18
- render: () => <Badge variant="secondary">Secondary</Badge>,
19
- };
20
-
21
- /** Shows the destructive badge variant for error or warning indicators. */
22
- export const Destructive: Story = {
23
- render: () => <Badge variant="destructive">Destructive</Badge>,
24
- };
25
-
26
- /** Shows the outline badge variant with a visible border and no fill. */
27
- export const Outline: Story = {
28
- render: () => <Badge variant="outline">Outline</Badge>,
29
- };
30
-
31
- /** Displays all badge variants side by side for visual comparison. */
32
- export const AllVariants: Story = {
33
- render: () => (
34
- <div className="flex flex-wrap gap-2">
35
- <Badge variant="default">Default</Badge>
36
- <Badge variant="secondary">Secondary</Badge>
37
- <Badge variant="destructive">Destructive</Badge>
38
- <Badge variant="outline">Outline</Badge>
39
- </div>
40
- ),
41
- };
@@ -1,45 +0,0 @@
1
- import * as React from 'react';
2
- import { cva, type VariantProps } from 'class-variance-authority';
3
- import { Slot } from 'radix-ui';
4
-
5
- import { cn } from '@/lib/utils';
6
-
7
- const badgeVariants = cva(
8
- 'inline-flex items-center justify-center rounded-full border border-transparent px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
9
- {
10
- variants: {
11
- variant: {
12
- default: 'bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
13
- secondary: 'bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
14
- destructive:
15
- 'bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
16
- outline: 'border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
17
- ghost: '[a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
18
- link: 'text-primary underline-offset-4 [a&]:hover:underline',
19
- },
20
- },
21
- defaultVariants: {
22
- variant: 'default',
23
- },
24
- },
25
- );
26
-
27
- /**
28
- * A small label used to highlight status, category, or count.
29
- * Supports multiple visual variants: default, secondary, destructive, outline, ghost, and link.
30
- */
31
- function Badge({
32
- className,
33
- variant = 'default',
34
- /** Merges props onto the child element instead of rendering a span. Use with custom wrapper elements. */
35
- asChild = false,
36
- ...props
37
- }: React.ComponentProps<'span'> & VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
38
- const Comp = asChild ? Slot.Root : 'span';
39
-
40
- return (
41
- <Comp data-slot="badge" data-variant={variant} className={cn(badgeVariants({ variant }), className)} {...props} />
42
- );
43
- }
44
-
45
- export { Badge, badgeVariants };
@@ -1,54 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import {
3
- Breadcrumb,
4
- BreadcrumbList,
5
- BreadcrumbItem,
6
- BreadcrumbLink,
7
- BreadcrumbPage,
8
- BreadcrumbSeparator,
9
- } from '@/components/ui/Breadcrumb';
10
-
11
- const meta: Meta<typeof Breadcrumb> = {
12
- title: 'UI Components/Breadcrumb',
13
- component: Breadcrumb,
14
- };
15
- export default meta;
16
- type Story = StoryObj<typeof Breadcrumb>;
17
-
18
- /** Shows a three-level breadcrumb trail with home, category, and current page. */
19
- export const Default: Story = {
20
- render: () => (
21
- <Breadcrumb>
22
- <BreadcrumbList>
23
- <BreadcrumbItem>
24
- <BreadcrumbLink href="/">Home</BreadcrumbLink>
25
- </BreadcrumbItem>
26
- <BreadcrumbSeparator />
27
- <BreadcrumbItem>
28
- <BreadcrumbLink href="/components">Components</BreadcrumbLink>
29
- </BreadcrumbItem>
30
- <BreadcrumbSeparator />
31
- <BreadcrumbItem>
32
- <BreadcrumbPage>Breadcrumb</BreadcrumbPage>
33
- </BreadcrumbItem>
34
- </BreadcrumbList>
35
- </Breadcrumb>
36
- ),
37
- };
38
-
39
- /** Shows a minimal two-level breadcrumb with just a parent link and current page. */
40
- export const TwoLevels: Story = {
41
- render: () => (
42
- <Breadcrumb>
43
- <BreadcrumbList>
44
- <BreadcrumbItem>
45
- <BreadcrumbLink href="/">Dashboard</BreadcrumbLink>
46
- </BreadcrumbItem>
47
- <BreadcrumbSeparator />
48
- <BreadcrumbItem>
49
- <BreadcrumbPage>Settings</BreadcrumbPage>
50
- </BreadcrumbItem>
51
- </BreadcrumbList>
52
- </Breadcrumb>
53
- ),
54
- };
@@ -1,104 +0,0 @@
1
- import * as React from 'react';
2
- import { ChevronRight, MoreHorizontal } from 'lucide-react';
3
- import { Slot } from 'radix-ui';
4
-
5
- import { cn } from '@/lib/utils';
6
-
7
- /**
8
- * A navigation aid that shows the user's current location within a site hierarchy.
9
- * Compose with BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, and BreadcrumbSeparator.
10
- * Renders as a `<nav>` with `aria-label="breadcrumb"` for accessibility.
11
- */
12
- function Breadcrumb({ ...props }: React.ComponentProps<'nav'>) {
13
- return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
14
- }
15
-
16
- /** The ordered list container for breadcrumb items, handling wrapping and spacing. */
17
- function BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {
18
- return (
19
- <ol
20
- data-slot="breadcrumb-list"
21
- className={cn(
22
- 'text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5',
23
- className,
24
- )}
25
- {...props}
26
- />
27
- );
28
- }
29
-
30
- /** A single step in the breadcrumb trail, wrapping a link or the current page label. */
31
- function BreadcrumbItem({ className, ...props }: React.ComponentProps<'li'>) {
32
- return <li data-slot="breadcrumb-item" className={cn('inline-flex items-center gap-1.5', className)} {...props} />;
33
- }
34
-
35
- /** A navigable link within a breadcrumb item. Use `asChild` to render a router Link component instead of an anchor. */
36
- function BreadcrumbLink({
37
- /** Merges props onto the child element instead of rendering an anchor tag. */
38
- asChild,
39
- className,
40
- ...props
41
- }: React.ComponentProps<'a'> & {
42
- asChild?: boolean;
43
- }) {
44
- const Comp = asChild ? Slot.Root : 'a';
45
-
46
- return (
47
- <Comp data-slot="breadcrumb-link" className={cn('hover:text-foreground transition-colors', className)} {...props} />
48
- );
49
- }
50
-
51
- /** The current page label in the breadcrumb trail, marked with `aria-current="page"` and rendered as non-interactive text. */
52
- function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {
53
- return (
54
- <span
55
- data-slot="breadcrumb-page"
56
- role="link"
57
- aria-disabled="true"
58
- aria-current="page"
59
- className={cn('text-foreground font-normal', className)}
60
- {...props}
61
- />
62
- );
63
- }
64
-
65
- /** A visual divider between breadcrumb items, defaulting to a chevron-right icon. Pass children to customize the separator. */
66
- function BreadcrumbSeparator({ children, className, ...props }: React.ComponentProps<'li'>) {
67
- return (
68
- <li
69
- data-slot="breadcrumb-separator"
70
- role="presentation"
71
- aria-hidden="true"
72
- className={cn('[&>svg]:size-3.5', className)}
73
- {...props}
74
- >
75
- {children ?? <ChevronRight />}
76
- </li>
77
- );
78
- }
79
-
80
- /** A "..." indicator used to collapse intermediate breadcrumb levels when the trail is too long. */
81
- function BreadcrumbEllipsis({ className, ...props }: React.ComponentProps<'span'>) {
82
- return (
83
- <span
84
- data-slot="breadcrumb-ellipsis"
85
- role="presentation"
86
- aria-hidden="true"
87
- className={cn('flex size-9 items-center justify-center', className)}
88
- {...props}
89
- >
90
- <MoreHorizontal className="size-4" />
91
- <span className="sr-only">More</span>
92
- </span>
93
- );
94
- }
95
-
96
- export {
97
- Breadcrumb,
98
- BreadcrumbList,
99
- BreadcrumbItem,
100
- BreadcrumbLink,
101
- BreadcrumbPage,
102
- BreadcrumbSeparator,
103
- BreadcrumbEllipsis,
104
- };