From 4f74b232e205089801de8268c68608427f41a96f Mon Sep 17 00:00:00 2001 From: sawka Date: Fri, 2 Aug 2024 15:39:22 -0700 Subject: [PATCH] trap Shift:Cmd, and enable special blockmask action to show block indexes --- frontend/app/app.tsx | 50 ++++++++++++++++++++------ frontend/app/block/block.less | 19 ++++++++++ frontend/app/block/blockframe.tsx | 60 +++++++++++++++++++++++++------ frontend/app/store/global.ts | 2 ++ frontend/app/theme.less | 1 + frontend/types/custom.d.ts | 1 + 6 files changed, 112 insertions(+), 21 deletions(-) diff --git a/frontend/app/app.tsx b/frontend/app/app.tsx index efa1e738..a0409c77 100644 --- a/frontend/app/app.tsx +++ b/frontend/app/app.tsx @@ -332,20 +332,31 @@ function genericClose(tabId: string) { services.ObjectService.DeleteBlock(activeBlockId); } -const AppInner = () => { - const client = jotai.useAtomValue(atoms.client); - const windowData = jotai.useAtomValue(atoms.waveWindow); +const simpleCmdShiftAtom = jotai.atom(false); + +const AppKeyHandlers = () => { const tabId = jotai.useAtomValue(atoms.activeTabId); - if (client == null || windowData == null) { - return ( -
- - invalid configuration, client or window was not loaded -
- ); + + function handleKeyUp(event: KeyboardEvent) { + const waveEvent = keyutil.adaptFromReactOrNativeKeyEvent(event); + if (waveEvent.key == "Meta" || waveEvent.key == "Shift") { + globalStore.set(simpleCmdShiftAtom, false); + globalStore.set(atoms.cmdShiftDelayAtom, false); + } } function handleKeyDown(waveEvent: WaveKeyboardEvent): boolean { + if ((waveEvent.key == "Meta" || waveEvent.key == "Shift") && waveEvent.cmd && waveEvent.shift) { + globalStore.set(simpleCmdShiftAtom, true); + setTimeout(() => { + const simpleState = globalStore.get(simpleCmdShiftAtom); + if (simpleState) { + globalStore.set(atoms.cmdShiftDelayAtom, true); + } + }, 400); + return false; + } + // global key handler for now (refactor later) if (keyutil.checkKeyPressed(waveEvent, "Cmd:]") || keyutil.checkKeyPressed(waveEvent, "Shift:Cmd:]")) { switchTab(1); @@ -381,15 +392,34 @@ const AppInner = () => { React.useEffect(() => { const staticKeyDownHandler = keyutil.keydownWrapper(handleKeyDown); document.addEventListener("keydown", staticKeyDownHandler); + const savedKeyUpHandler = handleKeyUp; + document.addEventListener("keyup", savedKeyUpHandler); + return () => { document.removeEventListener("keydown", staticKeyDownHandler); + document.removeEventListener("keyup", savedKeyUpHandler); }; }, []); + return null; +}; + +const AppInner = () => { + const client = jotai.useAtomValue(atoms.client); + const windowData = jotai.useAtomValue(atoms.waveWindow); + if (client == null || windowData == null) { + return ( +
+ + invalid configuration, client or window was not loaded +
+ ); + } const isFullScreen = jotai.useAtomValue(atoms.isFullScreen); return (
+ diff --git a/frontend/app/block/block.less b/frontend/app/block/block.less index bdaca320..64a090c4 100644 --- a/frontend/app/block/block.less +++ b/frontend/app/block/block.less @@ -271,7 +271,26 @@ pointer-events: none; padding: 2px; border-radius: calc(var(--block-border-radius) + 2px); + z-index: var(--zindex-block-mask-inner); + + &.is-layoutmode .block-mask-inner { + margin-top: 35px; // TODO fix this magic + background-color: rgba(0, 0, 0, 0.5); + height: 100%; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + + .bignum { + margin-top: -15%; + font-size: 60px; + font-weight: bold; + opacity: 0.7; + } + } } + &.block-focused { .block-mask { border: 2px solid var(--accent-color); diff --git a/frontend/app/block/blockframe.tsx b/frontend/app/block/blockframe.tsx index 92ea79a5..50c447f8 100644 --- a/frontend/app/block/blockframe.tsx +++ b/frontend/app/block/blockframe.tsx @@ -6,6 +6,7 @@ import { Button } from "@/app/element/button"; import { ContextMenuModel } from "@/app/store/contextmenu"; import { atoms, globalStore, useBlockAtom, WOS } from "@/app/store/global"; import * as services from "@/app/store/services"; +import { LayoutTreeState } from "@/layout/index"; import { getLayoutStateAtomForTab } from "@/layout/lib/layoutAtom"; import { adaptFromReactOrNativeKeyEvent, checkKeyPressed } from "@/util/keyutil"; import { isBlockMagnified } from "@/util/layoututil"; @@ -221,6 +222,50 @@ function renderHeaderElements(headerTextUnion: HeaderElem[]): JSX.Element[] { return headerTextElems; } +function BlockNum({ blockId }: { blockId: string }) { + const tabId = jotai.useAtomValue(atoms.activeTabId); + const tabAtom = WOS.getWaveObjectAtom(WOS.makeORef("tab", tabId)); + const layoutTreeState: LayoutTreeState = globalStore.get(getLayoutStateAtomForTab(tabId, tabAtom)); + if (!layoutTreeState || !layoutTreeState.leafs) { + return null; + } + for (let idx = 0; idx < layoutTreeState.leafs.length; idx++) { + const leaf = layoutTreeState.leafs[idx]; + if (leaf?.data?.blockId == blockId) { + return String(idx + 1); + } + } + return null; +} + +const BlockMask = ({ blockId, preview, isFocused }: { blockId: string; preview: boolean; isFocused: boolean }) => { + const isLayoutMode = jotai.useAtomValue(atoms.cmdShiftDelayAtom); + const [blockData] = WOS.useWaveObjectValue(WOS.makeORef("block", blockId)); + + const style: React.CSSProperties = {}; + if (!isFocused && blockData?.meta?.["frame:bordercolor"]) { + style.borderColor = blockData.meta["frame:bordercolor"]; + } + if (isFocused && blockData?.meta?.["frame:bordercolor:focused"]) { + style.borderColor = blockData.meta["frame:bordercolor:focused"]; + } + let innerElem = null; + if (isLayoutMode) { + innerElem = ( +
+
+ +
+
+ ); + } + return ( +
+ {innerElem} +
+ ); +}; + const BlockFrame_Default_Component = (props: BlockFrameProps) => { const { blockId, layoutModel, viewModel, blockModel, preview, numBlocksInTab, children } = props; const [blockData] = WOS.useWaveObjectValue(WOS.makeORef("block", blockId)); @@ -230,19 +275,14 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => { return winData?.activeblockid === blockId; }); }); - let isFocused = jotai.useAtomValue(isFocusedAtom); const viewIconUnion = util.useAtomValueSafe(viewModel.viewIcon) ?? blockViewToIcon(blockData?.meta?.view); const customBg = util.useAtomValueSafe(viewModel.blockBg); + + let isFocused = jotai.useAtomValue(isFocusedAtom); if (preview) { isFocused = true; } - const style: React.CSSProperties = {}; - if (!isFocused && blockData?.meta?.["frame:bordercolor"]) { - style.borderColor = blockData.meta["frame:bordercolor"]; - } - if (isFocused && blockData?.meta?.["frame:bordercolor:focused"]) { - style.borderColor = blockData.meta["frame:bordercolor:focused"]; - } + const viewIconElem = getViewIconElem(viewIconUnion, blockData); function handleKeyDown(e: React.KeyboardEvent) { @@ -253,7 +293,6 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => { return; } } - const innerStyle: React.CSSProperties = {}; if (!preview && customBg?.bg != null) { innerStyle.background = customBg.bg; @@ -278,10 +317,9 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => { onClick={blockModel?.onClick} onFocusCapture={blockModel?.onFocusCapture} ref={blockModel?.blockRef} - style={style} onKeyDown={handleKeyDown} > -
+
{preview ? previewElem : children} diff --git a/frontend/app/store/global.ts b/frontend/app/store/global.ts index d19ae3ed..330fc08c 100644 --- a/frontend/app/store/global.ts +++ b/frontend/app/store/global.ts @@ -103,6 +103,7 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) { } return windowData.activetabid; }); + const cmdShiftDelayAtom = jotai.atom(false); atoms = { // initialized in wave.ts (will not be null inside of application) windowId: windowIdAtom, @@ -115,6 +116,7 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) { tabAtom: tabAtom, activeTabId: activeTabIdAtom, isFullScreen: isFullScreenAtom, + cmdShiftDelayAtom: cmdShiftDelayAtom, }; } diff --git a/frontend/app/theme.less b/frontend/app/theme.less index 0d655a4c..3ae59f0f 100644 --- a/frontend/app/theme.less +++ b/frontend/app/theme.less @@ -46,6 +46,7 @@ --zindex-tab-name: 3; --zindex-layout-placeholder-container: 1; --zindex-layout-overlay-container: 2; + --zindex-block-mask-inner: 10; // z-indexes in xterm.css // xterm-helpers: 5 diff --git a/frontend/types/custom.d.ts b/frontend/types/custom.d.ts index 9c59e606..ba8d797e 100644 --- a/frontend/types/custom.d.ts +++ b/frontend/types/custom.d.ts @@ -16,6 +16,7 @@ declare global { tabAtom: jotai.Atom; // driven from WOS activeTabId: jotai.Atom; // derrived from windowDataAtom isFullScreen: jotai.PrimitiveAtom; + cmdShiftDelayAtom: jotai.PrimitiveAtom; }; type TabLayoutData = {