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; | |
} | |
}; | |