Skip to content

Commit 7c9f575

Browse files
committed
feat: add features showcase section with interactive video gallery to Landing page
1 parent be3a0b9 commit 7c9f575

7 files changed

Lines changed: 109 additions & 1 deletion

File tree

public/videos/.gitkeep

Whitespace-only changes.

public/videos/Appointments.mp4

4.36 MB
Binary file not shown.
2.72 MB
Binary file not shown.
12 MB
Binary file not shown.
4.15 MB
Binary file not shown.

public/videos/Diary.mp4

4.12 MB
Binary file not shown.

src/pages/Landing.jsx

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from 'react';
1+
import { useState, useEffect } from 'react';
22
import { useNavigate } from 'react-router-dom';
33
import { motion } from 'framer-motion';
44
import { apiClient } from '@/api/client';
@@ -41,6 +41,29 @@ const TEAM = [
4141
},
4242
];
4343

44+
const FEATURES = [
45+
{
46+
title: 'Seamless Connection',
47+
video: '/videos/Connecting doctor and patients.mp4'
48+
},
49+
{
50+
title: 'Precision Medication',
51+
video: '/videos/Assigning medication.mp4'
52+
},
53+
{
54+
title: 'Intuitive Diary',
55+
video: '/videos/Diary.mp4'
56+
},
57+
{
58+
title: 'Smart Appointments',
59+
video: '/videos/Appointments.mp4'
60+
},
61+
{
62+
title: 'Custom Health Forms',
63+
video: '/videos/Creating a health form.mp4'
64+
},
65+
];
66+
4467
const containerVariants = {
4568
hidden: { opacity: 0 },
4669
visible: {
@@ -74,6 +97,27 @@ export default function Landing() {
7497
document.getElementById(id)?.scrollIntoView({ behavior: 'smooth' });
7598
};
7699

100+
useEffect(() => {
101+
const handleFullscreenChange = () => {
102+
if (!document.fullscreenElement && !document.webkitFullscreenElement) {
103+
// Mute all feature videos when exiting fullscreen
104+
const videos = document.querySelectorAll('video');
105+
videos.forEach(v => {
106+
if (v.src.includes('/videos/')) {
107+
v.muted = true;
108+
}
109+
});
110+
}
111+
};
112+
113+
document.addEventListener('fullscreenchange', handleFullscreenChange);
114+
document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
115+
return () => {
116+
document.removeEventListener('fullscreenchange', handleFullscreenChange);
117+
document.removeEventListener('webkitfullscreenchange', handleFullscreenChange);
118+
};
119+
}, []);
120+
77121
const handleReviewSubmit = async (e) => {
78122
e.preventDefault();
79123
const name = isAnonymous ? 'Anonymous' : reviewName || 'Anonymous';
@@ -362,6 +406,70 @@ export default function Landing() {
362406
</div>
363407
</section>
364408

409+
{/* Features Showcase */}
410+
<section className="px-8 py-32 max-w-7xl mx-auto">
411+
<motion.div
412+
initial={{ opacity: 0, y: 20 }}
413+
whileInView={{ opacity: 1, y: 0 }}
414+
viewport={{ once: true }}
415+
className="text-center mb-20"
416+
>
417+
<h2 className="text-4xl font-heading font-bold mb-4 tracking-tight">Features Showcase</h2>
418+
<p className="text-muted-foreground">Experience the powerful tools designed to simplify complex care.</p>
419+
</motion.div>
420+
421+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
422+
{FEATURES.map((feature, i) => (
423+
<motion.div
424+
key={i}
425+
initial={{ opacity: 0, y: 30 }}
426+
whileInView={{ opacity: 1, y: 0 }}
427+
viewport={{ once: true }}
428+
transition={{ delay: i * 0.1 }}
429+
className="bg-card rounded-[32px] border border-border overflow-hidden hover:shadow-2xl transition-all group"
430+
>
431+
<div
432+
className="aspect-video bg-muted relative overflow-hidden cursor-pointer group"
433+
onClick={(e) => {
434+
const video = e.currentTarget.querySelector('video');
435+
if (video) {
436+
if (video.requestFullscreen) video.requestFullscreen();
437+
else if (video.webkitRequestFullscreen) video.webkitRequestFullscreen();
438+
video.muted = false;
439+
video.play();
440+
}
441+
}}
442+
>
443+
<video
444+
src={feature.video}
445+
autoPlay
446+
loop
447+
muted
448+
playsInline
449+
className="w-full h-full object-cover grayscale group-hover:grayscale-0 transition-all duration-700 scale-105 group-hover:scale-100"
450+
/>
451+
452+
{/* Split Screen Labels */}
453+
<div className="absolute inset-x-0 top-4 px-6 flex justify-between pointer-events-none">
454+
<span className="text-[8px] uppercase tracking-[0.2em] font-bold bg-black/40 backdrop-blur-md px-2 py-1 rounded-md text-white/90 border border-white/10">Patient</span>
455+
<span className="text-[8px] uppercase tracking-[0.2em] font-bold bg-black/40 backdrop-blur-md px-2 py-1 rounded-md text-white/90 border border-white/10">Doctor</span>
456+
</div>
457+
458+
<div className="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent pointer-events-none" />
459+
460+
{/* Fullscreen indicator on hover */}
461+
<div className="absolute inset-x-0 bottom-4 flex justify-center opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none">
462+
<span className="text-[10px] uppercase tracking-widest font-bold bg-primary/80 backdrop-blur-sm px-3 py-1.5 rounded-full text-white shadow-lg">Click to Fullscreen</span>
463+
</div>
464+
</div>
465+
<div className="p-8 text-center">
466+
<h3 className="text-xl font-heading font-bold">{feature.title}</h3>
467+
</div>
468+
</motion.div>
469+
))}
470+
</div>
471+
</section>
472+
365473
{/* Testimonial */}
366474
<motion.section
367475
initial={{ opacity: 0 }}

0 commit comments

Comments
 (0)