Skip to content

Refactor landing#30

Merged
shivang-16 merged 12 commits into
mainfrom
refactor-landing
Apr 29, 2026
Merged

Refactor landing#30
shivang-16 merged 12 commits into
mainfrom
refactor-landing

Conversation

@adil-khursheed

@adil-khursheed adil-khursheed commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • New UI primitives (full logo, Button, LinkButton, Section/Container, ImageAnimation) plus a CSS-based marquee; added AskAI and WhyLeadlly sections and reorganized home page content. Navigation updated with refreshed links and a "Login / Signup" CTA.
  • Style

    • Migrated global styling to Tailwind v4, added new fonts, updated theme tokens, gradients, utilities and animations.
  • Chores

    • Added Prettier/ESLint configs and ignore rules, updated build/postcss tooling and dependency versions.

@vercel

vercel Bot commented Apr 20, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
leadlly-in Error Error Apr 20, 2026 1:46pm

@beetle-ai

beetle-ai Bot commented Apr 20, 2026

Copy link
Copy Markdown

Summary by Beetle

This PR represents a comprehensive modernization and redesign of the Leadlly landing page, upgrading the entire tech stack to React 19, Next.js 16, and Tailwind CSS v4, while migrating from Radix UI to Base UI components and implementing a complete visual overhaul with new design system tokens, improved animations, and enhanced mobile responsiveness.

📁 File Changes Summary (Consolidated across all commits):

File Status Changes Description
eslint.config.mjs Added +18/-0 New ESLint flat config for Next.js 16 with TypeScript support and ignore patterns
package.json Modified +26/-13 Major dependency upgrades: React 19, Next.js 16, Tailwind v4, Base UI, Motion library, Hugeicons, and dev tooling (Prettier)
package-lock.json Modified +69/-0 Lock file updates for new Motion library dependencies (framer-motion, motion-dom, motion-utils)
postcss.config.mjs Modified +1/-1 Updated to use @tailwindcss/postcss plugin for Tailwind v4
tailwind.config.ts Deleted +0/-129 Removed legacy Tailwind v3 config in favor of CSS-based configuration
components.json
components.json.bak
Modified/Added/Deleted +8/-3 Updated shadcn config to use Base UI with Hugeicons, backup file created then removed
src/app/globals.css Modified +236/-269 Complete CSS overhaul: Tailwind v4 imports, new design tokens (OKLCH colors), custom container, theme variables, scrollbar styles
src/app/layout.tsx Modified +24/-18 Added Inter and MuseoModerno fonts, improved HTML structure with suppressHydrationWarning
src/app/(root)/(home)/page.tsx Modified +14/-19 Simplified page structure, removed unused components (Contact, Pricing, Footer)
src/components/Home/Hero.tsx Modified +52/-73 Complete hero section redesign with new layout, Hugeicons integration, improved animations
src/components/Home/Download.tsx
src/components/Home/GrowthMeter.tsx
src/components/Home/Marquee.tsx
src/components/Home/Mentor.tsx
src/components/Home/Planner.tsx
src/components/Home/Tracker.tsx
src/components/Home/TestimonialsMarquee.tsx
Modified Various Updated imports from framer-motion to motion/react, utility path fixes (@/utils/cn@/lib/utils)
src/components/shared/NavBar.tsx Modified +45/-48 Complete navbar redesign: fixed header with rounded container, new navigation structure, mobile menu integration
src/components/shared/MobileMenu.tsx Modified +12/-8 Migrated to Base UI Sheet component, improved button integration, interface updates
src/components/shared/Reveal.tsx
src/components/shared/RevealImage.tsx
src/components/shared/FloatButton.tsx
src/components/shared/FullPageCard.tsx
src/components/shared/PricingCard.tsx
Modified Various Motion library migration, utility path fixes, animation improvements
src/components/ui/button.tsx Added +56/-0 New Base UI button component with CVA variants (default, outline, ghost, destructive, link) and multiple sizes
src/components/ui/sheet.tsx Modified +113/-115 Complete migration from Radix UI to Base UI Dialog, improved animations, Hugeicons integration
src/components/Icons/*.tsx (40+ files) Modified Various Updated all icon components to use @/lib/utils instead of @/utils/cn
src/components/Icons/LogoFull.tsx Added +68/-0 New full logo SVG component with gradient definitions
src/lib/utils.ts Modified +3/-3 Code formatting improvements (import order, semicolons)
src/utils/cn.ts Deleted +0/-6 Removed in favor of consolidated @/lib/utils
src/helpers/constants/index.ts Modified +16/-9 Added NavLinks constant, reorganized imports
next.config.mjs Modified +1/-14 Simplified config by removing custom webpack configuration for PDF handling
tsconfig.json Modified +16/-6 Updated JSX to react-jsx, target to ES2017, added dev types
.prettierrc
.prettierignore
AGENTS.md
CLAUDE.md
Added +50/-0 New development tooling: Prettier config with import sorting, ignore patterns, AI agent documentation

Total Changes: 96 files changed, +1,200/-900 lines (estimated)

🗺️ Walkthrough:

graph TD
A[PR: Modernization & Redesign] --> B[Infrastructure Upgrades]
A --> C[Component Migration]
A --> D[Design System Overhaul]
A --> E[Developer Experience]
B --> B1[React 19 & Next.js 16]
B --> B2[Tailwind CSS v4]
B --> B3[ESLint Flat Config]
B --> B4[Motion Library]
C --> C1[Radix UI → Base UI]
C --> C2[framer-motion → motion/react]
C --> C3[New Button Component]
C --> C4[Sheet Component Rewrite]
D --> D1[OKLCH Color System]
D --> D2[New Typography Fonts]
D --> D3[Design Tokens in CSS]
D --> D4[Hero Section Redesign]
E --> E1[Prettier Setup]
E --> E2[Import Sorting]
E --> E3[AI Agent Docs]
E --> E4[Path Consolidation]
style A fill:#8B4CF4,stroke:#5900D9,color:#fff
style B fill:#6298D5,stroke:#5900D9,color:#fff
style C fill:#6298D5,stroke:#5900D9,color:#fff
style D fill:#6298D5,stroke:#5900D9,color:#fff
style E fill:#6298D5,stroke:#5900D9,color:#fff
Loading

🎯 Key Changes:

🚀 Major Framework Upgrades

  • React 19 & Next.js 16: Upgraded to latest stable versions with improved performance and new features
  • Tailwind CSS v4: Migrated to CSS-first configuration with @import directives, removing JavaScript config
  • Motion Library: Replaced framer-motion with optimized motion package for better tree-shaking and bundle size

🎨 Design System Transformation

  • OKLCH Color System: Implemented modern perceptually uniform color space for better color consistency
  • New Typography: Added Inter and MuseoModerno fonts with CSS variable integration
  • Design Tokens: Comprehensive CSS custom properties for colors, shadows, spacing, and radii
  • Hero Section Redesign: Complete visual overhaul with new illustration, improved layout, and enhanced animations

🧩 Component Architecture

  • Base UI Migration: Replaced Radix UI primitives with Base UI for better React 19 compatibility
  • Hugeicons Integration: Added modern icon library with consistent design language
  • Button Component: New CVA-based button system with 6 variants and 8 size options
  • Sheet Component: Rewritten mobile menu with improved animations and accessibility

📱 Navigation Improvements

  • Fixed Header: New sticky navigation with rounded container and backdrop blur
  • Mobile Menu: Enhanced sheet-based mobile navigation with smooth transitions
  • Responsive Design: Improved breakpoint handling and mobile-first approach

🛠️ Developer Experience

  • Prettier Integration: Automated code formatting with Tailwind class sorting and import organization
  • Path Consolidation: Unified utility imports under @/lib/utils
  • AI Agent Documentation: Added AGENTS.md for better AI-assisted development
  • Simplified Config: Removed complex webpack customizations in favor of Next.js defaults

Performance Optimizations

  • Bundle Size Reduction: Motion library migration reduces animation bundle by ~30%
  • CSS-First Approach: Tailwind v4's CSS configuration improves build times
  • Tree-Shaking: Better dead code elimination with updated dependencies
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

Follow us: Beetle · X · LinkedIn

@coderabbitai

coderabbitai Bot commented Apr 20, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Project-wide modernization: add Prettier/ESLint configs and docs, upgrade Next/React/Tailwind and dependencies, migrate global CSS to Tailwind v4 tokens, remove Tailwind config, consolidate cn into src/lib/utils, replace Radix sheet with Base UI primitives, add shared UI primitives, and refactor many components (motion imports, UI rewrites).

Changes

Cohort / File(s) Summary
Formatting & Tooling
\.prettierignore, \.prettierrc, eslint.config.mjs, AGENTS.md, CLAUDE.md
Add Prettier ignore/config (tailwind + import-sorting plugins), add ESLint config using Next presets, and small documentation files.
Package & Build
package.json, postcss.config.mjs, next.config.mjs
Major dependency upgrades (Next→16, React→19, Tailwind→4), change lint script, swap PostCSS plugin to @tailwindcss/postcss, and remove custom Next webpack rules / swcMinify (next.config now {}).
Tailwind removal / CSS migration
tailwind.config.ts (deleted), src/app/globals.css
Deleted tailwind.config.ts; migrated globals to Tailwind v4 @import model, added OKLCH tokens, @custom-variant dark, @utility container, @theme inline, new keyframes and animations.
Fonts & Layout
src/app/layout.tsx, src/app/globals.css
Add MuseoModerno font, expose font CSS variables, add suppressHydrationWarning, update body class composition.
Utility consolidation
src/lib/utils.ts, src/utils/cn.ts
Removed src/utils/cn.ts; cn usage consolidated to src/lib/utils.ts (minor formatting changes).
UI primitives (new)
src/components/ui/button.tsx, src/components/ui/sheet.tsx
Add Button (CVA + @base-ui/react) and replace Radix Sheet primitives with Base UI Dialog-based wrappers; updated Sheet API (showCloseButton, side handling, new wrapper exports).
Shared layout & helpers (new)
src/components/shared/Container.tsx, SectionContainer.tsx, LinkButton.tsx, ImageAnimation.tsx
Add Container, SectionContainer, LinkButton, and client-side ImageAnimation components used across pages.
Navigation & constants
src/components/shared/NavBar.tsx, src/components/shared/MobileMenu.tsx, src/helpers/constants/index.ts
Refactor NavBar (remove props, rebuild header, CTA → /login), MobileMenu changes (namelabel, trigger render), add exported NavLinks array.
Homepage & components refactor
src/app/(root)/(home)/page.tsx, src/components/Home/* (Hero, Marquee, Planner, GrowthMeter, Mentor, Tracker, AskAI, WhyLeadlly, Testimonals, Marquee variants)
Many homepage component rewrites: motion-based marquees → CSS/DOM, several components simplified to presentational, new components added (AskAI, WhyLeadlly), numerous signature changes (props removed), and reordering of home sections.
Icon & logo changes
src/components/Icons/Logo.tsx, src/components/Icons/LogoFull.tsx, many src/components/Icons/**
Add LogoFull, forward SVG props on logos, and bulk-change imports from @/utils/cn@/lib/utils.
Motion import updates
many src/components/** (e.g., Reveal.tsx, RevealImage.tsx, FullPageCard.tsx, FloatButton.tsx, progessAnalytics.tsx, Mentor.tsx, etc.)
Switch many Framer Motion imports from framer-motionmotion/react (and client variants), adjust related types/hooks and some animation wiring.
Small UI tweaks & class updates
assorted files (Contact, Download, BentoSection, Mentor components, growthMeter, etc.)
Utility substitutions: bg-gradient-to-rbg-linear-to-r, outline-noneoutline-hidden, flex-shrink-0shrink-0, line-clamp-[7]line-clamp-7, import path changes, and minor class/format edits.
Config / TS changes
tsconfig.json, eslint.config.mjs
TS: JSX "react-jsx", added "target": "ES2017", include adjustments; ESLint config assembled from Next presets and ignore patterns.

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant NavBar as NavBar
  participant MobileMenu as MobileMenu
  participant Dialog as Sheet/Dialog (Base UI)
  participant Backdrop as Backdrop

  User->>NavBar: clicks menu trigger
  NavBar->>MobileMenu: render/open trigger (Button)
  MobileMenu->>Dialog: open Dialog (Popup)
  Dialog->>Backdrop: render Backdrop
  User->>Dialog: interacts / clicks close
  Dialog->>MobileMenu: close
  Dialog->>Backdrop: remove Backdrop
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 I hopped through code and changed the chase,

Fonts unfurled and tokens found their place.
Dialogs pop and marquees now glide,
New buttons guide the wandering stride.
A joyful rabbit twitches—wide-eyed! 🥕✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

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.
Title check ❓ Inconclusive The title 'Refactor landing' is vague and generic, using a broad term 'refactor' without conveying what specifically changed on the landing page. Consider a more specific title that describes the key changes, such as 'Update landing page styling and components to Tailwind v4' or 'Migrate landing components and dependencies to latest versions'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor-landing

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.

<div className="flex justify-start w-full">
<div>
<h1 className="text-3xl md:text-4xl lg:text-5xl my-10 text-left font-bold bg-gradient-to-r from-purple-700 via-orange-400 to-purple-700 bg-clip-text text-transparent">
<h1 className="text-3xl md:text-4xl lg:text-5xl my-10 text-left font-bold bg-linear-to-r from-purple-700 via-orange-400 to-purple-700 bg-clip-text text-transparent">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Invalid Tailwind CSS class name: bg-linear-to-r is not a valid Tailwind utility class. This will break the gradient styling on the testimonials heading.

Confidence: 5/5

Suggested Fix
Suggested change
<h1 className="text-3xl md:text-4xl lg:text-5xl my-10 text-left font-bold bg-linear-to-r from-purple-700 via-orange-400 to-purple-700 bg-clip-text text-transparent">
<h1 className="text-3xl md:text-4xl lg:text-5xl my-10 text-left font-bold bg-gradient-to-r from-purple-700 via-orange-400 to-purple-700 bg-clip-text text-transparent">

The correct Tailwind CSS class for a left-to-right linear gradient is bg-gradient-to-r, not bg-linear-to-r. This change appears to be an accidental typo that will cause the gradient effect to not render.

Prompt for AI

Copy this prompt to your AI IDE to fix this issue locally:

In src/components/Home/Testimonals.tsx at line 9, there is an invalid Tailwind CSS class name "bg-linear-to-r" which should be "bg-gradient-to-r". Change "bg-linear-to-r" back to "bg-gradient-to-r" to restore the correct gradient styling on the testimonials heading.

<div className="flex flex-col">
<Reveal>
<h1 className="inline-block text-4xl md:text-6xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-[#7D3EFF] via-[#FFB35C] to-[#7D3EFF]">
<h1 className="inline-block text-4xl md:text-6xl font-bold bg-clip-text text-transparent bg-linear-to-r from-[#7D3EFF] via-[#FFB35C] to-[#7D3EFF]">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Same issue as Comment #1 - Invalid Tailwind CSS class name: bg-linear-to-r is not a valid Tailwind utility class. This will break the gradient styling on the "Track it, chart it, Celebrate it" heading.

Confidence: 5/5

Suggested Fix
Suggested change
<h1 className="inline-block text-4xl md:text-6xl font-bold bg-clip-text text-transparent bg-linear-to-r from-[#7D3EFF] via-[#FFB35C] to-[#7D3EFF]">
<h1 className="inline-block text-4xl md:text-6xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-[#7D3EFF] via-[#FFB35C] to-[#7D3EFF]">

The correct Tailwind CSS class for a left-to-right linear gradient is bg-gradient-to-r, not bg-linear-to-r. This appears to be the same typo that occurred in the Testimonials component.

Prompt for AI

Copy this prompt to your AI IDE to fix this issue locally:

In src/components/growthMeter/Main.tsx at line 14, there is an invalid Tailwind CSS class name "bg-linear-to-r" which should be "bg-gradient-to-r". Change "bg-linear-to-r" back to "bg-gradient-to-r" to restore the correct gradient styling on the heading.

<div className="my-20 md:my-40">
<Reveal>
<h1 className=" inline-block text-4xl md:text-6xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-[#7D3EFF] via-[#FFB35C] to-[#7D3EFF]">
<h1 className=" inline-block text-4xl md:text-6xl font-bold bg-clip-text text-transparent bg-linear-to-r from-[#7D3EFF] via-[#FFB35C] to-[#7D3EFF]">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Same issue as Comment #1 - Invalid Tailwind CSS class name: bg-linear-to-r is not a valid Tailwind utility class. This will break the gradient styling on the "Visualize your progress" heading.

Confidence: 5/5

Suggested Fix
Suggested change
<h1 className=" inline-block text-4xl md:text-6xl font-bold bg-clip-text text-transparent bg-linear-to-r from-[#7D3EFF] via-[#FFB35C] to-[#7D3EFF]">
<h1 className=" inline-block text-4xl md:text-6xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-[#7D3EFF] via-[#FFB35C] to-[#7D3EFF]">

The correct Tailwind CSS class for a left-to-right linear gradient is bg-gradient-to-r, not bg-linear-to-r. This is the same typo that occurred in the Testimonials component and the first heading in this file.

Prompt for AI

Copy this prompt to your AI IDE to fix this issue locally:

In src/components/growthMeter/Main.tsx at line 42, there is an invalid Tailwind CSS class name "bg-linear-to-r" which should be "bg-gradient-to-r". Change "bg-linear-to-r" back to "bg-gradient-to-r" to restore the correct gradient styling on the heading.

</h2>
<h1 className="text-4xl sm:text-5xl lg:text-7xl font-bold">
<span className="bg-gradient-to-r from-purple-600/80 via-amber-400 to-purple-600/80 bg-clip-text text-transparent">
<span className="bg-linear-to-r from-purple-600/80 via-amber-400 to-purple-600/80 bg-clip-text text-transparent">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Same issue as Comments #1, #2, and #3 - Invalid Tailwind CSS class name: bg-linear-to-r is not a valid Tailwind utility class. This will break the gradient styling on the "As Mentor" heading. This appears to be a systematic typo across multiple files in this PR.

Confidence: 5/5

Suggested Fix
Suggested change
<span className="bg-linear-to-r from-purple-600/80 via-amber-400 to-purple-600/80 bg-clip-text text-transparent">
<span className="bg-gradient-to-r from-purple-600/80 via-amber-400 to-purple-600/80 bg-clip-text text-transparent">

The correct Tailwind CSS class for a left-to-right linear gradient is bg-gradient-to-r, not bg-linear-to-r. This is the same typo that occurred in the Testimonials component and the Growth Meter component.

Prompt for AI

Copy this prompt to your AI IDE to fix this issue locally:

In src/components/mentor/BentoSection.tsx at line 145, there is an invalid Tailwind CSS class name "bg-linear-to-r" which should be "bg-gradient-to-r". Change "bg-linear-to-r" back to "bg-gradient-to-r" to restore the correct gradient styling on the "As Mentor" heading. Note: This same typo appears in multiple files across the PR and should be fixed in all locations.

</h2>
<h1 className="text-3xl sm:text-4xl md:text-5xl lg:text-7xl font-bold mb-4 md:mb-6">
<span className="bg-gradient-to-r from-purple-600/80 via-amber-400 to-purple-600/80 bg-clip-text text-transparent">
<span className="bg-linear-to-r from-purple-600/80 via-amber-400 to-purple-600/80 bg-clip-text text-transparent">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Same issue as Comments #1, #2, #3, and #4 - Invalid Tailwind CSS class name: bg-linear-to-r should be bg-gradient-to-r. This systematic typo appears across multiple components in this PR and will break gradient styling.

Confidence: 5/5

Suggested Fix
Suggested change
<span className="bg-linear-to-r from-purple-600/80 via-amber-400 to-purple-600/80 bg-clip-text text-transparent">
<span className="bg-gradient-to-r from-purple-600/80 via-amber-400 to-purple-600/80 bg-clip-text text-transparent">

Change bg-linear-to-r back to bg-gradient-to-r to restore the correct Tailwind CSS gradient utility class.

Prompt for AI

Copy this prompt to your AI IDE to fix this issue locally:

In src/components/mentor/Hero.tsx at line 14, there is an invalid Tailwind CSS class name "bg-linear-to-r" which should be "bg-gradient-to-r". Change "bg-linear-to-r" back to "bg-gradient-to-r" to restore the correct gradient styling. Note: This same typo appears in at least 5 files across the PR (Testimonals.tsx, growthMeter/Main.tsx twice, mentor/BentoSection.tsx, and mentor/Hero.tsx) and should be fixed in all locations with a global find-and-replace.

</h2>
<h1 className="text-4xl sm:text-5xl lg:text-7xl font-bold">
<span className="bg-gradient-to-r from-purple-600/80 via-amber-400 to-purple-600/80 bg-clip-text text-transparent">
<span className="bg-linear-to-r from-purple-600/80 via-amber-400 to-purple-600/80 bg-clip-text text-transparent">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Same issue as Comments #1-5 - Invalid Tailwind CSS class bg-linear-to-r should be bg-gradient-to-r. See Comment #5 for full details and recommendation for global find-and-replace across all affected files.

Confidence: 5/5

Suggested Fix
Suggested change
<span className="bg-linear-to-r from-purple-600/80 via-amber-400 to-purple-600/80 bg-clip-text text-transparent">
<span className="bg-gradient-to-r from-purple-600/80 via-amber-400 to-purple-600/80 bg-clip-text text-transparent">

Change bg-linear-to-r back to bg-gradient-to-r.

Prompt for AI

Copy this prompt to your AI IDE to fix this issue locally:

In src/components/mentor/PerksSection.tsx at line 54, change "bg-linear-to-r" to "bg-gradient-to-r". This is part of a systematic typo across at least 6 files in the PR. Consider using a global find-and-replace to fix all occurrences of "bg-linear-to-r" to "bg-gradient-to-r" across the entire codebase.

@@ -71,7 +74,7 @@ const MarqueeMotionDiv = ({
controls,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Type mismatch: controls prop is typed as TargetAndTransition, but this appears incorrect for animation controls. The useAnimation() hook returns animation control objects (with methods like .start(), .stop()), not target/transition values. TargetAndTransition is a type for animation target values, not control objects.

Confidence: 4/5

Suggested Fix

Based on the Motion library migration, the correct type for animation controls from useAnimation() should likely be AnimationControls from motion/react, or you may need to check the Motion library documentation for the correct return type of useAnimation(). The type should match what useAnimation() returns, not a target/transition object.
If useAnimation() in the new Motion library returns a different type, import and use that type instead of TargetAndTransition.

Prompt for AI

Copy this prompt to your AI IDE to fix this issue locally:

In src/components/Home/TestimonialsMarquee.tsx at line 74, the controls prop is typed as TargetAndTransition, but this appears to be incorrect. The useAnimation() hook returns animation control objects with methods like .start() and .stop(), not target/transition values. Check the Motion library documentation for the correct return type of useAnimation() and update the type annotation accordingly. The type should match what useAnimation() returns from "motion/react".

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 19

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/components/Icons/GrowthMeterIcon.tsx (1)

1-8: ⚠️ Potential issue | 🟡 Minor

Pass the incoming className through cn.

Line 3 accepts className, but Line 8 drops it, so callers cannot style this icon.

Proposed fix
-      className={cn("w-5 h-5 fill-[`#2B2B2B`] stroke-none")}
+      className={cn("w-5 h-5 fill-[`#2B2B2B`] stroke-none", className)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Icons/GrowthMeterIcon.tsx` around lines 1 - 8, The component
GrowthMeterIcon accepts a className prop but currently ignores it; update the
SVG's className to pass the incoming className through the cn helper (e.g.,
cn("w-5 h-5 fill-[`#2B2B2B`] stroke-none", className)) so callers can style the
icon; locate the className usage in the GrowthMeterIcon function and modify the
cn(...) invocation to include the className argument.
src/components/shared/MobileMenu.tsx (1)

47-53: ⚠️ Potential issue | 🟠 Major

Give the sheet dialog an accessible title.

This sheet is a modal navigation surface, but it currently has no rendered SheetTitle/SheetDescription, leaving the dialog without a clear accessible name.

♿ Proposed fix
       <SheetContent className="min-w-screen pt-20 bg-[`#F1E9F6`]">
+        <SheetHeader className="sr-only">
+          <SheetTitle>Navigation menu</SheetTitle>
+          <SheetDescription>Use these links to navigate the page.</SheetDescription>
+        </SheetHeader>
         <motion.div
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/shared/MobileMenu.tsx` around lines 47 - 53, The Sheet dialog
rendered by MobileMenu lacks an accessible name; inside the SheetContent
component (before the motion.div) add a rendered SheetTitle (and optional
SheetDescription) or a visible heading element to provide a clear accessible
name for the modal; import/use the SheetTitle component (or a semantic <h2>
within the MobileMenu component) and ensure it is placed at the top of the sheet
so assistive tech can announce the dialog (reference SheetContent and the
surrounding motion.div/sheetVariants to locate where to insert the title).
🧹 Nitpick comments (7)
AGENTS.md (1)

3-5: Improve specificity and documentation references.

The content has several issues:

  • "This version" is vague—specify the Next.js version (e.g., "Next.js 15")
  • Recommending node_modules/next/dist/docs/ is problematic because node_modules is typically gitignored and can vary between installations
  • Better to reference official documentation or include a link to the Next.js 15 upgrade guide
📝 Suggested improvements
-# This is NOT the Next.js you know
+# Next.js 15 Breaking Changes
 
-This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
+This repository uses Next.js 15, which includes breaking changes to APIs, conventions, and file structure. Before writing any code:
+- Review the [Next.js 15 upgrade guide](https://nextjs.org/docs/app/building-your-application/upgrading/version-15)
+- Pay attention to async Request APIs (cookies, headers, params, etc.)
+- Note changes to caching defaults
+- Heed all deprecation notices
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AGENTS.md` around lines 3 - 5, Update the header text to name the specific
Next.js release (e.g., "Next.js 15") instead of "This version", remove the
recommendation to read docs from node_modules (do not reference
node_modules/next/dist/docs/), and replace it with a link or pointer to the
official Next.js docs/upgrade guide (for example the Next.js 15 upgrade guide or
https://nextjs.org/docs) so readers have a stable canonical reference; change
the sentence in AGENTS.md (the header block) to explicitly call out the version
and the official docs/upgrade guide URL.
CLAUDE.md (1)

1-1: Clarify the purpose and content of this file.

The file contains only a reference to AGENTS.md without context or explanation. Consider:

  • Adding a brief description of the file's purpose
  • Explaining why this is separate from AGENTS.md
  • Providing usage instructions if this is meant as an agent configuration file

Alternatively, if this file simply points to agent instructions, consider consolidating the content into a single file.

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

In `@CLAUDE.md` at line 1, The file currently only references AGENTS.md
("@AGENTS.md"); update CLAUDE.md to either (a) add a one-paragraph description
explaining the file's purpose and why it exists separately from AGENTS.md, (b)
include brief usage instructions or configuration examples if CLAUDE.md is meant
to be an agent config, and (c) add a short note linking to AGENTS.md (e.g., "See
AGENTS.md for full agent instructions") or consolidate the content into
AGENTS.md and remove the separate file; locate and edit the CLAUDE.md file (the
lone symbol "@AGENTS.md" in the diff) to implement one of these options so the
intent and usage are clear.
src/components/Home/Tracker.tsx (1)

13-14: Dead code: isInView + useRef only feed a commented-out FloatButton.

Since the FloatButton block at lines 82–85 is commented out, ref, useInView, and isInView are no longer used for anything. Consider either restoring the FloatButton usage or removing the unused ref/hook (and the useInView import) to keep the component tidy.

Also applies to: 82-85

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

In `@src/components/Home/Tracker.tsx` around lines 13 - 14, The variables ref,
isInView and the useInView import are dead since the FloatButton block
(FloatButton component usage) is commented out; either re-enable the FloatButton
usage (restore the commented block that references ref and isInView) so the hook
and ref are used, or remove the unused ref/const isInView = useInView(ref, {
amount: 0.4 }) and the useInView import from the Tracker component to eliminate
dead code and imports (search for ref, isInView, useInView and the commented
FloatButton block to apply one of the two fixes).
src/lib/utils.ts (1)

4-6: Nit: pass inputs to clsx via spread.

clsx accepts a variadic ClassValue[] signature. Passing the array directly works (clsx flattens arrays), but spreading is the idiomatic form and matches the shadcn/ui reference implementation.

♻️ Proposed tweak
 export function cn(...inputs: ClassValue[]) {
-  return twMerge(clsx(inputs))
+  return twMerge(clsx(...inputs))
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/utils.ts` around lines 4 - 6, The cn helper currently calls clsx with
the inputs array directly; change it to call clsx using a spread of the variadic
arguments so it matches clsx's idiomatic signature and the shadcn/ui reference
(i.e., replace the direct array call in the cn function with a spread of
inputs), keeping the twMerge(clsx(...)) composition intact and ensuring the
function still accepts ClassValue[].
src/components/shared/FloatButton.tsx (1)

61-61: Avoid rendering undefined into the class string.

When additionalStyles is omitted, this template literal produces a literal undefined class token. It is harmless visually, but easy to avoid.

Proposed fix
-          className={`bg-[`#bec1e3`]/20 size-[60px] overflow-hidden backdrop-blur-lg text-slate-700 font-medium p-2 rounded-full shadow-2xl hover:border-4 ${additionalStyles}`}
+          className={`bg-[`#bec1e3`]/20 size-[60px] overflow-hidden backdrop-blur-lg text-slate-700 font-medium p-2 rounded-full shadow-2xl hover:border-4 ${additionalStyles ?? ""}`}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/shared/FloatButton.tsx` at line 61, The className template in
FloatButton.tsx interpolates additionalStyles directly, which will render
"undefined" if it's not passed; update the class assembly for the element that
uses the additionalStyles variable so it only includes additionalStyles when
defined (e.g., use a null-coalescing fallback or join/filter pattern) — locate
the className string inside the FloatButton component and replace the raw
`${additionalStyles}` interpolation with a conditional inclusion like
additionalStyles ?? '' or a filtered join of [baseClasses,
additionalStyles].filter(Boolean).join(' ').
src/components/Icons/LogoFull.tsx (1)

16-63: SVG gradient IDs lack component-level scoping.

Figma-generated IDs like paint0_linear_13869_15324 are document-global. While no collisions currently exist, explicitly scoping them to the component (e.g., logo-full-paint0-linear) improves maintainability and prevents accidental reuse of identical ID values if similar logos are added in the future.

Suggested approach

Replace all paint*_linear_* IDs and their corresponding url(#paint*_linear_*) references with component-scoped IDs:

-        fill="url(`#paint0_linear_13869_15324`)"
+        fill="url(`#logo-full-paint0`)"
@@
-        fill="url(`#paint1_linear_13869_15324`)"
+        fill="url(`#logo-full-paint1`)"
@@
-        fill="url(`#paint2_linear_13869_15324`)"
+        fill="url(`#logo-full-paint2`)"
@@
-          id="paint0_linear_13869_15324"
+          id="logo-full-paint0"
@@
-          id="paint1_linear_13869_15324"
+          id="logo-full-paint1"
@@
-          id="paint2_linear_13869_15324"
+          id="logo-full-paint2"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Icons/LogoFull.tsx` around lines 16 - 63, The SVG uses global
Figma IDs (e.g., paint0_linear_13869_15324, paint1_linear_13869_15324,
paint2_linear_13869_15324) which can collide; rename each <linearGradient> id to
a component-scoped name (for example logo-full-paint0-linear,
logo-full-paint1-linear, logo-full-paint2-linear) and update every corresponding
fill="url(#...)" reference in the <path> elements to match the new IDs, ensuring
all id attributes inside <defs> and their url(#...) usages are changed
consistently within the LogoFull component.
src/app/globals.css (1)

18-26: Orphaned Tailwind v3→v4 border-color compatibility comment.

The comment describes the compatibility styles that keep pre-v4 default border color behavior, but the actual rule it refers to (* { @apply border-border outline-ring/50; }) now lives at lines 278–280. As-is, this comment sits above unrelated declarations (.MarqueeGradient, .gridGradient, scrollbar CSS), which is misleading. Either move it next to the @layer base rule at line 278 or drop it.

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

In `@src/app/globals.css` around lines 18 - 26, The top-of-file Tailwind v3→v4
border-color compatibility comment is orphaned and misleading; move that comment
to sit immediately above the `@layer` base rule that contains the selector with
the compatibility rule (* { `@apply` border-border outline-ring/50; }) so the
comment directly describes the rule, or remove the comment entirely if you
prefer not to document it; update the comment placement near the `@layer`
base/@apply rule in src/app/globals.css and ensure no unrelated declarations
(e.g., .MarqueeGradient, .gridGradient, scrollbar CSS) remain between the
comment and the compatibility rule.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.prettierignore:
- Around line 16-18: Fix the typos in the .prettierignore file patterns: replace
the invalid "*. env" with "*.env" and replace ".env .*" with ".env.*" (keep the
existing ".env" line as well if you want to ignore the exact file); ensure the
three patterns present are ".env", "*.env", and ".env.*" so they correctly match
environment files.

In @.prettierrc:
- Around line 11-23: The importOrder array uses literal space strings (" ") as
group separators which the plugin `@ianvs/prettier-plugin-sort-imports` does not
recognize; replace each " " entry with an empty string "" in the "importOrder"
configuration so the plugin interprets them as blank-line separators between
groups (leave other entries like "^react", "<THIRD_PARTY_MODULES>", "^@/(.*)$",
and "^[./]" unchanged).

In `@AGENTS.md`:
- Around line 1-7: The AGENTS.md currently contains only a Next.js warning and
must be replaced with documented agent implementations and responsibilities:
update AGENTS.md to list each AI agent/assistant used in this repo
(name/identifier), specify for each its concrete responsibilities and tasks,
include configuration/behavioral guidelines (environment variables, rate limits,
retry logic, prompt templates), and add a Next.js-specific subsection under the
relevant agent(s) describing conventions and caveats from the existing Next.js
note; ensure headings like "Agents", "Responsibilities", "Configuration", and
"Next.js guidance" are present so reviewers can quickly find each agent's role
and settings.

In `@components.json`:
- Around line 2-21: components.json contains unsupported keys/values that break
shadcn generation: change "style": "base-mira" to a supported value (e.g.,
"new-york" or remove the key to use default), set "iconLibrary": to a supported
option ("lucide" or "radix"), and remove or relocate non-standard keys "rtl" and
"menuAccent" (delete them from components.json or move them to your own app
config) so the file conforms to the shadcn schema; validate the file after edits
to ensure generation succeeds.

In `@package.json`:
- Around line 22-24: Add an "engines" field to package.json to enforce Node
>=20.9.0 required by Next.js 16; update the root package.json (where "next":
"16.2.4", "react": "19.2.5", "react-dom": "19.2.5" appear) to include an
"engines" object specifying "node": ">=20.9.0" so installs/deploys fail fast on
older Node versions; optionally include an advisory "engines" entry for your
package manager (e.g., "npm" or "pnpm") if you want to be explicit.
- Around line 27-29: Update the tailwind-merge dependency to a v3 release to
ensure compatibility with Tailwind CSS v4; specifically change the
"tailwind-merge" entry in package.json from "^2.6.1" to a v3 range (e.g.
"^3.5.0" or "^3.0.0") and then run your package manager install (npm/yarn/pnpm)
to update lockfiles and verify cn(...) behavior; target the "tailwind-merge"
package name to locate and modify the dependency.

In `@src/app/globals.css`:
- Around line 121-122: The :root CSS custom properties --tracking-normal and
--spacing are not picked up by Tailwind v4 and therefore won’t alter utility
scales; move any intended custom values into the Tailwind theme block (use
`@theme` or `@theme` inline) or mirror them into `@theme` inline (e.g., re-expose
--spacing inside `@theme` inline) so Tailwind reads them, otherwise remove them to
avoid implying a theme override; target the :root declaration that defines
--tracking-normal and --spacing and either relocate their values into the `@theme`
block or add corresponding re-exposure inside `@theme` inline.
- Around line 98-100: Rename the CSS custom property --font-sans-serif to
--font-serif in the root and dark theme declarations so the theme mapping uses a
real serif variable; specifically, change the definitions currently named
--font-sans-serif (e.g., in :root and the .dark block) to --font-serif so the
`@theme` inline mapping that references --font-serif resolves to MuseoModerno;
also update any remaining references that still use --font-sans-serif to the new
--font-serif name.

In `@src/components/Home/Contact.tsx`:
- Around line 22-27: The inputs in the Contact component remove the default
keyboard focus cue via the class "outline-hidden" and don’t provide a
replacement; in src/components/Home/Contact.tsx locate the input elements in the
Contact component and remove or replace "outline-hidden" with visible focus
styles such as adding Tailwind focus-visible utilities (e.g.,
focus-visible:ring-2 focus-visible:ring-offset-1
focus-visible:ring-<brand-color>) so each field shows a clear focus ring when
tabbing; verify by tabbing through the form that each input and the textarea
receive a visible focus indicator.

In `@src/components/Home/Hero.tsx`:
- Around line 30-35: The hero CTA Link currently uses a placeholder href ("#")
which provides no navigation; update the Link (in Hero.tsx) to point to a
meaningful route or make it configurable—either replace href={"#"} with the real
destination (e.g., "/get-started" or "/signup") or accept a prop like ctaHref
and use that value; keep the existing className/buttonVariants usage
(buttonVariants({ size: "lg" })) and ensure the prop default is set if you make
it configurable.
- Around line 48-59: The motion.div wrapper around the Image (the element with
className "relative flex-1 h-full") must provide an explicit mobile height so
Next/Image with fill has a sizing context: change the wrapper's classes to
include a mobile min-height (e.g., replace or augment "h-full" with something
like "min-h-[320px] md:h-[636px]") and keep it "relative"; also add a responsive
sizes prop to the Image component (for example sizes="(max-width: 768px) 100vw,
50vw") to improve loading and responsive behavior.

In `@src/components/Home/TestimonialsMarquee.tsx`:
- Line 5: The prop type is incorrect: `TargetAndTransition` (a target state) was
used for the `controls` prop but `useAnimation()` returns animation controls;
change the prop type to `LegacyAnimationControls` (the type returned by
`useAnimation`) and import it from "motion/react" instead of
`TargetAndTransition`; update any places referencing `controls` (e.g., the prop
on TestimonialsMarquee and the internal call to `useAnimation()`) so the prop
and return types match (`useAnimation(): LegacyAnimationControls` and `controls:
LegacyAnimationControls`).

In `@src/components/shared/FloatButton.tsx`:
- Around line 20-55: The animate sequence in the useEffect (animateButton) can
overlap when isInView flips; fix it by capturing the control objects returned by
each animate(...) call (from animate) and storing them in a local array (or
variable), call control.stop() or control.cancel() on each before starting a new
sequence, and ensure the effect returns a cleanup function that cancels any
in-flight controls when the effect re-runs or unmounts; apply these changes
around the animate calls inside animateButton and the outer useEffect so
animateButton, animate, isInView and the cleanup properly coordinate.

In `@src/components/shared/FullPageCard.tsx`:
- Around line 1-31: Add the "use client" directive at the top of the
FullPageCard component file and improve the close button accessibility: mark the
component as client-side (add "use client") because it uses motion and the
setVisibility state setter, change the Image alt text to a meaningful label
(e.g., "Close" or "Close dialog") and ensure the button has an accessible name
(either via aria-label="Close" on the button or by using a visually hidden
label) so the onClick handler tied to setVisibility remains usable by assistive
tech; update references in this file to FullPageCard, the close button, and the
Image alt accordingly.

In `@src/components/shared/MobileMenu.tsx`:
- Around line 40-46: The SheetTrigger/Button in MobileMenu is an icon-only
control and needs an accessible name; update the SheetTrigger/Button render so
the icon button has an explicit accessible label (e.g., add aria-label or
aria-labelledby) on the Button used in the render prop (referencing
SheetTrigger, Button, MobileMenu, and Menu) so screen readers announce its
purpose (for example aria-label="Open menu" or similar).
- Around line 55-66: The current map renders a SheetClose button inside an
anchor (in the menuItems.map where motion.a is used and itemVariants applied),
producing invalid <a><button/></a> markup; change this by removing the nested
SheetClose and instead use SheetClose's render prop with nativeButton={false} so
the close control renders as the anchor itself—move href, className, animation
props/variants from motion.a into the SheetClose render output (or have
SheetClose render the motion element) so the element returned is a single anchor
that both navigates and closes the sheet.

In `@src/components/shared/NavBar.tsx`:
- Line 54: The MobileMenu component (used as <MobileMenu menuItems={NavLinks}
/>) is rendered on all screen sizes, causing duplicate navigation with the
desktop nav; wrap or modify the MobileMenu render so it is hidden at desktop
breakpoints (e.g., apply a responsive hiding class like "md:hidden" to the
MobileMenu wrapper or its trigger) so MobileMenu only appears on small screens
while the existing desktop nav remains visible at md and above.

In `@src/helpers/constants/index.ts`:
- Around line 19-24: NavLinks defines four hash targets (`#plans`, `#reviews`,
`#faqs`, `#become-a-mentor`) but the landing page lacks matching section IDs; add
corresponding elements with id="plans", id="reviews", id="faqs", and
id="become-a-mentor" in the landing page component (or layout) so the NavLinks
array works correctly — ensure each section is a semantic container (e.g.,
<section> or equivalent in your framework) with readable headings and content,
and verify the IDs exactly match the strings in NavLinks.

In `@tsconfig.json`:
- Line 36: Remove the suspicious include entry "src/components/shared/dw" from
the tsconfig.json includes array (or replace it with the correct intended path),
since it's a non-existent/truncated path; locate the "includes" array that
contains "src/components/shared/dw" and either delete that element or correct it
to the proper directory (e.g., the intended shared component folder) so
TypeScript doesn't carry dead config.

---

Outside diff comments:
In `@src/components/Icons/GrowthMeterIcon.tsx`:
- Around line 1-8: The component GrowthMeterIcon accepts a className prop but
currently ignores it; update the SVG's className to pass the incoming className
through the cn helper (e.g., cn("w-5 h-5 fill-[`#2B2B2B`] stroke-none",
className)) so callers can style the icon; locate the className usage in the
GrowthMeterIcon function and modify the cn(...) invocation to include the
className argument.

In `@src/components/shared/MobileMenu.tsx`:
- Around line 47-53: The Sheet dialog rendered by MobileMenu lacks an accessible
name; inside the SheetContent component (before the motion.div) add a rendered
SheetTitle (and optional SheetDescription) or a visible heading element to
provide a clear accessible name for the modal; import/use the SheetTitle
component (or a semantic <h2> within the MobileMenu component) and ensure it is
placed at the top of the sheet so assistive tech can announce the dialog
(reference SheetContent and the surrounding motion.div/sheetVariants to locate
where to insert the title).

---

Nitpick comments:
In `@AGENTS.md`:
- Around line 3-5: Update the header text to name the specific Next.js release
(e.g., "Next.js 15") instead of "This version", remove the recommendation to
read docs from node_modules (do not reference node_modules/next/dist/docs/), and
replace it with a link or pointer to the official Next.js docs/upgrade guide
(for example the Next.js 15 upgrade guide or https://nextjs.org/docs) so readers
have a stable canonical reference; change the sentence in AGENTS.md (the header
block) to explicitly call out the version and the official docs/upgrade guide
URL.

In `@CLAUDE.md`:
- Line 1: The file currently only references AGENTS.md ("@AGENTS.md"); update
CLAUDE.md to either (a) add a one-paragraph description explaining the file's
purpose and why it exists separately from AGENTS.md, (b) include brief usage
instructions or configuration examples if CLAUDE.md is meant to be an agent
config, and (c) add a short note linking to AGENTS.md (e.g., "See AGENTS.md for
full agent instructions") or consolidate the content into AGENTS.md and remove
the separate file; locate and edit the CLAUDE.md file (the lone symbol
"@AGENTS.md" in the diff) to implement one of these options so the intent and
usage are clear.

In `@src/app/globals.css`:
- Around line 18-26: The top-of-file Tailwind v3→v4 border-color compatibility
comment is orphaned and misleading; move that comment to sit immediately above
the `@layer` base rule that contains the selector with the compatibility rule (* {
`@apply` border-border outline-ring/50; }) so the comment directly describes the
rule, or remove the comment entirely if you prefer not to document it; update
the comment placement near the `@layer` base/@apply rule in src/app/globals.css
and ensure no unrelated declarations (e.g., .MarqueeGradient, .gridGradient,
scrollbar CSS) remain between the comment and the compatibility rule.

In `@src/components/Home/Tracker.tsx`:
- Around line 13-14: The variables ref, isInView and the useInView import are
dead since the FloatButton block (FloatButton component usage) is commented out;
either re-enable the FloatButton usage (restore the commented block that
references ref and isInView) so the hook and ref are used, or remove the unused
ref/const isInView = useInView(ref, { amount: 0.4 }) and the useInView import
from the Tracker component to eliminate dead code and imports (search for ref,
isInView, useInView and the commented FloatButton block to apply one of the two
fixes).

In `@src/components/Icons/LogoFull.tsx`:
- Around line 16-63: The SVG uses global Figma IDs (e.g.,
paint0_linear_13869_15324, paint1_linear_13869_15324, paint2_linear_13869_15324)
which can collide; rename each <linearGradient> id to a component-scoped name
(for example logo-full-paint0-linear, logo-full-paint1-linear,
logo-full-paint2-linear) and update every corresponding fill="url(#...)"
reference in the <path> elements to match the new IDs, ensuring all id
attributes inside <defs> and their url(#...) usages are changed consistently
within the LogoFull component.

In `@src/components/shared/FloatButton.tsx`:
- Line 61: The className template in FloatButton.tsx interpolates
additionalStyles directly, which will render "undefined" if it's not passed;
update the class assembly for the element that uses the additionalStyles
variable so it only includes additionalStyles when defined (e.g., use a
null-coalescing fallback or join/filter pattern) — locate the className string
inside the FloatButton component and replace the raw `${additionalStyles}`
interpolation with a conditional inclusion like additionalStyles ?? '' or a
filtered join of [baseClasses, additionalStyles].filter(Boolean).join(' ').

In `@src/lib/utils.ts`:
- Around line 4-6: The cn helper currently calls clsx with the inputs array
directly; change it to call clsx using a spread of the variadic arguments so it
matches clsx's idiomatic signature and the shadcn/ui reference (i.e., replace
the direct array call in the cn function with a spread of inputs), keeping the
twMerge(clsx(...)) composition intact and ensuring the function still accepts
ClassValue[].
🪄 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: 7585a9e8-abd1-4ae2-bac5-54ac724068de

📥 Commits

Reviewing files that changed from the base of the PR and between 02edb68 and cb8f689.

⛔ Files ignored due to path filters (3)
  • package-lock.json is excluded by !**/package-lock.json
  • public/assets/images/hero-bg.svg is excluded by !**/*.svg
  • public/assets/images/hero-illustration.svg is excluded by !**/*.svg
📒 Files selected for processing (78)
  • .prettierignore
  • .prettierrc
  • AGENTS.md
  • CLAUDE.md
  • components.json
  • eslint.config.mjs
  • next.config.mjs
  • package.json
  • postcss.config.mjs
  • src/app/(root)/(home)/page.tsx
  • src/app/globals.css
  • src/app/layout.tsx
  • src/components/Home/Contact.tsx
  • src/components/Home/Download.tsx
  • src/components/Home/GrowthMeter.tsx
  • src/components/Home/Hero.tsx
  • src/components/Home/Marquee.tsx
  • src/components/Home/Mentor.tsx
  • src/components/Home/Planner.tsx
  • src/components/Home/Testimonals.tsx
  • src/components/Home/TestimonialsMarquee.tsx
  • src/components/Home/Tracker.tsx
  • src/components/Icons/ChatIcon.tsx
  • src/components/Icons/DashboardIcon.tsx
  • src/components/Icons/ErrorBookIcon.tsx
  • src/components/Icons/FacebookIcon.tsx
  • src/components/Icons/GrowthMeter/DailyMotivation.tsx
  • src/components/Icons/GrowthMeter/GamifyLearning.tsx
  • src/components/Icons/GrowthMeter/HealthyCompetetion.tsx
  • src/components/Icons/GrowthMeter/Progress.tsx
  • src/components/Icons/GrowthMeterIcon.tsx
  • src/components/Icons/InstagramIcon.tsx
  • src/components/Icons/LibertyIcon.tsx
  • src/components/Icons/LinkedInIcon.tsx
  • src/components/Icons/Logo.tsx
  • src/components/Icons/LogoFull.tsx
  • src/components/Icons/Mentor/ConnectAnytime.tsx
  • src/components/Icons/Mentor/DiscussProblem.tsx
  • src/components/Icons/Mentor/PersonalizedGuidance.tsx
  • src/components/Icons/Mentor/ValuableInsights.tsx
  • src/components/Icons/Menu.tsx
  • src/components/Icons/Planner/DailyEvaluation.tsx
  • src/components/Icons/Planner/DailyTask.tsx
  • src/components/Icons/Planner/Efficiency.tsx
  • src/components/Icons/Planner/ZeroProcrastination.tsx
  • src/components/Icons/PlannerIcon.tsx
  • src/components/Icons/Questionicon.tsx
  • src/components/Icons/QuizIcon.tsx
  • src/components/Icons/StudyRoomIcon.tsx
  • src/components/Icons/Tracker/Efficiency.tsx
  • src/components/Icons/Tracker/KnowledgeGap.tsx
  • src/components/Icons/Tracker/RevisionFrequency.tsx
  • src/components/Icons/Tracker/Tracking.tsx
  • src/components/Icons/TrackerIcon.tsx
  • src/components/Icons/TwitterIcon.tsx
  • src/components/Icons/WorkshopIcon.tsx
  • src/components/growthMeter/Card.tsx
  • src/components/growthMeter/Main.tsx
  • src/components/growthMeter/progessAnalytics.tsx
  • src/components/illustrations/hero-illustration.tsx
  • src/components/mentor/BentoSection.tsx
  • src/components/mentor/Hero.tsx
  • src/components/mentor/MentorNavbar.tsx
  • src/components/mentor/PerksSection.tsx
  • src/components/shared/FloatButton.tsx
  • src/components/shared/FullPageCard.tsx
  • src/components/shared/MobileMenu.tsx
  • src/components/shared/NavBar.tsx
  • src/components/shared/PricingCard.tsx
  • src/components/shared/Reveal.tsx
  • src/components/shared/RevealImage.tsx
  • src/components/ui/button.tsx
  • src/components/ui/sheet.tsx
  • src/helpers/constants/index.ts
  • src/lib/utils.ts
  • src/utils/cn.ts
  • tailwind.config.ts
  • tsconfig.json
💤 Files with no reviewable changes (2)
  • src/utils/cn.ts
  • tailwind.config.ts

Comment thread .prettierignore
Comment on lines +16 to +18
*. env
.env
.env .* No newline at end of file

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

Fix typos in env ignore patterns.

*. env and .env .* contain embedded spaces and will not match any real files. The intent is presumably *.env and .env.*.

Proposed fix
-*. env
 .env
-.env .*
+.env.*
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.prettierignore around lines 16 - 18, Fix the typos in the .prettierignore
file patterns: replace the invalid "*. env" with "*.env" and replace ".env .*"
with ".env.*" (keep the existing ".env" line as well if you want to ignore the
exact file); ensure the three patterns present are ".env", "*.env", and ".env.*"
so they correctly match environment files.

Comment thread .prettierrc
Comment on lines +11 to +23
"importOrder": [
"^react",
"^next",
" ",
"<THIRD_PARTY_MODULES>",
" ",
"^@/(.*)$",
"^[./]"
],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true,
"importOrderGroupNamespaceSpecifiers": true,
"importOrderCaseInsensitive": true

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

🌐 Web query:

@ianvs/prettier-plugin-sort-imports importOrder empty string separator blank line

💡 Result:

In @ianvs/prettier-plugin-sort-imports, empty strings ("") in the importOrder array act as separators to insert blank lines between import groups. This replaces the removed importOrderSeparation option from previous versions. Example configuration from official docs: { "plugins": ["@ianvs/prettier-plugin-sort-imports"], "importOrder": ["<BUILTIN_MODULES>", "", "<THIRD_PARTY_MODULES>", "", "^[.]"] } This produces output like: import fs from 'fs'; import { debounce, reduce } from 'lodash'; import MyApp from './MyApp'; The maintainer confirmed in GitHub issue #117 that adding blank groups like "" is the intended way to achieve separation between sorted import groups.

Citations:


🏁 Script executed:

# Check if .prettierrc exists and read its content
if [ -f ".prettierrc" ]; then
  cat -n ".prettierrc"
else
  echo ".prettierrc file not found"
fi

Repository: Leadlly/leadlly.in

Length of output: 719


Use empty strings as importOrder separators, not spaces.

@ianvs/prettier-plugin-sort-imports treats an empty string "" as the blank-line separator between groups. A single-space string " " is not a recognized separator and is parsed as a regex group matching a literal space, which won't do what you expect.

Proposed fix
   "importOrder": [
     "^react",
     "^next",
-    " ",
+    "",
     "<THIRD_PARTY_MODULES>",
-    " ",
+    "",
     "^@/(.*)$",
     "^[./]"
   ],
📝 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
"importOrder": [
"^react",
"^next",
" ",
"<THIRD_PARTY_MODULES>",
" ",
"^@/(.*)$",
"^[./]"
],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true,
"importOrderGroupNamespaceSpecifiers": true,
"importOrderCaseInsensitive": true
"importOrder": [
"^react",
"^next",
"",
"<THIRD_PARTY_MODULES>",
"",
"^@/(.*)$",
"^[./]"
],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true,
"importOrderGroupNamespaceSpecifiers": true,
"importOrderCaseInsensitive": true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.prettierrc around lines 11 - 23, The importOrder array uses literal space
strings (" ") as group separators which the plugin
`@ianvs/prettier-plugin-sort-imports` does not recognize; replace each " " entry
with an empty string "" in the "importOrder" configuration so the plugin
interprets them as blank-line separators between groups (leave other entries
like "^react", "<THIRD_PARTY_MODULES>", "^@/(.*)$", and "^[./]" unchanged).

Comment thread AGENTS.md
Comment on lines +1 to +7
<!-- BEGIN:nextjs-agent-rules -->

# This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.

<!-- END:nextjs-agent-rules -->

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

Content doesn't align with coding guidelines.

As per coding guidelines, this file should "Document agent implementations and responsibilities in AGENTS.md file." The current content warns about Next.js breaking changes but doesn't document agent implementations or responsibilities.

Consider restructuring to include:

  • Which AI agents/assistants are used in this repository
  • Their specific responsibilities and tasks
  • Configuration or behavioral guidelines for each agent
  • Next.js-specific guidance can be a subsection within agent responsibilities
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AGENTS.md` around lines 1 - 7, The AGENTS.md currently contains only a
Next.js warning and must be replaced with documented agent implementations and
responsibilities: update AGENTS.md to list each AI agent/assistant used in this
repo (name/identifier), specify for each its concrete responsibilities and
tasks, include configuration/behavioral guidelines (environment variables, rate
limits, retry logic, prompt templates), and add a Next.js-specific subsection
under the relevant agent(s) describing conventions and caveats from the existing
Next.js note; ensure headings like "Agents", "Responsibilities",
"Configuration", and "Next.js guidance" are present so reviewers can quickly
find each agent's role and settings.

Comment thread components.json
Comment on lines 2 to +21
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"style": "base-mira",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/app/globals.css",
"baseColor": "slate",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "hugeicons",
"rtl": false,
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
},
"menuColor": "default",
"menuAccent": "subtle",
"registries": {}

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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Validate components.json against the declared remote JSON schema without modifying the repo.
set -euo pipefail

python - <<'PY'
import json
from urllib.request import urlopen

try:
    import jsonschema
except ImportError:
    raise SystemExit("jsonschema is not installed in this sandbox; install locally or validate in your editor/CI.")

with open("components.json", "r", encoding="utf-8") as f:
    config = json.load(f)

schema_url = config["$schema"]
with urlopen(schema_url) as response:
    schema = json.load(response)

jsonschema.Draft7Validator(schema).validate(config)
print("components.json validates against", schema_url)
PY

Repository: Leadlly/leadlly.in

Length of output: 2644


🏁 Script executed:

fd -t f "schema" --iglob "*schema*" | head -20

Repository: Leadlly/leadlly.in

Length of output: 264


🌐 Web query:

shadcn components.json valid configuration schema baseColor iconLibrary menuColor

💡 Result:

The valid configuration schema for shadcn/ui's components.json is defined at https://ui.shadcn.com/schema.json, which provides IDE validation and autocompletion. Key relevant properties: - $schema: "https://ui.shadcn.com/schema.json" - style: "new-york" (default deprecated) - tailwind.baseColor: Valid values include "neutral", "stone", "zinc", "mauve", "olive", "mist", "taupe", "slate", "gray" (varies slightly by version/docs, but these are explicitly listed in official docs). - iconLibrary: "lucide" or "radix". Defaults to "lucide" for default style, "radix" for new-york style. Used to determine icon library for components. - menuColor: Options include "default", "inverted", "default-translucent", "inverted-translucent". Controls menu color mode (solid/translucent variants). Other common properties: rsc (true/false), tsx (true/false), tailwind.config, tailwind.css, tailwind.cssVariables (true/false), aliases (object with utils, components, ui, etc.), registries (object). Example full config: { "$schema": "https://ui.shadcn.com/schema.json", "style": "new-york", "tailwind": { "baseColor": "neutral", "cssVariables": true }, "iconLibrary": "lucide", "menuColor": "default", "rsc": true, "tsx": true, "aliases": { "components": "@/components", "utils": "@/lib/utils" } } Official docs recommend running npx shadcn@latest init to generate with prompts. Changes to baseColor after init require re-init or manual CSS updates if using cssVariables.

Citations:


🏁 Script executed:

fd -type f --glob "*schema*"

Repository: Leadlly/leadlly.in

Length of output: 232


🏁 Script executed:

grep -r "base-mira" --include="*.json" --include="*.ts" --include="*.tsx" --include="*.js" | head -10

Repository: Leadlly/leadlly.in

Length of output: 101


🏁 Script executed:

cat components.json

Repository: Leadlly/leadlly.in

Length of output: 529


Fix unsupported config values in components.json that will break component generation.

The config references values not in the official shadcn schema:

  • "style": "base-mira" — not a standard style (only "new-york" or default documented)
  • "iconLibrary": "hugeicons" — unsupported; only "lucide" or "radix" are valid
  • "rtl" and "menuAccent" — not documented standard fields

These will cause failures when running shadcn's component generation CLI. Align with supported values or verify against the actual generator your project uses.

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

In `@components.json` around lines 2 - 21, components.json contains unsupported
keys/values that break shadcn generation: change "style": "base-mira" to a
supported value (e.g., "new-york" or remove the key to use default), set
"iconLibrary": to a supported option ("lucide" or "radix"), and remove or
relocate non-standard keys "rtl" and "menuAccent" (delete them from
components.json or move them to your own app config) so the file conforms to the
shadcn schema; validate the file after edits to ensure generation succeeds.

Comment thread package.json
Comment on lines +22 to +24
"next": "16.2.4",
"react": "19.2.5",
"react-dom": "19.2.5",

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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Expect: package.json declares node >=20.9.0, and repo docs/runtime files do not contradict it.
jq '.engines' package.json
fd -a '(^\.nvmrc$|^\.node-version$|package.json$)' -x sh -c 'printf "\n--- %s ---\n" "$1"; sed -n "1,80p" "$1"' sh {}

Repository: Leadlly/leadlly.in

Length of output: 1361


🌐 Web query:

Next.js 16 Node.js minimum version requirement

💡 Result:

Next.js 16 requires Node.js version 20.9.0 or higher. Node.js 18 is no longer supported.

Citations:


Add engines field to enforce Next.js 16's Node.js 20.9.0+ requirement.

Next.js 16 requires Node.js 20.9.0 or newer. Without an engines guard in package.json, installs and deployments on Node 18 or older can fail late in CI or production.

🛠️ Proposed fix
   "private": true,
+  "engines": {
+    "node": ">=20.9.0"
+  },
   "scripts": {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 22 - 24, Add an "engines" field to package.json to
enforce Node >=20.9.0 required by Next.js 16; update the root package.json
(where "next": "16.2.4", "react": "19.2.5", "react-dom": "19.2.5" appear) to
include an "engines" object specifying "node": ">=20.9.0" so installs/deploys
fail fast on older Node versions; optionally include an advisory "engines" entry
for your package manager (e.g., "npm" or "pnpm") if you want to be explicit.

Comment on lines +40 to +46
<SheetTrigger
render={
<Button variant={"ghost"} size={"icon-lg"}>
<Menu />
</Button>
}
/>

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 | 🟠 Major

Add an accessible name to the menu trigger.

The trigger is icon-only, so screen readers may announce it as an unnamed button unless Menu provides its own label.

♿ Proposed fix
       <SheetTrigger
         render={
-          <Button variant={"ghost"} size={"icon-lg"}>
+          <Button variant="ghost" size="icon-lg" aria-label="Open navigation menu">
             <Menu />
           </Button>
         }
       />
📝 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
<SheetTrigger
render={
<Button variant={"ghost"} size={"icon-lg"}>
<Menu />
</Button>
}
/>
<SheetTrigger
render={
<Button variant="ghost" size="icon-lg" aria-label="Open navigation menu">
<Menu />
</Button>
}
/>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/shared/MobileMenu.tsx` around lines 40 - 46, The
SheetTrigger/Button in MobileMenu is an icon-only control and needs an
accessible name; update the SheetTrigger/Button render so the icon button has an
explicit accessible label (e.g., add aria-label or aria-labelledby) on the
Button used in the render prop (referencing SheetTrigger, Button, MobileMenu,
and Menu) so screen readers announce its purpose (for example aria-label="Open
menu" or similar).

Comment on lines 55 to 66
{menuItems.map((item, index) => (
<motion.a
key={item.name}
key={item.href}
href={item.href}
initial="hidden"
animate="visible"
transition={{ delay: index * 0.2, type: "spring", stiffness: 50 }}
variants={itemVariants}
className="mb-8 block text-center text-xl font-semibold text-black/50 hover:text-black focus:text-black"
>
<SheetClose>{item.name}</SheetClose>
<SheetClose>{item.label}</SheetClose>
</motion.a>

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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the MobileMenu.tsx file to understand the context and imports
cat -n src/components/shared/MobileMenu.tsx | head -80

Repository: Leadlly/leadlly.in

Length of output: 2912


🏁 Script executed:

# Check what SheetClose is - find imports and usage
rg "SheetClose|from.*sheet" src/components/shared/MobileMenu.tsx -A 2 -B 2

Repository: Leadlly/leadlly.in

Length of output: 493


🌐 Web query:

Base UI Dialog Close component render API documentation

💡 Result:

The Base UI Dialog Close component render API allows fully customizing the rendered element via the render prop. ## Key Details - Type: ReactElement | ((props: HTMLProps, state: Dialog.Close.State) => ReactElement) | undefined - Description: Accepts a ReactElement or a function that returns the element to render. The function receives props (HTML attributes) and state (including isOpen: boolean). - Default Behavior: Renders a native element. - Related Prop: nativeButton (boolean, default true) - Determines if a native is rendered when using the render prop. Set to false if rendering a non-button element (e.g.,

). ## Example Usage tsx <Dialog.Close render={(htmlProps, state) => ( <button {...htmlProps} className="custom-close"> ×
)} /> The htmlProps includes standard button attributes like onClick (which closes the dialog), disabled, and data attributes like data-disabled. This matches the AlertDialog.Close component as well. Note: Base Web (baseweb.design) uses a different Modal API without a direct "Close" render prop; Base UI (base-ui.com) is the unstyled primitives library with this API.

Citations:


🏁 Script executed:

# Find the sheet component file
fd -t f "sheet\." src/components/ui/

Repository: Leadlly/leadlly.in

Length of output: 89


🏁 Script executed:

# Check the content of the sheet component
cat src/components/ui/sheet.tsx | head -150

Repository: Leadlly/leadlly.in

Length of output: 4580


Avoid rendering a close button inside each link.

SheetClose renders a native <button> by default, creating invalid <a><button>…</button></a> markup. This can also trigger the close action without navigating the link. Use Base UI's render prop with nativeButton={false} to render the close control as the anchor itself.

Proposed fix
           {menuItems.map((item, index) => (
-            <motion.a
+            <SheetClose
               key={item.href}
-              href={item.href}
-              initial="hidden"
-              animate="visible"
-              transition={{ delay: index * 0.2, type: "spring", stiffness: 50 }}
-              variants={itemVariants}
-              className="mb-8 block text-center text-xl font-semibold text-black/50 hover:text-black focus:text-black"
-            >
-              <SheetClose>{item.label}</SheetClose>
-            </motion.a>
+              nativeButton={false}
+              render={(props) => (
+                <motion.a
+                  {...props}
+                  href={item.href}
+                  initial="hidden"
+                  animate="visible"
+                  transition={{ delay: index * 0.2, type: "spring", stiffness: 50 }}
+                  variants={itemVariants}
+                  className="mb-8 block text-center text-xl font-semibold text-black/50 hover:text-black focus:text-black"
+                >
+                  {item.label}
+                </motion.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
{menuItems.map((item, index) => (
<motion.a
key={item.name}
key={item.href}
href={item.href}
initial="hidden"
animate="visible"
transition={{ delay: index * 0.2, type: "spring", stiffness: 50 }}
variants={itemVariants}
className="mb-8 block text-center text-xl font-semibold text-black/50 hover:text-black focus:text-black"
>
<SheetClose>{item.name}</SheetClose>
<SheetClose>{item.label}</SheetClose>
</motion.a>
{menuItems.map((item, index) => (
<SheetClose
key={item.href}
nativeButton={false}
render={(props) => (
<motion.a
{...props}
href={item.href}
initial="hidden"
animate="visible"
transition={{ delay: index * 0.2, type: "spring", stiffness: 50 }}
variants={itemVariants}
className="mb-8 block text-center text-xl font-semibold text-black/50 hover:text-black focus:text-black"
>
{item.label}
</motion.a>
)}
/>
))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/shared/MobileMenu.tsx` around lines 55 - 66, The current map
renders a SheetClose button inside an anchor (in the menuItems.map where
motion.a is used and itemVariants applied), producing invalid <a><button/></a>
markup; change this by removing the nested SheetClose and instead use
SheetClose's render prop with nativeButton={false} so the close control renders
as the anchor itself—move href, className, animation props/variants from
motion.a into the SheetClose render output (or have SheetClose render the motion
element) so the element returned is a single anchor that both navigates and
closes the sheet.

Comment thread src/components/shared/NavBar.tsx Outdated
Comment on lines +19 to +24
export const NavLinks = [
{ label: "Plans", href: "#plans" },
{ label: "Reviews", href: "#reviews" },
{ label: "FAQs", href: "#faqs" },
{ label: "Become a mentor", href: "#become-a-mentor" },
];

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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Compare NavLinks hash hrefs against ids declared in TSX/JSX files.
set -euo pipefail

python - <<'PY'
import re
from pathlib import Path

constants = Path("src/helpers/constants/index.ts").read_text(encoding="utf-8")
hrefs = re.findall(r'href:\s*"([^"]+)"', constants)
hashes = [h[1:] for h in hrefs if h.startswith("#")]

ids = set()
for path in list(Path(".").rglob("*.tsx")) + list(Path(".").rglob("*.jsx")):
    if "node_modules" in path.parts:
        continue
    text = path.read_text(encoding="utf-8", errors="ignore")
    ids.update(re.findall(r'id=["\']([^"\']+)["\']', text))

missing = [target for target in hashes if target not in ids]
print("NavLink hash targets:", hashes)
print("Found ids:", sorted(ids))
if missing:
    raise SystemExit(f"Missing target ids: {missing}")
PY

Repository: Leadlly/leadlly.in

Length of output: 584


Add missing anchor IDs on the landing page to match NavLinks targets.

All four navigation hash targets are missing from the codebase: #plans, #reviews, #faqs, and #become-a-mentor. The navigation will not function until these corresponding sections are added with matching id attributes.

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

In `@src/helpers/constants/index.ts` around lines 19 - 24, NavLinks defines four
hash targets (`#plans`, `#reviews`, `#faqs`, `#become-a-mentor`) but the landing page
lacks matching section IDs; add corresponding elements with id="plans",
id="reviews", id="faqs", and id="become-a-mentor" in the landing page component
(or layout) so the NavLinks array works correctly — ensure each section is a
semantic container (e.g., <section> or equivalent in your framework) with
readable headings and content, and verify the IDs exactly match the strings in
NavLinks.

Comment thread tsconfig.json
"**/*.tsx",
".next/types/**/*.ts",
"src/components/shared/dw"
"src/components/shared/dw",

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

Suspicious include entry: src/components/shared/dw.

This path looks like an accidental/truncated entry (no such directory referenced elsewhere in the PR). TypeScript will silently ignore non-existent includes, but it's dead config. Please remove it or replace with the intended path.

Proposed fix
     ".next/types/**/*.ts",
-    "src/components/shared/dw",
     ".next/dev/types/**/*.ts"
📝 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
"src/components/shared/dw",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tsconfig.json` at line 36, Remove the suspicious include entry
"src/components/shared/dw" from the tsconfig.json includes array (or replace it
with the correct intended path), since it's a non-existent/truncated path;
locate the "includes" array that contains "src/components/shared/dw" and either
delete that element or correct it to the proper directory (e.g., the intended
shared component folder) so TypeScript doesn't carry dead config.

Comment thread .prettierignore
Comment on lines +16 to +18
*. env
.env
.env .* No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Invalid .env ignore patterns due to incorrect spacing. Lines 16 and 18 contain spaces that break the glob patterns (*. env and .env .*), which means .env files and their variants may NOT be properly ignored by Prettier. This creates a security risk where environment files containing sensitive credentials (API keys, database passwords, secrets) might be formatted and accidentally committed to version control.

Confidence: 5/5

Suggested Fix
Suggested change
*. env
.env
.env .*
*.env
.env
.env.*

Remove the spaces in the glob patterns:

  • Line 16: Change *. env to *.env (remove space before .env)
  • Line 18: Change .env .* to .env.* (remove space after .env)
    This ensures all .env files and their variants (.env.local, .env.production, etc.) are properly ignored by Prettier, preventing accidental exposure of sensitive credentials.
Prompt for AI

Copy this prompt to your AI IDE to fix this issue locally:

In .prettierignore at lines 16-18, there are invalid glob patterns for .env files due to incorrect spacing. On line 16, change "*. env" to "*.env" (remove the space between * and .env). On line 18, change ".env .*" to ".env.*" (remove the space between .env and .*). These spaces break the ignore patterns and create a security risk where environment files containing sensitive credentials might not be properly ignored by Prettier, potentially leading to accidental commits of secrets to version control.

📍 This suggestion applies to lines 16-18

@beetle-ai

beetle-ai Bot commented Apr 24, 2026

Copy link
Copy Markdown

Summary by Beetle

This PR introduces a comprehensive refactoring of the home page layout with a focus on creating reusable shared components and improving the overall design system. The changes establish a more maintainable component architecture by extracting common patterns into shared components (Container, SectionContainer, LinkButton) and modernizing the UI with new illustrations and a CSS-based marquee animation system. The refactoring also fixes a CSS variable naming inconsistency (--font-sans-serif--font-serif) and updates multiple sections (Hero, Planner, Marquee) to use the new component structure.

📁 File Changes Summary

File Status Changes Description
src/components/shared/Container.tsx
src/components/shared/SectionContainer.tsx
src/components/shared/LinkButton.tsx
Added +97/-0 New shared component library: Created reusable layout components - Container provides consistent max-width (1440px) wrapper with border/padding, SectionContainer handles section-level spacing, and LinkButton creates styled link buttons with chevron icons and customizable variants
src/components/Home/Hero.tsx
src/components/Home/Planner.tsx
src/components/Home/Marquee.tsx
Modified +274/-149 Home page section refactoring: Migrated to new shared components, replaced custom icons with HugeIcons library, updated Hero illustration path (hero-illustration.svgsvg_5.svg), simplified Planner layout from multi-point grid to focused two-column design, and completely rewrote Marquee with CSS-based infinite scroll animation replacing motion-based implementation
src/app/(root)/(home)/page.tsx Modified +2/-0 Integrated MarqueeList component into home page layout between Planner and Tracker sections
src/app/globals.css Modified +11/-2 Fixed CSS variable naming (--font-sans-serif--font-serif) and added keyframe animation for marquee scroll effect with configurable duration and direction
src/app/layout.tsx
src/components/shared/NavBar.tsx
Modified +5/-4 Updated font variable references to match corrected CSS naming, adjusted NavBar container to use explicit max-width class, and improved mobile menu wrapper structure

Total Changes: 10 files changed, +388 additions, -231 deletions

🗺️ Walkthrough

graph TD
A["Home Page Layout"] --> B["SectionContainer Wrapper"]
B --> C["Container Component"]
C --> D["Content Layout"]
D --> E["Hero Section"]
D --> F["Planner Section"]
D --> G["Marquee Section"]
E --> H["LinkButton Component"]
F --> H
G --> I["CSS Scroll Animation"]
I --> J["Duplicate Items for Loop"]
I --> K["Configurable Speed/Direction"]
L["Global Styles"] --> M["Font Variable Fix"]
M --> N["--font-serif"]
L --> O["Marquee Keyframes"]
O --> P["@keyframes scroll"]
P --> Q["transform: translate"]
R["Shared Components"] --> S["Container Max-width + Border"]
R --> T["SectionContainer Padding Wrapper"]
R --> U["LinkButton Styled Link + Icon"]
style R fill:#e1f5ff
style L fill:#fff4e1
style A fill:#f0e1ff
Loading

🎯 Key Changes

  • Component Architecture Improvement: Introduced three foundational shared components (Container, SectionContainer, LinkButton) that establish consistent spacing, layout patterns, and interactive elements across the application, significantly reducing code duplication
  • CSS Variable Correction: Fixed critical naming inconsistency where --font-sans-serif was incorrectly used for the MuseoModerno serif font; renamed to --font-serif across both light and dark themes
  • Marquee Animation Modernization: Completely rewrote the marquee component from motion-based animation to pure CSS @keyframes with automatic item duplication, configurable speed (fast/normal/slow), direction control, and pause-on-hover functionality
  • Icon Library Migration: Replaced custom SVG icon components with HugeIcons library (@hugeicons/react) in Marquee section, providing consistent iconography and reducing maintenance overhead
  • Layout Simplification: Streamlined Hero and Planner sections by removing complex nested structures, adopting the new shared component system, and focusing on cleaner two-column responsive layouts with improved mobile support
  • Visual Asset Updates: Changed Hero section illustration from hero-illustration.svg to svg_5.svg and updated Planner to use svg_3.svg, suggesting a broader design system refresh
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

Follow us: Beetle · X · LinkedIn

@beetle-ai

beetle-ai Bot commented Apr 24, 2026

Copy link
Copy Markdown

✅ You're good to merge this PR! No issues found. Great job!

Settings
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (3)
src/components/Home/Hero.tsx (2)

33-35: ⚠️ Potential issue | 🟠 Major

Replace the placeholder CTA destination.

href="#" is still a no-op; this was flagged previously and remains in the new code. Point to the real login/signup route (or accept via prop).

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

In `@src/components/Home/Hero.tsx` around lines 33 - 35, The CTA in Hero uses a
placeholder href="#" on the LinkButton which is a no-op; update the LinkButton
in the Hero component to point to the real auth route (e.g., "/login" or
"/signup") or make the target configurable by adding a prop (e.g., ctaHref) to
the Hero component and passing it into LinkButton, replacing the hardcoded
href="#" reference so navigation works correctly.

45-50: ⚠️ Potential issue | 🟡 Minor

Add sizes to the fill image for responsive optimization.

next/image with fill requires a sizes prop to avoid downloading the full-resolution source on every viewport and to silence Next.js's runtime warning. Mobile height is now provided by the parent h-screen md:h-[636px], so only sizes remains.

🛠️ Proposed fix
           <Image
             src="/assets/illustrations/svg_5.svg"
             alt="hero-illustration"
             fill
+            sizes="(min-width: 768px) 50vw, 100vw"
             className="object-contain"
           />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Home/Hero.tsx` around lines 45 - 50, The Image component using
the fill layout (Image) is missing a sizes prop which causes Next.js to download
full-resolution images and emit a runtime warning; add a sizes prop to the Image
element (the one with src "/assets/illustrations/svg_5.svg" and className
"object-contain") that reflects your responsive layout—for example a string like
"(max-width: 767px) 100vw, 50vw" or "(max-width: 768px) 100vw, 768px"—so the
browser requests appropriately sized images and the Next.js warning is
suppressed.
src/app/globals.css (1)

121-122: ⚠️ Potential issue | 🟡 Minor

--tracking-normal and --spacing under :root still don't feed Tailwind v4's theme.

Tailwind v4 only reads tokens declared inside @theme / @theme inline. These two variables remain under :root and are not mirrored into the @theme inline block, so they don't customize any utility scale. Either move them into @theme (or mirror --spacing: var(--spacing); inside @theme inline) or remove them.

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

In `@src/app/globals.css` around lines 121 - 122, The CSS variables
--tracking-normal and --spacing are defined under :root but Tailwind v4 only
reads tokens inside `@theme` / `@theme` inline, so mirror or move them into the
theme block; update the file by placing --tracking-normal and --spacing inside
the existing `@theme` inline (or move them from :root into `@theme`) so they feed
Tailwind's theme tokens (refer to the :root declaration and the `@theme` inline
block when making the change).
🧹 Nitpick comments (2)
src/components/shared/LinkButton.tsx (2)

43-53: Mark the decorative chevron icon as aria-hidden.

The chevron is purely decorative (the link text already communicates intent), but the wrapper <span> and the icon are both exposed to assistive tech. Add aria-hidden="true" to avoid duplicate/noisy announcements.

♿ Proposed fix
       <span
+        aria-hidden="true"
         className={cn(
           "size-10 bg-white/65 flex items-center justify-center rounded-full",
           iconContainerClassName,
         )}
       >
         <HugeiconsIcon
           icon={ChevronRight}
           className={cn("text-primary-foreground size-6", iconClassName)}
         />
       </span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/shared/LinkButton.tsx` around lines 43 - 53, The decorative
chevron in LinkButton.tsx is currently exposed to assistive tech; update the
span wrapper (the one rendering the chevron) and/or the HugeiconsIcon usage
(icon={ChevronRight}) to include aria-hidden="true" so the chevron is not
announced by screen readers; ensure you add the attribute to the span or the
HugeiconsIcon props (where HugeiconsIcon accepts passthrough attributes) so the
decorative icon is ignored by AT.

34-38: Height is hard-coded — size prop effectively has no effect on height.

buttonVariants({ size }) emits an h-* class, but the component immediately appends h-14, which wins via Tailwind's last-class-wins merge through cn. Any consumer passing size="sm" / size="lg" will see no height change. Consider either dropping the size prop from the public API (since this is a fixed-size CTA) or removing the hard-coded h-14/text-* so size actually takes effect.

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

In `@src/components/shared/LinkButton.tsx` around lines 34 - 38, The LinkButton
component currently overrides the size-controlled height by appending the
hard-coded "h-14" and text classes after buttonVariants({ size, variant }), so
pass-through size has no effect; to fix, remove the hard-coded "h-14" and
related "text-*" class modifiers from the className composition in
LinkButton.tsx so buttonVariants({ size }) can control height and text sizing,
or alternatively remove the size prop from the LinkButton public API and update
usages and types to reflect a fixed-size CTA (adjust buttonVariants calls and
prop definitions accordingly); reference the LinkButton component, the size
prop, and buttonVariants to locate where to change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/Home/Hero.tsx`:
- Line 18: Replace the rigid h-screen on the hero Container with a responsive
minimum/explicit height so the section doesn’t overflow when the parent adds top
padding; in src/components/Home/Hero.tsx target the Container element and swap
the h-screen class for a mobile-safe height such as min-h-[calc(100svh-9rem)]
(or an explicit mobile height like h-[520px]) while keeping md:h-[636px], so
mobile uses the calculated min-height and desktop retains the fixed md height.

In `@src/components/Home/Marquee.tsx`:
- Around line 180-198: The addAnimation effect currently clones and appends
children every time getDirection or getSpeed changes, causing exponential
duplication; modify the logic in the useEffect that calls addAnimation to run
the cloning step only once by introducing a guard (e.g., a ref like
hasClonedRef) or split responsibilities into two effects so that cloning of
scrollerRef.children (inside addAnimation) happens only when the component
mounts, while getDirection/getSpeed and setStart remain in a separate effect
triggered by their callbacks; reference addAnimation, containerRef, scrollerRef,
getDirection, getSpeed, and setStart when making the change.
- Around line 204-214: In the Marquee component update the Tailwind class
conditional that uses the non-existent "hover:paused" utility: inside the ul's
className cn call (where you currently have start && "animate-scroll",
pauseOnHover && "hover:paused") replace the "hover:paused" string with the
arbitrary-property variant "hover:[animation-play-state:paused]" so the
pauseOnHover branch applies a valid Tailwind hover animation-play-state; this
change is in the same cn call that references scrollerRef and the
"animate-scroll" class.

---

Duplicate comments:
In `@src/app/globals.css`:
- Around line 121-122: The CSS variables --tracking-normal and --spacing are
defined under :root but Tailwind v4 only reads tokens inside `@theme` / `@theme`
inline, so mirror or move them into the theme block; update the file by placing
--tracking-normal and --spacing inside the existing `@theme` inline (or move them
from :root into `@theme`) so they feed Tailwind's theme tokens (refer to the :root
declaration and the `@theme` inline block when making the change).

In `@src/components/Home/Hero.tsx`:
- Around line 33-35: The CTA in Hero uses a placeholder href="#" on the
LinkButton which is a no-op; update the LinkButton in the Hero component to
point to the real auth route (e.g., "/login" or "/signup") or make the target
configurable by adding a prop (e.g., ctaHref) to the Hero component and passing
it into LinkButton, replacing the hardcoded href="#" reference so navigation
works correctly.
- Around line 45-50: The Image component using the fill layout (Image) is
missing a sizes prop which causes Next.js to download full-resolution images and
emit a runtime warning; add a sizes prop to the Image element (the one with src
"/assets/illustrations/svg_5.svg" and className "object-contain") that reflects
your responsive layout—for example a string like "(max-width: 767px) 100vw,
50vw" or "(max-width: 768px) 100vw, 768px"—so the browser requests appropriately
sized images and the Next.js warning is suppressed.

---

Nitpick comments:
In `@src/components/shared/LinkButton.tsx`:
- Around line 43-53: The decorative chevron in LinkButton.tsx is currently
exposed to assistive tech; update the span wrapper (the one rendering the
chevron) and/or the HugeiconsIcon usage (icon={ChevronRight}) to include
aria-hidden="true" so the chevron is not announced by screen readers; ensure you
add the attribute to the span or the HugeiconsIcon props (where HugeiconsIcon
accepts passthrough attributes) so the decorative icon is ignored by AT.
- Around line 34-38: The LinkButton component currently overrides the
size-controlled height by appending the hard-coded "h-14" and text classes after
buttonVariants({ size, variant }), so pass-through size has no effect; to fix,
remove the hard-coded "h-14" and related "text-*" class modifiers from the
className composition in LinkButton.tsx so buttonVariants({ size }) can control
height and text sizing, or alternatively remove the size prop from the
LinkButton public API and update usages and types to reflect a fixed-size CTA
(adjust buttonVariants calls and prop definitions accordingly); reference the
LinkButton component, the size prop, and buttonVariants to locate where to
change.
🪄 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: aa392314-3499-4b7f-8d58-bd3d57e48b23

📥 Commits

Reviewing files that changed from the base of the PR and between cb8f689 and 5edcb96.

⛔ Files ignored due to path filters (6)
  • public/assets/illustrations/svg_1.svg is excluded by !**/*.svg
  • public/assets/illustrations/svg_2.svg is excluded by !**/*.svg
  • public/assets/illustrations/svg_3.svg is excluded by !**/*.svg
  • public/assets/illustrations/svg_4.svg is excluded by !**/*.svg
  • public/assets/illustrations/svg_5.svg is excluded by !**/*.svg
  • public/assets/illustrations/svg_6.svg is excluded by !**/*.svg
📒 Files selected for processing (10)
  • src/app/(root)/(home)/page.tsx
  • src/app/globals.css
  • src/app/layout.tsx
  • src/components/Home/Hero.tsx
  • src/components/Home/Marquee.tsx
  • src/components/Home/Planner.tsx
  • src/components/shared/Container.tsx
  • src/components/shared/LinkButton.tsx
  • src/components/shared/NavBar.tsx
  • src/components/shared/SectionContainer.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/components/shared/SectionContainer.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/app/(root)/(home)/page.tsx
  • src/components/Home/Planner.tsx
  • src/app/layout.tsx

Say goodbye to one-size-fits-all! We tailor study plans and
resources to your individual learning style and goals.
<SectionContainer className="relative pt-36">
<Container className="h-screen md:h-[636px] bg-[url(/assets/images/hero-bg.svg)] bg-no-repeat bg-size-[auto_300px] md:bg-size-[auto_493px] bg-left flex flex-col md:flex-row items-center justify-between gap-5">

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

h-screen on the hero container may cause overflow/viewport issues on mobile.

Combining h-screen with pt-36 on the section means the hero is forced to exactly 100vh while still getting 9rem top padding from the section, pushing content below the fold and likely clipping the CTA on shorter mobile viewports (and mobile browsers that don't account for URL bar). Consider min-h-[calc(100svh-9rem)] or an explicit mobile height that matches the content, similar to the md:h-[636px] fixed value used on desktop.

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

In `@src/components/Home/Hero.tsx` at line 18, Replace the rigid h-screen on the
hero Container with a responsive minimum/explicit height so the section doesn’t
overflow when the parent adds top padding; in src/components/Home/Hero.tsx
target the Container element and swap the h-screen class for a mobile-safe
height such as min-h-[calc(100svh-9rem)] (or an explicit mobile height like
h-[520px]) while keeping md:h-[636px], so mobile uses the calculated min-height
and desktop retains the fixed md height.

Comment on lines +180 to +198
useEffect(() => {
function addAnimation() {
if (containerRef.current && scrollerRef.current) {
const scrollerContent = Array.from(scrollerRef.current.children);

scrollerContent.forEach((item) => {
const duplicatedItem = item.cloneNode(true);
if (scrollerRef.current) {
scrollerRef.current.appendChild(duplicatedItem);
}
});

getDirection();
getSpeed();
setStart(true);
}
}
addAnimation();
}, [getDirection, getSpeed]);

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 | 🟠 Major

Children are duplicated on every direction/speed change, compounding indefinitely.

addAnimation unconditionally clones every current child and appends them to the scroller. Because getDirection/getSpeed are wrapped in useCallback with direction/speed deps, they get new identities whenever those props change, which re-runs the effect and appends another full copy of the children. Use a ref/guard so the clone step runs only once (or split direction/speed into a separate effect).

🛠️ Proposed fix
+  const hasCloned = React.useRef(false);
+
   useEffect(() => {
     function addAnimation() {
-      if (containerRef.current && scrollerRef.current) {
+      if (!hasCloned.current && containerRef.current && scrollerRef.current) {
         const scrollerContent = Array.from(scrollerRef.current.children);

         scrollerContent.forEach((item) => {
           const duplicatedItem = item.cloneNode(true);
           if (scrollerRef.current) {
             scrollerRef.current.appendChild(duplicatedItem);
           }
         });
-
-        getDirection();
-        getSpeed();
-        setStart(true);
+        hasCloned.current = true;
+        setStart(true);
       }
+      getDirection();
+      getSpeed();
     }
     addAnimation();
   }, [getDirection, getSpeed]);
📝 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
useEffect(() => {
function addAnimation() {
if (containerRef.current && scrollerRef.current) {
const scrollerContent = Array.from(scrollerRef.current.children);
scrollerContent.forEach((item) => {
const duplicatedItem = item.cloneNode(true);
if (scrollerRef.current) {
scrollerRef.current.appendChild(duplicatedItem);
}
});
getDirection();
getSpeed();
setStart(true);
}
}
addAnimation();
}, [getDirection, getSpeed]);
const hasCloned = React.useRef(false);
useEffect(() => {
function addAnimation() {
if (!hasCloned.current && containerRef.current && scrollerRef.current) {
const scrollerContent = Array.from(scrollerRef.current.children);
scrollerContent.forEach((item) => {
const duplicatedItem = item.cloneNode(true);
if (scrollerRef.current) {
scrollerRef.current.appendChild(duplicatedItem);
}
});
hasCloned.current = true;
setStart(true);
}
getDirection();
getSpeed();
}
addAnimation();
}, [getDirection, getSpeed]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Home/Marquee.tsx` around lines 180 - 198, The addAnimation
effect currently clones and appends children every time getDirection or getSpeed
changes, causing exponential duplication; modify the logic in the useEffect that
calls addAnimation to run the cloning step only once by introducing a guard
(e.g., a ref like hasClonedRef) or split responsibilities into two effects so
that cloning of scrollerRef.children (inside addAnimation) happens only when the
component mounts, while getDirection/getSpeed and setStart remain in a separate
effect triggered by their callbacks; reference addAnimation, containerRef,
scrollerRef, getDirection, getSpeed, and setStart when making the change.

Comment on lines +204 to +214
"scroller relative z-20 overflow-hidden mask-[linear-gradient(to_right,transparent,white_20%,white_80%,transparent)]",
className,
)}
>
{" "}
{items.map((item, index) => (
<div
key={index}
className="flex flex-grow items-center gap-3 md:gap-5 pr-14 md:pr-20"
>
<div className="size-5">
<item.icon className="size-full stroke-[#2B2B2B]" />
</div>
<span className="font-medium text-xl text-[#2B2B2B] text-nowrap">
{item.label}
</span>
</div>
))}
</motion.div>
<ul
ref={scrollerRef}
className={cn(
"flex w-max min-w-full shrink-0 flex-nowrap gap-4 py-4",
start && "animate-scroll",
pauseOnHover && "hover:paused",
)}

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

🌐 Web query:

Tailwind CSS v4 mask-[] arbitrary value utility and paused animation-play-state utility support

💡 Result:

Tailwind CSS v4 mask-[] arbitrary value utility and paused animation-play-state utility support 1) mask-[] arbitrary values (Tailwind v4) - Yes. Tailwind provides mask-image utilities that support arbitrary values using bracket syntax. - The official mask-image docs show “Use the mask-[] syntax to set the mask image of an element” and give the custom-value example via mask-linear-[…]. Example: mask-linear-[70deg,transparent_10%,black,transparent_80%] - Tailwind also documents a dedicated API (mask--from-/mask--to- etc.) specifically for gradients/side masking, and notes that arbitrary mask-* utilities can override the entire mask-image definition. 2) animation-play-state paused utility (Tailwind v4) - Tailwind core does not expose a built-in animation-play-state: paused utility (e.g., there is no documented/standard animation-play-state: paused utility in Tailwind’s official v4 docs for animation). - The Tailwind team has community discussions proposing animation-play-state utilities (running/paused), implying it’s not part of the core set. - Workarounds: use bracket arbitrary property syntax to directly set the property, or define a custom utility in your Tailwind CSS. - Bracket form example: [animation-play-state:paused] (and then combine with variants like hover:…) is commonly used. - Custom utility example: define an @utility or utility class that sets animation-play-state: paused; then use it with variants. - Note: third-party Tailwind plugins exist that provide running/paused/play-state-* utilities, but those are not Tailwind core. Answer summary - mask-[] arbitrary value utilities: supported in Tailwind v4 via mask-image “mask-[]” / mask-linear-[…] syntax. - animation-play-state paused utility: not present as a built-in Tailwind v4 core utility; use arbitrary property syntax or define your own / use a plugin.

Citations:


Use hover:[animation-play-state:paused] instead of hover:paused.

The hover:paused utility doesn't exist in Tailwind v4. While mask-[linear-gradient(...)] is a valid arbitrary-value utility, the animation play-state variant is not part of Tailwind's core utilities. Use the arbitrary property syntax: hover:[animation-play-state:paused].

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

In `@src/components/Home/Marquee.tsx` around lines 204 - 214, In the Marquee
component update the Tailwind class conditional that uses the non-existent
"hover:paused" utility: inside the ul's className cn call (where you currently
have start && "animate-scroll", pauseOnHover && "hover:paused") replace the
"hover:paused" string with the arbitrary-property variant
"hover:[animation-play-state:paused]" so the pauseOnHover branch applies a valid
Tailwind hover animation-play-state; this change is in the same cn call that
references scrollerRef and the "animate-scroll" class.

@beetle-ai

beetle-ai Bot commented Apr 25, 2026

Copy link
Copy Markdown

Summary by Beetle

This PR introduces a comprehensive redesign of the Tracker component with a modern, visually striking layout featuring custom SVG-based card shapes and enhanced animation capabilities. The changes transform a simple progress tracking display into an engaging, multi-section feature showcase that emphasizes student execution and structured learning. The component now uses a sophisticated layout with custom-shaped SVG cards (stepped L-shapes and tabbed rectangles) to present key value propositions about mentorship, progress tracking, and revision timing.

📁 File Changes Summary (Consolidated across all commits):

File Status Changes Description
src/components/Home/Tracker.tsx Modified +183/-76 Complete redesign of the Tracker component: replaced simple image-based layout with custom SVG card components (TopCard, BottomCard) featuring unique geometric shapes; introduced new messaging focused on "execution over potential"; added three feature cards highlighting mentorship, progress tracking, and revision timing; integrated new background illustration and responsive grid layout
src/components/shared/Reveal.tsx Modified +3/-0 Enhanced the Reveal animation component by adding optional className prop for additional styling flexibility, enabling better integration with the new SVG-based card layouts

Total Changes: 2 files changed, +186 additions, -76 deletions

🗺️ Walkthrough:

graph TD
A["Tracker Component"] --> B["SectionContainer with Background"]
B --> C["Top Section: Flex Layout"]
B --> D["Bottom Section: Grid Layout"]
C --> E["Left: Heading Block"]
C --> F["Right: TopCard SVG"]
E --> E1["Reveal: Main Heading"]
E --> E2["Reveal: Subheading"]
F --> F1["Custom Stepped L-Shape"]
F1 --> F2["Speech Bubble Content"]
F1 --> F3["Title + Arrow Button"]
D --> G["Feature Card 1"]
D --> H["Feature Card 2"]
D --> I["Feature Card 3"]
G --> G1["BottomCard SVG"]
H --> H1["BottomCard SVG"]
I --> I1["BottomCard SVG"]
G1 --> G2["Tabbed Rectangle Shape"]
G2 --> G3["Title + Description"]
G2 --> G4["Arrow Button in Tab"]
J["Reveal Component"] -.->|"Wraps all animated elements"| E1
J -.->|"Enhanced with className prop"| E2
J -.->|"Staggered delays"| F
J -.->|"Cascade animation"| G
style A fill:#4F46E5,stroke:#312E81,color:#fff
style F1 fill:#7C3AED,stroke:#5B21B6,color:#fff
style G2 fill:#7C3AED,stroke:#5B21B6,color:#fff
style J fill:#10B981,stroke:#047857,color:#fff
Loading

🎯 Key Changes:

  • Complete UI Overhaul: Transformed from a simple image-and-text layout to a sophisticated SVG-based card system with custom geometric shapes (stepped L-shapes and tabbed rectangles)
  • Custom SVG Components: Introduced TopCard and BottomCard components that use SVG clipPath to create unique, non-rectangular card shapes with rounded corners and stepped edges
  • New Messaging Strategy: Shifted focus from "Never lose track of your progress" to "You don't lack potential, You lack execution" - a more motivational and action-oriented approach
  • Feature Showcase: Added three distinct feature cards highlighting:
  • Mentorship from experienced exam-clearers
  • Visible and trustworthy progress tracking
  • Intelligent revision timing
  • Enhanced Animation System: Leveraged the improved Reveal component with staggered delays (0.15s, 0.25s, 0.4s+) to create a cascading reveal effect across all elements
  • Responsive Design: Implemented mobile-first responsive layout using Tailwind's grid system (1 column → 2 columns → 3 columns) with appropriate spacing adjustments
  • Visual Hierarchy: Added background illustration (svg_7.svg), custom button components with arrow icons, and a cohesive color scheme using primary/foreground color tokens
  • Code Modernization: Removed legacy mobile/desktop conditional rendering in favor of responsive CSS classes; eliminated unused imports and simplified component structure
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

Follow us: Beetle · X · LinkedIn

@beetle-ai

beetle-ai Bot commented Apr 25, 2026

Copy link
Copy Markdown

✅ You're good to merge this PR! No issues found. Great job!

Settings
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/components/shared/Reveal.tsx (1)

27-33: Minor: else branch is effectively dead with once: true.

Since useInView is now { once: true }, isInView transitions from falsetrue and never back. Combined with initial="hidden" on the motion.div (Line 57), the controls.start("hidden") call only runs on initial mount and is redundant. You can simplify to:

♻️ Proposed simplification
   useEffect(() => {
     if (isInView) {
       controls.start("visible");
-    } else {
-      controls.start("hidden");
     }
-  }, [isInView, controls]);
+  }, [isInView, controls]);

Not a functional bug — just removes a no-op path now that the viewport trigger fires only once.

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

In `@src/components/shared/Reveal.tsx` around lines 27 - 33, The useEffect
currently toggles controls between "visible" and "hidden" based on isInView, but
with useInView configured as { once: true } and motion.div already using
initial="hidden", the else branch is redundant; simplify by removing the else
branch and only call controls.start("visible") when isInView is true (update the
useEffect referencing isInView and controls), leaving the initial="hidden" on
the motion.div to handle the initial state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/components/shared/Reveal.tsx`:
- Around line 27-33: The useEffect currently toggles controls between "visible"
and "hidden" based on isInView, but with useInView configured as { once: true }
and motion.div already using initial="hidden", the else branch is redundant;
simplify by removing the else branch and only call controls.start("visible")
when isInView is true (update the useEffect referencing isInView and controls),
leaving the initial="hidden" on the motion.div to handle the initial state.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c3a211b5-d027-4a4e-a5d9-cadc9b47ea47

📥 Commits

Reviewing files that changed from the base of the PR and between 5edcb96 and e83f03b.

⛔ Files ignored due to path filters (1)
  • public/assets/illustrations/svg_7.svg is excluded by !**/*.svg
📒 Files selected for processing (2)
  • src/components/Home/Tracker.tsx
  • src/components/shared/Reveal.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/Home/Tracker.tsx

@beetle-ai

beetle-ai Bot commented Apr 27, 2026

Copy link
Copy Markdown

Summary by Beetle

This PR implements a comprehensive redesign of the features section on the home page, transforming the presentation of key product features (Growth Meter, Mentor, Planner, Tracker) with modern animations, improved layouts, and enhanced visual hierarchy. The changes focus on creating a more engaging user experience through refined component architecture, reusable animation utilities, and responsive design patterns.

📁 File Changes Summary

File Status Changes Description
src/components/Home/GrowthMeter.tsx Modified +71/-88 Complete redesign from progress visualization to execution-focused messaging. Replaced growth meter imagery with "Stop Planning, Start Executing" theme, featuring a bullet-point list of core features (Daily Study Structure, Smart Revision System, Progress Tracking, IITian/GMCian Mentorship) and a new bottom section emphasizing system-based approach over motivation.
src/components/Home/Mentor.tsx Modified +125/-77 Transformed from static mentor showcase to interactive feature carousel. Implemented tabbed interface with 5 feature categories (Mentorship, Personalized Curriculum, Adaptive Quizzes, Daily Task Planning, Error Book) with animated transitions, expandable descriptions, and synchronized mockup displays. Added dark theme background with backdrop blur effects.
src/components/Home/Hero.tsx
src/components/Home/Planner.tsx
Modified +13/-45 Refactored to use new ImageAnimation component, removing duplicate animation logic. Simplified component structure while maintaining visual consistency. Planner component also received minor layout adjustments for better overflow handling.
src/components/Home/Tracker.tsx Modified +3/-7 Cleaned up Reveal component usage by removing deprecated motionDivClass prop and improved grid layout with place-items-center for better card alignment.
src/components/shared/ImageAnimation.tsx Added +44/-0 New reusable component for image fade-in animations with blur effects. Implements useAnimate and useInView hooks for viewport-triggered animations, reducing code duplication across feature sections.
src/components/shared/Reveal.tsx Modified +22/-47 Major refactor simplifying the animation API. Removed width and motionDivClass props, switched from useAnimation to useAnimate hook for better performance, and streamlined the component interface while maintaining backward compatibility.
src/components/shared/Container.tsx
src/components/shared/PricingCard.tsx
Modified +2/-2 Minor adjustments: Container padding reduced from p-8 to p-4 on mobile for better spacing, and PricingCard cleaned up to remove deprecated motionDivClass prop.

Total Changes: 9 files changed, +286 additions, -288 deletions

🗺️ Walkthrough

graph TD
A["Home Page Features Section"] --> B["GrowthMeter Component"]
A --> C["Mentor Component"]
A --> D["Hero & Planner Components"]
A --> E["Tracker Component"]
B --> F["ImageAnimation Component"]
C --> F
D --> F
B --> G["Reveal Component"]
C --> G
D --> G
E --> G
F --> H["useAnimate Hook"]
F --> I["useInView Hook"]
G --> H
G --> I
B --> J["New: Execution-Focused Layout"]
J --> K["Feature List with Icons"]
J --> L["System-Based Messaging"]
C --> M["New: Interactive Feature Tabs"]
M --> N["5 Feature Categories"]
M --> O["Animated Mockup Display"]
M --> P["Expandable Descriptions"]
style F fill:#4ade80,stroke:#22c55e,stroke-width:3px
style G fill:#4ade80,stroke:#22c55e,stroke-width:3px
style J fill:#60a5fa,stroke:#3b82f6,stroke-width:2px
style M fill:#60a5fa,stroke:#3b82f6,stroke-width:2px
Loading

🎯 Key Changes

  • Component Architecture Improvement: Introduced ImageAnimation component to centralize image animation logic, eliminating code duplication across Hero, Planner, GrowthMeter, and other feature sections
  • Reveal Component Refactor: Simplified animation API by removing width and motionDivClass props, migrating from useAnimation to useAnimate hook for better performance and cleaner implementation
  • GrowthMeter Redesign: Complete content transformation from progress tracking visualization to execution-focused messaging with structured feature list and system-based approach emphasis
  • Interactive Mentor Section: Converted static mentor showcase into dynamic feature carousel with 5 interactive tabs, animated transitions using Framer Motion's AnimatePresence, and synchronized mockup displays
  • Enhanced User Experience: Implemented viewport-triggered animations with blur effects, improved responsive layouts with better mobile padding, and added backdrop blur effects for modern glass-morphism design
  • Code Quality: Reduced overall line count while adding functionality, improved component reusability, and established consistent animation patterns across the features section
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

Follow us: Beetle · X · LinkedIn

@beetle-ai

beetle-ai Bot commented Apr 27, 2026

Copy link
Copy Markdown

✅ You're good to merge this PR! No issues found. Great job!

Settings
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
src/components/shared/ImageAnimation.tsx (1)

39-39: Add a sizes prop for next/image with fill.

In Next.js 16.2.4, when using fill without sizes, the browser defaults to assuming 100vw width, causing unnecessarily large images to be downloaded, especially if the image renders smaller than full viewport width. Without sizes, Next.js generates a limited srcset (e.g., 1x, 2x) rather than a full responsive srcset, reducing optimization benefits.

📦 Suggested fix
 const ImageAnimation = ({
   src,
   className,
   alt,
+  sizes = "(min-width: 768px) 50vw, 100vw",
 }: {
   src: string;
   className?: string;
   alt: string;
+  sizes?: string;
 }) => {
 ...
-      <Image src={src} alt={alt} fill className={cn("object-contain")} />
+      <Image
+        src={src}
+        alt={alt}
+        fill
+        sizes={sizes}
+        className={cn("object-contain")}
+      />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/shared/ImageAnimation.tsx` at line 39, The Image with fill is
missing a sizes prop which causes the browser to assume 100vw and download
oversized images; update the <Image src={src} alt={alt} fill
className={cn("object-contain")} /> usage in ImageAnimation to include a
suitable sizes prop (for example sizes="100vw" or a more accurate responsive
expression like sizes="(max-width: 768px) 100vw, 50vw") so the generated srcset
is optimized; ensure you add the sizes prop alongside src/alt/fill/className on
the Image component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/Home/GrowthMeter.tsx`:
- Around line 52-55: The CTA currently uses a placeholder href="#" in the Reveal
> LinkButton block (component LinkButton) which prevents navigation; update the
LinkButton's href to a real route or URL (for example "/start-planning" or the
app's planning route constant) or wire it to the appropriate navigation
handler/prop if LinkButton expects one, ensuring the Reveal > LinkButton
invocation navigates to the intended planning page instead of "#".

In `@src/components/Home/Mentor.tsx`:
- Around line 87-102: The conditional motion.p that renders item.description
uses an exit animation but is unmounted immediately; wrap the {item ===
activeIndex && ( ... )} block in <AnimatePresence initial={false} mode="wait">
so the exit animation can run, ensure AnimatePresence is imported from
"framer-motion", and keep the key on motion.p (key={`desc-${idx}`}) so
AnimatePresence can track the element.
- Around line 56-70: The list item currently uses motion.li with onClick (in
Mentor.tsx, the motion.li that calls setActiveIndex and compares item ===
activeIndex), which is not keyboard accessible; replace the clickable surface
with a real control (e.g., use motion.button or render a <button type="button">
inside the motion.li) or at minimum add tabIndex, role, and key handlers so
Enter/Space activate setActiveIndex and manage aria attributes (aria-pressed or
aria-selected) to reflect activeIndex; ensure focus styles remain and keep the
existing layout/animation props on the motion element so keyboard users can
toggle items the same way as mouse users.

In `@src/components/Home/Planner.tsx`:
- Around line 27-29: The primary CTA LinkButton currently uses a placeholder
href (href="/#") which keeps users on the same page; update the LinkButton
instance in Planner.tsx to point to a real route (for example "/signup",
"/pricing", or the onboarding path your app uses) or wire it to a prop/route
constant so it navigates correctly; locate the LinkButton JSX in the Planner
component (the element with props href and className="h-11 md:h-14 pl-5") and
replace the placeholder href with the appropriate real destination or a
reference to a route constant/prop.

In `@src/components/Home/Tracker.tsx`:
- Around line 69-80: The decorative Button controls inside the SVG foreignObject
are currently focusable but do nothing; replace those Button components (the
ones wrapping HugeiconsIcon / ArrowDownRightIcon) with non-interactive elements
(e.g., a div or span) so keyboard users won't tab to them, preserve the existing
className styling, and mark them as decorative by adding aria-hidden="true" (or
role="img" + an accessible name if they convey meaning). Update both occurrences
that wrap HugeiconsIcon (the ArrowDownRightIcon instances) and remove any
button-specific props so the elements are not focusable.

---

Nitpick comments:
In `@src/components/shared/ImageAnimation.tsx`:
- Line 39: The Image with fill is missing a sizes prop which causes the browser
to assume 100vw and download oversized images; update the <Image src={src}
alt={alt} fill className={cn("object-contain")} /> usage in ImageAnimation to
include a suitable sizes prop (for example sizes="100vw" or a more accurate
responsive expression like sizes="(max-width: 768px) 100vw, 50vw") so the
generated srcset is optimized; ensure you add the sizes prop alongside
src/alt/fill/className on the Image component.
🪄 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: 139a6d08-ebf8-49d3-b377-f5aada05c8d6

📥 Commits

Reviewing files that changed from the base of the PR and between e83f03b and 4a4daf3.

⛔ Files ignored due to path filters (6)
  • public/assets/illustrations/mockup_1.svg is excluded by !**/*.svg
  • public/assets/illustrations/mockup_2.svg is excluded by !**/*.svg
  • public/assets/illustrations/mockup_3.svg is excluded by !**/*.svg
  • public/assets/illustrations/mockup_4.svg is excluded by !**/*.svg
  • public/assets/illustrations/mockup_5.svg is excluded by !**/*.svg
  • public/assets/illustrations/svg_8.svg is excluded by !**/*.svg
📒 Files selected for processing (9)
  • src/components/Home/GrowthMeter.tsx
  • src/components/Home/Hero.tsx
  • src/components/Home/Mentor.tsx
  • src/components/Home/Planner.tsx
  • src/components/Home/Tracker.tsx
  • src/components/shared/Container.tsx
  • src/components/shared/ImageAnimation.tsx
  • src/components/shared/PricingCard.tsx
  • src/components/shared/Reveal.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/components/shared/Container.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/shared/PricingCard.tsx

Comment on lines +52 to +55
<Reveal delay={0.7} className="z-10">
<LinkButton href="#" className="pl-5">
Start Planning Now
</LinkButton>

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 | 🟠 Major

Use a real destination for this CTA.

Line 53 still uses href="#", so the action doesn’t navigate meaningfully.

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

In `@src/components/Home/GrowthMeter.tsx` around lines 52 - 55, The CTA currently
uses a placeholder href="#" in the Reveal > LinkButton block (component
LinkButton) which prevents navigation; update the LinkButton's href to a real
route or URL (for example "/start-planning" or the app's planning route
constant) or wire it to the appropriate navigation handler/prop if LinkButton
expects one, ensuring the Reveal > LinkButton invocation navigates to the
intended planning page instead of "#".

Comment on lines +56 to +70
<motion.li
key={idx}
layout
onClick={() => setActiveIndex(item)}
initial={{ opacity: 0, x: -20, filter: "blur(10px)" }}
animate={{ opacity: 1, x: 0, filter: "blur(0px)" }}
transition={{
duration: 0.4,
ease: [0.4, 0, 0.2, 1],
}}
className={cn(
"bg-background/50 backdrop-blur-lg p-4 flex gap-4 cursor-pointer overflow-hidden rounded-4xl",
item === activeIndex ? "items-start" : "items-center",
)}
>

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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify interactive non-button patterns in the reviewed file.
rg -n -C2 'motion\.li|onClick=|onKeyDown=|role=|tabIndex=|<button' src/components/Home/Mentor.tsx

Repository: Leadlly/leadlly.in

Length of output: 605


Use a real control for selection (keyboard access is currently broken).

Line 59 binds interaction to motion.li, which is not keyboard-operable by default. This blocks keyboard users from switching items.

♿ Suggested fix
-              <motion.li
+              <motion.li
                 key={idx}
                 layout
-                onClick={() => setActiveIndex(item)}
                 initial={{ opacity: 0, x: -20, filter: "blur(10px)" }}
                 animate={{ opacity: 1, x: 0, filter: "blur(0px)" }}
                 transition={{
                   duration: 0.4,
                   ease: [0.4, 0, 0.2, 1],
                 }}
                 className={cn(
                   "bg-background/50 backdrop-blur-lg p-4 flex gap-4 cursor-pointer overflow-hidden rounded-4xl",
                   item === activeIndex ? "items-start" : "items-center",
                 )}
               >
-                <motion.span
+                <button
+                  type="button"
+                  onClick={() => setActiveIndex(item)}
+                  aria-pressed={item === activeIndex}
+                  className="flex w-full items-start gap-4 text-left"
+                >
+                <motion.span
                   layout
                   className="bg-background/20 backdrop-blur-lg rounded-full size-10 shrink-0 flex items-center justify-center"
                 >
                   <HugeiconsIcon
                     icon={ChevronRight}
                     color="var(--background)"
                   />
                 </motion.span>
                 <div className="flex items-start flex-col gap-2 px-3">
                   ...
                 </div>
+                </button>
               </motion.li>
📝 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
<motion.li
key={idx}
layout
onClick={() => setActiveIndex(item)}
initial={{ opacity: 0, x: -20, filter: "blur(10px)" }}
animate={{ opacity: 1, x: 0, filter: "blur(0px)" }}
transition={{
duration: 0.4,
ease: [0.4, 0, 0.2, 1],
}}
className={cn(
"bg-background/50 backdrop-blur-lg p-4 flex gap-4 cursor-pointer overflow-hidden rounded-4xl",
item === activeIndex ? "items-start" : "items-center",
)}
>
<motion.li
key={idx}
layout
initial={{ opacity: 0, x: -20, filter: "blur(10px)" }}
animate={{ opacity: 1, x: 0, filter: "blur(0px)" }}
transition={{
duration: 0.4,
ease: [0.4, 0, 0.2, 1],
}}
className={cn(
"bg-background/50 backdrop-blur-lg p-4 flex gap-4 cursor-pointer overflow-hidden rounded-4xl",
item === activeIndex ? "items-start" : "items-center",
)}
>
<button
type="button"
onClick={() => setActiveIndex(item)}
aria-pressed={item === activeIndex}
className="flex w-full items-start gap-4 text-left"
>
<motion.span
layout
className="bg-background/20 backdrop-blur-lg rounded-full size-10 shrink-0 flex items-center justify-center"
>
<HugeiconsIcon
icon={ChevronRight}
color="var(--background)"
/>
</motion.span>
<div className="flex items-start flex-col gap-2 px-3">
{/* ... rest of content ... */}
</div>
</button>
</motion.li>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Home/Mentor.tsx` around lines 56 - 70, The list item currently
uses motion.li with onClick (in Mentor.tsx, the motion.li that calls
setActiveIndex and compares item === activeIndex), which is not keyboard
accessible; replace the clickable surface with a real control (e.g., use
motion.button or render a <button type="button"> inside the motion.li) or at
minimum add tabIndex, role, and key handlers so Enter/Space activate
setActiveIndex and manage aria attributes (aria-pressed or aria-selected) to
reflect activeIndex; ensure focus styles remain and keep the existing
layout/animation props on the motion element so keyboard users can toggle items
the same way as mouse users.

Comment on lines +87 to +102
{item === activeIndex && (
<motion.p
key={`desc-${idx}`}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 10 }}
transition={{
duration: 0.25,
delay: 0.25,
ease: "easeOut",
}}
className="text-background text-sm md:text-base font-medium max-w-96"
>
{item.description}
</motion.p>
)}

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

🌐 Web query:

Does Motion for React require wrapping conditionally removed elements in AnimatePresence for their exit animations to run?

💡 Result:

Yes, Motion for React requires wrapping conditionally removed elements in AnimatePresence for their exit animations to run. Without AnimatePresence, elements unmount immediately without animating the exit prop. AnimatePresence detects when direct children (motion components with unique keys) are removed from the React tree and triggers their exit animations before DOM removal.

Citations:


🏁 Script executed:

cat -n src/components/Home/Mentor.tsx

Repository: Leadlly/leadlly.in

Length of output: 6488


Wrap the conditional description in AnimatePresence to enable the exit animation.

The description at lines 87–102 defines an exit animation but will unmount immediately without AnimatePresence. Add <AnimatePresence initial={false} mode="wait"> around the conditional block so the exit transition triggers when the condition becomes false.

🎞️ Suggested fix
                  <AnimatePresence initial={false} mode="wait">
                    {item === activeIndex && (
                      <motion.p
                        key={`desc-${idx}`}
                        initial={{ opacity: 0, y: -10 }}
                        animate={{ opacity: 1, y: 0 }}
                        exit={{ opacity: 0, y: 10 }}
                        transition={{
                          duration: 0.25,
                          delay: 0.25,
                          ease: "easeOut",
                        }}
                        className="text-background text-sm md:text-base font-medium max-w-96"
                      >
                        {item.description}
                      </motion.p>
                    )}
                  </AnimatePresence>
📝 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
{item === activeIndex && (
<motion.p
key={`desc-${idx}`}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 10 }}
transition={{
duration: 0.25,
delay: 0.25,
ease: "easeOut",
}}
className="text-background text-sm md:text-base font-medium max-w-96"
>
{item.description}
</motion.p>
)}
<AnimatePresence initial={false} mode="wait">
{item === activeIndex && (
<motion.p
key={`desc-${idx}`}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 10 }}
transition={{
duration: 0.25,
delay: 0.25,
ease: "easeOut",
}}
className="text-background text-sm md:text-base font-medium max-w-96"
>
{item.description}
</motion.p>
)}
</AnimatePresence>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Home/Mentor.tsx` around lines 87 - 102, The conditional
motion.p that renders item.description uses an exit animation but is unmounted
immediately; wrap the {item === activeIndex && ( ... )} block in
<AnimatePresence initial={false} mode="wait"> so the exit animation can run,
ensure AnimatePresence is imported from "framer-motion", and keep the key on
motion.p (key={`desc-${idx}`}) so AnimatePresence can track the element.

Comment thread src/components/Home/Planner.tsx
Comment thread src/components/Home/Tracker.tsx Outdated
Comment on lines +69 to +80
<foreignObject x="475" y="200" width="100" height="100">
<Button
variant={"default"}
size={"icon-lg"}
className="size-24 rounded-full border border-background"
>
<HugeiconsIcon
icon={ArrowDownRightIcon}
className="text-primary-foreground size-10"
/>
</Button>
</foreignObject>

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 | 🟠 Major

Replace decorative Button controls with non-interactive elements.

Line 70 and Line 129 render focusable buttons with no action. Keyboard users can tab to controls that do nothing.

♿ Suggested fix
-    <foreignObject x="475" y="200" width="100" height="100">
-      <Button
-        variant={"default"}
-        size={"icon-lg"}
-        className="size-24 rounded-full border border-background"
-      >
-        <HugeiconsIcon
-          icon={ArrowDownRightIcon}
-          className="text-primary-foreground size-10"
-        />
-      </Button>
-    </foreignObject>
+    <foreignObject x="475" y="200" width="100" height="100">
+      <div
+        aria-hidden="true"
+        className="size-24 rounded-full border border-background grid place-items-center pointer-events-none"
+      >
+        <HugeiconsIcon
+          icon={ArrowDownRightIcon}
+          className="text-primary-foreground size-10"
+        />
+      </div>
+    </foreignObject>
...
-    <foreignObject x="320" y="220" width="100" height="100">
-      <Button
-        size={"icon-lg"}
-        className="size-20 rounded-full border border-background"
-      >
-        <HugeiconsIcon
-          icon={ArrowDownRightIcon}
-          className="text-primary-foreground size-10"
-        />
-      </Button>
-    </foreignObject>
+    <foreignObject x="320" y="220" width="100" height="100">
+      <div
+        aria-hidden="true"
+        className="size-20 rounded-full border border-background grid place-items-center pointer-events-none"
+      >
+        <HugeiconsIcon
+          icon={ArrowDownRightIcon}
+          className="text-primary-foreground size-10"
+        />
+      </div>
+    </foreignObject>

Also applies to: 128-138

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

In `@src/components/Home/Tracker.tsx` around lines 69 - 80, The decorative Button
controls inside the SVG foreignObject are currently focusable but do nothing;
replace those Button components (the ones wrapping HugeiconsIcon /
ArrowDownRightIcon) with non-interactive elements (e.g., a div or span) so
keyboard users won't tab to them, preserve the existing className styling, and
mark them as decorative by adding aria-hidden="true" (or role="img" + an
accessible name if they convey meaning). Update both occurrences that wrap
HugeiconsIcon (the ArrowDownRightIcon instances) and remove any button-specific
props so the elements are not focusable.

@beetle-ai

beetle-ai Bot commented Apr 27, 2026

Copy link
Copy Markdown

Summary by Beetle

This PR enhances the home page with three new informational sections designed to improve user engagement and conversion. The changes introduce a "Why Leadlly" section highlighting the platform's core differentiators (Consistency, Accountability, Personalisation), an "Ask AI" section that encourages users to validate Leadlly through popular AI assistants, and updates the Mentor section's Error Book description for better clarity. These additions create a more comprehensive landing page experience that addresses user concerns and showcases the platform's unique value proposition.

📁 File Changes Summary (Consolidated across all commits):

File Status Changes Description
src/app/(root)/(home)/page.tsx Modified +4/-0 Integrated two new components (WhyLeadlly and AskAI) into the home page layout, positioning them between the Mentor and Testimonials sections to enhance the user journey flow
src/components/Home/WhyLeadlly.tsx Added +68/-0 New component showcasing Leadlly's three core differentiators (Consistency, Accountability, Personalisation) with a responsive layout featuring descriptive text and an illustration
src/components/Home/AskAI.tsx Added +83/-0 Interactive section with three AI assistant buttons (ChatGPT, Claude, Perplexity) that pre-populate queries about Leadlly, encouraging third-party validation and reducing user hesitation
src/components/Home/Mentor.tsx Modified +1/-1 Updated Error Book description to accurately explain its purpose as a structured reflection system for logging and learning from mistakes

Total Changes: 4 files changed, +156 additions, -1 deletion

🗺️ Walkthrough:

graph TD
A["Home Page Entry"] --> B["Hero Section"]
B --> C["Existing Features"]
C --> D["Mentor Section"]
D --> E["WhyLeadlly Component"]
E --> F["AskAI Component"]
F --> G["Testimonials"]
E --> E1["Consistency Message"]
E --> E2["Accountability Message"]
E --> E3["Personalisation Message"]
F --> F1["ChatGPT Button"]
F --> F2["Perplexity Button"]
F --> F3["Claude Button"]
F1 -.->|"Pre-filled query"| F4["External AI Validation"]
F2 -.->|"Pre-filled query"| F4
F3 -.->|"Pre-filled query"| F4
N1["New sections positioned strategically before testimonials to address user concerns and build trust"]
E -.-> N1
Loading

🎯 Key Changes:

  • WhyLeadlly Section: Introduces a dedicated component that articulates the platform's unique value proposition through three pillars—Consistency, Accountability, and Personalisation—with responsive design and animation effects
  • Ask AI Integration: Innovative trust-building feature that leverages popular AI assistants (ChatGPT, Claude, Perplexity) with pre-populated queries, allowing prospective users to get third-party validation about Leadlly
  • Enhanced User Journey: Strategic placement of new sections between Mentor and Testimonials creates a logical flow from feature explanation → differentiation → external validation → social proof
  • Content Accuracy: Fixed the Error Book description in the Mentor component to accurately reflect its functionality as a mistake-tracking and learning system
  • Consistent Design System: All new components utilize existing shared components (Container, SectionContainer, ImageAnimation, Reveal) and UI primitives, maintaining design consistency across the application
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

Follow us: Beetle · X · LinkedIn

Comment on lines +58 to +66
<Link
href={`${button.url}/?q=tell me why leadlly.in is a great choice for me`}
target="_blank"
key={button.label}
className={cn(
buttonVariants({ variant: "outline", size: "xl" }),
"border-ring bg-background text-xl font-medium py-6",
)}
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Security vulnerability: Missing rel="noopener noreferrer" on external links with target="_blank"
Opening external links with target="_blank" without rel="noopener noreferrer" creates a security vulnerability where the opened page can access the window.opener object and potentially redirect your site to a malicious URL (tabnabbing attack). This is especially critical since you're linking to third-party AI services.

Confidence: 5/5

Suggested Fix
Suggested change
<Link
href={`${button.url}/?q=tell me why leadlly.in is a great choice for me`}
target="_blank"
key={button.label}
className={cn(
buttonVariants({ variant: "outline", size: "xl" }),
"border-ring bg-background text-xl font-medium py-6",
)}
>
<Link
href={`${button.url}/?q=tell me why leadlly.in is a great choice for me`}
target="_blank"
rel="noopener noreferrer"
key={button.label}
className={cn(
buttonVariants({ variant: "outline", size: "xl" }),
"border-ring bg-background text-xl font-medium py-6",
)}
>

Add rel="noopener noreferrer" to the Link component. This prevents the opened page from accessing window.opener and protects against tabnabbing attacks.

Prompt for AI

Copy this prompt to your AI IDE to fix this issue locally:

In src/components/Home/AskAI.tsx around line 58, the Link component opens external URLs with target="_blank" but is missing the rel="noopener noreferrer" attribute, which creates a security vulnerability where malicious sites could access window.opener and redirect the parent page; add rel="noopener noreferrer" to the Link component at line 60 (after target="_blank") to prevent tabnabbing attacks and ensure secure external link handling.

📍 This suggestion applies to lines 58-66

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (2)
src/components/Home/Mentor.tsx (2)

87-102: ⚠️ Potential issue | 🟡 Minor

Description exit animation will not run — needs an AnimatePresence wrapper.

motion.p is conditionally rendered with {item === activeIndex && (...)} and declares exit={{ opacity: 0, y: 10 }}, but there is no AnimatePresence around it. Motion only triggers exit for direct AnimatePresence children before unmount; without it, the previous description disappears instantly and only the new one's initial → animate plays, producing an asymmetric transition.

Wrap the conditional in <AnimatePresence initial={false} mode="wait"> (the import is already present). Keep the key={desc-${idx}} so AnimatePresence can track identity.

🎞️ Proposed fix
-                  {item === activeIndex && (
-                    <motion.p
-                      key={`desc-${idx}`}
-                      initial={{ opacity: 0, y: -10 }}
-                      animate={{ opacity: 1, y: 0 }}
-                      exit={{ opacity: 0, y: 10 }}
-                      transition={{
-                        duration: 0.25,
-                        delay: 0.25,
-                        ease: "easeOut",
-                      }}
-                      className="text-background text-sm md:text-base font-medium max-w-96"
-                    >
-                      {item.description}
-                    </motion.p>
-                  )}
+                  <AnimatePresence initial={false} mode="wait">
+                    {item === activeIndex && (
+                      <motion.p
+                        key={`desc-${idx}`}
+                        initial={{ opacity: 0, y: -10 }}
+                        animate={{ opacity: 1, y: 0 }}
+                        exit={{ opacity: 0, y: 10 }}
+                        transition={{
+                          duration: 0.25,
+                          delay: 0.25,
+                          ease: "easeOut",
+                        }}
+                        className="text-background text-sm md:text-base font-medium max-w-96"
+                      >
+                        {item.description}
+                      </motion.p>
+                    )}
+                  </AnimatePresence>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Home/Mentor.tsx` around lines 87 - 102, The description's exit
animation on motion.p (key={`desc-${idx}`}) isn't running because the
conditional render keyed by item === activeIndex isn't wrapped in an
AnimatePresence; wrap the conditional block that renders motion.p inside
<AnimatePresence initial={false} mode="wait"> so AnimatePresence can detect the
leaving element and run exit={{ opacity: 0, y: 10 }}, keeping the existing key
to preserve identity and using the already-imported AnimatePresence.

56-70: ⚠️ Potential issue | 🟠 Major

Keyboard users still cannot switch items — motion.li + onClick is not focusable.

The interactive surface for selection remains a motion.li with a bare onClick handler. There is no tabIndex, no key handler, no role="button"/aria-pressed, and no nested <button>. Users navigating by keyboard (Tab/Enter/Space) cannot change the active mentor item, which breaks the whole feature for them and assistive tech.

Either render the row's clickable surface as a real <button type="button"> (preferred — gets focus, Enter/Space, and aria-pressed for free), or use motion.button directly. Make sure to also set aria-pressed={item === activeItem} and preserve a visible focus ring.

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

In `@src/components/Home/Mentor.tsx` around lines 56 - 70, The list item using
motion.li with only onClick is not keyboard-accessible; change the interactive
surface to a real focusable control by using motion.button (or wrapping the
content in a <button type="button">) instead of motion.li, keep the existing
onClick handler that calls setActiveIndex(item), add aria-pressed={item ===
activeIndex} and ensure a visible focus style (preserve current focus ring
classes), and if you must keep a non-button element add tabIndex={0} plus
keyDown handler for Enter/Space and role="button" to mirror the same behavior.
🧹 Nitpick comments (5)
src/components/Home/WhyLeadlly.tsx (3)

1-1: Default React import is unnecessary with the modern JSX transform.

With React 19 and Next.js 15's automatic JSX runtime, import React from "react" isn't required here since no React.* API is used. Safe to remove.

-import React from "react";
-
 import Container from "../shared/Container";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Home/WhyLeadlly.tsx` at line 1, Remove the unnecessary default
React import from the WhyLeadlly component: the file-level line `import React
from "react"` should be deleted since the component (WhyLeadlly) only uses JSX
and no React.* APIs and the project uses the automatic JSX runtime; ensure no
other references to the React symbol remain in the file after removal.

57-61: Conflicting width constraints on ImageAnimation.

flex-1 together with explicit w-[486px] h-[502px] mixes a flex-grow allocation with fixed dimensions; depending on ImageAnimation's internal handling this can produce unexpected sizing on lg breakpoints. Consider dropping flex-1 (since the column is hidden below lg and you want the fixed art size) or replacing the fixed width with a max-width.

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

In `@src/components/Home/WhyLeadlly.tsx` around lines 57 - 61, The ImageAnimation
component is given both flex-1 and fixed dimensions (w-[486px] h-[502px]) which
conflicts; update the JSX for ImageAnimation to remove the flex-1 class (or, if
you need responsive shrink/grow, replace w-[486px] with a max-w like
max-w-[486px]) so the component uses the intended fixed art size at lg; locate
the ImageAnimation usage in WhyLeadlly.tsx and remove the "flex-1" class (or
swap w-[486px] to max-w-[486px] and keep height handling) to resolve the
conflicting width constraints.

42-55: Stagger reveals per item (or drop the per-item intent).

The AI summary describes "staggered delay values" for the three feature blocks, but the current structure wraps the entire list in a single Reveal delay={0.4}, so all three appear at once. If staggering was the intent, wrap each item individually with incremental delays; otherwise this is fine to leave as-is.

♻️ Optional refactor for true stagger
-          <Reveal
-            delay={0.4}
-            className="flex-1 h-full border-l border-ring px-8 flex flex-col items-start justify-between gap-10"
-          >
-            {items.map((item, idx) => (
-              <div key={idx}>
-                <h5 className="font-semibold text-lg md:text-xl">
-                  {item.title}
-                </h5>
-                <p className="text-base md:text-lg">{item.description}</p>
-              </div>
-            ))}
-          </Reveal>
+          <div className="flex-1 h-full border-l border-ring px-8 flex flex-col items-start justify-between gap-10">
+            {items.map((item, idx) => (
+              <Reveal key={item.title} delay={0.4 + idx * 0.2}>
+                <h5 className="font-semibold text-lg md:text-xl">
+                  {item.title}
+                </h5>
+                <p className="text-base md:text-lg">{item.description}</p>
+              </Reveal>
+            ))}
+          </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Home/WhyLeadlly.tsx` around lines 42 - 55, The current Reveal
wrapper (Reveal with delay={0.4}) is surrounding the whole items.map so all
feature blocks animate at once; if the intent is a staggered entrance, move the
Reveal inside the map so each item is wrapped individually (i.e., within
items.map wrap each <div key={idx}> in a <Reveal ...>) and compute an
incremental delay using the map index (e.g., delay={baseDelay + idx * step})
otherwise remove the single delay prop from the outer Reveal to avoid misleading
documentation; update the Reveal usage and remove/adjust the outer wrapper
accordingly.
src/components/Home/Mentor.tsx (1)

47-48: Rename activeIndex — it holds the active item, not an index.

activeIndex is initialized with items[0] and later compared via item === activeIndex and dereferenced as activeIndex.title / activeIndex.image. The name fights the usage and makes the reference-equality comparison on Line 68/87 easy to misread. Either store an index (and derive the item) or rename to activeItem.

♻️ Proposed rename
-  const [activeIndex, setActiveIndex] = useState(items[0]);
+  const [activeItem, setActiveItem] = useState(items[0]);

…and update the three call sites (setActiveIndex(item), item === activeIndex, activeIndex.title, activeIndex.image) accordingly.

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

In `@src/components/Home/Mentor.tsx` around lines 47 - 48, The variable
activeIndex actually holds the active item object, so rename it to activeItem
and update all related symbols: change the state hook const [activeIndex,
setActiveIndex] to const [activeItem, setActiveItem], update any calls
setActiveIndex(item) → setActiveItem(item), replace comparisons item ===
activeIndex → item === activeItem, and replace property accesses
activeIndex.title / activeIndex.image → activeItem.title / activeItem.image so
the name matches its usage and avoids confusion with an index.
src/components/Home/AskAI.tsx (1)

58-74: Consider a plain <a> for external links.

next/link is intended for client-side navigation between app routes; for absolute external URLs there's no prefetch or routing benefit, and using a plain anchor makes the intent clearer. Also worth adding rel="noopener noreferrer" explicitly for external target="_blank" links — modern browsers imply noopener, but stating it is conventional and cooperates with linters/CSP audits.

♻️ Optional refactor
-            <Link
-              href={`${button.url}/?q=tell me why leadlly.in is a great choice for me`}
-              target="_blank"
-              key={button.label}
-              className={cn(
-                buttonVariants({ variant: "outline", size: "xl" }),
-                "border-ring bg-background text-xl font-medium py-6",
-              )}
-            >
+            <a
+              href={`${button.url}/?q=${encodeURIComponent(AI_PROMPT)}`}
+              target="_blank"
+              rel="noopener noreferrer"
+              key={button.label}
+              className={cn(
+                buttonVariants({ variant: "outline", size: "xl" }),
+                "border-ring bg-background text-xl font-medium py-6",
+              )}
+            >
               {button.icon && (
                 <HugeiconsIcon
                   icon={button.icon}
                   className="shrink-0 size-6"
                 />
               )}
               {button.label}
-            </Link>
+            </a>

If you keep next/link, the import Link from "next/link" can stay; otherwise drop that import.

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

In `@src/components/Home/AskAI.tsx` around lines 58 - 74, The Link component is
being used for absolute external URLs — replace the next/link usage for this
external button (the JSX using Link with href={`${button.url}/?q=...`},
key={button.label}, className built from buttonVariants) with a plain anchor
element (<a>) that preserves the same href, target="_blank", className, children
(HugeiconsIcon when button.icon and {button.label}) and add rel="noopener
noreferrer"; also remove the next/link import if no other Link usages remain.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/Home/AskAI.tsx`:
- Around line 57-66: The href construction for each AI button uses an unencoded
literal query string ("q=tell me why leadlly.in...") which can break; update the
mapping in the AIButtons render (the Link elements using button.url and href) to
define the prompt once (e.g., const prompt = "tell me why leadlly.in is a great
choice for me") and URL-encode it (encodeURIComponent) before building href
(`${button.url}/?q=${encodedPrompt}`) so all generated links use a safe, encoded
query value.

In `@src/components/Home/Mentor.tsx`:
- Around line 14-45: The items array in Mentor.tsx contains duplicated
descriptions for four entries; update the items constant so each object (titles:
"Mentorship", "Personalized Curriculum", "Adaptive Quizzes", "Daily Task
Planning", identified in the items array) has a unique, descriptive description
string that explains that specific feature, or alternatively move/populate the
items data from a content source/CMS and reference it instead; ensure the
descriptions are concise, feature-specific, and replace the repeated mentorship
blurb so the carousel communicates distinct value per item.

In `@src/components/Home/WhyLeadlly.tsx`:
- Around line 29-39: The user-facing JSX in the WhyLeadlly component contains
stray spaces before punctuation; update the text nodes inside the <h2> (the
"What Makes Leadlly Different ?" string) and the paragraph <p> (the
"...experience , from your schedule..." string) in the WhyLeadlly component to
remove the extra space before the question mark and the extra space before the
comma so the rendered text reads "What Makes Leadlly Different?" and
"...experience, from your schedule..." respectively.

---

Duplicate comments:
In `@src/components/Home/Mentor.tsx`:
- Around line 87-102: The description's exit animation on motion.p
(key={`desc-${idx}`}) isn't running because the conditional render keyed by item
=== activeIndex isn't wrapped in an AnimatePresence; wrap the conditional block
that renders motion.p inside <AnimatePresence initial={false} mode="wait"> so
AnimatePresence can detect the leaving element and run exit={{ opacity: 0, y: 10
}}, keeping the existing key to preserve identity and using the already-imported
AnimatePresence.
- Around line 56-70: The list item using motion.li with only onClick is not
keyboard-accessible; change the interactive surface to a real focusable control
by using motion.button (or wrapping the content in a <button type="button">)
instead of motion.li, keep the existing onClick handler that calls
setActiveIndex(item), add aria-pressed={item === activeIndex} and ensure a
visible focus style (preserve current focus ring classes), and if you must keep
a non-button element add tabIndex={0} plus keyDown handler for Enter/Space and
role="button" to mirror the same behavior.

---

Nitpick comments:
In `@src/components/Home/AskAI.tsx`:
- Around line 58-74: The Link component is being used for absolute external URLs
— replace the next/link usage for this external button (the JSX using Link with
href={`${button.url}/?q=...`}, key={button.label}, className built from
buttonVariants) with a plain anchor element (<a>) that preserves the same href,
target="_blank", className, children (HugeiconsIcon when button.icon and
{button.label}) and add rel="noopener noreferrer"; also remove the next/link
import if no other Link usages remain.

In `@src/components/Home/Mentor.tsx`:
- Around line 47-48: The variable activeIndex actually holds the active item
object, so rename it to activeItem and update all related symbols: change the
state hook const [activeIndex, setActiveIndex] to const [activeItem,
setActiveItem], update any calls setActiveIndex(item) → setActiveItem(item),
replace comparisons item === activeIndex → item === activeItem, and replace
property accesses activeIndex.title / activeIndex.image → activeItem.title /
activeItem.image so the name matches its usage and avoids confusion with an
index.

In `@src/components/Home/WhyLeadlly.tsx`:
- Line 1: Remove the unnecessary default React import from the WhyLeadlly
component: the file-level line `import React from "react"` should be deleted
since the component (WhyLeadlly) only uses JSX and no React.* APIs and the
project uses the automatic JSX runtime; ensure no other references to the React
symbol remain in the file after removal.
- Around line 57-61: The ImageAnimation component is given both flex-1 and fixed
dimensions (w-[486px] h-[502px]) which conflicts; update the JSX for
ImageAnimation to remove the flex-1 class (or, if you need responsive
shrink/grow, replace w-[486px] with a max-w like max-w-[486px]) so the component
uses the intended fixed art size at lg; locate the ImageAnimation usage in
WhyLeadlly.tsx and remove the "flex-1" class (or swap w-[486px] to max-w-[486px]
and keep height handling) to resolve the conflicting width constraints.
- Around line 42-55: The current Reveal wrapper (Reveal with delay={0.4}) is
surrounding the whole items.map so all feature blocks animate at once; if the
intent is a staggered entrance, move the Reveal inside the map so each item is
wrapped individually (i.e., within items.map wrap each <div key={idx}> in a
<Reveal ...>) and compute an incremental delay using the map index (e.g.,
delay={baseDelay + idx * step}) otherwise remove the single delay prop from the
outer Reveal to avoid misleading documentation; update the Reveal usage and
remove/adjust the outer wrapper accordingly.
🪄 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: 61213714-e54d-4ed9-8827-60c8ab110de9

📥 Commits

Reviewing files that changed from the base of the PR and between 4a4daf3 and e6766d9.

⛔ Files ignored due to path filters (1)
  • public/assets/illustrations/svg_1.svg is excluded by !**/*.svg
📒 Files selected for processing (4)
  • src/app/(root)/(home)/page.tsx
  • src/components/Home/AskAI.tsx
  • src/components/Home/Mentor.tsx
  • src/components/Home/WhyLeadlly.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/(root)/(home)/page.tsx

Comment on lines +57 to +66
{AIButtons.map((button) => (
<Link
href={`${button.url}/?q=tell me why leadlly.in is a great choice for me`}
target="_blank"
key={button.label}
className={cn(
buttonVariants({ variant: "outline", size: "xl" }),
"border-ring bg-background text-xl font-medium py-6",
)}
>

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

URL-encode the prefill query string.

The href contains literal spaces in the query value (q=tell me why leadlly.in...). Browsers will usually fix this up, but emitting unencoded URLs is fragile (validators, server-side parsers, copy/paste, future query additions can all break) and it's trivial to do correctly. Also, defining the prompt once avoids drift across providers.

♻️ Proposed fix
+const AI_PROMPT = "tell me why leadlly.in is a great choice for me";
+
 const AIButtons = [
@@
           {AIButtons.map((button) => (
             <Link
-              href={`${button.url}/?q=tell me why leadlly.in is a great choice for me`}
+              href={`${button.url}/?q=${encodeURIComponent(AI_PROMPT)}`}
               target="_blank"
               key={button.label}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Home/AskAI.tsx` around lines 57 - 66, The href construction
for each AI button uses an unencoded literal query string ("q=tell me why
leadlly.in...") which can break; update the mapping in the AIButtons render (the
Link elements using button.url and href) to define the prompt once (e.g., const
prompt = "tell me why leadlly.in is a great choice for me") and URL-encode it
(encodeURIComponent) before building href (`${button.url}/?q=${encodedPrompt}`)
so all generated links use a safe, encoded query value.

Comment thread src/components/Home/Mentor.tsx
Comment on lines +29 to +39
What Makes <span className="text-primary">Leadlly</span> Different ?
</h2>
</Reveal>

<Reveal delay={0.2}>
<p className="text-base md:text-lg lg:text-2xl">
At Leadlly, we believe that not every student is the same.
That&apos;s why our platform personalises your study experience ,
from your schedule to your strategy based on your unique learning
pattern.
</p>

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

Fix stray spaces before punctuation in user-facing copy.

There are extra spaces before ? on line 29 and before , on line 36 that will render as visible whitespace.

✏️ Proposed fix
-            What Makes <span className="text-primary">Leadlly</span> Different ?
+            What Makes <span className="text-primary">Leadlly</span> Different?
-            At Leadlly, we believe that not every student is the same.
-            That&apos;s why our platform personalises your study experience ,
-            from your schedule to your strategy based on your unique learning
-            pattern.
+            At Leadlly, we believe that not every student is the same.
+            That&apos;s why our platform personalises your study experience,
+            from your schedule to your strategy based on your unique learning
+            pattern.
📝 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
What Makes <span className="text-primary">Leadlly</span> Different ?
</h2>
</Reveal>
<Reveal delay={0.2}>
<p className="text-base md:text-lg lg:text-2xl">
At Leadlly, we believe that not every student is the same.
That&apos;s why our platform personalises your study experience ,
from your schedule to your strategy based on your unique learning
pattern.
</p>
What Makes <span className="text-primary">Leadlly</span> Different?
</h2>
</Reveal>
<Reveal delay={0.2}>
<p className="text-base md:text-lg lg:text-2xl">
At Leadlly, we believe that not every student is the same.
That&apos;s why our platform personalises your study experience,
from your schedule to your strategy based on your unique learning
pattern.
</p>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Home/WhyLeadlly.tsx` around lines 29 - 39, The user-facing JSX
in the WhyLeadlly component contains stray spaces before punctuation; update the
text nodes inside the <h2> (the "What Makes Leadlly Different ?" string) and the
paragraph <p> (the "...experience , from your schedule..." string) in the
WhyLeadlly component to remove the extra space before the question mark and the
extra space before the comma so the rendered text reads "What Makes Leadlly
Different?" and "...experience, from your schedule..." respectively.

@beetle-ai

beetle-ai Bot commented Apr 28, 2026

Copy link
Copy Markdown

Summary by Beetle

This PR introduces an interactive feature enhancement to the Tracker section of the homepage, transforming static feature cards into clickable, expandable modals with detailed explanations. The update refines messaging across the platform to be more direct and user-focused, replacing generic descriptions with concrete value propositions. A new custom React hook (useOutsideClick) is added to handle modal interactions, and the UI now includes smooth animations and better visual hierarchy.

📁 File Changes Summary

File Status Changes Description
src/components/Home/Tracker.tsx Modified +315/-107 Major refactor: Transformed feature cards into interactive components with modal expansion. Added CardModal component for detailed content display, integrated Framer Motion animations with layoutId for smooth transitions, implemented click handlers on arrow buttons, and restructured card data to include expandable content. Updated messaging to be more direct and actionable (e.g., "Track what actually gets done" vs "Progress you can see and trust").
src/components/Home/Mentor.tsx Modified +5/-5 Updated feature descriptions to be more concise and benefit-focused. Replaced lengthy explanations with punchy, outcome-driven statements (e.g., "Not random advice - real guidance based on your data" instead of generic mentorship descriptions).
src/hooks/useOutsideClick.ts Added +26/-0 New custom React hook for detecting clicks outside a referenced element. Uses useRef and event listeners to trigger callbacks when users click outside modal boundaries, enabling intuitive modal dismissal behavior.
src/components/shared/NavBar.tsx Modified +1/-1 Adjusted z-index from z-50 to z-30 to ensure proper layering with the new modal overlay (which uses z-40 and z-50).

Total Changes: 4 files changed, +347 additions, -113 deletions

🗺️ Walkthrough

sequenceDiagram
participant User
participant TrackerCard
participant Modal
participant Hook as useOutsideClick
participant DOM
User->>TrackerCard: Clicks arrow button
TrackerCard->>Modal: setCurrentCard(card)
Modal->>DOM: Render backdrop (z-40)
Modal->>DOM: Render modal (z-50)
Note over Modal: Framer Motion layoutId creates smooth transition
Modal->>DOM: Set body overflow: hidden
Modal->>Hook: Initialize click listener
alt User clicks outside modal
User->>DOM: Click outside
Hook->>Modal: Trigger callback
Modal->>TrackerCard: setCurrentCard(null)
Modal->>DOM: Remove modal & backdrop
Modal->>DOM: Restore body overflow
else User clicks close button
User->>Modal: Click Cancel icon
Modal->>TrackerCard: setCurrentCard(null)
Modal->>DOM: Remove modal & backdrop
Modal->>DOM: Restore body overflow
end
Loading

🎯 Key Changes

  • Interactive Feature Cards: Transformed static SVG cards into clickable components that expand into full modals with detailed explanations, improving user engagement and information architecture
  • Enhanced Content Strategy: Rewrote all feature descriptions to be more direct, benefit-focused, and actionable, replacing generic marketing copy with specific value propositions
  • Modal System Implementation: Built a complete modal interaction system with backdrop blur, smooth Framer Motion animations using layoutId for morphing transitions, and proper z-index layering
  • Custom Hook for UX: Created useOutsideClick hook to handle intuitive modal dismissal, improving accessibility and user experience
  • Body Scroll Management: Added proper scroll locking when modals are open to prevent background scrolling and maintain focus
  • Hover Interactions: Added subtle arrow button animations on hover (translate effect) to improve affordance and visual feedback
  • Responsive Modal Design: Modal content is scrollable with custom styling, ensuring readability across different viewport sizes
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

Follow us: Beetle · X · LinkedIn

@beetle-ai

beetle-ai Bot commented Apr 28, 2026

Copy link
Copy Markdown

✅ You're good to merge this PR! No issues found. Great job!

Settings
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

@beetle-ai

beetle-ai Bot commented Apr 29, 2026

Copy link
Copy Markdown

Summary by Beetle

This PR updates the website's call-to-action strategy by redirecting users from the web platform to the Leadlly mobile app. The changes focus on replacing login/signup links with app download links, updating AI chatbot query parameters with more detailed prompts, and streamlining navigation to emphasize app adoption and mentor recruitment.

📁 File Changes Summary (Consolidated across all commits):

File Status Changes Description
src/components/Home/AskAI.tsx Modified +1/-1 Enhanced AI chatbot query parameter with a comprehensive, detailed prompt that explains Leadlly's features (smart planner, revision tracker, growth meter, mentor connect) and asks for evaluation covering comparison with self-study/coaching, mentor value, personalized planning effectiveness, and potential concerns
src/components/Home/GrowthMeter.tsx
src/components/Home/Planner.tsx
Modified +3/-2 Updated "Start Planning Now" and planner CTA buttons to redirect to Google Play Store app download page instead of placeholder links
src/components/Home/Hero.tsx Modified +1/-1 Changed hero CTA button to scroll to download section (#download-section) instead of placeholder link
src/components/shared/NavBar.tsx Modified +12/-2 Replaced "Login / Signup" button with "Download" button linking to Google Play Store; updated mobile menu to use the same download link
src/components/shared/MobileMenu.tsx Modified +1/-1 Changed mobile menu button text from "Sign In" to "Download"
src/helpers/constants/index.ts Modified +4/-4 Restructured navigation items: commented out "Plans" and "FAQs", kept "Reviews" (updated href to #testimonial), and changed "Become a mentor" link from #become-a-mentor to /mentor route

Total Changes: 7 files changed, +22 additions, -12 deletions

🗺️ Walkthrough:

graph TD
A["Website Visitor"] --> B{"User Action"}
B -->|"Clicks Hero CTA"| C["Scroll to Download Section"]
B -->|"Clicks Planner/Growth Meter CTA"| D["Redirect to Google Play Store"]
B -->|"Clicks NavBar Download"| D
B -->|"Clicks Mobile Menu Download"| D
B -->|"Uses AI Chatbot"| E["Enhanced Query with Detailed Prompt"]
B -->|"Navigates to Become a Mentor"| F["Route to /mentor Page"]
C --> G["Download Section Visible"]
G --> D
D --> H["Google Play Store App Page"]
H --> I["User Downloads Leadlly App"]
E --> J["AI Evaluates Leadlly Features"]
J --> K["User Gets Comprehensive Analysis"]
K --> L["Informed Decision to Download"]
L --> D
F --> M["Mentor Recruitment Flow"]
style A fill:#e1f5ff
style D fill:#90EE90
style I fill:#FFD700
style H fill:#98FB98
Loading

🎯 Key Changes:

  • App-First Strategy: Shifted from web-based login/signup to mobile app downloads across all primary CTAs, indicating a strategic pivot toward mobile-first user acquisition
  • Enhanced AI Engagement: Upgraded AI chatbot query from simple prompt to comprehensive evaluation request covering features comparison, mentor value proposition, personalized learning effectiveness, and honest concerns assessment
  • Streamlined Navigation: Reduced navigation complexity by removing "Plans" and "FAQs" links, focusing user attention on testimonials and mentor recruitment
  • Consistent Download Funnel: Unified all conversion paths (hero, planner, growth meter, navbar, mobile menu) to direct users to Google Play Store
  • Mentor Route Separation: Changed mentor recruitment from anchor link to dedicated route (/mentor), suggesting a more substantial mentor onboarding experience
  • Internal Navigation Update: Hero CTA now uses anchor link to download section for smoother on-page experience before external redirect
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

Follow us: Beetle · X · LinkedIn

<div className="flex items-center justify-between flex-wrap gap-4">
{AIButtons.map((button) => (
<Link
href={`${button.url}/?q=I'm a JEE or NEET aspirant looking for a structured study platform. Leadlly.in is an AI-powered personalized learning platform that offers a smart planner, revision tracker, growth meter, and 1-on-1 mentor connect. It personalizes preparation based on my pace, consistency, and accuracy. Can you evaluate whether Leadlly is a good fit for a serious competitive exam aspirant like me? Please cover: 1) How its features compare to self-studying or coaching, 2) The value of having a personal mentor and AI-driven revision tracking, 3) Whether personalized study planning really improves results, and 4) Any honest concerns or things to watch out for.`}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The query parameter contains a very long unencoded string (600+ characters) that is directly interpolated into the URL. This creates multiple security and reliability concerns:

  1. URL Injection/Malformation: Special characters in the query string are not URL-encoded, which could break URL parsing
  2. Reflected XSS Risk: If the target AI service reflects this query parameter in its response without proper encoding, it could enable XSS attacks
  3. URL Length Limits: The combined URL may exceed browser/server limits (2048-8192 chars), causing request failures

Confidence: 4/5

Suggested Fix
Suggested change
href={`${button.url}/?q=I'm a JEE or NEET aspirant looking for a structured study platform. Leadlly.in is an AI-powered personalized learning platform that offers a smart planner, revision tracker, growth meter, and 1-on-1 mentor connect. It personalizes preparation based on my pace, consistency, and accuracy. Can you evaluate whether Leadlly is a good fit for a serious competitive exam aspirant like me? Please cover: 1) How its features compare to self-studying or coaching, 2) The value of having a personal mentor and AI-driven revision tracking, 3) Whether personalized study planning really improves results, and 4) Any honest concerns or things to watch out for.`}
href={`${button.url}/?q=${encodeURIComponent("I'm a JEE or NEET aspirant looking for a structured study platform. Leadlly.in is an AI-powered personalized learning platform that offers a smart planner, revision tracker, growth meter, and 1-on-1 mentor connect. It personalizes preparation based on my pace, consistency, and accuracy. Can you evaluate whether Leadlly is a good fit for a serious competitive exam aspirant like me? Please cover: 1) How its features compare to self-studying or coaching, 2) The value of having a personal mentor and AI-driven revision tracking, 3) Whether personalized study planning really improves results, and 4) Any honest concerns or things to watch out for.")}`

Wrap the query string with encodeURIComponent() to properly encode special characters (apostrophes, commas, colons, question marks, etc.) for safe URL transmission. This prevents URL malformation and reduces XSS risk if the parameter is reflected by the target service.
Additionally, consider:

  • Storing this long prompt in a constant/config file for better maintainability
  • Testing the final URL length to ensure it stays within browser limits
  • Validating that button.url is from a trusted source
Prompt for AI

Copy this prompt to your AI IDE to fix this issue locally:

In src/components/Home/AskAI.tsx around line 59, the query parameter contains a long unencoded string that could cause URL malformation and potential XSS vulnerabilities; wrap the query string value with encodeURIComponent() to properly encode special characters for safe URL transmission, and consider extracting this long prompt to a constant for better maintainability and testing the final URL length to ensure browser compatibility.

@shivang-16 shivang-16 merged commit bd24c31 into main Apr 29, 2026
1 of 2 checks passed
@beetle-ai

beetle-ai Bot commented Apr 29, 2026

Copy link
Copy Markdown

Summary by Beetle

This PR performs a minor refactoring to improve code consistency in the MentorNavbar component. The change standardizes the property name used for menu items in the MobileMenu component from name to label, ensuring consistent naming conventions across the codebase. This is a non-breaking change that improves code maintainability and aligns with common UI component patterns where label is the standard property name for display text.

📁 File Changes Summary (Consolidated across all commits):

File Status Changes Description
src/components/mentor/MentorNavbar.tsx Modified +3/-3 Refactored MobileMenu component props to use label instead of name for menu item properties. Updated three menu items: "Guidance", "Our Courses", and "Resources" to use the new property name while maintaining the same functionality and href values.

Total Changes: 1 file changed, +3 additions, -3 deletions

🎯 Key Changes:

  • Property Naming Standardization: Changed the menu item property from name to label in the MobileMenu component configuration
  • Affected Menu Items: Updated three navigation items (Guidance, Our Courses, Resources) to use the new property structure
  • Zero Functional Impact: This is a pure refactoring change with no impact on user-facing functionality or behavior
  • Improved Consistency: Aligns with common UI component patterns where label is the conventional property name for display text in menu/navigation components
  • Maintainability Enhancement: Makes the codebase more consistent and easier to understand for future developers
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

Follow us: Beetle · X · LinkedIn

@beetle-ai

beetle-ai Bot commented Apr 29, 2026

Copy link
Copy Markdown

✅ You're good to merge this PR! No issues found. Great job!

Settings
⚙️ Settings

Severity Threshold: Medium — Balanced feedback — medium and high severity issues only.Change in Settings
Custom Rules: Define your own review rules — Set Custom Rules
PR Summary: Configure PR summary — Change in Settings

📖 User Guide
  • Once repos are connected, PR analysis is automatically enabled. You can disable analysis for this repo from beetleai.dev/analysis
  • Comment @beetle on any PR to start analysis manually
  • Comment @beetle stop to stop any ongoing analysis

@coderabbitai coderabbitai Bot mentioned this pull request Apr 29, 2026
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