diff --git a/docs/seed-kits/dark/01-list.png b/docs/seed-kits/dark/01-list.png new file mode 100644 index 0000000..e68e080 Binary files /dev/null and b/docs/seed-kits/dark/01-list.png differ diff --git a/docs/seed-kits/dark/02-create-form.png b/docs/seed-kits/dark/02-create-form.png new file mode 100644 index 0000000..a7a154a Binary files /dev/null and b/docs/seed-kits/dark/02-create-form.png differ diff --git a/docs/seed-kits/dark/03-apply-dialog.png b/docs/seed-kits/dark/03-apply-dialog.png new file mode 100644 index 0000000..55fb13f Binary files /dev/null and b/docs/seed-kits/dark/03-apply-dialog.png differ diff --git a/docs/seed-kits/01-list.png b/docs/seed-kits/light/01-list.png similarity index 100% rename from docs/seed-kits/01-list.png rename to docs/seed-kits/light/01-list.png diff --git a/docs/seed-kits/02-create-form.png b/docs/seed-kits/light/02-create-form.png similarity index 100% rename from docs/seed-kits/02-create-form.png rename to docs/seed-kits/light/02-create-form.png diff --git a/docs/seed-kits/03-apply-dialog.png b/docs/seed-kits/light/03-apply-dialog.png similarity index 100% rename from docs/seed-kits/03-apply-dialog.png rename to docs/seed-kits/light/03-apply-dialog.png diff --git a/packages/web/scripts/screenshot-seed-kits.mjs b/packages/web/scripts/screenshot-seed-kits.mjs index 2f45a33..cfbe791 100644 --- a/packages/web/scripts/screenshot-seed-kits.mjs +++ b/packages/web/scripts/screenshot-seed-kits.mjs @@ -1,94 +1,104 @@ // One-off screenshot capture for PR documentation. // Usage: BASE_URL=http://localhost:5177 node scripts/screenshot-seed-kits.mjs +// +// Produces both light- and dark-mode variants for each panel into +// docs/seed-kits/{light,dark}/. import { mkdir } from "node:fs/promises"; import { resolve } from "node:path"; import { chromium } from "@playwright/test"; const BASE_URL = process.env.BASE_URL ?? "http://localhost:5177"; -const OUT_DIR = resolve(process.cwd(), "docs/seed-kits"); -await mkdir(OUT_DIR, { recursive: true }); +const OUT_ROOT = resolve(process.cwd(), "docs/seed-kits"); -const browser = await chromium.launch(); -const ctx = await browser.newContext({ - viewport: { width: 1440, height: 900 }, - deviceScaleFactor: 2, -}); +const SEED_INSTANCES = { + instances: [ + { id: "neo", name: "Neo (personal)", baseUrl: "http://localhost:8001", token: "" }, + { id: "jeeves", name: "Jeeves (CodeWalnut)", baseUrl: "http://localhost:8002", token: "" }, + ], + activeId: "neo", +}; -await ctx.addInitScript(() => { - window.localStorage.setItem( - "openconcho:instances", - JSON.stringify({ - instances: [ - { id: "neo", name: "Neo (personal)", baseUrl: "http://localhost:8001", token: "" }, - { id: "jeeves", name: "Jeeves (CodeWalnut)", baseUrl: "http://localhost:8002", token: "" }, - ], - activeId: "neo", - }), +const SEED_KITS = [ + { + id: "kit_ben_personal", + name: "Ben — personal core", + description: "Identity facts Ben wants every personal-tier agent to know.", + lines: [ + "Name: Ben Sheridan-Edwards", + "Preferred address: Chief", + "Email: ben@codewalnut.com", + "Role: Founder", + "Github: BenSheridanEdwards", + ], + }, + { + id: "kit_codewalnut_context", + name: "CodeWalnut work context", + description: "Work-tier identity for Jeeves and any future CodeWalnut agents.", + lines: ["Employer: CodeWalnut", "Role: Founder", "Reports to: (self)"], + }, +]; + +async function captureTheme(browser, theme) { + const outDir = resolve(OUT_ROOT, theme); + await mkdir(outDir, { recursive: true }); + + const ctx = await browser.newContext({ + viewport: { width: 1440, height: 900 }, + deviceScaleFactor: 2, + colorScheme: theme === "dark" ? "dark" : "light", + }); + + await ctx.addInitScript( + ([instances, kits, themeValue]) => { + window.localStorage.setItem("openconcho:instances", instances); + window.localStorage.setItem("openconcho:seed-kits", kits); + window.localStorage.setItem("openconcho:theme", themeValue); + }, + [JSON.stringify(SEED_INSTANCES), JSON.stringify(SEED_KITS), theme], ); - window.localStorage.setItem( - "openconcho:seed-kits", - JSON.stringify([ - { - id: "kit_ben_personal", - name: "Ben — personal core", - description: "Identity facts Ben wants every personal-tier agent to know.", - lines: [ - "Name: Ben Sheridan-Edwards", - "Preferred address: Chief", - "Email: ben@codewalnut.com", - "Role: Founder", - "Github: BenSheridanEdwards", - ], - }, - { - id: "kit_codewalnut_context", - name: "CodeWalnut work context", - description: "Work-tier identity for Jeeves and any future CodeWalnut agents.", - lines: ["Employer: CodeWalnut", "Role: Founder", "Reports to: (self)"], - }, - ]), - ); -}); -const page = await ctx.newPage(); + const page = await ctx.newPage(); -async function shot(name, options = {}) { - const file = resolve(OUT_DIR, `${name}.png`); - await page.screenshot({ path: file, fullPage: false, ...options }); - console.log("wrote", file); + async function shot(name) { + const file = resolve(outDir, `${name}.png`); + await page.screenshot({ path: file, fullPage: false }); + console.log("wrote", file); + } + + // 1. List view with built-ins + user kits + await page.goto(`${BASE_URL}/seed-kits`, { waitUntil: "networkidle" }); + await page.waitForSelector("text=Seed Kits"); + await page.waitForTimeout(400); // settle animations + await shot("01-list"); + + // 2. Create form (use the "New kit" button) + await page + .getByRole("button", { name: /^New kit$/ }) + .first() + .click(); + await page.waitForSelector("text=New seed kit"); + await page.waitForTimeout(300); + await shot("02-create-form"); + + // 3. Back to list, then open apply dialog on the first user kit + await page.goto(`${BASE_URL}/seed-kits`, { waitUntil: "networkidle" }); + await page.waitForSelector("text=Ben — personal core"); + await page.waitForTimeout(400); + const applyButtons = page.getByRole("button", { name: /^Apply$/ }); + // User kits render after the 3 built-ins, so index 3 = first user kit. + await applyButtons.nth(3).click(); + await page.waitForSelector("text=Apply seed kit"); + await page.waitForTimeout(500); + await shot("03-apply-dialog"); + + await ctx.close(); } -// 1. List view with built-ins + user kits -await page.goto(`${BASE_URL}/seed-kits`, { waitUntil: "networkidle" }); -await page.waitForSelector("text=Seed Kits"); -await page.waitForTimeout(400); // settle animations -await shot("01-list"); - -// 2. Create form (use the "New kit" button) -await page - .getByRole("button", { name: /^New kit$/ }) - .first() - .click(); -await page.waitForSelector("text=New seed kit"); -await page.waitForTimeout(300); -await shot("02-create-form"); - -// 3. Back to list, then open apply dialog on the "Ben — personal core" user kit -await page.goto(`${BASE_URL}/seed-kits`, { waitUntil: "networkidle" }); -await page.waitForSelector("text=Ben — personal core"); -await page.waitForTimeout(400); - -// Find the Apply button next to "Ben — personal core" card -const benCard = page.locator("div", { hasText: /^Ben — personal core/ }).first(); -// Just click the visible Apply button on that kit row -const applyButtons = page.getByRole("button", { name: /^Apply$/ }); -const applyCount = await applyButtons.count(); -// User kits are rendered after built-ins; the Ben card is the 4th apply button (0-3 built-ins, 4 = first user kit) -await applyButtons.nth(3).click(); -await page.waitForSelector("text=Apply seed kit"); -await page.waitForTimeout(500); -await shot("03-apply-dialog"); - +const browser = await chromium.launch(); +for (const theme of ["light", "dark"]) { + await captureTheme(browser, theme); +} await browser.close(); console.log("done");