mirror of
https://github.com/Yidadaa/ChatGPT-Next-Web.git
synced 2025-09-05 15:06:53 +08:00
feat: redesign settings page
This commit is contained in:
59
app/hooks/useDrag.ts
Normal file
59
app/hooks/useDrag.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { RefObject, useRef } from "react";
|
||||
|
||||
export default function useDrag(options: {
|
||||
customDragMove: (nextWidth: number, start?: number) => void;
|
||||
customToggle: () => void;
|
||||
customLimit?: (x: number, start?: number) => number;
|
||||
customDragEnd?: (nextWidth: number, start?: number) => void;
|
||||
}) {
|
||||
const { customDragMove, customToggle, customLimit, customDragEnd } =
|
||||
options || {};
|
||||
const limit = customLimit;
|
||||
|
||||
const startX = useRef(0);
|
||||
const lastUpdateTime = useRef(Date.now());
|
||||
|
||||
const toggleSideBar = customToggle;
|
||||
|
||||
const onDragMove = customDragMove;
|
||||
|
||||
const onDragStart = (e: MouseEvent) => {
|
||||
// Remembers the initial width each time the mouse is pressed
|
||||
startX.current = e.clientX;
|
||||
const dragStartTime = Date.now();
|
||||
|
||||
const handleDragMove = (e: MouseEvent) => {
|
||||
if (Date.now() < lastUpdateTime.current + 20) {
|
||||
return;
|
||||
}
|
||||
lastUpdateTime.current = Date.now();
|
||||
const d = e.clientX - startX.current;
|
||||
const nextWidth = limit?.(d, startX.current) ?? d;
|
||||
|
||||
onDragMove(nextWidth, startX.current);
|
||||
};
|
||||
|
||||
const handleDragEnd = (e: MouseEvent) => {
|
||||
// In useRef the data is non-responsive, so `config.sidebarWidth` can't get the dynamic sidebarWidth
|
||||
window.removeEventListener("pointermove", handleDragMove);
|
||||
window.removeEventListener("pointerup", handleDragEnd);
|
||||
|
||||
// if user click the drag icon, should toggle the sidebar
|
||||
const shouldFireClick = Date.now() - dragStartTime < 300;
|
||||
if (shouldFireClick) {
|
||||
toggleSideBar();
|
||||
} else {
|
||||
const d = e.clientX - startX.current;
|
||||
const nextWidth = limit?.(d, startX.current) ?? d;
|
||||
customDragEnd?.(nextWidth, startX.current);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("pointermove", handleDragMove);
|
||||
window.addEventListener("pointerup", handleDragEnd);
|
||||
};
|
||||
|
||||
return {
|
||||
onDragStart,
|
||||
};
|
||||
}
|
@@ -1,74 +0,0 @@
|
||||
import {
|
||||
DEFAULT_SIDEBAR_WIDTH,
|
||||
MAX_SIDEBAR_WIDTH,
|
||||
MIN_SIDEBAR_WIDTH,
|
||||
} from "@/app/constant";
|
||||
import { useAppConfig } from "@/app/store/config";
|
||||
import { useRef } from "react";
|
||||
import { updateGlobalCSSVars } from "@/app/utils/client";
|
||||
|
||||
export default function useDragSideBar() {
|
||||
const limit = (x: number) =>
|
||||
Math.max(MIN_SIDEBAR_WIDTH, Math.min(MAX_SIDEBAR_WIDTH, x));
|
||||
|
||||
const config = useAppConfig();
|
||||
const startX = useRef(0);
|
||||
const startDragWidth = useRef(config.sidebarWidth ?? DEFAULT_SIDEBAR_WIDTH);
|
||||
const lastUpdateTime = useRef(Date.now());
|
||||
|
||||
const toggleSideBar = () => {
|
||||
config.update((config) => {
|
||||
config.sidebarWidth = DEFAULT_SIDEBAR_WIDTH;
|
||||
});
|
||||
};
|
||||
|
||||
const onDragStart = (e: MouseEvent) => {
|
||||
// Remembers the initial width each time the mouse is pressed
|
||||
startX.current = e.clientX;
|
||||
startDragWidth.current = config.sidebarWidth;
|
||||
const dragStartTime = Date.now();
|
||||
|
||||
const handleDragMove = (e: MouseEvent) => {
|
||||
if (Date.now() < lastUpdateTime.current + 20) {
|
||||
return;
|
||||
}
|
||||
lastUpdateTime.current = Date.now();
|
||||
const d = e.clientX - startX.current;
|
||||
const nextWidth = limit(startDragWidth.current + d);
|
||||
|
||||
const { menuWidth } = updateGlobalCSSVars(nextWidth);
|
||||
|
||||
document.documentElement.style.setProperty(
|
||||
"--menu-width",
|
||||
`${menuWidth}px`,
|
||||
);
|
||||
config.update((config) => {
|
||||
config.sidebarWidth = nextWidth;
|
||||
});
|
||||
};
|
||||
|
||||
const handleDragEnd = () => {
|
||||
// In useRef the data is non-responsive, so `config.sidebarWidth` can't get the dynamic sidebarWidth
|
||||
window.removeEventListener("pointermove", handleDragMove);
|
||||
window.removeEventListener("pointerup", handleDragEnd);
|
||||
|
||||
// if user click the drag icon, should toggle the sidebar
|
||||
const shouldFireClick = Date.now() - dragStartTime < 300;
|
||||
if (shouldFireClick) {
|
||||
toggleSideBar();
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("pointermove", handleDragMove);
|
||||
window.addEventListener("pointerup", handleDragEnd);
|
||||
};
|
||||
|
||||
// useLayoutEffect(() => {
|
||||
// const barWidth = limit(config.sidebarWidth ?? DEFAULT_SIDEBAR_WIDTH);
|
||||
// document.documentElement.style.setProperty("--menu-width", `${barWidth}px`);
|
||||
// }, [config.sidebarWidth]);
|
||||
|
||||
return {
|
||||
onDragStart,
|
||||
};
|
||||
}
|
@@ -8,7 +8,6 @@ import {
|
||||
DEFAULT_SIDEBAR_WIDTH,
|
||||
MAX_SIDEBAR_WIDTH,
|
||||
MIN_SIDEBAR_WIDTH,
|
||||
SIDEBAR_ID,
|
||||
} from "@/app/constant";
|
||||
import { useAppConfig } from "@/app/store/config";
|
||||
import { updateGlobalCSSVars } from "@/app/utils/client";
|
||||
@@ -49,5 +48,8 @@ export default function useListenWinResize() {
|
||||
config.update((config) => {
|
||||
config.sidebarWidth = menuWidth;
|
||||
});
|
||||
config.update((config) => {
|
||||
config.isMobileScreen = size.width <= MOBILE_MAX_WIDTH;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { useWindowSize } from "@/app/hooks/useWindowSize";
|
||||
|
||||
export const MOBILE_MAX_WIDTH = 768;
|
||||
import { MOBILE_MAX_WIDTH } from "@/app/hooks/useListenWinResize";
|
||||
|
||||
export default function useMobileScreen() {
|
||||
const { width } = useWindowSize();
|
||||
|
@@ -2,7 +2,7 @@ import { RefObject, useState } from "react";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
|
||||
export interface Options {
|
||||
containerRef: RefObject<HTMLDivElement | null>;
|
||||
containerRef?: RefObject<HTMLElement | null>;
|
||||
delay?: number;
|
||||
offsetDistance?: number;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ interface Position {
|
||||
}
|
||||
|
||||
export default function useRelativePosition({
|
||||
containerRef,
|
||||
containerRef = { current: window.document.body },
|
||||
delay = 100,
|
||||
offsetDistance = 0,
|
||||
}: Options) {
|
||||
@@ -49,6 +49,7 @@ export default function useRelativePosition({
|
||||
width: targetW,
|
||||
height: targetH,
|
||||
} = target.getBoundingClientRect();
|
||||
|
||||
const {
|
||||
x: containerX,
|
||||
y: containerY,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import { autoGrowTextArea } from "../utils";
|
||||
import useMobileScreen from "./useMobileScreen";
|
||||
import { useAppConfig } from "../store";
|
||||
|
||||
export default function useRows({
|
||||
inputRef,
|
||||
@@ -9,14 +9,14 @@ export default function useRows({
|
||||
inputRef: React.RefObject<HTMLTextAreaElement>;
|
||||
}) {
|
||||
const [inputRows, setInputRows] = useState(2);
|
||||
const isMobileScreen = useMobileScreen();
|
||||
const config = useAppConfig();
|
||||
|
||||
const measure = useDebouncedCallback(
|
||||
() => {
|
||||
const rows = inputRef.current ? autoGrowTextArea(inputRef.current) : 1;
|
||||
const inputRows = Math.min(
|
||||
20,
|
||||
Math.max(2 + (isMobileScreen ? -1 : 1), rows),
|
||||
Math.max(2 + (config.isMobileScreen ? -1 : 1), rows),
|
||||
);
|
||||
setInputRows(inputRows);
|
||||
},
|
||||
|
Reference in New Issue
Block a user