修改
This commit is contained in:
@@ -41,6 +41,7 @@ import {
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
import { Sheet, SheetContent, SheetTitle } from "@/components/ui/sheet";
|
||||
import {
|
||||
ACTIVE_SESSION_CHANGED_EVENT,
|
||||
readActiveSessionId,
|
||||
@@ -140,7 +141,7 @@ type ActivityItem = {
|
||||
|
||||
type LiveRunEvent = NonNullable<ClawRunStatus["events"]>[number];
|
||||
|
||||
export function ActivityPanel() {
|
||||
export function ActivityPanel({ asDrawer = false }: { asDrawer?: boolean } = {}) {
|
||||
const {
|
||||
open,
|
||||
mode,
|
||||
@@ -221,20 +222,12 @@ export function ActivityPanel() {
|
||||
prevLatestIdRef.current = latestId;
|
||||
}, [items, mode, openActivity, selectedId]);
|
||||
|
||||
if (!open) return null;
|
||||
if (!asDrawer && !open) return null;
|
||||
|
||||
if (mode === "files") {
|
||||
return (
|
||||
<SessionFilesPanel
|
||||
key={`${sessionId ?? "active"}:${filesRefreshToken}`}
|
||||
sessionId={sessionId}
|
||||
onClose={close}
|
||||
/>
|
||||
);
|
||||
}
|
||||
const isFilesMode = mode === "files";
|
||||
|
||||
return (
|
||||
<aside className="fixed inset-y-0 right-0 z-30 flex w-[min(23rem,calc(100vw-1rem))] flex-col border-l bg-background shadow-xl lg:static lg:z-auto lg:h-full lg:w-92 lg:shrink-0 lg:shadow-none">
|
||||
const activityBody = (
|
||||
<>
|
||||
<header className="flex h-16 shrink-0 items-center justify-between border-b px-4">
|
||||
<div className="min-w-0">
|
||||
<h2 className="font-semibold text-base">活动</h2>
|
||||
@@ -244,16 +237,18 @@ export function ActivityPanel() {
|
||||
: "暂无链路"}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-8"
|
||||
onClick={close}
|
||||
aria-label="关闭活动面板"
|
||||
>
|
||||
<PanelRightCloseIcon className="size-4" />
|
||||
</Button>
|
||||
{!asDrawer ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-8"
|
||||
onClick={close}
|
||||
aria-label="关闭活动面板"
|
||||
>
|
||||
<PanelRightCloseIcon className="size-4" />
|
||||
</Button>
|
||||
) : null}
|
||||
</header>
|
||||
<div className="min-h-0 flex-1 overflow-y-auto px-4 py-4">
|
||||
{visibleItems.length === 0 ? (
|
||||
@@ -280,6 +275,52 @@ export function ActivityPanel() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
if (asDrawer) {
|
||||
return (
|
||||
<Sheet
|
||||
open={open}
|
||||
onOpenChange={(next) => {
|
||||
if (!next) close();
|
||||
}}
|
||||
>
|
||||
<SheetContent
|
||||
side="right"
|
||||
className="flex w-[min(25rem,calc(100vw-1rem))] flex-col gap-0 p-0 sm:max-w-md"
|
||||
>
|
||||
<SheetTitle className="sr-only">
|
||||
{isFilesMode ? "聊天中的文件" : "活动"}
|
||||
</SheetTitle>
|
||||
{isFilesMode ? (
|
||||
<SessionFilesPanel
|
||||
key={`drawer:${sessionId ?? "active"}:${filesRefreshToken}`}
|
||||
sessionId={sessionId}
|
||||
onClose={close}
|
||||
embedded
|
||||
/>
|
||||
) : (
|
||||
activityBody
|
||||
)}
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
|
||||
if (isFilesMode) {
|
||||
return (
|
||||
<SessionFilesPanel
|
||||
key={`${sessionId ?? "active"}:${filesRefreshToken}`}
|
||||
sessionId={sessionId}
|
||||
onClose={close}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className="fixed inset-y-0 right-0 z-30 flex w-[min(23rem,calc(100vw-1rem))] flex-col border-l bg-background shadow-xl lg:static lg:z-auto lg:h-full lg:w-92 lg:shrink-0 lg:shadow-none">
|
||||
{activityBody}
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
@@ -308,9 +349,11 @@ type SessionFilesPayload = {
|
||||
function SessionFilesPanel({
|
||||
sessionId,
|
||||
onClose,
|
||||
embedded = false,
|
||||
}: {
|
||||
sessionId: string | null;
|
||||
onClose: () => void;
|
||||
embedded?: boolean;
|
||||
}) {
|
||||
const [payload, setPayload] = useState<SessionFilesPayload | null>(null);
|
||||
const [status, setStatus] = useState("正在读取聊天中的文件...");
|
||||
@@ -377,8 +420,8 @@ function SessionFilesPanel({
|
||||
const outputFiles = payload?.output ?? [];
|
||||
const total = inputFiles.length + outputFiles.length;
|
||||
|
||||
return (
|
||||
<aside className="fixed inset-y-0 right-0 z-30 flex w-[min(25rem,calc(100vw-1rem))] flex-col border-l bg-background shadow-xl lg:static lg:z-auto lg:h-full lg:w-96 lg:shrink-0 lg:shadow-none">
|
||||
const body = (
|
||||
<>
|
||||
<header className="flex h-16 shrink-0 items-center justify-between border-b px-4">
|
||||
<div className="min-w-0">
|
||||
<h2 className="font-semibold text-base">聊天中的文件</h2>
|
||||
@@ -386,16 +429,18 @@ function SessionFilesPanel({
|
||||
{status || `${total} 个文件`}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-8"
|
||||
onClick={onClose}
|
||||
aria-label="关闭文件面板"
|
||||
>
|
||||
<PanelRightCloseIcon className="size-4" />
|
||||
</Button>
|
||||
{!embedded ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-8"
|
||||
onClick={onClose}
|
||||
aria-label="关闭文件面板"
|
||||
>
|
||||
<PanelRightCloseIcon className="size-4" />
|
||||
</Button>
|
||||
) : null}
|
||||
</header>
|
||||
<div className="min-h-0 flex-1 overflow-y-auto px-4 py-4">
|
||||
{!status && total === 0 ? (
|
||||
@@ -406,6 +451,16 @@ function SessionFilesPanel({
|
||||
<FileSection title="输入" files={inputFiles} />
|
||||
<FileSection title="输出" files={outputFiles} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
if (embedded) {
|
||||
return <div className="flex min-h-0 flex-1 flex-col">{body}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className="fixed inset-y-0 right-0 z-30 flex w-[min(25rem,calc(100vw-1rem))] flex-col border-l bg-background shadow-xl lg:static lg:z-auto lg:h-full lg:w-96 lg:shrink-0 lg:shadow-none">
|
||||
{body}
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user