Ran prettier

This commit is contained in:
Simon Willison 2025-10-20 16:03:22 -07:00
commit 5b0baf7cd5

View file

@ -1,7 +1,7 @@
class NavigationSearch extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.attachShadow({ mode: "open" });
this.selectedIndex = -1;
this.matches = [];
this.debounceTimer = null;
@ -186,42 +186,43 @@ class NavigationSearch extends HTMLElement {
}
setupEventListeners() {
const dialog = this.shadowRoot.querySelector('dialog');
const input = this.shadowRoot.querySelector('.search-input');
const resultsContainer = this.shadowRoot.querySelector('.results-container');
const dialog = this.shadowRoot.querySelector("dialog");
const input = this.shadowRoot.querySelector(".search-input");
const resultsContainer =
this.shadowRoot.querySelector(".results-container");
// Global keyboard listener for "/"
document.addEventListener('keydown', (e) => {
if (e.key === '/' && !this.isInputFocused() && !dialog.open) {
document.addEventListener("keydown", (e) => {
if (e.key === "/" && !this.isInputFocused() && !dialog.open) {
e.preventDefault();
this.openMenu();
}
});
// Input event
input.addEventListener('input', (e) => {
input.addEventListener("input", (e) => {
this.handleSearch(e.target.value);
});
// Keyboard navigation
input.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown') {
input.addEventListener("keydown", (e) => {
if (e.key === "ArrowDown") {
e.preventDefault();
this.moveSelection(1);
} else if (e.key === 'ArrowUp') {
} else if (e.key === "ArrowUp") {
e.preventDefault();
this.moveSelection(-1);
} else if (e.key === 'Enter') {
} else if (e.key === "Enter") {
e.preventDefault();
this.selectCurrentItem();
} else if (e.key === 'Escape') {
} else if (e.key === "Escape") {
this.closeMenu();
}
});
// Click on result item
resultsContainer.addEventListener('click', (e) => {
const item = e.target.closest('.result-item');
resultsContainer.addEventListener("click", (e) => {
const item = e.target.closest(".result-item");
if (item) {
const index = parseInt(item.dataset.index);
this.selectItem(index);
@ -229,7 +230,7 @@ class NavigationSearch extends HTMLElement {
});
// Close on backdrop click
dialog.addEventListener('click', (e) => {
dialog.addEventListener("click", (e) => {
if (e.target === dialog) {
this.closeMenu();
}
@ -241,21 +242,22 @@ class NavigationSearch extends HTMLElement {
isInputFocused() {
const activeElement = document.activeElement;
return activeElement && (
activeElement.tagName === 'INPUT' ||
activeElement.tagName === 'TEXTAREA' ||
activeElement.isContentEditable
return (
activeElement &&
(activeElement.tagName === "INPUT" ||
activeElement.tagName === "TEXTAREA" ||
activeElement.isContentEditable)
);
}
loadInitialData() {
const itemsAttr = this.getAttribute('items');
const itemsAttr = this.getAttribute("items");
if (itemsAttr) {
try {
this.allItems = JSON.parse(itemsAttr);
this.matches = this.allItems;
} catch (e) {
console.error('Failed to parse items attribute:', e);
console.error("Failed to parse items attribute:", e);
this.allItems = [];
this.matches = [];
}
@ -266,7 +268,7 @@ class NavigationSearch extends HTMLElement {
clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(() => {
const url = this.getAttribute('url');
const url = this.getAttribute("url");
if (url) {
// Fetch from API
@ -287,7 +289,7 @@ class NavigationSearch extends HTMLElement {
this.selectedIndex = this.matches.length > 0 ? 0 : -1;
this.renderResults();
} catch (e) {
console.error('Failed to fetch search results:', e);
console.error("Failed to fetch search results:", e);
this.matches = [];
this.renderResults();
}
@ -298,9 +300,10 @@ class NavigationSearch extends HTMLElement {
this.matches = [];
} else {
const lowerQuery = query.toLowerCase();
this.matches = (this.allItems || []).filter(item =>
this.matches = (this.allItems || []).filter(
(item) =>
item.name.toLowerCase().includes(lowerQuery) ||
item.url.toLowerCase().includes(lowerQuery)
item.url.toLowerCase().includes(lowerQuery),
);
}
this.selectedIndex = this.matches.length > 0 ? 0 : -1;
@ -308,18 +311,22 @@ class NavigationSearch extends HTMLElement {
}
renderResults() {
const container = this.shadowRoot.querySelector('.results-container');
const input = this.shadowRoot.querySelector('.search-input');
const container = this.shadowRoot.querySelector(".results-container");
const input = this.shadowRoot.querySelector(".search-input");
if (this.matches.length === 0) {
const message = input.value.trim() ? 'No results found' : 'Start typing to search...';
const message = input.value.trim()
? "No results found"
: "Start typing to search...";
container.innerHTML = `<div class="no-results">${message}</div>`;
return;
}
container.innerHTML = this.matches.map((match, index) => `
container.innerHTML = this.matches
.map(
(match, index) => `
<div
class="result-item ${index === this.selectedIndex ? 'selected' : ''}"
class="result-item ${index === this.selectedIndex ? "selected" : ""}"
data-index="${index}"
role="option"
aria-selected="${index === this.selectedIndex}"
@ -329,13 +336,15 @@ class NavigationSearch extends HTMLElement {
<div class="result-url">${this.escapeHtml(match.url)}</div>
</div>
</div>
`).join('');
`,
)
.join("");
// Scroll selected item into view
if (this.selectedIndex >= 0) {
const selectedItem = container.children[this.selectedIndex];
if (selectedItem) {
selectedItem.scrollIntoView({ block: 'nearest' });
selectedItem.scrollIntoView({ block: "nearest" });
}
}
}
@ -358,11 +367,13 @@ class NavigationSearch extends HTMLElement {
const match = this.matches[index];
if (match) {
// Dispatch custom event
this.dispatchEvent(new CustomEvent('select', {
this.dispatchEvent(
new CustomEvent("select", {
detail: match,
bubbles: true,
composed: true
}));
composed: true,
}),
);
// Navigate to URL
window.location.href = match.url;
@ -372,11 +383,11 @@ class NavigationSearch extends HTMLElement {
}
openMenu() {
const dialog = this.shadowRoot.querySelector('dialog');
const input = this.shadowRoot.querySelector('.search-input');
const dialog = this.shadowRoot.querySelector("dialog");
const input = this.shadowRoot.querySelector(".search-input");
dialog.showModal();
input.value = '';
input.value = "";
input.focus();
// Reset state - start with no items shown
@ -386,16 +397,16 @@ class NavigationSearch extends HTMLElement {
}
closeMenu() {
const dialog = this.shadowRoot.querySelector('dialog');
const dialog = this.shadowRoot.querySelector("dialog");
dialog.close();
}
escapeHtml(text) {
const div = document.createElement('div');
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}
}
// Register the custom element
customElements.define('navigation-search', NavigationSearch);
customElements.define("navigation-search", NavigationSearch);