Animation Added and Gif file updated
This commit is contained in:
@@ -17,6 +17,7 @@ import { useRef, useEffect, useState } from "react";
|
||||
|
||||
export default function AIDiagnosis() {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const canvasContainerRef = useRef<HTMLDivElement>(null); // Ref for the wrapper of the canvas
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const [modelLoaded, setModelLoaded] = useState(false);
|
||||
const [scanProgress, setScanProgress] = useState(0);
|
||||
@@ -28,7 +29,7 @@ export default function AIDiagnosis() {
|
||||
|
||||
const y = useTransform(scrollYProgress, [0, 0.5], [100, 0]);
|
||||
const opacity = useTransform(scrollYProgress, [0, 0.3], [0, 1]);
|
||||
const scale = useTransform(scrollYProgress, [0, 0.5], [0.9, 1]);
|
||||
const scale = useTransform(scrollYProgress, [0, 0.5], [0.95, 1]); // Subtle scale
|
||||
|
||||
// Simulate scan progress
|
||||
useEffect(() => {
|
||||
@@ -40,7 +41,7 @@ export default function AIDiagnosis() {
|
||||
|
||||
// Three.js setup
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined" || !canvasRef.current) return;
|
||||
if (typeof window === "undefined" || !canvasRef.current || !canvasContainerRef.current) return;
|
||||
|
||||
let animationId: number | undefined;
|
||||
let scene: any;
|
||||
@@ -53,8 +54,12 @@ export default function AIDiagnosis() {
|
||||
const THREE = await import("three");
|
||||
const { GLTFLoader, OrbitControls } = await import("three-stdlib");
|
||||
|
||||
// Get initial dimensions from the parent container
|
||||
const width = canvasContainerRef.current?.clientWidth || 500;
|
||||
const height = canvasContainerRef.current?.clientHeight || 500;
|
||||
|
||||
scene = new THREE.Scene();
|
||||
camera = new THREE.PerspectiveCamera(45, 1, 0.1, 1000);
|
||||
camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
|
||||
camera.position.set(0, 0, 5);
|
||||
|
||||
renderer = new THREE.WebGLRenderer({
|
||||
@@ -62,17 +67,15 @@ export default function AIDiagnosis() {
|
||||
alpha: true,
|
||||
antialias: true,
|
||||
});
|
||||
renderer.setSize(500, 500);
|
||||
renderer.setSize(width, height);
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
||||
renderer.setClearColor(0x000000, 0);
|
||||
|
||||
// Lighting
|
||||
scene.add(new THREE.AmbientLight(0xffffff, 0.8));
|
||||
|
||||
const dirLight1 = new THREE.DirectionalLight(0x6366f1, 1.2);
|
||||
dirLight1.position.set(5, 5, 5);
|
||||
scene.add(dirLight1);
|
||||
|
||||
const dirLight2 = new THREE.DirectionalLight(0xa855f7, 0.8);
|
||||
dirLight2.position.set(-5, 3, -5);
|
||||
scene.add(dirLight2);
|
||||
@@ -85,6 +88,21 @@ export default function AIDiagnosis() {
|
||||
controls.autoRotate = true;
|
||||
controls.autoRotateSpeed = 1.5;
|
||||
|
||||
// Handle Resize - Critical for responsiveness
|
||||
const handleResize = () => {
|
||||
if (!canvasContainerRef.current || !camera || !renderer) return;
|
||||
const newWidth = canvasContainerRef.current.clientWidth;
|
||||
const newHeight = canvasContainerRef.current.clientHeight;
|
||||
|
||||
camera.aspect = newWidth / newHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(newWidth, newHeight);
|
||||
};
|
||||
|
||||
// Use ResizeObserver for robust sizing (handles container changes, not just window)
|
||||
const resizeObserver = new ResizeObserver(() => handleResize());
|
||||
resizeObserver.observe(canvasContainerRef.current!);
|
||||
|
||||
// Model loading
|
||||
const loader = new GLTFLoader();
|
||||
const modelURL = "/human_body.glb";
|
||||
@@ -103,7 +121,6 @@ export default function AIDiagnosis() {
|
||||
model.scale.setScalar(scaleFactor);
|
||||
model.position.sub(center.multiplyScalar(scaleFactor));
|
||||
|
||||
// Performance: disable shadows
|
||||
model.traverse((child: any) => {
|
||||
if (child.isMesh) {
|
||||
child.castShadow = false;
|
||||
@@ -114,8 +131,7 @@ export default function AIDiagnosis() {
|
||||
scene.add(model);
|
||||
setModelLoaded(true);
|
||||
} catch (error) {
|
||||
console.error("Failed to load GLB model → using fallback", error);
|
||||
|
||||
console.warn("Using fallback geometry");
|
||||
const geometry = new THREE.IcosahedronGeometry(1.5, 2);
|
||||
const material = new THREE.MeshStandardMaterial({
|
||||
color: 0x6366f1,
|
||||
@@ -123,6 +139,7 @@ export default function AIDiagnosis() {
|
||||
metalness: 0.7,
|
||||
emissive: 0x3b82f6,
|
||||
emissiveIntensity: 0.2,
|
||||
wireframe: true, // Added wireframe for a more "tech" fallback look
|
||||
});
|
||||
model = new THREE.Mesh(geometry, material);
|
||||
scene.add(model);
|
||||
@@ -138,29 +155,22 @@ export default function AIDiagnosis() {
|
||||
};
|
||||
|
||||
animate();
|
||||
|
||||
// Clean up specifically for this closure
|
||||
return () => {
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
};
|
||||
|
||||
initThreeJS();
|
||||
const cleanupPromise = initThreeJS();
|
||||
|
||||
// Cleanup
|
||||
return () => {
|
||||
if (animationId !== undefined) {
|
||||
cancelAnimationFrame(animationId);
|
||||
}
|
||||
cleanupPromise.then((cleanup) => cleanup && cleanup());
|
||||
if (animationId !== undefined) cancelAnimationFrame(animationId);
|
||||
if (controls) controls.dispose();
|
||||
if (renderer) renderer.dispose();
|
||||
if (scene) {
|
||||
scene.traverse((obj: any) => {
|
||||
if (obj.geometry) obj.geometry.dispose();
|
||||
if (obj.material) {
|
||||
if (Array.isArray(obj.material)) {
|
||||
obj.material.forEach((m: any) => m.dispose());
|
||||
} else {
|
||||
obj.material.dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Simplified scene disposal
|
||||
if (scene) scene.clear();
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -168,11 +178,11 @@ export default function AIDiagnosis() {
|
||||
<section
|
||||
ref={containerRef}
|
||||
id="diagnosis"
|
||||
className="relative py-20 md:py-32 lg:py-40 overflow-hidden"
|
||||
className="relative py-16 sm:py-20 md:py-32 lg:py-40 2xl:py-48 overflow-hidden w-full"
|
||||
>
|
||||
{/* Ambient glows */}
|
||||
<div className="absolute top-1/4 left-0 w-[700px] h-[700px] bg-blue-500/10 rounded-full blur-[150px] animate-pulse" />
|
||||
<div className="absolute bottom-1/4 right-0 w-[600px] h-[600px] bg-purple-500/10 rounded-full blur-[120px]" />
|
||||
{/* Ambient glows - Optimized for mobile by reducing blur radius slightly */}
|
||||
{/* <div className="absolute top-1/4 left-0 w-[300px] sm:w-[500px] lg:w-[700px] h-[300px] sm:h-[500px] lg:h-[700px] bg-cyan-500/10 rounded-full blur-[80px] sm:blur-[150px] animate-pulse" />
|
||||
<div className="absolute bottom-1/4 right-0 w-[250px] sm:w-[400px] lg:w-[600px] h-[250px] sm:h-[400px] lg:h-[600px] bg-purple-500/10 rounded-full blur-[60px] sm:blur-[120px]" /> */}
|
||||
|
||||
{/* Subtle grid */}
|
||||
<div
|
||||
@@ -184,159 +194,157 @@ export default function AIDiagnosis() {
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="container relative z-10 mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid lg:grid-cols-2 gap-12 lg:gap-16 xl:gap-24 items-center">
|
||||
{/* 3D Viewer Column */}
|
||||
<div className="container relative z-10 mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl 2xl:max-w-[1600px]">
|
||||
<div className="grid lg:grid-cols-2 gap-10 sm:gap-12 lg:gap-16 xl:gap-24 2xl:gap-32 items-center">
|
||||
|
||||
{/* --- 3D Viewer Column --- */}
|
||||
{/* Order-2 on mobile ensures text comes first if desired, but default is fine */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: -50 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 1 }}
|
||||
className="relative"
|
||||
className="relative w-full max-w-[500px] lg:max-w-none mx-auto"
|
||||
>
|
||||
<div className="absolute inset-0 rounded-[3rem] blur-3xl opacity-60" />
|
||||
{/* Background Blur blob */}
|
||||
<div className="absolute inset-0 rounded-[3rem] blur-3xl opacity-60 bg-gradient-to-tr from-cyan-900/20 to-purple-900/20" />
|
||||
|
||||
<div className="relative rounded-3xl backdrop-blur-2xl shadow-2xl overflow-hidden">
|
||||
{/* Header */}
|
||||
<div className="relative p-6 border-b border-white/5">
|
||||
<div className="relative rounded-3xl backdrop-blur-2xl bg-black/40 border border-white/10 shadow-2xl overflow-hidden">
|
||||
{/* Card Header */}
|
||||
<div className="relative p-4 sm:p-6 border-b border-white/5">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="relative">
|
||||
<div className="w-10 h-10 rounded-xl flex items-center justify-center">
|
||||
<Brain className="w-5 h-5 text-blue-400" />
|
||||
<div className="w-10 h-10 rounded-xl bg-white/5 flex items-center justify-center">
|
||||
<Brain className="w-5 h-5 text-cyan-400" />
|
||||
</div>
|
||||
<div className="absolute -top-1 -right-1 w-3 h-3 bg-green-400 rounded-full border-2 border-black animate-pulse" />
|
||||
<div className="absolute -top-1 -right-1 w-2.5 h-2.5 bg-green-400 rounded-full border-2 border-black animate-pulse" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-bold text-white">Neural Diagnostic Engine</h3>
|
||||
<p className="text-xs text-zinc-500">Real-time Analysis Active</p>
|
||||
<h3 className="text-sm font-bold text-white">Neural Engine</h3>
|
||||
<p className="text-[10px] sm:text-xs text-zinc-500">Analysis Active</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-3 py-1 rounded-full bg-green-500/10 border border-green-500/20">
|
||||
<span className="text-xs font-semibold text-green-400">Live</span>
|
||||
<div className="hidden xs:flex px-3 py-1 rounded-full bg-green-500/10 border border-green-500/20">
|
||||
<span className="text-[10px] sm:text-xs font-semibold text-green-400">Live Feed</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Canvas area */}
|
||||
<div className="relative p-6 sm:p-8">
|
||||
<div className="absolute top-8 left-8 w-16 h-16 border-l-2 border-t-2 border-blue-400/30 rounded-tl-2xl" />
|
||||
<div className="absolute top-8 right-8 w-16 h-16 border-r-2 border-t-2 border-purple-400/30 rounded-tr-2xl" />
|
||||
<div className="absolute bottom-8 left-8 w-16 h-16 border-l-2 border-b-2 border-pink-400/30 rounded-bl-2xl" />
|
||||
<div className="absolute bottom-8 right-8 w-16 h-16 border-r-2 border-b-2 border-cyan-400/30 rounded-br-2xl" />
|
||||
{/* Canvas Container - Responsive Aspect Ratio */}
|
||||
<div className="relative p-4 sm:p-8">
|
||||
{/* Decorative corners */}
|
||||
<div className="absolute top-4 sm:top-8 left-4 sm:left-8 w-12 sm:w-16 h-12 sm:h-16 border-l-2 border-t-2 border-cyan-400/30 rounded-tl-2xl" />
|
||||
<div className="absolute top-4 sm:top-8 right-4 sm:right-8 w-12 sm:w-16 h-12 sm:h-16 border-r-2 border-t-2 border-purple-400/30 rounded-tr-2xl" />
|
||||
<div className="absolute bottom-4 sm:bottom-8 left-4 sm:left-8 w-12 sm:w-16 h-12 sm:h-16 border-l-2 border-b-2 border-pink-400/30 rounded-bl-2xl" />
|
||||
<div className="absolute bottom-4 sm:bottom-8 right-4 sm:right-8 w-12 sm:w-16 h-12 sm:h-16 border-r-2 border-b-2 border-cyan-400/30 rounded-br-2xl" />
|
||||
|
||||
<div className="relative aspect-square flex items-center justify-center">
|
||||
{/* The actual canvas wrapper */}
|
||||
<div
|
||||
ref={canvasContainerRef}
|
||||
className="relative w-full aspect-square max-h-[400px] lg:max-h-[500px] flex items-center justify-center mx-auto"
|
||||
>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
className="w-full h-full max-w-[500px] max-h-[500px] relative z-10"
|
||||
className="w-full h-full relative z-10 block"
|
||||
/>
|
||||
|
||||
{/* Loading State */}
|
||||
{!modelLoaded && (
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
|
||||
<div className="space-y-4 text-center">
|
||||
<motion.div
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
|
||||
>
|
||||
<Brain className="w-16 h-16 text-blue-400 mx-auto" />
|
||||
<Brain className="w-12 h-12 sm:w-16 sm:h-16 text-cyan-400 mx-auto" />
|
||||
</motion.div>
|
||||
<p className="text-sm text-zinc-400 font-semibold">
|
||||
Initializing Neural Network...
|
||||
<p className="text-xs sm:text-sm text-zinc-400 font-semibold">
|
||||
Initializing Network...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Scanning Animation Overlay */}
|
||||
{modelLoaded && (
|
||||
<>
|
||||
<div className="absolute inset-0 pointer-events-none overflow-hidden rounded-xl">
|
||||
<motion.div
|
||||
animate={{ y: [-250, 250] }}
|
||||
animate={{ top: ["0%", "100%", "0%"] }}
|
||||
transition={{ duration: 3, repeat: Infinity, ease: "linear" }}
|
||||
className="absolute inset-x-0 h-px bg-gradient-to-r from-transparent via-blue-400 to-transparent opacity-50"
|
||||
className="absolute left-0 right-0 h-px bg-gradient-to-r from-transparent via-cyan-400 to-transparent opacity-50 shadow-[0_0_15px_rgba(34,211,238,0.5)]"
|
||||
/>
|
||||
<motion.div
|
||||
animate={{ y: [250, -250] }}
|
||||
transition={{ duration: 4, repeat: Infinity, ease: "linear", delay: 1.5 }}
|
||||
className="absolute inset-x-0 h-px bg-gradient-to-r from-transparent via-purple-400 to-transparent opacity-30"
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Status footer */}
|
||||
<div className="p-6 space-y-4 border-t border-white/5">
|
||||
<div className="p-4 sm:p-6 space-y-4 border-t border-white/5">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between text-xs">
|
||||
<span className="text-zinc-400 font-semibold">Analysis Progress</span>
|
||||
<span className="text-blue-400 font-bold">{scanProgress}%</span>
|
||||
<span className="text-cyan-400 font-bold">{scanProgress}%</span>
|
||||
</div>
|
||||
<div className="h-2 bg-white/5 rounded-full overflow-hidden">
|
||||
<div className="h-1.5 sm:h-2 bg-white/5 rounded-full overflow-hidden">
|
||||
<motion.div
|
||||
style={{ width: `${scanProgress}%` }}
|
||||
className="h-full bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500"
|
||||
className="h-full bg-gradient-to-r from-cyan-500 via-purple-500 to-pink-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<div className="grid grid-cols-3 gap-2 sm:gap-3">
|
||||
{[
|
||||
{ icon: Cpu, label: "Processing", value: "98.4%", color: "text-blue-400" },
|
||||
{ icon: Network, label: "Neural Load", value: "76.2%", color: "text-purple-400" },
|
||||
{ icon: Activity, label: "Accuracy", value: "99.8%", color: "text-green-400" },
|
||||
{ icon: Cpu, label: "CPU Load", value: "98%", color: "text-cyan-400" },
|
||||
{ icon: Network, label: "Net Load", value: "76%", color: "text-purple-400" },
|
||||
{ icon: Activity, label: "Accuracy", value: "99%", color: "text-green-400" },
|
||||
].map((stat, idx) => (
|
||||
<motion.div
|
||||
<div
|
||||
key={idx}
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: idx * 0.1 }}
|
||||
className="p-3 rounded-xl bg-white/[0.03] border border-white/5"
|
||||
className="p-2 sm:p-3 rounded-xl bg-white/[0.03] border border-white/5 text-center sm:text-left"
|
||||
>
|
||||
<stat.icon className={`w-4 h-4 ${stat.color} mb-2`} />
|
||||
<p className="text-xs text-zinc-500 mb-1">{stat.label}</p>
|
||||
<p className="text-sm font-bold text-white">{stat.value}</p>
|
||||
</motion.div>
|
||||
<stat.icon className={`w-3 h-3 sm:w-4 sm:h-4 ${stat.color} mb-1 sm:mb-2 mx-auto sm:mx-0`} />
|
||||
<p className="hidden sm:block text-[10px] text-zinc-500 mb-0.5">{stat.label}</p>
|
||||
<p className="text-xs sm:text-sm font-bold text-white">{stat.value}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="px-6 pb-6">
|
||||
<p className="text-center text-xs text-zinc-600 font-medium flex items-center justify-center gap-2">
|
||||
<span className="w-1 h-1 rounded-full bg-zinc-600 animate-pulse" />
|
||||
Drag to rotate • Interactive 3D visualization
|
||||
<span className="w-1 h-1 rounded-full bg-zinc-600 animate-pulse" />
|
||||
</p>
|
||||
|
||||
<div className="pb-4 sm:pb-6 text-center">
|
||||
<p className="text-[10px] text-zinc-600 font-medium">Interactive 3D Visualization</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Text / Features Column */}
|
||||
{/* --- Text / Features Column --- */}
|
||||
<motion.div
|
||||
style={{ y, opacity, scale }}
|
||||
className="space-y-10 lg:space-y-12"
|
||||
className="space-y-8 sm:space-y-10 lg:space-y-12 text-center lg:text-left"
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.7, delay: 0.1 }}
|
||||
className="space-y-6"
|
||||
className="space-y-4 sm:space-y-6"
|
||||
>
|
||||
<h2 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold leading-[1.1] tracking-tight text-white">
|
||||
<h2 className="text-3xl sm:text-4xl md:text-5xl lg:text-6xl 2xl:text-7xl font-bold leading-[1.1] tracking-tight text-white">
|
||||
Neural Clinical
|
||||
<br />
|
||||
<span className="bg-gradient-to-r from-purple-400 via-pink-400 to-blue-400 bg-clip-text text-transparent">
|
||||
<span className="bg-gradient-to-r from-purple-400 via-pink-400 to-cyan-400 bg-clip-text text-transparent">
|
||||
Synthesis
|
||||
</span>
|
||||
</h2>
|
||||
<p className="text-base sm:text-lg lg:text-xl text-zinc-400 leading-relaxed max-w-2xl">
|
||||
<p className="text-sm sm:text-base md:text-lg lg:text-xl text-zinc-400 leading-relaxed max-w-2xl mx-auto lg:mx-0">
|
||||
Enterprise-grade diagnostic assistance powered by advanced AI. Cross-reference clinical patterns against{" "}
|
||||
<span className="text-white font-semibold">global medical databases</span> with{" "}
|
||||
<span className="text-white font-semibold">sub-second latency</span> and unparalleled accuracy.
|
||||
<span className="text-white font-semibold">sub-second latency</span>.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
{/* Feature Cards */}
|
||||
{/* Feature Cards - Stack on mobile, grid on tablet+ */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
@@ -349,8 +357,8 @@ export default function AIDiagnosis() {
|
||||
icon: Search,
|
||||
title: "Pattern Recognition",
|
||||
text: "AI-powered clinical marker identification with zero-bias analysis technology.",
|
||||
color: "from-blue-500 to-cyan-500",
|
||||
iconColor: "text-blue-400",
|
||||
color: "from-cyan-500 to-cyan-500",
|
||||
iconColor: "text-cyan-400",
|
||||
},
|
||||
{
|
||||
icon: Database,
|
||||
@@ -362,58 +370,49 @@ export default function AIDiagnosis() {
|
||||
].map((item, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6, delay: 0.3 + i * 0.1 }}
|
||||
whileHover={{
|
||||
y: -4,
|
||||
transition: { duration: 0.2 },
|
||||
}}
|
||||
className="group p-5 sm:p-6 rounded-2xl bg-white/[0.02] border border-white/5 backdrop-blur-sm hover:bg-white/[0.04] hover:border-white/10 transition-all cursor-pointer"
|
||||
whileHover={{ y: -4, transition: { duration: 0.2 }}}
|
||||
className="group p-5 rounded-2xl bg-white/[0.02] border border-white/5 backdrop-blur-sm hover:bg-white/[0.04] hover:border-white/10 transition-all cursor-pointer text-left"
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<div className="relative inline-block">
|
||||
<div
|
||||
className={`absolute inset-0 bg-gradient-to-br ${item.color} rounded-xl blur-lg opacity-0 group-hover:opacity-50 transition-opacity`}
|
||||
/>
|
||||
<div className="relative w-12 h-12 rounded-xl bg-gradient-to-br from-white/10 to-white/5 border border-white/10 flex items-center justify-center group-hover:border-white/20 transition-colors">
|
||||
<item.icon className={`w-6 h-6 ${item.iconColor}`} />
|
||||
<div className="flex sm:block items-start gap-4">
|
||||
<div className="relative shrink-0">
|
||||
<div className={`absolute inset-0 bg-gradient-to-br ${item.color} rounded-xl blur-lg opacity-0 group-hover:opacity-50 transition-opacity`} />
|
||||
<div className="relative w-10 h-10 sm:w-12 sm:h-12 rounded-xl bg-gradient-to-br from-white/10 to-white/5 border border-white/10 flex items-center justify-center group-hover:border-white/20 transition-colors">
|
||||
<item.icon className={`w-5 h-5 sm:w-6 sm:h-6 ${item.iconColor}`} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-lg font-bold text-white group-hover:text-white/90 transition-colors">
|
||||
<div className="space-y-1 sm:space-y-2 sm:mt-4">
|
||||
<h3 className="text-base sm:text-lg font-bold text-white group-hover:text-white/90 transition-colors">
|
||||
{item.title}
|
||||
</h3>
|
||||
<p className="text-sm text-zinc-400 leading-relaxed">{item.text}</p>
|
||||
<p className="text-xs sm:text-sm text-zinc-400 leading-relaxed">{item.text}</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</motion.div>
|
||||
|
||||
{/* Stats */}
|
||||
{/* Stats - Grid adjustments */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.7, delay: 0.4 }}
|
||||
className="grid grid-cols-3 gap-4 sm:gap-6 pt-6"
|
||||
className="grid grid-cols-3 gap-2 sm:gap-6 pt-4 sm:pt-6 border-t border-white/5 lg:border-none"
|
||||
>
|
||||
{[
|
||||
{ icon: Zap, value: "<500ms", label: "Query Time" },
|
||||
{ icon: Shield, value: "100%", label: "Secure" },
|
||||
{ icon: TrendingUp, value: "99.8%", label: "Accuracy" },
|
||||
].map((stat, i) => (
|
||||
<div key={i} className="text-center space-y-2">
|
||||
<div key={i} className="text-center space-y-1 sm:space-y-2">
|
||||
<div className="flex justify-center">
|
||||
<div className="p-2 rounded-lg bg-white/5 border border-white/10">
|
||||
<stat.icon className="w-4 h-4 sm:w-5 sm:h-5 text-purple-400" />
|
||||
<div className="p-1.5 sm:p-2 rounded-lg bg-white/5 border border-white/10">
|
||||
<stat.icon className="w-3.5 h-3.5 sm:w-5 sm:h-5 text-purple-400" />
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xl sm:text-2xl font-bold text-white">{stat.value}</p>
|
||||
<p className="text-[10px] sm:text-xs text-zinc-500 font-semibold uppercase tracking-wider">
|
||||
<p className="text-lg sm:text-xl md:text-2xl font-bold text-white">{stat.value}</p>
|
||||
<p className="text-[9px] sm:text-xs text-zinc-500 font-semibold uppercase tracking-wider">
|
||||
{stat.label}
|
||||
</p>
|
||||
</div>
|
||||
@@ -426,12 +425,12 @@ export default function AIDiagnosis() {
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.7, delay: 0.5 }}
|
||||
className="flex flex-wrap gap-3 sm:gap-4 pt-4"
|
||||
className="flex flex-wrap justify-center lg:justify-start gap-2 sm:gap-4 pt-2"
|
||||
>
|
||||
{["FDA Compliant", "HIPAA Certified", "ISO 27001"].map((badge, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex items-center gap-2 px-3 sm:px-4 py-2 rounded-full bg-white/[0.03] border border-white/10 backdrop-blur-sm"
|
||||
className="flex items-center gap-1.5 sm:gap-2 px-3 py-1.5 sm:px-4 sm:py-2 rounded-full bg-white/[0.03] border border-white/10 backdrop-blur-sm"
|
||||
>
|
||||
<CheckCircle className="w-3 h-3 sm:w-4 sm:h-4 text-green-400" />
|
||||
<span className="text-[10px] sm:text-xs text-zinc-400 font-semibold">{badge}</span>
|
||||
|
||||
@@ -1,173 +1,172 @@
|
||||
"use client";
|
||||
|
||||
import { motion, useScroll, useTransform } from "framer-motion";
|
||||
import { Mic, CheckCircle2, Brain, Zap, Lock, Sparkles } from "lucide-react";
|
||||
import { Mic, Brain, Zap, Lock, Sparkles, AudioWaveform } from "lucide-react";
|
||||
import { useRef } from "react";
|
||||
|
||||
export default function AIVoiceSoap() {
|
||||
const containerRef = useRef(null);
|
||||
const { scrollYProgress } = useScroll({
|
||||
target: containerRef,
|
||||
offset: ["start end", "end start"],
|
||||
});
|
||||
const containerRef = useRef(null);
|
||||
const { scrollYProgress } = useScroll({
|
||||
target: containerRef,
|
||||
offset: ["start end", "end start"],
|
||||
});
|
||||
|
||||
const scale = useTransform(scrollYProgress, [0, 0.5], [0.95, 1]);
|
||||
const opacity = useTransform(scrollYProgress, [0, 0.4], [0.6, 1]);
|
||||
const y = useTransform(scrollYProgress, [0, 0.5], [40, 0]);
|
||||
const scale = useTransform(scrollYProgress, [0, 0.5], [0.95, 1]);
|
||||
const opacity = useTransform(scrollYProgress, [0, 0.4], [0.6, 1]);
|
||||
const y = useTransform(scrollYProgress, [0, 0.5], [40, 0]);
|
||||
|
||||
const bars = Array.from({ length: 24 }, (_, i) => ({
|
||||
height: [20, 45 + Math.sin(i * 0.8) * 30, 20],
|
||||
duration: 2 + (i % 8) * 0.25,
|
||||
delay: i * 0.03,
|
||||
}));
|
||||
// Dynamic bar animation for visualizer
|
||||
const bars = Array.from({ length: 24 }, (_, i) => ({
|
||||
height: [20, 45 + Math.sin(i * 0.8) * 30, 20],
|
||||
duration: 2 + (i % 8) * 0.25,
|
||||
delay: i * 0.03,
|
||||
}));
|
||||
|
||||
return (
|
||||
<section
|
||||
ref={containerRef}
|
||||
id="voice-soap"
|
||||
className="relative py-20 md:py-32 lg:py-40 text-white overflow-hidden"
|
||||
>
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-zinc-950 via-zinc-900/50 to-zinc-950" />
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,_var(--tw-gradient-stops))] from-blue-950/20 via-transparent to-transparent" />
|
||||
return (
|
||||
<section
|
||||
ref={containerRef}
|
||||
id="voice-soap"
|
||||
className="relative py-16 sm:py-20 md:py-32 lg:py-40 2xl:py-48 text-white overflow-hidden bg-transparent"
|
||||
>
|
||||
<div className="container relative z-10 mx-auto px-4 sm:px-6 lg:px-12 max-w-7xl 2xl:max-w-[1600px]">
|
||||
<div className="grid lg:grid-cols-2 gap-12 lg:gap-24 xl:gap-32 items-center">
|
||||
<motion.div
|
||||
style={{ scale, opacity, y }}
|
||||
className="space-y-10 lg:space-y-14 order-2 lg:order-1"
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
viewport={{ once: true }}
|
||||
className="inline-flex items-center gap-2 sm:gap-3 px-4 py-2 rounded-full bg-cyan-950/30 border border-cyan-500/20 text-cyan-400 text-[10px] sm:text-xs font-semibold tracking-wide uppercase backdrop-blur-md"
|
||||
>
|
||||
<Mic className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
|
||||
Ambient Clinical Intelligence
|
||||
</motion.div>
|
||||
|
||||
<div className="container relative z-10 mx-auto px-5 md:px-8 lg:px-12 max-w-7xl">
|
||||
<div className="grid lg:grid-cols-2 gap-16 lg:gap-24 xl:gap-32 items-center">
|
||||
<motion.div
|
||||
style={{ scale, opacity, y }}
|
||||
className="space-y-10 lg:space-y-14"
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
viewport={{ once: true }}
|
||||
className="inline-flex items-center gap-3 px-6 py-2 rounded-full bg-blue-950/40 border border-blue-800/40 text-blue-400 text-xs font-semibold tracking-wide uppercase"
|
||||
>
|
||||
<Mic className="w-4 h-4" />
|
||||
Ambient Clinical Intelligence
|
||||
</motion.div>
|
||||
|
||||
<div className="space-y-6">
|
||||
<h2 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold tracking-tight leading-tight">
|
||||
Autonomous{" "}
|
||||
<span className="text-blue-400">Voice-to-SOAP</span>
|
||||
</h2>
|
||||
<p className="text-xl md:text-2xl text-zinc-400 leading-relaxed max-w-3xl font-light">
|
||||
Transform ambient conversations into structured, accurate{" "}
|
||||
<span className="text-white font-medium">SOAP notes</span> in real-time — with enterprise-grade security and clinical precision.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6 pt-6">
|
||||
{[
|
||||
{ icon: Brain, title: "Neural Context Understanding", desc: "Advanced NLP for medical terminology and context" },
|
||||
{ icon: Zap, title: "Instant SOAP Generation", desc: "Zero-latency transcription to structured notes" },
|
||||
{ icon: Lock, title: "End-to-End PHI Security", desc: "AES-256 encryption & HIPAA/GDPR compliant" },
|
||||
{ icon: Sparkles, title: "Auto-Suggest & Edit", desc: "AI-powered refinements & clinician review" },
|
||||
].map((item, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
initial={{ opacity: 0, y: 15 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.15 * i }}
|
||||
viewport={{ once: true }}
|
||||
whileHover={{ scale: 1.03, transition: { duration: 0.2 } }}
|
||||
className="flex gap-5 p-5 rounded-2xl bg-zinc-900/50 border border-zinc-800 hover:border-blue-800/50 transition-all"
|
||||
>
|
||||
<div className="w-12 h-12 rounded-xl bg-blue-950/40 border border-blue-800/40 flex items-center justify-center flex-shrink-0">
|
||||
<item.icon className="w-6 h-6 text-blue-400" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<h4 className="text-lg font-semibold text-white">{item.title}</h4>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.96 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.8, delay: 0.2 }}
|
||||
viewport={{ once: true }}
|
||||
className="relative w-full max-w-lg mx-auto lg:mx-0"
|
||||
>
|
||||
<div className="relative rounded-3xl backdrop-blur-xl shadow-2xl overflow-hidden">
|
||||
<div className="absolute inset-0 pointer-events-none" />
|
||||
|
||||
<div className="p-8 md:p-10 lg:p-12 space-y-10 lg:space-y-12 relative">
|
||||
<div className="flex justify-center">
|
||||
<div className="relative">
|
||||
<motion.div
|
||||
animate={{ scale: [1, 1.4, 1], opacity: [0.4, 0, 0.4] }}
|
||||
transition={{ duration: 3, repeat: Infinity, ease: "easeInOut" }}
|
||||
className="absolute inset-[-20%] rounded-full bg-blue-500/20 blur-2xl"
|
||||
/>
|
||||
<motion.div
|
||||
animate={{ scale: [1, 1.3, 1], opacity: [0.3, 0, 0.3] }}
|
||||
transition={{ duration: 4, repeat: Infinity, ease: "easeInOut", delay: 0.6 }}
|
||||
className="absolute inset-[-20%] rounded-full bg-purple-500/15 blur-3xl"
|
||||
/>
|
||||
|
||||
<div className="relative w-24 h-24 md:w-32 md:h-32 lg:w-40 lg:h-40 rounded-full bg-zinc-800/70 border-2 border-zinc-700 flex items-center justify-center shadow-inner">
|
||||
<Mic className="w-12 h-12 md:w-16 md:h-16 lg:w-20 lg:h-20 text-blue-400 drop-shadow-lg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center items-end gap-1.5 h-32 md:h-6 px-4">
|
||||
{bars.map((bar, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
animate={{ height: bar.height }}
|
||||
transition={{
|
||||
repeat: Infinity,
|
||||
duration: bar.duration,
|
||||
ease: "easeInOut",
|
||||
delay: bar.delay,
|
||||
}}
|
||||
className="w-1.5 md:w-2 rounded-full bg-gradient-to-t from-blue-700 to-blue-400 shadow-md"
|
||||
style={{ opacity: 0.4 + (i % 8) * 0.08 }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.7, delay: 0.4 }}
|
||||
viewport={{ once: true }}
|
||||
className="relative rounded-2xl bg-zinc-800/60 border border-zinc-700/80 p-6 md:p-8 shadow-inner overflow-hidden"
|
||||
>
|
||||
<motion.div
|
||||
animate={{ x: ["-100%", "200%"] }}
|
||||
transition={{ duration: 4, repeat: Infinity, ease: "linear", repeatDelay: 3 }}
|
||||
className="absolute inset-0 bg-gradient-to-r from-transparent via-white/5 to-transparent pointer-events-none"
|
||||
/>
|
||||
|
||||
<div className="space-y-4 text-sm md:text-base">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-2.5 h-2.5 rounded-full bg-blue-500 shadow-lg" />
|
||||
<div className="h-3 bg-gradient-to-r from-blue-400/30 to-transparent rounded-full flex-1" />
|
||||
</div>
|
||||
<div className="h-2.5 bg-zinc-700/50 rounded-full ml-8" />
|
||||
<div className="h-2.5 bg-zinc-700/50 rounded-full ml-8 w-5/6" />
|
||||
<div className="h-2.5 bg-zinc-700/50 rounded-full ml-8 w-3/4" />
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex items-center gap-3 text-xs md:text-sm text-zinc-400">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
|
||||
<span>Processing in real-time</span>
|
||||
</div>
|
||||
<div className="ml-auto text-emerald-400 font-medium">Secure • Encrypted</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
<div className="space-y-4 sm:space-y-6">
|
||||
<h2 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl 2xl:text-8xl font-bold tracking-tight leading-[1.1]">
|
||||
Autonomous{" "}
|
||||
<span className="text-cyan-400 block sm:inline">Voice-to-SOAP</span>
|
||||
</h2>
|
||||
<p className="text-lg sm:text-xl md:text-2xl 2xl:text-3xl text-zinc-400 leading-relaxed max-w-3xl font-light">
|
||||
Transform ambient conversations into structured, accurate{" "}
|
||||
<span className="text-white font-medium">SOAP notes</span> in real-time — with enterprise-grade security.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-6 pt-2 sm:pt-6">
|
||||
{[
|
||||
{ icon: Brain, title: "Neural Context", desc: "Advanced NLP for medical terminology" },
|
||||
{ icon: Zap, title: "Instant Generation", desc: "Zero-latency transcription to notes" },
|
||||
{ icon: Lock, title: "PHI Security", desc: "AES-256 encryption & HIPAA compliant" },
|
||||
{ icon: Sparkles, title: "Auto-Refinement", desc: "AI-powered suggestions & review" },
|
||||
].map((item, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
initial={{ opacity: 0, y: 15 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.15 * i }}
|
||||
viewport={{ once: true }}
|
||||
whileHover={{ scale: 1.02, backgroundColor: "rgba(255,255,255,0.08)" }}
|
||||
className="flex gap-4 p-4 sm:p-5 rounded-2xl bg-white/5 border border-white/10 backdrop-blur-sm hover:border-cyan-500/30 transition-all cursor-default"
|
||||
>
|
||||
<div className="w-10 h-10 rounded-lg bg-cyan-500/10 border border-cyan-500/20 flex items-center justify-center flex-shrink-0">
|
||||
<item.icon className="w-5 h-5 text-cyan-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-sm sm:text-base font-bold text-white mb-1">{item.title}</h4>
|
||||
<p className="text-xs text-zinc-400 leading-relaxed">{item.desc}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.96 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.8, delay: 0.2 }}
|
||||
viewport={{ once: true }}
|
||||
className="relative w-full max-w-lg 2xl:max-w-xl mx-auto lg:mx-0 order-1 lg:order-2"
|
||||
>
|
||||
<div className="relative rounded-[2rem] sm:rounded-[2.5rem] backdrop-blur-xl shadow-2xl overflow-hidden">
|
||||
{/* Inner Content Padding */}
|
||||
<div className="p-6 sm:p-10 lg:p-12 2xl:p-16 space-y-8 sm:space-y-10 lg:space-y-12 relative z-10">
|
||||
{/* Microphone Animation */}
|
||||
<div className="flex justify-center">
|
||||
<div className="relative">
|
||||
<motion.div
|
||||
animate={{ scale: [1, 1.4, 1], opacity: [0.4, 0, 0.4] }}
|
||||
transition={{ duration: 3, repeat: Infinity, ease: "easeInOut" }}
|
||||
className="absolute inset-[-20%] rounded-full bg-cyan-500/20 blur-2xl"
|
||||
/>
|
||||
<div className="relative w-20 h-20 sm:w-28 sm:h-28 2xl:w-36 2xl:h-36 rounded-full bg-gradient-to-b from-zinc-800 to-zinc-900 border border-zinc-700 flex items-center justify-center shadow-[0_8px_32px_rgba(0,0,0,0.5)]">
|
||||
<Mic className="w-8 h-8 sm:w-12 sm:h-12 2xl:w-16 2xl:h-16 text-cyan-400 drop-shadow-lg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Audio Waveform Bars - Responsive height/gap */}
|
||||
<div className="flex justify-center items-end gap-1 sm:gap-1.5 h-12 sm:h-16 px-2 sm:px-4">
|
||||
{bars.map((bar, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
animate={{ height: bar.height }}
|
||||
transition={{
|
||||
repeat: Infinity,
|
||||
duration: bar.duration,
|
||||
ease: "easeInOut",
|
||||
delay: bar.delay,
|
||||
}}
|
||||
className="w-1 sm:w-1.5 md:w-2 rounded-full bg-cyan-500"
|
||||
style={{ opacity: 0.3 + (i % 8) * 0.1 }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Processing Status Box */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.7, delay: 0.4 }}
|
||||
viewport={{ once: true }}
|
||||
className="relative rounded-2xl bg-black/20 border border-white/5 p-4 sm:p-6 backdrop-blur-md"
|
||||
>
|
||||
{/* Scan Line Animation */}
|
||||
<motion.div
|
||||
animate={{ x: ["-100%", "200%"] }}
|
||||
transition={{ duration: 3, repeat: Infinity, ease: "linear", repeatDelay: 2 }}
|
||||
className="absolute inset-0 bg-gradient-to-r from-transparent via-cyan-400/10 to-transparent pointer-events-none"
|
||||
/>
|
||||
|
||||
{/* Abstract Data Lines */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-2 h-2 rounded-full bg-cyan-500 shadow-[0_0_10px_rgba(6,182,212,0.5)]" />
|
||||
<div className="h-1.5 sm:h-2 bg-white/10 rounded-full flex-1 w-full" />
|
||||
</div>
|
||||
<div className="h-1.5 sm:h-2 bg-white/10 rounded-full ml-5 w-3/4" />
|
||||
<div className="h-1.5 sm:h-2 bg-white/10 rounded-full ml-5 w-5/6" />
|
||||
</div>
|
||||
|
||||
<div className="mt-4 sm:mt-5 flex items-center justify-between text-[10px] sm:text-xs text-zinc-400 font-mono">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="relative flex h-2 w-2">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
|
||||
<span className="relative inline-flex rounded-full h-2 w-2 bg-emerald-500"></span>
|
||||
</span>
|
||||
<span>Processing...</span>
|
||||
</div>
|
||||
<div className="text-emerald-400">Encrypted</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -40,8 +40,8 @@ export default function AIVoiceSoap() {
|
||||
icon: Activity,
|
||||
title: "Context-Aware Intelligence",
|
||||
desc: "Understands medical terminology, patient history context & follow-up questions.",
|
||||
color: "text-blue-400",
|
||||
bg: "from-blue-600/15 to-blue-800/5",
|
||||
color: "text-cyan-400",
|
||||
bg: "from-cyan-600/15 to-cyan-800/5",
|
||||
},
|
||||
{
|
||||
icon: Zap,
|
||||
|
||||
@@ -142,10 +142,10 @@ function TechCard({ tech, i }: { tech: Technology; i: number }) {
|
||||
<tech.icon className="w-8 h-8 text-white" />
|
||||
</motion.div>
|
||||
|
||||
<div className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-green-500/10 border border-green-500/20">
|
||||
{/* <div className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-green-500/10 border border-green-500/20">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-green-400 animate-pulse" />
|
||||
<span className="text-[10px] text-green-400 font-bold uppercase tracking-wider">Active</span>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@@ -230,7 +230,7 @@ export default function TechShowcase() {
|
||||
return (
|
||||
<section id="technologies" className="relative py-20 md:py-32 lg:py-40 overflow-hidden">
|
||||
{/* Ambient Effects - More Subtle */}
|
||||
<div className="absolute top-1/3 left-0 w-[500px] h-[500px] bg-blue-500/5 rounded-full blur-[120px]" />
|
||||
<div className="absolute top-1/3 left-0 w-[500px] h-[500px] bg-cyan-500/5 rounded-full blur-[120px]" />
|
||||
<div className="absolute bottom-1/3 right-0 w-[500px] h-[500px] bg-purple-500/5 rounded-full blur-[120px]" />
|
||||
|
||||
{/* Dot Grid Pattern */}
|
||||
|
||||
Reference in New Issue
Block a user