feat: funciones core frontend — generate_theme_css, get_computed_color, get_theme_tokens

Utilidades TypeScript puras para generación de CSS desde tema, resolución de colores computados y extracción de tokens del sistema de temas.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-03 03:23:38 +02:00
parent c5bb64160f
commit 40d6db312d
6 changed files with 270 additions and 0 deletions
@@ -0,0 +1,63 @@
---
name: generate_theme_css
kind: function
lang: ts
domain: core
version: "1.0.0"
purity: pure
signature: "generateThemeCss(colors: Record<string, string>, selector?: string): string"
description: "Genera un bloque CSS con variables de tema a partir de un objeto de tokens. Convierte claves camelCase a kebab-case automaticamente. Pura — solo transforma datos, no accede al DOM."
tags: [theme, css, generator, pure]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
tested: false
tests: []
test_file_path: ""
file_path: "frontend/functions/core/generate_theme_css.ts"
---
## Ejemplo
```typescript
import { generateThemeCss } from './generate_theme_css'
import { themeConfigToColors } from './theme_config_to_colors'
import { darkTheme } from '../ui/themes'
// Generar CSS para inyectar en <style>
const colors = themeConfigToColors(darkTheme)
const css = generateThemeCss(colors)
// Output:
// :root {
// --background: oklch(8% 0.015 260);
// --foreground: oklch(95% 0.01 260);
// --card: oklch(12% 0.015 260);
// --card-foreground: oklch(95% 0.01 260);
// ...
// }
// Inyectar en el documento
const style = document.createElement('style')
style.textContent = css
document.head.appendChild(style)
// Generar para selector especifico (dark mode)
const darkCss = generateThemeCss(colors, '.dark')
// Output: .dark { --background: oklch(...); ... }
// Generar para multiples selectores
const lightCss = generateThemeCss(lightColors, ':root')
const darkCss2 = generateThemeCss(darkColors, ':root.dark')
const combined = [lightCss, darkCss2].join('\n\n')
```
## Notas
Funcion pura — sin acceso al DOM, sin side effects. Util para SSR, generacion de archivos CSS estaticos, o pre-generar temas en build time.
La conversion camelCase → kebab-case es simple (reemplaza mayusculas con `-` + minuscula). No maneja casos especiales como `backgroundColor``background-color`; los tokens del registry ya usan nombres semanticos directos (`background`, `cardForeground`, etc.).
Compone naturalmente con `themeConfigToColors` del registry: `generateThemeCss(themeConfigToColors(config))`.
@@ -0,0 +1,23 @@
/**
* Genera un bloque CSS con variables de tema para inyectar como &lt;style&gt; o
* escribir en un archivo .css.
*
* Convierte claves camelCase a kebab-case automaticamente:
* `cardForeground` → `--card-foreground`
*
* @param colors - Objeto con tokens de tema. Claves en camelCase, valores CSS.
* @param selector - Selector CSS donde aplicar las variables. Por defecto `:root`.
* @returns String CSS con el bloque completo.
*/
export function generateThemeCss(
colors: Record<string, string>,
selector: string = ':root',
): string {
const lines = Object.entries(colors)
.map(([key, value]) => {
const cssName = key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)
return ` --${cssName}: ${value};`
})
.join('\n')
return `${selector} {\n${lines}\n}`
}
@@ -0,0 +1,49 @@
---
name: get_computed_color
kind: function
lang: ts
domain: core
version: "1.0.0"
purity: impure
signature: "getComputedColor(cssVar: string): string"
description: "Resuelve una CSS variable de color a su valor RGB computado por el browser. Acepta '--primary', 'primary' o 'var(--primary)'. Util para canvas, sigma.js y APIs que no soportan CSS variables."
tags: [theme, css, color, runtime, dom, canvas]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
tested: false
tests: []
test_file_path: ""
file_path: "frontend/functions/core/get_computed_color.ts"
---
## Ejemplo
```typescript
import { getComputedColor } from './get_computed_color'
// Todos estos formatos son equivalentes:
const color1 = getComputedColor('--primary') // "rgb(120, 80, 220)"
const color2 = getComputedColor('primary') // "rgb(120, 80, 220)"
const color3 = getComputedColor('var(--primary)') // "rgb(120, 80, 220)"
// Usar en canvas 2D
const ctx = canvas.getContext('2d')
ctx.fillStyle = getComputedColor('--background')
ctx.strokeStyle = getComputedColor('--border')
// Usar en sigma.js v2
renderer.setSetting('defaultNodeColor', getComputedColor('--primary'))
renderer.setSetting('defaultEdgeColor', getComputedColor('--muted'))
```
## Notas
Impura — muta el DOM temporalmente (append + remove) para forzar la resolucion del color. Solo disponible en browser.
El browser retorna el valor en formato `rgb(r, g, b)` o `rgba(r, g, b, a)`, no en el formato original de la CSS variable (oklch, hsl, etc.). Si necesitas el valor original sin resolver, usar `getThemeTokens` en su lugar.
Para multiples colores en un mismo render, llamar una vez y cachear los resultados — cada llamada hace un ciclo DOM.
@@ -0,0 +1,27 @@
/**
* Resuelve una CSS variable de color a su valor RGB computado por el browser.
*
* Acepta cualquiera de los formatos:
* - `"--primary"`
* - `"primary"` (sin prefijo --)
* - `"var(--primary)"`
*
* Retorna el valor en formato `rgb(r, g, b)` o `rgba(r, g, b, a)` segun
* como lo expanda el browser. Util para canvas, sigma.js y cualquier API
* que no soporte CSS variables directamente.
*/
export function getComputedColor(cssVar: string): string {
const name = cssVar.startsWith('var(')
? cssVar.slice(4, -1).trim()
: cssVar.startsWith('--')
? cssVar
: `--${cssVar}`
const el = document.createElement('div')
el.style.color = `var(${name})`
el.style.display = 'none'
document.body.appendChild(el)
const computed = getComputedStyle(el).color
document.body.removeChild(el)
return computed
}
@@ -0,0 +1,49 @@
---
name: get_theme_tokens
kind: function
lang: ts
domain: core
version: "1.0.0"
purity: impure
signature: "getThemeTokens(): ThemeTokens"
description: "Lee todas las CSS variables de tema del documento y devuelve un objeto tipado con los valores computados desde :root. Util para pasar colores a APIs que no entienden CSS variables (canvas, sigma.js, D3)."
tags: [theme, css, tokens, runtime, dom]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
tested: false
tests: []
test_file_path: ""
file_path: "frontend/functions/core/get_theme_tokens.ts"
---
## Ejemplo
```typescript
import { getThemeTokens } from './get_theme_tokens'
const tokens = getThemeTokens()
// Pasar colores a sigma.js (que no soporta CSS variables)
const sigmaSettings = {
defaultNodeColor: tokens.primary,
defaultEdgeColor: tokens.muted,
labelColor: { color: tokens.foreground },
}
// Pasar colores a un canvas 2D
const ctx = canvas.getContext('2d')
ctx.fillStyle = tokens.background
ctx.strokeStyle = tokens.border
```
## Notas
Impura — accede a `document.documentElement` y `getComputedStyle`. Solo disponible en browser.
Los valores retornados son los valores sin procesar de las CSS variables (ej: `oklch(8% 0.015 260)`). Para obtener valores RGB computed (necesarios para algunas APIs), usar `getComputedColor`.
Funciona con cualquier tema activo: el resultado cambia automaticamente cuando se cambia el tema via `applyTheme`.
@@ -0,0 +1,59 @@
/** Tokens de tema leidos de las CSS variables activas en :root. */
export interface ThemeTokens {
background: string
foreground: string
card: string
cardForeground: string
popover: string
popoverForeground: string
primary: string
primaryForeground: string
secondary: string
secondaryForeground: string
muted: string
mutedForeground: string
accent: string
accentForeground: string
destructive: string
destructiveForeground: string
success: string
successForeground: string
border: string
input: string
ring: string
}
/**
* Lee todas las CSS variables de tema del documento y devuelve un objeto
* tipado con los valores computados desde :root.
*
* Util para pasar colores a APIs que no entienden CSS variables
* (canvas, sigma.js, D3, etc.).
*/
export function getThemeTokens(): ThemeTokens {
const style = getComputedStyle(document.documentElement)
const get = (name: string) => style.getPropertyValue(`--${name}`).trim()
return {
background: get('background'),
foreground: get('foreground'),
card: get('card'),
cardForeground: get('card-foreground'),
popover: get('popover'),
popoverForeground: get('popover-foreground'),
primary: get('primary'),
primaryForeground: get('primary-foreground'),
secondary: get('secondary'),
secondaryForeground: get('secondary-foreground'),
muted: get('muted'),
mutedForeground: get('muted-foreground'),
accent: get('accent'),
accentForeground: get('accent-foreground'),
destructive: get('destructive'),
destructiveForeground: get('destructive-foreground'),
success: get('success'),
successForeground: get('success-foreground'),
border: get('border'),
input: get('input'),
ring: get('ring'),
}
}