From 7e15316ad67923216b10dce077e98dbe57c09660 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 24 Sep 2021 00:08:37 -0400 Subject: [PATCH] Improve UX and add more page links --- 404.html | 87 ++++++++++++++++++++++++++++++ index.html | 2 +- pages.json | 13 +++-- scripts/fuzzy.js | 134 ++++++++++++++++++++++++++++++----------------- 4 files changed, 183 insertions(+), 53 deletions(-) create mode 100644 404.html diff --git a/404.html b/404.html new file mode 100644 index 0000000..b2961af --- /dev/null +++ b/404.html @@ -0,0 +1,87 @@ + + + + + + + PaulW.XYZ / + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + +
+

Error 404: Not Found

+

+ Uh oh! The page you are looking for does not exist...
+ [Wikipedia] Learn more about HTTP status codes. +

+
+ + + + \ No newline at end of file diff --git a/index.html b/index.html index e8a8176..d6522ee 100644 --- a/index.html +++ b/index.html @@ -74,7 +74,7 @@
-

Using the search bar will clear this message and list responses based on your query.

+

Press any key to clear this message...

This is a draft of the rationale behind writing pages the way I have. I do not like the traditional web conventions so this is where I experiment the most with interfacing elements. The navigation pane-based design works when they are simple and easy to understand. When they get too complex, people rely on using search bars to get where they want. My goal is to find a method to eliminate the visual noise of the complex navigation panes and find a reasonable alternative them while being easy to use.

Page Categorization

The home page or the index page solely acts as a gateway to all the other pages on the site. diff --git a/pages.json b/pages.json index 5e2512b..8fd9ae0 100644 --- a/pages.json +++ b/pages.json @@ -1,7 +1,10 @@ [ - ["Pages", "/pages/"], - ["Resources", "/pages/resources"], - ["Recommended", "/pages/recommended"], - ["Grade Calculator", "/pages/grade-calc/"], - ["GitHub", "https://github.com/lambdapaul"] + {"title":"Pages", "link": "/pages/"}, + {"title":"Resources", "link": "/pages/resources"}, + {"title":"Recommended", "link": "/pages/recommended"}, + {"title":"Grade Calculator", "link": "/pages/grade-calc/"}, + {"title":"GitHub", "link": "https://github.com/lambdapaul"}, + {"title":"GitLab", "link": "https://gitlab.com/lambdapaul"}, + {"title":"Mastodon", "link": "https://mastodon.social/@lambdapaul"}, + {"title":"Keybase", "link": "https://keybase.io/lambdapaul"} ] \ No newline at end of file diff --git a/scripts/fuzzy.js b/scripts/fuzzy.js index a7b5510..76054a1 100644 --- a/scripts/fuzzy.js +++ b/scripts/fuzzy.js @@ -1,19 +1,27 @@ -// good luck reading through this -(function () { - var client = new XMLHttpRequest(); +setTimeout(() => { + let searchField = document.querySelector("#search"); + if (searchField === null) + return; + + let client = new XMLHttpRequest(); client.open("GET", "/pages.json"); client.onreadystatechange = () => { if (client.readyState === 4) fuzzyInit(client.responseText); } client.send(); - document.querySelector("#search").focus(); -})(); + searchField.focus(); +}, 50); function fuzzyInit(pagesFileName) { if (pagesFileName == "") return; - + + let searchField = document.querySelector("#search"); + let resultBlock = document.querySelector("#results"); + if (searchField === null || resultBlock === null) + return; + var pages; try { pages = JSON.parse(pagesFileName); @@ -25,66 +33,97 @@ function fuzzyInit(pagesFileName) { pages.sort(); - document.querySelector("#search") - .addEventListener("keyup", (e) => { - switch (e.code) { - case "Enter": - if (document.querySelector("#results").childNodes[0].href === undefined) - return; - window.location = document.querySelector("#results").childNodes[0].href; - break; - case "ArrowDown": - console.log("S"); - break; - case "ArrowUp": - console.log("W"); - break; - } + searchField.addEventListener("keyup", (e) => { - // help - if (document.querySelector("#search").value === "?" || document.querySelector("#search").value == "help") { - document.querySelector("#results").innerHTML = "Enter a page or directory name. If do not know any, clear the search field to list everything. Using the Enter key would take you to the first page in list, if it is not empty." + let searchValue = searchField.value ? searchField.value.toLowerCase() : ""; + + if (e.code === "Enter") { + if (resultBlock.childNodes === null + || resultBlock.childNodes[0] === null + || resultBlock.childNodes[0].href === undefined) + return; + + window.location = resultBlock.childNodes[0].href; return; } - - // if (document.querySelector("#search").value === ""){ - // document.querySelector("#results").innerHTML = "Try entering something into the input field..."; - // return; - // } + // help + if (searchValue === "?" || searchValue === "help") { + resultBlock.innerHTML = "

Help

Enter a page or directory name.
If do not know any, clear the search field to list everything.
Using the Enter key would take you to the first page in list, if the list is not empty.
Alternatively, use the Up and Down arrow keys to select the page you want and use the Enter key." + return; + } let results = []; - for (const [i, [title, page]] of pages.entries()) { - ret = fuzzySearch(title, document.querySelector("#search").value); + for (const [i, page] of pages.entries()) { + ret = fuzzySearch(page.title, searchValue); if (ret === null) continue; - results.push([ret, page]); + results.push({formatted: ret.formatted, link: page.link, score: ret.score}); } - results.sort((x, y) => {return x[0].second - y[0].second}); + results.sort((x, y) => {return x.score - y.score}); - let output = ""; - for (const [hfRet, rlink] of results) { - output += `
${hfRet.first}
`; + resultBlock.innerHTML = ""; + for (const res of results) { + linkBlock = document.createElement("a"); + linkBlock.classList.add("hyperlink"); + linkBlock.href = res.link; + linkBlock.innerHTML = `
${res.formatted}
`; + resultBlock.appendChild(linkBlock); } - if (output == "") - output = "No matches found." - - document.querySelector("#results").innerHTML = output; + if (results.length <= 0) + resultBlock.innerHTML = "Unknown command or no matching pages found." } ); + + document.body.addEventListener("keyup", (e) => { + if (e.code === "ArrowDown" || e.code === "ArrowUp") { + if (resultBlock.childNodes === null) + return; + + resultNodes = resultBlock.childNodes; + + if (resultNodes.length <= 1) + return; + + let currNode = document.activeElement; + + if (searchField === currNode) { + if (e.code === "ArrowDown") + resultNodes[0].focus(); + else + resultNodes[resultNodes.length - 1].focus(); + return; + } + + if (Array.from(resultNodes).indexOf(currNode) < 0) + return; + + if (e.code === "ArrowDown") + if (currNode.nextElementSibling === null) + searchField.focus(); + else + currNode.nextElementSibling.focus(); + else if (e.code === "ArrowUp") + if (currNode.previousElementSibling === null) + searchField.focus(); + else + currNode.previousElementSibling.focus(); + return; + } + }); } -function fuzzySearch(list, input) { - let search = input.replace(/\s/g, ""); +function fuzzySearch(findIn, find) { + let search = find.replace(/\s/g, ""); search = search.toLowerCase(); - let tokens = list.split(''); + let tokens = findIn.split(''); let pc = 0; let score = 0; for (const [i, ch] of tokens.entries()) { - if (ch.toLowerCase() == search[pc]) { + if (ch.toLowerCase() === search[pc]) { score += i - pc; tokens[i] = `${ch}`; pc++; @@ -92,8 +131,9 @@ function fuzzySearch(list, input) { return null; } } - if (search.length != pc) - return null; + + if (search.length === pc) + return {formatted: tokens.join(''), score: (score / search.length)}; - return {first: tokens.join(''), second: (score / search.length)}; + return null; } \ No newline at end of file