ReviewOS

also looking at this

stacks/lastsoulultra

LSU's own coaching surface, and what auditing the site turned up

#12
Merged glennmichael123 wants to merge claude/last-soul-ultra-web-6e0718 into main
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.

public/assets/styles/production/coaching.cssmodified+5-0
Changes to public/assets/styles/production/coaching.css
@@ -22,6 +22,11 @@
2222 sold the idea again. The red hairline under it carries the brand instead. */
2323.coaching-surface .coach-head {padding:clamp(104px,11vw,136px) 0 clamp(26px,3vw,38px)}
2424.coaching-surface .coach-head .kicker {display:block;color:var(--lsu-red)}
25/* The kicker is the way back to the hub. The module nav hides itself when the
26 brand publishes nothing, and without this a module page was then a dead end
27 with no link to the page that explains what coaching here is. */
28.coaching-surface .coach-up {width:fit-content;text-decoration:none;border-bottom:1px solid transparent}
29.coaching-surface .coach-up:hover {border-bottom-color:var(--lsu-red)}
2530.coaching-surface .coach-head h1 {max-width:16ch;margin:16px 0 0;font:400 clamp(38px,5.2vw,76px)/1.04 var(--lsu-display);text-transform:uppercase;letter-spacing:.02em}
2631.coaching-surface .coach-head p {max-width:58ch;margin:20px 0 0;color:var(--lsu-dim-1);font:400 18px/1.65 var(--lsu-body)}
2732
resources/assets/styles/site/coaching.cssmodified+5-0
Changes to resources/assets/styles/site/coaching.css
@@ -22,6 +22,11 @@
2222 sold the idea again. The red hairline under it carries the brand instead. */
2323.coaching-surface .coach-head {padding:clamp(104px,11vw,136px) 0 clamp(26px,3vw,38px)}
2424.coaching-surface .coach-head .kicker {display:block;color:var(--lsu-red)}
25/* The kicker is the way back to the hub. The module nav hides itself when the
26 brand publishes nothing, and without this a module page was then a dead end
27 with no link to the page that explains what coaching here is. */
28.coaching-surface .coach-up {width:fit-content;text-decoration:none;border-bottom:1px solid transparent}
29.coaching-surface .coach-up:hover {border-bottom-color:var(--lsu-red)}
2530.coaching-surface .coach-head h1 {max-width:16ch;margin:16px 0 0;font:400 clamp(38px,5.2vw,76px)/1.04 var(--lsu-display);text-transform:uppercase;letter-spacing:.02em}
2631.coaching-surface .coach-head p {max-width:58ch;margin:20px 0 0;color:var(--lsu-dim-1);font:400 18px/1.65 var(--lsu-body)}
2732
resources/components/CoachingModule.stxmodified+1-1
Changes to resources/components/CoachingModule.stx
@@ -30,7 +30,7 @@ const panelHost = portalHost()
3030<div class="coaching-surface">
3131 <header class="coach-head">
3232 <div class="coach-shell">
33 <span class="kicker">Coaching</span>
33 <a class="coach-up kicker" href="/coaching">Coaching</a>
3434 <h1>{{ panel.title }}</h1>
3535 <p>{{ panel.summary }}</p>
3636 </div>
tests/coaching-views.test.tsmodified+17-0
Changes to tests/coaching-views.test.ts
@@ -152,3 +152,20 @@ describe('a module route, with nothing published', () => {
152152 expect(plans).toContain('Nothing is open yet')
153153 })
154154})
155
156describe('getting back out of a module', () => {
157 it('links to the hub from every module, published or not', async () => {
158 stubHq(null)
159 for (const module of coachingModules)
160 expect(await render(module.slug)).toMatch(/<a class="[^"]*coach-up[^"]*" href="\/coaching">Coaching<\/a>/)
161 })
162
163 it('leaves the storefront a way back when the nav has hidden itself', async () => {
164 stubHq(null)
165 const plans = await render('plans')
166
167 // The nav only renders with more than one module to move between.
168 expect(plans).not.toContain('coach-nav')
169 expect(plans).toContain('href="/coaching"')
170 })
171})