feat(mobile): rework Session and Project headers for narrow viewports

Session header: breadcrumb (Projects > project) wrapped in
hidden sm:flex; active file path hidden on mobile; session name cap
max-w-[140px] sm:max-w-[280px]; padding px-3 sm:px-4. Mobile gets
just hamburger | session name | model pill.

Project header: px-3 sm:px-6, py-2 sm:py-3, heading text-base
sm:text-lg, project path hidden sm:block, "New session" button is
icon-only on mobile via <span className="hidden sm:inline">. Both
headers retain the safe-area-inset-top padding from v1.6.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-16 06:36:36 +00:00
parent f6c7e12dbf
commit e167f851fd
2 changed files with 42 additions and 29 deletions

View File

@@ -81,32 +81,32 @@ export function Project() {
return (
<div className="flex-1 flex flex-col">
<header
className="border-b px-6 py-3 flex items-center justify-between gap-2"
style={{ paddingTop: 'max(0.75rem, env(safe-area-inset-top))' }}
className="border-b px-3 sm:px-6 py-2 sm:py-3 flex items-center justify-between gap-2"
style={{ paddingTop: 'max(0.5rem, env(safe-area-inset-top))' }}
>
<div className="flex items-center gap-2 min-w-0">
{isMobile && (
<button
type="button"
onClick={() => setDrawerOpen(true)}
className="inline-flex items-center justify-center -ml-2 min-w-[44px] min-h-[44px] rounded text-muted-foreground hover:bg-muted hover:text-foreground shrink-0"
className="inline-flex items-center justify-center -ml-1 min-w-[44px] min-h-[44px] rounded text-muted-foreground hover:bg-muted hover:text-foreground shrink-0"
aria-label="Open sidebar"
>
<Menu className="size-5" />
</button>
)}
<div className="min-w-0">
<h1 className="text-lg font-semibold tracking-tight truncate">
<h1 className="text-base sm:text-lg font-semibold tracking-tight truncate">
{project?.name ?? '…'}
</h1>
<div className="text-xs text-muted-foreground font-mono truncate">
<div className="text-xs text-muted-foreground font-mono truncate hidden sm:block">
{project?.path}
</div>
</div>
</div>
<Button onClick={handleNew} disabled={creating} className="shrink-0">
<Button onClick={handleNew} disabled={creating} className="shrink-0" aria-label="New session">
<Plus />
New session
<span className="hidden sm:inline">New session</span>
</Button>
</header>

View File

@@ -87,33 +87,42 @@ export function Session() {
return (
<div className="flex-1 flex flex-col min-h-0">
<header className="border-b px-4 py-2 flex items-center gap-1.5 shrink-0 text-sm" style={{ paddingTop: 'max(0.5rem, env(safe-area-inset-top))' }}>
<header
className="border-b px-3 sm:px-4 py-2 flex items-center gap-1.5 shrink-0 text-sm"
style={{ paddingTop: 'max(0.5rem, env(safe-area-inset-top))' }}
>
{isMobile && (
<button
type="button"
onClick={() => setDrawerOpen(true)}
className="inline-flex items-center justify-center -ml-1 mr-1 min-w-[44px] min-h-[44px] rounded text-muted-foreground hover:bg-muted hover:text-foreground"
className="inline-flex items-center justify-center -ml-1 min-w-[44px] min-h-[44px] rounded text-muted-foreground hover:bg-muted hover:text-foreground shrink-0"
aria-label="Open sidebar"
>
<Menu className="size-5" />
</button>
)}
<Link to="/" className="text-muted-foreground hover:text-foreground">
Projects
</Link>
<ChevronRight className="size-3 text-muted-foreground/60" />
{project ? (
<Link
to={`/project/${project.id}`}
className="text-muted-foreground hover:text-foreground truncate max-w-[200px]"
title={project.name}
>
{project.name}
{/* Breadcrumb — desktop only */}
<div className="hidden sm:flex items-center gap-1.5 min-w-0">
<Link to="/" className="text-muted-foreground hover:text-foreground shrink-0 text-xs">
Projects
</Link>
) : (
<span className="text-muted-foreground/60"></span>
)}
<ChevronRight className="size-3 text-muted-foreground/60" />
<ChevronRight className="size-3 text-muted-foreground/60 shrink-0" />
{project ? (
<Link
to={`/project/${project.id}`}
className="text-muted-foreground hover:text-foreground truncate max-w-[200px]"
title={project.name}
>
{project.name}
</Link>
) : (
<span className="text-muted-foreground/60"></span>
)}
<ChevronRight className="size-3 text-muted-foreground/60 shrink-0" />
</div>
{/* Session name — always visible, truncated, editable */}
{editingName ? (
<input
autoFocus
@@ -127,30 +136,34 @@ export function Session() {
setEditingName(false);
}
}}
className="bg-transparent border-b border-border px-1 py-0.5 text-sm font-medium outline-none focus:border-ring"
className="bg-transparent border-b border-border px-1 py-0.5 text-sm font-medium outline-none focus:border-ring min-w-0"
/>
) : (
<button
type="button"
className="text-sm font-medium hover:underline truncate max-w-[280px]"
className="text-sm font-medium hover:underline truncate max-w-[140px] sm:max-w-[280px] min-w-0"
onClick={() => setEditingName(true)}
title={session?.name ?? ''}
>
{session?.name ?? '…'}
</button>
)}
{/* Active file — desktop only */}
{showActiveFile && active.activeFile && (
<>
<span className="text-muted-foreground/40 mx-1">·</span>
<span className="text-muted-foreground/40 mx-1 hidden sm:inline">·</span>
<span
className="text-xs font-mono text-muted-foreground truncate max-w-[320px]"
className="text-xs font-mono text-muted-foreground truncate max-w-[200px] hidden sm:inline"
title={active.activeFile}
>
{active.activeFile}
</span>
</>
)}
<div className="ml-auto">
{/* Model picker — right-aligned */}
<div className="ml-auto shrink-0">
{session && (
<div className="inline-flex items-center rounded-full bg-muted/40 hover:bg-muted/70 px-1">
<ModelPicker