spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1"use client";23import dynamic from "next/dynamic";4import Link from "next/link";5import { useEffect, useRef, useState } from "react";6import { cn } from "@/components/ui/cn";7import { Skeleton } from "@/components/ui/skeleton";8import { routes } from "@/lib/routes";910const MapCanvas = dynamic(() => import("@/components/map/map-canvas").then((m) => m.MapCanvas), { ssr: false, loading: () => <Skeleton className="h-full w-full rounded-none" /> });1112/**13 * Home: live global map (clusters at zoom ~1.4), lazy-loaded when scrolled into view; the whole surface links to /map.14 * `interactive` lets the hero map pan/zoom while the corner button keeps the way into the full map.15 */16export function MapPreview({ className, interactive, children }: { className?: string; interactive?: boolean; children?: React.ReactNode }) {17 const ref = useRef<HTMLDivElement>(null);18 const [visible, setVisible] = useState(false);19 useEffect(() => {20 const el = ref.current;21 if (!el) return;22 if (typeof IntersectionObserver === "undefined") {23 const t = setTimeout(() => setVisible(true), 0);24 return () => clearTimeout(t);25 }26 const io = new IntersectionObserver(27 (entries) => {28 if (entries.some((e) => e.isIntersecting)) {29 setVisible(true);30 io.disconnect();31 }32 },33 { rootMargin: "200px" },34 );35 io.observe(el);36 return () => io.disconnect();37 }, []);38 return (39 <div ref={ref} className={cn("relative w-full overflow-hidden rounded-sm border border-hair bg-surface-2", className ?? "h-[260px] sm:h-[380px]")}>40 {visible ? <MapCanvas preview interactivePreview={interactive} className="h-full w-full" /> : <Skeleton className="h-full w-full rounded-none" />}41 {children}42 {interactive ? (43 <Link href={routes.map()} aria-label="Open the interactive map" className="absolute bottom-3 right-3 z-[2] inline-flex h-10 items-center gap-1.5 rounded-sm border border-hair-2 bg-surface px-3 text-[12.5px] font-medium text-ink outline-none hover:border-ink focus-visible:ring-2 focus-visible:ring-accent sm:h-9">44 Open interactive map <span aria-hidden>→</span>45 </Link>46 ) : (47 <Link href={routes.map()} aria-label="Open the interactive map" className="absolute inset-0 z-[2] flex items-end justify-end p-3 outline-none focus-visible:ring-2 focus-visible:ring-accent">48 <span className="inline-flex h-9 items-center gap-1.5 rounded-sm border border-hair-2 bg-surface px-3 text-[12.5px] font-medium text-ink">49 Open interactive map <span aria-hidden>→</span>50 </span>51 </Link>52 )}53 </div>54 );55}56