first commit

This commit is contained in:
2026-03-06 10:32:28 +00:00
commit c969c1c968
90 changed files with 16823 additions and 0 deletions

119
src/sections/About.tsx Normal file
View File

@@ -0,0 +1,119 @@
import { useEffect, useRef } from 'react';
import { Brain, Wifi, Eye } from 'lucide-react';
const features = [
{
icon: Brain,
title: 'Inteligente',
description: 'Tecnologia de ponta integrada em um design ergonômico e leve. Processamento avançado para análise em tempo real.',
color: 'orange',
},
{
icon: Wifi,
title: 'Conectado',
description: 'Sincronização perfeita com seu smartphone para análise completa dos seus treinos e progresso.',
color: 'teal',
},
{
icon: Eye,
title: 'Em Tempo Real',
description: 'Visualize suas métricas sem tirar os olhos do caminho. Display HUD de alta definição sempre visível.',
color: 'cyan',
},
];
export function About() {
const sectionRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const elements = entry.target.querySelectorAll('.reveal-card');
elements.forEach((el, index) => {
setTimeout(() => {
el.classList.add('animate-fade-in-up');
}, index * 100);
});
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.2 }
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => observer.disconnect();
}, []);
const getColorClasses = (color: string) => {
const colors: Record<string, { bg: string; text: string; border: string }> = {
orange: { bg: 'bg-orange-500/10', text: 'text-orange-400', border: 'border-orange-500/30' },
teal: { bg: 'bg-teal-500/10', text: 'text-teal-400', border: 'border-teal-500/30' },
cyan: { bg: 'bg-cyan-500/10', text: 'text-cyan-400', border: 'border-cyan-500/30' },
};
return colors[color] || colors.orange;
};
return (
<section id="sobre" ref={sectionRef} className="py-24 lg:py-32 bg-[#0f172a]">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Section Header */}
<div className="text-center mb-16">
<h2 className="font-display font-bold text-3xl sm:text-4xl lg:text-5xl text-white mb-4">
Sobre o Produto
</h2>
<div className="w-16 h-1 bg-gradient-to-r from-orange-500 to-orange-400 mx-auto rounded-full" />
</div>
{/* Features Grid */}
<div className="grid md:grid-cols-3 gap-6 lg:gap-8">
{features.map((feature, index) => {
const colors = getColorClasses(feature.color);
const Icon = feature.icon;
return (
<div
key={index}
className="reveal-card opacity-0 group relative bg-slate-800/50 border border-slate-700 rounded-2xl p-8 hover:border-slate-500 transition-all duration-300 hover:-translate-y-2 hover:shadow-xl hover:shadow-slate-900/50"
>
{/* Icon */}
<div
className={`w-14 h-14 rounded-xl ${colors.bg} border ${colors.border} flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-300`}
>
<Icon className={`w-7 h-7 ${colors.text}`} />
</div>
{/* Content */}
<h3 className="font-display font-semibold text-xl text-white mb-3">
{feature.title}
</h3>
<p className="text-slate-400 leading-relaxed">
{feature.description}
</p>
{/* Hover Glow */}
<div
className={`absolute inset-0 rounded-2xl ${colors.bg} opacity-0 group-hover:opacity-100 transition-opacity duration-300 -z-10 blur-xl`}
/>
</div>
);
})}
</div>
{/* Description Box */}
<div className="mt-16 reveal-card opacity-0">
<div className="bg-gradient-to-r from-slate-800/80 to-slate-800/40 border border-slate-700 rounded-2xl p-8 lg:p-10">
<p className="text-slate-300 text-center text-lg leading-relaxed max-w-4xl mx-auto">
O <span className="text-orange-400 font-semibold">VisionRun Pro</span> é um óculos inteligente desenvolvido para auxiliar corredores durante seus treinos. Ele permite visualizar informações importantes em tempo real, sem a necessidade de olhar para o celular.
</p>
</div>
</div>
</div>
</section>
);
}

155
src/sections/Colors.tsx Normal file
View File

@@ -0,0 +1,155 @@
import { useState, useEffect, useRef } from 'react';
import { Droplets, Feather, Sparkles } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
const colorOptions = [
{ name: 'Midnight Blue', color: '#1e3a5f', bg: 'bg-[#1e3a5f]' },
{ name: 'Rose Pink', color: '#e891a8', bg: 'bg-[#e891a8]' },
{ name: 'Classic Grey', color: '#6b7280', bg: 'bg-[#6b7280]' },
{ name: 'Pure White', color: '#f8fafc', bg: 'bg-[#f8fafc]' },
{ name: 'Carbon Black', color: '#1f2937', bg: 'bg-[#1f2937]' },
{ name: 'Nordic Blue', color: '#0ea5e9', bg: 'bg-[#0ea5e9]' },
];
const designFeatures = [
{
icon: Droplets,
title: 'Resistente à Água',
description: 'Protegido contra suor e chuva leve durante suas corridas.',
},
{
icon: Feather,
title: 'Leve e Confortável',
description: 'Apenas 45g para conforto máximo durante longas corridas.',
},
{
icon: Sparkles,
title: 'Acabamento Premium',
description: 'Materiais de alta qualidade com design moderno e sofisticado.',
},
];
export function Colors() {
const [selectedColor, setSelectedColor] = useState(0);
const sectionRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const elements = entry.target.querySelectorAll('.reveal-colors');
elements.forEach((el, index) => {
setTimeout(() => {
el.classList.add('animate-fade-in-up');
}, index * 100);
});
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.15 }
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => observer.disconnect();
}, []);
return (
<section ref={sectionRef} className="py-24 lg:py-32 bg-slate-900/50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Section Header */}
<div className="text-center mb-16 reveal-colors opacity-0">
<Badge className="mb-4 bg-slate-800 text-pink-400 border-pink-500/30 hover:bg-slate-700 px-4 py-1.5 text-xs font-semibold tracking-wider uppercase">
Design Premium
</Badge>
<h2 className="font-display font-bold text-3xl sm:text-4xl lg:text-5xl text-white mb-4">
Design & Cores Personalizáveis
</h2>
<div className="w-16 h-1 bg-gradient-to-r from-orange-500 to-orange-400 mx-auto rounded-full mb-6" />
<p className="text-slate-400 text-lg max-w-2xl mx-auto">
Design ergonômico e personalizável com acabamentos premium que combinam estilo e funcionalidade.
</p>
</div>
{/* Design Features */}
<div className="grid md:grid-cols-3 gap-6 mb-16">
{designFeatures.map((feature, index) => {
const Icon = feature.icon;
return (
<div
key={index}
className="reveal-colors opacity-0 group bg-slate-800/50 border border-slate-700 rounded-2xl p-6 hover:border-slate-500 transition-all duration-300"
>
<div className="w-12 h-12 rounded-xl bg-slate-700/50 border border-slate-600 flex items-center justify-center mb-4 group-hover:bg-slate-700 transition-colors">
<Icon className="w-6 h-6 text-white" />
</div>
<h3 className="font-display font-semibold text-lg text-white mb-2">
{feature.title}
</h3>
<p className="text-slate-400 text-sm leading-relaxed">
{feature.description}
</p>
</div>
);
})}
</div>
{/* Color Selector */}
<div className="reveal-colors opacity-0">
<h3 className="font-display font-semibold text-xl text-white text-center mb-8">
Escolha Sua Cor
</h3>
<div className="flex flex-wrap justify-center gap-4 lg:gap-6">
{colorOptions.map((color, index) => (
<button
key={index}
onClick={() => setSelectedColor(index)}
className={`group relative transition-all duration-300 ${
selectedColor === index ? 'scale-110' : 'hover:scale-105'
}`}
>
<div
className={`w-16 h-16 lg:w-20 lg:h-20 rounded-2xl ${color.bg} shadow-lg transition-all duration-300 ${
selectedColor === index
? 'ring-4 ring-orange-500 ring-offset-4 ring-offset-[#0f172a]'
: 'ring-2 ring-slate-700 group-hover:ring-slate-500'
}`}
/>
<span
className={`absolute -bottom-8 left-1/2 -translate-x-1/2 text-xs font-medium whitespace-nowrap transition-colors duration-300 ${
selectedColor === index ? 'text-orange-400' : 'text-slate-400'
}`}
>
{color.name}
</span>
</button>
))}
</div>
{/* Selected Color Preview */}
<div className="mt-16 text-center">
<div
className="inline-flex items-center gap-3 px-6 py-3 rounded-full bg-slate-800 border border-slate-700"
>
<div
className={`w-6 h-6 rounded-full ${colorOptions[selectedColor].bg} ring-2 ring-slate-600`}
/>
<span className="text-white font-medium">
{colorOptions[selectedColor].name}
</span>
<span className="text-slate-400 text-sm">
- Selecionado
</span>
</div>
</div>
</div>
</div>
</section>
);
}

169
src/sections/Comfort.tsx Normal file
View File

@@ -0,0 +1,169 @@
import { useEffect, useRef } from 'react';
import { Weight, Users, Wind, Hand } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
const comfortFeatures = [
{
icon: Weight,
title: '35g',
subtitle: 'Ultra-Leve',
description: 'Peso mínimo para máximo conforto durante longas distâncias',
bullets: [
'Design otimizado',
'Sem pontos de pressão',
'Distribuição equilibrada',
],
color: 'orange',
},
{
icon: Users,
title: '100%',
subtitle: 'Ergonômico',
description: 'Ajuste perfeito para todos os tipos de rosto e cabeça',
bullets: [
'Hastes ajustáveis',
'Ponte nasal flexível',
'Fit personalizado',
],
color: 'teal',
},
{
icon: Wind,
title: 'Active',
subtitle: 'Ventilação',
description: 'Sistema de ventilação ativa para prevenir embaçamento',
bullets: [
'Fluxo de ar otimizado',
'Anti-fog coating',
'Respirável',
],
color: 'cyan',
},
{
icon: Hand,
title: 'Pro',
subtitle: 'Grip Seguro',
description: 'Tecnologia antiderrapante para estabilidade total',
bullets: [
'Borracha hidrogrip',
'Não escorrega',
'Testado em chuva',
],
color: 'orange',
},
];
export function Comfort() {
const sectionRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const elements = entry.target.querySelectorAll('.reveal-comfort');
elements.forEach((el, index) => {
setTimeout(() => {
el.classList.add('animate-fade-in-up');
}, index * 100);
});
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.15 }
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => observer.disconnect();
}, []);
const getColorClasses = (color: string) => {
const colors: Record<string, { bg: string; text: string; bullet: string }> = {
orange: { bg: 'bg-orange-500/10', text: 'text-orange-400', bullet: 'bg-orange-500' },
teal: { bg: 'bg-teal-500/10', text: 'text-teal-400', bullet: 'bg-teal-500' },
cyan: { bg: 'bg-cyan-500/10', text: 'text-cyan-400', bullet: 'bg-cyan-500' },
};
return colors[color] || colors.orange;
};
return (
<section id="design" ref={sectionRef} className="py-24 lg:py-32 bg-[#0f172a]">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Section Header */}
<div className="text-center mb-16 reveal-comfort opacity-0">
<Badge className="mb-4 bg-slate-800 text-orange-400 border-orange-500/30 hover:bg-slate-700 px-4 py-1.5 text-xs font-semibold tracking-wider uppercase">
Conforto Premium
</Badge>
<h2 className="font-display font-bold text-3xl sm:text-4xl lg:text-5xl text-white mb-4">
Conforto & Ergonomia
</h2>
<div className="w-16 h-1 bg-gradient-to-r from-orange-500 to-orange-400 mx-auto rounded-full mb-6" />
<p className="text-slate-400 text-lg max-w-2xl mx-auto">
Design pensado para proporcionar conforto excepcional durante toda a sua corrida.
</p>
</div>
{/* Comfort Cards Grid */}
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-6">
{comfortFeatures.map((feature, index) => {
const colors = getColorClasses(feature.color);
const Icon = feature.icon;
return (
<div
key={index}
className="reveal-comfort opacity-0 group relative bg-slate-800/50 border border-slate-700 rounded-2xl p-6 hover:border-slate-500 transition-all duration-300 hover:-translate-y-2"
>
{/* Icon */}
<div
className={`w-12 h-12 rounded-xl ${colors.bg} flex items-center justify-center mb-4 group-hover:scale-110 transition-transform duration-300`}
>
<Icon className={`w-6 h-6 ${colors.text}`} />
</div>
{/* Title */}
<div className="mb-3">
<span className={`font-display font-bold text-2xl ${colors.text}`}>
{feature.title}
</span>
<h3 className="font-display font-semibold text-white">
{feature.subtitle}
</h3>
</div>
{/* Description */}
<p className="text-slate-400 text-sm mb-4 leading-relaxed">
{feature.description}
</p>
{/* Bullets */}
<ul className="space-y-2">
{feature.bullets.map((bullet, bulletIndex) => (
<li key={bulletIndex} className="flex items-center gap-2 text-sm text-slate-300">
<span className={`w-1.5 h-1.5 rounded-full ${colors.bullet} flex-shrink-0`} />
{bullet}
</li>
))}
</ul>
</div>
);
})}
</div>
{/* Availability Badge */}
<div className="mt-16 text-center reveal-comfort opacity-0">
<Badge className="bg-teal-500/10 text-teal-400 border-teal-500/30 hover:bg-teal-500/20 px-6 py-2 text-sm font-semibold">
<svg className="w-4 h-4 mr-2 inline" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
Disponível Agora
</Badge>
</div>
</div>
</section>
);
}

121
src/sections/Features.tsx Normal file
View File

@@ -0,0 +1,121 @@
import { useEffect, useRef } from 'react';
import { Gauge, Route, Smartphone, Map, TrendingUp } from 'lucide-react';
const features = [
{
icon: Gauge,
title: 'Cálculo da velocidade em tempo real',
description: 'Acompanhe sua velocidade instantânea durante toda a corrida',
},
{
icon: Route,
title: 'Cálculo da distância percorrida',
description: 'Saiba exatamente quantos quilômetros você já completou',
},
{
icon: Smartphone,
title: 'Monitoramento pelo celular',
description: 'Sincronização automática com o aplicativo móvel',
},
{
icon: Map,
title: 'Exibição do circuito percorrido',
description: 'Visualize todo o trajeto no aplicativo após o treino',
},
{
icon: TrendingUp,
title: 'Acompanhamento de desempenho',
description: 'Análise completa do seu progresso durante a corrida',
},
];
export function Features() {
const sectionRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const elements = entry.target.querySelectorAll('.reveal-feature');
elements.forEach((el, index) => {
setTimeout(() => {
el.classList.add('animate-fade-in-up');
}, index * 100);
});
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.15 }
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => observer.disconnect();
}, []);
return (
<section id="funcionalidades" ref={sectionRef} className="py-24 lg:py-32 bg-slate-900/50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Section Header */}
<div className="text-center mb-16 reveal-feature opacity-0">
<h2 className="font-display font-bold text-3xl sm:text-4xl lg:text-5xl text-white mb-4">
Funcionalidades Atuais
</h2>
<div className="w-16 h-1 bg-gradient-to-r from-orange-500 to-orange-400 mx-auto rounded-full mb-6" />
</div>
{/* Features Grid */}
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
{features.map((feature, index) => {
const Icon = feature.icon;
return (
<div
key={index}
className="reveal-feature opacity-0 group relative bg-slate-800/50 border border-slate-700 rounded-2xl p-6 hover:border-slate-500 transition-all duration-300 hover:-translate-y-1"
>
{/* Icon */}
<div className="w-12 h-12 rounded-xl bg-slate-700/50 border border-slate-600 flex items-center justify-center mb-4 group-hover:bg-slate-700 transition-colors">
<Icon className="w-6 h-6 text-white" />
</div>
{/* Content */}
<h3 className="font-display font-semibold text-lg text-white mb-2">
{feature.title}
</h3>
<p className="text-slate-400 text-sm leading-relaxed">
{feature.description}
</p>
</div>
);
})}
</div>
{/* Operational Notice */}
<div className="mt-12 reveal-feature opacity-0">
<div className="bg-gradient-to-r from-teal-500/10 to-teal-500/5 border border-teal-500/20 rounded-2xl p-6">
<div className="flex items-start gap-4">
<div className="w-10 h-10 rounded-lg bg-teal-500/20 flex items-center justify-center flex-shrink-0">
<svg className="w-5 h-5 text-teal-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div>
<h4 className="font-display font-semibold text-white mb-1">
Funcionalidades Completamente Operacionais
</h4>
<p className="text-slate-400 text-sm leading-relaxed">
Todas as funcionalidades listadas acima estão implementadas e funcionando perfeitamente no VisionRun Pro. O sistema foi testado extensivamente para garantir precisão e confiabilidade durante suas corridas.
</p>
</div>
</div>
</div>
</div>
</div>
</section>
);
}

168
src/sections/Footer.tsx Normal file
View File

@@ -0,0 +1,168 @@
import { Glasses, Mail, Phone, MapPin, Instagram, Twitter, Youtube, Linkedin } from 'lucide-react';
import { Button } from '@/components/ui/button';
const quickLinks = [
{ label: 'Sobre', href: '#sobre' },
{ label: 'Tecnologia', href: '#tecnologia' },
{ label: 'Design', href: '#design' },
{ label: 'Funcionalidades', href: '#funcionalidades' },
{ label: 'Especificações', href: '#especificacoes' },
];
const contactInfo = [
{ icon: Mail, label: 'contato@visionrun.com' },
{ icon: Phone, label: '+55 (11) 4000-1234' },
{ icon: MapPin, label: 'São Paulo, SP - Brasil' },
];
const socialLinks = [
{ icon: Instagram, href: '#', label: 'Instagram' },
{ icon: Twitter, href: '#', label: 'Twitter' },
{ icon: Youtube, href: '#', label: 'YouTube' },
{ icon: Linkedin, href: '#', label: 'LinkedIn' },
];
export function Footer() {
const scrollToSection = (href: string) => {
if (href === '#') return;
const element = document.querySelector(href);
if (element) {
element.scrollIntoView({ behavior: 'smooth' });
}
};
return (
<footer id="contato" className="bg-[#0a0f1c] border-t border-slate-800">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* CTA Section */}
<div className="py-16 text-center border-b border-slate-800">
<h2 className="font-display font-bold text-3xl sm:text-4xl text-white mb-4">
Pronto para Revolucionar suas Corridas?
</h2>
<p className="text-slate-400 text-lg max-w-2xl mx-auto mb-8">
Adquira o VisionRun Pro hoje e experimente o futuro da tecnologia wearable para corrida.
</p>
<Button
size="lg"
className="bg-orange-500 hover:bg-orange-400 text-white font-semibold px-8 py-6 text-base transition-all duration-300 hover:shadow-xl hover:shadow-orange-500/30"
>
<svg className="w-5 h-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
</svg>
Fale Conosco
</Button>
</div>
{/* Main Footer Content */}
<div className="py-12 grid sm:grid-cols-2 lg:grid-cols-4 gap-8 lg:gap-12">
{/* Brand */}
<div className="sm:col-span-2 lg:col-span-1">
<a href="#" className="flex items-center gap-2 mb-4">
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-orange-500 to-orange-600 flex items-center justify-center">
<Glasses className="w-5 h-5 text-white" />
</div>
<div className="flex flex-col">
<span className="font-display font-bold text-lg text-white leading-tight">
VisionRun
</span>
<span className="text-[10px] text-slate-400 leading-tight">
Smart Running Glasses
</span>
</div>
</a>
<p className="text-slate-400 text-sm leading-relaxed mb-6">
Tecnologia de ponta para corredores que buscam performance e inovação.
</p>
{/* Social Links */}
<div className="flex gap-3">
{socialLinks.map((social, index) => {
const Icon = social.icon;
return (
<a
key={index}
href={social.href}
aria-label={social.label}
className="w-10 h-10 rounded-lg bg-slate-800 border border-slate-700 flex items-center justify-center text-slate-400 hover:text-white hover:border-orange-500 hover:bg-orange-500/10 transition-all duration-300"
>
<Icon className="w-5 h-5" />
</a>
);
})}
</div>
</div>
{/* Quick Links */}
<div>
<h3 className="font-display font-semibold text-white mb-4">Links Rápidos</h3>
<ul className="space-y-3">
{quickLinks.map((link, index) => (
<li key={index}>
<button
onClick={() => scrollToSection(link.href)}
className="text-slate-400 hover:text-white text-sm transition-colors duration-200"
>
{link.label}
</button>
</li>
))}
</ul>
</div>
{/* Contact */}
<div>
<h3 className="font-display font-semibold text-white mb-4">Contato</h3>
<ul className="space-y-3">
{contactInfo.map((item, index) => {
const Icon = item.icon;
return (
<li key={index} className="flex items-center gap-3">
<Icon className="w-4 h-4 text-orange-400 flex-shrink-0" />
<span className="text-slate-400 text-sm">{item.label}</span>
</li>
);
})}
</ul>
</div>
{/* Newsletter */}
<div>
<h3 className="font-display font-semibold text-white mb-4">Newsletter</h3>
<p className="text-slate-400 text-sm mb-4">
Receba novidades e atualizações sobre o VisionRun Pro.
</p>
<div className="flex gap-2">
<input
type="email"
placeholder="Seu e-mail"
className="flex-1 bg-slate-800 border border-slate-700 rounded-lg px-4 py-2 text-white text-sm placeholder:text-slate-500 focus:outline-none focus:border-orange-500 transition-colors"
/>
<Button
size="sm"
className="bg-orange-500 hover:bg-orange-400 text-white px-4"
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14 5l7 7m0 0l-7 7m7-7H3" />
</svg>
</Button>
</div>
</div>
</div>
{/* Bottom Bar */}
<div className="py-6 border-t border-slate-800 flex flex-col sm:flex-row justify-between items-center gap-4">
<p className="text-slate-500 text-sm">
© 2026 VisionRun Pro. Todos os direitos reservados.
</p>
<div className="flex gap-6">
<a href="#" className="text-slate-500 hover:text-slate-300 text-sm transition-colors">
Política de Privacidade
</a>
<a href="#" className="text-slate-500 hover:text-slate-300 text-sm transition-colors">
Termos de Uso
</a>
</div>
</div>
</div>
</footer>
);
}

View File

@@ -0,0 +1,158 @@
import { useEffect, useRef } from 'react';
import { Headphones, Moon, Activity, Volume2, Music, Bell } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
const upcomingFeatures = [
{
icon: Headphones,
title: 'Áudio Integrado',
subtitle: 'Tecnologia de condução óssea para máxima segurança',
features: [
{ icon: Volume2, title: 'Notificações por Voz', desc: 'Receba métricas importantes em áudio sem olhar para nada' },
{ icon: Music, title: 'Reprodução de Música', desc: 'Ouça suas playlists favoritas durante a corrida' },
{ icon: Bell, title: 'Alertas Inteligentes', desc: 'Notificações de frequência cardíaca e zona de treino' },
],
},
];
const roadmapItems = [
{
icon: Moon,
title: 'Display Noturno',
description: 'Modo de visualização otimizado para corridas noturnas com ajuste automático de brilho e contraste adaptativo.',
quarter: 'Q3 2026',
color: 'pink',
},
{
icon: Activity,
title: 'Integração com Sensores',
description: 'Conexão com monitores de frequência cardíaca, pods de corrida e outros dispositivos ANT+ para métricas completas.',
quarter: 'Q4 2026',
color: 'teal',
},
];
export function FutureUpdates() {
const sectionRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const elements = entry.target.querySelectorAll('.reveal-future');
elements.forEach((el, index) => {
setTimeout(() => {
el.classList.add('animate-fade-in-up');
}, index * 100);
});
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.15 }
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => observer.disconnect();
}, []);
return (
<section ref={sectionRef} className="py-24 lg:py-32 bg-slate-900/50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Section Header */}
<div className="text-center mb-16 reveal-future opacity-0">
<Badge className="mb-4 bg-slate-800 text-pink-400 border-pink-500/30 hover:bg-slate-700 px-4 py-1.5 text-xs font-semibold tracking-wider uppercase">
<svg className="w-3 h-3 mr-1 inline" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
Em Breve
</Badge>
<h2 className="font-display font-bold text-3xl sm:text-4xl lg:text-5xl text-white mb-4">
Futuras Atualizações
</h2>
<div className="w-16 h-1 bg-gradient-to-r from-orange-500 to-orange-400 mx-auto rounded-full mb-6" />
<p className="text-slate-400 text-lg max-w-2xl mx-auto">
O VisionRun Pro está em constante evolução. Confira as próximas funcionalidades que estão sendo desenvolvidas.
</p>
</div>
{/* Audio Feature Card */}
<div className="mb-12 reveal-future opacity-0">
<div className="bg-gradient-to-br from-slate-800/80 to-slate-800/40 border border-slate-700 rounded-2xl p-6 lg:p-8">
<div className="flex items-center gap-4 mb-6">
<div className="w-12 h-12 rounded-xl bg-slate-700/50 border border-slate-600 flex items-center justify-center">
<Headphones className="w-6 h-6 text-white" />
</div>
<div>
<h3 className="font-display font-semibold text-xl text-white">
Áudio Integrado
</h3>
<p className="text-slate-400 text-sm">
Tecnologia de condução óssea para máxima segurança
</p>
</div>
</div>
<div className="grid sm:grid-cols-3 gap-4">
{upcomingFeatures[0].features.map((feature, index) => {
const Icon = feature.icon;
return (
<div
key={index}
className="bg-slate-800/50 border border-slate-700 rounded-xl p-4 hover:border-slate-500 transition-colors"
>
<Icon className="w-5 h-5 text-slate-400 mb-2" />
<h4 className="font-semibold text-white text-sm mb-1">
{feature.title}
</h4>
<p className="text-slate-400 text-xs leading-relaxed">
{feature.desc}
</p>
</div>
);
})}
</div>
</div>
</div>
{/* Roadmap Grid */}
<div className="grid md:grid-cols-2 gap-6">
{roadmapItems.map((item, index) => {
const Icon = item.icon;
const colorClasses =
item.color === 'pink'
? 'bg-pink-500/10 text-pink-400 border-pink-500/30'
: 'bg-teal-500/10 text-teal-400 border-teal-500/30';
return (
<div
key={index}
className="reveal-future opacity-0 bg-slate-800/50 border border-slate-700 rounded-2xl p-6 hover:border-slate-500 transition-all duration-300"
>
<div className="flex items-start justify-between mb-4">
<div className="w-10 h-10 rounded-lg bg-slate-700/50 flex items-center justify-center">
<Icon className="w-5 h-5 text-white" />
</div>
<Badge className={`${colorClasses} text-xs font-semibold`}>
{item.quarter}
</Badge>
</div>
<h3 className="font-display font-semibold text-lg text-white mb-2">
{item.title}
</h3>
<p className="text-slate-400 text-sm leading-relaxed">
{item.description}
</p>
</div>
);
})}
</div>
</div>
</section>
);
}

186
src/sections/Hero.tsx Normal file
View File

@@ -0,0 +1,186 @@
import { useEffect, useRef } from 'react';
import { Check, ChevronRight, Play } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
const features = [
'GPS Integrado de Alta Precisão',
'Display HUD em Tempo Real',
'Processador ESP32 Dual-Core',
];
export function Hero() {
const heroRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-fade-in-up');
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1, rootMargin: '0px 0px -50px 0px' }
);
const elements = heroRef.current?.querySelectorAll('.reveal');
elements?.forEach((el) => observer.observe(el));
return () => observer.disconnect();
}, []);
const scrollToSection = (href: string) => {
const element = document.querySelector(href);
if (element) {
element.scrollIntoView({ behavior: 'smooth' });
}
};
return (
<section
ref={heroRef}
className="relative min-h-screen flex items-center overflow-hidden bg-gradient-hero"
>
{/* Background Elements */}
<div className="absolute inset-0 overflow-hidden">
{/* Grid Pattern */}
<div
className="absolute inset-0 opacity-[0.03]"
style={{
backgroundImage: `linear-gradient(rgba(255,255,255,0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.1) 1px, transparent 1px)`,
backgroundSize: '60px 60px',
}}
/>
{/* Glow Circles */}
<div className="absolute top-1/4 -left-32 w-96 h-96 bg-teal-500/20 rounded-full blur-[120px] animate-pulse-glow" />
<div className="absolute bottom-1/4 -right-32 w-96 h-96 bg-orange-500/20 rounded-full blur-[120px] animate-pulse-glow" style={{ animationDelay: '1s' }} />
</div>
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20 lg:py-0">
<div className="grid lg:grid-cols-2 gap-12 lg:gap-8 items-center">
{/* Product Image - Left Side */}
<div className="relative order-2 lg:order-1 reveal opacity-0">
<div className="relative aspect-square max-w-lg mx-auto lg:mx-0">
{/* Glow Effect */}
<div className="absolute inset-0 bg-gradient-to-br from-orange-500/30 to-teal-500/30 rounded-full blur-3xl" />
{/* Product Container */}
<div className="relative animate-float">
<img
src="/product-hero.png"
alt="VisionRun Pro - Óculos Inteligentes"
className="w-full h-full object-contain drop-shadow-2xl"
onError={(e) => {
// Fallback if image doesn't exist
const target = e.target as HTMLImageElement;
target.style.display = 'none';
const parent = target.parentElement;
if (parent) {
const fallback = document.createElement('div');
fallback.className = 'w-full h-full flex items-center justify-center';
fallback.innerHTML = `
<div class="relative">
<div class="w-64 h-32 bg-gradient-to-r from-slate-700 to-slate-800 rounded-3xl transform -rotate-6 shadow-2xl flex items-center justify-center border border-slate-600">
<div class="w-56 h-20 bg-gradient-to-br from-slate-800 to-slate-900 rounded-2xl flex items-center justify-center">
<span class="text-2xl font-display font-bold text-white">VisionRun</span>
</div>
</div>
<div class="absolute -top-4 left-1/2 -translate-x-1/2 w-4 h-4 bg-orange-500 rounded-full glow-orange"></div>
</div>
`;
parent.appendChild(fallback);
}
}}
/>
</div>
{/* Floating Stats */}
<div className="absolute -bottom-4 -right-4 lg:right-0 bg-slate-800/90 backdrop-blur-sm border border-slate-700 rounded-xl p-4 shadow-xl">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-lg bg-orange-500/20 flex items-center justify-center">
<span className="text-orange-400 font-bold text-sm">35g</span>
</div>
<div>
<p className="text-white font-semibold text-sm">Ultra-Leve</p>
<p className="text-slate-400 text-xs">Design ergonômico</p>
</div>
</div>
</div>
<div className="absolute -top-4 -left-4 lg:left-0 bg-slate-800/90 backdrop-blur-sm border border-slate-700 rounded-xl p-4 shadow-xl">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-lg bg-teal-500/20 flex items-center justify-center">
<span className="text-teal-400 font-bold text-sm">8h</span>
</div>
<div>
<p className="text-white font-semibold text-sm">Bateria</p>
<p className="text-slate-400 text-xs">Uso contínuo</p>
</div>
</div>
</div>
</div>
</div>
{/* Content - Right Side */}
<div className="order-1 lg:order-2 text-center lg:text-left">
<div className="reveal opacity-0" style={{ animationDelay: '100ms' }}>
<Badge className="mb-6 bg-slate-800 text-teal-400 border-teal-500/30 hover:bg-slate-700 px-4 py-1.5 text-xs font-semibold tracking-wider uppercase">
Tecnologia de Ponta
</Badge>
</div>
<h1 className="reveal opacity-0 font-display font-bold text-5xl sm:text-6xl lg:text-7xl text-white leading-[1.1] mb-6" style={{ animationDelay: '200ms' }}>
VisionRun
<span className="text-gradient"> Pro</span>
</h1>
<p className="reveal opacity-0 text-xl sm:text-2xl text-slate-300 font-medium mb-4" style={{ animationDelay: '300ms' }}>
Óculos de Corrida de Alta Performance
</p>
<p className="reveal opacity-0 text-slate-400 text-base sm:text-lg max-w-xl mx-auto lg:mx-0 mb-8" style={{ animationDelay: '400ms' }}>
Tecnologia e desempenho ao alcance da sua visão. Experimente o futuro da corrida com dados em tempo real sem tirar os olhos do caminho.
</p>
<div className="reveal opacity-0 flex flex-col sm:flex-row gap-4 justify-center lg:justify-start mb-8" style={{ animationDelay: '500ms' }}>
<Button
size="lg"
onClick={() => scrollToSection('#contato')}
className="bg-orange-500 hover:bg-orange-400 text-white font-semibold px-8 py-6 text-base transition-all duration-300 hover:shadow-xl hover:shadow-orange-500/30 hover:-translate-y-0.5"
>
Comprar Agora
<ChevronRight className="w-5 h-5 ml-2" />
</Button>
<Button
size="lg"
variant="outline"
onClick={() => scrollToSection('#sobre')}
className="border-slate-600 text-slate-300 hover:border-orange-500 hover:text-white bg-transparent px-8 py-6 text-base transition-all duration-300"
>
<Play className="w-5 h-5 mr-2" />
Saiba Mais
</Button>
</div>
<div className="reveal opacity-0 flex flex-col sm:flex-row gap-4 justify-center lg:justify-start" style={{ animationDelay: '600ms' }}>
{features.map((feature, index) => (
<div key={index} className="flex items-center gap-2 text-slate-400 text-sm">
<div className="w-5 h-5 rounded-full bg-teal-500/20 flex items-center justify-center flex-shrink-0">
<Check className="w-3 h-3 text-teal-400" />
</div>
<span>{feature}</span>
</div>
))}
</div>
</div>
</div>
</div>
{/* Bottom Gradient Fade */}
<div className="absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-[#0f172a] to-transparent" />
</section>
);
}

View File

@@ -0,0 +1,183 @@
import { useEffect, useRef } from 'react';
import { Map as MapIcon, BarChart3, Database } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
const integrationFeatures = [
{
icon: MapIcon,
title: 'Visualização do Trajeto',
description: 'O trajeto completo é exibido no aplicativo do smartphone com mapa interativo e detalhes de elevação.',
},
{
icon: BarChart3,
title: 'Acompanhamento do Percurso',
description: 'Após finalizar a corrida, você pode acompanhar o percurso completo com análise detalhada de cada trecho.',
},
{
icon: Database,
title: 'Dados Registrados',
description: 'Todos os dados ficam registrados no aplicativo para análise de desempenho e acompanhamento de evolução.',
},
];
export function Integration() {
const sectionRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const elements = entry.target.querySelectorAll('.reveal-integration');
elements.forEach((el, index) => {
setTimeout(() => {
el.classList.add('animate-fade-in-up');
}, index * 150);
});
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.15 }
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => observer.disconnect();
}, []);
return (
<section ref={sectionRef} className="py-24 lg:py-32 bg-[#0f172a] overflow-hidden">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Section Header */}
<div className="text-center mb-16 reveal-integration opacity-0">
<Badge className="mb-4 bg-slate-800 text-cyan-400 border-cyan-500/30 hover:bg-slate-700 px-4 py-1.5 text-xs font-semibold tracking-wider uppercase">
Conectividade
</Badge>
<h2 className="font-display font-bold text-3xl sm:text-4xl lg:text-5xl text-white mb-4">
Integração com Smartphone
</h2>
<div className="w-16 h-1 bg-gradient-to-r from-orange-500 to-orange-400 mx-auto rounded-full mb-6" />
</div>
<div className="grid lg:grid-cols-2 gap-12 lg:gap-16 items-center">
{/* App Mockup - Left Side */}
<div className="reveal-integration opacity-0 relative order-2 lg:order-1">
<div className="relative max-w-sm mx-auto">
{/* Phone Frame */}
<div className="relative bg-slate-800 rounded-[2.5rem] p-3 shadow-2xl shadow-slate-900/50 border border-slate-700">
{/* Screen */}
<div className="bg-slate-900 rounded-[2rem] overflow-hidden aspect-[9/19]">
{/* App Header */}
<div className="bg-slate-800 px-4 py-3 flex items-center justify-between">
<span className="text-white font-semibold text-sm">9:41</span>
<div className="flex gap-1">
<div className="w-4 h-4 rounded-full bg-slate-600" />
<div className="w-4 h-4 rounded-full bg-slate-600" />
</div>
</div>
{/* App Content */}
<div className="p-4">
{/* Run Title */}
<div className="mb-4">
<h4 className="text-white font-semibold text-lg">Corrida Matinal</h4>
<p className="text-slate-400 text-xs">11 de Fevereiro, 2026</p>
</div>
{/* Map Placeholder */}
<div className="bg-slate-800 rounded-xl aspect-square mb-4 relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-br from-slate-700 to-slate-800">
{/* Map Grid */}
<div
className="absolute inset-0 opacity-20"
style={{
backgroundImage: `linear-gradient(rgba(255,255,255,0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.1) 1px, transparent 1px)`,
backgroundSize: '20px 20px',
}}
/>
{/* Route Line */}
<svg className="absolute inset-0 w-full h-full" viewBox="0 0 100 100" preserveAspectRatio="none">
<path
d="M20,80 Q30,60 40,65 T60,50 T80,30"
fill="none"
stroke="#f97316"
strokeWidth="2"
strokeLinecap="round"
/>
{/* Start Point */}
<circle cx="20" cy="80" r="3" fill="#0d9488" />
{/* End Point */}
<circle cx="80" cy="30" r="3" fill="#f97316" />
</svg>
{/* Location Pin */}
<div className="absolute top-1/3 right-1/4">
<div className="w-6 h-6 bg-orange-500 rounded-full flex items-center justify-center shadow-lg">
<MapIcon className="w-3 h-3 text-white" />
</div>
</div>
</div>
</div>
{/* Stats */}
<div className="grid grid-cols-3 gap-3">
<div className="text-center">
<p className="text-orange-400 font-bold text-xl">5.2</p>
<p className="text-slate-400 text-xs">km</p>
</div>
<div className="text-center">
<p className="text-orange-400 font-bold text-xl">28:14</p>
<p className="text-slate-400 text-xs">tempo</p>
</div>
<div className="text-center">
<p className="text-orange-400 font-bold text-xl">5:25</p>
<p className="text-slate-400 text-xs">pace</p>
</div>
</div>
</div>
</div>
{/* Notch */}
<div className="absolute top-6 left-1/2 -translate-x-1/2 w-24 h-6 bg-slate-800 rounded-full" />
</div>
{/* Floating Badge */}
<div className="absolute -top-4 -right-4 bg-orange-500 text-white text-xs font-bold px-3 py-1.5 rounded-full shadow-lg">
APP
</div>
</div>
</div>
{/* Features List - Right Side */}
<div className="order-1 lg:order-2 space-y-6">
{integrationFeatures.map((feature, index) => {
const Icon = feature.icon;
return (
<div
key={index}
className="reveal-integration opacity-0 group flex gap-4 p-4 rounded-xl hover:bg-slate-800/50 transition-colors duration-300"
>
<div className="w-12 h-12 rounded-xl bg-slate-700/50 border border-slate-600 flex items-center justify-center flex-shrink-0 group-hover:bg-slate-700 transition-colors">
<Icon className="w-6 h-6 text-white" />
</div>
<div>
<h3 className="font-display font-semibold text-lg text-white mb-1">
{feature.title}
</h3>
<p className="text-slate-400 text-sm leading-relaxed">
{feature.description}
</p>
</div>
</div>
);
})}
</div>
</div>
</div>
</section>
);
}

131
src/sections/Navigation.tsx Normal file
View File

@@ -0,0 +1,131 @@
import { useState, useEffect } from 'react';
import { Menu, X, Glasses } from 'lucide-react';
import { Button } from '@/components/ui/button';
const navLinks = [
{ label: 'Sobre', href: '#sobre' },
{ label: 'Tecnologia', href: '#tecnologia' },
{ label: 'Design', href: '#design' },
{ label: 'Funcionalidades', href: '#funcionalidades' },
{ label: 'Especificações', href: '#especificacoes' },
{ label: 'Contato', href: '#contato' },
];
export function Navigation() {
const [isScrolled, setIsScrolled] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 50);
};
window.addEventListener('scroll', handleScroll, { passive: true });
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const scrollToSection = (href: string) => {
const element = document.querySelector(href);
if (element) {
element.scrollIntoView({ behavior: 'smooth' });
}
setIsMobileMenuOpen(false);
};
return (
<header
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
isScrolled
? 'glass border-b border-slate-700/50'
: 'bg-transparent'
}`}
>
<nav className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16 lg:h-20">
{/* Logo */}
<a
href="#"
className="flex items-center gap-2 group"
onClick={(e) => {
e.preventDefault();
window.scrollTo({ top: 0, behavior: 'smooth' });
}}
>
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-orange-500 to-orange-600 flex items-center justify-center group-hover:shadow-lg group-hover:shadow-orange-500/30 transition-all duration-300">
<Glasses className="w-5 h-5 text-white" />
</div>
<div className="flex flex-col">
<span className="font-display font-bold text-lg text-white leading-tight">
VisionRun
</span>
<span className="text-[10px] text-slate-400 leading-tight">
Smart Running Glasses
</span>
</div>
</a>
{/* Desktop Navigation */}
<div className="hidden lg:flex items-center gap-1">
{navLinks.map((link) => (
<button
key={link.href}
onClick={() => scrollToSection(link.href)}
className="px-4 py-2 text-sm font-medium text-slate-300 hover:text-white transition-colors duration-200 relative group"
>
{link.label}
<span className="absolute bottom-0 left-1/2 -translate-x-1/2 w-0 h-0.5 bg-orange-500 group-hover:w-1/2 transition-all duration-300" />
</button>
))}
</div>
{/* CTA Button */}
<div className="hidden lg:block">
<Button
onClick={() => scrollToSection('#contato')}
className="bg-orange-500 hover:bg-orange-400 text-white font-semibold px-6 transition-all duration-300 hover:shadow-lg hover:shadow-orange-500/30"
>
Comprar Agora
</Button>
</div>
{/* Mobile Menu Button */}
<button
className="lg:hidden p-2 text-slate-300 hover:text-white transition-colors"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
>
{isMobileMenuOpen ? (
<X className="w-6 h-6" />
) : (
<Menu className="w-6 h-6" />
)}
</button>
</div>
{/* Mobile Menu */}
<div
className={`lg:hidden overflow-hidden transition-all duration-300 ${
isMobileMenuOpen ? 'max-h-96 pb-4' : 'max-h-0'
}`}
>
<div className="flex flex-col gap-1 pt-2 border-t border-slate-700/50">
{navLinks.map((link) => (
<button
key={link.href}
onClick={() => scrollToSection(link.href)}
className="px-4 py-3 text-left text-sm font-medium text-slate-300 hover:text-white hover:bg-slate-800/50 rounded-lg transition-all duration-200"
>
{link.label}
</button>
))}
<Button
onClick={() => scrollToSection('#contato')}
className="mt-2 bg-orange-500 hover:bg-orange-400 text-white font-semibold"
>
Comprar Agora
</Button>
</div>
</div>
</nav>
</header>
);
}

196
src/sections/Specs.tsx Normal file
View File

@@ -0,0 +1,196 @@
import { useEffect, useRef } from 'react';
import { Cpu, Battery, Wifi } from 'lucide-react';
const specCategories = [
{
icon: Cpu,
title: 'Processador',
specs: [
{ label: 'Microcontrolador', value: 'ESP32 Dual-Core' },
{ label: 'Frequência', value: '240 MHz' },
{ label: 'Memória RAM', value: '520 KB SRAM' },
{ label: 'Flash', value: '4 MB' },
],
},
{
icon: Battery,
title: 'Energia',
specs: [
{ label: 'Bateria', value: 'Li-Po 500mAh' },
{ label: 'Autonomia', value: '8 horas' },
{ label: 'Carregamento', value: 'USB-C (2h)' },
{ label: 'Standby', value: '72 horas' },
],
},
{
icon: Wifi,
title: 'Conectividade',
specs: [
{ label: 'Bluetooth', value: '4.2 BLE' },
{ label: 'Wi-Fi', value: '802.11 b/g/n' },
{ label: 'GPS', value: 'Multi-GNSS' },
{ label: 'ANT+', value: 'Compatível' },
],
},
];
const dimensions = [
{ label: 'Peso', value: '35 gramas' },
{ label: 'Largura', value: '145 mm' },
{ label: 'Altura', value: '48 mm' },
{ label: 'Profundidade', value: '40 mm' },
];
const resistance = [
{ label: 'À água', value: 'IPX4' },
{ label: 'À poeira', value: 'IP5X' },
{ label: 'Temperatura', value: '-10°C a 45°C' },
{ label: 'Umidade', value: '10% a 90%' },
];
const display = [
{ label: 'Tipo', value: 'Projeção HUD' },
{ label: 'Brilho', value: 'Auto-ajustável' },
{ label: 'Visualização', value: 'Sempre visível' },
{ label: 'Cores', value: 'Monocromático' },
];
export function Specs() {
const sectionRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const elements = entry.target.querySelectorAll('.reveal-specs');
elements.forEach((el, index) => {
setTimeout(() => {
el.classList.add('animate-fade-in-up');
}, index * 100);
});
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.15 }
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => observer.disconnect();
}, []);
return (
<section id="especificacoes" ref={sectionRef} className="py-24 lg:py-32 bg-[#0f172a]">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Section Header */}
<div className="text-center mb-16 reveal-specs opacity-0">
<h2 className="font-display font-bold text-3xl sm:text-4xl lg:text-5xl text-white mb-4">
Especificações Técnicas
</h2>
<div className="w-16 h-1 bg-gradient-to-r from-orange-500 to-orange-400 mx-auto rounded-full mb-6" />
<p className="text-slate-400 text-lg max-w-2xl mx-auto">
Conheça todos os detalhes técnicos do VisionRun Pro e descubra a tecnologia por trás da inovação.
</p>
</div>
{/* Main Specs Grid */}
<div className="grid md:grid-cols-3 gap-6 mb-8">
{specCategories.map((category, index) => {
const Icon = category.icon;
return (
<div
key={index}
className="reveal-specs opacity-0 bg-slate-800/50 border border-slate-700 rounded-2xl p-6"
>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-10 rounded-lg bg-slate-700/50 flex items-center justify-center">
<Icon className="w-5 h-5 text-white" />
</div>
<h3 className="font-display font-semibold text-lg text-white">
{category.title}
</h3>
</div>
<div className="space-y-3">
{category.specs.map((spec, specIndex) => (
<div
key={specIndex}
className="flex justify-between items-center py-2 border-b border-slate-700/50 last:border-0"
>
<span className="text-slate-400 text-sm">{spec.label}</span>
<span className="text-white font-medium text-sm font-mono">
{spec.value}
</span>
</div>
))}
</div>
</div>
);
})}
</div>
{/* Secondary Specs */}
<div className="grid md:grid-cols-3 gap-6 reveal-specs opacity-0">
{/* Dimensions */}
<div className="bg-slate-800/30 border border-slate-700/50 rounded-2xl p-6">
<div className="flex items-center gap-2 mb-4">
<svg className="w-5 h-5 text-orange-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" />
</svg>
<h4 className="font-display font-semibold text-white">Dimensões</h4>
</div>
<div className="space-y-2">
{dimensions.map((item, index) => (
<div key={index} className="flex justify-between text-sm">
<span className="text-slate-400">{item.label}</span>
<span className="text-white font-mono">{item.value}</span>
</div>
))}
</div>
</div>
{/* Resistance */}
<div className="bg-slate-800/30 border border-slate-700/50 rounded-2xl p-6">
<div className="flex items-center gap-2 mb-4">
<svg className="w-5 h-5 text-teal-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
<h4 className="font-display font-semibold text-white">Resistência</h4>
</div>
<div className="space-y-2">
{resistance.map((item, index) => (
<div key={index} className="flex justify-between text-sm">
<span className="text-slate-400">{item.label}</span>
<span className="text-white font-mono">{item.value}</span>
</div>
))}
</div>
</div>
{/* Display */}
<div className="bg-slate-800/30 border border-slate-700/50 rounded-2xl p-6">
<div className="flex items-center gap-2 mb-4">
<svg className="w-5 h-5 text-cyan-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
<h4 className="font-display font-semibold text-white">Display</h4>
</div>
<div className="space-y-2">
{display.map((item, index) => (
<div key={index} className="flex justify-between text-sm">
<span className="text-slate-400">{item.label}</span>
<span className="text-white font-mono">{item.value}</span>
</div>
))}
</div>
</div>
</div>
</div>
</section>
);
}

189
src/sections/Technology.tsx Normal file
View File

@@ -0,0 +1,189 @@
import { useEffect, useRef } from 'react';
import { Cpu, Box, MapPin, Battery } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
const techCards = [
{
icon: Cpu,
title: 'Microcontrolador ESP32',
description: 'Processador dual-core de 240MHz com conectividade Wi-Fi e Bluetooth integrada para máxima performance.',
tags: [
{ label: 'Dual-core Xtensa', color: 'slate' },
{ label: '520KB SRAM', color: 'slate' },
{ label: 'Wi-Fi 802.11 b/g/n', color: 'slate' },
{ label: 'Bluetooth 4.2', color: 'slate' },
],
color: 'blue',
},
{
icon: Box,
title: 'Impressão 3D Avançada',
description: 'Estrutura fabricada com tecnologia de impressão 3D de alta precisão, garantindo design ergonômico e peso reduzido.',
tags: [
{ label: 'Material PLA+', color: 'orange' },
{ label: 'Resistente a UV', color: 'orange' },
{ label: 'Ultra-leve', color: 'orange' },
{ label: 'Design customizável', color: 'orange' },
],
color: 'orange',
},
{
icon: MapPin,
title: 'Módulo GPS',
description: 'GPS de alta precisão para rastreamento exato de localização, velocidade e distância em tempo real.',
tags: [
{ label: 'Precisão <3m', color: 'slate' },
{ label: 'Atualização 10Hz', color: 'slate' },
{ label: 'Multi-GNSS', color: 'slate' },
{ label: 'Cold start <30s', color: 'slate' },
],
color: 'teal',
},
{
icon: Battery,
title: 'Bateria Inteligente',
description: 'Sistema de energia otimizado com bateria de lítio recarregável via USB-C para até 8 horas de uso contínuo.',
tags: [
{ label: 'Li-Po 500mAh', color: 'orange' },
{ label: 'USB-C Fast Charge', color: 'orange' },
{ label: '8h autonomia', color: 'orange' },
{ label: 'Carregamento 2h', color: 'orange' },
],
color: 'green',
},
];
export function Technology() {
const sectionRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const elements = entry.target.querySelectorAll('.reveal-tech');
elements.forEach((el, index) => {
setTimeout(() => {
el.classList.add('animate-fade-in-up');
}, index * 150);
});
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.15 }
);
if (sectionRef.current) {
observer.observe(sectionRef.current);
}
return () => observer.disconnect();
}, []);
return (
<section id="tecnologia" ref={sectionRef} className="py-24 lg:py-32 bg-slate-900/50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Section Header */}
<div className="text-center mb-16 reveal-tech opacity-0">
<Badge className="mb-4 bg-slate-800 text-cyan-400 border-cyan-500/30 hover:bg-slate-700 px-4 py-1.5 text-xs font-semibold tracking-wider uppercase">
Tecnologia Avançada
</Badge>
<h2 className="font-display font-bold text-3xl sm:text-4xl lg:text-5xl text-white mb-4">
Tecnologia de Ponta
</h2>
<div className="w-16 h-1 bg-gradient-to-r from-orange-500 to-orange-400 mx-auto rounded-full mb-6" />
<p className="text-slate-400 text-lg max-w-2xl mx-auto">
Hardware e software de última geração combinados para criar uma experiência única em óculos de corrida inteligentes.
</p>
</div>
{/* Tech Cards Grid */}
<div className="grid md:grid-cols-2 gap-6 lg:gap-8">
{techCards.map((card, index) => {
const Icon = card.icon;
return (
<div
key={index}
className="reveal-tech opacity-0 group relative bg-gradient-to-br from-slate-800/80 to-slate-800/40 border border-slate-700 rounded-2xl p-6 lg:p-8 hover:border-slate-500 transition-all duration-300 hover:-translate-y-1"
>
{/* Header */}
<div className="flex items-start gap-4 mb-4">
<div className="w-12 h-12 rounded-xl bg-slate-700/50 border border-slate-600 flex items-center justify-center flex-shrink-0 group-hover:bg-slate-700 transition-colors">
<Icon className="w-6 h-6 text-white" />
</div>
<div>
<h3 className="font-display font-semibold text-xl text-white mb-1">
{card.title}
</h3>
<div className="w-12 h-0.5 bg-orange-500 rounded-full" />
</div>
</div>
{/* Description */}
<p className="text-slate-400 mb-6 leading-relaxed">
{card.description}
</p>
{/* Tags */}
<div className="flex flex-wrap gap-2">
{card.tags.map((tag, tagIndex) => (
<Badge
key={tagIndex}
variant="secondary"
className={`${
tag.color === 'orange'
? 'bg-orange-500/10 text-orange-400 border-orange-500/20'
: 'bg-slate-700 text-slate-300 border-slate-600'
} border text-xs font-medium px-3 py-1`}
>
{tag.label}
</Badge>
))}
</div>
</div>
);
})}
</div>
{/* Connectivity Banner */}
<div className="mt-12 reveal-tech opacity-0">
<div className="bg-gradient-to-r from-slate-800/60 to-slate-800/30 border border-slate-700 rounded-2xl p-6 lg:p-8">
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-6">
<div className="flex items-center gap-4">
<div className="w-12 h-12 rounded-xl bg-teal-500/10 border border-teal-500/30 flex items-center justify-center">
<svg className="w-6 h-6 text-teal-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01m-7.08-7.071c3.904-3.905 10.236-3.905 14.141 0M1.394 9.393c5.857-5.857 15.355-5.857 21.213 0" />
</svg>
</div>
<div>
<h4 className="font-display font-semibold text-lg text-white">
Conectividade Sem Limites
</h4>
<p className="text-slate-400 text-sm">
O ESP32 oferece conectividade Bluetooth 4.2 e Wi-Fi integrada
</p>
</div>
</div>
<div className="flex flex-wrap gap-2">
{['Bluetooth LE', 'Wi-Fi Direct', 'OTA Updates', 'Low Power Mode'].map((item, i) => (
<Badge
key={i}
className={`${
i % 2 === 0
? 'bg-slate-700 text-slate-300 border-slate-600'
: 'bg-teal-500/10 text-teal-400 border-teal-500/30'
} border text-xs font-medium px-3 py-1`}
>
{item}
</Badge>
))}
</div>
</div>
</div>
</div>
</div>
</section>
);
}