feat(ui): center search in a 3-zone top bar
Implements the v2 design's top-bar reorganization in the Tauri launcher. The bar was previously a flat flex row that let the search field drift left or right depending on filter / sort widths; now it's a 3-column CSS grid with the search field pinned to the geometric center of the window. - `.topbar` becomes `display: grid` with `grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr)` and a 16 px column gap. The middle (auto) column holds only the search, capped at `flex: 0 1 360px` so it cannot push into the side columns. - The left zone is `flex; justify-content: space-between`: brand pins far-left, filter pills hug the search. The filter pills are now grouped with the search semantically (they scope it) instead of floating next to the brand. - The right zone mirrors that: sort hugs the search, kebab pins far-right, with the directory button between them. - A `@container launcher (max-width: 1100px)` rule collapses the layout back to a single nowrap flex row at narrow widths — the geometric centering doesn't read at small widths and would force awkward truncation, so we abandon it rather than fight it. The launcher root opts into container queries via `container-type: inline-size; container-name: launcher`. `TopBar.tsx` now wraps the existing children in `.topbar-left`, `.topbar-center`, `.topbar-right` (plus `.topbar-left-trail` / `.topbar-right-lead` for the inner space-between alignment), but each control component is otherwise untouched. Test Plan - `just frontend-test` — passes. - `npx tsc --noEmit` from the frontend crate — clean. - Manual: run `just run`, confirm the search input's horizontal center matches the window's horizontal center across the standard launcher width. Shrink the window below 1100 px and confirm the row collapses to a single left-to-right strip with no overlap or wrapping.
This commit is contained in:
@@ -36,11 +36,21 @@ export const TopBar = ({
|
|||||||
kebabItems,
|
kebabItems,
|
||||||
}: Props) => (
|
}: Props) => (
|
||||||
<header className="topbar">
|
<header className="topbar">
|
||||||
<Brand peerCount={peerCount} />
|
<div className="topbar-left">
|
||||||
<SegmentedFilters value={filter} onChange={setFilter} counts={counts} />
|
<Brand peerCount={peerCount} />
|
||||||
<SearchField value={query} onChange={setQuery} />
|
<div className="topbar-left-trail">
|
||||||
<SortMenu value={sort} onChange={setSort} />
|
<SegmentedFilters value={filter} onChange={setFilter} counts={counts} />
|
||||||
<DirectoryButton path={gameDir} onClick={onPickDirectory} />
|
</div>
|
||||||
<KebabMenu items={kebabItems} />
|
</div>
|
||||||
|
<div className="topbar-center">
|
||||||
|
<SearchField value={query} onChange={setQuery} />
|
||||||
|
</div>
|
||||||
|
<div className="topbar-right">
|
||||||
|
<div className="topbar-right-lead">
|
||||||
|
<SortMenu value={sort} onChange={setSort} />
|
||||||
|
</div>
|
||||||
|
<DirectoryButton path={gameDir} onClick={onPickDirectory} />
|
||||||
|
<KebabMenu items={kebabItems} />
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: var(--bg-0);
|
background: var(--bg-0);
|
||||||
color: var(--t-1);
|
color: var(--t-1);
|
||||||
|
container-type: inline-size;
|
||||||
|
container-name: launcher;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
isolation: isolate;
|
isolation: isolate;
|
||||||
@@ -56,7 +58,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Top bar */
|
/* Top bar — three visual zones with search at the geometric center */
|
||||||
.topbar {
|
.topbar {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
@@ -64,12 +66,69 @@
|
|||||||
-webkit-backdrop-filter: blur(20px) saturate(140%);
|
-webkit-backdrop-filter: blur(20px) saturate(140%);
|
||||||
backdrop-filter: blur(20px) saturate(140%);
|
backdrop-filter: blur(20px) saturate(140%);
|
||||||
border-bottom: 1px solid var(--bd-1);
|
border-bottom: 1px solid var(--bd-1);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 16px;
|
||||||
|
padding: 14px 24px;
|
||||||
|
min-height: 64px;
|
||||||
|
}
|
||||||
|
.topbar-left {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 18px;
|
justify-content: space-between;
|
||||||
padding: 14px 24px;
|
gap: 16px;
|
||||||
flex-wrap: nowrap;
|
min-width: 0;
|
||||||
min-height: 64px;
|
}
|
||||||
|
.topbar-left-trail {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.topbar-center {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.topbar-center .search {
|
||||||
|
flex: 0 1 360px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.topbar-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.topbar-right-lead {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Below ~1100px of launcher width the geometric centering stops reading —
|
||||||
|
collapse the three zones into a single left-to-right flowing row. */
|
||||||
|
@container launcher (max-width: 1100px) {
|
||||||
|
.topbar {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.topbar-left,
|
||||||
|
.topbar-center,
|
||||||
|
.topbar-right {
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.topbar-center {
|
||||||
|
flex: 1 1 200px;
|
||||||
|
}
|
||||||
|
.topbar-center .search {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Brand */
|
/* Brand */
|
||||||
|
|||||||
Reference in New Issue
Block a user