Repository navigation
Add a live demo page and show the mark in the page header - #10
Conversation
ForgeDialog had a README and a manual test page but nothing to point people at. site/ is a landing page with an interactive appearance playground, written in plain HTML, CSS, and browser JavaScript so the site carries no dependencies of its own, matching the library it advertises. The page runs the build from this checkout rather than a CDN: scripts/build-site.mjs copies dist/index.global.js and dist/index.css into site/vendor/, which is git-ignored. It uses only Node built-ins and rewrites no source files. The version badge reads the library's own VERSION export at runtime, so nothing has to be kept in sync by hand. The playground calls instance.update() on every control change, so the dialog restyles while it is open, and it prints the matching source alongside, so the demo doubles as documentation for the appearance API. site/_headers ships a strict CSP for Cloudflare Pages limited to same-origin scripts and styles, which the library already satisfies: test:csp enforces that dist contains no eval or new Function. docs/website.md covers local use and the Cloudflare build settings. Verified in Chromium: no console errors or failed requests, the alert traps focus and returns it to the trigger on Escape, the playground applies a 30px radius and casts its shadow right at 90 degrees, live updates reach an open dialog, and the theme toggle drives the library and the page together. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtJ3nDatGiv7dHjvZL1uZ4
…ise for search and answer engines The site had a landing page and an emoji favicon; it now has a full API reference, a real mark, and the metadata that search engines and answer engines read. Naming: the product is Forge Dialog, two words, and every page and document now says so. Identifiers keep the one-word spelling because that is what they are: the npm package (forgedialog), the browser global (ForgeDialog), the custom element (forge-dialog), and the repository. Nothing under src/ changed, so the published API and its runtime strings are untouched. Docs: site/docs.html is a 23-section reference written against the reviewed API report in etc/, covering every option, method, and entry point. The shared chrome (version badge, theme toggle, copy buttons) moved out of site.js into common.js so both pages use it without the landing page's demo wiring. Icon: site/icon.svg is the source of truth and the favicon browsers load. scripts/build-icons.mjs renders the committed apple-touch-icon.png and og-image.png from it through Chromium, which is already a dev dependency. The touch variant squares off the mark's ground because iOS applies its own mask. The first draft of the OG image used a gradient and cost 296 KB; a flat ground looks the same at preview size and costs 37 KB. SEO: canonical, og:url, and og:image are absolute. The canonical tag in index.html is the single source of truth for the domain — build-site.mjs reads it back to generate sitemap.xml, robots.txt, and llms.txt, so moving the site is an edit to the canonical tags and nothing else. Both pages carry JSON-LD; the FAQ entries are generated from the visible questions so the markup and the page cannot disagree. Answer engines: llms.txt follows the llmstxt.org convention and states the facts models most often get wrong, with the version read from package.json so it cannot drift. robots.txt names the AI crawlers explicitly rather than leaving them to the default, and deliberately does not disallow /vendor/ — blocking a site's own CSS and JS is what breaks rendering for crawlers. Two layout bugs found while measuring, both pre-existing: - The header never wrapped, so at 380px the page scrolled sideways by 102px. - The playground's grid track had an automatic minimum of min-content, which the long code lines inside .snippet pushed open — 812px of horizontal overflow at 320px. Capping the track at minmax(0, 1fr) and giving .snippet min-width: 0 fixes it. Both pages now fit at 320, 380, 480, and 768px with zero horizontal overflow. Verified in Chromium against the production CSP: no console errors and no failed requests on either page, the inline JSON-LD survives script-src 'self' (it is a data block, not an executable script), all 23 sidebar links resolve to real sections, scroll-spy tracks the section being read, the hero alert still gets role="alertdialog" with focus returning to its trigger, and robots.txt, sitemap.xml, llms.txt, and all three icons serve with the right content types. npm run validate and format:check pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtJ3nDatGiv7dHjvZL1uZ4
The Cloudflare Worker was built with `npm run build` and deployed with `wrangler deploy --assets ./dist`, so it uploaded 97 files of compiled library — .mjs, .cjs, .d.ts, .css — with no index.html among them. Workers Assets had nothing to answer `/` with, which is why the domain served nothing. wrangler.jsonc now pins the assets directory to `site/`, the directory `npm run site:build` actually fills, so the configuration lives in the repository rather than in a dashboard field. A deploy command that passes `--assets` overrides it, so docs/website.md says to drop the flag. While verifying the routing, the docs page turned out to be reachable only by redirect. Workers Assets serves `foo.html` at `/foo` and 307s the extension form, and `serve` (which `npm run site` uses) does the same, so every URL naming `/docs.html` — the canonical tag, og:url, the TechArticle and BreadcrumbList nodes, the sitemap entry, the llms.txt link, and the in-page links — pointed at a URL that redirects. A canonical or sitemap entry that redirects is a conflicting signal, so `/docs` is now the URL everywhere, and the docs page links back to `./` rather than `./index.html`. Verified against `wrangler dev` with the production `_headers` CSP: both pages and every asset return 200, every relative link resolves without a redirect, the pages load with no console errors or failed requests, the JSON-LD parses, and the hero alert still opens as `role="alertdialog"` and closes on Escape. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtJ3nDatGiv7dHjvZL1uZ4
A repo-wide pass before the worker is recreated from scratch. An unmatched path got the platform's bare 404, so site/404.html now answers for them through not_found_handling. It links its assets root-relative rather than with "./" because it also answers for nested paths, where a relative href would resolve against the missing directory, and it carries noindex with no canonical tag since it has no URL of its own. The sitemap stamped every entry with the build date, which told crawlers both pages change daily. lastmod now comes from the last commit that touched each page's HTML. A build with no reachable git history writes the entry without a lastmod rather than with a plausible-looking date. npm run check:release reported what the docs had not caught up with: forgedialog 0.7.0 was published on 1 September. docs/releasing.md still said the package was unpublished and framed the manual first publish and the E404 troubleshooting entry as the likely path; both are now scoped to a fork starting from an unpublished name. package.json homepage moves from the README anchor to the site, listed under Unreleased because 0.7.0 is already out and cannot carry it. README no longer calls the deployment Cloudflare Pages. Verified against wrangler dev with the production _headers: /, /docs and every asset return 200; /nope and /deep/nested/nope return 404 with the site's own page, its assets loading and the CSP applied; both pages and the 404 render with no console errors, no failed requests, and zero horizontal overflow at 320, 380, 480 and 768px. npm run validate passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtJ3nDatGiv7dHjvZL1uZ4
main added a wrangler.jsonc pointing `assets.directory` at `./dist`, which is the compiled library — .mjs, .cjs, .d.ts and .css with no index.html — so a deploy from it serves nothing at /. This branch's version, pointing at `./site`, is kept. The conflict is also why CI stopped running here: workflows triggered by `pull_request` build the merge ref, and GitHub cannot compute one for a conflicting PR, so no run was created for the last two pushes. Merging the base back in restores it. "$schema" is left out rather than carried over: it resolves into node_modules, and wrangler is deliberately not a dependency of this package — deploys invoke it through npx. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtJ3nDatGiv7dHjvZL1uZ4
The site advertised the library but barely demonstrated it. The landing page had four hero buttons and the appearance playground; the "examples" section was static code with a Copy button and nothing that ran. The full demo — the one covering drawers, sheets, toasts, the palette, forms and wizards — was demo/index.html at the repository root, which loads ../dist/ directly and is never deployed. site/demo.html runs all of it at /demo, against the same vendored build the rest of the site uses: alert, confirm, prompt, validated prompt, open(), stacking, animation options, drawers on both sides, bottom sheets, three toast tones, the lightbox, loading states, the command palette, the notification centre, form(), wizard(), and formWizard(). Each card pairs a control that really runs with the snippet of the call being made, so the page cannot drift from what it documents — a wrong snippet would show up as a misbehaving button beside it. A plugin registered on the page logs afterOpen and afterClose, and every demo prints its return value, so the result log is also evidence the hooks fire. demo.js uses a single delegated listener keyed by data-demo. The site's CSP is script-src 'self', so inline handlers would be blocked; a demo that throws prints the failure into the log rather than only the console. The mark was only ever a favicon and an apple-touch icon: no page displayed it. It now sits in the header of every page beside the wordmark, with alt="" because the adjacent text already names the product and a screen reader should not announce it twice. The API calls were taken from the reviewed report in etc/ and the manual demo page rather than written from memory, and the global surface was read out of a real browser first, so nothing here calls an export that does not exist. Verified in Chromium against wrangler dev with the production _headers CSP: all 22 demo controls surface what they claim with no console errors and no failed requests, the header mark renders on all four pages, the version badge reads from the library's own export, and every page fits at 320, 380, 480, 768 and 1280px with zero horizontal overflow. npm run validate passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtJ3nDatGiv7dHjvZL1uZ4
PR #9 was squashed onto main as 631f43c, so this branch was restarted from main and the demo work sits on top of it. The remote branch still points at the pre-squash commits, whose content main already carries; recording them as a parent lets this push fast-forward without discarding the branch history a force push would have rewritten. The tree is unchanged by this merge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtJ3nDatGiv7dHjvZL1uZ4
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Team Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
forge-dialog | c83ce5a | Sep 02 2026, 06:35 AM |
Read against autumn.konexforge.com and forgeselect.konexforge.com — their sources, since this environment's egress proxy refuses both hostnames — and closed the gaps that were real rather than cosmetic. The checker is the substantial one. ForgeSelect verifies its built site for broken local links; scripts/check-site.mjs does that and the four other things this site has actually got wrong: a fragment naming an id that does not exist on the page it lands on, a link written in the .html form the server answers with a redirect, JSON-LD that does not parse or an FAQPage whose questions have drifted from the visible ones, and a page missing a canonical, title, description or og:image — plus a 404 that declares a canonical or forgets noindex, and any disagreement between pages about the canonical origin. Each rule was verified by breaking the site and watching it fail, not by watching it pass. It runs at the end of site:build, so a broken site fails the Cloudflare deploy instead of reaching the domain. Entity graph: an Organization node for KonexForge, referenced as the site's publisher and the software's author. Both sibling sites are under the same domain, and a shared @id is what lets a search engine treat them as one publisher's products rather than three unrelated pages. Positioning: the FAQ answered how the library differs from window.alert but named no library. It now answers the comparison people actually search for — SweetAlert2 and Bootstrap modals — factually: the native dialog element does the focus and layering work, there are no runtime dependencies where a Bootstrap modal needs Bootstrap, and an alert-only build is about 5.5 KB. Metadata parity with the siblings: robots, author, explicit twitter:title, twitter:description and twitter:image rather than relying on the og: tags being inherited, og:image:type, rel=sitemap, and og:locale corrected from "en" to the en_US form the property actually takes. favicon.ico, rendered from the same icon.svg as every other icon: a 32×32 PNG in an ICO container, which needs no bitmap encoder and costs 1.2 KB. Clients request that path whatever the markup says. build-icons.mjs writes it alongside the other two and reproduces all three byte-for-byte. Deliberately not adopted: meta keywords. Both siblings carry one and Google has ignored it for years; the competitor terms belong in the visible FAQ answer, where they are also true, and that is where they went. Verified in Chromium against wrangler dev with the production _headers CSP: all four pages carry the new tags in the live DOM, /favicon.ico serves as image/vnd.microsoft.icon, the four schema types on the landing page parse with Organization among them, and every page still fits at 320, 380 and 768px with zero horizontal overflow and no console errors. npm run validate passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtJ3nDatGiv7dHjvZL1uZ4
Autumn Note ships its site in English and Vietnamese under /vi/; this one did not. All three pages now do: /vi/, /vi/demo, and /vi/docs, translations of the English pages rather than different content, mirroring them section for section and keeping the same element ids so the scripts drive both languages. Nothing user-visible stayed hard-coded in those scripts. site.js, demo.js and common.js now read their strings from a JSON data block in the page, falling back to English — a data block rather than an inline script, because the site's CSP is script-src 'self' and real inline code would be blocked. The block's id is prefixed: "i18n" alone is already a section id on the docs page, and getElementById would have found that section instead. Nothing broke on that today, since the docs page loads neither script, but it was a trap set for whoever added one. common.js also passes the page's `labels` to the library's own setLabels(), so a dialog opened from a Vietnamese page says Huỷ and Gửi rather than Cancel and Submit. The theme toggle and copy buttons read their four strings from data- attributes for the same reason. The code shown beside each demo is translated too: the snippet has to be the call actually made, or the page stops documenting itself. hreflang: every page declares en, vi and x-default, and the sitemap repeats the set as xhtml:link alternates on all six entries, as Autumn's does. Assets on a /vi/ page are linked root-relative, because the page sits a directory down and "./" would resolve inside /vi/. check-site.mjs gained the hreflang rules, and they earned their place immediately: writing this, both /vi/demo and /vi/docs shipped a language switcher still marking EN as current, because the replacement that flips it silently matched nothing. The checker now fails on a one-way annotation, a missing x-default, and a page whose hreflang set omits its own canonical — each verified by breaking the site and watching it fail. None of the three is visible in a browser. Verified in Chromium against wrangler dev with the production CSP: all six pages return 200 with the right lang attribute, the switcher marking the right side, the localised theme label, the mark rendered, and the version badge read from the library's own export — with zero console errors, zero failed requests, and zero horizontal overflow at 320 and 768px. The Vietnamese demo opens a Vietnamese dialog with Vietnamese buttons while the English one is unchanged. npm run validate passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MtJ3nDatGiv7dHjvZL1uZ4
The red
|
PR #10 was squashed onto main as 19a9303, so this branch was restarted from main and the package split sits on top of it. The remote branch still points at the pre-squash commits, whose content main already carries; recording them as a parent lets this push fast-forward without rewriting history. The tree is unchanged by this merge.
Summary
The site advertised the library but barely demonstrated it, and never displayed its own mark.
Demos. The landing page had four hero buttons and the appearance playground; its "examples" section was static code with a Copy button and nothing that ran. The full demo — drawers, sheets, toasts, the palette, forms, wizards — was
demo/index.htmlat the repository root, which loads../dist/directly and is never deployed.site/demo.htmlruns all of it at/demo, against the same vendored build the rest of the site uses:alert,confirm,prompt, a validated prompt,open(), stacking,animation: 'none'and'slide', drawers on both sides, bottom sheets, three toast tones, the lightbox, loading states, the command palette, the notification centre,form(),wizard(), andformWizard().Each card pairs a control that really runs with the snippet of the call being made, so the page cannot drift from what it documents — a wrong snippet would show up as a misbehaving button beside it. A plugin registered on the page logs
afterOpenandafterClose, and every demo prints its return value, so the result log is also evidence the hooks fire.demo.jsuses a single delegated listener keyed bydata-demo. The site's CSP isscript-src 'self', so inline handlers would be blocked; a demo that throws prints the failure into the log rather than only the console.The mark.
site/icon.svgwas only ever a favicon and an apple-touch icon — no page displayed it. It now sits in the header of every page beside the wordmark, withalt=""because the adjacent text already names the product and a screen reader should not announce it twice.No library code changed. Nothing under
src/was touched, so there is no API, runtime, or accessibility impact on the published package.Where the API calls came from
They were taken from the reviewed report in
etc/and fromdemo/index.html, not written from memory, and the global surface was read out of a real browser first (Object.keys(window.ForgeDialog)) so nothing here calls an export that does not exist. That check is also what surfacedform,formWizard,lightbox,loading,notificationCenter,getNotificationHistory, andclearNotificationHistoryas demo-worthy — the root demo page covers none of them.Wiring
/demois in the nav on every page, insitemap.xmlandllms.txt(via thepageslist inscripts/build-site.mjs), and carriesWebPage+BreadcrumbListJSON-LD. Like/docsit is the extensionless URL, because Workers Assets and the local server both serve that form and redirect the other.Branch history
PR #9 was squashed onto
mainas631f43c, so this branch was restarted frommainwith the demo work on top. The remote branch still pointed at the pre-squash commits, whose contentmainalready carries. A force push was declined by policy, so those commits are recorded as a merge parent with-s oursinstead — the tree is byte-identical before and after that merge, and the diff againstmainis only the nine files below.Verification
npm run validatenpm run test:e2e— not run locally (the pinned Playwright wants a browser build this container does not have). It drivesdemo/index.htmland the library, neither of which changed. CI runs it.Driven in Chromium against
wrangler dev, so the routing and the production_headersCSP are the real ones:naturalWidth150, displayed at 26px) — checked as rendered, not merely present in the markup/,/demo,/docsreturn 200 and an unmatched path returns 404 with the site's own pagev0.7.0from the library's own export on every pageChecklist
npm run changeset) — not applicable: nothing in the published package changes, andsite/is not published.npm run sizeand the tarball check pass unchanged (120.3 KiB, 71 files).demo/index.html, which the screenshot test drives, is unchanged.Screenshots
Verified in the browser run rather than captured: the demo page's card grid at desktop and 320px, the header with the mark beside the wordmark, and each surface as its button was clicked.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MtJ3nDatGiv7dHjvZL1uZ4
Generated by Claude Code