chore: 更新素材和组件优化
- 更新展品图片(鲁迅/毛泽东/孙中山/黄炎培/聂耳/张乐平故居) - 新增点击查看图标、报纸素材 - 优化视频组件、拼图组件、展品组件 - 更新陈云音频资源 - 新增输入验证文档和工具函数 - 组件布局和动画优化 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
73d02eb62d
commit
73f6df92ce
130 files changed
+2345
-759
No files matched your search
@@ -89,139 +89,137 @@ const ExhibitFlipOverlay = ({
|
||||
if (!mounted || !visible) return null
|
||||
|
||||
return (
|
||||
<div style={OVERLAY_STYLE}>
|
||||
<div
|
||||
className={cn('absolute inset-0 flex items-center justify-center', className)}
|
||||
style={{ pointerEvents: 'auto' }}
|
||||
>
|
||||
{/* 第二段:背景与按钮在展品入场后再出现 */}
|
||||
{showChrome && (
|
||||
<>
|
||||
<div
|
||||
className={cn('absolute inset-0 flex items-center justify-center z-9999', className)}
|
||||
style={{ pointerEvents: 'auto' }}
|
||||
>
|
||||
{/* 第二段:背景与按钮在展品入场后再出现 */}
|
||||
{showChrome && (
|
||||
<>
|
||||
<motion.div
|
||||
className="absolute inset-0 bg-black/70"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.22, ease: 'easeOut' }}
|
||||
/>
|
||||
|
||||
{onClose && (
|
||||
<motion.div
|
||||
className="absolute inset-0 bg-black/70"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
className="absolute top-5 right-5 z-20"
|
||||
initial={{ opacity: 0, y: -6 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.22, ease: 'easeOut' }}
|
||||
/>
|
||||
>
|
||||
<Image
|
||||
src={backSrc}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onClose()
|
||||
}}
|
||||
alt="返回"
|
||||
button
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{onClose && (
|
||||
<motion.div
|
||||
className="absolute top-5 right-5 z-20"
|
||||
initial={{ opacity: 0, y: -6 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.22, ease: 'easeOut' }}
|
||||
>
|
||||
<Image
|
||||
src={backSrc}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onClose()
|
||||
}}
|
||||
alt="返回"
|
||||
button
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<div
|
||||
className="relative z-10 w-[900px] h-[900px] max-w-[90%] max-h-[90%] flex items-center justify-center select-none"
|
||||
<div
|
||||
className="relative z-10 w-[900px] h-[900px] max-w-[90%] max-h-[90%] flex items-center justify-center select-none"
|
||||
style={{
|
||||
perspective: 1200,
|
||||
WebkitPerspective: '1200px',
|
||||
}}
|
||||
>
|
||||
{/* 第一段:像“获得装备”一样先把展品弹出 */}
|
||||
<motion.div
|
||||
className={cn(
|
||||
'relative w-full h-full',
|
||||
'transition-transform duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)]'
|
||||
)}
|
||||
initial={{ scale: 0.25, opacity: 0, rotateY: 0 }}
|
||||
animate={{ scale: displayScale, opacity: 1, rotateY: flipped ? 180 : 0 }}
|
||||
transition={{
|
||||
type: 'spring',
|
||||
stiffness: 520,
|
||||
damping: 26,
|
||||
mass: 0.8,
|
||||
}}
|
||||
onAnimationComplete={() => {
|
||||
if (!showChrome) {
|
||||
setShowChrome(true)
|
||||
onEnterComplete?.()
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
perspective: 1200,
|
||||
WebkitPerspective: '1200px',
|
||||
transformStyle: 'preserve-3d',
|
||||
WebkitTransformStyle: 'preserve-3d',
|
||||
}}
|
||||
>
|
||||
{/* 第一段:像“获得装备”一样先把展品弹出 */}
|
||||
<motion.div
|
||||
className={cn(
|
||||
'relative w-full h-full',
|
||||
'transition-transform duration-500 ease-[cubic-bezier(0.2,0.8,0.2,1)]'
|
||||
)}
|
||||
initial={{ scale: 0.25, opacity: 0, rotateY: 0 }}
|
||||
animate={{ scale: displayScale, opacity: 1, rotateY: flipped ? 180 : 0 }}
|
||||
transition={{
|
||||
type: 'spring',
|
||||
stiffness: 520,
|
||||
damping: 26,
|
||||
mass: 0.8,
|
||||
}}
|
||||
onAnimationComplete={() => {
|
||||
if (!showChrome) {
|
||||
setShowChrome(true)
|
||||
onEnterComplete?.()
|
||||
}
|
||||
}}
|
||||
<div
|
||||
className="absolute inset-0 flex items-center justify-center"
|
||||
style={{
|
||||
transformStyle: 'preserve-3d',
|
||||
WebkitTransformStyle: 'preserve-3d',
|
||||
backfaceVisibility: 'hidden',
|
||||
WebkitBackfaceVisibility: 'hidden',
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={frontImageSrc}
|
||||
alt="展品"
|
||||
className="max-w-full max-h-full object-contain drop-shadow-2xl"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{canFlip && (
|
||||
<div
|
||||
className="absolute inset-0 flex items-center justify-center"
|
||||
style={{
|
||||
backfaceVisibility: 'hidden',
|
||||
WebkitBackfaceVisibility: 'hidden',
|
||||
transform: 'rotateY(180deg)',
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={frontImageSrc}
|
||||
alt="展品"
|
||||
src={backImageSrc!}
|
||||
alt="展品背面"
|
||||
className="max-w-full max-h-full object-contain drop-shadow-2xl"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{canFlip && (
|
||||
<div
|
||||
className="absolute inset-0 flex items-center justify-center"
|
||||
style={{
|
||||
backfaceVisibility: 'hidden',
|
||||
WebkitBackfaceVisibility: 'hidden',
|
||||
transform: 'rotateY(180deg)',
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={backImageSrc!}
|
||||
alt="展品背面"
|
||||
className="max-w-full max-h-full object-contain drop-shadow-2xl"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</motion.div>
|
||||
|
||||
{showChrome && canFlip && (
|
||||
<motion.div
|
||||
className="absolute bottom-50 right-0 z-20"
|
||||
initial={{ opacity: 0, y: 8 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.22, ease: 'easeOut' }}
|
||||
>
|
||||
<FlipActionButton
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setFlipped((v) => !v)
|
||||
}}
|
||||
>
|
||||
翻转一下
|
||||
</FlipActionButton>
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{showChrome && footer && (
|
||||
{showChrome && canFlip && (
|
||||
<motion.div
|
||||
className={cn(
|
||||
'absolute left-1/2 bottom-38 z-30 -translate-x-1/2 pointer-events-auto',
|
||||
footerClassName
|
||||
)}
|
||||
className="absolute bottom-50 right-0 z-20"
|
||||
initial={{ opacity: 0, y: 8 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.22, ease: 'easeOut' }}
|
||||
>
|
||||
{footer}
|
||||
<FlipActionButton
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setFlipped((v) => !v)
|
||||
}}
|
||||
>
|
||||
翻转一下
|
||||
</FlipActionButton>
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{showChrome && footer && (
|
||||
<motion.div
|
||||
className={cn(
|
||||
'absolute left-1/2 bottom-38 z-30 -translate-x-1/2 pointer-events-auto',
|
||||
footerClassName
|
||||
)}
|
||||
initial={{ opacity: 0, y: 8 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.22, ease: 'easeOut' }}
|
||||
>
|
||||
{footer}
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user