diff options
-rw-r--r-- | frontend/helper.ts | 4 | ||||
-rw-r--r-- | frontend/main.ts | 2 | ||||
-rw-r--r-- | frontend/query.ts | 3 | ||||
-rw-r--r-- | frontend/search.ts | 4 | ||||
-rw-r--r-- | frontend/start.ts | 53 | ||||
-rw-r--r-- | frontend/style.sass | 3 | ||||
-rw-r--r-- | frontend/submit.ts | 12 |
7 files changed, 53 insertions, 28 deletions
diff --git a/frontend/helper.ts b/frontend/helper.ts index 2ecfc35..6e7ca5c 100644 --- a/frontend/helper.ts +++ b/frontend/helper.ts @@ -17,7 +17,7 @@ function apply_opts<E extends HTMLElement>(e: E, o: Opts<E>) { if (o.onchange) e.onchange = () => o.onchange!(e) if (o.for) (e as unknown as HTMLLabelElement).htmlFor = o.for if (o.type && e instanceof HTMLInputElement) e.type = o.type - if (o.href && e instanceof HTMLAnchorElement) e.href = o.href; + if (o.href && e instanceof HTMLAnchorElement) e.href = o.href if (typeof o?.class == "string") e.classList.add(o.class) if (typeof o?.class == "object") e.classList.add(...o.class) } @@ -26,7 +26,7 @@ export function e<K extends keyof HTMLElementTagNameMap>(name: K, opts: Opts<HTM const el = document.createElement(name) apply_opts(el, opts) for (const c of children) { - if (typeof c == "string") el.textContent += c; + if (typeof c == "string") el.textContent += c else el.append(c) } return el diff --git a/frontend/main.ts b/frontend/main.ts index 6b92616..7f1041a 100644 --- a/frontend/main.ts +++ b/frontend/main.ts @@ -1,5 +1,5 @@ /// <reference lib="dom" /> -import { load_bangs, process_query } from "./query.ts"; +import { load_bangs, process_query } from "./query.ts" import { add_page_content } from "./ui.ts" load_bangs() diff --git a/frontend/query.ts b/frontend/query.ts index d8a2d25..37f62f4 100644 --- a/frontend/query.ts +++ b/frontend/query.ts @@ -1,10 +1,9 @@ import { status } from "./ui.ts" -// TODO embed this information into bangs.js const ENGINE_PINNED: Set<string> = new Set(["ddg", "ec", "qwl", "sp"]) interface Bangs { [key: string]: { url: string, name?: string, pinned?: boolean } | undefined } -export let bangs: Promise<Bangs>; +export let bangs: Promise<Bangs> export function load_bangs() { status("info", "Loading bangs...") bangs = new Promise(r => { diff --git a/frontend/search.ts b/frontend/search.ts index 1d28f58..3e510cb 100644 --- a/frontend/search.ts +++ b/frontend/search.ts @@ -1,5 +1,5 @@ -import { e } from "./helper.ts"; -import { bangs, process_query } from "./query.ts"; +import { e } from "./helper.ts" +import { bangs, process_query } from "./query.ts" import { status } from "./ui.ts" export function section_info_search() { diff --git a/frontend/start.ts b/frontend/start.ts index 838fd7c..1c02192 100644 --- a/frontend/start.ts +++ b/frontend/start.ts @@ -1,6 +1,7 @@ -import { e } from "./helper.ts"; -import { bangs } from "./query.ts"; +import { e } from "./helper.ts" +import { bangs } from "./query.ts" import { status } from "./ui.ts" +import Fuse from "https://cdn.jsdelivr.net/npm/fuse.js@6.6.2/dist/fuse.esm.js" export function section_info_start() { return e("section", { class: "info" }, @@ -18,7 +19,7 @@ export function section_info_start() { export function section_engine_select() { const select = async (e: string) => { - const engine = e.toLowerCase(); + const engine = e.toLowerCase() if (!(await bangs)[engine]) return status("error", `Engine ${JSON.stringify(e)} does not exist.`) window.location.hash = `#${e}` } @@ -30,19 +31,20 @@ export function section_engine_select() { } }) + + const submit = e("button", {}, "Select") + submit.addEventListener("click", () => select(input.value)) + const searchResults = e("ul", {class: "dropdown"}) - const input = e("input", {type: "text"}) + const input = e("input", {type: "search"}) input.addEventListener("keydown", ev => { if (ev.code == "Enter") select(input.value) }) input.addEventListener("keyup", _ => { - setSearchResults(searchResults, input) + setSearchResults(searchResults, input, submit) }) - const submit = e("button", {}, "Select") - submit.addEventListener("click", () => select(input.value)) - const manualInput = e("div", {id: "engine-select-manual"}, e("label", {}, "Search engines:"), input, @@ -57,26 +59,49 @@ export function section_engine_select() { ) } -function setSearchResults(ul, input) { - bangs.then(bangs => { +// TODO fuse is a bit slow; this search function may hinder fast typing +let bangsSearch: Promise<any> = undefined; + +function setSearchResults(ul, input, submit) { + if (bangsSearch === undefined) { + bangsSearch = bangs.then(bangs => { + let searchSpace = [] + for (let k in bangs) { + searchSpace.push({ + bang: k, + name: bangs[k].name, + url: bangs[k].url + }) + } + return new Fuse(searchSpace, { + keys: ["bang", "name"], + minMatchCharLength: 3 + }) + }) + } + + bangsSearch.then(fuse => { ul.innerHTML = "" let results = bangs[input.value] ? [bangs[input.value]] : [] + results = fuse.search(input.value).slice(0, 5) if (results.length === 0) ul.style.display = "none" else { ul.style.display = "flex" for (const r of results) { + const it = r.item + const li = e("li", {}, - e("p", {class: "name"}, r.name), - e("p", {class: "bang"}, "TODO")) + e("p", {class: "name"}, it.name), + e("p", {class: "bang"}, it.bang)) li.addEventListener("click", () => { - input.value = "TODO" + input.value = it.bang + submit.click() }) ul.appendChild(li) } - console.log(ul) } }) } diff --git a/frontend/style.sass b/frontend/style.sass index e8606d5..36fda60 100644 --- a/frontend/style.sass +++ b/frontend/style.sass @@ -64,11 +64,12 @@ section.engine-select position: absolute display: none margin: 0 + margin-top: -2px padding: 0 + max-width: 30em background-color: $dark background-color: black border: 0.15em solid $light - border-top: 0 border-radius: 0.5em cursor: pointer li diff --git a/frontend/submit.ts b/frontend/submit.ts index a380998..e08e890 100644 --- a/frontend/submit.ts +++ b/frontend/submit.ts @@ -1,9 +1,9 @@ -import { e } from "./helper.ts"; -import { bangs } from "./query.ts"; -import { status } from "./ui.ts"; +import { e } from "./helper.ts" +import { bangs } from "./query.ts" +import { status } from "./ui.ts" export function section_submit() { - let skipped_warn = false; + let skipped_warn = false const submit_button = e("button", {}, "Submit") const onchange = () => { skipped_warn = false; submit_button.textContent = "Submit" } const bang_input = e("input", { id: "i-bang", type: "text", onchange }) @@ -13,7 +13,7 @@ export function section_submit() { submit_button.addEventListener("click", async () => { const [bang, url, email, name] = [bang_input.value, url_input.value, email_input.value, name_input.value] - const w = []; + const w = [] if (!url.includes("{{{s}}}")) w.push("URL does not include {{{s}}} pattern") if ((await bangs)[bang]) w.push("Bang already exists, it will be overwritten") if (!/^[A-Za-z0-9_-]+$/g.test(bang)) w.push("Bang has uncommon characters") @@ -52,7 +52,7 @@ export function section_submit() { } async function submit_bang(submission: { bang: string, url: string, name: string, email: string }) { - status("info", "Submitting bang..."); + status("info", "Submitting bang...") const r = await fetch(`/submitBang`, { method: "POST", |