diff --git a/app/client/src/components/ads/Switcher.tsx b/app/client/src/components/ads/Switcher.tsx index 81e8b42c0d..558d9a5248 100644 --- a/app/client/src/components/ads/Switcher.tsx +++ b/app/client/src/components/ads/Switcher.tsx @@ -24,6 +24,7 @@ const SwitchBlock = styled.div<{ active?: boolean }>` height: 100%; flex: 1; border: 1px solid transparent; + user-select: none; ${(props) => props.active && diff --git a/app/client/src/pages/Editor/Explorer/Entity/Collapse.tsx b/app/client/src/pages/Editor/Explorer/Entity/Collapse.tsx index f679fca2dd..8ba43689ee 100644 --- a/app/client/src/pages/Editor/Explorer/Entity/Collapse.tsx +++ b/app/client/src/pages/Editor/Explorer/Entity/Collapse.tsx @@ -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 | null; }) { if (!props.children) return null; return ( - + {props.children} diff --git a/app/client/src/pages/Editor/Explorer/Entity/index.tsx b/app/client/src/pages/Editor/Explorer/Entity/index.tsx index 387da7e6d1..d1a460c1b9 100644 --- a/app/client/src/pages/Editor/Explorer/Entity/index.tsx +++ b/app/client/src/pages/Editor/Explorer/Entity/index.tsx @@ -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 | null; customAddButton?: ReactNode; }; @@ -363,7 +365,12 @@ export const Entity = forwardRef( )} - + {props.children} diff --git a/app/client/src/pages/Editor/Explorer/Pages/index.tsx b/app/client/src/pages/Editor/Explorer/Pages/index.tsx index 6f2adbbfaa..5a4b658abd 100644 --- a/app/client/src/pages/Editor/Explorer/Pages/index.tsx +++ b/app/client/src/pages/Editor/Explorer/Pages/index.tsx @@ -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(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 ( - - {pageElements} - + + + {pageElements} + +
setMouseDown(true)} + > +
+
+ ); } diff --git a/app/client/src/utils/hooks/useResize.tsx b/app/client/src/utils/hooks/useResize.tsx new file mode 100644 index 0000000000..db39f65524 --- /dev/null +++ b/app/client/src/utils/hooks/useResize.tsx @@ -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, + 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;