@greatapps/greatchat-ui 0.1.5 → 0.2.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.d.ts +106 -5
- package/dist/index.js +1787 -1116
- package/dist/index.js.map +1 -1
- package/package.json +17 -13
- package/src/components/channel-card.tsx +1 -1
- package/src/components/channel-create-dialog.tsx +126 -0
- package/src/components/channel-edit-dialog.tsx +132 -0
- package/src/components/channels-page.tsx +242 -0
- package/src/components/chat-dashboard.tsx +433 -0
- package/src/components/chat-input.tsx +1 -2
- package/src/components/chat-view.tsx +1 -8
- package/src/components/contact-avatar.tsx +1 -2
- package/src/components/contact-form-dialog.tsx +139 -0
- package/src/components/contact-info-panel.tsx +1 -4
- package/src/components/contacts-page.tsx +41 -0
- package/src/components/contacts-table.tsx +216 -0
- package/src/components/data-table.tsx +185 -0
- package/src/components/inbox-item.tsx +6 -4
- package/src/components/inbox-page.tsx +167 -0
- package/src/components/inbox-sidebar.tsx +1 -5
- package/src/components/message-bubble.tsx +4 -6
- package/src/components/new-conversation-dialog.tsx +2 -6
- package/src/components/whatsapp-icon.tsx +21 -0
- package/src/components/whatsapp-qr-dialog.tsx +147 -0
- package/src/components/whatsapp-status-badge.tsx +1 -1
- package/src/index.ts +37 -2
- package/src/components/ui/alert-dialog.tsx +0 -167
- package/src/components/ui/avatar.tsx +0 -51
- package/src/components/ui/badge.tsx +0 -44
- package/src/components/ui/button.tsx +0 -62
- package/src/components/ui/command.tsx +0 -106
- package/src/components/ui/dialog.tsx +0 -133
- package/src/components/ui/dropdown-menu.tsx +0 -173
- package/src/components/ui/input.tsx +0 -19
- package/src/components/ui/scroll-area.tsx +0 -50
- package/src/components/ui/select.tsx +0 -156
- package/src/components/ui/separator.tsx +0 -26
- package/src/components/ui/skeleton.tsx +0 -16
- package/src/components/ui/tabs.tsx +0 -64
- package/src/components/ui/textarea.tsx +0 -18
- package/src/components/ui/tooltip.tsx +0 -58
- package/src/lib/utils.ts +0 -6
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState, useCallback } from "react";
|
|
4
|
+
import type { GchatHookConfig } from "../hooks/types";
|
|
5
|
+
import { useConnectChannel, useChannelQR, useChannelWhatsappStatus } from "../hooks/use-channels";
|
|
6
|
+
import {
|
|
7
|
+
Dialog,
|
|
8
|
+
DialogContent,
|
|
9
|
+
DialogHeader,
|
|
10
|
+
DialogTitle,
|
|
11
|
+
DialogDescription,
|
|
12
|
+
Button,
|
|
13
|
+
} from "@greatapps/greatauth-ui/ui";
|
|
14
|
+
import { Loader2, Check, AlertCircle, RefreshCw } from "lucide-react";
|
|
15
|
+
import { toast } from "sonner";
|
|
16
|
+
|
|
17
|
+
type QRState = "connecting" | "waiting_qr" | "showing_qr" | "connected" | "error";
|
|
18
|
+
|
|
19
|
+
export interface WhatsappQrDialogProps {
|
|
20
|
+
open: boolean;
|
|
21
|
+
onOpenChange: (open: boolean) => void;
|
|
22
|
+
channelId: number;
|
|
23
|
+
config: GchatHookConfig;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function WhatsappQrDialog({
|
|
27
|
+
open,
|
|
28
|
+
onOpenChange,
|
|
29
|
+
channelId,
|
|
30
|
+
config,
|
|
31
|
+
}: WhatsappQrDialogProps) {
|
|
32
|
+
const connectChannel = useConnectChannel(config);
|
|
33
|
+
const [state, setState] = useState<QRState>("connecting");
|
|
34
|
+
const [errorMsg, setErrorMsg] = useState("");
|
|
35
|
+
|
|
36
|
+
const { data: qrUrl } = useChannelQR(
|
|
37
|
+
config,
|
|
38
|
+
channelId,
|
|
39
|
+
open && (state === "waiting_qr" || state === "showing_qr"),
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const { data: status } = useChannelWhatsappStatus(
|
|
43
|
+
config,
|
|
44
|
+
channelId,
|
|
45
|
+
open && state !== "connected",
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const startConnect = useCallback(() => {
|
|
49
|
+
setState("connecting");
|
|
50
|
+
setErrorMsg("");
|
|
51
|
+
connectChannel.mutate(channelId, {
|
|
52
|
+
onSuccess: () => setState("waiting_qr"),
|
|
53
|
+
onError: (err) => {
|
|
54
|
+
setState("error");
|
|
55
|
+
setErrorMsg(err.message || "Erro ao conectar");
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}, [channelId, connectChannel]);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (!open) {
|
|
62
|
+
setState("connecting");
|
|
63
|
+
setErrorMsg("");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
startConnect();
|
|
67
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
68
|
+
}, [open, channelId]);
|
|
69
|
+
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
if (qrUrl && (state === "waiting_qr" || state === "showing_qr")) {
|
|
72
|
+
setState("showing_qr");
|
|
73
|
+
}
|
|
74
|
+
}, [qrUrl, state]);
|
|
75
|
+
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
if (status?.connected && status?.logged_in) {
|
|
78
|
+
setState("connected");
|
|
79
|
+
toast.success("WhatsApp conectado com sucesso!");
|
|
80
|
+
setTimeout(() => onOpenChange(false), 1500);
|
|
81
|
+
}
|
|
82
|
+
}, [status, onOpenChange]);
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
86
|
+
<DialogContent className="sm:max-w-md">
|
|
87
|
+
<DialogHeader>
|
|
88
|
+
<DialogTitle>Conectar WhatsApp</DialogTitle>
|
|
89
|
+
<DialogDescription>
|
|
90
|
+
Escaneie o QR code com seu WhatsApp para conectar
|
|
91
|
+
</DialogDescription>
|
|
92
|
+
</DialogHeader>
|
|
93
|
+
|
|
94
|
+
<div className="flex min-h-[300px] items-center justify-center">
|
|
95
|
+
{state === "connecting" && (
|
|
96
|
+
<div className="flex flex-col items-center gap-3 text-muted-foreground">
|
|
97
|
+
<Loader2 className="h-8 w-8 animate-spin" />
|
|
98
|
+
<p className="text-sm">Iniciando conexão...</p>
|
|
99
|
+
</div>
|
|
100
|
+
)}
|
|
101
|
+
|
|
102
|
+
{state === "waiting_qr" && (
|
|
103
|
+
<div className="flex flex-col items-center gap-3 text-muted-foreground">
|
|
104
|
+
<Loader2 className="h-8 w-8 animate-spin" />
|
|
105
|
+
<p className="text-sm">Gerando QR code...</p>
|
|
106
|
+
</div>
|
|
107
|
+
)}
|
|
108
|
+
|
|
109
|
+
{state === "showing_qr" && qrUrl && (
|
|
110
|
+
<div className="flex flex-col items-center gap-3">
|
|
111
|
+
<img
|
|
112
|
+
src={qrUrl}
|
|
113
|
+
alt="QR Code WhatsApp"
|
|
114
|
+
className="h-64 w-64 rounded-lg border"
|
|
115
|
+
/>
|
|
116
|
+
<p className="text-sm text-muted-foreground">
|
|
117
|
+
Abra o WhatsApp > Aparelhos conectados > Conectar
|
|
118
|
+
</p>
|
|
119
|
+
</div>
|
|
120
|
+
)}
|
|
121
|
+
|
|
122
|
+
{state === "connected" && (
|
|
123
|
+
<div className="flex flex-col items-center gap-3 text-green-600">
|
|
124
|
+
<Check className="h-12 w-12" />
|
|
125
|
+
<p className="text-lg font-medium">Conectado!</p>
|
|
126
|
+
</div>
|
|
127
|
+
)}
|
|
128
|
+
|
|
129
|
+
{state === "error" && (
|
|
130
|
+
<div className="flex flex-col items-center gap-3 text-destructive">
|
|
131
|
+
<AlertCircle className="h-8 w-8" />
|
|
132
|
+
<p className="text-sm">{errorMsg || "Erro ao gerar QR code"}</p>
|
|
133
|
+
<Button
|
|
134
|
+
variant="outline"
|
|
135
|
+
size="sm"
|
|
136
|
+
onClick={startConnect}
|
|
137
|
+
>
|
|
138
|
+
<RefreshCw className="mr-2 h-4 w-4" />
|
|
139
|
+
Tentar novamente
|
|
140
|
+
</Button>
|
|
141
|
+
</div>
|
|
142
|
+
)}
|
|
143
|
+
</div>
|
|
144
|
+
</DialogContent>
|
|
145
|
+
</Dialog>
|
|
146
|
+
);
|
|
147
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -15,13 +15,13 @@ export { createGchatClient } from "./client";
|
|
|
15
15
|
export type { GchatClientConfig } from "./client";
|
|
16
16
|
|
|
17
17
|
// Utils
|
|
18
|
-
export { cn } from "
|
|
18
|
+
export { cn } from "@greatapps/greatauth-ui/ui";
|
|
19
19
|
export { groupMessagesByDate, formatDateGroup, formatMessageTime } from "./utils";
|
|
20
20
|
|
|
21
21
|
// Hooks
|
|
22
22
|
export * from "./hooks";
|
|
23
23
|
|
|
24
|
-
// Components
|
|
24
|
+
// Base Components
|
|
25
25
|
export {
|
|
26
26
|
ChatView,
|
|
27
27
|
ChatInput,
|
|
@@ -46,3 +46,38 @@ export type {
|
|
|
46
46
|
ChannelCardProps,
|
|
47
47
|
WhatsappStatusBadgeProps,
|
|
48
48
|
} from "./components";
|
|
49
|
+
|
|
50
|
+
// Icons
|
|
51
|
+
export { WhatsappIcon } from "./components/whatsapp-icon";
|
|
52
|
+
|
|
53
|
+
// Dialogs & Forms
|
|
54
|
+
export { WhatsappQrDialog } from "./components/whatsapp-qr-dialog";
|
|
55
|
+
export type { WhatsappQrDialogProps } from "./components/whatsapp-qr-dialog";
|
|
56
|
+
|
|
57
|
+
export { ChannelCreateDialog } from "./components/channel-create-dialog";
|
|
58
|
+
export type { ChannelCreateDialogProps } from "./components/channel-create-dialog";
|
|
59
|
+
|
|
60
|
+
export { ChannelEditDialog } from "./components/channel-edit-dialog";
|
|
61
|
+
export type { ChannelEditDialogProps } from "./components/channel-edit-dialog";
|
|
62
|
+
|
|
63
|
+
export { ContactFormDialog } from "./components/contact-form-dialog";
|
|
64
|
+
export type { ContactFormDialogProps } from "./components/contact-form-dialog";
|
|
65
|
+
|
|
66
|
+
export { ContactsTable } from "./components/contacts-table";
|
|
67
|
+
export type { ContactsTableProps } from "./components/contacts-table";
|
|
68
|
+
|
|
69
|
+
export { DataTable } from "./components/data-table";
|
|
70
|
+
export type { DataTableProps } from "./components/data-table";
|
|
71
|
+
|
|
72
|
+
// Page Compositions
|
|
73
|
+
export { InboxPage } from "./components/inbox-page";
|
|
74
|
+
export type { InboxPageProps } from "./components/inbox-page";
|
|
75
|
+
|
|
76
|
+
export { ChannelsPage } from "./components/channels-page";
|
|
77
|
+
export type { ChannelsPageProps } from "./components/channels-page";
|
|
78
|
+
|
|
79
|
+
export { ContactsPage } from "./components/contacts-page";
|
|
80
|
+
export type { ContactsPageProps } from "./components/contacts-page";
|
|
81
|
+
|
|
82
|
+
export { ChatDashboard } from "./components/chat-dashboard";
|
|
83
|
+
export type { ChatDashboardProps } from "./components/chat-dashboard";
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { AlertDialog as AlertDialogPrimitive } from "radix-ui";
|
|
3
|
-
|
|
4
|
-
import { cn } from "../../lib/utils";
|
|
5
|
-
import { Button } from "./button";
|
|
6
|
-
|
|
7
|
-
function AlertDialog({
|
|
8
|
-
...props
|
|
9
|
-
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
|
|
10
|
-
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function AlertDialogTrigger({
|
|
14
|
-
...props
|
|
15
|
-
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
|
|
16
|
-
return (
|
|
17
|
-
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function AlertDialogPortal({
|
|
22
|
-
...props
|
|
23
|
-
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
|
|
24
|
-
return (
|
|
25
|
-
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function AlertDialogOverlay({
|
|
30
|
-
className,
|
|
31
|
-
...props
|
|
32
|
-
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
|
|
33
|
-
return (
|
|
34
|
-
<AlertDialogPrimitive.Overlay
|
|
35
|
-
data-slot="alert-dialog-overlay"
|
|
36
|
-
className={cn(
|
|
37
|
-
"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50",
|
|
38
|
-
className,
|
|
39
|
-
)}
|
|
40
|
-
{...props}
|
|
41
|
-
/>
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function AlertDialogContent({
|
|
46
|
-
className,
|
|
47
|
-
...props
|
|
48
|
-
}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
|
|
49
|
-
return (
|
|
50
|
-
<AlertDialogPortal>
|
|
51
|
-
<AlertDialogOverlay />
|
|
52
|
-
<AlertDialogPrimitive.Content
|
|
53
|
-
data-slot="alert-dialog-content"
|
|
54
|
-
className={cn(
|
|
55
|
-
"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 bg-background ring-foreground/10 gap-6 rounded-xl p-6 ring-1 duration-100 sm:max-w-lg fixed top-1/2 left-1/2 z-50 grid w-full max-w-xs -translate-x-1/2 -translate-y-1/2 outline-none",
|
|
56
|
-
className,
|
|
57
|
-
)}
|
|
58
|
-
{...props}
|
|
59
|
-
/>
|
|
60
|
-
</AlertDialogPortal>
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function AlertDialogHeader({
|
|
65
|
-
className,
|
|
66
|
-
...props
|
|
67
|
-
}: React.ComponentProps<"div">) {
|
|
68
|
-
return (
|
|
69
|
-
<div
|
|
70
|
-
data-slot="alert-dialog-header"
|
|
71
|
-
className={cn("grid gap-1.5 text-center sm:text-left", className)}
|
|
72
|
-
{...props}
|
|
73
|
-
/>
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function AlertDialogFooter({
|
|
78
|
-
className,
|
|
79
|
-
...props
|
|
80
|
-
}: React.ComponentProps<"div">) {
|
|
81
|
-
return (
|
|
82
|
-
<div
|
|
83
|
-
data-slot="alert-dialog-footer"
|
|
84
|
-
className={cn(
|
|
85
|
-
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
86
|
-
className,
|
|
87
|
-
)}
|
|
88
|
-
{...props}
|
|
89
|
-
/>
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function AlertDialogTitle({
|
|
94
|
-
className,
|
|
95
|
-
...props
|
|
96
|
-
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
|
|
97
|
-
return (
|
|
98
|
-
<AlertDialogPrimitive.Title
|
|
99
|
-
data-slot="alert-dialog-title"
|
|
100
|
-
className={cn("text-lg font-medium", className)}
|
|
101
|
-
{...props}
|
|
102
|
-
/>
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function AlertDialogDescription({
|
|
107
|
-
className,
|
|
108
|
-
...props
|
|
109
|
-
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
|
|
110
|
-
return (
|
|
111
|
-
<AlertDialogPrimitive.Description
|
|
112
|
-
data-slot="alert-dialog-description"
|
|
113
|
-
className={cn("text-muted-foreground text-sm", className)}
|
|
114
|
-
{...props}
|
|
115
|
-
/>
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function AlertDialogAction({
|
|
120
|
-
className,
|
|
121
|
-
variant = "default",
|
|
122
|
-
size = "default",
|
|
123
|
-
...props
|
|
124
|
-
}: React.ComponentProps<typeof AlertDialogPrimitive.Action> &
|
|
125
|
-
Partial<Pick<React.ComponentProps<typeof Button>, "variant" | "size">>) {
|
|
126
|
-
return (
|
|
127
|
-
<Button variant={variant} size={size} asChild>
|
|
128
|
-
<AlertDialogPrimitive.Action
|
|
129
|
-
data-slot="alert-dialog-action"
|
|
130
|
-
className={cn(className)}
|
|
131
|
-
{...props}
|
|
132
|
-
/>
|
|
133
|
-
</Button>
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function AlertDialogCancel({
|
|
138
|
-
className,
|
|
139
|
-
variant = "outline",
|
|
140
|
-
size = "default",
|
|
141
|
-
...props
|
|
142
|
-
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &
|
|
143
|
-
Partial<Pick<React.ComponentProps<typeof Button>, "variant" | "size">>) {
|
|
144
|
-
return (
|
|
145
|
-
<Button variant={variant} size={size} asChild>
|
|
146
|
-
<AlertDialogPrimitive.Cancel
|
|
147
|
-
data-slot="alert-dialog-cancel"
|
|
148
|
-
className={cn(className)}
|
|
149
|
-
{...props}
|
|
150
|
-
/>
|
|
151
|
-
</Button>
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export {
|
|
156
|
-
AlertDialog,
|
|
157
|
-
AlertDialogAction,
|
|
158
|
-
AlertDialogCancel,
|
|
159
|
-
AlertDialogContent,
|
|
160
|
-
AlertDialogDescription,
|
|
161
|
-
AlertDialogFooter,
|
|
162
|
-
AlertDialogHeader,
|
|
163
|
-
AlertDialogOverlay,
|
|
164
|
-
AlertDialogPortal,
|
|
165
|
-
AlertDialogTitle,
|
|
166
|
-
AlertDialogTrigger,
|
|
167
|
-
};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { Avatar as AvatarPrimitive } from "radix-ui";
|
|
3
|
-
|
|
4
|
-
import { cn } from "../../lib/utils";
|
|
5
|
-
|
|
6
|
-
function Avatar({
|
|
7
|
-
className,
|
|
8
|
-
...props
|
|
9
|
-
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
|
10
|
-
return (
|
|
11
|
-
<AvatarPrimitive.Root
|
|
12
|
-
data-slot="avatar"
|
|
13
|
-
className={cn(
|
|
14
|
-
"relative flex size-8 shrink-0 overflow-hidden rounded-full",
|
|
15
|
-
className,
|
|
16
|
-
)}
|
|
17
|
-
{...props}
|
|
18
|
-
/>
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function AvatarImage({
|
|
23
|
-
className,
|
|
24
|
-
...props
|
|
25
|
-
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
|
26
|
-
return (
|
|
27
|
-
<AvatarPrimitive.Image
|
|
28
|
-
data-slot="avatar-image"
|
|
29
|
-
className={cn("aspect-square size-full", className)}
|
|
30
|
-
{...props}
|
|
31
|
-
/>
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function AvatarFallback({
|
|
36
|
-
className,
|
|
37
|
-
...props
|
|
38
|
-
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
|
39
|
-
return (
|
|
40
|
-
<AvatarPrimitive.Fallback
|
|
41
|
-
data-slot="avatar-fallback"
|
|
42
|
-
className={cn(
|
|
43
|
-
"flex size-full items-center justify-center rounded-full bg-muted",
|
|
44
|
-
className,
|
|
45
|
-
)}
|
|
46
|
-
{...props}
|
|
47
|
-
/>
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export { Avatar, AvatarImage, AvatarFallback };
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
-
import { Slot } from "radix-ui";
|
|
4
|
-
|
|
5
|
-
import { cn } from "../../lib/utils";
|
|
6
|
-
|
|
7
|
-
const badgeVariants = cva(
|
|
8
|
-
"h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none overflow-hidden",
|
|
9
|
-
{
|
|
10
|
-
variants: {
|
|
11
|
-
variant: {
|
|
12
|
-
default: "bg-primary text-primary-foreground",
|
|
13
|
-
secondary: "bg-secondary text-secondary-foreground",
|
|
14
|
-
destructive:
|
|
15
|
-
"bg-destructive/10 text-destructive dark:bg-destructive/20",
|
|
16
|
-
outline: "border-border text-foreground",
|
|
17
|
-
ghost: "hover:bg-muted hover:text-muted-foreground",
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
defaultVariants: {
|
|
21
|
-
variant: "default",
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
function Badge({
|
|
27
|
-
className,
|
|
28
|
-
variant = "default",
|
|
29
|
-
asChild = false,
|
|
30
|
-
...props
|
|
31
|
-
}: React.ComponentProps<"span"> &
|
|
32
|
-
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
|
33
|
-
const Comp = asChild ? Slot.Root : "span";
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<Comp
|
|
37
|
-
data-slot="badge"
|
|
38
|
-
className={cn(badgeVariants({ variant }), className)}
|
|
39
|
-
{...props}
|
|
40
|
-
/>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export { Badge, badgeVariants };
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
-
import { Slot } from "radix-ui";
|
|
4
|
-
|
|
5
|
-
import { cn } from "../../lib/utils";
|
|
6
|
-
|
|
7
|
-
const buttonVariants = cva(
|
|
8
|
-
"focus-visible:border-ring focus-visible:ring-ring/50 rounded-md border border-transparent text-sm font-medium focus-visible:ring-3 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none select-none",
|
|
9
|
-
{
|
|
10
|
-
variants: {
|
|
11
|
-
variant: {
|
|
12
|
-
default: "bg-primary text-primary-foreground hover:bg-primary/80",
|
|
13
|
-
outline:
|
|
14
|
-
"border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 shadow-xs",
|
|
15
|
-
secondary:
|
|
16
|
-
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
17
|
-
ghost:
|
|
18
|
-
"hover:bg-muted hover:text-foreground dark:hover:bg-muted/50",
|
|
19
|
-
destructive:
|
|
20
|
-
"bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:bg-destructive/20 text-destructive",
|
|
21
|
-
link: "text-primary underline-offset-4 hover:underline",
|
|
22
|
-
},
|
|
23
|
-
size: {
|
|
24
|
-
default: "h-9 gap-1.5 px-2.5",
|
|
25
|
-
xs: "h-6 gap-1 px-2 text-xs [&_svg:not([class*='size-'])]:size-3",
|
|
26
|
-
sm: "h-8 gap-1 px-2.5",
|
|
27
|
-
lg: "h-10 gap-1.5 px-2.5",
|
|
28
|
-
icon: "size-9",
|
|
29
|
-
"icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
|
|
30
|
-
"icon-sm": "size-8",
|
|
31
|
-
"icon-lg": "size-10",
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
defaultVariants: {
|
|
35
|
-
variant: "default",
|
|
36
|
-
size: "default",
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
function Button({
|
|
42
|
-
className,
|
|
43
|
-
variant = "default",
|
|
44
|
-
size = "default",
|
|
45
|
-
asChild = false,
|
|
46
|
-
...props
|
|
47
|
-
}: React.ComponentProps<"button"> &
|
|
48
|
-
VariantProps<typeof buttonVariants> & {
|
|
49
|
-
asChild?: boolean;
|
|
50
|
-
}) {
|
|
51
|
-
const Comp = asChild ? Slot.Root : "button";
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<Comp
|
|
55
|
-
data-slot="button"
|
|
56
|
-
className={cn(buttonVariants({ variant, size, className }))}
|
|
57
|
-
{...props}
|
|
58
|
-
/>
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export { Button, buttonVariants };
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { Command as CommandPrimitive } from "cmdk";
|
|
3
|
-
import { Search } from "lucide-react";
|
|
4
|
-
|
|
5
|
-
import { cn } from "../../lib/utils";
|
|
6
|
-
|
|
7
|
-
function Command({
|
|
8
|
-
className,
|
|
9
|
-
...props
|
|
10
|
-
}: React.ComponentProps<typeof CommandPrimitive>) {
|
|
11
|
-
return (
|
|
12
|
-
<CommandPrimitive
|
|
13
|
-
data-slot="command"
|
|
14
|
-
className={cn(
|
|
15
|
-
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
|
|
16
|
-
className,
|
|
17
|
-
)}
|
|
18
|
-
{...props}
|
|
19
|
-
/>
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function CommandInput({
|
|
24
|
-
className,
|
|
25
|
-
...props
|
|
26
|
-
}: React.ComponentProps<typeof CommandPrimitive.Input>) {
|
|
27
|
-
return (
|
|
28
|
-
<div className="flex h-9 items-center gap-2 border-b px-3" data-slot="command-input-wrapper">
|
|
29
|
-
<Search className="size-4 shrink-0 opacity-50" />
|
|
30
|
-
<CommandPrimitive.Input
|
|
31
|
-
data-slot="command-input"
|
|
32
|
-
className={cn(
|
|
33
|
-
"flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
|
34
|
-
className,
|
|
35
|
-
)}
|
|
36
|
-
{...props}
|
|
37
|
-
/>
|
|
38
|
-
</div>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function CommandList({
|
|
43
|
-
className,
|
|
44
|
-
...props
|
|
45
|
-
}: React.ComponentProps<typeof CommandPrimitive.List>) {
|
|
46
|
-
return (
|
|
47
|
-
<CommandPrimitive.List
|
|
48
|
-
data-slot="command-list"
|
|
49
|
-
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
|
50
|
-
{...props}
|
|
51
|
-
/>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function CommandEmpty({
|
|
56
|
-
...props
|
|
57
|
-
}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
|
|
58
|
-
return (
|
|
59
|
-
<CommandPrimitive.Empty
|
|
60
|
-
data-slot="command-empty"
|
|
61
|
-
className="py-6 text-center text-sm"
|
|
62
|
-
{...props}
|
|
63
|
-
/>
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function CommandGroup({
|
|
68
|
-
className,
|
|
69
|
-
...props
|
|
70
|
-
}: React.ComponentProps<typeof CommandPrimitive.Group>) {
|
|
71
|
-
return (
|
|
72
|
-
<CommandPrimitive.Group
|
|
73
|
-
data-slot="command-group"
|
|
74
|
-
className={cn(
|
|
75
|
-
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
|
76
|
-
className,
|
|
77
|
-
)}
|
|
78
|
-
{...props}
|
|
79
|
-
/>
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function CommandItem({
|
|
84
|
-
className,
|
|
85
|
-
...props
|
|
86
|
-
}: React.ComponentProps<typeof CommandPrimitive.Item>) {
|
|
87
|
-
return (
|
|
88
|
-
<CommandPrimitive.Item
|
|
89
|
-
data-slot="command-item"
|
|
90
|
-
className={cn(
|
|
91
|
-
"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
92
|
-
className,
|
|
93
|
-
)}
|
|
94
|
-
{...props}
|
|
95
|
-
/>
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export {
|
|
100
|
-
Command,
|
|
101
|
-
CommandInput,
|
|
102
|
-
CommandList,
|
|
103
|
-
CommandEmpty,
|
|
104
|
-
CommandGroup,
|
|
105
|
-
CommandItem,
|
|
106
|
-
};
|