Skip to content

feat(ui): add markdown preview to file viewer#352

Merged
shantur merged 6 commits intoNeuralNomadsAI:devfrom
Pagecran:feat/file-viewer-markdown-wrap
Apr 26, 2026
Merged

feat(ui): add markdown preview to file viewer#352
shantur merged 6 commits intoNeuralNomadsAI:devfrom
Pagecran:feat/file-viewer-markdown-wrap

Conversation

@pascalandr
Copy link
Copy Markdown
Contributor

Fixes #331

Summary

  • add an optional Markdown preview toggle for markdown files in the Files tab
  • add a word-wrap toggle for the source editor
  • escape raw HTML in preview mode and limit preview to plain Markdown file extensions

Why

The Files tab only showed raw source, which makes Markdown files harder to read quickly.

This change adds a lightweight preview/source switch without introducing a larger viewer registry.

What Changed

  • packages/ui/src/components/instance/shell/right-panel/tabs/FilesTab.tsx
    • added Preview Markdown / Show source toggle for markdown files
    • added a word-wrap toggle for the Monaco source viewer
    • restricted preview mode to plain Markdown extensions
    • escaped raw HTML in markdown preview mode
  • packages/ui/src/components/file-viewer/monaco-file-viewer.tsx
    • added configurable word-wrap support
  • packages/ui/src/components/instance/shell/right-panel/RightPanel.tsx
    • moved file-viewer word-wrap state up so it persists across tab switches
  • packages/ui/src/components/instance/shell/storage.ts
    • added storage key for file-viewer word wrap
  • packages/ui/src/lib/i18n/messages/*/instance.ts
    • added strings for preview/source and word-wrap controls

Validation

  • npm run build --workspace @codenomad/ui

@pascalandr
Copy link
Copy Markdown
Contributor Author

@CodeNomadBot

I want you to perform the gatekeeper checks for latest PR state

check for regressions
check for better possible implementations
Be the PR gatekeeper
Be ruthless about code quality

@codenomadbot
Copy link
Copy Markdown
Contributor

codenomadbot Bot commented Apr 23, 2026

Automation failed.

remote: Internal Server Error
fatal: unable to access 'https://github.com/NeuralNomadsAI/CodeNomad.git/': The requested URL returned error: 500

--
Yours,
CodeNomadBot

@pascalandr
Copy link
Copy Markdown
Contributor Author

@CodeNomadBot

I want you to perform the gatekeeper checks for latest PR state

check for regressions
check for better possible implementations
Be the PR gatekeeper
Be ruthless about code quality

@codenomadbot
Copy link
Copy Markdown
Contributor

codenomadbot Bot commented Apr 23, 2026

Reviewed the latest PR state against dev with a gatekeeper pass.

Assumptions

  • I reviewed the current PR head in this worktree (codenomad/pr-352) and focused on the files changed by this PR.
  • Scope of review: regressions, behavior risks, and better-implementation concerns for the new markdown preview / word-wrap work.

Findings

  1. Medium: Ctrl/Cmd+S stops working whenever markdown preview is active.

    • packages/ui/src/components/instance/shell/right-panel/tabs/FilesTab.tsx:114-135 swaps Monaco out for <Markdown /> in preview mode.
    • The only keyboard save binding still lives inside Monaco at packages/ui/src/components/file-viewer/monaco-file-viewer.tsx:39-42,65.
    • Result: after editing a markdown file, switching to Preview removes the save shortcut even though the save button is still visible at FilesTab.tsx:238-245 and the file can still be dirty. That is a behavior regression specific to markdown files.
  2. Medium: the new preview is intentionally not faithful for markdown files that rely on inline HTML.

    • packages/ui/src/components/instance/shell/right-panel/tabs/FilesTab.tsx:135 always passes escapeRawHtml.
    • That flows into packages/ui/src/lib/markdown.ts:316-321, which escapes raw HTML instead of rendering it.
    • Result: common README/docs patterns like <details>, <img>, <kbd>, badge markup, and custom anchors render as literal text in the preview. If the security goal is to prevent unsafe HTML, a sanitizer/allowlist approach would preserve fidelity much better than disabling all inline HTML.

Validation

  • I attempted npm run build --workspace @codenomad/ui, but this environment is missing the vite package, so I could not complete a local build verification here.

Gatekeeper verdict

  • Not ready to merge as-is. The keyboard-save regression is a real usability break.
  • The raw-HTML decision may be acceptable if it is explicitly desired, but it should be treated as a product tradeoff, not a transparent markdown preview.

--
Yours,
CodeNomadBot

@pascalandr
Copy link
Copy Markdown
Contributor Author

@CodeNomadBot

I want you to perform the gatekeeper checks for latest PR state

check for regressions
check for better possible implementations
Be the PR gatekeeper
Be ruthless about code quality

@codenomadbot
Copy link
Copy Markdown
Contributor

codenomadbot Bot commented Apr 23, 2026

Reviewed the latest PR head again after the new fix commit (d502fb9).

Assumptions

  • I reviewed the current PR state in this worktree against dev.
  • Scope stayed tight to the Files tab markdown preview / word-wrap changes introduced by this PR.

Findings

  1. Medium: the save-shortcut fix is now too broad in scope and can trigger from the wrong place.

    • packages/ui/src/components/instance/shell/right-panel/tabs/FilesTab.tsx:73-85 adds a window-level keydown listener whenever markdown preview is open and the file is dirty.
    • That means Ctrl/Cmd+S is intercepted even when focus is elsewhere in the app, as long as the preview is visible.
    • This is still a regression from the original Monaco behavior, where the shortcut was scoped to the editor itself (packages/ui/src/components/file-viewer/monaco-file-viewer.tsx:39-42,65).
    • Gatekeeper view: the shortcut should be scoped to the preview pane / active viewer state, not the whole window.
  2. Medium: markdown preview still is not faithful for files that use inline HTML.

    • packages/ui/src/components/instance/shell/right-panel/tabs/FilesTab.tsx:149 still passes escapeRawHtml.
    • That routes to packages/ui/src/lib/markdown.ts:316-321, which escapes all raw HTML instead of sanitizing it.
    • Result: valid markdown content that uses <details>, <img>, badge HTML, anchors, <kbd>, etc. renders as literal text in preview.
    • If the goal is safety, a sanitizer/allowlist approach would preserve fidelity better than disabling all inline HTML.

Validation

  • I re-checked the latest source changes locally.
  • I did not repeat the build command because this environment previously failed before app code validation due to a missing vite package.

Gatekeeper verdict

  • The prior missing-save-shortcut finding is partially addressed, but I still would not approve this as merge-ready.
  • The current head removes one regression and introduces a broader shortcut-scope regression, and the preview-fidelity concern remains.

--
Yours,
CodeNomadBot

@pascalandr
Copy link
Copy Markdown
Contributor Author

@CodeNomadBot

I want you to perform the gatekeeper checks for latest PR state

check for regressions
check for better possible implementations
Be the PR gatekeeper
Be ruthless about code quality

@codenomadbot
Copy link
Copy Markdown
Contributor

codenomadbot Bot commented Apr 23, 2026

Reviewed the latest PR head again after the new fix commit (b6b3fbd).

Assumptions

  • I reviewed the current PR state in this worktree against dev.
  • Scope stayed tight to the markdown preview / word-wrap changes in the Files tab and the new markdown sanitization logic added to support them.

Findings

  1. High: the new sanitizer allows file: image URLs, which creates a local-file disclosure path in markdown preview.

    • packages/ui/src/lib/markdown.ts:54-56 explicitly allow file: URLs for <img src>.
    • packages/ui/src/components/instance/shell/right-panel/tabs/FilesTab.tsx:156 renders repository markdown through that sanitizer in preview mode.
    • Result: opening a markdown file in preview can cause the app to request and display arbitrary local files via <img src="file:///...">. In a desktop/webview context, that is a real security problem and should not be permitted.
  2. Medium: the raw-HTML sanitizer still produces an inaccurate preview for common safe markdown HTML.

    • packages/ui/src/lib/markdown.ts:19-46 only allow a narrow set of tags.
    • packages/ui/src/lib/markdown.ts:83-85 unwrap any non-allowed tag by dropping the element and keeping only its children.
    • Result: common safe constructs like <h1>-<h6> and <hr> lose their semantics and styling in FilesTab preview. For example, <h1>Title</h1> renders as plain body text.
    • Gatekeeper view: this is better than the prior all-or-nothing escaping behavior, but the preview still materially diverges from normal markdown/GitHub rendering for real docs.

What changed since the last review

  • The prior window-level Ctrl/Cmd+S regression appears resolved: the save shortcut is now scoped to a focusable preview container instead of the whole window.

Validation

  • I reviewed the latest source changes locally.
  • I did not re-run the UI build because the previous attempt in this environment failed before app-code validation due to a missing vite package.

Gatekeeper verdict

  • Still not merge-ready.
  • The new shortcut fix improved the UX regression, but the sanitizer now introduces a higher-severity security issue via file: URLs, and the preview-fidelity gap is still present.

--
Yours,
CodeNomadBot

@pascalandr
Copy link
Copy Markdown
Contributor Author

@CodeNomadBot

I want you to perform the gatekeeper checks for latest PR state

check for regressions
check for better possible implementations
Be the PR gatekeeper
Be ruthless about code quality

@codenomadbot
Copy link
Copy Markdown
Contributor

codenomadbot Bot commented Apr 23, 2026

Reviewed the latest PR head again after the new fix commit (adfca8b).

Assumptions

  • I reviewed the current PR state in this worktree against dev.
  • Scope stayed tight to the Files tab markdown preview / word-wrap changes and the markdown sanitization added to support preview mode.

Findings

  • No concrete regressions or blocking implementation issues found in the latest head.

What changed since the last review

  • The prior high-severity file: URL issue appears resolved: packages/ui/src/lib/markdown.ts:61-64 no longer allow file: for image sources.
  • The earlier preview-fidelity concern around raw HTML headings/separators also appears addressed: the sanitizer now allows h1-h6 and hr in packages/ui/src/lib/markdown.ts:19-53.
  • The scoped save shortcut behavior in preview mode remains intact in packages/ui/src/components/instance/shell/right-panel/tabs/FilesTab.tsx:75-85,149-156.

Validation

  • I reviewed the latest source changes locally.
  • I did not re-run the UI build because the prior build attempt in this environment failed before app-code validation due to a missing vite package.

Gatekeeper verdict

  • Latest PR state looks acceptable from this review pass.
  • I do not currently see a blocker in scope for this PR.

--
Yours,
CodeNomadBot

@shantur
Copy link
Copy Markdown
Collaborator

shantur commented Apr 26, 2026

@pascalandr - would you be able to resolve the conflicts in the PR

Add an optional Markdown preview toggle for markdown files and a word-wrap toggle for the source editor so the Files tab can switch between rendered and editable views without introducing a larger viewer registry.
Escape raw HTML in markdown previews, stop treating MDX as supported markdown preview input, and persist file-viewer word wrap outside the Files tab so the new controls survive tab switches.
Preserve Ctrl/Cmd+S for dirty markdown files while preview mode is active so switching from source to preview does not remove the keyboard save path.
Handle Ctrl/Cmd+S only while the preview pane itself is focused, and sanitize allowlisted inline HTML so markdown previews preserve common safe constructs like details, images, anchors, and kbd tags without falling back to raw HTML.
Remove file:// image support from the markdown sanitizer and allow common safe semantic tags like headings and hr so the preview stays safer while remaining closer to normal markdown rendering.
@pascalandr pascalandr force-pushed the feat/file-viewer-markdown-wrap branch from adfca8b to 6bc796a Compare April 26, 2026 16:49
@github-actions
Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/24961897653

Artifacts expire in 7 days.
Artifacts: (none found on this run)

@shantur
Copy link
Copy Markdown
Collaborator

shantur commented Apr 26, 2026

@pascalandr - Build seems to be broken now

@pascalandr
Copy link
Copy Markdown
Contributor Author

fixed

@shantur shantur merged commit 0ba1371 into NeuralNomadsAI:dev Apr 26, 2026
11 of 12 checks passed
@shantur
Copy link
Copy Markdown
Collaborator

shantur commented Apr 26, 2026

Thanks @pascalandr

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] markdown render and word wrap

2 participants