fix: filter bar layout — pills left, search right
Previous layout was [search] [centered pills] [clear-all]. Flip to [pills left-aligned] [clear-all] [search right]. Pills get a flex-1 slot on the left so they fill the available space and overflow-x- auto kicks in when they don't fit. Clear-all only renders when any filter is active and sits between the pills and the search input. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -128,42 +128,8 @@ export function FilterBar() {
|
|||||||
// clear-all button can stretch the bar vertically. The fixed h-11
|
// clear-all button can stretch the bar vertically. The fixed h-11
|
||||||
// matches the h-7 pills + 8px symmetric vertical padding.
|
// matches the h-7 pills + 8px symmetric vertical padding.
|
||||||
<div className="flex h-11 items-center gap-3 border-b border-border bg-surface px-3 py-0">
|
<div className="flex h-11 items-center gap-3 border-b border-border bg-surface px-3 py-0">
|
||||||
{/* Search — left of the pill cluster. Same id as before so the
|
{/* Pills — left side, scroll horizontally if they overflow. */}
|
||||||
* global "/" focus shortcut still finds it. */}
|
<div className="flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto">
|
||||||
<div className="relative w-56 flex-shrink-0">
|
|
||||||
<Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-text-muted" />
|
|
||||||
<input
|
|
||||||
id="topbar-search"
|
|
||||||
type="text"
|
|
||||||
value={searchQuery}
|
|
||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
|
||||||
onKeyDown={(e) => {
|
|
||||||
if (e.key === 'Escape') {
|
|
||||||
setSearchQuery('')
|
|
||||||
setStoreQ('')
|
|
||||||
e.currentTarget.blur()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
placeholder="Search photos…"
|
|
||||||
className="w-full rounded-full border border-border bg-surface-2 py-1 pl-8 pr-7 text-xs text-text placeholder-text-muted focus:border-primary focus:outline-none"
|
|
||||||
/>
|
|
||||||
{searchQuery && (
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
setSearchQuery('')
|
|
||||||
setStoreQ('')
|
|
||||||
}}
|
|
||||||
className="absolute right-1.5 top-1/2 -translate-y-1/2 rounded-full p-0.5 text-text-muted hover:bg-surface-offset hover:text-text"
|
|
||||||
title="Clear search (Esc)"
|
|
||||||
aria-label="Clear search"
|
|
||||||
>
|
|
||||||
<X className="h-3 w-3" />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Pills — centered, scroll horizontally if they overflow. */}
|
|
||||||
<div className="flex flex-1 items-center justify-center gap-1.5 overflow-x-auto">
|
|
||||||
{/* Date */}
|
{/* Date */}
|
||||||
<FilterPill
|
<FilterPill
|
||||||
label="Date"
|
label="Date"
|
||||||
@@ -391,18 +357,49 @@ export function FilterBar() {
|
|||||||
</FilterPill>
|
</FilterPill>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right slot — fixed-width so the pill cluster stays perfectly
|
{/* Clear-all — sits between the pill cluster and the search input
|
||||||
* centered in the bar regardless of whether Clear-all is visible.
|
* on the right. Only renders when any filter is active so it
|
||||||
* Width matches the search input on the left for symmetric
|
* doesn't take space in the resting state. */}
|
||||||
* framing. The button itself is right-aligned within the slot. */}
|
{anyActive && (
|
||||||
<div className="flex w-56 flex-shrink-0 justify-end">
|
<button
|
||||||
{anyActive && (
|
onClick={clearAll}
|
||||||
|
className="flex h-7 flex-shrink-0 items-center whitespace-nowrap rounded-full border border-border px-2.5 text-xs text-text-muted hover:bg-surface-2 hover:text-text"
|
||||||
|
title="Clear all filters in this section"
|
||||||
|
>
|
||||||
|
Clear all
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Search — pinned to the right edge of the bar. Same id as before
|
||||||
|
* so the global "/" focus shortcut still finds it. */}
|
||||||
|
<div className="relative w-56 flex-shrink-0">
|
||||||
|
<Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-text-muted" />
|
||||||
|
<input
|
||||||
|
id="topbar-search"
|
||||||
|
type="text"
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
setSearchQuery('')
|
||||||
|
setStoreQ('')
|
||||||
|
e.currentTarget.blur()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
placeholder="Search photos…"
|
||||||
|
className="w-full rounded-full border border-border bg-surface-2 py-1 pl-8 pr-7 text-xs text-text placeholder-text-muted focus:border-primary focus:outline-none"
|
||||||
|
/>
|
||||||
|
{searchQuery && (
|
||||||
<button
|
<button
|
||||||
onClick={clearAll}
|
onClick={() => {
|
||||||
className="flex h-7 items-center whitespace-nowrap rounded-full border border-border px-2.5 text-xs text-text-muted hover:bg-surface-2 hover:text-text"
|
setSearchQuery('')
|
||||||
title="Clear all filters in this section"
|
setStoreQ('')
|
||||||
|
}}
|
||||||
|
className="absolute right-1.5 top-1/2 -translate-y-1/2 rounded-full p-0.5 text-text-muted hover:bg-surface-offset hover:text-text"
|
||||||
|
title="Clear search (Esc)"
|
||||||
|
aria-label="Clear search"
|
||||||
>
|
>
|
||||||
Clear all
|
<X className="h-3 w-3" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user