@cubud/wen 1.0.0

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.
@@ -0,0 +1,239 @@
1
+ // Import the industry-standard markdown parser for our live previews
2
+ import { marked } from 'https://esm.sh/marked@12.0.1';
3
+ import { sanitizeHtml } from './wen-utils.js';
4
+
5
+ export class WenComponentView {
6
+ constructor(node, getPos, editor) {
7
+ this.node = node;
8
+ this.getPos = getPos;
9
+ this.editor = editor;
10
+
11
+ this.dom = document.createElement('div');
12
+ this.dom.className = 'wen-component-block';
13
+ this.dom.contentEditable = 'false';
14
+
15
+ this.dom.innerHTML = `
16
+ <div class="wen-component-header">
17
+ <span class="wen-component-title">🧩 Component Wireframe</span>
18
+ <button class="wen-component-toggle-btn" data-state="visual">View Raw XML</button>
19
+ </div>
20
+ <div class="wen-component-view-visual active"></div>
21
+ <div class="wen-component-view-raw"><textarea class="wen-component-raw-input"></textarea></div>
22
+ `;
23
+
24
+ const toggleBtn = this.dom.querySelector('.wen-component-toggle-btn');
25
+ const visualView = this.dom.querySelector('.wen-component-view-visual');
26
+ const rawView = this.dom.querySelector('.wen-component-view-raw');
27
+ const rawInput = this.dom.querySelector('.wen-component-raw-input');
28
+
29
+ rawInput.value = this.node.textContent;
30
+ let isUpdatingFromUI = false;
31
+
32
+ const updateTipTapState = (newRawContent) => {
33
+ if (newRawContent === this.node.textContent) return;
34
+ if (typeof this.getPos === 'function') {
35
+ const tr = this.editor.state.tr;
36
+ const start = this.getPos() + 1;
37
+ const end = start + this.node.nodeSize - 2;
38
+ if (newRawContent) tr.replaceWith(start, end, this.editor.schema.text(newRawContent));
39
+ else tr.delete(start, end);
40
+ this.editor.view.dispatch(tr);
41
+ }
42
+ };
43
+
44
+ const renderVisualWireframe = () => {
45
+ visualView.innerHTML = '';
46
+
47
+ // Safe by default: marked output is sanitized unless the editor opts into unsafe mode.
48
+ const unsafe = this.editor.wenEditorInstance?.unsafe === true;
49
+
50
+ let rawCode = rawInput.value.trim();
51
+ rawCode = rawCode.replace(/^```[a-zA-Z0-9-]*\r?\n/, '').replace(/\r?\n```$/, '').trim();
52
+
53
+ const componentRegex = /^<([a-zA-Z0-9-]+)\s*([^>]*?)(?:(?:>([\s\S]*)<\/\1>)|(?:\/?>))$/;
54
+ const match = rawCode.match(componentRegex);
55
+
56
+ if (!match) {
57
+ visualView.innerHTML = `<div class="wen-component-error">Syntax Error: Cannot parse component structure.</div>`;
58
+ return;
59
+ }
60
+
61
+ let currentTagName = match[1];
62
+ let attributesStr = match[2].trim();
63
+ let currentInner = match[3];
64
+ let isSelfClosing = currentInner === undefined && rawCode.endsWith('/>');
65
+
66
+ let currentAttributes = [];
67
+ const attrRegex = /([a-zA-Z0-9_]+)=(?:'([^']*)'|"([^"]*)"|\{([^}]*)\})/g;
68
+ let attrMatch;
69
+ while ((attrMatch = attrRegex.exec(attributesStr)) !== null) {
70
+ currentAttributes.push({ name: attrMatch[1], value: attrMatch[2] || attrMatch[3] || attrMatch[4] || '' });
71
+ }
72
+
73
+ const syncState = () => {
74
+ const attrsStr = currentAttributes.map(a => `${a.name}="${a.value}"`).join(' ');
75
+ const space = attrsStr ? ' ' + attrsStr : '';
76
+ let newRaw = isSelfClosing
77
+ ? `<${currentTagName}${space} />`
78
+ : `<${currentTagName}${space}>\n${currentInner}\n</${currentTagName}>`;
79
+
80
+ rawInput.value = newRaw;
81
+ isUpdatingFromUI = true;
82
+ updateTipTapState(newRaw);
83
+ isUpdatingFromUI = false;
84
+ };
85
+
86
+ const wireframe = document.createElement('div');
87
+ wireframe.className = 'wen-wireframe';
88
+
89
+ const header = document.createElement('div');
90
+ header.className = 'wen-wireframe-header';
91
+ header.innerHTML = `<strong>${currentTagName}</strong> ${isSelfClosing ? '<em>(Self-Closing)</em>' : ''}`;
92
+ wireframe.appendChild(header);
93
+
94
+ if (currentAttributes.length > 0) {
95
+ const propsContainer = document.createElement('div');
96
+ propsContainer.className = 'wen-wireframe-props';
97
+
98
+ currentAttributes.forEach((attr, idx) => {
99
+ const prop = document.createElement('span');
100
+ prop.className = 'wen-wireframe-prop';
101
+ prop.innerHTML = `<span class="wen-prop-key">${attr.name}</span> = `;
102
+
103
+ const input = document.createElement('input');
104
+ input.type = 'text';
105
+ input.className = 'wen-prop-val-input';
106
+ input.value = attr.value;
107
+
108
+ input.addEventListener('input', (e) => {
109
+ currentAttributes[idx].value = e.target.value;
110
+ syncState();
111
+ });
112
+
113
+ prop.appendChild(input);
114
+ propsContainer.appendChild(prop);
115
+ });
116
+ wireframe.appendChild(propsContainer);
117
+ }
118
+
119
+ if (!isSelfClosing) {
120
+ const contentContainer = document.createElement('div');
121
+ contentContainer.className = 'wen-wireframe-content';
122
+
123
+ // 1. The DOMParser Preview Logic (Restored!)
124
+ let previewHTML = '<em>Empty content</em>';
125
+ if ((currentInner || '').trim()) {
126
+ try {
127
+ const doc = new DOMParser().parseFromString(currentInner, 'text/html');
128
+
129
+ const parseNode = (n) => {
130
+ if (n.nodeType === 1) { // HTML node
131
+ const name = n.localName;
132
+ if (n.hasChildNodes() && n.childNodes.length > 0) {
133
+ return `<div class="wen-preview-tag">&lt;${name}&gt;</div>\n${parseChildren(n.childNodes)}\n<div class="wen-preview-tag">&lt;/${name}&gt;</div>\n`;
134
+ } else {
135
+ return `<div class="wen-preview-tag">&lt;${name}/&gt;</div>\n`;
136
+ }
137
+ } else if (n.nodeType === 3) { // Text node
138
+ const text = n.textContent.replace(/^ +/gm, '');
139
+ if (!text.trim()) return '';
140
+ return `<div class="wen-preview-md">${marked.parse(text)}</div>`;
141
+ }
142
+ return '';
143
+ };
144
+
145
+ const parseChildren = (children) => {
146
+ let raw = '';
147
+ for (let i = 0; i < children.length; i++) {
148
+ raw += parseNode(children[i]);
149
+ }
150
+ return raw;
151
+ };
152
+
153
+ const parsed = parseChildren(doc.body.childNodes);
154
+ if (parsed.trim()) previewHTML = parsed;
155
+ } catch(e) {
156
+ previewHTML = '<em>Preview unavailable</em>';
157
+ }
158
+ }
159
+
160
+ const safePreview = unsafe ? previewHTML : sanitizeHtml(previewHTML);
161
+ contentContainer.innerHTML = `
162
+ <div class="wen-wireframe-preview-box">
163
+ <div class="wen-wireframe-preview">${safePreview}</div>
164
+ </div>
165
+ <button class="wen-wireframe-edit-btn">✏️ Edit in WYSIWYG</button>
166
+ `;
167
+
168
+ // 2. The Smart Outdent Utility
169
+ const outdent = (str) => {
170
+ if (!str) return '';
171
+ const lines = str.split('\n');
172
+ let minIndent = Infinity;
173
+ lines.forEach(line => {
174
+ if (line.trim().length > 0) {
175
+ const match = line.match(/^[ \t]*/);
176
+ if (match) {
177
+ const indent = match[0].length;
178
+ if (indent < minIndent) minIndent = indent;
179
+ }
180
+ }
181
+ });
182
+ if (minIndent === Infinity || minIndent === 0) return str;
183
+ return lines.map(line => line.trim().length === 0 ? line : line.substring(minIndent)).join('\n');
184
+ };
185
+
186
+ contentContainer.querySelector('.wen-wireframe-edit-btn').addEventListener('click', () => {
187
+ // Clean the indentation before handing it to the modal
188
+ const cleanMarkdown = outdent(currentInner || '');
189
+
190
+ this.editor.wenEditorInstance.showRichModal(currentTagName, cleanMarkdown, (newMd) => {
191
+ currentInner = '\n' + newMd + '\n';
192
+ syncState();
193
+ renderVisualWireframe();
194
+ });
195
+ });
196
+
197
+ wireframe.appendChild(contentContainer);
198
+ }
199
+
200
+ visualView.appendChild(wireframe);
201
+ };
202
+
203
+ toggleBtn.addEventListener('click', () => {
204
+ const isVisual = toggleBtn.getAttribute('data-state') === 'visual';
205
+ if (isVisual) {
206
+ visualView.classList.remove('active');
207
+ rawView.classList.add('active');
208
+ toggleBtn.setAttribute('data-state', 'raw');
209
+ toggleBtn.innerText = 'View UI';
210
+ } else {
211
+ renderVisualWireframe();
212
+ rawView.classList.remove('active');
213
+ visualView.classList.add('active');
214
+ toggleBtn.setAttribute('data-state', 'visual');
215
+ toggleBtn.innerText = 'View Raw XML';
216
+ }
217
+ });
218
+
219
+ rawInput.addEventListener('input', () => {
220
+ isUpdatingFromUI = true;
221
+ updateTipTapState(rawInput.value);
222
+ isUpdatingFromUI = false;
223
+ });
224
+
225
+ renderVisualWireframe();
226
+
227
+ this.update = (updatedNode) => {
228
+ if (updatedNode.type.name !== 'codeBlock' || !['xml', 'component', 'jsx'].includes(updatedNode.attrs.language)) return false;
229
+ if (this.node.textContent !== updatedNode.textContent) {
230
+ this.node = updatedNode;
231
+ rawInput.value = this.node.textContent;
232
+ if (!isUpdatingFromUI) renderVisualWireframe();
233
+ }
234
+ return true;
235
+ };
236
+
237
+ this.stopEvent = () => true;
238
+ }
239
+ }
@@ -0,0 +1,351 @@
1
+ /* GitHub Dark syntax-highlighting theme (highlight.js 11.9.0), vendored and
2
+ scoped to the editor so it never leaks into a consumer's global stylesheet.
3
+ Source: github.com/highlightjs/highlight.js — MIT, theme by @Hirse. */
4
+ .wen-editor-root pre code.hljs { display: block; overflow-x: auto; padding: 1em; }
5
+ .wen-editor-root code.hljs { padding: 3px 5px; }
6
+ .wen-editor-root .hljs { color: #c9d1d9; background: #0d1117; }
7
+ .wen-editor-root .hljs-doctag,
8
+ .wen-editor-root .hljs-keyword,
9
+ .wen-editor-root .hljs-meta .hljs-keyword,
10
+ .wen-editor-root .hljs-template-tag,
11
+ .wen-editor-root .hljs-template-variable,
12
+ .wen-editor-root .hljs-type,
13
+ .wen-editor-root .hljs-variable.language_ { color: #ff7b72; }
14
+ .wen-editor-root .hljs-title,
15
+ .wen-editor-root .hljs-title.class_,
16
+ .wen-editor-root .hljs-title.class_.inherited__,
17
+ .wen-editor-root .hljs-title.function_ { color: #d2a8ff; }
18
+ .wen-editor-root .hljs-attr,
19
+ .wen-editor-root .hljs-attribute,
20
+ .wen-editor-root .hljs-literal,
21
+ .wen-editor-root .hljs-meta,
22
+ .wen-editor-root .hljs-number,
23
+ .wen-editor-root .hljs-operator,
24
+ .wen-editor-root .hljs-selector-attr,
25
+ .wen-editor-root .hljs-selector-class,
26
+ .wen-editor-root .hljs-selector-id,
27
+ .wen-editor-root .hljs-variable { color: #79c0ff; }
28
+ .wen-editor-root .hljs-meta .hljs-string,
29
+ .wen-editor-root .hljs-regexp,
30
+ .wen-editor-root .hljs-string { color: #a5d6ff; }
31
+ .wen-editor-root .hljs-built_in,
32
+ .wen-editor-root .hljs-symbol { color: #ffa657; }
33
+ .wen-editor-root .hljs-code,
34
+ .wen-editor-root .hljs-comment,
35
+ .wen-editor-root .hljs-formula { color: #8b949e; }
36
+ .wen-editor-root .hljs-name,
37
+ .wen-editor-root .hljs-quote,
38
+ .wen-editor-root .hljs-selector-pseudo,
39
+ .wen-editor-root .hljs-selector-tag { color: #7ee787; }
40
+ .wen-editor-root .hljs-subst { color: #c9d1d9; }
41
+ .wen-editor-root .hljs-section { color: #1f6feb; font-weight: 700; }
42
+ .wen-editor-root .hljs-bullet { color: #f2cc60; }
43
+ .wen-editor-root .hljs-emphasis { color: #c9d1d9; font-style: italic; }
44
+ .wen-editor-root .hljs-strong { color: #c9d1d9; font-weight: 700; }
45
+ .wen-editor-root .hljs-addition { color: #aff5b4; background-color: #033a16; }
46
+ .wen-editor-root .hljs-deletion { color: #ffdcd7; background-color: #67060c; }
47
+
48
+ :root {
49
+ --wen-bg: #ffffff;
50
+ --wen-surface: #f9fafb;
51
+ --wen-surface-hover: #f3f4f6;
52
+ --wen-border: #e5e7eb;
53
+ --wen-text-main: #1f2937;
54
+ --wen-text-muted: #6b7280;
55
+ --wen-accent: #0f172a;
56
+ --wen-accent-text: #ffffff;
57
+ --wen-danger: #ef4444;
58
+ --wen-font-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
59
+ --wen-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
60
+ --wen-radius: 8px;
61
+ --wen-radius-sm: 4px;
62
+ --wen-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);
63
+ }
64
+
65
+ .wen-editor-wrapper {
66
+ background: var(--wen-bg);
67
+ border: 1px solid var(--wen-border);
68
+ border-radius: var(--wen-radius);
69
+ box-shadow: var(--wen-shadow);
70
+ display: flex;
71
+ flex-direction: column;
72
+ font-family: var(--wen-font-sans);
73
+ color: var(--wen-text-main);
74
+ }
75
+
76
+ .wen-toolbar {
77
+ display: flex;
78
+ flex-wrap: wrap;
79
+ gap: 0.25rem;
80
+ padding: 0.5rem;
81
+ background: var(--wen-surface);
82
+ border-bottom: 1px solid var(--wen-border);
83
+ align-items: center;
84
+ border-top-left-radius: calc(var(--wen-radius) - 1px);
85
+ border-top-right-radius: calc(var(--wen-radius) - 1px);
86
+ }
87
+
88
+ .wen-toolbar-btn {
89
+ background: transparent;
90
+ border: 1px solid transparent;
91
+ padding: 0.35rem 0.6rem;
92
+ cursor: pointer;
93
+ font-family: var(--wen-font-sans);
94
+ font-size: 0.85rem;
95
+ color: var(--wen-text-muted);
96
+ border-radius: var(--wen-radius-sm);
97
+ transition: all 0.15s ease;
98
+ }
99
+
100
+ .wen-toolbar-btn:hover { background: var(--wen-surface-hover); color: var(--wen-text-main); }
101
+ .wen-toolbar-btn.is-active { background: var(--wen-accent); color: var(--wen-accent-text); }
102
+ .wen-toolbar-divider { width: 1px; height: 1.25rem; background: var(--wen-border); margin: 0 0.25rem; }
103
+
104
+ .wen-editor-root { padding: 1.5rem; min-height: 300px; outline: none; line-height: 1.6; }
105
+ .wen-editor-root p, .wen-editor-root h1, .wen-editor-root h2, .wen-editor-root h3 { margin-top: 0; margin-bottom: 1rem; }
106
+ .wen-editor-root h1, .wen-editor-root h2 { font-weight: 600; color: var(--wen-text-main); }
107
+ /* Inline code (e.g. `const x = 1`) */
108
+ .wen-editor-root p code {
109
+ background: var(--wen-surface);
110
+ color: var(--wen-text-main);
111
+ padding: 0.2em 0.4em;
112
+ border-radius: var(--wen-radius-sm);
113
+ font-family: var(--wen-font-mono);
114
+ font-size: 0.9em;
115
+ border: 1px solid var(--wen-border);
116
+ }
117
+
118
+ /* Block code (Syntax Highlighted) */
119
+ .wen-editor-root pre {
120
+ background: #0d1117; /* GitHub Dark background */
121
+ color: #c9d1d9; /* GitHub Dark text */
122
+ padding: 1rem;
123
+ border-radius: var(--wen-radius);
124
+ font-family: var(--wen-font-mono);
125
+ font-size: 0.9rem;
126
+ overflow-x: auto;
127
+ margin: 1.5rem 0;
128
+ }
129
+
130
+ .wen-editor-root pre code {
131
+ background: transparent;
132
+ color: inherit;
133
+ padding: 0;
134
+ border: none;
135
+ font-size: inherit;
136
+ }
137
+ .wen-editor-root blockquote { border-left: 3px solid var(--wen-border); margin-left: 0; padding-left: 1rem; font-style: italic; color: var(--wen-text-muted); }
138
+
139
+ /* Utility Modals (Link/Image) must always sit absolute top */
140
+ .wen-modal-overlay {
141
+ position: fixed;
142
+ top: 0; left: 0; right: 0; bottom: 0;
143
+ background: rgba(0, 0, 0, 0.6);
144
+ z-index: 99999 !important; /* Wins the z-index battle */
145
+ display: flex;
146
+ align-items: center;
147
+ justify-content: center;
148
+ }
149
+
150
+ .wen-modal {
151
+ background: var(--wen-bg);
152
+ padding: 1.5rem;
153
+ border-radius: var(--wen-radius);
154
+ box-shadow: 0 10px 30px rgba(0,0,0,0.5);
155
+ width: 350px;
156
+ display: flex;
157
+ flex-direction: column;
158
+ gap: 1rem;
159
+ border: 1px solid var(--wen-border);
160
+ color: var(--wen-text-main);
161
+ font-family: var(--wen-font-sans);
162
+ }
163
+
164
+ .wen-modal strong {
165
+ font-size: 1.1rem;
166
+ }
167
+
168
+ .wen-modal input {
169
+ padding: 0.5rem;
170
+ border-radius: var(--wen-radius-sm);
171
+ border: 1px solid var(--wen-border);
172
+ background: var(--wen-surface);
173
+ color: var(--wen-text-main);
174
+ font-family: var(--wen-font-mono);
175
+ outline: none;
176
+ }
177
+
178
+ .wen-modal input:focus {
179
+ border-color: #3b82f6;
180
+ }
181
+
182
+ .wen-modal-actions {
183
+ display: flex;
184
+ justify-content: flex-end;
185
+ gap: 0.5rem;
186
+ }
187
+
188
+ .wen-modal-cancel, .wen-modal-submit {
189
+ padding: 0.4rem 0.8rem;
190
+ border-radius: var(--wen-radius-sm);
191
+ cursor: pointer;
192
+ border: none;
193
+ font-weight: 600;
194
+ }
195
+
196
+ .wen-modal-cancel {
197
+ background: transparent;
198
+ color: var(--wen-text-muted);
199
+ }
200
+
201
+ .wen-modal-cancel:hover {
202
+ background: var(--wen-surface);
203
+ color: var(--wen-text-main);
204
+ }
205
+
206
+ .wen-modal-submit {
207
+ background: #3b82f6;
208
+ color: white;
209
+ }
210
+
211
+ .wen-modal-submit:hover {
212
+ background: #2563eb;
213
+ }
214
+
215
+ /* Disabled Toolbar Buttons */
216
+ .wen-toolbar-btn:disabled {
217
+ opacity: 0.4;
218
+ cursor: not-allowed;
219
+ background: transparent !important;
220
+ color: var(--wen-text-muted) !important;
221
+ }
222
+
223
+ /* Table Architecture */
224
+ .wen-editor-root .tableWrapper {
225
+ overflow-x: auto;
226
+ margin: 1.5rem 0;
227
+ border: 1px solid var(--wen-border);
228
+ border-radius: var(--wen-radius-sm);
229
+ }
230
+
231
+ /* Bulletproof: Target ALL tables inside the editor */
232
+ .wen-editor-root table {
233
+ border-collapse: collapse;
234
+ table-layout: fixed;
235
+ width: 100%;
236
+ margin: 0;
237
+ overflow: hidden;
238
+ }
239
+
240
+ .wen-editor-root table td,
241
+ .wen-editor-root table th {
242
+ min-width: 1em;
243
+ border: 1px solid #cbd5e1; /* Darker, crisp slate border */
244
+ padding: 0.5rem;
245
+ vertical-align: top;
246
+ box-sizing: border-box;
247
+ position: relative;
248
+ }
249
+
250
+ .wen-editor-root table th {
251
+ font-weight: 600;
252
+ text-align: left;
253
+ background-color: var(--wen-surface);
254
+ color: var(--wen-text-main);
255
+ }
256
+
257
+ .wen-editor-root table p {
258
+ margin: 0;
259
+ }
260
+
261
+ /* Task Lists (Checklists) */
262
+ .wen-editor-root ul[data-type="taskList"] {
263
+ list-style: none;
264
+ padding: 0;
265
+ }
266
+
267
+ .wen-editor-root ul[data-type="taskList"] li {
268
+ display: flex;
269
+ align-items: flex-start;
270
+ margin-bottom: 0.5rem;
271
+ }
272
+
273
+ .wen-editor-root ul[data-type="taskList"] li > label {
274
+ margin-right: 0.5rem;
275
+ user-select: none;
276
+ margin-top: 0.15rem; /* Optical alignment with text */
277
+ }
278
+
279
+ .wen-editor-root ul[data-type="taskList"] li > label input[type="checkbox"] {
280
+ cursor: pointer;
281
+ }
282
+
283
+ .wen-editor-root ul[data-type="taskList"] li > div {
284
+ flex: 1;
285
+ }
286
+
287
+ .wen-editor-root ul[data-type="taskList"] li p {
288
+ margin: 0;
289
+ }
290
+
291
+ /* GitHub Flavored Alerts (Admonitions) */
292
+ .wen-editor-root .wen-github-alert {
293
+ border-left: 4px solid var(--wen-border);
294
+ padding: 0.75rem 1rem;
295
+ margin: 1.5rem 0;
296
+ border-radius: 0 var(--wen-radius-sm) var(--wen-radius-sm) 0;
297
+ font-style: normal; /* Overrides standard blockquote italic */
298
+ color: var(--wen-text-main);
299
+ }
300
+
301
+ .wen-editor-root .wen-github-alert p:last-child {
302
+ margin-bottom: 0;
303
+ }
304
+
305
+ /* Background Tints & Border Colors */
306
+ .wen-editor-root .wen-github-alert-note { border-left-color: #0969da; background-color: rgba(9, 105, 218, 0.05); }
307
+ .wen-editor-root .wen-github-alert-tip { border-left-color: #1a7f37; background-color: rgba(26, 127, 55, 0.05); }
308
+ .wen-editor-root .wen-github-alert-important { border-left-color: #8250df; background-color: rgba(130, 80, 223, 0.05); }
309
+ .wen-editor-root .wen-github-alert-warning { border-left-color: #bf8700; background-color: rgba(191, 135, 0, 0.05); }
310
+ .wen-editor-root .wen-github-alert-caution { border-left-color: #cf222e; background-color: rgba(207, 34, 46, 0.05); }
311
+
312
+ /* The [!TAG] Badge styling */
313
+ .wen-editor-root .wen-github-alert-badge {
314
+ display: inline-block;
315
+ font-weight: 600;
316
+ font-size: 0.9em;
317
+ font-family: var(--wen-font-mono);
318
+ }
319
+
320
+ .wen-editor-root .wen-github-alert-badge-note { color: #0969da; }
321
+ .wen-editor-root .wen-github-alert-badge-tip { color: #1a7f37; }
322
+ .wen-editor-root .wen-github-alert-badge-important { color: #8250df; }
323
+ .wen-editor-root .wen-github-alert-badge-warning { color: #bf8700; }
324
+ .wen-editor-root .wen-github-alert-badge-caution { color: #cf222e; }
325
+
326
+ /* Rich Recursive Modal */
327
+ .wen-rich-modal-overlay {
328
+ position: fixed; top: 0; left: 0; right: 0; bottom: 0;
329
+ background: rgba(0,0,0,0.7); z-index: 9999;
330
+ display: flex; align-items: center; justify-content: center;
331
+ }
332
+
333
+ .wen-rich-modal {
334
+ width: 90vw; height: 90vh; background: #fff;
335
+ border-radius: var(--wen-radius); display: flex; flex-direction: column;
336
+ overflow: hidden; box-shadow: 0 10px 40px rgba(0,0,0,0.5);
337
+ }
338
+
339
+ .wen-rich-modal-header {
340
+ padding: 1rem 1.5rem; background: #1e1e1e; color: white;
341
+ display: flex; justify-content: space-between; align-items: center;
342
+ }
343
+
344
+ .wen-rich-modal-body {
345
+ flex: 1; min-height: 0; display: flex; flex-direction: column;
346
+ background: var(--wen-bg);
347
+ }
348
+
349
+ .wen-rich-modal-body .wen-editor-wrapper {
350
+ height: 100%; border: none;
351
+ }