aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLia Lenckowski <lialenck@protonmail.com>2023-08-14 17:39:18 +0200
committerLia Lenckowski <lialenck@protonmail.com>2023-08-14 17:39:18 +0200
commit44e16504a1605d1d00f202863935767326cd453c (patch)
tree2bad385871dd1b602aff4d55477084ca541cbb0e
parent3df03c42763dccf2993a0a76bdf36e2cbb3674c7 (diff)
downloadfastbangs-44e16504a1605d1d00f202863935767326cd453c.tar
fastbangs-44e16504a1605d1d00f202863935767326cd453c.tar.bz2
fastbangs-44e16504a1605d1d00f202863935767326cd453c.tar.zst
implement searching for engines/bangs
-rw-r--r--frontend/helper.ts4
-rw-r--r--frontend/main.ts2
-rw-r--r--frontend/query.ts3
-rw-r--r--frontend/search.ts4
-rw-r--r--frontend/start.ts53
-rw-r--r--frontend/style.sass3
-rw-r--r--frontend/submit.ts12
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",