first commit
This commit is contained in:
119
src/sections/About.tsx
Normal file
119
src/sections/About.tsx
Normal 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
155
src/sections/Colors.tsx
Normal 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
169
src/sections/Comfort.tsx
Normal 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
121
src/sections/Features.tsx
Normal 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 já 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
168
src/sections/Footer.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
158
src/sections/FutureUpdates.tsx
Normal file
158
src/sections/FutureUpdates.tsx
Normal 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
186
src/sections/Hero.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
183
src/sections/Integration.tsx
Normal file
183
src/sections/Integration.tsx
Normal 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
131
src/sections/Navigation.tsx
Normal 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
196
src/sections/Specs.tsx
Normal 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
189
src/sections/Technology.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user