mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-23 19:05:16 +02:00
refactor(sidebar): update sidebar resizing logic to use pointer events; enhance drag cursor handling and improve sidebar width persistence
This commit is contained in:
parent
331589275b
commit
147be71238
5 changed files with 208 additions and 166 deletions
|
|
@ -10,18 +10,36 @@ export const SIDEBAR_MAX_WIDTH = 480;
|
|||
|
||||
interface UseSidebarResizeReturn {
|
||||
sidebarWidth: number;
|
||||
handleMouseDown: (e: React.MouseEvent) => void;
|
||||
handlePointerDown: (e: React.PointerEvent<HTMLElement>) => void;
|
||||
isDragging: boolean;
|
||||
}
|
||||
|
||||
function setGlobalDragCursor(active: boolean) {
|
||||
const html = document.documentElement;
|
||||
const body = document.body;
|
||||
if (active) {
|
||||
html.style.cursor = "col-resize";
|
||||
body.style.cursor = "col-resize";
|
||||
html.style.userSelect = "none";
|
||||
body.style.userSelect = "none";
|
||||
} else {
|
||||
html.style.cursor = "";
|
||||
body.style.cursor = "";
|
||||
html.style.userSelect = "";
|
||||
body.style.userSelect = "";
|
||||
}
|
||||
}
|
||||
|
||||
export function useSidebarResize(defaultWidth = SIDEBAR_MIN_WIDTH): UseSidebarResizeReturn {
|
||||
const [sidebarWidth, setSidebarWidth] = useState(defaultWidth);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
const startXRef = useRef(0);
|
||||
const startWidthRef = useRef(defaultWidth);
|
||||
const widthRef = useRef(defaultWidth);
|
||||
const pointerIdRef = useRef<number | null>(null);
|
||||
const captureTargetRef = useRef<HTMLElement | null>(null);
|
||||
|
||||
// Initialize from cookie on mount
|
||||
useEffect(() => {
|
||||
try {
|
||||
const match = document.cookie.match(/(?:^|; )sidebar_width=([^;]+)/);
|
||||
|
|
@ -29,14 +47,13 @@ export function useSidebarResize(defaultWidth = SIDEBAR_MIN_WIDTH): UseSidebarRe
|
|||
const parsed = Number(match[1]);
|
||||
if (!Number.isNaN(parsed) && parsed >= SIDEBAR_MIN_WIDTH && parsed <= SIDEBAR_MAX_WIDTH) {
|
||||
setSidebarWidth(parsed);
|
||||
widthRef.current = parsed;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Ignore cookie read errors
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Persist width to cookie
|
||||
const persistWidth = useCallback((width: number) => {
|
||||
try {
|
||||
// biome-ignore lint/suspicious/noDocumentCookie: SSR-readable preference, not security-sensitive
|
||||
|
|
@ -46,57 +63,81 @@ export function useSidebarResize(defaultWidth = SIDEBAR_MIN_WIDTH): UseSidebarRe
|
|||
}
|
||||
}, []);
|
||||
|
||||
const handleMouseDown = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
startXRef.current = e.clientX;
|
||||
startWidthRef.current = sidebarWidth;
|
||||
setIsDragging(true);
|
||||
const releaseCapture = useCallback(() => {
|
||||
const target = captureTargetRef.current;
|
||||
const pointerId = pointerIdRef.current;
|
||||
if (target && pointerId !== null) {
|
||||
try {
|
||||
if (target.hasPointerCapture(pointerId)) {
|
||||
target.releasePointerCapture(pointerId);
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
captureTargetRef.current = null;
|
||||
pointerIdRef.current = null;
|
||||
}, []);
|
||||
|
||||
document.body.style.cursor = "col-resize";
|
||||
document.body.style.userSelect = "none";
|
||||
const handlePointerDown = useCallback(
|
||||
(e: React.PointerEvent<HTMLElement>) => {
|
||||
if (e.pointerType === "mouse" && e.button !== 0) return;
|
||||
|
||||
e.preventDefault();
|
||||
const target = e.currentTarget;
|
||||
try {
|
||||
target.setPointerCapture(e.pointerId);
|
||||
} catch {
|
||||
}
|
||||
captureTargetRef.current = target;
|
||||
pointerIdRef.current = e.pointerId;
|
||||
startXRef.current = e.clientX;
|
||||
startWidthRef.current = widthRef.current;
|
||||
setIsDragging(true);
|
||||
setGlobalDragCursor(true);
|
||||
},
|
||||
[sidebarWidth]
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDragging) return;
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
const handlePointerMove = (e: PointerEvent) => {
|
||||
if (pointerIdRef.current !== null && e.pointerId !== pointerIdRef.current) return;
|
||||
const delta = e.clientX - startXRef.current;
|
||||
const newWidth = Math.min(
|
||||
SIDEBAR_MAX_WIDTH,
|
||||
Math.max(SIDEBAR_MIN_WIDTH, startWidthRef.current + delta)
|
||||
);
|
||||
setSidebarWidth(newWidth);
|
||||
if (newWidth !== widthRef.current) {
|
||||
widthRef.current = newWidth;
|
||||
setSidebarWidth(newWidth);
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
const stop = (e: PointerEvent) => {
|
||||
if (pointerIdRef.current !== null && e.pointerId !== pointerIdRef.current) return;
|
||||
releaseCapture();
|
||||
setIsDragging(false);
|
||||
document.body.style.cursor = "";
|
||||
document.body.style.userSelect = "";
|
||||
|
||||
// Persist the final width
|
||||
setSidebarWidth((currentWidth) => {
|
||||
persistWidth(currentWidth);
|
||||
return currentWidth;
|
||||
});
|
||||
setGlobalDragCursor(false);
|
||||
persistWidth(widthRef.current);
|
||||
};
|
||||
|
||||
document.addEventListener("mousemove", handleMouseMove);
|
||||
document.addEventListener("mouseup", handleMouseUp);
|
||||
window.addEventListener("pointermove", handlePointerMove);
|
||||
window.addEventListener("pointerup", stop);
|
||||
window.addEventListener("pointercancel", stop);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("mousemove", handleMouseMove);
|
||||
document.removeEventListener("mouseup", handleMouseUp);
|
||||
document.body.style.cursor = "";
|
||||
document.body.style.userSelect = "";
|
||||
window.removeEventListener("pointermove", handlePointerMove);
|
||||
window.removeEventListener("pointerup", stop);
|
||||
window.removeEventListener("pointercancel", stop);
|
||||
setGlobalDragCursor(false);
|
||||
releaseCapture();
|
||||
};
|
||||
}, [isDragging, persistWidth]);
|
||||
}, [isDragging, persistWidth, releaseCapture]);
|
||||
|
||||
return {
|
||||
sidebarWidth,
|
||||
handleMouseDown,
|
||||
handlePointerDown,
|
||||
isDragging,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue