Skip to content

💄 Redesign /products index + third-party brand card tokens - #4984

Open
hveraus wants to merge 19 commits into
mainfrom
Refine-products-index-page
Open

💄 Redesign /products index + third-party brand card tokens#4984
hveraus wants to merge 19 commits into
mainfrom
Refine-products-index-page

Conversation

@hveraus

@hveraus hveraus commented Aug 13, 2026

Copy link
Copy Markdown
Member

Bring /products in line with the /consulting index redesigned in #4939: same page background, container geometry, title scale and card interaction model.

  • Opt /products into home theming via THEMED_ROUTES, so it picks up the sunken-glow background and dark-mode surfaces.
  • Split the page into per-product card components under components/products/, with the shared card chrome (geometry, hover, focus) in shared.ts.
  • Give TinaCMS and YakShaver their own branded cards, spanning two columns from md up. Matched on product name so the treatment follows the product if an editor reorders the CMS list.
  • Add MoreProductsPanel to fill the trailing gap on the last grid row, sized from the occupied cell count rather than hardcoded.
  • Namespace TinaCMS brand colours as global --brand-tina-* tokens in styles.css, documenting the WCAG AA contrast measurement behind each value, and expose them through tailwind.config.js.
  • Fix the title's Tina visual-editing attribute: props-tina-field was never a real attribute, so the h1 never registered as a click target.
  • Affected routes:

  • Fixed #{{ ISSUE NUMBER }}

Bring /products in line with the /consulting index redesigned in #4939: same
page background, container geometry, title scale and card interaction model.

- Opt /products into home theming via THEMED_ROUTES, so it picks up the
  sunken-glow background and dark-mode surfaces.
- Split the page into per-product card components under components/products/,
  with the shared card chrome (geometry, hover, focus) in shared.ts.
- Give TinaCMS and YakShaver their own branded cards, spanning two columns
  from md up. Matched on product name so the treatment follows the product if
  an editor reorders the CMS list.
- Add MoreProductsPanel to fill the trailing gap on the last grid row, sized
  from the occupied cell count rather than hardcoded.
- Namespace TinaCMS brand colours as global --brand-tina-* tokens in
  styles.css, documenting the WCAG AA contrast measurement behind each value,
  and expose them through tailwind.config.js.
- Fix the title's Tina visual-editing attribute: props-tina-field was never a
  real attribute, so the h1 never registered as a click target.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 13, 2026 04:00
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Coverage report

St.
Category Percentage Covered / Total
🔴 Statements 1.92% 954/49600
🔴 Branches 17.51% 104/594
🔴 Functions 4.82% 24/498
🔴 Lines 1.92% 954/49600

Test suite run success

34 tests passing in 4 suites.

Report generated by 🧪jest coverage report action from b725e3b

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.

Pull request overview

Updates the /products index to match the redesigned /consulting index by opting into home theming, introducing a shared card interaction model, and adding branded card treatments for third-party products.

Changes:

  • Opts /products into home theming and updates page wrapper/geometry to match /consulting.
  • Replaces the old PageCard grid with dedicated product card components (standard + branded TinaCMS/YakShaver) and shared card chrome.
  • Adds global TinaCMS brand CSS tokens (documented for contrast) and exposes them to Tailwind utilities.

Reviewed changes

Copilot reviewed 8 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tailwind.config.js Exposes TinaCMS brand CSS variables via Tailwind color tokens.
styles.css Introduces namespaced third-party brand tokens for TinaCMS (with contrast notes).
public/images/company-logos/TinaCms-Logo-Full-Default.svg Adds TinaCMS full lockup SVG for branded product card.
components/products/yakShaverProductCard.tsx Adds YakShaver branded card component (always-dark scoped surface + artwork).
components/products/tinaProductCard.tsx Adds TinaCMS branded card component using new brand tokens.
components/products/shared.ts Introduces shared card shell classes and destination label helper.
components/products/productCard.tsx Adds standard product card component using shared chrome and tokens.
components/products/moreProductsPanel.tsx Adds grid “More products coming” filler panel with computed spans.
components/layout/homeTheme.tsx Adds /products to THEMED_ROUTES so it receives home theming.
app/(about)/products/products-index.tsx Rebuilds /products index layout and renders new card components + filler panel.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread components/products/tinaProductCard.tsx Outdated
// overlay is unnecessary, which also means the focus outline can sit on the
// card itself again instead of on a child that overflow-hidden would clip.
<CustomLink
href={product.url ?? ""}
Comment thread components/products/productCard.tsx Outdated
// (/products/rewards) through next/link and adds target/rel to the
// genuinely external ones.
<CustomLink
href={product.url ?? ""}
}) => {
return (
<CustomLink
href={product.url ?? ""}
@hveraus hveraus added the no-issue This label is used to bypass the PR-Lint check. Should be used for non-coding changes label Aug 13, 2026
hveraus added a commit that referenced this pull request Aug 13, 2026
Re-exports the decorative bloom at 500x320 instead of 1670x1069, taking the
file from 1.1 MB to 164 KB. Aspect ratio is unchanged (1.5625 vs 1.5622), so
the artwork renders identically.

Also corrects the hardcoded width/height on the <Image>. next/image derives
its srcset from `width`, so leaving 1670 there would have requested
1670w/3840w candidates of a 500px source and given back most of the saving.

Addresses the asset-weight finding from the multi-agent review of #4984.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Re-exports the decorative bloom at 500x320 instead of 1670x1069, taking the
file from 1.1 MB to 164 KB. Aspect ratio is unchanged (1.5625 vs 1.5622), so
the artwork renders identically.

Also corrects the hardcoded width/height on the <Image>. next/image derives
its srcset from `width`, so leaving 1670 there would have requested
1670w/3840w candidates of a 500px source and given back most of the saving.

Addresses the asset-weight finding from the multi-agent review of #4984.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@hveraus
hveraus force-pushed the Refine-products-index-page branch from 83efb6f to 8c0f6bc Compare August 13, 2026 05:11
hveraus and others added 2 commits August 13, 2026 08:40
Follow-up to the review of #4984.

Fix
- A product with no `url` lost its entire card. All three cards passed
  `product.url ?? ""` and CustomLink returns a bare fragment when href is
  falsy, discarding the wrapper along with its className, so the logo plate,
  copy and footer became loose grid items. `url` is optional in
  tina/collections/products.tsx, and the design this replaced guarded it via
  `{page.url && ...}` in pageCards.tsx.
  New ProductCardShell renders CustomLink when there is a href and the same
  shell as a plain div when there is not. Guarded here rather than in
  CustomLink on purpose: that component has ~99 call sites, several inside <p>
  elements, where emitting a <div> would be invalid HTML and a hydration
  mismatch.
- Covered by __tests__/components/products/productCard.tsx, which fails on the
  previous implementation. jest.config.ts gains a `@/lib/*` moduleNameMapper
  entry so components importing cn() are testable at all.

Brand cards (TinaCMS, YakShaver)
- Dropped the arrow affordance and replaced the destination URL with a
  "Learn More" chip. The chip is a styled <span>, not a <button> or nested
  <a>, both of which are invalid inside the card's own <a>.
- Chip grows to 105% on card hover; needed transition-all rather than
  transition-colors for the transform to ease.
- Right padding raised to 40px (`pr-10`), kept after `p-6` in the cn() list
  because tailwind-merge drops a `pr-*` that precedes a `p-*`.
- Tina llama watermark enlarged to h-3/4 and pushed to -bottom-4, so
  overflow-hidden crops the feet deliberately.

Standard cards
- Logo plate radius raised from rounded-utility (8px) to rounded-card (16px).
- Arrow is now filled at rest and only turns and grows on hover, achieved by
  removing the overrides that forced an outline-to-fill effect and pinned
  group-hover:scale-100. ArrowCircle's own bg-foreground/text-background
  defaults give a dark circle in light mode and a white one in dark mode.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Replaces the copy on the /products TinaCMS card so it covers TinaDocs as well
as the visual editor.

Note the same sentence is still duplicated in content/megamenu/menu.json, which
is deliberately left alone here - the mega menu is a separate surface, so the
two now differ.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@hveraus

hveraus commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

/deploy

@github-actions

Copy link
Copy Markdown
Contributor

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

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

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Lighthouse Report

🌐 URL ⚡ Performance ♿ Accessibility ✅ Best Practices 🔍 SEO 📦 Bundle Size 🗑️ Unused Bundle
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/ 33 100 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/articles 90 97 59 57 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/company/about-us 68 100 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/company/clients 98 95 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/company/contact-us 72 92 59 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/consulting 87 97 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/consulting/net-upgrade 80 100 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/consulting/web-applications 75 100 59 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/employment 78 95 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/events/angular-superpowers-tour 54 97 56 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/events/ai-workshop 92 92 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/events/ai-workshop-essentials 69 97 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/netug/sydney 78 94 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/training/internship-fullstack 80 91 59 61 0.00 MB 0.00 MB

Tags
- New optional `tags` string list on productsList (tina/collections/products.tsx)
  so the copy stays editable in the CMS like every other product field, with
  three authored per product. At most three render; blanks and extras are
  dropped, so an editor can add a fourth without changing a card's height.
- Rendered as sentence-case chips with a brand-red stroke and a 16% red wash.
  The stroke is what makes them read as chips: the neutral hairline they started
  with measured 1.25:1 against the light card and 1.38:1 against the dark one,
  where red measures 4.53:1 and 3.99:1.
- The label stays neutral rather than going red with the stroke: text-brand is
  only 3.99:1 on the dark card at 12px, which fails AA. The TinaCMS card keeps
  white outline chips for the inverse reason - red measures 1.15:1 against its
  orange field, and a white wash would drop its label to 4.33:1.

Chrome
- Both brand cards' Learn More chips now come from one shared constant, so the
  near-black label is identical on each. The TinaCMS one previously used the
  darkened brand orange.
- The footer arrow's disc no longer uses ArrowCircle's full-strength inversion,
  which measured 16.7:1 against the light card and 19.0:1 against the dark one -
  more contrast than the card title, for an affordance. Now 1.27:1 / 1.20:1,
  with the glyph gaining contrast as the disc fades. Overridden at the call site
  only; the v3 blocks still get the strong version.

All contrast figures measured in a browser against the rendered surfaces.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@hveraus

hveraus commented Aug 19, 2026

Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

…-page

# Conflicts:
#	tina/tina-lock.json

Co-authored-by: hveraus <4745861+hveraus@users.noreply.github.com>

Copilot AI commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Merge conflicts resolved — the only conflict was in tina/tina-lock.json (auto-generated), which I resolved by accepting main's version. The branch is now up to date with main.

…solution

Co-authored-by: hveraus <4745861+hveraus@users.noreply.github.com>
Co-authored-by: hveraus <4745861+hveraus@users.noreply.github.com>
The merge of main at b1549ea hand-resolved the conflict in this generated
file and left its `eventsCalendar` collection at the pre-#4978 shape, so the
lock disagreed with tina/collections/events-calendar.tsx in the same tree:

  committed lock   26 fields, including an obsolete `headerLayout`
  source schema    32 fields

Missing from the lock were availability, bannerImage, ctaLabel, entryCost,
lead, price and venue. `tinacms build --content=local` checks the local schema
against the one TinaCloud indexed, so it exited 1 and took `pnpm run build`
with it - surfacing only as the Docker `buildx failed` wrapper in CI, since the
job logs are not readable without admin rights. Every `PR - build` run since
that merge failed this way; the two follow-up commits that hand-patched this
file did not fully restore it.

Regenerated rather than hand-edited, which is the only reliable way to touch a
30MB generated file. Verified structurally against origin/main's lock: all 46
collections, the entire lookup table and all 20035 GraphQL definitions are now
identical to main's, with the sole exception of productsIndex gaining the
`tags` field this PR adds (schema plus ProductsIndexProductsList, its Filter
and its Mutation).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@hveraus

hveraus commented Aug 19, 2026

Copy link
Copy Markdown
Member Author

/deploy

@github-actions

Copy link
Copy Markdown
Contributor

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

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

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Lighthouse Report

🌐 URL ⚡ Performance ♿ Accessibility ✅ Best Practices 🔍 SEO 📦 Bundle Size 🗑️ Unused Bundle
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/ 47 92 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/articles 38 92 56 50 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/company/about-us 44 92 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/company/clients 43 89 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/company/contact-us 37 88 56 54 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/consulting 38 92 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/consulting/net-upgrade 36 92 56 54 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/consulting/web-applications 38 92 56 54 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/employment 53 89 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/events/angular-superpowers-tour 40 92 52 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/events/ai-workshop 60 87 52 54 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/events/ai-workshop-essentials 36 92 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/netug/sydney 47 92 56 54 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/training/internship-fullstack 52 89 56 54 0.00 MB 0.00 MB

hveraus and others added 4 commits August 20, 2026 11:12
Swap SophieHub/SSW Dory order and refresh several products' tag copy
(TinaCMS, YakShaver, SophieHub, CodeAuditor, SSW Rewards) to better
describe each product's capability at a glance.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Three tags per card pushed most of the grid onto a second chip row at
the 4-up tier; the first two already communicate what a product is, so
drop MAX_VISIBLE_TAGS to 2 (editors can still store more — extras are
just not rendered). Also drops MoreProductsPanel's second line, which
read as filler copy once the heading said the whole thing, and updates
a stale comment about SSW Rewards' URL now being absolute rather than
site-relative.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A stray lockfile in a parent directory (e.g. ~/package-lock.json) made
Turbopack infer the workspace root above this project, which broke
resolution of instrumentation.ts and crashed `next dev` on startup.
Pin turbopack.root explicitly to the project directory.

tsconfig.json's accompanying diff is Next.js's own auto-update for
Next 16 (moduleResolution: bundler, jsx: react-jsx, .next/dev/types).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@hveraus

hveraus commented Aug 20, 2026

Copy link
Copy Markdown
Member Author

/deploy

@github-actions

Copy link
Copy Markdown
Contributor

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

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

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Lighthouse Report

🌐 URL ⚡ Performance ♿ Accessibility ✅ Best Practices 🔍 SEO 📦 Bundle Size 🗑️ Unused Bundle
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/ 26 100 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/articles 91 97 59 57 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/company/about-us 71 100 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/company/clients 99 95 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/company/contact-us 81 92 59 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/consulting 87 97 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/consulting/net-upgrade 79 100 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/consulting/web-applications 81 100 59 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/employment 78 95 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/events/angular-superpowers-tour 77 97 56 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/events/ai-workshop 98 92 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/events/ai-workshop-essentials 48 97 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/netug/sydney 76 94 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/training/internship-fullstack 94 91 59 61 0.00 MB 0.00 MB

@isaaclombardssw isaaclombardssw left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖 Agent Review

Requesting changes on four things, all commented inline against the diff.

🚨 Must Fix / Address

  • 💄 Comment volume - 477 of 888 lines in components/products/ are comment (54%), and two of them are already wrong.
  • SSW Rewards link - relative to absolute non-www, which costs the soft navigation and adds a 301 hop.
  • tsconfig.json - no longer Prettier-clean where main was, plus an undeclared repo-wide moduleResolution/jsx flip.
  • subTitle - still required: true and populated, but never rendered.

🤏 Small Feedback

  • Make the brand-card ordering explicit rather than assumed.
  • BRAND_CARDS and the render branches state the same list twice.
  • "Fun Quizes" typo in the Rewards tags.

📞 Callouts

  • The rest is in good shape - CI passes on this SHA, tests and lint are clean locally, and the THEMED_ROUTES opt-in, the data-tina-field fix and the falsy-href guard in ProductCardShell are all nicely done. This is a request for changes on the list above only.

@@ -0,0 +1,170 @@
// Shared chrome for the three kinds of card on /products (standard, TinaCMS,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment volume. components/products/ is 477 of 888 lines comment (54%), and this file is 127 of 170 (74%). The baseline across components/ is about 4%.

The twMerge traps are worth keeping - I ran twMerge and confirmed outline-2 really does swallow the bare outline and silently kill the focus indicator. That is a genuine trap and the comment earns its place.

What I would cut is the revision narrative ("an earlier revision lifted the card 6px", "two intermediate revisions were still too strong") which git already stores, and the hand-measured contrast ratios, which nothing tests and which quietly become false the moment someone changes --card.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

done with Claude:

Removed revision narrative — sentences describing prior iterations (e.g. "an earlier revision lifted the card 6px," "two intermediate revisions were still too strong," the removed install-command chip / gradient blend-mode history). Git history already covers this.
Removed hardcoded contrast ratios — every manually-measured X.XX:1 value, since nothing tests them and they'd silently go stale if a --card/--brand token changes. Kept the accessibility intent instead (e.g. "clears WCAG 3:1," "would fail AA in dark mode").
Kept as-is: the outline-2/twMerge focus-indicator warning in shared.ts, plus all other why-comments explaining twMerge conflicts, library quirks, and non-obvious trade-offs.

Net diff: -142/+103 lines, comment-only (verified no non-comment lines touched), tests still pass. Also fixed a stale doc-comment in yakShaverProductCard.tsx that claimed the text column was width-capped when the actual code (and the per-element comment) shows it isn't.

Comment thread components/products/productCard.tsx Outdated
return (
// ProductCardShell, not a raw <a>: for a product that has a url it wraps
// CustomLink, which routes the one on-site product (SSW Rewards, at
// https://www.ssw.com.au/products/rewards) through next/link and adds

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This says https://www.ssw.com.au/products/rewards, but the content has no www - it is https://ssw.com.au/products/rewards. The missing www is exactly what causes the redirect hop flagged in index.json.

A second one at line 49: the chrome is not identical to ConsultingCard, which uses rounded-xl where this uses rounded-card. Two comments drifted from the code inside one PR is the argument for fewer of them.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed the comment and made the requested display change:

Fixed the stale/inaccurate comments they flagged (productCard.tsx):

The doc-comment referenced https://www.ssw.com.au/products/rewards — updated to https://ssw.com.au/products/rewards to match the actual content (no www).
The comment claiming ConsultingCard and this card have "identical card chrome" was wrong — ConsultingCard uses rounded-xl (12px), this uses rounded-card (16px). Reworded to state parity is on colour/motion only, not shape, so the comment can't drift from the code again.
Changed the displayed URL (shared.ts):

destinationLabel used to strip the path and show hostname only. It now keeps the path when the URL points below the domain root, so SSW Rewards' footer shows ssw.com.au/products/rewards instead of the ambiguous ssw.com.au (which read like a link to the homepage).
Side effect, not a regression: SophieBot's URL also has a non-root path (/sophiebot), so its footer label picked up the same fix and now shows sswsophie.com/sophiebot instead of just sswsophie.com. Every other product's URL is root-path, so their labels are unchanged.

Comment thread content/products/index/index.json Outdated
Comment thread tsconfig.json Outdated
Comment thread app/(about)/products/products-index.tsx Outdated
<PageCard page={product} key={index} />
))}
</div>
{/* The CMS `subTitle` is deliberately not rendered. It still holds

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please remove subTitle properly rather than dropping it at the render.

The reasoning here is that the field is required: true so it cannot be emptied - but this PR already edits tina/collections/products.tsx to add tags and regenerates tina-lock.json, so the collection is in play.

As it stands an editor sees a mandatory field, fills it in, and nothing happens on the page, with no signal anywhere in the CMS. Either drop required, or add a description saying it is not displayed - exactly what the new tags field does.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Don't understand, but this is what Claude fixed:

Removed subTitle from the schema properly rather than leaving it dropped at render:

tina/collections/products.tsx — deleted the field definition entirely.
content/products/index/index.json — removed the orphaned subTitle key and its content.
app/(about)/products/products-index.tsx — removed the now-obsolete comment explaining the render-time drop.
tina/tina-lock.json — regenerated via tinacms build --content=local. Verified productsIndex now has ['seo', 'title', 'productsList'] (matches main minus subTitle), productsList still carries tags, and the total collection count is unchanged.

Comment thread app/(about)/products/products-index.tsx Outdated

// Each brand card occupies two grid cells at the tiers where it spans, so the
// trailing gap the panel fills is measured in cells, not products.
const cellCount =

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Worth making the ordering explicit. This is exact only because TinaCMS and YakShaver happen to lead the CMS list.

A col-span-2 card that cannot fit the remaining columns is bumped to the next row and leaves the rest of the current row empty (sparse auto-placement, the default). cellCount never sees that hole. I simulated placement across orderings: with the current order the panel span is right at both tiers, but move any standard card in front of a brand card and real cells go 13 to 14, so at 4-up the panel computes span 3 into 2 free slots, cannot fit, and wraps to a row of its own - the ragged trailing row the panel exists to prevent.

Sorting brand cards to the front before the map is one line, makes this count provably exact (2 divides both 2 and 4, so brand-first never leaves a hole), and changes nothing visually today.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed the correctness bug the reviewer flagged in app/(about)/products/products-index.tsx: cellCount was only accurate because TinaCMS and YakShaver happen to lead the CMS list today. Under CSS Grid's default sparse auto-placement, a col-span-2 brand card that doesn't fit the remaining columns of its row gets bumped to a fresh row, leaving the skipped cell empty — cellCount's arithmetic can't see that gap, so a reorder in the CMS would make the trailing MoreProductsPanel compute the wrong span and wrap into its own ragged row.

Fix: sort brand cards to the front of the render order before computing cellCount and mapping the grid, using a stable sort so CMS order is otherwise preserved on both sides of the split. Verified this makes the count provably correct (2 divides both the 2-col and 4-col breakpoints, so brand-first can never leave a gap) and changes nothing visually today — confirmed the live-rendered grid order is exactly TinaCMS, YakShaver, SugarLearning, EagleEye, TimePro, SophieBot, SophieHub, SSW Dory, CodeAuditor, SSW Rewards, SmashingBarrier, unchanged from the CMS order.

Bonus catch along the way: while verifying this, I hit a page-breaking error (Cannot read properties of null (reading 'data')) that turned out to be unrelated to this edit — the manual tinacms build I ran earlier for the subTitle fix had left the running dev server's Turbopack/Tina cache stale. Traced it by querying the local GraphQL server directly and calling the generated query function standalone (both succeeded, proving the schema/content were fine), then restarted the dev server to clear the stale cache. It's now healthy and serving the page correctly.

Comment thread app/(about)/products/products-index.tsx Outdated
// The two products whose owners' media kits require their own card surface.
// Matched on name rather than list position so the treatment follows the
// product if an editor reorders the CMS list.
const BRAND_CARDS = ["tinacms", "yakshaver"];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Minor: this list drives cellCount, but rendering branches on hardcoded name === "tinacms" / "yakshaver" literals at lines 106 and 114. Hardcoding these two is completely fine - it is just stated in two places, so adding a third name here would inflate the panel span against a card that never actually spans.

One Record<string, FC> that both the count and the render read from would close it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Consolidated the brand-card lookup into a single source of truth, per the reviewer's suggestion, since the previous BRAND_CARDS array plus the two hardcoded name === "tinacms" / name === "yakshaver" render branches were three separately-maintained lists that cellCount and the JSX could silently drift apart from.

Change in app/(about)/products/products-index.tsx:

Replaced BRAND_CARDS/isBrandCard with BRAND_CARD_COMPONENTS: Record<string, FC> mapping "tinacms" → TinaProductCard and "yakshaver" → YakShaverProductCard, plus a brandCardFor(name) lookup.
The sort (brand-first ordering), cellCount, and the render's brand-card branch all now read from this one map — the two if (name === ...) branches collapsed into a single if (BrandCard) return <BrandCard .../>.
Kept it as a plain object rather than reaching for anything fancier, since it's still just two entries.

Comment thread content/products/index/index.json Outdated
- Trim comment bloat in components/products/*: drop revision-narrative
  and hardcoded contrast-ratio comments, keep twMerge/why comments.
- Fix stale comments referencing the old absolute Rewards URL and the
  false "identical chrome" claim vs ConsultingCard.
- Revert SSW Rewards' url to the relative /products/rewards path used
  on main; destinationLabel now appends the path for on-site links so
  the footer still shows the full destination.
- Remove the CMS subTitle field properly (schema, content, generated
  lock) instead of leaving it unrendered.
- Fix products-index.tsx's brand-card ordering: pin brand cards first
  so cellCount's grid-cell arithmetic can't be thrown off by sparse
  auto-placement if the CMS list is ever reordered, and consolidate the
  brand-card name checks into one Record<string, FC> both cellCount and
  the render read from.
- Revert tsconfig.json to main: its diff was Next's own dev-server
  auto-rewrite, unrelated to this PR's turbopack.root fix.
- Fix "Quizes" typo in SSW Rewards' tags.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@hveraus

hveraus commented Aug 20, 2026

Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

…-page

Co-authored-by: hveraus <4745861+hveraus@users.noreply.github.com>

Copilot AI commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved and pushed in ec18b525. The branch is merged with main, the tina/tina-lock.json conflict is resolved, and targeted lint/test validation passed.

Copilot's conflict resolution when merging main into this branch left
tina-lock.json out of sync with the merged collections schema (main
added the Pills block among other changes). tinacms build --content=local
audits the local schema against this lock, so it exited 1 and took
npm run build with it — the same failure mode as the earlier
4837779 incident, just surfaced through Copilot's merge this time.

Regenerated via tinacms build rather than hand-edited, since it's a
30MB generated file. Verified structurally: still 46 collections, the
new Pills block schema from main is present, and productsIndex still
matches this branch's changes (no subTitle, tags on productsList).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@hveraus

hveraus commented Aug 20, 2026

Copy link
Copy Markdown
Member Author

/deploy

@github-actions

Copy link
Copy Markdown
Contributor

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

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

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Lighthouse Report

🌐 URL ⚡ Performance ♿ Accessibility ✅ Best Practices 🔍 SEO 📦 Bundle Size 🗑️ Unused Bundle
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/ 70 100 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/articles 91 97 59 57 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/company/about-us 69 100 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/company/clients 91 95 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/company/contact-us 81 92 59 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/consulting 88 97 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/consulting/net-upgrade 85 100 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/consulting/web-applications 76 100 59 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/employment 69 95 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/events/angular-superpowers-tour 56 97 56 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/events/ai-workshop 85 92 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/events/ai-workshop-essentials 75 97 59 69 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/netug/sydney 81 94 56 61 0.00 MB 0.00 MB
https://app-sswwebsite-9eb3-pr-4984.azurewebsites.net/training/internship-fullstack 81 91 59 61 0.00 MB 0.00 MB

@isaaclombardssw isaaclombardssw left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please cut the comments right down - this is the one item from last round that measurably didn't move. components/products/ went from 40.1% comment lines to 39.6%, and shared.ts is still 119 comment lines to 34 of code. The contrast ratios moved to styles.css rather than going away. components/consulting/ next door is 7 comment lines across 117 lines of code.

About 10 lines across the whole folder is what I'd expect. Worth keeping: the border-0.75 note (shared.ts:9), the twMerge outline-2 trap (shared.ts:26), why the spans are looked up in a map instead of interpolated, and the contrast values in styles.css. The rest is restating the code, aesthetic rationale that belongs in the PR description, or revision narrative git already stores.

The risk isn't just noise. Nothing compiles or tests a comment, so volume is exposure - and two are wrong right now. shared.ts:144 says every product is authored with an absolute URL, which your own Rewards fix falsified this round, and it sits directly above the new URL(url, base) fallback telling the next person the base isn't needed. shared.ts:136 lists duplicates as a case visibleTags handles, but it doesn't, and key={tag} throws on a repeated tag.

Drops the trailing dashed panel and the grid-cell math that only
existed to size it.
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.

4 participants