Skip to content

site: Forge redesign — landing, blog, playground, mobile#2648

Merged
borisbat merged 20 commits into
masterfrom
feat/website-forge-redesign
May 13, 2026
Merged

site: Forge redesign — landing, blog, playground, mobile#2648
borisbat merged 20 commits into
masterfrom
feat/website-forge-redesign

Conversation

@borisbat
Copy link
Copy Markdown
Collaborator

Summary

End-to-end visual + UX redesign of daslang.io ("Forge" — dark #0d0c0a background, amber #e8a13a accent, Inter Tight + JetBrains Mono) across every surface the user sees:

  • Landing (site/index.html) — new hero with a live CodeMirror editor + sample picker (hello/fib/generic), three-tier execution story, benchmarks panel sourcing live data from borisbat/dasProfile, install/embed dual-tab block, news strip generated from _news/*.md.
  • Blog (site/blog/) — new Markdown pipeline (build_blog.py) renders 25 posts + an Atom feed from _posts/*.md. Forge-themed code blocks tokenized by highlight.js for daslang. Disqus comments under each post (legacy dascf-blog shortname, identifier pinned to slug; dark theme picked up via :root { color-scheme: dark }).
  • Playground (site/playground/) — unified single-toolbar IDE: multi-file tab strip (main.das non-deletable, +/×/rename), Select-example dropdown, ↗ share popover (compressed #z= hash + is.gd shortener), ▶ run via MEMFS write loop, draggable code | output splitter (persists to localStorage). 250 ms debounced autosave; URL-hash priority over autosave for first load. Both legacy #code= (hero handoff) and #z= multi-file hash formats accepted.
  • Mobile (<768 px) — pure CSS + tiny synchronous gate scripts. Hero swaps to a static <pre><code class="language-daslang"> block (CM never inits). /playground/ shows an "Open this on a laptop" notice with zero WASM fetched (verified by a network-level Playwright spec). ≡ hamburger menu replaces the inline nav links.
  • Sphinx docs (doc/source/conf.py + theme) — retokened to match Forge palette (dark bg, amber active sidebar, JetBrains Mono code). version bumped to 0.6.2 for parity with the site.
  • CodeMirror unification — single daslang mode shared by hero + playground (site/files/cm/). Removed legacy eclipse.css/codemirror.{min.js,css} mirrors from web/ui/src/ (~232 KB no longer copied per CI deploy).

Tests + CI

  • New Playwright e2e suite under site/tests/playground/ — 28 specs covering dropdowns, tab CRUD, multi-file persistence, share-URL round-trip with real is.gd mocking, splitter drag (real page.mouse.down/move/up), hero ↗ playground handoff, mobile-gate WASM short-circuit. 5 specs tagged @wasm for the WASM-dependent run flow.
  • New CI workflow .github/workflows/playground-e2e.yml runs the no-WASM subset on every PR (~5 s).

File-tree impact

 117 files changed, ~9.3k insertions, ~2k deletions

Hand-authored sources are committed; build artifacts (blog/<slug>.html, news/, changelist.html, files/wasm/, files/news.json, doc/) are generated and gitignored. The (already-updated) site/README.md is the canonical guide.

Test plan

Most surfaces have a Playwright spec; the manual checks below cover what specs don't.

  • Local landingcd site && python3 -m http.server 8000, open /. Hero editor types/runs hello.das; sample tabs swap; ↗ playground opens /playground/#code=... populated with current buffer; ▶ run prints (requires WASM artifact, see README).
  • Benchmarks — § 02 chart renders for both Interpreted and AOT · JIT categories; rows match the profile_results.json snapshot fetched from borisbat/dasProfile.
  • News + changelistpython3 site/blog/build_blog.py .... § 05 on landing shows top 5 from _news/*.md; /changelist.html shows the full list. The 2026-02-28 RC entry reads cleanly (no double label).
  • Blog post — open /blog/quality-of-life.html. Forge nav at top, syntax-highlighted code blocks, Disqus thread at the bottom in dark mode.
  • Playground — open /playground/. Add a file via +, rename, delete. ↗ share copies a #z=… URL; pasting it in a fresh window restores both tabs. Drag the splitter, double-click to reset. Run the "Macros (multi-file)" sample to confirm require for_loop_macro_mod resolves across MEMFS.
  • Mobile — Cmd+Shift+M in Chrome → iPhone preset. Landing hero is the static block, no CM init. /playground/ shows the notice (DevTools Network tab: zero daslang_static.{js,wasm} requests). Tap ≡ to confirm the nav dropdown opens with all 5 links.
  • Playwrightcd site/tests/playground && npx playwright test --grep-invert "@wasm" → 28 specs green (hero-handoff has retries: 1 for a two-window parallelism race).
  • CI.github/workflows/playground-e2e.yml green; pages.yml builds clean (no references to the deleted eclipse.css / codemirror.{min.js,css} orphans).
  • Sphinxsphinx-build -W --keep-going -b html doc/source build/site succeeds with zero warnings; rendered docs show version 0.6.2 in the sidebar.

🤖 Generated with Claude Code

borisbat and others added 14 commits May 13, 2026 12:28
Lands the new "Forge" design across the daslang.io site and replaces three
mismatched highlighters with one CodeMirror mode driven by the canonical
lexer keyword set.

Site:
- Landing rewrite (forge.css/forge.js/index.html): Forge tokens, hero
  terminal panel with three live samples, dasProfile bench renderer,
  install tabs, news feed, ecosystem footer.
- /playground/ skinned in Forge (forge-skin.css over web/ui's main.css).
- Blog: 25 posts migrated from borisbat/dascf-blog with Hexo-style
  front matter, build_blog.py renders HTML + RSS + changelist.
- /news/ from _news/*.md (27 entries, oldest 2019 -> newest 2026-05-09).
- /downloads.html for binary releases.

Highlighters unified:
- Vendored CodeMirror 5.65.16 + simple-mode addon under site/files/cm/.
- Single keyword module (daslang-keywords.js) sourced from ds2_lexer.lpp
  (105 reserved words); used by both daslang-mode.js (CodeMirror) and
  highlight.js (blog tokenizer).
- cm-forge.css theme maps CM token classes to Forge tokens; replaces
  the eclipse theme + JS-heuristic mode previously used by /playground/.
- Hero editor is now a CodeMirror instance (drops ~150 lines of
  contenteditable wiring); "playground" button trampolines current
  source into /playground/ via #code= URL hash.
- Pygments daslang lexer in doc/source/daslang.py refreshed:
  removed move/move_new/nothing (no longer real), added
  capture/static_elif/template/const/default/typedecl/uninitialized.

Sphinx docs reskinned via doc/source/_static/custom.css + forge-logo.

CI (.github/workflows/pages.yml): builds WASM via Emscripten, copies
site/files (including cm/ bundle), renders blog + news, snapshots
dasProfile JSON, drops everything into the Pages artifact.
Phase 1 of the playground multi-file plan: lock the test harness shape
before the real features land. No production code touched.

- site/tests/playground/ — Playwright config + fixtures + one smoke spec
  asserting the page loads with the Forge-themed CodeMirror instance and
  the daslang mode is tokenizing source.
- .github/workflows/playground-e2e.yml — PR + branch-push CI gate. Builds
  the site without WASM (skipping the 5-10 min Emscripten step), boots
  python -m http.server against _site/, runs the suite minus any spec
  tagged @wasm. Uploads playwright-report/ on failure.
- site/.gitignore — tests/playground/{node_modules,playwright-report,
  test-results,blob-report}/
- .gitignore — .playwright-mcp/ scratch dir from the local MCP

Subsequent phases will land their specs alongside their features
(dropdowns, tabs, share button, hero handoff).
Phase 2: the Examples + Tests <select>s were populated correctly but
never had a change handler, so picking an option did nothing. selectSample
itself had a latent bug — `vv !== NaN` is always true, so any non-numeric
value would crash on the lookup.

- Add `onchange="selectSample('examples'|'tests')"` to both <select>s.
- Fix the NaN check (`!Number.isNaN`) and validate the index range up
  front; bail cleanly on the "Select..." sentinel.
- Refactor selectSample to load every entry of `files[]` in parallel
  (samples have always shipped a multi-file schema even though loaders
  only ever read files[0]). The bundle is handed to a new `loadSample`
  helper that surfaces main.das (or the first file) in the single CM
  instance and stashes the full bundle on window for phase 3's tab strip
  to pick up.
- web/ui/src/main.js is the canonical source — site/playground/main.js
  is a gitignored CI re-sync, so the patch goes upstream.
- site/tests/playground/dropdowns.spec.js asserts both dropdowns swap
  the editor buffer and the sentinel-reset behavior holds.
Phase 3: the playground now edits multiple files. CodeMirror.Doc per file,
editor.swapDoc on tab click, full add/delete/rename UI, localStorage
autosave, URL-hash override.

Tab strip (replaces the hardcoded main.das label in the toolbar):
- Click tab → switch active buffer (in-place class toggle to avoid
  destroying the DOM mid-dblclick).
- Click + → adds untitled{N}.das, switches to it.
- Double-click name → inline rename input; Enter commits, Escape cancels.
- Click × → confirm if non-empty, delete, fall back to main.das.
- main.das is fixed: × disabled, rename rejected, delete refused.

Multi-file run (main.js): runCode iterates every pgState file via
FS.writeFile before Module.callMain('main.das'). Same MEMFS, same
require resolution, just N files instead of one.

URL hash + autosave priority:
- `#code=<percent>` (hero handoff) → wrapped into main.das.
- `#z=<lz-base64>` (share button — phase 6) → full multi-file payload.
- localStorage `daslang.playground.state.v1` autosaves debounced (250ms),
  restored only when no hash is present.
- pgRestoredFromState flag tells main.js to skip its default
  selectSample("examples", 0), which otherwise async-clobbers the
  restored state ~200ms after page load.

playground-init.js extended: dispatches on hash prefix, stashes payload
to __pendingSampleBundle for pgInit to pick up.

forge-skin.css: .pg-tab / .pg-tab--active / .pg-tab__close /
.pg-tab__rename / .pg-tab__add styling using Forge tokens.

Specs (all green, 15/15 in the full suite):
- tabs.spec.js: 8 cases covering add / switch / rename / delete /
  main-protection / dialog flows.
- persistence.spec.js: 2 cases for 3-file reload survival + hash
  override.
Phase 4: vendors tutorials/macros/09_for_loop_macro.das + its companion
for_loop_macro_mod.das into web/ui/samples/examples/macros/ and registers
the pair as "Macros (multi-file)" in samples/data.json. Picking it from
the Examples dropdown populates both tabs.

This is the wedge case for multi-file: macros must live in a separate
module from the one that uses them, so a single-file playground simply
cannot demonstrate them. Running the sample emits the `for ((k,v) in tab)`
expansion — a real macro module compiled live in the browser.

macro-sample.spec.js covers three cases:
- two tabs appear after picking the sample (no-WASM)
- main.das contains `require for_loop_macro_mod` + macro syntax (no-WASM)
- ▶ run produces section-3 output `apple => 10` (@wasm-tagged; skipped
  by the no-WASM CI gate)
Phase 5: the runCode loop landed back in phase 3 (write every pgState
file to MEMFS before callMain). This adds the spec that exercises it:

- runs a user-authored two-file program: writes main.das requiring utils
  with a `hello()` print, asserts the output panel shows "hi, playground".
- renaming utils.das breaks the build: after pgRenameFile, `require utils`
  should fail at compile time, surfaced through stderr.

Both tagged @wasm so the no-WASM CI gate skips them.
Phase 6: a "share this playground" button next to ▶ run. Clicking opens
a small popover with a shareable URL of the current state, [Copy], and
optional [Shorten to is.gd].

URL encoding: every file in pgState + the active filename serialize as
JSON, then LZString.compressToEncodedURIComponent → `#z=<base64ish>`.
URL-safe out of the box; a 3-file ~40-line state lands well under 1 KB.

is.gd shortener: GET https://is.gd/create.php?format=simple&url=… returns
the short URL as plain text with permissive CORS. On success the input
swaps to the short form; on failure the button briefly says "failed"
and the long URL stays put.

Vendored: site/files/lz-string.min.js (~5 KB, MIT, lz-string@1.5.0).

forge-skin.css: .button_header--ghost variant for the share button;
.pg-share popover (header, URL row, copy/shorten/footer).

playground-init.js already dispatches `#z=`/`#code=` to pgLoadFiles from
phase 3 — this commit just produces those URLs.

share.spec.js: four cases.
  - share popover surfaces the URL with all files (decode round-trip)
  - opening the URL in a fresh context restores state (one retry, since
    new-context bootstrap can race the polling pgInit under high
    parallelism)
  - is.gd shorten replaces the URL on success (route() stubs the request)
  - shorten failure surfaces the error and preserves the long URL
Phase 7: the landing hero's "↗ playground" button has been there since
the prior PR and emits `playground/index.html#code=<percent-encoded>` —
the legacy single-file format. After the multi-file rework that hash
shape still has to land cleanly in main.das.

hero-handoff.spec.js opens the landing page, plants a marker into the
hero's CodeMirror via the CM JS API, clicks the handoff button, captures
the popup page, and asserts /playground/ comes up with a single main.das
tab carrying the marker.

Full suite: 25 specs locally (3 @wasm-tagged), 22 in the CI no-WASM tier.
- Single top toolbar: [tabs] [+] [examples] [share] [run] on the left,
  [clear] on the right. Drop the per-panel "output" label and the Tests
  dropdown. Random Sequence moves into Examples; other test samples
  are removed.
- New .main_workspace flex-row contains [code | output] split by a
  draggable handle (11px hit area, 1px line, amber on drag). Position
  persists to localStorage; double-click resets to 50/50.
- The first splitter pass looked correct but did nothing in real
  browsers: .main_col carried `flex: 1 1 0 !important`, which !important
  beats the splitter's inline `style.flex = '0 0 N%'`. Switch to a
  higher-specificity .main_workspace > .main_col selector with no
  !important so the inline override actually applies.
- Splitter spec drives page.mouse.down/move/up and asserts the
  *measured* column width — the synthetic-event flavor passed even
  while the layout never moved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The "source: github.com/borisbat/dasProfile" line under the
benchmarks panel was plain text. Wrap it in an <a> with a new
`.forge-bench__source` style — amber-dim by default (subtle enough
to sit next to fg-faint meta text), full amber + underline on hover.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hook up the legacy dascf-blog Disqus account (shortname
"https-borisbat-github-io-dascf-blog") under every blog post. Identifier
pins to the post slug so threads stay stable across dev/prod URLs and
future renames; old comments stay tied to the original blog URLs in
the Disqus admin (can be migrated later via Disqus' URL Mapper).

- build_blog.py: render_comments() emits a .forge-post__comments
  section after the article on post pages only (not index/news/
  changelist).
- forge.css: section wrapper styled to match Forge (top divider,
  amber "§ comments" label, dark bg-2 thread container with rule
  border). `color-scheme: dark` on :root hints Disqus to render its
  Auto theme as dark.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two surfaces depend on a real keyboard and (for playground) a 5 MB WASM
bundle that's mediocre on a phone. On <768px viewports we now:

- Landing hero: hide the live CodeMirror panel + sample tabs + run /
  playground buttons. A static <pre><code class="language-daslang">
  block, tokenized by the existing highlight.js, takes its place. The
  terminal frame (dots + filename) is kept so the visual identity stays
  intact. forge.js short-circuits the CM init on mobile so the editor
  doesn't materialize behind the static block.
- /playground/: a synchronous mobile detector tags <html> with
  `.is-pg-mobile` so CSS hides the IDE chrome, and on DOMContentLoaded
  overrides `pageInit` so the body.onload bootstrap renders a Forge-
  styled "open on a laptop" notice instead of fetching daslang_static.js
  / .wasm. Spec asserts zero requests for either resource on mobile.

The (already-hidden-on-mobile) playground nav link in .forge-nav__links
stays as-is; the redundant "playground" version label on the playground
page is also hidden when the notice is showing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Punch list from a full-site audit:

Block fixes
- Mobile nav: ≡ hamburger button in the right-side chip strip on every
  Forge nav (landing, downloads, blog template, playground). Toggles
  `.forge-nav.is-open`, which reveals `.forge-nav__links` as an
  absolutely-positioned dropdown panel under the nav. Phone users can
  now reach docs / benchmarks / downloads / blog / community.
- Mobile blog/changelist grid: `.forge-blog-item` carried only its
  desktop `140px 90px 1fr` shape, which squeezed titles into ~94px at
  390px viewport (one word per line). Added a mobile override stacking
  date+tag on row 1, body on row 2.
- Missing image in blog/instruments: `/images/call_tree.PNG` is a
  Hexo-era absolute path with no asset on this site. Rewrote the
  sentence to drop the inline image.

Cleanup
- Removed dead `runTests`/`runTest`/`outputPool` machinery from
  web/ui/src/main.js (and the mirrored site/playground/main.js) — the
  Tests dropdown that drove them is gone. Simplified the dropdown
  populate loop now that only Examples remains.
- Deleted orphan CodeMirror files from web/ui/src/: codemirror.css,
  codemirror.min.js, eclipse.css. The playground now loads the
  Forge-themed CodeMirror bundle from /files/cm/ — these were ~232 KB
  of dead bytes copied per CI deploy. site/.gitignore entries for the
  same files dropped.
- Hide `.forge-nav__version` at <480 px so the version label stops
  crowding [github ↗] on narrow phones.
- Fixed "0.6.0-RC1 0.6.0-RC2" double label in the 2026-02-28 news
  entry (left over from a partial RC1→RC2 edit).
- Sphinx `version` was '0.6' while the site shows v0.6.2; bumped to
  '0.6.2' to match.
- hero-handoff.spec.js: added `retries: 1` for the two-window race
  that flakes under high parallelism (passes alone, fails ~1/3 in
  full suite). Suite is green-on-retry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…uite

The audit flagged the README as stale — all three recently-landed surfaces
(mobile fallbacks, multi-file playground, Disqus comments) had no mention.
Updated:

- Replaced the desktop-only summary with a "Surface map" table covering
  hero / playground / blog / nav behavior on desktop vs <768 px.
- Expanded the playground section: multi-file tab CRUD, ▶ run via MEMFS
  write loop, ↗ share (#z= compressed hash + is.gd shorten), 250 ms
  autosave to localStorage, splitter persistence.
- Added a Playwright suite section: 28 specs, no-WASM in ~5 s,
  pointer to the CI workflow.
- Refreshed the file tree under site/ — new playground-*.js files,
  the site/tests/playground/ suite, the relocated CodeMirror bundle at
  site/files/cm/, and lz-string.min.js.
- Updated the "/playground/ blank page" gotcha now that CodeMirror lives
  in /files/cm/ rather than web/ui/src/.
- Added a mobile-gate gotcha (hard-refresh required after toggling
  DevTools' device toolbar).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 13, 2026 22:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR redesigns the daslang website and playground, adds a Markdown-driven blog/news pipeline, refreshes docs styling/versioning, and introduces Playwright coverage for the new playground UX.

Changes:

  • Reworked the playground into a Forge-themed multi-file IDE with tabs, sharing, splitter persistence, samples, and mobile gating.
  • Added site assets, blog/news source content, docs theme updates, and deployment/build workflow changes.
  • Added Playwright e2e coverage for playground rendering, tabs, persistence, sharing, splitter behavior, mobile gate, and WASM-tagged run flows.

Reviewed changes

Copilot reviewed 104 out of 114 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
web/ui/src/main.js Updates sample loading and run behavior for multi-file playground integration.
web/ui/src/eclipse.css Removes legacy CodeMirror theme.
web/ui/samples/** Removes old test samples and adds Forge playground examples, including multi-file macros.
site/playground/** Adds new playground shell, init, tabs, share, splitter, and Forge skin scripts/styles.
site/files/** Adds Forge assets, CodeMirror daslang mode/theme, highlighter, runner, and support libraries.
site/blog/** Adds blog template, build pipeline, and imported Markdown posts.
site/_news/** Adds Markdown-backed news/changelog entries.
site/tests/playground/** Adds Playwright e2e tests and package metadata.
tools/seed_news.py Adds one-time legacy news migration helper.
doc/source/conf.py Updates docs version and Forge-themed Sphinx settings.
doc/source/daslang.py Updates docs lexer keyword set.
doc/source/_static/forge-logo.svg Adds docs sidebar logo.
.github/workflows/pages.yml Extends Pages deployment to build blog/news, WASM, playground, and benchmarks.
.github/workflows/playground-e2e.yml Adds no-WASM Playwright PR workflow.
.gitignore, site/.gitignore Adjusts tracked site source vs generated output ignores.
Files not reviewed (1)
  • site/tests/playground/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/playground-e2e.yml Outdated
Comment thread .github/workflows/pages.yml Outdated
Comment thread site/playground/playground-tabs.js Outdated
Comment thread site/files/forge.js
Round 1 from Copilot. All four findings were real.

- pages.yml + playground-e2e.yml: stage every `playground-*.js` (init,
  tabs, share, splitter) not just init.js. CI's 404 storm on
  playground-tabs/share/splitter is the root cause of the failed
  playground-e2e run; same bug in pages.yml would have landed the
  regression in prod. Globbing also picks up future additions.
- playground-tabs.js: drop `/` from the rename regex. The previous
  pattern accepted `dir/foo.das`, but Emscripten MEMFS's `FS.writeFile`
  doesn't auto-create parents — Run would silently ENOENT. Flat
  namespace is enough for the playground.
- forge.js escapeHtml: also escape `"` and `'`. The news renderer
  interpolates `n.link` inside `href="..."`; a `"` in the URL would
  break out and inject markup. `_news/*.md` is committed so practical
  risk is near-zero, but the fix is one line and defensive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 104 out of 114 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • site/tests/playground/package-lock.json: Language not supported

Comment thread site/blog/build_blog.py Outdated
Comment thread web/ui/src/main.js
Two more from Copilot. Both real.

- Atom feed default `--site-url` was `https://dascript.org`; neither
  workflow passed `--site-url`, so `blog/feed.xml` would have advertised
  old-domain URLs once deployed at daslang.io. Subscribers' clients
  follow `<link>`/`<id>` URLs to fetch posts — those would have hit a
  domain that no longer serves the site. Bumped the default to
  daslang.io AND pinned `--site-url https://daslang.io` from both
  workflows so the default can't silently drift again. Updated the
  stale README header that still pointed at dascript.org.
- runCode() wrote every current pgState file to MEMFS but never
  unlinked files the user had deleted/renamed. Concrete bug: open
  utils.das, write `require utils` in main, run (writes utils.das to
  MEMFS), then delete utils.das tab, run again — still works from
  stale MEMFS state, executed program no longer matches visible tabs.
  Fixed by tracking a module-level Set of last-written names; each
  run unlinks stale-from-prior-run names (ENOENT tolerated) before
  writing current. Mirrored to site/playground/main.js.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@borisbat borisbat requested a review from Copilot May 13, 2026 22:27
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 104 out of 114 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • site/tests/playground/package-lock.json: Language not supported
Comments suppressed due to low confidence (2)

web/ui/src/main.js:92

  • web/ui/index.html is still the entry point copied to web/output/index.html by the WASM build, and it still renders the Tests dropdown plus a Run all tests button wired to runTests(). Removing the tests list and runTests implementation here leaves that standalone Web IDE with a non-functional button (and selectSample('tests') no longer has data to load). Either update web/ui/index.html to remove the tests UI as well, or keep the test-loading functions until the legacy entry point is retired.
    web/ui/src/eclipse.css:1
  • web/ui/index.html still links ./src/eclipse.css, and the web build copies that entry point to web/output/index.html. Deleting this stylesheet without updating the legacy entry point makes the standalone Web IDE serve a 404 for its theme; update web/ui/index.html to use the new shared CodeMirror theme/assets or stop publishing that entry point.

Comment thread web/ui/src/main.js
Comment thread doc/source/_static/custom.css Outdated
Comment thread site/files/cm/daslang-keywords.js
Three real, one false alarm.

Real:
- doc/source/_static/custom.css: `@import` for Inter Tight + JetBrains
  Mono lived AFTER a `:root` rule, so browsers silently drop it (CSS 2.1
  §6.3). Docs were quietly falling back to system fonts. Moved the
  import to the very top.
- playground-init.js + hero-handoff.spec.js: the hash-payload dispatch
  stashed `__pendingSampleBundle` but never set `pgRestoredFromState`.
  main.js's default `selectSample("examples", 0)` then ran and the
  data.json fetch sometimes beat pgLoadFiles, overwriting the marker
  text with hello.das. Visible as a flake in CI (slower http.server)
  but a real correctness bug on cold-cache loads in prod too. Set the
  flag; also harden the spec to wait for the marker content, not just
  for pgState's structure to materialize. Three consecutive local runs
  green.
- web/ui/index.html: legacy standalone IDE entry point referencing
  files we deleted (codemirror.{min.js,css}, eclipse.css). Nothing in
  CI/build references it. Removed.

False alarm:
- site/files/cm/daslang-keywords.js: Copilot flagged enum / typedef /
  with / aka / reinterpret / upcast / range64 / urange / urange64 as
  absent. They're all present (verified against
  src/parser/ds2_lexer.lpp's `DAS_*` returns). Reply on the thread —
  no code change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 105 out of 115 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • site/tests/playground/package-lock.json: Language not supported

Comment thread site/playground/index.html
Comment thread site/_news/2026-01-20-say-hello-to-templates-and-typemacros-in.md
Comment thread .github/workflows/pages.yml
…stage

playground-tabs.js: tryInit() polled every 30ms for `window.code` indefinitely.
On mobile, pageInit is short-circuited so the variable never appears, leaving
a 33Hz setTimeout chain running for the life of every mobile tab. Skip the
init when the .is-pg-mobile gate class is present.

pages.yml: the WASM build step keeps continue-on-error so docs/blog still
ship through emsdk hiccups, but the staging block then accepted a half-built
web/output and deployed a playground whose Run button 404'd the runtime.
Tighten the gate to require both daslang_static.{js,wasm} on disk before
staging any playground files — Pages preserves the prior deploy, so the
visible /playground/ keeps working instead of going silently broken.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@borisbat borisbat requested a review from Copilot May 13, 2026 22:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 105 out of 115 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • site/tests/playground/package-lock.json: Language not supported

Comment thread site/playground/playground-init.js
Comment thread .github/workflows/pages.yml Outdated
Comment thread site/playground/playground-splitter.js
…-miss placeholder

playground-init: the `#z=` hash decode stashed `__pendingSampleBundle =
payload.files` but dropped `payload.active`. When playground-tabs.js's
tryInit consumed the bundle before this script's tryApply loop resolved,
`pgLoadFiles(bundle)` ran without an active argument and fell back to
main.das, so a shared URL whose author was viewing utils.das landed on the
recipient's screen with main.das in front. Stash `__pendingSampleActive`
alongside the bundle and consume it in both tab-init paths.

pages.yml: round-4 staging gate (require daslang_static.{js,wasm} before
copying playground files) was based on an incorrect read of
actions/deploy-pages — Pages publishes _site as a complete snapshot, not a
layer over the prior deploy, so a missing _site/playground/ 404s the route
instead of preserving the previous runtime. Stage site/playground/
placeholder.html into _site/playground/index.html on the missing-artifact
branch so /playground/ keeps resolving to something useful while the next
merge re-rolls the runtime.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 106 out of 116 changed files in this pull request and generated 4 comments.

Files not reviewed (1)
  • site/tests/playground/package-lock.json: Language not supported

Comment thread site/blog/template.html Outdated
Comment thread site/downloads.html Outdated
Comment thread site/index.html Outdated
Comment thread site/playground/playground-tabs.js
License footer in site/index.html, site/downloads.html, and
site/blog/template.html displayed "MIT" but the repository LICENSE is
BSD 3-Clause (Gaijin Entertainment, 2019-2023). The blog template fixes
every generated blog page on the next build, so no per-page edits needed.

playground-tabs.js: pgSwitchFile updated pgState.active and swapped the
visible Doc but never called autosave(). User-initiated tab clicks
therefore didn't persist; a page reload restored the previous active tab
(or main.das if no content edit had triggered autosave on `change` yet).
The other state-changing entry points (pgAddFile/Delete/Rename/LoadFiles)
were already saving correctly — only the bare tab-click path was leaking.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 106 out of 116 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • site/tests/playground/package-lock.json: Language not supported

Comment thread .github/workflows/pages.yml
@borisbat borisbat merged commit a061bb6 into master May 13, 2026
33 checks passed
@borisbat borisbat deleted the feat/website-forge-redesign branch May 14, 2026 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants