Spaces:
Running
Running
| import React from 'react'; | |
| import { motion } from 'framer-motion'; | |
| import { useTranslation } from 'react-i18next'; | |
| const HeroSection = () => { | |
| const { t } = useTranslation(); | |
| return ( | |
| <section className="w-full flex flex-col items-center text-center gap-10 px-margin_edge max-w-screen-2xl mx-auto py-12 md:py-24"> | |
| <div className="max-w-4xl flex flex-col gap-6"> | |
| <motion.h1 | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ duration: 0.6 }} | |
| className="text-5xl md:text-8xl font-display-lg text-primary leading-tight" | |
| > | |
| {t('landing.hero_title_p1', 'Plans break.')} <br /> | |
| <span className="highlighter-bg px-4">{t('landing.hero_title_p2', 'TaskFlow adapts.')}</span> | |
| </motion.h1> | |
| <motion.p | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ duration: 0.6, delay: 0.2 }} | |
| className="text-2xl md:text-3xl text-on-surface-variant max-w-3xl mx-auto leading-relaxed" | |
| > | |
| {t('landing.hero_desc', "The first visual goal constructor designed for focus. Move from linear lists to adaptive graphs that handle life's \"If/Then\" moments.")} | |
| </motion.p> | |
| <motion.div | |
| initial={{ opacity: 0, y: 20 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ duration: 0.6, delay: 0.4 }} | |
| className="mt-6 font-accent-note text-3xl text-secondary flex items-center justify-center gap-3" | |
| > | |
| <span className="material-symbols-outlined text-4xl" style={{ fontVariationSettings: '"FILL" 1' }}>psychology</span> | |
| {t('landing.hero_badge', 'ADHD-friendly. Resilience-driven.')} | |
| </motion.div> | |
| </div> | |
| {/* Hero Visual: Mockup */} | |
| <motion.div | |
| initial={{ opacity: 0, scale: 0.95 }} | |
| whileInView={{ opacity: 1, scale: 1 }} | |
| viewport={{ once: true }} | |
| transition={{ duration: 1, ease: "easeOut" }} | |
| className="w-full max-w-5xl mt-12 relative min-h-[500px] flex items-center justify-center border-2 border-dashed border-primary/30 rounded-2xl bg-white rough-shadow p-12 overflow-visible" | |
| > | |
| {/* SVG Connections */} | |
| <svg className="absolute inset-0 w-full h-full pointer-events-none overflow-visible" style={{ zIndex: 0 }}> | |
| <defs> | |
| <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="0" refY="3.5" orient="auto"> | |
| <polygon points="0 0, 10 3.5, 0 7" fill="#181919" /> | |
| </marker> | |
| </defs> | |
| <motion.path | |
| initial={{ pathLength: 0 }} | |
| whileInView={{ pathLength: 1 }} | |
| viewport={{ once: true }} | |
| transition={{ duration: 1.5, ease: "easeInOut" }} | |
| d="M 180 250 Q 260 220 340 250" | |
| fill="none" stroke="#181919" strokeWidth="4" strokeLinecap="round" strokeDasharray="8 6" | |
| /> | |
| <motion.path | |
| initial={{ pathLength: 0 }} | |
| whileInView={{ pathLength: 1 }} | |
| viewport={{ once: true }} | |
| transition={{ duration: 1.2, delay: 0.5 }} | |
| d="M 460 250 Q 530 250 580 250" | |
| fill="none" stroke="#181919" strokeWidth="4" strokeLinecap="round" | |
| /> | |
| <motion.path | |
| initial={{ pathLength: 0 }} | |
| whileInView={{ pathLength: 1 }} | |
| viewport={{ once: true }} | |
| transition={{ duration: 1.2, delay: 1.5 }} | |
| d="M 720 250 Q 780 160 850 160" | |
| fill="none" stroke="#45a84a" strokeWidth="4" strokeLinecap="round" | |
| /> | |
| <motion.path | |
| initial={{ pathLength: 0 }} | |
| whileInView={{ pathLength: 1 }} | |
| viewport={{ once: true }} | |
| transition={{ duration: 1.2, delay: 1.7 }} | |
| d="M 720 250 Q 780 340 850 340" | |
| fill="none" stroke="#ba1a1a" strokeWidth="4" strokeLinecap="round" | |
| /> | |
| </svg> | |
| {/* Nodes */} | |
| {[ | |
| { label: t('landing.node_a', 'Task A'), pos: 'left-12 top-[210px]', rot: -2, delay: 0.2 }, | |
| { label: t('landing.node_b', 'Task B'), pos: 'left-[340px] top-[210px]', rot: 1, delay: 0.4 }, | |
| { label: t('landing.node_failed', 'Failed?'), pos: 'left-[580px] top-[180px]', rot: 45, diamond: true, delay: 0.6 }, | |
| { label: t('landing.node_c', 'Task C'), pos: 'right-12 top-[120px]', rot: 2, delay: 0.8, color: '#45a84a' }, | |
| { label: t('landing.node_d', 'Task D'), pos: 'right-12 top-[300px]', rot: -1, delay: 1.0, color: '#ba1a1a' } | |
| ].map((node, i) => ( | |
| <motion.div | |
| key={i} | |
| initial={{ opacity: 0, scale: 0 }} | |
| whileInView={{ opacity: 1, scale: 1 }} | |
| animate={{ | |
| y: [0, i % 2 === 0 ? -8 : 8, 0], | |
| rotate: node.diamond ? [45, 47, 43, 45] : [node.rot, node.rot + 1, node.rot - 1, node.rot] | |
| }} | |
| transition={{ | |
| initial: { delay: node.delay, type: "spring", stiffness: 200 }, | |
| animate: { repeat: Infinity, duration: 5 + i, ease: "easeInOut" } | |
| }} | |
| viewport={{ once: true }} | |
| className={`absolute ${node.pos} z-10 flex items-center justify-center p-2 group overflow-visible`} | |
| > | |
| {node.diamond ? ( | |
| <div className="w-36 h-36 flex items-center justify-center relative"> | |
| <div className="absolute inset-0 border-4 border-primary bg-white shadow-[8px_8px_0px_0px_rgba(0,0,0,0.15)] rotate-45 transform transition-transform group-hover:scale-105" /> | |
| <span className="relative font-display-lg text-2xl text-primary font-bold">{node.label}</span> | |
| </div> | |
| ) : ( | |
| <div | |
| style={{ borderColor: node.color || 'var(--color-primary)' }} | |
| className={`bg-white p-6 border-4 rounded-xl shadow-[8px_8px_0px_0px_rgba(0,0,0,0.1)] w-40 text-center transform transition-transform group-hover:scale-105 group-hover:-rotate-2`} | |
| > | |
| <span className="text-2xl font-bold">{node.label}</span> | |
| </div> | |
| )} | |
| </motion.div> | |
| ))} | |
| </motion.div> | |
| </section> | |
| ); | |
| }; | |
| export default HeroSection; | |