Compare commits
No commits in common. "06e215a209e701a801931eff7d36ceb256330b6d" and "e93926fca3cbbb80df7463e337024cf25b7eb909" have entirely different histories.
06e215a209
...
e93926fca3
@ -10,18 +10,18 @@ generator client {
|
||||
|
||||
// User model
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
createdAt DateTime @default(now())
|
||||
name String
|
||||
email String @unique
|
||||
passwordHash String
|
||||
role String @default("GUEST") @db.VarChar(10) // Allowed: ADMIN, SCIENTIST, GUEST
|
||||
scientist Scientist? @relation
|
||||
purchasedOrders Order[] @relation("UserOrders")
|
||||
requests Request[] @relation("UserRequests")
|
||||
earthquakes Earthquake[] @relation("UserEarthquakeCreator")
|
||||
observatories Observatory[] @relation("UserObservatoryCreator")
|
||||
artefacts Artefact[] @relation("UserArtefactCreator")
|
||||
id Int @id @default(autoincrement())
|
||||
createdAt DateTime @default(now())
|
||||
name String
|
||||
email String @unique
|
||||
passwordHash String
|
||||
role String @default("GUEST") @db.VarChar(10) // Allowed: ADMIN, SCIENTIST, GUEST
|
||||
scientist Scientist? @relation
|
||||
purchasedOrders Order[] @relation("UserOrders")
|
||||
requests Request[] @relation("UserRequests")
|
||||
earthquakes Earthquake[] @relation("UserEarthquakeCreator")
|
||||
observatories Observatory[] @relation("UserObservatoryCreator")
|
||||
artefacts Artefact[] @relation("UserArtefactCreator")
|
||||
}
|
||||
|
||||
model Request {
|
||||
@ -35,15 +35,15 @@ model Request {
|
||||
|
||||
// Scientist model
|
||||
model Scientist {
|
||||
id Int @id @default(autoincrement())
|
||||
createdAt DateTime @default(now())
|
||||
name String
|
||||
level String @db.VarChar(10) // JUNIOR, SENIOR
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId Int @unique
|
||||
superior Scientist? @relation("SuperiorRelation", fields: [superiorId], references: [id], onDelete: NoAction, onUpdate: NoAction)
|
||||
superiorId Int?
|
||||
subordinates Scientist[] @relation("SuperiorRelation")
|
||||
id Int @id @default(autoincrement())
|
||||
createdAt DateTime @default(now())
|
||||
name String
|
||||
level String @db.VarChar(10) // JUNIOR, SENIOR
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId Int @unique
|
||||
superior Scientist? @relation("SuperiorRelation", fields: [superiorId], references: [id], onDelete: NoAction, onUpdate: NoAction)
|
||||
superiorId Int?
|
||||
subordinates Scientist[] @relation("SuperiorRelation")
|
||||
}
|
||||
|
||||
model Earthquake {
|
||||
@ -93,7 +93,7 @@ model Artefact {
|
||||
earthquake Earthquake @relation(fields: [earthquakeId], references: [id])
|
||||
creatorId Int?
|
||||
creator User? @relation("UserArtefactCreator", fields: [creatorId], references: [id], onDelete: NoAction, onUpdate: NoAction)
|
||||
isRequired Boolean @default(true) @map("isRequired")
|
||||
isRequired Boolean @default(true)
|
||||
dateAddedToShop DateTime?
|
||||
shopPrice Float?
|
||||
isSold Boolean @default(false)
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 862 KiB |
BIN
public/artefacts.jpg
Normal file
|
After Width: | Height: | Size: 280 KiB |
BIN
public/crackedRoad.jpg
Normal file
|
After Width: | Height: | Size: 848 KiB |
|
Before Width: | Height: | Size: 319 KiB |
BIN
public/insta.webp
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
public/lava.jpg
Normal file
|
After Width: | Height: | Size: 438 KiB |
BIN
public/road.jpg
Normal file
|
After Width: | Height: | Size: 614 KiB |
BIN
public/tectonicPlate.jpg
Normal file
|
After Width: | Height: | Size: 315 KiB |
|
Before Width: | Height: | Size: 85 KiB |
@ -1,18 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { prisma } from "@utils/prisma";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const artefact = await prisma.artefact.findMany();
|
||||
|
||||
return NextResponse.json({
|
||||
message: "Got artefacts successfully",
|
||||
artefact
|
||||
}, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error in artefacts endpoint:", error);
|
||||
return NextResponse.json({ message: "Internal Server Error" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@ -2,157 +2,65 @@
|
||||
|
||||
import { useMemo, useState } from "react";
|
||||
import useSWR from "swr";
|
||||
|
||||
import Map from "@components/Map";
|
||||
import Sidebar from "@components/Sidebar";
|
||||
import { createPoster } from "@utils/axiosHelpers";
|
||||
import { Earthquake } from "@prismaclient";
|
||||
import { getRelativeDate } from "@utils/formatters";
|
||||
import GeologicalEvent from "@appTypes/Event";
|
||||
import axios from "axios";
|
||||
|
||||
// --- SEARCH MODAL COMPONENT ---
|
||||
function EarthquakeSearchModal({ open, onClose, onSelect }) {
|
||||
const [search, setSearch] = useState("");
|
||||
const [results, setResults] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleSearch = async (e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
setResults([]);
|
||||
try {
|
||||
const res = await axios.post("/api/earthquakes/search", { query: search });
|
||||
setResults(res.data.earthquakes || []);
|
||||
} catch (e) {
|
||||
alert("Failed to search.");
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
if (!open) return null;
|
||||
return (
|
||||
<div className="fixed z-50 inset-0 bg-black/40 flex items-center justify-center">
|
||||
<div className="bg-white rounded-lg shadow-lg p-6 max-w-lg w-full relative">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="absolute right-4 top-4 text-gray-500 hover:text-black text-lg"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
<h2 className="font-bold text-xl mb-4">Search Earthquakes</h2>
|
||||
<form onSubmit={handleSearch} className="flex gap-2 mb-4">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="e.g. Mexico, EV-7.4-Mexico-00035"
|
||||
value={search}
|
||||
onChange={e => setSearch(e.target.value)}
|
||||
className="flex-grow px-3 py-2 border rounded"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
|
||||
>
|
||||
{loading ? "Searching..." : "Search"}
|
||||
</button>
|
||||
</form>
|
||||
<div>
|
||||
{results.length === 0 && !loading && search !== "" && (
|
||||
<p className="text-gray-400 text-sm">No results found.</p>
|
||||
)}
|
||||
<ul>
|
||||
{results.map(eq => (
|
||||
<li
|
||||
key={eq.id}
|
||||
className="border-b py-2 cursor-pointer hover:bg-gray-50 flex items-center justify-between"
|
||||
onClick={() => { onSelect(eq); onClose(); }}
|
||||
tabIndex={0}
|
||||
>
|
||||
<div>
|
||||
<strong>{eq.code}</strong> {" "}
|
||||
<span>{eq.location}</span> <span className="text-xs text-gray-500">{new Date(eq.date).toLocaleDateString()}</span>
|
||||
</div>
|
||||
<div className={`rounded-full px-2 py-1 ml-2 text-white font-semibold ${eq.magnitude >= 7 ? "bg-red-500" : eq.magnitude >= 6 ? "bg-orange-400" : "bg-yellow-400"}`}>
|
||||
{eq.magnitude}
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// --- MAIN PAGE COMPONENT ---
|
||||
export default function Earthquakes() {
|
||||
const [selectedEventId, setSelectedEventId] = useState("");
|
||||
const [hoveredEventId, setHoveredEventId] = useState("");
|
||||
const [selectedEventId, setSelectedEventId] = useState("");
|
||||
const [hoveredEventId, setHoveredEventId] = useState("");
|
||||
// todo properly integrate loading
|
||||
const { data, error, isLoading } = useSWR("/api/earthquakes", createPoster({ rangeDaysPrev: 5 }));
|
||||
|
||||
// Search modal state
|
||||
const [searchModalOpen, setSearchModalOpen] = useState(false);
|
||||
const earthquakeEvents = useMemo(
|
||||
() =>
|
||||
data && data.earthquakes
|
||||
? data.earthquakes
|
||||
.map(
|
||||
(x: Earthquake): GeologicalEvent => ({
|
||||
id: x.code,
|
||||
title: `Earthquake in ${x.code.split("-")[2]}`,
|
||||
magnitude: x.magnitude,
|
||||
longitude: x.longitude,
|
||||
latitude: x.latitude,
|
||||
text1: "",
|
||||
text2: getRelativeDate(x.date),
|
||||
date: x.date,
|
||||
})
|
||||
)
|
||||
.sort((a: GeologicalEvent, b: GeologicalEvent) => new Date(b.date).getTime() - new Date(a.date).getTime()) // Remove Date conversion
|
||||
: [],
|
||||
[data]
|
||||
);
|
||||
|
||||
// Fetch recent earthquakes as before
|
||||
const { data, error, isLoading } = useSWR("/api/earthquakes", createPoster({ rangeDaysPrev: 5 }));
|
||||
|
||||
// Prepare events for maps/sidebar
|
||||
const earthquakeEvents = useMemo(
|
||||
() =>
|
||||
data && data.earthquakes
|
||||
? data.earthquakes
|
||||
.map(
|
||||
(x: Earthquake): GeologicalEvent => ({
|
||||
id: x.code,
|
||||
title: `Earthquake in ${x.code.split("-")[2]}`,
|
||||
magnitude: x.magnitude,
|
||||
longitude: x.longitude,
|
||||
latitude: x.latitude,
|
||||
text1: "",
|
||||
text2: getRelativeDate(x.date),
|
||||
date: x.date,
|
||||
})
|
||||
)
|
||||
.sort((a: GeologicalEvent, b: GeologicalEvent) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
||||
: [],
|
||||
[data]
|
||||
);
|
||||
|
||||
// Optional: show details of selected search result (not implemented here)
|
||||
// const [selectedSearchResult, setSelectedSearchResult] = useState(null);
|
||||
|
||||
return (
|
||||
<div className="flex h-[calc(100vh-3.5rem)] w-full overflow-hidden">
|
||||
<div className="flex-grow h-full">
|
||||
<Map
|
||||
events={earthquakeEvents}
|
||||
selectedEventId={selectedEventId}
|
||||
setSelectedEventId={setSelectedEventId}
|
||||
hoveredEventId={hoveredEventId}
|
||||
setHoveredEventId={setHoveredEventId}
|
||||
mapType="Earthquakes"
|
||||
/>
|
||||
</div>
|
||||
<Sidebar
|
||||
logTitle="Log an Earthquake"
|
||||
logSubtitle="Record new earthquakes - time/date, location, magnitude, observatory and scientists"
|
||||
recentsTitle="Recent Earthquakes"
|
||||
events={earthquakeEvents}
|
||||
selectedEventId={selectedEventId}
|
||||
setSelectedEventId={setSelectedEventId}
|
||||
hoveredEventId={hoveredEventId}
|
||||
setHoveredEventId={setHoveredEventId}
|
||||
button1Name="Log an Earthquake"
|
||||
button2Name="Search Earthquakes"
|
||||
onButton2Click={() => setSearchModalOpen(true)} // <-- important!
|
||||
/>
|
||||
<EarthquakeSearchModal
|
||||
open={searchModalOpen}
|
||||
onClose={() => setSearchModalOpen(false)}
|
||||
onSelect={eq => {
|
||||
setSelectedEventId(eq.code); // select on map/sidebar
|
||||
// setSelectedSearchResult(eq); // you can use this if you want to show detail modal
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="flex h-[calc(100vh-3.5rem)] w-full overflow-hidden">
|
||||
<div className="flex-grow h-full">
|
||||
<Map
|
||||
events={earthquakeEvents}
|
||||
selectedEventId={selectedEventId}
|
||||
setSelectedEventId={setSelectedEventId}
|
||||
hoveredEventId={hoveredEventId}
|
||||
setHoveredEventId={setHoveredEventId}
|
||||
mapType="Earthquakes"
|
||||
/>
|
||||
</div>
|
||||
<Sidebar
|
||||
logTitle="Log an Earthquake"
|
||||
logSubtitle="Record new earthquakes - time/date, location, magnitude, observatory and scientists"
|
||||
recentsTitle="Recent Earthquakes"
|
||||
events={earthquakeEvents}
|
||||
selectedEventId={selectedEventId}
|
||||
setSelectedEventId={setSelectedEventId}
|
||||
hoveredEventId={hoveredEventId}
|
||||
setHoveredEventId={setHoveredEventId}
|
||||
button1Name="Log an Earthquake"
|
||||
button2Name="Search Earthquakes"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { prisma } from "@utils/prisma";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
try {
|
||||
const { query } = await req.json();
|
||||
|
||||
// Find earthquakes where either code or location matches (case-insensitive)
|
||||
const earthquakes = await prisma.earthquake.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{ code: { contains: query, mode: "insensitive" } },
|
||||
{ location: { contains: query, mode: "insensitive" } }
|
||||
],
|
||||
},
|
||||
orderBy: { date: "desc" },
|
||||
take: 20, // limit results
|
||||
});
|
||||
|
||||
return NextResponse.json({ earthquakes, message: "Success" });
|
||||
} catch (error) {
|
||||
console.error("Error in earthquake search", error);
|
||||
return NextResponse.json({ message: "Internal Server Error" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@ -1,53 +1,48 @@
|
||||
// app/learn/page.tsx
|
||||
"use client";
|
||||
import BottomFooter from "@components/BottomFooter";
|
||||
|
||||
export default function LearnPage() {
|
||||
return (
|
||||
<div
|
||||
className="min-h-screen bg-fixed bg-cover bg-center flex flex-col relative"
|
||||
style={{
|
||||
backgroundImage: "url('/earthquakeRelief.jpg')", // adjust path as needed
|
||||
}}
|
||||
>
|
||||
{/* Overlay for readability */}
|
||||
<div className="absolute inset-0 bg-black bg-opacity-50"></div>
|
||||
<div className="min-h-screen bg-blue-50 flex flex-col">
|
||||
{/* (Optional) Navbar */}
|
||||
{/* <Navbar /> */}
|
||||
|
||||
<main className="flex-1 flex flex-col items-center justify-start pt-16 px-4 relative z-20">
|
||||
{/* Title & subtitle OVER the background (not in the content box) */}
|
||||
<h1 className="text-4xl font-bold mb-4 text-white text-center drop-shadow-lg">Earthquakes</h1>
|
||||
<p className="max-w-2xl text-lg text-white mb-8 text-center font-bold drop-shadow">
|
||||
In this page, you can learn all about what earthquakes are, and how best to keep safe!
|
||||
<main className="flex-1 flex flex-col items-center justify-start pt-12 px-4">
|
||||
<h1 className="text-4xl font-bold mb-4 text-blue-800 text-center">Earthquakes</h1>
|
||||
<p className="max-w-2xl text-lg text-gray-700 mb-6 text-center">
|
||||
<span className="font-bold">In this page, you can learn all about what earthquakes are, and how to keep safe!</span>
|
||||
</p>
|
||||
|
||||
{/* Content box: all following info INSIDE */}
|
||||
<div className="max-w-4xl w-full bg-white bg-opacity-90 rounded-xl shadow-2xl mx-auto mb-12 p-8 md:p-10">
|
||||
<div className="max-w-3xl text-base text-gray-600 text-left space-y-8">
|
||||
{/* Section 1 */}
|
||||
<section className="mb-8">
|
||||
<section>
|
||||
<p>
|
||||
<span className="font-bold text-black md:text-xl">What are earthquakes?</span>
|
||||
<span className="font-semibold text-blue-800">What are earthquakes?</span>
|
||||
<br />
|
||||
Earthquakes are a shaking of the earth's surface caused by a sudden release of energy underground. They can range in
|
||||
size, from tiny trembles to large quakes, which can cause destruction and even tsunamis. Hundreds of earthquakes
|
||||
happen every day—but most are too small to feel.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Section 2 */}
|
||||
<section className="mb-8">
|
||||
<section>
|
||||
<p>
|
||||
<span className="font-bold text-black md:text-xl">What are the types of earthquakes?</span>
|
||||
<span className="font-semibold text-blue-800">What are the types of earthquakes?</span>
|
||||
<br />
|
||||
Regions near plate boundaries, such as around the Pacific Ocean ("The Ring of Fire"), experience the most activity.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Section 3 */}
|
||||
<section>
|
||||
<p>
|
||||
<span className="font-bold text-black md:text-xl">How can I be prepared?</span>
|
||||
<span className="font-semibold text-blue-800">How can I be prepared?</span>
|
||||
</p>
|
||||
{/* MAIN BULLET POINTS */}
|
||||
<ul className="list-disc list-inside pl-6 space-y-2">
|
||||
<li>
|
||||
<span className="font-bold text-gray-800 ">Assemble an emergency kit:</span>
|
||||
<span className="font-bold text-gray-800">Assemble an emergency kit:</span>
|
||||
This should be stored in your earthquake emergency zone. It may be useful, as in an earthquake, you may lose
|
||||
electricity or water supplies.
|
||||
{/* SUB BULLETS */}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
import BottomFooter from "@components/BottomFooter";
|
||||
|
||||
export default function Home() {
|
||||
@ -17,7 +16,10 @@ export default function Home() {
|
||||
</div>
|
||||
<p className="mt-2"></p>
|
||||
<div className="flex flex-col md:flex-row md:justify-evenly gap-6 mt-2">
|
||||
<Link href="/earthquakes" className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300">
|
||||
<Link
|
||||
href="/earthquakes"
|
||||
className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300"
|
||||
>
|
||||
<Image height={100} width={100} src="/earthquake.png" alt="Education Icon" className="h-40 w-40 mb-4" />
|
||||
<h3 className="text-xl font-bold text-black mb-4">Earthquakes</h3>
|
||||
<p className="text-md text-black text-center max-w-xs opacity-90">
|
||||
@ -34,7 +36,10 @@ export default function Home() {
|
||||
Find recently active observatories, and newly opened/closed sites
|
||||
</p>
|
||||
</Link>
|
||||
<Link href="/shop" className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300">
|
||||
<Link
|
||||
href="/shop"
|
||||
className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300"
|
||||
>
|
||||
<Image height={100} width={100} src="/artifactIcon.jpg" alt="Technology Icon" className="h-40 w-40 mb-4" />
|
||||
<h3 className="text-xl font-bold text-black mb-4">Artefacts</h3>
|
||||
<p className="text-md text-black text-center max-w-xs opacity-90">
|
||||
@ -54,16 +59,11 @@ export default function Home() {
|
||||
Welcome to Tremor Tracker
|
||||
</h1>
|
||||
<p className="text-lg md:text-xl font-sans text-white w-4/6 mx-auto drop-shadow-md z-10">
|
||||
TremorTracker is a non-profit website and research company, that aims to provide true, reliable data. Our mission
|
||||
is seismic education and preparation for all
|
||||
TremorTracker is a non-profit website and research company, that aims to provide true, reliable data. Our mission is seismic education and preparation for all
|
||||
</p>
|
||||
<p className="mt-20"></p>
|
||||
<p className="text-lg md:text-3xl font-bold text-white w-4/6 mx-auto drop-shadow-md z-10">What is an earthquake?</p>
|
||||
<p className="text-lg md:text-xl text-white w-4/6 mx-auto drop-shadow-md z-10">
|
||||
Earthquakes are a shaking of the earth's surface caused by a sudden release of energy underground. They can range
|
||||
in size, from tiny trembles to large quakes, which can cause destruction and even tsunamis. Hundreds of
|
||||
earthquakes happen every day—but most are too small to feel.
|
||||
</p>
|
||||
<p className="text-lg md:text-xl text-white w-4/6 mx-auto drop-shadow-md z-10">info</p>
|
||||
<p className="mt-20"></p>
|
||||
<p className="text-lg md:text-3xl font-bold text-white w-4/6 mx-auto drop-shadow-md z-10">
|
||||
How do we log earthquakes?
|
||||
@ -107,21 +107,30 @@ export default function Home() {
|
||||
</section>
|
||||
<p className="mt-2"></p>
|
||||
<div className="flex flex-col md:flex-row md:justify-evenly gap-6 mt-2">
|
||||
<Link href="/contact-us" className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300">
|
||||
<Link
|
||||
href="/contact-us"
|
||||
className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300"
|
||||
>
|
||||
<Image height={100} width={100} src="/contactUs.jpg" alt="Education Icon" className="h-20 w-20 mb-4" />
|
||||
<h3 className="text-xl font-bold text-black mb-4">Contact us directly</h3>
|
||||
<p className="text-md text-black text-center max-w-xs opacity-90">
|
||||
Visit our socials or leave us a message via phone or email.
|
||||
</p>
|
||||
</Link>
|
||||
<Link href="/our-mission" className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300">
|
||||
<Link
|
||||
href="/our-mission"
|
||||
className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300"
|
||||
>
|
||||
<Image height={100} width={100} src="/mission.jpg" alt="Research Icon" className="h-20 w-20 mb-4" />
|
||||
<h3 className="text-xl font-bold text-black mb-4">Our Mission</h3>
|
||||
<p className="text-md text-black text-center max-w-xs opacity-90">
|
||||
Find out more about our purpose and the features we offer.
|
||||
</p>
|
||||
</Link>
|
||||
<Link href="/the-team" className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300">
|
||||
<Link
|
||||
href="/the-team"
|
||||
className="icon-link flex flex-col items-center p-6 rounded-xl transition-colors duration-300"
|
||||
>
|
||||
<Image height={100} width={100} src="/team.jpg" alt="Technology Icon" className="h-20 w-20 mb-4" />
|
||||
<h3 className="text-xl font-bold text-black mb-4">Meet the Team</h3>
|
||||
<p className="text-md text-black text-center max-w-xs opacity-90">
|
||||
@ -130,12 +139,12 @@ export default function Home() {
|
||||
</Link>
|
||||
</div>
|
||||
<p className="mt-10"></p>
|
||||
<section style={{ height: 500 }} className="text-black">
|
||||
<section style={{ height: 500}} className="text-black">
|
||||
<div className="w-full relative overflow-hidden z=10">
|
||||
<div className="">
|
||||
<Image height={1000} width={2000} alt="Background Image" src="/scientists.png"></Image>
|
||||
</div>
|
||||
<BottomFooter />
|
||||
<BottomFooter />
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@ -1,46 +1,191 @@
|
||||
"use client";
|
||||
import Image from "next/image";
|
||||
import { Dispatch, SetStateAction, useCallback, useState, useEffect } from "react";
|
||||
import BottomFooter from "@components/BottomFooter";
|
||||
import { Dispatch, SetStateAction, useCallback, useState } from "react";
|
||||
|
||||
import { ExtendedArtefact } from "@appTypes/ApiTypes";
|
||||
import { Currency } from "@appTypes/StoreModel";
|
||||
import { useStoreState } from "@hooks/store";
|
||||
|
||||
const artefacts: ExtendedArtefact[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Golden Scarab",
|
||||
description: "An ancient Egyptian artefact symbolizing rebirth.",
|
||||
location: "Cairo, Egypt",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact1.jpg",
|
||||
price: 150,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Aztec Sunstone",
|
||||
description: "A replica of the Aztec calendar (inscriptions intact).",
|
||||
location: "Peru",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact2.jpg",
|
||||
price: 200,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Medieval Chalice",
|
||||
description: "Used by royalty in medieval ceremonies.",
|
||||
location: "Cambridge, England",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact3.jpg",
|
||||
price: 120,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Roman Coin",
|
||||
description: "An authentic Roman coin from the 2nd century CE.",
|
||||
location: "Rome, Italy",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact4.jpg",
|
||||
price: 80,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Samurai Mask",
|
||||
description: "Replica of Japanese Samurai battle masks.",
|
||||
location: "Tokyo, Japan",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact5.jpg",
|
||||
price: 300,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Ancient Greek Vase",
|
||||
description: "Depicts Greek mythology, found in the Acropolis.",
|
||||
location: "Athens, Greece",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact6.jpg",
|
||||
price: 250,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Incan Pendant",
|
||||
description: "Represents the Sun God Inti.",
|
||||
location: "India",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact7.jpg",
|
||||
price: 175,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Persian Carpet Fragment",
|
||||
description: "Ancient Persian artistry.",
|
||||
location: "Petra, Jordan",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact8.jpg",
|
||||
price: 400,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Stone Buddha",
|
||||
description: "Authentic stone Buddha carving.",
|
||||
location: "India",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact9.jpg",
|
||||
price: 220,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Victorian Brooch",
|
||||
description: "A beautiful Victorian-era brooch with a ruby centre.",
|
||||
location: "Oxford, England",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact10.jpg",
|
||||
price: 150,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Ancient Scroll",
|
||||
description: "A mysterious scroll from ancient times.",
|
||||
location: "Madrid, Spain",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact11.jpg",
|
||||
price: 500,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Ming Dynasty Porcelain",
|
||||
description: "Porcelain from China's Ming Dynasty.",
|
||||
location: "Beijing, China",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact12.jpg",
|
||||
price: 300,
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: "African Tribal Mask",
|
||||
description: "A unique tribal mask from Africa.",
|
||||
location: "Nigeria",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact13.jpg",
|
||||
price: 250,
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
name: "Crystal Skull",
|
||||
description: "A mystical pre-Columbian artefact.",
|
||||
location: "Colombia",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact14.jpg",
|
||||
price: 1000,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
name: "Medieval Armor Fragment",
|
||||
description: "A fragment of medieval armor.",
|
||||
location: "Normandy, France",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact15.jpg",
|
||||
price: 400,
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
name: "Medieval Helmet Fragment",
|
||||
description: "A fragment of a medieval helmet.",
|
||||
location: "Normandy, France",
|
||||
earthquakeID: "h",
|
||||
observatory: "jhd",
|
||||
dateReleased: "12/02/2025",
|
||||
image: "/artefact16.jpg",
|
||||
price: 500,
|
||||
},
|
||||
];
|
||||
|
||||
export default function Shop() {
|
||||
const [artefacts, setArtefacts] = useState<ExtendedArtefact[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
// 3. Fetch from your API route and map data to fit your existing fields
|
||||
useEffect(() => {
|
||||
async function fetchArtefacts() {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await fetch("/api/artefacts");
|
||||
const data = await res.json();
|
||||
|
||||
const transformed = data.artefact.map((a: any) => ({
|
||||
id: a.id,
|
||||
name: a.name,
|
||||
description: a.description,
|
||||
location: a.warehouseArea, // your database
|
||||
earthquakeID: a.earthquakeId?.toString() ?? "",
|
||||
observatory: a.type ?? "", // if you want to display type
|
||||
dateReleased: a.createdAt ? new Date(a.createdAt).toLocaleDateString() : "",
|
||||
image: "/artefactImages/" + (a.imageName || "NoImageFound.PNG"),
|
||||
price: a.shopPrice ?? 100, // fallback price if not in DB
|
||||
}));
|
||||
setArtefacts(transformed);
|
||||
} catch (e) {
|
||||
// Optionally handle error
|
||||
console.error("Failed to fetch artefacts", e);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
fetchArtefacts();
|
||||
}, []);
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [selectedArtefact, setSelectedArtefact] = useState<Artefact | null>(null);
|
||||
const [showPaymentModal, setShowPaymentModal] = useState(false);
|
||||
@ -288,20 +433,20 @@ export default function Shop() {
|
||||
}
|
||||
return (
|
||||
<div
|
||||
className="min-h-screen bg-blue-50 relative flex flex-col"
|
||||
className="min-h-screen relative flex flex-col"
|
||||
style={{
|
||||
backgroundImage: "url('/EarthHighRes.jpg')",
|
||||
backgroundImage: "url('/artefacts.jpg')",
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
}}
|
||||
>
|
||||
<div className="absolute inset-0 bg-black bg-opacity-0 z-0"></div>
|
||||
<div className="absolute inset-0 bg-black bg-opacity-50 z-0"></div>
|
||||
<div className="relative z-10 flex flex-col items-center w-full px-2 py-12">
|
||||
<h1 className="text-4xl md:text-4xl font-bold text-center text-blue-300 mb-2 tracking-tight drop-shadow-lg">
|
||||
<h1 className="text-4xl md:text-4xl font-bold text-center text-white mb-2 tracking-tight drop-shadow-lg">
|
||||
Artefact Shop
|
||||
</h1>
|
||||
<p className="text-lg md:text-xl text-center text-white mb-10 drop-shadow-md max-w-2xl">
|
||||
Discover extraordinary artefacts and collectibles from major seismic events from around the world - Previously studied by our scientists, now
|
||||
Discover extraordinary historical artefacts and collectibles from major seismic events from around the world - now
|
||||
available for purchase.
|
||||
</p>
|
||||
<div className="w-full max-w-7xl grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-10 p-2">
|
||||
@ -344,10 +489,6 @@ export default function Shop() {
|
||||
{showThankYouModal && orderNumber && (
|
||||
<ThankYouModal orderNumber={orderNumber} onClose={() => setShowThankYouModal(false)} />
|
||||
)}
|
||||
{!selectedArtefact && !showPaymentModal && !showThankYouModal && (
|
||||
<div className="relative z-50">
|
||||
<BottomFooter />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ export default function Page() {
|
||||
return (
|
||||
<div
|
||||
className="min-h-screen relative flex flex-col items-center justify-center px-4 py-30"
|
||||
style={{ backgroundImage: "url('tectonicPlates.png')", backgroundSize: "cover", backgroundPosition: "center" }}
|
||||
style={{ backgroundImage: "url('tectonicPlate.jpg')", backgroundSize: "cover", backgroundPosition: "center" }}
|
||||
>
|
||||
{/* Overlay */}
|
||||
<div className="absolute inset-0 bg-black bg-opacity-50 pointer-events-none"></div>
|
||||
|
||||
@ -1,74 +1,88 @@
|
||||
// components/Footer.tsx
|
||||
import Link from "next/link";
|
||||
import { FaFacebook, FaLinkedin, FaTwitter, FaYoutube } from "react-icons/fa";
|
||||
import { FaTwitter, FaFacebook, FaYoutube, FaLinkedin } from "react-icons/fa";
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="bg-[#16424b] text-white pt-12 pb-4 px-6 mt-12 z-0">
|
||||
<div className="max-w-6xl mx-auto flex flex-col md:flex-row justify-between gap-8">
|
||||
{/* Useful Links */}
|
||||
<div className="min-w-[200px] mb-8 md:mb-0 flex-1">
|
||||
<h3 className="font-bold underline text-lg mb-3">Useful links</h3>
|
||||
<ul className="space-y-2">
|
||||
<li>
|
||||
<Link
|
||||
href="https://www.gov.uk/guidance/extreme-weather-and-natural-hazards"
|
||||
className="hover:underline"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Gov.UK guidance
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="https://www.dysoninstitute.ac.uk/about-us/governance/privacy-notices/" className="hover:underline">
|
||||
Privacy policy
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="https://privacy.dyson.com/en/globalcookiepolicy.aspx" className="hover:underline">
|
||||
Cookies policy
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{/* Donate Section */}
|
||||
<div className="min-w-[220px] mb-8 md:mb-0 flex-1">
|
||||
<h3 className="font-bold underline text-lg mb-3">Donate</h3>
|
||||
<p className="mb-4">
|
||||
We are a nonprofit entirely funded by your donations, every penny helps provide life saving information.
|
||||
</p>
|
||||
<Link
|
||||
href="#"
|
||||
className="bg-gray-200 hover:bg-blue-600 hover:text-white text-black font-bold rounded-full px-8 py-2 shadow transition-colors duration-200 inline-block text-center"
|
||||
>
|
||||
Donate Now
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
{/* Bottom bar */}
|
||||
<div className="max-w-6xl mx-auto mt-8 pt-6 flex flex-col md:flex-row items-center justify-between border-t border-gray-200/30">
|
||||
{/* Bottom left: Copyright */}
|
||||
<span className="text-sm flex items-center">
|
||||
<span className="mr-2">©</span> TremorTracker 2025
|
||||
</span>
|
||||
{/* Bottom right: Social icons */}
|
||||
<div className="flex flex-col items-end">
|
||||
<span className="text-sm mb-2">Follow us on</span>
|
||||
<div className="flex space-x-3">
|
||||
{/* Replace src with your icon URLs, or use next/image if preferred */}
|
||||
<a href="#" target="_blank" rel="noopener noreferrer">
|
||||
<img src="instagram.png" alt="instagram" className="h-7 w-7 rounded-full shadow" />
|
||||
</a>
|
||||
<a href="#" target="_blank" rel="noopener noreferrer">
|
||||
<img src="linkedin.png" alt="linkedin" className="h-7 w-7 rounded-full shadow" />
|
||||
</a>
|
||||
<a href="#" target="_blank" rel="noopener noreferrer">
|
||||
<img src="x_logo.jpg" alt="X" className="h-7 w-7 rounded-full shadow" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
return (
|
||||
<footer className="bg-[#16424b] text-white pt-12 pb-4 px-6 mt-12">
|
||||
<div className="max-w-6xl mx-auto flex flex-col md:flex-row justify-between gap-8">
|
||||
{/* Useful Links */}
|
||||
<div className="min-w-[200px] mb-8 md:mb-0 flex-1">
|
||||
<h3 className="font-bold underline text-lg mb-3">Useful links</h3>
|
||||
<ul className="space-y-2">
|
||||
<li>
|
||||
<Link
|
||||
href="https://www.gov.uk/guidance/extreme-weather-and-natural-hazards"
|
||||
className="hover:underline"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Gov.UK guidance
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="https://www.dysoninstitute.ac.uk/about-us/governance/privacy-notices/"
|
||||
className="hover:underline">
|
||||
Privacy policy
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="https://privacy.dyson.com/en/globalcookiepolicy.aspx"
|
||||
className="hover:underline">
|
||||
Cookies policy
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{/* Donate Section */}
|
||||
<div className="min-w-[220px] mb-8 md:mb-0 flex-1">
|
||||
<h3 className="font-bold underline text-lg mb-3">Donate</h3>
|
||||
<p className="mb-4">
|
||||
We are a nonprofit entirely funded by your donations, every penny helps provide life saving information.
|
||||
</p>
|
||||
<Link
|
||||
href="#"
|
||||
className="bg-gray-200 hover:bg-blue-600 hover:text-white text-black font-bold rounded-full px-8 py-2 shadow transition-colors duration-200 inline-block text-center"
|
||||
>
|
||||
Donate Now
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
{/* Bottom bar */}
|
||||
<div className="max-w-6xl mx-auto mt-8 pt-6 flex flex-col md:flex-row items-center justify-between border-t border-gray-200/30">
|
||||
{/* Bottom left: Copyright */}
|
||||
<span className="text-sm flex items-center">
|
||||
<span className="mr-2">©</span> TremorTracker 2025
|
||||
</span>
|
||||
{/* Bottom right: Social icons */}
|
||||
<div className="flex flex-col items-end">
|
||||
<span className="text-sm mb-2">Follow us on</span>
|
||||
<div className="flex space-x-3">
|
||||
{/* Replace src with your icon URLs, or use next/image if preferred */}
|
||||
<a href="#" target="_blank" rel="noopener noreferrer">
|
||||
<img
|
||||
src="instagram.png"
|
||||
alt="instagram"
|
||||
className="h-7 w-7 rounded-full shadow"
|
||||
/>
|
||||
</a>
|
||||
<a href="#" target="_blank" rel="noopener noreferrer">
|
||||
<img
|
||||
src="linkedin.png"
|
||||
alt="linkedin"
|
||||
className="h-7 w-7 rounded-full shadow"
|
||||
/>
|
||||
</a>
|
||||
<a href="#" target="_blank" rel="noopener noreferrer">
|
||||
<img
|
||||
src="x_logo.jpg"
|
||||
alt="X"
|
||||
className="h-7 w-7 rounded-full shadow"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
@ -1,87 +0,0 @@
|
||||
import Link from "next/link";
|
||||
import React, { Dispatch, SetStateAction, useState } from "react";
|
||||
import { TbHexagon } from "react-icons/tb";
|
||||
|
||||
import Event from "@appTypes/Event";
|
||||
import getMagnitudeColor from "@utils/getMagnitudeColour";
|
||||
|
||||
function setButton1(button1Name) {
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
return (
|
||||
modalOpen && (
|
||||
<div className="fixed z-50 inset-0 bg-black bg-opacity-50 flex items-center justify-center">
|
||||
<div className="bg-white rounded-lg shadow-lg max-w-6xl w-full p-10">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h2 className="text-2xl font-extrabold">Log New Earthquake</h2>
|
||||
<button
|
||||
onClick={() => setModalOpen(false)}
|
||||
className="text-2xl font-bold text-gray-500 hover:text-gray-900"
|
||||
aria-label="Close modal"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
{/* Blank Table */}
|
||||
<table className="w-full border mb-4">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="border px-2 py-1">Date</th>
|
||||
<th className="border px-2 py-1">Code</th>
|
||||
<th className="border px-2 py-1">Magnitude</th>
|
||||
<th className="border px-2 py-1">Observatory</th>
|
||||
<th className="border px-2 py-1">Type</th>
|
||||
<th className="border px-2 py-1">Latitude</th>
|
||||
<th className="border px-2 py-1">Longitude</th>
|
||||
<th className="border px-2 py-1">Location</th>
|
||||
<th className="border px-2 py-1">Observatory</th>
|
||||
<th className="border px-2 py-1">Depth</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="border px-2 py-1">
|
||||
<input type="date" className="border p-1 w-full" disabled />
|
||||
</td>
|
||||
<td className="border px-2 py-1">
|
||||
<input type="number" className="border p-1 w-full" disabled />
|
||||
</td>
|
||||
<td className="border px-2 py-1">
|
||||
<input type="text" className="border p-1 w-full" disabled />
|
||||
</td>
|
||||
<td className="border px-2 py-1">
|
||||
<input type="text" className="border p-1 w-full" disabled />
|
||||
</td>
|
||||
<td className="border px-2 py-1">
|
||||
<input type="text" className="border p-1 w-full" disabled />
|
||||
</td>
|
||||
<td className="border px-2 py-1">
|
||||
<input type="date" className="border p-1 w-full" disabled />
|
||||
</td>
|
||||
<td className="border px-2 py-1">
|
||||
<input type="number" className="border p-1 w-full" disabled />
|
||||
</td>
|
||||
<td className="border px-2 py-1">
|
||||
<input type="text" className="border p-1 w-full" disabled />
|
||||
</td>
|
||||
<td className="border px-2 py-1">
|
||||
<input type="text" className="border p-1 w-full" disabled />
|
||||
</td>
|
||||
<td className="border px-2 py-1">
|
||||
<input type="text" className="border p-1 w-full" disabled />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="flex justify-end gap-4">
|
||||
<button onClick={() => setModalOpen(true)} className="bg-blue-600 text-white px-10 py-2 rounded">
|
||||
Add
|
||||
</button>
|
||||
<button onClick={() => setModalOpen(false)} className="bg-blue-600 text-white px-4 py-2 rounded">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -16,7 +16,6 @@ interface SidebarProps {
|
||||
setHoveredEventId: Dispatch<SetStateAction<string>>;
|
||||
button1Name: string;
|
||||
button2Name: string;
|
||||
onButton2Click?: () => void;
|
||||
}
|
||||
|
||||
function MagnitudeNumber({ magnitude }: { magnitude: number }) {
|
||||
@ -48,7 +47,6 @@ export default function Sidebar({
|
||||
setHoveredEventId,
|
||||
button1Name,
|
||||
button2Name,
|
||||
onButton2Click,
|
||||
}: SidebarProps) {
|
||||
const eventsContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@ -70,21 +68,17 @@ export default function Sidebar({
|
||||
<div className="px-6 pb-8 border-b border-neutral-200">
|
||||
<h2 className="text-2xl font-bold text-neutral-800 mb-2">{logTitle}</h2>
|
||||
<p className="text-sm text-neutral-600 leading-relaxed">{logSubtitle}</p>
|
||||
|
||||
<Link href="/">
|
||||
<button className="mt-4 w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg transition-colors duration-200 font-medium">
|
||||
{button1Name}
|
||||
</button>
|
||||
</Link>
|
||||
{/* "Search Earthquakes" should NOT be wrapped in a Link! */}
|
||||
<button
|
||||
className="mt-4 w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg transition-colors duration-200 font-medium"
|
||||
onClick={onButton2Click}
|
||||
type="button"
|
||||
>
|
||||
{button2Name}
|
||||
</button>
|
||||
</div>
|
||||
<Link href="/">
|
||||
<button className="mt-4 w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg transition-colors duration-200 font-medium">
|
||||
{button1Name}
|
||||
</button>
|
||||
</Link>
|
||||
<Link href="/">
|
||||
<button className="mt-4 w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg transition-colors duration-200 font-medium">
|
||||
{button2Name}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="px-6 pt-6">
|
||||
<h2 className="text-xl font-bold text-neutral-800 mb-4">{recentsTitle}</h2>
|
||||
</div>
|
||||
|
||||
42
src/components/sidebar_e.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import Link from "next/link";
|
||||
import React from "react";
|
||||
|
||||
const Sidebar = () => {
|
||||
return (
|
||||
<div className="flex flex-col h-screen w-64 bg-neutral-400 text-white border-l border-neutral-700">
|
||||
<div className="flex flex-col p-4 border-b border-neutral-700">
|
||||
<h2 className="text-xl font-semibold mb-2">Log an Earthquake</h2>
|
||||
<p className="text-sm text-neutral-700">
|
||||
Record new earthquakes - time/date, location, magnitude, observatory and scientists
|
||||
</p>
|
||||
<button className="mt-4 bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded">
|
||||
<Link href="/">Log Event</Link>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Section: Recent Events - Will need to be replaced with a link to the database*/}
|
||||
<div className="flex-1 p-4">
|
||||
<h2 className="text-xl font-semibold mb-2">Recent Events</h2>
|
||||
<ul className="space-y-2">
|
||||
<li className="bg-neutral-700 p-3 rounded hover:bg-neutral-600">
|
||||
<p className="text-sm">Earthquake in California</p>
|
||||
<p className="text-xs text-neutral-300">Magnitude 5.3</p>
|
||||
<p className="text-xs text-neutral-400">2 hours ago</p>
|
||||
</li>
|
||||
<li className="bg-neutral-700 p-3 rounded hover:bg-neutral-600">
|
||||
<p className="text-sm">Tremor in Japan</p>
|
||||
<p className="text-xs text-neutral-300">Magnitude 4.7</p>
|
||||
<p className="text-xs text-neutral-400">5 hours ago</p>
|
||||
</li>
|
||||
<li className="bg-neutral-700 p-3 rounded hover:bg-neutral-600">
|
||||
<p className="text-sm">Tremor in Spain</p>
|
||||
<p className="text-xs text-neutral-300">Magnitude 2.1</p>
|
||||
<p className="text-xs text-neutral-400">10 hours ago</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
40
src/components/sidebar_o.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import Link from "next/link";
|
||||
import React from "react";
|
||||
|
||||
const Sidebar = () => {
|
||||
return (
|
||||
<div className="flex flex-col h-screen w-64 bg-neutral-400 text-white border-l border-neutral-700">
|
||||
<div className="flex flex-col p-4 border-b border-neutral-700">
|
||||
<h2 className="text-xl font-semibold mb-2">Observatories</h2>
|
||||
<p className="text-sm text-neutral-700">Observatory events - location, scientists, recent earthquakes</p>
|
||||
<button className="mt-4 bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded">
|
||||
<Link href="/">Observatory News</Link>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Section: Recent Events - Will need to be replaced with a link to the database*/}
|
||||
<div className="flex-1 p-4">
|
||||
<h2 className="text-xl font-semibold mb-2">Recent Observatory Events</h2>
|
||||
<ul className="space-y-2">
|
||||
<li className="bg-neutral-700 p-3 rounded hover:bg-neutral-600">
|
||||
<p className="text-sm">Earthquake in California</p>
|
||||
<p className="text-xs text-neutral-300">Magnitude 5.3</p>
|
||||
<p className="text-xs text-neutral-400">Cali Observatory</p>
|
||||
</li>
|
||||
<li className="bg-neutral-700 p-3 rounded hover:bg-neutral-600">
|
||||
<p className="text-sm">Tremor in Japan</p>
|
||||
<p className="text-xs text-neutral-300">Magnitude 4.7</p>
|
||||
<p className="text-xs text-neutral-400">Kyoto Observatory</p>
|
||||
</li>
|
||||
<li className="bg-neutral-700 p-3 rounded hover:bg-neutral-600">
|
||||
<p className="text-sm">Tremor in Spain</p>
|
||||
<p className="text-xs text-neutral-300">Magnitude 2.1</p>
|
||||
<p className="text-xs text-neutral-400">Madrid Observatory</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||