mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
963ad0df23
The experience notes, skills, education and a new /resume Page text now come from Greg's Resume Interview answers (tools/migrate/src/seed.ts). Comcast and Drexel move to a short Earlier list, and the page and PDF gain Selected projects. Carrier Connect's numbers are Greg's corrected ones. The PDF fits on one page and carries the email from site settings. Store lines migrate with no open slots until Greg opens orders. Schema: experience earlier, page projects, site-settings email. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012aSbo2D1qP8cMFQCykf7kx
61 lines
2.5 KiB
TypeScript
61 lines
2.5 KiB
TypeScript
/** The resume's data, shared by the page and the PDF so they never disagree. */
|
||
import type { Note } from "./content.ts";
|
||
import type { SiteIndex } from "./site.ts";
|
||
|
||
export interface ResumeData {
|
||
name: string;
|
||
headline: string;
|
||
location?: string;
|
||
summary?: string;
|
||
availability?: string;
|
||
email?: string;
|
||
stats: { value: string; label: string; detail?: string }[];
|
||
/** Roles shown in full, current first. */
|
||
roles: Note<"experience">[];
|
||
/** Roles marked earlier: a short list of title, company, dates and focus. */
|
||
earlier: Note<"experience">[];
|
||
projects: { title: string; detail: string; link?: string }[];
|
||
skills?: Note<"skills">["data"];
|
||
education?: Note<"education">["data"];
|
||
socials: { label: string; handle: string; url: string }[];
|
||
/** The newest change to any note the resume is built from (YYYY-MM-DD). */
|
||
updated: string;
|
||
}
|
||
|
||
/** "Mar 2019", from "2019-03". */
|
||
export const month = (ym: string | undefined) => {
|
||
if (!ym) return "Present";
|
||
const [y, m] = ym.split("-").map(Number);
|
||
return new Date(Date.UTC(y!, (m ?? 1) - 1, 1)).toLocaleDateString("en-US", { timeZone: "UTC", month: "short", year: "numeric" });
|
||
};
|
||
|
||
export const period = (r: Note<"experience">) => `${month(r.data.start)} – ${month(r.data.end)}`;
|
||
|
||
/** "A, B and C". */
|
||
export const listOf = (items: string[]) => new Intl.ListFormat("en-US", { style: "long", type: "conjunction" }).format(items);
|
||
|
||
export function resumeData(s: SiteIndex): ResumeData {
|
||
const settings = s.settings();
|
||
const page = s.pageText("/resume");
|
||
const roles = [...s.all("experience")].sort((a, b) => (b.data.end ?? "9999").localeCompare(a.data.end ?? "9999") || b.data.start.localeCompare(a.data.start));
|
||
const current = roles.find((r) => !r.data.end) ?? roles[0];
|
||
const sources: Note[] = [...roles, ...(page ? [page] : []), ...[s.one("skills"), s.one("education")].filter((n): n is Note<"skills"> | Note<"education"> => !!n)];
|
||
const updated = sources.map((n) => n.acceptedAt?.slice(0, 10) ?? "").sort().at(-1) ?? "";
|
||
return {
|
||
name: settings?.name ?? "Greg Kilmer",
|
||
headline: page?.data.lede ?? current?.data.role ?? "",
|
||
location: settings?.location,
|
||
summary: page?.body?.trim() || undefined,
|
||
availability: settings?.availability,
|
||
email: settings?.email,
|
||
stats: page?.data.stats ?? [],
|
||
roles: roles.filter((r) => !r.data.earlier),
|
||
earlier: roles.filter((r) => r.data.earlier),
|
||
projects: page?.data.projects ?? [],
|
||
skills: s.one("skills")?.data,
|
||
education: s.one("education")?.data,
|
||
socials: settings?.socials ?? [],
|
||
updated,
|
||
};
|
||
}
|