Skip to content

Shnnew #87

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open

Shnnew #87

wants to merge 28 commits into from

Conversation

AksaRose
Copy link
Collaborator

@AksaRose AksaRose commented Jun 9, 2025

What does it do?

Build a completely New Website frontend.

Why is it needed?

It lacked a lot of informations.

Summary by CodeRabbit

  • New Features

    • Introduced a new React-based frontend using Vite, React, and Tailwind CSS.
    • Added interactive components including a carousel, looping text, animated FAQ, testimonials, partners section, stats, and a countdown timer.
    • Implemented a visually rich homepage with animated backgrounds, parallax effects, and a typewriter headline.
    • Added a customizable navigation bar and shimmer-effect buttons for enhanced UI.
    • Added new components for registration steps, display cards, and footer with social links.
  • Style

    • Integrated custom fonts, color themes, and dark mode support.
    • Applied advanced CSS animations and glassmorphism effects for modern aesthetics.
    • Included shimmer button styles and animations.
  • Chores

    • Migrated from a monorepo and Next.js/Firebase backend to a single-package Vite React app.
    • Updated configuration files for ESLint, Tailwind CSS, PostCSS, and TypeScript.
    • Removed legacy Firebase functions, authentication context, and related components.
    • Cleaned up obsolete files including API routes, modals, layouts, pages, utilities, and type definitions.
    • Added new utility functions for class name merging and streamlined CSS imports.

Copy link

netlify bot commented Jun 9, 2025

Deploy Preview for saturday-hack-night ready!

Name Link
🔨 Latest commit 4499074
🔍 Latest deploy log https://app.netlify.com/projects/saturday-hack-night/deploys/685eca5b1d147700080f061f
😎 Deploy Preview https://deploy-preview-87--saturday-hack-night.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

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

Copy link

coderabbitai bot commented Jun 9, 2025

"""

Walkthrough

This change transitions the project from a complex monorepo and Firebase/Next.js-based full-stack application to a focused single-package frontend built with React, Vite, and Tailwind CSS. All backend, serverless, and Next.js files are removed, along with monorepo tooling, in favor of a new, simpler structure featuring custom animated UI components, utility functions, and modern configuration files for Vite, Tailwind, ESLint, and TypeScript.

Changes

Files/Groups Change Summary
.firebaserc, firebase.json, firestore.rules, firestore.indexes.json, turbo.json, work-space.code-workspace, LICENSE Deleted Firebase, Firestore, monorepo, and workspace configuration files.
.github/pull_request_template.md Deleted GitHub pull request template.
apps/functions/** Deleted all backend Firebase Cloud Functions code, configuration, and dependencies.
apps/web/** Deleted all Next.js frontend app code, components, pages, hooks, contexts, utilities, types, and configuration.
packages/eslint-config-custom/** Deleted custom ESLint configuration package and its dependencies.
package.json Replaced monorepo config with a single-package setup for Vite, React, Tailwind, and related tooling.
.gitignore Revised and reorganized ignore rules for a single-package frontend project.
README.md Rewritten as a minimal Vite+React+Tailwind setup guide.
index.html Added as the new app HTML entry point with font and favicon links.
postcss.config.js, tailwind.config.js Added new PostCSS and Tailwind CSS configuration files with custom theme and plugin settings.
eslint.config.js Added new ESLint configuration for JS/JSX and React.
tsconfig.json, tsconfig.node.json Added new TypeScript configuration for the Vite project and Node context.
components.json Added UI component system configuration with Tailwind and path aliases.
src/App.jsx, src/pages/Home.jsx Added main React app and homepage with animated, interactive UI.
src/components/Carousel.jsx, Displaycards.jsx, FAQ.jsx, Looptext.jsx, Navbar.jsx, Partners.jsx, Register.jsx, Stats.jsx, Testimonials.jsx, TestimonialsColumn.jsx, Timer.jsx Added new UI components for carousel, cards, FAQ, looping text, navigation, partners, registration, stats, testimonials, and timer.
src/components/magicui/shimmer-button.jsx, shimmer-button.css Added animated shimmer button component and its styles.
src/index.css Added global CSS with Tailwind layers, custom fonts, colors, and animations.
src/lib/utils.js, src/lib/utils.ts Added utility functions for class name merging.
src/main.jsx Added React entry point initializing the app and enabling dark mode.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Browser
    participant ReactApp
    participant UIComponents

    User->>Browser: Navigates to index.html
    Browser->>ReactApp: Loads main.jsx, App.jsx, Home.jsx
    ReactApp->>UIComponents: Renders Navbar, Carousel, LoopText, Cards, FAQ, etc.
    UIComponents-->>User: Display interactive UI (carousel, stats, testimonials, etc.)
    User->>UIComponents: Interacts (hover, click, scroll)
    UIComponents-->>ReactApp: Update state/animations
    ReactApp-->>Browser: Renders updated UI
Loading

Poem

🐇✨
The old stack is gone, the monorepo's through,
Now Vite and Tailwind bring something new!
With shimmer and carousel, the UI's a delight,
Stats and testimonials, glowing through the night.
React hops ahead with a simpler scene—
This rabbit loves code that's fast and clean!
🌟
"""

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-06-27T16_45_25_713Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 13

🧹 Nitpick comments (13)
web/vite.config.js (1)

1-7: Consider enhancing the Vite configuration for production use.

The basic setup is correct, but for a production application replacing a Next.js frontend, consider adding common configurations:

 import { defineConfig } from 'vite'
 import react from '@vitejs/plugin-react'
+import path from 'path'

 // https://vite.dev/config/
 export default defineConfig({
   plugins: [react()],
+  resolve: {
+    alias: {
+      '@': path.resolve(__dirname, './src'),
+    },
+  },
+  build: {
+    rollupOptions: {
+      output: {
+        manualChunks: {
+          vendor: ['react', 'react-dom'],
+        },
+      },
+    },
+  },
+  server: {
+    port: 3000,
+    open: true,
+  },
 })
web/README.md (1)

1-31: Consider customizing the README for project-specific context.

The technical content is accurate and helpful, but consider adding project-specific information since this replaces the previous Next.js frontend for Saturday Hack Night.

Consider adding sections like:

  • Project description and purpose
  • Migration notes from the previous Next.js setup
  • Contributing guidelines
  • Deployment instructions
  • Links to Saturday Hack Night resources
web/eslint.config.js (2)

26-26: Refine the no-unused-vars rule pattern for better linting.

The current pattern '^[A-Z_]' might be too permissive, potentially hiding legitimate unused variable issues.

Consider a more specific pattern:

-      'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
+      'no-unused-vars': ['error', { 
+        varsIgnorePattern: '^_',
+        argsIgnorePattern: '^_',
+      }],

This pattern only ignores variables/arguments prefixed with underscore, which is a more common convention for intentionally unused variables.


1-33: Consider adding TypeScript support for future scalability.

Given this is a production application replacing a Next.js frontend, consider adding TypeScript support to match modern development practices.

You can enhance the configuration to support TypeScript when needed:

// Add to the files array when TypeScript is adopted
files: ['**/*.{js,jsx,ts,tsx}'],

And consider the TypeScript ESLint parser and rules mentioned in the README for production applications.

web/src/main.jsx (1)

6-10: Optional: Add null check for the root element
Guard against a missing <div id="root"> to avoid cryptic runtime errors:

- createRoot(document.getElementById('root')).render(
+ const container = document.getElementById('root');
+ if (!container) throw new Error('Root element not found');
+ createRoot(container).render(
web/src/App.jsx (1)

10-15: Enhance accessibility for dynamic text
Add live region attributes so screen readers announce updates:

- <div className="bg-blue-50 p-4 rounded-lg mb-6">
+ <div className="bg-blue-50 p-4 rounded-lg mb-6" role="status" aria-live="polite">
web/index.html (3)

7-7: Update the generic page title.

The title "Vite + React" should be updated to reflect the actual application name "Saturday HackNight" to improve branding and SEO.

-    <title>Vite + React</title>
+    <title>Saturday HackNight</title>

8-8: Consider optimizing font loading for performance.

Loading fonts from external CDN can impact performance. Consider:

  1. Using font-display: swap in the external stylesheet
  2. Adding rel="preconnect" for the font domain
  3. Self-hosting the fonts (which you're already doing in index.css)
+    <link rel="preconnect" href="https://api.fontshare.com">
     <link href="https://api.fontshare.com/v2/css?f[]=clash-display@200,300,400,500,600,700&display=swap" rel="stylesheet">

Or consider removing this external font since you're already defining the same fonts locally in index.css.


1-14: Consider adding essential meta tags for SEO and social sharing.

The HTML lacks important meta tags for SEO, social sharing, and accessibility.

   <head>
     <meta charset="UTF-8" />
+    <meta name="description" content="Saturday HackNight - Weekly coding and development meetup">
+    <meta name="keywords" content="hackathon, coding, development, Saturday, meetup">
+    <meta property="og:title" content="Saturday HackNight">
+    <meta property="og:description" content="Weekly coding and development meetup">
+    <meta property="og:type" content="website">
     <link rel="icon" type="image/svg+xml" href="/vite.svg" />
web/package.json (1)

6-11: Consider adding a test script.

The package.json lacks a test script, which is important for maintaining code quality in a frontend application.

   "scripts": {
     "dev": "vite",
     "build": "vite build",
     "lint": "eslint .",
+    "test": "vitest",
     "preview": "vite preview"
   },

You would also need to add vitest to devDependencies.

web/src/components/Navbar.jsx (2)

7-22: Optimize scroll handler performance.

The scroll event handler runs on every scroll event which can impact performance. Consider throttling or debouncing the scroll handler.

  useEffect(() => {
+    let ticking = false
+    
     const handleScroll = () => {
+      if (!ticking) {
+        requestAnimationFrame(() => {
           const offset = window.scrollY
           if (offset > 50) {
             setScrolled(true)
           } else {
             setScrolled(false)
           }
+          ticking = false
+        })
+        ticking = true
+      }
     }

     window.addEventListener('scroll', handleScroll)
     
     return () => {
       window.removeEventListener('scroll', handleScroll)
     }
   }, [])

32-36: Consider moving hard-coded colors to theme variables.

The component uses hard-coded color values like #FFFFE3. Consider moving these to CSS custom properties or Tailwind theme configuration for better maintainability.

In tailwind.config.js:

module.exports = {
  theme: {
    extend: {
      colors: {
        'brand-cream': '#FFFFE3',
      }
    }
  }
}

Then update the component:

-          ? 'bg-[#FFFFE3]/10 border border-[#FFFFE3]/20 shadow-lg' 
-          : 'bg-[#FFFFE3]/5 border border-[#FFFFE3]/10'
+          ? 'bg-brand-cream/10 border border-brand-cream/20 shadow-lg' 
+          : 'bg-brand-cream/5 border border-brand-cream/10'

Also applies to: 49-49

web/src/components/Register.jsx (1)

174-178: Consider adding touchcancel handler for better touch interaction

The touch event handlers might leave the component in a paused state if the user scrolls or the touch is cancelled.

           onMouseEnter={handlePause}
           onMouseLeave={handleResume}
           onTouchStart={handlePause}
           onTouchEnd={handleResume}
+          onTouchCancel={handleResume}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f04442a and 952e8ab.

⛔ Files ignored due to path filters (45)
  • .DS_Store is excluded by !**/.DS_Store
  • apps/web/public/fonts/ClashDisplayBold.woff is excluded by !**/*.woff
  • apps/web/public/fonts/ClashDisplayExtralight.woff is excluded by !**/*.woff
  • apps/web/public/fonts/ClashDisplayLight.woff is excluded by !**/*.woff
  • apps/web/public/fonts/ClashDisplayMedium.woff is excluded by !**/*.woff
  • apps/web/public/fonts/ClashDisplayRegular.woff is excluded by !**/*.woff
  • apps/web/public/fonts/ClashDisplaySemibold.woff is excluded by !**/*.woff
  • apps/web/public/images/TH.svg is excluded by !**/*.svg
  • apps/web/public/images/add-square.svg is excluded by !**/*.svg
  • apps/web/public/images/circle.svg is excluded by !**/*.svg
  • apps/web/public/images/codeBg.png is excluded by !**/*.png
  • apps/web/public/images/codeClub.png is excluded by !**/*.png
  • apps/web/public/images/favicon.svg is excluded by !**/*.svg
  • apps/web/public/images/leaderboard.png is excluded by !**/*.png
  • apps/web/public/images/logo.png is excluded by !**/*.png
  • apps/web/public/images/logo.svg is excluded by !**/*.svg
  • apps/web/public/images/logo_hover.svg is excluded by !**/*.svg
  • apps/web/public/images/medal-bronze.png is excluded by !**/*.png
  • apps/web/public/images/medal-gold.png is excluded by !**/*.png
  • apps/web/public/images/medal-silver.png is excluded by !**/*.png
  • apps/web/public/images/neon01.svg is excluded by !**/*.svg
  • apps/web/public/images/partners/engageSpot.svg is excluded by !**/*.svg
  • apps/web/public/images/partners/fof_kochi.png is excluded by !**/*.png
  • apps/web/public/images/physicalHack.png is excluded by !**/*.png
  • apps/web/public/images/seo-01.png is excluded by !**/*.png
  • apps/web/public/images/userFallback.png is excluded by !**/*.png
  • web/package-lock.json is excluded by !**/package-lock.json
  • web/public/vite.svg is excluded by !**/*.svg
  • web/src/assets/fonts/ClashDisplay-Bold.woff2 is excluded by !**/*.woff2
  • web/src/assets/fonts/ClashDisplay-Extralight.woff2 is excluded by !**/*.woff2
  • web/src/assets/fonts/ClashDisplay-Light.woff2 is excluded by !**/*.woff2
  • web/src/assets/fonts/ClashDisplay-Medium.woff2 is excluded by !**/*.woff2
  • web/src/assets/fonts/ClashDisplay-Regular.woff2 is excluded by !**/*.woff2
  • web/src/assets/fonts/ClashDisplay-Semibold.woff2 is excluded by !**/*.woff2
  • web/src/assets/fonts/ClashDisplay-Variable.woff2 is excluded by !**/*.woff2
  • web/src/assets/images/SHN.jpg is excluded by !**/*.jpg
  • web/src/assets/images/Satmain.jpg is excluded by !**/*.jpg
  • web/src/assets/images/carousal/IMG_5519.JPG is excluded by !**/*.jpg
  • web/src/assets/images/carousal/IMG_5699.JPG is excluded by !**/*.jpg
  • web/src/assets/images/carousal/IMG_5821.JPG is excluded by !**/*.jpg
  • web/src/assets/images/carousal/IMG_5850.JPG is excluded by !**/*.jpg
  • web/src/assets/images/carousal/IMG_5921.JPG is excluded by !**/*.jpg
  • web/src/assets/images/letxplore.jpg is excluded by !**/*.jpg
  • web/src/assets/react.svg is excluded by !**/*.svg
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (89)
  • .firebaserc (0 hunks)
  • .github/pull_request_template.md (0 hunks)
  • .gitignore (0 hunks)
  • LICENSE (0 hunks)
  • README.md (0 hunks)
  • apps/functions/.gitignore (0 hunks)
  • apps/functions/package.json (0 hunks)
  • apps/functions/src/index.ts (0 hunks)
  • apps/functions/tsconfig.json (0 hunks)
  • apps/web/.eslintrc (0 hunks)
  • apps/web/api/index.ts (0 hunks)
  • apps/web/components/CampusLeaderboard.tsx (0 hunks)
  • apps/web/components/CurrentEvent.tsx (0 hunks)
  • apps/web/components/Member.tsx (0 hunks)
  • apps/web/components/ParallaxView.tsx (0 hunks)
  • apps/web/components/ResultItems.tsx (0 hunks)
  • apps/web/components/UserLeaderboard.tsx (0 hunks)
  • apps/web/components/cards/Card.tsx (0 hunks)
  • apps/web/components/cards/EventCard.tsx (0 hunks)
  • apps/web/components/cards/index.ts (0 hunks)
  • apps/web/components/index.ts (0 hunks)
  • apps/web/components/modal/CreateTeamModal.tsx (0 hunks)
  • apps/web/components/modal/ProfileModal.tsx (0 hunks)
  • apps/web/components/modal/ResultsModal.tsx (0 hunks)
  • apps/web/components/modal/UpdateTeamModal.tsx (0 hunks)
  • apps/web/components/modal/index.ts (0 hunks)
  • apps/web/components/utils/Accordion.tsx (0 hunks)
  • apps/web/components/utils/LoadingAnimation.tsx (0 hunks)
  • apps/web/components/utils/Toast.tsx (0 hunks)
  • apps/web/components/utils/index.ts (0 hunks)
  • apps/web/contexts/authContext.tsx (0 hunks)
  • apps/web/contexts/index.ts (0 hunks)
  • apps/web/hooks/index.ts (0 hunks)
  • apps/web/hooks/useAuth.tsx (0 hunks)
  • apps/web/index.d.ts (0 hunks)
  • apps/web/layouts/BaseLayout.tsx (0 hunks)
  • apps/web/layouts/components/Footer.tsx (0 hunks)
  • apps/web/layouts/components/MobileBar.tsx (0 hunks)
  • apps/web/layouts/components/Navbar.tsx (0 hunks)
  • apps/web/layouts/components/index.ts (0 hunks)
  • apps/web/layouts/index.ts (0 hunks)
  • apps/web/next-env.d.ts (0 hunks)
  • apps/web/next.config.js (0 hunks)
  • apps/web/package.json (0 hunks)
  • apps/web/pages/_app.tsx (0 hunks)
  • apps/web/pages/_document.tsx (0 hunks)
  • apps/web/pages/api/college.ts (0 hunks)
  • apps/web/pages/error.tsx (0 hunks)
  • apps/web/pages/events.tsx (0 hunks)
  • apps/web/pages/index.tsx (0 hunks)
  • apps/web/pages/join.tsx (0 hunks)
  • apps/web/pages/leaderboard.tsx (0 hunks)
  • apps/web/public/js/squircle.js (0 hunks)
  • apps/web/public/style/clashDisplay.css (0 hunks)
  • apps/web/tsconfig.json (0 hunks)
  • apps/web/types/index.ts (0 hunks)
  • apps/web/utils/debounce.ts (0 hunks)
  • apps/web/utils/groupBy.ts (0 hunks)
  • apps/web/utils/index.ts (0 hunks)
  • apps/web/utils/redis.ts (0 hunks)
  • apps/web/utils/validators/index.ts (0 hunks)
  • apps/web/utils/validators/profileValidator.ts (0 hunks)
  • apps/web/utils/validators/teamValidator.ts (0 hunks)
  • firebase.json (0 hunks)
  • firestore.indexes.json (0 hunks)
  • firestore.rules (0 hunks)
  • next-env.d.ts (0 hunks)
  • package.json (0 hunks)
  • packages/eslint-config-custom/index.js (0 hunks)
  • packages/eslint-config-custom/package.json (0 hunks)
  • turbo.json (0 hunks)
  • web/.gitignore (1 hunks)
  • web/README.md (1 hunks)
  • web/eslint.config.js (1 hunks)
  • web/index.html (1 hunks)
  • web/package.json (1 hunks)
  • web/postcss.config.js (1 hunks)
  • web/src/App.jsx (1 hunks)
  • web/src/components/Carousel.jsx (1 hunks)
  • web/src/components/Looptext.jsx (1 hunks)
  • web/src/components/Navbar.jsx (1 hunks)
  • web/src/components/Register.jsx (1 hunks)
  • web/src/index.css (1 hunks)
  • web/src/lib/utils.js (1 hunks)
  • web/src/main.jsx (1 hunks)
  • web/src/pages/Home.jsx (1 hunks)
  • web/tailwind.config.js (1 hunks)
  • web/vite.config.js (1 hunks)
  • work-space.code-workspace (0 hunks)
💤 Files with no reviewable changes (72)
  • next-env.d.ts
  • apps/web/contexts/index.ts
  • .gitignore
  • firestore.indexes.json
  • apps/web/next-env.d.ts
  • firebase.json
  • LICENSE
  • apps/web/.eslintrc
  • apps/web/components/cards/index.ts
  • .github/pull_request_template.md
  • apps/web/layouts/components/index.ts
  • apps/functions/package.json
  • apps/functions/.gitignore
  • apps/web/components/modal/index.ts
  • apps/web/layouts/index.ts
  • packages/eslint-config-custom/index.js
  • apps/web/package.json
  • apps/web/components/modal/ProfileModal.tsx
  • packages/eslint-config-custom/package.json
  • apps/web/components/utils/index.ts
  • apps/web/utils/index.ts
  • .firebaserc
  • apps/web/components/cards/Card.tsx
  • apps/web/components/index.ts
  • apps/web/utils/validators/index.ts
  • apps/web/next.config.js
  • work-space.code-workspace
  • apps/functions/tsconfig.json
  • apps/web/pages/_app.tsx
  • apps/web/hooks/useAuth.tsx
  • package.json
  • apps/web/components/utils/LoadingAnimation.tsx
  • apps/web/utils/validators/teamValidator.ts
  • apps/web/pages/leaderboard.tsx
  • apps/web/components/CampusLeaderboard.tsx
  • apps/web/tsconfig.json
  • apps/web/layouts/components/MobileBar.tsx
  • apps/web/components/CurrentEvent.tsx
  • apps/web/utils/validators/profileValidator.ts
  • turbo.json
  • apps/web/pages/api/college.ts
  • apps/web/contexts/authContext.tsx
  • apps/web/layouts/BaseLayout.tsx
  • apps/web/components/UserLeaderboard.tsx
  • apps/web/hooks/index.ts
  • apps/web/layouts/components/Navbar.tsx
  • apps/web/api/index.ts
  • apps/web/pages/_document.tsx
  • apps/web/components/ParallaxView.tsx
  • apps/web/pages/events.tsx
  • apps/web/pages/error.tsx
  • apps/web/utils/debounce.ts
  • apps/web/components/utils/Toast.tsx
  • apps/web/components/modal/UpdateTeamModal.tsx
  • apps/web/components/utils/Accordion.tsx
  • apps/web/types/index.ts
  • apps/web/components/Member.tsx
  • apps/web/layouts/components/Footer.tsx
  • apps/web/components/modal/ResultsModal.tsx
  • apps/web/pages/index.tsx
  • apps/web/utils/groupBy.ts
  • apps/web/pages/join.tsx
  • firestore.rules
  • apps/web/components/modal/CreateTeamModal.tsx
  • apps/web/components/ResultItems.tsx
  • apps/web/public/style/clashDisplay.css
  • README.md
  • apps/web/public/js/squircle.js
  • apps/web/utils/redis.ts
  • apps/web/index.d.ts
  • apps/web/components/cards/EventCard.tsx
  • apps/functions/src/index.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
web/src/App.jsx (1)
web/src/components/Looptext.jsx (1)
  • LoopText (5-70)
web/src/main.jsx (1)
web/src/pages/Home.jsx (1)
  • Home (10-635)
🔇 Additional comments (10)
web/.gitignore (1)

1-25: LGTM! Comprehensive .gitignore coverage.

The .gitignore file appropriately covers all necessary patterns for a React + Vite project including logs, dependencies, build artifacts, editor files, and OS-specific files.

web/postcss.config.js (1)

1-6: Approve PostCSS configuration
The ESM-style export with Tailwind CSS and Autoprefixer plugins is correctly set up for a Vite + Tailwind stack.

web/src/main.jsx (1)

1-4: Imports are correct for React entry point
Using StrictMode, createRoot, and the global stylesheet is spot-on for a Vite-powered React app.

web/src/lib/utils.js (1)

4-6: Utility function cn is concise and effective
Combining clsx with twMerge will streamline Tailwind class merging across the codebase.

web/src/App.jsx (2)

1-3: Verify import path casing for LoopText
Ensure the component file is named LoopText.jsx (not Looptext.jsx) to avoid case-sensitive resolution issues on certain OSes.


6-15: Layout uses Tailwind utilities cleanly
The full-screen container and centered card with LoopText are well-structured and readable.

web/src/index.css (1)

1-3: Good structure with Tailwind CSS integration.

The CSS file properly integrates Tailwind CSS layers and provides a clean foundation for the application styling. The custom font class and CSS custom properties are well-implemented.

Also applies to: 53-55

web/package.json (1)

12-32: Well-structured dependency management.

The package.json shows good separation between runtime and development dependencies, with modern tooling choices that align well with the Vite + React + Tailwind CSS stack.

web/src/components/Navbar.jsx (1)

1-65: Well-implemented navbar component with modern React patterns.

The component demonstrates good React practices with proper hook usage, event listener cleanup, and smooth animations. The glassmorphism design and scroll-based interactions create a modern user experience.

web/src/components/Looptext.jsx (1)

10-23: Well-implemented interval management

The useEffect hook properly handles the timer lifecycle with appropriate cleanup and dependency tracking.

Comment on lines 1 to 3
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix clsx import
The clsx library exports a default function, so the named import will be undefined.

- import { clsx } from 'clsx';
+ import clsx from 'clsx';
📝 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
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
import clsx from 'clsx';
import { twMerge } from 'tailwind-merge';
🤖 Prompt for AI Agents
In web/src/lib/utils.js at lines 1 to 3, the import of `clsx` is incorrect
because `clsx` exports a default function, not a named export. Change the import
statement to use a default import instead of a named import by removing the
curly braces around `clsx`.

Comment on lines 3 to 7
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
],
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix content path for components folder
Your components live under src/components, so update the glob to pick them up:

-    "./components/**/*.{js,ts,jsx,tsx,mdx}", 
+    "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 
📝 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
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
],
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
],
🤖 Prompt for AI Agents
In web/tailwind.config.js around lines 3 to 7, the content path for the
components folder is incorrect because it points to
"./components/**/*.{js,ts,jsx,tsx,mdx}" instead of the correct
"./src/components/**/*.{js,ts,jsx,tsx,mdx}". Update the glob pattern to reflect
the correct directory structure by prefixing "components" with "src/".

Comment on lines 15 to 16
plugins: [require("tailwindcss-animate")],
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid mixing ESM export with CommonJS require
An ESM config file using export default can’t call require. Either switch the file to CommonJS (module.exports = { … }) or import the plugin:

- plugins: [require("tailwindcss-animate")],
+ import animate from 'tailwindcss-animate';
+ plugins: [animate],

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In web/tailwind.config.js at lines 15-16, the file uses ESM export syntax but
calls CommonJS require for the plugin, which is incompatible. To fix this,
either convert the entire file to CommonJS by replacing `export default` with
`module.exports =` and keep using require, or switch to ESM imports by replacing
the require call with an import statement at the top and keep using `export
default`.

Comment on lines 6 to 27
@font-face {
font-family: 'ClashDisplay';
src: url('./assets/fonts/ClashDisplay-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'ClashDisplay';
src: url('./assets/fonts/ClashDisplay-Medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'ClashDisplay';
src: url('./assets/fonts/ClashDisplay-Bold.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
}
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify font file paths exist.

The font-face declarations reference local font files. Ensure these WOFF2 files exist in the specified paths.


🏁 Script executed:

#!/bin/bash
# Check if ClashDisplay font files exist
fd -t f "ClashDisplay.*\.woff2" web/src/assets/fonts/

Length of output: 390


Font files verified
All referenced ClashDisplay .woff2 files exist in web/src/assets/fonts/—no missing assets.

Additional suggestions before approval:

  • Accessibility: the custom .cursor-none utility removes all cursors; consider retaining a default pointer or providing fallbacks to avoid confusing keyboard or assistive-tech users.
  • Color semantics: root variables use raw RGB values—consider semantic names or HSL/HEX notation for clarity and maintainability.

Overall structure and Tailwind setup look solid. Once these are addressed, this is good to merge.

🤖 Prompt for AI Agents
In web/src/index.css lines 6 to 27, the font-face declarations correctly
reference existing ClashDisplay WOFF2 font files, so no changes are needed
there. However, before merging, review the .cursor-none utility to ensure it
does not hinder accessibility by removing all cursors; consider modifying it to
retain a default pointer or provide fallbacks for keyboard and assistive
technology users. Also, update the root CSS variables to use semantic color
names or switch from raw RGB values to HSL or HEX notation to improve clarity
and maintainability.

Comment on lines 34 to 44
.custom-cursor-enabled {
cursor: none !important;
}

.custom-cursor-enabled a,
.custom-cursor-enabled button,
.custom-cursor-enabled input,
.custom-cursor-enabled textarea,
.custom-cursor-enabled select {
cursor: none !important;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider accessibility impact of removing all cursors.

The .custom-cursor-enabled class removes cursors entirely, which can significantly impact accessibility for users who rely on visual cursor feedback for navigation and interaction.

Consider implementing a custom cursor that still provides visual feedback:

 .custom-cursor-enabled {
-  cursor: none !important;
+  cursor: url('path/to/custom-cursor.svg'), auto !important;
 }

 .custom-cursor-enabled a,
 .custom-cursor-enabled button,
 .custom-cursor-enabled input,
 .custom-cursor-enabled textarea,
 .custom-cursor-enabled select {
-  cursor: none !important;
+  cursor: url('path/to/custom-cursor-hover.svg'), pointer !important;
 }

Or provide a toggle mechanism to disable custom cursors for accessibility.

📝 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
.custom-cursor-enabled {
cursor: none !important;
}
.custom-cursor-enabled a,
.custom-cursor-enabled button,
.custom-cursor-enabled input,
.custom-cursor-enabled textarea,
.custom-cursor-enabled select {
cursor: none !important;
}
.custom-cursor-enabled {
cursor: url('path/to/custom-cursor.svg'), auto !important;
}
.custom-cursor-enabled a,
.custom-cursor-enabled button,
.custom-cursor-enabled input,
.custom-cursor-enabled textarea,
.custom-cursor-enabled select {
cursor: url('path/to/custom-cursor-hover.svg'), pointer !important;
}
🤖 Prompt for AI Agents
In web/src/index.css around lines 34 to 44, the .custom-cursor-enabled class
removes all cursor visibility, which harms accessibility by removing visual
feedback. Instead of setting cursor: none !important, update the styles to use a
custom cursor image or style that remains visible to provide visual feedback.
Alternatively, implement a toggle mechanism in the UI to allow users to disable
the custom cursor and restore default cursor behavior for better accessibility.

alt={title}
src={src}
onLoad={imageLoaded}
loading="eager"
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider lazy loading for carousel images

Using loading="eager" forces all carousel images to load immediately, which can impact initial page load performance.

-            loading="eager"
+            loading={current === index ? "eager" : "lazy"}
📝 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
loading="eager"
loading={current === index ? "eager" : "lazy"}
🤖 Prompt for AI Agents
In web/src/components/Carousel.jsx at line 120, the use of loading="eager" on
carousel images forces all images to load immediately, negatively impacting page
load performance. Change the loading attribute to "lazy" to defer loading images
until they are about to enter the viewport, improving initial load speed.

Comment on lines 44 to 65
useEffect(() => {
const animate = () => {
if (!slideRef.current) return;

const x = xRef.current;
const y = yRef.current;

slideRef.current.style.setProperty("--x", `${x}px`);
slideRef.current.style.setProperty("--y", `${y}px`);

frameRef.current = requestAnimationFrame(animate);
};

frameRef.current = requestAnimationFrame(animate);

return () => {
if (frameRef.current) {
cancelAnimationFrame(frameRef.current);
}
};
}, []);

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Optimize requestAnimationFrame to run only on hover

The animation frame runs continuously even when the slide is not being hovered, causing unnecessary CPU usage and repaints.

   useEffect(() => {
+    if (!slideRef.current) return;
+    
+    let isHovering = false;
+    
     const animate = () => {
-      if (!slideRef.current) return;
+      if (!slideRef.current || !isHovering) return;

       const x = xRef.current;
       const y = yRef.current;

       slideRef.current.style.setProperty("--x", `${x}px`);
       slideRef.current.style.setProperty("--y", `${y}px`);

-      frameRef.current = requestAnimationFrame(animate);
+      if (isHovering) {
+        frameRef.current = requestAnimationFrame(animate);
+      }
     };

-    frameRef.current = requestAnimationFrame(animate);
+    const handleMouseEnter = () => {
+      isHovering = true;
+      frameRef.current = requestAnimationFrame(animate);
+    };
+    
+    const handleMouseLeave = () => {
+      isHovering = false;
+      if (frameRef.current) {
+        cancelAnimationFrame(frameRef.current);
+      }
+    };
+    
+    const el = slideRef.current;
+    el.addEventListener('mouseenter', handleMouseEnter);
+    el.addEventListener('mouseleave', handleMouseLeave);

     return () => {
       if (frameRef.current) {
         cancelAnimationFrame(frameRef.current);
       }
+      el.removeEventListener('mouseenter', handleMouseEnter);
+      el.removeEventListener('mouseleave', handleMouseLeave);
     };
   }, []);
📝 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(() => {
const animate = () => {
if (!slideRef.current) return;
const x = xRef.current;
const y = yRef.current;
slideRef.current.style.setProperty("--x", `${x}px`);
slideRef.current.style.setProperty("--y", `${y}px`);
frameRef.current = requestAnimationFrame(animate);
};
frameRef.current = requestAnimationFrame(animate);
return () => {
if (frameRef.current) {
cancelAnimationFrame(frameRef.current);
}
};
}, []);
useEffect(() => {
if (!slideRef.current) return;
let isHovering = false;
const animate = () => {
if (!slideRef.current || !isHovering) return;
const x = xRef.current;
const y = yRef.current;
slideRef.current.style.setProperty("--x", `${x}px`);
slideRef.current.style.setProperty("--y", `${y}px`);
if (isHovering) {
frameRef.current = requestAnimationFrame(animate);
}
};
const handleMouseEnter = () => {
isHovering = true;
frameRef.current = requestAnimationFrame(animate);
};
const handleMouseLeave = () => {
isHovering = false;
if (frameRef.current) {
cancelAnimationFrame(frameRef.current);
}
};
const el = slideRef.current;
el.addEventListener("mouseenter", handleMouseEnter);
el.addEventListener("mouseleave", handleMouseLeave);
return () => {
if (frameRef.current) {
cancelAnimationFrame(frameRef.current);
}
el.removeEventListener("mouseenter", handleMouseEnter);
el.removeEventListener("mouseleave", handleMouseLeave);
};
}, []);
🤖 Prompt for AI Agents
In web/src/components/Carousel.jsx around lines 44 to 65, the
requestAnimationFrame animation runs continuously regardless of hover state,
causing unnecessary CPU usage. Modify the code to start the animation loop only
when the slide is hovered and cancel it when the hover ends. Use event listeners
or React state to track hover and conditionally trigger requestAnimationFrame
accordingly.

</div>

{/* Add CSS for the special effects */}
<style jsx="true">{`
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use boolean value for jsx prop

The jsx prop should be a boolean value, not a string.

-      <style jsx="true">{`
+      <style jsx={true}>{`
📝 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
<style jsx="true">{`
<style jsx={true}>{`
🤖 Prompt for AI Agents
In web/src/pages/Home.jsx at line 527, the jsx prop is currently set as a string
"true". Change this to a boolean value true without quotes to correctly use the
jsx prop as a boolean.

Comment on lines 68 to 130
let timeout

// Type current line character by character
const typeLine = async (line) => {
setIsTyping(true)
for (let i = 0; i <= line.length; i++) {
await new Promise(resolve => {
timeout = setTimeout(() => {
setCurrentText(line.substring(0, i))
resolve()
}, 100)
})
}

// Pause at the end of typing
await new Promise(resolve => {
timeout = setTimeout(resolve, 800)
})
}

// Backspace the current line character by character
const backspaceLine = async (line) => {
setIsTyping(false)
for (let i = line.length; i >= 0; i--) {
await new Promise(resolve => {
timeout = setTimeout(() => {
setCurrentText(line.substring(0, i))
resolve()
}, 50) // Faster deletion
})
}

// Short pause after deletion
await new Promise(resolve => {
timeout = setTimeout(resolve, 300)
})
}

const runTypewriter = async () => {
// Loop indefinitely through all lines
while (true) {
for (let i = 0; i < lines.length; i++) {
await typeLine(lines[i])

// Don't backspace the final line on the last iteration
if (i < lines.length - 1) {
await backspaceLine(lines[i])
} else {
// Pause longer on the final line before restarting
await new Promise(resolve => {
timeout = setTimeout(resolve, 3000)
})
await backspaceLine(lines[i])
}
}
}
}

runTypewriter()

// Cleanup
return () => clearTimeout(timeout)
}, [])
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix memory leak in typewriter animation

The infinite while(true) loop continues running after component unmount, causing a memory leak.

   useEffect(() => {
     let timeout
+    let isActive = true
     
     // ... (typeLine and backspaceLine functions remain the same)
     
     const runTypewriter = async () => {
       // Loop indefinitely through all lines
-      while (true) {
+      while (isActive) {
         for (let i = 0; i < lines.length; i++) {
+          if (!isActive) break;
           await typeLine(lines[i])
           
           // Don't backspace the final line on the last iteration
           if (i < lines.length - 1) {
             await backspaceLine(lines[i])
           } else {
             // Pause longer on the final line before restarting
             await new Promise(resolve => {
               timeout = setTimeout(resolve, 3000)
             })
             await backspaceLine(lines[i])
           }
         }
       }
     }
     
     runTypewriter()
     
     // Cleanup
-    return () => clearTimeout(timeout)
+    return () => {
+      isActive = false
+      clearTimeout(timeout)
+    }
   }, [])
📝 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
let timeout
// Type current line character by character
const typeLine = async (line) => {
setIsTyping(true)
for (let i = 0; i <= line.length; i++) {
await new Promise(resolve => {
timeout = setTimeout(() => {
setCurrentText(line.substring(0, i))
resolve()
}, 100)
})
}
// Pause at the end of typing
await new Promise(resolve => {
timeout = setTimeout(resolve, 800)
})
}
// Backspace the current line character by character
const backspaceLine = async (line) => {
setIsTyping(false)
for (let i = line.length; i >= 0; i--) {
await new Promise(resolve => {
timeout = setTimeout(() => {
setCurrentText(line.substring(0, i))
resolve()
}, 50) // Faster deletion
})
}
// Short pause after deletion
await new Promise(resolve => {
timeout = setTimeout(resolve, 300)
})
}
const runTypewriter = async () => {
// Loop indefinitely through all lines
while (true) {
for (let i = 0; i < lines.length; i++) {
await typeLine(lines[i])
// Don't backspace the final line on the last iteration
if (i < lines.length - 1) {
await backspaceLine(lines[i])
} else {
// Pause longer on the final line before restarting
await new Promise(resolve => {
timeout = setTimeout(resolve, 3000)
})
await backspaceLine(lines[i])
}
}
}
}
runTypewriter()
// Cleanup
return () => clearTimeout(timeout)
}, [])
useEffect(() => {
let timeout
+ let isActive = true
// Type current line character by character
const typeLine = async (line) => {
setIsTyping(true)
for (let i = 0; i <= line.length; i++) {
await new Promise(resolve => {
timeout = setTimeout(() => {
setCurrentText(line.substring(0, i))
resolve()
}, 100)
})
}
// Pause at the end of typing
await new Promise(resolve => {
timeout = setTimeout(resolve, 800)
})
}
// Backspace the current line character by character
const backspaceLine = async (line) => {
setIsTyping(false)
for (let i = line.length; i >= 0; i--) {
await new Promise(resolve => {
timeout = setTimeout(() => {
setCurrentText(line.substring(0, i))
resolve()
}, 50) // Faster deletion
})
}
// Short pause after deletion
await new Promise(resolve => {
timeout = setTimeout(resolve, 300)
})
}
const runTypewriter = async () => {
// Loop indefinitely through all lines
- while (true) {
+ while (isActive) {
for (let i = 0; i < lines.length; i++) {
+ if (!isActive) break;
await typeLine(lines[i])
// Don't backspace the final line on the last iteration
if (i < lines.length - 1) {
await backspaceLine(lines[i])
} else {
// Pause longer on the final line before restarting
await new Promise(resolve => {
timeout = setTimeout(resolve, 3000)
})
await backspaceLine(lines[i])
}
}
}
}
runTypewriter()
// Cleanup
- return () => clearTimeout(timeout)
+ return () => {
+ isActive = false
+ clearTimeout(timeout)
+ }
}, [])
🤖 Prompt for AI Agents
In web/src/pages/Home.jsx around lines 68 to 130, the infinite while(true) loop
in the runTypewriter function continues running after the component unmounts,
causing a memory leak. To fix this, introduce a mounted flag or a cancellation
mechanism that stops the loop when the component unmounts. Set this flag to
false in the cleanup function and check it inside the loop to break out and
prevent further execution. Also, ensure all timeouts are cleared on unmount to
avoid lingering async operations.

Comment on lines 12 to 54
const [gridPoints, setGridPoints] = useState([])
const { scrollYProgress } = useScroll()
const [showParticles, setShowParticles] = useState(false)



// Parallax effect values
// Reduced parallax for smoother experience
const bgY = useTransform(scrollYProgress, [0, 1], ['0%', '10%'])

// Generate grid points
useEffect(() => {
const generateGrid = () => {
const points = []
const cols = 15
const rows = 10

for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
points.push({
id: `${i}-${j}`,
x: (i * 100) / (cols - 1),
y: (j * 100) / (rows - 1),
size: 4,
opacity: 0.15,
highlighted: false
})
}
}
setGridPoints(points)
}

generateGrid()

// Show particles after initial load for better performance
const timer = setTimeout(() => {
setShowParticles(true)
}, 500)

return () => {
clearTimeout(timer)
}
}, [])
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unused state variables

The gridPoints and showParticles states are initialized but never used in the render output.

-  const [gridPoints, setGridPoints] = useState([])
   const { scrollYProgress } = useScroll()
-  const [showParticles, setShowParticles] = useState(false)
   
   // ... rest of the code ...
   
-  // Generate grid points
-  useEffect(() => {
-    const generateGrid = () => {
-      const points = []
-      const cols = 15
-      const rows = 10
-      
-      for (let i = 0; i < cols; i++) {
-        for (let j = 0; j < rows; j++) {
-          points.push({
-            id: `${i}-${j}`,
-            x: (i * 100) / (cols - 1),
-            y: (j * 100) / (rows - 1),
-            size: 4,
-            opacity: 0.15,
-            highlighted: false
-          })
-        }
-      }
-      setGridPoints(points)
-    }
-    
-    generateGrid()
-    
-    // Show particles after initial load for better performance
-    const timer = setTimeout(() => {
-      setShowParticles(true)
-    }, 500)
-    
-    return () => {
-      clearTimeout(timer)
-    }
-  }, [])
📝 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
const [gridPoints, setGridPoints] = useState([])
const { scrollYProgress } = useScroll()
const [showParticles, setShowParticles] = useState(false)
// Parallax effect values
// Reduced parallax for smoother experience
const bgY = useTransform(scrollYProgress, [0, 1], ['0%', '10%'])
// Generate grid points
useEffect(() => {
const generateGrid = () => {
const points = []
const cols = 15
const rows = 10
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
points.push({
id: `${i}-${j}`,
x: (i * 100) / (cols - 1),
y: (j * 100) / (rows - 1),
size: 4,
opacity: 0.15,
highlighted: false
})
}
}
setGridPoints(points)
}
generateGrid()
// Show particles after initial load for better performance
const timer = setTimeout(() => {
setShowParticles(true)
}, 500)
return () => {
clearTimeout(timer)
}
}, [])
// Removed unused gridPoints/showParticles state and effect
const { scrollYProgress } = useScroll()
// Parallax effect values
// Reduced parallax for smoother experience
const bgY = useTransform(scrollYProgress, [0, 1], ['0%', '10%'])
// ...rest of your code...
🤖 Prompt for AI Agents
In web/src/pages/Home.jsx between lines 12 and 54, the state variables
gridPoints and showParticles are declared and updated but never used in the
component's render output. To fix this, remove the declarations and all related
code that sets or updates these states, including the useEffect hook that
generates gridPoints and sets showParticles, to clean up unused state and
improve code clarity.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 12

🧹 Nitpick comments (11)
vite.config.js (1)

12-15: Remove redundant JSX configuration.

The manual JSX factory and fragment configuration in esbuild is unnecessary when using @vitejs/plugin-react, as the plugin already handles JSX transformation automatically.

-  esbuild: {
-    jsxFactory: 'React.createElement',
-    jsxFragment: 'React.Fragment',
-  },
src/components/Timer.jsx (2)

1-1: Remove unnecessary "use client" directive.

The "use client" directive is specific to Next.js 13+ and is not needed in a Vite React application.

-"use client";
-

7-7: Consider making the target date configurable.

The hardcoded target date limits reusability. Consider accepting it as a prop for better component flexibility.

-const Timer = () => {
-  const targetDate = new Date("2025-07-03");
+const Timer = ({ targetDate = new Date("2025-07-03") }) => {
src/components/FAQ.jsx (1)

1-1: Remove unnecessary "use client" directive.

The "use client" directive is specific to Next.js App Router and is not needed in a Vite-based React application. This directive is inconsistently used across components and should be removed for consistency.

-"use client";
-
src/components/Looptext.jsx (1)

1-1: Remove unnecessary "use client" directive.

Similar to other components, this directive is not needed for Vite-based React applications and should be removed for consistency.

-'use client';
src/components/Register.jsx (1)

3-91: Consider extracting TABS constant to improve maintainability.

The large TABS constant takes up significant space in the component file. Consider moving it to a separate constants file for better organization.

Create a new file src/constants/registerTabs.js:

export const REGISTER_TABS = [
  // Move the entire TABS array here
];

Then import it in the component:

+import { REGISTER_TABS as TABS } from '../constants/registerTabs';
-const TABS = [
-  // ... all the tab data
-];
src/components/TestimonialsColumn.jsx (1)

1-1: Remove unnecessary "use client" directive.

Consistent with other components, this directive should be removed for Vite-based applications.

-"use client";
-
src/components/Navbar.jsx (2)

84-84: Move displayName assignment before the export statement.

The displayName should be assigned before the export for better code organization and consistency.

-export default Navbar;
-
-// Add this at the top of the file
-Navbar.displayName = 'Navbar';
+// Add display name for debugging
+Navbar.displayName = 'Navbar';
+
+export default Navbar;

61-61: Consider improving the Register Now button behavior.

Scrolling to the very bottom of the page might not provide the best user experience. Consider scrolling to a specific registration section instead.

-onClick={() => window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' })}
+onClick={() => {
+  const registerSection = document.getElementById('register-section');
+  if (registerSection) {
+    registerSection.scrollIntoView({ behavior: 'smooth' });
+  } else {
+    window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
+  }
+}}

Make sure to add an id="register-section" to your register component container.

src/pages/Home.jsx (1)

21-22: Remove unnecessary empty lines

Clean up the extra empty lines for better code organization.

  const [showParticles, setShowParticles] = useState(false)
  
-
-
  // Parallax effect values
src/components/Carousel.jsx (1)

3-7: Consider lazy loading images for better performance

While direct imports are good for bundling, consider implementing lazy loading for carousel images to improve initial page load.

import { lazy, Suspense } from 'react';

// Lazy load images
const images = {
  img1: () => import('../assets/images/carousal/IMG_5519.JPG'),
  img2: () => import('../assets/images/carousal/IMG_5699.JPG'),
  // ... etc
};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 952e8ab and 44df7f9.

⛔ Files ignored due to path filters (20)
  • package-lock.json is excluded by !**/package-lock.json
  • public/vite.svg is excluded by !**/*.svg
  • src/assets/fonts/ClashDisplay-Bold.woff2 is excluded by !**/*.woff2
  • src/assets/fonts/ClashDisplay-Extralight.woff2 is excluded by !**/*.woff2
  • src/assets/fonts/ClashDisplay-Light.woff2 is excluded by !**/*.woff2
  • src/assets/fonts/ClashDisplay-Medium.woff2 is excluded by !**/*.woff2
  • src/assets/fonts/ClashDisplay-Regular.woff2 is excluded by !**/*.woff2
  • src/assets/fonts/ClashDisplay-Semibold.woff2 is excluded by !**/*.woff2
  • src/assets/fonts/ClashDisplay-Variable.woff2 is excluded by !**/*.woff2
  • src/assets/images/SHN.jpg is excluded by !**/*.jpg
  • src/assets/images/Satmain.jpg is excluded by !**/*.jpg
  • src/assets/images/carousal/IMG_5519.JPG is excluded by !**/*.jpg
  • src/assets/images/carousal/IMG_5699.JPG is excluded by !**/*.jpg
  • src/assets/images/carousal/IMG_5821.JPG is excluded by !**/*.jpg
  • src/assets/images/carousal/IMG_5850.JPG is excluded by !**/*.jpg
  • src/assets/images/carousal/IMG_5921.JPG is excluded by !**/*.jpg
  • src/assets/images/letxplore.jpg is excluded by !**/*.jpg
  • src/assets/images/partners/engagespot.png is excluded by !**/*.png
  • src/assets/images/partners/fof.png is excluded by !**/*.png
  • src/assets/react.svg is excluded by !**/*.svg
📒 Files selected for processing (25)
  • .gitignore (1 hunks)
  • README.md (1 hunks)
  • eslint.config.js (1 hunks)
  • index.html (1 hunks)
  • package.json (1 hunks)
  • postcss.config.js (1 hunks)
  • src/App.jsx (1 hunks)
  • src/components/Carousel.jsx (1 hunks)
  • src/components/Displaycards.jsx (1 hunks)
  • src/components/DisplaycardsNew.jsx (1 hunks)
  • src/components/FAQ.jsx (1 hunks)
  • src/components/Looptext.jsx (1 hunks)
  • src/components/Navbar.jsx (1 hunks)
  • src/components/Partners.jsx (1 hunks)
  • src/components/Register.jsx (1 hunks)
  • src/components/Stats.jsx (1 hunks)
  • src/components/Testimonials.jsx (1 hunks)
  • src/components/TestimonialsColumn.jsx (1 hunks)
  • src/components/Timer.jsx (1 hunks)
  • src/index.css (1 hunks)
  • src/lib/utils.js (1 hunks)
  • src/main.jsx (1 hunks)
  • src/pages/Home.jsx (1 hunks)
  • tailwind.config.js (1 hunks)
  • vite.config.js (1 hunks)
✅ Files skipped from review due to trivial changes (11)
  • postcss.config.js
  • src/main.jsx
  • src/lib/utils.js
  • tailwind.config.js
  • index.html
  • eslint.config.js
  • src/components/Stats.jsx
  • src/components/Displaycards.jsx
  • src/index.css
  • src/components/Partners.jsx
  • src/components/DisplaycardsNew.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/App.jsx (1)
src/components/Looptext.jsx (1)
  • LoopText (5-70)
src/components/TestimonialsColumn.jsx (1)
src/components/Testimonials.jsx (1)
  • testimonials (6-61)
🔇 Additional comments (12)
.gitignore (1)

1-25: Well-structured gitignore file.

The gitignore patterns are comprehensive and well-organized, covering all necessary development artifacts for a Vite + React project.

README.md (1)

1-31: Clear and concise documentation.

The README provides essential information for getting started with the React + Vite + Tailwind setup. The structure is clean and includes all necessary commands and technology references.

src/App.jsx (1)

4-24: Clean component structure with good styling.

The App component is well-structured with proper use of Tailwind CSS classes and a clear layout hierarchy. The LoopText integration demonstrates the component effectively.

src/components/Timer.jsx (2)

10-29: Solid timer logic implementation.

The countdown calculation logic is correctly implemented with proper cleanup and edge case handling when the timer expires.


40-56:

✅ Verification successful

Verify custom font class availability.

The component uses font-clash class extensively. Ensure this custom font is properly configured in your Tailwind CSS setup.

Check if the custom font class is defined in Tailwind configuration:


🏁 Script executed:

#!/bin/bash
# Check for font-clash definition in Tailwind config
fd -t f "tailwind.config" . --exec cat {} \; | grep -i "clash"

Length of output: 111


Custom font class verified
The font-clash utility is defined in your Tailwind config (clash: ['Clash Display', 'sans-serif']), so this component’s usage of font-clash is valid.

No changes needed.

src/components/Looptext.jsx (1)

5-70: Well-implemented text cycling component.

The component correctly handles:

  • Interval cleanup and pause functionality
  • Proper use of AnimatePresence for smooth transitions
  • Children array management with React.Children.toArray
  • Hover state management
src/components/Register.jsx (1)

108-161: Well-implemented auto-cycling and responsive positioning logic.

The component correctly handles:

  • Auto-slide with pause on interaction
  • Dynamic line positioning calculations
  • Responsive recalculation on window resize
  • Proper cleanup of timers and event listeners
src/components/TestimonialsColumn.jsx (1)

9-19: Excellent infinite scroll animation implementation.

The use of translateY: "-50%" with duplicated content creates a seamless infinite scroll effect. The linear easing and repeat configuration are perfect for this use case.

src/components/Navbar.jsx (1)

4-78: Well-implemented responsive navbar with smooth animations.

The component excellently handles:

  • Dynamic styling based on scroll position
  • Proper event listener cleanup
  • Smooth framer-motion animations
  • Glassmorphism design with backdrop blur
  • Interactive hover effects
src/components/Testimonials.jsx (1)

88-92: Good responsive design implementation

The column visibility control and mask gradient effect create an elegant responsive layout.

src/components/Carousel.jsx (2)

38-140: Excellent implementation of 3D parallax effect

The Slide component demonstrates excellent use of React patterns:

  • Proper use of refs for performance
  • RequestAnimationFrame for smooth animations
  • Clean event handling
  • Good separation of concerns

144-192: Well-implemented carousel with good UX patterns

The carousel implementation includes excellent features:

  • Autoplay with pause on hover
  • Smooth transitions
  • Accessibility support with aria-labelledby
  • Clean state management

@@ -0,0 +1,26 @@
import React from 'react';
import LoopText from './components/LoopText';
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Fix import case mismatch.

The import statement uses LoopText but based on the file structure, the actual component file appears to be Looptext.jsx (with lowercase 't'). This mismatch will cause import errors on case-sensitive file systems.

-import LoopText from './components/LoopText';
+import LoopText from './components/Looptext';

Verify the correct filename for the LoopText component:


🏁 Script executed:

#!/bin/bash
# Check for the correct filename of the LoopText component
fd -t f "looptext" src/
fd -t f "LoopText" src/

Length of output: 75


Fix case mismatch in import path for Looptext component

The file src/components/Looptext.jsx uses a lowercase “t” in its filename. On case-sensitive file systems this will cause a module not found error.

• Location: src/App.jsx line 2

- import LoopText from './components/LoopText';
+ import LoopText from './components/Looptext';
📝 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
import LoopText from './components/LoopText';
import LoopText from './components/Looptext';
🤖 Prompt for AI Agents
In src/App.jsx at line 2, the import statement for LoopText has a case mismatch
with the actual filename Looptext.jsx in src/components. Update the import path
to use the exact casing of the filename, changing 'LoopText' to 'Looptext' to
match the file and avoid module not found errors on case-sensitive systems.

}, 1000);

return () => clearInterval(interval);
}, []);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add missing dependency to useEffect.

The targetDate variable should be included in the useEffect dependency array to ensure the timer recalculates if the target date changes.

-  }, []);
+  }, [targetDate]);
📝 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
}, []);
}, [targetDate]);
🤖 Prompt for AI Agents
In src/components/Timer.jsx at line 30, the useEffect hook's dependency array is
currently empty but should include the targetDate variable. Update the
dependency array to include targetDate so that the effect reruns and
recalculates the timer whenever targetDate changes.

Comment on lines 63 to 73
{activeIndex === index && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: 'auto', opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.3 }}
className="p-6 text-white/90"
>
<p className="text-base leading-relaxed">{item.answer}</p>
</motion.div>
)}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add AnimatePresence wrapper for proper exit animations.

The motion.div for the expanded content lacks an AnimatePresence wrapper, which means exit animations won't work properly when items collapse.

+import { motion, AnimatePresence } from 'framer-motion';

              <button>
                {/* button content */}
              </button>
              
-             {activeIndex === index && (
+             <AnimatePresence>
+               {activeIndex === index && (
                  <motion.div
                    initial={{ height: 0, opacity: 0 }}
                    animate={{ height: 'auto', opacity: 1 }}
                    exit={{ height: 0, opacity: 0 }}
                    transition={{ duration: 0.3 }}
                    className="p-6 text-white/90"
                  >
                    <p className="text-base leading-relaxed">{item.answer}</p>
                  </motion.div>
-               )}
+                 )}
+             </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
{activeIndex === index && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: 'auto', opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.3 }}
className="p-6 text-white/90"
>
<p className="text-base leading-relaxed">{item.answer}</p>
</motion.div>
)}
// Add AnimatePresence to the import
import { motion, AnimatePresence } from 'framer-motion';
...
<button>
{/* button content */}
</button>
<AnimatePresence>
{activeIndex === index && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: 'auto', opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ duration: 0.3 }}
className="p-6 text-white/90"
>
<p className="text-base leading-relaxed">{item.answer}</p>
</motion.div>
)}
</AnimatePresence>
🤖 Prompt for AI Agents
In src/components/FAQ.jsx around lines 63 to 73, the motion.div used for the
expanded content is missing an AnimatePresence wrapper, causing exit animations
to not function correctly. Wrap the conditional rendering of the motion.div
inside an AnimatePresence component to enable proper exit animations when the
content collapses.

Comment on lines 30 to 35
<img
width={40}
height={40}
src={image}
alt={name}
className="h-10 w-10 rounded-full"
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for testimonial images.

The images lack error handling which could result in broken image displays if URLs are invalid or images fail to load.

                  <img
                    width={40}
                    height={40}
                    src={image}
                    alt={name}
                    className="h-10 w-10 rounded-full"
+                   onError={(e) => {
+                     e.target.src = 'https://via.placeholder.com/40x40/gray/white?text=?';
+                   }}
                  />
📝 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
<img
width={40}
height={40}
src={image}
alt={name}
className="h-10 w-10 rounded-full"
<img
width={40}
height={40}
src={image}
alt={name}
className="h-10 w-10 rounded-full"
+ onError={(e) => {
+ e.target.src = 'https://via.placeholder.com/40x40/gray/white?text=?';
+ }}
/>
🤖 Prompt for AI Agents
In src/components/TestimonialsColumn.jsx around lines 30 to 35, the img element
displaying testimonial images lacks error handling for failed image loads. Add
an onError event handler to the img tag that sets a fallback image source or
hides the image when the original image fails to load, ensuring the UI does not
show broken image icons.

Comment on lines 15 to 476
animation: blink 1s infinite;
display: inline-block;
}

@keyframes pulse-slow {
0%, 100% { opacity: 0.2; transform: scale(0.95); }
50% { opacity: 0.5; transform: scale(1.05); }
}

.fixed-subtitle-container {
height: 10px;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 30;
margin-bottom: 30px;
}
.perspective-1000 {
perspective: 1000px;
}

.grid-pattern {
background-image: linear-gradient(rgba(255, 255, 227, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 227, 0.05) 1px, transparent 1px);
background-size: 40px 40px;
animation: grid-move 100s linear infinite;
}

.aurora-beam {
position: absolute;
height: 100%;
width: 30px;
filter: blur(30px);
opacity: 0.5;
background: linear-gradient(to bottom, rgba(0, 183, 255, 0.15), rgba(139, 0, 255, 0.05));
transform: skew(20deg);
animation: aurora 15s linear infinite;
}

.aurora-1 {
left: 20%;
animation-delay: 0s;
}

.aurora-2 {
left: 50%;
animation-delay: 5s;
background: linear-gradient(to bottom, rgba(139, 0, 255, 0.15), rgba(0, 183, 255, 0.05));
}

.aurora-3 {
left: 80%;
animation-delay: 10s;
background: linear-gradient(to bottom, rgba(0, 255, 179, 0.15), rgba(179, 0, 255, 0.05));
}

.particles-container {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
}

.particle {
position: absolute;
border-radius: 50%;
}

@keyframes grid-move {
0% {
transform: translateY(0);
}
100% {
transform: translateY(40px);
}
}

@keyframes aurora {
0% {
transform: skew(20deg) translateX(-100px);
}
100% {
transform: skew(20deg) translateX(100px);
}
}

@keyframes bg-gradient-radial {
from {
background-position: 0% 0%;
}
to {
background-position: 100% 100%;
}
}
`}</style>
</div>
)
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor large component and optimize performance

This component is too large (478 lines) and handles too many responsibilities. Consider:

  1. Extract the typewriter animation logic into a custom hook
  2. Move background animations to a separate component
  3. Extract the CSS-in-JS styles to a separate file or use CSS modules
  4. Monitor performance impact of multiple concurrent animations

Example structure:

// hooks/useTypewriter.js
export const useTypewriter = (lines) => {
  // Extract lines 62-135
}

// components/AnimatedBackground.jsx
export const AnimatedBackground = () => {
  // Extract background effects
}

// styles/Home.module.css
/* Move CSS from style tag */
🤖 Prompt for AI Agents
In src/pages/Home.jsx from lines 15 to 476, the Home component is too large and
mixes multiple concerns, which affects maintainability and performance. Refactor
by extracting the typewriter animation logic (lines ~62-135) into a custom hook
named useTypewriter, move all background animation elements and related
motion.divs into a separate AnimatedBackground component, and relocate the
CSS-in-JS styles from the style jsx tag into a dedicated CSS module file like
Home.module.css. This modularization will improve code clarity and allow better
performance monitoring of animations.



{/* Add CSS for the special effects */}
<style jsx="true">{`
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix JSX attribute syntax

The jsx attribute should use boolean syntax.

-      <style jsx="true">{`
+      <style jsx>{`
📝 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
<style jsx="true">{`
<style jsx>{`
🤖 Prompt for AI Agents
In src/pages/Home.jsx at line 368, the JSX attribute `jsx="true"` is incorrectly
using a string value. Change it to use boolean syntax by replacing `jsx="true"`
with `jsx` to correctly indicate a boolean true value.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (6)
package.json (3)

2-5: Consider enriching project metadata
Currently you have basic fields (name, private, version, type), which is fine for a private package. Optionally, you could add repository, license, and author for clarity, and bump the version to 0.1.0 to mark your initial frontend release.


7-11: Enhance the NPM script suite
You have the core Vite commands in place. Consider adding:

  • type-check: tsc --noEmit
  • format: e.g. eslint --fix or a Prettier command
    to automate type validation and code formatting.

29-40: Verify Vite version and linting plugins

  • The pinned Vite version (^6.3.5) doesn’t match the current stable major (v4.x); please confirm you have the correct version in devDependencies.
  • Also ensure you’ve installed and configured eslint-plugin-react (and any JSX/a11y plugins) if you intend to lint React components.
tailwind.config.js (1)

6-7: Verify content path accuracy for component scanning.

The content path "./components/**/*.{js,ts,jsx,tsx,mdx}" may be redundant since components appear to be located under src/components/ based on the provided file structure. This could lead to unnecessary file scanning.

Consider removing the redundant path:

  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx,mdx}", 
-   "./components/**/*.{js,ts,jsx,tsx,mdx}", 
  ],
src/components/magicui/shimmer-button.tsx (1)

52-91: Consider performance impact of complex layered animations.

The button uses multiple absolutely positioned layers with blur effects and animations. While visually appealing, this could impact performance on lower-end devices, especially with multiple buttons on a page.

Consider adding a reduced-motion variant for accessibility:

        <div
          className={cn(
            "-z-30 blur-[2px]",
+           "motion-reduce:blur-none",
            "absolute inset-0 overflow-visible [container-type:size]",
          )}
        >
          <div className="absolute inset-0 h-[100cqh] animate-shimmer-slide [aspect-ratio:1] [border-radius:0] [mask:none]">
-           <div className="absolute -inset-full w-auto rotate-0 animate-spin-around [background:conic-gradient(from_calc(270deg-(var(--spread)*0.5)),transparent_0,var(--shimmer-color)_var(--spread),transparent_var(--spread))] [translate:0_0]" />
+           <div className="absolute -inset-full w-auto rotate-0 animate-spin-around motion-reduce:animate-none [background:conic-gradient(from_calc(270deg-(var(--spread)*0.5)),transparent_0,var(--shimmer-color)_var(--spread),transparent_var(--spread))] [translate:0_0]" />
          </div>
        </div>
src/index.css (1)

91-101: Review accessibility impact of cursor hiding.

The .custom-cursor-enabled class globally hides cursors on interactive elements, which could negatively impact accessibility for users who rely on cursor visibility for navigation cues.

Consider implementing this more selectively or ensure you have a custom cursor implementation that maintains accessibility:

+/* Only apply when custom cursor is actively implemented */
+.custom-cursor-active {
+  cursor: none !important;
+}
+
+.custom-cursor-active a,
+.custom-cursor-active button,
+.custom-cursor-active input,
+.custom-cursor-active textarea,
+.custom-cursor-active select {
+  cursor: none !important;
+}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44df7f9 and f6d0a71.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (12)
  • components.json (1 hunks)
  • package.json (1 hunks)
  • src/App.jsx (1 hunks)
  • src/components/Navbar.jsx (1 hunks)
  • src/components/Stats.jsx (1 hunks)
  • src/components/magicui/shimmer-button.tsx (1 hunks)
  • src/index.css (1 hunks)
  • src/lib/utils.ts (1 hunks)
  • src/main.jsx (1 hunks)
  • tailwind.config.js (1 hunks)
  • tsconfig.json (1 hunks)
  • tsconfig.node.json (1 hunks)
✅ Files skipped from review due to trivial changes (4)
  • tsconfig.node.json
  • tsconfig.json
  • components.json
  • src/lib/utils.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/main.jsx
  • src/App.jsx
  • src/components/Stats.jsx
  • src/components/Navbar.jsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/components/magicui/shimmer-button.tsx (1)
src/lib/utils.ts (1)
  • cn (4-6)
🔇 Additional comments (7)
package.json (1)

13-26: Approve runtime dependencies
The set of runtime libraries (React, icon sets, animation tools, Tailwind helpers, etc.) is appropriate for your new Vite-powered frontend.

tailwind.config.js (2)

22-63: LGTM! Well-structured color system using CSS variables.

The color configuration effectively uses CSS variables with HSL values, enabling dynamic theming and dark mode support. This approach provides excellent maintainability and consistency across the application.


66-66:

✅ Verification successful

Verify tailwindcss-animate plugin dependency.

Ensure that the tailwindcss-animate plugin is included in your package.json dependencies, as it's required for the animation utilities used in components like ShimmerButton.


🏁 Script executed:

#!/bin/bash
# Check if tailwindcss-animate is listed in package.json dependencies
if [ -f "package.json" ]; then
  cat package.json | jq '.dependencies["tailwindcss-animate"], .devDependencies["tailwindcss-animate"]' | grep -v null || echo "tailwindcss-animate not found in dependencies"
else
  echo "package.json not found"
fi

Length of output: 153


Dependency Confirmed: tailwindcss-animate Present in package.json

The tailwindcss-animate plugin (version 1.0.7) is already listed in your dependencies. No further action needed.

src/components/magicui/shimmer-button.tsx (2)

5-13: Well-designed TypeScript interface with proper extension.

The interface correctly extends ComponentPropsWithoutRef<"button"> and provides good default values for customization props. This ensures type safety while maintaining flexibility.


60-62:

✅ Verification successful

Verify CSS animation class availability.

The component uses animate-shimmer-slide and animate-spin-around classes that need to be defined in your CSS. Ensure these animations are properly configured in your stylesheet.


🏁 Script executed:

#!/bin/bash
# Check if the required animation classes are defined in CSS files
rg -A 5 "shimmer-slide|spin-around" --type css

Length of output: 753


CSS animations verified and correctly defined.

Found in src/index.css:

  • --animate-shimmer-slide and @keyframes shimmer-slide
  • --animate-spin-around and @keyframes spin-around

No further changes needed.

src/index.css (2)

124-142: Animation definitions match component requirements.

The shimmer-slide and spin-around keyframe animations are correctly defined and align with the usage in the ShimmerButton component. The timing and transform properties are well-structured.


8-8:

✅ Verification successful

Verify font file availability.

The CSS references ClashDisplay font files that need to exist in the specified paths. Ensure these WOFF2 files are present in your assets directory.

Also applies to: 15-15, 22-22


🏁 Script executed:

#!/bin/bash
# Check if the ClashDisplay font files exist
fd "ClashDisplay.*\.woff2$" src/assets/fonts/ || echo "Font files not found in src/assets/fonts/"

Length of output: 354


Font file availability verified

All referenced ClashDisplay .woff2 files (Regular, Bold, Extralight, Light, Medium, Semibold, Variable) are present in src/assets/fonts/. No further action needed for lines 8, 15, 22.

Comment on lines +86 to +89
:root {
--foreground-rgb: 255, 255, 227;
--background-rgb: 16, 16, 14;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Clarify dual color variable systems.

You have two different color systems defined - HSL values in CSS custom properties (lines 27-79) and RGB values (lines 86-89, 103-108). This could lead to confusion and inconsistency.

Consider consolidating to use only the HSL system since it's more comprehensive and already integrated with Tailwind:

-:root {
-  --foreground-rgb: 255, 255, 227;
-  --background-rgb: 16, 16, 14;
-}

 body {
   margin: 0;
   padding: 0;
-  color: rgb(var(--foreground-rgb));
-  background: rgb(var(--background-rgb));
+  /* Colors will be applied by Tailwind utilities in @layer base */
 }

Also applies to: 103-108

🤖 Prompt for AI Agents
In src/index.css around lines 86 to 89 and also lines 103 to 108, you have
defined RGB color variables that coexist with HSL color variables defined
earlier (lines 27 to 79). This dual system can cause confusion and
inconsistency. To fix this, remove the RGB color variable definitions and
convert those colors to use the existing HSL custom properties instead, ensuring
all color variables follow the HSL system already integrated with Tailwind.

Comment on lines +80 to +83
.theme {
--animate-shimmer-slide: shimmer-slide var(--speed) ease-in-out infinite alternate;
--animate-spin-around: spin-around calc(var(--speed) * 2) infinite linear;
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Ensure animation variables are used correctly.

The .theme class defines animation variables, but verify these are being applied where needed. The ShimmerButton component should use this class or have these variables available in scope.


🏁 Script executed:

#!/bin/bash
# Check how the .theme class is used in components
rg "theme|--animate-shimmer-slide|--animate-spin-around" --type tsx --type jsx -A 2 -B 2

Length of output: 118


To ensure we catch all .theme and CSS‐variable usages, let’s search without relying on custom type aliases:


🏁 Script executed:

#!/bin/bash
# 1. Find any JSX/TSX usages of the "theme" class
rg "className.*theme" -n src -A2 -B2

# 2. Look for direct references to our animation variables in JS/JSX
rg "--animate-shimmer-slide|--animate-spin-around" -n src -A2 -B2

# 3. Locate and inspect the ShimmerButton component for theme or variable usage
rg "ShimmerButton" -n src

Length of output: 1178


Include the .theme class where CSS variables are needed

It looks like the animation variables you defined in src/index.css (lines 80–83) are never actually in scope—no component applies className="theme" nor references --animate-shimmer-slide/--animate-spin-around. Without that, your keyframe helpers won’t run.

Key locations to update:

  • src/index.css (lines 80–83): defines
    .theme {
      --animate-shimmer-slide: shimmer-slide var(--speed) ease-in-out infinite alternate;
      --animate-spin-around: spin-around calc(var(--speed) * 2) infinite linear;
    }
  • src/components/magicui/shimmer-button.tsx: no .theme or variable usage detected
  • src/components/Navbar.jsx:56
    <ShimmerButton className="shadow-2xl">…</ShimmerButton> (missing "theme")

Recommended fixes:

  • Wrap the button (or its parent) in <div className="theme">…</div>
  • Or add className="theme" to ShimmerButton by default or via its className prop
  • Alternatively, import/apply the CSS variables directly inside the component
🤖 Prompt for AI Agents
In src/index.css lines 80 to 83, the .theme class defines animation CSS
variables that are not applied in any component, so the animations won't run. To
fix this, ensure the ShimmerButton component or its parent includes the
className "theme" so these variables are in scope. You can either wrap
ShimmerButton in a div with className="theme" or add "theme" to the
ShimmerButton's className prop by default or when used, enabling the CSS
variables to apply correctly.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (5)
src/pages/Home.jsx (5)

67-69: Remove unused variables or implement the staggered animation

The text and words variables are created but marked as unused. Either remove them or implement the intended functionality.


137-137: Remove standalone semicolon

There's a syntax error with a standalone semicolon.


154-155: Incorrect Timer component placement

The Timer component is placed inside the background effects motion.div, which seems incorrect. Timer should likely be part of the main content, not background decorations.


15-476: Refactor large component and optimize performance

This component is too large (478 lines) and handles too many responsibilities. Consider:

  1. Extract the typewriter animation logic into a custom hook
  2. Move background animations to a separate component
  3. Extract the CSS-in-JS styles to a separate file or use CSS modules
  4. Monitor performance impact of multiple concurrent animations

368-368: Fix JSX attribute syntax

The jsx attribute should use boolean syntax.

🧹 Nitpick comments (2)
src/pages/Home.jsx (2)

174-212: Consider performance impact of multiple simultaneous animations

Multiple large blur elements with continuous scale and opacity animations may impact performance, especially on lower-end devices.

Consider:

  1. Reducing the number of animated elements
  2. Using transform3d for better GPU acceleration
  3. Adding will-change: transform to animated elements
  4. Implementing animation based on viewport visibility
.animated-blur {
  will-change: transform, opacity;
  transform: translate3d(0, 0, 0);
}

400-405: Optimize grid animation performance

The grid pattern animation runs for 100 seconds continuously which may impact performance. Consider using CSS transforms instead of background-position changes for better performance.

Replace the grid animation with a transform-based approach:

.grid-pattern {
  background-image: linear-gradient(rgba(255, 255, 227, 0.05) 1px, transparent 1px),
                   linear-gradient(90deg, rgba(255, 255, 227, 0.05) 1px, transparent 1px);
  background-size: 40px 40px;
- animation: grid-move 100s linear infinite;
+ transform: translateY(0);
+ animation: grid-transform 20s linear infinite;
}

@keyframes grid-transform {
  0% { transform: translateY(0); }
  100% { transform: translateY(40px); }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6d0a71 and 2c2ce8a.

📒 Files selected for processing (1)
  • src/pages/Home.jsx (1 hunks)
🔇 Additional comments (1)
src/pages/Home.jsx (1)

1-13: LGTM - Clean imports with proper organization

The imports are well-organized with React hooks, Framer Motion, and component imports properly structured.

Comment on lines 236 to 243
className={`text-[7vw] md:text-[6vw] lg:text-[5vw] font-clash font-bold mb-[-1vw] leading-[1.2] text-center w-full ${isTyping ? 'cursor' : ''}`}
initial={{ opacity: 1 }}
style={{
fontFamily: "monospace",
WebkitTextStroke: "1px rgba(255, 255, 227, 0.2)",
textShadow: "0 0 10px rgba(255, 255, 227, 0.3)"
}}
>{currentText}</motion.h2>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Accessibility concern: Motion-sensitive users

The continuous typewriter animation and cursor blinking may cause issues for users with motion sensitivity or vestibular disorders.

Add a prefers-reduced-motion check:

+const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches

// In the typewriter effect
+if (prefersReducedMotion) {
+  setCurrentText(lines[lines.length - 1]) // Show final text immediately
+  return
+}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/pages/Home.jsx around lines 236 to 243, the continuous typewriter
animation and blinking cursor can negatively impact motion-sensitive users. To
fix this, add a check for the user's `prefers-reduced-motion` setting using a
media query or React hook. If the user prefers reduced motion, disable or
simplify the animation and cursor blinking effects to improve accessibility.

<div className="absolute inset-0 bg-[#0A0A0F]"></div>
<div className="absolute inset-0 bg-gradient-radial from-blue-900/25 via-indigo-900/15 to-[#0A0A0F]"></div>
<div className="absolute inset-0 bg-gradient-to-b from-blue-900/30 via-purple-900/15 to-[#0A0A0F]"></div>
<div className="absolute inset-0 bg-[#0A0A0F]" style={{ opacity: useTransform(scrollYProgress, [0, 0.1], [0, 0.2]) }}></div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix useTransform usage in inline style

The useTransform hook should not be called inside the style prop as it needs to be at the component level.

Move the transform outside the JSX:

+const overlayOpacity = useTransform(scrollYProgress, [0, 0.1], [0, 0.2])

-<div className="absolute inset-0 bg-[#0A0A0F]" style={{ opacity: useTransform(scrollYProgress, [0, 0.1], [0, 0.2]) }}></div>
+<motion.div className="absolute inset-0 bg-[#0A0A0F]" style={{ opacity: overlayOpacity }}></motion.div>
🤖 Prompt for AI Agents
In src/pages/Home.jsx at line 161, the useTransform hook is incorrectly called
inside the style prop, which violates React hook rules. To fix this, move the
useTransform call to the top of the component function to create a transformed
opacity value, then use that value in the style prop inline. This ensures hooks
are called at the component level and not inside JSX.

Comment on lines +72 to +135
useEffect(() => {
let timeout

// Type current line character by character
const typeLine = async (line) => {
setIsTyping(true)
for (let i = 0; i <= line.length; i++) {
await new Promise(resolve => {
timeout = setTimeout(() => {
setCurrentText(line.substring(0, i))
resolve()
}, 100)
})
}

// Pause at the end of typing
await new Promise(resolve => {
timeout = setTimeout(resolve, 800)
})
}

// Backspace the current line character by character
const backspaceLine = async (line) => {
setIsTyping(false)
for (let i = line.length; i >= 0; i--) {
await new Promise(resolve => {
timeout = setTimeout(() => {
setCurrentText(line.substring(0, i))
resolve()
}, 50) // Faster deletion
})
}

// Short pause after deletion
await new Promise(resolve => {
timeout = setTimeout(resolve, 300)
})
}

const runTypewriter = async () => {
// Loop indefinitely through all lines
while (true) {
for (let i = 0; i < lines.length; i++) {
await typeLine(lines[i])

// Don't backspace the final line on the last iteration
if (i < lines.length - 1) {
await backspaceLine(lines[i])
} else {
// Pause longer on the final line before restarting
await new Promise(resolve => {
timeout = setTimeout(resolve, 3000)
})
await backspaceLine(lines[i])
}
}
}
}

runTypewriter()

// Cleanup
return () => clearTimeout(timeout)
}, [])
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Potential memory leak in typewriter animation logic

The complex async typewriter effect with nested timeouts and promises could cause memory leaks if the component unmounts during animation. The current cleanup only clears the last timeout, not all pending timeouts.

Consider refactoring to use a single interval or implementing proper cleanup:

useEffect(() => {
-  let timeout
+  let timeouts = []
+  let isMounted = true
  
  const typeLine = async (line) => {
+    if (!isMounted) return
    setIsTyping(true)
    for (let i = 0; i <= line.length; i++) {
+      if (!isMounted) return
      await new Promise(resolve => {
-        timeout = setTimeout(() => {
+        const timeoutId = setTimeout(() => {
          setCurrentText(line.substring(0, i))
          resolve()
        }, 100)
+        timeouts.push(timeoutId)
      })
    }
  }
  
  // Similar changes for backspaceLine and other timeout usages
  
  return () => {
+    isMounted = false
+    timeouts.forEach(clearTimeout)
-    clearTimeout(timeout)
  }
}, [])

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/pages/Home.jsx between lines 72 and 135, the typewriter effect uses
multiple nested timeouts without tracking all timeout IDs, causing potential
memory leaks on component unmount. Refactor by storing all active timeout IDs in
an array and clear them all in the cleanup function, or replace the nested
timeouts with a single interval or requestAnimationFrame loop that can be fully
cleared on unmount to ensure no pending timers remain.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/components/magicui/shimmer-button.tsx (1)

75-75: Fix typo in CSS class name.

There's a typo in the class name - insert-0 should be inset-0.

-            "insert-0 absolute size-full",
+            "inset-0 absolute size-full",
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c2ce8a and a697237.

📒 Files selected for processing (5)
  • src/components/Navbar.jsx (1 hunks)
  • src/components/Stats.jsx (1 hunks)
  • src/components/magicui/shimmer-button.css (1 hunks)
  • src/components/magicui/shimmer-button.tsx (1 hunks)
  • src/index.css (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/components/magicui/shimmer-button.css
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/components/Stats.jsx
  • src/components/Navbar.jsx
  • src/index.css
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/components/magicui/shimmer-button.tsx (1)
src/lib/utils.ts (1)
  • cn (4-6)
🪛 Biome (1.9.4)
src/components/magicui/shimmer-button.tsx

[error] 57-57: expected ) but instead found {

Remove {

(parse)


[error] 96-96: Expected an expression but instead found '<'.

Expected an expression here.

(parse)


[error] 58-70: This code is unreachable

... because this statement will return from the function beforehand

(lint/correctness/noUnreachable)


[error] 73-88: This code is unreachable

... because this statement will return from the function beforehand

(lint/correctness/noUnreachable)


[error] 91-95: This code is unreachable

... because this statement will return from the function beforehand

(lint/correctness/noUnreachable)


[error] 97-97: This code is unreachable

... because this statement will return from the function beforehand

(lint/correctness/noUnreachable)


[error] 57-57: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.
Safe fix: Remove redundant block.

(lint/complexity/noUselessLoneBlockStatements)


[error] 70-70: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.
Safe fix: Remove redundant block.

(lint/complexity/noUselessLoneBlockStatements)


[error] 72-72: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.
Safe fix: Remove redundant block.

(lint/complexity/noUselessLoneBlockStatements)


[error] 90-90: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.
Safe fix: Remove redundant block.

(lint/complexity/noUselessLoneBlockStatements)

Comment on lines 32 to 96
return (
<button
style={
{
"--spread": "90deg",
"--shimmer-color": shimmerColor,
"--radius": borderRadius,
"--speed": shimmerDuration,
"--cut": shimmerSize,
"--bg": background,
} as CSSProperties
}
className={cn(
"group relative z-0 flex cursor-pointer items-center justify-center overflow-hidden whitespace-nowrap border border-white/10 px-6 py-3 text-white [background:var(--bg)] [border-radius:var(--radius)] dark:text-white/90",
"transform-gpu transition-all duration-300 ease-out hover:scale-[1.02] active:scale-[0.98] active:translate-y-px",
"backdrop-blur-sm border-2 border-white/10 hover:border-white/20",
"before:absolute before:inset-0 before:rounded-full before:bg-gradient-to-r before:from-transparent before:via-[#FFFFE3]/20 before:to-transparent before:animate-shimmer-slide",
"after:absolute after:inset-0 after:rounded-full after:border after:border-white/10 after:opacity-0 group-hover:after:opacity-100 after:transition-opacity after:duration-300",
className,
)}
ref={ref}
{...props}
>
<span className="relative z-10">{children}</span>
</button>
{/* spark container */}
<div
className={cn(
"-z-30 blur-[2px]",
"absolute inset-0 overflow-visible [container-type:size]",
)}
>
{/* spark */}
<div className="absolute inset-0 h-[100cqh] animate-shimmer-slide [aspect-ratio:1] [border-radius:0] [mask:none]">
{/* spark before */}
<div className="absolute -inset-full w-auto rotate-0 animate-spin-around [background:conic-gradient(from_calc(270deg-(var(--spread)*0.5)),transparent_0,var(--shimmer-color)_var(--spread),transparent_var(--spread))] [translate:0_0]" />
</div>
</div>
{children}

{/* Highlight */}
<div
className={cn(
"insert-0 absolute size-full",

"rounded-2xl px-4 py-1.5 text-sm font-medium shadow-[inset_0_-8px_10px_#ffffff1f]",

// transition
"transform-gpu transition-all duration-300 ease-in-out",

// on hover
"group-hover:shadow-[inset_0_-6px_10px_#ffffff3f]",

// on click
"group-active:shadow-[inset_0_-10px_10px_#ffffff3f]",
)}
/>

{/* backdrop */}
<div
className={cn(
"absolute -z-20 [background:var(--bg)] [border-radius:var(--radius)] [inset:var(--cut)]",
)}
/>
</button>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix critical structural issue: JSX elements are unreachable after return statement.

The button element closes at line 56, but additional JSX elements (spark container, highlight, backdrop) are placed after the return statement ends, making them unreachable and causing parsing errors.

Move the additional div elements inside the button element:

       <button
         style={
           {
             "--spread": "90deg",
             "--shimmer-color": shimmerColor,
             "--radius": borderRadius,
             "--speed": shimmerDuration,
             "--cut": shimmerSize,
             "--bg": background,
           } as CSSProperties
         }
         className={cn(
           "group relative z-0 flex cursor-pointer items-center justify-center overflow-hidden whitespace-nowrap border border-white/10 px-6 py-3 text-white [background:var(--bg)] [border-radius:var(--radius)] dark:text-white/90",
           "transform-gpu transition-all duration-300 ease-out hover:scale-[1.02] active:scale-[0.98] active:translate-y-px",
           "backdrop-blur-sm border-2 border-white/10 hover:border-white/20",
           "before:absolute before:inset-0 before:rounded-full before:bg-gradient-to-r before:from-transparent before:via-[#FFFFE3]/20 before:to-transparent before:animate-shimmer-slide",
           "after:absolute after:inset-0 after:rounded-full after:border after:border-white/10 after:opacity-0 group-hover:after:opacity-100 after:transition-opacity after:duration-300",
           className,
         )}
         ref={ref}
         {...props}
       >
         <span className="relative z-10">{children}</span>
-      </button>
-        {/* spark container */}
-        <div
-          className={cn(
-            "-z-30 blur-[2px]",
-            "absolute inset-0 overflow-visible [container-type:size]",
-          )}
-        >
-          {/* spark */}
-          <div className="absolute inset-0 h-[100cqh] animate-shimmer-slide [aspect-ratio:1] [border-radius:0] [mask:none]">
-            {/* spark before */}
-            <div className="absolute -inset-full w-auto rotate-0 animate-spin-around [background:conic-gradient(from_calc(270deg-(var(--spread)*0.5)),transparent_0,var(--shimmer-color)_var(--spread),transparent_var(--spread))] [translate:0_0]" />
-          </div>
-        </div>
-        {children}
-
-        {/* Highlight */}
-        <div
-          className={cn(
-            "insert-0 absolute size-full",
-
-            "rounded-2xl px-4 py-1.5 text-sm font-medium shadow-[inset_0_-8px_10px_#ffffff1f]",
-
-            // transition
-            "transform-gpu transition-all duration-300 ease-in-out",
-
-            // on hover
-            "group-hover:shadow-[inset_0_-6px_10px_#ffffff3f]",
-
-            // on click
-            "group-active:shadow-[inset_0_-10px_10px_#ffffff3f]",
-          )}
-        />
-
-        {/* backdrop */}
-        <div
-          className={cn(
-            "absolute -z-20 [background:var(--bg)] [border-radius:var(--radius)] [inset:var(--cut)]",
-          )}
-        />
-      </button>
+
+        {/* spark container */}
+        <div
+          className={cn(
+            "-z-30 blur-[2px]",
+            "absolute inset-0 overflow-visible [container-type:size]",
+          )}
+        >
+          {/* spark */}
+          <div className="absolute inset-0 h-[100cqh] animate-shimmer-slide [aspect-ratio:1] [border-radius:0] [mask:none]">
+            {/* spark before */}
+            <div className="absolute -inset-full w-auto rotate-0 animate-spin-around [background:conic-gradient(from_calc(270deg-(var(--spread)*0.5)),transparent_0,var(--shimmer-color)_var(--spread),transparent_var(--spread))] [translate:0_0]" />
+          </div>
+        </div>
+
+        {/* Highlight */}
+        <div
+          className={cn(
+            "inset-0 absolute size-full",
+            "rounded-2xl px-4 py-1.5 text-sm font-medium shadow-[inset_0_-8px_10px_#ffffff1f]",
+            "transform-gpu transition-all duration-300 ease-in-out",
+            "group-hover:shadow-[inset_0_-6px_10px_#ffffff3f]",
+            "group-active:shadow-[inset_0_-10px_10px_#ffffff3f]",
+          )}
+        />
+
+        {/* backdrop */}
+        <div
+          className={cn(
+            "absolute -z-20 [background:var(--bg)] [border-radius:var(--radius)] [inset:var(--cut)]",
+          )}
+        />
+      </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
return (
<button
style={
{
"--spread": "90deg",
"--shimmer-color": shimmerColor,
"--radius": borderRadius,
"--speed": shimmerDuration,
"--cut": shimmerSize,
"--bg": background,
} as CSSProperties
}
className={cn(
"group relative z-0 flex cursor-pointer items-center justify-center overflow-hidden whitespace-nowrap border border-white/10 px-6 py-3 text-white [background:var(--bg)] [border-radius:var(--radius)] dark:text-white/90",
"transform-gpu transition-all duration-300 ease-out hover:scale-[1.02] active:scale-[0.98] active:translate-y-px",
"backdrop-blur-sm border-2 border-white/10 hover:border-white/20",
"before:absolute before:inset-0 before:rounded-full before:bg-gradient-to-r before:from-transparent before:via-[#FFFFE3]/20 before:to-transparent before:animate-shimmer-slide",
"after:absolute after:inset-0 after:rounded-full after:border after:border-white/10 after:opacity-0 group-hover:after:opacity-100 after:transition-opacity after:duration-300",
className,
)}
ref={ref}
{...props}
>
<span className="relative z-10">{children}</span>
</button>
{/* spark container */}
<div
className={cn(
"-z-30 blur-[2px]",
"absolute inset-0 overflow-visible [container-type:size]",
)}
>
{/* spark */}
<div className="absolute inset-0 h-[100cqh] animate-shimmer-slide [aspect-ratio:1] [border-radius:0] [mask:none]">
{/* spark before */}
<div className="absolute -inset-full w-auto rotate-0 animate-spin-around [background:conic-gradient(from_calc(270deg-(var(--spread)*0.5)),transparent_0,var(--shimmer-color)_var(--spread),transparent_var(--spread))] [translate:0_0]" />
</div>
</div>
{children}
{/* Highlight */}
<div
className={cn(
"insert-0 absolute size-full",
"rounded-2xl px-4 py-1.5 text-sm font-medium shadow-[inset_0_-8px_10px_#ffffff1f]",
// transition
"transform-gpu transition-all duration-300 ease-in-out",
// on hover
"group-hover:shadow-[inset_0_-6px_10px_#ffffff3f]",
// on click
"group-active:shadow-[inset_0_-10px_10px_#ffffff3f]",
)}
/>
{/* backdrop */}
<div
className={cn(
"absolute -z-20 [background:var(--bg)] [border-radius:var(--radius)] [inset:var(--cut)]",
)}
/>
</button>
return (
<button
style={
{
"--spread": "90deg",
"--shimmer-color": shimmerColor,
"--radius": borderRadius,
"--speed": shimmerDuration,
"--cut": shimmerSize,
"--bg": background,
} as CSSProperties
}
className={cn(
"group relative z-0 flex cursor-pointer items-center justify-center overflow-hidden whitespace-nowrap border border-white/10 px-6 py-3 text-white [background:var(--bg)] [border-radius:var(--radius)] dark:text-white/90",
"transform-gpu transition-all duration-300 ease-out hover:scale-[1.02] active:scale-[0.98] active:translate-y-px",
"backdrop-blur-sm border-2 border-white/10 hover:border-white/20",
"before:absolute before:inset-0 before:rounded-full before:bg-gradient-to-r before:from-transparent before:via-[#FFFFE3]/20 before:to-transparent before:animate-shimmer-slide",
"after:absolute after:inset-0 after:rounded-full after:border after:border-white/10 after:opacity-0 group-hover:after:opacity-100 after:transition-opacity after:duration-300",
className,
)}
ref={ref}
{...props}
>
<span className="relative z-10">{children}</span>
{/* spark container */}
<div
className={cn(
"-z-30 blur-[2px]",
"absolute inset-0 overflow-visible [container-type:size]",
)}
>
{/* spark */}
<div className="absolute inset-0 h-[100cqh] animate-shimmer-slide [aspect-ratio:1] [border-radius:0] [mask:none]">
{/* spark before */}
<div className="absolute -inset-full w-auto rotate-0 animate-spin-around [background:conic-gradient(from_calc(270deg-(var(--spread)*0.5)),transparent_0,var(--shimmer-color)_var(--spread),transparent_var(--spread))] [translate:0_0]" />
</div>
</div>
{/* Highlight */}
<div
className={cn(
"inset-0 absolute size-full",
"rounded-2xl px-4 py-1.5 text-sm font-medium shadow-[inset_0_-8px_10px_#ffffff1f]",
"transform-gpu transition-all duration-300 ease-in-out",
"group-hover:shadow-[inset_0_-6px_10px_#ffffff3f]",
"group-active:shadow-[inset_0_-10px_10px_#ffffff3f]",
)}
/>
{/* backdrop */}
<div
className={cn(
"absolute -z-20 [background:var(--bg)] [border-radius:var(--radius)] [inset:var(--cut)]",
)}
/>
</button>
);
🧰 Tools
🪛 Biome (1.9.4)

[error] 57-57: expected ) but instead found {

Remove {

(parse)


[error] 96-96: Expected an expression but instead found '<'.

Expected an expression here.

(parse)


[error] 58-70: This code is unreachable

... because this statement will return from the function beforehand

(lint/correctness/noUnreachable)


[error] 73-88: This code is unreachable

... because this statement will return from the function beforehand

(lint/correctness/noUnreachable)


[error] 91-95: This code is unreachable

... because this statement will return from the function beforehand

(lint/correctness/noUnreachable)


[error] 57-57: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.
Safe fix: Remove redundant block.

(lint/complexity/noUselessLoneBlockStatements)


[error] 70-70: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.
Safe fix: Remove redundant block.

(lint/complexity/noUselessLoneBlockStatements)


[error] 72-72: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.
Safe fix: Remove redundant block.

(lint/complexity/noUselessLoneBlockStatements)


[error] 90-90: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.
Safe fix: Remove redundant block.

(lint/complexity/noUselessLoneBlockStatements)

🤖 Prompt for AI Agents
In src/components/magicui/shimmer-button.tsx between lines 32 and 96, the JSX
elements for the spark container, highlight, and backdrop are placed after the
closing button tag, making them unreachable and causing parsing errors. To fix
this, move all these additional div elements inside the button element before
its closing tag so that they are part of the button's children and properly
rendered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a697237 and b49552b.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • package.json (1 hunks)
  • src/components/Navbar.jsx (1 hunks)
  • src/components/magicui/shimmer-button.css (1 hunks)
  • src/components/magicui/shimmer-button.jsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/components/magicui/shimmer-button.jsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/magicui/shimmer-button.css
  • src/components/Navbar.jsx
🔇 Additional comments (1)
package.json (1)

2-5: Package metadata looks good
The "name", "private", "version", and "type" fields correctly define an ESM-only, unpublished project root.

package.json Outdated
Comment on lines 12 to 27
"dependencies": {
"@tabler/icons-react": "^3.33.0",
"@tsconfig/recommended": "^1.0.8",
"@types/node": "^24.0.0",
"class-variance-authority": "^0.7.1",
"classnames": "^2.5.1",
"clsx": "^2.1.1",
"framer-motion": "^12.15.0",
"lucide-react": "^0.511.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^5.5.0",
"react-use-measure": "^2.1.7",
"tailwind-merge": "^3.3.0",
"tailwindcss-animate": "^1.0.7",
"typescript": "^5.8.3"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Move build-only packages out of dependencies
typescript, @tsconfig/recommended, and @types/node are only needed at build time and should not be runtime dependencies.

--- a/package.json
+++ b/package.json
@@ "dependencies": {
-   "@tsconfig/recommended": "^1.0.8",
-   "@types/node": "^24.0.0",
...
-   "typescript": "^5.8.3"
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In package.json lines 12 to 27, move the build-only packages "typescript",
"@tsconfig/recommended", and "@types/node" from the "dependencies" section to
"devDependencies" to ensure they are only installed for development and not
included in the runtime dependencies.

Comment on lines +7 to +11
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add a type-check script
Since this is a TypeScript project, it’s essential to validate types as part of your CI/linting workflow. Consider adding:

  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint .",
+   "type-check": "tsc --noEmit",
    "preview": "vite preview"
  },
📝 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
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"type-check": "tsc --noEmit",
"preview": "vite preview"
},
🤖 Prompt for AI Agents
In package.json around lines 7 to 11, add a new script named "type-check" that
runs the TypeScript compiler in noEmit mode to validate types without generating
output. This ensures type correctness is checked during CI or linting workflows.
Add the script alongside existing scripts like "dev" and "lint" for consistency.

Comment on lines +30 to 42
"@eslint/js": "^9.25.0",
"@types/react": "^19.1.7",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^4.5.2",
"autoprefixer": "^10.4.21",
"eslint": "^9.25.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^16.0.0",
"postcss": "^8.5.3",
"tailwindcss": "^3.4.17",
"vite": "^6.3.5"
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Install TypeScript and types under devDependencies
After removing from dependencies, add these entries to devDependencies to ensure proper build support:

--- a/package.json
+++ b/package.json
@@ "devDependencies": {
     "vite": "^6.3.5"
+  },
+  "devDependencies": {
+    "@tsconfig/recommended": "^1.0.8",
+    "@types/node": "^24.0.0",
+    "typescript": "^5.8.3"
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In package.json lines 30 to 42, TypeScript and its type definitions were removed
from dependencies but not added to devDependencies. Move the TypeScript package
and any related @types packages from dependencies to devDependencies by adding
them under the devDependencies section to ensure they are only used during
development and build processes.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/components/Register.jsx (1)

169-169: Fix hardcoded translation that breaks responsive design.

This is the same issue flagged in previous reviews. The translate-x-64 class will push content off-screen on smaller devices.

🧹 Nitpick comments (3)
src/components/Register.jsx (3)

139-161: Optimize resize handler performance with debouncing.

The resize handler may fire frequently during window resizing, potentially causing performance issues with expensive DOM calculations.

Consider debouncing the resize handler:

+  const debounce = (func, wait) => {
+    let timeout;
+    return function executedFunction(...args) {
+      const later = () => {
+        clearTimeout(timeout);
+        func(...args);
+      };
+      clearTimeout(timeout);
+      timeout = setTimeout(later, wait);
+    };
+  };
+
   useEffect(() => {
-    const handleResize = () => {
+    const handleResize = debounce(() => {
       if (regRef.current && expRef.current && buildRef.current && containerRef.current) {
         // ... existing logic
       }
-    };
+    }, 100);
     window.addEventListener('resize', handleResize);
     return () => window.removeEventListener('resize', handleResize);
   }, []);

119-137: Simplify line positioning logic.

The current line positioning implementation is overly complex and prone to errors. Consider using CSS for visual connections instead of JavaScript calculations.

Alternative approach using CSS pseudo-elements:

.tab-container::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 2px;
  background: linear-gradient(to bottom, transparent 60px, #3b82f6 60px, #3b82f6 calc(100% - 60px), transparent calc(100% - 60px));
  transform: translateX(-50%);
  opacity: 0.6;
}

This eliminates the need for complex JavaScript calculations and is more maintainable.


93-106: Consider extracting custom hooks for cleaner component logic.

The component handles multiple concerns (tab state, auto-slide, line positioning) which could be separated into custom hooks for better maintainability.

Extract auto-slide logic into a custom hook:

const useAutoSlide = (tabCount, isPaused) => {
  const [activeTab, setActiveTab] = useState(0);
  const timerRef = useRef();

  useEffect(() => {
    if (!isPaused) {
      timerRef.current = setTimeout(() => {
        setActiveTab((prev) => (prev + 1) % tabCount);
      }, 5000);
    }
    return () => clearTimeout(timerRef.current);
  }, [activeTab, isPaused, tabCount]);

  return [activeTab, setActiveTab];
};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b49552b and ade924d.

📒 Files selected for processing (1)
  • src/components/Register.jsx (1 hunks)

Comment on lines +119 to +161
// Refs for lines
useLayoutEffect(() => {
if (regRef.current && expRef.current && buildRef.current && containerRef.current) {
const regRect = regRef.current.getBoundingClientRect();
const expRect = expRef.current.getBoundingClientRect();
const buildRect = buildRef.current.getBoundingClientRect();
const contRect = containerRef.current.getBoundingClientRect();
setLinePos({
regToExp: {
top: regRect.bottom - contRect.top + 8, // 8px for padding
height: expRect.top - regRect.bottom - 16 // 16px for spacing
},
expToBuild: {
top: expRect.bottom - contRect.top + 8,
height: buildRect.top - expRect.bottom - 16
}
});
}
}, [activeTab]);

// Responsive: recalc on resize
useEffect(() => {
const handleResize = () => {
if (regRef.current && expRef.current && buildRef.current && containerRef.current) {
const regRect = regRef.current.getBoundingClientRect();
const expRect = expRef.current.getBoundingClientRect();
const buildRect = buildRef.current.getBoundingClientRect();
const contRect = containerRef.current.getBoundingClientRect();
setLinePos({
regToExp: {
left: regRect.right - contRect.left + 8,
width: expRect.left - regRect.right - 16
},
expToBuild: {
left: expRect.right - contRect.left + 8,
width: buildRect.left - expRect.right - 16
}
});
}
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix inconsistent line positioning logic between layout effect and resize handler.

The line positioning logic has a critical inconsistency. The useLayoutEffect calculates vertical properties (top, height) for connecting lines, but the resize handler calculates horizontal properties (left, width). This will cause the lines to render incorrectly on window resize.

Apply this diff to make the resize handler consistent with the layout effect:

-        setLinePos({
-          regToExp: {
-            left: regRect.right - contRect.left + 8,
-            width: expRect.left - regRect.right - 16
-          },
-          expToBuild: {
-            left: expRect.right - contRect.left + 8,
-            width: buildRect.left - expRect.right - 16
-          }
-        });
+        setLinePos({
+          regToExp: {
+            top: regRect.bottom - contRect.top + 8,
+            height: expRect.top - regRect.bottom - 16
+          },
+          expToBuild: {
+            top: expRect.bottom - contRect.top + 8,
+            height: buildRect.top - expRect.bottom - 16
+          }
+        });
📝 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
// Refs for lines
useLayoutEffect(() => {
if (regRef.current && expRef.current && buildRef.current && containerRef.current) {
const regRect = regRef.current.getBoundingClientRect();
const expRect = expRef.current.getBoundingClientRect();
const buildRect = buildRef.current.getBoundingClientRect();
const contRect = containerRef.current.getBoundingClientRect();
setLinePos({
regToExp: {
top: regRect.bottom - contRect.top + 8, // 8px for padding
height: expRect.top - regRect.bottom - 16 // 16px for spacing
},
expToBuild: {
top: expRect.bottom - contRect.top + 8,
height: buildRect.top - expRect.bottom - 16
}
});
}
}, [activeTab]);
// Responsive: recalc on resize
useEffect(() => {
const handleResize = () => {
if (regRef.current && expRef.current && buildRef.current && containerRef.current) {
const regRect = regRef.current.getBoundingClientRect();
const expRect = expRef.current.getBoundingClientRect();
const buildRect = buildRef.current.getBoundingClientRect();
const contRect = containerRef.current.getBoundingClientRect();
setLinePos({
regToExp: {
left: regRect.right - contRect.left + 8,
width: expRect.left - regRect.right - 16
},
expToBuild: {
left: expRect.right - contRect.left + 8,
width: buildRect.left - expRect.right - 16
}
});
}
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
// Responsive: recalc on resize
useEffect(() => {
const handleResize = () => {
if (regRef.current && expRef.current && buildRef.current && containerRef.current) {
const regRect = regRef.current.getBoundingClientRect();
const expRect = expRef.current.getBoundingClientRect();
const buildRect = buildRef.current.getBoundingClientRect();
const contRect = containerRef.current.getBoundingClientRect();
setLinePos({
regToExp: {
top: regRect.bottom - contRect.top + 8,
height: expRect.top - regRect.bottom - 16
},
expToBuild: {
top: expRect.bottom - contRect.top + 8,
height: buildRect.top - expRect.bottom - 16
}
});
}
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
🤖 Prompt for AI Agents
In src/components/Register.jsx between lines 119 and 161, the useLayoutEffect
sets vertical line positions using top and height, but the resize handler sets
horizontal positions using left and width, causing inconsistent line rendering
on resize. To fix this, update the resize handler to recalculate and set the
vertical properties (top and height) for the lines, matching the logic in
useLayoutEffect, instead of horizontal properties. This ensures consistent line
positioning both initially and on window resize.

Comment on lines 200 to 228
<div className="flex flex-col h-full items-center justify-between">
<span
ref={regRef}
className={`z-10 text-3xl md:text-4xl font-clash font-bold uppercase tracking-wide px-2 ${
activeTab === 0 ? "text-white" : "text-gray-400"
}`}
style={{ letterSpacing: '0.04em' }}
>
REGISTER
</span>
<span
ref={expRef}
className={`z-10 text-3xl md:text-4xl font-clash font-bold uppercase tracking-wide px-2 mt-24 ${
activeTab === 1 ? "text-white" : "text-gray-400"
}`}
style={{ letterSpacing: '0.04em' }}
>
EXPLORE
</span>
<span
ref={buildRef}
className={`z-10 text-3xl md:text-4xl font-clash font-bold uppercase tracking-wide px-2 mt-24 ${
activeTab === 2 ? "text-white" : "text-gray-400"
}`}
style={{ letterSpacing: '0.04em' }}
>
BUILD
</span>
</div>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add accessibility features for keyboard navigation.

The tab navigation lacks proper keyboard accessibility and ARIA attributes, making it difficult for screen readers and keyboard users to navigate.

Add keyboard navigation and ARIA attributes:

           <div className="flex flex-col h-full items-center justify-between">
-            <span
+            <button
               ref={regRef}
+              onClick={() => setActiveTab(0)}
+              onKeyDown={(e) => e.key === 'Enter' && setActiveTab(0)}
+              aria-pressed={activeTab === 0}
+              role="tab"
               className={`z-10 text-3xl md:text-4xl font-clash font-bold uppercase tracking-wide px-2 ${
                 activeTab === 0 ? "text-white" : "text-gray-400"
-              }`}
+              } cursor-pointer focus:outline-none focus:ring-2 focus:ring-blue-500`}
               style={{ letterSpacing: '0.04em' }}
             >
               REGISTER
-            </span>
+            </button>

Apply similar changes to the EXPLORE and BUILD tab buttons.

📝 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
<div className="flex flex-col h-full items-center justify-between">
<span
ref={regRef}
className={`z-10 text-3xl md:text-4xl font-clash font-bold uppercase tracking-wide px-2 ${
activeTab === 0 ? "text-white" : "text-gray-400"
}`}
style={{ letterSpacing: '0.04em' }}
>
REGISTER
</span>
<span
ref={expRef}
className={`z-10 text-3xl md:text-4xl font-clash font-bold uppercase tracking-wide px-2 mt-24 ${
activeTab === 1 ? "text-white" : "text-gray-400"
}`}
style={{ letterSpacing: '0.04em' }}
>
EXPLORE
</span>
<span
ref={buildRef}
className={`z-10 text-3xl md:text-4xl font-clash font-bold uppercase tracking-wide px-2 mt-24 ${
activeTab === 2 ? "text-white" : "text-gray-400"
}`}
style={{ letterSpacing: '0.04em' }}
>
BUILD
</span>
</div>
<div className="flex flex-col h-full items-center justify-between">
<button
ref={regRef}
onClick={() => setActiveTab(0)}
onKeyDown={(e) => e.key === 'Enter' && setActiveTab(0)}
aria-pressed={activeTab === 0}
role="tab"
className={`z-10 text-3xl md:text-4xl font-clash font-bold uppercase tracking-wide px-2 ${
activeTab === 0 ? "text-white" : "text-gray-400"
} cursor-pointer focus:outline-none focus:ring-2 focus:ring-blue-500`}
style={{ letterSpacing: '0.04em' }}
>
REGISTER
</button>
<span
ref={expRef}
className={`z-10 text-3xl md:text-4xl font-clash font-bold uppercase tracking-wide px-2 mt-24 ${
activeTab === 1 ? "text-white" : "text-gray-400"
}`}
style={{ letterSpacing: '0.04em' }}
>
EXPLORE
</span>
<span
ref={buildRef}
className={`z-10 text-3xl md:text-4xl font-clash font-bold uppercase tracking-wide px-2 mt-24 ${
activeTab === 2 ? "text-white" : "text-gray-400"
}`}
style={{ letterSpacing: '0.04em' }}
>
BUILD
</span>
</div>
🤖 Prompt for AI Agents
In src/components/Register.jsx between lines 200 and 228, the tab navigation
spans lack keyboard accessibility and ARIA attributes. To fix this, convert the
spans to button elements or add tabindex="0" to make them focusable, implement
keyboard event handlers to allow navigation via arrow keys or tab, and add
appropriate ARIA roles such as role="tab" and aria-selected attributes to
indicate the active tab. Apply these changes consistently to the REGISTER,
EXPLORE, and BUILD tab elements to improve screen reader and keyboard user
experience.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (7)
src/pages/Home.jsx (7)

155-156: Timer component is incorrectly placed in background effects.

The Timer component should be part of the main content, not background decorations.

This issue was previously identified and remains unresolved.


68-70: Remove unused variables or implement staggered animation.

The text and words variables are declared but never used, causing code clutter.

This issue was previously identified and remains unresolved.


138-138: Remove standalone semicolon.

There's a syntax error with a standalone semicolon that should be removed.

This issue was previously identified and remains unresolved.


372-372: Fix JSX attribute syntax.

The jsx attribute should use boolean syntax instead of string.

This issue was previously identified and remains unresolved.


162-162: Fix useTransform usage in inline style.

The useTransform hook violates React hook rules when called inside JSX.

This issue was previously identified and remains unresolved.


73-136: Potential memory leak in typewriter animation.

The complex async typewriter effect could cause memory leaks if the component unmounts during animation.

This issue was previously identified and remains unresolved.


15-482: 🛠️ Refactor suggestion

Component is too large and handles multiple responsibilities.

This 480+ line component mixes concerns and affects maintainability.

The previous refactoring suggestion to extract typewriter logic, background animations, and CSS styles into separate modules remains valid and should be implemented.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e32400d and 1d03e26.

📒 Files selected for processing (3)
  • src/components/Footer.jsx (1 hunks)
  • src/components/Register.jsx (1 hunks)
  • src/pages/Home.jsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/Register.jsx

Comment on lines +27 to +34
name: 'GITHUB',
url: 'https://app.tinkerhub.org',
icon: (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 16 16">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"/>
</svg>
)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix inconsistent social link naming and URL.

The third social link has the name "GITHUB" but points to "https://app.tinkerhub.org" and uses the GitHub icon. This is misleading and inconsistent.

Consider either:

  1. Changing the name to match the actual destination:
- name: 'GITHUB',
- url: 'https://app.tinkerhub.org',
+ name: 'Hub App',
+ url: 'https://app.tinkerhub.org',
  1. Or use a more appropriate icon for the Hub App instead of the GitHub icon.
🤖 Prompt for AI Agents
In src/components/Footer.jsx around lines 27 to 34, the social link named
"GITHUB" incorrectly points to "https://app.tinkerhub.org" while using the
GitHub icon, causing inconsistency. To fix this, either update the name to
reflect the actual destination URL or replace the GitHub icon with one that
better represents the Hub App. Ensure the name, URL, and icon are consistent and
accurately represent the link's target.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (8)
src/pages/Home.jsx (8)

68-70: Remove unused variables or implement the staggered animation

The text and words variables are created but marked as unused. Either remove them or implement the intended functionality.

-  // For staggered word animation (unused but kept for reference)
-  const text = "Recurring hackathon to build break and learn by doing"
-  const words = text.split(" ")

73-136: Potential memory leak in typewriter animation logic

The complex async typewriter effect with nested timeouts and promises could cause memory leaks if the component unmounts during animation. The current cleanup only clears the last timeout, not all pending timeouts.

Consider refactoring to use a single interval or implementing proper cleanup by tracking all timeout IDs in an array and clearing them all in the cleanup function.


138-138: Remove standalone semicolon

There's a syntax error with a standalone semicolon.

-;

155-156: Incorrect Timer component placement

The Timer component is placed inside the background effects motion.div, which seems incorrect. Timer should likely be part of the main content, not background decorations.

Consider moving the Timer to a more appropriate location in the component hierarchy, perhaps after the Navbar or within the main content area.


161-161: Fix useTransform usage in inline style

The useTransform hook should not be called inside the style prop as it needs to be at the component level.

Move the transform outside the JSX:

+const overlayOpacity = useTransform(scrollYProgress, [0, 0.1], [0, 0.2])

-<div className="absolute inset-0 bg-[#0A0A0F]" style={{ opacity: useTransform(scrollYProgress, [0, 0.1], [0, 0.2]) }}></div>
+<motion.div className="absolute inset-0 bg-[#0A0A0F]" style={{ opacity: overlayOpacity }}></motion.div>

236-243: Accessibility concern: Motion-sensitive users

The continuous typewriter animation and cursor blinking may cause issues for users with motion sensitivity or vestibular disorders.

Add a prefers-reduced-motion check to disable or simplify animations for motion-sensitive users.


375-375: Fix JSX attribute syntax

The jsx attribute should use boolean syntax.

-      <style jsx="true">{`
+      <style jsx>{`

16-485: Refactor large component and optimize performance

This component is too large (485 lines) and handles too many responsibilities. The multiple concurrent animations may also impact performance.

Consider:

  1. Extract the typewriter animation logic into a custom hook
  2. Move background animations to a separate component
  3. Extract the CSS-in-JS styles to a separate file or use CSS modules
  4. Monitor performance impact of multiple concurrent animations

This modularization will improve maintainability and allow better performance monitoring.

🧹 Nitpick comments (1)
src/pages/Home.jsx (1)

407-412: Consider performance impact of infinite grid animation

The grid pattern with infinite vertical translation animation may consume unnecessary resources, especially on lower-end devices.

Consider adding a performance check or allowing users to disable decorative animations:

+const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches

        .grid-pattern {
          background-image: linear-gradient(rgba(255, 255, 227, 0.05) 1px, transparent 1px),
                           linear-gradient(90deg, rgba(255, 255, 227, 0.05) 1px, transparent 1px);
          background-size: 40px 40px;
-          animation: grid-move 100s linear infinite;
+          animation: ${prefersReducedMotion ? 'none' : 'grid-move 100s linear infinite'};
        }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d03e26 and ebe1daa.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • package.json (1 hunks)
  • src/components/Carousel.jsx (1 hunks)
  • src/components/FAQ.jsx (1 hunks)
  • src/components/Footer.jsx (1 hunks)
  • src/components/Partners.jsx (1 hunks)
  • src/components/Register.jsx (1 hunks)
  • src/components/Testimonials.jsx (1 hunks)
  • src/components/Timer.jsx (1 hunks)
  • src/pages/Home.jsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • src/components/Partners.jsx
  • src/components/FAQ.jsx
  • src/components/Register.jsx
  • src/components/Timer.jsx
  • src/components/Testimonials.jsx
  • src/components/Footer.jsx
  • src/components/Carousel.jsx
  • package.json

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (7)
src/pages/Home.jsx (7)

138-138: Remove standalone semicolon

There's a syntax error with a standalone semicolon.

-;

68-70: Remove unused variables or implement the staggered animation

The text and words variables are created but marked as unused. Either remove them or implement the intended functionality.

-  // For staggered word animation (unused but kept for reference)
-  const text = "Recurring hackathon to build break and learn by doing"
-  const words = text.split(" ")

73-136: Potential memory leak in typewriter animation logic

The complex async typewriter effect with nested timeouts and promises could cause memory leaks if the component unmounts during animation. The current cleanup only clears the last timeout, not all pending timeouts.

Consider refactoring to use a single interval or implementing proper cleanup:

useEffect(() => {
-  let timeout
+  let timeouts = []
+  let isMounted = true
  
  const typeLine = async (line) => {
+    if (!isMounted) return
    setIsTyping(true)
    for (let i = 0; i <= line.length; i++) {
+      if (!isMounted) return
      await new Promise(resolve => {
-        timeout = setTimeout(() => {
+        const timeoutId = setTimeout(() => {
          setCurrentText(line.substring(0, i))
          resolve()
        }, 100)
+        timeouts.push(timeoutId)
      })
    }
  }
  
  // Similar changes for backspaceLine and other timeout usages
  
  return () => {
+    isMounted = false
+    timeouts.forEach(clearTimeout)
-    clearTimeout(timeout)
  }
}, [])

158-158: Fix useTransform usage in inline style

The useTransform hook should not be called inside the style prop as it needs to be at the component level.

Move the transform outside the JSX:

+const overlayOpacity = useTransform(scrollYProgress, [0, 0.1], [0, 0.2])

-<div className="absolute inset-0 bg-[#0A0A0F]" style={{ opacity: useTransform(scrollYProgress, [0, 0.1], [0, 0.2]) }}></div>
+<motion.div className="absolute inset-0 bg-[#0A0A0F]" style={{ opacity: overlayOpacity }}></motion.div>

377-377: Fix JSX attribute syntax

The jsx attribute should use boolean syntax.

-      <style jsx="true">{`
+      <style jsx>{`

233-240: Accessibility concern: Motion-sensitive users

The continuous typewriter animation and cursor blinking may cause issues for users with motion sensitivity or vestibular disorders.

Add a prefers-reduced-motion check:

+const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches

// In the typewriter effect
+if (prefersReducedMotion) {
+  setCurrentText(lines[lines.length - 1]) // Show final text immediately
+  return
+}

15-486: Refactor large component and optimize performance

This component is too large (488 lines) and handles too many responsibilities. Consider:

  1. Extract the typewriter animation logic into a custom hook
  2. Move background animations to a separate component
  3. Extract the CSS-in-JS styles to a separate file or use CSS modules
  4. Monitor performance impact of multiple concurrent animations

Example structure:

// hooks/useTypewriter.js
export const useTypewriter = (lines) => {
  // Extract lines 62-135
}

// components/AnimatedBackground.jsx
export const AnimatedBackground = () => {
  // Extract background effects
}

// styles/Home.module.css
/* Move CSS from style tag */
🧹 Nitpick comments (2)
src/pages/Home.jsx (2)

144-144: Remove redundant inline style

The background color is already set in the className, making the inline style redundant.

-      style={{ backgroundColor: "#0A0A0F" }}

163-168: Misplaced comment and content

The "FAQ Section" comment is misleading as this code creates aurora beam effects, not FAQ content. The actual FAQ section is much later in the component.

-        {/* FAQ Section */}
+        {/* Aurora beam effects */}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ebe1daa and d00e92d.

📒 Files selected for processing (3)
  • src/components/Navbar.jsx (1 hunks)
  • src/components/Timer.jsx (1 hunks)
  • src/pages/Home.jsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/Timer.jsx
  • src/components/Navbar.jsx
🔇 Additional comments (1)
src/pages/Home.jsx (1)

311-313: Timer component placement looks correct now

The Timer component has been moved out of the background effects and is now properly positioned at the bottom of the landing section. This addresses the previous placement concern.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (6)
src/pages/Home.jsx (6)

30-32: Remove unused variables or implement staggered animation

These variables are declared but never used in the component logic, which creates unnecessary clutter.

-  // For staggered word animation (unused but kept for reference)
-  const text = "Recurring hackathon to build break and learn by doing"
-  const words = text.split(" ")

35-98: Fix memory leak in typewriter animation

The typewriter effect still has the same memory leak issue where multiple nested timeouts are created but only the last one is tracked for cleanup. If the component unmounts during animation, pending timeouts will continue to execute.

 useEffect(() => {
-  let timeout
+  let timeouts = []
+  let isMounted = true
   
   const typeLine = async (line) => {
+    if (!isMounted) return
     setIsTyping(true)
     for (let i = 0; i <= line.length; i++) {
+      if (!isMounted) return
       await new Promise(resolve => {
-        timeout = setTimeout(() => {
+        const timeoutId = setTimeout(() => {
           setCurrentText(line.substring(0, i))
           resolve()
         }, 100)
+        timeouts.push(timeoutId)
       })
     }
   }
   
   // Apply similar changes to backspaceLine and other timeout usages
   
   return () => {
+    isMounted = false
+    timeouts.forEach(clearTimeout)
-    clearTimeout(timeout)
   }
 }, [])

118-118: Move useTransform hook call outside JSX

The useTransform hook is still being called inside the style prop, which violates React's rules of hooks.

+const overlayOpacity = useTransform(scrollYProgress, [0, 0.1], [0, 0.2])

-<div className="absolute inset-0 bg-[#0A0A0F]" style={{ opacity: useTransform(scrollYProgress, [0, 0.1], [0, 0.2]) }}></div>
+<motion.div className="absolute inset-0 bg-[#0A0A0F]" style={{ opacity: overlayOpacity }}></motion.div>

202-209: Add accessibility support for motion-sensitive users

The continuous typewriter animation and cursor blinking can cause issues for users with motion sensitivity or vestibular disorders.

Consider adding a prefers-reduced-motion check:

+const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches

// In the typewriter effect
+if (prefersReducedMotion) {
+  setCurrentText(lines[lines.length - 1]) // Show final text immediately
+  return
+}

324-324: Make heading text responsive

The text-9xl class creates extremely large text that may cause overflow issues on smaller screens.

-<h1 className="text-9xl font-clash font-medium text-left">We build, we learn. It's the maker mindset.</h1>
+<h1 className="text-4xl md:text-6xl lg:text-8xl xl:text-9xl font-clash font-medium text-left">We build, we learn. It's the maker mindset.</h1>

344-344: Fix JSX attribute syntax

The jsx attribute should use boolean syntax instead of a string value.

-<style jsx="true">{`
+<style jsx>{`
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6168df8 and 8ce8a29.

📒 Files selected for processing (1)
  • src/pages/Home.jsx (1 hunks)

Comment on lines 16 to 451
margin-left: 4px;
animation: blink 1s infinite;
display: inline-block;
}

@keyframes pulse-slow {
0%, 100% { opacity: 0.2; transform: scale(0.95); }
50% { opacity: 0.5; transform: scale(1.05); }
}

.fixed-subtitle-container {
height: 10px;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 30;
margin-bottom: 30px;
}
.perspective-1000 {
perspective: 1000px;
}

.grid-pattern {
background-image: linear-gradient(rgba(255, 255, 227, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 227, 0.05) 1px, transparent 1px);
background-size: 40px 40px;
animation: grid-move 100s linear infinite;
}

.aurora-beam {
position: absolute;
height: 100%;
width: 30px;
filter: blur(30px);
opacity: 0.5;
background: linear-gradient(to bottom, rgba(0, 183, 255, 0.15), rgba(139, 0, 255, 0.05));
transform: skew(20deg);
animation: aurora 15s linear infinite;
}

.aurora-1 {
left: 20%;
animation-delay: 0s;
}

.aurora-2 {
left: 50%;
animation-delay: 5s;
background: linear-gradient(to bottom, rgba(139, 0, 255, 0.15), rgba(0, 183, 255, 0.05));
}

.aurora-3 {
left: 80%;
animation-delay: 10s;
background: linear-gradient(to bottom, rgba(0, 255, 179, 0.15), rgba(179, 0, 255, 0.05));
}

.particles-container {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
}

.particle {
position: absolute;
border-radius: 50%;
}

@keyframes grid-move {
0% {
transform: translateY(0);
}
100% {
transform: translateY(40px);
}
}

@keyframes aurora {
0% {
transform: skew(20deg) translateX(-100px);
}
100% {
transform: skew(20deg) translateX(100px);
}
}

@keyframes bg-gradient-radial {
from {
background-position: 0% 0%;
}
to {
background-position: 100% 100%;
}
}
`}</style>
</div>
)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider component refactoring for maintainability

This component remains very large (455 lines) and handles multiple responsibilities including animations, layout, and styling. The previously suggested refactoring to extract custom hooks, separate components, and CSS modules would improve maintainability and performance monitoring.

Key areas for extraction:

  • Typewriter animation logic into a useTypewriter hook
  • Background animation effects into an AnimatedBackground component
  • CSS-in-JS styles into CSS modules
  • Individual page sections into separate components
🤖 Prompt for AI Agents
In src/pages/Home.jsx from lines 16 to 451, the Home component is too large and
mixes animation logic, layout, and styling, reducing maintainability. Refactor
by extracting the typewriter animation logic into a custom hook named
useTypewriter, move the background animation effects into a separate
AnimatedBackground component, relocate CSS-in-JS styles into CSS modules, and
split individual page sections into their own components. This modularization
will improve code clarity, reusability, and performance monitoring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant