Conversation
WalkthroughImplements end-to-end Image Preview feature with backend path resolution (Tauri command), frontend hover detection (Alt-key state tracking), image preview component rendering, and supporting utilities for detecting image URLs across Markdown/HTML. Includes configuration updates, test coverage, and documentation. Changes
Sequence DiagramsequenceDiagram
participant User
participant Editor
participant useImageHover
participant ImagePreview
participant Tauri
participant FileSystem
User->>Editor: Hover over image + press Alt
Editor->>useImageHover: Emit mousemove event with Alt state
useImageHover->>useImageHover: Convert mouse to doc position
useImageHover->>useImageHover: Extract image URLs from line
useImageHover->>Editor: Return HoveredImage
Editor->>ImagePreview: Pass hoveredImage, projectPath, currentFilePath
alt Local Image Path
ImagePreview->>Tauri: invoke('resolve_image_path', {path, projectRoot, currentFile})
Tauri->>FileSystem: Validate path within project root
FileSystem-->>Tauri: Canonical path / error
Tauri-->>ImagePreview: Resolved absolute path
ImagePreview->>ImagePreview: Convert to asset URL
else Remote URL
ImagePreview->>ImagePreview: Use URL directly
end
ImagePreview->>ImagePreview: Render preview or loading state
ImagePreview-->>User: Display image preview
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes The changes span frontend components, backend commands, detection utilities, and configuration with mixed complexity. Logic includes state machines, path validation, and hover tracking across multiple files. Consistent patterns (image detection, state management) reduce friction, but multiple interdependencies and new public APIs require careful integration review. Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (9)
src/lib/editor/urls/detection.test.ts (2)
274-323: Edge-case expectation:isImageUrl('.png') === true— confirm intent.Accepting bare extensions as “image URLs” may surprise future callers outside the text scanner. If intentional, add a brief docstring note; otherwise, require at least one path segment.
325-504: Great coverage; add a couple more cases for robustness.Consider tests for:
- Data URLs:
data:image/png;base64,...(should likely be false).- File URLs:
file:///...(should be false).- URLs with fragments:
image.png#v=1(should be true).docs/tasks-done/task-1-image-previews.md (2)
37-41: Docs/config mismatch: allowlisthttps:in CSP.Docs state remote images work; ensure the CSP example includes
https:inimg-srcto match the implementation change suggested in tauri.conf.json.
5-9: Minor copy nits.Capitalize “Markdown”; consider replacing bolded section titles with proper headings to satisfy MD036.
src/components/editor/ImagePreview.tsx (1)
69-69: Simplify the dependency array.The dependency array includes both
hoveredImage?.urlandhoveredImage, which is redundant. SinceuseImageHoverreturns the same object reference when the URL hasn't changed (as shown in the implementation), including justhoveredImageis sufficient to track all necessary changes.Apply this diff to simplify:
- }, [hoveredImage?.url, projectPath, currentFilePath, hoveredImage]) + }, [hoveredImage, projectPath, currentFilePath])src-tauri/src/commands/files.rs (1)
1013-1053: LGTM with a minor documentation suggestion.The path resolution logic is well-structured and secure:
- Properly handles absolute, relative, and ambiguous paths
- Uses
validate_project_pathto prevent directory traversal attacks- Validates file existence before returning
- Clear error messages
The comment on line 1035 says "try as absolute from project root first" but there's no fallback or "second" option. Consider simplifying to just "treat as absolute from project root" for clarity.
docs/developer/image-preview-implementation.md (2)
5-5: Consider using proper capitalization."markdown" should be "Markdown" when referring to the formatting language as a proper noun.
19-38: Consider adding language identifiers to code blocks.The code blocks at lines 19, 25, and 35 should specify a language identifier for better syntax highlighting in documentation viewers. For example, the paths at lines 20, 26, and 36-37 could use
textorbashas the language identifier.src/hooks/editor/useImageHover.ts (1)
71-74: Consider clarifying the catch block comment.The catch block is generic and will catch any error, not just "position is out of bounds" errors. While failing gracefully for all errors is reasonable here, consider updating the comment to reflect this broader error handling.
- } catch { - // Silently fail if position is out of bounds + } catch { + // Silently fail for any errors (e.g., position out of bounds, invalid state) setHoveredImage(null) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
src-tauri/Cargo.lockis excluded by!**/*.locktest/dummy-astro-project/src/content/articles/imagetest.pngis excluded by!**/*.png
📒 Files selected for processing (14)
docs/developer/image-preview-implementation.md(1 hunks)docs/tasks-done/task-1-image-previews.md(1 hunks)docs/tasks-todo/task-2-images-in-frontmatter.md(1 hunks)src-tauri/Cargo.toml(1 hunks)src-tauri/src/commands/files.rs(1 hunks)src-tauri/src/lib.rs(1 hunks)src-tauri/tauri.conf.json(1 hunks)src/components/editor/Editor.tsx(4 hunks)src/components/editor/ImagePreview.tsx(1 hunks)src/hooks/editor/index.ts(2 hunks)src/hooks/editor/useImageHover.ts(1 hunks)src/lib/editor/urls/detection.test.ts(2 hunks)src/lib/editor/urls/detection.ts(2 hunks)test/dummy-astro-project/src/content/articles/2025-01-22-image-preview-test.md(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src-tauri/**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
Write and maintain Rust tests and code for the Tauri backend with modern Rust formatting (use format("{variable}"))
Files:
src-tauri/src/lib.rssrc-tauri/src/commands/files.rs
src/lib/**/*.test.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Write unit tests for src/lib modules as .test.ts files under src/lib
Files:
src/lib/editor/urls/detection.test.ts
src/components/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Use the Direct Store Pattern in React components (access Zustand stores directly) and never use React Hook Form
Files:
src/components/editor/ImagePreview.tsxsrc/components/editor/Editor.tsx
🧬 Code graph analysis (7)
src/hooks/editor/useImageHover.ts (2)
src/hooks/editor/index.ts (2)
HoveredImage(19-19)useImageHover(18-18)src/lib/editor/urls/detection.ts (1)
findImageUrlsAndPathsInText(114-183)
src-tauri/src/lib.rs (1)
src-tauri/src/commands/files.rs (1)
resolve_image_path(1013-1053)
src/lib/editor/urls/detection.ts (1)
src/lib/editor/dragdrop/fileProcessing.ts (1)
IMAGE_EXTENSIONS(10-19)
src-tauri/src/commands/files.rs (1)
src-tauri/src/commands/mdx_components.rs (1)
validate_project_path(17-32)
src/lib/editor/urls/detection.test.ts (1)
src/lib/editor/urls/detection.ts (2)
isImageUrl(95-99)findImageUrlsAndPathsInText(114-183)
src/components/editor/ImagePreview.tsx (1)
src/hooks/editor/useImageHover.ts (1)
HoveredImage(5-9)
src/components/editor/Editor.tsx (3)
src/store/editorStore.ts (1)
useEditorStore(219-490)src/store/projectStore.ts (1)
useProjectStore(42-396)src/hooks/editor/useImageHover.ts (1)
useImageHover(18-116)
🪛 LanguageTool
docs/tasks-todo/task-2-images-in-frontmatter.md
[style] ~9-~9: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...nt this before, it got very complicated very quickly. I don't see why it should be that comp...
(EN_WEAK_ADJECTIVE)
docs/tasks-done/task-1-image-previews.md
[uncategorized] ~7-~7: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...n editor ### Original Requirements In markdown or MDX files when there are image links...
(MARKDOWN_NNP)
[uncategorized] ~7-~7: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...at are inserted using MDX components or markdown links and we need to be able to support...
(MARKDOWN_NNP)
[grammar] ~129-~129: Use a hyphen to join words.
Context: ...or mouse leave - Handles edge cases (out of bounds positions, no view instance) ...
(QB_NEW_EN_HYPHEN)
[grammar] ~129-~129: Use a hyphen to join words.
Context: ...mouse leave - Handles edge cases (out of bounds positions, no view instance) **3...
(QB_NEW_EN_HYPHEN)
[uncategorized] ~173-~173: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...xt`) - ✅ Phase 2: Detects images in markdown, HTML, MDX components, and plain text -...
(MARKDOWN_NNP)
docs/developer/image-preview-implementation.md
[uncategorized] ~5-~5: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...hs/URLs with Alt key held. Works across markdown, HTML, MDX components, and plain text u...
(MARKDOWN_NNP)
🪛 markdownlint-cli2 (0.18.1)
docs/tasks-todo/task-2-images-in-frontmatter.md
5-5: Bare URL used
(MD034, no-bare-urls)
test/dummy-astro-project/src/content/articles/2025-01-22-image-preview-test.md
55-55: Bare URL used
(MD034, no-bare-urls)
docs/tasks-done/task-1-image-previews.md
35-35: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
42-42: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
48-48: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
docs/developer/image-preview-implementation.md
19-19: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
25-25: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
35-35: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (rust)
🔇 Additional comments (15)
src-tauri/Cargo.toml (1)
21-21: Feature alignment looks good.Adding
protocol-assetmatches the new asset protocol usage in config and frontend. No issues.src/lib/editor/urls/detection.test.ts (1)
2-8: Import surface extension is fine.New exports (
isImageUrl,findImageUrlsAndPathsInText) are exercised properly.src-tauri/src/lib.rs (1)
369-369: LGTM!The new
resolve_image_pathcommand is correctly registered in the invoke handler, following the established pattern for exposing Rust functions to the frontend.src/hooks/editor/index.ts (1)
9-19: LGTM!The new exports for the image hover functionality are well-documented and follow the existing module structure.
src/components/editor/Editor.tsx (3)
7-14: LGTM!The new imports are well-organized and follow the project's module structure.
30-31: LGTM!Store access follows the Direct Store Pattern correctly, and the image hover hook is properly integrated with the editor's state.
Also applies to: 70-71
251-257: LGTM!The conditional rendering and prop passing are correct. The
|| nullon line 255 properly convertsundefinedtonullfor type compatibility with theImagePreviewcomponent's prop signature.src/components/editor/ImagePreview.tsx (1)
23-68: LGTM!The image loading logic is well-structured with proper optimizations:
- Prevents reloading when hovering over the same URL (lines 32-34)
- Handles remote and local paths correctly
- Uses proper async error handling with silent failures
- Integrates cleanly with Tauri's path resolution and asset protocol
src/lib/editor/urls/detection.ts (2)
89-99: LGTM!The
isImageUrlfunction correctly handles edge cases by stripping query parameters and fragments before checking the extension. This ensures URLs likehttps://example.com/image.png?w=300are properly recognized.
114-183: LGTM!The syntax-agnostic detection strategy is well-implemented:
- Comprehensive coverage of remote URLs, relative paths, and absolute paths
- Proper overlap prevention to avoid duplicate matches
- Appropriate stop characters to handle various syntaxes (Markdown, HTML, MDX)
- Clear separation of concerns with three distinct regex patterns
This approach successfully works across different content formats without needing syntax-specific parsing.
docs/developer/image-preview-implementation.md (1)
1-217: Excellent documentation!This is comprehensive, well-structured documentation that covers:
- Architecture and component flow
- Path resolution strategies for all three types
- Performance optimization patterns with clear examples
- Security considerations and validation
- Configuration requirements
The rationale sections (like "Why Editor.tsx?") are particularly valuable for future maintainers.
src/hooks/editor/useImageHover.ts (4)
24-77: Excellent optimization to prevent unnecessary re-renders.The logic is well-structured with good defensive checks. The conditional state update on lines 58-61 that avoids creating a new object when the URL hasn't changed is a smart optimization that will prevent downstream components from re-rendering unnecessarily.
79-96: Well-structured effect with proper cleanup.The effect correctly manages the mousemove listener lifecycle, and clearing the hovered image on lines 88-91 when Alt is released is important defensive programming—it ensures state is cleared immediately without waiting for the next mousemove event.
99-113: Good optimization separating mouseleave into its own effect.By depending only on
viewrather than also includingisAltPressedandhandleMouseMove, this effect avoids unnecessary re-runs and listener re-attachment. This is a thoughtful performance optimization.
1-116: Excellent implementation of the image hover detection hook.The overall architecture is sound:
- Clean separation between mousemove and mouseleave event handling
- Thoughtful performance optimizations throughout
- Good defensive programming with proper null checks and error handling
- Well-documented with clear JSDoc comments
- Proper TypeScript typing with exported interface
The hook integrates cleanly with CodeMirror's API and the detection utilities, and should work reliably for the image preview feature.
Shows an image preview when hovering over image URL in the editor. Works with both remote images and local images.
Summary by CodeRabbit
New Features
Documentation