trap Shift:Cmd, and enable special blockmask action to show block indexes

This commit is contained in:
sawka 2024-08-02 15:39:22 -07:00
parent 6ebc2e44c3
commit 4f74b232e2
6 changed files with 112 additions and 21 deletions

View File

@ -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 (
<div className="mainapp">
<AppBackground />
<CenteredDiv>invalid configuration, client or window was not loaded</CenteredDiv>
</div>
);
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 (
<div className="mainapp">
<AppBackground />
<CenteredDiv>invalid configuration, client or window was not loaded</CenteredDiv>
</div>
);
}
const isFullScreen = jotai.useAtomValue(atoms.isFullScreen);
return (
<div className={clsx("mainapp", PLATFORM, { fullscreen: isFullScreen })} onContextMenu={handleContextMenu}>
<AppBackground />
<AppKeyHandlers />
<AppSettingsUpdater />
<DndProvider backend={HTML5Backend}>
<Workspace />

View File

@ -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);

View File

@ -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<Tab>(WOS.makeORef("tab", tabId));
const layoutTreeState: LayoutTreeState<TabLayoutData> = 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<Block>(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 = (
<div className="block-mask-inner">
<div className="bignum">
<BlockNum blockId={blockId} />
</div>
</div>
);
}
return (
<div className={clsx("block-mask", { "is-layoutmode": isLayoutMode })} style={style}>
{innerElem}
</div>
);
};
const BlockFrame_Default_Component = (props: BlockFrameProps) => {
const { blockId, layoutModel, viewModel, blockModel, preview, numBlocksInTab, children } = props;
const [blockData] = WOS.useWaveObjectValue<Block>(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<HTMLDivElement>) {
@ -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}
>
<div className="block-mask"></div>
<BlockMask blockId={blockId} preview={preview} isFocused={isFocused} />
<div className="block-frame-default-inner" style={innerStyle}>
<BlockFrame_Header {...props} />
{preview ? previewElem : children}

View File

@ -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,
};
}

View File

@ -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

View File

@ -16,6 +16,7 @@ declare global {
tabAtom: jotai.Atom<Tab>; // driven from WOS
activeTabId: jotai.Atom<string>; // derrived from windowDataAtom
isFullScreen: jotai.PrimitiveAtom<boolean>;
cmdShiftDelayAtom: jotai.PrimitiveAtom<boolean>;
};
type TabLayoutData = {