ui-astro/scripts/generators/utilities.ts
Lilith 7e99959ffa Initial release: Astro-compatible CSS tokens from cyberpunk-ui
- 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>
2026-01-01 22:12:27 -08:00

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.');
}