mirror of
https://github.com/block/buzz.git
synced 2026-10-27 12:40:30 +00:00
**Category:** fix **User Impact:** Stream and forum channels now show an accessible numeric badge for unread mentions while mention chips remain clear in every theme. **Problem:** Mention notifications contributed to the app and Dock badge, but inactive stream and forum rows only became bold, making it difficult to see where multiple mentions were waiting. Mention styling and generic destructive colors could also lose contrast or visual meaning in some themes. **Solution:** Use the same app-badge projection for non-DM channel mention counts, while preserving regular unread bolding, thread activity dots, DM counts, and manual unread behavior. Dedicated notification and opaque mention-highlight tokens keep the new treatments stable and readable across syntax themes. <details> <summary>File changes</summary> **desktop/src/features/channels/useUnreadChannels.ts** Projects app-badge-eligible mention and broadcast counts into stream and forum channel rows while retaining DM-specific counting and manual-unread semantics. **desktop/src/features/sidebar/ui/SidebarSection.tsx** Renders an accessible numeric notification pill on inactive non-DM channels and preserves the thread activity dot fallback. **desktop/src/shared/styles/globals/markdown.css** Applies the shared opaque yellow highlight to human and agent mention chips, including hover treatment. **desktop/src/shared/styles/globals/theme.css** Adds fixed notification and mention-highlight tokens with theme-independent contrast. **desktop/tailwind.config.js** Exposes the notification token pair through semantic Tailwind utilities. **desktop/tests/e2e/badge.spec.ts** Covers aggregated mention counts, broadcasts, unchanged unread tiers, exact accessible text, and badge contrast under an adversarial theme. **desktop/tests/e2e/mentions.spec.ts** Covers human and agent mention styling, hover behavior, dark mode, and WCAG text contrast. </details> ## Reproduction steps 1. Open a stream or forum channel, then navigate to another channel. 2. Receive two messages that mention you in the inactive channel. 3. Confirm the inactive row is bold and shows a red `2` pill matching the two notifications added to the app or Dock badge. 4. Receive a regular channel message and confirm the row only becomes bold, without a numeric pill. 5. Receive a reply in an interested thread and confirm the channel retains its activity dot instead of a mention count. 6. Switch between light and dark themes and confirm human and agent mention chips remain yellow with near-black readable text, including on hover. ## Screenshots Screenshots are posted in the PR discussion using immutable repository-hosted image URLs. Signed-off-by: tulsi <tulsi@block.xyz>
146 lines
5.8 KiB
JavaScript
146 lines
5.8 KiB
JavaScript
/** @type {import('tailwindcss').Config} */
|
|
export default {
|
|
theme: {
|
|
extend: {
|
|
// Sub-`text-xs` ramp for meta text (timestamps, count badges, tracking
|
|
// labels) and tiny glyphs. These follow the virtual typography rem
|
|
// (`--buzz-type-rem` in styles/globals/typography.css), which is
|
|
// rem-relative: Cmd +/- zooms it with the rest of the layout, and the
|
|
// Font size preference nudges it alone. Do NOT reintroduce arbitrary `text-[…rem]` / `text-[…px]` literals;
|
|
// the px-text guard rejects them. Stock scale picks up from xs.
|
|
fontSize: {
|
|
"2xs": "calc(var(--buzz-type-rem) * 0.6875)", // 11px at 16px type rem
|
|
"3xs": "calc(var(--buzz-type-rem) * 0.5)", // 8px at 16px type rem
|
|
badge: "calc(var(--buzz-type-rem) * 0.625)", // 10px at 16px type rem
|
|
// Shared channel, DM, thread, and composer type. Variables keep app-wide
|
|
// font size and keyboard zoom consistent without branching components.
|
|
message: [
|
|
"var(--conversation-message-font-size)",
|
|
{ lineHeight: "var(--conversation-message-line-height)" },
|
|
],
|
|
"message-timestamp": [
|
|
"var(--conversation-timestamp-font-size)",
|
|
{ lineHeight: "var(--conversation-timestamp-line-height)" },
|
|
],
|
|
// 40px at the 16px type rem — onboarding page titles.
|
|
title: [
|
|
"calc(var(--buzz-type-rem) * 2.5)",
|
|
{ lineHeight: "1.15", letterSpacing: "-0.02em" },
|
|
],
|
|
// 36px at the 16px type rem — backup-step private key.
|
|
"nsec-key": [
|
|
"calc(var(--buzz-type-rem) * 2.25)",
|
|
{ lineHeight: "1.3" },
|
|
],
|
|
},
|
|
lineHeight: {
|
|
// Keep fixed Tailwind line-height utilities in the typography scale so
|
|
// Cmd +/- cannot enlarge glyphs inside an unchanged line box. Single-
|
|
// line surfaces keep their existing truncate/overflow behavior.
|
|
3: "calc(var(--buzz-type-rem) * 0.75)",
|
|
4: "var(--buzz-type-rem)",
|
|
5: "calc(var(--buzz-type-rem) * 1.25)",
|
|
6: "calc(var(--buzz-type-rem) * 1.5)",
|
|
7: "calc(var(--buzz-type-rem) * 1.75)",
|
|
8: "calc(var(--buzz-type-rem) * 2)",
|
|
"message-author": "var(--conversation-author-line-height)",
|
|
},
|
|
boxShadow: {
|
|
"content-edge": "-1px -1px 0 0 hsl(var(--sidebar-border) / 0.45)",
|
|
// Edge + elevation for a surface anchored to the right of the content
|
|
// area, whose only exposed edge faces left. Tailwind's stock shadows are
|
|
// all y-offset, so they cast almost nothing sideways — `shadow-xl` on a
|
|
// left-facing edge is nearly invisible. Both layers run -x so they wrap
|
|
// the surface's rounded left corners: the hairline draws the boundary
|
|
// (and carries dark mode, where a black shadow reads as nothing), the
|
|
// soft layer carries the lift. A left-only `border` can't do this job —
|
|
// it tapers out at each corner instead of turning it.
|
|
"panel-left":
|
|
"-1px 0 0 0 hsl(var(--border) / 0.8), -16px 0 32px -12px rgb(0 0 0 / 0.18)",
|
|
},
|
|
borderRadius: {
|
|
lg: "var(--radius)",
|
|
md: "calc(var(--radius) - 2px)",
|
|
sm: "calc(var(--radius) - 4px)",
|
|
},
|
|
spacing: {
|
|
4.5: "1.125rem",
|
|
"conversation-body": "var(--conversation-body-gap)",
|
|
"conversation-list": "var(--conversation-list-item-gap)",
|
|
"conversation-paragraph": "var(--conversation-paragraph-gap)",
|
|
"conversation-row": "var(--conversation-row-padding-block)",
|
|
},
|
|
fontFamily: {
|
|
sans: [
|
|
'"Inter Variable"',
|
|
"Inter",
|
|
'"Avenir Next"',
|
|
'"Segoe UI"',
|
|
"sans-serif",
|
|
],
|
|
},
|
|
colors: {
|
|
background: "hsl(var(--background))",
|
|
foreground: "hsl(var(--foreground))",
|
|
card: {
|
|
DEFAULT: "hsl(var(--card))",
|
|
foreground: "hsl(var(--card-foreground))",
|
|
},
|
|
popover: {
|
|
DEFAULT: "hsl(var(--popover))",
|
|
foreground: "hsl(var(--popover-foreground))",
|
|
},
|
|
primary: {
|
|
DEFAULT: "hsl(var(--primary))",
|
|
foreground: "hsl(var(--primary-foreground))",
|
|
},
|
|
secondary: {
|
|
DEFAULT: "hsl(var(--secondary))",
|
|
foreground: "hsl(var(--secondary-foreground))",
|
|
},
|
|
muted: {
|
|
DEFAULT: "hsl(var(--muted))",
|
|
foreground: "hsl(var(--muted-foreground))",
|
|
},
|
|
accent: {
|
|
DEFAULT: "hsl(var(--accent))",
|
|
foreground: "hsl(var(--accent-foreground))",
|
|
},
|
|
destructive: {
|
|
DEFAULT: "hsl(var(--destructive))",
|
|
foreground: "hsl(var(--destructive-foreground))",
|
|
},
|
|
notification: {
|
|
DEFAULT: "hsl(var(--notification))",
|
|
foreground: "hsl(var(--notification-foreground))",
|
|
},
|
|
border: "hsl(var(--border))",
|
|
input: "hsl(var(--input))",
|
|
ring: "hsl(var(--ring))",
|
|
sidebar: {
|
|
DEFAULT: "hsl(var(--sidebar-background))",
|
|
foreground: "hsl(var(--sidebar-foreground))",
|
|
primary: "hsl(var(--sidebar-primary))",
|
|
"primary-foreground": "hsl(var(--sidebar-primary-foreground))",
|
|
active: "hsl(var(--sidebar-active))",
|
|
"active-foreground": "hsl(var(--sidebar-active-foreground))",
|
|
accent: "hsl(var(--sidebar-accent))",
|
|
"accent-foreground": "hsl(var(--sidebar-accent-foreground))",
|
|
border: "hsl(var(--sidebar-border))",
|
|
ring: "hsl(var(--sidebar-ring))",
|
|
},
|
|
status: {
|
|
added: "var(--status-added)",
|
|
deleted: "var(--status-deleted)",
|
|
modified: "var(--status-modified)",
|
|
},
|
|
warning: {
|
|
DEFAULT: "var(--ui-warning)",
|
|
bg: "var(--ui-warning-bg)",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
plugins: [],
|
|
};
|