From eafcf3fcb17218b4c8f77d1ce4414b772c7c5366 Mon Sep 17 00:00:00 2001 From: Brock H Caldwell Date: Sun, 6 Jul 2025 09:07:51 -0500 Subject: [PATCH] wip: renders live search results --- assets/controllers.json | 11 +++ assets/controllers/search_bar_controller.js | 33 ++++++++ assets/styles/app.css | 27 ++++++ composer.json | 1 + composer.lock | 92 ++++++++++++++++++++- config/bundles.php | 1 + config/routes/ux_autocomplete.yaml | 3 + importmap.php | 17 ++++ src/Controller/IndexController.php | 22 ++++- symfony.lock | 12 +++ templates/components/Card.html.twig | 2 +- templates/components/SearchBar.html.twig | 15 ++-- templates/index/index.html.twig | 2 +- 13 files changed, 226 insertions(+), 12 deletions(-) create mode 100644 assets/controllers/search_bar_controller.js create mode 100644 config/routes/ux_autocomplete.yaml diff --git a/assets/controllers.json b/assets/controllers.json index 71abe9d..48203c9 100644 --- a/assets/controllers.json +++ b/assets/controllers.json @@ -1,5 +1,16 @@ { "controllers": { + "@symfony/ux-autocomplete": { + "autocomplete": { + "enabled": true, + "fetch": "eager", + "autoimport": { + "tom-select/dist/css/tom-select.default.css": true, + "tom-select/dist/css/tom-select.bootstrap4.css": false, + "tom-select/dist/css/tom-select.bootstrap5.css": false + } + } + }, "@symfony/ux-live-component": { "live": { "enabled": true, diff --git a/assets/controllers/search_bar_controller.js b/assets/controllers/search_bar_controller.js new file mode 100644 index 0000000..5398046 --- /dev/null +++ b/assets/controllers/search_bar_controller.js @@ -0,0 +1,33 @@ +import { Controller } from '@hotwired/stimulus'; + +export default class extends Controller { + initialize() { + this._onPreConnect = this._onPreConnect.bind(this); + this._onConnect = this._onConnect.bind(this); + } + + connect() { + this.element.addEventListener('autocomplete:pre-connect', this._onPreConnect); + this.element.addEventListener('autocomplete:connect', this._onConnect); + } + + disconnect() { + // You should always remove listeners when the controller is disconnected to avoid side-effects + this.element.removeEventListener('autocomplete:connect', this._onConnect); + this.element.removeEventListener('autocomplete:pre-connect', this._onPreConnect); + } + + _onPreConnect(event) { + // TomSelect has not been initialized - options can be changed + console.log(event.detail.options); // Options that will be used to initialize TomSelect + event.detail.options.onChange = (value) => { + // ... + }; + } + + _onConnect(event) { + // TomSelect has just been initialized and you can access details from the event + console.log(event.detail.tomSelect); // TomSelect instance + console.log(event.detail.options); // Options used to initialize TomSelect + } +} \ No newline at end of file diff --git a/assets/styles/app.css b/assets/styles/app.css index 2e754ef..3cf7b9d 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -95,3 +95,30 @@ dialog[data-dialog-target="dialog"][closing] { display: inline-table; } } + +#search .ts-wrapper.single .ts-control::after { + display: none !important; +} + +#search .ts-control { + background: transparent !important; + border: none !important; + box-shadow: none !important; + color: #fff !important; + padding-left: 0; + + input { + color: #fff !important; + padding: 0; + } +} + +#search .ts-dropdown { + background: unset; + @apply bg-orange-500/80 backdrop-filter backdrop-blur-md text-white border border-orange-500 rounded-md +} + +#search .ts-dropdown .ts-dropdown-content .option.active { + background: unset; + @apply hover:bg-orange-500/80 active:bg-orange-500/80 text-black rounded-md +} diff --git a/composer.json b/composer.json index a9d6ccf..38de899 100644 --- a/composer.json +++ b/composer.json @@ -44,6 +44,7 @@ "symfony/security-bundle": "7.3.*", "symfony/stimulus-bundle": "^2.24", "symfony/twig-bundle": "7.3.*", + "symfony/ux-autocomplete": "^2.27", "symfony/ux-icons": "^2.24", "symfony/ux-live-component": "^2.24", "symfony/ux-turbo": "^2.24", diff --git a/composer.lock b/composer.lock index bc70748..5e579ed 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "67e697578f7237f60726c0d93bfed001", + "content-hash": "248d1e534ec6bb56594a7380fb2eb860", "packages": [ { "name": "1tomany/rich-bundle", @@ -9071,6 +9071,96 @@ ], "time": "2025-03-30T12:17:06+00:00" }, + { + "name": "symfony/ux-autocomplete", + "version": "v2.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-autocomplete.git", + "reference": "ab0be7ef7d59ea6925fd6fabccbd4d04cb5f5e06" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-autocomplete/zipball/ab0be7ef7d59ea6925fd6fabccbd4d04cb5f5e06", + "reference": "ab0be7ef7d59ea6925fd6fabccbd4d04cb5f5e06", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/dependency-injection": "^6.3|^7.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-foundation": "^6.3|^7.0", + "symfony/http-kernel": "^6.3|^7.0", + "symfony/property-access": "^6.3|^7.0" + }, + "conflict": { + "doctrine/orm": "2.9.0 || 2.9.1" + }, + "require-dev": { + "doctrine/collections": "^1.6.8|^2.0", + "doctrine/doctrine-bundle": "^2.4.3", + "doctrine/orm": "^2.9.4|^3.0", + "fakerphp/faker": "^1.22", + "mtdowling/jmespath.php": "^2.6", + "symfony/form": "^6.3|^7.0", + "symfony/framework-bundle": "^6.3|^7.0", + "symfony/maker-bundle": "^1.40", + "symfony/options-resolver": "^6.3|^7.0", + "symfony/phpunit-bridge": "^6.3|^7.0", + "symfony/process": "^6.3|^7.0", + "symfony/security-bundle": "^6.3|^7.0", + "symfony/twig-bundle": "^6.3|^7.0", + "symfony/uid": "^6.3|^7.0", + "twig/twig": "^2.14.7|^3.0.4", + "zenstruck/browser": "^1.1", + "zenstruck/foundry": "1.37.*" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\Autocomplete\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "JavaScript Autocomplete functionality for Symfony", + "homepage": "https://symfony.com", + "keywords": [ + "symfony-ux" + ], + "support": { + "source": "https://github.com/symfony/ux-autocomplete/tree/v2.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-21T10:08:18+00:00" + }, { "name": "symfony/ux-icons", "version": "v2.26.0", diff --git a/config/bundles.php b/config/bundles.php index c501bd2..a0d6c65 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -19,4 +19,5 @@ return [ Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true], + Symfony\UX\Autocomplete\AutocompleteBundle::class => ['all' => true], ]; diff --git a/config/routes/ux_autocomplete.yaml b/config/routes/ux_autocomplete.yaml new file mode 100644 index 0000000..da6b261 --- /dev/null +++ b/config/routes/ux_autocomplete.yaml @@ -0,0 +1,3 @@ +ux_autocomplete: + resource: '@AutocompleteBundle/config/routes.php' + prefix: '/autocomplete' diff --git a/importmap.php b/importmap.php index 1024843..4aa8096 100644 --- a/importmap.php +++ b/importmap.php @@ -47,4 +47,21 @@ return [ 'version' => '4.1.1', 'type' => 'css', ], + 'tom-select' => [ + 'version' => '2.4.3', + ], + '@orchidjs/sifter' => [ + 'version' => '1.1.0', + ], + '@orchidjs/unicode-variants' => [ + 'version' => '1.1.2', + ], + 'tom-select/dist/css/tom-select.default.min.css' => [ + 'version' => '2.4.3', + 'type' => 'css', + ], + 'tom-select/dist/css/tom-select.default.css' => [ + 'version' => '2.4.3', + 'type' => 'css', + ], ]; diff --git a/src/Controller/IndexController.php b/src/Controller/IndexController.php index 71a8542..d5d831b 100644 --- a/src/Controller/IndexController.php +++ b/src/Controller/IndexController.php @@ -31,9 +31,25 @@ final class IndexController extends AbstractController } #[Route('/test', name: 'app_test')] - public function test(MonitorDispatcher $dispatcher): Response + public function test(Tmdb $tmdb, Request $request): Response { - $dispatcher(); - return new Response(); + $results = []; + + $term = $request->query->get('query') ?? null; + + if (null !== $term) { + $tmdbResults = $tmdb->search($term); + + foreach ($tmdbResults as $tmdbResult) { + $results[] = [ + 'text' => $tmdbResult->title, + 'value' => $tmdbResult->title, + ]; + } + } + + return $this->json([ + 'results' => $results, + ]); } } diff --git a/symfony.lock b/symfony.lock index e8e21b9..04f4f5c 100644 --- a/symfony.lock +++ b/symfony.lock @@ -281,6 +281,18 @@ "templates/base.html.twig" ] }, + "symfony/ux-autocomplete": { + "version": "2.27", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.6", + "ref": "07d9602b7231ba355f484305d6cea58310c01741" + }, + "files": [ + "config/routes/ux_autocomplete.yaml" + ] + }, "symfony/ux-icons": { "version": "2.24", "recipe": { diff --git a/templates/components/Card.html.twig b/templates/components/Card.html.twig index cb6d3a2..55274ca 100644 --- a/templates/components/Card.html.twig +++ b/templates/components/Card.html.twig @@ -1,6 +1,6 @@

diff --git a/templates/components/SearchBar.html.twig b/templates/components/SearchBar.html.twig index 222d1de..f079710 100644 --- a/templates/components/SearchBar.html.twig +++ b/templates/components/SearchBar.html.twig @@ -1,15 +1,18 @@
-
- +