Browse Source

Ajoute les badges

master
vincent 1 month ago
parent
commit
f69093cc00
2 changed files with 137 additions and 0 deletions
  1. +134
    -0
      src/Controller/BadgeController.php
  2. +3
    -0
      templates/partials/_project-metadata.html.twig

+ 134
- 0
src/Controller/BadgeController.php View File

@ -0,0 +1,134 @@
<?php
namespace App\Controller;
use App\Entity\Project;
use App\Entity\Task;
use App\Service\TaskLifecycleManager;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Attribute\Route;
#[Route('/badge')]
class BadgeController extends AbstractController
{
#[Route('/project-status/{projectSlug}/{status}', name: 'app_badge_project_status')]
public function index(EntityManagerInterface $entityManager, TaskLifecycleManager $taskLifecycleManager, string $projectSlug, string $status): Response
{
$project = $entityManager->getRepository(Project::class)->findOneBySlug($projectSlug);
if (!$project) {
throw new NotFoundHttpException('Project not found');
}
$stats = $taskLifecycleManager->getProjectStats($project);
if (!isset($stats[$status])) {
throw new NotFoundHttpException('Status not found');
}
$stats = $stats[$status];
$response = new StreamedResponse();
$response->headers->set('Content-Type', 'image/svg+xml');
$response->headers->set('Cache-Control', 'public, max-age=300');
$response->setCallback(function () use ($stats): void {
$colors = [
'primary' => '#0d6efd', // $blue;
'secondary' => '#6c757d', // $gray-600;
'success' => '#198754', // $green;
'info' => '#0dcaf0', // $cyan;
'warning' => '#ffc107', // $yellow;
'danger' => '#dc3545', // $red;
];
$xml = new \DOMDocument();
$left = $stats['title'];
$leftColor = $colors['secondary'];
$right = sprintf(' % 3.0f%%', $stats['percentage']);
$rightColor = $colors[$stats['color']];
$charWidth = 7;
$fontSize = 11;
$totalHeight = 20;
$radius = ceil($totalHeight / $charWidth);
$verticalMargin = round(($totalHeight - $fontSize) / 2);
$horizontalMargin = round($fontSize / 3);
$totalWidth = round(strlen($left.$right) * $charWidth + 2 * $horizontalMargin);
$middle = floor(strlen($left) * $charWidth);
$svg = $xml->createElement('svg');
$svg->setAttributeNS('http://www.w3.org/2000/xmlns/','xmlns', 'http://www.w3.org/2000/svg');
$svg->setAttribute('width', $totalWidth);
$svg->setAttribute('height', $totalHeight);
$defs = $xml->createElement('defs');
$gradientId = 'a';
$gradient = $xml->createElement('linearGradient');
$gradient->setAttribute('id', $gradientId);
$stop = $xml->createElement('stop');
$stop->setAttribute('offset', ($middle * 100 / $totalWidth).'%');
$stop->setAttribute('stop-color', $leftColor);
$gradient->appendChild($stop);
$stop = $xml->createElement('stop');
$stop->setAttribute('offset', ($middle * 100 / $totalWidth).'%');
$stop->setAttribute('stop-color', $rightColor);
$gradient->appendChild($stop);
$defs->appendChild($gradient);
$svg->appendChild($defs);
$rect = $xml->createElement('rect');
$rect->setAttribute('width', $totalWidth);
$rect->setAttribute('height', $totalHeight);
$rect->setAttribute('rx', $radius);
$rect->setAttribute('style', sprintf('fill:url(#%s)', $gradientId));
$svg->appendChild($rect);
$fontG = $xml->createElement('g');
$fontG->setAttribute('font-family', implode(',', ['DejaVu Sans', 'Verdana', 'Geneva', 'sans-serif']));
$fontG->setAttribute('font-size', $fontSize);
$leftText = $xml->createElement('text', $left);
$leftText->setAttribute('x', $horizontalMargin);
$leftText->setAttribute('y', $totalHeight - $verticalMargin);
$leftText->setAttribute('fill', '#000');
$fontG->appendChild($leftText);
$leftText = $xml->createElement('text', $left);
$leftText->setAttribute('x', $horizontalMargin);
$leftText->setAttribute('y', $totalHeight - $verticalMargin - 1);
$leftText->setAttribute('fill', '#fff');
$fontG->appendChild($leftText);
$rightText = $xml->createElement('text', $right);
$rightText->setAttribute('x', $totalWidth - $horizontalMargin);
$rightText->setAttribute('y', $totalHeight - $verticalMargin);
$rightText->setAttribute('style', 'text-anchor:end;fill:#000');
$fontG->appendChild($rightText);
$rightText = $xml->createElement('text', $right);
$rightText->setAttribute('x', $totalWidth - $horizontalMargin);
$rightText->setAttribute('y', $totalHeight - $verticalMargin - 1);
$rightText->setAttribute('style', 'text-anchor:end;fill:#fff');
$fontG->appendChild($rightText);
$svg->appendChild($fontG);
$xml->appendChild($svg);
echo $xml->saveXML();
});
return $response;
}
}

+ 3
- 0
templates/partials/_project-metadata.html.twig View File

@ -10,3 +10,6 @@
</svg>
{{ project.createdAt|format_datetime('short', 'short', locale='fr') }}
</span>
<span class="me-2">
<img src="{{ path('app_badge_project_status', {'projectSlug': project.slug, 'status': 'done'}) }}" />
</span>

Loading…
Cancel
Save