feat(header): move the sync status into a chip on the header

The rail spent a two-row block plus a divider on per-user sync status. It's
global, not per-module, so it now rides the right end of the floating header as
a pill: the headline count at a glance, an accent dot when something wants you
(paused / missing history), and the counts, state, the channel-manager link and
pause in a popover.

Frees the rail's whole top block. Also drops SyncStatus's two now-dead layouts:
"bar" was a leftover of the top bar removed in 0.42.0, and "rail" lost its only
caller here — the component is chip-only, ~60 lines lighter, and the popover
reuses useDismiss.
This commit is contained in:
2026-07-15 22:42:31 +02:00
parent c440a043f2
commit 104183118d
4 changed files with 97 additions and 160 deletions
+12 -4
View File
@@ -6,11 +6,11 @@ import type { Page } from "../lib/urlState";
import { moduleLabelKey, moduleOrder, stepModule } from "../lib/modules";
import ModuleName from "./ModuleName";
import SearchBar from "./SearchBar";
import SyncStatus from "./SyncStatus";
// The floating top header: a fixed-position row of glass pills over the content — a ModuleName
// pill (label + accent dot + back/forward arrows) and, where a module searches, a SearchBar pill.
// The row's left edge is a constant (as if the nav rail AND filter sidebar were both open), so it
// never shifts when either collapses or when paging between modules; the right edge leaves ~10%.
// The floating top header: a row of glass pills over the content — a ModuleName pill (label +
// accent dot + back/forward arrows), the module's SearchBar where it has one, and the per-user
// sync chip at the right end.
export default function Header({
me,
filters,
@@ -24,6 +24,7 @@ export default function Header({
page,
setPage,
onYtSearch,
onGoToFullHistory,
}: {
me: Me;
filters: FeedFilters;
@@ -40,6 +41,8 @@ export default function Header({
// Trigger a live YouTube search for the current term (feed only; hidden for the demo account,
// which can't spend the shared quota).
onYtSearch: (q: string) => void;
// Jump to the channel manager filtered to channels still missing full history.
onGoToFullHistory: () => void;
}) {
const { t } = useTranslation();
// The ◀/▶ arrows step cyclically through the user's available modules (derived from `me`, so
@@ -116,6 +119,11 @@ export default function Header({
canNext={multiModule}
/>
{search}
{/* Per-user sync status — global, not per-module, so it rides the right end of the header
rather than costing the nav rail a whole block. */}
<div className="ml-auto">
<SyncStatus isAdmin={me.role === "admin"} onGoToFullHistory={onGoToFullHistory} />
</div>
</div>
);
}