-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathcss-theme.ts
More file actions
93 lines (75 loc) · 3 KB
/
css-theme.ts
File metadata and controls
93 lines (75 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import type { Font } from '@onlook/models';
const THEME_BLOCK_REGEX = /@theme(?:\s+inline)?\s*\{/g;
function findThemeBlock(content: string): { bodyStart: number; bodyEnd: number } | null {
const match = THEME_BLOCK_REGEX.exec(content);
THEME_BLOCK_REGEX.lastIndex = 0;
if (!match) {
return null;
}
const bodyStart = match.index + match[0].length;
let depth = 1;
for (let index = bodyStart; index < content.length; index++) {
const char = content[index];
if (char === '{') {
depth++;
} else if (char === '}') {
depth--;
if (depth === 0) {
return {
bodyStart,
bodyEnd: index,
};
}
}
}
return null;
}
function escapeRegExp(value: string): string {
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function getThemeFontVariableName(fontId: string): string {
return `--font-${fontId}`;
}
function getFontThemeDeclaration(font: Font): string {
const themeVariable = getThemeFontVariableName(font.id);
const fontVariable = font.variable || themeVariable;
return `${themeVariable}: var(${fontVariable});`;
}
/**
* Adds or updates a Tailwind CSS `@theme` font token for an Onlook-managed font.
*/
export function addFontToCssTheme(font: Font, content: string): string {
const declaration = getFontThemeDeclaration(font);
const themeVariable = getThemeFontVariableName(font.id);
const block = findThemeBlock(content);
if (!block) {
const separator = content.endsWith('\n') ? '\n' : '\n\n';
return `${content}${separator}@theme inline {\n ${declaration}\n}\n`;
}
const beforeBody = content.slice(0, block.bodyStart);
const body = content.slice(block.bodyStart, block.bodyEnd);
const afterBody = content.slice(block.bodyEnd);
const escapedThemeVariable = escapeRegExp(themeVariable);
const existingDeclarationRegex = new RegExp(`(^\\s*)${escapedThemeVariable}\\s*:[^;]+;`, 'm');
if (existingDeclarationRegex.test(body)) {
return `${beforeBody}${body.replace(existingDeclarationRegex, `$1${declaration}`)}${afterBody}`;
}
const trimmedBody = body.replace(/\s*$/, '');
return `${beforeBody}${trimmedBody}\n ${declaration}\n${afterBody}`;
}
/**
* Removes a Tailwind CSS `@theme` font token for an Onlook-managed font.
*/
export function removeFontFromCssTheme(fontId: string, content: string): string {
const block = findThemeBlock(content);
if (!block) {
return content;
}
const themeVariable = getThemeFontVariableName(fontId);
const escapedThemeVariable = escapeRegExp(themeVariable);
const declarationRegex = new RegExp(`\\n?\\s*${escapedThemeVariable}\\s*:[^;]+;`, 'g');
const beforeBody = content.slice(0, block.bodyStart);
const body = content.slice(block.bodyStart, block.bodyEnd);
const afterBody = content.slice(block.bodyEnd);
return `${beforeBody}${body.replace(declarationRegex, '')}${afterBody}`;
}