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