mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-11 12:17:45 +02:00
[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:
@@ -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();
|
||||
|
||||
+2
-2
@@ -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>.",
|
||||
|
||||
+51
@@ -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;
|
||||
}
|
||||
+1
-49
@@ -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';
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import {
|
||||
getActivity,
|
||||
type BrowserActivity,
|
||||
type BrowserAction,
|
||||
} from './browserCommandHandler';
|
||||
} from '@/shared/browsers/browserCommandHandler/browserCommandTypes';
|
||||
|
||||
interface BrowserActivityState {
|
||||
active: boolean;
|
||||
+1
-1
@@ -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';
|
||||
|
||||
|
||||
+2
-2
@@ -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();
|
||||
+2
-5
@@ -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>) {
|
||||
Reference in New Issue
Block a user