Skip to content

Commit

Permalink
💍🥑 ↝ [SSG-96]: Structures can now be shown in 3d and are modular (jus…
Browse files Browse the repository at this point in the history
…t no b/e integration)
  • Loading branch information
Gizmotronn committed Jan 6, 2025
1 parent 9de163f commit c1b1e39
Show file tree
Hide file tree
Showing 12 changed files with 648 additions and 21 deletions.
Binary file modified .DS_Store
Binary file not shown.
13 changes: 13 additions & 0 deletions components/Inventory/Grid/Items/Biodome.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export function Biodome({ level }: { level: number }) {
return (
<div className="flex flex-col items-center">
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 70 Q50 10 90 70" stroke="#00FF00" strokeWidth="2" fill="none" />
<line x1="10" y1="70" x2="90" y2="70" stroke="#00FF00" strokeWidth="2" />
<path d="M40 70 Q50 40 60 70" stroke="#00FF00" strokeWidth="2" fill="none" />
</svg>
<p className="text-white mt-2">Biodome</p>
</div>
)
}

199 changes: 199 additions & 0 deletions components/Inventory/Grid/Items/Colony3D.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import { Canvas } from '@react-three/fiber'
import { Environment } from '@react-three/drei'
import { Structures } from './Structures'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import { useState } from 'react'
import Image from 'next/image'
// import { HexColorPicker } from "react-colorful";

export type StructureInfo = {
id: string
name: string
description: string
level: number
maxLevel: number
status: 'operational' | 'upgrading' | 'maintenance'
color: string
};

export function Colony3D() {
const [structures, setStructures] = useState<Record<string, StructureInfo>>({
habitat: {
id: 'habitat',
name: "Habitat Dome",
description: "Primary living quarters for colony inhabitants. Features advanced life support systems and radiation shielding.",
level: 3,
maxLevel: 5,
status: "operational",
color: "#e0e0e0"
},
research: {
id: 'research',
name: "Research Station",
description: "Advanced facility for conducting scientific experiments and analyzing Martian samples.",
level: 2,
maxLevel: 5,
status: "operational",
color: "#c0c0c0"
},
solar: {
id: 'solar',
name: "Solar Array",
description: "High-efficiency solar panels providing primary power generation for the colony.",
level: 2,
maxLevel: 5,
status: "maintenance",
color: "#4169E1"
},
observatory: {
id: 'observatory',
name: "Observatory",
description: "Deep space observation facility with advanced tracking and communication capabilities.",
level: 2,
maxLevel: 5,
status: "operational",
color: "#d0d0d0"
},
launch: {
id: 'launch',
name: "Launch Pad",
description: "Vertical launch and landing facility for interplanetary vessels and supply missions.",
level: 1,
maxLevel: 5,
status: "upgrading",
color: "#808080"
}
})
const [selectedStructure, setSelectedStructure] = useState<string | null>(null)
const [showColorPicker, setShowColorPicker] = useState(false)

const handleLevelChange = (id: string, change: number) => {
setStructures(prev => ({
...prev,
[id]: {
...prev[id],
level: Math.max(1, Math.min(prev[id].maxLevel, prev[id].level + change))
}
}))
}

const handleColorChange = (id: string, color: string) => {
setStructures(prev => ({
...prev,
[id]: {
...prev[id],
color
}
}))
}

return (
<div className="w-full h-screen relative">

{/* 3D Scene */}
<div className="absolute inset-0">
<Canvas
shadows
camera={{
position: [0, 10, 25],
fov: 35,
rotation: [0, 0, 0],
}}
>
<Environment preset="sunset" />

{/* Structures */}
<Structures
structures={structures}
onSelectStructure={setSelectedStructure}
/>

{/* Lighting */}
<directionalLight
position={[10, 10, 10]}
castShadow
shadow-mapSize={[2048, 2048]}
shadow-camera-far={50}
shadow-camera-left={-20}
shadow-camera-right={20}
shadow-camera-top={20}
shadow-camera-bottom={-20}
intensity={1.5}
/>
<ambientLight intensity={0.4} />
</Canvas>
</div>

<Dialog open={!!selectedStructure} onOpenChange={() => setSelectedStructure(null)}>
<DialogContent className="bg-gray-900/95 text-white border-gray-800">
<DialogHeader>
<DialogTitle className="text-xl font-bold text-cyan-400">
{selectedStructure ? structures[selectedStructure].name : ''}
</DialogTitle>
</DialogHeader>
{selectedStructure && (
<div className="space-y-6">
<p className="text-gray-300">{structures[selectedStructure].description}</p>

<div className="space-y-4">
<div className="space-y-2">
<p className="text-sm text-gray-400">Level</p>
<div className="flex items-center gap-4">
<Button
variant="outline"
size="sm"
onClick={() => handleLevelChange(selectedStructure, -1)}
disabled={structures[selectedStructure].level <= 1}
>
-
</Button>
<span className="text-lg font-semibold text-cyan-400">
{structures[selectedStructure].level} / {structures[selectedStructure].maxLevel}
</span>
<Button
variant="outline"
size="sm"
onClick={() => handleLevelChange(selectedStructure, 1)}
disabled={structures[selectedStructure].level >= structures[selectedStructure].maxLevel}
>
+
</Button>
</div>
</div>

<div className="space-y-2">
<p className="text-sm text-gray-400">Status</p>
<p className="text-lg font-semibold text-cyan-400">
{structures[selectedStructure].status}
</p>
</div>

<div className="space-y-2">
<p className="text-sm text-gray-400">Accent Color</p>
<div className="relative">
<Button
variant="outline"
className="w-full h-10"
onClick={() => setShowColorPicker(!showColorPicker)}
style={{ backgroundColor: structures[selectedStructure].color }}
/>
{/* {showColorPicker && (
<div className="absolute top-full mt-2 z-50">
<HexColorPicker
color={structures[selectedStructure].color}
onChange={(color) => handleColorChange(selectedStructure, color)}
/>
</div>
)} */}
</div>
</div>
</div>
</div>
)}
</DialogContent>
</Dialog>
</div>
)
}

146 changes: 146 additions & 0 deletions components/Inventory/Grid/Items/ColonyStructures.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import { useState } from 'react'
import { Card } from '@/components/ui/card'

interface Structure {
id: string
name: string
maxLevel: number
type: 'dome' | 'telescope' | 'launcher' | 'solar' | 'hab'
}

const structures: Structure[] = [
{ id: '1', name: 'Habitat Dome', maxLevel: 3, type: 'dome' },
{ id: '2', name: 'Research Station', maxLevel: 3, type: 'hab' },
{ id: '3', name: 'Launch Pad', maxLevel: 3, type: 'launcher' },
{ id: '4', name: 'Solar Array', maxLevel: 3, type: 'solar' },
{ id: '5', name: 'Observatory', maxLevel: 3, type: 'telescope' },
]

export function ColonyStructures() {
return (
<div className="min-h-screen bg-gradient-to-b from-orange-900/90 to-orange-950/90 p-6">
<div className="max-w-7xl mx-auto">
<h1 className="text-2xl font-bold text-orange-100 mb-6">Mars Colony Structures</h1>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6">
{structures.map((structure) => (
<div key={structure.id} className="space-y-4">
<h2 className="text-xl font-semibold text-orange-100 text-center">{structure.name}</h2>
<div className="space-y-4">
{Array.from({ length: structure.maxLevel }, (_, i) => i + 1).map((level) => (
<Card
key={`${structure.id}-${level}`}
className="bg-orange-950/50 border-orange-900/50 backdrop-blur-sm hover:bg-orange-950/70 transition-colors"
>
<div className="p-4">
<div className="aspect-square w-full relative mb-4">
<StructureIcon type={structure.type} level={level} />
</div>
<div className="space-y-1">
<h3 className="text-orange-100 font-medium text-center">Level {level}</h3>
<div className="flex items-center gap-2">
<div className="h-2 flex-1 bg-orange-900/50 rounded-full overflow-hidden">
<div
className="h-full bg-cyan-400 rounded-full"
style={{ width: `${(level / structure.maxLevel) * 100}%` }}
/>
</div>
</div>
</div>
</div>
</Card>
))}
</div>
</div>
))}
</div>
</div>
</div>
)
}

function StructureIcon({ type, level }: { type: Structure['type'], level: number }) {
const scale = 1 + (level - 1) * 0.2

switch (type) {
case 'dome':
return (
<svg width="100%" height="100%" viewBox="0 0 100 100" className="text-cyan-400">
<path
d={`M10,70 A40,40 0 0,1 90,70`}
fill="none"
stroke="currentColor"
strokeWidth={3}
style={{ transform: `scale(${scale})`, transformOrigin: 'center' }}
/>
<rect x="15" y="70" width="70" height="20" fill="currentColor" opacity="0.5" />
<line x1="50" y1="70" x2="50" y2="90" stroke="currentColor" strokeWidth="2" />
</svg>
)
case 'launcher':
return (
<svg width="100%" height="100%" viewBox="0 0 100 100" className="text-cyan-400">
<path
d="M40,90 L50,20 L60,90 Z"
fill="currentColor"
style={{ transform: `scale(${scale})`, transformOrigin: 'center' }}
/>
<rect x="35" y="85" width="30" height="5" fill="currentColor" opacity="0.5" />
</svg>
)
case 'solar':
return (
<svg width="100%" height="100%" viewBox="0 0 100 100" className="text-cyan-400">
<g style={{ transform: `scale(${scale})`, transformOrigin: 'center' }}>
{Array.from({ length: level }, (_, i) => (
<rect
key={i}
x={25 + i * 20 / level}
y="40"
width={15 / level}
height="40"
fill="currentColor"
opacity="0.8"
/>
))}
</g>
<rect x="20" y="80" width="60" height="5" fill="currentColor" />
</svg>
)
case 'telescope':
return (
<svg width="100%" height="100%" viewBox="0 0 100 100" className="text-cyan-400">
{level >= 1 && (
<g style={{ transform: `scale(${scale})`, transformOrigin: 'center' }}>
<circle cx="50" cy="40" r="15" fill="currentColor" opacity="0.8" />
<line x1="50" y1="55" x2="50" y2="90" stroke="currentColor" strokeWidth="3" />
</g>
)}
{level >= 2 && (
<path d="M20,60 Q50,20 80,60" fill="none" stroke="currentColor" strokeWidth="2" />
)}
{level >= 3 && (
<>
<circle cx="20" cy="70" r="10" fill="currentColor" opacity="0.6" />
<circle cx="80" cy="70" r="10" fill="currentColor" opacity="0.6" />
</>
)}
<rect x="45" y="85" width="10" height="10" fill="currentColor" />
</svg>
)
case 'hab':
return (
<svg width="100%" height="100%" viewBox="0 0 100 100" className="text-cyan-400">
<g style={{ transform: `scale(${scale})`, transformOrigin: 'center' }}>
<rect x="30" y="50" width="40" height="30" fill="currentColor" opacity="0.8" />
<polygon points="30,50 50,30 70,50" fill="currentColor" />
{level >= 2 && <rect x="10" y="60" width="20" height="20" fill="currentColor" opacity="0.6" />}
{level >= 3 && <rect x="70" y="60" width="20" height="20" fill="currentColor" opacity="0.6" />}
</g>
<rect x="25" y="80" width="50" height="5" fill="currentColor" />
</svg>
)
default:
return null
}
}

13 changes: 13 additions & 0 deletions components/Inventory/Grid/Items/RadioTelescope.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export function RadioTelescope({ level }: { level: number }) {
return (
<div className="flex flex-col items-center">
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="70" r="25" stroke="#00FFFF" strokeWidth="2" />
<line x1="50" y1="70" x2="50" y2="10" stroke="#00FFFF" strokeWidth="2" />
<line x1="35" y1="25" x2="65" y2="25" stroke="#00FFFF" strokeWidth="2" />
</svg>
<p className="text-white mt-2">Radio Telescope</p>
</div>
)
}

13 changes: 13 additions & 0 deletions components/Inventory/Grid/Items/ResearchStation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export function ResearchStation({ level }: { level: number }) {
return (
<div className="flex flex-col items-center">
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="20" y="40" width="60" height="40" stroke="#FFFF00" strokeWidth="2" />
<polygon points="20,40 50,20 80,40" stroke="#FFFF00" strokeWidth="2" fill="none" />
<rect x="40" y="60" width="20" height="20" stroke="#FFFF00" strokeWidth="2" />
</svg>
<p className="text-white mt-2">Research Station</p>
</div>
)
}

Loading

0 comments on commit c1b1e39

Please sign in to comment.