Spaces:
Running
Running
import { forwardRef, useEffect, useRef, useState } from "react"; | |
import { BadgeType } from "@/types/badge"; | |
import { FONT_FAMILY } from "@/components/font-family/font-family.constants"; | |
import { RATIONAL_BADGE_WIDTH } from "../badge-editor.constants"; | |
import { Icons } from "@/components/svg/icons"; | |
import { IconItem } from "@/types/editor"; | |
import { BADGE_COMPONENTS } from "@/components/svg/badges"; | |
import classNames from "classnames"; | |
import { ShineEffect } from "./shine_effect"; | |
export const Badge = forwardRef( | |
( | |
{ | |
badge, | |
size = "medium", | |
}: { | |
badge: BadgeType; | |
size?: "medium" | "small"; | |
}, | |
ref | |
) => { | |
const textRef = useRef<any>(null); | |
const svgRef = useRef<any>(null); | |
const badgeContentRef = useRef<any>(null); | |
const [viewBox, setViewBox] = useState<string>("0 0 24 24"); | |
useEffect(() => { | |
if (!textRef.current) return; | |
if (!badgeContentRef.current) return; | |
const textWidth = textRef.current.getBoundingClientRect().width; | |
let newBadgeWidth = RATIONAL_BADGE_WIDTH; | |
if (textWidth > RATIONAL_BADGE_WIDTH) { | |
newBadgeWidth = Math.ceil(textWidth / 32) * 32; | |
} | |
if ( | |
(findShape?.autoResize || badge.type === "circle") && | |
newBadgeWidth - textWidth < (badge.type === "circle" ? 6 : 3) | |
) | |
newBadgeWidth += 32; | |
badgeContentRef.current.style.width = `${newBadgeWidth}px`; | |
}, [ | |
badge.text, | |
badge.fontFamily, | |
badge.letterSpacing, | |
badge.fontWeight, | |
badge.type, | |
badge?.icon?.component, | |
badge?.icon?.enabled, | |
badge?.icon?.position, | |
]); | |
const fontFamily = FONT_FAMILY?.find((f) => f.label === badge?.fontFamily); | |
const defaultStyle = { | |
letterSpacing: badge?.letterSpacing, | |
fontWeight: badge?.fontWeight, | |
}; | |
const findIcon = Icons?.find( | |
(i: IconItem) => badge?.icon?.component === i.name | |
); | |
const findShape = BADGE_COMPONENTS?.find( | |
(b: any) => b.name === badge?.type | |
); | |
useEffect(() => { | |
return setViewBox( | |
svgRef?.current?.getAttribute("viewBox") ?? "0 0 200 200" | |
); | |
}, [badge?.icon]); | |
const IconComponent = findIcon?.component as any; | |
const ShapeComponent = findShape?.component as any; | |
return ( | |
<div | |
id={size === "medium" ? "discotools-selected-badge" : ""} | |
ref={ref as any} | |
className="max-w-max flex items-center h-[32px] justify-center relative" | |
> | |
{findShape?.component && ( | |
<ShapeComponent.left color={badge?.stringColor ?? badge?.colour} /> | |
)} | |
{badge?.shinyEffect && ( | |
<> | |
<ShineEffect className="absolute left-[6px] -bottom-[0px] z-1" /> | |
<ShineEffect className="absolute right-[6px] -top-[0px] z-1" /> | |
</> | |
)} | |
<div | |
className="whitespace-nowrap text-white font-bold flex text-[18px] h-[28px] items-center justify-center text-center transition-all duration-200 relative" | |
ref={badgeContentRef} | |
style={{ | |
background: badge?.stringColor ?? badge?.colour, | |
borderRadius: badge.type !== "circle" ? 0 : badge?.radius ?? 0, | |
}} | |
> | |
<div | |
ref={textRef as any} | |
className="flex items-center justify-center gap-2" | |
> | |
{badge?.icon?.enabled && | |
badge?.icon?.position?.includes("left") && | |
findIcon?.component && | |
badge?.icon?.component && ( | |
<svg | |
width={16} | |
height={16} | |
fill={badge?.icon?.colour} | |
viewBox={viewBox} | |
style={{ minWidth: 16, minHeight: 16 }} | |
> | |
<IconComponent ref={svgRef as any} /> | |
</svg> | |
)} | |
{badge?.text?.value && ( | |
<p | |
className={`!bg-clip-text text-transparent ${fontFamily?.value}`} | |
style={ | |
badge?.text?.gradient?.enabled | |
? { | |
backgroundImage: | |
badge?.text?.stringColor ?? badge?.text?.colour, | |
...defaultStyle, | |
} | |
: { | |
backgroundColor: | |
badge?.text?.stringColor ?? badge?.text?.colour, | |
...defaultStyle, | |
} | |
} | |
> | |
{badge?.text?.value} | |
</p> | |
)} | |
{badge?.icon?.enabled && | |
badge?.icon?.position?.includes("right") && | |
findIcon?.component && | |
badge?.icon?.component && ( | |
<svg | |
width={16} | |
height={16} | |
fill={badge?.icon?.colour} | |
viewBox={viewBox} | |
style={{ minWidth: 16, minHeight: 16 }} | |
> | |
<IconComponent ref={svgRef as any} /> | |
</svg> | |
)} | |
</div> | |
</div> | |
{findShape?.component && ( | |
<ShapeComponent.right color={badge?.stringColor ?? badge?.colour} /> | |
)} | |
</div> | |
); | |
} | |
); | |