From 116812b3f80da11e9f901d8cd32b842fa9e187e2 Mon Sep 17 00:00:00 2001 From: thibaud-leclere Date: Tue, 31 Mar 2026 22:18:46 +0200 Subject: [PATCH] save movies release date in BDD, remove unused badge, add help to export movie from letterboxd --- assets/bootstrap.js | 2 + assets/controllers/import_help_controller.js | 20 +++++ .../controllers/import_status_controller.js | 6 +- assets/styles/app.css | 80 +++++++++++++++---- migrations/Version20260331000002.php | 26 ++++++ src/Entity/Movie.php | 15 ++++ src/Service/FilmImporter.php | 3 +- templates/_navbar.html.twig | 33 ++++++-- 8 files changed, 158 insertions(+), 27 deletions(-) create mode 100644 assets/controllers/import_help_controller.js create mode 100644 migrations/Version20260331000002.php diff --git a/assets/bootstrap.js b/assets/bootstrap.js index 0916546..fa8abed 100644 --- a/assets/bootstrap.js +++ b/assets/bootstrap.js @@ -2,11 +2,13 @@ import { startStimulusApp } from 'vite-plugin-symfony/stimulus/helpers'; import DropdownController from './controllers/dropdown_controller.js'; import ImportModalController from './controllers/import_modal_controller.js'; import ImportStatusController from './controllers/import_status_controller.js'; +import ImportHelpController from './controllers/import_help_controller.js'; const app = startStimulusApp(); app.register('dropdown', DropdownController); app.register('import-modal', ImportModalController); app.register('import-status', ImportStatusController); +app.register('import-help', ImportHelpController); // Register React components for {{ react_component() }} Twig function. // We register them manually because @symfony/ux-react's registerReactControllerComponents diff --git a/assets/controllers/import_help_controller.js b/assets/controllers/import_help_controller.js new file mode 100644 index 0000000..68f8faf --- /dev/null +++ b/assets/controllers/import_help_controller.js @@ -0,0 +1,20 @@ +import { Controller } from '@hotwired/stimulus'; + +export default class extends Controller { + static targets = ['overlay']; + + open(event) { + event.stopPropagation(); + this.overlayTarget.hidden = false; + } + + close() { + this.overlayTarget.hidden = true; + } + + closeOnBackdrop(event) { + if (event.target === this.overlayTarget) { + this.close(); + } + } +} diff --git a/assets/controllers/import_status_controller.js b/assets/controllers/import_status_controller.js index a6c8a2e..6ffeb68 100644 --- a/assets/controllers/import_status_controller.js +++ b/assets/controllers/import_status_controller.js @@ -1,7 +1,7 @@ import { Controller } from '@hotwired/stimulus'; export default class extends Controller { - static targets = ['item', 'importBtn', 'badge']; + static targets = ['item', 'importBtn']; connect() { this._poll(); @@ -50,7 +50,6 @@ export default class extends Controller { this.importBtnTarget.disabled = false; this.importBtnTarget.textContent = 'Importer ses films'; this._removeStatus(); - this.badgeTarget.hidden = true; } _showActive(data) { @@ -62,7 +61,6 @@ export default class extends Controller { : 0; this._setStatus(`${progress}% — ${data.totalFilms} films`, 'active'); - this.badgeTarget.hidden = true; } _showCompleted(data) { @@ -71,14 +69,12 @@ export default class extends Controller { const imported = data.totalFilms - data.failedFilms; this._setStatus(`Dernier import : ${imported}/${data.totalFilms} films`, 'completed'); - this.badgeTarget.hidden = true; } _showFailed() { this.importBtnTarget.disabled = false; this.importBtnTarget.textContent = 'Importer ses films'; this._setStatus('Dernier import : échoué', 'failed'); - this.badgeTarget.hidden = true; } _setStatus(text, type) { diff --git a/assets/styles/app.css b/assets/styles/app.css index 4220de8..073d0f9 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -296,22 +296,6 @@ body { /* ── Badge ── */ -.badge { - position: absolute; - top: 2px; - right: 2px; - background: var(--orange); - color: white; - font-size: 10px; - font-weight: 700; - min-width: 16px; - height: 16px; - border-radius: 8px; - display: flex; - align-items: center; - justify-content: center; - padding: 0 4px; -} /* ── Dropdown ── */ @@ -367,6 +351,70 @@ body { margin: 0; } +/* ── Dropdown item row ── */ + +.dropdown-item-row { + display: flex; + align-items: center; +} + +.dropdown-item-row .dropdown-item { + flex: 1; +} + +.info-btn { + width: 20px; + height: 20px; + border-radius: 50%; + border: 1.5px solid var(--text-faint); + background: none; + color: var(--text-faint); + font-size: 12px; + font-weight: 700; + font-style: italic; + font-family: 'Georgia', serif; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + margin-right: 10px; + transition: border-color 0.15s, color 0.15s, background 0.15s; +} + +.info-btn:hover { + border-color: var(--orange); + color: var(--orange); + background: var(--surface-tint); +} + +/* ── Help steps ── */ + +.help-steps { + margin: 0; + padding-left: 20px; + color: var(--text-muted); + font-size: 14px; + line-height: 1.8; +} + +.help-steps code { + background: var(--surface-tint); + padding: 2px 6px; + border-radius: 4px; + font-size: 13px; +} + +.help-steps a { + color: var(--orange); + font-weight: 600; + text-decoration: none; +} + +.help-steps a:hover { + text-decoration: underline; +} + /* ── Import status ── */ .import-status-item { diff --git a/migrations/Version20260331000002.php b/migrations/Version20260331000002.php new file mode 100644 index 0000000..6e50410 --- /dev/null +++ b/migrations/Version20260331000002.php @@ -0,0 +1,26 @@ +addSql('ALTER TABLE movie ADD year INT DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE movie DROP COLUMN year'); + } +} diff --git a/src/Entity/Movie.php b/src/Entity/Movie.php index 7d00b6d..d0bb38d 100644 --- a/src/Entity/Movie.php +++ b/src/Entity/Movie.php @@ -24,6 +24,9 @@ class Movie #[ORM\Column(length: 255)] private ?string $title = null; + #[ORM\Column(nullable: true)] + private ?int $year = null; + /** * @var Collection */ @@ -76,6 +79,18 @@ class Movie return $this; } + public function getYear(): ?int + { + return $this->year; + } + + public function setYear(?int $year): static + { + $this->year = $year; + + return $this; + } + /** * @return Collection */ diff --git a/src/Service/FilmImporter.php b/src/Service/FilmImporter.php index 1a034e4..f6ce6d1 100644 --- a/src/Service/FilmImporter.php +++ b/src/Service/FilmImporter.php @@ -38,7 +38,8 @@ readonly class FilmImporter $movie = new Movie() ->setLtbxdRef($ltbxdMovie->getLtbxdRef()) ->setTitle($ltbxdMovie->getName()) - ->setTmdbId($tmdbMovie->getId()); + ->setTmdbId($tmdbMovie->getId()) + ->setYear($ltbxdMovie->getYear()); $this->em->persist($movie); diff --git a/templates/_navbar.html.twig b/templates/_navbar.html.twig index ec8bffb..f7174eb 100644 --- a/templates/_navbar.html.twig +++ b/templates/_navbar.html.twig @@ -1,5 +1,5 @@ {% if app.user %} -
+
+{# Help Modal #} + {% else %}