From 691077df7a4918cce6dcb839f133833bd2587ca8 Mon Sep 17 00:00:00 2001 From: NriotHrreion Date: Mon, 1 Jan 2024 20:13:15 +0800 Subject: [PATCH] feat: Add sash resizer --- public/index.html | 1 + src/components/Sash.tsx | 97 ++++++++++++++++++++++++++++++++ src/components/sidebar/index.tsx | 13 ++++- src/style/layout.less | 16 ++++++ src/style/sidebar.less | 5 +- 5 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 src/components/Sash.tsx diff --git a/public/index.html b/public/index.html index b08748d..061b2ee 100644 --- a/public/index.html +++ b/public/index.html @@ -14,6 +14,7 @@
+
diff --git a/src/components/Sash.tsx b/src/components/Sash.tsx new file mode 100644 index 0000000..42d4f30 --- /dev/null +++ b/src/components/Sash.tsx @@ -0,0 +1,97 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions */ +/* eslint-disable react-hooks/exhaustive-deps */ +import React, { useState, useEffect, useRef, useId } from "react"; + +import Utils from "@/utils/Utils"; + +interface SashProps { + direction: "vertical" | "horizontal" + defaultValue: number + minValue?: number + maxValue?: number + side: "left" | "right" | "top" | "bottom" + disabled?: boolean + onChange?: (value: number) => void +} + +const Sash: React.FC = (props) => { + const [isHovered, setIsHovered] = useState(false); + const [isMoving, setIsMoving] = useState(false); + const id = useRef(useId()); + const timer = useRef(); + + const handleMouseOver = () => { + if(props.disabled || timer.current) return; + + timer.current = setTimeout(() => { + setIsHovered(true); + }, 350); + }; + + const handleMouseOut = () => { + if(props.disabled || isMoving) return; + + setIsHovered(false); + clearTimeout(timer.current ?? 0); + timer.current = null; + }; + + const handleMouseDown = () => { + if(props.disabled) return; + + setIsHovered(true); + setIsMoving(true); + }; + + useEffect(() => { + window.addEventListener("mousemove", async (e: MouseEvent) => { + if(props.disabled || !(await Utils.getCurrentState(setIsMoving))) return; + + var newValue = props.direction === "vertical" ? e.clientX : e.clientY; + if( + props.minValue && + props.minValue >= newValue + ) newValue = props.minValue; + if( + props.maxValue && + props.maxValue <= newValue + ) newValue = props.maxValue; + + const elem = Utils.getElem("sash--"+ id.current); + elem.style[props.side] = newValue +"px"; + // Do a repaint so that the update of page will + // be able to keep up with the update of CSS. + // Thanks to ChatGPT.... + elem.style.display = "none"; + elem.offsetHeight; // trigger a repaint + elem.style.display = ""; + if(props.onChange) props.onChange(newValue); + }); + window.addEventListener("mouseup", (e) => { + if(props.disabled || (e.target as HTMLElement).id !== "sash--"+ id.current) setIsHovered(false); + setIsMoving(false); + }); + }, []); + + useEffect(() => { + if(isHovered) { + document.body.style.cursor = props.direction === "vertical" ? "ew-resize" : "ns-resize"; + } else { + document.body.style.cursor = ""; + } + }, [isHovered]); + + useEffect(() => { + Utils.getElem("sash--"+ id.current).style[props.side] = props.defaultValue +"px"; + }, [props.disabled]); + + return
handleMouseOver()} + onMouseOut={() => handleMouseOut()} + onMouseDown={() => handleMouseDown()}/>; +} + +export default Sash; diff --git a/src/components/sidebar/index.tsx b/src/components/sidebar/index.tsx index d726f63..36033a5 100644 --- a/src/components/sidebar/index.tsx +++ b/src/components/sidebar/index.tsx @@ -7,6 +7,7 @@ import KeepAlive from "react-activation"; import ModeButton from "@/components/sidebar/ModeButton"; import History from "@/components/sidebar/History"; import FunctionList from "@/components/sidebar/FunctionList"; +import Sash from "@/components/Sash"; import { Mode, Theme } from "@/types"; import { version } from "@/global"; @@ -25,6 +26,7 @@ import ProgrammingIcon from "@/icons/programming_mode.svg"; const Sidebar: React.FC = () => { const { mode } = useContext(MainContext); const [sidebarOpen, setSidebarOpen] = useState(!Utils.isMobile()); + const [width, setWidth] = useState(382); const themeValue = Storage.get().getItem("theme", useThemeDetector()); const handleToggle = (isActive: boolean) => { @@ -63,7 +65,7 @@ const Sidebar: React.FC = () => { }, [sidebarOpen]); return ( -