Spaces:
Running
Running
| import { Fragment, useRef, useState } from "react"; | |
| import { useMount, useUpdateEffect } from "react-use"; | |
| import { motion } from "framer-motion"; | |
| import saveAsPng from "save-svg-as-png"; | |
| import { EditorType, IconItem } from "types/editor"; | |
| import Shapes from "@/components/svg/shapes"; | |
| import { Icons } from "components/svg/icons"; | |
| import { Null } from "components/svg/shapes/null"; | |
| export const Icon = ({ | |
| editor, | |
| size = 200, | |
| id, | |
| onChange, | |
| onChangeTab, | |
| }: { | |
| editor: EditorType; | |
| id?: string; | |
| size?: number; | |
| onChange?: (e: EditorType) => void; | |
| onChangeTab?: (e: number) => void; | |
| }) => { | |
| const shapeRef = useRef<any>(null); | |
| const ComponentShape = | |
| Shapes[editor.shape?.component as keyof typeof Shapes] ?? Null; | |
| return ( | |
| <ComponentShape | |
| ref={shapeRef} | |
| width={size} | |
| height={size} | |
| shape={editor.shape} | |
| id={id} | |
| > | |
| {editor?.icons?.map((icon, k) => { | |
| const findIcon = Icons?.find( | |
| (i: IconItem) => icon.component === i.name | |
| ); | |
| const customText = icon?.custom_text?.enabled; | |
| const customImage = icon?.image; | |
| const GradientType = | |
| icon?.gradient?.type === "radialGradient" | |
| ? "radialGradient" | |
| : "linearGradient"; | |
| if (!findIcon && !customText && !customImage) return null; | |
| return ( | |
| <Fragment key={k}> | |
| <defs> | |
| <GradientType | |
| id={`icon-gradient-${k}`} | |
| gradientTransform={`rotate(${icon?.gradient?.angle ?? "90"})`} | |
| > | |
| {icon?.gradient?.enabled ? ( | |
| <> | |
| {icon?.gradient?.colours?.map((color, c) => ( | |
| <stop | |
| key={c} | |
| offset={`${color.left}%`} | |
| stopColor={ | |
| editor?.shape?.transparency ? "#000" : color.value | |
| } | |
| /> | |
| ))} | |
| </> | |
| ) : ( | |
| <stop | |
| offset="0%" | |
| stopColor={ | |
| editor?.shape?.transparency ? "#000" : icon.colour | |
| } | |
| /> | |
| )} | |
| </GradientType> | |
| </defs> | |
| <_IconComponent | |
| component={findIcon?.component} | |
| shapeRef={shapeRef} | |
| shape={editor?.shape?.component} | |
| key={k} | |
| index={k} | |
| icon={icon} | |
| onChange={(e: any) => | |
| onChange && | |
| onChange({ | |
| ...editor, | |
| icons: editor.icons.map((i: any, index: number) => | |
| index === k ? e : i | |
| ), | |
| }) | |
| } | |
| onClick={onChangeTab ? () => onChangeTab(2) : undefined} | |
| /> | |
| </Fragment> | |
| ); | |
| })} | |
| </ComponentShape> | |
| ); | |
| }; | |
| const _IconComponent = ({ | |
| shapeRef, | |
| component, | |
| icon, | |
| shape, | |
| index, | |
| onChange, | |
| ...props | |
| }: any) => { | |
| const iconRef = useRef<any>(null); | |
| const [position, setPosition] = useState<any>(null); | |
| useUpdateEffect(() => { | |
| const position = setIconPosition(iconRef, shapeRef); | |
| setPosition(position); | |
| const svg = document.getElementById("discotools-selected-svg"); | |
| saveAsPng.svgAsPngUri(svg).then(() => {}); | |
| }, [shapeRef.current, icon.component, icon?.image]); | |
| useMount(() => { | |
| const position = setIconPosition(iconRef, shapeRef); | |
| setPosition(position); | |
| }); | |
| useUpdateEffect(() => { | |
| onChange({ | |
| ...icon, | |
| position, | |
| }); | |
| }, [position]); | |
| const IconComponent = component as any; | |
| return ( | |
| <motion.g | |
| animate={{ | |
| x: icon?.position?.x ?? position?.x ?? 0, | |
| y: icon?.position?.y ?? position?.y ?? 0, | |
| scale: icon?.position?.scale ?? 1, | |
| rotate: icon?.position?.angle ?? 0, | |
| originX: 0.5, | |
| filter: | |
| icon?.shadow?.enabled && | |
| `drop-shadow(${icon?.shadow?.position?.x}px ${icon?.shadow?.position?.y}px ${icon?.shadow?.position?.blur}px ${icon?.shadow?.colour})`, | |
| }} | |
| fill={`url(#${`icon-gradient-${index}`})`} | |
| stroke={icon?.border?.colour} | |
| strokeLinejoin="round" | |
| strokeWidth={icon?.border?.width} | |
| style={{ | |
| transformOrigin: "center", | |
| // filter: `drop-shadow(${icon?.shadow?.position?.x}px ${icon?.shadow?.position?.y}px ${icon?.shadow?.position?.blur}px ${icon?.shadow?.colour})`, | |
| }} | |
| > | |
| {icon?.custom_text?.enabled ? ( | |
| <text | |
| ref={iconRef as any} | |
| style={{ | |
| fontSize: icon?.custom_text?.size | |
| ? `${icon?.custom_text?.size}px` | |
| : "100px", | |
| fontWeight: 900, | |
| }} | |
| className="font-title" | |
| viewBox="0 0 200 -100" | |
| > | |
| {icon?.custom_text?.text} | |
| </text> | |
| ) : icon?.image ? ( | |
| <image | |
| ref={iconRef as any} | |
| href={icon?.image} | |
| width={190} | |
| height={190} | |
| viewBox="0 0 190 190" | |
| preserveAspectRatio="xMidYMid slice" | |
| /> | |
| ) : ( | |
| <IconComponent ref={iconRef} {...props} /> | |
| )} | |
| </motion.g> | |
| ); | |
| }; | |
| const setIconPosition = (iconRef: any, shapeRef: any) => { | |
| if (iconRef?.current) { | |
| const shapeBoxW = shapeRef?.current?.getAttribute("viewBox")?.split(" ")[2]; | |
| const shapeBoxH = shapeRef?.current?.getAttribute("viewBox")?.split(" ")[3]; | |
| const iconBoxW = iconRef?.current?.getAttribute("viewBox")?.split(" ")[2]; | |
| const iconBoxH = iconRef?.current?.getAttribute("viewBox")?.split(" ")[3]; | |
| const position = { | |
| x: shapeBoxW / 2 - iconBoxW / 2, | |
| y: shapeBoxH / 2 - iconBoxH / 2, | |
| xPath: Number(shapeBoxW - iconBoxW), | |
| yPath: Number(shapeBoxH - iconBoxH), | |
| }; | |
| return position; | |
| } | |
| }; | |