mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-19 18:45:15 +02:00
refactor: improve UI consistency by standardizing header and sidebar component heights, and enhance right panel functionality with expanded button integration
This commit is contained in:
parent
b5cc45e819
commit
7632291731
7 changed files with 73 additions and 57 deletions
|
|
@ -1,20 +1,20 @@
|
|||
"use client";
|
||||
|
||||
import { useAtom, useAtomValue } from "jotai";
|
||||
import { PanelRight } from "lucide-react";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { hitlEditPanelAtom } from "@/atoms/chat/hitl-edit-panel.atom";
|
||||
import { currentThreadAtom } from "@/atoms/chat/current-thread.atom";
|
||||
import { reportPanelAtom } from "@/atoms/chat/report-panel.atom";
|
||||
import { documentsSidebarOpenAtom } from "@/atoms/documents/ui.atoms";
|
||||
import { editorPanelAtom } from "@/atoms/editor/editor-panel.atom";
|
||||
import { rightPanelCollapsedAtom } from "@/atoms/layout/right-panel.atom";
|
||||
import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms";
|
||||
import { activeTabAtom } from "@/atoms/tabs/tabs.atom";
|
||||
import { activeTabAtom, tabsAtom } from "@/atoms/tabs/tabs.atom";
|
||||
import { ChatHeader } from "@/components/new-chat/chat-header";
|
||||
import { ChatShareButton } from "@/components/new-chat/chat-share-button";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import type { ChatVisibility, ThreadRecord } from "@/lib/chat/thread-persistence";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface HeaderProps {
|
||||
mobileMenuTrigger?: React.ReactNode;
|
||||
|
|
@ -25,9 +25,20 @@ export function Header({ mobileMenuTrigger }: HeaderProps) {
|
|||
const searchSpaceId = useAtomValue(activeSearchSpaceIdAtom);
|
||||
const isMobile = useIsMobile();
|
||||
const activeTab = useAtomValue(activeTabAtom);
|
||||
const tabs = useAtomValue(tabsAtom);
|
||||
const collapsed = useAtomValue(rightPanelCollapsedAtom);
|
||||
const documentsOpen = useAtomValue(documentsSidebarOpenAtom);
|
||||
const reportState = useAtomValue(reportPanelAtom);
|
||||
const editorState = useAtomValue(editorPanelAtom);
|
||||
const hitlEditState = useAtomValue(hitlEditPanelAtom);
|
||||
|
||||
const isChatPage = pathname?.includes("/new-chat") ?? false;
|
||||
const isDocumentTab = activeTab?.type === "document";
|
||||
const reportOpen = reportState.isOpen && !!reportState.reportId;
|
||||
const editorOpen = editorState.isOpen && !!editorState.documentId;
|
||||
const hitlEditOpen = hitlEditState.isOpen && !!hitlEditState.onSave;
|
||||
const showExpandButton = !isMobile && collapsed && (documentsOpen || reportOpen || editorOpen || hitlEditOpen);
|
||||
const hasTabBar = tabs.length > 1;
|
||||
|
||||
const currentThreadState = useAtomValue(currentThreadAtom);
|
||||
|
||||
|
|
@ -49,15 +60,8 @@ export function Header({ mobileMenuTrigger }: HeaderProps) {
|
|||
|
||||
const handleVisibilityChange = (_visibility: ChatVisibility) => {};
|
||||
|
||||
const [collapsed, setCollapsed] = useAtom(rightPanelCollapsedAtom);
|
||||
const documentsOpen = useAtomValue(documentsSidebarOpenAtom);
|
||||
const reportState = useAtomValue(reportPanelAtom);
|
||||
const reportOpen = reportState.isOpen && !!reportState.reportId;
|
||||
const hasRightPanelContent = documentsOpen || reportOpen;
|
||||
const showExpandButton = !isMobile && collapsed && hasRightPanelContent;
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-10 flex h-14 shrink-0 items-center gap-2 bg-main-panel/95 backdrop-blur supports-backdrop-filter:bg-main-panel/60 px-4">
|
||||
<header className="sticky top-0 z-10 flex h-12 shrink-0 items-center gap-2 bg-main-panel/95 backdrop-blur supports-backdrop-filter:bg-main-panel/60 px-4">
|
||||
{/* Left side - Mobile menu trigger + Model selector */}
|
||||
<div className="flex flex-1 items-center gap-2 min-w-0">
|
||||
{mobileMenuTrigger}
|
||||
|
|
@ -67,26 +71,10 @@ export function Header({ mobileMenuTrigger }: HeaderProps) {
|
|||
</div>
|
||||
|
||||
{/* Right side - Actions */}
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={cn("ml-auto flex items-center gap-2", showExpandButton && !hasTabBar && "mr-10")}>
|
||||
{hasThread && (
|
||||
<ChatShareButton thread={threadForButton} onVisibilityChange={handleVisibilityChange} />
|
||||
)}
|
||||
{showExpandButton && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setCollapsed(false)}
|
||||
className="h-8 w-8 shrink-0"
|
||||
>
|
||||
<PanelRight className="h-4 w-4" />
|
||||
<span className="sr-only">Expand panel</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">Expand panel</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export function RightPanelExpandButton() {
|
|||
if (!collapsed || !hasContent) return null;
|
||||
|
||||
return (
|
||||
<div className="absolute top-4 right-4 z-20">
|
||||
<div className="absolute top-0 right-4 z-20 flex h-12 items-center">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@
|
|||
import { useAtomValue } from "jotai";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { hitlEditPanelAtom } from "@/atoms/chat/hitl-edit-panel.atom";
|
||||
import { reportPanelAtom } from "@/atoms/chat/report-panel.atom";
|
||||
import { documentsSidebarOpenAtom } from "@/atoms/documents/ui.atoms";
|
||||
import { editorPanelAtom } from "@/atoms/editor/editor-panel.atom";
|
||||
import { rightPanelCollapsedAtom } from "@/atoms/layout/right-panel.atom";
|
||||
import { activeTabAtom, type Tab } from "@/atoms/tabs/tabs.atom";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import type { InboxItem } from "@/hooks/use-inbox";
|
||||
|
|
@ -13,7 +18,7 @@ import { useSidebarResize } from "../../hooks/useSidebarResize";
|
|||
import type { ChatItem, NavItem, PageUsage, SearchSpace, User } from "../../types/layout.types";
|
||||
import { Header } from "../header";
|
||||
import { IconRail } from "../icon-rail";
|
||||
import { RightPanel } from "../right-panel/RightPanel";
|
||||
import { RightPanel, RightPanelExpandButton } from "../right-panel/RightPanel";
|
||||
import {
|
||||
AllPrivateChatsSidebarContent,
|
||||
AllSharedChatsSidebarContent,
|
||||
|
|
@ -116,11 +121,26 @@ function MainContentPanel({
|
|||
children: React.ReactNode;
|
||||
}) {
|
||||
const activeTab = useAtomValue(activeTabAtom);
|
||||
const rightPanelCollapsed = useAtomValue(rightPanelCollapsedAtom);
|
||||
const documentsOpen = useAtomValue(documentsSidebarOpenAtom);
|
||||
const reportState = useAtomValue(reportPanelAtom);
|
||||
const editorState = useAtomValue(editorPanelAtom);
|
||||
const hitlEditState = useAtomValue(hitlEditPanelAtom);
|
||||
const isDocumentTab = activeTab?.type === "document";
|
||||
const reportOpen = reportState.isOpen && !!reportState.reportId;
|
||||
const editorOpen = editorState.isOpen && !!editorState.documentId;
|
||||
const hitlEditOpen = hitlEditState.isOpen && !!hitlEditState.onSave;
|
||||
const showRightPanelExpandButton =
|
||||
rightPanelCollapsed && (documentsOpen || reportOpen || editorOpen || hitlEditOpen);
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-1 flex-col rounded-xl border bg-main-panel overflow-hidden min-w-0">
|
||||
<TabBar onTabSwitch={onTabSwitch} onNewChat={onNewChat} />
|
||||
<RightPanelExpandButton />
|
||||
<TabBar
|
||||
onTabSwitch={onTabSwitch}
|
||||
onNewChat={onNewChat}
|
||||
className={showRightPanelExpandButton ? "pr-14" : undefined}
|
||||
/>
|
||||
<Header />
|
||||
|
||||
{isDocumentTab && activeTab.documentId && activeTab.searchSpaceId ? (
|
||||
|
|
|
|||
|
|
@ -557,7 +557,7 @@ export function DocumentsSidebar({
|
|||
|
||||
const documentsContent = (
|
||||
<>
|
||||
<div className="shrink-0 flex h-14 items-center px-4">
|
||||
<div className="shrink-0 flex h-12 items-center px-4">
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
{isMobile && (
|
||||
|
|
@ -609,7 +609,7 @@ export function DocumentsSidebar({
|
|||
</div>
|
||||
|
||||
{/* Connected tools strip */}
|
||||
<div className="shrink-0 mx-4 mt-2 mb-3 flex select-none items-center gap-2 rounded-lg border bg-muted/50 transition-colors hover:bg-muted/80">
|
||||
<div className="shrink-0 mx-4 mt-4 mb-4 flex select-none items-center gap-2 rounded-lg border bg-muted/50 transition-colors hover:bg-muted/80">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setConnectorDialogOpen(true)}
|
||||
|
|
|
|||
|
|
@ -105,15 +105,15 @@ export function Sidebar({
|
|||
>
|
||||
{/* Header - search space name or collapse button when collapsed */}
|
||||
{isCollapsed ? (
|
||||
<div className="flex h-14 shrink-0 items-center justify-center border-b">
|
||||
<SidebarCollapseButton
|
||||
<div className="flex h-12 shrink-0 items-center justify-center border-b">
|
||||
<SidebarCollapseButton
|
||||
isCollapsed={isCollapsed}
|
||||
onToggle={onToggleCollapse ?? (() => {})}
|
||||
disableTooltip={disableTooltips}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex h-14 shrink-0 items-center gap-0 px-1 border-b">
|
||||
<div className="flex h-12 shrink-0 items-center gap-0 px-1 border-b">
|
||||
<SidebarHeader
|
||||
searchSpace={searchSpace}
|
||||
isCollapsed={isCollapsed}
|
||||
|
|
|
|||
|
|
@ -58,8 +58,11 @@ export function TabBar({ onTabSwitch, onNewChat, className }: TabBarProps) {
|
|||
if (tabs.length <= 1) return null;
|
||||
|
||||
return (
|
||||
<div className={cn("flex items-center shrink-0 border-b bg-main-panel", className)}>
|
||||
<div ref={scrollRef} className="flex items-center flex-1 overflow-x-auto scrollbar-none">
|
||||
<div className={cn("flex h-12 items-stretch shrink-0 border-b bg-main-panel", className)}>
|
||||
<div
|
||||
ref={scrollRef}
|
||||
className="flex h-full items-stretch flex-1 overflow-x-auto overflow-y-hidden scrollbar-hide [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden"
|
||||
>
|
||||
{tabs.map((tab) => {
|
||||
const isActive = tab.id === activeTabId;
|
||||
const Icon = tab.type === "document" ? FileText : MessageSquare;
|
||||
|
|
@ -71,10 +74,10 @@ export function TabBar({ onTabSwitch, onNewChat, className }: TabBarProps) {
|
|||
data-tab-id={tab.id}
|
||||
onClick={() => handleTabClick(tab)}
|
||||
className={cn(
|
||||
"group relative flex items-center gap-1.5 px-3 h-9 min-w-0 max-w-[200px] text-xs font-medium border-r transition-colors shrink-0",
|
||||
"group relative flex h-full items-center self-stretch gap-1.5 px-3 min-w-0 max-w-[200px] text-xs font-medium border-r transition-colors shrink-0",
|
||||
isActive
|
||||
? "bg-main-panel text-foreground"
|
||||
: "bg-muted/30 text-muted-foreground hover:bg-muted/60 hover:text-foreground"
|
||||
? "bg-muted/40 text-foreground"
|
||||
: "bg-transparent text-muted-foreground hover:bg-muted/25 hover:text-foreground"
|
||||
)}
|
||||
>
|
||||
{isActive && <span className="absolute bottom-0 left-0 right-0 h-[2px] bg-primary" />}
|
||||
|
|
@ -103,18 +106,19 @@ export function TabBar({ onTabSwitch, onNewChat, className }: TabBarProps) {
|
|||
</button>
|
||||
);
|
||||
})}
|
||||
{onNewChat && (
|
||||
<div className="flex h-full items-center px-1.5 shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onNewChat}
|
||||
className="flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:text-foreground hover:bg-muted/60"
|
||||
title="New Chat"
|
||||
>
|
||||
<Plus className="size-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{onNewChat && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onNewChat}
|
||||
className="flex items-center justify-center size-9 shrink-0 text-muted-foreground hover:text-foreground hover:bg-muted/60 transition-colors"
|
||||
title="New Chat"
|
||||
>
|
||||
<Plus className="size-3.5" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue