Brushed up on core sections of landing page. Laid our structure for web/mobile/devops pages
All checks were successful
ci/woodpecker/release/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/release/woodpecker Pipeline was successful
This commit is contained in:
parent
104e179cc0
commit
f26f81d941
|
|
@ -2,8 +2,7 @@ variables:
|
||||||
- &app_name "portfolio"
|
- &app_name "portfolio"
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: [release, push]
|
- event: release
|
||||||
branch: main
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
build-and-push:
|
build-and-push:
|
||||||
|
|
|
||||||
128
app/page copy 2.tsx
Normal file
128
app/page copy 2.tsx
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
"use client";
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { Globe, Smartphone, Server, 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 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>
|
||||||
|
|
||||||
|
<div className="max-w-7xl mx-auto grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
|
|
||||||
|
{/* Top Row: The Architect (Wide) */}
|
||||||
|
<div className="md:col-span-2 p-8 rounded-3xl bg-neutral-900/50 border border-neutral-800 flex flex-col justify-between min-h-[320px]">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-3xl font-bold mb-4">The Architect</h2>
|
||||||
|
<p className="text-neutral-400 leading-relaxed max-w-2xl">
|
||||||
|
Bridging the gap between complex system architecture and fluid user experiences.
|
||||||
|
I specialize in designing distributed web systems and cross-platform mobile apps
|
||||||
|
with a relentless focus on performance, self-sovereign infrastructure, and automated delivery pipelines.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-3 mt-8 text-[10px] font-mono text-neutral-600">
|
||||||
|
{['#Architecture', '#SystemDesign', '#Automation', '#FullStack', '#Scalability'].map(tag => (
|
||||||
|
<span key={tag}>{tag}</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Top Row: Hetzner Node (Narrow) */}
|
||||||
|
<div className="p-8 rounded-3xl bg-neutral-900/50 border border-neutral-800 flex flex-col justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-2 h-2 rounded-full bg-green-500 animate-pulse" />
|
||||||
|
<span className="text-sm font-medium">Hetzner Node-01</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between items-end">
|
||||||
|
<span className="text-xs text-neutral-500 uppercase tracking-widest">Status: UP</span>
|
||||||
|
<Activity className="text-neutral-800 w-12 h-12" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Middle Row: Web Systems */}
|
||||||
|
<Link href="/projects/web" className="group">
|
||||||
|
<motion.div
|
||||||
|
whileHover={{ y: -5 }}
|
||||||
|
className="p-6 rounded-3xl bg-neutral-900 border border-neutral-800 h-full flex flex-col justify-between min-h-[260px] relative overflow-hidden transition-colors hover:border-blue-500/30"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Globe className="text-blue-400 w-6 h-6 mb-4" />
|
||||||
|
<h3 className="font-bold text-xl mb-2">Web Systems</h3>
|
||||||
|
<p className="text-sm text-neutral-500 leading-relaxed">
|
||||||
|
Architecting distributed platforms with a focus on high-availability, API design, and containerized deployment.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2 mt-6">
|
||||||
|
{['Next.js', 'Python', 'Node.js', 'Caddy', 'PostgreSQL'].map(tech => (
|
||||||
|
<span key={tech} className="text-[9px] font-mono text-neutral-600 border border-neutral-800 px-2 py-1 rounded-md uppercase group-hover:text-blue-400 group-hover:border-blue-500/20">
|
||||||
|
{tech}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Middle Row: Mobile Apps */}
|
||||||
|
<Link href="/projects/mobile" className="group">
|
||||||
|
<motion.div
|
||||||
|
whileHover={{ y: -5 }}
|
||||||
|
className="p-6 rounded-3xl bg-neutral-900 border border-neutral-800 h-full flex flex-col justify-between min-h-[260px] relative overflow-hidden transition-colors hover:border-purple-500/30"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Smartphone className="text-purple-400 w-6 h-6 mb-4" />
|
||||||
|
<h3 className="font-bold text-xl mb-2">Mobile Apps</h3>
|
||||||
|
<p className="text-sm text-neutral-500 leading-relaxed">
|
||||||
|
Building fluid, cross-platform experiences using reactive state management and native hardware integration.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2 mt-6">
|
||||||
|
{['Android', 'iOS', 'Flutter', 'Riverpod', 'Stores'].map(tech => (
|
||||||
|
<span key={tech} className="text-[9px] font-mono text-neutral-600 border border-neutral-800 px-2 py-1 rounded-md uppercase group-hover:text-purple-400 group-hover:border-purple-500/20">
|
||||||
|
{tech}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Middle Row: Infrastructure (The New Card) */}
|
||||||
|
<Link href="/projects/infrastructure" className="group">
|
||||||
|
<motion.div
|
||||||
|
whileHover={{ y: -5 }}
|
||||||
|
className="p-6 rounded-3xl bg-neutral-900 border border-neutral-800 h-full flex flex-col justify-between min-h-[260px] relative overflow-hidden transition-colors hover:border-green-500/30"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Server className="text-green-400 w-6 h-6 mb-4" />
|
||||||
|
<h3 className="font-bold text-xl mb-2">DevOps</h3>
|
||||||
|
<p className="text-sm text-neutral-500 leading-relaxed">
|
||||||
|
Managing self-hosted cloud nodes with automated CI/CD pipelines, secure proxying, and proactive monitoring.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2 mt-6">
|
||||||
|
{['Docker', 'Woodpecker', 'Hetzner', 'Linux', 'Uptime'].map(tech => (
|
||||||
|
<span key={tech} className="text-[9px] font-mono text-neutral-600 border border-neutral-800 px-2 py-1 rounded-md uppercase group-hover:text-green-400 group-hover:border-green-500/20">
|
||||||
|
{tech}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Bottom Row: The Forge (Wide) */}
|
||||||
|
<div className="md:col-span-3 p-8 rounded-3xl bg-neutral-900/50 border border-neutral-800 flex items-center gap-6">
|
||||||
|
<div className="p-4 bg-orange-500/10 rounded-2xl border border-orange-500/20">
|
||||||
|
<Gamepad2 className="text-orange-500 w-8 h-8" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-bold text-xl">The Forge</h3>
|
||||||
|
<p className="text-sm text-neutral-500">Indie Game Dev & Creative Prototypes</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
195
app/page copy.tsx
Normal file
195
app/page copy.tsx
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
"use client";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
import { Server, Globe, Smartphone, Gamepad2, Activity } from "lucide-react";
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
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">
|
||||||
|
Bridging the gap between complex system architecture and fluid user experiences. I specialize in designing distributed web systems and cross-platform mobile apps with a relentless focus on performance, self-sovereign infrastructure, and automated delivery pipelines.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2 text-xs font-mono text-neutral-500">
|
||||||
|
<span>#NextJS</span> <span>#Flutter</span> <span>#Typescript</span> <span>#Python</span> <span>#Node</span> <span>#Docker</span> <span>#Kubernetes</span> <span>#Serverless</span> <span>#CI/CD</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 */}
|
||||||
|
<Link href="/projects/web" className="h-full">
|
||||||
|
<motion.div
|
||||||
|
whileHover={{ y: -5 }}
|
||||||
|
className="group p-6 rounded-3xl bg-neutral-900 border border-neutral-800 h-full relative overflow-hidden cursor-pointer flex flex-col min-h-[260px]"
|
||||||
|
>
|
||||||
|
{/* Icon Container - Fixed size ensures it never disappears */}
|
||||||
|
<div className="mb-4">
|
||||||
|
<Globe className="text-blue-400 w-6 h-6" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1">
|
||||||
|
<h3 className="font-bold text-xl mb-1 text-white">Web Systems</h3>
|
||||||
|
<p className="text-sm text-neutral-500 leading-relaxed mb-4">
|
||||||
|
Architecting distributed platforms with a focus on high-availability, API design, and containerized deployment.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Tech Pips - Use 'flex-wrap' and 'gap-y' to handle multiline safely */}
|
||||||
|
<div className="flex flex-wrap gap-x-2 gap-y-2 pt-2 border-t border-neutral-800/50">
|
||||||
|
{['Next.js', 'Node.js', 'Python', 'PostgreSQL', 'Docker'].map((tech) => (
|
||||||
|
<span key={tech} className="text-[9px] font-mono text-neutral-500 border border-neutral-800 px-2 py-1 rounded-md uppercase tracking-wider group-hover:border-blue-500/30 group-hover:text-blue-400 transition-colors">
|
||||||
|
{tech}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Hover Indicator */}
|
||||||
|
<div className="absolute top-6 right-6 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||||
|
<div className="w-2 h-2 rounded-full bg-blue-500 animate-pulse" />
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Project Two */}
|
||||||
|
<Link href="/projects/mobile">
|
||||||
|
<motion.div
|
||||||
|
whileHover={{ y: -5 }}
|
||||||
|
className="group p-6 rounded-3xl bg-neutral-900 border border-neutral-800 h-full relative overflow-hidden cursor-pointer flex flex-col"
|
||||||
|
>
|
||||||
|
<div className="mb-4">
|
||||||
|
<Smartphone className="text-purple-400 w-6 h-6" />
|
||||||
|
</div>
|
||||||
|
<h3 className="font-bold text-xl mb-1 text-white">Mobile Apps</h3>
|
||||||
|
<p className="text-sm text-neutral-500 leading-relaxed mb-4">
|
||||||
|
Building fluid, cross-platform experiences using reactive state management and native hardware integration.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Tech Pips */}
|
||||||
|
<div className="flex flex-wrap gap-x-2 gap-y-2 pt-2 border-t border-neutral-800/50">
|
||||||
|
{['Android', 'iOS', 'Flutter', 'Riverpod', 'Publishing'].map((tech) => (
|
||||||
|
<span key={tech} className="text-[9px] font-mono text-neutral-500 border border-neutral-800 px-2 py-1 rounded-md uppercase tracking-wider group-hover:border-blue-500/30 group-hover:text-blue-400 transition-colors">
|
||||||
|
{tech}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="absolute top-6 right-6 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||||
|
<div className="w-2 h-2 rounded-full bg-purple-500 animate-pulse" />
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
237
app/page.tsx
237
app/page.tsx
|
|
@ -1,38 +1,96 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { motion } from "framer-motion";
|
|
||||||
import { Server, Globe, Smartphone, Gamepad2, Activity } from "lucide-react";
|
import Link from 'next/link';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { Globe, Smartphone, Server, Gamepad2, Activity } from 'lucide-react';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen bg-[#0a0a0a] text-white p-6 md:p-12 lg:p-24">
|
<main className="min-h-screen bg-[#0a0a0a] text-white p-6 md:p-12 lg:p-24">
|
||||||
{/* Header section */}
|
<div className="max-w-7xl mx-auto">
|
||||||
<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 */}
|
<header className="mb-12">
|
||||||
<motion.div
|
<h1 className="text-4xl font-bold tracking-tight">George W.</h1>
|
||||||
whileHover={{ y: -5 }}
|
<p className="text-neutral-400 mt-2">Senior Full Stack Engineer & Tech Lead</p>
|
||||||
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"
|
</header>
|
||||||
>
|
|
||||||
<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>#Typescript</span> <span>#Python</span> <span>#Node</span> <span>#Docker</span> <span>#Kubernetes</span> <span>#Serverless</span> <span>#CI/CD</span>
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
|
|
||||||
{/* Live Pulse Card */}
|
<div className="grid grid-cols-1 md:grid-cols-6 gap-6">
|
||||||
<motion.div
|
|
||||||
|
{/* Top Row Left: The Architect */}
|
||||||
|
<div className="md:col-span-4 p-8 rounded-3xl bg-neutral-900/50 border border-neutral-800 flex flex-col md:flex-row gap-8 min-h-[350px] overflow-hidden relative">
|
||||||
|
{/* Background Decoration: Subtle Grid or Blueprint */}
|
||||||
|
<div className="absolute top-0 right-0 w-1/2 h-full opacity-[0.03] pointer-events-none">
|
||||||
|
{/* You could place a subtle SVG circuit or architectural grid here */}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Left: Bio & Tags */}
|
||||||
|
<div className="flex-[1.5] flex flex-col justify-between relative z-10">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-3xl font-bold mb-4 tracking-tight">The Architect</h2>
|
||||||
|
<p className="text-base text-neutral-400 leading-relaxed max-w-lg">
|
||||||
|
Bridging the gap between rigid regulatory requirements and fluid user experiences.
|
||||||
|
I specialize in designing <span className="text-white">distributed systems</span> and
|
||||||
|
<span className="text-white"> cross-platform mobile apps</span> with a focus on
|
||||||
|
automated delivery and high-integrity code.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap gap-2 mt-8">
|
||||||
|
{['#Architecture', '#Regulatory Compliance', '#Agile Leadership', '#DevOps'].map(tag => (
|
||||||
|
<span key={tag} className="text-[10px] font-mono text-neutral-500 border border-neutral-800 px-2 py-1 rounded">
|
||||||
|
{tag}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Vertical Divider */}
|
||||||
|
<div className="hidden md:block w-px bg-neutral-800/50 self-stretch" />
|
||||||
|
|
||||||
|
{/* Right: Seniority Specs */}
|
||||||
|
<div className="flex-1 flex flex-col justify-around py-2 relative z-10">
|
||||||
|
<div className="space-y-6">
|
||||||
|
<section>
|
||||||
|
<h4 className="text-[10px] font-mono text-blue-500 uppercase tracking-[0.2em] mb-2">Leadership</h4>
|
||||||
|
<p className="text-xs text-neutral-300 leading-tight">
|
||||||
|
Tech Lead & Scrum Master. Orchestrating sprint cycles, system design, and cross-functional team growth.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h4 className="text-[10px] font-mono text-purple-500 uppercase tracking-[0.2em] mb-2">Integrity</h4>
|
||||||
|
<p className="text-xs text-neutral-300 leading-tight">
|
||||||
|
Experienced in <span className="italic">High-Stakes Environments</span> (Medical/Regulatory), QMS, and Cyber Essentials.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h4 className="text-[10px] font-mono text-green-500 uppercase tracking-[0.2em] mb-2">Infrastructure</h4>
|
||||||
|
<p className="text-xs text-neutral-300 leading-tight">
|
||||||
|
Kubernetes, GCP, and automated CI/CD pipelines.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* <div className="md:col-span-4 p-8 rounded-3xl bg-neutral-900/50 border border-neutral-800 flex flex-col justify-between min-h-[320px]">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-2xl font-bold mb-4">The Architect</h2>
|
||||||
|
<p className="text-sm text-neutral-400 leading-relaxed">
|
||||||
|
Bridging the gap between complex system architecture and fluid user experiences.
|
||||||
|
I specialize in designing distributed web systems and cross-platform mobile apps
|
||||||
|
with a focus on performance and automated delivery.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2 mt-8 text-[9px] font-mono text-neutral-600 uppercase tracking-tighter">
|
||||||
|
{['#Architecture', '#Regulatory', '#SystemDesign', '#Automation', '#FullStack', '#ProductOwner'].map(tag => (
|
||||||
|
<span key={tag}>{tag}</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div> */}
|
||||||
|
|
||||||
|
{/* Top Row Right: The Service Registry (Restored) */}
|
||||||
|
<motion.div
|
||||||
whileHover={{ y: -5 }}
|
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]"
|
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]"
|
||||||
>
|
>
|
||||||
|
|
@ -70,14 +128,14 @@ export default function Home() {
|
||||||
|
|
||||||
{/* Hover View: Friendly Names */}
|
{/* 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">
|
<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>
|
<h4 className="text-[12px] 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">
|
<div className="grid grid-cols-1 sm:grid-cols-1 gap-2">
|
||||||
{monitors.map((m) => (
|
{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">
|
<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>
|
<span className="text-[11px] font-medium text-neutral-300 truncate mr-2">{m.name}</span>
|
||||||
<div className="flex gap-1 shrink-0">
|
<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}/status`} className="h-4" alt="up" />
|
||||||
<img src={`https://status.georgew.dev/api/badge/${m.id}/avg-response/24`} className="h-3 opacity-60" alt="ms" />
|
<img src={`https://status.georgew.dev/api/badge/${m.id}/avg-response/24`} className="h-4 opacity-60" alt="ms" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
@ -88,44 +146,87 @@ export default function Home() {
|
||||||
})()}
|
})()}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Project One */}
|
{/* Middle Row: Web Systems */}
|
||||||
<motion.div
|
<Link href="/projects/web" className="group md:col-span-2">
|
||||||
whileHover={{ scale: 1.02 }}
|
<motion.div
|
||||||
className="md:col-span-1 p-6 rounded-3xl bg-[#1a1a1a] border border-neutral-800 flex flex-col justify-end group cursor-pointer"
|
whileHover={{ y: -5 }}
|
||||||
>
|
className="p-6 rounded-3xl bg-neutral-900 border border-neutral-800 h-full flex flex-col justify-between min-h-[260px] relative transition-colors hover:border-blue-500/30"
|
||||||
<Globe className="mb-auto text-blue-400" />
|
>
|
||||||
<h3 className="font-semibold mt-4">Prod Website</h3>
|
<div>
|
||||||
<p className="text-xs text-neutral-500">Case Study 01</p>
|
<Globe className="text-blue-400 w-6 h-6 mb-4" />
|
||||||
</motion.div>
|
<h3 className="font-bold text-xl mb-2">Web Systems</h3>
|
||||||
|
<p className="text-sm text-neutral-500 leading-relaxed">
|
||||||
|
Architecting distributed platforms with a focus on high-availability and containerized deployment.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2 mt-6">
|
||||||
|
{['Next.js', 'Python', 'Node.js', 'Caddy', 'PostgreSQL'].map(tech => (
|
||||||
|
<span key={tech} className="text-[9px] font-mono text-neutral-600 border border-neutral-800 px-2 py-1 rounded-md uppercase group-hover:text-blue-400 group-hover:border-blue-500/20 transition-all">
|
||||||
|
{tech}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
{/* Project Two */}
|
{/* Middle Row: Mobile Apps */}
|
||||||
<motion.div
|
<Link href="/projects/mobile" className="group md:col-span-2">
|
||||||
whileHover={{ scale: 1.02 }}
|
<motion.div
|
||||||
className="md:col-span-1 p-6 rounded-3xl bg-[#1a1a1a] border border-neutral-800 flex flex-col justify-end cursor-pointer"
|
whileHover={{ y: -5 }}
|
||||||
>
|
className="p-6 rounded-3xl bg-neutral-900 border border-neutral-800 h-full flex flex-col justify-between min-h-[260px] relative transition-colors hover:border-purple-500/30"
|
||||||
<Smartphone className="mb-auto text-purple-400" />
|
>
|
||||||
<h3 className="font-semibold mt-4">Mobile App</h3>
|
<div>
|
||||||
<p className="text-xs text-neutral-500">Active Dev</p>
|
<Smartphone className="text-purple-400 w-6 h-6 mb-4" />
|
||||||
</motion.div>
|
<h3 className="font-bold text-xl mb-2">Mobile Apps</h3>
|
||||||
|
<p className="text-sm text-neutral-500 leading-relaxed">
|
||||||
|
Building fluid, cross-platform experiences using reactive state and native hardware integration.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2 mt-6">
|
||||||
|
{['Android', 'iOS', 'Flutter', 'Riverpod', 'Stores'].map(tech => (
|
||||||
|
<span key={tech} className="text-[9px] font-mono text-neutral-600 border border-neutral-800 px-2 py-1 rounded-md uppercase group-hover:text-purple-400 group-hover:border-purple-500/20 transition-all">
|
||||||
|
{tech}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
{/* Game Teaser / The Lab */}
|
{/* Middle Row: DevOps */}
|
||||||
<motion.div
|
<Link href="/projects/infrastructure" className="group md:col-span-2">
|
||||||
whileHover={{ scale: 1.02 }}
|
<motion.div
|
||||||
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"
|
whileHover={{ y: -5 }}
|
||||||
>
|
className="p-6 rounded-3xl bg-neutral-900 border border-neutral-800 h-full flex flex-col justify-between min-h-[260px] relative transition-colors hover:border-green-500/30"
|
||||||
<div className="p-4 rounded-2xl bg-neutral-800">
|
>
|
||||||
<Gamepad2 className="w-8 h-8 text-orange-400" />
|
<div>
|
||||||
|
<Server className="text-green-400 w-6 h-6 mb-4" />
|
||||||
|
<h3 className="font-bold text-xl mb-2">DevOps</h3>
|
||||||
|
<p className="text-sm text-neutral-500 leading-relaxed">
|
||||||
|
Managing self-hosted cloud nodes with automated CI/CD pipelines and proactive monitoring.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2 mt-6">
|
||||||
|
{['Docker', 'Woodpecker', 'Hetzner', 'Linux', 'Uptime'].map(tech => (
|
||||||
|
<span key={tech} className="text-[9px] font-mono text-neutral-600 border border-neutral-800 px-2 py-1 rounded-md uppercase group-hover:text-green-400 group-hover:border-green-500/20 transition-all">
|
||||||
|
{tech}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Bottom Row: The Forge */}
|
||||||
|
<div className="md:col-span-6 p-8 rounded-3xl bg-neutral-900/50 border border-neutral-800 flex items-center gap-6 group hover:border-orange-500/30 transition-colors cursor-pointer">
|
||||||
|
<div className="p-4 bg-orange-500/10 rounded-2xl border border-orange-500/20 group-hover:border-orange-500/40 transition-colors">
|
||||||
|
<Gamepad2 className="text-orange-500 w-8 h-8" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-bold text-xl">The Forge</h3>
|
||||||
|
<p className="text-sm text-neutral-500">Indie Game Dev & Creative Prototypes</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
</div>
|
||||||
<h3 className="font-semibold italic">The Forge</h3>
|
<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">
|
||||||
<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-6">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<p>Pipeline Status</p>
|
<p>Pipeline Status</p>
|
||||||
|
|
@ -146,6 +247,8 @@ export default function Home() {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
116
app/projects/[category]/page.tsx
Normal file
116
app/projects/[category]/page.tsx
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
"use client";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { Globe, Smartphone, ArrowLeft } from "lucide-react";
|
||||||
|
import { use } from "react";
|
||||||
|
|
||||||
|
const categories = {
|
||||||
|
web: {
|
||||||
|
title: "Web Systems",
|
||||||
|
icon: <Globe className="w-8 h-8 text-blue-400" />,
|
||||||
|
description: "Architecting scalable web applications and distributed systems.",
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: "Ratoong",
|
||||||
|
detail: "Professional production platform.",
|
||||||
|
stack: ["Node.js", "PostgreSQL", "Caddy"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Datasaur",
|
||||||
|
detail: "Full-stack data science pipeline.",
|
||||||
|
stack: ["Python", "FastAPI", "Next.js"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
mobile: {
|
||||||
|
title: "Mobile Apps",
|
||||||
|
icon: <Smartphone className="w-8 h-8 text-purple-400" />,
|
||||||
|
description: "Building cross-platform experiences with Flutter and native integrations.",
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: "Flutter App 1",
|
||||||
|
detail: "Active Development - Coming Soon",
|
||||||
|
stack: ["Flutter", "Dart", "Firebase"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Flutter App 2",
|
||||||
|
detail: "Internal R&D Prototype",
|
||||||
|
stack: ["Flutter", "Riverpod", "SQLite"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function CategoryPage({ params }: { params: Promise<{ category: string }> }) {
|
||||||
|
|
||||||
|
|
||||||
|
const resolvedParams = use(params);
|
||||||
|
const category = resolvedParams.category;
|
||||||
|
|
||||||
|
const data = categories[category as keyof typeof categories];
|
||||||
|
|
||||||
|
if (!data) return <div className="p-24 text-white">Category not found.</div>;
|
||||||
|
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return (
|
||||||
|
<div className="p-24 text-white font-mono">
|
||||||
|
<h1 className="text-2xl mb-4">404: Category Not Found</h1>
|
||||||
|
<p className="text-neutral-500">Path: /projects/{category}</p>
|
||||||
|
<Link href="/" className="text-blue-400 underline mt-4 block">Return Home</Link>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen bg-[#0a0a0a] text-white p-8 md:p-24">
|
||||||
|
<Link href="/" className="flex items-center gap-2 text-neutral-500 hover:text-white transition-colors mb-12 font-mono text-xs">
|
||||||
|
<ArrowLeft size={14} /> BACK TO DASHBOARD
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="max-w-5xl mx-auto"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-4 mb-6">
|
||||||
|
{data.icon}
|
||||||
|
<h1 className="text-5xl font-bold">{data.title}</h1>
|
||||||
|
</div>
|
||||||
|
<p className="text-xl text-neutral-400 max-w-2xl mb-16">{data.description}</p>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 gap-8">
|
||||||
|
{data.projects.map((project, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={project.name}
|
||||||
|
layout
|
||||||
|
initial={{ opacity: 0, x: -20 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{
|
||||||
|
delay: index * 0.1,
|
||||||
|
duration: 0.4,
|
||||||
|
ease: "easeOut"
|
||||||
|
}}
|
||||||
|
className="group p-8 rounded-3xl bg-neutral-900/50 border border-neutral-800 hover:border-neutral-700 transition-colors"
|
||||||
|
>
|
||||||
|
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
||||||
|
<div>
|
||||||
|
<h3 className="text-2xl font-semibold mb-2">{project.name}</h3>
|
||||||
|
<p className="text-neutral-500">{project.detail}</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{project.stack.map(s => (
|
||||||
|
<span key={s} className="text-[10px] font-mono bg-neutral-800 text-neutral-400 px-3 py-1 rounded-full uppercase">
|
||||||
|
{s}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue