import { useState } from "react";
import { ChatBubbleList, type ChatMessageProp } from "@godxjp/ui/data-display";
import { ChatComposer } from "@godxjp/ui/data-entry";
import { Text } from "@godxjp/ui/general";
import {
AppShell,
Flex,
MasterDetail,
PageContainer,
Sidebar,
type SidebarSectionProp,
Topbar,
} from "@godxjp/ui/layout";
import { Conversations, type ConversationsEntryProp } from "@godxjp/ui/navigation";
import { Bot, MessageSquare, Pencil, Settings, Trash2, Users } from "lucide-react";
/**
* Conversations — the session rail of a chat surface (Ant Design X `Conversations`).
*
* This page is the whole surface gh#559 is about: the rail on the left, the feed and the composer
* on the right. They were shipped one half at a time, and the missing half is why every consumer
* hand-rolled a stack of full-width Buttons — one tab stop per conversation, no per-row menu, no
* recency buckets.
*
* The three cards below are one axis each, at rest, so the API is visible without clicking:
* the live surface, the recency buckets (`groupable`), and the flat rail with a divider and a
* disabled row. Composed only from real @godxjp/ui components.
*/
const sections: SidebarSectionProp[] = [
{
label: "アシスタント",
items: [
{ id: "chat", label: "チャット", icon: MessageSquare },
{ id: "agents", label: "エージェント", icon: Bot },
{ id: "members", label: "メンバー", icon: Users },
],
},
{ label: "管理", items: [{ id: "settings", label: "設定", icon: Settings }] },
];
/** The rail's data, bucketed by recency — the `group` field is what `groupable` reads. */
const HISTORY: ConversationsEntryProp[] = [
{ key: "invoice", label: "請求書の下書きを直す", group: "今日" },
{ key: "expense", label: "経費精算の規則をまとめる", group: "今日" },
{ key: "travel", label: "出張手当の確認", group: "過去7日間" },
{ key: "onboarding", label: "入社手続きのチェックリスト", group: "過去7日間" },
{ key: "payroll", label: "給与計算の締め日について", group: "それ以前" },
];
/** A flat rail — no buckets, one rule, one archived row. */
const FLAT: ConversationsEntryProp[] = [
{ key: "invoice", label: "請求書の下書きを直す", icon: },
{ key: "expense", label: "経費精算の規則をまとめる", icon: },
{ type: "divider", key: "rule" },
{ key: "archived", label: "アーカイブ済みの相談", icon: , disabled: true },
];
const TRANSCRIPT: Record = {
invoice: [
{ id: "m1", role: "user", content: "先月分の請求書の下書きを直したいです。" },
{
id: "m2",
role: "assistant",
content: "差分は3件でした。金額、支払期日、宛名のうちどれから直しますか。",
},
],
expense: [
{ id: "m1", role: "user", content: "経費精算の規則を3行でまとめてください。" },
{
id: "m2",
role: "assistant",
content: "領収書は原本、申請は当月末まで、3万円以上は事前承認が要ります。",
},
],
};
export default function ConversationsDoc() {
const [active, setActive] = useState("invoice");
const [draft, setDraft] = useState("");
const menu = {
items: [
{ key: "rename", label: "名前を変更", icon: },
{ key: "delete", label: "削除", icon: , danger: true },
],
};
return (
{}}
product={{ name: "CoreDesk", role: "アシスタント", color: "hsl(var(--primary))" }}
/>
}
topbar={}
>
{/* THE SURFACE. The rail is the master; the feed and the composer are the detail. */}
setActive("invoice") }}
menu={menu}
/>
}
>
setDraft("")}
placeholder="メッセージを入力"
/>
{/* BUCKETS, EXPANDED. `groupable` with no options groups but never collapses. */}
recency buckets · groupable
バケットの見出しは同じローヴィング順に入るので、畳む操作もレールを離れずに届く。
{/* FLAT, WITH A RULE AND A DISABLED ROW. */}
flat rail · divider and a disabled row
無効な行は見えるが選べず、矢印キーの巡回からも外れる。無効なコントロールは
フォーカスを受け取らないため。
);
}