import { Component, TFile } from "obsidian"; import { mount } from "svelte"; import App from "../src/ui/app.svelte"; import { DEFAULT_SETTINGS } from "../src/settings"; import type { BeaverCalendarSettings } from "../src/settings"; import { BoardStore } from "../src/vault/store.svelte"; const FIXTURES = ["personal", "work", "reading", "home"]; /** * Settings come off the query string, so a screenshot can start from the * same preferences a real vault has: ?groupBy=due&includeArchive=1&railCollapsed=1 */ function prefsFromQuery(): Partial { const params = new URLSearchParams(location.search); const out: Record = {}; const flag = (value: string): boolean => value === "1" || value === "true"; for (const [key, value] of params) { if (!(key in DEFAULT_SETTINGS)) continue; const current = DEFAULT_SETTINGS[key as keyof BeaverCalendarSettings]; out[key] = typeof current === "boolean" ? flag(value) : value; } return out as Partial; } async function main(): Promise { // Real boards when the server was given a folder, the fixtures otherwise. const index = (await (await fetch("/boards.json")).json()) as { folder: string; names: string[]; } | null; const folder = index?.folder ?? "Boards"; const sources = index ? index.names.map((name) => ({ path: `${folder}/${name}`, url: `/boards/${name}` })) : FIXTURES.map((name) => ({ path: `${folder}/${name}.md`, url: `/tests/fixtures/${name}.md`, })); const files = new Map(); await Promise.all( sources.map(async ({ path, url }) => { const response = await fetch(url); files.set(path, await response.text()); }), ); const handles = new Map( [...files.keys()].map((path) => [path, new TFile(path)]), ); const app = { vault: { getMarkdownFiles: () => [...handles.values()], getAbstractFileByPath: (path: string) => handles.get(path) ?? null, cachedRead: async (file: TFile) => files.get(file.path) ?? "", read: async (file: TFile) => files.get(file.path) ?? "", process: async (file: TFile, fn: (data: string) => string) => { const next = fn(files.get(file.path) ?? ""); files.set(file.path, next); store.queueReload(file.path); return next; }, on: () => ({}), }, workspace: { getLeaf: () => ({}), activeEditor: null }, plugins: { plugins: {} }, }; const settings = { ...DEFAULT_SETTINGS, boardsFolder: folder, ...prefsFromQuery() }; const store = new BoardStore(app as never, settings, () => {}); await store.reloadAll(); mount(App, { target: document.getElementById("app") as HTMLElement, props: { app: app as never, store, settings, component: new Component() as never, }, }); // Scenes for screenshots: open the page with a hash to land in a state. const scene = location.hash.slice(1); if (!scene) return; const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); await wait(50); store.keyboard = true; const first = store.spheres[0]; const tab = async (times: number): Promise => { for (let i = 0; i < times; i += 1) { document.activeElement?.dispatchEvent( new KeyboardEvent("keydown", { key: "Tab", code: "Tab", bubbles: true }), ); await wait(20); } }; if (scene.startsWith("rail")) { store.toggleRail(); store.railExpanded = new Set([first.path, store.spheres[1].path]); if (scene === "rail-some") { store.toggleSphere(store.spheres[2].path); store.toggleLane(first.path, first.projects[0]); store.cursorRail = `lane:${encodeURIComponent(first.path)} ${encodeURIComponent(first.projects[0])}`; } if (scene === "rail-none") store.filterNone(); } // The month grid on its own, opened on the month the fixtures are busiest in. if (scene === "cal") { const months = new Map(); for (const item of store.visible) { const key = (item.due ?? item.scheduled)?.slice(0, 7); if (key) months.set(key, (months.get(key) ?? 0) + 1); } const busiest = [...months.entries()].sort((a, b) => b[1] - a[1])[0]?.[0]; store.view = "calendar"; if (busiest) store.focusDay(`${busiest}-15`); } if (scene.startsWith("peek")) { if (scene === "peek-cal") store.view = "calendar"; if (scene === "peek-notes") store.showDone = true; await wait(20); const task = store.visible.find((item) => item.body.length > 0) ?? store.visible[0]; if (scene === "peek-cal") { const key = task.due ?? task.scheduled; if (key) store.focusDay(key); } store.zone = "task"; store.cursorTask = task.id; await wait(50); store.peek(); } if (scene === "date") { store.write(null, "[data-composer='toolbar']"); await wait(50); await tab(3); } // The editor over an existing task, tabbed through to its date field. if (scene === "edit-date") { const task = store.visible[0]; store.zone = "task"; store.cursorTask = task.id; await wait(20); store.edit(task.id); await wait(50); await tab(3); } } void main();