move top icons to sidebar buttons

This commit is contained in:
Arjun 2026-04-15 22:40:09 +05:30 committed by arkml
parent 7dbfcb72f4
commit efe2a93d8a
2 changed files with 98 additions and 93 deletions

View file

@ -5,7 +5,7 @@ import { RunEvent, ListRunsResponse } from '@x/shared/src/runs.js';
import type { LanguageModelUsage, ToolUIPart } from 'ai';
import './App.css'
import z from 'zod';
import { CheckIcon, LoaderIcon, PanelLeftIcon, Maximize2, Minimize2, ChevronLeftIcon, ChevronRightIcon, SquarePen, SearchIcon, HistoryIcon, RadioIcon, SquareIcon, Globe } from 'lucide-react';
import { CheckIcon, LoaderIcon, PanelLeftIcon, Maximize2, Minimize2, ChevronLeftIcon, ChevronRightIcon, SquarePen, HistoryIcon } from 'lucide-react';
import { cn } from '@/lib/utils';
import { MarkdownEditor, type MarkdownEditorHandle } from './components/markdown-editor';
import { ChatSidebar } from './components/chat-sidebar';
@ -454,28 +454,12 @@ function FixedSidebarToggle({
onNavigateForward,
canNavigateBack,
canNavigateForward,
onNewChat,
onOpenSearch,
meetingState,
meetingSummarizing,
meetingAvailable,
onToggleMeeting,
isBrowserOpen,
onToggleBrowser,
leftInsetPx,
}: {
onNavigateBack: () => void
onNavigateForward: () => void
canNavigateBack: boolean
canNavigateForward: boolean
onNewChat: () => void
onOpenSearch: () => void
meetingState: MeetingTranscriptionState
meetingSummarizing: boolean
meetingAvailable: boolean
onToggleMeeting: () => void
isBrowserOpen: boolean
onToggleBrowser: () => void
leftInsetPx: number
}) {
const { toggleSidebar, state } = useSidebar()
@ -493,74 +477,6 @@ function FixedSidebarToggle({
>
<PanelLeftIcon className="size-5" />
</button>
<button
type="button"
onClick={onNewChat}
className="flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground transition-colors"
style={{ marginLeft: TITLEBAR_BUTTON_GAP_PX }}
aria-label="New chat"
>
<SquarePen className="size-5" />
</button>
<button
type="button"
onClick={onOpenSearch}
className="flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground transition-colors"
style={{ marginLeft: TITLEBAR_BUTTON_GAP_PX }}
aria-label="Search"
>
<SearchIcon className="size-5" />
</button>
{meetingAvailable && (
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
onClick={onToggleMeeting}
disabled={meetingState === 'connecting' || meetingState === 'stopping' || meetingSummarizing}
className={cn(
"flex h-8 w-8 items-center justify-center rounded-md transition-colors disabled:pointer-events-none",
meetingSummarizing
? "text-muted-foreground"
: meetingState === 'recording'
? "text-red-500 hover:bg-accent"
: "text-muted-foreground hover:bg-accent hover:text-foreground"
)}
style={{ marginLeft: TITLEBAR_BUTTON_GAP_PX }}
>
{meetingSummarizing || meetingState === 'connecting' ? (
<LoaderIcon className="size-4 animate-spin" />
) : meetingState === 'recording' ? (
<SquareIcon className="size-4 animate-pulse" />
) : (
<RadioIcon className="size-5" />
)}
</button>
</TooltipTrigger>
<TooltipContent side="bottom">
{meetingSummarizing ? 'Generating meeting notes...' : meetingState === 'connecting' ? 'Starting transcription...' : meetingState === 'recording' ? 'Stop meeting notes' : 'Take new meeting notes'}
</TooltipContent>
</Tooltip>
)}
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
onClick={onToggleBrowser}
className={cn(
"flex h-8 w-8 items-center justify-center rounded-md transition-colors",
isBrowserOpen
? "bg-accent text-foreground"
: "text-muted-foreground hover:bg-accent hover:text-foreground"
)}
style={{ marginLeft: TITLEBAR_BUTTON_GAP_PX }}
aria-label={isBrowserOpen ? "Close browser" : "Open browser"}
>
<Globe className="size-5" />
</button>
</TooltipTrigger>
<TooltipContent side="bottom">{isBrowserOpen ? 'Close browser' : 'Open browser'}</TooltipContent>
</Tooltip>
{/* Back / Forward navigation */}
{isCollapsed && (
<>
@ -4149,6 +4065,14 @@ function App() {
}}
backgroundTasks={backgroundTasks}
selectedBackgroundTask={selectedBackgroundTask}
onNewChat={handleNewChatTab}
onOpenSearch={() => setIsSearchOpen(true)}
meetingState={meetingTranscription.state}
meetingSummarizing={meetingSummarizing}
meetingAvailable={voiceAvailable}
onToggleMeeting={() => { void handleToggleMeeting() }}
isBrowserOpen={isBrowserOpen}
onToggleBrowser={handleToggleBrowser}
/>
<SidebarInset
className={cn(
@ -4651,14 +4575,6 @@ function App() {
onNavigateForward={() => { void navigateForward() }}
canNavigateBack={canNavigateBack}
canNavigateForward={canNavigateForward}
onNewChat={handleNewChatTab}
onOpenSearch={() => setIsSearchOpen(true)}
meetingState={meetingTranscription.state}
meetingSummarizing={meetingSummarizing}
meetingAvailable={voiceAvailable}
onToggleMeeting={() => { void handleToggleMeeting() }}
isBrowserOpen={isBrowserOpen}
onToggleBrowser={handleToggleBrowser}
leftInsetPx={isMac ? MACOS_TRAFFIC_LIGHTS_RESERVED_PX : 0}
/>
</SidebarProvider>

View file

@ -12,11 +12,15 @@ import {
FilePlus,
Folder,
FolderPlus,
Globe,
AlertTriangle,
HelpCircle,
Mic,
Network,
Pencil,
Radio,
SearchIcon,
SquarePen,
Table2,
Plug,
LoaderIcon,
@ -90,6 +94,7 @@ import { SettingsDialog } from "@/components/settings-dialog"
import { toast } from "@/lib/toast"
import { useBilling } from "@/hooks/useBilling"
import { ServiceEvent } from "@x/shared/src/service-events.js"
import type { MeetingTranscriptionState } from "@/hooks/useMeetingTranscription"
import z from "zod"
interface TreeNode {
@ -172,6 +177,14 @@ type SidebarContentPanelProps = {
tasksActions?: TasksActions
backgroundTasks?: BackgroundTaskItem[]
selectedBackgroundTask?: string | null
onNewChat?: () => void
onOpenSearch?: () => void
meetingState?: MeetingTranscriptionState
meetingSummarizing?: boolean
meetingAvailable?: boolean
onToggleMeeting?: () => void
isBrowserOpen?: boolean
onToggleBrowser?: () => void
} & React.ComponentProps<typeof Sidebar>
const sectionTabs: { id: ActiveSection; label: string }[] = [
@ -395,6 +408,14 @@ export function SidebarContentPanel({
tasksActions,
backgroundTasks = [],
selectedBackgroundTask,
onNewChat,
onOpenSearch,
meetingState = 'idle',
meetingSummarizing = false,
meetingAvailable = false,
onToggleMeeting,
isBrowserOpen = false,
onToggleBrowser,
...props
}: SidebarContentPanelProps) {
const { activeSection, setActiveSection } = useSidebarSection()
@ -488,6 +509,74 @@ export function SidebarContentPanel({
))}
</div>
</div>
{/* Quick action buttons */}
<div className="titlebar-no-drag flex flex-col gap-0.5 px-2 pb-1">
{onNewChat && (
<button
type="button"
onClick={onNewChat}
className="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground transition-colors"
>
<SquarePen className="size-4" />
<span>New chat</span>
</button>
)}
{onOpenSearch && (
<button
type="button"
onClick={onOpenSearch}
className="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground transition-colors"
>
<SearchIcon className="size-4" />
<span>Search</span>
</button>
)}
{meetingAvailable && onToggleMeeting && (
<button
type="button"
onClick={onToggleMeeting}
disabled={meetingState === 'connecting' || meetingState === 'stopping' || meetingSummarizing}
className={cn(
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors disabled:pointer-events-none",
meetingState === 'recording'
? "text-red-500 hover:bg-sidebar-accent"
: "text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
)}
>
{meetingSummarizing || meetingState === 'connecting' ? (
<LoaderIcon className="size-4 animate-spin" />
) : meetingState === 'recording' ? (
<Square className="size-4 animate-pulse" />
) : (
<Radio className="size-4" />
)}
<span>
{meetingSummarizing
? 'Generating notes…'
: meetingState === 'connecting'
? 'Starting…'
: meetingState === 'recording'
? 'Stop recording'
: 'Take meeting notes'}
</span>
</button>
)}
{onToggleBrowser && (
<button
type="button"
onClick={onToggleBrowser}
className={cn(
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors",
isBrowserOpen
? "bg-sidebar-accent text-sidebar-accent-foreground"
: "text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
)}
>
<Globe className="size-4" />
<span>Run browser task</span>
</button>
)}
</div>
</SidebarHeader>
<SidebarContent>
{activeSection === "knowledge" && (