adding easter eggs to the contact page
This commit is contained in:
parent
4438953fab
commit
ba99d6a2be
BIN
public/pulsatingMap.jpg
Normal file
BIN
public/pulsatingMap.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
@ -1,28 +1,150 @@
|
||||
"use client";
|
||||
import Image from "next/image";
|
||||
import React, { useState } from "react";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
|
||||
import BottomFooter from "@components/BottomFooter";
|
||||
|
||||
const ContactUs = () => {
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
email: "",
|
||||
message: "",
|
||||
});
|
||||
// Form/modal
|
||||
const [formData, setFormData] = useState({ name: "", email: "", message: "" });
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
const handleChange = (e: { target: { name: any; value: any } }) => {
|
||||
// 1. Lava (Instagram): state & timer
|
||||
const [lavaActive, setLavaActive] = useState(false);
|
||||
const lavaTimeout = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
// 2. Pulsating Map (Facebook): state & timer
|
||||
const [pulsatingActive, setPulsatingActive] = useState(false);
|
||||
const pulsatingTimeout = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
// 3. Shake (LinkedIn): state & timer
|
||||
const [shaking, setShaking] = useState(false);
|
||||
const shakeTimeout = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
// 4. Crack & Collapse (X): state & timer
|
||||
const [showCracks, setShowCracks] = useState(false);
|
||||
const [collapse, setCollapse] = useState(false);
|
||||
const crackTimeout = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
// Lava flood handler (top-down flood)
|
||||
const handleInstagramClick = useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
setLavaActive(true);
|
||||
if (lavaTimeout.current) clearTimeout(lavaTimeout.current);
|
||||
lavaTimeout.current = setTimeout(() => setLavaActive(false), 2000);
|
||||
}, []);
|
||||
|
||||
// Pulsating Map handler
|
||||
const handleFacebookClick = useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
setPulsatingActive(true);
|
||||
if (pulsatingTimeout.current) clearTimeout(pulsatingTimeout.current);
|
||||
pulsatingTimeout.current = setTimeout(() => setPulsatingActive(false), 2000);
|
||||
}, []);
|
||||
|
||||
// LinkedIn shake handler
|
||||
const handleLinkedInClick = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
if (shaking) return;
|
||||
setShaking(true);
|
||||
const body = document.body;
|
||||
body.classList.remove("shake-screen");
|
||||
void body.offsetWidth;
|
||||
body.classList.add("shake-screen");
|
||||
if (shakeTimeout.current) clearTimeout(shakeTimeout.current);
|
||||
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);
|
||||
if (crackTimeout.current) clearTimeout(crackTimeout.current);
|
||||
crackTimeout.current = setTimeout(() => {
|
||||
setCollapse(true);
|
||||
setTimeout(() => {
|
||||
setShowCracks(false);
|
||||
setCollapse(false);
|
||||
}, 1500);
|
||||
}, 1000);
|
||||
}, []);
|
||||
|
||||
// Clean up timeouts and shake class
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (lavaTimeout.current) clearTimeout(lavaTimeout.current);
|
||||
if (pulsatingTimeout.current) clearTimeout(pulsatingTimeout.current);
|
||||
if (shakeTimeout.current) clearTimeout(shakeTimeout.current);
|
||||
if (crackTimeout.current) clearTimeout(crackTimeout.current);
|
||||
document.body.classList.remove("shake-screen");
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Form handlers
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||
};
|
||||
|
||||
const handleSubmit = (e: { preventDefault: () => void }) => {
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
console.log("Form submitted with data:", formData);
|
||||
alert("Thank you for reaching out! We will get back to you soon.");
|
||||
setIsModalOpen(true);
|
||||
setFormData({ name: "", email: "", message: "" });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-full relative text-white border border-black overflow-hidden">
|
||||
{/* Lava Flood Overlay */}
|
||||
{lavaActive && (
|
||||
<div className="lava-flood-overlay lava-active fixed inset-0 z-[60] flex items-center justify-center">
|
||||
<img
|
||||
src="/lava.jpg"
|
||||
alt="Lava flood"
|
||||
draggable={false}
|
||||
className="w-full h-full object-cover opacity-80 pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* Pulsating Overlay */}
|
||||
{pulsatingActive && (
|
||||
<div className="pulsating-map-overlay pulsating-active fixed inset-0 z-[60] flex items-center justify-center">
|
||||
<img
|
||||
src="/pulsatingMap.jpg"
|
||||
alt="Pulsating Map"
|
||||
draggable={false}
|
||||
className="w-full h-full object-cover opacity-80 pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* Crack & Collapse Overlay */}
|
||||
{(showCracks || collapse) && (
|
||||
<div
|
||||
className={`crack-overlay fixed inset-0 z-[60] flex items-center justify-center${collapse ? " crack-collapse" : ""}`}
|
||||
>
|
||||
<img className="crack crack1 absolute w-3/4" src="/crack1.png" alt="" />
|
||||
<img className="crack crack2 absolute w-3/4" src="/crack2.png" alt="" />
|
||||
</div>
|
||||
)}
|
||||
{/* Modal: Submit Success */}
|
||||
{isModalOpen && (
|
||||
<div className="fixed inset-0 z-[70] flex items-center justify-center bg-black/60">
|
||||
<div className="bg-white rounded-lg shadow-lg p-8 max-w-sm w-full text-center">
|
||||
<h2 className="text-2xl font-bold mb-4 text-neutral-800">Thank You!</h2>
|
||||
<p className="text-neutral-700 mb-6">Thank you for submitting a message. We will be responding via our email.</p>
|
||||
<button
|
||||
className="bg-blue-600 text-white px-5 py-2 rounded-lg font-medium hover:bg-blue-700 transition"
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<Image
|
||||
height={5000}
|
||||
width={5000}
|
||||
@ -30,7 +152,6 @@ const ContactUs = () => {
|
||||
className="border border-neutral-300 absolute z-10 -top-20"
|
||||
src="/tsunamiWaves.jpg"
|
||||
/>
|
||||
|
||||
{/* Overlay for readability */}
|
||||
<div className="absolute overflow-hidden w-full h-full bg-gradient-to-b from-black/80 via-black/40 to-black/20 flex flex-col items-center z-20">
|
||||
{/* Container */}
|
||||
@ -41,8 +162,6 @@ const ContactUs = () => {
|
||||
Have questions or concerns about earthquakes, observatories or artefacts? Contact us via phone, email, social media or
|
||||
using the form below with the relevant contact details.
|
||||
</p>
|
||||
|
||||
{/* Content Section */}
|
||||
<div className="flex flex-col md:flex-row gap-6">
|
||||
{/* Contact Form Section */}
|
||||
<div className="flex-1 bg-white bg-opacity-90 text-neutral-800 rounded-lg shadow-lg p-6">
|
||||
@ -62,7 +181,6 @@ const ContactUs = () => {
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<label htmlFor="email" className="block text-neutral-700 font-medium mb-2">
|
||||
Email
|
||||
@ -78,7 +196,6 @@ const ContactUs = () => {
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<label htmlFor="message" className="block text-neutral-700 font-medium mb-2">
|
||||
Message
|
||||
@ -95,7 +212,6 @@ const ContactUs = () => {
|
||||
style={{ resize: "none" }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-blue-600 text-white py-3 rounded-lg font-medium hover:bg-blue-700 transition duration-200"
|
||||
@ -104,7 +220,6 @@ const ContactUs = () => {
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{/* Contact Details Section */}
|
||||
<div className="w-[45%] bg-white bg-opacity-90 text-neutral-800 rounded-lg shadow-lg p-6">
|
||||
<h2 className="text-2xl font-bold text-neutral-800 mb-4">Get in Touch</h2>
|
||||
@ -120,23 +235,51 @@ const ContactUs = () => {
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-neutral-700 font-bold font-large">Address</h3>
|
||||
<p className="text-neutral-600 font-medium">1 Swentown Row, Greenwich, London, SE3 0FQ</p>
|
||||
<p className="text-neutral-600 font-medium">1 Sweentown Row, Greenwich, London, SE3 0FQ</p>
|
||||
</div>
|
||||
<h2 className="text-xl font-bold text-neutral-800 mb-4 mt-6">Follow Us</h2>
|
||||
<div className="flex justify-around items-center">
|
||||
<a href="#" className="w-20 h-20 text-blue-600 hover:text-blue-800 transition duration-200">
|
||||
{/* Instagram: Lava Flood */}
|
||||
<a
|
||||
href="#"
|
||||
className="w-20 h-20 text-blue-600 hover:text-blue-800 transition duration-200"
|
||||
aria-label="Instagram"
|
||||
onClick={handleInstagramClick}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<span className="sr-only">Instagram</span>
|
||||
<Image height={200} width={200} alt="Logo" className="z-10" src="/insta.webp" />
|
||||
</a>
|
||||
<a href="#" className="w-20 h-20 text-blue-600 hover:text-blue-800 transition duration-200">
|
||||
{/* Facebook: Pulsating Map */}
|
||||
<a
|
||||
href="#"
|
||||
className="w-20 h-20 text-blue-600 hover:text-blue-800 transition duration-200"
|
||||
aria-label="Facebook"
|
||||
onClick={handleFacebookClick}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<span className="sr-only">Facebook</span>
|
||||
<Image height={200} width={200} alt="Logo" className="z-10" src="/facebook.webp" />
|
||||
</a>
|
||||
<a href="#" className="w-20 h-20 p-4 text-blue-600 hover:text-blue-800 transition duration-200">
|
||||
{/* X: Crack & Collapse */}
|
||||
<a
|
||||
href="#"
|
||||
className="w-20 h-20 p-4 text-blue-600 hover:text-blue-800 transition duration-200"
|
||||
aria-label="X"
|
||||
onClick={handleXClick}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<span className="sr-only">X</span>
|
||||
<Image height={200} width={200} alt="Logo" className="z-10 rounded-lg" src="/x_logo.jpg" />
|
||||
</a>
|
||||
<a href="#" className="w-20 h-20 flex items-center text-blue-600 hover:text-blue-800 transition duration-200">
|
||||
{/* LinkedIn: Shake */}
|
||||
<a
|
||||
href="#"
|
||||
className="w-20 h-20 flex items-center text-blue-600 hover:text-blue-800 transition duration-200"
|
||||
aria-label="LinkedIn"
|
||||
onClick={handleLinkedInClick}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<span className="sr-only">LinkedIn</span>
|
||||
<Image height={200} width={200} alt="Logo" className="z-10" src="/linkedIn.png" />
|
||||
</a>
|
||||
|
||||
@ -191,7 +191,6 @@ export default function Shop() {
|
||||
|
||||
// todo create receiving api route
|
||||
// todo handle sending to api route
|
||||
// todo only ask for email if the user is not signed in
|
||||
// todo (optional) add create account button to auto-fill email in sign-up modal
|
||||
const genOrder = () => "#" + Math.random().toString(36).substring(2, 10).toUpperCase();
|
||||
setOrderNumber(genOrder());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user