[hAIk]: refactor: reorganize browser modules (browserRegistry, browserCommandHandler, resolveUrl, useBrowserActivity) into shared/browsers/ subdirectory, extract duplicate useResolvedTheme hook from CodeDiff into CodeBlockRoot helpers, and update all consumer imports across Dashboard and Layout

This commit is contained in:
haikdc
2026-04-18 18:29:49 -07:00
parent 4ac8fa2c12
commit decd61349d
14 changed files with 65 additions and 65 deletions
@@ -4,7 +4,7 @@ import { useAppDispatch } from '@/shared/hooks';
import { CREATE_DASHBOARD } from '@/shared/backend-bridge/apps/dashboards';
import { addBrowserCard, addBrowserTab } from '@/shared/state/dashboardLayoutSlice';
import { setPendingBrowserUrl } from '@/shared/state/tempStateSlice';
import { findBrowserByWebContentsId } from '@/shared/browserRegistry';
import { findBrowserByWebContentsId } from '@/shared/browsers/browserRegistry';
export function useUrlInterception(dashboardList: { id: string }[]) {
const dispatch = useAppDispatch();
@@ -5,7 +5,7 @@ import {
useCallback,
useEffect,
createContext,
use,
useContext,
type ReactNode,
} from "react";
import { type Highlighter } from "shiki/bundle/web";
@@ -40,7 +40,7 @@ type CodeBlockSharedState = {
const CodeBlockContext = createContext<CodeBlockSharedState | null>(null);
export function useCodeBlock(): CodeBlockSharedState {
const context = use(CodeBlockContext);
const context = useContext(CodeBlockContext);
if (!context) {
throw new Error(
"CodeBlock subcomponents must be used within <CodeBlock.Root>.",
@@ -5,6 +5,7 @@ import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
import pierreDarkTheme from "../../../_shared/pierre-dark-theme.js";
import pierreLightTheme from "../../../_shared/pierre-light-theme.js";
import type { CodeBlockLineNumbersMode } from "../../schema";
import { useEffect, useState } from "react";
const MAX_HTML_CACHE_ENTRIES = 64;
@@ -53,4 +54,54 @@ export function setCachedHtml(cacheKey: string, html: string): void {
}
htmlCache.set(cacheKey, html);
}
function getSystemTheme(): "light" | "dark" {
if (typeof window === "undefined") return "light";
return window.matchMedia?.("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
}
function getDocumentTheme(): "light" | "dark" | null {
if (typeof document === "undefined") return null;
const root = document.documentElement;
const dataTheme = root.getAttribute("data-theme")?.toLowerCase();
if (dataTheme === "dark") return "dark";
if (dataTheme === "light") return "light";
if (root.classList.contains("dark")) return "dark";
if (root.classList.contains("light")) return "light";
return null;
}
export function useResolvedTheme(): "light" | "dark" {
const [theme, setTheme] = useState<"light" | "dark">(() => {
return getDocumentTheme() ?? getSystemTheme();
});
useEffect(() => {
if (typeof window === "undefined" || typeof document === "undefined") {
return;
}
const update = () => setTheme(getDocumentTheme() ?? getSystemTheme());
const mql = window.matchMedia?.("(prefers-color-scheme: dark)");
mql?.addEventListener("change", update);
const observer = new MutationObserver(update);
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["class", "data-theme"],
});
return () => {
mql?.removeEventListener("change", update);
observer.disconnect();
};
}, []);
return theme;
}
@@ -3,7 +3,6 @@
import {
useState,
useCallback,
useEffect,
useMemo,
createContext,
useContext,
@@ -19,6 +18,7 @@ import { Copy, Check, ChevronDown, ChevronUp } from "lucide-react";
import type { CodeDiffProps } from "./schema";
import { useCopyToClipboard } from "../_shared/useCopyToClipboard";
import { Button, cn, Collapsible, CollapsibleTrigger } from "./_adapter";
import { useResolvedTheme } from "../CodeBlock/components/CodeBlockRoot/helpers";
/*
* Pierre's shared_highlighter registers custom themes with dynamic imports
@@ -38,54 +38,6 @@ const COPY_ID = "codediff-code";
/* ── Theme detection (mirrors CodeBlock) ────────────────────────── */
function getSystemTheme(): "light" | "dark" {
if (typeof window === "undefined") return "light";
return window.matchMedia?.("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
}
function getDocumentTheme(): "light" | "dark" | null {
if (typeof document === "undefined") return null;
const root = document.documentElement;
const dataTheme = root.getAttribute("data-theme")?.toLowerCase();
if (dataTheme === "dark") return "dark";
if (dataTheme === "light") return "light";
if (root.classList.contains("dark")) return "dark";
if (root.classList.contains("light")) return "light";
return null;
}
function useResolvedTheme(): "light" | "dark" {
const [theme, setTheme] = useState<"light" | "dark">(() => {
return getDocumentTheme() ?? getSystemTheme();
});
useEffect(() => {
if (typeof window === "undefined" || typeof document === "undefined") {
return;
}
const update = () => setTheme(getDocumentTheme() ?? getSystemTheme());
const mql = window.matchMedia?.("(prefers-color-scheme: dark)");
mql?.addEventListener("change", update);
const observer = new MutationObserver(update);
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["class", "data-theme"],
});
return () => {
mql?.removeEventListener("change", update);
observer.disconnect();
};
}, []);
return theme;
}
/* ── Language display names (mirrors CodeBlock) ─────────────────── */
const LANGUAGE_DISPLAY_NAMES: Record<string, string> = {
@@ -4,8 +4,8 @@ import Typography from '@mui/material/Typography';
import { setBrowserCardPosition, setBrowserCardSize, updateBrowserTabUrl, type BrowserTab } from '@/shared/state/dashboardLayoutSlice';
import { useAppDispatch, useAppSelector } from '@/shared/hooks';
import { useClaudeTokens } from '@/shared/styles/ThemeContext';
import { useBrowserActivity } from '@/shared/useBrowserActivity';
import { resolveInput, isGoogleSearch } from '@/shared/resolveUrl';
import { useBrowserActivity } from './hooks/useBrowserActivity';
import { resolveInput, isGoogleSearch } from '@/shared/browsers/resolveUrl';
import BrowserAgentOverlay from './components/BrowserAgentOverlay/BrowserAgentOverlay';
import { useOverlayScrollPassthrough } from '../shared/useOverlayScrollPassthrough';
import { useElementSelection } from '@/app/pages/_shared/element_selection/useElementSelection';
@@ -3,7 +3,7 @@ import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import CircularProgress from '@mui/material/CircularProgress';
import SmartToyOutlinedIcon from '@mui/icons-material/SmartToyOutlined';
import { getActionLabel } from '@/shared/browserCommandHandler';
import { getActionLabel } from '@/shared/browsers/browserCommandHandler/browserCommandTypes';
interface BrowserActionOverlayProps {
agentAction: string | null;
@@ -4,7 +4,7 @@ import {
getActivity,
type BrowserActivity,
type BrowserAction,
} from './browserCommandHandler';
} from '@/shared/browsers/browserCommandHandler/browserCommandTypes';
interface BrowserActivityState {
active: boolean;
@@ -5,7 +5,7 @@ import {
unregisterWebview, // only used in this file, maybe an aNr opportunity? -HD
setActiveTab as setRegistryActiveTab,
type BrowserWebview,
} from '@/shared/browserRegistry';
} from '@/shared/browsers/browserRegistry';
import {
updateBrowserTabUrl,
updateBrowserTabTitle,
@@ -12,7 +12,7 @@ import {
} from '@/shared/state/dashboardLayoutSlice';
import { LIST_APPS } from '@/shared/backend-bridge/apps/app_builder';
import { agentsWs } from '@/shared/ws/WebSocketManager';
import { initBrowserCommandHandler } from '@/shared/browserCommandHandler';
import { initBrowserCommandHandler } from '@/shared/browsers/browserCommandHandler/browserCommandHandler';
import { clearPendingBrowserUrl, clearPendingFocusAgentId } from '@/shared/state/tempStateSlice';
import { type CanvasActions } from '@/app/pages/Dashboard/_shared/types';
@@ -1,5 +1,5 @@
import { type BrowserWebview } from './browserRegistry';
import { resolveInput } from './resolveUrl';
import { type BrowserWebview } from '../browserRegistry';
import { resolveInput } from '../resolveUrl';
export async function handleScreenshot(wv: BrowserWebview): Promise<Record<string, any>> {
const nativeImage = await wv.capturePage();
@@ -1,5 +1,5 @@
import { getWebview } from './browserRegistry';
import { agentsWs } from './ws/WebSocketManager';
import { getWebview } from '../browserRegistry';
import { agentsWs } from '@/shared/ws/WebSocketManager';
import { type BrowserAction, setActivity } from './browserCommandTypes';
import {
handleScreenshot,
@@ -13,9 +13,6 @@ import {
handleEvaluate,
} from './browserActionHandlers';
export type { BrowserAction, BrowserActivity } from './browserCommandTypes';
export { getActivity, subscribeActivity, getActionLabel } from './browserCommandTypes';
let initialized = false;
async function handleBrowserCommand(data: Record<string, any>) {