@authdog/react-elements 0.0.40 → 0.0.43
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.
- package/.eslintrc.js +1 -1
- package/.storybook/main.ts +21 -0
- package/.storybook/preview.ts +17 -0
- package/.storybook/vitest.setup.ts +7 -0
- package/.turbo/turbo-build.log +48 -44
- package/CHANGELOG.md +19 -0
- package/dist/components/ui/alert.js.map +1 -1
- package/dist/components/ui/alert.mjs.map +1 -1
- package/dist/components/ui/avatar.js.map +1 -1
- package/dist/components/ui/avatar.mjs.map +1 -1
- package/dist/components/ui/badge.js.map +1 -1
- package/dist/components/ui/badge.mjs.map +1 -1
- package/dist/components/ui/card.js.map +1 -1
- package/dist/components/ui/card.mjs.map +1 -1
- package/dist/components/ui/dropdown-menu.js +1 -1
- package/dist/components/ui/dropdown-menu.js.map +1 -1
- package/dist/components/ui/dropdown-menu.mjs +1 -1
- package/dist/components/ui/dropdown-menu.mjs.map +1 -1
- package/dist/components/ui/input.js.map +1 -1
- package/dist/components/ui/input.mjs.map +1 -1
- package/dist/components/ui/label.js.map +1 -1
- package/dist/components/ui/label.mjs.map +1 -1
- package/dist/components/ui/separator.js.map +1 -1
- package/dist/components/ui/separator.mjs.map +1 -1
- package/dist/components/ui/sheet.js.map +1 -1
- package/dist/components/ui/sheet.mjs.map +1 -1
- package/dist/components/ui/theme-toggle.js +3 -0
- package/dist/components/ui/theme-toggle.js.map +1 -0
- package/dist/components/ui/theme-toggle.mjs +3 -0
- package/dist/components/ui/theme-toggle.mjs.map +1 -0
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +314 -20
- package/package.json +23 -12
- package/src/components/core/navbar.tsx +145 -112
- package/src/components/core/user-dropdown.tsx +22 -4
- package/src/components/icons.tsx +6 -12
- package/src/components/ui/alert.tsx +1 -1
- package/src/components/ui/avatar.tsx +1 -1
- package/src/components/ui/badge.tsx +1 -1
- package/src/components/ui/card.tsx +1 -1
- package/src/components/ui/dropdown-menu.tsx +198 -197
- package/src/components/ui/input.tsx +1 -1
- package/src/components/ui/label.tsx +1 -1
- package/src/components/ui/separator.tsx +1 -1
- package/src/components/ui/sheet.tsx +1 -1
- package/src/components/ui/theme-toggle.tsx +55 -0
- package/src/stories/core/Navbar.stories.tsx +45 -0
- package/src/stories/core/PlaceholderAlert.stories.tsx +23 -0
- package/src/stories/core/UserDropdown.stories.tsx +56 -0
- package/src/stories/core/UserProfile.stories.tsx +47 -0
- package/src/stories/flow/LoginForm.stories.tsx +20 -0
- package/src/stories/flow/TotpValidator.stories.tsx +23 -0
- package/src/stories/showcase/Landing.stories.tsx +376 -0
- package/src/stories/ui/Button.stories.tsx +45 -0
- package/vitest.config.ts +39 -0
- package/vitest.shims.d.ts +1 -0
- package/wrangler.prod.toml +4 -0
- package/ladle.config.mjs +0 -21
- package/src/main.tsx +0 -9
- package/src/preview.tsx +0 -7
- package/src/stories/Button._stories.tsx +0 -28
- package/src/stories/LoginForm.stories.tsx +0 -29
- package/src/stories/Navbar._stories.tsx +0 -66
- package/src/stories/PlaceholderAlert._stories.tsx +0 -13
- package/src/stories/TotpValidator.stories.tsx +0 -16
- package/src/stories/UserDropdown.stories.tsx +0 -34
- package/src/stories/UserProfile.stories.tsx +0 -46
|
@@ -27,177 +27,178 @@ function DropdownMenuPortal({
|
|
|
27
27
|
);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
function DropdownMenuContent({
|
|
42
|
-
className,
|
|
43
|
-
sideOffset = 4,
|
|
44
|
-
...props
|
|
45
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
46
|
-
return (
|
|
47
|
-
<DropdownMenuPrimitive.Portal>
|
|
48
|
-
<DropdownMenuPrimitive.Content
|
|
49
|
-
data-slot="dropdown-menu-content"
|
|
50
|
-
sideOffset={sideOffset}
|
|
51
|
-
className={cn(
|
|
52
|
-
"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 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
|
|
53
|
-
className,
|
|
54
|
-
)}
|
|
55
|
-
{...props}
|
|
56
|
-
/>
|
|
57
|
-
</DropdownMenuPrimitive.Portal>
|
|
58
|
-
);
|
|
59
|
-
}
|
|
30
|
+
const DropdownMenuTrigger = React.forwardRef<
|
|
31
|
+
React.ElementRef<typeof DropdownMenuPrimitive.Trigger>,
|
|
32
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>
|
|
33
|
+
>(({ ...props }, ref) => (
|
|
34
|
+
<DropdownMenuPrimitive.Trigger
|
|
35
|
+
ref={ref}
|
|
36
|
+
data-slot="dropdown-menu-trigger"
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
));
|
|
40
|
+
DropdownMenuTrigger.displayName = DropdownMenuPrimitive.Trigger.displayName;
|
|
60
41
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
className,
|
|
71
|
-
inset,
|
|
72
|
-
variant = "default",
|
|
73
|
-
...props
|
|
74
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
75
|
-
inset?: boolean;
|
|
76
|
-
variant?: "default" | "destructive";
|
|
77
|
-
}) {
|
|
78
|
-
return (
|
|
79
|
-
<DropdownMenuPrimitive.Item
|
|
80
|
-
data-slot="dropdown-menu-item"
|
|
81
|
-
data-inset={inset}
|
|
82
|
-
data-variant={variant}
|
|
42
|
+
const DropdownMenuContent = React.forwardRef<
|
|
43
|
+
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
|
44
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
|
45
|
+
>(({ className, sideOffset = 4, ...props }, ref) => (
|
|
46
|
+
<DropdownMenuPrimitive.Portal>
|
|
47
|
+
<DropdownMenuPrimitive.Content
|
|
48
|
+
ref={ref}
|
|
49
|
+
data-slot="dropdown-menu-content"
|
|
50
|
+
sideOffset={sideOffset}
|
|
83
51
|
className={cn(
|
|
84
|
-
"
|
|
52
|
+
"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 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
|
|
85
53
|
className,
|
|
86
54
|
)}
|
|
87
55
|
{...props}
|
|
88
56
|
/>
|
|
89
|
-
|
|
90
|
-
|
|
57
|
+
</DropdownMenuPrimitive.Portal>
|
|
58
|
+
));
|
|
59
|
+
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
91
60
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
className,
|
|
104
|
-
)}
|
|
105
|
-
checked={checked}
|
|
106
|
-
{...props}
|
|
107
|
-
>
|
|
108
|
-
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
109
|
-
<DropdownMenuPrimitive.ItemIndicator>
|
|
110
|
-
<CheckIcon className="size-4" />
|
|
111
|
-
</DropdownMenuPrimitive.ItemIndicator>
|
|
112
|
-
</span>
|
|
113
|
-
{children}
|
|
114
|
-
</DropdownMenuPrimitive.CheckboxItem>
|
|
115
|
-
);
|
|
116
|
-
}
|
|
61
|
+
const DropdownMenuGroup = React.forwardRef<
|
|
62
|
+
React.ElementRef<typeof DropdownMenuPrimitive.Group>,
|
|
63
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Group>
|
|
64
|
+
>(({ ...props }, ref) => (
|
|
65
|
+
<DropdownMenuPrimitive.Group
|
|
66
|
+
ref={ref}
|
|
67
|
+
data-slot="dropdown-menu-group"
|
|
68
|
+
{...props}
|
|
69
|
+
/>
|
|
70
|
+
));
|
|
71
|
+
DropdownMenuGroup.displayName = DropdownMenuPrimitive.Group.displayName;
|
|
117
72
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
73
|
+
const DropdownMenuItem = React.forwardRef<
|
|
74
|
+
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
|
75
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
|
76
|
+
inset?: boolean;
|
|
77
|
+
variant?: "default" | "destructive";
|
|
78
|
+
}
|
|
79
|
+
>(({ className, inset, variant = "default", ...props }, ref) => (
|
|
80
|
+
<DropdownMenuPrimitive.Item
|
|
81
|
+
ref={ref}
|
|
82
|
+
data-slot="dropdown-menu-item"
|
|
83
|
+
data-inset={inset}
|
|
84
|
+
data-variant={variant}
|
|
85
|
+
className={cn(
|
|
86
|
+
"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",
|
|
87
|
+
className,
|
|
88
|
+
)}
|
|
89
|
+
{...props}
|
|
90
|
+
/>
|
|
91
|
+
));
|
|
92
|
+
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
128
93
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
94
|
+
const DropdownMenuCheckboxItem = React.forwardRef<
|
|
95
|
+
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
|
96
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
|
97
|
+
>(({ className, children, checked, ...props }, ref) => (
|
|
98
|
+
<DropdownMenuPrimitive.CheckboxItem
|
|
99
|
+
ref={ref}
|
|
100
|
+
data-slot="dropdown-menu-checkbox-item"
|
|
101
|
+
className={cn(
|
|
102
|
+
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm 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",
|
|
103
|
+
className,
|
|
104
|
+
)}
|
|
105
|
+
checked={checked}
|
|
106
|
+
{...props}
|
|
107
|
+
>
|
|
108
|
+
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
109
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
110
|
+
<CheckIcon className="size-4" />
|
|
111
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
112
|
+
</span>
|
|
113
|
+
{children}
|
|
114
|
+
</DropdownMenuPrimitive.CheckboxItem>
|
|
115
|
+
));
|
|
116
|
+
DropdownMenuCheckboxItem.displayName =
|
|
117
|
+
DropdownMenuPrimitive.CheckboxItem.displayName;
|
|
152
118
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
|
|
166
|
-
className,
|
|
167
|
-
)}
|
|
168
|
-
{...props}
|
|
169
|
-
/>
|
|
170
|
-
);
|
|
171
|
-
}
|
|
119
|
+
const DropdownMenuRadioGroup = React.forwardRef<
|
|
120
|
+
React.ElementRef<typeof DropdownMenuPrimitive.RadioGroup>,
|
|
121
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioGroup>
|
|
122
|
+
>(({ ...props }, ref) => (
|
|
123
|
+
<DropdownMenuPrimitive.RadioGroup
|
|
124
|
+
ref={ref}
|
|
125
|
+
data-slot="dropdown-menu-radio-group"
|
|
126
|
+
{...props}
|
|
127
|
+
/>
|
|
128
|
+
));
|
|
129
|
+
DropdownMenuRadioGroup.displayName =
|
|
130
|
+
DropdownMenuPrimitive.RadioGroup.displayName;
|
|
172
131
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
132
|
+
const DropdownMenuRadioItem = React.forwardRef<
|
|
133
|
+
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
|
134
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
|
135
|
+
>(({ className, children, ...props }, ref) => (
|
|
136
|
+
<DropdownMenuPrimitive.RadioItem
|
|
137
|
+
ref={ref}
|
|
138
|
+
data-slot="dropdown-menu-radio-item"
|
|
139
|
+
className={cn(
|
|
140
|
+
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm 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",
|
|
141
|
+
className,
|
|
142
|
+
)}
|
|
143
|
+
{...props}
|
|
144
|
+
>
|
|
145
|
+
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
146
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
147
|
+
<CircleIcon className="size-2 fill-current" />
|
|
148
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
149
|
+
</span>
|
|
150
|
+
{children}
|
|
151
|
+
</DropdownMenuPrimitive.RadioItem>
|
|
152
|
+
));
|
|
153
|
+
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
|
185
154
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
155
|
+
const DropdownMenuLabel = React.forwardRef<
|
|
156
|
+
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
|
157
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
|
158
|
+
inset?: boolean;
|
|
159
|
+
}
|
|
160
|
+
>(({ className, inset, ...props }, ref) => (
|
|
161
|
+
<DropdownMenuPrimitive.Label
|
|
162
|
+
ref={ref}
|
|
163
|
+
data-slot="dropdown-menu-label"
|
|
164
|
+
data-inset={inset}
|
|
165
|
+
className={cn(
|
|
166
|
+
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
|
|
167
|
+
className,
|
|
168
|
+
)}
|
|
169
|
+
{...props}
|
|
170
|
+
/>
|
|
171
|
+
));
|
|
172
|
+
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
|
173
|
+
|
|
174
|
+
const DropdownMenuSeparator = React.forwardRef<
|
|
175
|
+
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
|
176
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
|
177
|
+
>(({ className, ...props }, ref) => (
|
|
178
|
+
<DropdownMenuPrimitive.Separator
|
|
179
|
+
ref={ref}
|
|
180
|
+
data-slot="dropdown-menu-separator"
|
|
181
|
+
className={cn("bg-border -mx-1 my-1 h-px", className)}
|
|
182
|
+
{...props}
|
|
183
|
+
/>
|
|
184
|
+
));
|
|
185
|
+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
|
186
|
+
|
|
187
|
+
const DropdownMenuShortcut = React.forwardRef<
|
|
188
|
+
HTMLSpanElement,
|
|
189
|
+
React.ComponentPropsWithoutRef<"span">
|
|
190
|
+
>(({ className, ...props }, ref) => (
|
|
191
|
+
<span
|
|
192
|
+
ref={ref}
|
|
193
|
+
data-slot="dropdown-menu-shortcut"
|
|
194
|
+
className={cn(
|
|
195
|
+
"text-muted-foreground ml-auto text-xs tracking-widest",
|
|
196
|
+
className,
|
|
197
|
+
)}
|
|
198
|
+
{...props}
|
|
199
|
+
/>
|
|
200
|
+
));
|
|
201
|
+
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
|
201
202
|
|
|
202
203
|
function DropdownMenuSub({
|
|
203
204
|
...props
|
|
@@ -205,45 +206,45 @@ function DropdownMenuSub({
|
|
|
205
206
|
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
|
|
206
207
|
}
|
|
207
208
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
data-
|
|
220
|
-
className
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
209
|
+
const DropdownMenuSubTrigger = React.forwardRef<
|
|
210
|
+
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
|
211
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
212
|
+
inset?: boolean;
|
|
213
|
+
}
|
|
214
|
+
>(({ className, inset, children, ...props }, ref) => (
|
|
215
|
+
<DropdownMenuPrimitive.SubTrigger
|
|
216
|
+
ref={ref}
|
|
217
|
+
data-slot="dropdown-menu-sub-trigger"
|
|
218
|
+
data-inset={inset}
|
|
219
|
+
className={cn(
|
|
220
|
+
"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-hidden select-none data-[inset]:pl-8",
|
|
221
|
+
className,
|
|
222
|
+
)}
|
|
223
|
+
{...props}
|
|
224
|
+
>
|
|
225
|
+
{children}
|
|
226
|
+
<ChevronRightIcon className="ml-auto size-4" />
|
|
227
|
+
</DropdownMenuPrimitive.SubTrigger>
|
|
228
|
+
));
|
|
229
|
+
DropdownMenuSubTrigger.displayName =
|
|
230
|
+
DropdownMenuPrimitive.SubTrigger.displayName;
|
|
231
231
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
232
|
+
const DropdownMenuSubContent = React.forwardRef<
|
|
233
|
+
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
|
234
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
|
235
|
+
>(({ className, ...props }, ref) => (
|
|
236
|
+
<DropdownMenuPrimitive.SubContent
|
|
237
|
+
ref={ref}
|
|
238
|
+
data-slot="dropdown-menu-sub-content"
|
|
239
|
+
className={cn(
|
|
240
|
+
"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-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
|
|
241
|
+
className,
|
|
242
|
+
)}
|
|
243
|
+
{...props}
|
|
244
|
+
/>
|
|
245
|
+
));
|
|
246
|
+
DropdownMenuSubContent.displayName =
|
|
247
|
+
DropdownMenuPrimitive.SubContent.displayName;
|
|
247
248
|
|
|
248
249
|
export {
|
|
249
250
|
DropdownMenu,
|
|
@@ -5,7 +5,7 @@ import * as SheetPrimitive from "@radix-ui/react-dialog";
|
|
|
5
5
|
import { X } from "lucide-react";
|
|
6
6
|
import type { ComponentType } from "react";
|
|
7
7
|
|
|
8
|
-
import { cn } from "
|
|
8
|
+
import { cn } from "../../lib/utils";
|
|
9
9
|
|
|
10
10
|
const XIcon = X as ComponentType<React.SVGProps<SVGSVGElement>>;
|
|
11
11
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { Sun, Moon } from "lucide-react";
|
|
5
|
+
|
|
6
|
+
import { Button } from "./button";
|
|
7
|
+
|
|
8
|
+
const STORAGE_KEY = "authdog-theme";
|
|
9
|
+
|
|
10
|
+
type ThemeMode = "light" | "dark";
|
|
11
|
+
|
|
12
|
+
const getPreferredTheme = (): ThemeMode => {
|
|
13
|
+
if (typeof window === "undefined") return "light";
|
|
14
|
+
const stored = window.localStorage.getItem(STORAGE_KEY);
|
|
15
|
+
if (stored === "light" || stored === "dark") {
|
|
16
|
+
return stored;
|
|
17
|
+
}
|
|
18
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const applyTheme = (mode: ThemeMode) => {
|
|
22
|
+
document.documentElement.classList.toggle("dark", mode === "dark");
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const ThemeToggle = () => {
|
|
26
|
+
const [mode, setMode] = useState<ThemeMode>("light");
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
const initial = getPreferredTheme();
|
|
30
|
+
applyTheme(initial);
|
|
31
|
+
setMode(initial);
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
34
|
+
const toggle = () => {
|
|
35
|
+
const nextMode: ThemeMode = mode === "dark" ? "light" : "dark";
|
|
36
|
+
applyTheme(nextMode);
|
|
37
|
+
try {
|
|
38
|
+
window.localStorage.setItem(STORAGE_KEY, nextMode);
|
|
39
|
+
} catch {
|
|
40
|
+
// ignore
|
|
41
|
+
}
|
|
42
|
+
setMode(nextMode);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Button
|
|
47
|
+
variant="ghost"
|
|
48
|
+
size="icon"
|
|
49
|
+
aria-label={mode === "dark" ? "Switch to light theme" : "Switch to dark theme"}
|
|
50
|
+
onClick={toggle}
|
|
51
|
+
>
|
|
52
|
+
{mode === "dark" ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
|
|
53
|
+
</Button>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
4
|
+
|
|
5
|
+
import { Navbar } from "../../components/core/navbar";
|
|
6
|
+
import React from "react";
|
|
7
|
+
|
|
8
|
+
const demoItems = [
|
|
9
|
+
{ title: "Home", href: "/" },
|
|
10
|
+
{ title: "Features", href: "/features" },
|
|
11
|
+
{ title: "Pricing", href: "/pricing" },
|
|
12
|
+
// { title: "Contact", href: "/contact" },
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const demoUser = {
|
|
16
|
+
id: "user_123",
|
|
17
|
+
displayName: "Avery Stone",
|
|
18
|
+
emails: [{ value: "avery.stone@example.com" }],
|
|
19
|
+
photos: [{ value: "https://i.pravatar.cc/120?img=56" }],
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const meta = {
|
|
23
|
+
title: "Core/Navbar",
|
|
24
|
+
component: Navbar,
|
|
25
|
+
tags: ["autodocs"],
|
|
26
|
+
parameters: {
|
|
27
|
+
layout: "fullscreen",
|
|
28
|
+
},
|
|
29
|
+
args: {
|
|
30
|
+
logoText: "Authdog",
|
|
31
|
+
items: demoItems,
|
|
32
|
+
},
|
|
33
|
+
} satisfies Meta<typeof Navbar>;
|
|
34
|
+
|
|
35
|
+
export default meta;
|
|
36
|
+
|
|
37
|
+
type Story = StoryObj<typeof Navbar>;
|
|
38
|
+
|
|
39
|
+
export const Guest: Story = {};
|
|
40
|
+
|
|
41
|
+
export const Authenticated: Story = {
|
|
42
|
+
args: {
|
|
43
|
+
user: demoUser,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
4
|
+
|
|
5
|
+
import { PlaceholderAlert } from "../../components/core/placeholder-alert";
|
|
6
|
+
import React from "react";
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: "Core/Placeholder Alert",
|
|
10
|
+
component: PlaceholderAlert,
|
|
11
|
+
tags: ["autodocs"],
|
|
12
|
+
} satisfies Meta<typeof PlaceholderAlert>;
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
|
|
16
|
+
type Story = StoryObj<typeof PlaceholderAlert>;
|
|
17
|
+
|
|
18
|
+
export const Basic: Story = {
|
|
19
|
+
args: {
|
|
20
|
+
title: "Custom Alert Title",
|
|
21
|
+
description: "This is a custom description for the placeholder alert.",
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
4
|
+
|
|
5
|
+
import { UserDropdown } from "../../components/core/user-dropdown";
|
|
6
|
+
import {
|
|
7
|
+
Avatar,
|
|
8
|
+
AvatarFallback,
|
|
9
|
+
AvatarImage,
|
|
10
|
+
} from "../../components/ui/avatar";
|
|
11
|
+
import React from "react";
|
|
12
|
+
|
|
13
|
+
const demoUser = {
|
|
14
|
+
displayName: "Jane Doe",
|
|
15
|
+
emails: [{ value: "jane.doe@example.com" }],
|
|
16
|
+
photos: [{ value: "https://i.pravatar.cc/100" }],
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const trigger = (
|
|
20
|
+
<span className="inline-flex h-10 w-10 items-center justify-center rounded-full border bg-white shadow">
|
|
21
|
+
<Avatar className="h-8 w-8 rounded-full">
|
|
22
|
+
<AvatarImage src="https://i.pravatar.cc/100" />
|
|
23
|
+
<AvatarFallback>JD</AvatarFallback>
|
|
24
|
+
</Avatar>
|
|
25
|
+
</span>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const meta = {
|
|
29
|
+
title: "Core/User Dropdown",
|
|
30
|
+
component: UserDropdown,
|
|
31
|
+
tags: ["autodocs"],
|
|
32
|
+
parameters: {
|
|
33
|
+
layout: "centered",
|
|
34
|
+
},
|
|
35
|
+
render: (args) => (
|
|
36
|
+
<div className="p-10">
|
|
37
|
+
<UserDropdown {...args} />
|
|
38
|
+
</div>
|
|
39
|
+
),
|
|
40
|
+
} satisfies Meta<typeof UserDropdown>;
|
|
41
|
+
|
|
42
|
+
export default meta;
|
|
43
|
+
|
|
44
|
+
type Story = StoryObj<typeof UserDropdown>;
|
|
45
|
+
|
|
46
|
+
export const Default: Story = {
|
|
47
|
+
args: {
|
|
48
|
+
trigger,
|
|
49
|
+
user: demoUser,
|
|
50
|
+
links: [{ label: "My Organizations", href: "/organizations" }],
|
|
51
|
+
side: "bottom",
|
|
52
|
+
align: "start",
|
|
53
|
+
onManageAccount: () => console.log("Manage account"),
|
|
54
|
+
onSignout: () => console.log("Sign out"),
|
|
55
|
+
},
|
|
56
|
+
};
|