import type { Meta, StoryObj } from '@storybook/vue3-vite' import type { Token } from '@/stories/tokenUtils' import { docLabelStyle } from '@/stories/documentationStyles' import { copyableClass, copyableCopiedClass, readTokens, useCopier } from '@/stories/tokenUtils' const meta: Meta = { title: 'Foundations/Colors', tags: ['!dev'], parameters: { layout: 'padded', controls: { disable: true }, docs: { source: { code: null } }, }, } export default meta type Story = StoryObj const FAMILIES = ['accent', 'blue', 'error', 'magenta', 'neutral', 'pink', 'success', 'warning', 'yellow'] as const const FAMILY_ORDER: readonly string[] = [ 'base', 'accent', 'error', 'warning', 'success', 'blue', 'pink', 'magenta', 'yellow', 'neutral', ] const FAMILY_LABEL: Record = { base: 'Base', accent: 'Accent', error: 'Error', warning: 'Warning', success: 'Success', blue: 'Blue', pink: 'Pink', magenta: 'Magenta', yellow: 'Yellow', neutral: 'Neutral', } const gridStyle = 'display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px;' const cardStyle = 'display: flex; flex-direction: column; border: 1px solid #e9eaf6; border-radius: 8px; overflow: hidden; background: #ffffff;' const swatchStyle = (tokenName: string) => `height: 72px; background: var(${tokenName}); border-bottom: 1px solid rgba(0, 0, 0, 0.06);` const cardBodyStyle = 'display: flex; flex-direction: column; gap: 2px; padding: 10px 12px;' const cardNameStyle = 'font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; color: #111; word-break: break-all;' const cardValueStyle = 'font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; color: #6b7280; word-break: break-all;' const familyGroupStyle = 'display: flex; flex-direction: column; gap: 10px; margin-bottom: 24px;' type Family = { label: string; tokens: Token[] } const familyOf = (name: string, prefix: string): string => { const rest = name.startsWith(prefix) ? name.slice(prefix.length) : name const first = rest.split('-')[0] return (FAMILIES as readonly string[]).includes(first) ? first : 'base' } const groupByFamily = (tokens: Token[], prefix: string): Family[] => { const byFamily = new Map() for (const token of tokens) { const key = familyOf(token.name, prefix) const bucket = byFamily.get(key) ?? [] bucket.push(token) byFamily.set(key, bucket) } return FAMILY_ORDER.filter((key) => byFamily.has(key)).map((key) => ({ label: FAMILY_LABEL[key] ?? key, tokens: byFamily.get(key) ?? [], })) } type SectionArgs = { exclude?: (RegExp | string)[]; prefix: string } const makeSectionStory = (section: SectionArgs): Story => ({ render: () => ({ setup() { const tokens = readTokens([section.prefix], section.exclude ?? []) const { copiedKey, copy } = useCopier() return { count: tokens.length, families: groupByFamily(tokens, section.prefix), copiedKey, copy, labelStyle: docLabelStyle, groupStyle: familyGroupStyle, grid: gridStyle, card: cardStyle, body: cardBodyStyle, nameText: cardNameStyle, valueText: cardValueStyle, copyClass: copyableClass, copiedClass: copyableCopiedClass, swatch: (tokenName: string) => swatchStyle(tokenName), } }, template: `
{{ family.label }} ({{ family.tokens.length }})
{{ copiedKey === token.name ? 'Copied!' : token.name }} {{ token.value }}
No tokens
`, }), }) /** * Surface colors used for page, card and control backgrounds. */ export const Background: Story = makeSectionStory({ prefix: '--cp-background-' }) /** * Border colors for dividers, card outlines and control edges. */ export const Border: Story = makeSectionStory({ prefix: '--cp-border-' }) /** * Foreground colors used for icons, illustrations and decorative surfaces * that sit on top of the background. */ export const Foreground: Story = makeSectionStory({ prefix: '--cp-foreground-' }) /** * Text colors. Typography size, line-height and letter-spacing tokens live * under the Typography section. */ export const Text: Story = makeSectionStory({ prefix: '--cp-text-', exclude: [/-line-height$/, /-letter-spacing$/, /^--cp-text-size-/], }) /** * Utility colors for transient UI surfaces such as overlays, shadows or * state indicators. */ export const Utility: Story = makeSectionStory({ prefix: '--cp-utility-' }) /** * Dedicated colors used by focus rings. See the Focus Rings section for * composite ring tokens. */ export const Focus: Story = makeSectionStory({ prefix: '--cp-focus' })