Feature/raw text toggle#128
Conversation
… make toolbar vertical
WalkthroughAdds raw Markdown viewing in the renderer by wiring view-mode state into ChangesRaw markdown view toggle
Welcome file-drop artwork
Sequence Diagram(s)sequenceDiagram
participant User
participant ReaderToolbar
participant App
participant RawTextViewer
participant Reader
User->>ReaderToolbar: click raw text toggle
ReaderToolbar->>App: onToggleRawText()
App->>App: switch viewMode
alt raw mode
App->>RawTextViewer: pass activeTab.markdown
else rendered mode
App->>Reader: pass activeTab.html and getHiglightedHtml
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/renderer/__tests__/components/ReaderToolbar.test.tsx`:
- Around line 22-29: The ReaderToolbar test only verifies the click handler, but
it should also cover the dynamic label/state contract driven by viewMode. Update
the existing ReaderToolbar test suite to include a case using the component’s
viewMode prop set to raw and assert the toggle button label changes to "Show
rendered text" (and, if relevant, the rendered/raw styling/state reflects that
mode). Use the ReaderToolbar and onToggleRawText symbols to keep the test
aligned with the component behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: e95cc518-db73-4347-b680-18cfe5c5a9e6
⛔ Files ignored due to path filters (1)
assets/file.pngis excluded by!**/*.png,!**/*.{png,jpg,jpeg,gif,webp,ico,icns,mp4,zip}
📒 Files selected for processing (8)
apps/renderer/__tests__/components/ReaderToolbar.test.tsxapps/renderer/src/App.tsxapps/renderer/src/components/RawTextViewer.tsxapps/renderer/src/components/ReaderToolbar.tsxapps/renderer/src/components/Welcome.tsxapps/renderer/src/hooks/useViewMode.tsapps/renderer/src/types/component-types.tsapps/renderer/src/utils/constants/icon-contants.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: build
🧰 Additional context used
📓 Path-based instructions (8)
apps/renderer/**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use React for the renderer UI layer.
Files:
apps/renderer/src/hooks/useViewMode.tsapps/renderer/src/components/RawTextViewer.tsxapps/renderer/__tests__/components/ReaderToolbar.test.tsxapps/renderer/src/types/component-types.tsapps/renderer/src/utils/constants/icon-contants.tsxapps/renderer/src/App.tsxapps/renderer/src/components/Welcome.tsxapps/renderer/src/components/ReaderToolbar.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use TypeScript for application code.
Files:
apps/renderer/src/hooks/useViewMode.tsapps/renderer/src/components/RawTextViewer.tsxapps/renderer/__tests__/components/ReaderToolbar.test.tsxapps/renderer/src/types/component-types.tsapps/renderer/src/utils/constants/icon-contants.tsxapps/renderer/src/App.tsxapps/renderer/src/components/Welcome.tsxapps/renderer/src/components/ReaderToolbar.tsx
**
⚙️ CodeRabbit configuration file
**: # Markdown ReaderA native desktop applicaion for reading Markdown files, built entirely on the JavaScript/TypeScript ecosystem using Electron as the desktop runtime.
markdown-reader is to Markdown what Adobe Acrobat Reader is to PDF:
a dedicated, native, first-class desktop viewer for .md files.Table of Contents
Why Markdown Reader ?
The Problem
Markdown is the most widely used plain-text writing format in the world.
Developers, writers, and teams produce millions of .md files daily.
Yet there is no dedicated desktop reader for Markdown that:
Missing Capability Current Workaround Pain Level Opens .md files natively on double-click No default handler — opens as raw text High Renders beautifully like a document VS Code preview pane feels like a dev tool Medium Has a sidebar TOC like a PDF reader Manual heading scanning Medium Supports all Markdown features GitHub renders some, browsers render none High Works fully offline Must open a browser manually High Feels like a reader, not an editor Every tool adds edit affordances Medium VS Code is an editor. GitHub is a web interface. Obsidian is a note-taking vault.
None of them are just a reader — a clean, dedicated app for opening and
reading Markdown files.The Solution
markdown-reader is a dedicated native desktop Markdown reader:
- Double-click any .md file and it opens in markdown-reader
- Registered as the system default application for .md files on install
- Beautiful readable typography — not a developer tool aesthetic
- Full M...
Files:
apps/renderer/src/hooks/useViewMode.tsapps/renderer/src/components/RawTextViewer.tsxapps/renderer/__tests__/components/ReaderToolbar.test.tsxapps/renderer/src/types/component-types.tsapps/renderer/src/utils/constants/icon-contants.tsxapps/renderer/src/App.tsxapps/renderer/src/components/Welcome.tsxapps/renderer/src/components/ReaderToolbar.tsx
apps/renderer/src/**/*.{ts,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/*.{ts,tsx}: Review as React renderer code.
- Keep components typed, accessible, keyboard-friendly, and resilient to missing preload APIs.
- Effects must have correct dependencies and cleanup.
- Handle loading, empty, error, stale-response, and rejected-promise states.
- Do not import Node-only modules into renderer code.
- Avoid unnecessary derived state, unsafe globals, and broad any types.
Files:
apps/renderer/src/hooks/useViewMode.tsapps/renderer/src/components/RawTextViewer.tsxapps/renderer/src/types/component-types.tsapps/renderer/src/utils/constants/icon-contants.tsxapps/renderer/src/App.tsxapps/renderer/src/components/Welcome.tsxapps/renderer/src/components/ReaderToolbar.tsx
apps/renderer/src/**/*.{css,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/*.{css,tsx}: Review UI, theme, and accessibility.
- Interactive controls need semantic elements, visible focus, and keyboard access.
- Theme changes must preserve readable contrast in light and dark modes.
- Markdown prose must remain readable for tables, code, blockquotes, links, lists, and images.
- Prefer existing tokens/classes over ad hoc inline styling.
Files:
apps/renderer/src/components/RawTextViewer.tsxapps/renderer/src/utils/constants/icon-contants.tsxapps/renderer/src/App.tsxapps/renderer/src/components/Welcome.tsxapps/renderer/src/components/ReaderToolbar.tsx
**/*.{test,spec}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Write unit tests for all new features to maintain code quality, adding test cases alongside component source code and ensuring all tests pass via
pnpm vitest
Files:
apps/renderer/__tests__/components/ReaderToolbar.test.tsx
**/*.{test,spec}.{ts,tsx}
⚙️ CodeRabbit configuration file
**/*.{test,spec}.{ts,tsx}: Review tests.
- Cover success and failure paths, especially IPC, filesystem, markdown rendering, search, settings, tabs, and exports.
- Use isolated temp directories for disk tests and clean them up.
- Mock Electron/preload APIs explicitly.
- Prefer Testing Library user-event and getByRole for UI tests.
Files:
apps/renderer/__tests__/components/ReaderToolbar.test.tsx
apps/renderer/src/**/{renderer,markdown,utils}/**/*.{ts,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/{renderer,markdown,utils}/**/*.{ts,tsx}: Review markdown rendering carefully.
- Sanitize raw HTML, links, images, Mermaid, KaTeX, anchors, and exported content.
- Block script execution, javascript: URLs, unsafe inline handlers, and unsafe local file references.
- Heading IDs and TOC entries must be stable and collision-safe.
- Mermaid/KaTeX/code highlighting failures should not break the whole document.
- Add tests for unsafe HTML, malformed markdown, links, images, code blocks, Mermaid, and KaTeX when changed.
Files:
apps/renderer/src/utils/constants/icon-contants.tsx
🔇 Additional comments (9)
apps/renderer/src/components/Welcome.tsx (1)
6-6: LGTM!Also applies to: 99-101
apps/renderer/src/types/component-types.ts (1)
184-191: LGTM!apps/renderer/src/hooks/useViewMode.ts (1)
4-15: LGTM!apps/renderer/src/components/RawTextViewer.tsx (2)
4-10: Rendering raw markdown as escaped text content (nodangerouslySetInnerHTML) is the right call — keeps the source view XSS-safe.
6-6: 🎯 Functional Correctness
wrap-break-wordis correctly configured for Tailwind v4The project uses Tailwind v4.2.4 (
package.json), which natively supports thewrap-break-wordutility. The current implementation inapps/renderer/src/components/RawTextViewer.tsxcorrectly prevents horizontal overflow for long URLs and paths in the raw view. No changes are needed.apps/renderer/src/App.tsx (1)
36-37: LGTM!Also applies to: 62-62, 240-253
apps/renderer/src/utils/constants/icon-contants.tsx (1)
240-247: LGTM!apps/renderer/src/components/ReaderToolbar.tsx (1)
176-189: Raw-text toggle uses a semantic button with dynamicaria-label/titleand clear active state — accessible and keyboard-friendly.apps/renderer/__tests__/components/ReaderToolbar.test.tsx (1)
16-20: LGTM!
mind-murtaza
left a comment
There was a problem hiding this comment.
The new raw text toggle feature is a great addition, and the architectural choice to use a dedicated useViewMode hook keeps the components clean and focused. Adding the explicit aria-label and title attributes to the toolbar buttons is also a great step for accessibility.
However, there are a few issues that we need to address before merging this in—most notably, an accessibility/UX regression on the Welcome screen and a couple of styling/formatting inconsistencies.
Please review the inline comments below and let me know if you have any questions!
📄 apps/renderer/src/components/Welcome.tsx
[Minor] Semantic meaning removed from the Welcome Logo
-
Line(s): 96–101
-
What's wrong: The semantic logo SVG was replaced with a generic
fileIconPNG and explicitly hidden from screen readers usingaria-hidden="true"with an emptyaltattribute. -
Why it matters: The logo on the Welcome screen provides brand identity and context. Hiding it degrades the accessibility (A11y) for screen-reader users and creates a UX regression.
-
Requested Change: If this icon replacement is intentional, please provide a meaningful
alttext rather than hiding it.<img src={fileIcon} alt="Markdown Reader Logo" className="w-10 h-10 object-contain" />
📄 apps/renderer/src/components/RawTextViewer.tsx
[Minor] Invalid Tailwind CSS class
-
Line(s): 97
-
What's wrong: The
pretag useswrap-break-word, which is not a valid Tailwind CSS utility class. -
Why it matters: Because this class is unrecognized, the raw text might fail to wrap correctly on smaller screens or when dealing with long, unbroken strings (like URLs or hashes), leading to horizontal scrolling or layout breaks.
-
Requested Change: Replace
wrap-break-wordwith standard Tailwind classes likebreak-wordsorbreak-all.<pre className="p-8 whitespace-pre-wrap break-words font-mono text-sm leading-relaxed max-w-4xl mx-auto"> {markdown ?? ''} </pre>
📄 apps/renderer/src/components/ReaderToolbar.tsx
[Nit] Missing border-radius on the Reset Zoom button
-
Line(s): 214
-
What's wrong: The
rounded-mdclass was removed from the "Reset Zoom" button, while all adjacent toolbar buttons retained it. -
Why it matters: This introduces a visual inconsistency in the UI. When hovering over this button, the background will appear as a sharp rectangle, which clashes with the rounded corners of the other buttons in the toolbar.
-
Requested Change: Add
rounded-mdback to the class list.<button type="button" onClick={onZoomReset} className="w-full rounded-md text-center py-1 text-xs font-semibold text-text-muted transition-colors hover:bg-accent-bg hover:text-text-base" aria-label={`Reset zoom, current size ${fontSize} pixels`} title={`Reset zoom, current size ${fontSize} pixels`} >
📄 apps/renderer/src/utils/constants/icon-contants.tsx
[Nit] Formatting/Linting bypassed
-
Line(s): 240–245
-
What's wrong: The newly added
Codecomponent lacks standard spacing around operators, parameters, and curly braces. -
Why it matters: This breaks codebase style consistency and suggests that our automatic formatter (e.g., Prettier) wasn't run prior to committing.
-
Requested Change: Format the component according to our style guidelines. (Also, note that the file is named
icon-contants.tsxinstead ofconstants, which might be worth fixing in a separate tech-debt PR!)const Code = ({ size = 20, ...props }: IconProps) => ( <svg width={size} height={size} viewBox="0 0 24 24" {...defaultProps} {...props}> <polyline points="16 18 22 12 16 6" /> <polyline points="8 6 2 12 8 18" /> </svg> );
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/renderer/src/components/ReaderToolbar.tsx (1)
179-185: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winExpose the raw-view toggle state with
aria-pressed.This is a stateful toggle, but assistive tech only gets the action text today. Add
aria-pressed={viewMode === 'raw'}so the current mode is announced correctly.As per path instructions, "Keep components typed, accessible, keyboard-friendly, and resilient to missing preload APIs."
Suggested fix
<button type="button" onClick={onToggleRawText} className={`rounded-md p-2 transition-colors hover:bg-accent-bg ${viewMode === 'raw' ? 'text-accent bg-accent-bg' : 'text-text-muted hover:text-text-base'}`} + aria-pressed={viewMode === 'raw'} aria-label={viewMode === 'raw' ? "Show rendered text" : "Show raw text"} title={viewMode === 'raw' ? "Show rendered text" : "Show raw text"} >🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/renderer/src/components/ReaderToolbar.tsx` around lines 179 - 185, The toggle button in ReaderToolbar is stateful but only exposes label text, so assistive tech cannot tell whether raw view is active. Update the button rendered by ReaderToolbar to include an aria-pressed state derived from viewMode === 'raw', alongside the existing aria-label/title, so the toggle’s current state is announced correctly and remains keyboard-accessible.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/renderer/src/components/RawTextViewer.tsx`:
- Line 6: The RawTextViewer pre element is currently forcing long lines to wrap,
which changes the displayed source layout. Update the className on the pre in
RawTextViewer to preserve original raw lines and allow horizontal scrolling
instead of hard-wrapping, so URLs, paths, and code remain faithful to the file
content while staying readable for Markdown elements.
---
Outside diff comments:
In `@apps/renderer/src/components/ReaderToolbar.tsx`:
- Around line 179-185: The toggle button in ReaderToolbar is stateful but only
exposes label text, so assistive tech cannot tell whether raw view is active.
Update the button rendered by ReaderToolbar to include an aria-pressed state
derived from viewMode === 'raw', alongside the existing aria-label/title, so the
toggle’s current state is announced correctly and remains keyboard-accessible.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: b681a63f-2906-4fb2-b569-be4436571222
📒 Files selected for processing (3)
apps/renderer/src/components/RawTextViewer.tsxapps/renderer/src/components/ReaderToolbar.tsxapps/renderer/src/components/Welcome.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: build
🧰 Additional context used
📓 Path-based instructions (5)
apps/renderer/**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use React for the renderer UI layer.
Files:
apps/renderer/src/components/Welcome.tsxapps/renderer/src/components/RawTextViewer.tsxapps/renderer/src/components/ReaderToolbar.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use TypeScript for application code.
Files:
apps/renderer/src/components/Welcome.tsxapps/renderer/src/components/RawTextViewer.tsxapps/renderer/src/components/ReaderToolbar.tsx
**
⚙️ CodeRabbit configuration file
**: # Markdown ReaderA native desktop applicaion for reading Markdown files, built entirely on the JavaScript/TypeScript ecosystem using Electron as the desktop runtime.
markdown-reader is to Markdown what Adobe Acrobat Reader is to PDF:
a dedicated, native, first-class desktop viewer for .md files.Table of Contents
Why Markdown Reader ?
The Problem
Markdown is the most widely used plain-text writing format in the world.
Developers, writers, and teams produce millions of .md files daily.
Yet there is no dedicated desktop reader for Markdown that:
Missing Capability Current Workaround Pain Level Opens .md files natively on double-click No default handler — opens as raw text High Renders beautifully like a document VS Code preview pane feels like a dev tool Medium Has a sidebar TOC like a PDF reader Manual heading scanning Medium Supports all Markdown features GitHub renders some, browsers render none High Works fully offline Must open a browser manually High Feels like a reader, not an editor Every tool adds edit affordances Medium VS Code is an editor. GitHub is a web interface. Obsidian is a note-taking vault.
None of them are just a reader — a clean, dedicated app for opening and
reading Markdown files.The Solution
markdown-reader is a dedicated native desktop Markdown reader:
- Double-click any .md file and it opens in markdown-reader
- Registered as the system default application for .md files on install
- Beautiful readable typography — not a developer tool aesthetic
- Full M...
Files:
apps/renderer/src/components/Welcome.tsxapps/renderer/src/components/RawTextViewer.tsxapps/renderer/src/components/ReaderToolbar.tsx
apps/renderer/src/**/*.{ts,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/*.{ts,tsx}: Review as React renderer code.
- Keep components typed, accessible, keyboard-friendly, and resilient to missing preload APIs.
- Effects must have correct dependencies and cleanup.
- Handle loading, empty, error, stale-response, and rejected-promise states.
- Do not import Node-only modules into renderer code.
- Avoid unnecessary derived state, unsafe globals, and broad any types.
Files:
apps/renderer/src/components/Welcome.tsxapps/renderer/src/components/RawTextViewer.tsxapps/renderer/src/components/ReaderToolbar.tsx
apps/renderer/src/**/*.{css,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/*.{css,tsx}: Review UI, theme, and accessibility.
- Interactive controls need semantic elements, visible focus, and keyboard access.
- Theme changes must preserve readable contrast in light and dark modes.
- Markdown prose must remain readable for tables, code, blockquotes, links, lists, and images.
- Prefer existing tokens/classes over ad hoc inline styling.
Files:
apps/renderer/src/components/Welcome.tsxapps/renderer/src/components/RawTextViewer.tsxapps/renderer/src/components/ReaderToolbar.tsx
🔇 Additional comments (2)
apps/renderer/src/components/Welcome.tsx (1)
99-102: 🔒 Security & Privacy | ⚡ Quick winFix misleading alt text on file-drop icon.
Line 100 sets
alt="Markdown Reader Logo"onfileIcon, but this is a generic file icon in the drop zone, not the application logo. The extension mode's actual logo (line 19) uses the same alt text, creating duplicate/confusing announcements for screen reader users. Usealt=""(decorative, since the button's visible text "Load Markdown File" provides context) oralt="File icon"to accurately describe the image's purpose.As per path instructions, interactive controls need semantic elements and accessible labeling. The button is accessible via its text, but the image's alt should not misidentify it as the app logo.
🛠️ Proposed fix
<img src={fileIcon} - alt="Markdown Reader Logo" + alt="" className="w-10 h-10 object-contain" />Source: Path instructions
apps/renderer/src/components/ReaderToolbar.tsx (1)
21-22: LGTM!Also applies to: 45-47, 58-71, 80-118, 204-246
Description
This PR adds a toggle option in the reader toolbar , to convert the rendered content into raw text , so it will be helpful for users to use it , directly from their without going to any editor.
Type of Change
Related Issue
Closes #127
Changes Made
-Added raw text viewer component.
Screenshots (if applicable)
Checklist
Electron main/preload
Renderer UI
flex-col) stack.viewModestate so the user can switch between rendered and raw markdown within the reader.file.pngasset.Markdown rendering
RawTextViewer, which renders the active tab’smarkdownin a<pre>-based monospace view.useViewModeto manage'rendered'vs'raw'mode, withAppconditionally rendering:RawTextViewer markdown={activeTab.markdown}whenviewMode === 'raw'Reader html={activeTab.html}otherwise.Shared packages
Tests
ReaderToolbartests to verify the vertical layout and that clicking “Show raw text” callsonToggleRawTextonce.Tooling/CI
Docs
Packaging
Breaking changes: None