also looking at this
LSU's own coaching surface, and what auditing the site turned up
#12
86 files
+3943
-1190
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -0,0 +1,14 @@ | ||
| 1 | /* /404. | |
| 2 | ||
| 3 | The page used to be written in six class names that exist in no stylesheet | |
| 4 | on this site - h-page, display, ink, faint, muted and btn-accent - left | |
| 5 | over from an earlier design system, so its heading, eyebrow, body copy and | |
| 6 | primary button all rendered unstyled. It is written in the site's own | |
| 7 | vocabulary now: the same .phero block the legal pages use, and the .btn and | |
| 8 | .btn-outline pair from base.css. | |
| 9 | ||
| 10 | All this sheet adds is the row the two buttons sit in, and the bottom | |
| 11 | padding .phero does not carry. */ | |
| 12 | ||
| 13 | .not-found-actions{display:flex;flex-wrap:wrap;gap:14px;margin-top:10px} | |
| 14 | .phero:last-child{padding-bottom:clamp(90px,12vw,160px)} | |
| @@ -0,0 +1,14 @@ | ||
| 1 | /* /404. | |
| 2 | ||
| 3 | The page used to be written in six class names that exist in no stylesheet | |
| 4 | on this site - h-page, display, ink, faint, muted and btn-accent - left | |
| 5 | over from an earlier design system, so its heading, eyebrow, body copy and | |
| 6 | primary button all rendered unstyled. It is written in the site's own | |
| 7 | vocabulary now: the same .phero block the legal pages use, and the .btn and | |
| 8 | .btn-outline pair from base.css. | |
| 9 | ||
| 10 | All this sheet adds is the row the two buttons sit in, and the bottom | |
| 11 | padding .phero does not carry. */ | |
| 12 | ||
| 13 | .not-found-actions{display:flex;flex-wrap:wrap;gap:14px;margin-top:10px} | |
| 14 | .phero:last-child{padding-bottom:clamp(90px,12vw,160px)} | |
| @@ -1,6 +1,7 @@ | ||
| 1 | @extends('layouts/LSU') | |
| 2 | @section('content') | |
| 1 | 3 | <script server> |
| 2 | import { liveRaceState } from '../data/live' | |
| 3 | import { race } from '../data/race' | |
| 4 | import { liveRaceState } from '~/resources/data/live' | |
| 4 | 5 | |
| 5 | 6 | /* The head partial reads `currentPage`. This page used to declare pageTitle, |
| 6 | 7 | pageDescription and noindex as loose names nothing looked at, so a 404 |
| @@ -8,30 +9,25 @@ import { race } from '../data/race' | ||
| 8 | 9 | const currentPage = { |
| 9 | 10 | title: 'not found - Last Soul Ultra', |
| 10 | 11 | description: 'That page is not here.', |
| 11 | styles: ['/assets/styles/production/base.css'], | |
| 12 | styles: ['/assets/styles/production/base.css', '/assets/styles/production/not-found.css'], | |
| 12 | 13 | noindex: true, |
| 13 | 14 | } |
| 14 | 15 | const canonicalPath = '/404' |
| 15 | 16 | const state = await liveRaceState() |
| 16 | 17 | </script> |
| 17 | <!DOCTYPE html> | |
| 18 | <html lang="en"> | |
| 19 | <head>@include('head')</head> | |
| 20 | <body> | |
| 21 | <SiteNav current="/404" /> | |
| 22 | <main id="main" class="mx-auto px-5 py-20 lg:px-8 lg:py-32 max-w-[1100px]"> | |
| 23 | <p class="faint label">404</p> | |
| 24 | <h1 class="mt-4 h-page max-w-[14ch] display ink">you missed the cut-off.</h1> | |
| 25 | <p class="mt-6 max-w-[46ch] leading-relaxed text-base muted">That page is not here. The race, thankfully, still is.</p> | |
| 26 | <div class="flex flex-wrap gap-3 mt-9"> | |
| 27 | <a class="btn btn-accent" href="/">back to the start</a> | |
| 28 | @if(state !== 'upcoming') | |
| 29 | <a class="btn btn-outline" href="/results">{{ state === 'finished' ? 'the result' : 'live results' }}</a> | |
| 30 | @else | |
| 31 | <a class="btn btn-outline" href="/format">the format</a> | |
| 32 | @endif | |
| 33 | </div> | |
| 34 | </main> | |
| 35 | <SiteFooter /> | |
| 36 | </body> | |
| 37 | </html> | |
| 18 | <section class="phero"> | |
| 19 | <div class="phero-copy"> | |
| 20 | <div class="kicker">404</div> | |
| 21 | <h1>You missed the cut-off.</h1> | |
| 22 | <p>That page is not here. The race, thankfully, still is.</p> | |
| 23 | <div class="not-found-actions"> | |
| 24 | <a class="btn" href="/">Back to the start</a> | |
| 25 | @if(state !== 'upcoming') | |
| 26 | <a class="btn-outline" href="/results">{{ state === 'finished' ? 'The result' : 'Live results' }}</a> | |
| 27 | @else | |
| 28 | <a class="btn-outline" href="/format">The format</a> | |
| 29 | @endif | |
| 30 | </div> | |
| 31 | </div> | |
| 32 | </section> | |
| 33 | @endsection | |
| @@ -158,4 +158,21 @@ describe('the page that is not found', () => { | ||
| 158 | 158 | // Nothing crawls it, so it carries no graph. |
| 159 | 159 | expect(html).not.toContain('application/ld+json') |
| 160 | 160 | }) |
| 161 | ||
| 162 | it('wears the same chrome as every other page', async () => { | |
| 163 | const path = resolve('resources/views/404.stx') | |
| 164 | const html = await processDirectives(await Bun.file(path).text(), {}, path, { | |
| 165 | enabled: true, | |
| 166 | cache: false, | |
| 167 | componentsDir: resolve('resources/components'), | |
| 168 | layoutsDir: resolve('resources/layouts'), | |
| 169 | partialsDir: resolve('resources/partials'), | |
| 170 | }, new Set()) | |
| 171 | ||
| 172 | // It used to write its own html, head and body, and so was the one page | |
| 173 | // with no skip link, no focusable main and the wrong lang. | |
| 174 | expect(html).toContain('class="lsu-skip"') | |
| 175 | expect(html).toContain('<main id="main" tabindex="-1">') | |
| 176 | expect(html).toContain('lang="en-GB"') | |
| 177 | }) | |
| 161 | 178 | }) |