Skip to content

Instantly share code, notes, and snippets.

@garyharan
Last active December 2, 2023 22:16
Show Gist options
  • Save garyharan/dcf4ae30a9f66a9d892db3cc102bdb6c to your computer and use it in GitHub Desktop.
Save garyharan/dcf4ae30a9f66a9d892db3cc102bdb6c to your computer and use it in GitHub Desktop.
search select
<%= form_tag home_search_path, method: :get, data: { controller: "search" } do |form| %>
<div class="relative">
<div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">
<svg class="w-4 h-4 text-gray-500 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"/>
</svg>
</div>
<%= text_field_tag :q, params[:q], data: { "search-target": "query" }, class: "block w-full p-4 ps-10 text-sm text-gray-900 border border-gray-300 rounded-t-lg rounded-b-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500", placeholder: "Search", required: true %>
<div id="results" data-search-target="results" class="absolute z-10 w-full mt-0 shadow bg-gray-50 rounded-b-lg shadow-lg dark:bg-gray-800">
<!-- here be results -->
</div>
<%= submit_tag "Search", class: "text-white absolute end-2.5 bottom-2.5 bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" %>
</div>
<% end %>
<% @results.each do |result| %>
<a href="<%= result["url"] %>" class="flex">
<div class="text-lg text-bold flex-grow hover:bg-blue-100 m-3"><%= result["name"] %></div>
</div>
<% end %>
import { Controller } from "@hotwired/stimulus";
// Connects to data-controller="search"
export default class extends Controller {
static targets = ["query", "results"];
static values = { enabledIndex: Number };
connect() {
this.queryTarget.addEventListener("keydown", (e) => {
var currentValue = this.queryTarget.value;
if (e.key === "Backspace") {
currentValue = currentValue.slice(0, -1);
} else if (e.key === "ArrowDown") {
this.enabledIndexValue += 1;
e.preventDefault();
this.update();
return;
} else if (e.key === "ArrowUp") {
this.enabledIndexValue -= 1;
e.preventDefault();
this.update();
return;
} else if (e.key === "Escape") {
this.enabledIndexValue = null;
this.queryTarget.value = "";
currentValue = "";
e.preventDefault();
} else if (e.key === "Enter") {
var links = this.resultsTarget.querySelectorAll("a");
links[this.enabledIndexValue % links.length].click();
e.preventDefault();
return;
} else {
currentValue += e.key;
}
var fullUrl = this.element.action + "?q=" + currentValue;
fetch(fullUrl, {
method: "GET",
credentials: "same-origin",
headers: {
"X-CSRF-Token": this.getMetaValue("csrf-token"),
"X-Requested-With": "XMLHttpRequest",
Accept: "text/html",
"Content-Type": "text/plain",
},
})
.then(function (response) {
return response.text();
})
.then((html) => {
this.resultsTarget.innerHTML = html;
this.update();
})
.catch((error) => {
console.error(error);
});
});
}
update() {
var links = this.resultsTarget.querySelectorAll("a");
links.forEach((link) => {
link.classList.remove("bg-blue-100");
});
console.info(this.enabledIndexValue);
if (this.enabledIndexValue !== null && this.enabledIndexValue >= 0) {
links[this.enabledIndexValue % links.length].classList.add("bg-blue-100");
}
}
getMetaValue(name) {
const element = document.head.querySelector(`meta[name="${name}"]`);
return element.getAttribute("content");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment