diff --git a/apps/web/src/components/landing/handlebars.tsx b/apps/web/src/components/landing/handlebars.tsx new file mode 100644 index 0000000..36705e9 --- /dev/null +++ b/apps/web/src/components/landing/handlebars.tsx @@ -0,0 +1,164 @@ +"use client"; + +import React, { useState, useRef, useEffect } from "react"; +import { motion, useMotionValue, useTransform, PanInfo } from "motion/react"; + +interface HandlebarsProps { + children: React.ReactNode; + minWidth?: number; + maxWidth?: number; + onRangeChange?: (left: number, right: number) => void; +} + +export function Handlebars({ + children, + minWidth = 50, + maxWidth = 400, + onRangeChange, +}: HandlebarsProps) { + const [leftHandle, setLeftHandle] = useState(0); + const [rightHandle, setRightHandle] = useState(maxWidth); + const [contentWidth, setContentWidth] = useState(maxWidth); + + const leftHandleX = useMotionValue(0); + const rightHandleX = useMotionValue(maxWidth); + + const visibleWidth = useTransform( + [leftHandleX, rightHandleX], + (values: number[]) => values[1] - values[0] + ); + + const contentLeft = useTransform(leftHandleX, (left: number) => -left); + + const containerRef = useRef(null); + const measureRef = useRef(null); + + useEffect(() => { + if (!measureRef.current) return; + + const measureContent = () => { + if (measureRef.current) { + const width = measureRef.current.scrollWidth; + const paddedWidth = width + 32; + setContentWidth(paddedWidth); + setRightHandle(paddedWidth); + rightHandleX.set(paddedWidth); + } + }; + + measureContent(); + const timer = setTimeout(measureContent, 50); + + return () => clearTimeout(timer); + }, [children, rightHandleX]); + + useEffect(() => { + leftHandleX.set(leftHandle); + }, [leftHandle, leftHandleX]); + + useEffect(() => { + rightHandleX.set(rightHandle); + }, [rightHandle, rightHandleX]); + + useEffect(() => { + onRangeChange?.(leftHandle, rightHandle); + }, [leftHandle, rightHandle, onRangeChange]); + + const handleLeftDrag = (event: any, info: PanInfo) => { + const newLeft = Math.max( + 0, + Math.min(leftHandle + info.offset.x, rightHandle - minWidth) + ); + setLeftHandle(newLeft); + }; + + const handleRightDrag = (event: any, info: PanInfo) => { + const newRight = Math.max( + leftHandle + minWidth, + Math.min(contentWidth, rightHandle + info.offset.x) + ); + setRightHandle(newRight); + }; + + return ( +
+
+ {children} +
+ +
+
+ +
+
+ + +
+
+
+ + + + {children} + + +
+
+ ); +}; diff --git a/apps/web/src/components/landing/hero.tsx b/apps/web/src/components/landing/hero.tsx index 65fbb3d..776cc65 100644 --- a/apps/web/src/components/landing/hero.tsx +++ b/apps/web/src/components/landing/hero.tsx @@ -8,6 +8,7 @@ import { useState } from "react"; import { useToast } from "@/hooks/use-toast"; import Image from "next/image"; +import { Handlebars } from "./handlebars"; interface HeroProps { signupCount: number; @@ -91,14 +92,7 @@ export function Hero({ signupCount }: HeroProps) { className="inline-block font-bold tracking-tighter text-4xl md:text-[4rem]" >

The Open Source

-
-
- frame - - Video Editor - -
-
+ Video Editor