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.

add /pro site

Luna 539675c7 a6db1704

+213 -4
+182
app/(home)/pro/page.tsx
··· 1 + import { Metadata } from "next"; 2 + import { Montserrat, Patrick_Hand } from "next/font/google"; 3 + import Link from "next/link"; 4 + import { BsDiscord, BsQuestionLg } from "react-icons/bs"; 5 + import { HiChevronRight, HiLightningBolt, HiOutlineCheck, HiX } from "react-icons/hi"; 6 + import { IoMdInfinite } from "react-icons/io"; 7 + 8 + import Badge from "@/components/badge"; 9 + import ImageReduceMotion from "@/components/ImageReduceMotion"; 10 + import ServerGrid from "@/components/ServerGrid"; 11 + import { ApiV1TopguildsGetResponse } from "@/typings"; 12 + import { getBaseUrl, getCanonicalUrl } from "@/utils/urls"; 13 + 14 + const maybe = null; 15 + const montserrat = Montserrat({ subsets: ["latin"] }); 16 + const handwritten = Patrick_Hand({ subsets: ["latin"], weight: "400" }); 17 + 18 + export const generateMetadata = async (): Promise<Metadata> => { 19 + 20 + const title = "Professional experience"; 21 + const description = "Get epic Pro+ ULTRA HD features for wamellow to upgrade your servers to a whole new experience and unlock tons of premium features."; 22 + const url = getCanonicalUrl("pro"); 23 + 24 + return { 25 + title, 26 + description, 27 + alternates: { 28 + canonical: url 29 + }, 30 + openGraph: { 31 + title, 32 + description, 33 + type: "website", 34 + url, 35 + images: `${getBaseUrl()}/waya-v3.jpg` 36 + }, 37 + twitter: { 38 + card: "summary", 39 + site: "wamellow.com", 40 + title, 41 + description, 42 + images: `${getBaseUrl()}/waya-v3.jpg` 43 + } 44 + }; 45 + }; 46 + 47 + export default async function Home() { 48 + 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[]; 49 + 50 + const buttons = ( 51 + <> 52 + <Link href="/login?invite=true" className="flex text-neutral-200 bg-neutral-600 hover:bg-neutral-600/80 py-2 px-4 rounded-md duration-200 justify-center gap-2 w-1/2"> 53 + <BsDiscord className="relative top-1" /> 54 + <span className="ml-2">Get started</span> 55 + </Link> 56 + <button className="flex text-neutral-200 bg-violet-600 hover:bg-violet-600/80 py-2 px-4 rounded-md duration-200 justify-center gap-2 w-1/2 opacity-30 cursor-not-allowed" disabled> 57 + <HiLightningBolt className="relative top-1" /> 58 + <span className="ml-2">Subscribe</span> 59 + </button> 60 + </> 61 + ); 62 + 63 + const displayState = (is: string | number | boolean | null) => { 64 + if (typeof is === "boolean" || is === null) { 65 + if (is === true) return <HiOutlineCheck className="dark:text-violet-400 text-violet-600 w-6 h-6" />; 66 + if (is === false) return <HiX className="dark:text-red-400 text-red-600 w-6 h-6" />; 67 + if (is === null) return <BsQuestionLg className="text-orange-400 dark:text-orange-600 w-6 h-6" title="To be discussed" />; 68 + } 69 + 70 + if (is === Infinity) return <IoMdInfinite className="w-7 h-7" title="Infinite" />; 71 + return is; 72 + }; 73 + 74 + return ( 75 + <div className="flex items-center flex-col w-full"> 76 + 77 + <div className="md:text-5xl text-4xl font-semibold md:mb-6 mb-4 dark:text-neutral-100 text-neutral-900 flex gap-2 w-full"> 78 + <h1 className={montserrat.className}> 79 + <span className="bg-gradient-to-r from-indigo-400 to-pink-400 bg-clip-text text-transparent break-keep block md:hidden">Pro</span> 80 + <span className="bg-gradient-to-r from-indigo-400 to-pink-400 bg-clip-text text-transparent break-keep hidden md:block">Professional</span> 81 + </h1> 82 + <HiLightningBolt className="text-pink-400 rotate-6" /> 83 + <Badge text="Not available" /> 84 + </div> 85 + 86 + <ServerGrid guilds={topGuilds} /> 87 + 88 + <div className="dark:bg-wamellow bg-wamellow-100 dark:text-neutral-300 text-neutral-700 mt-10 w-full p-4 rounded-xl text-xl"> 89 + 90 + <div className="flex items-center py-4 border-b-2 dark:border-wamellow-light border-wamellow-100-light text-2xl font-semibold"> 91 + <span className="dark:text-neutral-100 text-neutral-900 w-2/4 block md:hidden">Features</span> 92 + <span className="dark:text-neutral-100 text-neutral-900 w-2/4 hidden md:block">Pricing and Features</span> 93 + 94 + <span className="bg-gradient-to-r from-red-400 to-pink-400 bg-clip-text text-transparent w-1/4 ">Free</span> 95 + 96 + <span className="bg-gradient-to-r from-indigo-400 to-pink-400 bg-clip-text text-transparent w-1/4 block md:hidden">Pro</span> 97 + <span className="bg-gradient-to-r from-indigo-400 to-pink-400 bg-clip-text text-transparent w-1/4 hidden md:block">Pro+ ULTRA HD</span> 98 + </div> 99 + 100 + {[ 101 + { title: "Price", free: "$0 /month", pro: "$3.21 /month" }, 102 + { title: "Custom commands", free: 30, pro: Infinity }, 103 + { title: "Stickymessages", free: 10, pro: 50 }, 104 + { title: "Custom footers", free: false, pro: true }, 105 + { title: "Welcome roles", free: 5, pro: 10 }, 106 + { title: "Welcome pings", free: 5, pro: 15 }, 107 + { title: "Level roles", free: 15, pro: 25 }, 108 + { title: "Spotify control", free: maybe, pro: true, url: "/profile/spotify" }, 109 + { title: "Custom rank sub-text", free: false, pro: true }, 110 + { title: "Display user as webhook", free: false, pro: true }, 111 + { title: "Passport bypass", free: false, pro: true }, 112 + { title: "Custom page color", free: false, pro: true }, 113 + { title: "Statistics & Analytics", free: false, pro: true }, 114 + { title: "Sex with me*", free: false, pro: false } 115 + ].map((item) => ( 116 + <div key={item.title} className="flex items-center py-4 border-b-2 dark:border-wamellow-light border-wamellow-100-light"> 117 + <span className="md:text-base text-sm font-medium w-2/4 md:pr-0 pr-4">{item.title}</span> 118 + <span className="dark:text-neutral-200 text-neutral-700 font-medium w-1/4"> 119 + {displayState(item.free)} 120 + </span> 121 + <span className="dark:text-neutral-200 text-neutral-700 font-medium w-1/4 flex"> 122 + {displayState(item.pro)} 123 + {item.url && <Link href={item.url} target="_blank" rel="noopener noreferrer" className="ml-auto mr-3 hover:underline italic text-sm text-neutral-500 hidden md:block relative top-0.5">Take me there {"->"}</Link>} 124 + </span> 125 + </div> 126 + ))} 127 + 128 + <div className="flex items-center pt-4"> 129 + <span className="text-sm dark:text-neutral-400 text-neutral-600 md:w-2/4">*Sex only with cute femboys from Vienna :3</span> 130 + <div className="hidden md:flex w-2/4 gap-4"> 131 + {buttons} 132 + </div> 133 + </div> 134 + 135 + </div> 136 + 137 + <div className="w-full flex"> 138 + <Link href="/support" target="_blank" rel="noopener noreferrer" className="ml-auto mt-1 dark:text-violet-400/60 text-violet-600/60 hover:text-violet-400/80 dark:hover:text-violet-600/80 hover:underline duration-200 text-sm">Restore previous purchases</Link> 139 + </div> 140 + 141 + <div className="w-full mt-6 md:flex gap-4 items-center"> 142 + <div className="flex gap-4 items-center"> 143 + <span className="flex items-center gap-2"> 144 + <ImageReduceMotion url="https://cdn.discordapp.com/avatars/821472922140803112/ee0026a578a9b2a0844ffa0efe9e3cf4" size={64} alt="mwlica's profile picture" className="w-12 h-12 rounded-full" /> 145 + <div> 146 + <span className="text-xl font-medium dark:text-neutral-200 text-neutral-800">@mwlica</span> <Badge text="Developer" /> <br /> 147 + <span className="dark:text-neutral-300 text-neutral-700">Cute femboy</span> 148 + </div> 149 + </span> 150 + <HiChevronRight className="w-8 h-8" /> 151 + </div> 152 + <span className={`${handwritten.className} text-2xl break-words block md:hidden mt-2`}>„buy it, buy it, buy it, buy it, buy it“</span> 153 + <span className={`${handwritten.className} text-2xl break-words hidden md:block`}>„buy it, buy it, buy it, buy it, buy it, buy it, buy it“</span> 154 + </div> 155 + 156 + <div className="p-2 fixed z-10 bottom-0 left-0 w-full md:hidden"> 157 + <div className="dark:bg-wamellow-light bg-wamellow-100-light rounded-lg shadow-md w-full flex flex-col gap-2 items-center justify-center p-3"> 158 + 159 + <div className="flex gap-2 items-center"> 160 + <span className="dark:text-neutral-200 text-neutral-800 font-medium text-sm">Upgrade your guilds further!</span> 161 + <Badge text="Not available" /> 162 + </div> 163 + 164 + <button className="flex dark:text-violet-400 text-violet-600 bg-violet-600/30 hover:bg-violet-600/10 py-2 px-4 rounded-md duration-200 justify-center gap-2 w-full opacity-30 cursor-not-allowed" disabled> 165 + <HiLightningBolt className="relative top-1" /> 166 + <span className="ml-2">Subscribe</span> 167 + </button> 168 + 169 + </div> 170 + </div> 171 + 172 + </div> 173 + ); 174 + } 175 + 176 + /* 177 + <div className="p-2 fixed z-10 bottom-0 left-0 w-full"> 178 + <div className="bg-wamellow-light rounded-lg shadow-md w-full flex gap-2 items-center justify-center p-3"> 179 + {buttons} 180 + </div> 181 + </div> 182 + */
+2 -2
components/ImageReduceMotion.tsx
··· 5 5 import { webStore } from "@/common/webstore"; 6 6 7 7 interface Props { 8 - url: string; 8 + url: string | null | undefined; 9 9 size: number; 10 10 alt: string; 11 11 className: string; ··· 15 15 const ImageReduceMotion: FunctionComponent<Props> = ({ url, size, alt, className, forceStatic }) => { 16 16 const web = webStore((w) => w); 17 17 18 - return <Image itemProp="image" src={!url.includes("null") ? `${url}.${url.includes("a_") && !web.reduceMotions && !forceStatic ? "gif" : "webp"}?size=${size}` : "/discord.png"} width={size} height={size} alt={alt} className={className} />; 18 + return <Image itemProp="image" src={!url?.includes("null") && url ? `${url}.${url.includes("a_") && !web.reduceMotions && !forceStatic ? "gif" : "webp"}?size=${size}` : "/discord.png"} width={size} height={size} alt={alt} className={className} />; 19 19 }; 20 20 21 21 export default ImageReduceMotion;
+1 -1
components/List.tsx
··· 47 47 else router.push(`${url}${tab.value}`); 48 48 }} 49 49 > 50 - {tab.name} 50 + <span dangerouslySetInnerHTML={{ __html: tab.name.replace(/ +/g, "&nbsp;") }} /> 51 51 </button> 52 52 </li> 53 53 );
+27
components/ServerGrid.tsx
··· 1 + import { FunctionComponent } from "react"; 2 + 3 + import { ApiV1TopguildsGetResponse } from "@/typings"; 4 + 5 + import ImageReduceMotion from "./ImageReduceMotion"; 6 + 7 + interface Props { 8 + guilds: ApiV1TopguildsGetResponse[]; 9 + } 10 + 11 + const ServerGrid: FunctionComponent<Props> = ({ guilds }) => { 12 + return ( 13 + <div className="w-full h-52 overflow-hidden rounded-xl"> 14 + <div className="grid grid-flow-col grid-rows-3 w-full md:gap-4 gap-3 rotate-6 relative right-8 bottom-10 md:bottom-20"> 15 + 16 + {[...guilds, ...guilds, ...guilds, ...guilds, ...guilds, ...guilds].map((guild) => ( 17 + <div key={guild.name} className="md:h-32 h-24 md:w-32 w-24"> 18 + <ImageReduceMotion url={guild.icon?.split(".").slice(0, -1).join(".")} size={128} alt="Server" className="rounded-xl" /> 19 + </div> 20 + ))} 21 + 22 + </div> 23 + </div> 24 + ); 25 + }; 26 + 27 + export default ServerGrid;
+1 -1
components/badge.tsx
··· 6 6 7 7 const Badge: FunctionComponent<Props> = ({ text }) => { 8 8 return ( 9 - <span className="inline-block whitespace-nowrap rounded-[0.27rem] bg-violet-400/40 px-[0.65em] pb-[0.25em] pt-[0.35em] text-center align-baseline text-[0.75em] font-medium leading-none text-violet-300"> 9 + <span className="inline-block whitespace-nowrap rounded-[0.27rem] dark:bg-violet-400/40 bg-violet-600/40 px-[0.65em] pb-[0.25em] pt-[0.35em] text-center align-baseline text-[0.75em] font-medium leading-none dark:text-violet-300 text-violet-700/60 ml-auto"> 10 10 {text} 11 11 </span> 12 12 );