enhance: modernize landing page feature and workflow sections#440
enhance: modernize landing page feature and workflow sections#440vv-verse wants to merge 1 commit into
Conversation
✅ Deploy Preview for github-spy ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
📝 WalkthroughWalkthroughApp.tsx main layout is updated to handle fullscreen state with separate flex configurations. Features.tsx is rewritten with animated 3D-tilting cards driven by mouse position tracking. HowItWorks.tsx is refactored from theme-context styling to Framer Motion with responsive desktop/mobile connector bubbles and animated step cards. ChangesLanding Page UI and Animation Enhancements
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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
🤖 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 `@src/components/Features.tsx`:
- Around line 123-139: The two glow divs in Features.tsx use the non-existent
Tailwind token "duration-400" (see the className values on the absolute glow
divs with "transition-opacity duration-400"); replace "duration-400" with a
valid token such as "duration-300" or "duration-500" or, if you need exactly
400ms and your Tailwind setup allows arbitrary values, use "duration-[400ms]" so
the hover fade timing is actually applied.
In `@src/components/HowItWorks.tsx`:
- Around line 261-289: The mapped fragments need top-level keys and the mobile
mapping has a redundant motion wrapper; replace the anonymous fragments in both
steps.map() calls with keyed containers (e.g., use <React.Fragment
key={step.number}> or a keyed div) so the fragment itself has a key, and in the
mobile branch remove the extra <motion.div variants={cardVariants}> since
StepCard already receives variants={cardVariants}; instead render StepCard
directly (with the key on the fragment/container) and keep DownArrowBubble keyed
as before (references: steps.map, StepCard, ArrowBubble, DownArrowBubble,
cardVariants, motion.div).
🪄 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: ea37c18c-9f18-4fc9-aa96-63572aef6326
📒 Files selected for processing (3)
src/App.tsxsrc/components/Features.tsxsrc/components/HowItWorks.tsx
| {/* Strong ambient glow on hover */} | ||
| <div | ||
| className="absolute inset-0 rounded-2xl pointer-events-none transition-opacity duration-400" | ||
| style={{ | ||
| opacity: hovered ? 1 : 0, | ||
| background: `radial-gradient(ellipse at 50% 0%, rgba(${feature.glow},0.22) 0%, transparent 60%)`, | ||
| }} | ||
| /> | ||
|
|
||
| {/* Bottom glow puddle */} | ||
| <div | ||
| className="absolute -bottom-6 left-1/2 -translate-x-1/2 w-3/4 h-12 rounded-full pointer-events-none transition-opacity duration-400 blur-xl" | ||
| style={{ | ||
| opacity: hovered ? 0.5 : 0, | ||
| background: `rgba(${feature.glow}, 0.35)`, | ||
| }} | ||
| /> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate Tailwind config
echo "== Tailwind config files =="
ls -1 tailwind.config.* 2>/dev/null || true
ls -1 **/tailwind.config.* 2>/dev/null || true
# Search for duration-400 usage across the repo
echo "== occurrences of 'duration-400' =="
rg -n "duration-400" . || true
# Inspect Tailwind transitionDuration configuration (if tailwind.config exists)
for f in $(ls -1 tailwind.config.* 2>/dev/null || true); do
echo "== transitionDuration in $f =="
rg -n "transitionDuration|duration" "$f" || true
done
# Show tailwind version from package.json (best-effort)
echo "== tailwind version in package.json =="
if [ -f package.json ]; then
cat package.json | rg -n "\"tailwindcss\"|tailwindcss" || true
fi
# Inspect the referenced file section for exact class usage
echo "== src/components/Features.tsx excerpt around duration-400 =="
sed -n '100,160p' src/components/Features.tsx 2>/dev/null || trueRepository: GitMetricsLab/github_tracker
Length of output: 2864
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== tailwind.config.js =="
wc -l tailwind.config.js
sed -n '1,200p' tailwind.config.js
echo "== transitionDuration matches (if any) in tailwind.config.js =="
rg -n "transitionDuration|extend.*transitionDuration|duration" tailwind.config.js || trueRepository: GitMetricsLab/github_tracker
Length of output: 520
Use a valid Tailwind duration token for these hover fades
duration-400 won’t be generated here (Tailwind config has no transitionDuration override), so the intended 400ms timing won’t apply.
Proposed fix
- className="absolute inset-0 rounded-2xl pointer-events-none transition-opacity duration-400"
+ className="absolute inset-0 rounded-2xl pointer-events-none transition-opacity duration-[400ms]"
@@
- className="absolute -bottom-6 left-1/2 -translate-x-1/2 w-3/4 h-12 rounded-full pointer-events-none transition-opacity duration-400 blur-xl"
+ className="absolute -bottom-6 left-1/2 -translate-x-1/2 w-3/4 h-12 rounded-full pointer-events-none transition-opacity duration-[400ms] blur-xl"🤖 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 `@src/components/Features.tsx` around lines 123 - 139, The two glow divs in
Features.tsx use the non-existent Tailwind token "duration-400" (see the
className values on the absolute glow divs with "transition-opacity
duration-400"); replace "duration-400" with a valid token such as "duration-300"
or "duration-500" or, if you need exactly 400ms and your Tailwind setup allows
arbitrary values, use "duration-[400ms]" so the hover fade timing is actually
applied.
| {steps.map((step, i) => ( | ||
| <> | ||
| <div key={step.number} className="flex-1 min-w-0 flex flex-col"> | ||
| <StepCard step={step} className="flex-1" /> | ||
| </div> | ||
| {i < steps.length - 1 && ( | ||
| <ArrowBubble key={`arrow-${i}`} color={step.arrowColor} /> | ||
| )} | ||
| </> | ||
| ))} | ||
| </motion.div> | ||
|
|
||
| {/* Mobile: stacked cards + down arrows */} | ||
| <motion.div | ||
| className="flex flex-col md:hidden gap-0" | ||
| variants={containerVariants} | ||
| initial="hidden" | ||
| whileInView="visible" | ||
| viewport={{ once: true, margin: '-50px' }} | ||
| > | ||
| {steps.map((step, i) => ( | ||
| <> | ||
| <motion.div key={step.number} variants={cardVariants}> | ||
| <StepCard step={step} /> | ||
| </motion.div> | ||
| {i < steps.length - 1 && ( | ||
| <DownArrowBubble key={`down-${i}`} color={step.arrowColor} /> | ||
| )} | ||
| </> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate and display the relevant section of HowItWorks.tsx
FILE="src/components/HowItWorks.tsx"
if [ ! -f "$FILE" ]; then
echo "Missing file: $FILE"
exit 1
fi
# Show lines around 240-320 (includes the provided 261-289 region)
nl -ba "$FILE" | sed -n '230,320p'Repository: GitMetricsLab/github_tracker
Length of output: 116
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check how Fragment is currently handled in this file (if imported or used)
FILE="src/components/HowItWorks.tsx"
rg -n "import\s+\{[^}]*Fragment[^}]*\}" "$FILE" || true
rg -n "\bFragment\b" "$FILE" || true
# Check StepCard / motion usage within the file for variants/ownership
rg -n "StepCard|cardVariants|variants=\{cardVariants\}|ArrowBubble|DownArrowBubble|motion\.div" "$FILE"Repository: GitMetricsLab/github_tracker
Length of output: 966
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="src/components/HowItWorks.tsx"
sed -n '120,170p' "$FILE"Repository: GitMetricsLab/github_tracker
Length of output: 1901
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="src/components/HowItWorks.tsx"
sed -n '240,310p' "$FILE"Repository: GitMetricsLab/github_tracker
Length of output: 2229
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="src/components/HowItWorks.tsx"
# Check if Fragment is already imported/used
rg -n "import\s+\{[^}]*Fragment|Fragment\s*[,)>]" "$FILE" || trueRepository: GitMetricsLab/github_tracker
Length of output: 54
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="src/components/HowItWorks.tsx"
sed -n '1,80p' "$FILE"Repository: GitMetricsLab/github_tracker
Length of output: 2837
Key the mapped wrapper elements and remove the redundant mobile motion wrapper.
- Both
steps.map()branches return anonymous<>...</>fragments; React needs akeyon the top-level fragment (innerkeys don’t cover the fragment itself). - In the mobile branch,
StepCardalready appliesvariants={cardVariants}, so the extra<motion.div variants={cardVariants}>duplicates the entrance animation.
Proposed fix
+import { Fragment } from 'react';
import { motion } from 'framer-motion';
@@
- {steps.map((step, i) => (
- <>
- <div key={step.number} className="flex-1 min-w-0 flex flex-col">
+ {steps.map((step, i) => (
+ <Fragment key={step.number}>
+ <div className="flex-1 min-w-0 flex flex-col">
<StepCard step={step} className="flex-1" />
</div>
{i < steps.length - 1 && (
<ArrowBubble key={`arrow-${i}`} color={step.arrowColor} />
)}
- </>
+ </Fragment>
))}
@@
- {steps.map((step, i) => (
- <>
- <motion.div key={step.number} variants={cardVariants}>
- <StepCard step={step} />
- </motion.div>
+ {steps.map((step, i) => (
+ <Fragment key={step.number}>
+ <StepCard step={step} />
{i < steps.length - 1 && (
<DownArrowBubble key={`down-${i}`} color={step.arrowColor} />
)}
- </>
+ </Fragment>
))}🤖 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 `@src/components/HowItWorks.tsx` around lines 261 - 289, The mapped fragments
need top-level keys and the mobile mapping has a redundant motion wrapper;
replace the anonymous fragments in both steps.map() calls with keyed containers
(e.g., use <React.Fragment key={step.number}> or a keyed div) so the fragment
itself has a key, and in the mobile branch remove the extra <motion.div
variants={cardVariants}> since StepCard already receives
variants={cardVariants}; instead render StepCard directly (with the key on the
fragment/container) and keep DownArrowBubble keyed as before (references:
steps.map, StepCard, ArrowBubble, DownArrowBubble, cardVariants, motion.div).
Summary
This PR modernizes key landing page sections with improved layouts, refined card designs, enhanced workflow visualization, and better dark mode consistency to create a more premium SaaS-style experience.
Closes #439
Sections Improved
Powerful Features
How It Works
UI/UX Enhancements
Design Direction
Testing
Screenshots
Before :
After :
final.github.mp4
Summary by CodeRabbit