fix: 升级了一些视觉、各种单图相册效果、日历效果、多种模板任选
This commit is contained in:
@@ -10,13 +10,18 @@ const props = defineProps({
|
||||
bubbleEnabled: { type: Boolean, default: true },
|
||||
/** 预览/抽屉等遮罩时关闭粒子绘制 */
|
||||
active: { type: Boolean, default: true },
|
||||
/** 主题 fx 色板注入:空则用默认暖彩 */
|
||||
petalPalette: { type: Array, default: null },
|
||||
heartPalette: { type: Array, default: null },
|
||||
})
|
||||
|
||||
const canvasRef = ref(null)
|
||||
const petals = []
|
||||
const hearts = []
|
||||
const petalColors = ['#f7dce3', '#fbeee3', '#f3c9d6', '#efdcc8', '#f9e7d6']
|
||||
const heartColors = ['#c9b08a', '#e2b3c0', '#d4af37', '#e8c9d2']
|
||||
const DEFAULT_PETALS = ['#f7dce3', '#fbeee3', '#f3c9d6', '#efdcc8', '#f9e7d6']
|
||||
const DEFAULT_HEARTS = ['#c9b08a', '#e2b3c0', '#d4af37', '#e8c9d2']
|
||||
const petalColorsOf = () => (props.petalPalette?.length ? props.petalPalette : DEFAULT_PETALS)
|
||||
const heartColorsOf = () => (props.heartPalette?.length ? props.heartPalette : DEFAULT_HEARTS)
|
||||
|
||||
let ctx = null
|
||||
let rafId = 0
|
||||
@@ -39,7 +44,8 @@ function resetPetal(p, initial = false) {
|
||||
p.rotation = rand(0, Math.PI * 2)
|
||||
p.rotationSpeed = rand(-0.9, 0.9)
|
||||
p.opacity = rand(0.28, 0.7)
|
||||
p.color = petalColors[Math.floor(rand(0, petalColors.length))]
|
||||
const pc = petalColorsOf()
|
||||
p.color = pc[Math.floor(rand(0, pc.length))]
|
||||
}
|
||||
|
||||
function resetHeart(h, initial = false) {
|
||||
@@ -50,7 +56,8 @@ function resetHeart(h, initial = false) {
|
||||
h.sway = rand(8, 26)
|
||||
h.phase = rand(0, Math.PI * 2)
|
||||
h.opacity = rand(0.1, 0.32)
|
||||
h.color = heartColors[Math.floor(rand(0, heartColors.length))]
|
||||
const hc = heartColorsOf()
|
||||
h.color = hc[Math.floor(rand(0, hc.length))]
|
||||
}
|
||||
|
||||
function seedParticles() {
|
||||
|
||||
@@ -30,7 +30,7 @@ const GLOW_BLUR = isIOS ? 4 : 10
|
||||
const GLOW_ALPHA = 0.55
|
||||
const DPR_CAP = isIOS ? 1.5 : 2
|
||||
|
||||
/** 多色爱心:主色 */
|
||||
/** 多色爱心:主色(可被主题 fx 色板覆盖) */
|
||||
const HEART_COLORS = [
|
||||
'#ff2442', '#ff2d55', '#ff4770', '#ff6b8a',
|
||||
'#f472b6', '#ec4899', '#e879f9', '#c084fc',
|
||||
@@ -47,6 +47,14 @@ const GLOW_COLORS = [
|
||||
'#fdba74', '#f5d0b0', '#ffffff',
|
||||
]
|
||||
|
||||
const props = defineProps({
|
||||
/** 主题色板注入:空则用默认 */
|
||||
colors: { type: Array, default: null },
|
||||
glowColors: { type: Array, default: null },
|
||||
})
|
||||
const heartPalette = () => (props.colors?.length ? props.colors : HEART_COLORS)
|
||||
const glowPalette = () => (props.glowColors?.length ? props.glowColors : GLOW_COLORS)
|
||||
|
||||
const pick = (arr) => arr[Math.floor(Math.random() * arr.length)]
|
||||
const rand = (min, max) => min + Math.random() * (max - min)
|
||||
|
||||
@@ -199,8 +207,8 @@ function createHeart(x, y, now) {
|
||||
birthTime: now,
|
||||
maxAge: rand(HEART_MIN_LIFE, HEART_MAX_LIFE),
|
||||
baseSize: rand(HEART_MIN_SIZE, HEART_MAX_SIZE),
|
||||
color: pick(HEART_COLORS),
|
||||
glowColor: pick(GLOW_COLORS),
|
||||
color: pick(heartPalette()),
|
||||
glowColor: pick(glowPalette()),
|
||||
peakScale: rand(0.75, 1.35),
|
||||
riseSpeed: rand(RISE_SPEED_MIN, RISE_SPEED_MAX),
|
||||
driftAmp: rand(DRIFT_AMP_MIN, DRIFT_AMP_MAX),
|
||||
|
||||
@@ -214,8 +214,8 @@
|
||||
:class="{ 'g-heart-done': heartDone }"
|
||||
>
|
||||
<div
|
||||
v-for="(slot, imgIdx) in HEART_SLOTS"
|
||||
:key="imgIdx"
|
||||
v-for="(slot, imgIdx) in heartSlots"
|
||||
:key="`${page.heartLayout || 'classic'}-${imgIdx}`"
|
||||
class="g-heart-slot"
|
||||
:class="{ 'g-heart-placeholder': imgIdx >= shownCount }"
|
||||
:style="heartSlotStyle(slot)"
|
||||
@@ -225,7 +225,7 @@
|
||||
v-reveal="{ variant: heartReveal(imgIdx), immediate: true }"
|
||||
class="absolute inset-0 g-heart-cell"
|
||||
:class="frameClass"
|
||||
:style="heartCellShape(imgIdx)"
|
||||
:style="heartCellShape(slot)"
|
||||
>
|
||||
<img
|
||||
:src="displayAt(imgIdx)"
|
||||
@@ -309,7 +309,7 @@
|
||||
import { ref, computed, watch, nextTick, onMounted, onUnmounted } from 'vue'
|
||||
import { borderClass, borderStyleMeta } from '@/composables/borderStyles'
|
||||
import { createSequentialMount } from '@/composables/useSequentialMount'
|
||||
import { HEART_SLOTS, heartSlotStyle, heartFocusCssAt, heartCellShape } from '@/composables/heartCollage'
|
||||
import { heartSlotsFor, heartSlotStyle, heartFocusCssAt, heartCellShape } from '@/composables/heartCollage'
|
||||
import SectionHeading from '@/components/themes/SectionHeading.vue'
|
||||
|
||||
const NINE_STEP_MS = 300
|
||||
@@ -735,16 +735,21 @@ function polaroidTransform(i) {
|
||||
}
|
||||
|
||||
/** 爱心:左右对称入场,中轴与心尖用缩放 */
|
||||
/** 当前爱心拼接方案的槽位(page.heartLayout 可选,classic 默认) */
|
||||
const heartSlots = computed(() => heartSlotsFor(props.page))
|
||||
|
||||
function heartReveal(i) {
|
||||
if (i === 5 || i === 12) return 'scale'
|
||||
if (i === 0 || i === 2 || i === 3 || i === 4 || i === 9) return 'left'
|
||||
if (i === 1 || i === 6 || i === 7 || i === 8 || i === 11) return 'right'
|
||||
return 'up'
|
||||
// 按槽位横向位置决定入场方向:左半从左入、右半从右入、中轴缩放
|
||||
const slot = heartSlots.value[i]
|
||||
if (!slot) return 'up'
|
||||
const cx = slot.l + slot.w / 2
|
||||
if (cx > 42 && cx < 58) return 'scale'
|
||||
return cx <= 42 ? 'left' : 'right'
|
||||
}
|
||||
|
||||
/** 爱心拼合完成:触发一次心跳 + 小心心飘散 */
|
||||
const heartDone = computed(() =>
|
||||
props.page?.type === 'heart-collage' && shownCount.value >= HEART_SLOTS.length
|
||||
props.page?.type === 'heart-collage' && shownCount.value >= heartSlots.value.length
|
||||
)
|
||||
|
||||
</script>
|
||||
|
||||
@@ -201,6 +201,156 @@ html[data-theme='pixel'] .sh-note {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
/* —— 水墨:楷体 + 墨横 + 朱砂点 —— */
|
||||
html[data-theme='inkwash'] .sh-kicker {
|
||||
font-family: var(--font-kai);
|
||||
letter-spacing: 0.4em;
|
||||
}
|
||||
html[data-theme='inkwash'] .sh-title {
|
||||
font-family: var(--font-kai);
|
||||
letter-spacing: 0.36em;
|
||||
text-indent: 0.36em;
|
||||
}
|
||||
html[data-theme='inkwash'] .sh-rule-bottom {
|
||||
display: block;
|
||||
width: 46px;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, transparent, var(--c-ink) 30%, var(--c-ink) 70%, transparent);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* —— 电影:场记板 SCENE —— */
|
||||
html[data-theme='cinema'] .sh-index {
|
||||
display: block;
|
||||
font-family: var(--font-number);
|
||||
font-style: normal;
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.2em;
|
||||
color: var(--c-on-primary);
|
||||
background: var(--c-primary);
|
||||
padding: 3px 10px;
|
||||
border-radius: 3px;
|
||||
transform: rotate(-2deg);
|
||||
}
|
||||
html[data-theme='cinema'] .sh-index::before {
|
||||
content: 'SCENE ';
|
||||
}
|
||||
html[data-theme='cinema'] .sh-title {
|
||||
font-family: var(--font-serif);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.2em;
|
||||
}
|
||||
html[data-theme='cinema'] .sh-kicker {
|
||||
font-family: var(--font-cinzel);
|
||||
}
|
||||
|
||||
/* —— 胶片:帧号标记 —— */
|
||||
html[data-theme='kodak'] .sh-index {
|
||||
display: block;
|
||||
font-family: var(--font-number);
|
||||
font-style: normal;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.16em;
|
||||
color: #ff9a3c;
|
||||
text-shadow: 0 0 6px rgba(255, 130, 30, 0.55);
|
||||
}
|
||||
html[data-theme='kodak'] .sh-index::before {
|
||||
content: '▸ ';
|
||||
}
|
||||
html[data-theme='kodak'] .sh-index::after {
|
||||
content: 'A';
|
||||
}
|
||||
html[data-theme='kodak'] .sh-title {
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.14em;
|
||||
}
|
||||
|
||||
/* —— 文艺:罗马分幕 —— */
|
||||
html[data-theme='arthouse'] .sh {
|
||||
gap: 10px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
html[data-theme='arthouse'] .sh-kicker {
|
||||
font-family: var(--font-display);
|
||||
letter-spacing: 0.56em;
|
||||
}
|
||||
html[data-theme='arthouse'] .sh-title {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.3em;
|
||||
text-indent: 0.3em;
|
||||
}
|
||||
html[data-theme='arthouse'] .sh-rule-bottom {
|
||||
display: block;
|
||||
width: 1px;
|
||||
height: 22px;
|
||||
background: rgba(var(--c-line-rgb), 0.6);
|
||||
}
|
||||
|
||||
/* —— 旅行:邮戳圆章 —— */
|
||||
html[data-theme='passport'] .sh-index {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-family: var(--font-number);
|
||||
font-style: normal;
|
||||
font-size: 13px;
|
||||
color: var(--c-primary);
|
||||
border: 2px solid rgba(var(--c-primary-rgb), 0.55);
|
||||
border-radius: 50%;
|
||||
transform: rotate(-10deg);
|
||||
}
|
||||
html[data-theme='passport'] .sh-kicker {
|
||||
font-family: var(--font-number);
|
||||
letter-spacing: 0.34em;
|
||||
}
|
||||
html[data-theme='passport'] .sh-title {
|
||||
letter-spacing: 0.22em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* —— 手账:标签贴 + 胶带 —— */
|
||||
html[data-theme='scrapbook'] .sh-title {
|
||||
font-family: var(--font-longcang);
|
||||
padding: 6px 20px;
|
||||
background: var(--c-card);
|
||||
border: 1px dashed rgba(var(--c-primary-rgb), 0.45);
|
||||
border-radius: 6px;
|
||||
transform: rotate(-1.4deg);
|
||||
box-shadow: 0 6px 16px rgba(69, 58, 48, 0.1);
|
||||
}
|
||||
html[data-theme='scrapbook'] .sh-kicker {
|
||||
font-family: var(--font-liujian);
|
||||
text-transform: none;
|
||||
letter-spacing: 0.18em;
|
||||
}
|
||||
|
||||
/* —— Y2K:窗口标题条 —— */
|
||||
html[data-theme='y2k'] .sh-title {
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.1em;
|
||||
background: linear-gradient(180deg, #7a4ae0 10%, #4a90e0 50%, #e04ad0 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
}
|
||||
html[data-theme='y2k'] .sh-kicker {
|
||||
font-family: var(--font-pixel);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.2em;
|
||||
color: var(--c-line);
|
||||
text-transform: none;
|
||||
}
|
||||
html[data-theme='y2k'] .sh-rule-bottom {
|
||||
display: block;
|
||||
width: 60px;
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
background: repeating-linear-gradient(90deg, #7a4ae0 0 8px, #4adce0 8px 16px);
|
||||
}
|
||||
|
||||
/* —— 极简主义:小字 + 一条细线 + 大留白 —— */
|
||||
html[data-theme='zen'] .sh {
|
||||
gap: 12px;
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<div class="ca-root">
|
||||
<span v-reveal="'down'" class="ca-chapter">CHAPITRE UN</span>
|
||||
|
||||
<div class="ca-mid">
|
||||
<i v-reveal="'down'" class="ca-line" aria-hidden="true"></i>
|
||||
<div v-reveal="{ variant: 'scale', delay: 180 }" class="ca-photo">
|
||||
<img :src="heroImg" class="ca-img" fetchpriority="high" decoding="async" alt="封面" />
|
||||
</div>
|
||||
<i v-reveal="'up'" class="ca-line" aria-hidden="true"></i>
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'up', delay: 320 }" class="ca-copy">
|
||||
<span class="ca-names">{{ groom }} <em>et</em> {{ bride }}</span>
|
||||
<span class="ca-date">{{ date }} — {{ lunar }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/** 文艺影调封面:严格对称构图、上下轴线、法式分幕字 */
|
||||
defineProps({
|
||||
heroImg: { type: String, default: '' },
|
||||
groom: { type: String, default: '' },
|
||||
bride: { type: String, default: '' },
|
||||
date: { type: String, default: '' },
|
||||
lunar: { type: String, default: '' },
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ca-root {
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
min-height: 100dvh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
padding: max(40px, env(safe-area-inset-top)) 30px 48px;
|
||||
background: var(--c-bg);
|
||||
overflow: hidden;
|
||||
}
|
||||
.ca-chapter {
|
||||
font-family: var(--font-display);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.66em;
|
||||
text-indent: 0.66em;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
.ca-mid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
.ca-line {
|
||||
width: 1px;
|
||||
height: 30px;
|
||||
background: rgba(var(--c-line-rgb), 0.7);
|
||||
}
|
||||
.ca-photo {
|
||||
width: min(58vw, 215px);
|
||||
aspect-ratio: 4 / 5;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ca-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
filter: saturate(0.82) contrast(1.03);
|
||||
}
|
||||
.ca-copy {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
.ca-names {
|
||||
font-family: var(--font-display);
|
||||
font-size: clamp(23px, 7vw, 30px);
|
||||
letter-spacing: 0.16em;
|
||||
color: var(--c-ink);
|
||||
}
|
||||
.ca-names em {
|
||||
font-style: italic;
|
||||
font-size: 0.62em;
|
||||
color: var(--c-muted);
|
||||
margin: 0 0.3em;
|
||||
}
|
||||
.ca-date {
|
||||
font-family: var(--font-serif);
|
||||
font-size: 10.5px;
|
||||
letter-spacing: 0.3em;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
</style>
|
||||
152
vite-tailwindcss/src/components/themes/covers/CoverCinema.vue
Normal file
152
vite-tailwindcss/src/components/themes/covers/CoverCinema.vue
Normal file
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div class="cc-root">
|
||||
<div v-reveal="'down'" class="cc-top">
|
||||
<span class="cc-badge">NOW SHOWING</span>
|
||||
<span class="cc-studio">LOVE PICTURES 出品</span>
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'scale', delay: 150 }" class="cc-poster">
|
||||
<img :src="heroImg" class="cc-img" fetchpriority="high" decoding="async" alt="封面" />
|
||||
<span class="cc-poster-veil" aria-hidden="true"></span>
|
||||
<span class="cc-corner" aria-hidden="true">彩色 · 宽银幕</span>
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'up', delay: 280 }" class="cc-title-wrap">
|
||||
<span class="cc-title">THE WEDDING</span>
|
||||
<span class="cc-starring">领衔主演</span>
|
||||
<span class="cc-names">{{ groom }} · {{ bride }}</span>
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'up', delay: 380 }" class="cc-release">
|
||||
<i aria-hidden="true"></i>
|
||||
<span>{{ date }} 隆重献映 · {{ lunar }}</span>
|
||||
<i aria-hidden="true"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/** 复古电影海报封面:NOW SHOWING 角标 + 主演字幕 + 上映日期 */
|
||||
defineProps({
|
||||
heroImg: { type: String, default: '' },
|
||||
groom: { type: String, default: '' },
|
||||
bride: { type: String, default: '' },
|
||||
date: { type: String, default: '' },
|
||||
lunar: { type: String, default: '' },
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cc-root {
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
min-height: 100dvh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
padding: max(24px, env(safe-area-inset-top)) 26px 34px;
|
||||
background:
|
||||
var(--t-bg-texture),
|
||||
radial-gradient(ellipse at 50% 0%, rgba(212, 162, 74, 0.16), transparent 55%),
|
||||
var(--c-bg);
|
||||
overflow: hidden;
|
||||
}
|
||||
.cc-top {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.cc-badge {
|
||||
padding: 4px 10px;
|
||||
font-family: var(--font-cinzel);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.24em;
|
||||
color: var(--c-on-primary);
|
||||
background: var(--c-primary);
|
||||
border-radius: 3px;
|
||||
transform: rotate(-3deg);
|
||||
box-shadow: 2px 3px 0 rgba(58, 44, 34, 0.25);
|
||||
}
|
||||
.cc-studio {
|
||||
font-family: var(--font-serif);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.2em;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
.cc-poster {
|
||||
position: relative;
|
||||
width: min(70vw, 260px);
|
||||
aspect-ratio: 3 / 4;
|
||||
border: 3px solid var(--c-ink);
|
||||
outline: 1px solid rgba(var(--c-line-rgb), 0.8);
|
||||
outline-offset: 5px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 18px 44px rgba(58, 44, 34, 0.3);
|
||||
}
|
||||
.cc-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
filter: sepia(0.16) saturate(1.12) contrast(1.04);
|
||||
}
|
||||
.cc-poster-veil {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(180deg, transparent 62%, rgba(38, 24, 16, 0.42));
|
||||
pointer-events: none;
|
||||
}
|
||||
.cc-corner {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
bottom: 8px;
|
||||
font-family: var(--font-serif);
|
||||
font-size: 9px;
|
||||
letter-spacing: 0.16em;
|
||||
color: rgba(248, 240, 226, 0.92);
|
||||
}
|
||||
.cc-title-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
.cc-title {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 700;
|
||||
font-size: clamp(30px, 9.4vw, 42px);
|
||||
letter-spacing: 0.1em;
|
||||
color: var(--c-primary);
|
||||
text-shadow: 2px 2px 0 rgba(212, 162, 74, 0.4);
|
||||
}
|
||||
.cc-starring {
|
||||
font-family: var(--font-serif);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.5em;
|
||||
text-indent: 0.5em;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
.cc-names {
|
||||
font-family: var(--font-serif);
|
||||
font-weight: 700;
|
||||
font-size: clamp(19px, 5.6vw, 24px);
|
||||
letter-spacing: 0.2em;
|
||||
color: var(--c-ink);
|
||||
}
|
||||
.cc-release {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
font-family: var(--font-serif);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.16em;
|
||||
color: var(--c-ink-soft);
|
||||
}
|
||||
.cc-release i {
|
||||
width: 34px;
|
||||
height: 1px;
|
||||
background: rgba(var(--c-line-rgb), 0.8);
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex flex-col items-center justify-between py-12 flex-1 w-full relative border-[0.5px] border-[var(--c-primary)]/20 bg-[var(--c-card)]/40">
|
||||
<div class="flex flex-col items-center justify-between py-12 flex-1 w-full relative border-[0.5px] border-[var(--c-primary)]/20 bg-[var(--c-card)]/20">
|
||||
<div v-reveal="'down'" class="text-center mt-6 z-10">
|
||||
<span class="cover-kicker calligraphy text-[10px] tracking-[0.5em] uppercase text-[var(--c-primary)] font-bold block">Wedding Invitation</span>
|
||||
<div class="w-6 h-[0.5px] bg-[var(--c-primary)] mx-auto opacity-50 mt-4"></div>
|
||||
|
||||
114
vite-tailwindcss/src/components/themes/covers/CoverInkwash.vue
Normal file
114
vite-tailwindcss/src/components/themes/covers/CoverInkwash.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="ci-root">
|
||||
<svg class="ci-mount" viewBox="0 0 400 160" preserveAspectRatio="none" aria-hidden="true">
|
||||
<path d="M0 128C60 84 120 108 170 92 230 72 260 108 320 96 360 88 380 104 400 96V160H0Z" fill="var(--c-primary)" fill-opacity="0.1" />
|
||||
<path d="M0 144C80 112 150 136 220 118 290 100 340 128 400 116V160H0Z" fill="var(--c-primary)" fill-opacity="0.16" />
|
||||
</svg>
|
||||
|
||||
<span v-reveal="'down'" class="ci-kicker">山 水 有 相 逢</span>
|
||||
|
||||
<div v-reveal="{ variant: 'scale', delay: 160 }" class="ci-photo">
|
||||
<img :src="heroImg" class="ci-img" fetchpriority="high" decoding="async" alt="封面" />
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'up', delay: 280 }" class="ci-names">
|
||||
<span class="vertical-text">{{ groom }}</span>
|
||||
<b class="ci-seal" aria-hidden="true">囍</b>
|
||||
<span class="vertical-text">{{ bride }}</span>
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'up', delay: 360 }" class="ci-date">{{ date }} · {{ lunar }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/** 水墨山水封面:宣纸底 + 泼墨山影 + 竖排名 + 朱砂印 */
|
||||
defineProps({
|
||||
heroImg: { type: String, default: '' },
|
||||
groom: { type: String, default: '' },
|
||||
bride: { type: String, default: '' },
|
||||
date: { type: String, default: '' },
|
||||
lunar: { type: String, default: '' },
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ci-root {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
min-height: 100dvh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 26px;
|
||||
padding: max(30px, env(safe-area-inset-top)) 26px 90px;
|
||||
background: var(--c-bg);
|
||||
overflow: hidden;
|
||||
}
|
||||
.ci-mount {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
pointer-events: none;
|
||||
}
|
||||
.ci-kicker {
|
||||
font-family: var(--font-kai);
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.6em;
|
||||
text-indent: 0.6em;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
.ci-photo {
|
||||
width: min(62vw, 235px);
|
||||
aspect-ratio: 3 / 4;
|
||||
padding: 8px;
|
||||
background: var(--c-card);
|
||||
border: 1px solid rgba(var(--c-primary-rgb), 0.28);
|
||||
box-shadow: 0 16px 40px rgba(42, 46, 42, 0.14);
|
||||
}
|
||||
.ci-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
filter: saturate(0.85) contrast(1.02);
|
||||
}
|
||||
.ci-names {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 20px;
|
||||
font-family: var(--font-kai);
|
||||
font-size: clamp(21px, 6vw, 26px);
|
||||
letter-spacing: 0.3em;
|
||||
color: var(--c-ink);
|
||||
}
|
||||
.ci-names .vertical-text {
|
||||
writing-mode: vertical-rl;
|
||||
max-height: 120px;
|
||||
}
|
||||
.ci-seal {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 6px;
|
||||
font-family: var(--font-kai);
|
||||
font-size: 15px;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0;
|
||||
color: #fdf6f0;
|
||||
background: #b5493f;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.ci-date {
|
||||
font-family: var(--font-serif);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.24em;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
</style>
|
||||
127
vite-tailwindcss/src/components/themes/covers/CoverKodak.vue
Normal file
127
vite-tailwindcss/src/components/themes/covers/CoverKodak.vue
Normal file
@@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<div class="ck-root">
|
||||
<div v-reveal="'down'" class="ck-strip" aria-hidden="true">
|
||||
<i></i><i></i><i></i>
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'scale', delay: 150 }" class="ck-frame">
|
||||
<span class="ck-holes ck-holes-top" aria-hidden="true"></span>
|
||||
<div class="ck-photo">
|
||||
<img :src="heroImg" class="ck-img" fetchpriority="high" decoding="async" alt="封面" />
|
||||
<span class="ck-stamp">{{ dateStamp }}</span>
|
||||
</div>
|
||||
<span class="ck-holes ck-holes-bottom" aria-hidden="true"></span>
|
||||
<span class="ck-label">WEDDING FILM · 400</span>
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'up', delay: 300 }" class="ck-names">{{ groom }} ♥ {{ bride }}</div>
|
||||
<div v-reveal="{ variant: 'up', delay: 380 }" class="ck-sub">{{ date }} · {{ lunar }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
/** 胶片日记封面:齿孔胶片框 + 复古日期水印 + 柯达色条 */
|
||||
const props = defineProps({
|
||||
heroImg: { type: String, default: '' },
|
||||
groom: { type: String, default: '' },
|
||||
bride: { type: String, default: '' },
|
||||
date: { type: String, default: '' },
|
||||
lunar: { type: String, default: '' },
|
||||
})
|
||||
|
||||
/** 提取 'YY MM DD 形式的复古水印 */
|
||||
const dateStamp = computed(() => {
|
||||
const m = /(\d{4})年(\d{1,2})月(\d{1,2})日/.exec(props.date || '')
|
||||
if (!m) return "'26 09 04"
|
||||
return `'${m[1].slice(2)} ${m[2].padStart(2, '0')} ${m[3].padStart(2, '0')}`
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ck-root {
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
min-height: 100dvh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
padding: max(28px, env(safe-area-inset-top)) 26px 40px;
|
||||
background:
|
||||
var(--t-bg-texture),
|
||||
var(--c-bg);
|
||||
overflow: hidden;
|
||||
}
|
||||
/* 柯达色条 */
|
||||
.ck-strip {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
.ck-strip i {
|
||||
width: 26px;
|
||||
height: 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.ck-strip i:nth-child(1) { background: #e0782e; }
|
||||
.ck-strip i:nth-child(2) { background: #d84438; }
|
||||
.ck-strip i:nth-child(3) { background: #e8b02e; }
|
||||
/* 胶片框 */
|
||||
.ck-frame {
|
||||
width: min(76vw, 280px);
|
||||
background: #201d18;
|
||||
border-radius: 8px;
|
||||
padding: 6px 10px 8px;
|
||||
box-shadow: 0 18px 42px rgba(56, 48, 42, 0.34);
|
||||
}
|
||||
.ck-holes {
|
||||
display: block;
|
||||
height: 9px;
|
||||
margin: 4px 2px;
|
||||
background-image: repeating-linear-gradient(90deg, rgba(250, 246, 236, 0.9) 0 10px, transparent 10px 21px);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.ck-photo {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ck-img {
|
||||
width: 100%;
|
||||
aspect-ratio: 3 / 4;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
filter: sepia(0.18) saturate(1.15) contrast(1.02) brightness(1.02);
|
||||
}
|
||||
/* 复古橙色日期水印 */
|
||||
.ck-stamp {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
bottom: 8px;
|
||||
font-family: var(--font-number);
|
||||
font-size: 15px;
|
||||
letter-spacing: 0.08em;
|
||||
color: #ff9a3c;
|
||||
text-shadow: 0 0 7px rgba(255, 130, 30, 0.75);
|
||||
}
|
||||
.ck-label {
|
||||
display: block;
|
||||
text-align: center;
|
||||
padding-top: 3px;
|
||||
font-size: 8.5px;
|
||||
letter-spacing: 0.3em;
|
||||
color: rgba(250, 246, 236, 0.6);
|
||||
}
|
||||
.ck-names {
|
||||
font-size: clamp(21px, 6.4vw, 27px);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.14em;
|
||||
color: var(--c-ink);
|
||||
}
|
||||
.ck-sub {
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.2em;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
</style>
|
||||
209
vite-tailwindcss/src/components/themes/covers/CoverPassport.vue
Normal file
209
vite-tailwindcss/src/components/themes/covers/CoverPassport.vue
Normal file
@@ -0,0 +1,209 @@
|
||||
<template>
|
||||
<div class="cpp-root">
|
||||
<div v-reveal="'down'" class="cpp-head">
|
||||
<span class="cpp-air">LOVE AIRLINES</span>
|
||||
<span class="cpp-class">FIRST CLASS</span>
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'scale', delay: 150 }" class="cpp-ticket">
|
||||
<div class="cpp-photo">
|
||||
<img :src="heroImg" class="cpp-img" fetchpriority="high" decoding="async" alt="封面" />
|
||||
</div>
|
||||
<div class="cpp-info">
|
||||
<div class="cpp-route">
|
||||
<span class="cpp-port"><b>SGL</b><i>单身</i></span>
|
||||
<span class="cpp-plane" aria-hidden="true">
|
||||
<svg viewBox="0 0 90 20"><path d="M2 12h30M58 12h30" stroke="var(--c-line)" stroke-width="1" stroke-dasharray="3 3" fill="none"/><path d="M40 10l12 2-12 2 3-2z" fill="var(--c-primary)"/></svg>
|
||||
</span>
|
||||
<span class="cpp-port"><b>MRD</b><i>已婚</i></span>
|
||||
</div>
|
||||
<div class="cpp-row">
|
||||
<span class="cpp-cell"><i>PASSENGERS</i><b>{{ groom }} / {{ bride }}</b></span>
|
||||
</div>
|
||||
<div class="cpp-row">
|
||||
<span class="cpp-cell"><i>DATE</i><b>{{ date }}</b></span>
|
||||
<span class="cpp-cell"><i>GATE</i><b>FOREVER</b></span>
|
||||
</div>
|
||||
<div class="cpp-barcode" aria-hidden="true"><i v-for="n in 22" :key="n"></i></div>
|
||||
</div>
|
||||
<span class="cpp-stamp" aria-hidden="true">APPROVED ♥</span>
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'up', delay: 320 }" class="cpp-foot">{{ lunar }} · 一起飞往余生</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/** 环球旅行封面:登机牌(单身 → 已婚 航线、乘客栏、条码、盖章) */
|
||||
defineProps({
|
||||
heroImg: { type: String, default: '' },
|
||||
groom: { type: String, default: '' },
|
||||
bride: { type: String, default: '' },
|
||||
date: { type: String, default: '' },
|
||||
lunar: { type: String, default: '' },
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cpp-root {
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
min-height: 100dvh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 26px;
|
||||
padding: max(28px, env(safe-area-inset-top)) 22px 40px;
|
||||
background:
|
||||
var(--t-bg-texture),
|
||||
var(--c-bg);
|
||||
overflow: hidden;
|
||||
}
|
||||
.cpp-head {
|
||||
width: min(100%, 330px);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-family: var(--font-number);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.26em;
|
||||
color: var(--c-primary);
|
||||
}
|
||||
.cpp-class {
|
||||
color: var(--c-line);
|
||||
}
|
||||
.cpp-ticket {
|
||||
position: relative;
|
||||
width: min(100%, 330px);
|
||||
border-radius: 12px;
|
||||
background: var(--c-card);
|
||||
border: 1px solid rgba(var(--c-primary-rgb), 0.3);
|
||||
box-shadow: 0 16px 40px rgba(44, 54, 64, 0.16);
|
||||
overflow: hidden;
|
||||
}
|
||||
/* 登机牌撕边 */
|
||||
.cpp-ticket::before,
|
||||
.cpp-ticket::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 58%;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background: var(--c-bg);
|
||||
border: 1px solid rgba(var(--c-primary-rgb), 0.3);
|
||||
}
|
||||
.cpp-ticket::before { left: -9px; }
|
||||
.cpp-ticket::after { right: -9px; }
|
||||
.cpp-photo {
|
||||
height: 168px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.cpp-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.cpp-info {
|
||||
padding: 14px 16px 14px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.cpp-route {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
.cpp-port {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
.cpp-port b {
|
||||
font-family: var(--font-number);
|
||||
font-size: 24px;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--c-primary);
|
||||
}
|
||||
.cpp-port i {
|
||||
font-style: normal;
|
||||
font-size: 9px;
|
||||
letter-spacing: 0.2em;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
.cpp-plane {
|
||||
flex: 1;
|
||||
}
|
||||
.cpp-plane svg {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
display: block;
|
||||
}
|
||||
.cpp-row {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
border-top: 1px dashed rgba(var(--c-primary-rgb), 0.25);
|
||||
padding-top: 9px;
|
||||
}
|
||||
.cpp-cell {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
}
|
||||
.cpp-cell i {
|
||||
font-style: normal;
|
||||
font-family: var(--font-number);
|
||||
font-size: 8px;
|
||||
letter-spacing: 0.22em;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
.cpp-cell b {
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--c-ink);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.cpp-barcode {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 2px;
|
||||
height: 20px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.cpp-barcode i {
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background: var(--c-ink);
|
||||
opacity: 0.8;
|
||||
}
|
||||
.cpp-barcode i:nth-child(2n) { height: 72%; width: 1px; }
|
||||
.cpp-barcode i:nth-child(3n) { height: 86%; width: 3px; }
|
||||
/* 邮戳 */
|
||||
.cpp-stamp {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 130px;
|
||||
padding: 5px 10px;
|
||||
font-family: var(--font-number);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.14em;
|
||||
color: #b5493f;
|
||||
border: 2px solid #b5493f;
|
||||
border-radius: 6px;
|
||||
transform: rotate(-12deg);
|
||||
opacity: 0.85;
|
||||
background: rgba(255, 252, 246, 0.55);
|
||||
}
|
||||
.cpp-foot {
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.24em;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
</style>
|
||||
157
vite-tailwindcss/src/components/themes/covers/CoverScrapbook.vue
Normal file
157
vite-tailwindcss/src/components/themes/covers/CoverScrapbook.vue
Normal file
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<div class="cs-root">
|
||||
<span v-reveal="'down'" class="cs-kicker">○ my wedding journal ○</span>
|
||||
|
||||
<div v-reveal="{ variant: 'scale', delay: 150 }" class="cs-photo-wrap">
|
||||
<span class="cs-tape cs-tape-l" aria-hidden="true"></span>
|
||||
<span class="cs-tape cs-tape-r" aria-hidden="true"></span>
|
||||
<div class="cs-photo">
|
||||
<img :src="heroImg" class="cs-img" fetchpriority="high" decoding="async" alt="封面" />
|
||||
<span class="cs-caption">us ♥</span>
|
||||
</div>
|
||||
<span class="cs-sticker cs-sticker-1" aria-hidden="true">♥</span>
|
||||
<span class="cs-sticker cs-sticker-2" aria-hidden="true">★</span>
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'up', delay: 300 }" class="cs-names">
|
||||
<span>{{ groom }}</span>
|
||||
<em>&</em>
|
||||
<span>{{ bride }}</span>
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'up', delay: 380 }" class="cs-date-tag">
|
||||
<span>{{ date }}</span>
|
||||
<small>{{ lunar }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/** 手账拼贴封面:胶带斜贴拍立得 + 贴纸 + 手写标签 */
|
||||
defineProps({
|
||||
heroImg: { type: String, default: '' },
|
||||
groom: { type: String, default: '' },
|
||||
bride: { type: String, default: '' },
|
||||
date: { type: String, default: '' },
|
||||
lunar: { type: String, default: '' },
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cs-root {
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
min-height: 100dvh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
padding: max(28px, env(safe-area-inset-top)) 26px 42px;
|
||||
background:
|
||||
var(--t-bg-texture),
|
||||
var(--c-bg);
|
||||
overflow: hidden;
|
||||
}
|
||||
.cs-kicker {
|
||||
font-family: var(--font-liujian);
|
||||
font-size: 14px;
|
||||
letter-spacing: 0.2em;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
.cs-photo-wrap {
|
||||
position: relative;
|
||||
transform: rotate(-2.5deg);
|
||||
}
|
||||
.cs-photo {
|
||||
width: min(64vw, 240px);
|
||||
padding: 10px 10px 34px;
|
||||
background: var(--c-card);
|
||||
box-shadow: 0 12px 32px rgba(69, 58, 48, 0.18);
|
||||
border: 1px solid rgba(69, 58, 48, 0.08);
|
||||
}
|
||||
.cs-img {
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
.cs-caption {
|
||||
display: block;
|
||||
padding-top: 8px;
|
||||
text-align: center;
|
||||
font-family: var(--font-liujian);
|
||||
font-size: 15px;
|
||||
color: var(--c-ink-soft);
|
||||
}
|
||||
.cs-tape {
|
||||
position: absolute;
|
||||
width: 74px;
|
||||
height: 24px;
|
||||
background: rgba(138, 168, 138, 0.5);
|
||||
box-shadow: 0 1px 4px rgba(69, 58, 48, 0.16);
|
||||
z-index: 2;
|
||||
}
|
||||
.cs-tape-l { top: -12px; left: -22px; transform: rotate(-38deg); }
|
||||
.cs-tape-r { top: -10px; right: -24px; transform: rotate(32deg); background: rgba(216, 168, 72, 0.45); }
|
||||
.cs-sticker {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
box-shadow: 0 2px 6px rgba(69, 58, 48, 0.24);
|
||||
}
|
||||
.cs-sticker-1 {
|
||||
right: -16px;
|
||||
bottom: 22px;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
font-size: 15px;
|
||||
background: #c47a5a;
|
||||
transform: rotate(10deg);
|
||||
}
|
||||
.cs-sticker-2 {
|
||||
left: -14px;
|
||||
bottom: 52px;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
font-size: 12px;
|
||||
background: #8aa88a;
|
||||
transform: rotate(-14deg);
|
||||
}
|
||||
.cs-names {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 12px;
|
||||
font-family: var(--font-longcang);
|
||||
font-size: clamp(26px, 8vw, 34px);
|
||||
color: var(--c-ink);
|
||||
}
|
||||
.cs-names em {
|
||||
font-style: normal;
|
||||
font-size: 0.6em;
|
||||
color: var(--c-primary);
|
||||
}
|
||||
.cs-date-tag {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
padding: 8px 18px;
|
||||
background: var(--c-card);
|
||||
border: 1px dashed rgba(var(--c-primary-rgb), 0.5);
|
||||
border-radius: 8px;
|
||||
transform: rotate(1.6deg);
|
||||
font-family: var(--font-liujian);
|
||||
}
|
||||
.cs-date-tag span {
|
||||
font-size: 14px;
|
||||
color: var(--c-ink-soft);
|
||||
}
|
||||
.cs-date-tag small {
|
||||
font-size: 11px;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
</style>
|
||||
186
vite-tailwindcss/src/components/themes/covers/CoverY2k.vue
Normal file
186
vite-tailwindcss/src/components/themes/covers/CoverY2k.vue
Normal file
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div class="cy-root">
|
||||
<div v-reveal="{ variant: 'scale', delay: 100 }" class="cy-window">
|
||||
<div class="cy-titlebar">
|
||||
<span class="cy-title-text">wedding.exe</span>
|
||||
<span class="cy-btns" aria-hidden="true"><i>▁</i><i>▢</i><i>✕</i></span>
|
||||
</div>
|
||||
<div class="cy-body">
|
||||
<div class="cy-photo">
|
||||
<img :src="heroImg" class="cy-img" fetchpriority="high" decoding="async" alt="封面" />
|
||||
</div>
|
||||
<div class="cy-names">{{ groom }} ♥ {{ bride }}</div>
|
||||
<div class="cy-date">{{ date }} ☆ {{ lunar }}</div>
|
||||
<div class="cy-progress" aria-hidden="true">
|
||||
<span class="cy-progress-label">loading love… 99%</span>
|
||||
<span class="cy-progress-track"><i></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-reveal="{ variant: 'up', delay: 320 }" class="cy-cursor" aria-hidden="true">
|
||||
<span class="cy-star">✦</span>
|
||||
<span class="cy-hint">click to continue</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/** 千禧蒸汽波封面:复古 UI 窗口(标题栏/加载条)+ 渐变镜面字 + 星星光标 */
|
||||
defineProps({
|
||||
heroImg: { type: String, default: '' },
|
||||
groom: { type: String, default: '' },
|
||||
bride: { type: String, default: '' },
|
||||
date: { type: String, default: '' },
|
||||
lunar: { type: String, default: '' },
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cy-root {
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
min-height: 100dvh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 30px;
|
||||
padding: max(28px, env(safe-area-inset-top)) 24px 44px;
|
||||
background:
|
||||
var(--t-bg-texture),
|
||||
linear-gradient(160deg, #ece8f8 0%, #e0ecf8 48%, #f4e4f4 100%);
|
||||
overflow: hidden;
|
||||
}
|
||||
.cy-window {
|
||||
width: min(100%, 330px);
|
||||
border: 2px solid #9088b8;
|
||||
border-radius: 10px;
|
||||
background: var(--c-card);
|
||||
box-shadow:
|
||||
inset 1px 1px 0 rgba(255, 255, 255, 0.9),
|
||||
6px 8px 0 rgba(122, 74, 224, 0.18),
|
||||
0 20px 46px rgba(84, 74, 112, 0.22);
|
||||
overflow: hidden;
|
||||
}
|
||||
.cy-titlebar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 7px 10px;
|
||||
background: linear-gradient(90deg, #7a4ae0, #4a90e0 55%, #4adce0);
|
||||
color: #fff;
|
||||
}
|
||||
.cy-title-text {
|
||||
font-family: var(--font-pixel);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
.cy-btns {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
.cy-btns i {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 8px;
|
||||
font-style: normal;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
color: #544a70;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.cy-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 18px 18px 20px;
|
||||
}
|
||||
.cy-photo {
|
||||
width: 100%;
|
||||
border: 2px solid #b8b0d8;
|
||||
border-radius: 6px;
|
||||
padding: 4px;
|
||||
background: #fff;
|
||||
}
|
||||
.cy-img {
|
||||
width: 100%;
|
||||
aspect-ratio: 4 / 3;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
border-radius: 3px;
|
||||
filter: saturate(1.15) contrast(1.02);
|
||||
}
|
||||
/* 渐变镜面字 */
|
||||
.cy-names {
|
||||
font-size: clamp(23px, 7vw, 29px);
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.08em;
|
||||
background: linear-gradient(180deg, #7a4ae0 8%, #4a90e0 44%, #4adce0 58%, #e04ad0 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
filter: drop-shadow(0 2px 0 rgba(255, 255, 255, 0.8)) drop-shadow(0 4px 10px rgba(122, 74, 224, 0.3));
|
||||
}
|
||||
.cy-date {
|
||||
font-family: var(--font-pixel);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--c-ink-soft);
|
||||
}
|
||||
.cy-progress {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
.cy-progress-label {
|
||||
font-family: var(--font-pixel);
|
||||
font-size: 9px;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
.cy-progress-track {
|
||||
display: block;
|
||||
height: 12px;
|
||||
border: 2px solid #9088b8;
|
||||
border-radius: 4px;
|
||||
padding: 1px;
|
||||
background: #fff;
|
||||
}
|
||||
.cy-progress-track i {
|
||||
display: block;
|
||||
width: 99%;
|
||||
height: 100%;
|
||||
border-radius: 2px;
|
||||
background: repeating-linear-gradient(90deg, #7a4ae0 0 8px, #4adce0 8px 16px);
|
||||
animation: cyLoad 1.6s steps(8) infinite;
|
||||
}
|
||||
@keyframes cyLoad {
|
||||
0% { background-position: 0 0; }
|
||||
100% { background-position: 32px 0; }
|
||||
}
|
||||
.cy-cursor {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.cy-star {
|
||||
font-size: 20px;
|
||||
color: #7a4ae0;
|
||||
animation: cyTwinkle 1.2s steps(2) infinite;
|
||||
}
|
||||
@keyframes cyTwinkle {
|
||||
0%, 100% { opacity: 1; transform: scale(1); }
|
||||
50% { opacity: 0.45; transform: scale(0.85); }
|
||||
}
|
||||
.cy-hint {
|
||||
font-family: var(--font-pixel);
|
||||
font-size: 9px;
|
||||
letter-spacing: 0.16em;
|
||||
color: var(--c-muted);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user