design system token v0.1
This commit is contained in:
190
style-dictionary.config.mjs
Normal file
190
style-dictionary.config.mjs
Normal file
@@ -0,0 +1,190 @@
|
||||
import StyleDictionary from 'style-dictionary';
|
||||
|
||||
// Custom format: CSS custom properties with RGB triplets for Tailwind v4 compatibility
|
||||
// Outputs `--background: 240 240 236;` format that existing components expect
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'css/rgb-variables',
|
||||
format: ({ dictionary, options }) => {
|
||||
const selector = options.selector || ':root';
|
||||
const header = options.header || '';
|
||||
|
||||
function hexToRgb(hex) {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
if (!result) return null;
|
||||
return `${parseInt(result[1], 16)} ${parseInt(result[2], 16)} ${parseInt(result[3], 16)}`;
|
||||
}
|
||||
|
||||
// Map semantic token paths to CSS variable names
|
||||
function getCssVarName(token) {
|
||||
const path = token.path;
|
||||
// color.semantic.X or color.dark.X → --X
|
||||
if (path[0] === 'color' && (path[1] === 'semantic' || path[1] === 'dark')) {
|
||||
const rest = path.slice(2);
|
||||
// Handle nested like chart.1, sidebar.background
|
||||
if (rest[0] === 'chart') return `--chart-${rest[1]}`;
|
||||
if (rest[0] === 'sidebar') {
|
||||
const subParts = rest.slice(1);
|
||||
if (subParts.length === 1 && subParts[0] === 'background') return '--sidebar';
|
||||
return `--sidebar-${subParts.join('-')}`;
|
||||
}
|
||||
return `--${rest.join('-')}`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const lines = [];
|
||||
dictionary.allTokens.forEach((token) => {
|
||||
const varName = getCssVarName(token);
|
||||
if (!varName) return;
|
||||
|
||||
const value = token.value || token.$value;
|
||||
const rgb = hexToRgb(value);
|
||||
if (rgb) {
|
||||
const desc = token.$description || token.description;
|
||||
if (desc) lines.push(` /* ${desc} */`);
|
||||
lines.push(` ${varName}: ${rgb};`);
|
||||
}
|
||||
});
|
||||
|
||||
return `${header}\n${selector} {\n${lines.join('\n')}\n}`;
|
||||
},
|
||||
});
|
||||
|
||||
// Custom format: TypeScript constants
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'typescript/constants',
|
||||
format: ({ dictionary }) => {
|
||||
const lines = [
|
||||
'// Auto-generated by Style Dictionary — DO NOT EDIT',
|
||||
'// Source: tokens/*.json (W3C DTCG format)',
|
||||
'',
|
||||
];
|
||||
|
||||
// Group tokens by top-level category
|
||||
const groups = {};
|
||||
dictionary.allTokens.forEach((token) => {
|
||||
const group = token.path[0];
|
||||
if (!groups[group]) groups[group] = [];
|
||||
groups[group].push(token);
|
||||
});
|
||||
|
||||
for (const [group, tokens] of Object.entries(groups)) {
|
||||
const constName = group.charAt(0).toUpperCase() + group.slice(1) + 'Tokens';
|
||||
lines.push(`export const ${constName} = {`);
|
||||
tokens.forEach((token) => {
|
||||
const key = token.path.slice(1).join('.');
|
||||
const value = token.value || token.$value;
|
||||
if (typeof value === 'string' || typeof value === 'number') {
|
||||
lines.push(` '${key}': '${value}',`);
|
||||
}
|
||||
});
|
||||
lines.push('} as const;');
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
},
|
||||
});
|
||||
|
||||
// Custom format: Markdown reference
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'markdown/reference',
|
||||
format: ({ dictionary }) => {
|
||||
const lines = [
|
||||
'# Greyhaven Design Tokens Reference',
|
||||
'',
|
||||
'> Auto-generated by Style Dictionary — DO NOT EDIT',
|
||||
'> Source: `tokens/*.json` (W3C DTCG format)',
|
||||
'',
|
||||
];
|
||||
|
||||
const groups = {};
|
||||
dictionary.allTokens.forEach((token) => {
|
||||
const group = token.path[0];
|
||||
if (!groups[group]) groups[group] = [];
|
||||
groups[group].push(token);
|
||||
});
|
||||
|
||||
for (const [group, tokens] of Object.entries(groups)) {
|
||||
lines.push(`## ${group.charAt(0).toUpperCase() + group.slice(1)}`);
|
||||
lines.push('');
|
||||
lines.push('| Token | Value | Description |');
|
||||
lines.push('|-------|-------|-------------|');
|
||||
tokens.forEach((token) => {
|
||||
const name = token.path.join('.');
|
||||
const value = token.value || token.$value;
|
||||
const desc = token.$description || token.description || '';
|
||||
const displayValue = typeof value === 'object' ? JSON.stringify(value) : value;
|
||||
lines.push(`| \`${name}\` | \`${displayValue}\` | ${desc} |`);
|
||||
});
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
},
|
||||
});
|
||||
|
||||
export default {
|
||||
source: ['tokens/**/*.json'],
|
||||
preprocessors: ['tokens-studio'],
|
||||
platforms: {
|
||||
// CSS custom properties for light theme (semantic tokens)
|
||||
cssLight: {
|
||||
transformGroup: 'css',
|
||||
buildPath: 'app/tokens/',
|
||||
files: [
|
||||
{
|
||||
destination: 'tokens-light.css',
|
||||
format: 'css/rgb-variables',
|
||||
filter: (token) => {
|
||||
return token.path[0] === 'color' && token.path[1] === 'semantic';
|
||||
},
|
||||
options: {
|
||||
selector: ':root',
|
||||
header: '/* Greyhaven Design Tokens — Light Theme\n Auto-generated by Style Dictionary — DO NOT EDIT\n Source: tokens/color.json */\n',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// CSS custom properties for dark theme
|
||||
cssDark: {
|
||||
transformGroup: 'css',
|
||||
buildPath: 'app/tokens/',
|
||||
files: [
|
||||
{
|
||||
destination: 'tokens-dark.css',
|
||||
format: 'css/rgb-variables',
|
||||
filter: (token) => {
|
||||
return token.path[0] === 'color' && token.path[1] === 'dark';
|
||||
},
|
||||
options: {
|
||||
selector: '.dark',
|
||||
header: '/* Greyhaven Design Tokens — Dark Theme\n Auto-generated by Style Dictionary — DO NOT EDIT\n Source: tokens/color.json */\n',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// TypeScript constants
|
||||
ts: {
|
||||
transformGroup: 'js',
|
||||
buildPath: 'app/tokens/',
|
||||
files: [
|
||||
{
|
||||
destination: 'tokens.ts',
|
||||
format: 'typescript/constants',
|
||||
},
|
||||
],
|
||||
},
|
||||
// Markdown reference
|
||||
docs: {
|
||||
transformGroup: 'css',
|
||||
buildPath: 'app/tokens/',
|
||||
files: [
|
||||
{
|
||||
destination: 'TOKENS.md',
|
||||
format: 'markdown/reference',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user