juxscript 1.1.57 → 1.1.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/utils/codeparser.d.ts.map +1 -1
- package/lib/utils/codeparser.js +164 -8
- package/lib/utils/codeparser.ts +175 -8
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codeparser.d.ts","sourceRoot":"","sources":["codeparser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"codeparser.d.ts","sourceRoot":"","sources":["codeparser.ts"],"names":[],"mappings":"AA2DA,MAAM,WAAW,UAAU;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOxC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAqB,GAAG,UAAU,EAAE,CAQrF;AAiLD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAEnE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAkG9C;;;;;;;AAED,wBAKE"}
|
package/lib/utils/codeparser.js
CHANGED
|
@@ -12,6 +12,43 @@ const KEYWORDS = new Set([
|
|
|
12
12
|
'!=', '!==', '+', '-', '*', '/', '%', '++', '--', '&&', '||', '!', '<', '>',
|
|
13
13
|
'<=', '>=', '=>', '...', '.', ',', '(', ')', '{', '}', '[', ']', ':', '?'
|
|
14
14
|
]);
|
|
15
|
+
/**
|
|
16
|
+
* Categorized token sets for semantic highlighting
|
|
17
|
+
*/
|
|
18
|
+
// Control flow keywords (loops, conditionals, etc.)
|
|
19
|
+
const CONTROL_FLOW = new Set([
|
|
20
|
+
'if', 'else', 'switch', 'case', 'default',
|
|
21
|
+
'for', 'while', 'do', 'break', 'continue',
|
|
22
|
+
'return', 'throw', 'try', 'catch', 'finally'
|
|
23
|
+
]);
|
|
24
|
+
// Declaration keywords
|
|
25
|
+
const DECLARATIONS = new Set([
|
|
26
|
+
'const', 'let', 'var', 'function', 'class',
|
|
27
|
+
'import', 'export', 'from', 'as',
|
|
28
|
+
'interface', 'type', 'enum', 'namespace',
|
|
29
|
+
'static', 'get', 'set', 'extends'
|
|
30
|
+
]);
|
|
31
|
+
// Operator keywords
|
|
32
|
+
const OPERATORS = new Set([
|
|
33
|
+
'new', 'delete', 'typeof', 'instanceof',
|
|
34
|
+
'void', 'await', 'yield', 'in', 'of'
|
|
35
|
+
]);
|
|
36
|
+
// Special keywords
|
|
37
|
+
const SPECIAL = new Set([
|
|
38
|
+
'this', 'super', 'async', 'debugger', 'with'
|
|
39
|
+
]);
|
|
40
|
+
// JUX-specific keywords
|
|
41
|
+
const JUX_KEYWORDS = new Set([
|
|
42
|
+
'jux', 'state', 'registry', 'render', 'bind', 'sync'
|
|
43
|
+
]);
|
|
44
|
+
// Combine all keywords for quick lookup
|
|
45
|
+
const ALL_KEYWORDS = new Set([
|
|
46
|
+
...CONTROL_FLOW,
|
|
47
|
+
...DECLARATIONS,
|
|
48
|
+
...OPERATORS,
|
|
49
|
+
...SPECIAL,
|
|
50
|
+
...JUX_KEYWORDS
|
|
51
|
+
]);
|
|
15
52
|
/**
|
|
16
53
|
* Escape HTML entities
|
|
17
54
|
*/
|
|
@@ -35,7 +72,41 @@ export function parseCode(code, language = 'javascript') {
|
|
|
35
72
|
}));
|
|
36
73
|
}
|
|
37
74
|
/**
|
|
38
|
-
*
|
|
75
|
+
* Get the appropriate CSS class for a keyword
|
|
76
|
+
*/
|
|
77
|
+
function getKeywordClass(word) {
|
|
78
|
+
if (CONTROL_FLOW.has(word))
|
|
79
|
+
return 'token-control';
|
|
80
|
+
if (DECLARATIONS.has(word))
|
|
81
|
+
return 'token-declaration';
|
|
82
|
+
if (OPERATORS.has(word))
|
|
83
|
+
return 'token-operator-keyword';
|
|
84
|
+
if (SPECIAL.has(word))
|
|
85
|
+
return 'token-special';
|
|
86
|
+
if (JUX_KEYWORDS.has(word))
|
|
87
|
+
return 'token-jux';
|
|
88
|
+
return 'token-keyword'; // fallback
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Check if character is a structural punctuation (braces, brackets, parens)
|
|
92
|
+
*/
|
|
93
|
+
function isStructural(char) {
|
|
94
|
+
return '(){}[]'.includes(char);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Check if character is a delimiter (semicolon, comma, colon)
|
|
98
|
+
*/
|
|
99
|
+
function isDelimiter(char) {
|
|
100
|
+
return ';,:'.includes(char);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Check if character is an operator
|
|
104
|
+
*/
|
|
105
|
+
function isOperator(char) {
|
|
106
|
+
return '+-*/%=<>!&|^~?'.includes(char);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Tokenize a single line character-by-character with semantic categories
|
|
39
110
|
*/
|
|
40
111
|
function tokenizeLine(line) {
|
|
41
112
|
if (!line.trim())
|
|
@@ -43,6 +114,10 @@ function tokenizeLine(line) {
|
|
|
43
114
|
let result = '';
|
|
44
115
|
let i = 0;
|
|
45
116
|
const len = line.length;
|
|
117
|
+
// Check for comment at start
|
|
118
|
+
if (line.trim().startsWith('//')) {
|
|
119
|
+
return `<span class="token-comment">${escapeHtml(line)}</span>`;
|
|
120
|
+
}
|
|
46
121
|
while (i < len) {
|
|
47
122
|
const char = line[i];
|
|
48
123
|
// Whitespace - preserve
|
|
@@ -51,12 +126,42 @@ function tokenizeLine(line) {
|
|
|
51
126
|
i++;
|
|
52
127
|
continue;
|
|
53
128
|
}
|
|
129
|
+
// Comment (// or /* */)
|
|
130
|
+
if (char === '/' && i + 1 < len) {
|
|
131
|
+
if (line[i + 1] === '/') {
|
|
132
|
+
// Line comment - consume rest of line
|
|
133
|
+
const comment = line.slice(i);
|
|
134
|
+
result += `<span class="token-comment">${escapeHtml(comment)}</span>`;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
else if (line[i + 1] === '*') {
|
|
138
|
+
// Block comment start
|
|
139
|
+
const commentEnd = line.indexOf('*/', i + 2);
|
|
140
|
+
if (commentEnd !== -1) {
|
|
141
|
+
const comment = line.slice(i, commentEnd + 2);
|
|
142
|
+
result += `<span class="token-comment">${escapeHtml(comment)}</span>`;
|
|
143
|
+
i = commentEnd + 2;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// String literals (single, double, backtick)
|
|
149
|
+
if (char === '"' || char === "'" || char === '`') {
|
|
150
|
+
const stringEnd = line.indexOf(char, i + 1);
|
|
151
|
+
if (stringEnd !== -1) {
|
|
152
|
+
const str = line.slice(i, stringEnd + 1);
|
|
153
|
+
result += `<span class="token-string">${escapeHtml(str)}</span>`;
|
|
154
|
+
i = stringEnd + 1;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
54
158
|
// Word (identifier or keyword)
|
|
55
159
|
if (/[a-zA-Z_$]/.test(char)) {
|
|
56
160
|
const word = consumeWord(line, i);
|
|
57
161
|
const escaped = escapeHtml(word);
|
|
58
|
-
if (
|
|
59
|
-
|
|
162
|
+
if (ALL_KEYWORDS.has(word)) {
|
|
163
|
+
const tokenClass = getKeywordClass(word);
|
|
164
|
+
result += `<span class="${tokenClass}">${escaped}</span>`;
|
|
60
165
|
}
|
|
61
166
|
else {
|
|
62
167
|
result += escaped;
|
|
@@ -71,6 +176,24 @@ function tokenizeLine(line) {
|
|
|
71
176
|
i += num.length;
|
|
72
177
|
continue;
|
|
73
178
|
}
|
|
179
|
+
// Structural punctuation (braces, brackets, parens)
|
|
180
|
+
if (isStructural(char)) {
|
|
181
|
+
result += `<span class="token-structural">${escapeHtml(char)}</span>`;
|
|
182
|
+
i++;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
// Delimiters (semicolon, comma, colon)
|
|
186
|
+
if (isDelimiter(char)) {
|
|
187
|
+
result += `<span class="token-delimiter">${escapeHtml(char)}</span>`;
|
|
188
|
+
i++;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
// Operators
|
|
192
|
+
if (isOperator(char)) {
|
|
193
|
+
result += `<span class="token-operator">${escapeHtml(char)}</span>`;
|
|
194
|
+
i++;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
74
197
|
// Everything else - just escape and append
|
|
75
198
|
result += escapeHtml(char);
|
|
76
199
|
i++;
|
|
@@ -119,7 +242,7 @@ export function renderLineWithTokens(parsedLine) {
|
|
|
119
242
|
*/
|
|
120
243
|
export function getSyntaxHighlightCSS() {
|
|
121
244
|
return `
|
|
122
|
-
/*
|
|
245
|
+
/* Semantic Code Highlighting */
|
|
123
246
|
.jux-code {
|
|
124
247
|
font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;
|
|
125
248
|
font-size: 14px;
|
|
@@ -173,13 +296,46 @@ export function getSyntaxHighlightCSS() {
|
|
|
173
296
|
display: none;
|
|
174
297
|
}
|
|
175
298
|
|
|
176
|
-
/* Token colors */
|
|
177
|
-
.token-
|
|
178
|
-
color: #c678dd;
|
|
299
|
+
/* Token colors - Semantic categories */
|
|
300
|
+
.token-control {
|
|
301
|
+
color: #c678dd; /* Purple - control flow (if, for, return) */
|
|
179
302
|
font-weight: 600;
|
|
180
303
|
}
|
|
304
|
+
.token-declaration {
|
|
305
|
+
color: #61afef; /* Blue - declarations (const, let, function) */
|
|
306
|
+
font-weight: 600;
|
|
307
|
+
}
|
|
308
|
+
.token-operator-keyword {
|
|
309
|
+
color: #e06c75; /* Red - operator keywords (typeof, instanceof) */
|
|
310
|
+
font-weight: 600;
|
|
311
|
+
}
|
|
312
|
+
.token-special {
|
|
313
|
+
color: #e5c07b; /* Yellow - special keywords (this, super, async) */
|
|
314
|
+
font-weight: 600;
|
|
315
|
+
}
|
|
316
|
+
.token-jux {
|
|
317
|
+
color: #56b6c2; /* Cyan - JUX-specific (jux, state, render) */
|
|
318
|
+
font-weight: 700;
|
|
319
|
+
}
|
|
181
320
|
.token-number {
|
|
182
|
-
color: #d19a66;
|
|
321
|
+
color: #d19a66; /* Orange - numbers */
|
|
322
|
+
}
|
|
323
|
+
.token-string {
|
|
324
|
+
color: #98c379; /* Green - strings */
|
|
325
|
+
}
|
|
326
|
+
.token-comment {
|
|
327
|
+
color: #5c6370; /* Gray - comments */
|
|
328
|
+
font-style: italic;
|
|
329
|
+
}
|
|
330
|
+
.token-structural {
|
|
331
|
+
color: #abb2bf; /* Light gray - braces, brackets, parens */
|
|
332
|
+
font-weight: 600;
|
|
333
|
+
}
|
|
334
|
+
.token-delimiter {
|
|
335
|
+
color: #777; /* Dark gray - semicolons, commas, colons */
|
|
336
|
+
}
|
|
337
|
+
.token-operator {
|
|
338
|
+
color: #56b6c2; /* Cyan - operators (+, -, *, etc.) */
|
|
183
339
|
}
|
|
184
340
|
`;
|
|
185
341
|
}
|
package/lib/utils/codeparser.ts
CHANGED
|
@@ -13,6 +13,50 @@ const KEYWORDS = new Set([
|
|
|
13
13
|
'<=', '>=', '=>', '...', '.', ',', '(', ')', '{', '}', '[', ']', ':', '?'
|
|
14
14
|
]);
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Categorized token sets for semantic highlighting
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
// Control flow keywords (loops, conditionals, etc.)
|
|
21
|
+
const CONTROL_FLOW = new Set([
|
|
22
|
+
'if', 'else', 'switch', 'case', 'default',
|
|
23
|
+
'for', 'while', 'do', 'break', 'continue',
|
|
24
|
+
'return', 'throw', 'try', 'catch', 'finally'
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
// Declaration keywords
|
|
28
|
+
const DECLARATIONS = new Set([
|
|
29
|
+
'const', 'let', 'var', 'function', 'class',
|
|
30
|
+
'import', 'export', 'from', 'as',
|
|
31
|
+
'interface', 'type', 'enum', 'namespace',
|
|
32
|
+
'static', 'get', 'set', 'extends'
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
// Operator keywords
|
|
36
|
+
const OPERATORS = new Set([
|
|
37
|
+
'new', 'delete', 'typeof', 'instanceof',
|
|
38
|
+
'void', 'await', 'yield', 'in', 'of'
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
// Special keywords
|
|
42
|
+
const SPECIAL = new Set([
|
|
43
|
+
'this', 'super', 'async', 'debugger', 'with'
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
// JUX-specific keywords
|
|
47
|
+
const JUX_KEYWORDS = new Set([
|
|
48
|
+
'jux', 'state', 'registry', 'render', 'bind', 'sync'
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
// Combine all keywords for quick lookup
|
|
52
|
+
const ALL_KEYWORDS = new Set([
|
|
53
|
+
...CONTROL_FLOW,
|
|
54
|
+
...DECLARATIONS,
|
|
55
|
+
...OPERATORS,
|
|
56
|
+
...SPECIAL,
|
|
57
|
+
...JUX_KEYWORDS
|
|
58
|
+
]);
|
|
59
|
+
|
|
16
60
|
export interface ParsedLine {
|
|
17
61
|
lineNumber: number;
|
|
18
62
|
html: string;
|
|
@@ -45,7 +89,40 @@ export function parseCode(code: string, language: string = 'javascript'): Parsed
|
|
|
45
89
|
}
|
|
46
90
|
|
|
47
91
|
/**
|
|
48
|
-
*
|
|
92
|
+
* Get the appropriate CSS class for a keyword
|
|
93
|
+
*/
|
|
94
|
+
function getKeywordClass(word: string): string {
|
|
95
|
+
if (CONTROL_FLOW.has(word)) return 'token-control';
|
|
96
|
+
if (DECLARATIONS.has(word)) return 'token-declaration';
|
|
97
|
+
if (OPERATORS.has(word)) return 'token-operator-keyword';
|
|
98
|
+
if (SPECIAL.has(word)) return 'token-special';
|
|
99
|
+
if (JUX_KEYWORDS.has(word)) return 'token-jux';
|
|
100
|
+
return 'token-keyword'; // fallback
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if character is a structural punctuation (braces, brackets, parens)
|
|
105
|
+
*/
|
|
106
|
+
function isStructural(char: string): boolean {
|
|
107
|
+
return '(){}[]'.includes(char);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Check if character is a delimiter (semicolon, comma, colon)
|
|
112
|
+
*/
|
|
113
|
+
function isDelimiter(char: string): boolean {
|
|
114
|
+
return ';,:'.includes(char);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check if character is an operator
|
|
119
|
+
*/
|
|
120
|
+
function isOperator(char: string): boolean {
|
|
121
|
+
return '+-*/%=<>!&|^~?'.includes(char);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Tokenize a single line character-by-character with semantic categories
|
|
49
126
|
*/
|
|
50
127
|
function tokenizeLine(line: string): string {
|
|
51
128
|
if (!line.trim()) return ' ';
|
|
@@ -54,6 +131,11 @@ function tokenizeLine(line: string): string {
|
|
|
54
131
|
let i = 0;
|
|
55
132
|
const len = line.length;
|
|
56
133
|
|
|
134
|
+
// Check for comment at start
|
|
135
|
+
if (line.trim().startsWith('//')) {
|
|
136
|
+
return `<span class="token-comment">${escapeHtml(line)}</span>`;
|
|
137
|
+
}
|
|
138
|
+
|
|
57
139
|
while (i < len) {
|
|
58
140
|
const char = line[i];
|
|
59
141
|
|
|
@@ -64,13 +146,44 @@ function tokenizeLine(line: string): string {
|
|
|
64
146
|
continue;
|
|
65
147
|
}
|
|
66
148
|
|
|
149
|
+
// Comment (// or /* */)
|
|
150
|
+
if (char === '/' && i + 1 < len) {
|
|
151
|
+
if (line[i + 1] === '/') {
|
|
152
|
+
// Line comment - consume rest of line
|
|
153
|
+
const comment = line.slice(i);
|
|
154
|
+
result += `<span class="token-comment">${escapeHtml(comment)}</span>`;
|
|
155
|
+
break;
|
|
156
|
+
} else if (line[i + 1] === '*') {
|
|
157
|
+
// Block comment start
|
|
158
|
+
const commentEnd = line.indexOf('*/', i + 2);
|
|
159
|
+
if (commentEnd !== -1) {
|
|
160
|
+
const comment = line.slice(i, commentEnd + 2);
|
|
161
|
+
result += `<span class="token-comment">${escapeHtml(comment)}</span>`;
|
|
162
|
+
i = commentEnd + 2;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// String literals (single, double, backtick)
|
|
169
|
+
if (char === '"' || char === "'" || char === '`') {
|
|
170
|
+
const stringEnd = line.indexOf(char, i + 1);
|
|
171
|
+
if (stringEnd !== -1) {
|
|
172
|
+
const str = line.slice(i, stringEnd + 1);
|
|
173
|
+
result += `<span class="token-string">${escapeHtml(str)}</span>`;
|
|
174
|
+
i = stringEnd + 1;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
67
179
|
// Word (identifier or keyword)
|
|
68
180
|
if (/[a-zA-Z_$]/.test(char)) {
|
|
69
181
|
const word = consumeWord(line, i);
|
|
70
182
|
const escaped = escapeHtml(word);
|
|
71
183
|
|
|
72
|
-
if (
|
|
73
|
-
|
|
184
|
+
if (ALL_KEYWORDS.has(word)) {
|
|
185
|
+
const tokenClass = getKeywordClass(word);
|
|
186
|
+
result += `<span class="${tokenClass}">${escaped}</span>`;
|
|
74
187
|
} else {
|
|
75
188
|
result += escaped;
|
|
76
189
|
}
|
|
@@ -87,6 +200,27 @@ function tokenizeLine(line: string): string {
|
|
|
87
200
|
continue;
|
|
88
201
|
}
|
|
89
202
|
|
|
203
|
+
// Structural punctuation (braces, brackets, parens)
|
|
204
|
+
if (isStructural(char)) {
|
|
205
|
+
result += `<span class="token-structural">${escapeHtml(char)}</span>`;
|
|
206
|
+
i++;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Delimiters (semicolon, comma, colon)
|
|
211
|
+
if (isDelimiter(char)) {
|
|
212
|
+
result += `<span class="token-delimiter">${escapeHtml(char)}</span>`;
|
|
213
|
+
i++;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Operators
|
|
218
|
+
if (isOperator(char)) {
|
|
219
|
+
result += `<span class="token-operator">${escapeHtml(char)}</span>`;
|
|
220
|
+
i++;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
90
224
|
// Everything else - just escape and append
|
|
91
225
|
result += escapeHtml(char);
|
|
92
226
|
i++;
|
|
@@ -141,7 +275,7 @@ export function renderLineWithTokens(parsedLine: ParsedLine): string {
|
|
|
141
275
|
*/
|
|
142
276
|
export function getSyntaxHighlightCSS(): string {
|
|
143
277
|
return `
|
|
144
|
-
/*
|
|
278
|
+
/* Semantic Code Highlighting */
|
|
145
279
|
.jux-code {
|
|
146
280
|
font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;
|
|
147
281
|
font-size: 14px;
|
|
@@ -195,13 +329,46 @@ export function getSyntaxHighlightCSS(): string {
|
|
|
195
329
|
display: none;
|
|
196
330
|
}
|
|
197
331
|
|
|
198
|
-
/* Token colors */
|
|
199
|
-
.token-
|
|
200
|
-
color: #c678dd;
|
|
332
|
+
/* Token colors - Semantic categories */
|
|
333
|
+
.token-control {
|
|
334
|
+
color: #c678dd; /* Purple - control flow (if, for, return) */
|
|
335
|
+
font-weight: 600;
|
|
336
|
+
}
|
|
337
|
+
.token-declaration {
|
|
338
|
+
color: #61afef; /* Blue - declarations (const, let, function) */
|
|
339
|
+
font-weight: 600;
|
|
340
|
+
}
|
|
341
|
+
.token-operator-keyword {
|
|
342
|
+
color: #e06c75; /* Red - operator keywords (typeof, instanceof) */
|
|
201
343
|
font-weight: 600;
|
|
202
344
|
}
|
|
345
|
+
.token-special {
|
|
346
|
+
color: #e5c07b; /* Yellow - special keywords (this, super, async) */
|
|
347
|
+
font-weight: 600;
|
|
348
|
+
}
|
|
349
|
+
.token-jux {
|
|
350
|
+
color: #56b6c2; /* Cyan - JUX-specific (jux, state, render) */
|
|
351
|
+
font-weight: 700;
|
|
352
|
+
}
|
|
203
353
|
.token-number {
|
|
204
|
-
color: #d19a66;
|
|
354
|
+
color: #d19a66; /* Orange - numbers */
|
|
355
|
+
}
|
|
356
|
+
.token-string {
|
|
357
|
+
color: #98c379; /* Green - strings */
|
|
358
|
+
}
|
|
359
|
+
.token-comment {
|
|
360
|
+
color: #5c6370; /* Gray - comments */
|
|
361
|
+
font-style: italic;
|
|
362
|
+
}
|
|
363
|
+
.token-structural {
|
|
364
|
+
color: #abb2bf; /* Light gray - braces, brackets, parens */
|
|
365
|
+
font-weight: 600;
|
|
366
|
+
}
|
|
367
|
+
.token-delimiter {
|
|
368
|
+
color: #777; /* Dark gray - semicolons, commas, colons */
|
|
369
|
+
}
|
|
370
|
+
.token-operator {
|
|
371
|
+
color: #56b6c2; /* Cyan - operators (+, -, *, etc.) */
|
|
205
372
|
}
|
|
206
373
|
`;
|
|
207
374
|
}
|