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:
104
src/App.css
104
src/App.css
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user