import * as React from 'react'; import { Badge } from '@/components/badge'; import type { BadgeProps } from '@/components/badge'; import { PlusIcon, SettingsIcon } from '@/icons'; import { MatrixGrid } from '~/chrome/ui/matrix'; import { useMessages } from '../i18n'; import type { Complete, Palette } from '../registry/axis-values'; import { useParam } from '../router'; /** * The Badge set as CBAR's canvas lays it out. * * Read off the set's own `absoluteBoundingBox` values (node `2456:5146`, 32 * variants): x is **variant**, two columns 164px apart — `solid(1315) → * surface(1479)`. y is banded by **color**, ~228px apart, in this order — * `black(261) → success(484) → removed(712) → default(940)`. Within a band, y * sub-offset is **size** — `xs(+0) → sm(+33) → md(+72) → lg(+117)`. * * So a band is one grid with size down and variant across, and the four of them * come to 4 × 8 = 32 — the whole set, cell for cell. Unlike Button, Badge has no * state axis: it is not interactive, so every prop shown here is a real prop and * there is nothing for a `code` override to strip. * * Two artefacts on the canvas, neither of them a divergence to fix. The * `surface / lg / default` cell takes its inset border from `secondary-500` * while its three siblings take `secondary-200`, and `solid / lg / black` * carries `paddingTop/Bottom: 128` where every other variant carries 10 — the * frame height is `FIXED`, so that padding never reaches the pixels. */ /** * CBAR's band order, paired with the kit palette that paints it. * * The pairing is read off the fills, not off the axis names — those name a role * (`default`, `removed`) rather than a ramp, so there is nothing to match on. * Per band, `solid` / `surface` / border: * * black #333333 #F9F9F9 #474747 neutral-700 / -50 / (neutral-600) * success #22C55E #DCFCE7 #22C55E green-500 / -100 / -500 * removed #EF4444 #FEE2E2 #F00000 red-500 / -100 / (off-ramp) * default #4BC7B5 #CFF3EC #A6E8DA secondary-500 / -100 / -200 * * The last row is the same three values `pages/alerts-figma.tsx` records for its * `info` band, so CBAR's default badge is the turquoise `secondary`, not the * navy `primary` — which is what `registry/badge.tsx`'s `valueMap` used to say. * That leaves `primary`, `tertiary` and `yellow` with no band here; all three * are still on the Gallery tab, which sweeps every kit palette. */ const COLOR_BANDS = [ { color: 'black', palette: 'black' }, { color: 'success', palette: 'green' }, { color: 'removed', palette: 'red' }, { color: 'default', palette: 'secondary' }, ] as const satisfies readonly { color: string; palette: Palette }[]; /** * Canvas order, restated as a literal rather than reversed off the kit's array * at runtime, so the coverage check below reads a literal — the rule * `pages/avatars-figma.tsx` follows for the same reason. */ const FIGMA_SIZES = ['xs', 'sm', 'md', 'lg'] as const; /** * The canvas draws two treatments. It is deliberately **not** covered by a * `Complete<>` check: the kit's `subtle`, `outline` and `ghost` have no column * here because CBAR does not draw them, and a coverage error would be the page * complaining about the design file. * * CBAR's `surface` is the kit's `surface`, not its `subtle`. Every one of the 16 * surface variants carries `box-shadow: 0 0 1px 0 inset` — a 1px border * drawn as an inset shadow — which is the tint-plus-outline the kit calls * `surface`. */ const FIGMA_VARIANTS = ['solid', 'surface'] as const; type Variant = (typeof FIGMA_VARIANTS)[number]; type Size = (typeof FIGMA_SIZES)[number]; /* Exported because `noUnusedLocals` is on; it is a compile-time assertion that the canvas list above still names every size the kit ships. */ export type _SizesCovered = Complete>; /** * `.iconStart?` and `.iconEnd?` are BOOLEAN properties on the set and both * default to **true**, so every one of the 32 variants on the canvas has a glyph * on each side. The kit takes icons as children rather than as props, which * means the arrangement is child order and there is nothing to compare on the * parity page — so it is a control here instead, defaulting to what Figma * defaults to. * * The two glyphs are the set's own INSTANCE_SWAP defaults: `leftElement` = * `Outline/Interface/Plus` (2163:386), `rightElement` = * `Outline/Interface/Settings` (2163:176). Both already default to outline, so * neither needs a `variant` prop. */ const ICON_SLOTS = ['both', 'left', 'right', 'none'] as const; type IconSlots = (typeof ICON_SLOTS)[number]; /** The canvas's own label text — demo data, so it stays out of the catalogue. */ const LABEL = 'Label'; function Field({ label, children }: { label: string; children: React.ReactNode }) { return ( ); } export function FigmaLayoutView() { const m = useMessages(); const [color, setColor] = useParam('color', 'all'); const [slots, setSlots] = useParam('icons', 'both'); /* A hand-edited `?icons=` would otherwise read as "neither", which looks like the page ignoring the design rather than the URL being wrong. */ const iconSlots: IconSlots = ICON_SLOTS.includes(slots as IconSlots) ? (slots as IconSlots) : 'both'; const showLeft = iconSlots === 'both' || iconSlots === 'left'; const showRight = iconSlots === 'both' || iconSlots === 'right'; const bands = React.useMemo( () => (color === 'all' ? COLOR_BANDS : COLOR_BANDS.filter((b) => b.color === color)), [color] ); const cell = (variant: Variant, colorPalette: Palette, size: Size) => ( {showLeft ? : null} {LABEL} {showRight ? : null} ); return (

{m.badges.figma.lead}

{m.badges.figma.bandNote}

{m.badges.figma.defaultNote}

{m.badges.figma.variantNote}

{m.badges.figma.iconNote}

{bands.map((band) => (

color="{band.color}" ({band.palette})

cell(col as Variant, band.palette, row as Size)} cellTitle={(row, col) => `variant=${String(col)}, size=${String(row)}, color=${band.color} (colorPalette=${band.palette})` } copyAll={false} />
))}
); }