- SheetTrigger: remove asChild (base-ui doesn't support it) - ComposeBox: use plain buttons with cn() instead of ToggleGroup (API mismatch) - Remove unused Button import from App Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
108 lines
3.0 KiB
TypeScript
108 lines
3.0 KiB
TypeScript
import { useState } from "react";
|
|
import type { MessageType } from "@/types/MessageType";
|
|
import { postMessage } from "@/api";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface Props {
|
|
channelId: string;
|
|
replyTo: string | null;
|
|
onClearReply: () => void;
|
|
onMessageSent: () => void;
|
|
}
|
|
|
|
const MSG_TYPES: { value: MessageType; label: string }[] = [
|
|
{ value: "text", label: "T" },
|
|
{ value: "code", label: "C" },
|
|
{ value: "result", label: "R" },
|
|
{ value: "error", label: "E" },
|
|
{ value: "plan", label: "P" },
|
|
];
|
|
|
|
export function ComposeBox({
|
|
channelId,
|
|
replyTo,
|
|
onClearReply,
|
|
onMessageSent,
|
|
}: Props) {
|
|
const [content, setContent] = useState("");
|
|
const [msgType, setMsgType] = useState<MessageType>("text");
|
|
const [sending, setSending] = useState(false);
|
|
|
|
async function handleSend() {
|
|
if (!content.trim() || sending) return;
|
|
setSending(true);
|
|
try {
|
|
await postMessage(channelId, {
|
|
content: content.trim(),
|
|
type: msgType,
|
|
reply_to: replyTo ?? undefined,
|
|
});
|
|
setContent("");
|
|
setMsgType("text");
|
|
onClearReply();
|
|
onMessageSent();
|
|
} finally {
|
|
setSending(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="border-t border-border bg-card px-3 py-2 md:px-4 md:py-3 pb-[env(safe-area-inset-bottom,8px)]">
|
|
{replyTo && (
|
|
<div className="flex items-center gap-2 mb-1.5 text-xs text-muted-foreground">
|
|
<span>^ #{replyTo.slice(0, 8)}</span>
|
|
<Button variant="ghost" size="sm" onClick={onClearReply} className="h-6 px-1 text-xs">
|
|
[x]
|
|
</Button>
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex items-center gap-1.5 md:gap-2">
|
|
{/* Type selector */}
|
|
<div className="flex gap-0.5 rounded-md border border-border p-0.5">
|
|
{MSG_TYPES.map((t) => (
|
|
<button
|
|
type="button"
|
|
key={t.value}
|
|
onClick={() => setMsgType(t.value)}
|
|
className={cn(
|
|
"h-7 w-7 md:h-6 md:w-6 rounded-sm text-xs font-bold transition-colors",
|
|
msgType === t.value
|
|
? "bg-primary text-primary-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
)}
|
|
>
|
|
{t.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
<Input
|
|
value={content}
|
|
onChange={(e) => setContent(e.target.value)}
|
|
onKeyDown={(e) => {
|
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
e.preventDefault();
|
|
handleSend();
|
|
}
|
|
}}
|
|
placeholder="message..."
|
|
disabled={sending}
|
|
className="flex-1 h-9 md:h-8 text-sm"
|
|
/>
|
|
|
|
<Button
|
|
onClick={handleSend}
|
|
disabled={sending || !content.trim()}
|
|
size="sm"
|
|
className="h-9 md:h-8 px-3 text-xs font-bold"
|
|
>
|
|
{sending ? "..." : "SEND"}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|