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.

Merge branch 'master' of https://github.com/Luna-devv/Wamellow-Web

Luna add0e10c 05f08c93

+234 -3
+123
components/inputs/ColorInput.tsx
··· 1 + import { FunctionComponent, useEffect, useState } from "react"; 2 + import { TailSpin } from "react-loading-icons"; 3 + 4 + import { RouteErrorResponse } from "@/typings"; 5 + 6 + import { useStateDebounced } from "../../utils/useDebounce"; 7 + import DumbColorInput from "./Dumb_ColorInput"; 8 + 9 + type Props = { 10 + name: string; 11 + url: string; 12 + dataName: string; 13 + disabled?: boolean; 14 + description?: string; 15 + __defaultState: string | number; 16 + resetState?: string | number; 17 + 18 + max?: number; 19 + placeholder?: string; 20 + 21 + onSave?: (value: string | number) => void; 22 + }; 23 + 24 + 25 + const ColorInput: FunctionComponent<Props> = ({ name, url, dataName, disabled, description, __defaultState, resetState, max, placeholder, onSave }) => { 26 + const [state, setState] = useState<"LOADING" | "ERRORED" | "SUCCESS" | undefined>(); 27 + const [error, setError] = useState<string>(); 28 + 29 + const [valuedebounced, setValuedebounced] = useStateDebounced<string | number>("", 1000); 30 + const [value, setValue] = useState<string | number>(""); 31 + const [__defaultStatealue, set__defaultStatealue] = useState<string | number>(""); 32 + 33 + useEffect(() => { 34 + if (!__defaultStatealue) set__defaultStatealue(__defaultState); 35 + setValue(__defaultState); 36 + }, [__defaultState]); 37 + 38 + useEffect(() => { 39 + if (__defaultStatealue === value) return; 40 + setError(undefined); 41 + setState("LOADING"); 42 + 43 + fetch(`${process.env.NEXT_PUBLIC_API}${url}`, { 44 + method: "PATCH", 45 + headers: { 46 + "Content-Type": "application/json", 47 + authorization: localStorage.getItem("token") as string 48 + }, 49 + body: JSON.stringify({ [dataName]: value || 0x000000 }) 50 + }) 51 + .then(async (res) => { 52 + const response = await res.json(); 53 + if (!response) return; 54 + 55 + switch (res.status) { 56 + case 200: { 57 + setValue(value || 0x000000); 58 + onSave?.(value || 0x000000); 59 + set__defaultStatealue(value || 0x000000); 60 + 61 + setState("SUCCESS"); 62 + setTimeout(() => setState(undefined), 1_000 * 8); 63 + break; 64 + } 65 + default: { 66 + setState("ERRORED"); 67 + setError((response as unknown as RouteErrorResponse).message); 68 + break; 69 + } 70 + } 71 + 72 + }) 73 + .catch(() => { 74 + setState("ERRORED"); 75 + setError("Error while updatung"); 76 + }); 77 + 78 + }, [valuedebounced]); 79 + 80 + return ( 81 + <div className="relative w-full"> 82 + 83 + <div className="flex items-center gap-2"> 84 + <span className="text-lg dark:text-neutral-300 text-neutral-700 font-medium">{name}</span> 85 + {state === "LOADING" && <TailSpin stroke="#d4d4d4" strokeWidth={8} className="relative h-3 w-3 overflow-visible" />} 86 + 87 + {(resetState && resetState !== value) && 88 + <button 89 + className="text-sm ml-auto text-violet-400/60 hover:text-violet-400/90 duration-200" 90 + onClick={() => { 91 + setValue(resetState); 92 + setValuedebounced(resetState); 93 + setState(undefined); 94 + }} 95 + disabled={disabled} 96 + > 97 + reset 98 + </button> 99 + } 100 + </div> 101 + 102 + <DumbColorInput 103 + value={value} 104 + setValue={(v) => { 105 + setValue(v); 106 + setValuedebounced(v); 107 + setState(undefined); 108 + }} 109 + disabled={disabled} 110 + placeholder={placeholder} 111 + max={max} 112 + description={description} 113 + /> 114 + 115 + <div className="flex absolute right-0 bottom-0"> 116 + {(error || state === "ERRORED") && <div className="ml-auto text-red-500 text-sm">{error || "Unknown error while saving"}</div>} 117 + </div> 118 + 119 + </div> 120 + ); 121 + }; 122 + 123 + export default ColorInput;
+91
components/inputs/Dumb_ColorInput.tsx
··· 1 + import { AnimatePresence, motion } from "framer-motion"; 2 + import React, { FunctionComponent, HTMLAttributes, useEffect, useState } from "react"; 3 + import { AiOutlineEdit } from "react-icons/ai"; 4 + 5 + type Props = { 6 + name?: string; 7 + placeholder?: string; 8 + 9 + // eslint-disable-next-line @typescript-eslint/no-explicit-any 10 + value: any; setValue: React.Dispatch<React.SetStateAction<any>>; 11 + 12 + disabled?: boolean; 13 + description?: string; 14 + max?: number; 15 + thin?: boolean; 16 + 17 + dataName?: string; 18 + }; 19 + 20 + 21 + const DumbColorInput: FunctionComponent<Props> = ({ name, placeholder, value, setValue, disabled, description, max = 256, thin, dataName }) => { 22 + const className = `relative cursor-pointer mt-1 ${max > 300 ? "h-28" : (thin ? "h-10" : "h-12")} ${thin && "relative bottom-1"} resize-none w-full rounded-md flex items-center px-4 py-2 focus:outline outline-violet-400 outline-2 ${disabled && "cursor-not-allowed opacity-50 "}` as HTMLAttributes<HTMLDivElement>["className"]; 23 + console.log("value", value); 24 + // console.log(dataName && JSON.parse(value)[dataName]); 25 + 26 + // this cuz there can be multiple color inputs on the same page, so it will bug, so we need to identify them 27 + const [inputId, setInputId] = useState<string>(""); 28 + useEffect(() => { 29 + setInputId(Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)); 30 + }, []); 31 + 32 + const [isHovered, setIsHovered] = useState<boolean>(false); 33 + 34 + return ( 35 + <div className="relative select-none w-full max-w-full mb-3"> 36 + {name && 37 + <div className="flex items-center gap-2"> 38 + <span className="text-lg dark:text-neutral-300 text-neutral-700 font-medium">{name}</span> 39 + </div> 40 + } 41 + 42 + <input 43 + className={"absolute -bottom-2 left-0 w-0 h-0 opacity-0 pointer-events-none"} 44 + id={inputId} 45 + placeholder={placeholder} 46 + onChange={(e) => { 47 + if (dataName) { 48 + setValue(JSON.stringify(Object.assign(JSON.parse(value), { [dataName]: parseInt(e.target.value.slice(1), 16) }))); 49 + } else { 50 + setValue(parseInt(e.target.value.slice(1), 16)); 51 + } 52 + }} 53 + value={(dataName ? JSON.parse(value)[dataName] : value) ? `#${(dataName ? JSON.parse(value)[dataName] : value)?.toString(16)}` : "#ffffff"} 54 + disabled={disabled} 55 + type={"color"} 56 + maxLength={max || Infinity} 57 + /> 58 + 59 + <label 60 + htmlFor={inputId} 61 + className={className} 62 + onPointerEnter={() => setIsHovered(true)} 63 + onPointerLeave={() => setIsHovered(false)} 64 + // style cuz bg-[#color] didnt work for me in tw 65 + style={{ 66 + backgroundColor: (dataName ? JSON.parse(value)[dataName] : value) ? `#${(dataName ? JSON.parse(value)[dataName] : value)?.toString(16)}` : "#ffffff" 67 + }} 68 + > 69 + <AnimatePresence initial={false} mode="wait"> 70 + {isHovered && <motion.div 71 + initial={{ opacity: 0 }} 72 + animate={{ opacity: 1 }} 73 + exit={{ opacity: 0 }} 74 + transition={{ 75 + duration: 0.15, 76 + ease: "easeInOut" 77 + }} 78 + className="absolute top-0 left-0 w-full h-full bg-wamellow-900-alpha rounded-md pointer-events-none flex items-center justify-center"> 79 + <AiOutlineEdit className="w-6 h-6 text-[rgba(255,255,255,0.8)]" /> 80 + </motion.div> 81 + } 82 + </AnimatePresence> 83 + </label> 84 + 85 + {description && <div className="dark:text-neutral-500 text-neutral-400 text-sm mt-1">{description}</div>} 86 + 87 + </div> 88 + ); 89 + }; 90 + 91 + export default DumbColorInput;
+2 -2
components/inputs/Dumb_TextInput.tsx
··· 1 - import React, { FunctionComponent, useEffect, useState } from "react"; 1 + import React, { FunctionComponent, HTMLAttributes, useEffect, useState } from "react"; 2 2 3 3 import cn from "@/utils/cn"; 4 4 ··· 20 20 21 21 22 22 const DumbTextInput: FunctionComponent<Props> = ({ name, placeholder, value, setValue, disabled, description, max = 256, thin, type, dataName }) => { 23 - const className = `mt-1 ${max > 300 ? "h-28" : (thin ? "h-10" : "h-12")} ${thin && "relative bottom-1"} resize-none w-full dark:bg-wamellow bg-wamellow-100 rounded-md flex items-center px-4 py-2 focus:outline outline-violet-400 outline-2 ${disabled && "cursor-not-allowed opacity-50"}`; 23 + const className = `mt-1 ${max > 300 ? "h-28" : (thin ? "h-10" : "h-12")} ${thin && "relative bottom-1"} resize-none w-full dark:bg-wamellow bg-wamellow-100 rounded-md flex items-center px-4 py-2 focus:outline outline-violet-400 outline-2 ${disabled && "cursor-not-allowed opacity-50"}` as HTMLAttributes<HTMLInputElement>["className"]; 24 24 25 25 const [length, setLength] = useState(0); 26 26
+2 -1
components/messageCreator/Embed.tsx
··· 7 7 import Highlight from "../discord/Markdown"; 8 8 import DiscordMessage from "../discord/Message"; 9 9 import DiscordMessageEmbed from "../discord/MessageEmbed"; 10 + import DumbColorInput from "../inputs/Dumb_ColorInput"; 10 11 import DumbTextInput from "../inputs/Dumb_TextInput"; 11 12 12 13 interface Props { ··· 133 134 <DumbTextInput placeholder="Embed Title" value={embed} setValue={setEmbed} max={256} dataName="title" disabled={disabled} /> 134 135 <DumbTextInput placeholder="Embed Description" value={embed} setValue={setEmbed} max={4096} dataName="description" disabled={disabled} /> 135 136 <div className="flex gap-2"> 136 - <DumbTextInput placeholder="Embed Color" value={embed} setValue={setEmbed} type="color" dataName="color" disabled={disabled} /> 137 + <DumbColorInput placeholder="Embed Color" value={embed} setValue={setEmbed} dataName="color" disabled={disabled} /> 137 138 <DumbTextInput placeholder="Embed Thumbnail" value={embed} setValue={setEmbed} max={256} dataName="thumbnail" disabled={disabled} /> 138 139 </div> 139 140 <DumbTextInput placeholder="Embed Image" value={embed} setValue={setEmbed} max={256} dataName="image" disabled={disabled} />
+5
next.config.js
··· 24 24 port: "", 25 25 pathname: "/" 26 26 } 27 + ], 28 + domains: [ 29 + "cdn.discordapp.com", 30 + "cdn.waya.one", 31 + "imagerenderer.waya.one" 27 32 ] 28 33 } 29 34 };
+11
tailwind.config.js
··· 19 19 "wamellow-100-light": "#ced3da", 20 20 "wamellow-100-alpha": "rgba(0, 0, 0, 0.06)", 21 21 22 + "wamellow-200": "#cdd5e1", 23 + "wamellow-200-light": "#b4becb", 24 + "wamellow-200-alpha": "rgba(0, 0, 0, 0.12)", 25 + "wamellow-300-alpha": "rgba(0, 0, 0, 0.18)", 26 + "wamellow-400-alpha": "rgba(0, 0, 0, 0.24)", 27 + "wamellow-500-alpha": "rgba(0, 0, 0, 0.3)", 28 + "wamellow-600-alpha": "rgba(0, 0, 0, 0.36)", 29 + "wamellow-700-alpha": "rgba(0, 0, 0, 0.42)", 30 + "wamellow-800-alpha": "rgba(0, 0, 0, 0.48)", 31 + "wamellow-900-alpha": "rgba(0, 0, 0, 0.54)", 32 + 22 33 "blurple": "#5865f2", 23 34 "blurple-dark": "#454fbf", 24 35