151 lines
6.8 KiB
TypeScript
151 lines
6.8 KiB
TypeScript
"use client";
|
|
import { motion } from "framer-motion";
|
|
import { Server, Globe, Smartphone, Gamepad2, Activity } from "lucide-react";
|
|
|
|
export default function Home() {
|
|
return (
|
|
<main className="min-h-screen bg-[#0a0a0a] text-white p-6 md:p-12 lg:p-24">
|
|
{/* Header section */}
|
|
<header className="mb-12">
|
|
<h1 className="text-4xl font-bold tracking-tight">George W.</h1>
|
|
<p className="text-neutral-400 mt-2">Senior Full Stack Engineer & Tech Lead</p>
|
|
</header>
|
|
|
|
{/* Bento Grid */}
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 auto-rows-[180px]">
|
|
|
|
{/* About Me - Large Card */}
|
|
<motion.div
|
|
whileHover={{ y: -5 }}
|
|
className="md:col-span-2 md:row-span-2 p-8 rounded-3xl bg-neutral-900 border border-neutral-800 flex flex-col justify-between"
|
|
>
|
|
<div>
|
|
<h2 className="text-2xl font-semibold mb-4">The Architect</h2>
|
|
<p className="text-neutral-400 leading-relaxed">
|
|
Engineering high-scale web systems and mobile experiences.
|
|
Passionate about self-hosting, clean architecture, and performance.
|
|
</p>
|
|
</div>
|
|
<div className="flex gap-2 text-xs font-mono text-neutral-500">
|
|
<span>#NextJS</span> <span>#Flutter</span> <span>#Docker</span>
|
|
</div>
|
|
</motion.div>
|
|
|
|
{/* Live Pulse Card */}
|
|
<motion.div
|
|
whileHover={{ y: -5 }}
|
|
className="group md:col-span-2 p-6 rounded-3xl bg-neutral-900 border border-neutral-800 flex flex-col justify-center relative overflow-hidden transition-all duration-300 min-h-[180px]"
|
|
>
|
|
{/* The Monitor Map (Easily editable) */}
|
|
{(() => {
|
|
const monitors = [
|
|
{ id: 2, name: "Datasaur" },
|
|
{ id: 6, name: "Audiobookshelf" },
|
|
{ id: 7, name: "Woodpecker CI" },
|
|
{ id: 8, name: "Forgejo Git" },
|
|
{ id: 9, name: "Server dashboard" },
|
|
{ id: 10, name: "Ratoong" },
|
|
];
|
|
|
|
return (
|
|
<>
|
|
{/* Default View */}
|
|
<div className="flex items-center justify-between w-full group-hover:opacity-0 group-hover:pointer-events-none transition-opacity duration-300">
|
|
<div>
|
|
<div className="flex items-center gap-2 mb-1">
|
|
<div className="w-2 h-2 rounded-full bg-green-500 animate-pulse" />
|
|
<span className="font-medium text-white">Hetzner Node-01</span>
|
|
</div>
|
|
<div className="flex gap-2 items-center">
|
|
<p className="text-sm text-neutral-500">System Status:</p>
|
|
<img
|
|
src="https://status.georgew.dev/api/status-page/dashboard/badge"
|
|
alt="Overall Status"
|
|
className="h-5"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<Activity className="text-neutral-700 w-8 h-8" />
|
|
</div>
|
|
|
|
{/* Hover View: Friendly Names */}
|
|
<div className="absolute inset-0 p-6 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-col justify-center bg-neutral-900/95 backdrop-blur-sm">
|
|
<h4 className="text-[10px] font-mono text-neutral-500 mb-3 uppercase tracking-[0.2em]">Service Registry</h4>
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
|
{monitors.map((m) => (
|
|
<div key={m.id} className="flex items-center justify-between bg-neutral-800/40 p-2 rounded-lg border border-neutral-700/30">
|
|
<span className="text-[11px] font-medium text-neutral-300 truncate mr-2">{m.name}</span>
|
|
<div className="flex gap-1 shrink-0">
|
|
<img src={`https://status.georgew.dev/api/badge/${m.id}/status`} className="h-3" alt="up" />
|
|
<img src={`https://status.georgew.dev/api/badge/${m.id}/avg-response/24`} className="h-3 opacity-60" alt="ms" />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
})()}
|
|
</motion.div>
|
|
|
|
{/* Project One */}
|
|
<motion.div
|
|
whileHover={{ scale: 1.02 }}
|
|
className="md:col-span-1 p-6 rounded-3xl bg-[#1a1a1a] border border-neutral-800 flex flex-col justify-end group cursor-pointer"
|
|
>
|
|
<Globe className="mb-auto text-blue-400" />
|
|
<h3 className="font-semibold mt-4">Prod Website</h3>
|
|
<p className="text-xs text-neutral-500">Case Study 01</p>
|
|
</motion.div>
|
|
|
|
{/* Project Two */}
|
|
<motion.div
|
|
whileHover={{ scale: 1.02 }}
|
|
className="md:col-span-1 p-6 rounded-3xl bg-[#1a1a1a] border border-neutral-800 flex flex-col justify-end cursor-pointer"
|
|
>
|
|
<Smartphone className="mb-auto text-purple-400" />
|
|
<h3 className="font-semibold mt-4">Mobile App</h3>
|
|
<p className="text-xs text-neutral-500">Active Dev</p>
|
|
</motion.div>
|
|
|
|
{/* Game Teaser / The Lab */}
|
|
<motion.div
|
|
whileHover={{ scale: 1.02 }}
|
|
className="md:col-span-2 p-6 rounded-3xl bg-gradient-to-br from-[#111] to-[#1a1a1a] border border-neutral-800 flex items-center gap-6"
|
|
>
|
|
<div className="p-4 rounded-2xl bg-neutral-800">
|
|
<Gamepad2 className="w-8 h-8 text-orange-400" />
|
|
</div>
|
|
<div>
|
|
<h3 className="font-semibold italic">The Forge</h3>
|
|
<p className="text-sm text-neutral-500">Indie Game Dev & Prototypes</p>
|
|
</div>
|
|
</motion.div>
|
|
|
|
</div>
|
|
|
|
{/* Deployment Footer */}
|
|
<footer className="mt-12 pt-8 border-t border-neutral-900 flex flex-col md:flex-row justify-between items-center gap-4 text-[10px] text-neutral-600 font-mono tracking-wider uppercase">
|
|
<div className="flex items-center gap-6">
|
|
<div className="flex items-center gap-2">
|
|
<p>Pipeline Status</p>
|
|
<img
|
|
src="https://ci.georgew.dev/api/badges/11/status.svg"
|
|
alt="Build Status"
|
|
className="h-3 grayscale opacity-50 hover:opacity-100 hover:grayscale-0 transition-all"
|
|
/>
|
|
</div>
|
|
<div className="hidden md:block w-[1px] h-3 bg-neutral-800" />
|
|
<p>Engine: Next.js 15 (Standalone)</p>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-4 bg-neutral-900/50 px-3 py-1 rounded-full border border-neutral-800/50">
|
|
<div className="w-1 h-1 rounded-full bg-blue-500" />
|
|
<p className="text-neutral-400">
|
|
Deploy: {process.env.NEXT_PUBLIC_APP_VERSION || 'v1.0.0-dev'}
|
|
</p>
|
|
</div>
|
|
</footer>
|
|
</main>
|
|
);
|
|
} |