feat: redesign persisted session summaries

This commit is contained in:
2026-07-23 15:35:31 +02:00
parent 12c7a976d7
commit 0db85e4e4e
12 changed files with 1090 additions and 71 deletions
+36 -8
View File
@@ -4,6 +4,7 @@ import { WidgetHost } from "./WidgetHost";
import { CentralStatus } from "./CentralStatus";
import { ModelActivityPanel } from "./ModelActivityPanel";
import { useActivityPanelResize } from "./useActivityPanelResize";
import { useSessionPanelResize } from "./useSessionPanelResize";
import { NavSessions } from "./NavSessions";
import { SessionMenu } from "./SessionMenu";
import { SessionDocumentsPanel } from "./SessionDocumentsPanel";
@@ -37,7 +38,20 @@ import type { CSSProperties } from "react";
* portal's left sidebar, and the workflow phases ride a slim strip above the chat.
*/
export function AppShell() {
const { containerRef, panelWidth, desktopSplit, resizing, separatorProps } = useActivityPanelResize();
const [panelSession, setPanelSession] = useState<SessionSummary | null>(null);
const {
containerRef,
panelWidth,
desktopSplit,
resizing: activityResizing,
separatorProps: activitySeparatorProps,
} = useActivityPanelResize();
const {
panelWidth: sessionPanelWidth,
desktopSplit: sessionDesktopSplit,
resizing: sessionResizing,
separatorProps: sessionSeparatorProps,
} = useSessionPanelResize(containerRef, panelSession !== null);
// Publish the app area's horizontal geometry as CSS vars on <html>: when the app
// is embedded beside the portal's left sidebar, viewport-fixed dialogs (dialog.tsx)
// must center on the ThothII area, not on the whole browser window.
@@ -61,8 +75,9 @@ export function AppShell() {
doc.style.removeProperty("--app-area-width");
};
}, [containerRef]);
const activityWidthStyle = {
const panelWidthsStyle = {
"--activity-panel-width": `${panelWidth}px`,
"--session-panel-width": `${sessionPanelWidth}px`,
} as CSSProperties;
const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
const activeSessionIdRef = useRef<string | null>(null);
@@ -83,7 +98,6 @@ export function AppShell() {
const composerRef = useRef<HTMLTextAreaElement>(null);
const queryClient = useQueryClient();
const [panelSession, setPanelSession] = useState<SessionSummary | null>(null);
const [showActivity, setShowActivity] = useState(false);
const [activeOpen, setActiveOpen] = useState(true);
const [archiveOpen, setArchiveOpen] = useState(false);
@@ -448,13 +462,14 @@ export function AppShell() {
return (
<div
ref={containerRef}
style={activityWidthStyle}
style={panelWidthsStyle}
data-testid="app-shell"
data-activity-layout={showActivity ? "open" : "closed"}
data-activity-resizing={resizing}
data-activity-resizing={activityResizing}
data-session-resizing={sessionResizing}
className={[
"flex h-screen bg-background text-foreground",
resizing ? "select-none cursor-col-resize" : "",
activityResizing || sessionResizing ? "select-none cursor-col-resize" : "",
].join(" ")}
>
{panelSession && (
@@ -462,15 +477,28 @@ export function AppShell() {
session={panelSession}
onClose={() => setPanelSession(null)}
onResume={doResume}
desktopSplit={sessionDesktopSplit}
/>
)}
{panelSession && sessionDesktopSplit && (
<div className="relative w-0 shrink-0">
<div
{...sessionSeparatorProps}
data-testid="session-resize-handle"
data-dragging={sessionResizing}
className="group absolute inset-y-0 left-1/2 z-30 w-3 -translate-x-1/2 touch-none cursor-col-resize outline-none"
>
<span className="absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-border transition-colors group-hover:bg-primary/60 group-focus-visible:bg-primary group-data-[dragging=true]:bg-primary" />
</div>
</div>
)}
{showActivity && <ModelActivityPanel desktopSplit={desktopSplit} onClose={() => setShowActivity(false)} />}
{showActivity && desktopSplit && (
<div className="relative w-0 shrink-0">
<div
{...separatorProps}
{...activitySeparatorProps}
data-testid="activity-resize-handle"
data-dragging={resizing}
data-dragging={activityResizing}
className="group absolute inset-y-0 left-1/2 z-20 w-3 -translate-x-1/2 touch-none cursor-col-resize outline-none"
>
<span className="absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-border transition-colors group-hover:bg-primary/60 group-focus-visible:bg-primary group-data-[dragging=true]:bg-primary" />