1
0
Fork 0
mirror of https://github.com/wallabag/wallabag.git synced 2025-08-11 17:51:02 +00:00

Add display article configurator (font family, font size, line height and max width)

This commit is contained in:
Nicolas Lœuillet 2023-07-29 12:26:44 +02:00
parent 0e44035b67
commit b1752b619d
71 changed files with 1457 additions and 170 deletions

View file

@ -11,6 +11,7 @@ use JMS\Serializer\SerializerBuilder;
use PragmaRX\Recovery\Recovery as BackupCodes;
use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
@ -25,6 +26,7 @@ use Wallabag\CoreBundle\Entity\Config as ConfigEntity;
use Wallabag\CoreBundle\Entity\IgnoreOriginUserRule;
use Wallabag\CoreBundle\Entity\RuleInterface;
use Wallabag\CoreBundle\Entity\TaggingRule;
use Wallabag\CoreBundle\Event\ConfigUpdatedEvent;
use Wallabag\CoreBundle\Form\Type\ChangePasswordType;
use Wallabag\CoreBundle\Form\Type\ConfigType;
use Wallabag\CoreBundle\Form\Type\FeedType;
@ -48,15 +50,24 @@ class ConfigController extends AbstractController
private TagRepository $tagRepository;
private AnnotationRepository $annotationRepository;
private ConfigRepository $configRepository;
private EventDispatcherInterface $eventDispatcher;
public function __construct(EntityManagerInterface $entityManager, UserManagerInterface $userManager, EntryRepository $entryRepository, TagRepository $tagRepository, AnnotationRepository $annotationRepository, ConfigRepository $configRepository)
{
public function __construct(
EntityManagerInterface $entityManager,
UserManagerInterface $userManager,
EntryRepository $entryRepository,
TagRepository $tagRepository,
AnnotationRepository $annotationRepository,
ConfigRepository $configRepository,
EventDispatcherInterface $eventDispatcher
) {
$this->entityManager = $entityManager;
$this->userManager = $userManager;
$this->entryRepository = $entryRepository;
$this->tagRepository = $tagRepository;
$this->annotationRepository = $annotationRepository;
$this->configRepository = $configRepository;
$this->eventDispatcher = $eventDispatcher;
}
/**
@ -72,6 +83,7 @@ class ConfigController extends AbstractController
$configForm->handleRequest($request);
if ($configForm->isSubmitted() && $configForm->isValid()) {
$this->eventDispatcher->dispatch(new ConfigUpdatedEvent($config), ConfigUpdatedEvent::NAME);
$this->entityManager->persist($config);
$this->entityManager->flush();

View file

@ -72,6 +72,9 @@ class Configuration implements ConfigurationInterface
->end()
->end()
->end()
->arrayNode('fonts')
->prototype('scalar')->end()
->end()
->end()
;

View file

@ -29,6 +29,7 @@ class WallabagCoreExtension extends Extension
$container->setParameter('wallabag_core.default_internal_settings', $config['default_internal_settings']);
$container->setParameter('wallabag_core.site_credentials.encryption_key_path', $config['encryption_key_path']);
$container->setParameter('wallabag_core.default_ignore_origin_instance_rules', $config['default_ignore_origin_instance_rules']);
$container->setParameter('wallabag_core.fonts', $config['fonts']);
}
public function getAlias()

View file

@ -126,6 +126,49 @@ class Config
*/
private $displayThumbnails;
/**
* @var string
*
* @ORM\Column(name="font", type="text", nullable=true)
*
* @Groups({"config_api"})
*/
private $font;
/**
* @var float
*
* @ORM\Column(name="fontsize", type="float", nullable=true)
*
* @Groups({"config_api"})
*/
private $fontsize;
/**
* @var float
*
* @ORM\Column(name="line_height", type="float", nullable=true)
*
* @Groups({"config_api"})
*/
private $lineHeight;
/**
* @var float
*
* @ORM\Column(name="max_width", type="float", nullable=true)
*
* @Groups({"config_api"})
*/
private $maxWidth;
/**
* @var string
*
* @ORM\Column(name="custom_css", type="text", nullable=true)
*/
private $customCSS;
/**
* @ORM\OneToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="config")
*/
@ -390,6 +433,93 @@ class Config
return $this;
}
/**
* @return string
*/
public function getFont(): ?string
{
return $this->font;
}
/**
* @return $this
*/
public function setFont(string $font): self
{
$this->font = $font;
return $this;
}
/**
* @return float
*/
public function getFontsize(): ?float
{
return $this->fontsize;
}
/**
* @return $this
*/
public function setFontsize(float $fontsize): self
{
$this->fontsize = $fontsize;
return $this;
}
/**
* @return float
*/
public function getLineHeight(): ?float
{
return $this->lineHeight;
}
/**
* @return $this
*/
public function setLineHeight(float $lineHeight): self
{
$this->lineHeight = $lineHeight;
return $this;
}
/**
* @return float
*/
public function getMaxWidth(): ?float
{
return $this->maxWidth;
}
/**
* @return $this
*/
public function setMaxWidth(float $maxWidth): self
{
$this->maxWidth = $maxWidth;
return $this;
}
public function getCustomCSS(): ?string
{
return $this->customCSS;
}
/**
* @return $this
*/
public function setCustomCSS(?string $customCSS): self
{
$this->customCSS = $customCSS;
return $this;
}
/**
* @return Config
*/

View file

@ -0,0 +1,26 @@
<?php
namespace Wallabag\CoreBundle\Event;
use Symfony\Contracts\EventDispatcher\Event;
use Wallabag\CoreBundle\Entity\Config;
/**
* This event is fired as soon as user configuration is updated.
*/
class ConfigUpdatedEvent extends Event
{
public const NAME = 'config.updated';
protected $config;
public function __construct(Config $entry)
{
$this->config = $entry;
}
public function getConfig(): Config
{
return $this->config;
}
}

View file

@ -0,0 +1,53 @@
<?php
namespace Wallabag\CoreBundle\Event\Subscriber;
use Doctrine\ORM\EntityManagerInterface;
use ScssPhp\ScssPhp\Compiler;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Wallabag\CoreBundle\Event\ConfigUpdatedEvent;
class GenerateCustomCSSSubscriber implements EventSubscriberInterface
{
private $em;
private $compiler;
public function __construct(EntityManagerInterface $em, Compiler $compiler)
{
$this->em = $em;
$this->compiler = $compiler;
}
public static function getSubscribedEvents()
{
return [
ConfigUpdatedEvent::NAME => 'onConfigUpdated',
];
}
/**
* Generate custom CSS.
*/
public function onConfigUpdated(ConfigUpdatedEvent $event)
{
$config = $event->getConfig();
$css = $this->compiler->compileString(
'h1 { font-family: "' . $config->getFont() . '";}
#article {
max-width: ' . $config->getMaxWidth() . 'em;
font-family: "' . $config->getFont() . '";
}
#article article {
font-size: ' . $config->getFontsize() . 'em;
line-height: ' . $config->getLineHeight() . 'em;
}
;
')->getCss();
$config->setCustomCSS($css);
$this->em->persist($config);
$this->em->flush();
}
}

View file

@ -6,6 +6,7 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\RangeType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
@ -14,18 +15,53 @@ use Wallabag\CoreBundle\Entity\Config;
class ConfigType extends AbstractType
{
private $languages = [];
private $fonts = [];
/**
* @param array $languages Languages come from configuration, array just code language as key and label as value
* @param array $fonts Fonts come from configuration, array just font name as key / value
*/
public function __construct($languages)
public function __construct($languages, $fonts)
{
$this->languages = $languages;
$this->fonts = $fonts;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('font', ChoiceType::class, [
'choices' => $this->initFonts(),
'label' => 'config.form_settings.font_label',
'property_path' => 'font',
])
->add('fontsize', RangeType::class, [
'attr' => [
'min' => 0.6,
'max' => 2,
'step' => 0.1,
],
'label' => 'config.form_settings.fontsize_label',
'property_path' => 'fontsize',
])
->add('lineHeight', RangeType::class, [
'attr' => [
'min' => 0.6,
'max' => 2,
'step' => 0.1,
],
'label' => 'config.form_settings.lineheight_label',
'property_path' => 'lineHeight',
])
->add('maxWidth', RangeType::class, [
'attr' => [
'min' => 20,
'max' => 60,
'step' => 5,
],
'label' => 'config.form_settings.maxwidth_label',
'property_path' => 'maxWidth',
])
->add('items_per_page', IntegerType::class, [
'label' => 'config.form_settings.items_per_page_label',
'property_path' => 'itemsPerPage',
@ -72,4 +108,20 @@ class ConfigType extends AbstractType
{
return 'config';
}
/**
* Creates an array with font name as key / value.
*
* @return array
*/
private function initFonts()
{
$fonts = [];
foreach ($this->fonts as $font) {
$fonts[$font] = $font;
}
return $fonts;
}
}

View file

@ -25,18 +25,18 @@
{{ form_start(form.config) }}
{{ form_errors(form.config) }}
<div class="row">
<div class="input-field col s11">
{{ form_errors(form.config.items_per_page) }}
{{ form_widget(form.config.items_per_page) }}
{{ form_label(form.config.items_per_page) }}
</div>
<div class="input-field col s1">
<a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_settings.help_items_per_page'|trans }}">
<i class="material-icons">live_help</i>
</a>
</div>
<div class="row">
<div class="input-field col s11">
{{ form_errors(form.config.items_per_page) }}
{{ form_widget(form.config.items_per_page) }}
{{ form_label(form.config.items_per_page) }}
</div>
<div class="input-field col s1">
<a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_settings.help_items_per_page'|trans }}">
<i class="material-icons">live_help</i>
</a>
</div>
</div>
<div class="row">
<div class="input-field col s11 settings-checkbox-col">
@ -117,6 +117,66 @@
</script>
</div>
<h5>{{ 'config.tab_menu.article_display'|trans }}</h5>
<div class="row">
<div class="input-field col s5">
{{ form_errors(form.config.font) }}
{{ form_widget(form.config.font) }}
{{ form_label(form.config.font) }}
</div>
<div class="input-field col s1">
<a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_settings.help_font'|trans }}">
<i class="material-icons">live_help</i>
</a>
</div>
<div class="input-field col s5">
{{ form_errors(form.config.lineHeight) }}
{{ form_widget(form.config.lineHeight) }}
{{ form_label(form.config.lineHeight, null, {'label_attr': {'class': 'settings-range-label'}}) }}
</div>
<div class="input-field col s1">
<a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_settings.help_lineheight'|trans }}">
<i class="material-icons">live_help</i>
</a>
</div>
</div>
<div class="row">
<div class="input-field col s5">
{{ form_errors(form.config.fontsize) }}
{{ form_widget(form.config.fontsize) }}
{{ form_label(form.config.fontsize, null, {'label_attr': {'class': 'settings-range-label'}}) }}
</div>
<div class="input-field col s1">
<a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_settings.help_fontsize'|trans }}">
<i class="material-icons">live_help</i>
</a>
</div>
<div class="input-field col s5">
{{ form_errors(form.config.maxWidth) }}
{{ form_widget(form.config.maxWidth) }}
{{ form_label(form.config.maxWidth, null, {'label_attr': {'class': 'settings-range-label'}}) }}
</div>
<div class="input-field col s1">
<a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_settings.help_maxwidth'|trans }}">
<i class="material-icons">live_help</i>
</a>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<div id="preview-article">
<article id="preview-content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</article>
</div>
</div>
</div>
{{ form_widget(form.config.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
{{ form_rest(form.config) }}
</form>

View file

@ -319,4 +319,9 @@
{% endblock %}
{% block footer %}
<style>
{{ app.user.config.customCSS|raw }}
</style>
{% endblock %}