-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy paththeme.js
More file actions
180 lines (156 loc) · 7.19 KB
/
Copy paththeme.js
File metadata and controls
180 lines (156 loc) · 7.19 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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/**
* 테마 관리 유틸리티
*/
import { themeTemplates } from '../constants/skeletonCode';
/**
* CSS 내용에서 CSS 변수 값만 추출 (주석 제거)
* @param {string} cssContent - CSS 내용
* @returns {Object} CSS 변수 객체
*/
export function extractCSSVariables(cssContent) {
if (!cssContent) return {};
// :root 블록 찾기
const rootBlockMatch = cssContent.match(/:root\s*\{([^}]+)\}/s);
if (!rootBlockMatch) {
return {};
}
const rootContent = rootBlockMatch[1];
// 주석 제거 (/* ... */ 형식)
const withoutComments = rootContent.replace(/\/\*[\s\S]*?\*\//g, '');
// CSS 변수 파싱 (--변수명: 값; 형식)
const variableRegex = /--([^:]+):\s*([^;]+);/g;
let match;
const variables = {};
while ((match = variableRegex.exec(withoutComments)) !== null) {
const variableName = match[1].trim();
const variableValue = match[2].trim();
variables[variableName] = variableValue;
}
return variables;
}
/**
* style.css 내용을 분석하여 테마 모드 감지
* @param {string} cssContent - CSS 내용
* @returns {string} 테마 모드 ('dark', 'light', 'custom')
*/
export function detectThemeMode(cssContent) {
const currentVariables = extractCSSVariables(cssContent);
const darkVariables = extractCSSVariables(themeTemplates.dark);
const lightVariables = extractCSSVariables(themeTemplates.light);
// Dark 테마와 비교
let matchesDark = true;
for (const key in darkVariables) {
if (currentVariables[key] !== darkVariables[key]) {
matchesDark = false;
break;
}
}
// 변수 개수도 확인
if (Object.keys(currentVariables).length !== Object.keys(darkVariables).length) {
matchesDark = false;
}
if (matchesDark) {
return 'dark';
}
// Light 테마와 비교
let matchesLight = true;
for (const key in lightVariables) {
if (currentVariables[key] !== lightVariables[key]) {
matchesLight = false;
break;
}
}
// 변수 개수도 확인
if (Object.keys(currentVariables).length !== Object.keys(lightVariables).length) {
matchesLight = false;
}
if (matchesLight) {
return 'light';
}
return 'custom';
}
/**
* CSS에서 :root 블록의 CSS 변수를 파싱하여 적용
* @param {string} cssContent - CSS 내용
*/
export function applyCSSVariables(cssContent) {
if (typeof window === 'undefined') return;
const root = document.documentElement;
const variables = extractCSSVariables(cssContent);
// CSS 변수를 DOM에 적용
Object.entries(variables).forEach(([key, value]) => {
root.style.setProperty(`--${key}`, value);
});
// 테마 모드 감지
const themeMode = detectThemeMode(cssContent);
// Monaco Editor 테마 업데이트
if (window.monaco && variables['color-bg-editor'] && variables['color-text-editor']) {
try {
const themeColors = {
'editor.background': variables['color-bg-editor'],
'editor.foreground': variables['color-text-editor'],
'editor.lineHighlightBackground': variables['color-bg-header'] || variables['color-bg-sidebar'],
'editor.selectionBackground': (variables['color-accent-primary'] || '#007acc') + '40',
'editorCursor.foreground': variables['color-accent-primary'] || '#007acc',
'editorWhitespace.foreground': (variables['color-border-default'] || '#3e3e42') + '40',
'editorIndentGuide.background': (variables['color-border-default'] || '#3e3e42') + '40',
'editorIndentGuide.activeBackground': variables['color-border-default'] || '#3e3e42',
'editorLineNumber.foreground': variables['color-text-secondary'] || '#858585',
'editorLineNumber.activeForeground': variables['color-text-primary'] || '#cccccc',
'editorGutter.background': variables['color-bg-main'] || '#1e1e1e',
'editorWidget.background': variables['color-bg-sidebar'] || '#252526',
'editorWidget.border': variables['color-border-default'] || '#3e3e42',
'editorSuggestWidget.background': variables['color-bg-sidebar'] || '#252526',
'editorSuggestWidget.border': variables['color-border-default'] || '#3e3e42',
'editorSuggestWidget.foreground': variables['color-text-primary'] || '#cccccc',
'editorSuggestWidget.selectedBackground': variables['color-bg-header'] || '#2d2d30',
'editorHoverWidget.background': variables['color-bg-sidebar'] || '#252526',
'editorHoverWidget.border': variables['color-border-default'] || '#3e3e42',
'input.background': variables['color-bg-input'] || '#1e1e1e',
'input.border': variables['color-border-input'] || '#3e3e42',
'input.foreground': variables['color-text-input'] || '#cccccc',
'inputOption.activeBorder': variables['color-accent-primary'] || '#007acc',
'dropdown.background': variables['color-bg-sidebar'] || '#252526',
'dropdown.border': variables['color-border-default'] || '#3e3e42',
'dropdown.foreground': variables['color-text-primary'] || '#cccccc',
'list.activeSelectionBackground': variables['color-bg-header'] || '#2d2d30',
'list.activeSelectionForeground': variables['color-text-primary'] || '#cccccc',
'list.hoverBackground': variables['color-bg-header'] || '#2d2d30',
'list.inactiveSelectionBackground': variables['color-bg-header'] || '#2d2d30',
'scrollbar.shadow': (variables['color-border-default'] || '#3e3e42') + '40',
'scrollbarSlider.background': variables['color-scrollbar-thumb'] || (variables['color-border-default'] || '#3e3e42') + '80',
'scrollbarSlider.hoverBackground': variables['color-scrollbar-thumb-hover'] || variables['color-border-default'] || '#3e3e42',
'scrollbarSlider.activeBackground': variables['color-scrollbar-thumb-hover'] || variables['color-border-default'] || '#3e3e42'
};
// Light 테마일 때만 연산자 색상 규칙 추가
const rules = themeMode === 'light' ? [
// Light 테마: 연산자와 특수 문자를 더 어둡게 설정하여 가독성 향상
{ token: 'operator', foreground: '#000000' },
{ token: 'delimiter', foreground: '#000000' },
{ token: 'delimiter.bracket', foreground: '#000000' },
{ token: 'delimiter.parenthesis', foreground: '#000000' },
{ token: 'delimiter.square', foreground: '#000000' },
{ token: 'delimiter.curly', foreground: '#000000' },
{ token: 'delimiter.angle', foreground: '#000000' },
{ token: 'delimiter.comma', foreground: '#000000' },
{ token: 'delimiter.semicolon', foreground: '#000000' },
{ token: 'delimiter.colon', foreground: '#000000' },
{ token: 'delimiter.dot', foreground: '#000000' },
] : [];
// base 테마도 테마 모드에 따라 변경
const baseTheme = themeMode === 'light' ? 'vs' : 'vs-dark';
window.monaco.editor.defineTheme('custom-theme', {
base: baseTheme,
inherit: true,
rules: rules,
colors: themeColors
});
// 모든 에디터 인스턴스에 테마 적용
if (window.monaco && window.monaco.editor) {
window.monaco.editor.setTheme('custom-theme');
}
} catch (error) {
console.error('Monaco Editor 테마 업데이트 오류:', error);
}
}
}