This commit is contained in:
Baghaztra 2025-10-22 17:09:53 +07:00
commit 8d84a54e79
17 changed files with 1079 additions and 290 deletions

View File

@ -4,14 +4,14 @@
<img
src="/balloon2.png"
alt="Balloons Left"
class="fixed left-0 bottom-0 w-64 md:w-80 lg:w-96 opacity-90 animate-swing-left select-none pointer-events-none z-0 balloon-left -translate-x-[53%]"
class="fixed left-0 bottom-0 w-52 md:w-80 lg:w-96 opacity-90 animate-swing-left select-none pointer-events-none z-0 balloon-left -translate-x-[53%]"
/>
<!-- Balon kanan - di ujung kanan -->
<img
src="/balloon2.png"
alt="Balloons Right"
class="fixed right-0 bottom-0 w-64 md:w-80 lg:w-96 opacity-90 animate-swing-right select-none pointer-events-none z-0 balloon-right translate-x-[54%]"
class="fixed right-0 bottom-0 w-52 md:w-80 lg:w-96 opacity-90 animate-swing-right select-none pointer-events-none z-0 balloon-right translate-x-[54%]"
/>
<!-- Judul -->

View File

@ -1,10 +1,10 @@
<template>
<div class="relative p-6 text-center max-w-4xl mx-auto">
<div class="relative p-6 text-center max-w-6xl mx-auto">
<!-- Gambar Happy Birthday di belakang -->
<img
src="/happy1.png"
alt="Happy Birthday"
class="absolute top-[-59%] left-1/2 transform w-80 md:w-96 opacity-90 z-0 animate-happy-drop"
class="absolute top-[-59%] left-1/2 transform w-80 md:w-96 opacity-90 z-0 animate-happy-drop"
/>
<h2
@ -13,22 +13,28 @@
📸 Galeri Foto 📸
</h2>
<!-- Grid galeri -->
<div
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 relative z-10"
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 relative z-10"
>
<div
v-for="(img, i) in images"
:key="i"
class="group relative overflow-hidden rounded-2xl shadow-lg transform hover:scale-105 transition-all duration-500"
>
<!-- Overlay saat hover -->
<div
class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-10"
></div>
<!-- Gambar -->
<img
:src="img"
alt="Galeri"
class="w-full h-64 object-cover transform group-hover:scale-110 transition-transform duration-500"
/>
<!-- Teks muncul saat hover -->
<div
class="absolute bottom-0 left-0 right-0 p-4 text-white transform translate-y-full group-hover:translate-y-0 transition-transform duration-300 z-20"
>
@ -37,6 +43,7 @@
</div>
</div>
<!-- Pesan jika belum ada foto -->
<div
v-if="images.length === 0"
class="bg-white/80 rounded-2xl p-8 shadow-lg relative z-10"
@ -48,7 +55,10 @@
<script setup>
defineProps({
images: Array
images: {
type: Array,
default: () => []
}
})
</script>

View File

@ -1,10 +1,29 @@
<template>
<div class="p-6 text-center max-w-2xl mx-auto">
<h2 class="text-4xl font-bold bg-gradient-to-r from-orange-600 to-yellow-600 bg-clip-text text-transparent mb-8">
<div class="p-6 text-center max-w-2xl mx-auto relative">
<h2
class="text-4xl font-bold bg-gradient-to-r from-orange-600 to-yellow-600 bg-clip-text text-transparent mb-8"
>
💌 Buku Tamu 💌
</h2>
<div class="bg-white/80 backdrop-blur-lg rounded-2xl p-8 shadow-xl border border-yellow-100 mb-8">
<!-- 🎈 Balon Kiri -->
<img
src="/balloon2.png"
alt="Balloons Left"
class="absolute w-32 md:w-40 -top-12 -left-7.5 animate-swing-top pointer-events-none select-none"
/>
<!-- 🎈 Balon Kanan -->
<img
src="/balloon2.png"
alt="Balloons Right"
class="absolute w-32 md:w-40 -top-12 -right-10.5 animate-swing-top pointer-events-none select-none"
/>
<!-- 💌 Card Utama -->
<div
class="bg-white/80 backdrop-blur-lg rounded-2xl p-8 shadow-xl border border-yellow-100 mb-8 relative z-10"
>
<form @submit.prevent="submitMessage" class="space-y-4">
<textarea
v-model="newMessage"
@ -23,7 +42,8 @@
</form>
</div>
<div class="space-y-4 max-h-96 overflow-y-auto px-2">
<!-- 💬 Daftar Pesan -->
<div class="space-y-4 max-h-96 overflow-y-auto px-2 relative z-10">
<div
v-for="(msg, i) in messages"
:key="i"
@ -38,7 +58,9 @@
</div>
<div v-if="messages.length === 0" class="bg-white/60 p-8 rounded-2xl">
<p class="text-gray-600">Belum ada ucapan. Jadilah yang pertama mengucapkan!</p>
<p class="text-gray-600">
Belum ada ucapan. Jadilah yang pertama mengucapkan!
</p>
</div>
</div>
</div>
@ -60,4 +82,23 @@ function submitMessage() {
emit('addMessage', newMessage.value)
newMessage.value = ''
}
</script>
</script>
<style scoped>
@keyframes swing-top {
0% {
transform: rotate(2deg);
}
50% {
transform: rotate(-2deg);
}
100% {
transform: rotate(2deg);
}
}
.animate-swing-top {
animation: swing-top 4s ease-in-out infinite;
transform-origin: bottom center; /* ✅ Balon berayun dari bawah (tali diam) */
}
</style>

View File

@ -1,33 +1,59 @@
<template>
<div class="flex flex-col items-center text-center p-6 space-y-6 max-w-2xl mx-auto">
<!-- Photo frame with decoration -->
<div class="relative">
<div class="absolute -inset-4 bg-gradient-to-r from-yellow-400 to-orange-400 rounded-full blur opacity-30"></div>
<img
v-if="childPhoto"
:src="childPhoto"
alt="Foto Anak"
class="relative w-48 h-48 rounded-full object-cover border-4 border-white shadow-2xl z-10"
/>
<div v-else class="relative w-48 h-48 rounded-full bg-gradient-to-br from-yellow-200 to-orange-200 border-4 border-white shadow-2xl flex items-center justify-center z-10">
<span class="text-4xl">👶</span>
</div>
<div>
<!-- 🎈 Balon Background - Fixed di seluruh layar -->
<div class="fixed inset-0 w-full h-full overflow-hidden z-0 pointer-events-none">
<!-- Balon Kiri -->
<img src="/balon1.png" alt="Balon" class="absolute w-26 animate-fly-slow" style="left: 5%; bottom: -150px;" />
<img src="/balon2.png" alt="Balon" class="absolute w-24 animate-fly-medium delay-[0.5s]" style="left: 10%; bottom: -200px;" />
<img src="/balon3.png" alt="Balon" class="absolute w-26 animate-fly-fast delay-[1s]" style="left: 2%; bottom: -250px;" />
<img src="/balon1.png" alt="Balon" class="absolute w-24 animate-fly-slow delay-[1.5s]" style="left: 8%; bottom: -300px;" />
<!-- Balon Kanan -->
<img src="/balon2.png" alt="Balon" class="absolute w-26 animate-fly-medium" style="right: 5%; bottom: -150px;" />
<img src="/balon3.png" alt="Balon" class="absolute w-24 animate-fly-slow delay-[1s]" style="right: 10%; bottom: -200px;" />
<img src="/balon1.png" alt="Balon" class="absolute w-26 animate-fly-fast delay-[2s]" style="right: 2%; bottom: -250px;" />
<img src="/balon2.png" alt="Balon" class="absolute w-24 animate-fly-slow delay-[2.5s]" style="right: 8%; bottom: -300px;" />
</div>
<div class="bg-white/80 backdrop-blur-md rounded-2xl p-8 shadow-xl border border-yellow-100">
<h2 class="text-4xl font-bold bg-gradient-to-r from-orange-600 to-yellow-600 bg-clip-text text-transparent mb-4">
Halo, Aku {{ childName }}
</h2>
<div class="space-y-3 text-gray-700">
<p class="text-xl font-semibold">Usiaku kini <span class="text-orange-500">{{ age }}</span> tahun 🎉</p>
<p class="text-gray-600">Putra/Putri dari</p>
<p class="text-xl font-bold text-gray-800 bg-gradient-to-r from-orange-400 to-yellow-400 bg-clip-text text-transparent">
{{ parentsName }}
<!-- Container Konten Utama -->
<div class="relative flex flex-col items-center text-center p-6 space-y-6 max-w-2xl mx-auto">
<!-- Foto Anak -->
<div class="relative z-10 mb-6 group transition-transform duration-500 hover:scale-105">
<div class="absolute -inset-4 bg-gradient-to-r from-yellow-400 to-orange-400 rounded-full blur opacity-30 transition-all duration-500 group-hover:opacity-60 group-hover:blur-lg"></div>
<img
v-if="childPhoto"
:src="childPhoto"
alt="Foto Anak"
class="relative w-48 h-48 rounded-full object-cover border-4 border-white shadow-2xl z-10 transition-all duration-500 group-hover:shadow-[0_0_25px_rgba(255,165,0,0.6)]"
/>
<div
v-else
class="relative w-48 h-48 rounded-full bg-gradient-to-br from-yellow-200 to-orange-200 border-4 border-white shadow-2xl flex items-center justify-center z-10 transition-all duration-500 group-hover:shadow-[0_0_25px_rgba(255,165,0,0.6)]"
>
<span class="text-4xl">👶</span>
</div>
</div>
<!-- Kartu Ucapan -->
<div
class="bg-white/80 backdrop-blur-md rounded-2xl p-8 shadow-xl border border-yellow-100 z-10 transition-all duration-500 hover:scale-105 hover:shadow-[0_0_30px_rgba(255,200,0,0.4)]"
>
<h2 class="text-4xl font-bold bg-gradient-to-r from-orange-600 to-yellow-600 bg-clip-text text-transparent mb-4">
Halo, Aku {{ childName }}
</h2>
<div class="space-y-3 text-gray-700">
<p class="text-xl font-semibold">
Usiaku kini <span class="text-orange-500">{{ age }}</span> tahun 🎉
</p>
<p class="text-gray-600">Putra/Putri dari</p>
<p class="text-xl font-bold text-gray-800 bg-gradient-to-r from-orange-400 to-yellow-400 bg-clip-text text-transparent">
{{ parentsName }}
</p>
</div>
<p class="mt-6 text-lg text-gray-600 italic">
Aku sangat senang jika kamu bisa hadir di pesta ulang tahunku!
</p>
</div>
<p class="mt-6 text-lg text-gray-600 italic">
Aku sangat senang jika kamu bisa hadir di pesta ulang tahunku!
</p>
</div>
</div>
</template>
@ -39,4 +65,40 @@ defineProps({
age: [String, Number],
childPhoto: String
})
</script>
</script>
<style scoped>
@keyframes flyUp {
0% {
transform: translateY(100vh) scale(0.9) rotate(0deg);
opacity: 0;
}
70% {
opacity: 1;
}
100% {
transform: translateY(-110vh) scale(1.05) rotate(10deg);
opacity: 0;
}
}
/* 💨 Durasi lebih cepat agar terasa ramai */
.animate-fly-slow {
animation: flyUp 8s linear infinite;
}
.animate-fly-medium {
animation: flyUp 6s linear infinite;
}
.animate-fly-fast {
animation: flyUp 4s linear infinite;
}
/* ⏱️ Delay singkat agar balon muncul hampir bersamaan */
.delay-\[0\.5s\] { animation-delay: 0.5s; }
.delay-\[1s\] { animation-delay: 1s; }
.delay-\[1\.5s\] { animation-delay: 1.5s; }
.delay-\[2s\] { animation-delay: 2s; }
.delay-\[2\.5s\] { animation-delay: 2.5s; }
</style>

View File

@ -1,14 +1,34 @@
<template>
<div class="flex flex-col items-center justify-center text-center p-6 space-y-8 max-w-2xl mx-auto">
<h2 class="text-4xl font-bold bg-gradient-to-r from-orange-600 to-yellow-600 bg-clip-text text-transparent">
<div class="flex flex-col items-center justify-center text-center p-6 space-y-8 max-w-2xl mx-auto relative overflow-hidden min-h-screen">
<!-- 🎈 BALLOON BACKGROUND -->
<div class="balloon-container">
<div class="balloon balloon-left-1">
<img src="/balloon1.png" alt="Balloon" class="w-32 h-auto" />
</div>
<div class="balloon balloon-left-2">
<img src="/balloon1.png" alt="Balloon" class="w-32 h-auto" />
</div>
<div class="balloon balloon-right-1">
<img src="/balloon1.png" alt="Balloon" class="w-32 h-auto" />
</div>
<div class="balloon balloon-right-2">
<img src="/balloon1.png" alt="Balloon" class="w-32 h-auto" />
</div>
</div>
<!-- 🎀 THANK YOU CARD -->
<h2 class="text-4xl font-bold bg-gradient-to-r from-orange-600 to-yellow-600 bg-clip-text text-transparent z-10">
Terima Kasih! 🙏
</h2>
<div class="bg-white/80 backdrop-blur-lg rounded-2xl p-8 shadow-xl border border-yellow-100 space-y-6">
<div class="bg-white/80 backdrop-blur-lg rounded-2xl p-8 shadow-xl border border-yellow-100 space-y-6 z-10">
<p class="text-lg text-gray-700">Sudah meluangkan waktu untuk melihat undangan ulang tahunku 💛</p>
<p class="text-xl font-semibold text-gray-800">
Salam hangat dari <span class="bg-gradient-to-r from-orange-500 to-yellow-500 bg-clip-text text-transparent font-bold">{{ childName }}</span>
Salam hangat dari
<span class="bg-gradient-to-r from-orange-500 to-yellow-500 bg-clip-text text-transparent font-bold">
{{ childName }}
</span>
</p>
<div v-if="jsonData?.pesan_terimakasih" class="bg-gradient-to-r from-yellow-100 to-orange-100 p-6 rounded-xl border-l-4 border-orange-400">
@ -21,7 +41,8 @@
</div>
</div>
<div class="flex space-x-4 mt-6">
<!-- EMOJI ANIMATION -->
<div class="flex space-x-4 mt-6 z-10">
<div class="animate-bounce">🎈</div>
<div class="animate-bounce delay-100">🎁</div>
<div class="animate-bounce delay-200">🍰</div>
@ -35,4 +56,67 @@ defineProps({
childName: String,
jsonData: Object
})
</script>
</script>
<style scoped>
.balloon-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
overflow: hidden;
z-index: 1;
}
/* BALLOON ANIMATION */
.balloon {
position: absolute;
bottom: -150px;
opacity: 0;
animation: floatUp 12s ease-in-out infinite;
}
.balloon-left-1 {
left: 8%;
animation-delay: 0s;
}
.balloon-left-2 {
left: 20%;
animation-delay: 4s;
}
.balloon-right-1 {
right: 8%;
animation-delay: 2s;
}
.balloon-right-2 {
right: 22%;
animation-delay: 6s;
}
@keyframes floatUp {
0% {
transform: translateY(0) scale(0.8) rotate(0deg);
opacity: 0;
}
10% {
opacity: 1;
}
60% {
transform: translateY(-60vh) scale(1) rotate(10deg);
opacity: 0.9;
}
80% {
transform: translateY(-80vh) scale(1.1) rotate(-10deg);
opacity: 0.5;
}
100% {
transform: translateY(-100vh) scale(1.2) rotate(15deg);
opacity: 0;
}
}
</style>

View File

@ -1,35 +1,138 @@
<template>
<div class="min-h-screen flex flex-col items-center justify-center text-center bg-orange-100 py-10 px-6">
<h2 class="text-3xl font-bold text-orange-700 mb-4">📅 Detail Acara</h2>
<section
class="relative w-full h-screen flex flex-col justify-center items-center overflow-hidden text-center bg-gradient-to-b from-purple-900 via-red-900 to-black text-white px-6"
>
<!-- Judul -->
<h1 class="text-4xl md:text-5xl font-extrabold text-yellow-400 drop-shadow-lg mb-6">
Detail Petualangan
</h1>
<div class="bg-white rounded-2xl shadow-md p-6 w-full max-w-md text-gray-700">
<p class="mb-2"><strong>Hari & Tanggal:</strong> {{ formatDate(hari_tanggal_acara) }}</p>
<p class="mb-2"><strong>Waktu:</strong> {{ waktu }}</p>
<p class="mb-2"><strong>Alamat:</strong> {{ alamat }}</p>
<!-- Kotak konten utama -->
<div
class="bg-black/60 rounded-2xl p-6 md:p-8 w-full max-w-2xl shadow-[0_0_25px_rgba(255,255,255,0.1)] flex flex-col gap-4"
>
<!-- Hari & Tanggal -->
<div class="flex items-center gap-4 border border-red-600 rounded-lg p-4 bg-gradient-to-r from-red-800/40 to-red-900/30">
<div class="text-3xl">📅</div>
<div class="text-left">
<h2 class="font-semibold text-red-400">Hari & Tanggal</h2>
<p class="text-white font-medium">Rabu, 22 Oktober 2025</p>
</div>
</div>
<a
v-if="link_gmaps"
:href="link_gmaps"
target="_blank"
class="inline-block mt-4 bg-orange-600 text-white py-2 px-6 rounded-full hover:bg-orange-700 transition"
<!-- Waktu -->
<div class="flex items-center gap-4 border border-blue-600 rounded-lg p-4 bg-gradient-to-r from-blue-800/40 to-blue-900/30">
<div class="text-3xl"></div>
<div class="text-left">
<h2 class="font-semibold text-blue-400">Waktu Acara</h2>
<p class="text-white font-medium">18.00</p>
</div>
</div>
<!-- Lokasi -->
<div class="flex items-center gap-4 border border-yellow-600 rounded-lg p-4 bg-gradient-to-r from-yellow-800/40 to-yellow-900/30">
<div class="text-3xl">📍</div>
<div class="text-left">
<h2 class="font-semibold text-yellow-400">Lokasi Petualangan</h2>
<p class="text-white font-medium">jkbjkb</p>
</div>
</div>
<!-- Tombol Maps -->
<button
class="mt-4 bg-gray-800 text-white px-6 py-3 rounded-full font-semibold hover:bg-gray-700 transition-all duration-300 mx-auto flex items-center gap-2"
>
📍 Lihat di Google Maps
</a>
🗺 Link Maps Menyusul
</button>
</div>
</div>
<!-- Catatan -->
<p
class="mt-6 text-sm md:text-base italic text-yellow-300 max-w-2xl text-center leading-relaxed"
>
Bersiaplah untuk berayun-ayun dalam keseruan! Kostum Spider-Man opsional tapi sangat disarankan!
Jangan lupa bawa kekuatan super dan senyuman! 🕷
</p>
</section>
</template>
<script setup>
import { ref, onMounted } from "vue";
defineProps({
hari_tanggal_acara: String,
waktu: String,
alamat: String,
link_gmaps: String
})
link_gmaps: String,
});
const showSpider = ref(false);
onMounted(() => {
setTimeout(() => {
showSpider.value = true;
}, 2000);
});
const formatDate = (dateStr) => {
if (!dateStr) return '-'
const d = new Date(dateStr)
return d.toLocaleDateString('id-ID', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })
}
if (!dateStr) return "Akan diumumkan";
try {
const d = new Date(dateStr);
return d.toLocaleDateString("id-ID", {
weekday: "long",
day: "numeric",
month: "long",
year: "numeric",
});
} catch {
return dateStr;
}
};
</script>
<style scoped>
/* 🕸️ Animasi Spider-Man */
@keyframes float-slow {
0%, 100% {
transform: translateY(0px) scaleX(-1);
}
50% {
transform: translateY(-25px) scaleX(-1);
}
}
.animate-float-slow {
animation: float-slow 6s ease-in-out infinite;
}
/* 🕷️ Transisi Spider muncul */
.fade-slide-enter-active {
transition: all 1s ease;
}
.fade-slide-enter-from {
opacity: 0;
transform: translateY(-40px);
}
/* 🕷️ Bounce kecil */
@keyframes bounce {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-12px);
}
}
.animate-bounce {
animation: bounce 2s ease-in-out infinite;
}
/* 📱 Responsif untuk HP */
@media (max-width: 768px) {
img[alt="Spider-Man"] {
width: 6rem !important;
bottom: 3%;
left: 4%;
opacity: 0.6;
}
}
</style>

View File

@ -1,17 +1,70 @@
<template>
<div class="min-h-screen bg-yellow-100 py-10 px-4">
<h2 class="text-3xl font-bold text-orange-700 text-center mb-8">📸 Galeri Foto</h2>
<section
class="relative w-full min-h-screen bg-gradient-to-b from-blue-900 via-red-800 to-black text-white flex flex-col justify-center items-center overflow-hidden py-16 px-6"
>
<!-- Efek jaring latar -->
<div class="absolute inset-0 opacity-10 pointer-events-none">
<div class="absolute top-0 left-1/3 w-0.5 h-full bg-gradient-to-b from-blue-200 to-red-200"></div>
<div class="absolute top-0 left-2/3 w-0.5 h-full bg-gradient-to-b from-blue-200 to-red-200"></div>
<div class="absolute inset-0 bg-[radial-gradient(circle_at_center,rgba(255,255,255,0.15),transparent_70%)]"></div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6 max-w-5xl mx-auto">
<!-- Judul -->
<div class="relative z-10 text-center mb-12">
<h2
class="text-5xl md:text-6xl font-extrabold text-yellow-300 drop-shadow-[0_0_10px_rgba(255,255,0,0.4)] tracking-tight"
>
🕸 Galeri Petualangan 🕷
</h2>
<p class="mt-3 text-base md:text-lg text-gray-200 italic tracking-wide">
Momen seru para Spider-Hero yang tertangkap kamera!
</p>
<div class="w-32 h-1 bg-gradient-to-r from-red-500 to-blue-500 mx-auto mt-4 rounded-full"></div>
</div>
<!-- Grid Foto -->
<div
class="relative z-10 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 max-w-6xl mx-auto"
>
<div
v-for="(img, index) in images"
:key="index"
class="relative group overflow-hidden rounded-2xl shadow-md"
class="relative group rounded-2xl overflow-hidden shadow-[0_0_25px_rgba(255,255,255,0.15)] border border-white/10 bg-black/40 backdrop-blur-sm hover:shadow-[0_0_35px_rgba(255,0,0,0.4)] transition-all duration-500"
>
<img :src="img" alt="Foto" class="w-full h-64 object-cover transition-transform duration-300 group-hover:scale-110" />
<!-- Gambar -->
<img
:src="img"
alt="Foto"
class="w-full h-72 object-cover transform group-hover:scale-110 transition-transform duration-700 ease-out"
/>
<!-- Overlay hover -->
<div
class="absolute inset-0 bg-gradient-to-t from-black/80 via-black/30 to-transparent opacity-0 group-hover:opacity-100 transition-all duration-500 flex flex-col items-center justify-end pb-5"
>
<span class="text-yellow-300 font-semibold text-lg mb-1 drop-shadow-md">Photo {{ index + 1 }}</span>
<span class="text-sm text-gray-200">🕷 Klik untuk zoom</span>
</div>
<!-- Icon Spider -->
<div
class="absolute top-3 right-3 bg-gradient-to-r from-red-600 to-red-800 text-white px-3 py-1 rounded-full text-sm font-bold shadow-lg"
>
🕷
</div>
</div>
</div>
</div>
<!-- Empty State -->
<div
v-if="images.length === 0"
class="relative z-10 text-center mt-16 animate-pulse"
>
<div class="text-6xl mb-3">🕸</div>
<p class="text-xl font-semibold">Foto-foto sedang dalam petualangan...</p>
<p class="text-yellow-300 mt-2">Mereka akan segera muncul!</p>
</div>
</section>
</template>
<script setup>
@ -21,4 +74,31 @@ defineProps({
default: () => []
}
})
</script>
</script>
<style scoped>
/* Efek muncul halus untuk tiap foto */
.group {
animation: fadeInUp 0.8s ease both;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Responsif tambahan */
@media (max-width: 640px) {
h2 {
font-size: 2.25rem;
}
img {
height: 12rem;
}
}
</style>

View File

@ -1,28 +1,236 @@
<template>
<div class="flex flex-col items-center text-center min-h-screen bg-yellow-200 py-12 px-6">
<img
v-if="childPhoto"
:src="childPhoto"
alt="Foto Anak"
class="w-40 h-40 rounded-full shadow-lg mb-6 object-cover border-4 border-yellow-500"
/>
<section
class="relative w-full min-h-screen flex flex-col items-center justify-center overflow-hidden text-center bg-gradient-to-b from-blue-900 via-red-800 to-black text-white animate-fade-in"
>
<!-- 🕸 Background grid lembut -->
<div class="absolute inset-0 opacity-10 pointer-events-none">
<div class="absolute top-0 left-1/4 w-0.5 h-full bg-white/30"></div>
<div class="absolute top-0 left-2/4 w-0.5 h-full bg-white/30"></div>
<div class="absolute top-0 left-3/4 w-0.5 h-full bg-white/30"></div>
<div class="absolute top-1/4 left-0 w-full h-0.5 bg-white/30"></div>
<div class="absolute top-2/4 left-0 w-full h-0.5 bg-white/30"></div>
<div class="absolute top-3/4 left-0 w-full h-0.5 bg-white/30"></div>
</div>
<h2 class="text-3xl font-bold text-orange-700 mb-2">{{ childName }}</h2>
<p class="text-lg text-gray-700 mb-4">Berusia {{ age }} tahun 🎂</p>
<p class="text-md text-gray-600 mb-6">Putra/Putri dari {{ parentsName }}</p>
<!-- 🕷 Laba-laba animasi turun dari atas -->
<div
v-for="(spider, index) in spiders"
:key="index"
class="absolute text-3xl animate-spider-move"
:style="{
left: spider.left,
animationDelay: spider.delay,
fontSize: spider.size,
}"
>
🕷
</div>
<p class="max-w-md text-gray-700 leading-relaxed">
Dengan penuh sukacita, kami mengundang teman-teman dan keluarga untuk hadir dalam acara ulang tahun kami yang
ke-{{ age }}!
</p>
</div>
<!-- Konten utama -->
<div class="relative z-10 w-full px-6 max-w-2xl mt-16 md:mt-0 animate-slide-up">
<!-- Foto Anak -->
<div class="relative mb-8 flex justify-center">
<!-- Cahaya latar -->
<div
class="absolute w-72 h-72 md:w-80 md:h-80 rounded-full bg-gradient-to-br from-red-500 via-yellow-500 to-blue-600 blur-3xl opacity-60 animate-pulse-slow"
></div>
<!-- Foto anak -->
<img
v-if="childPhoto"
:src="childPhoto"
alt="Foto Anak"
class="relative w-56 h-56 md:w-64 md:h-64 rounded-full shadow-2xl object-cover border-4 border-white mx-auto transform hover:scale-105 transition duration-500 z-10"
/>
<!-- Placeholder jika foto belum ada -->
<div
v-else
class="relative w-56 h-56 md:w-64 md:h-64 rounded-full shadow-2xl bg-gradient-to-br from-red-600 to-blue-600 flex items-center justify-center mx-auto border-4 border-white z-10"
>
<span class="text-7xl">🕷</span>
</div>
</div>
<!-- Nama & Informasi -->
<h2 class="text-5xl md:text-6xl font-extrabold text-yellow-300 drop-shadow-lg mb-4 tracking-tight">
{{ childName || 'Spider Kid' }}
</h2>
<p class="text-xl md:text-2xl text-blue-200 mb-3 font-semibold">
Berusia {{ age || '?' }} tahun 🎂
</p>
<p class="text-lg md:text-xl text-gray-200 mb-8">
Putra/Putri dari {{ parentsName || 'Peter Parker & Mary Jane' }}
</p>
<!-- Deskripsi -->
<div class="bg-black/70 backdrop-blur-lg rounded-2xl p-6 border border-red-500/60 shadow-xl mb-8">
<p class="text-white leading-relaxed text-lg md:text-xl">
Dengan kekuatan
<span class="text-red-400 font-bold">Spider-Sense</span>
yang bergetar, kami mengundang Anda untuk bergabung dalam perayaan ulang tahun ke-
{{ age || '?' }} petualangan kami!
</p>
</div>
<!-- Info tambahan -->
<div class="flex flex-wrap gap-4 justify-center animate-bounce-slow">
<div
class="bg-red-600/90 text-white px-5 py-3 rounded-full text-base font-medium shadow-lg flex items-center gap-2"
>
<span>🕸</span>
<span>Anak ke-{{ childOrder || '?' }}</span>
</div>
<div
class="bg-blue-600/90 text-white px-5 py-3 rounded-full text-base font-medium shadow-lg flex items-center gap-2"
>
<span>🎭</span>
<span>{{ age || '?' }} Tahun</span>
</div>
</div>
</div>
</section>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const spiders = ref([])
// 🕷 Generate posisi dan delay acak
onMounted(() => {
for (let i = 0; i < 8; i++) {
spiders.value.push({
left: `${Math.random() * 90}%`,
delay: `${i * 1.8}s`,
size: `${Math.floor(Math.random() * 16) + 20}px`,
})
}
})
defineProps({
age: [String, Number],
childName: String,
childOrder: [String, Number],
parentsName: String,
childPhoto: String
childPhoto: String,
})
</script>
<style scoped>
/* ✨ Animasi masuk */
@keyframes fade-in {
from {
opacity: 0;
transform: scale(0.98);
}
to {
opacity: 1;
transform: scale(1);
}
}
.animate-fade-in {
animation: fade-in 1.2s ease-out;
}
/* ✨ Konten naik perlahan */
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(40px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-slide-up {
animation: slide-up 1.5s ease-out;
}
/* 🕷️ Laba-laba turun dari atas ke bawah */
@keyframes spider-move {
0% {
transform: translateY(-100px) rotate(0deg);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(30deg);
opacity: 0;
}
}
.animate-spider-move {
animation: spider-move 8s linear infinite;
top: -50px; /* Mulai dari atas layar */
}
/* 🕸️ Spider-Man melayang */
@keyframes float-slow {
0%,
100% {
transform: translateY(0px) rotate(0deg);
}
25% {
transform: translateY(-15px) rotate(2deg);
}
50% {
transform: translateY(-10px) rotate(0deg);
}
75% {
transform: translateY(-15px) rotate(-2deg);
}
}
.animate-float-slow {
animation: float-slow 8s ease-in-out infinite;
}
/* 🔥 Efek cahaya berdenyut */
@keyframes pulse-slow {
0%,
100% {
opacity: 0.6;
transform: scale(1);
}
50% {
opacity: 0.9;
transform: scale(1.1);
}
}
.animate-pulse-slow {
animation: pulse-slow 5s ease-in-out infinite;
}
/* 🩵 Info tambahan bergerak lembut */
@keyframes bounce-slow {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-6px);
}
}
.animate-bounce-slow {
animation: bounce-slow 3s ease-in-out infinite;
}
/* 📱 Responsif */
@media (max-width: 768px) {
img[alt='Spider-Man'] {
width: 16rem !important;
right: 0;
top: 15%;
opacity: 0.6;
}
}
</style>

View File

@ -1,21 +1,65 @@
<!-- components/templates/UltahStarter/Landing.vue -->
<template>
<div
class="flex flex-col items-center justify-center text-center min-h-screen px-6 py-10 text-white bg-gradient-to-b from-yellow-400 to-orange-500"
<section
class="relative flex flex-col items-center justify-center text-center h-screen w-screen text-white bg-gradient-to-b from-red-800 via-blue-900 to-black overflow-hidden"
>
<h1 class="text-4xl font-bold mb-4 animate-bounce">
🎉 Selamat Datang di Undangan Ulang Tahun 🎉
<!-- 🕸 BACKGROUND SPIDER WEB -->
<div class="absolute inset-0 opacity-15 animate-spin-slow">
<svg
viewBox="0 0 500 500"
xmlns="http://www.w3.org/2000/svg"
class="w-full h-full"
>
<g stroke="white" stroke-width="0.4" fill="none">
<circle cx="250" cy="250" r="60" />
<circle cx="250" cy="250" r="120" />
<circle cx="250" cy="250" r="180" />
<circle cx="250" cy="250" r="240" />
<circle cx="250" cy="250" r="300" />
<line x1="250" y1="0" x2="250" y2="500" />
<line x1="0" y1="250" x2="500" y2="250" />
<line x1="125" y1="0" x2="375" y2="500" />
<line x1="375" y1="0" x2="125" y2="500" />
</g>
</svg>
</div>
<!-- 🕷 SPIDER ICON -->
<div class="text-8xl mb-6 animate-pulse-slow drop-shadow-lg">🕷</div>
<!-- 🎉 TITLE -->
<h1
class="text-5xl md:text-6xl font-extrabold mb-6 text-red-400 drop-shadow-[0_0_12px_rgba(255,0,0,0.7)] animate-fade-down"
>
🕸 Spider-Man Birthday Invitation 🕸
</h1>
<p class="text-lg mb-2">Halo, <span class="font-semibold">{{ guestName || 'Tamu Spesial' }}</span>!</p>
<p class="text-xl font-semibold mb-8">Kami mengundangmu ke pesta ulang tahun {{ childName }} 🎂</p>
<!-- 👋 GREETING -->
<p class="text-xl mb-4 font-semibold animate-fade-up">
Halo,
<span class="text-red-300 font-bold">
{{ guestName || 'Friendly Neighborhood Guest' }}
</span>!
</p>
<!-- 🕶 EVENT INTRO -->
<p
class="text-2xl font-bold mb-10 text-yellow-100 drop-shadow-md animate-fade-up-delay"
>
Bergabunglah dalam petualangan ulang tahun {{ childName }}! 🎭
</p>
<!-- 🔘 BUTTON -->
<button
@click="$emit('open-invitation')"
class="bg-white text-orange-700 font-bold py-3 px-8 rounded-full shadow-lg hover:bg-yellow-100 transition"
class="relative bg-gradient-to-r from-red-600 to-blue-600 text-white font-bold py-4 px-10 rounded-full shadow-2xl border-2 border-white/40 overflow-hidden group transition-all duration-300 hover:scale-110"
>
Buka Undangan
<span class="relative z-10">🕷 Buka Undangan 🕸</span>
<div
class="absolute inset-0 bg-white/25 transform -skew-x-12 -translate-x-full group-hover:translate-x-full transition-transform duration-700"
></div>
</button>
</div>
</section>
</template>
<script setup>
@ -24,3 +68,39 @@ defineProps({
childName: String
})
</script>
<style scoped>
/* ───────────── Animations ───────────── */
@keyframes spin-slow {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes pulse-slow {
0%,100% { transform: scale(1); }
50% { transform: scale(1.15); }
}
@keyframes fade-down {
0% { opacity: 0; transform: translateY(-20px); }
100% { opacity: 1; transform: translateY(0); }
}
@keyframes fade-up {
0% { opacity: 0; transform: translateY(20px); }
100% { opacity: 1; transform: translateY(0); }
}
/* Utility classes */
.animate-spin-slow { animation: spin-slow 40s linear infinite; }
.animate-pulse-slow { animation: pulse-slow 3s ease-in-out infinite; }
.animate-fade-down { animation: fade-down 1s ease-out; }
.animate-fade-up { animation: fade-up 1.2s ease-out; }
.animate-fade-up-delay { animation: fade-up 1.8s ease-out; }
/* Pastikan layar penuh */
:host, html, body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow: hidden;
}
</style>

View File

@ -1,31 +1,135 @@
<template>
<div class="min-h-screen flex flex-col items-center justify-center bg-gradient-to-br from-orange-300 to-yellow-400 text-white text-center p-8">
<h2 class="text-4xl font-bold mb-4">Terima Kasih! 💖</h2>
<p class="text-lg mb-2">Atas kehadiran dan doa untuk {{ childName }}</p>
<p class="text-md mb-6">Semoga kebahagiaan selalu menyertai kita semua 🎉</p>
<div class="bg-white/20 rounded-2xl p-4 shadow-md max-w-md">
<p><strong>Nama Pemesan:</strong> {{ jsonData.nama_pemesan }}</p>
<p><strong>Email:</strong> {{ jsonData.email }}</p>
<p><strong>No Telepon:</strong> {{ jsonData.no_telepon }}</p>
<section
class="relative w-full min-h-screen bg-gradient-to-b from-blue-900 via-red-800 to-black text-white flex flex-col lg:flex-row items-center justify-between overflow-hidden"
>
<!-- 🌐 Efek jaring latar -->
<div class="absolute inset-0 opacity-10 pointer-events-none">
<div class="absolute top-0 left-1/3 w-0.5 h-full bg-gradient-to-b from-blue-200 to-red-200"></div>
<div class="absolute top-0 left-2/3 w-0.5 h-full bg-gradient-to-b from-blue-200 to-red-200"></div>
<div
class="absolute inset-0 bg-[radial-gradient(circle_at_center,rgba(255,255,255,0.15),transparent_70%)]"
></div>
</div>
<button
@click="reloadPage"
class="mt-8 bg-white text-orange-700 py-3 px-6 rounded-full font-semibold shadow hover:bg-yellow-100 transition"
<!-- 🕷 Laba-laba animasi -->
<div v-if="showSpider" class="absolute top-10 left-10 text-4xl animate-bounce hidden sm:block">🕷</div>
<div
v-if="showSpider"
class="absolute top-20 right-1/4 text-3xl animate-bounce hidden sm:block"
style="animation-delay: 0.5s;"
>🕸</div>
<div
v-if="showSpider"
class="absolute bottom-20 left-1/3 text-4xl animate-bounce hidden sm:block"
style="animation-delay: 1s;"
>🕷</div>
<!-- ================= FOTO SPIDERMAN (BACKGROUND UNTUK MOBILE) ================= -->
<div class="absolute inset-0 lg:hidden pointer-events-none">
<img
src="/spiderman.png"
alt="Spider-Man"
class="absolute inset-0 w-full h-full object-cover object-center opacity-40"
@error="onImageError"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent"></div>
</div>
<!-- ================= KONTEN TEKS (KIRI) ================= -->
<div
class="relative z-10 w-full lg:w-1/2 min-h-[50vh] flex flex-col justify-center items-center lg:items-start text-center lg:text-left px-6 lg:px-20 py-12 lg:py-0 space-y-8"
>
💌 Kembali ke Awal
</button>
</div>
<div class="text-5xl sm:text-6xl animate-bounce">🕷</div>
<h1
class="text-3xl sm:text-5xl lg:text-6xl font-extrabold text-yellow-300 drop-shadow-[0_0_10px_rgba(255,255,0,0.4)]"
>
Terima Kasih! 💙
</h1>
<p class="text-lg sm:text-2xl text-blue-200">
Atas kehadiran dan doa <span class="text-yellow-300 font-semibold">spider-power</span> untuk
</p>
<p
class="text-2xl sm:text-4xl font-bold text-yellow-300 bg-black/40 py-3 sm:py-4 px-6 sm:px-8 rounded-2xl border border-yellow-500/50"
>
{{ childName || 'Spider-Kid' }}
</p>
<div class="bg-black/50 backdrop-blur-lg rounded-2xl p-6 border border-red-500/50">
<p class="text-base sm:text-lg italic leading-relaxed">
"With great age comes great responsibility!
Semoga kebahagiaan selalu menyertai kita semua 🕸"
</p>
</div>
<!-- Tombol Kembali -->
<button
@click="reloadPage"
class="w-full bg-gradient-to-r from-red-600 to-blue-600 text-white py-4 px-8 rounded-full font-bold shadow-2xl hover:from-red-700 hover:to-blue-700 transition-all duration-300 transform hover:scale-105 border-2 border-white/30 text-lg flex items-center justify-center gap-3"
>
<span class="text-2xl">🕸</span>
Kembali ke Awal
<span class="text-2xl">🕷</span>
</button>
</div>
<!-- ================= FOTO SPIDERMAN (KANAN UNTUK DESKTOP) ================= -->
<div
class="hidden lg:flex absolute top-0 right-0 h-full w-1/2 justify-end items-center overflow-hidden"
>
<img
src="/spiderman.png"
alt="Spider-Man"
class="h-full w-auto object-cover object-right transform translate-x-10"
@error="onImageError"
/>
<!-- Efek gradasi ke kiri -->
<div class="absolute inset-0 bg-gradient-to-l from-black/80 via-black/50 to-transparent"></div>
</div>
</section>
</template>
<script setup>
import { ref, onMounted } from "vue";
defineProps({
childName: String,
jsonData: Object
})
jsonData: {
type: Object,
default: () => ({}),
},
});
const reloadPage = () => {
window.location.reload()
}
const showSpider = ref(false);
const reloadPage = () => window.location.reload();
const onImageError = (e) => {
e.target.src =
"https://images.unsplash.com/photo-1635805737707-575885ab0820?w=800&h=1000&fit=crop&auto=format";
e.target.alt = "Spider-Man Character";
};
onMounted(() => {
setTimeout(() => (showSpider.value = true), 1500);
});
</script>
<style scoped>
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-15px); }
}
.animate-bounce {
animation: bounce 2s ease-in-out infinite;
}
/* Responsif tambahan agar spiderman selalu kanan dan proporsional */
@media (max-width: 1024px) {
img[alt="Spider-Man"] {
object-position: center right;
}
}
</style>

View File

@ -85,12 +85,7 @@
/>
</main>
<!-- Footer -->
<footer
class="relative z-10 bg-white/50 backdrop-blur-md text-center py-4 text-gray-700 font-medium border-t border-yellow-300/50"
>
<p>© {{ new Date().getFullYear() }}</p>
</footer>
</div>
</template>

View File

@ -1,180 +1,202 @@
<template>
<div class="min-h-screen bg-gradient-to-br from-yellow-200 via-yellow-300 to-yellow-400 relative overflow-hidden">
<!-- Background decorations -->
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<div class="absolute top-10 left-10 w-20 h-20 bg-yellow-500/20 rounded-full blur-xl"></div>
<div class="absolute top-1/4 right-16 w-16 h-16 bg-orange-500/20 rounded-full blur-lg"></div>
<div class="absolute bottom-20 left-1/4 w-24 h-24 bg-pink-500/15 rounded-full blur-xl"></div>
<div class="absolute bottom-10 right-10 w-20 h-20 bg-red-500/15 rounded-full blur-lg"></div>
</div>
<!-- Navigation -->
<nav
v-if="currentSection !== 'landing'"
class="fixed top-6 left-1/2 transform -translate-x-1/2 z-20 animate-fade-in"
<div
class="relative min-h-screen w-full bg-gradient-to-br from-red-900 via-red-800 to-blue-900 overflow-hidden text-white"
>
<!-- 🕸 ANIMATED SPIDER-WEB BACKGROUND -->
<div class="absolute inset-0 opacity-15 animate-spin-slow">
<svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" class="w-full h-full">
<g stroke="white" stroke-width="0.4" fill="none">
<circle cx="250" cy="250" r="60" />
<circle cx="250" cy="250" r="120" />
<circle cx="250" cy="250" r="180" />
<circle cx="250" cy="250" r="240" />
<circle cx="250" cy="250" r="300" />
<line x1="250" y1="0" x2="250" y2="500" />
<line x1="0" y1="250" x2="500" y2="250" />
<line x1="125" y1="0" x2="375" y2="500" />
<line x1="375" y1="0" x2="125" y2="500" />
</g>
</svg>
</div>
<!-- 💫 LIGHT ORBS -->
<div class="absolute top-10 left-10 w-32 h-32 bg-red-500/30 rounded-full blur-2xl"></div>
<div class="absolute bottom-20 right-10 w-24 h-24 bg-blue-500/25 rounded-full blur-xl"></div>
<!-- 🕷 FLOATING ICONS -->
<div class="absolute top-16 right-16 text-6xl opacity-20 animate-bounce-slow">🕷</div>
<div class="absolute bottom-20 left-16 text-6xl opacity-20 animate-bounce-slow delay-700">🕸</div>
<!-- 🔻 NAVIGATION -->
<nav
v-if="currentSection !== 'landing'"
class="fixed top-6 left-1/2 transform -translate-x-1/2 z-30 animate-fade-in"
>
<ul
class="flex space-x-2 bg-black/70 backdrop-blur-lg px-6 py-3 rounded-full shadow-lg text-sm font-semibold text-white border border-red-500/60"
>
<ul
class="flex space-x-2 bg-white/70 backdrop-blur-lg px-6 py-3 rounded-full shadow-lg text-sm font-semibold text-gray-800 border border-yellow-200"
>
<li><button @click="switchSection('introduction')" :class="navClass('introduction')" class="px-3 py-1 rounded-full transition-all duration-300">Intro</button></li>
<li><button @click="switchSection('event')" :class="navClass('event')" class="px-3 py-1 rounded-full transition-all duration-300">Event</button></li>
<li><button @click="switchSection('gallery')" :class="navClass('gallery')" class="px-3 py-1 rounded-full transition-all duration-300">Gallery</button></li>
<li><button @click="switchSection('guestbook')" :class="navClass('guestbook')" class="px-3 py-1 rounded-full transition-all duration-300">Guest Book</button></li>
<li><button @click="switchSection('thanks')" :class="navClass('thanks')" class="px-3 py-1 rounded-full transition-all duration-300">Thanks</button></li>
</ul>
</nav>
<!-- Tombol Musik -->
<div class="fixed bottom-6 left-6 z-30" v-if="currentSection !== 'landing'">
<button
@click="toggleMusic"
class="bg-gradient-to-r from-yellow-500 to-orange-500 hover:from-yellow-600 hover:to-orange-600 p-4 rounded-full text-white shadow-xl transition-all duration-300 hover:scale-110 hover:shadow-2xl"
>
<span class="text-lg">{{ isPlaying ? '⏸️' : '▶️' }}</span>
</button>
</div>
<!-- Main Section -->
<main
class="relative z-10 min-h-screen flex items-center justify-center p-4 transition-all duration-700 ease-in-out"
<li v-for="section in sections" :key="section.key">
<button
@click="switchSection(section.key)"
:class="navClass(section.key)"
class="px-3 py-1 rounded-full transition-all duration-300"
>
{{ section.label }}
</button>
</li>
</ul>
</nav>
<!-- 🎵 MUSIC BUTTON -->
<div class="fixed bottom-6 left-6 z-40" v-if="currentSection !== 'landing'">
<button
@click="toggleMusic"
class="bg-gradient-to-r from-red-600 to-blue-600 hover:from-red-700 hover:to-blue-700 p-4 rounded-full shadow-2xl transition-all duration-300 hover:scale-110 animate-pulse-slow"
>
<!-- Landing -->
<Landing
v-if="currentSection === 'landing'"
:childName="formData.nama_panggilan"
:guestName="data.nama_tamu"
<span class="text-lg">{{ isPlaying ? '⏸️' : '▶️' }}</span>
</button>
</div>
<!-- 🌆 MAIN CONTENT -->
<main
class="relative z-20 h-screen w-screen flex items-center justify-center transition-all duration-700 ease-in-out overflow-hidden"
>
<transition name="fade" mode="out-in">
<component
:is="currentComponent"
:key="currentSection"
v-bind="componentProps"
@open-invitation="switchSection('introduction')"
/>
<!-- Introduction -->
<Introduction
v-if="currentSection === 'introduction'"
:age="formData.umur_yang_dirayakan"
:childName="formData.nama_lengkap"
:childOrder="formData.anak_ke"
:parentsName="`${formData.nama_bapak} & ${formData.nama_ibu}`"
:childPhoto="formData.foto && formData.foto.length ? `${backendUrl}/storage/${formData.foto[0]}` : null"
/>
<!-- Event -->
<Event
v-if="currentSection === 'event'"
:hari_tanggal_acara="formData.hari_tanggal_acara"
:waktu="formData.waktu"
:alamat="formData.alamat"
:link_gmaps="formData.link_gmaps"
:hitung_mundur="formData.hitung_mundur"
/>
<!-- Gallery -->
<Gallery v-if="currentSection === 'gallery'" :images="galleryImages" />
<!-- Guest Book -->
<GuestBook
v-if="currentSection === 'guestbook'"
:guestName="data.nama_tamu"
:messages="messages"
@addMessage="addMessage"
/>
<!-- Thank You -->
<ThankYou
v-if="currentSection === 'thanks'"
:childName="formData.nama_panggilan"
:jsonData="formData"
/>
</main>
<!-- Footer -->
<footer
class="relative z-10 bg-white/50 backdrop-blur-md text-center py-4 text-gray-700 font-medium border-t border-yellow-300/50"
>
<p>© {{ new Date().getFullYear() }}</p>
</footer>
</div>
</template>
<script setup>
import { ref, computed, watchEffect } from 'vue'
import { useRuntimeConfig } from '#app'
// Import Komponen
import Landing from '~/components/templates/UltahStarter/Landing.vue'
</transition>
</main>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useRuntimeConfig } from '#app'
// 🧩 Import Semua Komponen
import Landing from '~/components/templates/UltahStarter/Landing.vue'
import Introduction from '~/components/templates/UltahStarter/Introduction.vue'
import Event from '~/components/templates/UltahStarter/Event.vue'
import Gallery from '~/components/templates/UltahStarter/Gallery.vue'
import ThankYou from '~/components/templates/UltahStarter/ThankYou.vue'
// Props dari halaman induk
const props = defineProps({
data: { type: Object, required: true }
})
// Runtime config (untuk backend URL)
const config = useRuntimeConfig()
const backendUrl = config.public.apiBaseUrl
// Data dari backend
const formData = computed(() => props.data.form || {})
// FIX: Galeri gambar (hapus prefix public/, tambahkan /storage/)
const galleryImages = computed(() => {
const f = formData.value
const imageList = [
f.foto_1,
f.foto_2,
f.foto_3,
f.foto_4,
f.foto_5
].filter(Boolean)
return imageList.map(img => {
const cleanPath = img.replace(/^public\//, '')
return `${backendUrl}/storage/${cleanPath}`
})
})
watchEffect(() => {
console.log("🧾 formData:", formData.value)
console.log("🖼️ galleryImages:", galleryImages.value)
})
// Navigasi antar bagian
const currentSection = ref('landing')
const switchSection = (s) => (currentSection.value = s)
// Musik toggle
const isPlaying = ref(false)
const toggleMusic = () => (isPlaying.value = !isPlaying.value)
// Buku tamu
const messages = ref([])
const addMessage = (msg) => messages.value.push(msg)
// Style untuk navigasi aktif
const navClass = (s) =>
currentSection.value === s
? 'text-white bg-gradient-to-r from-orange-500 to-yellow-500 shadow-md'
: 'hover:text-orange-600 hover:bg-white/50'
</script>
<style scoped>
html {
scroll-behavior: smooth;
// Props dari induk
const props = defineProps({ data: Object })
// URL backend
const config = useRuntimeConfig()
const backendUrl = config.public.apiBaseUrl
// Data backend
const formData = computed(() => props.data.form || {})
// Gambar galeri
const galleryImages = computed(() => {
const f = formData.value
return [f.foto_1, f.foto_2, f.foto_3, f.foto_4, f.foto_5]
.filter(Boolean)
.map(img => `${backendUrl}/storage/${img.replace(/^public\//, '')}`)
})
// 🌍 Navigasi section
const currentSection = ref('landing')
const sections = [
{ key: 'introduction', label: 'Intro' },
{ key: 'event', label: 'Event' },
{ key: 'gallery', label: 'Gallery' },
{ key: 'thanks', label: 'Thanks' }
]
const switchSection = (section) => (currentSection.value = section)
// 🔊 Musik
const isPlaying = ref(false)
const toggleMusic = () => (isPlaying.value = !isPlaying.value)
// 💬 Buku tamu
const messages = ref([])
const addMessage = (msg) => messages.value.push(msg)
// 🎭 Komponen dinamis berdasarkan section
const currentComponent = computed(() => {
switch (currentSection.value) {
case 'landing': return Landing
case 'introduction': return Introduction
case 'event': return Event
case 'gallery': return Gallery
case 'guestbook': return GuestBook
case 'thanks': return ThankYou
default: return Landing
}
button {
transition: all 0.3s ease;
}
@keyframes fade-in {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.animate-fade-in {
animation: fade-in 0.5s ease-out;
}
</style>
})
// 🎁 Props untuk tiap komponen
const componentProps = computed(() => ({
childName: formData.value.nama_panggilan,
guestName: props.data.nama_tamu,
age: formData.value.umur_yang_dirayakan,
childOrder: formData.value.anak_ke,
parentsName: `${formData.value.nama_bapak} & ${formData.value.nama_ibu}`,
childPhoto: formData.value.foto?.length
? `${backendUrl}/storage/${formData.value.foto[0]}`
: null,
hari_tanggal_acara: formData.value.hari_tanggal_acara,
waktu: formData.value.waktu,
alamat: formData.value.alamat,
link_gmaps: formData.value.link_gmaps,
hitung_mundur: formData.value.hitung_mundur,
images: galleryImages.value,
messages: messages.value,
jsonData: formData.value
}))
// Style aktif navigasi
const navClass = (key) =>
currentSection.value === key
? 'bg-gradient-to-r from-red-600 to-blue-600 text-white shadow-lg'
: 'hover:text-red-400 hover:bg-black/40'
</script>
<style scoped>
/* 🌟 Animations */
@keyframes spin-slow {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes bounce-slow {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
@keyframes pulse-slow {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); }
}
/* ✨ Fade transition between sections */
.fade-enter-active, .fade-leave-active {
transition: opacity 0.8s ease, transform 0.8s ease;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
transform: scale(0.98);
}
.animate-spin-slow { animation: spin-slow 40s linear infinite; }
.animate-bounce-slow { animation: bounce-slow 4s ease-in-out infinite; }
.animate-pulse-slow { animation: pulse-slow 3s ease-in-out infinite; }
.animate-fade-in {
animation: fade-in 0.6s ease-out;
}
@keyframes fade-in {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB