diff --git a/public/assets/css/app.css b/public/assets/css/app.css index ca04b22bf6aa0e109091576de25875bca7d13194..1a699c65098a8db739ea75687e1b2784216ec320 100644 --- a/public/assets/css/app.css +++ b/public/assets/css/app.css @@ -152,11 +152,14 @@ p:hover .fa.text-grey, h4:hover .fa.text-grey, h1:hover .fa.text-grey { color: dimgrey; } .text-light-green { - color: #c3eec3; + color: #d2e8d2; } p:hover .fa.text-light-green, h4:hover .fa.text-light-green, h1:hover .fa.text-light-green { color: limegreen; } +.fa-fixed-sized { + font-size: 1rem; +} .bg-label-personal { background-color: #d9f2ff; diff --git a/src/Controller/EntryController.php b/src/Controller/EntryController.php index 46589cd1c55a79d5b49d1236b8bbe32063440a8f..e6b4fd5a7221270227eb8bbddbc226a4cac43913 100644 --- a/src/Controller/EntryController.php +++ b/src/Controller/EntryController.php @@ -7,6 +7,7 @@ use App\Entity\Label; use App\Entity\Lexicon; use App\Entity\Log; use App\Form\BlockType; +use App\Form\PartOfSpeechType; use App\Form\SearchStringType; use App\Manager\LabelManager; use App\Repository\EntryRepository; @@ -166,6 +167,7 @@ class EntryController extends AppBaseController */ public function editBlock(Request $request, Entry $entry, $blockId): Response { + $blockCategory = $request->get('blockCategory'); $attributes = $entry->getAttributes(); $propertyAccessor = PropertyAccess::createPropertyAccessor(); $block = $propertyAccessor->getValue($attributes, $blockId); @@ -173,8 +175,10 @@ class EntryController extends AppBaseController $form = $this->createForm(BlockType::class, ['block' => $block], [ 'action' => $this->generateUrl('app_entry_edit_block', [ 'id' => $entry->getId(), - 'blockId' => $blockId - ]) + 'blockId' => $blockId, + 'blockCategory' => $blockCategory, + ]), + 'blockCategory' => $blockCategory, ]); $form->handleRequest($request); @@ -246,4 +250,42 @@ class EntryController extends AppBaseController 'form' => $form->createView(), ]); } + + /** + * @Route("/{id}/add-block-pos", name="app_entry_add_block_pos", methods={"GET", "POST"}) + */ + public function addBlockPartOfSpeech(Request $request, Entry $entry): Response + { + $attributes = $entry->getAttributes(); + + $form = $this->createForm(PartOfSpeechType::class, null, [ + 'action' => $this->generateUrl('app_entry_add_block_pos', [ + 'id' => $entry->getId(), + ]), + 'entry' => $entry, + ]); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $attributes["Items"][] = [ + "PartOfSpeech" => $form->get('PartOfSpeech')->getData(), + "Sense" => [ + "Definitions" => [ + ["Def" => $form->get('Def')->getData()] + ] + ] + ]; + $entry->setAttributes($attributes); + $this->em->flush(); + + return $this->render('closeModalAndReload.html.twig'); + } + + $this->addFlash('info', "Veuillez indiquer également la première définition pour cette nature."); + + return $this->render('genericModalForm.html.twig', [ + 'form' => $form->createView(), + 'title' => "Ajouter une nature", + ]); + } } diff --git a/src/Entity/Entry.php b/src/Entity/Entry.php index d982fb4c2934cbc554a23084f6e8d1930f664c7a..01cfca59069d0e5b299397e98aad045c9d2c1a07 100644 --- a/src/Entity/Entry.php +++ b/src/Entity/Entry.php @@ -22,9 +22,20 @@ use OpenApi\Annotations as OA; class Entry { const ATTR_PRONUNCIATION = 'Pronunciations'; - const ATTR_PART_OF_SPEECH = 'PartOfSpeech'; const ATTR_DEFINITION = 'Definitions'; + const PART_OF_SPEECH_LIST = [ + "N" => "N", + "V" => "V", + "Interj" => "Interj", + "Adj" => "Adj", + "Adv" => "Adv", + "Det" => "Det", + "Pro" => "Pro", + "Conj" => "Conj", + "Prep" => "Prep", + ]; + use LoggableTrait; /** diff --git a/src/Form/BlockType.php b/src/Form/BlockType.php index d8a4751210d54f0afbfb58e060ea1ddacc165ba8..82b177a0adb2b8edca9a37d8aa4841066be92c2d 100644 --- a/src/Form/BlockType.php +++ b/src/Form/BlockType.php @@ -36,12 +36,6 @@ class BlockType extends AbstractType 'label' => false, ]) ; - } elseif ($blockCategory === Entry::ATTR_PART_OF_SPEECH) { - $builder - ->add('block', PartOfSpeechType::class, [ - 'label' => false, - ]) - ; } else { $builder ->add('block', TextareaType::class, [ diff --git a/src/Form/PartOfSpeechType.php b/src/Form/PartOfSpeechType.php index c65927df1851def8823812d71d849a1a43014e47..3186c8ca46e354453a94ddbb7fcd9fec46acd635 100644 --- a/src/Form/PartOfSpeechType.php +++ b/src/Form/PartOfSpeechType.php @@ -6,6 +6,7 @@ use App\Entity\Entry; use App\Entity\Label; use App\Entity\User; use App\Languages\LanguagesIso; +use App\Manager\EntryManager; use App\Repository\GroupRepository; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; @@ -21,22 +22,46 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class PartOfSpeechType extends AbstractType { + /** + * @var EntryManager + */ + private $entryManager; + + public function __construct(EntryManager $entryManager) + { + $this->entryManager = $entryManager; + } + public function buildForm(FormBuilderInterface $builder, array $options): void { + $entry = $options['entry']; + $currentPartsOfSpeech = $entry ? $this->entryManager->getAllPartOfSpeech($entry) : []; + $builder - ->add('PartOfSpeech', TextType::class, [ + ->add('PartOfSpeech', ChoiceType::class, [ 'label' => "Nature", + 'choices' => array_diff(Entry::PART_OF_SPEECH_LIST, $currentPartsOfSpeech), ]) - ->add('Sense', HiddenType::class, [ - 'required' => false, - 'label' => false, + ->add('Def', TextareaType::class, [ + 'label' => "Definition", ]) ; + + $builder + ->add('submit', SubmitType::class, [ + 'label' => 'Enregistrer', + ]); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ + 'entry' => null, + 'attr' => [ + 'data-ajax-form' => '', + 'data-ajax-form-target' => '#bootstrap-modal .modal-content', + 'novalidate' => 'novalidate', + ], ]); } } diff --git a/src/Manager/EntryManager.php b/src/Manager/EntryManager.php index 324537178cfd4c5ff735e879bd91e757cb2e16b4..0f3103adc654ae19fc9662536e0e69860b16fc4c 100644 --- a/src/Manager/EntryManager.php +++ b/src/Manager/EntryManager.php @@ -47,14 +47,13 @@ class EntryManager return $item["Sense"]; } - public function getPartOfSpeechFromItem($item) + public function getAllPartOfSpeech(Entry $entry) { - return $item["PartOfSpeech"]; - } - - public function getDefinitionsFromItem($item) - { - return $item["Sense"]["Definitions"]; + $result = []; + foreach ($this->getItems($entry) as $item) { + $result[] = $item["PartOfSpeech"]; + } + return $result; } public function getPronunciationsFromSense($sense) diff --git a/templates/entry/_entryAttributes.html.twig b/templates/entry/_entryAttributes.html.twig index a93098e89319d50c8ad209d1115f17e662936468..91b5492cc36a0683f07d9523723d59f017a191d4 100644 --- a/templates/entry/_entryAttributes.html.twig +++ b/templates/entry/_entryAttributes.html.twig @@ -3,7 +3,9 @@ <h1> {{ entry }} - {{ _self.actions(entry, '', ['add'], "Ajouter une nature", 'Items') }} + {% if not entry.lexicon.zero %} + <a href="#" data-url="{{ path('app_entry_add_block_pos', {id: entry.id}) }}" class="modal-form"><i class="fa fa-plus-circle fa-fixed-sized text-light-green" title="{{ "Ajouter une nature à cette entrée"|trans }}"></i></a> + {% endif %} </h1> <h4> @@ -11,9 +13,14 @@ {{ _self.actions(entry, '[Items][0][Sense]', ['add'], "Ajouter une prononciation", 'Pronunciations') }} </h4> <div class="ms-1 ps-4 mb-2"> - {% for pronunciation in entry_manager.pronunciations(entry) %} + {% for key, pronunciation in entry_manager.pronunciations(entry) %} + {######### SET KEY ##########} + {% set pronunciationKey = '[Items][0][Sense][Pronunciations]['~key~']' %} + {% if pronunciation.accent is defined %}{{ pronunciation.accent }} :{% endif %} - {{ pronunciation.api }}<br> + {{ pronunciation.api }} + {{ _self.actions(entry, pronunciationKey, ['edit', 'delete'], '', 'Pronunciations') }} + <br> {% endfor %} </div> @@ -24,8 +31,9 @@ {% set itemKey = '[Items]['~key~']' %} <h4> - {{ entry_manager.partOfSpeechFromItem(item)|trans }} - {{ _self.actions(entry, itemKey~'[Sense]', ['add'], "Ajouter une définition", 'Definitions') }} + {{ item.PartOfSpeech|trans }} + {{ _self.actions(entry, itemKey~'[Sense]', ['add'], "Ajouter une définition à cette nature", 'Definitions') }} + {{ _self.actions(entry, itemKey, ['delete']) }} </h4> <div class="ms-1 ps-4 left-border-blue bg-light-grey"> @@ -38,7 +46,8 @@ <p class="fw-bold"> {{ loop.index }}. {{ definition.Def }} - {{ _self.actions(entry, definitionKey, ['add'], "Ajouter un exemple", 'Examples') }} + {{ _self.actions(entry, definitionKey, ['add'], "Ajouter un exemple à cette définition", 'Examples') }} + {{ _self.actions(entry, definitionKey, ['edit', 'delete'], '', 'Definitions') }} </p> {% for key, example in definition.Examples|default([]) %} @@ -60,15 +69,22 @@ </div> {% macro actions(entry, key, operations, title, category) %} - {% if 'add' in operations %} - <a href="#" data-url="{{ path('app_entry_add_block', {id: entry.id, blockId: key, blockCategory: category}) }}" class="modal-form"><i class="fa fa-plus-circle fa-lg text-light-green" title="{{ title ? title|trans : category|trans }} {{ key }}"></i></a> - {% endif %} - {% if 'edit' in operations %} - <a href="#" data-url="{{ path('app_entry_edit_block', {id: entry.id, blockId: key}) }}" class="modal-form"><i class="fa fa-pencil-square fa-lg text-grey" title="{{ key }}"></i></a> - {% endif %} - {% if 'delete' in operations %} - <a href="#" data-href="{{ path('app_entry_delete_block', {id: entry.id, blockId: key}) }}" - data-confirm="{{ "Confirmer la suppression ?"|trans }}" data-bs-toggle="modal" data-bs-target="#confirm-dialog"><i class="fa fa-trash fa-lg text-grey" title="{{ key }}"></i></a> + + {% if not entry.lexicon.zero %} + + {% if 'add' in operations %} + <a href="#" data-url="{{ path('app_entry_add_block', {id: entry.id, blockId: key, blockCategory: category}) }}" class="modal-form"><i class="fa fa-plus-circle fa-fixed-sized text-light-green" title="{{ title ? title|trans : category|trans }} {{ key }}"></i></a> + {% endif %} + + {% if 'edit' in operations %} + <a href="#" data-url="{{ path('app_entry_edit_block', {id: entry.id, blockId: key, blockCategory: category}) }}" class="modal-form"><i class="fa fa-pencil-square fa-fixed-sized text-grey" title="{{ key }}"></i></a> + {% endif %} + + {% if 'delete' in operations %} + <a href="#" data-href="{{ path('app_entry_delete_block', {id: entry.id, blockId: key}) }}" + data-confirm="{{ "Confirmer la suppression ?"|trans }}" data-bs-toggle="modal" data-bs-target="#confirm-dialog"><i class="fa fa-trash fa-fixed-sized text-grey" title="{{ key }}"></i></a> + {% endif %} + {% endif %} {% endmacro %} diff --git a/templates/entry/show.html.twig b/templates/entry/show.html.twig index c9b922b0fc4388aef0bc6440e5bff1e6d2a143f3..0cbc9aceb9ca116946c8b1c09438d50bd6c2b729 100644 --- a/templates/entry/show.html.twig +++ b/templates/entry/show.html.twig @@ -38,7 +38,7 @@ <div id="tabContent" class="{{ entry.lexicon.zero ? 'tab-wiktionnary' }}"> <div class="row"> - <div class="col-sm-6 col-lg-4"> + <div class="col-sm-6 col-xl-4"> {% include "entry/_entryLabels.html.twig" %} </div> </div> diff --git a/templates/home.html.twig b/templates/home.html.twig index 7bfce711a2a96c590baa91dd4ba7dcc1670724fe..69857e9c64437185c5fb56494a1a340a94f06f33 100644 --- a/templates/home.html.twig +++ b/templates/home.html.twig @@ -21,30 +21,32 @@ {% endif %} </div> - <div class="row align-items-start"> + <div class="row g-5 align-items-start"> <div class="col"> <h1>{{ "Mes lexiques"|trans }}</h1> - <div class="card mt-3"> + <div class="card my-3"> <div class="card-header"> <div class="card-title pt-2 d-flex justify-content-between align-items-start"> <a href="{{ path('app_lexicon_show', {id: app.user.lexicon.id}) }}">{{ app.user.lexicon|badge }} {{ "Lexique personnel"|trans }}</a> <span>{{ lexicon_manager.entriesNb(app.user.lexicon) }}</span> </div> </div> - <div class="card-body d-flex justify-content-between align-items-start"> + <div class="card-body"> {% for lexicon in app.user.myLexicons %} {% if lexicon.masterGroup %} - <a href="{{ path('app_lexicon_show', {id: app.user.lexicon.id}) }}">{{ lexicon|badge }} {{ "Lexique du groupe"|trans }} « {{ lexicon }} »</a> - <span>{{ lexicon_manager.entriesNb(lexicon) }}</span> + <div class=" d-flex justify-content-between align-items-start py-2"> + <a href="{{ path('app_lexicon_show', {id: app.user.lexicon.id}) }}">{{ lexicon|badge }} {{ "Lexique du groupe"|trans }} « {{ lexicon }} »</a> + <span>{{ lexicon_manager.entriesNb(lexicon) }}</span> + </div> {% endif %} {% endfor %} </div> </div> <h1>{{ "Labels récents"|trans }}</h1> - <div class="card mt-3"> + <div class="card my-3"> <div class="card-body d-flex justify-content-between align-items-end"> <span> {% for label in label_manager.lastLabels(app.user) %} @@ -59,7 +61,7 @@ <h1>{{ "Agora Des Néologismes"|trans }}</h1> {% set newWordsLexicon = lexicon_manager.newWordsLexicon %} - <div class="card mt-3"> + <div class="card my-3"> <div class="card-body d-flex justify-content-between align-items-end"> <span> <p> @@ -77,16 +79,15 @@ </div> - <div class="col text-center"> - <h1>{{ "Bonjour"|trans }} {{ app.user }}</h1> + <div class="col"> + <h1 class="text-center">{{ "Bonjour"|trans }} {{ app.user }}</h1> <h1 class="mt-5">{{ "Mot du jour"|trans }}</h1> <div class="card mt-3"> <div class="card-body bg-pink"> <a href="{{ path('app_entry_show', {id: entry.id}) }}"> - <h3>{{ entry }}</h3> + {% include "entry/_entryAttributes.html.twig" %} </a> - {% include "entry/_entryAttributes.html.twig" %} </div> </div> </div>