mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
Further content updates
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
* The kicker is rendered as a monospace number/label per the spec's "Accent/
|
||||
* quotes: a monospace or display font sparingly for section numbers" guidance.
|
||||
*/
|
||||
import Icon from '@components/Icon.astro';
|
||||
import Icon from "@components/Icon.astro";
|
||||
|
||||
interface Props {
|
||||
/** Monospace kicker, e.g. "02" or "Experience". */
|
||||
@@ -19,32 +19,46 @@ interface Props {
|
||||
/** Optional mdi icon shown beside the kicker. */
|
||||
icon?: string;
|
||||
class?: string;
|
||||
align?: 'left' | 'center';
|
||||
align?: "left" | "center";
|
||||
}
|
||||
|
||||
const { kicker, title, subtitle, icon, class: className = '', align = 'left' } = Astro.props;
|
||||
const {
|
||||
kicker,
|
||||
title,
|
||||
subtitle,
|
||||
icon,
|
||||
class: className = "",
|
||||
align = "left",
|
||||
} = Astro.props;
|
||||
---
|
||||
|
||||
<div
|
||||
class:list={[
|
||||
'flex flex-col gap-3',
|
||||
align === 'center' && 'items-center text-center',
|
||||
"flex flex-col gap-3",
|
||||
align === "center" && "items-center text-center",
|
||||
className,
|
||||
]}
|
||||
>
|
||||
{kicker && (
|
||||
<span
|
||||
class="inline-flex items-center gap-2 font-mono text-xs uppercase tracking-[0.22em]"
|
||||
style="color: var(--color-accent);"
|
||||
>
|
||||
{icon && <Icon name={icon} class="h-4 w-4" />}
|
||||
{kicker}
|
||||
</span>
|
||||
)}
|
||||
{
|
||||
kicker && (
|
||||
<span
|
||||
class="inline-flex items-center gap-2 font-mono text-xs uppercase tracking-[0.22em]"
|
||||
style="color: var(--color-accent);"
|
||||
>
|
||||
{icon && <Icon name={icon} class="h-4 w-4" />}
|
||||
{kicker}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
<h2>{title}</h2>
|
||||
{subtitle && (
|
||||
<p class="max-w-2xl text-base sm:text-lg" style="color: var(--color-text-muted);">
|
||||
{subtitle}
|
||||
</p>
|
||||
)}
|
||||
{
|
||||
subtitle && (
|
||||
<p
|
||||
class="max-w-2xl text-base sm:text-lg"
|
||||
style="color: var(--color-text-muted);"
|
||||
>
|
||||
{subtitle}
|
||||
</p>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -11,58 +11,101 @@
|
||||
* treatment (decorative, not a proficiency claim) to feel like the spec's
|
||||
* "visual skill bars" suggestion without implying false metrics.
|
||||
*/
|
||||
import Icon from '@components/Icon.astro';
|
||||
import Placeholder from '@components/layout/Placeholder.astro';
|
||||
import Icon from "@components/Icon.astro";
|
||||
import Placeholder from "@components/layout/Placeholder.astro";
|
||||
|
||||
const core = [
|
||||
{ icon: 'cloud', label: 'Cloud Architecture & Development' },
|
||||
{ icon: 'cellphone-link', label: 'Mobile Application Development' },
|
||||
{ icon: 'server-network', label: 'SAP Business Technology Platform (BTP)' },
|
||||
{ icon: 'account-group', label: 'Team Leadership & Technical Mentorship' },
|
||||
{ icon: 'translate', label: 'Cross-functional Communication' },
|
||||
{ icon: "cloud", label: "Cloud Architecture & Development" },
|
||||
{ icon: "cellphone-link", label: "Mobile Application Development" },
|
||||
{ icon: "server-network", label: "SAP Business Technology Platform (BTP)" },
|
||||
{ icon: "account-group", label: "Team Leadership & Technical Mentorship" },
|
||||
{ icon: "translate", label: "Cross-functional Communication" },
|
||||
];
|
||||
|
||||
const emerging = [
|
||||
{ icon: 'chart-line', label: 'SAP BTP deep-dive (active expansion)' },
|
||||
{ icon: 'robot', label: 'AI-powered development tooling' },
|
||||
{ icon: 'cog-refresh', label: 'Advanced automation and workflow engineering' },
|
||||
{ icon: "chart-line", label: "SAP BTP deep-dive (active expansion)" },
|
||||
{ icon: "robot", label: "Cutting edge AI-powered development tooling" },
|
||||
{
|
||||
icon: "cog-refresh",
|
||||
label: "Advanced automation and workflow engineering",
|
||||
},
|
||||
];
|
||||
|
||||
// Technical stack mixes known items (from spec context) with explicit gaps.
|
||||
const techStack = [
|
||||
{ icon: 'code-braces', label: 'Languages', value: null, hint: 'Likely JavaScript/TypeScript, Python, Java, ABAP given SAP focus.' },
|
||||
{ icon: 'cube-outline', label: 'Frameworks', value: null, hint: 'Add your primary frameworks here.' },
|
||||
{ icon: 'microsoft-azure-devops', label: 'Cloud Platforms', value: 'SAP BTP, [others]', hint: 'List the cloud platforms you ship on.' },
|
||||
{ icon: 'git', label: 'Tools', value: 'Git, CI/CD pipelines, [fill in]', hint: 'Add the rest of your toolchain.' },
|
||||
{ icon: 'brain', label: 'AI/ML', value: 'Hands-on experience with machine learning frameworks and LLM integration', hint: null },
|
||||
{
|
||||
icon: "code-braces",
|
||||
label: "Languages",
|
||||
value:
|
||||
"JavaScript, TypeScript, Java, Python, C#, C, SQL, HTML, CSS, and many more.",
|
||||
hint: "JavaScript, TypeScript, Java, Python, C#, C, SQL, HTML, CSS, and many more.",
|
||||
},
|
||||
{
|
||||
icon: "cube-outline",
|
||||
label: "Frameworks",
|
||||
value: "React, Vue, Astro, Flask",
|
||||
hint: "Add your primary frameworks here.",
|
||||
},
|
||||
{
|
||||
icon: "microsoft-azure-devops",
|
||||
label: "Cloud Platforms",
|
||||
value: "SAP BTP, Google Cloud Platform, AWS",
|
||||
hint: "List the cloud platforms you ship on.",
|
||||
},
|
||||
{
|
||||
icon: "git",
|
||||
label: "Tools",
|
||||
value: "Git, Gitea, CI/CD pipelines",
|
||||
hint: "Add the rest of your toolchain.",
|
||||
},
|
||||
{
|
||||
icon: "brain",
|
||||
label: "AI/ML",
|
||||
value:
|
||||
"Hands-on experience with machine learning frameworks and LLM integration and agent harnesses like ClaudeCode, Hermes, and OpenClaw",
|
||||
hint: null,
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<div class="flex flex-col gap-8">
|
||||
<!-- Core Competencies -->
|
||||
<div class="flex flex-col gap-4">
|
||||
<h3 class="font-sans" style="color: var(--color-text);">Core Competencies</h3>
|
||||
<h3 class="font-sans" style="color: var(--color-text);">
|
||||
Core Competencies
|
||||
</h3>
|
||||
<ul class="grid gap-3 sm:grid-cols-2">
|
||||
{core.map((item, i) => (
|
||||
<li
|
||||
class="reveal card flex items-center gap-3"
|
||||
data-reveal
|
||||
style={`transition-delay:${i * 60}ms`}
|
||||
>
|
||||
<span
|
||||
class="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg"
|
||||
style="background: color-mix(in srgb, var(--color-accent) 16%, transparent); color: var(--color-accent);"
|
||||
aria-hidden="true"
|
||||
{
|
||||
core.map((item, i) => (
|
||||
<li
|
||||
class="reveal card flex items-center gap-3"
|
||||
data-reveal
|
||||
style={`transition-delay:${i * 60}ms`}
|
||||
>
|
||||
<Icon name={item.icon} class="h-5 w-5" />
|
||||
</span>
|
||||
<span class="text-sm font-medium" style="color: var(--color-text);">{item.label}</span>
|
||||
{/* Decorative bar; intentionally not a % so we never imply false metrics. */}
|
||||
<span class="ml-auto hidden h-1.5 w-16 overflow-hidden rounded-full sm:block" style="background: var(--color-border);" aria-hidden="true">
|
||||
<span class="block h-full w-full" style="background: var(--color-accent);"></span>
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
<span
|
||||
class="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg"
|
||||
style="background: color-mix(in srgb, var(--color-accent) 16%, transparent); color: var(--color-accent);"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<Icon name={item.icon} class="h-5 w-5" />
|
||||
</span>
|
||||
<span class="text-sm font-medium" style="color: var(--color-text);">
|
||||
{item.label}
|
||||
</span>
|
||||
{/* Decorative bar; intentionally not a % so we never imply false metrics. */}
|
||||
<span
|
||||
class="ml-auto hidden h-1.5 w-16 overflow-hidden rounded-full sm:block"
|
||||
style="background: var(--color-border);"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<span
|
||||
class="block h-full w-full"
|
||||
style="background: var(--color-accent);"
|
||||
/>
|
||||
</span>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -70,46 +113,67 @@ const techStack = [
|
||||
<div class="flex flex-col gap-4">
|
||||
<h3 class="font-sans" style="color: var(--color-text);">Technical Stack</h3>
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
{techStack.map((item) => (
|
||||
<div class="card flex flex-col gap-2">
|
||||
<div class="flex items-center gap-3">
|
||||
<span
|
||||
class="inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg"
|
||||
style="background: color-mix(in srgb, var(--color-secondary) 18%, transparent); color: var(--color-secondary);"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<Icon name={item.icon} class="h-5 w-5" />
|
||||
</span>
|
||||
<span class="font-sans text-sm font-semibold" style="color: var(--color-text);">{item.label}</span>
|
||||
{
|
||||
techStack.map((item) => (
|
||||
<div class="card flex flex-col gap-2">
|
||||
<div class="flex items-center gap-3">
|
||||
<span
|
||||
class="inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg"
|
||||
style="background: color-mix(in srgb, var(--color-secondary) 18%, transparent); color: var(--color-secondary);"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<Icon name={item.icon} class="h-5 w-5" />
|
||||
</span>
|
||||
<span
|
||||
class="font-sans text-sm font-semibold"
|
||||
style="color: var(--color-text);"
|
||||
>
|
||||
{item.label}
|
||||
</span>
|
||||
</div>
|
||||
{item.value ? (
|
||||
<p class="text-sm" style="color: var(--color-text-muted);">
|
||||
{item.value}
|
||||
</p>
|
||||
) : (
|
||||
<Placeholder
|
||||
label={item.label}
|
||||
hint={item.hint ?? ""}
|
||||
class="mt-1"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{item.value
|
||||
? <p class="text-sm" style="color: var(--color-text-muted);">{item.value}</p>
|
||||
: <Placeholder label={item.label} hint={item.hint ?? ''} class="mt-1" />}
|
||||
</div>
|
||||
))}
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Emerging & Exploring -->
|
||||
<div class="flex flex-col gap-4">
|
||||
<h3 class="font-sans" style="color: var(--color-text);">Emerging & Exploring</h3>
|
||||
<h3 class="font-sans" style="color: var(--color-text);">
|
||||
Emerging & Exploring
|
||||
</h3>
|
||||
<ul class="grid gap-3 sm:grid-cols-3">
|
||||
{emerging.map((item, i) => (
|
||||
<li
|
||||
class="reveal card flex items-start gap-3"
|
||||
data-reveal
|
||||
style={`transition-delay:${i * 70}ms`}
|
||||
>
|
||||
<span
|
||||
class="inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg"
|
||||
style="background: color-mix(in srgb, var(--color-accent) 16%, transparent); color: var(--color-accent);"
|
||||
aria-hidden="true"
|
||||
{
|
||||
emerging.map((item, i) => (
|
||||
<li
|
||||
class="reveal card flex items-start gap-3"
|
||||
data-reveal
|
||||
style={`transition-delay:${i * 70}ms`}
|
||||
>
|
||||
<Icon name={item.icon} class="h-5 w-5" />
|
||||
</span>
|
||||
<span class="text-sm" style="color: var(--color-text);">{item.label}</span>
|
||||
</li>
|
||||
))}
|
||||
<span
|
||||
class="inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg"
|
||||
style="background: color-mix(in srgb, var(--color-accent) 16%, transparent); color: var(--color-accent);"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<Icon name={item.icon} class="h-5 w-5" />
|
||||
</span>
|
||||
<span class="text-sm" style="color: var(--color-text);">
|
||||
{item.label}
|
||||
</span>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
# This seeds the Experience timeline. The narrative bullets below are the spec's
|
||||
# template bullets; Greg should replace the bracketed placeholders with real
|
||||
# outcomes, metrics, and dates. See docs/CONTENT.md for how to add more roles.
|
||||
company: 'Implico Inc.'
|
||||
title: 'Software Developer / Lead Developer / Team Lead'
|
||||
period: '[Greg to fill dates]'
|
||||
focus: 'Cloud and mobile application development, SAP-adjacent solutions.'
|
||||
icon: 'briefcase'
|
||||
company: "Implico Inc."
|
||||
title: "Software Developer / Lead Developer / BTP Cloud and Mobile App Lead"
|
||||
period: "Mar 2019 - Present"
|
||||
focus: "BTP, Cloud, and Mobile application development, SAP-adjacent solutions."
|
||||
icon: "briefcase"
|
||||
order: 10
|
||||
---
|
||||
|
||||
@@ -15,8 +15,9 @@ Current expansion: **SAP Business Technology Platform (BTP)**.
|
||||
|
||||
Key contributions:
|
||||
|
||||
- Lead development on [cloud/mobile project], delivering [specific outcome].
|
||||
- Architect and maintain [system/platform], supporting [X users/clients].
|
||||
- Lead development on Carrier Connect, delivering a robust 3rd party carrier logistics tool.
|
||||
- Architect and maintain multiple carrier integration systems, supporting over 1000 active users and 100 companies.
|
||||
- Collaborate with cross-functional teams to translate business requirements into technical solutions.
|
||||
- Mentor junior developers and establish coding standards and review practices.
|
||||
- Drive adoption of new technologies and frameworks within the team.
|
||||
- Maintain responsible AI usage guidelines in an every changing ecosystem.
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
# entries. To replace it: copy this file, edit the frontmatter + body, and bump
|
||||
# `placeholder: false`. Or just delete this file and add your own. See
|
||||
# docs/CONTENT.md. The schema lives in src/content.config.ts.
|
||||
title: 'Your project here'
|
||||
role: 'Lead Developer'
|
||||
tech: ['TypeScript', 'Node.js', 'SAP BTP']
|
||||
title: "PUT PROJECTS HERE"
|
||||
role: "Lead Developer"
|
||||
tech: ["TypeScript", "Node.js", "SAP BTP"]
|
||||
summary: >
|
||||
This is a placeholder so the project grid has the right layout. Replace it
|
||||
with a real 2-3 sentence description of what the project does and your
|
||||
with a real 2-3 sentence description of what the project does and my
|
||||
contribution, then add links below.
|
||||
order: 100
|
||||
placeholder: true
|
||||
|
||||
@@ -27,7 +27,7 @@ const quickFacts = [
|
||||
{ icon: "dice-multiple", text: "Running D&D & Daggerheart campaigns" },
|
||||
{
|
||||
icon: "book-open-variant",
|
||||
text: "Currently reading: Heir of Fire by Sarah J. Maas",
|
||||
text: "Currently tandem reading: Heir of Fire and Tower of Dawn by Sarah J. Maas",
|
||||
},
|
||||
{ icon: "tea", text: "Fueled by loose-leaf Chinese tea and Mountain Dew" },
|
||||
];
|
||||
@@ -64,11 +64,12 @@ const quickFacts = [
|
||||
class="border-l-2 pl-5 font-sans text-xl leading-relaxed sm:text-2xl"
|
||||
style="border-color: var(--color-accent); color: var(--color-text);"
|
||||
>
|
||||
I am Greg: a software developer based in Philadelphia who spends his
|
||||
free time running tabletop RPGs, making resin dice and custom cards, 3D
|
||||
printing anything I can, and reading his way through fantasy series at
|
||||
an alarming rate. I live with my partner Krystina, our mini dachshund
|
||||
Kashi, and more board games than any reasonable apartment should hold.
|
||||
I am Greg: a software developer and technical team lead based in
|
||||
Philadelphia who spends his free time running tabletop RPGs, making
|
||||
resin dice and custom cards, 3D printing anything I can, and reading his
|
||||
way through fantasy series at an alarming rate. I live with my partner
|
||||
Krystina, our mini dachshund Kashi, and more board games than any
|
||||
reasonable apartment should hold.
|
||||
</p>
|
||||
</Reveal>
|
||||
</section>
|
||||
|
||||
@@ -25,7 +25,7 @@ const cards = [
|
||||
{
|
||||
icon: "briefcase",
|
||||
title: "Professional",
|
||||
copy: "From SAP-adjacent cloud apps to full-stack mobile — a decade of building software that businesses actually use.",
|
||||
copy: "From SAP-adjacent cloud to full-stack mobile, a decade of building software that businesses actually use.",
|
||||
href: "/professional",
|
||||
image: "/images/pro-workspace.jpg",
|
||||
alt: "Developer workspace with code on screen",
|
||||
@@ -33,7 +33,7 @@ const cards = [
|
||||
{
|
||||
icon: "dice-multiple",
|
||||
title: "Tabletop",
|
||||
copy: "Currently running two campaigns in Foundry VTT and playtesting MCDM's Crows. Always rolling dice.",
|
||||
copy: "Currently obsessed with Spirit Island, Magic: The Gathering, and running campaigns in Foundry VTT. Always planning more; always rolling dice.",
|
||||
href: "/interests/ttrpgs",
|
||||
image: "/images/ttrpg-dice.jpg",
|
||||
alt: "Polyhedral dice on a dark surface",
|
||||
@@ -41,7 +41,7 @@ const cards = [
|
||||
{
|
||||
icon: "palette",
|
||||
title: "Making",
|
||||
copy: "Resin dice, 3D prints, and whatever else catches my eye. If it involves layers and precision, I am in.",
|
||||
copy: "Resin dice, 3D prints, TCG proxies, and whatever else catches my eye. If it involves really nice cardboard or mastering a new craft, I am in.",
|
||||
href: "/interests/making",
|
||||
image: "/images/making-resin.jpg",
|
||||
alt: "Resin crafting in progress",
|
||||
|
||||
@@ -5,31 +5,55 @@
|
||||
* Per-interest template: header + tagline, verbatim overview, platforms card
|
||||
* grid, favorite genres, currently playing placeholder, and related interests.
|
||||
*/
|
||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||
import Reveal from '@components/motion/Reveal.astro';
|
||||
import InterestHero from '@components/layout/InterestHero.astro';
|
||||
import InterestCard from '@components/cards/InterestCard.astro';
|
||||
import SectionHeader from '@components/layout/SectionHeader.astro';
|
||||
import RelatedInterests from '@components/layout/RelatedInterests.astro';
|
||||
import Placeholder from '@components/layout/Placeholder.astro';
|
||||
import Icon from '@components/Icon.astro';
|
||||
import BaseLayout from "@layouts/BaseLayout.astro";
|
||||
import Reveal from "@components/motion/Reveal.astro";
|
||||
import InterestHero from "@components/layout/InterestHero.astro";
|
||||
import InterestCard from "@components/cards/InterestCard.astro";
|
||||
import SectionHeader from "@components/layout/SectionHeader.astro";
|
||||
import RelatedInterests from "@components/layout/RelatedInterests.astro";
|
||||
import Placeholder from "@components/layout/Placeholder.astro";
|
||||
import Icon from "@components/Icon.astro";
|
||||
|
||||
const platforms = [
|
||||
{ icon: 'sony-playstation', title: 'PlayStation 5', body: 'Main console for AAA titles and exclusives.' },
|
||||
{ icon: 'nintendo-switch', title: 'Nintendo Switch / Switch 2', body: 'Handheld and docked. Nintendo first-party plus indie gems.' },
|
||||
{ icon: 'steam', title: 'Steam', body: 'The primary PC library. Strategy, RPGs, and an ever-growing backlog.' },
|
||||
{
|
||||
icon: "sony-playstation",
|
||||
title: "PlayStation 5",
|
||||
body: "Main console for AAA titles and exclusives.",
|
||||
},
|
||||
{
|
||||
icon: "nintendo-switch",
|
||||
title: "Nintendo Switch / Switch 2",
|
||||
body: "Handheld and docked. Nintendo first-party plus indie gems.",
|
||||
},
|
||||
{
|
||||
icon: "steam",
|
||||
title: "Steam",
|
||||
body: "The primary PC library. Strategy, RPGs, and an ever-growing backlog.",
|
||||
},
|
||||
];
|
||||
|
||||
const genres = [
|
||||
'RPGs (both Western and JRPG)',
|
||||
'Strategy and tactics',
|
||||
'Open-world exploration',
|
||||
'Indie darlings',
|
||||
"RPGs (both Western and JRPG)",
|
||||
"Strategy and tactics",
|
||||
"Building and crafting",
|
||||
"Automation",
|
||||
"Open-world exploration",
|
||||
"Indie darlings",
|
||||
];
|
||||
|
||||
const related = [
|
||||
{ href: '/interests/pokemon', title: 'Pokémon', icon: 'pokeball', blurb: 'Nintendo console overlap and a lifelong obsession.' },
|
||||
{ href: '/interests/ttrpgs', title: 'TTRPGs & Tabletop', icon: 'dice-multiple', blurb: 'Digital RPGs as another expression of the same impulse.' },
|
||||
{
|
||||
href: "/interests/pokemon",
|
||||
title: "Pokémon",
|
||||
icon: "pokeball",
|
||||
blurb: "Nintendo console overlap and a lifelong obsession.",
|
||||
},
|
||||
{
|
||||
href: "/interests/ttrpgs",
|
||||
title: "TTRPGs & Tabletop",
|
||||
icon: "dice-multiple",
|
||||
blurb: "Digital RPGs as another expression of the same impulse.",
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
@@ -48,48 +72,92 @@ const related = [
|
||||
|
||||
<div class="container-prose flex flex-col gap-20 py-12 sm:py-16">
|
||||
{/* Overview */}
|
||||
<section class="flex flex-col gap-5 text-lg leading-relaxed" style="color: var(--color-text-muted);">
|
||||
<Reveal><p>Gaming is my other constant. I span console generations with a PlayStation 5, Nintendo Switch 2, and a Steam library that has gotten politely out of hand. I'm particularly drawn to RPGs, strategy games, and anything with a deeply layered world. If a game has lore compendiums, I'm reading them.</p></Reveal>
|
||||
<section
|
||||
class="flex flex-col gap-5 text-lg leading-relaxed"
|
||||
style="color: var(--color-text-muted);"
|
||||
>
|
||||
<Reveal
|
||||
><p>
|
||||
Gaming is my other constant. I span console generations with a
|
||||
PlayStation 5, Nintendo Switch 2, and a Steam library that has gotten
|
||||
politely out of hand. I'm particularly drawn to RPGs, strategy games,
|
||||
and anything with a deeply layered world. If a game has lore
|
||||
compendiums, I'm reading them.
|
||||
</p></Reveal
|
||||
>
|
||||
</section>
|
||||
|
||||
{/* Platforms */}
|
||||
<section class="flex flex-col gap-6">
|
||||
<Reveal><SectionHeader kicker="Platforms" icon="gamepad-variant" title="Where I play" /></Reveal>
|
||||
<Reveal
|
||||
><SectionHeader
|
||||
kicker="Platforms"
|
||||
icon="gamepad-variant"
|
||||
title="Where I play"
|
||||
/></Reveal
|
||||
>
|
||||
<div class="grid gap-5 sm:grid-cols-3">
|
||||
{platforms.map((p, i) => (
|
||||
<Reveal delay={i * 80}>
|
||||
<InterestCard icon={p.icon} title={p.title}>{p.body}</InterestCard>
|
||||
</Reveal>
|
||||
))}
|
||||
{
|
||||
platforms.map((p, i) => (
|
||||
<Reveal delay={i * 80}>
|
||||
<InterestCard icon={p.icon} title={p.title}>
|
||||
{p.body}
|
||||
</InterestCard>
|
||||
</Reveal>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Genres */}
|
||||
<section class="flex flex-col gap-5">
|
||||
<Reveal><SectionHeader kicker="Tastes" icon="shape" title="Favorite genres" /></Reveal>
|
||||
<Reveal
|
||||
><SectionHeader
|
||||
kicker="Tastes"
|
||||
icon="shape"
|
||||
title="Favorite genres"
|
||||
/></Reveal
|
||||
>
|
||||
<Reveal delay={80}>
|
||||
<ul class="flex flex-wrap gap-3">
|
||||
{genres.map((g) => (
|
||||
<li class="pill text-sm">
|
||||
<Icon name="star-four-points" class="h-3.5 w-3.5" />
|
||||
{g}
|
||||
</li>
|
||||
))}
|
||||
{
|
||||
genres.map((g) => (
|
||||
<li class="pill text-sm">
|
||||
<Icon name="star-four-points" class="h-3.5 w-3.5" />
|
||||
{g}
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</Reveal>
|
||||
</section>
|
||||
|
||||
{/* Currently */}
|
||||
<section class="flex flex-col gap-6">
|
||||
<Reveal><SectionHeader kicker="Currently" icon="calendar-clock" title="Now playing" /></Reveal>
|
||||
<Reveal
|
||||
><SectionHeader
|
||||
kicker="Currently"
|
||||
icon="calendar-clock"
|
||||
title="Now playing"
|
||||
/></Reveal
|
||||
>
|
||||
<div class="grid gap-4 sm:grid-cols-[1fr_1fr]">
|
||||
<figure
|
||||
class="relative overflow-hidden rounded-xl border"
|
||||
style="border-color: color-mix(in srgb, var(--color-accent) 35%, transparent);"
|
||||
>
|
||||
<img src="/images/gaming-setup.jpg" alt="Gaming setup" loading="lazy" decoding="async" class="aspect-[4/3] w-full object-cover" />
|
||||
<img
|
||||
src="/images/gaming-setup.jpg"
|
||||
alt="Gaming setup"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
class="aspect-[4/3] w-full object-cover"
|
||||
/>
|
||||
</figure>
|
||||
<Placeholder label="Currently playing" hint="Add the games you are actively playing right now." />
|
||||
<Placeholder
|
||||
label="Currently playing"
|
||||
hint="Add the games you are actively playing right now."
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
+113
-72
@@ -6,51 +6,56 @@
|
||||
* sub-page, using the spec's taglines. Sets surface="interest" so the whole
|
||||
* page reads warm (cream/amber) regardless of the global light/dark toggle.
|
||||
*/
|
||||
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 AnimatedBackground from '@components/hero/AnimatedBackground.tsx';
|
||||
import SacredGeometry from '@components/mystic/SacredGeometry.astro';
|
||||
import ConstellationField from '@components/mystic/ConstellationField.tsx';
|
||||
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 AnimatedBackground from "@components/hero/AnimatedBackground.tsx";
|
||||
import SacredGeometry from "@components/mystic/SacredGeometry.astro";
|
||||
import ConstellationField from "@components/mystic/ConstellationField.tsx";
|
||||
|
||||
const interests = [
|
||||
{
|
||||
href: '/interests/ttrpgs',
|
||||
icon: 'dice-multiple',
|
||||
title: 'TTRPGs & Tabletop',
|
||||
tagline: 'Three campaigns, two systems, one rolling table.',
|
||||
blurb: 'Long-running D&D and Daggerheart campaigns on Foundry VTT, plus the Crows playtest. Worldbuilding, NPC relationships, and player-driven narrative.',
|
||||
image: '/images/ttrpg-dice.jpg',
|
||||
alt: 'Polyhedral dice on a dark surface',
|
||||
href: "/interests/ttrpgs",
|
||||
icon: "dice-multiple",
|
||||
title: "TTRPGs & Tabletop",
|
||||
tagline: "Have dice, will roll.",
|
||||
blurb:
|
||||
"Card Games, Board Games, and Long-running D&D and Daggerheart campaigns on Foundry VTT. Worldbuilding, NPC relationships, and player-driven narrative.",
|
||||
image: "/images/ttrpg-dice.jpg",
|
||||
alt: "Boardgame Shelf",
|
||||
},
|
||||
{
|
||||
href: '/interests/gaming',
|
||||
icon: 'sony-playstation',
|
||||
title: 'Gaming',
|
||||
tagline: 'If it has a screen or a controller, I have probably played it.',
|
||||
blurb: 'PlayStation 5, Nintendo Switch 2, and a politely out-of-hand Steam library. RPGs, strategy, and anything with a deeply layered world.',
|
||||
image: '/images/gaming-setup.jpg',
|
||||
alt: 'Gaming setup with controller',
|
||||
href: "/interests/gaming",
|
||||
icon: "sony-playstation",
|
||||
title: "Gaming",
|
||||
tagline: "We do not talk about my backlog.",
|
||||
blurb:
|
||||
"PlayStation 5, Nintendo Switch 2, and a politely out-of-hand Steam library. RPGs, strategy, and anything with a deeply layered world.",
|
||||
image: "/images/gaming-setup.jpg",
|
||||
alt: "Gaming setup desk",
|
||||
},
|
||||
{
|
||||
href: '/interests/reading',
|
||||
icon: 'book-open-page-variant',
|
||||
title: 'Reading & Media',
|
||||
tagline: 'Perpetually three books ahead of my to-read list.',
|
||||
blurb: 'The Cosmere, Dune, the Pendergast saga, and Throne of Glass. Plus light novels, manga, manhwa, anime, and film.',
|
||||
image: '/images/fantasy-books.jpg',
|
||||
alt: 'Fantasy bookshelf',
|
||||
href: "/interests/reading",
|
||||
icon: "book-open-page-variant",
|
||||
title: "Reading & Media",
|
||||
tagline: "Perpetually three books ahead of my to-read list.",
|
||||
blurb:
|
||||
"The Cosmere, Dune, the Pendergast saga, and Throne of Glass. Plus light novels, manga, manhwa, anime, and film.",
|
||||
image: "/images/fantasy-books.jpg",
|
||||
alt: "Fantasy bookshelf",
|
||||
},
|
||||
{
|
||||
href: '/interests/making',
|
||||
icon: 'palette',
|
||||
title: 'Making & Creating',
|
||||
tagline: 'If it involves layers and precision, I am in.',
|
||||
blurb: 'Resin dice in a pressure pot, miniatures and terrain on the Elegoo Mars 4 and Bambu Labs P1S. Much of it ends up on the virtual table.',
|
||||
image: '/images/making-resin.jpg',
|
||||
alt: 'Resin crafting in progress',
|
||||
},
|
||||
href: "/interests/making",
|
||||
icon: "palette",
|
||||
title: "Making & Creating",
|
||||
tagline:
|
||||
"If it involves really nice cardboard or mastering a new craft, I am in.",
|
||||
blurb:
|
||||
"Resin dice in a pressure pot, fun and functional prints on the P1s, custom TCG proxies and decks. Passion and utility.",
|
||||
image: "/images/making-resin.jpg",
|
||||
alt: "Polyhedral dice on a dark bag",
|
||||
} /*
|
||||
{
|
||||
href: '/interests/pokemon',
|
||||
icon: 'pokeball',
|
||||
@@ -59,7 +64,7 @@ const interests = [
|
||||
blurb: 'A lifelong obsession from Red and Blue to modern competitive. Steel/Psychic, beautiful design, absolutely devastating in battle.',
|
||||
image: '/images/pokemon-cards.jpg',
|
||||
alt: 'Trading card collection',
|
||||
},
|
||||
},*/,
|
||||
];
|
||||
---
|
||||
|
||||
@@ -70,9 +75,13 @@ const interests = [
|
||||
>
|
||||
<!-- Hero -->
|
||||
<section class="relative min-h-[60vh] overflow-hidden pt-28 sm:pt-32">
|
||||
{/* Full animated Milky Way field + stars, matching the Home hero treatment. */}
|
||||
{
|
||||
/* Full animated Milky Way field + stars, matching the Home hero treatment. */
|
||||
}
|
||||
<AnimatedBackground client:idle transitionName="sky" />
|
||||
<div class="container-prose relative z-10 flex flex-col items-start gap-6 py-16">
|
||||
<div
|
||||
class="container-prose relative z-10 flex flex-col items-start gap-6 py-16"
|
||||
>
|
||||
<Reveal>
|
||||
<SectionHeader
|
||||
kicker="The personal wing"
|
||||
@@ -94,38 +103,59 @@ const interests = [
|
||||
/>
|
||||
<div class="container-prose relative z-10">
|
||||
<div class="grid gap-5 md:grid-cols-2 lg:grid-cols-3">
|
||||
{interests.map((item, i) => (
|
||||
<Reveal delay={i * 80}>
|
||||
<a href={item.href} class="card card-interactive group flex h-full flex-col gap-4 overflow-hidden p-0">
|
||||
<div class="aspect-[16/10] w-full overflow-hidden">
|
||||
<img
|
||||
src={item.image}
|
||||
alt={item.alt}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
class="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-3 px-5 pb-5">
|
||||
<div class="flex items-center justify-between">
|
||||
<span
|
||||
class="inline-flex h-12 w-12 items-center justify-center rounded-xl"
|
||||
style="background: color-mix(in srgb, var(--color-accent) 16%, transparent); color: var(--color-accent);"
|
||||
aria-hidden="true"
|
||||
{
|
||||
interests.map((item, i) => (
|
||||
<Reveal delay={i * 80}>
|
||||
<a
|
||||
href={item.href}
|
||||
class="card card-interactive group flex h-full flex-col gap-4 overflow-hidden p-0"
|
||||
>
|
||||
<div class="aspect-[16/10] w-full overflow-hidden">
|
||||
<img
|
||||
src={item.image}
|
||||
alt={item.alt}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
class="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-3 px-5 pb-5">
|
||||
<div class="flex items-center justify-between">
|
||||
<span
|
||||
class="inline-flex h-12 w-12 items-center justify-center rounded-xl"
|
||||
style="background: color-mix(in srgb, var(--color-accent) 16%, transparent); color: var(--color-accent);"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<Icon name={item.icon} class="h-6 w-6" />
|
||||
</span>
|
||||
<Icon
|
||||
name="arrow-right"
|
||||
class="h-5 w-5 transition-transform group-hover:translate-x-1"
|
||||
style="color: var(--color-accent);"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<h3 class="font-sans" style="color: var(--color-text);">
|
||||
{item.title}
|
||||
</h3>
|
||||
<p
|
||||
class="font-sans text-sm italic"
|
||||
style="color: var(--color-secondary);"
|
||||
>
|
||||
{item.tagline}
|
||||
</p>
|
||||
</div>
|
||||
<p
|
||||
class="grow text-sm leading-relaxed"
|
||||
style="color: var(--color-text-muted);"
|
||||
>
|
||||
<Icon name={item.icon} class="h-6 w-6" />
|
||||
</span>
|
||||
<Icon name="arrow-right" class="h-5 w-5 transition-transform group-hover:translate-x-1" style="color: var(--color-accent);" />
|
||||
{item.blurb}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<h3 class="font-sans" style="color: var(--color-text);">{item.title}</h3>
|
||||
<p class="font-sans text-sm italic" style="color: var(--color-secondary);">{item.tagline}</p>
|
||||
</div>
|
||||
<p class="grow text-sm leading-relaxed" style="color: var(--color-text-muted);">{item.blurb}</p>
|
||||
</div>
|
||||
</a>
|
||||
</Reveal>
|
||||
))}
|
||||
</a>
|
||||
</Reveal>
|
||||
))
|
||||
}
|
||||
|
||||
{/* Cross-link back to professional wing */}
|
||||
<Reveal delay={interests.length * 80}>
|
||||
@@ -134,9 +164,20 @@ const interests = [
|
||||
class="card card-interactive group flex h-full flex-col justify-center gap-2 border-dashed p-5 text-center"
|
||||
style="border-color: color-mix(in srgb, var(--color-accent) 40%, transparent);"
|
||||
>
|
||||
<Icon name="briefcase" class="mx-auto h-7 w-7" style="color: var(--color-accent);" />
|
||||
<p class="font-sans font-semibold" style="color: var(--color-text);">The other wing</p>
|
||||
<p class="text-sm" style="color: var(--color-text-muted);">See where curiosity meets the day job.</p>
|
||||
<Icon
|
||||
name="briefcase"
|
||||
class="mx-auto h-7 w-7"
|
||||
style="color: var(--color-accent);"
|
||||
/>
|
||||
<p
|
||||
class="font-sans font-semibold"
|
||||
style="color: var(--color-text);"
|
||||
>
|
||||
The other wing
|
||||
</p>
|
||||
<p class="text-sm" style="color: var(--color-text-muted);">
|
||||
See where curiosity meets the day job.
|
||||
</p>
|
||||
</a>
|
||||
</Reveal>
|
||||
</div>
|
||||
|
||||
@@ -55,8 +55,8 @@ const projects = (await getCollection("projects")).sort(
|
||||
<SectionHeader
|
||||
kicker="Professional"
|
||||
icon="briefcase"
|
||||
title="Resume & portfolio"
|
||||
subtitle="Clean, confident, skimmable. Browsable here, screenshot-able for a recruiter, printable if needed."
|
||||
title="Resume & Portfolio"
|
||||
subtitle="Clean, confident, skimmable."
|
||||
/>
|
||||
</Reveal>
|
||||
<Reveal delay={80}>
|
||||
@@ -152,7 +152,7 @@ const projects = (await getCollection("projects")).sort(
|
||||
kicker="04"
|
||||
icon="view-grid"
|
||||
title="Projects"
|
||||
subtitle="What I've built. Replace the placeholder with 3-6 of your own."
|
||||
subtitle="What I've built. [TODO: Replace the placeholder with 3-6 of my projects]"
|
||||
/>
|
||||
</Reveal>
|
||||
<div class="grid gap-5 sm:grid-cols-2">
|
||||
@@ -164,10 +164,6 @@ const projects = (await getCollection("projects")).sort(
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<Placeholder
|
||||
label="Add 3-6 projects"
|
||||
hint="Drop a new markdown file in src/content/projects/ for each notable project. See docs/CONTENT.md."
|
||||
/>
|
||||
</section>
|
||||
|
||||
{/* ===== 5. Education ===== */}
|
||||
|
||||
Reference in New Issue
Block a user