Add markdown source toggle#1263
Conversation
|
| Filename | Overview |
|---|---|
| packages/app/src/workspace/file-open/index.ts | Adds WorkspaceFileRenderMode, WorkspaceFileTabTargetInput (optional renderMode), normalizeWorkspaceFileRenderMode, and workspaceFileTabTargetsEqual — the core type/normalization layer for this feature |
| packages/app/src/stores/workspace-tabs-store/state.ts | Adds preserveExistingFileRenderMode flag and targetsShareFileLocation guard in buildNextTabsForEnsure to prevent clobbering source mode on re-navigation; coerces persisted tabs missing renderMode to "preview" |
| packages/app/src/stores/workspace-layout-actions.ts | Threads preserveExistingFileRenderMode into updateExistingTabTarget so the layout store also skips retargeting source-mode tabs when no explicit renderMode is requested |
| packages/app/src/stores/workspace-layout-store.ts | Adds shouldPreserveExistingFileRenderMode helper and passes the flag through all three open-tab actions (focused, child, background) |
| packages/app/src/workspace-tabs/identity.ts | normalizeFileTabTarget now includes renderMode; workspaceTabTargetsEqual delegates to workspaceFileTabTargetsEqual so source vs preview are treated as distinct targets |
| packages/app/src/screens/workspace/workspace-tab-menu.ts | Adds "Show source / Show preview" toggle entry with code/eye icons; correctly guarded by isRenderedMarkdownFile and absence of lineStart |
| packages/app/src/screens/workspace/workspace-screen.tsx | Wires handleToggleMarkdownSource via retargetWorkspaceTab to all three tab-row surfaces (desktop tabs, mobile switcher, split container) |
| packages/app/src/components/file-pane.tsx | location prop tightened to WorkspaceFileTabTarget; renderMode !== "source" guard added so markdown preview is suppressed in source mode |
| packages/app/src/screens/workspace/workspace-pane-state.ts | preferredTarget and resolveSideFileOpenPlacement target widened to WorkspaceTabTargetInput; added defensive null-check after normalization in resolveSideFileOpenPlacement |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User navigates to file\ne.g. from file explorer] --> B{renderMode\nprovided?}
B -- "No (undefined/null)" --> C[preserveExistingFileRenderMode = true\nnormalize → renderMode: preview]
B -- "Yes (source/preview)" --> D[preserveExistingFileRenderMode = false\nnormalize → explicit renderMode]
C --> E{Tab already open\nfor this file path?}
D --> E
E -- No --> F[Insert new tab\nwith normalized renderMode]
E -- Yes --> G{preserveExistingFileRenderMode\n&& same file location?}
G -- Yes --> H[Return currentTabs unchanged\n★ source mode preserved]
G -- No\n(explicit renderMode request) --> I[Retarget tab to\nnew renderMode]
J[Toggle button clicked] --> K[retargetWorkspaceTab with\nexplicit nextRenderMode]
K --> D
Reviews (14): Last reviewed commit: "fix: use preview icon for markdown previ..." | Re-trigger Greptile
88b0b7a to
2fa83db
Compare
2fa83db to
4d22713
Compare
Linked issue
Closes #1264
Type of change
What does this PR do
Markdown file tabs currently render the preview directly, with no way to inspect the raw Markdown from the same tab. This adds a tab-menu action for rendered Markdown files that toggles the tab between the rendered preview and the highlighted source view.
The tab state now stores an explicit file render mode:
previeworsource. Opening a file without a render mode still normalizes topreview, so existing open-file paths and older persisted file tabs keep their current behavior. The toggle is wired through the desktop tab menu, mobile tab menu, and split-pane tab rows, and it is intentionally hidden for line-targeted Markdown links because those already need the source/highlighted-line view.The toggle uses distinct destination icons:
Show sourceuses the code icon, andShow previewuses the eye icon.Follow-up review feedback is also covered: reopening an already-open Markdown file without an explicit render mode preserves the user's current preview/source mode, while callers that explicitly request
renderMode: "source"orrenderMode: "preview"are still honored.How did you verify it
npx vitest run packages/app/src/workspace/file-open/index.test.ts packages/app/src/screens/workspace/workspace-tab-menu.test.ts packages/app/src/components/file-pane-render-mode.test.ts packages/app/src/screens/workspace/workspace-pane-state.test.ts packages/app/src/screens/workspace/workspace-tab-model.test.ts packages/app/src/screens/workspace/workspace-bulk-close.test.ts packages/app/src/utils/workspace-navigation.test.ts --bail=1npx vitest run packages/app/src/stores/workspace-tabs-store/state.test.ts packages/app/src/stores/workspace-layout-store.test.ts --bail=1npm run formatnpm run lintnpm run typecheckgit diff --checkworkspace-tab-menu.test.tsalso asserts the icon mapping:Show sourceusescode, andShow previewuseseye.Visual QA is still needed before marking this ready: open a Markdown file tab on desktop/web and mobile, verify the menu shows
Show source, toggle to the source view, verify the menu changes toShow preview, then toggle back.Risk surface
This touches workspace tab target normalization and equality for file tabs. The intended behavior is still one tab per file path, with source/preview represented as mutable state on that tab rather than separate tabs.
The main UI risk is that one of the tab menu surfaces could fail to expose or refresh the action correctly after toggling. The main state risk is old persisted file tabs without
renderMode; those are normalized topreviewand covered by the file target tests. Reopen/focus behavior for existing file tabs is covered by reducer and split-layout store tests so omitted render mode preserves the current tab mode without blocking explicit render-mode requests.Checklist
npm run typecheckpassesnpm run lintpassesnpm run formatran