Ajoute le pipeline PageSpec (validation, rendu, publication /p/{slug}),
les démos TipTap /demo, et le simulateur Carnot (modes frigo/PAC/moteur,
énergie kJ vs puissance W, unités K/°C/°F) avec correctifs d’équations KaTeX.
Co-authored-by: Cursor <cursoragent@cursor.com>
63 lines
1.7 KiB
TypeScript
63 lines
1.7 KiB
TypeScript
import type { IntentId } from '@/lib/interactive-demo/types'
|
||
|
||
/**
|
||
* Desaturated palette — one set for light, one for dark (P11).
|
||
* No free hex in demo JSON; app maps intents here.
|
||
*/
|
||
export const INTENT_PALETTE_LIGHT: Record<IntentId | 'neutral', string> = {
|
||
neutral: '#5c5c5c',
|
||
highlight: '#5a7a9a', // prune / slate-blue
|
||
flow: '#4a7d68',
|
||
cache: '#7a6a8a',
|
||
compute: '#8a6b4a',
|
||
output: '#4a7a8a',
|
||
warning: '#9a6548',
|
||
}
|
||
|
||
export const INTENT_PALETTE_DARK: Record<IntentId | 'neutral', string> = {
|
||
neutral: '#a8a8a8',
|
||
highlight: '#8aabca',
|
||
flow: '#7ab89a',
|
||
cache: '#a898b8',
|
||
compute: '#c0a080',
|
||
output: '#7ab0c0',
|
||
warning: '#d09070',
|
||
}
|
||
|
||
/** Light: ~35% readable on white; dark: ~20% as spec. */
|
||
export const DIM_OPACITY_LIGHT = 0.35
|
||
export const DIM_OPACITY_DARK = 0.2
|
||
|
||
export function intentColor(
|
||
intent: IntentId | null | undefined,
|
||
dark: boolean
|
||
): string {
|
||
const palette = dark ? INTENT_PALETTE_DARK : INTENT_PALETTE_LIGHT
|
||
if (!intent) return palette.neutral
|
||
return palette[intent] ?? palette.neutral
|
||
}
|
||
|
||
export function spotlightColor(dark: boolean): string {
|
||
return intentColor('highlight', dark)
|
||
}
|
||
|
||
export function dimOpacity(dark: boolean): number {
|
||
return dark ? DIM_OPACITY_DARK : DIM_OPACITY_LIGHT
|
||
}
|
||
|
||
export const CIRCLED_NUMBERS = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩'] as const
|
||
|
||
export function badgeGlyph(index: number): string {
|
||
if (index >= 1 && index <= CIRCLED_NUMBERS.length) {
|
||
return CIRCLED_NUMBERS[index - 1]!
|
||
}
|
||
return String(index)
|
||
}
|
||
|
||
/** Writing rule for generation prompts (not enforced in renderer). */
|
||
export const SPEAK_WRITING_GUIDE = {
|
||
maxWordsApprox: 25,
|
||
sentences: '1–2',
|
||
note: 'Demo tempo is decided at writing time, not at render.',
|
||
} as const
|