This commit is contained in:
Muzakki Parsaoran Siregar 2025-10-24 16:43:47 +07:00
parent f044a14fa2
commit 3b6063d8c5
9 changed files with 343 additions and 231 deletions

View File

@ -2,3 +2,4 @@
html {
scroll-behavior: smooth;
}

View File

@ -12,7 +12,7 @@
</div>
<!-- Main Content -->
<div class="relative z-10 min-h-screen flex items-center justify-center px-4 md:px-8 py-12">
<div class="relative z-10 min-h-screen flex items-center justify-center px-4 md:px-8 py-22">
<div class="text-center max-w-5xl mx-auto">
<!-- Bismillah -->
<div class="mb-10 animate-fade-in-down">
@ -158,16 +158,20 @@
</div>
</div>
<!-- Decorative Element -->
<div class="absolute inset-0 pointer-events-none overflow-hidden">
<div class="absolute top-0 left-1/2 transform -translate-x-1/2">
<svg viewBox="0 0 200 100" class="w-40 md:w-48 h-20 md:h-24 text-yellow-400 opacity-20">
<path
d="M100 20 Q120 0 140 20 Q160 40 140 60 Q120 40 100 60 Q80 40 60 60 Q40 40 60 20 Q80 0 100 20"
fill="currentColor"
/>
</svg>
<!-- Decorative Lanterns -->
<div class="absolute top-4 left-4 md:top-8 md:left-8 animate-sway">
<Lantern />
</div>
<div class="absolute top-4 right-4 md:top-8 md:right-8 animate-sway animation-delay-1000">
<Lantern />
</div>
<!-- Kubah Decorations -->
<div class="absolute top-0 left-8 md:left-32 w-14 md:w-34 kubah-swing animation-delay-300">
<img src="/kubah.png" alt="Kubah" class="w-full h-auto opacity-80" />
</div>
<div class="absolute top-0 right-8 md:right-22 w-14 md:w-44 kubah-swing animation-delay-600">
<img src="/kubah.png" alt="Kubah" class="w-full h-auto opacity-80" />
</div>
</div>
</template>
@ -294,11 +298,16 @@ onUnmounted(() => {
</script>
<style scoped>
/* Animations & bg-pattern */
/* =========================
🎨 Background Pattern
========================= */
.bg-pattern {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><defs><pattern id='pattern' x='0' y='0' width='20' height='20' patternUnits='userSpaceOnUse'><path d='M10 5 L15 10 L10 15 L5 10 Z' fill='none' stroke='rgba(255,255,255,0.1)' stroke-width='0.5'/></pattern></defs><rect width='100' height='100' fill='url(%23pattern)'/></svg>");
}
/* =========================
General Animations
========================= */
.animate-sway {
animation: sway 3s ease-in-out infinite;
}
@ -308,20 +317,37 @@ onUnmounted(() => {
50% { transform: translateY(-10px); }
}
/* =========================
🕌 Smooth Kubah Swing
========================= */
.kubah-swing {
animation: kubahSwingSmooth 6s cubic-bezier(0.45, 0, 0.55, 1) infinite;
transform-origin: top center;
}
@keyframes kubahSwingSmooth {
0% { transform: rotate(0deg); }
20% { transform: rotate(3deg); }
40% { transform: rotate(-3deg); }
60% { transform: rotate(3.5deg); }
80% { transform: rotate(-3deg); }
100% { transform: rotate(0deg); }
}
/* =========================
Fade Animations
========================= */
.animate-fade-in-down {
animation: fadeInDown 1s ease-out forwards;
animation: fadeInDown 0.5s ease-out forwards;
}
.animate-fade-in-up {
animation: fadeInUp 1s ease-out forwards;
animation: fadeInUp 0.5s ease-out forwards;
}
.animate-fade-in-left {
animation: fadeInLeft 1s ease-out forwards;
animation: fadeInLeft 0.5s ease-out forwards;
}
.animate-fade-in-right {
animation: fadeInRight 1s ease-out forwards;
animation: fadeInRight 0.5s ease-out forwards;
}
@keyframes fadeInDown {
@ -344,18 +370,16 @@ onUnmounted(() => {
to { opacity: 1; transform: translateX(0); }
}
.animation-delay-300 {
animation-delay: 0.3s;
}
.animation-delay-600 {
animation-delay: 0.6s;
}
.animation-delay-1000 {
animation-delay: 1s;
}
/* =========================
Delay Utilities
========================= */
.animation-delay-300 { animation-delay: 0.3s; }
.animation-delay-600 { animation-delay: 0.6s; }
.animation-delay-1000 { animation-delay: 0.8s; }
/* =========================
🕌 Font Arabic
========================= */
.arabic-text {
font-family: 'Noto Naskh Arabic', serif;
}

View File

@ -4,7 +4,7 @@
<div class="absolute inset-0 bg-pattern opacity-30"></div>
<!-- Main Content -->
<div class="relative z-10 flex flex-col items-center justify-center px-6 py-12">
<div class="relative z-10 flex flex-col items-center justify-center px-6 py-18">
<!-- Gallery Title -->
<div class="text-center mb-8 animate-fade-in-down">
<h1 class="text-yellow-400 text-4xl md:text-5xl font-bold mb-6 font-script">
@ -17,40 +17,20 @@
</p>
</div>
<!-- Photo Gallery Grid -->
<div class="flex-1 max-w-4xl mx-auto w-full animate-fade-in-up animation-delay-300">
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
<!-- Foto pertama (besar) -->
<!-- Masonry-style Gallery -->
<div class="flex-1 max-w-5xl mx-auto w-full animate-fade-in-up animation-delay-300">
<div class="columns-2 md:columns-3 gap-4 space-y-4">
<div
v-if="images.length > 0"
class="md:col-span-1 md:row-span-2 relative group cursor-pointer"
@click="openModal(0)"
v-for="(image, index) in images"
:key="index"
class="relative group break-inside-avoid cursor-pointer"
@click="openModal(index)"
>
<div class="bg-white/10 backdrop-blur-sm rounded-2xl overflow-hidden border border-yellow-400/30 hover:border-yellow-400/60 transition-all duration-300">
<img
:src="images[0]"
:alt="`Gallery Image 1`"
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
@error="handleImageError"
/>
<div class="absolute inset-0 bg-black/0 group-hover:bg-black/20 flex items-center justify-center transition-colors duration-300">
<Icon name="lucide:zoom-in" class="w-8 h-8 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
</div>
</div>
</div>
<!-- Foto lainnya -->
<div
v-for="(image, index) in images.slice(1)"
:key="index + 1"
class="relative group cursor-pointer"
@click="openModal(index + 1)"
>
<div class="bg-white/10 backdrop-blur-sm rounded-xl overflow-hidden border border-yellow-400/30 hover:border-yellow-400/60 transition-all duration-300">
<img
:src="image"
:alt="`Gallery Image ${index + 2}`"
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
:alt="`Gallery Image ${index + 1}`"
class="w-full h-auto object-cover group-hover:scale-105 transition-transform duration-300"
@error="handleImageError"
/>
<div class="absolute inset-0 bg-black/0 group-hover:bg-black/20 flex items-center justify-center transition-colors duration-300">
@ -180,4 +160,9 @@ onUnmounted(() => {
.bg-pattern {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="islamic" x="0" y="0" width="25" height="25" patternUnits="userSpaceOnUse"><g fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="0.5"><path d="M12.5 0 L25 12.5 L12.5 25 L0 12.5 Z M6.25 6.25 L18.75 6.25 L18.75 18.75 L6.25 18.75 Z"/><circle cx="12.5" cy="12.5" r="3"/></g></pattern></defs><rect width="100%" height="100%" fill="url(%23islamic)"/></svg>');
}
/* Masonry layout fix */
.break-inside-avoid {
break-inside: avoid;
}
</style>

View File

@ -1,11 +1,12 @@
<!-- components/shared/GuestBook.vue -->
<template>
<div class="h-screen w-full relative bg-gradient-to-br from-blue-900 via-blue-800 to-blue-900 overflow-hidden">
<div class="min-h-screen w-full relative bg-gradient-to-br from-blue-900 via-blue-800 to-blue-900 overflow-x-hidden overflow-y-auto">
<!-- Background Pattern -->
<div class="absolute inset-0 bg-pattern opacity-30"></div>
<!-- Main Content -->
<div class="relative z-10 h-full flex items-center justify-center px-6 py-12">
<div class="relative z-10 h-full flex items-center justify-center px-6 py-18">
<div class="w-full max-w-6xl mx-auto">
<!-- Title -->

View File

@ -2,6 +2,9 @@
<div
class="h-screen w-full relative bg-gradient-to-br from-blue-900 via-blue-800 to-blue-900 overflow-hidden"
>
<!-- Background Pattern -->
<div class="absolute inset-0 bg-pattern opacity-30"></div>
<!-- Main Content -->
<div class="relative z-10 min-h-screen flex items-center justify-center px-4 md:px-8 py-12">
<div class="text-center max-w-4xl mx-auto">
@ -12,16 +15,10 @@
</h1>
</div>
<!-- Background Pattern -->
<div class="absolute inset-0 bg-pattern opacity-30"></div>
<!-- Main Content -->
<div
class="relative z-10 h-full flex flex-col items-center justify-center px-6 text-center"
>
<!-- Child Section -->
<div class="relative z-10 h-full flex flex-col items-center justify-center px-6 text-center">
<!-- Child Photo -->
<div class="w-48 h-60 overflow-hidden rounded-t-3xl mx-auto mb-6 shadow-lg">
<div class="w-68 h-80 overflow-hidden rounded-t-3xl mx-auto mb-[-20px] shadow-lg">
<img
:src="getFullPhotoUrl(childPhoto)"
alt="Child"
@ -29,15 +26,16 @@
/>
</div>
<!-- Child Name -->
<!-- Child Name with nickname.png background (Tailwind version) -->
<div
class="bg-blue-800/50 border border-yellow-400 rounded-md px-6 py-2 mb-4 inline-block"
class="relative mb-0 inline-flex items-center justify-center w-[420px] h-[110px] bg-[url('/nickname.png')] bg-contain bg-no-repeat bg-center"
>
<h1 class="text-yellow-400 font-bold text-xl">
<h1 class="text-yellow-400 font-bold text-xl md:text-2xl font-script drop-shadow-lg">
{{ form.nama_lengkap || 'Nama Anak' }}
</h1>
</div>
<!-- Child Order -->
<div v-if="form.anak_ke" class="text-white/80 text-lg mb-2">
Putra ke {{ form.anak_ke }} dari
@ -89,4 +87,20 @@ const getFullPhotoUrl = (photo) => {
.bg-pattern {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="islamic" x="0" y="0" width="25" height="25" patternUnits="userSpaceOnUse"><g fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="0.5"><path d="M12.5 0 L25 12.5 L12.5 25 L0 12.5 Z M6.25 6.25 L18.75 6.25 L18.75 18.75 L6.25 18.75 Z"/><circle cx="12.5" cy="12.5" r="3"/></g></pattern></defs><rect width="100%" height="100%" fill="url(%23islamic)"/></svg>');
}
/* Efek animasi halus muncul dari atas */
@keyframes fade-in-down {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fade-in-down {
animation: fade-in-down 1s ease-out;
}
</style>

View File

@ -1,33 +1,55 @@
```vue
<template>
<div class="min-h-screen w-full relative bg-gradient-to-br from-blue-900 via-blue-800 to-blue-900 overflow-hidden">
<!-- Background Pattern -->
<div
class="min-h-screen w-full relative bg-gradient-to-br from-blue-900 via-blue-800 to-blue-900 overflow-hidden"
>
<!-- 🌙 Background Pattern -->
<div class="absolute inset-0 bg-pattern opacity-20"></div>
<!-- Main Content -->
<!-- Kubah Decorations -->
<div class="absolute top-0 left-8 md:left-32 w-16 md:w-34 kubah-swing animation-delay-300">
<img src="/kubah.png" alt="Kubah" class="w-full h-auto opacity-80" />
</div>
<div class="absolute top-0 right-8 md:right-22 w-16 md:w-44 kubah-swing animation-delay-600">
<img src="/kubah.png" alt="Kubah" class="w-full h-auto opacity-80" />
</div>
<!-- 🌸 Main Content -->
<div class="relative z-10 min-h-screen flex items-center justify-center px-4 md:px-8 py-12">
<div class="text-center max-w-4xl mx-auto">
<!-- Title -->
<div class="mb-10 animate-fade-in-down">
<h1 class="text-yellow-400 text-3xl md:text-5xl lg:text-6xl font-bold mb-4 md:mb-6 font-script">
<h1
class="text-yellow-400 text-3xl md:text-5xl lg:text-6xl font-bold mb-4 md:mb-6 font-script"
>
Terima Kasih
</h1>
<p class="text-white text-sm md:text-base lg:text-lg leading-relaxed max-w-3xl mx-auto">
<p
class="text-white text-sm md:text-base lg:text-lg leading-relaxed max-w-3xl mx-auto"
>
Kami mengucapkan terima kasih atas kehadiran serta doa restu yang diberikan untuk
<span class="text-yellow-400 font-semibold">{{ jsonData.nama_panggilan || 'putra kami' }}</span>.
<span class="text-yellow-400 font-semibold">{{
jsonData.nama_panggilan || "putra kami"
}}</span>.
Semoga Allah SWT senantiasa melimpahkan rahmat dan keberkahan kepada kita semua.
</p>
</div>
<!-- Family Info -->
<div class="mb-12 animate-fade-in-up animation-delay-300">
<h2 class="text-yellow-400 text-xl md:text-2xl lg:text-3xl font-bold mb-6 md:mb-8">
<h2
class="text-yellow-400 text-xl md:text-2xl lg:text-3xl font-bold mb-6 md:mb-8"
>
Kami Keluarga Besar Dari
</h2>
<div class="space-y-4 md:space-y-6">
<div class="bg-white/10 backdrop-blur-md rounded-2xl p-4 md:p-6 border border-yellow-400/30 shadow-lg animate-fade-in-up animation-delay-500">
<div class="text-yellow-400 text-base md:text-lg font-semibold mb-2">
{{ jsonData.nama_bapak || 'Bpk H. Munawar Huda, S.H.' }} & {{ jsonData.nama_ibu || 'Ibu Hj. Dinah, A.M.Keb' }}
<div
class="bg-white/10 backdrop-blur-md rounded-2xl p-4 md:p-6 border border-yellow-400/30 shadow-lg animate-fade-in-up animation-delay-500"
>
<div
class="text-yellow-400 text-base md:text-lg font-semibold mb-2"
>
{{ jsonData.nama_bapak || "Bpk H. Munawar Huda, S.H." }} &
{{ jsonData.nama_ibu || "Ibu Hj. Dinah, A.M.Keb" }}
</div>
</div>
</div>
@ -35,91 +57,147 @@
<!-- Final Message -->
<div class="animate-fade-in-up animation-delay-1200">
<div class="bg-gradient-to-r from-yellow-400/20 to-yellow-600/20 backdrop-blur-md rounded-2xl p-6 md:p-8 border border-yellow-400/50 shadow-lg">
<div
class="bg-gradient-to-r from-yellow-400/20 to-yellow-600/20 backdrop-blur-md rounded-2xl p-6 md:p-8 border border-yellow-400/50 shadow-lg"
>
<p class="text-white text-base md:text-lg font-medium mb-4 italic">
"Dan Allah telah mengeluarkan kamu dari perut ibumu dalam keadaan tidak mengetahui sesuatupun..."
"Dan Allah telah mengeluarkan kamu dari perut ibumu dalam keadaan
tidak mengetahui sesuatupun..."
</p>
<p class="text-yellow-400 text-sm md:text-base font-semibold">
- QS. An-Nahl: 78
</p>
<p class="text-yellow-400 text-sm md:text-base font-semibold">- QS. An-Nahl: 78</p>
</div>
</div>
<!-- Social Media Links -->
<div class="mt-10 md:mt-12 animate-fade-in-up animation-delay-1500 flex justify-center space-x-4 md:space-x-6">
<!-- Social Media Links -->
<div
class="mt-10 md:mt-12 animate-fade-in-up animation-delay-1500 flex justify-center space-x-4 md:space-x-6"
>
<a
v-if="jsonData.link_instagram"
:href="jsonData.link_instagram"
target="_blank"
rel="noopener noreferrer"
class="rounded-full p-2 md:p-3 backdrop-blur-md border border-yellow-400/30 hover:border-yellow-400/60 hover:bg-white/20 transition-all duration-300 transform hover:scale-110"
class="w-10 h-10 md:w-12 md:h-12 flex items-center justify-center rounded-full backdrop-blur-md border border-yellow-400/30 hover:border-yellow-400/60 hover:bg-white/20 transition-all duration-300 transform hover:scale-110"
aria-label="Instagram"
>
<Icon name="lucide:instagram" class="w-5 h-5 md:w-6 md:h-6 text-yellow-400" />
<Icon
name="lucide:instagram"
class="w-5 h-5 md:w-6 md:h-6 text-yellow-400"
/>
</a>
<a
v-if="jsonData.link_facebook"
:href="jsonData.link_facebook"
target="_blank"
rel="noopener noreferrer"
class="rounded-full p-2 md:p-3 backdrop-blur-md border border-yellow-400/30 hover:border-yellow-400/60 hover:bg-white/20 transition-all duration-300 transform hover:scale-110"
class="w-10 h-10 md:w-12 md:h-12 flex items-center justify-center rounded-full backdrop-blur-md border border-yellow-400/30 hover:border-yellow-400/60 hover:bg-white/20 transition-all duration-300 transform hover:scale-110"
aria-label="Facebook"
>
<Icon name="lucide:facebook" class="w-5 h-5 md:w-6 md:h-6 text-yellow-400" />
<Icon
name="lucide:facebook"
class="w-5 h-5 md:w-6 md:h-6 text-yellow-400"
/>
</a>
<a
v-if="jsonData.link_twitter"
:href="jsonData.link_twitter"
target="_blank"
rel="noopener noreferrer"
class="rounded-full p-2 md:p-3 backdrop-blur-md border border-yellow-400/30 hover:border-yellow-400/60 hover:bg-white/20 transition-all duration-300 transform hover:scale-110"
class="w-10 h-10 md:w-12 md:h-12 flex items-center justify-center rounded-full backdrop-blur-md border border-yellow-400/30 hover:border-yellow-400/60 hover:bg-white/20 transition-all duration-300 transform hover:scale-110"
aria-label="Twitter"
>
<Icon name="lucide:twitter" class="w-5 h-5 md:w-6 md:h-6 text-yellow-400" />
<Icon
name="lucide:twitter"
class="w-5 h-5 md:w-6 md:h-6 text-yellow-400"
/>
</a>
</div>
</div>
</div>
<!-- Copyright -->
<!-- Footer -->
<div class="absolute bottom-4 left-1/2 transform -translate-x-1/2 z-10">
<p class="text-white/60 text-xs text-center">© {{ currentYear }} - Invitation Template</p>
<p class="text-white/60 text-xs text-center">
© {{ currentYear }} - Invitation Template
</p>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue'
import { computed } from "vue";
const props = defineProps({
childName: {
type: String,
default: ''
default: "",
},
jsonData: {
type: Object,
default: () => ({})
}
})
default: () => ({}),
},
});
const currentYear = computed(() => new Date().getFullYear())
const currentYear = computed(() => new Date().getFullYear());
</script>
<style scoped>
/* Animations & bg-pattern */
/* =========================
🎨 Background Pattern
========================= */
.bg-pattern {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><defs><pattern id='pattern' x='0' y='0' width='20' height='20' patternUnits='userSpaceOnUse'><path d='M10 5 L15 10 L10 15 L5 10 Z' fill='none' stroke='rgba(255,255,255,0.1)' stroke-width='0.5'/></pattern></defs><rect width='100' height='100' fill='url(%23pattern)'/></svg>");
}
.animate-fade-in-up {
animation: fadeInUp 1s ease-out forwards;
/* =========================
General Animations
========================= */
.animate-sway {
animation: sway 3s ease-in-out infinite;
}
@keyframes sway {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
/* =========================
🕌 Smooth Kubah Swing
========================= */
.kubah-swing {
animation: kubahSwingSmooth 6s cubic-bezier(0.45, 0, 0.55, 1) infinite;
transform-origin: top center;
}
@keyframes kubahSwingSmooth {
0% { transform: rotate(0deg); }
20% { transform: rotate(2.5deg); }
40% { transform: rotate(-2.5deg); }
60% { transform: rotate(2deg); }
80% { transform: rotate(-2deg); }
100% { transform: rotate(0deg); }
}
/* =========================
Fade Animations
========================= */
.animate-fade-in-down {
animation: fadeInDown 1s ease-out forwards;
}
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
.animate-fade-in-up {
animation: fadeInUp 1s ease-out forwards;
}
.animate-fade-in-left {
animation: fadeInLeft 1s ease-out forwards;
}
.animate-fade-in-right {
animation: fadeInRight 1s ease-out forwards;
}
@keyframes fadeInDown {
@ -127,20 +205,32 @@ const currentYear = computed(() => new Date().getFullYear())
to { opacity: 1; transform: translateY(0); }
}
.animation-delay-300 {
animation-delay: 0.3s;
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.animation-delay-500 {
animation-delay: 0.5s;
@keyframes fadeInLeft {
from { opacity: 0; transform: translateX(-20px); }
to { opacity: 1; transform: translateX(0); }
}
.animation-delay-1200 {
animation-delay: 1.2s;
@keyframes fadeInRight {
from { opacity: 0; transform: translateX(20px); }
to { opacity: 1; transform: translateX(0); }
}
.animation-delay-1500 {
animation-delay: 1.5s;
/* =========================
Delay Utilities
========================= */
.animation-delay-300 { animation-delay: 0.3s; }
.animation-delay-600 { animation-delay: 0.6s; }
.animation-delay-1000 { animation-delay: 1s; }
/* =========================
🕌 Font Arabic
========================= */
.arabic-text {
font-family: 'Noto Naskh Arabic', serif;
}
</style>
```

View File

@ -31,7 +31,6 @@
<main
class="relative z-10 min-h-screen flex items-center justify-center p-4 transition-all duration-700 ease-in-out"
>
<!-- Landing Page -->
<KhitanA
v-if="currentSection === 'landing'"
:childName="formData.nama_panggilan"
@ -39,14 +38,11 @@
@next-page="switchSection('introduction')"
/>
<!-- Introduction -->
<KhitanIntroduction
v-if="currentSection === 'introduction'"
:form="formData"
/>
<!-- Event -->
<KhitanEvent
v-if="currentSection === 'event'"
:hari_tanggal_acara="formData.hari_tanggal_acara"
@ -54,7 +50,6 @@
:alamat="formData.alamat"
:link_gmaps="formData.link_gmaps"
:hitung_mundur_mulai="formData.hitung_mundur_mulai"
:hari_tanggal_syukuran="formData.hari_tanggal_syukuran"
:waktu_syukuran="formData.waktu_syukuran"
:alamat_syukuran="formData.alamat_syukuran"
@ -62,14 +57,11 @@
:hitung_mundur_selesai="formData.hitung_mundur_selesai"
/>
<!-- Gallery -->
<KhitanGallery
v-if="currentSection === 'gallery'"
:images="galleryImages"
/>
<!-- Guest Book -->
<KhitanSay
v-if="currentSection === 'say'"
:guestName="data.nama_tamu"
@ -77,18 +69,18 @@
@addMessage="addMessage"
/>
<!-- Thank You -->
<KhitanThankYou v-if="currentSection === 'thanks'" :childName="formData.nama_panggilan" :jsonData="formData" />
<KhitanThankYou
v-if="currentSection === 'thanks'"
:childName="formData.nama_panggilan"
:jsonData="formData"
/>
</main>
</div>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
import { ref, computed } from 'vue'
import { useRuntimeConfig } from '#app'
// ================== IMPORT KOMPONEN ==================
import KhitanA from '~/components/templates/khitan/KhitanA.vue'
import KhitanIntroduction from '~/components/templates/khitan/Introduction.vue'
import KhitanEvent from '~/components/templates/khitan/Event.vue'
@ -96,28 +88,18 @@ import KhitanGallery from '~/components/templates/khitan/Gallery.vue'
import KhitanSay from '~/components/templates/khitan/GuestBook.vue'
import KhitanThankYou from '~/components/templates/khitan/ThankYou.vue'
// ================== PROPS ==================
const props = defineProps({
data: { type: Object, required: true }
})
// ================== BACKEND CONFIG ==================
const config = useRuntimeConfig()
const backendUrl = config.public.apiBaseUrl
// ================== FORM DATA ==================
const formData = computed(() => props.data.form || {})
// ================== GALERI ==================
const galleryImages = computed(() => {
const f = formData.value.foto
if (Array.isArray(f)) {
return f.map(img => `${backendUrl}/storage/${img}`)
}
// Jika masih bentuk lama (foto_1, foto_2, dst.)
return [
formData.value.foto_1,
formData.value.foto_2,
@ -127,17 +109,9 @@ const galleryImages = computed(() => {
].filter(Boolean).map(img => `${backendUrl}/${img}`)
})
// Foto utama diambil dari foto pertama
const mainPhoto = computed(() => {
const firstPhoto = formData.value.foto?.[0]
return firstPhoto ? `${backendUrl}/${firstPhoto}` : ''
})
// ================== NAVIGASI SECTION ==================
const currentSection = ref('landing')
const switchSection = (s) => (currentSection.value = s)
// ================== MUSIK ==================
const audioPlayer = ref(null)
const isPlaying = ref(false)
const musicUrl = computed(() =>
@ -154,11 +128,9 @@ const toggleMusic = () => {
isPlaying.value = !isPlaying.value
}
// ================== GUEST BOOK ==================
const messages = ref([])
const addMessage = (msg) => messages.value.push(msg)
// ================== STYLE NAV ==================
const navClass = (s) =>
currentSection.value === s
? 'text-blue-800 underline'
@ -166,6 +138,31 @@ const navClass = (s) =>
</script>
<style scoped>
/* Pastikan benar-benar fullscreen */
html,
body,
:host,
div[min-h-screen],
.min-h-screen {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
/* Hilangkan white space akibat scroll */
body {
overflow-x: hidden;
background: transparent;
}
/* Pastikan gradient menutup seluruh layar */
div[min-h-screen] {
position: relative;
inset: 0;
}
/* Transisi section tetap */
main {
transition: all 0.7s ease-in-out;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB