Sidebar: arrow sits directly below the logo, in both states

As requested: the collapse/expand control is its own row right under the
brand row — labelled "Collapse sidebar" when expanded, icon-only and
centred when collapsed — so it never moves anywhere else. Measured: the
same y (73px) in both states, directly below the logo.

(The previous attempt anchored it to the rail's top-right corner instead —
not what was asked.)

README: decision 22 updated. SW -> freezmo-v42.
This commit is contained in:
Martin Dvořák 2026-10-12 11:57:17 +00:00
commit 43dd4e4ec9
3 changed files with 34 additions and 38 deletions

View file

@ -103,43 +103,39 @@ function NavContent({ collapsed = false }: { collapsed?: boolean }) {
return (
<div className="flex min-h-0 flex-1 flex-col">
{/* brand ---------------------------------------------------------- */}
<div className={cn("mb-1 flex items-center", collapsed ? "justify-end" : "justify-between")}>
{!collapsed ? (
<Link
href="/"
className="nav-row flex-1 gap-2.5"
aria-label={t("header.home")}
title="Freezmo"
>
{brandMark}
<span className="text-[15px] font-semibold tracking-[-0.01em] text-[var(--text)]">Freezmo</span>
{IS_DEV_INSTANCE ? (
<span className="rounded-md border border-amber-400/60 bg-amber-400/15 px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide text-amber-700 dark:text-amber-300">
DEV
</span>
) : null}
</Link>
) : null}
{/* One home for the arrow: the rail's top-right corner in both states.
It used to swap between the brand row and the middle of the icon
column, which read as the control jumping around. */}
<button
type="button"
onClick={() => sidebarCollapse.set(!collapsed)}
aria-label={collapsed ? t("sidebar.expand") : t("sidebar.collapse")}
title={collapsed ? t("sidebar.expand") : t("sidebar.collapse")}
className="grid size-8 shrink-0 place-items-center rounded-lg text-[var(--text-subtle)] transition hover:bg-[var(--hover)] hover:text-[var(--text)]"
<div className={cn("mb-1 flex items-center", collapsed ? "justify-center" : "justify-between")}>
<Link
href="/"
className={cn("nav-row gap-2.5", collapsed ? "w-auto px-2" : "flex-1")}
aria-label={t("header.home")}
title="Freezmo"
>
{collapsed ? <ChevronRightIcon className="size-4" /> : <ChevronLeftIcon className="size-4" />}
</button>
{brandMark}
{!collapsed ? (
<>
<span className="text-[15px] font-semibold tracking-[-0.01em] text-[var(--text)]">Freezmo</span>
{IS_DEV_INSTANCE ? (
<span className="rounded-md border border-amber-400/60 bg-amber-400/15 px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide text-amber-700 dark:text-amber-300">
DEV
</span>
) : null}
</>
) : null}
</Link>
</div>
{/* collapsed: the brand mark leads the icon column ------------------ */}
{collapsed ? (
<Link href="/" className="nav-row mb-3 justify-center px-2" aria-label={t("header.home")} title="Freezmo">
{brandMark}
</Link>
) : null}
{/* collapse / expand: its own row directly below the logo, in both
states, so the arrow never jumps around the rail. */}
<button
type="button"
onClick={() => sidebarCollapse.set(!collapsed)}
aria-label={collapsed ? t("sidebar.expand") : t("sidebar.collapse")}
title={collapsed ? t("sidebar.expand") : t("sidebar.collapse")}
className={cn("nav-row mb-3", collapsed && "justify-center px-2")}
>
{collapsed ? <ChevronRightIcon className="size-4 shrink-0" /> : <ChevronLeftIcon className="size-4 shrink-0" />}
{!collapsed ? <span className="flex-1 truncate text-left">{t("sidebar.collapse")}</span> : null}
</button>
{/* new deck: a quiet row, not a competing primary button ---------- */}
<Link