prep for the nook

This commit is contained in:
2026-08-26 17:41:57 -04:00
parent 898c891bd5
commit e4a9be4899
27 changed files with 1234 additions and 20 deletions

View File

@@ -16,7 +16,7 @@ import {
} from "./nav-config";
import { SITE_CONFIG, type SiteId } from "./site-context";
const ALL_SITES: SiteId[] = ["main", "nessa", "lineage", "gaze", "inputhalo"];
const ALL_SITES: SiteId[] = ["main", "nessa", "lineage", "gaze", "inputhalo", "nook"];
describe("NAV_CONFIG — per-site link sets", () => {
it("main → Home, Blog, Downloads, Resume, Contact, GitHub, LinkedIn", () => {
@@ -80,7 +80,7 @@ describe("NAV_CONFIG — href correctness", () => {
});
it("subdomain nav hrefs are public browser paths, never the internal rewritten prefix", () => {
for (const id of ["nessa", "lineage", "gaze", "inputhalo"] as SiteId[]) {
for (const id of ["nessa", "lineage", "gaze", "inputhalo", "nook"] as SiteId[]) {
for (const item of NAV_CONFIG[id]) {
// No subdomain-prefixed paths leak into the public nav.
expect(item.href.startsWith(`/${id}/`)).toBe(false);
@@ -111,7 +111,7 @@ describe("NAV_CONFIG — href correctness", () => {
describe("NAV_CONFIG — auth-scoping by construction", () => {
it("no subdomain nav item sets showLoggedIn / showLoggedOut", () => {
for (const id of ["nessa", "lineage", "gaze", "inputhalo"] as SiteId[]) {
for (const id of ["nessa", "lineage", "gaze", "inputhalo", "nook"] as SiteId[]) {
for (const item of NAV_CONFIG[id]) {
expect(item.showLoggedIn).toBeUndefined();
expect(item.showLoggedOut).toBeUndefined();

View File

@@ -116,6 +116,10 @@ export const NAV_CONFIG: Record<SiteId, NavItem[]> = {
{ label: "Contact", href: "/contact", icon: "contact" },
{ label: "Privacy", href: "/privacy", icon: "privacy" },
{ label: "Downloads", href: "/downloads", icon: "downloads" }
],
nook: [
{ label: "Home", href: "/", icon: "home" },
{ label: "Privacy", href: "/privacy", icon: "privacy" }
]
};

View File

@@ -81,7 +81,7 @@ describe("resolveSiteFromHost", () => {
});
it("every SITE_CONFIG entry has a non-empty baseRoutePrefix for subdomains", () => {
for (const id of ["nessa", "lineage", "gaze", "inputhalo"] as SiteId[]) {
for (const id of ["nessa", "lineage", "gaze", "inputhalo", "nook"] as SiteId[]) {
expect(SITE_CONFIG[id].baseRoutePrefix).toBe(`/${id}`);
expect(SITE_CONFIG[id].subdomain).toBe(id);
expect(SITE_CONFIG[id].titleSuffix).toBe(

View File

@@ -12,7 +12,7 @@
* `src/server/site-context-server.ts` builds on `resolveSiteFromHost`.
*/
export type SiteId = "main" | "nessa" | "lineage" | "gaze" | "inputhalo";
export type SiteId = "main" | "nessa" | "lineage" | "gaze" | "inputhalo" | "nook";
export interface Site {
/** Canonical id, also serialized into `<html data-site>` and `window.__SITE__`. */
@@ -122,6 +122,18 @@ export const SITE_CONFIG: Record<SiteId, Site> = {
brandColor: "#41a5ff",
ogDefaultImage: "/inputhalo/og-default.png",
faviconPath: "/inputhalo/favicon/favicon.ico"
},
nook: {
id: "nook",
subdomain: "nook",
domain: `nook.${BASE_DOMAIN}`,
baseRoutePrefix: "/nook",
displayName: "The Nook",
titleSuffix: " | The Nook",
brandColor: "#8b5cf6",
brandColorDark: "#a78bfa",
ogDefaultImage: "/nook/og-default.png",
faviconPath: "/nook/favicon/favicon.ico"
}
};
@@ -130,7 +142,8 @@ const SUBDOMAIN_SITES: ReadonlyArray<Site> = [
SITE_CONFIG.nessa,
SITE_CONFIG.lineage,
SITE_CONFIG.gaze,
SITE_CONFIG.inputhalo
SITE_CONFIG.inputhalo,
SITE_CONFIG.nook
];
/** Matches `<sub>.localhost` and `<sub>.localhost:<port>` (dev only). */

View File

@@ -146,7 +146,7 @@ describe("SITEMAP_ROUTES validation", () => {
});
it("each site has at least the home page entry", () => {
const siteIds: SiteId[] = ["main", "nessa", "lineage", "gaze", "inputhalo"];
const siteIds: SiteId[] = ["main", "nessa", "lineage", "gaze", "inputhalo", "nook"];
for (const id of siteIds) {
expect(SITEMAP_ROUTES[id].some((e) => e.path === "/")).toBe(true);
}

View File

@@ -77,5 +77,11 @@ export const SITEMAP_ROUTES: Record<SiteId, SitemapEntry[]> = {
{ path: "/", changefreq: "weekly", priority: 1.0 },
{ path: "/contact", changefreq: "monthly", priority: 0.6 },
{ path: "/privacy", changefreq: "yearly", priority: 0.4 }
],
nook: [
{ path: "/", changefreq: "weekly", priority: 1.0 },
{ path: "/checkout", changefreq: "monthly", priority: 0.5 },
{ path: "/privacy", changefreq: "yearly", priority: 0.4 }
]
};