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:
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
import { screen, waitFor } from "@testing-library/react";
|
||||
import { screen } from "@testing-library/react";
|
||||
import { userEvent } from "@testing-library/user-event";
|
||||
import { ChatButton } from "../../../components/layout/ChatButton.tsx";
|
||||
import { ChatContext } from "../../../contexts/chat/ChatContext.ts";
|
||||
@@ -17,8 +17,9 @@ describe("ChatButton", () => {
|
||||
</ChatContext.Provider>,
|
||||
{ ws: { unreadChatCount: 4 } },
|
||||
);
|
||||
await user.click(screen.getByRole("button", { name: "Chat (4 unread)" }));
|
||||
const chat = screen.getByRole("button", { name: "Chat (4 unread)" });
|
||||
expect(chat).toHaveClass("chat-button--unread");
|
||||
await user.click(chat);
|
||||
expect(openChat).toHaveBeenCalled();
|
||||
await waitFor(() => expect(screen.getByText("4")).toBeInTheDocument());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import { currentPath, renderWithContexts } from "../../render.tsx";
|
||||
import { defaultWSValue, WSContext } from "../../../contexts/ws/WSContext.ts";
|
||||
|
||||
describe("NotificationBell", () => {
|
||||
test("the bell shows the unread count and goes to notifications", async () => {
|
||||
test("the bell shows unread notifications and goes to them", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithContexts(<NotificationBell />, {
|
||||
ws: { unreadNotificationCount: 120 },
|
||||
@@ -15,7 +15,7 @@ describe("NotificationBell", () => {
|
||||
const bell = screen.getByRole("button", {
|
||||
name: "Notifications (120 unread)",
|
||||
});
|
||||
expect(bell).toHaveTextContent("99+");
|
||||
expect(bell).toHaveClass("notification-bell--unread");
|
||||
await user.click(bell);
|
||||
expect(currentPath()).toBe("/notifications");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user