Skip to content

Commit

Permalink
feat(search): support different search index types (#145)
Browse files Browse the repository at this point in the history
* add support for different search index types: `content | summary | heading | title`
* resolves #139
  • Loading branch information
imfing authored Oct 21, 2023
1 parent 88b0f1b commit 93cb788
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 27 deletions.
9 changes: 8 additions & 1 deletion assets/json/search-data.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
{{/* FlexSearch Index Data */}}
{{- $indexType := site.Params.search.flexsearch.index | default "content" -}}

{{- if not (in (slice "content" "summary" "heading" "title" ) $indexType) -}}
{{- errorf "unknown flexsearch index type: %s" $indexType -}}
{{- end -}}

{{- $pages := where .Site.Pages "Kind" "in" (slice "page" "section") -}}
{{- $pages = where $pages "Params.excludeSearch" "!=" true -}}
{{- $pages = where $pages "Content" "!=" "" -}}
Expand All @@ -7,7 +14,7 @@
{{- range $index, $page := $pages -}}
{{- $pageTitle := $page.LinkTitle | default $page.File.BaseFileName -}}
{{- $pageLink := $page.RelPermalink -}}
{{- $data := partial "utils/fragments" $page -}}
{{- $data := partial "utils/fragments" (dict "context" $page "type" $indexType) -}}
{{- $output = $output | merge (dict $pageLink (dict "title" $pageTitle "data" $data)) -}}
{{- end -}}

Expand Down
31 changes: 31 additions & 0 deletions exampleSite/content/docs/guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,37 @@ By default, the page width is set to `normal`.

Similarly, the width of the navbar and footer can be customized by the `params.navbar.width` and `params.footer.width` parameters.

### Search Index

Full-text search powered by [FlexSearch](https://github.com/nextapps-de/flexsearch) is enabled by default.
To customize the search index, set the `params.search.flexsearch.index` parameter in the config file:

```yaml {filename="hugo.yaml"}
params:
# Search
search:
enable: true
type: flexsearch
flexsearch:
# index page by: content | summary | heading | title
index: content
```

available options for `flexsearch.index`:
- `content` - full content of the page (default)
- `summary` - summary of the page, see [Hugo Content Summaries](https://gohugo.io/content-management/summaries/) for more details
- `heading` - level 1 and level 2 headings
- `title` - only include the page title

To exclude a page from the search index, set the `excludeSearch: true` in the front matter of the page:

```yaml {filename="content/docs/guide/configuration.md"}
---
title: Configuration
excludeSearch: true
---
```

### Google Analytics

Expand Down
7 changes: 7 additions & 0 deletions exampleSite/hugo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,15 @@ params:
displayUpdatedDate: true
dateFormat: "January 2, 2006"

# Search
# flexsearch is enabled by default
search:
enable: true
type: flexsearch

flexsearch:
# index page by: content | summary | heading | title
index: content

editURL:
enable: true
Expand Down
22 changes: 14 additions & 8 deletions layouts/partials/scripts.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,22 @@
{{- end -}}
<script defer src="{{ $scripts.RelPermalink }}" integrity="{{ $scripts.Data.Integrity }}"></script>

{{/* FlexSearch */}}

{{/* Search */}}
{{- if (site.Params.search.enable | default true) -}}
{{- $jsSearchScript := printf "%s.search.js" .Language.Lang -}}
{{- $jsSearch := resources.Get "js/flexsearch.js" | resources.ExecuteAsTemplate $jsSearchScript . -}}
{{- if hugo.IsProduction -}}
{{- $jsSearch = $jsSearch | minify | fingerprint -}}
{{- $searchType := site.Params.search.type | default "flexsearch" -}}
{{- if eq $searchType "flexsearch" -}}
{{- $jsSearchScript := printf "%s.search.js" .Language.Lang -}}
{{- $jsSearch := resources.Get "js/flexsearch.js" | resources.ExecuteAsTemplate $jsSearchScript . -}}
{{- if hugo.IsProduction -}}
{{- $jsSearch = $jsSearch | minify | fingerprint -}}
{{- end -}}
{{- $flexSearchJS := resources.Get "lib/flexsearch/flexsearch.bundle.min.js" | fingerprint -}}
<script defer src="{{ $flexSearchJS.RelPermalink }}" integrity="{{ $flexSearchJS.Data.Integrity }}"></script>
<script defer src="{{ $jsSearch.RelPermalink }}" integrity="{{ $jsSearch.Data.Integrity }}"></script>
{{- else -}}
{{- warnf `search type "%s" is not supported` $searchType -}}
{{- end -}}
{{- $flexSearchJS := resources.Get "lib/flexsearch/flexsearch.bundle.min.js" | fingerprint -}}
<script defer src="{{ $flexSearchJS.RelPermalink }}" integrity="{{ $flexSearchJS.Data.Integrity }}"></script>
<script defer src="{{ $jsSearch.RelPermalink }}" integrity="{{ $jsSearch.Data.Integrity }}"></script>
{{- end -}}

{{/* Mermaid */}}
Expand Down
53 changes: 35 additions & 18 deletions layouts/partials/utils/fragments.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{{/* Split page raw content into fragments */}}
{{ $page := . }}
{{ $page := .context }}
{{ $type := .type | default "content" }}

{{ $headingKeys := slice }}
{{ $headingTitles := slice }}
Expand All @@ -22,24 +23,40 @@
{{ $len := len $headingKeys }}
{{ $data := dict }}

{{ if eq $len 0 }}
{{ $data = $data | merge (dict "" $page.Plain) }}
{{ else }}
{{ range seq $len }}
{{ $i := sub $len . }}
{{ $headingKey := index $headingKeys $i }}
{{ $headingTitle := index $headingTitles $i }}

{{ if eq $i 0 }}
{{ $data = $data | merge (dict $headingKey ($content | markdownify | plainify)) }}
{{ else }}
{{ $parts := split $content (printf "\n%s\n" $headingTitle) }}
{{ $lastPart := index $parts (sub (len $parts) 1) }}

{{ $data = $data | merge (dict $headingKey ($lastPart | markdownify | plainify)) }}
{{ $content = strings.TrimSuffix $lastPart $content }}
{{ $content = strings.TrimSuffix (printf "\n%s\n" $headingTitle) $content }}
{{ if eq $type "content" }}
{{/* Include full content of the page */}}
{{ if eq $len 0 }}
{{ $data = $data | merge (dict "" ($page.Plain | htmlUnescape | chomp)) }}
{{ else }}
{{/* Split the raw content from bottom to top */}}
{{ range seq $len }}
{{ $i := sub $len . }}
{{ $headingKey := index $headingKeys $i }}
{{ $headingTitle := index $headingTitles $i }}

{{ if eq $i 0 }}
{{ $data = $data | merge (dict $headingKey ($content | markdownify | plainify | htmlUnescape | chomp)) }}
{{ else }}
{{ $parts := split $content (printf "\n%s\n" $headingTitle) }}
{{ $lastPart := index $parts (sub (len $parts) 1) }}

{{ $data = $data | merge (dict $headingKey ($lastPart | markdownify | plainify | htmlUnescape | chomp)) }}
{{ $content = strings.TrimSuffix $lastPart $content }}
{{ $content = strings.TrimSuffix (printf "\n%s\n" $headingTitle) $content }}
{{ end }}
{{ end }}
{{ end }}
{{ else if (eq $type "heading" ) }}
{{/* Put heading keys with empty content to the data object */}}
{{ $data = dict "" "" }}
{{ range $headingKeys }}
{{ $data = $data | merge (dict . "") }}
{{ end }}
{{ else if (eq $type "title") }}
{{/* Use empty data object since title is included in search-data.json */}}
{{ $data = $data | merge (dict "" "") }}
{{ else if (eq $type "summary" ) }}
{{ $data = $data | merge (dict "" ($page.Summary | plainify | htmlUnescape | chomp)) }}
{{ end }}

{{ return $data }}

0 comments on commit 93cb788

Please sign in to comment.