Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 7 additions & 14 deletions assets/styles/app.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/* Vendors */
@import "../../vendor/tempest/highlight/src/Themes/Css/catppuccin-latte.css";

/* Tailwind */
@import "tailwindcss";

/* AFUP */
@import "./fonts.css";
@import "tailwindcss" source(none);
@source "../../templates";
@import "./prose.css";

@plugin "@tailwindcss/typography";

Expand All @@ -26,23 +31,11 @@
--color-erreur-500: #C10825;
/* Texte d'un message d'erreur */
--color-erreur-700: #960018;

/* Surcharge de la police par défaut des pages */
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;

/* Police utilisée pour les titres */
--font-titre: "Glegoo", ui-serif, Georgia, serif;
}

@layer base {
body {
/* Désactive les effets (italic, gras, etc) automatiques des polices pour prioriser les version contenues dans les polices */
font-synthesis: none;
}

/* Pour les balises de code "inline" dans les articles (les blocs de code ont déjà un padding et un arrondi de base) */
.prose code {
@apply px-2 py-1;
@apply rounded-lg;
}
}
8 changes: 8 additions & 0 deletions assets/styles/fonts.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,11 @@
font-display: swap;
src: url("../fonts/glegoo-latin-700-normal.woff2") format("woff2");
}

@theme {
/* Surcharge de la police par défaut des pages */
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;

/* Police utilisée pour les titres */
--font-titre: "Glegoo", ui-serif, Georgia, serif;
}
21 changes: 21 additions & 0 deletions assets/styles/prose.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Ce fichier contient des surcharges pour le HTML généré à partir de markdown
Tailwind fournit une lib pour styliser ce genre de HTML : https://github.com/tailwindlabs/tailwindcss-typography
*/

@layer base {
/* Pour les balises de code "inline" dans les articles (les blocs de code ont déjà un padding et un arrondi de base) */
.prose code {
@apply px-2 py-1;
@apply rounded-lg;
}

/* Gestion de certaines pages CMS avec des boutons */
/* Les classes sont les mêmes que pour le composant Button */
/* @see templates/components/Button.html.twig */
.prose a.button.button--call-to-action {
@apply items-center! justify-center! rounded-lg! border! border-transparent! bg-clip-border! text-sm! font-medium! whitespace-nowrap! px-3! py-2!;
@apply bg-ruby-500! text-white! hover:bg-ruby-700!;
@apply no-underline!;
}
}
8 changes: 3 additions & 5 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,10 @@ services:
class: Parsedown
autowire: true

Twig\Extra\Markdown\MarkdownInterface: '@twig.markdown.default'
twig.markdown.default:
alias: AppBundle\Markdown\Markdown

League\CommonMark\Extension\Autolink\AutolinkExtension:
tags: [ 'twig.markdown.league_extension' ]
Tempest\Highlight\CommonMark\HighlightExtension:
tags: [ 'twig.markdown.league_extension' ]
Twig\Extra\Markdown\MarkdownInterface: '@twig.markdown.default'

geocoder:
class: Geocoder\StatefulGeocoder
Expand Down
44 changes: 44 additions & 0 deletions sources/AppBundle/Markdown/Markdown.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace AppBundle\Markdown;

use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\Autolink\AutolinkExtension;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkProcessor;
use League\CommonMark\MarkdownConverter;
use Tempest\Highlight\CommonMark\HighlightExtension;
use Twig\Extra\Markdown\MarkdownInterface;

final readonly class Markdown implements MarkdownInterface
{
private MarkdownConverter $converter;

public function __construct()
{
$environment = new Environment([
'heading_permalink' => [
'symbol' => '',
'apply_id_to_heading' => true,
'insert' => HeadingPermalinkProcessor::INSERT_NONE,
],
'slug_normalizer' => [
'instance' => new SymfonySlugNormalizer(),
],
]);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new AutolinkExtension());
$environment->addExtension(new HeadingPermalinkExtension());
$environment->addExtension(new HighlightExtension());

$this->converter = new MarkdownConverter($environment);
}

public function convert(string $body): string
{
return $this->converter->convert($body)->getContent();
}
}
16 changes: 16 additions & 0 deletions sources/AppBundle/Markdown/SymfonySlugNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace AppBundle\Markdown;

use League\CommonMark\Normalizer\TextNormalizerInterface;
use Symfony\Component\String\Slugger\AsciiSlugger;

final readonly class SymfonySlugNormalizer implements TextNormalizerInterface
{
public function normalize(string $text, array $context = []): string
{
return (new AsciiSlugger())->slug($text)->lower()->toString();
}
}
64 changes: 54 additions & 10 deletions sources/AppBundle/Twig/Components/MainMenu.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,29 @@
use AppBundle\Security\Authentication;
use AppBundle\Site\Entity\Feuille as FeuilleEntity;
use AppBundle\Site\Entity\Repository\FeuilleRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent]
final readonly class MainMenu
final class MainMenu
{
public ?int $currentFeuilleId = null;

public function __construct(
private RequestStack $requestStack,
private FeuilleRepository $feuilleRepository,
private Authentication $authentication,
private readonly RequestStack $requestStack,
private readonly FeuilleRepository $feuilleRepository,
private readonly Authentication $authentication,
) {}

/**
* @return array<array{isCurrent: boolean, lien: string, nom: string}>
* @return array{main: array<array{isCurrent: boolean, feuille: FeuilleEntity}>, sub: array<array{feuille: FeuilleEntity, is_active: boolean}>}
*/
public function getFeuilles(): array
public function getEntries(): array
{
$feuillesEnfants = $this->feuilleRepository->getFeuillesEnfant(Feuille::ID_FEUILLE_HEADER);
$request = $this->requestStack->getMainRequest();

if ($this->authentication->getAfupUserOrNull() instanceof UserInterface) {
$feuilleLogin = new FeuilleEntity();
Expand All @@ -42,7 +46,7 @@ public function getFeuilles(): array
$feuillesEnfants[] = $feuilleLogin;
}

$currentUri = $this->requestStack->getCurrentRequest()?->getRequestUri() ?? '';
$currentUri = $request?->getRequestUri() ?? '';
$feuilles = [];

foreach ($feuillesEnfants as $feuille) {
Expand Down Expand Up @@ -85,11 +89,51 @@ public function getFeuilles(): array

$feuilles[] = [
'isCurrent' => $isCurrent,
'lien' => $feuille->lien,
'nom' => $feuille->nom,
'feuille' => $feuille,
];
}

return $feuilles;
$subEntries = [];
if ($this->currentFeuilleId !== null && $request !== null) {
$menu = $this->feuilleRepository->getFeuillesEnfant($this->currentFeuilleId);

foreach ($menu as $feuille) {
$subEntries[] = [
'feuille' => $feuille,
'is_active' => $this->isSubEntryActive($request, $feuille),
];
}
}

return [
'main' => $feuilles,
'sub' => $subEntries,
];
}

private function isSubEntryActive(Request $request, FeuilleEntity $feuille): bool
{
$url = $request->getUri();

$pattern = '/' . preg_quote((string) $feuille->lien, '/') . '/';

if (preg_match($pattern, $url)) {
return true;
}

if ($feuille->patterns) {
foreach (explode(PHP_EOL, $feuille->patterns) as $pattern) {
$pattern = trim($pattern);
if ($pattern === '') {
continue;
}

if (preg_match($pattern, $url)) {
return true;
}
}
}

return false;
}
}
15 changes: 13 additions & 2 deletions templates/components/MainMenu.html.twig
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
<nav class="bg-afup-500 hidden sm:block [body:has(#menu-toggle:checked)_&]:block">
<div class="container mx-auto flex flex-col sm:flex-row sm:items-center sm:gap-8 text-white font-bold uppercase">
{% for feuille in this.feuilles %}
<twig:MainMenu:Item href="{{ feuille.lien }}" :variant="feuille.isCurrent ? 'active' : null">{{ feuille.nom }}</twig:MainMenu:Item>
{% for entry in this.entries.main %}
<twig:MainMenu:Item href="{{ entry.feuille.lien }}" :variant="entry.isCurrent ? 'active' : null">{{ entry.feuille.nom }}</twig:MainMenu:Item>
{% endfor %}

<div class="sm:hidden flex flex-col gap-2 px-4 py-4 border-t border-white/20 text-center">
{% block account %}{% endblock %}
</div>
</div>
{% if this.entries.sub|length > 0 %}
<div class="bg-white border-b-2 border-neutre-300">
<div class="container mx-auto flex flex-row gap-2">
{% for entry in this.entries.sub %}
<div class="px-4 pt-3">
<a href="{{ entry.feuille.lien }}" class="block pb-2 text-gray-800 border-b-3 hover:border-neutre-400 uppercase text-sm {{ entry.is_active ? 'border-black' : 'border-transparent' }}">{{ entry.feuille.nom }}</a>
</div>
{% endfor %}
</div>
</div>
{% endif %}
</nav>
2 changes: 1 addition & 1 deletion templates/components/MainMenu/Item.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{# @block content Label du menu #}
{%- props variant = 'default' -%}
{%- set style = html_cva(
base: "px-4 py-4 font-inter whitespace-nowrap",
base: "p-4 font-inter whitespace-nowrap",
variants: {
variant: {
default: 'hover:text-black hover:bg-white',
Expand Down
4 changes: 3 additions & 1 deletion templates/layouts/site.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
</div>
</main>

<twig:MainMenu>
{% set menu_current_feuille_id = menu_current_feuille_id|default(null) %}

<twig:MainMenu currentFeuilleId="{{ menu_current_feuille_id }}">
<twig:block name="account">{{ account_buttons }}</twig:block>
</twig:MainMenu>
</header>
Expand Down
21 changes: 6 additions & 15 deletions templates/site/cms_page/display.html.twig
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
{% extends 'site/base.html.twig' %}
{% extends 'layouts/site.html.twig' %}
{% set menu_current_feuille_id = rubrique.feuilleAssociee %}

{% block title %}{{ article.titre }} - AFUP{% endblock %}

{% block header %}
{{ parent() }}
<link rel="stylesheet" href="{{ asset('css/buttons.css') }}" media="all" />
{% endblock %}

{% block content %}
{{ render(controller(
'AppBundle\\Controller\\Website\\SecondaryMenuController::display',
{ 'feuille_id': rubrique.feuilleAssociee }
)) }}
<div class="mw1400p center" id="container">
<div class="line" id="main">
<h1>{{ rubrique.nom }}</h1>
<h2>{{ article.titre }}</h2>
<article class="container mx-auto sm:pt-10 flex flex-col gap-5">
<h1 class="text-afup-800 text-2xl sm:text-4xl">{{ article.titre }}</h1>

<div class="prose prose-lg max-w-none sm:my-10 mt-10 sm:text-justify">
{{ article.contenu|markdown_to_html }}
</div>
</div>
</article>
{% endblock %}
5 changes: 4 additions & 1 deletion tests/behat/features/PublicSite/News.feature
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ Feature: Site Public - News
When I follow "Actualités"
And I follow "Lire l'article: Un article en Markdown"
Then I should not see "### Un premier titre !"
And the response should contain the html "<h3>Un premier titre !</h3>"
And the response should contain the html
"""
<h3 id="content-un-premier-titre">Un premier titre !</h3>
"""
And I should not see "**de texte en gras**"
And the response should contain the html "<strong>de texte en gras</strong>"
And I should not see "*de texte en italic*"
Expand Down
5 changes: 4 additions & 1 deletion tests/behat/features/PublicSite/Rss.feature
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ Feature: Site Public - Flux RSS
And the response should contain "<rss version=\"2.0\">"
And the response should contain "<title><![CDATA[Les vidéos des talks du Forum PHP 2018 sont disponibles]]></title>"
And the response should contain "<guid>https://apachephptest:80/news/1-les-videos-du-forum-2018-en-ligne</guid>"
And the response should contain "<h3>Un premier titre !</h3>"
And the response should contain the html
"""
<h3 id="content-un-premier-titre">Un premier titre !</h3>
"""
And the response should contain "Et un peu <em>de texte en italic</em>"
And the response should contain "</rss>"
Loading