From 0709d6abc3ec464a4145f684bdfdcba0141a3ddf Mon Sep 17 00:00:00 2001 From: bitfathers94 <237535319+bitfathers94@users.noreply.github.com> Date: Sat, 25 Jul 2026 23:22:32 +0000 Subject: [PATCH] fix(ui-kit): ratchet-clean src/components (16/19 files, 38/43 violations) Converts each no-restricted-syntax violation to its named token per the eslint message: text-[9-13px] one-offs onto mg-type-micro/label/caption/ data/data-sm (dropping the now-redundant font-mono/uppercase/tracking utilities where the token already supplies them), off-scale px-5/pb-14/ mb-5 spacing snapped to the nearest --mg-space-*-backed step, the ActionBar/SegmentedToggle/PrimaryLinksRail hand-rolled shells wrapped in (the same recipe #8083 already proved for connected icon-bar shells), and PrimaryLinksRail's icon segments moved onto (a new opt-in prop that skips the glyph/underline for icon-only composition -- everything else keeps ExternalLink's default rendering). RATCHETED_DIRS gains "src/components/**/*.{ts,tsx}" with a 3-file `ignores`: entity-hero.tsx and page-hero.tsx each still carry a hero

/KPI-value size (text-[2.5rem]/[1.75rem]) with no mg-type-* or Tailwind-native equivalent past caption-lg (13px) -- no display/heading tier is authored yet, so forcing these onto mg-type-caption would shrink the page hero. section-anchor.tsx's scroll-mt-32 is the same sticky-header scroll-offset compensation #7810 already left unconverted elsewhere in the codebase, not a spacing-scale value. Ratcheting around these 3 (rather than leaving all of src/components/** un-ratcheted over them) still fails CI on any new drift in the other 16 files -- confirmed by introducing then reverting a throwaway violation in accent-band.tsx (errors, not warnings) before/after this change. npx eslint src/components: 43 warnings -> 5 (0 errors either way). npx tsc --noEmit / prettier --check / vitest run (98 tests): all clean. dist rebuilt via npm run build (committed per this package's own .gitignore exception for the runtime bundle). Closes #8172 --- packages/ui-kit/dist/index.cjs | 412 +++++++++--------- packages/ui-kit/dist/index.js | 412 +++++++++--------- packages/ui-kit/eslint.config.ts | 36 +- .../components/metagraphed/accent-band.tsx | 2 +- .../src/components/metagraphed/action-bar.tsx | 14 +- .../metagraphed/charts/spark-legend.tsx | 2 +- .../metagraphed/charts/stat-with-spark.tsx | 14 +- .../metagraphed/charts/treemap-mini.tsx | 2 +- .../src/components/metagraphed/chips.tsx | 10 +- .../metagraphed/download-csv-button.tsx | 4 +- .../metagraphed/eligibility-chip.tsx | 11 +- .../components/metagraphed/entity-hero.tsx | 8 +- .../components/metagraphed/external-link.tsx | 39 ++ .../components/metagraphed/hover-preview.tsx | 2 +- .../components/metagraphed/info-tooltip.tsx | 5 +- .../src/components/metagraphed/list-shell.tsx | 6 +- .../metagraphed/methodology-callout.tsx | 2 +- .../src/components/metagraphed/page-hero.tsx | 6 +- .../components/metagraphed/page-section.tsx | 4 +- .../metagraphed/primary-links-rail.tsx | 23 +- .../components/metagraphed/section-anchor.tsx | 2 +- .../components/metagraphed/share-button.tsx | 4 +- .../src/components/ui/segmented-toggle.tsx | 15 +- 23 files changed, 557 insertions(+), 478 deletions(-) diff --git a/packages/ui-kit/dist/index.cjs b/packages/ui-kit/dist/index.cjs index 6bdab944f7..095ff5f17e 100644 --- a/packages/ui-kit/dist/index.cjs +++ b/packages/ui-kit/dist/index.cjs @@ -460,6 +460,115 @@ var SheetDescription = React3__namespace.forwardRef(({ className, ...props }, re } )); SheetDescription.displayName = DialogPrimitive__namespace.Description.displayName; +var TONE_CLASSES = { + default: "text-ink-muted", + muted: "text-ink-subtle-text", + accent: "text-accent-text", + warn: "text-health-warn-text", + down: "text-health-down" +}; +function SectionLabel({ + children, + size = "micro", + tone = "default", + icon, + hint, + as, + className, + title +}) { + const Cmp = as ?? "span"; + return /* @__PURE__ */ jsxRuntime.jsxs( + Cmp, + { + title, + className: classNames( + size === "micro" ? "mg-type-micro" : "mg-type-label", + "inline-flex items-center gap-1.5", + TONE_CLASSES[tone], + className + ), + children: [ + icon ? /* @__PURE__ */ jsxRuntime.jsx( + "span", + { + "aria-hidden": true, + className: "inline-flex size-3 items-center justify-center", + children: icon + } + ) : null, + /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children }), + hint != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-subtle-text normal-case tracking-normal", children: hint }) : null + ] + } + ); +} +var TONE_STYLES = { + default: { border: "border-border", bg: "bg-card" }, + accent: { border: "border-accent/40", bg: "bg-primary-soft" }, + warn: { border: "border-health-warn/40", bg: "bg-health-warn/5" }, + down: { border: "border-health-down/40", bg: "bg-health-down/5" }, + ok: { border: "border-health-ok/40", bg: "bg-health-ok/5" }, + muted: { border: "border-border", bg: "bg-surface-2" } +}; +function Panel({ + title, + action, + caption, + dense, + flush, + interactive, + tone = "default", + tintBorderOnly, + glow, + as, + className, + bodyClassName, + children, + ...rest +}) { + const Cmp = as ?? "section"; + const hasHeader = title != null || action != null || caption != null; + const padClass = flush ? "mg-panel-pad-flush" : dense ? "mg-panel-pad-dense" : "mg-panel-pad"; + const toneStyle = TONE_STYLES[tone]; + return /* @__PURE__ */ jsxRuntime.jsxs( + Cmp, + { + ...rest, + className: classNames( + "rounded border", + toneStyle.border, + tintBorderOnly ? "bg-card" : toneStyle.bg, + interactive ? "mg-hover-lift" : null, + glow ? tone === "accent" ? "mg-card-glow-accent" : "mg-card-glow" : null, + className + ), + children: [ + hasHeader ? /* @__PURE__ */ jsxRuntime.jsxs( + "header", + { + className: classNames( + "flex items-start justify-between gap-3 border-b border-border/70", + dense ? "mg-panel-pad-dense" : "mg-panel-pad" + ), + style: { + paddingTop: "var(--mg-space-sm)", + paddingBottom: "var(--mg-space-sm)" + }, + children: [ + /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [ + title != null ? /* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: title }) : null, + caption != null ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 mg-type-caption-lg text-ink-muted", children: caption }) : null + ] }), + action != null ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 flex items-center gap-2", children: action }) : null + ] + } + ) : null, + /* @__PURE__ */ jsxRuntime.jsx("div", { className: classNames(padClass, bodyClassName), children }) + ] + } + ); +} function SegmentedToggle({ options, value, @@ -468,14 +577,14 @@ function SegmentedToggle({ className }) { return /* @__PURE__ */ jsxRuntime.jsx( - "div", + Panel, { + as: "div", + flush: true, role: "tablist", "aria-label": ariaLabel, - className: classNames( - "inline-flex items-center rounded-md border border-border bg-card p-0.5", - className - ), + className, + bodyClassName: "inline-flex items-center p-0.5", children: options.map( ({ value: v, label, Icon, ariaLabel: optionAriaLabel, title }) => { const active = v === value; @@ -489,7 +598,7 @@ function SegmentedToggle({ title: title ?? label, onClick: () => onChange(v), className: classNames( - "inline-flex items-center gap-1.5 rounded px-2 py-1 text-[11px] font-medium transition-colors min-h-8", + "inline-flex items-center gap-1.5 rounded px-2 py-1 mg-type-caption font-medium transition-colors min-h-8", active ? "bg-surface text-ink-strong" : "text-ink-muted hover:text-ink-strong" ), children: [ @@ -568,7 +677,7 @@ function AccentBand({ "div", { className: classNames( - "relative max-w-shell-max mx-auto px-4 md:px-8 py-14 md:py-20", + "relative max-w-shell-max mx-auto px-4 md:px-8 py-12 md:py-20", innerClassName ), children @@ -1234,7 +1343,7 @@ function HealthDot({ if (variant === "dot") return dot; return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [ dot, - /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-medium text-ink", children: label }) + /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mg-type-caption font-medium text-ink", children: label }) ] }); } function HealthPill({ @@ -1244,7 +1353,7 @@ function HealthPill({ if (label) { return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [ /* @__PURE__ */ jsxRuntime.jsx(HealthDot, { state }), - /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-medium text-ink", children: label }) + /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mg-type-caption font-medium text-ink", children: label }) ] }); } return /* @__PURE__ */ jsxRuntime.jsx(HealthDot, { state, variant: "label" }); @@ -1287,7 +1396,7 @@ function CurationChip({ level }) { "span", { className: classNames( - "inline-flex items-center rounded border px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wider", + "inline-flex items-center rounded border px-1.5 py-0.5 mg-type-caption font-medium uppercase tracking-wider", cls ), children: label @@ -1309,7 +1418,7 @@ function ReviewChip({ state }) { "span", { className: classNames( - "inline-flex items-center rounded border px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wider", + "inline-flex items-center rounded border px-1.5 py-0.5 mg-type-caption font-medium uppercase tracking-wider", reviewCls[key] ), title: `Maintainer review: ${key}`, @@ -1318,7 +1427,7 @@ function ReviewChip({ state }) { ); } function CandidateChip() { - return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center rounded border border-dashed border-ink-subtle bg-transparent px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wider text-ink-muted", children: "Unverified" }); + return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center rounded border border-dashed border-ink-subtle bg-transparent px-1.5 py-0.5 mg-type-caption font-medium uppercase tracking-wider text-ink-muted", children: "Unverified" }); } function truncateCopyPreview(value, max = 64) { return value.length > max ? value.slice(0, max) + "\u2026" : value; @@ -1584,11 +1693,11 @@ function DownloadCsvButton({ "aria-label": label, title: label, className: classNames( - bare ? "inline-flex items-center gap-1.5 rounded px-2 py-1 min-h-8 text-[11px] font-medium text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : ( + bare ? "inline-flex items-center gap-1.5 rounded px-2 py-1 min-h-8 mg-type-caption font-medium text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : ( // rounded-full matches the pill idiom shared by SectionBadge/FilterChip/ // other compact header controls it commonly sits next to — a plain // `rounded` rectangle reads as a mismatched shape beside a pill. - "inline-flex items-center gap-1.5 rounded-full border border-border bg-card p-1.5 text-[11px] font-medium text-ink hover:border-ink/30 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring sm:px-2.5 sm:py-1" + "inline-flex items-center gap-1.5 rounded-full border border-border bg-card p-1.5 mg-type-caption font-medium text-ink hover:border-ink/30 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring sm:px-2.5 sm:py-1" ), className ), @@ -1627,26 +1736,19 @@ function EligibilityChip({ { tabIndex: 0, className: classNames( - "inline-flex items-center gap-1.5 rounded-full border bg-transparent font-mono uppercase tracking-wider whitespace-nowrap cursor-help transition-colors", + "inline-flex items-center gap-1.5 rounded-full border bg-transparent whitespace-nowrap cursor-help transition-colors", "before:content-[''] before:size-1.5 before:rounded-full", "hover:bg-surface/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", - size === "xs" ? "px-2 py-0 text-[9px] h-5" : "px-2.5 py-0 text-[10px] h-6", + size === "xs" ? "px-2 py-0 h-5 mg-type-micro" : "px-2.5 py-0 h-6 mg-type-label", TONE[eligibility] ), children: ELIGIBILITY_LABEL[eligibility] } ) }), - /* @__PURE__ */ jsxRuntime.jsxs( - TooltipContent, - { - side: "top", - className: "max-w-[240px] text-[11px] leading-relaxed", - children: [ - /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mg-type-micro opacity-70 mb-1", children: ELIGIBILITY_LABEL[eligibility] }), - RULE[eligibility] - ] - } - ) + /* @__PURE__ */ jsxRuntime.jsxs(TooltipContent, { side: "top", className: "max-w-[240px] mg-type-caption", children: [ + /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mg-type-micro opacity-70 mb-1", children: ELIGIBILITY_LABEL[eligibility] }), + RULE[eligibility] + ] }) ] }) }); } var SAFE_EXTERNAL_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]); @@ -1690,9 +1792,36 @@ function ExternalLink({ children, authRequired, publicSafe = true, - className + className, + bare, + title, + ariaLabel }) { const safeHref = safeExternalUrl(href); + if (bare) { + if (!safeHref) { + return /* @__PURE__ */ jsxRuntime.jsx( + "span", + { + className, + title: title ?? "Blocked unsafe external URL", + children + } + ); + } + return /* @__PURE__ */ jsxRuntime.jsx( + "a", + { + href: safeHref, + target: "_blank", + rel: "noopener noreferrer", + title, + "aria-label": ariaLabel, + className, + children + } + ); + } const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children }), safeHref ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "size-3 shrink-0 text-ink-muted" }) : null, @@ -1752,14 +1881,7 @@ function InfoTooltip({ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { className: "size-3.5" }) } ) }), - /* @__PURE__ */ jsxRuntime.jsx( - TooltipContent, - { - side: "top", - className: "max-w-xs text-[11px] leading-relaxed", - children: label - } - ) + /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", className: "max-w-xs mg-type-caption", children: label }) ] }) }); } function FreshnessIndicator({ @@ -1840,7 +1962,7 @@ function HoverPreview({ "span", { role: "tooltip", - className: "absolute left-0 top-full z-[var(--mg-z-overlay)] mt-1.5 w-72 max-w-[80vw] rounded border border-border bg-card p-3 shadow-lg text-[11px] text-ink leading-relaxed", + className: "absolute left-0 top-full z-[var(--mg-z-overlay)] mt-1.5 w-72 max-w-[80vw] rounded border border-border bg-card p-3 shadow-lg mg-type-caption text-ink", children: content } ) : null @@ -2005,7 +2127,7 @@ function LoadMore({ ); } if (error) { - return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-health-down/30 bg-health-down/5 px-4 py-2 text-[11px]", children: [ + return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-health-down/30 bg-health-down/5 px-4 py-2 mg-type-caption", children: [ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 text-health-down", children: [ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "size-3" }), "Couldn\u2019t load more \u2014 ", @@ -2027,7 +2149,7 @@ function LoadMore({ ] }); } if (cursorInvalid) { - return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-health-warn/30 bg-health-warn/5 px-4 py-2 text-[11px] text-health-warn", children: [ + return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-health-warn/30 bg-health-warn/5 px-4 py-2 mg-type-caption text-health-warn", children: [ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "size-3" }), "Pagination stopped \u2014 the server returned an invalid next cursor." @@ -2048,7 +2170,7 @@ function LoadMore({ { type: "button", onClick: onLoadMore, - className: "inline-flex items-center rounded border border-border bg-card px-3 py-1.5 text-[11px] font-medium hover:border-ink/30 min-h-9", + className: "inline-flex items-center rounded border border-border bg-card px-3 py-1.5 mg-type-caption font-medium hover:border-ink/30 min-h-9", children: "Load more" } ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-60", children: "end of list" }) @@ -2069,7 +2191,7 @@ function PageHero({ "section", { className: classNames( - "mg-hero-slab relative mb-12 md:mb-16 pt-12 md:pt-20 pb-10 md:pb-14", + "mg-hero-slab relative mb-12 md:mb-16 pt-12 md:pt-20 pb-10 md:pb-12", className ), children: [ @@ -2080,8 +2202,8 @@ function PageHero({ live ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mg-live-dot" }) : null, eyebrow ] }) : null, - /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "mg-fade-in mg-fade-in-delay-1 mt-4 font-display text-[2.5rem] sm:text-5xl md:text-[3.75rem] font-semibold leading-[1.02] tracking-[-0.025em] text-ink-strong", children: title }), - description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mg-fade-in mg-fade-in-delay-2 mt-5 max-w-xl text-base md:text-lg text-ink-muted leading-relaxed", children: description }) : null, + /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "mg-fade-in mg-fade-in-delay-1 mt-4 font-display text-[2.5rem] sm:text-5xl md:text-6xl font-semibold leading-[1.02] tracking-[-0.025em] text-ink-strong", children: title }), + description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mg-fade-in mg-fade-in-delay-2 mt-4 max-w-xl text-base md:text-lg text-ink-muted leading-relaxed", children: description }) : null, actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mg-fade-in mg-fade-in-delay-3 mt-6 flex flex-wrap items-center gap-2", children: actions }) : null ] }), aside ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mg-fade-in mg-fade-in-delay-2 hidden md:block shrink-0", children: aside }) : null @@ -2124,12 +2246,12 @@ function EntityHero({ { className: classNames( "mg-hero-slab relative", - display ? "mb-12 md:mb-16 pt-12 md:pt-20 pb-10 md:pb-14" : "pt-8 md:pt-12 pb-8 md:pb-10 mb-6", + display ? "mb-12 md:mb-16 pt-12 md:pt-20 pb-10 md:pb-12" : "pt-8 md:pt-12 pb-8 md:pb-10 mb-6", className ), children: [ caption ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0 top-4 hidden md:block", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mg-hero-caption", children: caption }) }) : null, - banner ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-5", children: banner }) : null, + banner ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4", children: banner }) : null, /* @__PURE__ */ jsxRuntime.jsxs( "div", { @@ -2160,7 +2282,7 @@ function EntityHero({ { className: classNames( "mg-fade-in mg-fade-in-delay-1 font-display font-semibold text-ink-strong", - display ? "mt-4 text-[2.5rem] sm:text-5xl md:text-[3.75rem] leading-[1.02] tracking-[-0.025em]" : "text-3xl md:text-4xl tracking-[-0.01em]" + display ? "mt-4 text-[2.5rem] sm:text-5xl md:text-6xl leading-[1.02] tracking-[-0.025em]" : "text-3xl md:text-4xl tracking-[-0.01em]" ), children: title } @@ -2172,7 +2294,7 @@ function EntityHero({ { className: classNames( "mg-fade-in mg-fade-in-delay-2 text-ink-muted leading-relaxed", - display ? "mt-5 max-w-xl text-base md:text-lg" : "mt-3 max-w-3xl text-sm md:text-base" + display ? "mt-4 max-w-xl text-base md:text-lg" : "mt-3 max-w-3xl text-sm md:text-base" ), children: description } @@ -2236,7 +2358,7 @@ function PageSection({ "data-section-anchor": id ? "" : void 0, className: classNames( "mg-section", - tone === "muted" && "rounded-xl bg-surface-2/40 px-5 md:px-8 py-8 md:py-10", + tone === "muted" && "rounded-xl bg-surface-2/40 px-4 md:px-8 py-8 md:py-10", className ), children: [ @@ -2251,7 +2373,7 @@ function PageSection({ children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [ eyebrow ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mg-type-micro text-ink-muted inline-flex items-center gap-2", children: eyebrow }) : null, - title ? /* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "group/anchor mt-2 flex items-baseline gap-2 font-display text-2xl md:text-[1.875rem] font-semibold tracking-[-0.02em] text-ink-strong", children: [ + title ? /* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "group/anchor mt-2 flex items-baseline gap-2 font-display text-2xl md:text-3xl font-semibold tracking-[-0.02em] text-ink-strong", children: [ /* @__PURE__ */ jsxRuntime.jsx("span", { children: title }), id ? /* @__PURE__ */ jsxRuntime.jsx( "a", @@ -2366,7 +2488,7 @@ function SectionAnchor({ } ) ] }), - subtitle ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-[11px] text-ink-muted", children: subtitle }) : null + subtitle ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 mg-type-caption text-ink-muted", children: subtitle }) : null ] }), right ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: right }) : null ] }), @@ -2442,7 +2564,7 @@ function ShareButton({ "aria-label": "Copy link with current filters, sort, and page", title: "Copy link with current filters, sort, and page", className: classNames( - connected ? "inline-flex size-8 items-center justify-center text-ink-muted hover:bg-surface hover:text-ink-strong transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : bare ? iconOnly ? "inline-flex items-center justify-center rounded p-1 min-h-8 text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : "inline-flex items-center gap-1.5 rounded px-2 py-1 min-h-8 text-[11px] font-medium text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : iconOnly ? "inline-flex size-8 items-center justify-center rounded-md border border-border bg-card text-ink-muted hover:border-ink/30 hover:text-ink-strong transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : "inline-flex items-center gap-1.5 rounded border border-border bg-card px-2.5 py-1 text-[11px] font-medium text-ink hover:border-ink/30 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring", + connected ? "inline-flex size-8 items-center justify-center text-ink-muted hover:bg-surface hover:text-ink-strong transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : bare ? iconOnly ? "inline-flex items-center justify-center rounded p-1 min-h-8 text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : "inline-flex items-center gap-1.5 rounded px-2 py-1 min-h-8 mg-type-caption font-medium text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : iconOnly ? "inline-flex size-8 items-center justify-center rounded-md border border-border bg-card text-ink-muted hover:border-ink/30 hover:text-ink-strong transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : "inline-flex items-center gap-1.5 rounded border border-border bg-card px-2.5 py-1 mg-type-caption font-medium text-ink hover:border-ink/30 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring", className ), children: [ @@ -2469,12 +2591,12 @@ function ActionBar({ className }) { return /* @__PURE__ */ jsxRuntime.jsx( - "div", + Panel, { - className: classNames( - "inline-flex items-center gap-0.5 rounded-md border border-border bg-card p-0.5", - className - ), + as: "div", + flush: true, + className, + bodyClassName: "inline-flex items-center gap-0.5 p-0.5", children } ); @@ -2934,13 +3056,12 @@ function PrimaryLinksRail({ const Icon = it.icon; const href = safeExternalUrl(it.href); return /* @__PURE__ */ jsxRuntime.jsx( - "a", + ExternalLink, { href, - target: "_blank", - rel: "noopener noreferrer", + bare: true, title: it.label, - "aria-label": it.label, + ariaLabel: it.label, className: "inline-flex size-8 items-center justify-center text-ink-muted hover:bg-surface hover:text-ink-strong transition-colors", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-4" }) }, @@ -2948,7 +3069,15 @@ function PrimaryLinksRail({ ); }); if (bare) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: segments }); - return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "inline-flex items-center rounded-md border border-border bg-card divide-x divide-border overflow-hidden", children: segments }); + return /* @__PURE__ */ jsxRuntime.jsx( + Panel, + { + as: "div", + flush: true, + bodyClassName: "inline-flex items-center divide-x divide-border overflow-hidden", + children: segments + } + ); } function MethodologyCallout({ generatedAt, @@ -2996,7 +3125,7 @@ function MethodologyCallout({ ] } ), - open ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-3 border-t border-border px-3 py-3 text-[11.5px] leading-relaxed text-ink-muted md:grid-cols-2", children: [ + open ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-3 border-t border-border px-3 py-3 mg-type-caption text-ink-muted md:grid-cols-2", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mg-type-micro text-ink-strong", children: "Sparklines" }), /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1", children: "Uptime & latency sparklines plot the active health window (7d default, switchable to 30d). Each point is the mean across every tracked endpoint in that bucket \u2014 gaps mean no probe landed in the window, not zero." }) @@ -3421,7 +3550,7 @@ function SparkLegend({ sideOffset: 6, collisionPadding: 8, avoidCollisions: true, - className: "max-w-xs text-[11px] leading-relaxed", + className: "max-w-xs mg-type-caption", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mg-type-micro mb-1", children: [ metric, @@ -3608,115 +3737,6 @@ function Sparkline({ } ); } -var TONE_CLASSES = { - default: "text-ink-muted", - muted: "text-ink-subtle-text", - accent: "text-accent-text", - warn: "text-health-warn-text", - down: "text-health-down" -}; -function SectionLabel({ - children, - size = "micro", - tone = "default", - icon, - hint, - as, - className, - title -}) { - const Cmp = as ?? "span"; - return /* @__PURE__ */ jsxRuntime.jsxs( - Cmp, - { - title, - className: classNames( - size === "micro" ? "mg-type-micro" : "mg-type-label", - "inline-flex items-center gap-1.5", - TONE_CLASSES[tone], - className - ), - children: [ - icon ? /* @__PURE__ */ jsxRuntime.jsx( - "span", - { - "aria-hidden": true, - className: "inline-flex size-3 items-center justify-center", - children: icon - } - ) : null, - /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children }), - hint != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-subtle-text normal-case tracking-normal", children: hint }) : null - ] - } - ); -} -var TONE_STYLES = { - default: { border: "border-border", bg: "bg-card" }, - accent: { border: "border-accent/40", bg: "bg-primary-soft" }, - warn: { border: "border-health-warn/40", bg: "bg-health-warn/5" }, - down: { border: "border-health-down/40", bg: "bg-health-down/5" }, - ok: { border: "border-health-ok/40", bg: "bg-health-ok/5" }, - muted: { border: "border-border", bg: "bg-surface-2" } -}; -function Panel({ - title, - action, - caption, - dense, - flush, - interactive, - tone = "default", - tintBorderOnly, - glow, - as, - className, - bodyClassName, - children, - ...rest -}) { - const Cmp = as ?? "section"; - const hasHeader = title != null || action != null || caption != null; - const padClass = flush ? "mg-panel-pad-flush" : dense ? "mg-panel-pad-dense" : "mg-panel-pad"; - const toneStyle = TONE_STYLES[tone]; - return /* @__PURE__ */ jsxRuntime.jsxs( - Cmp, - { - ...rest, - className: classNames( - "rounded border", - toneStyle.border, - tintBorderOnly ? "bg-card" : toneStyle.bg, - interactive ? "mg-hover-lift" : null, - glow ? tone === "accent" ? "mg-card-glow-accent" : "mg-card-glow" : null, - className - ), - children: [ - hasHeader ? /* @__PURE__ */ jsxRuntime.jsxs( - "header", - { - className: classNames( - "flex items-start justify-between gap-3 border-b border-border/70", - dense ? "mg-panel-pad-dense" : "mg-panel-pad" - ), - style: { - paddingTop: "var(--mg-space-sm)", - paddingBottom: "var(--mg-space-sm)" - }, - children: [ - /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [ - title != null ? /* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: title }) : null, - caption != null ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 mg-type-caption-lg text-ink-muted", children: caption }) : null - ] }), - action != null ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 flex items-center gap-2", children: action }) : null - ] - } - ) : null, - /* @__PURE__ */ jsxRuntime.jsx("div", { className: classNames(padClass, bodyClassName), children }) - ] - } - ); -} function StatTile({ icon: Icon, eyebrow, @@ -3827,26 +3847,19 @@ function StatWithSpark({ delta ] }), viz ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 min-h-[18px]", children: viz }) : null, - hint ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-mono text-[9.5px] text-ink-muted/80 truncate", children: hint }) : null, - freshLine ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-mono text-[9px] tracking-wide text-ink-muted/70 truncate", children: freshLine }) : null + hint ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mg-type-data-sm text-ink-muted/80 truncate", children: hint }) : null, + freshLine ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mg-type-data-sm tracking-wide text-ink-muted/70 truncate", children: freshLine }) : null ] } ) }), - /* @__PURE__ */ jsxRuntime.jsxs( - TooltipContent, - { - side: "bottom", - className: "max-w-xs text-[11px] leading-relaxed", - children: [ - /* @__PURE__ */ jsxRuntime.jsx("div", { children: full ?? hint ?? label }), - freshAbs || windowLabel ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 mg-type-data-sm text-primary-foreground/70", children: [ - freshAbs ? `Last checked ${freshAbs}` : null, - freshAbs && windowLabel ? " \xB7 " : "", - windowLabel ? `${windowLabel} window` : null - ] }) : null - ] - } - ) + /* @__PURE__ */ jsxRuntime.jsxs(TooltipContent, { side: "bottom", className: "max-w-xs mg-type-caption", children: [ + /* @__PURE__ */ jsxRuntime.jsx("div", { children: full ?? hint ?? label }), + freshAbs || windowLabel ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 mg-type-data-sm text-primary-foreground/70", children: [ + freshAbs ? `Last checked ${freshAbs}` : null, + freshAbs && windowLabel ? " \xB7 " : "", + windowLabel ? `${windowLabel} window` : null + ] }) : null + ] }) ] }) }) ); } @@ -3999,19 +4012,12 @@ function NoDataSpark({ ] } ) }), - /* @__PURE__ */ jsxRuntime.jsxs( - TooltipContent, - { - side: "top", - className: "max-w-xs text-[11px] leading-relaxed", - children: [ - reason, - ".", - " ", - freshAbs ? `Last checked ${freshAbs}${windowLabel ? ` \xB7 ${windowLabel} window` : ""}.` : "No probe samples recorded yet." - ] - } - ) + /* @__PURE__ */ jsxRuntime.jsxs(TooltipContent, { side: "top", className: "max-w-xs mg-type-caption", children: [ + reason, + ".", + " ", + freshAbs ? `Last checked ${freshAbs}${windowLabel ? ` \xB7 ${windowLabel} window` : ""}.` : "No probe samples recorded yet." + ] }) ] }) }) ); } @@ -4114,7 +4120,7 @@ function TreemapMini({ style: { background: t.color ?? "var(--accent)" }, children: t.w > MIN_TILE_W_FOR_LABEL && t.h > MIN_TILE_H_FOR_LABEL ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate mg-type-data-sm font-medium leading-none text-accent-foreground", children: t.label }), - t.w > MIN_TILE_W_FOR_VALUE && t.h > MIN_TILE_H_FOR_VALUE ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-mono text-[9px] leading-none text-accent-foreground/80", children: formatValue(t.value) }) : null + t.w > MIN_TILE_W_FOR_VALUE && t.h > MIN_TILE_H_FOR_VALUE ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate mg-type-data-sm leading-none text-accent-foreground/80", children: formatValue(t.value) }) : null ] }) : null } ) diff --git a/packages/ui-kit/dist/index.js b/packages/ui-kit/dist/index.js index c0b7cde474..d3b36b5d5b 100644 --- a/packages/ui-kit/dist/index.js +++ b/packages/ui-kit/dist/index.js @@ -431,6 +431,115 @@ var SheetDescription = React3.forwardRef(({ className, ...props }, ref) => /* @_ } )); SheetDescription.displayName = DialogPrimitive.Description.displayName; +var TONE_CLASSES = { + default: "text-ink-muted", + muted: "text-ink-subtle-text", + accent: "text-accent-text", + warn: "text-health-warn-text", + down: "text-health-down" +}; +function SectionLabel({ + children, + size = "micro", + tone = "default", + icon, + hint, + as, + className, + title +}) { + const Cmp = as ?? "span"; + return /* @__PURE__ */ jsxs( + Cmp, + { + title, + className: classNames( + size === "micro" ? "mg-type-micro" : "mg-type-label", + "inline-flex items-center gap-1.5", + TONE_CLASSES[tone], + className + ), + children: [ + icon ? /* @__PURE__ */ jsx( + "span", + { + "aria-hidden": true, + className: "inline-flex size-3 items-center justify-center", + children: icon + } + ) : null, + /* @__PURE__ */ jsx("span", { className: "truncate", children }), + hint != null ? /* @__PURE__ */ jsx("span", { className: "text-ink-subtle-text normal-case tracking-normal", children: hint }) : null + ] + } + ); +} +var TONE_STYLES = { + default: { border: "border-border", bg: "bg-card" }, + accent: { border: "border-accent/40", bg: "bg-primary-soft" }, + warn: { border: "border-health-warn/40", bg: "bg-health-warn/5" }, + down: { border: "border-health-down/40", bg: "bg-health-down/5" }, + ok: { border: "border-health-ok/40", bg: "bg-health-ok/5" }, + muted: { border: "border-border", bg: "bg-surface-2" } +}; +function Panel({ + title, + action, + caption, + dense, + flush, + interactive, + tone = "default", + tintBorderOnly, + glow, + as, + className, + bodyClassName, + children, + ...rest +}) { + const Cmp = as ?? "section"; + const hasHeader = title != null || action != null || caption != null; + const padClass = flush ? "mg-panel-pad-flush" : dense ? "mg-panel-pad-dense" : "mg-panel-pad"; + const toneStyle = TONE_STYLES[tone]; + return /* @__PURE__ */ jsxs( + Cmp, + { + ...rest, + className: classNames( + "rounded border", + toneStyle.border, + tintBorderOnly ? "bg-card" : toneStyle.bg, + interactive ? "mg-hover-lift" : null, + glow ? tone === "accent" ? "mg-card-glow-accent" : "mg-card-glow" : null, + className + ), + children: [ + hasHeader ? /* @__PURE__ */ jsxs( + "header", + { + className: classNames( + "flex items-start justify-between gap-3 border-b border-border/70", + dense ? "mg-panel-pad-dense" : "mg-panel-pad" + ), + style: { + paddingTop: "var(--mg-space-sm)", + paddingBottom: "var(--mg-space-sm)" + }, + children: [ + /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [ + title != null ? /* @__PURE__ */ jsx(SectionLabel, { children: title }) : null, + caption != null ? /* @__PURE__ */ jsx("p", { className: "mt-1 mg-type-caption-lg text-ink-muted", children: caption }) : null + ] }), + action != null ? /* @__PURE__ */ jsx("div", { className: "shrink-0 flex items-center gap-2", children: action }) : null + ] + } + ) : null, + /* @__PURE__ */ jsx("div", { className: classNames(padClass, bodyClassName), children }) + ] + } + ); +} function SegmentedToggle({ options, value, @@ -439,14 +548,14 @@ function SegmentedToggle({ className }) { return /* @__PURE__ */ jsx( - "div", + Panel, { + as: "div", + flush: true, role: "tablist", "aria-label": ariaLabel, - className: classNames( - "inline-flex items-center rounded-md border border-border bg-card p-0.5", - className - ), + className, + bodyClassName: "inline-flex items-center p-0.5", children: options.map( ({ value: v, label, Icon, ariaLabel: optionAriaLabel, title }) => { const active = v === value; @@ -460,7 +569,7 @@ function SegmentedToggle({ title: title ?? label, onClick: () => onChange(v), className: classNames( - "inline-flex items-center gap-1.5 rounded px-2 py-1 text-[11px] font-medium transition-colors min-h-8", + "inline-flex items-center gap-1.5 rounded px-2 py-1 mg-type-caption font-medium transition-colors min-h-8", active ? "bg-surface text-ink-strong" : "text-ink-muted hover:text-ink-strong" ), children: [ @@ -539,7 +648,7 @@ function AccentBand({ "div", { className: classNames( - "relative max-w-shell-max mx-auto px-4 md:px-8 py-14 md:py-20", + "relative max-w-shell-max mx-auto px-4 md:px-8 py-12 md:py-20", innerClassName ), children @@ -1205,7 +1314,7 @@ function HealthDot({ if (variant === "dot") return dot; return /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", children: [ dot, - /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-ink", children: label }) + /* @__PURE__ */ jsx("span", { className: "mg-type-caption font-medium text-ink", children: label }) ] }); } function HealthPill({ @@ -1215,7 +1324,7 @@ function HealthPill({ if (label) { return /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", children: [ /* @__PURE__ */ jsx(HealthDot, { state }), - /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-ink", children: label }) + /* @__PURE__ */ jsx("span", { className: "mg-type-caption font-medium text-ink", children: label }) ] }); } return /* @__PURE__ */ jsx(HealthDot, { state, variant: "label" }); @@ -1258,7 +1367,7 @@ function CurationChip({ level }) { "span", { className: classNames( - "inline-flex items-center rounded border px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wider", + "inline-flex items-center rounded border px-1.5 py-0.5 mg-type-caption font-medium uppercase tracking-wider", cls ), children: label @@ -1280,7 +1389,7 @@ function ReviewChip({ state }) { "span", { className: classNames( - "inline-flex items-center rounded border px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wider", + "inline-flex items-center rounded border px-1.5 py-0.5 mg-type-caption font-medium uppercase tracking-wider", reviewCls[key] ), title: `Maintainer review: ${key}`, @@ -1289,7 +1398,7 @@ function ReviewChip({ state }) { ); } function CandidateChip() { - return /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded border border-dashed border-ink-subtle bg-transparent px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wider text-ink-muted", children: "Unverified" }); + return /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded border border-dashed border-ink-subtle bg-transparent px-1.5 py-0.5 mg-type-caption font-medium uppercase tracking-wider text-ink-muted", children: "Unverified" }); } function truncateCopyPreview(value, max = 64) { return value.length > max ? value.slice(0, max) + "\u2026" : value; @@ -1555,11 +1664,11 @@ function DownloadCsvButton({ "aria-label": label, title: label, className: classNames( - bare ? "inline-flex items-center gap-1.5 rounded px-2 py-1 min-h-8 text-[11px] font-medium text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : ( + bare ? "inline-flex items-center gap-1.5 rounded px-2 py-1 min-h-8 mg-type-caption font-medium text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : ( // rounded-full matches the pill idiom shared by SectionBadge/FilterChip/ // other compact header controls it commonly sits next to — a plain // `rounded` rectangle reads as a mismatched shape beside a pill. - "inline-flex items-center gap-1.5 rounded-full border border-border bg-card p-1.5 text-[11px] font-medium text-ink hover:border-ink/30 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring sm:px-2.5 sm:py-1" + "inline-flex items-center gap-1.5 rounded-full border border-border bg-card p-1.5 mg-type-caption font-medium text-ink hover:border-ink/30 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring sm:px-2.5 sm:py-1" ), className ), @@ -1598,26 +1707,19 @@ function EligibilityChip({ { tabIndex: 0, className: classNames( - "inline-flex items-center gap-1.5 rounded-full border bg-transparent font-mono uppercase tracking-wider whitespace-nowrap cursor-help transition-colors", + "inline-flex items-center gap-1.5 rounded-full border bg-transparent whitespace-nowrap cursor-help transition-colors", "before:content-[''] before:size-1.5 before:rounded-full", "hover:bg-surface/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", - size === "xs" ? "px-2 py-0 text-[9px] h-5" : "px-2.5 py-0 text-[10px] h-6", + size === "xs" ? "px-2 py-0 h-5 mg-type-micro" : "px-2.5 py-0 h-6 mg-type-label", TONE[eligibility] ), children: ELIGIBILITY_LABEL[eligibility] } ) }), - /* @__PURE__ */ jsxs( - TooltipContent, - { - side: "top", - className: "max-w-[240px] text-[11px] leading-relaxed", - children: [ - /* @__PURE__ */ jsx("div", { className: "mg-type-micro opacity-70 mb-1", children: ELIGIBILITY_LABEL[eligibility] }), - RULE[eligibility] - ] - } - ) + /* @__PURE__ */ jsxs(TooltipContent, { side: "top", className: "max-w-[240px] mg-type-caption", children: [ + /* @__PURE__ */ jsx("div", { className: "mg-type-micro opacity-70 mb-1", children: ELIGIBILITY_LABEL[eligibility] }), + RULE[eligibility] + ] }) ] }) }); } var SAFE_EXTERNAL_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]); @@ -1661,9 +1763,36 @@ function ExternalLink({ children, authRequired, publicSafe = true, - className + className, + bare, + title, + ariaLabel }) { const safeHref = safeExternalUrl(href); + if (bare) { + if (!safeHref) { + return /* @__PURE__ */ jsx( + "span", + { + className, + title: title ?? "Blocked unsafe external URL", + children + } + ); + } + return /* @__PURE__ */ jsx( + "a", + { + href: safeHref, + target: "_blank", + rel: "noopener noreferrer", + title, + "aria-label": ariaLabel, + className, + children + } + ); + } const content = /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx("span", { className: "truncate", children }), safeHref ? /* @__PURE__ */ jsx(ExternalLink$1, { className: "size-3 shrink-0 text-ink-muted" }) : null, @@ -1723,14 +1852,7 @@ function InfoTooltip({ children: /* @__PURE__ */ jsx(Info, { className: "size-3.5" }) } ) }), - /* @__PURE__ */ jsx( - TooltipContent, - { - side: "top", - className: "max-w-xs text-[11px] leading-relaxed", - children: label - } - ) + /* @__PURE__ */ jsx(TooltipContent, { side: "top", className: "max-w-xs mg-type-caption", children: label }) ] }) }); } function FreshnessIndicator({ @@ -1811,7 +1933,7 @@ function HoverPreview({ "span", { role: "tooltip", - className: "absolute left-0 top-full z-[var(--mg-z-overlay)] mt-1.5 w-72 max-w-[80vw] rounded border border-border bg-card p-3 shadow-lg text-[11px] text-ink leading-relaxed", + className: "absolute left-0 top-full z-[var(--mg-z-overlay)] mt-1.5 w-72 max-w-[80vw] rounded border border-border bg-card p-3 shadow-lg mg-type-caption text-ink", children: content } ) : null @@ -1976,7 +2098,7 @@ function LoadMore({ ); } if (error) { - return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-health-down/30 bg-health-down/5 px-4 py-2 text-[11px]", children: [ + return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-health-down/30 bg-health-down/5 px-4 py-2 mg-type-caption", children: [ /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 text-health-down", children: [ /* @__PURE__ */ jsx(AlertCircle, { className: "size-3" }), "Couldn\u2019t load more \u2014 ", @@ -1998,7 +2120,7 @@ function LoadMore({ ] }); } if (cursorInvalid) { - return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-health-warn/30 bg-health-warn/5 px-4 py-2 text-[11px] text-health-warn", children: [ + return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-health-warn/30 bg-health-warn/5 px-4 py-2 mg-type-caption text-health-warn", children: [ /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", children: [ /* @__PURE__ */ jsx(AlertCircle, { className: "size-3" }), "Pagination stopped \u2014 the server returned an invalid next cursor." @@ -2019,7 +2141,7 @@ function LoadMore({ { type: "button", onClick: onLoadMore, - className: "inline-flex items-center rounded border border-border bg-card px-3 py-1.5 text-[11px] font-medium hover:border-ink/30 min-h-9", + className: "inline-flex items-center rounded border border-border bg-card px-3 py-1.5 mg-type-caption font-medium hover:border-ink/30 min-h-9", children: "Load more" } ) : /* @__PURE__ */ jsx("span", { className: "opacity-60", children: "end of list" }) @@ -2040,7 +2162,7 @@ function PageHero({ "section", { className: classNames( - "mg-hero-slab relative mb-12 md:mb-16 pt-12 md:pt-20 pb-10 md:pb-14", + "mg-hero-slab relative mb-12 md:mb-16 pt-12 md:pt-20 pb-10 md:pb-12", className ), children: [ @@ -2051,8 +2173,8 @@ function PageHero({ live ? /* @__PURE__ */ jsx("span", { className: "mg-live-dot" }) : null, eyebrow ] }) : null, - /* @__PURE__ */ jsx("h1", { className: "mg-fade-in mg-fade-in-delay-1 mt-4 font-display text-[2.5rem] sm:text-5xl md:text-[3.75rem] font-semibold leading-[1.02] tracking-[-0.025em] text-ink-strong", children: title }), - description ? /* @__PURE__ */ jsx("p", { className: "mg-fade-in mg-fade-in-delay-2 mt-5 max-w-xl text-base md:text-lg text-ink-muted leading-relaxed", children: description }) : null, + /* @__PURE__ */ jsx("h1", { className: "mg-fade-in mg-fade-in-delay-1 mt-4 font-display text-[2.5rem] sm:text-5xl md:text-6xl font-semibold leading-[1.02] tracking-[-0.025em] text-ink-strong", children: title }), + description ? /* @__PURE__ */ jsx("p", { className: "mg-fade-in mg-fade-in-delay-2 mt-4 max-w-xl text-base md:text-lg text-ink-muted leading-relaxed", children: description }) : null, actions ? /* @__PURE__ */ jsx("div", { className: "mg-fade-in mg-fade-in-delay-3 mt-6 flex flex-wrap items-center gap-2", children: actions }) : null ] }), aside ? /* @__PURE__ */ jsx("div", { className: "mg-fade-in mg-fade-in-delay-2 hidden md:block shrink-0", children: aside }) : null @@ -2095,12 +2217,12 @@ function EntityHero({ { className: classNames( "mg-hero-slab relative", - display ? "mb-12 md:mb-16 pt-12 md:pt-20 pb-10 md:pb-14" : "pt-8 md:pt-12 pb-8 md:pb-10 mb-6", + display ? "mb-12 md:mb-16 pt-12 md:pt-20 pb-10 md:pb-12" : "pt-8 md:pt-12 pb-8 md:pb-10 mb-6", className ), children: [ caption ? /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-4 hidden md:block", children: /* @__PURE__ */ jsx("span", { className: "mg-hero-caption", children: caption }) }) : null, - banner ? /* @__PURE__ */ jsx("div", { className: "mb-5", children: banner }) : null, + banner ? /* @__PURE__ */ jsx("div", { className: "mb-4", children: banner }) : null, /* @__PURE__ */ jsxs( "div", { @@ -2131,7 +2253,7 @@ function EntityHero({ { className: classNames( "mg-fade-in mg-fade-in-delay-1 font-display font-semibold text-ink-strong", - display ? "mt-4 text-[2.5rem] sm:text-5xl md:text-[3.75rem] leading-[1.02] tracking-[-0.025em]" : "text-3xl md:text-4xl tracking-[-0.01em]" + display ? "mt-4 text-[2.5rem] sm:text-5xl md:text-6xl leading-[1.02] tracking-[-0.025em]" : "text-3xl md:text-4xl tracking-[-0.01em]" ), children: title } @@ -2143,7 +2265,7 @@ function EntityHero({ { className: classNames( "mg-fade-in mg-fade-in-delay-2 text-ink-muted leading-relaxed", - display ? "mt-5 max-w-xl text-base md:text-lg" : "mt-3 max-w-3xl text-sm md:text-base" + display ? "mt-4 max-w-xl text-base md:text-lg" : "mt-3 max-w-3xl text-sm md:text-base" ), children: description } @@ -2207,7 +2329,7 @@ function PageSection({ "data-section-anchor": id ? "" : void 0, className: classNames( "mg-section", - tone === "muted" && "rounded-xl bg-surface-2/40 px-5 md:px-8 py-8 md:py-10", + tone === "muted" && "rounded-xl bg-surface-2/40 px-4 md:px-8 py-8 md:py-10", className ), children: [ @@ -2222,7 +2344,7 @@ function PageSection({ children: [ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [ eyebrow ? /* @__PURE__ */ jsx("div", { className: "mg-type-micro text-ink-muted inline-flex items-center gap-2", children: eyebrow }) : null, - title ? /* @__PURE__ */ jsxs("h2", { className: "group/anchor mt-2 flex items-baseline gap-2 font-display text-2xl md:text-[1.875rem] font-semibold tracking-[-0.02em] text-ink-strong", children: [ + title ? /* @__PURE__ */ jsxs("h2", { className: "group/anchor mt-2 flex items-baseline gap-2 font-display text-2xl md:text-3xl font-semibold tracking-[-0.02em] text-ink-strong", children: [ /* @__PURE__ */ jsx("span", { children: title }), id ? /* @__PURE__ */ jsx( "a", @@ -2337,7 +2459,7 @@ function SectionAnchor({ } ) ] }), - subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-[11px] text-ink-muted", children: subtitle }) : null + subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-0.5 mg-type-caption text-ink-muted", children: subtitle }) : null ] }), right ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: right }) : null ] }), @@ -2413,7 +2535,7 @@ function ShareButton({ "aria-label": "Copy link with current filters, sort, and page", title: "Copy link with current filters, sort, and page", className: classNames( - connected ? "inline-flex size-8 items-center justify-center text-ink-muted hover:bg-surface hover:text-ink-strong transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : bare ? iconOnly ? "inline-flex items-center justify-center rounded p-1 min-h-8 text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : "inline-flex items-center gap-1.5 rounded px-2 py-1 min-h-8 text-[11px] font-medium text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : iconOnly ? "inline-flex size-8 items-center justify-center rounded-md border border-border bg-card text-ink-muted hover:border-ink/30 hover:text-ink-strong transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : "inline-flex items-center gap-1.5 rounded border border-border bg-card px-2.5 py-1 text-[11px] font-medium text-ink hover:border-ink/30 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring", + connected ? "inline-flex size-8 items-center justify-center text-ink-muted hover:bg-surface hover:text-ink-strong transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : bare ? iconOnly ? "inline-flex items-center justify-center rounded p-1 min-h-8 text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : "inline-flex items-center gap-1.5 rounded px-2 py-1 min-h-8 mg-type-caption font-medium text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : iconOnly ? "inline-flex size-8 items-center justify-center rounded-md border border-border bg-card text-ink-muted hover:border-ink/30 hover:text-ink-strong transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : "inline-flex items-center gap-1.5 rounded border border-border bg-card px-2.5 py-1 mg-type-caption font-medium text-ink hover:border-ink/30 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring", className ), children: [ @@ -2440,12 +2562,12 @@ function ActionBar({ className }) { return /* @__PURE__ */ jsx( - "div", + Panel, { - className: classNames( - "inline-flex items-center gap-0.5 rounded-md border border-border bg-card p-0.5", - className - ), + as: "div", + flush: true, + className, + bodyClassName: "inline-flex items-center gap-0.5 p-0.5", children } ); @@ -2905,13 +3027,12 @@ function PrimaryLinksRail({ const Icon = it.icon; const href = safeExternalUrl(it.href); return /* @__PURE__ */ jsx( - "a", + ExternalLink, { href, - target: "_blank", - rel: "noopener noreferrer", + bare: true, title: it.label, - "aria-label": it.label, + ariaLabel: it.label, className: "inline-flex size-8 items-center justify-center text-ink-muted hover:bg-surface hover:text-ink-strong transition-colors", children: /* @__PURE__ */ jsx(Icon, { className: "size-4" }) }, @@ -2919,7 +3040,15 @@ function PrimaryLinksRail({ ); }); if (bare) return /* @__PURE__ */ jsx(Fragment, { children: segments }); - return /* @__PURE__ */ jsx("div", { className: "inline-flex items-center rounded-md border border-border bg-card divide-x divide-border overflow-hidden", children: segments }); + return /* @__PURE__ */ jsx( + Panel, + { + as: "div", + flush: true, + bodyClassName: "inline-flex items-center divide-x divide-border overflow-hidden", + children: segments + } + ); } function MethodologyCallout({ generatedAt, @@ -2967,7 +3096,7 @@ function MethodologyCallout({ ] } ), - open ? /* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-t border-border px-3 py-3 text-[11.5px] leading-relaxed text-ink-muted md:grid-cols-2", children: [ + open ? /* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-t border-border px-3 py-3 mg-type-caption text-ink-muted md:grid-cols-2", children: [ /* @__PURE__ */ jsxs("div", { children: [ /* @__PURE__ */ jsx("div", { className: "mg-type-micro text-ink-strong", children: "Sparklines" }), /* @__PURE__ */ jsx("p", { className: "mt-1", children: "Uptime & latency sparklines plot the active health window (7d default, switchable to 30d). Each point is the mean across every tracked endpoint in that bucket \u2014 gaps mean no probe landed in the window, not zero." }) @@ -3392,7 +3521,7 @@ function SparkLegend({ sideOffset: 6, collisionPadding: 8, avoidCollisions: true, - className: "max-w-xs text-[11px] leading-relaxed", + className: "max-w-xs mg-type-caption", children: [ /* @__PURE__ */ jsxs("div", { className: "mg-type-micro mb-1", children: [ metric, @@ -3579,115 +3708,6 @@ function Sparkline({ } ); } -var TONE_CLASSES = { - default: "text-ink-muted", - muted: "text-ink-subtle-text", - accent: "text-accent-text", - warn: "text-health-warn-text", - down: "text-health-down" -}; -function SectionLabel({ - children, - size = "micro", - tone = "default", - icon, - hint, - as, - className, - title -}) { - const Cmp = as ?? "span"; - return /* @__PURE__ */ jsxs( - Cmp, - { - title, - className: classNames( - size === "micro" ? "mg-type-micro" : "mg-type-label", - "inline-flex items-center gap-1.5", - TONE_CLASSES[tone], - className - ), - children: [ - icon ? /* @__PURE__ */ jsx( - "span", - { - "aria-hidden": true, - className: "inline-flex size-3 items-center justify-center", - children: icon - } - ) : null, - /* @__PURE__ */ jsx("span", { className: "truncate", children }), - hint != null ? /* @__PURE__ */ jsx("span", { className: "text-ink-subtle-text normal-case tracking-normal", children: hint }) : null - ] - } - ); -} -var TONE_STYLES = { - default: { border: "border-border", bg: "bg-card" }, - accent: { border: "border-accent/40", bg: "bg-primary-soft" }, - warn: { border: "border-health-warn/40", bg: "bg-health-warn/5" }, - down: { border: "border-health-down/40", bg: "bg-health-down/5" }, - ok: { border: "border-health-ok/40", bg: "bg-health-ok/5" }, - muted: { border: "border-border", bg: "bg-surface-2" } -}; -function Panel({ - title, - action, - caption, - dense, - flush, - interactive, - tone = "default", - tintBorderOnly, - glow, - as, - className, - bodyClassName, - children, - ...rest -}) { - const Cmp = as ?? "section"; - const hasHeader = title != null || action != null || caption != null; - const padClass = flush ? "mg-panel-pad-flush" : dense ? "mg-panel-pad-dense" : "mg-panel-pad"; - const toneStyle = TONE_STYLES[tone]; - return /* @__PURE__ */ jsxs( - Cmp, - { - ...rest, - className: classNames( - "rounded border", - toneStyle.border, - tintBorderOnly ? "bg-card" : toneStyle.bg, - interactive ? "mg-hover-lift" : null, - glow ? tone === "accent" ? "mg-card-glow-accent" : "mg-card-glow" : null, - className - ), - children: [ - hasHeader ? /* @__PURE__ */ jsxs( - "header", - { - className: classNames( - "flex items-start justify-between gap-3 border-b border-border/70", - dense ? "mg-panel-pad-dense" : "mg-panel-pad" - ), - style: { - paddingTop: "var(--mg-space-sm)", - paddingBottom: "var(--mg-space-sm)" - }, - children: [ - /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [ - title != null ? /* @__PURE__ */ jsx(SectionLabel, { children: title }) : null, - caption != null ? /* @__PURE__ */ jsx("p", { className: "mt-1 mg-type-caption-lg text-ink-muted", children: caption }) : null - ] }), - action != null ? /* @__PURE__ */ jsx("div", { className: "shrink-0 flex items-center gap-2", children: action }) : null - ] - } - ) : null, - /* @__PURE__ */ jsx("div", { className: classNames(padClass, bodyClassName), children }) - ] - } - ); -} function StatTile({ icon: Icon, eyebrow, @@ -3798,26 +3818,19 @@ function StatWithSpark({ delta ] }), viz ? /* @__PURE__ */ jsx("div", { className: "mt-0.5 min-h-[18px]", children: viz }) : null, - hint ? /* @__PURE__ */ jsx("div", { className: "font-mono text-[9.5px] text-ink-muted/80 truncate", children: hint }) : null, - freshLine ? /* @__PURE__ */ jsx("div", { className: "font-mono text-[9px] tracking-wide text-ink-muted/70 truncate", children: freshLine }) : null + hint ? /* @__PURE__ */ jsx("div", { className: "mg-type-data-sm text-ink-muted/80 truncate", children: hint }) : null, + freshLine ? /* @__PURE__ */ jsx("div", { className: "mg-type-data-sm tracking-wide text-ink-muted/70 truncate", children: freshLine }) : null ] } ) }), - /* @__PURE__ */ jsxs( - TooltipContent, - { - side: "bottom", - className: "max-w-xs text-[11px] leading-relaxed", - children: [ - /* @__PURE__ */ jsx("div", { children: full ?? hint ?? label }), - freshAbs || windowLabel ? /* @__PURE__ */ jsxs("div", { className: "mt-1 mg-type-data-sm text-primary-foreground/70", children: [ - freshAbs ? `Last checked ${freshAbs}` : null, - freshAbs && windowLabel ? " \xB7 " : "", - windowLabel ? `${windowLabel} window` : null - ] }) : null - ] - } - ) + /* @__PURE__ */ jsxs(TooltipContent, { side: "bottom", className: "max-w-xs mg-type-caption", children: [ + /* @__PURE__ */ jsx("div", { children: full ?? hint ?? label }), + freshAbs || windowLabel ? /* @__PURE__ */ jsxs("div", { className: "mt-1 mg-type-data-sm text-primary-foreground/70", children: [ + freshAbs ? `Last checked ${freshAbs}` : null, + freshAbs && windowLabel ? " \xB7 " : "", + windowLabel ? `${windowLabel} window` : null + ] }) : null + ] }) ] }) }) ); } @@ -3970,19 +3983,12 @@ function NoDataSpark({ ] } ) }), - /* @__PURE__ */ jsxs( - TooltipContent, - { - side: "top", - className: "max-w-xs text-[11px] leading-relaxed", - children: [ - reason, - ".", - " ", - freshAbs ? `Last checked ${freshAbs}${windowLabel ? ` \xB7 ${windowLabel} window` : ""}.` : "No probe samples recorded yet." - ] - } - ) + /* @__PURE__ */ jsxs(TooltipContent, { side: "top", className: "max-w-xs mg-type-caption", children: [ + reason, + ".", + " ", + freshAbs ? `Last checked ${freshAbs}${windowLabel ? ` \xB7 ${windowLabel} window` : ""}.` : "No probe samples recorded yet." + ] }) ] }) }) ); } @@ -4085,7 +4091,7 @@ function TreemapMini({ style: { background: t.color ?? "var(--accent)" }, children: t.w > MIN_TILE_W_FOR_LABEL && t.h > MIN_TILE_H_FOR_LABEL ? /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx("span", { className: "truncate mg-type-data-sm font-medium leading-none text-accent-foreground", children: t.label }), - t.w > MIN_TILE_W_FOR_VALUE && t.h > MIN_TILE_H_FOR_VALUE ? /* @__PURE__ */ jsx("span", { className: "truncate font-mono text-[9px] leading-none text-accent-foreground/80", children: formatValue(t.value) }) : null + t.w > MIN_TILE_W_FOR_VALUE && t.h > MIN_TILE_H_FOR_VALUE ? /* @__PURE__ */ jsx("span", { className: "truncate mg-type-data-sm leading-none text-accent-foreground/80", children: formatValue(t.value) }) : null ] }) : null } ) diff --git a/packages/ui-kit/eslint.config.ts b/packages/ui-kit/eslint.config.ts index a7226bff4a..4c71a49aab 100644 --- a/packages/ui-kit/eslint.config.ts +++ b/packages/ui-kit/eslint.config.ts @@ -145,10 +145,31 @@ const SSR_SAFETY_RULES = [ // it. Any PR that brings a directory to 0 warnings MUST add it here in the // same PR (see apps/ui/CONTRIBUTING.md); removing an entry requires an issue // explaining why. Initial set (2026-07-24 audit): src/hooks/** and src/lib/** -// were the only ui-kit directories clean end-to-end -- src/components/** is -// not (19 of 109 files still warn) and stays un-ratcheted. +// were the only ui-kit directories clean end-to-end -- src/components/** was +// not (19 of 109 files warned). #8172 cleaned 16 of those 19; the remaining +// 3 files (see RATCHETED_COMPONENT_EXCEPTIONS below) each keep one genuinely +// missing token, so src/components/** ratchets everywhere except them rather +// than staying un-ratcheted repo-wide over 3 residual sites. const RATCHETED_DIRS = ["src/hooks/**/*.{ts,tsx}", "src/lib/**/*.{ts,tsx}"]; +// Excluded from the src/components/** ratchet below -- each still carries one +// no-restricted-syntax warning with no existing design-system-token +// equivalent (not invented ad hoc per #8172's own guidance): +// - entity-hero.tsx / page-hero.tsx: the "display"-size hero

and its +// KPI-strip value use text-[2.5rem]/text-[1.75rem] -- the mg-type-* scale +// tops out at mg-type-caption-lg (13px, see styles.css); no hero/display +// heading tier is authored yet (--mg-type-h1..h4 are reserved CSS +// variables, not yet exposed as .mg-type-h* utility classes). +// - section-anchor.tsx: `scroll-mt-32` compensates for the sticky header's +// pixel height on anchor scroll, not a spacing-scale choice -- the exact +// same site class #7810 already left unconverted elsewhere (see that +// commit's own "endpoint-detail-drawer.tsx ... scroll-mt-32" note). +const RATCHETED_COMPONENT_EXCEPTIONS = [ + "src/components/metagraphed/entity-hero.tsx", + "src/components/metagraphed/page-hero.tsx", + "src/components/metagraphed/section-anchor.tsx", +]; + const PRIMITIVE_FILES = [ "src/components/metagraphed/panel.tsx", "src/components/metagraphed/panel-header.tsx", @@ -248,6 +269,17 @@ export default tseslint.config( "no-restricted-syntax": ["error", ...DESIGN_RULES, ...SSR_SAFETY_RULES], }, }, + { + // #8172: src/components/** joins the ratchet -- every file is clean + // except the 3 in RATCHETED_COMPONENT_EXCEPTIONS (documented above), + // which `ignores` keeps at the warn tier from the block above instead + // of failing CI on their one pre-existing, genuinely-missing-token site. + files: ["src/components/**/*.{ts,tsx}"], + ignores: RATCHETED_COMPONENT_EXCEPTIONS, + rules: { + "no-restricted-syntax": ["error", ...DESIGN_RULES, ...SSR_SAFETY_RULES], + }, + }, { files: PRIMITIVE_FILES, rules: { "no-restricted-syntax": "off" }, diff --git a/packages/ui-kit/src/components/metagraphed/accent-band.tsx b/packages/ui-kit/src/components/metagraphed/accent-band.tsx index c805e4b254..c75c8063bc 100644 --- a/packages/ui-kit/src/components/metagraphed/accent-band.tsx +++ b/packages/ui-kit/src/components/metagraphed/accent-band.tsx @@ -45,7 +45,7 @@ export function AccentBand({ ) : null}
diff --git a/packages/ui-kit/src/components/metagraphed/action-bar.tsx b/packages/ui-kit/src/components/metagraphed/action-bar.tsx index 39f7211498..ad80581a72 100644 --- a/packages/ui-kit/src/components/metagraphed/action-bar.tsx +++ b/packages/ui-kit/src/components/metagraphed/action-bar.tsx @@ -1,5 +1,5 @@ import type { ReactNode } from "react"; -import { classNames } from "@/lib/format"; +import { Panel } from "./panel"; /** * Segmented container for one-shot page actions (share, download, reset @@ -17,13 +17,13 @@ export function ActionBar({ className?: string; }) { return ( -
{children} -
+ ); } diff --git a/packages/ui-kit/src/components/metagraphed/charts/spark-legend.tsx b/packages/ui-kit/src/components/metagraphed/charts/spark-legend.tsx index b9b84e2b97..da64791a64 100644 --- a/packages/ui-kit/src/components/metagraphed/charts/spark-legend.tsx +++ b/packages/ui-kit/src/components/metagraphed/charts/spark-legend.tsx @@ -53,7 +53,7 @@ export function SparkLegend({ sideOffset={6} collisionPadding={8} avoidCollisions - className="max-w-xs text-[11px] leading-relaxed" + className="max-w-xs mg-type-caption" >
{metric} diff --git a/packages/ui-kit/src/components/metagraphed/charts/stat-with-spark.tsx b/packages/ui-kit/src/components/metagraphed/charts/stat-with-spark.tsx index c2fcae6881..403da64684 100644 --- a/packages/ui-kit/src/components/metagraphed/charts/stat-with-spark.tsx +++ b/packages/ui-kit/src/components/metagraphed/charts/stat-with-spark.tsx @@ -82,21 +82,18 @@ export function StatWithSpark({
{viz ?
{viz}
: null} {hint ? ( -
+
{hint}
) : null} {freshLine ? ( -
+
{freshLine}
) : null}
- +
{full ?? hint ?? label}
{freshAbs || windowLabel ? (
@@ -273,10 +270,7 @@ export function NoDataSpark({
- + {reason}.{" "} {freshAbs ? `Last checked ${freshAbs}${windowLabel ? ` · ${windowLabel} window` : ""}.` diff --git a/packages/ui-kit/src/components/metagraphed/charts/treemap-mini.tsx b/packages/ui-kit/src/components/metagraphed/charts/treemap-mini.tsx index 58bfcd78ad..6e66ddbb0e 100644 --- a/packages/ui-kit/src/components/metagraphed/charts/treemap-mini.tsx +++ b/packages/ui-kit/src/components/metagraphed/charts/treemap-mini.tsx @@ -177,7 +177,7 @@ export function TreemapMini({ {t.label} {t.w > MIN_TILE_W_FOR_VALUE && t.h > MIN_TILE_H_FOR_VALUE ? ( - + {formatValue(t.value)} ) : null} diff --git a/packages/ui-kit/src/components/metagraphed/chips.tsx b/packages/ui-kit/src/components/metagraphed/chips.tsx index 28a579e2cd..853da2735a 100644 --- a/packages/ui-kit/src/components/metagraphed/chips.tsx +++ b/packages/ui-kit/src/components/metagraphed/chips.tsx @@ -89,7 +89,7 @@ export function HealthDot({ return ( {dot} - {label} + {label} ); } @@ -109,7 +109,7 @@ export function HealthPill({ return ( - {label} + {label} ); } @@ -172,7 +172,7 @@ export function CurationChip({ level }: { level?: CurationLevel | string }) { return ( @@ -200,7 +200,7 @@ export function ReviewChip({ state }: { state?: string }) { return ( + Unverified ); diff --git a/packages/ui-kit/src/components/metagraphed/download-csv-button.tsx b/packages/ui-kit/src/components/metagraphed/download-csv-button.tsx index c8247cdbae..b0f51e42ec 100644 --- a/packages/ui-kit/src/components/metagraphed/download-csv-button.tsx +++ b/packages/ui-kit/src/components/metagraphed/download-csv-button.tsx @@ -39,11 +39,11 @@ export function DownloadCsvButton({ title={label} className={classNames( bare - ? "inline-flex items-center gap-1.5 rounded px-2 py-1 min-h-8 text-[11px] font-medium text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" + ? "inline-flex items-center gap-1.5 rounded px-2 py-1 min-h-8 mg-type-caption font-medium text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : // rounded-full matches the pill idiom shared by SectionBadge/FilterChip/ // other compact header controls it commonly sits next to — a plain // `rounded` rectangle reads as a mismatched shape beside a pill. - "inline-flex items-center gap-1.5 rounded-full border border-border bg-card p-1.5 text-[11px] font-medium text-ink hover:border-ink/30 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring sm:px-2.5 sm:py-1", + "inline-flex items-center gap-1.5 rounded-full border border-border bg-card p-1.5 mg-type-caption font-medium text-ink hover:border-ink/30 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring sm:px-2.5 sm:py-1", className, )} > diff --git a/packages/ui-kit/src/components/metagraphed/eligibility-chip.tsx b/packages/ui-kit/src/components/metagraphed/eligibility-chip.tsx index 4f70f0f2a1..9515f122d0 100644 --- a/packages/ui-kit/src/components/metagraphed/eligibility-chip.tsx +++ b/packages/ui-kit/src/components/metagraphed/eligibility-chip.tsx @@ -66,22 +66,19 @@ export function EligibilityChip({ {ELIGIBILITY_LABEL[eligibility]} - +
{ELIGIBILITY_LABEL[eligibility]}
diff --git a/packages/ui-kit/src/components/metagraphed/entity-hero.tsx b/packages/ui-kit/src/components/metagraphed/entity-hero.tsx index 7a8c903ac0..5d521a0058 100644 --- a/packages/ui-kit/src/components/metagraphed/entity-hero.tsx +++ b/packages/ui-kit/src/components/metagraphed/entity-hero.tsx @@ -81,7 +81,7 @@ export function EntityHero({ className={classNames( "mg-hero-slab relative", display - ? "mb-12 md:mb-16 pt-12 md:pt-20 pb-10 md:pb-14" + ? "mb-12 md:mb-16 pt-12 md:pt-20 pb-10 md:pb-12" : "pt-8 md:pt-12 pb-8 md:pb-10 mb-6", className, )} @@ -92,7 +92,7 @@ export function EntityHero({
) : null} - {banner ?
{banner}
: null} + {banner ?
{banner}
: null}
@@ -136,7 +136,7 @@ export function EntityHero({ className={classNames( "mg-fade-in mg-fade-in-delay-2 text-ink-muted leading-relaxed", display - ? "mt-5 max-w-xl text-base md:text-lg" + ? "mt-4 max-w-xl text-base md:text-lg" : "mt-3 max-w-3xl text-sm md:text-base", )} > diff --git a/packages/ui-kit/src/components/metagraphed/external-link.tsx b/packages/ui-kit/src/components/metagraphed/external-link.tsx index 087e3cf508..6d84d98850 100644 --- a/packages/ui-kit/src/components/metagraphed/external-link.tsx +++ b/packages/ui-kit/src/components/metagraphed/external-link.tsx @@ -11,6 +11,16 @@ interface Props { authRequired?: boolean; publicSafe?: boolean; className?: string; + /** + * Skip the external-icon glyph, underline styling, and auth/publicSafe + * badges -- for composing into an icon-only segmented bar (e.g. + * PrimaryLinksRail) where the icon itself is the only content and a + * trailing external-icon/underline would be redundant. Still runs the + * same safeExternalUrl filtering and target/rel handling. + */ + bare?: boolean; + title?: string; + ariaLabel?: string; } const SAFE_EXTERNAL_PROTOCOLS = new Set(["http:", "https:"]); @@ -98,8 +108,37 @@ export function ExternalLink({ authRequired, publicSafe = true, className, + bare, + title, + ariaLabel, }: Props) { const safeHref = safeExternalUrl(href); + + if (bare) { + if (!safeHref) { + return ( + + {children} + + ); + } + return ( + + {children} + + ); + } + const content = ( <> {children} diff --git a/packages/ui-kit/src/components/metagraphed/hover-preview.tsx b/packages/ui-kit/src/components/metagraphed/hover-preview.tsx index fa0189416a..3afe1689bc 100644 --- a/packages/ui-kit/src/components/metagraphed/hover-preview.tsx +++ b/packages/ui-kit/src/components/metagraphed/hover-preview.tsx @@ -37,7 +37,7 @@ export function HoverPreview({ {open ? ( {content} diff --git a/packages/ui-kit/src/components/metagraphed/info-tooltip.tsx b/packages/ui-kit/src/components/metagraphed/info-tooltip.tsx index c41a898adc..0b76b9f9e4 100644 --- a/packages/ui-kit/src/components/metagraphed/info-tooltip.tsx +++ b/packages/ui-kit/src/components/metagraphed/info-tooltip.tsx @@ -32,10 +32,7 @@ export function InfoTooltip({ - + {label} diff --git a/packages/ui-kit/src/components/metagraphed/list-shell.tsx b/packages/ui-kit/src/components/metagraphed/list-shell.tsx index 693f6509bf..f2af396ac9 100644 --- a/packages/ui-kit/src/components/metagraphed/list-shell.tsx +++ b/packages/ui-kit/src/components/metagraphed/list-shell.tsx @@ -150,7 +150,7 @@ export function LoadMore({ if (error) { return ( -
+
Couldn’t load more — {error.message || "network error"}. @@ -168,7 +168,7 @@ export function LoadMore({ if (cursorInvalid) { return ( -
+
Pagination stopped — the server returned an invalid next cursor. @@ -191,7 +191,7 @@ export function LoadMore({ diff --git a/packages/ui-kit/src/components/metagraphed/methodology-callout.tsx b/packages/ui-kit/src/components/metagraphed/methodology-callout.tsx index 6fc3f02f82..9ae2bb31a2 100644 --- a/packages/ui-kit/src/components/metagraphed/methodology-callout.tsx +++ b/packages/ui-kit/src/components/metagraphed/methodology-callout.tsx @@ -59,7 +59,7 @@ export function MethodologyCallout({ /> {open ? ( -
+
Sparklines

diff --git a/packages/ui-kit/src/components/metagraphed/page-hero.tsx b/packages/ui-kit/src/components/metagraphed/page-hero.tsx index 341d8c988b..6d4deed975 100644 --- a/packages/ui-kit/src/components/metagraphed/page-hero.tsx +++ b/packages/ui-kit/src/components/metagraphed/page-hero.tsx @@ -43,7 +43,7 @@ export function PageHero({ return (

@@ -60,11 +60,11 @@ export function PageHero({ {eyebrow}
) : null} -

+

{title}

{description ? ( -

+

{description}

) : null} diff --git a/packages/ui-kit/src/components/metagraphed/page-section.tsx b/packages/ui-kit/src/components/metagraphed/page-section.tsx index 351e419fb3..ee1cb9a2c7 100644 --- a/packages/ui-kit/src/components/metagraphed/page-section.tsx +++ b/packages/ui-kit/src/components/metagraphed/page-section.tsx @@ -44,7 +44,7 @@ export function PageSection({ className={classNames( "mg-section", tone === "muted" && - "rounded-xl bg-surface-2/40 px-5 md:px-8 py-8 md:py-10", + "rounded-xl bg-surface-2/40 px-4 md:px-8 py-8 md:py-10", className, )} > @@ -65,7 +65,7 @@ export function PageSection({
) : null} {title ? ( -

+

{title} {id ? ( - + ); }); if (bare) return <>{segments}; return ( -
+ {segments} -
+ ); } diff --git a/packages/ui-kit/src/components/metagraphed/section-anchor.tsx b/packages/ui-kit/src/components/metagraphed/section-anchor.tsx index c2bc20f890..a412897d57 100644 --- a/packages/ui-kit/src/components/metagraphed/section-anchor.tsx +++ b/packages/ui-kit/src/components/metagraphed/section-anchor.tsx @@ -87,7 +87,7 @@ export function SectionAnchor({

{subtitle ? ( -

{subtitle}

+

{subtitle}

) : null}
{right ?
{right}
: null} diff --git a/packages/ui-kit/src/components/metagraphed/share-button.tsx b/packages/ui-kit/src/components/metagraphed/share-button.tsx index 8961e0e6ef..6062509661 100644 --- a/packages/ui-kit/src/components/metagraphed/share-button.tsx +++ b/packages/ui-kit/src/components/metagraphed/share-button.tsx @@ -91,10 +91,10 @@ export function ShareButton({ : bare ? iconOnly ? "inline-flex items-center justify-center rounded p-1 min-h-8 text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" - : "inline-flex items-center gap-1.5 rounded px-2 py-1 min-h-8 text-[11px] font-medium text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" + : "inline-flex items-center gap-1.5 rounded px-2 py-1 min-h-8 mg-type-caption font-medium text-ink-muted hover:text-ink-strong hover:bg-surface transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" : iconOnly ? "inline-flex size-8 items-center justify-center rounded-md border border-border bg-card text-ink-muted hover:border-ink/30 hover:text-ink-strong transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring" - : "inline-flex items-center gap-1.5 rounded border border-border bg-card px-2.5 py-1 text-[11px] font-medium text-ink hover:border-ink/30 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring", + : "inline-flex items-center gap-1.5 rounded border border-border bg-card px-2.5 py-1 mg-type-caption font-medium text-ink hover:border-ink/30 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring", className, )} > diff --git a/packages/ui-kit/src/components/ui/segmented-toggle.tsx b/packages/ui-kit/src/components/ui/segmented-toggle.tsx index 6be0185fc3..9f98f51985 100644 --- a/packages/ui-kit/src/components/ui/segmented-toggle.tsx +++ b/packages/ui-kit/src/components/ui/segmented-toggle.tsx @@ -1,5 +1,6 @@ import { type ComponentType } from "react"; import { classNames } from "@/lib/format"; +import { Panel } from "@/components/metagraphed/panel"; export interface SegmentedToggleOption { value: T; @@ -29,13 +30,13 @@ export function SegmentedToggle({ className?: string; }) { return ( -
{options.map( ({ value: v, label, Icon, ariaLabel: optionAriaLabel, title }) => { @@ -50,7 +51,7 @@ export function SegmentedToggle({ title={title ?? label} onClick={() => onChange(v)} className={classNames( - "inline-flex items-center gap-1.5 rounded px-2 py-1 text-[11px] font-medium transition-colors min-h-8", + "inline-flex items-center gap-1.5 rounded px-2 py-1 mg-type-caption font-medium transition-colors min-h-8", active ? "bg-surface text-ink-strong" : "text-ink-muted hover:text-ink-strong", @@ -62,6 +63,6 @@ export function SegmentedToggle({ ); }, )} -
+ ); }