WhatIsNotedeck.tsx (10393B)
1 import { Onest } from 'next/font/google' 2 import { FormattedMessage, useIntl } from "react-intl"; 3 import { motion } from "framer-motion"; 4 import { RoundedContainerWithGradientBorder } from "@/components/ui/RoundedContainerWithGradientBorder"; 5 import { cn } from "@/lib/utils"; 6 import { Columns, Eye, Film, Gauge, Globe, Joystick, KeyRound, Mail, Scale, Search, Settings2, ThumbsUp, Upload, Wallet, Zap, ArrowLeftRightIcon } from "lucide-react"; 7 import { MeshGradient3 } from "@/components/effects/MeshGradient.3"; 8 import { MarkdownView } from '@/components/ui/MarkdownView'; 9 import { Item, ItemSection } from './ItemSection'; 10 import Markdown from 'react-markdown'; 11 12 const onest = Onest({ subsets: ['latin'] }) 13 14 export function WhatIsNotedeck({ className }: { className?: string }) { 15 const intl = useIntl() 16 17 const list = { 18 visible: { 19 opacity: 1, 20 transition: { 21 when: "beforeChildren", 22 staggerChildren: 2, 23 }, 24 }, 25 hidden: { 26 opacity: 0, 27 transition: { 28 when: "afterChildren", 29 }, 30 }, 31 } 32 33 const item = { 34 visible: { 35 opacity: 1 36 }, 37 hidden: { 38 opacity: 0 39 }, 40 } 41 42 const items: Item[] = [ 43 { 44 icon: <Eye className="h-12 w-12 text-white opacity-80"/>, 45 headline: intl.formatMessage({ id: "notedeck.feature.customization.name", defaultMessage: "Powerful Views" }), 46 description: intl.formatMessage({ id: "notedeck.feature.customization.description", defaultMessage: "Add profile, hashtag, and notification columns of any nostr public or private key. Which means you can see the nostr landscape through other peoples' eyes" }), 47 }, 48 { 49 icon: <Gauge className="h-12 w-12 text-white opacity-80"/>, 50 headline: intl.formatMessage({ id: "notedeck.feature.speed.name", defaultMessage: "Speed" }), 51 description: intl.formatMessage({ id: "notedeck.feature.speed.description", defaultMessage: "The fastest nostr client. Built from the ground up with an ultra-fast database made exclusively for nostr, leveraging several state-of-the-art performance techniques not available on web clients" }), 52 }, 53 { 54 icon: <ArrowLeftRightIcon className="h-12 w-12 text-white opacity-80"/>, 55 headline: intl.formatMessage({ id: "notedeck.feature.availability.name", defaultMessage: "Switch Between Accounts" }), 56 description: intl.formatMessage({ id: "notedeck.feature.availability.description", defaultMessage: "Nostriches can also switch between multiple accounts quickly and easily, drastically improving personal and business use cases" }), 57 }, 58 ] 59 60 return (<> 61 <div id="introducing" className={cn("bg-black overflow-hidden relative", className)}> 62 <div className="container mx-auto px-6 pb-32 pt-20"> 63 <div className="flex flex-col items-center justify-center mt-32 lg:mt-16"> 64 <div className="relative mb-16 flex flex-col items-center"> 65 <motion.h2 66 className={cn("mt-6 text-3xl sm:text-4xl md:text-5xl text-center text-transparent bg-clip-text pb-6 font-semibold whitespace-pre-line max-w-4xl tracking-wide leading-relaxed", onest.className)} 67 style={{ 68 backgroundImage: "linear-gradient(to right, #ffffff -100%, #ffffff -40%, #2D175B 100%)", 69 opacity: 0, 70 }} 71 animate={{ 72 backgroundImage: "linear-gradient(to right, #ffffff 0%, #ffffff 60%, #2D175B 150%)", 73 transition: { duration: 2 }, 74 opacity: 1 75 }} 76 > 77 {intl.formatMessage({ id: "notedeck.what-is.headline", defaultMessage: "Introducing Notedeck" })} 78 </motion.h2> 79 <motion.div 80 initial="hidden" 81 whileInView="visible" 82 transition={{ duration: 1 }} 83 variants={list} 84 viewport={{ once: true }} 85 > 86 <motion.div 87 className={cn("text-white/60 text-4xl leading-relaxed text-left max-w-4xl my-32 break-keep")} 88 variants={item} 89 transition={{ duration: 1 }} 90 > 91 <SpecialMarkdownView> 92 {intl.formatMessage({ 93 id: "notedeck.what-is.description1", 94 defaultMessage: "**Nostr is the future of social media** and Notedeck is our latest innovation towards the **future of nostr**.\n\n" 95 })} 96 </SpecialMarkdownView> 97 </motion.div> 98 <motion.div 99 className={cn("text-white/60 text-4xl leading-relaxed text-left max-w-4xl my-32 break-keep")} 100 variants={item} 101 transition={{ duration: 1 }} 102 > 103 <SpecialMarkdownView> 104 {intl.formatMessage({ 105 id: "notedeck.what-is.description2", 106 defaultMessage: "A **lightning fast native app** that allows you to explore the nostr social network in a **completely new way**! Notedeck includes several power features to both personal and business use cases, including:" 107 })} 108 </SpecialMarkdownView> 109 </motion.div> 110 {(intl.locale != "ja" || process.env.FORCE_LOAD_ALL_JA_SECTIONS) && ( 111 <motion.div 112 className="flex flex-wrap gap-x-8 gap-y-16 items-stretch justify-center mt-28 mb-56" 113 variants={item} 114 > 115 {items.map((item, index) => ( 116 <ItemView key={index} item={item} index={index} /> 117 ))} 118 </motion.div> 119 )} 120 <motion.div 121 className={cn("text-white/60 text-4xl leading-relaxed text-left max-w-4xl my-32 break-keep")} 122 variants={item} 123 transition={{ duration: 1 }} 124 > 125 <SpecialMarkdownView> 126 {intl.formatMessage({ 127 id: "notedeck.what-is.description3", 128 defaultMessage: "This isn't a web app and it's not just \"another\" social client. This is nostr **like you've never seen it before!**\n\nNotedeck works on **Linux**, **macOS**, and **Windows** on day one. An Android version will be added in 2025, along with iOS and iPadOS eventually.\n\nFuture nostr apps **will run on Notedeck in 2025.**\n\nAn early Notedeck Alpha version is available **today** to our paid [Purple](/purple) subscribers." 129 })} 130 </SpecialMarkdownView> 131 </motion.div> 132 </motion.div> 133 </div> 134 </div> 135 </div> 136 </div> 137 </>) 138 } 139 140 interface ItemViewProps { 141 item: Item, 142 index: number 143 } 144 145 function ItemView({ item, index }: ItemViewProps) { 146 return ( 147 <div key={index} className="w-72 flex flex-col items-start justify-start"> 148 <div className="flex justify-between w-full items-start"> 149 {item.icon} 150 {item.badgeText && ( 151 <div className={cn("py-1 px-2 bg-orange-500/30 text-orange-200 rounded-lg", item.badgeClassName)}> 152 {item.badgeText} 153 </div> 154 )} 155 </div> 156 <h3 className="text-xl font-semibold text-transparent bg-clip-text bg-gradient-to-br text-white text-left text-normal mt-6"> 157 {item.headline} 158 </h3> 159 <p className="text-white/80 text-left text-normal mt-4"> 160 {item.description} 161 </p> 162 </div> 163 ) 164 } 165 166 function SpecialMarkdownView({ children, className }: { children?: string | null | undefined, className?: string }) { 167 168 const container = { 169 hidden: { opacity: 0 }, 170 show: { 171 opacity: 1, 172 transition: { 173 delayChildren: 1, 174 staggerChildren: 1 175 } 176 } 177 } 178 179 const item = { 180 hidden: { opacity: 0.6 }, 181 show: { opacity: 1 } 182 } 183 184 return ( 185 <motion.div 186 initial="hidden" 187 whileInView="show" 188 transition={{ duration: 0.5 }} 189 variants={container} 190 className={className} 191 > 192 <Markdown components={{ 193 h1: ({node, ...props}) => <h1 className="opacity-90 font-bold text-6xl mb-6" {...props} />, 194 h2: ({node, ...props}) => <h2 className="opacity-90 font-bold text-4xl mb-4" {...props} />, 195 h3: ({node, ...props}) => <h3 className="opacity-90 font-bold text-2xl" {...props} />, 196 ul: ({node, ...props}) => <ul className="opacity-80 list-disc list-inside mb-5" {...props} />, 197 ol: ({node, ...props}) => <ol className="opacity-80 list-decimal list-inside mb-5" {...props} />, 198 li: ({node, ...props}) => <li className="opacity-80 m-1" {...props} />, 199 em: ({node, ...props}) => <i className="italic" {...props} />, 200 // @ts-ignore 201 strong: ({node, ...props}) => <motion.strong 202 variants={item} 203 className="font-bold text-white" 204 {...props} 205 />, 206 p: ({node, ...props}) => <p className="opacity-80 mb-4" {...props} />, 207 // @ts-ignore 208 a: ({node, ...props}) => <motion.a 209 variants={item} 210 className="text-white font-bold underline" 211 target="_blank" 212 {...props} 213 />, 214 pre: ({node, ...props}) => <pre className="my-2 bg-white/10 overflow-scroll p-3 rounded-lg font-mono" {...props} />, 215 code: ({node, ...props}) => { 216 return (<code className="my-2 bg-white/10 overflow-scroll p-1 font-mono rounded-sm" {...props} />) 217 }, 218 }} className={className}>{children}</Markdown> 219 </motion.div> 220 ) 221 }