The weeb for the next gen discord boat - Wamellow wamellow.com
bot discord
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

home add popular commands & error handling

Luna 0d366012 b8011f40

+81 -37
+77 -35
app/(home)/page.tsx
··· 3 3 import Link from "next/link"; 4 4 import { Suspense } from "react"; 5 5 import { BsDiscord } from "react-icons/bs"; 6 - import { HiArrowRight, HiFire, HiUserAdd } from "react-icons/hi"; 6 + import { HiArrowRight, HiFire, HiInformationCircle, HiUserAdd } from "react-icons/hi"; 7 7 8 8 import Badge from "@/components/badge"; 9 9 import { StatsBar } from "@/components/counter"; ··· 18 18 import WaifuPic from "@/public/waifu.webp"; 19 19 import WelcomePic from "@/public/welcome.webp"; 20 20 import { ApiV1StatisticsGetResponse, ApiV1TopguildsGetResponse } from "@/typings"; 21 + import cn from "@/utils/cn"; 21 22 import { convertMonthToName } from "@/utils/time"; 22 23 23 24 const montserrat = Montserrat({ subsets: ["latin"] }); 24 25 const handwritten = Patrick_Hand({ subsets: ["latin"], weight: "400" }); 25 26 27 + const fetchOptions = { headers: { Authorization: process.env.API_SECRET as string }, next: { revalidate: 60 * 60 } }; 28 + 29 + interface Commands { 30 + name: string; 31 + description: string; 32 + uses: number; 33 + } 34 + 26 35 export default async function Home() { 27 - const topGuilds = await fetch(`${process.env.NEXT_PUBLIC_API}/top-guilds`, { headers: { Authorization: process.env.API_SECRET as string }, next: { revalidate: 60 * 60 } }).then((res) => res.json()) as ApiV1TopguildsGetResponse[]; 28 - const stats = await fetch(`${process.env.NEXT_PUBLIC_API}/statistics`, { headers: { Authorization: process.env.API_SECRET as string }, next: { revalidate: 60 * 60 } }).then((res) => res.json()) as ApiV1StatisticsGetResponse; 36 + const topGuilds = await fetch(`${process.env.NEXT_PUBLIC_API}/top-guilds`, fetchOptions).then((res) => res.json()).catch(() => null) as ApiV1TopguildsGetResponse[] | null; 37 + const stats = await fetch(`${process.env.NEXT_PUBLIC_API}/statistics`, fetchOptions).then((res) => res.json()).catch(() => null) as ApiV1StatisticsGetResponse | null; 38 + const commands = await fetch(`${process.env.NEXT_PUBLIC_API}/commands`, fetchOptions).then((res) => res.json()).catch(() => ([])) as Commands[]; 29 39 30 40 const uwus = ["UwU", "uwu", "OwO", "owo", "QwQ", "qwq", ">:(", "Femboys ❤️"]; 41 + const intl = new Intl.NumberFormat("en", { notation: "standard" }); 42 + 43 + const Invite = () => ( 44 + <Link href="/login?invite=true" className="button-primary"> 45 + <HiUserAdd /> 46 + <span className="block sm:hidden">Wamellow</span> 47 + <span className="hidden sm:block">Invite Wamellow</span> 48 + </Link> 49 + ); 31 50 32 51 return ( 33 52 <div className="flex items-center flex-col w-full"> ··· 46 65 </div> 47 66 </div> 48 67 49 - <ServerGrid guilds={topGuilds} /> 68 + {topGuilds && <ServerGrid guilds={topGuilds} />} 50 69 51 70 <div className="md:text-xl text-lg lg:flex w-full mt-4"> 52 71 <span className="tracking-wide"> ··· 94 113 </div> 95 114 96 115 <div className="flex gap-2 mt-4"> 97 - <Link href="/login?invite=true" className="button-primary"> 98 - <HiUserAdd /> 99 - <span className="block sm:hidden">Wamellow</span> 100 - <span className="hidden sm:block">Invite Wamellow</span> 101 - </Link> 116 + <Invite /> 102 117 <Link href="/leaderboard/1055188344188973066" className="button"> 103 118 <span className="mr-2">View Leaderboard</span> 104 119 <HiArrowRight /> ··· 165 180 </div> 166 181 167 182 <div className="flex gap-2 mt-4"> 168 - <Link href="/login?invite=true" className="button-primary"> 169 - <HiUserAdd /> 170 - <span className="block sm:hidden">Wamellow</span> 171 - <span className="hidden sm:block">Invite Wamellow</span> 183 + <Invite /> 184 + <Link href="/dashboard?to=greeting" className="button"> 185 + <span className="mr-2">Setup</span> 186 + <HiArrowRight /> 172 187 </Link> 173 188 </div> 174 189 ··· 188 203 </div> 189 204 190 205 <div className="flex gap-2 mt-4"> 191 - <Link href="/login?invite=true" className="button-primary"> 192 - <HiUserAdd /> 193 - <span className="block sm:hidden">Wamellow</span> 194 - <span className="hidden sm:block">Invite Wamellow</span> 206 + <Invite /> 207 + <Link href="/dashboard?to=starboard" className="button"> 208 + <span className="mr-2">Setup</span> 209 + <HiArrowRight /> 195 210 </Link> 196 211 </div> 197 212 ··· 262 277 </div> 263 278 264 279 <div className="flex gap-2 mt-4"> 265 - <Link href="/login?invite=true" className="button-primary"> 266 - <HiUserAdd /> 267 - <span className="block sm:hidden">Wamellow</span> 268 - <span className="hidden sm:block">Invite Wamellow</span> 269 - </Link> 280 + <Invite /> 270 281 </div> 271 282 272 283 </div> ··· 282 293 Dive into a world of adorable nekos, charming waifus, and much more, all at your fingertips. 283 294 Whether it{"'"}s sharing the cutest characters or discovering stunning artwork, bring the joy of anime directly to your community, making your server a hub for all things anime-related. 284 295 285 - <div className="p-4 pb-3 border-2 dark:border-wamellow border-wamellow-100 rounded-xl mt-4"> 296 + <div className="p-4 pb-3 border-2 dark:border-wamellow border-wamellow-100 rounded-lg mt-4"> 286 297 <Badge 287 298 before={<HiFire />} 288 299 text="NSFW Supported" ··· 296 307 </div> 297 308 298 309 <div className="flex gap-2 mt-4"> 299 - <Link href="/login?invite=true" className="button-primary"> 300 - <HiUserAdd /> 301 - <span className="block sm:hidden">Wamellow</span> 302 - <span className="hidden sm:block">Invite Wamellow</span> 303 - </Link> 310 + <Invite /> 304 311 </div> 305 312 306 313 </div> ··· 332 339 333 340 </article> 334 341 342 + <div className="p-5 pb-3 dark:bg-wamellow bg-wamellow-100 rounded-lg mt-4 w-full"> 343 + <div className="flex"> 344 + <Badge 345 + before={<HiFire />} 346 + text="Popular Slash Commands" 347 + classname="mr-auto ml-0 mb-2" 348 + /> 349 + <div className="ml-auto flex items-center gap-1 opacity-80"> 350 + <span className="text-xs">Since 7th December</span> 351 + <HiInformationCircle /> 352 + </div> 353 + </div> 354 + {Array.isArray(commands) && commands 355 + .filter((command) => ["tts", "rank", "leaderboard", "anime"].includes(command.name)) 356 + .map((command, i) => ( 357 + <div key={command.name} className={cn("text-base py-4 flex flex-col md:flex-row gap-4 md:items-center", i + 1 !== 4 && "border-b border-wamellow-alpha")}> 358 + <div className="-mb-2 md:mb-0 flex items-center h-min"> 359 + <span className="dark:text-neutral-100 text-neutral-900 text-xl font-semibold md:font-medium">/{command.name}</span> 360 + <span className="ml-auto italic text-sm md:hidden opacity-80">{intl.format(command.uses)} uses</span> 361 + </div> 362 + <span>{command.description}</span> 363 + <span className="ml-auto italic text-sm hidden md:block">{intl.format(command.uses)} uses</span> 364 + </div> 365 + )) 366 + } 367 + {(!commands || !Array.isArray(commands)) && 368 + <div className="flex flex-col items-center my-10"> 369 + <div className="text-3xl dark:text-neutral-100 text-neutral-900 font-semibold mb-4">Something went wrong...</div> 370 + <div className="text-md dark:text-neutral-400 text-neutral-600 font-semibold">The commands list could not be loaded at this time</div> 371 + </div> 372 + } 373 + </div> 374 + 375 + <div className="h-8" /> 376 + 335 377 <StatsBar 336 378 items={[ 337 379 { 338 380 name: "Guilds using us", 339 - number: stats.approximateGuildCount, 340 - gained: stats.guildsGained 381 + number: stats?.approximateGuildCount || 0, 382 + gained: stats?.guildsGained 341 383 }, 342 384 { 343 385 name: "Users using us", 344 - number: stats.approximateUserCount, 345 - gained: stats.usersGained 386 + number: stats?.approximateUserCount || 0, 387 + gained: stats?.usersGained || 0 346 388 }, 347 389 { 348 390 name: "Votes for us", 349 - number: stats.approximateVoteCount, 350 - gained: stats.votesGained, 391 + number: stats?.approximateVoteCount || 0, 392 + gained: stats?.votesGained || 0, 351 393 append: `in ${convertMonthToName(new Date().getMonth())}` 352 394 }, 353 395 { 354 396 name: "Our experience with", 355 - number: stats.globalGuilds, 397 + number: stats?.globalGuilds || 0, 356 398 gained: "guilds, 5 bots", 357 399 info: "https://discordlist.gg/user/821472922140803112" 358 400 }
+4 -2
app/(home)/pro/page.tsx
··· 6 6 import { IoMdInfinite } from "react-icons/io"; 7 7 8 8 import Badge from "@/components/badge"; 9 - import ImageReduceMotion from "@/components/image-reduce-motion"; 10 9 import ServerGrid from "@/components/guild-grid"; 10 + import ImageReduceMotion from "@/components/image-reduce-motion"; 11 11 import { ApiV1TopguildsGetResponse } from "@/typings"; 12 12 import { getBaseUrl, getCanonicalUrl } from "@/utils/urls"; 13 13 ··· 143 143 <span className="flex items-center gap-2"> 144 144 <ImageReduceMotion url="/luna" size={64} alt="mwlica's profile picture" className="w-12 h-12 rounded-full" /> 145 145 <div> 146 - <span className="text-xl font-medium dark:text-neutral-200 text-neutral-800">@mwlica</span> <Badge text="Developer" /> <br /> 146 + <div className="flex items-center gap-2"> 147 + <span className="text-xl font-medium dark:text-neutral-200 text-neutral-800">@mwlica</span> <Badge text="Developer" /> 148 + </div> 147 149 <span className="dark:text-neutral-300 text-neutral-700">Cute femboy</span> 148 150 </div> 149 151 </span>