Spaces:
Running
Running
import { useContext, useState } from "react"; | |
import Image from "next/image"; | |
import { useTour } from "@reactour/tour"; | |
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | |
import { faDownload } from "@fortawesome/free-solid-svg-icons"; | |
import saveAsPng from "save-svg-as-png"; | |
import { EditorType, IconItem } from "types/editor"; | |
import { Icon } from "./icon"; | |
import { EditorTabs } from "components/editor-icons/comps/tabs"; | |
import { ListIcons } from "components/editor-icons/comps/list"; | |
import { Search } from "components/search"; | |
import { ClydeMessage } from "components/clyde/message"; | |
import { Switch } from "components/switch"; | |
import { Shapes } from "@/components/editor-icons/comps/shapes"; | |
import { Icons } from "components/editor-icons/comps/icons"; | |
import { useUser } from "utils/auth"; | |
import { PremiumContext } from "components/premium/premium"; | |
import DefaultAvatar from "assets/images/avatars/default-avatar.svg"; | |
import DefaultAvatar2 from "assets/images/avatars/default-avatar-2.svg"; | |
import BackgroundTransparent from "assets/images/editor/transparent_bg.svg"; | |
import { API } from "@/utils/api"; | |
import { Premium } from "../premium"; | |
import { FormattedMessage, useIntl } from "react-intl"; | |
export default function Editor({ | |
editor, | |
onChange, | |
}: { | |
editor: EditorType; | |
onChange: (e: EditorType) => void; | |
}) { | |
const intl = useIntl(); | |
const { user } = useUser(); | |
const { setOpen } = useContext(PremiumContext); | |
const { setIsOpen } = useTour(); | |
const [currentTab, setCurrentTab] = useState(0); | |
const [multiIcons, setMultiIcons] = useState(false); | |
const [search, setSearch] = useState(""); | |
const renderTabs = (currentTab: number) => { | |
switch (currentTab) { | |
case 0: | |
return ( | |
<> | |
<Search search={search} setSearch={setSearch} /> | |
<div className="flex items-center justify-start gap-2 mt-4 lg:mt-3 mb-5"> | |
<Switch | |
value={multiIcons} | |
size="small" | |
onChange={!user?.id ? () => setOpen(true) : setMultiIcons} | |
/> | |
<p className="text-dark-100 text-sm font-semibold tracking-wider select-none flex items-center justify-start gap-2"> | |
<FormattedMessage id="iconsEditor.editor.listIcons.multiIcons" /> | |
{/* {!user?.id ? <Premium tooltip={false} /> : ""} */} | |
</p> | |
</div> | |
<ListIcons | |
onCustomText={() => { | |
// if (!user?.id) return setOpen(true); | |
onChange({ | |
...editor, | |
icons: multiIcons | |
? [ | |
...editor.icons, | |
{ | |
colour: "#ffffff", | |
custom_text: { | |
enabled: true, | |
text: "10", | |
size: 160, | |
}, | |
}, | |
] | |
: [ | |
{ | |
...editor?.icons[0], | |
component: undefined, | |
position: undefined, | |
colour: "#ffffff", | |
custom_text: { | |
enabled: true, | |
text: "10", | |
size: 160, | |
}, | |
}, | |
], | |
}); | |
if (!multiIcons) setCurrentTab(2); | |
}} | |
onCustomUpload={(image) => { | |
onChange({ | |
...editor, | |
icons: multiIcons | |
? [ | |
...editor.icons, | |
{ | |
colour: "#ffffff", | |
image, | |
}, | |
] | |
: [ | |
{ | |
...editor?.icons[0], | |
custom_text: undefined, | |
component: undefined, | |
position: undefined, | |
colour: "#ffffff", | |
image, | |
}, | |
], | |
}); | |
if (!multiIcons) setCurrentTab(2); | |
}} | |
onSelect={(icon: IconItem) => { | |
onChange({ | |
...editor, | |
icons: multiIcons | |
? [ | |
...editor.icons, | |
{ | |
component: icon.name, | |
colour: icon?.defaultColor ?? "#fff", | |
}, | |
] | |
: [ | |
{ | |
...editor?.icons[0], | |
colour: icon?.defaultColor ?? "#fff", | |
component: icon.name, | |
position: undefined, | |
custom_text: undefined, | |
}, | |
], | |
}); | |
}} | |
/> | |
</> | |
); | |
case 1: | |
return ( | |
<> | |
<Shapes | |
editor={editor} | |
onChange={(newShape: any) => | |
onChange({ ...editor, shape: { ...editor.shape, ...newShape } }) | |
} | |
/> | |
</> | |
); | |
case 2: | |
return ( | |
<> | |
<Icons | |
editor={editor} | |
onChange={onChange} | |
onStep={(tabIndex: number, allowMultiple?: boolean) => { | |
setCurrentTab(tabIndex); | |
setMultiIcons(user?.id ? allowMultiple || false : false); | |
}} | |
/> | |
</> | |
); | |
default: | |
return null; | |
} | |
}; | |
const handleSaveIcon = () => { | |
const svg = document.getElementById("discotools-selected-svg"); | |
saveAsPng.saveSvgAsPng(svg, "discotools-xyz-icon.png", { | |
scale: 1.25, | |
encoderOptions: 1, | |
}); | |
// API.download(); | |
}; | |
const previewAvatar = () => { | |
if (user?.id) { | |
if (user?.avatar) | |
return `https://cdn.discordapp.com/avatars/${user?.id}/${user?.avatar}.png`; | |
else | |
return `https://cdn.discordapp.com/embed/avatars/${ | |
user.discriminator % 5 | |
}.png`; | |
} | |
return DefaultAvatar.src; | |
}; | |
const renderColor = () => { | |
if (editor?.shape?.gradient?.enabled) { | |
const color = editor?.shape?.gradient?.colours?.[0]?.value; | |
if (color.includes("rgba")) { | |
const rgba = color?.split(","); | |
return `rgb(${rgba[0].split("(")[1]}, ${rgba[1]}, ${rgba[2]})`; | |
} | |
return color; | |
} | |
if (editor?.shape?.colour?.includes("rgba")) { | |
const rgba = editor?.shape?.colour?.split(","); | |
return `rgb(${rgba[0].split("(")[1]}, ${rgba[1]}, ${rgba[2]})`; | |
} | |
if (editor?.shape?.colour) { | |
return editor.shape.colour; | |
} | |
return "#fff"; | |
}; | |
return ( | |
<div className="relative mt-20 max-w-6xl mx-auto z-1"> | |
<ClydeMessage | |
message={intl.formatMessage({ id: "helper.title" })} | |
auto | |
onClick={() => setIsOpen(true)} | |
/> | |
<div | |
className="bg-dark-500 shadow-lg grid grid-cols-1 lg:grid-cols-5 rounded-2xl lg:max-h-[700px] lg:h-[700px]" | |
onClick={(e) => { | |
// e.preventDefault(); | |
// e.stopPropagation(); | |
}} | |
> | |
<div className="lg:col-span-3 flex flex-col justify-start overflow-hidden"> | |
<EditorTabs current={currentTab} onChange={setCurrentTab} /> | |
<div className="px-6 pb-6 pt-4 w-full overflow-y-auto h-full"> | |
{renderTabs(currentTab)} | |
</div> | |
</div> | |
<div className="bg-dark-500 rounded-b-2xl lg:rounded-r-2xl col-span-2 flex flex-col flex-1 h-full"> | |
<header | |
className="relative p-5 lg:p-8 flex items-center lg:rounded-tr-2xl justify-center bg-repeat h-[300px] w-full z-10 transition-all duration-200 first-step" | |
style={{ | |
backgroundImage: `url(${BackgroundTransparent.src})`, | |
}} | |
> | |
<Icon | |
editor={editor} | |
id="discotools-selected-svg" | |
onChange={onChange} | |
onChangeTab={(i: number) => setCurrentTab(i)} | |
/> | |
</header> | |
<main className="lg:border-l border-dark-300 flex flex-1 flex-col px-5 py-6 justify-between gap-6"> | |
<div> | |
<div className="grid grid-cols-1 gap-5"> | |
<div className="flex items-start gap-3 justify-start"> | |
<img | |
src={previewAvatar()} | |
width={32} | |
height={32} | |
alt="Default Avatar for user" | |
className="rounded-full object-cover w-10 h-10" | |
/> | |
<div className="text-left"> | |
<div className="flex items-center justify-start gap-1"> | |
<p | |
className="font-semibold text-base" | |
style={{ color: renderColor() }} | |
> | |
Captain Astro | |
</p> | |
<Icon size={24} editor={editor} /> | |
<p className="text-white text-opacity-50 text-[10px]"> | |
Today at 11:23 pm | |
</p> | |
</div> | |
<p className="text-white text-opacity-60 text-sm mt-0.5"> | |
<FormattedMessage id="iconsEdtior.editor.preview.text1" /> | |
</p> | |
</div> | |
</div> | |
<div className="flex items-start gap-3 justify-start"> | |
<Image | |
src={DefaultAvatar2} | |
width={32} | |
height={32} | |
alt="Second user without custom roles icons" | |
className="rounded-full object-cover w-10 h-10" | |
/> | |
<div className="text-left"> | |
<div className="flex items-center justify-start gap-1"> | |
<p className="font-semibold text-base text-white"> | |
Rookie | |
</p> | |
<p className="text-white text-opacity-50 text-[10px] ml-1"> | |
Today at 11:23 pm | |
</p> | |
</div> | |
<p className="text-white text-opacity-60 text-sm mt-0.5"> | |
<FormattedMessage | |
id="iconsEdtior.editor.preview.text2" | |
values={{ | |
user: (t) => user?.username ?? "Captain Astro", | |
}} | |
/> | |
</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<button | |
className="text-white font-medium bg-blue hover:bg-blue tracking-wide text-base px-5 py-2.5 rounded justify-center flex items-center gap-2" | |
onClick={handleSaveIcon} | |
> | |
<FontAwesomeIcon icon={faDownload} className="w-4" /> | |
<FormattedMessage id="iconsEdtior.editor.preview.download" /> | |
</button> | |
</main> | |
</div> | |
</div> | |
</div> | |
); | |
} | |