add search support using fusejs
This commit is contained in:
parent
844f9fcfa7
commit
ce0ce5be25
14 changed files with 156 additions and 26 deletions
23
README.md
23
README.md
|
@ -1,23 +1,24 @@
|
||||||
# Minima
|
# Minima
|
||||||
|
|
||||||
A clean and minimal Hugo theme porting from [Hexo Minima](https://github.com/adisaktijrs/hexo-theme-minima). Check out the [example site](https://mivinci.github.io/hugo-theme-minima).
|
Minima is a clean and minimal Hugo theme originally ported from [Hexo Minima](https://github.com/adisaktijrs/hexo-theme-minima). Check out the [example site](https://mivinci.github.io/hugo-theme-minima).
|
||||||
|
|
||||||
![screenshot](./images/tn.png)
|
![screenshot](./images/tn.png)
|
||||||
|
|
||||||
> Note that the main branch is in development stage, UI or configuration may vary.
|
> Note that the main branch is in development phase, UI or configuration may vary.
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- [x] Dark mode
|
- [x] 🌗 Dark mode
|
||||||
- [x] Multilingual mode
|
- [x] 📚 Multilingual mode
|
||||||
- [x] Code highlighting - VSCode dark+
|
- [x] 🏳️🌈 Code highlighting - VSCode dark+
|
||||||
- [x] Math - KaTeX
|
- [x] 🔢 Math - KaTeX
|
||||||
- [x] Flowcharts - Mermaid
|
- [x] 💹 Flowcharts - Mermaid
|
||||||
- [x] Comment - Disqus, Utterances, Giscus
|
- [x] 🧑💻 Comment - Disqus, Utterances, Giscus
|
||||||
- [x] Google analytics
|
- [x] 🔎 Search - FuseJS
|
||||||
- [x] External link
|
- [x] 〽️ Google analytics
|
||||||
- [x] RSS
|
- [x] 🔗 External link
|
||||||
|
- [x] ✉️ RSS
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,16 @@ main p a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main .search > input {
|
||||||
|
width: 100%;
|
||||||
|
padding: .5em;
|
||||||
|
font-size: large;
|
||||||
|
border: 2px solid var(--grid);
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: transparent;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes showup {
|
@keyframes showup {
|
||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
--prime: #3170a7;
|
--prime: #3170a7;
|
||||||
--back: #e6dece;
|
--back: #e6dece;
|
||||||
--text: #434343;
|
--text: #434343;
|
||||||
|
--grid: #555;
|
||||||
|
|
||||||
--code-back: #dbd3c1be;
|
--code-back: #dbd3c1be;
|
||||||
--code-text: #24292f;
|
--code-text: #24292f;
|
||||||
|
@ -58,6 +59,7 @@
|
||||||
--prime: #3170a7;
|
--prime: #3170a7;
|
||||||
--back: #ccc;
|
--back: #ccc;
|
||||||
--text: #434343;
|
--text: #434343;
|
||||||
|
--grid: #555;
|
||||||
|
|
||||||
--code-back: #c1c1c1be;
|
--code-back: #c1c1c1be;
|
||||||
--code-text: #24292f;
|
--code-text: #24292f;
|
||||||
|
|
9
assets/js/min/fuse.basic.min.js
vendored
Normal file
9
assets/js/min/fuse.basic.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
24
assets/js/search.js
Normal file
24
assets/js/search.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import * as params from '@params';
|
||||||
|
|
||||||
|
const search_input = document.querySelector("#search-input");
|
||||||
|
const search_result = document.querySelector("#search-result");
|
||||||
|
|
||||||
|
let fuse;
|
||||||
|
|
||||||
|
window.onload = async function() {
|
||||||
|
const data = await fetch("../index.json").then(res => res.json());
|
||||||
|
const opts = params.search.fuse;
|
||||||
|
fuse = new Fuse(data, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
search_input.addEventListener("input", function () {
|
||||||
|
if (!fuse) return;
|
||||||
|
const results = fuse.search(this.value.trim());
|
||||||
|
let html = '';
|
||||||
|
if (results.length > 0) {
|
||||||
|
for (const v of results) {
|
||||||
|
html += `<li><a href="${v.item.permalink}">${v.item.title}</a></li>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
search_result.innerHTML = html;
|
||||||
|
})
|
|
@ -1,6 +1,8 @@
|
||||||
|
import * as params from '@params';
|
||||||
|
|
||||||
export function setup_selectable () {
|
export function setup_selectable () {
|
||||||
const selectable = '{{ .Site.Params.selectable }}'
|
const selectable = params.selectable
|
||||||
if (selectable === 'false') {
|
if (!selectable) {
|
||||||
document.documentElement.style = 'user-select:none'
|
document.documentElement.style = 'user-select:none'
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
const comment = '{{ .Site.Params.comment.provider }}'
|
import * as params from '@params';
|
||||||
const default_theme_config = '{{ .Site.Params.defaultTheme }}'
|
|
||||||
const icon_light = '{{ index .Site.Params.switch 1 }}'
|
const comment = params.comment.provider
|
||||||
const icon_dark = '{{ index .Site.Params.switch 0 }}'
|
const default_theme_config = params.defaulttheme
|
||||||
|
const icon_light = params.switch[1]
|
||||||
|
const icon_dark = params.switch[0]
|
||||||
const THEME_LIGHT = default_theme_config === 'system' ? 'light' : default_theme_config
|
const THEME_LIGHT = default_theme_config === 'system' ? 'light' : default_theme_config
|
||||||
const THEME_DARK = 'dark'
|
const THEME_DARK = 'dark'
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ paginate: 12
|
||||||
theme: hugo-theme-minima
|
theme: hugo-theme-minima
|
||||||
# defaultContentLanguage specifies the default language to use.
|
# defaultContentLanguage specifies the default language to use.
|
||||||
defaultContentLanguage: en
|
defaultContentLanguage: en
|
||||||
# language.x setup
|
# language.xxx setup
|
||||||
languages:
|
languages:
|
||||||
en:
|
en:
|
||||||
languageName: EN # will be displayed in the navbar.
|
languageName: EN # will be displayed in the navbar.
|
||||||
|
@ -97,15 +97,42 @@ params:
|
||||||
reactions: true
|
reactions: true
|
||||||
metadata: false
|
metadata: false
|
||||||
|
|
||||||
|
# search plugin
|
||||||
|
search:
|
||||||
|
enable: true
|
||||||
|
provider: fuse
|
||||||
|
title: Search
|
||||||
|
placeholder: Enter keywords
|
||||||
|
# check out https://fusejs.io
|
||||||
|
fuse:
|
||||||
|
keys:
|
||||||
|
- title
|
||||||
|
- permalink
|
||||||
|
- summary
|
||||||
|
- content
|
||||||
|
distance: 100
|
||||||
|
location: 0
|
||||||
|
threshold: 0.6
|
||||||
|
ignoreLocation: false
|
||||||
|
isCaseSensitive: false
|
||||||
|
includeScore: false
|
||||||
|
includeMatches: false
|
||||||
|
minMatchCharLength: 1
|
||||||
|
shouldSort: true
|
||||||
|
findAllMatches: false
|
||||||
|
|
||||||
|
|
||||||
# menu.main is an array containing what is used as the navigator.
|
# menu.main is an array containing what is used as the navigator.
|
||||||
menu:
|
menu:
|
||||||
main:
|
main:
|
||||||
- identifier: tags
|
- identifier: tags
|
||||||
name: "Tags"
|
name: Tags
|
||||||
weight: 2
|
weight: 1
|
||||||
- identifier: series
|
- identifier: series
|
||||||
name: "Series"
|
name: Series
|
||||||
|
weight: 2
|
||||||
|
- identifier: search
|
||||||
|
name: 🔍
|
||||||
weight: 3
|
weight: 3
|
||||||
|
|
||||||
# taxonomies defines ways to classify yout posts. Below are some presets that
|
# taxonomies defines ways to classify yout posts. Below are some presets that
|
||||||
|
@ -115,6 +142,13 @@ taxonomies:
|
||||||
tag: tags
|
tag: tags
|
||||||
series: series
|
series: series
|
||||||
|
|
||||||
|
# outputs tells Hugo the kind of files to be rendered.
|
||||||
|
outputs:
|
||||||
|
home:
|
||||||
|
- HTML
|
||||||
|
- RSS
|
||||||
|
- JSON
|
||||||
|
|
||||||
# markup.highlight has two keys set to make sure that the syntax highlighting
|
# markup.highlight has two keys set to make sure that the syntax highlighting
|
||||||
# in your posts are rendered correctly, so DO NOT edit them.
|
# in your posts are rendered correctly, so DO NOT edit them.
|
||||||
markup:
|
markup:
|
||||||
|
|
4
exampleSite/content/search.md
Normal file
4
exampleSite/content/search.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: Search
|
||||||
|
layout: search
|
||||||
|
---
|
4
exampleSite/content/search.zh-cn.md
Normal file
4
exampleSite/content/search.zh-cn.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: 搜索
|
||||||
|
layout: search
|
||||||
|
---
|
16
layouts/_default/search.html
Normal file
16
layouts/_default/search.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{{ define "main" }}
|
||||||
|
<main class="container mx-auto">
|
||||||
|
{{- $title := .Site.Params.search.title | default .Title }}
|
||||||
|
{{- $placeholder := .Site.Params.search.placeholder | default .Title }}
|
||||||
|
<h1 class="text-4xl font-extrabold mt-6">{{ $title }}</h1>
|
||||||
|
<p class="text-sm mb-6">Powered by <a href="https://fusejs.io" target="_blank">fuse.js</a>.</p>
|
||||||
|
<div class="search">
|
||||||
|
<input class="mb-4"
|
||||||
|
autofocus autocomplete="off" id="search-input" type="search" placeholder="{{ printf `%s ↵` $placeholder }}">
|
||||||
|
{{ if not .Site.Params.search.enable }}
|
||||||
|
<p>No search plugin is enabled.</p>
|
||||||
|
{{ end }}
|
||||||
|
<ul id="search-result"></ul>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
{{ end }}
|
|
@ -11,8 +11,10 @@
|
||||||
<div>
|
<div>
|
||||||
{{ $paginator := .Paginate (where .Site.RegularPages "Kind" "page") }}
|
{{ $paginator := .Paginate (where .Site.RegularPages "Kind" "page") }}
|
||||||
{{ range $paginator.Pages }}
|
{{ range $paginator.Pages }}
|
||||||
|
{{ if ne .Page.Layout "search" }}
|
||||||
{{ partial "item.html" . }}
|
{{ partial "item.html" . }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
{{ partial "paginator.html" . }}
|
{{ partial "paginator.html" . }}
|
||||||
</div>
|
</div>
|
||||||
{{ if .Site.Params.friends.feeds }}
|
{{ if .Site.Params.friends.feeds }}
|
||||||
|
|
7
layouts/index.json
Normal file
7
layouts/index.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{{- $.Scratch.Add "index" slice -}}
|
||||||
|
{{- range site.RegularPages -}}
|
||||||
|
{{- if ne .Layout "search" -}}
|
||||||
|
{{- $.Scratch.Add "index" (dict "title" .Title "permalink" .Permalink "summary" .Summary "content" .Plain) -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- $.Scratch.Get "index" | jsonify -}}
|
|
@ -1,9 +1,11 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
{{ if hugo.IsProduction }}
|
||||||
{{ template "_internal/opengraph.html" . }}
|
{{ template "_internal/opengraph.html" . }}
|
||||||
{{ template "_internal/twitter_cards.html" . }}
|
{{ template "_internal/twitter_cards.html" . }}
|
||||||
{{ template "_internal/google_analytics.html" . }}
|
{{ template "_internal/google_analytics.html" . }}
|
||||||
|
{{ end }}
|
||||||
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#ffffff">
|
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#ffffff">
|
||||||
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#262d33">
|
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#262d33">
|
||||||
<title>
|
<title>
|
||||||
|
@ -13,14 +15,25 @@
|
||||||
{{ .Site.Title }} - {{ .Title }}
|
{{ .Site.Title }} - {{ .Title }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</title>
|
</title>
|
||||||
|
<!-- favicon -->
|
||||||
{{ $favicon := "favicon.ico" }}
|
{{ $favicon := "favicon.ico" }}
|
||||||
<link rel="shortcut icon" href="{{ $favicon | relURL }}" type="image/x-icon" />
|
<link rel="shortcut icon" href="{{ $favicon | relURL }}" type="image/x-icon" />
|
||||||
|
<!-- styles -->
|
||||||
{{ $options := (dict "targetPath" "minima.css" "outputStyle" "compressed" "enableSourceMap" true) }}
|
{{ $options := (dict "targetPath" "minima.css" "outputStyle" "compressed" "enableSourceMap" true) }}
|
||||||
{{ $style := resources.Get "css/main.scss" | resources.ExecuteAsTemplate "main.scss" . | resources.ToCSS $options }}
|
{{ $style := resources.Get "css/main.scss" | resources.ExecuteAsTemplate "main.scss" . | resources.ToCSS $options | fingerprint }}
|
||||||
<link rel="stylesheet" href="{{ $style.RelPermalink }}">
|
<link rel="stylesheet" href="{{ $style.RelPermalink }}" integrity="{{ $style.Data.Integrity }}">
|
||||||
{{ $options = (dict "targetPath" "minima.js" "minify" true) }}
|
<!-- scripts -->
|
||||||
{{ $js := resources.Get "js/main.js" | js.Build $options | resources.ExecuteAsTemplate "minima.js" . }}
|
{{ $options = (dict "targetPath" "minima.js" "minify" true "params" site.Params) }}
|
||||||
<script defer type="text/javascript" src="{{ $js.RelPermalink }}"></script>
|
{{ $script := resources.Get "js/main.js" | js.Build $options | fingerprint }}
|
||||||
|
<script defer type="text/javascript" src="{{ $script.RelPermalink }}" integrity="{{ $script.Data.Integrity }}"></script>
|
||||||
|
{{ if and .Site.Params.search.enable (eq .Layout "search") }}
|
||||||
|
{{ $options = (dict "minify" true "params" site.Params) }}
|
||||||
|
{{ $search := resources.Get "js/search.js" | js.Build $options}}
|
||||||
|
{{ $fusejs := resources.Get "js/min/fuse.basic.min.js" }}
|
||||||
|
{{ $script := (slice $fusejs $search) | resources.Concat "assets/js/search.js" | fingerprint }}
|
||||||
|
<script defer crossorigin="anonymous" src="{{ $script.RelPermalink }}" integrity="{{ $script.Data.Integrity }}"></script>
|
||||||
|
{{ end }}
|
||||||
|
<!-- i18n -->
|
||||||
{{ if .IsTranslated }}
|
{{ if .IsTranslated }}
|
||||||
{{ range .Translations }}
|
{{ range .Translations }}
|
||||||
<link rel="alternate" hreflang="{{ .Language.Lang }}" href="{{ .Permalink }}" title="{{ .Language.LanguageName }}">
|
<link rel="alternate" hreflang="{{ .Language.Lang }}" href="{{ .Permalink }}" title="{{ .Language.LanguageName }}">
|
||||||
|
|
Loading…
Reference in a new issue