π Redesign /events index β consulting sidebar, product card chrome, dark mode - #5008
π Redesign /events index β consulting sidebar, product card chrome, dark mode#5008hveraus wants to merge 14 commits into
Conversation
Brings /events in line with the pages it sits beside. It had no dark mode while / and /consulting did, and its cards were a floated 100px thumbnail over a bare bottom border. Layout β borrowed from /consulting's index - New components/events/eventsSidebar.tsx: the sticky category index, with the page h1 in the sidebar, grid-cols-sidebar, and the mobile scrim strip that cards scroll under. The existing filter groups render as its nav. - Not folded into FilterBlock: that is shared with /clients and /opportunities, which are unthemed and want the old flex column. Cards β borrowed from the home Upcoming Events block - rounded-card hairline surface, cover image, whole-card link overlay and ArrowCircle, with the same icon meta grid (date, location, presenter) and type/category as chips. Description clamped to three lines. Theming - /events added to THEMED_ROUTES, so it gets the pre-paint script and the same light/dark treatment as / and /consulting. No new tokens: grid-cols-sidebar, top-headerOffset, sunken-glow, sunken-scrim, rounded-card, hairline, card/card-hover and brand-subtle all already existed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The sticky column had a max-height and overflow-y-auto I added defensively, which put a scrollbar inside the sidebar β /consulting has neither, and the two are meant to behave the same way. The guard was unnecessary anyway: the events sidebar renders 10 nav items to /consulting's 11, so it was never the taller of the two. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The nav rows sat on a 50px pitch β min-h-11 (44px, the AAA touch target) plus a 6px gap β which read as far too loose for a desktop index. Down to a 38px pitch: min-h-9, py-1.5, gap-0.5. Applied to both sidebars together so the two pages stay in lockstep. Mobile is unchanged. The pill row's py-2.5 already renders ~40px, so the smaller min-height never binds there and the touch target holds. 36px still clears WCAG 2.5.8 Target Size (Minimum, 24px) comfortably. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Measured in the browser at 1440x900, not estimated. Thumbnail β 29 of the 40 files in public/images/events are 1:1, the rest scatter from 1.07 to 3.69. The full-height object-cover column cropped the square majority and stretched the card to whatever the content was. Now a fixed 1:1 plate with object-contain, so every ratio shows whole, on a white plate for the transparent logos among them. Height β 277px average per card down to 175px (min 155, max 188), and the page from 4022px to 3161px: - The meta row was a rigid 2-col grid forcing two tall rows (93px). A flex-wrap flow packs the same four items into 54px. A 4-col grid was tried first and was worse (107px) β narrow cells wrap more than they save. - Dropped the description. line-clamp-2 does not clamp TinaMarkdown's block children, so it rendered 54-67px inconsistently, and it is the least necessary field on an index. Sidebar β only the heading and nav are sticky now. sidebarBody is an ~800px promo which, inside the sticky element, made the column 1343px in a 900px viewport and stranded its own bottom off-screen. This is the overflow I wrongly dismissed earlier by counting nav items and ignoring that block; the sticky part is now 504px. Note the root font-size is 18px, so every rem class is 12.5% larger than its name implies. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sidebarBody sat below the nav in the sticky column, so scrolling dragged its ~800px of promo straight through the pinned nav. Measured at scroll 900: nav pinned at y104-608, promo at y-55-747, and hit-testing inside the nav returned the promo's <img>. The nav has no background, so it showed through rather than occluding. Moved the promo out of the sidebar to the end of the content column, under a hairline rule. The sidebar is now nav only and short enough to stick whole, which is what /consulting does and what the two earlier attempts here were talking around. Verified at scroll 0 / 900 / 1800 / 2600: six sample points down the nav all resolve to the nav itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts: # components/layout/homeTheme.tsx
/products landed on main, so its card language is now importable instead of approximated. No new styles. - cardShell replaces the hand-written shell (rounded-card, border-0.75, transition, focus-visible outline). flex-row overrides its flex-col through twMerge. - productTagChip replaces eventTagChip, which was the same class string character for character. - Same surface, hover and active states as ProductCard, so hovering now brings up the brand border here too. - Thumbnail plate uses rounded-card like the product logo plate, not rounded-utility, with the logo inset rather than filling the plate. - ArrowCircle takes ProductCard's exact override β size-9, the gray fill, size-3.5 icon β and moves to bottom-right to match. Not copied: ProductCard's footer row (border-t-0.75 plus destination label). Events have no equivalent label, and the divider would add back height that was just removed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Coverage report
Test suite run success35 tests passing in 4 suites. Report generated by π§ͺjest coverage report action from 9912b5d |
There was a problem hiding this comment.
π‘ Changes recommended
The new card-wide link overlay makes presenter profile links rendered by PresenterList pointer-inaccessible while remaining focusable, creating an accessibility/interaction regression.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Aligns the /events index with the newer themed βhome/consultingβ layout and card styling, including dark mode support and a new sticky sidebar-based filter/navigation experience.
Changes:
- Added
/eventsto the home-theme route allowlist so it picks up the pre-paint theme script and dark/light tokens. - Reworked
/eventslayout to use a newEventsSidebar(sticky h1 + filter nav) and moved the long sidebar promo content into the main column. - Redesigned event cards to use the shared
ProductCard-style chrome and a consistent square thumbnail plate.
File summaries
| File | Description |
|---|---|
| components/layout/homeTheme.tsx | Adds /events to THEMED_ROUTES so the route participates in home theming. |
| components/filter/events.tsx | Replaces FilterBlock layout with EventsSidebar and restyles event cards using shared product card primitives. |
| components/events/eventsSidebar.tsx | New reusable sticky sidebar component for /events filters and page title. |
| app/consulting/index.tsx | Tightens sidebar nav row spacing to match the new /events sidebar rhythm. |
| app/(events)/events/index.tsx | Wraps /events index in HomeThemeShell and updates page structure to match themed layout. |
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 1
- Review effort level: Lite
π‘ Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| {event.presenterName ? ( | ||
| event.presenterName | ||
| ) : event.presenterList?.length > 0 ? ( | ||
| <PresenterList presenters={event.presenterList} /> | ||
| ) : null} |
The Vimeo "Video On Demand" / "Free SuperPowers Videos" thumbnails are
gone from the sidebar body; one SSW TV card takes their place, under the
filter nav on desktop and at the foot of the list on mobile, where the
pinned filter bar leaves no room for it. It reuses the product card
chrome, so it matches the cards this branch already reworked.
Upcoming and Past stop being peer tabs: the list gets a heading and a
"View Past Events" toggle in the corner, which keeps ?past=1 in step
with the URL so the archive stays linkable.
Event card facts now take one line each β date, then presenter and
location, then tags β and thumbnails fill their plate instead of sitting
inside a white ring.
Both emptied rich-text fields needed guarding: Tina returns a truthy
{ type: "root", children: [] }, so the preface was rendering an empty
div whose mb-8 pushed /events 36px out of line with /consulting and
/products, and the sidebar body was drawing a bare hairline. The sticky
sidebar column is also narrower from xl up, giving the list more room.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
/deploy |
|
Deployed changes to https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net βΉοΈ Staging slots are no longer created automatically - comment |
Both index pages carried the same sticky-index shell character for character: the grid, the sticky column with its mobile scrim, the heading class and the nav-item colour logic, comments included. The cost was already visible in this branch - tightening the row pitch meant editing both files by hand to keep them aligned. StickySidebarLayout now owns the grid, the sticky column, the <h1> and the content column, and each page passes only its own nav: /consulting anchors to in-page sections, /events renders filter buttons. sidebarNavItem takes the per-page extras, which is all that actually differed - /events needs the width and alignment resets a <button> does not get for free. It also mounts both copies of the sidebar promo, desktop and mobile, so the page no longer hand-places a second SswTvCard at the foot of the content. Verified non-visual: the old and new class strings were run through the repo's own cn() and compared as sets - identical for the sidebar <h1>, both content columns, and both nav items in each of their active and inactive states. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two defects in the new card, both found by review. The card is one overlay anchor at z-10, and the content column beneath it has no stacking context, so the profile links PresenterList renders were painted underneath it: unreachable by mouse, still focusable by keyboard, and still underlined by the global anchor rule. Pointer and keyboard users navigated to different destinations from the same visual element, and these links worked before this branch. PresenterList takes a `linkless` opt-in now and the card uses it, so presenter names are plain text; the profile links stay on the event page itself, and every other caller keeps them. The icon meta row replaced the old inline "Presenter:" / "Location:" text, but react-icons emits a bare <svg> with no accessible name and no aria-hidden, so a screen reader read "Melbourne" with nothing saying it was a location. EventMetaItem now requires a label, rendering it sr-only and hiding the glyph. Also here: the card takes its light surface from bg-card / bg-card-hover rather than hardcoded greys, since those tokens are theme-aware and already carried light values; and eventSite collapses to eventSiteName, dropping a url nobody read once the card became a single link. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The rich-text field is still called "Sidebar Body" in the CMS, but it renders at the foot of the content column now, so the label told editors the opposite of where their content lands. Relabelled with a description; the field name stays as it is, since renaming it would break the generated query and the existing content. FilterBlock's sidebarChildren prop had no callers left once /events moved off it - clients and opportunities never passed it - so it goes. min-h-[200px] on the SSW TV card becomes a min-h-sidebar-card token, mirroring the max-w-sidebar-card beside it. tailwindcss/no-arbitrary-value is set to error and only missed it because cn() is not in the plugin's callees. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts: # tailwind.config.js
Co-authored-by: hveraus <4745861+hveraus@users.noreply.github.com>
Brings
/eventsin line with the pages either side of it. It had no dark mode while/and/consultingdid, and its cards were a floated 100px thumbnail over a bare bottom border β the last index page still on the old chrome./events,/consultingThere is no linked issue for this one.
What changed
Layout β borrowed from the
/consultingindexh1in the sidebar,grid-cols-sidebar, and the mobile scrim strip that cards scroll under. The existing filter groups (Technology / Format, with counts) render as its nav.FilterBlock: that is shared with/clientsand/opportunities, which are unthemed and want the old flex column. Variant flags there would have made it worse for both.sidebarBody(the ~800px Video On Demand promo) moved out of the sidebar to the end of the content column. Inside the sticky column it made the sidebar 1343px tall in a 900px viewport, so scrolling dragged it straight over the pinned nav.Cards β the home Upcoming Events block, wearing the
ProductCardchromecardShellandproductTagChipare imported fromcomponents/products/shared.tsrather than re-approximated. The localeventTagChipthis replaced was the same class string character for character.ProductCard, so hover raises the brand border here too. Samerounded-cardplate, sameArrowCircleoverride (size-9, gray fill,size-3.5icon) at bottom-right.Presenter:/Location:labels.Thumbnails now have a standard ratio. 29 of the 40 files in
public/images/eventsare 1:1; the rest scatter from 1.07 to 3.69. The previous full-heightobject-covercropped the square majority and let the image stretch to whatever the content height was. Now a fixed 1:1 plate withobject-contain, so every ratio shows whole, on a white plate for the transparent logos among them.Theming β
/eventsadded toTHEMED_ROUTES, so it gets the pre-paint script and the same light/dark treatment as/and/consulting.Sidebar row spacing tightened on
/eventsand/consultingtogether, from a 50px pitch to 38px, so the two stay in lockstep. Mobile touch targets are unchanged β the pill row'spy-2.5already renders ~40px, so the smallermin-heightnever binds there.No new styles
Every token used already existed:
grid-cols-sidebar,top-headerOffset,sunken-glow,sunken-scrim,rounded-card,hairline,card/card-hover,brand-subtle. Nothing added tostyles.cssortailwind.config.jsβ the diff touches neither. One class string was deleted as a duplicate.Measured, at 1440x900
A 4-column meta grid was tried first and was worse (107px) β narrow cells wrap more than the row saves.
flex-wrapwon.Overlap fix verified at scroll 2200 / 3000 / 3800: six sample points down the pinned nav all resolve to the nav itself, where before they returned the promo's
<img>.Worth a reviewer's opinion
The card no longer shows the event description.
line-clamp-2does not clampTinaMarkdown's block children, so it rendered inconsistently between 54px and 67px, and it was the largest remaining block on an index card. Happy to put it back as a first-paragraph excerpt if you would rather keep it.components/filter/events.tsxnow imports fromcomponents/products/shared.ts. The module is pure constants and helpers β no React, no server imports β so it is safe, but theproductsnamespace on something/eventsconsumes is a bit off. Happy to promotecardShell/productTagChipto a neutral module if preferred.If adding a new page, I have followed the π New Webpage issue template
If updating the livestream banner, I have tested and followed the steps in Wiki - Testing the live banner
Include Done Video or screenshots