Add CLAUDE.md

Documents the .razor/.razor.js page-script pattern, shared JS helpers, the BRP backend, and the token-based CSS system.

author
Marijn Besseling <njirambem@gmail.com> · 2026-08-17 16:20 UTC
commit
af51f010d25caee924d52de5c341b5930cc097d9
parent
117e3160b4
tree
browse at this commit

1 file changed +82 -0

CLAUDE.md added +82 -0

CLAUDE.md +82 -0

@@ -0,0 +1,82 @@
1 +# CLAUDE.md
2 +
3 +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4 +
5 +## What this is
6 +
7 +`bes.is` — a Blazor Server app (single ASP.NET Core project, no test project) hosting a
8 +collection of small, mostly self-contained JS/HTML experiments/tools (RPN calculator,
9 +QR code scan/generate, a Netflix→Letterboxd converter, a JSON query playground, BRP
10 +lookup, etc.), each on its own route.
11 +
12 +## Commands
13 +
14 +Run from the repo root or `Blog/`:
15 +
16 +```
17 +dotnet build # build
18 +dotnet run --project Blog # run locally (http://localhost:5296)
19 +dotnet watch --project Blog # run with hot reload
20 +```
21 +
22 +There is no test project in the solution — don't invent `dotnet test` commands or test
23 +files unless asked to add a test project first.
24 +
25 +Publishing is done via the Rider run configuration "Publish Blog to custom server" (self-contained
26 +`linux-x64`, Release, ReadyToRun) — not part of normal dev workflow.
27 +
28 +## Architecture
29 +
30 +**One project, one layout, many independent page-features.** `Blog/Components/Pages/*.razor`
31 +are the routes (`@page "/Xyz"`), each linked from `SiteFooter.razor`. Most pages are a
32 +`.razor` file paired with a `.razor.js` file of the same name — this is the pattern to
33 +follow for any new interactive page.
34 +
35 +### The `.razor` + `.razor.js` pairing
36 +
37 +Blazor's `<PageScript Src="./Components/Pages/Foo.razor.js"/>` (wrapping the built-in
38 +`<page-script>` custom element, registered in `wwwroot/Blog.lib.module.js`) loads a JS
39 +module scoped to that page. The module can export `onLoad`, `onUpdate`, `onDispose`
40 +lifecycle hooks, called as the custom element connects/re-renders/disconnects (this
41 +matters across Blazor's enhanced navigation, which doesn't do a full page reload).
42 +Page logic is written in vanilla JS DOM manipulation, not Blazor data binding — components
43 +grab elements with `getById` and wire up listeners directly in `onLoad`.
44 +
45 +`PageScript.razor`, `Log.razor`, `Panel.razor`, and the `StackOp*.razor` components live in
46 +`Components/_Shared/` and are reused across pages (e.g. `Log` renders a debug/error log
47 +panel that JS writes into via `writeDebug`/`writeError`; `Panel` is a bordered
48 +fieldset-with-legend used for docs/credits/grouped controls).
49 +
50 +### `wwwroot/common.module.js`
51 +
52 +Shared JS helpers imported by page scripts:
53 +- `h(tag, attrs?, children?)` / `t(text)` — a small hyperscript-style DOM builder (no
54 + framework, just `document.createElement`/`appendChild`). Prefer this over manual DOM
55 + building or template strings in new page scripts.
56 +- `getById(id)` — like `document.getElementById` but throws instead of returning null.
57 +- `writeError` / `writeInfo` / `writeDebug` / `resetLog` — write into the `#log` element
58 + that `Log.razor` renders.
59 +- `debounce(fn, wait)`.
60 +
61 +Other `wwwroot/*.js` files (`dactal.js`, `qrcode.js`, `lz-string.module.js`, `jsonql-js/`)
62 +are third-party or semi-vendored libraries used by specific pages (e.g. `Query.razor.js`
63 +uses both `dactal.js` and `jsonql-js` to run two query languages against the same mock
64 +BRP dataset in `wwwroot/brp.json`).
65 +
66 +### BRP feature (the one page with a real backend)
67 +
68 +`BRP.razor`/`.razor.cs` and `BrpTestData.razor` are backed by `Services/BrpService.cs`,
69 +which calls an external "Haal Centraal BRP" lookup API (base address configured in
70 +`Program.cs` as `https://brp.bes.is/`) and caches responses via `HybridCache`
71 +(`Microsoft.Extensions.Caching.Hybrid`). `Models/BRPEntry.cs` and
72 +`Models/RaadpleegMetBurgerservicenummer.cs` model the request/response shapes. Test/mock
73 +data lives in `Resources/test-data.json` and `wwwroot/brp.json`.
74 +
75 +### Styling
76 +
77 +`wwwroot/app.css` is one hand-maintained stylesheet (no CSS framework, no build step),
78 +organized into numbered sections (Tokens → Reset/base → Typography → Layout → Controls →
79 +Components → Media) with CSS custom properties as the single source of design tokens
80 +(colors, spacing scale, fonts). It uses `light-dark()` and `color-scheme` for automatic
81 +dark mode — don't hardcode light/dark colors, extend the token set in section 1 instead.
82 +`MainLayout.razor.css` holds the one layout-specific scoped stylesheet.