waveterm/frontend/app/tab/tabcontent.tsx
Evan Simkowitz 75c9e211d9
Add resize handles to the layout system (#66)
Adds resizability to the layout system.

Hovering in the margins of a block will highlight the available resize
handle and show a cursor indicating its resize direction. Dragging will
cause the resizing nodes to blur out and be replaced by an outline.
Releasing the handle will commit the new resize operation and cause the
underlying nodes to update to their new sizes.

We'll want to refactor this in the future to move all layout and resize
logic into a shared model that the TileLayout code can talk to, but
that's a future improvement. For now, this makes some compromises,
mainly that the logic is kind of distributed around.

---------

Co-authored-by: sawka <mike.sawka@gmail.com>
2024-07-03 14:31:02 -07:00

90 lines
2.8 KiB
TypeScript

// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { Block, BlockFrame } from "@/app/block/block";
import { getApi } from "@/store/global";
import * as services from "@/store/services";
import * as WOS from "@/store/wos";
import * as React from "react";
import { CenteredDiv, CenteredLoadingDiv } from "@/element/quickelems";
import { TileLayout } from "@/faraday/index";
import { getLayoutStateAtomForTab } from "@/faraday/lib/layoutAtom";
import { useAtomValue } from "jotai";
import { useMemo } from "react";
import "./tabcontent.less";
const TabContent = React.memo(({ tabId }: { tabId: string }) => {
const oref = useMemo(() => WOS.makeORef("tab", tabId), [tabId]);
const loadingAtom = useMemo(() => WOS.getWaveObjectLoadingAtom(oref), [oref]);
const tabLoading = useAtomValue(loadingAtom);
const tabAtom = useMemo(() => WOS.getWaveObjectAtom<Tab>(oref), [oref]);
const layoutStateAtom = useMemo(() => getLayoutStateAtomForTab(tabId, tabAtom), [tabAtom, tabId]);
const tabData = useAtomValue(tabAtom);
const tileLayoutContents = useMemo(() => {
function renderBlock(
tabData: TabLayoutData,
ready: boolean,
onClose: () => void,
dragHandleRef: React.RefObject<HTMLDivElement>
) {
if (!tabData.blockId || !ready) {
return null;
}
return (
<Block
key={tabData.blockId}
blockId={tabData.blockId}
onClose={onClose}
dragHandleRef={dragHandleRef}
/>
);
}
function renderPreview(tabData: TabLayoutData) {
return <BlockFrame key={tabData.blockId} blockId={tabData.blockId} preview={true} />;
}
function onNodeDelete(data: TabLayoutData) {
return services.ObjectService.DeleteBlock(data.blockId);
}
return {
renderContent: renderBlock,
renderPreview: renderPreview,
tabId: tabId,
onNodeDelete: onNodeDelete,
};
}, []);
if (tabLoading) {
return <CenteredLoadingDiv />;
}
if (!tabData) {
return (
<div className="tabcontent">
<CenteredDiv>Tab Not Found</CenteredDiv>
</div>
);
}
if (tabData?.blockids?.length == 0) {
return <div className="tabcontent tabcontent-empty"></div>;
}
return (
<div className="tabcontent">
<TileLayout
key={tabId}
contents={tileLayoutContents}
layoutTreeStateAtom={layoutStateAtom}
getCursorPoint={getApi().getCursorPoint}
/>
</div>
);
});
export { TabContent };