webdlh-net/Views/Components/Home/_Website.cshtml

726 lines
25 KiB
Plaintext

<div class="relative py-16 md:py-32 bg-gradient-to-b from-slate-50 to-slate-100 overflow-hidden">
<!-- Background subtle design elements -->
<div class="absolute top-0 left-0 w-full h-full overflow-hidden">
<div class="absolute top-0 left-0 w-full h-full bg-grid-pattern opacity-5"></div>
<div class="absolute top-10 left-10 w-32 h-32 bg-blue-500 rounded-full filter blur-[100px] opacity-20"></div>
<div class="absolute bottom-10 right-10 w-32 h-32 bg-purple-500 rounded-full filter blur-[100px] opacity-20"></div>
<div id="particle-container" class="absolute inset-0"></div>
</div>
<div class="container mx-auto px-4 max-w-7xl relative z-10">
<!-- Heading Section with animated underline -->
<div class="text-center mb-20">
<div class="inline-block relative">
<h2 class="text-2xl md:text-3xl font-bold text-gray-800">
Layanan Digital
</h2>
@* <div class="heading-underline"></div> *@
</div>
<p class="max-w-2xl mx-auto text-lg md:text-xl leading-relaxed text-gray-600 mt-6">
Solusi digital inovatif dari DLH DKI Jakarta untuk Jakarta yang lebih bersih,
hijau, dan berkelanjutan.
</p>
</div>
<!-- 3D Website Showcase -->
<div id="websites-showcase" class="relative">
<!-- Laptop mockup container -->
<div class="laptop-viewport relative max-w-5xl mx-auto h-[450px] md:h-[600px]">
<div class="laptop-container w-full h-full relative transform-gpu perspective">
<!-- Website slides will be created by JavaScript within this laptop mockup -->
</div>
<!-- Floating UI elements -->
@* <div class="floating-ui-element device-metrics absolute top-0 left-0 md:left-10 p-4 bg-white/10 backdrop-blur-lg rounded-lg border border-white/30 shadow-xl transform-gpu -translate-y-1/2 opacity-0">
<div class="flex items-center gap-2">
<span class="w-3 h-3 rounded-full bg-red-500"></span>
<div>
<span class="text-xs font-mono text-gray-700 block">Resolution</span>
<span class="text-sm font-bold text-gray-900">1920 x 1080</span>
</div>
</div>
</div> *@
<div class="floating-ui-element website-info absolute top-10 right-0 md:right-10 p-4 bg-white/10 backdrop-blur-lg rounded-lg border border-white/30 shadow-xl transform-gpu translate-y-1/2 opacity-0">
<h3 class="text-lg font-bold text-gray-900" id="current-website-title">Sistem Ketaatan Lingkungan</h3>
<div class="flex items-center mt-2">
<div class="flex items-center bg-gray-100 rounded-l-md px-3 py-2">
<span class="text-gray-500">https://</span>
</div>
<input type="text" id="urlDisplay" value="wasdal.jakarta.go.id" class="bg-white py-2 px-3 border-y border-r border-gray-200 rounded-r-md text-gray-800 text-sm flex-1 font-medium focus:outline-none" readonly>
</div>
<div class="mt-2 flex justify-end">
<a href="#" id="visitWebsite" target="_blank" class="visit-btn inline-flex items-center gap-1 px-3 py-1 rounded-md text-white text-sm font-medium">
<span>Kunjungi</span>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
</svg>
</a>
</div>
</div>
</div>
<!-- Custom navigation -->
<div class="website-nav flex items-center justify-center">
<button id="prev-website" class="nav-btn flex items-center justify-center w-12 h-12 rounded-full bg-white/80 backdrop-blur-sm shadow-lg hover:bg-white transition-all duration-300 focus:outline-none">
<svg class="w-5 h-5 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
</svg>
</button>
<div class="website-progress relative h-1 bg-gray-200 rounded-full mx-6 overflow-hidden w-1/3 max-w-xs">
<div class="absolute top-0 left-0 h-full bg-gradient-to-r from-green-500 to-green-600 rounded-full progress-bar" style="width: 0%"></div>
</div>
<div id="website-indicators" class="hidden md:flex justify-center space-x-3 mx-6">
<!-- Indicators will be dynamically populated -->
</div>
<button id="next-website" class="nav-btn flex items-center justify-center w-12 h-12 rounded-full bg-white/80 backdrop-blur-sm shadow-lg hover:bg-white transition-all duration-300 focus:outline-none">
<svg class="w-5 h-5 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
</button>
</div>
</div>
<!-- Visual tech elements -->
@* <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-12 max-w-4xl mx-auto">
<div class="tech-feature bg-white rounded-xl p-4 shadow-lg transform hover:-translate-y-1 transition-all duration-300">
<div class="flex items-center gap-3">
<div class="p-2 bg-blue-50 rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-blue-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="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>
</div>
<div>
<span class="text-sm font-medium text-gray-800">Aman</span>
<span class="block text-xs text-gray-500">SSL Secured</span>
</div>
</div>
</div>
<div class="tech-feature bg-white rounded-xl p-4 shadow-lg transform hover:-translate-y-1 transition-all duration-300">
<div class="flex items-center gap-3">
<div class="p-2 bg-green-50 rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-green-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
</div>
<div>
<span class="text-sm font-medium text-gray-800">Cepat</span>
<span class="block text-xs text-gray-500">Optimized</span>
</div>
</div>
</div>
<div class="tech-feature bg-white rounded-xl p-4 shadow-lg transform hover:-translate-y-1 transition-all duration-300">
<div class="flex items-center gap-3">
<div class="p-2 bg-purple-50 rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-purple-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z" />
</svg>
</div>
<div>
<span class="text-sm font-medium text-gray-800">Responsif</span>
<span class="block text-xs text-gray-500">Mobile-friendly</span>
</div>
</div>
</div>
<div class="tech-feature bg-white rounded-xl p-4 shadow-lg transform hover:-translate-y-1 transition-all duration-300">
<div class="flex items-center gap-3">
<div class="p-2 bg-amber-50 rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-amber-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" />
</svg>
</div>
<div>
<span class="text-sm font-medium text-gray-800">Terintegrasi</span>
<span class="block text-xs text-gray-500">Connected APIs</span>
</div>
</div>
</div>
</div> *@
</div>
</div>
<register-block dynamic-section="css" key="cssWebsite">
<style>
/* Background pattern */
.bg-grid-pattern {
background-image: radial-gradient(circle, #000 1px, transparent 1px);
background-size: 30px 30px;
}
/* Animated heading underline */
.heading-underline {
position: absolute;
bottom: 0;
left: 0;
height: 4px;
width: 0;
background: linear-gradient(90deg, #3b82f6, #8b5cf6);
border-radius: 4px;
animation: underline-expand 1.5s ease-out forwards;
}
@@keyframes underline-expand {
0% { width: 0; }
100% { width: 100%; }
}
/* 3D perspective for laptop */
.perspective {
perspective: 2500px;
transform-style: preserve-3d;
}
/* Laptop mockup styles */
.laptop-mockup {
position: absolute;
width: 80%;
height: 70%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotateX(20deg);
transform-style: preserve-3d;
transition: transform 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.laptop-lid {
position: relative;
width: 100%;
height: 100%;
background: #32363e;
border-radius: 12px;
padding: 8px;
}
.laptop-screen {
position: relative;
width: 100%;
height: 100%;
background: #000;
border-radius: 4px;
overflow: hidden;
}
.laptop-keyboard {
position: absolute;
width: 110%;
height: 10px;
bottom: -15px;
left: -5%;
background: linear-gradient(to bottom, #32363e, #1a1c20);
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
transform: rotateX(-90deg);
transform-origin: top;
transform-style: preserve-3d;
box-shadow: 0 6px 20px rgba(0,0,0,0.2);
}
.laptop-keyboard::after {
content: '';
position: absolute;
width: 20%;
height: 4px;
bottom: 3px;
left: 40%;
background: #555;
border-radius: 10px;
}
.laptop-camera {
position: absolute;
top: 6px;
left: 50%;
transform: translateX(-50%);
width: 8px;
height: 8px;
border-radius: 50%;
background: #333;
z-index: 10;
}
/* Website slide styles */
.website-slide {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transform: translateZ(-500px);
transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.website-slide.active {
opacity: 1;
transform: translateZ(0);
}
.website-image {
width: 100%;
height: 100%;
object-fit: cover;
}
/* Floating UI elements */
.floating-ui-element {
transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* Visit button styling */
.visit-btn {
background-color: #f49827;
transition: all 0.3s ease;
}
.visit-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
}
/* Navigation button effects */
.nav-btn {
transition: all 0.3s ease;
}
.nav-btn:hover {
transform: scale(1.05);
}
.nav-btn:active {
transform: scale(0.95);
}
/* Progress bar animation */
.progress-bar {
transition: width 0.3s ease-in-out;
}
/* Indicator styling */
.website-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background: rgba(34, 197, 94, 0.3);
transition: all 0.3s ease;
cursor: pointer;
}
.website-indicator.active {
background: #26ac7e;
transform: scale(1.2);
}
/* Tech feature hover */
.tech-feature {
transition: all 0.3s ease;
}
/* Particle styling */
.website-particle {
position: absolute;
border-radius: 50%;
background-color: rgba(79, 70, 229, 0.2);
pointer-events: none;
}
</style>
</register-block>
<register-block dynamic-section="scripts" key="jsWebsite">
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
const asset = (file) => `${window.assetBaseUrl}images/home/${file}`;
// Website data configuration
const websites = [
{
image: asset("skl.jpg"),
url: "wasdal.jakarta.go.id",
title: "Sistem Ketaatan Lingkungan",
color: "#3b82f6"
},
{
image: asset("bps.jpg"),
url: "jaklingko.jakarta.go.id",
title: "Jakarta Lingko",
color: "#10b981"
},
{
image: asset("skl.jpg"),
url: "lingkungan.jakarta.go.id",
title: "Lingkungan Jakarta",
color: "#f59e0b"
},
{
image: asset("bps.jpg"),
url: "bpsrw.jakarta.go.id",
title: "Bank Sampah RW",
color: "#8b5cf6"
},
{
image: asset("skl.jpg"),
url: "dlhjakarta.go.id",
title: "Portal DLH Jakarta",
color: "#ef4444"
}
];
// DOM Elements
const laptopContainer = document.querySelector('.laptop-container');
const indicatorsContainer = document.getElementById('website-indicators');
const urlDisplay = document.getElementById('urlDisplay');
const websiteTitle = document.getElementById('current-website-title');
const visitBtn = document.getElementById('visitWebsite');
const prevBtn = document.getElementById('prev-website');
const nextBtn = document.getElementById('next-website');
const progressBar = document.querySelector('.progress-bar');
let currentIndex = 0;
let isAnimating = false;
// Create laptop mockup with websites inside
const laptopMockup = document.createElement('div');
laptopMockup.className = 'laptop-mockup';
laptopMockup.innerHTML = `
<div class="laptop-lid">
<div class="laptop-camera"></div>
<div class="laptop-screen">
<!-- Website slides will be added here -->
</div>
</div>
<div class="laptop-keyboard"></div>
`;
laptopContainer.appendChild(laptopMockup);
const laptopScreen = laptopMockup.querySelector('.laptop-screen');
// Create website slides
websites.forEach((site, index) => {
// Create slide
const slide = document.createElement('div');
slide.className = `website-slide ${index === 0 ? 'active' : ''}`;
slide.setAttribute('data-index', index);
slide.innerHTML = `
<img src="${site.image}" alt="${site.title}" class="website-image">
`;
laptopScreen.appendChild(slide);
// Create indicator
const indicator = document.createElement('button');
indicator.className = `website-indicator ${index === 0 ? 'active' : ''}`;
indicator.setAttribute('data-index', index);
indicator.addEventListener('click', () => {
if (!isAnimating && currentIndex !== index) {
goToSlide(index);
}
});
indicatorsContainer.appendChild(indicator);
});
const slides = document.querySelectorAll('.website-slide');
const indicators = document.querySelectorAll('.website-indicator');
// Initialize website information
updateWebsiteInfo(0);
// Create floating UI animations
const floatingElements = document.querySelectorAll('.floating-ui-element');
floatingElements.forEach((el, index) => {
// Show elements with stagger
gsap.to(el, {
opacity: 1,
y: 0,
delay: 0.5 + (index * 0.2),
duration: 1,
ease: "power3.out"
});
// Add slight floating animation
gsap.to(el, {
y: "+=10",
duration: 2,
ease: "sine.inOut",
repeat: -1,
yoyo: true,
delay: Math.random()
});
});
// Create particles
createParticles();
// Initialize 3D laptop animation
gsap.fromTo(laptopMockup,
{
rotateX: 40,
rotateY: 10,
y: 100,
opacity: 0
},
{
rotateX: 20,
rotateY: 0,
y: 0,
opacity: 1,
duration: 1.5,
ease: "power3.out",
delay: 0.3
}
);
// Laptop subtle movement based on mouse position
const websitesShowcase = document.getElementById('websites-showcase');
websitesShowcase.addEventListener('mousemove', (e) => {
const rect = websitesShowcase.getBoundingClientRect();
const mouseX = e.clientX - rect.left - (rect.width / 2);
const mouseY = e.clientY - rect.top - (rect.height / 2);
gsap.to(laptopMockup, {
rotateY: mouseX * 0.005,
rotateX: 20 - (mouseY * 0.01),
duration: 1,
ease: "power1.out"
});
});
// Reset rotation when mouse leaves
websitesShowcase.addEventListener('mouseleave', () => {
gsap.to(laptopMockup, {
rotateX: 20,
rotateY: 0,
duration: 1,
ease: "power1.out"
});
});
// Update website information
function updateWebsiteInfo(index) {
const site = websites[index];
if (!site) return;
// Update URL and title
urlDisplay.value = site.url;
websiteTitle.textContent = site.title;
visitBtn.href = `https://${site.url}`;
// Update progress bar
const progress = ((index + 1) / websites.length) * 100;
progressBar.style.width = `${progress}%`;
// Update visit button color
@* gsap.to(visitBtn, {
background: `linear-gradient(to right, ${site.color}, ${adjustBrightness(site.color, -20)})`,
duration: 0.5
}); *@
}
// Helper function to adjust brightness
function adjustBrightness(hex, percent) {
// This is a simplified version
return hex;
}
// Update slider
function goToSlide(index) {
if (isAnimating) return;
isAnimating = true;
// Get current and new slide
const currentSlide = slides[currentIndex];
const newSlide = slides[index];
// Direction for animation (left or right)
const direction = index > currentIndex ? 1 : -1;
// Update current index
currentIndex = index;
// Animate current slide out
gsap.to(currentSlide, {
opacity: 0,
z: -500 * direction,
duration: 0.8,
ease: "power2.in"
});
// Prepare new slide
gsap.set(newSlide, {
opacity: 0,
z: 500 * -direction
});
// Animate new slide in
gsap.to(newSlide, {
opacity: 1,
z: 0,
duration: 0.8,
delay: 0.2,
ease: "power2.out",
onComplete: () => {
isAnimating = false;
// Update classes
slides.forEach(slide => slide.classList.remove('active'));
newSlide.classList.add('active');
// Update indicators
indicators.forEach((indicator, i) => {
if (i === index) {
indicator.classList.add('active');
} else {
indicator.classList.remove('active');
}
});
// Update website information
updateWebsiteInfo(index);
}
});
// Animate laptop slightly based on direction
gsap.to(laptopMockup, {
rotateY: 5 * direction,
duration: 0.8,
ease: "power2.inOut",
onComplete: () => {
gsap.to(laptopMockup, {
rotateY: 0,
duration: 0.6,
ease: "power2.out"
});
}
});
}
// Navigation functions
prevBtn.addEventListener('click', () => {
if (!isAnimating) {
const prevIndex = (currentIndex - 1 + websites.length) % websites.length;
goToSlide(prevIndex);
}
});
nextBtn.addEventListener('click', () => {
if (!isAnimating) {
const nextIndex = (currentIndex + 1) % websites.length;
goToSlide(nextIndex);
}
});
// Create and animate particles
function createParticles() {
const particleContainer = document.getElementById('particle-container');
const particleCount = 20;
for (let i = 0; i < particleCount; i++) {
const particle = document.createElement('div');
particle.className = 'website-particle';
// Random size between 5px and 15px
const size = Math.random() * 10 + 5;
particle.style.width = `${size}px`;
particle.style.height = `${size}px`;
// Random position
const posX = Math.random() * 100;
const posY = Math.random() * 100;
particle.style.left = `${posX}%`;
particle.style.top = `${posY}%`;
particle.style.opacity = Math.random() * 0.5;
particleContainer.appendChild(particle);
// Animate particles with GSAP
gsap.to(particle, {
x: "random(-100, 100)",
y: "random(-100, 100)",
opacity: "random(0.1, 0.5)",
duration: "random(10, 20)",
repeat: -1,
repeatRefresh: true,
ease: "sine.inOut"
});
}
}
// Keyboard navigation
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') {
prevBtn.click();
} else if (e.key === 'ArrowRight') {
nextBtn.click();
}
});
// Touch support for mobile
let touchStartX = 0;
let touchEndX = 0;
websitesShowcase.addEventListener('touchstart', (e) => {
touchStartX = e.changedTouches[0].screenX;
});
websitesShowcase.addEventListener('touchend', (e) => {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
});
function handleSwipe() {
if (touchEndX < touchStartX - 50) {
// Swipe left
nextBtn.click();
} else if (touchEndX > touchStartX + 50) {
// Swipe right
prevBtn.click();
}
}
// Auto-rotate setup
let autoRotateInterval;
function startAutoRotate() {
autoRotateInterval = setInterval(() => {
if (!isAnimating) {
const nextIndex = (currentIndex + 1) % websites.length;
goToSlide(nextIndex);
}
}, 6000);
}
function stopAutoRotate() {
clearInterval(autoRotateInterval);
}
// Pause on hover
websitesShowcase.addEventListener('mouseenter', stopAutoRotate);
websitesShowcase.addEventListener('mouseleave', startAutoRotate);
// Start auto rotation
startAutoRotate();
// Add entrance animation for tech features
const techFeatures = document.querySelectorAll('.tech-feature');
gsap.from(techFeatures, {
y: 50,
opacity: 0,
stagger: 0.1,
duration: 0.8,
ease: "power2.out",
scrollTrigger: {
trigger: techFeatures[0],
start: "top bottom-=100px",
toggleActions: "play none none none"
}
});
});
</script>
</register-block>