Files
com.gregkilmer.www/src/pages/professional/index.astro
T
2026-07-04 18:58:16 -04:00

304 lines
11 KiB
Plaintext

---
/**
* professional/index.astro — Professional (Resume / Portfolio)
* ---------------------------------------------------------------------------
* The "polished wing". A single long-scroll page whose sections read as a
* narrative (Summary -> Experience -> Skills -> Projects -> Education ->
* Contact), per the spec. Uses surface="professional" for the dark slate tone.
*
* Experience comes from the `experience` collection; projects from the
* `projects` collection. Both are sorted by `order`. Education is a placeholder
* block (spec leaves it to Greg).
*/
import BaseLayout from "@layouts/BaseLayout.astro";
import Reveal from "@components/motion/Reveal.astro";
import Icon from "@components/Icon.astro";
import SectionHeader from "@components/layout/SectionHeader.astro";
import SectionNav from "@components/professional/SectionNav.astro";
import Timeline from "@components/professional/Timeline.astro";
import SkillGrid from "@components/professional/SkillGrid.astro";
import ProjectCard from "@components/professional/ProjectCard.astro";
import EducationHistory from "@components/professional/EducationHistory.astro";
import Certifications from "@components/professional/Certifications.astro";
import AlchemicalDivider from "@components/mystic/AlchemicalDivider.astro";
import Astrolabe from "@components/mystic/Astrolabe.astro";
import CircuitField from "@components/mystic/CircuitField.tsx";
import CelestialFrame from "@components/mystic/CelestialFrame.astro";
import { getCollection } from "astro:content";
const experience = (await getCollection("experience")).sort(
(a, b) => a.data.order - b.data.order,
);
const projects = (await getCollection("projects")).sort(
(a, b) => a.data.order - b.data.order,
);
---
<BaseLayout
surface="professional"
title="Professional"
description="Software developer and team lead: cloud and mobile development, SAP Business Technology Platform, AI/ML, full-stack work. Resume and portfolio for Greg Kilmer."
>
{/* Page header + overlapping headshot.
The headshot is anchored to the HERO SECTION (not container-prose) so its
straddle point is the true hero/next-section boundary. It's positioned on
the right, aligned with the content column's right edge via the same
container-prose centering math (a centered max-width column). translate-y-1/2
puts its center on the boundary: half in the hero, half over the next
section, in front of both (z-50). */}
<section class="relative overflow-visible pt-28 pb-28 sm:pt-32 sm:pb-36">
{/* Background layer — clipped to the hero so the circuit canvas/astrolabe
don't bleed into the content below. */}
<div class="pointer-events-none absolute inset-0 overflow-hidden">
<CircuitField client:idle className="vt-sky opacity-100" />
<Astrolabe
class="absolute z-0 -right-48 -top-24 h-[34rem] w-[34rem] animate-spin-slow"
style="color: var(--color-accent); opacity:.13;"
/>
</div>
{/* Headshot — anchored to the hero section's bottom edge (the true boundary
with the next section), aligned right with the content column. Wrapped in
a centered max-width box that mirrors container-prose so the headshot's
right edge lines up with the content's right edge. */}
<div class="pointer-events-none absolute inset-x-0 bottom-0 z-50 mx-auto max-w-[72rem] px-5 lg:ml-56 lg:max-w-[calc(72rem+14rem)] sm:px-8">
<div class="pointer-events-auto ml-auto w-44 translate-y-1/2 sm:w-52 md:w-60">
<CelestialFrame rounded="2xl" emphasis="strong">
<img
src="/images/about-portrait.jpg"
alt="Greg Kilmer headshot"
class="h-full w-full object-cover"
style="aspect-ratio: 4/5;"
/>
</CelestialFrame>
</div>
</div>
<div class="container-prose relative z-10 lg:ml-56 lg:max-w-[calc(72rem+14rem)]">
<Reveal class="max-w-2xl">
<SectionHeader
tone="hero"
kicker="Professional"
icon="briefcase"
title="Resume & Portfolio"
subtitle="Clean, confident, skimmable."
/>
</Reveal>
</div>
</section>
{
/* Fixed left section rail. It is position:fixed so it renders once here
and stays pinned to the viewport's left edge while the page scrolls.
The main content column below is given lg:pl-* to clear the 14rem rail. */
}
<SectionNav />
{
/* Content column. On lg+ the fixed left rail (w-56 = 14rem) takes the left
edge, so this column is offset by that width via margin (NOT padding on a
centered max-width box — that caused asymmetric overflow / broken grids).
It keeps container-prose's max-width but lets it sit beside the rail. */
}
<div
class="container-prose flex flex-col gap-20 pt-28 pb-16 sm:gap-24 sm:pt-40 sm:pb-20 lg:ml-56 lg:max-w-[calc(72rem+14rem)]"
>
{/* ===== 1. Summary ===== */}
<section id="summary" class="scroll-mt-28 flex flex-col gap-6">
<Reveal>
<SectionHeader
kicker="01"
icon="format-list-text"
title="Professional summary"
/>
</Reveal>
<Reveal delay={80}>
<blockquote
class="border-l-2 pl-5 text-lg leading-relaxed"
style="border-color: var(--color-accent); color: var(--color-text-muted);"
>
Software developer and team lead with deep experience in cloud and
mobile application development, currently focused on SAP-adjacent
solutions at Implico Inc. Expanding into SAP Business Technology
Platform (BTP) while maintaining a broad technical foundation across
AI/ML, full-stack development, and automation. Known for bridging
complex technical requirements with practical, maintainable solutions.
Strong communicator who thrives at the intersection of engineering and
business needs.
</blockquote>
</Reveal>
<Reveal delay={120}>
<figure
class="relative overflow-hidden rounded-2xl border"
style="border-color: color-mix(in srgb, var(--color-accent) 35%, transparent);"
>
<img
src="/images/pro-workspace.jpg"
alt="Cloud development workspace"
loading="lazy"
decoding="async"
class="aspect-[21/9] w-full object-cover"
/>
<figcaption
class="absolute bottom-0 left-0 m-3 rounded-md px-3 py-1 font-mono text-[0.65rem] uppercase tracking-[0.18em] backdrop-blur-sm"
style="background: color-mix(in srgb, var(--color-ink) 60%, transparent); color: var(--color-cream);"
>
Where the day-job work happens
</figcaption>
</figure>
</Reveal>
</section>
<Reveal>
<AlchemicalDivider
class="mx-auto h-6 w-full max-w-sm"
style="color: var(--color-accent);"
/>
</Reveal>
{/* ===== 2. Experience ===== */}
<section id="experience" class="scroll-mt-28 flex flex-col gap-6">
<Reveal>
<SectionHeader
kicker="02"
icon="timeline-text"
title="Experience"
subtitle="Where I've proven it. Expand any role for the detail."
/>
</Reveal>
<Timeline entries={experience} />
</section>
{/* ===== 3. Skills ===== */}
<section id="skills" class="scroll-mt-28 flex flex-col gap-6">
<Reveal>
<SectionHeader
kicker="03"
icon="chart-bar"
title="Skills & technologies"
subtitle="What I bring to the table, organized into three tiers."
/>
</Reveal>
<SkillGrid />
</section>
{/* ===== 4. Projects ===== */}
<section id="projects" class="scroll-mt-28 flex flex-col gap-6">
<Reveal>
<SectionHeader
kicker="04"
icon="view-grid"
title="Projects"
subtitle="What I've built."
/>
</Reveal>
<div class="grid
gap-5
sm:grid-cols-2">
{
projects.map((project, i) => (
<Reveal delay={i * 80}>
<ProjectCard project={project} />
</Reveal>
))
}
</div>
</section>
{/* ===== 5. Education ===== */}
<section id="education" class="scroll-mt-28 flex flex-col gap-8">
<Reveal>
<SectionHeader
kicker="05"
icon="school"
title="Education & certifications"
subtitle="My foundation."
/>
</Reveal>
<Reveal delay={60}>
<div class="flex flex-col gap-3">
<h3 class="font-mono text-xs uppercase tracking-[0.22em]" style="color: var(--color-accent);">
Education history
</h3>
<EducationHistory />
</div>
</Reveal>
<Reveal delay={120}>
<div class="flex flex-col gap-3">
<h3 class="font-mono text-xs uppercase tracking-[0.22em]" style="color: var(--color-accent);">
Certifications
</h3>
<Certifications />
</div>
</Reveal>
</section>
{/* ===== 6. Contact ===== */}
<section id="contact" class="scroll-mt-28 flex flex-col gap-6">
<Reveal>
<SectionHeader
kicker="06"
icon="email"
title="Let's talk"
subtitle="Open to opportunities in AI/ML, mobile app, and cloud development, VR and Game Development, and technical leadership."
/>
</Reveal>
<Reveal delay={80}>
<div class="card flex flex-col gap-6">
<ul class="flex flex-col gap-4 sm:flex-row sm:flex-wrap sm:gap-8">
<li class="flex items-center gap-2">
<Icon
name="email-outline"
class="h-5 w-5"
style="color: var(--color-accent);"
/>
<span
class="font-mono text-xs uppercase tracking-[0.18em]"
style="color: var(--color-accent);"
>
<a href="mailto:Kilmer.GM@Gmail.com">Kilmer.GM@Gmail.com</a>
</span>
</li>
<li class="flex items-center gap-2">
<Icon
name="linkedin"
class="h-5 w-5"
style="color: var(--color-accent);"
/>
<span
class="font-mono text-xs uppercase tracking-[0.18em]"
style="color: var(--color-accent);"
><a
href="https://www.linkedin.com/in/gregory-kilmer-36646bb5/"
target="_blank"
rel="noopener noreferrer">LinkedIn</a
></span
>
</li>
<li class="flex items-center gap-2">
<Icon
name="github"
class="h-5 w-5"
style="color: var(--color-accent);"
/>
<span
class="font-mono text-xs uppercase tracking-[0.18em]"
style="color: var(--color-accent);"
><a
href="https://github.com/patiun"
target="_blank"
rel="noopener noreferrer">GitHub</a
></span
>
</li>
</ul>
<a href="/contact" class="btn btn-primary self-start">
Full contact page
<Icon name="arrow-right" class="h-5 w-5" />
</a>
</div>
</Reveal>
</section>
</div>
</BaseLayout>