-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Desktop app Tailwind 4 #1438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Desktop app Tailwind 4 #1438
Conversation
WalkthroughThis PR performs a comprehensive refactoring of the desktop application's window system (renaming Changes
Sequence Diagram(s)No sequence diagrams generated. The changes, while extensive and affecting multiple components, are predominantly refactoring (renaming), styling updates, and dependency management—they do not introduce new multi-component control-flow interactions or significant feature behavior changes. Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Key areas requiring extra attention:
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Some hover elements aren't working properly yet. |
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/desktop/src-tauri/src/lib.rs (1)
2858-2864: Avoidunwrap()onCapWindowDef::from_strin hide_dock_icon logicHere:
if let Some(settings) = GeneralSettingsStore::get(app).unwrap_or(None) && settings.hide_dock_icon && app .webview_windows() .keys() .all(|label| !CapWindowDef::from_str(label).unwrap().activates_dock()) { // ... }any window label not recognized by
CapWindowDef::from_str(for example, windows created by plugins) will cause a panic viaunwrap(). This can crash the app when the last window is destroyed whilehide_dock_iconis enabled.Consider treating unknown labels as non‑activating instead of panicking:
- .keys() - .all(|label| !CapWindowDef::from_str(label).unwrap().activates_dock()) + .keys() + .all(|label| { + CapWindowDef::from_str(label) + .map(|id| !id.activates_dock()) + .unwrap_or(true) + })This preserves behavior for known windows and safely ignores any others.
apps/desktop/src-tauri/src/windows.rs (1)
377-407: Fix undefinedwindow_builderin Windows TargetSelectOverlay branchIn the
TargetSelectOverlayvariant, the Windows-specific block currently reads:#[cfg(windows)] { - builder = window_builder.inner_size(100.0, 100.0).position(0.0, 0.0); }
window_builderis not defined in this scope; the intended variable is the existing mutablebuilder. This will fail to compile on Windows.Suggested fix:
#[cfg(windows)] { - builder = window_builder.inner_size(100.0, 100.0).position(0.0, 0.0); + builder = builder.inner_size(100.0, 100.0).position(0.0, 0.0); }This keeps the behavior the same while fixing the compilation error.
🧹 Nitpick comments (5)
apps/desktop/src/routes/editor/Timeline/ZoomTrack.tsx (1)
400-412: Consider using segment IDs instead of positional indices for selection.The
findIndexlookup bystart/endvalues works around the issue that sorting segments (lines 477-480, 593-596) invalidates stored indices. However, this creates O(n) lookups per segment and a dependency on the entirezoomSegmentsarray.A cleaner approach would be to assign stable IDs to segments and use those in
selection.indicesinstead of positional indices. This would simplifyisSelectedto:const isSelected = createMemo(() => { const selection = editorState.timeline.selection; if (!selection || selection.type !== "zoom") return false; - const seg = segment(); - const segmentIndex = project.timeline?.zoomSegments?.findIndex( - (s) => s.start === seg.start && s.end === seg.end, - ); - if (segmentIndex === undefined || segmentIndex === -1) return false; - return selection.indices.includes(segmentIndex); + return selection.ids.includes(segment().id); });packages/ui/src/components/Cmdk.tsx (1)
94-101: Confirm group heading token behavior and consider centralizing stylingThe
CommandGroupheading styles now mirror the token-based approach fromCommandDialog(**:[[cmdk-group-heading]]:*) while still retaining the[&_[cmdk-group-heading]]:text-muted-foregroundselector. Functionally this should work, but:
- It’s worth verifying that both selectors still resolve to the same DOM node after the cmdk/Tailwind changes.
- If the intent is for
[[cmdk-group-heading]]to be the single source of truth, you may want to centralize all heading typography/spacing inCommandGroup(or a shared place) to avoid future divergence.This is primarily a maintainability concern rather than a functional bug.
apps/desktop/src/routes/screenshot-editor/popovers/BackgroundSettingsPopover.tsx (1)
255-269: Consolidateui-*variants todata-*/ standard hover for consistencyThese blocks still mix legacy
ui-not-selected/ui-not-checkedvariants with the newdata-selectedanddata-checkedstyling:
- Line 260:
KTabs.Triggerkeepsui-not-selected:hover:border-gray-7.- Line 288: Wallpaper theme tab trigger also uses
ui-not-selected:hover:border-gray-7.- Line 325:
KRadioGroup.ItemControlkeeps multipleui-not-checked:*ring classes alongsidedata-checked:*.If the
ui-*variant plugin is being phased out with the Tailwind 4 migration, these classes will become dead weight and make state styling harder to follow. Even if the plugin remains, it would be clearer to express “idle” vs “selected/checked” purely via:
- Baseline +
hover:*utilities for the idle state.data-selected:*/data-checked:*utilities for the active state.Consider removing the
ui-*pieces and encoding the intended hover/border/ring behavior withhover:*plus the existingdata-*attributes.Also applies to: 288-288, 323-335, 345-355
apps/desktop/src/routes/editor/Editor.tsx (1)
476-485: Consider tightening vertical padding on cropNumberFieldinputThe crop dialog’s
NumberField.Inputnow combinesh-8withpy-[18px]:class="... h-8 ... py-[18px] ..."For an 8‑unit tall control this is a lot of vertical padding and may visually fight with the fixed height (or lead to inconsistent text baselines compared to other 8‑unit inputs). It might be worth revisiting the
py-*value here to better match the new height scale and the rest of the editor’s form controls, while keeping the rest of the spacing/transition changes as‑is.Also applies to: 487-507, 525-528
apps/desktop/src-tauri/src/recording.rs (1)
1224-1242: Avoid duplicated Camera window close calls inhandle_recording_endWithin the
elsebranch after attempting to unminimizeCapWindowDef::Main,CapWindowDef::Camera.get(&handle)is invoked twice to close the camera window. This is harmless but redundant and slightly obscures intent.You can simplify to a single close:
- } else { - if let Some(v) = CapWindowDef::Camera.get(&handle) { - let _ = v.close(); - } - let _ = app.mic_feed.ask(microphone::RemoveInput).await; - let _ = app.camera_feed.ask(camera::RemoveInput).await; - app.selected_mic_label = None; - app.selected_camera_id = None; - app.camera_in_use = false; - if let Some(win) = CapWindowDef::Camera.get(&handle) { - win.close().ok(); - } - } + } else { + if let Some(camera) = CapWindowDef::Camera.get(&handle) { + camera.close().ok(); + } + let _ = app.mic_feed.ask(microphone::RemoveInput).await; + let _ = app.camera_feed.ask(camera::RemoveInput).await; + app.selected_mic_label = None; + app.selected_camera_id = None; + app.camera_in_use = false; + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
Cargo.lockis excluded by!**/*.lockpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (96)
Cargo.toml(3 hunks)apps/desktop/package.json(2 hunks)apps/desktop/postcss.config.cjs(1 hunks)apps/desktop/src-tauri/Cargo.toml(2 hunks)apps/desktop/src-tauri/src/deeplink_actions.rs(2 hunks)apps/desktop/src-tauri/src/hotkeys.rs(2 hunks)apps/desktop/src-tauri/src/lib.rs(22 hunks)apps/desktop/src-tauri/src/permissions.rs(2 hunks)apps/desktop/src-tauri/src/platform/macos/delegates.rs(0 hunks)apps/desktop/src-tauri/src/platform/macos/mod.rs(1 hunks)apps/desktop/src-tauri/src/platform/mod.rs(1 hunks)apps/desktop/src-tauri/src/recording.rs(9 hunks)apps/desktop/src-tauri/src/screenshot_editor.rs(2 hunks)apps/desktop/src-tauri/src/target_select_overlay.rs(5 hunks)apps/desktop/src-tauri/src/tray.rs(3 hunks)apps/desktop/src-tauri/src/windows.rs(28 hunks)apps/desktop/src-tauri/tauri.conf.json(2 hunks)apps/desktop/src/components/CapErrorBoundary.tsx(1 hunks)apps/desktop/src/components/Loader.tsx(1 hunks)apps/desktop/src/components/SignInButton.tsx(1 hunks)apps/desktop/src/components/Toggle.tsx(2 hunks)apps/desktop/src/components/titlebar/Titlebar.tsx(1 hunks)apps/desktop/src/entry-server.tsx(1 hunks)apps/desktop/src/routes/(window-chrome).tsx(1 hunks)apps/desktop/src/routes/(window-chrome)/(main).tsx(10 hunks)apps/desktop/src/routes/(window-chrome)/new-main/CameraSelect.tsx(1 hunks)apps/desktop/src/routes/(window-chrome)/new-main/MicrophoneSelect.tsx(1 hunks)apps/desktop/src/routes/(window-chrome)/new-main/TargetCard.tsx(4 hunks)apps/desktop/src/routes/(window-chrome)/new-main/TargetDropdownButton.tsx(1 hunks)apps/desktop/src/routes/(window-chrome)/new-main/index.tsx(3 hunks)apps/desktop/src/routes/(window-chrome)/settings.tsx(3 hunks)apps/desktop/src/routes/(window-chrome)/settings/changelog.tsx(1 hunks)apps/desktop/src/routes/(window-chrome)/settings/hotkeys.tsx(1 hunks)apps/desktop/src/routes/(window-chrome)/settings/integrations/s3-config.tsx(2 hunks)apps/desktop/src/routes/(window-chrome)/settings/license.tsx(3 hunks)apps/desktop/src/routes/(window-chrome)/settings/recordings.tsx(3 hunks)apps/desktop/src/routes/(window-chrome)/settings/screenshots.tsx(3 hunks)apps/desktop/src/routes/(window-chrome)/setup.tsx(7 hunks)apps/desktop/src/routes/(window-chrome)/update.tsx(3 hunks)apps/desktop/src/routes/(window-chrome)/upgrade.tsx(6 hunks)apps/desktop/src/routes/camera.tsx(3 hunks)apps/desktop/src/routes/capture-area.tsx(4 hunks)apps/desktop/src/routes/debug.tsx(1 hunks)apps/desktop/src/routes/editor/AspectRatioSelect.tsx(1 hunks)apps/desktop/src/routes/editor/CaptionsTab.tsx(4 hunks)apps/desktop/src/routes/editor/ConfigSidebar.tsx(26 hunks)apps/desktop/src/routes/editor/Editor.tsx(3 hunks)apps/desktop/src/routes/editor/ExportDialog.tsx(1 hunks)apps/desktop/src/routes/editor/Header.tsx(1 hunks)apps/desktop/src/routes/editor/PresetsDropdown.tsx(1 hunks)apps/desktop/src/routes/editor/ShadowSettings.tsx(1 hunks)apps/desktop/src/routes/editor/ShareButton.tsx(3 hunks)apps/desktop/src/routes/editor/Timeline/ClipTrack.tsx(5 hunks)apps/desktop/src/routes/editor/Timeline/MaskTrack.tsx(2 hunks)apps/desktop/src/routes/editor/Timeline/SceneTrack.tsx(3 hunks)apps/desktop/src/routes/editor/Timeline/TextTrack.tsx(3 hunks)apps/desktop/src/routes/editor/Timeline/Track.tsx(1 hunks)apps/desktop/src/routes/editor/Timeline/TrackManager.tsx(2 hunks)apps/desktop/src/routes/editor/Timeline/ZoomTrack.tsx(3 hunks)apps/desktop/src/routes/editor/Timeline/index.tsx(4 hunks)apps/desktop/src/routes/editor/ui.tsx(11 hunks)apps/desktop/src/routes/in-progress-recording.tsx(3 hunks)apps/desktop/src/routes/recordings-overlay.tsx(8 hunks)apps/desktop/src/routes/screenshot-editor/AnnotationConfig.tsx(1 hunks)apps/desktop/src/routes/screenshot-editor/AnnotationTools.tsx(1 hunks)apps/desktop/src/routes/screenshot-editor/ColorPicker.tsx(3 hunks)apps/desktop/src/routes/screenshot-editor/Editor.tsx(5 hunks)apps/desktop/src/routes/screenshot-editor/popovers/AspectRatioSelect.tsx(1 hunks)apps/desktop/src/routes/screenshot-editor/popovers/BackgroundSettingsPopover.tsx(4 hunks)apps/desktop/src/routes/screenshot-editor/popovers/BorderPopover.tsx(1 hunks)apps/desktop/src/routes/screenshot-editor/popovers/RoundingPopover.tsx(1 hunks)apps/desktop/src/routes/screenshot-editor/popovers/ShadowSettings.tsx(1 hunks)apps/desktop/src/routes/screenshot-editor/ui.tsx(11 hunks)apps/desktop/src/routes/target-select-overlay.tsx(3 hunks)apps/desktop/src/styles/theme.css(2 hunks)apps/desktop/src/utils/tauri.ts(2 hunks)apps/desktop/tailwind.config.js(0 hunks)apps/web/app/(org)/dashboard/caps/components/web-recorder-dialog/CameraPreviewWindow.tsx(5 hunks)crates/cursor-info/Cargo.toml(1 hunks)crates/scap-screencapturekit/Cargo.toml(1 hunks)packages/ui-solid/package.json(1 hunks)packages/ui-solid/src/Button.tsx(1 hunks)packages/ui-solid/src/SwitchTab.tsx(2 hunks)packages/ui-solid/src/main.css(1 hunks)packages/ui-solid/tailwind.config.js(0 hunks)packages/ui/src/components/Button.tsx(2 hunks)packages/ui/src/components/Card.tsx(1 hunks)packages/ui/src/components/Cmdk.tsx(3 hunks)packages/ui/src/components/Dialog.tsx(2 hunks)packages/ui/src/components/Dropdown.tsx(5 hunks)packages/ui/src/components/NavigationMenu.tsx(3 hunks)packages/ui/src/components/Select.tsx(4 hunks)packages/ui/src/components/SkeletonRows.tsx(1 hunks)packages/ui/src/components/Switch.tsx(1 hunks)packages/ui/src/components/Table.tsx(2 hunks)packages/ui/src/components/input/Input.tsx(1 hunks)
💤 Files with no reviewable changes (3)
- packages/ui-solid/tailwind.config.js
- apps/desktop/src-tauri/src/platform/macos/delegates.rs
- apps/desktop/tailwind.config.js
🧰 Additional context used
📓 Path-based instructions (10)
**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Use React Query hooks with Server Actions for mutations and perform precise cache updates using setQueryData/setQueriesData instead of broad invalidations
Files:
apps/desktop/src/routes/(window-chrome)/settings/hotkeys.tsxpackages/ui/src/components/Dialog.tsxpackages/ui/src/components/input/Input.tsxapps/desktop/src/routes/editor/Timeline/SceneTrack.tsxapps/desktop/src/components/Toggle.tsxapps/desktop/src/routes/editor/AspectRatioSelect.tsxapps/desktop/src/routes/(window-chrome)/new-main/CameraSelect.tsxpackages/ui-solid/src/SwitchTab.tsxapps/desktop/src/routes/screenshot-editor/AnnotationConfig.tsxapps/web/app/(org)/dashboard/caps/components/web-recorder-dialog/CameraPreviewWindow.tsxapps/desktop/src/routes/debug.tsxapps/desktop/src/routes/editor/CaptionsTab.tsxapps/desktop/src/routes/screenshot-editor/popovers/BorderPopover.tsxapps/desktop/src/components/SignInButton.tsxapps/desktop/src/routes/screenshot-editor/AnnotationTools.tsxapps/desktop/src/routes/editor/Timeline/TrackManager.tsxapps/desktop/src/routes/(window-chrome)/new-main/MicrophoneSelect.tsxapps/desktop/src/routes/(window-chrome)/settings/changelog.tsxpackages/ui-solid/src/Button.tsxapps/desktop/src/routes/(window-chrome)/settings/recordings.tsxpackages/ui/src/components/Switch.tsxapps/desktop/src/routes/(window-chrome)/settings.tsxapps/desktop/src/routes/(window-chrome)/settings/screenshots.tsxapps/desktop/src/routes/screenshot-editor/popovers/AspectRatioSelect.tsxpackages/ui/src/components/Select.tsxapps/desktop/src/routes/editor/ConfigSidebar.tsxapps/desktop/src/routes/editor/ExportDialog.tsxapps/desktop/src/routes/editor/Timeline/TextTrack.tsxapps/desktop/src/routes/recordings-overlay.tsxapps/desktop/src/routes/camera.tsxapps/desktop/src/routes/screenshot-editor/popovers/ShadowSettings.tsxapps/desktop/src/routes/in-progress-recording.tsxapps/desktop/src/routes/editor/Header.tsxapps/desktop/src/components/Loader.tsxapps/desktop/src/routes/(window-chrome)/settings/license.tsxpackages/ui/src/components/NavigationMenu.tsxapps/desktop/src/routes/(window-chrome)/update.tsxapps/desktop/src/components/CapErrorBoundary.tsxapps/desktop/src/routes/editor/PresetsDropdown.tsxapps/desktop/src/routes/(window-chrome)/upgrade.tsxapps/desktop/src/routes/(window-chrome)/settings/integrations/s3-config.tsxpackages/ui/src/components/Card.tsxapps/desktop/src/routes/(window-chrome)/new-main/index.tsxapps/desktop/src/routes/editor/Timeline/index.tsxpackages/ui/src/components/Button.tsxapps/desktop/src/routes/screenshot-editor/ColorPicker.tsxapps/desktop/src/routes/editor/ShadowSettings.tsxapps/desktop/src/routes/editor/Timeline/Track.tsxapps/desktop/src/routes/(window-chrome)/(main).tsxapps/desktop/src/routes/(window-chrome)/setup.tsxapps/desktop/src/routes/capture-area.tsxapps/desktop/src/routes/editor/Timeline/MaskTrack.tsxapps/desktop/src/routes/editor/ui.tsxapps/desktop/src/routes/editor/Editor.tsxapps/desktop/src/routes/(window-chrome)/new-main/TargetDropdownButton.tsxapps/desktop/src/entry-server.tsxpackages/ui/src/components/Cmdk.tsxpackages/ui/src/components/SkeletonRows.tsxapps/desktop/src/routes/editor/Timeline/ZoomTrack.tsxapps/desktop/src/routes/(window-chrome)/new-main/TargetCard.tsxpackages/ui/src/components/Dropdown.tsxapps/desktop/src/routes/target-select-overlay.tsxapps/desktop/src/routes/screenshot-editor/popovers/RoundingPopover.tsxapps/desktop/src/routes/(window-chrome).tsxapps/desktop/src/routes/screenshot-editor/popovers/BackgroundSettingsPopover.tsxpackages/ui/src/components/Table.tsxapps/desktop/src/routes/screenshot-editor/Editor.tsxapps/desktop/src/routes/editor/ShareButton.tsxapps/desktop/src/components/titlebar/Titlebar.tsxapps/desktop/src/routes/editor/Timeline/ClipTrack.tsxapps/desktop/src/routes/screenshot-editor/ui.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: Use strict TypeScript; avoid any type; leverage shared types from @cap/* packages
Follow camelCase naming for variables and functions; PascalCase for components; hooks must start with 'use' prefix
Use Biome for linting and formatting; match existing formatting conventions in the codebase
Use Tailwind CSS for styling in web components; stay consistent with spacing and tokens
Use static skeletons for loading states that mirror content; avoid bouncing animations
Memoize expensive work, code-split naturally, and use Next/Image for remote assets
**/*.{ts,tsx,js,jsx}: Use 2-space indent for TypeScript files; format with Biome usingpnpm format
Use Biome for code formatting and linting; runpnpm formatregularly
Use kebab-case for file names (e.g.,user-menu.tsx); use PascalCase for components
Files:
apps/desktop/src/routes/(window-chrome)/settings/hotkeys.tsxpackages/ui/src/components/Dialog.tsxpackages/ui/src/components/input/Input.tsxapps/desktop/src/routes/editor/Timeline/SceneTrack.tsxapps/desktop/src/components/Toggle.tsxapps/desktop/src/routes/editor/AspectRatioSelect.tsxapps/desktop/src/routes/(window-chrome)/new-main/CameraSelect.tsxpackages/ui-solid/src/SwitchTab.tsxapps/desktop/src/routes/screenshot-editor/AnnotationConfig.tsxapps/web/app/(org)/dashboard/caps/components/web-recorder-dialog/CameraPreviewWindow.tsxapps/desktop/src/routes/debug.tsxapps/desktop/src/routes/editor/CaptionsTab.tsxapps/desktop/src/routes/screenshot-editor/popovers/BorderPopover.tsxapps/desktop/src/components/SignInButton.tsxapps/desktop/src/routes/screenshot-editor/AnnotationTools.tsxapps/desktop/src/routes/editor/Timeline/TrackManager.tsxapps/desktop/src/routes/(window-chrome)/new-main/MicrophoneSelect.tsxapps/desktop/src/routes/(window-chrome)/settings/changelog.tsxpackages/ui-solid/src/Button.tsxapps/desktop/src/routes/(window-chrome)/settings/recordings.tsxpackages/ui/src/components/Switch.tsxapps/desktop/src/routes/(window-chrome)/settings.tsxapps/desktop/src/routes/(window-chrome)/settings/screenshots.tsxapps/desktop/src/routes/screenshot-editor/popovers/AspectRatioSelect.tsxpackages/ui/src/components/Select.tsxapps/desktop/src/routes/editor/ConfigSidebar.tsxapps/desktop/src/routes/editor/ExportDialog.tsxapps/desktop/src/routes/editor/Timeline/TextTrack.tsxapps/desktop/src/routes/recordings-overlay.tsxapps/desktop/src/routes/camera.tsxapps/desktop/src/routes/screenshot-editor/popovers/ShadowSettings.tsxapps/desktop/src/routes/in-progress-recording.tsxapps/desktop/src/routes/editor/Header.tsxapps/desktop/src/components/Loader.tsxapps/desktop/src/routes/(window-chrome)/settings/license.tsxpackages/ui/src/components/NavigationMenu.tsxapps/desktop/src/routes/(window-chrome)/update.tsxapps/desktop/src/components/CapErrorBoundary.tsxapps/desktop/src/routes/editor/PresetsDropdown.tsxapps/desktop/src/routes/(window-chrome)/upgrade.tsxapps/desktop/src/routes/(window-chrome)/settings/integrations/s3-config.tsxpackages/ui/src/components/Card.tsxapps/desktop/src/routes/(window-chrome)/new-main/index.tsxapps/desktop/src/routes/editor/Timeline/index.tsxpackages/ui/src/components/Button.tsxapps/desktop/src/routes/screenshot-editor/ColorPicker.tsxapps/desktop/src/routes/editor/ShadowSettings.tsxapps/desktop/src/routes/editor/Timeline/Track.tsxapps/desktop/src/routes/(window-chrome)/(main).tsxapps/desktop/src/routes/(window-chrome)/setup.tsxapps/desktop/src/routes/capture-area.tsxapps/desktop/src/routes/editor/Timeline/MaskTrack.tsxapps/desktop/src/routes/editor/ui.tsxapps/desktop/src/routes/editor/Editor.tsxapps/desktop/src/routes/(window-chrome)/new-main/TargetDropdownButton.tsxapps/desktop/src/entry-server.tsxapps/desktop/src/utils/tauri.tspackages/ui/src/components/Cmdk.tsxpackages/ui/src/components/SkeletonRows.tsxapps/desktop/src/routes/editor/Timeline/ZoomTrack.tsxapps/desktop/src/routes/(window-chrome)/new-main/TargetCard.tsxpackages/ui/src/components/Dropdown.tsxapps/desktop/src/routes/target-select-overlay.tsxapps/desktop/src/routes/screenshot-editor/popovers/RoundingPopover.tsxapps/desktop/src/routes/(window-chrome).tsxapps/desktop/src/routes/screenshot-editor/popovers/BackgroundSettingsPopover.tsxpackages/ui/src/components/Table.tsxapps/desktop/src/routes/screenshot-editor/Editor.tsxapps/desktop/src/routes/editor/ShareButton.tsxapps/desktop/src/components/titlebar/Titlebar.tsxapps/desktop/src/routes/editor/Timeline/ClipTrack.tsxapps/desktop/src/routes/screenshot-editor/ui.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Never add any form of comments to code (single-line //, multi-line /* /, JSDoc /* */, or any other comment syntax); code must be self-explanatory through naming, types, and structure
Directory naming must use lowercase-dashed convention
Files:
apps/desktop/src/routes/(window-chrome)/settings/hotkeys.tsxpackages/ui/src/components/Dialog.tsxpackages/ui/src/components/input/Input.tsxapps/desktop/src/routes/editor/Timeline/SceneTrack.tsxapps/desktop/src/components/Toggle.tsxapps/desktop/src/routes/editor/AspectRatioSelect.tsxapps/desktop/src/routes/(window-chrome)/new-main/CameraSelect.tsxpackages/ui-solid/src/SwitchTab.tsxapps/desktop/src/routes/screenshot-editor/AnnotationConfig.tsxapps/web/app/(org)/dashboard/caps/components/web-recorder-dialog/CameraPreviewWindow.tsxapps/desktop/src/routes/debug.tsxapps/desktop/src/routes/editor/CaptionsTab.tsxapps/desktop/src/routes/screenshot-editor/popovers/BorderPopover.tsxapps/desktop/src/components/SignInButton.tsxapps/desktop/src/routes/screenshot-editor/AnnotationTools.tsxapps/desktop/src/routes/editor/Timeline/TrackManager.tsxapps/desktop/src/routes/(window-chrome)/new-main/MicrophoneSelect.tsxapps/desktop/src/routes/(window-chrome)/settings/changelog.tsxpackages/ui-solid/src/Button.tsxapps/desktop/src/routes/(window-chrome)/settings/recordings.tsxpackages/ui/src/components/Switch.tsxapps/desktop/src/routes/(window-chrome)/settings.tsxapps/desktop/src/routes/(window-chrome)/settings/screenshots.tsxapps/desktop/src/routes/screenshot-editor/popovers/AspectRatioSelect.tsxpackages/ui/src/components/Select.tsxapps/desktop/src/routes/editor/ConfigSidebar.tsxapps/desktop/src/routes/editor/ExportDialog.tsxapps/desktop/src/routes/editor/Timeline/TextTrack.tsxapps/desktop/src/routes/recordings-overlay.tsxapps/desktop/src/routes/camera.tsxapps/desktop/src/routes/screenshot-editor/popovers/ShadowSettings.tsxapps/desktop/src/routes/in-progress-recording.tsxapps/desktop/src/routes/editor/Header.tsxapps/desktop/src/components/Loader.tsxapps/desktop/src/routes/(window-chrome)/settings/license.tsxpackages/ui/src/components/NavigationMenu.tsxapps/desktop/src/routes/(window-chrome)/update.tsxapps/desktop/src/components/CapErrorBoundary.tsxapps/desktop/src/routes/editor/PresetsDropdown.tsxapps/desktop/src/routes/(window-chrome)/upgrade.tsxapps/desktop/src/routes/(window-chrome)/settings/integrations/s3-config.tsxpackages/ui/src/components/Card.tsxapps/desktop/src/routes/(window-chrome)/new-main/index.tsxapps/desktop/src/routes/editor/Timeline/index.tsxpackages/ui/src/components/Button.tsxapps/desktop/src/routes/screenshot-editor/ColorPicker.tsxapps/desktop/src/routes/editor/ShadowSettings.tsxapps/desktop/src/routes/editor/Timeline/Track.tsxapps/desktop/src/routes/(window-chrome)/(main).tsxapps/desktop/src/routes/(window-chrome)/setup.tsxapps/desktop/src/routes/capture-area.tsxapps/desktop/src/routes/editor/Timeline/MaskTrack.tsxapps/desktop/src/routes/editor/ui.tsxapps/desktop/src/routes/editor/Editor.tsxapps/desktop/src/routes/(window-chrome)/new-main/TargetDropdownButton.tsxapps/desktop/src/entry-server.tsxapps/desktop/src/utils/tauri.tspackages/ui/src/components/Cmdk.tsxpackages/ui/src/components/SkeletonRows.tsxapps/desktop/src/routes/editor/Timeline/ZoomTrack.tsxapps/desktop/src/routes/(window-chrome)/new-main/TargetCard.tsxpackages/ui/src/components/Dropdown.tsxapps/desktop/src/routes/target-select-overlay.tsxapps/desktop/src/routes/screenshot-editor/popovers/RoundingPopover.tsxapps/desktop/src/routes/(window-chrome).tsxapps/desktop/src/routes/screenshot-editor/popovers/BackgroundSettingsPopover.tsxpackages/ui/src/components/Table.tsxapps/desktop/src/routes/screenshot-editor/Editor.tsxapps/desktop/src/routes/editor/ShareButton.tsxapps/desktop/src/components/titlebar/Titlebar.tsxapps/desktop/src/routes/editor/Timeline/ClipTrack.tsxapps/desktop/src/routes/screenshot-editor/ui.tsx
**/*.{ts,tsx,js,jsx,rs}
📄 CodeRabbit inference engine (AGENTS.md)
Never add comments to code (
//,/* */,///,//!,#, etc.); code must be self-explanatory through naming, types, and structure
Files:
apps/desktop/src/routes/(window-chrome)/settings/hotkeys.tsxapps/desktop/src-tauri/src/tray.rspackages/ui/src/components/Dialog.tsxpackages/ui/src/components/input/Input.tsxapps/desktop/src/routes/editor/Timeline/SceneTrack.tsxapps/desktop/src/components/Toggle.tsxapps/desktop/src/routes/editor/AspectRatioSelect.tsxapps/desktop/src-tauri/src/deeplink_actions.rsapps/desktop/src/routes/(window-chrome)/new-main/CameraSelect.tsxpackages/ui-solid/src/SwitchTab.tsxapps/desktop/src/routes/screenshot-editor/AnnotationConfig.tsxapps/web/app/(org)/dashboard/caps/components/web-recorder-dialog/CameraPreviewWindow.tsxapps/desktop/src/routes/debug.tsxapps/desktop/src/routes/editor/CaptionsTab.tsxapps/desktop/src/routes/screenshot-editor/popovers/BorderPopover.tsxapps/desktop/src/components/SignInButton.tsxapps/desktop/src/routes/screenshot-editor/AnnotationTools.tsxapps/desktop/src/routes/editor/Timeline/TrackManager.tsxapps/desktop/src/routes/(window-chrome)/new-main/MicrophoneSelect.tsxapps/desktop/src/routes/(window-chrome)/settings/changelog.tsxpackages/ui-solid/src/Button.tsxapps/desktop/src-tauri/src/hotkeys.rsapps/desktop/src/routes/(window-chrome)/settings/recordings.tsxpackages/ui/src/components/Switch.tsxapps/desktop/src/routes/(window-chrome)/settings.tsxapps/desktop/src/routes/(window-chrome)/settings/screenshots.tsxapps/desktop/src/routes/screenshot-editor/popovers/AspectRatioSelect.tsxapps/desktop/src-tauri/src/permissions.rspackages/ui/src/components/Select.tsxapps/desktop/src/routes/editor/ConfigSidebar.tsxapps/desktop/src/routes/editor/ExportDialog.tsxapps/desktop/src/routes/editor/Timeline/TextTrack.tsxapps/desktop/src/routes/recordings-overlay.tsxapps/desktop/src-tauri/src/platform/mod.rsapps/desktop/src/routes/camera.tsxapps/desktop/src/routes/screenshot-editor/popovers/ShadowSettings.tsxapps/desktop/src/routes/in-progress-recording.tsxapps/desktop/src/routes/editor/Header.tsxapps/desktop/src/components/Loader.tsxapps/desktop/src/routes/(window-chrome)/settings/license.tsxpackages/ui/src/components/NavigationMenu.tsxapps/desktop/src/routes/(window-chrome)/update.tsxapps/desktop/src/components/CapErrorBoundary.tsxapps/desktop/src/routes/editor/PresetsDropdown.tsxapps/desktop/src/routes/(window-chrome)/upgrade.tsxapps/desktop/src/routes/(window-chrome)/settings/integrations/s3-config.tsxpackages/ui/src/components/Card.tsxapps/desktop/src/routes/(window-chrome)/new-main/index.tsxapps/desktop/src/routes/editor/Timeline/index.tsxpackages/ui/src/components/Button.tsxapps/desktop/src-tauri/src/screenshot_editor.rsapps/desktop/src/routes/screenshot-editor/ColorPicker.tsxapps/desktop/src/routes/editor/ShadowSettings.tsxapps/desktop/src/routes/editor/Timeline/Track.tsxapps/desktop/src/routes/(window-chrome)/(main).tsxapps/desktop/src/routes/(window-chrome)/setup.tsxapps/desktop/src/routes/capture-area.tsxapps/desktop/src/routes/editor/Timeline/MaskTrack.tsxapps/desktop/src/routes/editor/ui.tsxapps/desktop/src-tauri/src/platform/macos/mod.rsapps/desktop/src/routes/editor/Editor.tsxapps/desktop/src/routes/(window-chrome)/new-main/TargetDropdownButton.tsxapps/desktop/src/entry-server.tsxapps/desktop/src/utils/tauri.tspackages/ui/src/components/Cmdk.tsxpackages/ui/src/components/SkeletonRows.tsxapps/desktop/src/routes/editor/Timeline/ZoomTrack.tsxapps/desktop/src/routes/(window-chrome)/new-main/TargetCard.tsxpackages/ui/src/components/Dropdown.tsxapps/desktop/src-tauri/src/target_select_overlay.rsapps/desktop/src/routes/target-select-overlay.tsxapps/desktop/src/routes/screenshot-editor/popovers/RoundingPopover.tsxapps/desktop/src/routes/(window-chrome).tsxapps/desktop/src/routes/screenshot-editor/popovers/BackgroundSettingsPopover.tsxpackages/ui/src/components/Table.tsxapps/desktop/src/routes/screenshot-editor/Editor.tsxapps/desktop/src/routes/editor/ShareButton.tsxapps/desktop/src/components/titlebar/Titlebar.tsxapps/desktop/src-tauri/src/recording.rsapps/desktop/src/routes/editor/Timeline/ClipTrack.tsxapps/desktop/src-tauri/src/lib.rsapps/desktop/src-tauri/src/windows.rsapps/desktop/src/routes/screenshot-editor/ui.tsx
**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.rs: Never use dbg!() macro; use proper logging (tracing::debug!, etc.) instead
Never write let _ = async_fn() which silently drops futures; await or explicitly handle them
Use duration.saturating_sub(other) instead of duration - other to avoid panics on underflow
Merge nested if statements: write 'if a && b { }' instead of 'if a { if b { } }'
Don't call .clone() on Copy types (integers, bools, etc.); copy them directly
Use function references directly: iter.map(foo) instead of iter.map(|x| foo(x))
Accept &[T] or &str instead of &Vec or &String in function parameters for flexibility
Use .is_empty() instead of .len() == 0 or .len() > 0 / .len() != 0
Don't assign () to a variable: write foo(); instead of let _ = foo(); or let x = foo(); when return is unit
Use .unwrap_or(val) instead of .unwrap_or_else(|| val) when the default is a simple/cheap value
Use 'for item in &collection' or 'for (i, item) in collection.iter().enumerate()' instead of 'for i in 0..collection.len()'
Use value.clamp(min, max) instead of manual if chains or .min(max).max(min) patterns
Always handle Result/Option or types marked #[must_use]; never ignore them
**/*.rs: Userustfmtand workspace clippy lints for Rust code formatting and linting
Use snake_case for Rust module names and kebab-case for crate names
Never usedbg!()macro in Rust code; use proper logging instead (Clippy:dbg_macro= deny)
Always handleResult/Optionor types marked#[must_use]; never ignore them (Rust compiler lint:unused_must_use= deny)
Never writelet _ = async_fn()which silently drops futures; await or explicitly handle them (Clippy:let_underscore_future= deny)
Usesaturating_subinstead of-forDurationto avoid panics (Clippy:unchecked_duration_subtraction= deny)
Merge nestedifstatements: useif a && b { }instead ofif a { if b { } }(Clippy:collapsible_if= deny)
Don't call.clone()onCopytypes; just copy them directly (Clippy:clone_on_copy= deny)
U...
Files:
apps/desktop/src-tauri/src/tray.rsapps/desktop/src-tauri/src/deeplink_actions.rsapps/desktop/src-tauri/src/hotkeys.rsapps/desktop/src-tauri/src/permissions.rsapps/desktop/src-tauri/src/platform/mod.rsapps/desktop/src-tauri/src/screenshot_editor.rsapps/desktop/src-tauri/src/platform/macos/mod.rsapps/desktop/src-tauri/src/target_select_overlay.rsapps/desktop/src-tauri/src/recording.rsapps/desktop/src-tauri/src/lib.rsapps/desktop/src-tauri/src/windows.rs
apps/web/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
apps/web/**/*.tsx: Prefer Server Components for initial data fetching and SEO; pass initialData to client components and let React Query take over
Minimize useEffect usage in React components; compute during render, handle logic in event handlers, and ensure cleanups for subscriptions/timers
Files:
apps/web/app/(org)/dashboard/caps/components/web-recorder-dialog/CameraPreviewWindow.tsx
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use
useEffectQuery/useEffectMutationfrom@/lib/EffectRuntimein client components; do not callEffectRuntime.run*directly
Files:
apps/web/app/(org)/dashboard/caps/components/web-recorder-dialog/CameraPreviewWindow.tsx
**/*.config.{js,ts,mjs,cjs}
📄 CodeRabbit inference engine (CLAUDE.md)
Configuration files must follow their respective tool conventions (Next.js, Tailwind, etc.)
Files:
apps/desktop/postcss.config.cjs
**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Use TanStack Query v5 for all client-side server state and data fetching in TypeScript files
Files:
apps/desktop/src/utils/tauri.ts
apps/desktop/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
apps/desktop/**/*.ts: Use @tanstack/solid-query for server state management in SolidJS components
Use generated commands and events from tauri_specta for IPC; never manually construct IPC calls
Listen directly to generated events from tauri_specta and use typed event interfaces
Files:
apps/desktop/src/utils/tauri.ts
🧠 Learnings (14)
📚 Learning: 2025-11-19T18:25:41.457Z
Learnt from: ItsEeleeya
Repo: CapSoftware/Cap PR: 1396
File: apps/desktop/src/routes/(window-chrome)/settings/general.tsx:183-192
Timestamp: 2025-11-19T18:25:41.457Z
Learning: In SolidJS, when using the Show component with the `keyed` attribute and a dynamic reactive value (like a memo result), the component will recreate its children when the condition value changes by reference. This pattern is useful for triggering CSS animations (like fade-in) when the rendered content needs to update. For example, in apps/desktop/src/routes/(window-chrome)/settings/general.tsx, `<Show when={previews()[theme.id]} keyed>` ensures the image re-animates when switching between different preview sources.
Applied to files:
apps/desktop/src/routes/(window-chrome)/settings/hotkeys.tsxapps/desktop/src/routes/(window-chrome)/update.tsxapps/desktop/src/routes/editor/Timeline/index.tsxapps/desktop/src/routes/capture-area.tsxapps/desktop/src/routes/editor/Editor.tsxapps/desktop/src/routes/screenshot-editor/Editor.tsx
📚 Learning: 2025-10-28T08:39:42.230Z
Learnt from: Brendonovich
Repo: CapSoftware/Cap PR: 1305
File: crates/recording/src/output_pipeline/macos.rs:80-90
Timestamp: 2025-10-28T08:39:42.230Z
Learning: In `crates/recording/src/output_pipeline/macos.rs`, the `AVFoundationMp4Muxer` intentionally holds the `Mutex<MP4Encoder>` lock during retry attempts in `send_video_frame()` and `send_audio_frame()`. This blocking behavior is correct because frame processing must happen sequentially to prevent audio and video frames from being interleaved incorrectly in the encoder.
Applied to files:
apps/desktop/src-tauri/src/tray.rs
📚 Learning: 2025-12-07T14:29:19.166Z
Learnt from: CR
Repo: CapSoftware/Cap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T14:29:19.166Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use Tailwind CSS for styling in web components; stay consistent with spacing and tokens
Applied to files:
packages/ui/src/components/input/Input.tsxapps/desktop/src/routes/editor/Timeline/SceneTrack.tsxapps/desktop/src/routes/debug.tsxapps/desktop/src/routes/editor/CaptionsTab.tsxapps/desktop/src/routes/editor/Timeline/TrackManager.tsxapps/desktop/src/routes/(window-chrome)/settings/changelog.tsxpackages/ui-solid/src/Button.tsxpackages/ui-solid/src/main.cssapps/desktop/src/routes/(window-chrome)/settings/recordings.tsxapps/desktop/src/routes/(window-chrome)/settings/screenshots.tsxpackages/ui/src/components/Select.tsxapps/desktop/src/routes/editor/ConfigSidebar.tsxapps/desktop/src/routes/editor/Timeline/TextTrack.tsxapps/desktop/package.jsonapps/desktop/src/styles/theme.cssapps/desktop/src/routes/editor/Header.tsxapps/desktop/src/routes/(window-chrome)/settings/license.tsxapps/desktop/src/routes/(window-chrome)/update.tsxapps/desktop/src/components/CapErrorBoundary.tsxpackages/ui-solid/package.jsonapps/desktop/src/routes/(window-chrome)/upgrade.tsxapps/desktop/src/routes/(window-chrome)/settings/integrations/s3-config.tsxapps/desktop/postcss.config.cjsapps/desktop/src/routes/(window-chrome)/new-main/index.tsxapps/desktop/src/routes/editor/Timeline/index.tsxpackages/ui/src/components/Button.tsxapps/desktop/src/routes/screenshot-editor/ColorPicker.tsxapps/desktop/src/routes/editor/Timeline/Track.tsxapps/desktop/src/routes/(window-chrome)/(main).tsxapps/desktop/src/routes/(window-chrome)/setup.tsxapps/desktop/src/routes/editor/Timeline/MaskTrack.tsxapps/desktop/src/routes/editor/ui.tsxapps/desktop/src/routes/editor/Editor.tsxapps/desktop/src/routes/(window-chrome)/new-main/TargetDropdownButton.tsxapps/desktop/src/entry-server.tsxpackages/ui/src/components/Cmdk.tsxpackages/ui/src/components/SkeletonRows.tsxapps/desktop/src/routes/(window-chrome)/new-main/TargetCard.tsxapps/desktop/src/routes/(window-chrome).tsxpackages/ui/src/components/Table.tsxapps/desktop/src/routes/screenshot-editor/Editor.tsxapps/desktop/src/routes/editor/ShareButton.tsxapps/desktop/src/components/titlebar/Titlebar.tsxapps/desktop/src/routes/editor/Timeline/ClipTrack.tsxapps/desktop/src/routes/screenshot-editor/ui.tsx
📚 Learning: 2025-12-07T14:29:40.721Z
Learnt from: CR
Repo: CapSoftware/Cap PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T14:29:40.721Z
Learning: Applies to **/tauri.ts|**/queries.ts|apps/desktop/src-tauri/gen/** : Never edit auto-generated files: `**/tauri.ts`, `**/queries.ts`, `apps/desktop/src-tauri/gen/**`
Applied to files:
apps/desktop/src/routes/editor/Timeline/SceneTrack.tsxapps/desktop/src/routes/(window-chrome)/new-main/index.tsxapps/desktop/src/routes/(window-chrome)/setup.tsx
📚 Learning: 2025-12-07T14:29:19.166Z
Learnt from: CR
Repo: CapSoftware/Cap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T14:29:19.166Z
Learning: Applies to packages/web-api-contract-effect/**/*.ts : HTTP contract definitions in web-api-contract-effect must be kept in sync with API route changes
Applied to files:
apps/desktop/package.json
📚 Learning: 2025-12-07T14:29:40.721Z
Learnt from: CR
Repo: CapSoftware/Cap PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T14:29:40.721Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use kebab-case for file names (e.g., `user-menu.tsx`); use PascalCase for components
Applied to files:
packages/ui/src/components/NavigationMenu.tsxapps/desktop/src/routes/(window-chrome)/(main).tsx
📚 Learning: 2025-12-07T14:29:19.165Z
Learnt from: CR
Repo: CapSoftware/Cap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T14:29:19.165Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use strict TypeScript; avoid any type; leverage shared types from cap/* packages
Applied to files:
apps/desktop/src/components/CapErrorBoundary.tsxpackages/ui-solid/package.json
📚 Learning: 2025-12-07T14:29:19.165Z
Learnt from: CR
Repo: CapSoftware/Cap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T14:29:19.165Z
Learning: Applies to apps/web/app/api/**/*.ts : Map domain-level errors to transport errors with HttpApiError.* and keep error translation exhaustive using Effect.catchTags and Effect.tapErrorCause(Effect.logError)
Applied to files:
apps/desktop/src/components/CapErrorBoundary.tsx
📚 Learning: 2025-12-07T14:29:19.165Z
Learnt from: CR
Repo: CapSoftware/Cap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T14:29:19.165Z
Learning: Applies to **/*.config.{js,ts,mjs,cjs} : Configuration files must follow their respective tool conventions (Next.js, Tailwind, etc.)
Applied to files:
apps/desktop/postcss.config.cjs
📚 Learning: 2025-12-07T14:29:19.166Z
Learnt from: CR
Repo: CapSoftware/Cap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T14:29:19.166Z
Learning: Applies to apps/desktop/**/*.ts : Use generated commands and events from tauri_specta for IPC; never manually construct IPC calls
Applied to files:
apps/desktop/src/utils/tauri.ts
📚 Learning: 2025-12-07T14:29:19.166Z
Learnt from: CR
Repo: CapSoftware/Cap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T14:29:19.166Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use static skeletons for loading states that mirror content; avoid bouncing animations
Applied to files:
packages/ui/src/components/SkeletonRows.tsx
📚 Learning: 2025-09-23T12:34:13.729Z
Learnt from: Brendonovich
Repo: CapSoftware/Cap PR: 1053
File: .github/workflows/publish.yml:222-230
Timestamp: 2025-09-23T12:34:13.729Z
Learning: In the Cap desktop app, there's a beforeBundle Tauri script (prodBeforeBundle.js) that creates Cap.dSYM in the target/ directory using dsymutil, so the Sentry debug symbols upload path "target/Cap.dSYM" is correct and doesn't need to be changed to the matrix target subdirectory.
Applied to files:
apps/desktop/src-tauri/tauri.conf.json
📚 Learning: 2025-12-07T14:29:19.166Z
Learnt from: CR
Repo: CapSoftware/Cap PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T14:29:19.166Z
Learning: Never edit auto-generated files: tauri.ts, queries.ts, and files under apps/desktop/src-tauri/gen/
Applied to files:
apps/desktop/src-tauri/tauri.conf.json
📚 Learning: 2025-12-07T14:29:40.721Z
Learnt from: CR
Repo: CapSoftware/Cap PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-07T14:29:40.721Z
Learning: Use Turborepo monorepo structure with `apps/desktop`, `apps/web`, `apps/cli`, `packages/*`, `crates/*`, and tooling directories
Applied to files:
Cargo.toml
🧬 Code graph analysis (10)
apps/desktop/src-tauri/src/tray.rs (1)
apps/desktop/src/utils/tauri.ts (2)
RecordingTargetMode(461-461)CapWindow(365-365)
apps/desktop/src-tauri/src/deeplink_actions.rs (1)
apps/desktop/src-tauri/src/lib.rs (8)
show_window(2153-2156)app(576-576)app(1649-1650)app(2721-2721)app(2757-2757)app(2834-2834)app(2840-2840)app(3073-3074)
apps/desktop/src/routes/in-progress-recording.tsx (1)
apps/desktop/src/utils/tauri.ts (1)
stopRecording(20-22)
apps/desktop/src-tauri/src/screenshot_editor.rs (1)
apps/desktop/src-tauri/src/windows.rs (1)
from_str(61-100)
apps/desktop/src/routes/(window-chrome)/(main).tsx (1)
apps/desktop/src/routes/(window-chrome)/new-main/InfoPill.tsx (1)
InfoPill(4-17)
apps/desktop/src/routes/editor/ui.tsx (1)
apps/desktop/src/routes/screenshot-editor/ui.tsx (4)
topLeftAnimateClasses(420-421)topCenterAnimateClasses(423-424)topRightAnimateClasses(426-427)topSlideAnimateClasses(429-430)
apps/desktop/src/routes/editor/Timeline/ZoomTrack.tsx (1)
apps/desktop/src/routes/editor/Timeline/Track.tsx (3)
SegmentRoot(55-96)SegmentHandle(112-134)SegmentContent(98-110)
apps/desktop/src-tauri/src/target_select_overlay.rs (1)
apps/desktop/src-tauri/src/windows.rs (9)
from_str(61-100)app(265-265)app(284-284)app(431-431)app(525-525)app(829-829)app(847-847)app(987-987)app(999-999)
apps/desktop/src-tauri/src/recording.rs (1)
apps/desktop/src-tauri/src/windows.rs (9)
app(265-265)app(284-284)app(431-431)app(525-525)app(829-829)app(847-847)app(987-987)app(999-999)label(129-131)
apps/desktop/src-tauri/src/lib.rs (2)
apps/desktop/src/utils/tauri.ts (2)
CapWindow(365-365)Camera(357-357)apps/desktop/src-tauri/src/windows.rs (13)
from_str(61-100)app(265-265)app(284-284)app(431-431)app(525-525)app(829-829)app(847-847)app(987-987)app(999-999)label(129-131)get(170-173)get(986-988)get(998-1000)
| "@fontsource/geist-sans": "^5.0.3", | ||
| "@iconify/json": "^2.2.239", | ||
| "@tauri-apps/cli": ">=2.1.0", | ||
| "@tauri-apps/cli": "^2.9.5", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
@tauri-apps/cli 2.9.5 release notes changelog
💡 Result:
Here are the release notes / changelog entries for @tauri-apps/cli v2.9.5:
-
Bug fixes:
- Fixed mismatched tauri package versions check for pnpm. (commit f855caf8a, #14481). [1]
- Fixed CLI error when signing keys were set in config but --no-sign was used together with tauri-plugin-updater (commit f022b2d1a, #14582). [1]
- Fixed parsing error when there was no Cargo.lock (reported as noisy unless --verbose) (commit 79a7d9ec0, #14468). [1]
-
Performance improvements:
- Refactor to remove needless collect (ce98d87ce, #14474). [1]
- Removed needless clones in various files for improved perf (ee3cca... #14475). [1]
-
Dependencies:
- Upgraded to tauri-bundler@2.7.4, tauri-macos-sign@2.3.1, tauri-utils@2.8.1 and to tauri-cli (Rust) v2.9.5 (as referenced in the tauri repo release). [1][2]
Sources: [1] Tauri release page for @tauri-apps/cli v2.9.5, [2] tauri-apps/tauri GitHub release (tauri-cli v2.9.5).
🌐 Web query:
@tauri-apps/cli 2.9.5 @tauri-apps/api 2.5.0 compatibility
💡 Result:
Short answer: not recommended — upgrade @tauri-apps/api to a 2.9.x release to match @tauri-apps/cli 2.9.5.
Why: the Tauri ecosystem expects matching/close releases across packages (tauri, @tauri-apps/api, tauri-cli/@tauri-apps/cli). @tauri-apps/cli 2.9.5 is part of the 2.9.x ecosystem; @tauri-apps/api 2.5.0 is an older 2.5.x release and may miss APIs/behavior introduced since 2.5.0. For best compatibility, use @tauri-apps/api 2.9.x with @tauri-apps/cli 2.9.5. [1][2]
Sources:
- Tauri core releases / recommended matching versions. [1]
- @tauri-apps/api v2.5.0 release notes (shows it’s a 2.5.x release). [2]
References:
[1] Tauri Core Ecosystem Releases (shows tauri/@tauri-apps/api and cli 2.9.x alignment).
[2] @tauri-apps/api v2.5.0 release page.
Upgrade @tauri-apps/api to 2.9.x for compatibility with @tauri-apps/cli 2.9.5.
The version constraint for @tauri-apps/cli was updated to ^2.9.5, but @tauri-apps/api is pinned at 2.5.0. The Tauri ecosystem requires matching or close release versions across packages; using cli 2.9.5 with api 2.5.0 creates a significant version mismatch (4 minor versions apart). This can result in missing APIs or behavioral inconsistencies. Upgrade @tauri-apps/api to a 2.9.x release to ensure ecosystem alignment.
🤖 Prompt for AI Agents
In apps/desktop/package.json around line 76, @tauri-apps/cli was bumped to
^2.9.5 but @tauri-apps/api remains pinned at 2.5.0, causing a large version
mismatch; update the @tauri-apps/api dependency to a 2.9.x release (e.g., ^2.9.0
or ^2.9.5) in package.json, run your package manager install to update lockfile,
and rebuild/test the app to ensure there are no API breakages.
| // module.exports = require("@cap/ui/postcss"); | ||
|
|
||
| module.exports = { | ||
| plugins: { | ||
| "@tailwindcss/postcss": {}, | ||
| autoprefixer: {}, | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
fd -type f -name "postcss.config.*"Repository: CapSoftware/Cap
Length of output: 174
🏁 Script executed:
find . -type f -name "*postcss*" | grep -E "\.(ts|js|cjs|mjs)$" | head -20Repository: CapSoftware/Cap
Length of output: 174
🏁 Script executed:
find . -path "*/cap/ui/*" -type f | grep -iE "(postcss|index)" | head -20Repository: CapSoftware/Cap
Length of output: 174
🏁 Script executed:
rg -t js -t ts "@cap/ui/postcss" --max-count 20Repository: CapSoftware/Cap
Length of output: 174
🌐 Web query:
Tailwind CSS 4 @tailwindcss/postcss autoprefixer redundant Lightning CSS
💡 Result:
Short answer: Yes — in Tailwind CSS v4 the new @tailwindcss/postcss plugin + Lightning CSS make separate autoprefixer (and postcss-import / postcss-preset-env) generally redundant.
What changed
- Tailwind v4 moves the PostCSS integration into a new package: @tailwindcss/postcss (replace the old tailwindcss PostCSS plugin). [1][2]
- Tailwind runs your CSS through Lightning CSS in production, which performs vendor-prefixing, transpilation of modern features, minification, etc. That replaces the need for autoprefixer and similar PostCSS plugins in most setups. [1][3]
What to do
- Replace your PostCSS config from:
plugins: { tailwindcss: {}, autoprefixer: {}, postcss-import: {} }
to:
plugins: { "@tailwindcss/postcss": {} } - If you need special behavior not covered by Lightning CSS (rare), keep the specific PostCSS plugin(s) you require.
Sources: Tailwind v4 docs and migration guidance. [1] [2] [3]
Remove JS comment and redundant autoprefixer from PostCSS config
Two things to fix here:
-
JS comment violates repo guidelines
The
// module.exports = require("@cap/ui/postcss");line must be removed. The codebase forbids comments in.cjsfiles; git history already preserves the old config. -
autoprefixeris redundant with@tailwindcss/postcssTailwind 4's
@tailwindcss/postcssplugin integrates Lightning CSS, which handles vendor-prefixing, transpilation, and minification. A separateautoprefixerentry is unnecessary and can be dropped.
Corrected config:
-// module.exports = require("@cap/ui/postcss");
-
module.exports = {
plugins: {
"@tailwindcss/postcss": {},
- autoprefixer: {},
},
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // module.exports = require("@cap/ui/postcss"); | |
| module.exports = { | |
| plugins: { | |
| "@tailwindcss/postcss": {}, | |
| autoprefixer: {}, | |
| }, | |
| }; | |
| module.exports = { | |
| plugins: { | |
| "@tailwindcss/postcss": {}, | |
| }, | |
| }; |
🤖 Prompt for AI Agents
In apps/desktop/postcss.config.cjs around lines 1 to 8, remove the leading JS
comment line and drop the redundant autoprefixer plugin: delete the comment //
module.exports = require("@cap/ui/postcss"); and remove the autoprefixer entry
from the plugins object so only "@tailwindcss/postcss": {} remains; keep the
file as a plain module.exports object with no comments.
| fn has_open_editor_window(app: &AppHandle) -> bool { | ||
| app.webview_windows() | ||
| .keys() | ||
| .any(|label| matches!(CapWindowId::from_str(label), Ok(CapWindowId::Editor { .. }))) | ||
| .any(|label| matches!(CapWindow::from_str(label), Ok(CapWindow::Editor { .. }))) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
has_open_editor_window should use CapWindowDef::from_str, not CapWindow::from_str
Current code:
#[cfg(target_os = "windows")]
fn has_open_editor_window(app: &AppHandle) -> bool {
app.webview_windows()
.keys()
- .any(|label| matches!(CapWindow::from_str(label), Ok(CapWindow::Editor { .. })))
+ // ...
}CapWindow does not implement FromStr in windows.rs, so this will fail to compile on Windows targets. Conceptually, this helper wants to know if any open window label corresponds to an editor window, which is exactly what CapWindowDef::from_str provides.
Suggested fix:
#[cfg(target_os = "windows")]
fn has_open_editor_window(app: &AppHandle) -> bool {
app.webview_windows()
.keys()
- .any(|label| matches!(CapWindow::from_str(label), Ok(CapWindow::Editor { .. })))
+ .any(|label| matches!(CapWindowDef::from_str(label), Ok(CapWindowDef::Editor { .. })))
}This aligns with the rest of the CapWindowDef‑based label parsing.
🤖 Prompt for AI Agents
In apps/desktop/src-tauri/src/lib.rs around lines 2947 to 2951, the helper uses
CapWindow::from_str which doesn't exist on Windows; change the parsing to use
CapWindowDef::from_str and update the pattern to match the CapWindowDef::Editor
variant (e.g. replace the matches!(CapWindow::from_str(label),
Ok(CapWindow::Editor { .. })) call with matches!(CapWindowDef::from_str(label),
Ok(CapWindowDef::Editor { .. }))) so label parsing uses CapWindowDef as in the
rest of the code.
| disabled={openCommercialCheckout.isPending} | ||
| variant="dark" | ||
| class="w-full !rounded-full !h-[48px] text-lg font-medium" | ||
| class="w-full rounded-full! h-[48px]! text-lg font-medium" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix inconsistent Tailwind v4 syntax in arbitrary value.
The important modifiers have been correctly moved to suffix position, but the arbitrary height value still uses brackets. According to Tailwind v4 migration requirements, all arbitrary values must use parentheses syntax.
Apply this diff:
- class="w-full rounded-full! h-[48px]! text-lg font-medium"
+ class="w-full rounded-full! h-(48px)! text-lg font-medium"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| class="w-full rounded-full! h-[48px]! text-lg font-medium" | |
| class="w-full rounded-full! h-(48px)! text-lg font-medium" |
🤖 Prompt for AI Agents
In apps/desktop/src/routes/(window-chrome)/upgrade.tsx around line 424, the
Tailwind arbitrary height uses bracket syntax h-[48px]! which is incompatible
with Tailwind v4; replace it with the parentheses form h-(48px)! so the class
becomes e.g. "w-full rounded-full! h-(48px)! text-lg font-medium" ensuring the
important modifier remains as the suffix and spacing stays consistent.
| const el = (props?: object) => ( | ||
| <KTabs.Trigger | ||
| class="z-10 flex-1 py-2.5 px-2 text-xs text-gray-11 ui-selected:border-gray-3 ui-selected:bg-gray-3 ui-not-selected:hover:border-gray-7 rounded-[10px] transition-colors duration-200 outline-none border ui-selected:text-gray-12 peer" | ||
| class="z-10 flex-1 py-2.5 px-2 text-xs text-gray-11 data-selected:border-gray-3 data-selected:bg-gray-3 ui-not-selected:hover:border-gray-7 rounded-[10px] transition-colors duration-200 outline-none border data-selected:text-gray-12 peer" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tailwind CSS v4 incompatibility: ui-not-selected pseudo-class no longer supported.
Line 1387 still contains ui-not-selected:hover:border-gray-7, which is invalid in Tailwind v4. The ui-* pseudo-classes have been replaced with data-* attribute selectors.
This needs to be either removed or replaced with a valid v4 variant. If you need to style the non-selected state, consider using a negation variant or alternative approach that works with data-* attributes from Kobalte.
🤖 Prompt for AI Agents
In apps/desktop/src/routes/editor/ConfigSidebar.tsx around line 1387, the class
string uses the removed Tailwind v4 pseudo-class
`ui-not-selected:hover:border-gray-7`; remove that token and replace it with a
valid data-attribute based variant such as
`[data-selected="false"]:hover:border-gray-7` or, if relying on the peer
element, `peer-[data-selected="false"]:hover:border-gray-7` so the non-selected
hover style works with Kobalte's data-selected attribute; update the class
string accordingly and ensure quotes/escaping match existing string formatting.
| } | ||
| value={key} | ||
| class="flex relative z-10 flex-1 justify-center items-center px-4 py-2 bg-transparent rounded-lg border transition-colors duration-200 text-gray-11 ui-not-selected:hover:border-gray-7 ui-selected:bg-gray-3 ui-selected:border-gray-3 group ui-selected:text-gray-12 disabled:opacity-50 focus:outline-none" | ||
| class="flex relative z-10 flex-1 justify-center items-center px-4 py-2 bg-transparent rounded-lg border transition-colors duration-200 text-gray-11 ui-not-selected:hover:border-gray-7 data-selected:bg-gray-3 data-selected:border-gray-3 group data-selected:text-gray-12 disabled:opacity-50 focus:outline-none" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tailwind CSS v4 incompatibility: ui-not-selected pseudo-class on line 1531.
The background theme tab trigger contains ui-not-selected:hover:border-gray-7, which is not valid in Tailwind v4. This is the same issue as line 1387 and needs to be migrated to a v4-compatible approach using data-* attributes.
🤖 Prompt for AI Agents
In apps/desktop/src/routes/editor/ConfigSidebar.tsx around line 1531, replace
the Tailwind v3 pseudo-class `ui-not-selected:hover:border-gray-7` with a
v4-compatible data-attribute variant such as
`data-[selected=false]:hover:border-gray-7` and ensure the element sets the
`data-selected` attribute to "true" or "false" appropriately (mirror the same
change applied at line 1387); this removes the invalid `ui-not-selected` token
and uses a data-* hover selector compatible with Tailwind v4.
| <KRadioGroup.ItemControl class="overflow-hidden w-full h-full rounded-lg transition cursor-pointer ui-not-checked:ring-offset-1 ui-not-checked:ring-offset-gray-200 ui-not-checked:hover:ring-1 ui-not-checked:hover:ring-gray-400 data-checked:ring-2 data-checked:ring-gray-500 data-checked:ring-offset-2 data-checked:ring-offset-gray-200"> | ||
| <img |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tailwind CSS v4 incompatibility: Multiple ui-not-checked pseudo-classes.
Lines 1587–1588 contain several invalid v4 variants: ui-not-checked:ring-offset-1, ui-not-checked:ring-offset-gray-200, ui-not-checked:hover:ring-1, and ui-not-checked:hover:ring-gray-400. These need to be migrated to use data-* attributes or removed entirely. The data-checked:* variants on the same lines are correctly formatted for v4, but the negation states remain unconverted.
| </TooltipIconButton> | ||
| <TooltipIconButton | ||
| class="absolute right-3 bottom-3 z-[998]" | ||
| class="absolute right-3 bottom-3 z-998" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Show the actual code at the specified lines
echo "=== Code at line 366 in recordings-overlay.tsx ==="
sed -n '360,372p' apps/desktop/src/routes/recordings-overlay.tsx
echo -e "\n=== Code at line 451 in recordings-overlay.tsx ==="
sed -n '445,457p' apps/desktop/src/routes/recordings-overlay.tsx
echo -e "\n=== Search for all z-index patterns in the file ==="
rg -n "z-\d+" apps/desktop/src/routes/recordings-overlay.tsx
</parameter>Repository: CapSoftware/Cap
Length of output: 174
🏁 Script executed:
#!/bin/bash
# Search for other z-index usage patterns in the codebase
echo "=== All z-index utilities in desktop/src ==="
rg -n "z-\[?\d+\]?" apps/desktop/src --type ts --type tsx | head -30
</parameter>Repository: CapSoftware/Cap
Length of output: 174
🌐 Web query:
Tailwind CSS v4 z-index arbitrary values syntax brackets support
💡 Result:
Yes — Tailwind CSS v4 supports arbitrary z-index values.
- Syntax: z-[] (e.g. class="z-[100]" or class="z-[calc(var(--i)+1)]"). [1]
- CSS-variable shorthand: z-(--my-z) → expands to z-[var(--my-z)]. [1]
- Negative values: you can prefix with a dash for negative utilities (e.g. -z-10); the same negative-prefix pattern also applies to arbitrary values (e.g. -z-[100]). [1][2]
Sources: Tailwind v4 docs (z-index) and v4 feature notes. [1] [2]
References
[1] Tailwind CSS — z-index (v4) documentation.
[2] Tailwind CSS v4 release / features.
Restore brackets for arbitrary z-index values in Tailwind v4.
The syntax z-998 and z-999999 (without brackets) are invalid in Tailwind v4. Arbitrary z-index values must use bracket notation: z-[998] and z-[999999]. Only predefined utilities in Tailwind's z-index scale (e.g., z-10, z-50) work without brackets; arbitrary values always require brackets according to Tailwind v4 documentation.
🤖 Prompt for AI Agents
In apps/desktop/src/routes/recordings-overlay.tsx around line 366, the class
uses invalid Tailwind v4 syntax `z-998` (and elsewhere `z-999999`) which must
use bracket notation for arbitrary values; replace those with `z-[998]` and
`z-[999999]` respectively so Tailwind v4 recognizes the arbitrary z-indexes, and
verify no other non-scale z- classes exist without brackets.
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Dependencies
Style
✏️ Tip: You can customize this high-level summary in your review settings.