Skip to content

feat(marketing): 3-card options comparator replaces table#21

Merged
Codehagen merged 5 commits intomainfrom
feat/comparator-revamp
Apr 20, 2026
Merged

feat(marketing): 3-card options comparator replaces table#21
Codehagen merged 5 commits intomainfrom
feat/comparator-revamp

Conversation

@Codehagen
Copy link
Copy Markdown
Owner

@Codehagen Codehagen commented Apr 20, 2026

Summary

  • Replace the tabular Tailark comparator-7 with a 3-card options block that matches the page's card language
  • Each card: option name → headline metric (2-3 days / 1 day / 3 min) → paragraph → 3 signal bullets → cost footer
  • Helpbase card is emphasized (shadow + "Recommended" badge + all-positive signals)

Why

The old table was the only tabular element on a page of cards. Eye snagged on it during scroll. The new layout reads naturally adjacent to the pricing section and keeps the exact same 3-way comparison message (roll your own / hosted SaaS / helpbase).

Test plan

  • Tests 155/155 passing
  • Typecheck clean
  • Verified on localhost:3000 — cards align, emphasized Helpbase card stands out, copy reads clean
  • Vercel preview QA
  • Mobile (stacks to 1-col on md:)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Style

    • Redesigned the comparison interface from a table to a 3‑card layout with check/X signals and a “Recommended” badge.
    • Simplified hero styling by removing the notched/rounded top and border accents for a cleaner header.
    • Updated an illustration to use a centered text glyph and slightly darker dark‑mode background.
    • Refined buttons for snappier press/hover interactions.
  • New Features

    • Source preview now shows a “Source” header plus a separate “Rendered” section with a highlighted callout and icons.

The old Tailark comparator-7 rendered a 3-column feature table with
tooltip-gated descriptions. It was the only table on a page of
cards \u2014 the visual language mismatched the rest of the narrative
scroll (hero \u2192 bento cards \u2192 how-it-works \u2192 feature cards \u2192 pricing
cards \u2192 FAQ). Reader's eye hit the tabular row and snagged.

Rewritten as a 3-col OptionCard grid. Each card:
  - option name (small label)
  - headline metric (tabular-nums large number)
  - time-to-site subtitle
  - short paragraph explaining the option
  - 3 signal bullets (Check/X icon in rounded pill, emerald for
    positive, muted for negative)
  - cost footer with border-t separator

Helpbase card is emphasized:
  - heavier shadow, opaque bg-card (the other two are bg-card/40)
  - 'Recommended' badge top-right
  - all positive signals

No tooltips required \u2014 the signal text is short enough to read inline,
and more detail is available in the other sections below.

Behavior preserved: same 3-way comparison (roll your own / hosted SaaS
/ helpbase), same 'to first site' metric, same cost ladder. Just
rendered as cards that sit naturally next to the pricing section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
helpbase Ready Ready Preview, Comment Apr 20, 2026 11:56am

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e7cad743-802e-4f8c-9881-a5b258c583b9

📥 Commits

Reviewing files that changed from the base of the PR and between b06556f and fffeeaf.

📒 Files selected for processing (20)
  • apps/web/public/r/help-center.json
  • apps/web/public/r/registry.json
  • packages/create-helpbase/templates/components/ui/button.tsx
  • packages/create-helpbase/templates/components/ui/card.tsx
  • packages/create-helpbase/templates/components/ui/chart.tsx
  • packages/create-helpbase/templates/components/ui/infinite-slider.tsx
  • packages/create-helpbase/templates/components/ui/input.tsx
  • packages/create-helpbase/templates/components/ui/label.tsx
  • packages/create-helpbase/templates/components/ui/text-scramble.tsx
  • packages/create-helpbase/templates/components/ui/tooltip.tsx
  • packages/create-helpbase/templates/package.json
  • registry.json
  • registry/helpbase/components/ui/card.tsx
  • registry/helpbase/components/ui/chart.tsx
  • registry/helpbase/components/ui/infinite-slider.tsx
  • registry/helpbase/components/ui/input.tsx
  • registry/helpbase/components/ui/label.tsx
  • registry/helpbase/components/ui/text-scramble.tsx
  • registry/helpbase/components/ui/tooltip.tsx
  • scripts/sync-templates.mjs

📝 Walkthrough

Walkthrough

Replaced the comparator’s feature-by-plan table with a new options-driven 3-card layout; updated hero/container and several illustration/preview components; adjusted button variant interactions; removed multiple UI primitives from templates/registry and added button primitive plus @radix-ui/react-slot dependency.

Changes

Cohort / File(s) Summary
Comparator Layout Refactor
apps/web/components/comparator-7.tsx
Removed plans/features table + tooltip logic; introduced typed Option model, OptionCard component, and new rendering that maps options → cards; swapped markers to lucide-react Check/X.
Hero & Illustrations
apps/web/components/marketing/hero.tsx, apps/web/components/illustrations/flow.tsx, apps/web/components/illustrations/mdx-source-preview.tsx
Hero container lost notched/rounded top and border classes; flow illustration replaced LogoIcon SVG with text glyph and increased dark bg opacity; MDX preview restructured into Source header + Rendered section, added FileText/Lightbulb icons and updated copy/styling.
Button Styling and Template Button Add
apps/web/components/ui/button.tsx, packages/create-helpbase/templates/components/ui/button.tsx
Refined buttonVariants transitions (explicit properties, duration, active scale, motion-reduce) and per-variant shadow/hover behaviors; added a new template Button + exported buttonVariants in scaffolding templates.
Registry & Template Dependencies
apps/web/public/r/help-center.json, apps/web/public/r/registry.json, registry.json, packages/create-helpbase/templates/package.json, scripts/sync-templates.mjs
Added @radix-ui/react-slot dependency and added button to registryDependencies; updated sync script to inline Badge and Button to templates and exclude multiple primitives from hosted tier.
Removed Template UI Primitives
packages/create-helpbase/templates/components/ui/card.tsx, .../chart.tsx, .../infinite-slider.tsx, .../input.tsx, .../label.tsx, .../text-scramble.tsx, .../tooltip.tsx
Deleted several client UI primitives from template package: Card, Chart, InfiniteSlider, Input, Label, TextScramble, Tooltip (exports and types removed).
Removed Registry UI Primitives
registry/helpbase/components/ui/card.tsx, .../chart.tsx, .../infinite-slider.tsx, .../input.tsx, .../label.tsx, .../text-scramble.tsx, .../tooltip.tsx
Removed same set of primitives from registry files (exports/types deleted), aligning registry with template exclusions.
Footer Registry Change
apps/web/public/r/help-center.json (module contents)
Replaced named Footer() with default FooterSection() + export { FooterSection as Footer }; footer now builds from a links constant and uses Button (asChild) with conditional external-link routing logic.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

"I hopped from rows to cards with glee,
Check and X dance for all to see.
The hero trimmed its fancy crown,
Templates leaner, icons sprout round—
A rabbit cheers the tidy spree." 🐇✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: replacing a tabular comparator with a 3-card layout for marketing purposes.
Description check ✅ Passed The description includes a clear summary, rationale, and test plan with most boxes checked. However, it lacks the required 'Type of change' section and missing verification of some testing steps.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/comparator-revamp

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 and usage tips.

The hero's content wrapper carried 'corner-t-notch rounded-t-[2rem]
border-x border-t' \u2014 a Tailark hero-section/six poster frame at
max-w-6xl that wrapped the headline + sub + CTAs + terminal.

Three reasons it had to go:

  1. The frame's bottom edge floated orphan in the viewport when you
     scrolled past it. The frame ended at the hero's bottom with
     nothing visually continuing it below \u2014 a horizontal line that
     pointed at empty space.

  2. The page already has section frames where they pay rent
     (how-it-works grid, demo cross-link card, faqs sidebar+accordion).
     Each of those frames groups a content cluster. The hero frame
     wrapped one large content block but didn't group anything that
     wasn't already visually unified by typography and the terminal.

  3. The 6xl frame width didn't align with anything below \u2014 every
     other framed section sits at 5xl. Two different widths, two
     different visual languages on one page.

Mintlify, Stripe, and Anthropic don't frame their heroes. The hero
is the hero because of the headline, the terminal, and the install
command \u2014 not because of a border.

Three classes removed (corner-t-notch, rounded-t-[2rem], border-x,
border-t) plus the corner-t-notch decoration. Hero typography and
content untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/web/components/comparator-7.tsx (1)

157-166: Pin the cost footer to the bottom of each card.

The card is already flex flex-col; using mt-auto keeps cost footers aligned when body copy wraps differently.

📐 Proposed refinement
-            <div className="border-border/60 mt-6 flex items-baseline gap-1 border-t pt-4">
+            <div className="border-border/60 mt-auto flex items-baseline gap-1 border-t pt-4">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/components/comparator-7.tsx` around lines 157 - 166, The cost/footer
div containing option.cost should be pinned to the bottom of each flex-column
card by adding the utility that pushes it to the end of the column; update the
div with className "border-border/60 mt-6 flex items-baseline gap-1 border-t
pt-4" (the footer that renders {option.cost} and {option.costNote}) to include
"mt-auto" (e.g., "mt-auto mt-6 ...") so the cost footer aligns across cards when
body content wraps.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/components/comparator-7.tsx`:
- Around line 126-151: The signal icons are currently decorative only; inside
the option.signals.map rendering add accessible state text and mark the SVG
icons as decorative: set the Check and X components to aria-hidden="true" and
add a visually-hidden span (e.g., className "sr-only") next to each icon that
outputs the semantic state based on signal.positive (for example "Positive" vs
"Tradeoff"/"Negative") so screen readers receive the meaning while visual users
keep the same UI; update the spans wrapping the icons and the icon components
accordingly.
- Around line 95-98: Replace the invalid Tailwind opacity token
"shadow-black/6.5" inside the emphasized class string (the ternary using
option.emphasized) with a valid Tailwind opacity—either a nearest standard step
like "shadow-black/5" or an arbitrary value using bracket notation such as
"shadow-black/[0.065]"; update the class array element in the comparator-7
component where option.emphasized controls the string so the resulting class
list uses a valid Tailwind opacity token.

---

Nitpick comments:
In `@apps/web/components/comparator-7.tsx`:
- Around line 157-166: The cost/footer div containing option.cost should be
pinned to the bottom of each flex-column card by adding the utility that pushes
it to the end of the column; update the div with className "border-border/60
mt-6 flex items-baseline gap-1 border-t pt-4" (the footer that renders
{option.cost} and {option.costNote}) to include "mt-auto" (e.g., "mt-auto mt-6
...") so the cost footer aligns across cards when body content wraps.
🪄 Autofix (Beta)

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

Run ID: 27063bdf-d240-43c3-b5fb-201088344ad0

📥 Commits

Reviewing files that changed from the base of the PR and between fb004ed and b123010.

📒 Files selected for processing (2)
  • apps/web/components/comparator-7.tsx
  • apps/web/components/marketing/hero.tsx

Comment on lines +95 to +98
"ring-border relative flex flex-col rounded-2xl border border-transparent p-6 ring-1",
option.emphasized
? "bg-card shadow-black/6.5 z-10 shadow-xl"
: "bg-card/40",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find and read tailwind config and package.json to understand Tailwind version and opacity settings
find . -type f \( -name "tailwind.config.*" -o -name "package.json" \) -not -path "*/node_modules/*" | head -20

Repository: Codehagen/Helpbase

Length of output: 384


🏁 Script executed:

# Check the specific file mentioned in the review
cat -n apps/web/components/comparator-7.tsx | sed -n '90,105p'

Repository: Codehagen/Helpbase

Length of output: 808


🏁 Script executed:

# Search for other instances of shadow opacity syntax in the codebase
rg "shadow-.*/([\d\.]+)" --no-heading -A 1 -B 1 | head -40

Repository: Codehagen/Helpbase

Length of output: 15361


🏁 Script executed:

# Check Tailwind configuration for custom opacity tokens
find . -type f -name "tailwind.config.*" -not -path "*/node_modules/*" | head -5

Repository: Codehagen/Helpbase

Length of output: 44


🏁 Script executed:

# Read the main tailwind config
cat tailwind.config.ts 2>/dev/null || cat tailwind.config.js 2>/dev/null || cat tailwind.config.mjs 2>/dev/null || echo "No tailwind config found at root"

Repository: Codehagen/Helpbase

Length of output: 94


🏁 Script executed:

# Check package.json for Tailwind version
grep -A 2 "tailwindcss" ./package.json

Repository: Codehagen/Helpbase

Length of output: 157


🏁 Script executed:

# Check if opacity 6.5 is used elsewhere in the codebase
rg "/(6\.5|0\.065)" --no-heading -B 2 -A 2

Repository: Codehagen/Helpbase

Length of output: 14166


🏁 Script executed:

# Search more carefully for Tailwind config files (might be in nested packages)
find . -type f \( -name "tailwind.config.*" -o -name "tailwind.css" \) -not -path "*/node_modules/*" -not -path "*/.next/*" 2>/dev/null

Repository: Codehagen/Helpbase

Length of output: 44


🏁 Script executed:

# Check package.json files for tailwind config references or versions
grep -r "tailwindcss" */package.json --include="package.json" | grep -v node_modules | head -20

Repository: Codehagen/Helpbase

Length of output: 109


🏁 Script executed:

# Look for CSS files that might define custom opacity or theme extensions
find . -type f -name "*.css" -not -path "*/node_modules/*" | xargs grep -l "opacity\|theme\|6\.5" 2>/dev/null | head -10

Repository: Codehagen/Helpbase

Length of output: 202


🏁 Script executed:

# Search more broadly for tailwind configuration in the entire repository
find . -type f \( -name "*.ts" -o -name "*.js" -o -name "*.mjs" \) -not -path "*/node_modules/*" -not -path "*/.next/*" | xargs grep -l "tailwind.*config\|theme.*opacity" 2>/dev/null | head -10

Repository: Codehagen/Helpbase

Length of output: 44


🏁 Script executed:

# Check one of the CSS files to understand the theme setup
cat ./packages/ui/src/styles/globals.css

Repository: Codehagen/Helpbase

Length of output: 12037


🏁 Script executed:

# Search for any custom theme or opacity configuration in TS/JS files
rg "opacity.*[6\.5|0\.065]|@layer|theme\s*:" -A 5 -B 2 --type ts --type js | head -60

Repository: Codehagen/Helpbase

Length of output: 4902


🏁 Script executed:

# Check if there's any custom opacity configuration in the CSS variables or extended theme
rg "opacity|--opacity" packages/ui/src/styles/globals.css apps/web/styles/ 2>/dev/null || echo "No opacity in theme"

Repository: Codehagen/Helpbase

Length of output: 795


🏁 Script executed:

# Check Tailwind documentation to understand the version being used
grep -r "tailwindcss\|@tailwindcss" package.json apps/web/package.json 2>/dev/null | head -5

Repository: Codehagen/Helpbase

Length of output: 296


🏁 Script executed:

# Check for postcss config
find . -type f \( -name "postcss.config.*" -o -name ".postcssrc*" \) -not -path "*/node_modules/*"

Repository: Codehagen/Helpbase

Length of output: 180


🏁 Script executed:

# Check the apps/web package.json for any theme or tailwind-specific config
cat apps/web/package.json | grep -A 50 "tailwind\|theme" || head -100 apps/web/package.json

Repository: Codehagen/Helpbase

Length of output: 1133


🏁 Script executed:

# Search for any extend theme or opacity configuration in the app
rg "extend.*theme|opacity.*scale" apps/web --type ts --type js | head -20

Repository: Codehagen/Helpbase

Length of output: 316


🏁 Script executed:

# Check the postcss config
cat apps/web/postcss.config.mjs

Repository: Codehagen/Helpbase

Length of output: 117


🏁 Script executed:

# Search for any CSS custom properties or theme extensions related to opacity
rg "6\.5|0\.065" apps/web/ packages/ui/src/styles/ -B 3 -A 3 --type css --type ts | head -100

Repository: Codehagen/Helpbase

Length of output: 8015


🏁 Script executed:

# Check if Tailwind v4 docs mention how /6.5 is handled
# Let's test by looking at what the actual build might generate
find apps/web -type f -name "*.tsx" -o -name "*.css" | xargs grep -l "shadow-black/6.5" | wc -l

Repository: Codehagen/Helpbase

Length of output: 64


🏁 Script executed:

# Check the workspace UI postcss config to see if there's any custom opacity definition
cat packages/ui/postcss.config.mjs

Repository: Codehagen/Helpbase

Length of output: 202


🏁 Script executed:

# Verify the actual Tailwind v4 syntax by checking their documentation patterns
# Let's also count how many build-time warnings might be generated
rg "shadow-" apps/web/components/*.tsx | grep -c "shadow-black"

Repository: Codehagen/Helpbase

Length of output: 63


🏁 Script executed:

# Check the `@theme` block in globals.css for any opacity configuration
cat packages/ui/src/styles/globals.css | grep -A 100 "@theme inline" | grep -i opacity

Repository: Codehagen/Helpbase

Length of output: 44


🏁 Script executed:

# Check if there's any Tailwind config that might extend opacity values in Tailwind v4
# Also look for any extend or custom theme configuration
find . -type f \( -name "*.ts" -o -name "*.js" -o -name "*.css" \) -not -path "*/node_modules/*" | xargs grep -l "opacity.*6\.5\|extend.*opacity" 2>/dev/null | head -10

Repository: Codehagen/Helpbase

Length of output: 44


🏁 Script executed:

# Let's verify what the standard Tailwind v4 opacity scale is by checking if 6.5 converts to decimal correctly
# 6.5 would be 6.5% opacity = 0.065 in decimal (or as a ratio 6.5/100)
python3 << 'EOF'
# Standard Tailwind opacity scale: 5, 10, 15, ... 95
# In percentages and decimal equivalents
standard_scale = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
print("Standard Tailwind opacity scale:")
for val in standard_scale:
    print(f"  /{val} = {val/100}")

print("\nFor 6.5:")
print(f"  /6.5 would be {6.5/100} (not in standard scale)")
print(f"  /[0.065] would be 0.065 (6.5%)")
EOF

Repository: Codehagen/Helpbase

Length of output: 420


Use valid Tailwind opacity syntax for the emphasized shadow.

shadow-black/6.5 is not a standard Tailwind opacity value. Tailwind's opacity scale includes 5, 10, 15... 95 (increments of 5). Arbitrary opacity values must use bracket notation.

🎨 Proposed fix
-                    ? "bg-card shadow-black/6.5 z-10 shadow-xl"
+                    ? "bg-card z-10 shadow-xl shadow-black/[0.065]"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"ring-border relative flex flex-col rounded-2xl border border-transparent p-6 ring-1",
option.emphasized
? "bg-card shadow-black/6.5 z-10 shadow-xl"
: "bg-card/40",
"ring-border relative flex flex-col rounded-2xl border border-transparent p-6 ring-1",
option.emphasized
? "bg-card z-10 shadow-xl shadow-black/[0.065]"
: "bg-card/40",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/components/comparator-7.tsx` around lines 95 - 98, Replace the
invalid Tailwind opacity token "shadow-black/6.5" inside the emphasized class
string (the ternary using option.emphasized) with a valid Tailwind
opacity—either a nearest standard step like "shadow-black/5" or an arbitrary
value using bracket notation such as "shadow-black/[0.065]"; update the class
array element in the comparator-7 component where option.emphasized controls the
string so the resulting class list uses a valid Tailwind opacity token.

Comment on lines +126 to +151
{option.signals.map((signal, i) => (
<li
key={i}
className="flex items-start gap-2">
{signal.positive ? (
<span className="bg-emerald-500/15 text-emerald-600 dark:text-emerald-400 mt-px flex size-4 shrink-0 items-center justify-center rounded-full">
<Check
className="size-2.5"
strokeWidth={3}
/>
</span>
) : (
<span className="bg-foreground/10 text-muted-foreground mt-px flex size-4 shrink-0 items-center justify-center rounded-full">
<X
className="size-2.5"
strokeWidth={3}
/>
</span>
)}
<span
className={cn(
signal.positive
? "text-foreground"
: "text-muted-foreground",
)}>
{signal.text}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Expose the check/X meaning to assistive tech.

The positive/tradeoff state is currently visual-only. Add hidden text for the state and mark decorative icons as hidden.

♿ Proposed fix
                         {signal.positive ? (
                             <span className="bg-emerald-500/15 text-emerald-600 dark:text-emerald-400 mt-px flex size-4 shrink-0 items-center justify-center rounded-full">
                                 <Check
+                                    aria-hidden="true"
                                     className="size-2.5"
                                     strokeWidth={3}
                                 />
                             </span>
                         ) : (
                             <span className="bg-foreground/10 text-muted-foreground mt-px flex size-4 shrink-0 items-center justify-center rounded-full">
                                 <X
+                                    aria-hidden="true"
                                     className="size-2.5"
                                     strokeWidth={3}
                                 />
                             </span>
                         )}
                         <span
                             className={cn(
                                 signal.positive
                                     ? "text-foreground"
                                     : "text-muted-foreground",
                             )}>
+                            <span className="sr-only">
+                                {signal.positive ? "Advantage: " : "Tradeoff: "}
+                            </span>
                             {signal.text}
                         </span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/components/comparator-7.tsx` around lines 126 - 151, The signal
icons are currently decorative only; inside the option.signals.map rendering add
accessible state text and mark the SVG icons as decorative: set the Check and X
components to aria-hidden="true" and add a visually-hidden span (e.g., className
"sr-only") next to each icon that outputs the semantic state based on
signal.positive (for example "Positive" vs "Tradeoff"/"Negative") so screen
readers receive the meaning while visual users keep the same UI; update the
spans wrapping the icons and the icon components accordingly.

…review to source+rendered

Two improvements in the 'Every file is yours' row.

FlowIllustration hub:
  The center node was the Tailark logomark (LogoIcon \u2014 a purple/teal
  gradient geometric shape that ships with their illustration kit).
  That's their brand bleeding through ours. Replaced with a clean white
  'h' letterform on the dark circle, matching the helpbase wordmark in
  the header. Bumped the circle bg from black/75 to black/85 so the
  letterform reads cleanly in light mode. Removed the LogoIcon import.

MdxSourcePreview:
  Was source-only \u2014 a single panel of fake .mdx code. The card's copy
  promises 'Import React components, version control every change, diff
  in PR review' but the visual didn't show the moment that matters most:
  MDX source rendering as actual docs.

  Rebuilt as a stacked card:
    - Header tab: filename + 'SOURCE' label
    - Source panel: syntax-highlighted MDX (violet frontmatter keys,
      amber numbers, emerald strings, sky-blue JSX tags) \u2014 a real-feeling
      code block, not flat mono text
    - Divider
    - Rendered panel: 'RENDERED' label, then the h1 styled as a real
      heading, body text, and the <Callout type="tip"> shown as an
      actual amber-tinted callout box with a lucide Lightbulb icon

  This makes the abstract claim concrete: MDX is code AND it's docs.
  The visual literally shows the transformation the platform performs.

Both files are in components/illustrations/ which is in
HOSTED_TIER_EXCLUDES \u2014 no template drift.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The marketing page button (used by header CTAs, hero 'See live demo',
pricing tier CTAs, and demo cross-link CTAs) had only transition-colors
\u2014 hover worked but clicks had zero visual feedback. The shared
packages/ui button had active:translate-y-px so CopyButton already
felt right, but everything else didn't.

Applied Emil Kowalski's micro-interaction blueprint from animations.dev:

  - Transition widened from colors-only to
    transition-[color,background-color,transform,box-shadow]
    so transform and shadow can animate together.
  - duration-150 ease-out \u2014 micro-interaction range (100\u2013150ms),
    ease-out for the element entering its pressed state.
  - active:scale-[0.98] \u2014 2% squeeze on press. Buttons are h-9/h-10,
    3% would read as cartoonish; 2% feels like a tap, not a gimmick.
  - active:shadow-sm (default, destructive) / active:shadow-xs (outline)
    \u2014 shadow reduces on press, mimicking a physical button being
    depressed. Subtle but readable.
  - motion-reduce:transition-none motion-reduce:active:scale-100
    \u2014 respects prefers-reduced-motion, disables animation for users
    who've opted out.
  - Removed the stray duration-200 override on outline (now inherits
    the base duration-150 for consistency across variants).

Tailwind v4's hover: modifier already guards against mobile tap-flicker
via @media (hover: hover), so no extra work needed there.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/components/illustrations/flow.tsx`:
- Around line 186-190: The "h" glyph span uses class text-background which can
render too dark against the dark-mode badge (dark:bg-illustration/75); update
the span's dark-mode foreground to ensure legibility by adding a dark-specific
text class (for example dark:text-foreground or dark:text-white) to the span
containing the "h" so it forces a light color in dark mode while leaving
light-mode styling unchanged.

In `@apps/web/components/illustrations/mdx-source-preview.tsx`:
- Line 23: Visible heading text uses lowercase brand casing "Install helpbase";
update the UI copy to use proper product casing "Install Helpbase" where the
span with className "text-foreground" renders that heading in the
mdx-source-preview component (also update the other occurrences of the same
literal in this file). Replace only the displayed text (not package/CLI
literals) so the component's visible headings read "Install Helpbase".
🪄 Autofix (Beta)

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

Run ID: c636d5be-2199-4dd6-9fd3-e772f5493f02

📥 Commits

Reviewing files that changed from the base of the PR and between b123010 and b06556f.

📒 Files selected for processing (3)
  • apps/web/components/illustrations/flow.tsx
  • apps/web/components/illustrations/mdx-source-preview.tsx
  • apps/web/components/ui/button.tsx

Comment on lines +186 to 190
<div className="dark:bg-illustration/75 dark:ring-border-illustration relative flex size-14 items-center justify-center rounded-full bg-black/85 shadow-xl shadow-black/20 ring-1 ring-black backdrop-blur">
<span className="text-background text-lg font-semibold leading-none tracking-tight">
h
</span>
</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Verify dark-mode contrast of the "h" glyph.

The badge background switches to dark:bg-illustration/75 in dark mode while the glyph keeps text-background. Since --background is typically dark in dark themes and --illustration also tends to be a dark/neutral surface, the "h" may render dark-on-dark and become barely visible. In light mode it's fine (white h on bg-black/85). Consider forcing a light foreground in dark mode (e.g. dark:text-foreground or a fixed dark:text-white) so the wordmark stays legible on both themes.

The whole illustration is aria-hidden, so this is purely visual, not an a11y blocker.

🎨 Suggested tweak
-                    <span className="text-background text-lg font-semibold leading-none tracking-tight">
+                    <span className="text-background dark:text-foreground text-lg font-semibold leading-none tracking-tight">
                         h
                     </span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/components/illustrations/flow.tsx` around lines 186 - 190, The "h"
glyph span uses class text-background which can render too dark against the
dark-mode badge (dark:bg-illustration/75); update the span's dark-mode
foreground to ensure legibility by adding a dark-specific text class (for
example dark:text-foreground or dark:text-white) to the span containing the "h"
so it forces a light color in dark mode while leaving light-mode styling
unchanged.

<span className="text-muted-foreground">title:</span>{" "}
<span className="text-foreground">Getting started</span>
<span className="text-violet-600 dark:text-violet-400">title:</span>{" "}
<span className="text-foreground">Install helpbase</span>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use the product casing in visible heading copy.

Install helpbase reads like a brand-casing typo in title/heading contexts. Consider Install Helpbase here while keeping any literal package/CLI names lowercase if needed.

✏️ Proposed copy adjustment
-        <span className="text-foreground">Install helpbase</span>
+        <span className="text-foreground">Install Helpbase</span>
...
-        <span className="text-foreground"># Install helpbase</span>
+        <span className="text-foreground"># Install Helpbase</span>
...
-        Install helpbase
+        Install Helpbase

Also applies to: 32-32, 56-56

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/components/illustrations/mdx-source-preview.tsx` at line 23, Visible
heading text uses lowercase brand casing "Install helpbase"; update the UI copy
to use proper product casing "Install Helpbase" where the span with className
"text-foreground" renders that heading in the mdx-source-preview component (also
update the other occurrences of the same literal in this file). Replace only the
displayed text (not package/CLI literals) so the component's visible headings
read "Install Helpbase".

PR #20 added components/footer.tsx with an import of @/components/ui/button,
but apps/web's button.tsx is in HOSTED_TIER_EXCLUDES because it carries
marketing-only press feedback styling. The synced footer landed in the
scaffold templates and registry without a Button to resolve, breaking
both smoke:install and smoke:registry on Turbopack with
'Module not found: @/components/ui/button'. CI has been red on main
since fb004ed; this fix restores green.

Three coordinated changes:

1. inlineShadcnPrimitivesToTemplates now inlines BOTH Badge and Button
   from packages/ui/src/components/ into templates/components/ui/.
   Button uses the umbrella radix-ui import (Slot.Root pattern), works
   cleanly with @workspace import rewrites.

2. registry.json adds 'button' to registryDependencies and
   '@radix-ui/react-slot' to dependencies, so consumers running
   'shadcn add helpbase' get Button auto-installed from the official
   shadcn registry and the slot primitive resolves for any other
   shadcn primitive that needs it.

3. Templates package.json now ships @radix-ui/react-slot directly. The
   umbrella radix-ui package re-exports it under Slot.Root with a
   different API, so primitives that import { Slot } from
   '@radix-ui/react-slot' need the individual package.

Plus: deleted 7 dead UI primitives from templates AND registry that
were copied from apps/web by the default sync rule. None of them
were used by anything in the scaffold path:

  - card.tsx, chart.tsx, infinite-slider.tsx, input.tsx, label.tsx,
    text-scramble.tsx, tooltip.tsx

Their only consumers in apps/web were components in HOSTED_TIER_EXCLUDES
(pricing, bento, chart-illustration). Shipping them as dead code dragged
in recharts, motion/react, and other marketing-only deps the scaffold
doesn't need. Added all 7 to HOSTED_TIER_EXCLUDES so future syncs don't
recreate them. Scaffold consumers can shadcn-add card / tooltip / etc.
on demand.

Locally verified:
  - pnpm smoke:install passes (templates path)
  - pnpm smoke:registry passes (shadcn add path)
  - pnpm registry:build regenerates public/r/*.json clean

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Codehagen Codehagen merged commit 5426c1e into main Apr 20, 2026
3 of 5 checks passed
@Codehagen Codehagen deleted the feat/comparator-revamp branch April 20, 2026 11:55
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.

1 participant