premium
This commit is contained in:
parent
f044a14fa2
commit
3b6063d8c5
@ -2,3 +2,4 @@
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
|
||||
@ -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,17 +158,21 @@
|
||||
</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;
|
||||
}
|
||||
|
||||
@ -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>
|
||||
@ -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 -->
|
||||
|
||||
@ -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,14 +26,15 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Child Name -->
|
||||
<div
|
||||
class="bg-blue-800/50 border border-yellow-400 rounded-md px-6 py-2 mb-4 inline-block"
|
||||
>
|
||||
<h1 class="text-yellow-400 font-bold text-xl">
|
||||
<!-- Child Name with nickname.png background (Tailwind version) -->
|
||||
<div
|
||||
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 md:text-2xl font-script drop-shadow-lg">
|
||||
{{ form.nama_lengkap || 'Nama Anak' }}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Child Order -->
|
||||
<div v-if="form.anak_ke" class="text-white/80 text-lg mb-2">
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
</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>
|
||||
```
|
||||
@ -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,37 +38,30 @@
|
||||
@next-page="switchSection('introduction')"
|
||||
/>
|
||||
|
||||
<!-- Introduction -->
|
||||
<KhitanIntroduction
|
||||
v-if="currentSection === 'introduction'"
|
||||
:form="formData"
|
||||
/>
|
||||
|
||||
|
||||
<!-- Event -->
|
||||
<KhitanEvent
|
||||
<KhitanEvent
|
||||
v-if="currentSection === 'event'"
|
||||
:hari_tanggal_acara="formData.hari_tanggal_acara"
|
||||
:waktu="formData.waktu"
|
||||
: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"
|
||||
:link_gmaps_syukuran="formData.link_gmaps_syukuran"
|
||||
: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;
|
||||
}
|
||||
|
||||
BIN
proyek-frontend/public/kubah.png
Normal file
BIN
proyek-frontend/public/kubah.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
BIN
proyek-frontend/public/nickname.png
Normal file
BIN
proyek-frontend/public/nickname.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
Loading…
Reference in New Issue
Block a user