refactor(editor-panel): enhance layout and styling for improved usability

- Updated the EditorPanelContent to streamline the header layout and improve button styling for closing the panel.
- Adjusted the grid layout for better alignment and spacing, enhancing the overall user experience.
- Integrated a vertical separator with updated styling for a more cohesive design.
This commit is contained in:
Anish Sarkar 2026-07-06 16:12:38 +05:30
parent 4088289f95
commit 7a3f99c4f2
2 changed files with 87 additions and 72 deletions

View file

@ -574,28 +574,14 @@ export function EditorPanelContent({
<> <>
{showDesktopHeader ? ( {showDesktopHeader ? (
<div className="shrink-0"> <div className="shrink-0">
<div className="shrink-0 flex h-12 items-center justify-between px-3 border-b"> <div className="grid h-12 grid-cols-[minmax(0,1fr)_auto] items-center gap-3 border-b px-4">
<h2 className="select-none text-lg font-semibold">File</h2>
<div className="flex items-center gap-1 shrink-0">
<Button
variant="ghost"
size="icon"
onClick={onClose}
className="h-8 w-8 rounded-full shrink-0 text-muted-foreground hover:text-accent-foreground"
>
<XIcon className="h-4 w-4" />
<span className="sr-only">Close editor panel</span>
</Button>
</div>
</div>
<div className="grid h-10 grid-cols-[minmax(0,1fr)_auto] items-center gap-3 border-b px-4">
<div className="min-w-0 flex flex-1 items-center gap-2"> <div className="min-w-0 flex flex-1 items-center gap-2">
<p className="truncate text-sm text-muted-foreground">{displayTitle}</p> <p className="truncate text-sm text-muted-foreground">{displayTitle}</p>
{memoryLimitState && ( {memoryLimitState && (
<> <>
<Separator <Separator
orientation="vertical" orientation="vertical"
className="mx-1 bg-border data-[orientation=vertical]:h-4 data-[orientation=vertical]:w-px dark:bg-white/10" className="mx-1.5 bg-muted-foreground/20 data-[orientation=vertical]:h-4 data-[orientation=vertical]:w-px dark:bg-muted-foreground/25"
/> />
<span className={`shrink-0 text-xs ${memoryCounterClassName}`}> <span className={`shrink-0 text-xs ${memoryCounterClassName}`}>
{memoryLimitState.label} {memoryLimitState.label}
@ -671,6 +657,19 @@ export function EditorPanelContent({
)} )}
</> </>
)} )}
<Separator
orientation="vertical"
className="mx-1.5 bg-muted-foreground/20 data-[orientation=vertical]:h-4 data-[orientation=vertical]:w-px dark:bg-muted-foreground/25"
/>
<Button
variant="ghost"
size="icon"
onClick={onClose}
className="size-6 shrink-0 rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground"
>
<XIcon className="size-4" />
<span className="sr-only">Close editor panel</span>
</Button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -2,6 +2,7 @@
import { useAtom, useAtomValue, useSetAtom } from "jotai"; import { useAtom, useAtomValue, useSetAtom } from "jotai";
import { PanelRight } from "lucide-react"; import { PanelRight } from "lucide-react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { startTransition, useEffect } from "react"; import { startTransition, useEffect } from "react";
import { closeReportPanelAtom, reportPanelAtom } from "@/atoms/chat/report-panel.atom"; import { closeReportPanelAtom, reportPanelAtom } from "@/atoms/chat/report-panel.atom";
@ -161,6 +162,11 @@ const PANEL_WIDTHS = {
artifacts: 420, artifacts: 420,
} as const; } as const;
const PANEL_SLIDE_TRANSITION = {
duration: 0.2,
ease: [0.22, 1, 0.36, 1],
} as const;
/** /**
* Priority order used to fall back to another open surface when the active * Priority order used to fall back to another open surface when the active
* tab's content closes. The neutral "sources" tab is kept as the closed state. * tab's content closes. The neutral "sources" tab is kept as the closed state.
@ -195,6 +201,7 @@ export function RightPanel({ showTopBorder = false }: RightPanelProps) {
const artifactsOpen = useAtomValue(artifactsPanelOpenAtom); const artifactsOpen = useAtomValue(artifactsPanelOpenAtom);
const closeArtifacts = useSetAtom(closeArtifactsPanelAtom); const closeArtifacts = useSetAtom(closeArtifactsPanelAtom);
const [collapsed] = useAtom(rightPanelCollapsedAtom); const [collapsed] = useAtom(rightPanelCollapsedAtom);
const reduceMotion = useReducedMotion();
const reportOpen = reportState.isOpen && !!reportState.reportId; const reportOpen = reportState.isOpen && !!reportState.reportId;
const editorOpen = const editorOpen =
@ -246,64 +253,73 @@ export function RightPanel({ showTopBorder = false }: RightPanelProps) {
}); });
const targetWidth = PANEL_WIDTHS[effectiveTab]; const targetWidth = PANEL_WIDTHS[effectiveTab];
if (!isVisible) return null;
return ( return (
<aside <AnimatePresence initial={false}>
style={{ width: targetWidth }} {isVisible ? (
className={cn( <motion.aside
"flex h-full shrink-0 flex-col border-l bg-panel text-sidebar-foreground overflow-hidden transition-[width] duration-200 ease-out", key="right-panel"
showTopBorder && "border-t" initial={reduceMotion ? { width: targetWidth } : { width: 0, x: 24, opacity: 0 }}
)} animate={{ width: targetWidth, x: 0, opacity: 1 }}
> exit={reduceMotion ? { width: 0 } : { width: 0, x: 24, opacity: 0 }}
<div className="relative flex-1 min-h-0 overflow-hidden"> transition={reduceMotion ? { duration: 0 } : PANEL_SLIDE_TRANSITION}
{effectiveTab === "report" && reportOpen && ( className={cn(
<div className="h-full flex flex-col"> "flex h-full shrink-0 flex-col overflow-hidden border-l bg-panel text-sidebar-foreground",
<ReportPanelContent showTopBorder && "border-t"
reportId={reportState.reportId as number} )}
title={reportState.title || "Report"} >
onClose={closeReport} <div style={{ width: targetWidth }} className="flex h-full min-h-0 flex-col">
shareToken={reportState.shareToken} <div className="relative flex-1 min-h-0 overflow-hidden">
/> {effectiveTab === "report" && reportOpen && (
<div className="h-full flex flex-col">
<ReportPanelContent
reportId={reportState.reportId as number}
title={reportState.title || "Report"}
onClose={closeReport}
shareToken={reportState.shareToken}
/>
</div>
)}
{effectiveTab === "editor" && editorOpen && (
<div className="h-full flex flex-col">
<EditorPanelContent
kind={editorState.kind}
documentId={editorState.documentId ?? undefined}
localFilePath={editorState.localFilePath ?? undefined}
memoryScope={editorState.memoryScope ?? undefined}
workspaceId={editorState.workspaceId ?? undefined}
title={editorState.title}
onClose={closeEditor}
/>
</div>
)}
{effectiveTab === "hitl-edit" && hitlEditOpen && hitlEditState.onSave && (
<div className="h-full flex flex-col">
<HitlEditPanelContent
title={hitlEditState.title}
content={hitlEditState.content}
toolName={hitlEditState.toolName}
contentFormat={hitlEditState.contentFormat}
extraFields={hitlEditState.extraFields}
onSave={hitlEditState.onSave}
onClose={closeHitlEdit}
/>
</div>
)}
{effectiveTab === "citation" && citationOpen && citationState.chunkId != null && (
<div className="h-full flex flex-col">
<CitationPanelContent chunkId={citationState.chunkId} onClose={closeCitation} />
</div>
)}
{effectiveTab === "artifacts" && artifactsOpen && (
<div className="h-full flex flex-col">
<ArtifactsPanelContent onClose={closeArtifacts} />
</div>
)}
</div>
</div> </div>
)} </motion.aside>
{effectiveTab === "editor" && editorOpen && ( ) : null}
<div className="h-full flex flex-col"> </AnimatePresence>
<EditorPanelContent
kind={editorState.kind}
documentId={editorState.documentId ?? undefined}
localFilePath={editorState.localFilePath ?? undefined}
memoryScope={editorState.memoryScope ?? undefined}
workspaceId={editorState.workspaceId ?? undefined}
title={editorState.title}
onClose={closeEditor}
/>
</div>
)}
{effectiveTab === "hitl-edit" && hitlEditOpen && hitlEditState.onSave && (
<div className="h-full flex flex-col">
<HitlEditPanelContent
title={hitlEditState.title}
content={hitlEditState.content}
toolName={hitlEditState.toolName}
contentFormat={hitlEditState.contentFormat}
extraFields={hitlEditState.extraFields}
onSave={hitlEditState.onSave}
onClose={closeHitlEdit}
/>
</div>
)}
{effectiveTab === "citation" && citationOpen && citationState.chunkId != null && (
<div className="h-full flex flex-col">
<CitationPanelContent chunkId={citationState.chunkId} onClose={closeCitation} />
</div>
)}
{effectiveTab === "artifacts" && artifactsOpen && (
<div className="h-full flex flex-col">
<ArtifactsPanelContent onClose={closeArtifacts} />
</div>
)}
</div>
</aside>
); );
} }