@meshagent/meshagent-tailwind 0.5.0 → 0.5.2

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/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.5.2]
2
+ - Stability
3
+
4
+ ## [0.5.1]
5
+ - Stability
6
+
1
7
  ## [0.5.0]
2
8
  - Stability
3
9
 
package/dist/cjs/Chat.js CHANGED
@@ -26,20 +26,33 @@ var import_meshagent_react = require("@meshagent/meshagent-react");
26
26
  var import_ChatThread = require("./ChatThread");
27
27
  var import_ChatInput = require("./ChatInput");
28
28
  var import_ChatTypingIndicator = require("./ChatTypingIndicator");
29
- var import_card = require("./components/ui/card");
30
29
  function Chat({ room, path, participants }) {
31
30
  const {
32
31
  messages,
33
32
  sendMessage,
34
- selectAttachments
33
+ selectAttachments,
34
+ attachments,
35
+ setAttachments
35
36
  } = (0, import_meshagent_react.useChat)({ room, path, participants });
36
37
  const localParticipantName = room.localParticipant.getAttribute("name");
37
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_card.Card, { className: "flex flex-col min-h-0", children: [
38
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_card.CardHeader, { className: "border-b flex-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_card.CardTitle, { children: "Chat" }) }),
39
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_card.CardContent, { className: "flex flex-col flex-1 min-h-0 gap-2 p-0", children: [
40
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ChatThread.ChatThread, { messages, localParticipantName }),
41
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ChatTypingIndicator.ChatTypingIndicator, { room, path }),
42
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ChatInput.ChatInput, { onSubmit: sendMessage, onFilesSelected: selectAttachments })
43
- ] })
38
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col flex-1 min-h-0 gap-2 p-0", children: [
39
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
40
+ import_ChatThread.ChatThread,
41
+ {
42
+ room,
43
+ messages,
44
+ localParticipantName
45
+ }
46
+ ),
47
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ChatTypingIndicator.ChatTypingIndicator, { room, path }),
48
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
49
+ import_ChatInput.ChatInput,
50
+ {
51
+ onSubmit: sendMessage,
52
+ attachments,
53
+ onFilesSelected: selectAttachments,
54
+ setAttachments
55
+ }
56
+ )
44
57
  ] });
45
58
  }
@@ -1,7 +1,9 @@
1
- import { ChatMessage } from "@meshagent/meshagent-react";
1
+ import { ChatMessage, FileUpload } from "@meshagent/meshagent-react";
2
2
  interface ChatInputProps {
3
3
  onSubmit: (message: ChatMessage) => void;
4
4
  onFilesSelected: (files: File[]) => void;
5
+ attachments: FileUpload[];
6
+ setAttachments: (attachments: FileUpload[]) => void;
5
7
  }
6
- export declare function ChatInput({ onSubmit }: ChatInputProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function ChatInput({ onSubmit, onFilesSelected, attachments, setAttachments }: ChatInputProps): import("react/jsx-runtime").JSX.Element;
7
9
  export {};
@@ -32,39 +32,61 @@ __export(ChatInput_exports, {
32
32
  });
33
33
  module.exports = __toCommonJS(ChatInput_exports);
34
34
  var import_jsx_runtime = require("react/jsx-runtime");
35
- var React = __toESM(require("react"));
35
+ var import_react = __toESM(require("react"));
36
36
  var import_uuid = require("uuid");
37
37
  var import_meshagent_react = require("@meshagent/meshagent-react");
38
38
  var import_button = require("./components/ui/button");
39
39
  var import_textarea = require("./components/ui/textarea");
40
- function ChatInput({ onSubmit }) {
41
- const [value, setValue] = React.useState("");
42
- const handleSend = () => {
43
- const trimmed = value.trim();
44
- if (!trimmed) return;
40
+ var import_FileUploader = require("./FileUploader");
41
+ var import_UploadPill = require("./UploadPill");
42
+ function ChatInput({ onSubmit, onFilesSelected, attachments, setAttachments }) {
43
+ const [value, setValue] = import_react.default.useState("");
44
+ const handleSend = (0, import_react.useCallback)(() => {
45
+ const trimmed2 = value.trim();
46
+ if (attachments.length === 0 && !trimmed2) {
47
+ return;
48
+ }
45
49
  onSubmit(new import_meshagent_react.ChatMessage({
46
50
  id: (0, import_uuid.v4)(),
47
- text: trimmed
51
+ text: trimmed2,
52
+ attachments: attachments.map((file) => file.path)
48
53
  }));
49
54
  setValue("");
50
- };
55
+ setAttachments([]);
56
+ }, [value, onSubmit, attachments]);
51
57
  const onKeyDown = (e) => {
52
- if (e.key === "Enter" && e.ctrlKey) {
58
+ if (e.key === "Enter" && !e.shiftKey) {
53
59
  e.preventDefault();
54
60
  handleSend();
55
61
  }
56
62
  };
57
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "border-t p-3 flex gap-3", children: [
58
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
59
- import_textarea.Textarea,
63
+ const cancelAttachment = (0, import_react.useCallback)((attachment) => {
64
+ setAttachments(attachments.filter((f) => f.path !== attachment.path));
65
+ }, [attachments, setAttachments]);
66
+ const trimmed = value.trim();
67
+ const disabled = !trimmed && attachments.length === 0;
68
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "border-t py-3 gap-3 flex flex-col", children: [
69
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-0 gap-2 flex-wrap", children: attachments.map((attachment) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
70
+ import_UploadPill.UploadPill,
60
71
  {
61
- placeholder: "Type a message and press Ctrl+Enter\u2026",
62
- className: "flex-1 resize-none h-20",
63
- value,
64
- onChange: (e) => setValue(e.currentTarget.value),
65
- onKeyDown
66
- }
67
- ),
68
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_button.Button, { onClick: handleSend, disabled: !value.trim(), children: "Send" })
72
+ attachment,
73
+ onCancel: cancelAttachment
74
+ },
75
+ attachment.path
76
+ )) }),
77
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-0 gap-3", children: [
78
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_FileUploader.FileUploader, { onFilesSelected }),
79
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
80
+ import_textarea.Textarea,
81
+ {
82
+ placeholder: "Type a message and press Enter",
83
+ className: "flex-1 resize-none h-20",
84
+ value,
85
+ onChange: (e) => setValue(e.currentTarget.value),
86
+ onKeyDown
87
+ }
88
+ ),
89
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_button.Button, { onClick: handleSend, disabled, children: "Send" })
90
+ ] })
69
91
  ] });
70
92
  }
@@ -1,6 +1,7 @@
1
- import { Element } from "@meshagent/meshagent";
1
+ import { Element, RoomClient } from "@meshagent/meshagent";
2
2
  export declare function timeAgo(iso: string): string;
3
- export declare function ChatThread({ messages, localParticipantName }: {
3
+ export declare function ChatThread({ room, messages, localParticipantName }: {
4
+ room: RoomClient;
4
5
  messages: Element[];
5
6
  localParticipantName: string;
6
7
  }): import("react/jsx-runtime").JSX.Element;
@@ -33,7 +33,8 @@ __export(ChatThread_exports, {
33
33
  });
34
34
  module.exports = __toCommonJS(ChatThread_exports);
35
35
  var import_jsx_runtime = require("react/jsx-runtime");
36
- var React = __toESM(require("react"));
36
+ var import_react = __toESM(require("react"));
37
+ var import_lucide_react = require("lucide-react");
37
38
  var import_react_markdown = __toESM(require("react-markdown"));
38
39
  var import_remark_gfm = __toESM(require("remark-gfm"));
39
40
  var import_rehype_sanitize = __toESM(require("rehype-sanitize"));
@@ -51,6 +52,9 @@ function formatDateTime(iso) {
51
52
  timeZoneName: "short"
52
53
  }).format(date);
53
54
  }
55
+ function isImageFilename(filename) {
56
+ return /\.(jpe?g|png|gif|bmp|webp|avif|svg)$/i.test(filename);
57
+ }
54
58
  function timeAgo(iso) {
55
59
  const rtf = new Intl.RelativeTimeFormat(void 0, { numeric: "auto" });
56
60
  const date = new Date(iso);
@@ -66,28 +70,80 @@ function timeAgo(iso) {
66
70
  if (Math.abs(minutes) >= 1) return rtf.format(minutes, "minute");
67
71
  return rtf.format(seconds, "second");
68
72
  }
69
- function ChatThread({ messages, localParticipantName }) {
70
- const bottomRef = React.useRef(null);
71
- React.useEffect(() => {
73
+ function ChatThread({ room, messages, localParticipantName }) {
74
+ const bottomRef = import_react.default.useRef(null);
75
+ (0, import_react.useEffect)(() => {
72
76
  bottomRef.current?.scrollIntoView({ behavior: "smooth" });
73
77
  }, [messages]);
74
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 flex-shrink-1 basis-0 overflow-y-auto p-4 space-y-4", children: [
75
- messages.map((message) => {
76
- const mine = localParticipantName == message.getAttribute("author_name");
77
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_utils.cn)("flex flex-col max-w-prose items-start gap-1", { "justify-end": mine, "justify-start": !mine }), children: [
78
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-0.5 text-xs text-muted-foreground", children: [
79
- "By ",
80
- message.getAttribute("author_name"),
81
- " at ",
82
- timeAgo(message.getAttribute("created_at"))
83
- ] }),
84
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChatBubble, { text: message.getAttribute("text"), mine }, message.id)
85
- ] }, message.id);
86
- }),
78
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col flex-1 flex-shrink-1 basis-0 overflow-y-auto p-4 space-y-4", children: [
79
+ messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
80
+ ChatMessage,
81
+ {
82
+ room,
83
+ message,
84
+ localParticipantName
85
+ },
86
+ message.id
87
+ )),
87
88
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: bottomRef })
88
89
  ] });
89
90
  }
91
+ function ChatImage({ room, path, alt }) {
92
+ const [url, setUrl] = import_react.default.useState("");
93
+ (0, import_react.useEffect)(() => {
94
+ room.storage.downloadUrl(path).then(setUrl);
95
+ }, [path]);
96
+ return url === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: url, alt, className: "max-h-48 max-w-full rounded-lg" });
97
+ }
98
+ function ChatMessage({ room, message, localParticipantName }) {
99
+ const mine = localParticipantName == message.getAttribute("author_name");
100
+ const attachments = (message.children ?? []).filter((child) => child.tagName === "file");
101
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_utils.cn)("flex flex-col max-w-prose gap-1", { "items-end self-end": mine, "items-start self-start": !mine }), children: [
102
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-0.5 text-xs text-muted-foreground", children: [
103
+ "By ",
104
+ message.getAttribute("author_name"),
105
+ " at ",
106
+ timeAgo(message.getAttribute("created_at"))
107
+ ] }),
108
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChatBubble, { text: message.getAttribute("text"), mine }, message.id),
109
+ attachments && attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_utils.cn)("flex flex-wrap gap-2 mt-2", { "text-right": mine }), children: attachments.map((attachment) => {
110
+ const path = attachment.getAttribute("path") || "";
111
+ const isImage = isImageFilename(path);
112
+ const filename = path.split("/").pop();
113
+ if (isImage) {
114
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
115
+ ChatImage,
116
+ {
117
+ room,
118
+ path,
119
+ alt: filename || "Image Attachment"
120
+ },
121
+ attachment.id
122
+ );
123
+ }
124
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
125
+ "button",
126
+ {
127
+ type: "button",
128
+ onClick: () => {
129
+ room.storage.downloadUrl(path).then((url) => window.open(url, "_blank"));
130
+ },
131
+ className: "relative inline-flex max-w-full items-center border bg-muted pl-3 pr-1 py-1 gap-2 cursor-pointer hover:bg-muted-foreground/20 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
132
+ rel: "noopener noreferrer",
133
+ children: [
134
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate text-sm font-medium leading-none", children: filename }),
135
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Download, { className: "inline-block mr-1" })
136
+ ]
137
+ },
138
+ attachment.id
139
+ );
140
+ }) })
141
+ ] });
142
+ }
90
143
  function ChatBubble({ text, mine }) {
144
+ if (!text || text.trim() === "") {
145
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {});
146
+ }
91
147
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_utils.cn)(
92
148
  "rounded-lg px-4 py-2 text-sm max-w-prose whitespace-pre-wrap",
93
149
  {
@@ -100,8 +156,9 @@ function ChatBubble({ text, mine }) {
100
156
  remarkPlugins: [import_remark_gfm.default],
101
157
  rehypePlugins: [import_rehype_sanitize.default, import_rehype_highlight.default],
102
158
  components: {
103
- p: ({ node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { ...props, className: "mb-2 last:mb-0" }),
104
- code: ({ className, children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { className: "my-2 overflow-x-auto rounded-lg", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { ...props, className, children }) })
159
+ pre: ({ node, className, children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { ...props, className: (0, import_utils.cn)("overflow-x-auto rounded-lg", className), children }),
160
+ p: ({ node, children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { ...props, className: "mb-2 last:mb-0", children }),
161
+ code: ({ className, children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { ...props, className, children })
105
162
  },
106
163
  children: text
107
164
  }
@@ -22,15 +22,14 @@ __export(ChatTypingIndicator_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(ChatTypingIndicator_exports);
24
24
  var import_jsx_runtime = require("react/jsx-runtime");
25
- var import_lucide_react = require("lucide-react");
26
25
  var import_meshagent_react = require("@meshagent/meshagent-react");
27
26
  function ChatTypingIndicator({ room, path }) {
28
27
  const { typing } = (0, import_meshagent_react.useRoomIndicators)({ room, path });
29
28
  return typing ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-end space-x-1 h-6 p-6", children: [
30
29
  [0, 1, 2].map((index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
31
- import_lucide_react.Circle,
30
+ "span",
32
31
  {
33
- className: "w-2 h-2 text-gray-500",
32
+ className: `inline-block w-2 h-2 bg-current rounded-full`,
34
33
  style: {
35
34
  animation: "typingBounce 0.6s ease-in-out infinite",
36
35
  animationDelay: `${index * 0.2}s`
@@ -25,10 +25,7 @@ var import_jsx_runtime = require("react/jsx-runtime");
25
25
  var import_react = require("react");
26
26
  var import_lucide_react = require("lucide-react");
27
27
  var import_button = require("./components/ui/button");
28
- function FileUploader({
29
- onFilesSelected,
30
- accept = ""
31
- }) {
28
+ function FileUploader({ onFilesSelected, accept = "" }) {
32
29
  const inputRef = (0, import_react.useRef)(null);
33
30
  const handleButtonClick = () => inputRef.current?.click();
34
31
  const handleFileChange = (e) => {
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ import { FileUpload } from "@meshagent/meshagent-react";
3
+ export interface UploadPillProps {
4
+ attachment: FileUpload;
5
+ onCancel: (attachment: FileUpload) => void;
6
+ }
7
+ export declare function UploadPill({ attachment, onCancel }: UploadPillProps): React.ReactElement;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var UploadPill_exports = {};
20
+ __export(UploadPill_exports, {
21
+ UploadPill: () => UploadPill
22
+ });
23
+ module.exports = __toCommonJS(UploadPill_exports);
24
+ var import_jsx_runtime = require("react/jsx-runtime");
25
+ var import_react = require("react");
26
+ var import_progress = require("./components/ui/progress");
27
+ var import_lucide_react = require("lucide-react");
28
+ function UploadPill({ attachment, onCancel }) {
29
+ const [progress, setProgress] = (0, import_react.useState)(0);
30
+ const handleCancel = (0, import_react.useCallback)(() => onCancel(attachment), [attachment, onCancel]);
31
+ (0, import_react.useEffect)(() => {
32
+ const onChange = () => setProgress(
33
+ Math.round(attachment.bytesUploaded * 100 / attachment.size)
34
+ );
35
+ attachment.on("status", onChange);
36
+ return () => attachment.off("status", onChange);
37
+ }, [attachment]);
38
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative inline-flex max-w-full items-center border bg-muted pl-3 pr-1 py-1 gap-2", children: [
39
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate text-sm font-medium leading-none", children: attachment.filename }),
40
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
41
+ "button",
42
+ {
43
+ type: "button",
44
+ onClick: handleCancel,
45
+ "aria-label": "Cancel upload",
46
+ className: "rounded-full p-1 transition-colors hover:bg-muted-foreground/20 focus:outline-none cursor-pointer focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
47
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "h-4 w-4" })
48
+ }
49
+ ),
50
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
51
+ import_progress.Progress,
52
+ {
53
+ value: progress,
54
+ className: "absolute left-0 bottom-0 h-0.5 w-full rounded-full bg-muted-foreground/20"
55
+ }
56
+ )
57
+ ] });
58
+ }
59
+ ;
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ import * as ProgressPrimitive from "@radix-ui/react-progress";
3
+ export declare function Progress({ className, value, ...props }: React.ComponentProps<typeof ProgressPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var progress_exports = {};
30
+ __export(progress_exports, {
31
+ Progress: () => Progress
32
+ });
33
+ module.exports = __toCommonJS(progress_exports);
34
+ var import_jsx_runtime = require("react/jsx-runtime");
35
+ var ProgressPrimitive = __toESM(require("@radix-ui/react-progress"));
36
+ var import_utils = require("@/lib/utils");
37
+ function Progress({ className, value, ...props }) {
38
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
39
+ ProgressPrimitive.Root,
40
+ {
41
+ "data-slot": "progress",
42
+ className: (0, import_utils.cn)(
43
+ "bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
44
+ className
45
+ ),
46
+ ...props,
47
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
48
+ ProgressPrimitive.Indicator,
49
+ {
50
+ "data-slot": "progress-indicator",
51
+ className: "bg-primary h-full w-full flex-1 transition-all",
52
+ style: { transform: `translateX(-${100 - (value || 0)}%)` }
53
+ }
54
+ )
55
+ }
56
+ );
57
+ }
package/dist/esm/Chat.js CHANGED
@@ -3,21 +3,34 @@ import { useChat } from "@meshagent/meshagent-react";
3
3
  import { ChatThread } from "./ChatThread";
4
4
  import { ChatInput } from "./ChatInput";
5
5
  import { ChatTypingIndicator } from "./ChatTypingIndicator";
6
- import { Card, CardContent, CardHeader, CardTitle } from "./components/ui/card";
7
6
  function Chat({ room, path, participants }) {
8
7
  const {
9
8
  messages,
10
9
  sendMessage,
11
- selectAttachments
10
+ selectAttachments,
11
+ attachments,
12
+ setAttachments
12
13
  } = useChat({ room, path, participants });
13
14
  const localParticipantName = room.localParticipant.getAttribute("name");
14
- return /* @__PURE__ */ jsxs(Card, { className: "flex flex-col min-h-0", children: [
15
- /* @__PURE__ */ jsx(CardHeader, { className: "border-b flex-0", children: /* @__PURE__ */ jsx(CardTitle, { children: "Chat" }) }),
16
- /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col flex-1 min-h-0 gap-2 p-0", children: [
17
- /* @__PURE__ */ jsx(ChatThread, { messages, localParticipantName }),
18
- /* @__PURE__ */ jsx(ChatTypingIndicator, { room, path }),
19
- /* @__PURE__ */ jsx(ChatInput, { onSubmit: sendMessage, onFilesSelected: selectAttachments })
20
- ] })
15
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col flex-1 min-h-0 gap-2 p-0", children: [
16
+ /* @__PURE__ */ jsx(
17
+ ChatThread,
18
+ {
19
+ room,
20
+ messages,
21
+ localParticipantName
22
+ }
23
+ ),
24
+ /* @__PURE__ */ jsx(ChatTypingIndicator, { room, path }),
25
+ /* @__PURE__ */ jsx(
26
+ ChatInput,
27
+ {
28
+ onSubmit: sendMessage,
29
+ attachments,
30
+ onFilesSelected: selectAttachments,
31
+ setAttachments
32
+ }
33
+ )
21
34
  ] });
22
35
  }
23
36
  export {
@@ -1,7 +1,9 @@
1
- import { ChatMessage } from "@meshagent/meshagent-react";
1
+ import { ChatMessage, FileUpload } from "@meshagent/meshagent-react";
2
2
  interface ChatInputProps {
3
3
  onSubmit: (message: ChatMessage) => void;
4
4
  onFilesSelected: (files: File[]) => void;
5
+ attachments: FileUpload[];
6
+ setAttachments: (attachments: FileUpload[]) => void;
5
7
  }
6
- export declare function ChatInput({ onSubmit }: ChatInputProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function ChatInput({ onSubmit, onFilesSelected, attachments, setAttachments }: ChatInputProps): import("react/jsx-runtime").JSX.Element;
7
9
  export {};
@@ -1,38 +1,60 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import * as React from "react";
2
+ import React, { useCallback } from "react";
3
3
  import { v4 as uuidV4 } from "uuid";
4
4
  import { ChatMessage } from "@meshagent/meshagent-react";
5
5
  import { Button } from "./components/ui/button";
6
6
  import { Textarea } from "./components/ui/textarea";
7
- function ChatInput({ onSubmit }) {
7
+ import { FileUploader } from "./FileUploader";
8
+ import { UploadPill } from "./UploadPill";
9
+ function ChatInput({ onSubmit, onFilesSelected, attachments, setAttachments }) {
8
10
  const [value, setValue] = React.useState("");
9
- const handleSend = () => {
10
- const trimmed = value.trim();
11
- if (!trimmed) return;
11
+ const handleSend = useCallback(() => {
12
+ const trimmed2 = value.trim();
13
+ if (attachments.length === 0 && !trimmed2) {
14
+ return;
15
+ }
12
16
  onSubmit(new ChatMessage({
13
17
  id: uuidV4(),
14
- text: trimmed
18
+ text: trimmed2,
19
+ attachments: attachments.map((file) => file.path)
15
20
  }));
16
21
  setValue("");
17
- };
22
+ setAttachments([]);
23
+ }, [value, onSubmit, attachments]);
18
24
  const onKeyDown = (e) => {
19
- if (e.key === "Enter" && e.ctrlKey) {
25
+ if (e.key === "Enter" && !e.shiftKey) {
20
26
  e.preventDefault();
21
27
  handleSend();
22
28
  }
23
29
  };
24
- return /* @__PURE__ */ jsxs("div", { className: "border-t p-3 flex gap-3", children: [
25
- /* @__PURE__ */ jsx(
26
- Textarea,
30
+ const cancelAttachment = useCallback((attachment) => {
31
+ setAttachments(attachments.filter((f) => f.path !== attachment.path));
32
+ }, [attachments, setAttachments]);
33
+ const trimmed = value.trim();
34
+ const disabled = !trimmed && attachments.length === 0;
35
+ return /* @__PURE__ */ jsxs("div", { className: "border-t py-3 gap-3 flex flex-col", children: [
36
+ /* @__PURE__ */ jsx("div", { className: "flex flex-0 gap-2 flex-wrap", children: attachments.map((attachment) => /* @__PURE__ */ jsx(
37
+ UploadPill,
27
38
  {
28
- placeholder: "Type a message and press Ctrl+Enter\u2026",
29
- className: "flex-1 resize-none h-20",
30
- value,
31
- onChange: (e) => setValue(e.currentTarget.value),
32
- onKeyDown
33
- }
34
- ),
35
- /* @__PURE__ */ jsx(Button, { onClick: handleSend, disabled: !value.trim(), children: "Send" })
39
+ attachment,
40
+ onCancel: cancelAttachment
41
+ },
42
+ attachment.path
43
+ )) }),
44
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-0 gap-3", children: [
45
+ /* @__PURE__ */ jsx(FileUploader, { onFilesSelected }),
46
+ /* @__PURE__ */ jsx(
47
+ Textarea,
48
+ {
49
+ placeholder: "Type a message and press Enter",
50
+ className: "flex-1 resize-none h-20",
51
+ value,
52
+ onChange: (e) => setValue(e.currentTarget.value),
53
+ onKeyDown
54
+ }
55
+ ),
56
+ /* @__PURE__ */ jsx(Button, { onClick: handleSend, disabled, children: "Send" })
57
+ ] })
36
58
  ] });
37
59
  }
38
60
  export {
@@ -1,6 +1,7 @@
1
- import { Element } from "@meshagent/meshagent";
1
+ import { Element, RoomClient } from "@meshagent/meshagent";
2
2
  export declare function timeAgo(iso: string): string;
3
- export declare function ChatThread({ messages, localParticipantName }: {
3
+ export declare function ChatThread({ room, messages, localParticipantName }: {
4
+ room: RoomClient;
4
5
  messages: Element[];
5
6
  localParticipantName: string;
6
7
  }): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,6 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
2
- import * as React from "react";
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import React, { useEffect } from "react";
3
+ import { Download } from "lucide-react";
3
4
  import ReactMarkdown from "react-markdown";
4
5
  import remarkGfm from "remark-gfm";
5
6
  import rehypeSanitize from "rehype-sanitize";
@@ -17,6 +18,9 @@ function formatDateTime(iso) {
17
18
  timeZoneName: "short"
18
19
  }).format(date);
19
20
  }
21
+ function isImageFilename(filename) {
22
+ return /\.(jpe?g|png|gif|bmp|webp|avif|svg)$/i.test(filename);
23
+ }
20
24
  function timeAgo(iso) {
21
25
  const rtf = new Intl.RelativeTimeFormat(void 0, { numeric: "auto" });
22
26
  const date = new Date(iso);
@@ -32,28 +36,80 @@ function timeAgo(iso) {
32
36
  if (Math.abs(minutes) >= 1) return rtf.format(minutes, "minute");
33
37
  return rtf.format(seconds, "second");
34
38
  }
35
- function ChatThread({ messages, localParticipantName }) {
39
+ function ChatThread({ room, messages, localParticipantName }) {
36
40
  const bottomRef = React.useRef(null);
37
- React.useEffect(() => {
41
+ useEffect(() => {
38
42
  bottomRef.current?.scrollIntoView({ behavior: "smooth" });
39
43
  }, [messages]);
40
- return /* @__PURE__ */ jsxs("div", { className: "flex-1 flex-shrink-1 basis-0 overflow-y-auto p-4 space-y-4", children: [
41
- messages.map((message) => {
42
- const mine = localParticipantName == message.getAttribute("author_name");
43
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col max-w-prose items-start gap-1", { "justify-end": mine, "justify-start": !mine }), children: [
44
- /* @__PURE__ */ jsxs("div", { className: "mb-0.5 text-xs text-muted-foreground", children: [
45
- "By ",
46
- message.getAttribute("author_name"),
47
- " at ",
48
- timeAgo(message.getAttribute("created_at"))
49
- ] }),
50
- /* @__PURE__ */ jsx(ChatBubble, { text: message.getAttribute("text"), mine }, message.id)
51
- ] }, message.id);
52
- }),
44
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col flex-1 flex-shrink-1 basis-0 overflow-y-auto p-4 space-y-4", children: [
45
+ messages.map((message) => /* @__PURE__ */ jsx(
46
+ ChatMessage,
47
+ {
48
+ room,
49
+ message,
50
+ localParticipantName
51
+ },
52
+ message.id
53
+ )),
53
54
  /* @__PURE__ */ jsx("div", { ref: bottomRef })
54
55
  ] });
55
56
  }
57
+ function ChatImage({ room, path, alt }) {
58
+ const [url, setUrl] = React.useState("");
59
+ useEffect(() => {
60
+ room.storage.downloadUrl(path).then(setUrl);
61
+ }, [path]);
62
+ return url === "" ? null : /* @__PURE__ */ jsx("img", { src: url, alt, className: "max-h-48 max-w-full rounded-lg" });
63
+ }
64
+ function ChatMessage({ room, message, localParticipantName }) {
65
+ const mine = localParticipantName == message.getAttribute("author_name");
66
+ const attachments = (message.children ?? []).filter((child) => child.tagName === "file");
67
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col max-w-prose gap-1", { "items-end self-end": mine, "items-start self-start": !mine }), children: [
68
+ /* @__PURE__ */ jsxs("div", { className: "mb-0.5 text-xs text-muted-foreground", children: [
69
+ "By ",
70
+ message.getAttribute("author_name"),
71
+ " at ",
72
+ timeAgo(message.getAttribute("created_at"))
73
+ ] }),
74
+ /* @__PURE__ */ jsx(ChatBubble, { text: message.getAttribute("text"), mine }, message.id),
75
+ attachments && attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("flex flex-wrap gap-2 mt-2", { "text-right": mine }), children: attachments.map((attachment) => {
76
+ const path = attachment.getAttribute("path") || "";
77
+ const isImage = isImageFilename(path);
78
+ const filename = path.split("/").pop();
79
+ if (isImage) {
80
+ return /* @__PURE__ */ jsx(
81
+ ChatImage,
82
+ {
83
+ room,
84
+ path,
85
+ alt: filename || "Image Attachment"
86
+ },
87
+ attachment.id
88
+ );
89
+ }
90
+ return /* @__PURE__ */ jsxs(
91
+ "button",
92
+ {
93
+ type: "button",
94
+ onClick: () => {
95
+ room.storage.downloadUrl(path).then((url) => window.open(url, "_blank"));
96
+ },
97
+ className: "relative inline-flex max-w-full items-center border bg-muted pl-3 pr-1 py-1 gap-2 cursor-pointer hover:bg-muted-foreground/20 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
98
+ rel: "noopener noreferrer",
99
+ children: [
100
+ /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium leading-none", children: filename }),
101
+ /* @__PURE__ */ jsx(Download, { className: "inline-block mr-1" })
102
+ ]
103
+ },
104
+ attachment.id
105
+ );
106
+ }) })
107
+ ] });
108
+ }
56
109
  function ChatBubble({ text, mine }) {
110
+ if (!text || text.trim() === "") {
111
+ return /* @__PURE__ */ jsx(Fragment, {});
112
+ }
57
113
  return /* @__PURE__ */ jsx("div", { className: cn(
58
114
  "rounded-lg px-4 py-2 text-sm max-w-prose whitespace-pre-wrap",
59
115
  {
@@ -66,8 +122,9 @@ function ChatBubble({ text, mine }) {
66
122
  remarkPlugins: [remarkGfm],
67
123
  rehypePlugins: [rehypeSanitize, rehypeHighlight],
68
124
  components: {
69
- p: ({ node, ...props }) => /* @__PURE__ */ jsx("p", { ...props, className: "mb-2 last:mb-0" }),
70
- code: ({ className, children, ...props }) => /* @__PURE__ */ jsx("pre", { className: "my-2 overflow-x-auto rounded-lg", children: /* @__PURE__ */ jsx("code", { ...props, className, children }) })
125
+ pre: ({ node, className, children, ...props }) => /* @__PURE__ */ jsx("pre", { ...props, className: cn("overflow-x-auto rounded-lg", className), children }),
126
+ p: ({ node, children, ...props }) => /* @__PURE__ */ jsx("p", { ...props, className: "mb-2 last:mb-0", children }),
127
+ code: ({ className, children, ...props }) => /* @__PURE__ */ jsx("code", { ...props, className, children })
71
128
  },
72
129
  children: text
73
130
  }
@@ -1,13 +1,12 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { Circle } from "lucide-react";
3
2
  import { useRoomIndicators } from "@meshagent/meshagent-react";
4
3
  function ChatTypingIndicator({ room, path }) {
5
4
  const { typing } = useRoomIndicators({ room, path });
6
5
  return typing ? /* @__PURE__ */ jsxs("div", { className: "flex items-end space-x-1 h-6 p-6", children: [
7
6
  [0, 1, 2].map((index) => /* @__PURE__ */ jsx(
8
- Circle,
7
+ "span",
9
8
  {
10
- className: "w-2 h-2 text-gray-500",
9
+ className: `inline-block w-2 h-2 bg-current rounded-full`,
11
10
  style: {
12
11
  animation: "typingBounce 0.6s ease-in-out infinite",
13
12
  animationDelay: `${index * 0.2}s`
@@ -2,10 +2,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useRef } from "react";
3
3
  import { Plus } from "lucide-react";
4
4
  import { Button } from "./components/ui/button";
5
- function FileUploader({
6
- onFilesSelected,
7
- accept = ""
8
- }) {
5
+ function FileUploader({ onFilesSelected, accept = "" }) {
9
6
  const inputRef = useRef(null);
10
7
  const handleButtonClick = () => inputRef.current?.click();
11
8
  const handleFileChange = (e) => {
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ import { FileUpload } from "@meshagent/meshagent-react";
3
+ export interface UploadPillProps {
4
+ attachment: FileUpload;
5
+ onCancel: (attachment: FileUpload) => void;
6
+ }
7
+ export declare function UploadPill({ attachment, onCancel }: UploadPillProps): React.ReactElement;
@@ -0,0 +1,39 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useState, useCallback, useEffect } from "react";
3
+ import { Progress } from "./components/ui/progress";
4
+ import { X } from "lucide-react";
5
+ function UploadPill({ attachment, onCancel }) {
6
+ const [progress, setProgress] = useState(0);
7
+ const handleCancel = useCallback(() => onCancel(attachment), [attachment, onCancel]);
8
+ useEffect(() => {
9
+ const onChange = () => setProgress(
10
+ Math.round(attachment.bytesUploaded * 100 / attachment.size)
11
+ );
12
+ attachment.on("status", onChange);
13
+ return () => attachment.off("status", onChange);
14
+ }, [attachment]);
15
+ return /* @__PURE__ */ jsxs("div", { className: "relative inline-flex max-w-full items-center border bg-muted pl-3 pr-1 py-1 gap-2", children: [
16
+ /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium leading-none", children: attachment.filename }),
17
+ /* @__PURE__ */ jsx(
18
+ "button",
19
+ {
20
+ type: "button",
21
+ onClick: handleCancel,
22
+ "aria-label": "Cancel upload",
23
+ className: "rounded-full p-1 transition-colors hover:bg-muted-foreground/20 focus:outline-none cursor-pointer focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
24
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
25
+ }
26
+ ),
27
+ /* @__PURE__ */ jsx(
28
+ Progress,
29
+ {
30
+ value: progress,
31
+ className: "absolute left-0 bottom-0 h-0.5 w-full rounded-full bg-muted-foreground/20"
32
+ }
33
+ )
34
+ ] });
35
+ }
36
+ ;
37
+ export {
38
+ UploadPill
39
+ };
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ import * as ProgressPrimitive from "@radix-ui/react-progress";
3
+ export declare function Progress({ className, value, ...props }: React.ComponentProps<typeof ProgressPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,27 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import * as ProgressPrimitive from "@radix-ui/react-progress";
3
+ import { cn } from "@/lib/utils";
4
+ function Progress({ className, value, ...props }) {
5
+ return /* @__PURE__ */ jsx(
6
+ ProgressPrimitive.Root,
7
+ {
8
+ "data-slot": "progress",
9
+ className: cn(
10
+ "bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
11
+ className
12
+ ),
13
+ ...props,
14
+ children: /* @__PURE__ */ jsx(
15
+ ProgressPrimitive.Indicator,
16
+ {
17
+ "data-slot": "progress-indicator",
18
+ className: "bg-primary h-full w-full flex-1 transition-all",
19
+ style: { transform: `translateX(-${100 - (value || 0)}%)` }
20
+ }
21
+ )
22
+ }
23
+ );
24
+ }
25
+ export {
26
+ Progress
27
+ };
package/dist/index.css CHANGED
@@ -1,2 +1,2 @@
1
1
  /*! tailwindcss v4.1.11 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-ease:initial;--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-600:oklch(57.7% .245 27.325);--color-gray-500:oklch(55.1% .027 264.364);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--radius-2xl:1rem;--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){*{outline-color:color-mix(in oklab,var(--ring)50%,transparent)}}body{background-color:var(--background);color:var(--foreground)}}@layer components;@layer utilities{.\@container\/card-header{container:card-header/inline-size}.relative{position:relative}.col-start-2{grid-column-start:2}.row-span-2{grid-row:span 2/span 2}.row-start-1{grid-row-start:1}.my-2{margin-block:calc(var(--spacing)*2)}.mt-1{margin-top:calc(var(--spacing)*1)}.mb-0\.5{margin-bottom:calc(var(--spacing)*.5)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.field-sizing-content{field-sizing:content}.aspect-square{aspect-ratio:1}.size-8{width:calc(var(--spacing)*8);height:calc(var(--spacing)*8)}.size-9{width:calc(var(--spacing)*9);height:calc(var(--spacing)*9)}.size-full{width:100%;height:100%}.h-2{height:calc(var(--spacing)*2)}.h-4{height:calc(var(--spacing)*4)}.h-6{height:calc(var(--spacing)*6)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-10{height:calc(var(--spacing)*10)}.h-20{height:calc(var(--spacing)*20)}.h-full{height:100%}.min-h-0{min-height:calc(var(--spacing)*0)}.min-h-16{min-height:calc(var(--spacing)*16)}.w-2{width:calc(var(--spacing)*2)}.w-4{width:calc(var(--spacing)*4)}.w-6{width:calc(var(--spacing)*6)}.w-8{width:calc(var(--spacing)*8)}.w-10{width:calc(var(--spacing)*10)}.w-full{width:100%}.max-w-prose{max-width:65ch}.min-w-0{min-width:calc(var(--spacing)*0)}.flex-0{flex:0}.flex-1{flex:1}.flex-shrink-1{flex-shrink:1}.shrink-0{flex-shrink:0}.basis-0{flex-basis:calc(var(--spacing)*0)}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.resize-none{resize:none}.auto-rows-min{grid-auto-rows:min-content}.grid-rows-\[auto_auto\]{grid-template-rows:auto auto}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-6{gap:calc(var(--spacing)*6)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*6)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-x-1>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*1)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-x-reverse)))}.self-start{align-self:flex-start}.justify-self-end{justify-self:flex-end}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-xl{border-radius:calc(var(--radius) + 4px)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-input{border-color:var(--input)}.bg-accent{background-color:var(--accent)}.bg-background{background-color:var(--background)}.bg-card{background-color:var(--card)}.bg-destructive{background-color:var(--destructive)}.bg-muted{background-color:var(--muted)}.bg-primary{background-color:var(--primary)}.bg-secondary{background-color:var(--secondary)}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.p-0{padding:calc(var(--spacing)*0)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.py-6{padding-block:calc(var(--spacing)*6)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-card-foreground{color:var(--card-foreground)}.text-current{color:currentColor}.text-gray-500{color:var(--color-gray-500)}.text-muted-foreground{color:var(--muted-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-red-600{color:var(--color-red-600)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-white{color:var(--color-white)}.underline-offset-4{text-underline-offset:4px}.shadow,.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-\[color\,box-shadow\]{transition-property:color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.group-data-\[disabled\=true\]\:pointer-events-none:is(:where(.group)[data-disabled=true] *){pointer-events:none}.group-data-\[disabled\=true\]\:opacity-50:is(:where(.group)[data-disabled=true] *){opacity:.5}.peer-disabled\:cursor-not-allowed:is(:where(.peer):disabled~*){cursor:not-allowed}.peer-disabled\:opacity-50:is(:where(.peer):disabled~*){opacity:.5}.selection\:bg-primary ::selection{background-color:var(--primary)}.selection\:bg-primary::selection{background-color:var(--primary)}.selection\:text-primary-foreground ::selection{color:var(--primary-foreground)}.selection\:text-primary-foreground::selection{color:var(--primary-foreground)}.file\:inline-flex::file-selector-button{display:inline-flex}.file\:h-7::file-selector-button{height:calc(var(--spacing)*7)}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:bg-transparent::file-selector-button{background-color:#0000}.file\:text-sm::file-selector-button{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\:text-foreground::file-selector-button{color:var(--foreground)}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.last\:mb-0:last-child{margin-bottom:calc(var(--spacing)*0)}@media (hover:hover){.hover\:bg-accent:hover{background-color:var(--accent)}.hover\:bg-destructive\/90:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab,var(--destructive)90%,transparent)}}.hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--primary)90%,transparent)}}.hover\:bg-secondary\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab,var(--secondary)80%,transparent)}}.hover\:text-accent-foreground:hover{color:var(--accent-foreground)}.hover\:underline:hover{text-decoration-line:underline}}.focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\:ring-\[3px\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(3px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab,var(--ring)50%,transparent)}}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.has-data-\[slot\=card-action\]\:grid-cols-\[1fr_auto\]:has([data-slot=card-action]){grid-template-columns:1fr auto}.has-\[\>svg\]\:px-2\.5:has(>svg){padding-inline:calc(var(--spacing)*2.5)}.has-\[\>svg\]\:px-3:has(>svg){padding-inline:calc(var(--spacing)*3)}.has-\[\>svg\]\:px-4:has(>svg){padding-inline:calc(var(--spacing)*4)}.aria-invalid\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}@media (min-width:48rem){.md\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}.dark\:border-input:is(.dark *){border-color:var(--input)}.dark\:bg-destructive\/60:is(.dark *){background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-destructive\/60:is(.dark *){background-color:color-mix(in oklab,var(--destructive)60%,transparent)}}.dark\:bg-input\/30:is(.dark *){background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-input\/30:is(.dark *){background-color:color-mix(in oklab,var(--input)30%,transparent)}}@media (hover:hover){.dark\:hover\:bg-accent\/50:is(.dark *):hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-accent\/50:is(.dark *):hover{background-color:color-mix(in oklab,var(--accent)50%,transparent)}}.dark\:hover\:bg-input\/50:is(.dark *):hover{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-input\/50:is(.dark *):hover{background-color:color-mix(in oklab,var(--input)50%,transparent)}}}.dark\:focus-visible\:ring-destructive\/40:is(.dark *):focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:focus-visible\:ring-destructive\/40:is(.dark *):focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.dark\:aria-invalid\:ring-destructive\/40:is(.dark *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:aria-invalid\:ring-destructive\/40:is(.dark *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4 svg:not([class*=size-]){width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.\[\.border-b\]\:pb-6.border-b{padding-bottom:calc(var(--spacing)*6)}.\[\.border-t\]\:pt-6.border-t{padding-top:calc(var(--spacing)*6)}}@property --tw-animation-delay{syntax:"*";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:"*";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:"*";inherits:false}@property --tw-animation-fill-mode{syntax:"*";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:"*";inherits:false;initial-value:0}#root{max-width:1280px;min-height:100vh;margin:0 auto;padding:0 2rem}:root{--radius:.625rem;--background:oklch(100% 0 0);--foreground:oklch(14.5% 0 0);--card:oklch(100% 0 0);--card-foreground:oklch(14.5% 0 0);--popover:oklch(100% 0 0);--popover-foreground:oklch(14.5% 0 0);--primary:oklch(20.5% 0 0);--primary-foreground:oklch(98.5% 0 0);--secondary:oklch(97% 0 0);--secondary-foreground:oklch(20.5% 0 0);--muted:oklch(97% 0 0);--muted-foreground:oklch(55.6% 0 0);--accent:oklch(97% 0 0);--accent-foreground:oklch(20.5% 0 0);--destructive:oklch(57.7% .245 27.325);--border:oklch(92.2% 0 0);--input:oklch(92.2% 0 0);--ring:oklch(70.8% 0 0);--chart-1:oklch(64.6% .222 41.116);--chart-2:oklch(60% .118 184.704);--chart-3:oklch(39.8% .07 227.392);--chart-4:oklch(82.8% .189 84.429);--chart-5:oklch(76.9% .188 70.08);--sidebar:oklch(98.5% 0 0);--sidebar-foreground:oklch(14.5% 0 0);--sidebar-primary:oklch(20.5% 0 0);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(97% 0 0);--sidebar-accent-foreground:oklch(20.5% 0 0);--sidebar-border:oklch(92.2% 0 0);--sidebar-ring:oklch(70.8% 0 0)}.dark{--background:oklch(14.5% 0 0);--foreground:oklch(98.5% 0 0);--card:oklch(20.5% 0 0);--card-foreground:oklch(98.5% 0 0);--popover:oklch(20.5% 0 0);--popover-foreground:oklch(98.5% 0 0);--primary:oklch(92.2% 0 0);--primary-foreground:oklch(20.5% 0 0);--secondary:oklch(26.9% 0 0);--secondary-foreground:oklch(98.5% 0 0);--muted:oklch(26.9% 0 0);--muted-foreground:oklch(70.8% 0 0);--accent:oklch(26.9% 0 0);--accent-foreground:oklch(98.5% 0 0);--destructive:oklch(70.4% .191 22.216);--border:oklch(100% 0 0/.1);--input:oklch(100% 0 0/.15);--ring:oklch(55.6% 0 0);--chart-1:oklch(48.8% .243 264.376);--chart-2:oklch(69.6% .17 162.48);--chart-3:oklch(76.9% .188 70.08);--chart-4:oklch(62.7% .265 303.9);--chart-5:oklch(64.5% .246 16.439);--sidebar:oklch(20.5% 0 0);--sidebar-foreground:oklch(98.5% 0 0);--sidebar-primary:oklch(48.8% .243 264.376);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(26.9% 0 0);--sidebar-accent-foreground:oklch(98.5% 0 0);--sidebar-border:oklch(100% 0 0/.1);--sidebar-ring:oklch(55.6% 0 0)}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-ease:initial;--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-600:oklch(57.7% .245 27.325);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-gray-600:oklch(44.6% .03 256.802);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--radius-2xl:1rem;--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){*{outline-color:color-mix(in oklab,var(--ring)50%,transparent)}}body{background-color:var(--background);color:var(--foreground)}}@layer components;@layer utilities{.\@container\/card-header{container:card-header/inline-size}.absolute{position:absolute}.relative{position:relative}.static{position:static}.bottom-0{bottom:calc(var(--spacing)*0)}.left-0{left:calc(var(--spacing)*0)}.col-start-2{grid-column-start:2}.row-span-2{grid-row:span 2/span 2}.row-start-1{grid-row-start:1}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-2{margin-top:calc(var(--spacing)*2)}.mr-1{margin-right:calc(var(--spacing)*1)}.mb-0\.5{margin-bottom:calc(var(--spacing)*.5)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.field-sizing-content{field-sizing:content}.aspect-square{aspect-ratio:1}.size-8{width:calc(var(--spacing)*8);height:calc(var(--spacing)*8)}.size-9{width:calc(var(--spacing)*9);height:calc(var(--spacing)*9)}.size-full{width:100%;height:100%}.h-0\.5{height:calc(var(--spacing)*.5)}.h-2{height:calc(var(--spacing)*2)}.h-4{height:calc(var(--spacing)*4)}.h-6{height:calc(var(--spacing)*6)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-10{height:calc(var(--spacing)*10)}.h-20{height:calc(var(--spacing)*20)}.h-full{height:100%}.max-h-48{max-height:calc(var(--spacing)*48)}.min-h-0{min-height:calc(var(--spacing)*0)}.min-h-16{min-height:calc(var(--spacing)*16)}.w-2{width:calc(var(--spacing)*2)}.w-4{width:calc(var(--spacing)*4)}.w-6{width:calc(var(--spacing)*6)}.w-8{width:calc(var(--spacing)*8)}.w-10{width:calc(var(--spacing)*10)}.w-full{width:100%}.max-w-full{max-width:100%}.max-w-prose{max-width:65ch}.min-w-0{min-width:calc(var(--spacing)*0)}.flex-0{flex:0}.flex-1{flex:1}.flex-shrink-1{flex-shrink:1}.shrink-0{flex-shrink:0}.basis-0{flex-basis:calc(var(--spacing)*0)}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.auto-rows-min{grid-auto-rows:min-content}.grid-rows-\[auto_auto\]{grid-template-rows:auto auto}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*6)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-x-1>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*1)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-x-reverse)))}.self-end{align-self:flex-end}.self-start{align-self:flex-start}.justify-self-end{justify-self:flex-end}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-xl{border-radius:calc(var(--radius) + 4px)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-input{border-color:var(--input)}.bg-accent{background-color:var(--accent)}.bg-background{background-color:var(--background)}.bg-blue-500{background-color:var(--color-blue-500)}.bg-card{background-color:var(--card)}.bg-current{background-color:currentColor}.bg-destructive{background-color:var(--destructive)}.bg-muted{background-color:var(--muted)}.bg-muted-foreground\/20{background-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.bg-muted-foreground\/20{background-color:color-mix(in oklab,var(--muted-foreground)20%,transparent)}}.bg-primary,.bg-primary\/20{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/20{background-color:color-mix(in oklab,var(--primary)20%,transparent)}}.bg-secondary{background-color:var(--secondary)}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.p-0{padding:calc(var(--spacing)*0)}.p-1{padding:calc(var(--spacing)*1)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.py-3{padding-block:calc(var(--spacing)*3)}.py-6{padding-block:calc(var(--spacing)*6)}.pr-1{padding-right:calc(var(--spacing)*1)}.pl-3{padding-left:calc(var(--spacing)*3)}.text-right{text-align:right}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-card-foreground{color:var(--card-foreground)}.text-current{color:currentColor}.text-gray-600{color:var(--color-gray-600)}.text-muted-foreground{color:var(--muted-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-red-600{color:var(--color-red-600)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-white{color:var(--color-white)}.underline-offset-4{text-underline-offset:4px}.shadow,.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-\[color\,box-shadow\]{transition-property:color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.group-data-\[disabled\=true\]\:pointer-events-none:is(:where(.group)[data-disabled=true] *){pointer-events:none}.group-data-\[disabled\=true\]\:opacity-50:is(:where(.group)[data-disabled=true] *){opacity:.5}.peer-disabled\:cursor-not-allowed:is(:where(.peer):disabled~*){cursor:not-allowed}.peer-disabled\:opacity-50:is(:where(.peer):disabled~*){opacity:.5}.selection\:bg-primary ::selection{background-color:var(--primary)}.selection\:bg-primary::selection{background-color:var(--primary)}.selection\:text-primary-foreground ::selection{color:var(--primary-foreground)}.selection\:text-primary-foreground::selection{color:var(--primary-foreground)}.file\:inline-flex::file-selector-button{display:inline-flex}.file\:h-7::file-selector-button{height:calc(var(--spacing)*7)}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:bg-transparent::file-selector-button{background-color:#0000}.file\:text-sm::file-selector-button{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\:text-foreground::file-selector-button{color:var(--foreground)}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.last\:mb-0:last-child{margin-bottom:calc(var(--spacing)*0)}@media (hover:hover){.hover\:bg-accent:hover{background-color:var(--accent)}.hover\:bg-blue-600:hover{background-color:var(--color-blue-600)}.hover\:bg-destructive\/90:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab,var(--destructive)90%,transparent)}}.hover\:bg-muted-foreground\/20:hover{background-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-muted-foreground\/20:hover{background-color:color-mix(in oklab,var(--muted-foreground)20%,transparent)}}.hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--primary)90%,transparent)}}.hover\:bg-secondary\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab,var(--secondary)80%,transparent)}}.hover\:text-accent-foreground:hover{color:var(--accent-foreground)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-\[3px\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(3px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.focus-visible\:ring-ring:focus-visible,.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab,var(--ring)50%,transparent)}}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.has-data-\[slot\=card-action\]\:grid-cols-\[1fr_auto\]:has([data-slot=card-action]){grid-template-columns:1fr auto}.has-\[\>svg\]\:px-2\.5:has(>svg){padding-inline:calc(var(--spacing)*2.5)}.has-\[\>svg\]\:px-3:has(>svg){padding-inline:calc(var(--spacing)*3)}.has-\[\>svg\]\:px-4:has(>svg){padding-inline:calc(var(--spacing)*4)}.aria-invalid\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}@media (min-width:48rem){.md\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}.dark\:border-input:is(.dark *){border-color:var(--input)}.dark\:bg-destructive\/60:is(.dark *){background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-destructive\/60:is(.dark *){background-color:color-mix(in oklab,var(--destructive)60%,transparent)}}.dark\:bg-input\/30:is(.dark *){background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-input\/30:is(.dark *){background-color:color-mix(in oklab,var(--input)30%,transparent)}}@media (hover:hover){.dark\:hover\:bg-accent\/50:is(.dark *):hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-accent\/50:is(.dark *):hover{background-color:color-mix(in oklab,var(--accent)50%,transparent)}}.dark\:hover\:bg-input\/50:is(.dark *):hover{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\:hover\:bg-input\/50:is(.dark *):hover{background-color:color-mix(in oklab,var(--input)50%,transparent)}}}.dark\:focus-visible\:ring-destructive\/40:is(.dark *):focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:focus-visible\:ring-destructive\/40:is(.dark *):focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.dark\:aria-invalid\:ring-destructive\/40:is(.dark *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\:aria-invalid\:ring-destructive\/40:is(.dark *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4 svg:not([class*=size-]){width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.\[\.border-b\]\:pb-6.border-b{padding-bottom:calc(var(--spacing)*6)}.\[\.border-t\]\:pt-6.border-t{padding-top:calc(var(--spacing)*6)}}@property --tw-animation-delay{syntax:"*";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:"*";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:"*";inherits:false}@property --tw-animation-fill-mode{syntax:"*";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:"*";inherits:false;initial-value:0}#root{max-width:1280px;min-height:100vh;margin:0 auto;padding:0 2rem}:root{--radius:.625rem;--background:oklch(100% 0 0);--foreground:oklch(14.5% 0 0);--card:oklch(100% 0 0);--card-foreground:oklch(14.5% 0 0);--popover:oklch(100% 0 0);--popover-foreground:oklch(14.5% 0 0);--primary:oklch(20.5% 0 0);--primary-foreground:oklch(98.5% 0 0);--secondary:oklch(97% 0 0);--secondary-foreground:oklch(20.5% 0 0);--muted:oklch(97% 0 0);--muted-foreground:oklch(55.6% 0 0);--accent:oklch(97% 0 0);--accent-foreground:oklch(20.5% 0 0);--destructive:oklch(57.7% .245 27.325);--border:oklch(92.2% 0 0);--input:oklch(92.2% 0 0);--ring:oklch(70.8% 0 0);--chart-1:oklch(64.6% .222 41.116);--chart-2:oklch(60% .118 184.704);--chart-3:oklch(39.8% .07 227.392);--chart-4:oklch(82.8% .189 84.429);--chart-5:oklch(76.9% .188 70.08);--sidebar:oklch(98.5% 0 0);--sidebar-foreground:oklch(14.5% 0 0);--sidebar-primary:oklch(20.5% 0 0);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(97% 0 0);--sidebar-accent-foreground:oklch(20.5% 0 0);--sidebar-border:oklch(92.2% 0 0);--sidebar-ring:oklch(70.8% 0 0)}.dark{--background:oklch(14.5% 0 0);--foreground:oklch(98.5% 0 0);--card:oklch(20.5% 0 0);--card-foreground:oklch(98.5% 0 0);--popover:oklch(20.5% 0 0);--popover-foreground:oklch(98.5% 0 0);--primary:oklch(92.2% 0 0);--primary-foreground:oklch(20.5% 0 0);--secondary:oklch(26.9% 0 0);--secondary-foreground:oklch(98.5% 0 0);--muted:oklch(26.9% 0 0);--muted-foreground:oklch(70.8% 0 0);--accent:oklch(26.9% 0 0);--accent-foreground:oklch(98.5% 0 0);--destructive:oklch(70.4% .191 22.216);--border:oklch(100% 0 0/.1);--input:oklch(100% 0 0/.15);--ring:oklch(55.6% 0 0);--chart-1:oklch(48.8% .243 264.376);--chart-2:oklch(69.6% .17 162.48);--chart-3:oklch(76.9% .188 70.08);--chart-4:oklch(62.7% .265 303.9);--chart-5:oklch(64.5% .246 16.439);--sidebar:oklch(20.5% 0 0);--sidebar-foreground:oklch(98.5% 0 0);--sidebar-primary:oklch(48.8% .243 264.376);--sidebar-primary-foreground:oklch(98.5% 0 0);--sidebar-accent:oklch(26.9% 0 0);--sidebar-accent-foreground:oklch(98.5% 0 0);--sidebar-border:oklch(100% 0 0/.1);--sidebar-ring:oklch(55.6% 0 0)}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meshagent/meshagent-tailwind",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Meshagent Tailwind Components",
5
5
  "homepage": "https://github.com/meshagent/meshagent-tailwind",
6
6
  "scripts": {
@@ -30,12 +30,14 @@
30
30
  "CHANGELOG.md"
31
31
  ],
32
32
  "dependencies": {
33
- "@meshagent/meshagent": "^0.5.0",
34
- "@meshagent/meshagent-react": "^0.5.0",
33
+ "@meshagent/meshagent": "^0.5.2",
34
+ "@meshagent/meshagent-react": "^0.5.2",
35
35
  "@radix-ui/react-avatar": "^1.1.10",
36
+ "@radix-ui/react-progress": "^1.1.7",
36
37
  "@radix-ui/react-slot": "^1.2.3",
37
38
  "class-variance-authority": "^0.7.1",
38
39
  "clsx": "^2.1.1",
40
+ "esbuild-plugin-alias": "^0.2.1",
39
41
  "lucide-react": "^0.525.0",
40
42
  "react": "^19.1.0",
41
43
  "react-dom": "^19.1.0",
@@ -70,4 +72,4 @@
70
72
  "typescript-eslint": "^8.34.1",
71
73
  "vite": "^7.0.0"
72
74
  }
73
- }
75
+ }