mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
Copy update and some formatting
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 641 KiB After Width: | Height: | Size: 802 KiB |
@@ -9,7 +9,7 @@
|
|||||||
* Left -> Professional (polished tone)
|
* Left -> Professional (polished tone)
|
||||||
* Right -> Interests (warm tone)
|
* Right -> Interests (warm tone)
|
||||||
*/
|
*/
|
||||||
import Icon from '@components/Icon.astro';
|
import Icon from "@components/Icon.astro";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/** Optional override copy for each side. Defaults to spec phrasing. */
|
/** Optional override copy for each side. Defaults to spec phrasing. */
|
||||||
@@ -20,10 +20,10 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
leftHref = '/professional',
|
leftHref = "/professional",
|
||||||
rightHref = '/interests',
|
rightHref = "/interests",
|
||||||
leftText = 'See where I apply that curiosity professionally',
|
leftText = "See where I apply that curiosity professionally",
|
||||||
rightText = 'See where it takes me outside of work',
|
rightText = "See where it takes me outside of work",
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -32,15 +32,25 @@ const {
|
|||||||
href={leftHref}
|
href={leftHref}
|
||||||
class="card card-interactive group flex items-center justify-between gap-4"
|
class="card card-interactive group flex items-center justify-between gap-4"
|
||||||
>
|
>
|
||||||
|
<Icon
|
||||||
|
name="arrow-left"
|
||||||
|
class="h-6 w-6 shrink-0 transition-transform group-hover:translate-x-1"
|
||||||
|
style="color: var(--color-accent);"
|
||||||
|
/>
|
||||||
<span class="flex flex-col gap-1">
|
<span class="flex flex-col gap-1">
|
||||||
<span class="font-mono text-xs uppercase tracking-[0.18em]" style="color: var(--color-text-subtle);">
|
<span
|
||||||
|
class="font-mono text-xs uppercase tracking-[0.18em]"
|
||||||
|
style="color: var(--color-text-subtle); text-align:right;"
|
||||||
|
>
|
||||||
The professional wing
|
The professional wing
|
||||||
</span>
|
</span>
|
||||||
<span class="font-sans text-lg font-semibold" style="color: var(--color-text);">
|
<span
|
||||||
|
class="font-sans text-lg font-semibold"
|
||||||
|
style="color: var(--color-text);"
|
||||||
|
>
|
||||||
{leftText}
|
{leftText}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<Icon name="arrow-right" class="h-6 w-6 shrink-0 transition-transform group-hover:translate-x-1" style="color: var(--color-accent);" />
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
@@ -48,13 +58,23 @@ const {
|
|||||||
class="card card-interactive group flex items-center justify-between gap-4"
|
class="card card-interactive group flex items-center justify-between gap-4"
|
||||||
>
|
>
|
||||||
<span class="flex flex-col gap-1">
|
<span class="flex flex-col gap-1">
|
||||||
<span class="font-mono text-xs uppercase tracking-[0.18em]" style="color: var(--color-text-subtle);">
|
<span
|
||||||
|
class="font-mono text-xs uppercase tracking-[0.18em]"
|
||||||
|
style="color: var(--color-text-subtle);"
|
||||||
|
>
|
||||||
The personal wing
|
The personal wing
|
||||||
</span>
|
</span>
|
||||||
<span class="font-sans text-lg font-semibold" style="color: var(--color-text);">
|
<span
|
||||||
|
class="font-sans text-lg font-semibold"
|
||||||
|
style="color: var(--color-text);"
|
||||||
|
>
|
||||||
{rightText}
|
{rightText}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<Icon name="arrow-right" class="h-6 w-6 shrink-0 transition-transform group-hover:translate-x-1" style="color: var(--color-accent);" />
|
<Icon
|
||||||
|
name="arrow-right"
|
||||||
|
class="h-6 w-6 shrink-0 transition-transform group-hover:translate-x-1"
|
||||||
|
style="color: var(--color-accent);"
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,67 +17,65 @@
|
|||||||
* </CelestialFrame>
|
* </CelestialFrame>
|
||||||
* <CelestialFrame rounded="none"> ... </CelestialFrame>
|
* <CelestialFrame rounded="none"> ... </CelestialFrame>
|
||||||
*/
|
*/
|
||||||
import StarBurst from './StarBurst.astro';
|
import StarBurst from "./StarBurst.astro";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
class?: string;
|
class?: string;
|
||||||
/** Corner rounding. */
|
/** Corner rounding. */
|
||||||
rounded?: 'lg' | 'xl' | '2xl' | 'none';
|
rounded?: "lg" | "xl" | "2xl" | "none";
|
||||||
/** Stroke emphasis on the frame border. */
|
/** Stroke emphasis on the frame border. */
|
||||||
emphasis?: 'subtle' | 'strong';
|
emphasis?: "subtle" | "strong";
|
||||||
}
|
}
|
||||||
const {
|
const {
|
||||||
class: className = '',
|
class: className = "",
|
||||||
rounded = '2xl',
|
rounded = "2xl",
|
||||||
emphasis = 'subtle',
|
emphasis = "subtle",
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
|
||||||
const radius = {
|
const radius = {
|
||||||
none: 'rounded-none',
|
none: "rounded-none",
|
||||||
lg: 'rounded-lg',
|
lg: "rounded-lg",
|
||||||
xl: 'rounded-xl',
|
xl: "rounded-xl",
|
||||||
'2xl': 'rounded-2xl',
|
"2xl": "rounded-2xl",
|
||||||
}[rounded];
|
}[rounded];
|
||||||
|
|
||||||
const borderStyle =
|
const borderStyle = emphasis === "strong" ? "border-2" : "border";
|
||||||
emphasis === 'strong'
|
|
||||||
? 'border-2'
|
|
||||||
: 'border';
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<figure
|
<figure
|
||||||
class:list={['relative', radius, borderStyle, className]}
|
class:list={["relative", radius, borderStyle, className]}
|
||||||
style="border-color: color-mix(in srgb, var(--color-accent) 45%, transparent);"
|
style="border-color: color-mix(in srgb, var(--color-accent) 75%, transparent); border-width: 3px;"
|
||||||
>
|
>
|
||||||
{/* Faint sacred-geometry tint behind the image. */}
|
{/* Faint sacred-geometry tint behind the image. */}
|
||||||
<div
|
<div
|
||||||
class:list={['absolute inset-0', radius]}
|
class:list={["absolute inset-0", radius]}
|
||||||
style="background: color-mix(in srgb, var(--color-violet, var(--color-accent)) 14%, var(--color-surface-sunken));"
|
style="background: color-mix(in srgb, var(--color-violet, var(--color-accent)) 14%, var(--color-surface-sunken));"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* The media itself, clipped to the frame. */}
|
{/* The media itself, clipped to the frame. */}
|
||||||
<div class:list={['relative overflow-hidden', radius]}>
|
<div class:list={["relative overflow-hidden", radius]}>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Corner star-burst flourishes (sit on the border corners). */}
|
{/* Corner star-burst flourishes (sit on the border corners). */}
|
||||||
<StarBurst
|
<StarBurst
|
||||||
class="pointer-events-none absolute -left-2 -top-2 h-5 w-5 drop-shadow-[0_0_6px_color-mix(in_srgb,var(--color-accent)_60%,transparent)]"
|
class="pointer-events-none absolute -left-3 -top-3 h-6 w-6 drop-shadow-[0_0_6px_color-mix(in_srgb,var(--color-accent)_60%,transparent)]"
|
||||||
style="color: var(--color-accent);"
|
style="color: var(--color-accent);"
|
||||||
/>
|
/>
|
||||||
<StarBurst
|
<StarBurst
|
||||||
class="pointer-events-none absolute -bottom-2 -right-2 h-5 w-5 drop-shadow-[0_0_6px_color-mix(in_srgb,var(--color-accent)_60%,transparent)]"
|
class="pointer-events-none absolute -bottom-5 -right-5 h-7 w-7 drop-shadow-[0_0_6px_color-mix(in_srgb,var(--color-accent)_60%,transparent)]"
|
||||||
style="color: var(--color-accent);"
|
style="color: var(--color-accent);"
|
||||||
/>
|
/>
|
||||||
<StarBurst
|
<StarBurst
|
||||||
variant="outline"
|
variant="outline"
|
||||||
class="pointer-events-none absolute -right-1 -top-1 h-3 w-3"
|
class="pointer-events-none absolute -right-2 -top-2 h-3 w-3"
|
||||||
style="color: var(--color-accent); opacity:.7;"
|
style="color: var(--color-accent); opacity:.7;"
|
||||||
/>
|
/>
|
||||||
<StarBurst
|
<StarBurst
|
||||||
variant="outline"
|
variant="outline"
|
||||||
class="pointer-events-none absolute -left-1 -bottom-1 h-3 w-3"
|
class="pointer-events-none absolute -left-2 -bottom-2 h-3 w-3"
|
||||||
style="color: var(--color-accent); opacity:.7;"
|
style="color: var(--color-accent); opacity:.7;"
|
||||||
/>
|
/>
|
||||||
</figure>
|
</figure>
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
* <CelestialImage src="/images/hero.jpg" alt="Greg at his desk" aspect="4/3" />
|
* <CelestialImage src="/images/hero.jpg" alt="Greg at his desk" aspect="4/3" />
|
||||||
* <CelestialImage src="/images/about.jpg" alt="Greg" aspect="3/4" rounded="xl" />
|
* <CelestialImage src="/images/about.jpg" alt="Greg" aspect="3/4" rounded="xl" />
|
||||||
*/
|
*/
|
||||||
import CelestialFrame from './CelestialFrame.astro';
|
import CelestialFrame from "./CelestialFrame.astro";
|
||||||
import StarField from './StarField.astro';
|
import StarField from "./StarField.astro";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
src?: string;
|
src?: string;
|
||||||
@@ -23,8 +23,8 @@ interface Props {
|
|||||||
/** Aspect ratio, e.g. "4/3", "3/4", "16/9". */
|
/** Aspect ratio, e.g. "4/3", "3/4", "16/9". */
|
||||||
aspect?: string;
|
aspect?: string;
|
||||||
/** Image fit. object-cover by default. */
|
/** Image fit. object-cover by default. */
|
||||||
fit?: 'cover' | 'contain';
|
fit?: "cover" | "contain";
|
||||||
rounded?: 'lg' | 'xl' | '2xl' | 'none';
|
rounded?: "lg" | "xl" | "2xl" | "none";
|
||||||
class?: string;
|
class?: string;
|
||||||
/** When true, render only the frame + placeholder (no <img>). */
|
/** When true, render only the frame + placeholder (no <img>). */
|
||||||
placeholder?: boolean;
|
placeholder?: boolean;
|
||||||
@@ -33,19 +33,21 @@ interface Props {
|
|||||||
const {
|
const {
|
||||||
src,
|
src,
|
||||||
alt,
|
alt,
|
||||||
aspect = '4/3',
|
aspect = "4/3",
|
||||||
fit = 'cover',
|
fit = "cover",
|
||||||
rounded = '2xl',
|
rounded = "2xl",
|
||||||
class: className = '',
|
class: className = "",
|
||||||
placeholder = false,
|
placeholder = false,
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
|
||||||
const showPlaceholder = placeholder || !src;
|
const showPlaceholder = placeholder || !src;
|
||||||
const objectFit = fit === 'contain' ? 'object-contain' : 'object-cover';
|
const objectFit = fit === "contain" ? "object-contain" : "object-cover";
|
||||||
---
|
---
|
||||||
<CelestialFrame rounded={rounded} class:list={['w-full', className]}>
|
|
||||||
|
<CelestialFrame rounded={rounded} class:list={["w-full", className]}>
|
||||||
<div class="w-full" style={`aspect-ratio: ${aspect};`}>
|
<div class="w-full" style={`aspect-ratio: ${aspect};`}>
|
||||||
{showPlaceholder ? (
|
{
|
||||||
|
showPlaceholder ? (
|
||||||
// Themed SVG placeholder: starfield + moon glyph over the surface tone.
|
// Themed SVG placeholder: starfield + moon glyph over the surface tone.
|
||||||
<div
|
<div
|
||||||
class="relative h-full w-full"
|
class="relative h-full w-full"
|
||||||
@@ -70,7 +72,11 @@ const objectFit = fit === 'contain' ? 'object-contain' : 'object-cover';
|
|||||||
>
|
>
|
||||||
{/* Crescent moon + small star as the placeholder glyph. */}
|
{/* Crescent moon + small star as the placeholder glyph. */}
|
||||||
<path d="M16 12a7 7 0 1 1-6.4-7 5.5 5.5 0 0 0 0 14A7 7 0 0 0 16 12z" />
|
<path d="M16 12a7 7 0 1 1-6.4-7 5.5 5.5 0 0 0 0 14A7 7 0 0 0 16 12z" />
|
||||||
<path d="M18.5 5.5c.3 1.8 1 3.1 2.5 3.5-1.5.3-2.2 1.7-2.5 3.5-.3-1.8-1-3.2-2.5-3.5 1.5-.4 2.2-1.7 2.5-3.5z" fill="currentColor" stroke="none" />
|
<path
|
||||||
|
d="M18.5 5.5c.3 1.8 1 3.1 2.5 3.5-1.5.3-2.2 1.7-2.5 3.5-.3-1.8-1-3.2-2.5-3.5 1.5-.4 2.2-1.7 2.5-3.5z"
|
||||||
|
fill="currentColor"
|
||||||
|
stroke="none"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -86,8 +92,9 @@ const objectFit = fit === 'contain' ? 'object-contain' : 'object-cover';
|
|||||||
alt={alt}
|
alt={alt}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
class:list={['h-full w-full', objectFit]}
|
class:list={["h-full w-full", objectFit]}
|
||||||
/>
|
/>
|
||||||
)}
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</CelestialFrame>
|
</CelestialFrame>
|
||||||
|
|||||||
+6
-6
@@ -63,22 +63,22 @@ export const allNavItems: NavItem[] = navGroups.flatMap((g) => g.items);
|
|||||||
export const socials = {
|
export const socials = {
|
||||||
github: {
|
github: {
|
||||||
label: 'GitHub',
|
label: 'GitHub',
|
||||||
handle: '[Greg to fill]',
|
handle: 'Patiun',
|
||||||
href: 'https://github.com/',
|
href: 'https://github.com/patiun',
|
||||||
icon: 'github',
|
icon: 'github',
|
||||||
},
|
},
|
||||||
linkedin: {
|
linkedin: {
|
||||||
label: 'LinkedIn',
|
label: 'LinkedIn',
|
||||||
handle: '[Greg to fill]',
|
handle: 'Gregory Kilmer',
|
||||||
href: 'https://www.linkedin.com/',
|
href: 'https://www.linkedin.com/in/gregory-kilmer-36646bb5/',
|
||||||
icon: 'linkedin',
|
icon: 'linkedin',
|
||||||
},
|
},
|
||||||
discord: {
|
/*discord: {
|
||||||
label: 'Discord',
|
label: 'Discord',
|
||||||
handle: '[Greg to fill]',
|
handle: '[Greg to fill]',
|
||||||
href: '#',
|
href: '#',
|
||||||
icon: 'discord',
|
icon: 'discord',
|
||||||
},
|
},*/
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
/** Spec footer microcopy. */
|
/** Spec footer microcopy. */
|
||||||
|
|||||||
+66
-37
@@ -7,23 +7,29 @@
|
|||||||
* quick facts (spec emojis mapped to mdi icons). Ends with the SplitTransition
|
* quick facts (spec emojis mapped to mdi icons). Ends with the SplitTransition
|
||||||
* fork into Professional / Interests.
|
* fork into Professional / Interests.
|
||||||
*/
|
*/
|
||||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
import BaseLayout from "@layouts/BaseLayout.astro";
|
||||||
import Reveal from '@components/motion/Reveal.astro';
|
import Reveal from "@components/motion/Reveal.astro";
|
||||||
import Icon from '@components/Icon.astro';
|
import Icon from "@components/Icon.astro";
|
||||||
import SectionHeader from '@components/layout/SectionHeader.astro';
|
import SectionHeader from "@components/layout/SectionHeader.astro";
|
||||||
import SplitTransition from '@components/layout/SplitTransition.astro';
|
import SplitTransition from "@components/layout/SplitTransition.astro";
|
||||||
import CelestialImage from '@components/mystic/CelestialImage.astro';
|
import CelestialImage from "@components/mystic/CelestialImage.astro";
|
||||||
import AlchemicalDivider from '@components/mystic/AlchemicalDivider.astro';
|
import AlchemicalDivider from "@components/mystic/AlchemicalDivider.astro";
|
||||||
import ConstellationField from '@components/mystic/ConstellationField.tsx';
|
import ConstellationField from "@components/mystic/ConstellationField.tsx";
|
||||||
|
|
||||||
// Spec "Quick Facts", emojis -> mdi icons.
|
// Spec "Quick Facts", emojis -> mdi icons.
|
||||||
const quickFacts = [
|
const quickFacts = [
|
||||||
{ icon: 'map-marker', text: 'Philadelphia, PA' },
|
{ icon: "map-marker", text: "Philadelphia, PA" },
|
||||||
{ icon: 'briefcase', text: 'Software Developer at Implico Inc.' },
|
{
|
||||||
{ icon: 'dog', text: 'Dog dad to Kashi the mini dachshund' },
|
icon: "briefcase",
|
||||||
{ icon: 'dice-multiple', text: 'Running D&D & Daggerheart campaigns' },
|
text: "BTP, Cloud, and Mobile App Lead at Implico Inc.",
|
||||||
{ icon: 'book-open-variant', text: 'Currently reading: Heir of Fire by Sarah J. Maas' },
|
},
|
||||||
{ icon: 'tea', text: 'Fueled by loose-leaf Chinese tea and Mountain Dew' },
|
{ icon: "dog", text: "Dog dad to Kashi the mini dachshund" },
|
||||||
|
{ icon: "dice-multiple", text: "Running D&D & Daggerheart campaigns" },
|
||||||
|
{
|
||||||
|
icon: "book-open-variant",
|
||||||
|
text: "Currently reading: Heir of Fire by Sarah J. Maas",
|
||||||
|
},
|
||||||
|
{ icon: "tea", text: "Fueled by loose-leaf Chinese tea and Mountain Dew" },
|
||||||
];
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -33,7 +39,12 @@ const quickFacts = [
|
|||||||
>
|
>
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<section class="relative overflow-hidden pb-10 pt-28 sm:pt-32">
|
<section class="relative overflow-hidden pb-10 pt-28 sm:pt-32">
|
||||||
<ConstellationField client:idle className="opacity-40" tint="violet" transitionName="sky" />
|
<ConstellationField
|
||||||
|
client:idle
|
||||||
|
className="opacity-40"
|
||||||
|
tint="violet"
|
||||||
|
transitionName="sky"
|
||||||
|
/>
|
||||||
<div class="container-prose relative z-10 flex flex-col gap-10">
|
<div class="container-prose relative z-10 flex flex-col gap-10">
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
@@ -53,10 +64,10 @@ const quickFacts = [
|
|||||||
class="border-l-2 pl-5 font-sans text-xl leading-relaxed sm:text-2xl"
|
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);"
|
style="border-color: var(--color-accent); color: var(--color-text);"
|
||||||
>
|
>
|
||||||
I am Greg — a software developer based in Philadelphia who spends
|
I am Greg: a software developer based in Philadelphia who spends his
|
||||||
his free time running tabletop RPGs, making resin dice, 3D printing
|
free time running tabletop RPGs, making resin dice and custom cards, 3D
|
||||||
miniatures and props, and reading his way through fantasy series at an
|
printing anything I can, and reading his way through fantasy series at
|
||||||
alarming rate. I live with my partner Krystina, our mini dachshund
|
an alarming rate. I live with my partner Krystina, our mini dachshund
|
||||||
Kashi, and more board games than any reasonable apartment should hold.
|
Kashi, and more board games than any reasonable apartment should hold.
|
||||||
</p>
|
</p>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
@@ -66,22 +77,25 @@ const quickFacts = [
|
|||||||
<section class="container-prose grid gap-10 py-10 lg:grid-cols-[1fr_18rem]">
|
<section class="container-prose grid gap-10 py-10 lg:grid-cols-[1fr_18rem]">
|
||||||
<Reveal class="flex flex-col gap-5">
|
<Reveal class="flex flex-col gap-5">
|
||||||
<h2>The longer arc</h2>
|
<h2>The longer arc</h2>
|
||||||
<div class="flex flex-col gap-5 text-lg leading-relaxed" style="color: var(--color-text-muted);">
|
<div
|
||||||
|
class="flex flex-col gap-5 text-lg leading-relaxed"
|
||||||
|
style="color: var(--color-text-muted);"
|
||||||
|
>
|
||||||
<p>
|
<p>
|
||||||
I grew up surrounded by books and games, and not much has changed.
|
I grew up loving books and games, and not much has changed. Technology
|
||||||
Technology pulled me into a career building cloud and mobile
|
pulled me into a career building cloud and mobile applications, but I
|
||||||
applications, but I never stopped collecting dice, designing
|
never stopped collecting dice, designing campaigns, or losing weekends
|
||||||
campaigns, or losing weekends to Sanderson rereads. I am currently
|
to Sanderson reads. I am currently expanding into SAP's Business
|
||||||
expanding into SAP's Business Technology Platform, exploring AI and
|
Technology Platform, exploring AI and machine learning, and trying to
|
||||||
machine learning, and trying to convince my group that yes, we
|
convince my group that yes, we
|
||||||
<em> can</em> fit one more board game into game night.
|
<em> can</em> fit one more board game into game night.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
I believe the best work happens when curiosity isn't compartmentalized.
|
I believe the best work happens when curiosity isn't
|
||||||
The same system-thinking that makes a good developer makes a good
|
compartmentalized. The same system-thinking that makes a good
|
||||||
gamemaster. The patience that produces a clean resin cast is the same
|
developer makes a good gamemaster. The patience that produces a clean
|
||||||
patience that debugs a stubborn deployment. This site is where I don't
|
resin cast is the same patience that debugs a stubborn deployment.
|
||||||
have to pretend those things are separate.
|
This site is where I don't have to pretend those things are separate.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
@@ -97,16 +111,28 @@ const quickFacts = [
|
|||||||
</Reveal>
|
</Reveal>
|
||||||
<Reveal delay={120}>
|
<Reveal delay={120}>
|
||||||
<aside class="card flex flex-col gap-4 lg:sticky lg:top-24">
|
<aside class="card flex flex-col gap-4 lg:sticky lg:top-24">
|
||||||
<h3 class="font-mono text-xs uppercase tracking-[0.22em]" style="color: var(--color-accent);">
|
<h3
|
||||||
|
class="font-mono text-xs uppercase tracking-[0.22em]"
|
||||||
|
style="color: var(--color-accent);"
|
||||||
|
>
|
||||||
Quick facts
|
Quick facts
|
||||||
</h3>
|
</h3>
|
||||||
<ul class="flex flex-col gap-3">
|
<ul class="flex flex-col gap-3">
|
||||||
{quickFacts.map((f) => (
|
{
|
||||||
<li class="flex items-start gap-3 text-sm" style="color: var(--color-text);">
|
quickFacts.map((f) => (
|
||||||
<Icon name={f.icon} class="mt-0.5 h-5 w-5 shrink-0" style="color: var(--color-accent);" />
|
<li
|
||||||
|
class="flex items-start gap-3 text-sm"
|
||||||
|
style="color: var(--color-text);"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name={f.icon}
|
||||||
|
class="mt-0.5 h-5 w-5 shrink-0"
|
||||||
|
style="color: var(--color-accent);"
|
||||||
|
/>
|
||||||
<span>{f.text}</span>
|
<span>{f.text}</span>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))
|
||||||
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</aside>
|
</aside>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
@@ -115,7 +141,10 @@ const quickFacts = [
|
|||||||
|
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<div class="container-prose">
|
<div class="container-prose">
|
||||||
<AlchemicalDivider class="mx-auto h-6 w-full max-w-sm" style="color: var(--color-accent);" />
|
<AlchemicalDivider
|
||||||
|
class="mx-auto h-6 w-full max-w-sm"
|
||||||
|
style="color: var(--color-accent);"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
||||||
|
|||||||
+85
-27
@@ -10,24 +10,48 @@
|
|||||||
* Spec items Greg still needs to fill (email, Discord, etc.) appear as
|
* Spec items Greg still needs to fill (email, Discord, etc.) appear as
|
||||||
* Placeholder slots.
|
* Placeholder slots.
|
||||||
*/
|
*/
|
||||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
import BaseLayout from "@layouts/BaseLayout.astro";
|
||||||
import Reveal from '@components/motion/Reveal.astro';
|
import Reveal from "@components/motion/Reveal.astro";
|
||||||
import Icon from '@components/Icon.astro';
|
import Icon from "@components/Icon.astro";
|
||||||
import SectionHeader from '@components/layout/SectionHeader.astro';
|
import SectionHeader from "@components/layout/SectionHeader.astro";
|
||||||
import Placeholder from '@components/layout/Placeholder.astro';
|
import Placeholder from "@components/layout/Placeholder.astro";
|
||||||
import ContactForm from '@components/professional/ContactForm.tsx';
|
import ContactForm from "@components/professional/ContactForm.tsx";
|
||||||
|
|
||||||
const professional = [
|
const professional = [
|
||||||
{ icon: 'email-outline', label: 'Email', hint: 'Greg professional email address.' },
|
{
|
||||||
{ icon: 'linkedin', label: 'LinkedIn', hint: 'LinkedIn profile URL.' },
|
icon: "email-outline",
|
||||||
{ icon: 'github', label: 'GitHub', hint: 'GitHub profile URL.' },
|
label: "Email",
|
||||||
|
hint: '<a href="mailto:Kilmer.GM@Gmail.com">Kilmer.GM@Gmail.com</a>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "linkedin",
|
||||||
|
label: "LinkedIn",
|
||||||
|
hint: '<a href="https://www.linkedin.com/in/gregory-kilmer-36646bb5/" target="_blank" rel="noopener noreferrer">LinkedIn</a>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "github",
|
||||||
|
label: "GitHub",
|
||||||
|
hint: '<a href="https://github.com/patiun" target="_blank" rel="noopener noreferrer">GitHub</a>',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const social = [
|
const social = [
|
||||||
{ icon: 'discord', label: 'Discord', hint: 'Handle or invite link.' },
|
{ icon: "discord", label: "Discord", hint: "Handle or invite link." },
|
||||||
{ icon: 'twitter', label: 'Twitter / X', hint: 'Profile link, if applicable.' },
|
{
|
||||||
{ icon: 'paw', label: 'Pokémon', hint: 'Showdown or Trainer name, if shared.' },
|
icon: "twitter",
|
||||||
{ icon: 'cube-outline', label: 'Foundry VTT', hint: 'Server link, if public.' },
|
label: "Twitter / X",
|
||||||
|
hint: "Profile link, if applicable.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "paw",
|
||||||
|
label: "Pokémon",
|
||||||
|
hint: "Showdown or Trainer name, if shared.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "cube-outline",
|
||||||
|
label: "Foundry VTT",
|
||||||
|
hint: "Server link, if public.",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -52,11 +76,15 @@ const social = [
|
|||||||
{/* Professional */}
|
{/* Professional */}
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<section class="flex flex-col gap-4">
|
<section class="flex flex-col gap-4">
|
||||||
<h2 class="font-mono text-xs uppercase tracking-[0.22em]" style="color: var(--color-accent);">
|
<h2
|
||||||
|
class="font-mono text-xs uppercase tracking-[0.22em]"
|
||||||
|
style="color: var(--color-accent);"
|
||||||
|
>
|
||||||
Professional
|
Professional
|
||||||
</h2>
|
</h2>
|
||||||
<ul class="flex flex-col gap-3">
|
<ul class="flex flex-col gap-3">
|
||||||
{professional.map((item) => (
|
{
|
||||||
|
professional.map((item) => (
|
||||||
<li class="card flex items-center gap-3">
|
<li class="card flex items-center gap-3">
|
||||||
<span
|
<span
|
||||||
class="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg"
|
class="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg"
|
||||||
@@ -66,24 +94,38 @@ const social = [
|
|||||||
<Icon name={item.icon} class="h-5 w-5" />
|
<Icon name={item.icon} class="h-5 w-5" />
|
||||||
</span>
|
</span>
|
||||||
<span class="flex flex-col gap-0.5">
|
<span class="flex flex-col gap-0.5">
|
||||||
<span class="font-sans text-sm font-semibold" style="color: var(--color-text);">{item.label}</span>
|
<span
|
||||||
<span class="text-xs" style="color: var(--color-text-subtle);">{item.hint}</span>
|
class="font-sans text-sm font-semibold"
|
||||||
|
style="color: var(--color-text);"
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="text-xs"
|
||||||
|
style="color: var(--color-text-subtle);"
|
||||||
|
>
|
||||||
|
{item.hint}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))
|
||||||
|
}
|
||||||
</ul>
|
</ul>
|
||||||
<Placeholder label="Professional links" hint="Replace the slots above with your real email / LinkedIn / GitHub once ready." />
|
|
||||||
</section>
|
</section>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
||||||
{/* Social / personal */}
|
{/* Social / personal */}
|
||||||
<Reveal delay={80}>
|
<Reveal delay={80}>
|
||||||
<section class="flex flex-col gap-4">
|
<section class="flex flex-col gap-4">
|
||||||
<h2 class="font-mono text-xs uppercase tracking-[0.22em]" style="color: var(--color-secondary);">
|
<h2
|
||||||
|
class="font-mono text-xs uppercase tracking-[0.22em]"
|
||||||
|
style="color: var(--color-secondary);"
|
||||||
|
>
|
||||||
Personal / Social
|
Personal / Social
|
||||||
</h2>
|
</h2>
|
||||||
<ul class="grid gap-3 sm:grid-cols-2">
|
<ul class="grid gap-3 sm:grid-cols-2">
|
||||||
{social.map((item) => (
|
{
|
||||||
|
social.map((item) => (
|
||||||
<li class="card flex items-center gap-3">
|
<li class="card flex items-center gap-3">
|
||||||
<span
|
<span
|
||||||
class="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg"
|
class="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg"
|
||||||
@@ -93,11 +135,22 @@ const social = [
|
|||||||
<Icon name={item.icon} class="h-5 w-5" />
|
<Icon name={item.icon} class="h-5 w-5" />
|
||||||
</span>
|
</span>
|
||||||
<span class="flex flex-col gap-0.5">
|
<span class="flex flex-col gap-0.5">
|
||||||
<span class="font-sans text-sm font-semibold" style="color: var(--color-text);">{item.label}</span>
|
<span
|
||||||
<span class="text-xs" style="color: var(--color-text-subtle);">{item.hint}</span>
|
class="font-sans text-sm font-semibold"
|
||||||
|
style="color: var(--color-text);"
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="text-xs"
|
||||||
|
style="color: var(--color-text-subtle);"
|
||||||
|
>
|
||||||
|
{item.hint}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))
|
||||||
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
@@ -108,7 +161,9 @@ const social = [
|
|||||||
class="rounded-xl border-l-2 p-4 text-sm"
|
class="rounded-xl border-l-2 p-4 text-sm"
|
||||||
style="border-color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 8%, transparent); color: var(--color-text-muted);"
|
style="border-color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 8%, transparent); color: var(--color-text-muted);"
|
||||||
>
|
>
|
||||||
<strong style="color: var(--color-text);">Availability:</strong> Open to opportunities in cloud development, SAP BTP, and technical leadership.
|
<strong style="color: var(--color-text);">Availability:</strong> Open to
|
||||||
|
opportunities in AI/ML, app and cloud development, SAP BTP, and technical
|
||||||
|
leadership.
|
||||||
</p>
|
</p>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
</div>
|
</div>
|
||||||
@@ -117,7 +172,9 @@ const social = [
|
|||||||
<Reveal delay={100}>
|
<Reveal delay={100}>
|
||||||
<section class="card flex flex-col gap-5">
|
<section class="card flex flex-col gap-5">
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<h2 class="font-sans" style="color: var(--color-text);">Send a message</h2>
|
<h2 class="font-sans" style="color: var(--color-text);">
|
||||||
|
Send a message
|
||||||
|
</h2>
|
||||||
<p class="text-sm" style="color: var(--color-text-muted);">
|
<p class="text-sm" style="color: var(--color-text-muted);">
|
||||||
Prefer a form? Drop a note and it will land in my inbox.
|
Prefer a form? Drop a note and it will land in my inbox.
|
||||||
</p>
|
</p>
|
||||||
@@ -134,7 +191,8 @@ const social = [
|
|||||||
class="mx-auto max-w-2xl border-l-2 pl-5 text-center font-sans text-lg italic"
|
class="mx-auto max-w-2xl border-l-2 pl-5 text-center font-sans text-lg italic"
|
||||||
style="border-color: var(--color-accent); color: var(--color-text-muted);"
|
style="border-color: var(--color-accent); color: var(--color-text-muted);"
|
||||||
>
|
>
|
||||||
Whether you want to talk cloud architecture, debate the best Gundam series, or need a fourth for game night, reach out.
|
Whether you want to talk cloud architecture, debate the best Gundam
|
||||||
|
series, or need a fourth for game night, reach out.
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
+136
-70
@@ -9,76 +9,86 @@
|
|||||||
*
|
*
|
||||||
* Emojis from the spec table are rendered as mdi icons (no emojis per spec).
|
* Emojis from the spec table are rendered as mdi icons (no emojis per spec).
|
||||||
*/
|
*/
|
||||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
import BaseLayout from "@layouts/BaseLayout.astro";
|
||||||
import Reveal from '@components/motion/Reveal.astro';
|
import Reveal from "@components/motion/Reveal.astro";
|
||||||
import AnimatedBackground from '@components/hero/AnimatedBackground.tsx';
|
import AnimatedBackground from "@components/hero/AnimatedBackground.tsx";
|
||||||
import Icon from '@components/Icon.astro';
|
import Icon from "@components/Icon.astro";
|
||||||
import SectionHeader from '@components/layout/SectionHeader.astro';
|
import SectionHeader from "@components/layout/SectionHeader.astro";
|
||||||
import CelestialImage from '@components/mystic/CelestialImage.astro';
|
import CelestialImage from "@components/mystic/CelestialImage.astro";
|
||||||
import AlchemicalDivider from '@components/mystic/AlchemicalDivider.astro';
|
import AlchemicalDivider from "@components/mystic/AlchemicalDivider.astro";
|
||||||
import SacredGeometry from '@components/mystic/SacredGeometry.astro';
|
import SacredGeometry from "@components/mystic/SacredGeometry.astro";
|
||||||
import ConstellationField from '@components/mystic/ConstellationField.tsx';
|
import ConstellationField from "@components/mystic/ConstellationField.tsx";
|
||||||
|
|
||||||
// Snapshot grid content from the spec, with spec emojis mapped to mdi icons.
|
// Snapshot grid content from the spec, with spec emojis mapped to mdi icons.
|
||||||
// Each card now carries a vibe-matched stock image (swap for real photos later).
|
// Each card now carries a vibe-matched stock image (swap for real photos later).
|
||||||
const cards = [
|
const cards = [
|
||||||
{
|
{
|
||||||
icon: 'briefcase',
|
icon: "briefcase",
|
||||||
title: 'Professional',
|
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 apps to full-stack mobile — a decade of building software that businesses actually use.",
|
||||||
href: '/professional',
|
href: "/professional",
|
||||||
image: '/images/pro-workspace.jpg',
|
image: "/images/pro-workspace.jpg",
|
||||||
alt: 'Developer workspace with code on screen',
|
alt: "Developer workspace with code on screen",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'dice-multiple',
|
icon: "dice-multiple",
|
||||||
title: 'Tabletop',
|
title: "Tabletop",
|
||||||
copy: "Currently running two campaigns in Foundry VTT and playtesting MCDM's Crows. Always rolling dice.",
|
copy: "Currently running two campaigns in Foundry VTT and playtesting MCDM's Crows. Always rolling dice.",
|
||||||
href: '/interests/ttrpgs',
|
href: "/interests/ttrpgs",
|
||||||
image: '/images/ttrpg-dice.jpg',
|
image: "/images/ttrpg-dice.jpg",
|
||||||
alt: 'Polyhedral dice on a dark surface',
|
alt: "Polyhedral dice on a dark surface",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'palette',
|
icon: "palette",
|
||||||
title: 'Making',
|
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, and whatever else catches my eye. If it involves layers and precision, I am in.",
|
||||||
href: '/interests/making',
|
href: "/interests/making",
|
||||||
image: '/images/making-resin.jpg',
|
image: "/images/making-resin.jpg",
|
||||||
alt: 'Resin crafting in progress',
|
alt: "Resin crafting in progress",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout>
|
<BaseLayout>
|
||||||
<!-- ===================== HERO ===================== -->
|
<!-- ===================== HERO ===================== -->
|
||||||
<section class="vt-hero-sky relative flex min-h-[88vh] items-center overflow-hidden pt-16">
|
<section
|
||||||
|
class="vt-hero-sky relative flex min-h-[88vh] items-center overflow-hidden pt-16"
|
||||||
|
>
|
||||||
<AnimatedBackground client:idle transitionName="sky" />
|
<AnimatedBackground client:idle transitionName="sky" />
|
||||||
|
|
||||||
<div class="container-prose relative z-10 flex flex-col items-start gap-8 py-20">
|
<div
|
||||||
|
class="container-prose relative z-10 flex flex-col items-start gap-8 py-20"
|
||||||
|
>
|
||||||
<div class="flex w-full flex-col gap-10 lg:flex-row lg:items-center">
|
<div class="flex w-full flex-col gap-10 lg:flex-row lg:items-center">
|
||||||
<Reveal as="div" class="max-w-2xl grow">
|
<Reveal as="div" class="max-w-2xl grow">
|
||||||
<span
|
<span
|
||||||
class="mb-5 inline-flex items-center gap-2 rounded-full border px-3 py-1 font-mono text-xs uppercase tracking-[0.18em]"
|
class="mb-5 inline-flex items-center gap-2 rounded-full border px-3 py-1 font-mono text-xs uppercase tracking-[0.18em]"
|
||||||
style="border-color: var(--color-border); color: var(--color-text-muted); background: color-mix(in srgb, var(--color-surface-raised) 60%, transparent);">
|
style="border-color: var(--color-border); color: var(--color-text-muted); background: color-mix(in srgb, var(--color-surface-raised) 60%, transparent);"
|
||||||
<span class="h-2 w-2 rounded-full animate-pulse-glow" style="background: var(--color-accent);"></span>
|
>
|
||||||
|
<span
|
||||||
|
class="h-2 w-2 rounded-full animate-pulse-glow"
|
||||||
|
style="background: var(--color-accent);"></span>
|
||||||
Developer. Maker. Storyteller.
|
Developer. Maker. Storyteller.
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<h1 class="text-balance" style="color: var(--text);">
|
<h1 class="text-balance" style="color: var(--text);">Greg Kilmer</h1>
|
||||||
Greg Kilmer
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<p class="mt-3 font-sans text-xl font-medium sm:text-2xl" style="color: var(--color-accent);">
|
<p
|
||||||
|
class="mt-3 font-sans text-xl font-medium sm:text-2xl"
|
||||||
|
style="color: var(--color-accent);"
|
||||||
|
>
|
||||||
Software Developer · Maker · Tabletop Gamemaster
|
Software Developer · Maker · Tabletop Gamemaster
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<blockquote class="mt-7 max-w-2xl border-l-2 pl-5 text-lg leading-relaxed"
|
<blockquote
|
||||||
style="border-color: var(--color-accent); color: var(--text-muted);">
|
class="mt-7 max-w-2xl border-l-2 pl-5 text-lg leading-relaxed"
|
||||||
|
style="border-color: var(--color-accent); color: var(--text-muted);"
|
||||||
|
>
|
||||||
I build things with code during the day and with resin, plastic, and
|
I build things with code during the day and with resin, plastic, and
|
||||||
imagination at night. I lead cloud and mobile development at Implico,
|
imagination at night. I lead cloud and mobile development at
|
||||||
run D&D campaigns that span years, and fill my shelves with Brandon
|
Implico, run D&D campaigns that span years, and fill my shelves with
|
||||||
Sanderson novels, custom dice, and board games. This is the place
|
Brandon Sanderson novels, custom dice, and board games. This is the
|
||||||
where all of those worlds meet.
|
place where all of those worlds meet.
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<div class="mt-9 flex flex-wrap gap-4">
|
<div class="mt-9 flex flex-wrap gap-4">
|
||||||
@@ -93,87 +103,143 @@ alt: 'Resin crafting in progress',
|
|||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
||||||
{/* Hero portrait — framed in celestial ornament. Swap for a real photo of Greg. */}
|
{/* Hero portrait — framed in celestial ornament. */}
|
||||||
<Reveal as="div" delay={120} class="w-full max-w-sm shrink-0 lg:w-80">
|
<Reveal as="div" delay={120} class="w-full max-w-sm shrink-0 lg:w-80">
|
||||||
<CelestialImage src="/images/hero-portrait.jpg" alt="Greg at his desk" aspect="4/5" />
|
<CelestialImage
|
||||||
|
src="/images/hero-portrait.jpg"
|
||||||
|
alt="Greg at his desk"
|
||||||
|
aspect="4/5"
|
||||||
|
/>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Scroll cue -->
|
<!-- Scroll cue -->
|
||||||
<div class="pointer-events-none absolute bottom-6 left-1/2 -translate-x-1/2 animate-float"
|
<div
|
||||||
style="color: var(--color-text-subtle);" aria-hidden="true">
|
class="pointer-events-none absolute bottom-6 left-1/2 -translate-x-1/2 animate-float"
|
||||||
|
style="color: var(--color-text-subtle);"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<Icon name="chevron-down" class="h-7 w-7" />
|
<Icon name="chevron-down" class="h-7 w-7" />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- ===================== SNAPSHOT GRID ===================== -->
|
<!-- ===================== SNAPSHOT GRID ===================== -->
|
||||||
<section class="relative overflow-hidden py-20 sm:py-28">
|
<section class="relative overflow-hidden py-20 sm:py-28">
|
||||||
{/* Slow-rotating constellation field behind the section — a slice of sky. */}
|
{
|
||||||
|
/* Slow-rotating constellation field behind the section — a slice of sky. */
|
||||||
|
}
|
||||||
<ConstellationField client:idle className="opacity-60" />
|
<ConstellationField client:idle className="opacity-60" />
|
||||||
{/* Faint sacred-geometry ornament behind the section. */}
|
{/* Faint sacred-geometry ornament behind the section. */}
|
||||||
<SacredGeometry figure="flower" class="pointer-events-none absolute -right-40 top-10 z-0 h-[40rem] w-[40rem]"
|
<SacredGeometry
|
||||||
style="color: var(--color-violet); opacity:.08;" />
|
figure="flower"
|
||||||
|
class="pointer-events-none absolute -right-40 top-10 z-0 h-[40rem] w-[40rem]"
|
||||||
|
style="color: var(--color-violet); opacity:.08;"
|
||||||
|
/>
|
||||||
<div class="container-prose relative z-10 flex flex-col gap-12">
|
<div class="container-prose relative z-10 flex flex-col gap-12">
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<SectionHeader kicker="The two wings" icon="home-heart" title="A snapshot"
|
<SectionHeader
|
||||||
subtitle="One house, two wings. Polished and precise on the professional side; warm and inviting on the personal side." />
|
kicker="The two wings"
|
||||||
|
icon="home-heart"
|
||||||
|
title="A snapshot"
|
||||||
|
subtitle="One house, two wings. Polished and precise on the professional side; warm and inviting on the personal side."
|
||||||
|
/>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
||||||
<div class="grid gap-5 md:grid-cols-3">
|
<div class="grid gap-5 md:grid-cols-3">
|
||||||
{cards.map((card, i) => (
|
{
|
||||||
|
cards.map((card, i) => (
|
||||||
<Reveal delay={i * 90}>
|
<Reveal delay={i * 90}>
|
||||||
<a href={card.href} class="card card-interactive group flex h-full flex-col gap-4 overflow-hidden p-0">
|
<a
|
||||||
|
href={card.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">
|
<div class="aspect-[16/10] w-full overflow-hidden">
|
||||||
<img src={card.image} alt={card.alt} loading="lazy" decoding="async"
|
<img
|
||||||
class="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105" />
|
src={card.image}
|
||||||
|
alt={card.alt}
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
class="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-4 px-5 pb-5">
|
<div class="flex flex-col gap-4 px-5 pb-5">
|
||||||
<span class="inline-flex h-12 w-12 items-center justify-center rounded-xl"
|
<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);"
|
style="background: color-mix(in srgb, var(--color-accent) 16%, transparent); color: var(--color-accent);"
|
||||||
aria-hidden="true">
|
aria-hidden="true"
|
||||||
|
>
|
||||||
<Icon name={card.icon} class="h-6 w-6" />
|
<Icon name={card.icon} class="h-6 w-6" />
|
||||||
</span>
|
</span>
|
||||||
<h3 class="font-sans" style="color: var(--color-text);">{card.title}</h3>
|
<h3 class="font-sans" style="color: var(--color-text);">
|
||||||
<p class="grow text-sm leading-relaxed" style="color: var(--color-text-muted);">
|
{card.title}
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="grow text-sm leading-relaxed"
|
||||||
|
style="color: var(--color-text-muted);"
|
||||||
|
>
|
||||||
{card.copy}
|
{card.copy}
|
||||||
</p>
|
</p>
|
||||||
<span
|
<span
|
||||||
class="mt-1 inline-flex items-center gap-1 font-sans text-sm font-semibold transition-transform group-hover:translate-x-1"
|
class="mt-1 inline-flex items-center gap-1 font-sans text-sm font-semibold transition-transform group-hover:translate-x-1"
|
||||||
style="color: var(--color-accent);">
|
style="color: var(--color-accent);"
|
||||||
|
>
|
||||||
Learn more
|
Learn more
|
||||||
<Icon name="arrow-right" class="h-4 w-4" />
|
<Icon name="arrow-right" class="h-4 w-4" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
))}
|
))
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<AlchemicalDivider class="mx-auto h-6 w-full max-w-sm" style="color: var(--color-accent);" />
|
<AlchemicalDivider
|
||||||
|
class="mx-auto h-6 w-full max-w-sm"
|
||||||
|
style="color: var(--color-accent);"
|
||||||
|
/>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
||||||
{/* Wider strip: Reading & Media */}
|
{/* Wider strip: Reading & Media */}
|
||||||
<Reveal delay={120}>
|
<Reveal delay={120}>
|
||||||
<a href="/interests/reading"
|
<a
|
||||||
class="card card-interactive group flex flex-col gap-4 overflow-hidden p-0 sm:flex-row sm:items-center sm:justify-between">
|
href="/interests/reading"
|
||||||
|
class="card card-interactive group flex flex-col gap-4 overflow-hidden p-0 sm:flex-row sm:items-center sm:justify-between"
|
||||||
|
>
|
||||||
<span class="flex items-center gap-4">
|
<span class="flex items-center gap-4">
|
||||||
<span class="hidden aspect-square w-32 shrink-0 overflow-hidden sm:block">
|
<span
|
||||||
<img src="/images/fantasy-books.jpg" alt="Fantasy bookshelf" loading="lazy" decoding="async"
|
class="hidden aspect-square w-32 shrink-0 overflow-hidden sm:block"
|
||||||
class="h-full w-full object-cover" />
|
>
|
||||||
|
<img
|
||||||
|
src="/images/fantasy-books.jpg"
|
||||||
|
alt="Fantasy bookshelf"
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
class="h-full w-full object-cover"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="flex flex-col gap-1 px-5 py-4 sm:px-0 sm:py-0">
|
<span class="flex flex-col gap-1 px-5 py-4 sm:px-0 sm:py-0">
|
||||||
<span class="font-mono text-xs uppercase tracking-[0.18em]" style="color: var(--color-text-subtle);">
|
<span
|
||||||
|
class="font-mono text-xs uppercase tracking-[0.18em]"
|
||||||
|
style="color: var(--color-text-subtle);"
|
||||||
|
>
|
||||||
Reading & Media
|
Reading & Media
|
||||||
</span>
|
</span>
|
||||||
<span class="font-sans text-lg font-semibold" style="color: var(--color-text);">
|
<span
|
||||||
Deep in the Cosmere, catching up on anime, and always three books ahead on my to-read list.
|
class="font-sans text-lg font-semibold"
|
||||||
|
style="color: var(--color-text);"
|
||||||
|
>
|
||||||
|
Deep in the Cosmere, catching up on anime, and always three
|
||||||
|
books ahead on my to-read list.
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<Icon name="arrow-right" class="h-6 w-6 shrink-0 transition-transform group-hover:translate-x-1 sm:ml-4"
|
<Icon
|
||||||
style="color: var(--color-accent);" />
|
name="arrow-right"
|
||||||
|
class="h-6 w-6 shrink-0 transition-transform group-hover:translate-x-1 sm:ml-4"
|
||||||
|
style="color: var(--color-accent);"
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,24 +10,24 @@
|
|||||||
* `projects` collection. Both are sorted by `order`. Education is a placeholder
|
* `projects` collection. Both are sorted by `order`. Education is a placeholder
|
||||||
* block (spec leaves it to Greg).
|
* block (spec leaves it to Greg).
|
||||||
*/
|
*/
|
||||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
import BaseLayout from "@layouts/BaseLayout.astro";
|
||||||
import Reveal from '@components/motion/Reveal.astro';
|
import Reveal from "@components/motion/Reveal.astro";
|
||||||
import Icon from '@components/Icon.astro';
|
import Icon from "@components/Icon.astro";
|
||||||
import SectionHeader from '@components/layout/SectionHeader.astro';
|
import SectionHeader from "@components/layout/SectionHeader.astro";
|
||||||
import Placeholder from '@components/layout/Placeholder.astro';
|
import Placeholder from "@components/layout/Placeholder.astro";
|
||||||
import SectionNav from '@components/professional/SectionNav.astro';
|
import SectionNav from "@components/professional/SectionNav.astro";
|
||||||
import Timeline from '@components/professional/Timeline.astro';
|
import Timeline from "@components/professional/Timeline.astro";
|
||||||
import SkillGrid from '@components/professional/SkillGrid.astro';
|
import SkillGrid from "@components/professional/SkillGrid.astro";
|
||||||
import ProjectCard from '@components/professional/ProjectCard.astro';
|
import ProjectCard from "@components/professional/ProjectCard.astro";
|
||||||
import AlchemicalDivider from '@components/mystic/AlchemicalDivider.astro';
|
import AlchemicalDivider from "@components/mystic/AlchemicalDivider.astro";
|
||||||
import Astrolabe from '@components/mystic/Astrolabe.astro';
|
import Astrolabe from "@components/mystic/Astrolabe.astro";
|
||||||
import CircuitField from '@components/mystic/CircuitField.tsx';
|
import CircuitField from "@components/mystic/CircuitField.tsx";
|
||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from "astro:content";
|
||||||
|
|
||||||
const experience = (await getCollection('experience')).sort(
|
const experience = (await getCollection("experience")).sort(
|
||||||
(a, b) => a.data.order - b.data.order,
|
(a, b) => a.data.order - b.data.order,
|
||||||
);
|
);
|
||||||
const projects = (await getCollection('projects')).sort(
|
const projects = (await getCollection("projects")).sort(
|
||||||
(a, b) => a.data.order - b.data.order,
|
(a, b) => a.data.order - b.data.order,
|
||||||
);
|
);
|
||||||
---
|
---
|
||||||
@@ -39,9 +39,11 @@ const projects = (await getCollection('projects')).sort(
|
|||||||
>
|
>
|
||||||
<!-- Page header -->
|
<!-- Page header -->
|
||||||
<section class="relative overflow-hidden pt-28 sm:pt-32">
|
<section class="relative overflow-hidden pt-28 sm:pt-32">
|
||||||
{/* Circuit-board field. Shares view-transition-name "sky" with the star
|
{
|
||||||
|
/* Circuit-board field. Shares view-transition-name "sky" with the star
|
||||||
fields on other pages, so navigating here morphs constellations into
|
fields on other pages, so navigating here morphs constellations into
|
||||||
circuitry. */}
|
circuitry. */
|
||||||
|
}
|
||||||
<CircuitField client:idle className="opacity-70" transitionName="sky" />
|
<CircuitField client:idle className="opacity-70" transitionName="sky" />
|
||||||
{/* Slowly rotating astrolabe ornament behind the header. */}
|
{/* Slowly rotating astrolabe ornament behind the header. */}
|
||||||
<Astrolabe
|
<Astrolabe
|
||||||
@@ -53,7 +55,7 @@ const projects = (await getCollection('projects')).sort(
|
|||||||
<SectionHeader
|
<SectionHeader
|
||||||
kicker="Professional"
|
kicker="Professional"
|
||||||
icon="briefcase"
|
icon="briefcase"
|
||||||
title="Resume & portfolio"
|
title="Resume & portfolio"
|
||||||
subtitle="Clean, confident, skimmable. Browsable here, screenshot-able for a recruiter, printable if needed."
|
subtitle="Clean, confident, skimmable. Browsable here, screenshot-able for a recruiter, printable if needed."
|
||||||
/>
|
/>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
@@ -67,7 +69,11 @@ const projects = (await getCollection('projects')).sort(
|
|||||||
{/* ===== 1. Summary ===== */}
|
{/* ===== 1. Summary ===== */}
|
||||||
<section id="summary" class="scroll-mt-28 flex flex-col gap-6">
|
<section id="summary" class="scroll-mt-28 flex flex-col gap-6">
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<SectionHeader kicker="01" icon="format-list-text" title="Professional summary" />
|
<SectionHeader
|
||||||
|
kicker="01"
|
||||||
|
icon="format-list-text"
|
||||||
|
title="Professional summary"
|
||||||
|
/>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<Reveal delay={80}>
|
<Reveal delay={80}>
|
||||||
<blockquote
|
<blockquote
|
||||||
@@ -107,7 +113,10 @@ const projects = (await getCollection('projects')).sort(
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<AlchemicalDivider class="mx-auto h-6 w-full max-w-sm" style="color: var(--color-accent);" />
|
<AlchemicalDivider
|
||||||
|
class="mx-auto h-6 w-full max-w-sm"
|
||||||
|
style="color: var(--color-accent);"
|
||||||
|
/>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
||||||
{/* ===== 2. Experience ===== */}
|
{/* ===== 2. Experience ===== */}
|
||||||
@@ -129,7 +138,7 @@ const projects = (await getCollection('projects')).sort(
|
|||||||
<SectionHeader
|
<SectionHeader
|
||||||
kicker="03"
|
kicker="03"
|
||||||
icon="chart-bar"
|
icon="chart-bar"
|
||||||
title="Skills & technologies"
|
title="Skills & technologies"
|
||||||
subtitle="What I bring to the table, organized into three tiers."
|
subtitle="What I bring to the table, organized into three tiers."
|
||||||
/>
|
/>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
@@ -147,11 +156,13 @@ const projects = (await getCollection('projects')).sort(
|
|||||||
/>
|
/>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div class="grid gap-5 sm:grid-cols-2">
|
<div class="grid gap-5 sm:grid-cols-2">
|
||||||
{projects.map((project, i) => (
|
{
|
||||||
|
projects.map((project, i) => (
|
||||||
<Reveal delay={i * 80}>
|
<Reveal delay={i * 80}>
|
||||||
<ProjectCard project={project} />
|
<ProjectCard project={project} />
|
||||||
</Reveal>
|
</Reveal>
|
||||||
))}
|
))
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<Placeholder
|
<Placeholder
|
||||||
label="Add 3-6 projects"
|
label="Add 3-6 projects"
|
||||||
@@ -165,13 +176,19 @@ const projects = (await getCollection('projects')).sort(
|
|||||||
<SectionHeader
|
<SectionHeader
|
||||||
kicker="05"
|
kicker="05"
|
||||||
icon="school"
|
icon="school"
|
||||||
title="Education & certifications"
|
title="Education & certifications"
|
||||||
subtitle="My foundation."
|
subtitle="My foundation."
|
||||||
/>
|
/>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div class="grid gap-4 sm:grid-cols-2">
|
<div class="grid gap-4 sm:grid-cols-2">
|
||||||
<Placeholder label="Education history" hint="Add degrees, institutions, and dates." />
|
<Placeholder
|
||||||
<Placeholder label="Certifications" hint="SAP, cloud, or other relevant certifications." />
|
label="Education history"
|
||||||
|
hint="Add degrees, institutions, and dates."
|
||||||
|
/>
|
||||||
|
<Placeholder
|
||||||
|
label="Certifications"
|
||||||
|
hint="SAP, cloud, or other relevant certifications."
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -189,16 +206,49 @@ const projects = (await getCollection('projects')).sort(
|
|||||||
<div class="card flex flex-col gap-6">
|
<div class="card flex flex-col gap-6">
|
||||||
<ul class="flex flex-col gap-4 sm:flex-row sm:flex-wrap sm:gap-8">
|
<ul class="flex flex-col gap-4 sm:flex-row sm:flex-wrap sm:gap-8">
|
||||||
<li class="flex items-center gap-2">
|
<li class="flex items-center gap-2">
|
||||||
<Icon name="email-outline" class="h-5 w-5" style="color: var(--color-accent);" />
|
<Icon
|
||||||
<span class="font-mono text-xs uppercase tracking-[0.18em]" style="color: var(--color-accent);">Email: [Greg to fill]</span>
|
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>
|
||||||
<li class="flex items-center gap-2">
|
<li class="flex items-center gap-2">
|
||||||
<Icon name="linkedin" class="h-5 w-5" style="color: var(--color-accent);" />
|
<Icon
|
||||||
<span class="font-mono text-xs uppercase tracking-[0.18em]" style="color: var(--color-accent);">LinkedIn: [Greg to fill]</span>
|
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>
|
||||||
<li class="flex items-center gap-2">
|
<li class="flex items-center gap-2">
|
||||||
<Icon name="github" class="h-5 w-5" style="color: var(--color-accent);" />
|
<Icon
|
||||||
<span class="font-mono text-xs uppercase tracking-[0.18em]" style="color: var(--color-accent);">GitHub: [Greg to fill]</span>
|
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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<a href="/contact" class="btn btn-primary self-start">
|
<a href="/contact" class="btn btn-primary self-start">
|
||||||
|
|||||||
Reference in New Issue
Block a user