feat: Entity explorer pages section resize (#13576)
* * Page container resize changes * * changed inline style to styled component * * Added preserve height functionality
This commit is contained in:
parent
a956ff6d71
commit
7f241cb98e
|
|
@ -24,6 +24,7 @@ const SwitchBlock = styled.div<{ active?: boolean }>`
|
|||
height: 100%;
|
||||
flex: 1;
|
||||
border: 1px solid transparent;
|
||||
user-select: none;
|
||||
|
||||
${(props) =>
|
||||
props.active &&
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { ReactNode } from "react";
|
||||
import React, { RefObject, ReactNode } from "react";
|
||||
import styled from "styled-components";
|
||||
import { Collapse } from "@blueprintjs/core";
|
||||
|
||||
|
|
@ -10,11 +10,16 @@ export function EntityCollapse(props: {
|
|||
isOpen: boolean;
|
||||
step: number;
|
||||
active?: boolean;
|
||||
collapseRef?: RefObject<HTMLDivElement> | null;
|
||||
}) {
|
||||
if (!props.children) return null;
|
||||
return (
|
||||
<Collapse isOpen={props.isOpen}>
|
||||
<CollapsedContainer active={props.active} step={props.step}>
|
||||
<CollapsedContainer
|
||||
active={props.active}
|
||||
ref={props.collapseRef}
|
||||
step={props.step}
|
||||
>
|
||||
{props.children}
|
||||
</CollapsedContainer>
|
||||
</Collapse>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import React, {
|
|||
useRef,
|
||||
forwardRef,
|
||||
useCallback,
|
||||
RefObject,
|
||||
} from "react";
|
||||
import styled, { css } from "styled-components";
|
||||
import { Colors } from "constants/Colors";
|
||||
|
|
@ -205,6 +206,7 @@ export type EntityProps = {
|
|||
preRightIcon?: ReactNode;
|
||||
onClickPreRightIcon?: () => void;
|
||||
isSticky?: boolean;
|
||||
collapseRef?: RefObject<HTMLDivElement> | null;
|
||||
customAddButton?: ReactNode;
|
||||
};
|
||||
|
||||
|
|
@ -363,7 +365,12 @@ export const Entity = forwardRef(
|
|||
)}
|
||||
<Loader isVisible={isUpdating} />
|
||||
</EntityItem>
|
||||
<Collapse active={props.active} isOpen={isOpen} step={props.step}>
|
||||
<Collapse
|
||||
active={props.active}
|
||||
collapseRef={props.collapseRef}
|
||||
isOpen={isOpen}
|
||||
step={props.step}
|
||||
>
|
||||
{props.children}
|
||||
</Collapse>
|
||||
</Wrapper>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useCallback, useMemo, useEffect } from "react";
|
||||
import React, { useCallback, useMemo, useEffect, useRef } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
getCurrentApplicationId,
|
||||
|
|
@ -33,12 +33,26 @@ import { setExplorerPinnedAction } from "actions/explorerActions";
|
|||
import { selectAllPages } from "selectors/entitiesSelector";
|
||||
import { builderURL, pageListEditorURL } from "RouteBuilder";
|
||||
import { saveExplorerStatus, getExplorerStatus } from "../helpers";
|
||||
import { tailwindLayers } from "constants/Layers";
|
||||
import useResize, {
|
||||
DIRECTION,
|
||||
CallbackResponseType,
|
||||
} from "utils/hooks/useResize";
|
||||
|
||||
const StyledEntity = styled(Entity)`
|
||||
const ENTITY_HEIGHT = 36;
|
||||
const MIN_PAGES_HEIGHT = 60;
|
||||
|
||||
const StyledEntity = styled(Entity)<{ pagesSize?: number }>`
|
||||
&.pages {
|
||||
& > div:not(.t--entity-item) {
|
||||
max-height: 144px !important;
|
||||
overflow-y: auto !important;
|
||||
& > div:not(.t--entity-item) > div > div {
|
||||
max-height: 40vh;
|
||||
min-height: ${(props) =>
|
||||
props.pagesSize && props.pagesSize > MIN_PAGES_HEIGHT
|
||||
? MIN_PAGES_HEIGHT
|
||||
: props.pagesSize}px;
|
||||
height: ${(props) =>
|
||||
props.pagesSize && props.pagesSize > 128 ? 128 : props.pagesSize}px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
&.page .${EntityClassNames.PRE_RIGHT_ICON} {
|
||||
|
|
@ -52,6 +66,10 @@ const StyledEntity = styled(Entity)`
|
|||
}
|
||||
`;
|
||||
|
||||
const RelativeContainer = styled.div`
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
function Pages() {
|
||||
const applicationId = useSelector(getCurrentApplicationId);
|
||||
const pages: Page[] = useSelector(selectAllPages);
|
||||
|
|
@ -59,11 +77,30 @@ function Pages() {
|
|||
const pinned = useSelector(getExplorerPinned);
|
||||
const dispatch = useDispatch();
|
||||
const isPagesOpen = getExplorerStatus(applicationId, "pages");
|
||||
const pageResizeRef = useRef<HTMLDivElement>(null);
|
||||
const storedHeightKey = "pagesContainerHeight_" + applicationId;
|
||||
const storedHeight = localStorage.getItem(storedHeightKey);
|
||||
|
||||
const resizeAfterCallback = (data: CallbackResponseType) => {
|
||||
localStorage.setItem(storedHeightKey, data.height.toString());
|
||||
};
|
||||
|
||||
const { mouseDown, setMouseDown } = useResize(
|
||||
pageResizeRef,
|
||||
DIRECTION.vertical,
|
||||
resizeAfterCallback,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
document.getElementsByClassName("activePage")[0]?.scrollIntoView();
|
||||
}, [currentPageId]);
|
||||
|
||||
useEffect(() => {
|
||||
if ((isPagesOpen === null ? true : isPagesOpen) && pageResizeRef.current) {
|
||||
pageResizeRef.current.style.height = storedHeight + "px";
|
||||
}
|
||||
}, [pageResizeRef]);
|
||||
|
||||
const switchPage = useCallback((page: Page) => {
|
||||
history.push(
|
||||
builderURL({
|
||||
|
|
@ -165,25 +202,39 @@ function Pages() {
|
|||
);
|
||||
|
||||
return (
|
||||
<StyledEntity
|
||||
action={onPageListSelection}
|
||||
addButtonHelptext={createMessage(ADD_PAGE_TOOLTIP)}
|
||||
alwaysShowRightIcon
|
||||
className="group pages"
|
||||
entityId="Pages"
|
||||
icon={""}
|
||||
isDefaultExpanded={isPagesOpen === null ? true : isPagesOpen}
|
||||
name="PAGES"
|
||||
onClickPreRightIcon={onPin}
|
||||
onClickRightIcon={onClickRightIcon}
|
||||
onCreate={createPageCallback}
|
||||
onToggle={onPageToggle}
|
||||
rightIcon={settingsIconWithTooltip}
|
||||
searchKeyword={""}
|
||||
step={0}
|
||||
>
|
||||
{pageElements}
|
||||
</StyledEntity>
|
||||
<RelativeContainer>
|
||||
<StyledEntity
|
||||
action={onPageListSelection}
|
||||
addButtonHelptext={createMessage(ADD_PAGE_TOOLTIP)}
|
||||
alwaysShowRightIcon
|
||||
className="group pages"
|
||||
collapseRef={pageResizeRef}
|
||||
entityId="Pages"
|
||||
icon={""}
|
||||
isDefaultExpanded={isPagesOpen === null ? true : isPagesOpen}
|
||||
name="PAGES"
|
||||
onClickPreRightIcon={onPin}
|
||||
onClickRightIcon={onClickRightIcon}
|
||||
onCreate={createPageCallback}
|
||||
onToggle={onPageToggle}
|
||||
pagesSize={ENTITY_HEIGHT * pages.length}
|
||||
rightIcon={settingsIconWithTooltip}
|
||||
searchKeyword={""}
|
||||
step={0}
|
||||
>
|
||||
{pageElements}
|
||||
</StyledEntity>
|
||||
<div
|
||||
className={`absolute -bottom-2 left-0 w-full h-2 group cursor-ns-resize ${tailwindLayers.resizer}`}
|
||||
onMouseDown={() => setMouseDown(true)}
|
||||
>
|
||||
<div
|
||||
className={`w-full h-1 bg-transparent hover:bg-gray-300 transform transition
|
||||
${mouseDown ? "hover:bg-blue-500" : ""}
|
||||
`}
|
||||
/>
|
||||
</div>
|
||||
</RelativeContainer>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
76
app/client/src/utils/hooks/useResize.tsx
Normal file
76
app/client/src/utils/hooks/useResize.tsx
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import React, { MutableRefObject } from "react";
|
||||
|
||||
export enum DIRECTION {
|
||||
vertical,
|
||||
horizontal,
|
||||
}
|
||||
|
||||
export interface CallbackResponseType {
|
||||
height: number;
|
||||
width: number;
|
||||
}
|
||||
|
||||
function useResize(
|
||||
ref: MutableRefObject<HTMLElement | null>,
|
||||
direction: DIRECTION,
|
||||
afterResizeCallback?: (data: CallbackResponseType) => void,
|
||||
) {
|
||||
const [mouseDown, setMouseDown] = React.useState(false);
|
||||
|
||||
const pointer =
|
||||
direction === DIRECTION.vertical ? "cursor-ns-resize" : "cursor-ew-resize";
|
||||
|
||||
const onMouseMove = (e: MouseEvent) => {
|
||||
document.body.classList.add(pointer);
|
||||
if (ref.current) {
|
||||
// below lines stop selection of texts
|
||||
if (e.stopPropagation) e.stopPropagation();
|
||||
if (e.preventDefault) e.preventDefault();
|
||||
|
||||
const { bottom, left, right, top } = ref.current.getBoundingClientRect();
|
||||
|
||||
const currentMouseYPosition = e.clientY;
|
||||
const currentMouseXPosition = e.clientX;
|
||||
|
||||
const distanceYDragged = currentMouseYPosition - bottom;
|
||||
const distanceXDragged = currentMouseXPosition - right;
|
||||
|
||||
const currentHeight = bottom - top;
|
||||
const currentWidth = right - left;
|
||||
|
||||
const newHeight = currentHeight + distanceYDragged;
|
||||
const newWidth = currentWidth + distanceXDragged;
|
||||
|
||||
if (direction === DIRECTION.vertical) {
|
||||
ref.current.style.height = newHeight + "px";
|
||||
} else {
|
||||
ref.current.style.width = newWidth + "px";
|
||||
}
|
||||
|
||||
if (afterResizeCallback) {
|
||||
afterResizeCallback({ height: newHeight, width: newWidth });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = () => {
|
||||
setMouseDown(false);
|
||||
document.body.classList.remove(pointer);
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (mouseDown) {
|
||||
document.addEventListener("mousemove", onMouseMove);
|
||||
document.addEventListener("mouseup", onMouseUp);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("mousemove", onMouseMove);
|
||||
document.removeEventListener("mouseup", onMouseUp);
|
||||
};
|
||||
}, [mouseDown]);
|
||||
|
||||
return { mouseDown, setMouseDown };
|
||||
}
|
||||
|
||||
export default useResize;
|
||||
Loading…
Reference in New Issue
Block a user