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.

new homepage layout & fix styles

Luna 62c7a215 b65d83dc

+200 -90
+7
app/(home)/layout.tsx
··· 57 57 <div className="ml-auto svg-max flex flex-wrap items-center gap-2 mt-2 md:mt-0"> 58 58 <Link href="https://tiktok.com/@wamellow.com" className="text-neutral-400 hover:dark:text-neutral-300 hover:text-neutral-700 duration-200 h-6 w-6" aria-label="Wamellow on TikTok"> 59 59 <BiLogoTiktok /> 60 + <span className="sr-only">Wamellow on TikTok</span> 60 61 </Link> 61 62 <Link href="https://youtube.com/@wayabot" className="text-neutral-400 hover:dark:text-neutral-300 hover:text-neutral-700 duration-200 h-6 w-6" aria-label="Wamellow on YouTube"> 62 63 <BiLogoYoutube /> 64 + <span className="sr-only">Wamellow on YouTube</span> 63 65 </Link> 64 66 <Link href="https://twitter.com/licamw" className="text-neutral-400 hover:dark:text-neutral-300 hover:text-neutral-700 duration-200 h-6 w-6" aria-label="Wamellow on Twitter (X.com)"> 65 67 <BiLogoTwitter /> 68 + <span className="sr-only">Wamellow on Twitter</span> 66 69 </Link> 67 70 <Link href="https://github.com/Luna-devv" className="text-neutral-400 hover:dark:text-neutral-300 hover:text-neutral-700 duration-200 h-6 w-6" aria-label="Wamellow's developers on GitHub"> 68 71 <BiLogoGithub /> 72 + <span className="sr-only">Wamellow{"'"}s developers on GitHub</span> 69 73 </Link> 70 74 <Link href="mailto:support@waya.one" className="text-neutral-400 hover:dark:text-neutral-300 hover:text-neutral-700 duration-200 h-6 w-6" aria-label="Contact Wamellow via email"> 71 75 <BiLogoGmail /> 76 + <span className="sr-only">Contact Wamellow via email</span> 72 77 </Link> 73 78 <Link href="https://lunish.nl/kofi" className="text-neutral-400 hover:dark:text-neutral-300 hover:text-neutral-700 duration-200 h-[22px] w-[22px]" aria-label="Support Wamellow's developers monetarily on Kofi"> 74 79 <SiKofi /> 80 + <span className="sr-only">Support Wamellow{"'"}s developers monetarily on Kofi</span> 75 81 </Link> 76 82 <Link href="https://top.gg/bot/1125449347451068437/vote" className="text-neutral-400 hover:text-[#ff3366] duration-200 h-6 w-6" aria-label="Wamellow on top.gg"> 77 83 <TopggIcon /> 84 + <span className="sr-only">Wamellow on top.gg</span> 78 85 </Link> 79 86 </div> 80 87
+117 -68
app/(home)/page.tsx
··· 1 - import { Chip, Code } from "@nextui-org/react"; 1 + import { Avatar, AvatarGroup, Chip, Code } from "@nextui-org/react"; 2 2 import { Montserrat, Patrick_Hand } from "next/font/google"; 3 3 import Image from "next/image"; 4 4 import Link from "next/link"; ··· 13 13 import DiscordMessage from "@/components/discord/message"; 14 14 import DiscordMessageEmbed from "@/components/discord/message-embed"; 15 15 import DiscordUser from "@/components/discord/user"; 16 - import ImageGrid from "@/components/image-grid"; 16 + import ImageReduceMotion from "@/components/image-reduce-motion"; 17 17 import { ServerButton } from "@/components/server-button"; 18 18 import AiPic from "@/public/ai.webp"; 19 19 import ArrowPic from "@/public/arroww.webp"; ··· 24 24 import WelcomePic from "@/public/welcome.webp"; 25 25 import { ApiV1StatisticsGetResponse, ApiV1TopguildsGetResponse } from "@/typings"; 26 26 import cn from "@/utils/cn"; 27 + import { toFixedArrayLength } from "@/utils/fixed-array-length"; 27 28 import { convertMonthToName } from "@/utils/time"; 28 29 import { getCanonicalUrl } from "@/utils/urls"; 29 30 ··· 45 46 const stats = await fetch(`${process.env.NEXT_PUBLIC_API}/statistics`, fetchOptions).then((res) => res.json()).catch(() => null) as ApiV1StatisticsGetResponse | null; 46 47 const commands = await fetch(`${process.env.NEXT_PUBLIC_API}/commands`, fetchOptions).then((res) => res.json()).catch(() => ([])) as Commands[]; 47 48 48 - const uwus = ["UwU", "uwu", "OwO", "owo", "QwQ", "qwq", ">:(", "Femboys ❤️"]; 49 49 const intl = new Intl.NumberFormat("en", { notation: "standard" }); 50 50 51 51 const styles = { ··· 83 83 </ServerButton> 84 84 ); 85 85 86 + async function renderCount() { 87 + "use server"; 88 + return <span>trust us!</span>; 89 + } 90 + 86 91 return ( 87 92 <div className="flex items-center flex-col w-full"> 88 93 89 - <div className="lg:text-7xl text-5xl flex font-semibold md:mb-6 mb-4 dark:text-neutral-100 text-neutral-900 break-words w-full"> 90 - <h1 className={montserrat.className}> 91 - <span className="bg-gradient-to-r from-indigo-400 to-pink-400 bg-clip-text text-transparent h-20 break-keep">Next-gen</span> 92 - {" of "} 93 - <span className="underline decoration-blurple break-keep">discord bots</span> 94 - </h1> 95 - <div 96 - className="bg-gradient-to-r from-blue-400 to-pink-400 bg-clip-text text-transparent font-medium text-2xl relative right-2 rotate-12 select-none sm:block hidden" 97 - style={{ animation: "ScaleBlink 1s ease-in-out infinite" }} 98 - > 99 - {uwus[Math.floor(Math.random() * uwus.length)]} 100 - </div> 101 - </div> 94 + <div className="flex w-full items-center gap-8 mb-20 md:mb-12" style={{ height: "calc(100svh - 20rem)" }}> 95 + <div className="min-w-96 w-full md:w-2/3 xl:w-1/2 flex flex-col space-y-6"> 102 96 103 - {topGuilds && 104 - <ImageGrid images={topGuilds 105 - .sort((a, b) => b.memberCount - a.memberCount) 106 - .map((guild) => ({ 107 - id: guild.id, 108 - url: guild.icon || "/discord.webp", 109 - link: getCanonicalUrl("leaderboard", guild.id) 110 - }))} 111 - /> 112 - } 97 + <Chip 98 + color="secondary" 99 + variant="flat" 100 + startContent={<HiCash className="mx-1" />} 101 + > 102 + <span className="font-semibold">Everything for free</span> 103 + </Chip> 113 104 114 - <div className="md:text-xl text-lg lg:flex w-full mt-4 gap-4"> 115 - <span className="font-medium"> 116 - Experience the next-gen revolution, offering a list of features and extensive customization, providing a superior alternative to popular bots. 117 - </span> 105 + <h1 className={cn(montserrat.className, "lg:text-7xl text-6xl font-semibold dark:text-neutral-100 text-neutral-900 break-words")}> 106 + <span className="bg-gradient-to-r from-indigo-400 to-pink-400 bg-clip-text text-transparent h-20 break-keep">Next generation</span> 107 + {" of "} 108 + <span className="underline decoration-blurple break-keep">discord bots</span> 109 + </h1> 118 110 119 - <div className="flex flex-col min-w-full lg:min-w-[420px]"> 111 + <span className="text-lg font-medium max-w-xl mb-4"> 112 + Engage with leaderboards, starboards, and welcoming atmosphere. Dive into anime discussions, enjoy free /image AI and unleash the power of Text-To-Speech. 113 + </span> 120 114 121 - <div className="lg:ml-auto flex gap-2 mt-4 lg:mt-0"> 122 - <ServerButton 123 - as={Link} 124 - startContent={<HiUserAdd />} 125 - className="w-1/2 lg:w-fit !text-xl !font-medium" 126 - color="secondary" 127 - href="/login?invite=true" 128 - size="lg" 129 - > 130 - <span className="block sm:hidden">Invite</span> 131 - <span className="hidden sm:block">Invite Wamellow</span> 132 - </ServerButton> 133 - <ServerButton 134 - as={Link} 135 - startContent={<BsDiscord />} 136 - className="w-1/2 lg:w-fit !text-xl !font-medium" 137 - href="/support" 138 - size="lg" 139 - > 140 - <span className="block sm:hidden">Support</span> 141 - <span className="hidden sm:block">Join support</span> 142 - </ServerButton> 143 - </div> 115 + <AvatarGroup 116 + className="mr-auto md:hidden" 117 + max={8} 118 + renderCount={renderCount} 119 + > 120 + {toFixedArrayLength(topGuilds || [], 8)?.map((guild) => ( 121 + <Avatar 122 + as={Link} 123 + href={getCanonicalUrl("leaderboard", guild.id, "?utm_source=wamellow.com&utm_medium=home")} 124 + key={guild.id} 125 + src={guild.icon || "/discord.webp"} 126 + alt={guild.name} 127 + title={guild.name} 128 + /> 129 + ))} 130 + </AvatarGroup> 144 131 132 + <div className="space-y-4"> 133 + <div className="flex gap-2 lg:mt-0"> 134 + <ServerButton 135 + as={Link} 136 + startContent={<HiUserAdd />} 137 + className="w-1/2 lg:w-fit !text-xl !font-medium" 138 + color="secondary" 139 + href="/login?invite=true" 140 + size="lg" 141 + > 142 + <span className="block sm:hidden">Invite</span> 143 + <span className="hidden sm:block">Invite Wamellow</span> 144 + </ServerButton> 145 + <ServerButton 146 + as={Link} 147 + startContent={<BsDiscord />} 148 + className="w-1/2 lg:w-fit !text-xl !font-medium" 149 + href="/support" 150 + size="lg" 151 + > 152 + <span className="block sm:hidden">Support</span> 153 + <span className="hidden sm:block">Join support</span> 154 + </ServerButton> 155 + </div> 145 156 146 - <span className={`lg:ml-auto flex gap-2 text-neutral-500 font-mediumr ${handwritten.className} mt-3 opacity-80 pl-20 lg:pr-20 rotate-2`}> 147 - <Image src={ArrowPic} width={24} height={24} alt="arrow up" className="h-5 w-5 relative top-px" draggable={false} /> 148 - Get started here in seconds 149 - </span> 157 + <span className={cn("lg:ml-auto flex gap-2 text-neutral-500 font-mediumr mt-3 opacity-80 pl-20 lg:pr-20 rotate-2", handwritten.className)}> 158 + <Image src={ArrowPic} width={24} height={24} alt="arrow up" className="h-5 w-5 relative top-px" draggable={false} /> 159 + Get started here in seconds 160 + </span> 150 161 162 + </div> 151 163 </div> 152 164 165 + <div className="ml-auto w-fit xl:w-1/2 hidden md:block"> 166 + <div className="flex gap-4 rotate-6 relative left-14 w-fit"> 167 + {[0, 1, 2, 3].map((i) => ( 168 + <div 169 + key={"guildGridThing-" + i} 170 + className={cn("flex flex-col gap-4", i % 2 === 1 && "mt-8", (i === 0 || i === 3) && "hidden xl:flex")} 171 + > 172 + {toFixedArrayLength(topGuilds || [], 12) 173 + .slice(i * 3, (i * 3) + 3) 174 + .map((guild, i) => ( 175 + <Link 176 + key={"guildGrid-" + guild.id + i} 177 + className="relative md:h-32 h-24 md:w-32 w-24 hover:scale-110 duration-200" 178 + href={getCanonicalUrl("leaderboard", guild.id, "?utm_source=wamellow.com&utm_medium=home")} 179 + > 180 + <ImageReduceMotion 181 + alt="server" 182 + className="rounded-xl" 183 + url={(guild.icon || "/discord.webp")?.split(".").slice(0, -1).join(".")} 184 + size={128} 185 + /> 186 + </Link> 187 + )) 188 + } 189 + </div> 190 + ))} 191 + </div> 192 + </div> 153 193 </div> 154 194 155 - <div className="lg:mt-14 mt-10" /> 195 + <div className="flex flex-col items-center space-x-2"> 196 + <div className="animate-scroll"> 197 + <div className="animate-scroll-wheel" /> 198 + </div> 199 + <span className="text-lg font-medium mt-2 text-neutral-500/50">Scroll down...</span> 200 + </div> 156 201 157 - <article itemScope itemType="http://schema.org/Article" className="flex flex-col gap-28 mb-10"> 202 + <article 203 + itemScope 204 + itemType="http://schema.org/Article" 205 + className="flex flex-col gap-28 my-10" 206 + > 158 207 159 208 <div> 160 209 <h2 className={styles.h2}>Fun leveling and leaderboards 🦄</h2> ··· 184 233 as={Link} 185 234 className="bg-wamellow" 186 235 startContent={<HiArrowRight />} 187 - href="/leaderboard/828676951023550495" 236 + href="/leaderboard/828676951023550495?utm_source=wamellow.com&utm_medium=home" 188 237 > 189 238 View Leaderboard 190 239 </ServerButton> ··· 281 330 as={Link} 282 331 className="bg-wamellow" 283 332 startContent={<HiArrowRight />} 284 - href="/dashboard?to=starboard" 333 + href="/dashboard?to=starboard&utm_source=wamellow.com&utm_medium=home" 285 334 > 286 335 Setup 287 336 </ServerButton> ··· 343 392 as={Link} 344 393 className="bg-wamellow" 345 394 startContent={<HiArrowRight />} 346 - href="/dashboard?to=greeting" 395 + href="/dashboard?to=greeting&utm_source=wamellow.com&utm_medium=home" 347 396 > 348 397 Setup 349 398 </ServerButton> ··· 387 436 as={Link} 388 437 className="bg-wamellow" 389 438 startContent={<HiLockOpen />} 390 - href="/passport/1125063180801036329" 439 + href="/passport/1125063180801036329?utm_source=wamellow.com&utm_medium=home" 391 440 > 392 441 Try it out 393 442 </ServerButton> ··· 395 444 as={Link} 396 445 className="bg-wamellow" 397 446 startContent={<HiArrowRight />} 398 - href="/dashboard?to=greeting" 447 + href="/dashboard?to=greeting&utm_source=wamellow.com&utm_medium=home" 399 448 > 400 449 Setup 401 450 </ServerButton> ··· 509 558 as={Link} 510 559 className="bg-wamellow" 511 560 startContent={<HiArrowRight />} 512 - href="/ai" 561 + href="/ai?utm_source=wamellow.com&utm_medium=home" 513 562 > 514 563 View all models 515 564 </ServerButton> ··· 562 611 as={Link} 563 612 className="bg-wamellow" 564 613 startContent={<HiArrowRight />} 565 - href="/dashboard?to=custom-commands" 614 + href="/dashboard?to=custom-commands&utm_source=wamellow.com&utm_medium=home" 566 615 > 567 616 Setup 568 617 </ServerButton> ··· 684 733 ]} 685 734 /> 686 735 687 - </div> 736 + </div > 688 737 ); 689 738 }
+39
app/globals.css
··· 61 61 background: rgb(139, 92, 246, 1); 62 62 } 63 63 64 + .animate-scroll { 65 + border: 2px solid rgb(139, 92, 246, 1); 66 + border-radius: 22px; 67 + height: 2.2rem; 68 + position: relative; 69 + width: 20px; 70 + } 71 + 72 + .animate-scroll-wheel { 73 + animation: scroll 2.5s ease infinite; 74 + background: rgb(139, 92, 246, 1); 75 + border-radius: 1rem; 76 + height: 0.5rem; 77 + left: calc(50% - 1.5px); 78 + position: absolute; 79 + right: 50%; 80 + top: 8px; 81 + width: 3px; 82 + } 83 + 84 + @keyframes scroll { 85 + 0% { 86 + transform: translateY(0); 87 + } 88 + 89 + 50% { 90 + transform: translateY(0.5rem); 91 + } 92 + 93 + 51% { 94 + opacity: 1; 95 + } 96 + 97 + 100% { 98 + opacity: 0; 99 + transform: translateY(0); 100 + } 101 + } 102 + 64 103 button.subpixel-antialiased:not(.w-unit-10):not(.default):not(.bg-secondary):not(.button-primary):not(.button-blurple):not(.button-underline), 65 104 a[role="button"]:not(.w-unit-10):not(.default):not(.bg-secondary):not(.button-primary):not(.button-blurple):not(.button-underline) { 66 105 @apply py-2 px-4 duration-200 justify-center gap-2 items-center text-medium
+24 -10
app/layout.tsx
··· 6 6 import Image from "next/image"; 7 7 import Link from "next/link"; 8 8 import Script from "next/script"; 9 + import { BsDiscord } from "react-icons/bs"; 9 10 import { SiKofi } from "react-icons/si"; 10 11 11 12 import Header from "@/components/header"; 12 13 import TopggIcon from "@/components/icons/topgg"; 14 + import cn from "@/utils/cn"; 13 15 import { getBaseUrl } from "@/utils/urls"; 14 16 15 17 import { Provider } from "./provider"; ··· 25 27 export const generateMetadata = async (): Promise<Metadata> => { 26 28 27 29 const title = "Wamellow: Next-gen of discord bots"; 28 - const description = "Experience the next-gen revolution with Wamellow, offering a list of features and extensive customization, providing a superior alternative to popular bots."; 30 + const description = "Engage with leaderboards, starboards, and welcoming atmosphere. Dive into anime discussions, enjoy free /image AI and unleash the power of Text-To-Speech."; 29 31 30 32 return { 31 33 metadataBase: new URL(getBaseUrl()), ··· 83 85 }) { 84 86 return ( 85 87 <html 88 + suppressHydrationWarning 86 89 data-theme="dark" 87 90 lang="en" 88 91 className="dark flex justify-center min-h-screen max-w-screen overflow-x-hidden" ··· 90 93 91 94 <Script defer data-domain="wamellow.com" src="https://analytics.wamellow.com/js/script.js" /> 92 95 93 - <body className={`${outfit.className} w-full max-w-7xl`}> 96 + <body className={cn("w-full max-w-7xl", outfit.className)}> 94 97 <div id="bg" className="absolute top-0 right-0 w-screen h-screen -z-10" /> 95 98 96 - <div className="absolute left-0 bg-gradient-to-r from-indigo-400 to-pink-400 h-8 w-full flex items-center justify-center text-white font-medium text-sm"> 97 - <div className="hidden md:block"> 98 - Please note that this is an <span className="underline decoration-dotted break-word">early alpha version</span> of the bot and the website! 99 - </div> 100 - <div className="block md:hidden"> 101 - This is an <span className="underline decoration-dotted break-word">early alpha version</span>! 99 + <div className="w-6xl w-full max-w-full px-2 mt-3"> 100 + <div className="flex items-center justify-between p-3 bg-gradient-to-r from-indigo-400/75 to-pink-400/75 h-8 text-white font-medium text-sm rounded-md"> 101 + <div /> 102 + 103 + <div className="items-center flex"> 104 + <span className="hidden md:block"> 105 + Please note that this is an <span className="underline decoration-dotted break-word">early alpha version</span> of the bot and the website! 106 + </span> 107 + <span className="block md:hidden"> 108 + This is an <span className="underline decoration-dotted break-word">early alpha version</span>! 109 + </span> 110 + </div> 111 + 112 + <Link href="/support" target="_blank"> 113 + <BsDiscord className="h-4 w-4" /> 114 + <span className="sr-only">Discord server and support</span> 115 + </Link> 102 116 </div> 103 117 </div> 104 118 105 - <nav className="p-4 flex items-center gap-2 text-base font-medium dark:text-neutral-300 text-neutral-700 select-none mt-7 h-20"> 106 - <Link href="/" className={`${montserrat.className} font-semibold flex items-center mr-2`}> 119 + <nav className="p-4 flex items-center gap-2 text-base font-medium dark:text-neutral-300 text-neutral-700 select-none h-20"> 120 + <Link href="/" className={cn("font-semibold flex items-center mr-2", montserrat.className)}> 107 121 <Image src="/waya-v3-small.webp" width={64} height={64} alt="" className="rounded-full mr-2 w-8 h-8" /> 108 122 <span className="text-xl dark:text-neutral-100 text-neutral-900">Wamellow</span> 109 123 </Link>
+2 -12
components/image-grid.tsx
··· 1 1 import Image from "next/image"; 2 2 import Link from "next/link"; 3 3 4 + import { toFixedArrayLength } from "@/utils/fixed-array-length"; 5 + 4 6 import ImageReduceMotion from "./image-reduce-motion"; 5 7 6 8 interface Props { ··· 76 78 </Link> 77 79 ); 78 80 79 - } 80 - 81 - function toFixedArrayLength<T>(arr: T[], length: number): T[] { 82 - const originalLength = arr.length; 83 - const numCopies = Math.ceil(length / originalLength); 84 - const slicedArray: T[] = []; 85 - 86 - for (let i = 0; i < numCopies; i++) { 87 - slicedArray.push(...arr); 88 - } 89 - 90 - return slicedArray.slice(0, length); 91 81 }
+11
utils/fixed-array-length.ts
··· 1 + export function toFixedArrayLength<T>(arr: T[], length: number): T[] { 2 + const originalLength = arr.length; 3 + const numCopies = Math.ceil(length / originalLength); 4 + const slicedArray: T[] = []; 5 + 6 + for (let i = 0; i < numCopies; i++) { 7 + slicedArray.push(...arr); 8 + } 9 + 10 + return slicedArray.slice(0, length); 11 + }