feat(design): the header search is a 40 glass pill; a wrapper field dims for its input only (E28 S3c)

This commit is contained in:
2026-09-25 00:05:31 +02:00
parent dac9d89f91
commit db10bfbbca
13 changed files with 78 additions and 39 deletions
+14 -5
View File
@@ -1,3 +1,4 @@
import clsx from "clsx";
import {
useRef,
type FocusEventHandler,
@@ -12,10 +13,12 @@ import { PaletteKeycap } from "./PaletteLauncher";
import { Button } from "./ui/Button";
import { IconButton } from "./ui/IconButton";
import { InnerInput } from "./ui/Input";
import { fieldClass } from "./ui/fieldStyles";
// The floating search pill in the top header. One component for every module that searches
// (feed, Plex, channels, playlists): a glass rounded box with a search icon, the input, a
// clear button, and a "Go" trigger (Enter also fires it). The feed passes its live-YouTube
// (feed, Plex, channels, playlists): a 40px glass pill with the A4 field edge (the page's one hero
// field, the YouTube/Gmail shape), holding a search icon, the input, a clear button and a "Go"
// trigger (Enter also fires it). What sits inside the pill is round too, so the radii nest. The feed passes its live-YouTube
// escalation as the Go action; the other modules filter as you type and Go just commits/blurs.
//
// Optional slots keep the box reusable while letting one module enrich it: `leading` replaces the
@@ -72,10 +75,15 @@ export default function SearchBar({
// small pills (module name + Plex scope toggle / feed sync chip) share the line above it.
return (
<div className="pointer-events-auto relative flex-1 min-w-0 max-w-xl @min-[420px]/appmain:min-w-[15rem] @max-[640px]/appmain:order-last @max-[640px]/appmain:basis-full">
<div className="h-11 pl-3 pr-2 rounded-2xl glass-menu flex items-center gap-2 focus-within:outline-2 focus-within:outline-accent/60 focus-within:outline-offset-2">
{/* `free` + its own padding: the Go button sits 6px in from the pill's end, not a field's 12. */}
<div
className={clsx(
fieldClass({ size: "free", pill: true, floating: true }),
"flex h-10 items-center gap-2 pr-1.5 pl-3 text-sm pointer-coarse:text-base",
)}
>
{leading ?? <Search className="w-4 h-4 shrink-0 text-muted" />}
<InnerInput
className="text-sm"
{...inputProps}
ref={inputRef}
value={value}
@@ -94,7 +102,7 @@ export default function SearchBar({
placeholder={placeholder}
/>
{value && (
<IconButton onClick={() => onChange("")} label={t("header.clearSearch")}>
<IconButton round onClick={() => onChange("")} label={t("header.clearSearch")}>
<X />
</IconButton>
)}
@@ -102,6 +110,7 @@ export default function SearchBar({
{onGo && (
<Button
size="sm"
round
onClick={fire}
disabled={goDisabled}
title={goTitle ?? goLabel ?? t("header.goTip")}