added project detail report (#2651)
- avatars via css only - random colors for entities - improves print view - added colors for teams - added color to tag
This commit is contained in:
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Twig;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Utils\AvatarService;
|
||||
use Symfony\Component\Asset\Packages;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
class AvatarExtension extends AbstractExtension
|
||||
{
|
||||
/**
|
||||
* @var AvatarService
|
||||
*/
|
||||
private $avatar;
|
||||
/**
|
||||
* @var Packages
|
||||
*/
|
||||
private $packages;
|
||||
|
||||
public function __construct(AvatarService $avatar, Packages $packages)
|
||||
{
|
||||
$this->avatar = $avatar;
|
||||
$this->packages = $packages;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFunctions()
|
||||
{
|
||||
return [
|
||||
new TwigFunction('avatar', [$this, 'getAvatarUrl']),
|
||||
];
|
||||
}
|
||||
|
||||
public function getAvatarUrl(?User $profile, string $default): string
|
||||
{
|
||||
if (null === $profile) {
|
||||
return $this->packages->getUrl($default);
|
||||
}
|
||||
|
||||
$url = $this->avatar->getAvatar($profile);
|
||||
|
||||
if (null === $url) {
|
||||
return $this->packages->getUrl($default);
|
||||
}
|
||||
|
||||
return $this->packages->getUrl($url, 'avatars');
|
||||
}
|
||||
}
|
||||
67
src/Twig/Configuration.php
Normal file
67
src/Twig/Configuration.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Twig;
|
||||
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
final class Configuration extends AbstractExtension
|
||||
{
|
||||
private $configuration;
|
||||
private $cache = [];
|
||||
|
||||
public function __construct(SystemConfiguration $configuration)
|
||||
{
|
||||
$this->configuration = $configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFunctions()
|
||||
{
|
||||
return [
|
||||
new TwigFunction('config', [$this, 'get']),
|
||||
];
|
||||
}
|
||||
|
||||
public function get(string $name)
|
||||
{
|
||||
if (\array_key_exists($name, $this->cache)) {
|
||||
return $this->cache[$name];
|
||||
}
|
||||
|
||||
$value = $this->configuration->find($name);
|
||||
$this->cache[$name] = $value;
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
if (\array_key_exists($name, $this->cache)) {
|
||||
return $this->cache[$name];
|
||||
}
|
||||
|
||||
$checks = ['is' . $name, 'get' . $name, 'has' . $name, $name];
|
||||
|
||||
foreach ($checks as $methodName) {
|
||||
if (method_exists($this->configuration, $methodName)) {
|
||||
$value = \call_user_func([$this->configuration, $methodName], $arguments);
|
||||
$this->cache[$name] = $value;
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->configuration->find($name);
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ class Extensions extends AbstractExtension
|
||||
new TwigFilter('multiline_indent', [$this, 'multilineIndent']),
|
||||
new TwigFilter('color', [$this, 'color']),
|
||||
new TwigFilter('font_contrast', [$this, 'calculateFontContrastColor']),
|
||||
new TwigFilter('default_color', [$this, 'defaultColor']),
|
||||
new TwigFilter('nl2str', [$this, 'replaceNewline'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
|
||||
];
|
||||
}
|
||||
@@ -43,6 +44,7 @@ class Extensions extends AbstractExtension
|
||||
return [
|
||||
new TwigFunction('class_name', [$this, 'getClassName']),
|
||||
new TwigFunction('iso_day_by_name', [$this, 'getIsoDayByName']),
|
||||
new TwigFunction('random_color', [$this, 'randomColor']),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -71,11 +73,21 @@ class Extensions extends AbstractExtension
|
||||
return (new Color())->getColor($entity, $defaultColor);
|
||||
}
|
||||
|
||||
public function randomColor(?string $input = null): string
|
||||
{
|
||||
return (new Color())->getRandom($input);
|
||||
}
|
||||
|
||||
public function calculateFontContrastColor(string $color): string
|
||||
{
|
||||
return (new Color())->getFontContrastColor($color);
|
||||
}
|
||||
|
||||
public function defaultColor(?string $color = null): string
|
||||
{
|
||||
return $color ?? Constants::DEFAULT_COLOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $object
|
||||
* @return null|string
|
||||
|
||||
@@ -59,6 +59,7 @@ final class LocaleFormatExtensions extends AbstractExtension
|
||||
new TwigFilter('time', [$this, 'time']),
|
||||
new TwigFilter('hour24', [$this, 'hour24']),
|
||||
new TwigFilter('duration', [$this, 'duration']),
|
||||
new TwigFilter('chart_duration', [$this, 'durationChart']),
|
||||
new TwigFilter('duration_decimal', [$this, 'durationDecimal']),
|
||||
new TwigFilter('money', [$this, 'money']),
|
||||
new TwigFilter('currency', [$this, 'currency']),
|
||||
@@ -91,6 +92,7 @@ final class LocaleFormatExtensions extends AbstractExtension
|
||||
new TwigFunction('get_format_duration', [$this, 'getDurationFormat']),
|
||||
new TwigFunction('create_date', [$this, 'createDate']),
|
||||
new TwigFunction('locales', [$this, 'getLocales']),
|
||||
new TwigFunction('month_names', [$this, 'getMonthNames']),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -187,6 +189,25 @@ final class LocaleFormatExtensions extends AbstractExtension
|
||||
return $this->getFormatter()->time($date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $year
|
||||
* @return string[]
|
||||
*/
|
||||
public function getMonthNames(?string $year = null): array
|
||||
{
|
||||
$withYear = true;
|
||||
if ($year === null) {
|
||||
$year = date('Y');
|
||||
$withYear = false;
|
||||
}
|
||||
$months = [];
|
||||
for ($i = 1; $i < 13; $i++) {
|
||||
$months[] = $this->getFormatter()->monthName(new DateTime(sprintf('%s-%s-10', $year, ($i < 10 ? '0' . $i : (string) $i))), $withYear);
|
||||
}
|
||||
|
||||
return $months;
|
||||
}
|
||||
|
||||
public function monthName(\DateTime $dateTime, bool $withYear = false): string
|
||||
{
|
||||
return $this->getFormatter()->monthName($dateTime, $withYear);
|
||||
@@ -235,6 +256,11 @@ final class LocaleFormatExtensions extends AbstractExtension
|
||||
return $this->getFormatter()->durationDecimal($duration);
|
||||
}
|
||||
|
||||
public function durationChart($duration): string
|
||||
{
|
||||
return number_format(($duration / 3600), 2, '.', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|float $amount
|
||||
* @return bool|false|string
|
||||
|
||||
@@ -15,6 +15,7 @@ use App\Entity\User;
|
||||
use App\Event\PageActionsEvent;
|
||||
use App\Event\ThemeEvent;
|
||||
use App\Event\ThemeJavascriptTranslationsEvent;
|
||||
use App\Utils\Color;
|
||||
use Symfony\Bridge\Twig\AppVariable;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
@@ -26,6 +27,10 @@ final class ThemeExtension implements RuntimeExtensionInterface
|
||||
private $eventDispatcher;
|
||||
private $translator;
|
||||
private $configuration;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $randomColors;
|
||||
|
||||
public function __construct(EventDispatcherInterface $dispatcher, TranslatorInterface $translator, SystemConfiguration $configuration)
|
||||
{
|
||||
@@ -135,4 +140,25 @@ final class ThemeExtension implements RuntimeExtensionInterface
|
||||
|
||||
return $this->configuration->find($name);
|
||||
}
|
||||
|
||||
public function colorize(?string $color, ?string $identifier = null, ?string $fallback = null): string
|
||||
{
|
||||
if ($color !== null) {
|
||||
return $color;
|
||||
}
|
||||
|
||||
if ($this->randomColors === null) {
|
||||
$this->randomColors = $this->configuration->isThemeRandomColors();
|
||||
}
|
||||
|
||||
if ($this->randomColors) {
|
||||
return (new Color())->getRandom($identifier);
|
||||
}
|
||||
|
||||
if ($fallback !== null) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
return Constants::DEFAULT_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ class RuntimeExtensions extends AbstractExtension
|
||||
new TwigFilter('desc2html', [MarkdownExtension::class, 'timesheetContent'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
|
||||
new TwigFilter('comment2html', [MarkdownExtension::class, 'commentContent'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
|
||||
new TwigFilter('comment1line', [MarkdownExtension::class, 'commentOneLiner'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
|
||||
new TwigFilter('colorize', [ThemeExtension::class, 'colorize']),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user