damus.io

damus.io website
git clone git://jb55.com/damus.io
Log | Files | Refs | README | LICENSE

MostZappedNote.tsx (3179B)


      1 import { MotionValue, circOut, easeInOut, easeOut, motion, useMotionValue, useScroll, useTime, useTransform } from "framer-motion";
      2 import { PurpleIcon } from "../../icons/PurpleIcon";
      3 import { ArrowDown, ZapIcon } from "lucide-react";
      4 import { NostrNoteView, ParsedNote } from "@/components/note/NostrNoteView";
      5 import { Npub2024InReviewStats } from "@/pages/purple/2024-in-review/[npub]";
      6 import { cn } from "@/lib/utils";
      7 import { useRef } from "react";
      8 import { Orbitron } from "next/font/google";
      9 import NumberFlow from '@number-flow/react'
     10 import { useEffect, useState } from "react";
     11 import { useInterval } from "usehooks-ts";
     12 
     13 const orbitron = Orbitron({ subsets: ['latin'] })
     14 
     15 export function MostZappedNote({ stats, className, style }: { stats: Npub2024InReviewStats, className?: string, style?: React.CSSProperties }) {
     16   const time = useTime()
     17   const ref = useRef<HTMLDivElement>(null)
     18   const { scrollYProgress } = useScroll({
     19     target: ref
     20   })
     21   const [animatedZapAmount, setAnimatedZapAmount] = useState(10000);
     22   const zapProgress = useTransform(
     23     scrollYProgress,
     24     [0.4, 0.6],
     25     [
     26       0.0,
     27       1.0
     28     ],
     29     {
     30       clamp: true,
     31       ease: circOut
     32     }
     33   )
     34   const headingOpacity = useTransform(
     35     scrollYProgress,
     36     [0, 0.4],
     37     [0, 1],
     38     {
     39       clamp: true,
     40       ease: easeInOut
     41     }
     42   )
     43   const secondaryContentOpacity = useTransform(
     44     scrollYProgress,
     45     [0.4, 0.6],
     46     [0, 1],
     47     {
     48       clamp: true,
     49       ease: easeInOut
     50     }
     51   )
     52 
     53   useInterval(() => {
     54     if (zapProgress.get() > 0.0001) {
     55       setAnimatedZapAmount(stats.most_zapped_post_sats)
     56     }
     57     else {
     58       setAnimatedZapAmount(10000)
     59     }
     60   }, 500)
     61 
     62   return <div
     63     ref={ref}
     64     className={cn("container z-30 mx-auto px-4 pt-12 h-full min-h-screen flex flex-col gap-y-4 justify-center items-center", className)}
     65     style={style}
     66   >
     67     <motion.h2
     68       className="text-4xl md:text-6xl text-center text-yellow-50 drop-shadow font-semibold break-keep tracking-tight z-30"
     69       style={{
     70         textShadow: "0 0 60px #facc15",
     71         opacity: headingOpacity,
     72       }}
     73     >
     74       Your most zapped note received
     75     </motion.h2>
     76     <motion.h3
     77       className="flex items-center gap-4 text-3xl md:text-8xl text-center text-white font-semibold break-keep tracking-tight z-30"
     78       style={{
     79         opacity: secondaryContentOpacity,
     80       }}
     81     >
     82       <motion.span
     83         style={{ opacity: secondaryContentOpacity }}
     84       >
     85         <ZapIcon className="w-8 h-8 md:w-16 md:h-16 text-amber-300" />
     86       </motion.span>
     87       <NumberFlow
     88         value={animatedZapAmount}
     89         continuous={true}
     90         transformTiming={{ duration: 1500, easing: "ease-out" }}
     91         opacityTiming={{ duration: 1500, easing: "ease-out" }}
     92         trend={1}
     93       />
     94       <motion.span
     95         className="text-amber-300"
     96         style={{ opacity: secondaryContentOpacity }}
     97       >
     98         sats
     99       </motion.span>
    100     </motion.h3>
    101     <motion.div
    102       className="space-y-4 z-30 w-full max-w-lg"
    103       style={{ opacity: secondaryContentOpacity }}
    104     >
    105       <NostrNoteView note={stats.most_zapped_post} className="w-full max-w-lg" />
    106     </motion.div>
    107   </div>
    108 }