diff --git a/components/add-sighting-drawer.tsx b/components/add-sighting-drawer.tsx index 471703a..e4a7b29 100644 --- a/components/add-sighting-drawer.tsx +++ b/components/add-sighting-drawer.tsx @@ -237,10 +237,6 @@ export function AddSightingDrawer() { ) : (
- -
)} diff --git a/components/book-sticker-instruction.tsx b/components/book-sticker-instruction.tsx index 29f7358..48c32d6 100644 --- a/components/book-sticker-instruction.tsx +++ b/components/book-sticker-instruction.tsx @@ -13,6 +13,17 @@ interface BookStickerInstructionProps { code: string coverUrl?: string className?: string + animationSpeedMultiplier?: number +} + +// Animation Configuration +const ANIMATION_BASE_DURATION_S = 2.5 +// Derived timings +const ANIMATION_CONFIG = { + duration: ANIMATION_BASE_DURATION_S, + openDelay: ANIMATION_BASE_DURATION_S * 0.3, // ~0.5s if base is 2.5 + urlWriteDelay: ANIMATION_BASE_DURATION_S * 0.28, // Starts shortly after page flip starts? No, originally 0.2 which is small. + codeWriteDelay: 1.0, // 1.2 - 0.2, relative to URL finishing } const TypewriterText = ({ @@ -76,20 +87,24 @@ const TypewriterText = ({ export function BookStickerInstruction({ code, coverUrl, className }: BookStickerInstructionProps) { const [copied, setCopied] = useState(false) const [isOpen, setIsOpen] = useState(false) + const [aspectRatio, setAspectRatio] = useState(1 / 1.3) + + // Refined plan: Use a ref or state for style. + const [dynamicAspectRatio, setDynamicAspectRatio] = useState(1.3) useEffect(() => { // Open the book shortly after mount const timer = setTimeout(() => { setIsOpen(true) - }, 500) + }, ANIMATION_CONFIG.openDelay * 1000) return () => clearTimeout(timer) }, []) useEffect(() => { if (isOpen) { - // Trigger confetti when book opens and ink dries (approx 2s delay total relative to open) - // Let's time it with the code writing completion + const confettiDelayMs = (ANIMATION_CONFIG.duration + 1.0) * 1000 + const confettiTimer = setTimeout(() => { const end = Date.now() + 1000 const colors = ["#a8e6cf", "#dcedc1", "#ffd3b6", "#ffaaa5", "#ff8b94"] @@ -114,7 +129,7 @@ export function BookStickerInstruction({ code, coverUrl, className }: BookSticke requestAnimationFrame(frame) } })() - }, 2500) // Delay to match writing animation + }, confettiDelayMs) return () => clearTimeout(confettiTimer) } @@ -135,7 +150,7 @@ export function BookStickerInstruction({ code, coverUrl, className }: BookSticke
{/* The 3D Book Container */} -
+
{/* The Book Itself */} {/* RIGHT PAGE (The "Book Block" that stays underneath) */}
@@ -163,7 +178,12 @@ export function BookStickerInstruction({ code, coverUrl, className }: BookSticke animate={{ rotateY: isOpen ? -180 : 0, }} - transition={{ duration: 1.5, type: "spring", stiffness: 40, damping: 12 }} + transition={{ + duration: ANIMATION_CONFIG.duration, + type: "spring", + stiffness: 40, + damping: 12, + }} onUpdate={(latest) => { // Track rotation to toggle visibility state at 90 degrees (halfway) if (typeof latest.rotateY === "number") { @@ -184,7 +204,13 @@ export function BookStickerInstruction({ code, coverUrl, className }: BookSticke Book Cover { + const img = e.currentTarget + if (img.naturalWidth && img.naturalHeight) { + setDynamicAspectRatio(img.naturalWidth / img.naturalHeight) + } + }} /> ) : (
@@ -221,7 +247,7 @@ export function BookStickerInstruction({ code, coverUrl, className }: BookSticke
@@ -234,7 +260,9 @@ export function BookStickerInstruction({ code, coverUrl, className }: BookSticke