feat: Railway-style interactive hero demo + /feed/more screen - #64
feat: Railway-style interactive hero demo + /feed/more screen#64Tar-ive wants to merge 2 commits into
Conversation
- Replace hero section with 5-tab interactive demo (Discover → Swipe → Gift → Pool → Maxi) showing simulated app UI with auto-cycling and click-override - Rebuild features section with Railway-style narrative arc and connector lines - Add /feed/more page with feature hub, quick stats, and Maxi CTA banner - Add CSS animations for panel transitions and card hover effects Co-Authored-By: Saksham <tarive22@gmail.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 3 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughThis PR adds a new ChangesFeed More Page
Landing Page Redesign
Estimated code review effort: 3 (Moderate) | ~30 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant HeroSection
participant TimerRef
participant PANELS
HeroSection->>TimerRef: start interval (AUTO_CYCLE_MS)
TimerRef->>HeroSection: tick, advance activeTab
HeroSection->>PANELS: render Panel for activeTab
User->>HeroSection: click tab
HeroSection->>TimerRef: restart interval
HeroSection->>PANELS: render selected Panel
sequenceDiagram
participant User
participant MorePage
participant useCurrentUser
participant CardGrid
User->>MorePage: navigate to /feed/more
MorePage->>useCurrentUser: fetch current user
useCurrentUser-->>MorePage: user avatar/name/handle
MorePage->>CardGrid: render feature arrays
CardGrid-->>User: linked feature tiles
Related PRs: None found. Suggested labels: frontend, ui-enhancement Suggested reviewers: Tar-ive Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
web/app/feed/more/page.tsx (2)
23-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valuePrefer lucide-react's exported
LucideIcontype overtypeof Search.
typeof Searchworks but couples the alias to whichever icon happens to be imported first (fragile indirection).lucide-reactexports a canonicalLucideIcontype for exactly this component-typing use case.♻️ Suggested tightening
-type IconComponent = typeof Search; +import type { LucideIcon } from "lucide-react"; +type IconComponent = LucideIcon;🤖 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 `@web/app/feed/more/page.tsx` at line 23, Replace the IconComponent alias in the feed page with lucide-react’s exported LucideIcon type instead of using typeof Search. Update the type definition near IconComponent to import and reference LucideIcon directly, so the component typing is decoupled from whichever icon is imported first and stays consistent across icon swaps.
34-123: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoffFeature/color config overlaps with features-section.tsx's own dataset.
Per the stack context,
features-section.tsx(sibling layer, same PR) maintains its ownFEATURESdataset plus aFEATURE_COLORSpalette for the same five product pillars (Discover/Swipe/Gift/Pool/Maxi). This file independently re-declares titles/colors/icons for an overlapping but distinct card set (hub page vs. landing feature blocks). Not a bug today, but two sources of truth for feature branding (icon/color/copy) risk drift as either evolves — consider a shared config module if these are meant to represent the same product surfaces.🤖 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 `@web/app/feed/more/page.tsx` around lines 34 - 123, The feature card titles, icons, and colors in PRIMARY_FEATURES and SECONDARY_FEATURES are duplicating branding data that also exists in features-section.tsx, creating multiple sources of truth. Move the shared product-pillar metadata into a common config module and have both this page’s card arrays and features-section.tsx consume it, keeping only page-specific copy or links local. Use the existing FeatureCard shape and the PRIMARY_FEATURES/SECONDARY_FEATURES constants as the main call sites to refactor.web/components/landing/features-section.tsx (1)
92-99: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueObserver keeps watching after visibility is already latched.
Once
entry.isIntersectingfires andisVisibleis set true, the observer (obs) is neverunobserve/disconnect-ed until unmount, so it keeps computing intersection on every scroll for a block that will never change state again. Cheap fix: disconnect right after the first trigger.♻️ Proposed fix
const observer = new IntersectionObserver( - ([entry]) => { if (entry.isIntersecting) setIsVisible(true); }, + ([entry]) => { + if (entry.isIntersecting) { + setIsVisible(true); + observer.disconnect(); + } + }, { threshold: 0.15 } );🤖 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 `@web/components/landing/features-section.tsx` around lines 92 - 99, The IntersectionObserver in the features-section component keeps observing after the first visible state is latched, causing unnecessary work on later scrolls. Update the useEffect callback in features-section.tsx so the observer is disconnected or unobserved immediately after setIsVisible(true) runs for the first intersecting entry, and keep the cleanup disconnect in place for unmount. Refer to the useEffect, observer, and setIsVisible logic in the landing/features-section component when making the change.web/components/landing/hero-section.tsx (1)
447-455: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoffHard-coded third-party CDN image (external dependency, EDN risk) for the hero background.
https://cdn.midjourney.com/...is loaded via a raw<img>rather thannext/image, and depends entirely on a third-party CDN outside your control. Beyond losing Next.js image optimization (responsive sizes, lazy loading, format negotiation), if that asset is ever removed/rotated by Midjourney, the hero silently falls back todisplay:noneon error, leaving an empty background. Consider hosting the asset yourself (e.g.public/or your own CDN) and rendering vianext/image.🤖 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 `@web/components/landing/hero-section.tsx` around lines 447 - 455, The hero background currently depends on a hard-coded Midjourney CDN URL in the hero section, which should be replaced with an asset you control. Update the hero background in hero-section.tsx to use a self-hosted image (for example from public/ or your own CDN) and render it through next/image instead of a raw img so the component keeps optimization and doesn’t vanish if the external asset disappears. Keep the change localized to the hero image markup and its fallback handling.
🤖 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 `@web/app/feed/more/page.tsx`:
- Around line 194-208: The quick stat cards in the live profile header are
hardcoded placeholder values, so update the stats block in the feed page to use
real user data or clearly mark it as mock copy. Refactor the inline stats array
in the header section so it pulls from the appropriate user stats source, or
replace the current `12k+ / 0 / 4.9` values with explicit placeholder labeling.
Keep the existing card rendering structure, but ensure the data source is
dynamic or intentionally non-production.
In `@web/components/landing/hero-section.tsx`:
- Around line 549-570: The tab buttons in hero-section lose their accessible
name on small screens because the label span is hidden for inactive tabs. Update
the tab button markup in the TABS map so each button always has a persistent
accessible name, using the tab label as button text or an aria-label on the
button, and ensure the Icon in the same button is treated as decorative if
needed. Keep the visual mobile behavior, but make sure inactive tabs in
handleTabClick remain announced correctly for screen readers.
---
Nitpick comments:
In `@web/app/feed/more/page.tsx`:
- Line 23: Replace the IconComponent alias in the feed page with lucide-react’s
exported LucideIcon type instead of using typeof Search. Update the type
definition near IconComponent to import and reference LucideIcon directly, so
the component typing is decoupled from whichever icon is imported first and
stays consistent across icon swaps.
- Around line 34-123: The feature card titles, icons, and colors in
PRIMARY_FEATURES and SECONDARY_FEATURES are duplicating branding data that also
exists in features-section.tsx, creating multiple sources of truth. Move the
shared product-pillar metadata into a common config module and have both this
page’s card arrays and features-section.tsx consume it, keeping only
page-specific copy or links local. Use the existing FeatureCard shape and the
PRIMARY_FEATURES/SECONDARY_FEATURES constants as the main call sites to
refactor.
In `@web/components/landing/features-section.tsx`:
- Around line 92-99: The IntersectionObserver in the features-section component
keeps observing after the first visible state is latched, causing unnecessary
work on later scrolls. Update the useEffect callback in features-section.tsx so
the observer is disconnected or unobserved immediately after setIsVisible(true)
runs for the first intersecting entry, and keep the cleanup disconnect in place
for unmount. Refer to the useEffect, observer, and setIsVisible logic in the
landing/features-section component when making the change.
In `@web/components/landing/hero-section.tsx`:
- Around line 447-455: The hero background currently depends on a hard-coded
Midjourney CDN URL in the hero section, which should be replaced with an asset
you control. Update the hero background in hero-section.tsx to use a self-hosted
image (for example from public/ or your own CDN) and render it through
next/image instead of a raw img so the component keeps optimization and doesn’t
vanish if the external asset disappears. Keep the change localized to the hero
image markup and its fallback handling.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3f8d39fc-b606-49f4-80c4-0307dcb398ab
📒 Files selected for processing (4)
web/app/feed/more/page.tsxweb/app/globals.cssweb/components/landing/features-section.tsxweb/components/landing/hero-section.tsx
| <div className="grid grid-cols-3 gap-3 mb-10"> | ||
| {[ | ||
| { value: "12k+", label: "Finds saved" }, | ||
| { value: "0", label: "Double-buys" }, | ||
| { value: "4.9", label: "Avg rating" }, | ||
| ].map((stat) => ( | ||
| <div | ||
| key={stat.label} | ||
| className="rounded-2xl border border-line bg-surface p-4 text-center" | ||
| > | ||
| <p className="text-2xl font-display text-ink">{stat.value}</p> | ||
| <p className="text-[10px] text-ink-faint mt-1">{stat.label}</p> | ||
| </div> | ||
| ))} | ||
| </div> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the target file and nearby context.
sed -n '1,260p' web/app/feed/more/page.tsx
# Search for the stat labels/values and any related data source in the feed area.
rg -n '"12k\+|"0"|"4\.9"|Finds saved|Double-buys|Avg rating|quick stats|stats' web/app/feed -S
# Check whether this page pulls any user-specific metrics elsewhere.
rg -n 'useCurrentUser|avatar|handle|grad|rating|saved|double-buys|finds saved' web/app -SRepository: Tar-ive/giftmaxxing
Length of output: 21839
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the file structure for the page component before reading smaller slices.
ast-grep outline web/app/feed/more/page.tsx --view expanded
# Show line numbers around the stats block only.
nl -ba web/app/feed/more/page.tsx | sed -n '180,220p'Repository: Tar-ive/giftmaxxing
Length of output: 644
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path("web/app/feed/more/page.tsx")
text = p.read_text()
for needle in ["12k+", "0", "4.9", "Finds saved", "Double-buys", "Avg rating"]:
print(needle, text.count(needle))
PYRepository: Tar-ive/giftmaxxing
Length of output: 216
Wire the quick stats to real user data The 12k+ / 0 / 4.9 cards read as per-user metrics under the live profile header, but they’re hardcoded. Either source them from user stats or mark them as placeholder copy.
🤖 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 `@web/app/feed/more/page.tsx` around lines 194 - 208, The quick stat cards in
the live profile header are hardcoded placeholder values, so update the stats
block in the feed page to use real user data or clearly mark it as mock copy.
Refactor the inline stats array in the header section so it pulls from the
appropriate user stats source, or replace the current `12k+ / 0 / 4.9` values
with explicit placeholder labeling. Keep the existing card rendering structure,
but ensure the data source is dynamic or intentionally non-production.
Co-Authored-By: Saksham <tarive22@gmail.com>
Summary
Replaces the landing page hero with a Railway-inspired 5-tab interactive product demo and adds a new
/feed/morefeature hub page.Hero Section (
hero-section.tsx)The hero now contains a dark-framed "device window" on the right that renders 5 animated mock UI panels, each telling the next chapter of the giftmaxxing user journey:
Tabs auto-cycle every 5s; clicking a tab resets the timer. Each panel re-mounts with a
key={activeTab}cross-fade via CSS (animate-panel-in). Tab bar uses pill-style buttons matching Railway's bottom nav pattern.Left column retains headline + CTAs but now uses the tagline
"Gifting, finally figured out."with the existingword-gradientanimation.Features Section (
features-section.tsx)Rebuilt as 5 alternating
FeatureBlocksections (one per tab) with:"Alternative to"competitive positioning badges (Amazon, Google Shopping, Pinterest)More Page (
/feed/more/page.tsx)New in-app page at
/feed/moreserving as a feature hub:card-glowCSS), and arrow reveal on hoverCSS (
globals.css)Added
animate-panel-in(opacity+translateY+scale cross-fade),animate-in(staggered item entrance), andcard-glow(hover gradient border) animations.Link to Devin session: https://calhacks-promptetheus.devinenterprise.com/sessions/622c5fce32b64bff863ca8ef7a2efc41
Requested by: @Tar-ive
Summary by CodeRabbit