create-astram-app 0.5.0 → 0.6.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/README.md +211 -38
- package/dist/add-frontend.js.map +1 -1
- package/dist/index.js +14 -9
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/template/README.md +51 -20
- package/template/frontend/README.md +21 -11
- package/template/frontend/index.html +16 -0
- package/template/frontend/package.json +1 -1
- package/template/frontend/src/App.jsx +82 -20
- package/template/frontend/src/auth/AuthContext.jsx +139 -21
- package/template/frontend/src/auth/routeGate.js +31 -0
- package/template/frontend/src/auth/routeGate.test.mjs +59 -0
- package/template/frontend/src/auth/sessionFlow.js +27 -0
- package/template/frontend/src/auth/sessionFlow.test.mjs +63 -0
- package/template/frontend/src/components/EntityList.jsx +1 -7
- package/template/frontend/src/components/PageHeader.jsx +5 -4
- package/template/frontend/src/components/ShareDialog.jsx +3 -5
- package/template/frontend/src/components/access/CollapsibleGroup.jsx +4 -1
- package/template/frontend/src/components/ui/alert-dialog.tsx +27 -50
- package/template/frontend/src/components/ui/alert.tsx +17 -23
- package/template/frontend/src/components/ui/avatar.tsx +8 -20
- package/template/frontend/src/components/ui/badge.tsx +17 -26
- package/template/frontend/src/components/ui/button.tsx +22 -24
- package/template/frontend/src/components/ui/card.tsx +19 -36
- package/template/frontend/src/components/ui/checkbox.tsx +7 -10
- package/template/frontend/src/components/ui/date-field.tsx +26 -27
- package/template/frontend/src/components/ui/dialog.tsx +24 -40
- package/template/frontend/src/components/ui/dropdown-menu.tsx +25 -54
- package/template/frontend/src/components/ui/input-otp.tsx +1 -4
- package/template/frontend/src/components/ui/label.tsx +10 -12
- package/template/frontend/src/components/ui/searchable-select.tsx +1 -3
- package/template/frontend/src/components/ui/select.tsx +31 -43
- package/template/frontend/src/components/ui/separator.tsx +6 -6
- package/template/frontend/src/components/ui/sheet.tsx +29 -38
- package/template/frontend/src/components/ui/skeleton.tsx +3 -3
- package/template/frontend/src/components/ui/sonner.tsx +7 -7
- package/template/frontend/src/components/ui/table.tsx +56 -70
- package/template/frontend/src/components/ui/tooltip.tsx +7 -11
- package/template/frontend/src/config/branding.js +1 -4
- package/template/frontend/src/hooks/useMobile.tsx +4 -6
- package/template/frontend/src/index.css +5 -2
- package/template/frontend/src/pages/Dashboard.jsx +13 -7
- package/template/frontend/src/pages/ForgotPassword.jsx +9 -2
- package/template/frontend/src/pages/Login.jsx +85 -70
- package/template/frontend/src/pages/ResetPassword.jsx +9 -2
- package/template/frontend/src/pages/access/AccessForm.jsx +49 -15
- package/template/frontend/src/pages/access/AccessPage.jsx +10 -6
- package/template/frontend/src/pages/access/RecordPoliciesPage.jsx +9 -2
- package/template/frontend/src/pages/account/AccountLayout.jsx +11 -6
- package/template/frontend/src/pages/account/ChangePasswordPage.jsx +2 -2
- package/template/frontend/src/pages/account/ReenrollPage.jsx +3 -5
- package/template/frontend/src/pages/account/TwoFactorPage.jsx +3 -8
- package/template/frontend/src/pages/companies/CompaniesPage.jsx +7 -9
- package/template/frontend/src/pages/cross-tenant/GrantForm.jsx +41 -8
- package/template/frontend/src/pages/cross-tenant/GrantsPage.jsx +30 -7
- package/template/frontend/src/pages/cross-tenant/InboxPage.jsx +12 -3
- package/template/frontend/src/pages/roles/RolesPage.jsx +5 -9
- package/template/frontend/src/pages/service-accounts/ServiceAccountsPage.jsx +77 -18
- package/template/frontend/src/pages/service-accounts/accessModel.js +22 -0
- package/template/frontend/src/pages/service-accounts/accessModel.test.mjs +28 -0
- package/template/frontend/src/pages/users/MembershipCard.jsx +3 -1
- package/template/frontend/src/pages/users/PostingRow.jsx +8 -14
- package/template/frontend/src/pages/users/UsersPage.jsx +7 -9
- package/template/frontend/src/platform/httpClient.js +5 -0
- package/template/frontend/src/platform/sessionStore.js +55 -13
- package/template/frontend/src/platform/sessionStore.test.mjs +89 -0
- package/template/frontend/src/platform/shieldTransport.js +6 -0
- package/template/frontend/src/platform/shieldTransport.test.mjs +84 -5
- package/template/frontend/src/shell/AppShell.jsx +10 -12
- package/template/frontend/src/shell/Sidebar.jsx +15 -3
- package/template/frontend/src/shell/nav.js +1 -3
- package/template/frontend/vite.config.js +19 -1
- package/template/server/_env.example +22 -1
- package/template/server/eslint.config.mjs +194 -0
- package/template/server/package.json +11 -11
- package/template/server/scripts/dev.mjs +17 -6
- package/template/server/scripts/sync-astram-guide.mjs +45 -19
- package/template/server/src/app.module.ts +11 -5
- package/template/server/src/health/demo.controller.ts +16 -12
- package/template/server/src/main.ts +23 -1
- package/template/server/eslint.config.js +0 -95
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import * as AlertDialogPrimitive from
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
|
|
3
3
|
|
|
4
|
-
import { cn } from
|
|
5
|
-
import { buttonVariants } from
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
|
+
import { buttonVariants } from '@/components/ui/button';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Radix AlertDialog — the semantic confirm primitive (Phase B moves
|
|
@@ -20,9 +20,7 @@ import { buttonVariants } from "@/components/ui/button";
|
|
|
20
20
|
* NOTE: requires `@radix-ui/react-alert-dialog` to be installed.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
function AlertDialog({
|
|
24
|
-
...props
|
|
25
|
-
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
|
|
23
|
+
function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
|
|
26
24
|
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
|
|
27
25
|
}
|
|
28
26
|
|
|
@@ -30,20 +28,12 @@ const AlertDialogTrigger = React.forwardRef<
|
|
|
30
28
|
React.ElementRef<typeof AlertDialogPrimitive.Trigger>,
|
|
31
29
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Trigger>
|
|
32
30
|
>((props, ref) => (
|
|
33
|
-
<AlertDialogPrimitive.Trigger
|
|
34
|
-
ref={ref}
|
|
35
|
-
data-slot="alert-dialog-trigger"
|
|
36
|
-
{...props}
|
|
37
|
-
/>
|
|
31
|
+
<AlertDialogPrimitive.Trigger ref={ref} data-slot="alert-dialog-trigger" {...props} />
|
|
38
32
|
));
|
|
39
|
-
AlertDialogTrigger.displayName =
|
|
33
|
+
AlertDialogTrigger.displayName = 'AlertDialogTrigger';
|
|
40
34
|
|
|
41
|
-
function AlertDialogPortal({
|
|
42
|
-
...props
|
|
43
|
-
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
|
|
44
|
-
return (
|
|
45
|
-
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
|
|
46
|
-
);
|
|
35
|
+
function AlertDialogPortal({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
|
|
36
|
+
return <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />;
|
|
47
37
|
}
|
|
48
38
|
|
|
49
39
|
const AlertDialogOverlay = React.forwardRef<
|
|
@@ -54,13 +44,13 @@ const AlertDialogOverlay = React.forwardRef<
|
|
|
54
44
|
ref={ref}
|
|
55
45
|
data-slot="alert-dialog-overlay"
|
|
56
46
|
className={cn(
|
|
57
|
-
|
|
58
|
-
className
|
|
47
|
+
'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',
|
|
48
|
+
className,
|
|
59
49
|
)}
|
|
60
50
|
{...props}
|
|
61
51
|
/>
|
|
62
52
|
));
|
|
63
|
-
AlertDialogOverlay.displayName =
|
|
53
|
+
AlertDialogOverlay.displayName = 'AlertDialogOverlay';
|
|
64
54
|
|
|
65
55
|
const AlertDialogContent = React.forwardRef<
|
|
66
56
|
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
|
@@ -72,39 +62,30 @@ const AlertDialogContent = React.forwardRef<
|
|
|
72
62
|
ref={ref}
|
|
73
63
|
data-slot="alert-dialog-content"
|
|
74
64
|
className={cn(
|
|
75
|
-
|
|
76
|
-
className
|
|
65
|
+
'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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100vw-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
|
|
66
|
+
className,
|
|
77
67
|
)}
|
|
78
68
|
{...props}
|
|
79
69
|
/>
|
|
80
70
|
</AlertDialogPortal>
|
|
81
71
|
));
|
|
82
|
-
AlertDialogContent.displayName =
|
|
72
|
+
AlertDialogContent.displayName = 'AlertDialogContent';
|
|
83
73
|
|
|
84
|
-
function AlertDialogHeader({
|
|
85
|
-
className,
|
|
86
|
-
...props
|
|
87
|
-
}: React.ComponentProps<"div">) {
|
|
74
|
+
function AlertDialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
88
75
|
return (
|
|
89
76
|
<div
|
|
90
77
|
data-slot="alert-dialog-header"
|
|
91
|
-
className={cn(
|
|
78
|
+
className={cn('flex flex-col gap-2 text-center sm:text-left', className)}
|
|
92
79
|
{...props}
|
|
93
80
|
/>
|
|
94
81
|
);
|
|
95
82
|
}
|
|
96
83
|
|
|
97
|
-
function AlertDialogFooter({
|
|
98
|
-
className,
|
|
99
|
-
...props
|
|
100
|
-
}: React.ComponentProps<"div">) {
|
|
84
|
+
function AlertDialogFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
101
85
|
return (
|
|
102
86
|
<div
|
|
103
87
|
data-slot="alert-dialog-footer"
|
|
104
|
-
className={cn(
|
|
105
|
-
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
106
|
-
className
|
|
107
|
-
)}
|
|
88
|
+
className={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)}
|
|
108
89
|
{...props}
|
|
109
90
|
/>
|
|
110
91
|
);
|
|
@@ -117,11 +98,11 @@ const AlertDialogTitle = React.forwardRef<
|
|
|
117
98
|
<AlertDialogPrimitive.Title
|
|
118
99
|
ref={ref}
|
|
119
100
|
data-slot="alert-dialog-title"
|
|
120
|
-
className={cn(
|
|
101
|
+
className={cn('text-lg leading-none font-semibold', className)}
|
|
121
102
|
{...props}
|
|
122
103
|
/>
|
|
123
104
|
));
|
|
124
|
-
AlertDialogTitle.displayName =
|
|
105
|
+
AlertDialogTitle.displayName = 'AlertDialogTitle';
|
|
125
106
|
|
|
126
107
|
const AlertDialogDescription = React.forwardRef<
|
|
127
108
|
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
|
@@ -130,23 +111,19 @@ const AlertDialogDescription = React.forwardRef<
|
|
|
130
111
|
<AlertDialogPrimitive.Description
|
|
131
112
|
ref={ref}
|
|
132
113
|
data-slot="alert-dialog-description"
|
|
133
|
-
className={cn(
|
|
114
|
+
className={cn('text-muted-foreground text-sm', className)}
|
|
134
115
|
{...props}
|
|
135
116
|
/>
|
|
136
117
|
));
|
|
137
|
-
AlertDialogDescription.displayName =
|
|
118
|
+
AlertDialogDescription.displayName = 'AlertDialogDescription';
|
|
138
119
|
|
|
139
120
|
const AlertDialogAction = React.forwardRef<
|
|
140
121
|
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
|
141
122
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
|
142
123
|
>(({ className, ...props }, ref) => (
|
|
143
|
-
<AlertDialogPrimitive.Action
|
|
144
|
-
ref={ref}
|
|
145
|
-
className={cn(buttonVariants(), className)}
|
|
146
|
-
{...props}
|
|
147
|
-
/>
|
|
124
|
+
<AlertDialogPrimitive.Action ref={ref} className={cn(buttonVariants(), className)} {...props} />
|
|
148
125
|
));
|
|
149
|
-
AlertDialogAction.displayName =
|
|
126
|
+
AlertDialogAction.displayName = 'AlertDialogAction';
|
|
150
127
|
|
|
151
128
|
const AlertDialogCancel = React.forwardRef<
|
|
152
129
|
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
|
@@ -154,11 +131,11 @@ const AlertDialogCancel = React.forwardRef<
|
|
|
154
131
|
>(({ className, ...props }, ref) => (
|
|
155
132
|
<AlertDialogPrimitive.Cancel
|
|
156
133
|
ref={ref}
|
|
157
|
-
className={cn(buttonVariants({ variant:
|
|
134
|
+
className={cn(buttonVariants({ variant: 'outline' }), className)}
|
|
158
135
|
{...props}
|
|
159
136
|
/>
|
|
160
137
|
));
|
|
161
|
-
AlertDialogCancel.displayName =
|
|
138
|
+
AlertDialogCancel.displayName = 'AlertDialogCancel';
|
|
162
139
|
|
|
163
140
|
export {
|
|
164
141
|
AlertDialog,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import { cva, type VariantProps } from
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
3
|
|
|
4
|
-
import { cn } from
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Inline alert / callout — the shared replacement for the ~8 ad-hoc
|
|
@@ -16,31 +16,31 @@ import { cn } from "@/lib/utils";
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
const alertVariants = cva(
|
|
19
|
-
|
|
19
|
+
'relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5',
|
|
20
20
|
{
|
|
21
21
|
variants: {
|
|
22
22
|
variant: {
|
|
23
|
-
default:
|
|
23
|
+
default: 'bg-card text-card-foreground border-border [&>svg]:text-foreground',
|
|
24
24
|
destructive:
|
|
25
|
-
|
|
25
|
+
'border-destructive/30 bg-destructive/10 text-destructive [&>svg]:text-destructive [&_[data-slot=alert-description]]:text-destructive/90',
|
|
26
26
|
warning:
|
|
27
|
-
|
|
27
|
+
'border-warn/30 bg-warn/10 text-warn [&>svg]:text-warn [&_[data-slot=alert-description]]:text-warn/90',
|
|
28
28
|
success:
|
|
29
|
-
|
|
30
|
-
info:
|
|
29
|
+
'border-ok/30 bg-ok/10 text-ok [&>svg]:text-ok [&_[data-slot=alert-description]]:text-ok/90',
|
|
30
|
+
info: 'border-primary/30 bg-primary/10 text-primary [&>svg]:text-primary [&_[data-slot=alert-description]]:text-primary/90',
|
|
31
31
|
},
|
|
32
32
|
},
|
|
33
33
|
defaultVariants: {
|
|
34
|
-
variant:
|
|
34
|
+
variant: 'default',
|
|
35
35
|
},
|
|
36
|
-
}
|
|
36
|
+
},
|
|
37
37
|
);
|
|
38
38
|
|
|
39
39
|
function Alert({
|
|
40
40
|
className,
|
|
41
41
|
variant,
|
|
42
42
|
...props
|
|
43
|
-
}: React.ComponentProps<
|
|
43
|
+
}: React.ComponentProps<'div'> & VariantProps<typeof alertVariants>) {
|
|
44
44
|
return (
|
|
45
45
|
<div
|
|
46
46
|
data-slot="alert"
|
|
@@ -51,29 +51,23 @@ function Alert({
|
|
|
51
51
|
);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
function AlertTitle({ className, ...props }: React.ComponentProps<
|
|
54
|
+
function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
55
55
|
return (
|
|
56
56
|
<div
|
|
57
57
|
data-slot="alert-title"
|
|
58
|
-
className={cn(
|
|
59
|
-
"col-start-2 line-clamp-1 min-h-4 font-semibold tracking-tight",
|
|
60
|
-
className
|
|
61
|
-
)}
|
|
58
|
+
className={cn('col-start-2 line-clamp-1 min-h-4 font-semibold tracking-tight', className)}
|
|
62
59
|
{...props}
|
|
63
60
|
/>
|
|
64
61
|
);
|
|
65
62
|
}
|
|
66
63
|
|
|
67
|
-
function AlertDescription({
|
|
68
|
-
className,
|
|
69
|
-
...props
|
|
70
|
-
}: React.ComponentProps<"div">) {
|
|
64
|
+
function AlertDescription({ className, ...props }: React.ComponentProps<'div'>) {
|
|
71
65
|
return (
|
|
72
66
|
<div
|
|
73
67
|
data-slot="alert-description"
|
|
74
68
|
className={cn(
|
|
75
|
-
|
|
76
|
-
className
|
|
69
|
+
'text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed',
|
|
70
|
+
className,
|
|
77
71
|
)}
|
|
78
72
|
{...props}
|
|
79
73
|
/>
|
|
@@ -1,32 +1,23 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import * as AvatarPrimitive from
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
|
3
3
|
|
|
4
|
-
import { cn } from
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
5
|
|
|
6
|
-
function Avatar({
|
|
7
|
-
className,
|
|
8
|
-
...props
|
|
9
|
-
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
|
6
|
+
function Avatar({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
|
10
7
|
return (
|
|
11
8
|
<AvatarPrimitive.Root
|
|
12
9
|
data-slot="avatar"
|
|
13
|
-
className={cn(
|
|
14
|
-
"relative flex size-8 shrink-0 overflow-hidden rounded-full",
|
|
15
|
-
className
|
|
16
|
-
)}
|
|
10
|
+
className={cn('relative flex size-8 shrink-0 overflow-hidden rounded-full', className)}
|
|
17
11
|
{...props}
|
|
18
12
|
/>
|
|
19
13
|
);
|
|
20
14
|
}
|
|
21
15
|
|
|
22
|
-
function AvatarImage({
|
|
23
|
-
className,
|
|
24
|
-
...props
|
|
25
|
-
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
|
16
|
+
function AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
|
26
17
|
return (
|
|
27
18
|
<AvatarPrimitive.Image
|
|
28
19
|
data-slot="avatar-image"
|
|
29
|
-
className={cn(
|
|
20
|
+
className={cn('aspect-square size-full', className)}
|
|
30
21
|
{...props}
|
|
31
22
|
/>
|
|
32
23
|
);
|
|
@@ -39,10 +30,7 @@ function AvatarFallback({
|
|
|
39
30
|
return (
|
|
40
31
|
<AvatarPrimitive.Fallback
|
|
41
32
|
data-slot="avatar-fallback"
|
|
42
|
-
className={cn(
|
|
43
|
-
"bg-muted flex size-full items-center justify-center rounded-full",
|
|
44
|
-
className
|
|
45
|
-
)}
|
|
33
|
+
className={cn('bg-muted flex size-full items-center justify-center rounded-full', className)}
|
|
46
34
|
{...props}
|
|
47
35
|
/>
|
|
48
36
|
);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import { Slot } from
|
|
3
|
-
import { cva, type VariantProps } from
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
|
-
import { cn } from
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
6
|
|
|
7
7
|
// Pill shape (`rounded-full`) + OCA's `.dsa-badge` density (.72rem-ish text,
|
|
8
8
|
// weight 600, 3px/10px padding). Existing solid variants kept intact; the new
|
|
@@ -10,29 +10,25 @@ import { cn } from "@/lib/utils";
|
|
|
10
10
|
// same-family colored text (OCA's tint-bg + colored-label treatment), driven by
|
|
11
11
|
// `--ok` / `--warn` / `--primary` so light + dark both read correctly.
|
|
12
12
|
const badgeVariants = cva(
|
|
13
|
-
|
|
13
|
+
'inline-flex items-center justify-center rounded-full border px-2.5 py-0.5 text-xs font-semibold 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',
|
|
14
14
|
{
|
|
15
15
|
variants: {
|
|
16
16
|
variant: {
|
|
17
|
-
default:
|
|
18
|
-
"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
17
|
+
default: 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
|
|
19
18
|
secondary:
|
|
20
|
-
|
|
19
|
+
'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
|
|
21
20
|
destructive:
|
|
22
|
-
|
|
23
|
-
outline:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
warning:
|
|
28
|
-
"border-transparent bg-warn/15 text-warn [a&]:hover:bg-warn/20",
|
|
29
|
-
info: "border-transparent bg-primary/15 text-primary [a&]:hover:bg-primary/20",
|
|
21
|
+
'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
|
|
22
|
+
outline: 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
|
|
23
|
+
success: 'border-transparent bg-ok/15 text-ok [a&]:hover:bg-ok/20',
|
|
24
|
+
warning: 'border-transparent bg-warn/15 text-warn [a&]:hover:bg-warn/20',
|
|
25
|
+
info: 'border-transparent bg-primary/15 text-primary [a&]:hover:bg-primary/20',
|
|
30
26
|
},
|
|
31
27
|
},
|
|
32
28
|
defaultVariants: {
|
|
33
|
-
variant:
|
|
29
|
+
variant: 'default',
|
|
34
30
|
},
|
|
35
|
-
}
|
|
31
|
+
},
|
|
36
32
|
);
|
|
37
33
|
|
|
38
34
|
function Badge({
|
|
@@ -40,16 +36,11 @@ function Badge({
|
|
|
40
36
|
variant,
|
|
41
37
|
asChild = false,
|
|
42
38
|
...props
|
|
43
|
-
}: React.ComponentProps<
|
|
44
|
-
|
|
45
|
-
const Comp = asChild ? Slot : "span";
|
|
39
|
+
}: React.ComponentProps<'span'> & VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
|
40
|
+
const Comp = asChild ? Slot : 'span';
|
|
46
41
|
|
|
47
42
|
return (
|
|
48
|
-
<Comp
|
|
49
|
-
data-slot="badge"
|
|
50
|
-
className={cn(badgeVariants({ variant }), className)}
|
|
51
|
-
{...props}
|
|
52
|
-
/>
|
|
43
|
+
<Comp data-slot="badge" className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
53
44
|
);
|
|
54
45
|
}
|
|
55
46
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import { Slot } from
|
|
3
|
-
import { cva, type VariantProps } from
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
|
-
import { cn } from
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
6
|
|
|
7
7
|
const buttonVariants = cva(
|
|
8
8
|
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-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",
|
|
@@ -13,34 +13,32 @@ const buttonVariants = cva(
|
|
|
13
13
|
// depth (a crisp `shadow-sm` in light; the dark `.dark [data-slot=button].bg-primary`
|
|
14
14
|
// rule in index.css supplies the top-light inset + brand glow in dark),
|
|
15
15
|
// so it reads as a raised, saturated control rather than a flat swatch.
|
|
16
|
-
default:
|
|
16
|
+
default: 'bg-primary text-primary-foreground shadow-sm hover:bg-primary/90',
|
|
17
17
|
destructive:
|
|
18
|
-
|
|
18
|
+
'bg-destructive text-white shadow-sm hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
|
|
19
19
|
outline:
|
|
20
|
-
|
|
21
|
-
secondary:
|
|
22
|
-
|
|
23
|
-
ghost:
|
|
24
|
-
"hover:bg-accent dark:hover:bg-accent/50",
|
|
20
|
+
'border bg-transparent shadow-xs hover:bg-accent dark:bg-transparent dark:border-input dark:hover:bg-input/50',
|
|
21
|
+
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
22
|
+
ghost: 'hover:bg-accent dark:hover:bg-accent/50',
|
|
25
23
|
// Tonal button (OCA `.oca-btn--soft-primary`): a brand-tinted fill with
|
|
26
24
|
// brand-colored text — a lighter-weight primary for secondary actions.
|
|
27
|
-
soft:
|
|
28
|
-
link:
|
|
25
|
+
soft: 'bg-primary/10 text-primary hover:bg-primary/15',
|
|
26
|
+
link: 'text-primary underline-offset-4 hover:underline',
|
|
29
27
|
},
|
|
30
28
|
size: {
|
|
31
|
-
default:
|
|
32
|
-
sm:
|
|
33
|
-
lg:
|
|
34
|
-
icon:
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
|
|
30
|
+
sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
|
|
31
|
+
lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
|
|
32
|
+
icon: 'size-9',
|
|
33
|
+
'icon-sm': 'size-8',
|
|
34
|
+
'icon-lg': 'size-10',
|
|
37
35
|
},
|
|
38
36
|
},
|
|
39
37
|
defaultVariants: {
|
|
40
|
-
variant:
|
|
41
|
-
size:
|
|
38
|
+
variant: 'default',
|
|
39
|
+
size: 'default',
|
|
42
40
|
},
|
|
43
|
-
}
|
|
41
|
+
},
|
|
44
42
|
);
|
|
45
43
|
|
|
46
44
|
function Button({
|
|
@@ -49,11 +47,11 @@ function Button({
|
|
|
49
47
|
size,
|
|
50
48
|
asChild = false,
|
|
51
49
|
...props
|
|
52
|
-
}: React.ComponentProps<
|
|
50
|
+
}: React.ComponentProps<'button'> &
|
|
53
51
|
VariantProps<typeof buttonVariants> & {
|
|
54
52
|
asChild?: boolean;
|
|
55
53
|
}) {
|
|
56
|
-
const Comp = asChild ? Slot :
|
|
54
|
+
const Comp = asChild ? Slot : 'button';
|
|
57
55
|
|
|
58
56
|
return (
|
|
59
57
|
<Comp
|
|
@@ -1,92 +1,75 @@
|
|
|
1
|
-
import * as React from
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
import { cn } from
|
|
3
|
+
import { cn } from '@/lib/utils';
|
|
4
4
|
|
|
5
|
-
function Card({ className, ...props }: React.ComponentProps<
|
|
5
|
+
function Card({ className, ...props }: React.ComponentProps<'div'>) {
|
|
6
6
|
return (
|
|
7
7
|
<div
|
|
8
8
|
data-slot="card"
|
|
9
9
|
className={cn(
|
|
10
|
-
|
|
11
|
-
className
|
|
10
|
+
'bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
|
|
11
|
+
className,
|
|
12
12
|
)}
|
|
13
13
|
{...props}
|
|
14
14
|
/>
|
|
15
15
|
);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
function CardHeader({ className, ...props }: React.ComponentProps<
|
|
18
|
+
function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
19
19
|
return (
|
|
20
20
|
<div
|
|
21
21
|
data-slot="card-header"
|
|
22
22
|
className={cn(
|
|
23
|
-
|
|
24
|
-
className
|
|
23
|
+
'@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
|
|
24
|
+
className,
|
|
25
25
|
)}
|
|
26
26
|
{...props}
|
|
27
27
|
/>
|
|
28
28
|
);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function CardTitle({ className, ...props }: React.ComponentProps<
|
|
31
|
+
function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
32
32
|
return (
|
|
33
33
|
<div
|
|
34
34
|
data-slot="card-title"
|
|
35
|
-
className={cn(
|
|
35
|
+
className={cn('leading-none font-semibold', className)}
|
|
36
36
|
{...props}
|
|
37
37
|
/>
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function CardDescription({ className, ...props }: React.ComponentProps<
|
|
41
|
+
function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
|
|
42
42
|
return (
|
|
43
43
|
<div
|
|
44
44
|
data-slot="card-description"
|
|
45
|
-
className={cn(
|
|
45
|
+
className={cn('text-muted-foreground text-sm', className)}
|
|
46
46
|
{...props}
|
|
47
47
|
/>
|
|
48
48
|
);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
function CardAction({ className, ...props }: React.ComponentProps<
|
|
51
|
+
function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
|
|
52
52
|
return (
|
|
53
53
|
<div
|
|
54
54
|
data-slot="card-action"
|
|
55
|
-
className={cn(
|
|
56
|
-
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
|
57
|
-
className
|
|
58
|
-
)}
|
|
55
|
+
className={cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', className)}
|
|
59
56
|
{...props}
|
|
60
57
|
/>
|
|
61
58
|
);
|
|
62
59
|
}
|
|
63
60
|
|
|
64
|
-
function CardContent({ className, ...props }: React.ComponentProps<
|
|
65
|
-
return (
|
|
66
|
-
<div
|
|
67
|
-
data-slot="card-content"
|
|
68
|
-
className={cn("px-6", className)}
|
|
69
|
-
{...props}
|
|
70
|
-
/>
|
|
71
|
-
);
|
|
61
|
+
function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
62
|
+
return <div data-slot="card-content" className={cn('px-6', className)} {...props} />;
|
|
72
63
|
}
|
|
73
64
|
|
|
74
|
-
function CardFooter({ className, ...props }: React.ComponentProps<
|
|
65
|
+
function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
75
66
|
return (
|
|
76
67
|
<div
|
|
77
68
|
data-slot="card-footer"
|
|
78
|
-
className={cn(
|
|
69
|
+
className={cn('flex items-center px-6 [.border-t]:pt-6', className)}
|
|
79
70
|
{...props}
|
|
80
71
|
/>
|
|
81
72
|
);
|
|
82
73
|
}
|
|
83
74
|
|
|
84
|
-
export {
|
|
85
|
-
Card,
|
|
86
|
-
CardHeader,
|
|
87
|
-
CardFooter,
|
|
88
|
-
CardTitle,
|
|
89
|
-
CardAction,
|
|
90
|
-
CardDescription,
|
|
91
|
-
CardContent,
|
|
92
|
-
};
|
|
75
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent };
|
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import * as CheckboxPrimitive from
|
|
3
|
-
import { CheckIcon } from
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
3
|
+
import { CheckIcon } from 'lucide-react';
|
|
4
4
|
|
|
5
|
-
import { cn } from
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
6
|
|
|
7
|
-
function Checkbox({
|
|
8
|
-
className,
|
|
9
|
-
...props
|
|
10
|
-
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
|
|
7
|
+
function Checkbox({ className, ...props }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
|
|
11
8
|
return (
|
|
12
9
|
<CheckboxPrimitive.Root
|
|
13
10
|
data-slot="checkbox"
|
|
14
11
|
className={cn(
|
|
15
|
-
|
|
16
|
-
className
|
|
12
|
+
'peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
|
|
13
|
+
className,
|
|
17
14
|
)}
|
|
18
15
|
{...props}
|
|
19
16
|
>
|