diff --git a/public/crack1.png b/public/crack1.png new file mode 100644 index 0000000..f366469 Binary files /dev/null and b/public/crack1.png differ diff --git a/public/crack2.png b/public/crack2.png new file mode 100644 index 0000000..f6ca3e1 Binary files /dev/null and b/public/crack2.png differ diff --git a/public/lava.jpg b/public/lava.jpg new file mode 100644 index 0000000..ea8a87b Binary files /dev/null and b/public/lava.jpg differ diff --git a/src/app/globals.css b/src/app/globals.css index 2ab11b8..5fe3514 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -64,4 +64,167 @@ body { .icon-link:focus p { color: #111; /* or black */ +} + +/* ---- LAVA FLOOD OVERLAY ---- */ +.lava-flood-overlay { + pointer-events: none; + position: fixed; + top: -100vh; + left: 0; + right: 0; + width: 100vw; + height: 100vh; + z-index: 9999; + display: flex; + justify-content: center; + align-items: flex-start; + transition: top 0.9s cubic-bezier(.6, 0, .2, 1); +} + +.lava-flood-overlay.lava-active { + top: 0; + transition: top 0.33s cubic-bezier(.6, 0, .2, 1); +} + +.lava-flood-overlay img, +.lava-gradient { + width: 100vw; + height: 100vh; + object-fit: cover; + pointer-events: none; + user-select: none; + filter: brightness(1.15) saturate(1.8) drop-shadow(0 0 80px #ff5500); +} + +/* ---- INSANE SCREEN SHAKE (LinkedIn) ---- */ +@keyframes supershake { + 0% { + transform: translate(0, 0) rotate(0); + } + + 5% { + transform: translate(-20px, 5px) rotate(-2deg); + } + + 10% { + transform: translate(18px, -8px) rotate(2deg); + } + + 15% { + transform: translate(-22px, 8px) rotate(-4deg); + } + + 20% { + transform: translate(22px, -2px) rotate(4deg); + } + + 25% { + transform: translate(-18px, 12px) rotate(-2deg); + } + + 30% { + transform: translate(18px, -10px) rotate(2deg); + } + + 35% { + transform: translate(-22px, 14px) rotate(-4deg); + } + + 40% { + transform: translate(22px, -12px) rotate(4deg); + } + + 45% { + transform: translate(-18px, 8px) rotate(-2deg); + } + + 50% { + transform: translate(18px, -14px) rotate(4deg); + } + + 55% { + transform: translate(-22px, 12px) rotate(-4deg); + } + + 60% { + transform: translate(22px, -8px) rotate(2deg); + } + + 65% { + transform: translate(-18px, 10px) rotate(-2deg); + } + + 70% { + transform: translate(18px, -12px) rotate(2deg); + } + + 75% { + transform: translate(-22px, 14px) rotate(-4deg); + } + + 80% { + transform: translate(22px, -10px) rotate(4deg); + } + + 85% { + transform: translate(-18px, 8px) rotate(-2deg); + } + + 90% { + transform: translate(18px, -14px) rotate(2deg); + } + + 95% { + transform: translate(-20px, 5px) rotate(-2deg); + } + + 100% { + transform: translate(0, 0) rotate(0); + } +} + +.shake-screen { + animation: supershake 1s cubic-bezier(.36, .07, .19, .97) both; +} + +/* ---- CRACK + COLLAPSE OVERLAY (X icon) ---- */ +.crack-overlay { + pointer-events: none; + position: fixed; + inset: 0; + width: 100vw; + height: 100vh; + z-index: 9999; + transition: transform 1.1s cubic-bezier(.65, .05, .45, 1), opacity 0.5s; + will-change: transform, opacity; +} + +.crack { + position: absolute; + pointer-events: none; +} + +.crack1 { + width: 35vw; + left: 10vw; + top: 22vh; + opacity: 0.8; +} + +.crack2 { + width: 32vw; + right: 12vw; + top: 42vh; + opacity: 0.7; + transform: rotate(-8deg); +} + +/* Add more .crackN classes if using more cracks */ + +/* Collapse falling effect */ +.crack-collapse { + transform: perspective(900px) rotateX(75deg) translateY(80vh) scale(0.9); + opacity: 0; + transition: transform 1.1s cubic-bezier(.65, .05, .45, 1), opacity 0.6s; } \ No newline at end of file diff --git a/src/app/learn/page.tsx b/src/app/learn/page.tsx index ad0542f..b11f775 100644 --- a/src/app/learn/page.tsx +++ b/src/app/learn/page.tsx @@ -55,7 +55,7 @@ export default function LearnPage() {
  • First aid kit and emergency medication
  • Food (non-perishable)
  • Bottled water
  • -
  • Torch (flashlight)
  • +
  • Torch
  • Satellite phone
  • Warm clothing and blankets
  • diff --git a/src/app/observatories/page.tsx b/src/app/observatories/page.tsx index 6409fac..d1a919e 100644 --- a/src/app/observatories/page.tsx +++ b/src/app/observatories/page.tsx @@ -22,18 +22,17 @@ export default function Observatories() { const observatoryEvents = useMemo( () => data && data.observatories - ? data.observatories - .map( - (x: Observatory): GeologicalEvent => ({ - id: x.id.toString(), - title: `New Observatory - ${x.name}`, - longitude: x.longitude, - latitude: x.latitude, - text1: "", - text2: getRelativeDate(x.dateEstablished), - date: x.dateEstablished, - }) - ) + ? data.observatories + .map((x: Observatory): GeologicalEvent & { isFunctional: boolean } => ({ + id: x.id.toString(), + title: ` ${x.name}`, + longitude: x.longitude, + latitude: x.latitude, + isFunctional: x.isFunctional, // <-- include this! + text1: "", + text2: getRelativeDate(x.dateEstablished), + date: x.dateEstablished, + })) .sort( (a: GeologicalEvent, b: GeologicalEvent) => new Date(b.date).getTime() - new Date(a.date).getTime() diff --git a/src/components/BottomFooter.tsx b/src/components/BottomFooter.tsx index 80f133c..39339fd 100644 --- a/src/components/BottomFooter.tsx +++ b/src/components/BottomFooter.tsx @@ -1,74 +1,170 @@ -// components/Footer.tsx +import React, { useCallback, useRef, useState } from "react"; import Link from "next/link"; -import { FaFacebook, FaLinkedin, FaTwitter, FaYoutube } from "react-icons/fa"; -export default function Footer() { - return ( - - ); -} +export default function BottomFooter() { + // Lava flood state & timer + const [lavaActive, setLavaActive] = useState(false); + const lavaTimeout = useRef(null); + + // LinkedIn shake state & timer + const [shaking, setShaking] = useState(false); + const shakeTimeout = useRef(null); + + // Crack+collapse states for the X logo + const [showCracks, setShowCracks] = useState(false); + const [collapse, setCollapse] = useState(false); + const crackTimeout = useRef(null); + + // Lava flood handler (top-down flood) + const handleInstagramClick = useCallback((e: React.MouseEvent) => { + e.preventDefault(); + setLavaActive(true); + clearTimeout(lavaTimeout.current); + lavaTimeout.current = setTimeout(() => setLavaActive(false), 2000); + }, []); + + // LinkedIn shake handler + const handleLinkedInClick = useCallback((e: React.MouseEvent) => { + e.preventDefault(); + if (shaking) return; // prevent stacking + setShaking(true); + const body = document.body; + body.classList.remove("shake-screen"); + void body.offsetWidth; + body.classList.add("shake-screen"); + shakeTimeout.current = setTimeout(() => { + setShaking(false); + body.classList.remove("shake-screen"); + }, 1000); + }, [shaking]); + + // X (crack and collapse) handler + const handleXClick = useCallback((e: React.MouseEvent) => { + e.preventDefault(); + setShowCracks(true); + crackTimeout.current = setTimeout(() => { + setCollapse(true); + setTimeout(() => { + setShowCracks(false); + setCollapse(false); + }, 1500); + }, 1000); + }, []); + + React.useEffect(() => { + return () => { + clearTimeout(lavaTimeout.current); + clearTimeout(shakeTimeout.current); + clearTimeout(crackTimeout.current); + document.body.classList.remove("shake-screen"); + }; + }, []); + + return ( + <> + {/* Lava Flood Overlay */} + {lavaActive && ( +
    + Lava flood +
    + )} + + {/* Crack & Collapse Overlay */} + {(showCracks || collapse) && ( +
    + + + {/* Add more cracks for extra effect if you wish */} +
    + )} + + {/* Footer */} +
    +
    + {/* Useful Links */} +
    +

    Useful links

    +
      +
    • + + Gov.UK guidance + +
    • +
    • + + Privacy policy + +
    • +
    • + + Cookies policy + +
    • +
    +
    + + {/* Donate Section */} +
    +

    Donate

    +

    + We are a nonprofit entirely funded by your donations, every penny helps provide life saving information. +

    + + Donate Now + +
    +
    + + {/* Bottom bar */} +
    + + © TremorTracker 2025 + +
    + Follow us on + +
    +
    +
    + + ); +} \ No newline at end of file diff --git a/src/components/Map.tsx b/src/components/Map.tsx index 2a4094a..9472d62 100644 --- a/src/components/Map.tsx +++ b/src/components/Map.tsx @@ -111,8 +111,12 @@ function MapComponent({ } const observatoryElement = document.createElement("div"); - const root = createRoot(observatoryElement); - root.render(); + const root = createRoot(observatoryElement); + root.render( + + ); quakeElement.appendChild(pulseElement); quakeElement.appendChild(dotElement);