Merged in feat/SW-3636-storybook-structure (pull request #3309)

feat(SW-3636): Storybook structure

* New sections in Storybook sidebar

* Group Storybook content files and add token files for spacing, border radius and shadows


Approved-by: Joakim Jäderberg
This commit is contained in:
Rasmus Langvad
2025-12-08 12:35:14 +00:00
parent 177c2e7176
commit ca6cc5ab6c
83 changed files with 1272 additions and 525 deletions

View File

@@ -0,0 +1,128 @@
/* eslint-disable formatjs/no-literal-string-in-jsx */
import copy from 'copy-to-clipboard'
import { kebabify } from '../../generate/utils'
import tableStyles from './tokens.module.css'
type ThemeValue = {
resolved: string | number
alias?: string | number
}
type Theme = Record<string, ThemeValue>
type SpacingProps = {
theme: Theme
}
function copyToClipboard(text: string) {
copy(text)
}
// Extract base unit multiplier from token name
function getBaseUnitMultiplier(tokenName: string): string {
// Token names are like "Space/x0", "Space/x025", "Space/x05", "Space/x1", "Space/x15", etc.
const match = tokenName.match(/Space\/x(\d+)/)
if (!match) return '0x'
const num = match[1]
// Handle special cases
if (num === '0') return '0x'
if (num === '025') return '0.25x'
if (num === '05') return '0.5x'
if (num === '15') return '1.5x'
// For other numbers, they're already the multiplier (x1 = 1x, x2 = 2x, etc.)
return `${num}x`
}
export function Spacing({ theme }: SpacingProps) {
// Filter spacing tokens
const spacingTokens: Theme = {}
for (const [k, v] of Object.entries(theme)) {
if (k.startsWith('Space/')) {
spacingTokens[k] = v as ThemeValue
}
}
// Sort by value
const sortedTokens = Object.entries(spacingTokens).sort((a, b) => {
const aValue = typeof a[1].resolved === 'number' ? a[1].resolved : 0
const bValue = typeof b[1].resolved === 'number' ? b[1].resolved : 0
return aValue - bValue
})
return (
<div>
<div className={tableStyles.tableContainer}>
<table className={tableStyles.table}>
<thead className={tableStyles.tableHeader}>
<tr>
<th className={tableStyles.tableHeaderCell}>Token</th>
<th className={tableStyles.tableHeaderCell}>
Base unit multiplier
</th>
<th className={tableStyles.tableHeaderCell}>Pixels</th>
<th className={tableStyles.tableHeaderCell}>
Visual representation
</th>
</tr>
</thead>
<tbody>
{sortedTokens.map(([k, v]) => {
const value = typeof v.resolved === 'number' ? v.resolved : 0
const valuePx = `${value}px`
const multiplier = getBaseUnitMultiplier(k)
return (
<tr key={k} className={tableStyles.tableRow}>
<td className={tableStyles.tableCell}>
<code
className={tableStyles.tokenName}
onClick={() => {
copyToClipboard(`var(--${kebabify(k)})`)
}}
title="Click to copy CSS variable"
>
{kebabify(k)}
</code>
</td>
<td className={tableStyles.tableCell}>
<span className={tableStyles.value}>{multiplier}</span>
</td>
<td className={tableStyles.tableCell}>
<code
className={tableStyles.value}
onClick={() => {
copyToClipboard(valuePx)
}}
title="Click to copy"
>
{valuePx}
</code>
</td>
<td className={tableStyles.tableCell}>
<div className={tableStyles.visualBarContainer}>
<span className={tableStyles.visualBarLabel}>
{valuePx}
</span>
<div
className={tableStyles.visualBar}
style={{
width: `${value}px`,
minWidth: value > 0 ? '2px' : '0',
}}
/>
</div>
</td>
</tr>
)
})}
</tbody>
</table>
</div>
</div>
)
}