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.

fix lists, code and image markdown, add emoji support

Luna 5c871661 214287b6

+90 -33
+90 -33
components/markdown.tsx
··· 1 1 /* eslint-disable @typescript-eslint/no-unused-vars */ 2 2 import { Code } from "@nextui-org/react"; 3 3 import Link from "next/link"; 4 - import { ReactMarkdown } from "react-markdown/lib/react-markdown"; 4 + import { HiExternalLink } from "react-icons/hi"; 5 + import ReactMarkdown from "react-markdown"; 5 6 import rehypeRaw from "rehype-raw"; 7 + 8 + import cn from "@/utils/cn"; 6 9 7 10 export default function BeautifyMarkdown({ 8 11 markdown ··· 13 16 function parseDiscordMarkdown(content: string) { 14 17 return content 15 18 .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>"); 19 + .replace(/<a?:\w{2,32}:(.*?)>/g, "<img alt='emoji' className='rounded-md inline' style='height: 1.375em; position: relative' src='https://cdn.discordapp.com/emojis/$1.webp?size=40&quality=lossless' />") 20 + .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>") 21 + .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 22 } 21 23 22 24 return ( 23 25 <ReactMarkdown 24 - /* @ts-expect-error they broke types */ 25 26 rehypePlugins={[rehypeRaw]} 26 27 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>, 28 + h1: (props) => ( 29 + <Link 30 + href={`#${props.children?.toString().toLowerCase().replace(/ +/g, "-")}`} 31 + className="flex mt-10 mb-3 cursor-pointer dark:text-neutral-100 text-neutral-900 hover:underline" 32 + > 33 + <h2 id={props.children?.toString().toLowerCase().replace(/ +/g, "-")} className="text-3xl font-semibold" {...props} /> 34 + </Link> 35 + ), 33 36 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>, 37 + h2: (props) => ( 38 + <Link 39 + href={`#${props.children?.toString().toLowerCase().replace(/ +/g, "-")}`} 40 + className="flex mt-6 mb-2 cursor-pointer dark:text-neutral-100 text-neutral-900 hover:underline" 41 + > 42 + <h1 id={props.children?.toString().toLowerCase().replace(/ +/g, "-")} className="text-2xl font-semibold" {...props} /> 43 + </Link> 44 + ), 40 45 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>, 46 + h3: (props) => ( 47 + <Link 48 + href={`#${props.children?.toString().toLowerCase().replace(/ +/g, "-")}`} 49 + className="flex mt-6 mb-2 cursor-pointer dark:text-neutral-100 text-neutral-900 hover:underline" 50 + > 51 + <h3 id={props.children?.toString().toLowerCase().replace(/ +/g, "-")} className="text-xl font-semibold" {...props} /> 52 + </Link> 53 + ), 47 54 48 55 strong: (props) => <span className="font-semibold dark:text-neutral-200 text-neutral-800" {...props} />, 49 56 i: (props) => <span className="italic" {...props} />, 50 - a: (props) => <a className="text-blue-500 hover:underline underline-blue-500" {...props} />, 51 57 del: (props) => <span className="line-through" {...props} />, 52 58 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 + // @ts-expect-error inline does exist 61 + code: ({ inline, ref, color, ...props }) => { 62 + if (inline) return <Code color="secondary" {...props} />; 63 + 64 + return ( 65 + <div 66 + className="bg-wamellow border border-wamellow-light text-neutral-200 rounded-md p-3 my-2 break-all" 67 + {...props} 68 + /> 69 + ); 70 + }, 71 + img: ({ alt = "image", ...props }) => ( 72 + <span 73 + className={cn( 74 + "max-w-lg w-fit flex-col items-center inline", 75 + alt === "emoji" ? "inline" : "flex" 76 + )} 77 + > 78 + {/* eslint-disable-next-line @next/next/no-img-element */} 79 + <img alt={alt} className="rounded-md" loading="lazy" {...props} /> 80 + {alt && alt !== "emoji" && <span className="text-neutral-500 font-medium relative bottom-1">{alt}</span>} 81 + </span> 82 + ), 83 + a: ({ href, children, ...props }) => ( 84 + <Link 85 + href={href || "#"} 86 + target="_blank" 87 + className="text-violet-400 hover:underline" 88 + {...props} 89 + > 90 + {children} <HiExternalLink className="inline" /> 91 + </Link> 92 + ), 59 93 60 - table: (props) => <table className="mt-4 table-auto w-full divide-y-1 divide-wamellow overflow-scroll" {...props} />, 94 + // @ts-expect-error isHeader does exist 95 + table: ({ isHeader, ...props }) => <table className="mt-4 table-auto w-full divide-y-1 divide-wamellow overflow-scroll" {...props} />, 96 + // @ts-expect-error isHeader does exist 61 97 th: ({ isHeader, ...props }) => <th className=" px-2 pb-2 font-medium text-neutral-800 dark:text-neutral-200 text-left" {...props} />, 98 + // @ts-expect-error isHeader does exist 62 99 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} /> 100 + // @ts-expect-error isHeader does exist 101 + td: ({ isHeader, ...props }) => <td className="px-2 py-1 divide-x-8 divide-wamellow break-all" {...props} />, 102 + 103 + // @ts-expect-error ordered does exist 104 + ol: ({ ordered, ...props }) => ( 105 + <div className="list-decimal list-inside marker:text-neutral-300/40 my-1"> 106 + <span 107 + className="space-y-1" 108 + {...props} 109 + /> 110 + </div> 111 + ), 112 + // @ts-expect-error ordered does exist 113 + ul: ({ ordered, ...props }) => ( 114 + <div className="list-disc list-inside marker:text-neutral-300/40 my-1"> 115 + <span 116 + className="space-y-1" 117 + {...props} 118 + /> 119 + </div> 120 + ) 64 121 }} 65 122 > 66 123 {parseDiscordMarkdown(markdown)}