Commit Graph

4 Commits

Author SHA1 Message Date
1a2bf257da Brand the auth screens per tenant
A club member signing in at ajax-united.rosterchief.app now sees their club's
logo, name and colours; the base domain keeps the RosterChief skin for the
control panel and Django admin.

The mechanism is `{% extends base_template %}` -- Django lets the parent be a
context variable, so the `branding` context processor picks the skin from
request.club and *every* auth screen allauth ships (login, password reset, MFA,
passkeys, and whatever it adds next) follows the tenant without a single one of
them knowing that clubs exist.

Templates split three ways: _base.html is the skeleton with no branding, and
_platform_base.html / _club_base.html dress it. The control panel extends the
platform base *explicitly* rather than through the variable, so a bug in
branding resolution can never dress the panel up as a club.

Club gains an optional logo and primary_color. Notes on both:

- No logo falls back to the club's initials, never the RosterChief mark, which
  would pass our branding off as theirs.
- Club colours land in an inline :root. daisyUI declares its theme variables
  inside `@layer base`, and unlayered styles beat every layered rule regardless
  of specificity, so this needs no !important. --color-primary-content is derived
  from WCAG relative luminance, so a club that picks pale yellow gets black text
  instead of invisible white.
- primary_color is a text input, not <input type="color">: a colour picker cannot
  express "no colour", so every club that never touched it would submit #000000
  and silently get a black theme.

"/" now resolves per tenant (club home, or hand off to the control panel), which
is why LOGIN_REDIRECT_URL can stay "/" and allauth needs no redirect adapter.

Also folds in the theme toggle gaining a third "auto" state and the logo
switching from `content:` to background-image (content-replacement on a real
element is not supported in Firefox), both of which lived in the base template
this commit replaces.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 22:30:38 +02:00
fc51e1903c Self-host Ubuntu, JetBrains Mono, Roboto and Tourney
Ubuntu becomes the default sans and JetBrains Mono the default mono (via
--font-sans / --font-mono, which Tailwind wires to the body and <code>
defaults). Roboto and Tourney are opt-in utilities: `font-roboto`, and
`font-tourney` for display numerals like jersey numbers.

Self-hosted rather than linked from Google's CDN: a CDN <link> sends every
visitor's IP to a third party on each page load, which is an avoidable GDPR
liability for an EU club platform, and it puts someone else's uptime in our
render path. Files come from the @fontsource packages.

Two subsets each, with unicode-range: plain `latin` cannot render the Polish,
Czech or Turkish letters that turn up in member names, and the range means
latin-ext is only fetched by pages that actually contain those glyphs.

Tourney is variable on two axes, so font-stretch is declared as a range next to
the weight range -- declare only the weight and the browser clamps the width
axis to its default, making `font-stretch: 125%` (a wide shirt number) silently
do nothing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 22:30:02 +02:00
334c706aec Reload the browser on template and static changes in dev
Adds django-browser-reload: runserver already restarts on Python changes, but
the browser had to be refreshed by hand for every template or CSS edit. It also
watches static/, so a Tailwind rebuild now refreshes the page on its own.

Mounted only under DEBUG -- it injects a script into every HTML response and
serves an open event stream, neither of which belongs in production; a test
holds that line. Its endpoint is exempt from RequireMFAMiddleware, otherwise a
not-yet-enrolled staff user has the stream redirected away and live reload dies
on the MFA enrolment page, which is exactly a page we are restyling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 18:32:19 +02:00
848a8578de build(ui): add Tailwind v4 + daisyUI 5 pipeline
daisyUI is an npm plugin, so the standalone Tailwind CLI can't load it; this
adds a real build. Themes are configured as `light --default, dark
--prefersdark`, so dark follows the OS with no JavaScript, and an explicit
data-theme (set by the toggle) overrides it.

The built CSS is committed, so `uv run manage.py runserver` remains all a
Python dev needs; `npm run watch` is only for those touching styles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 15:29:10 +02:00