"use client"; import { useCallback, useRef, useEffect } from "react"; import { motion } from "motion/react"; import { Plus, Minus, ChevronsUp, ChevronsDown, RotateCw, RotateCcw, Navigation, } from "lucide-react"; import { useSettings } from "@/hooks/use-settings"; type CameraActionType = "zoom" | "pitch" | "bearing"; function dispatchCameraStart(type: CameraActionType, direction: number) { window.dispatchEvent( new CustomEvent("aeris:camera-start", { detail: { type, direction } }), ); } function dispatchCameraStop(type: CameraActionType) { window.dispatchEvent( new CustomEvent("aeris:camera-stop", { detail: { type } }), ); } function useCameraAction(type: CameraActionType, direction: number) { const activeRef = useRef(false); const start = useCallback(() => { if (activeRef.current) return; activeRef.current = true; dispatchCameraStart(type, direction); }, [type, direction]); const stop = useCallback(() => { if (!activeRef.current) return; activeRef.current = false; dispatchCameraStop(type); }, [type]); useEffect( () => () => { if (activeRef.current) dispatchCameraStop(type); }, [type], ); return { onPointerDown: start, onPointerUp: stop, onPointerLeave: stop }; } function ControlButton({ type, direction, label, title, children, }: { type: CameraActionType; direction: number; label: string; title: string; children: React.ReactNode; }) { const handlers = useCameraAction(type, direction); return ( e.preventDefault()} > {children} ); } function Divider() { return (
); } export function CameraControls() { const { settings, update } = useSettings(); const locked = settings.lockNorthUp; return (
update("lockNorthUp", !locked)} > ); }