t2-mapper/src/components/CopyCoordinatesButton.tsx
2026-03-16 18:16:34 -07:00

74 lines
2.4 KiB
TypeScript

import { RefObject, useCallback, useRef, useState } from "react";
import { FaMapPin } from "react-icons/fa";
import { FaClipboardCheck } from "react-icons/fa6";
import { Camera, Quaternion, Vector3 } from "three";
import { useSettings } from "./SettingsProvider";
import styles from "./CopyCoordinatesButton.module.css";
function encodeViewHash({
position,
quaternion,
}: {
position: Vector3;
quaternion: Quaternion;
}) {
const trunc = (num: number) => parseFloat(num.toFixed(3));
const encodedPosition = `${trunc(position.x)},${trunc(position.y)},${trunc(position.z)}`;
const encodedQuaternion = `${trunc(quaternion.x)},${trunc(quaternion.y)},${trunc(quaternion.z)},${trunc(quaternion.w)}`;
return `#c${encodedPosition}~${encodedQuaternion}`;
}
export function CopyCoordinatesButton({
cameraRef,
missionName,
missionType,
disabled,
}: {
cameraRef: RefObject<Camera | null>;
missionName: string;
missionType?: string;
disabled?: boolean;
}) {
const { fogEnabled } = useSettings();
const [showCopied, setShowCopied] = useState(false);
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const handleCopyLink = useCallback(async () => {
if (timerRef.current) clearTimeout(timerRef.current);
const camera = cameraRef.current;
if (!camera) return;
const hash = encodeViewHash(camera);
const params = new URLSearchParams();
params.set("mission", `${missionName}~${missionType}`);
params.set("fog", fogEnabled.toString());
const fullPath = `${window.location.pathname}?${params}${hash}`;
const fullUrl = `${window.location.origin}${fullPath}`;
window.history.replaceState(null, "", fullPath);
try {
await navigator.clipboard.writeText(fullUrl);
setShowCopied(true);
timerRef.current = setTimeout(() => {
setShowCopied(false);
}, 1100);
} catch (err) {
console.error(err);
}
}, [cameraRef, missionName, missionType, fogEnabled]);
return (
<button
type="button"
className={styles.Root}
aria-label="Link to coordinates"
title="Copy the current coordinates to URL"
onClick={handleCopyLink}
disabled={disabled}
data-copied={showCopied ? "true" : "false"}
id="copyCoordinatesButton"
>
<FaMapPin className={styles.MapPin} />
<FaClipboardCheck className={styles.ClipboardCheck} />
<span className={styles.ButtonLabel}> Link to coordinates</span>
</button>
);
}