From 835c0f0afc145558279de2efd6984001abb664eb Mon Sep 17 00:00:00 2001 From: Evgeny Varnakov Date: Sun, 30 Jul 2023 17:33:32 +0300 Subject: [PATCH] solution: day 2 - task 4 --- app/assets/stylesheets/nav.css | 12 +++++++ app/controllers/search_controller.rb | 14 +++++--- .../controllers/search_controller.js | 35 +++++++++++++++++++ app/views/search/_live_results.html.erb | 26 ++++++++++++++ app/views/shared/_nav.html.erb | 18 ++++++---- config/importmap.rb | 1 + 6 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 app/javascript/controllers/search_controller.js create mode 100644 app/views/search/_live_results.html.erb diff --git a/app/assets/stylesheets/nav.css b/app/assets/stylesheets/nav.css index 67d5d9a..0965c1a 100644 --- a/app/assets/stylesheets/nav.css +++ b/app/assets/stylesheets/nav.css @@ -28,6 +28,18 @@ @apply pl-10 p-1 w-full rounded border-none bg-opacity-0 bg-white transition-colors focus:bg-opacity-90 focus:border focus:border-gray-300 focus:outline-none outline-offset-0 !important; } +.nav--search--input:has(+ .nav--search--results) { + @apply bg-opacity-90 border border-gray-300; +} + +.nav--search--results { + @apply absolute w-[300px] top-4 bg-white mt-8 z-40 shadow-md pt-2; +} + +.nav--search--result { + @apply p-2; +} + .nav--logo { @apply flex h-full items-center self-start; background: url("/assets/logo.png") no-repeat; diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 73f25d1..e20bdc0 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -3,11 +3,17 @@ def index q = params[:q] if q.blank? || q.length < 3 - return redirect_back(fallback_location: root_path, alert: "Please, enter at least 3 characters") + unless turbo_frame_request? + return redirect_back(fallback_location: root_path, alert: "Please, enter at least 3 characters") + end + else + @artists = Artist.search(q).limit(10) + @albums = Album.search(q).limit(10) + @tracks = Track.search(q).limit(10) end - @artists = Artist.search(q).limit(10) - @albums = Album.search(q).limit(10) - @tracks = Track.search(q).limit(10) + if turbo_frame_request? + render partial: "live_results", locals: {artists: @artists, albums: @albums, tracks: @tracks} + end end end diff --git a/app/javascript/controllers/search_controller.js b/app/javascript/controllers/search_controller.js new file mode 100644 index 0000000..ba5cbfc --- /dev/null +++ b/app/javascript/controllers/search_controller.js @@ -0,0 +1,35 @@ +import { ApplicationController, useDebounce, useClickOutside } from 'stimulus-use' + +export default class extends ApplicationController { + static targets = ["form", "term", "results"] + static debounces = ["fetch"] + + connect() { + useDebounce(this, {wait: 100}); + useClickOutside(this); + } + + disconnect() { + this.away(); + } + + fetch() { + this.resultsTarget.src = this.formTarget.action + "?q=" + encodeURIComponent(this.termTarget.value); + } + + away() { + setTimeout(() => { + this.termTarget.value = ""; + this.resultsTarget.src = ""; + this.resultsTarget.innerHTML = ''; + }, 50); + } + + clickOutside() { + this.resultsTarget.hidden = true; + } + + focus() { + this.resultsTarget.hidden = false; + } +} diff --git a/app/views/search/_live_results.html.erb b/app/views/search/_live_results.html.erb new file mode 100644 index 0000000..1802136 --- /dev/null +++ b/app/views/search/_live_results.html.erb @@ -0,0 +1,26 @@ +<%# locals: (artists: , albums:, tracks:) -%> +<%= turbo_frame_tag "search-results", data: {search_target: "results"}, target: "_top" do %> + <% if artists.present? || albums.present? || tracks.present? %> + + <% end %> +<% end %> diff --git a/app/views/shared/_nav.html.erb b/app/views/shared/_nav.html.erb index 4fcbfc2..0ab122c 100644 --- a/app/views/shared/_nav.html.erb +++ b/app/views/shared/_nav.html.erb @@ -14,18 +14,22 @@ <% end %> <% end %> <%- end -%> - <%= form_with(url: search_path, method: :get, class: "nav--search") do |f| %> - - <%= f.search_field :q, value: params[:q], class: "nav--search--input" %> - <% end %> +
+ <%= form_with(url: search_path, method: :get, class: "nav--search", data: {search_target: "form"}) do |f| %> + + <%= f.search_field :q, value: params[:q], class: "nav--search--input", + data: {action: "keyup->search#fetch focus->search#focus", search_target: "term"} %> + <% end %> + <%= turbo_frame_tag "search-results", data: {search_target: "results"}, target: "_top" %> +