@mdzip/editor 1.3.15 → 1.3.17

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/dist/view.js CHANGED
@@ -5,7 +5,7 @@ import { closeSearchPanel, openSearchPanel, search, searchKeymap } from '@codemi
5
5
  import { Compartment, EditorState } from '@codemirror/state';
6
6
  import { Decoration, EditorView, MatchDecorator, ViewPlugin, dropCursor, keymap, lineNumbers } from '@codemirror/view';
7
7
  import { tags } from '@lezer/highlight';
8
- import { Bold, ChevronDown, ChevronRight, ClipboardPaste, ClipboardType, Code, Columns2, Copy, Eraser, Eye, File, FileBraces, FileImage, Folder, FolderOpen, Hash, Heading1, Heading2, Heading3, Heading4, Heading5, Heading6, Highlighter, ImagePlus, Info, Italic, Link2Off, Link, List, ListOrdered, CornerDownLeft, Moon, PackagePlus, PanelLeft, Pilcrow, Quote, Save, Scissors, Search, SquareCode, SquarePen, Strikethrough, Sun, TextSelect, ZoomIn } from 'lucide';
8
+ import { Bold, Check, ChevronDown, ChevronRight, ClipboardPaste, ClipboardType, Code, Columns2, Copy, Eraser, Eye, File, FileBraces, FileImage, Folder, FolderOpen, Hash, Heading1, Heading2, Heading3, Heading4, Heading5, Heading6, Highlighter, ImagePlus, Info, Italic, Link2Off, Link, List, ListOrdered, CornerDownLeft, Moon, PackagePlus, PanelLeft, Pilcrow, Quote, Save, Scissors, Search, SquareCode, SquarePen, Strikethrough, Sun, TextSelect, ZoomIn } from 'lucide';
9
9
  import { browserClipboardHasImage, readBrowserClipboardImage } from './browser.js';
10
10
  import { MdzipAssetSession, mdzipArchiveSourceId, sniffImageSize } from './asset-cache.js';
11
11
  import { MD_MARKDOWN_ICON } from './icons/md-markdown.js';
@@ -54,6 +54,16 @@ const LINK_ICON_HTML = lucideIcon(Link, FORMAT_ICON_CLASS);
54
54
  const IMAGE_FORMAT_ICON_HTML = lucideIcon(ImagePlus, FORMAT_ICON_CLASS);
55
55
  const CHEVRON_ICON_HTML = lucideIcon(ChevronDown, 'format-chevron');
56
56
  const INFO_ICON_HTML = lucideIcon(Info, 'document-info-icon');
57
+ const CODE_BLOCK_ICON_CLASS = 'mdzip-code-block-icon';
58
+ const CODE_BLOCK_COPY_ICON_HTML = lucideIcon(Copy, CODE_BLOCK_ICON_CLASS);
59
+ const CODE_BLOCK_COPIED_ICON_HTML = lucideIcon(Check, CODE_BLOCK_ICON_CLASS);
60
+ const CODE_BLOCK_COLLAPSE_ICON_HTML = lucideIcon(ChevronDown, CODE_BLOCK_ICON_CLASS);
61
+ // Below this, collapsing (240px / ~12 visible lines) would have no visible
62
+ // effect, so the collapse button isn't shown at all rather than appearing to
63
+ // do nothing when clicked.
64
+ const CODE_BLOCK_COLLAPSIBLE_MIN_LINES = 15;
65
+ // Blocks taller than this start collapsed; still manually expandable either way.
66
+ const CODE_BLOCK_AUTO_COLLAPSE_LINES = 25;
57
67
  // Leading icons for context-menu items (Obsidian-style icon column).
58
68
  const MENU_ICON_CLASS = 'nav-menu-icon';
59
69
  const MENU_CUT_ICON_HTML = lucideIcon(Scissors, MENU_ICON_CLASS);
@@ -182,7 +192,8 @@ const CONTROL_PRESETS = {
182
192
  colorScheme: false,
183
193
  orphanActions: false,
184
194
  fileActions: false,
185
- search: false
195
+ search: false,
196
+ codeBlockTools: true
186
197
  },
187
198
  viewer: {
188
199
  preset: 'viewer',
@@ -197,7 +208,8 @@ const CONTROL_PRESETS = {
197
208
  colorScheme: true,
198
209
  orphanActions: false,
199
210
  fileActions: false,
200
- search: true
211
+ search: true,
212
+ codeBlockTools: true
201
213
  },
202
214
  'standalone-editor': {
203
215
  preset: 'standalone-editor',
@@ -212,7 +224,8 @@ const CONTROL_PRESETS = {
212
224
  colorScheme: true,
213
225
  orphanActions: true,
214
226
  fileActions: true,
215
- search: true
227
+ search: true,
228
+ codeBlockTools: true
216
229
  },
217
230
  'hosted-editor': {
218
231
  preset: 'hosted-editor',
@@ -227,7 +240,8 @@ const CONTROL_PRESETS = {
227
240
  colorScheme: true,
228
241
  orphanActions: true,
229
242
  fileActions: true,
230
- search: true
243
+ search: true,
244
+ codeBlockTools: true
231
245
  }
232
246
  };
233
247
  export function resolveMdzipControlPolicy(controls) {
@@ -449,7 +463,7 @@ const mdzipMarkdownHighlight = HighlightStyle.define([
449
463
  { tag: tags.emphasis, color: '#008b8b', fontStyle: 'italic' },
450
464
  { tag: tags.strikethrough, color: '#57606a', textDecoration: 'line-through' },
451
465
  { tag: tags.link, color: '#0969da' },
452
- { tag: tags.url, color: '#0969da' },
466
+ { tag: tags.url, color: '#6e7781' },
453
467
  { tag: tags.monospace, color: '#8a8f00' },
454
468
  { tag: tags.quote, color: '#7a5c00' },
455
469
  { tag: tags.contentSeparator, color: '#6a9955' },
@@ -563,19 +577,19 @@ depth = 0) {
563
577
  : isImageFile(node.entry.path)
564
578
  ? IMAGE_ICON_HTML
565
579
  : FILE_ICON_HTML;
566
- const orphanBtnHtml = isOrphaned && options.allowOrphanActions ? `
567
- <span class="nav-orphan-button" role="button" tabindex="0"
568
- title="Orphaned asset" aria-label="Orphaned asset actions"
569
- data-orphan-path="${safePath}">
570
- ${ORPHAN_ICON_HTML}
580
+ const orphanBtnHtml = isOrphaned && options.allowOrphanActions ? `
581
+ <span class="nav-orphan-button" role="button" tabindex="0"
582
+ title="Orphaned asset" aria-label="Orphaned asset actions"
583
+ data-orphan-path="${safePath}">
584
+ ${ORPHAN_ICON_HTML}
571
585
  </span>` : '';
572
586
  const draggable = options.allowDrag && !isManifest;
573
- return `<button type="button" class="${classes}" title="${title}"
574
- data-nav-path="${safePath}" data-orphan="${isOrphaned ? 'true' : ''}"${draggable ? ' draggable="true"' : ''}>
575
- ${guides}<span class="nav-caret"></span>
576
- <span class="nav-file-icon ${iconKind}">${iconHtml}</span>
577
- ${orphanBtnHtml}
578
- <span class="nav-label">${safeName}</span>
587
+ return `<button type="button" class="${classes}" title="${title}"
588
+ data-nav-path="${safePath}" data-orphan="${isOrphaned ? 'true' : ''}"${draggable ? ' draggable="true"' : ''}>
589
+ ${guides}<span class="nav-caret"></span>
590
+ <span class="nav-file-icon ${iconKind}">${iconHtml}</span>
591
+ ${orphanBtnHtml}
592
+ <span class="nav-label">${safeName}</span>
579
593
  </button>`;
580
594
  }
581
595
  const childTrail = depth === 0 ? [] : [...trail, !isLast];
@@ -583,14 +597,14 @@ depth = 0) {
583
597
  .map((child, index) => renderNavNode(child, state, options, childTrail, index === node.children.length - 1, depth + 1))
584
598
  .join('');
585
599
  const pending = options.pendingFolders.has(node.path.toLowerCase());
586
- return `<details class="nav-directory${pending ? ' pending-folder' : ''}" open data-nav-dir="${escapeHtml(node.path)}">
587
- <summary${pending ? ` title="${escapeHtml(node.path)} — not saved until it contains a file"` : ''}>
588
- ${guides}<span class="nav-caret" aria-hidden="true"></span>
589
- <span class="nav-folder-icon closed">${FOLDER_CLOSED_ICON_HTML}</span>
590
- <span class="nav-folder-icon open">${FOLDER_OPEN_ICON_HTML}</span>
591
- <span class="nav-label">${escapeHtml(node.name)}</span>
592
- </summary>
593
- <div class="nav-directory-children">${children}</div>
600
+ return `<details class="nav-directory${pending ? ' pending-folder' : ''}" open data-nav-dir="${escapeHtml(node.path)}">
601
+ <summary${pending ? ` title="${escapeHtml(node.path)} — not saved until it contains a file"` : ''}>
602
+ ${guides}<span class="nav-caret" aria-hidden="true"></span>
603
+ <span class="nav-folder-icon closed">${FOLDER_CLOSED_ICON_HTML}</span>
604
+ <span class="nav-folder-icon open">${FOLDER_OPEN_ICON_HTML}</span>
605
+ <span class="nav-label">${escapeHtml(node.name)}</span>
606
+ </summary>
607
+ <div class="nav-directory-children">${children}</div>
594
608
  </details>`;
595
609
  }
596
610
  // Inserts view-local pending (not yet saved) folders into the nav tree so they
@@ -1338,6 +1352,10 @@ export class MdzipWorkspaceView {
1338
1352
  mountPreviewHtml(html, snapshot, context, generation) {
1339
1353
  this.elPreviewContent.innerHTML = html;
1340
1354
  this.mountPreviewExtensions(context, generation);
1355
+ const codeBlockHandle = this.mountCodeBlockControls();
1356
+ if (codeBlockHandle) {
1357
+ this.previewHandles.push(codeBlockHandle);
1358
+ }
1341
1359
  // No archive images to resolve on this path: the preview is ready now.
1342
1360
  this.firePreviewRendered(snapshot, generation);
1343
1361
  this.fireAssetsHydrated(snapshot, generation);
@@ -1388,6 +1406,10 @@ export class MdzipWorkspaceView {
1388
1406
  pending.push({ image, slot, source });
1389
1407
  }
1390
1408
  this.mountPreviewExtensions(context, generation);
1409
+ const codeBlockHandle = this.mountCodeBlockControls();
1410
+ if (codeBlockHandle) {
1411
+ this.previewHandles.push(codeBlockHandle);
1412
+ }
1391
1413
  this.firePreviewRendered(snapshot, generation);
1392
1414
  if (!session || pending.length === 0) {
1393
1415
  this.fireAssetsHydrated(snapshot, generation);
@@ -1531,6 +1553,130 @@ export class MdzipWorkspaceView {
1531
1553
  }
1532
1554
  }
1533
1555
  }
1556
+ /**
1557
+ * Built-in preview affordances for rendered code blocks: a language-name
1558
+ * header, a copy-to-clipboard button, and (on long enough blocks) a
1559
+ * collapse/expand toggle. Gated by `controlPolicy.codeBlockTools`.
1560
+ *
1561
+ * Deliberately not a `markdownExtensions` entry (unlike the Mermaid
1562
+ * extension) — every consumer gets this automatically, gated by policy
1563
+ * rather than opt-in wiring. Runs after `mountPreviewExtensions` so any
1564
+ * extension-provided `pre > code` blocks already exist in the DOM. See #29.
1565
+ */
1566
+ mountCodeBlockControls() {
1567
+ if (!this.controlPolicy.codeBlockTools) {
1568
+ return null;
1569
+ }
1570
+ const codeEls = Array.from(this.elPreviewContent.querySelectorAll('pre > code'));
1571
+ if (codeEls.length === 0) {
1572
+ return null;
1573
+ }
1574
+ const doc = this.elPreviewContent.ownerDocument;
1575
+ // Resolve AbortController from the document's own realm, not the ambient
1576
+ // global: addEventListener's `signal` option is validated against the
1577
+ // listener target's realm, so a controller from a different realm (e.g.
1578
+ // Node's global AbortController against a jsdom-hosted element in a
1579
+ // server-side/test environment) fails that check even though both are
1580
+ // spec-compliant AbortControllers.
1581
+ const AbortControllerCtor = doc.defaultView?.AbortController ?? AbortController;
1582
+ const controller = new AbortControllerCtor();
1583
+ for (const code of codeEls) {
1584
+ const pre = code.parentElement;
1585
+ if (pre) {
1586
+ this.enhanceCodeBlock(pre, code, doc, controller.signal);
1587
+ }
1588
+ }
1589
+ return { destroy: () => controller.abort() };
1590
+ }
1591
+ /**
1592
+ * Wraps one `pre > code` block with a header (language label + action
1593
+ * buttons) and a collapsible body, in place. `pre` itself is relocated
1594
+ * (not cloned) into the new structure, so existing references to it and
1595
+ * its `code` child stay valid.
1596
+ */
1597
+ enhanceCodeBlock(pre, code, doc, signal) {
1598
+ const language = /language-([\w-]+)/.exec(code.className)?.[1] ?? '';
1599
+ const wrapper = doc.createElement('div');
1600
+ wrapper.className = 'mdzip-code-block';
1601
+ const header = doc.createElement('div');
1602
+ header.className = 'mdzip-code-block-header';
1603
+ const label = doc.createElement('span');
1604
+ label.className = 'mdzip-code-block-lang';
1605
+ label.textContent = language || 'text';
1606
+ header.appendChild(label);
1607
+ const actions = doc.createElement('div');
1608
+ actions.className = 'mdzip-code-block-actions';
1609
+ header.appendChild(actions);
1610
+ const body = doc.createElement('div');
1611
+ body.className = 'mdzip-code-block-body';
1612
+ pre.replaceWith(wrapper);
1613
+ wrapper.append(header, body);
1614
+ body.appendChild(pre);
1615
+ // Collapse toggle: only shown when the block has enough lines that
1616
+ // collapsing is actually visible — the collapsed body still shows ~12
1617
+ // lines (240px, see .mdzip-code-block-collapsed in view-css.ts), so a
1618
+ // button that collapses a block shorter than that would visibly do
1619
+ // nothing, which is more confusing than not offering it at all. Blocks
1620
+ // past the longer auto-collapse threshold start pre-collapsed; anything
1621
+ // between the two thresholds is collapsible but starts open.
1622
+ const lineCount = (code.textContent ?? '').split('\n').length;
1623
+ if (lineCount > CODE_BLOCK_COLLAPSIBLE_MIN_LINES) {
1624
+ if (lineCount > CODE_BLOCK_AUTO_COLLAPSE_LINES) {
1625
+ wrapper.classList.add('mdzip-code-block-collapsed');
1626
+ }
1627
+ const collapseBtn = doc.createElement('button');
1628
+ collapseBtn.type = 'button';
1629
+ collapseBtn.className = 'mdzip-code-block-btn';
1630
+ collapseBtn.innerHTML = CODE_BLOCK_COLLAPSE_ICON_HTML;
1631
+ const syncCollapseLabel = () => {
1632
+ const collapsed = wrapper.classList.contains('mdzip-code-block-collapsed');
1633
+ collapseBtn.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
1634
+ collapseBtn.setAttribute('aria-label', collapsed ? 'Expand code block' : 'Collapse code block');
1635
+ };
1636
+ syncCollapseLabel();
1637
+ collapseBtn.title = 'Collapse/expand';
1638
+ collapseBtn.addEventListener('click', () => {
1639
+ wrapper.classList.toggle('mdzip-code-block-collapsed');
1640
+ syncCollapseLabel();
1641
+ }, { signal });
1642
+ actions.appendChild(collapseBtn);
1643
+ }
1644
+ // Copy button: icon swaps to a confirmation state for a beat, then reverts.
1645
+ // The revert timer is cleared on unmount so it never touches a stale button
1646
+ // after the preview re-renders.
1647
+ const copyBtn = doc.createElement('button');
1648
+ copyBtn.type = 'button';
1649
+ copyBtn.className = 'mdzip-code-block-btn';
1650
+ copyBtn.innerHTML = CODE_BLOCK_COPY_ICON_HTML;
1651
+ copyBtn.setAttribute('aria-label', 'Copy code');
1652
+ copyBtn.title = 'Copy code';
1653
+ // Re-check clipboard availability at click time rather than capturing it
1654
+ // once at mount: a host can grant/attach clipboard access after the
1655
+ // preview first renders, and this way there is nothing to keep in sync.
1656
+ let copiedTimer;
1657
+ copyBtn.addEventListener('click', () => {
1658
+ const clip = doc.defaultView?.navigator.clipboard;
1659
+ if (!clip) {
1660
+ return;
1661
+ }
1662
+ void clip.writeText(code.textContent ?? '').then(() => {
1663
+ copyBtn.innerHTML = CODE_BLOCK_COPIED_ICON_HTML;
1664
+ copyBtn.classList.add('mdzip-code-block-btn-copied');
1665
+ copyBtn.setAttribute('aria-label', 'Copied');
1666
+ clearTimeout(copiedTimer);
1667
+ copiedTimer = setTimeout(() => {
1668
+ copyBtn.innerHTML = CODE_BLOCK_COPY_ICON_HTML;
1669
+ copyBtn.classList.remove('mdzip-code-block-btn-copied');
1670
+ copyBtn.setAttribute('aria-label', 'Copy code');
1671
+ }, 1500);
1672
+ }).catch(() => {
1673
+ // Write can fail (permissions, insecure context); leave the button
1674
+ // as-is rather than showing a false confirmation.
1675
+ });
1676
+ }, { signal });
1677
+ signal.addEventListener('abort', () => clearTimeout(copiedTimer), { once: true });
1678
+ actions.appendChild(copyBtn);
1679
+ }
1534
1680
  firePreviewRendered(snapshot, generation) {
1535
1681
  if (generation !== this.previewGeneration) {
1536
1682
  return;
@@ -4146,7 +4292,14 @@ export class MdzipWorkspaceView {
4146
4292
  const editorHeight = cmScroller.scrollHeight - cmScroller.clientHeight;
4147
4293
  cmScroller.scrollTop = scrollRatio * editorHeight;
4148
4294
  }
4149
- this.syncing = false;
4295
+ // Programmatically setting scrollTop fires the target's own 'scroll'
4296
+ // event asynchronously (not inline with this assignment), so clearing
4297
+ // the guard synchronously here doesn't actually suppress that echo — it
4298
+ // arrives after `syncing` is already back to false, triggers a sync back
4299
+ // in the other direction, and small rounding differences between the two
4300
+ // panes' scroll ratios compound with each round trip. Clearing on the
4301
+ // next frame keeps the guard up until the echo has had its chance to fire.
4302
+ requestAnimationFrame(() => { this.syncing = false; });
4150
4303
  }
4151
4304
  syncScrollToPreview() {
4152
4305
  if (this.syncing || !this.cmEditor || this.layout !== 'split') {
@@ -4160,7 +4313,8 @@ export class MdzipWorkspaceView {
4160
4313
  const previewHeight = this.elPreviewPane.scrollHeight - this.elPreviewPane.clientHeight;
4161
4314
  this.elPreviewPane.scrollTop = scrollRatio * previewHeight;
4162
4315
  }
4163
- this.syncing = false;
4316
+ // See syncScrollFromPreview: deferred for the same reason.
4317
+ requestAnimationFrame(() => { this.syncing = false; });
4164
4318
  }
4165
4319
  }
4166
4320
  function canShowSourceLayout(snapshot) {
@@ -4299,270 +4453,270 @@ function formatMetadataValue(value) {
4299
4453
  }
4300
4454
  return 'Not available';
4301
4455
  }
4302
- const SHELL_HTML = `
4303
- <section class="mdzip-root">
4304
- <div class="document-strip" data-ref="document-strip" hidden>
4305
- <button type="button" class="title-button" data-ref="title-btn"></button>
4306
- <button type="button" class="document-info-button" data-ref="document-info-btn"
4307
- title="Document information" aria-label="Document information">
4308
- ${INFO_ICON_HTML}
4309
- </button>
4310
- </div>
4311
-
4312
- <header class="toolbar" data-ref="toolbar" hidden>
4313
- <div class="toolbar-start">
4314
- <div class="toolbar-left">
4315
- <button type="button" class="icon-toggle nav-toggle" data-ref="nav-btn" title="Toggle contents" aria-label="Toggle contents">
4316
- ${NAV_TOGGLE_ICON_HTML}
4317
- </button>
4318
- </div>
4319
-
4320
- <div class="edit-toolbar" data-ref="edit-toolbar" role="toolbar" aria-label="Markdown formatting">
4321
- <div class="edit-toolbar-group">
4322
- <button type="button" data-format="bold" data-format-control="bold" title="Bold" aria-label="Bold">${BOLD_ICON_HTML}</button>
4323
- <button type="button" data-format="italic" data-format-control="italic" title="Italic" aria-label="Italic">${ITALIC_ICON_HTML}</button>
4324
- <button type="button" data-format="strike" data-format-control="strikethrough" title="Strikethrough" aria-label="Strikethrough">${STRIKE_ICON_HTML}</button>
4325
- <div class="format-menu" data-format-control="headings">
4326
- <button type="button" class="format-menu-toggle" data-format-menu-toggle
4327
- aria-label="Heading" aria-haspopup="menu" aria-expanded="false">
4328
- ${HEADING_ICON_HTML}${CHEVRON_ICON_HTML}
4329
- </button>
4330
- <div class="format-menu-popover" data-format-menu role="menu" aria-label="Heading level" hidden>
4331
- <button type="button" role="menuitem" data-format="paragraph">Paragraph</button>
4332
- <button type="button" role="menuitem" data-format="heading-1" data-heading-level="1"><strong>H1</strong> Heading 1</button>
4333
- <button type="button" role="menuitem" data-format="heading-2" data-heading-level="2"><strong>H2</strong> Heading 2</button>
4334
- <button type="button" role="menuitem" data-format="heading-3" data-heading-level="3"><strong>H3</strong> Heading 3</button>
4335
- <button type="button" role="menuitem" data-format="heading-4" data-heading-level="4"><strong>H4</strong> Heading 4</button>
4336
- <button type="button" role="menuitem" data-format="heading-5" data-heading-level="5"><strong>H5</strong> Heading 5</button>
4337
- <button type="button" role="menuitem" data-format="heading-6" data-heading-level="6"><strong>H6</strong> Heading 6</button>
4338
- </div>
4339
- </div>
4340
- </div>
4341
- <span class="edit-toolbar-divider" aria-hidden="true"></span>
4342
- <div class="edit-toolbar-group">
4343
- <button type="button" data-format="bullet-list" data-format-control="bulletList" title="Bulleted list" aria-label="Bulleted list">${BULLET_LIST_ICON_HTML}</button>
4344
- <button type="button" data-format="ordered-list" data-format-control="orderedList" title="Numbered list" aria-label="Numbered list">${ORDERED_LIST_ICON_HTML}</button>
4345
- <div class="format-menu" data-format-control="code">
4346
- <button type="button" class="format-menu-toggle" data-format-menu-toggle
4347
- aria-label="Code" aria-haspopup="menu" aria-expanded="false">
4348
- ${CODE_ICON_HTML}${CHEVRON_ICON_HTML}
4349
- </button>
4350
- <div class="format-menu-popover" data-format-menu role="menu" aria-label="Code format" hidden>
4351
- <button type="button" role="menuitem" data-format="code" data-code-kind="inline">Inline code</button>
4352
- <button type="button" role="menuitem" data-format="code-block" data-code-kind="block">Code block</button>
4353
- </div>
4354
- </div>
4355
- <button type="button" data-format="quote" data-format-control="blockquote" title="Blockquote" aria-label="Blockquote">${QUOTE_ICON_HTML}</button>
4356
- <button type="button" data-format="line-break" data-format-control="lineBreak" title="Line break" aria-label="Line break">${LINE_BREAK_ICON_HTML}</button>
4357
- </div>
4358
- <span class="edit-toolbar-divider" aria-hidden="true"></span>
4359
- <div class="edit-toolbar-group">
4360
- <button type="button" data-format="link" data-format-control="link" title="Link" aria-label="Link">${LINK_ICON_HTML}</button>
4361
- <button type="button" data-format="image" data-format-control="image" title="Image" aria-label="Image">${IMAGE_FORMAT_ICON_HTML}</button>
4362
- <input type="file" data-ref="image-input" accept="image/*" hidden />
4363
- </div>
4364
- </div>
4365
- </div>
4366
-
4367
- <div class="toolbar-buttons view-mode-toggle-group" data-ref="layout-controls" role="group" aria-label="Editor layout">
4368
- <button type="button" class="icon-toggle view-mode-toggle" data-ref="source-btn" title="Edit" aria-label="Edit" aria-pressed="false">
4369
- <span class="commandbar-flex-container" data-ref="source-icon">${SOURCE_EDIT_ICON_HTML}</span>
4370
- </button>
4371
- <button type="button" class="icon-toggle view-mode-toggle" data-ref="split-btn" title="Split" aria-label="Split" aria-pressed="false">
4372
- <span class="commandbar-flex-container">
4373
- ${SPLIT_ICON_HTML}
4374
- </span>
4375
- </button>
4376
- <button type="button" class="icon-toggle view-mode-toggle" data-ref="preview-btn" title="View" aria-label="View" aria-pressed="false">
4377
- <span class="commandbar-flex-container">
4378
- ${PREVIEW_ICON_HTML}
4379
- </span>
4380
- </button>
4381
- </div>
4382
-
4383
- <div class="toolbar-controls" data-ref="toolbar-controls">
4384
- <button type="button" class="icon-toggle" data-ref="search-btn" title="Find/replace (Mod-F)" aria-label="Find/replace">
4385
- ${SEARCH_ICON_HTML}
4386
- </button>
4387
- <button type="button" class="icon-toggle" data-ref="save-btn" title="Save" aria-label="Save">
4388
- ${SAVE_ICON_HTML}
4389
- </button>
4390
- <button type="button" class="icon-toggle zoom-toggle" data-ref="zoom-btn" title="Zoom controls" aria-label="Zoom controls">
4391
- ${ZOOM_ICON_HTML}
4392
- </button>
4393
- <div class="theme-toggle-group" data-ref="theme-controls" role="group" aria-label="Color scheme">
4394
- <button type="button" class="icon-toggle theme-toggle" data-ref="dark-theme-btn"
4395
- title="Dark mode" aria-label="Dark mode" aria-pressed="false">
4396
- ${DARK_THEME_ICON_HTML}
4397
- </button>
4398
- <button type="button" class="icon-toggle theme-toggle" data-ref="light-theme-btn"
4399
- title="Light mode" aria-label="Light mode" aria-pressed="false">
4400
- ${LIGHT_THEME_ICON_HTML}
4401
- </button>
4402
- </div>
4403
- <div class="zoom-popover" data-ref="zoom-popover" hidden role="group" aria-label="Zoom">
4404
- <span class="zoom-level" data-ref="zoom-level">100%</span>
4405
- <span class="zoom-stepper">
4406
- <button type="button" data-action="zoom-out" title="Zoom out" aria-label="Zoom out">-</button>
4407
- <button type="button" data-action="zoom-in" title="Zoom in" aria-label="Zoom in">+</button>
4408
- </span>
4409
- <button type="button" class="zoom-reset" data-action="zoom-reset" title="Reset zoom">Reset</button>
4410
- </div>
4411
- </div>
4412
- </header>
4413
-
4414
- <div class="workspace-shell" data-ref="workspace-shell" hidden>
4415
- <aside class="nav-pane" data-ref="nav-pane" aria-label="Package contents">
4416
- <div class="nav-tree" data-ref="nav-tree"></div>
4417
- </aside>
4418
- <div class="nav-resizer" data-ref="nav-resizer"
4419
- role="separator" aria-orientation="vertical" aria-label="Resize contents pane"></div>
4420
-
4421
- <div class="pane-stack" data-ref="pane-stack">
4422
- <section class="pane edit-pane" data-ref="edit-pane">
4423
- <div class="editor-host" data-ref="editor-host"></div>
4424
- </section>
4425
- <div class="split-resizer" data-ref="split-resizer"
4426
- role="separator" aria-orientation="vertical" aria-label="Resize split panes"></div>
4427
- <section class="pane preview-pane" data-ref="preview-pane">
4428
- <article class="preview-content" data-ref="preview-content"></article>
4429
- </section>
4430
- <section class="pane entry-pane" data-ref="entry-pane"></section>
4431
- </div>
4432
- </div>
4433
-
4434
- <div class="title-dialog-backdrop" data-ref="title-dialog" hidden
4435
- role="dialog" aria-modal="true" aria-labelledby="mdzip-title-dialog-heading">
4436
- <div class="title-dialog">
4437
- <h3 id="mdzip-title-dialog-heading">Set Document Title</h3>
4438
- <p>This is the package-level title stored in manifest.json.</p>
4439
- <input type="text" maxlength="120" data-ref="title-input" aria-label="Document title" />
4440
- <p class="title-dialog-validation" data-ref="title-validation" hidden>Title cannot be empty.</p>
4441
- <p>If unset, consumers may fall back to entry point, filename, or first heading.</p>
4442
- <div class="title-dialog-actions">
4443
- <button type="button" class="reset-title" data-ref="title-reset-btn">Reset</button>
4444
- <button type="button" data-action="cancel-title">Cancel</button>
4445
- <button type="button" class="save-title" data-ref="title-save-btn">Save</button>
4446
- </div>
4447
- </div>
4448
- </div>
4449
-
4450
- <div class="title-dialog-backdrop" data-ref="conversion-dialog" hidden
4451
- role="dialog" aria-modal="true" aria-labelledby="mdzip-conversion-dialog-heading">
4452
- <div class="title-dialog">
4453
- <h3 id="mdzip-conversion-dialog-heading">Convert to MDZ?</h3>
4454
- <p>
4455
- Regular Markdown files contain only text. Convert this document to an
4456
- MDZ package to add images, package navigation, and document metadata.
4457
- </p>
4458
- <p>The next save will produce an .mdz file.</p>
4459
- <div class="title-dialog-actions">
4460
- <button type="button" data-action="cancel-conversion">Cancel</button>
4461
- <button type="button" class="save-title" data-ref="conversion-confirm-btn">Convert</button>
4462
- </div>
4463
- </div>
4464
- </div>
4465
-
4466
- <div class="title-dialog-backdrop" data-ref="image-insert-dialog" hidden
4467
- role="dialog" aria-modal="true" aria-labelledby="mdzip-image-insert-dialog-heading">
4468
- <div class="title-dialog image-insert-dialog">
4469
- <h3 id="mdzip-image-insert-dialog-heading">Insert Image</h3>
4470
- <p>Choose the Markdown inserted for this image.</p>
4471
- <fieldset class="image-insert-options">
4472
- <legend>Output</legend>
4473
- <label>
4474
- <input type="radio" name="mdzip-image-insert-mode" value="markdown"
4475
- data-ref="image-insert-mode-markdown" checked />
4476
- Markdown image
4477
- </label>
4478
- <label>
4479
- <input type="radio" name="mdzip-image-insert-mode" value="html"
4480
- data-ref="image-insert-mode-html" />
4481
- HTML &lt;img&gt; with sizing
4482
- </label>
4483
- </fieldset>
4484
- <label class="image-insert-field">
4485
- <span>Alt text</span>
4486
- <input type="text" data-ref="image-insert-alt" />
4487
- </label>
4488
- <div class="image-insert-grid">
4489
- <label class="image-insert-field">
4490
- <span>Size by</span>
4491
- <select data-ref="image-insert-size-mode">
4492
- <option value="original">Original size</option>
4493
- <option value="width" selected>Width</option>
4494
- <option value="height">Height</option>
4495
- <option value="percent">Percent</option>
4496
- </select>
4497
- </label>
4498
- <label class="image-insert-field">
4499
- <span>Value</span>
4500
- <input type="number" min="1" step="1" data-ref="image-insert-size-value" />
4501
- </label>
4502
- </div>
4503
- <label class="image-insert-field">
4504
- <span>Position</span>
4505
- <select data-ref="image-insert-position">
4506
- <option value="inline">Inline/default</option>
4507
- <option value="left">Left</option>
4508
- <option value="center">Center</option>
4509
- <option value="right">Right</option>
4510
- <option value="wrap-left">Wrap left</option>
4511
- <option value="wrap-right">Wrap right</option>
4512
- </select>
4513
- </label>
4514
- <div class="title-dialog-actions">
4515
- <button type="button" data-action="cancel-image-insert">Cancel</button>
4516
- <button type="button" class="save-title" data-ref="image-insert-confirm-btn">Insert</button>
4517
- </div>
4518
- </div>
4519
- </div>
4520
-
4521
- <div class="title-dialog-backdrop" data-ref="metadata-dialog" hidden
4522
- role="dialog" aria-modal="true" aria-labelledby="mdzip-metadata-dialog-heading">
4523
- <div class="title-dialog metadata-dialog">
4524
- <h3 id="mdzip-metadata-dialog-heading">Document Information</h3>
4525
- <dl data-ref="metadata-list"></dl>
4526
- <h4>Libraries</h4>
4527
- <dl data-ref="library-list"></dl>
4528
- <div class="title-dialog-actions">
4529
- <button type="button" class="save-title" data-action="close-metadata">Close</button>
4530
- </div>
4531
- </div>
4532
- </div>
4533
-
4534
- <div class="title-dialog-backdrop" data-ref="name-dialog" hidden
4535
- role="dialog" aria-modal="true" aria-labelledby="mdzip-name-dialog-heading">
4536
- <div class="title-dialog">
4537
- <h3 id="mdzip-name-dialog-heading" data-ref="name-dialog-heading">New Markdown File</h3>
4538
- <input type="text" maxlength="260" data-ref="name-input" aria-label="File name" />
4539
- <p class="title-dialog-validation" data-ref="name-validation" hidden></p>
4540
- <div class="title-dialog-actions">
4541
- <button type="button" data-action="cancel-name">Cancel</button>
4542
- <button type="button" class="save-title" data-ref="name-confirm-btn">Create</button>
4543
- </div>
4544
- </div>
4545
- </div>
4546
-
4547
- <div class="title-dialog-backdrop" data-ref="delete-dialog" hidden
4548
- role="dialog" aria-modal="true" aria-labelledby="mdzip-delete-dialog-heading">
4549
- <div class="title-dialog">
4550
- <h3 id="mdzip-delete-dialog-heading">Delete File?</h3>
4551
- <p data-ref="delete-dialog-text"></p>
4552
- <div class="title-dialog-actions">
4553
- <button type="button" data-action="cancel-delete">Cancel</button>
4554
- <button type="button" class="danger-action" data-ref="delete-confirm-btn">Delete</button>
4555
- </div>
4556
- </div>
4557
- </div>
4558
-
4559
- <input type="file" data-ref="replace-input" hidden />
4560
-
4561
- <div class="nav-context-menu" data-ref="nav-menu" hidden role="menu"></div>
4562
-
4563
- <div class="mdzip-tooltip" data-ref="tooltip" role="tooltip" hidden></div>
4564
-
4565
- <p class="mdzip-empty" data-ref="empty-state">No MDZip workspace loaded.</p>
4566
- </section>
4456
+ const SHELL_HTML = `
4457
+ <section class="mdzip-root">
4458
+ <div class="document-strip" data-ref="document-strip" hidden>
4459
+ <button type="button" class="title-button" data-ref="title-btn"></button>
4460
+ <button type="button" class="document-info-button" data-ref="document-info-btn"
4461
+ title="Document information" aria-label="Document information">
4462
+ ${INFO_ICON_HTML}
4463
+ </button>
4464
+ </div>
4465
+
4466
+ <header class="toolbar" data-ref="toolbar" hidden>
4467
+ <div class="toolbar-start">
4468
+ <div class="toolbar-left">
4469
+ <button type="button" class="icon-toggle nav-toggle" data-ref="nav-btn" title="Toggle contents" aria-label="Toggle contents">
4470
+ ${NAV_TOGGLE_ICON_HTML}
4471
+ </button>
4472
+ </div>
4473
+
4474
+ <div class="edit-toolbar" data-ref="edit-toolbar" role="toolbar" aria-label="Markdown formatting">
4475
+ <div class="edit-toolbar-group">
4476
+ <button type="button" data-format="bold" data-format-control="bold" title="Bold" aria-label="Bold">${BOLD_ICON_HTML}</button>
4477
+ <button type="button" data-format="italic" data-format-control="italic" title="Italic" aria-label="Italic">${ITALIC_ICON_HTML}</button>
4478
+ <button type="button" data-format="strike" data-format-control="strikethrough" title="Strikethrough" aria-label="Strikethrough">${STRIKE_ICON_HTML}</button>
4479
+ <div class="format-menu" data-format-control="headings">
4480
+ <button type="button" class="format-menu-toggle" data-format-menu-toggle
4481
+ aria-label="Heading" aria-haspopup="menu" aria-expanded="false">
4482
+ ${HEADING_ICON_HTML}${CHEVRON_ICON_HTML}
4483
+ </button>
4484
+ <div class="format-menu-popover" data-format-menu role="menu" aria-label="Heading level" hidden>
4485
+ <button type="button" role="menuitem" data-format="paragraph">Paragraph</button>
4486
+ <button type="button" role="menuitem" data-format="heading-1" data-heading-level="1"><strong>H1</strong> Heading 1</button>
4487
+ <button type="button" role="menuitem" data-format="heading-2" data-heading-level="2"><strong>H2</strong> Heading 2</button>
4488
+ <button type="button" role="menuitem" data-format="heading-3" data-heading-level="3"><strong>H3</strong> Heading 3</button>
4489
+ <button type="button" role="menuitem" data-format="heading-4" data-heading-level="4"><strong>H4</strong> Heading 4</button>
4490
+ <button type="button" role="menuitem" data-format="heading-5" data-heading-level="5"><strong>H5</strong> Heading 5</button>
4491
+ <button type="button" role="menuitem" data-format="heading-6" data-heading-level="6"><strong>H6</strong> Heading 6</button>
4492
+ </div>
4493
+ </div>
4494
+ </div>
4495
+ <span class="edit-toolbar-divider" aria-hidden="true"></span>
4496
+ <div class="edit-toolbar-group">
4497
+ <button type="button" data-format="bullet-list" data-format-control="bulletList" title="Bulleted list" aria-label="Bulleted list">${BULLET_LIST_ICON_HTML}</button>
4498
+ <button type="button" data-format="ordered-list" data-format-control="orderedList" title="Numbered list" aria-label="Numbered list">${ORDERED_LIST_ICON_HTML}</button>
4499
+ <div class="format-menu" data-format-control="code">
4500
+ <button type="button" class="format-menu-toggle" data-format-menu-toggle
4501
+ aria-label="Code" aria-haspopup="menu" aria-expanded="false">
4502
+ ${CODE_ICON_HTML}${CHEVRON_ICON_HTML}
4503
+ </button>
4504
+ <div class="format-menu-popover" data-format-menu role="menu" aria-label="Code format" hidden>
4505
+ <button type="button" role="menuitem" data-format="code" data-code-kind="inline">Inline code</button>
4506
+ <button type="button" role="menuitem" data-format="code-block" data-code-kind="block">Code block</button>
4507
+ </div>
4508
+ </div>
4509
+ <button type="button" data-format="quote" data-format-control="blockquote" title="Blockquote" aria-label="Blockquote">${QUOTE_ICON_HTML}</button>
4510
+ <button type="button" data-format="line-break" data-format-control="lineBreak" title="Line break" aria-label="Line break">${LINE_BREAK_ICON_HTML}</button>
4511
+ </div>
4512
+ <span class="edit-toolbar-divider" aria-hidden="true"></span>
4513
+ <div class="edit-toolbar-group">
4514
+ <button type="button" data-format="link" data-format-control="link" title="Link" aria-label="Link">${LINK_ICON_HTML}</button>
4515
+ <button type="button" data-format="image" data-format-control="image" title="Image" aria-label="Image">${IMAGE_FORMAT_ICON_HTML}</button>
4516
+ <input type="file" data-ref="image-input" accept="image/*" hidden />
4517
+ </div>
4518
+ </div>
4519
+ </div>
4520
+
4521
+ <div class="toolbar-buttons view-mode-toggle-group" data-ref="layout-controls" role="group" aria-label="Editor layout">
4522
+ <button type="button" class="icon-toggle view-mode-toggle" data-ref="source-btn" title="Edit" aria-label="Edit" aria-pressed="false">
4523
+ <span class="commandbar-flex-container" data-ref="source-icon">${SOURCE_EDIT_ICON_HTML}</span>
4524
+ </button>
4525
+ <button type="button" class="icon-toggle view-mode-toggle" data-ref="split-btn" title="Split" aria-label="Split" aria-pressed="false">
4526
+ <span class="commandbar-flex-container">
4527
+ ${SPLIT_ICON_HTML}
4528
+ </span>
4529
+ </button>
4530
+ <button type="button" class="icon-toggle view-mode-toggle" data-ref="preview-btn" title="View" aria-label="View" aria-pressed="false">
4531
+ <span class="commandbar-flex-container">
4532
+ ${PREVIEW_ICON_HTML}
4533
+ </span>
4534
+ </button>
4535
+ </div>
4536
+
4537
+ <div class="toolbar-controls" data-ref="toolbar-controls">
4538
+ <button type="button" class="icon-toggle" data-ref="search-btn" title="Find/replace (Mod-F)" aria-label="Find/replace">
4539
+ ${SEARCH_ICON_HTML}
4540
+ </button>
4541
+ <button type="button" class="icon-toggle" data-ref="save-btn" title="Save" aria-label="Save">
4542
+ ${SAVE_ICON_HTML}
4543
+ </button>
4544
+ <button type="button" class="icon-toggle zoom-toggle" data-ref="zoom-btn" title="Zoom controls" aria-label="Zoom controls">
4545
+ ${ZOOM_ICON_HTML}
4546
+ </button>
4547
+ <div class="theme-toggle-group" data-ref="theme-controls" role="group" aria-label="Color scheme">
4548
+ <button type="button" class="icon-toggle theme-toggle" data-ref="dark-theme-btn"
4549
+ title="Dark mode" aria-label="Dark mode" aria-pressed="false">
4550
+ ${DARK_THEME_ICON_HTML}
4551
+ </button>
4552
+ <button type="button" class="icon-toggle theme-toggle" data-ref="light-theme-btn"
4553
+ title="Light mode" aria-label="Light mode" aria-pressed="false">
4554
+ ${LIGHT_THEME_ICON_HTML}
4555
+ </button>
4556
+ </div>
4557
+ <div class="zoom-popover" data-ref="zoom-popover" hidden role="group" aria-label="Zoom">
4558
+ <span class="zoom-level" data-ref="zoom-level">100%</span>
4559
+ <span class="zoom-stepper">
4560
+ <button type="button" data-action="zoom-out" title="Zoom out" aria-label="Zoom out">-</button>
4561
+ <button type="button" data-action="zoom-in" title="Zoom in" aria-label="Zoom in">+</button>
4562
+ </span>
4563
+ <button type="button" class="zoom-reset" data-action="zoom-reset" title="Reset zoom">Reset</button>
4564
+ </div>
4565
+ </div>
4566
+ </header>
4567
+
4568
+ <div class="workspace-shell" data-ref="workspace-shell" hidden>
4569
+ <aside class="nav-pane" data-ref="nav-pane" aria-label="Package contents">
4570
+ <div class="nav-tree" data-ref="nav-tree"></div>
4571
+ </aside>
4572
+ <div class="nav-resizer" data-ref="nav-resizer"
4573
+ role="separator" aria-orientation="vertical" aria-label="Resize contents pane"></div>
4574
+
4575
+ <div class="pane-stack" data-ref="pane-stack">
4576
+ <section class="pane edit-pane" data-ref="edit-pane">
4577
+ <div class="editor-host" data-ref="editor-host"></div>
4578
+ </section>
4579
+ <div class="split-resizer" data-ref="split-resizer"
4580
+ role="separator" aria-orientation="vertical" aria-label="Resize split panes"></div>
4581
+ <section class="pane preview-pane" data-ref="preview-pane">
4582
+ <article class="preview-content" data-ref="preview-content"></article>
4583
+ </section>
4584
+ <section class="pane entry-pane" data-ref="entry-pane"></section>
4585
+ </div>
4586
+ </div>
4587
+
4588
+ <div class="title-dialog-backdrop" data-ref="title-dialog" hidden
4589
+ role="dialog" aria-modal="true" aria-labelledby="mdzip-title-dialog-heading">
4590
+ <div class="title-dialog">
4591
+ <h3 id="mdzip-title-dialog-heading">Set Document Title</h3>
4592
+ <p>This is the package-level title stored in manifest.json.</p>
4593
+ <input type="text" maxlength="120" data-ref="title-input" aria-label="Document title" />
4594
+ <p class="title-dialog-validation" data-ref="title-validation" hidden>Title cannot be empty.</p>
4595
+ <p>If unset, consumers may fall back to entry point, filename, or first heading.</p>
4596
+ <div class="title-dialog-actions">
4597
+ <button type="button" class="reset-title" data-ref="title-reset-btn">Reset</button>
4598
+ <button type="button" data-action="cancel-title">Cancel</button>
4599
+ <button type="button" class="save-title" data-ref="title-save-btn">Save</button>
4600
+ </div>
4601
+ </div>
4602
+ </div>
4603
+
4604
+ <div class="title-dialog-backdrop" data-ref="conversion-dialog" hidden
4605
+ role="dialog" aria-modal="true" aria-labelledby="mdzip-conversion-dialog-heading">
4606
+ <div class="title-dialog">
4607
+ <h3 id="mdzip-conversion-dialog-heading">Convert to MDZ?</h3>
4608
+ <p>
4609
+ Regular Markdown files contain only text. Convert this document to an
4610
+ MDZ package to add images, package navigation, and document metadata.
4611
+ </p>
4612
+ <p>The next save will produce an .mdz file.</p>
4613
+ <div class="title-dialog-actions">
4614
+ <button type="button" data-action="cancel-conversion">Cancel</button>
4615
+ <button type="button" class="save-title" data-ref="conversion-confirm-btn">Convert</button>
4616
+ </div>
4617
+ </div>
4618
+ </div>
4619
+
4620
+ <div class="title-dialog-backdrop" data-ref="image-insert-dialog" hidden
4621
+ role="dialog" aria-modal="true" aria-labelledby="mdzip-image-insert-dialog-heading">
4622
+ <div class="title-dialog image-insert-dialog">
4623
+ <h3 id="mdzip-image-insert-dialog-heading">Insert Image</h3>
4624
+ <p>Choose the Markdown inserted for this image.</p>
4625
+ <fieldset class="image-insert-options">
4626
+ <legend>Output</legend>
4627
+ <label>
4628
+ <input type="radio" name="mdzip-image-insert-mode" value="markdown"
4629
+ data-ref="image-insert-mode-markdown" checked />
4630
+ Markdown image
4631
+ </label>
4632
+ <label>
4633
+ <input type="radio" name="mdzip-image-insert-mode" value="html"
4634
+ data-ref="image-insert-mode-html" />
4635
+ HTML &lt;img&gt; with sizing
4636
+ </label>
4637
+ </fieldset>
4638
+ <label class="image-insert-field">
4639
+ <span>Alt text</span>
4640
+ <input type="text" data-ref="image-insert-alt" />
4641
+ </label>
4642
+ <div class="image-insert-grid">
4643
+ <label class="image-insert-field">
4644
+ <span>Size by</span>
4645
+ <select data-ref="image-insert-size-mode">
4646
+ <option value="original">Original size</option>
4647
+ <option value="width" selected>Width</option>
4648
+ <option value="height">Height</option>
4649
+ <option value="percent">Percent</option>
4650
+ </select>
4651
+ </label>
4652
+ <label class="image-insert-field">
4653
+ <span>Value</span>
4654
+ <input type="number" min="1" step="1" data-ref="image-insert-size-value" />
4655
+ </label>
4656
+ </div>
4657
+ <label class="image-insert-field">
4658
+ <span>Position</span>
4659
+ <select data-ref="image-insert-position">
4660
+ <option value="inline">Inline/default</option>
4661
+ <option value="left">Left</option>
4662
+ <option value="center">Center</option>
4663
+ <option value="right">Right</option>
4664
+ <option value="wrap-left">Wrap left</option>
4665
+ <option value="wrap-right">Wrap right</option>
4666
+ </select>
4667
+ </label>
4668
+ <div class="title-dialog-actions">
4669
+ <button type="button" data-action="cancel-image-insert">Cancel</button>
4670
+ <button type="button" class="save-title" data-ref="image-insert-confirm-btn">Insert</button>
4671
+ </div>
4672
+ </div>
4673
+ </div>
4674
+
4675
+ <div class="title-dialog-backdrop" data-ref="metadata-dialog" hidden
4676
+ role="dialog" aria-modal="true" aria-labelledby="mdzip-metadata-dialog-heading">
4677
+ <div class="title-dialog metadata-dialog">
4678
+ <h3 id="mdzip-metadata-dialog-heading">Document Information</h3>
4679
+ <dl data-ref="metadata-list"></dl>
4680
+ <h4>Libraries</h4>
4681
+ <dl data-ref="library-list"></dl>
4682
+ <div class="title-dialog-actions">
4683
+ <button type="button" class="save-title" data-action="close-metadata">Close</button>
4684
+ </div>
4685
+ </div>
4686
+ </div>
4687
+
4688
+ <div class="title-dialog-backdrop" data-ref="name-dialog" hidden
4689
+ role="dialog" aria-modal="true" aria-labelledby="mdzip-name-dialog-heading">
4690
+ <div class="title-dialog">
4691
+ <h3 id="mdzip-name-dialog-heading" data-ref="name-dialog-heading">New Markdown File</h3>
4692
+ <input type="text" maxlength="260" data-ref="name-input" aria-label="File name" />
4693
+ <p class="title-dialog-validation" data-ref="name-validation" hidden></p>
4694
+ <div class="title-dialog-actions">
4695
+ <button type="button" data-action="cancel-name">Cancel</button>
4696
+ <button type="button" class="save-title" data-ref="name-confirm-btn">Create</button>
4697
+ </div>
4698
+ </div>
4699
+ </div>
4700
+
4701
+ <div class="title-dialog-backdrop" data-ref="delete-dialog" hidden
4702
+ role="dialog" aria-modal="true" aria-labelledby="mdzip-delete-dialog-heading">
4703
+ <div class="title-dialog">
4704
+ <h3 id="mdzip-delete-dialog-heading">Delete File?</h3>
4705
+ <p data-ref="delete-dialog-text"></p>
4706
+ <div class="title-dialog-actions">
4707
+ <button type="button" data-action="cancel-delete">Cancel</button>
4708
+ <button type="button" class="danger-action" data-ref="delete-confirm-btn">Delete</button>
4709
+ </div>
4710
+ </div>
4711
+ </div>
4712
+
4713
+ <input type="file" data-ref="replace-input" hidden />
4714
+
4715
+ <div class="nav-context-menu" data-ref="nav-menu" hidden role="menu"></div>
4716
+
4717
+ <div class="mdzip-tooltip" data-ref="tooltip" role="tooltip" hidden></div>
4718
+
4719
+ <p class="mdzip-empty" data-ref="empty-state">No MDZip workspace loaded.</p>
4720
+ </section>
4567
4721
  `;
4568
4722
  //# sourceMappingURL=view.js.map