This commit is contained in:
Maze Winther
2026-01-15 11:05:17 +01:00
parent c19f085e48
commit deef784b76
182 changed files with 7787 additions and 18046 deletions
+101 -74
View File
@@ -13,6 +13,24 @@ export function Handlebars({ children }: HandlebarsProps) {
const [leftHandle, setLeftHandle] = useState(0);
const [rightHandle, setRightHandle] = useState(0);
const widthRef = useRef(0);
const leftHandlePositionRef = useRef(0);
const rightHandlePositionRef = useRef(0);
const dragRef = useRef<{
isDragging: boolean;
side: "left" | "right" | null;
pointerId: number | null;
startX: number;
initialPosition: number;
}>({
isDragging: false,
side: null,
pointerId: null,
startX: 0,
initialPosition: 0,
});
useEffect(() => {
const el = containerRef.current;
if (!el) return;
@@ -31,85 +49,85 @@ export function Handlebars({ children }: HandlebarsProps) {
}, []);
useEffect(() => {
const leftEl = leftHandleRef.current;
const rightEl = rightHandleRef.current;
if (!leftEl || !rightEl) return;
let isDraggingLeft = false;
let isDraggingRight = false;
let startX = 0;
let initialPosition = 0;
const handleMouseDown = (e: MouseEvent, isLeft: boolean) => {
e.preventDefault();
startX = e.clientX;
if (isLeft) {
isDraggingLeft = true;
initialPosition = leftHandle;
} else {
isDraggingRight = true;
initialPosition = rightHandle;
}
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
};
const handleMouseMove = (e: MouseEvent) => {
const deltaX = e.clientX - startX;
if (isDraggingLeft) {
const newPosition = Math.max(0, Math.min(rightHandle - 60, initialPosition + deltaX));
setLeftHandle(newPosition);
if (leftEl) {
leftEl.style.transform = `translateX(${newPosition}px)`;
}
} else if (isDraggingRight) {
const newPosition = Math.max(leftHandle + 60, Math.min(width, initialPosition + deltaX));
setRightHandle(newPosition);
if (rightEl) {
rightEl.style.transform = `translateX(${newPosition}px)`;
}
}
};
const handleMouseUp = () => {
isDraggingLeft = false;
isDraggingRight = false;
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
};
const leftMouseDown = (e: MouseEvent) => handleMouseDown(e, true);
const rightMouseDown = (e: MouseEvent) => handleMouseDown(e, false);
leftEl.addEventListener("mousedown", leftMouseDown);
rightEl.addEventListener("mousedown", rightMouseDown);
return () => {
leftEl.removeEventListener("mousedown", leftMouseDown);
rightEl.removeEventListener("mousedown", rightMouseDown);
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
};
widthRef.current = width;
leftHandlePositionRef.current = leftHandle;
rightHandlePositionRef.current = rightHandle;
}, [leftHandle, rightHandle, width]);
useEffect(() => {
const handlePointerMove = (event: PointerEvent) => {
const { isDragging, side, pointerId, startX, initialPosition } =
dragRef.current;
if (!isDragging) return;
if (pointerId !== null && event.pointerId !== pointerId) return;
if (!side) return;
const deltaX = event.clientX - startX;
if (side === "left") {
const maxLeft = Math.max(0, rightHandlePositionRef.current - 60);
const nextLeftHandle = Math.max(
0,
Math.min(maxLeft, initialPosition + deltaX),
);
setLeftHandle(nextLeftHandle);
return;
}
const minRight = Math.min(
widthRef.current,
leftHandlePositionRef.current + 60,
);
const nextRightHandle = Math.max(
minRight,
Math.min(widthRef.current, initialPosition + deltaX),
);
setRightHandle(nextRightHandle);
};
const handlePointerEnd = (event: PointerEvent) => {
const { pointerId } = dragRef.current;
if (pointerId !== null && event.pointerId !== pointerId) return;
dragRef.current.isDragging = false;
dragRef.current.side = null;
dragRef.current.pointerId = null;
};
window.addEventListener("pointermove", handlePointerMove);
window.addEventListener("pointerup", handlePointerEnd);
window.addEventListener("pointercancel", handlePointerEnd);
return () => {
window.removeEventListener("pointermove", handlePointerMove);
window.removeEventListener("pointerup", handlePointerEnd);
window.removeEventListener("pointercancel", handlePointerEnd);
};
}, []);
const leftGradientPercent = width > 0 ? (leftHandle / (width - 10)) * 100 : 0;
const rightGradientPercent = width > 0 ? (rightHandle / (width + 10)) * 100 : 0;
const rightGradientPercent =
width > 0 ? (rightHandle / (width + 10)) * 100 : 0;
return (
<div className="leading-16 -z-10 flex justify-center gap-4">
<div
ref={containerRef}
className="relative -z-10 mt-0.5 -rotate-[2.76deg]"
>
<div className="absolute inset-0 flex h-full w-full justify-between rounded-2xl border border-yellow-500">
<div className="leading-16 flex justify-center gap-4">
<div ref={containerRef} className="relative mt-0.5 -rotate-[2.76deg]">
<div className="absolute inset-0 z-10 flex h-full w-full justify-between rounded-2xl border border-yellow-500">
<div
ref={leftHandleRef}
className="bg-background absolute left-0 flex h-full w-7 select-none items-center justify-center rounded-full border border-yellow-500 cursor-grab hover:scale-105 transition-transform"
className="bg-background absolute left-0 z-20 flex h-full w-7 cursor-ew-resize touch-none select-none items-center justify-center rounded-full border border-yellow-500"
style={{
transform: `translateX(${leftHandle}px)`,
translate: `${leftHandle}px 0`,
}}
onPointerDown={(event) => {
event.preventDefault();
leftHandleRef.current?.setPointerCapture(event.pointerId);
dragRef.current.isDragging = true;
dragRef.current.side = "left";
dragRef.current.pointerId = event.pointerId;
dragRef.current.startX = event.clientX;
dragRef.current.initialPosition = leftHandlePositionRef.current;
}}
>
<div className="h-8 w-2 rounded-full bg-yellow-500" />
@@ -117,9 +135,18 @@ export function Handlebars({ children }: HandlebarsProps) {
<div
ref={rightHandleRef}
className="bg-background absolute -left-[30px] flex h-full w-7 select-none items-center justify-center rounded-full border border-yellow-500 cursor-grab hover:scale-105 transition-transform]"
className="bg-background absolute -left-[30px] z-20 flex h-full w-7 cursor-ew-resize touch-none select-none items-center justify-center rounded-full border border-yellow-500"
style={{
transform: `translateX(${rightHandle}px)`,
translate: `${rightHandle}px 0`,
}}
onPointerDown={(event) => {
event.preventDefault();
rightHandleRef.current?.setPointerCapture(event.pointerId);
dragRef.current.isDragging = true;
dragRef.current.side = "right";
dragRef.current.pointerId = event.pointerId;
dragRef.current.startX = event.clientX;
dragRef.current.initialPosition = rightHandlePositionRef.current;
}}
>
<div className="h-8 w-2 rounded-full bg-yellow-500" />
@@ -127,7 +154,7 @@ export function Handlebars({ children }: HandlebarsProps) {
</div>
<span
className="relative inline-flex h-full w-full items-center justify-center rounded-2xl px-9 will-change-auto"
className="relative z-0 inline-flex h-full w-full items-center justify-center rounded-2xl px-9 will-change-auto"
style={{
mask: `linear-gradient(90deg,
rgba(255, 255, 255, 0) 0%,