feat(nav): N1 — collapsible left nav sidebar (Design C)

Move the modules (Feed/Channels/Playlists/Stats) out of the avatar dropdown into a
persistent left sidebar with icon+label entries; collapses to a thin icon rail
(persisted in localStorage). Account actions (About, Sign out, admin badge) move to a
popover at the sidebar bottom; Settings is a rail entry. Header is now a contextual top
bar (sync status, feed scope + search or page title, language, notifications) — logo and
account menu removed from it. New nav.json strings (HU/EN/DE). First step of Epic N.
This commit is contained in:
npeter83 2026-06-16 00:42:23 +02:00
parent 3143d1c1db
commit 4a80ea5aa5
6 changed files with 234 additions and 166 deletions

View file

@ -21,6 +21,7 @@ import { configureNotifications, notify } from "./lib/notifications";
import { setHintsEnabled } from "./lib/hints";
import Login from "./components/Login";
import Header from "./components/Header";
import NavSidebar from "./components/NavSidebar";
import Sidebar from "./components/Sidebar";
import Feed from "./components/Feed";
import Channels, { type ChannelStatusFilter } from "./components/Channels";
@ -192,32 +193,37 @@ export default function App() {
);
return (
<div className="h-screen flex flex-col bg-bg text-fg">
<Header
<div className="h-screen flex bg-bg text-fg">
<NavSidebar
me={meQuery.data!}
filters={filters}
setFilters={setFilters}
page={page}
setPage={setPage}
onOpenSettings={() => setSettingsOpen(true)}
onOpenAbout={() => setAboutOpen(true)}
onChangeLanguage={changeLanguage}
onGoToFullHistory={() => {
setChannelFilter("needs_full");
setPage("channels");
}}
/>
<VersionBanner onOpen={() => openReleaseNotes(CURRENT_VERSION)} />
<div className="flex flex-1 min-h-0">
{page === "feed" && (
<Sidebar
filters={filters}
setFilters={setFilters}
layout={sidebarLayout}
setLayout={setSidebarLayout}
/>
)}
<main className="flex-1 min-w-0 overflow-y-auto">
<div className="flex-1 min-w-0 flex flex-col">
<Header
me={meQuery.data!}
filters={filters}
setFilters={setFilters}
page={page}
onChangeLanguage={changeLanguage}
onGoToFullHistory={() => {
setChannelFilter("needs_full");
setPage("channels");
}}
/>
<VersionBanner onOpen={() => openReleaseNotes(CURRENT_VERSION)} />
<div className="flex flex-1 min-h-0">
{page === "feed" && (
<Sidebar
filters={filters}
setFilters={setFilters}
layout={sidebarLayout}
setLayout={setSidebarLayout}
/>
)}
<main className="flex-1 min-w-0 overflow-y-auto">
{page === "channels" ? (
<Channels
canWrite={meQuery.data!.can_write}
@ -242,7 +248,8 @@ export default function App() {
onOpenWizard={() => setWizardOpen(true)}
/>
)}
</main>
</main>
</div>
</div>
{settingsOpen && (
<SettingsPanel