diff --git a/app/javascript/controllers/filteredlist_controller.js b/app/javascript/controllers/filteredlist_controller.js index 00f849269f2b2f87d63a20538b9895f6dc764b8b..102ba2d30ee97f5808332a9a631e7f317d69fcc8 100644 --- a/app/javascript/controllers/filteredlist_controller.js +++ b/app/javascript/controllers/filteredlist_controller.js @@ -9,7 +9,7 @@ function debounce(func, wait) { } export default class extends Controller { - static targets = ["input", "list"]; + static targets = ["input", "clear", "list"]; connect() { this.filter = debounce(this.filter_nodebounce.bind(this), 300); @@ -17,6 +17,13 @@ export default class extends Controller { filter_nodebounce() { const query = this.inputTarget.value.toLowerCase(); + + if (query) { + this.clearTarget.classList.remove("hidden"); + } else { + this.clearTarget.classList.add("hidden"); + } + // Filter options by the `data-filteredlist-match` attribute for (const option of this.listTarget.children) { if (option.dataset.filteredlistMatch.includes(query)) { @@ -26,4 +33,10 @@ export default class extends Controller { } } } + + clear_filter() { + this.inputTarget.value = ''; + this.filter_nodebounce(); + this.inputTarget.focus(); + } } diff --git a/app/views/assignments/_filteredlist.html.erb b/app/views/assignments/_filteredlist.html.erb index 100375ce271d311cf47e6efce88543bd0cd6ad72..06ed8449c4d4c690b2c0e6df00ec028468abd0ba 100644 --- a/app/views/assignments/_filteredlist.html.erb +++ b/app/views/assignments/_filteredlist.html.erb @@ -1,13 +1,20 @@ <div data-controller="filteredlist"> - <input - type="text" - data-filteredlist-target="input" - data-action="input->filteredlist#filter" - autocomplete="off" - class="w-full border border-gray-300 rounded-md shadow-sm text-sm p-1 focus:ring-indigo-500 focus:border-indigo-500" - placeholder="Filter..." - /> - <ul data-filteredlist-target="list" class="flex flex-row flex-wrap gap-1 my-1 flex-shrink-0"> + <div class="relative"> + <input + type="text" + data-filteredlist-target="input" + data-action="input->filteredlist#filter" + autocomplete="off" + class="w-full bg-white/60 border border-gray-300 rounded-t-md shadow-sm text-sm p-1 pr-8 focus:ring-indigo-500 focus:border-indigo-500" + placeholder="Filter..." + /> + <button + data-action="click->filteredlist#clear_filter" + aria-label="Clear filter" + data-filteredlist-target="clear" + class="absolute hidden inset-y-0 right-0 px-2 text-gray-500"> × </button> + </div> + <ul data-filteredlist-target="list" class="max-h-32 overflow-scroll flex flex-row flex-wrap gap-1 my-1 mt-0 flex-shrink-0 bg-black/10 rounded-b-md p-2"> <% users.each do |user| %> <%= render partial: 'assignments/filteredlist_option', locals: { session: session, user: user } %> <% end %> diff --git a/app/views/sessions/_session.html.erb b/app/views/sessions/_session.html.erb index dd370bfb8555099549b62de8472fd2c992f8949e..a0eeadbbfc72290d647e13f116e4df3cd33dfee8 100644 --- a/app/views/sessions/_session.html.erb +++ b/app/views/sessions/_session.html.erb @@ -1,5 +1,5 @@ <% unassigned_users = User.all - session.assignments.collect(&:user) %> -<%= turbo_frame_tag dom_id(session), method: "morph" do %> +<%= turbo_frame_tag dom_id(session), method: "morph", class: "w-full" do %> <div class="session shadow hover:shadow-lg overflow-scroll text-sm w-full !h-full min-h-full hover:!min-h-max <%= session.translators_needed? ? "translators-needed" : "no-translators-needed" %> <%= session.backup_needed? ? "backup-needed" : "no-backup-needed" %> <%= session.assignees? ? "has-assignees" : "no-assignees" %> <%= (session.ends_at < Time.now ? "past" : "") %>"> <h4> <small class="text-2xs uppercase font-light bg-black/10 rounded-sm p-1 mr-1 lang-<%= session.language %>"><%= session.language %></small>