diff --git a/packages/schema/src/types.ts b/packages/schema/src/types.ts index a46bb6a..21af330 100644 --- a/packages/schema/src/types.ts +++ b/packages/schema/src/types.ts @@ -475,6 +475,7 @@ export const siteSettings = def({ lockup: line({ title: "Lockup line" }), location: line({ title: "Location" }).optional(), email: line({ title: "Email", description: "Printed on the resume PDF." }).optional(), + replyTime: line({ title: "Reply time", description: "How soon you answer inquiries, like 2 days." }).optional(), availability: line({ title: "Availability", description: "Shown on the resume and Inquiries, like Open to freelance web work." }).optional(), socials: z .array(z.object({ label: line({ title: "Label" }), handle: line({ title: "Handle" }), url: z.url().meta({ title: "Link" }) })) diff --git a/services/site/src/lib/content.ts b/services/site/src/lib/content.ts index e4bfc0d..42c7f24 100644 --- a/services/site/src/lib/content.ts +++ b/services/site/src/lib/content.ts @@ -6,6 +6,7 @@ * background, so a saved note shows within a minute and a slow or restarting * content service never takes a page down: the last good copy keeps serving. */ +import { env } from "./env.ts"; import type { NoteData, NoteType } from "@gk/schema"; import { SiteIndex } from "./site.ts"; @@ -27,7 +28,6 @@ export interface Redirect { toPath: string; } -const env = (k: string, fallback?: string) => process.env[k] ?? import.meta.env[k] ?? fallback; const baseUrl = () => (env("CONTENT_URL", "http://localhost:4310") as string).replace(/\/$/, ""); const token = () => env("CONTENT_TOKEN", "") as string; /** Preview only: include unpublished notes. Needs an editor or admin token; never set in production. */ diff --git a/services/site/src/lib/env.ts b/services/site/src/lib/env.ts new file mode 100644 index 0000000..29c2852 --- /dev/null +++ b/services/site/src/lib/env.ts @@ -0,0 +1,12 @@ +/** + * Server settings, read from process.env at run time only. Never read secrets + * through import.meta.env: Vite replaces it at build time and can copy every + * value, secrets included, into the built bundle. Set variables in the + * environment (Docker env_file, or the shell when running locally). + */ +export function env(key: string): string | undefined; +export function env(key: string, fallback: string): string; +export function env(key: string, fallback?: string): string | undefined { + const v = process.env[key]; + return v === undefined || v === "" ? fallback : v; +} diff --git a/services/site/src/pages/inquiries/index.astro b/services/site/src/pages/inquiries/index.astro index 0b24410..abfeb8f 100644 --- a/services/site/src/pages/inquiries/index.astro +++ b/services/site/src/pages/inquiries/index.astro @@ -7,6 +7,7 @@ import Seal from "@gk/ui/components/Seal.astro"; import Star from "@gk/ui/components/Star.astro"; import StatusPill from "@gk/ui/components/StatusPill.astro"; import ChoicePills from "../../components/work/ChoicePills.astro"; +import { env } from "../../lib/env.ts"; import { site } from "../../lib/page.ts"; import { inquiryTypes, parseInquiryType, type InquiryType } from "../../lib/work.ts"; @@ -15,7 +16,7 @@ const settings = s.settings(); const text = s.pageText("/inquiries"); const selected = parseInquiryType(Astro.url.searchParams.get("type")); const lede = text?.data.lede ?? "Roles, freelance web work or a custom Patiun order. Pick one and the form asks the right questions."; -const quickFacts = text?.data.quickFacts?.map((f) => f.text) ?? ["Replies within [PLACEHOLDER] days", "Read by me, not a bot"]; +const quickFacts = text?.data.quickFacts?.map((f) => f.text) ?? [`Replies within ${s.settings()?.replyTime ?? "a few days"}`, "Read by me, not a bot"]; const socials = settings?.socials ?? []; const placeholders: Record = { @@ -29,7 +30,6 @@ const timing = [ { value: "within-a-month", label: "Within a month" }, { value: "date", label: "A specific date" }, ]; -const env = (k: string) => (process.env[k] ?? import.meta.env[k]) as string | undefined; const turnstileKey = env("PUBLIC_TURNSTILE_SITE_KEY") ?? env("TURNSTILE_SITE_KEY"); --- diff --git a/services/site/src/pages/inquiries/sent.astro b/services/site/src/pages/inquiries/sent.astro index eddf0cc..716faab 100644 --- a/services/site/src/pages/inquiries/sent.astro +++ b/services/site/src/pages/inquiries/sent.astro @@ -12,7 +12,9 @@ import Star from "@gk/ui/components/Star.astro"; import TickRing from "@gk/ui/components/TickRing.astro"; import TickScale from "@gk/ui/components/TickScale.astro"; import { inquiryTypes, parseInquiryType, parseSentSummary } from "../../lib/work.ts"; +import { site } from "../../lib/page.ts"; +const replyTime = (await site().catch(() => null))?.settings()?.replyTime ?? "a few days"; const sent = parseSentSummary(Astro.cookies.get("gk-inquiry")?.value); if (sent) Astro.cookies.delete("gk-inquiry", { path: "/" }); Astro.response.headers.set("Cache-Control", "private, no-store"); @@ -38,7 +40,7 @@ const steps = [ Inquiry sent

Your note is on its way

-

Thanks{firstName ? `, ${firstName}` : ""}. I read every inquiry myself and reply within [PLACEHOLDER] days.

+

Thanks{firstName ? `, ${firstName}` : ""}. I read every inquiry myself and reply within {replyTime}.

    { steps.map((st, i) => ( diff --git a/tools/migrate/src/seed.ts b/tools/migrate/src/seed.ts index 76832e4..8d02627 100644 --- a/tools/migrate/src/seed.ts +++ b/tools/migrate/src/seed.ts @@ -20,6 +20,8 @@ export const site = { email: "greg@gregkilmer.com", /** Resume Interview: open to offers but not looking, so the page says this. */ availability: "Open to freelance web work", + /** Greg, 2026-10-11. */ + replyTime: "2 days", socials: [ { label: "GitHub", handle: "Patiun", url: "https://github.com/patiun" }, { label: "LinkedIn", handle: "Gregory Kilmer", url: "https://www.linkedin.com/in/gregory-kilmer-36646bb5/" },