feat: add optional page description to search (#550)
Add optional page description to the search result list. The feature can be enabled by `geekdocSearchShowDescription=true` and is disabled by default. The max length of the description is set to `55` and will be truncated automatically if the limit is exceeded.
This commit is contained in:
parent
d82d05fffc
commit
fb905bd6c1
12 changed files with 87 additions and 91 deletions
|
@ -3,5 +3,6 @@
|
||||||
{
|
{
|
||||||
"dataFile": {{ $searchData.RelPermalink | jsonify }},
|
"dataFile": {{ $searchData.RelPermalink | jsonify }},
|
||||||
"indexConfig": {{ .Site.Params.GeekdocSearchConfig | jsonify }},
|
"indexConfig": {{ .Site.Params.GeekdocSearchConfig | jsonify }},
|
||||||
"showParent": {{ if .Site.Params.GeekdocSearchShowParent }}true{{ else }}false{{ end }}
|
"showParent": {{ if .Site.Params.GeekdocSearchShowParent }}true{{ else }}false{{ end }},
|
||||||
|
"showDescription": {{ if .Site.Params.GeekdocSearchshowDescription }}true{{ else }}false{{ end }}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
"href": "{{ $page.RelPermalink }}",
|
"href": "{{ $page.RelPermalink }}",
|
||||||
"title": {{ (partial "utils/title" $page) | jsonify }},
|
"title": {{ (partial "utils/title" $page) | jsonify }},
|
||||||
"parent": {{ with $page.Parent }}{{ (partial "utils/title" .) | jsonify }}{{ else }}""{{ end }},
|
"parent": {{ with $page.Parent }}{{ (partial "utils/title" .) | jsonify }}{{ else }}""{{ end }},
|
||||||
"content": {{ $page.Plain | jsonify }}
|
"content": {{ $page.Plain | jsonify }},
|
||||||
|
"description": {{ $page.Summary | plainify | jsonify }}
|
||||||
}
|
}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,6 +14,7 @@ geekdocEditPath: edit/main/exampleSite
|
||||||
|
|
||||||
geekdocSearch: true
|
geekdocSearch: true
|
||||||
geekdocSearchShowParent: true
|
geekdocSearchShowParent: true
|
||||||
|
geekdocSearchShowDescription: true
|
||||||
|
|
||||||
geekdocLegalNotice: https://thegeeklab.de/legal-notice/#contact-information
|
geekdocLegalNotice: https://thegeeklab.de/legal-notice/#contact-information
|
||||||
geekdocPrivacyPolicy: https://thegeeklab.de/legal-notice/#privacy-policy
|
geekdocPrivacyPolicy: https://thegeeklab.de/legal-notice/#privacy-policy
|
||||||
|
|
|
@ -5,13 +5,12 @@
|
||||||
type="text"
|
type="text"
|
||||||
id="gdoc-search-input"
|
id="gdoc-search-input"
|
||||||
class="gdoc-search__input"
|
class="gdoc-search__input"
|
||||||
placeholder="{{ i18n "form_placeholder_search" }}"
|
placeholder="{{ i18n "form_placeholder_search" }}..."
|
||||||
aria-label="{{ i18n "form_placeholder_search" }}"
|
aria-label="{{ i18n "form_placeholder_search" }}"
|
||||||
maxlength="64"
|
maxlength="64"
|
||||||
data-site-base-url="{{ .Site.BaseURL }}"
|
data-site-base-url="{{ .Site.BaseURL }}"
|
||||||
data-site-lang="{{ .Site.Language.Lang }}"
|
data-site-lang="{{ .Site.Language.Lang }}"
|
||||||
/>
|
/>
|
||||||
<div class="gdoc-search__spinner spinner hidden"></div>
|
|
||||||
<ul id="gdoc-search-results" class="gdoc-search__list"></ul>
|
<ul id="gdoc-search-results" class="gdoc-search__list"></ul>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
1
package-lock.json
generated
1
package-lock.json
generated
|
@ -13,6 +13,7 @@
|
||||||
"clipboard": "2.0.11",
|
"clipboard": "2.0.11",
|
||||||
"flexsearch": "0.7.31",
|
"flexsearch": "0.7.31",
|
||||||
"katex": "0.16.3",
|
"katex": "0.16.3",
|
||||||
|
"lodash": "4.17.21",
|
||||||
"mermaid": "9.2.2",
|
"mermaid": "9.2.2",
|
||||||
"store2": "2.14.2"
|
"store2": "2.14.2"
|
||||||
},
|
},
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
"clipboard": "2.0.11",
|
"clipboard": "2.0.11",
|
||||||
"flexsearch": "0.7.31",
|
"flexsearch": "0.7.31",
|
||||||
"katex": "0.16.3",
|
"katex": "0.16.3",
|
||||||
|
"lodash": "4.17.21",
|
||||||
"mermaid": "9.2.2",
|
"mermaid": "9.2.2",
|
||||||
"store2": "2.14.2"
|
"store2": "2.14.2"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
/**
|
|
||||||
* Part of [Canivete](http://canivete.leofavre.com/#deepgroupby)
|
|
||||||
*
|
|
||||||
* Groups the contents of an array by one or more iteratees.
|
|
||||||
* Unlike Lodash [`groupBy()`](https://lodash.com/docs/4.17.4#groupBy),
|
|
||||||
* this function can create nested groups, but cannot receive
|
|
||||||
* strings for iteratees.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const groupBy = (e, ...t) => {
|
|
||||||
let r = e.map((e) => t.map((t) => t(e))),
|
|
||||||
a = {}
|
|
||||||
return (
|
|
||||||
r.forEach((t, r) => {
|
|
||||||
let l = (_simpleAt(a, t) || []).concat([e[r]])
|
|
||||||
_simpleSet(a, t, l)
|
|
||||||
}),
|
|
||||||
a
|
|
||||||
)
|
|
||||||
},
|
|
||||||
_isPlainObject = (e) => null != e && "object" == typeof e && e.constructor == Object,
|
|
||||||
_parsePath = (e) => (Array.isArray(e) ? e : `${e}`.split(".")),
|
|
||||||
_simpleAt = (e, t) =>
|
|
||||||
_parsePath(t).reduce((e, t) => (null != e && e.hasOwnProperty(t) ? e[t] : void 0), e),
|
|
||||||
_simpleSet = (e, t, r) =>
|
|
||||||
_parsePath(t).reduce((e, t, a, l) => {
|
|
||||||
let s = a === l.length - 1
|
|
||||||
return (
|
|
||||||
(e.hasOwnProperty(t) && (s || _isPlainObject(e[t]))) || (e[t] = {}), s ? (e[t] = r) : e[t]
|
|
||||||
)
|
|
||||||
}, e)
|
|
|
@ -1,4 +1,5 @@
|
||||||
const { groupBy } = require("./groupBy")
|
const groupBy = require("lodash/groupBy")
|
||||||
|
const truncate = require("lodash/truncate")
|
||||||
const { FlexSearch } = require("flexsearch/dist/flexsearch.compact")
|
const { FlexSearch } = require("flexsearch/dist/flexsearch.compact")
|
||||||
const { Validator } = require("@cfworker/json-schema")
|
const { Validator } = require("@cfworker/json-schema")
|
||||||
|
|
||||||
|
@ -19,6 +20,9 @@ document.addEventListener("DOMContentLoaded", function (event) {
|
||||||
},
|
},
|
||||||
showParent: {
|
showParent: {
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
|
},
|
||||||
|
showDescription: {
|
||||||
|
type: "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
@ -58,8 +62,8 @@ function init(input, searchConfig) {
|
||||||
|
|
||||||
indexCfg.document = {
|
indexCfg.document = {
|
||||||
key: "id",
|
key: "id",
|
||||||
index: ["title", "content"],
|
index: ["title", "content", "description"],
|
||||||
store: ["title", "href", "parent"]
|
store: ["title", "href", "parent", "description"]
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = new FlexSearch.Document(indexCfg)
|
const index = new FlexSearch.Document(indexCfg)
|
||||||
|
@ -75,7 +79,7 @@ function init(input, searchConfig) {
|
||||||
function search(input, results, searchConfig) {
|
function search(input, results, searchConfig) {
|
||||||
const searchCfg = {
|
const searchCfg = {
|
||||||
enrich: true,
|
enrich: true,
|
||||||
limit: 10
|
limit: 5
|
||||||
}
|
}
|
||||||
|
|
||||||
while (results.firstChild) {
|
while (results.firstChild) {
|
||||||
|
@ -106,8 +110,12 @@ function search(input, results, searchConfig) {
|
||||||
title = item.appendChild(document.createElement("span")),
|
title = item.appendChild(document.createElement("span")),
|
||||||
subList = item.appendChild(document.createElement("ul"))
|
subList = item.appendChild(document.createElement("ul"))
|
||||||
|
|
||||||
|
if (!section) {
|
||||||
|
title.remove()
|
||||||
|
}
|
||||||
|
title.classList.add("gdoc-search__section")
|
||||||
title.textContent = section
|
title.textContent = section
|
||||||
createLinks(searchHits[section], subList)
|
createLinks(searchHits[section], subList, searchConfig.showDescription)
|
||||||
|
|
||||||
items.push(item)
|
items.push(item)
|
||||||
}
|
}
|
||||||
|
@ -117,7 +125,7 @@ function search(input, results, searchConfig) {
|
||||||
subList = item.appendChild(document.createElement("ul"))
|
subList = item.appendChild(document.createElement("ul"))
|
||||||
|
|
||||||
title.textContent = "Results"
|
title.textContent = "Results"
|
||||||
createLinks(searchHits, subList)
|
createLinks(searchHits, subList, searchConfig.showDescription)
|
||||||
|
|
||||||
items.push(item)
|
items.push(item)
|
||||||
}
|
}
|
||||||
|
@ -133,20 +141,28 @@ function search(input, results, searchConfig) {
|
||||||
* @param {HTMLElement} target Element to which the links should be attatched
|
* @param {HTMLElement} target Element to which the links should be attatched
|
||||||
* @returns {Array} If target is not specified, returns an array of built links
|
* @returns {Array} If target is not specified, returns an array of built links
|
||||||
*/
|
*/
|
||||||
function createLinks(pages, target) {
|
function createLinks(pages, target, showDesc) {
|
||||||
const items = []
|
const items = []
|
||||||
|
|
||||||
for (const page of pages) {
|
for (const page of pages) {
|
||||||
const item = document.createElement("li"),
|
const item = document.createElement("li"),
|
||||||
entry = item.appendChild(document.createElement("span")),
|
a = item.appendChild(document.createElement("a")),
|
||||||
a = entry.appendChild(document.createElement("a"))
|
entry = a.appendChild(document.createElement("span"))
|
||||||
|
|
||||||
entry.classList.add("flex")
|
|
||||||
|
|
||||||
a.href = page.href
|
a.href = page.href
|
||||||
a.textContent = page.title
|
entry.classList.add("gdoc-search__entry--title")
|
||||||
|
entry.textContent = page.title
|
||||||
a.classList.add("gdoc-search__entry")
|
a.classList.add("gdoc-search__entry")
|
||||||
|
|
||||||
|
if (showDesc === true) {
|
||||||
|
const desc = a.appendChild(document.createElement("span"))
|
||||||
|
desc.classList.add("gdoc-search__entry--description")
|
||||||
|
desc.textContent = truncate(page.description, {
|
||||||
|
length: 55,
|
||||||
|
separator: " "
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (target) {
|
if (target) {
|
||||||
target.appendChild(item)
|
target.appendChild(item)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -228,7 +228,6 @@ svg.gdoc-icon {
|
||||||
|
|
||||||
.gdoc-nav {
|
.gdoc-nav {
|
||||||
flex: 0 0 $menu-width;
|
flex: 0 0 $menu-width;
|
||||||
font-size: $font-size-14;
|
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
width: $menu-width;
|
width: $menu-width;
|
||||||
|
@ -329,7 +328,6 @@ svg.gdoc-icon {
|
||||||
}
|
}
|
||||||
|
|
||||||
.gdoc-nav__entry,
|
.gdoc-nav__entry,
|
||||||
.gdoc-search__entry,
|
|
||||||
.gdoc-language__entry {
|
.gdoc-language__entry {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
color: var(--body-font-color);
|
color: var(--body-font-color);
|
||||||
|
@ -349,10 +347,10 @@ svg.gdoc-icon {
|
||||||
.gdoc-language__list {
|
.gdoc-language__list {
|
||||||
background: var(--body-background);
|
background: var(--body-background);
|
||||||
border-radius: $border-radius;
|
border-radius: $border-radius;
|
||||||
box-shadow: 0 1px 3px 0 var(--accent-color), 0 1px 2px 0 var(--accent-color-lite);
|
box-shadow: 0 1px 3px 0 var(--accent-color-dark), 0 1px 2px 0 var(--accent-color);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: $padding-8 !important;
|
padding: $padding-8 $padding-4 !important;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
top: calc(100% + #{$padding-8});
|
top: calc(100% + #{$padding-8});
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
@ -576,8 +574,8 @@ svg.gdoc-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: $padding-8;
|
left: $padding-8;
|
||||||
color: var(--control-icons);
|
color: var(--control-icons);
|
||||||
width: $font-size-16;
|
width: $font-size-20;
|
||||||
height: $font-size-16;
|
height: $font-size-20;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
|
@ -591,33 +589,19 @@ svg.gdoc-icon {
|
||||||
padding: $padding-8;
|
padding: $padding-8;
|
||||||
padding-left: $padding-32;
|
padding-left: $padding-32;
|
||||||
|
|
||||||
border: $border-1 solid var(--accent-color);
|
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||||
|
border: 1px solid transparent;
|
||||||
border-radius: $border-radius;
|
border-radius: $border-radius;
|
||||||
|
|
||||||
background: var(--accent-color-lite);
|
background: var(--accent-color-lite);
|
||||||
color: var(--body-font-color);
|
color: var(--body-font-color);
|
||||||
|
|
||||||
&:required + &__spinner {
|
&:focus {
|
||||||
display: block;
|
outline: none !important;
|
||||||
|
border: 1px solid var(--accent-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__spinner {
|
|
||||||
position: absolute;
|
|
||||||
margin: $padding-8;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
|
|
||||||
width: $padding-16;
|
|
||||||
height: $padding-16;
|
|
||||||
|
|
||||||
border: $border-1 solid transparent;
|
|
||||||
border-top-color: var(--body-font-color);
|
|
||||||
border-radius: 50%;
|
|
||||||
|
|
||||||
@include spin(1s);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__list {
|
&__list {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -625,20 +609,15 @@ svg.gdoc-icon {
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin-top: $padding-8;
|
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
|
||||||
margin: $padding-4 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> li > span {
|
> li > span {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
> li + li {
|
> li + li {
|
||||||
margin-top: $padding-8;
|
margin-top: $padding-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg.gdoc-icon {
|
svg.gdoc-icon {
|
||||||
|
@ -646,6 +625,40 @@ svg.gdoc-icon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: $padding-4 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__entry {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
color: var(--body-font-color);
|
||||||
|
padding: $padding-4 !important;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&.is-active {
|
||||||
|
background: var(--accent-color-lite);
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
.gdoc-search__entry--title {
|
||||||
|
text-decoration-style: dashed !important;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:visited {
|
||||||
|
color: var(--body-font-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--description {
|
||||||
|
font-size: $font-size-14;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:focus-within &__list.has-hits,
|
&:focus-within &__list.has-hits,
|
||||||
&__list.has-hits:active {
|
&__list.has-hits:active {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
--link-color: #{$link-color};
|
--link-color: #{$link-color};
|
||||||
--link-color-visited: #{$link-color-visited};
|
--link-color-visited: #{$link-color-visited};
|
||||||
|
|
||||||
|
--accent-color-dark: #{$gray-300};
|
||||||
--accent-color: #{$gray-200};
|
--accent-color: #{$gray-200};
|
||||||
--accent-color-lite: #{$gray-100};
|
--accent-color-lite: #{$gray-100};
|
||||||
|
|
||||||
|
@ -58,6 +59,7 @@
|
||||||
--link-color: #{$link-color-dark};
|
--link-color: #{$link-color-dark};
|
||||||
--link-color-visited: #{$link-color-visited-dark};
|
--link-color-visited: #{$link-color-visited-dark};
|
||||||
|
|
||||||
|
--accent-color-dark: #{darken($body-background-dark, 6)};
|
||||||
--accent-color: #{darken($body-background-dark, 4)};
|
--accent-color: #{darken($body-background-dark, 4)};
|
||||||
--accent-color-lite: #{darken($body-background-dark, 2)};
|
--accent-color-lite: #{darken($body-background-dark, 2)};
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ $padding-8: 0.5rem !default;
|
||||||
$padding-16: 1rem !default;
|
$padding-16: 1rem !default;
|
||||||
$padding-24: 1.5rem !default;
|
$padding-24: 1.5rem !default;
|
||||||
$padding-32: 2rem !default;
|
$padding-32: 2rem !default;
|
||||||
|
$padding-48: 3rem !default;
|
||||||
$padding-64: 4rem !default;
|
$padding-64: 4rem !default;
|
||||||
$padding-96: 6rem !default;
|
$padding-96: 6rem !default;
|
||||||
|
|
||||||
|
@ -47,13 +48,13 @@ $body-font-color: $gray-800 !default;
|
||||||
$body-font-weight: normal !default;
|
$body-font-weight: normal !default;
|
||||||
$body-min-width: 20rem !default;
|
$body-min-width: 20rem !default;
|
||||||
|
|
||||||
$code-font-color: rgba(95, 95, 95, 1) !default;
|
$code-font-color: rgba(70, 70, 70, 1) !default;
|
||||||
$code-font-color-dark: rgba(185, 185, 185, 1) !default;
|
$code-font-color-dark: rgba(185, 185, 185, 1) !default;
|
||||||
|
|
||||||
$body-background-dark: $gray-800 !default;
|
$body-background-dark: $gray-800 !default;
|
||||||
$body-font-color-dark: $gray-100 !default;
|
$body-font-color-dark: $gray-100 !default;
|
||||||
|
|
||||||
$container-max-width: 80rem !default;
|
$container-max-width: 82rem !default;
|
||||||
|
|
||||||
$main-color: rgba(65, 134, 201, 1) !default;
|
$main-color: rgba(65, 134, 201, 1) !default;
|
||||||
$second-color: rgba(47, 51, 62, 1) !default;
|
$second-color: rgba(47, 51, 62, 1) !default;
|
||||||
|
@ -63,11 +64,11 @@ $body-background-dark: mix(invert($body-background, 75%), $second-color) !defaul
|
||||||
$link-color-dark: rgba(110, 168, 212, 1) !default;
|
$link-color-dark: rgba(110, 168, 212, 1) !default;
|
||||||
$link-color-visited-dark: rgba(186, 142, 240) !default;
|
$link-color-visited-dark: rgba(186, 142, 240) !default;
|
||||||
|
|
||||||
$code-background: lighten($gray-200, 4) !default;
|
$code-background: $gray-100 !default;
|
||||||
$code-background-dark: darken($body-background-dark, 2) !default;
|
$code-background-dark: darken($body-background-dark, 2) !default;
|
||||||
|
|
||||||
$header-height: 3.5rem !default;
|
$header-height: 3.5rem !default;
|
||||||
$menu-width: 16rem !default;
|
$menu-width: 18rem !default;
|
||||||
|
|
||||||
$sm-breakpoint: $menu-width + $body-min-width + 3rem !default;
|
$sm-breakpoint: $menu-width + $body-min-width + 3rem !default;
|
||||||
|
|
||||||
|
|
|
@ -89,12 +89,3 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-width: 4rem;
|
min-width: 4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin spin($duration) {
|
|
||||||
animation: spin $duration ease infinite;
|
|
||||||
@keyframes spin {
|
|
||||||
100% {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue