Skip to content

Comments

Add Shortcuts Editor#47

Merged
iamEvanYT merged 28 commits intomainfrom
evan/keybind-editor
May 13, 2025
Merged

Add Shortcuts Editor#47
iamEvanYT merged 28 commits intomainfrom
evan/keybind-editor

Conversation

@iamEvanYT
Copy link
Member

@iamEvanYT iamEvanYT commented May 12, 2025

Summary:

Add Shortcuts Editor which allows you to customize the shortcuts.

Random Little Changes:

  • fix: rerender toast animation when new message shown
  • settings: change to sidebar-based ui & update sections
  • fix: devtools url not opening
  • feat: fetch favicons from the actual session instead of default session
  • feat: detect close or back to tab for picture in picture
  • chore: some visual style changes
  • fix: window controls not appearing in fullscreen
  • feat: pipe logs to files

Summary by CodeRabbit

  • New Features

    • Introduced a comprehensive keyboard shortcuts management system with a dedicated settings UI for viewing, editing, resetting, and searching shortcuts.
    • Added a new global actions system including centralized "copy link" handling.
    • Enhanced tab management with refined Picture-in-Picture exit detection and new devtools URL handling.
    • Added persistent application logging with platform-specific log file locations.
    • Improved settings navigation with a sidebar layout and sectioned organization.
    • Added animated and accessible UI components for dialogs, toasts, and shortcut editing.
    • Introduced context providers for actions and shortcuts to manage related functionality and state.
    • Added dynamic menu accelerators that reflect current shortcut configurations.
    • Implemented caching and optimized serving of active tab favicons.
  • Improvements

    • Refined UI for settings, cards, and external apps with better accessibility, error handling, and visual consistency.
    • Enhanced favicon handling and sidebar tab group UI with animated audio mute/unmute controls.
    • Improved loading and error states for informational cards and permission management.
    • Standardized keyboard shortcut management by replacing hardcoded accelerators with dynamic retrieval.
    • Updated menu accelerators to reflect current shortcut configurations dynamically.
    • Improved window button visibility management, especially during full-screen transitions.
    • Enhanced toast message transitions with smoother state changes.
  • Bug Fixes

    • Fixed menu shortcut accelerators to respond to user-configured shortcuts.
    • Improved Picture-in-Picture mode transitions and tab focus logic.
  • Documentation

    • Added documentation on log file locations across operating systems.
  • Chores

    • Standardized GitHub issue templates formatting.
    • Added and updated dependencies related to UI components and alert dialogs.
    • Integrated new IPC handlers for shortcuts and actions in the main process.
  • Refactor

    • Replaced legacy settings topbar with a sidebar layout and new titlebar.
    • Modularized and restructured settings and provider components for improved maintainability and state management.
    • Replaced card UI components with custom styled containers for better control.
    • Refactored clipboard copy logic to use centralized action dispatching.
    • Updated menu creation functions to remove unused parameters and improve shortcut handling.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 12, 2025

Walkthrough

This update introduces a comprehensive keyboard shortcuts management system, including backend storage, IPC integration, and a full React-based UI for editing, resetting, and displaying shortcuts. It also adds a logging module, improves Picture-in-Picture tab control, enhances menu shortcut handling, and refactors several settings UI components for better structure, feedback, and accessibility.

Changes

Files / Groups Change Summary
.github/ISSUE_TEMPLATE/bug_report.md, .github/ISSUE_TEMPLATE/feature_request.md Standardized YAML syntax and minor markdown formatting in issue templates.
components.json Added new configuration file for UI components, Tailwind CSS, and path aliases.
docs/references/logs.md Added documentation listing log file locations for different OSes.
package.json Updated @radix-ui/react-slot version and added @radix-ui/react-alert-dialog as a dev dependency.
src/main/browser/tabs/tab-manager.ts, src/main/ipc/browser/tabs.ts, src/shared/flow/interfaces/browser/tabs.ts Extended disablePictureInPicture to accept a goBackToTab parameter, updating method and IPC handler signatures.
src/main/browser/tabs/tab.ts Improved devtools URL handling and refined Picture-in-Picture exit logic.
src/main/browser/utility/menu.ts, src/main/browser/utility/menu/items/archive.ts, src/main/browser/utility/menu/items/edit.ts, src/main/browser/utility/menu/items/file.ts, src/main/browser/utility/menu/items/view.ts Refactored menu shortcut accelerators to use dynamic shortcut fetching; updated edit menu to use IPC for "Copy URL".
src/main/browser/utility/protocols.ts, src/renderer/src/lib/utils.ts, src/renderer/src/components/browser-ui/sidebar/content/sidebar-tab-groups.tsx Introduced active favicon protocol handler and utility; updated sidebar tab favicon rendering.
src/main/browser/window.ts, src/main/ipc/browser/interface.ts Centralized window button visibility state and updated IPC handler to use new method.
src/main/ipc/app/actions.ts, src/shared/flow/interfaces/app/actions.ts, src/shared/flow/flow.ts Added IPC actions API for copy link and generic actions, updating global flow API.
src/main/ipc/app/shortcuts.ts, src/main/modules/shortcuts.ts, src/main/saving/shortcuts.ts, src/shared/flow/interfaces/app/shortcuts.ts, src/shared/types/shortcuts.ts Introduced keyboard shortcuts backend, IPC handlers, TypeScript interfaces, and persistent storage for modified shortcuts.
src/main/ipc/main.ts Integrated shortcuts IPC module into main IPC entry point.
src/main/modules/logs.ts, src/main/modules/output.ts, docs/references/logs.md Added logging module to persist stdout to log files and updated output module to import it.
src/preload/index.ts Exposed new actions and shortcuts APIs, updated permissions, and extended tabs API.
src/renderer/src/components/browser-ui/main.tsx Wrapped browser UI in new ActionsProvider for centralized actions handling.
src/renderer/src/components/browser-ui/sidebar/header/address-bar/address-bar.tsx, src/renderer/src/components/browser-ui/sidebar/header/address-bar/copy-link-button.tsx Refactored copy link button to use context action instead of direct clipboard access.
src/renderer/src/components/omnibox/main.tsx Simplified background styling logic.
src/renderer/src/components/providers/actions-provider.tsx Added provider/context for copy link and incoming actions with event subscriptions.
src/renderer/src/components/providers/minimal-toast-provider.tsx Improved toast message transition logic for better feedback.
src/renderer/src/components/providers/shortcuts-provider.tsx Added provider/context for managing and formatting keyboard shortcuts.
src/renderer/src/components/settings/sections/about/browser-info-card.tsx Improved loading/error handling and UI structure for browser info card.
src/renderer/src/components/settings/sections/about/section.tsx Removed unused update and legal info cards.
src/renderer/src/components/settings/sections/external-apps/section.tsx Enhanced accessibility, loading, error handling, and animations for external apps permissions.
src/renderer/src/components/settings/sections/general/basic-settings-cards.tsx, src/renderer/src/components/settings/sections/general/reset-onboarding-card.tsx, src/renderer/src/components/settings/sections/general/set-as-default-browser-setting.tsx, src/renderer/src/components/settings/sections/general/update-card.tsx Refactored settings UI to use custom styled divs instead of Card components; improved loading, error, and action states.
src/renderer/src/components/settings/sections/shortcuts/components/category-section.tsx, src/renderer/src/components/settings/sections/shortcuts/components/empty-state.tsx, src/renderer/src/components/settings/sections/shortcuts/components/modified-shortcuts-section.tsx, src/renderer/src/components/settings/sections/shortcuts/components/reset-dialog.tsx, src/renderer/src/components/settings/sections/shortcuts/components/search-header.tsx, src/renderer/src/components/settings/sections/shortcuts/shortcut-item.tsx, src/renderer/src/components/settings/sections/shortcuts/hooks/use-keyboard-normalizer.tsx, src/renderer/src/components/settings/sections/shortcuts/section.tsx Added complete keyboard shortcuts management UI: category display, editing, search, reset dialog, empty/loading states, keyboard normalization, and shortcut item component.
src/renderer/src/components/settings/settings-layout.tsx, src/renderer/src/components/settings/settings-sidebar.tsx, src/renderer/src/components/settings/settings-titlebar.tsx, src/renderer/src/components/providers/shortcuts-provider.tsx Refactored settings layout to use sidebar navigation, added Shortcuts section and provider, replaced topbar with titlebar.
src/renderer/src/components/settings/settings-topbar.tsx Removed obsolete settings topbar component.
src/renderer/src/components/ui/alert-dialog.tsx Added new AlertDialog UI component set based on Radix primitives.
src/renderer/src/hooks/use-debounce.tsx Introduced generic debounce hook for value updates.

Sequence Diagram(s)

Keyboard Shortcut Update Flow

sequenceDiagram
    participant Renderer as Renderer (React UI)
    participant Preload as Preload Script
    participant Main as Main Process
    participant Storage as Shortcuts Storage

    Renderer->>Preload: flow.shortcuts.setShortcut(actionId, shortcut)
    Preload->>Main: IPC "shortcuts:set" (actionId, shortcut)
    Main->>Storage: updateModifiedShortcut(actionId, shortcut)
    Storage-->>Main: Success/Failure
    Main->>Preload: Returns success status
    Preload->>Renderer: Returns success status
    Main-->>Renderer: Broadcast "shortcuts-changed" via IPC
    Renderer->>Renderer: UI updates with new shortcuts
Loading

Copy Link Action Flow

sequenceDiagram
    participant Renderer as Renderer (UI)
    participant Preload as Preload Script
    participant Main as Main Process

    Renderer->>Preload: (User clicks Copy Link)
    Preload->>Main: IPC "actions:on-copy-link"
    Main->>Renderer: IPC event "actions:on-copy-link"
    Renderer->>Renderer: Copies link to clipboard, shows toast
Loading

Possibly related PRs

  • MultiboxLabs/flow-browser#5: Introduced favicon caching and protocol handling, directly related to the new favicon cache and protocol handler in this PR.
  • MultiboxLabs/flow-browser#31: Added and updated "Set as Default Browser" logic and UI, which is further refined and restyled in this PR.
  • MultiboxLabs/flow-browser#22: Added the initial disablePictureInPicture method, which is extended with new parameters and logic in this PR.

Suggested labels

enhancement, bug

Poem

In the warren where shortcuts hop and play,
A rabbit coded keys to brighten every day.
With menus that shimmer and settings anew,
Logs are now tidy, and favicons, too!
“Copy Link!” cries the bunny, clipboard at the ready—
All thanks to teamwork, swift and steady.
🐇✨⌨️

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@iamEvanYT iamEvanYT changed the title Add Keybind Editor Add Shortcuts Editor May 13, 2025
@iamEvanYT iamEvanYT marked this pull request as ready for review May 13, 2025 10:17
Copy link
Contributor

@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: 18

🔭 Outside diff range comments (4)
src/main/browser/tabs/tab-manager.ts (1)

231-251: 🛠️ Refactor suggestion

Improve documentation for the new parameter and use optional chaining

The added goBackToTab parameter provides helpful flexibility for controlling tab focus behavior after disabling Picture-in-Picture mode. Two improvements would enhance this code:

  1. Add JSDoc comments to explain the purpose of the new parameter
  2. Use optional chaining as suggested by static analysis
/**
 * Disable Picture in Picture mode for a tab
+ * @param tabId The ID of the tab to disable Picture in Picture mode for
+ * @param goBackToTab Whether to focus the window and set the tab as active after disabling PiP
+ * @returns true if PiP was disabled, false if the tab wasn't in PiP mode
 */
public disablePictureInPicture(tabId: number, goBackToTab: boolean) {
  const tab = this.getTabById(tabId);
-  if (tab && tab.isPictureInPicture) {
+  if (tab?.isPictureInPicture) {
    tab.updateStateProperty("isPictureInPicture", false);

    if (goBackToTab) {
      // Set the space for the window
      const win = tab.getWindow();
      setWindowSpace(win, tab.spaceId);

      // Focus window
      win.window.focus();

      // Set active tab
      this.setActiveTab(tab);
    }

    return true;
  }
  return false;
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 233-233: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/main/modules/logs.ts (1)

1-50: 🛠️ Refactor suggestion

Consider adding error handling for log file operations

The logging implementation currently doesn't handle potential errors when writing to log files, which could lead to unhandled exceptions.

Add error handling to prevent crashes if log writing fails:

+// Set up error handling for the log stream
+logStream.on('error', (error) => {
+  console.error(`Error writing to log file: ${error.message}`);
+  // Restore original stdout to prevent infinite loops if logging fails
+  if (process.stdout.write !== originalStdoutWrite) {
+    process.stdout.write = originalStdoutWrite;
+  }
+});

function newStdoutWrite(
  chunk: Uint8Array | string,
  encodingOrCallback?: BufferEncoding | Callback,
  callback?: Callback
) {
  if (typeof chunk === "string") {
    // Remove ANSI escape codes from console output
    // This regex targets escape sequences that control terminal colors and formatting
    // eslint-disable-next-line no-control-regex
    chunk = chunk.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "");
  }

+  try {
    logStream.write(chunk);
+  } catch (error) {
+    console.error(`Failed to write to log file: ${error.message}`);
+  }

  // @ts-expect-error: This is a workaround to log to the log file
  return originalStdoutWrite.call(process.stdout, chunk, encodingOrCallback, callback);
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 41-41: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)

src/main/browser/tabs/tab.ts (1)

759-779: 🛠️ Refactor suggestion

enterPiP relies on global flow – verify preload exposure

Inside the injected enterPiP function, flow.tabs.disablePictureInPicture is assumed to be globally available in the page context.
If extensions or CSPs inject an isolated world, or the preload fails, flow may be undefined, causing an uncaught exception that aborts the promise and hides the PiP failure.

Add a presence check and fall back gracefully:

-                  flow.tabs.disablePictureInPicture(goBackToTab);
+                  if (window.flow?.tabs?.disablePictureInPicture) {
+                    window.flow.tabs.disablePictureInPicture(goBackToTab);
+                  } else {
+                    console.warn("flow API unavailable – cannot disable PiP");
+                  }
src/preload/index.ts (1)

47-72: ⚠️ Potential issue

"all" permission bypasses every check – confirm this is intentional

hasPermission("all") always returns true, making any API wrapped with that permission callable from any renderer (including un-trusted ones if they ever get this preload).
In particular, tabs.disablePictureInPicture is now exposed under "all" (see lines 510-512).

Double-check the threat model and consider limiting "all" to isInternalProtocols instead of unconditional access.

🧹 Nitpick comments (26)
src/main/ipc/app/actions.ts (2)

4-6: Consider removing unnecessary async keyword

This function doesn't contain any awaited operations. Unless there are plans to add asynchronous operations in the future, consider removing the async keyword to avoid setting false expectations.

-export async function fireCopyLinkAction(win: TabbedBrowserWindow) {
+export function fireCopyLinkAction(win: TabbedBrowserWindow) {
  sendMessageToListenersInWindow(win, "actions:on-copy-link");
}

8-10: Consider removing unnecessary async keyword

This function doesn't contain any awaited operations. Unless there are plans to add asynchronous operations in the future, consider removing the async keyword to avoid setting false expectations.

-export async function fireFrontendAction(action: string) {
+export function fireFrontendAction(action: string) {
  sendMessageToListeners("actions:on-incoming", action);
}
src/renderer/src/components/settings/sections/shortcuts/components/search-header.tsx (1)

12-33: Enhance accessibility.

The component has good UI/UX with responsive design and visual feedback, but could benefit from improved accessibility.

Add aria-label attributes to the buttons for screen readers:

<Input
  type="search"
  placeholder="Search shortcuts..."
  className="pl-9 w-full"
  value={searchTerm}
  onChange={(e) => onSearchChange(e.target.value)}
+  aria-label="Search shortcuts"
/>
...
<Button 
  variant="outline" 
  onClick={onResetClick} 
  disabled={isLoading} 
  className="group"
+  aria-label="Reset all shortcuts to default values"
>
src/renderer/src/components/browser-ui/sidebar/header/address-bar/copy-link-button.tsx (1)

65-68: Extract magic number to constant.

The timeout duration for resetting the copied state is hardcoded to 3000ms. For better maintainability, consider extracting this to a named constant.

+const COPY_FEEDBACK_DURATION_MS = 3000;

export function AddressBarCopyLinkButton() {
  // ...existing code...
  
  setTimeout(() => {
    setCopied(false);
-  }, 3000);
+  }, COPY_FEEDBACK_DURATION_MS);
src/main/modules/logs.ts (2)

38-42: Control character in regex needs to be justified

The regex to remove ANSI escape codes uses a control character sequence. While this is intentional and necessary for cleaning logs, it's triggered a linting error.

Add a more specific comment explaining why the control character regex is necessary:

-    // remove ANSI escape codes
+    // Remove ANSI escape codes from console output
+    // This regex targets escape sequences that control terminal colors and formatting
🧰 Tools
🪛 Biome (1.9.4)

[error] 41-41: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)


46-48: Consider improving the type safety of stdout write override

The current implementation uses @ts-expect-error to bypass TypeScript checking when calling the original stdout write method.

Consider using a more type-safe approach by explicitly casting the function types:

-  // @ts-expect-error: This is a workaround to log to the log file
-  return originalStdoutWrite.call(process.stdout, chunk, encodingOrCallback, callback);
+  // Cast the function to ensure type compatibility
+  return (originalStdoutWrite as Function).call(
+    process.stdout, 
+    chunk, 
+    encodingOrCallback, 
+    callback
+  );
src/main/browser/tabs/tab.ts (1)

791-799: Surface enterPiP execution errors to the caller

executeJavaScript failures are swallowed and only logged to the console.
Emitting an event (or at least updating a state flag) would allow UI components to react and show feedback to the user.

Consider emitting a dedicated "pip-error" event or returning the rejection so the caller can decide.

src/renderer/src/components/settings/sections/shortcuts/components/modified-shortcuts-section.tsx (2)

1-6: Verify Motion One React package name

motion/react belongs to Motion One’s React bindings (@motionone/react).
If the project uses Framer Motion elsewhere (framer-motion), this import will resolve differently and bundle two animation libraries.

Double-check package.json to ensure only one motion library is installed and update the import accordingly:

-import { AnimatePresence, motion } from "motion/react";
+import { AnimatePresence, motion } from "@motionone/react"; // or "framer-motion"

50-69: Keyboard handler & ref passed to every item

onKeyDown and inputRef are only meaningful for the item currently being edited, yet they are forwarded to every ShortcutItem.
Passing the same ref to multiple elements breaks the “one-ref-per-node” contract and may lead to unexpected focus behaviour.

Refactor so those props are only provided to the editing item:

-<ShortcutItem
+const isEditing = editingActionId === shortcut.id;
+<ShortcutItem
   ...
-  inputRef={inputRef}
-  onKeyDown={onKeyDown}
+  inputRef={isEditing ? inputRef : undefined}
+  onKeyDown={isEditing ? onKeyDown : undefined}
   ...
/>
src/main/browser/utility/protocols.ts (2)

132-176: parseInt without radix & missing fetch-error handling

  1. Always pass a radix to parseInt to avoid subtle bugs in browsers that still treat "08"/"09" as octal.
  2. If profile.session.fetch fails (network error, 4xx/5xx), the resulting response is still cached and returned; subsequent callers will always see the error response.
    Check response.ok before caching.
-const tabIdInt = parseInt(tabId);
+const tabIdInt = parseInt(tabId, 10);

-const faviconResponse = await profile.session.fetch(faviconURL);
-if (!faviconResponse.ok) return faviconResponse; // don’t cache failures
+const faviconResponse = await profile.session.fetch(faviconURL);
+if (!faviconResponse.ok) return faviconResponse;

195-199: Route precedence comment

Nice integration of the new active-favicon route.
Consider documenting it in a central protocol routing table to avoid future collisions with additional hosts.

src/renderer/src/components/settings/settings-sidebar.tsx (2)

6-10: Icon prop typing is off – use ReactElement not component generic

React.ReactElement<LucideIcon> is not the intended generic – the first generic parameter is the element’s props shape, not the component type.
Simplest fix:

-  icon: React.ReactElement<LucideIcon>;
+  icon: React.ReactElement;

or expose the icon component instead (icon: LucideIcon) and render it as <section.icon className="…" />.


22-33: Accessibility: convey current section to assistive tech

Add aria-current="page" (or "true") to the active button so screen-reader users know which section is selected.

<motion.button
  …
+ aria-current={activeSection === section.id ? "page" : undefined}
>
src/renderer/src/components/providers/shortcuts-provider.tsx (2)

32-41: .replace without /g only replaces first occurrence

If a shortcut somehow contains multiple + signs or other tokens, only the first instance is replaced. Minor now, but safer to use global regexes:

-return shortcut
-  .replace(/\+/g, " + ")
-  .replace("CommandOrControl", "⌘/Ctrl")
+return shortcut
+  .replace(/\+/g, " + ")
+  .replace(/CommandOrControl/g, "⌘/Ctrl")

96-107: Reset-all performs N IPC round-trips – expose bulk API instead

resetAllShortcuts issues one IPC call per action, increasing latency and load.
Consider adding a dedicated flow.shortcuts.resetAll() in the main process that resets everything in one call, then refresh once.

This will also avoid partial failure states if one of the awaits rejects midway.

src/renderer/src/components/settings/sections/general/update-card.tsx (2)

240-246: Progress bar shows 0 % until first tick – minor UX nit

Consider rendering the bar only after the first progress event to avoid a momentary 0 % bar that may feel like a glitch.
E.g. isDownloadingUpdate && updateProgress > 0.


250-271: cn helper used but not needed – small bundle win

className={cn("rounded-md border p-3 …", "bg-orange-500/10 …")} merges only two static strings.
Direct string concatenation is enough here and keeps the generated class list predictable.

-className={cn(
-  "rounded-md border p-3 mt-4 text-sm",
-  "bg-orange-500/10 border-orange-500/30 text-orange-700 dark:text-orange-400"
-)}
+className="rounded-md border p-3 mt-4 text-sm bg-orange-500/10 border-orange-500/30 text-orange-700 dark:text-orange-400"
src/renderer/src/components/providers/actions-provider.tsx (2)

41-49: Improve error handling for copyLink function.

The function currently returns silently when addressUrl is undefined. Consider providing feedback to the user in this case.

  const copyLink = useCallback(async (): Promise<void> => {
    if (!addressUrl) {
+     showToast("No URL available to copy.", {
+       type: "error"
+     });
      return;
    }

    copyTextToClipboard(addressUrl, false).then((success) => {
      if (success) {
        showToast("Copied to clipboard!");
      }
    });
  }, [addressUrl, showToast]);

64-71: Properly managed event subscriptions.

The event subscriptions are properly set up and cleaned up on component unmount, preventing memory leaks. However, the dependency arrays could be simplified since the refs themselves don't change.

  // Listener for the onCopyLink event from the main process
  useEffect(() => {
    const unsubscribe = flow.actions.onCopyLink(() => {
      return copyLinkCallbackRef.current();
    });
    return () => {
      unsubscribe();
    };
-  }, [copyLinkCallbackRef]);
+  }, []);

  // Listener for the onIncomingAction event from the main process
  useEffect(() => {
    const unsubscribe = flow.actions.onIncomingAction((action) => {
      return handleIncomingActionCallbackRef.current(action);
    });
    return () => {
      unsubscribe();
    };
-  }, [handleIncomingActionCallbackRef]);
+  }, []);

Also applies to: 74-81

src/renderer/src/components/settings/sections/shortcuts/section.tsx (1)

140-175: Minor: “Modified” sort rule is redundant

You treat "Modified" as a special category when sorting, yet that string never occurs in groupedKeybinds because modified shortcuts are handled in a dedicated array.
The extra comparison adds an unnecessary branch and can be safely removed to simplify the sorter.

src/renderer/src/components/settings/sections/general/basic-settings-cards.tsx (1)

55-93: TooltipProvider wrapper is unused

TooltipProvider is rendered but no descendant Tooltip is present inside the card.
Unless tooltips are added later, this wrapper adds one extra React node and context provider per card without benefit.

If not required, consider removing it to keep the DOM tree shallow.

src/preload/index.ts (1)

482-495: Specify expected return types on ipcRenderer.invoke to regain type-safety

ipcRenderer.invoke returns Promise<unknown> unless a generic is supplied. Right now the compiler can’t tell that setShortcut resolves to boolean, etc.

-return ipcRenderer.invoke("shortcuts:set", actionId, shortcut);
+return ipcRenderer.invoke<boolean>("shortcuts:set", actionId, shortcut);

Apply the same pattern to every invoke call in shortcutsAPI.

src/renderer/src/components/settings/sections/external-apps/section.tsx (1)

37-42: Replace deprecated onKeyPress with onKeyDown for accessibility

onKeyPress is deprecated in React 18 and doesn’t fire for all keyboards. Use onKeyDown and filter for Enter/Space.

- onKeyPress={(e) => (e.key === "Enter" || e.key === " ") && setExpanded(!expanded)}
+ onKeyDown={(e) => {
+   if (e.key === "Enter" || e.key === " ") {
+     e.preventDefault();
+     setExpanded(!expanded);
+   }
+ }}
src/main/saving/shortcuts.ts (1)

29-40: Consider cleaning up invalid data from the datastore

Currently, invalid shortcut data is logged but remains in the datastore, which could lead to repeated errors on application restart.

Consider removing invalid data:

 for (const key of Object.keys(rawModifiedShortcuts)) {
   const rawModifiedShortcutData = rawModifiedShortcuts[key];
   const parseResult = ModifiedShortcutData.safeParse(rawModifiedShortcutData);
   if (!parseResult.success) {
     console.error(`Invalid shortcut data for ${key}:`, parseResult.error);
+    // Remove invalid data to prevent repeated errors
+    ShortcutsDataStore.remove(key).catch(err => {
+      console.error(`Failed to remove invalid shortcut data for ${key}:`, err);
+    });
     continue;
   }

   const modifiedShortcutData = parseResult.data;
   modifiedShortcuts.set(key, modifiedShortcutData);
   hasChanged = true;
 }
src/renderer/src/components/ui/alert-dialog.tsx (2)

7-13: Consider using explicit type declarations for components

The AlertDialog and AlertDialogTrigger components use ComponentProps for type definitions, which works but could be more explicit about the props they accept.

For clearer type definitions:

-function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
+type AlertDialogProps = React.ComponentProps<typeof AlertDialogPrimitive.Root>;
+
+function AlertDialog({ ...props }: AlertDialogProps) {
   return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
 }

-function AlertDialogTrigger({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
+type AlertDialogTriggerProps = React.ComponentProps<typeof AlertDialogPrimitive.Trigger>;
+
+function AlertDialogTrigger({ ...props }: AlertDialogTriggerProps) {
   return <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />;
 }

1-6: Consider adding accessibility documentation

While the implementation correctly uses Radix UI primitives which have good accessibility support, it might be helpful to document the accessibility features for developers using these components.

Add a comment at the top of the file explaining the accessibility features:

 import * as React from "react";
 import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
 
+/**
+ * Alert Dialog Component
+ * 
+ * Built on Radix UI's AlertDialog primitives with the following accessibility features:
+ * - Manages focus correctly
+ * - Supports keyboard navigation
+ * - Properly implements ARIA attributes
+ * - Provides screen reader announcements
+ * 
+ * Usage guidelines:
+ * - Use for important confirmations that require user attention
+ * - Provide clear, concise messages in the title and description
+ * - Always include a cancel option
+ */
+
 import { cn } from "@/lib/utils";
 import { buttonVariants } from "@/components/ui/button";
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ec86d2 and c60760f.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (59)
  • .github/ISSUE_TEMPLATE/bug_report.md (2 hunks)
  • .github/ISSUE_TEMPLATE/feature_request.md (1 hunks)
  • components.json (1 hunks)
  • docs/references/logs.md (1 hunks)
  • package.json (1 hunks)
  • src/main/browser/tabs/tab-manager.ts (2 hunks)
  • src/main/browser/tabs/tab.ts (4 hunks)
  • src/main/browser/utility/menu.ts (3 hunks)
  • src/main/browser/utility/menu/items/archive.ts (2 hunks)
  • src/main/browser/utility/menu/items/edit.ts (2 hunks)
  • src/main/browser/utility/menu/items/file.ts (2 hunks)
  • src/main/browser/utility/menu/items/view.ts (5 hunks)
  • src/main/browser/utility/protocols.ts (2 hunks)
  • src/main/browser/window.ts (4 hunks)
  • src/main/ipc/app/actions.ts (1 hunks)
  • src/main/ipc/app/shortcuts.ts (1 hunks)
  • src/main/ipc/browser/interface.ts (2 hunks)
  • src/main/ipc/browser/tabs.ts (1 hunks)
  • src/main/ipc/main.ts (1 hunks)
  • src/main/modules/logs.ts (1 hunks)
  • src/main/modules/output.ts (1 hunks)
  • src/main/modules/shortcuts.ts (1 hunks)
  • src/main/saving/shortcuts.ts (1 hunks)
  • src/preload/index.ts (7 hunks)
  • src/renderer/src/components/browser-ui/main.tsx (2 hunks)
  • src/renderer/src/components/browser-ui/sidebar/content/sidebar-tab-groups.tsx (3 hunks)
  • src/renderer/src/components/browser-ui/sidebar/header/address-bar/address-bar.tsx (1 hunks)
  • src/renderer/src/components/browser-ui/sidebar/header/address-bar/copy-link-button.tsx (2 hunks)
  • src/renderer/src/components/omnibox/main.tsx (1 hunks)
  • src/renderer/src/components/providers/actions-provider.tsx (1 hunks)
  • src/renderer/src/components/providers/minimal-toast-provider.tsx (1 hunks)
  • src/renderer/src/components/providers/shortcuts-provider.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/about/browser-info-card.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/about/section.tsx (0 hunks)
  • src/renderer/src/components/settings/sections/external-apps/section.tsx (6 hunks)
  • src/renderer/src/components/settings/sections/general/basic-settings-cards.tsx (3 hunks)
  • src/renderer/src/components/settings/sections/general/reset-onboarding-card.tsx (2 hunks)
  • src/renderer/src/components/settings/sections/general/set-as-default-browser-setting.tsx (2 hunks)
  • src/renderer/src/components/settings/sections/general/update-card.tsx (5 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/components/category-section.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/components/empty-state.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/components/modified-shortcuts-section.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/components/reset-dialog.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/components/search-header.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/hooks/use-keyboard-normalizer.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/section.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/shortcut-item.tsx (1 hunks)
  • src/renderer/src/components/settings/settings-layout.tsx (3 hunks)
  • src/renderer/src/components/settings/settings-sidebar.tsx (1 hunks)
  • src/renderer/src/components/settings/settings-titlebar.tsx (1 hunks)
  • src/renderer/src/components/settings/settings-topbar.tsx (0 hunks)
  • src/renderer/src/components/ui/alert-dialog.tsx (1 hunks)
  • src/renderer/src/hooks/use-debounce.tsx (1 hunks)
  • src/renderer/src/lib/utils.ts (1 hunks)
  • src/shared/flow/flow.ts (2 hunks)
  • src/shared/flow/interfaces/app/actions.ts (1 hunks)
  • src/shared/flow/interfaces/app/shortcuts.ts (1 hunks)
  • src/shared/flow/interfaces/browser/tabs.ts (1 hunks)
  • src/shared/types/shortcuts.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • src/renderer/src/components/settings/sections/about/section.tsx
  • src/renderer/src/components/settings/settings-topbar.tsx
🧰 Additional context used
🧬 Code Graph Analysis (24)
src/renderer/src/components/browser-ui/sidebar/header/address-bar/address-bar.tsx (1)
src/renderer/src/components/browser-ui/sidebar/header/address-bar/copy-link-button.tsx (1)
  • AddressBarCopyLinkButton (54-79)
src/main/browser/utility/menu.ts (2)
src/main/browser/utility/menu/items/edit.ts (1)
  • createEditMenu (6-30)
src/main/saving/shortcuts.ts (1)
  • shortcutsEmitter (18-18)
src/main/ipc/app/shortcuts.ts (2)
src/main/modules/shortcuts.ts (1)
  • getShortcuts (78-91)
src/main/saving/shortcuts.ts (3)
  • updateModifiedShortcut (50-62)
  • resetModifiedShortcut (65-74)
  • shortcutsEmitter (18-18)
src/main/ipc/app/actions.ts (1)
src/main/browser/window.ts (1)
  • TabbedBrowserWindow (29-274)
src/main/browser/utility/menu/items/view.ts (1)
src/main/modules/shortcuts.ts (1)
  • getCurrentShortcut (101-105)
src/shared/flow/flow.ts (2)
src/shared/flow/interfaces/app/actions.ts (1)
  • FlowActionsAPI (4-14)
src/shared/flow/interfaces/app/shortcuts.ts (1)
  • FlowShortcutsAPI (7-27)
src/main/ipc/browser/interface.ts (1)
src/main/index.ts (1)
  • browser (14-14)
src/renderer/src/components/browser-ui/main.tsx (3)
src/renderer/src/components/providers/actions-provider.tsx (1)
  • ActionsProvider (36-93)
src/renderer/src/lib/utils.ts (1)
  • cn (5-7)
src/renderer/src/components/browser-ui/sidebar/hover-detector.tsx (1)
  • SidebarHoverDetector (5-35)
src/renderer/src/components/browser-ui/sidebar/header/address-bar/copy-link-button.tsx (1)
src/renderer/src/components/providers/actions-provider.tsx (1)
  • useActions (24-30)
src/main/modules/logs.ts (1)
src/main/modules/paths.ts (1)
  • FLOW_DATA_DIR (16-16)
src/main/ipc/browser/tabs.ts (1)
src/main/index.ts (1)
  • browser (14-14)
src/renderer/src/components/settings/sections/shortcuts/components/category-section.tsx (2)
src/shared/types/shortcuts.ts (1)
  • ShortcutAction (1-7)
src/renderer/src/components/settings/sections/shortcuts/shortcut-item.tsx (1)
  • ShortcutItem (24-141)
src/renderer/src/components/providers/shortcuts-provider.tsx (1)
src/shared/types/shortcuts.ts (1)
  • ShortcutAction (1-7)
src/main/browser/utility/protocols.ts (1)
src/main/index.ts (1)
  • browser (14-14)
src/renderer/src/components/settings/sections/general/basic-settings-cards.tsx (2)
src/renderer/src/lib/utils.ts (1)
  • cn (5-7)
src/renderer/src/components/settings/sections/general/set-as-default-browser-setting.tsx (1)
  • SetAsDefaultBrowserSetting (6-59)
src/renderer/src/components/settings/sections/general/update-card.tsx (2)
src/main/modules/auto-update.ts (3)
  • isAutoUpdateSupported (52-56)
  • checkForUpdates (58-86)
  • downloadUpdate (122-184)
src/renderer/src/lib/utils.ts (1)
  • cn (5-7)
src/renderer/src/components/settings/sections/general/set-as-default-browser-setting.tsx (1)
src/main/modules/default-browser.ts (1)
  • setDefaultBrowser (16-42)
src/shared/flow/interfaces/app/shortcuts.ts (1)
src/shared/types/shortcuts.ts (1)
  • ShortcutAction (1-7)
src/renderer/src/components/settings/sections/shortcuts/shortcut-item.tsx (2)
src/shared/types/shortcuts.ts (1)
  • ShortcutAction (1-7)
src/renderer/src/lib/utils.ts (1)
  • cn (5-7)
src/renderer/src/components/settings/sections/external-apps/section.tsx (1)
src/renderer/src/lib/utils.ts (1)
  • cn (5-7)
src/renderer/src/components/providers/actions-provider.tsx (2)
src/renderer/src/components/providers/minimal-toast-provider.tsx (1)
  • useToast (14-20)
src/renderer/src/lib/utils.ts (1)
  • copyTextToClipboard (15-34)
src/renderer/src/components/ui/alert-dialog.tsx (1)
src/renderer/src/lib/utils.ts (1)
  • cn (5-7)
src/main/modules/shortcuts.ts (2)
src/shared/types/shortcuts.ts (1)
  • ShortcutAction (1-7)
src/main/saving/shortcuts.ts (1)
  • getAllModifiedShortcuts (94-99)
src/preload/index.ts (2)
src/shared/flow/interfaces/app/actions.ts (1)
  • FlowActionsAPI (4-14)
src/shared/flow/interfaces/app/shortcuts.ts (2)
  • FlowShortcutsAPI (7-27)
  • ShortcutsData (4-4)
🪛 Biome (1.9.4)
src/main/browser/tabs/tab-manager.ts

[error] 233-233: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/main/modules/logs.ts

[error] 41-41: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)

🔇 Additional comments (94)
.github/ISSUE_TEMPLATE/feature_request.md (1)

6-6: Standardize YAML quoting for assignees field
Changed the empty single-quoted string to double quotes to align with the bug-report template and maintain consistency across issue templates.

.github/ISSUE_TEMPLATE/bug_report.md (3)

4-6: Standardize YAML quoting for title, labels, and assignees fields
Converted the empty single-quoted values to double-quoted strings to ensure uniform syntax across all issue templates.


14-14: Insert blank line before reproduction steps
Added a blank line before the numbered list under “To Reproduce” to improve readability in the rendered Markdown.


27-29: Add spacing before device information list
Inserted a blank line and ensured proper indentation for the device info items to enhance visual separation and clarity.

src/renderer/src/components/settings/sections/about/browser-info-card.tsx (5)

6-18: Well-structured reusable component for consistent display

The new InfoRow component improves code reusability and ensures consistent styling for the browser information display. The component properly handles text overflow with break-words and uses semantic class names to indicate the purpose of each element.


22-22: Good addition of loading state tracking

Adding an explicit loading state improves the user experience by providing feedback during data fetching.


24-37: Improved error handling with proper state management

The enhanced error handling now properly manages loading state, clears stale data on errors, and uses a finally block to ensure loading state is always updated regardless of success or failure.


40-45: Enhanced semantic structure with better accessibility

Replacing Card with a styled div that includes proper heading hierarchy (h3) and descriptive text improves accessibility and semantic structure.


47-66: Comprehensive UI states with user feedback

The component now properly handles all three states (loading, success, error) with appropriate visual feedback:

  • Loading state shows an animated spinner
  • Success state displays structured information
  • Error state shows a clear error message with appropriate styling

This significantly improves the user experience by providing clear feedback at each stage.

src/main/modules/output.ts (1)

4-4: Good integration of logging module

Adding the logs module import ensures that application logs are captured from the beginning of the application lifecycle. This aligns with the PR objective to "pipe logs to files" and follows the principle of separation of concerns by keeping logging functionality in a dedicated module.

package.json (2)

63-63: Dependency version update

Updating the @radix-ui/react-slot dependency to version 1.2.2 ensures the application uses the latest bug fixes and improvements.


67-67: New UI component dependency for dialog functionality

Adding the @radix-ui/react-alert-dialog package supports the implementation of accessible dialog components, which are likely used in the new Shortcuts Editor feature mentioned in the PR objectives.

src/main/ipc/main.ts (1)

5-5: Integration of shortcuts IPC module

Adding the shortcuts IPC module import ensures that keyboard shortcut management functionality is properly integrated into the main process. This addition correctly supports the new Shortcuts Editor feature mentioned in the PR objectives by enabling communication between the renderer and main processes for shortcut operations.

src/renderer/src/components/browser-ui/sidebar/header/address-bar/address-bar.tsx (1)

63-63: Clean refactoring of AddressBarCopyLinkButton implementation.

The removal of the addressUrl prop aligns with the component's refactored implementation that now uses the centralized copyLink action from the useActions context. This approach improves maintainability by decoupling the button from direct data dependencies.

docs/references/logs.md (1)

1-7: Helpful documentation for log locations.

This documentation clearly lists the log file locations for different operating systems, which will be valuable for users and developers troubleshooting issues. The paths follow standard OS conventions.

src/renderer/src/components/omnibox/main.tsx (1)

211-211: UI styling simplification.

The background styling has been simplified to use consistent opacity values rather than dynamically changing based on the openIn prop. This reduces complexity while maintaining the visual aesthetic of the omnibox.

src/shared/flow/interfaces/browser/tabs.ts (1)

46-48: Good enhancement to Picture-in-Picture control.

Adding the goBackToTab parameter provides more flexibility in handling Picture-in-Picture mode, allowing callers to specify whether they want to return to the tab after disabling PiP. This is a user-friendly improvement that enhances the tab control experience.

src/main/browser/utility/menu/items/archive.ts (1)

4-4: Great improvement with dynamic shortcut retrieval!

The change from hardcoded accelerator strings to dynamic retrieval via getCurrentShortcut() successfully integrates the Archive menu with the new shortcuts management system. This enables runtime customization of navigation shortcuts while maintaining the same functionality.

Also applies to: 11-11, 25-25

src/main/browser/utility/menu.ts (2)

14-14: Proper adaptation to the EditMenu changes

The removal of the browser parameter from createEditMenu() call correctly aligns with the signature change in that function.

Also applies to: 23-23


36-36: Well-implemented dynamic menu updates for shortcut changes

The addition of the event listener for "shortcuts-changed" ensures the application menu is automatically rebuilt whenever shortcuts are modified. This maintains consistency between user-customized shortcuts and the displayed menu accelerators.

src/shared/flow/flow.ts (1)

21-22: Clean integration of new API interfaces

The addition of actions and shortcuts properties to the global flow API interface properly exposes the new functionality to the renderer process. This follows the established pattern and maintains consistency with the rest of the API structure.

Also applies to: 35-36

src/renderer/src/components/settings/settings-titlebar.tsx (1)

1-9: Clean and well-structured title bar component

This new SettingsTitlebar component is simple yet effective, with appropriate styling for a modern titlebar. The use of Tailwind classes and the "app-drag" class for window dragging functionality is well-implemented. The component integrates well with the new sidebar-based settings layout.

src/renderer/src/lib/utils.ts (1)

60-76: Well-implemented utility function.

The new craftActiveFaviconURL utility is well-structured, properly documented, and serves a clear purpose in the Flow Browser's favicon handling system. The approach of using query parameters to identify the tab and trigger cache invalidation is elegant.

src/renderer/src/hooks/use-debounce.tsx (1)

1-18: Clean and well-implemented debounce hook.

This implementation of useDebounce follows React best practices by properly:

  • Using generics to maintain type safety
  • Handling cleanup with the effect's return function
  • Managing dependencies correctly in the dependency array

This will be useful for optimizing performance in UI components that handle frequent state updates.

src/main/browser/utility/menu/items/file.ts (3)

5-5: Good addition for centralized shortcut management.

This import enables the dynamic shortcut resolution system described in the PR objectives.


12-12: Improved flexibility with dynamic shortcut resolution.

Replacing the hardcoded accelerator with getCurrentShortcut("tabs.new") aligns with the Shortcuts Editor feature described in the PR objectives, allowing users to customize keyboard shortcuts.


25-25: Consistent application of dynamic shortcut resolution.

This change maintains consistency with the approach used for the "New Tab" menu item, allowing user customization of the "New Window" shortcut.

src/main/ipc/browser/interface.ts (1)

2-2: Browser import needed for window management.

This import provides access to the global browser instance, which is necessary for the updated window button visibility handling.

components.json (1)

1-21: Configuration looks well-structured for the UI framework integration.

This configuration file correctly sets up shadcn/ui components with Tailwind CSS. The path aliases are properly defined to support modular imports in the project, which will help with the new UI components for the Shortcuts Editor feature.

src/main/ipc/browser/tabs.ts (1)

206-214: Good enhancement to the Picture-in-Picture functionality.

The new goBackToTab parameter allows users to control whether the tab becomes active after disabling PiP mode, aligning with the PR objective of "implementing detection for closing or returning to a tab when using picture-in-picture mode."

src/shared/flow/interfaces/app/actions.ts (1)

1-14: Well-structured interface for IPC actions.

The FlowActionsAPI interface is clearly defined with descriptive JSDoc comments. The interface properly establishes the contract for IPC event handling related to app actions, which supports the improved application functionality described in the PR objectives.

src/main/browser/utility/menu/items/view.ts (2)

7-7: Good integration with the new shortcuts system.

The import of getCurrentShortcut replaces hardcoded shortcuts, enabling the Shortcuts Editor feature mentioned in the PR objectives.


40-40: Consistently applied dynamic shortcuts across all menu items.

The replacement of hardcoded accelerators with getCurrentShortcut calls is implemented consistently across all menu items. This change enables runtime customization of keyboard shortcuts through the new Shortcuts Editor feature.

Also applies to: 52-52, 61-61, 70-70, 77-77

src/shared/types/shortcuts.ts (1)

1-7: Well-structured interface for keyboard shortcuts management

The ShortcutAction interface is well-designed with clear property names and helpful comments. The inclusion of originalShortcut is a good practice for allowing users to reset to default values.

src/renderer/src/components/settings/sections/general/reset-onboarding-card.tsx (1)

30-34: Clean UI refactoring to direct markup

The refactoring from Card components to direct HTML elements with utility classes looks good and follows the project's standardization efforts.

src/renderer/src/components/settings/sections/shortcuts/components/reset-dialog.tsx (2)

1-15: Well-structured component interface and imports

The component has a clean interface with appropriate props for handling the dialog state and confirmation action. The imports are well-organized, following best practices by importing specific components from the UI library.


17-44: LGTM! Clean implementation of the reset dialog

The implementation is concise and correctly handles state transitions. The dialog properly shows a warning about the irreversible nature of the reset action and uses appropriate UI components for the dialog structure. The button handlers are well-implemented, ensuring the dialog closes before calling the confirmation callback.

src/renderer/src/components/providers/minimal-toast-provider.tsx (1)

100-113: Good fix for toast animation when showing sequential messages

The changes address the issue mentioned in PR objectives by ensuring proper animation when transitioning between toasts. By introducing a small delay when replacing an existing toast, you allow the exit animation to complete before starting the entry animation of the new toast.

The implementation uses a smart approach:

  1. Checking if there's already a message showing
  2. Clearing it first if needed
  3. Using a small (100ms) delay to ensure smooth transitions
  4. Keeping the original functionality for the first toast
src/shared/flow/interfaces/app/shortcuts.ts (2)

1-5: Well-defined type for shortcuts data collection

The ShortcutsData type is properly defined as an array of ShortcutAction objects, creating a clear data structure for the shortcuts system.


6-27: Well-designed API interface with comprehensive methods

The FlowShortcutsAPI interface provides a complete set of methods needed for shortcuts management:

  • Getting all shortcuts
  • Setting individual shortcuts
  • Resetting shortcuts to defaults
  • Subscribing to shortcut updates

The JSDoc comments provide good documentation, and the method signatures with appropriate return types make the interface clear and type-safe.

src/renderer/src/components/browser-ui/main.tsx (3)

17-17: Good integration of the ActionsProvider

Adding the ActionsProvider import prepares for the integration of the centralized action handling system as mentioned in the PR objectives.


80-143: Well-implemented ActionsProvider integration

The ActionsProvider is correctly positioned to wrap the entire UI subtree, making its context available to all child components. This enables centralized handling of actions like copying links as mentioned in the PR objectives.


97-122: Improved loading animation with better visual transitions

The topbar loading animation has been refined by:

  1. Adjusting the height from 2.5 to 2 units
  2. Using nested motion components for better animation layering
  3. Maintaining the same functionality with improved visual appearance

This change enhances the user experience with smoother animations.

src/main/browser/utility/menu/items/edit.ts (4)

1-4: Clean import organization.

The imports have been properly updated to reflect the architectural changes. The removal of the direct clipboard dependency in favor of the IPC action system (fireCopyLinkAction) is a good move toward better separation of concerns.


6-6: Improved function signature.

Removing the browser parameter from createEditMenu helps decouple the menu creation from specific browser instances, making the code more modular and easier to maintain.


16-16: Good use of dynamic shortcut retrieval.

Using getCurrentShortcut instead of hardcoded values allows for user customization of shortcuts. This change integrates well with the new Shortcuts Editor feature.


18-22: Improved URL copy implementation.

The implementation now uses an IPC action system instead of directly accessing the clipboard. This is a better architectural approach that separates concerns and allows for centralized handling of clipboard operations.

src/main/ipc/app/shortcuts.ts (2)

6-9: Good implementation of shortcuts retrieval.

The handler correctly uses the shortcuts module to retrieve all shortcuts and returns them to the caller.


24-27: Good event listener implementation.

The event listener properly responds to internal shortcut changes and broadcasts them to all listeners. This ensures all UI components stay in sync with the latest shortcuts.

src/renderer/src/components/settings/sections/shortcuts/components/search-header.tsx (2)

5-10: Well-defined component props interface.

The props interface clearly defines the expected inputs and callbacks for the component, making it easy to understand how to use it.


26-29: Great user feedback with hover animation.

The rotating icon on hover provides excellent visual feedback to the user, enhancing the interactive experience.

src/renderer/src/components/browser-ui/sidebar/header/address-bar/copy-link-button.tsx (1)

3-3: Good refactor to use centralized actions.

The component now uses the useActions hook to access the centralized copyLink action, which aligns with the architectural goals of the PR to centralize action handling.

Also applies to: 54-55

src/renderer/src/components/settings/settings-layout.tsx (3)

2-3: Good organization of settings layout with clear section definitions

The new sidebar-based settings UI is well structured with clear icons and labels for each section. The addition of the Shortcuts section with the KeyboardIcon is consistent with the overall design pattern.

Also applies to: 13-14, 21-29


57-58: Proper integration of ShortcutsSettings component

The ShortcutsSettings component is correctly integrated into the switch statement with the appropriate section ID.


66-80: Good component hierarchy with appropriate context providers

The component hierarchy with ShortcutsProvider wrapping SettingsProvider ensures that shortcut context is available to all settings components. The layout structure with a separate sidebar and content area follows modern UI patterns.

src/renderer/src/components/settings/sections/shortcuts/components/empty-state.tsx (4)

4-7: Well-defined props interface with appropriate types

The EmptyState component has a clear and concise props interface with appropriate type definitions.


9-22: Loading state implementation with proper animation

The loading state provides good user feedback with a spinner and text. The motion animations provide a smooth transition experience.


24-39: No-results state with dynamic search term display

The no-results state appropriately handles both cases - with and without a search term - providing helpful guidance to users.


41-53: Consistent styling across all state variations

The default no-shortcuts state maintains consistent styling with the other states, creating a unified user experience. The component follows good React patterns with conditional rendering and proper motion animations.

src/renderer/src/components/settings/sections/general/set-as-default-browser-setting.tsx (3)

11-12: Variable rename improves code clarity

Renaming the variable from defaultBrowserResult to isDefaultResult makes the code more readable and consistent with the state variable name.


25-31: Enhanced UI with improved layout and styling

The refactored layout uses Flexbox effectively with appropriate spacing, hover effects, and text styling. The descriptive text helps users understand the purpose of this setting.


32-56: Improved button states with appropriate visual feedback

The component now provides clear visual differentiation between loading, not-default, and default states. The button styling is consistent and the use of icons enhances the user experience.

src/main/modules/logs.ts (3)

7-15: Platform-specific log path determination

The function correctly determines the appropriate log directory based on the platform, following OS conventions for log storage.


19-21: Ensures log directory exists before writing

Good practice to create the log directory if it doesn't exist, preventing potential file write errors.


23-28: Well-structured log filename generation

The log filename includes both version and timestamp, making it easy to identify logs from specific application sessions.

src/renderer/src/components/settings/sections/shortcuts/hooks/use-keyboard-normalizer.tsx (1)

52-63: Returning single non-modifier keys bypasses modifier filter

The branch in lines 60-62 returns normalizedKey even when it is itself a modifier alias (Space is fine, but e.g. Escape is filtered earlier).
Consider explicitly filtering‐out any residual modifiers or reserved keys to avoid accidental acceptance of pure modifier keys when users release modifiers in quick succession.

src/renderer/src/components/browser-ui/sidebar/content/sidebar-tab-groups.tsx (6)

3-3: Good use of utils import for favicon URL generation.

The import of craftActiveFaviconURL from utils is a good practice that centralizes the URL generation logic, making it reusable across components.


6-6: AnimatePresence improves UI transitions.

Adding AnimatePresence from framer-motion enables smooth exit animations for elements that are removed from the DOM, which will provide better visual feedback for users.


79-80: Good pattern for conditional icon selection.

Creating a variable to dynamically select the appropriate icon based on state is cleaner than using inline conditionals in JSX, improving readability.


113-128: Improved favicon rendering with proper fallback.

The updated favicon container implementation with proper error handling, rounded corners, and the use of craftActiveFaviconURL improves the user experience by ensuring favicons are properly displayed with cache-busting capabilities.


130-155: Well-implemented animation for audio controls.

The animation for audio controls using AnimatePresence and motion.div is well-implemented with proper spring physics and transitions. The event propagation stopping in the button's onMouseDown handler prevents unintended parent interactions.


157-160: Improved layout with better spacing.

The updated layout for the title and right-side container provides better spacing and visual consistency, which improves the overall user interface.

src/main/browser/window.ts (5)

41-41: Good addition of state tracking property.

Adding a private property to track window button visibility state is a good approach for maintaining the component's state.


77-79: Improved initialization in constructor.

Using the new setWindowButtonVisibility method in the constructor instead of directly calling native methods improves consistency and centralizes the visibility logic.


91-91: Fixed window controls in fullscreen mode.

Adding calls to _updateWindowButtonVisibility() in both fullscreen event handlers ensures window controls remain visible in fullscreen mode, fixing the issue mentioned in the PR objectives.

Also applies to: 96-96


256-264: Well-implemented window button visibility logic.

The private method centralizes the visibility logic with proper conditional checks. It ensures window buttons are always visible in fullscreen mode, addressing the issue described in the PR objectives.


266-273: Good API design for button visibility control.

The public methods provide a clean API for controlling window button visibility, making it easier to manage visibility state from other components or modules.

src/renderer/src/components/settings/sections/shortcuts/components/category-section.tsx (6)

1-5: Clean imports with proper organization.

The imports are well-organized, including only what's necessary for the component to function properly.


6-20: Well-defined props interface with clear typing.

The props interface is comprehensive and well-typed, making it clear what data and callbacks the component expects.


37-38: Good implementation of modified shortcuts detection.

The component efficiently calculates the number of modified shortcuts by comparing current values with original values, which helps provide useful feedback to users.


40-44: Smooth entry animation for improved UX.

The use of framer-motion to animate the component's entry with proper timing and delay creates a pleasant user experience.


45-52: Informative heading with modification indicator.

The category heading with a badge showing the number of modified shortcuts provides valuable information to users at a glance.


53-76: Well-structured shortcut items rendering with animations.

The component properly maps over shortcuts and renders ShortcutItem components with appropriate props, including animation delays for a staggered effect. The use of AnimatePresence ensures smooth exit animations.

src/renderer/src/components/providers/actions-provider.tsx (4)

8-20: Well-defined context interface with clear documentation.

The context interface is well-documented with JSDoc comments that explain the purpose of each method.


24-30: Good error handling in custom hook.

The custom hook properly checks for context existence and throws a helpful error message if used outside the provider.


55-58: TODO comment needs implementation.

There's a TODO comment for handling generic incoming actions that should be addressed before finalizing this feature.

Do you have plans for implementing the generic incoming actions handler mentioned in the TODO comment?


60-61: Good use of callback refs for stable references.

Using refs to maintain stable references for callbacks in event listeners is a good practice to avoid unnecessary re-subscriptions.

Also applies to: 51-52

src/renderer/src/components/settings/sections/general/basic-settings-cards.tsx (1)

100-104: Avoid using array index as React key

Using the loop index (key={index}) prevents React from reliably tracking re-ordering or insertion of cards at runtime, which can cause incorrect DOM mutations and state leakage between cards.

If card has a stable identifier (card.id or card.title), prefer that:

-      {cards.map((card, index) => (
-        <BasicSettingsCard key={index} card={card} />
+      {cards.map((card) => (
+        <BasicSettingsCard key={card.title} card={card} />
       ))}

[ suggest_optional_refactor ]

src/renderer/src/components/settings/sections/shortcuts/shortcut-item.tsx (2)

82-110: Icon buttons need accessible labels

The three ghost buttons rely solely on iconography. Screen-reader users will not detect their purpose because title is not consistently announced by all assistive tech.

Supply aria-label or aria-describedby attributes:

-<Button … title="Save">
+<Button … aria-label="Save shortcut" title="Save">-<Button … title="Cancel Edit">
+<Button … aria-label="Cancel editing" title="Cancel Edit">-<Button … title="Reset to Default">
+<Button … aria-label="Reset shortcut to default" title="Reset to Default">

This small addition markedly improves accessibility compliance.
[ suggest_nitpick ]


114-125: Guard against empty shortcuts in display

formatShortcutForDisplay(shortcut.shortcut) may return an empty string for unassigned shortcuts, producing a visually empty badge.
You already style the “unassigned” case in editing mode; mirror that here for consistency:

-{formatShortcutForDisplay(shortcut.shortcut)}
+{formatShortcutForDisplay(shortcut.shortcut) || "—"}

Optionally add a dedicated style (e.g., italic text-muted-foreground) to align with the placeholder used during recording.
[ suggest_nitpick ]

src/main/modules/shortcuts.ts (1)

81-88: newShortcut is un-typed – tighten the contract with a dedicated interface

modifiedShortcutData?.newShortcut is accessed blindly. If getAllModifiedShortcuts() ever returns a record without that field (or with a typo), the merge silently falls back to the default shortcut and the bug is hard to track.

Create a small interface for the persisted shape so TypeScript can help:

 // saving/shortcuts.ts
 export interface ModifiedShortcut {
   newShortcut: string;
 }

 // shortcuts.ts
 const modifiedShortcutsData = getAllModifiedShortcuts() as Array<
-  { id: string } & { newShortcut: string }
+  { id: ShortcutId } & ModifiedShortcut
 >;

Type-safety now guarantees newShortcut exists and is a string.

src/renderer/src/components/settings/sections/external-apps/section.tsx (1)

2-2: motion/react import path may be wrong

Most projects use framer-motion (import { motion, AnimatePresence } from "framer-motion").
motion/react belongs to Motion-One; unless you deliberately migrated, this will cause a bundler error.

-import { motion, AnimatePresence } from "motion/react";
+import { motion, AnimatePresence } from "framer-motion";
src/renderer/src/components/ui/alert-dialog.tsx (2)

32-46: Note the coupling of Content, Portal, and Overlay components

The AlertDialogContent component includes both the AlertDialogPortal and AlertDialogOverlay components, which means they're tightly coupled. This is a design choice that's worth noting.

This design means that every time AlertDialogContent is used, a new portal and overlay are created. While this simplifies usage, it's important to verify this is the intended behavior across the application.

Consider documenting this relationship in a comment to make it clear to other developers:

 function AlertDialogContent({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
+  // AlertDialogContent automatically includes Portal and Overlay components
   return (
     <AlertDialogPortal>
       <AlertDialogOverlay />

91-97: Consider handling missing buttonVariants

The AlertDialogAction and AlertDialogCancel components rely on the buttonVariants utility, but there's no error handling if the utility is unavailable or changed.

The implementation is clean and properly uses the button variants. The code correctly styles action buttons as primary and cancel buttons as outline variant.

Copy link
Contributor

@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: 1

🧹 Nitpick comments (3)
src/renderer/src/components/providers/shortcuts-provider.tsx (3)

32-41: Consider enhancing the shortcut formatting function

The formatting function handles some common keys, but could be more comprehensive to support all possible keyboard keys that might be used in shortcuts.

const formatShortcutForDisplay = useCallback((shortcut: string | null): string => {
  if (!shortcut) return "None";
  return shortcut
    .replace(/\+/g, " + ")
    .replace("CommandOrControl", "⌘/Ctrl")
    .replace("ArrowUp", "↑")
    .replace("ArrowDown", "↓")
    .replace("ArrowLeft", "←")
    .replace("ArrowRight", "→")
+   .replace("Alt", "⌥/Alt")
+   .replace("Shift", "⇧/Shift")
+   .replace("Escape", "Esc")
+   .replace("Delete", "Del")
+   .replace("Backspace", "⌫")
+   .replace("Enter", "↵")
+   .replace("Tab", "⇥");
}, []);

98-109: Optimize loading state management in resetAllShortcuts

The function sets isLoading to true but then calls fetchShortcuts which also sets isLoading to true, potentially causing unnecessary state updates.

const resetAllShortcuts = useCallback(async (): Promise<void> => {
  setIsLoading(true);
  try {
    const resetPromises = shortcuts.map((shortcut) => flow.shortcuts.resetShortcut(shortcut.id));
    await Promise.all(resetPromises);
-   fetchShortcuts();
+   // Directly fetch shortcuts without setting isLoading again
+   try {
+     const fetchedShortcuts = await flow.shortcuts.getShortcuts();
+     setShortcuts(fetchedShortcuts);
+   } catch (error) {
+     console.error("Failed to fetch shortcuts:", error);
+   }
  } catch (error) {
    console.error("Failed to reset all shortcuts:", error);
  } finally {
    setIsLoading(false);
  }
}, [shortcuts, fetchShortcuts]);

66-80: Consider adding user feedback for errors

The error handling in async functions only logs to the console but doesn't provide user feedback.

Consider integrating with a toast notification system to inform users when shortcuts cannot be set or reset.

// Example integration with a toast notification system
const setShortcut = useCallback(
  async (actionId: string, shortcut: string): Promise<boolean> => {
    try {
      const success = await flow.shortcuts.setShortcut(actionId, shortcut);
      if (success) {
        fetchShortcuts(); // Refresh shortcut data
      }
      return success;
    } catch (error) {
      console.error("Error setting shortcut:", error);
      // Add user notification
      // toast.error("Failed to set shortcut. Please try again.");
      return false;
    }
  },
  [fetchShortcuts]
);

Also applies to: 82-96

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f98a51d and 598e011.

📒 Files selected for processing (8)
  • src/main/settings/main.ts (1 hunks)
  • src/renderer/src/components/providers/shortcuts-provider.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/components/category-section.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/components/modified-shortcuts-section.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/hooks/use-keyboard-normalizer.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/section.tsx (1 hunks)
  • src/renderer/src/components/settings/sections/shortcuts/shortcut-item.tsx (1 hunks)
  • src/shared/flow/interfaces/app/shortcuts.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/renderer/src/components/settings/sections/shortcuts/components/modified-shortcuts-section.tsx
  • src/shared/flow/interfaces/app/shortcuts.ts
  • src/renderer/src/components/settings/sections/shortcuts/section.tsx
  • src/renderer/src/components/settings/sections/shortcuts/hooks/use-keyboard-normalizer.tsx
  • src/renderer/src/components/settings/sections/shortcuts/components/category-section.tsx
  • src/renderer/src/components/settings/sections/shortcuts/shortcut-item.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/renderer/src/components/providers/shortcuts-provider.tsx (1)
src/shared/types/shortcuts.ts (1)
  • ShortcutAction (1-7)
🔇 Additional comments (5)
src/renderer/src/components/providers/shortcuts-provider.tsx (5)

1-13: Well-structured shortcuts context and value interface

The interfaces and context setup follow React best practices, providing a clear contract for the shortcut management system.


15-21: Good implementation of context hook with error boundary

The custom hook implementation correctly ensures the context is used within a provider and provides a helpful error message.


43-53: Good implementation of data fetching with proper loading state management

The fetchShortcuts function correctly manages loading state and includes robust error handling.


55-64: Well-implemented effect hook with proper cleanup

The useEffect hook correctly fetches data on mount and sets up a subscription with proper cleanup.


111-125: Well-structured context provider implementation

The provider correctly passes all necessary functions and state to children components.

@iamEvanYT iamEvanYT merged commit 4358584 into main May 13, 2025
1 check passed
@iamEvanYT iamEvanYT deleted the evan/keybind-editor branch May 13, 2025 11:06
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