Compare commits
2 commits
7ad84c3ddb
...
fa7e1a5e09
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa7e1a5e09 | ||
|
|
7c40c82296 |
386
app/cv/page.tsx
Normal file
386
app/cv/page.tsx
Normal file
|
|
@ -0,0 +1,386 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import PageLayout from "@/components/PageLayout";
|
||||||
|
import { Mail, Globe, MapPin, ExternalLink, Server, Zap } from "lucide-react";
|
||||||
|
|
||||||
|
export default function CVPage() {
|
||||||
|
return (
|
||||||
|
<PageLayout backLink="/" maxWidth="5xl">
|
||||||
|
{/* Hide the print button itself during printing */}
|
||||||
|
<div className="flex justify-end mb-4 no-print">
|
||||||
|
<button
|
||||||
|
onClick={() => window.print()}
|
||||||
|
className="flex items-center gap-2 px-4 py-2 bg-slate-800 hover:bg-orange-600 text-white text-xs font-mono tracking-widest uppercase transition-colors rounded-sm"
|
||||||
|
>
|
||||||
|
<Zap size={14} /> Print PDF
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Main Container*/}
|
||||||
|
<div className="bg-white text-slate-900 p-8 md:p-16 rounded-sm shadow-2xl print:shadow-none print:p-12 print:m-0 font-sans print:text-[12pt] leading-normal">
|
||||||
|
<header className="border-b-4 border-slate-900 pb-8 print:pb-4 mb-8 print:mb-6 flex flex-col md:flex-row print:grid print:grid-cols-[1.5fr_1fr] justify-between items-start gap-6">
|
||||||
|
<div className="flex print:flex print:items-center">
|
||||||
|
<div className="mr-3 shrink-0">
|
||||||
|
<img
|
||||||
|
src="/profile.jpg"
|
||||||
|
alt="George A. Webberley"
|
||||||
|
className="w-25 h-25 print:w-16 print:h-16 rounded-full object-cover border-2 border-slate-100 shadow-sm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="min-w-0">
|
||||||
|
<h1 className="text-5xl print:text-3xl font-extrabold tracking-tighter mb-2 text-slate-900 whitespace-nowrap">
|
||||||
|
George A. Webberley
|
||||||
|
</h1>
|
||||||
|
<p className="text-2xl print:text-[14pt] text-orange-600 font-bold uppercase tracking-tight whitespace-nowrap">
|
||||||
|
Full Stack Engineer // Systems Architect
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Contact Info - Explicitly right-aligned for print */}
|
||||||
|
<div className="space-y-1 text-sm print:text-[9px] text-slate-500 font-mono text-right print:w-full print:flex print:flex-col print:items-end">
|
||||||
|
<div className="flex items-center md:justify-end gap-2">
|
||||||
|
<MapPin size={14} /> Copenhagen, Denmark
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center md:justify-end gap-2">
|
||||||
|
<Mail size={14} /> george@georgew.dev
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center md:justify-end gap-2 text-orange-600 font-bold">
|
||||||
|
<Globe size={14} /> georgew.dev
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-12 print:grid-cols-12 gap-8 print:gap-10">
|
||||||
|
{/* Main Column */}
|
||||||
|
<div className="lg:col-span-8 print:col-span-8 space-y-10 print:space-y-6">
|
||||||
|
<section>
|
||||||
|
<h2 className="text-xs uppercase tracking-[0.2em] font-black text-slate-400 mb-4 print:mb-2 border-b border-slate-100 pb-2">
|
||||||
|
Professional Summary
|
||||||
|
</h2>
|
||||||
|
<p className="text-md print:text-sm leading-relaxed text-slate-700">
|
||||||
|
After 5 years as a dental surgeon, a serendipitous broken leg
|
||||||
|
led me to discover that software engineering perfectly suits my
|
||||||
|
analytical mind. Now an MSc (Distinction) graduate and Senior
|
||||||
|
Engineer, my core expertise lies in the entire product
|
||||||
|
lifecycle. I’m less about a specific niche and more about the
|
||||||
|
whole stack. I enjoy the challenge of creating a clean frontend,
|
||||||
|
connecting a stable backend API, and building the infrastructure
|
||||||
|
that keeps it all running. I'm always looking for the most
|
||||||
|
efficient way to get a project from 'concept' to
|
||||||
|
'shipped'.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2 className="text-xs uppercase tracking-[0.2em] font-black text-slate-400 mb-6 print:mb-3 border-b border-slate-100 pb-2">
|
||||||
|
Engineering Experience
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-10 print:space-y-6">
|
||||||
|
{/* Brain+ Section */}
|
||||||
|
<div className="break-inside-avoid">
|
||||||
|
<div className="flex justify-between items-baseline mb-1">
|
||||||
|
<h3 className="text-xl print:text-base font-bold italic text-slate-900">
|
||||||
|
Brain+, Copenhagen
|
||||||
|
</h3>
|
||||||
|
<span className="text-sm print:text-xs font-mono font-bold text-orange-600 uppercase">
|
||||||
|
2022 — Present
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-slate-500 font-bold mb-3 print:mb-1 italic text-sm print:text-xs">
|
||||||
|
Technical Lead & Senior Full Stack Developer
|
||||||
|
</p>
|
||||||
|
<ul className="list-disc ml-5 space-y-2 text-slate-600 text-sm print:text-[12px] print:leading-snug">
|
||||||
|
<li>
|
||||||
|
<strong>Product Ownership:</strong> I act as the bridge
|
||||||
|
between technical and product teams; I handle the full
|
||||||
|
product lifecycle from initial design and sprint planning
|
||||||
|
to final demos.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Infrastructure:</strong> Architected a resilient
|
||||||
|
multi-cloud setup focusing on high availability,
|
||||||
|
scalability, and security. I leveraged container
|
||||||
|
orchestration (K8s), modern load balancers, and VPC
|
||||||
|
security policies all managed through IaC (Terraform) to
|
||||||
|
ensure 24/7 reliability.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>DevOps & Automation:</strong> Built automated
|
||||||
|
CI/CD pipelines using GitHub Actions and Fastlane for
|
||||||
|
mobile releases. I utilize Kubectl and custom Makefiles to
|
||||||
|
streamline cluster management and standardize local
|
||||||
|
development environments.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Full Stack Delivery:</strong> Scaled core features
|
||||||
|
using Ruby on Rails REST API services and Flask, while
|
||||||
|
managing the rigorous documentation and release processes
|
||||||
|
required for high-stakes medical compliance.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Other Roles */}
|
||||||
|
<div className="space-y-8 print:space-y-4">
|
||||||
|
{/* StageUp */}
|
||||||
|
<div className="break-inside-avoid">
|
||||||
|
<div className="flex justify-between items-baseline mb-1">
|
||||||
|
<h4 className="text-lg print:text-sm font-bold italic text-slate-800">
|
||||||
|
StageUp, Cardiff
|
||||||
|
</h4>
|
||||||
|
<span className="text-xs font-mono text-slate-400 uppercase">
|
||||||
|
2021 — 2022
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm print:text-xs text-slate-600 mb-3 print:mb-1.5 leading-relaxed">
|
||||||
|
Delivered new features and backend logic for a startup
|
||||||
|
platform, while maintaining the GCP infrastructure and
|
||||||
|
deployment pipelines.
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
{[
|
||||||
|
"Angular",
|
||||||
|
"Node.js",
|
||||||
|
"PostgreSQL",
|
||||||
|
"Terraform",
|
||||||
|
"Docker",
|
||||||
|
"GCP",
|
||||||
|
].map((t) => (
|
||||||
|
<span
|
||||||
|
key={t}
|
||||||
|
className="text-[9px] print:text-[8px] font-bold px-1.5 py-0.5 bg-slate-50 border border-slate-200 text-slate-500 rounded-sm uppercase"
|
||||||
|
>
|
||||||
|
{t}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Startemup */}
|
||||||
|
<div className="break-inside-avoid">
|
||||||
|
<div className="flex justify-between items-baseline mb-1">
|
||||||
|
<h4 className="text-lg print:text-sm font-bold italic text-slate-800">
|
||||||
|
Startemup, Ontario
|
||||||
|
</h4>
|
||||||
|
<span className="text-xs font-mono text-slate-400 uppercase">
|
||||||
|
2021 — 2023
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm print:text-xs text-slate-600 mb-3 print:mb-1.5 leading-relaxed">
|
||||||
|
Technical troubleshooter for complex WordPress
|
||||||
|
customizations requiring bespoke PHP logic and deep
|
||||||
|
performance optimization.
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
{[
|
||||||
|
"PHP",
|
||||||
|
"WordPress",
|
||||||
|
"Performance Optimization",
|
||||||
|
"Bespoke Logic",
|
||||||
|
].map((t) => (
|
||||||
|
<span
|
||||||
|
key={t}
|
||||||
|
className="text-[9px] print:text-[8px] font-bold px-1.5 py-0.5 bg-slate-50 border border-slate-200 text-slate-500 rounded-sm uppercase"
|
||||||
|
>
|
||||||
|
{t}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Ratoong */}
|
||||||
|
<div className="break-inside-avoid">
|
||||||
|
<div className="flex justify-between items-baseline mb-1">
|
||||||
|
<h4 className="text-lg print:text-sm font-bold italic text-slate-800">
|
||||||
|
Ratoong, Copenhagen
|
||||||
|
</h4>
|
||||||
|
<span className="text-xs font-mono text-slate-400 uppercase">
|
||||||
|
2020 — 2022
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm print:text-xs text-slate-600 mb-3 print:mb-1.5 leading-relaxed">
|
||||||
|
Leading the end-to-end development of a functional SPA,
|
||||||
|
moving from initial UI designs to a live production
|
||||||
|
environment.
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
{["Angular", "Firebase", "GCP", "SPA Architecture"].map(
|
||||||
|
(t) => (
|
||||||
|
<span
|
||||||
|
key={t}
|
||||||
|
className="text-[9px] print:text-[8px] font-bold px-1.5 py-0.5 bg-slate-50 border border-slate-200 text-slate-500 rounded-sm uppercase"
|
||||||
|
>
|
||||||
|
{t}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Sidebar */}
|
||||||
|
<div className="lg:col-span-4 print:col-span-4 space-y-10 print:space-y-6">
|
||||||
|
<section>
|
||||||
|
<h2 className="text-xs uppercase tracking-[0.2em] font-black text-slate-400 mb-6 print:mb-3 border-b border-slate-100 pb-2 text-slate-900">
|
||||||
|
Technical Mastery
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-6 print:space-y-4">
|
||||||
|
<div>
|
||||||
|
<p className="text-[10px] font-black uppercase mb-2 text-slate-500">
|
||||||
|
Infrastructure & Ops
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
{[
|
||||||
|
"Kubernetes",
|
||||||
|
"Docker",
|
||||||
|
"Terraform",
|
||||||
|
"GCP",
|
||||||
|
"OTC",
|
||||||
|
"CI/CD",
|
||||||
|
"VPC",
|
||||||
|
].map((s) => (
|
||||||
|
<span
|
||||||
|
key={s}
|
||||||
|
className="px-2 py-0.5 bg-slate-900 text-white text-[10px] print:text-[8px] font-bold rounded-sm uppercase"
|
||||||
|
>
|
||||||
|
{s}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-[10px] font-black uppercase mb-2 text-slate-500">
|
||||||
|
Full Stack Engineering
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
{[
|
||||||
|
"TypeScript",
|
||||||
|
"Flutter",
|
||||||
|
"Python",
|
||||||
|
"React",
|
||||||
|
"Angular",
|
||||||
|
"Node.js",
|
||||||
|
"Rails",
|
||||||
|
"PostgreSQL",
|
||||||
|
"NoSQL",
|
||||||
|
].map((s) => (
|
||||||
|
<span
|
||||||
|
key={s}
|
||||||
|
className="px-2 py-0.5 bg-slate-100 text-slate-700 text-[10px] print:text-[8px] font-bold rounded-sm uppercase"
|
||||||
|
>
|
||||||
|
{s}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2 className="text-xs uppercase tracking-[0.2em] font-black text-slate-400 mb-6 print:mb-3 border-b border-slate-100 pb-2">
|
||||||
|
Education
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-4 print:space-y-2">
|
||||||
|
<div>
|
||||||
|
<p className="font-bold text-slate-900 text-sm print:text-xs">
|
||||||
|
MSc Computer Science
|
||||||
|
</p>
|
||||||
|
<p className="text-[10px] text-orange-600 font-bold uppercase tracking-tighter">
|
||||||
|
Distinction
|
||||||
|
</p>
|
||||||
|
<p className="text-[10px] text-slate-400 italic">
|
||||||
|
Univ. of Bristol
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-bold text-slate-900 text-sm print:text-xs">
|
||||||
|
Bachelor of Dental Surgery
|
||||||
|
</p>
|
||||||
|
<p className="text-[10px] text-slate-400 italic">
|
||||||
|
Univ. of Bristol (Merit)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2 className="text-xs uppercase tracking-[0.2em] font-black text-slate-400 mb-6 print:mb-3 border-b border-slate-100 pb-2 text-slate-900">
|
||||||
|
Systems Tinkering
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-6 print:space-y-3">
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<Server size={14} className="text-orange-600" />
|
||||||
|
<p className="font-bold text-slate-900 text-xs">
|
||||||
|
Cloud-Hybrid Laboratory
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<p className="text-[11px] print:text-[10px] text-slate-600 leading-snug">
|
||||||
|
I manage a suite of self-hosted services. A playground for
|
||||||
|
breaking things in private. I use{" "}
|
||||||
|
<strong>Tailscale and Woodpecker CI</strong> to orchestrate
|
||||||
|
everything from <strong>Grafana surf dashboards</strong> to
|
||||||
|
personal wikis.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<Zap size={14} className="text-orange-600" />
|
||||||
|
<p className="font-bold text-slate-900 text-xs">
|
||||||
|
Product Prototyping
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<p className="text-[12px] print:text-[10px] text-slate-600 leading-snug">
|
||||||
|
Building quirky apps like a "not-pokemon" pet
|
||||||
|
collecting game and a space-rocket countdown dashboard.
|
||||||
|
Check out my <strong>portfolio website</strong> for full
|
||||||
|
details!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2 className="text-xs uppercase tracking-[0.2em] font-black text-slate-400 mb-6 print:mb-3 border-b border-slate-100 pb-2 text-slate-900">
|
||||||
|
Human
|
||||||
|
</h2>
|
||||||
|
<p className="text-[12px] print:text-[10px] text-slate-600 leading-relaxed italic">
|
||||||
|
Surfing, photography, and following space news. Usually found
|
||||||
|
watching anime while tinkering with my server stack. Currently
|
||||||
|
learning Danish (undskyld på forhånd).
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div className="pt-4 print:pt-2">
|
||||||
|
<div className="p-4 print:p-3 bg-orange-50 rounded-sm border-l-4 border-orange-600">
|
||||||
|
<p className="text-[10px] font-bold text-orange-600 uppercase mb-2 print:mb-1">
|
||||||
|
Portfolio Deep Dive
|
||||||
|
</p>
|
||||||
|
<p className="text-[12px] print:text-[10px] text-slate-700 mb-3 print:mb-1.5 leading-tight">
|
||||||
|
Detailed architecture diagrams and documentation:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Web Version: Clickable Link */}
|
||||||
|
<a
|
||||||
|
href="https://georgew.dev"
|
||||||
|
className="text-sm print:hidden font-black flex items-center gap-1 hover:underline text-slate-900"
|
||||||
|
>
|
||||||
|
GEORGEW.DEV <ExternalLink size={14} />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{/* Print Version: Static text that won't be stripped by "a" selectors */}
|
||||||
|
<div className="hidden print:block text-sm font-black text-slate-900">
|
||||||
|
GEORGEW.DEV
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PageLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -31,3 +31,62 @@ body {
|
||||||
max-width: none;
|
max-width: none;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
@page {
|
||||||
|
size: A4;
|
||||||
|
margin: 0 !important; /* Use 0 here, and handle padding in the React component */
|
||||||
|
-webkit-margin-before: 0;
|
||||||
|
-webkit-margin-after: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force the body to be the exact width of A4 to prevent scaling */
|
||||||
|
body {
|
||||||
|
width: 210mm;
|
||||||
|
height: 297mm;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: white !important;
|
||||||
|
-webkit-print-color-adjust: exact !important;
|
||||||
|
print-color-adjust: exact !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide everything outside the CV content */
|
||||||
|
#safari-extension-is-installed,
|
||||||
|
main a[href="/"],
|
||||||
|
main a[href*="back"],
|
||||||
|
footer,
|
||||||
|
.no-print {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure the PageLayout wrapper doesn't add width or centering */
|
||||||
|
main {
|
||||||
|
display: block !important;
|
||||||
|
min-height: auto !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
background: white !important;
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Ensure the inner container doesn't push content down */
|
||||||
|
main > div {
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
max-width: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Fix the "page break" issue after the title */
|
||||||
|
h1,
|
||||||
|
header {
|
||||||
|
break-after: avoid;
|
||||||
|
break-inside: avoid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,12 @@ export default function Home() {
|
||||||
>
|
>
|
||||||
LinkedIn
|
LinkedIn
|
||||||
</a>
|
</a>
|
||||||
|
<Link
|
||||||
|
href="/cv"
|
||||||
|
className="text-neutral-500 hover:text-white transition-colors"
|
||||||
|
>
|
||||||
|
CV
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</motion.header>
|
</motion.header>
|
||||||
|
|
||||||
|
|
|
||||||
BIN
public/profile.jpg
Normal file
BIN
public/profile.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
Loading…
Reference in a new issue