Skip to content

Main page redesign (fixes from #4015)#4030

Open
devin-ai-integration[bot] wants to merge 7 commits intomainfrom
devin/1771332822-new-main-page-fixes
Open

Main page redesign (fixes from #4015)#4030
devin-ai-integration[bot] wants to merge 7 commits intomainfrom
devin/1771332822-new-main-page-fixes

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Feb 17, 2026

Main page redesign with scroll-reveal hero and reworked features

Summary

Redesigns the main landing page (from PR #4015 by @elstua) with the following changes:

  • Replaces the hero section with a new scroll-reveal paragraph manifesto (HeroParagraphSection)
  • Reworks feature blocks: new CoolStuffSection, AISection (with animated research status), GrowsWithYouSection (contacts + calendar), and a tabbed HowItWorksSection (notes → summary animation)
  • Adds new static assets (avatar.webp, contact_human.webp, hand-drawing SVGs)
  • Adds shimmer text CSS animation
  • Removes dev script from root package.json
  • Fixes invalid category in mac-productivity-apps.mdx (→ "Guides")
  • Formats index.tsx to pass dprint check

Updates since last revision

  • Fixed TypeScript errors causing CI ci job to fail:
    • Removed unused selectedFeature, featuresScrollRef, and scrollToFeature from Component
    • Removed invalid audioIndicatorWidth prop from MockWindow usage (prop doesn't exist on the component)
    • Exported HeroSection and ManifestoSection to resolve TS6133 unused-declaration errors

Review & Testing Checklist for Human

  • Visual review on desktop and mobile — this is a large UI overhaul; verify layout, spacing, typography, and animations render correctly at all breakpoints. Use the Netlify deploy preview once available.
  • HeroSection is commented out in JSX, not removedheroInputRef is still created and passed to CTASection. On non-macOS platforms where the CTA action is "waitlist", the bottom CTA button scrolls to top but does nothing (the email input it targets doesn't exist). Decide whether to wire up a new input or change the waitlist behavior.
  • audioIndicatorWidth={120} was removed, not wired up — the MockWindow component doesn't accept this prop, so it was removed to fix the TS error. The audio indicator in the "How it works" section now renders at the default 17px width instead of the intended 120px. If the wider indicator was desired, MockWindow needs to be updated to accept and forward this prop.
  • Animation timers in HowItWorksSection are never cleaned up on unmount — the recursive setTimeout/setInterval loop (~line 1043–1097) has no cleanup return in the useEffect. This can cause state updates on unmounted components.
  • Test the scroll-reveal paragraph animationScrollRevealParagraph uses Framer Motion scroll progress; verify it works smoothly and doesn't cause jank on lower-end devices.

Notes


Open with Devin

@netlify
Copy link

netlify bot commented Feb 17, 2026

Deploy Preview for hyprnote-storybook canceled.

Name Link
🔨 Latest commit f968038
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/699465f5158a7d00082a9604

@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@netlify
Copy link

netlify bot commented Feb 17, 2026

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit f968038
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/699465f5a67b2b000888fb2f
😎 Deploy Preview https://deploy-preview-4030--hyprnote.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Co-Authored-By: Sungbin Jo <goranmoomin@daum.net>
Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 3 potential issues.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines 1064 to 1094
clearInterval(interval2);

setTimeout(() => {
setEnhancedLines(1);
setActiveTab("summary");

setTimeout(() => {
setEnhancedLines(2);
setEnhancedLines(1);
setTimeout(() => {
setEnhancedLines(3);
setEnhancedLines(2);
setTimeout(() => {
setEnhancedLines(4);
setEnhancedLines(3);
setTimeout(() => {
setEnhancedLines(5);
setEnhancedLines(4);
setTimeout(() => {
setEnhancedLines(6);
setEnhancedLines(5);
setTimeout(() => {
setEnhancedLines(7);
setTimeout(() => runAnimation(), 1000);
setEnhancedLines(6);
setTimeout(() => {
setEnhancedLines(7);
setTimeout(() => runAnimation(), 2000);
}, 800);
}, 800);
}, 800);
}, 800);
}, 800);
}, 800);
}, 800);
}, 500);
}, 300);
}, 800);
}
}, 50);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🔴 HowItWorksSection animation timers are never cleaned up on unmount

The useEffect in HowItWorksSection (line 1042) calls runAnimation() which spawns a deeply nested chain of setTimeout and setInterval calls that recursively re-invoke runAnimation(). The effect has no cleanup return, so when the component unmounts (e.g., navigating away), all pending timers continue to fire and call setState (setTypedText1, setTypedText2, setEnhancedLines, setActiveTab) on an unmounted component.

Detailed Explanation

The animation loop at apps/web/src/routes/_view/index.tsx:1042-1100 creates:

  • An outer setTimeout (line 1050)
  • setInterval for typing text1 (line 1051)
  • setInterval for typing text2 (line 1059)
  • 9+ nested setTimeout calls for enhancedLines (lines 1066-1091)
  • A final setTimeout(() => runAnimation(), 2000) (line 1083) that restarts the entire cycle

None of these timer IDs are tracked, and the useEffect returns nothing (}, []); at line 1100). On unmount, all timers keep firing, causing React state updates on an unmounted component. This is a resource leak that can cause memory leaks and React warnings in development.

Impact: Memory leak and potential React "Can't perform a React state update on an unmounted component" warnings. On pages with frequent navigation, leaked timers accumulate.

(Refers to lines 1042-1100)

Prompt for agents
In apps/web/src/routes/_view/index.tsx, the useEffect starting at line 1042 in HowItWorksSection needs a cleanup mechanism. The approach should be:

1. Create a mutable ref (e.g., `const timersRef = useRef<(ReturnType<typeof setTimeout> | ReturnType<typeof setInterval>)[]>([])`) to track all timer IDs.
2. Wrap every `setTimeout` and `setInterval` call inside `runAnimation()` to push the returned ID into `timersRef.current`.
3. Add a boolean `cancelled` flag (or use a ref) that is checked before each `setState` call.
4. Return a cleanup function from the useEffect that sets `cancelled = true` and calls `clearTimeout`/`clearInterval` on every ID in `timersRef.current`.

Alternatively, refactor the entire animation to use a single `requestAnimationFrame` loop with elapsed-time-based state transitions, which is easier to clean up with a single `cancelAnimationFrame` call.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

onVideoExpand={setExpandedVideo}
heroInputRef={heroInputRef}
/>
<HeroParagraphSection onVideoExpand={setExpandedVideo} />
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🔴 CTASection's waitlist button does nothing because heroInputRef is never attached to a DOM element

The bottom CTA button for non-macOS platforms (Windows, Linux, mobile) scrolls to the top and attempts to focus heroInputRef.current, but this ref is always null because the HeroSection component (which contained <input ref={heroInputRef}>) was replaced by HeroParagraphSection which doesn't use the ref.

Root Cause

In the Component function at apps/web/src/routes/_view/index.tsx:118-156, heroInputRef is created at line 120 and passed to CTASection at line 147. Previously, it was also passed to HeroSection which rendered an <input ref={heroInputRef}> (line 304). But the PR replaced HeroSection with HeroParagraphSection (line 129), which does not accept or use heroInputRef.

As a result, heroInputRef.current is permanently null. When CTASection.handleCTAClick() runs (line 2425-2443), it calls window.scrollTo({ top: 0, behavior: "smooth" }) and then checks if (heroInputRef.current) — which is always false. The user sees the page scroll to top but nothing else happens. There's no email input to focus or interact with.

Impact: On Windows, Linux, and mobile platforms, the bottom CTA "Join waitlist" / "Get reminder" button is completely broken — it scrolls to the top of the page but provides no way for the user to actually join the waitlist or enter their email.

Prompt for agents
In apps/web/src/routes/_view/index.tsx, the HeroParagraphSection (line 129) replaced HeroSection but the heroInputRef is now orphaned. There are two options to fix this:

Option A: Add an email waitlist input to HeroParagraphSection (or a new section) and pass heroInputRef to it, so the CTASection button can scroll to and focus it.

Option B: Update CTASection (lines 2410-2502) to handle the waitlist action differently when there's no input to focus. For example, navigate to a dedicated waitlist/signup page, or show an inline email form within CTASection itself instead of trying to scroll to a non-existent input.

Also clean up the now-unused heroInputRef from Component() at line 120 if going with Option B.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines 392 to 393
);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🚩 HeroSection is exported but no longer rendered — dead code remains

The HeroSection function at apps/web/src/routes/_view/index.tsx:180-393 was changed from a private function to export function HeroSection(...) but is no longer used in the Component render tree (line 129 now renders HeroParagraphSection). Along with it, heroContent, mainFeatures, activeFeatureIndices, FEATURES_AUTO_ADVANCE_DURATION, MainFeaturesSection, FeaturesMobileCarousel, MobileFeatureVideo, FeatureVideo, FeaturesDesktopGrid, ValuePropsGrid, and ManifestoSection are all still defined but no longer referenced from the main page component. This is a significant amount of dead code that increases bundle size. The MainFeaturesSection and its children were previously rendered inline and are now entirely removed from the page layout.

(Refers to lines 180-393)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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.

2 participants

Comments