create-strayl-web-app 1.0.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.
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -0
- package/template/README.md +290 -0
- package/template/components.json +24 -0
- package/template/package.json +56 -0
- package/template/public/favicon.ico +0 -0
- package/template/public/google-logo.svg +6 -0
- package/template/public/logo-dark.ico +0 -0
- package/template/public/logo-dark.webp +0 -0
- package/template/public/logo-light.ico +0 -0
- package/template/public/logo-light.webp +0 -0
- package/template/public/manifest.json +16 -0
- package/template/public/robots.txt +3 -0
- package/template/src/components/Header.tsx +76 -0
- package/template/src/components/language-switcher.tsx +38 -0
- package/template/src/components/theme-provider.tsx +14 -0
- package/template/src/components/themed-logo.tsx +44 -0
- package/template/src/components/ui/accordion.tsx +69 -0
- package/template/src/components/ui/alert-dialog.tsx +169 -0
- package/template/src/components/ui/alert.tsx +80 -0
- package/template/src/components/ui/autocomplete.tsx +301 -0
- package/template/src/components/ui/avatar.tsx +46 -0
- package/template/src/components/ui/badge.tsx +60 -0
- package/template/src/components/ui/breadcrumb.tsx +112 -0
- package/template/src/components/ui/button.tsx +73 -0
- package/template/src/components/ui/card.tsx +244 -0
- package/template/src/components/ui/checkbox-group.tsx +16 -0
- package/template/src/components/ui/checkbox.tsx +60 -0
- package/template/src/components/ui/collapsible.tsx +45 -0
- package/template/src/components/ui/combobox.tsx +415 -0
- package/template/src/components/ui/command.tsx +264 -0
- package/template/src/components/ui/dialog.tsx +196 -0
- package/template/src/components/ui/empty.tsx +127 -0
- package/template/src/components/ui/field.tsx +74 -0
- package/template/src/components/ui/fieldset.tsx +29 -0
- package/template/src/components/ui/form.tsx +17 -0
- package/template/src/components/ui/frame.tsx +82 -0
- package/template/src/components/ui/group.tsx +97 -0
- package/template/src/components/ui/input-group.tsx +101 -0
- package/template/src/components/ui/input.tsx +66 -0
- package/template/src/components/ui/kbd.tsx +28 -0
- package/template/src/components/ui/label.tsx +28 -0
- package/template/src/components/ui/menu.tsx +310 -0
- package/template/src/components/ui/meter.tsx +67 -0
- package/template/src/components/ui/number-field.tsx +160 -0
- package/template/src/components/ui/pagination.tsx +136 -0
- package/template/src/components/ui/popover.tsx +104 -0
- package/template/src/components/ui/preview-card.tsx +55 -0
- package/template/src/components/ui/progress.tsx +81 -0
- package/template/src/components/ui/radio-group.tsx +36 -0
- package/template/src/components/ui/scroll-area.tsx +64 -0
- package/template/src/components/ui/select.tsx +180 -0
- package/template/src/components/ui/separator.tsx +23 -0
- package/template/src/components/ui/sheet.tsx +203 -0
- package/template/src/components/ui/sidebar.tsx +743 -0
- package/template/src/components/ui/skeleton.tsx +16 -0
- package/template/src/components/ui/slider.tsx +74 -0
- package/template/src/components/ui/spinner.tsx +18 -0
- package/template/src/components/ui/switch.tsx +27 -0
- package/template/src/components/ui/table.tsx +126 -0
- package/template/src/components/ui/tabs.tsx +87 -0
- package/template/src/components/ui/textarea.tsx +51 -0
- package/template/src/components/ui/toast.tsx +269 -0
- package/template/src/components/ui/toggle-group.tsx +102 -0
- package/template/src/components/ui/toggle.tsx +45 -0
- package/template/src/components/ui/toolbar.tsx +83 -0
- package/template/src/components/ui/tooltip.tsx +65 -0
- package/template/src/hooks/use-mobile.ts +21 -0
- package/template/src/lib/i18n.ts +70 -0
- package/template/src/lib/utils.ts +6 -0
- package/template/src/routeTree.gen.ts +68 -0
- package/template/src/router.tsx +17 -0
- package/template/src/routes/__root.tsx +62 -0
- package/template/src/routes/index.tsx +71 -0
- package/template/src/styles.css +121 -0
- package/template/tsconfig.json +28 -0
- package/template/vite.config.ts +30 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
function Avatar({ className, ...props }: AvatarPrimitive.Root.Props) {
|
|
8
|
+
return (
|
|
9
|
+
<AvatarPrimitive.Root
|
|
10
|
+
className={cn(
|
|
11
|
+
"inline-flex size-8 shrink-0 select-none items-center justify-center overflow-hidden rounded-full bg-background align-middle font-medium text-xs",
|
|
12
|
+
className,
|
|
13
|
+
)}
|
|
14
|
+
data-slot="avatar"
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function AvatarImage({ className, ...props }: AvatarPrimitive.Image.Props) {
|
|
21
|
+
return (
|
|
22
|
+
<AvatarPrimitive.Image
|
|
23
|
+
className={cn("size-full object-cover", className)}
|
|
24
|
+
data-slot="avatar-image"
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function AvatarFallback({
|
|
31
|
+
className,
|
|
32
|
+
...props
|
|
33
|
+
}: AvatarPrimitive.Fallback.Props) {
|
|
34
|
+
return (
|
|
35
|
+
<AvatarPrimitive.Fallback
|
|
36
|
+
className={cn(
|
|
37
|
+
"flex size-full items-center justify-center rounded-full bg-muted",
|
|
38
|
+
className,
|
|
39
|
+
)}
|
|
40
|
+
data-slot="avatar-fallback"
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { Avatar, AvatarImage, AvatarFallback };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
4
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
6
|
+
|
|
7
|
+
import { cn } from "@/lib/utils";
|
|
8
|
+
|
|
9
|
+
const badgeVariants = cva(
|
|
10
|
+
"relative inline-flex shrink-0 items-center justify-center gap-1 whitespace-nowrap rounded-sm border border-transparent font-medium outline-none transition-shadow focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-3.5 sm:[&_svg:not([class*='size-'])]:size-3 [&_svg]:pointer-events-none [&_svg]:shrink-0 [button,a&]:cursor-pointer [button,a&]:pointer-coarse:after:absolute [button,a&]:pointer-coarse:after:size-full [button,a&]:pointer-coarse:after:min-h-11 [button,a&]:pointer-coarse:after:min-w-11",
|
|
11
|
+
{
|
|
12
|
+
defaultVariants: {
|
|
13
|
+
size: "default",
|
|
14
|
+
variant: "default",
|
|
15
|
+
},
|
|
16
|
+
variants: {
|
|
17
|
+
size: {
|
|
18
|
+
default:
|
|
19
|
+
"h-5.5 min-w-5.5 px-[calc(--spacing(1)-1px)] text-sm sm:h-4.5 sm:min-w-4.5 sm:text-xs",
|
|
20
|
+
lg: "h-6.5 min-w-6.5 px-[calc(--spacing(1.5)-1px)] text-base sm:h-5.5 sm:min-w-5.5 sm:text-sm",
|
|
21
|
+
sm: "h-5 min-w-5 rounded-[calc(var(--radius-sm)-2px)] px-[calc(--spacing(1)-1px)] text-xs sm:h-4 sm:min-w-4 sm:text-[.625rem]",
|
|
22
|
+
},
|
|
23
|
+
variant: {
|
|
24
|
+
default:
|
|
25
|
+
"bg-primary text-primary-foreground [button,a&]:hover:bg-primary/90",
|
|
26
|
+
destructive:
|
|
27
|
+
"bg-destructive text-white [button,a&]:hover:bg-destructive/90",
|
|
28
|
+
error:
|
|
29
|
+
"bg-destructive/8 text-destructive-foreground dark:bg-destructive/16",
|
|
30
|
+
info: "bg-info/8 text-info-foreground dark:bg-info/16",
|
|
31
|
+
outline:
|
|
32
|
+
"border-input bg-background text-foreground dark:bg-input/32 [button,a&]:hover:bg-accent/50 dark:[button,a&]:hover:bg-input/48",
|
|
33
|
+
secondary:
|
|
34
|
+
"bg-secondary text-secondary-foreground [button,a&]:hover:bg-secondary/90",
|
|
35
|
+
success: "bg-success/8 text-success-foreground dark:bg-success/16",
|
|
36
|
+
warning: "bg-warning/8 text-warning-foreground dark:bg-warning/16",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
interface BadgeProps extends useRender.ComponentProps<"span"> {
|
|
43
|
+
variant?: VariantProps<typeof badgeVariants>["variant"];
|
|
44
|
+
size?: VariantProps<typeof badgeVariants>["size"];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function Badge({ className, variant, size, render, ...props }: BadgeProps) {
|
|
48
|
+
const defaultProps = {
|
|
49
|
+
className: cn(badgeVariants({ className, size, variant })),
|
|
50
|
+
"data-slot": "badge",
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return useRender({
|
|
54
|
+
defaultTagName: "span",
|
|
55
|
+
props: mergeProps<"span">(defaultProps, props),
|
|
56
|
+
render,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { Badge, badgeVariants };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
4
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
5
|
+
import { ChevronRight, MoreHorizontal } from "lucide-react";
|
|
6
|
+
import type * as React from "react";
|
|
7
|
+
|
|
8
|
+
import { cn } from "@/lib/utils";
|
|
9
|
+
|
|
10
|
+
function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
|
|
11
|
+
return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
|
|
15
|
+
return (
|
|
16
|
+
<ol
|
|
17
|
+
className={cn(
|
|
18
|
+
"wrap-break-word flex flex-wrap items-center gap-1.5 text-muted-foreground text-sm sm:gap-2.5",
|
|
19
|
+
className,
|
|
20
|
+
)}
|
|
21
|
+
data-slot="breadcrumb-list"
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
|
|
28
|
+
return (
|
|
29
|
+
<li
|
|
30
|
+
className={cn("inline-flex items-center gap-1.5", className)}
|
|
31
|
+
data-slot="breadcrumb-item"
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function BreadcrumbLink({
|
|
38
|
+
className,
|
|
39
|
+
render,
|
|
40
|
+
...props
|
|
41
|
+
}: useRender.ComponentProps<"a">) {
|
|
42
|
+
const defaultProps = {
|
|
43
|
+
className: cn("transition-colors hover:text-foreground", className),
|
|
44
|
+
"data-slot": "breadcrumb-link",
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return useRender({
|
|
48
|
+
defaultTagName: "a",
|
|
49
|
+
props: mergeProps<"a">(defaultProps, props),
|
|
50
|
+
render,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
|
|
55
|
+
return (
|
|
56
|
+
// biome-ignore lint(a11y/useFocusableInteractive): known
|
|
57
|
+
<span
|
|
58
|
+
aria-current="page"
|
|
59
|
+
aria-disabled="true"
|
|
60
|
+
className={cn("font-normal text-foreground", className)}
|
|
61
|
+
data-slot="breadcrumb-page"
|
|
62
|
+
role="link"
|
|
63
|
+
{...props}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function BreadcrumbSeparator({
|
|
69
|
+
children,
|
|
70
|
+
className,
|
|
71
|
+
...props
|
|
72
|
+
}: React.ComponentProps<"li">) {
|
|
73
|
+
return (
|
|
74
|
+
<li
|
|
75
|
+
aria-hidden="true"
|
|
76
|
+
className={cn("opacity-80 [&>svg]:size-4", className)}
|
|
77
|
+
data-slot="breadcrumb-separator"
|
|
78
|
+
role="presentation"
|
|
79
|
+
{...props}
|
|
80
|
+
>
|
|
81
|
+
{children ?? <ChevronRight />}
|
|
82
|
+
</li>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function BreadcrumbEllipsis({
|
|
87
|
+
className,
|
|
88
|
+
...props
|
|
89
|
+
}: React.ComponentProps<"span">) {
|
|
90
|
+
return (
|
|
91
|
+
<span
|
|
92
|
+
aria-hidden="true"
|
|
93
|
+
className={className}
|
|
94
|
+
data-slot="breadcrumb-ellipsis"
|
|
95
|
+
role="presentation"
|
|
96
|
+
{...props}
|
|
97
|
+
>
|
|
98
|
+
<MoreHorizontal className="size-4" />
|
|
99
|
+
<span className="sr-only">More</span>
|
|
100
|
+
</span>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export {
|
|
105
|
+
Breadcrumb,
|
|
106
|
+
BreadcrumbList,
|
|
107
|
+
BreadcrumbItem,
|
|
108
|
+
BreadcrumbLink,
|
|
109
|
+
BreadcrumbPage,
|
|
110
|
+
BreadcrumbSeparator,
|
|
111
|
+
BreadcrumbEllipsis,
|
|
112
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
4
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
6
|
+
import type * as React from "react";
|
|
7
|
+
|
|
8
|
+
import { cn } from "@/lib/utils";
|
|
9
|
+
|
|
10
|
+
const buttonVariants = cva(
|
|
11
|
+
"[&_svg]:-mx-0.5 relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 sm:text-sm [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
12
|
+
{
|
|
13
|
+
defaultVariants: {
|
|
14
|
+
size: "default",
|
|
15
|
+
variant: "default",
|
|
16
|
+
},
|
|
17
|
+
variants: {
|
|
18
|
+
size: {
|
|
19
|
+
default: "h-9 px-[calc(--spacing(3)-1px)] sm:h-8",
|
|
20
|
+
icon: "size-9 sm:size-8",
|
|
21
|
+
"icon-lg": "size-10 sm:size-9",
|
|
22
|
+
"icon-sm": "size-8 sm:size-7",
|
|
23
|
+
"icon-xl":
|
|
24
|
+
"size-11 sm:size-10 [&_svg:not([class*='size-'])]:size-5 sm:[&_svg:not([class*='size-'])]:size-4.5",
|
|
25
|
+
"icon-xs":
|
|
26
|
+
"size-7 rounded-md before:rounded-[calc(var(--radius-md)-1px)] sm:size-6 not-in-data-[slot=input-group]:[&_svg:not([class*='size-'])]:size-4 sm:not-in-data-[slot=input-group]:[&_svg:not([class*='size-'])]:size-3.5",
|
|
27
|
+
lg: "h-10 px-[calc(--spacing(3.5)-1px)] sm:h-9",
|
|
28
|
+
sm: "h-8 gap-1.5 px-[calc(--spacing(2.5)-1px)] sm:h-7",
|
|
29
|
+
xl: "h-11 px-[calc(--spacing(4)-1px)] text-lg sm:h-10 sm:text-base [&_svg:not([class*='size-'])]:size-5 sm:[&_svg:not([class*='size-'])]:size-4.5",
|
|
30
|
+
xs: "h-7 gap-1 rounded-md px-[calc(--spacing(2)-1px)] text-sm before:rounded-[calc(var(--radius-md)-1px)] sm:h-6 sm:text-xs [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5",
|
|
31
|
+
},
|
|
32
|
+
variant: {
|
|
33
|
+
default:
|
|
34
|
+
"not-disabled:inset-shadow-[0_1px_--theme(--color-white/16%)] border-primary bg-primary text-primary-foreground shadow-primary/24 shadow-xs [:active,[data-pressed]]:inset-shadow-[0_1px_--theme(--color-black/8%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:bg-primary/90",
|
|
35
|
+
destructive:
|
|
36
|
+
"not-disabled:inset-shadow-[0_1px_--theme(--color-white/16%)] border-destructive bg-destructive text-white shadow-destructive/24 shadow-xs [:active,[data-pressed]]:inset-shadow-[0_1px_--theme(--color-black/8%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:bg-destructive/90",
|
|
37
|
+
"destructive-outline":
|
|
38
|
+
"border-input bg-transparent not-dark:bg-clip-padding text-destructive-foreground shadow-xs/5 not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/6%)] dark:bg-input/32 dark:not-disabled:before:shadow-[0_-1px_--theme(--color-white/2%)] dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:border-destructive/32 [:hover,[data-pressed]]:bg-destructive/4",
|
|
39
|
+
ghost:
|
|
40
|
+
"border-transparent text-foreground data-pressed:bg-accent [:hover,[data-pressed]]:bg-accent",
|
|
41
|
+
link: "border-transparent underline-offset-4 [:hover,[data-pressed]]:underline",
|
|
42
|
+
outline:
|
|
43
|
+
"border-input bg-background not-dark:bg-clip-padding text-foreground shadow-xs/5 not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/6%)] dark:bg-input/32 dark:not-disabled:before:shadow-[0_-1px_--theme(--color-white/2%)] dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:bg-accent/50 dark:[:hover,[data-pressed]]:bg-input/64",
|
|
44
|
+
secondary:
|
|
45
|
+
"border-transparent bg-secondary text-secondary-foreground [:active,[data-pressed]]:bg-secondary/80 [:hover,[data-pressed]]:bg-secondary/90",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
interface ButtonProps extends useRender.ComponentProps<"button"> {
|
|
52
|
+
variant?: VariantProps<typeof buttonVariants>["variant"];
|
|
53
|
+
size?: VariantProps<typeof buttonVariants>["size"];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function Button({ className, variant, size, render, ...props }: ButtonProps) {
|
|
57
|
+
const typeValue: React.ButtonHTMLAttributes<HTMLButtonElement>["type"] =
|
|
58
|
+
render ? undefined : "button";
|
|
59
|
+
|
|
60
|
+
const defaultProps = {
|
|
61
|
+
className: cn(buttonVariants({ className, size, variant })),
|
|
62
|
+
"data-slot": "button",
|
|
63
|
+
type: typeValue,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return useRender({
|
|
67
|
+
defaultTagName: "button",
|
|
68
|
+
props: mergeProps<"button">(defaultProps, props),
|
|
69
|
+
render,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
4
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
function Card({
|
|
9
|
+
className,
|
|
10
|
+
render,
|
|
11
|
+
...props
|
|
12
|
+
}: useRender.ComponentProps<"div">) {
|
|
13
|
+
const defaultProps = {
|
|
14
|
+
className: cn(
|
|
15
|
+
"relative flex flex-col rounded-2xl border bg-card not-dark:bg-clip-padding text-card-foreground shadow-xs/5 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
|
|
16
|
+
className,
|
|
17
|
+
),
|
|
18
|
+
"data-slot": "card",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
return useRender({
|
|
22
|
+
defaultTagName: "div",
|
|
23
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
24
|
+
render,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function CardFrame({
|
|
29
|
+
className,
|
|
30
|
+
render,
|
|
31
|
+
...props
|
|
32
|
+
}: useRender.ComponentProps<"div">) {
|
|
33
|
+
const defaultProps = {
|
|
34
|
+
className: cn(
|
|
35
|
+
"flex flex-col relative rounded-2xl border bg-background before:absolute before:inset-0 before:rounded-[inherit] before:bg-muted/72 before:pointer-events-none not-dark:bg-clip-padding text-card-foreground shadow-xs/5 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)] *:data-[slot=card]:-m-px *:not-last:data-[slot=card]:rounded-b-lg *:not-last:data-[slot=card]:before:rounded-b-[calc(var(--radius-lg)-1px)] *:not-first:data-[slot=card]:rounded-t-lg *:not-first:data-[slot=card]:before:rounded-t-[calc(var(--radius-lg)-1px)] *:data-[slot=card]:[clip-path:inset(-1rem_1px)] *:data-[slot=card]:first:[clip-path:inset(1px_1px_-1rem_1px_round_calc(var(--radius-2xl)-1px))] *:data-[slot=card]:last:[clip-path:inset(-1rem_1px_1px_1px_round_calc(var(--radius-2xl)-1px))] *:data-[slot=card]:shadow-none *:data-[slot=card]:before:hidden *:data-[slot=card]:bg-clip-padding",
|
|
36
|
+
className,
|
|
37
|
+
),
|
|
38
|
+
"data-slot": "card-frame",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return useRender({
|
|
42
|
+
defaultTagName: "div",
|
|
43
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
44
|
+
render,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function CardFrameHeader({
|
|
49
|
+
className,
|
|
50
|
+
render,
|
|
51
|
+
...props
|
|
52
|
+
}: useRender.ComponentProps<"div">) {
|
|
53
|
+
const defaultProps = {
|
|
54
|
+
className: cn("flex flex-col px-6 py-4", className),
|
|
55
|
+
"data-slot": "card-frame-header",
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return useRender({
|
|
59
|
+
defaultTagName: "div",
|
|
60
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
61
|
+
render,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function CardFrameTitle({
|
|
66
|
+
className,
|
|
67
|
+
render,
|
|
68
|
+
...props
|
|
69
|
+
}: useRender.ComponentProps<"div">) {
|
|
70
|
+
const defaultProps = {
|
|
71
|
+
className: cn("font-semibold text-sm", className),
|
|
72
|
+
"data-slot": "card-frame-title",
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return useRender({
|
|
76
|
+
defaultTagName: "div",
|
|
77
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
78
|
+
render,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function CardFrameDescription({
|
|
83
|
+
className,
|
|
84
|
+
render,
|
|
85
|
+
...props
|
|
86
|
+
}: useRender.ComponentProps<"div">) {
|
|
87
|
+
const defaultProps = {
|
|
88
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
89
|
+
"data-slot": "card-frame-description",
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return useRender({
|
|
93
|
+
defaultTagName: "div",
|
|
94
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
95
|
+
render,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function CardFrameFooter({
|
|
100
|
+
className,
|
|
101
|
+
render,
|
|
102
|
+
...props
|
|
103
|
+
}: useRender.ComponentProps<"div">) {
|
|
104
|
+
const defaultProps = {
|
|
105
|
+
className: cn("px-6 py-4", className),
|
|
106
|
+
"data-slot": "card-frame-footer",
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return useRender({
|
|
110
|
+
defaultTagName: "div",
|
|
111
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
112
|
+
render,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function CardHeader({
|
|
117
|
+
className,
|
|
118
|
+
render,
|
|
119
|
+
...props
|
|
120
|
+
}: useRender.ComponentProps<"div">) {
|
|
121
|
+
const defaultProps = {
|
|
122
|
+
className: cn(
|
|
123
|
+
"grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 p-6 in-[[data-slot=card]:has(>[data-slot=card-panel])]:pb-4 has-data-[slot=card-action]:grid-cols-[1fr_auto]",
|
|
124
|
+
className,
|
|
125
|
+
),
|
|
126
|
+
"data-slot": "card-header",
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
return useRender({
|
|
130
|
+
defaultTagName: "div",
|
|
131
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
132
|
+
render,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function CardTitle({
|
|
137
|
+
className,
|
|
138
|
+
render,
|
|
139
|
+
...props
|
|
140
|
+
}: useRender.ComponentProps<"div">) {
|
|
141
|
+
const defaultProps = {
|
|
142
|
+
className: cn("font-semibold text-lg leading-none", className),
|
|
143
|
+
"data-slot": "card-title",
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
return useRender({
|
|
147
|
+
defaultTagName: "div",
|
|
148
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
149
|
+
render,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function CardDescription({
|
|
154
|
+
className,
|
|
155
|
+
render,
|
|
156
|
+
...props
|
|
157
|
+
}: useRender.ComponentProps<"div">) {
|
|
158
|
+
const defaultProps = {
|
|
159
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
160
|
+
"data-slot": "card-description",
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
return useRender({
|
|
164
|
+
defaultTagName: "div",
|
|
165
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
166
|
+
render,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function CardAction({
|
|
171
|
+
className,
|
|
172
|
+
render,
|
|
173
|
+
...props
|
|
174
|
+
}: useRender.ComponentProps<"div">) {
|
|
175
|
+
const defaultProps = {
|
|
176
|
+
className: cn(
|
|
177
|
+
"col-start-2 row-span-2 row-start-1 self-start justify-self-end inline-flex",
|
|
178
|
+
className,
|
|
179
|
+
),
|
|
180
|
+
"data-slot": "card-action",
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
return useRender({
|
|
184
|
+
defaultTagName: "div",
|
|
185
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
186
|
+
render,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function CardPanel({
|
|
191
|
+
className,
|
|
192
|
+
render,
|
|
193
|
+
...props
|
|
194
|
+
}: useRender.ComponentProps<"div">) {
|
|
195
|
+
const defaultProps = {
|
|
196
|
+
className: cn(
|
|
197
|
+
"flex-1 p-6 in-[[data-slot=card]:has(>[data-slot=card-header]:not(.border-b))]:pt-0 in-[[data-slot=card]:has(>[data-slot=card-footer]:not(.border-t))]:pb-0",
|
|
198
|
+
className,
|
|
199
|
+
),
|
|
200
|
+
"data-slot": "card-panel",
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
return useRender({
|
|
204
|
+
defaultTagName: "div",
|
|
205
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
206
|
+
render,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function CardFooter({
|
|
211
|
+
className,
|
|
212
|
+
render,
|
|
213
|
+
...props
|
|
214
|
+
}: useRender.ComponentProps<"div">) {
|
|
215
|
+
const defaultProps = {
|
|
216
|
+
className: cn(
|
|
217
|
+
"flex items-center p-6 in-[[data-slot=card]:has(>[data-slot=card-panel])]:pt-4",
|
|
218
|
+
className,
|
|
219
|
+
),
|
|
220
|
+
"data-slot": "card-footer",
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
return useRender({
|
|
224
|
+
defaultTagName: "div",
|
|
225
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
226
|
+
render,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export {
|
|
231
|
+
Card,
|
|
232
|
+
CardFrame,
|
|
233
|
+
CardFrameHeader,
|
|
234
|
+
CardFrameTitle,
|
|
235
|
+
CardFrameDescription,
|
|
236
|
+
CardFrameFooter,
|
|
237
|
+
CardAction,
|
|
238
|
+
CardDescription,
|
|
239
|
+
CardFooter,
|
|
240
|
+
CardHeader,
|
|
241
|
+
CardPanel,
|
|
242
|
+
CardPanel as CardContent,
|
|
243
|
+
CardTitle,
|
|
244
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { CheckboxGroup as CheckboxGroupPrimitive } from "@base-ui/react/checkbox-group";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
function CheckboxGroup({ className, ...props }: CheckboxGroupPrimitive.Props) {
|
|
8
|
+
return (
|
|
9
|
+
<CheckboxGroupPrimitive
|
|
10
|
+
className={cn("flex flex-col items-start gap-3", className)}
|
|
11
|
+
{...props}
|
|
12
|
+
/>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { CheckboxGroup };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
|
|
8
|
+
return (
|
|
9
|
+
<CheckboxPrimitive.Root
|
|
10
|
+
className={cn(
|
|
11
|
+
"relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-[4px] border border-input bg-background not-dark:bg-clip-padding shadow-xs/5 outline-none ring-ring transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[3px] not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/6%)] focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-offset-background aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/48 data-disabled:opacity-64 sm:size-4 dark:not-data-checked:bg-input/32 dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [[data-disabled],[data-checked],[aria-invalid]]:shadow-none",
|
|
12
|
+
className,
|
|
13
|
+
)}
|
|
14
|
+
data-slot="checkbox"
|
|
15
|
+
{...props}
|
|
16
|
+
>
|
|
17
|
+
<CheckboxPrimitive.Indicator
|
|
18
|
+
className="-inset-px absolute flex items-center justify-center rounded-[4px] text-primary-foreground data-unchecked:hidden data-checked:bg-primary data-indeterminate:text-foreground"
|
|
19
|
+
data-slot="checkbox-indicator"
|
|
20
|
+
render={(props, state) => (
|
|
21
|
+
<span {...props}>
|
|
22
|
+
{state.indeterminate ? (
|
|
23
|
+
<svg
|
|
24
|
+
className="size-3.5 sm:size-3"
|
|
25
|
+
fill="none"
|
|
26
|
+
height="24"
|
|
27
|
+
stroke="currentColor"
|
|
28
|
+
strokeLinecap="round"
|
|
29
|
+
strokeLinejoin="round"
|
|
30
|
+
strokeWidth="3"
|
|
31
|
+
viewBox="0 0 24 24"
|
|
32
|
+
width="24"
|
|
33
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
34
|
+
>
|
|
35
|
+
<path d="M5.252 12h13.496" />
|
|
36
|
+
</svg>
|
|
37
|
+
) : (
|
|
38
|
+
<svg
|
|
39
|
+
className="size-3.5 sm:size-3"
|
|
40
|
+
fill="none"
|
|
41
|
+
height="24"
|
|
42
|
+
stroke="currentColor"
|
|
43
|
+
strokeLinecap="round"
|
|
44
|
+
strokeLinejoin="round"
|
|
45
|
+
strokeWidth="3"
|
|
46
|
+
viewBox="0 0 24 24"
|
|
47
|
+
width="24"
|
|
48
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
49
|
+
>
|
|
50
|
+
<path d="M5.252 12.7 10.2 18.63 18.748 5.37" />
|
|
51
|
+
</svg>
|
|
52
|
+
)}
|
|
53
|
+
</span>
|
|
54
|
+
)}
|
|
55
|
+
/>
|
|
56
|
+
</CheckboxPrimitive.Root>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { Checkbox };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Collapsible as CollapsiblePrimitive } from "@base-ui/react/collapsible";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
function Collapsible({ ...props }: CollapsiblePrimitive.Root.Props) {
|
|
8
|
+
return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function CollapsibleTrigger({
|
|
12
|
+
className,
|
|
13
|
+
...props
|
|
14
|
+
}: CollapsiblePrimitive.Trigger.Props) {
|
|
15
|
+
return (
|
|
16
|
+
<CollapsiblePrimitive.Trigger
|
|
17
|
+
className={cn("cursor-pointer", className)}
|
|
18
|
+
data-slot="collapsible-trigger"
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function CollapsiblePanel({
|
|
25
|
+
className,
|
|
26
|
+
...props
|
|
27
|
+
}: CollapsiblePrimitive.Panel.Props) {
|
|
28
|
+
return (
|
|
29
|
+
<CollapsiblePrimitive.Panel
|
|
30
|
+
className={cn(
|
|
31
|
+
"h-(--collapsible-panel-height) overflow-hidden transition-[height] duration-200 data-ending-style:h-0 data-starting-style:h-0",
|
|
32
|
+
className,
|
|
33
|
+
)}
|
|
34
|
+
data-slot="collapsible-panel"
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
Collapsible,
|
|
42
|
+
CollapsibleTrigger,
|
|
43
|
+
CollapsiblePanel,
|
|
44
|
+
CollapsiblePanel as CollapsibleContent,
|
|
45
|
+
};
|