Skip to content

feat: add plan review comment system - #1

Merged
wilcorrea merged 20 commits into
mainfrom
feat/plan-review-comments
Feb 23, 2026
Merged

feat: add plan review comment system#1
wilcorrea merged 20 commits into
mainfrom
feat/plan-review-comments

Conversation

@wilcorrea

@wilcorrea wilcorrea commented Feb 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds interactive plan review system with inline comment functionality
  • Supports multi-selection of markdown blocks (Cmd/Ctrl+click) for commenting
  • Collapsible bottom bar UI with expand/collapse animation
  • Generates structured review prompts with quoted block content for easy copy-paste to coding agents
  • Persists comments in .comments.json sidecar files with file hash validation
  • Adds window state persistence (remembers position and size across sessions)
  • Fixes light theme icon rendering and refresh button padding

Test plan

  • Open a markdown file in Arandu
  • Click on markdown blocks to select them (try Cmd/Ctrl+click for multi-selection)
  • Add comments via the "+ Add Comment" button
  • Verify bottom bar appears collapsed at bottom of screen
  • Click on "COMMENTS (X)" title to expand/collapse the panel
  • Test "Generate Review" button to create formatted review prompt
  • Verify "Copy to Clipboard" works and prompt is properly formatted
  • Close and reopen the file - comments should persist
  • Modify the file externally - should show hash mismatch warning in console
  • Test Delete and Resolve buttons on comments (confirm dialog should work)
  • Close and reopen app - window position/size should be remembered
  • Verify .comments.json files are gitignored

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • In-app commenting UI: comment modal, badges, stale-comments banner, bottom bar, multi-block selection, per-file persistent comments, review-generation modal with copy-to-clipboard.
    • Clipboard management and window-state persistence; file-hash support.
  • Bug Fixes

    • Corrected updater repository URL casing.
  • Chores

    • Added local dev HTTP server script and dependency.
    • Ignore generated comment files (*.comments.json).
    • Granted permissions for writing comment files and clipboard access.

Implement GitHub-style code review for plan files:
- Click blocks to select and add comments
- Bottom bar shows all comments with line indicators
- Generate consolidated review prompt
- Copy to clipboard for coding agent feedback
- Persistent storage in .comments.json sidecar files
- Integrated clipboard support from feat/voice-to-text

Backend:
- Add load_comments, save_comments, hash_file Tauri commands
- Add Comment and CommentsFile structs for persistence
- Integrate tauri-plugin-clipboard-manager and sha2 deps

Frontend:
- Block selection with visual highlight
- Comment CRUD operations with badges
- Bottom bar UI (200px height, resizable)
- Review prompt generation with unresolved filtering
- Theme-aware styling for all new components

UI Components:
- Bottom bar with comment list and actions
- Comment modal for adding feedback
- Review modal with prompt preview
- Line indicators (L<number>) for navigation
- Badge counters on commented blocks
Event listeners were being registered before DOM elements existed,
causing blank screen on app load. Moved all bottom bar and comment
modal event listeners to execute after theme initialization and
initial file load.
Remove devUrl from tauri.conf.json to serve static files directly
from frontendDist. The app was trying to connect to http://localhost:1420
but no server was running on that port.

Also add defensive checks in updateBottomBar() and selectBlock()
to handle cases where DOM elements don't exist yet during initial load.
Add beforeDevCommand to start Python HTTP server on port 1420.
This ensures CSS files are served with correct MIME types instead
of being rejected by browser strict mode.
Replace python3 dependency with npm serve package for cross-platform
compatibility. This works on any system with Node.js installed
(which is already required for the project).
Tauri already serves static files automatically in dev mode.
The beforeDevCommand was unnecessary complexity.
Restore to original working configuration.
Tauri can serve static files directly from frontendDist without
needing an external dev server. This is simpler and works correctly
with proper MIME types.
- Add http-server dependency for serving static files
- Configure beforeDevCommand to auto-start dev server
- Remove center positioning from recording window
Window starts with visible:false and only appears when a file
is opened, avoiding empty window taking up screen space.
If app starts without a file argument, show window so user can
use the Open File button. Window only stays hidden if launched
with a file that will trigger show() via loadFile().
The visible:false configuration was preventing window from appearing.
Removed to allow normal window behavior.
- Add collapsible bottom bar for plan review comments
- Support multi-selection of markdown blocks (Cmd/Ctrl+click)
- Generate review prompts with quoted block content
- Persist comments in .comments.json sidecar files
- Add window state persistence plugin
- Fix light theme icon and refresh button padding
- Ignore *.comments.json files
@coderabbitai

coderabbitai Bot commented Feb 22, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an in-file markdown commenting system: frontend UI (modals, badges, bottom bar), client-side logic for comment lifecycle and selection, persistent per-markdown JSON storage, new Tauri commands (load/save comments, file hash), clipboard & window-state plugins, filesystem write capability, and small tooling/config updates.

Changes

Cohort / File(s) Summary
Ignore & Tooling
/.gitignore, apps/tauri/package.json
Ignore *.comments.json; add http-server devDependency and dev:server npm script.
Tauri Build Config
apps/tauri/src-tauri/tauri.conf.json
Add beforeDevCommand, reorder build keys, remove fixed Windows width/height, fix updater repo host casing.
Rust Dependencies & Capabilities
apps/tauri/src-tauri/Cargo.toml, apps/tauri/src-tauri/capabilities/default.json
Add dependencies: tauri-plugin-window-state, tauri-plugin-clipboard-manager, sha2; grant fs write, clipboard-manager, and window-state capabilities, re-add updater.
Backend Commands & Setup
apps/tauri/src-tauri/src/lib.rs
Add Comment and CommentsFile types (Serialize/Deserialize); add commands load_comments, save_comments, hash_file; register clipboard-manager and window-state plugins and new invoke handlers.
Frontend Markup
apps/tauri/src/index.html
Insert Comment modal, Review Prompt modal, Stale Comments and Save Error banners, and Bottom Bar DOM for comment workflows.
Frontend Styles
apps/tauri/src/app.css
Large CSS additions for stale banner, bottom bar (hidden/visible/expanded), commentable blocks, badges, comment & review modals, and related states; tweak refresh button selector.
Frontend Logic
apps/tauri/src/main.js
Implement comments state and lifecycle (load/save/add/delete/toggle resolve), block ID/tagging and selection (multi-select), comment badges, bottom bar expand/collapse, review prompt generation and clipboard copy, stale-banner handling, and extensive UI event wiring.

Sequence Diagram

sequenceDiagram
    actor User
    participant Frontend as Frontend (main.js)
    participant Tauri as Tauri Backend (lib.rs)
    participant FS as File System
    participant Clipboard as Clipboard Plugin
    participant WindowState as Window-State Plugin

    User->>Frontend: Open markdown file
    Frontend->>Tauri: hash_file(path)
    Tauri->>FS: Read file bytes
    FS-->>Tauri: File bytes
    Tauri-->>Frontend: SHA-256 hash

    Frontend->>Tauri: load_comments(markdown_path)
    Tauri->>FS: Read {markdown_path}.comments.json
    alt comments file exists
        FS-->>Tauri: comments JSON
        Tauri-->>Frontend: CommentsFile
    else missing
        Tauri-->>Frontend: Default empty CommentsFile
    end

    Frontend->>Frontend: Render commentable blocks & badges
    User->>Frontend: Add comment(s)
    Frontend->>Frontend: Update comments state
    User->>Frontend: Save comments
    Frontend->>Tauri: save_comments(path, data)
    Tauri->>FS: Write {markdown_path}.comments.json
    FS-->>Tauri: Write OK
    Tauri-->>Frontend: Success

    User->>Frontend: Generate review prompt
    Frontend->>Clipboard: copy(prompt)
    Clipboard-->>Frontend: Copied
    Frontend->>WindowState: persist window state (optional)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 I nibbled bytes and sketched a tiny bar,
JSON burrows follow every heading's scar.
Badges twitch, modals hum a gentle tune,
Hashes hold secrets safe beneath the moon.
Clipboard ready — hop, reviews are strewn!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add plan review comment system' directly and clearly summarizes the main change: adding a comprehensive comment system for plan/markdown review. It aligns with the PR objectives and all file changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/plan-review-comments

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/tauri/src/main.js (1)

60-105: ⚠️ Potential issue | 🟠 Major

Clear stale selection when loading a new file.

selectedBlocks persists across file loads, so “Add Comment” can attach comments to unrelated blocks after switching files. Reset the selection and hide the add button when content is replaced.

🧹 Suggested fix
     document.getElementById("content").innerHTML = html;
+
+    // Reset selection state for new file
+    selectedBlocks = [];
+    const addBtn = document.getElementById("bottom-bar-add-comment");
+    if (addBtn) {
+      addBtn.style.display = "none";
+      addBtn.textContent = "+ Add Comment";
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/tauri/src/main.js` around lines 60 - 105, When loading a new file in the
main file-loading flow (around where populateOutline(headings) and await
loadCommentsForFile(path) are called), clear any previous selection state so
comments don't attach to blocks from the previous file: reset the selectedBlocks
variable (e.g., set selectedBlocks = [] or new Set()), remove any selection
CSS/classes from DOM nodes (remove class like "selected" from
document.querySelectorAll(".commentable-block.selected")), and hide/disable the
Add Comment button (e.g., getElementById or querySelector for the add-button and
set style.display = "none" or disable it) before populating the new content and
loading comments; place this logic near the start of the file-load success path
where headings/contents are assigned so selection is always cleared when
switching files.
🧹 Nitpick comments (3)
apps/tauri/src/app.css (1)

494-498: Hardcoded color values may not adapt to theme changes.

The selected block highlight uses a hardcoded rgba(73, 163, 255, 0.15) which may not align with --link in all themes. Consider using CSS custom properties with opacity for better theme consistency.

🎨 Proposed theme-aware approach
 .commentable-block.selected {
-  background: rgba(73, 163, 255, 0.15);
+  background: color-mix(in srgb, var(--link) 15%, transparent);
   outline: 2px solid var(--link);
   outline-offset: -2px;
 }

Note: color-mix() has broad browser support but verify it works in your WebView target. Alternatively, define a --link-bg variable in both theme blocks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/tauri/src/app.css` around lines 494 - 498, The selected block uses a
hardcoded rgba color which can mismatch themes; update
.commentable-block.selected to derive the background from theme variables
instead (e.g., use color-mix() with --link or reference a new --link-bg custom
property defined in both theme blocks) and keep the outline using var(--link);
ensure you provide a fallback for environments without color-mix (fallback to
the current rgba) and add/update the theme declarations to define --link-bg (or
rely on color-mix(--link 15% on white/transparent) as appropriate) so the
highlight adapts to theme changes.
apps/tauri/src/index.html (1)

74-107: Consider adding accessibility attributes to interactive elements.

The modal and bottom bar structure is well-organized. For improved accessibility, consider adding aria-label attributes to buttons that only have icons or short text, and role="dialog" with aria-modal="true" to the modal overlays.

♿ Example accessibility improvements
-  <div id="comment-modal" class="modal-overlay" style="display:none">
+  <div id="comment-modal" class="modal-overlay" role="dialog" aria-modal="true" aria-labelledby="comment-modal-title" style="display:none">
     <div class="modal-box">
-      <h3>Add Comment</h3>
+      <h3 id="comment-modal-title">Add Comment</h3>
-      <button id="bottom-bar-add-comment">+ Add Comment</button>
+      <button id="bottom-bar-add-comment" aria-label="Add comment to selected blocks">+ Add Comment</button>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/tauri/src/index.html` around lines 74 - 107, Add ARIA attributes to the
modal overlays and interactive buttons: give the modal containers (ids
comment-modal and review-modal) role="dialog", aria-modal="true",
aria-labelledby referencing their h3 ids (e.g., comment-modal-title,
review-modal-title) and aria-describedby referencing the explanatory element ids
(e.g., comment-context, review-output); add aria-hidden="true" when the modal is
hidden and set it to "false" when shown. Add descriptive aria-label attributes
to buttons with short text or icon-only controls (e.g., bottom-bar-add-comment,
comment-cancel, comment-submit, review-close, review-copy, bottom-bar-generate)
and ensure the comment-block-preview and comment-input have accessible labels
(use aria-labelledby or aria-label) so screen readers can identify them.
apps/tauri/src/main.js (1)

345-421: Remove debug logs from the delete flow before release.

🧽 Suggested cleanup
     deleteBtn.textContent = "Delete";
     deleteBtn.onclick = async () => {
-      console.log("Delete button clicked - showing confirm");
       const result = await confirm("Delete this comment?");
-      console.log("Confirm result:", result);
       if (result) {
-        console.log("User clicked OK - deleting comment");
         deleteComment(comment.id);
-      } else {
-        console.log("User clicked Cancel - not deleting");
       }
     };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/tauri/src/main.js` around lines 345 - 421, In updateBottomBar's delete
flow (inside the deleteBtn.onclick handler), remove the debug console.log calls
so the UI doesn't emit debug output in production; specifically delete the three
console.log lines ("Delete button clicked - showing confirm", "Confirm result:",
result) and the subsequent "User clicked OK/Cancel" logs, leaving the existing
confirm(...) await and the deleteComment(comment.id) call intact so behavior is
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/tauri/src-tauri/src/lib.rs`:
- Around line 187-199: The load_comments function currently treats any
std::fs::read_to_string error as "no comments" which hides real I/O issues;
change the match on read_to_string in load_comments to inspect the error (e.g.,
err.kind()) and only return the default CommentsFile when the error kind is
NotFound, otherwise return Err with a descriptive message including the original
error; update the error branch to propagate permission/IO errors instead of
swallowing them so callers can react to real failures.

In `@apps/tauri/src/main.js`:
- Around line 135-155: The console.warn about a file/hash mismatch in
loadCommentsForFile should be replaced with a user-visible banner or modal;
implement (or call) a helper like showStaleCommentsBanner(currentHash) from
loadCommentsForFile when commentsData.file_hash && commentsData.file_hash !==
currentHash, and ensure the banner provides a clear message and actions (e.g.,
"Reload comments" or "Ignore") and is dismissed when commentsData.file_hash is
updated or when renderCommentBadges/updateBottomBar run; add a corresponding
hideStaleCommentsBanner() and wire it to showBottomBar or to the successful
comment reload flow so the banner is removed when comments are fresh.
- Around line 221-255: The badge count is being inserted as visible text inside
blocks (renderCommentBadges -> badge.textContent), which leaks into any block
text extraction; instead set the count as a data attribute (e.g.,
badge.dataset.count = count), remove badge.textContent, mark the badge
aria-hidden (badge.setAttribute('aria-hidden','true')) and keep the badge
visually via CSS using .comment-badge::after { content: attr(data-count); } so
the DOM text nodes remain clean; additionally, ensure any code that extracts
block text (where commentsByBlock or preview code runs) strips or ignores
.comment-badge elements by removing/querying them out of a cloned node before
reading textContent.

---

Outside diff comments:
In `@apps/tauri/src/main.js`:
- Around line 60-105: When loading a new file in the main file-loading flow
(around where populateOutline(headings) and await loadCommentsForFile(path) are
called), clear any previous selection state so comments don't attach to blocks
from the previous file: reset the selectedBlocks variable (e.g., set
selectedBlocks = [] or new Set()), remove any selection CSS/classes from DOM
nodes (remove class like "selected" from
document.querySelectorAll(".commentable-block.selected")), and hide/disable the
Add Comment button (e.g., getElementById or querySelector for the add-button and
set style.display = "none" or disable it) before populating the new content and
loading comments; place this logic near the start of the file-load success path
where headings/contents are assigned so selection is always cleared when
switching files.

---

Nitpick comments:
In `@apps/tauri/src/app.css`:
- Around line 494-498: The selected block uses a hardcoded rgba color which can
mismatch themes; update .commentable-block.selected to derive the background
from theme variables instead (e.g., use color-mix() with --link or reference a
new --link-bg custom property defined in both theme blocks) and keep the outline
using var(--link); ensure you provide a fallback for environments without
color-mix (fallback to the current rgba) and add/update the theme declarations
to define --link-bg (or rely on color-mix(--link 15% on white/transparent) as
appropriate) so the highlight adapts to theme changes.

In `@apps/tauri/src/index.html`:
- Around line 74-107: Add ARIA attributes to the modal overlays and interactive
buttons: give the modal containers (ids comment-modal and review-modal)
role="dialog", aria-modal="true", aria-labelledby referencing their h3 ids
(e.g., comment-modal-title, review-modal-title) and aria-describedby referencing
the explanatory element ids (e.g., comment-context, review-output); add
aria-hidden="true" when the modal is hidden and set it to "false" when shown.
Add descriptive aria-label attributes to buttons with short text or icon-only
controls (e.g., bottom-bar-add-comment, comment-cancel, comment-submit,
review-close, review-copy, bottom-bar-generate) and ensure the
comment-block-preview and comment-input have accessible labels (use
aria-labelledby or aria-label) so screen readers can identify them.

In `@apps/tauri/src/main.js`:
- Around line 345-421: In updateBottomBar's delete flow (inside the
deleteBtn.onclick handler), remove the debug console.log calls so the UI doesn't
emit debug output in production; specifically delete the three console.log lines
("Delete button clicked - showing confirm", "Confirm result:", result) and the
subsequent "User clicked OK/Cancel" logs, leaving the existing confirm(...)
await and the deleteComment(comment.id) call intact so behavior is unchanged.

Comment thread apps/tauri/src-tauri/src/lib.rs
Comment thread apps/tauri/src/main.js
Comment thread apps/tauri/src/main.js
- Distinguish NotFound from other IO errors in load_comments
- Replace console.warn with user-visible stale comments banner
- Use data attribute + CSS ::after for badge count to prevent text leak
- Clear selection state when loading a new file
- Use color-mix() for theme-aware selected block highlight
- Add ARIA attributes to comment and review modals
- Remove debug console.log from delete flow
@wilcorrea

Copy link
Copy Markdown
Contributor Author

Code Review Feedback - All Comments Addressed

All 7 review findings from CodeRabbit have been resolved in commit 637697d.

Inline Comments (3)

# File Finding Status
1 lib.rs L187-199 Error handling masks read failures other than NotFound Fixed - now distinguishes NotFound from other IO errors
2 main.js L135-155 Hash mismatch warning only in console Fixed - added user-visible #stale-comments-banner with dismiss button
3 main.js L221-255 Badge text leaks into block text extraction Fixed - uses data-count attribute + CSS ::after; clones and strips badges before textContent reads

Outside-Diff Comment (1)

# File Finding Status
4 main.js L60-105 Stale selection persists across file loads Fixed - selectedBlocks reset and add button hidden at start of loadFile()

Nitpick Comments (3)

# File Finding Status
5 app.css L494-498 Hardcoded rgba color for selected block Fixed - uses color-mix(in srgb, var(--link) 15%, transparent)
6 index.html L74-107 Missing accessibility attributes on modals Fixed - added role="dialog", aria-modal, aria-labelledby, and aria-label attributes
7 main.js L345-421 Debug console.log in delete flow Fixed - removed all debug logs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/tauri/src-tauri/src/lib.rs`:
- Around line 211-217: The function hash_file currently reads file contents with
read_to_string which fails on non‑UTF8 files; change it to read raw bytes via
std::fs::read inside fn hash_file so you hash the raw byte slice (pass the
Vec<u8> or &[u8] to Sha256::digest) and return the hex string as before; update
the error mapping (map_err on std::fs::read) and keep the function signature and
return behavior intact.

In `@apps/tauri/src/main.js`:
- Around line 143-165: When loadCommentsForFile fails and you reset
commentsData, also clear the UI so stale entries aren't shown: inside the catch
block for loadCommentsForFile, after setting commentsData = { version: "1.0",
file_hash: "", comments: [] }, call the UI-cleanup functions (e.g.
hideStaleCommentsBanner(), hideBottomBar() or hideBottomBar equivalent,
renderCommentBadges(), updateBottomBar()) to ensure badges, banners and the
bottom bar/list reflect the cleared commentsData; reference loadCommentsForFile,
commentsData, showStaleCommentsBanner/hideStaleCommentsBanner,
renderCommentBadges, updateBottomBar, and showBottomBar to locate where to add
the calls.

Comment thread apps/tauri/src-tauri/src/lib.rs
Comment thread apps/tauri/src/main.js
@wilcorrea

Copy link
Copy Markdown
Contributor Author

Code Review Feedback - Round 2 Addressed

Both new findings from CodeRabbit (second review pass) resolved in commit 543f72f.

# File Finding Status
1 lib.rs L211-217 hash_file uses read_to_string which fails on non-UTF-8 files Fixed - now uses std::fs::read for raw byte hashing
2 main.js L143-165 loadCommentsForFile catch block does not clear UI state Fixed - added renderCommentBadges(), updateBottomBar(), hideBottomBar(), hideStaleCommentsBanner() in catch block

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
apps/tauri/src/main.js (3)

172-182: Consider surfacing save errors to the user.

Save failures are currently only logged to console. Users may unknowingly lose comments if saves fail silently. A brief toast or banner would improve reliability feedback.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/tauri/src/main.js` around lines 172 - 182, The catch in
saveCommentsForFile currently only logs errors to console; update the catch
block in saveCommentsForFile to surface failures to the user by invoking the
app's UI notification method (e.g., showToast, showErrorBanner, or equivalent)
with a concise message like "Failed to save comments for {currentPath}" and
include error details for troubleshooting; ensure the notification is
non-blocking and keep the console.error for debugging, and consider returning or
propagating a failure indicator from saveCommentsForFile so callers can react if
needed.

397-407: Block chip labels may be unclear to users.

The L{number} format (e.g., "L1", "L2") extracted from IDs like mkw-list-1 may confuse users—does "L" mean List, Line, or Level? Consider using more descriptive prefixes (e.g., "H1" for headings, "P1" for paragraphs, "§1" generically) or showing a tooltip with the block type.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/tauri/src/main.js` around lines 397 - 407, The block chip labels use an
ambiguous "L{number}" string; update the label generation in the
comment.block_ids.forEach loop to derive a clearer prefix from the blockId or
block element (e.g., "H" for headings, "P" for paragraphs, or "§" for generic
blocks) instead of always using "L" and set chip.textContent accordingly, and
add a descriptive tooltip (set chip.title) based on the resolved block type so
users see the meaning on hover; locate this logic around
comment.block_ids.forEach, chip.textContent, blockId.match, and chip.onclick to
implement the change.

312-332: Consider using CSS variables for the padding value.

The 64px padding is hardcoded and must stay in sync with CSS. Using a CSS variable (e.g., var(--bottom-bar-collapsed-height)) or calculating from the element would be more maintainable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/tauri/src/main.js` around lines 312 - 332, The
showBottomBar/hideBottomBar functions use a hardcoded "64px" padding; change
them to read a CSS variable from the bottom-bar element (e.g.,
getComputedStyle(bottomBar).getPropertyValue('--bottom-bar-collapsed-height'))
and use that value for content-area.style.paddingBottom, falling back to the
existing "64px" if the variable is missing or empty; ensure you trim the
returned value and apply it directly (or compute px if you parse numbers) so the
JS stays in sync with the bottom-bar CSS variable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/tauri/src/main.js`:
- Around line 614-617: The truncation always appends "..." because the code
unconditionally does clone.textContent.substring(0, 100) + "..."; change the
logic in the block that handles selectedBlocks with clone/preview so you compute
the fullText = clone.textContent, then set preview.textContent to
fullText.slice(0, 100) plus "..." only when fullText.length > 100 (otherwise use
fullText as-is); update references to selectedBlocks, clone, and preview
accordingly so short content is not suffixed with ellipsis.

---

Nitpick comments:
In `@apps/tauri/src/main.js`:
- Around line 172-182: The catch in saveCommentsForFile currently only logs
errors to console; update the catch block in saveCommentsForFile to surface
failures to the user by invoking the app's UI notification method (e.g.,
showToast, showErrorBanner, or equivalent) with a concise message like "Failed
to save comments for {currentPath}" and include error details for
troubleshooting; ensure the notification is non-blocking and keep the
console.error for debugging, and consider returning or propagating a failure
indicator from saveCommentsForFile so callers can react if needed.
- Around line 397-407: The block chip labels use an ambiguous "L{number}"
string; update the label generation in the comment.block_ids.forEach loop to
derive a clearer prefix from the blockId or block element (e.g., "H" for
headings, "P" for paragraphs, or "§" for generic blocks) instead of always using
"L" and set chip.textContent accordingly, and add a descriptive tooltip (set
chip.title) based on the resolved block type so users see the meaning on hover;
locate this logic around comment.block_ids.forEach, chip.textContent,
blockId.match, and chip.onclick to implement the change.
- Around line 312-332: The showBottomBar/hideBottomBar functions use a hardcoded
"64px" padding; change them to read a CSS variable from the bottom-bar element
(e.g.,
getComputedStyle(bottomBar).getPropertyValue('--bottom-bar-collapsed-height'))
and use that value for content-area.style.paddingBottom, falling back to the
existing "64px" if the variable is missing or empty; ensure you trim the
returned value and apply it directly (or compute px if you parse numbers) so the
JS stays in sync with the bottom-bar CSS variable.

Comment thread apps/tauri/src/main.js Outdated
- Fix ellipsis always appended on short preview text
- Surface save errors via banner instead of console only
- Use descriptive block chip labels (H, P, Li, C, Q) with tooltips
- Replace hardcoded padding with CSS variable
@wilcorrea

Copy link
Copy Markdown
Contributor Author

Review comments addressed in fb84418

All CodeRabbit comments from the latest review round have been reviewed and resolved:

Actionable fixes (implemented)

  • Truncation always appends ellipsis (main.js:617): Preview text now only adds ... when content exceeds 100 characters.

Nitpick fixes (implemented)

  • Surface save errors to user (main.js:172-182): Save failures now display a visible banner instead of only logging to console.
  • Block chip labels unclear (main.js:397-407): Chips now show descriptive prefixes (H for heading, P for paragraph, Li for list, C for code, Q for quote) with tooltips showing the full block type.
  • Hardcoded padding value (main.js:312-332): Replaced hardcoded 64px with CSS variable --bottom-bar-padding read at runtime via getComputedStyle.

Already addressed in previous commits (verified)

  • Clear stale selection on file load (main.js:60-105): Already clearing selectedBlocks, hiding the add button, and hiding stale banner in loadFile(). DOM elements are replaced via innerHTML.
  • Theme-aware selected block color (app.css:494-498): Already using color-mix(in srgb, var(--link) 15%, transparent).
  • Accessibility attributes (index.html:74-107): Modals already have role="dialog", aria-modal="true", aria-labelledby, and buttons have aria-label.
  • Remove debug logs (main.js:345-421): console.log calls in the delete flow were already removed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
apps/tauri/src/main.js (2)

434-439: Using synchronous confirm() blocks the UI thread.

The native confirm() dialog is blocking. In a Tauri app, this works but could freeze the UI momentarily. Consider using Tauri's dialog API for consistency with the rest of the app.

♻️ Consider using Tauri's confirm dialog
+const { confirm } = window.__TAURI__.dialog;
+
 deleteBtn.onclick = async () => {
-  const result = await confirm("Delete this comment?");
+  const result = await confirm("Delete this comment?", { 
+    title: "Delete Comment",
+    kind: "warning"
+  });
   if (result) {
     deleteComment(comment.id);
   }
 };

Note: confirm is already imported at line 3 as part of open from dialog, so you'd need to add it to the destructuring.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/tauri/src/main.js` around lines 434 - 439, The code uses the blocking
native confirm in the deleteBtn.onclick handler; update the handler to call
Tauri's asynchronous confirm from the dialog API (ensure confirm is included in
the destructured import alongside open) and await its promise before calling
deleteComment(comment.id) so the UI is not blocked — modify the
deleteBtn.onclick async handler to use the imported confirm and call
deleteComment only when the awaited result is true.

179-186: Save error reuses stale-comments-banner with different semantics.

The error handling correctly surfaces save failures to users (good!), but repurposing the stale-comments-banner for save errors could cause confusion if both conditions occur. Consider whether a dedicated error banner or a more generic message element would be cleaner.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/tauri/src/main.js` around lines 179 - 186, The catch block is reusing
the "stale-comments-banner" for save failures which can conflict with the
stale-comments state; instead create/use a dedicated banner id (e.g.,
"save-error-banner" or a generic "error-banner") and update the catch to select
that element (banner = document.getElementById("save-error-banner")) and set its
span textContent and display independently so stale-comments and save errors can
show concurrently; also add the corresponding DOM element or ensure the generic
error banner exists and is toggled separately from the "stale-comments-banner".
apps/tauri/src/app.css (2)

296-325: Stale banner uses hardcoded colors instead of theme variables.

The banner styling uses fixed colors (#f0ad4e, #333) that won't adapt to light/dark theme changes, potentially causing accessibility or visual consistency issues in dark mode.

♻️ Consider using theme-aware colors
 `#stale-comments-banner` {
   position: fixed;
   top: 52px;
   left: 0;
   right: 0;
   display: flex;
   align-items: center;
   justify-content: center;
   gap: 12px;
   padding: 8px 16px;
-  background: `#f0ad4e`;
-  color: `#333`;
+  background: var(--warning-bg, `#f0ad4e`);
+  color: var(--warning-text, `#333`);
   font-size: 12px;
   font-weight: 500;
   z-index: 200;
 }

Then define --warning-bg and --warning-text in both html.light and html.dark theme blocks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/tauri/src/app.css` around lines 296 - 325, The stale banner CSS
(`#stale-comments-banner` and its button rules) uses hardcoded colors (`#f0ad4e` and
`#333`); change these to theme variables (e.g., use var(--warning-bg) for
background and var(--warning-text) for text and button color) and ensure you add
definitions for --warning-bg and --warning-text inside your html.light and
html.dark theme blocks so the banner adapts to both themes.

442-445: Hardcoded RGBA in box-shadow may not match theme.

The .highlight state uses a hardcoded color rgba(73, 163, 255, 0.2) which approximates --link but won't update if the link color changes per theme.

♻️ Consider using color-mix for consistency
 .bottom-bar-item.highlight {
   border-color: var(--link);
-  box-shadow: 0 0 0 2px rgba(73, 163, 255, 0.2);
+  box-shadow: 0 0 0 2px color-mix(in srgb, var(--link) 20%, transparent);
 }

This mirrors the approach already used in .commentable-block.selected at line 530.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/tauri/src/app.css` around lines 442 - 445, The box-shadow in
.bottom-bar-item.highlight uses a hardcoded rgba value; replace it with a
color-mix using the --link CSS variable so the highlight tracks theme changes
(follow the same pattern used in .commentable-block.selected). Locate the
.bottom-bar-item.highlight rule and change the box-shadow to use color-mix(in
srgb, var(--link) <percentage>, transparent) (or the exact color-mix variant
used in .commentable-block.selected) so the shadow alpha is derived from --link
instead of a fixed rgba.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/tauri/src/app.css`:
- Around line 296-325: The stale banner CSS (`#stale-comments-banner` and its
button rules) uses hardcoded colors (`#f0ad4e` and `#333`); change these to theme
variables (e.g., use var(--warning-bg) for background and var(--warning-text)
for text and button color) and ensure you add definitions for --warning-bg and
--warning-text inside your html.light and html.dark theme blocks so the banner
adapts to both themes.
- Around line 442-445: The box-shadow in .bottom-bar-item.highlight uses a
hardcoded rgba value; replace it with a color-mix using the --link CSS variable
so the highlight tracks theme changes (follow the same pattern used in
.commentable-block.selected). Locate the .bottom-bar-item.highlight rule and
change the box-shadow to use color-mix(in srgb, var(--link) <percentage>,
transparent) (or the exact color-mix variant used in
.commentable-block.selected) so the shadow alpha is derived from --link instead
of a fixed rgba.

In `@apps/tauri/src/main.js`:
- Around line 434-439: The code uses the blocking native confirm in the
deleteBtn.onclick handler; update the handler to call Tauri's asynchronous
confirm from the dialog API (ensure confirm is included in the destructured
import alongside open) and await its promise before calling
deleteComment(comment.id) so the UI is not blocked — modify the
deleteBtn.onclick async handler to use the imported confirm and call
deleteComment only when the awaited result is true.
- Around line 179-186: The catch block is reusing the "stale-comments-banner"
for save failures which can conflict with the stale-comments state; instead
create/use a dedicated banner id (e.g., "save-error-banner" or a generic
"error-banner") and update the catch to select that element (banner =
document.getElementById("save-error-banner")) and set its span textContent and
display independently so stale-comments and save errors can show concurrently;
also add the corresponding DOM element or ensure the generic error banner exists
and is toggled separately from the "stale-comments-banner".

- Replace hardcoded banner colors with CSS variables (--warning-bg,
  --warning-text, --error-bg, --error-text) for light/dark themes
- Create dedicated save-error-banner instead of reusing stale-comments-banner
- Use Tauri dialog confirm() instead of blocking native confirm()
- Replace hardcoded RGBA in .bottom-bar-item.highlight with color-mix()
- Extract shared banner styles into .notification-banner base class
@wilcorrea

Copy link
Copy Markdown
Contributor Author

Addressed CodeRabbit nitpicks from latest reviews

Fixed in 8221278:

Review 3 nitpicks (already resolved in code before this commit):

  • Block chip labels (main.js ~397-407): Already using descriptive prefixes (H, P, Li, C, Q) with tooltips showing block type
  • CSS variable for padding (main.js ~312-332): Already reading --bottom-bar-padding from computed style with 64px fallback
  • Save errors surface (main.js ~172-182): Now uses a dedicated #save-error-banner (see below)

Review 4 nitpicks (all addressed in this commit):

  • Dedicated save-error-banner: Created a separate #save-error-banner element with error-themed styling (--error-bg, --error-text) instead of reusing #stale-comments-banner. Both banners can now display concurrently
  • Tauri dialog API for confirm: Replaced blocking native confirm() with window.__TAURI__.dialog.confirm() using { title: "Delete Comment", kind: "warning" }
  • Theme-aware banner colors: Defined --warning-bg, --warning-text, --error-bg, --error-text CSS variables in both html.light and html.dark theme blocks. Extracted shared styles into .notification-banner base class
  • color-mix for highlight: Replaced hardcoded rgba(73, 163, 255, 0.2) in .bottom-bar-item.highlight with color-mix(in srgb, var(--link) 20%, transparent), consistent with .commentable-block.selected

Review 1 nitpick (already clean):

  • Debug console.log in delete flow: Already removed in previous commit

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/tauri/src/app.css`:
- Around line 352-356: The CSS block for selector `#bottom-bar` has custom
properties followed immediately by a standard declaration, which Stylelint
flags; update the `#bottom-bar` rule (the block containing
--bottom-bar-collapsed-height and --bottom-bar-padding) to insert a single blank
line before the first standard declaration (position: fixed;) so there is an
empty line separating custom property declarations from regular declarations.

In `@apps/tauri/src/index.html`:
- Around line 99-109: The dynamic notification banners with ids
stale-comments-banner and save-error-banner need ARIA live regions so screen
readers announce them; update the elements (and optionally their dismiss buttons
stale-banner-dismiss and save-error-dismiss) to include an appropriate aria-live
attribute (e.g., aria-live="polite" or aria-live="assertive" depending on
importance) and ensure aria-atomic="true" so the entire message is read; also
verify that when the banners are shown/hidden the DOM text changes trigger the
live region announcement (e.g., by setting innerText or toggling display) rather
than only using CSS visibility.

In `@apps/tauri/src/main.js`:
- Around line 19-20: saveCommentsForFile currently allows concurrent disk writes
that can finish out-of-order and overwrite newer data; implement a serialization
queue for saves (e.g., a per-file promise chain or an in-memory FIFO) so each
invocation of saveCommentsForFile waits for the previous save to complete before
writing, and resolve/reject the queued promise accordingly; reference the
saveCommentsForFile function and the commentsData/selectedBlocks state and
ensure successful queued saves clear any error banner (or error flag) while
failures set it, preventing concurrent writes from clobbering newer changes.

Comment thread apps/tauri/src/app.css
Comment thread apps/tauri/src/index.html
Comment thread apps/tauri/src/main.js
- Queue concurrent saveCommentsForFile calls to prevent out-of-order
  writes from overwriting newer data
- Add aria-live roles to notification banners for screen reader support
- Add empty line before standard declarations in #bottom-bar CSS
- Replace parentheses with GitHub-style pill badge for comment count
- Unify Generate Review button style with Add Comment button
- Make review modal responsive with flexible height to prevent button clipping
- Replace height animation with transform for better performance (GPU-accelerated)
- Add dedicated toggle button for bottom bar expand/collapse
- Standardize all icon buttons with .icon-button class
- Reduce bottom bar border to 1px and height to 46px
- Normalize icon sizes to 14px across all buttons
- Remove text from refresh button for consistency
- Remove readonly attribute from review prompt textarea
- Change resize from none to vertical for user customization
- Use code-bg background for subtle visual differentiation
@wilcorrea
wilcorrea merged commit b5417a2 into main Feb 23, 2026
1 check passed
@wilcorrea
wilcorrea deleted the feat/plan-review-comments branch February 23, 2026 00:07
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.

1 participant