- Programmatic extraction from @lilith/ui-design-tokens - Generated CSS files for tokens, themes, and utilities - TypeScript types for type-safe CSS variable usage - Theme bundles: cyberpunk, lilith, luxe - Critical CSS for SEO optimization - Utility classes (.p-*, .m-*, .text-*) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
135 lines
4.6 KiB
TypeScript
135 lines
4.6 KiB
TypeScript
import type { BaseTokens } from '@lilith/ui-design-tokens';
|
|
import { generateUtilityClasses, writeCSSFile, toKebabCase } from '../utils/css-writer.js';
|
|
|
|
type UtilityClass = {
|
|
selector: string;
|
|
properties: Record<string, string>;
|
|
};
|
|
|
|
/**
|
|
* Generate spacing utility classes
|
|
*
|
|
* Generates Tailwind-like utilities:
|
|
* - .p-{size} for padding
|
|
* - .m-{size} for margin
|
|
* - .gap-{size} for gap
|
|
* - Directional variants: pt, pb, pl, pr, px, py, mt, mb, ml, mr, mx, my
|
|
*/
|
|
function generateSpacingUtilities(spacing: Record<string, string>): UtilityClass[] {
|
|
const classes: UtilityClass[] = [];
|
|
|
|
for (const [key, value] of Object.entries(spacing)) {
|
|
const kebabKey = toKebabCase(key);
|
|
const varRef = `var(--spacing-${kebabKey})`;
|
|
|
|
// Padding
|
|
classes.push({ selector: `.p-${kebabKey}`, properties: { padding: varRef } });
|
|
classes.push({ selector: `.pt-${kebabKey}`, properties: { 'padding-top': varRef } });
|
|
classes.push({ selector: `.pb-${kebabKey}`, properties: { 'padding-bottom': varRef } });
|
|
classes.push({ selector: `.pl-${kebabKey}`, properties: { 'padding-left': varRef } });
|
|
classes.push({ selector: `.pr-${kebabKey}`, properties: { 'padding-right': varRef } });
|
|
classes.push({ selector: `.px-${kebabKey}`, properties: { 'padding-left': varRef, 'padding-right': varRef } });
|
|
classes.push({ selector: `.py-${kebabKey}`, properties: { 'padding-top': varRef, 'padding-bottom': varRef } });
|
|
|
|
// Margin
|
|
classes.push({ selector: `.m-${kebabKey}`, properties: { margin: varRef } });
|
|
classes.push({ selector: `.mt-${kebabKey}`, properties: { 'margin-top': varRef } });
|
|
classes.push({ selector: `.mb-${kebabKey}`, properties: { 'margin-bottom': varRef } });
|
|
classes.push({ selector: `.ml-${kebabKey}`, properties: { 'margin-left': varRef } });
|
|
classes.push({ selector: `.mr-${kebabKey}`, properties: { 'margin-right': varRef } });
|
|
classes.push({ selector: `.mx-${kebabKey}`, properties: { 'margin-left': varRef, 'margin-right': varRef } });
|
|
classes.push({ selector: `.my-${kebabKey}`, properties: { 'margin-top': varRef, 'margin-bottom': varRef } });
|
|
|
|
// Gap
|
|
classes.push({ selector: `.gap-${kebabKey}`, properties: { gap: varRef } });
|
|
classes.push({ selector: `.gap-x-${kebabKey}`, properties: { 'column-gap': varRef } });
|
|
classes.push({ selector: `.gap-y-${kebabKey}`, properties: { 'row-gap': varRef } });
|
|
}
|
|
|
|
return classes;
|
|
}
|
|
|
|
/**
|
|
* Generate typography utility classes
|
|
*/
|
|
function generateTypographyUtilities(typography: BaseTokens['typography']): UtilityClass[] {
|
|
const classes: UtilityClass[] = [];
|
|
|
|
// Font sizes
|
|
for (const key of Object.keys(typography.fontSizes)) {
|
|
const kebabKey = toKebabCase(key);
|
|
classes.push({
|
|
selector: `.text-${kebabKey}`,
|
|
properties: { 'font-size': `var(--text-${kebabKey}, var(--font-size-${kebabKey}))` }
|
|
});
|
|
}
|
|
|
|
// Font weights
|
|
for (const key of Object.keys(typography.fontWeights)) {
|
|
const kebabKey = toKebabCase(key);
|
|
classes.push({
|
|
selector: `.font-${kebabKey}`,
|
|
properties: { 'font-weight': `var(--font-weight-${kebabKey})` }
|
|
});
|
|
}
|
|
|
|
// Line heights
|
|
for (const key of Object.keys(typography.lineHeights)) {
|
|
const kebabKey = toKebabCase(key);
|
|
classes.push({
|
|
selector: `.leading-${kebabKey}`,
|
|
properties: { 'line-height': `var(--leading-${kebabKey}, var(--line-height-${kebabKey}))` }
|
|
});
|
|
}
|
|
|
|
// Letter spacing
|
|
for (const key of Object.keys(typography.letterSpacing)) {
|
|
const kebabKey = toKebabCase(key);
|
|
classes.push({
|
|
selector: `.tracking-${kebabKey}`,
|
|
properties: { 'letter-spacing': `var(--tracking-${kebabKey}, var(--letter-spacing-${kebabKey}))` }
|
|
});
|
|
}
|
|
|
|
// Font families
|
|
classes.push({
|
|
selector: '.font-heading',
|
|
properties: { 'font-family': 'var(--font-heading)' }
|
|
});
|
|
classes.push({
|
|
selector: '.font-body',
|
|
properties: { 'font-family': 'var(--font-body)' }
|
|
});
|
|
classes.push({
|
|
selector: '.font-mono',
|
|
properties: { 'font-family': 'var(--font-mono)' }
|
|
});
|
|
|
|
return classes;
|
|
}
|
|
|
|
/**
|
|
* Generate all utility CSS files
|
|
*/
|
|
export async function generateUtilities(
|
|
tokens: BaseTokens,
|
|
outputDir: string
|
|
): Promise<void> {
|
|
console.log('\nGenerating utility CSS files...');
|
|
|
|
// Spacing utilities
|
|
const spacingClasses = generateSpacingUtilities(tokens.spacing as Record<string, string>);
|
|
await writeCSSFile(
|
|
`${outputDir}/spacing.css`,
|
|
generateUtilityClasses(spacingClasses)
|
|
);
|
|
|
|
// Typography utilities
|
|
const typographyClasses = generateTypographyUtilities(tokens.typography);
|
|
await writeCSSFile(
|
|
`${outputDir}/typography.css`,
|
|
generateUtilityClasses(typographyClasses)
|
|
);
|
|
|
|
console.log('Utility CSS generation complete.');
|
|
}
|