Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ footnoteReturnLinkContents = "^"
[params.author]
name = "Hugo Author"

[outputs]
section = ["JSON", "HTML"]

[[params.nav]]
identifier = "about"
name = "About"
Expand Down Expand Up @@ -127,7 +124,9 @@ If you don't change them, your favicon and icon are my face :)

### Search entire blog posts

You should make `search.md` in the `content` directory.
This theme uses [Pagefind](https://pagefind.app/) for search functionality.

1. First, make `search.md` in the `content` directory:

```
---
Expand All @@ -136,6 +135,21 @@ layout: "search"
---
```

2. After building your Hugo site, run Pagefind to index it:

```bash
hugo
npm run build:search
```

Or if you're using a different output directory, specify it:

```bash
npx pagefind --site <your-output-directory>
```

The Pagefind index will be created in the `pagefind` directory inside your site's output folder.

### TOC

If you want to use TableOfContent, you need to write words greater than 400, and set `true` of the frontmatter `toc`.
Expand Down
33 changes: 0 additions & 33 deletions assets/js/flexsearch.bundle.js

This file was deleted.

7 changes: 0 additions & 7 deletions assets/js/mark.min.js

This file was deleted.

84 changes: 45 additions & 39 deletions assets/js/search.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,22 @@
{{ $searchData := resources.Get "list.json" | resources.ExecuteAsTemplate "search-data.json" . }}
const searchDataURL = '{{ $searchData.RelPermalink }}'

const init = () => {
const searchBox = document.querySelector('#searchBox')
if (searchBox === null) {
return
}

let index = new FlexSearch.Document({
tokenize: 'reverse',
document: {
field: ['title', 'body'],
store: ['title', 'href', 'body']
},
})

fetch(searchDataURL)
.then(pages => pages.json())
.then(pages => {
for(let i = 0; i < pages.length; i++){
index.add(i, pages[i]);
}
})
// Initialize Pagefind
let pagefind = null
const loadPagefind = async () => {
if (!pagefind) {
pagefind = await import('/pagefind/pagefind.js')
await pagefind.options({
excerptLength: 100
})
}
return pagefind
}

searchBox.addEventListener('keyup', function (event) {
searchBox.addEventListener('keyup', async function (event) {
let searchResultsArea = document.querySelector('#searchResults')
let query = event.currentTarget.value

Expand All @@ -33,19 +26,25 @@ const init = () => {
return
}

// Load Pagefind if not already loaded
const pf = await loadPagefind()

// Perform search
const search = await pf.search(query)

// Display search results
renderResults(index.search(query, 10, { enrich: true }));
renderResults(search.results, query)
searchResultsArea.style.display = 'block'
})
}

/**
* Rendering search results
* @param {Object[]} results Array of search results ( fields[] => { field, result[] => { document }} )
* @param {Object[]} results Array of search results from Pagefind
* @param {string} query The search query
*/
const renderResults = (results) => {
const renderResults = async (results, query) => {
const searchResults = document.querySelector('#searchResults')
const query = document.querySelector('#searchBox').value
const BODY_LENGTH = 100

// Clear search result
Expand All @@ -61,35 +60,42 @@ const renderResults = (results) => {
return
}

let arr = results[0].result
if (results.length > 1) {
arr.concat(results[1].result)
}
arr.filter((element, index, self) =>
self.findIndex(e => e.id === element.id) === index)

let instance = new Mark(document.querySelector('#searchResults'))
// Load and render each result
let fragment = document.createDocumentFragment();
arr.forEach((result) => {
for (const result of results) {
const data = await result.data()

let resultPage = document.createElement('div')
resultPage.className = 'searchResultPage'

let resultTitle = document.createElement('a')
resultTitle.className = 'searchResultTitle'
resultTitle.href = result.doc.href
resultTitle.innerHTML = result.doc.title
resultTitle.href = data.url
resultTitle.textContent = data.meta.title || 'Untitled'
resultPage.append(resultTitle)

let resultBody = document.createElement('div')
resultBody.className = 'searchResultBody'
let matchPos = result.doc.body.indexOf(query)
let bodyStartPos = matchPos - BODY_LENGTH / 2 > 0 ? matchPos - BODY_LENGTH / 2 : 0
resultBody.innerHTML = result.doc.body.substr(bodyStartPos, BODY_LENGTH)

// Use Pagefind's excerpt if available, otherwise use content
if (data.excerpt) {
resultBody.innerHTML = data.excerpt
} else if (data.content) {
// Fallback to manual excerpt creation
let content = data.content
let matchPos = content.toLowerCase().indexOf(query.toLowerCase())
if (matchPos !== -1) {
let bodyStartPos = matchPos - BODY_LENGTH / 2 > 0 ? matchPos - BODY_LENGTH / 2 : 0
resultBody.textContent = content.substr(bodyStartPos, BODY_LENGTH)
} else {
resultBody.textContent = content.substr(0, BODY_LENGTH)
}
}

resultPage.append(resultBody)
fragment.append(resultPage)
})
}
searchResults.append(fragment);
instance.mark(query)
}

init();
15 changes: 0 additions & 15 deletions assets/list.json

This file was deleted.

7 changes: 1 addition & 6 deletions layouts/partials/head.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,9 @@
<script defer crossorigin="anonymous" src="{{ $instantpage.RelPermalink }}" integrity="{{ $instantpage.Data.Integrity }}"></script>

{{- if (eq .Layout `search`) -}}
{{ $flexsearch := resources.Get "js/flexsearch.bundle.js" }}
<script defer crossorigin="anonymous" src="{{ $flexsearch.RelPermalink }}" integrity="{{ $flexsearch.Data.Integrity }}"></script>

{{ $mark := resources.Get "js/mark.min.js" }}
{{ $basesearch := resources.Get "js/search.js" }}

{{ $searchJSFile := printf "js/%s.search.js" .Language.Lang }}
{{ $search := (slice $mark $basesearch) | resources.Concat "js/search.js" | resources.ExecuteAsTemplate $searchJSFile . | resources.Fingerprint }}
{{ $search := $basesearch | resources.ExecuteAsTemplate $searchJSFile . | resources.Fingerprint }}
<script defer crossorigin="anonymous" src="{{ $search.RelPermalink }}" integrity="{{ $search.Data.Integrity }}"></script>
{{- end -}}

Expand Down
Loading
Loading