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 ? (
<div className="shrink-0">
<div className="shrink-0 flex h-12 items-center justify-between px-3 border-b">
<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="grid h-12 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">
<p className="truncate text-sm text-muted-foreground">{displayTitle}</p>
{memoryLimitState && (
<>
<Separator
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}`}>
{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>

View file

@ -2,6 +2,7 @@
import { useAtom, useAtomValue, useSetAtom } from "jotai";
import { PanelRight } from "lucide-react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
import dynamic from "next/dynamic";
import { startTransition, useEffect } from "react";
import { closeReportPanelAtom, reportPanelAtom } from "@/atoms/chat/report-panel.atom";
@ -161,6 +162,11 @@ const PANEL_WIDTHS = {
artifacts: 420,
} 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
* 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 closeArtifacts = useSetAtom(closeArtifactsPanelAtom);
const [collapsed] = useAtom(rightPanelCollapsedAtom);
const reduceMotion = useReducedMotion();
const reportOpen = reportState.isOpen && !!reportState.reportId;
const editorOpen =
@ -246,64 +253,73 @@ export function RightPanel({ showTopBorder = false }: RightPanelProps) {
});
const targetWidth = PANEL_WIDTHS[effectiveTab];
if (!isVisible) return null;
return (
<aside
style={{ width: targetWidth }}
className={cn(
"flex h-full shrink-0 flex-col border-l bg-panel text-sidebar-foreground overflow-hidden transition-[width] duration-200 ease-out",
showTopBorder && "border-t"
)}
>
<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}
/>
<AnimatePresence initial={false}>
{isVisible ? (
<motion.aside
key="right-panel"
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 }}
transition={reduceMotion ? { duration: 0 } : PANEL_SLIDE_TRANSITION}
className={cn(
"flex h-full shrink-0 flex-col overflow-hidden border-l bg-panel text-sidebar-foreground",
showTopBorder && "border-t"
)}
>
<div style={{ width: targetWidth }} className="flex h-full min-h-0 flex-col">
<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>
)}
{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>
</aside>
</motion.aside>
) : null}
</AnimatePresence>
);
}