Skip to content

πŸ’„ Redesign /events index β€” consulting sidebar, product card chrome, dark mode - #5008

Open
hveraus wants to merge 14 commits into
mainfrom
refine-events-index
Open

πŸ’„ Redesign /events index β€” consulting sidebar, product card chrome, dark mode#5008
hveraus wants to merge 14 commits into
mainfrom
refine-events-index

Conversation

@hveraus

@hveraus hveraus commented Sep 2, 2026

Copy link
Copy Markdown
Member

Brings /events in line with the pages either side of it. It had no dark mode while / and /consulting did, and its cards were a floated 100px thumbnail over a bare bottom border β€” the last index page still on the old chrome.

  • Affected routes: /events, /consulting

There is no linked issue for this one.

What changed

Layout β€” borrowed from the /consulting index

  • New components/events/eventsSidebar.tsx: the sticky index, with the page h1 in 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.
  • Deliberately not folded into FilterBlock: that is shared with /clients and /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 ProductCard chrome

  • cardShell and productTagChip are imported from components/products/shared.ts rather than re-approximated. The local eventTagChip this replaced was the same class string character for character.
  • Same surface, hover and active states as ProductCard, so hover raises the brand border here too. Same rounded-card plate, same ArrowCircle override (size-9, gray fill, size-3.5 icon) at bottom-right.
  • Icon meta row (date, location, presenter, tags) replaces the old inline Presenter: / Location: labels.

Thumbnails now have a standard ratio. 29 of the 40 files in public/images/events are 1:1; the rest scatter from 1.07 to 3.69. The previous full-height object-cover cropped the square majority and let the image stretch to whatever the content height 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.

Theming β€” /events added to THEMED_ROUTES, so it gets the pre-paint script and the same light/dark treatment as / and /consulting.

Sidebar row spacing tightened on /events and /consulting together, from a 50px pitch to 38px, so the two stay in lockstep. Mobile touch targets are unchanged β€” the pill row's py-2.5 already renders ~40px, so the smaller min-height never 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 to styles.css or tailwind.config.js β€” the diff touches neither. One class string was deleted as a duplicate.

Measured, at 1440x900

before after
card height (avg) 277px 173px
page scroll height 4022px 3161px
meta block 93px 54px
sticky sidebar 1343px 504px

A 4-column meta grid was tried first and was worse (107px) β€” narrow cells wrap more than the row saves. flex-wrap won.

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-2 does not clamp TinaMarkdown'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.tsx now imports from components/products/shared.ts. The module is pure constants and helpers β€” no React, no server imports β€” so it is safe, but the products namespace on something /events consumes is a bit off. Happy to promote cardShell / productTagChip to a neutral module if preferred.

hveraus and others added 7 commits September 2, 2026 15:01
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>
Copilot AI lite review requested due to automatic review settings September 2, 2026 08:51
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Coverage report

St.❔
Category Percentage Covered / Total
πŸ”΄ Statements 1.85% 917/49659
πŸ”΄ Branches 17.85% 106/594
πŸ”΄ Functions 4.81% 24/499
πŸ”΄ Lines 1.85% 917/49659

Test suite run success

35 tests passing in 4 suites.

Report generated by πŸ§ͺjest coverage report action from 9912b5d

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟑 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 /events to the home-theme route allowlist so it picks up the pre-paint theme script and dark/light tokens.
  • Reworked /events layout to use a new EventsSidebar (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.

Comment thread components/filter/events.tsx Outdated
Comment on lines +429 to +433
{event.presenterName ? (
event.presenterName
) : event.presenterList?.length > 0 ? (
<PresenterList presenters={event.presenterList} />
) : null}
@hveraus hveraus added the no-issue This label is used to bypass the PR-Lint check. Should be used for non-coding changes label Sep 2, 2026
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>
@hveraus

hveraus commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

/deploy

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Deployed changes to https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net

ℹ️ Staging slots are no longer created automatically - comment /deploy to deploy new commits.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

πŸš€ Lighthouse Report

🌐 URL ⚑ Performance β™Ώ Accessibility βœ… Best Practices πŸ” SEO πŸ“¦ Bundle Size πŸ—‘οΈ Unused Bundle
⭐ https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/ 40 100 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/articles 93 96 59 57 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/company/about-us 69 100 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/company/clients 98 95 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/company/contact-us 81 92 59 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/consulting 87 97 59 69 0.00 MB 0.00 MB
⭐ https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/consulting/net-upgrade 83 100 56 61 0.00 MB 0.00 MB
⭐ https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/consulting/web-applications 77 100 59 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/employment 78 95 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/events/angular-superpowers-tour 52 97 56 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/events/ai-workshop 71 92 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/events/ai-workshop-essentials 71 97 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/netug/sydney 79 93 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-5008.azurewebsites.net/training/internship-fullstack 79 91 59 61 0.00 MB 0.00 MB

hveraus and others added 4 commits September 4, 2026 18:40
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>
Co-authored-by: hveraus <4745861+hveraus@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-issue This label is used to bypass the PR-Lint check. Should be used for non-coding changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants