From dc03631a05ba93b463855abc9e027fd16f872eb4 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Tue, 8 Sep 2026 15:42:18 +0000 Subject: [PATCH 1/2] Declare a showcase frame for the hqtui.com apps gallery hqtui.com/apps captures screenshots of applications built on the library. The capture script takes an application directory and imports `scripts/showcase.ts` from it, because only the application knows what a good state looks like. A fixture rather than a live board. The test suite already drives the client against a real server, and a screenshot needs the opposite property: it has to be identical on every capture, or the image churns in every diff and nobody can review what changed. Built from the real exported ForumNode and TopicSummary with no casts, so this stops compiling if the view model moves. The topics screen rather than the forum list, because it is the one that shows the state the view actually encodes -- unread, solved, locked, selection, reply counts and relative ages. Build-time fixture only; nothing here ships. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_017Df2FNu5DhinMV2soRz3cy --- scripts/showcase.ts | 110 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 scripts/showcase.ts diff --git a/scripts/showcase.ts b/scripts/showcase.ts new file mode 100644 index 0000000..0a8b8cc --- /dev/null +++ b/scripts/showcase.ts @@ -0,0 +1,110 @@ +/** + * Frames for the hqtui.com apps showcase. + * + * hqtui.com/apps captures screenshots of applications built on the library. The + * capture script takes an application directory and imports this file, because + * only the application knows what a good state looks like. + * + * A fixture rather than a live board: the test suite already drives the client + * against a real server, and a screenshot needs the opposite property. It has + * to be the same on every capture, or the image churns in every diff and + * nobody can review what actually changed. + * + * Built from the real exported types with no casts, so this stops compiling if + * the view model moves underneath it. + */ +import type { ForumNode, TopicSummary } from '@tsbb/client'; +import { initialState, type State } from '../apps/tui/src/state.ts'; +import { renderApp } from '../apps/tui/src/views.ts'; + +const DAY = 86_400_000; +const NOW = Date.parse('2026-09-08T15:00:00.000Z'); + +const forum = ( + id: number, + slug: string, + name: string, + description: string, + topics: number, + posts: number, +): ForumNode => ({ + id, + slug, + name, + kind: 'forum', + description, + topics, + posts, + children: [], +}); + +const topic = ( + id: number, + title: string, + author: string, + replies: number, + views: number, + ageDays: number, + over: Partial = {}, +): TopicSummary => ({ + id, + slug: `t${id}`, + title, + kind: 'topic', + locked: false, + solved: false, + replies, + views, + createdAt: NOW - ageDays * DAY, + lastPostAt: NOW - Math.floor(ageDays * DAY * 0.4), + author, + lastPoster: author, + unread: false, + url: `/t/${id}`, + ...over, +}); + +const FORUMS: ForumNode[] = [ + forum(1, 'announcements', 'Announcements', 'Releases and breaking changes', 14, 92), + forum(2, 'help', 'Help & Support', 'Questions about using hqtui', 186, 1043), + forum(3, 'showcase', 'Showcase', 'What you built with it', 47, 312), + forum(4, 'ports', 'Language Ports', 'Rust, Go, Python, Zig, C++, COBOL', 63, 508), + forum(5, 'meta', 'Meta', 'About the board itself', 9, 41), +]; + +const TOPICS: TopicSummary[] = [ + topic(101, '0.3.0: styled text spans', 'anthony', 12, 840, 0.2, { unread: true }), + topic(102, 'Braille glyphs render wide in headless Chrome', 'anthony', 6, 219, 1.1, { solved: true }), + topic(103, 'Collapsed borders across the language ports', 'kai', 23, 1102, 2.4), + topic(104, 'Anyone using hqtui for a TUI file manager?', 'rin', 31, 1876, 4.0), + topic(105, 'RFC: inline viewports and insertBefore', 'anthony', 18, 964, 5.5), + topic(106, 'Zig 0.16 removed getenv — port build broken', 'mara', 9, 402, 7.2, { locked: true }), + topic(107, 'Show: a REST client whose requests are files', 'anthony', 27, 2301, 9.8), +]; + +const STATE: State = { + ...initialState('https://bbs.hqtui.com'), + boardName: 'hqtui bbs', + me: { authenticated: true, user: { id: 1, username: 'anthony', displayName: 'Anthony', postCount: 412 }, unread: 3 }, + screen: 'topics', + forums: FORUMS.map((node) => ({ node, depth: 0 })), + topics: TOPICS, + forumName: 'Help & Support', + forumSlug: 'help', + selected: 2, + status: '7 topics · 186 in this forum', +}; + +const WIDTH = 118; +const HEIGHT = 30; + +export const frames = [ + { + name: 'tsbb', + width: WIDTH, + height: HEIGHT, + draw: ({ ui, height }: { ui: Parameters[0]; height: number }) => { + renderApp(ui, STATE, WIDTH, height); + }, + }, +]; From 7c5cb1d2ebfa11ad4e33de527e564930cdf47ab1 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Tue, 8 Sep 2026 15:42:59 +0000 Subject: [PATCH 2/2] Typecheck scripts/ as well The showcase frame is written against the real exported types precisely so it stops compiling when the view model moves. That only works if the project actually compiles it, and the include list stopped at test/. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_017Df2FNu5DhinMV2soRz3cy --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 1508e6b..24333c0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -35,6 +35,6 @@ "@tsbb/plugin-host": ["packages/plugin-host/src/index.ts"] } }, - "include": ["packages/**/*.ts", "apps/**/*.ts", "plugins/**/*.ts", "test/**/*.ts"], + "include": ["packages/**/*.ts", "apps/**/*.ts", "plugins/**/*.ts", "test/**/*.ts", "scripts/**/*.ts"], "exclude": ["node_modules", "**/node_modules", "**/dist"] }