NotedeckHero.tsx (6470B)
1 import { TopMenu } from "../TopMenu"; 2 import { Onest } from 'next/font/google' 3 import { Button } from "../../ui/Button"; 4 import { FormattedMessage, useIntl } from "react-intl"; 5 import Link from "next/link"; 6 import { motion, useScroll, useTransform } from "framer-motion"; 7 import Image from "next/image"; 8 import { NOTEDECK_WAITLIST_URL } from "@/lib/constants"; 9 import { cn } from "@/lib/utils"; 10 import { ArrowUpRight, ChevronRight, Sparkles } from "lucide-react"; 11 import { useRef } from "react"; 12 13 const onest = Onest({ subsets: ['latin'] }) 14 15 export function NotedeckHero({ className, introducing }: { className?: string, introducing?: boolean }) { 16 const intl = useIntl() 17 const ref = useRef(null) 18 const { scrollYProgress } = useScroll({ 19 target: ref, 20 offset: ["start start", "end start"] 21 }) 22 const mobileScreenshotOffsetX = useTransform(scrollYProgress, [0, 1], [0, -1200]); 23 const bgOpacity = useTransform(scrollYProgress, [0.3, 1], [1.0, 0.0]); 24 25 return (<> 26 <div 27 ref={ref} 28 className={cn("bg-black overflow-hidden flex-col relative min-h-screen", className)} 29 > 30 <motion.div className="container mt-28 z-10 mx-auto px-6 pt-6 flex flex-col justify-center"> 31 <motion.div 32 className="flex flex-col items-start justify-start h-full grow mt-8 z-10" 33 style={{ opacity: 0 }} 34 animate={{ opacity: 1, transition: { delay: 0.5, duration: 1 } }} 35 > 36 {introducing && ( 37 <motion.h1 38 className={cn("text-2xl uppercase text-white/80 mb-12", onest.className)} 39 > 40 Introducing 41 </motion.h1> 42 )} 43 <div className="flex gap-x-4 items-center mb-2 md:mb-6"> 44 <Image 45 src="/logo_icon.png" 46 alt="damus logo" 47 width={80} 48 height={80} 49 className="rounded-lg md:rounded-xl lg:rounded-2xl w-12 md:w-16 lg:w-20 aspect-square" 50 /> 51 <motion.h1 52 className={cn("text-4xl sm:text-4xl md:text-7xl text-transparent bg-clip-text font-semibold whitespace-pre-line max-w-4xl tracking-wide leading-loose", onest.className)} 53 style={{ 54 backgroundImage: "linear-gradient(to right, #ffffff -100%, #ffffff -80%, #2D175B 100%)", 55 opacity: 0, 56 }} 57 animate={{ 58 backgroundImage: "linear-gradient(to right, #ffffff 0%, #ffffff 100%, #2D175B 180%)", 59 transition: { duration: 3 }, 60 opacity: 1 61 }} 62 > 63 Notedeck 64 </motion.h1> 65 </div> 66 <motion.h2 67 className={cn("mt-2 text-2xl sm:text-3xl md:text-5xl text-transparent bg-clip-text pb-6 font-semibold whitespace-pre-line max-w-4xl tracking-wide leading-8 md:leading-snug lg:leading-normal", onest.className)} 68 style={{ 69 backgroundImage: "linear-gradient(to right, #ffffff -100%, #ffffff -40%, #2D175B 100%)", 70 opacity: 0, 71 }} 72 animate={{ 73 backgroundImage: "linear-gradient(to right, #ffffff 0%, #ffffff 40%, #2D175B 100%)", 74 transition: { duration: 3 }, 75 opacity: 1 76 }} 77 > 78 <FormattedMessage defaultMessage="Damus. Everywhere. The fastest native, customizable nostr experience, for all platforms." id="notedeck.hero.headline"/> 79 </motion.h2> 80 <motion.div 81 className="inline-flex gap-2 items-center text-xs md:text-md rounded-full bg-purple-100/10 backdrop-blur-sm shadow-lg p-1 px-3 text-purple-100/80 border border-purple-100/30 active:scale-95 transition mt-2 mb-8 md:mb-10" 82 style={{ opacity: 0 }} 83 animate={{ opacity: 1, transition: { delay: 1.5, duration: 1 } }} 84 > 85 <Sparkles className="h-4 mr-1 text-purple-50" aria-hidden="true" /> 86 {intl.formatMessage({ id: "notedeck.hero.announcement", defaultMessage: "Notedeck Alpha now available on Purple" })} 87 </motion.div> 88 <motion.div 89 className="mt-6 md:mt-4 mb-8 flex flex-col md:flex-row items-center md:items-center gap-y-4 gap-x-6 w-full md:w-auto" 90 style={{ opacity: 0 }} 91 animate={{ opacity: 1, transition: { delay: 1.5, duration: 1 } }} 92 > 93 <InstallNowButton/> 94 <a href={"/notedeck#introducing"}> 95 <Button variant="link" className="w-full md:w-auto"> 96 { intl.formatMessage({ id: "notedeck.hero.learn-more", defaultMessage: "Learn more" }) } 97 98 </Button> 99 </a> 100 </motion.div> 101 </motion.div> 102 </motion.div> 103 <motion.div className="flex justify-end w-full relative"> 104 {/* Gradient fade to black on the bottom */} 105 <div className="w-full h-96 bottom-0 absolute bg-gradient-to-b from-transparent to-black z-10" /> 106 <motion.div 107 className="z-0 w-auto pointer-events-none mt-[-553px] overflow-x-hidden overflow-y-visible flex" 108 > 109 <motion.img 110 src="/notedeck/notedeck-hero-2.png" 111 className="block md:hidden" 112 style={{ 113 width: "1728px", 114 height: "1106px", 115 maxWidth: "1728px", 116 marginLeft: mobileScreenshotOffsetX, 117 opacity: bgOpacity 118 }} 119 alt="Notedeck screenshot" 120 sizes="1728px" 121 width={1728} 122 height={1106} 123 /> 124 <motion.img 125 src="/notedeck/notedeck-hero-2.png" 126 className="hidden md:block" 127 style={{ 128 width: "1728px", 129 height: "1106px", 130 maxWidth: "1728px", 131 }} 132 alt="Notedeck screenshot" 133 sizes="1728px" 134 width={1728} 135 height={1106} 136 /> 137 </motion.div> 138 </motion.div> 139 </div> 140 </>) 141 } 142 143 export function InstallNowButton({ className }: { className?: string }) { 144 const intl = useIntl() 145 146 return ( 147 <Link href={"/notedeck/install"} className={cn("w-full md:w-auto", className)}> 148 <Button variant="accent" className="w-full flex gap-x-2 text-lg font-semibold"> 149 <Sparkles className="w-4 h-4"/> 150 {intl.formatMessage({ id: "notedeck.hero.install", defaultMessage: "Install now" })} 151 </Button> 152 </Link> 153 ) 154 }