198 lines
7.4 KiB
Vue
198 lines
7.4 KiB
Vue
<script setup lang="ts">
|
||
import { usePreferredReducedMotion } from '@vueuse/core'
|
||
import { computed, ref } from 'vue'
|
||
import type { Memory } from '../api/client'
|
||
import { getStandardNepalTheme } from '../constants/nepalThemes'
|
||
import PolaroidCard from './PolaroidCard.vue'
|
||
import { renderMarkdown } from '../utils/renderMarkdown'
|
||
|
||
const props = defineProps<{
|
||
memory: Memory
|
||
}>()
|
||
|
||
const bodyHtml = computed(() => renderMarkdown(props.memory.main_text))
|
||
const theme = computed(() => getStandardNepalTheme(props.memory.nepal_art_style))
|
||
const reduceMotion = usePreferredReducedMotion()
|
||
const talkedItOut = ref(false)
|
||
</script>
|
||
|
||
<template>
|
||
<div
|
||
class="relative mx-auto max-w-lg overflow-hidden rounded-3xl bg-gradient-to-br px-3 pb-8 pt-6 sm:px-5 sm:pb-10 sm:pt-8"
|
||
:class="theme.gradient"
|
||
>
|
||
<div
|
||
class="pointer-events-none absolute -left-10 top-12 h-44 w-44 rounded-full bg-emerald-300/22 blur-[3rem]"
|
||
aria-hidden="true"
|
||
/>
|
||
<div
|
||
class="pointer-events-none absolute -right-10 bottom-10 h-52 w-52 rounded-full bg-cyan-300/18 blur-[3.5rem]"
|
||
aria-hidden="true"
|
||
/>
|
||
|
||
<div
|
||
class="relative z-[1] mx-auto mb-7 max-w-[min(100%,396px)] overflow-hidden rounded-[2rem] border border-emerald-200/65 bg-[linear-gradient(180deg,#f7fffb_0%,#eefcf7_100%)] shadow-[0_24px_56px_-18px_rgba(16,185,129,0.22)]"
|
||
>
|
||
<div class="pointer-events-none absolute inset-0 nepal-fiber opacity-[0.14] mix-blend-multiply" />
|
||
|
||
<div class="relative px-5 pb-5 pt-5 sm:px-6 sm:pb-6">
|
||
<div class="flex items-start justify-between gap-4">
|
||
<div>
|
||
<p class="text-[10px] font-semibold uppercase tracking-[0.32em] text-emerald-700/65">
|
||
Make Up / 05.04
|
||
</p>
|
||
<h3 class="mt-2 font-display-cn text-[1.9rem] leading-none text-emerald-950">
|
||
和好了,在一起吧
|
||
</h3>
|
||
</div>
|
||
<div
|
||
class="rounded-2xl border border-emerald-200/70 bg-white/88 px-3 py-2 text-right shadow-[0_8px_20px_rgba(16,185,129,0.12)]"
|
||
>
|
||
<p class="text-[9px] font-semibold tracking-[0.22em] text-emerald-700/70">
|
||
关系状态
|
||
</p>
|
||
<p class="mt-1 font-brush text-xl text-emerald-950">已和好</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mt-6 rounded-[1.8rem] border border-emerald-200/60 bg-white/78 p-4 shadow-inner">
|
||
<div class="grid gap-3 sm:grid-cols-[0.92fr_0.16fr_0.92fr] sm:items-center">
|
||
<div
|
||
class="rounded-[1.5rem] border border-rose-200/65 bg-rose-50/88 px-4 py-4 shadow-[0_10px_20px_rgba(244,114,182,0.08)]"
|
||
:class="[
|
||
reduceMotion === 'reduce' ? '' : 'reconcile-card-left',
|
||
talkedItOut ? 'sm:translate-x-2' : '',
|
||
]"
|
||
>
|
||
<p class="text-[10px] font-semibold uppercase tracking-[0.25em] text-rose-700/65">
|
||
Before
|
||
</p>
|
||
<p class="mt-2 text-lg font-medium text-rose-950">别扭、沉默、想解释</p>
|
||
</div>
|
||
|
||
<div class="relative flex items-center justify-center py-2">
|
||
<div
|
||
class="flex h-16 w-16 items-center justify-center rounded-full bg-gradient-to-br from-emerald-300 to-cyan-300 text-2xl text-white shadow-[0_14px_28px_rgba(16,185,129,0.22)]"
|
||
:class="[
|
||
reduceMotion === 'reduce' ? '' : 'reconcile-heartbeat',
|
||
talkedItOut ? 'scale-110' : '',
|
||
]"
|
||
role="button"
|
||
tabindex="0"
|
||
@click="talkedItOut = !talkedItOut"
|
||
>
|
||
♡
|
||
</div>
|
||
<div class="absolute inset-x-0 top-1/2 h-px -translate-y-1/2 bg-gradient-to-r from-rose-200 via-emerald-300 to-cyan-200" aria-hidden="true" />
|
||
</div>
|
||
|
||
<div
|
||
class="rounded-[1.5rem] border border-cyan-200/70 bg-cyan-50/88 px-4 py-4 shadow-[0_10px_20px_rgba(34,211,238,0.08)]"
|
||
:class="[
|
||
reduceMotion === 'reduce' ? '' : 'reconcile-card-right',
|
||
talkedItOut ? 'sm:-translate-x-2' : '',
|
||
]"
|
||
>
|
||
<p class="text-[10px] font-semibold uppercase tracking-[0.25em] text-cyan-700/65">
|
||
After
|
||
</p>
|
||
<p class="mt-2 text-lg font-medium text-cyan-950">说开了、靠近了、在一起了</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mt-4 rounded-[1.4rem] border border-emerald-200/75 bg-emerald-50/85 px-4 py-4">
|
||
<div class="flex flex-wrap justify-center gap-2">
|
||
<span
|
||
v-for="tag in ['把话说完', '空气变甜', '正式在一起']"
|
||
:key="tag"
|
||
class="rounded-full border border-emerald-200 bg-white/85 px-3 py-1.5 text-[11px] font-medium text-emerald-800/85"
|
||
>
|
||
{{ tag }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mt-4 flex flex-col items-center gap-2">
|
||
<button
|
||
type="button"
|
||
class="rounded-full border border-emerald-200 bg-white/92 px-4 py-2 text-xs font-semibold tracking-[0.18em] text-emerald-900 transition hover:bg-emerald-50"
|
||
@click="talkedItOut = !talkedItOut"
|
||
>
|
||
{{ talkedItOut ? '先把话收回一点' : '把话说开' }}
|
||
</button>
|
||
<p class="text-center text-[11px] leading-relaxed text-emerald-900/70">
|
||
{{ talkedItOut ? '说开以后,卡在中间的那口气终于顺了。' : '轻点一下,让“Before”和“After”靠近一点。' }}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="relative z-[1] flex flex-col gap-6 sm:gap-8">
|
||
<PolaroidCard :memory="memory" :index="memory.story_order" compact />
|
||
|
||
<div
|
||
class="nepal-torn-panel mx-auto max-w-md border border-emerald-200/70 bg-gradient-to-b from-[#fffefa] to-emerald-50/65 px-5 py-6 shadow-[0_16px_36px_-12px_rgba(16,185,129,0.18)] ring-1 ring-white/80 sm:px-6 sm:py-7"
|
||
>
|
||
<div class="mb-4 h-1 w-14 rounded-full bg-gradient-to-r from-emerald-400 to-cyan-400" aria-hidden="true" />
|
||
<div
|
||
class="text-[15px] leading-[1.82] tracking-wide text-emerald-950/88 [&_a]:font-bold [&_a]:text-cyan-700 [&_a]:underline [&_a]:underline-offset-4 [&_blockquote]:border-l-4 [&_blockquote]:border-emerald-300/60 [&_blockquote]:bg-emerald-50/55 [&_blockquote]:py-1 [&_blockquote]:pl-3 [&_blockquote]:text-emerald-900/70 [&_code]:rounded [&_code]:bg-emerald-100/50 [&_code]:px-1.5 [&_strong]:text-emerald-950 [&_p+p]:mt-4"
|
||
v-html="bodyHtml"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.reconcile-heartbeat {
|
||
animation: reconcile-heartbeat 2.4s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes reconcile-heartbeat {
|
||
0%,
|
||
100% {
|
||
transform: scale(1);
|
||
}
|
||
20% {
|
||
transform: scale(1.08);
|
||
}
|
||
36% {
|
||
transform: scale(0.98);
|
||
}
|
||
56% {
|
||
transform: scale(1.05);
|
||
}
|
||
}
|
||
|
||
.reconcile-card-left {
|
||
animation: reconcile-card-left 0.65s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||
}
|
||
|
||
.reconcile-card-right {
|
||
animation: reconcile-card-right 0.65s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||
}
|
||
|
||
@keyframes reconcile-card-left {
|
||
0% {
|
||
opacity: 0;
|
||
transform: translateX(-16px);
|
||
}
|
||
100% {
|
||
opacity: 1;
|
||
transform: translateX(0);
|
||
}
|
||
}
|
||
|
||
@keyframes reconcile-card-right {
|
||
0% {
|
||
opacity: 0;
|
||
transform: translateX(16px);
|
||
}
|
||
100% {
|
||
opacity: 1;
|
||
transform: translateX(0);
|
||
}
|
||
}
|
||
</style>
|