feat(website): interactive browser playground - #5
Merged
Conversation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ator Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
Add a JSON config editor beside the spec: it takes an openapi-ng config
body (emit, mappedTypes, responseTypeMapping, naming), drops input and
output with a note, and lowers "/…/flags" strings into the {source,
flags} shape the wrapper needs, since JSON cannot carry a RegExp.
Diagnostics move into a scrolling console card under the panes, and the
page hands the viewport below the title to the panes so only they
scroll. Starlight's auto inline margins made the content container a
content-sized flex item, so its width tracked the widest generated
file; pin it to 100%. CodeMirror and the highlight.js theme each own
their scrolling, so drop the wrapper scrollers that fought them.
Remove the share link: it earned little next to the cost of carrying
lz-string and a hash codec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
Warnings were rendered in the body colour, so a dropped cookie parameter read like ordinary chrome next to a red fatal. Colour each line from the diagnostic's own `severity` instead of its position in the list, and give notes their own hue. Use the `-high` tints throughout: the mid-tone red and orange fall to 3.35:1 and 1.62:1 against the console background in the light theme, which a new contrast test now guards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
The output pane rendered each file through highlight.js into a bare <pre>, so it had no line numbers, no search, and re-highlighted the whole file on every regeneration. Swap it for a read-only CodeMirror view in TypeScript mode, which also renders only the viewport. The theme and token mapping move to theme.ts and are shared by all three panes; the highlight.js runtime is gone, its GitHub stylesheets stay as the colour source. Non-editable content is not focusable by default, so the view gets a tabindex for the search keymap to reach it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
Pasting was the only way in. Add an "Open file…" button backed by a hidden file input, and replace the document when a file is dropped on an editor: CodeMirror's default handler would splice the file in at the cursor and merge two specs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
The playground sat in the sidebar, so following that link dropped the reader onto a splash page where the sidebar disappears. Override the Starlight header with a Docs / Playground switch next to the site title, marking the current section, and take the entry out of the sidebar. Docs points at Getting started, the first page with a sidebar. The playground page drops its own heading and the docs search box, both redundant next to the switch. Below Starlight's mobile breakpoint the header fits only the title and one link, so it shows the way out. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
The config pane accepted plain JSON and a single live option, so every other setting meant a trip to the docs. Parse the config as JSONC and ship a template with mappedTypes, responseTypeMapping and naming commented out at their default values, each with a one-line example of the shape. Enabling all of them must not change the output, which an e2e test checks on petstore and on a spec without tags. The JSON grammar has no comments, so the config editor uses the JavaScript mode. The root element now records the last settled generation so tests can wait for a specific edit instead of the debounce. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
The editors wore highlight.js's GitHub theme while every snippet in the docs is Night Owl on Starlight's grey. Colour the CodeMirror panes from a --pg-* palette copied out of Starlight's bundled Night Owl themes, on the same background tokens Starlight paints its code blocks with, and drop highlight.js altogether. Tokens get plain tok-* classes styled in CSS, so the theme toggle stays a pure CSS switch. Property names share the JSON key colour across YAML, JSON and TypeScript; Night Owl varies it per language, but CodeMirror has a single tag for all three. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
The website's vitest and Playwright files now match ava's default glob, so the root suite tried to run them and failed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
ready() returned as soon as the status landed, ahead of the first run. On a fast machine the run counter was still unset, so the first check passed trivially; on CI the run had settled and the test replaced the config with its identical default, which CodeMirror treats as no change, so nothing regenerated. Wait for the first run, drop the no-op edit and settle after each edit so the debounce cannot merge them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an interactive playground to the docs site at
/playground/: paste or open an OpenAPI spec, edit the generator config as JSONC, and see the generated files in the browser. It runs the@avsystem/openapi-ng-wasm32-wasibuild shipped in #4, so the site needs no backend. Also tracks the StackBlitz demo app instackblitz/and links both from the README.Changes
mappedTypes,responseTypeMappingandnamingcommented out at their defaults."/…/flags"strings are lowered into the{ source, flags }RegExp shape. An e2e test checks that enabling every default leaves the output unchanged.scripts/bundle-engine.mjspre-bundles the napi-rs WASI browser loader intopublic/playground-engine/(gitignored) beforedevandbuild.websitejoins the root pnpm workspace; its own lockfile is removed. The docs workflow now type-checks and runs the unit and Playwright suites, and triggers on lockfile and workspace changes.__test__/**/*.spec.ts, since the website's vitest and Playwright files matched its default glob.stackblitz/and linked from the README next to the playground.Testing
pnpm test(root, ava): 333 passed.website:pnpm buildOK,pnpm check0 errors,pnpm test:unit16 passed,pnpm test:e2e15 passed againstwrangler dev.pnpm lintclean.🤖 Generated with Claude Code
https://claude.ai/code/session_011t8uBVY6h4kfN5cXHXuCpR