海报暂未开放
@@ -204,21 +87,16 @@ import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue' import { useRoute, useRouter } from 'vue-router' import { getPosterConfig } from '@/api/wedding' import { normalizePosterConfig, resolvePosterSide } from '@/composables/posterDefaults' -import BlurText from '@/components/vue-bits/BlurText.vue' -import TextType from '@/components/vue-bits/TextType.vue' +import ClassicPoster from '@/views/hb/templates/ClassicPoster.vue' +import SplitPoster from '@/views/hb/templates/SplitPoster.vue' const route = useRoute() const router = useRouter() -const posterSide = computed(() => resolvePosterSide(route.meta.posterSide) || 'male') +const posterSide = computed(() => resolvePosterSide(route.meta.posterSide) || 1) const cfg = reactive(normalizePosterConfig(null, posterSide.value)) -const phase = ref('loading') // loading | enter | content +const phase = ref('loading') const enterLeaving = ref(false) const contentVisible = ref(false) -const stage = ref(0) -const lineStage = ref(0) -const namesRightReady = ref(false) -const nameLeft = computed(() => `${cfg.sonLabel || ''}${cfg.sonName || ''}`) -const nameRight = computed(() => `${cfg.daughterInLawLabel || ''}${cfg.daughterInLawName || ''}`) let timers = [] function later(fn, ms) { @@ -227,29 +105,6 @@ function later(fn, ms) { return id } -function bumpStage(n) { - if (stage.value < n) stage.value = n - if (n === 4) { - if (!cfg.lines?.length) { - later(() => bumpStage(5), 200) - return - } - lineStage.value = 1 - } -} - -function onNamesLeftDone() { - namesRightReady.value = true -} - -function onLineDone(i) { - if (i + 1 >= cfg.lines.length) { - bumpStage(5) - return - } - if (lineStage.value === i + 1) lineStage.value = i + 2 -} - function goInvite() { const path = cfg.invitePath || '/' if (path.startsWith('http')) window.location.href = path @@ -276,10 +131,7 @@ async function runSequence() { contentVisible.value = true }, 80) await new Promise((r) => later(r, enterMs)) - phase.value = 'content' - later(() => { stage.value = 1 }, 200) - later(() => { stage.value = 2 }, 700) } onMounted(async () => { @@ -323,130 +175,56 @@ onUnmounted(() => { overflow-x: hidden; font-family: "Noto Serif SC", "Source Han Serif SC", "Songti SC", "STSong", serif; } - -.hb-sprite { - position: absolute; - width: 0; - height: 0; - overflow: hidden; -} - -/* —— 全屏背景装饰 —— */ -.hb-bg-decor { - position: fixed; - inset: 0; - z-index: 0; - pointer-events: none; - overflow: hidden; -} - +.hb-sprite { position: absolute; width: 0; height: 0; overflow: hidden; } +.hb-bg-decor { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; } .hb-bg-xi { - position: absolute; - color: rgba(240, 215, 140, 0.14); - font-weight: 700; - line-height: 1; - user-select: none; - animation: hb-pulse-soft 7s ease-in-out infinite; + position: absolute; color: rgba(240, 215, 140, 0.14); font-weight: 700; line-height: 1; + user-select: none; animation: hb-pulse-soft 7s ease-in-out infinite; } -.hb-bg-xi-1 { top: 6%; left: 4%; font-size: 56px; transform: rotate(-12deg); animation-delay: 0s; } -.hb-bg-xi-2 { top: 14%; right: 6%; font-size: 42px; transform: rotate(10deg); animation-delay: 1.2s; color: rgba(196, 30, 58, 0.22); } +.hb-bg-xi-1 { top: 6%; left: 4%; font-size: 56px; transform: rotate(-12deg); } +.hb-bg-xi-2 { top: 14%; right: 6%; font-size: 42px; transform: rotate(10deg); color: rgba(196, 30, 58, 0.22); animation-delay: 1.2s; } .hb-bg-xi-3 { bottom: 18%; left: 8%; font-size: 48px; transform: rotate(8deg); animation-delay: 2s; } -.hb-bg-xi-4 { bottom: 10%; right: 10%; font-size: 64px; transform: rotate(-8deg); animation-delay: 0.6s; color: rgba(196, 30, 58, 0.18); } +.hb-bg-xi-4 { bottom: 10%; right: 10%; font-size: 64px; transform: rotate(-8deg); color: rgba(196, 30, 58, 0.18); animation-delay: 0.6s; } .hb-bg-xi-5 { top: 42%; left: 2%; font-size: 36px; opacity: 0.8; animation-delay: 3s; } .hb-bg-xi-6 { top: 48%; right: 3%; font-size: 40px; opacity: 0.75; animation-delay: 2.4s; } - -.hb-bg-knot { - position: absolute; - color: rgba(212, 175, 55, 0.28); - width: 72px; - height: 72px; - animation: hb-float 10s ease-in-out infinite; -} -.hb-bg-knot-1 { top: 8%; left: 14%; width: 64px; height: 64px; animation-delay: 0.4s; } +.hb-bg-knot { position: absolute; color: rgba(212, 175, 55, 0.28); width: 72px; height: 72px; animation: hb-float 10s ease-in-out infinite; } +.hb-bg-knot-1 { top: 8%; left: 14%; width: 64px; height: 64px; } .hb-bg-knot-2 { top: 22%; right: 12%; width: 56px; height: 56px; color: rgba(196, 30, 58, 0.28); animation-delay: 1.8s; } .hb-bg-knot-3 { bottom: 22%; left: 10%; width: 60px; height: 60px; animation-delay: 2.6s; } .hb-bg-knot-4 { bottom: 12%; right: 14%; width: 70px; height: 70px; color: rgba(240, 215, 140, 0.22); animation-delay: 1s; } - -.hb-bg-lantern { - position: absolute; - color: rgba(240, 215, 140, 0.35); - width: 36px; - height: 50px; - animation: hb-swing 5.5s ease-in-out infinite; -} +.hb-bg-lantern { position: absolute; color: rgba(240, 215, 140, 0.35); width: 36px; height: 50px; animation: hb-swing 5.5s ease-in-out infinite; } .hb-bg-lantern-1 { top: 4%; left: 22%; } .hb-bg-lantern-2 { top: 5%; right: 20%; animation-delay: 1.4s; } - .hb-bg-spark { - position: absolute; - width: 6px; - height: 6px; - border-radius: 50%; + position: absolute; width: 6px; height: 6px; border-radius: 50%; background: radial-gradient(circle, var(--hb-gold-soft), transparent 70%); - box-shadow: 0 0 10px rgba(240, 215, 140, 0.55); - animation: hb-twinkle 2.8s ease-in-out infinite; + box-shadow: 0 0 10px rgba(240, 215, 140, 0.55); animation: hb-twinkle 2.8s ease-in-out infinite; } -.hb-bg-spark-1 { top: 18%; left: 30%; animation-delay: 0s; } +.hb-bg-spark-1 { top: 18%; left: 30%; } .hb-bg-spark-2 { top: 28%; right: 28%; animation-delay: 0.7s; } .hb-bg-spark-3 { bottom: 30%; left: 26%; animation-delay: 1.3s; } .hb-bg-spark-4 { bottom: 24%; right: 24%; animation-delay: 2s; } - .hb-loading { - position: fixed; - inset: 0; - z-index: 40; - display: flex; - align-items: center; - justify-content: center; + position: fixed; inset: 0; z-index: 40; display: flex; align-items: center; justify-content: center; background: var(--hb-red-deep); } - .hb-seal { - width: 88px; - height: 88px; - border-radius: 50%; - border: 3px solid var(--hb-gold); - color: var(--hb-gold); - display: flex; - align-items: center; - justify-content: center; - font-size: 42px; - font-weight: 700; - animation: hb-seal-pop 1s ease both; - box-shadow: 0 0 0 6px rgba(212, 175, 55, 0.15); + width: 88px; height: 88px; border-radius: 50%; border: 3px solid var(--hb-gold); color: var(--hb-gold); + display: flex; align-items: center; justify-content: center; font-size: 42px; font-weight: 700; + animation: hb-seal-pop 1s ease both; box-shadow: 0 0 0 6px rgba(212, 175, 55, 0.15); } - .hb-shimmer { - font-size: 28px; - letter-spacing: 0.35em; - background: linear-gradient(90deg, #8a6a1a, var(--hb-gold-soft), #8a6a1a); - background-size: 200% 100%; - -webkit-background-clip: text; - background-clip: text; - color: transparent; - animation: hb-shimmer 1.2s linear infinite; + font-size: 28px; letter-spacing: 0.35em; + background: linear-gradient(90deg, #8a6a1a, var(--hb-gold-soft), #8a6a1a); background-size: 200% 100%; + -webkit-background-clip: text; background-clip: text; color: transparent; animation: hb-shimmer 1.2s linear infinite; } - .hb-fade-dot { - width: 12px; - height: 12px; - border-radius: 50%; - background: var(--hb-gold); + width: 12px; height: 12px; border-radius: 50%; background: var(--hb-gold); animation: hb-fade-pulse 0.9s ease-in-out infinite; } - -.hb-enter { - position: fixed; - inset: 0; - z-index: 30; - pointer-events: none; -} - +.hb-enter { position: fixed; inset: 0; z-index: 30; pointer-events: none; } .hb-enter--curtain .hb-enter-panel { - position: absolute; - top: 0; - bottom: 0; - width: 50%; + position: absolute; top: 0; bottom: 0; width: 50%; background: linear-gradient(180deg, #8b0000, #5c0000); transition: transform 0.95s cubic-bezier(0.65, 0, 0.35, 1); } @@ -454,409 +232,33 @@ onUnmounted(() => { .hb-enter--curtain .hb-enter-right { right: 0; border-left: 1px solid rgba(212, 175, 55, 0.35); } .hb-enter--curtain.is-done .hb-enter-left { transform: translateX(-105%); } .hb-enter--curtain.is-done .hb-enter-right { transform: translateX(105%); } - .hb-enter--fadeUp .hb-enter-veil, .hb-enter--scaleIn .hb-enter-veil { - position: absolute; - inset: 0; - background: var(--hb-red-deep); + position: absolute; inset: 0; background: var(--hb-red-deep); transition: opacity 0.7s ease, transform 0.8s ease; } -.hb-enter--fadeUp.is-done .hb-enter-veil { - opacity: 0; - transform: translateY(-24px); -} -.hb-enter--scaleIn.is-done .hb-enter-veil { - opacity: 0; - transform: scale(1.08); -} - -.hb-stage { - position: relative; - z-index: 1; - width: min(420px, 100%); - opacity: 0; - transform: translateY(18px) scale(0.98); - transition: opacity 0.6s ease, transform 0.7s cubic-bezier(0.22, 1, 0.36, 1); -} -.hb-stage.is-visible { - opacity: 1; - transform: translateY(0) scale(1); -} - -.hb-frame { - position: relative; - border: 1.5px solid var(--hb-gold); - border-radius: 10px; - padding: 8px; - background: - linear-gradient(135deg, rgba(212, 175, 55, 0.18), transparent 40%), - linear-gradient(180deg, rgba(155, 0, 0, 0.4), rgba(90, 0, 0, 0.25)); - box-shadow: - 0 12px 40px rgba(0, 0, 0, 0.35), - inset 0 0 0 1px rgba(240, 215, 140, 0.2); -} - -.hb-frame-ornament { - position: absolute; - width: 34px; - height: 34px; - color: var(--hb-gold-soft); - z-index: 2; - pointer-events: none; - opacity: 0.9; -} -.hb-frame-ornament svg { width: 100%; height: 100%; display: block; } -.hb-frame-ornament-tl { top: 2px; left: 2px; } -.hb-frame-ornament-tr { top: 2px; right: 2px; transform: scaleX(-1); } -.hb-frame-ornament-bl { bottom: 2px; left: 2px; transform: scaleY(-1); } -.hb-frame-ornament-br { bottom: 2px; right: 2px; transform: scale(-1); } - -.hb-inner { - position: relative; - border: 1.5px solid rgba(212, 175, 55, 0.85); - border-radius: 6px; - padding: 14px 14px 20px; - background: - linear-gradient(180deg, rgba(130, 0, 0, 0.58), rgba(110, 0, 0, 0.38)), - radial-gradient(circle at 90% 8%, rgba(255, 255, 255, 0.08), transparent 28%), - radial-gradient(circle at 10% 92%, rgba(196, 30, 58, 0.2), transparent 30%); - min-height: min(780px, calc(100dvh - 40px)); - display: flex; - flex-direction: column; - align-items: center; - overflow: hidden; -} - -.hb-inner::before { - content: ''; - position: absolute; - inset: 5px; - border: 1px solid rgba(240, 215, 140, 0.35); - border-radius: 4px; - pointer-events: none; - z-index: 1; - clip-path: polygon( - 0 8px, 8px 0, calc(100% - 8px) 0, 100% 8px, - 100% calc(100% - 8px), calc(100% - 8px) 100%, 8px 100%, 0 calc(100% - 8px) - ); -} - -.hb-inner::after { - content: ''; - position: absolute; - inset: 10px; - pointer-events: none; - z-index: 1; - border: 1px dashed rgba(212, 175, 55, 0.18); - border-radius: 2px; - opacity: 0.8; -} - -/* —— 纸面装饰 —— */ -.hb-paper-decor { - position: absolute; - inset: 0; - z-index: 0; - pointer-events: none; - overflow: hidden; -} - -.hb-paper-watermark { - position: absolute; - left: 50%; - top: 52%; - transform: translate(-50%, -50%); - font-size: min(220px, 58vw); - font-weight: 700; - color: rgba(196, 30, 58, 0.1); - line-height: 1; - letter-spacing: 0.05em; - text-shadow: 0 0 1px rgba(212, 175, 55, 0.15); -} - -.hb-paper-knot { - position: absolute; - width: 42px; - height: 42px; - color: rgba(212, 175, 55, 0.45); -} -.hb-paper-knot-tl { top: 10px; left: 10px; } -.hb-paper-knot-tr { top: 10px; right: 10px; transform: scaleX(-1); color: rgba(240, 215, 140, 0.4); } -.hb-paper-knot-bl { bottom: 12px; left: 10px; transform: scaleY(-1); color: rgba(240, 215, 140, 0.38); } -.hb-paper-knot-br { bottom: 12px; right: 10px; transform: scale(-1); } - -.hb-paper-cloud { - position: absolute; - width: 96px; - height: 42px; - color: rgba(212, 175, 55, 0.32); -} -.hb-paper-cloud-t { top: 8px; left: 50%; transform: translateX(-50%); } -.hb-paper-cloud-b { bottom: 8px; left: 50%; transform: translateX(-50%) scaleY(-1); color: rgba(196, 30, 58, 0.28); } - -.hb-paper-xi { - position: absolute; - top: 46%; - font-size: 22px; - font-weight: 700; - color: rgba(196, 30, 58, 0.28); - text-shadow: 0 0 8px rgba(212, 175, 55, 0.15); -} -.hb-paper-xi-l { left: 8px; transform: rotate(-18deg); } -.hb-paper-xi-r { right: 8px; transform: rotate(18deg); } - -.hb-paper-dot { - position: absolute; - width: 5px; - height: 5px; - border-radius: 50%; - background: rgba(212, 175, 55, 0.45); - box-shadow: 0 0 0 3px rgba(196, 30, 58, 0.12); -} -.hb-paper-dot-1 { top: 22%; left: 14px; } -.hb-paper-dot-2 { top: 22%; right: 14px; } -.hb-paper-dot-3 { bottom: 26%; left: 16px; } -.hb-paper-dot-4 { bottom: 26%; right: 16px; } - -.hb-paper-side { - position: absolute; - top: 28%; - bottom: 28%; - width: 10px; - background: - repeating-linear-gradient( - 180deg, - transparent 0 10px, - rgba(212, 175, 55, 0.22) 10px 11px, - transparent 11px 20px - ); - opacity: 0.7; -} -.hb-paper-side-l { - left: 4px; - border-left: 1px solid rgba(212, 175, 55, 0.25); -} -.hb-paper-side-r { - right: 4px; - border-right: 1px solid rgba(212, 175, 55, 0.25); -} - -.hb-hero-wrap, -.hb-names, -.hb-title-wrap, -.hb-body, -.hb-footer, -.hb-cta { - position: relative; - z-index: 2; -} - -.hb-hero-wrap { - width: 100%; - opacity: 0; - transform: translateY(12px); - transition: opacity 0.55s ease, transform 0.55s ease; - margin-bottom: 14px; -} -.hb-hero-wrap.is-show { - opacity: 1; - transform: none; -} - -.hb-hero { - position: relative; - border: 1.5px solid var(--hb-gold); - padding: 3px; - background: rgba(0, 0, 0, 0.15); - aspect-ratio: 16 / 11; - overflow: hidden; -} - -.hb-hero-img { - width: 100%; - height: 100%; - object-fit: cover; - display: block; -} - -.hb-hero-placeholder { - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - color: rgba(240, 215, 140, 0.55); - letter-spacing: 0.3em; - font-size: 13px; - background: rgba(0, 0, 0, 0.2); -} - -.hb-xi { - position: absolute; - top: 10%; - font-size: 28px; - color: #c41e3a; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); - font-weight: 700; - opacity: 0.92; - pointer-events: none; -} -.hb-xi-l { left: 8%; } -.hb-xi-r { right: 8%; } - -.hb-names { - width: 100%; - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - min-height: 28px; - margin-bottom: 8px; - opacity: 0; - transition: opacity 0.4s ease; -} -.hb-names.is-show { opacity: 1; } - -.hb-name { - color: #f7efe0 !important; - font-size: 12px; - letter-spacing: 0.12em; - justify-content: center; -} - -.hb-xi-circle { - width: 22px; - height: 22px; - border-radius: 50%; - border: 1px solid var(--hb-gold); - color: var(--hb-gold); - font-size: 11px; - display: inline-flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - background: rgba(155, 0, 0, 0.5); -} - -.hb-title-wrap { - margin: 4px 0 12px; - min-height: 48px; - opacity: 0; - transition: opacity 0.35s ease; -} -.hb-title-wrap.is-show { opacity: 1; } - -.hb-title { - color: var(--hb-gold-soft) !important; - font-size: clamp(30px, 9vw, 40px); - letter-spacing: 0.18em; - justify-content: center; - text-shadow: 0 2px 8px rgba(0, 0, 0, 0.35); -} - -.hb-body { - width: 100%; - flex: 1; - display: flex; - flex-direction: column; - align-items: center; - gap: 9px; - padding: 4px 4px 10px; -} - -.hb-line { - color: var(--hb-gold-soft) !important; - font-size: 13px; - letter-spacing: 0.14em; - line-height: 1.55; - text-align: center; - justify-content: center; -} - -.hb-cursor { - color: var(--hb-gold); -} - -.hb-footer { - margin-top: 8px; - min-height: 24px; - opacity: 0; - transition: opacity 0.4s ease; -} -.hb-footer.is-show { opacity: 1; } - -.hb-footer-text { - color: #f7efe0 !important; - font-size: 12px; - letter-spacing: 0.2em; - justify-content: center; -} - -.hb-cta { - margin-top: 16px; - opacity: 0; - transform: translateY(8px); - animation: hb-cta-in 0.5s ease forwards; -} -.hb-cta.is-show { opacity: 1; } - -.hb-cta-btn { - appearance: none; - border: 1px solid var(--hb-gold); - background: linear-gradient(180deg, rgba(212, 175, 55, 0.22), rgba(212, 175, 55, 0.08)); - color: var(--hb-gold-soft); - padding: 8px 22px; - border-radius: 999px; - letter-spacing: 0.28em; - font-size: 13px; - cursor: pointer; -} -.hb-cta-btn:active { transform: scale(0.98); } - +.hb-enter--fadeUp.is-done .hb-enter-veil { opacity: 0; transform: translateY(-24px); } +.hb-enter--scaleIn.is-done .hb-enter-veil { opacity: 0; transform: scale(1.08); } .hb-disabled { - position: fixed; - inset: 0; - z-index: 50; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 16px; - background: rgba(80, 0, 0, 0.92); - color: var(--hb-cream); + position: fixed; inset: 0; z-index: 50; display: flex; flex-direction: column; + align-items: center; justify-content: center; gap: 16px; + background: rgba(80, 0, 0, 0.92); color: var(--hb-cream); +} +.hb-cta-btn { + appearance: none; border: 1px solid var(--hb-gold); + background: linear-gradient(180deg, rgba(212, 175, 55, 0.22), rgba(212, 175, 55, 0.08)); + color: var(--hb-gold-soft); padding: 8px 22px; border-radius: 999px; + letter-spacing: 0.28em; font-size: 13px; cursor: pointer; } - @keyframes hb-seal-pop { 0% { opacity: 0; transform: scale(0.4) rotate(-12deg); } 60% { opacity: 1; transform: scale(1.08) rotate(2deg); } 100% { opacity: 1; transform: scale(1) rotate(0); } } -@keyframes hb-shimmer { - 0% { background-position: 100% 0; } - 100% { background-position: -100% 0; } -} -@keyframes hb-fade-pulse { - 0%, 100% { opacity: 0.25; transform: scale(0.85); } - 50% { opacity: 1; transform: scale(1.1); } -} -@keyframes hb-cta-in { - to { opacity: 1; transform: none; } -} -@keyframes hb-float { - 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(-8px); } -} -@keyframes hb-pulse-soft { - 0%, 100% { opacity: 0.55; } - 50% { opacity: 1; } -} -@keyframes hb-swing { - 0%, 100% { transform: rotate(-4deg); } - 50% { transform: rotate(4deg); } -} -@keyframes hb-twinkle { - 0%, 100% { opacity: 0.25; transform: scale(0.7); } - 50% { opacity: 1; transform: scale(1.25); } -} +@keyframes hb-shimmer { 0% { background-position: 100% 0; } 100% { background-position: -100% 0; } } +@keyframes hb-fade-pulse { 0%, 100% { opacity: 0.25; transform: scale(0.85); } 50% { opacity: 1; transform: scale(1.1); } } +@keyframes hb-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } } +@keyframes hb-pulse-soft { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } } +@keyframes hb-swing { 0%, 100% { transform: rotate(-4deg); } 50% { transform: rotate(4deg); } } +@keyframes hb-twinkle { 0%, 100% { opacity: 0.25; transform: scale(0.7); } 50% { opacity: 1; transform: scale(1.25); } } diff --git a/vite-tailwindcss/src/views/hb/templates/ClassicPoster.vue b/vite-tailwindcss/src/views/hb/templates/ClassicPoster.vue new file mode 100644 index 0000000..568797b --- /dev/null +++ b/vite-tailwindcss/src/views/hb/templates/ClassicPoster.vue @@ -0,0 +1,342 @@ + +