Created
November 5, 2020 01:24
-
-
Save obie/342db3c594db62f6aecc8b7b1f2b0dca to your computer and use it in GitHub Desktop.
Search Implementation using stimulus, shoelace, and mark.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.spreadsheet--search.grid.grid-flow-col.grid-cols-auto.gap-0.auto-cols-fr.pl-1.pr-8.hidden{ data: { controller: "spreadsheet--search", action: "toggle-search@window->spreadsheet--search#toggleSearch" }} | |
.input.col-span-9.p-2 | |
%sl-input.w-full(placeholder="Search" size="small" clearable pill){ data: { target: "spreadsheet--search.input"}} | |
%sl-icon(name="search" slot="prefix") | |
%sl-dropdown(slot="suffix" placement="bottom-end" hoist){ data: { target: "spreadsheet--search.dropdown"}} | |
%sl-button(slot="trigger" caret type="text" size="small"){ data: { target: "spreadsheet--search.trigger"}} Highlight | |
%sl-menu | |
%sl-menu-item{ data: { target: "spreadsheet--search.higlight"}, checked: true} Highlight | |
%sl-menu-item{ data: { target: "spreadsheet--search.filter"}} Filter | |
.search-results.text-center.p-3{ data: { target: "spreadsheet--search.results"}} | |
0 found | |
.search-actions.text-right.p-2.flex | |
%sl-icon-button(name="caret-up-fill" label="Previous"){ data: { target: "spreadsheet--search.previous" }, class: "w-1/3"} | |
%sl-icon-button(name="caret-down-fill" label="Next"){ data: { target: "spreadsheet--search.next"}, class: "w-1/3"} | |
%sl-icon-button(name="x-circle-fill" label="Close"){ data: { target: "spreadsheet--search.cancel"}, class: "w-1/3"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Controller } from 'stimulus' | |
import Mark from 'mark.js'; | |
import hotkeys from 'hotkeys-js'; | |
export default class extends Controller { | |
static targets = ['input','dropdown', 'trigger', 'filter','highlight','results','next','previous','cancel'] | |
connect() { | |
this.inputTarget.addEventListener("sl-input", this.input.bind(this)) | |
this.inputTarget.addEventListener("sl-clear", this.input.bind(this)) | |
this.dropdownTarget.addEventListener("sl-select", this.selectMode.bind(this)) | |
this.cancelTarget.addEventListener("click", this.cancel.bind(this)) | |
this.previousTarget.addEventListener("click", this.previous.bind(this)) | |
this.nextTarget.addEventListener("click", this.next.bind(this)) | |
this.marker = new Mark(".spreadsheet--sheet .searchable") | |
hotkeys("ctrl+f, command+f", (event, handler) => { | |
event.preventDefault(); | |
this.toggleSearch(); | |
}) | |
} | |
input(event) { | |
const value = event.target.value; | |
this.mark(value) | |
if(this.filterTarget.checked) { | |
this.element.closest(".spreadsheet--sheet").querySelectorAll(".spreadsheet--row").forEach((row) => { | |
if(row.querySelector("mark") || value == "") { | |
row.classList.remove("hidden") | |
} | |
else { | |
row.classList.add("hidden") | |
} | |
}) | |
// remove the rows that don't match | |
} | |
} | |
mark(value) { | |
this.marker.unmark() | |
this.marker.mark(value, | |
{ | |
done: (num) => { | |
this.currentMarkIndex = -1 | |
this.resultsTarget.innerHTML = `${num} found` | |
} | |
} | |
) | |
} | |
currentMarks() { | |
return this.element.closest(".spreadsheet--sheet").querySelectorAll("mark") | |
} | |
selectMode(event) { | |
console.log('selectMode'); | |
const selectedItem = event.detail.item; | |
this.triggerTarget.textContent = selectedItem.textContent; | |
[...this.dropdownTarget.querySelectorAll('sl-menu-item')].map(item => item.checked = item === selectedItem); | |
} | |
previous() { | |
const marks = this.currentMarks(); | |
if(this.currentMarkIndex > 0) { | |
this.currentMarkIndex -= 1 | |
marks.forEach((m) => m.classList.remove("current")) | |
marks[this.currentMarkIndex].classList.add("current") | |
this.resultsTarget.innerHTML = `${this.currentMarkIndex + 1} of ${marks.length} found` | |
} | |
} | |
next() { | |
const marks = this.currentMarks(); | |
if(this.currentMarkIndex < (marks.length - 1)) { | |
this.currentMarkIndex += 1 | |
marks.forEach((m) => m.classList.remove("current")) | |
marks[this.currentMarkIndex].classList.add("current") | |
this.resultsTarget.innerHTML = `${this.currentMarkIndex + 1} of ${marks.length} found` | |
} | |
} | |
cancel() { | |
console.log('cancel'); | |
this.marker.unmark() | |
this.toggleSearch(); | |
} | |
toggleSearch() { | |
this.element.classList.toggle("hidden") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment