Skip to content

Visual refresh: two column layout and easy themeability#197

Open
aJanuary wants to merge 2 commits into
lostcarpark:mainfrom
aJanuary:two-column-layout
Open

Visual refresh: two column layout and easy themeability#197
aJanuary wants to merge 2 commits into
lostcarpark:mainfrom
aJanuary:two-column-layout

Conversation

@aJanuary

Copy link
Copy Markdown
Collaborator

This contains two big changes:

  1. Switch to a two column layout
  2. Rework the colours to make it easier to theme
image

I chose to put them in the same PR because the second depends on the first, and it felt awkward to stack it into two PRs. But if you'd prefer, I can split them apart. They are in two separate commits.

The primary motivation for the two column layout is that as we start adding more things in (such as the login link) the horizontal navigation was getting difficult to fit in. Moving it to a vertical list down the side makes it feel less cramped.

On smaller devices, it switches to a drawer that is opened by pressing the burger button. I chose to keep this always visible in a fixed header, as that felt most idiomatic. However, it does sacrifice some vertical screen-space.

While working on this, I realised I was having to make up colours, and try and hunt around the existing set to work out what ones would be most suitable. This, combined with prior experiences trying to theme the colours around a cons brand colour, let to the second part of the work.

We define a palette of colours (using variables with the structure --<palette>-<brightness>. These are then what are referenced by the rest of the CSS. This makes it much easier to use consistent colours, because you're not having to invent a new shade of gray, or find out which grays have been used before.

These palettes can be hand-picked. Or, for convenience, they can be derived from a handful of "tint" variables. For most cons without a dedicated graphic designer on hand to come up with the palettes for them, they should be able to get away with just setting --brand-tint, --gray-tint and --info-tint to the cons brand colour and have something that looks reasonable in both light and dark mode.

aJanuary added 2 commits June 17, 2026 13:41
Move navigation out of the page header and into a persistent left
sidebar, giving a two-column shell (sidebar + scrolling main column).
Below 768px the sidebar collapses into a drawer toggled from a top bar.

Implement the drawer as a native <dialog> opened with showModal(), so
the platform provides the backdrop, focus trap, focus restore, Escape
to close, and inerting of the background while it is open. Layer on the
parts the element doesn't give us: a CSS :has() rule locks body scroll
while it is open, a click outside the dialog box dismisses it, a
matchMedia listener closes it when the viewport grows back past the
breakpoint, and a route-change effect closes it after navigation. The
drawer slides in/out via @starting-style and allow-discrete transitions
where supported, degrading to appear/disappear on older baselines.

Add a NavIcon component and per-item icons for the nav links, including
optional icons on NAVIGATION.EXTRA config entries via a built-in
ICON_NAME set or a custom ICON_URL, and swap the help-text close label
for a FaTimes icon. Move HelpText out of the header into the main column
and flatten the footer markup to suit the new layout.

Replace the program item's text selection label with a star icon
(filled when selected, outline when not). The checkbox stays in the DOM
and focusable but is visually hidden; a screen-reader-only label gives
it a Select/Unselect action name, and focus-visible styling on the star
keeps it keyboard-operable.
Replace the ad-hoc hard-coded color variables with a structured palette:

  1. Inputs    - a few tint knobs (--brand-tint, --gray-tint, --info-tint,
                 --danger-tint) that drive everything.
  2. Palette   - gray/brand/info/danger ramps (steps 50-950) plus shadow
                 and utility colors, derived from the inputs with
                 color-mix() against per-step bases.
  3. Semantic  - the variables the rest of the CSS references (--main-bg,
                 --button-primary-bg, ...), mapped onto palette entries.

Semantic mappings live once in App.css and are shared by both modes;
light and dark differ only in the ramp inputs (base colors and mix
amounts) supplied by lightmode.css and darkmode.css. Re-theming the
whole site is now a matter of changing --brand-tint.

Drive dark mode off <html data-theme="light|dark"> resolved in
AppRoutes from the "browser"/"light"/"dark" setting, and resolve it
before first paint via an inline script in index.html to avoid a flash.
This replaces the lazy-loaded ThemeSelector/LightStyle/DarkStyle
components, which are removed. Also document the system in the README.
@aJanuary aJanuary requested a review from lostcarpark June 17, 2026 12:52
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