feat(app): add focus mode (Cmd+Shift+F) to show only the active pane
Hides ScreenHeader, LeftSidebar, and ExplorerSidebar on desktop, replacing the split layout with the single focused pane. Respects macOS traffic light padding in the tab bar when active. Shortcut is restricted to workspace screens. Also nudges traffic light buttons up 3px globally.
This commit is contained in:
@@ -265,6 +265,8 @@ function AppContainer({
|
|||||||
const toggleAgentList = usePanelStore((state) => state.toggleAgentList);
|
const toggleAgentList = usePanelStore((state) => state.toggleAgentList);
|
||||||
const toggleFileExplorer = usePanelStore((state) => state.toggleFileExplorer);
|
const toggleFileExplorer = usePanelStore((state) => state.toggleFileExplorer);
|
||||||
const toggleBothSidebars = usePanelStore((state) => state.toggleBothSidebars);
|
const toggleBothSidebars = usePanelStore((state) => state.toggleBothSidebars);
|
||||||
|
const toggleFocusMode = usePanelStore((state) => state.toggleFocusMode);
|
||||||
|
const isFocusModeEnabled = usePanelStore((state) => state.desktop.focusModeEnabled);
|
||||||
|
|
||||||
const isMobile = UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm";
|
const isMobile = UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm";
|
||||||
const chromeEnabled = chromeEnabledOverride ?? daemons.length > 0;
|
const chromeEnabled = chromeEnabledOverride ?? daemons.length > 0;
|
||||||
@@ -276,6 +278,7 @@ function AppContainer({
|
|||||||
selectedAgentId,
|
selectedAgentId,
|
||||||
toggleFileExplorer,
|
toggleFileExplorer,
|
||||||
toggleBothSidebars,
|
toggleBothSidebars,
|
||||||
|
toggleFocusMode,
|
||||||
});
|
});
|
||||||
|
|
||||||
const containerStyle = useMemo(
|
const containerStyle = useMemo(
|
||||||
@@ -286,7 +289,7 @@ function AppContainer({
|
|||||||
const content = (
|
const content = (
|
||||||
<View style={containerStyle}>
|
<View style={containerStyle}>
|
||||||
<View style={rowStyle}>
|
<View style={rowStyle}>
|
||||||
{!isMobile && chromeEnabled && <LeftSidebar selectedAgentId={selectedAgentId} />}
|
{!isMobile && chromeEnabled && !isFocusModeEnabled && <LeftSidebar selectedAgentId={selectedAgentId} />}
|
||||||
<View style={flexStyle}>{children}</View>
|
<View style={flexStyle}>{children}</View>
|
||||||
</View>
|
</View>
|
||||||
{isMobile && chromeEnabled && <LeftSidebar selectedAgentId={selectedAgentId} />}
|
{isMobile && chromeEnabled && <LeftSidebar selectedAgentId={selectedAgentId} />}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ import { Platform, View, Text } from "react-native";
|
|||||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||||
import { ResizeHandle } from "@/components/resize-handle";
|
import { ResizeHandle } from "@/components/resize-handle";
|
||||||
import { shouldFocusPaneFromEventTarget } from "@/components/split-container-pane-focus";
|
import { shouldFocusPaneFromEventTarget } from "@/components/split-container-pane-focus";
|
||||||
|
import { usePanelStore } from "@/stores/panel-store";
|
||||||
|
import { useTrafficLightPadding } from "@/utils/desktop-window";
|
||||||
import {
|
import {
|
||||||
computeTabDropPreview,
|
computeTabDropPreview,
|
||||||
type TabDropPreview,
|
type TabDropPreview,
|
||||||
@@ -109,6 +111,7 @@ interface SplitContainerProps {
|
|||||||
onResizeSplit: (groupId: string, sizes: number[]) => void;
|
onResizeSplit: (groupId: string, sizes: number[]) => void;
|
||||||
onReorderTabsInPane: (paneId: string, tabIds: string[]) => void;
|
onReorderTabsInPane: (paneId: string, tabIds: string[]) => void;
|
||||||
renderPaneEmptyState?: () => ReactNode;
|
renderPaneEmptyState?: () => ReactNode;
|
||||||
|
focusModeEnabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WorkspaceTabDragData {
|
interface WorkspaceTabDragData {
|
||||||
@@ -262,6 +265,7 @@ export function SplitContainer({
|
|||||||
onResizeSplit,
|
onResizeSplit,
|
||||||
onReorderTabsInPane,
|
onReorderTabsInPane,
|
||||||
renderPaneEmptyState = () => null,
|
renderPaneEmptyState = () => null,
|
||||||
|
focusModeEnabled,
|
||||||
}: SplitContainerProps) {
|
}: SplitContainerProps) {
|
||||||
const [activeDragTabId, setActiveDragTabId] = useState<string | null>(null);
|
const [activeDragTabId, setActiveDragTabId] = useState<string | null>(null);
|
||||||
const [dropPreview, setDropPreview] = useState<SplitDropZoneHover | null>(null);
|
const [dropPreview, setDropPreview] = useState<SplitDropZoneHover | null>(null);
|
||||||
@@ -280,6 +284,17 @@ export function SplitContainer({
|
|||||||
|
|
||||||
const panesById = useMemo(() => collectPanesById(layout.root), [layout.root]);
|
const panesById = useMemo(() => collectPanesById(layout.root), [layout.root]);
|
||||||
|
|
||||||
|
const effectiveRoot = useMemo(() => {
|
||||||
|
if (!focusModeEnabled) {
|
||||||
|
return layout.root;
|
||||||
|
}
|
||||||
|
const focusedPane = panesById.get(layout.focusedPaneId);
|
||||||
|
if (!focusedPane) {
|
||||||
|
return layout.root;
|
||||||
|
}
|
||||||
|
return { kind: "pane" as const, pane: focusedPane };
|
||||||
|
}, [focusModeEnabled, layout.root, layout.focusedPaneId, panesById]);
|
||||||
|
|
||||||
const handleDragStart = useCallback((event: DragStartEvent) => {
|
const handleDragStart = useCallback((event: DragStartEvent) => {
|
||||||
const data = event.active.data.current as WorkspaceTabDragData | undefined;
|
const data = event.active.data.current as WorkspaceTabDragData | undefined;
|
||||||
if (data?.kind !== "workspace-tab") {
|
if (data?.kind !== "workspace-tab") {
|
||||||
@@ -491,7 +506,7 @@ export function SplitContainer({
|
|||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
>
|
>
|
||||||
<SplitNodeView
|
<SplitNodeView
|
||||||
node={layout.root}
|
node={effectiveRoot}
|
||||||
workspaceKey={workspaceKey}
|
workspaceKey={workspaceKey}
|
||||||
uiTabs={uiTabs}
|
uiTabs={uiTabs}
|
||||||
focusedPaneId={layout.focusedPaneId}
|
focusedPaneId={layout.focusedPaneId}
|
||||||
@@ -781,6 +796,8 @@ function SplitPaneView({
|
|||||||
const { theme } = useUnistyles();
|
const { theme } = useUnistyles();
|
||||||
const paneRef = useRef<View | null>(null);
|
const paneRef = useRef<View | null>(null);
|
||||||
const stableOnFocusPane = useStableEvent(onFocusPane);
|
const stableOnFocusPane = useStableEvent(onFocusPane);
|
||||||
|
const isFocusModeEnabled = usePanelStore((s) => s.desktop.focusModeEnabled);
|
||||||
|
const trafficLightPadding = useTrafficLightPadding();
|
||||||
const paneState = useMemo(
|
const paneState = useMemo(
|
||||||
() =>
|
() =>
|
||||||
deriveWorkspacePaneState({
|
deriveWorkspacePaneState({
|
||||||
@@ -852,7 +869,13 @@ function SplitPaneView({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View ref={paneRef} collapsable={false} style={styles.pane}>
|
<View ref={paneRef} collapsable={false} style={styles.pane}>
|
||||||
<View style={styles.paneTabs}>
|
<View
|
||||||
|
style={[
|
||||||
|
styles.paneTabs,
|
||||||
|
isFocusModeEnabled &&
|
||||||
|
trafficLightPadding.left > 0 && { paddingLeft: trafficLightPadding.left },
|
||||||
|
]}
|
||||||
|
>
|
||||||
<WorkspaceDesktopTabsRow
|
<WorkspaceDesktopTabsRow
|
||||||
paneId={pane.id}
|
paneId={pane.id}
|
||||||
isFocused={isFocused}
|
isFocused={isFocused}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export function useKeyboardShortcuts({
|
|||||||
selectedAgentId,
|
selectedAgentId,
|
||||||
toggleFileExplorer,
|
toggleFileExplorer,
|
||||||
toggleBothSidebars,
|
toggleBothSidebars,
|
||||||
|
toggleFocusMode,
|
||||||
}: {
|
}: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
isMobile: boolean;
|
isMobile: boolean;
|
||||||
@@ -41,6 +42,7 @@ export function useKeyboardShortcuts({
|
|||||||
selectedAgentId?: string;
|
selectedAgentId?: string;
|
||||||
toggleFileExplorer?: () => void;
|
toggleFileExplorer?: () => void;
|
||||||
toggleBothSidebars?: () => void;
|
toggleBothSidebars?: () => void;
|
||||||
|
toggleFocusMode?: () => void;
|
||||||
}) {
|
}) {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const hosts = useHosts();
|
const hosts = useHosts();
|
||||||
@@ -250,6 +252,11 @@ export function useKeyboardShortcuts({
|
|||||||
}
|
}
|
||||||
toggleFileExplorer();
|
toggleFileExplorer();
|
||||||
return true;
|
return true;
|
||||||
|
case "view.toggle.focus":
|
||||||
|
if (toggleFocusMode) {
|
||||||
|
toggleFocusMode();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
case "command-center.toggle": {
|
case "command-center.toggle": {
|
||||||
const store = useKeyboardShortcutsStore.getState();
|
const store = useKeyboardShortcutsStore.getState();
|
||||||
if (!store.commandCenterOpen) {
|
if (!store.commandCenterOpen) {
|
||||||
@@ -404,5 +411,6 @@ export function useKeyboardShortcuts({
|
|||||||
selectedAgentId,
|
selectedAgentId,
|
||||||
toggleAgentList,
|
toggleAgentList,
|
||||||
toggleFileExplorer,
|
toggleFileExplorer,
|
||||||
|
toggleFocusMode,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export type KeyboardActionId =
|
|||||||
| "workspace.terminal.new"
|
| "workspace.terminal.new"
|
||||||
| "worktree.new"
|
| "worktree.new"
|
||||||
| "worktree.archive"
|
| "worktree.archive"
|
||||||
|
| "view.toggle.focus"
|
||||||
| "message-input.action";
|
| "message-input.action";
|
||||||
|
|
||||||
export type KeyboardShortcutPayload =
|
export type KeyboardShortcutPayload =
|
||||||
|
|||||||
@@ -718,6 +718,32 @@ const SHORTCUT_BINDINGS: readonly ShortcutBinding[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// --- Focus mode ---
|
||||||
|
{
|
||||||
|
id: "view-toggle-focus-cmd-shift-f-mac",
|
||||||
|
action: "view.toggle.focus",
|
||||||
|
combo: "Cmd+Shift+F",
|
||||||
|
when: { mac: true, hasSelectedAgent: true, commandCenter: false },
|
||||||
|
help: {
|
||||||
|
id: "toggle-focus",
|
||||||
|
section: "panels",
|
||||||
|
label: "Toggle focus mode",
|
||||||
|
keys: ["mod", "shift", "F"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "view-toggle-focus-ctrl-shift-f-non-mac",
|
||||||
|
action: "view.toggle.focus",
|
||||||
|
combo: "Ctrl+Shift+F",
|
||||||
|
when: { mac: false, hasSelectedAgent: true, commandCenter: false, terminal: false },
|
||||||
|
help: {
|
||||||
|
id: "toggle-focus",
|
||||||
|
section: "panels",
|
||||||
|
label: "Toggle focus mode",
|
||||||
|
keys: ["mod", "shift", "F"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
// --- Message input ---
|
// --- Message input ---
|
||||||
{
|
{
|
||||||
id: "message-input-voice-toggle-cmd-shift-d-mac",
|
id: "message-input-voice-toggle-cmd-shift-d-mac",
|
||||||
|
|||||||
@@ -550,6 +550,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
|
|||||||
const mainBackgroundColor = isDarkMode ? theme.colors.surface1 : theme.colors.surface0;
|
const mainBackgroundColor = isDarkMode ? theme.colors.surface1 : theme.colors.surface0;
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const isMobile = UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm";
|
const isMobile = UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm";
|
||||||
|
const isFocusModeEnabled = usePanelStore((state) => state.desktop.focusModeEnabled);
|
||||||
|
|
||||||
const normalizedServerId = trimNonEmpty(decodeSegment(serverId)) ?? "";
|
const normalizedServerId = trimNonEmpty(decodeSegment(serverId)) ?? "";
|
||||||
const normalizedWorkspaceId =
|
const normalizedWorkspaceId =
|
||||||
@@ -1949,6 +1950,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
|
|||||||
) : null}
|
) : null}
|
||||||
<View style={styles.threePaneRow}>
|
<View style={styles.threePaneRow}>
|
||||||
<View style={styles.centerColumn}>
|
<View style={styles.centerColumn}>
|
||||||
|
{(!isFocusModeEnabled || isMobile) && (
|
||||||
<ScreenHeader
|
<ScreenHeader
|
||||||
left={
|
left={
|
||||||
<>
|
<>
|
||||||
@@ -2135,6 +2137,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
|
|||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
<MobileWorkspaceTabSwitcher
|
<MobileWorkspaceTabSwitcher
|
||||||
@@ -2165,6 +2168,7 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
|
|||||||
{workspaceLayout && persistenceKey ? (
|
{workspaceLayout && persistenceKey ? (
|
||||||
<SplitContainer
|
<SplitContainer
|
||||||
layout={workspaceLayout}
|
layout={workspaceLayout}
|
||||||
|
focusModeEnabled={isFocusModeEnabled && !isMobile}
|
||||||
workspaceKey={persistenceKey}
|
workspaceKey={persistenceKey}
|
||||||
normalizedServerId={normalizedServerId}
|
normalizedServerId={normalizedServerId}
|
||||||
normalizedWorkspaceId={normalizedWorkspaceId}
|
normalizedWorkspaceId={normalizedWorkspaceId}
|
||||||
@@ -2200,13 +2204,15 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<ExplorerSidebar
|
{(!isFocusModeEnabled || isMobile) && (
|
||||||
serverId={normalizedServerId}
|
<ExplorerSidebar
|
||||||
workspaceId={normalizedWorkspaceId}
|
serverId={normalizedServerId}
|
||||||
workspaceRoot={normalizedWorkspaceId}
|
workspaceId={normalizedWorkspaceId}
|
||||||
isGit={isGitCheckout}
|
workspaceRoot={normalizedWorkspaceId}
|
||||||
onOpenFile={handleOpenFileFromExplorer}
|
isGit={isGitCheckout}
|
||||||
/>
|
onOpenFile={handleOpenFileFromExplorer}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ type MobilePanelView = "agent" | "agent-list" | "file-explorer";
|
|||||||
interface DesktopSidebarState {
|
interface DesktopSidebarState {
|
||||||
agentListOpen: boolean;
|
agentListOpen: boolean;
|
||||||
fileExplorerOpen: boolean;
|
fileExplorerOpen: boolean;
|
||||||
|
focusModeEnabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SortOption = "name" | "modified" | "size";
|
export type SortOption = "name" | "modified" | "size";
|
||||||
@@ -79,6 +80,7 @@ interface PanelState {
|
|||||||
toggleAgentList: () => void;
|
toggleAgentList: () => void;
|
||||||
toggleFileExplorer: () => void;
|
toggleFileExplorer: () => void;
|
||||||
toggleBothSidebars: () => void;
|
toggleBothSidebars: () => void;
|
||||||
|
toggleFocusMode: () => void;
|
||||||
|
|
||||||
// File explorer settings actions
|
// File explorer settings actions
|
||||||
setExplorerTab: (tab: ExplorerTab) => void;
|
setExplorerTab: (tab: ExplorerTab) => void;
|
||||||
@@ -134,6 +136,7 @@ export const usePanelStore = create<PanelState>()(
|
|||||||
desktop: {
|
desktop: {
|
||||||
agentListOpen: DEFAULT_DESKTOP_OPEN,
|
agentListOpen: DEFAULT_DESKTOP_OPEN,
|
||||||
fileExplorerOpen: false,
|
fileExplorerOpen: false,
|
||||||
|
focusModeEnabled: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// File explorer defaults
|
// File explorer defaults
|
||||||
@@ -175,6 +178,7 @@ export const usePanelStore = create<PanelState>()(
|
|||||||
// On desktop, closing depends on which panel triggered it
|
// On desktop, closing depends on which panel triggered it
|
||||||
// This is called when closing via gesture/backdrop, so we close the currently active mobile panel
|
// This is called when closing via gesture/backdrop, so we close the currently active mobile panel
|
||||||
desktop: {
|
desktop: {
|
||||||
|
...state.desktop,
|
||||||
agentListOpen: state.mobileView === "agent-list" ? false : state.desktop.agentListOpen,
|
agentListOpen: state.mobileView === "agent-list" ? false : state.desktop.agentListOpen,
|
||||||
fileExplorerOpen:
|
fileExplorerOpen:
|
||||||
state.mobileView === "file-explorer" ? false : state.desktop.fileExplorerOpen,
|
state.mobileView === "file-explorer" ? false : state.desktop.fileExplorerOpen,
|
||||||
@@ -217,6 +221,11 @@ export const usePanelStore = create<PanelState>()(
|
|||||||
return nextState;
|
return nextState;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
toggleFocusMode: () =>
|
||||||
|
set((state) => ({
|
||||||
|
desktop: { ...state.desktop, focusModeEnabled: !state.desktop.focusModeEnabled },
|
||||||
|
})),
|
||||||
|
|
||||||
toggleBothSidebars: () =>
|
toggleBothSidebars: () =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
// If either sidebar is open, close both. Otherwise, open both.
|
// If either sidebar is open, close both. Otherwise, open both.
|
||||||
@@ -224,13 +233,13 @@ export const usePanelStore = create<PanelState>()(
|
|||||||
if (anyOpen) {
|
if (anyOpen) {
|
||||||
return {
|
return {
|
||||||
mobileView: "agent" as MobilePanelView,
|
mobileView: "agent" as MobilePanelView,
|
||||||
desktop: { agentListOpen: false, fileExplorerOpen: false },
|
desktop: { ...state.desktop, agentListOpen: false, fileExplorerOpen: false },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const resolvedTab = resolveExplorerTabFromActiveCheckout(state);
|
const resolvedTab = resolveExplorerTabFromActiveCheckout(state);
|
||||||
return {
|
return {
|
||||||
mobileView: "agent" as MobilePanelView,
|
mobileView: "agent" as MobilePanelView,
|
||||||
desktop: { agentListOpen: true, fileExplorerOpen: true },
|
desktop: { ...state.desktop, agentListOpen: true, fileExplorerOpen: true },
|
||||||
...(resolvedTab ? { explorerTab: resolvedTab } : {}),
|
...(resolvedTab ? { explorerTab: resolvedTab } : {}),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
@@ -286,7 +295,7 @@ export const usePanelStore = create<PanelState>()(
|
|||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: "panel-state",
|
name: "panel-state",
|
||||||
version: 6,
|
version: 8,
|
||||||
storage: createJSONStorage(() => AsyncStorage),
|
storage: createJSONStorage(() => AsyncStorage),
|
||||||
migrate: (persistedState, version) => {
|
migrate: (persistedState, version) => {
|
||||||
const state = persistedState as Partial<PanelState> & Record<string, unknown>;
|
const state = persistedState as Partial<PanelState> & Record<string, unknown>;
|
||||||
@@ -341,6 +350,23 @@ export const usePanelStore = create<PanelState>()(
|
|||||||
state.explorerTabByCheckout = next;
|
state.explorerTabByCheckout = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (version < 8) {
|
||||||
|
const desktop = state.desktop as Record<string, unknown> | undefined;
|
||||||
|
if (desktop) {
|
||||||
|
if ("zoomed" in desktop) {
|
||||||
|
desktop.focusModeEnabled = desktop.zoomed;
|
||||||
|
delete desktop.zoomed;
|
||||||
|
}
|
||||||
|
if ("focused" in desktop) {
|
||||||
|
desktop.focusModeEnabled = desktop.focused;
|
||||||
|
delete desktop.focused;
|
||||||
|
}
|
||||||
|
if (typeof desktop.focusModeEnabled !== "boolean") {
|
||||||
|
desktop.focusModeEnabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (version < 6 || typeof state.sidebarWidth !== "number") {
|
if (version < 6 || typeof state.sidebarWidth !== "number") {
|
||||||
state.sidebarWidth = DEFAULT_SIDEBAR_WIDTH;
|
state.sidebarWidth = DEFAULT_SIDEBAR_WIDTH;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ async function createMainWindow(): Promise<void> {
|
|||||||
show: false,
|
show: false,
|
||||||
...(iconPath ? { icon: iconPath } : {}),
|
...(iconPath ? { icon: iconPath } : {}),
|
||||||
titleBarStyle: isMac ? "hidden" : "default",
|
titleBarStyle: isMac ? "hidden" : "default",
|
||||||
trafficLightPosition: isMac ? { x: 16, y: 17 } : undefined,
|
trafficLightPosition: isMac ? { x: 16, y: 14 } : undefined,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: getPreloadPath(),
|
preload: getPreloadPath(),
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user