Skip to content

feat(site): restyle the documentation site dark-first - #3

Merged
w0rxbend merged 2 commits into
mainfrom
feat/site-redesign
Aug 9, 2026
Merged

feat(site): restyle the documentation site dark-first#3
w0rxbend merged 2 commits into
mainfrom
feat/site-redesign

Conversation

@w0rxbend

@w0rxbend w0rxbend commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

What this does

Redesigns the documentation site. It was stock Helium with the colours changed; this makes it a designed page — near-black canvas, one accent colour, cards, real type hierarchy, and a landing page whose header offers a way into the docs.

Dark is the mode this is designed for. Light is fully supported and derived from the same tokens, not an afterthought.

Why

The site looked dated and, in places, unfinished:

  • Only the light colour scheme was ever configured. Dark mode fell back to Helium's default teal — a palette nobody on this project chose.
  • The landing page's only routes onward were a boxed "Documentation" panel in the corner and a list at the very bottom of the prose. Helium renders the landing page from a template with no navigation bar in it.
  • Headings were the accent colour, and so were links, so nothing distinguished "this is a heading" from "this is clickable".
  • Code blocks wrapped. In Scala that breaks lines inside identifiers — Future[Page[Issue]] rendered as Futur / e[Page[Issue]].
  • The sidebar told section headings apart from page links with a 2px rule, and sized a top-level page link larger than the section heading above it.
  • The top bar put the home icon in the dead centre of the screen, which is where Helium's space-between leaves it on a wide monitor.

How it works

Helium stays. It already owns the sidebar, responsive layout, syntax highlighting and page navigation; replacing it means rewriting all of that to end up somewhere worse. Everything here is either Helium configuration or a CSS layer on top.

Two commits.

feat(site): give the landing page a hero action row — adds titleLinks to the landingPage config: Get started, Examples, API reference, source. Removes documentationLinks, which rendered a boxed panel listing the same destinations; it was also the tallest thing in the header, so it set the header's height and left the title column beside it looking empty. Nothing is lost — every destination is still one click away, and the "Where to go next" list at the foot of the page is untouched.

feat(site): restyle the site dark-first over Helium — the design pass:

  • site/build/laika.scala gains a Palette object holding both schemes in full, plus darkMode.themeColors, syntax-highlighting quintets for both, a new type scale via fontSizes, and column metrics via layout. The header's gradient is set to the same colour at both stops, which is how Helium is told to draw a flat surface rather than a gradient.
  • site/assets/css/site.css (new) holds component shapes — the things Helium exposes no setting for. Wired in with internalCSS(Root / "assets" / "css"), which loads it after Helium's own stylesheets at the same specificity, so every rule is a plain override and nothing needs !important.

The split matters and is documented in both files: colours, type scale and metrics are configuration and live in laika.scala; component shapes are CSS and live in site.css. A colour set in both places will drift.

Specifics worth calling out:

Change Why
Headings take the body colour The accent now means "clickable" and nothing else
white-space: pre on code blocks Wrapping broke Scala identifiers mid-token; a snippet a reader may copy should not be re-flowed
Inline code is a bordered chip A type name in a sentence is no longer mistaken for emphasis
Body 15px → 16px, column 860px → 820px ~75 characters, where the eye stops hunting for the next line
Hero accent is a separate token The page accent darkens in light mode to carry text on white; used on the always-dark header it put a near-black label on a dark blue button at about 2:1
Header padding uses max(28px, calc(…)) There is no wrapper element inside #header to constrain, so the shell is emulated with padding — this aligns the hero's left edge with the cards and prose below it

How to test it

./scripts/site.sh --serve

Then open http://localhost:8080/ and toggle your OS between light and dark. --no-api skips Scaladoc and is much faster if you are only looking at prose.

To check the specific fixes:

  • Dark mode is designed, not defaulted — open in dark mode; the page is near-black, not teal.
  • Code does not break mid-identifierguides/04-pagination.html, first snippet: Future[Page[Issue]] is intact on one line, and the block scrolls sideways if it needs to.
  • Accent means clickable — on any guide, section headings are body-coloured and only links are azure.
  • Hero contrast in light mode — the "Get started" button is bright azure with a near-black label in both schemes.
  • Mobile — at 390px wide the header stacks, the buttons wrap, and the cards go single-column.

The pipeline's own guarantees are unchanged and still enforced: every tagged snippet is compiled against the library, and every internal link is validated. A full ./scripts/site.sh --clean is green, and all 963 generated pages have exactly one </html>.

Notes for reviewers

  • Verified by rendering, not by reading the CSS. Every iteration was screenshotted headless at 1400px dark, 1400px light and 390px, on both the landing page and a guide page, and the layout numbers quoted above were read off those renders.
  • Deliberately not done: a custom landing-page template. A sticky navigation bar on the landing page would need overriding Helium's landing.template.html, which means depending on an internal path and re-checking it on every Laika upgrade — and getting it wrong fails silently by falling back to the default. titleLinks covers the same need through a supported option. Worth revisiting only if Laika makes the template a public extension point.
  • Contrast. Every text-on-background pair clears WCAG AA. The tightest is muted text on the page background, at 7.0:1 dark and 5.9:1 light.
  • The four teasers still restate the "four properties" section immediately below them. That is the summary-then-detail structure the existing comment in laika.scala describes, and rewriting the prose was out of scope for a styling change. Say the word if you want it condensed.
  • Fonts are still system stacks. No webfont was added, so the site continues to render correctly offline and makes no third-party request.

Helium renders the landing page from a template of its own, and that
template has no navigation bar in it. So the front page offered a reader
exactly two ways onward: a boxed "Documentation" panel in the top-right
corner, and the "Where to go next" list at the very bottom of the prose.

`titleLinks` puts the routes where a reader looks first — directly under
the title, as a row of buttons: Get started, Examples, API reference, and
the source repository.

The boxed panel is removed in the same change rather than kept alongside,
because it listed the same three destinations. A header that says "Getting
Started" as a button and "Getting Started" again in a panel four inches to
the right is not twice as helpful. It was also the tallest thing in the
header, which set the header's height and left the title column beside it
looking abandoned.

Nothing is lost: every destination the panel held is in the row, and the
"Where to go next" list at the foot of the page is unchanged.
The site was stock Helium in the project's original blue: a gradient
banner, centred headings, teaser text floating with no container, code
blocks with no border, and a sidebar whose section headings were told
apart from its page links by a 2px rule. It read as a theme with the
colours changed, because that is what it was.

This is a design pass, not a theme swap. Helium stays — it already owns
the sidebar, the responsive layout, the syntax highlighter and the page
navigation, and hand-writing those to end up somewhere worse is not a
good trade. What changes is everything Helium lets you change.

**Palette.** Near-black (#0b0f14) with one accent hue, azure, in two
tones: a bright one for interactive text on dark, a deep one for the same
on white. Both colour schemes are now defined in full — before, only the
light one was, and dark fell back to Helium's default teal, which no one
had chosen. The header keeps its near-black in both schemes, so the site
has one first impression rather than two, and its gradient is set to the
same colour at both stops, which is how Helium is told to draw a flat
surface.

**Type.** 16px body, up from 15, in an 820px column rather than 860 —
about 75 characters, which is where the eye stops having to hunt for the
start of the next line. The heading scale steps 40 / 27 / 20 / 16 so a
heading's level is visible without counting.

**Components.** These are shapes, not settings, so they live in the new
`site/assets/css/site.css`, wired in with `internalCSS` and loaded after
Helium's own stylesheets — same specificity, later in the cascade, so
nothing needs `!important`. Teasers become cards. Code blocks get a
border, a radius, and `white-space: pre` (Helium wraps them, which in
Scala breaks lines mid-identifier: `Future[Page[Issue]]` came out as
`Futur` / `e[Page[Issue]]`). Inline code becomes a chip so a type name in
a sentence is not mistaken for emphasis. Headings take the body colour
instead of the accent, leaving the accent to mean "you can click this".
Sidebar sections become small caps labels and the current page gets a
bar. The home icon moves from the centre of the top bar, where Helium's
space-between puts it on a wide screen, to the left where a brand mark
goes.

Verified by rendering: dark, light, and 390px wide, on the landing page
and on a guide. The full pipeline is unchanged and still green — every
snippet compiles, every internal link resolves.
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@w0rxbend, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 32 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0b82a952-4881-40ce-921d-97ffa7d1c42d

📥 Commits

Reviewing files that changed from the base of the PR and between 99a7cc4 and b3a252e.

📒 Files selected for processing (3)
  • site/README.md
  • site/assets/css/site.css
  • site/build/laika.scala

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@w0rxbend
w0rxbend merged commit 1906a40 into main Aug 9, 2026
5 checks passed
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.

1 participant