Repository navigation
Port the heykody.dev redesign (all 9 surfaces) + motion polish - #1233
Conversation
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
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe 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. ChangesSite redesign
Community and blog server data
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
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
|
🔎 Preview deployed: https://kody-pr-1233.kody-a99.workers.dev Worker: 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
There was a problem hiding this comment.
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 winThe stretched card link covers the Trusted badge.
listingLinkCssadds an::afterpseudo-element withposition: absolute; inset: 0, andlistingCardCsssetsposition: 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
titletooltip never appears, so the only explanation of "Trusted" becomes unreachable. The badgecursor: helpis 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 valueConsider moving the shared starter styles into a dedicated style module.
onboarding-starter-card.tsxnow exportsstarterCardCss,starterGhostButtonCss, andstarterTooltipSurfaceCss, andonboarding-diy-card.tsximports them. This makes one component module the style source for another component module. A smallonboarding-starter-styles.tsmodule would keep the dependency direction one-way and remove thetooltipSurfaceCssalias 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 winStyle README headings below h3.
renderReadmeappliesheadingOffset: 1, so an authored###section becomes anh4.readmeProseCssstyles onlyh3, andproseCssstyles onlyh2. Anh4therefore falls back to the user-agent default, which is smaller than the surrounding body text. Add a rule forh4and 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
inlineLinkCssduplicates the definition inhome.tsx.
packages/worker/client/routes/home.tsxlines 617-622 declares the same four properties. Move this object into#client/styles/style-primitives.tsand 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 winMove the shared community primitives out of the listings frame module.
community-detail-content.tsxnow importscommunityBadgePillCss,communityTagListCss,communityTagPillCss, andrenderCommunityListingNamefromcommunity-listings-content.tsx. That pulls the whole listings frame component and itsrenderToStringentry 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 winThe rating display rule is now implemented twice.
packages/worker/src/app/community-display.tsexportsformatCommunityStars, andcommunity-detail-content.tsxstill 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
formatCommunityStarsreturn 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 winThe 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: noneatheaderNavMq, so the actions are removed at that width.menuToggleCsspins the toggle with its ownmarginLeft: '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 winExtract the duplicated sidebar button style.
The two inline
css({...})objects are identical except for thebackgroundColorexpression. Both now carry the same transition, press scale,hoverMqhover, 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
dangerButtonCssat 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.AccountManagementListItemButtonreceives an explicitactiveprop for the connection rows below. Consider addingaria-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 valueClear
activeViewTransitionwhen the transition settles.
activeViewTransitionkeeps 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
finishedadded 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 winMove these constants above
AccountBillingRoute.
primaryButtonCssandsecondaryButtonCssare 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
AccountBillingRouteduring module evaluation would read the bindings inside their temporal dead zone and throw.account-email.tsxandaccount-integrations.tsxdeclare 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
⛔ Files ignored due to path filters (23)
packages/worker/public/fonts/bricolage-grotesque-latin-ext.woff2is excluded by!**/*.woff2packages/worker/public/fonts/bricolage-grotesque-latin.woff2is excluded by!**/*.woff2packages/worker/public/fonts/wix-madefor-text-italic-latin-ext.woff2is excluded by!**/*.woff2packages/worker/public/fonts/wix-madefor-text-italic-latin.woff2is excluded by!**/*.woff2packages/worker/public/fonts/wix-madefor-text-latin-ext.woff2is excluded by!**/*.woff2packages/worker/public/fonts/wix-madefor-text-latin.woff2is excluded by!**/*.woff2packages/worker/public/images/icons/bluesky.svgis excluded by!**/*.svgpackages/worker/public/images/icons/caldotcom.svgis excluded by!**/*.svgpackages/worker/public/images/icons/claudecode.svgis excluded by!**/*.svgpackages/worker/public/images/icons/cursor.svgis excluded by!**/*.svgpackages/worker/public/images/icons/flydotio.svgis excluded by!**/*.svgpackages/worker/public/images/icons/groupme.svgis excluded by!**/*.svgpackages/worker/public/images/icons/kit.svgis excluded by!**/*.svgpackages/worker/public/images/icons/paypal.svgis excluded by!**/*.svgpackages/worker/public/images/icons/raycast.svgis excluded by!**/*.svgpackages/worker/public/images/icons/resend.svgis excluded by!**/*.svgpackages/worker/public/images/icons/sentry.svgis excluded by!**/*.svgpackages/worker/public/images/icons/spotify.svgis excluded by!**/*.svgpackages/worker/public/images/icons/stripe.svgis excluded by!**/*.svgpackages/worker/public/images/icons/twitch.svgis excluded by!**/*.svgpackages/worker/public/images/icons/x.svgis excluded by!**/*.svgpackages/worker/public/images/kody-mark.pngis excluded by!**/*.pngpackages/worker/public/images/kody-pattern.pngis excluded by!**/*.png
📒 Files selected for processing (83)
e2e/smoke.spec.tspackages/worker/client/app.tsxpackages/worker/client/client-router.node.test.tspackages/worker/client/client-router.tsxpackages/worker/client/copy-text-button.tsxpackages/worker/client/hero-stage.tsxpackages/worker/client/markdown-view.node.test.tspackages/worker/client/markdown-view.tsxpackages/worker/client/navigation-progress.tsxpackages/worker/client/reveal.tspackages/worker/client/routes/account-activity.tsxpackages/worker/client/routes/account-billing.tsxpackages/worker/client/routes/account-email.tsxpackages/worker/client/routes/account-integrations.tsxpackages/worker/client/routes/account-jobs.tsxpackages/worker/client/routes/account-management-components.tsxpackages/worker/client/routes/account-mcp-servers.tsxpackages/worker/client/routes/account-memories.tsxpackages/worker/client/routes/account-package-invocation-tokens.tsxpackages/worker/client/routes/account-packages.tsxpackages/worker/client/routes/account-passkeys.tsxpackages/worker/client/routes/account-remote-connectors.tsxpackages/worker/client/routes/account-secrets.tsxpackages/worker/client/routes/account-stars.tsxpackages/worker/client/routes/account-two-factor.tsxpackages/worker/client/routes/account-values.tsxpackages/worker/client/routes/account.tsxpackages/worker/client/routes/admin-codemods.tsxpackages/worker/client/routes/admin-community-reports.tsxpackages/worker/client/routes/admin-feature-flags.tsxpackages/worker/client/routes/admin-invites.tsxpackages/worker/client/routes/admin-platform-feedback.tsxpackages/worker/client/routes/admin-users.tsxpackages/worker/client/routes/blog-post.tsxpackages/worker/client/routes/blog.tsxpackages/worker/client/routes/community-detail.tsxpackages/worker/client/routes/community.tsxpackages/worker/client/routes/home.tsxpackages/worker/client/routes/login.tsxpackages/worker/client/routes/onboarding-banner.tsxpackages/worker/client/routes/onboarding-diy-card.tsxpackages/worker/client/routes/onboarding-mcp-client-tabs.tsxpackages/worker/client/routes/onboarding-starter-card.tsxpackages/worker/client/routes/onboarding.tsxpackages/worker/client/routes/pricing.tsxpackages/worker/client/scroll-restoration.tsxpackages/worker/client/site-footer.tsxpackages/worker/client/site-header.tsxpackages/worker/client/styles/style-primitives.tspackages/worker/client/styles/tokens.tspackages/worker/client/theme-toggle.tsxpackages/worker/public/images/hero/kody-base.webppackages/worker/public/images/hero/prop-1.webppackages/worker/public/images/hero/prop-2.webppackages/worker/public/images/hero/prop-3.webppackages/worker/public/images/hero/prop-4.webppackages/worker/public/images/hero/prop-5.webppackages/worker/public/images/hero/prop-6.webppackages/worker/public/images/hero/prop-7.webppackages/worker/public/images/hero/prop-8.webppackages/worker/public/images/hero/prop-9.webppackages/worker/public/images/kody-agent-briefing.webppackages/worker/public/images/kody-community-packages.webppackages/worker/public/images/kody-compounding-capabilities.webppackages/worker/public/images/kody-connect-callout.webppackages/worker/public/images/kody-github-triage.webppackages/worker/public/images/kody-greeting.webppackages/worker/public/images/kody-keys.webppackages/worker/public/images/kody-mcp-plug.webppackages/worker/public/images/kody-plan-week.webppackages/worker/public/images/kody-slack-catchup.webppackages/worker/public/styles.csspackages/worker/public/theme-init.jspackages/worker/src/app/blog-display.tspackages/worker/src/app/community-detail-content.tsxpackages/worker/src/app/community-listing-icon.tsxpackages/worker/src/app/community-listings-content.tsxpackages/worker/src/app/handlers/blog.tsxpackages/worker/src/app/loader-data.tspackages/worker/src/app/ssr-document.tsxpackages/worker/src/app/ssr-render.node.test.tspackages/worker/src/blog/catalog.node.test.tspackages/worker/src/blog/catalog.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/worker/src/app/timeline-display.node.test.ts (1)
93-104: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a test for an offset timestamp.
utcDayKeynormalizes throughtoISOStringspecifically so that an offset timestamp such as2026-08-04T01:00:00+02:00groups under2026-08-03. No test covers that case. The current boundary test only usesZtimestamps, which a plainiso.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
📒 Files selected for processing (14)
packages/worker/client/app.tsxpackages/worker/client/routes/onboarding.tsxpackages/worker/client/routes/timeline.tsxpackages/worker/client/styles/style-primitives.tspackages/worker/public/images/kody-lantern.webppackages/worker/public/styles.csspackages/worker/src/app/community-detail-content.tsxpackages/worker/src/app/community-listing-name.tsxpackages/worker/src/app/community-listings-content.tsxpackages/worker/src/app/timeline-data.tspackages/worker/src/app/timeline-display.node.test.tspackages/worker/src/app/timeline-display.tspackages/worker/src/app/user-avatar.tsxpackages/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
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
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
|
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. |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (2)
packages/worker/client/routes/onboarding-banner.tsx (1)
2-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winPrefer
getSurfaceCardCss()over spreading and overridingnoticeCardCss.
noticeCardCsssupplies six properties. Lines 19, 22, and 23 overridedisplay,gap, andpadding, so onlyborderRadius,border, andbackgroundColorsurvive. Those three are exactly whatgetSurfaceCardCss()in#client/styles/style-primitives.tsreturns.This also removes a route-to-route import.
onboarding-banner.tsxcurrently depends onaccount-management-components.tsxfor a style constant, whilepackages/worker/src/app/community-listings-content.tsxuses 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 winConsolidate 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 oflogin.tsxdeclares the identical constant. Export one from#client/styles/style-primitives.ts.- Lines 1147-1149 define
honeypotCss. Lines 1257-1263 oflogin.tsxdefine a second, differenthoneypotCssfor the same honeypot field. The two implementations already diverge.renderHoneypotinlogin.tsxand 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 oflogin.tsxuses thetransitions.easeOuttoken for the samesuccess-inanimation. Use the token in both places so a token change cannot leave one site stale.Line 657 also aliases
codeLinkFooterCsstocodeLinkCsswith 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
⛔ Files ignored due to path filters (23)
packages/worker/public/fonts/bricolage-grotesque-latin-ext.woff2is excluded by!**/*.woff2packages/worker/public/fonts/bricolage-grotesque-latin.woff2is excluded by!**/*.woff2packages/worker/public/fonts/wix-madefor-text-italic-latin-ext.woff2is excluded by!**/*.woff2packages/worker/public/fonts/wix-madefor-text-italic-latin.woff2is excluded by!**/*.woff2packages/worker/public/fonts/wix-madefor-text-latin-ext.woff2is excluded by!**/*.woff2packages/worker/public/fonts/wix-madefor-text-latin.woff2is excluded by!**/*.woff2packages/worker/public/images/icons/bluesky.svgis excluded by!**/*.svgpackages/worker/public/images/icons/caldotcom.svgis excluded by!**/*.svgpackages/worker/public/images/icons/claudecode.svgis excluded by!**/*.svgpackages/worker/public/images/icons/cursor.svgis excluded by!**/*.svgpackages/worker/public/images/icons/flydotio.svgis excluded by!**/*.svgpackages/worker/public/images/icons/groupme.svgis excluded by!**/*.svgpackages/worker/public/images/icons/kit.svgis excluded by!**/*.svgpackages/worker/public/images/icons/paypal.svgis excluded by!**/*.svgpackages/worker/public/images/icons/raycast.svgis excluded by!**/*.svgpackages/worker/public/images/icons/resend.svgis excluded by!**/*.svgpackages/worker/public/images/icons/sentry.svgis excluded by!**/*.svgpackages/worker/public/images/icons/spotify.svgis excluded by!**/*.svgpackages/worker/public/images/icons/stripe.svgis excluded by!**/*.svgpackages/worker/public/images/icons/twitch.svgis excluded by!**/*.svgpackages/worker/public/images/icons/x.svgis excluded by!**/*.svgpackages/worker/public/images/kody-mark.pngis excluded by!**/*.pngpackages/worker/public/images/kody-pattern.pngis excluded by!**/*.png
📒 Files selected for processing (94)
e2e/smoke.spec.tspackages/worker/client/app.tsxpackages/worker/client/client-router.node.test.tspackages/worker/client/client-router.tsxpackages/worker/client/copy-text-button.tsxpackages/worker/client/hero-stage.tsxpackages/worker/client/markdown-view.node.test.tspackages/worker/client/markdown-view.tsxpackages/worker/client/navigation-progress.tsxpackages/worker/client/public-form-protection.tspackages/worker/client/reveal.tspackages/worker/client/routes/account-activity.tsxpackages/worker/client/routes/account-billing.tsxpackages/worker/client/routes/account-email.tsxpackages/worker/client/routes/account-integrations.tsxpackages/worker/client/routes/account-jobs.tsxpackages/worker/client/routes/account-management-components.tsxpackages/worker/client/routes/account-mcp-servers.tsxpackages/worker/client/routes/account-memories.tsxpackages/worker/client/routes/account-package-invocation-tokens.tsxpackages/worker/client/routes/account-packages.tsxpackages/worker/client/routes/account-passkeys.tsxpackages/worker/client/routes/account-remote-connectors.tsxpackages/worker/client/routes/account-secrets.tsxpackages/worker/client/routes/account-stars.tsxpackages/worker/client/routes/account-two-factor.tsxpackages/worker/client/routes/account-values.tsxpackages/worker/client/routes/account.tsxpackages/worker/client/routes/admin-codemods.tsxpackages/worker/client/routes/admin-community-reports.tsxpackages/worker/client/routes/admin-feature-flags.tsxpackages/worker/client/routes/admin-invites.tsxpackages/worker/client/routes/admin-platform-feedback.tsxpackages/worker/client/routes/admin-users.tsxpackages/worker/client/routes/blog-post.tsxpackages/worker/client/routes/blog.tsxpackages/worker/client/routes/community-detail.tsxpackages/worker/client/routes/community.tsxpackages/worker/client/routes/home.tsxpackages/worker/client/routes/login.tsxpackages/worker/client/routes/onboarding-banner.tsxpackages/worker/client/routes/onboarding-diy-card.tsxpackages/worker/client/routes/onboarding-mcp-client-tabs.tsxpackages/worker/client/routes/onboarding-starter-card.tsxpackages/worker/client/routes/onboarding.tsxpackages/worker/client/routes/pricing.tsxpackages/worker/client/routes/timeline.tsxpackages/worker/client/scroll-restoration.tsxpackages/worker/client/site-footer.tsxpackages/worker/client/site-header.tsxpackages/worker/client/styles/style-primitives.tspackages/worker/client/styles/tokens.tspackages/worker/client/theme-toggle.tsxpackages/worker/client/waitlist-banner.tsxpackages/worker/public/images/hero/kody-base.webppackages/worker/public/images/hero/prop-1.webppackages/worker/public/images/hero/prop-2.webppackages/worker/public/images/hero/prop-3.webppackages/worker/public/images/hero/prop-4.webppackages/worker/public/images/hero/prop-5.webppackages/worker/public/images/hero/prop-6.webppackages/worker/public/images/hero/prop-7.webppackages/worker/public/images/hero/prop-8.webppackages/worker/public/images/hero/prop-9.webppackages/worker/public/images/kody-agent-briefing.webppackages/worker/public/images/kody-community-packages.webppackages/worker/public/images/kody-compounding-capabilities.webppackages/worker/public/images/kody-connect-callout.webppackages/worker/public/images/kody-github-triage.webppackages/worker/public/images/kody-greeting.webppackages/worker/public/images/kody-keys.webppackages/worker/public/images/kody-lantern.webppackages/worker/public/images/kody-mcp-plug.webppackages/worker/public/images/kody-plan-week.webppackages/worker/public/images/kody-slack-catchup.webppackages/worker/public/styles.csspackages/worker/public/theme-init.jspackages/worker/src/app/blog-display.tspackages/worker/src/app/community-detail-content.tsxpackages/worker/src/app/community-display.tspackages/worker/src/app/community-listing-icon.tsxpackages/worker/src/app/community-listing-name.tsxpackages/worker/src/app/community-listings-content.tsxpackages/worker/src/app/handlers/blog.tsxpackages/worker/src/app/loader-data.tspackages/worker/src/app/ssr-document.tsxpackages/worker/src/app/ssr-render.node.test.tspackages/worker/src/app/timeline-data.tspackages/worker/src/app/timeline-display.node.test.tspackages/worker/src/app/timeline-display.tspackages/worker/src/app/user-avatar.tsxpackages/worker/src/blog/catalog.node.test.tspackages/worker/src/blog/catalog.tspackages/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
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
|
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:
That covers your past and future contributions from this GitHub account. Details: https://github.com/kentcdodds/kody/blob/main/docs/contributing/inbound-contributions.md |
|
I have read the CLA and I hereby sign the CLA |
* 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>
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
--color-primary= the green, flat grey canvas, paired--*-darkvalues; thedata-thememechanism is unchanged)style-src/font-src 'self'CSPcubic-bezier(0.22, 1, 0.36, 1)),data-risepage-open choreography, scroll/card reveals, everything enhance-only (html.js) and off underprefers-reduced-motionSurfaces: 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
##→ h2) instead of the README demotion; README/community rendering unchanged and test-pinnedformatBlogPostDateuses 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 URLaria-currentnav state, focus-ring layering fixes, greenaccent-colorfor radios/checkboxesVerification
npm run typecheckclean;npm run test:node475 files / 1581 tests green on top of latest mainKnown follow-ups
maxReposexists 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:
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-styleentrances: onboarding client-tab panel and BYOK details enter via interruptible transitions instead of keyframes; account settings and community report disclosures no longer teleport open.success-inat 200ms (was 400ms fromscale(0.5)); tab pills and wizard step buttons compress on press; hover art lifts aligned to house durations.Summary by CodeRabbit
New Features
Bug Fixes