diff --git a/apps/x/apps/renderer/src/App.tsx b/apps/x/apps/renderer/src/App.tsx
index f5868166..560df891 100644
--- a/apps/x/apps/renderer/src/App.tsx
+++ b/apps/x/apps/renderer/src/App.tsx
@@ -6,7 +6,7 @@ import type { LanguageModelUsage, ToolUIPart } from 'ai';
import './App.css'
import z from 'zod';
import { Button } from './components/ui/button';
-import { CheckIcon, LoaderIcon, ArrowUp, PanelLeftIcon, PanelRightIcon, Square, X, ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';
+import { CheckIcon, LoaderIcon, ArrowUp, PanelLeftIcon, PanelRightIcon, Square, X, ChevronLeftIcon, ChevronRightIcon, SquarePen } from 'lucide-react';
import { cn } from '@/lib/utils';
import { MarkdownEditor } from './components/markdown-editor';
import { ChatInputBar } from './components/chat-button';
@@ -126,6 +126,12 @@ const graphPalette = [
]
const MACOS_TRAFFIC_LIGHTS_RESERVED_PX = 12 + 12 * 3 + 8 * 2
+const TITLEBAR_BUTTON_PX = 32
+const TITLEBAR_BUTTON_GAP_PX = 4
+const TITLEBAR_HEADER_GAP_PX = 8
+const TITLEBAR_TOGGLE_MARGIN_LEFT_PX = 12
+const TITLEBAR_BUTTONS_COLLAPSED = 4
+const TITLEBAR_BUTTON_GAPS_COLLAPSED = 3
const clampNumber = (value: number, min: number, max: number) =>
Math.min(max, Math.max(min, value))
@@ -469,15 +475,18 @@ function FixedSidebarToggle({
onNavigateForward,
canNavigateBack,
canNavigateForward,
+ onNewChat,
leftInsetPx,
}: {
onNavigateBack: () => void
onNavigateForward: () => void
canNavigateBack: boolean
canNavigateForward: boolean
+ onNewChat: () => void
leftInsetPx: number
}) {
- const { toggleSidebar } = useSidebar()
+ const { toggleSidebar, state } = useSidebar()
+ const isCollapsed = state === "collapsed"
return (
@@ -485,36 +494,62 @@ function FixedSidebarToggle({
+
{/* Back / Forward navigation */}
-
-
+ {isCollapsed && (
+ <>
+
+
+ >
+ )}
)
}
/** Main content header that adjusts padding based on sidebar state */
-function ContentHeader({ children }: { children: React.ReactNode }) {
+function ContentHeader({
+ children,
+ onNavigateBack,
+ onNavigateForward,
+ canNavigateBack,
+ canNavigateForward,
+ collapsedLeftPaddingPx,
+}: {
+ children: React.ReactNode
+ onNavigateBack?: () => void
+ onNavigateForward?: () => void
+ canNavigateBack?: boolean
+ canNavigateForward?: boolean
+ collapsedLeftPaddingPx?: number
+}) {
const { state } = useSidebar()
const isCollapsed = state === "collapsed"
return (
@@ -523,9 +558,35 @@ function ContentHeader({ children }: { children: React.ReactNode }) {
"titlebar-drag-region flex h-10 shrink-0 items-center gap-2 border-b border-border px-3 bg-sidebar transition-[padding] duration-200 ease-linear",
// When the sidebar is collapsed the content area shifts left, so we need enough left padding
// to avoid overlapping the fixed traffic-lights/toggle/back/forward controls.
- isCollapsed && "pl-[168px]"
+ isCollapsed && !collapsedLeftPaddingPx && "pl-[168px]"
)}
+ style={isCollapsed && collapsedLeftPaddingPx ? { paddingLeft: collapsedLeftPaddingPx } : undefined}
>
+ {!isCollapsed && onNavigateBack && onNavigateForward ? (
+
+
+
+
+ ) : null}
+ {onNavigateBack && onNavigateForward ? (
+
+ ) : null}
{children}
)
@@ -549,6 +610,13 @@ function App() {
const [graphStatus, setGraphStatus] = useState<'idle' | 'loading' | 'ready' | 'error'>('idle')
const [graphError, setGraphError] = useState(null)
const [isChatSidebarOpen, setIsChatSidebarOpen] = useState(true)
+ const isMac = typeof navigator !== 'undefined' && navigator.platform.toLowerCase().includes('mac')
+ const collapsedLeftPaddingPx =
+ (isMac ? MACOS_TRAFFIC_LIGHTS_RESERVED_PX : 0) +
+ TITLEBAR_TOGGLE_MARGIN_LEFT_PX +
+ TITLEBAR_BUTTON_PX * TITLEBAR_BUTTONS_COLLAPSED +
+ TITLEBAR_BUTTON_GAP_PX * TITLEBAR_BUTTON_GAPS_COLLAPSED +
+ TITLEBAR_HEADER_GAP_PX
// Keep the latest selected path in a ref (avoids stale async updates when switching rapidly)
const selectedPathRef = useRef(null)
@@ -602,7 +670,6 @@ function App() {
// Onboarding state
const [showOnboarding, setShowOnboarding] = useState(false)
- const isMac = typeof navigator !== 'undefined' && navigator.platform.toLowerCase().includes('mac')
// Background tasks state
type BackgroundTaskItem = {
@@ -2216,7 +2283,13 @@ function App() {
/>
{/* Header - also serves as titlebar drag region, adjusts padding when sidebar collapsed */}
-
+ { void navigateBack() }}
+ onNavigateForward={() => { void navigateForward() }}
+ canNavigateBack={canNavigateBack}
+ canNavigateForward={canNavigateForward}
+ collapsedLeftPaddingPx={collapsedLeftPaddingPx}
+ >
{headerTitle}
@@ -2249,20 +2322,20 @@ function App() {
)}
{(selectedPath || isGraphOpen) && (
)}
@@ -2447,6 +2520,7 @@ function App() {
onNavigateForward={() => { void navigateForward() }}
canNavigateBack={canNavigateBack}
canNavigateForward={canNavigateForward}
+ onNewChat={handleNewChat}
leftInsetPx={isMac ? MACOS_TRAFFIC_LIGHTS_RESERVED_PX : 0}
/>
diff --git a/apps/x/apps/renderer/src/components/sidebar-content.tsx b/apps/x/apps/renderer/src/components/sidebar-content.tsx
index c765e7bb..8b678163 100644
--- a/apps/x/apps/renderer/src/components/sidebar-content.tsx
+++ b/apps/x/apps/renderer/src/components/sidebar-content.tsx
@@ -159,6 +159,25 @@ function formatEventTime(ts: string): string {
return date.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" })
}
+function formatRunTime(ts: string): string {
+ const date = new Date(ts)
+ if (Number.isNaN(date.getTime())) return ""
+ const now = Date.now()
+ const diffMs = Math.max(0, now - date.getTime())
+ const diffMinutes = Math.floor(diffMs / (1000 * 60))
+ const diffHours = Math.floor(diffMinutes / 60)
+ const diffDays = Math.floor(diffHours / 24)
+ const diffWeeks = Math.floor(diffDays / 7)
+ const diffMonths = Math.floor(diffDays / 30)
+
+ if (diffMinutes < 1) return "just now"
+ if (diffMinutes < 60) return `${diffMinutes} m`
+ if (diffHours < 24) return `${diffHours} h`
+ if (diffDays < 7) return `${diffDays} d`
+ if (diffWeeks < 4) return `${diffWeeks} w`
+ return `${Math.max(1, diffMonths)} m`
+}
+
function SyncStatusBar() {
const { state, isMobile } = useSidebar()
const [activeServices, setActiveServices] = useState