@hcu-lab.me/mcp-device 1.0.1 → 1.0.3

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.
Files changed (47) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +70 -51
  3. package/dist/bootstrap.js +0 -0
  4. package/dist/command-manager.js +0 -0
  5. package/dist/config-field-definitions.js +0 -0
  6. package/dist/config-manager.js +0 -0
  7. package/dist/config.js +0 -0
  8. package/dist/custom-stdio.js +0 -0
  9. package/dist/data/official-app-ca.pem +12 -12
  10. package/dist/data/onboarding-prompts.json +70 -70
  11. package/dist/device/gateway-config.d.ts +1 -9
  12. package/dist/device/gateway-config.js +7 -27
  13. package/dist/device/gateway-identity.d.ts +2 -11
  14. package/dist/device/gateway-identity.js +11 -52
  15. package/dist/error-handlers.js +0 -0
  16. package/dist/handlers/filesystem-handlers.js +2 -2
  17. package/dist/index.js +0 -0
  18. package/dist/mcp-device.js +0 -0
  19. package/dist/search-manager.js +0 -0
  20. package/dist/server.js +656 -656
  21. package/dist/terminal-manager.js +0 -0
  22. package/dist/tools/edit.js +2 -2
  23. package/dist/tools/fuzzySearch.js +9 -9
  24. package/dist/tools/improved-process-tools.js +10 -10
  25. package/dist/tools/prompts.js +1 -1
  26. package/dist/types.js +0 -0
  27. package/dist/ui/config-editor/index.html +13 -13
  28. package/dist/ui/config-editor/src/app.js +30 -30
  29. package/dist/ui/config-editor/src/array-modal.js +32 -32
  30. package/dist/ui/config-editor/styles.css +586 -586
  31. package/dist/ui/file-preview/index.html +16 -16
  32. package/dist/ui/file-preview/src/app.js +8 -8
  33. package/dist/ui/file-preview/src/document-layout.js +31 -31
  34. package/dist/ui/file-preview/src/document-outline.js +8 -8
  35. package/dist/ui/file-preview/src/markdown/conflict-dialog.js +33 -33
  36. package/dist/ui/file-preview/src/markdown/controller.js +9 -9
  37. package/dist/ui/file-preview/src/markdown/editor.js +31 -31
  38. package/dist/ui/file-preview/styles.css +1630 -1630
  39. package/dist/utils/files/binary.js +4 -4
  40. package/dist/utils/files/excel.js +3 -3
  41. package/dist/utils/system-info.js +90 -90
  42. package/dist/utils/usageTracker.js +49 -49
  43. package/dist/version.d.ts +1 -1
  44. package/dist/version.js +1 -1
  45. package/package.json +131 -131
  46. package/dist/device/windows-dpapi.d.ts +0 -11
  47. package/dist/device/windows-dpapi.js +0 -67
@@ -1,16 +1,16 @@
1
- <!doctype html>
2
- <!--
3
- Host page for the File Preview MCP UI. It establishes the root structure and script/style loading required to render text, markdown, and HTML previews safely.
4
- -->
5
- <html lang="en">
6
- <head>
7
- <meta charset="utf-8" />
8
- <meta name="viewport" content="width=device-width, initial-scale=1" />
9
- <title>Desktop Commander File Preview</title>
10
- <link rel="stylesheet" href="./styles.css" />
11
- </head>
12
- <body>
13
- <div id="app"></div>
14
- <script src="./preview-runtime.js"></script>
15
- </body>
16
- </html>
1
+ <!doctype html>
2
+ <!--
3
+ Host page for the File Preview MCP UI. It establishes the root structure and script/style loading required to render text, markdown, and HTML previews safely.
4
+ -->
5
+ <html lang="en">
6
+ <head>
7
+ <meta charset="utf-8" />
8
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
9
+ <title>Desktop Commander File Preview</title>
10
+ <link rel="stylesheet" href="./styles.css" />
11
+ </head>
12
+ <body>
13
+ <div id="app"></div>
14
+ <script src="./preview-runtime.js"></script>
15
+ </body>
16
+ </html>
@@ -234,18 +234,18 @@ function clearPreviewWatchdog() {
234
234
  }
235
235
  function renderStatusState(container, message) {
236
236
  clearPreviewWatchdog();
237
- container.innerHTML = `
238
- <main class="shell">
239
- ${renderCompactRow({ label: message, variant: 'status', interactive: false })}
240
- </main>
237
+ container.innerHTML = `
238
+ <main class="shell">
239
+ ${renderCompactRow({ label: message, variant: 'status', interactive: false })}
240
+ </main>
241
241
  `;
242
242
  document.body.classList.add('dc-ready');
243
243
  }
244
244
  function renderLoadingState(container) {
245
- container.innerHTML = `
246
- <main class="shell">
247
- ${renderCompactRow({ label: 'Preparing preview…', variant: 'loading', interactive: false })}
248
- </main>
245
+ container.innerHTML = `
246
+ <main class="shell">
247
+ ${renderCompactRow({ label: 'Preparing preview…', variant: 'loading', interactive: false })}
248
+ </main>
249
249
  `;
250
250
  document.body.classList.add('dc-ready');
251
251
  // Fall back to a failure row if nothing renders in time. Any successful
@@ -73,37 +73,37 @@ export function buildDocumentLayout(options) {
73
73
  const canCopy = options.capabilities.canCopy;
74
74
  return {
75
75
  effectiveExpanded,
76
- html: `
77
- <main id="tool-shell" class="shell tool-shell ${effectiveExpanded ? 'expanded' : 'collapsed'}${options.hideSummaryRow ? ' host-framed' : ''}${isFullscreen ? ' fullscreen' : ''}">
78
- ${isFullscreen ? '' : renderCompactRow({ id: 'compact-toggle', label: compactLabel, filename: options.payload.fileName, variant: 'ready', expandable: true, expanded: options.isExpanded, interactive: true })}
79
- <section class="panel">
80
- <div class="panel-topbar">
81
- ${backButton}
82
- ${options.hideSummaryRow ? '' : `<span class="panel-breadcrumb" title="${escapeHtml(options.payload.filePath)}">${breadcrumb}</span>`}
83
- <span class="panel-topbar-actions">
84
- ${isMarkdownEdit ? renderMarkdownSaveStatus(options.markdownWorkspace) : ''}
85
- ${htmlToggle}
86
- ${isMarkdownEdit && isFullscreen ? renderMarkdownModeToggle(options.markdownWorkspace.editorView) : ''}
87
- ${isMarkdown && !isFullscreen && options.canGoFullscreen ? `<button class="panel-action" id="expand-fullscreen" title="Expand" aria-label="Expand">${renderExpandIcon()}</button>` : ''}
88
- ${isMarkdownEdit ? `<button class="panel-action" id="revert-markdown" ${isFullscreen ? '' : 'title="Undo" aria-label="Undo" '}${revertDisabled ? 'disabled' : ''}>${renderUndoIcon()}${isFullscreen ? ' Undo' : ''}</button>` : ''}
89
- ${isMarkdownEdit && isFullscreen ? renderMarkdownCopyButton() : ''}
90
- ${isMarkdown && !isFullscreen ? `<button class="panel-action" id="copy-active-markdown" title="Copy" aria-label="Copy">${renderCopyIcon()}</button>` : ''}
91
- ${canCopy && options.capabilities.supportsPreview && !isMarkdown ? `<button class="panel-action" id="copy-source" title="Copy source" aria-label="Copy source">${renderCopyIcon()}</button>` : ''}
92
- ${canOpenInFolder && isMarkdownEdit && isFullscreen ? `<button class="panel-action" id="open-in-editor" ${fileDeleted ? 'disabled' : ''}>${options.markdownEditorAppIcon} Open in ${escapeHtml(options.defaultMarkdownEditorName ?? 'editor')}</button>` : ''}
93
- ${canOpenInFolder && !(isMarkdownEdit && isFullscreen) ? `<button class="panel-action" id="open-in-folder" title="Open in folder" aria-label="Open in folder" ${isMarkdownEdit && fileDeleted ? 'disabled' : ''}>${renderFolderIcon()}</button>` : ''}
94
- </span>
95
- </div>
96
- ${notice}
97
- <div class="panel-content-wrapper">
98
- ${loadBeforeBanner}
99
- ${options.body.html}
100
- ${loadAfterBanner}
101
- </div>
102
- <div class="panel-footer">
103
- <span>${footerLabel}</span>
104
- </div>
105
- </section>
106
- </main>
76
+ html: `
77
+ <main id="tool-shell" class="shell tool-shell ${effectiveExpanded ? 'expanded' : 'collapsed'}${options.hideSummaryRow ? ' host-framed' : ''}${isFullscreen ? ' fullscreen' : ''}">
78
+ ${isFullscreen ? '' : renderCompactRow({ id: 'compact-toggle', label: compactLabel, filename: options.payload.fileName, variant: 'ready', expandable: true, expanded: options.isExpanded, interactive: true })}
79
+ <section class="panel">
80
+ <div class="panel-topbar">
81
+ ${backButton}
82
+ ${options.hideSummaryRow ? '' : `<span class="panel-breadcrumb" title="${escapeHtml(options.payload.filePath)}">${breadcrumb}</span>`}
83
+ <span class="panel-topbar-actions">
84
+ ${isMarkdownEdit ? renderMarkdownSaveStatus(options.markdownWorkspace) : ''}
85
+ ${htmlToggle}
86
+ ${isMarkdownEdit && isFullscreen ? renderMarkdownModeToggle(options.markdownWorkspace.editorView) : ''}
87
+ ${isMarkdown && !isFullscreen && options.canGoFullscreen ? `<button class="panel-action" id="expand-fullscreen" title="Expand" aria-label="Expand">${renderExpandIcon()}</button>` : ''}
88
+ ${isMarkdownEdit ? `<button class="panel-action" id="revert-markdown" ${isFullscreen ? '' : 'title="Undo" aria-label="Undo" '}${revertDisabled ? 'disabled' : ''}>${renderUndoIcon()}${isFullscreen ? ' Undo' : ''}</button>` : ''}
89
+ ${isMarkdownEdit && isFullscreen ? renderMarkdownCopyButton() : ''}
90
+ ${isMarkdown && !isFullscreen ? `<button class="panel-action" id="copy-active-markdown" title="Copy" aria-label="Copy">${renderCopyIcon()}</button>` : ''}
91
+ ${canCopy && options.capabilities.supportsPreview && !isMarkdown ? `<button class="panel-action" id="copy-source" title="Copy source" aria-label="Copy source">${renderCopyIcon()}</button>` : ''}
92
+ ${canOpenInFolder && isMarkdownEdit && isFullscreen ? `<button class="panel-action" id="open-in-editor" ${fileDeleted ? 'disabled' : ''}>${options.markdownEditorAppIcon} Open in ${escapeHtml(options.defaultMarkdownEditorName ?? 'editor')}</button>` : ''}
93
+ ${canOpenInFolder && !(isMarkdownEdit && isFullscreen) ? `<button class="panel-action" id="open-in-folder" title="Open in folder" aria-label="Open in folder" ${isMarkdownEdit && fileDeleted ? 'disabled' : ''}>${renderFolderIcon()}</button>` : ''}
94
+ </span>
95
+ </div>
96
+ ${notice}
97
+ <div class="panel-content-wrapper">
98
+ ${loadBeforeBanner}
99
+ ${options.body.html}
100
+ ${loadAfterBanner}
101
+ </div>
102
+ <div class="panel-footer">
103
+ <span>${footerLabel}</span>
104
+ </div>
105
+ </section>
106
+ </main>
107
107
  `,
108
108
  };
109
109
  }
@@ -23,14 +23,14 @@ export function renderDocumentOutline(outline, activeHeadingId) {
23
23
  if (outline.length === 0) {
24
24
  return '';
25
25
  }
26
- return `
27
- <aside class="document-outline-shell markdown-toc-shell" aria-label="Table of contents">
28
- <div class="document-outline-header markdown-toc-header">
29
- <span class="document-outline-title markdown-toc-title">Contents</span>
30
- <button class="document-outline-toggle" id="toc-toggle" type="button" title="Collapse sidebar" aria-label="Collapse sidebar">${renderCollapseIcon()}</button>
31
- </div>
32
- <nav class="document-outline-nav markdown-toc-nav">${renderDocumentOutlineItems(outline, activeHeadingId)}</nav>
33
- </aside>
26
+ return `
27
+ <aside class="document-outline-shell markdown-toc-shell" aria-label="Table of contents">
28
+ <div class="document-outline-header markdown-toc-header">
29
+ <span class="document-outline-title markdown-toc-title">Contents</span>
30
+ <button class="document-outline-toggle" id="toc-toggle" type="button" title="Collapse sidebar" aria-label="Collapse sidebar">${renderCollapseIcon()}</button>
31
+ </div>
32
+ <nav class="document-outline-nav markdown-toc-nav">${renderDocumentOutlineItems(outline, activeHeadingId)}</nav>
33
+ </aside>
34
34
  `;
35
35
  }
36
36
  export function attachDocumentOutline(options) {
@@ -22,39 +22,39 @@
22
22
  * dirty so the user can retry or keep editing.
23
23
  */
24
24
  export function renderConflictDialogMarkup() {
25
- return `
26
- <div class="md-conflict-modal" id="md-conflict-modal" role="dialog" aria-modal="true" aria-labelledby="md-conflict-title" aria-describedby="md-conflict-body" hidden>
27
- <div class="md-conflict-card">
28
- <header class="md-conflict-header">
29
- <h3 id="md-conflict-title">⚠ This file changed on disk</h3>
30
- <button type="button" class="md-conflict-close" id="md-conflict-close" aria-label="Close">
31
- <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
32
- <path d="M7 7l10 10M17 7L7 17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
33
- </svg>
34
- </button>
35
- </header>
36
- <div class="md-conflict-body" id="md-conflict-body">
37
- <p>
38
- Something else modified
39
- <strong class="md-conflict-filename" id="md-conflict-filename"></strong>
40
- while you were editing. Your unsaved edits are preserved.
41
- </p>
42
- <p>If you save now:</p>
43
- <ul>
44
- <li>Changes you made to lines the external edit didn't touch will be saved alongside the external changes.</li>
45
- <li>Changes you made to lines that also changed externally will overwrite the external version on those lines.</li>
46
- </ul>
47
- </div>
48
- <footer class="md-conflict-footer">
49
- <button type="button" class="md-conflict-btn md-conflict-btn--secondary" id="md-conflict-use-disk">
50
- Use disk version
51
- </button>
52
- <button type="button" class="md-conflict-btn md-conflict-btn--primary" id="md-conflict-save-mine">
53
- Save my changes
54
- </button>
55
- </footer>
56
- </div>
57
- </div>
25
+ return `
26
+ <div class="md-conflict-modal" id="md-conflict-modal" role="dialog" aria-modal="true" aria-labelledby="md-conflict-title" aria-describedby="md-conflict-body" hidden>
27
+ <div class="md-conflict-card">
28
+ <header class="md-conflict-header">
29
+ <h3 id="md-conflict-title">⚠ This file changed on disk</h3>
30
+ <button type="button" class="md-conflict-close" id="md-conflict-close" aria-label="Close">
31
+ <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
32
+ <path d="M7 7l10 10M17 7L7 17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
33
+ </svg>
34
+ </button>
35
+ </header>
36
+ <div class="md-conflict-body" id="md-conflict-body">
37
+ <p>
38
+ Something else modified
39
+ <strong class="md-conflict-filename" id="md-conflict-filename"></strong>
40
+ while you were editing. Your unsaved edits are preserved.
41
+ </p>
42
+ <p>If you save now:</p>
43
+ <ul>
44
+ <li>Changes you made to lines the external edit didn't touch will be saved alongside the external changes.</li>
45
+ <li>Changes you made to lines that also changed externally will overwrite the external version on those lines.</li>
46
+ </ul>
47
+ </div>
48
+ <footer class="md-conflict-footer">
49
+ <button type="button" class="md-conflict-btn md-conflict-btn--secondary" id="md-conflict-use-disk">
50
+ Use disk version
51
+ </button>
52
+ <button type="button" class="md-conflict-btn md-conflict-btn--primary" id="md-conflict-save-mine">
53
+ Save my changes
54
+ </button>
55
+ </footer>
56
+ </div>
57
+ </div>
58
58
  `;
59
59
  }
60
60
  export function createConflictDialogController(options) {
@@ -344,15 +344,15 @@ export function createMarkdownController(dependencies) {
344
344
  .find((value) => typeof value === 'string' && value.trim().length > 0);
345
345
  return {
346
346
  notice,
347
- html: `
348
- <div class="panel-content markdown-content markdown-content--workspace">
349
- <div class="markdown-workspace markdown-workspace--edit${tocHtml ? ' markdown-workspace--with-toc' : ''}">
350
- ${tocHtml}
351
- <section class="markdown-workspace-main markdown-workspace-main--editor">
352
- ${renderMarkdownEditorShell({ view: state.editorView })}
353
- </section>
354
- </div>
355
- </div>
347
+ html: `
348
+ <div class="panel-content markdown-content markdown-content--workspace">
349
+ <div class="markdown-workspace markdown-workspace--edit${tocHtml ? ' markdown-workspace--with-toc' : ''}">
350
+ ${tocHtml}
351
+ <section class="markdown-workspace-main markdown-workspace-main--editor">
352
+ ${renderMarkdownEditorShell({ view: state.editorView })}
353
+ </section>
354
+ </div>
355
+ </div>
356
356
  `,
357
357
  };
358
358
  }
@@ -780,24 +780,24 @@ function shouldIgnoreBlur(shell, event) {
780
780
  return Boolean(nextTarget && (shell?.contains(nextTarget) || widgetShell?.contains(nextTarget)));
781
781
  }
782
782
  function renderFormattingButtons() {
783
- return `
784
- <button class="markdown-format-button" type="button" data-format="bold"><strong>B</strong></button>
785
- <button class="markdown-format-button" type="button" data-format="italic"><em>I</em></button>
786
- <button class="markdown-format-button" type="button" data-format="strike"><span style="text-decoration:line-through">S</span></button>
787
- <span class="markdown-format-sep" aria-hidden="true"></span>
788
- <label class="markdown-format-size" title="Block style" aria-label="Block style">
789
- <select id="markdown-block-style">
790
- <option value="p" selected>Normal</option>
791
- <option value="h1">H1</option>
792
- <option value="h2">H2</option>
793
- <option value="h3">H3</option>
794
- </select>
795
- </label>
796
- <span class="markdown-format-sep" aria-hidden="true"></span>
797
- <button class="markdown-format-button" type="button" data-format="quote" title="Quote" aria-label="Quote">&#10077;</button>
798
- <button class="markdown-format-button" type="button" data-format="list" title="List" aria-label="List">&#8226;</button>
799
- <button class="markdown-format-button" type="button" data-format="link" title="Link" aria-label="Link">&#128279;</button>
800
- <button class="markdown-format-button" type="button" data-format="code" title="Code" aria-label="Code">&lsaquo;&rsaquo;</button>
783
+ return `
784
+ <button class="markdown-format-button" type="button" data-format="bold"><strong>B</strong></button>
785
+ <button class="markdown-format-button" type="button" data-format="italic"><em>I</em></button>
786
+ <button class="markdown-format-button" type="button" data-format="strike"><span style="text-decoration:line-through">S</span></button>
787
+ <span class="markdown-format-sep" aria-hidden="true"></span>
788
+ <label class="markdown-format-size" title="Block style" aria-label="Block style">
789
+ <select id="markdown-block-style">
790
+ <option value="p" selected>Normal</option>
791
+ <option value="h1">H1</option>
792
+ <option value="h2">H2</option>
793
+ <option value="h3">H3</option>
794
+ </select>
795
+ </label>
796
+ <span class="markdown-format-sep" aria-hidden="true"></span>
797
+ <button class="markdown-format-button" type="button" data-format="quote" title="Quote" aria-label="Quote">&#10077;</button>
798
+ <button class="markdown-format-button" type="button" data-format="list" title="List" aria-label="List">&#8226;</button>
799
+ <button class="markdown-format-button" type="button" data-format="link" title="Link" aria-label="Link">&#128279;</button>
800
+ <button class="markdown-format-button" type="button" data-format="code" title="Code" aria-label="Code">&lsaquo;&rsaquo;</button>
801
801
  `;
802
802
  }
803
803
  function renderModeToggleIcon(view) {
@@ -817,23 +817,23 @@ export function renderMarkdownCopyButton() {
817
817
  return `<button class="markdown-editor-copy-button" type="button" id="copy-active-markdown" title="Copy" aria-label="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><span>Copy</span></button>`;
818
818
  }
819
819
  export function renderMarkdownModeToggle(view) {
820
- return `
821
- <div class="markdown-editor-mode-toggle" role="tablist" aria-label="Editor mode">
822
- <div class="markdown-editor-mode-toggle-indicator markdown-editor-mode-toggle-indicator--${view}" aria-hidden="true"></div>
823
- <button class="markdown-editor-mode-option${view === 'raw' ? ' is-active' : ''}" type="button" id="markdown-mode-raw" role="tab" aria-selected="${view === 'raw' ? 'true' : 'false'}" title="Raw" aria-label="Raw">${renderModeToggleIcon('raw')}<span>Raw</span></button>
824
- <button class="markdown-editor-mode-option${view === 'markdown' ? ' is-active' : ''}" type="button" id="markdown-mode-markdown" role="tab" aria-selected="${view === 'markdown' ? 'true' : 'false'}" title="Preview" aria-label="Preview">${renderModeToggleIcon('markdown')}<span>Preview</span></button>
825
- </div>
820
+ return `
821
+ <div class="markdown-editor-mode-toggle" role="tablist" aria-label="Editor mode">
822
+ <div class="markdown-editor-mode-toggle-indicator markdown-editor-mode-toggle-indicator--${view}" aria-hidden="true"></div>
823
+ <button class="markdown-editor-mode-option${view === 'raw' ? ' is-active' : ''}" type="button" id="markdown-mode-raw" role="tab" aria-selected="${view === 'raw' ? 'true' : 'false'}" title="Raw" aria-label="Raw">${renderModeToggleIcon('raw')}<span>Raw</span></button>
824
+ <button class="markdown-editor-mode-option${view === 'markdown' ? ' is-active' : ''}" type="button" id="markdown-mode-markdown" role="tab" aria-selected="${view === 'markdown' ? 'true' : 'false'}" title="Preview" aria-label="Preview">${renderModeToggleIcon('markdown')}<span>Preview</span></button>
825
+ </div>
826
826
  `;
827
827
  }
828
828
  export function renderMarkdownEditorShell(options) {
829
829
  const isMarkdownView = options.view === 'markdown';
830
- return `
831
- <div class="markdown-editor-shell markdown-editor-shell--${options.view}">
832
- <section class="markdown-editor-pane markdown-editor-pane--${options.view}" aria-label="Markdown editor">
833
- ${isMarkdownView ? `<div id="markdown-editor-context-menu" class="markdown-editor-context-menu" hidden>${renderFormattingButtons()}</div><div id="markdown-link-modal" class="markdown-link-modal" hidden><div class="markdown-link-modal-card"><div class="markdown-link-mode-tabs"><button type="button" id="markdown-link-mode-file" class="markdown-link-mode-tab is-active">File</button><button type="button" id="markdown-link-mode-url" class="markdown-link-mode-tab">URL</button></div><div id="markdown-link-file-fields"><label class="markdown-link-modal-label" for="markdown-link-search">Find note</label><input id="markdown-link-search" class="markdown-link-modal-input" type="text" placeholder="Search files..." /><div id="markdown-link-results" class="markdown-link-results"></div><label class="markdown-link-modal-label" for="markdown-link-heading">Heading</label><select id="markdown-link-heading" class="markdown-link-modal-input markdown-link-modal-select"><option value="">None</option></select><label class="markdown-link-modal-label" for="markdown-link-alias">Alias</label><input id="markdown-link-alias" class="markdown-link-modal-input" type="text" placeholder="Optional label" /></div><div id="markdown-link-url-fields" hidden><label class="markdown-link-modal-label" for="markdown-link-input">URL</label><input id="markdown-link-input" class="markdown-link-modal-input" type="url" placeholder="https://example.com" /><label class="markdown-link-modal-label" for="markdown-link-label">Label</label><input id="markdown-link-label" class="markdown-link-modal-input" type="text" placeholder="Optional label" /></div><div class="markdown-link-modal-actions"><button type="button" id="markdown-link-cancel" class="markdown-link-modal-button">Cancel</button><button type="button" id="markdown-link-apply" class="markdown-link-modal-button markdown-link-modal-button--primary">Insert</button></div></div></div>` : ''}
834
- <div id="markdown-editor-root" class="markdown-editor-root"></div>
835
- </section>
836
- </div>
830
+ return `
831
+ <div class="markdown-editor-shell markdown-editor-shell--${options.view}">
832
+ <section class="markdown-editor-pane markdown-editor-pane--${options.view}" aria-label="Markdown editor">
833
+ ${isMarkdownView ? `<div id="markdown-editor-context-menu" class="markdown-editor-context-menu" hidden>${renderFormattingButtons()}</div><div id="markdown-link-modal" class="markdown-link-modal" hidden><div class="markdown-link-modal-card"><div class="markdown-link-mode-tabs"><button type="button" id="markdown-link-mode-file" class="markdown-link-mode-tab is-active">File</button><button type="button" id="markdown-link-mode-url" class="markdown-link-mode-tab">URL</button></div><div id="markdown-link-file-fields"><label class="markdown-link-modal-label" for="markdown-link-search">Find note</label><input id="markdown-link-search" class="markdown-link-modal-input" type="text" placeholder="Search files..." /><div id="markdown-link-results" class="markdown-link-results"></div><label class="markdown-link-modal-label" for="markdown-link-heading">Heading</label><select id="markdown-link-heading" class="markdown-link-modal-input markdown-link-modal-select"><option value="">None</option></select><label class="markdown-link-modal-label" for="markdown-link-alias">Alias</label><input id="markdown-link-alias" class="markdown-link-modal-input" type="text" placeholder="Optional label" /></div><div id="markdown-link-url-fields" hidden><label class="markdown-link-modal-label" for="markdown-link-input">URL</label><input id="markdown-link-input" class="markdown-link-modal-input" type="url" placeholder="https://example.com" /><label class="markdown-link-modal-label" for="markdown-link-label">Label</label><input id="markdown-link-label" class="markdown-link-modal-input" type="text" placeholder="Optional label" /></div><div class="markdown-link-modal-actions"><button type="button" id="markdown-link-cancel" class="markdown-link-modal-button">Cancel</button><button type="button" id="markdown-link-apply" class="markdown-link-modal-button markdown-link-modal-button--primary">Insert</button></div></div></div>` : ''}
834
+ <div id="markdown-editor-root" class="markdown-editor-root"></div>
835
+ </section>
836
+ </div>
837
837
  `;
838
838
  }
839
839
  function applyRawTab(textarea) {