// ============================================================ // SECTION LAB — White rounded card slides in from below. // 3 compound boxes (flavonoid, polifenol, alkaloid). // Below: Download lab-result button + parallax field of // sachet + test-tube illustrations (uniform speed, random heights). // ============================================================ function CompoundIcon({ name }) { // Stylized molecular icons per compound. if (name === 'flavonoid') { return ( ); } if (name === 'polifenol') { return ( ); } // alkaloid return ( ); } // SVG sachet icon — small version for parallax field function MiniSachet({ color = '#E85D1A' }) { return ( Yojea ); } // Test tube icon function TestTube({ fill = '#E85D1A' }) { return ( {/* Liquid */} {/* Bubbles */} {/* Top rim highlight */} ); } // ============================================================ // LabImageStack — stack of 5 lab certificate pages that slide in // from the right (one-by-one with stagger when the section enters // the viewport), then auto-rotate which one is "on top". Clicking // the stack opens the full PDF in a new tab. // ============================================================ function LabImageStack() { const wrapRef = React.useRef(null); const [entered, setEntered] = React.useState(false); const [top, setTop] = React.useState(0); const IMAGES = [ 'assets/lab-1.webp', 'assets/lab-2.webp', 'assets/lab-3.webp', 'assets/lab-4.webp', 'assets/lab-5.webp', ]; // Trigger slide-in when section enters viewport React.useEffect(() => { if (!wrapRef.current) return; const io = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) setEntered(true); }); }, { threshold: 0.18 }); io.observe(wrapRef.current); return () => io.disconnect(); }, []); // Auto-rotate which page is on top React.useEffect(() => { if (!entered) return; const id = setInterval(() => setTop(t => (t + 1) % IMAGES.length), 3200); return () => clearInterval(id); }, [entered]); // Manual cycle on click — opens the full PDF on the topmost click const handleClick = () => { window.open( 'https://drive.google.com/file/d/1yXF9ZxzD2h1y6FrcyWortXIfaAwFodcN/view', '_blank', 'noopener,noreferrer' ); }; return (
{IMAGES.map((src, i) => { // Distance from "top" position (0 = on top, larger = further back) const dist = (i - top + IMAGES.length) % IMAGES.length; const offsetX = dist * 14; // px shift to the right const offsetY = dist * -10; // px shift up const rot = (i % 2 === 0 ? -1 : 1) * (2 + dist * 1.2); const scale = 1 - dist * 0.04; const opacity = dist === 0 ? 1 : Math.max(0.35, 1 - dist * 0.18); const zIndex = IMAGES.length - dist; // Entrance: start far to the right, slide into stacked pose with stagger const enterX = entered ? offsetX : 480 + i * 60; const enterRot = entered ? rot : rot + 18; const enterOpacity = entered ? opacity : 0; return (
{'Hasil Page {i + 1}/5
); })}
Buka PDF lengkap
); } function SectionLab() { const sectionRef = React.useRef(null); const [scrollY, setScrollY] = React.useState(0); const [intro, setIntro] = React.useState(0); React.useEffect(() => { let raf = 0; const onScroll = () => { if (!sectionRef.current) return; const rect = sectionRef.current.getBoundingClientRect(); // Slide-in intro: 0 when top below viewport, 1 when top reaches 50% viewport. const introT = Math.max(0, Math.min(1, 1 - rect.top / (window.innerHeight * 0.6))); cancelAnimationFrame(raf); raf = requestAnimationFrame(() => { setIntro(introT); setScrollY(window.scrollY); }); }; window.addEventListener('scroll', onScroll, { passive: true }); onScroll(); return () => { window.removeEventListener('scroll', onScroll); cancelAnimationFrame(raf); }; }, []); const COMPOUNDS = [ { key: 'flavonoid', name: 'Flavonoid', tag: 'Senyawa Aktif 01', text: 'Senyawa yang memiliki sifat antioksidan dan antiinflamasi.', }, { key: 'polifenol', name: 'Polifenol', tag: 'Senyawa Aktif 02', text: 'Senyawa dengan aktivitas antibakteri dan antijamur.', }, { key: 'alkaloid', name: 'Alkaloid', tag: 'Senyawa Aktif 03', text: 'Senyawa yang dikenal memiliki sifat analgesik dan antispasmodik alami.', }, ]; // Parallax field: 12 items distributed across the width at random heights. // Uniform vertical speed driven by scrollY, random base offset. const FIELD = React.useMemo(() => { const items = []; const n = 14; for (let i = 0; i < n; i++) { const isTube = i % 3 === 0; items.push({ kind: isTube ? 'tube' : 'sachet', leftPct: (i + 0.5) * (100 / n) + (Math.random() * 4 - 2), baseY: Math.random() * 80 - 40, // random base vertical offset (px) scale: isTube ? 0.85 + Math.random() * 0.3 : 0.7 + Math.random() * 0.5, rot: (Math.random() * 16 - 8), speed: 0.30 + Math.random() * 0.08, // ~uniform with tiny variation so it doesn't look canned color: ['#E85D1A', '#C84A14', '#1F1612', '#6A7A5C'][i % 4], }); } return items; }, []); const slideUp = (1 - intro) * 120; // px slide-in return (
{/* Rising white bubbles — fizz that seamlessly bubbles upward as you scroll into the lab section. Sits behind the card; clipped by .sl overflow so they appear contained within the section bounds. */}
Lab Tested · 2025

Kandungan zat aktif
dalam Yojea
sudah teruji lab!

Berdasarkan hasil uji laboratorium, Yojea mengandung senyawa aktif berupa flavonoid, alkaloid, dan polifenol. Senyawa-senyawa ini secara umum dikenal terdapat pada bahan alami dan sering dikaitkan dengan pemeliharaan kesehatan, termasuk dalam membantu mengurangi ketidaknyamanan yang berkaitan dengan menstruasi.

{/* Lab result image carousel — slides in from the right. 5 certificate pages auto-rotate; clicking opens the full PDF. Replaces the prior 3D test tube. */}
{COMPOUNDS.map((c, i) => (
{c.tag}

{c.name}

{c.text}

))}
{/* Download button */}
Download Hasil Uji Lab PDF · SIG · 2025
{/* Parallax field of sachets & test tubes */}
); } Object.assign(window, { SectionLab });