Skip to content

Redesign#2

Merged
iamEvanYT merged 32 commits intomainfrom
evan/redesign
Mar 21, 2025
Merged

Redesign#2
iamEvanYT merged 32 commits intomainfrom
evan/redesign

Conversation

@iamEvanYT
Copy link
Member

@iamEvanYT iamEvanYT commented Mar 21, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a new omnibox interface for enhanced search suggestions and streamlined navigation.
    • Revamped the browser interface with interactive tabs, dynamic sidebars, and improved window controls.
    • Added new components for improved UI interactions, including buttons, dialogs, tooltips, and dropdown menus.
    • Implemented a responsive sidebar with customizable behaviors and persistent state management.
    • Enhanced IPC capabilities for improved communication between main and renderer processes.
  • Refactor & Style

    • Refined window management with smoother sizing, transparency, and vibrancy adjustments.
    • Updated overall styling, including dark mode enhancements and responsive layouts for a more polished user experience.
    • Simplified the application structure by adopting a component-based architecture for better state management.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 21, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This pull request refactors and extends both Electron and Vite components. In Electron, IPC communication is enhanced, with new handlers for window button positioning, tab navigation, and omnibox integration. A new Omnibox class is introduced along with updates to window management logic and path handling via a new constant. In Vite, numerous new React components, hooks, and utility functions are added to build a richer browser UI—including omnibox pages, enhanced sidebar functionality, and improved routing—along with updates to dependencies and build configurations.

Changes

File(s) Change Summary
electron/browser/main.ts, electron/browser/menu.ts, electron/index.ts, electron/modules/flags.ts, electron/preload.ts Enhanced IPC handling with new methods (set-window-button-position, set-window-button-visibility), introduced WEBPACK_ROOT_DIR for preload path management, refined window/tab behaviors, and updated flag configurations.
electron/browser/omnibox.ts, electron/browser/tabs.ts Introduced the Omnibox class with associated IPC handlers for showing/hiding the omnibox, plus new types and event listeners for dynamic tab bounds management.
electron/webpack.renderer.config.js Added a new ts-loader rule to process TypeScript files in the Electron renderer bundle.
vite/package.json Added new dependencies (@radix-ui packages, cmdk, react-resizable-panels) and updated lucide-react version.
vite/src/components/** (browser-ui, omnibox, sidebar, ui, old-ui) Introduced a wide range of new React components including BrowserContent, BrowserSidebar, Omnibox, BrowserUI, Button, Command, Dialog, DropdownMenu, Input, Resizable Sidebar, Separator, Skeleton, Tooltip, and others to enhance the user interface and navigation.
vite/src/hooks/use-mobile.ts, vite/src/hooks/use-sidebar-resize.tsx Added custom React hooks for detecting mobile viewports and managing sidebar resize events with drag interactions and cookie persistence.
vite/src/lib/** (flow.ts, merge-button-refs.ts, omnibox.ts, search.ts, url.ts) Added utility functions and type definitions for a Flow API, merged ref support, omnibox text processing, search URL and suggestion fetching, and improved URL parsing/simplification.
vite/src/routes/** (main page, new/index.html, omnibox/index.html, omnibox/index.tsx, omnibox/page.tsx) Refactored the main browser app to use a component-based architecture with BrowserProvider, and introduced new entry points and routing pages for the omnibox feature.
vite/src/index.css Updated background-color properties to transparent and added the .remove-app-drag class to control draggable regions.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Menu
    participant MainProcess
    participant Omnibox
    participant UI

    User->>Menu: Click "New Tab" (omnibox mode)
    Menu->>MainProcess: Send IPC event for omnibox tab creation
    MainProcess->>Omnibox: Conditionally create Omnibox instance
    Omnibox->>MainProcess: Load interface & inject dynamic CSS
    MainProcess->>UI: Update window to display omnibox
    UI-->>User: Render omnibox input and suggestions
    User->>UI: Enter query
    UI->>Omnibox: Process input (debounced) for suggestions
    Omnibox->>UI: Return sorted/culled match results
Loading

Possibly related PRs

  • Custom Page Load Error #1: Involved similar updates with protocol requests and export modifications in electron/browser/main.ts, aligning closely with the IPC and window management enhancements introduced here.

Poem

Hop, hop, in lines of code I roam,
New paths and IPC calls light my digital home.
Omnibox blooms like a field of carrots bright,
With refined tabs and UI shining in the night.
I twitch my nose at changes sleek and new—
A bunny’s joy in every commit I pursue!
🥕🐇 Happy coding, from a rabbit true!


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4017ee6 and ad6dca0.

⛔ Files ignored due to path filters (2)
  • assets/screenshots/beta-1.png is excluded by !**/*.png
  • assets/screenshots/beta-2.png is excluded by !**/*.png
📒 Files selected for processing (1)
  • README.md (2 hunks)

🪧 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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 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.

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: 8

🧹 Nitpick comments (49)
vite/src/routes/omnibox/index.tsx (1)

1-13: Well-structured React entry point for the Omnibox feature.

The file follows standard React patterns by using StrictMode and a ThemeProvider wrapper for the main App component.

Consider adding a null check before accessing the root element:

-createRoot(document.getElementById("root")!).render(
+const rootElement = document.getElementById("root");
+if (!rootElement) {
+  throw new Error("Root element not found");
+}
+createRoot(rootElement).render(

This would provide a more explicit error message if the root element is missing.

vite/src/routes/omnibox/index.html (1)

1-12: Clean HTML structure for the Omnibox feature.

The HTML file correctly sets up the document structure with appropriate meta tags and creates a mounting point for the React application.

Consider adding the "dark" class to the body element for consistency with the new tab page:

-  <body>
+  <body class="dark">

This would ensure a consistent theme across different parts of the application.

electron/webpack.renderer.config.js (1)

3-16: TypeScript configuration looks good, but consider type checking implications.

The added TypeScript configuration uses transpileOnly: true, which improves build speed but skips type checking during compilation. This is a valid approach, especially if type checking is performed elsewhere in your workflow (like in your IDE or a separate CI process).

If you don't have a separate type checking step in your build process, you might want to consider these alternatives:

- options: {
-   transpileOnly: true
- }
+ options: {
+   // Option 1: Enable type checking in Webpack
+   transpileOnly: false
+ }

Or alternatively, add a separate type checking script in package.json:

"scripts": {
  "typecheck": "tsc --noEmit",
  // other scripts...
}
vite/src/routes/omnibox/page.tsx (1)

1-16: Clean and well-structured component hierarchy.

The component structure follows good React patterns with clear separation of concerns. The OmniboxApp handles rendering the Omnibox while the App component provides the necessary context via BrowserProvider.

Consider adding a brief JSDoc comment to describe the purpose of each component for better documentation:

+/**
+ * Renders the Omnibox component without context
+ */
function OmniboxApp() {
  return <Omnibox />;
}

+/**
+ * Main Omnibox page component that provides browser context
+ */
function App() {
  return (
    <BrowserProvider>
      <OmniboxApp />
    </BrowserProvider>
  );
}
vite/src/components/ui/skeleton.tsx (1)

1-13: Well-implemented Skeleton component with flexible styling options.

The component follows best practices by:

  1. Accepting all standard div props
  2. Using a utility for class name composition
  3. Providing sensible default styles while allowing customization
  4. Using data-slot for targeting in CSS or testing

Consider adding a brief JSDoc comment to document the component's purpose and usage:

import { cn } from "@/lib/utils"

+/**
+ * Skeleton component for displaying loading states
+ * 
+ * @example
+ * <Skeleton className="h-10 w-full" />
+ */
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="skeleton"
      className={cn("bg-accent animate-pulse rounded-md", className)}
      {...props}
    />
  )
}

export { Skeleton }
vite/src/components/ui/input.tsx (1)

10-15: Consider extracting the long className string for better readability

The className chain is quite lengthy which might make it difficult to maintain. Consider extracting these styles into constants or using a design system pattern to organize them better.

+ const baseStyles = "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm"
+ const focusStyles = "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
+ const invalidStyles = "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"

  className={cn(
-   "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
-   "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
-   "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
+   baseStyles,
+   focusStyles,
+   invalidStyles,
    className
  )}
vite/src/components/browser-ui/sidebar/address-bar.tsx (2)

8-46: Rename FakeAddressBar to a more descriptive name

The component name "FakeAddressBar" implies it's not a real address bar, which might be confusing. Consider a more descriptive name like "SidebarAddressInput" or "ClickableAddressBar" to better indicate its purpose.

-function FakeAddressBar() {
+function SidebarAddressInput() {
  const { addressUrl } = useBrowser();
  const { open } = useSidebar();
  
  // Rest of component code...
}

export function SidebarAddressBar() {
  return (
    <SidebarGroup className="pt-0">
-      <FakeAddressBar />
+      <SidebarAddressInput />
    </SidebarGroup>
  );
}

20-31: Consider using constants for omnibox dimensions

The hardcoded multipliers (2x width, 8x height) seem arbitrary and could lead to inconsistent UI across different screen sizes. Consider using named constants or a more responsive approach.

+const OMNIBOX_WIDTH_MULTIPLIER = 2;
+const OMNIBOX_HEIGHT_MULTIPLIER = 8;
+
 function FakeAddressBar() {
   // ...existing code...
   
   showOmnibox(
     {
       x: inputBoxBounds.x,
       y: inputBoxBounds.y,
-      width: inputBoxBounds.width * 2,
-      height: inputBoxBounds.height * 8
+      width: inputBoxBounds.width * OMNIBOX_WIDTH_MULTIPLIER,
+      height: inputBoxBounds.height * OMNIBOX_HEIGHT_MULTIPLIER
     },
     {
       currentInput: addressUrl,
       openIn: "current"
     }
   );
vite/src/components/old-ui/tab-list.tsx (2)

18-22: Remove console.log statement before deployment

Debug logging statements should be removed from production code to avoid cluttering the console and potentially exposing sensitive information.

-  // Log for debugging
-  console.log("TabList render:", {
-    tabsCount: tabs.length,
-    tabIds: tabs.map((t) => t.id),
-    activeTabs: tabs.filter((t) => t.active).map((t) => t.id)
-  });

35-47: Good improvement to filter tabs by window

This change properly filters tabs that don't belong to the current window, improving the user experience. For better performance, consider filtering the tabs array before mapping.

  const { currentWindow } = useBrowser();
+
+  // Filter tabs that belong to the current window
+  const windowTabs = currentWindow?.id 
+    ? tabs.filter(tab => tab.windowId === currentWindow.id)
+    : [];

  return (
    <div className="w-full h-8 min-h-[calc(env(titlebar-area-height)+1px)]">
      <div className="fixed left-[env(titlebar-area-x)] top-[env(titlebar-area-y)] w-[env(titlebar-area-width)] h-8 min-h-[calc(env(titlebar-area-height)+1px)] flex flex-row">
        {/* Tab List */}
        <ul ref={tabListRef} className="h-full flex flex-row min-w-0 overflow-x-none">
          <AnimatePresence initial={false}>
-            {tabs.map((tab) => {
-              // If tab is not in this window, don't render it
-              if (tab.windowId !== currentWindow?.id) {
-                return null;
-              }
+            {windowTabs.map((tab) => {
              return (
                <Tab
                  key={`tab-${tab.id}`}
                  // ...rest of props
                />
              );
            })}
          </AnimatePresence>
        </ul>
vite/src/index.css (2)

12-13: Consider revisiting the use of !important for background-color

While making the background transparent makes sense for an Electron application, using !important might lead to style specificity issues in the future. Consider whether this can be achieved through more specific selectors or restructuring the CSS hierarchy.


142-144: Consider consolidating duplicate transparent background declarations

This declaration duplicates the same property already set on :root at line 13. Consider consolidating these styles to improve maintainability:

:root {
  /* ... */
  background-color: transparent !important;
  /* ... */
}

-body {
-  background-color: transparent !important;
-}

Alternatively, if both are intentionally needed, add a comment explaining why.

vite/src/components/browser-ui/sidebar/navigation-buttons.tsx (1)

40-44: Consider adding a more descriptive comment for dropdown open logic

While there is a comment explaining the dropdown open behavior, it could be more descriptive about why this approach was chosen:

// Keep auto-deselect, but disable the dropdown menu from being open as we have our own custom logic for opening it
+// We only want the dropdown to open on right-click (context menu), not on regular click
if (open === true) return;
setOpen(open);
vite/src/components/browser-ui/main.tsx (2)

17-19: Consider making sidebar configuration options dynamic.

You're initializing state variables for collapseMode, variant, and side with useState, but there doesn't appear to be any functionality to change these values. If these settings are intended to be configurable, consider adding UI controls or loading preferences from storage.


38-55: Optimize loading indicator rendering.

The motion.div animation runs continuously even when it's not visible. Consider conditionally rendering the entire motion element instead of just its container to save resources:

- {isActiveTabLoading && (
-   <div className="w-28 h-1 bg-gray-200/30 dark:bg-white/10 rounded-full overflow-hidden">
-     <motion.div
-       className="h-full bg-gray-800/90 dark:bg-white/90 rounded-full"
-       initial={{ x: "-100%" }}
-       animate={{ x: "100%" }}
-       transition={{
-         duration: 1,
-         ease: "easeInOut",
-         repeat: Infinity,
-         repeatType: "loop",
-         repeatDelay: 0.1
-       }}
-     />
-   </div>
- )}
+ {isActiveTabLoading && (
+   <div className="w-28 h-1 bg-gray-200/30 dark:bg-white/10 rounded-full overflow-hidden">
+     <motion.div
+       className="h-full bg-gray-800/90 dark:bg-white/90 rounded-full"
+       initial={{ x: "-100%" }}
+       animate={{ x: "100%" }}
+       transition={{
+         duration: 1,
+         ease: "easeInOut",
+         repeat: Infinity,
+         repeatType: "loop",
+         repeatDelay: 0.1
+       }}
+     />
+   </div>
+ )}
vite/src/components/browser-ui/browser-sidebar.tsx (3)

6-7: Combine duplicate imports.

The imports from @/lib/flow are duplicated on lines 6 and 7. These can be combined into a single import statement for better code organization.

- import { setWindowButtonPosition } from "@/lib/flow";
- import { setWindowButtonVisibility } from "@/lib/flow";
+ import { setWindowButtonPosition, setWindowButtonVisibility } from "@/lib/flow";

22-35: Improve effect dependency to handle titlebar reference availability.

The useEffect for updating window button position only runs when variant changes, but it depends on titlebarRef.current which might not be available immediately. Consider adding the open state to the dependency array to ensure the effect runs when the sidebar is opened.

  useEffect(() => {
    const titlebar = titlebarRef.current;
    if (titlebar) {
      const titlebarBounds = titlebar.getBoundingClientRect();
      setWindowButtonPosition({
        x: titlebarBounds.x,
        y: titlebarBounds.y
      });
    }
-  }, [variant]);
+  }, [variant, open]);

46-49: Consider adding a fallback for CSS environment variables.

The calculation for titlebar height uses CSS environment variables that might not be available in all environments. Consider adding fallback values to ensure the layout works everywhere.

- className="h-[calc(env(titlebar-area-y)+env(titlebar-area-height)+1px-1.5rem)] w-full app-drag"
+ className="h-[calc(env(titlebar-area-y, 0px)+env(titlebar-area-height, 28px)+1px-1.5rem)] w-full app-drag"
vite/src/components/browser-ui/sidebar/tabs.tsx (1)

47-57: Optimize the tabs array mapping and reversing.

The current implementation recreates the reversed array on every render, which can be inefficient for large numbers of tabs. Consider using useMemo to optimize this operation:

export function SidebarTabs() {
  const { tabs } = useBrowser();
+  
+  const reversedTabs = useMemo(() => [...tabs].reverse(), [tabs]);

  return (
    <SidebarGroup>
      <SidebarGroupLabel className="select-none">Tabs</SidebarGroupLabel>
      <SidebarMenu>
        <NewTabButton />
-        {tabs.map((tab) => <SidebarTab key={tab.id} tab={tab} />).reverse()}
+        {reversedTabs.map((tab) => <SidebarTab key={tab.id} tab={tab} />)}
      </SidebarMenu>
    </SidebarGroup>
  );
}

Don't forget to add the import:

import { useMemo } from "react";
vite/src/components/browser-ui/sidebar/tab.tsx (1)

36-40: Double-check event propagation.
e.preventDefault() stops the default action for the event, but if you also need to halt any parent click handlers, consider calling e.stopPropagation().

vite/src/components/browser-ui/sidebar/action-buttons.tsx (2)

37-48: Ensure error handling for status retrieval.
When the promise from getTabNavigationStatus(tabId) fails or returns invalid data, it gracefully exits. If partial data is returned, you may need more robust error handling or logs for debugging.


56-59: Await or handle stopLoadingTab response.
stopLoadingTab returns a promise that is neither awaited nor wrapped in error handling. Consider handling or logging the result to detect potential failures.

- stopLoadingTab(activeTab.id);
+ stopLoadingTab(activeTab.id)
+   .catch((err) => {
+     console.error("Failed to stop loading tab:", err);
+   });
vite/package.json (1)

21-22: Consider using semver for the cmdk dependency

While the other dependencies use semver ranges (^), the cmdk dependency is pinned to an exact version. This might cause issues if you need to apply security patches without manually updating the version.

-    "cmdk": "1.0.0",
+    "cmdk": "^1.0.0",
vite/src/components/omnibox/main.tsx (3)

34-44: Consider using async/await for getCurrentTab

The Promise-based approach works but could be more readable with async/await.

-function getCurrentTab(): Promise<chrome.tabs.Tab | null> {
-  return new Promise((resolve) => {
-    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
-      if (tabs[0]) {
-        resolve(tabs[0]);
-      } else {
-        resolve(null);
-      }
-    });
-  });
-}
+async function getCurrentTab(): Promise<chrome.tabs.Tab | null> {
+  const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
+  return tabs[0] || null;
+}

136-148: Simplify switch statement by removing redundant cases

The switch statement has several cases that fall through to the default case, which could be simplified.

  const getMatchIcon = (match: OmniboxMatch) => {
    switch (match.type) {
      case "search":
        return <SearchIcon className="h-5 w-5 text-black/80 dark:text-white/80" />;
-      case "history":
-      case "bookmark":
-      case "verbatim":
-      case "navigation":
-      case "tab":
      default:
        return <GlobeIcon className="h-5 w-5 text-black/80 dark:text-white/80" />;
    }
  };
🧰 Tools
🪛 Biome (1.9.4)

[error] 140-140: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 141-141: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 142-142: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 143-143: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 144-144: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


150-164: Simplify action text switch statement

Similar to the icon switch, this could be simplified by removing redundant cases.

  const getMatchAction = (match: OmniboxMatch) => {
    switch (match.type) {
      case "search":
        return "Search";
      case "tab":
        return "Switch to Tab";
-      case "history":
-      case "bookmark":
-      case "verbatim":
-      case "navigation":
      default:
        return "Navigate";
    }
  };
🧰 Tools
🪛 Biome (1.9.4)

[error] 157-157: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 158-158: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 159-159: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 160-160: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)

vite/src/components/ui/tooltip.tsx (2)

21-29: Automatic provider usage within Tooltip.
Wrapping TooltipPrimitive.Root in the TooltipProvider ensures the tooltip has a provider context. This is acceptable, though if you ever create many tooltips at once, you might consider having a single provider at a higher level to avoid multiple nested providers.


37-59: Consider adding or verifying accessibility features.
While Radix handles most aria attributes, confirm your custom classes and structure do not disrupt keyboard accessibility or screen reader announcements.

vite/src/components/main/browser-context.tsx (1)

279-295: Window state management.
Minimizing, maximizing, and closing the window is handled seamlessly with Chrome’s API calls, but consider providing user feedback or confirming if data is unsaved before closing.

vite/src/lib/url.ts (2)

12-62: Robust URL parsing with a clear fallback strategy.

  1. Returning null for empty or invalid input is a clear approach, but ensure all callers handle null defensively.
  2. The domain pattern regex is helpful, though heavily reliant on TLD-based validation. If you need to handle advanced domain formats or punycode, consider adding more flexible checks.
-  const urlRegex = /^([-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&//=]*))$/;
+  // Could consider expansions or punycode if you plan to handle internationalized domains

120-142: Neat utility for simplifying URLs.

  1. Removing “www.” is a common approach to presenting cleaner hostnames.
  2. Consider additional logic for other subdomains or advanced use cases if needed.
  3. Good fallback to the original string when parsing fails.
electron/browser/tabs.ts (1)

260-271: IPC handler for updating page bounds.

  1. Properly updates global windowsBounds and emits a targeted event for the impacted window only.
  2. Consider verifying that bounds are valid (e.g., >= 0 sizes) to avoid unexpected geometry.
+ if (bounds.width <= 0 || bounds.height <= 0) {
+   console.warn("Received invalid bounds", bounds);
+   return;
+ }
vite/src/components/ui/command.tsx (2)

21-43: Potential ARIA improvements for accessibility.
CommandDialog uses a title and description, which is excellent for screen readers. However, if you anticipate custom or advanced accessibility needs (e.g., dynamic updates inside the dialog), further ARIA attributes might be beneficial. Consider verifying correctness with a screen reader test.


45-59: Verify icon usage for accessibility.
SearchIcon is visually decorative, but it might be worth setting an aria-hidden="true" attribute or providing an accessible label if needed for assistive technologies.

vite/src/components/ui/dialog.tsx (1)

27-31: Clarify usage of DialogClose.
While DialogClose is convenient, some apps may need custom close logic (e.g., prompting "Are you sure?" on unsaved changes). Ensure your usage meets your UX requirements.

electron/preload.ts (1)

16-53: Ensure consistent return types from exposed methods.
The getTabNavigationStatus method uses ipcRenderer.invoke (returns a promise), while others use send. Ensure consumers of flow.interface don’t expect a promise where none is returned, and handle promise-based vs. non-promise-based calls accordingly.

electron/browser/main.ts (1)

114-124: Short-Lived Tab Hack
Creating and destroying a tab is a practical workaround to ensure electron-chrome-extensions detects a new window. Consider introducing a slightly longer or configurable delay to reduce race conditions if the user interacts with the blank tab.

electron/browser/omnibox.ts (1)

101-120: show Method & Keep-On-Top Logic
Periodically re-adding the omnibox view ensures it remains on top. You might reduce the interval or cancel it more aggressively to improve performance.

vite/src/lib/flow.ts (1)

27-71: Consider error handling on asynchronous methods.
Your interface methods like getTabNavigationStatus are returning promises, but the interface doesn't specify how errors are handled or propagated. Consider defining structured error handling or signaling for these methods to ensure consistent handling of potential failures (e.g., invalid tab IDs, internal IPC errors, etc.).

vite/src/lib/omnibox.ts (2)

66-79: Clarify behavior of parseInput.
When parseInput returns OmniboxInputType.UNKNOWN, downstream logic might treat it as either a URL or a query. Ensure calling code handles this condition consistently.


200-241: Handle concurrency and partial results gracefully.
handleOmniboxInput asynchronously fetches search suggestions. If user input changes rapidly or multiple requests are triggered, consider aborting prior requests or checking whether the input changed before updating suggestions to avoid race conditions and stale UI states.

vite/src/components/ui/sidebar.tsx (4)

84-95: Provide discoverability for the keyboard shortcut.
Users might not know about the Ctrl/Cmd + B toggle. Consider providing a small tooltip, an in-app message, or documentation in the UI, improving discoverability of this shortcut.


136-233: Extract large component logic for maintainability.
The Sidebar component handles resizing, mobile vs. desktop logic, floating vs. inset styles, and more. Consider splitting it into smaller components or hooks to reduce complexity and enhance maintainability.


442-463: Centralize theming and variant definitions.
You use cva to define multiple variant states and sizes. Make sure these align with your global design tokens to maintain consistency across the app. Also ensure your variant definitions remain DRY by referencing any shared spacing or color tokens in a single location.


464-507: Review tooltip logic on collapsed state.
While the tooltip is hidden if state !== "collapsed", consider using media queries or user preference for showing tooltips in more states, especially for accessibility. You might allow an advanced option that shows tooltips even when expanded.

Would you like me to open an issue to track making tooltips accessible in all sidebar states?

vite/src/components/ui/resizable-sidebar.tsx (4)

57-95: Consider loading sidebar state from the cookie.
You set a cookie with sidebar_state but never read it upon mounting. If your goal is to preserve the user's preference across page reloads, consider parsing and initializing the open state from the cookie as well, or switch to localStorage if that better meets your requirements.


172-221: Mobile fallback design.
The usage of a Sheet component for the mobile variant and a simple <div> for the desktop variant is a neat approach. Make sure to confirm that both experiences are tested thoroughly, particularly focus trapping or gestures on mobile devices.


293-296: Ref handling can be improved with forwardRef.
Because you're directly passing ref as a prop, it might be more idiomatic to convert SidebarRail to a forwardRef component. That ensures the TypeScript types for refs are enforced seamlessly and avoids potential shadowing of the standard ref prop.

- function SidebarRail({
-   className,
-   enableDrag = true,
-   ref,
-   ...props
- }: React.ComponentProps<"button"> & { enableDrag?: boolean }) {
+ const SidebarRail = React.forwardRef<
+   HTMLButtonElement,
+   React.ComponentProps<"button"> & { enableDrag?: boolean }
+ >(({
+   className,
+   enableDrag = true,
+   ...props
+ }, forwardedRef) => {
    // ...
    const combinedRef = React.useMemo(
-     () => mergeButtonRefs([ref, dragRef]),
-     [ref, dragRef]
+     () => mergeButtonRefs([forwardedRef, dragRef]),
+     [forwardedRef, dragRef]
    );
    // ...
  }
);

325-325: Remove commented-out toggle logic if not needed.
There's a leftover commented-out line // onClick={toggleSidebar}. Consider removing it to keep the codebase clean and ensure clarity for future maintainers.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5edd3f8 and fdbff52.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (44)
  • electron/browser/main.ts (11 hunks)
  • electron/browser/menu.ts (3 hunks)
  • electron/browser/omnibox.ts (1 hunks)
  • electron/browser/tabs.ts (6 hunks)
  • electron/index.ts (2 hunks)
  • electron/modules/flags.ts (2 hunks)
  • electron/preload.ts (1 hunks)
  • electron/webpack.renderer.config.js (1 hunks)
  • vite/package.json (1 hunks)
  • vite/src/components/browser-ui/browser-content.tsx (1 hunks)
  • vite/src/components/browser-ui/browser-sidebar.tsx (1 hunks)
  • vite/src/components/browser-ui/main.tsx (1 hunks)
  • vite/src/components/browser-ui/sidebar/action-buttons.tsx (1 hunks)
  • vite/src/components/browser-ui/sidebar/address-bar.tsx (1 hunks)
  • vite/src/components/browser-ui/sidebar/navigation-buttons.tsx (1 hunks)
  • vite/src/components/browser-ui/sidebar/tab.tsx (1 hunks)
  • vite/src/components/browser-ui/sidebar/tabs.tsx (1 hunks)
  • vite/src/components/main/browser-context.tsx (1 hunks)
  • vite/src/components/old-ui/tab-list.tsx (2 hunks)
  • vite/src/components/omnibox/main.tsx (1 hunks)
  • vite/src/components/ui/button.tsx (1 hunks)
  • vite/src/components/ui/command.tsx (1 hunks)
  • vite/src/components/ui/dialog.tsx (1 hunks)
  • vite/src/components/ui/dropdown-menu.tsx (1 hunks)
  • vite/src/components/ui/input.tsx (1 hunks)
  • vite/src/components/ui/resizable-sidebar.tsx (1 hunks)
  • vite/src/components/ui/separator.tsx (1 hunks)
  • vite/src/components/ui/sheet.tsx (1 hunks)
  • vite/src/components/ui/sidebar.tsx (1 hunks)
  • vite/src/components/ui/skeleton.tsx (1 hunks)
  • vite/src/components/ui/tooltip.tsx (1 hunks)
  • vite/src/hooks/use-mobile.ts (1 hunks)
  • vite/src/hooks/use-sidebar-resize.tsx (1 hunks)
  • vite/src/index.css (3 hunks)
  • vite/src/lib/flow.ts (1 hunks)
  • vite/src/lib/merge-button-refs.ts (1 hunks)
  • vite/src/lib/omnibox.ts (1 hunks)
  • vite/src/lib/search.ts (1 hunks)
  • vite/src/lib/url.ts (3 hunks)
  • vite/src/routes/main/page.tsx (1 hunks)
  • vite/src/routes/new/index.html (1 hunks)
  • vite/src/routes/omnibox/index.html (1 hunks)
  • vite/src/routes/omnibox/index.tsx (1 hunks)
  • vite/src/routes/omnibox/page.tsx (1 hunks)
🧰 Additional context used
🧬 Code Definitions (18)
vite/src/components/browser-ui/sidebar/navigation-buttons.tsx (3)
vite/src/components/browser-ui/sidebar/action-buttons.tsx (2) (2)
  • NavigationEntryWithIndex (9-9)
  • SidebarActionButton (11-24)
vite/src/components/ui/dropdown-menu.tsx (4) (4)
  • DropdownMenu (240-240)
  • DropdownMenuTrigger (242-242)
  • DropdownMenuContent (243-243)
  • DropdownMenuItem (246-246)
vite/src/lib/flow.ts (1) (1)
  • goToNavigationEntry (117-119)
vite/src/components/browser-ui/sidebar/address-bar.tsx (3)
vite/src/components/main/browser-context.tsx (1) (1)
  • useBrowser (320-328)
vite/src/lib/flow.ts (1) (1)
  • showOmnibox (122-124)
vite/src/lib/url.ts (1) (1)
  • simplifyUrl (121-142)
vite/src/lib/url.ts (1)
vite/src/lib/search.ts (1) (1)
  • createSearchUrl (1-3)
vite/src/components/omnibox/main.tsx (3)
vite/src/components/ui/command.tsx (4) (4)
  • CommandItem (128-128)
  • Command (122-122)
  • CommandInput (124-124)
  • CommandList (125-125)
vite/src/lib/omnibox.ts (2) (2)
  • OmniboxMatch (23-38)
  • handleOmniboxInput (203-240)
vite/src/lib/flow.ts (1) (1)
  • hideOmnibox (126-128)
vite/src/components/browser-ui/browser-content.tsx (1)
vite/src/lib/flow.ts (2) (2)
  • PageBounds (1-6)
  • setPageBounds (97-99)
vite/src/components/browser-ui/sidebar/action-buttons.tsx (2)
vite/src/lib/flow.ts (3) (3)
  • NavigationEntry (8-11)
  • getTabNavigationStatus (109-111)
  • stopLoadingTab (113-115)
vite/src/components/browser-ui/sidebar/navigation-buttons.tsx (2) (2)
  • GoBackButton (74-91)
  • GoForwardButton (93-110)
vite/src/components/browser-ui/sidebar/tabs.tsx (4)
vite/src/components/main/browser-context.tsx (1) (1)
  • useBrowser (320-328)
vite/src/lib/omnibox.ts (1) (1)
  • getNewTabMode (4-6)
vite/src/lib/flow.ts (1) (1)
  • showOmnibox (122-124)
vite/src/components/browser-ui/sidebar/tab.tsx (1) (1)
  • SidebarTab (11-108)
vite/src/components/main/browser-context.tsx (1)
vite/src/lib/url.ts (2) (2)
  • transformUrl (85-119)
  • parseAddressBarInput (68-83)
vite/src/components/browser-ui/main.tsx (2)
vite/src/components/ui/resizable-sidebar.tsx (3) (3)
  • useSidebar (735-735)
  • SidebarInset (721-721)
  • SidebarProvider (731-731)
vite/src/components/browser-ui/browser-sidebar.tsx (1) (1)
  • BrowserSidebar (17-69)
electron/browser/menu.ts (3)
electron/browser/omnibox.ts (6) (6)
  • getNewTabMode (133-135)
  • isOmniboxOpen (165-168)
  • hideOmnibox (158-163)
  • loadOmnibox (144-149)
  • setOmniboxBounds (137-142)
  • showOmnibox (151-156)
vite/src/lib/omnibox.ts (1) (1)
  • getNewTabMode (4-6)
electron/browser/main.ts (1) (1)
  • getFocusedWindow (225-227)
vite/src/components/browser-ui/browser-sidebar.tsx (5)
vite/src/components/browser-ui/main.tsx (3) (3)
  • CollapseMode (9-9)
  • SidebarVariant (10-10)
  • SidebarSide (11-11)
vite/src/lib/flow.ts (2) (2)
  • setWindowButtonVisibility (105-107)
  • setWindowButtonPosition (101-103)
vite/src/components/browser-ui/sidebar/action-buttons.tsx (1) (1)
  • NavigationControls (26-74)
vite/src/components/browser-ui/sidebar/address-bar.tsx (1) (1)
  • SidebarAddressBar (48-54)
vite/src/components/browser-ui/sidebar/tabs.tsx (1) (1)
  • SidebarTabs (47-59)
vite/src/components/ui/command.tsx (1)
vite/src/components/ui/dialog.tsx (5) (5)
  • Dialog (125-125)
  • DialogHeader (130-130)
  • DialogTitle (133-133)
  • DialogDescription (128-128)
  • DialogContent (127-127)
electron/browser/tabs.ts (2)
vite/src/lib/flow.ts (1) (1)
  • PageBounds (1-6)
electron/modules/flags.ts (1) (1)
  • FLAGS (7-17)
electron/browser/omnibox.ts (3)
vite/src/components/omnibox/main.tsx (1) (1)
  • Omnibox (46-224)
vite/src/lib/omnibox.ts (1) (1)
  • getNewTabMode (4-6)
vite/src/lib/flow.ts (2) (2)
  • showOmnibox (122-124)
  • hideOmnibox (126-128)
vite/src/components/ui/resizable-sidebar.tsx (2)
vite/src/hooks/use-sidebar-resize.tsx (1) (1)
  • useSidebarResize (33-160)
vite/src/lib/merge-button-refs.ts (1) (1)
  • mergeButtonRefs (7-19)
vite/src/lib/omnibox.ts (3)
electron/browser/omnibox.ts (1) (1)
  • getNewTabMode (133-135)
vite/src/lib/url.ts (1) (1)
  • getURLFromInput (12-62)
vite/src/lib/search.ts (2) (2)
  • createSearchUrl (1-3)
  • getSearchSuggestions (25-30)
vite/src/components/ui/sidebar.tsx (7)
vite/src/hooks/use-mobile.ts (1) (1)
  • useIsMobile (5-19)
vite/src/components/ui/tooltip.tsx (2) (2)
  • TooltipProvider (61-61)
  • Tooltip (61-61)
vite/src/components/ui/sheet.tsx (5) (5)
  • Sheet (129-129)
  • SheetContent (132-132)
  • SheetHeader (133-133)
  • SheetTitle (135-135)
  • SheetDescription (136-136)
vite/src/components/ui/button.tsx (1) (1)
  • Button (59-59)
vite/src/components/ui/input.tsx (1) (1)
  • Input (21-21)
vite/src/components/ui/separator.tsx (1) (1)
  • Separator (28-28)
vite/src/components/ui/skeleton.tsx (1) (1)
  • Skeleton (13-13)
vite/src/lib/flow.ts (1)
electron/browser/omnibox.ts (2) (2)
  • showOmnibox (151-156)
  • hideOmnibox (158-163)
🪛 Biome (1.9.4)
vite/src/components/omnibox/main.tsx

[error] 140-140: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 141-141: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 142-142: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 143-143: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 144-144: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 157-157: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 158-158: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 159-159: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 160-160: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)

vite/src/components/main/browser-context.tsx

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (140)
vite/src/routes/new/index.html (1)

8-8: Added dark theme to the new tab page.

The addition of the "dark" class to the body element implements dark mode styling for the new tab page, ensuring a consistent theme across the application.

electron/modules/flags.ts (2)

4-4: New debug flag for disabling tab view.

This flag provides a convenient way to disable the tab view functionality during development and debugging.


13-16: Well-documented flag implementation with proper formatting.

The addition of the trailing comma after the previous property and the descriptive comment for the new debug flag follow good code practices.

vite/src/lib/merge-button-refs.ts (1)

1-19: Well-implemented ref merging utility with proper TypeScript typing.

This utility function correctly handles both callback refs and object refs, following React's ref patterns. The TypeScript generic constraint ensures type safety for button elements.

vite/src/hooks/use-mobile.ts (1)

1-19: Well-implemented responsive hook for mobile detection

This hook is cleanly implemented with proper event listener setup, initial state calculation, and cleanup on unmount. The mobile breakpoint constant makes the code more maintainable.

vite/src/components/ui/separator.tsx (1)

1-28: Well implemented Separator component using Radix UI

This is a clean implementation of a Separator component using Radix UI's primitive. The component:

  • Appropriately forwards all props to the underlying primitive
  • Sets sensible defaults for orientation and decorative props
  • Uses the cn utility for classname composition
  • Implements conditional styling based on orientation using data attributes
  • Follows best practices with the "use client" directive for Next.js compatibility
vite/src/index.css (1)

57-59: Good addition for controlling app region dragging behavior

The .remove-app-drag class is a useful counterpart to the existing .app-drag class, providing fine-grained control over which elements can be used to drag the window.

vite/src/components/browser-ui/sidebar/navigation-buttons.tsx (3)

20-72: Well-implemented NavigationButton with dropdown history functionality

The NavigationButton component is well structured with proper separation of concerns:

  • Clear handling of navigation actions
  • Good use of context menu for showing navigation history
  • Appropriate state management for the dropdown menu
  • Clear comment explaining the custom dropdown open behavior

The component elegantly handles both click navigation and right-click history access, which provides a good user experience.


74-91: Good component composition for GoBackButton

The GoBackButton component effectively utilizes the base NavigationButton component with the appropriate props for back navigation. This demonstrates good component composition and code reuse.


93-110: Good component composition for GoForwardButton

Similarly, the GoForwardButton component follows the same pattern, reusing the NavigationButton component with forward navigation props. This consistency in implementation is excellent.

vite/src/components/ui/button.tsx (2)

7-36: Comprehensive button variant system using class-variance-authority

The buttonVariants constant defines a robust set of styling options using the class-variance-authority library. This approach:

  • Provides consistent styling across button variations
  • Makes it easy to add new variants and sizes
  • Follows modern CSS utility practices
  • Handles focus states, disabled states, and SVG styling appropriately

The variant definitions are well-organized and cover common use cases (default, destructive, outline, etc.).


38-57: Well-implemented flexible Button component with Slot support

The Button component implementation:

  • Uses the Slot pattern for component composition
  • Properly types props with React.ComponentProps and VariantProps
  • Handles className merging correctly
  • Correctly forwards props to the underlying component

This is a solid foundation for button elements throughout the application.

vite/src/components/browser-ui/browser-content.tsx (4)

1-57: Well-structured dimension tracking implementation.

This component effectively manages its dimensions using ResizeObserver and updates the page bounds for the Flow interface. The cleanup logic in the useEffect hook properly prevents memory leaks by removing event listeners and observers.


58-69: Good implementation of DEBUG_SHOW_BOUNDS visualization.

The debug overlay is a helpful development tool that only appears when DEBUG_SHOW_BOUNDS is true, showing the current dimensions in a non-intrusive way.


70-98: Well-implemented content rendering with proper animations.

The AnimatePresence component provides smooth transitions between states, and the conditional rendering logic clearly handles both active tab and empty states. The use of motion.div with appropriate animation properties ensures a polished user experience.


103-104: Good use of memo for performance optimization.

Wrapping the component with memo prevents unnecessary re-renders, which is a good practice for components that depend primarily on props and may be rendered frequently.

vite/src/components/browser-ui/main.tsx (2)

23-29: Good implementation of loading state management.

The useEffect hook properly updates the loading state based on the activeTab status change, which is a clean approach to derive UI state from application state.


65-71: Proper context provider implementation.

The BrowserUI component correctly wraps the internal component with SidebarProvider, ensuring that the sidebar context is available throughout the component tree.

vite/src/components/browser-ui/browser-sidebar.tsx (1)

57-66: Well-implemented dynamic styling for SidebarRail.

The conditional styling using the cn utility function is well-structured and covers all the possible combinations of open state, variant, and side. This ensures that the UI adapts correctly to different configurations.

vite/src/components/browser-ui/sidebar/tabs.tsx (1)

12-44: Well-structured NewTabButton with proper animation feedback.

The NewTabButton component effectively handles the different modes of creating new tabs (omnibox or direct tab creation) and provides good visual feedback with spring animations. The separation of concerns is clear, making the component easy to understand and maintain.

vite/src/components/browser-ui/sidebar/tab.tsx (2)

31-34: Guard usage of tab.id more thoroughly.
If tab.id doesn't exist or is invalid, calls to handleTabClick will be ignored. Consider adding logging or additional guard logic to detect and handle unexpected tab.id values.


42-49: Confirm that middle-click is handled consistently across platforms.
Some devices might not send button code 1 for a middle click. If you aim for cross-platform consistency, consider a fallback or additional checks.

vite/src/components/browser-ui/sidebar/action-buttons.tsx (1)

61-74: Good compositional structure.
Your layout and control grouping is clear and responsive. Overall, this code segment looks well-structured to manage sidebar actions.

vite/src/lib/search.ts (1)

25-30: Handle network or parsing errors.
If fetch or response.json() fails, the code could throw an error. Consider wrapping these calls in try/catch or adding error handling logic to gracefully handle failures.

vite/src/routes/main/page.tsx (1)

4-12: Clean and modular approach.
By wrapping BrowserApp in BrowserProvider, you offload complex state management to a higher-level context. This is a solid design choice that keeps the component simple and maintainable.

vite/src/hooks/use-sidebar-resize.tsx (6)

14-18: Clear and well-structured utility functions

The parseWidth, toPx, and formatWidth utility functions are well-implemented and provide a clean abstraction for handling width conversions between different units.


30-31: Good usage of constants for cookie configuration

Using named constants for cookie parameters improves maintainability and readability.


33-53: Well-implemented state management with refs

The hook properly initializes refs for tracking drag state, positions, and thresholds. The persistWidth callback is correctly memoized and handles cookie storage appropriately.


56-74: Proper event handling in mouseDown callback

The handleMouseDown callback is correctly memoized with the right dependencies and includes appropriate validation logic before initiating dragging operations.


76-153: Comprehensive resize logic and cleanup

The resize logic handles different units, enforces constraints, and includes auto-collapse functionality. The code properly cleans up event listeners to prevent memory leaks.


155-159: Clean hook return interface

The hook returns a minimal, focused set of values that make it easy to integrate with components.

vite/package.json (2)

13-17: Good selection of UI component libraries

The addition of Radix UI components provides accessible, unstyled components that work well with the existing styling approach.


26-26: Good addition of react-resizable-panels

This package aligns well with the sidebar resize functionality implemented in the hooks.

electron/index.ts (4)

1-1: Updated imports for IPC functionality

The import statement now includes the necessary Electron modules for the added IPC handlers.


18-29: Well-implemented tab loading control

The IPC handler correctly retrieves the window and tab objects before stopping the loading, with proper null checks.


31-48: Comprehensive navigation status retrieval

The handler returns all necessary navigation data including history entries, active index, and navigation capabilities.


50-59: Robust navigation entry handling

The handler includes proper validation before performing the navigation operation, preventing potential errors.

vite/src/components/omnibox/main.tsx (5)

17-32: Well-structured OmniboxItem component

The component provides a consistent layout for search results with appropriate icon and action display.


51-54: Clean state and ref initialization

The component properly initializes state from URL parameters and sets up necessary refs.


56-73: Good keyboard accessibility

The component handles focus and keyboard shortcuts appropriately, improving accessibility.


75-112: Robust request management with AbortController

The component correctly handles in-flight request cancellation and implements debouncing for input changes.


176-223: Well-structured command UI with appropriate styling

The component uses the Command components effectively and applies appropriate styling and accessibility attributes.

vite/src/components/ui/tooltip.tsx (4)

1-2: Using "use client" successfully in Next.js.
This directive ensures that the file is rendered on the client side, which is required for using client-specific APIs or stateful components.


8-19: Encapsulation of TooltipProvider is clear.
This component neatly wraps TooltipPrimitive.Provider and applies a default delay, making it easy to configure tooltip timing across the application.


31-35: TooltipTrigger usage is straightforward.
Prop forwarding and data-slot="tooltip-trigger" usage follow best practices for transparency and debugging.


61-61: Exporting all tooltip components together.
Exporting these components together simplifies import statements across the codebase.

electron/browser/menu.ts (3)

2-3: Refined named imports for Browser and omnibox utilities.
Switching to named imports improves clarity and ensures consistent usage of the imported symbols across the file.


85-105: Omnibox-based close logic looks consistent.
You correctly hide the omnibox or close the tab/window. The guard if (!win) return; already avoids null references, making an optional chain superfluous here.


108-108: Corrected Menu Label.
Renaming to "Toggle Developer Tools" reflects the plural form, matching common conventions.

vite/src/components/main/browser-context.tsx (8)

1-4: Imports and Chrome extension environment setup.
Using parseAddressBarInput and transformUrl properly sets up URL transformations for the context’s internal logic.


7-25: Well-defined BrowserContextType interface.
It thoroughly lists the state and handlers the provider will supply, ensuring type safety for consumers of the context.


29-66: Proper initialization of state and references in BrowserProvider.
The stateful variables for tabs, active tab, and address URL are correctly set, and references like addressUrl_urlRef reduce unnecessary re-renders.


80-92: Fetching initial tabs is handled correctly.
Querying tabs on load ensures consistent state when the provider initializes.

🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


94-114: Dynamic title logic is sound.
The approach to updating the title based on the active tab’s title is correct for immediate UI feedback.


128-145: Tab event listener setup with stable callbacks.
Using stable callbacks with useCallback and referencing the latest states is a clean approach, reducing subscription overhead and ensuring consistent event handling.


257-265: Cautious URL handling in handleAddressUrlSubmit.
Parsing the address bar input and updating or creating a tab is correct. Confirm that chrome.tabs.update works reliably on ephemeral tabs in certain extension contexts.


320-328: useBrowser custom hook usage guard.
Throwing an error when outside the provider prevents incorrect usage of the context, ensuring that components cannot misuse the context inadvertently.

vite/src/lib/url.ts (4)

1-1: Good import for creating search URLs.

The createSearchUrl import is used appropriately to handle search fallback logic.


64-66: Simple utility function to check if input is a URL.

This is straightforward and reuses getURLFromInput effectively.


68-83: Intuitive address bar parsing with proper search fallback.

  1. Returning an empty string for empty input might cause confusion in downstream usage. Confirm that no further logic depends on an actual URL.
  2. The fallback to createSearchUrl is well-integrated and user-friendly.

5-5:

Details

✅ Verification successful

Ensure whitelisted pages are valid and restricted.

Adding "omnibox" to whitelistedPages might inadvertently permit unauthorized pages if there's no strict validation elsewhere.

Would you like to confirm usage of omnibox in the codebase to ensure it’s protected from injection or misconfigurations?


🏁 Script executed:

#!/bin/bash
rg -A 3 "omnibox"

Length of output: 10600


Action: Confirmed "omnibox" Whitelisting Usage

After verifying the references to "omnibox" across the codebase—including its dedicated handling in files such as vite/src/lib/omnibox.ts, electron/browser/omnibox.ts, and its use in conditionals like if (getNewTabMode() === "omnibox")—it appears that whitelisting "omnibox" is an intentional design choice. The omnibox mode is systematically managed through dedicated functions (e.g., getNewTabMode(), showOmnibox(), hideOmnibox()) and UI components, reducing the risk of injection or misconfiguration.

Please ensure that:

  • The omnibox page continues to enforce proper access control and validation within its dedicated modules.
  • Any future modifications to routing or page validation maintain these security measures.
electron/browser/tabs.ts (10)

2-2: Expanded Electron imports for IPC usage.

Great to see ipcMain included, as it enables communication for dynamic window sizing.


5-10: Defines clear bounding parameters for windows.

PageBounds is a concise type. You might want to ensure coordinates and sizes are validated before usage to prevent off-screen rendering issues.


12-13: Maintains dynamic window bounds mapping and signaling.

windowsBounds and windowsBoundsEmitter enable robust tracking of custom bounds transitions across different windows.


23-23: Bounds listener property is well-defined.

Initializes to null to prevent potential undefined usage.


32-47: Conditional creation of WebContentsView is flexible.

  1. Good approach to handle existing webContents if provided, or create a new one otherwise.
  2. Ensure consistent usage of webPreferences merging from both provided and default sources.

113-122: Starting bounds listener on show.

  1. This ensures the layout is responsive as soon as the tab is displayed.
  2. Hiding the tab view when FLAGS.DEBUG_DISABLE_TAB_VIEW is true is a useful debug feature.

125-130: Stopping bounds listener on hide.

This prevents unnecessary event handling for invisible tabs, improving performance and clarity.


146-155: Applies dynamic layout and rounded corners.

Updating bounds from windowsBounds while setting a borderRadius is consistent with a modern UI.


158-174: Sets up robust event listeners for resizing and custom bounds.

  1. Merging OS-level “resize” with custom bounds updates ensures all resizing triggers are captured.
  2. Good housekeeping by stopping old listeners first.

175-184: Graceful detachment of bounds listeners.

Clears both “resize” and custom bounds events to prevent memory leaks or stale triggers.

vite/src/components/ui/sheet.tsx (11)

7-9: Sheet root wrapper for Radix UI.

This is a straightforward pass-through to SheetPrimitive.Root, enhancing composition.


11-15: Sheet trigger for opening the sheet.

Provides a consistent “trigger” slot—follows Radix UI idioms nicely.


17-21: Sheet close for dismissing the sheet.

Simple pass-through ensures consistent close behavior.


23-27: Sheet portal for managing DOM hierarchy.

This ensures proper layering and accessibility.


29-43: Sheet overlay with configurable animations.

The usage of Radix UI states (data-[state=open]) to control animations is idiomatic and user-friendly.


45-80: Sheet content with variable side positioning.

  1. Good usage of utility classes for top/right/bottom/left transitions.
  2. The close button is well-labeled for screen readers.

82-90: Sheet header with flexible layout.

Simple container for header elements.


92-100: Sheet footer placed at the bottom.

Placing the footer automatically at the bottom using mt-auto is a neat approach for stacked layout.


102-113: Sheet title for accessible naming.

Proper use of SheetPrimitive.Title, plus a utility class for styling.


115-126: Sheet description for accessible details.

Applies text-muted-foreground class, ensuring text is visually distinct yet accessible.


128-137: Clean exports for all sheet components.

Neatly grouped exports provide a predictable import structure for consumers.

vite/src/components/ui/command.tsx (3)

1-5: Consider verifying dependency usage and versions.
The code relies on the cmdk and lucide-react libraries. Please ensure that the versions specified in your project's package configuration (e.g., package.json) match the features you're using here.


8-19: Looks good — well-structured component.
The Command functional component is well-defined, with clear separation of props and the utility function cn for conditional class merging. Implementation appears correct.


111-119: Well-thought-out approach for CommandShortcut.
The CommandShortcut component effectively displays keyboard shortcuts. No issues spotted.

vite/src/components/ui/dialog.tsx (3)

9-13: Straightforward usage of Radix UI root.
The Dialog component successfully wraps DialogPrimitive.Root with minimal overhead, keeping the API consistent.


33-46: Overlay styling looks good.
The animated overlay usage with data-[state=...] classes is solid, ensuring fluid transitions. No issues spotted here.


65-69: Validate close button accessibility.
The close button includes an icon and a visually hidden <span>Close</span>. This is good for screen readers, but confirm that it meets your specific accessibility standards for the chosen audience.

electron/preload.ts (3)

4-8: Clear UI distinction checks.
The isBrowserUI and isOmniboxUI variables are a clean approach to gating features in the correct context.


10-13: Injected browser action.
Calling injectBrowserAction() conditionally based on isBrowserUI is succinct and keeps the code organized.


19-42: Consider verifying async check or capturing errors.
Several interface methods call ipcRenderer.send, which doesn’t provide a response. If you need confirmation or error handling, prefer ipcRenderer.invoke. Otherwise, confirm that a one-way send is sufficient.

electron/browser/main.ts (12)

1-1: Added ipcMain Import Looks Good
Importing ipcMain is necessary for the newly introduced IPC handlers and appears correct.


14-14: Omnibox Import is Appropriate
Importing getNewTabMode and Omnibox is consistent with subsequent usage in this file. No issues found.


18-18: New WEBPACK_ROOT_DIR Constant
Defining a distinct constant for the Webpack directory path helps improve clarity. This approach is maintainable and avoids repeated path construction.


72-72: Omnibox Property Acknowledged
Declaring a dedicated omnibox property ensures clarity when referencing this feature within the class. No immediate concerns.


110-112: Conditional Omnibox Instantiation
By only instantiating Omnibox when webuiExtensionId is available, you gracefully handle environments where the extension isn’t loaded. Overall logic seems solid.


426-427: Reasonable Min Dimensions
Enforcing a minimum window size is acceptable for most use cases. If additional flexibility is desired, consider making these dimensions user-configurable.


432-433: Window Aesthetic Configurations
These additional window properties (titleBarOverlay, transparency, vibrancy, etc.) enhance UI aesthetics on macOS and Windows. Be aware that vibrancy visuals differ per platform, and some properties may have no effect on other OSes.

Also applies to: 440-447


487-490: Construction Options Sanity Check
The usage of constructionOptions for creating a new tab is straightforward. Verify that your details object always provides the necessary parameters to prevent runtime issues.


526-527: Allowlist for Flow Utility Paths
Introducing FLOW_UTILITY_ALLOWED_DIRECTORIES is a logical security measure. Should you need additional directories in the future, this pattern is easily extensible.


595-595: No Meaningful Change
This blank line addition does not affect functionality.


596-609: IPC Handlers for Custom Window Button Management
These IPC handlers correctly retrieve the BrowserWindow and conditionally call custom setWindowButtonPosition and setWindowButtonVisibility methods. Ensure these window methods are well-defined in a subclass or extended type to avoid runtime errors.


33-33:

Details

❓ Verification inconclusive

Ensure Preload Path is Valid
You are now pointing PATHS.PRELOAD to .webpack/renderer/browser/preload.js. Verify that this file consistently exists after packaging to avoid load failures.


🏁 Script executed:

#!/bin/bash
# Validate that the new preload path is present in the build output
fd preload.js .webpack --exec ls -lh

Length of output: 134


Preload File Path Verification Needed
The current preload path is set as follows:

PRELOAD: path.join(WEBPACK_ROOT_DIR, "renderer", "browser", "preload.js"),

The original intent was for this to point to .webpack/renderer/browser/preload.js. However, the automated check failed because the .webpack directory was not found in the repository build output. Please verify manually that your packaging process correctly generates the expected file at this path. Additionally, ensure that the WEBPACK_ROOT_DIR variable is set to a directory that is indeed created during packaging.

  • Confirm that the output directory (e.g. .webpack) is correctly generated.
  • Verify that .webpack/renderer/browser/preload.js exists post-packaging.
  • Update the build configuration if the output directory or path has changed.
electron/browser/omnibox.ts (13)

1-4: Map-Based Omnibox Storage
Using a Map<BrowserWindow, Omnibox> to track per-window omnibox instances is straightforward. However, ensure entries are removed upon window destruction to prevent memory leaks.


5-5: Simple QueryParams Alias
Defining a basic { [key: string]: string } alias is sufficient for your needs.


7-49: Omnibox Constructor & Setup

  1. Creating a WebContentsView and attaching it to parentWindow establishes a cohesive UI.
  2. The on("blur", ...) event to hide the omnibox on focus loss is a user-friendly approach.
  3. setTimeout(...) to load the interface and update bounds, then hiding the omnibox ensures a clean initial state.
    Overall, this design is sensible for a dedicated floating omnibox window.

51-68: loadInterface Method
Dynamically constructing the URL with query parameters is well-handled. The conditional reload if the URL matches is also a nice touch. No immediate issues.


70-75: Clearing Keep-On-Top Interval
Properly clearing your interval avoids resource leaks. Good housekeeping.


77-95: updateBounds Handling
Gracefully handles custom bounds or defaults to center the omnibox. Consider verifying that the resulting positions remain on-screen for smaller displays.


97-100: isVisible Method
Delegating visibility checks to this.view.getVisible() is simple and direct.


122-125: hide Method
Stopping the keep-on-top interval before hiding prevents concurrency issues or repeated calls. Appropriately implemented.


127-131: setBounds
Storing bounds in this.bounds and reapplying them is straightforward. No concerns.


133-135: getNewTabMode Always Returns "omnibox"
Returning a constant "omnibox" is consistent with your logic. If you plan to switch modes dynamically, consider a more robust approach.


137-149: Omnibox Bound & Interface Utility Functions
setOmniboxBounds and loadOmnibox unify repeated code for a cleaner approach. No issues found.


151-163: Visibility & State Helpers
showOmnibox, hideOmnibox, and isOmniboxOpen nicely delegate to your Omnibox instance for code reuse.


170-182: IPC Handlers for Omnibox
Providing direct IPC handlers—show-omnibox and hide-omnibox—to manage bounds and parameters is coherent. Ensure comprehensive error-checking if parentWindow is null or destroyed.

vite/src/components/ui/dropdown-menu.tsx (18)

1-4: Importing Radix and Icons
These imports are appropriate for creating a customized dropdown menu with icons. No issues noted.


5-5: Utility Function Import
cn from "@/lib/utils" is a standard approach for conditional classnames.


7-11: DropdownMenu Root Component
Wrapping DropdownMenuPrimitive.Root in a local component is a neat way to add custom data attributes.


13-19: DropdownMenuPortal
Forwarding all props to DropdownMenuPrimitive.Portal is straightforward. The extra data-slot helps with debugging and styling.


21-30: DropdownMenuTrigger
A standard Radix wrapper. Implementation aligns with typical usage.


32-50: DropdownMenuContent

  1. The additional class naming for open/close animations is well-structured.
  2. The sideOffset default is set to 4, which is sensible.
  3. Wrapping in DropdownMenuPrimitive.Portal ensures correct layering.

52-58: DropdownMenuGroup
Simple pass-through to DropdownMenuPrimitive.Group; no problems.


60-81: DropdownMenuItem

  1. The data-inset and data-variant attributes provide fine-grained styling.
  2. The destructured variant prop is a handy extension.
  3. Good usage of Radix states for focus/disabled.

83-107: DropdownMenuCheckboxItem

  1. Integrates a checkbox indicator with CheckIcon.
  2. The absolute positioning for the checkbox is typical of menu items.
  3. Overall usage of CheckboxItem is correct.

109-118: DropdownMenuRadioGroup
Acts as a container for radio items. Straightforward.


120-142: DropdownMenuRadioItem

  1. Provides a CircleIcon for the radio selection.
  2. The code mirrors the CheckboxItem approach.
  3. Good usage of ItemIndicator.

144-162: DropdownMenuLabel
Simple extension wrapping DropdownMenuPrimitive.Label. The custom inset logic is on point.


164-175: DropdownMenuSeparator
Appropriate styling for dividing items.


177-191: DropdownMenuShortcut
A quick utility to align keyboard shortcuts to the right. Implementation is minimal and effective.


193-197: DropdownMenuSub
Standard sub-menu usage from Radix.


199-221: DropdownMenuSubTrigger

  1. Combines a sub-trigger with optional inset.
  2. Visually indicates a submenu with ChevronRightIcon.

223-237: DropdownMenuSubContent
Mirrors the root Content styling, applying typical sub-menu animations and layout.


239-255: Named Exports Provided
All menu components are exported, supporting modular usage of the dropdown menu API.

vite/src/lib/flow.ts (2)

73-83: Validate null checks on omnibox methods.
If for some reason the omnibox object is not injected or not yet initialized, calls to flow.omnibox.show or flow.omnibox.hide from other modules might fail. You could add runtime checks or fallbacks for robust error handling when the omnibox is unavailable.


85-128: Ensure availability of global flow.
All exported helper functions rely on flow being globally present. Depending on your build or preload script timing, flow might not be attached yet. If that’s guaranteed by design, this is fine. Otherwise, consider adding optional chaining or defensive checks:

-export function showOmnibox(bounds: PageBounds | null, params: QueryParams | null) {
-  return flow.omnibox.show(bounds, params);
+export function showOmnibox(bounds: PageBounds | null, params: QueryParams | null) {
+  if (!flow?.omnibox?.show) {
+    console.warn("Omnibox unavailable");
+    return;
+  }
+  return flow.omnibox.show(bounds, params);
}
vite/src/lib/omnibox.ts (1)

99-118: Review fallback URL.
When input.type === OmniboxInputType.URL but getURLFromInput returns null, you fall back to "about:blank". Confirm that this silent fallback is intended, as it may navigate to a blank page instead of prompting the user or surfacing an error.

vite/src/components/ui/resizable-sidebar.tsx (3)

103-113: Great use of a keyboard shortcut.
The logic for toggling the sidebar with "Ctrl + b" or "Cmd + b" is straightforward and well-cleaned up with the removal of the event listener in the effect cleanup.


540-565: Tooltips logic is well-structured.
Wrapping the menu button in a tooltip only when a tooltip is provided is a clean approach. The condition to hide the tooltip while not collapsed or on mobile devices is appropriate for usability.


712-736: Robust export structure.
Exporting all components, subcomponents, and hooks from a single file significantly improves discoverability. This modular design will benefit maintainability and code reuse.

iamEvanYT and others added 2 commits March 21, 2025 23:16
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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: 0

🧹 Nitpick comments (5)
vite/src/components/main/browser-context.tsx (5)

87-90: Add optional chaining for safer property access

The active tab check could be simplified using optional chaining to make the code more defensive.

- if (activeTab && activeTab.id) {
+ if (activeTab?.id) {
  setActiveTabId(activeTab.id);
}
🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


166-166: Remove console.log statements before production

There are several console.log statements throughout the file (also at lines 185, 213) that should be removed or replaced with proper logging before production deployment.

- console.log("Tab Created!", tab.id, tab);

256-264: Consider adding error handling for Chrome API calls

The handler doesn't check if the Chrome API is available before using it. In extensions, the API might not always be accessible when running in certain contexts.

const handleAddressUrlSubmit = useCallback(() => {
  const parsedUrl = parseAddressBarInput(addressUrl);
+ if (!chrome.tabs) {
+   console.error("Chrome tabs API not available");
+   return;
+ }
  if (parsedUrl && activeTabId && activeTabId > 0) {
    chrome.tabs.update(activeTabId, { url: parsedUrl });
  } else if (parsedUrl) {
    // If no active tab or invalid tab ID, create a new tab with the URL
    chrome.tabs.create({ url: parsedUrl });
  }
}, [addressUrl, activeTabId]);

54-58: Simplify conditional logic for clarity

The nested condition can be flattened to improve readability.

 if (!transformedUrl) {
   setAddressUrl(activeTab.url);
 } else {
-  if (transformedUrl && transformedUrl !== "flow://new") {
+  if (transformedUrl !== "flow://new") {
     setAddressUrl(transformedUrl);
   } else {
     setAddressUrl("");
   }
 }

233-244: Optimize tab click handler for clarity and performance

The current implementation iterates through all tabs to find a matching tab ID. This can be simplified since you already know the tab ID.

const handleTabClick = useCallback(
  (tabId: number) => {
-   // Only update if the tab exists
-   tabs.forEach((tab) => {
-     if (tab.id === tabId) {
-       chrome.tabs.update(tabId, { active: true });
-     }
-   });
+   // No need to iterate through all tabs when we already have the ID
+   const tabExists = tabs.some(tab => tab.id === tabId);
+   if (tabExists) {
+     chrome.tabs.update(tabId, { active: true });
+   }
  },
  [tabs]
);
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c709594 and f1aba72.

📒 Files selected for processing (1)
  • vite/src/components/main/browser-context.tsx (1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
vite/src/components/main/browser-context.tsx (1)
vite/src/lib/url.ts (2) (2)
  • transformUrl (85-119)
  • parseAddressBarInput (68-83)
🪛 Biome (1.9.4)
vite/src/components/main/browser-context.tsx

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (1)
vite/src/components/main/browser-context.tsx (1)

1-328: Excellent implementation of browser context provider with solid state management

Overall, this is a well-structured React Context implementation that properly manages browser state. The code demonstrates good practices:

  1. Proper use of React hooks (useState, useEffect, useRef, useCallback)
  2. Effective management of Chrome extension API interactions
  3. Good separation of concerns between state management and event handlers
  4. Appropriate error handling and edge case management in most areas
  5. Clean, consistent coding style with good comments

The logic for updating the address bar URL, managing tabs, and handling window state is well thought out. The export of a custom hook with proper error checking ensures consumers use the context correctly.

🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

@iamEvanYT iamEvanYT merged commit 6e87c22 into main Mar 21, 2025
1 check was pending
@iamEvanYT iamEvanYT deleted the evan/redesign branch March 21, 2025 23:42
@coderabbitai coderabbitai bot mentioned this pull request Apr 3, 2025
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