Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 20 additions & 34 deletions frontend/src/components/landing/Hero.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
import React from 'react'
import { useTranslation, Trans } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import { motion } from 'framer-motion'
import { Sparkles, ArrowRight } from 'lucide-react'
import { useParticles } from '../../hooks/useParticles'
import { useTypingAnimation } from '../../hooks/useTypingAnimation'
import styles from './Hero.module.css'

const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { staggerChildren: 0.12, delayChildren: 0.2 },
},
} as const

const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0, transition: { duration: 0.5, ease: 'easeOut' as const } },
} as const

const Hero: React.FC = () => {
const { t } = useTranslation()
const navigate = useNavigate()
Expand All @@ -45,29 +31,29 @@ const Hero: React.FC = () => {
</div>

{/* Centered Logo Mark */}
<motion.div
className="w-[72px] h-[72px] rounded-2xl bg-background-surface border border-border-subtle flex items-center justify-center mb-8 shadow-xl relative overflow-hidden"
variants={itemVariants}
<div
className="w-[72px] h-[72px] rounded-2xl bg-background-surface border border-border-subtle flex items-center justify-center mb-8 shadow-xl relative overflow-hidden slide-up"
style={{ animationDelay: '100ms' }}
>
<div className="absolute inset-0 bg-gradient-primary opacity-20 blur-xl" />
<div className="w-[42px] h-[42px] rounded-xl bg-gradient-primary flex items-center justify-center font-bold text-white text-2xl relative z-10 shadow-[0_0_20px_rgba(56,189,248,0.4)]">
a
</div>
</motion.div>
</div>

{/* Status Pill */}
<motion.div
className="inline-flex items-center gap-2 px-4 py-1.5 rounded-full bg-background-surface-alt border border-border-subtle mb-8"
variants={itemVariants}
<div
className="inline-flex items-center gap-2 px-4 py-1.5 rounded-full bg-background-surface-alt border border-border-subtle mb-8 slide-up"
style={{ animationDelay: '200ms' }}
>
<div className="w-1.5 h-1.5 rounded-full bg-accent-green shadow-[0_0_8px_rgba(52,211,153,0.6)] animate-pulse" />
<span className="text-xs font-semibold text-accent-green tracking-wide">{t('landing.hero.badge')}</span>
</motion.div>

{/* Headline */}
<motion.h1
className="text-[48px] sm:text-[56px] font-bold text-text-primary tracking-tight leading-[1.1] mb-6"
variants={itemVariants}
<h1
className="text-[48px] sm:text-[56px] font-bold text-text-primary tracking-tight leading-[1.1] mb-6 slide-up"
style={{ animationDelay: '300ms' }}
>
<Trans
i18nKey="landing.hero.headline"
Expand All @@ -79,35 +65,35 @@ const Hero: React.FC = () => {
</motion.h1>

{/* Subtext */}
<motion.p
className="text-base sm:text-lg text-text-secondary max-w-[540px] mx-auto mb-10 leading-[1.6]"
variants={itemVariants}
<p
className="text-base sm:text-lg text-text-secondary max-w-[540px] mx-auto mb-10 leading-[1.6] slide-up"
style={{ animationDelay: '400ms' }}
>
{t('landing.hero.subtitle')}
</motion.p>

{/* CTAs */}
<motion.div
className="flex flex-col sm:flex-row items-center gap-4 w-full sm:w-auto"
variants={itemVariants}
<div
className="flex flex-col sm:flex-row items-center gap-4 w-full sm:w-auto slide-up"
style={{ animationDelay: '500ms' }}
>
<button
onClick={() => navigate('/tasks/new')}
className="group w-full sm:w-auto flex items-center justify-center gap-2 px-7 py-3.5 rounded-xl bg-gradient-primary text-white font-semibold shadow-[0_0_20px_rgba(139,92,246,0.3)] hover:shadow-[0_0_35px_rgba(139,92,246,0.5)] hover:scale-[1.02] active:scale-[0.98] transition-all"
className="group w-full sm:w-auto flex items-center justify-center gap-2 px-7 py-3.5 rounded-xl bg-gradient-primary text-white font-semibold shadow-[0_0_20px_rgba(139,92,246,0.3)] hover:shadow-[0_0_35px_rgba(139,92,246,0.5)] transition-all hover-scale focus-ring"
>
<Sparkles size={18} className="group-hover:rotate-12 transition-transform" />
<span>{t('landing.hero.startTask')}</span>
</button>

<button
onClick={() => navigate('/agents')}
className="group w-full sm:w-auto flex items-center justify-center gap-2 px-7 py-3.5 rounded-xl bg-background-surface-alt border border-border-subtle text-text-secondary font-medium hover:text-text-primary hover:bg-background-surface hover:border-border-subtle/50 active:scale-[0.98] transition-all"
className="group w-full sm:w-auto flex items-center justify-center gap-2 px-7 py-3.5 rounded-xl bg-background-surface-alt border border-border-subtle text-text-secondary font-medium hover:text-text-primary hover:bg-background-surface hover:border-border-subtle/50 transition-all hover-scale focus-ring"
>
<span>{t('landing.hero.browseAgents')}</span>
<ArrowRight size={18} className="group-hover:translate-x-0.5 transition-transform" />
</button>
</motion.div>
</motion.section>
</div>
</section>
)
}

Expand Down
70 changes: 70 additions & 0 deletions frontend/src/styles/animations.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
.fade-in {
animation: fadeIn 0.3s ease forwards;
}

.slide-up {
animation: slideUp 0.3s ease forwards;
}

.scale-in {
animation: scaleIn 0.3s ease forwards;
}

.pulse {
animation: pulse 2s infinite ease-in-out;
}

@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}

@keyframes pulse {
0% {
opacity: 1;
}
50% {
opacity: 0.6;
}
100% {
opacity: 1;
}
}

@media (prefers-reduced-motion: reduce) {
.fade-in,
.slide-up,
.scale-in,
.pulse {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
animation-delay: 0.01ms !important;
}
}
3 changes: 3 additions & 0 deletions frontend/src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
@tailwind components;
@tailwind utilities;

@import './animations.css';
@import './micro-interactions.css';

:root {
--font-sans: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
--bg-primary: #0A0E14;
Expand Down
62 changes: 62 additions & 0 deletions frontend/src/styles/micro-interactions.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
.hover-lift {
transition-property: transform, box-shadow;
transition-duration: 300ms;
transition-timing-function: ease;
}

.hover-lift:hover {
transform: translateY(-4px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
}

.hover-glow {
transition-property: box-shadow;
transition-duration: 300ms;
transition-timing-function: ease;
}

.hover-glow:hover {
box-shadow: 0 0 15px var(--accent-cyan);
}

.hover-scale {
transition-property: transform;
transition-duration: 300ms;
transition-timing-function: ease;
}

.hover-scale:hover {
transform: scale(1.05);
}

.focus-ring {
outline: none;
}

.focus-ring:focus-visible {
outline: 2px solid var(--accent-cyan);
outline-offset: 2px;
}

.transition-fast {
transition-duration: 150ms;
}

.transition-normal {
transition-duration: 300ms;
}

.transition-slow {
transition-duration: 500ms;
}

@media (prefers-reduced-motion: reduce) {
.hover-lift,
.hover-glow,
.hover-scale,
.transition-fast,
.transition-normal,
.transition-slow {
transition-duration: 0.01ms !important;
}
}
Loading