Add code-block syntax highlighting + full-screen Markdown editor
#16 in tonybierman/dx-blog — merged 2026-05-30
This PR bundles two related editor/reader improvements.
1. Server-side syntax highlighting for code blocks
Fenced code blocks rendered as plain <pre><code> with no token coloring. This adds syntect-based syntax highlighting with a per-block language label, done entirely server-side so it adds zero bytes to the wasm bundle.
Why this architecture
render_markdown/parse_body deliberately run on both the server (SSR) and the wasm client (hydration + the editor's live preview). Calling syntect there would ship its ~1–2 MB of bundled syntaxes to every reader's browser.
Instead, the post body is rendered (with highlighting) on the server and delivered as serialized Segments through the use_server_future the reader already uses — the client reuses those bytes and never runs syntect. Hydration parity is automatic because both sides use the identical server-produced HTML.
Changes
- syntect in the
serverfeature only (default-fancy, pure-Rust regex — no C toolchain).cargo tree --features webconfirms it's absent from the wasm build. src/server/highlight.rs(new): class-based spans (syn-prefix to avoid Tailwind collisions) + adata-langattribute that drives a CSS corner label. Sanitized via an ammonia builder that permitsclass/data-langonpre/code/span(defaultcleanstrips them).Segmentnow derivesSerialize/Deserialize;PostDetail.body_segmentsis server-filled (sqlx(skip)). The reader renders from it instead of re-running the markdown pipeline client-side.- Editor live preview keeps its zero-latency client-side render — code shows unhighlighted while typing; the published/reader view is highlighted.
assets/highlight.cssgenerated from the bundled base16-ocean.dark theme (via an#[ignore]d generator test inhighlight.rs).
2. Full-screen mode for the Markdown editor
Adds a full-screen toggle to the Markdown editor (src/pages/admin/posts.rs).
Testing
cargo checkon server, web, and default targets — all greencargo tree --features web | grep syntect→ empty (no wasm impact)cargo test --features server,sqlite→ 19 pass, including new tests assertingsyn-classes survive sanitization, thedata-langlabel is present, unlabeled fences get no label, and non-code prose stays byte-identical to the plain pipelinecargo fmt --checkclean
Not yet done: a manual visual check in the browser.
🤖 Generated with Claude Code
Last updated 2026-05-31
Links to this note
Merged pull requests, newest first.