From 477bea19b1a9c10eec7ba3ef835f8b6d3b387088 Mon Sep 17 00:00:00 2001 From: Huxpro <5563315+Huxpro@users.noreply.github.com> Date: Thu, 4 Jun 2026 11:38:45 -0700 Subject: [PATCH 1/9] refactor(theme): centralize platform color tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extracts the inline PLATFORM_TINT map from the homepage feature row into src/components/platform-navigation/platform-colors.ts as the single source of truth for platform brand color across the site. Covers every platform key consumed by PlatformBadge — including the clay umbrella + clay_* variants — and exposes both the Tailwind tint string and the underlying hex/bg values so the PlatformBadge CSS can stay in lockstep with what the homepage row uses. Brand mapping: apple family (ios, macos) -> zinc android -> emerald harmony -> rose web / web_lynx -> orange windows -> sky clay umbrella + variants -> cyan Change-Id: I10af83dc736bf9e057e3b6bd1a6d0c4a0c93d7fe --- src/components/home-comps/features/icon.tsx | 17 +-- .../platform-navigation/platform-colors.ts | 104 ++++++++++++++++++ 2 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 src/components/platform-navigation/platform-colors.ts diff --git a/src/components/home-comps/features/icon.tsx b/src/components/home-comps/features/icon.tsx index 9bedd36e1..864068613 100644 --- a/src/components/home-comps/features/icon.tsx +++ b/src/components/home-comps/features/icon.tsx @@ -2,22 +2,15 @@ import React from 'react'; import { withBase } from '@rspress/core/runtime'; import { cn } from '@/lib/utils'; import { PlatformSvg } from '@/components/platform-navigation/PlatformIcon'; +import { + PLATFORM_TINT, + type PlatformKey, +} from '@/components/platform-navigation/platform-colors'; import ReactLynxIcon from '@/components/api-table/compat-table/assets/icons/reactlynx.svg?react'; import VueLynxIcon from '@assets/home/vue-lynx-logo.svg?react'; import styles from './index.module.less'; -// Each platform gets a brand-adjacent hue, kept at matching tonal weight -// (Tailwind ~600 in light mode, ~400 in dark) so the row stays harmonious. -const PLATFORM_TINT: Record = { - ios: 'text-zinc-700 dark:text-zinc-300', - macos: 'text-zinc-700 dark:text-zinc-300', - android: 'text-emerald-600 dark:text-emerald-400', - harmony: 'text-rose-600 dark:text-rose-400', - web: 'text-orange-600 dark:text-orange-400', - windows: 'text-sky-600 dark:text-sky-400', -}; - -const PlatformIconWrapper = ({ platform }: { platform: string }) => ( +const PlatformIconWrapper = ({ platform }: { platform: PlatformKey }) => ( ` reuses the underlying-platform icon glyph, so the color +// is the only thing keeping `ClayAndroidOnly` and `AndroidOnly` visually +// distinct. That's why every clay_* shares one Clay color rather than +// borrowing the underlying-platform color. + +export type PlatformKey = + | 'ios' + | 'macos' + | 'android' + | 'harmony' + | 'web' + | 'web_lynx' + | 'windows' + | 'clay' + | 'clay_ios' + | 'clay_android' + | 'clay_macos' + | 'clay_windows'; + +type PlatformHue = { + // Tailwind class string for icon/text tinting (light: ~600, dark: ~400). + tint: string; + // Solid hex pair for inline styles and CSS-variable overrides. + // light = Tailwind 600, dark = Tailwind 400. + hex: { light: string; dark: string }; + // Subtle container background pair used by PlatformBadge. + // light = Tailwind 50, dark = Tailwind 950 + 60% (mixed against bg by the + // browser via alpha). Keeps the badge calm so the icon does the signalling. + bg: { light: string; dark: string }; +}; + +const APPLE_HUE: PlatformHue = { + tint: 'text-zinc-700 dark:text-zinc-300', + hex: { light: '#52525b', dark: '#d4d4d8' }, + bg: { light: '#fafafa', dark: '#27272a99' }, +}; + +const ANDROID_HUE: PlatformHue = { + tint: 'text-emerald-600 dark:text-emerald-400', + hex: { light: '#059669', dark: '#34d399' }, + bg: { light: '#ecfdf5', dark: '#022c2299' }, +}; + +const HARMONY_HUE: PlatformHue = { + tint: 'text-rose-600 dark:text-rose-400', + hex: { light: '#e11d48', dark: '#fb7185' }, + bg: { light: '#fff1f2', dark: '#4c051599' }, +}; + +const WEB_HUE: PlatformHue = { + tint: 'text-orange-600 dark:text-orange-400', + hex: { light: '#ea580c', dark: '#fb923c' }, + bg: { light: '#fff7ed', dark: '#43140799' }, +}; + +const WINDOWS_HUE: PlatformHue = { + tint: 'text-sky-600 dark:text-sky-400', + hex: { light: '#0284c7', dark: '#38bdf8' }, + bg: { light: '#f0f9ff', dark: '#082f4999' }, +}; + +const CLAY_HUE: PlatformHue = { + tint: 'text-cyan-600 dark:text-cyan-400', + hex: { light: '#0891b2', dark: '#22d3ee' }, + bg: { light: '#ecfeff', dark: '#08344499' }, +}; + +export const PLATFORM_HUES: Record = { + ios: APPLE_HUE, + macos: APPLE_HUE, + android: ANDROID_HUE, + harmony: HARMONY_HUE, + web: WEB_HUE, + web_lynx: WEB_HUE, + windows: WINDOWS_HUE, + clay: CLAY_HUE, + clay_ios: CLAY_HUE, + clay_android: CLAY_HUE, + clay_macos: CLAY_HUE, + clay_windows: CLAY_HUE, +}; + +// Tailwind tint classes by platform key. Kept as a separate export because +// the homepage icon row only needs the tint string, not the full hue object. +export const PLATFORM_TINT: Record = Object.fromEntries( + (Object.keys(PLATFORM_HUES) as PlatformKey[]).map((key) => [ + key, + PLATFORM_HUES[key].tint, + ]), +) as Record; From 1d22ce1a4ca8fe2b5493952b0173b2697eb0b3c0 Mon Sep 17 00:00:00 2001 From: Huxpro <5563315+Huxpro@users.noreply.github.com> Date: Thu, 4 Jun 2026 11:39:02 -0700 Subject: [PATCH 2/9] feat(badge): unify PlatformBadge palette and reframe Only/No variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three coordinated changes so the API-doc PlatformBadge stops fighting the rest of the site: 1. Palette unified to the shared platform color tokens. iOS goes from saturated blue back to Apple's zinc-silver, Harmony from orange to the Huawei rose, web from purple to lynx orange, and the four clay_* variants collapse from cyan/indigo/teal/sky into one Clay cyan so ClayAndroidOnly stays visually distinct from AndroidOnly even though they share the Android glyph. 2. Contrast quieted. Background drops from a saturated ~500@10% wash to a tinted 50/950, while the icon stays in full platform color so the badge is still scannable at a glance — the icon does the signalling. 3. Visual semantics for *Only / No*. Previously info/warning/danger all rendered in the same platform color, so "iOS Only" and "No iOS" looked like the same chip with different words. Now: default platform color, subtle bg .platform-badge--only adds an inset platform-tinted ring (emphasis) .platform-badge--no drops platform color, mutes to neutral, strikes the label, dims the icon (negation) Also relabels bare `clay` as "Desktop" in the user-facing label only — the component export names (ClayOnly, NoClay), APIStatus colors, and compat tables keep `clay`. Temporary until the desktop branding settles. Change-Id: If12a812aab5d351e19c39f01065847954ca24d85 --- src/components/api-badge/PlatformBadge.css | 251 ++++++++++----------- src/components/api-badge/PlatformBadge.tsx | 32 ++- 2 files changed, 136 insertions(+), 147 deletions(-) diff --git a/src/components/api-badge/PlatformBadge.css b/src/components/api-badge/PlatformBadge.css index 4cf2c9477..930877eca 100644 --- a/src/components/api-badge/PlatformBadge.css +++ b/src/components/api-badge/PlatformBadge.css @@ -1,175 +1,150 @@ /* - * Platform-specific color overrides for PlatformBadge. + * PlatformBadge styling. Single source of truth for platform color is + * platform-navigation/platform-colors.ts — hex values below mirror that map + * exactly. If you change one, change both. * - * Overrides all Rspress Badge type variables (info, warning, danger) - * so the badge always renders in the platform's color. - * - * Color values match PLATFORM_CONFIG in src/components/api-status/constants.tsx: - * android → emerald - * ios → blue - * harmony → orange - * web_lynx → purple - * clay → teal - * clay_android → teal - * clay_ios → cyan - * clay_macos → indigo - * clay_windows → sky - * - * Light mode: Tailwind {color}-700 for text, {color}-500 at ~10% for bg. - * Dark mode: Tailwind {color}-400 for text, {color}-500 at ~15% for bg. + * Design intent: + * - Icon stays in full platform color so the badge is still scannable. + * - Background drops to a tinted 50/950 wash. Less ink, same signal. + * - The semantic variants (default / *Only / No*) read as three distinct + * things instead of "same chip, different word": + * default — platform color, subtle bg + * .platform-badge--only — adds an inset ring in the platform color + * .platform-badge--no — drops platform color, mutes, strikes the label */ -/* android → emerald */ -.platform-badge-android { - --rp-container-info-text: #047857; - --rp-container-info-bg: #10b9811a; - --rp-container-warning-text: #047857; - --rp-container-warning-bg: #10b9811a; - --rp-container-danger-text: #047857; - --rp-container-danger-bg: #10b9811a; +/* ── Base: tighten Rspress's container variables to a quiet, tinted wash ── */ + +/* apple family (ios, macos) → zinc */ +.platform-badge-ios, +.platform-badge-clay_ios, +.platform-badge-macos, +.platform-badge-clay_macos { + --platform-badge-fg: #52525b; /* zinc-600 */ + --platform-badge-bg: #fafafa; /* zinc-50 */ + --platform-badge-ring: #d4d4d8; /* zinc-300 */ } -/* ios → blue */ -.platform-badge-ios { - --rp-container-info-text: #1d4ed8; - --rp-container-info-bg: #3b82f61a; - --rp-container-warning-text: #1d4ed8; - --rp-container-warning-bg: #3b82f61a; - --rp-container-danger-text: #1d4ed8; - --rp-container-danger-bg: #3b82f61a; +/* android → emerald */ +.platform-badge-android { + --platform-badge-fg: #059669; + --platform-badge-bg: #ecfdf5; + --platform-badge-ring: #a7f3d0; } -/* harmony → orange */ +/* harmony → rose */ .platform-badge-harmony { - --rp-container-info-text: #c2410c; - --rp-container-info-bg: #f973161a; - --rp-container-warning-text: #c2410c; - --rp-container-warning-bg: #f973161a; - --rp-container-danger-text: #c2410c; - --rp-container-danger-bg: #f973161a; + --platform-badge-fg: #e11d48; + --platform-badge-bg: #fff1f2; + --platform-badge-ring: #fecdd3; } -/* web_lynx → purple */ +/* web / web_lynx → orange */ +.platform-badge-web, .platform-badge-web_lynx { - --rp-container-info-text: #7e22ce; - --rp-container-info-bg: #a855f71a; - --rp-container-warning-text: #7e22ce; - --rp-container-warning-bg: #a855f71a; - --rp-container-danger-text: #7e22ce; - --rp-container-danger-bg: #a855f71a; + --platform-badge-fg: #ea580c; + --platform-badge-bg: #fff7ed; + --platform-badge-ring: #fed7aa; } -/* clay, clay_android → teal */ -.platform-badge-clay, -.platform-badge-clay_android { - --rp-container-info-text: #0f766e; - --rp-container-info-bg: #14b8a61a; - --rp-container-warning-text: #0f766e; - --rp-container-warning-bg: #14b8a61a; - --rp-container-danger-text: #0f766e; - --rp-container-danger-bg: #14b8a61a; -} - -/* clay_ios → cyan */ -.platform-badge-clay_ios { - --rp-container-info-text: #0e7490; - --rp-container-info-bg: #06b6d41a; - --rp-container-warning-text: #0e7490; - --rp-container-warning-bg: #06b6d41a; - --rp-container-danger-text: #0e7490; - --rp-container-danger-bg: #06b6d41a; -} - -/* clay_macos → indigo */ -.platform-badge-clay_macos { - --rp-container-info-text: #4338ca; - --rp-container-info-bg: #6366f11a; - --rp-container-warning-text: #4338ca; - --rp-container-warning-bg: #6366f11a; - --rp-container-danger-text: #4338ca; - --rp-container-danger-bg: #6366f11a; +/* windows (incl. clay_windows underlying surface) → sky for raw windows */ +.platform-badge-windows { + --platform-badge-fg: #0284c7; + --platform-badge-bg: #f0f9ff; + --platform-badge-ring: #bae6fd; } -/* clay_windows → sky */ +/* clay umbrella + variants → cyan (Clay/Desktop signature) */ +.platform-badge-clay, +.platform-badge-clay_android, .platform-badge-clay_windows { - --rp-container-info-text: #0369a1; - --rp-container-info-bg: #0ea5e91a; - --rp-container-warning-text: #0369a1; - --rp-container-warning-bg: #0ea5e91a; - --rp-container-danger-text: #0369a1; - --rp-container-danger-bg: #0ea5e91a; + --platform-badge-fg: #0891b2; + --platform-badge-bg: #ecfeff; + --platform-badge-ring: #a5f3fc; } -/* Dark mode */ -:where(html.rp-dark, html.dark) .platform-badge-android { - --rp-container-info-text: #34d399; - --rp-container-info-bg: #10b98126; - --rp-container-warning-text: #34d399; - --rp-container-warning-bg: #10b98126; - --rp-container-danger-text: #34d399; - --rp-container-danger-bg: #10b98126; +/* Dark mode — bump foreground to ~400, swap bg to a deep tinted wash */ +:where(html.rp-dark, html.dark) .platform-badge-ios, +:where(html.rp-dark, html.dark) .platform-badge-clay_ios, +:where(html.rp-dark, html.dark) .platform-badge-macos, +:where(html.rp-dark, html.dark) .platform-badge-clay_macos { + --platform-badge-fg: #d4d4d8; + --platform-badge-bg: #27272a99; + --platform-badge-ring: #52525b; } -:where(html.rp-dark, html.dark) .platform-badge-ios { - --rp-container-info-text: #60a5fa; - --rp-container-info-bg: #3b82f626; - --rp-container-warning-text: #60a5fa; - --rp-container-warning-bg: #3b82f626; - --rp-container-danger-text: #60a5fa; - --rp-container-danger-bg: #3b82f626; +:where(html.rp-dark, html.dark) .platform-badge-android { + --platform-badge-fg: #34d399; + --platform-badge-bg: #022c2299; + --platform-badge-ring: #065f46; } :where(html.rp-dark, html.dark) .platform-badge-harmony { - --rp-container-info-text: #fb923c; - --rp-container-info-bg: #f9731626; - --rp-container-warning-text: #fb923c; - --rp-container-warning-bg: #f9731626; - --rp-container-danger-text: #fb923c; - --rp-container-danger-bg: #f9731626; + --platform-badge-fg: #fb7185; + --platform-badge-bg: #4c051599; + --platform-badge-ring: #9f1239; } +:where(html.rp-dark, html.dark) .platform-badge-web, :where(html.rp-dark, html.dark) .platform-badge-web_lynx { - --rp-container-info-text: #c084fc; - --rp-container-info-bg: #a855f726; - --rp-container-warning-text: #c084fc; - --rp-container-warning-bg: #a855f726; - --rp-container-danger-text: #c084fc; - --rp-container-danger-bg: #a855f726; + --platform-badge-fg: #fb923c; + --platform-badge-bg: #43140799; + --platform-badge-ring: #9a3412; +} + +:where(html.rp-dark, html.dark) .platform-badge-windows { + --platform-badge-fg: #38bdf8; + --platform-badge-bg: #082f4999; + --platform-badge-ring: #075985; } :where(html.rp-dark, html.dark) .platform-badge-clay, -:where(html.rp-dark, html.dark) .platform-badge-clay_android { - --rp-container-info-text: #2dd4bf; - --rp-container-info-bg: #14b8a626; - --rp-container-warning-text: #2dd4bf; - --rp-container-warning-bg: #14b8a626; - --rp-container-danger-text: #2dd4bf; - --rp-container-danger-bg: #14b8a626; +:where(html.rp-dark, html.dark) .platform-badge-clay_android, +:where(html.rp-dark, html.dark) .platform-badge-clay_windows { + --platform-badge-fg: #22d3ee; + --platform-badge-bg: #08344499; + --platform-badge-ring: #155e75; } -:where(html.rp-dark, html.dark) .platform-badge-clay_ios { - --rp-container-info-text: #22d3ee; - --rp-container-info-bg: #06b6d426; - --rp-container-warning-text: #22d3ee; - --rp-container-warning-bg: #06b6d426; - --rp-container-danger-text: #22d3ee; - --rp-container-danger-bg: #06b6d426; +/* ── Apply our variables to Rspress's container slots ────────────────────── */ + +[class*='platform-badge-'] { + --rp-container-info-text: var(--platform-badge-fg); + --rp-container-info-bg: var(--platform-badge-bg); + --rp-container-warning-text: var(--platform-badge-fg); + --rp-container-warning-bg: var(--platform-badge-bg); + --rp-container-danger-text: var(--platform-badge-fg); + --rp-container-danger-bg: var(--platform-badge-bg); } -:where(html.rp-dark, html.dark) .platform-badge-clay_macos { - --rp-container-info-text: #818cf8; - --rp-container-info-bg: #6366f126; - --rp-container-warning-text: #818cf8; - --rp-container-warning-bg: #6366f126; - --rp-container-danger-text: #818cf8; - --rp-container-danger-bg: #6366f126; +/* ── Variant: *Only — emphasize with an inset platform-tinted ring ──────── */ + +.platform-badge--only .rp-badge { + box-shadow: inset 0 0 0 1px var(--platform-badge-ring); } -:where(html.rp-dark, html.dark) .platform-badge-clay_windows { - --rp-container-info-text: #38bdf8; - --rp-container-info-bg: #0ea5e926; - --rp-container-warning-text: #38bdf8; - --rp-container-warning-bg: #0ea5e926; - --rp-container-danger-text: #38bdf8; - --rp-container-danger-bg: #0ea5e926; +/* ── Variant: No* — drop the platform color, mute, strike the label ─────── */ + +.platform-badge--no { + /* Override the cascade above with neutral grays so "No iOS" doesn't read + the same as "iOS Only" at a glance. */ + --platform-badge-fg: #71717a; /* zinc-500 */ + --platform-badge-bg: #f4f4f5; /* zinc-100 */ +} + +:where(html.rp-dark, html.dark) .platform-badge--no { + --platform-badge-fg: #a1a1aa; /* zinc-400 */ + --platform-badge-bg: #18181b99; /* zinc-900 @ 60% */ +} + +.platform-badge--no .platform-badge__label { + text-decoration: line-through; + text-decoration-thickness: 1px; + text-decoration-color: currentColor; +} + +/* The icon also dims in the No* variant — full saturation here would fight + the strikethrough and read as "supported but crossed out". */ +.platform-badge--no .platform-badge__icon { + opacity: 0.7; } diff --git a/src/components/api-badge/PlatformBadge.tsx b/src/components/api-badge/PlatformBadge.tsx index 63cd16109..1cea011e9 100644 --- a/src/components/api-badge/PlatformBadge.tsx +++ b/src/components/api-badge/PlatformBadge.tsx @@ -25,12 +25,14 @@ type ExtendedPlatformName = LCD.PlatformName | 'clay'; /** * Maps a platform name to its full name. - * @param platform The platform name to map. - * @returns The full name of the given platform. + * + * Note: bare `clay` renders as "Desktop" in user-facing badges while the + * underlying type stays `clay` (component exports, APIStatus, compat tables + * keep the technical name). Temporary until the desktop branding settles. */ function mapPlatformNameToFullName(platform: ExtendedPlatformName) { if (platform === 'clay') { - return 'Clay'; + return 'Desktop'; } if (platform === 'harmony') { return 'Harmony'; @@ -46,10 +48,21 @@ type PlatformBadgeInnerProps = { type?: BadgeProps['type']; }; +// Maps the semantic `type` to a visual modifier class. The CSS in +// PlatformBadge.css decides what each modifier looks like — default keeps the +// platform color, `--only` emphasizes via a tinted ring, `--no` mutes the +// platform color and strikes the label so support/non-support don't read as +// the same chip in different words. +const TYPE_TO_MODIFIER: Record, string> = { + info: '', + warning: 'platform-badge--only', + danger: 'platform-badge--no', + tip: '', + note: '', +}; + /** * Internal component for rendering a platform badge. - * @param props The properties for the PlatformBadgeInner component. - * @returns A Badge component with platform-specific styling. * @internal */ function PlatformBadgeInner({ @@ -57,17 +70,18 @@ function PlatformBadgeInner({ badgeText, type = 'info', }: PlatformBadgeInnerProps) { + const modifier = TYPE_TO_MODIFIER[type] ?? ''; return ( - {badgeText} + {badgeText} ); @@ -143,7 +157,7 @@ function createNoPlatformComponent(platform: ExtendedPlatformName) { return ( ); From af23da6d6cc19d5a415263dd83a47160b2ab079c Mon Sep 17 00:00:00 2001 From: Huxpro <5563315+Huxpro@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:51:45 -0700 Subject: [PATCH 3/9] fix(badge): keep ClayOnly/NoClay component keys when label says Desktop The previous commit changed mapPlatformNameToFullName('clay') to return 'Desktop' so the badge would read "Desktop", but that same function also drove the dynamic component-name derivation. Result: generatedComponents held 'DesktopOnly'/'NoDesktop' while the destructured exports still asked for 'ClayOnly'/'NoClay', so both came back as undefined and every MDX page that rendered SSG-failed with React #130. Split the responsibility: - mapPlatformNameToTechnicalName -> stable 'Clay'/'Harmony'/... drives the generatedComponents keys, so ClayOnly/NoClay stay valid. - mapPlatformNameToLabel -> what the user sees, returns 'Desktop' for clay. Also drops em dashes from comments in this PR's new code per repo prose preferences. Change-Id: Ib82b76c1511b665405204e76a7475c58dc092dad --- src/components/api-badge/PlatformBadge.css | 22 +++++------ src/components/api-badge/PlatformBadge.tsx | 37 +++++++++++++------ .../platform-navigation/platform-colors.ts | 12 +++--- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/components/api-badge/PlatformBadge.css b/src/components/api-badge/PlatformBadge.css index 930877eca..a1b2e398c 100644 --- a/src/components/api-badge/PlatformBadge.css +++ b/src/components/api-badge/PlatformBadge.css @@ -1,16 +1,16 @@ /* * PlatformBadge styling. Single source of truth for platform color is - * platform-navigation/platform-colors.ts — hex values below mirror that map - * exactly. If you change one, change both. + * platform-navigation/platform-colors.ts, whose hex values are mirrored + * below. If you change one, change both. * * Design intent: * - Icon stays in full platform color so the badge is still scannable. * - Background drops to a tinted 50/950 wash. Less ink, same signal. - * - The semantic variants (default / *Only / No*) read as three distinct + * - The semantic variants default, *Only, No* read as three distinct * things instead of "same chip, different word": - * default — platform color, subtle bg - * .platform-badge--only — adds an inset ring in the platform color - * .platform-badge--no — drops platform color, mutes, strikes the label + * default platform color, subtle bg + * .platform-badge--only adds an inset ring in the platform color + * .platform-badge--no drops platform color, mutes, strikes the label */ /* ── Base: tighten Rspress's container variables to a quiet, tinted wash ── */ @@ -63,7 +63,7 @@ --platform-badge-ring: #a5f3fc; } -/* Dark mode — bump foreground to ~400, swap bg to a deep tinted wash */ +/* Dark mode bumps foreground to ~400 and swaps bg to a deep tinted wash. */ :where(html.rp-dark, html.dark) .platform-badge-ios, :where(html.rp-dark, html.dark) .platform-badge-clay_ios, :where(html.rp-dark, html.dark) .platform-badge-macos, @@ -117,13 +117,13 @@ --rp-container-danger-bg: var(--platform-badge-bg); } -/* ── Variant: *Only — emphasize with an inset platform-tinted ring ──────── */ +/* ── Variant: *Only, emphasized with an inset platform-tinted ring ─────── */ .platform-badge--only .rp-badge { box-shadow: inset 0 0 0 1px var(--platform-badge-ring); } -/* ── Variant: No* — drop the platform color, mute, strike the label ─────── */ +/* ── Variant: No*, drops platform color, mutes, strikes the label ───────── */ .platform-badge--no { /* Override the cascade above with neutral grays so "No iOS" doesn't read @@ -143,8 +143,8 @@ text-decoration-color: currentColor; } -/* The icon also dims in the No* variant — full saturation here would fight - the strikethrough and read as "supported but crossed out". */ +/* The icon also dims in the No* variant, since full saturation here would + fight the strikethrough and read as "supported but crossed out". */ .platform-badge--no .platform-badge__icon { opacity: 0.7; } diff --git a/src/components/api-badge/PlatformBadge.tsx b/src/components/api-badge/PlatformBadge.tsx index 1cea011e9..cb2a967ca 100644 --- a/src/components/api-badge/PlatformBadge.tsx +++ b/src/components/api-badge/PlatformBadge.tsx @@ -24,15 +24,13 @@ function mapPlatformNameToIconName(platform: ExtendedPlatformName) { type ExtendedPlatformName = LCD.PlatformName | 'clay'; /** - * Maps a platform name to its full name. - * - * Note: bare `clay` renders as "Desktop" in user-facing badges while the - * underlying type stays `clay` (component exports, APIStatus, compat tables - * keep the technical name). Temporary until the desktop branding settles. + * Technical, stable platform name. Used to derive the exported component keys + * (`ClayOnly`, `NoHarmony`, etc.) so MDX imports stay valid no matter how the + * user-facing label moves around. */ -function mapPlatformNameToFullName(platform: ExtendedPlatformName) { +function mapPlatformNameToTechnicalName(platform: ExtendedPlatformName) { if (platform === 'clay') { - return 'Desktop'; + return 'Clay'; } if (platform === 'harmony') { return 'Harmony'; @@ -40,6 +38,18 @@ function mapPlatformNameToFullName(platform: ExtendedPlatformName) { return getFullPlatformName(platform); } +/** + * User-facing label rendered inside the badge. Bare `clay` renders as + * "Desktop" while the desktop branding is in flux. APIStatus and compat + * tables keep the technical name; this only affects the badge chip. + */ +function mapPlatformNameToLabel(platform: ExtendedPlatformName) { + if (platform === 'clay') { + return 'Desktop'; + } + return mapPlatformNameToTechnicalName(platform); +} + type BadgeProps = React.ComponentProps; type PlatformBadgeInnerProps = { @@ -49,7 +59,7 @@ type PlatformBadgeInnerProps = { }; // Maps the semantic `type` to a visual modifier class. The CSS in -// PlatformBadge.css decides what each modifier looks like — default keeps the +// PlatformBadge.css decides what each modifier looks like: default keeps the // platform color, `--only` emphasizes via a tinted ring, `--no` mutes the // platform color and strikes the label so support/non-support don't read as // the same chip in different words. @@ -109,7 +119,7 @@ export function PlatformBadge({ version, type = 'info', }: PlatformBadgeProps) { - const platformName = mapPlatformNameToFullName(platform); + const platformName = mapPlatformNameToLabel(platform); const badgeText = version ? `${platformName} ${version}+` : platformName; return ( @@ -140,7 +150,7 @@ function createPlatformOnlyComponent(platform: ExtendedPlatformName) { return ( ); @@ -157,7 +167,7 @@ function createNoPlatformComponent(platform: ExtendedPlatformName) { return ( ); @@ -168,7 +178,10 @@ function createNoPlatformComponent(platform: ExtendedPlatformName) { const generatedComponents: Record = {}; for (const platform of platformNames) { - const name = mapPlatformNameToFullName(platform) + // Component name derivation MUST use the technical name so `ClayOnly` and + // `NoClay` exports stay valid even while the user-facing label says + // "Desktop". Don't switch this to mapPlatformNameToLabel. + const name = mapPlatformNameToTechnicalName(platform) .split(' ') .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join(''); diff --git a/src/components/platform-navigation/platform-colors.ts b/src/components/platform-navigation/platform-colors.ts index b6d092108..0cb00be67 100644 --- a/src/components/platform-navigation/platform-colors.ts +++ b/src/components/platform-navigation/platform-colors.ts @@ -5,12 +5,12 @@ // perceived lightness, which is what lets the icons hum at the same volume. // // Brand mapping: -// apple family (ios, macos) → zinc — Apple system silver/space gray -// android → emerald — Android green -// harmony → rose — Huawei red (brand cue) -// web / web_lynx → orange — Lynx-on-web warmth -// windows → sky — Microsoft blue -// clay umbrella + variants → cyan — Clay/Desktop signature +// apple family ios and macos -> zinc Apple system silver/space gray +// android -> emerald Android green +// harmony -> rose Huawei red, the brand cue +// web and web_lynx -> orange Lynx-on-web warmth +// windows -> sky Microsoft blue +// clay umbrella and variants -> cyan Clay/Desktop signature // // `clay_` reuses the underlying-platform icon glyph, so the color // is the only thing keeping `ClayAndroidOnly` and `AndroidOnly` visually From 366ef571ceaf6af4443a91533a5fef242e6f9e0d Mon Sep 17 00:00:00 2001 From: Huxpro <5563315+Huxpro@users.noreply.github.com> Date: Thu, 4 Jun 2026 16:19:37 -0700 Subject: [PATCH 4/9] chore: re-trigger CI Change-Id: I98a04f9a62cc6e860d74719f5e4f1d0f6bb968ea From 38ab2ec0bfe171cb3eb6f41e158741e45a397e94 Mon Sep 17 00:00:00 2001 From: Huxpro <5563315+Huxpro@users.noreply.github.com> Date: Thu, 4 Jun 2026 16:33:44 -0700 Subject: [PATCH 5/9] fix(badge): vertical-align middle so chip sits on the line center The Rspress Badge is inline-flex, which baseline-aligns its line box to the surrounding text baseline. That looks fine next to body text and code chips, but inside a heading it makes the chip cling to the bottom of the heading line and read as stranded. Setting vertical-align: middle on the chip re-centers it on the line box and fixes alignment in body, TOC, and heading contexts without changing the chip's size. Also moves the icon size from inline Tailwind utilities into the same CSS rule (--icon-size: 0.9rem) so future tweaks live in one place. Change-Id: Ibc9c30567a716e666be65a20e55b9e323d7963d5 --- src/components/api-badge/PlatformBadge.css | 18 ++++++++++++++++++ src/components/api-badge/PlatformBadge.tsx | 5 +---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/components/api-badge/PlatformBadge.css b/src/components/api-badge/PlatformBadge.css index a1b2e398c..516d7d9e6 100644 --- a/src/components/api-badge/PlatformBadge.css +++ b/src/components/api-badge/PlatformBadge.css @@ -117,6 +117,24 @@ --rp-container-danger-bg: var(--platform-badge-bg); } +/* ── Vertical alignment ───────────────────────────────────────────────── + * Same fixed badge size everywhere. The only thing that varies between + * the body, the TOC list, and a heading is what the badge sits next to. + * Default inline-flex baseline alignment makes the chip cling to the + * surrounding text baseline, which looks fine in body but reads as + * "stranded at the bottom" next to a large heading. `vertical-align: + * middle` re-centers the chip on the line box, so the same chip aligns + * cleanly against a code chip in body text, a TOC list item, and a + * heading without changing size. + */ +[class*='platform-badge-'] .rp-badge { + vertical-align: middle; +} + +[class*='platform-badge-'] .platform-badge__icon { + --icon-size: 0.9rem; +} + /* ── Variant: *Only, emphasized with an inset platform-tinted ring ─────── */ .platform-badge--only .rp-badge { diff --git a/src/components/api-badge/PlatformBadge.tsx b/src/components/api-badge/PlatformBadge.tsx index cb2a967ca..8063341e6 100644 --- a/src/components/api-badge/PlatformBadge.tsx +++ b/src/components/api-badge/PlatformBadge.tsx @@ -87,10 +87,7 @@ function PlatformBadgeInner({ style={{ display: 'contents' }} > - + {badgeText} From 7af5676758c9eb3f5dc51fb6eabec9520ffce1d5 Mon Sep 17 00:00:00 2001 From: Huxpro <5563315+Huxpro@users.noreply.github.com> Date: Sat, 6 Jun 2026 21:57:51 -0700 Subject: [PATCH 6/9] fix(icons): tighten Android viewBox and shrink api/status support chips Two adjacent fixes for how platform chips read on the api/status page. 1. Android SVG viewBox cropped from `0 0 21 20` to `1.5 1.5 18 18`. The half-dome glyph only fills the lower half of the original viewBox, so at the same `--icon-size` the rendered Android glyph looked visibly smaller than Apple / Harmony / Web (which fill their viewBoxes). The new square crop centers on the glyph centroid and removes the dead margin so the rendered icon picks up the same visual weight as the other platforms. 2. API-status support chips in `APIStatusDashboard.tsx` shrunk to match the older compact pill. Icon 10px -> 8px, dot 6px -> 4px, padding 4/2px -> 2/1px, gap 2px -> 1px. The chip footprint goes from ~26x14 down to ~16x10, restoring the tight pill feel. Change-Id: I5f45a45f00c314871207eab1ebc98112be3c50af --- src/components/api-status/APIStatusDashboard.tsx | 6 +++--- .../api-table/compat-table/assets/icons/android.svg | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/api-status/APIStatusDashboard.tsx b/src/components/api-status/APIStatusDashboard.tsx index 42aa72a6d..7c59c7f39 100644 --- a/src/components/api-status/APIStatusDashboard.tsx +++ b/src/components/api-status/APIStatusDashboard.tsx @@ -345,17 +345,17 @@ export const APIItem: React.FC = ({
- {Icon && } + {Icon && } + From d251a1534508cbc59af4cdc8de7b9d6778467589 Mon Sep 17 00:00:00 2001 From: Huxpro <5563315+Huxpro@users.noreply.github.com> Date: Sat, 6 Jun 2026 22:15:58 -0700 Subject: [PATCH 7/9] fix(api-status): size support-chip icon via --icon-size and force inline-block on dot Tailwind `w-2 h-2` lost to `.icon { width: var(--size) }` in CSS source order, so the chip icons rendered at 1rem (16px) instead of the intended 8px. Pass `--icon-size: 0.5rem` on the chip wrapper so the .icon rule picks up the right size, and switch the status dot from `` (inline, ignores width/height) to an inline-block element so the 4px circle actually renders. Change-Id: I50f994b4a40449a20c80cf10f62d3e9c93fad799 --- src/components/api-status/APIStatusDashboard.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/api-status/APIStatusDashboard.tsx b/src/components/api-status/APIStatusDashboard.tsx index 7c59c7f39..a5a8b30d6 100644 --- a/src/components/api-status/APIStatusDashboard.tsx +++ b/src/components/api-status/APIStatusDashboard.tsx @@ -345,17 +345,17 @@ export const APIItem: React.FC = ({
- {Icon && } + {Icon && } Date: Sat, 6 Jun 2026 22:22:26 -0700 Subject: [PATCH 8/9] fix(api-status): restore breathing room on support-chip layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous shrink went too tight: icon (8px) and dot (4px) sat right next to each other with 1px gap and 2px padding, so the chip read as a single cramped square instead of an "icon + status" pill. Back off slightly to match the reference proportions: --icon-size: 0.625rem (10px) dot 6px gap 4px padding 4px / 2px Chip footprint becomes roughly 22 x 14 — small enough on mobile to fit a multi-platform row, comfortable enough on desktop that the icon and the status dot don't read as one blob. Change-Id: I2303122243c05c347974668186381e84abddf2bb --- src/components/api-status/APIStatusDashboard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/api-status/APIStatusDashboard.tsx b/src/components/api-status/APIStatusDashboard.tsx index a5a8b30d6..2fb58b659 100644 --- a/src/components/api-status/APIStatusDashboard.tsx +++ b/src/components/api-status/APIStatusDashboard.tsx @@ -345,7 +345,7 @@ export const APIItem: React.FC = ({
= ({ {Icon && } Date: Sat, 6 Jun 2026 22:33:50 -0700 Subject: [PATCH 9/9] fix(api-status): force support-chip icon to 10px via inline style The previous attempt set --icon-size on the chip wrapper hoping it would cascade into the .icon child, but .icon's `width: var(--size)` was still winning at the rendered size (~16px) on desktop, so the chips read as huge despite the smaller Tailwind paddings. Add a `style` pass-through on PlatformSvg + the api-status icon factory, and set the chip icon to { width: 10, height: 10 } directly. Inline style sits above any cascade contest so the icon actually renders at 10px now. Change-Id: I1a2a182b24f183ed3d3e1ce2e981133166f41a5a --- src/components/api-status/APIStatusDashboard.tsx | 4 ++-- src/components/api-status/constants.tsx | 9 ++++++--- src/components/platform-navigation/PlatformIcon.tsx | 3 +++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/api-status/APIStatusDashboard.tsx b/src/components/api-status/APIStatusDashboard.tsx index 2fb58b659..0e9524346 100644 --- a/src/components/api-status/APIStatusDashboard.tsx +++ b/src/components/api-status/APIStatusDashboard.tsx @@ -345,14 +345,14 @@ export const APIItem: React.FC = ({
- {Icon && } + {Icon && } ; + icon: React.FC<{ className?: string; style?: React.CSSProperties }>; colors: { bg: string; border: string; @@ -14,11 +14,14 @@ export interface PlatformConfig { }; } -const makeIcon = (platformName: string): React.FC<{ className?: string }> => { - return ({ className }) => ( +const makeIcon = ( + platformName: string, +): React.FC<{ className?: string; style?: React.CSSProperties }> => { + return ({ className, style }) => ( ); }; diff --git a/src/components/platform-navigation/PlatformIcon.tsx b/src/components/platform-navigation/PlatformIcon.tsx index 2ee4bf6c5..d677fde7f 100644 --- a/src/components/platform-navigation/PlatformIcon.tsx +++ b/src/components/platform-navigation/PlatformIcon.tsx @@ -49,10 +49,12 @@ export const PlatformSvg = ({ platformName, className, key, + style, }: { platformName: PlatformName | string; className?: string; key?: string; + style?: React.CSSProperties; }) => { const svgUrl = toIconUrl(platformName); return ( @@ -62,6 +64,7 @@ export const PlatformSvg = ({ style={{ maskImage: `url(${svgUrl})`, WebkitMaskImage: `url(${svgUrl})`, + ...style, }} /> );