v4: the header's controls are line icons, and the avatar leads them — 🔍, ✕, 💬 and 🔔 were four emoji in four palettes beside the avatar and the "+", none of them the theme's. They are now stroked icons (NavIcons.tsx, which the search bar's submit and ChatFab share) in the text colour, their bodies washed with the accent; the wash deepens on hover, and fills while something is unread, with a small dot in place of the red count (the count stays in the button's label and the tab's title, and ChatFab keeps its own). Themes set the line through --nav-icon-stroke, -linecap, -linejoin and -tint-strength: Brutalist heavy and square-cut, Times hairline in ink (its grayscale filter no longer needed on them), GeoCities fat and soaked. The search toggle was a ghost button with its own hover; it now shares the chat button's and the bell's rule, background and borders in every theme. The avatar sat among the icons, its hover box larger than theirs and 1.5px higher (a block .user-menu left a line-box gap under the inline-flex trigger): it now leads the row, where the name and Playlists links stand on wide screens, so the icons run unbroken to the "+"; it is 32px, and hover rings it with the accent instead of a box. 669 frontend tests pass, and tsc, eslint and deno fmt are clean; checked in screenshots in all six styles, light and dark, at 390px, at rest and unread, and Smooth and Brutalist at 1280px.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
khannurien
2026-10-08 21:56:19 +00:00
parent a0c8b1d509
commit 7531be300e
14 changed files with 203 additions and 110 deletions

View File

@@ -1775,7 +1775,7 @@ body.has-fab .page-content {
top 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.chat-fab-icon {
.chat-fab .chat-fab-icon {
width: 1.6rem;
height: 1.6rem;
}
@@ -3075,23 +3075,38 @@ body.has-player .chat-fab {
justify-content: center;
}
/* Ghost search button — opens the search (in the center column, or the row
under the header on small viewports) and turns into its ✕ */
.nav-search-btn {
display: flex;
align-items: center;
padding: 0.35rem;
background: transparent;
border: none;
color: inherit;
text-decoration: none;
font-size: var(--text-base);
cursor: pointer;
border-radius: var(--radius-md);
/* Line icons (NavIcons.tsx), stroked in the text colour. */
.nav-icon {
width: 1.25rem;
height: 1.25rem;
flex-shrink: 0;
fill: none;
stroke: currentColor;
stroke-width: var(--nav-icon-stroke);
stroke-linecap: var(--nav-icon-linecap);
stroke-linejoin: var(--nav-icon-linejoin);
}
.nav-search-btn:hover {
background: var(--color-surface);
/* Two-tone in the header and its search: the icons' bodies take a wash of
the accent, which deepens on hover and fills while something is unread.
The floating chat button sits on the accent, so its bubble stays hollow. */
.app-header .nav-icon-tint,
.search-bar-btn .nav-icon-tint {
fill: color-mix(in srgb, var(--color-accent) var(--nav-icon-tint-strength),
transparent);
transition: fill var(--dur-base);
}
.nav-search-btn:hover,
.chat-button:hover,
.notification-bell:hover,
.search-bar-btn:hover {
--nav-icon-tint-strength: 45%;
}
.chat-button--unread,
.notification-bell--unread {
--nav-icon-tint-strength: 100%;
}
/* Text links — visible only at wide viewports */
@@ -3137,8 +3152,11 @@ body.has-player .chat-fab {
}
/* ── User menu (compact nav) ── */
/* A flex box, so the inline-flex trigger leaves no line-box gap under it
that would sit it higher than the buttons beside it. */
.user-menu {
position: relative;
display: flex;
}
.user-menu-trigger {
@@ -3152,8 +3170,15 @@ body.has-player .chat-fab {
transition: background var(--dur-base);
}
.user-menu-trigger:hover {
background: var(--color-header-user-bg-hover);
/* The avatar fills its button, so a hover background would read as a box
bigger than the icons' ones: an accent ring shows instead. */
.user-menu-trigger > * {
transition: box-shadow var(--dur-base);
}
.user-menu-trigger:hover > *,
.user-menu-trigger[aria-expanded="true"] > * {
box-shadow: 0 0 0 2px var(--color-accent);
}
.user-menu-dropdown {
@@ -6484,24 +6509,28 @@ body.has-player .chat-fab {
}
}
/* ── Header icon buttons ──
Search (which opens the search, in the center column or the row under the
header on small viewports, and turns into its ✕), chat and the bell. */
.nav-search-btn,
.chat-button,
.notification-bell {
position: relative;
background: var(--color-header-user-bg);
color: inherit;
border: none;
cursor: pointer;
font-size: var(--text-md);
font-weight: 600;
padding: 0.35rem 0.85rem;
border-radius: var(--radius-lg);
transition: background var(--dur-base);
display: inline-flex;
align-items: center;
}
.nav-search-btn:hover,
.chat-button:hover,
.notification-bell:hover {
background: var(--color-header-user-bg-hover);
}
.notification-bell-icon {
display: inline-block;
transform-origin: 50% 10%;
}
.notification-bell--ringing .notification-bell-icon {
@@ -6527,25 +6556,16 @@ body.has-player .chat-fab {
box-shadow: 0 0 0 2px var(--color-bg);
}
/* ── Header chat button ── */
.chat-button {
position: relative;
background: var(--color-header-user-bg);
border: none;
cursor: pointer;
font-size: var(--text-md);
font-weight: 600;
padding: 0.35rem 0.85rem;
border-radius: var(--radius-lg);
transition: background var(--dur-base);
display: inline-flex;
align-items: center;
}
.chat-button:hover {
background: var(--color-header-user-bg-hover);
}
.chat-button-icon {
display: inline-block;
/* The header's buttons fill their icon while something is unread, so a dot
is enough; the count is in their label. */
.notification-badge--dot {
top: 6px;
right: 6px;
min-width: 0;
width: 8px;
height: 8px;
padding: 0;
background: var(--color-accent);
}
/* ── Notifications page ── */
@@ -7067,6 +7087,8 @@ body.has-player .chat-fab {
}
.search-bar-btn {
display: flex;
align-items: center;
padding: 0.3rem 0.55rem;
background: transparent;
border: var(--border-width) solid var(--color-border-subtle);