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.

create docs

Luna cb4e86b4 83278ddf

+412 -70
+1 -1
app/(home)/privacy/page.tsx
··· 1 1 import { Metadata } from "next"; 2 2 import React from "react"; 3 3 4 - import BeautifyMarkdown from "@/components/BeautifyMarkdown"; 4 + import BeautifyMarkdown from "@/components/markdown"; 5 5 import { CopyToClipboardButton } from "@/components/copy-to-clipboard"; 6 6 import { getBaseUrl, getCanonicalUrl } from "@/utils/urls"; 7 7
+1 -1
app/(home)/terms/page.tsx
··· 1 1 import { Metadata } from "next"; 2 2 import React from "react"; 3 3 4 - import BeautifyMarkdown from "@/components/BeautifyMarkdown"; 4 + import BeautifyMarkdown from "@/components/markdown"; 5 5 import { CopyToClipboardButton } from "@/components/copy-to-clipboard"; 6 6 import { getBaseUrl, getCanonicalUrl } from "@/utils/urls"; 7 7
+4 -3
app/[pathname]/page.tsx
··· 22 22 return redirect("/login?invite=true"); 23 23 case "logout": 24 24 return redirect("/login?logout=true"); 25 - case "youtube": 26 - case "docs": 27 - case "guides": { 25 + case "youtube": { 28 26 const res = await fetch("http://100.65.0.1:5001/?channel_id=UClWBeVcz5LUmcCN1gHG_GCg", fetchOptions) 29 27 .then((res) => res.json()) 30 28 .catch(() => null) as { videoUrl: string } | null; 31 29 32 30 return redirect(res?.videoUrl || "https://www.youtube.com/channel/UClWBeVcz5LUmcCN1gHG_GCg"); 33 31 } 32 + case "docs": 33 + case "guides": 34 + return redirect("/docs/index"); 34 35 case "ai": 35 36 return redirect("/ai-gallery"); 36 37 }
+121
app/docs/[...pathname]/layout.tsx
··· 1 + import { Button, Divider } from "@nextui-org/react"; 2 + import { Metadata } from "next"; 3 + import Link from "next/link"; 4 + import { BsDiscord } from "react-icons/bs"; 5 + import { HiExternalLink } from "react-icons/hi"; 6 + 7 + import Footer from "@/components/footer"; 8 + import metadata from "@/public/docs/meta.json"; 9 + import { getBaseUrl, getCanonicalUrl } from "@/utils/urls"; 10 + 11 + interface Props { 12 + params: { pathname: string[] }; 13 + children: React.ReactNode; 14 + } 15 + 16 + export const generateMetadata = async ({ 17 + params 18 + }: Props): Promise<Metadata> => { 19 + const meta = metadata.pages.find((page) => page.file === `${params.pathname.join("/")}.md`); 20 + 21 + const title = "Documentation"; 22 + const url = getCanonicalUrl("docs", ...params.pathname); 23 + 24 + return { 25 + title, 26 + description: meta?.description, 27 + alternates: { 28 + canonical: url 29 + }, 30 + openGraph: { 31 + title, 32 + description: meta?.description, 33 + url, 34 + type: "website", 35 + images: `${getBaseUrl()}/waya-v3.jpg?v=2` 36 + }, 37 + twitter: { 38 + card: "summary", 39 + title, 40 + description: meta?.description, 41 + images: `${getBaseUrl()}/waya-v3.jpg?v=2` 42 + } 43 + }; 44 + }; 45 + 46 + export default async function RootLayout({ 47 + params, 48 + children 49 + }: Props) { 50 + const meta = metadata.pages.find((page) => page.file === `${params.pathname.join("/")}.md`); 51 + 52 + return ( 53 + <div className="w-full"> 54 + 55 + <div className="flex justify-between items-center"> 56 + <div> 57 + <h1 className="text-2xl font-medium text-neutral-100"> 58 + Documentation 59 + </h1> 60 + <div> 61 + {meta?.description} 62 + </div> 63 + </div> 64 + <div className="text-red-400"> 65 + The docs are still work in progress! 66 + </div> 67 + </div> 68 + 69 + <Divider className="mt-2" /> 70 + 71 + <div className="flex flex-col lg:flex-row gap-6 mt-5 min-h-[63vh]"> 72 + <ul className="w-full lg:w-1/4 space-y-2"> 73 + {metadata.pages.map((page) => ( 74 + <ol key={page.file}> 75 + <Button 76 + as={Link} 77 + className="w-full !justify-start" 78 + href={`/docs/${page.file.replace(/\.md$/, "")}`} 79 + > 80 + {page.name} 81 + </Button> 82 + </ol> 83 + ))} 84 + 85 + <ol> 86 + <Button 87 + as={Link} 88 + className="w-full !justify-start button-blurple mt-4" 89 + href="/support" 90 + startContent={<BsDiscord />} 91 + endContent={<HiExternalLink />} 92 + > 93 + Join Support 94 + </Button> 95 + </ol> 96 + <ol> 97 + <Button 98 + as={Link} 99 + className="w-full !justify-start font-medium" 100 + href="/invite" 101 + color="secondary" 102 + startContent={<BsDiscord />} 103 + endContent={<HiExternalLink />} 104 + > 105 + Invite Wamellow 106 + </Button> 107 + </ol> 108 + </ul> 109 + 110 + <Divider className="lg:hidden" /> 111 + <div className="w-full lg:w-3/4"> 112 + {children} 113 + </div> 114 + 115 + </div> 116 + 117 + <Footer className="mt-24" /> 118 + 119 + </div> 120 + ); 121 + }
+43
app/docs/[...pathname]/page.tsx
··· 1 + import { Code } from "@nextui-org/react"; 2 + import { readFile } from "fs/promises"; 3 + 4 + import BeautifyMarkdown from "@/components/markdown"; 5 + import Notice, { NoticeType } from "@/components/notice"; 6 + import metadata from "@/public/docs/meta.json"; 7 + 8 + interface Props { 9 + params: { pathname: string[] }; 10 + } 11 + 12 + const PATH = `${process.cwd()}/public/docs` as const; 13 + 14 + export default async function Home({ params }: Props) { 15 + const markdown = await readFile(`${PATH}/${params.pathname.join("/")}.md`, "utf-8"); 16 + const meta = metadata.pages.find((page) => page.file === `${params.pathname.join("/")}.md`); 17 + 18 + return ( 19 + <div> 20 + {meta?.permissions?.bot && 21 + <Notice 22 + type={NoticeType.Info} 23 + message="Required bot permissions:" 24 + location="bottom" 25 + > 26 + <div className="flex flex-wrap gap-1"> 27 + {meta.permissions.bot.map((perm) => ( 28 + <Code 29 + key={perm} 30 + className="font-semibold text-violet-400" 31 + color="secondary" 32 + > 33 + {perm} 34 + </Code> 35 + ))} 36 + </div> 37 + </Notice> 38 + } 39 + 40 + <BeautifyMarkdown markdown={markdown} /> 41 + </div> 42 + ); 43 + }
-53
components/BeautifyMarkdown.tsx
··· 1 - import Link from "next/link"; 2 - import { FunctionComponent } from "react"; 3 - import { ReactMarkdown } from "react-markdown/lib/react-markdown"; 4 - import rehypeRaw from "rehype-raw"; 5 - 6 - const BeautifyMarkdown: FunctionComponent<{ markdown: string }> = ({ markdown }) => { 7 - 8 - function parseDiscordMarkdown(content: string) { 9 - return content 10 - .replace(/__(.*?)__/g, "<u>$1</u>") 11 - // .replace(/<a?:\w{2,32}:(.*?)>/g, "<img className='rounded-md' style='height: 1.375em; position: relative' src=\"https://cdn.discordapp.com/emojis/$1.webp?size=40&quality=lossless\" />") 12 - .replace(/<a?:\w{2,32}:(.*?)>/g, "") 13 - .replace(/<(@|@!)\d{15,21}>/g, "<span className='bg-blurple/25 hover:bg-blurple/50 p-1 rounded-md dark:text-neutral-100 text-neutral-900 font-light text-sx duration-200 cursor-pointer'>@User</span>") 14 - .replace(/<(#)\d{15,21}>/g, "<span className='bg-blurple/25 hover:bg-blurple/50 p-1 rounded-md dark:text-neutral-100 text-neutral-900 font-light text-sx duration-200 cursor-pointer'>@Channel</span>"); 15 - } 16 - 17 - return ( 18 - <ReactMarkdown 19 - /* @ts-expect-error they broke types */ 20 - rehypePlugins={[rehypeRaw]} 21 - components={{ 22 - h1: ({ ...props }) => <Link 23 - href={`#${props.children.toString().toLowerCase().replace(/ +/g, "-")}`} 24 - className="flex mt-10 mb-3 cursor-pointer dark:text-neutral-100 text-neutral-900 hover:underline" 25 - > 26 - <h2 id={props.children.toString().toLowerCase().replace(/ +/g, "-")} className="text-3xl font-semibold" {...props} /> 27 - </Link>, 28 - 29 - h2: ({ ...props }) => <Link 30 - href={`#${props.children.toString().toLowerCase().replace(/ +/g, "-")}`} 31 - className="flex mt-6 mb-2 cursor-pointer dark:text-neutral-100 text-neutral-900 hover:underline" 32 - > 33 - <h1 id={props.children.toString().toLowerCase().replace(/ +/g, "-")} className="text-2xl font-semibold" {...props} /> 34 - </Link>, 35 - 36 - strong: ({ ...props }) => <span className="font-semibold dark:text-neutral-200 text-neutral-800" {...props} />, 37 - i: ({ ...props }) => <span className="italic" {...props} />, 38 - a: ({ ...props }) => <a className="text-blue-500 hover:underline underline-blue-500" {...props} />, 39 - del: ({ ...props }) => <span className="line-through" {...props} />, 40 - ins: ({ ...props }) => <span className="underline" {...props} />, 41 - li: ({ ...props }) => <div className="flex gap-1 my-1"> 42 - <span className="mr-1">•</span> 43 - <span {...props} /> 44 - </div> 45 - }} 46 - > 47 - {parseDiscordMarkdown(markdown)} 48 - </ReactMarkdown> 49 - ); 50 - 51 - }; 52 - 53 - export default BeautifyMarkdown;
-8
components/Betweener.tsx
··· 1 - export default function Betweener() { 2 - return ( 3 - <> 4 - <hr className="w-1/2 dark:border-wamellow-light border-wamellow-100-light rounded-full select-none md:hidden" /> 5 - <span className="w-0.5 h-20 dark:bg-wamellow-light bg-wamellow-100-light rounded-full rotate-6 select-none hidden md:block" /> 6 - </> 7 - ); 8 - }
+70
components/markdown.tsx
··· 1 + /* eslint-disable @typescript-eslint/no-unused-vars */ 2 + import { Code } from "@nextui-org/react"; 3 + import Link from "next/link"; 4 + import { ReactMarkdown } from "react-markdown/lib/react-markdown"; 5 + import rehypeRaw from "rehype-raw"; 6 + 7 + export default function BeautifyMarkdown({ 8 + markdown 9 + }: { 10 + markdown: string 11 + }) { 12 + 13 + function parseDiscordMarkdown(content: string) { 14 + return content 15 + .replace(/__(.*?)__/g, "<u>$1</u>") 16 + // .replace(/<a?:\w{2,32}:(.*?)>/g, "<img className='rounded-md' style='height: 1.375em; position: relative' src=\"https://cdn.discordapp.com/emojis/$1.webp?size=40&quality=lossless\" />") 17 + .replace(/<a?:\w{2,32}:(.*?)>/g, "") 18 + .replace(/<(@|@!)\d{15,21}>/g, "<span className='bg-blurple/25 hover:bg-blurple/50 p-1 rounded-md dark:text-neutral-100 text-neutral-900 font-light text-sx duration-200 cursor-pointer'>@User</span>") 19 + .replace(/<(#)\d{15,21}>/g, "<span className='bg-blurple/25 hover:bg-blurple/50 p-1 rounded-md dark:text-neutral-100 text-neutral-900 font-light text-sx duration-200 cursor-pointer'>@Channel</span>"); 20 + } 21 + 22 + return ( 23 + <ReactMarkdown 24 + /* @ts-expect-error they broke types */ 25 + rehypePlugins={[rehypeRaw]} 26 + components={{ 27 + h1: (props) => <Link 28 + href={`#${props.children.toString().toLowerCase().replace(/ +/g, "-")}`} 29 + className="flex mt-10 mb-3 cursor-pointer dark:text-neutral-100 text-neutral-900 hover:underline" 30 + > 31 + <h2 id={props.children.toString().toLowerCase().replace(/ +/g, "-")} className="text-3xl font-semibold" {...props} /> 32 + </Link>, 33 + 34 + h2: (props) => <Link 35 + href={`#${props.children.toString().toLowerCase().replace(/ +/g, "-")}`} 36 + className="flex mt-6 mb-2 cursor-pointer dark:text-neutral-100 text-neutral-900 hover:underline" 37 + > 38 + <h1 id={props.children.toString().toLowerCase().replace(/ +/g, "-")} className="text-2xl font-semibold" {...props} /> 39 + </Link>, 40 + 41 + h3: (props) => <Link 42 + href={`#${props.children.toString().toLowerCase().replace(/ +/g, "-")}`} 43 + className="flex mt-6 mb-2 cursor-pointer dark:text-neutral-100 text-neutral-900 hover:underline" 44 + > 45 + <h3 id={props.children.toString().toLowerCase().replace(/ +/g, "-")} className="text-xl font-semibold" {...props} /> 46 + </Link>, 47 + 48 + strong: (props) => <span className="font-semibold dark:text-neutral-200 text-neutral-800" {...props} />, 49 + i: (props) => <span className="italic" {...props} />, 50 + a: (props) => <a className="text-blue-500 hover:underline underline-blue-500" {...props} />, 51 + del: (props) => <span className="line-through" {...props} />, 52 + ins: (props) => <span className="underline" {...props} />, 53 + li: (props) => <div className="flex gap-1 my-1"> 54 + <span className="mr-1">•</span> 55 + <span {...props} /> 56 + </div>, 57 + // @ts-expect-error Warning: Received `true` for a non-boolean attribute `inline`. 58 + code: (props: { children: React.ReactNode }) => <Code color="secondary" {...props} inline="false" />, 59 + 60 + table: (props) => <table className="mt-4 table-auto w-full divide-y-1 divide-wamellow overflow-scroll" {...props} />, 61 + th: ({ isHeader, ...props }) => <th className=" px-2 pb-2 font-medium text-neutral-800 dark:text-neutral-200 text-left" {...props} />, 62 + tr: ({ isHeader, ...props }) => <tr className="divide-x-1 divide-wamellow" {...props} />, 63 + td: ({ isHeader, ...props }) => <td className="px-2 py-1 divide-x-8 divide-wamellow break-all" {...props} /> 64 + }} 65 + > 66 + {parseDiscordMarkdown(markdown)} 67 + </ReactMarkdown> 68 + ); 69 + 70 + }
+14 -4
components/notice.tsx
··· 10 10 interface Props { 11 11 message: string; 12 12 type?: NoticeType; 13 + location?: "side" | "bottom"; 13 14 children?: React.ReactNode; 14 15 } 15 16 16 17 export default function Notice({ 17 18 message, 18 19 type, 20 + location = "side", 19 21 children 20 22 }: Props) { 21 23 22 24 return ( 23 - <div className={cn("w-full text-neutral-100 py-2 px-4 mb-6 rounded-md flex gap-2 items-center", type === NoticeType.Info ? "bg-violet-400/40" : "bg-red-400/40")}> 24 - {type === NoticeType.Info ? <HiExclamationCircle className="h-5 w-5" /> : <HiExclamation className="h-5 w-5" />} 25 - <div className="text-lg">{message}</div> 25 + <div 26 + className={cn( 27 + "w-full text-neutral-100 py-2 px-4 mb-6 rounded-md flex gap-2", 28 + location === "side" ? "flex-row items-center" : "flex-col", 29 + type === NoticeType.Info ? "bg-violet-400/40" : "bg-red-400/40" 30 + )} 31 + > 32 + <div className="flex items-center gap-2"> 33 + {type === NoticeType.Info ? <HiExclamationCircle className="h-5 w-5" /> : <HiExclamation className="h-5 w-5" />} 34 + <div className="text-lg">{message}</div> 35 + </div> 26 36 27 37 {children && 28 - <div className="ml-auto"> 38 + <div className={cn(location === "side" && "ml-auto")}> 29 39 {children} 30 40 </div> 31 41 }
+124
public/docs/greetings.md
··· 1 + ## Placeholders 2 + 3 + Placeholders allow you to use variables that change from message to message, for example to display information about the joining user or your server. They are always enclosed in curly braces, such as `{user.username}`. 4 + 5 + <table> 6 + <thead> 7 + <tr> 8 + <th width="181">Placeholder</th> 9 + <th>Example</th> 10 + <th width="181">Description</th> 11 + </tr> 12 + </thead> 13 + <tbody> 14 + <tr> 15 + <td><code>user.mention</code></td> 16 + <td><@821472922140803112></td> 17 + <td>User mention</td> 18 + </tr> 19 + <tr> 20 + <td><code>user.id</code></td> 21 + <td>821472922140803112</td> 22 + <td>User id</td> 23 + </tr> 24 + <tr> 25 + <td><code>user.tag</code></td> 26 + <td>@mwlica</td> 27 + <td>User tag</td> 28 + </tr> 29 + <tr> 30 + <td><code>user.name</code></td> 31 + <td>yll</td> 32 + <td>Username</td> 33 + </tr> 34 + <tr> 35 + <td><code>user.avatar</code></td> 36 + <td>https://cdn.discordapp.com/...</td> 37 + <td>Avatar URL</td> 38 + </tr> 39 + </tbody> 40 + </table> 41 + 42 + <table> 43 + <thead> 44 + <tr> 45 + <th width="181">Placeholder</th> 46 + <th>Example</th> 47 + <th width="181">Description</th> 48 + </tr> 49 + </thead> 50 + <tbody> 51 + <tr> 52 + <td><code>guild.name</code></td> 53 + <td>Someone's</td> 54 + <td>Server name</td> 55 + </tr> 56 + <tr> 57 + <td><code>guild.id</code></td> 58 + <td>828676951023550495</td> 59 + <td>Server id</td> 60 + </tr> 61 + <tr> 62 + <td><code>guild.avatar</code></td> 63 + <td>https://cdn.discordapp.com/...</td> 64 + <td>Icon URL</td> 65 + </tr> 66 + <tr> 67 + <td><code>guild.rules</code></td> 68 + <td><#883818033867542648></td> 69 + <td>Rules channel</td> 70 + </tr> 71 + <tr> 72 + <td><code>guild.memberCount</code></td> 73 + <td>848</td> 74 + <td>Member count</td> 75 + </tr> 76 + </tbody> 77 + </table> 78 + 79 + <table> 80 + <thead> 81 + <tr> 82 + <th width="181">Placeholder</th> 83 + <th>Example</th> 84 + <th width="181">Description</th> 85 + </tr> 86 + </thead> 87 + <tbody> 88 + <tr> 89 + <td><code>inviter.mention</code></td> 90 + <td><@821472922140803112></td> 91 + <td>User mention</td> 92 + </tr> 93 + <tr> 94 + <td><code>inviter.id</code></td> 95 + <td>821472922140803112</td> 96 + <td>User id</td> 97 + </tr> 98 + <tr> 99 + <td><code>inviter.tag</code></td> 100 + <td>@mwlica</td> 101 + <td>User tag</td> 102 + </tr> 103 + <tr> 104 + <td><code>inviter.name</code></td> 105 + <td>yll</td> 106 + <td>Username</td> 107 + </tr> 108 + <tr> 109 + <td><code>inviter.avatar</code></td> 110 + <td>https://cdn.discordapp.com/...</td> 111 + <td>Avatar URL</td> 112 + </tr> 113 + <tr> 114 + <td><code>inviter.code</code></td> 115 + <td>yYd6YKHQZH</td> 116 + <td>Invite code</td> 117 + </tr> 118 + <tr> 119 + <td><code>inviter.count</code></td> 120 + <td>259</td> 121 + <td>Count of invited users</td> 122 + </tr> 123 + </tbody> 124 + </table>
+9
public/docs/index.md
··· 1 + # Hello and welcome 2 + ## Hello and welcome 3 + ### Hello and welcome 4 + ### Hello and welcome 5 + **Hello and welcome** 6 + 7 + *Hell and welcomeo* 8 + 9 + fds `code` fds
+25
public/docs/meta.json
··· 1 + { 2 + "pages": [ 3 + { 4 + "name": "🍪 Home", 5 + "file": "index.md", 6 + "description": "Welcome to the Wamellow documentation!" 7 + }, 8 + { 9 + "name": "👋 Greetings", 10 + "file": "greetings.md", 11 + "description": "Welcome new members to your community!", 12 + "permissions": { 13 + "bot": [ 14 + "View Channel", 15 + "Send Messages", 16 + "Embed Links", 17 + "Attach Files" 18 + ], 19 + "user": [ 20 + "Manage Server" 21 + ] 22 + } 23 + } 24 + ] 25 + }