Skip to content

feat(ui): panel pin/dock, FLIP animations and workspace management#43

Merged
wilcorrea merged 8 commits intomainfrom
feat/ui-improvements
Mar 5, 2026
Merged

feat(ui): panel pin/dock, FLIP animations and workspace management#43
wilcorrea merged 8 commits intomainfrom
feat/ui-improvements

Conversation

@wilcorrea
Copy link
Copy Markdown
Contributor

@wilcorrea wilcorrea commented Mar 5, 2026

Summary

  • Removed deprecated apps: Deleted apps/macos/ and apps/web/ directories (all development in Tauri)
  • Panel pin/dock: Outline and Review panels can be pinned (docked to sides, pushing content) or left as floating overlays, with state persisted in localStorage
  • FLIP-based animations: Replaced clip-path animations with transform-based FLIP technique for expand/minimize transitions, adding backdrop dimming effect
  • Workspace card redesign: Close is now instant (no confirmation dialog), added "Forget" action with confirmation that deletes all sessions/plans/comments via new forget_workspace_data Rust command
  • Outline icon: Changed from Hash (#) to AlignLeft for better UX affordance
  • Type fix: Added missing emit to Tauri event type declarations

Test plan

  • Open a markdown file → outline toggle button shows AlignLeft icon
  • Open outline → click pin → panel docks to left, content area shrinks
  • Close and reopen outline → stays pinned (localStorage persistence)
  • Same behavior for Review panel on the right
  • Pin both panels simultaneously → content area narrows but remains functional
  • Expand a workspace card → FLIP animation with backdrop effect
  • Minimize → smooth reverse animation back to card
  • Click X on workspace card → closes immediately (no dialog)
  • Click forget (unlink icon) on directory workspace → confirmation dialog → deletes data
  • cd apps/tauri && npm run build compiles without errors
  • npm test — all 69 tests pass

Summary by CodeRabbit

  • Removed Features

    • Native macOS app and web app bundles, installers and related UI have been removed; Tauri desktop app remains.
  • New Features

    • Forget workspace/document action to remove items from the Home screen.
    • Pin/unpin controls for outline and review panels with persistent state.
  • Bug Fixes / UX

    • Smoother multi-phase expand/minimize animations; improved panel docking/floating behavior.
  • Chores

    • Updated localization strings for new flows and controls.
  • Tests

    • Added/updated tests for outline pin and forget flows.

Deletes all sessions, plans, and comments for a workspace in one call.
- Outline and Review panels can be pinned (docked) or floating
- FLIP-based expand/minimize animations with backdrop
- Workspace cards: direct close, forget action with confirmation
- Outline icon changed from Hash to AlignLeft
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 5, 2026

Warning

Rate limit exceeded

@wilcorrea has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 22 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 07cf973a-639b-49af-a83b-a18c74ad2492

📥 Commits

Reviewing files that changed from the base of the PR and between 94aafc8 and b45994f.

📒 Files selected for processing (5)
  • apps/tauri/src-tauri/src/sessions.rs
  • apps/tauri/src/App.tsx
  • apps/tauri/src/__tests__/components/WorkspaceCard.test.tsx
  • apps/tauri/src/components/MarkdownViewer.tsx
  • apps/tauri/src/components/WorkspaceCard.tsx
📝 Walkthrough

Walkthrough

Removes the macOS app and extensive web app (sources, UI primitives, assets, configs) and adds Tauri backend commands plus frontend flows to forget workspace data and to pin/dock review/outline panels.

Changes

Cohort / File(s) Summary
macOS app removal
apps/macos/Makefile, apps/macos/project.yml, apps/macos/Sources/Arandu/..., apps/macos/scripts/*
Entire macOS target deleted: build/project configs, Swift sources, Info.plist, resources, installer and launcher scripts removed.
Web app removal (large)
apps/web/... (e.g. apps/web/src/*, apps/web/package.json, apps/web/tailwind.config.ts, apps/web/vite.config.ts, apps/web/src/components/ui/*, apps/web/src/lib/*, apps/web/src/store/*, apps/web/src/types/*, apps/web/src/pages/*, apps/web/public/*, apps/web/*.md)
Mass deletion of the web application: React app bootstrap, pages, many UI primitives/components, hooks, store, types, styles, build/test configs, docs, and assets.
Tauri backend: delete/forget handlers
apps/tauri/src-tauri/src/comments.rs, apps/tauri/src-tauri/src/sessions.rs, apps/tauri/src-tauri/src/lib.rs
Adds DB-level deletion functions and registers a Tauri command to forget workspace data (deletes comments/file_hashes, sessions; transactional DB operations).
Tauri frontend: forget workspace flow
apps/tauri/src/contexts/AppContext.tsx, apps/tauri/src/components/WorkspaceCard.tsx, apps/tauri/src/components/DirectoryWorkspace.tsx, apps/tauri/src/App.tsx, apps/tauri/src/__tests__/*
Introduces forgetWorkspace API and onForget prop, UI for forgetting a workspace (removes prior close-confirm flows), state updates and unwatching logic in AppContext; tests updated/added for WorkspaceCard behavior.
Tauri frontend: panel pinning & docking
apps/tauri/src/components/OutlineSidebar.tsx, apps/tauri/src/components/ReviewPanel.tsx, apps/tauri/src/components/MarkdownViewer.tsx, apps/tauri/src/App.tsx
Adds pinned?: boolean and onTogglePin?: () => void to panels; implements localStorage-backed pin state, docked vs floating placements, and animation/overlay logic in App.tsx and MarkdownViewer.
Localization & typing
apps/tauri/src/locales/en.json, apps/tauri/src/locales/pt-BR.json, apps/tauri/src/vite-env.d.ts
Adds localization keys for forget/pin actions and extends Tauri window event typing with emit(event,payload).
Tests, configs & misc docs removed
apps/web/src/test/*, apps/web/.gitignore, apps/web/components.json, apps/web/README.md, apps/web/.lovable/*
Removes example tests, shadcn config, README/plan docs and alters .gitignore entries for the web app.

Sequence Diagram(s)

sequenceDiagram
    participant UI as Frontend (Tauri)
    participant API as Tauri Command Layer
    participant DB as SQLite
    participant FS as Filesystem (app data)

    UI->>API: invoke("forget_workspace_data", workspace_path, workspace_type)
    API->>DB: begin transaction
    alt workspace_type == "directory"
        API->>DB: delete from comments where path LIKE workspace_path/%
        API->>DB: delete from file_hashes where file_path LIKE workspace_path/%
        API->>DB: delete sessions where workspace_path = workspace_path
        DB-->>API: return deleted session IDs
        API->>FS: remove plan files for each session ID in app data
    else
        API->>DB: delete from comments where file_path = workspace_path
        API->>DB: delete from file_hashes where file_path = workspace_path
    end
    API->>DB: commit
    DB-->>API: commit result
    API-->>UI: return success / error
    UI->>FS: unwatches file (if applicable) and removes workspace from client state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I hopped through code and cleared a trail,

Mac and web footprints fade from the vale,
Tauri keeps the burrow tidy and hale,
Pin the panels, forget a space without fail,
I nibble bugs and leave a tidy tail.

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (3)
apps/tauri/src/__tests__/components/OutlineSidebar.test.tsx (1)

48-49: Avoid hardcoding translated strings in selectors.

These assertions are tightly coupled to Portuguese copy; a locale/default-language change will break tests unrelated to behavior. Prefer role-based queries with stable labels (or mock t to return keys).

Also applies to: 58-60, 70-71

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

In `@apps/tauri/src/__tests__/components/OutlineSidebar.test.tsx` around lines 48
- 49, Tests in OutlineSidebar.test.tsx are using hardcoded Portuguese strings
(e.g., screen.getByTitle('Fixar painel')) which will break if locales change;
replace those string-based selectors with stable queries like
getByRole/getByLabelText (e.g., screen.getByRole('button', { name:
/pin-panel|fix-panel|pin/i }) or use aria-labels) or alternatively mock the
translation function (mock the i18n/t used in the component to return
predictable keys) and update the three occurrences (the getByTitle call at the
shown line plus the assertions around 58-60 and 70-71) to use role-based queries
or mocked labels instead of literal translated text.
apps/tauri/src/components/MarkdownViewer.tsx (1)

376-398: Use shadcn Button for these new panel toggles.

The new outline/review toggle controls are plain <button> elements; in this components layer, UI primitives should use shadcn components.

🔧 Proposed fix
-          {!outlineOpen && headings.length > 0 && (
-            <button
+          {!outlineOpen && headings.length > 0 && (
+            <Button
+              variant="outline"
+              size="icon"
               onClick={() => setOutlineOpen(true)}
-              className="absolute top-3 left-3 z-20 h-8 w-8 flex items-center justify-center rounded-md bg-card border border-border text-muted-foreground hover:text-foreground hover:bg-accent transition-colors shadow-sm"
+              className="absolute top-3 left-3 z-20 h-8 w-8 text-muted-foreground hover:text-foreground shadow-sm"
               title={t("outline.title")}
             >
               <AlignLeft className="h-4 w-4" />
-            </button>
+            </Button>
           )}

As per coding guidelines, "Use shadcn/ui for all UI primitives; install new components via npx shadcn@latest add <component>".

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

In `@apps/tauri/src/components/MarkdownViewer.tsx` around lines 376 - 398, Replace
the plain <button> toggles with the shadcn Button component: import and use
Button for the outline toggle (wrapping AlignLeft) and the review toggle
(wrapping MessageSquare), keeping the same onClick handlers (setOutlineOpen, and
the combined setReviewOpen + review.setIsPanelOpen) and title props; move the
badge that shows review.unresolvedCount into Button's content (preserving
styling or using Button variants/size) and keep existing className/aria
attributes as needed. If Button is not yet added, run npx shadcn@latest add
button then update the two elements referenced by setOutlineOpen and the review
toggle logic (review.setIsPanelOpen, review.unresolvedCount) to use the shadcn
Button API instead of a raw button.
apps/tauri/src/App.tsx (1)

20-24: Replace hardcoded overlay/shadow colors with theme variables.

The new animation styling introduces hardcoded color values (rgba(...), bg-black/45), which breaks theme-token consistency.

As per coding guidelines, "Use TailwindCSS with HSL CSS variables for theming instead of hardcoded color values".

Also applies to: 223-227

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

In `@apps/tauri/src/App.tsx` around lines 20 - 24, The constants (EXPAND_EASING,
MINIMIZE_EASING, DURATION_S, SHADOW) currently embed hardcoded colors (e.g.,
"rgba(...)" and "bg-black/45"); update the styling to use theme HSL CSS
variables/Tailwind tokens instead: replace any rgba(...) overlay values with a
CSS variable like var(--overlay-color) or a Tailwind HSL variable (e.g.,
theme('colors.overlay') / --tw-overlay) and change SHADOW to reference HSL
variables for color stops (e.g., "0 30px 90px hsla(var(--shadow-h),
var(--shadow-s), var(--shadow-l), 0.55), 0 0 0 0.5px hsla(var(--highlight-h),
var(--highlight-s), var(--highlight-l), 0.1)"); also update places flagged
(around the 223-227 region) where bg-black/45 is used to use the same theme
variable (e.g.,
bg-[hsla(var(--overlay-h),var(--overlay-s),var(--overlay-l),0.45)] or a named
Tailwind token) so all overlay and shadow colors come from theme variables
rather than hardcoded rgba values.
🤖 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/comments.rs`:
- Around line 143-149: The two DELETEs in delete_comments_for_file run
separately and can leave stale data if the second fails; wrap both operations in
a single database transaction by creating a Transaction from conn (e.g.,
conn.transaction()), run the two deletes against the transaction (tx.execute
with params![file_path]), map/propagate errors to the same Result<String, ...>
format, and commit the transaction (tx.commit()) so either both deletes succeed
or none are applied.

In `@apps/tauri/src-tauri/src/sessions.rs`:
- Around line 325-334: The directory "forget" branch currently only deletes
sessions/plans (delete_workspace_sessions + delete_plan) but leaves comments and
file_hashes behind; add and call a new function delete_comments_for_workspace in
apps/tauri/src-tauri/src/comments.rs and invoke it from the workspace_type ==
"directory" branch (alongside delete_workspace_sessions and delete_plan) to
purge all comments and file_hashes for files under the workspace; implement
delete_comments_for_workspace to accept the DB connection and workspace_path,
look up all file paths in that workspace and remove their rows from the comments
and file_hashes tables (mirroring the behavior of delete_comments_for_file but
operating on all files in the workspace) and return appropriate Result<> so the
caller can propagate errors.
- Around line 329-331: The loop in the forget flow swallows errors from
crate::plan_file::delete_plan by using let _ = ..., so plan deletion failures
are ignored; change the loop to propagate errors (e.g., replace let _ =
crate::plan_file::delete_plan(&app_data, id); with
crate::plan_file::delete_plan(&app_data, id)? inside the same function so any
filesystem error returns early, or collect results and return an aggregated Err
if any delete_plan call fails), ensuring the surrounding function's signature
returns a compatible Result so the ? operator can be used.

In `@apps/tauri/src/App.tsx`:
- Around line 83-89: The animation timeout assignment in the expand/minimize
flows can leave previous timers active; before calling window.setTimeout to
assign animTimeoutRef.current (used around ANIMATION_DURATION and in functions
like finishExpand and the minimize flow), clear any existing timer by checking
animTimeoutRef.current and calling clearTimeout(animTimeoutRef.current) (and
then nulling it) before reassigning, and likewise clear the timer when the
component unmounts to prevent stale callbacks from calling setAnimPhase,
setFlipTransform, setTransitionEnabled, or touching sourceCard.style.opacity
after the component has changed.

In `@apps/tauri/src/components/MarkdownViewer.tsx`:
- Around line 366-370: The HTML returned from render_markdown is being fed
directly into the article via dangerouslySetInnerHTML which can introduce XSS;
sanitize the markup first (e.g., run html through a sanitizeHtml call that
strips <script>, inline event handlers (on*), javascript: and data: URLs, and
unsafe attributes) and use the sanitized string in dangerouslySetInnerHTML
(replace the current html variable with sanitizedHtml), or alternatively enforce
this sanitization in the Rust render_markdown command contract so the value
assigned to dangerouslySetInnerHTML is guaranteed safe; update the code paths
around render_markdown and the article element (articleRef /
dangerouslySetInnerHTML) to use the sanitized output.
- Around line 57-77: The component must listen for window "storage" events and
update outlinePinned and reviewPinned when OUTLINE_PINNED_KEY or
REVIEW_PINNED_KEY change; add a useEffect that registers a storage event handler
which checks event.key (OUTLINE_PINNED_KEY or REVIEW_PINNED_KEY), reads the new
value (localStorage.getItem or event.newValue), converts it to a boolean, and
calls setOutlinePinned or setReviewPinned accordingly, and remove the listener
in the cleanup; reference OUTLINE_PINNED_KEY, REVIEW_PINNED_KEY,
setOutlinePinned, setReviewPinned, and the existing
toggleOutlinePin/toggleReviewPin to keep behavior consistent.

In `@apps/tauri/src/components/OutlineSidebar.tsx`:
- Around line 69-77: The icon-only header action Buttons (the pin toggle and
close buttons rendered when onTogglePin/onClose are provided, using props
pinned, Pin/PinOff and X) lack accessible names; update those <Button> instances
to include aria-label and title attributes (use t(...) for localized labels,
e.g., t(pinned ? 'outline.unpin' : 'outline.pin') for the pin button and
t('outline.close') for the close button) and apply the same change to the other
occurrence of the close button (the one around lines 95-103) so both icon-only
controls have accessible names.

In `@apps/tauri/src/components/WorkspaceCard.tsx`:
- Around line 84-87: The confirm action for deleting a workspace in
WorkspaceCard currently calls onForget(workspace.id) without awaiting or
handling errors; update the AlertDialogAction onClick handler to call an async
wrapper that awaits onForget(workspace.id) and catches any rejection (e.g.,
try/catch) to show user feedback (toast/Alert) and prevent unhandled promise
rejections; ensure you reference the existing onForget function and
AlertDialogAction component so the handler replacement is localized to that
confirm button.

---

Nitpick comments:
In `@apps/tauri/src/__tests__/components/OutlineSidebar.test.tsx`:
- Around line 48-49: Tests in OutlineSidebar.test.tsx are using hardcoded
Portuguese strings (e.g., screen.getByTitle('Fixar painel')) which will break if
locales change; replace those string-based selectors with stable queries like
getByRole/getByLabelText (e.g., screen.getByRole('button', { name:
/pin-panel|fix-panel|pin/i }) or use aria-labels) or alternatively mock the
translation function (mock the i18n/t used in the component to return
predictable keys) and update the three occurrences (the getByTitle call at the
shown line plus the assertions around 58-60 and 70-71) to use role-based queries
or mocked labels instead of literal translated text.

In `@apps/tauri/src/App.tsx`:
- Around line 20-24: The constants (EXPAND_EASING, MINIMIZE_EASING, DURATION_S,
SHADOW) currently embed hardcoded colors (e.g., "rgba(...)" and "bg-black/45");
update the styling to use theme HSL CSS variables/Tailwind tokens instead:
replace any rgba(...) overlay values with a CSS variable like
var(--overlay-color) or a Tailwind HSL variable (e.g., theme('colors.overlay') /
--tw-overlay) and change SHADOW to reference HSL variables for color stops
(e.g., "0 30px 90px hsla(var(--shadow-h), var(--shadow-s), var(--shadow-l),
0.55), 0 0 0 0.5px hsla(var(--highlight-h), var(--highlight-s),
var(--highlight-l), 0.1)"); also update places flagged (around the 223-227
region) where bg-black/45 is used to use the same theme variable (e.g.,
bg-[hsla(var(--overlay-h),var(--overlay-s),var(--overlay-l),0.45)] or a named
Tailwind token) so all overlay and shadow colors come from theme variables
rather than hardcoded rgba values.

In `@apps/tauri/src/components/MarkdownViewer.tsx`:
- Around line 376-398: Replace the plain <button> toggles with the shadcn Button
component: import and use Button for the outline toggle (wrapping AlignLeft) and
the review toggle (wrapping MessageSquare), keeping the same onClick handlers
(setOutlineOpen, and the combined setReviewOpen + review.setIsPanelOpen) and
title props; move the badge that shows review.unresolvedCount into Button's
content (preserving styling or using Button variants/size) and keep existing
className/aria attributes as needed. If Button is not yet added, run npx
shadcn@latest add button then update the two elements referenced by
setOutlineOpen and the review toggle logic (review.setIsPanelOpen,
review.unresolvedCount) to use the shadcn Button API instead of a raw button.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ec4ca811-d4ca-49b3-98e5-54322b6e907c

📥 Commits

Reviewing files that changed from the base of the PR and between c3aa469 and 141df50.

⛔ Files ignored due to path filters (5)
  • apps/macos/Sources/Arandu/Resources/highlight.min.js is excluded by !**/*.min.js
  • apps/web/bun.lockb is excluded by !**/bun.lockb
  • apps/web/package-lock.json is excluded by !**/package-lock.json
  • apps/web/public/favicon.ico is excluded by !**/*.ico
  • apps/web/public/placeholder.svg is excluded by !**/*.svg
📒 Files selected for processing (113)
  • apps/macos/Makefile
  • apps/macos/Sources/Arandu/Info.plist
  • apps/macos/Sources/Arandu/Resources/AppIcon.icns
  • apps/macos/Sources/Arandu/Resources/highlight-dark.min.css
  • apps/macos/Sources/Arandu/Resources/highlight-light.min.css
  • apps/macos/Sources/Arandu/Resources/style.css
  • apps/macos/Sources/Arandu/main.swift
  • apps/macos/project.yml
  • apps/macos/scripts/arandu
  • apps/macos/scripts/install.sh
  • apps/tauri/src-tauri/src/comments.rs
  • apps/tauri/src-tauri/src/lib.rs
  • apps/tauri/src-tauri/src/sessions.rs
  • apps/tauri/src/App.tsx
  • apps/tauri/src/__tests__/components/OutlineSidebar.test.tsx
  • apps/tauri/src/__tests__/components/WorkspaceCard.test.tsx
  • apps/tauri/src/components/DirectoryWorkspace.tsx
  • apps/tauri/src/components/HomeScreen.tsx
  • apps/tauri/src/components/MarkdownViewer.tsx
  • apps/tauri/src/components/OutlineSidebar.tsx
  • apps/tauri/src/components/ReviewPanel.tsx
  • apps/tauri/src/components/WorkspaceCard.tsx
  • apps/tauri/src/contexts/AppContext.tsx
  • apps/tauri/src/locales/en.json
  • apps/tauri/src/locales/pt-BR.json
  • apps/tauri/src/vite-env.d.ts
  • apps/web/.gitignore
  • apps/web/.lovable/plan.md
  • apps/web/README.md
  • apps/web/components.json
  • apps/web/eslint.config.js
  • apps/web/index.html
  • apps/web/package.json
  • apps/web/postcss.config.js
  • apps/web/public/robots.txt
  • apps/web/src/App.css
  • apps/web/src/App.tsx
  • apps/web/src/components/NavLink.tsx
  • apps/web/src/components/arandu/ActivityBar.tsx
  • apps/web/src/components/arandu/AranduLayout.tsx
  • apps/web/src/components/arandu/MarkdownViewer.tsx
  • apps/web/src/components/arandu/PrimarySidebar.tsx
  • apps/web/src/components/arandu/ReviewPanel.tsx
  • apps/web/src/components/arandu/StatusBar.tsx
  • apps/web/src/components/arandu/TabBar.tsx
  • apps/web/src/components/arandu/TitleBar.tsx
  • apps/web/src/components/ui/accordion.tsx
  • apps/web/src/components/ui/alert-dialog.tsx
  • apps/web/src/components/ui/alert.tsx
  • apps/web/src/components/ui/aspect-ratio.tsx
  • apps/web/src/components/ui/avatar.tsx
  • apps/web/src/components/ui/badge.tsx
  • apps/web/src/components/ui/breadcrumb.tsx
  • apps/web/src/components/ui/button.tsx
  • apps/web/src/components/ui/calendar.tsx
  • apps/web/src/components/ui/card.tsx
  • apps/web/src/components/ui/carousel.tsx
  • apps/web/src/components/ui/chart.tsx
  • apps/web/src/components/ui/checkbox.tsx
  • apps/web/src/components/ui/collapsible.tsx
  • apps/web/src/components/ui/command.tsx
  • apps/web/src/components/ui/context-menu.tsx
  • apps/web/src/components/ui/dialog.tsx
  • apps/web/src/components/ui/drawer.tsx
  • apps/web/src/components/ui/dropdown-menu.tsx
  • apps/web/src/components/ui/form.tsx
  • apps/web/src/components/ui/hover-card.tsx
  • apps/web/src/components/ui/input-otp.tsx
  • apps/web/src/components/ui/input.tsx
  • apps/web/src/components/ui/label.tsx
  • apps/web/src/components/ui/menubar.tsx
  • apps/web/src/components/ui/navigation-menu.tsx
  • apps/web/src/components/ui/pagination.tsx
  • apps/web/src/components/ui/popover.tsx
  • apps/web/src/components/ui/progress.tsx
  • apps/web/src/components/ui/radio-group.tsx
  • apps/web/src/components/ui/resizable.tsx
  • apps/web/src/components/ui/scroll-area.tsx
  • apps/web/src/components/ui/select.tsx
  • apps/web/src/components/ui/separator.tsx
  • apps/web/src/components/ui/sheet.tsx
  • apps/web/src/components/ui/sidebar.tsx
  • apps/web/src/components/ui/skeleton.tsx
  • apps/web/src/components/ui/slider.tsx
  • apps/web/src/components/ui/sonner.tsx
  • apps/web/src/components/ui/switch.tsx
  • apps/web/src/components/ui/table.tsx
  • apps/web/src/components/ui/tabs.tsx
  • apps/web/src/components/ui/textarea.tsx
  • apps/web/src/components/ui/toast.tsx
  • apps/web/src/components/ui/toaster.tsx
  • apps/web/src/components/ui/toggle-group.tsx
  • apps/web/src/components/ui/toggle.tsx
  • apps/web/src/components/ui/tooltip.tsx
  • apps/web/src/components/ui/use-toast.ts
  • apps/web/src/hooks/use-mobile.tsx
  • apps/web/src/hooks/use-toast.ts
  • apps/web/src/index.css
  • apps/web/src/lib/utils.ts
  • apps/web/src/main.tsx
  • apps/web/src/pages/Index.tsx
  • apps/web/src/pages/NotFound.tsx
  • apps/web/src/store/useAranduStore.ts
  • apps/web/src/test/example.test.ts
  • apps/web/src/test/setup.ts
  • apps/web/src/types/arandu.ts
  • apps/web/src/vite-env.d.ts
  • apps/web/tailwind.config.ts
  • apps/web/tsconfig.app.json
  • apps/web/tsconfig.json
  • apps/web/tsconfig.node.json
  • apps/web/vite.config.ts
  • apps/web/vitest.config.ts
💤 Files with no reviewable changes (96)
  • apps/web/src/components/ui/aspect-ratio.tsx
  • apps/web/src/vite-env.d.ts
  • apps/web/src/components/NavLink.tsx
  • apps/web/src/index.css
  • apps/web/src/components/ui/skeleton.tsx
  • apps/web/src/components/ui/toggle-group.tsx
  • apps/web/src/components/ui/switch.tsx
  • apps/web/src/components/ui/toggle.tsx
  • apps/web/src/components/ui/slider.tsx
  • apps/web/tsconfig.node.json
  • apps/web/package.json
  • apps/web/src/components/ui/textarea.tsx
  • apps/web/src/pages/Index.tsx
  • apps/web/src/components/ui/carousel.tsx
  • apps/web/src/components/arandu/AranduLayout.tsx
  • apps/web/src/components/ui/calendar.tsx
  • apps/web/src/components/arandu/ActivityBar.tsx
  • apps/web/src/components/ui/select.tsx
  • apps/web/src/components/ui/label.tsx
  • apps/web/src/components/ui/input.tsx
  • apps/web/src/test/setup.ts
  • apps/web/src/components/ui/breadcrumb.tsx
  • apps/web/src/components/arandu/ReviewPanel.tsx
  • apps/web/src/components/arandu/StatusBar.tsx
  • apps/web/src/components/ui/hover-card.tsx
  • apps/web/src/components/ui/command.tsx
  • apps/web/src/components/ui/drawer.tsx
  • apps/macos/scripts/arandu
  • apps/web/components.json
  • apps/macos/Sources/Arandu/Resources/style.css
  • apps/web/index.html
  • apps/web/src/components/ui/popover.tsx
  • apps/web/README.md
  • apps/web/src/components/arandu/TitleBar.tsx
  • apps/web/src/App.tsx
  • apps/web/src/store/useAranduStore.ts
  • apps/web/vite.config.ts
  • apps/web/postcss.config.js
  • apps/macos/Sources/Arandu/Resources/highlight-light.min.css
  • apps/macos/project.yml
  • apps/macos/scripts/install.sh
  • apps/web/tsconfig.app.json
  • apps/macos/Makefile
  • apps/web/src/components/ui/navigation-menu.tsx
  • apps/web/src/components/ui/form.tsx
  • apps/web/src/components/ui/checkbox.tsx
  • apps/web/src/hooks/use-mobile.tsx
  • apps/web/src/pages/NotFound.tsx
  • apps/web/src/components/arandu/MarkdownViewer.tsx
  • apps/web/src/components/ui/alert.tsx
  • apps/web/src/App.css
  • apps/web/src/components/ui/pagination.tsx
  • apps/macos/Sources/Arandu/Info.plist
  • apps/web/src/lib/utils.ts
  • apps/web/src/components/ui/chart.tsx
  • apps/web/.lovable/plan.md
  • apps/web/vitest.config.ts
  • apps/web/src/hooks/use-toast.ts
  • apps/macos/Sources/Arandu/Resources/highlight-dark.min.css
  • apps/web/src/types/arandu.ts
  • apps/web/src/components/ui/progress.tsx
  • apps/web/src/components/ui/resizable.tsx
  • apps/web/src/components/ui/button.tsx
  • apps/web/src/components/ui/input-otp.tsx
  • apps/macos/Sources/Arandu/main.swift
  • apps/web/src/test/example.test.ts
  • apps/web/.gitignore
  • apps/web/src/components/ui/scroll-area.tsx
  • apps/web/src/components/ui/avatar.tsx
  • apps/web/src/components/ui/separator.tsx
  • apps/web/tailwind.config.ts
  • apps/web/src/components/ui/radio-group.tsx
  • apps/web/tsconfig.json
  • apps/web/src/components/ui/collapsible.tsx
  • apps/web/src/components/ui/table.tsx
  • apps/web/src/components/ui/alert-dialog.tsx
  • apps/web/src/components/ui/badge.tsx
  • apps/web/src/components/ui/accordion.tsx
  • apps/web/public/robots.txt
  • apps/web/src/components/arandu/PrimarySidebar.tsx
  • apps/web/src/components/ui/dropdown-menu.tsx
  • apps/web/src/components/ui/context-menu.tsx
  • apps/web/src/components/arandu/TabBar.tsx
  • apps/web/src/components/ui/tooltip.tsx
  • apps/web/src/components/ui/sonner.tsx
  • apps/web/src/main.tsx
  • apps/web/eslint.config.js
  • apps/web/src/components/ui/toaster.tsx
  • apps/web/src/components/ui/tabs.tsx
  • apps/web/src/components/ui/menubar.tsx
  • apps/web/src/components/ui/card.tsx
  • apps/web/src/components/ui/sidebar.tsx
  • apps/web/src/components/ui/use-toast.ts
  • apps/web/src/components/ui/sheet.tsx
  • apps/web/src/components/ui/toast.tsx
  • apps/web/src/components/ui/dialog.tsx

Comment thread apps/tauri/src-tauri/src/comments.rs
Comment thread apps/tauri/src-tauri/src/sessions.rs Outdated
Comment thread apps/tauri/src-tauri/src/sessions.rs Outdated
Comment thread apps/tauri/src/App.tsx
Comment thread apps/tauri/src/components/MarkdownViewer.tsx
Comment thread apps/tauri/src/components/MarkdownViewer.tsx
Comment thread apps/tauri/src/components/OutlineSidebar.tsx
Comment thread apps/tauri/src/components/WorkspaceCard.tsx
- Wrap delete_comments_for_file in a transaction
- Clear animation timers before reassigning
- Add storage event sync for pinned panel state
- Add aria-label to OutlineSidebar icon buttons
- Handle async forget errors in WorkspaceCard
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
apps/tauri/src/App.tsx (1)

23-24: Use theme tokens instead of hardcoded animation colors.

The shadow/backdrop currently hardcode color values, which breaks theme consistency.

🎨 Proposed direction
-const SHADOW = "0 30px 90px rgba(0,0,0,0.55), 0 0 0 0.5px rgba(255,255,255,0.1)";
+const SHADOW = "0 30px 90px hsl(var(--foreground) / 0.45), 0 0 0 0.5px hsl(var(--background) / 0.25)";
@@
-              <div
-                className="absolute inset-0 z-[9] bg-black/45 pointer-events-none"
-                style={backdropStyle}
-              />
+              <div
+                className="absolute inset-0 z-[9] pointer-events-none"
+                style={{ ...backdropStyle, backgroundColor: "hsl(var(--foreground) / 0.45)" }}
+              />

As per coding guidelines, "Use TailwindCSS with HSL CSS variables for theming instead of hardcoded color values".

Also applies to: 229-230

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

In `@apps/tauri/src/App.tsx` around lines 23 - 24, The SHADOW constant currently
embeds hardcoded RGBA colors; replace its literal color values with theme token
CSS variables (HSL-based) and use those vars in the shadow string (e.g.,
var(--bg-backdrop), var(--accent-shadow)) so theming follows Tailwind/HSL
conventions; update the SHADOW definition and any other occurrences with the
same pattern (the other hardcoded shadow/backdrop uses) to reference the new CSS
variables and ensure Tailwind or the app's global CSS defines those HSL
variables.
apps/tauri/src/components/MarkdownViewer.tsx (1)

358-358: Use cn() for conditional class composition.

On Line 358, class merging is done with a template literal; this should use cn() for consistency.

♻️ Proposed fix
+import { cn } from "@/lib/utils";
@@
-      <div className={`flex flex-row ${isEmbedded ? "h-full" : "flex-1 min-h-0"}`}>
+      <div className={cn("flex flex-row", isEmbedded ? "h-full" : "flex-1 min-h-0")}>

As per coding guidelines, "Use the cn() utility from lib/utils.ts for merging Tailwind CSS classes".

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

In `@apps/tauri/src/components/MarkdownViewer.tsx` at line 358, Replace the
template-literal class merge in the MarkdownViewer component with the cn()
utility: in the JSX where the div currently uses `className={`flex flex-row
${isEmbedded ? "h-full" : "flex-1 min-h-0"}`}`, import and call cn (from
lib/utils.ts) and pass the static and conditional classes (e.g., cn('flex
flex-row', isEmbedded ? 'h-full' : 'flex-1 min-h-0')); ensure the MarkdownViewer
file imports cn if it's not already present.
🤖 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.tsx`:
- Around line 57-61: When isExpanding is true but cardRect is missing the
current early return leaves the expand lifecycle half-complete; update the
branch where (!isExpanding || !cardRect) returns so that when isExpanding &&
!cardRect you finalize the expand state by clearing the flip transform and
settling animation flags—for example call setFlipTransform(null) (or undefined),
setTransitionEnabled(false), and setAnimPhase("expanded") (or the appropriate
final phase used elsewhere) so the expand flow never leaves flags out of sync;
reference symbols: isExpanding, cardRect, setFlipTransform,
setTransitionEnabled, setAnimPhase, calcInverseTransform.

In `@apps/tauri/src/components/MarkdownViewer.tsx`:
- Around line 79-90: The onStorage handler (onStorage) only updates when
event.newValue != null, so clearing OUTLINE_PINNED_KEY or REVIEW_PINNED_KEY in
another window won't resync; update onStorage to handle event.newValue === null
by treating removal as "false" and calling setOutlinePinned(false) for
OUTLINE_PINNED_KEY and setReviewPinned(false) for REVIEW_PINNED_KEY (while
preserving the existing truthy check for "true" when newValue is present).
- Around line 389-412: Replace the two raw icon-only <button> elements in
MarkdownViewer (the one that calls setOutlineOpen(true) and the one that opens
the review panel via setReviewOpen(true) / review.setIsPanelOpen(true)) with the
shadcn/ui Button component, preserve the onClick handlers and existing className
styling, move the current title values to an aria-label on the new Button, keep
the icon children (AlignLeft and MessageSquare) and the unresolvedCount badge
logic intact, and add the Button import from shadcn/ui at the top of the file.

In `@apps/tauri/src/components/WorkspaceCard.tsx`:
- Around line 61-69: The icon-only action Buttons (the one using Unlink inside
the WorkspaceCard component and the similar close/forget button later) only set
title; add an aria-label attribute to each Button so screen readers can identify
them — use the same localized string you pass to title (e.g.,
aria-label={t(`${prefix}.forgetAction`)}) for the Unlink Button and the
corresponding t(...) key for the other icon button; update the Button props in
the JSX where Unlink and the close icon are rendered so both title and
aria-label are present.

---

Nitpick comments:
In `@apps/tauri/src/App.tsx`:
- Around line 23-24: The SHADOW constant currently embeds hardcoded RGBA colors;
replace its literal color values with theme token CSS variables (HSL-based) and
use those vars in the shadow string (e.g., var(--bg-backdrop),
var(--accent-shadow)) so theming follows Tailwind/HSL conventions; update the
SHADOW definition and any other occurrences with the same pattern (the other
hardcoded shadow/backdrop uses) to reference the new CSS variables and ensure
Tailwind or the app's global CSS defines those HSL variables.

In `@apps/tauri/src/components/MarkdownViewer.tsx`:
- Line 358: Replace the template-literal class merge in the MarkdownViewer
component with the cn() utility: in the JSX where the div currently uses
`className={`flex flex-row ${isEmbedded ? "h-full" : "flex-1 min-h-0"}`}`,
import and call cn (from lib/utils.ts) and pass the static and conditional
classes (e.g., cn('flex flex-row', isEmbedded ? 'h-full' : 'flex-1 min-h-0'));
ensure the MarkdownViewer file imports cn if it's not already present.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6667d718-f890-4243-92bd-daf5aeb25373

📥 Commits

Reviewing files that changed from the base of the PR and between 141df50 and 8274800.

📒 Files selected for processing (5)
  • apps/tauri/src-tauri/src/comments.rs
  • apps/tauri/src/App.tsx
  • apps/tauri/src/components/MarkdownViewer.tsx
  • apps/tauri/src/components/OutlineSidebar.tsx
  • apps/tauri/src/components/WorkspaceCard.tsx

Comment thread apps/tauri/src/App.tsx Outdated
Comment thread apps/tauri/src/components/MarkdownViewer.tsx
Comment thread apps/tauri/src/components/MarkdownViewer.tsx Outdated
Comment thread apps/tauri/src/components/WorkspaceCard.tsx
- Add delete_comments_for_workspace using LIKE prefix match
- Call it in the directory forget flow alongside session cleanup
- Show forget button for file workspaces too
- Finalize expand state when cardRect is unavailable
- Handle storage key removals when syncing pin state
- Replace raw buttons with shadcn Button on toggle icons
- Add aria-label to all icon-only buttons
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/tauri/src/__tests__/components/WorkspaceCard.test.tsx (1)

59-60: Avoid locale-locked selectors in these tests.

Hardcoded 'Fechar'/'Esquecer' makes tests brittle when language config changes. Prefer role-based queries scoped to the dialog and stable accessible names.

Also applies to: 79-83, 94-98, 109-110

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

In `@apps/tauri/src/__tests__/components/WorkspaceCard.test.tsx` around lines 59 -
60, Replace locale-locked title selectors like getByTitle('Fechar') /
getByTitle('Esquecer') with role-based, accessible queries scoped to the dialog:
find the dialog (or the WorkspaceCard component's dialog) using
getByRole('dialog') and then use within(dialog).getByRole('button', { name:
/close|fechar/i }) or a stable accessible name to click the close/forget
buttons; update all occurrences referenced (closeButton, forgetButton, etc.) in
WorkspaceCard.test.tsx to use scoped getByRole queries instead of hardcoded
titles.
🤖 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/sessions.rs`:
- Around line 323-335: The forget flow currently holds the DB mutex
(db.0.lock()) while performing filesystem work and treats any non-"directory"
workspace_type as a file silently; change it to validate workspace_type
explicitly (accept "directory" and "file" only, returning an error for other
values) and restrict the DB lock scope so you acquire the mutex only for DB
operations: call delete_comments_for_workspace/delete_workspace_sessions or
delete_comments_for_file under the lock, capture the session_ids, then drop the
lock before calling app.path().app_data_dir() and crate::plan_file::delete_plan
for each id; ensure the functions delete_workspace_sessions and
delete_comments_for_workspace/delete_comments_for_file are invoked while holding
conn but filesystem calls happen after releasing conn.

In `@apps/tauri/src/__tests__/components/WorkspaceCard.test.tsx`:
- Around line 16-21: The test mocks for the component's onForget callback are
synchronous (vi.fn()) but the component types and usage expect an async function
returning a Promise; replace the bare vi.fn() mocks used in defaultProps and the
other two test-specific mocks with async-resolving mocks (e.g.,
vi.fn().mockResolvedValue(undefined) or () => Promise.resolve()) so onForget
returns a Promise and callers can safely call .catch(); update the defaultProps
object (workspace: mockWorkspace, onExpand, onClose, onForget) and the other two
test sites where onForget is mocked to use the resolved-Promise form.

In `@apps/tauri/src/components/WorkspaceCard.tsx`:
- Line 57: The action controls div in WorkspaceCard uses
"group-hover:opacity-100" so controls remain hidden for keyboard users; update
the visibility classes to also respond to focus by adding focus/focus-within
variants (e.g., add "group-focus-within:opacity-100" and/or
"focus-within:opacity-100" alongside "group-hover:opacity-100") on the same div,
and ensure the wrapper element that has the "group" class can receive focus (or
already contains focusable children) so keyboard focus triggers the
"focus-within" variant.

---

Nitpick comments:
In `@apps/tauri/src/__tests__/components/WorkspaceCard.test.tsx`:
- Around line 59-60: Replace locale-locked title selectors like
getByTitle('Fechar') / getByTitle('Esquecer') with role-based, accessible
queries scoped to the dialog: find the dialog (or the WorkspaceCard component's
dialog) using getByRole('dialog') and then use
within(dialog).getByRole('button', { name: /close|fechar/i }) or a stable
accessible name to click the close/forget buttons; update all occurrences
referenced (closeButton, forgetButton, etc.) in WorkspaceCard.test.tsx to use
scoped getByRole queries instead of hardcoded titles.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b48cbd53-9086-4bab-801e-4358f4b5a8a6

📥 Commits

Reviewing files that changed from the base of the PR and between 8274800 and 94aafc8.

📒 Files selected for processing (4)
  • apps/tauri/src-tauri/src/comments.rs
  • apps/tauri/src-tauri/src/sessions.rs
  • apps/tauri/src/__tests__/components/WorkspaceCard.test.tsx
  • apps/tauri/src/components/WorkspaceCard.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/tauri/src-tauri/src/comments.rs

Comment thread apps/tauri/src-tauri/src/sessions.rs Outdated
Comment thread apps/tauri/src/__tests__/components/WorkspaceCard.test.tsx
Comment thread apps/tauri/src/components/WorkspaceCard.tsx Outdated
- Validate workspace_type and shorten DB lock scope in forget flow
- Mock onForget as async to match component contract
- Show action controls on keyboard focus via group-focus-within
@wilcorrea wilcorrea merged commit 25da3bf into main Mar 5, 2026
1 check passed
@wilcorrea wilcorrea deleted the feat/ui-improvements branch March 5, 2026 03:23
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