mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-04 18:59:08 +01:00
implement Cmd-I and restructure block viewmodels (#257)
This commit is contained in:
parent
7df91de2e5
commit
dedfc31344
@ -1,7 +1,7 @@
|
|||||||
// Copyright 2024, Command Line Inc.
|
// Copyright 2024, Command Line Inc.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import { atoms, createBlock, globalStore, setBlockFocus, WOS } from "@/app/store/global";
|
import { atoms, createBlock, getViewModel, globalStore, setBlockFocus, WOS } from "@/app/store/global";
|
||||||
import { deleteLayoutModelForTab, getLayoutModelForTab } from "@/layout/index";
|
import { deleteLayoutModelForTab, getLayoutModelForTab } from "@/layout/index";
|
||||||
import * as services from "@/store/services";
|
import * as services from "@/store/services";
|
||||||
import * as keyutil from "@/util/keyutil";
|
import * as keyutil from "@/util/keyutil";
|
||||||
@ -225,6 +225,25 @@ async function handleCmdT() {
|
|||||||
setBlockFocus(newBlockId);
|
setBlockFocus(newBlockId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleCmdI() {
|
||||||
|
const waveWindow = globalStore.get(atoms.waveWindow);
|
||||||
|
if (waveWindow == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let activeBlockId = waveWindow.activeblockid;
|
||||||
|
if (activeBlockId == null) {
|
||||||
|
// get the first block
|
||||||
|
const tabData = globalStore.get(atoms.tabAtom);
|
||||||
|
const firstBlockId = tabData.blockids?.length == 0 ? null : tabData.blockids[0];
|
||||||
|
if (firstBlockId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
activeBlockId = firstBlockId;
|
||||||
|
}
|
||||||
|
const viewModel = getViewModel(activeBlockId);
|
||||||
|
viewModel?.giveFocus?.();
|
||||||
|
}
|
||||||
|
|
||||||
function appHandleKeyDown(waveEvent: WaveKeyboardEvent): boolean {
|
function appHandleKeyDown(waveEvent: WaveKeyboardEvent): boolean {
|
||||||
if (waveEvent.key === "Control" || waveEvent.key === "Shift" || waveEvent.key === "Meta") {
|
if (waveEvent.key === "Control" || waveEvent.key === "Shift" || waveEvent.key === "Meta") {
|
||||||
if (waveEvent.control && waveEvent.shift && !waveEvent.meta) {
|
if (waveEvent.control && waveEvent.shift && !waveEvent.meta) {
|
||||||
@ -251,6 +270,10 @@ function appHandleKeyDown(waveEvent: WaveKeyboardEvent): boolean {
|
|||||||
handleCmdT();
|
handleCmdT();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (keyutil.checkKeyPressed(waveEvent, "Cmd:i")) {
|
||||||
|
handleCmdI();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (keyutil.checkKeyPressed(waveEvent, "Cmd:t")) {
|
if (keyutil.checkKeyPressed(waveEvent, "Cmd:t")) {
|
||||||
const workspace = globalStore.get(atoms.workspace);
|
const workspace = globalStore.get(atoms.workspace);
|
||||||
const newTabName = `T${workspace.tabids.length + 1}`;
|
const newTabName = `T${workspace.tabids.length + 1}`;
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
// Copyright 2024, Command Line Inc.
|
// Copyright 2024, Command Line Inc.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import { BlockComponentModel, BlockProps } from "@/app/block/blocktypes";
|
import { BlockComponentModel, BlockProps, LayoutComponentModel } from "@/app/block/blocktypes";
|
||||||
import { PlotView } from "@/app/view/plotview/plotview";
|
import { PlotView } from "@/app/view/plotview/plotview";
|
||||||
import { PreviewView, makePreviewModel } from "@/app/view/preview/preview";
|
import { PreviewModel, PreviewView, makePreviewModel } from "@/app/view/preview/preview";
|
||||||
import { ErrorBoundary } from "@/element/errorboundary";
|
import { ErrorBoundary } from "@/element/errorboundary";
|
||||||
import { CenteredDiv } from "@/element/quickelems";
|
import { CenteredDiv } from "@/element/quickelems";
|
||||||
import { atoms, setBlockFocus, useBlockAtom } from "@/store/global";
|
import { atoms, counterInc, registerViewModel, setBlockFocus, unregisterViewModel, useBlockAtom } from "@/store/global";
|
||||||
import * as WOS from "@/store/wos";
|
import * as WOS from "@/store/wos";
|
||||||
import * as util from "@/util/util";
|
import * as util from "@/util/util";
|
||||||
import { CpuPlotView, makeCpuPlotViewModel } from "@/view/cpuplot/cpuplot";
|
import { CpuPlotView, CpuPlotViewModel, makeCpuPlotViewModel } from "@/view/cpuplot/cpuplot";
|
||||||
import { HelpView } from "@/view/helpview/helpview";
|
import { HelpView } from "@/view/helpview/helpview";
|
||||||
import { TerminalView, makeTerminalModel } from "@/view/term/term";
|
import { TermViewModel, TerminalView, makeTerminalModel } from "@/view/term/term";
|
||||||
import { WaveAi, makeWaveAiViewModel } from "@/view/waveai/waveai";
|
import { WaveAi, WaveAiModel, makeWaveAiViewModel } from "@/view/waveai/waveai";
|
||||||
import { WebView, makeWebViewModel } from "@/view/webview/webview";
|
import { WebView, WebViewModel, makeWebViewModel } from "@/view/webview/webview";
|
||||||
import * as jotai from "jotai";
|
import * as jotai from "jotai";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { BlockFrame } from "./blockframe";
|
import { BlockFrame } from "./blockframe";
|
||||||
@ -21,47 +21,58 @@ import { blockViewToIcon, blockViewToName } from "./blockutil";
|
|||||||
|
|
||||||
import "./block.less";
|
import "./block.less";
|
||||||
|
|
||||||
function getViewElemAndModel(
|
type FullBlockProps = {
|
||||||
blockId: string,
|
blockId: string;
|
||||||
blockView: string,
|
preview: boolean;
|
||||||
blockRef: React.RefObject<HTMLDivElement>
|
layoutModel: LayoutComponentModel;
|
||||||
): { viewModel: ViewModel; viewElem: JSX.Element } {
|
viewModel: ViewModel;
|
||||||
let viewElem: JSX.Element = null;
|
};
|
||||||
let viewModel: ViewModel = null;
|
|
||||||
|
function makeViewModel(blockId: string, blockView: string): ViewModel {
|
||||||
|
if (blockView === "term") {
|
||||||
|
return makeTerminalModel(blockId);
|
||||||
|
}
|
||||||
|
if (blockView === "preview") {
|
||||||
|
return makePreviewModel(blockId);
|
||||||
|
}
|
||||||
|
if (blockView === "web") {
|
||||||
|
return makeWebViewModel(blockId);
|
||||||
|
}
|
||||||
|
if (blockView === "waveai") {
|
||||||
|
return makeWaveAiViewModel(blockId);
|
||||||
|
}
|
||||||
|
if (blockView === "cpuplot") {
|
||||||
|
return makeCpuPlotViewModel(blockId);
|
||||||
|
}
|
||||||
|
return makeDefaultViewModel(blockId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getViewElem(blockId: string, blockView: string, viewModel: ViewModel): JSX.Element {
|
||||||
if (util.isBlank(blockView)) {
|
if (util.isBlank(blockView)) {
|
||||||
viewElem = <CenteredDiv>No View</CenteredDiv>;
|
return <CenteredDiv>No View</CenteredDiv>;
|
||||||
viewModel = makeDefaultViewModel(blockId);
|
|
||||||
} else if (blockView === "term") {
|
|
||||||
const termViewModel = makeTerminalModel(blockId);
|
|
||||||
viewElem = <TerminalView key={blockId} blockId={blockId} model={termViewModel} />;
|
|
||||||
viewModel = termViewModel;
|
|
||||||
} else if (blockView === "preview") {
|
|
||||||
const previewModel = makePreviewModel(blockId);
|
|
||||||
viewElem = <PreviewView key={blockId} blockId={blockId} model={previewModel} />;
|
|
||||||
viewModel = previewModel;
|
|
||||||
} else if (blockView === "plot") {
|
|
||||||
viewElem = <PlotView key={blockId} />;
|
|
||||||
} else if (blockView === "web") {
|
|
||||||
const webviewModel = makeWebViewModel(blockId);
|
|
||||||
viewElem = <WebView key={blockId} parentRef={blockRef} model={webviewModel} />;
|
|
||||||
viewModel = webviewModel;
|
|
||||||
} else if (blockView === "waveai") {
|
|
||||||
const waveAiModel = makeWaveAiViewModel(blockId);
|
|
||||||
viewElem = <WaveAi key={blockId} model={waveAiModel} />;
|
|
||||||
viewModel = waveAiModel;
|
|
||||||
} else if (blockView === "cpuplot") {
|
|
||||||
const cpuPlotModel = makeCpuPlotViewModel(blockId);
|
|
||||||
viewElem = <CpuPlotView key={blockId} model={cpuPlotModel} />;
|
|
||||||
viewModel = cpuPlotModel;
|
|
||||||
} else if (blockView == "help") {
|
|
||||||
viewElem = <HelpView key={blockId} />;
|
|
||||||
viewModel = makeDefaultViewModel(blockId);
|
|
||||||
}
|
}
|
||||||
if (viewModel == null) {
|
if (blockView === "term") {
|
||||||
viewElem = <CenteredDiv>Invalid View "{blockView}"</CenteredDiv>;
|
return <TerminalView key={blockId} blockId={blockId} model={viewModel as TermViewModel} />;
|
||||||
viewModel = makeDefaultViewModel(blockId);
|
|
||||||
}
|
}
|
||||||
return { viewElem, viewModel };
|
if (blockView === "preview") {
|
||||||
|
return <PreviewView key={blockId} blockId={blockId} model={viewModel as PreviewModel} />;
|
||||||
|
}
|
||||||
|
if (blockView === "plot") {
|
||||||
|
return <PlotView key={blockId} />;
|
||||||
|
}
|
||||||
|
if (blockView === "web") {
|
||||||
|
return <WebView key={blockId} blockId={blockId} model={viewModel as WebViewModel} />;
|
||||||
|
}
|
||||||
|
if (blockView === "waveai") {
|
||||||
|
return <WaveAi key={blockId} blockId={blockId} model={viewModel as WaveAiModel} />;
|
||||||
|
}
|
||||||
|
if (blockView === "cpuplot") {
|
||||||
|
return <CpuPlotView key={blockId} blockId={blockId} model={viewModel as CpuPlotViewModel} />;
|
||||||
|
}
|
||||||
|
if (blockView == "help") {
|
||||||
|
return <HelpView key={blockId} blockId={blockId} />;
|
||||||
|
}
|
||||||
|
return <CenteredDiv>Invalid View "{blockView}"</CenteredDiv>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeDefaultViewModel(blockId: string): ViewModel {
|
function makeDefaultViewModel(blockId: string): ViewModel {
|
||||||
@ -85,12 +96,11 @@ function makeDefaultViewModel(blockId: string): ViewModel {
|
|||||||
return viewModel;
|
return viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BlockPreview = React.memo(({ blockId, layoutModel }: BlockProps) => {
|
const BlockPreview = React.memo(({ blockId, layoutModel, viewModel }: FullBlockProps) => {
|
||||||
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
||||||
if (!blockData) {
|
if (!blockData) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let { viewModel } = getViewElemAndModel(blockId, blockData?.meta?.view, null);
|
|
||||||
return (
|
return (
|
||||||
<BlockFrame
|
<BlockFrame
|
||||||
key={blockId}
|
key={blockId}
|
||||||
@ -103,11 +113,12 @@ const BlockPreview = React.memo(({ blockId, layoutModel }: BlockProps) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const BlockFull = React.memo(({ blockId, layoutModel }: BlockProps) => {
|
const BlockFull = React.memo(({ blockId, layoutModel, viewModel }: FullBlockProps) => {
|
||||||
|
counterInc("render-BlockFull");
|
||||||
const focusElemRef = React.useRef<HTMLInputElement>(null);
|
const focusElemRef = React.useRef<HTMLInputElement>(null);
|
||||||
const blockRef = React.useRef<HTMLDivElement>(null);
|
const blockRef = React.useRef<HTMLDivElement>(null);
|
||||||
const [blockClicked, setBlockClicked] = React.useState(false);
|
const [blockClicked, setBlockClicked] = React.useState(false);
|
||||||
const [blockData, blockDataLoading] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
||||||
const [focusedChild, setFocusedChild] = React.useState(null);
|
const [focusedChild, setFocusedChild] = React.useState(null);
|
||||||
const isFocusedAtom = useBlockAtom<boolean>(blockId, "isFocused", () => {
|
const isFocusedAtom = useBlockAtom<boolean>(blockId, "isFocused", () => {
|
||||||
return jotai.atom((get) => {
|
return jotai.atom((get) => {
|
||||||
@ -145,9 +156,9 @@ const BlockFull = React.memo(({ blockId, layoutModel }: BlockProps) => {
|
|||||||
setBlockClicked(true);
|
setBlockClicked(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
let { viewElem, viewModel } = React.useMemo(
|
let viewElem = React.useMemo(
|
||||||
() => getViewElemAndModel(blockId, blockData?.meta?.view, blockRef),
|
() => getViewElem(blockId, blockData?.meta?.view, viewModel),
|
||||||
[blockId, blockData?.meta?.view, blockRef]
|
[blockId, blockData?.meta?.view, viewModel]
|
||||||
);
|
);
|
||||||
|
|
||||||
const determineFocusedChild = React.useCallback(
|
const determineFocusedChild = React.useCallback(
|
||||||
@ -165,11 +176,6 @@ const BlockFull = React.memo(({ blockId, layoutModel }: BlockProps) => {
|
|||||||
focusElemRef.current?.focus({ preventScroll: true });
|
focusElemRef.current?.focus({ preventScroll: true });
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!blockId || !blockData) return null;
|
|
||||||
|
|
||||||
if (blockDataLoading) {
|
|
||||||
viewElem = <CenteredDiv>Loading...</CenteredDiv>;
|
|
||||||
}
|
|
||||||
const blockModel: BlockComponentModel = {
|
const blockModel: BlockComponentModel = {
|
||||||
onClick: setBlockClickedTrue,
|
onClick: setBlockClickedTrue,
|
||||||
onFocusCapture: determineFocusedChild,
|
onFocusCapture: determineFocusedChild,
|
||||||
@ -202,10 +208,25 @@ const BlockFull = React.memo(({ blockId, layoutModel }: BlockProps) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const Block = React.memo((props: BlockProps) => {
|
const Block = React.memo((props: BlockProps) => {
|
||||||
if (props.preview) {
|
counterInc("render-Block");
|
||||||
return <BlockPreview {...props} />;
|
counterInc("render-Block-" + props.blockId.substring(0, 8));
|
||||||
|
const [blockData, loading] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", props.blockId));
|
||||||
|
const viewModel = makeViewModel(props.blockId, blockData?.meta?.view);
|
||||||
|
React.useEffect(() => {
|
||||||
|
registerViewModel(props.blockId, viewModel);
|
||||||
|
}, [blockData?.meta?.view]);
|
||||||
|
React.useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
unregisterViewModel(props.blockId);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
if (loading || util.isBlank(props.blockId) || blockData == null) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return <BlockFull {...props} />;
|
if (props.preview) {
|
||||||
|
return <BlockPreview {...props} viewModel={viewModel} />;
|
||||||
|
}
|
||||||
|
return <BlockFull {...props} viewModel={viewModel} />;
|
||||||
});
|
});
|
||||||
|
|
||||||
export { Block };
|
export { Block };
|
||||||
|
@ -23,6 +23,8 @@ let PLATFORM: NodeJS.Platform = "darwin";
|
|||||||
const globalStore = jotai.createStore();
|
const globalStore = jotai.createStore();
|
||||||
let atoms: GlobalAtomsType;
|
let atoms: GlobalAtomsType;
|
||||||
let globalEnvironment: "electron" | "renderer";
|
let globalEnvironment: "electron" | "renderer";
|
||||||
|
const blockViewModelMap = new Map<string, ViewModel>();
|
||||||
|
const Counters = new Map<string, number>();
|
||||||
|
|
||||||
type GlobalInitOptions = {
|
type GlobalInitOptions = {
|
||||||
platform: NodeJS.Platform;
|
platform: NodeJS.Platform;
|
||||||
@ -238,6 +240,13 @@ function useBlockAtom<T>(blockId: string, name: string, makeFn: () => jotai.Atom
|
|||||||
return atom as jotai.Atom<T>;
|
return atom as jotai.Atom<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useBlockDataLoaded(blockId: string): boolean {
|
||||||
|
const loadedAtom = useBlockAtom<boolean>(blockId, "block-loaded", () => {
|
||||||
|
return WOS.getWaveObjectLoadingAtom(WOS.makeORef("block", blockId));
|
||||||
|
});
|
||||||
|
return jotai.useAtomValue(loadedAtom);
|
||||||
|
}
|
||||||
|
|
||||||
let globalWS: WSControl = null;
|
let globalWS: WSControl = null;
|
||||||
|
|
||||||
function handleWSEventMessage(msg: WSEventType) {
|
function handleWSEventMessage(msg: WSEventType) {
|
||||||
@ -455,8 +464,41 @@ async function openLink(uri: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function registerViewModel(blockId: string, viewModel: ViewModel) {
|
||||||
|
blockViewModelMap.set(blockId, viewModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
function unregisterViewModel(blockId: string) {
|
||||||
|
blockViewModelMap.delete(blockId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getViewModel(blockId: string): ViewModel {
|
||||||
|
return blockViewModelMap.get(blockId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function countersClear() {
|
||||||
|
Counters.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
function counterInc(name: string, incAmt: number = 1) {
|
||||||
|
let count = Counters.get(name) ?? 0;
|
||||||
|
count += incAmt;
|
||||||
|
Counters.set(name, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
function countersPrint() {
|
||||||
|
let outStr = "";
|
||||||
|
for (const [name, count] of Counters.entries()) {
|
||||||
|
outStr += `${name}: ${count}\n`;
|
||||||
|
}
|
||||||
|
console.log(outStr);
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
atoms,
|
atoms,
|
||||||
|
counterInc,
|
||||||
|
countersClear,
|
||||||
|
countersPrint,
|
||||||
createBlock,
|
createBlock,
|
||||||
fetchWaveFile,
|
fetchWaveFile,
|
||||||
getApi,
|
getApi,
|
||||||
@ -464,6 +506,7 @@ export {
|
|||||||
getEventSubject,
|
getEventSubject,
|
||||||
getFileSubject,
|
getFileSubject,
|
||||||
getObjectId,
|
getObjectId,
|
||||||
|
getViewModel,
|
||||||
globalStore,
|
globalStore,
|
||||||
globalWS,
|
globalWS,
|
||||||
initGlobal,
|
initGlobal,
|
||||||
@ -471,11 +514,14 @@ export {
|
|||||||
isDev,
|
isDev,
|
||||||
openLink,
|
openLink,
|
||||||
PLATFORM,
|
PLATFORM,
|
||||||
|
registerViewModel,
|
||||||
sendWSCommand,
|
sendWSCommand,
|
||||||
setBlockFocus,
|
setBlockFocus,
|
||||||
setPlatform,
|
setPlatform,
|
||||||
|
unregisterViewModel,
|
||||||
useBlockAtom,
|
useBlockAtom,
|
||||||
useBlockCache,
|
useBlockCache,
|
||||||
|
useBlockDataLoaded,
|
||||||
useSettingsAtom,
|
useSettingsAtom,
|
||||||
WOS,
|
WOS,
|
||||||
};
|
};
|
||||||
|
@ -71,7 +71,7 @@ function makeCpuPlotViewModel(blockId: string): CpuPlotViewModel {
|
|||||||
return cpuPlotViewModel;
|
return cpuPlotViewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
function CpuPlotView({ model }: { model: CpuPlotViewModel }) {
|
function CpuPlotView({ model }: { model: CpuPlotViewModel; blockId: string }) {
|
||||||
const containerRef = React.useRef<HTMLInputElement>();
|
const containerRef = React.useRef<HTMLInputElement>();
|
||||||
const plotData = jotai.useAtomValue(model.dataAtom);
|
const plotData = jotai.useAtomValue(model.dataAtom);
|
||||||
const addPlotData = jotai.useSetAtom(model.addDataAtom);
|
const addPlotData = jotai.useSetAtom(model.addDataAtom);
|
||||||
|
@ -168,7 +168,7 @@ Other useful metadata values to override block titles, icons, colors, themes, et
|
|||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function HelpView() {
|
function HelpView({ blockId }: { blockId: string }) {
|
||||||
return <Markdown text={helpText} className="help-view" />;
|
return <Markdown text={helpText} className="help-view" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,4 +404,4 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { TerminalView, makeTerminalModel };
|
export { TermViewModel, TerminalView, makeTerminalModel };
|
||||||
|
@ -398,7 +398,7 @@ const ChatInput = forwardRef<HTMLTextAreaElement, ChatInputProps>(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const WaveAi = ({ model }: { model: WaveAiModel }) => {
|
const WaveAi = ({ model }: { model: WaveAiModel; blockId: string }) => {
|
||||||
const { messages, sendMessage } = model.useWaveAi();
|
const { messages, sendMessage } = model.useWaveAi();
|
||||||
const waveaiRef = useRef<HTMLDivElement>(null);
|
const waveaiRef = useRef<HTMLDivElement>(null);
|
||||||
const chatWindowRef = useRef<HTMLDivElement>(null);
|
const chatWindowRef = useRef<HTMLDivElement>(null);
|
||||||
|
@ -9,6 +9,7 @@ import { WebviewTag } from "electron";
|
|||||||
import * as jotai from "jotai";
|
import * as jotai from "jotai";
|
||||||
import React, { memo, useEffect } from "react";
|
import React, { memo, useEffect } from "react";
|
||||||
|
|
||||||
|
import { checkKeyPressed } from "@/util/keyutil";
|
||||||
import "./webview.less";
|
import "./webview.less";
|
||||||
|
|
||||||
export class WebViewModel implements ViewModel {
|
export class WebViewModel implements ViewModel {
|
||||||
@ -307,6 +308,19 @@ export class WebViewModel implements ViewModel {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keyDownHandler(e: WaveKeyboardEvent): boolean {
|
||||||
|
if (checkKeyPressed(e, "Cmd:l")) {
|
||||||
|
this.urlInputRef?.current?.focus();
|
||||||
|
this.urlInputRef?.current?.select();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (checkKeyPressed(e, "Cmd:r")) {
|
||||||
|
this.webviewRef?.current?.reload();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeWebViewModel(blockId: string): WebViewModel {
|
function makeWebViewModel(blockId: string): WebViewModel {
|
||||||
@ -315,11 +329,11 @@ function makeWebViewModel(blockId: string): WebViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface WebViewProps {
|
interface WebViewProps {
|
||||||
parentRef: React.RefObject<HTMLDivElement>;
|
blockId: string;
|
||||||
model: WebViewModel;
|
model: WebViewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
const WebView = memo(({ parentRef, model }: WebViewProps) => {
|
const WebView = memo(({ model }: WebViewProps) => {
|
||||||
const url = model.getUrl();
|
const url = model.getUrl();
|
||||||
const blockData = jotai.useAtomValue(model.blockAtom);
|
const blockData = jotai.useAtomValue(model.blockAtom);
|
||||||
const metaUrl = blockData?.meta?.url;
|
const metaUrl = blockData?.meta?.url;
|
||||||
@ -386,34 +400,6 @@ const WebView = memo(({ parentRef, model }: WebViewProps) => {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
|
||||||
if ((e.ctrlKey || e.metaKey) && e.key === "l") {
|
|
||||||
e.preventDefault();
|
|
||||||
if (model.urlInputRef) {
|
|
||||||
model.urlInputRef.current.focus();
|
|
||||||
model.urlInputRef.current.select();
|
|
||||||
}
|
|
||||||
} else if ((e.ctrlKey || e.metaKey) && e.key === "r") {
|
|
||||||
e.preventDefault();
|
|
||||||
if (model.webviewRef.current) {
|
|
||||||
model.webviewRef.current.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const parentElement = parentRef.current;
|
|
||||||
if (parentElement) {
|
|
||||||
parentElement.addEventListener("keydown", handleKeyDown);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (parentElement) {
|
|
||||||
parentElement.removeEventListener("keydown", handleKeyDown);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [parentRef]);
|
|
||||||
|
|
||||||
return <webview id="webview" className="webview" ref={model.webviewRef} src={url}></webview>;
|
return <webview id="webview" className="webview" ref={model.webviewRef} src={url}></webview>;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import { WshServer } from "@/app/store/wshserver";
|
import { WshServer } from "@/app/store/wshserver";
|
||||||
import { atoms, getApi, globalStore, globalWS, initGlobal, initWS } from "@/store/global";
|
import { atoms, countersClear, countersPrint, getApi, globalStore, globalWS, initGlobal, initWS } from "@/store/global";
|
||||||
import * as services from "@/store/services";
|
import * as services from "@/store/services";
|
||||||
import * as WOS from "@/store/wos";
|
import * as WOS from "@/store/wos";
|
||||||
import * as keyutil from "@/util/keyutil";
|
import * as keyutil from "@/util/keyutil";
|
||||||
@ -30,6 +30,8 @@ loadFonts();
|
|||||||
(window as any).globalAtoms = atoms;
|
(window as any).globalAtoms = atoms;
|
||||||
(window as any).WshServer = WshServer;
|
(window as any).WshServer = WshServer;
|
||||||
(window as any).isFullScreen = false;
|
(window as any).isFullScreen = false;
|
||||||
|
(window as any).countersPrint = countersPrint;
|
||||||
|
(window as any).countersClear = countersClear;
|
||||||
|
|
||||||
document.title = `The Next Wave (${windowId.substring(0, 8)})`;
|
document.title = `The Next Wave (${windowId.substring(0, 8)})`;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user