clean code

main
marszayn 2025-04-23 10:38:28 +07:00
parent ba05dc4bc8
commit 019963e1ba
30 changed files with 749 additions and 615 deletions

View File

@ -0,0 +1,30 @@
.custom-blue {
color: #003296;
}
.custom-blue-bg,
.bg-custom-blue {
background-color: #003296;
}
.border-custom-blue {
border-color: #003296;
}
.faq-item {
border-left: 4px solid transparent;
transition: all 0.3s ease;
}
.faq-item:hover,
.faq-item.active {
border-left: 4px solid #003296;
}
.faq-item.active {
box-shadow: 0 10px 15px -3px rgba(0, 50, 150, 0.1);
}
@media (min-width: 768px) {
.faq-icon {
transform: scale(0.9);
transition: transform 0.3s ease;
}
.faq-item:hover .faq-icon {
transform: scale(1.1);
}
}

View File

@ -0,0 +1,13 @@
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fade-in-up {
animation: fadeInUp 0.8s ease-out forwards;
}

View File

@ -0,0 +1,169 @@
@keyframes gradient-x {
0%,
100% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
}
.animate-gradient-x {
background-size: 200% 200%;
animation: gradient-x 3s ease infinite;
}
@keyframes pulse-slow {
0%,
100% {
opacity: 0.3;
}
50% {
opacity: 0.7;
}
}
.animate-pulse-slow {
animation: pulse-slow 6s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes float {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-15px);
}
}
.animate-float {
animation: float 8s ease-in-out infinite;
}
.animate-float-slow {
animation: float 12s ease-in-out infinite;
}
.animate-float-slow-reverse {
animation: float 12s ease-in-out infinite reverse;
}
@keyframes float-text {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-5px) rotate(2deg);
}
}
.animate-float-text {
animation: float-text 2s ease-in-out infinite;
display: inline-block;
}
@keyframes subtle-rotate {
0%,
100% {
transform: rotate(-1deg);
}
50% {
transform: rotate(1deg);
}
}
.animate-subtle-rotate {
animation: subtle-rotate 12s ease-in-out infinite;
}
/* efek 3d */
.perspective {
perspective: 1000px;
}
.perspective-hero {
perspective: 2000px;
}
.perspective-card {
perspective: 1000px;
transform-style: preserve-3d;
}
.transform-3d {
transform-style: preserve-3d;
transition: transform 0.6s cubic-bezier(0.2, 0.85, 0.4, 1);
}
.glow-line {
box-shadow: 0 0 15px 2px rgba(124, 207, 0, 0.6);
animation: glow-pulse 3s ease-in-out infinite alternate;
}
@keyframes glow-pulse {
0% {
box-shadow: 0 0 10px 1px rgba(124, 207, 0, 0.5);
}
100% {
box-shadow: 0 0 25px 5px rgba(124, 207, 0, 0.8);
}
}
.ripple-effect {
position: absolute;
width: 70px;
height: 70px;
border-radius: 50%;
background: rgba(72, 127, 255, 0.4);
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
opacity: 0;
animation: ripple 2s linear infinite;
}
@keyframes ripple {
0% {
transform: translate(-50%, -50%) scale(1);
opacity: 0;
}
20% {
transform: translate(-50%, -50%) scale(1.2);
opacity: 0.6;
}
100% {
transform: translate(-50%, -50%) scale(2);
opacity: 0;
}
}
.masonry-card-wide {
grid-row: span 1;
}
@media (min-width: 1024px) {
.masonry-card:nth-child(4n + 1) {
grid-row: span 2;
}
}
#beritaContent,
#videoContent {
transition: all 0.5s cubic-bezier(0.2, 0.85, 0.4, 1);
}
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.line-clamp-3 {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.tab-glass-container {
position: relative;
z-index: 1;
}
.tab-glass-container::after {
content: "";
position: absolute;
inset: 0;
z-index: -1;
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(10px);
border-radius: inherit;
}

View File

@ -0,0 +1,6 @@
.banner-slide {
transition: opacity 0.5s ease;
}
.dot-indicator.active {
background-color: #3182ce;
}

View File

@ -0,0 +1,42 @@
document.addEventListener("DOMContentLoaded", function () {
const container = document.getElementById("marquee-container");
const content = document.getElementById("marquee-content");
// Calculate the total width needed for animation
let contentWidth = content.offsetWidth;
// Clone the content multiple times to ensure smooth looping
for (let i = 0; i < 3; i++) {
const clone = content.cloneNode(true);
container.appendChild(clone);
}
// Start animation
let scrollPosition = 0;
const speed = 0.5; // slower speed (was 1)
let isAnimating = true;
// Pause on hover
container.addEventListener("mouseenter", function () {
isAnimating = false;
});
container.addEventListener("mouseleave", function () {
isAnimating = true;
});
function scroll() {
if (isAnimating) {
scrollPosition -= speed;
// Reset when first element is completely scrolled out
if (scrollPosition <= -contentWidth) {
scrollPosition += contentWidth;
}
container.style.transform = `translateX(${scrollPosition}px)`;
}
requestAnimationFrame(scroll);
}
// Start the animation
scroll();
});

View File

@ -0,0 +1,27 @@
document.querySelectorAll(".faq-header").forEach((header) => {
header.addEventListener("click", () => {
const parent = header.parentElement;
const content = parent.querySelector(".faq-content");
const toggle = parent.querySelector(".faq-toggle svg");
document.querySelectorAll(".faq-item").forEach((item) => {
if (item !== parent && item.classList.contains("active")) {
item.classList.remove("active");
item.querySelector(".faq-content").style.maxHeight = "0";
item.querySelector(".faq-toggle svg").classList.remove(
"rotate-45"
);
}
});
parent.classList.toggle("active");
if (parent.classList.contains("active")) {
content.style.maxHeight = content.scrollHeight + "px";
toggle.classList.add("rotate-45");
} else {
content.style.maxHeight = "0";
toggle.classList.remove("rotate-45");
}
});
});

View File

@ -0,0 +1,39 @@
document.getElementById("filter-button").addEventListener("click", function () {
const filterSection = document.getElementById("filter-section");
filterSection.classList.toggle("hidden");
});
document.getElementById("clear-filter").addEventListener("click", function () {
// Reset province and city dropdowns
document.getElementById("kabkota").value = "";
document.getElementById("kecamatan").value = "";
document.getElementById("kelurahan").value = "";
// Reset search input
const searchInput = document.querySelector('input[placeholder="Search"]');
if (searchInput) searchInput.value = "";
});
function changeTab(tabName) {
const contentSections = document.querySelectorAll(".tab-content");
contentSections.forEach((section) => {
section.classList.add("hidden");
});
const tabButtons = document.querySelectorAll(".tab-btn");
tabButtons.forEach((button) => {
button.classList.remove("bg-blue-900", "text-white");
button.classList.add("bg-white", "border", "border-gray-300");
});
const selectedTab = document.getElementById("tab-" + tabName);
selectedTab.classList.remove("bg-white", "border", "border-gray-300");
selectedTab.classList.add("bg-blue-900", "text-white");
const selectedContent = document.getElementById("content-" + tabName);
selectedContent.classList.remove("hidden");
}
document.addEventListener("DOMContentLoaded", function () {
changeTab("pertek");
});

View File

@ -0,0 +1,177 @@
document.addEventListener("DOMContentLoaded", function () {
if (typeof particlesJS !== "undefined") {
particlesJS("particles-js", {
particles: {
number: {
value: 80,
density: { enable: true, value_area: 1000 },
},
color: { value: "#ffffff" },
shape: { type: "circle" },
opacity: { value: 0.1, random: true },
size: { value: 3, random: true },
line_linked: {
enable: true,
distance: 150,
color: "#ffffff",
opacity: 0.05,
width: 1,
},
move: {
enable: true,
speed: 0.5,
direction: "none",
random: true,
out_mode: "out",
bounce: false,
},
},
interactivity: {
detect_on: "canvas",
events: {
onhover: { enable: true, mode: "bubble" },
resize: true,
},
modes: {
bubble: {
distance: 200,
size: 4,
duration: 2,
opacity: 0.2,
},
},
},
retina_detect: true,
});
}
// Parallax effect image utama
initParallaxEffect();
initHoverEffects();
});
function initParallaxEffect() {
const parallaxContainers = document.querySelectorAll(".parallax-container");
parallaxContainers.forEach((container) => {
const img = container.querySelector(".parallax-img");
if (img) {
container.addEventListener("mousemove", (e) => {
const rect = container.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const xPercent = (x / rect.width - 0.5) * 2; // -1 to 1
const yPercent = (y / rect.height - 0.5) * 2; // -1 to 1
img.style.transform = `translate(${xPercent * -10}px, ${
yPercent * -10
}px) scale(1.1)`;
});
container.addEventListener("mouseleave", () => {
img.style.transform = "translate(0, 0) scale(1.05)";
});
}
});
}
function initHoverEffects() {
const perspectiveCards = document.querySelectorAll(".perspective-card");
perspectiveCards.forEach((card) => {
card.addEventListener("mousemove", (e) => {
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const xPercent = (x / rect.width - 0.5) * 2; // -1 to 1
const yPercent = (y / rect.height - 0.5) * -2; // -1 to 1
const inner = card.querySelector(".transform-3d");
if (inner) {
inner.style.transform = `rotateY(${xPercent * 5}deg) rotateX(${
yPercent * 5
}deg)`;
}
});
card.addEventListener("mouseleave", () => {
const inner = card.querySelector(".transform-3d");
if (inner) {
inner.style.transform = "rotateY(0) rotateX(0)";
}
});
});
}
function switchTab(tabName) {
const beritaContent = document.getElementById("beritaContent");
const videoContent = document.getElementById("videoContent");
const beritaTab = document.getElementById("beritaTab");
const videoTab = document.getElementById("videoTab");
if (tabName === "berita") {
// Update tab styles
beritaTab.classList.add(
"bg-gradient-to-r",
"from-[#00c950]/80",
"to-[#00c950]/80",
"text-white"
);
beritaTab.classList.remove("bg-white/5", "text-white/80");
videoTab.classList.remove(
"bg-gradient-to-r",
"from-[#487fff]/80",
"to-[#487fff]/80",
"text-white"
);
videoTab.classList.add("bg-white/5", "text-white/80");
// Enhanced transition effects
beritaContent.style.transform = "translateX(20px)";
beritaContent.style.opacity = "0";
setTimeout(() => {
videoContent.classList.add("hidden");
beritaContent.classList.remove("hidden");
requestAnimationFrame(() => {
beritaContent.style.transform = "translateX(0)";
beritaContent.style.opacity = "1";
});
}, 300);
} else {
videoTab.classList.add(
"bg-gradient-to-r",
"from-[#487fff]/80",
"to-[#487fff]/80",
"text-white"
);
videoTab.classList.remove("bg-white/5", "text-white/80");
beritaTab.classList.remove(
"bg-gradient-to-r",
"from-[#00c950]/80",
"to-[#00c950]/80",
"text-white"
);
beritaTab.classList.add("bg-white/5", "text-white/80");
videoContent.style.transform = "translateX(20px)";
videoContent.style.opacity = "0";
beritaContent.style.opacity = "0";
beritaContent.style.transform = "translateX(-20px)";
setTimeout(() => {
beritaContent.classList.add("hidden");
videoContent.classList.remove("hidden");
requestAnimationFrame(() => {
videoContent.style.transform = "translateX(0)";
videoContent.style.opacity = "1";
});
}, 300);
}
}

View File

@ -0,0 +1,75 @@
document.addEventListener("DOMContentLoaded", function () {
// Show popup with slight delay after page load
setTimeout(function () {
document.getElementById("popupBanner").classList.remove("hidden");
}, 800);
// Close popup when clicking the close button
document
.getElementById("closePopup")
.addEventListener("click", function () {
document.getElementById("popupBanner").classList.add("hidden");
});
// Close popup when clicking outside the banner
document
.getElementById("popupBanner")
.addEventListener("click", function (e) {
if (e.target === this) {
this.classList.add("hidden");
}
});
// Slider functionality
const slides = document.querySelectorAll(".banner-slide");
const dots = document.querySelectorAll(".dot-indicator");
let currentSlide = 0;
function showSlide(index) {
slides.forEach((slide) => slide.classList.add("hidden"));
dots.forEach((dot) => dot.classList.remove("active"));
slides[index].classList.remove("hidden");
dots[index].classList.add("active");
currentSlide = index;
}
// Auto slide every 5 seconds
let slideInterval = setInterval(() => {
let nextSlide = (currentSlide + 1) % slides.length;
showSlide(nextSlide);
}, 5000);
// Navigation buttons
document.getElementById("nextSlide").addEventListener("click", function () {
clearInterval(slideInterval);
let nextSlide = (currentSlide + 1) % slides.length;
showSlide(nextSlide);
slideInterval = setInterval(() => {
nextSlide = (currentSlide + 1) % slides.length;
showSlide(nextSlide);
}, 5000);
});
document.getElementById("prevSlide").addEventListener("click", function () {
clearInterval(slideInterval);
let prevSlide = (currentSlide - 1 + slides.length) % slides.length;
showSlide(prevSlide);
slideInterval = setInterval(() => {
let nextSlide = (currentSlide + 1) % slides.length;
showSlide(nextSlide);
}, 5000);
});
// Dot indicators
dots.forEach((dot, index) => {
dot.addEventListener("click", function () {
clearInterval(slideInterval);
showSlide(index);
slideInterval = setInterval(() => {
let nextSlide = (currentSlide + 1) % slides.length;
showSlide(nextSlide);
}, 5000);
});
});
});

View File

@ -0,0 +1,26 @@
// Mobile Menu Toggle
const mobileMenuToggle = document.getElementById("mobile-menu-toggle");
const mobileMenuClose = document.getElementById("mobile-menu-close");
const mobileMenu = document.getElementById("mobile-menu");
mobileMenuToggle.addEventListener("click", () => {
mobileMenu.classList.remove("-translate-x-full");
});
mobileMenuClose.addEventListener("click", () => {
mobileMenu.classList.add("-translate-x-full");
});
// Mobile Submenu Toggle
const mobileSubmenuToggles = document.querySelectorAll(
".mobile-submenu-toggle"
);
mobileSubmenuToggles.forEach((toggle) => {
toggle.addEventListener("click", (e) => {
const submenu = e.currentTarget.nextElementSibling;
const svg = e.currentTarget.querySelector("svg");
submenu.classList.toggle("hidden");
svg.classList.toggle("rotate-180");
});
});

View File

@ -4,6 +4,8 @@
<x-head/>
<link rel="stylesheet" href="{{ asset('assets/css/login/login.css') }}">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
@ -53,7 +55,9 @@
</div>
</div>
</div>
</body>
<x-script />
<script>
document.querySelector('.password-toggle').addEventListener('click', function() {
const passwordInput = document.getElementById('password');
@ -67,10 +71,5 @@
}
});
</script>
</body>
<x-script />
</body>
</html>

View File

@ -11,6 +11,4 @@
</a>
</div>
</div>
</section>

View File

@ -1,4 +1,7 @@
<body>
@push('script')
<script src="{{ asset('assets/js/frontend/footer.js') }}"></script>
@endpush
<!-- Marquee Header -->
<div class="bg-green-500 py-2 overflow-hidden relative">
<div id="marquee-container" class="flex whitespace-nowrap">
@ -17,51 +20,6 @@
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const container = document.getElementById('marquee-container');
const content = document.getElementById('marquee-content');
// Calculate the total width needed for animation
let contentWidth = content.offsetWidth;
// Clone the content multiple times to ensure smooth looping
for (let i = 0; i < 3; i++) {
const clone = content.cloneNode(true);
container.appendChild(clone);
}
// Start animation
let scrollPosition = 0;
const speed = 0.5; // slower speed (was 1)
let isAnimating = true;
// Pause on hover
container.addEventListener('mouseenter', function() {
isAnimating = false;
});
container.addEventListener('mouseleave', function() {
isAnimating = true;
});
function scroll() {
if (isAnimating) {
scrollPosition -= speed;
// Reset when first element is completely scrolled out
if (scrollPosition <= -contentWidth) {
scrollPosition += contentWidth;
}
container.style.transform = `translateX(${scrollPosition}px)`;
}
requestAnimationFrame(scroll);
}
// Start the animation
scroll();
});
</script>
<!-- Footer -->
<footer class="bg-black text-white pt-16 pb-8 z-11 relative">
<div class="container mx-auto px-4">
@ -177,4 +135,3 @@
</div>
</div>
</footer>
</body>

View File

@ -1,15 +1,37 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@yield('title', 'Sistem Perizinan Lingkungan')</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Perizinan Lingkungan</title>
<link rel="icon" type="image/ico" href="{{ asset('favicon.ico') }}" sizes="16x16">
<!-- SEO Meta Tags -->
<meta name="description" content="@yield('description', 'Sistem Perizinan Lingkungan Dinas Lingkungan Hidup Provinsi DKI Jakarta')" />
<meta name="keywords" content="@yield('keywords', 'Sistem Perizinan Lingkungan, Dinas Lingkungan Hidup DKI Jakarta')" />
<meta name="author" content="Dinas Lingkungan Hidup Provinsi DKI Jakarta" />
<meta name="robots" content="index, follow" />
<!-- Open Graph Meta Tags -->
<meta property="og:title" content="@yield('ogTitle', 'Sistem Perizinan Lingkungan')" />
<meta property="og:description" content="@yield('ogDescription', 'Dinas Lingkungan Hidup Provinsi DKI Jakarta')" />
<meta property="og:image" content="{{ asset('assets/images/logo_color.svg') }}" />
<meta property="og:url" content="{{ url()->current() }}" />
<meta property="og:type" content="website" />
<!-- Twitter Card Meta Tags -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="@yield('twitterTitle', 'Sistem Perizinan Lingkungan')" />
<meta name="twitter:description" content="@yield('twitterDescription', 'Dinas Lingkungan Hidup Provinsi DKI Jakarta')" />
<meta name="twitter:image" content="{{ asset('assets/images/logo_color.svg') }}" />
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Sans:ital,wght@0,400..700;1,400..700&display=swap" rel="stylesheet">
@stack('css')
@if (file_exists(public_path('build/manifest.json')) || file_exists(public_path('hot')))
@vite(['resources/css/app.css', 'resources/js/app.js'])
@else

View File

@ -1,8 +1,15 @@
@push('css')
<link rel="stylesheet" href="{{ asset('assets/css/frontend/home/faq.css') }}">
@endpush
@push('script')
<script src="{{ asset('assets/js/frontend/home/faq.js') }}"></script>
@endpush
<section class="bg-gradient-to-b from-gray-50 to-gray-100 font-sans py-6">
<div class="container mx-auto max-w-7xl px-4">
<div class="flex flex-col md:flex-row gap-8">
<!-- Left Column - FAQ -->
<div>
<h2 class="text-2xl font-bold custom-blue mb-4">Frequently Asked Questions</h2>
@ -56,7 +63,6 @@
</div>
</div>
<!-- Right Column - Tracking Document -->
<div>
<div class="bg-white rounded-xl shadow-sm p-6 border-l-4 border-custom-blue">
<h2 class="text-2xl font-bold custom-blue mb-6">Track Your Document</h2>
@ -74,65 +80,5 @@
</div>
</div>
</div>
<script>
document.querySelectorAll('.faq-header').forEach(header => {
header.addEventListener('click', () => {
const parent = header.parentElement;
const content = parent.querySelector('.faq-content');
const toggle = parent.querySelector('.faq-toggle svg');
// Close all other FAQs
document.querySelectorAll('.faq-item').forEach(item => {
if (item !== parent && item.classList.contains('active')) {
item.classList.remove('active');
item.querySelector('.faq-content').style.maxHeight = '0';
item.querySelector('.faq-toggle svg').classList.remove('rotate-45');
}
});
// Toggle current FAQ
parent.classList.toggle('active');
if (parent.classList.contains('active')) {
content.style.maxHeight = content.scrollHeight + "px";
toggle.classList.add('rotate-45');
} else {
content.style.maxHeight = '0';
toggle.classList.remove('rotate-45');
}
});
});
</script>
</section>
<style>
.custom-blue {
color: #003296;
}
.custom-blue-bg, .bg-custom-blue {
background-color: #003296;
}
.border-custom-blue {
border-color: #003296;
}
.faq-item {
border-left: 4px solid transparent;
transition: all 0.3s ease;
}
.faq-item:hover, .faq-item.active {
border-left: 4px solid #003296;
}
.faq-item.active {
box-shadow: 0 10px 15px -3px rgba(0, 50, 150, 0.1);
}
@media (min-width: 768px) {
.faq-icon {
transform: scale(0.9);
transition: transform 0.3s ease;
}
.faq-item:hover .faq-icon {
transform: scale(1.1);
}
}
</style>

View File

@ -1,10 +1,12 @@
<div class="relative w-full overflow-hidden min-h-[600px] md:min-h-[800px]">
<!-- Background -->
@push('css')
<link rel="stylesheet" href="{{ asset('assets/css/frontend/home/hero.css') }}">
@endpush
<section class="relative w-full overflow-hidden min-h-[600px] md:min-h-[800px]">
<div class="absolute inset-0 z-0">
<img src="{{ asset('assets/images/home/bg-home.png') }}" alt="Hero Background" class="w-full h-full object-contain md:object-cover rounded-b-2xl">
</div>
<!-- Tagline -->
<div class="relative z-10 max-w-7xl mx-auto px-4 mt-20 md:mt-10" style="z-index: 0;>
<div class="grid grid-cols-1 items-center">
<div class="text-center space-y-6 animate-fade-in-up">
@ -18,21 +20,4 @@
</div>
</div>
</div>
<style>
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fade-in-up {
animation: fadeInUp 0.8s ease-out forwards;
}
</style>
</section>

View File

@ -1,3 +1,7 @@
@push('script')
<script src="{{ asset('assets/js/frontend/home/layanan.js') }}"></script>
@endpush
<section class="bg-gray-100">
<div class="container mx-auto max-w-7xl px-4 py-8 sm:py-15">
<!-- Header -->
@ -295,48 +299,4 @@
</div>
</div>
</div>
<script>
document.getElementById('filter-button').addEventListener('click', function() {
const filterSection = document.getElementById('filter-section');
filterSection.classList.toggle('hidden');
});
document.getElementById('clear-filter').addEventListener('click', function() {
// Reset province and city dropdowns
document.getElementById('kabkota').value = '';
document.getElementById('kecamatan').value = '';
document.getElementById('kelurahan').value = '';
// Reset search input
const searchInput = document.querySelector('input[placeholder="Search"]');
if (searchInput) searchInput.value = '';
});
</script>
<script>
function changeTab(tabName) {
const contentSections = document.querySelectorAll('.tab-content');
contentSections.forEach(section => {
section.classList.add('hidden');
});
const tabButtons = document.querySelectorAll('.tab-btn');
tabButtons.forEach(button => {
button.classList.remove('bg-blue-900', 'text-white');
button.classList.add('bg-white', 'border', 'border-gray-300');
});
const selectedTab = document.getElementById('tab-' + tabName);
selectedTab.classList.remove('bg-white', 'border', 'border-gray-300');
selectedTab.classList.add('bg-blue-900', 'text-white');
const selectedContent = document.getElementById('content-' + tabName);
selectedContent.classList.remove('hidden');
}
document.addEventListener('DOMContentLoaded', function() {
changeTab('pertek');
});
</script>
</section>

View File

@ -1,3 +1,12 @@
@push('script')
<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"></script>
<script src="{{ asset('assets/js/frontend/home/news.js') }}"></script>
@endpush
@push('css')
<link rel="stylesheet" href="{{ asset('assets/css/frontend/home/news.css') }}">
@endpush
<section class="news-section relative overflow-hidden py-20 bg-gradient-to-b from-[#0c1a3f] via-[#0c2a6f] to-[#0c1a3f]">
<!-- Advanced particle background -->
<div class="container max-w-6xl mx-auto">
@ -247,281 +256,4 @@
</div>
</div>
</div>
<!-- ParticlesJS script -->
<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
if (typeof particlesJS !== 'undefined') {
particlesJS('particles-js', {
particles: {
number: { value: 80, density: { enable: true, value_area: 1000 } },
color: { value: "#ffffff" },
shape: { type: "circle" },
opacity: { value: 0.1, random: true },
size: { value: 3, random: true },
line_linked: {
enable: true, distance: 150,
color: "#ffffff", opacity: 0.05, width: 1
},
move: {
enable: true, speed: 0.5, direction: "none",
random: true, out_mode: "out", bounce: false
}
},
interactivity: {
detect_on: "canvas",
events: {
onhover: { enable: true, mode: "bubble" },
resize: true
},
modes: {
bubble: { distance: 200, size: 4, duration: 2, opacity: 0.2 }
}
},
retina_detect: true
});
}
// Parallax effect image utama
initParallaxEffect();
initHoverEffects();
});
function initParallaxEffect() {
const parallaxContainers = document.querySelectorAll('.parallax-container');
parallaxContainers.forEach(container => {
const img = container.querySelector('.parallax-img');
if (img) {
container.addEventListener('mousemove', (e) => {
const rect = container.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const xPercent = (x / rect.width - 0.5) * 2; // -1 to 1
const yPercent = (y / rect.height - 0.5) * 2; // -1 to 1
img.style.transform = `translate(${xPercent * -10}px, ${yPercent * -10}px) scale(1.1)`;
});
container.addEventListener('mouseleave', () => {
img.style.transform = 'translate(0, 0) scale(1.05)';
});
}
});
}
function initHoverEffects() {
const perspectiveCards = document.querySelectorAll('.perspective-card');
perspectiveCards.forEach(card => {
card.addEventListener('mousemove', (e) => {
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const xPercent = (x / rect.width - 0.5) * 2; // -1 to 1
const yPercent = (y / rect.height - 0.5) * -2; // -1 to 1
const inner = card.querySelector('.transform-3d');
if (inner) {
inner.style.transform = `rotateY(${xPercent * 5}deg) rotateX(${yPercent * 5}deg)`;
}
});
card.addEventListener('mouseleave', () => {
const inner = card.querySelector('.transform-3d');
if (inner) {
inner.style.transform = 'rotateY(0) rotateX(0)';
}
});
});
}
function switchTab(tabName) {
const beritaContent = document.getElementById('beritaContent');
const videoContent = document.getElementById('videoContent');
const beritaTab = document.getElementById('beritaTab');
const videoTab = document.getElementById('videoTab');
if (tabName === 'berita') {
// Update tab styles
beritaTab.classList.add('bg-gradient-to-r', 'from-[#00c950]/80', 'to-[#00c950]/80', 'text-white');
beritaTab.classList.remove('bg-white/5', 'text-white/80');
videoTab.classList.remove('bg-gradient-to-r', 'from-[#487fff]/80', 'to-[#487fff]/80', 'text-white');
videoTab.classList.add('bg-white/5', 'text-white/80');
// Enhanced transition effects
beritaContent.style.transform = 'translateX(20px)';
beritaContent.style.opacity = '0';
setTimeout(() => {
videoContent.classList.add('hidden');
beritaContent.classList.remove('hidden');
requestAnimationFrame(() => {
beritaContent.style.transform = 'translateX(0)';
beritaContent.style.opacity = '1';
});
}, 300);
} else {
videoTab.classList.add('bg-gradient-to-r', 'from-[#487fff]/80', 'to-[#487fff]/80', 'text-white');
videoTab.classList.remove('bg-white/5', 'text-white/80');
beritaTab.classList.remove('bg-gradient-to-r', 'from-[#00c950]/80', 'to-[#00c950]/80', 'text-white');
beritaTab.classList.add('bg-white/5', 'text-white/80');
videoContent.style.transform = 'translateX(20px)';
videoContent.style.opacity = '0';
beritaContent.style.opacity = '0';
beritaContent.style.transform = 'translateX(-20px)';
setTimeout(() => {
beritaContent.classList.add('hidden');
videoContent.classList.remove('hidden');
requestAnimationFrame(() => {
videoContent.style.transform = 'translateX(0)';
videoContent.style.opacity = '1';
});
}, 300);
}
}
</script>
<style>
@keyframes gradient-x {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
.animate-gradient-x {
background-size: 200% 200%;
animation: gradient-x 3s ease infinite;
}
@keyframes pulse-slow {
0%, 100% { opacity: 0.3; }
50% { opacity: 0.7; }
}
.animate-pulse-slow {
animation: pulse-slow 6s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-15px); }
}
.animate-float {
animation: float 8s ease-in-out infinite;
}
.animate-float-slow {
animation: float 12s ease-in-out infinite;
}
.animate-float-slow-reverse {
animation: float 12s ease-in-out infinite reverse;
}
@keyframes float-text {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-5px) rotate(2deg); }
}
.animate-float-text {
animation: float-text 2s ease-in-out infinite;
display: inline-block;
}
@keyframes subtle-rotate {
0%, 100% { transform: rotate(-1deg); }
50% { transform: rotate(1deg); }
}
.animate-subtle-rotate {
animation: subtle-rotate 12s ease-in-out infinite;
}
/* efek 3d */
.perspective {
perspective: 1000px;
}
.perspective-hero {
perspective: 2000px;
}
.perspective-card {
perspective: 1000px;
transform-style: preserve-3d;
}
.transform-3d {
transform-style: preserve-3d;
transition: transform 0.6s cubic-bezier(0.2, 0.85, 0.4, 1);
}
.glow-line {
box-shadow: 0 0 15px 2px rgba(124, 207, 0, 0.6);
animation: glow-pulse 3s ease-in-out infinite alternate;
}
@keyframes glow-pulse {
0% { box-shadow: 0 0 10px 1px rgba(124, 207, 0, 0.5); }
100% { box-shadow: 0 0 25px 5px rgba(124, 207, 0, 0.8); }
}
.ripple-effect {
position: absolute;
width: 70px;
height: 70px;
border-radius: 50%;
background: rgba(72, 127, 255, 0.4);
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
opacity: 0;
animation: ripple 2s linear infinite;
}
@keyframes ripple {
0% { transform: translate(-50%, -50%) scale(1); opacity: 0; }
20% { transform: translate(-50%, -50%) scale(1.2); opacity: 0.6; }
100% { transform: translate(-50%, -50%) scale(2); opacity: 0; }
}
.masonry-card-wide {
grid-row: span 1;
}
@media (min-width: 1024px) {
.masonry-card:nth-child(4n+1) {
grid-row: span 2;
}
}
#beritaContent, #videoContent {
transition: all 0.5s cubic-bezier(0.2, 0.85, 0.4, 1);
}
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.line-clamp-3 {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.tab-glass-container {
position: relative;
z-index: 1;
}
.tab-glass-container::after {
content: '';
position: absolute;
inset: 0;
z-index: -1;
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(10px);
border-radius: inherit;
}
</style>
</section>

View File

@ -1,3 +1,11 @@
@push('css')
<link rel="stylesheet" href="{{ asset('assets/css/frontend/home/popup.css') }}">
@endpush
@push('script')
<script src="{{ asset('assets/js/frontend/home/popup.js') }}"></script>
@endpush
<div id="popupBanner" class="fixed inset-0 z-50 flex items-center justify-center bg-black/85 hidden">
<div class="relative bg-white w-11/12 max-w-6xl rounded-lg shadow-2xl overflow-hidden">
<!-- Close button (now floating on top of content) -->
@ -49,86 +57,3 @@
</div>
</div>
</div>
<style>
.banner-slide {
transition: opacity 0.5s ease;
}
.dot-indicator.active {
background-color: #3182ce;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Show popup with slight delay after page load
setTimeout(function() {
document.getElementById('popupBanner').classList.remove('hidden');
}, 800);
// Close popup when clicking the close button
document.getElementById('closePopup').addEventListener('click', function() {
document.getElementById('popupBanner').classList.add('hidden');
});
// Close popup when clicking outside the banner
document.getElementById('popupBanner').addEventListener('click', function(e) {
if (e.target === this) {
this.classList.add('hidden');
}
});
// Slider functionality
const slides = document.querySelectorAll('.banner-slide');
const dots = document.querySelectorAll('.dot-indicator');
let currentSlide = 0;
function showSlide(index) {
slides.forEach(slide => slide.classList.add('hidden'));
dots.forEach(dot => dot.classList.remove('active'));
slides[index].classList.remove('hidden');
dots[index].classList.add('active');
currentSlide = index;
}
// Auto slide every 5 seconds
let slideInterval = setInterval(() => {
let nextSlide = (currentSlide + 1) % slides.length;
showSlide(nextSlide);
}, 5000);
// Navigation buttons
document.getElementById('nextSlide').addEventListener('click', function() {
clearInterval(slideInterval);
let nextSlide = (currentSlide + 1) % slides.length;
showSlide(nextSlide);
slideInterval = setInterval(() => {
nextSlide = (currentSlide + 1) % slides.length;
showSlide(nextSlide);
}, 5000);
});
document.getElementById('prevSlide').addEventListener('click', function() {
clearInterval(slideInterval);
let prevSlide = (currentSlide - 1 + slides.length) % slides.length;
showSlide(prevSlide);
slideInterval = setInterval(() => {
let nextSlide = (currentSlide + 1) % slides.length;
showSlide(nextSlide);
}, 5000);
});
// Dot indicators
dots.forEach((dot, index) => {
dot.addEventListener('click', function() {
clearInterval(slideInterval);
showSlide(index);
slideInterval = setInterval(() => {
let nextSlide = (currentSlide + 1) % slides.length;
showSlide(nextSlide);
}, 5000);
});
});
});
</script>

View File

@ -8,5 +8,9 @@
@include('components.frontend.navbar')
@yield('content')
</main>
@include('components.frontend.script')
@stack('script')
</body>
</html>

View File

@ -1,3 +1,7 @@
@push('script')
<script src="{{ asset('assets/js/frontend/navbar.js') }}"></script>
@endpush
<nav class="relative">
<!-- Background Image Layer (Lowest z-index) -->
<div class="absolute inset-y-0 w-full flex justify-center top-0 mt-6" style="z-index: 0;">
@ -183,30 +187,3 @@
</div>
</div>
</nav>
<script>
// Mobile Menu Toggle
const mobileMenuToggle = document.getElementById('mobile-menu-toggle');
const mobileMenuClose = document.getElementById('mobile-menu-close');
const mobileMenu = document.getElementById('mobile-menu');
mobileMenuToggle.addEventListener('click', () => {
mobileMenu.classList.remove('-translate-x-full');
});
mobileMenuClose.addEventListener('click', () => {
mobileMenu.classList.add('-translate-x-full');
});
// Mobile Submenu Toggle
const mobileSubmenuToggles = document.querySelectorAll('.mobile-submenu-toggle');
mobileSubmenuToggles.forEach(toggle => {
toggle.addEventListener('click', (e) => {
const submenu = e.currentTarget.nextElementSibling;
const svg = e.currentTarget.querySelector('svg');
submenu.classList.toggle('hidden');
svg.classList.toggle('rotate-180');
});
});
</script>

View File

@ -7,7 +7,6 @@
</div>
</div>
</div>
<div class="container mx-auto px-4 py-12 max-w-7xl">
<!-- News Articles Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" id="news-container">

View File

@ -0,0 +1 @@
<?php echo (isset($script) ? $script : '')?>

View File

@ -1,7 +1,28 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Perizinan Lingkungan</title>
<title>{{ $title ?? 'Sistem Perizinan Lingkungan' }}</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- SEO Meta Tags -->
<meta name="description" content="{{ $description ?? 'Sistem Perizinan Lingkungan Dinas Lingkungan Hidup Provinsi DKI Jakarta' }}" />
<meta name="keywords" content="{{ $keywords ?? 'Sistem Perizinan Lingkungan, Dinas Lingkungan Hidup DKI Jakarta' }}" />
<meta name="author" content="Dinas Lingkungan Hidup Provinsi DKI Jakarta" />
<meta name="robots" content="index, follow" />
<!-- Open Graph Meta Tags -->
<meta property="og:title" content="{{ $ogTitle ?? 'Sistem Perizinan Lingkungan' }}" />
<meta property="og:description" content="{{ $ogDescription ?? 'Dinas Lingkungan Hidup Provinsi DKI Jakarta' }}" />
<meta property="og:image" content="{{ asset('assets/images/logo_color.svg') }}" />
<meta property="og:url" content="{{ url()->current() }}" />
<meta property="og:type" content="website" />
<!-- Twitter Card Meta Tags -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="{{ $twitterTitle ?? 'Sistem Perizinan Lingkungan' }}" />
<meta name="twitter:description" content="{{ $twitterDescription ?? 'Dinas Lingkungan Hidup Provinsi DKI Jakarta' }}" />
<meta name="twitter:image" content="{{ asset('assets/images/logo_color.svg') }}" />
<link rel="icon" type="image/ico" href="{{ asset('favicon.ico') }}" sizes="16x16">
<!-- remix icon font css -->
<link rel="stylesheet" href="{{ asset('assets/css/remixicon.css') }}">
@ -11,10 +32,12 @@
<link rel="stylesheet" href="{{ asset('assets/css/lib/apexcharts.css') }}">
<!-- Data Table css -->
<link rel="stylesheet" href="{{ asset('assets/css/lib/dataTables.min.css') }}">
<!-- Text Editor css -->
<link rel="stylesheet" href="{{ asset('assets/css/lib/editor-katex.min.css') }}">
<link rel="stylesheet" href="{{ asset('assets/css/lib/editor.atom-one-dark.min.css') }}">
<link rel="stylesheet" href="{{ asset('assets/css/lib/editor.quill.snow.css') }}">
<!-- Date picker css -->
<link rel="stylesheet" href="{{ asset('assets/css/lib/flatpickr.min.css') }}">
<!-- Calendar css -->
@ -36,11 +59,6 @@
{{-- custom css --}}
{!! $css ?? '' !!}
{{-- <link rel="stylesheet" href="{{ asset('assets/css/lib/select2.min.css') }}" /> --}}
<!-- Include select2 CSS -->
<link href="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/css/select2.min.css" rel="stylesheet" />
</head>

View File

@ -303,12 +303,6 @@
</li>
</ul>
</li>
</ul>
</div>
</aside>

View File

@ -1,10 +1,16 @@
@extends('components.frontend.layout')
@section('title', 'Not Found - Sistem Perizinan Lingkungan')
@section('description', 'Sistem Perizinan Lingkungan Dinas Lingkungan Hidup Provinsi DKI Jakarta')
@section('keywords', 'Not Found, DLH, Sistem Perizinan Lingkungan, Dinas Lingkungan Hidup DKI Jakarta')
@section('ogTitle', 'Not Found - Sistem Perizinan Lingkungan')
@section('ogDescription', 'Dinas Lingkungan Hidup DKI Jakarta')
@section('twitterTitle', 'Not Found - Sistem Perizinan Lingkungan')
@section('twitterDescription', 'Dinas Lingkungan Hidup DKI Jakarta')
@section('content')
@include('components.frontend.404')
@include('components.frontend.footer')
@endsection

View File

@ -1,5 +1,13 @@
@extends('components.frontend.layout')
@section('title', 'Sistem Perizinan Lingkungan')
@section('description', 'Sistem Perizinan Lingkungan Dinas Lingkungan Hidup Provinsi DKI Jakarta')
@section('keywords', 'Home, DLH, Sistem Perizinan Lingkungan, Dinas Lingkungan Hidup DKI Jakarta')
@section('ogTitle', 'Home - Sistem Perizinan Lingkungan')
@section('ogDescription', 'Dinas Lingkungan Hidup DKI Jakarta')
@section('twitterTitle', 'Home - Sistem Perizinan Lingkungan')
@section('twitterDescription', 'Dinas Lingkungan Hidup DKI Jakarta')
@section('content')
@include('components.frontend.home.popup')
@ -9,6 +17,4 @@
@include('components.frontend.home.news')
@include('components.frontend.footer')
@endsection

View File

@ -1,10 +1,16 @@
@extends('components.frontend.layout')
@section('title', 'Berita & Updates - Sistem Perizinan Lingkungan')
@section('description', 'Sistem Perizinan Lingkungan Dinas Lingkungan Hidup Provinsi DKI Jakarta')
@section('keywords', 'Berita & Updates, DLH, Sistem Perizinan Lingkungan, Dinas Lingkungan Hidup DKI Jakarta')
@section('ogTitle', 'Berita & Updates - Sistem Perizinan Lingkungan')
@section('ogDescription', 'Dinas Lingkungan Hidup DKI Jakarta')
@section('twitterTitle', 'Berita & Updates - Sistem Perizinan Lingkungan')
@section('twitterDescription', 'Dinas Lingkungan Hidup DKI Jakarta')
@section('content')
@include('components.frontend.news.index_news')
@include('components.frontend.footer')
@endsection

View File

@ -1,10 +1,16 @@
@extends('components.frontend.layout')
@section('title', 'Detail Berita & Updates - Sistem Perizinan Lingkungan')
@section('description', 'Sistem Perizinan Lingkungan Dinas Lingkungan Hidup Provinsi DKI Jakarta')
@section('keywords', 'Detail Berita & Updates, DLH, Sistem Perizinan Lingkungan, Dinas Lingkungan Hidup DKI Jakarta')
@section('ogTitle', 'Detail Berita & Updates - Sistem Perizinan Lingkungan')
@section('ogDescription', 'Dinas Lingkungan Hidup DKI Jakarta')
@section('twitterTitle', 'Detail Berita & Updates - Sistem Perizinan Lingkungan')
@section('twitterDescription', 'Dinas Lingkungan Hidup DKI Jakarta')
@section('content')
@include('components.frontend.news.detail_news')
@include('components.frontend.footer')
@endsection

View File

@ -1,4 +1,3 @@
<!-- meta tags and other links -->
<!DOCTYPE html>
<html lang="en" data-theme="light">
@ -7,33 +6,23 @@
<body>
<!-- ..:: header area start ::.. -->
<x-sidebar />
<!-- ..:: header area end ::.. -->
<main class="dashboard-main">
<!-- ..:: navbar start ::.. -->
<x-navbar />
<!-- ..:: navbar end ::.. -->
<div class="dashboard-main-body">
<!-- ..:: breadcrumb start ::.. -->
<x-breadcrumb title='{{ isset($title) ? $title : "" }}' subTitle='{{ isset($subTitle) ? $subTitle : "" }}' />
<!-- ..:: header area end ::.. -->
@yield('content')
</div>
<!-- ..:: footer start ::.. -->
<x-footer />
<!-- ..:: footer area end ::.. -->
</main>
<!-- ..:: scripts start ::.. -->
<x-script script='{!! isset($script) ? $script : "" !!}' />
<!-- ..:: scripts end ::.. -->
</body>