* feat: setup openapi libs for landing * feat: seperate landing layouts * feat: movee landing providers * feat: add auth layout * feat: implement cookie management for access and refresh tokens * feat: replace Inter font with Bai Jamjuree in layout and add font utility * feat: add signin * feat: add Poppins font to the font utility * feat: expand theme colors in index.css for improved styling options * feat: update dependencies and enhance button and form components with new variants and context * feat: move old components to __old__ dir * feat: add react query support * feat: hide the footer * fix: header style * feat: replace Image component with LogoSimple in Header and update Logo component to accept props * fix: update label for tutorial stat in hero-stats.json * feat: implement EventsPage component with event listing and details * feat: add signup button and page * feat: add HERO_CONTENT data and integrate into Hero component * fix: update navigations import to uppercase and add missing Testimoni entry * feat: implement testimonials display and add submission page * fix: correct link path for testimonial submission * feat: add communites component and integrate social links from JSON data * fix: adjust grid gap in Communities component for better layout * fix: update font imports in layout components for consistency * fix: replace text logo with LogoSimple component in Footer and restore Footer in Layout * feat: add TestimonialSection component and update testimonials data * fix: update section ID from 'komunitas' to 'community' for consistency * feat: add CTASection component with interactive elements and background pattern * fix: update join URL in hero content for consistency * fix: update text in CTASection for improved emphasis and consistency * feat: add CommunitySection component and integrate it into the main page * feat: update Footer component to use dynamic navigation and social links * feat: implement HeroSection component with dynamic content and animations * refactor: replace hardcoded testimonials with dynamic data from JSON * feat: add signup page * feat: integrate Turnstile captcha verification in signup process * feat: implement verification page * feat: add signin link to the signup page * feat: add "Forgot Password?" link to the signin form * refactor: clean up unused ThemeProvider code and CSS variables * feat: add base styles for borders and background to improve UI consistency * feat: implement forgot password functionality with validation and UI components * fix: update password validation rules for clarity and consistency * feat: enable rich colors for Toaster component in layout * feat: implement reset password functionality with validation and UI components * feat: implement Turnstile captcha verification for forgot password and signup actions * refactor: remove console log and enhance error handling in signin and resend OTP actions * feat: add navigation entries for Roadmap and Artikel sections * feat: create initial Page component for articles section * feat: update footer component with additional social media links and icons * feat: remove all unused components in landing * chore: add @radix-ui/react-label deps * feat: wrap VerificationTabs in Suspense * feat: update .env.example to include TURNSTILE_SECRET_KEY and correct NEXT_PUBLIC_TURNSTILE_SITEKEY
87 lines
2.2 KiB
TypeScript
87 lines
2.2 KiB
TypeScript
'use client';
|
|
|
|
import { motion } from 'framer-motion';
|
|
import { useEffect, useMemo, useState } from 'react';
|
|
import {
|
|
SiCplusplus,
|
|
SiCss3,
|
|
SiGo,
|
|
SiHtml5,
|
|
SiJavascript,
|
|
SiPhp,
|
|
SiPython,
|
|
SiRuby,
|
|
SiRust,
|
|
SiSwift,
|
|
SiTypescript,
|
|
} from 'react-icons/si';
|
|
|
|
export function AnimatedBackground() {
|
|
const [isClient, setIsClient] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setIsClient(true);
|
|
}, []);
|
|
|
|
const iconColorMap = useMemo(
|
|
() => [
|
|
{ Icon: SiJavascript, color: '#F7DF1E' },
|
|
{ Icon: SiTypescript, color: '#3178C6' },
|
|
{ Icon: SiPython, color: '#3776AB' },
|
|
{ Icon: SiCplusplus, color: '#00599C' },
|
|
{ Icon: SiRuby, color: '#CC342D' },
|
|
{ Icon: SiSwift, color: '#F05138' },
|
|
{ Icon: SiRust, color: '#000000' },
|
|
{ Icon: SiGo, color: '#00ADD8' },
|
|
{ Icon: SiPhp, color: '#777BB4' },
|
|
{ Icon: SiHtml5, color: '#E34F26' },
|
|
{ Icon: SiCss3, color: '#1572B6' },
|
|
],
|
|
[]
|
|
);
|
|
|
|
const getRandom = (min: number, max: number) =>
|
|
Math.random() * (max - min) + min;
|
|
|
|
const floatingIcons = useMemo(() => {
|
|
if (!isClient) return [];
|
|
|
|
return Array.from({ length: 40 }).map((_, i) => {
|
|
const { Icon, color } = iconColorMap[i % iconColorMap.length];
|
|
return (
|
|
<motion.div
|
|
key={i}
|
|
className="pointer-events-none absolute"
|
|
style={{
|
|
top: `${getRandom(0, 100)}%`,
|
|
left: `${getRandom(0, 100)}%`,
|
|
fontSize: `${getRandom(16, 32)}px`,
|
|
color: color,
|
|
opacity: getRandom(0.1, 0.2),
|
|
rotate: getRandom(-180, 180),
|
|
}}
|
|
animate={{
|
|
y: [0, getRandom(-100, 100), 0],
|
|
x: [0, getRandom(-50, 50), 0],
|
|
rotate: getRandom(-180, 180),
|
|
}}
|
|
transition={{
|
|
duration: getRandom(15, 25),
|
|
repeat: Infinity,
|
|
repeatType: 'loop',
|
|
ease: 'easeInOut',
|
|
}}
|
|
>
|
|
<Icon className="h-full w-full" />
|
|
</motion.div>
|
|
);
|
|
});
|
|
}, [isClient, iconColorMap]);
|
|
|
|
if (!isClient) return null;
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-0 overflow-hidden">{floatingIcons}</div>
|
|
);
|
|
}
|