From 95cbca1b271034b12fd3359d73c7d7d7db7546fb Mon Sep 17 00:00:00 2001 From: Arthur Belleville Date: Sun, 12 Apr 2026 14:10:04 +0200 Subject: [PATCH] feat(chat-ui): add feature components with xtablo theming --- packages/chat-ui/src/components/features.tsx | 508 +++++++++++++++++++ 1 file changed, 508 insertions(+) create mode 100644 packages/chat-ui/src/components/features.tsx diff --git a/packages/chat-ui/src/components/features.tsx b/packages/chat-ui/src/components/features.tsx new file mode 100644 index 0000000..b3589db --- /dev/null +++ b/packages/chat-ui/src/components/features.tsx @@ -0,0 +1,508 @@ +import * as React from "react" +import { cn } from "@xtablo/shared" +import { + X, + Search, + Pin, + ChevronDown, + ChevronRight, + ArrowUp, + ArrowDown, + Trash2, + Check, +} from "lucide-react" +import type { ChatMessageData } from "../types" +import { formatTimestamp } from "../hooks" + +// ─── ChatForwardDialog ──────────────────────────────────────────────────────── + +interface Conversation { + id: string + title: string + avatar?: string +} + +interface ChatForwardDialogProps { + message: ChatMessageData + conversations: Conversation[] + onForward: (targetIds: string[]) => void + onCancel: () => void + className?: string +} + +function ChatForwardDialog({ + message, + conversations, + onForward, + onCancel, + className, +}: ChatForwardDialogProps) { + const [query, setQuery] = React.useState("") + const [selected, setSelected] = React.useState>(new Set()) + + const filtered = conversations.filter((c) => + c.title.toLowerCase().includes(query.toLowerCase()) + ) + + const toggle = (id: string) => { + setSelected((prev) => { + const next = new Set(prev) + if (next.has(id)) next.delete(id) + else next.add(id) + return next + }) + } + + return ( +
+
+ {/* Header */} +
+ Forward message + +
+ + {/* Preview */} +
+ {message.senderName} +

{message.text}

+
+ + {/* Search */} +
+
+ + setQuery(e.target.value)} + placeholder="Search conversations..." + className="flex-1 bg-transparent text-[13px] text-foreground placeholder:text-muted-foreground/60 outline-none" + /> +
+
+ + {/* Conversation list */} +
+ {filtered.map((c) => ( + + ))} +
+ + {/* Actions */} +
+ + +
+
+
+ ) +} + +// ─── ChatEditComposer (inline edit mode) ────────────────────────────────────── + +interface ChatEditComposerProps { + message: ChatMessageData + onSave: (messageId: string, newText: string) => void + onCancel: () => void + className?: string +} + +function ChatEditComposer({ + message, + onSave, + onCancel, + className, +}: ChatEditComposerProps) { + const [value, setValue] = React.useState(message.text || "") + + return ( +
+ {/* Edit bar */} +
+ Editing message + +
+
+