Files
36ebc1f6fc Add Preview/Code toggle for Markdown file previews and code blocks (#39378)
* Add Rendered/Raw toggle for Markdown file previews and code blocks

Markdown files in the full-screen file preview and ```markdown code blocks
can now be switched between rendered output and raw source with a segmented
eye / code toggle (new MarkdownViewToggle, built on compass-ui IconButton).
File previews default to rendered, code blocks to raw; the choice is
remembered per surface in local storage.

- Markdown files use one fixed-size box in both views and wrap their source
- Rendered output reuses the standard Markdown component, with a nesting
  guard so rendered blocks don't offer a second toggle
- Copying a rendered code block still yields the raw fenced source
- Migrate the file preview header icons to compass-ui IconButton and fix
  the previous-file arrow tooltip that said "Close"

Co-Authored-By: Claude <noreply@anthropic.com>

* Refine Markdown toggle, detect untagged Markdown, polish preview header

- Detect untagged code blocks that look like Markdown (two distinct
  constructs, or a ## or deeper heading) and offer the toggle on them;
  explicitly tagged blocks keep their language
- Toggle: "Code"/"Preview" labels, track sized exactly to its icon buttons,
  sliding thumb with 12% border and elevation, calmer look on the dark
  file preview header, 2px inset-free compact size for code blocks
- Keep the code block toggle from lingering after a click (focus-visible
  instead of focus-within)
- File preview header: icon buttons are medium/compact (36px), restore a
  16% hover, and match the download link color to its siblings
- Update header and nav snapshots for the new IconButton classes

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix code review findings in the Markdown preview toggle

- Keep the file preview content when the same file is shown again, so
  arrow keys in a single-file preview no longer drop the toggle and Copy
- Derive the code block view from the saved preference when a block becomes
  toggleable later, instead of fixing it at first render
- Keep code blocks in search results raw so match highlighting stays visible
- Bound the link and bold regexes so a huge unclosed line can't scan
  quadratically
- Share the file preview header icon button props and class between the
  actions and the nav

Co-Authored-By: Claude <noreply@anthropic.com>

* Number wrapped Markdown lines and polish the Markdown preview styling

Markdown source now wraps with a line number on each source line instead of
dropping the numbers. The preview toggle no longer paints hover backgrounds
and uses an outline on its thumb, the modal's Preview and Code views share one
box size and corner radius, and the line number divider is softer.

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix circular import and address review comments on the Markdown preview

Load Markdown lazily in the code block so it no longer forms an import cycle
with the LaTeX block, which crashed latex_block.test.tsx. Copy-as-Markdown
now reads only the outer code block's language label, and the file preview
drops its loaded content when the shown file is swapped for another.

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix code review findings in the Markdown preview toggle

Restores hover affordance on the unselected toggle segment, gives
auto-detected Markdown the same numbered raw view as tagged blocks,
keeps the filename/language label visible in raw view for Markdown
files, re-derives the stored preview preference on user switch,
excludes CRLF from the Markdown-detection regexes, and dedupes the
line-number gutter CSS.

* Scope CodeBlock's chosen Markdown view to the current user

A locally-chosen view wasn't keyed by user, so if currentUserId
changed on a still-mounted block (the key is code, not user), the
previous user's selection could leak into the new user's view instead
of falling back to their own stored preference.

* Fix regression and simplify the two prior per-user-scoping fixes

code_preview.tsx: restore skipping the filename/language label for
Markdown files in both views. Showing it only in raw view unbalanced
how much of the fixed-size box each view's content gets, causing a
visible shift when toggling.

code_block.tsx: drop the {userId, view} wrapper for chosenMarkdownView
in favor of resetting it to null when currentUserId changes, which is
simpler and avoids a stale choice surviving a user switch via a
reference-equality mismatch.

file_preview_modal.tsx: move the currentUserId-driven markdownView
reset out of getDerivedStateFromProps (already handling an unrelated
file-list diffing concern) into its own componentDidUpdate.

* Address review feedback on the Markdown preview toggle

Hoist the duplicated Markdown source check, render wrapped code rows as
spans instead of divs inside <code>, and rebuild highlighted lines as
React elements rather than using dangerouslySetInnerHTML.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Keep the raw Markdown source on code blocks so a copy pastes back intact

Pasting a copied raw Markdown block read the code element's text, which
picked up the line numbers and lost every newline. Set the source
attribute whenever the block is Markdown and share its name between the
code block and turndown.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Rework the Markdown view toggle after review

- Add useMarkdownView so the stored view is one reactive, per-user value
  shared by every block and the file preview, replacing the memo, local
  override, ref/effect and componentDidUpdate re-read
- Parse highlighted HTML once into per-line React elements and drop
  splitHighlightedLines
- Decide whether a file can toggle in one place (canToggleMarkdownPreview)
  and let CodePreview read the view itself
- Draw line numbers with CSS counters so they are not part of the text, and
  only keep the raw source attribute while the block is rendered
- Turn the code block toggle off unless a surface (post markdown) enables it
- Share the on-dark IconButton variables and the specificity helper, simplify
  MarkdownViewToggle, move the code preview Markdown styles next to the
  component, store file content with its file id, and split the construct
  checks in is_likely_markdown

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Point Cypress file preview helpers at the Compass icon buttons

The preview header buttons are now SVG IconButtons, so the icon-font
class selectors no longer match. Select them by accessible name or
their stable class instead.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Ignore a CodePreview fetch that resolves after the file changed

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Document the Markdown Code/Preview toggle

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Read the download attribute from the preview's download anchor

The download button is now the anchor itself rather than an icon inside
it, so the Cypress specs no longer step up to its parent.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Keep the original post's image blocking in rendered Markdown previews

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Read a quoted selection's language label from a direct child of the code block

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Don't let blocked storage break the Markdown view preference

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Matthew Birtch <2040554+matthewbirtch@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 15:46:47 -05:00
..