Skip to content

feat(marketing): redesign hero section with Linear-style stacked layout#1452

Merged
Kitenite merged 12 commits intomainfrom
kitenite/hero-cleanup
Feb 16, 2026
Merged

feat(marketing): redesign hero section with Linear-style stacked layout#1452
Kitenite merged 12 commits intomainfrom
kitenite/hero-cleanup

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Feb 13, 2026

Summary

  • Restructure the marketing hero from a cramped 2-column grid to a clean, stacked vertical layout inspired by Linear's homepage
  • Add scroll-driven animations: mockup scales down from full-size, gradient fade overlays dissolve, and selector pills shift down as you scroll
  • Polish the app mockup with better readability (larger fonts, wider sidebars) and a refined container style

Changes

HeroSection.tsx

  • 2-column grid → stacked vertical flex-col with centered text and full-width demo below
  • Bigger headline (text-4xl to text-7xl), font-medium, tracking-tight
  • Centered subtitle with max-w-xl mx-auto
  • Scroll tracking via useScroll passed down to ProductDemo

ProductDemo.tsx

  • Removed mesh gradient backgrounds entirely
  • Moved selector pills above the mockup, centered
  • Scroll-driven scale animation (1 → 0.82) with gradient fade overlays that dissolve
  • Selector pills translate Y without scaling to follow the mockup
  • Added diffuse white back-shadow behind the mockup

AppMockup.tsx

  • rounded-xlrounded-2xl, darker bg (bg-black/60), thicker border (border-2 border-white/[0.12])
  • Bumped all font sizes for readability (text-[9px]text-[11px], text-[10px]text-xs)
  • Wider sidebars (left 180→210px, right 200→230px)
  • Larger icons and window chrome dots

SelectorPill.tsx

  • Added rounded-full for pill shape
  • Subtler inactive state colors

Test Plan

  • Run bun dev in apps/marketing and visually verify hero section
  • Check responsive behavior at mobile, tablet, and desktop breakpoints
  • Verify all 4 demo states still animate correctly (Use Any Agents, Create Parallel Branches, See Changes, Open in Any IDE)
  • Verify scroll-driven scale + fade animation works smoothly

Summary by CodeRabbit

  • New Features

    • Implemented scroll-driven animations for enhanced visual engagement and interaction feedback.
  • Style

    • Refined typography scaling, spacing, and color schemes throughout the interface for better readability.
    • Updated visual styling with improved borders, gradients, and icon sizing for enhanced aesthetics.
    • Enhanced mobile-responsive design with optimized logo sizing and layout adjustments across all screen sizes.

Note

Low Risk
Primarily marketing UI/layout and animation tweaks; main risk is visual/regression across breakpoints and scroll performance, with no data/auth impact.

Overview
Redesigns the marketing HeroSection from a two-column layout into a centered, stacked hero with updated headline/copy and regrouped CTAs.

Adds scroll-driven motion to the hero demo by tracking scrollYProgress in HeroSection and using it in ProductDemo to scale the mockup and shift selector pills (mobile-aware), while removing the prior mesh-gradient background layer.

Polishes the AppMockup and controls with refined glass/shadow styling, larger typography/icon sizing, widened sidebars, and updated TrustedBySection spacing/visibility for small screens.

Written by Cursor Bugbot for commit da04af9. This will update automatically on new commits. Configure here.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 13, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Refactored the HeroSection component to use a centered, mobile-first layout with scroll-driven animations. The ProductDemo component now accepts a scrollYProgress prop and renders scroll-triggered transformations. Updated AppMockup typography and layout dimensions. Adjusted TrustedBySection responsive behavior. Minor styling refinements to SelectorPill.

Changes

Cohort / File(s) Summary
Hero Section Core
apps/marketing/src/app/components/HeroSection/HeroSection.tsx, apps/marketing/src/app/components/HeroSection/components/ProductDemo/ProductDemo.tsx
Restructured hero layout from two-column to centered vertical stack; added scroll tracking via useScroll and demoRef; ProductDemo now accepts scrollYProgress prop for scroll-driven animations instead of dynamic gradient rendering.
Product Demo Styling
apps/marketing/src/app/components/HeroSection/components/ProductDemo/components/SelectorPill/SelectorPill.tsx
Added rounded-full shape to pill; updated inactive state background opacity and border styling for lighter visual appearance.
App Mockup UI
apps/marketing/src/app/components/HeroSection/components/AppMockup/AppMockup.tsx
Scaled typography from smaller to larger sizes across all components (StatusIndicator, FileChangeItem, terminal content); increased container widths (min-w 600→700, left sidebar 180→210px, right panel 200→230/380px); updated modal overlays with glass border gradients; adjusted spacing, gaps, and icon sizing throughout.
Trusted By Section
apps/marketing/src/app/components/TrustedBySection/TrustedBySection.tsx
Made H2 heading responsive (hidden on mobile, visible on small screens+); reduced logo item height on mobile (h-14→h-10) with responsive scale-up; adjusted logo image scaling and text label sizing (1.3rem→1rem default, responsive increase on small screens).

Sequence Diagram(s)

sequenceDiagram
    participant User as User<br/>(Scrolling)
    participant HS as HeroSection
    participant PS as useScroll<br/>(Hook)
    participant PD as ProductDemo
    participant AM as AppMockup

    User->>HS: Scroll on page
    HS->>PS: useScroll(demoRef)
    PS->>PS: Calculate scrollYProgress
    PS->>PD: Pass scrollYProgress
    PD->>PD: useTransform:<br/>scale & pillsY
    PD->>AM: Render with<br/>animated container
    AM->>User: Display scaled mockup<br/>+ repositioned pills
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hops of joy! The hero section springs anew,
Scroll-driven dreams in motion, fresh and true,
AppMockup grows with scale and pristine style,
Pills dance and shimmer as users scroll a mile!

🚥 Pre-merge checks | ✅ 3 | ❌ 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 (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately describes the main change: redesigning the hero section with a Linear-style stacked layout.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering summary, specific file changes, and a detailed test plan that aligns with the template sections.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch kitenite/hero-cleanup

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.

Copy link
Copy Markdown
Contributor

@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

🤖 Fix all issues with AI agents
In
`@apps/marketing/src/app/components/HeroSection/components/AppMockup/AppMockup.tsx`:
- Around line 730-732: The LuGitPullRequest icon inside the AppMockup component
uses an invalid Tailwind class "size-4.5"; replace it with a valid class such as
"size-4" or "size-5" on the LuGitPullRequest element to ensure the icon is
properly sized (adjust to "size-4" for 1rem or "size-5" for 1.25rem depending on
the desired visual).

In `@apps/marketing/src/app/components/HeroSection/HeroSection.tsx`:
- Around line 59-67: Replace the GitHub <button> in the HeroSection component
with a semantic <a> element that points to COMPANY.GITHUB_URL (use
target="_blank" and rel="noopener noreferrer"), keep the same className,
aria-label="View on GitHub", visible text "View on GitHub" and the <FaGithub>
icon so styling and accessibility remain identical but native link behaviors
(middle-click, context menu, crawlers) are preserved.
🧹 Nitpick comments (2)
apps/marketing/src/app/components/HeroSection/components/ProductDemo/ProductDemo.tsx (1)

17-22: Consider extracting animation constants.

The scroll-animation tuning values (0.82, 80, 0.6) are inline magic numbers. Extracting them to named constants at module top improves readability and makes future tweaks easier to find.

♻️ Suggested extraction
+const SCROLL_SCALE_END = 0.82;
+const PILLS_Y_OFFSET = 80;
+const OVERLAY_FADE_END = 0.6;
+
 export function ProductDemo({ scrollYProgress }: ProductDemoProps) {
   ...
-  const scale = useTransform(scrollYProgress, [0, 1], [1, 0.82]);
-  const pillsY = useTransform(scrollYProgress, [0, 1], [0, 80]);
-  const overlayOpacity = useTransform(scrollYProgress, [0, 0.6], [1, 0]);
+  const scale = useTransform(scrollYProgress, [0, 1], [1, SCROLL_SCALE_END]);
+  const pillsY = useTransform(scrollYProgress, [0, 1], [0, PILLS_Y_OFFSET]);
+  const overlayOpacity = useTransform(scrollYProgress, [0, OVERLAY_FADE_END], [1, 0]);

As per coding guidelines, "Extract hardcoded magic numbers, strings, and enums to named constants at module top instead of leaving them inline in logic".

apps/marketing/src/app/components/HeroSection/components/AppMockup/AppMockup.tsx (1)

408-495: Consider extracting repeated agent tab markup.

The four agent tab motion.div blocks (Claude, Codex, Gemini, Cursor) share identical animation config and structure, differing only in src, alt, label text, and delay. A data-driven approach would reduce ~90 lines of duplication.

This is pre-existing duplication and not introduced by this PR, so feel free to defer.

♻️ Sketch of a data-driven approach
const AGENT_TABS = [
  { src: "/app-icons/codex.svg", alt: "Codex", label: "codex", delay: 0.1 },
  { src: "/app-icons/gemini.svg", alt: "Gemini", label: "gemini", delay: 0.25 },
  { src: "/app-icons/cursor-agent.svg", alt: "Cursor", label: "cursor", delay: 0.4 },
];

{AGENT_TABS.map((tab) => (
  <motion.div
    key={tab.label}
    className="flex items-center gap-1.5 py-1 text-xs text-muted-foreground/60 hover:bg-white/5 rounded-t overflow-hidden"
    initial={{ opacity: 0, width: 0, paddingLeft: 0, paddingRight: 0 }}
    animate={{
      opacity: activeDemo === "Use Any Agents" ? 1 : 0,
      width: activeDemo === "Use Any Agents" ? "auto" : 0,
      paddingLeft: activeDemo === "Use Any Agents" ? 12 : 0,
      paddingRight: activeDemo === "Use Any Agents" ? 12 : 0,
    }}
    transition={{
      duration: 0.25,
      ease: "easeOut",
      delay: activeDemo === "Use Any Agents" ? tab.delay : 0,
    }}
  >
    <Image src={tab.src} alt={tab.alt} width={14} height={14} />
    <span>{tab.label}</span>
    <LuX className="size-3.5 text-muted-foreground/30" />
  </motion.div>
))}

Comment on lines +730 to +732
<div className="flex items-center justify-between px-3 py-2.5 border-b border-white/[0.06]">
<div className="flex items-center gap-2">
<LuGitPullRequest className="size-4 text-emerald-400/80" />
<LuGitPullRequest className="size-4.5 text-emerald-400/80" />
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Search for size-4.5 usage across the codebase
rg -n 'size-4\.5' --type=ts --type=tsx -g '!node_modules'

Repository: superset-sh/superset

Length of output: 91


🏁 Script executed:

# Find and inspect Tailwind config files
find . -name 'tailwind.config.*' -o -name 'tailwind.config.ts' | head -5 | xargs -I {} bash -c 'echo "=== {} ===" && head -100 {}'

Repository: superset-sh/superset

Length of output: 1003


🏁 Script executed:

# Search for size-4.5 without file type restrictions
rg 'size-4\.5' -g '!node_modules'

Repository: superset-sh/superset

Length of output: 214


🏁 Script executed:

# Find tailwind config in apps/marketing
find ./apps/marketing -name 'tailwind.config.*' | xargs -I {} bash -c 'echo "=== {} ===" && cat {}'

Repository: superset-sh/superset

Length of output: 46


🏁 Script executed:

# Also check the root tailwind config
cat ./tailwind.config.ts 2>/dev/null || cat ./tailwind.config.js 2>/dev/null || echo "No root tailwind config found"

Repository: superset-sh/superset

Length of output: 93


🏁 Script executed:

# Search for all tailwind-related config files
find . -type f \( -name '*tailwind*' -o -name '*postcss*' \) | grep -v node_modules | head -20

Repository: superset-sh/superset

Length of output: 228


🏁 Script executed:

# Check if tailwind extends spacing in package.json or other config references
rg 'extend.*spacing|spacing.*4\.5' --type json --type ts

Repository: superset-sh/superset

Length of output: 46


🏁 Script executed:

# Check what Tailwind utilities are actually available by looking at size classes used
rg 'size-[0-9]' -o | sort | uniq

Repository: superset-sh/superset

Length of output: 29694


Use size-4 or size-5 instead of the invalid size-4.5 Tailwind class.

The size-4.5 utility does not exist in standard Tailwind and no configuration extends the spacing scale to include half-values like 4.5. This class is silently ignored, leaving the LuGitPullRequest icon unsized. Change to size-4 (1rem) or size-5 (1.25rem) depending on the intended visual size.

🤖 Prompt for AI Agents
In
`@apps/marketing/src/app/components/HeroSection/components/AppMockup/AppMockup.tsx`
around lines 730 - 732, The LuGitPullRequest icon inside the AppMockup component
uses an invalid Tailwind class "size-4.5"; replace it with a valid class such as
"size-4" or "size-5" on the LuGitPullRequest element to ensure the icon is
properly sized (adjust to "size-4" for 1rem or "size-5" for 1.25rem depending on
the desired visual).

Comment on lines +59 to +67
<button
type="button"
className="px-4 py-2.5 sm:px-6 sm:py-3 text-sm sm:text-base font-normal bg-background border border-border text-foreground hover:bg-muted transition-colors flex items-center gap-2"
onClick={() => window.open(COMPANY.GITHUB_URL, "_blank")}
aria-label="View on GitHub"
>
View on GitHub
<FaGithub className="size-4" />
</button>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use an <a> tag instead of <button> with window.open for the GitHub link.

A <button> with onClick={() => window.open(...)) loses native link behavior — middle-click to open in new tab, right-click context menu, link preview on hover, and crawler discoverability. An anchor element is semantically correct here.

🔗 Proposed fix
-						<button
-							type="button"
-							className="px-4 py-2.5 sm:px-6 sm:py-3 text-sm sm:text-base font-normal bg-background border border-border text-foreground hover:bg-muted transition-colors flex items-center gap-2"
-							onClick={() => window.open(COMPANY.GITHUB_URL, "_blank")}
-							aria-label="View on GitHub"
-						>
-							View on GitHub
-							<FaGithub className="size-4" />
-						</button>
+						<a
+							href={COMPANY.GITHUB_URL}
+							target="_blank"
+							rel="noopener noreferrer"
+							className="px-4 py-2.5 sm:px-6 sm:py-3 text-sm sm:text-base font-normal bg-background border border-border text-foreground hover:bg-muted transition-colors flex items-center gap-2"
+						>
+							View on GitHub
+							<FaGithub className="size-4" />
+						</a>
📝 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
<button
type="button"
className="px-4 py-2.5 sm:px-6 sm:py-3 text-sm sm:text-base font-normal bg-background border border-border text-foreground hover:bg-muted transition-colors flex items-center gap-2"
onClick={() => window.open(COMPANY.GITHUB_URL, "_blank")}
aria-label="View on GitHub"
>
View on GitHub
<FaGithub className="size-4" />
</button>
<a
href={COMPANY.GITHUB_URL}
target="_blank"
rel="noopener noreferrer"
className="px-4 py-2.5 sm:px-6 sm:py-3 text-sm sm:text-base font-normal bg-background border border-border text-foreground hover:bg-muted transition-colors flex items-center gap-2"
>
View on GitHub
<FaGithub className="size-4" />
</a>
🤖 Prompt for AI Agents
In `@apps/marketing/src/app/components/HeroSection/HeroSection.tsx` around lines
59 - 67, Replace the GitHub <button> in the HeroSection component with a
semantic <a> element that points to COMPANY.GITHUB_URL (use target="_blank" and
rel="noopener noreferrer"), keep the same className, aria-label="View on
GitHub", visible text "View on GitHub" and the <FaGithub> icon so styling and
accessibility remain identical but native link behaviors (middle-click, context
menu, crawlers) are preserved.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 13, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ⚠️ Neon database branch
  • ✅ Electric Fly.io app
  • ✅ Streams Fly.io app

Thank you for your contribution! 🎉

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Comment thread biome.jsonc Outdated
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.15/schema.json",
"$schema": "https://biomejs.dev/schemas/2.3.8/schema.json",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Biome schema downgraded mismatching installed package version

Low Severity

The $schema URL in biome.jsonc was downgraded from 2.3.15 to 2.3.8, but the project's package.json declares "@biomejs/biome": "^2.3.15" and bun.lock resolves to 2.3.15. This version mismatch is unrelated to the hero section redesign and appears accidental. It could cause IDE schema validation to miss config options available in 2.3.15 or flag valid options as errors.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (2)
apps/marketing/src/app/components/HeroSection/components/AppMockup/AppMockup.tsx (1)

268-281: Duplicated glass-border overlay pattern — consider extracting a shared component.

The diagonal gradient glass border (CSS mask-composite trick) is repeated verbatim for the main container and the external IDE popup, with only minor opacity tweaks. A small <GlassBorder /> component accepting className and gradient values would eliminate the duplication.

Also applies to: 855-868

apps/marketing/src/app/components/HeroSection/components/ProductDemo/ProductDemo.tsx (1)

68-76: Type DEMO_OPTIONS labels as ActiveDemo to enforce compile-time safety.

The DemoOption.label field is currently typed as string, which allows the as ActiveDemo cast to bypass TypeScript's type checking. If a label is added to DEMO_OPTIONS without updating the ActiveDemo union, the cast will silently accept an invalid value. Instead, define the interface as:

export interface DemoOption {
	label: ActiveDemo;
	videoPath: string;
	colors: readonly [string, string, string, string];
}

This eliminates the need for the cast and catches label mismatches at compile time.

@Kitenite Kitenite merged commit a5fbd22 into main Feb 16, 2026
14 of 16 checks passed
@Kitenite Kitenite deleted the kitenite/hero-cleanup branch February 16, 2026 01:27
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