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,160 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { NumberField as NumberFieldPrimitive } from "@base-ui/react/number-field";
|
|
4
|
+
import { MinusIcon, PlusIcon } from "lucide-react";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
|
|
7
|
+
import { cn } from "@/lib/utils";
|
|
8
|
+
import { Label } from "@/components/ui/label";
|
|
9
|
+
|
|
10
|
+
const NumberFieldContext = React.createContext<{
|
|
11
|
+
fieldId: string;
|
|
12
|
+
} | null>(null);
|
|
13
|
+
|
|
14
|
+
function NumberField({
|
|
15
|
+
id,
|
|
16
|
+
className,
|
|
17
|
+
size = "default",
|
|
18
|
+
...props
|
|
19
|
+
}: NumberFieldPrimitive.Root.Props & {
|
|
20
|
+
size?: "sm" | "default" | "lg";
|
|
21
|
+
}) {
|
|
22
|
+
const generatedId = React.useId();
|
|
23
|
+
const fieldId = id ?? generatedId;
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<NumberFieldContext.Provider value={{ fieldId }}>
|
|
27
|
+
<NumberFieldPrimitive.Root
|
|
28
|
+
className={cn("flex w-full flex-col items-start gap-2", className)}
|
|
29
|
+
data-size={size}
|
|
30
|
+
data-slot="number-field"
|
|
31
|
+
id={fieldId}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
</NumberFieldContext.Provider>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function NumberFieldGroup({
|
|
39
|
+
className,
|
|
40
|
+
...props
|
|
41
|
+
}: NumberFieldPrimitive.Group.Props) {
|
|
42
|
+
return (
|
|
43
|
+
<NumberFieldPrimitive.Group
|
|
44
|
+
className={cn(
|
|
45
|
+
"relative flex w-full justify-between rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-xs/5 ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-data-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/6%)] focus-within:border-ring focus-within:ring-[3px] has-aria-invalid:border-destructive/36 focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive/48 data-disabled:pointer-events-none data-disabled:opacity-64 sm:text-sm dark:bg-input/32 dark:has-aria-invalid:ring-destructive/24 dark:not-data-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [[data-disabled],:focus-within,[aria-invalid]]:shadow-none",
|
|
46
|
+
className,
|
|
47
|
+
)}
|
|
48
|
+
data-slot="number-field-group"
|
|
49
|
+
{...props}
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function NumberFieldDecrement({
|
|
55
|
+
className,
|
|
56
|
+
...props
|
|
57
|
+
}: NumberFieldPrimitive.Decrement.Props) {
|
|
58
|
+
return (
|
|
59
|
+
<NumberFieldPrimitive.Decrement
|
|
60
|
+
className={cn(
|
|
61
|
+
"relative flex shrink-0 cursor-pointer items-center justify-center rounded-s-[calc(var(--radius-lg)-1px)] in-data-[size=sm]:px-[calc(--spacing(2.5)-1px)] px-[calc(--spacing(3)-1px)] transition-colors pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent",
|
|
62
|
+
className,
|
|
63
|
+
)}
|
|
64
|
+
data-slot="number-field-decrement"
|
|
65
|
+
{...props}
|
|
66
|
+
>
|
|
67
|
+
<MinusIcon />
|
|
68
|
+
</NumberFieldPrimitive.Decrement>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function NumberFieldIncrement({
|
|
73
|
+
className,
|
|
74
|
+
...props
|
|
75
|
+
}: NumberFieldPrimitive.Increment.Props) {
|
|
76
|
+
return (
|
|
77
|
+
<NumberFieldPrimitive.Increment
|
|
78
|
+
className={cn(
|
|
79
|
+
"relative flex shrink-0 cursor-pointer items-center justify-center rounded-e-[calc(var(--radius-lg)-1px)] in-data-[size=sm]:px-[calc(--spacing(2.5)-1px)] px-[calc(--spacing(3)-1px)] transition-colors pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent",
|
|
80
|
+
className,
|
|
81
|
+
)}
|
|
82
|
+
data-slot="number-field-increment"
|
|
83
|
+
{...props}
|
|
84
|
+
>
|
|
85
|
+
<PlusIcon />
|
|
86
|
+
</NumberFieldPrimitive.Increment>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function NumberFieldInput({
|
|
91
|
+
className,
|
|
92
|
+
...props
|
|
93
|
+
}: NumberFieldPrimitive.Input.Props) {
|
|
94
|
+
return (
|
|
95
|
+
<NumberFieldPrimitive.Input
|
|
96
|
+
className={cn(
|
|
97
|
+
"h-8.5 in-data-[size=lg]:h-9.5 in-data-[size=sm]:h-7.5 w-full min-w-0 grow bg-transparent in-data-[size=sm]:px-[calc(--spacing(2.5)-1px)] px-[calc(--spacing(3)-1px)] text-center tabular-nums in-data-[size=lg]:leading-9.5 in-data-[size=sm]:leading-7.5 leading-8.5 outline-none sm:h-7.5 sm:in-data-[size=lg]:h-8.5 sm:in-data-[size=sm]:h-6.5 sm:in-data-[size=lg]:leading-8.5 sm:in-data-[size=sm]:leading-8.5 sm:leading-7.5",
|
|
98
|
+
className,
|
|
99
|
+
)}
|
|
100
|
+
data-slot="number-field-input"
|
|
101
|
+
{...props}
|
|
102
|
+
/>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function NumberFieldScrubArea({
|
|
107
|
+
className,
|
|
108
|
+
label,
|
|
109
|
+
...props
|
|
110
|
+
}: NumberFieldPrimitive.ScrubArea.Props & {
|
|
111
|
+
label: string;
|
|
112
|
+
}) {
|
|
113
|
+
const context = React.useContext(NumberFieldContext);
|
|
114
|
+
|
|
115
|
+
if (!context) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
"NumberFieldScrubArea must be used within a NumberField component for accessibility.",
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<NumberFieldPrimitive.ScrubArea
|
|
123
|
+
className={cn("flex cursor-ew-resize", className)}
|
|
124
|
+
data-slot="number-field-scrub-area"
|
|
125
|
+
{...props}
|
|
126
|
+
>
|
|
127
|
+
<Label className="cursor-ew-resize" htmlFor={context.fieldId}>
|
|
128
|
+
{label}
|
|
129
|
+
</Label>
|
|
130
|
+
<NumberFieldPrimitive.ScrubAreaCursor className="drop-shadow-[0_1px_1px_#0008] filter">
|
|
131
|
+
<CursorGrowIcon />
|
|
132
|
+
</NumberFieldPrimitive.ScrubAreaCursor>
|
|
133
|
+
</NumberFieldPrimitive.ScrubArea>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function CursorGrowIcon(props: React.ComponentProps<"svg">) {
|
|
138
|
+
return (
|
|
139
|
+
<svg
|
|
140
|
+
fill="black"
|
|
141
|
+
height="14"
|
|
142
|
+
stroke="white"
|
|
143
|
+
viewBox="0 0 24 14"
|
|
144
|
+
width="26"
|
|
145
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
146
|
+
{...props}
|
|
147
|
+
>
|
|
148
|
+
<path d="M19.5 5.5L6.49737 5.51844V2L1 6.9999L6.5 12L6.49737 8.5L19.5 8.5V12L25 6.9999L19.5 2V5.5Z" />
|
|
149
|
+
</svg>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export {
|
|
154
|
+
NumberField,
|
|
155
|
+
NumberFieldScrubArea,
|
|
156
|
+
NumberFieldDecrement,
|
|
157
|
+
NumberFieldIncrement,
|
|
158
|
+
NumberFieldGroup,
|
|
159
|
+
NumberFieldInput,
|
|
160
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
4
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
5
|
+
import {
|
|
6
|
+
ChevronLeftIcon,
|
|
7
|
+
ChevronRightIcon,
|
|
8
|
+
MoreHorizontalIcon,
|
|
9
|
+
} from "lucide-react";
|
|
10
|
+
import type * as React from "react";
|
|
11
|
+
|
|
12
|
+
import { cn } from "@/lib/utils";
|
|
13
|
+
import { type Button, buttonVariants } from "@/components/ui/button";
|
|
14
|
+
|
|
15
|
+
function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
|
|
16
|
+
return (
|
|
17
|
+
<nav
|
|
18
|
+
aria-label="pagination"
|
|
19
|
+
className={cn("mx-auto flex w-full justify-center", className)}
|
|
20
|
+
data-slot="pagination"
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function PaginationContent({
|
|
27
|
+
className,
|
|
28
|
+
...props
|
|
29
|
+
}: React.ComponentProps<"ul">) {
|
|
30
|
+
return (
|
|
31
|
+
<ul
|
|
32
|
+
className={cn("flex flex-row items-center gap-1", className)}
|
|
33
|
+
data-slot="pagination-content"
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function PaginationItem({ ...props }: React.ComponentProps<"li">) {
|
|
40
|
+
return <li data-slot="pagination-item" {...props} />;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type PaginationLinkProps = {
|
|
44
|
+
isActive?: boolean;
|
|
45
|
+
size?: React.ComponentProps<typeof Button>["size"];
|
|
46
|
+
} & useRender.ComponentProps<"a">;
|
|
47
|
+
|
|
48
|
+
function PaginationLink({
|
|
49
|
+
className,
|
|
50
|
+
isActive,
|
|
51
|
+
size = "icon",
|
|
52
|
+
render,
|
|
53
|
+
...props
|
|
54
|
+
}: PaginationLinkProps) {
|
|
55
|
+
const defaultProps = {
|
|
56
|
+
"aria-current": isActive ? ("page" as const) : undefined,
|
|
57
|
+
className: render
|
|
58
|
+
? className
|
|
59
|
+
: cn(
|
|
60
|
+
buttonVariants({
|
|
61
|
+
size,
|
|
62
|
+
variant: isActive ? "outline" : "ghost",
|
|
63
|
+
}),
|
|
64
|
+
className,
|
|
65
|
+
),
|
|
66
|
+
"data-active": isActive,
|
|
67
|
+
"data-slot": "pagination-link",
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return useRender({
|
|
71
|
+
defaultTagName: "a",
|
|
72
|
+
props: mergeProps<"a">(defaultProps, props),
|
|
73
|
+
render,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function PaginationPrevious({
|
|
78
|
+
className,
|
|
79
|
+
...props
|
|
80
|
+
}: React.ComponentProps<typeof PaginationLink>) {
|
|
81
|
+
return (
|
|
82
|
+
<PaginationLink
|
|
83
|
+
aria-label="Go to previous page"
|
|
84
|
+
className={cn("max-sm:aspect-square max-sm:p-0", className)}
|
|
85
|
+
size="default"
|
|
86
|
+
{...props}
|
|
87
|
+
>
|
|
88
|
+
<ChevronLeftIcon className="sm:-ms-1" />
|
|
89
|
+
<span className="max-sm:hidden">Previous</span>
|
|
90
|
+
</PaginationLink>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function PaginationNext({
|
|
95
|
+
className,
|
|
96
|
+
...props
|
|
97
|
+
}: React.ComponentProps<typeof PaginationLink>) {
|
|
98
|
+
return (
|
|
99
|
+
<PaginationLink
|
|
100
|
+
aria-label="Go to next page"
|
|
101
|
+
className={cn("max-sm:aspect-square max-sm:p-0", className)}
|
|
102
|
+
size="default"
|
|
103
|
+
{...props}
|
|
104
|
+
>
|
|
105
|
+
<span className="max-sm:hidden">Next</span>
|
|
106
|
+
<ChevronRightIcon className="sm:-me-1" />
|
|
107
|
+
</PaginationLink>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function PaginationEllipsis({
|
|
112
|
+
className,
|
|
113
|
+
...props
|
|
114
|
+
}: React.ComponentProps<"span">) {
|
|
115
|
+
return (
|
|
116
|
+
<span
|
|
117
|
+
aria-hidden
|
|
118
|
+
className={cn("flex min-w-7 justify-center", className)}
|
|
119
|
+
data-slot="pagination-ellipsis"
|
|
120
|
+
{...props}
|
|
121
|
+
>
|
|
122
|
+
<MoreHorizontalIcon className="size-5 sm:size-4" />
|
|
123
|
+
<span className="sr-only">More pages</span>
|
|
124
|
+
</span>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
Pagination,
|
|
130
|
+
PaginationContent,
|
|
131
|
+
PaginationLink,
|
|
132
|
+
PaginationItem,
|
|
133
|
+
PaginationPrevious,
|
|
134
|
+
PaginationNext,
|
|
135
|
+
PaginationEllipsis,
|
|
136
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Popover as PopoverPrimitive } from "@base-ui/react/popover";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
const PopoverCreateHandle = PopoverPrimitive.createHandle;
|
|
8
|
+
|
|
9
|
+
const Popover = PopoverPrimitive.Root;
|
|
10
|
+
|
|
11
|
+
function PopoverTrigger(props: PopoverPrimitive.Trigger.Props) {
|
|
12
|
+
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function PopoverPopup({
|
|
16
|
+
children,
|
|
17
|
+
className,
|
|
18
|
+
side = "bottom",
|
|
19
|
+
align = "center",
|
|
20
|
+
sideOffset = 4,
|
|
21
|
+
alignOffset = 0,
|
|
22
|
+
tooltipStyle = false,
|
|
23
|
+
...props
|
|
24
|
+
}: PopoverPrimitive.Popup.Props & {
|
|
25
|
+
side?: PopoverPrimitive.Positioner.Props["side"];
|
|
26
|
+
align?: PopoverPrimitive.Positioner.Props["align"];
|
|
27
|
+
sideOffset?: PopoverPrimitive.Positioner.Props["sideOffset"];
|
|
28
|
+
alignOffset?: PopoverPrimitive.Positioner.Props["alignOffset"];
|
|
29
|
+
tooltipStyle?: boolean;
|
|
30
|
+
}) {
|
|
31
|
+
return (
|
|
32
|
+
<PopoverPrimitive.Portal>
|
|
33
|
+
<PopoverPrimitive.Positioner
|
|
34
|
+
align={align}
|
|
35
|
+
alignOffset={alignOffset}
|
|
36
|
+
className="z-50 h-(--positioner-height) w-(--positioner-width) max-w-(--available-width) transition-[top,left,right,bottom,transform] data-instant:transition-none"
|
|
37
|
+
data-slot="popover-positioner"
|
|
38
|
+
side={side}
|
|
39
|
+
sideOffset={sideOffset}
|
|
40
|
+
>
|
|
41
|
+
<PopoverPrimitive.Popup
|
|
42
|
+
className={cn(
|
|
43
|
+
"relative flex h-(--popup-height,auto) w-(--popup-width,auto) origin-(--transform-origin) rounded-lg border bg-popover not-dark:bg-clip-padding text-popover-foreground shadow-lg/5 transition-[width,height,scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] data-starting-style:scale-98 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
|
|
44
|
+
tooltipStyle &&
|
|
45
|
+
"w-fit text-balance rounded-md text-xs shadow-md/5 before:rounded-[calc(var(--radius-md)-1px)]",
|
|
46
|
+
className,
|
|
47
|
+
)}
|
|
48
|
+
data-slot="popover-popup"
|
|
49
|
+
{...props}
|
|
50
|
+
>
|
|
51
|
+
<PopoverPrimitive.Viewport
|
|
52
|
+
className={cn(
|
|
53
|
+
"relative size-full max-h-(--available-height) overflow-clip px-(--viewport-inline-padding) py-4 outline-none [--viewport-inline-padding:--spacing(4)] data-instant:transition-none **:data-current:data-ending-style:opacity-0 **:data-current:data-starting-style:opacity-0 **:data-previous:data-ending-style:opacity-0 **:data-previous:data-starting-style:opacity-0 **:data-current:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-previous:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-current:opacity-100 **:data-previous:opacity-100 **:data-current:transition-opacity **:data-previous:transition-opacity",
|
|
54
|
+
tooltipStyle
|
|
55
|
+
? "py-1 [--viewport-inline-padding:--spacing(2)]"
|
|
56
|
+
: "not-data-transitioning:overflow-y-auto",
|
|
57
|
+
)}
|
|
58
|
+
data-slot="popover-viewport"
|
|
59
|
+
>
|
|
60
|
+
{children}
|
|
61
|
+
</PopoverPrimitive.Viewport>
|
|
62
|
+
</PopoverPrimitive.Popup>
|
|
63
|
+
</PopoverPrimitive.Positioner>
|
|
64
|
+
</PopoverPrimitive.Portal>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function PopoverClose({ ...props }: PopoverPrimitive.Close.Props) {
|
|
69
|
+
return <PopoverPrimitive.Close data-slot="popover-close" {...props} />;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function PopoverTitle({ className, ...props }: PopoverPrimitive.Title.Props) {
|
|
73
|
+
return (
|
|
74
|
+
<PopoverPrimitive.Title
|
|
75
|
+
className={cn("font-semibold text-lg leading-none", className)}
|
|
76
|
+
data-slot="popover-title"
|
|
77
|
+
{...props}
|
|
78
|
+
/>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function PopoverDescription({
|
|
83
|
+
className,
|
|
84
|
+
...props
|
|
85
|
+
}: PopoverPrimitive.Description.Props) {
|
|
86
|
+
return (
|
|
87
|
+
<PopoverPrimitive.Description
|
|
88
|
+
className={cn("text-muted-foreground text-sm", className)}
|
|
89
|
+
data-slot="popover-description"
|
|
90
|
+
{...props}
|
|
91
|
+
/>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export {
|
|
96
|
+
PopoverCreateHandle,
|
|
97
|
+
Popover,
|
|
98
|
+
PopoverTrigger,
|
|
99
|
+
PopoverPopup,
|
|
100
|
+
PopoverPopup as PopoverContent,
|
|
101
|
+
PopoverTitle,
|
|
102
|
+
PopoverDescription,
|
|
103
|
+
PopoverClose,
|
|
104
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { PreviewCard as PreviewCardPrimitive } from "@base-ui/react/preview-card";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
const PreviewCard = PreviewCardPrimitive.Root;
|
|
8
|
+
|
|
9
|
+
function PreviewCardTrigger({ ...props }: PreviewCardPrimitive.Trigger.Props) {
|
|
10
|
+
return (
|
|
11
|
+
<PreviewCardPrimitive.Trigger data-slot="preview-card-trigger" {...props} />
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function PreviewCardPopup({
|
|
16
|
+
className,
|
|
17
|
+
children,
|
|
18
|
+
align = "center",
|
|
19
|
+
sideOffset = 4,
|
|
20
|
+
...props
|
|
21
|
+
}: PreviewCardPrimitive.Popup.Props & {
|
|
22
|
+
align?: PreviewCardPrimitive.Positioner.Props["align"];
|
|
23
|
+
sideOffset?: PreviewCardPrimitive.Positioner.Props["sideOffset"];
|
|
24
|
+
}) {
|
|
25
|
+
return (
|
|
26
|
+
<PreviewCardPrimitive.Portal>
|
|
27
|
+
<PreviewCardPrimitive.Positioner
|
|
28
|
+
align={align}
|
|
29
|
+
className="z-50"
|
|
30
|
+
data-slot="preview-card-positioner"
|
|
31
|
+
sideOffset={sideOffset}
|
|
32
|
+
>
|
|
33
|
+
<PreviewCardPrimitive.Popup
|
|
34
|
+
className={cn(
|
|
35
|
+
"relative flex w-64 origin-(--transform-origin) text-balance rounded-lg border bg-popover not-dark:bg-clip-padding p-4 text-popover-foreground text-sm shadow-lg/5 transition-[scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
|
|
36
|
+
className,
|
|
37
|
+
)}
|
|
38
|
+
data-slot="preview-card-content"
|
|
39
|
+
{...props}
|
|
40
|
+
>
|
|
41
|
+
{children}
|
|
42
|
+
</PreviewCardPrimitive.Popup>
|
|
43
|
+
</PreviewCardPrimitive.Positioner>
|
|
44
|
+
</PreviewCardPrimitive.Portal>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
PreviewCard,
|
|
50
|
+
PreviewCard as HoverCard,
|
|
51
|
+
PreviewCardTrigger,
|
|
52
|
+
PreviewCardTrigger as HoverCardTrigger,
|
|
53
|
+
PreviewCardPopup,
|
|
54
|
+
PreviewCardPopup as HoverCardContent,
|
|
55
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Progress as ProgressPrimitive } from "@base-ui/react/progress";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
function Progress({
|
|
8
|
+
className,
|
|
9
|
+
children,
|
|
10
|
+
...props
|
|
11
|
+
}: ProgressPrimitive.Root.Props) {
|
|
12
|
+
return (
|
|
13
|
+
<ProgressPrimitive.Root
|
|
14
|
+
className={cn("flex w-full flex-col gap-2", className)}
|
|
15
|
+
data-slot="progress"
|
|
16
|
+
{...props}
|
|
17
|
+
>
|
|
18
|
+
{children ? (
|
|
19
|
+
children
|
|
20
|
+
) : (
|
|
21
|
+
<ProgressTrack>
|
|
22
|
+
<ProgressIndicator />
|
|
23
|
+
</ProgressTrack>
|
|
24
|
+
)}
|
|
25
|
+
</ProgressPrimitive.Root>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {
|
|
30
|
+
return (
|
|
31
|
+
<ProgressPrimitive.Label
|
|
32
|
+
className={cn("font-medium text-sm", className)}
|
|
33
|
+
data-slot="progress-label"
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function ProgressTrack({ className, ...props }: ProgressPrimitive.Track.Props) {
|
|
40
|
+
return (
|
|
41
|
+
<ProgressPrimitive.Track
|
|
42
|
+
className={cn(
|
|
43
|
+
"block h-1.5 w-full overflow-hidden rounded-full bg-input",
|
|
44
|
+
className,
|
|
45
|
+
)}
|
|
46
|
+
data-slot="progress-track"
|
|
47
|
+
{...props}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function ProgressIndicator({
|
|
53
|
+
className,
|
|
54
|
+
...props
|
|
55
|
+
}: ProgressPrimitive.Indicator.Props) {
|
|
56
|
+
return (
|
|
57
|
+
<ProgressPrimitive.Indicator
|
|
58
|
+
className={cn("bg-primary transition-all duration-500", className)}
|
|
59
|
+
data-slot="progress-indicator"
|
|
60
|
+
{...props}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function ProgressValue({ className, ...props }: ProgressPrimitive.Value.Props) {
|
|
66
|
+
return (
|
|
67
|
+
<ProgressPrimitive.Value
|
|
68
|
+
className={cn("text-sm tabular-nums", className)}
|
|
69
|
+
data-slot="progress-value"
|
|
70
|
+
{...props}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export {
|
|
76
|
+
Progress,
|
|
77
|
+
ProgressLabel,
|
|
78
|
+
ProgressTrack,
|
|
79
|
+
ProgressIndicator,
|
|
80
|
+
ProgressValue,
|
|
81
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Radio as RadioPrimitive } from "@base-ui/react/radio";
|
|
4
|
+
import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group";
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
function RadioGroup({ className, ...props }: RadioGroupPrimitive.Props) {
|
|
9
|
+
return (
|
|
10
|
+
<RadioGroupPrimitive
|
|
11
|
+
className={cn("flex flex-col gap-3", className)}
|
|
12
|
+
data-slot="radio-group"
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function Radio({ className, ...props }: RadioPrimitive.Root.Props) {
|
|
19
|
+
return (
|
|
20
|
+
<RadioPrimitive.Root
|
|
21
|
+
className={cn(
|
|
22
|
+
"relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-full border border-input bg-background not-dark:bg-clip-padding shadow-xs/5 outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-full not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/6%)] focus-visible:ring-2 focus-visible:ring-ring 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",
|
|
23
|
+
className,
|
|
24
|
+
)}
|
|
25
|
+
data-slot="radio"
|
|
26
|
+
{...props}
|
|
27
|
+
>
|
|
28
|
+
<RadioPrimitive.Indicator
|
|
29
|
+
className="-inset-px absolute flex size-4.5 items-center justify-center rounded-full before:size-2 before:rounded-full before:bg-primary-foreground data-unchecked:hidden data-checked:bg-primary sm:size-4 sm:before:size-1.5"
|
|
30
|
+
data-slot="radio-indicator"
|
|
31
|
+
/>
|
|
32
|
+
</RadioPrimitive.Root>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { RadioGroup, Radio, Radio as RadioGroupItem };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
function ScrollArea({
|
|
8
|
+
className,
|
|
9
|
+
children,
|
|
10
|
+
scrollFade = false,
|
|
11
|
+
scrollbarGutter = false,
|
|
12
|
+
...props
|
|
13
|
+
}: ScrollAreaPrimitive.Root.Props & {
|
|
14
|
+
scrollFade?: boolean;
|
|
15
|
+
scrollbarGutter?: boolean;
|
|
16
|
+
}) {
|
|
17
|
+
return (
|
|
18
|
+
<ScrollAreaPrimitive.Root
|
|
19
|
+
className={cn("size-full min-h-0", className)}
|
|
20
|
+
{...props}
|
|
21
|
+
>
|
|
22
|
+
<ScrollAreaPrimitive.Viewport
|
|
23
|
+
className={cn(
|
|
24
|
+
"h-full rounded-[inherit] outline-none transition-shadows focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-has-overflow-x:overscroll-x-contain",
|
|
25
|
+
scrollFade &&
|
|
26
|
+
"mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] [--fade-size:1.5rem]",
|
|
27
|
+
scrollbarGutter &&
|
|
28
|
+
"data-has-overflow-y:pe-2.5 data-has-overflow-x:pb-2.5",
|
|
29
|
+
)}
|
|
30
|
+
data-slot="scroll-area-viewport"
|
|
31
|
+
>
|
|
32
|
+
{children}
|
|
33
|
+
</ScrollAreaPrimitive.Viewport>
|
|
34
|
+
<ScrollBar orientation="vertical" />
|
|
35
|
+
<ScrollBar orientation="horizontal" />
|
|
36
|
+
<ScrollAreaPrimitive.Corner data-slot="scroll-area-corner" />
|
|
37
|
+
</ScrollAreaPrimitive.Root>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function ScrollBar({
|
|
42
|
+
className,
|
|
43
|
+
orientation = "vertical",
|
|
44
|
+
...props
|
|
45
|
+
}: ScrollAreaPrimitive.Scrollbar.Props) {
|
|
46
|
+
return (
|
|
47
|
+
<ScrollAreaPrimitive.Scrollbar
|
|
48
|
+
className={cn(
|
|
49
|
+
"m-1 flex opacity-0 transition-opacity delay-300 data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:w-1.5 data-[orientation=horizontal]:flex-col data-hovering:opacity-100 data-scrolling:opacity-100 data-hovering:delay-0 data-scrolling:delay-0 data-hovering:duration-100 data-scrolling:duration-100",
|
|
50
|
+
className,
|
|
51
|
+
)}
|
|
52
|
+
data-slot="scroll-area-scrollbar"
|
|
53
|
+
orientation={orientation}
|
|
54
|
+
{...props}
|
|
55
|
+
>
|
|
56
|
+
<ScrollAreaPrimitive.Thumb
|
|
57
|
+
className="relative flex-1 rounded-full bg-foreground/20"
|
|
58
|
+
data-slot="scroll-area-thumb"
|
|
59
|
+
/>
|
|
60
|
+
</ScrollAreaPrimitive.Scrollbar>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { ScrollArea, ScrollBar };
|