diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2022-03-15 12:03:22 +0300 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2022-03-16 21:16:10 +0300 |
commit | e65e854ffa478edd485fe640c27aa06ec072c135 (patch) | |
tree | e2779d0f659130b5c988821de0021516fb81f561 | |
parent | d3b6d2a214c1af8da9c14d9e54604fc3c8a09def (diff) |
Add search
Fixes #21
-rw-r--r-- | assets/css/components/all.css | 1 | ||||
-rw-r--r-- | assets/css/components/search.css | 5 | ||||
-rw-r--r-- | assets/css/styles.css | 5 | ||||
-rw-r--r-- | assets/js/main/index.js | 83 | ||||
-rw-r--r-- | layouts/partials/sections/common/head.html | 16 | ||||
-rw-r--r-- | layouts/partials/sections/nav/menu.html | 11 | ||||
-rw-r--r-- | layouts/partials/sections/nav/search-results.html | 78 | ||||
-rw-r--r-- | layouts/partials/sections/nav/search.html | 21 | ||||
-rw-r--r-- | tailwind.config.js | 2 |
9 files changed, 207 insertions, 15 deletions
diff --git a/assets/css/components/all.css b/assets/css/components/all.css index 022512e..f94f7e4 100644 --- a/assets/css/components/all.css +++ b/assets/css/components/all.css @@ -6,3 +6,4 @@ @import "highlight.css"; @import "dd.css"; @import "prose.css"; +@import "search.css"; diff --git a/assets/css/components/search.css b/assets/css/components/search.css new file mode 100644 index 0000000..424364b --- /dev/null +++ b/assets/css/components/search.css @@ -0,0 +1,5 @@ + + +.algolia-docsearch-suggestion--highlight { + @apply bg-yellow-50; +}
\ No newline at end of file diff --git a/assets/css/styles.css b/assets/css/styles.css index b6802fc..cbf6ca6 100644 --- a/assets/css/styles.css +++ b/assets/css/styles.css @@ -30,11 +30,6 @@ body { max-width: 90%; } -/* Hide pre-initialized DOM elements. */ -[x-cloak] { - visibility: hidden; -} - /* Combine with classes in skins and skins-pseudo for * many different transition possibilities. */ .bg-animate, diff --git a/assets/js/main/index.js b/assets/js/main/index.js index b761a36..01d9171 100644 --- a/assets/js/main/index.js +++ b/assets/js/main/index.js @@ -3,6 +3,7 @@ import { newNavStore, initColorScheme, bridgeTurboAndAlpine } from "./nav/index" import Alpine from "jslibs/alpinejs/v3/alpinejs/dist/module.esm.js"; import intersect from "jslibs/alpinejs/v3/intersect/dist/module.esm.js"; import persist from "jslibs/alpinejs/v3/persist/dist/module.esm.js"; +import focus from "jslibs/alpinejs/v3/focus/dist/module.esm.js"; // Client state. (function () { @@ -24,13 +25,21 @@ import persist from "jslibs/alpinejs/v3/persist/dist/module.esm.js"; (function () { // Register AlpineJS plugins. { + Alpine.plugin(focus); Alpine.plugin(intersect); Alpine.plugin(persist); } // Register AlpineJS controllers. { - // None for now. + // Register AlpineJS data controllers. + let searchConfig = { + index: "hugodocs", + app_id: "BH4D9OD16A", + api_key: "167e7998590aebda7f9fedcf86bc4a55", + }; + + Alpine.data("searchController", () => newSearchController(searchConfig)); } // Set up AlpineJS stores. @@ -47,3 +56,75 @@ import persist from "jslibs/alpinejs/v3/persist/dist/module.esm.js"; // Start the Turbo-Alpine bridge. bridgeTurboAndAlpine(Alpine); })(); + +// TODO(bep) move out into its own file, also pull params out into config. +function newSearchController(cfg) { + const groupByLvl0 = (array) => { + if (!array) return []; + return array.reduce((result, currentValue) => { + (result[currentValue.hierarchy.lvl0] = result[currentValue.hierarchy.lvl0] || []).push(currentValue); + return result; + }, {}); + }; + + return { + query: "", + open: false, + result: {}, + toggleOpen: function () { + this.open = !this.open; + this.checkOpen(); + }, + checkOpen: function () { + if (!this.open) { + return; + } + this.search(); + this.$nextTick(() => { + this.$refs.input.focus(); + }); + }, + + init: function () { + this.checkOpen(); + return this.$nextTick(() => { + this.$watch("query", () => { + this.search(); + }); + }); + }, + search: function () { + if (!this.query) { + this.result = {}; + return; + } + var queries = { + requests: [ + { + indexName: cfg.index, + params: `query=${encodeURIComponent(this.query)}`, + attributesToHighlight: ["hierarchy", "content"], + attributesToRetrieve: ["hierarchy", "url", "content"], + }, + ], + }; + + const host = `https://${cfg.app_id}-dsn.algolia.net`; + const url = `${host}/1/indexes/*/queries`; + + fetch(url, { + method: "POST", + headers: { + "X-Algolia-Application-Id": cfg.app_id, + "X-Algolia-API-Key": cfg.api_key, + }, + body: JSON.stringify(queries), + }) + .then((response) => response.json()) + .then((data) => { + this.result = groupByLvl0(data.results[0].hits); + //console.log(this.result); + }); + }, + }; +} diff --git a/layouts/partials/sections/common/head.html b/layouts/partials/sections/common/head.html index 0f89f45..fb10d75 100644 --- a/layouts/partials/sections/common/head.html +++ b/layouts/partials/sections/common/head.html @@ -1,13 +1,15 @@ <head> <meta charset="utf-8" /> {{/* TODO1 self host https://fonts.google.com/specimen/Mulish?preview.text_type=custom */}} - <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> - <link href="https://fonts.googleapis.com/css2?family=Mulish:ital,wght@0,300;0,400;0,700;1,400;1,700&display=swap" rel="stylesheet"> - <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> + <link + href="https://fonts.googleapis.com/css2?family=Mulish:ital,wght@0,300;0,400;0,700;1,400;1,700&display=swap" + rel="stylesheet" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> {{/* NOTE: the Site's title, and if there is a page title, that is set too */}} <title> {{ block "title" . }} - {{ with .Title }}{{ . }} | {{ end }}{{ .Site.Title }} + {{ with .Title }}{{ . }} |{{ end }}{{ .Site.Title }} {{ end }} </title> @@ -48,6 +50,12 @@ {{ end }} + <style> + [x-cloak] { + visibility: hidden; + } + </style> + <noscript> <style> .hide-if-no-js { diff --git a/layouts/partials/sections/nav/menu.html b/layouts/partials/sections/nav/menu.html index c600101..affc32a 100644 --- a/layouts/partials/sections/nav/menu.html +++ b/layouts/partials/sections/nav/menu.html @@ -1,5 +1,5 @@ <nav - class="nightwind-prevent nightwind-prevent-block bg-gray-900 flex flex-wrap items-center justify-between p-4 m-0" + class="nightwind-prevent nightwind-prevent-block bg-gray-900 flex flex-wrap items-center justify-between p-4 m-0 z-20" x-data="{ open: false }"> <div class="container mx-auto flex flex-shrink-0 items-center"> <div class="mr-10"> @@ -56,12 +56,15 @@ {{ end }} </div> - <div class="flex items-center space-x-4"> + <div class="flex items-center space-x-3 mr-8"> + {{ partial "sections/nav/search.html" . }} + {{ partial "sections/nav/theme.html" . }} + + </div> + <div class="flex items-center space-x-3"> {{ template "button-social-twitter" }} {{ template "button-social-github" }} </div> - {{ partial "sections/nav/theme.html" . }} - </div> </div> </nav> diff --git a/layouts/partials/sections/nav/search-results.html b/layouts/partials/sections/nav/search-results.html new file mode 100644 index 0000000..6d5c669 --- /dev/null +++ b/layouts/partials/sections/nav/search-results.html @@ -0,0 +1,78 @@ +<div + class="fixed inset-0 overflow-hidden z-20" + :class="{'fixed': open}" + aria-labelledby="slide-over-title" + role="dialog" + aria-modal="true" + @keydown.right="$focus.next()" + @keydown.left="$focus.previous()" + @keydown.esc="open=false" + x-cloak> + <div class="absolute inset-0 overflow-hidden z-20" x-show="open"> + <div class="absolute inset-0" aria-hidden="true"></div> + + <div + class="pointer-events-none fixed inset-y-0 right-0 flex max-w-full pl-10" + @click.outside="open = false"> + <div + class="pointer-events-auto w-screen max-w-md" + x-show="open" + x-transition:enter="transform transition ease-in-out duration-500 sm:duration-700" + x-transition:enter-start="translate-x-full" + x-transition:enter-end="translate-x-0" + x-transition:leave="transform transition ease-in-out duration-500 sm:duration-700" + x-transition:leave-start="translate-x-0" + x-transition:leave-end="translate-x-full"> + <div + class="flex h-full flex-col overflow-y-scroll bg-white py-6 shadow-xl"> + <div class="px-4 sm:px-6"> + <div class="flex items-start justify-between"> + <input + x-model="query" + @click="search()" + type="search" + class="text-black bg-opacity-25 shadow rounded border-0 p-3 w-full" + placeholder="Search the Docs..." + x-ref="input" /> + </div> + </div> + <div class="relative mt-6 flex-1 px-4 sm:px-6"> + <ul role="list" class="divide-y divide-gray-200"> + <template + x-for="[group, entries] in Object.entries(result)" + :key="group"> + <li class="py-4"> + <div class="mb-1" x-text="group"></div> + <template x-for="entry in entries" :key="entry.objectID"> + <a + class="flex flex-nowrap space-x-4 py-2 text-sm leading-5 text-gray-900 hover:bg-gray-50 focus:outline-none focus:bg-gray-50 cursor-pointer transition duration-150 ease-in-out" + :href="entry.url"> + <span + class="w-1/3 text-xs text-right text-gray-500" + x-text="entry.hierarchy.lvl1"> + </span> + <div class="w-2/3"> + <h3 + class="text-md font-bold" + x-html="entry._highlightResult.hierarchy.lvl2 ? entry._highlightResult.hierarchy.lvl2.value :entry._highlightResult.hierarchy.lvl1.value"></h3> + <template + x-if="entry._snippetResult && entry._snippetResult.content"> + <div class="two-lines-ellipsis mt-1"> + <span>…</span> + <span x-html="entry._snippetResult.content.value"> + </span> + <span>…</span> + </div> + </template> + </div> + </a> + </template> + </li> + </template> + </ul> + </div> + </div> + </div> + </div> + </div> +</div> diff --git a/layouts/partials/sections/nav/search.html b/layouts/partials/sections/nav/search.html new file mode 100644 index 0000000..fe47ff6 --- /dev/null +++ b/layouts/partials/sections/nav/search.html @@ -0,0 +1,21 @@ +<div class="relative my-2" x-data="searchController" id="search-main"> + <div> + <button + @click="toggleOpen()" + class="nightwind-prevent inline-flex items-center p-2 border border-transparent rounded-full shadow-sm text-black bg-blue-400 hover:bg-blue-600 hover:text-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-steel-500"> + <svg + xmlns="http://www.w3.org/2000/svg" + class="h-6 w-6" + fill="none" + viewBox="0 0 24 24" + stroke="currentColor" + stroke-width="2"> + <path + stroke-linecap="round" + stroke-linejoin="round" + d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /> + </svg> + </button> + {{ partial "sections/nav/search-results.html" . }} + </div> +</div> diff --git a/tailwind.config.js b/tailwind.config.js index 26d9734..142610f 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -446,7 +446,7 @@ module.exports = { enabled: process.env.HUGO_ENVIRONMENT === "production", content: ["./hugo_stats.json", "./layouts/**/*.html"], options: { - safelist: ["dark", "nightwind"], + safelist: ["dark", "nightwind", "algolia-docsearch-suggestion--highlight"], }, extractors: [ { |