main
html 1,082 lines 36.2 KB
Raw
1 <html>
2 <head>
3 <script type="module">
4 import { store } from "/plugins/_editor/webui/editor-store.js";
5 </script>
6 </head>
7 <body>
8 <div x-data>
9 <template x-if="$store.editor">
10 <div class="editor-panel" x-create="$store.editor.onMount($el, xAttrs($el) || {})" x-destroy="$store.editor.cleanup()">
11 <div class="editor-shell" @keydown.capture="$store.editor.handleEditorKeydown($event)">
12 <div class="editor-tabs" x-show="$store.editor.visibleTabs().length > 0" style="display: none;" role="tablist" aria-label="Open text files">
13 <template x-for="tab in $store.editor.visibleTabs()" :key="tab.tab_id">
14 <div
15 class="editor-tab-shell"
16 :class="{ 'is-active': $store.editor.isActiveTab(tab), 'is-dirty': $store.editor.isTabDirty(tab), 'is-pending-close': $store.editor.pendingClose?.tabId === tab.tab_id }"
17 >
18 <button
19 type="button"
20 class="editor-tab"
21 role="tab"
22 :aria-selected="$store.editor.isActiveTab(tab).toString()"
23 :title="$store.editor.tabLabel(tab)"
24 @click="$store.editor.selectTab(tab.tab_id)"
25 >
26 <x-icon class="editor-tab-icon" aria-hidden="true" :name="$store.editor.tabIcon(tab)"></x-icon>
27 <span class="editor-tab-title" x-text="$store.editor.tabTitle(tab)"></span>
28 </button>
29 <button
30 type="button"
31 class="editor-tab-close"
32 title="Close file"
33 aria-label="Close file"
34 @pointerdown.stop
35 @click.stop="$store.editor.closeTab(tab.tab_id)"
36 >
37 <x-icon aria-hidden="true" name="close"></x-icon>
38 </button>
39 </div>
40 </template>
41 <button
42 type="button"
43 class="editor-new-tab"
44 title="Open file"
45 aria-label="Open file"
46 :disabled="$store.editor.loading || $store.editor.saving"
47 @click="$store.editor.runNewMenuAction('open')"
48 >
49 <span class="material-symbols-outlined" aria-hidden="true">folder_open</span>
50 </button>
51 <button
52 type="button"
53 class="editor-new-tab"
54 title="New Markdown"
55 aria-label="New Markdown"
56 :disabled="$store.editor.loading || $store.editor.saving"
57 @click="$store.editor.runNewMenuAction('markdown')"
58 >
59 <x-icon aria-hidden="true" name="add"></x-icon>
60 </button>
61 </div>
62
63 <div class="editor-close-confirm" x-show="$store.editor.hasPendingClose()" style="display: none;" role="status">
64 <x-icon class="editor-close-confirm-icon" aria-hidden="true" name="warning"></x-icon>
65 <div class="editor-close-confirm-copy">
66 <span class="editor-close-confirm-title" x-text="$store.editor.pendingCloseTitle()"></span>
67 <span class="editor-close-confirm-message" x-text="$store.editor.pendingCloseMessage()"></span>
68 </div>
69 <div class="editor-close-confirm-actions">
70 <button
71 type="button"
72 class="editor-text-button is-primary"
73 x-show="$store.editor.pendingCloseHasDirty()"
74 :disabled="$store.editor.saving"
75 @click="$store.editor.confirmPendingClose({ save: true })"
76 >
77 Save &amp; Close
78 </button>
79 <button
80 type="button"
81 class="editor-text-button"
82 :disabled="$store.editor.saving"
83 @click="$store.editor.confirmPendingClose({ save: false })"
84 x-text="$store.editor.pendingCloseDiscardLabel()"
85 ></button>
86 <button type="button" class="editor-text-button" :disabled="$store.editor.saving" @click="$store.editor.cancelPendingClose()">Cancel</button>
87 </div>
88 </div>
89
90 <div class="editor-toolbar" x-show="$store.editor.session" style="display: none;">
91 <div class="editor-toolbar-row">
92 <button
93 type="button"
94 class="editor-icon-button editor-mode-toggle"
95 x-show="$store.editor.isTextDocument()"
96 style="display: none;"
97 :title="$store.editor.viewModeTitle()"
98 :aria-label="$store.editor.viewModeTitle()"
99 @click="$store.editor.toggleViewMode()"
100 >
101 <x-icon aria-hidden="true" :name="$store.editor.viewModeIcon()"></x-icon>
102 </button>
103
104 <div class="editor-tool-group editor-history-tools" x-show="$store.editor.isTextDocument()" style="display: none;">
105 <button type="button" class="editor-icon-button" title="Undo" aria-label="Undo" :disabled="$store.editor.previewEditing || !$store.editor.canUndo()" @click="$store.editor.undo()">
106 <x-icon name="undo"></x-icon>
107 </button>
108 <button type="button" class="editor-icon-button" title="Redo" aria-label="Redo" :disabled="$store.editor.previewEditing || !$store.editor.canRedo()" @click="$store.editor.redo()">
109 <x-icon name="redo"></x-icon>
110 </button>
111 </div>
112
113 <div class="editor-tool-group editor-source-tools" x-show="$store.editor.isTextDocument() && $store.editor.isSourceMode()" style="display: none;">
114 <button type="button" class="editor-icon-button" title="Bold" aria-label="Bold" @click="$store.editor.format('bold')">
115 <x-icon name="format_bold"></x-icon>
116 </button>
117 <button type="button" class="editor-icon-button" title="Italic" aria-label="Italic" @click="$store.editor.format('italic')">
118 <x-icon name="format_italic"></x-icon>
119 </button>
120 <button type="button" class="editor-icon-button" title="List" aria-label="List" @click="$store.editor.format('list')">
121 <x-icon name="format_list_bulleted"></x-icon>
122 </button>
123 <button type="button" class="editor-icon-button" title="Numbered list" aria-label="Numbered list" @click="$store.editor.format('numbered')">
124 <x-icon name="format_list_numbered"></x-icon>
125 </button>
126 <button type="button" class="editor-icon-button" title="Table" aria-label="Table" @click="$store.editor.format('table')">
127 <x-icon name="table"></x-icon>
128 </button>
129 </div>
130 <div class="editor-tool-group editor-preview-tools" x-show="$store.editor.isTextDocument() && $store.editor.isPreviewMode()" style="display: none;">
131 <button type="button" class="editor-icon-button" title="Edit document" aria-label="Edit document" x-show="!$store.editor.previewEditing" @click="$store.editor.startPreviewEdit()">
132 <x-icon name="edit_note"></x-icon>
133 </button>
134 <button type="button" class="editor-icon-button is-primary" title="Apply document edit" aria-label="Apply document edit" x-show="$store.editor.previewEditing" @click="$store.editor.applyPreviewEdit()">
135 <x-icon name="check"></x-icon>
136 </button>
137 <button type="button" class="editor-icon-button" title="Cancel document edit" aria-label="Cancel document edit" x-show="$store.editor.previewEditing" @click="$store.editor.cancelPreviewEdit()">
138 <x-icon name="close"></x-icon>
139 </button>
140 <button type="button" class="editor-icon-button" title="Search" aria-label="Search" :disabled="$store.editor.previewEditing" @click="$store.editor.openSearch()">
141 <x-icon name="search"></x-icon>
142 </button>
143 </div>
144 <span class="editor-toolbar-spacer"></span>
145
146 <button
147 type="button"
148 class="editor-icon-button editor-save-button"
149 :class="{ 'is-primary': $store.editor.dirty || $store.editor.saving }"
150 :title="$store.editor.saving ? 'Saving' : 'Save'"
151 :aria-label="$store.editor.saving ? 'Saving' : 'Save'"
152 :disabled="$store.editor.saving"
153 @click="$store.editor.save()"
154 >
155 <x-icon :class="{ spinning: $store.editor.saving }" :name="$store.editor.saving ? 'progress_activity' : 'save'"></x-icon>
156 </button>
157
158 <button
159 type="button"
160 class="editor-icon-button editor-save-as-button"
161 title="Save As"
162 aria-label="Save As"
163 :disabled="$store.editor.saving"
164 @click="$store.editor.saveAs()"
165 >
166 <x-icon name="save_as"></x-icon>
167 </button>
168
169 <div class="editor-file-actions" x-data="{ open: false }" @click.outside="open = false" @keydown.escape.window="open = false">
170 <button
171 type="button"
172 class="editor-icon-button editor-file-menu-button"
173 title="File actions"
174 aria-label="File actions"
175 aria-haspopup="menu"
176 :aria-expanded="open.toString()"
177 :disabled="$store.editor.saving"
178 @click.stop="open = !open"
179 >
180 <x-icon name="more_vert"></x-icon>
181 </button>
182 <div class="editor-new-menu editor-file-menu" role="menu" x-show="open" @click.stop>
183 <button type="button" class="editor-new-menu-item" role="menuitem" :disabled="$store.editor.saving" @click="open = false; $store.editor.downloadActiveFile()">
184 <x-icon aria-hidden="true" name="download"></x-icon>
185 <span>Download</span>
186 </button>
187 <button type="button" class="editor-new-menu-item" role="menuitem" :disabled="$store.editor.saving" @click="open = false; $store.editor.renameActiveFile()">
188 <x-icon aria-hidden="true" name="edit"></x-icon>
189 <span>Rename</span>
190 </button>
191 <button type="button" class="editor-new-menu-item" role="menuitem" :disabled="$store.editor.loading" @click="open = false; $store.editor.closeActiveFile()">
192 <x-icon aria-hidden="true" name="close"></x-icon>
193 <span>Close File</span>
194 </button>
195 <button type="button" class="editor-new-menu-item" role="menuitem" :disabled="$store.editor.loading || $store.editor.visibleTabs().length === 0" @click="open = false; $store.editor.closeAllFiles()">
196 <x-icon aria-hidden="true" name="close"></x-icon>
197 <span>Close All</span>
198 </button>
199 </div>
200 </div>
201 </div>
202 </div>
203
204 <div class="editor-search-bar" x-show="$store.editor.searchOpen" style="display: none;">
205 <x-icon aria-hidden="true" name="search"></x-icon>
206 <input
207 type="search"
208 data-editor-search
209 aria-label="Search preview"
210 x-model="$store.editor.searchQuery"
211 @input="$store.editor.runSearch()"
212 @keydown.enter.prevent="$event.shiftKey ? $store.editor.previousSearchMatch() : $store.editor.nextSearchMatch()"
213 @keydown.escape.prevent="$store.editor.closeSearch()"
214 />
215 <span class="editor-search-count" x-text="$store.editor.searchCountLabel()"></span>
216 <button type="button" class="editor-icon-button" title="Previous match" aria-label="Previous match" :disabled="$store.editor.searchMatches.length === 0" @click="$store.editor.previousSearchMatch()">
217 <x-icon name="keyboard_arrow_up"></x-icon>
218 </button>
219 <button type="button" class="editor-icon-button" title="Next match" aria-label="Next match" :disabled="$store.editor.searchMatches.length === 0" @click="$store.editor.nextSearchMatch()">
220 <x-icon name="keyboard_arrow_down"></x-icon>
221 </button>
222 <button type="button" class="editor-icon-button" title="Close search" aria-label="Close search" @click="$store.editor.closeSearch()">
223 <x-icon name="close"></x-icon>
224 </button>
225 </div>
226
227 <div class="editor-state-line" x-show="$store.editor.message || $store.editor.error || $store.editor.loading" style="display: none;">
228 <x-icon :class="{ spinning: $store.editor.loading }" :name="$store.editor.loading ? 'progress_activity' : ($store.editor.error ? 'error' : 'check_circle')"></x-icon>
229 <span x-text="$store.editor.error || $store.editor.message || 'Working'"></span>
230 </div>
231
232 <div class="editor-body">
233 <div class="editor-wrap" x-show="$store.editor.session && $store.editor.isSourceMode()" style="display: none;">
234 <div class="editor-scroll" @click.self="$store.editor.focusEditor()">
235 <div class="editor-ace" data-editor-ace x-show="!$store.editor.aceUnavailable"></div>
236 <textarea
237 class="editor-source-editor"
238 data-editor-source
239 aria-label="Text source"
240 x-show="$store.editor.aceUnavailable"
241 x-model="$store.editor.editorText"
242 @input="$store.editor.onSourceInput()"
243 @blur="$store.editor.flushInput()"
244 spellcheck="true"
245 style="display: none;"
246 ></textarea>
247 </div>
248 </div>
249
250 <div class="editor-preview-shell" x-show="$store.editor.session && $store.editor.isTextDocument() && $store.editor.isPreviewMode()" style="display: none;">
251 <div class="editor-preview-title">
252 <h1 x-text="$store.editor.pageTitle()"></h1>
253 </div>
254 <div class="editor-preview-edit-shell" x-show="$store.editor.previewEditing" style="display: none;">
255 <textarea
256 class="editor-preview-page-editor"
257 data-editor-preview-source
258 aria-label="Document source"
259 x-model="$store.editor.previewEditText"
260 @input="$store.editor.onPreviewEditInput()"
261 @keydown.meta.enter.prevent="$store.editor.applyPreviewEdit()"
262 @keydown.ctrl.enter.prevent="$store.editor.applyPreviewEdit()"
263 @keydown.escape.prevent="$store.editor.cancelPreviewEdit()"
264 spellcheck="true"
265 ></textarea>
266 </div>
267 <div
268 class="editor-preview-content msg-content"
269 data-editor-preview
270 x-show="!$store.editor.previewEditing"
271 x-html="$store.editor.previewHtml()"
272 x-effect="$store.editor.editorText; $store.editor.searchQuery; $store.editor.searchIndex; $store.editor.schedulePreviewEnhance()"
273 @click="$store.editor.handlePreviewClick($event)"
274 ></div>
275 </div>
276
277 <div class="editor-empty" x-show="!$store.editor.session && !$store.editor.loading" style="display: none;">
278 <div class="editor-empty-actions">
279 <button type="button" class="editor-icon-button editor-command-button" @click="$store.editor.runNewMenuAction('open')">
280 <x-icon aria-hidden="true" name="folder_open"></x-icon>
281 <span class="editor-button-label">Open</span>
282 </button>
283 <button type="button" class="editor-icon-button editor-command-button" @click="$store.editor.runNewMenuAction('markdown')">
284 <x-icon aria-hidden="true" name="article"></x-icon>
285 <span class="editor-button-label">Markdown</span>
286 </button>
287 <button type="button" class="editor-icon-button editor-command-button" @click="$store.editor.runNewMenuAction('text')">
288 <x-icon aria-hidden="true" name="description"></x-icon>
289 <span class="editor-button-label">Text</span>
290 </button>
291 </div>
292 </div>
293 </div>
294 </div>
295 </div>
296 </template>
297 </div>
298
299 <style>
300 .editor-panel,
301 .editor-shell {
302 --editor-chrome-surface: color-mix(in srgb, var(--color-background) 92%, #000 8%);
303 --editor-chrome-border: color-mix(in srgb, var(--color-border) 58%, transparent);
304 --editor-tab-hover-border: color-mix(in srgb, var(--color-border) 78%, transparent);
305 --editor-tab-height: 36px;
306 --editor-tab-close-size: 32px;
307 --editor-control-radius: 0.55rem;
308 display: flex;
309 flex: 1 1 auto;
310 flex-direction: column;
311 width: 100%;
312 height: 100%;
313 min-width: 0;
314 min-height: 0;
315 background: var(--color-background);
316 color: var(--color-text);
317 }
318
319 .editor-panel {
320 container-type: inline-size;
321 }
322
323 .modal-inner.editor-modal {
324 box-sizing: border-box;
325 width: min(1040px, calc(100vw - 32px));
326 height: min(760px, calc(100vh - 32px));
327 min-width: min(640px, calc(100vw - 16px));
328 min-height: min(460px, calc(100vh - 16px));
329 max-width: none;
330 max-height: none;
331 resize: both;
332 overflow: hidden;
333 }
334
335 .modal-inner.editor-modal.is-focus-mode {
336 left: 8px !important;
337 top: 8px !important;
338 width: calc(100vw - 16px) !important;
339 height: calc(100vh - 16px) !important;
340 transform: none !important;
341 }
342
343 .modal-inner.editor-modal .modal-scroll,
344 .modal-inner.editor-modal .modal-bd.editor-modal-body,
345 .modal-inner.editor-modal .modal-bd.editor-modal-body > x-component,
346 .modal-inner.editor-modal .modal-bd.editor-modal-body > x-component > div[x-data],
347 .modal-inner.editor-modal .modal-bd.editor-modal-body > x-component > div[x-data] > .editor-panel {
348 display: flex;
349 flex: 1 1 auto;
350 min-width: 0;
351 min-height: 0;
352 width: 100%;
353 height: 100%;
354 max-height: none;
355 overflow: hidden;
356 padding: 0;
357 }
358
359 .modal-inner.editor-modal .modal-header {
360 grid-template-columns: minmax(0, 1fr) auto auto;
361 }
362
363 .editor-tabs {
364 display: flex;
365 align-items: end;
366 gap: 4px;
367 min-height: 44px;
368 padding: 7px 10px 0;
369 overflow-x: auto;
370 overflow-y: hidden;
371 border-bottom: 1px solid var(--editor-chrome-border);
372 background: var(--editor-chrome-surface);
373 scrollbar-width: thin;
374 }
375
376 .editor-tabs::-webkit-scrollbar {
377 height: 4px;
378 }
379
380 .editor-tabs::-webkit-scrollbar-track {
381 background: transparent;
382 }
383
384 .editor-tabs::-webkit-scrollbar-thumb {
385 background: color-mix(in srgb, var(--color-border) 78%, transparent);
386 border-radius: 999px;
387 }
388
389 .editor-tab-shell {
390 flex: 0 1 210px;
391 position: relative;
392 display: grid;
393 grid-template-columns: minmax(0, 1fr) var(--editor-tab-close-size);
394 align-items: center;
395 gap: 3px;
396 min-width: 128px;
397 max-width: 250px;
398 height: var(--editor-tab-height);
399 padding: 0 7px 0 10px;
400 border: 1px solid transparent;
401 border-radius: var(--editor-control-radius) var(--editor-control-radius) 0 0;
402 background: transparent;
403 opacity: 0.72;
404 transition: border-color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
405 color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
406 opacity 0.18s cubic-bezier(0.4, 0, 0.2, 1);
407 }
408
409 .editor-new-tab {
410 display: inline-flex;
411 align-items: center;
412 justify-content: center;
413 flex: 0 0 34px;
414 width: 34px;
415 min-width: 34px;
416 height: 34px;
417 min-height: 34px;
418 padding: 0;
419 border: 1px solid transparent;
420 border-radius: var(--editor-control-radius);
421 background: transparent;
422 color: color-mix(in srgb, var(--color-text) 62%, var(--color-primary) 38%);
423 cursor: pointer;
424 transition: background-color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
425 border-color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
426 color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
427 opacity 0.18s cubic-bezier(0.4, 0, 0.2, 1);
428 }
429
430 .editor-icon-button {
431 display: inline-grid;
432 place-items: center;
433 width: 32px;
434 height: 32px;
435 min-width: 32px;
436 padding: 0;
437 border: 1px solid color-mix(in srgb, var(--color-border), transparent 12%);
438 border-radius: 8px;
439 background: color-mix(in srgb, var(--color-panel), var(--color-background) 16%);
440 color: inherit;
441 cursor: pointer;
442 transition: border-color 120ms ease, background 120ms ease;
443 }
444
445 .editor-tab {
446 display: flex;
447 align-items: center;
448 gap: 8px;
449 min-width: 0;
450 width: 100%;
451 height: 100%;
452 padding: 0;
453 border: 0;
454 border-radius: 0;
455 background: transparent;
456 color: inherit;
457 cursor: pointer;
458 font: inherit;
459 text-align: left;
460 }
461
462 .editor-tab-close {
463 display: inline-flex;
464 align-items: center;
465 justify-content: center;
466 width: var(--editor-tab-close-size);
467 min-width: var(--editor-tab-close-size);
468 height: var(--editor-tab-close-size);
469 min-height: var(--editor-tab-close-size);
470 padding: 0;
471 border: 0;
472 border-radius: 6px;
473 background: transparent;
474 color: color-mix(in srgb, var(--color-text) 52%, var(--color-primary) 48%);
475 cursor: pointer;
476 opacity: 0.72;
477 transition: background-color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
478 color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
479 opacity 0.18s cubic-bezier(0.4, 0, 0.2, 1);
480 }
481
482 .editor-tab-shell:hover,
483 .editor-tab-shell:focus-within {
484 border-color: var(--editor-tab-hover-border);
485 opacity: 0.94;
486 }
487
488 .editor-tab-shell.is-active {
489 z-index: 2;
490 margin-bottom: -1px;
491 border-color: var(--editor-chrome-border);
492 background: transparent;
493 opacity: 1;
494 box-shadow: none;
495 }
496
497 .editor-icon-button.is-primary {
498 border-color: color-mix(in srgb, #2c7be5, var(--color-border) 36%);
499 background: color-mix(in srgb, #2c7be5, var(--color-panel) 88%);
500 }
501
502 .editor-tab-shell.is-pending-close {
503 border-color: color-mix(in srgb, #d98b2b, var(--color-border) 30%);
504 background: color-mix(in srgb, #d98b2b, var(--color-panel) 88%);
505 opacity: 1;
506 }
507
508 .editor-tab-shell.is-dirty .editor-tab-title::after {
509 content: " *";
510 color: #2ca58d;
511 }
512
513 .editor-tab-title {
514 min-width: 0;
515 overflow: hidden;
516 text-overflow: ellipsis;
517 white-space: nowrap;
518 font-size: 0.88rem;
519 font-weight: 600;
520 letter-spacing: 0;
521 }
522
523 .editor-toolbar,
524 .editor-state-line,
525 .editor-close-confirm,
526 .editor-search-bar {
527 display: flex;
528 align-items: center;
529 gap: 8px;
530 border-bottom: 1px solid color-mix(in srgb, var(--color-border), transparent 22%);
531 padding: 7px 10px;
532 min-width: 0;
533 }
534
535 .editor-close-confirm {
536 min-height: 44px;
537 background: color-mix(in srgb, #d98b2b 9%, var(--color-background));
538 color: var(--color-text);
539 }
540
541 .editor-close-confirm-icon {
542 color: #d98b2b;
543 font-size: 20px;
544 }
545
546 .editor-close-confirm-copy {
547 display: flex;
548 flex: 1 1 auto;
549 flex-direction: column;
550 min-width: 0;
551 gap: 2px;
552 }
553
554 .editor-close-confirm-title {
555 overflow: hidden;
556 text-overflow: ellipsis;
557 white-space: nowrap;
558 font-size: 13px;
559 font-weight: 800;
560 letter-spacing: 0;
561 }
562
563 .editor-close-confirm-message {
564 overflow: hidden;
565 text-overflow: ellipsis;
566 white-space: nowrap;
567 color: var(--color-text-secondary);
568 font-size: 12px;
569 letter-spacing: 0;
570 }
571
572 .editor-close-confirm-actions {
573 display: flex;
574 flex: 0 0 auto;
575 align-items: center;
576 gap: 6px;
577 }
578
579 .editor-toolbar {
580 min-height: 46px;
581 padding: 6px 10px;
582 position: relative;
583 z-index: 20;
584 overflow: visible;
585 background: color-mix(in srgb, var(--color-background), var(--color-panel) 48%);
586 }
587
588 .editor-toolbar-row,
589 .editor-tool-group {
590 display: flex;
591 align-items: center;
592 gap: 5px;
593 min-width: 0;
594 }
595
596 .editor-toolbar-row {
597 width: 100%;
598 overflow: visible;
599 }
600
601 .editor-toolbar-spacer {
602 flex: 1 1 16px;
603 min-width: 8px;
604 }
605
606 .editor-search-count {
607 min-width: 54px;
608 color: var(--color-text-secondary);
609 font-size: 12px;
610 font-weight: 700;
611 letter-spacing: 0;
612 text-align: center;
613 white-space: nowrap;
614 }
615
616 .editor-search-bar {
617 min-height: 40px;
618 background: color-mix(in srgb, var(--color-background), var(--color-panel) 30%);
619 }
620
621 .editor-search-bar input {
622 flex: 1 1 auto;
623 min-width: 90px;
624 height: 30px;
625 border: 1px solid color-mix(in srgb, var(--color-border), transparent 12%);
626 border-radius: 7px;
627 background: var(--color-background);
628 color: var(--color-text);
629 padding: 0 9px;
630 font: inherit;
631 font-size: 13px;
632 }
633
634 .editor-icon-button:hover:not(:disabled) {
635 border-color: color-mix(in srgb, #2c7be5, var(--color-border) 45%);
636 background: color-mix(in srgb, var(--color-panel), #2c7be5 8%);
637 }
638
639 .editor-tab:hover {
640 background: transparent;
641 }
642
643 .editor-tab:focus-visible,
644 .editor-tab-close:focus-visible {
645 outline: 1px solid color-mix(in srgb, var(--color-primary) 70%, transparent);
646 outline-offset: 1px;
647 }
648
649 .editor-tab-icon {
650 flex: 0 0 auto;
651 color: color-mix(in srgb, var(--color-text) 72%, var(--color-primary) 28%);
652 font-size: 1.04rem;
653 line-height: 1;
654 }
655
656 .editor-tab-close:hover {
657 background: color-mix(in srgb, var(--color-background-hover) 70%, transparent);
658 color: var(--color-text);
659 opacity: 1;
660 }
661
662 .editor-new-tab:hover:not(:disabled) {
663 background: color-mix(in srgb, var(--color-background-hover) 58%, transparent);
664 border-color: color-mix(in srgb, var(--color-primary) 24%, transparent);
665 color: var(--color-text);
666 }
667
668 .editor-new-tab:disabled {
669 cursor: default;
670 opacity: 0.42;
671 }
672
673 .editor-tab-close .material-symbols-outlined {
674 font-size: 1rem;
675 line-height: 1;
676 }
677
678 .editor-new-tab .material-symbols-outlined {
679 font-size: 1.12rem;
680 line-height: 1;
681 }
682
683 .editor-icon-button:disabled {
684 cursor: default;
685 opacity: 0.42;
686 }
687
688 .editor-file-actions,
689 .editor-header-actions {
690 position: relative;
691 display: inline-flex;
692 align-items: center;
693 flex: 0 0 auto;
694 z-index: 30;
695 }
696
697 .editor-new-menu {
698 position: absolute;
699 top: calc(100% + 6px);
700 right: 0;
701 z-index: 10000;
702 min-width: 184px;
703 padding: 5px;
704 border: 1px solid color-mix(in srgb, var(--color-border), transparent 10%);
705 border-radius: 8px;
706 background: color-mix(in srgb, var(--color-panel), var(--color-background) 10%);
707 box-shadow: 0 14px 34px rgba(0, 0, 0, 0.34);
708 }
709
710 .editor-new-menu[hidden] {
711 display: none;
712 }
713
714 .editor-new-menu-item,
715 .editor-header-new-button {
716 appearance: none;
717 display: flex;
718 align-items: center;
719 gap: 8px;
720 border: 1px solid transparent;
721 background: transparent;
722 color: var(--color-text);
723 cursor: pointer;
724 font: inherit;
725 font-size: 12px;
726 font-weight: 700;
727 letter-spacing: 0;
728 line-height: 1;
729 white-space: nowrap;
730 }
731
732 .editor-header-new-button {
733 justify-content: center;
734 height: 34px;
735 padding: 0 9px 0 8px;
736 border-radius: 7px;
737 opacity: 0.82;
738 }
739
740 .editor-new-menu-item {
741 width: 100%;
742 height: 32px;
743 padding: 0 8px;
744 border-radius: 6px;
745 text-align: left;
746 }
747
748 .editor-new-menu-item.is-emphasized {
749 color: var(--color-text);
750 background: color-mix(in srgb, #2c7be5 10%, transparent);
751 }
752
753 .editor-text-button {
754 appearance: none;
755 height: 28px;
756 padding: 0 9px;
757 border: 1px solid color-mix(in srgb, var(--color-border), transparent 10%);
758 border-radius: 7px;
759 background: color-mix(in srgb, var(--color-panel), var(--color-background) 18%);
760 color: var(--color-text);
761 cursor: pointer;
762 font: inherit;
763 font-size: 12px;
764 font-weight: 750;
765 letter-spacing: 0;
766 white-space: nowrap;
767 }
768
769 .editor-text-button.is-primary {
770 border-color: color-mix(in srgb, #2c7be5, var(--color-border) 35%);
771 background: color-mix(in srgb, #2c7be5, var(--color-panel) 82%);
772 }
773
774 .editor-header-new-button:hover,
775 .editor-header-actions.is-open .editor-header-new-button,
776 .editor-new-menu-item:hover,
777 .editor-text-button:hover:not(:disabled) {
778 opacity: 1;
779 border-color: color-mix(in srgb, var(--color-primary) 24%, transparent);
780 background: color-mix(in srgb, var(--color-background-hover) 76%, transparent);
781 }
782
783 .editor-text-button:disabled {
784 cursor: default;
785 opacity: 0.45;
786 }
787
788 @container (max-width: 560px) {
789 .editor-close-confirm {
790 align-items: stretch;
791 flex-direction: column;
792 }
793
794 .editor-close-confirm-actions {
795 flex-wrap: wrap;
796 }
797 }
798
799 .editor-body,
800 .editor-wrap,
801 .editor-scroll,
802 .editor-preview-shell {
803 display: flex;
804 flex: 1 1 auto;
805 min-width: 0;
806 min-height: 0;
807 }
808
809 .editor-body {
810 position: relative;
811 flex-direction: column;
812 overflow: hidden;
813 }
814
815 .editor-wrap,
816 .editor-scroll {
817 width: 100%;
818 height: 100%;
819 }
820
821 .editor-scroll {
822 position: relative;
823 }
824
825 .editor-ace {
826 flex: 1 1 auto;
827 width: 100%;
828 height: 100%;
829 min-width: 0;
830 min-height: 0;
831 font: 13px/1.55 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
832 }
833
834 .editor-ace .ace_gutter {
835 display: none !important;
836 }
837
838 .editor-ace .ace_scroller {
839 left: 0 !important;
840 }
841
842 .editor-source-editor {
843 box-sizing: border-box;
844 width: 100%;
845 height: 100%;
846 min-width: 0;
847 min-height: 0;
848 resize: none;
849 border: 0;
850 outline: none;
851 padding: 18px 20px;
852 background: var(--color-background);
853 color: var(--color-text);
854 font: 13px/1.55 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
855 letter-spacing: 0;
856 }
857
858 .editor-preview-shell {
859 flex-direction: column;
860 overflow: hidden;
861 background: var(--color-background);
862 }
863
864 .editor-preview-title {
865 flex: 0 0 auto;
866 padding: 20px 24px 10px;
867 border-bottom: 1px solid color-mix(in srgb, var(--color-border), transparent 30%);
868 }
869
870 .editor-preview-title h1 {
871 margin: 0;
872 color: var(--color-text);
873 font-size: 24px;
874 line-height: 1.2;
875 letter-spacing: 0;
876 }
877
878 .editor-preview-content {
879 flex: 1 1 auto;
880 min-width: 0;
881 min-height: 0;
882 overflow: auto;
883 padding: 20px 24px 36px;
884 color: var(--color-text);
885 line-height: 1.58;
886 }
887
888 .editor-preview-edit-shell {
889 display: flex;
890 flex: 1 1 auto;
891 min-width: 0;
892 min-height: 0;
893 padding: 16px 24px 36px;
894 background: var(--color-background);
895 }
896
897 .editor-preview-page-editor {
898 box-sizing: border-box;
899 flex: 1 1 auto;
900 width: 100%;
901 min-width: 0;
902 min-height: 0;
903 resize: none;
904 border: 1px solid color-mix(in srgb, var(--color-border), transparent 12%);
905 border-radius: 8px;
906 outline: none;
907 padding: 14px 16px;
908 background: color-mix(in srgb, var(--color-panel), var(--color-background) 28%);
909 color: var(--color-text);
910 font: 13px/1.55 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
911 letter-spacing: 0;
912 }
913
914 .editor-preview-page-editor:focus {
915 border-color: color-mix(in srgb, #2c7be5, var(--color-border) 40%);
916 box-shadow: 0 0 0 1px color-mix(in srgb, #2c7be5 24%, transparent);
917 }
918
919 .editor-preview-content img {
920 display: block;
921 max-width: 100%;
922 height: auto;
923 margin: 12px 0;
924 }
925
926 .editor-preview-content h1,
927 .editor-preview-content h2,
928 .editor-preview-content h3,
929 .editor-preview-content h4,
930 .editor-preview-content h5,
931 .editor-preview-content h6 {
932 scroll-margin-top: 16px;
933 letter-spacing: 0;
934 }
935
936 .editor-preview-content blockquote {
937 margin: 12px 0;
938 padding: 1px 0 1px 14px;
939 border-left: 3px solid color-mix(in srgb, var(--color-primary), var(--color-border) 45%);
940 color: var(--color-text-secondary);
941 }
942
943 .editor-table-wrap {
944 max-width: 100%;
945 overflow-x: auto;
946 margin: 14px 0;
947 border: 1px solid color-mix(in srgb, var(--color-border), transparent 12%);
948 border-radius: 8px;
949 }
950
951 .editor-preview-content table {
952 width: 100%;
953 border-collapse: collapse;
954 min-width: 420px;
955 }
956
957 .editor-preview-content th,
958 .editor-preview-content td {
959 border-bottom: 1px solid color-mix(in srgb, var(--color-border), transparent 22%);
960 padding: 8px 10px;
961 text-align: inherit;
962 vertical-align: top;
963 }
964
965 .editor-preview-content th {
966 background: color-mix(in srgb, var(--color-panel), var(--color-background) 24%);
967 font-weight: 800;
968 }
969
970 .editor-preview-content input[type="checkbox"] {
971 margin-right: 6px;
972 cursor: pointer;
973 }
974
975 .editor-code-block {
976 overflow: hidden;
977 margin: 14px 0;
978 border: 1px solid color-mix(in srgb, var(--color-border), transparent 12%);
979 border-radius: 8px;
980 background: color-mix(in srgb, var(--color-panel), var(--color-background) 16%);
981 }
982
983 .editor-code-header {
984 display: flex;
985 align-items: center;
986 justify-content: space-between;
987 gap: 10px;
988 min-height: 32px;
989 padding: 0 8px 0 10px;
990 border-bottom: 1px solid color-mix(in srgb, var(--color-border), transparent 22%);
991 color: var(--color-text-secondary);
992 font-size: 12px;
993 font-weight: 700;
994 }
995
996 .editor-code-copy {
997 height: 24px;
998 border: 1px solid color-mix(in srgb, var(--color-border), transparent 12%);
999 border-radius: 6px;
1000 background: var(--color-background);
1001 color: var(--color-text);
1002 cursor: pointer;
1003 font: inherit;
1004 font-size: 11px;
1005 font-weight: 750;
1006 }
1007
1008 .editor-code-block pre {
1009 margin: 0;
1010 overflow: auto;
1011 padding: 12px;
1012 }
1013
1014 .editor-code-block code {
1015 font: 12px/1.55 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
1016 }
1017
1018 .editor-math-display {
1019 margin: 14px 0;
1020 overflow-x: auto;
1021 text-align: center;
1022 }
1023
1024 .editor-footnotes {
1025 margin-top: 24px;
1026 border-top: 1px solid color-mix(in srgb, var(--color-border), transparent 22%);
1027 color: var(--color-text-secondary);
1028 font-size: 13px;
1029 }
1030
1031 mark.editor-search-mark {
1032 border-radius: 3px;
1033 background: color-mix(in srgb, #d9b12b 55%, transparent);
1034 color: inherit;
1035 padding: 0 1px;
1036 }
1037
1038 mark.editor-search-mark.is-current {
1039 background: color-mix(in srgb, #2c7be5 55%, transparent);
1040 outline: 1px solid color-mix(in srgb, #2c7be5, var(--color-border) 24%);
1041 }
1042
1043 .editor-empty {
1044 display: grid;
1045 flex: 1 1 auto;
1046 place-items: center;
1047 align-content: center;
1048 gap: 12px;
1049 color: color-mix(in srgb, var(--color-text) 70%, transparent);
1050 }
1051
1052 .editor-empty-actions {
1053 display: flex;
1054 gap: 8px;
1055 flex-wrap: wrap;
1056 justify-content: center;
1057 }
1058
1059 .editor-command-button {
1060 display: inline-flex;
1061 width: auto;
1062 max-width: 140px;
1063 padding: 0 9px;
1064 gap: 6px;
1065 }
1066
1067 .editor-button-label {
1068 overflow: hidden;
1069 text-overflow: ellipsis;
1070 white-space: nowrap;
1071 font-size: 11px;
1072 font-weight: 700;
1073 }
1074
1075 .editor-state-line {
1076 min-height: 34px;
1077 font-size: 12px;
1078 color: color-mix(in srgb, var(--color-text) 80%, transparent);
1079 }
1080 </style>
1081 </body>
1082 </html>