damus.io

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

NumberOfPosts.tsx (3513B)


      1 import { MotionValue, circOut, easeInOut, easeOut, motion, useMotionValue, useScroll, useTime, useTransform } from "framer-motion";
      2 import { ArrowDown, ZapIcon, StickyNote } from "lucide-react";
      3 import { NostrNoteView, ParsedNote } from "@/components/note/NostrNoteView";
      4 import { Npub2024InReviewStats } from "@/pages/purple/2024-in-review/[npub]";
      5 import { cn } from "@/lib/utils";
      6 import { useRef } from "react";
      7 import { Orbitron, Permanent_Marker } from "next/font/google";
      8 import NumberFlow from '@number-flow/react'
      9 import { useEffect, useState } from "react";
     10 import { useInterval } from "usehooks-ts";
     11 import Image from "next/image";
     12 
     13 // const permanentMarker = Permanent_Marker({ weight: "400", subsets: ['latin'] });
     14 
     15 export function NumberOfPosts({ numberOfPosts, className, style }: { numberOfPosts: number, 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 [animatedPostAmount, setAnimatedPostAmount] = useState(10);
     22   const postAmountProgress = 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   const tertiaryContentOpacity = useTransform(
     53     scrollYProgress,
     54     [0.8, 1.0],
     55     [0, 1],
     56     {
     57       clamp: true,
     58       ease: easeInOut
     59     }
     60   )
     61 
     62   useInterval(() => {
     63     if (postAmountProgress.get() > 0.0001) {
     64       setAnimatedPostAmount(numberOfPosts)
     65     }
     66     else {
     67       setAnimatedPostAmount(10)
     68     }
     69   }, 500)
     70 
     71   return <div
     72     ref={ref}
     73     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)}
     74     style={style}
     75   >
     76     <motion.h2
     77       className={cn(
     78         "text-4xl md:text-6xl text-center text-white font-semibold break-keep tracking-tight z-30",
     79         // permanentMarker.className
     80       )}
     81       style={{
     82         opacity: headingOpacity,
     83       }}
     84     >
     85       You posted
     86     </motion.h2>
     87     <motion.h3
     88       className="flex items-center gap-4 text-3xl md:text-8xl text-center text-white font-semibold break-keep tracking-tight z-30"
     89       style={{
     90         opacity: secondaryContentOpacity,
     91       }}
     92     >
     93       <motion.span
     94         style={{ opacity: secondaryContentOpacity }}
     95       >
     96         <StickyNote className="w-8 h-8 md:w-16 md:h-16 text-purple-400" />
     97       </motion.span>
     98       <NumberFlow
     99         value={animatedPostAmount}
    100         continuous={true}
    101         transformTiming={{ duration: 1500, easing: "ease-out" }}
    102         opacityTiming={{ duration: 1500, easing: "ease-out" }}
    103         trend={1}
    104       />
    105       <motion.span
    106         className="text-purple-400"
    107         style={{ opacity: secondaryContentOpacity }}
    108       >
    109         notes
    110       </motion.span>
    111     </motion.h3>
    112     <motion.div
    113       className="space-y-4 z-30"
    114       style={{ opacity: tertiaryContentOpacity }}
    115     >
    116       {numberOfPosts > 200 ?
    117         <Image src="/2024-in-review/cat-typing.webp" alt="Cat typing" width={500} height={500} />
    118         :
    119         <Image src="/2024-in-review/ostrich-dancing.webp" alt="Cat typing" width={500} height={500} />
    120       }
    121     </motion.div>
    122   </div>
    123 }