feat(header): floating module header with cyclic nav and shared search
Replace the full-width top bar with a fixed floating header of glass pills: a fixed-position ModuleName (accent dot + label + prev/next cyclic module stepper) and a shared SearchBar. The header's left edge is anchored as if the nav rail and filter sidebar were both open, so it never shifts on collapse or module change; the right edge leaves a 10% margin. - ModuleName label width is measured live from the reachable modules' titles in the current language, recomputing on a language or account change. - Module names come from a shared moduleLabelKey (the same short labels as the nav rail); NavSidebar and the header now read from one source (lib/modules.ts). - The arrows step cyclically through moduleOrder(me) — dynamic, no hard-coded targets, wrapping at both ends. - Search is hoisted into the SearchBar for feed (YouTube search), plex, channels (including the Discovery tab) and playlists (new); Go button, Enter triggers it. - The Playlists left rail now reaches the top; header clearance via --hdr-h.
This commit is contained in:
+19
-1
@@ -182,6 +182,10 @@ export default function App() {
|
||||
const saveMsgTimer = useRef<number | undefined>(undefined);
|
||||
const [sidebarLayout, setSidebarLayoutState] = useState<SidebarLayout>(loadLayout);
|
||||
const [page, setPageState] = useState<Page>(loadInitialPage);
|
||||
// Client-side name filters for the Channels + Playlists lists — lifted here so the shared top
|
||||
// SearchBar can drive them (the modules read/seed them via props).
|
||||
const [channelsSearch, setChannelsSearch] = useState("");
|
||||
const [playlistsSearch, setPlaylistsSearch] = useState("");
|
||||
// Live YouTube search term (null = normal feed). Ephemeral: not persisted and not in the URL,
|
||||
// so a reload returns to the normal feed (a search spends quota, so we never auto-replay it).
|
||||
// The search is a feed SUB-VIEW that owns a browser-history entry (history.state._yt): the
|
||||
@@ -803,9 +807,20 @@ export default function App() {
|
||||
setFilters={setFilters}
|
||||
plexQ={plexQ}
|
||||
setPlexQ={setPlexQ}
|
||||
channelsSearch={channelsSearch}
|
||||
setChannelsSearch={setChannelsSearch}
|
||||
playlistsSearch={playlistsSearch}
|
||||
setPlaylistsSearch={setPlaylistsSearch}
|
||||
page={page}
|
||||
setPage={setPage}
|
||||
onYtSearch={enterYtSearch}
|
||||
/>
|
||||
{/* The header floats (fixed) over the content, so it no longer occupies flow space. This
|
||||
wrapper clears it with a top pad — EXCEPT on Playlists, whose own left rail must reach
|
||||
the very top (it pads only its content pane internally instead). */}
|
||||
<div
|
||||
className={`flex-1 min-w-0 flex flex-col ${page === "playlists" ? "" : "pt-[var(--hdr-h)]"}`}
|
||||
>
|
||||
{meQuery.data!.is_demo && <DemoBanner />}
|
||||
<VersionBanner onOpen={() => openReleaseNotes(CURRENT_VERSION)} />
|
||||
<main className="flex-1 min-w-0 overflow-y-auto">
|
||||
@@ -814,6 +829,8 @@ export default function App() {
|
||||
<Channels
|
||||
canWrite={meQuery.data!.can_write}
|
||||
isAdmin={meQuery.data!.role === "admin"}
|
||||
search={channelsSearch}
|
||||
setSearch={setChannelsSearch}
|
||||
focusChannelName={focusChannelName}
|
||||
focusChannelToken={focusChannelToken}
|
||||
onFocusChannel={focusChannel}
|
||||
@@ -841,7 +858,7 @@ export default function App() {
|
||||
) : page === "audit" && meQuery.data!.role === "admin" ? (
|
||||
<AuditLog />
|
||||
) : page === "playlists" ? (
|
||||
<Playlists canWrite={meQuery.data!.can_write} />
|
||||
<Playlists canWrite={meQuery.data!.can_write} search={playlistsSearch} />
|
||||
) : page === "notifications" ? (
|
||||
<NotificationsPanel filters={filters} setFilters={setFilters} setPage={setPage} onFocusChannel={focusChannel} />
|
||||
) : page === "messages" && !meQuery.data!.is_demo ? (
|
||||
@@ -884,6 +901,7 @@ export default function App() {
|
||||
)}
|
||||
</Suspense>
|
||||
</main>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{/* Toasts rise from the bottom-left, by the notification bell in the nav rail.
|
||||
|
||||
Reference in New Issue
Block a user