[eric] shortcuts: Cmd+T new tab or browser, Cmd+W closes the focused card undoably, routed through main like Cmd+R

This commit is contained in:
ciregenz
2026-08-06 12:34:29 -07:00
parent 9d0562db22
commit 19926b5dea
4 changed files with 53 additions and 1 deletions
@@ -1,7 +1,7 @@
import React, { useEffect, type RefObject } from 'react';
import Box from '@mui/material/Box';
import { useAppDispatch, useAppSelector } from '@/shared/hooks';
import { addViewCard, clearTiledCard, toggleMinimizeCard, selectFullscreenCardId } from '@/shared/state/dashboardLayoutSlice';
import { addViewCard, addBrowserTab, clearTiledCard, toggleMinimizeCard, selectFullscreenCardId } from '@/shared/state/dashboardLayoutSlice';
import DashboardHeader from './DashboardHeader';
import TetherLayerHost from './TetherLayerHost';
import { useLiveMultiDrag } from '../hooks/interaction/useLiveMultiDrag';
@@ -33,6 +33,7 @@ import type { CardType, useDashboardSelection } from '../hooks/state/useDashboar
import type { useCanvasControls } from '../hooks/interaction/useCanvasControls';
import { useWebviewSuspend } from '../hooks/interaction/useWebviewSuspend';
import { deleteSelectedCards } from '../hooks/interaction/deleteSelectedCards';
import { getLastInteractedBrowser } from '@/shared/browserFocus';
import type { TetherInputs } from '../geometry/dashboardTethers';
type Selection = ReturnType<typeof useDashboardSelection>;
@@ -291,6 +292,23 @@ const DashboardCanvas: React.FC<DashboardCanvasProps> = ({
if (newestDeletable) deleteSelectedCards(new Map([[newestDeletable.id, newestDeletable.type]]), dispatch);
}, [selection, dispatch, newestDeletable]);
// Cmd/Ctrl+W and Cmd/Ctrl+T arrive as IPC echoes: main preventDefaults both before any DOM keydown
// (including from focused guests), so these bridges are the only firing path, no double-handling.
const browserHomepage = useAppSelector((st) => st.settings.data.browser_homepage ?? 'https://www.google.com');
React.useEffect(() => {
const w = window as unknown as { openswarm?: { onCloseShortcut?: (cb: () => void) => () => void; onNewTabShortcut?: (cb: () => void) => () => void } };
const offs: Array<() => void> = [];
if (w.openswarm?.onCloseShortcut) offs.push(w.openswarm.onCloseShortcut(() => handleDeleteSelected()));
if (w.openswarm?.onNewTabShortcut) {
offs.push(w.openswarm.onNewTabShortcut(() => {
const browserId = getLastInteractedBrowser();
if (browserId && browserCards[browserId]) dispatch(addBrowserTab({ browserId, url: browserHomepage, makeActive: true }));
else onAddBrowser();
}));
}
return () => { offs.forEach((off) => off()); };
}, [handleDeleteSelected, browserCards, browserHomepage, dispatch, onAddBrowser]);
// Gestures write the transform imperatively (no React commit per frame), so a foreign render mid-gesture would paint the stale committed transform for a frame. Re-applying live after EVERY render seals that; do not remove.
React.useLayoutEffect(() => {
canvas.actions.syncTransform();
+2
View File
@@ -76,6 +76,8 @@ declare global {
onUpdateError: (cb: (message: string) => void) => () => void;
onWebviewNewWindow: (cb: (url: string, webContentsId: number, disposition?: string) => void) => () => void;
onReloadShortcut?: (cb: () => void) => () => void;
onCloseShortcut?: (cb: () => void) => () => void;
onNewTabShortcut?: (cb: () => void) => () => void;
onBrowserShortcut?: (cb: (payload: { action: string; webContentsId: number }) => void) => () => void;
openExternal: (url: string) => Promise<void>;
harvestUsage?: (provider: string) => Promise<{ ok: boolean; total: number; titles: string[]; memories: string[] } | null>;