The weeb for the next gen discord boat - Wamellow wamellow.com
bot discord
at master 6.9 kB view raw
1import "./globals.css"; 2import { Header } from "@/components/header"; 3import { LoginButton } from "@/components/login-button"; 4import { Button } from "@/components/ui/button"; 5import { Separator } from "@/components/ui/separator"; 6import Icon from "@/public/icon.svg"; 7import { cn } from "@/utils/cn"; 8import { getBaseUrl } from "@/utils/urls"; 9import type { Metadata, Viewport } from "next"; 10import { Lexend, Noto_Sans_JP, Outfit } from "next/font/google"; 11import { cookies } from "next/headers"; 12import Image from "next/image"; 13import Link from "next/link"; 14import Script from "next/script"; 15import { CookiesProvider } from "next-client-cookies/server"; 16 17import { Provider } from "./provider"; 18 19const outfit = Outfit({ subsets: ["latin", "latin-ext"], variable: "--font-outfit" }); 20const notosansJP = Noto_Sans_JP({ subsets: ["cyrillic", "vietnamese"], variable: "--font-noto-sans-jp" }); 21 22const lexend = Lexend({ subsets: ["latin"] }); 23 24// TODO: get automatically from top.gg 25const reviews = { 26 "@context": "https://schema.org", 27 "@type": "Product", 28 name: "wamellow", 29 aggregateRating: { 30 "@type": "AggregateRating", 31 ratingValue: "5", 32 reviewCount: "110", 33 bestRating: "5" 34 } 35}; 36 37export const viewport: Viewport = { 38 themeColor: "#8957ff", 39 initialScale: 1 40}; 41 42export const generateMetadata = (): Metadata => { 43 44 const title = "Wamellow: Next-gen of Discord Bots & Apps"; 45 const description = "Accessibility where it's needed the most: Discord Voice Chats. Social notifications to stay connected and up to date with anyone, anywhere. Simple, customizable, free, and built in public."; 46 47 return { 48 metadataBase: new URL(getBaseUrl()), 49 50 manifest: "/manifest.json", 51 appleWebApp: { 52 capable: true, 53 title: "Wamellow", 54 startupImage: "/waya-v3.webp", 55 statusBarStyle: "black-translucent" 56 }, 57 58 title: { 59 default: title, 60 template: "%s" 61 }, 62 63 description, 64 65 alternates: { 66 canonical: getBaseUrl() 67 }, 68 69 openGraph: { 70 title: { 71 default: title, 72 template: "%s on Wamellow" 73 }, 74 description, 75 type: "website", 76 url: getBaseUrl(), 77 images: `${getBaseUrl()}/waya-v3.webp?v=3` 78 }, 79 80 twitter: { 81 card: "summary", 82 site: "wamellow.com", 83 title, 84 description, 85 images: `${getBaseUrl()}/waya-v3.webp?v=3` 86 }, 87 88 other: { 89 google: "notranslate" 90 }, 91 92 creator: "Luna (shi.gg)", 93 publisher: "Luna (shi.gg)", 94 95 robots: "index, follow" 96 }; 97}; 98 99export default function RootLayout({ children }: { children: React.ReactNode; }) { 100 return ( 101 <CookiesProvider> 102 <html 103 suppressHydrationWarning 104 data-theme="dark" 105 lang="en" 106 className="dark max-w-screen overflow-x-hidden" 107 > 108 <Script 109 defer 110 data-domain="wamellow.com" 111 src="https://analytics.wamellow.com/js/script.outbound-links.js" 112 /> 113 114 <Script 115 id="reviews" 116 type="application/ld+json" 117 > 118 {JSON.stringify(reviews)} 119 </Script> 120 121 {process.env.NODE_ENV === "development" && ( 122 <Script src="https://unpkg.com/react-scan/dist/auto.global.js" /> 123 )} 124 125 <body 126 className={cn( 127 "relative top-0 w-full flex justify-center overflow-x-hidden xl:overflow-visible!", 128 outfit.variable, 129 notosansJP.variable 130 )} 131 > 132 <div id="bg" className="absolute top-0 right-0 w-screen h-screen -z-50" /> 133 <Noise /> 134 135 <div className="w-full max-w-7xl"> 136 <NavBar className="w-full" /> 137 <Provider className="w-full">{children}</Provider> 138 </div> 139 </body> 140 </html> 141 </CookiesProvider> 142 ); 143} 144 145function Noise() { 146 return ( 147 <svg 148 className="absolute top-0 left-0 w-screen h-screen -z-40 blur-[1px] saturate-0" 149 viewBox='0 0 142 158' 150 xmlns='http://www.w3.org/2000/svg' 151 > 152 <filter id='noiseFilter'> 153 <feTurbulence 154 type="fractalNoise" 155 baseFrequency="9" 156 numOctaves="1" 157 stitchTiles="stitch" 158 result="turbulence" 159 160 /> 161 <feComponentTransfer> 162 <feFuncR type="table" tableValues="-1 0.2" /> 163 <feFuncG type="table" tableValues="-1 0.2" /> 164 <feFuncB type="table" tableValues="-1 0.2" /> 165 </feComponentTransfer> 166 </filter> 167 168 <rect 169 className="w-screen h-screen" 170 filter='url(#noiseFilter)' 171 /> 172 </svg> 173 ); 174} 175 176async function NavBar({ className }: { className?: string; }) { 177 const jar = await cookies(); 178 179 return ( 180 <nav className={cn("p-4 flex items-center gap-2 text-base text-neutral-300 select-none h-20 relative", className)}> 181 <Link 182 aria-label="Go to Wamellow's homepage" 183 className={cn("font-semibold flex items-center shrink-0 group", lexend.className)} 184 href="/" 185 > 186 <Image src={Icon} alt="wamellow icon" className="size-8 shrink-0 mr-4 pt-1 group-hover:rotate-45 duration-200" /> 187 <span className="text-xl dark:text-neutral-100 text-neutral-900 hidden sm:block">Wamellow</span> 188 </Link> 189 190 <Separator 191 className="h-10 rotate-6 ml-3" 192 orientation="vertical" 193 /> 194 195 <div className="flex shrink-0"> 196 <Button 197 asChild 198 size="sm" 199 variant="ghost" 200 > 201 <Link href="/docs/index"> 202 Documentation 203 </Link> 204 </Button> 205 <Button 206 asChild 207 className="hidden sm:flex" 208 size="sm" 209 variant="ghost" 210 > 211 <Link href="/premium"> 212 Premium 213 </Link> 214 </Button> 215 </div> 216 217 {jar.get("session")?.value 218 ? <Header /> 219 : <LoginButton className="ml-auto" /> 220 } 221 </nav> 222 ); 223}