Undangan/proyek-frontend/app/components/templates/wedding/Couple.vue
2025-10-24 17:05:32 +07:00

532 lines
27 KiB
Vue

<!-- components/invitation/templates/wedding/WeddingA.vue -->
<template>
<div class="wedding-template-a min-h-screen bg-white">
<!-- Opening Cover -->
<section v-if="!isOpened" class="fixed inset-0 z-50 flex items-center justify-center bg-cover bg-center"
:style="{ backgroundImage: `url(${data.coverImage || '/wedding1.png'})` }">
<div class="absolute inset-0 bg-black/50"></div>
<div class="relative text-center text-white p-8">
<p class="text-xs uppercase tracking-widest mb-2 opacity-90">You are invited to the big day</p>
<p class="text-sm mb-6 opacity-80">We invited you to celebrate our wedding</p>
<p class="text-lg uppercase tracking-widest mb-4">THE WEDDING OF</p>
<h1 class="text-5xl md:text-7xl font-serif mb-8 italic" style="font-family: 'Great Vibes', cursive;">
{{ data.groom?.nickname || 'Asep' }} & {{ data.bride?.nickname || 'Putri' }}
</h1>
<p class="text-xl mb-8">{{ formatSimpleDate(data.eventDate) }}</p>
<button @click="openInvitation"
class="px-8 py-3 bg-transparent border-2 border-white text-white rounded-md font-medium hover:bg-white hover:text-gray-800 transition-all duration-300">
Open Invitation
</button>
</div>
</section>
<!-- Main Content -->
<div v-show="isOpened" class="animate-fade-in">
<!-- Hero Section -->
<section class="relative h-screen flex items-center justify-center overflow-hidden bg-cover bg-center"
:style="{ backgroundImage: `url(${data.heroImage || '/wedding1.png'})` }">
<div class="absolute inset-0 bg-black/40"></div>
<div class="relative text-center text-white px-4 z-10">
<div class="flex items-center justify-center gap-4 mb-6">
<div class="w-12 h-px bg-white"></div>
<Icon name="mdi:leaf" class="text-2xl" />
<div class="w-12 h-px bg-white"></div>
</div>
<h2 class="text-6xl md:text-8xl font-serif mb-6 italic" style="font-family: 'Great Vibes', cursive;">
{{ data.groom.nickname }} & {{ data.bride.nickname }}
</h2>
<p class="text-lg mb-6" data-aos="fade-up">
#{{ data.groom.nickname }}{{ data.bride.nickname }} #WishesAndWilderness #WeddedintheWoods
</p>
<p class="text-2xl font-light">{{ formatSimpleDate(data.eventDate) }}</p>
</div>
<div class="absolute bottom-8 left-1/2 transform -translate-x-1/2 animate-bounce">
<Icon name="mdi:chevron-down" class="text-white text-3xl" />
</div>
</section>
<!-- Couple Section -->
<section class="py-20 bg-white">
<div class="max-w-6xl mx-auto px-6">
<div class="text-center mb-16" data-aos="fade-up">
<div class="flex items-center justify-center gap-3 mb-4">
<div class="w-16 h-px bg-amber-400"></div>
<span class="text-amber-500 text-2xl">🌸</span>
<div class="w-16 h-px bg-amber-400"></div>
</div>
<h2 class="text-3xl md:text-4xl font-bold text-amber-500 mb-4">Meet The Happy Couple</h2>
<p class="text-gray-600 max-w-2xl mx-auto text-sm leading-relaxed">
Glory be to God, who has created beings in pairs. With God as guide, we invite you to share this
special day with us as we join together in marriage
</p>
</div>
<div class="grid md:grid-cols-2 gap-16 max-w-3xl mx-auto">
<!-- Groom -->
<div class="text-center" data-aos="fade-right">
<div class="relative inline-block mb-6">
<div class="w-36 h-36 md:w-44 md:h-44 rounded-full bg-white mx-auto overflow-hidden border-8 border-amber-100 shadow-lg">
<img :src="data.groom.photo || '/pria.jpg'" :alt="data.groom.fullname"
class="w-full h-full object-cover" />
</div>
</div>
<h3 class="text-3xl md:text-4xl font-bold text-amber-500 mb-2 italic" style="font-family: 'Great Vibes', cursive;">
{{ data.groom.nickname }}
</h3>
<p class="text-gray-800 font-semibold mb-1 text-sm">{{ data.groom.fullname }}</p>
<p class="text-xs text-gray-500 mb-4">
Son of Mr. {{ data.groom.fatherName }} & Mrs. {{ data.groom.motherName }}
</p>
<div class="flex justify-center space-x-2">
<a v-if="data.groom.instagram" :href="`https://instagram.com/${data.groom.instagram}`"
target="_blank" class="w-7 h-7 flex items-center justify-center bg-amber-400 text-white rounded-full hover:bg-amber-500 transition-colors">
<Icon name="mdi:instagram" class="text-sm" />
</a>
<a v-if="data.groom.twitter" :href="`https://twitter.com/${data.groom.twitter}`"
target="_blank" class="w-7 h-7 flex items-center justify-center bg-amber-400 text-white rounded-full hover:bg-amber-500 transition-colors">
<Icon name="mdi:twitter" class="text-sm" />
</a>
<a v-if="data.groom.facebook" :href="`https://facebook.com/${data.groom.facebook}`"
target="_blank" class="w-7 h-7 flex items-center justify-center bg-amber-400 text-white rounded-full hover:bg-amber-500 transition-colors">
<Icon name="mdi:facebook" class="text-sm" />
</a>
</div>
</div>
<!-- Bride -->
<div class="text-center" data-aos="fade-left">
<div class="relative inline-block mb-6">
<div class="w-36 h-36 md:w-44 md:h-44 rounded-full bg-white mx-auto overflow-hidden border-8 border-amber-100 shadow-lg">
<img :src="data.bride.photo || '/wanita.jpg'" :alt="data.bride.fullname"
class="w-full h-full object-cover" />
</div>
</div>
<h3 class="text-3xl md:text-4xl font-bold text-amber-500 mb-2 italic" style="font-family: 'Great Vibes', cursive;">
{{ data.bride.nickname }}
</h3>
<p class="text-gray-800 font-semibold mb-1 text-sm">{{ data.bride.fullname }}</p>
<p class="text-xs text-gray-500 mb-4">
Daughter of Mr. {{ data.bride.fatherName }} & Mrs. {{ data.bride.motherName }}
</p>
<div class="flex justify-center space-x-2">
<a v-if="data.bride.instagram" :href="`https://instagram.com/${data.bride.instagram}`"
target="_blank" class="w-7 h-7 flex items-center justify-center bg-amber-400 text-white rounded-full hover:bg-amber-500 transition-colors">
<Icon name="mdi:instagram" class="text-sm" />
</a>
<a v-if="data.bride.twitter" :href="`https://twitter.com/${data.bride.twitter}`"
target="_blank" class="w-7 h-7 flex items-center justify-center bg-amber-400 text-white rounded-full hover:bg-amber-500 transition-colors">
<Icon name="mdi:twitter" class="text-sm" />
</a>
<a v-if="data.bride.facebook" :href="`https://facebook.com/${data.bride.facebook}`"
target="_blank" class="w-7 h-7 flex items-center justify-center bg-amber-400 text-white rounded-full hover:bg-amber-500 transition-colors">
<Icon name="mdi:facebook" class="text-sm" />
</a>
</div>
</div>
</div>
<!-- Decorative Line with Leaf -->
<div class="flex items-center justify-center gap-3 mt-12 mb-8">
<div class="w-20 h-px bg-amber-300"></div>
<span class="text-amber-400 text-xl">🌸</span>
<div class="w-20 h-px bg-amber-300"></div>
</div>
<!-- Our Story Button -->
<div class="text-center">
<button @click="showStory = !showStory"
class="bg-amber-400 hover:bg-amber-500 text-white px-10 py-3 rounded-full font-semibold transition-colors shadow-lg text-sm">
{{ showStory ? 'Hide Our Story' : 'Our Story' }}
</button>
</div>
</div>
</section>
<!-- Our Story Section (Toggle) -->
<section v-if="showStory" class="py-20 bg-white">
<div class="max-w-4xl mx-auto px-6">
<div class="text-center mb-16" data-aos="fade-up">
<div class="flex items-center justify-center gap-3 mb-4">
<div class="w-16 h-px bg-amber-400"></div>
<Icon name="mdi:leaf" class="text-amber-500 text-2xl" />
<div class="w-16 h-px bg-amber-400"></div>
</div>
<h2 class="text-4xl md:text-5xl font-bold text-amber-600 mb-4">Our Story</h2>
</div>
<div class="grid md:grid-cols-2 gap-8">
<!-- Story with Image -->
<div data-aos="fade-right">
<img :src="data.story?.image1 || '/wedding1.png'" alt="Our Story" class="w-full h-80 object-cover rounded-lg shadow-lg mb-4" />
<p class="text-gray-700 leading-relaxed text-sm">
{{ data.story?.text1 || 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.' }}
</p>
</div>
<div data-aos="fade-left">
<p class="text-gray-700 leading-relaxed text-sm mb-4">
{{ data.story?.text2 || 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.' }}
</p>
<img :src="data.story?.image2 || '/wedding1.png'" alt="Our Story" class="w-full h-80 object-cover rounded-lg shadow-lg" />
</div>
</div>
</div>
</section>
<!-- Event Details -->
<section class="py-20 bg-gradient-to-b from-amber-50 to-white">
<div class="max-w-5xl mx-auto px-6">
<div class="text-center mb-16" data-aos="fade-up">
<div class="flex items-center justify-center gap-3 mb-4">
<div class="w-16 h-px bg-amber-400"></div>
<Icon name="mdi:leaf" class="text-amber-500 text-2xl" />
<div class="w-16 h-px bg-amber-400"></div>
</div>
<h2 class="text-4xl md:text-5xl font-bold text-amber-600 mb-4">We Are Getting Married</h2>
<p class="text-3xl font-serif italic mb-4" style="font-family: 'Great Vibes', cursive;">
#{{ data.groom.nickname }}And{{ data.bride.nickname }} #WishesAndWilderness #WeddedintheWoods
</p>
<p class="text-xl text-gray-700">{{ formatSimpleDate(data.eventDate) }}</p>
</div>
<!-- Countdown -->
<div class="mb-12">
<CountdownTimer :targetDate="data.eventDate" />
</div>
<!-- Event Cards -->
<div class="text-center mb-12">
<div class="flex items-center justify-center gap-3 mb-6">
<div class="w-12 h-px bg-amber-400"></div>
<Icon name="mdi:leaf" class="text-amber-500 text-xl" />
<div class="w-12 h-px bg-amber-400"></div>
</div>
<h3 class="text-3xl font-bold text-amber-600">Our Wedding Celebration</h3>
</div>
<div class="grid md:grid-cols-2 gap-6 max-w-3xl mx-auto">
<!-- Wedding Ceremony -->
<div class="relative bg-cover bg-center h-64 rounded-lg overflow-hidden shadow-xl"
:style="{ backgroundImage: `url(${data.akad.image || '/wedding1.png'})` }" data-aos="fade-right">
<div class="absolute inset-0 bg-gradient-to-b from-black/40 to-black/70"></div>
<div class="relative h-full flex flex-col justify-center items-center text-white p-6">
<Icon name="mdi:ring" class="text-4xl mb-3" />
<h4 class="text-2xl font-bold mb-2">Wedding Ceremony</h4>
<p class="text-sm mb-1">{{ formatSimpleDate(data.akad.date) }}</p>
<p class="text-sm mb-1">{{ data.akad.time }}</p>
<p class="text-sm text-center">{{ data.akad.place }}</p>
</div>
</div>
<!-- Wedding Party -->
<div class="relative bg-cover bg-center h-64 rounded-lg overflow-hidden shadow-xl"
:style="{ backgroundImage: `url(${data.resepsi.image || '/wedding1.png'})` }" data-aos="fade-left">
<div class="absolute inset-0 bg-gradient-to-b from-black/40 to-black/70"></div>
<div class="relative h-full flex flex-col justify-center items-center text-white p-6">
<Icon name="mdi:party-popper" class="text-4xl mb-3" />
<h4 class="text-2xl font-bold mb-2">Wedding Party</h4>
<p class="text-sm mb-1">{{ formatSimpleDate(data.resepsi.date) }}</p>
<p class="text-sm mb-1">{{ data.resepsi.time }}</p>
<p class="text-sm text-center">{{ data.resepsi.place }}</p>
</div>
</div>
</div>
<!-- Maps -->
<div class="mt-12 grid md:grid-cols-2 gap-6 max-w-3xl mx-auto">
<div data-aos="fade-up">
<Maps :location="data.akad.mapUrl" />
</div>
<div data-aos="fade-up">
<Maps :location="data.resepsi.mapUrl" />
</div>
</div>
</div>
</section>
<!-- Gallery -->
<section class="py-20 bg-white">
<div class="max-w-6xl mx-auto px-6">
<div class="text-center mb-16" data-aos="fade-up">
<div class="flex items-center justify-center gap-3 mb-4">
<div class="w-16 h-px bg-amber-400"></div>
<Icon name="mdi:leaf" class="text-amber-500 text-2xl" />
<div class="w-16 h-px bg-amber-400"></div>
</div>
<h2 class="text-4xl md:text-5xl font-bold text-amber-600 mb-4">Gallery</h2>
</div>
<Gallery :images="data.gallery" />
<p class="text-center text-sm text-gray-600 mt-8 max-w-2xl mx-auto">
Thank you to everyone who helped make our special day so wonderful. We are blessed to have you celebrate with us and wish there
could be more smiles, laughs, good food, and company we could share. Truly blessed.
</p>
</div>
</section>
<!-- Gift Section -->
<section class="py-20 bg-gradient-to-b from-amber-50 to-white">
<div class="max-w-4xl mx-auto px-6">
<div class="text-center mb-16" data-aos="fade-up">
<div class="flex items-center justify-center gap-3 mb-4">
<div class="w-16 h-px bg-amber-400"></div>
<Icon name="mdi:leaf" class="text-amber-500 text-2xl" />
<div class="w-16 h-px bg-amber-400"></div>
</div>
<h2 class="text-4xl md:text-5xl font-bold text-amber-600 mb-4">Give a Gift</h2>
<p class="text-gray-600 text-sm">
Your love, laughter, and company on our wedding day is the greatest gift of all. However if you wish
to honor us with a gift, we will gracefully accept it. Thank you!
</p>
</div>
<div class="grid md:grid-cols-2 gap-6">
<!-- Digital Wallet -->
<div class="bg-white rounded-xl shadow-lg p-8 border border-amber-100" data-aos="fade-right">
<h3 class="text-xl font-bold text-amber-600 mb-6">Digital Wallet</h3>
<p class="text-xs text-gray-500 mb-6">Tap card number to copy</p>
<div class="space-y-4">
<div v-for="(account, index) in digitalWallets" :key="index">
<div class="flex items-center gap-2 mb-2">
<span class="font-semibold text-gray-800">{{ account.name }}</span>
<img :src="account.logo" :alt="account.bank" class="h-5" />
</div>
<div class="flex items-center bg-amber-50 rounded-lg p-3 border border-amber-200 cursor-pointer hover:bg-amber-100 transition-colors"
@click="copyToClipboard(account.number)">
<span class="flex-1 text-gray-700 font-mono text-sm">{{ account.number }}</span>
<Icon name="mdi:content-copy" class="text-amber-600 text-lg" />
</div>
</div>
</div>
</div>
<!-- Offline Gift -->
<div class="bg-white rounded-xl shadow-lg p-8 border border-amber-100" data-aos="fade-left">
<h3 class="text-xl font-bold text-amber-600 mb-6">Offline Gift</h3>
<p class="text-gray-700 text-sm mb-6">
{{ data.gift?.address || 'Jl. Terusan Jakarta No.53, Cicaheum, Kec. Kiaracondong, Kota Bandung, Jawa Barat 40291' }}
</p>
<a :href="data.gift?.mapUrl || 'https://maps.google.com'" target="_blank"
class="flex items-center justify-center gap-2 w-full bg-amber-500 hover:bg-amber-600 text-white px-6 py-3 rounded-lg transition-colors shadow-md">
<Icon name="mdi:map-marker" class="text-xl" />
<span>Open Map</span>
</a>
</div>
</div>
</div>
</section>
<!-- RSVP Section -->
<section class="py-20 bg-white">
<div class="max-w-2xl mx-auto px-6">
<div class="text-center mb-16" data-aos="fade-up">
<div class="flex items-center justify-center gap-3 mb-4">
<div class="w-16 h-px bg-amber-400"></div>
<Icon name="mdi:leaf" class="text-amber-500 text-2xl" />
<div class="w-16 h-px bg-amber-400"></div>
</div>
<h2 class="text-4xl md:text-5xl font-bold text-amber-600 mb-4">Say Something!</h2>
</div>
<RSVP :invitationId="data.id" @submitted="handleRSVPSubmit" />
</div>
</section>
<!-- Footer -->
<footer class="relative py-20 bg-cover bg-center" :style="{ backgroundImage: `url(${data.footerImage || '/wedding1.png'})` }">
<div class="absolute inset-0 bg-gradient-to-b from-black/60 to-black/80"></div>
<div class="relative z-10 text-center text-white px-6">
<div class="mb-8">
<Icon name="mdi:heart" class="text-5xl mb-6" />
</div>
<div class="flex items-center justify-center gap-6 mb-8">
<div class="px-8 py-4 bg-white/20 backdrop-blur-sm rounded-lg border border-white/30">
<p class="text-3xl font-serif italic" style="font-family: 'Great Vibes', cursive;">{{ data.groom.nickname }}</p>
</div>
<span class="text-2xl">-</span>
<div class="px-8 py-4 bg-white/20 backdrop-blur-sm rounded-lg border border-white/30">
<p class="text-3xl font-serif italic" style="font-family: 'Great Vibes', cursive;">{{ data.bride.nickname }}</p>
</div>
</div>
<Icon name="mdi:flower" class="text-3xl mb-6" />
<img src="/ABBAUF.png" alt="Logo" class="h-12 mx-auto mb-4 opacity-90" />
<p class="text-sm opacity-70">© 2024 All rights reserved</p>
</div>
</footer>
<!-- Music Player -->
<MusicPlayer v-if="data.musicUrl" :url="data.musicUrl" :autoplay="true" />
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import AOS from 'aos'
import 'aos/dist/aos.css'
import CountdownTimer from '~/components/templates/wedding/CountdownTimer.vue'
import Gallery from '~/components/templates/wedding/Gallery.vue'
import Maps from '~/components/templates/wedding/Maps.vue'
import RSVP from '~/components/templates/wedding/RSVP.vue'
import MusicPlayer from '~/components/templates/wedding/MusicPlayer.vue'
const props = defineProps({
data: {
type: Object,
required: true,
default: () => ({
id: '',
coverImage: '',
heroImage: '',
footerImage: '',
greeting: '',
eventDate: new Date(),
bride: {
fullname: '',
nickname: '',
photo: '',
fatherName: '',
motherName: '',
instagram: '',
twitter: '',
facebook: ''
},
groom: {
fullname: '',
nickname: '',
photo: '',
fatherName: '',
motherName: '',
instagram: '',
twitter: '',
facebook: ''
},
akad: {
date: new Date(),
time: '',
place: '',
address: '',
mapUrl: '',
image: ''
},
resepsi: {
date: new Date(),
time: '',
place: '',
address: '',
mapUrl: '',
image: ''
},
story: {
image1: '',
text1: '',
image2: '',
text2: ''
},
gallery: [],
gift: {
address: '',
mapUrl: ''
},
musicUrl: ''
})
}
})
const isOpened = ref(false)
const showStory = ref(false)
const guestMessages = ref([])
const digitalWallets = ref([
{ name: 'Asep Irawan', bank: 'BNI', number: '009 - 0222 2444 21', logo: '/logo1.png' },
{ name: 'Putri Amanda', bank: 'BCA', number: '009 - 0222 2444 21', logo: '/logo2.png' }
])
const openInvitation = () => {
isOpened.value = true
}
const formatSimpleDate = (date) => {
if (!date) return ''
const d = new Date(date)
const day = d.getDate().toString().padStart(2, '0')
const month = d.getMonth() + 1
const year = d.getFullYear()
return `${day}.${month.toString().padStart(2, '0')}.${year}`
}
const copyToClipboard = async (text) => {
try {
await navigator.clipboard.writeText(text)
alert('Account number copied!')
} catch (err) {
console.error('Failed to copy:', err)
}
}
const handleRSVPSubmit = (data) => {
console.log('RSVP submitted:', data)
if (data.message) {
guestMessages.value.unshift({
name: data.name,
message: data.message,
attendance: data.attendance,
createdAt: new Date()
})
}
}
onMounted(() => {
AOS.init({
duration: 1000,
once: true,
offset: 100,
easing: 'ease-out-cubic'
})
})
</script>
<style scoped>
@import url('https://fonts.googleapis.com/css2?family=Great+Vibes&display=swap');
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
.animate-fade-in {
animation: fade-in 1s ease-out;
}
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track {
background: #fef3c7;
}
::-webkit-scrollbar-thumb {
background: #f59e0b;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: #d97706;
}
</style>