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 ( return (
<div className="flex-1 flex flex-col"> <div className="flex-1 flex flex-col">
<header <header
className="border-b px-6 py-3 flex items-center justify-between gap-2" className="border-b px-3 sm:px-6 py-2 sm:py-3 flex items-center justify-between gap-2"
style={{ paddingTop: 'max(0.75rem, env(safe-area-inset-top))' }} style={{ paddingTop: 'max(0.5rem, env(safe-area-inset-top))' }}
> >
<div className="flex items-center gap-2 min-w-0"> <div className="flex items-center gap-2 min-w-0">
{isMobile && ( {isMobile && (
<button <button
type="button" type="button"
onClick={() => setDrawerOpen(true)} 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" aria-label="Open sidebar"
> >
<Menu className="size-5" /> <Menu className="size-5" />
</button> </button>
)} )}
<div className="min-w-0"> <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 ?? '…'} {project?.name ?? '…'}
</h1> </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} {project?.path}
</div> </div>
</div> </div>
</div> </div>
<Button onClick={handleNew} disabled={creating} className="shrink-0"> <Button onClick={handleNew} disabled={creating} className="shrink-0" aria-label="New session">
<Plus /> <Plus />
New session <span className="hidden sm:inline">New session</span>
</Button> </Button>
</header> </header>

View File

@@ -87,33 +87,42 @@ export function Session() {
return ( return (
<div className="flex-1 flex flex-col min-h-0"> <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 && ( {isMobile && (
<button <button
type="button" type="button"
onClick={() => setDrawerOpen(true)} 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" aria-label="Open sidebar"
> >
<Menu className="size-5" /> <Menu className="size-5" />
</button> </button>
)} )}
<Link to="/" className="text-muted-foreground hover:text-foreground">
Projects {/* Breadcrumb — desktop only */}
</Link> <div className="hidden sm:flex items-center gap-1.5 min-w-0">
<ChevronRight className="size-3 text-muted-foreground/60" /> <Link to="/" className="text-muted-foreground hover:text-foreground shrink-0 text-xs">
{project ? ( Projects
<Link
to={`/project/${project.id}`}
className="text-muted-foreground hover:text-foreground truncate max-w-[200px]"
title={project.name}
>
{project.name}
</Link> </Link>
) : ( <ChevronRight className="size-3 text-muted-foreground/60 shrink-0" />
<span className="text-muted-foreground/60"></span> {project ? (
)} <Link
<ChevronRight className="size-3 text-muted-foreground/60" /> 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 ? ( {editingName ? (
<input <input
autoFocus autoFocus
@@ -127,30 +136,34 @@ export function Session() {
setEditingName(false); 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 <button
type="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)} onClick={() => setEditingName(true)}
title={session?.name ?? ''} title={session?.name ?? ''}
> >
{session?.name ?? '…'} {session?.name ?? '…'}
</button> </button>
)} )}
{/* Active file — desktop only */}
{showActiveFile && active.activeFile && ( {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 <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} title={active.activeFile}
> >
{active.activeFile} {active.activeFile}
</span> </span>
</> </>
)} )}
<div className="ml-auto">
{/* Model picker — right-aligned */}
<div className="ml-auto shrink-0">
{session && ( {session && (
<div className="inline-flex items-center rounded-full bg-muted/40 hover:bg-muted/70 px-1"> <div className="inline-flex items-center rounded-full bg-muted/40 hover:bg-muted/70 px-1">
<ModelPicker <ModelPicker