Skip to content

Commit

Permalink
️🦋🏛️️ ↝ [SSG-111 SSG-112 SSG-109 SSG-107]: New modal flow for greenho…
Browse files Browse the repository at this point in the history
…use/biodome 3104, and exporting of post cards now works
  • Loading branch information
Gizmotronn committed Jan 28, 2025
1 parent 870e0b8 commit b3dc425
Show file tree
Hide file tree
Showing 13 changed files with 764 additions and 115 deletions.
31 changes: 25 additions & 6 deletions components/Account/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,34 @@ interface Props {
};

export const AvatarGenerator: React.FC<Props> = ({ author }) => {
const supabase = useSupabaseClient();
const session = useSession();

const [avatarUrl, setAvatarUrl] = useState("");

useEffect(() => {
const generateAvatar = () => {
const apiUrl = `https://api.dicebear.com/6.x/bottts/svg?seed=${encodeURIComponent(author)}`;
setAvatarUrl(apiUrl);
};

generateAvatar();
let ignore = false;

async function fetchAvatar () {
const { data, error } = await supabase
.from("profiles")
.select("avatar_url")
.eq("id", session?.user.id)
.single();

if (!data?.avatar_url) {
const generateAvatar = () => {
const apiUrl = `https://api.dicebear.com/6.x/bottts/svg?seed=${encodeURIComponent(author)}`;
setAvatarUrl(apiUrl);
};

generateAvatar();
} else {
setAvatarUrl(`${process.env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/avatars/${data.avatar_url}`)
};
}

fetchAvatar();
}, [author]);

return (
Expand Down
83 changes: 83 additions & 0 deletions components/Structures/Missions/Biologists/BiomePattern.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Biome } from "@/types/station"

interface BiomePatternProps {
biome: Biome
className?: string
}

export function BiomePattern({ biome, className = "" }: BiomePatternProps) {
// Generate a hex-like pattern
const generateHexPattern = () => {
const pattern = []
const rows = 3
const cols = 6

for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
const isOffset = i % 2 === 0
const colorIndex = (i * j + j) % 3
const color = colorIndex === 0 ? biome.accentColor : colorIndex === 1 ? biome.color : biome.darkColor

pattern.push(
<div
key={`${i}-${j}`}
className={`relative h-8 w-8 ${isOffset ? "translate-x-4" : ""}`}
style={{
clipPath: "polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%)",
backgroundColor: color,
opacity: Math.random() * 0.5 + 0.5, // Random opacity for more variety
transform: `rotate(${Math.random() * 30}deg)`, // Slight random rotation
}}
>
{/* Add subtle inner glow */}
<div
className="absolute inset-0 opacity-50"
style={{
background: `radial-gradient(circle at center, ${biome.accentColor}22 0%, transparent 70%)`,
}}
/>
</div>,
)
}
}
return pattern
}

return (
<div className={`relative overflow-hidden rounded-lg ${className}`}>
{/* Background gradient */}
<div
className="absolute inset-0 opacity-30"
style={{
background: `linear-gradient(45deg, ${biome.darkColor}, ${biome.color})`,
}}
/>

{/* Animated scan line */}
<div
className="absolute inset-0 animate-scan"
style={{
background: "linear-gradient(transparent 0%, rgba(255,255,255,0.1) 50%, transparent 100%)",
backgroundSize: "100% 200%",
animation: "scan 4s linear infinite",
}}
/>

{/* Hex pattern container */}
<div className="relative flex flex-wrap justify-center gap-0 py-2">{generateHexPattern()}</div>

{/* Grid overlay */}
<div
className="absolute inset-0"
style={{
backgroundImage: `
linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px)
`,
backgroundSize: "20px 20px",
}}
/>
</div>
)
}

48 changes: 48 additions & 0 deletions components/Structures/Missions/Biologists/Milestones.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Progress } from "./Progress"
import type { Milestone } from "@/types/milestone"
import { Trophy, Target, Globe } from "lucide-react"

const iconMap = {
animals: Trophy,
stations: Target,
biomes: Globe,
}

interface MilestonesProps {
milestones: Milestone[]
}

export function Milestones({ milestones }: MilestonesProps) {
return (
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-blue-400">Research Milestones</h2>
<div className="grid gap-4">
{milestones.map((milestone) => {
const Icon = iconMap[milestone.type]

return (
<Card key={milestone.id} className="bg-black/40 border-gray-800">
<CardHeader className="pb-2">
<CardTitle className="flex items-center gap-2 text-lg text-white">
<Icon className="w-5 h-5 text-blue-400" />
{milestone.title}
</CardTitle>
</CardHeader>
<CardContent>
<p className="text-sm text-gray-400 mb-2">{milestone.description}</p>
<div className="space-y-1">
<Progress value={milestone.current} max={milestone.target} />
<p className="text-sm text-blue-400">
Progress: {milestone.current} / {milestone.target}
</p>
</div>
</CardContent>
</Card>
)
})}
</div>
</div>
)
}

20 changes: 20 additions & 0 deletions components/Structures/Missions/Biologists/Progress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
interface ProgressProps {
value: number
max: number
}

export function Progress({ value, max }: ProgressProps) {
const percentage = (value / max) * 100

return (
<div className="relative w-full h-2 bg-gray-800 rounded-full overflow-hidden">
<div
className="absolute left-0 top-0 h-full bg-gradient-to-r from-blue-500 to-blue-400"
style={{ width: `${percentage}%` }}
>
<div className="absolute inset-0 bg-[linear-gradient(90deg,transparent_0%,rgba(255,255,255,0.2)_50%,transparent_100%)] animate-shimmer" />
</div>
</div>
)
}

172 changes: 172 additions & 0 deletions components/Structures/Missions/Biologists/ResearchStations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import { useState } from "react";
import { StationCard } from "./StationCard";
import { Milestones } from "./Milestones";
import type { Station } from "@/types/station";
import type { Milestone } from "@/types/milestone";

const initialStations: Station[] = [
{
id: "1",
name: "Coral Reef Observatory",
icon: "Anchor",
biome: {
name: "Marine",
color: "rgb(37, 99, 235)",
accentColor: "rgb(59, 130, 246)",
darkColor: "rgb(30, 58, 138)",
},
animals: [
{ name: "Clownfish", icon: "Fish" },
{ name: "Sea Turtle", icon: "Turtle" },
{ name: "Coral", icon: "Flower2" },
],
location: {
coordinates: "23.4162° N, 75.2397° W",
depth: "-45m",
},
built: false,
},
{
id: "2",
name: "Rainforest Canopy Station",
icon: "Trees",
biome: {
name: "Tropical",
color: "rgb(22, 163, 74)",
accentColor: "rgb(34, 197, 94)",
darkColor: "rgb(20, 83, 45)",
},
animals: [
{ name: "Toucan", icon: "Bird" },
{ name: "Monkey", icon: "Monkey" },
{ name: "Butterfly", icon: "Bug" },
],
location: {
coordinates: "2.4162° S, 54.2397° W",
altitude: "40m",
},
built: false,
},
{
id: "3",
name: "Arctic Research Base",
icon: "Snowflake",
biome: {
name: "Polar",
color: "rgb(148, 163, 184)",
accentColor: "rgb(226, 232, 240)",
darkColor: "rgb(51, 65, 85)",
},
animals: [
{ name: "Polar Bear", icon: "Bear" },
{ name: "Penguin", icon: "Bird" },
{ name: "Seal", icon: "Fish" },
],
location: {
coordinates: "78.4162° N, 15.2397° E",
},
built: false,
},
{
id: "4",
name: "Deep Sea Laboratory",
icon: "Waves",
biome: {
name: "Abyssal",
color: "rgb(30, 58, 138)",
accentColor: "rgb(37, 99, 235)",
darkColor: "rgb(30, 27, 75)",
},
animals: [
{ name: "Anglerfish", icon: "Fish" },
{ name: "Giant Squid", icon: "Bug" },
{ name: "Tube Worm", icon: "Wand2" },
],
location: {
coordinates: "31.4162° N, 159.2397° W",
depth: "-2500m",
},
built: false,
},
];

const initialMilestones: Milestone[] = [
{
id: "1",
title: "Wildlife Observer",
description: "Discover and document different animal species",
current: 3,
target: 10,
type: "animals",
},
{
id: "2",
title: "Global Network",
description: "Establish research stations worldwide",
current: 1,
target: 5,
type: "stations",
},
{
id: "3",
title: "Biome Explorer",
description: "Research different environmental biomes",
current: 1,
target: 4,
type: "biomes",
},
];

export function GreenhouseResearchStations() {
const [stations, setStations] = useState<Station[]>(initialStations)
const [milestones, setMilestones] = useState<Milestone[]>(initialMilestones)

const handleBuild = (id: string) => {
setStations(stations.map((station) => (station.id === id ? { ...station, built: true } : station)))
// Update station milestone
setMilestones(
milestones.map((milestone) =>
milestone.type === "stations" ? { ...milestone, current: milestone.current + 1 } : milestone,
),
);
};

const buildableStations = stations.filter((station) => !station.built)
const builtStations = stations.filter((station) => station.built)

return (
<div className="min-h-screen bg-gray-900 bg-[linear-gradient(rgba(0,0,0,0.7),rgba(0,0,0,0.7)),repeating-linear-gradient(0deg,transparent,transparent_40px,rgba(71,85,105,0.1)_40px,rgba(71,85,105,0.1)_80px)]">
<div className="container mx-auto px-4 py-8">
<h1 className="text-4xl font-bold mb-8 text-white tracking-tight">Research Stations</h1>

<div className="grid lg:grid-cols-[2fr,1fr] gap-8">
<div className="space-y-8">
<section>
<h2 className="text-2xl font-semibold mb-4 text-blue-400">Available Stations</h2>
<div className="grid gap-6">
{buildableStations.map((station) => (
<StationCard key={station.id} station={station} onBuild={handleBuild} />
))}
</div>
</section>

{builtStations.length > 0 && (
<section>
<h2 className="text-2xl font-semibold mb-4 text-blue-400">Built Stations</h2>
<div className="grid gap-6">
{builtStations.map((station) => (
<StationCard key={station.id} station={station} onBuild={handleBuild} />
))}
</div>
</section>
)}
</div>

<div className="lg:border-l lg:border-gray-800 lg:pl-8">
<Milestones milestones={milestones} />
</div>
</div>
</div>
</div>
);
};
Loading

0 comments on commit b3dc425

Please sign in to comment.