Repository: hiteshchoudhary/Music-school-hindi
Branch: main
Commit: ba6c0536c041
Files: 34
Total size: 70.1 KB
Directory structure:
gitextract_j5k2gb1j/
├── .eslintrc.json
├── .gitignore
├── README.md
├── next.config.mjs
├── package.json
├── postcss.config.js
├── src/
│ ├── app/
│ │ ├── contact/
│ │ │ └── page.tsx
│ │ ├── courses/
│ │ │ └── page.tsx
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ └── page.tsx
│ ├── components/
│ │ ├── FeaturedCourses.tsx
│ │ ├── Footer.tsx
│ │ ├── HeroSection.tsx
│ │ ├── Instructors.tsx
│ │ ├── Navbar.tsx
│ │ ├── TestimonialCards.tsx
│ │ ├── UpcomingWebinars.tsx
│ │ ├── WhyChooseUs.tsx
│ │ └── ui/
│ │ ├── 3d-card.tsx
│ │ ├── Spotlight.tsx
│ │ ├── animated-tooltip.tsx
│ │ ├── background-beams.tsx
│ │ ├── background-gradient.tsx
│ │ ├── card-hover-effect.tsx
│ │ ├── infinite-moving-cards.tsx
│ │ ├── moving-border.tsx
│ │ ├── navbar-menu.tsx
│ │ ├── sticky-scroll-reveal.tsx
│ │ └── wavy-background.tsx
│ ├── data/
│ │ └── music_courses.json
│ └── utils/
│ └── cn.ts
├── tailwind.config.ts
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc.json
================================================
{
"extends": "next/core-web-vitals"
}
================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
================================================
FILE: README.md
================================================
# A music school project in NextJS
## Description
Seach "chai aur code" on youtube and watch it there
## contributon
No need to make any PR in this repo. Specially DO NOT touch the README.md file
================================================
FILE: next.config.mjs
================================================
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
domains: ['images.unsplash.com', 'res.cloudinary.com']
}
};
export default nextConfig;
================================================
FILE: package.json
================================================
{
"name": "musicnextjs",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"clsx": "^2.1.0",
"framer-motion": "^11.0.3",
"mini-svg-data-uri": "^1.4.4",
"next": "14.1.0",
"react": "^18",
"react-dom": "^18",
"simplex-noise": "^4.0.1",
"tailwind-merge": "^2.2.1"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10.0.1",
"eslint": "^8",
"eslint-config-next": "14.1.0",
"postcss": "^8",
"tailwindcss": "^3.3.0",
"typescript": "^5"
}
}
================================================
FILE: postcss.config.js
================================================
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
================================================
FILE: src/app/contact/page.tsx
================================================
'use client';
import React, { FormEvent, useState } from 'react';
import { BackgroundBeams } from '@/components/ui/background-beams';
function MusicSchoolContactUs() {
const [email, setEmail] = useState('');
const [message, setMessage] = useState('');
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log('Submitted:', { email, message });
};
return (
<div className="min-h-screen bg-gray-100 dark:bg-gray-900 py-12 pt-36 relative">
{' '}
{/* Ensure the container is relative */}
{/* BackgroundBeams with adjusted z-index */}
<BackgroundBeams className="absolute top-0 left-0 w-full h-full z-0" />
{/* Content with higher z-index */}
<div className="max-w-2xl mx-auto p-4 relative z-10">
{' '}
{/* Add relative and z-10 to bring content to the front */}
<h1 className="text-lg md:text-7xl text-center font-sans font-bold mb-8 text-white">
Contact Us
</h1>
<p className="text-neutral-500 max-w-lg mx-auto my-2 text-sm text-center">
We're here to help with any questions about our courses,
programs, or events. Reach out and let us know how we can assist you
in your musical journey.
</p>
<form onSubmit={handleSubmit} className="space-y-4 mt-4">
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Your email address"
className="rounded-lg border border-neutral-800 focus:ring-2 focus:ring-teal-500 w-full p-4 bg-neutral-950 placeholder:text-neutral-700"
required
/>
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Your message"
className="rounded-lg border border-neutral-800 focus:ring-2 focus:ring-teal-500 w-full p-4 bg-neutral-950 placeholder:text-neutral-700"
rows={5}
required
></textarea>
<button
type="submit"
className="px-6 py-2 rounded-lg bg-teal-500 text-white font-medium hover:bg-teal-600 focus:outline-none focus:ring-2 focus:ring-teal-500 focus:ring-offset-2"
>
Send Message
</button>
</form>
</div>
</div>
);
}
export default MusicSchoolContactUs;
================================================
FILE: src/app/courses/page.tsx
================================================
'use client'
import Image from "next/image";
import React from "react";
import { CardBody, CardContainer, CardItem } from "@/components/ui/3d-card";
import courseData from "@/data/music_courses.json"
function page() {
return (
<div className="min-h-screen bg-black py-12 pt-36">
<h1 className="text-lg md:text-7xl text-center font-sans font-bold mb-8 text-white">All courses ({courseData.courses.length})</h1>
<div className="flex flex-wrap justify-center">
{courseData.courses.map((course) => (
<CardContainer className="inter-var m-4">
<CardBody className="bg-gray-50 relative group/card dark:hover:shadow-2xl dark:hover:shadow-emerald-500/[0.1] dark:bg-black dark:border-white/[0.2] border-black/[0.1] w-auto sm:w-[30rem] h-auto rounded-xl p-6 border ">
<CardItem
translateZ="50"
className="text-xl font-bold text-neutral-600 dark:text-white"
>
{course.title}
</CardItem>
<CardItem
as="p"
translateZ="60"
className="text-neutral-500 text-sm max-w-sm mt-2 dark:text-neutral-300"
>
{course.description}
</CardItem>
<CardItem translateZ="100" className="w-full mt-4">
<Image
src={course.image}
height="1000"
width="1000"
className="h-60 w-full object-cover rounded-xl group-hover/card:shadow-xl"
alt={course.title}
/>
</CardItem>
<div className="flex justify-between items-center mt-20">
<CardItem
translateZ={20}
as="button"
className="px-4 py-2 rounded-xl text-xs font-normal dark:text-white"
>
Try now →
</CardItem>
<CardItem
translateZ={20}
as="button"
className="px-4 py-2 rounded-xl bg-black dark:bg-white dark:text-black text-white text-xs font-bold"
>
Sign up
</CardItem>
</div>
</CardBody>
</CardContainer>
))}
</div>
</div>
)
}
export default page
================================================
FILE: src/app/globals.css
================================================
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
}
body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(
to bottom,
transparent,
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
}
================================================
FILE: src/app/layout.tsx
================================================
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import Navbar from "@/components/Navbar";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" className="dark">
<body className={inter.className}>
<div className="relative w-full flex items-center justify-center ">
<Navbar />
</div>
{children}
</body>
</html>
);
}
================================================
FILE: src/app/page.tsx
================================================
import FeaturedCourses from "@/components/FeaturedCourses";
import Footer from "@/components/Footer";
import HeroSection from "@/components/HeroSection";
import Instructors from "@/components/Instructors";
import MusicSchoolTestimonials from "@/components/TestimonialCards";
import UpcomingWebinars from "@/components/UpcomingWebinars";
import WhyChooseUs from "@/components/WhyChooseUs";
export default function Home() {
return (
<main className="min-h-screen bg-black/[0.96] antialiased bg-grid-white/[0.02]">
<HeroSection />
<FeaturedCourses />
<WhyChooseUs />
<MusicSchoolTestimonials />
<UpcomingWebinars />
<Instructors />
<Footer />
</main>
);
}
================================================
FILE: src/components/FeaturedCourses.tsx
================================================
'use client'
import Link from "next/link"
import courseData from "../data/music_courses.json"
import { BackgroundGradient } from "./ui/background-gradient"
interface Course{
id: number,
title: string,
slug: string,
description: string,
price: number,
instructor: string,
isFeatured: boolean,
}
function FeaturedCourses() {
const featuredCourses = courseData.courses.filter((course:Course) => course.isFeatured)
return (
<div className="py-12 bg-gray-900">
<div>
<div className="text-center">
<h2 className="text-base text-teal-600 font-semibold tracking-wide uppercase">FEATURED COURSES</h2>
<p className="mt-2 text-3xl leading-8 font-extrabold tracking-tight text-white sm:text-4xl">Learn With the Best</p>
</div>
</div>
<div className="mt-10 mx-8">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 justify-center">
{featuredCourses.map((course:Course)=> (
<div key={course.id} className="flex justify-center">
<BackgroundGradient
className="flex flex-col rounded-[22px] bg-white dark:bg-zinc-900 overflow-hidden h-full max-w-sm">
<div className="p-4 sm:p-6 flex flex-col items-center text-center flex-grow">
<p className="text-lg sm:text-xl text-black mt-4 mb-2 dark:text-neutral-200">{course.title}</p>
<p className="text-sm text-neutral-600 dark:text-neutral-400 flex-grow">{course.description}</p>
<Link href={`/courses/${course.slug}`}>
Learn More
</Link>
</div>
</BackgroundGradient>
</div>
))}
</div>
</div>
<div className="mt-20 text-center">
<Link href={"/courses"}
className="px-4 py-2 rounded border border-neutral-600 text-neutral-700 bg-white hover:bg-gray-100 transition duration-200"
>
View All courses
</Link>
</div>
</div>
)
}
export default FeaturedCourses
================================================
FILE: src/components/Footer.tsx
================================================
function Footer() {
return (
<footer className="bg-black text-gray-400 py-12">
<div className="max-w-6xl mx-auto grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8 px-4 sm:px-6 lg:px-8">
<div>
<h2 className="text-white text-lg font-semibold mb-4">About Us</h2>
<p className="mb-4">
Music School is a premier institution dedicated to teaching the art
and science of music. We nurture talent from the ground up,
fostering a vibrant community of musicians.
</p>
</div>
<div>
<h2 className="text-white text-lg font-semibold mb-4">Quick Links</h2>
<ul>
<li>
<a
href="#"
className="hover:text-white transition-colors duration-300"
>
Home
</a>
</li>
<li>
<a
href="#"
className="hover:text-white transition-colors duration-300"
>
About
</a>
</li>
<li>
<a
href="#"
className="hover:text-white transition-colors duration-300"
>
Courses
</a>
</li>
<li>
<a
href="#"
className="hover:text-white transition-colors duration-300"
>
Contact
</a>
</li>
</ul>
</div>
<div>
<h2 className="text-white text-lg font-semibold mb-4">Follow Us</h2>
<div className="flex space-x-4">
<a
href="#"
className="hover:text-white transition-colors duration-300"
>
Facebook
</a>
<a
href="#"
className="hover:text-white transition-colors duration-300"
>
Twitter
</a>
<a
href="#"
className="hover:text-white transition-colors duration-300"
>
Instagram
</a>
</div>
</div>
<div>
<h2 className="text-white text-lg font-semibold mb-4">Contact Us</h2>
<p>New Delhi, India</p>
<p>Delhi 10001</p>
<p>Email: info@musicschool.com</p>
<p>Phone: (123) 456-7890</p>
</div>
</div>
<p className="text-center text-xs pt-8">© 2024 Music School. All rights reserved.</p>
</footer>
)
}
export default Footer
================================================
FILE: src/components/HeroSection.tsx
================================================
import Link from "next/link"
import { Spotlight } from "./ui/Spotlight"
import { Button } from "./ui/moving-border";
function HeroSection() {
return (
<div
className="h-auto md:h-[40rem] w-full rounded-md flex flex-col items-center justify-center relative overflow-hidden mx-auto py-10 md:py-0"
>
<Spotlight
className="-top-40 left-0 md:left-60 md:-top-20"
fill="white"
/>
<div className="p-4 relative z-10 w-full text-center" >
<h1
className="mt-20 md:mt-0 text-4xl md:text-7xl font-bold bg-clip-text text-transparent bg-gradient-to-b from-neutral-50 to-neutral-400"
>Master the art of music</h1>
<p
className="mt-4 font-normal text-base md:text-lg text-neutral-300 max-w-lg mx-auto"
>Dive into our comprehensive music courses and transform your musical journey today. Whether you're a beginner or looking to refine your skills, join us to unlock your true potential.</p>
<div className="mt-4">
<Link href={"/courses"}>
<Button
borderRadius="1.75rem"
className="bg-white dark:bg-black text-black dark:text-white border-neutral-200 dark:border-slate-800"
>
Explore courses
</Button>
</Link>
</div>
</div>
</div>
)
}
export default HeroSection
================================================
FILE: src/components/Instructors.tsx
================================================
'use client'
import { WavyBackground } from "./ui/wavy-background"
import { AnimatedTooltip } from "./ui/animated-tooltip";
const instructors = [
{
id: 1,
name: 'Elena Briggs',
designation: 'Vocal Coach',
image:
'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTB8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D&auto=format&fit=crop&w=800&q=60',
},
{
id: 2,
name: 'Marcus Reid',
designation: 'Guitar Instructor',
image:
'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=3540&q=80',
},
{
id: 3,
name: 'Julia Zhang',
designation: 'Piano Teacher',
image:
'https://images.unsplash.com/photo-1580489944761-15a19d654956?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8NXx8YXZhdGFyfGVufDB8fDB8fHww&auto=format&fit=crop&w=800&q=60',
},
{
id: 4,
name: 'Andre Gomez',
designation: 'Drumming Expert',
image:
'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Mnx8YXZhdGFyfGVufDB8fDB8fHww&auto=format&fit=crop&w=800&q=60',
},
];
function Instructors() {
return (
<div className="relative h-[40rem] overflow-hidden flex items-center justify-center">
<WavyBackground className="w-full max-w-7xl mx-auto flex flex-col items-center justify-center h-full">
<h2 className="text-2xl md:text-4xl lg:text-7xl text-white font-bold text-center mb-8">Meet Our Instructors</h2>
<p className="text-base md:text-lg text-white text-center mb-4">Discover the talented professionals who will guide your musical journey</p>
<div className="flex flex-row items-center justify-center mb-10 w-full">
<AnimatedTooltip items={instructors} />
</div>
</WavyBackground>
</div>
)
}
export default Instructors
================================================
FILE: src/components/Navbar.tsx
================================================
'use client';
import React, { useState } from "react";
import { HoveredLink, Menu, MenuItem, ProductItem } from "./ui/navbar-menu";
import { cn } from "@/utils/cn";
import Link from "next/link";
function Navbar({ className }: { className?: string }) {
const [active, setActive] = useState<string | null>(null);
return (
<div
className={cn("fixed top-10 inset-x-0 max-w-2xl mx-auto z-50", className)}
>
<Menu setActive={setActive}>
<Link href={"/"}>
<MenuItem setActive={setActive} active={active} item="Home">
</MenuItem>
</Link>
<MenuItem
setActive={setActive} active={active} item="Our Courses"
>
<div className="flex flex-col space-y-4 text-sm">
<HoveredLink href="/courses">All Courses</HoveredLink>
<HoveredLink href="/courses">
Basic Music Theory
</HoveredLink>
<HoveredLink href="/courses">
Advanced Composition
</HoveredLink>
<HoveredLink href="/courses">Songwriting</HoveredLink>
<HoveredLink href="/courses">
Music Production
</HoveredLink>
</div>
</MenuItem>
<Link href={"/contact"}>
<MenuItem setActive={setActive} active={active} item="Contact Us">
</MenuItem>
</Link>
</Menu>
</div>
)
}
export default Navbar
================================================
FILE: src/components/TestimonialCards.tsx
================================================
'use client'
import { InfiniteMovingCards } from "./ui/infinite-moving-cards";
const musicSchoolTestimonials = [
{
quote:
'Joining the music school transformed my understanding of music and helped me to truly discover my own sound. The instructors are world-class!',
name: 'Alex Johnson',
title: 'Guitar Student',
},
{
quote:
"The community and support at this school are unmatched. I've grown not just as a pianist, but also as a performer, thanks to their comprehensive approach.",
name: 'Samantha Lee',
title: 'Piano Student',
},
{
quote:
"This school offered me the tools and confidence to take my singing to the next level. I'm endlessly grateful for the personalized coaching.",
name: 'Michael Chen',
title: 'Vocal Student',
},
{
quote:
'As a violinist, finding the right mentor can be challenging, but this school matched me with a teacher who truly understands my goals and challenges.',
name: 'Emily Taylor',
title: 'Violin Student',
},
{
quote:
'The production courses here opened my eyes to the intricacies of music production. Highly recommend for any aspiring producers!',
name: 'Chris Morales',
title: 'Music Production Student',
},
];
function MusicSchoolTestimonials() {
return (
<div className="h-[40rem] w-full dark:bg-black dark:bg-grid-white/[0.2] relative flex flex-col items-center justify-center overflow-hidden">
<h2 className="text-3xl font-bold text-center mb-8 z-10">Hear our Harmony: Voices of success</h2>
<div className="flex justify-center w-full overflow-hidden px-4 sm:px-6 lg:px-8">
<div className="w-full max-w-6xl">
<InfiniteMovingCards
items={musicSchoolTestimonials}
direction="right"
speed="slow"
/>
</div>
</div>
</div>
)
}
export default MusicSchoolTestimonials
================================================
FILE: src/components/UpcomingWebinars.tsx
================================================
'use client'
import Link from "next/link"
import { HoverEffect } from "./ui/card-hover-effect";
function UpcomingWebinars() {
const featuredWebinars = [
{
title: 'Understanding Music Theory',
description:
'Dive deep into the fundamentals of music theory and enhance your musical skills.',
slug: 'understanding-music-theory',
isFeatured: true,
},
{
title: 'The Art of Songwriting',
description:
'Learn the craft of songwriting from experienced musicians and songwriters.',
slug: 'the-art-of-songwriting',
isFeatured: true,
},
{
title: 'Mastering Your Instrument',
description:
'Advanced techniques to master your musical instrument of choice.',
slug: 'mastering-your-instrument',
isFeatured: true,
},
{
title: 'Music Production Essentials',
description:
'Get started with music production with this comprehensive overview.',
slug: 'music-production-essentials',
isFeatured: true,
},
// Added two more webinars
{
title: 'Live Performance Techniques',
description:
'Enhance your live performance skills with expert tips and strategies.',
slug: 'live-performance-techniques',
isFeatured: true,
},
{
title: 'Digital Music Marketing',
description:
'Learn how to promote your music effectively in the digital age.',
slug: 'digital-music-marketing',
isFeatured: true,
},
];
return (
<div className="p-12 bg-gray-900">
<div className="max-w-7xl mx-auto px-4 sm:px-6">
<div className="text-center">
<h2 className="text-base text-teal-600 font-semibold tracking-wide uppercase">FEATURED WEBINARS</h2>
<p className="mt-2 text-3xl leading-8 font-extrabold tracking-tight text-white sm:text-4xl">Enhance Your Musical Journey</p>
</div>
<div className="mt-10">
<HoverEffect
items={featuredWebinars.map(webinar => (
{
title: webinar.title,
description: webinar.description,
link: '/'
}
))}
/>
</div>
<div className="mt-10 text-center">
<Link href={"/"}
className="px-4 py-2 rounded border border-neutral-600 text-neutral-700 bg-white hover:bg-gray-100 transition duration-200"
>
View All webinars
</Link>
</div>
</div>
</div>
)
}
export default UpcomingWebinars
================================================
FILE: src/components/WhyChooseUs.tsx
================================================
"use client";
import React from "react";
import { StickyScroll } from "./ui/sticky-scroll-reveal";
const musicSchoolContent = [
{
title: 'Discover Your Sound with Us: A Personal Journey in Music Mastery',
description:
'Embark on a musical journey that’s uniquely yours. Our personalized instruction adapts to your individual needs, setting the stage for unparalleled growth and creativity. At our music school, your aspirations meet our dedicated support, creating a harmonious path to mastery.',
},
{
title: 'Discover Your Sound with Us: A Personal Journey in Music Mastery',
description:
'Embark on a musical journey that’s uniquely yours. Our personalized instruction adapts to your individual needs, setting the stage for unparalleled growth and creativity. At our music school, your aspirations meet our dedicated support, creating a harmonious path to mastery.',
},
{
title: 'Discover Your Sound with Us: A Personal Journey in Music Mastery',
description:
'Embark on a musical journey that’s uniquely yours. Our personalized instruction adapts to your individual needs, setting the stage for unparalleled growth and creativity. At our music school, your aspirations meet our dedicated support, creating a harmonious path to mastery.',
},
{
title: 'Live Feedback & Engagement',
description:
'Immerse yourself in an interactive learning experience where feedback is immediate, just like real-time changes in a collaborative project. This approach enhances your understanding and mastery of music concepts and performance techniques.',
},
{
title: 'Cutting-Edge Curriculum',
description:
'Our curriculum is continuously updated to include the latest music education trends and technologies, ensuring you’re always learning with the most current and effective methods. Say goodbye to outdated materials and welcome an education that evolves with the industry.',
},
{
title: 'Limitless Learning Opportunities',
description:
'With our expansive resource library and dynamic course offerings, you’ll never find yourself without something new to explore. Our platform provides continuous opportunities for growth, ensuring your musical skills are always advancing.',
},
];
function WhyChooseUs() {
return (
<div>
<StickyScroll content={musicSchoolContent} />
</div>
)
}
export default WhyChooseUs
================================================
FILE: src/components/ui/3d-card.tsx
================================================
"use client";
import { cn } from "@/utils/cn";
import Image from "next/image";
import React, {
createContext,
useState,
useContext,
useRef,
useEffect,
} from "react";
const MouseEnterContext = createContext<
[boolean, React.Dispatch<React.SetStateAction<boolean>>] | undefined
>(undefined);
export const CardContainer = ({
children,
className,
containerClassName,
}: {
children?: React.ReactNode;
className?: string;
containerClassName?: string;
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const [isMouseEntered, setIsMouseEntered] = useState(false);
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
if (!containerRef.current) return;
const { left, top, width, height } =
containerRef.current.getBoundingClientRect();
const x = (e.clientX - left - width / 2) / 25;
const y = (e.clientY - top - height / 2) / 25;
containerRef.current.style.transform = `rotateY(${x}deg) rotateX(${y}deg)`;
};
const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) => {
setIsMouseEntered(true);
if (!containerRef.current) return;
};
const handleMouseLeave = (e: React.MouseEvent<HTMLDivElement>) => {
if (!containerRef.current) return;
setIsMouseEntered(false);
containerRef.current.style.transform = `rotateY(0deg) rotateX(0deg)`;
};
return (
<MouseEnterContext.Provider value={[isMouseEntered, setIsMouseEntered]}>
<div
className={cn(
"py-20 flex items-center justify-center",
containerClassName
)}
style={{
perspective: "1000px",
}}
>
<div
ref={containerRef}
onMouseEnter={handleMouseEnter}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
className={cn(
"flex items-center justify-center relative transition-all duration-200 ease-linear",
className
)}
style={{
transformStyle: "preserve-3d",
}}
>
{children}
</div>
</div>
</MouseEnterContext.Provider>
);
};
export const CardBody = ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) => {
return (
<div
className={cn(
"h-96 w-96 [transform-style:preserve-3d] [&>*]:[transform-style:preserve-3d]",
className
)}
>
{children}
</div>
);
};
export const CardItem = ({
as: Tag = "div",
children,
className,
translateX = 0,
translateY = 0,
translateZ = 0,
rotateX = 0,
rotateY = 0,
rotateZ = 0,
...rest
}: {
as?: React.ElementType;
children: React.ReactNode;
className?: string;
translateX?: number | string;
translateY?: number | string;
translateZ?: number | string;
rotateX?: number | string;
rotateY?: number | string;
rotateZ?: number | string;
}) => {
const ref = useRef<HTMLDivElement>(null);
const [isMouseEntered] = useMouseEnter();
useEffect(() => {
handleAnimations();
}, [isMouseEntered]);
const handleAnimations = () => {
if (!ref.current) return;
if (isMouseEntered) {
ref.current.style.transform = `translateX(${translateX}px) translateY(${translateY}px) translateZ(${translateZ}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotateZ(${rotateZ}deg)`;
} else {
ref.current.style.transform = `translateX(0px) translateY(0px) translateZ(0px) rotateX(0deg) rotateY(0deg) rotateZ(0deg)`;
}
};
return (
<Tag
ref={ref}
className={cn("w-fit transition duration-200 ease-linear", className)}
{...rest}
>
{children}
</Tag>
);
};
// Create a hook to use the context
export const useMouseEnter = () => {
const context = useContext(MouseEnterContext);
if (context === undefined) {
throw new Error("useMouseEnter must be used within a MouseEnterProvider");
}
return context;
};
================================================
FILE: src/components/ui/Spotlight.tsx
================================================
import React from "react";
import { cn } from "@/utils/cn";
type SpotlightProps = {
className?: string;
fill?: string;
};
export const Spotlight = ({ className, fill }: SpotlightProps) => {
return (
<svg
className={cn(
"animate-spotlight pointer-events-none absolute z-[1] h-[169%] w-[138%] lg:w-[84%] opacity-0",
className
)}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 3787 2842"
fill="none"
>
<g filter="url(#filter)">
<ellipse
cx="1924.71"
cy="273.501"
rx="1924.71"
ry="273.501"
transform="matrix(-0.822377 -0.568943 -0.568943 0.822377 3631.88 2291.09)"
fill={fill || "white"}
fillOpacity="0.21"
></ellipse>
</g>
<defs>
<filter
id="filter"
x="0.860352"
y="0.838989"
width="3785.16"
height="2840.26"
filterUnits="userSpaceOnUse"
colorInterpolationFilters="sRGB"
>
<feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
<feBlend
mode="normal"
in="SourceGraphic"
in2="BackgroundImageFix"
result="shape"
></feBlend>
<feGaussianBlur
stdDeviation="151"
result="effect1_foregroundBlur_1065_8"
></feGaussianBlur>
</filter>
</defs>
</svg>
);
};
================================================
FILE: src/components/ui/animated-tooltip.tsx
================================================
"use client";
import Image from "next/image";
import React, { useState } from "react";
import {
motion,
useTransform,
AnimatePresence,
useMotionValue,
useSpring,
} from "framer-motion";
export const AnimatedTooltip = ({
items,
}: {
items: {
id: number;
name: string;
designation: string;
image: string;
}[];
}) => {
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
const springConfig = { stiffness: 100, damping: 5 };
const x = useMotionValue(0); // going to set this value on mouse move
// rotate the tooltip
const rotate = useSpring(
useTransform(x, [-100, 100], [-45, 45]),
springConfig
);
// translate the tooltip
const translateX = useSpring(
useTransform(x, [-100, 100], [-50, 50]),
springConfig
);
const handleMouseMove = (event: any) => {
const halfWidth = event.target.offsetWidth / 2;
x.set(event.nativeEvent.offsetX - halfWidth); // set the x value, which is then used in transform and rotate
};
return (
<>
{items.map((item, idx) => (
<div
className="-mr-4 relative group"
key={item.name}
onMouseEnter={() => setHoveredIndex(item.id)}
onMouseLeave={() => setHoveredIndex(null)}
>
<AnimatePresence mode="wait">
{hoveredIndex === item.id && (
<motion.div
initial={{ opacity: 0, y: 20, scale: 0.6 }}
animate={{
opacity: 1,
y: 0,
scale: 1,
transition: {
type: "spring",
stiffness: 260,
damping: 10,
},
}}
exit={{ opacity: 0, y: 20, scale: 0.6 }}
style={{
translateX: translateX,
rotate: rotate,
whiteSpace: "nowrap",
}}
className="absolute -top-16 -left-1/2 translate-x-1/2 flex text-xs flex-col items-center justify-center rounded-md bg-black z-50 shadow-xl px-4 py-2"
>
<div className="absolute inset-x-10 z-30 w-[20%] -bottom-px bg-gradient-to-r from-transparent via-emerald-500 to-transparent h-px " />
<div className="absolute left-10 w-[40%] z-30 -bottom-px bg-gradient-to-r from-transparent via-sky-500 to-transparent h-px " />
<div className="font-bold text-white relative z-30 text-base">
{item.name}
</div>
<div className="text-white text-xs">{item.designation}</div>
</motion.div>
)}
</AnimatePresence>
<Image
onMouseMove={handleMouseMove}
height={100}
width={100}
src={item.image}
alt={item.name}
className="object-cover !m-0 !p-0 object-top rounded-full h-14 w-14 border-2 group-hover:scale-105 group-hover:z-30 border-white relative transition duration-500"
/>
</div>
))}
</>
);
};
================================================
FILE: src/components/ui/background-beams.tsx
================================================
'use client';
import React from 'react';
import { motion } from 'framer-motion';
import { cn } from '@/utils/cn';
export function BackgroundBeamsDemo() {
return (
<div className="h-screen bg-neutral-950 relative flex flex-col items-center justify-center antialiased">
<div className="max-w-2xl mx-auto p-4">
<h1 className="relative z-10 text-lg md:text-7xl bg-clip-text text-transparent bg-gradient-to-b from-neutral-200 to-neutral-600 text-center font-sans font-bold">
Join the waitlist
</h1>
<p></p>
<p className="text-neutral-500 max-w-lg mx-auto my-2 text-sm text-center relative z-10">
Welcome to MailJet, the best transactional email service on the web.
We provide reliable, scalable, and customizable email solutions for
your business. Whether you're sending order confirmations,
password reset emails, or promotional campaigns, MailJet has got you
covered.
</p>
<input
type="text"
placeholder="hi@manuarora.in"
className="rounded-lg border border-neutral-800 focus:ring-2 focus:ring-teal-500 w-full relative z-10 mt-4 bg-neutral-950 placeholder:text-neutral-700"
/>
</div>
<BackgroundBeams />
</div>
);
}
export const BackgroundBeams = ({ className }: { className?: string }) => {
const paths = [
'M-380 -189C-380 -189 -312 216 152 343C616 470 684 875 684 875',
'M-373 -197C-373 -197 -305 208 159 335C623 462 691 867 691 867',
'M-366 -205C-366 -205 -298 200 166 327C630 454 698 859 698 859',
'M-359 -213C-359 -213 -291 192 173 319C637 446 705 851 705 851',
'M-352 -221C-352 -221 -284 184 180 311C644 438 712 843 712 843',
'M-345 -229C-345 -229 -277 176 187 303C651 430 719 835 719 835',
'M-338 -237C-338 -237 -270 168 194 295C658 422 726 827 726 827',
'M-331 -245C-331 -245 -263 160 201 287C665 414 733 819 733 819',
'M-324 -253C-324 -253 -256 152 208 279C672 406 740 811 740 811',
'M-317 -261C-317 -261 -249 144 215 271C679 398 747 803 747 803',
'M-310 -269C-310 -269 -242 136 222 263C686 390 754 795 754 795',
'M-303 -277C-303 -277 -235 128 229 255C693 382 761 787 761 787',
'M-296 -285C-296 -285 -228 120 236 247C700 374 768 779 768 779',
'M-289 -293C-289 -293 -221 112 243 239C707 366 775 771 775 771',
'M-282 -301C-282 -301 -214 104 250 231C714 358 782 763 782 763',
'M-275 -309C-275 -309 -207 96 257 223C721 350 789 755 789 755',
'M-268 -317C-268 -317 -200 88 264 215C728 342 796 747 796 747',
'M-261 -325C-261 -325 -193 80 271 207C735 334 803 739 803 739',
'M-254 -333C-254 -333 -186 72 278 199C742 326 810 731 810 731',
'M-247 -341C-247 -341 -179 64 285 191C749 318 817 723 817 723',
'M-240 -349C-240 -349 -172 56 292 183C756 310 824 715 824 715',
'M-233 -357C-233 -357 -165 48 299 175C763 302 831 707 831 707',
'M-226 -365C-226 -365 -158 40 306 167C770 294 838 699 838 699',
'M-219 -373C-219 -373 -151 32 313 159C777 286 845 691 845 691',
'M-212 -381C-212 -381 -144 24 320 151C784 278 852 683 852 683',
'M-205 -389C-205 -389 -137 16 327 143C791 270 859 675 859 675',
'M-198 -397C-198 -397 -130 8 334 135C798 262 866 667 866 667',
'M-191 -405C-191 -405 -123 0 341 127C805 254 873 659 873 659',
'M-184 -413C-184 -413 -116 -8 348 119C812 246 880 651 880 651',
'M-177 -421C-177 -421 -109 -16 355 111C819 238 887 643 887 643',
'M-170 -429C-170 -429 -102 -24 362 103C826 230 894 635 894 635',
'M-163 -437C-163 -437 -95 -32 369 95C833 222 901 627 901 627',
'M-156 -445C-156 -445 -88 -40 376 87C840 214 908 619 908 619',
'M-149 -453C-149 -453 -81 -48 383 79C847 206 915 611 915 611',
'M-142 -461C-142 -461 -74 -56 390 71C854 198 922 603 922 603',
'M-135 -469C-135 -469 -67 -64 397 63C861 190 929 595 929 595',
'M-128 -477C-128 -477 -60 -72 404 55C868 182 936 587 936 587',
'M-121 -485C-121 -485 -53 -80 411 47C875 174 943 579 943 579',
'M-114 -493C-114 -493 -46 -88 418 39C882 166 950 571 950 571',
'M-107 -501C-107 -501 -39 -96 425 31C889 158 957 563 957 563',
'M-100 -509C-100 -509 -32 -104 432 23C896 150 964 555 964 555',
'M-93 -517C-93 -517 -25 -112 439 15C903 142 971 547 971 547',
'M-86 -525C-86 -525 -18 -120 446 7C910 134 978 539 978 539',
'M-79 -533C-79 -533 -11 -128 453 -1C917 126 985 531 985 531',
'M-72 -541C-72 -541 -4 -136 460 -9C924 118 992 523 992 523',
'M-65 -549C-65 -549 3 -144 467 -17C931 110 999 515 999 515',
'M-58 -557C-58 -557 10 -152 474 -25C938 102 1006 507 1006 507',
'M-51 -565C-51 -565 17 -160 481 -33C945 94 1013 499 1013 499',
'M-44 -573C-44 -573 24 -168 488 -41C952 86 1020 491 1020 491',
'M-37 -581C-37 -581 31 -176 495 -49C959 78 1027 483 1027 483',
];
return (
<div
className={cn(
'absolute h-full w-full inset-0 [mask-size:40px] [mask-repeat:no-repeat] flex items-center justify-center',
className
)}
>
<svg
className=" z-0 h-full w-full pointer-events-none absolute "
width="100%"
height="100%"
viewBox="0 0 696 316"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M-380 -189C-380 -189 -312 216 152 343C616 470 684 875 684 875M-373 -197C-373 -197 -305 208 159 335C623 462 691 867 691 867M-366 -205C-366 -205 -298 200 166 327C630 454 698 859 698 859M-359 -213C-359 -213 -291 192 173 319C637 446 705 851 705 851M-352 -221C-352 -221 -284 184 180 311C644 438 712 843 712 843M-345 -229C-345 -229 -277 176 187 303C651 430 719 835 719 835M-338 -237C-338 -237 -270 168 194 295C658 422 726 827 726 827M-331 -245C-331 -245 -263 160 201 287C665 414 733 819 733 819M-324 -253C-324 -253 -256 152 208 279C672 406 740 811 740 811M-317 -261C-317 -261 -249 144 215 271C679 398 747 803 747 803M-310 -269C-310 -269 -242 136 222 263C686 390 754 795 754 795M-303 -277C-303 -277 -235 128 229 255C693 382 761 787 761 787M-296 -285C-296 -285 -228 120 236 247C700 374 768 779 768 779M-289 -293C-289 -293 -221 112 243 239C707 366 775 771 775 771M-282 -301C-282 -301 -214 104 250 231C714 358 782 763 782 763M-275 -309C-275 -309 -207 96 257 223C721 350 789 755 789 755M-268 -317C-268 -317 -200 88 264 215C728 342 796 747 796 747M-261 -325C-261 -325 -193 80 271 207C735 334 803 739 803 739M-254 -333C-254 -333 -186 72 278 199C742 326 810 731 810 731M-247 -341C-247 -341 -179 64 285 191C749 318 817 723 817 723M-240 -349C-240 -349 -172 56 292 183C756 310 824 715 824 715M-233 -357C-233 -357 -165 48 299 175C763 302 831 707 831 707M-226 -365C-226 -365 -158 40 306 167C770 294 838 699 838 699M-219 -373C-219 -373 -151 32 313 159C777 286 845 691 845 691M-212 -381C-212 -381 -144 24 320 151C784 278 852 683 852 683M-205 -389C-205 -389 -137 16 327 143C791 270 859 675 859 675M-198 -397C-198 -397 -130 8 334 135C798 262 866 667 866 667M-191 -405C-191 -405 -123 0 341 127C805 254 873 659 873 659M-184 -413C-184 -413 -116 -8 348 119C812 246 880 651 880 651M-177 -421C-177 -421 -109 -16 355 111C819 238 887 643 887 643M-170 -429C-170 -429 -102 -24 362 103C826 230 894 635 894 635M-163 -437C-163 -437 -95 -32 369 95C833 222 901 627 901 627M-156 -445C-156 -445 -88 -40 376 87C840 214 908 619 908 619M-149 -453C-149 -453 -81 -48 383 79C847 206 915 611 915 611M-142 -461C-142 -461 -74 -56 390 71C854 198 922 603 922 603M-135 -469C-135 -469 -67 -64 397 63C861 190 929 595 929 595M-128 -477C-128 -477 -60 -72 404 55C868 182 936 587 936 587M-121 -485C-121 -485 -53 -80 411 47C875 174 943 579 943 579M-114 -493C-114 -493 -46 -88 418 39C882 166 950 571 950 571M-107 -501C-107 -501 -39 -96 425 31C889 158 957 563 957 563M-100 -509C-100 -509 -32 -104 432 23C896 150 964 555 964 555M-93 -517C-93 -517 -25 -112 439 15C903 142 971 547 971 547M-86 -525C-86 -525 -18 -120 446 7C910 134 978 539 978 539M-79 -533C-79 -533 -11 -128 453 -1C917 126 985 531 985 531M-72 -541C-72 -541 -4 -136 460 -9C924 118 992 523 992 523M-65 -549C-65 -549 3 -144 467 -17C931 110 999 515 999 515M-58 -557C-58 -557 10 -152 474 -25C938 102 1006 507 1006 507M-51 -565C-51 -565 17 -160 481 -33C945 94 1013 499 1013 499M-44 -573C-44 -573 24 -168 488 -41C952 86 1020 491 1020 491M-37 -581C-37 -581 31 -176 495 -49C959 78 1027 483 1027 483M-30 -589C-30 -589 38 -184 502 -57C966 70 1034 475 1034 475M-23 -597C-23 -597 45 -192 509 -65C973 62 1041 467 1041 467M-16 -605C-16 -605 52 -200 516 -73C980 54 1048 459 1048 459M-9 -613C-9 -613 59 -208 523 -81C987 46 1055 451 1055 451M-2 -621C-2 -621 66 -216 530 -89C994 38 1062 443 1062 443M5 -629C5 -629 73 -224 537 -97C1001 30 1069 435 1069 435M12 -637C12 -637 80 -232 544 -105C1008 22 1076 427 1076 427M19 -645C19 -645 87 -240 551 -113C1015 14 1083 419 1083 419"
stroke="url(#paint0_radial_242_278)"
strokeOpacity="0.05"
strokeWidth="0.5"
></path>
{paths.map((path, index) => (
<motion.path
key={index}
d={path}
stroke={`url(#linearGradient-${index})`}
strokeOpacity="0.4"
strokeWidth="0.5"
></motion.path>
))}
<defs>
{paths.map((path, index) => (
<motion.linearGradient
id={`linearGradient-${index}`}
x1="100%"
x2="100%"
y1="100%"
y2="100%"
key={`gradient-${index}`}
animate={{
x1: ['0%', '100%'],
x2: ['0%', '95%'],
y1: ['0%', '100%'],
y2: ['0%', `${93 + Math.random() * 8}%`],
}}
transition={{
duration: Math.random() * 10 + 10,
ease: 'easeInOut',
repeat: Infinity,
delay: Math.random() * 10,
}}
>
<stop stopColor="#18CCFC" stopOpacity="0"></stop>
<stop stopColor="#18CCFC"></stop>
<stop offset="32.5%" stopColor="#6344F5"></stop>
<stop offset="100%" stopColor="#AE48FF" stopOpacity="0"></stop>
</motion.linearGradient>
))}
<radialGradient
id="paint0_radial_242_278"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(352 34) rotate(90) scale(555 1560.62)"
>
<stop offset="0.0666667" stopColor="var(--neutral-300)"></stop>
<stop offset="0.243243" stopColor="var(--neutral-300)"></stop>
<stop offset="0.43594" stopColor="white" stopOpacity="0"></stop>
</radialGradient>
</defs>
</svg>
</div>
);
};
================================================
FILE: src/components/ui/background-gradient.tsx
================================================
import { cn } from "@/utils/cn";
import React from "react";
import { motion } from "framer-motion";
export const BackgroundGradient = ({
children,
className,
containerClassName,
animate = true,
}: {
children?: React.ReactNode;
className?: string;
containerClassName?: string;
animate?: boolean;
}) => {
const variants = {
initial: {
backgroundPosition: "0 50%",
},
animate: {
backgroundPosition: ["0, 50%", "100% 50%", "0 50%"],
},
};
return (
<div className={cn("relative p-[4px] group", containerClassName)}>
<motion.div
variants={animate ? variants : undefined}
initial={animate ? "initial" : undefined}
animate={animate ? "animate" : undefined}
transition={
animate
? {
duration: 5,
repeat: Infinity,
repeatType: "reverse",
}
: undefined
}
style={{
backgroundSize: animate ? "400% 400%" : undefined,
}}
className={cn(
"absolute inset-0 rounded-3xl z-[1] opacity-60 group-hover:opacity-100 blur-xl transition duration-500",
" bg-[radial-gradient(circle_farthest-side_at_0_100%,#00ccb1,transparent),radial-gradient(circle_farthest-side_at_100%_0,#7b61ff,transparent),radial-gradient(circle_farthest-side_at_100%_100%,#ffc414,transparent),radial-gradient(circle_farthest-side_at_0_0,#1ca0fb,#141316)]"
)}
/>
<motion.div
variants={animate ? variants : undefined}
initial={animate ? "initial" : undefined}
animate={animate ? "animate" : undefined}
transition={
animate
? {
duration: 5,
repeat: Infinity,
repeatType: "reverse",
}
: undefined
}
style={{
backgroundSize: animate ? "400% 400%" : undefined,
}}
className={cn(
"absolute inset-0 rounded-3xl z-[1]",
"bg-[radial-gradient(circle_farthest-side_at_0_100%,#00ccb1,transparent),radial-gradient(circle_farthest-side_at_100%_0,#7b61ff,transparent),radial-gradient(circle_farthest-side_at_100%_100%,#ffc414,transparent),radial-gradient(circle_farthest-side_at_0_0,#1ca0fb,#141316)]"
)}
/>
<div className={cn("relative z-10", className)}>{children}</div>
</div>
);
};
================================================
FILE: src/components/ui/card-hover-effect.tsx
================================================
import { cn } from "@/utils/cn";
import { AnimatePresence, motion } from "framer-motion";
import Link from "next/link";
import { useState } from "react";
export const HoverEffect = ({
items,
className,
}: {
items: {
title: string;
description: string;
link: string;
}[];
className?: string;
}) => {
let [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
return (
<div
className={cn(
"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 py-10",
className
)}
>
{items.map((item, idx) => (
<Link
href={item?.link}
key={item?.link}
className="relative group block p-2 h-full w-full"
onMouseEnter={() => setHoveredIndex(idx)}
onMouseLeave={() => setHoveredIndex(null)}
>
<AnimatePresence>
{hoveredIndex === idx && (
<motion.span
className="absolute inset-0 h-full w-full bg-neutral-200 dark:bg-slate-800/[0.8] block rounded-3xl"
layoutId="hoverBackground"
initial={{ opacity: 0 }}
animate={{
opacity: 1,
transition: { duration: 0.15 },
}}
exit={{
opacity: 0,
transition: { duration: 0.15, delay: 0.2 },
}}
/>
)}
</AnimatePresence>
<Card>
<CardTitle>{item.title}</CardTitle>
<CardDescription>{item.description}</CardDescription>
</Card>
</Link>
))}
</div>
);
};
export const Card = ({
className,
children,
}: {
className?: string;
children: React.ReactNode;
}) => {
return (
<div
className={cn(
"rounded-2xl h-full w-full p-4 overflow-hidden bg-black border border-transparent dark:border-white/[0.2] group-hover:border-slate-700 relative z-50",
className
)}
>
<div className="relative z-50">
<div className="p-4">{children}</div>
</div>
</div>
);
};
export const CardTitle = ({
className,
children,
}: {
className?: string;
children: React.ReactNode;
}) => {
return (
<h4 className={cn("text-zinc-100 font-bold tracking-wide mt-4", className)}>
{children}
</h4>
);
};
export const CardDescription = ({
className,
children,
}: {
className?: string;
children: React.ReactNode;
}) => {
return (
<p
className={cn(
"mt-8 text-zinc-400 tracking-wide leading-relaxed text-sm",
className
)}
>
{children}
</p>
);
};
================================================
FILE: src/components/ui/infinite-moving-cards.tsx
================================================
"use client";
import { cn } from "@/utils/cn";
import React, { useEffect, useState } from "react";
export const InfiniteMovingCards = ({
items,
direction = "left",
speed = "fast",
pauseOnHover = true,
className,
}: {
items: {
quote: string;
name: string;
title: string;
}[];
direction?: "left" | "right";
speed?: "fast" | "normal" | "slow";
pauseOnHover?: boolean;
className?: string;
}) => {
const containerRef = React.useRef<HTMLDivElement>(null);
const scrollerRef = React.useRef<HTMLUListElement>(null);
useEffect(() => {
addAnimation();
}, []);
const [start, setStart] = useState(false);
function addAnimation() {
if (containerRef.current && scrollerRef.current) {
const scrollerContent = Array.from(scrollerRef.current.children);
scrollerContent.forEach((item) => {
const duplicatedItem = item.cloneNode(true);
if (scrollerRef.current) {
scrollerRef.current.appendChild(duplicatedItem);
}
});
getDirection();
getSpeed();
setStart(true);
}
}
const getDirection = () => {
if (containerRef.current) {
if (direction === "left") {
containerRef.current.style.setProperty(
"--animation-direction",
"forwards"
);
} else {
containerRef.current.style.setProperty(
"--animation-direction",
"reverse"
);
}
}
};
const getSpeed = () => {
if (containerRef.current) {
if (speed === "fast") {
containerRef.current.style.setProperty("--animation-duration", "20s");
} else if (speed === "normal") {
containerRef.current.style.setProperty("--animation-duration", "40s");
} else {
containerRef.current.style.setProperty("--animation-duration", "80s");
}
}
};
return (
<div
ref={containerRef}
className={cn(
"scroller relative z-20 max-w-7xl overflow-hidden [mask-image:linear-gradient(to_right,transparent,white_20%,white_80%,transparent)]",
className
)}
>
<ul
ref={scrollerRef}
className={cn(
" flex min-w-full shrink-0 gap-4 py-4 w-max flex-nowrap",
start && "animate-scroll ",
pauseOnHover && "hover:[animation-play-state:paused]"
)}
>
{items.map((item, idx) => (
<li
className="w-[350px] max-w-full relative rounded-2xl border border-b-0 flex-shrink-0 border-slate-700 px-8 py-6 md:w-[450px]"
style={{
background:
"linear-gradient(180deg, var(--slate-800), var(--slate-900)",
}}
key={item.name}
>
<blockquote>
<div
aria-hidden="true"
className="user-select-none -z-1 pointer-events-none absolute -left-0.5 -top-0.5 h-[calc(100%_+_4px)] w-[calc(100%_+_4px)]"
></div>
<span className=" relative z-20 text-sm leading-[1.6] text-gray-100 font-normal">
{item.quote}
</span>
<div className="relative z-20 mt-6 flex flex-row items-center">
<span className="flex flex-col gap-1">
<span className=" text-sm leading-[1.6] text-gray-400 font-normal">
{item.name}
</span>
<span className=" text-sm leading-[1.6] text-gray-400 font-normal">
{item.title}
</span>
</span>
</div>
</blockquote>
</li>
))}
</ul>
</div>
);
};
================================================
FILE: src/components/ui/moving-border.tsx
================================================
"use client";
import React from "react";
import {
motion,
useAnimationFrame,
useMotionTemplate,
useMotionValue,
useTransform,
} from "framer-motion";
import { useRef } from "react";
import { cn } from "@/utils/cn";
export function Button({
borderRadius = "1.75rem",
children,
as: Component = "button",
containerClassName,
borderClassName,
duration,
className,
...otherProps
}: {
borderRadius?: string;
children: React.ReactNode;
as?: any;
containerClassName?: string;
borderClassName?: string;
duration?: number;
className?: string;
[key: string]: any;
}) {
return (
<Component
className={cn(
"bg-transparent relative text-xl h-16 w-40 p-[1px] overflow-hidden ",
containerClassName
)}
style={{
borderRadius: borderRadius,
}}
{...otherProps}
>
<div
className="absolute inset-0"
style={{ borderRadius: `calc(${borderRadius} * 0.96)` }}
>
<MovingBorder duration={duration} rx="30%" ry="30%">
<div
className={cn(
"h-20 w-20 opacity-[0.8] bg-[radial-gradient(var(--sky-500)_40%,transparent_60%)]",
borderClassName
)}
/>
</MovingBorder>
</div>
<div
className={cn(
"relative bg-slate-900/[0.8] border border-slate-800 backdrop-blur-xl text-white flex items-center justify-center w-full h-full text-sm antialiased",
className
)}
style={{
borderRadius: `calc(${borderRadius} * 0.96)`,
}}
>
{children}
</div>
</Component>
);
}
export const MovingBorder = ({
children,
duration = 2000,
rx,
ry,
...otherProps
}: {
children: React.ReactNode;
duration?: number;
rx?: string;
ry?: string;
[key: string]: any;
}) => {
const pathRef = useRef<any>();
const progress = useMotionValue<number>(0);
useAnimationFrame((time) => {
const length = pathRef.current?.getTotalLength();
if (length) {
const pxPerMillisecond = length / duration;
progress.set((time * pxPerMillisecond) % length);
}
});
const x = useTransform(
progress,
(val) => pathRef.current?.getPointAtLength(val).x
);
const y = useTransform(
progress,
(val) => pathRef.current?.getPointAtLength(val).y
);
const transform = useMotionTemplate`translateX(${x}px) translateY(${y}px) translateX(-50%) translateY(-50%)`;
return (
<>
<svg
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="none"
className="absolute h-full w-full"
width="100%"
height="100%"
{...otherProps}
>
<rect
fill="none"
width="100%"
height="100%"
rx={rx}
ry={ry}
ref={pathRef}
/>
</svg>
<motion.div
style={{
position: "absolute",
top: 0,
left: 0,
display: "inline-block",
transform,
}}
>
{children}
</motion.div>
</>
);
};
================================================
FILE: src/components/ui/navbar-menu.tsx
================================================
"use client";
import React from "react";
import { motion } from "framer-motion";
import Link from "next/link";
import Image from "next/image";
const transition = {
type: "spring",
mass: 0.5,
damping: 11.5,
stiffness: 100,
restDelta: 0.001,
restSpeed: 0.001,
};
export const MenuItem = ({
setActive,
active,
item,
children,
}: {
setActive: (item: string) => void;
active: string | null;
item: string;
children?: React.ReactNode;
}) => {
return (
<div onMouseEnter={() => setActive(item)} className="relative ">
<motion.p
transition={{ duration: 0.3 }}
className="cursor-pointer text-black hover:opacity-[0.9] dark:text-white"
>
{item}
</motion.p>
{active !== null && (
<motion.div
initial={{ opacity: 0, scale: 0.85, y: 10 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
transition={transition}
>
{active === item && children && (
<div className="absolute top-[calc(100%_+_1.7rem)] left-1/2 transform -translate-x-1/2">
<motion.div
transition={transition}
layoutId="active" // layoutId ensures smooth animation
className="bg-white dark:bg-black backdrop-blur-sm rounded-2xl overflow-hidden border border-black/[0.2] dark:border-white/[0.2] shadow-xl"
>
<motion.div
layout // layout ensures smooth animation
className="w-max h-full p-4"
>
{children}
</motion.div>
</motion.div>
</div>
)}
</motion.div>
)}
</div>
);
};
export const Menu = ({
setActive,
children,
}: {
setActive: (item: string | null) => void;
children: React.ReactNode;
}) => {
return (
<nav
onMouseLeave={() => setActive(null)} // resets the state
className="relative rounded-full boder border-transparent dark:bg-black dark:border-white/[0.2] bg-white shadow-input flex justify-center space-x-4 px-8 py-6 "
>
{children}
</nav>
);
};
export const ProductItem = ({
title,
description,
href,
src,
}: {
title: string;
description: string;
href: string;
src: string;
}) => {
return (
<Link href={href} className="flex space-x-2">
<Image
src={src}
width={140}
height={70}
alt={title}
className="flex-shrink-0 rounded-md shadow-2xl"
/>
<div>
<h4 className="text-xl font-bold mb-1 text-black dark:text-white">
{title}
</h4>
<p className="text-neutral-700 text-sm max-w-[10rem] dark:text-neutral-300">
{description}
</p>
</div>
</Link>
);
};
export const HoveredLink = ({ children, ...rest }: any) => {
return (
<Link
{...rest}
className="text-neutral-700 dark:text-neutral-200 hover:text-black "
>
{children}
</Link>
);
};
================================================
FILE: src/components/ui/sticky-scroll-reveal.tsx
================================================
"use client";
import React, { useRef } from "react";
import { useMotionValueEvent, useScroll } from "framer-motion";
import { motion } from "framer-motion";
export const StickyScroll = ({
content,
}: {
content: {
title: string;
description: string;
}[];
}) => {
const [activeCard, setActiveCard] = React.useState(0);
const ref = useRef<any>(null);
const { scrollYProgress } = useScroll({
container: ref,
offset: ["start start", "end start"],
});
const cardLength = content.length;
useMotionValueEvent(scrollYProgress, "change", (latest) => {
const cardsBreakpoints = content.map((_, index) => index / cardLength);
cardsBreakpoints.forEach((breakpoint, index) => {
if (latest > breakpoint - 0.2 && latest <= breakpoint) {
setActiveCard(() => index);
}
});
});
const backgroundColors = [
"var(--slate-900)",
"var(--black)",
"var(--neutral-900)",
];
const linearGradients = [
"linear-gradient(to bottom right, var(--cyan-500), var(--emerald-500))",
"linear-gradient(to bottom right, var(--pink-500), var(--indigo-500))",
"linear-gradient(to bottom right, var(--orange-500), var(--yellow-500))",
];
return (
<motion.div
animate={{
backgroundColor: backgroundColors[activeCard % backgroundColors.length],
}}
className="h-[30rem] overflow-y-auto flex justify-center relative space-x-10 rounded-md p-10"
ref={ref}
>
<div className="div relative flex items-start px-4">
<div className="max-w-2xl">
{content.map((item, index) => (
<div key={item.title + index} className="my-20">
<motion.h2
initial={{
opacity: 0,
}}
animate={{
opacity: activeCard === index ? 1 : 0.3,
}}
className="text-2xl font-bold text-slate-100"
>
{item.title}
</motion.h2>
<motion.p
initial={{
opacity: 0,
}}
animate={{
opacity: activeCard === index ? 1 : 0.3,
}}
className="text-kg text-slate-300 max-w-sm mt-10"
>
{item.description}
</motion.p>
</div>
))}
<div className="h-40" />
</div>
</div>
<motion.div
animate={{
background: linearGradients[activeCard % linearGradients.length],
}}
className="hidden lg:block h-60 w-80 rounded-md bg-white sticky top-10 overflow-hidden"
></motion.div>
</motion.div>
);
};
================================================
FILE: src/components/ui/wavy-background.tsx
================================================
"use client";
import { cn } from "@/utils/cn";
import React, { useEffect, useRef } from "react";
import { createNoise3D } from "simplex-noise";
export const WavyBackground = ({
children,
className,
containerClassName,
colors,
waveWidth,
backgroundFill,
blur = 10,
speed = "fast",
waveOpacity = 0.5,
...props
}: {
children?: any;
className?: string;
containerClassName?: string;
colors?: string[];
waveWidth?: number;
backgroundFill?: string;
blur?: number;
speed?: "slow" | "fast";
waveOpacity?: number;
[key: string]: any;
}) => {
const noise = createNoise3D();
let w: number,
h: number,
nt: number,
i: number,
x: number,
ctx: any,
canvas: any;
const canvasRef = useRef<HTMLCanvasElement>(null);
const getSpeed = () => {
switch (speed) {
case "slow":
return 0.001;
case "fast":
return 0.002;
default:
return 0.001;
}
};
const init = () => {
canvas = canvasRef.current;
ctx = canvas.getContext("2d");
w = ctx.canvas.width = window.innerWidth;
h = ctx.canvas.height = window.innerHeight;
ctx.filter = `blur(${blur}px)`;
nt = 0;
window.onresize = function () {
w = ctx.canvas.width = window.innerWidth;
h = ctx.canvas.height = window.innerHeight;
ctx.filter = `blur(${blur}px)`;
};
render();
};
const waveColors = colors ?? [
"#38bdf8",
"#818cf8",
"#c084fc",
"#e879f9",
"#22d3ee",
];
const drawWave = (n: number) => {
nt += getSpeed();
for (i = 0; i < n; i++) {
ctx.beginPath();
ctx.lineWidth = waveWidth || 50;
ctx.strokeStyle = waveColors[i % waveColors.length];
for (x = 0; x < w; x += 5) {
var y = noise(x / 800, 0.3 * i, nt) * 100;
ctx.lineTo(x, y + h * 0.5); // adjust for height, currently at 50% of the container
}
ctx.stroke();
ctx.closePath();
}
};
let animationId: number;
const render = () => {
ctx.fillStyle = backgroundFill || "black";
ctx.globalAlpha = waveOpacity || 0.5;
ctx.fillRect(0, 0, w, h);
drawWave(5);
animationId = requestAnimationFrame(render);
};
useEffect(() => {
init();
return () => {
cancelAnimationFrame(animationId);
};
}, []);
return (
<div
className={cn(
"h-screen flex flex-col items-center justify-center",
containerClassName
)}
>
<canvas
className="absolute inset-0 z-0"
ref={canvasRef}
id="canvas"
></canvas>
<div className={cn("relative z-10", className)} {...props}>
{children}
</div>
</div>
);
};
================================================
FILE: src/data/music_courses.json
================================================
{
"courses": [
{
"id": 1,
"title": "Guitar Fundamentals",
"slug": "guitar-fundamentals",
"description": "Learn the basics of playing guitar with our comprehensive beginner's course.",
"price": 99.99,
"instructor": "John Doe",
"isFeatured": true,
"image": "/courses/guitar.jpg"
},
{
"id": 2,
"title": "Piano for Beginners",
"slug": "piano-for-beginners",
"description": "Start your musical journey with foundational piano skills taught by expert instructors.",
"price": 109.99,
"instructor": "Jane Smith",
"isFeatured": false,
"image": "/courses/piano.jpg"
},
{
"id": 3,
"title": "Advanced Vocal Techniques",
"slug": "advanced-vocal-techniques",
"description": "Enhance your singing with advanced vocal techniques for intermediate to advanced learners.",
"price": 119.99,
"instructor": "Emily Johnson",
"isFeatured": true,
"image": "/courses/vocalist.jpg"
},
{
"id": 4,
"title": "Drumming Mastery",
"slug": "drumming-mastery",
"description": "Master the drums with our comprehensive course covering all skill levels.",
"price": 129.99,
"instructor": "Mike Brown",
"isFeatured": false,
"image": "/courses/drumming.jpg"
},
{
"id": 5,
"title": "Jazz Improvisation",
"slug": "jazz-improvisation",
"description": "Learn the art of jazz improvisation with this course designed for all levels.",
"price": 139.99,
"instructor": "Chris Davis",
"isFeatured": false,
"image": "/courses/jazz.jpg"
},
{
"id": 6,
"title": "Music Production Fundamentals",
"slug": "music-production-fundamentals",
"description": "Dive into music production with this introductory course on the basics of sound engineering and mixing.",
"price": 149.99,
"instructor": "Alex Wilson",
"isFeatured": true,
"image": "/courses/music-prod.jpg"
},
{
"id": 7,
"title": "Songwriting Essentials",
"slug": "songwriting-essentials",
"description": "Learn the essentials of songwriting to express your musical creativity.",
"price": 159.99,
"instructor": "Samantha Miller",
"isFeatured": false,
"image": "/courses/song-writing.jpg"
},
{
"id": 8,
"title": "Electronic Music Production",
"slug": "electronic-music-production",
"description": "Create compelling electronic music with our course designed for beginners to advanced users.",
"price": 169.99,
"instructor": "Luke Harris",
"isFeatured": true,
"image": "/courses/music-prod.jpg"
},
{
"id": 9,
"title": "Classical Music History",
"slug": "classical-music-history",
"description": "Explore the rich history of classical music from its origins to the present day.",
"price": 179.99,
"instructor": "Grace Lee",
"isFeatured": false,
"image": "/courses/classical-music.jpg"
},
{
"id": 10,
"title": "Blues Guitar Techniques",
"slug": "blues-guitar-techniques",
"description": "Discover the techniques of blues guitar to add soul and depth to your playing.",
"price": 189.99,
"instructor": "Ethan Moore",
"isFeatured": true,
"image": "/courses/blues.jpg"
}
]
}
================================================
FILE: src/utils/cn.ts
================================================
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
================================================
FILE: tailwind.config.ts
================================================
import type { Config } from "tailwindcss";
const svgToDataUri = require("mini-svg-data-uri");
const colors = require("tailwindcss/colors");
const {
default: flattenColorPalette,
} = require("tailwindcss/lib/util/flattenColorPalette");
// Plugin to add each Tailwind color as a global CSS variable
function addVariablesForColors({ addBase, theme }: any) {
const allColors = flattenColorPalette(theme('colors'));
const newVars = Object.fromEntries(
Object.entries(allColors).map(([key, value]) => [`--${key}`, value])
);
addBase({
':root': newVars,
});
}
function addSvgPatterns({ matchUtilities, theme }: any) {
matchUtilities(
{
'bg-grid': (value: any) => ({
backgroundImage: `url("${svgToDataUri(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="none" stroke="${value}"><path d="M0 .5H31.5V32"/></svg>`
)}")`,
}),
'bg-grid-small': (value: any) => ({
backgroundImage: `url("${svgToDataUri(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="8" height="8" fill="none" stroke="${value}"><path d="M0 .5H31.5V32"/></svg>`
)}")`,
}),
'bg-dot': (value: any) => ({
backgroundImage: `url("${svgToDataUri(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="16" height="16" fill="none"><circle fill="${value}" id="pattern-circle" cx="10" cy="10" r="1.6257413380501518"></circle></svg>`
)}")`,
}),
},
{ values: flattenColorPalette(theme('backgroundColor')), type: 'color' }
);
}
const config: Config = {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
darkMode: 'class',
theme: {
extend: {
animation:{
spotlight: "spotlight 2s ease .75s 1 forwards",
scroll: "scroll var(--animation-duration, 40s) var(--animation-direction, forwards) linear infinite"
},
backgroundImage: {
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
"gradient-conic":
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
},
keyframes:{
spotlight: {
'0%': { opacity: '0', transform: 'translate(-72%, -62%) scale(0.5)' },
'100%': { opacity: '1', transform: 'translate(-50%,-40%) scale(1)' },
},
scroll: {
to: {
transform: "translate(calc(-50% - 0.5rem))",
},
},
}
},
},
plugins: [addVariablesForColors, addSvgPatterns],
};
export default config;
================================================
FILE: tsconfig.json
================================================
{
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
gitextract_j5k2gb1j/ ├── .eslintrc.json ├── .gitignore ├── README.md ├── next.config.mjs ├── package.json ├── postcss.config.js ├── src/ │ ├── app/ │ │ ├── contact/ │ │ │ └── page.tsx │ │ ├── courses/ │ │ │ └── page.tsx │ │ ├── globals.css │ │ ├── layout.tsx │ │ └── page.tsx │ ├── components/ │ │ ├── FeaturedCourses.tsx │ │ ├── Footer.tsx │ │ ├── HeroSection.tsx │ │ ├── Instructors.tsx │ │ ├── Navbar.tsx │ │ ├── TestimonialCards.tsx │ │ ├── UpcomingWebinars.tsx │ │ ├── WhyChooseUs.tsx │ │ └── ui/ │ │ ├── 3d-card.tsx │ │ ├── Spotlight.tsx │ │ ├── animated-tooltip.tsx │ │ ├── background-beams.tsx │ │ ├── background-gradient.tsx │ │ ├── card-hover-effect.tsx │ │ ├── infinite-moving-cards.tsx │ │ ├── moving-border.tsx │ │ ├── navbar-menu.tsx │ │ ├── sticky-scroll-reveal.tsx │ │ └── wavy-background.tsx │ ├── data/ │ │ └── music_courses.json │ └── utils/ │ └── cn.ts ├── tailwind.config.ts └── tsconfig.json
SYMBOL INDEX (20 symbols across 18 files)
FILE: src/app/contact/page.tsx
function MusicSchoolContactUs (line 6) | function MusicSchoolContactUs() {
FILE: src/app/courses/page.tsx
function page (line 7) | function page() {
FILE: src/app/layout.tsx
function RootLayout (line 13) | function RootLayout({
FILE: src/app/page.tsx
function Home (line 11) | function Home() {
FILE: src/components/FeaturedCourses.tsx
type Course (line 6) | interface Course{
function FeaturedCourses (line 17) | function FeaturedCourses() {
FILE: src/components/Footer.tsx
function Footer (line 3) | function Footer() {
FILE: src/components/HeroSection.tsx
function HeroSection (line 5) | function HeroSection() {
FILE: src/components/Instructors.tsx
function Instructors (line 36) | function Instructors() {
FILE: src/components/Navbar.tsx
function Navbar (line 8) | function Navbar({ className }: { className?: string }) {
FILE: src/components/TestimonialCards.tsx
function MusicSchoolTestimonials (line 37) | function MusicSchoolTestimonials() {
FILE: src/components/UpcomingWebinars.tsx
function UpcomingWebinars (line 5) | function UpcomingWebinars() {
FILE: src/components/WhyChooseUs.tsx
function WhyChooseUs (line 39) | function WhyChooseUs() {
FILE: src/components/ui/Spotlight.tsx
type SpotlightProps (line 4) | type SpotlightProps = {
FILE: src/components/ui/background-beams.tsx
function BackgroundBeamsDemo (line 6) | function BackgroundBeamsDemo() {
FILE: src/components/ui/infinite-moving-cards.tsx
function addAnimation (line 30) | function addAnimation() {
FILE: src/components/ui/moving-border.tsx
function Button (line 13) | function Button({
FILE: src/utils/cn.ts
function cn (line 4) | function cn(...inputs: ClassValue[]) {
FILE: tailwind.config.ts
function addVariablesForColors (line 10) | function addVariablesForColors({ addBase, theme }: any) {
function addSvgPatterns (line 21) | function addSvgPatterns({ matchUtilities, theme }: any) {
Condensed preview — 34 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (77K chars).
[
{
"path": ".eslintrc.json",
"chars": 40,
"preview": "{\n \"extends\": \"next/core-web-vitals\"\n}\n"
},
{
"path": ".gitignore",
"chars": 391,
"preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
},
{
"path": "README.md",
"chars": 197,
"preview": "# A music school project in NextJS\n\n## Description\nSeach \"chai aur code\" on youtube and watch it there\n\n## contributon\nN"
},
{
"path": "next.config.mjs",
"chars": 176,
"preview": "/** @type {import('next').NextConfig} */\nconst nextConfig = {\n images: {\n domains: ['images.unsplash.com', 're"
},
{
"path": "package.json",
"chars": 704,
"preview": "{\n \"name\": \"musicnextjs\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \""
},
{
"path": "postcss.config.js",
"chars": 83,
"preview": "module.exports = {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n },\n};\n"
},
{
"path": "src/app/contact/page.tsx",
"chars": 2418,
"preview": "'use client';\n\nimport React, { FormEvent, useState } from 'react';\nimport { BackgroundBeams } from '@/components/ui/back"
},
{
"path": "src/app/courses/page.tsx",
"chars": 2553,
"preview": "'use client'\nimport Image from \"next/image\";\nimport React from \"react\";\nimport { CardBody, CardContainer, CardItem } fro"
},
{
"path": "src/app/globals.css",
"chars": 606,
"preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n:root {\n --foreground-rgb: 0, 0, 0;\n --background-start-rg"
},
{
"path": "src/app/layout.tsx",
"chars": 660,
"preview": "import type { Metadata } from \"next\";\nimport { Inter } from \"next/font/google\";\nimport \"./globals.css\";\nimport Navbar fr"
},
{
"path": "src/app/page.tsx",
"chars": 710,
"preview": "\nimport FeaturedCourses from \"@/components/FeaturedCourses\";\nimport Footer from \"@/components/Footer\";\nimport HeroSectio"
},
{
"path": "src/components/FeaturedCourses.tsx",
"chars": 2301,
"preview": "'use client'\nimport Link from \"next/link\"\nimport courseData from \"../data/music_courses.json\"\nimport { BackgroundGradien"
},
{
"path": "src/components/Footer.tsx",
"chars": 2623,
"preview": "\n\nfunction Footer() {\n return (\n <footer className=\"bg-black text-gray-400 py-12\">\n <div className=\"max-w-6xl"
},
{
"path": "src/components/HeroSection.tsx",
"chars": 1471,
"preview": "import Link from \"next/link\"\nimport { Spotlight } from \"./ui/Spotlight\"\nimport { Button } from \"./ui/moving-border\";\n\nfu"
},
{
"path": "src/components/Instructors.tsx",
"chars": 2027,
"preview": "'use client'\nimport { WavyBackground } from \"./ui/wavy-background\"\nimport { AnimatedTooltip } from \"./ui/animated-toolti"
},
{
"path": "src/components/Navbar.tsx",
"chars": 1506,
"preview": "'use client';\n\nimport React, { useState } from \"react\";\nimport { HoveredLink, Menu, MenuItem, ProductItem } from \"./ui/n"
},
{
"path": "src/components/TestimonialCards.tsx",
"chars": 2003,
"preview": "'use client'\nimport { InfiniteMovingCards } from \"./ui/infinite-moving-cards\";\n\nconst musicSchoolTestimonials = [\n {\n"
},
{
"path": "src/components/UpcomingWebinars.tsx",
"chars": 2549,
"preview": "'use client'\nimport Link from \"next/link\"\nimport { HoverEffect } from \"./ui/card-hover-effect\";\n\nfunction UpcomingWebina"
},
{
"path": "src/components/WhyChooseUs.tsx",
"chars": 2488,
"preview": "\n\"use client\";\nimport React from \"react\";\nimport { StickyScroll } from \"./ui/sticky-scroll-reveal\";\n\nconst musicSchoolCo"
},
{
"path": "src/components/ui/3d-card.tsx",
"chars": 3924,
"preview": "\"use client\";\n\nimport { cn } from \"@/utils/cn\";\nimport Image from \"next/image\";\nimport React, {\n createContext,\n useSt"
},
{
"path": "src/components/ui/Spotlight.tsx",
"chars": 1449,
"preview": "import React from \"react\";\nimport { cn } from \"@/utils/cn\";\n\ntype SpotlightProps = {\n className?: string;\n fill?: stri"
},
{
"path": "src/components/ui/animated-tooltip.tsx",
"chars": 3089,
"preview": "\"use client\";\nimport Image from \"next/image\";\nimport React, { useState } from \"react\";\nimport {\n motion,\n useTransform"
},
{
"path": "src/components/ui/background-beams.tsx",
"chars": 10637,
"preview": "'use client';\nimport React from 'react';\nimport { motion } from 'framer-motion';\nimport { cn } from '@/utils/cn';\n\nexpor"
},
{
"path": "src/components/ui/background-gradient.tsx",
"chars": 2406,
"preview": "import { cn } from \"@/utils/cn\";\nimport React from \"react\";\nimport { motion } from \"framer-motion\";\n\nexport const Backgr"
},
{
"path": "src/components/ui/card-hover-effect.tsx",
"chars": 2628,
"preview": "import { cn } from \"@/utils/cn\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport Link from \"next/link\";\n"
},
{
"path": "src/components/ui/infinite-moving-cards.tsx",
"chars": 3641,
"preview": "\"use client\";\n\nimport { cn } from \"@/utils/cn\";\nimport React, { useEffect, useState } from \"react\";\n\nexport const Infini"
},
{
"path": "src/components/ui/moving-border.tsx",
"chars": 3089,
"preview": "\"use client\";\nimport React from \"react\";\nimport {\n motion,\n useAnimationFrame,\n useMotionTemplate,\n useMotionValue,\n"
},
{
"path": "src/components/ui/navbar-menu.tsx",
"chars": 2986,
"preview": "\"use client\";\nimport React from \"react\";\nimport { motion } from \"framer-motion\";\nimport Link from \"next/link\";\nimport Im"
},
{
"path": "src/components/ui/sticky-scroll-reveal.tsx",
"chars": 2703,
"preview": "\"use client\";\nimport React, { useRef } from \"react\";\nimport { useMotionValueEvent, useScroll } from \"framer-motion\";\nimp"
},
{
"path": "src/components/ui/wavy-background.tsx",
"chars": 2672,
"preview": "\"use client\";\nimport { cn } from \"@/utils/cn\";\nimport React, { useEffect, useRef } from \"react\";\nimport { createNoise3D "
},
{
"path": "src/data/music_courses.json",
"chars": 3639,
"preview": "{\n \"courses\": [\n {\n \"id\": 1,\n \"title\": \"Guitar Fundamentals\",\n \"slug\": \"guitar-fundamentals"
},
{
"path": "src/utils/cn.ts",
"chars": 164,
"preview": "import { ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassV"
},
{
"path": "tailwind.config.ts",
"chars": 2649,
"preview": "import type { Config } from \"tailwindcss\";\n\nconst svgToDataUri = require(\"mini-svg-data-uri\");\nconst colors = require(\"t"
},
{
"path": "tsconfig.json",
"chars": 578,
"preview": "{\n \"compilerOptions\": {\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"allowJs\": true,\n \"skipLibCheck\": true,\n "
}
]
About this extraction
This page contains the full source code of the hiteshchoudhary/Music-school-hindi GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 34 files (70.1 KB), approximately 20.6k tokens, and a symbol index with 20 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.