490 lines
25 KiB
PHP
490 lines
25 KiB
PHP
@extends('layouts.app')
|
|
|
|
@push('styles')
|
|
<link rel="stylesheet" href="{{ asset('css/utama.css') }}">
|
|
@endpush
|
|
|
|
@section('content')
|
|
|
|
{{-- ════════════════════════════════
|
|
HERO
|
|
════════════════════════════════ --}}
|
|
<section id="home" class="hero-section">
|
|
<div class="container">
|
|
<div class="row align-items-center">
|
|
<div class="col-md-6 reveal">
|
|
<h1 class="hero-title">
|
|
Selamat Datang di<br>
|
|
<span>Sistem Prediksi Penyakit Akibat Nyeri Ulu Hati</span>
|
|
</h1>
|
|
<p class="hero-desc">
|
|
Sistem ini menganalisis gejala dan gaya hidup untuk memberikan gambaran risiko penyakit seperti Dispepsia, Gerd, dan Gastritis.
|
|
</p>
|
|
<div class="d-flex flex-wrap gap-3">
|
|
<a href="{{ route('halaman.prediksi') }}" class="btn-hero-primary">
|
|
Mulai Prediksi Sekarang
|
|
<i class="fa-solid fa-arrow-right fa-sm"></i>
|
|
</a>
|
|
<a href="#tentang" class="btn-hero-outline">
|
|
Pelajari Tentang Sistem
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6 mt-5 mt-md-0 reveal reveal-delay-2">
|
|
<div class="hero-img-wrap">
|
|
<img src="{{ asset('img/lambung2.png') }}" alt="Ilustrasi Lambung" class="hero-img">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{{-- ════════════════════════════════
|
|
FEATURE CARDS
|
|
════════════════════════════════ --}}
|
|
<section class="features-section">
|
|
<div class="container">
|
|
<div class="row g-4">
|
|
<div class="col-md-6 reveal reveal-delay-1">
|
|
<div class="feature-card">
|
|
<div class="feature-icon">
|
|
<i class="fa-solid fa-chart-line"></i>
|
|
</div>
|
|
<h4>Akurasi Prediksi Tinggi</h4>
|
|
<p>Menggunakan metode Decision Tree untuk menghasilkan prediksi yang akurat berdasarkan data klinis yang diinput.</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6 reveal reveal-delay-2">
|
|
<div class="feature-card">
|
|
<div class="feature-icon">
|
|
<i class="fa-solid fa-shield-halved"></i>
|
|
</div>
|
|
<h4>Privasi Terjamin</h4>
|
|
<p>Data tidak disimpan atau dibagikan kepada pihak lain. Keamanan informasi kesehatan Anda adalah prioritas kami.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{{-- ════════════════════════════════
|
|
TENTANG
|
|
════════════════════════════════ --}}
|
|
<section id="tentang" class="tentang-section">
|
|
<div class="container">
|
|
|
|
{{-- Header --}}
|
|
<div class="st-header reveal">
|
|
<h2 class="st-title">Cara Kerja Sistem</h2>
|
|
<p class="st-subtitle">
|
|
Melalui kuesioner sederhana, sistem akan menganalisis gejala dan gaya hidup dan memprosesnya dengan metode Decision Tree untuk menampilkan hasil prediksi risiko penyakit.
|
|
</p>
|
|
</div>
|
|
|
|
{{-- Split Steps --}}
|
|
<div style="position: relative;">
|
|
|
|
{{-- SVG garis timeline --}}
|
|
<svg id="timelineSvg" style="position:absolute;left:50%;transform:translateX(-50%);top:0;width:60px;pointer-events:none;z-index:0;" viewBox="0 0 60 640" preserveAspectRatio="none" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M30 20 C50 100, 10 200, 30 300 C50 400, 10 500, 30 580 C40 610, 25 625, 30 640" stroke="#c8dfc3" stroke-width="1.5" stroke-linecap="round" fill="none"/>
|
|
<path id="timelineProgress" d="M30 20 C50 100, 10 200, 30 300 C50 400, 10 500, 30 580 C40 610, 25 625, 30 640" stroke="#2D5A3D" stroke-width="2.5" stroke-linecap="round" fill="none"/>
|
|
</svg>
|
|
|
|
<div class="st-steps" id="stSteps">
|
|
|
|
{{-- Langkah 01: ilustrasi kiri, card kanan --}}
|
|
<div class="st-step reveal reveal-delay-1">
|
|
<div class="st-step-left">
|
|
<div class="st-illus">
|
|
<svg viewBox="0 0 200 140" xmlns="http://www.w3.org/2000/svg">
|
|
<rect x="30" y="15" width="140" height="110" rx="12" fill="#e7f1e4" stroke="#7DAA6E" stroke-width="1"/>
|
|
<circle cx="100" cy="44" r="16" fill="#4F7C59" opacity=".2"/>
|
|
<circle cx="100" cy="44" r="10" fill="#2D5A3D"/>
|
|
<rect x="50" y="70" width="40" height="6" rx="3" fill="#7DAA6E" opacity=".5"/>
|
|
<rect x="96" y="70" width="60" height="6" rx="3" fill="#7DAA6E"/>
|
|
<rect x="50" y="84" width="40" height="6" rx="3" fill="#7DAA6E" opacity=".5"/>
|
|
<rect x="96" y="84" width="50" height="6" rx="3" fill="#7DAA6E" opacity=".7"/>
|
|
<rect x="50" y="98" width="40" height="6" rx="3" fill="#7DAA6E" opacity=".5"/>
|
|
<rect x="96" y="98" width="55" height="6" rx="3" fill="#7DAA6E" opacity=".6"/>
|
|
<line x1="90" y1="68" x2="90" y2="108" stroke="#7DAA6E" stroke-width="0.5" opacity=".4"/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<div class="st-step-center">
|
|
<div class="st-node" id="stNode0">
|
|
<div class="st-node-inner">👤</div>
|
|
</div>
|
|
</div>
|
|
<div class="st-step-right">
|
|
<div class="st-card" id="stCard0">
|
|
<p class="st-card-num">Langkah 01</p>
|
|
<p class="st-card-title">Isi data diri</p>
|
|
<p class="st-card-desc">Masukkan informasi dasar seperti nama, usia, dan jenis kelamin sebagai identitas sebelum memulai pemeriksaan.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Langkah 02: ilustrasi kiri, card kanan --}}
|
|
{{-- (CSS nth-child(even) akan flip tampilannya: card ke kiri, ilustrasi ke kanan) --}}
|
|
<div class="st-step reveal reveal-delay-2">
|
|
<div class="st-step-left">
|
|
<div class="st-illus">
|
|
<svg viewBox="0 0 200 140" xmlns="http://www.w3.org/2000/svg">
|
|
<rect x="30" y="15" width="140" height="110" rx="12" fill="#e7f1e4" stroke="#7DAA6E" stroke-width="1"/>
|
|
<circle cx="50" cy="38" r="6" fill="#2D5A3D"/>
|
|
<text x="50" y="41" text-anchor="middle" font-size="7" fill="#e7f1e4" font-weight="700" font-family="Plus Jakarta Sans, sans-serif">✓</text>
|
|
<rect x="62" y="34" width="90" height="7" rx="3" fill="#7DAA6E"/>
|
|
<circle cx="50" cy="58" r="6" fill="#2D5A3D"/>
|
|
<text x="50" y="61" text-anchor="middle" font-size="7" fill="#e7f1e4" font-weight="700" font-family="Plus Jakarta Sans, sans-serif">✓</text>
|
|
<rect x="62" y="54" width="75" height="7" rx="3" fill="#7DAA6E" opacity=".8"/>
|
|
<circle cx="50" cy="78" r="6" fill="#4F7C59" opacity=".4"/>
|
|
<rect x="62" y="74" width="85" height="7" rx="3" fill="#7DAA6E" opacity=".5"/>
|
|
<circle cx="50" cy="98" r="6" fill="#4F7C59" opacity=".3"/>
|
|
<rect x="62" y="94" width="65" height="7" rx="3" fill="#7DAA6E" opacity=".4"/>
|
|
<rect x="50" y="112" width="100" height="5" rx="2.5" fill="#c8dfc3"/>
|
|
<rect x="50" y="112" width="55" height="5" rx="2.5" fill="#2D5A3D"/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<div class="st-step-center">
|
|
<div class="st-node" id="stNode1">
|
|
<div class="st-node-inner">📋</div>
|
|
</div>
|
|
</div>
|
|
<div class="st-step-right">
|
|
<div class="st-card" id="stCard1">
|
|
<p class="st-card-num">Langkah 02</p>
|
|
<p class="st-card-title">Isi kuesioner gejala & gaya hidup</p>
|
|
<p class="st-card-desc">Jawab pertanyaan seputar gejala yang dirasakan serta kebiasaan gaya hidup Anda seperti stres, kebiasaan merokok, konsumsi alkohol, dan penggunaan obat anti inflamasi</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Langkah 03: ilustrasi kiri, card kanan --}}
|
|
<div class="st-step reveal reveal-delay-1">
|
|
<div class="st-step-left">
|
|
<div class="st-illus">
|
|
<svg viewBox="0 0 200 150" xmlns="http://www.w3.org/2000/svg">
|
|
<rect x="80" y="10" width="40" height="18" rx="9" fill="#e7f1e4" stroke="#7DAA6E" stroke-width="1"/>
|
|
<text x="100" y="21" text-anchor="middle" font-size="8" fill="#2D5A3D" font-weight="600" font-family="Plus Jakarta Sans, sans-serif">Nyeri?</text>
|
|
<line x1="100" y1="28" x2="65" y2="50" stroke="#7DAA6E" stroke-width="1.5"/>
|
|
<line x1="100" y1="28" x2="135" y2="50" stroke="#7DAA6E" stroke-width="1.5"/>
|
|
<rect x="38" y="50" width="54" height="18" rx="9" fill="#e7f1e4" stroke="#7DAA6E" stroke-width="1"/>
|
|
<text x="65" y="61" text-anchor="middle" font-size="7" fill="#2D5A3D" font-weight="500" font-family="Plus Jakarta Sans, sans-serif">Heartburn?</text>
|
|
<rect x="108" y="50" width="54" height="18" rx="9" fill="#e7f1e4" stroke="#7DAA6E" stroke-width="1"/>
|
|
<text x="135" y="61" text-anchor="middle" font-size="7" fill="#2D5A3D" font-weight="500" font-family="Plus Jakarta Sans, sans-serif">Obat?</text>
|
|
<text x="45" y="82" text-anchor="middle" font-size="6" fill="#4F7C59" font-family="Plus Jakarta Sans, sans-serif">Tidak</text>
|
|
<text x="86" y="82" text-anchor="middle" font-size="6" fill="#4F7C59" font-family="Plus Jakarta Sans, sans-serif">Ya</text>
|
|
<text x="114" y="82" text-anchor="middle" font-size="6" fill="#4F7C59" font-family="Plus Jakarta Sans, sans-serif">Tidak</text>
|
|
<text x="156" y="82" text-anchor="middle" font-size="6" fill="#4F7C59" font-family="Plus Jakarta Sans, sans-serif">Ya</text>
|
|
<line x1="52" y1="68" x2="36" y2="100" stroke="#7DAA6E" stroke-width="1.5"/>
|
|
<line x1="78" y1="68" x2="100" y2="100" stroke="#7DAA6E" stroke-width="1.5"/>
|
|
<line x1="122" y1="68" x2="100" y2="100" stroke="#7DAA6E" stroke-width="1.5"/>
|
|
<line x1="148" y1="68" x2="164" y2="100" stroke="#7DAA6E" stroke-width="1.5"/>
|
|
<rect x="10" y="100" width="52" height="16" rx="8" fill="#2D5A3D"/>
|
|
<text x="36" y="110" text-anchor="middle" font-size="7" fill="#e7f1e4" font-weight="600" font-family="Plus Jakarta Sans, sans-serif">Dispepsia</text>
|
|
<rect x="74" y="100" width="52" height="16" rx="8" fill="#4F7C59"/>
|
|
<text x="100" y="110" text-anchor="middle" font-size="7" fill="#e7f1e4" font-weight="600" font-family="Plus Jakarta Sans, sans-serif">GERD</text>
|
|
<rect x="138" y="100" width="52" height="16" rx="8" fill="#2D5A3D"/>
|
|
<text x="164" y="110" text-anchor="middle" font-size="7" fill="#e7f1e4" font-weight="600" font-family="Plus Jakarta Sans, sans-serif">Gastritis</text>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<div class="st-step-center">
|
|
<div class="st-node" id="stNode2">
|
|
<div class="st-node-inner">🌳</div>
|
|
</div>
|
|
</div>
|
|
<div class="st-step-right">
|
|
<div class="st-card" id="stCard2">
|
|
<p class="st-card-num">Langkah 03</p>
|
|
<p class="st-card-title">Analisis Decision Tree</p>
|
|
<p class="st-card-desc">Data yang dimasukkan diolah secara otomatis oleh algoritma pohon keputusan untuk menemukan pola yang paling sesuai.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Langkah 04: ilustrasi kiri, card kanan --}}
|
|
{{-- (CSS nth-child(even) akan flip tampilannya: card ke kiri, ilustrasi ke kanan) --}}
|
|
<div class="st-step reveal reveal-delay-2">
|
|
<div class="st-step-left">
|
|
<div class="st-illus">
|
|
<svg viewBox="0 0 220 140" xmlns="http://www.w3.org/2000/svg">
|
|
<rect x="20" y="15" width="180" height="110" rx="12" fill="#e7f1e4" stroke="#7DAA6E" stroke-width="1"/>
|
|
<text x="110" y="34" text-anchor="middle" font-size="7" fill="#4F7C59" font-weight="600" font-family="Plus Jakarta Sans, sans-serif">Hasil Prediksi</text>
|
|
<rect x="36" y="40" width="148" height="24" rx="8" fill="#2D5A3D"/>
|
|
<text x="110" y="55" text-anchor="middle" font-size="9" fill="#e7f1e4" font-weight="700" font-family="Plus Jakarta Sans, sans-serif">Kemungkinan Risiko: GERD</text>
|
|
<line x1="36" y1="74" x2="184" y2="74" stroke="#7DAA6E" stroke-width="0.5" opacity=".5"/>
|
|
<text x="36" y="86" font-size="7" fill="#2D5A3D" font-family="Plus Jakarta Sans, sans-serif">Hindari merokok</text>
|
|
<text x="36" y="100" font-size="7" fill="#2D5A3D" font-family="Plus Jakarta Sans, sans-serif">Kurangi makanan asam</text>
|
|
<text x="36" y="114" font-size="7" fill="#2D5A3D" font-family="Plus Jakarta Sans, sans-serif">Jaga pola makan teratur</text>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<div class="st-step-center">
|
|
<div class="st-node" id="stNode3">
|
|
<div class="st-node-inner">📊</div>
|
|
</div>
|
|
</div>
|
|
<div class="st-step-right">
|
|
<div class="st-card" id="stCard3">
|
|
<p class="st-card-num">Langkah 04</p>
|
|
<p class="st-card-title">Hasil prediksi</p>
|
|
<p class="st-card-desc">Sistem menampilkan kemungkinan risiko jenis penyakit sebagai gambaran awal kondisi kesehatan Anda.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Disclaimer --}}
|
|
<div class="st-disclaimer reveal">
|
|
<div class="st-disclaimer-icon">
|
|
<svg viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M5 2v3M5 7v.5" stroke="#fff" stroke-width="1.5" stroke-linecap="round"/>
|
|
</svg>
|
|
</div>
|
|
<p class="st-disclaimer-text">
|
|
Hasil sistem ini <strong>bukan diagnosis medis</strong>. Informasi yang diberikan hanya sebagai gambaran awal agar pengguna lebih waspada terhadap kondisi kesehatannya.
|
|
</p>
|
|
</div>
|
|
|
|
</div>
|
|
</section>
|
|
|
|
{{-- ════════════════════════════════
|
|
GEJALA
|
|
════════════════════════════════ --}}
|
|
<section id="gejala" class="gejala-section">
|
|
<div class="container">
|
|
<div class="text-center reveal">
|
|
<h2 class="section-title">Kenali Gejala</h2>
|
|
<div class="section-divider"></div>
|
|
</div>
|
|
<div class="row align-items-center">
|
|
<div class="col-md-4 text-center mb-4 mb-md-0 reveal reveal-delay-1">
|
|
<img src="{{ asset('img/kartun-sakit.png') }}" alt="Ilustrasi Gejala" class="gejala-img img-fluid">
|
|
</div>
|
|
<div class="col-md-8">
|
|
<div class="row g-3">
|
|
@php
|
|
$gejalas = [
|
|
['no' => '01', 'title' => 'Nyeri Ulu Hati', 'desc' => 'Rasa perih atau tidak nyaman di bagian tengah atas perut (ulu hati).'],
|
|
['no' => '02', 'title' => 'Kembung', 'desc' => 'Perut terasa penuh atau bengah akibat penumpukan gas di saluran pencernaan.'],
|
|
['no' => '03', 'title' => 'Penurunan Berat Badan', 'desc' => 'Berkurangnya berat badan secara tidak sengaja dalam jangka waktu tertentu.'],
|
|
['no' => '04', 'title' => 'Nafsu Makan Menurun', 'desc' => 'Kurangnya keinginan untuk makan atau tidak seperti biasanya.'],
|
|
['no' => '05', 'title' => 'Heartburn', 'desc' => 'Rasa terbakar di dada akibat asam lambung naik ke kerongkongan (refluks asam).'],
|
|
['no' => '06', 'title' => 'BAB Berdarah', 'desc' => 'Buang air besar yang disertai darah, bisa berwarna merah segar atau kehitaman.'],
|
|
];
|
|
@endphp
|
|
@foreach($gejalas as $i => $item)
|
|
<div class="col-md-4 reveal reveal-delay-{{ ($i % 3) + 1 }}">
|
|
<div class="gejala-card">
|
|
<div class="gejala-number">{{ $item['no'] }}</div>
|
|
<h6>{{ $item['title'] }}</h6>
|
|
<p>{{ $item['desc'] }}</p>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{{-- ════════════════════════════════
|
|
CTA
|
|
════════════════════════════════ --}}
|
|
<section class="cta-section">
|
|
<div class="container">
|
|
<div class="cta-box reveal" id="ctaBox">
|
|
|
|
<div class="cta-badge">
|
|
<i class="fa-solid fa-shield-heart fa-xs"></i>
|
|
Gratis & Tanpa Instalasi
|
|
</div>
|
|
|
|
<h2 class="cta-title">Pantau Kondisi Lambungmu,<br>Jangan Cuma Sekali.</h2>
|
|
|
|
<div class="cta-trust">
|
|
<div class="cta-trust-item">
|
|
<i class="fa-solid fa-circle-check"></i>
|
|
<span>Riwayat prediksi tersimpan otomatis</span>
|
|
</div>
|
|
<div class="cta-trust-item">
|
|
<i class="fa-solid fa-circle-check"></i>
|
|
<span>Pantau kondisi lambungmu dari waktu ke waktu</span>
|
|
</div>
|
|
<div class="cta-trust-item">
|
|
<i class="fa-solid fa-circle-check"></i>
|
|
<span>Kapan saja bisa cek ulang hasil sebelumnya</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="cta-actions">
|
|
@if(Auth::check())
|
|
<a href="{{ route('halaman.prediksi') }}" class="btn-cta">
|
|
Mulai Prediksi Sekarang
|
|
<i class="fa-solid fa-arrow-right fa-sm"></i>
|
|
</a>
|
|
@else
|
|
<a href="{{ route('login') }}" class="btn-cta">
|
|
Login & Mulai Prediksi
|
|
<i class="fa-solid fa-arrow-right fa-sm"></i>
|
|
</a>
|
|
@endif
|
|
</div>
|
|
|
|
@if(!Auth::check())
|
|
<p class="cta-note">
|
|
Belum punya akun? <a href="{{ route('register') }}">Daftar sekarang</a>
|
|
</p>
|
|
@endif
|
|
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
@push('scripts')
|
|
<script>
|
|
// Scroll reveal
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
entry.target.classList.add('visible');
|
|
}
|
|
});
|
|
}, { threshold: 0.12 });
|
|
|
|
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
|
|
|
|
// Restart animasi saat section tentang masuk viewport
|
|
const tentangSection = document.querySelector('#tentang');
|
|
const animasiFrame = document.querySelector('iframe[src*="sehati-animation"]');
|
|
|
|
const animasiObserver = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
animasiFrame.src = animasiFrame.src;
|
|
}
|
|
});
|
|
}, { threshold: 0.3 });
|
|
|
|
if (tentangSection && animasiFrame) {
|
|
animasiObserver.observe(tentangSection);
|
|
}
|
|
|
|
// Restart animasi saat klik menu "Tentang" di navbar
|
|
document.querySelectorAll('a[href="#tentang"], a[href="/#tentang"]').forEach(link => {
|
|
link.addEventListener('click', () => {
|
|
setTimeout(() => {
|
|
if (animasiFrame) animasiFrame.src = animasiFrame.src;
|
|
}, 600);
|
|
});
|
|
});
|
|
|
|
// Bubble CTA
|
|
const ctaBox = document.getElementById('ctaBox');
|
|
const bubbles = [];
|
|
|
|
function rand(min, max) { return Math.random() * (max - min) + min; }
|
|
|
|
function createBubble() {
|
|
const el = document.createElement('div');
|
|
const size = rand(8, 22);
|
|
el.style.cssText = `
|
|
position: absolute;
|
|
border-radius: 50%;
|
|
background: rgba(255,255,255,0.08);
|
|
pointer-events: none;
|
|
width: ${size}px;
|
|
height: ${size}px;
|
|
`;
|
|
ctaBox.appendChild(el);
|
|
bubbles.push({
|
|
el, size,
|
|
x: rand(0, ctaBox.offsetWidth),
|
|
y: rand(0, ctaBox.offsetHeight),
|
|
vx: rand(-0.35, 0.35),
|
|
vy: rand(-0.35, 0.35),
|
|
opacity: 0, life: 0,
|
|
maxLife: rand(220, 420),
|
|
});
|
|
}
|
|
|
|
for (let i = 0; i < 12; i++) createBubble();
|
|
|
|
function tick() {
|
|
const W = ctaBox.offsetWidth;
|
|
const H = ctaBox.offsetHeight;
|
|
for (let i = bubbles.length - 1; i >= 0; i--) {
|
|
const b = bubbles[i];
|
|
b.life++;
|
|
b.x += b.vx;
|
|
b.y += b.vy;
|
|
|
|
if (b.life < 40) b.opacity = b.life / 40;
|
|
else if (b.life > b.maxLife - 40) b.opacity = (b.maxLife - b.life) / 40;
|
|
else b.opacity = 1;
|
|
|
|
b.el.style.left = b.x + 'px';
|
|
b.el.style.top = b.y + 'px';
|
|
b.el.style.opacity = b.opacity * 0.7;
|
|
b.el.style.transform = 'translate(-50%, -50%)';
|
|
|
|
if (b.x < 0 || b.x > W) b.vx *= -1;
|
|
if (b.y < 0 || b.y > H) b.vy *= -1;
|
|
|
|
if (b.life >= b.maxLife) {
|
|
b.el.remove();
|
|
bubbles.splice(i, 1);
|
|
createBubble();
|
|
}
|
|
}
|
|
requestAnimationFrame(tick);
|
|
}
|
|
|
|
tick();
|
|
|
|
// Timeline draw-on-scroll
|
|
const timelineProgress = document.getElementById('timelineProgress');
|
|
const stSteps = document.getElementById('stSteps');
|
|
const timelineSvg = document.getElementById('timelineSvg');
|
|
|
|
if (timelineProgress && stSteps) {
|
|
const totalLen = timelineProgress.getTotalLength();
|
|
timelineProgress.style.strokeDasharray = totalLen;
|
|
timelineProgress.style.strokeDashoffset = totalLen;
|
|
|
|
const stNodes = [0,1,2,3].map(i => document.getElementById('stNode'+i));
|
|
const stCards = [0,1,2,3].map(i => document.getElementById('stCard'+i));
|
|
|
|
function resizeTimeline() {
|
|
if (timelineSvg) timelineSvg.style.height = stSteps.offsetHeight + 'px';
|
|
}
|
|
|
|
function updateTimeline() {
|
|
const rect = stSteps.getBoundingClientRect();
|
|
const progress = Math.min(1, Math.max(0, (-rect.top + window.innerHeight * 0.6) / stSteps.offsetHeight));
|
|
|
|
timelineProgress.style.strokeDashoffset = totalLen * (1 - progress);
|
|
|
|
stNodes.forEach((node, i) => {
|
|
if (!node) return;
|
|
const active = progress >= (i / 4) + 0.08;
|
|
node.classList.toggle('st-active', active);
|
|
if (stCards[i]) stCards[i].classList.toggle('st-active', active);
|
|
});
|
|
}
|
|
|
|
window.addEventListener('scroll', updateTimeline, { passive: true });
|
|
window.addEventListener('resize', () => { resizeTimeline(); updateTimeline(); });
|
|
resizeTimeline();
|
|
updateTimeline();
|
|
}
|
|
</script>
|
|
@endpush
|
|
|
|
@endsection
|