diff --git a/src/StarDustAdventures_frontend/src/components/landing-mobile/gameplayMechanics/Card/index.css b/src/StarDustAdventures_frontend/src/components/landing-mobile/gameplayMechanics/Card/index.css new file mode 100644 index 0000000..bbaf704 --- /dev/null +++ b/src/StarDustAdventures_frontend/src/components/landing-mobile/gameplayMechanics/Card/index.css @@ -0,0 +1,3 @@ +.mob-gameplay-card{ + @apply w-screen flex flex-col justify-start items-center gap-8 +} \ No newline at end of file diff --git a/src/StarDustAdventures_frontend/src/components/landing-mobile/gameplayMechanics/Card/index.tsx b/src/StarDustAdventures_frontend/src/components/landing-mobile/gameplayMechanics/Card/index.tsx new file mode 100644 index 0000000..e88613b --- /dev/null +++ b/src/StarDustAdventures_frontend/src/components/landing-mobile/gameplayMechanics/Card/index.tsx @@ -0,0 +1,22 @@ +import { CardProps } from "../../../landing/gamePlayMechanics/Cards"; +import './index.css'; + +/** + * A Card component that displays a gameplay mechanic. + * It includes an image, title, and description. + * + * @param {CardProps} props - The card properties. + * @param {string} props.title - The title of the card. + * @param {string} props.description - The description of the gameplay mechanic. + * @param {string} props.image - The image URL representing the gameplay mechanic. + * @returns {JSX.Element} A styled card with an image, title, and description. + */ +export default function Card({ title, description, image }: CardProps): JSX.Element { + return ( +
+ {title} +

{title}

+

{description}

+
+ ); +} diff --git a/src/StarDustAdventures_frontend/src/components/landing-mobile/gameplayMechanics/index.css b/src/StarDustAdventures_frontend/src/components/landing-mobile/gameplayMechanics/index.css new file mode 100644 index 0000000..a8ba482 --- /dev/null +++ b/src/StarDustAdventures_frontend/src/components/landing-mobile/gameplayMechanics/index.css @@ -0,0 +1,12 @@ +.mob-gameplay-container{ + @apply min-h-screen h-auto relative; +} + +.mob-gameplay-header{ + @apply relative h-screen min-h-fit flex flex-col justify-center z-[100]; + scroll-snap-align:center; +} + +.gameplay-mechanics-cards-list{ + @apply mt-4 flex justify-between items-center w-[300vw] +} \ No newline at end of file diff --git a/src/StarDustAdventures_frontend/src/components/landing-mobile/gameplayMechanics/index.tsx b/src/StarDustAdventures_frontend/src/components/landing-mobile/gameplayMechanics/index.tsx new file mode 100644 index 0000000..9edb877 --- /dev/null +++ b/src/StarDustAdventures_frontend/src/components/landing-mobile/gameplayMechanics/index.tsx @@ -0,0 +1,84 @@ +import { useEffect, useRef } from "react"; +import { CARDS } from "../../landing/gamePlayMechanics"; +import Card from "./Card"; +import './index.css'; +import gsap from "gsap"; +import { ScrollTrigger } from 'gsap/ScrollTrigger'; + +gsap.registerPlugin(ScrollTrigger); + +/** + * Renders the header for gameplay mechanics. + * @param {Object} props - Component props + * @param {React.RefObject} props.headerRef - Ref for the header container + */ +const Header = ({ headerRef }: { headerRef: React.RefObject }) => { + return ( +
+

Gameplay Mechanics

+

Explore the engaging system of Star Dust Adventures

+
+ ); +}; + +/** + * Renders a list of gameplay mechanic cards. + * @param {Object} props - Component props + * @param {React.RefObject} props.cardsRef - Ref for the cards container + */ +const CardList = ({ cardsRef }: { cardsRef: React.RefObject }) => { + return ( +
+ {CARDS.map((card, index) => ( + + ))} +
+ ); +}; + +/** + * Renders the Gameplay Mechanics section with GSAP animations and ScrollTrigger. + */ +const GameplayMechanics = () => { + const headerRef = useRef(null); + const containerRef = useRef(null); + const cardsRef = useRef(null); + + useEffect(() => { + if (headerRef.current && containerRef.current && cardsRef.current) { + const tl = gsap.timeline({ + scrollTrigger: { + trigger: containerRef.current, + start: "top top", + end: "bottom bottom", + scrub: true, + pin: true, + anticipatePin: 1, + } + }); + + // Header animation + tl.fromTo(headerRef.current, { x: '100%', height: '100vh' }, { x: 0, height: 0, duration: 1 }); + + // Cards animation + const cards = cardsRef.current.querySelectorAll(".mob-gameplay-card"); + tl.fromTo(cards, + { opacity: 0.8, scale: 0.8 }, + { xPercent: -100 * (cards.length - 1), ease: "none", opacity: 1, scale: 1 } + ); + + return () => { + ScrollTrigger.getAll().forEach(trigger => trigger.kill()); + }; + } + }, []); + + return ( +
+
+ +
+ ); +}; + +export default GameplayMechanics; diff --git a/src/StarDustAdventures_frontend/src/components/landing/GradientCover/index.css b/src/StarDustAdventures_frontend/src/components/landing/GradientCover/index.css index 0ebc7f6..c37c38e 100644 --- a/src/StarDustAdventures_frontend/src/components/landing/GradientCover/index.css +++ b/src/StarDustAdventures_frontend/src/components/landing/GradientCover/index.css @@ -1,5 +1,6 @@ .gradient-cover{ - @apply md:min-h-screen h-auto w-screen relative bg-black flex flex-col justify-between lg:gap-32 + @apply md:min-h-screen h-auto w-screen relative bg-black flex flex-col justify-between lg:gap-32; + scroll-snap-type: y mandatory; } .right-purple-pattern{ diff --git a/src/StarDustAdventures_frontend/src/components/landing/GradientCover/index.tsx b/src/StarDustAdventures_frontend/src/components/landing/GradientCover/index.tsx index defc1e7..d24ebfa 100644 --- a/src/StarDustAdventures_frontend/src/components/landing/GradientCover/index.tsx +++ b/src/StarDustAdventures_frontend/src/components/landing/GradientCover/index.tsx @@ -1,17 +1,25 @@ import React from 'react'; -import './index.css' -export default function Cover({children} : React.PropsWithChildren<{}>){ - return( +import './index.css'; + +/** + * A Cover component that wraps its children with a gradient background and patterned decorations. + * + * @param {React.PropsWithChildren<{}>} props - The props containing children elements. + * @param {React.ReactNode} props.children - The content to be rendered inside the cover. + * @returns {JSX.Element} A styled cover with children content. + */ +export default function Cover({ children }: React.PropsWithChildren<{}>): JSX.Element { + return (
- purple-pattern -
+ purple-pattern +
- blue-pattern -
+ blue-pattern +
{children}
- ) -} \ No newline at end of file + ); +} diff --git a/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/Cards/index.css b/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/Cards/index.css index c725681..6db89d1 100644 --- a/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/Cards/index.css +++ b/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/Cards/index.css @@ -1,6 +1,6 @@ .gameplay-card{ @apply relative flex flex-col lg:px-3 lg:py-4 justify-start items-center - bg-transparent lg:gap-7 text-white lg:h-[50vh] z-[1] md:w-auto w-screen + bg-transparent lg:gap-7 text-white lg:h-[50vh] z-[1] w-auto } .card-title{ diff --git a/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/Cards/index.tsx b/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/Cards/index.tsx index 01dcf71..061865e 100644 --- a/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/Cards/index.tsx +++ b/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/Cards/index.tsx @@ -6,16 +6,19 @@ export type CardProps = { image : string; } -/* - * Card Component - * - Component that renders a card with an image, title, and description - * - Returns a div with an image, title, and description - * - Used in Landing Page -*/ - +/** + * A Card component that displays a gameplay mechanic for desktop view. + * It includes an image, title, and description. + * + * @param {CardProps} props - The card properties. + * @param {string} props.title - The title of the card. + * @param {string} props.description - The description of the gameplay mechanic. + * @param {string} props.image - The image URL representing the gameplay mechanic. + * @returns {JSX.Element} A styled card with an image, title, and description for large screen sizes ( > 768px). + */ const Card = ({title, description,image}:CardProps)=>{ return( -
+
{title}

{title}

{description}

diff --git a/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/index.css b/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/index.css index 0a93721..ef6a55e 100644 --- a/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/index.css +++ b/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/index.css @@ -1,6 +1,5 @@ .gameplay-mechanics { - @apply w-full bg-transparent lg:mt-24 mt-12 text-white flex flex-col items-center justify-center py-3 md:min-h-min min-h-screen md:max-h-screen h-auto relative - + @apply w-full bg-transparent lg:mt-24 mt-12 text-white flex flex-col items-center justify-center py-3 max-h-screen h-auto relative ; } @@ -9,7 +8,7 @@ } .gameplay-mechanics-cards { - @apply flex md:flex-1 flex-row md:justify-between justify-center md:items-center items-center gap-6 relative mt-2 md:w-full w-[300vw] md:h-auto h-screen + @apply flex md:flex-1 flex-row md:justify-between justify-center md:items-center items-center gap-6 relative mt-2 w-full h-auto overflow-x-hidden px-2 ; } diff --git a/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/index.tsx b/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/index.tsx index 18d199e..067e9ed 100644 --- a/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/index.tsx +++ b/src/StarDustAdventures_frontend/src/components/landing/gamePlayMechanics/index.tsx @@ -1,4 +1,4 @@ -import { useRef, useEffect, useState } from 'react'; +import { useRef, useEffect} from 'react'; import GameplayMechanic, { CardProps } from './Cards'; import gsap from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; @@ -8,126 +8,112 @@ import React from 'react'; gsap.registerPlugin(ScrollTrigger); // Card Static Data -const CARDS = [ - { - title: "Core Gameplay Loop", - description: 'Players tap to mine StarDust, with oxygen consumption renewed every 8 hours.', - image: '/assets/images/mars.svg' - }, - { - title: "Progression Opportunities", - description: "Upgrade astronaut's oxygen tank, mining tool, & storage to unlock richer resources.", - image: '/assets/images/moon.svg' - }, - { - title: "Play-to-Earn System", - description: "Accumulate StarDust, converting it to a future token tradable on exchanges for financial rewards.", - image: '/assets/images/earth.svg' - } -] as CardProps[]; +export const CARDS: CardProps[] = [ + { + title: "Core Gameplay Loop", + description: 'Players tap to mine StarDust, with oxygen consumption renewed every 8 hours.', + image: '/assets/images/mars.svg', + }, + { + title: "Progression Opportunities", + description: "Upgrade astronaut's oxygen tank, mining tool, & storage to unlock richer resources.", + image: '/assets/images/moon.svg', + }, + { + title: "Play-to-Earn System", + description: "Accumulate StarDust, converting it to a future token tradable on exchanges for financial rewards.", + image: '/assets/images/earth.svg', + }, +]; -const Header = ({titleRef}:{titleRef : React.RefObject}) => { - return ( -
-

Gameplay Mechanics

-

Explore the engaging system of Star Dust Adventures

-
- ) -} +/** + * Renders the header section for the gameplay mechanics. + * @returns {JSX.Element} The header with a title and caption. + */ +const Header = (): JSX.Element => { + return ( +
+

Gameplay Mechanics

+

Explore the engaging system of Star Dust Adventures

+
+ ); +}; -type GamePlayCardListProps = { - containerRef : React.RefObject, - linesRef : React.RefObject -} +export type GamePlayCardListProps = { + containerRef: React.RefObject; + linesRef: React.MutableRefObject; +}; -const GamePlayCardList = ({ containerRef, linesRef } : GamePlayCardListProps) => { - return ( -
- {CARDS.map((card, index) => ( - - - {(index < CARDS.length - 1) && ( // Validate `linesRef.current` is not null -
el && linesRef.current && (linesRef.current[index] = el)}>
// Assign ref after validating that linesRef.current is not null - )} -
- ))} -
- ) -} +/** + * Renders a list of gameplay cards with connecting lines. + * @param {GamePlayCardListProps} props - Props containing container and lines refs. + * @returns {JSX.Element} A list of cards with animated lines. + */ +const GamePlayCardList = ({ containerRef, linesRef }: GamePlayCardListProps): JSX.Element => { + return ( +
+ {CARDS.map((card, index) => ( + + + {index < CARDS.length - 1 && ( +
el && linesRef.current && (linesRef.current[index] = el)} // Validate `linesRef.current` + >
+ )} +
+ ))} +
+ ); +}; -const GamePlayMechanics = () => { - const containerRef = useRef(null); - const sectionRef = useRef(null); - const linesRef = useRef>([]); - const titleRef = useRef(null); +/** + * Main component for rendering the gameplay mechanics section, handling both desktop and mobile views. + * @returns {JSX.Element} The gameplay mechanics section with animations. + */ +const GamePlayMechanics = (): JSX.Element => { + const containerRef = useRef(null); + const sectionRef = useRef(null); + const linesRef = useRef([]); - const [isMobile,setIsMobile] = useState(window.innerWidth < 768); + // GSAP Animation Hook + useEffect(() => { + if (!containerRef.current || !sectionRef.current) return; + + const cards = containerRef.current.querySelectorAll('.gameplay-card'); + const lines = linesRef.current; - useEffect(()=>{ - window.addEventListener('resize',()=>{ - setIsMobile(window.innerWidth < 768); - }); - return () => { - window.removeEventListener('resize',()=>{}); - } - },[]); + // Set initial animation properties + gsap.set(cards, { opacity: 0, scale: 0.8 }); + gsap.set(lines, { scaleX: 0 }); - useEffect(() => { - if (!containerRef.current || !sectionRef.current || !titleRef.current) return; - const cards = containerRef.current.querySelectorAll('.gameplay-card'); - const lines = linesRef.current; - console.log(cards) + // Timeline for animation + const tl = gsap.timeline({ + scrollTrigger: { + trigger: sectionRef.current, + start: 'top top', + end: 'bottom top', + pin: true, + pinSpacing: true, + scrub: 1, + }, + }); + tl.to(cards, { opacity: 1, scale: 1, stagger: 0.2, duration: 0.5 }) + .to(lines, { scaleX: 1, duration: 0.5, stagger: 0.2 }, '<'); - - - // Screen based Animation - if(!isMobile){ - gsap.set(cards, { opacity: 0, scale: 0.8 }); - gsap.set(lines, { scaleX: 0 }); - const tl = gsap.timeline({ - scrollTrigger: { - trigger: sectionRef.current, - start: 'top top', - end: 'bottom top', - pin: true, - pinSpacing: true, - scrub: 1, - }, - }); - // Desktop Animation - tl.to(cards, { opacity: 1, scale: 1, stagger: 0.2, duration: 0.5 }) - .to(lines, { scaleX: 1, duration: 0.5, stagger: 0.2 }, '<'); - } else{ - // Cards Scroll based Animation + // Cleanup ScrollTriggers on unmount + return () => { + ScrollTrigger.getAll().forEach((trigger) => trigger.kill()); + }; + }, []); - gsap.to(cards,{ - xPercent: - 100 * (cards.length -1), - scale:1.2, - ease : "none", - scrollTrigger:{ - trigger:sectionRef.current, - pin:true, - scrub : 1, - // snap : 1 / (cards.length - 1), - end : () => sectionRef.current ? "+=" + sectionRef.current.offsetWidth / 3 : "+=0", - markers:true - } - }) - - } - return () => { - ScrollTrigger.getAll().forEach((trigger) => trigger.kill()); - }; - }, [isMobile]); - return ( -
-
- -
- ); + return( +
+
+ +
+ ); }; -export default GamePlayMechanics; \ No newline at end of file +export default GamePlayMechanics; diff --git a/src/StarDustAdventures_frontend/src/components/re-usables/Button/Button.tsx b/src/StarDustAdventures_frontend/src/components/re-usables/Button/Button.tsx index b1edf85..28c79a4 100644 --- a/src/StarDustAdventures_frontend/src/components/re-usables/Button/Button.tsx +++ b/src/StarDustAdventures_frontend/src/components/re-usables/Button/Button.tsx @@ -1,66 +1,78 @@ -/* - * Button Component for StarDust Adventures - * This is a re-usable button component for the StarDust Adventures project - * The button component has the following props: - * variant: 'primary' | 'secondary' - * size: 'sm' | 'md' | 'lg' | 'xl' | 'xxl' - * className: string - * The button component is styled using Tailwind CSS - * The button component is exported as default - * clsx is used to combine multiple classes - * @param {ButtonProps} props - * @returns {JSX.Element} - * @author @ArjunQBTech - * @version 1.0 -*/ - import clsx from "clsx"; import './index.css'; interface ButtonProps extends React.ButtonHTMLAttributes { - variant?: 'primary' | 'secondary'; - size?: 'sm' | 'md' | 'lg' | 'xl' | 'xxl'; - className?: string; + variant?: 'primary' | 'secondary'; + size?: 'sm' | 'md' | 'lg' | 'xl' | 'xxl'; + className?: string; } +/** + * Reusable Button Component for StarDust Adventures + * + * This is a reusable button component that can be used across the StarDust Adventures project. + * It accepts various props to control its styling and behavior. + * The button uses Tailwind CSS classes, and `clsx` is used to combine the styles dynamically. + * + * @component + * @param {ButtonProps} props - The props for the Button component + * @param {'primary' | 'secondary'} [props.variant='primary'] - Defines the button variant (color scheme) + * @param {'sm' | 'md' | 'lg' | 'xl' | 'xxl'} [props.size='md'] - Defines the size of the button + * @param {string} [props.className] - Additional class names to apply custom styles + * @param {React.ReactNode} props.children - The content to be rendered inside the button + * @returns {JSX.Element} The rendered button component + * + * @example + * // Example usage of the Button component + * + * + * @example + * + * + * @version 1.0 + * @author @ArjunQBTech + */ +export default function Button({ + children, + variant = 'primary', + size = 'md', + className = '', + ...props +}: ButtonProps): JSX.Element { -export default function Button( - { - children, - variant = 'primary', - size = 'md', - className = '', - ...props - }: ButtonProps) { + const sizes = { + 'sm': 'text-sm min-w-[100px] text-[20px]', + 'md': 'min-w-[185px] text-[30px]', + 'lg': 'text-base px-6 py-2', + 'xl': 'text-lg px-8 py-3', + 'xxl': 'text-xl px-10 py-3' + }; - const sizes = { - 'sm': 'text-sm min-w-[100px] text-[20px]', - 'md': 'min-w-[185px] text-[30px]', - 'lg': 'text-base px-6 py-2', - 'xl' : 'text-lg px-8 py-3', - 'xxl' : 'text-xl px-10 py-3' - } + const vSpacing = { + 'sm': 'my-1', + 'md': 'my-2', + 'lg': 'my-3', + 'xl': 'my-4', + 'xxl': 'my-5' + }; - const vSpacing = { - 'sm': 'my-1', - 'md': 'my-2', - 'lg': 'my-3', - 'xl': 'my-4', - 'xxl': 'my-5' - } - - return ( - - ) -} \ No newline at end of file + return ( + + ); +} diff --git a/src/StarDustAdventures_frontend/src/index.css b/src/StarDustAdventures_frontend/src/index.css index 9d0ba16..ff20f1b 100644 --- a/src/StarDustAdventures_frontend/src/index.css +++ b/src/StarDustAdventures_frontend/src/index.css @@ -22,13 +22,14 @@ html{ scroll-behavior: smooth; + scrollbar-width: none; } body { overflow-x: hidden; min-height: 100vh; font-family: 'SF-Pro-Display', sans-serif; -} + } .app{ @apply min-h-screen bg-red-200 } diff --git a/src/StarDustAdventures_frontend/src/pages/Landing.jsx b/src/StarDustAdventures_frontend/src/pages/Landing.jsx index 299ba66..da61ebc 100644 --- a/src/StarDustAdventures_frontend/src/pages/Landing.jsx +++ b/src/StarDustAdventures_frontend/src/pages/Landing.jsx @@ -1,38 +1,65 @@ -import React, { useEffect, useState } from 'react' -import '../components/landing/landing.css' -import Hero from '../components/landing/hero/Hero' -import Footer from '../components/landing/footer' -import GamePlayMechanics from '../components/landing/gamePlayMechanics' -import GameConcept from '../components/landing/gameConcept/GameConcept' -import Lore from '../components/landing/loreStoryline/Lore' -import GradientCover from '../components/landing/GradientCover' -import GameConceptM from '../components/landing-mobile/gameConcept/GameConceptM' - -const PatternCover = () => { - return( +import React, { lazy, Suspense, useEffect, useState } from 'react'; +import '../components/landing/landing.css'; +import Hero from '../components/landing/hero/Hero'; +import Footer from '../components/landing/footer'; +import GameConcept from '../components/landing/gameConcept/GameConcept'; +import Lore from '../components/landing/loreStoryline/Lore'; +import GradientCover from '../components/landing/GradientCover'; +import GameConceptM from '../components/landing-mobile/gameConcept/GameConceptM'; + +const GamePlayMechanics = lazy(() => import('../components/landing/gamePlayMechanics')); +const MobileGameplayView = lazy(() => import('../components/landing-mobile/gameplayMechanics')); + +/** + * PatternCover component dynamically renders gameplay mechanics based on screen width, + * displaying a mobile or desktop view inside a gradient cover. It also includes the Lore component. + * + * @returns {JSX.Element} The PatternCover component wrapped in a GradientCover with dynamic content. + */ +const PatternCover = ()=> { + const [width, setWidth] = useState(window.innerWidth); + + useEffect(() => { + const handleResize = () => setWidth(window.innerWidth); + window.addEventListener('resize', handleResize); + + return () => window.removeEventListener('resize', handleResize); + }, []); + + return ( - - + Loading...

}> + {width > 768 ? : } + +
- ) -} + ); +}; + +/** + * Landing component renders the main landing page, including the Hero, Game Concept, and Footer sections. + * It dynamically switches between mobile and desktop versions of the GameConcept component based on screen width. + * + * @returns {JSX.Element} The complete landing page layout. + */ +const Landing = ()=>{ + const [width, setWidth] = useState(window.innerWidth); -const Landing = () => { - const [width,setWidth]=useState(window.innerWidth) + useEffect(() => { + const handleResize = () => setWidth(window.innerWidth); + window.addEventListener('resize', handleResize); - useEffect(()=>{ - window.addEventListener("resize", ()=>setWidth(window.innerWidth)); - return () => window.removeEventListener("resize", ()=>setWidth(window.innerWidth)); - },[]) + return () => window.removeEventListener('resize', handleResize); + }, []); return ( -
- - {width>1024?:} - -