--- template/app/src/landing-page/components/Hero/Orbit.tsx +++ opensaas-sh/app/src/landing-page/components/Hero/Orbit.tsx @@ -0,0 +1,217 @@ +import { useEffect, useState } from 'react'; +import logo from '../../../client/static/logo.webp'; +import nodeLogoDark from '../../../client/static/logos/nodejs-dark.webp'; +import nodeLogo from '../../../client/static/logos/nodejs-light.webp'; +import stripeLogoDark from '../../../client/static/logos/stripe-dark.webp'; +import stripeLogo from '../../../client/static/logos/stripe-light.webp'; +import tailwindLogoDark from '../../../client/static/logos/tailwind-dark.webp'; +import tailwindLogo from '../../../client/static/logos/tailwind-light.webp'; +import { cn } from '../../../lib/utils'; +import AstroLogo from '../../logos/AstroLogo'; +import OpenAILogo from '../../logos/OpenAILogo'; +import PrismaLogo from '../../logos/PrismaLogo'; +import ReactLogo from '../../logos/ReactLogo'; +import ShadCNLogo from '../../logos/ShadCNLogo'; + +interface LogoConfig { + id: string; + component: React.ComponentType; + circleIndex: number; + position: number; + size?: number; +} + +const ImageLogo = ({ + src, + alt, + className, + dark, +}: { + src: string; + alt: string; + className?: string; + dark?: boolean; +}) => { + return ( + {alt} + ); +}; + +const logoConfigs: LogoConfig[] = [ + { + id: 'wasp', + component: () => , + circleIndex: 1, + position: 0, + }, + { id: 'openai', component: OpenAILogo, circleIndex: 1, position: 120, size: 24 }, + { id: 'astro', component: AstroLogo, circleIndex: 1, position: 270, size: 24 }, + { id: 'prisma', component: PrismaLogo, circleIndex: 2, position: 90, size: 24 }, + { id: 'shadcn', component: ShadCNLogo, circleIndex: 2, position: 210, size: 24 }, + { + id: 'tailwind-light', + component: () => ( + + ), + circleIndex: 2, + position: 330, + }, + { + id: 'tailwind-dark', + component: () => , + circleIndex: 2, + position: 330, + }, + { + id: 'stripe-light', + component: () => , + circleIndex: 3, + position: 180, + }, + { + id: 'stripe-dark', + component: () => , + circleIndex: 3, + position: 180, + }, + { id: 'react', component: ReactLogo, circleIndex: 3, position: 300, size: 32 }, + { + id: 'node-light', + component: () => , + circleIndex: 3, + position: 50, + }, + { + id: 'node-dark', + component: () => , + circleIndex: 3, + position: 50, + }, +]; + +const circles = [ + { radius: 120, rotationSpeed: 0.5, circleRotationSpeed: 0.2 }, // Innermost circle + { radius: 180, rotationSpeed: 0.3, circleRotationSpeed: 0.15 }, // Second circle + { radius: 240, rotationSpeed: 0.2, circleRotationSpeed: 0.1 }, // Third circle + { radius: 300, rotationSpeed: 0.1, circleRotationSpeed: 0.05 }, // Outermost circle +]; + +const gradients = []; + +export default function Orbit() { + const [rotation, setRotation] = useState(0); + + useEffect(() => { + const animate = () => { + setRotation((prev) => prev + 0.5); + }; + + const interval = setInterval(animate, 50); + return () => clearInterval(interval); + }, []); + + const getLogoPosition = (circleIndex: number, position: number, rotation: number) => { + const circle = circles[circleIndex]; + const totalRotation = rotation * circle.rotationSpeed + position; + const radians = (totalRotation * Math.PI) / 180; + + return { + x: Math.cos(radians) * circle.radius, + y: Math.sin(radians) * circle.radius, + }; + }; + + return ( +
+
+

100%

+

Open Source

+
+ + {circles.map((circle, circleIndex) => { + const gradients = [ + `conic-gradient(from ${rotation * circle.circleRotationSpeed}deg, + hsl(var(--primary) / 0.15), + hsl(var(--primary) / 0), + hsl(var(--primary) / 0), + hsl(var(--primary) / 0.15), + hsl(var(--primary) / 0), + hsl(var(--primary) / 0.05), + hsl(var(--primary) / 0.15) + )`, + `conic-gradient(from ${rotation * circle.circleRotationSpeed + 45}deg, + hsl(var(--primary) / 0.12), + hsl(var(--primary) / 0), + hsl(var(--primary) / 0.08), + hsl(var(--primary) / 0), + hsl(var(--primary) / 0.2), + hsl(var(--primary) / 0), + hsl(var(--primary) / 0.12) + )`, + `conic-gradient(from ${rotation * circle.circleRotationSpeed + 90}deg, + hsl(var(--primary) / 0.1), + hsl(var(--primary) / 0.18), + hsl(var(--primary) / 0.1), + hsl(var(--primary) / 0), + hsl(var(--primary) / 0.15), + hsl(var(--primary) / 0), + hsl(var(--primary) / 0.1) + )`, + `conic-gradient(from ${rotation * circle.circleRotationSpeed + 135}deg, + hsl(var(--primary) / 0.08), + hsl(var(--primary) / 0), + hsl(var(--primary) / 0.16), + hsl(var(--primary) / 0.06), + hsl(var(--primary) / 0), + hsl(var(--primary) / 0.12), + hsl(var(--primary) / 0.08) + )`, + ]; + + return ( +
+ ); + })} + + {logoConfigs.map((logoConfig) => { + const { x, y } = getLogoPosition(logoConfig.circleIndex, logoConfig.position, rotation); + const LogoComponent = logoConfig.component; + const logoSize = logoConfig.size || 32; + + return ( +
+ +
+ ); + })} +
+ ); +}