Files
pcm-badge-bundle/src/Twig/Component/Badge.php
T
2026-04-30 15:28:01 +01:00

102 lines
3.8 KiB
PHP

<?php
declare(strict_types=1);
namespace Pcm\BadgeBundle\Twig\Component;
use Pcm\BadgeBundle\Enum\BadgeColour;
use Pcm\BadgeBundle\Interface\BadgeableInterface;
use Symfony\UX\Icons\Registry\IconifyOnDemandRegistry;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use TailwindMerge\TailwindMerge;
#[AsTwigComponent(name: 'Pcm:Badge', template: '@PcmBadge/Badge.html.twig')]
final class Badge
{
public string $finalClasses;
public ?string $label = null;
public ?string $icon = null;
public function __construct(private string $baseClasses)
{
}
/**
* @param ?BadgeableInterface $obj The object to be converted into a badge
* @param ?string $class Extra classes to add to the badge element.
* These will override the base classes in case
* of conflicts.
* @param ?string $colour Manually specify the colour of a badge
* @param bool $outline Whether the badge should be rendered with an outline
* @param ?string $icon
*/
public function mount(?BadgeableInterface $obj = null, ?string $class = null, ?string $colour = null, ?string $label = null, bool $outline = false, ?string $icon = null, bool $glossy = false): void
{
if (!$icon) {
$this->icon = null;
} else if ("1" === $icon) {
if (null === $obj) {
throw new \RuntimeException("Missing icon name.");
}
$this->icon = $obj->getBadgeIcon();
if (null === $this->icon) {
throw new \RuntimeException("Missing icon name.");
}
} else {
$this->icon = $icon;
}
$this->label = $label;
if (!$obj && !$colour) {
throw new \RuntimeException(sprintf('You must specify either a colour an instance of "%s".', BadgeableInterface::class));
}
if ($obj && $colour) {
throw new \RuntimeException(sprintf('You have specified both the colour "%s" and an instance of "%s". Please use one or the other.', $colour, $obj::class));
}
if ($obj) {
$palette = $obj->getBadgeColour()->getPalette();
}
if ($colour) {
$cases = array_map(fn (BadgeColour $b) => strtolower($b->name), BadgeColour::cases());
if (!in_array($colour, $cases)) {
$formattedCases = implode(', ', array_map(fn (string $s) => '"'.$s.'"', $cases));
throw new \RuntimeException(sprintf('"%s" is not a valid badge colour. Available options are: %s.', $colour, $formattedCases));
}
$colour = strtoupper($colour);
$palette = BadgeColour::{$colour}->getPalette();
}
$merger = TailwindMerge::instance();
if (true === $outline) {
$glossyClass = $glossy
? 'bg-[image:radial-gradient(ellipse_at_top_left,color-mix(in_srgb,currentColor_5%,transparent),transparent_65%),linear-gradient(to_bottom,transparent,color-mix(in_srgb,currentColor_4%,transparent))]'
: '';
$classes = sprintf('bg-white %s/50 %s %s %s %s', $palette->borderColourClass, $palette->textColourClass, $glossyClass, $this->baseClasses, $class);
} else {
$glossyClass = $glossy
? 'bg-[image:radial-gradient(ellipse_at_top_left,rgba(255,255,255,0.25),transparent_65%),linear-gradient(to_bottom,rgba(255,255,255,0.05),rgba(0,0,0,0.12))]'
: '';
$classes = sprintf('text-white border-transparent %s %s %s %s', $palette->backgroundColourClass, $glossyClass, $this->baseClasses, $class);
}
if ($this->icon !== null) {
$classes = sprintf("flex gap-1 items-center %s", $classes);
}
$this->finalClasses = $merger->merge(trim($classes));
}
}