Skip to content

Port the heykody.dev redesign (all 9 surfaces) + motion polish - #1233

Merged
kody-bot merged 26 commits into
mainfrom
redesign-port
Aug 6, 2026
Merged

kody-bot merged 26 commits into
mainfrom
redesign-port

Conversation

@vojtaholik

@vojtaholik vojtaholik commented Aug 5, 2026 •

Copy link
Copy Markdown
Collaborator

Ports the approved heykody.dev redesign prototype into the app — the full surface set in one branch, each surface implemented and adversarially reviewed against the prototype before landing.

What's inside

Foundation

  • Green OKLCH token system on the existing custom-property names (--color-primary = the green, flat grey canvas, paired --*-dark values; the data-theme mechanism is unchanged)
  • Self-hosted Bricolage Grotesque (display) + Wix Madefor Text (body) — Google Fonts wouldn't survive the style-src/font-src 'self' CSP
  • Motion system: one ease (cubic-bezier(0.22, 1, 0.36, 1)), data-rise page-open choreography, scroll/card reveals, everything enhance-only (html.js) and off under prefers-reduced-motion
  • Shared style primitives: pill/ghost buttons, page-head scaffold, prose, surface cards, layout-stable swap-label copy buttons

Surfaces: landing, pricing, blog index + post, community index + detail, login, onboarding (the new 3-step wizard), account (incl. the sticky sidebar scaffold that account + admin pages share)

Kept intact: every loader, form POST, frame mechanism, auth flow (password/passkeys/social/Turnstile), the per-pinned-commit community icon architecture, and all server-owned content (plans.ts limits, blog markdown, community data — nothing hardcoded)

Notable fixes along the way

  • Posts now render markdown headings at authored depth (## → h2) instead of the README demotion; README/community rendering unchanged and test-pinned
  • formatBlogPostDate uses a fixed locale (was a SSR/hydration mismatch)
  • method="post" on the auth forms so a pre-hydration native submit can never GET credentials into the URL
  • aria-current nav state, focus-ring layering fixes, green accent-color for radios/checkboxes

Verification

  • npm run typecheck clean; npm run test:node 475 files / 1581 tests green on top of latest main
  • Every surface browser-verified in both themes, mobile widths, and reduced motion

Known follow-ups

  • Account sidebar's grid implementation could be simplified (works, commented)
  • The prototype's onboarding-callout dismiss ✕ needs a persistence decision
  • Pricing says "every limit is published below" while maxRepos exists unpublished — copy question

🤖 Generated with Claude Code

https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf

Motion & interaction polish (added 2026-08-05)

Four follow-up commits from a full animation audit:

  • Native route animations: SPA navigations now commit inside document.startViewTransition() (feature-detected; Firefox and reduced-motion get today's instant swap). Old page fades 120ms, new page fades + rises 8px over 220ms; header/footer/progress bar are pinned out of the snapshot. The [data-rise] page-open choreography now plays on full document loads only.
  • @starting-style entrances: onboarding client-tab panel and BYOK details enter via interruptible transitions instead of keyframes; account settings and community report disclosures no longer teleport open.
  • Feedback physicality: onboarding checkmark/status pops reuse the shared success-in at 200ms (was 400ms from scale(0.5)); tab pills and wizard step buttons compress on press; hover art lifts aligned to house durations.
  • Fixes: hero pointer-parallax rAF loop no longer runs forever while the cursor rests on the stage; reduced-motion now keeps color/opacity feedback (only movement is dropped); motion tokens consolidated (140ms stragglers, WAAPI ease literal, lantern glow deduped).

Summary by CodeRabbit

  • New Features

    • Redesigned home, login, pricing, blog, community, onboarding, account, and timeline experiences.
    • Added responsive navigation and footer links, theme switching, waitlist signup, blog “read next” links, and richer community views.
    • Added accessible illustrations, copy controls, reveal animations, reduced-motion support, and light/dark social preview images.
  • Bug Fixes

    • Improved navigation transitions, scroll restoration, markdown rendering, date formatting, and protected-form retry handling.
    • Expanded smoke and server-rendering coverage for redesigned pages.

vojtaholik and others added 5 commits August 4, 2026 17:28
Green OKLCH token system on the existing custom-property names, self-hosted
Bricolage Grotesque + Wix Madefor Text, and the full surface port from the
approved prototype: landing, pricing, blog index/post, community index/detail,
login, onboarding, account (sticky sidebar scaffold shared by account + admin).
Shared chrome (site header/footer, theme toggle, reveal system), style
primitives (pill/ghost buttons, page-head, prose, cards, swap-label copy
buttons), motion system (single ease, data-rise/reveal, reduced-motion
first-class), and the unlayered focus-ring escape hatches.

Each surface implemented and adversarially reviewed against the prototype;
typecheck clean, 1594 node tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
…otion tokens

- stageParallax kept a requestAnimationFrame loop alive forever while the
  pointer rested off-center; stop once converged and snap to target
- reduced-motion blocks kept feedback: color/opacity fades survive, only
  transform/blur/scale motion is dropped (buttons, swap labels, cards,
  theme toggle; auth input block removed — it was color-only)
- transitions.easeOutValue literal for WAAPI call sites (wizardEase removed)
- 140ms stragglers aligned to the 160ms --transition-fast token
- lantern glow deduplicated into getLanternGlowCss({ maxWidth })

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
- checkmark/status pops reuse the shared success-in keyframes at 200ms
  instead of local 400ms scale(0.5) pops
- form success message matches the error entrance speed (250ms)
- tab pills and wizard step buttons compress on press (scale 0.97);
  starter cards drop their hover lift under the press
- 320ms hover art lifts aligned to the 200ms house duration

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
…tions

- client-tab panel and BYOK details enter via @starting-style + transition
  (interruptible; local entrance keyframes deleted)
- account settings and community report disclosures get a quiet 200ms
  entrance instead of teleporting open

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
- the router commit wraps the DOM swap in document.startViewTransition
  (feature-detected, reduced-motion gated, superseding navigations skip
  the in-flight transition); navigationend now fires after the swap
- old page fades 120ms, new page fades + rises 8px over 220ms on the
  house ease; header, footer, and progress bar are pinned out of the
  root snapshot via view-transition-name
- [data-rise] page-open choreography runs on full document loads only —
  SPA navigations get the view transition as their entrance
- scroll restoration scrolls instantly (never smooth) and makes its
  first attempt synchronously so back-navigation lands pre-snapshot
- progress bar animates transform: scaleX instead of width

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
@coderabbitai

coderabbitai Bot commented Aug 5, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR redesigns the shared shell, marketing and authentication routes, onboarding and account surfaces, community and blog rendering, timeline presentation, motion behavior, theme handling, and OG image generation. It also adds shared style primitives, form protection, blog navigation data, and expanded validation.

Changes

Site redesign

Layer / File(s) Summary
Shell and design system
packages/worker/client/app.tsx, packages/worker/client/client-router.tsx, packages/worker/client/site-header.tsx, packages/worker/client/site-footer.tsx, packages/worker/client/styles/*, packages/worker/public/*
Adds route-aware shell layouts, shared navigation, SPA view transitions, theme initialization, design tokens, motion rules, and reusable style primitives.
Shared interactions
packages/worker/client/copy-text-button.tsx, packages/worker/client/hero-stage.tsx, packages/worker/client/markdown-view.tsx, packages/worker/client/reveal.ts, packages/worker/client/navigation-progress.tsx, packages/worker/client/scroll-restoration.tsx, packages/worker/client/theme-toggle.tsx, packages/worker/client/public-form-protection.ts
Adds configurable copy buttons, hero parallax, configurable markdown rendering, reveal helpers, instant scroll restoration, theme toggling, navigation progress styling, and Turnstile reset support.
Marketing and auth routes
packages/worker/client/routes/home.tsx, packages/worker/client/routes/login.tsx, packages/worker/client/routes/pricing.tsx, packages/worker/client/routes/blog*.tsx, packages/worker/client/routes/community*.tsx, packages/worker/client/routes/onboarding*.tsx
Replaces the landing, login, pricing, blog, community, and onboarding layouts with redesigned responsive pages, waitlist flows, editorial content, plan tables, and wizard panels.
Account and admin surfaces
packages/worker/client/routes/account*.tsx, packages/worker/client/routes/admin-*.tsx
Migrates account and admin controls to account-specific inputs, selects, field rings, pill buttons, ghost buttons, danger pills, responsive navigation, and section styles.

Community and blog server data

Layer / File(s) Summary
Community, blog, timeline, and OG data
packages/worker/src/app/*, packages/worker/src/blog/*, packages/worker/src/community/*, packages/worker/src/og/*
Updates server-rendered community markup, timeline grouping and formatting, blog date and read-next data, document theme/font resources, and theme-aware OG image rendering.
Validation
e2e/smoke.spec.ts, packages/worker/client/*.node.test.ts, packages/worker/src/app/*.node.test.ts, packages/worker/src/blog/*.node.test.ts, packages/worker/src/og/*.node.test.ts
Adds coverage for redesigned headings, shell-area transitions, markdown options, SSR pages, community markup, blog navigation, timeline grouping, formatted pricing limits, and OG themes.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: kentcdodds

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary redesign across nine surfaces and the associated motion improvements.
Description check ✅ Passed The description covers intent, scope, system changes, testing, retained behavior, fixes, and known follow-ups in sufficient detail.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch redesign-port

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

vojtaholik and others added 11 commits August 5, 2026 10:08
The account/admin shell had the shared 72rem box but none of the
horizontal gutter every other container carries, so on wide screens its
content ran ~5rem wider than the header nav above it. Give it the gutter
(as a shared pageGutter token), start the sidebar rail at that gutter,
and zero <main>'s generic inset for the shell so the two don't stack.

Switching sidebar sections is a route change, so the unchanged rail was
crossfading and rising with the rest of the page inside the view
transition's root snapshot. Name it and pin it, opt-in per nav —
/admin/community-reports renders a second, page-local nav, and a
duplicate view-transition-name makes the browser skip the transition.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
The port dropped `.account`'s own padding, so the last section sat 8px
off the footer hairline (whatever <main>'s generic inset happened to be).
The shell now owns its full box.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
…t art

- getSelectCss(): <select> in the redesign's field vocabulary with our own
  chevron, inset by the field's padding so option text never runs under it
- pill/ghost buttons take size: 'sm' (the prototype's .account-actions size)
  so in-page actions stop reaching for the legacy body-font button
- scrollbar-gutter: stable — a short page and a long one now have the same
  content width, so navigating between them no longer shifts sideways
- the onboarding callout uses the prototype's bust cutout, which stands on
  the card's bottom edge; the full-body art it shipped with just floated

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
The account shell was ported but the controls inside its pages were not,
so every page mixed two design systems: dropdowns with the raw platform
chevron, fields with the old 1px/6px box, and buttons in the body font at
a lighter weight sitting next to redesign pill buttons.

Selects now use getSelectCss, text fields the shared account input, and
actions the pill/ghost getters at the prototype's in-page size. account.tsx
drops its hand-rolled compact button overrides — size: 'sm' is exactly
those values. Destructive actions keep getDangerButtonCss.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
Same conversion as the account sweep: selects get our chevron, text
fields the shared account input, actions the pill/ghost getters at the
prototype's in-page size. Destructive actions keep getDangerButtonCss.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
Switching sidebar sections kept shifting and wobbling. Pinning the rail
out of the root snapshot did not fix it and could not: the rail is a
full-height absolute track, so its snapshot box is as tall as the page,
and each section is a different height — the transition scaled the rail
between the two. Its sticky column moves relative to the viewport when
the navigation resets scroll, too.

Tab switching inside a shell is frequent navigation whose surrounding
chrome does not change, so it should not animate at all. Skip the
transition when a navigation stays inside one shell area, and drop the
rail pin the skip replaces.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
…here

The setup-prompt copy buttons still used the pre-redesign variant, so they
sat in the body font next to buttons the sweep had already moved to the
display face. CopyTextButton gains the in-page 'sm' size the account area
uses, and the integration cards ask for the ghost variant at that size.

The connection and OAuth-app rows in the sidebar navigate on click but had
no press feedback at all, and their hover was ungated on touch. They now
compress on press like every other pressable surface.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
The account and admin sweeps deliberately skipped getDangerButtonCss,
which left every destructive action as a filled salmon pill in the body
font — the one control on those pages still speaking the old vocabulary.

getDangerPillCss carries the ghost pill's quiet shape in the danger color:
these sit inline in lists next to ordinary actions, so a filled red fill
shouts louder than the action deserves. The ring and color mark it as
destructive; hover commits to the fill. Verified in both themes.

Left oauth-authorize.tsx alone — that page has not been redesigned, so
converting only its danger button would make it internally inconsistent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
Below 820px the nav links and session corner wrapped onto extra rows and
pushed the page down. They now fold into a menu the platform owns: a
native popover, so the top layer, light dismiss, Escape, and focus return
to the toggle all come for free rather than from a focus-trap library.

The entrance is a plain transition — @starting-style for the first frame,
discrete display/overlay for the rest — at 180ms, the dropdown budget,
since this opens on every phone visit. The toggle folds into a cross with
transform and opacity only; reduced motion keeps the end state and drops
the tween. Menu links navigate client-side, which nothing would otherwise
dismiss, so the router closes the panel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
It was the pre-redesign secondary button squeezed into the nav strip: a
squat bordered pill in the body font, reading like the page's main action
next to the display-face brand. The prototype's session corner is two
quiet text links — the username, then log out — so the button keeps the
form POST and drops the button chrome.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
@kentcdodds
kentcdodds marked this pull request as ready for review August 5, 2026 13:08
@github-actions

github-actions Bot commented Aug 5, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-1233.kody-a99.workers.dev

Worker: kody-pr-1233
D1: kody-pr-1233-db
KV: kody-pr-1233-oauth-kv

Mocks:

Ports landing/timeline.html. The feed groups by day with the date written
once in a sticky margin column, and collapses consecutive events by one
actor into a run under a single identity — eleven pushes in a morning read
as one person working rather than eleven copies of their face. Each row is
threaded onto a drawn spine by its type glyph and carries the time, which
is what tells four updates to the same package apart.

Grouping and formatting live in a pure, tested module and work in UTC with
a fixed locale, so the server and the client agree on which day an event
belongs to; anything locale-dependent would restructure the groups on
hydration rather than merely reword them.

Also here, found while reviewing the port:
- UserAvatar takes the well variant rather than letting a caller style it
  from a wrapper — every css() class gets its own layer, and this component's
  is registered after its caller's, so the caller silently lost
- rows whose whole box is the link keep their corners when focused, via an
  unlayered rule; a layered one cannot beat the global focus ring
- the inline status spinner is one primitive instead of two copies
- the empty-state art ships as a 39KB webp, not an 891KB png

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 15

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/worker/src/app/community-listings-content.tsx (1)

76-84: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The stretched card link covers the Trusted badge.

listingLinkCss adds an ::after pseudo-element with position: absolute; inset: 0, and listingCardCss sets position: relative. The pseudo-element therefore covers the whole card. The badge <span> is not positioned, so the overlay paints above it and intercepts pointer events.

Two consequences follow. The badge title tooltip never appears, so the only explanation of "Trusted" becomes unreachable. The badge cursor: help is replaced by the link pointer.

Raise the badge above the overlay.

🖱️ Proposed fix
 const trustedBadgeCss = {
 	...communityBadgePillCss,
 	marginLeft: 'auto',
+	// Lift above the stretched card link so the title tooltip stays reachable.
+	position: 'relative' as const,
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/community-listings-content.tsx` around lines 76 - 84,
Update the trusted badge span in the listing card render near listing.trusted to
establish a positioned stacking context above the stretched listing link
overlay, preserving its tooltip and help cursor while leaving the overlay
behavior unchanged.
🧹 Nitpick comments (9)
packages/worker/client/routes/onboarding-starter-card.tsx (1)

242-353: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider moving the shared starter styles into a dedicated style module.

onboarding-starter-card.tsx now exports starterCardCss, starterGhostButtonCss, and starterTooltipSurfaceCss, and onboarding-diy-card.tsx imports them. This makes one component module the style source for another component module. A small onboarding-starter-styles.ts module would keep the dependency direction one-way and remove the tooltipSurfaceCss alias at Line 353.

This is optional and can be deferred.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/client/routes/onboarding-starter-card.tsx` around lines 242 -
353, Move the shared starter style objects out of onboarding-starter-card.tsx
into a dedicated onboarding-starter-styles module so onboarding-diy-card.tsx can
import styles without depending on another component module. Update the exported
style symbols starterCardCss, starterGhostButtonCss, and
starterTooltipSurfaceCss to live in that shared module, and remove the
tooltipSurfaceCss alias from onboarding-starter-card.tsx. Keep the existing
style values and imports unchanged apart from the new one-way dependency.
packages/worker/client/routes/community-detail.tsx (1)

1224-1232: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Style README headings below h3.

renderReadme applies headingOffset: 1, so an authored ### section becomes an h4. readmeProseCss styles only h3, and proseCss styles only h2. An h4 therefore falls back to the user-agent default, which is smaller than the surrounding body text. Add a rule for h4 and deeper so nested README sections keep the prose scale.

♻️ Proposed refactor
 const readmeProseCss = mergeCss(proseCss, {
 	marginTop: '1.4rem',
 	'& h3': {
 		margin: '1.8rem 0 0',
 		fontSize: '1.15rem',
 		fontWeight: 720,
 		letterSpacing: '-0.01em',
 	},
+	'& h4, & h5, & h6': {
+		margin: '1.4rem 0 0',
+		fontSize: '1rem',
+		fontWeight: 700,
+		letterSpacing: '-0.006em',
+	},
 })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/client/routes/community-detail.tsx` around lines 1224 - 1232,
Update readmeProseCss to style h4 and deeper headings in addition to h3,
ensuring headings produced by renderReadme with headingOffset: 1 retain the
intended prose scale instead of browser defaults.
packages/worker/client/routes/login.tsx (1)

1079-1084: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

inlineLinkCss duplicates the definition in home.tsx.

packages/worker/client/routes/home.tsx lines 617-622 declares the same four properties. Move this object into #client/styles/style-primitives.ts and import it in both routes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/client/routes/login.tsx` around lines 1079 - 1084, Move the
shared inlineLinkCss object from the login route into
`#client/styles/style-primitives.ts`, then import and reuse that exported style in
both the login route and home route. Remove the duplicate local definitions
while preserving all four existing properties and values.
packages/worker/src/app/community-detail-content.tsx (1)

14-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the shared community primitives out of the listings frame module.

community-detail-content.tsx now imports communityBadgePillCss, communityTagListCss, communityTagPillCss, and renderCommunityListingName from community-listings-content.tsx. That pulls the whole listings frame component and its renderToString entry point into the detail frame's module graph only to reach four shared values.

Extract the shared name helper and the pill/tag style constants into a dedicated module, for example #app/community-shared-content.tsx, and import it from both frames.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/community-detail-content.tsx` around lines 14 - 20,
Extract communityBadgePillCss, communityTagListCss, communityTagPillCss, and
renderCommunityListingName from community-listings-content.tsx into a dedicated
shared module such as community-shared-content.tsx. Update both
community-detail-content.tsx and community-listings-content.tsx to import these
primitives from the new module, removing the detail frame’s dependency on the
listings frame and its renderToString entry point.
packages/worker/src/app/community-listings-content.tsx (1)

101-112: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

The rating display rule is now implemented twice.

packages/worker/src/app/community-display.ts exports formatCommunityStars, and community-detail-content.tsx still uses it. This card reimplements the same rule inline so the star glyph can carry its own colour. The two copies agree today. A later change to one will not reach the other.

Derive both from one source. For example, have formatCommunityStars return the parts (hasRatings, stars, ratingCount) and let each surface compose its own markup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/community-listings-content.tsx` around lines 101 -
112, Update the rating rendering near listing.averageStars and the shared
formatCommunityStars helper so the card no longer duplicates the rating-display
rule. Extend or reuse formatCommunityStars to provide the shared derived values
(hasRatings, stars, and ratingCount), then compose the card’s markup from those
values while preserving its separately styled star glyph.
packages/worker/client/site-header.tsx (1)

308-315: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

The comment contradicts the rule.

The comment says the actions take the free space and keep the toggle pinned to the right edge. The rule below sets display: none at headerNavMq, so the actions are removed at that width. menuToggleCss pins the toggle with its own marginLeft: 'auto'.

Correct the comment.

♻️ Proposed fix
 const navActionsCss = {
 	display: 'flex',
 	alignItems: 'center',
 	gap: '0.9rem',
-	// The links are gone at this width, so the actions take the free space
-	// and keep the toggle pinned to the right edge.
+	// Below this width the session corner folds into the menu panel; the
+	// toggle pins itself to the right edge with its own `marginLeft: auto`.
 	[headerNavMq]: { display: 'none' },
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/client/site-header.tsx` around lines 308 - 315, Update the
comment above the headerNavMq rule in navActionsCss to state that the navigation
actions are hidden at this width, while menuToggleCss independently pins the
toggle to the right edge with marginLeft: 'auto'.
packages/worker/client/routes/account-integrations.tsx (1)

527-552: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the duplicated sidebar button style.

The two inline css({...}) objects are identical except for the backgroundColor expression. Both now carry the same transition, press scale, hoverMq hover, and reduced-motion rules. Two copies of the same 25-line style block in one file will drift on the next motion pass.

Extract one helper and call it from both sites.

♻️ Proposed refactor

Add near dangerButtonCss at line 124:

function getSidebarAppButtonCss(active: boolean) {
	return {
		display: 'grid',
		gap: spacing.xs,
		padding: `${spacing.xs} ${spacing.sm}`,
		border: 'none',
		borderRadius: radius.md,
		backgroundColor: active ? colors.primarySoftest : 'transparent',
		color: colors.text,
		textAlign: 'left' as const,
		cursor: 'pointer',
		transition: `background-color ${transitions.fast}, scale ${transitions.fast}`,
		// Selecting an app swaps the panel beside this list, which is easy
		// to miss — the press itself has to register.
		'&:active': { scale: '0.98' },
		[hoverMq]: {
			'&:hover': { backgroundColor: colors.primarySoftest },
		},
		'`@media` (prefers-reduced-motion: reduce)': {
			'&:active': { scale: 'none' },
		},
	}
}

Then at line 527:

-														css({
-															display: 'grid',
-															…
-														}),
+														css(getSidebarAppButtonCss(appActive)),

And at line 657:

-														css({
-															display: 'grid',
-															…
-														}),
+														css(getSidebarAppButtonCss(selectedAppSlug === app.slug)),

Separately: both buttons signal the selected state only through backgroundColor. AccountManagementListItemButton receives an explicit active prop for the connection rows below. Consider adding aria-current="true" to these two buttons so screen-reader users get the same signal. That state predates this PR, so treat it as optional follow-up.

Also applies to: 657-683

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/client/routes/account-integrations.tsx` around lines 527 -
552, Extract the shared sidebar button style into a helper near dangerButtonCss,
such as getSidebarAppButtonCss(active), preserving the existing active
background, transition, press-scale, hover, and reduced-motion behavior. Replace
both inline css objects in the sidebar button sites around the connection and
app entries with calls to this helper; do not change the optional aria-current
follow-up.
packages/worker/client/client-router.tsx (1)

79-104: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Clear activeViewTransition when the transition settles.

activeViewTransition keeps the last transition object for the lifetime of the page. skipTransition() on a finished transition is a no-op, so behavior is correct. The reference is still stale state that a future reader can misread as "a transition is running".

♻️ Optional cleanup
-	activeViewTransition = startViewTransition(() => swapDom(onSwapped))
+	const transition = startViewTransition(() => swapDom(onSwapped))
+	activeViewTransition = transition
+	void Promise.resolve(
+		(transition as { finished?: Promise<void> }).finished,
+	).finally(() => {
+		if (activeViewTransition === transition) activeViewTransition = null
+	})

This needs finished added to the local type. Skip it if you prefer the smaller surface.

Also applies to: 124-149

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/client/client-router.tsx` around lines 79 - 104, Clear
activeViewTransition after the view transition settles so it does not retain a
stale completed transition. Update the transition-handling logic around
activeViewTransition to await or attach cleanup to the transition’s finished
promise, setting the reference to null when completion occurs; extend the local
transition type with finished if needed while preserving skipTransition behavior
for active transitions.
packages/worker/client/routes/account-billing.tsx (1)

614-615: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move these constants above AccountBillingRoute.

primaryButtonCss and secondaryButtonCss are declared at the end of the module but referenced at lines 476, 487, 500, 573, and 587. Those references sit inside the render closure, which runs after module evaluation, so there is no temporal dead zone error today.

The order is still fragile. Any future call to AccountBillingRoute during module evaluation would read the bindings inside their temporal dead zone and throw. account-email.tsx and account-integrations.tsx declare the equivalent constants before use.

Declare them near the other module constants around line 44.

♻️ Proposed fix
@@ near line 44
 type PaidTier = 'pro'
 type PlanTier = 'free' | PaidTier
 type SubscriptionStatusTone = 'ok' | 'warn' | 'action' | 'muted'
+
+const primaryButtonCss = getPillButtonCss({ size: 'sm' })
+const secondaryButtonCss = getGhostButtonCss({ size: 'sm' })
@@ at the end of the file
-const primaryButtonCss = getPillButtonCss({ size: 'sm' })
-const secondaryButtonCss = getGhostButtonCss({ size: 'sm' })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/client/routes/account-billing.tsx` around lines 614 - 615,
Move the module-level button style constants used by AccountBillingRoute so they
are declared with the other top-level constants near the start of the module
instead of after the component. Update the placements of primaryButtonCss and
secondaryButtonCss, keeping their existing getPillButtonCss and
getGhostButtonCss initialization unchanged. This should make the bindings
available before any possible AccountBillingRoute access during module
evaluation, matching the pattern used in account-email.tsx and
account-integrations.tsx.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/worker/client/app.tsx`:
- Around line 153-160: Update getListingIdFromPathname and getSlugFromPathname
to catch decodeURIComponent failures when parsing pathname segments and return
null for malformed paths. Preserve their existing identifiers for valid paths so
the isRedesignedMarketingPath classification continues to work normally.

In `@packages/worker/client/client-router.tsx`:
- Around line 116-121: In the Promise created by the swap flow, call resolve()
before invoking onSwapped?.() inside the queued microtask. Keep the existing
queueMicrotask scheduling and callback behavior, ensuring dispatchNavigationEnd
errors cannot prevent the promise returned to startViewTransition from settling.

In `@packages/worker/client/routes/blog-post.tsx`:
- Around line 209-212: Update the status paragraphs in
packages/worker/client/routes/blog-post.tsx at lines 209-212 by adding
role="status" to both the loading and error messages. Also add role="status" to
the loading paragraph in packages/worker/client/routes/community-detail.tsx at
lines 636-638, preserving the existing text and rendering conditions.

In `@packages/worker/client/routes/home.tsx`:
- Around line 490-517: Update the failed-submit handling in the form submission
function containing the response error path to reset the Turnstile widget or
clear its token before returning after a non-OK response. Ensure subsequent
submissions require a fresh human-verification token while preserving the
existing error message and state updates.

In `@packages/worker/client/routes/login.tsx`:
- Around line 456-468: Update packages/worker/client/routes/login.tsx lines
456-468 in renderStatusMessage to keep the status region mounted unconditionally
with a fixed role, remove the hidden-state behavior, and update formMessageCss’s
&:not([hidden]) selector accordingly. In packages/worker/client/routes/home.tsx
lines 520-539, keep the role="status" paragraph mounted for every state and move
focus to it after setState('success', ...) completes.

In `@packages/worker/client/routes/onboarding-mcp-client-tabs.tsx`:
- Around line 41-46: Update the doc comment above the config snippet to use the
current variant names `pill` and `ghost` instead of `primary` and `secondary`,
and state that `ghost` is the default.

In `@packages/worker/client/routes/onboarding.tsx`:
- Around line 638-649: The byok note container in onboarding.tsx uses
aria-labelledby on a plain div, so the association is ignored. Update the outer
element around the “Why there’s no one-click connect” content to either use a
role that supports naming or remove aria-labelledby and rely on the nested h2
with id byok-note-title. Keep the existing title element and visual structure
unchanged.

In `@packages/worker/client/routes/pricing.tsx`:
- Around line 213-221: Update formatLimitBytes to explicitly bound fractional
digits when formatting non-power-of-two byte limits, either by rounding the
converted value or configuring count with appropriate maximum fraction digits.
Preserve the existing KiB, MiB, and GiB unit selection and output format so
derived SSR expectations remain consistent.
- Around line 40-90: Add a “Repositories” row to the appropriate group in
limitGroups using the maxRepos PlanLimits key, so the pricing table displays
every enforced finite limit.

In `@packages/worker/client/styles/style-primitives.ts`:
- Around line 391-395: Update the inline code styling in proseCss so long tokens
inside regular prose can wrap on narrow screens; the current container-level
overflowWrap is not enough when nested code uses nowrap. Keep the existing & pre
code behavior unchanged, and adjust only the inline code rule within proseCss so
non-pre code can break instead of forcing horizontal scrolling. Use the proseCss
selector block and the & pre code exception as the anchors for the change.
- Around line 748-761: Update getSelectCss in
packages/worker/client/styles/style-primitives.ts:748-761 to replace the
hard-coded SVG stroke background with the currentColor mask/background-color
pattern used by getBrandChipCss, and set a theme-aware foreground color for
light and dark surfaces. No direct changes are needed in
packages/worker/client/routes/account-activity.tsx:490-546 or
packages/worker/client/routes/account-email.tsx:462-484 because both already
consume the shared CSS.
- Around line 319-336: Update the `pageHeadCss` pseudo-element styling so the
`&::before` glow is placed behind the heading content instead of painting over
it. Use the existing `pageHeadCss`/`&::before` rules to add the appropriate
layering control on the pseudo-element, while keeping the current positioning,
mask, and `pointerEvents: 'none'` behavior unchanged.

In `@packages/worker/client/theme-toggle.tsx`:
- Around line 21-30: Introduce a shared theme-change update signal consumed by
every ThemeToggle instance in theme-toggle.tsx, replacing the one-time
synchronization with a subscription that updates pressed state and calls
handle.update(). Emit that signal from both toggleTheme() and the system-theme
update path in packages/worker/public/theme-init.js, while preserving the
existing stored-preference behavior and avoiding stale mounted aria-pressed
labels.

In `@packages/worker/src/app/community-detail-content.tsx`:
- Around line 103-106: Update formatCommunityPublishedDate to pass the
established fixed locale to toLocaleDateString, matching the formatting pattern
used for blog dates. Keep the existing date conversion and rendered Published
field behavior unchanged.

In `@packages/worker/src/app/community-listing-icon.tsx`:
- Around line 53-57: Update the raster icon rendering path in
community-listing-icon so PNG/WebP/JPEG sources are normalized before applying
objectFit: cover, or switch those URLs to objectFit: contain. Keep the SVG path
unchanged, and anchor the fix around the existing image styling block where the
mix/css objectFit settings are applied so non-square raster icons are no longer
cropped.

---

Outside diff comments:
In `@packages/worker/src/app/community-listings-content.tsx`:
- Around line 76-84: Update the trusted badge span in the listing card render
near listing.trusted to establish a positioned stacking context above the
stretched listing link overlay, preserving its tooltip and help cursor while
leaving the overlay behavior unchanged.

---

Nitpick comments:
In `@packages/worker/client/client-router.tsx`:
- Around line 79-104: Clear activeViewTransition after the view transition
settles so it does not retain a stale completed transition. Update the
transition-handling logic around activeViewTransition to await or attach cleanup
to the transition’s finished promise, setting the reference to null when
completion occurs; extend the local transition type with finished if needed
while preserving skipTransition behavior for active transitions.

In `@packages/worker/client/routes/account-billing.tsx`:
- Around line 614-615: Move the module-level button style constants used by
AccountBillingRoute so they are declared with the other top-level constants near
the start of the module instead of after the component. Update the placements of
primaryButtonCss and secondaryButtonCss, keeping their existing getPillButtonCss
and getGhostButtonCss initialization unchanged. This should make the bindings
available before any possible AccountBillingRoute access during module
evaluation, matching the pattern used in account-email.tsx and
account-integrations.tsx.

In `@packages/worker/client/routes/account-integrations.tsx`:
- Around line 527-552: Extract the shared sidebar button style into a helper
near dangerButtonCss, such as getSidebarAppButtonCss(active), preserving the
existing active background, transition, press-scale, hover, and reduced-motion
behavior. Replace both inline css objects in the sidebar button sites around the
connection and app entries with calls to this helper; do not change the optional
aria-current follow-up.

In `@packages/worker/client/routes/community-detail.tsx`:
- Around line 1224-1232: Update readmeProseCss to style h4 and deeper headings
in addition to h3, ensuring headings produced by renderReadme with
headingOffset: 1 retain the intended prose scale instead of browser defaults.

In `@packages/worker/client/routes/login.tsx`:
- Around line 1079-1084: Move the shared inlineLinkCss object from the login
route into `#client/styles/style-primitives.ts`, then import and reuse that
exported style in both the login route and home route. Remove the duplicate
local definitions while preserving all four existing properties and values.

In `@packages/worker/client/routes/onboarding-starter-card.tsx`:
- Around line 242-353: Move the shared starter style objects out of
onboarding-starter-card.tsx into a dedicated onboarding-starter-styles module so
onboarding-diy-card.tsx can import styles without depending on another component
module. Update the exported style symbols starterCardCss, starterGhostButtonCss,
and starterTooltipSurfaceCss to live in that shared module, and remove the
tooltipSurfaceCss alias from onboarding-starter-card.tsx. Keep the existing
style values and imports unchanged apart from the new one-way dependency.

In `@packages/worker/client/site-header.tsx`:
- Around line 308-315: Update the comment above the headerNavMq rule in
navActionsCss to state that the navigation actions are hidden at this width,
while menuToggleCss independently pins the toggle to the right edge with
marginLeft: 'auto'.

In `@packages/worker/src/app/community-detail-content.tsx`:
- Around line 14-20: Extract communityBadgePillCss, communityTagListCss,
communityTagPillCss, and renderCommunityListingName from
community-listings-content.tsx into a dedicated shared module such as
community-shared-content.tsx. Update both community-detail-content.tsx and
community-listings-content.tsx to import these primitives from the new module,
removing the detail frame’s dependency on the listings frame and its
renderToString entry point.

In `@packages/worker/src/app/community-listings-content.tsx`:
- Around line 101-112: Update the rating rendering near listing.averageStars and
the shared formatCommunityStars helper so the card no longer duplicates the
rating-display rule. Extend or reuse formatCommunityStars to provide the shared
derived values (hasRatings, stars, and ratingCount), then compose the card’s
markup from those values while preserving its separately styled star glyph.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3a7b1b48-ab86-4d5a-8e46-70d11eded68d

📥 Commits

Reviewing files that changed from the base of the PR and between 9701196 and 45102aa.

⛔ Files ignored due to path filters (23)
  • packages/worker/public/fonts/bricolage-grotesque-latin-ext.woff2 is excluded by !**/*.woff2
  • packages/worker/public/fonts/bricolage-grotesque-latin.woff2 is excluded by !**/*.woff2
  • packages/worker/public/fonts/wix-madefor-text-italic-latin-ext.woff2 is excluded by !**/*.woff2
  • packages/worker/public/fonts/wix-madefor-text-italic-latin.woff2 is excluded by !**/*.woff2
  • packages/worker/public/fonts/wix-madefor-text-latin-ext.woff2 is excluded by !**/*.woff2
  • packages/worker/public/fonts/wix-madefor-text-latin.woff2 is excluded by !**/*.woff2
  • packages/worker/public/images/icons/bluesky.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/caldotcom.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/claudecode.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/cursor.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/flydotio.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/groupme.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/kit.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/paypal.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/raycast.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/resend.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/sentry.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/spotify.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/stripe.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/twitch.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/x.svg is excluded by !**/*.svg
  • packages/worker/public/images/kody-mark.png is excluded by !**/*.png
  • packages/worker/public/images/kody-pattern.png is excluded by !**/*.png
📒 Files selected for processing (83)
  • e2e/smoke.spec.ts
  • packages/worker/client/app.tsx
  • packages/worker/client/client-router.node.test.ts
  • packages/worker/client/client-router.tsx
  • packages/worker/client/copy-text-button.tsx
  • packages/worker/client/hero-stage.tsx
  • packages/worker/client/markdown-view.node.test.ts
  • packages/worker/client/markdown-view.tsx
  • packages/worker/client/navigation-progress.tsx
  • packages/worker/client/reveal.ts
  • packages/worker/client/routes/account-activity.tsx
  • packages/worker/client/routes/account-billing.tsx
  • packages/worker/client/routes/account-email.tsx
  • packages/worker/client/routes/account-integrations.tsx
  • packages/worker/client/routes/account-jobs.tsx
  • packages/worker/client/routes/account-management-components.tsx
  • packages/worker/client/routes/account-mcp-servers.tsx
  • packages/worker/client/routes/account-memories.tsx
  • packages/worker/client/routes/account-package-invocation-tokens.tsx
  • packages/worker/client/routes/account-packages.tsx
  • packages/worker/client/routes/account-passkeys.tsx
  • packages/worker/client/routes/account-remote-connectors.tsx
  • packages/worker/client/routes/account-secrets.tsx
  • packages/worker/client/routes/account-stars.tsx
  • packages/worker/client/routes/account-two-factor.tsx
  • packages/worker/client/routes/account-values.tsx
  • packages/worker/client/routes/account.tsx
  • packages/worker/client/routes/admin-codemods.tsx
  • packages/worker/client/routes/admin-community-reports.tsx
  • packages/worker/client/routes/admin-feature-flags.tsx
  • packages/worker/client/routes/admin-invites.tsx
  • packages/worker/client/routes/admin-platform-feedback.tsx
  • packages/worker/client/routes/admin-users.tsx
  • packages/worker/client/routes/blog-post.tsx
  • packages/worker/client/routes/blog.tsx
  • packages/worker/client/routes/community-detail.tsx
  • packages/worker/client/routes/community.tsx
  • packages/worker/client/routes/home.tsx
  • packages/worker/client/routes/login.tsx
  • packages/worker/client/routes/onboarding-banner.tsx
  • packages/worker/client/routes/onboarding-diy-card.tsx
  • packages/worker/client/routes/onboarding-mcp-client-tabs.tsx
  • packages/worker/client/routes/onboarding-starter-card.tsx
  • packages/worker/client/routes/onboarding.tsx
  • packages/worker/client/routes/pricing.tsx
  • packages/worker/client/scroll-restoration.tsx
  • packages/worker/client/site-footer.tsx
  • packages/worker/client/site-header.tsx
  • packages/worker/client/styles/style-primitives.ts
  • packages/worker/client/styles/tokens.ts
  • packages/worker/client/theme-toggle.tsx
  • packages/worker/public/images/hero/kody-base.webp
  • packages/worker/public/images/hero/prop-1.webp
  • packages/worker/public/images/hero/prop-2.webp
  • packages/worker/public/images/hero/prop-3.webp
  • packages/worker/public/images/hero/prop-4.webp
  • packages/worker/public/images/hero/prop-5.webp
  • packages/worker/public/images/hero/prop-6.webp
  • packages/worker/public/images/hero/prop-7.webp
  • packages/worker/public/images/hero/prop-8.webp
  • packages/worker/public/images/hero/prop-9.webp
  • packages/worker/public/images/kody-agent-briefing.webp
  • packages/worker/public/images/kody-community-packages.webp
  • packages/worker/public/images/kody-compounding-capabilities.webp
  • packages/worker/public/images/kody-connect-callout.webp
  • packages/worker/public/images/kody-github-triage.webp
  • packages/worker/public/images/kody-greeting.webp
  • packages/worker/public/images/kody-keys.webp
  • packages/worker/public/images/kody-mcp-plug.webp
  • packages/worker/public/images/kody-plan-week.webp
  • packages/worker/public/images/kody-slack-catchup.webp
  • packages/worker/public/styles.css
  • packages/worker/public/theme-init.js
  • packages/worker/src/app/blog-display.ts
  • packages/worker/src/app/community-detail-content.tsx
  • packages/worker/src/app/community-listing-icon.tsx
  • packages/worker/src/app/community-listings-content.tsx
  • packages/worker/src/app/handlers/blog.tsx
  • packages/worker/src/app/loader-data.ts
  • packages/worker/src/app/ssr-document.tsx
  • packages/worker/src/app/ssr-render.node.test.ts
  • packages/worker/src/blog/catalog.node.test.ts
  • packages/worker/src/blog/catalog.ts

Comment thread packages/worker/client/app.tsx
Comment thread packages/worker/client/client-router.tsx
Comment thread packages/worker/client/routes/blog-post.tsx Outdated
Comment thread packages/worker/client/routes/home.tsx
Comment thread packages/worker/client/routes/login.tsx
Comment thread packages/worker/client/styles/style-primitives.ts
Comment thread packages/worker/client/styles/style-primitives.ts
Comment thread packages/worker/client/theme-toggle.tsx
Comment thread packages/worker/src/app/community-detail-content.tsx
Comment thread packages/worker/src/app/community-listing-icon.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/worker/src/app/timeline-display.node.test.ts (1)

93-104: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a test for an offset timestamp.

utcDayKey normalizes through toISOString specifically so that an offset timestamp such as 2026-08-04T01:00:00+02:00 groups under 2026-08-03. No test covers that case. The current boundary test only uses Z timestamps, which a plain iso.slice(0, 10) implementation would also pass.

♻️ Proposed additional test
+test('an offset timestamp groups under its UTC day', () => {
+	const days = groupTimelineItems([
+		makeItem({ createdAt: '2026-08-04T01:00:00+02:00' }),
+	])
+
+	expect(days.map((day) => day.dayKey)).toEqual(['2026-08-03'])
+	expect(days[0]?.dayLabel).toBe('August 3, 2026')
+})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/app/timeline-display.node.test.ts` around lines 93 - 104,
Add a test in timeline-display.node.test.ts around groupTimelineItems/utcDayKey
that uses an offset timestamp like 2026-08-04T01:00:00+02:00 and asserts it
groups into the UTC day key 2026-08-03 with the matching day label. Keep the
existing UTC-midnight boundary test, but extend coverage with the offset case so
the normalization through toISOString is verified instead of a simple
date-prefix slice.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/worker/src/app/timeline-display.ts`:
- Around line 18-24: Update the dayLabel documentation in TimelineDay to
describe it as the formatted visible date text, such as “August 4, 2026,” rather
than the first event’s timestamp; leave dayKey’s UTC key description unchanged.

---

Nitpick comments:
In `@packages/worker/src/app/timeline-display.node.test.ts`:
- Around line 93-104: Add a test in timeline-display.node.test.ts around
groupTimelineItems/utcDayKey that uses an offset timestamp like
2026-08-04T01:00:00+02:00 and asserts it groups into the UTC day key 2026-08-03
with the matching day label. Keep the existing UTC-midnight boundary test, but
extend coverage with the offset case so the normalization through toISOString is
verified instead of a simple date-prefix slice.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bfcea9a9-bfa2-41a8-b08a-9709eaa29e04

📥 Commits

Reviewing files that changed from the base of the PR and between 45102aa and 8f463e6.

📒 Files selected for processing (14)
  • packages/worker/client/app.tsx
  • packages/worker/client/routes/onboarding.tsx
  • packages/worker/client/routes/timeline.tsx
  • packages/worker/client/styles/style-primitives.ts
  • packages/worker/public/images/kody-lantern.webp
  • packages/worker/public/styles.css
  • packages/worker/src/app/community-detail-content.tsx
  • packages/worker/src/app/community-listing-name.tsx
  • packages/worker/src/app/community-listings-content.tsx
  • packages/worker/src/app/timeline-data.ts
  • packages/worker/src/app/timeline-display.node.test.ts
  • packages/worker/src/app/timeline-display.ts
  • packages/worker/src/app/user-avatar.tsx
  • packages/worker/tsconfig-client.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/worker/src/app/community-detail-content.tsx
  • packages/worker/client/app.tsx
  • packages/worker/public/styles.css

Comment thread packages/worker/src/app/timeline-display.ts
Fifteen review threads, verified against current code and fixed:

Correctness
- getListingIdFromPathname/getSlugFromPathname caught decodeURIComponent
  errors. The shell classifies every pathname through these, so `/blog/%`
  took the whole page down instead of rendering a 404.
- swapDom resolves its promise before notifying subscribers. A throwing
  subscriber left the promise pending, freezing the view transition on
  its old snapshot.
- formatCommunityPublishedDate pins locale, format, and timezone. It
  renders on the server and again on hydration, so a runtime-dependent
  format both varied by host and risked a mismatch. The fixed form is
  also the prototype's date voice ("July 13, 2026").
- Inline `code` wraps instead of `white-space: nowrap`, which defeated
  the container's overflow guard for long package names and URLs.
- The pattern glows sit behind their headings (isolate + z-index: -1).
- Pricing lists maxRepos, so "every limit is finite" holds; byte limits
  bound their fraction digits.
- Community icons use `contain`: the icon endpoint serves rasters at
  source dimensions, so `cover` center-cropped non-square logos.

Accessibility
- The select chevron is a themed token. The one baked gray was 2.87:1
  against the light surface, under the 3:1 non-text minimum; each theme
  now uses its own muted-text color (6.3:1 and 7.5:1).
- Login and landing forms keep a mounted live region — a region only
  announces changes made while it is already in the accessibility tree.
  The landing form also moves focus to its confirmation, which replaces
  the submit button that held it.
- Status paragraphs on blog-post and community-detail announce.
- The BYOK note is a `section`, so its aria-labelledby name survives.
- ThemeToggle observes `data-theme`. theme-init.js follows the system
  scheme when nothing is stored, so mounted toggles announced a stale
  state.

Turnstile tokens are single-use, so forms that stay up after a failed
submit now request a fresh one. Client-side validation deliberately does
not: nothing was sent, so the solved token is still good.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
vojtaholik and others added 2 commits August 6, 2026 08:41
main introduced a third self-serve tier (Standard $5, Pro $20) and
replaced the `packageServicePersistentAllowed` boolean with a
`maxPersistentPackageServices` count. The redesigned pricing page only
knew two plans, so the conflict is resolved by keeping the redesign's
grammar and absorbing the new model:

- Three plan panels. The accent stays on the $5 tier the prototype
  accented, which is now Standard; Pro is a plain panel. Accenting both
  paid plans would leave the border meaning nothing.
- The plan grid widens for the extra column and drops to one column at
  860px, since three cards on the prototype's 44rem measure fall under
  the width a price and its copy need.
- The limits table gains a Standard column (group headers now span 4),
  and the header accent follows Standard rather than whichever column is
  last.
- Persistent package services renders zero as "Not included" instead of
  a bare 0, keeping the redesign's phrasing now that the field counts.

The SSR pricing test asserted only Free and Pro, so it would have passed
with the Standard column missing entirely; it now covers all three.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
`dayLabel` is the formatted visible heading text; the comment described
`dayKey`, which is what actually goes in `<time dateTime>`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (2)
packages/worker/client/routes/onboarding-banner.tsx (1)

2-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer getSurfaceCardCss() over spreading and overriding noticeCardCss.

noticeCardCss supplies six properties. Lines 19, 22, and 23 override display, gap, and padding, so only borderRadius, border, and backgroundColor survive. Those three are exactly what getSurfaceCardCss() in #client/styles/style-primitives.ts returns.

This also removes a route-to-route import. onboarding-banner.tsx currently depends on account-management-components.tsx for a style constant, while packages/worker/src/app/community-listings-content.tsx uses the shared primitive for the same card chrome.

♻️ Proposed refactor
-import { getPillButtonCss } from '`#client/styles/style-primitives.ts`'
-import { noticeCardCss } from '`#client/routes/account-management-components.tsx`'
+import {
+	getPillButtonCss,
+	getSurfaceCardCss,
+} from '`#client/styles/style-primitives.ts`'
 import { colors } from '`#client/styles/tokens.ts`'
 import { onboardingPath } from '`#client/routes/onboarding-redirect.ts`'
 			mix={css({
-				...noticeCardCss,
+				...getSurfaceCardCss(),
 				display: 'flex',
 				alignItems: 'center',
 				flexWrap: 'wrap',
 				gap: '1.2rem',
 				padding: '0.9rem 1.2rem',
 			})}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/client/routes/onboarding-banner.tsx` around lines 2 - 24, In
renderOnboardingBanner, replace the noticeCardCss spread and its overridden card
properties with the shared getSurfaceCardCss() primitive from
style-primitives.ts. Remove the account-management-components.tsx import and
preserve the banner’s remaining layout-specific styles.
packages/worker/client/routes/home.tsx (1)

636-657: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consolidate the duplicated motion constant, honeypot style, and easing reference.

Three small duplications appear across this file and packages/worker/client/routes/login.tsx:

  • Line 637 declares motionOk. Line 948 of login.tsx declares the identical constant. Export one from #client/styles/style-primitives.ts.
  • Lines 1147-1149 define honeypotCss. Lines 1257-1263 of login.tsx define a second, different honeypotCss for the same honeypot field. The two implementations already diverge. renderHoneypot in login.tsx and the honeypot input at Lines 564-571 here are otherwise identical markup, so a shared helper would cover both.
  • Lines 1119 and 1131 reference the easing as the raw var(--ease-out). Line 1161 of login.tsx uses the transitions.easeOut token for the same success-in animation. Use the token in both places so a token change cannot leave one site stale.

Line 657 also aliases codeLinkFooterCss to codeLinkCss with no difference. Remove it or let it diverge.

Also applies to: 1112-1149

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/client/routes/home.tsx` around lines 636 - 657, Consolidate
the duplicated styling primitives across home.tsx and login.tsx: export a shared
motionOk constant and honeypot style/helper from style-primitives.ts, then reuse
them in renderHoneypot and the home honeypot input. Replace raw --ease-out
references in the home success-in animation with the transitions.easeOut token.
Remove the redundant codeLinkFooterCss alias or make it independently
meaningful, updating any references accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/worker/client/routes/blog.tsx`:
- Around line 166-172: Update the featured mascot image in the blog route’s img
element to use an empty alt attribute, marking it decorative so the surrounding
link’s accessible name contains only the post content.

In `@packages/worker/client/routes/community-detail.tsx`:
- Around line 644-654: Update the community detail status rendering to keep a
single paragraph with role="status" mounted throughout the view, following the
renderStatusMessage pattern from login.tsx. Have its text change between the
loading message, the load-error message, and no message when neither state
applies, instead of conditionally mounting separate status elements.
- Around line 876-882: Update the stargazer total rendering near
community-stargazers-total to display the count and singular/plural label only
when stargazersStatus indicates a resolved fetch, keeping the loading message
unchanged and suppressing the misleading zero during loading or error states.
- Around line 1057-1074: Add isolation: 'isolate' to the detailArticleCss style
object so its &::before pseudo-element with negative zIndex remains within the
article’s stacking context and renders as the intended backdrop.

In `@packages/worker/client/routes/home.tsx`:
- Around line 1086-1099: Update waitlistInputCss to add a visible per-input
focus treatment on &:focus, such as a background tint or inset ring, while
preserving the connected-pill styling and existing outline removal. Ensure the
shared style is inherited by waitlistEmailInputCss so both waitlist inputs
clearly indicate which field is focused.

In `@packages/worker/client/routes/login.tsx`:
- Around line 1197-1208: Update authOauthCss to enable flex wrapping for the
OAuth button row, and adjust oauthButtonCss so each button uses an 8rem
flex-basis while retaining flexible growth. Ensure additional providers move to
subsequent rows instead of shrinking labels below usable widths.

In `@packages/worker/src/app/community-listings-content.tsx`:
- Around line 89-115: Update the rating markup in the listing stats block so
screen readers receive a descriptive text alternative identifying the average
rating and rating count, while marking the decorative ★ span as hidden from
assistive technology. Preserve the existing visual formatting and displayed
values for sighted users.

---

Nitpick comments:
In `@packages/worker/client/routes/home.tsx`:
- Around line 636-657: Consolidate the duplicated styling primitives across
home.tsx and login.tsx: export a shared motionOk constant and honeypot
style/helper from style-primitives.ts, then reuse them in renderHoneypot and the
home honeypot input. Replace raw --ease-out references in the home success-in
animation with the transitions.easeOut token. Remove the redundant
codeLinkFooterCss alias or make it independently meaningful, updating any
references accordingly.

In `@packages/worker/client/routes/onboarding-banner.tsx`:
- Around line 2-24: In renderOnboardingBanner, replace the noticeCardCss spread
and its overridden card properties with the shared getSurfaceCardCss() primitive
from style-primitives.ts. Remove the account-management-components.tsx import
and preserve the banner’s remaining layout-specific styles.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 71302e9c-ea8d-4aa2-8688-b5bfb679154e

📥 Commits

Reviewing files that changed from the base of the PR and between 7c6eb58 and c9c35f4.

⛔ Files ignored due to path filters (23)
  • packages/worker/public/fonts/bricolage-grotesque-latin-ext.woff2 is excluded by !**/*.woff2
  • packages/worker/public/fonts/bricolage-grotesque-latin.woff2 is excluded by !**/*.woff2
  • packages/worker/public/fonts/wix-madefor-text-italic-latin-ext.woff2 is excluded by !**/*.woff2
  • packages/worker/public/fonts/wix-madefor-text-italic-latin.woff2 is excluded by !**/*.woff2
  • packages/worker/public/fonts/wix-madefor-text-latin-ext.woff2 is excluded by !**/*.woff2
  • packages/worker/public/fonts/wix-madefor-text-latin.woff2 is excluded by !**/*.woff2
  • packages/worker/public/images/icons/bluesky.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/caldotcom.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/claudecode.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/cursor.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/flydotio.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/groupme.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/kit.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/paypal.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/raycast.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/resend.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/sentry.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/spotify.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/stripe.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/twitch.svg is excluded by !**/*.svg
  • packages/worker/public/images/icons/x.svg is excluded by !**/*.svg
  • packages/worker/public/images/kody-mark.png is excluded by !**/*.png
  • packages/worker/public/images/kody-pattern.png is excluded by !**/*.png
📒 Files selected for processing (94)
  • e2e/smoke.spec.ts
  • packages/worker/client/app.tsx
  • packages/worker/client/client-router.node.test.ts
  • packages/worker/client/client-router.tsx
  • packages/worker/client/copy-text-button.tsx
  • packages/worker/client/hero-stage.tsx
  • packages/worker/client/markdown-view.node.test.ts
  • packages/worker/client/markdown-view.tsx
  • packages/worker/client/navigation-progress.tsx
  • packages/worker/client/public-form-protection.ts
  • packages/worker/client/reveal.ts
  • packages/worker/client/routes/account-activity.tsx
  • packages/worker/client/routes/account-billing.tsx
  • packages/worker/client/routes/account-email.tsx
  • packages/worker/client/routes/account-integrations.tsx
  • packages/worker/client/routes/account-jobs.tsx
  • packages/worker/client/routes/account-management-components.tsx
  • packages/worker/client/routes/account-mcp-servers.tsx
  • packages/worker/client/routes/account-memories.tsx
  • packages/worker/client/routes/account-package-invocation-tokens.tsx
  • packages/worker/client/routes/account-packages.tsx
  • packages/worker/client/routes/account-passkeys.tsx
  • packages/worker/client/routes/account-remote-connectors.tsx
  • packages/worker/client/routes/account-secrets.tsx
  • packages/worker/client/routes/account-stars.tsx
  • packages/worker/client/routes/account-two-factor.tsx
  • packages/worker/client/routes/account-values.tsx
  • packages/worker/client/routes/account.tsx
  • packages/worker/client/routes/admin-codemods.tsx
  • packages/worker/client/routes/admin-community-reports.tsx
  • packages/worker/client/routes/admin-feature-flags.tsx
  • packages/worker/client/routes/admin-invites.tsx
  • packages/worker/client/routes/admin-platform-feedback.tsx
  • packages/worker/client/routes/admin-users.tsx
  • packages/worker/client/routes/blog-post.tsx
  • packages/worker/client/routes/blog.tsx
  • packages/worker/client/routes/community-detail.tsx
  • packages/worker/client/routes/community.tsx
  • packages/worker/client/routes/home.tsx
  • packages/worker/client/routes/login.tsx
  • packages/worker/client/routes/onboarding-banner.tsx
  • packages/worker/client/routes/onboarding-diy-card.tsx
  • packages/worker/client/routes/onboarding-mcp-client-tabs.tsx
  • packages/worker/client/routes/onboarding-starter-card.tsx
  • packages/worker/client/routes/onboarding.tsx
  • packages/worker/client/routes/pricing.tsx
  • packages/worker/client/routes/timeline.tsx
  • packages/worker/client/scroll-restoration.tsx
  • packages/worker/client/site-footer.tsx
  • packages/worker/client/site-header.tsx
  • packages/worker/client/styles/style-primitives.ts
  • packages/worker/client/styles/tokens.ts
  • packages/worker/client/theme-toggle.tsx
  • packages/worker/client/waitlist-banner.tsx
  • packages/worker/public/images/hero/kody-base.webp
  • packages/worker/public/images/hero/prop-1.webp
  • packages/worker/public/images/hero/prop-2.webp
  • packages/worker/public/images/hero/prop-3.webp
  • packages/worker/public/images/hero/prop-4.webp
  • packages/worker/public/images/hero/prop-5.webp
  • packages/worker/public/images/hero/prop-6.webp
  • packages/worker/public/images/hero/prop-7.webp
  • packages/worker/public/images/hero/prop-8.webp
  • packages/worker/public/images/hero/prop-9.webp
  • packages/worker/public/images/kody-agent-briefing.webp
  • packages/worker/public/images/kody-community-packages.webp
  • packages/worker/public/images/kody-compounding-capabilities.webp
  • packages/worker/public/images/kody-connect-callout.webp
  • packages/worker/public/images/kody-github-triage.webp
  • packages/worker/public/images/kody-greeting.webp
  • packages/worker/public/images/kody-keys.webp
  • packages/worker/public/images/kody-lantern.webp
  • packages/worker/public/images/kody-mcp-plug.webp
  • packages/worker/public/images/kody-plan-week.webp
  • packages/worker/public/images/kody-slack-catchup.webp
  • packages/worker/public/styles.css
  • packages/worker/public/theme-init.js
  • packages/worker/src/app/blog-display.ts
  • packages/worker/src/app/community-detail-content.tsx
  • packages/worker/src/app/community-display.ts
  • packages/worker/src/app/community-listing-icon.tsx
  • packages/worker/src/app/community-listing-name.tsx
  • packages/worker/src/app/community-listings-content.tsx
  • packages/worker/src/app/handlers/blog.tsx
  • packages/worker/src/app/loader-data.ts
  • packages/worker/src/app/ssr-document.tsx
  • packages/worker/src/app/ssr-render.node.test.ts
  • packages/worker/src/app/timeline-data.ts
  • packages/worker/src/app/timeline-display.node.test.ts
  • packages/worker/src/app/timeline-display.ts
  • packages/worker/src/app/user-avatar.tsx
  • packages/worker/src/blog/catalog.node.test.ts
  • packages/worker/src/blog/catalog.ts
  • packages/worker/tsconfig-client.json
🚧 Files skipped from review as they are similar to previous changes (66)
  • packages/worker/src/app/ssr-document.tsx
  • packages/worker/src/blog/catalog.node.test.ts
  • packages/worker/client/routes/account-stars.tsx
  • packages/worker/public/theme-init.js
  • packages/worker/src/app/timeline-display.node.test.ts
  • e2e/smoke.spec.ts
  • packages/worker/src/app/timeline-data.ts
  • packages/worker/client/routes/admin-platform-feedback.tsx
  • packages/worker/client/markdown-view.node.test.ts
  • packages/worker/tsconfig-client.json
  • packages/worker/client/public-form-protection.ts
  • packages/worker/client/routes/account-values.tsx
  • packages/worker/src/app/timeline-display.ts
  • packages/worker/client/styles/tokens.ts
  • packages/worker/src/app/blog-display.ts
  • packages/worker/client/routes/admin-community-reports.tsx
  • packages/worker/client/routes/account-packages.tsx
  • packages/worker/client/routes/community.tsx
  • packages/worker/client/waitlist-banner.tsx
  • packages/worker/client/routes/admin-invites.tsx
  • packages/worker/client/site-header.tsx
  • packages/worker/client/routes/account-passkeys.tsx
  • packages/worker/src/app/community-listing-name.tsx
  • packages/worker/client/routes/admin-codemods.tsx
  • packages/worker/client/routes/admin-feature-flags.tsx
  • packages/worker/client/client-router.tsx
  • packages/worker/src/app/loader-data.ts
  • packages/worker/client/routes/account-email.tsx
  • packages/worker/src/app/user-avatar.tsx
  • packages/worker/src/app/community-display.ts
  • packages/worker/src/blog/catalog.ts
  • packages/worker/client/reveal.ts
  • packages/worker/client/site-footer.tsx
  • packages/worker/client/routes/account-two-factor.tsx
  • packages/worker/src/app/handlers/blog.tsx
  • packages/worker/client/scroll-restoration.tsx
  • packages/worker/src/app/community-detail-content.tsx
  • packages/worker/src/app/ssr-render.node.test.ts
  • packages/worker/client/routes/admin-users.tsx
  • packages/worker/client/hero-stage.tsx
  • packages/worker/client/routes/blog-post.tsx
  • packages/worker/client/copy-text-button.tsx
  • packages/worker/client/routes/account.tsx
  • packages/worker/client/routes/account-remote-connectors.tsx
  • packages/worker/client/routes/account-secrets.tsx
  • packages/worker/client/routes/account-activity.tsx
  • packages/worker/client/routes/account-memories.tsx
  • packages/worker/client/routes/account-package-invocation-tokens.tsx
  • packages/worker/client/app.tsx
  • packages/worker/client/routes/account-mcp-servers.tsx
  • packages/worker/client/theme-toggle.tsx
  • packages/worker/client/routes/onboarding-diy-card.tsx
  • packages/worker/client/markdown-view.tsx
  • packages/worker/src/app/community-listing-icon.tsx
  • packages/worker/client/routes/timeline.tsx
  • packages/worker/client/routes/account-billing.tsx
  • packages/worker/client/styles/style-primitives.ts
  • packages/worker/client/routes/account-integrations.tsx
  • packages/worker/client/navigation-progress.tsx
  • packages/worker/client/routes/onboarding.tsx
  • packages/worker/client/client-router.node.test.ts
  • packages/worker/client/routes/pricing.tsx
  • packages/worker/client/routes/onboarding-starter-card.tsx
  • packages/worker/client/routes/onboarding-mcp-client-tabs.tsx
  • packages/worker/client/routes/account-management-components.tsx
  • packages/worker/client/routes/account-jobs.tsx

Comment thread packages/worker/client/routes/blog.tsx
Comment thread packages/worker/client/routes/community-detail.tsx Outdated
Comment thread packages/worker/client/routes/community-detail.tsx Outdated
Comment thread packages/worker/client/routes/community-detail.tsx
Comment thread packages/worker/client/routes/home.tsx
Comment thread packages/worker/client/routes/login.tsx
Comment thread packages/worker/src/app/community-listings-content.tsx
The Satori-rendered share cards were never updated for the redesign: every
shared link showed a blue-and-slate card set in Inter, the pre-redesign
theme. `palette.ts` even carried the warning to keep itself in sync with
`public/styles.css`, and we changed the palette across ten surfaces
without doing so.

Design system
- Palette syncs to the redesign tokens, converted from `oklch()` because
  Satori cannot parse it.
- Inter is replaced by the app's own faces. Both are variable fonts and
  Satori ignores variation axes, so they are instanced to static weights
  (Bricolage 700/opsz 96, Wix Madefor 400) — otherwise Satori silently
  renders the default instance, ExtraBold at 96pt optical size.
- `textReading` is a deliberate departure from the app tokens: a card is
  read at a third of its size in a feed, where `textMuted` turns to mush.
  11.1:1 on the dark ground against 7.4:1, and 8.6:1 on the pale one.

The default card
- Kody and his lantern, from the pre-composed `kody-lantern.webp` — the
  landing page keeps those props as nine parallax layers, but a static
  card has nothing to parallax, and one asset beats stitching ten.
- The shirt pattern fans in from the right. The app composes it live from
  a gradient masked by `--kody-pattern`; Satori supports neither masks nor
  CSS variables, so the mask, tint, and radial falloff are baked in. The
  tint is per-theme, which is why one shared asset would not do.
- No inner panel. A crawler already presents the image inside its own
  rounded container, so a second panel read as a card inside a card.
- The header is absolutely positioned so the title and description centre
  on the whole canvas rather than on a box that starts below it. That also
  decouples the art's offset from the logo size.

Both themes
- `?theme=light` renders the pale variant across all four card families;
  anything unrecognised falls back to dark rather than erroring, since
  crawlers own these URLs.
- The lantern halo and the filled-star amber both needed per-theme values:
  the warm glow read as a smudge on the pale ground, and the amber was
  2.6:1 there, under the 3:1 minimum for a non-text graphic.

Copy
- The home description no longer restates its own title.
- `truncateOgText` breaks on a word boundary, so an excerpt trails off
  instead of severing a word ("no m…").

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134SBHSA9QGtS4E3uTiaCdf
@kody-bot

Copy link
Copy Markdown
Collaborator

Hi @vojtaholik — this repository now requires a signed inbound Contributor License Agreement for outside contributions (you keep copyright; it is a license grant so Kody can stay a single-licensor Fair Source tree).

Please read https://github.com/kentcdodds/kody/blob/main/docs/legal/individual-cla.md and reply on this thread with exactly:

I have read the CLA and I hereby sign the CLA

That covers your past and future contributions from this GitHub account. Details: https://github.com/kentcdodds/kody/blob/main/docs/contributing/inbound-contributions.md

@vojtaholik

Copy link
Copy Markdown
Collaborator Author

I have read the CLA and I hereby sign the CLA

kentcdodds added a commit that referenced this pull request Aug 16, 2026
* Record vojtaholik as an individual CLA signer

Vojta commented the exact signing phrase on #1233. The workflow does
not write signers from comments; a maintainer records the login on main.

Co-authored-by: me <me@kentcdodds.com>

* Record individual CLA signatures from the signing comment

The exact PR comment now writes the commenter onto main and re-runs
the check. Tests cover that workflow with fixtures and no longer
assert the live allowlist or signer roster.

Co-authored-by: me <me@kentcdodds.com>

* Use glanceable emoji on the CLA workflow jobs

Match the Validate/Preview check names so CLA and Record CLA scan
the same way in the GitHub checks list.

Co-authored-by: me <me@kentcdodds.com>

* Harden CLA recording after review

Wait for an in-flight CLA check before re-running it, keep job outputs
to key=value lines, and stop interpolating the signer login into the
commit shell. Serializer and CLI flags are stricter; tests cover the
compact allowlist and blank-login ignore path.

Co-authored-by: me <me@kentcdodds.com>

* Keep the CLA comment filter oxfmt-safe

Use a shorter contains() prefilter so the workflow stays one line. The
tool still requires the exact signing phrase.

Co-authored-by: me <me@kentcdodds.com>

* Hoist CLA allowlist serializer helper

Exchange oxlint rejects nested helpers that capture nothing. Keep the
compact-array formatter at module scope.

Co-authored-by: me <me@kentcdodds.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants