Merge branch 'release_v4.2.0'
Some checks failed
sync-2-gitee / sync-2-gitee (push) Failing after 3s

This commit is contained in:
凡梦星尘 2022-08-15 21:58:03 +08:00
commit 0db1dac57f
50 changed files with 1145 additions and 340 deletions

10
.gitignore vendored
View File

@ -3,11 +3,15 @@
exampleSite/* exampleSite/*
# Exclude special files in content folder # Exclude special files in content folder
exampleSite/content/**/
!exampleSite/content !exampleSite/content
exampleSite/content/* !exmapleSite/content/about.md
!exampleSite/content/archives !exampleSite/content/archives
!exampleSite/content/post !exampleSite/content/post
# Exclude special files in data folder
!exampleSite/data
# Exclude special files in static folder # Exclude special files in static folder
!exampleSite/static !exampleSite/static
@ -15,3 +19,7 @@ exampleSite/content/*
!exampleSite/config.yaml !exampleSite/config.yaml
!exampleSite/start.sh !exampleSite/start.sh
data/*
!data/config.yaml
!data/resources.yaml

View File

@ -1 +1 @@
4.1.0 4.2.0

View File

@ -0,0 +1,141 @@
.flinks-block {
.flinks-block-title {
text-align: center;
font-weight: bold;
}
.flinks-list-title {
font-size: 1.25em;
font-weight: bold;
}
.flinks-lists > div:not(:first-child) {
margin-top: 40px;
}
.flinks-list-desc {
font-style: italic;
}
.flinks-list-items {
overflow: auto;
padding: 10px 10px 0;
text-align: center;
.flinks-list-item {
@include mobile() {
display: flex;
justify-content: center;
align-items: center;
}
position: relative;
float: left;
overflow: hidden;
margin: 15px 7px;
width: calc(100% / 3 - 18px);
height: 90px;
border-radius: 8px;
line-height: 17px;
-webkit-transform: translateZ(0);
border: groove 1px var(--highlight-foreground);
box-shadow: .6rem .5rem 0.3rem var(--body-bg-color);
&:hover:before,
&:focus:before,
&:active:before {
-webkit-transform:scale(1);
-moz-transform:scale(1);
-o-transform:scale(1);
-ms-transform:scale(1);
transform: scale(1);
}
&:hover .flinks-item-icon {
margin-left:-10px;
width:0;
}
&:before {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
background: var(--body-bg-color);
content: ' ';
transition: transform .3s ease-out;
transform: scale(0);
}
a {
//color: var(--font-color);
text-decoration: none;
}
.flinks-item-icon {
float: left;
overflow: hidden;
margin: 15px 10px;
width: 60px;
height: 60px;
border-radius: 35px;
border: solid 1px var(--body-bg-color);
-webkit-transition: width .3s ease-out;
-moz-transition: width .3s ease-out;
-o-transition: width .3s ease-out;
-ms-transition: width .3s ease-out;
transition: width .3s ease-out;
img {
width: 100%;
height: 100%;
-webkit-transition: filter 375ms ease-in .2s,-webkit-transform .3s;
-moz-transition: filter 375ms ease-in .2s,-moz-transform .3s;
-o-transition: filter 375ms ease-in .2s,-o-transform .3s;
-ms-transition: filter 375ms ease-in .2s,-ms-transform .3s;
transition: filter 375ms ease-in .2s,transform .3s;
object-fit: cover;
}
}
.flinks-item-name, .flinks-item-desc {
overflow:hidden;
-o-text-overflow:ellipsis;
text-overflow:ellipsis;
white-space:nowrap
}
.flinks-item-name {
padding: 20px 0 0 0;
height: 20px;
font-weight: 700;
font-size: 1em;
font-weight: bold;
@include mobile() {
display: none;
}
}
.flinks-item-desc {
padding: 10px 0;
font-size: .92em;
@include mobile() {
display: none;
}
}
}
}
.flinks-page-desc {
margin-top: 20px;
}
}

View File

@ -3,3 +3,4 @@
@import 'schedule'; @import 'schedule';
@import 'breadcrumb'; @import 'breadcrumb';
@import 'tag-cloud'; @import 'tag-cloud';
@import 'flinks';

View File

@ -18,7 +18,7 @@
.use-motion { .use-motion {
@if $motion_trans_post_block { @if $motion_trans_post_block {
.post-block, .pagination, .comments, .post-comments { .post-block, .flinks-block, .pagination, .comments, .post-comments {
visibility: hidden; visibility: hidden;
} }
} }

View File

@ -76,4 +76,8 @@
width: 100%; width: 100%;
} }
} }
svg {
max-width: 98%;
}
} }

View File

@ -3,7 +3,7 @@
// Fix issue #16 // Fix issue #16
// To do: use `gap` instead of `margin` // To do: use `gap` instead of `margin`
// See https://caniuse.com/flexbox-gap // See https://caniuse.com/flexbox-gap
.post-footer { .post-footer, .flinks-list-footer {
@include flex-column(); @include flex-column();
hr{ hr{

View File

@ -106,6 +106,13 @@
padding: 5px 0; padding: 5px 0;
} }
} }
mark.search-keyword {
background: transparent;
border-bottom: 1px dashed $red;
color: $red;
font-weight: bold;
}
} }
@if $algolia_search_enable { @if $algolia_search_enable {
@ -169,11 +176,4 @@
margin: auto; margin: auto;
} }
} }
mark.search-keyword {
background: transparent;
border-bottom: 1px dashed $red;
color: $red;
font-weight: bold;
}
} }

View File

@ -2,14 +2,29 @@
.highlight { .highlight {
background: var(--highlight-background); background: var(--highlight-background);
margin-bottom: 26px;
.table-container, pre { //TODO Need fixed the copy button show position.
div:first-child {
overflow-x: auto;
}
pre {
position: relative; position: relative;
} }
.table-container table tbody tr { table tbody tr {
background: none; //TODO Fixed the too long code line over
// layout background color.
background: #272822;
} }
/* pre > code span {
white-space: break-spaces;
overflow: hidden;
word-break: break-all;
word-wrap: break-word;
} */
} }
@if $codeblock_copy_btn_enable { @if $codeblock_copy_btn_enable {

View File

@ -6,7 +6,7 @@
} }
pre { pre {
padding: 10px; padding: 18px;
margin: 0; margin: 0;
} }

View File

@ -1,7 +1,7 @@
//@use 'sass:map'; //@use 'sass:map';
@if $note_style != 'disabled' { @if $note_style != 'disabled' {
.post-body .note { .main .note {
$note-icons : $note_icons; $note-icons : $note_icons;
$note-style : $note_style; $note-style : $note_style;

View File

@ -25,7 +25,7 @@
// ================================================== // ==================================================
// Post blocks. // Post blocks.
.main-inner > { .main-inner > {
.sub-menu, .post-block, .tabs-comment, .comments, .post-comments, .pagination { .sub-menu, .post-block, .flinks-block, .tabs-comment, .comments, .post-comments, .pagination {
background: var(--content-bg-color); background: var(--content-bg-color);
border-radius: $border-radius-inner; border-radius: $border-radius-inner;
box-shadow: $box-shadow-inner; box-shadow: $box-shadow-inner;
@ -47,7 +47,7 @@
} }
// Post & Comments blocks. // Post & Comments blocks.
.post-block, .comments, .post-comments { .post-block, .flinks-block, .comments, .post-comments {
padding: $content-desktop-padding; padding: $content-desktop-padding;
} }
@ -91,7 +91,7 @@
} }
} }
.post-block { .post-block, .flinks-block {
// Inside posts blocks content padding (default 40px). // Inside posts blocks content padding (default 40px).
padding: ($content-tablet-padding * 2); padding: ($content-tablet-padding * 2);
} }
@ -119,7 +119,7 @@
} }
} }
.post-block { .post-block, .flinks-block {
// Inside posts blocks content padding (default 40px). // Inside posts blocks content padding (default 40px).
padding: $sidebar-offset; padding: $sidebar-offset;
} }

View File

@ -95,7 +95,7 @@ NexT.motion.middleWares = {
}); });
} }
animate(postblock, '.post-block, .pagination, .post-comments'); animate(postblock, '.post-block,.flinks-block, .pagination, .post-comments');
animate(collheader, '.collection-header'); animate(collheader, '.collection-header');
animate(postheader, '.post-header'); animate(postheader, '.post-header');
animate(postbody, '.post-body'); animate(postbody, '.post-body');

View File

@ -4,7 +4,7 @@ NexT.boot = {};
NexT.boot.registerEvents = function() { NexT.boot.registerEvents = function() {
// NexT.utils.registerScrollPercent(); NexT.utils.registerScrollPercent();
// NexT.utils.registerCanIUseTag(); // NexT.utils.registerCanIUseTag();
// Mobile top menu bar. // Mobile top menu bar.

144
assets/js/third-party/search/algolia.js vendored Normal file
View File

@ -0,0 +1,144 @@
/* global instantsearch, algoliasearch, CONFIG, pjax */
document.addEventListener('DOMContentLoaded', () => {
const algoiajs = NexT.utils.getCDNResource(NexT.CONFIG.algolia.js);
const instantschjs = NexT.utils.getCDNResource(NexT.CONFIG.algolia.instantjs);
NexT.utils.getScript(algoiajs, {});
NexT.utils.getScript(instantschjs, {}).then(() => {
const { indexname, appid, apikey, hits } = NexT.CONFIG.algolia.cfg;
const indexName = indexname;
const search = instantsearch({
indexName,
searchClient: algoliasearch(appid, apikey),
searchFunction: helper => {
if (document.querySelector('.search-input').value) {
helper.search();
}
}
});
const markKeyWords = function(content) {
return content.replaceAll("<mark>", '<mark class="search-keyword">');
};
if (typeof pjax === 'object') {
search.on('render', () => {
pjax.refresh(document.querySelector('.algolia-hits'));
});
}
// Registering Widgets
search.addWidgets([
instantsearch.widgets.configure({
hitsPerPage: hits.perpage || 10
}),
instantsearch.widgets.searchBox({
container: '.search-input-container',
placeholder: NexT.CONFIG.i18n.placeholder,
// Hide default icons of algolia search
showReset: false,
showSubmit: false,
showLoadingIndicator: true,
cssClasses: {
input: 'search-input'
}
}),
instantsearch.widgets.stats({
container: '.algolia-stats',
templates: {
text: data => {
const stats = NexT.CONFIG.i18n.hits_time
.replace('${hits}', data.nbHits)
.replace('${time}', data.processingTimeMS);
return `<span>${stats}</span><img src="/imgs/algolia-logo.svg" alt="Algolia">`;
}
},
cssClasses: {
text: 'search-stats'
}
}),
instantsearch.widgets.hits({
container: '.algolia-hits',
escapeHTML: true,
templates: {
item: data => {
const { title, content } = data._highlightResult;
let result = `<a href="${data.permalink}" class="search-result-title">${markKeyWords(title.value)}</a>`;
//const content = excerpt || excerptStrip || content;
if (content && content.value) {
const div = document.createElement('div');
div.innerHTML = markKeyWords(content.value);
result += `<a href="${data.permalink}"><p class="search-result">${div.innerHTML.substring(0, 200)}...</p></a>`;
}
return result;
},
empty: data => {
return `<div class="algolia-hits-empty">
${NexT.CONFIG.i18n.empty.replace('${query}', data.query)}
</div>`;
}
},
cssClasses: {
list: 'search-result-list'
}
}),
instantsearch.widgets.pagination({
container: '.algolia-pagination',
scrollTo: false,
showFirst: true,
showLast: true,
templates: {
first: '<i class="fa fa-angle-double-left"></i>',
last: '<i class="fa fa-angle-double-right"></i>',
previous: '<i class="fa fa-angle-left"></i>',
next: '<i class="fa fa-angle-right"></i>'
},
cssClasses: {
list: ['pagination', 'algolia-pagination'],
item: 'pagination-item',
link: 'page-number',
selectedItem: 'current',
disabledItem: 'disabled-item'
}
})
]);
search.start();
// Handle and trigger popup window
document.querySelectorAll('.popup-trigger').forEach(element => {
element.addEventListener('click', () => {
document.body.classList.add('search-active');
setTimeout(() => document.querySelector('.search-input').focus(), 500);
});
});
// Monitor main search box
const onPopupClose = () => {
document.body.classList.remove('search-active');
};
document.querySelector('.search-pop-overlay').addEventListener('click', event => {
if (event.target === document.querySelector('.search-pop-overlay')) {
onPopupClose();
}
});
document.querySelector('.popup-btn-close').addEventListener('click', onPopupClose);
document.addEventListener('pjax:success', onPopupClose);
window.addEventListener('keyup', event => {
if (event.key === 'Escape') {
onPopupClose();
}
});
});;
});

326
assets/js/third-party/search/local.js vendored Normal file
View File

@ -0,0 +1,326 @@
/* global CONFIG, pjax, LocalSearch */
class LocalSearch {
constructor({
path = '',
unescape = false,
top_n_per_article = 1
}) {
this.path = path;
this.unescape = unescape;
this.top_n_per_article = top_n_per_article;
this.isfetched = false;
this.datas = null;
}
getIndexByWord(words, text, caseSensitive = false) {
const index = [];
const included = new Set();
if (!caseSensitive) {
text = text.toLowerCase();
}
words.forEach(word => {
if (this.unescape) {
const div = document.createElement('div');
div.innerText = word;
word = div.innerHTML;
}
const wordLen = word.length;
if (wordLen === 0) return;
let startPosition = 0;
let position = -1;
if (!caseSensitive) {
word = word.toLowerCase();
}
while ((position = text.indexOf(word, startPosition)) > -1) {
index.push({ position, word });
included.add(word);
startPosition = position + wordLen;
}
});
// Sort index by position of keyword
index.sort((left, right) => {
if (left.position !== right.position) {
return left.position - right.position;
}
return right.word.length - left.word.length;
});
return [index, included];
}
// Merge hits into slices
mergeIntoSlice(start, end, index) {
let item = index[0];
let { position, word } = item;
const hits = [];
const count = new Set();
while (position + word.length <= end && index.length !== 0) {
count.add(word);
hits.push({
position,
length: word.length
});
const wordEnd = position + word.length;
// Move to next position of hit
index.shift();
while (index.length !== 0) {
item = index[0];
position = item.position;
word = item.word;
if (wordEnd > position) {
index.shift();
} else {
break;
}
}
}
return {
hits,
start,
end,
count: count.size
};
}
// Highlight title and content
highlightKeyword(val, slice) {
let result = '';
let index = slice.start;
for (const { position, length } of slice.hits) {
result += val.substring(index, position);
index = position + length;
result += `<mark class="search-keyword">${val.substr(position, length)}</mark>`;
}
result += val.substring(index, slice.end);
return result;
}
getResultItems(keywords) {
const resultItems = [];
this.datas.forEach(({ title, content, url }) => {
// The number of different keywords included in the article.
const [indexOfTitle, keysOfTitle] = this.getIndexByWord(keywords, title);
const [indexOfContent, keysOfContent] = this.getIndexByWord(keywords, content);
const includedCount = new Set([...keysOfTitle, ...keysOfContent]).size;
// Show search results
const hitCount = indexOfTitle.length + indexOfContent.length;
if (hitCount === 0) return;
const slicesOfTitle = [];
if (indexOfTitle.length !== 0) {
slicesOfTitle.push(this.mergeIntoSlice(0, title.length, indexOfTitle));
}
let slicesOfContent = [];
while (indexOfContent.length !== 0) {
const item = indexOfContent[0];
const { position } = item;
// Cut out 100 characters. The maxlength of .search-input is 80.
const start = Math.max(0, position - 20);
const end = Math.min(content.length, position + 80);
slicesOfContent.push(this.mergeIntoSlice(start, end, indexOfContent));
}
// Sort slices in content by included keywords' count and hits' count
slicesOfContent.sort((left, right) => {
if (left.count !== right.count) {
return right.count - left.count;
} else if (left.hits.length !== right.hits.length) {
return right.hits.length - left.hits.length;
}
return left.start - right.start;
});
// Select top N slices in content
const upperBound = parseInt(this.top_n_per_article, 10);
if (upperBound >= 0) {
slicesOfContent = slicesOfContent.slice(0, upperBound);
}
let resultItem = '';
url = new URL(url, location.origin);
url.searchParams.append('highlight', keywords.join(' '));
if (slicesOfTitle.length !== 0) {
resultItem += `<li><a href="${url.href}" class="search-result-title">${this.highlightKeyword(title, slicesOfTitle[0])}</a>`;
} else {
resultItem += `<li><a href="${url.href}" class="search-result-title">${title}</a>`;
}
slicesOfContent.forEach(slice => {
resultItem += `<a href="${url.href}"><p class="search-result">${this.highlightKeyword(content, slice)}...</p></a>`;
});
resultItem += '</li>';
resultItems.push({
item: resultItem,
id : resultItems.length,
hitCount,
includedCount
});
});
return resultItems;
}
fetchData() {
const isXml = !this.path.endsWith('json');
fetch(this.path)
.then(response => response.text())
.then(res => {
// Get the contents from search data
this.isfetched = true;
this.datas = isXml ? [...new DOMParser().parseFromString(res, 'text/xml').querySelectorAll('entry')].map(element => ({
title : element.querySelector('title').textContent,
content: element.querySelector('content').textContent,
url : element.querySelector('url').textContent
})) : JSON.parse(res);
// Only match articles with non-empty titles
this.datas = this.datas.filter(data => data.title).map(data => {
data.title = data.title.trim();
data.content = data.content ? data.content.trim().replace(/<[^>]+>/g, '') : '';
data.url = decodeURIComponent(data.url).replace(/\/{2,}/g, '/');
return data;
});
// Remove loading animation
window.dispatchEvent(new Event('search:loaded'));
});
}
// Highlight by wrapping node in mark elements with the given class name
highlightText(node, slice, className) {
const val = node.nodeValue;
let index = slice.start;
const children = [];
for (const { position, length } of slice.hits) {
const text = document.createTextNode(val.substring(index, position));
index = position + length;
const mark = document.createElement('mark');
mark.className = className;
mark.appendChild(document.createTextNode(val.substr(position, length)));
children.push(text, mark);
}
node.nodeValue = val.substring(index, slice.end);
children.forEach(element => {
node.parentNode.insertBefore(element, node);
});
}
// Highlight the search words provided in the url in the text
highlightSearchWords(body) {
const params = new URL(location.href).searchParams.get('highlight');
const keywords = params ? params.split(' ') : [];
if (!keywords.length || !body) return;
const walk = document.createTreeWalker(body, NodeFilter.SHOW_TEXT, null);
const allNodes = [];
while (walk.nextNode()) {
if (!walk.currentNode.parentNode.matches('button, select, textarea')) allNodes.push(walk.currentNode);
}
allNodes.forEach(node => {
const [indexOfNode] = this.getIndexByWord(keywords, node.nodeValue);
if (!indexOfNode.length) return;
const slice = this.mergeIntoSlice(0, node.nodeValue.length, indexOfNode);
this.highlightText(node, slice, 'search-keyword');
});
}
}
document.addEventListener('DOMContentLoaded', () => {
if (! NexT.CONFIG.localSearch.path) {
// Search DB path
console.warn('`search indexes file` is not configurate!');
return;
}
const localSearch = new LocalSearch({
path : NexT.CONFIG.localSearch.path,
top_n_per_article: NexT.CONFIG.localSearch.topnperarticle,
unescape : NexT.CONFIG.localSearch.unescape
});
const input = document.querySelector('.search-input');
const inputEventFunction = () => {
if (!localSearch.isfetched) return;
const searchText = input.value.trim().toLowerCase();
const keywords = searchText.split(/[-\s]+/);
const container = document.querySelector('.search-result-container');
let resultItems = [];
if (searchText.length > 0) {
// Perform local searching
resultItems = localSearch.getResultItems(keywords);
}
if (keywords.length === 1 && keywords[0] === '') {
container.classList.add('no-result');
container.innerHTML = '<div class="search-result-icon"><i class="fa fa-search fa-5x"></i></div>';
} else if (resultItems.length === 0) {
container.classList.add('no-result');
container.innerHTML = '<div class="search-result-icon"><i class="far fa-frown fa-5x"></i></div>';
} else {
resultItems.sort((left, right) => {
if (left.includedCount !== right.includedCount) {
return right.includedCount - left.includedCount;
} else if (left.hitCount !== right.hitCount) {
return right.hitCount - left.hitCount;
}
return right.id - left.id;
});
const stats = NexT.CONFIG.i18n.hits.replace('${hits}', resultItems.length);
container.classList.remove('no-result');
container.innerHTML = `<div class="search-stats">${stats}</div>
<hr>
<ul class="search-result-list">${resultItems.map(result => result.item).join('')}</ul>`;
if (typeof pjax === 'object') pjax.refresh(container);
}
};
localSearch.highlightSearchWords(document.querySelector('.post-body'));
if (NexT.CONFIG.localSearch.preload) {
localSearch.fetchData();
}
if (NexT.CONFIG.localSearch.trigger === 'auto') {
input.addEventListener('input', inputEventFunction);
} else {
document.querySelector('.search-icon').addEventListener('click', inputEventFunction);
input.addEventListener('keypress', event => {
if (event.key === 'Enter') {
inputEventFunction();
}
});
}
window.addEventListener('search:loaded', inputEventFunction);
// Handle and trigger popup window
document.querySelectorAll('.popup-trigger').forEach(element => {
element.addEventListener('click', () => {
document.body.classList.add('search-active');
// Wait for search-popup animation to complete
setTimeout(() => input.focus(), 500);
if (!localSearch.isfetched) localSearch.fetchData();
});
});
// Monitor main search box
const onPopupClose = () => {
document.body.classList.remove('search-active');
};
document.querySelector('.search-pop-overlay').addEventListener('click', event => {
if (event.target === document.querySelector('.search-pop-overlay')) {
onPopupClose();
}
});
document.querySelector('.popup-btn-close').addEventListener('click', onPopupClose);
document.addEventListener('pjax:success', () => {
localSearch.highlightSearchWords(document.querySelector('.post-body'));
onPopupClose();
});
window.addEventListener('keyup', event => {
if (event.key === 'Escape') {
onPopupClose();
}
});
});

View File

@ -1,4 +1,4 @@
# Hugo NexT theme's custom config # Hugo NexT theme's custom config
# #
version: 4.1.0 version: 4.2.0

View File

@ -39,8 +39,8 @@ analytics:
addthis: addthis:
js: https://s7.addthis.com/js/300/addthis_widget.js js: https://s7.addthis.com/js/300/addthis_widget.js
# 评论组件资源 # 评论组件
# Comment component Resources # Comment component
waline: waline:
js: js:
name: '@waline/client' name: '@waline/client'
@ -71,3 +71,14 @@ utterances:
livere: livere:
js: https://cdn-city.livere.com/js/embed.dist.js js: https://cdn-city.livere.com/js/embed.dist.js
# 全文搜索
# Full text search
algolia:
name: algoliasearch
version: 4.13.0
file: dist/algoliasearch-lite.umd.js
instant:
name: instantsearch.js
version: 4.40.5
file: dist/instantsearch.production.min.js

View File

@ -55,6 +55,42 @@ markup:
endLevel: 3 endLevel: 3
ordered: false ordered: false
# 站点文章导航文件
# Site map of all articles
sitemap:
filename: "sitemap.xml"
changefreq: "weekly"
priority: 0.5
outputFormats:
RSS:
baseName: "rss"
# 自定义生成本地搜索文件
# Custom file of indexes for local search
LocalIndexes:
mediaType: application/xml
baseName: searchindexes
isPlainText: true
notAlternative: true
# 生成 Algolia 索引文件
# Build indexes of Aloglia
AlgoliaIndexes:
mediaType: application/json
baseName: algolia
isPlainText: true
notAlternative: true
# 默认使用本地搜索,如切换到 Algolia 搜索引擎,
# 请将下面的 LocalIndexes 替换成 AlgoliaIndexes
# By default use local search, before switch to Algolia engine
# Please replace LocalIndexes with AlgoliaIndexes
outputs:
home: ["HTML", "RSS", "LocalIndexes"]
# 输出 robots 文件支持爬虫扫描
# Enable robots with support crawler scan
enableRobotsTXT: true
#-------------------------------------- #--------------------------------------
# 菜单配置说明 # 菜单配置说明
# identifier 唯一标识不可重复 # identifier 唯一标识不可重复
@ -84,16 +120,21 @@ menus:
pageref: /about.html pageref: /about.html
pre: user pre: user
weight: 2 weight: 2
- identifier: flinks
name: 站点示例
pageref: /flinks.html
pre: thumbs-up
weight: 3
- identifier: archives - identifier: archives
name: 归档 name: 归档
pageref: /archives pageref: /archives
pre: archive pre: archive
weight: 3 weight: 4
- identifier: commonweal - identifier: commonweal
name: 公益 404 name: 公益 404
url: /404.html url: /404.html
pre: heartbeat pre: heartbeat
weight: 4 weight: 5
#----------------------------------------- #-----------------------------------------
# Hugo NexT 主题参数配置 # Hugo NexT 主题参数配置
@ -877,8 +918,7 @@ params:
# --------------------------------------------------------------- # ---------------------------------------------------------------
# TODO # 内容搜索服务
# 内容搜索服务(暂时未实现)
# Search Services # Search Services
# --------------------------------------------------------------- # ---------------------------------------------------------------
@ -886,19 +926,32 @@ params:
# For more information: https://www.algolia.com # For more information: https://www.algolia.com
algoliaSearch: algoliaSearch:
enable: false enable: false
appId: #<algolia app id>
apiKey: #<algolia api key>
indexName: #<algolia index name>
hits: hits:
perPage: 10 perPage: 10
# 本地搜索
# Local Search # Local Search
localSearch: localSearch:
# 是否开启搜索功能
# Enable search function
enable: true enable: true
# 搜索索引文件路径
# Indexes file path for search
path: searchindexes.xml
# 是立即搜索当输入关键字时,可选值: auto | manual
# If auto, trigger search by changing input. # If auto, trigger search by changing input.
# If manual, trigger search by pressing enter key or search button. # If manual, trigger search by pressing enter key or search button.
trigger: auto trigger: auto
# 显示头部的搜索记录,-1 表示显示所有搜索结果
# Show top n results per article, show all results by setting to -1 # Show top n results per article, show all results by setting to -1
top_n_per_article: 1 topNPerArticle: -1
# 将 html 字符串转换为可读字符串
# Unescape html strings to the readable one. # Unescape html strings to the readable one.
unescape: false unescape: false
# 页面加载时是否要重新载入索引文件
# Preload the search data when the page loads. # Preload the search data when the page loads.
preload: false preload: false

View File

@ -0,0 +1,27 @@
---
title: "关于 Hugo NexT 组织"
description: "Hugo NexT 组织介绍说明。"
date: 2022-06-09T20:12:52+08:00
lastmod: 2022-06-09T20:12:52+08:00
share: false
followme: false
nav: false
copyright: false
url: about.html
---
`Hugo NexT` 组织是由众多喜爱 `NexT` 主题及风格的世界各地友人共同组建而成,为的就是让这个主题继续在 `Hugo` 引擎中也能得到发扬光大,在此也欢迎你的加入!
# 我们的愿景
延续 `NexT` 经典的黑白调搭配,保持简单的易用性及强大的功能。
# 使用反馈
- 加入 [GitHub Discussions](https://github.com/hugo-next/hugo-theme-next/discussions) 或 [Gitter](https://gitter.im/hugo-next/community) 在线讨论 :beers:
- [GitHub Issues](https://github.com/hugo-next/hugo-theme-next/issues/new?labels=Bug&template=bug-report.md) 提交错误报告 :bug:
- [GitHub Feature](https://github.com/hugo-next/hugo-theme-next/issues/new?labels=Feature+Request&template=feature-request.md) 表新功能的想法 :sparkles:
> 同时国内用户也可加入 QQ 群交流: 604710815

View File

@ -0,0 +1,16 @@
---
title: "站点示例"
type: flinks
url: flinks.html
---
如想要交换友情链接,请在评论区留下你的站点信息,格式参考如下:
{{< note success no-icon >}}
**名称:** NexT 主题 <br/>
**说明:** 保持简单的易用性和强大的功能。 <br/>
**站标:** https://hugo-next.eu.org/imgs/hugo_next_avatar.png <br/>
**网址:** https://hugo-next.eu.org <br/>
{{< /note >}}

View File

@ -0,0 +1,86 @@
---
title: "自定义短语示例"
description: "将常用的块引用、标签卡、按钮等信息设置成短代码,便于快速引用"
keywords: "shortcode,短代码"
date: 2022-08-06T14:41:50+08:00
lastmod: 2022-08-06T14:41:50+08:00
categories:
- 示例
tags:
- 短代码
- 语法
url: "post/shortcodes.html"
---
虽然 `Markdown` 语法已经非常丰富能够满足我们写文章的绝大部分需求,但是为更好的对文章内容进行更友好的排版,为引设计一套自定义的短语,便于在使用时能够快速引用。
<!--more-->
# 块引用
在引用一些经典名言名句时,可以采用此短语,语法参考如下:
```markdown
{{</* quote */>}}
### block quote
写下你想表达的话语!
{{</* /quote */>}}
```
实际效果:
{{< quote >}}
希望是无所谓有,无所谓无的,这正如地上的路。
其实地上本没有路,走的人多了,也便成了路。
**鲁迅**
{{< /quote >}}
# 信息块
支持 `default``info``success``warning``danger` 等五种不同效果的展示,语法参考如下:
```markdown
{{</* note [class] [no-icon] */>}}
书写表达的信息
支持 Markdown 语法
{{</* /note */>}}
```
实际效果:
{{< note default no-icon >}}
### Default Header without icon
**Welcome** to [Hugo NexT!](https://preview.hugo-next.eu.org)
{{< /note >}}
{{< note default >}}
### Default Header
**Welcome** to [Hugo NexT!](https://preview.hugo-next.eu.org)
{{< /note >}}
{{< note info >}}
### Info Header
**Welcome** to [Hugo NexT!](https://preview.hugo-next.eu.org)
{{< /note >}}
{{< note success >}}
### Success Header
**Welcome** to [Hugo NexT!](https://preview.hugo-next.eu.org)
{{< /note >}}
{{< note warning >}}
### Warning Header
**Welcome** to [Hugo NexT!](https://preview.hugo-next.eu.org)
{{< /note >}}
{{< note danger >}}
### Danger Header
**Welcome** to [Hugo NexT!](https://preview.hugo-next.eu.org)
{{< /note >}}

View File

@ -0,0 +1,29 @@
# 友情链接
# Friend's links
- FLinksTitle: 官方示例
FLinksDesc: 来自主题官方的示例内容。
FLinksList:
- name: Hugo
desc: 世界上最快的网站建设框架!
avatar: https://gohugo.io/favicon-32x32.png
link: https://gohugo.io
- name: Hugo-NexT
desc: Hugo NexT 官方预览网站。
avatar: https://hugo-next.eu.org/imgs/hugo_next_avatar.png
link: https://hugo-next.eu.org
- name: 凡梦星尘空间站
desc: 再平凡的人也有属于他的梦想!
avatar: https://lisenhui.cn/img/avatar.png
link: https://lisenhui.cn
- FLinksTitle: Hugo NexT 粉丝群体
FLinksDesc: 来自 Hugo NexT 主题爱好者们的精彩呈现!
FLinksList:
- name: 阿哈吉
desc: 全网首个 Hugo NexT 忠实粉丝用户
avatar: https://a.happy2008.top/imgs/stayhome-small.png
link: https://a.happy2008.top/

View File

@ -20,4 +20,4 @@ EOT
next `cat ../VERSION` next `cat ../VERSION`
hugo server -D -t ../.. --port 1414 --panicOnWarning --config config.dev.yaml hugo server -t ../.. --port 1414 --panicOnWarning --config config.yaml

View File

@ -141,3 +141,12 @@ PageViewsLabel:
FooterPowerby: FooterPowerby:
other: "Power by %s" other: "Power by %s"
SearchPh:
other: Searching...
SearchEmpty:
other: "We didn't find any results for the search: ${query}"
SearchHits:
hits: "${hits} results found"
SearchHitsTime:
other: "${hits} results found in ${time} ms"

View File

@ -142,3 +142,12 @@ PageViewsLabel:
FooterPowerby: FooterPowerby:
other: 由 %s 强力驱动 other: 由 %s 强力驱动
SearchPh:
other: 搜索...
SearchEmpty:
other: "没有找到任何搜索结果:${query}"
SearchHits:
hits: "找到 ${hits} 个搜索结果"
SearchHitsTime:
other: "找到 ${hits} 个搜索结果(用时 ${time} 毫秒)"

View File

@ -0,0 +1,12 @@
[
{{- range $index, $entry := where .Site.RegularPages "Kind" "page" }}
{{- if $index }}, {{ end }}
{
"permalink": "{{ .Permalink | relURL }}",
"title": {{ .Title | jsonify }},
"content": {{ .Plain | jsonify }},
"date": {{ .Date.Format $.Site.Params.timeFormat | jsonify }},
"updated": {{ .Lastmod.Format $.Site.Params.timeFormat | jsonify }}
}
{{- end }}
]

View File

@ -1,7 +1,3 @@
{{- if and .Page.IsSection (eq .Section "archives") }} {{ $paginator := .Paginator.Pages.GroupByDate "2006" }}
{{- $paginator := (.Paginate (where .Page.Site.RegularPages "Section" "in" .Site.Params.mainSections)).Pages.GroupByDate "2006" }} {{ partial "list.html" $paginator }}
{{ partial "list.html" $paginator }}
{{ else }}
{{- $paginator := .Paginator.Pages.GroupByDate "2006" }}
{{ partial "list.html" $paginator }}
{{- end }}

View File

@ -0,0 +1,18 @@
{{ printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>" | safeHTML }}
<search>
{{range where .Site.RegularPages "Kind" "page"}}
<entry>
<title>{{ .Title }}</title>
<url>{{ .Permalink }}</url>
<categories>
{{- range .Params.categories }}<category>{{ . }}</category>{{- end }}
</categories>
<tags>
{{- range .Params.tags }}
<tag>{{ . }}</tag>
{{- end }}
</tags>
<content type="html"><![CDATA[{{ .Content | plainify }}]]></content>
</entry>
{{ end }}
</search>

View File

@ -1,39 +1,15 @@
{{- define "title" }} {{- define "title" }}
{{- .Params.Title | default (T .Section) | default .Section | dict "Some" | T "AllSome" }} - {{ .Site.Title -}} {{- .Params.Title | default (T .Section) | default .Section }} - {{ .Site.Title -}}
{{- end -}} {{- end -}}
{{ define "main_inner_class" }}archive posts-collapse{{ end }} {{ define "main_inner_class" }}index posts-expand{{ end }}
{{- define "main" }} {{- define "main" }}
<div class="post-block">
<div class="post-content">
<div class="collection-title">
{{- $cheers := "Um" }}
{{- $posts := .Scratch.Get "postsCount" }}
{{- if and .Page.IsSection (ne .Section "archives") }}
{{- $posts = .Scratch.Get .Section }}
{{- end }}
{{- if gt $posts 210 }}
{{- $cheers = "Excellent" }}
{{- else if gt $posts 130 }}
{{- $cheers = "Great" }}
{{- else if gt $posts 80 }}
{{- $cheers = "Good" }}
{{- else if gt $posts 50 }}
{{- $cheers = "Nice" }}
{{- else if gt $posts 30 }}
{{- $cheers = "Ok" }}
{{- end }}
<span class="collection-header">
{{- T (printf "PostArchiveCheers%s" $cheers) }}
{{- T "SymbolComma" }}
{{- T "ArchiveCounterTitle" $posts | safeHTML }}
{{- T "SymbolComma" }}
{{- T "PostArchiveKeepOn" }}
</span>
</div>
{{ .Render "list" }} {{ $paginator := .Paginate (where .Site.RegularPages "Section" "==" .Section) }}
{{- range $paginator.Pages }}
</div> {{ partial "post.html" (dict "ctx" . "IsHome" true) }}
</div> {{- end }}
{{- partial "pagination.html" . }}
{{- partial "partials/pagination.html" . }}
{{- end }} {{- end }}

View File

@ -0,0 +1,2 @@
{{ $paginator := (.Paginate (where .Page.Site.RegularPages "Section" "in" .Site.Params.mainSections)).Pages.GroupByDate "2006" }}
{{ partial "list.html" $paginator }}

View File

@ -0,0 +1,36 @@
{{- define "title" }}
{{- .Params.Title | default (T .Section) | default .Section | dict "Some" | T "AllSome" }} - {{ .Site.Title -}}
{{- end -}}
{{ define "main_inner_class" }}archive posts-collapse{{ end }}
{{- define "main" }}
<div class="post-block">
<div class="post-content">
<div class="collection-title">
{{- $cheers := "Um" }}
{{- $posts := .Scratch.Get "postsCount" }}
{{- if gt $posts 210 }}
{{- $cheers = "Excellent" }}
{{- else if gt $posts 130 }}
{{- $cheers = "Great" }}
{{- else if gt $posts 80 }}
{{- $cheers = "Good" }}
{{- else if gt $posts 50 }}
{{- $cheers = "Nice" }}
{{- else if gt $posts 30 }}
{{- $cheers = "Ok" }}
{{- end }}
<span class="collection-header">
{{- T (printf "PostArchiveCheers%s" $cheers) }}
{{- T "SymbolComma" }}
{{- T "ArchiveCounterTitle" $posts | safeHTML }}
{{- T "SymbolComma" }}
{{- T "PostArchiveKeepOn" }}
</span>
</div>
{{ .Render "list" }}
</div>
</div>
{{- partial "pagination.html" . }}
{{- end }}

View File

@ -0,0 +1,34 @@
{{- define "title" }}{{- .Title }} - {{ .Site.Title -}}{{- end }}
{{- define "main_inner_class" }}flinks posts-expand{{- end }}
{{ define "main" }}
<div class="flinks-block">
<h1 class="flinks-block-title">{{ .Title }}</h1>
<div class="flinks-lists">
{{ range .Site.Data.flinks }}
<div class="flinks-list">
<div class="flinks-list-title">{{ .FLinksTitle | safeHTML }}</div>
<div class="flinks-list-desc">{{ .FLinksDesc | safeHTML }}</div>
<div class="flinks-list-items">
{{ range .FLinksList }}
<div class="flinks-list-item">
<a href="{{ .link }}" rel="external nofollow noreferrer" title=" {{ .name }}" target="_blank">
<div class="flinks-item-icon">
<img class="no-lightbox entered loaded" src="{{ .avatar }}" alt="{{ .name }}"/>
</div>
<div class="flinks-item-name">{{ .name | safeHTML }}</div>
<div class="flinks-item-desc" title="{{ .desc }}">{{ .desc | safeHTML }}</div>
</a>
</div>
{{ end }}
</div>
</div>
{{ end }}
</div>
<div class="flinks-list-footer"><hr/></div>
<div class="flinks-page-desc">{{ .Content }}</div>
</div>
{{ end }}

View File

@ -1,8 +1,11 @@
{{- define "main_inner_class" }}index posts-expand{{- end }} {{- define "main_inner_class" }}index posts-expand{{- end }}
{{- define "main" }} {{- define "main" }}
{{ $paginator := .Paginate (where .Site.RegularPages "Section" "in" .Site.Params.mainSections) }} {{ $paginator := .Paginate (where .Site.RegularPages "Section" "in" .Site.Params.mainSections) }}
{{- range $paginator.Pages }} {{- range $paginator.Pages }}
{{ partial "post.html" (dict "ctx" . "IsHome" true) }} {{ partial "post.html" (dict "ctx" . "IsHome" true) }}
{{- end }} {{- end }}
{{- partial "partials/pagination.html" . }} {{- partial "partials/pagination.html" . }}
{{- end }} {{- end }}

View File

@ -0,0 +1,14 @@
<div class="search-header">
<span class="search-icon">
<i class="fa fa-search"></i>
</span>
<div class="search-input-container"></div>
<span class="popup-btn-close" role="button">
<i class="fa fa-times-circle"></i>
</span>
</div>
<div class="search-result-container">
<div class="algolia-stats"><hr></div>
<div class="algolia-hits"></div>
<div class="algolia-pagination"></div>
</div>

View File

@ -0,0 +1,18 @@
<div class="search-header">
<span class="search-icon">
<i class="fa fa-search"></i>
</span>
<div class="search-input-container">
<input autocomplete="off" autocapitalize="off" maxlength="80"
placeholder="{{ T "SearchPh" }}" spellcheck="false"
type="search" class="search-input">
</div>
<span class="popup-btn-close" role="button">
<i class="fa fa-times-circle"></i>
</span>
</div>
<div class="search-result-container no-result">
<div class="search-result-icon">
<i class="fa fa-spinner fa-pulse fa-5x"></i>
</div>
</div>

View File

@ -27,7 +27,7 @@
<link rel="stylesheet" href="{{ $css.RelPermalink }}"> <link rel="stylesheet" href="{{ $css.RelPermalink }}">
{{- if .IsPage }} {{- if .IsPage }}
<style type="text/css"> <style type="text/css">
.post-footer hr:after { .post-footer, .flinks-list-footer hr:after {
content: "{{ .Site.Params.postFooter.endLineTip }}"; content: "{{ .Site.Params.postFooter.endLineTip }}";
} }
</style> </style>

View File

@ -1,2 +1,3 @@
{{ partial "header/brand.html" . }} {{ partial "header/brand.html" . }}
{{ partial "header/menus.html" . }} {{ partial "header/menus.html" . }}
{{ partial "header/search.html" . }}

View File

@ -0,0 +1,11 @@
{{- if or .Site.Params.algoliaSearch.enable .Site.Params.localSearch.enable }}
<div class="search-pop-overlay">
<div class="popup search-popup">
{{- if .Site.Params.algoliaSearch.enable }}
{{ partial "_thirdparty/search/algolia.html" . }}
{{- else if .Site.Params.localSearch.enable }}
{{ partial "_thirdparty/search/local.html" . }}
{{- end }}
</div>
</div>
{{- end }}

View File

@ -1,22 +1,20 @@
{{/* Use to defind global variables */}} {{/* Use to defind global variables */}}
{{ if not hugo.IsExtended }}
{{ warnf "Hugo NexT 主题使用了 SCSS 框架,请到官方地址下载 Hugo Extended 版本https://github.com/gohugoio/hugo/releases" }}
{{ errorf "Because that use SCSS framework in Hugo NexT, Please download Hugo extended version on offical site: https://github.com/gohugoio/hugo/releases" }}
{{ end }}
{{ $version := int (index (split hugo.Version ".") 1) }} {{ $version := int (index (split hugo.Version ".") 1) }}
{{ if lt $version 89 }} {{ if lt $version 89 }}
{{ warnf "当前 Hugo 版本小于 0.89.0,请到官方地址下载 Hugo 最新版本https://github.com/gohugoio/hugo/releases" }} {{ warnf "当前 Hugo 版本小于 0.89.0,请到官方地址下载 Hugo 最新版本https://github.com/gohugoio/hugo/releases" }}
{{ errorf "Current Hugo version is less then 0.89.0, Please download Hugo latest version on offical site: https://github.com/gohugoio/hugo/releases" }} {{ errorf "Current Hugo version is less then 0.89.0, Please download Hugo latest version on offical site: https://github.com/gohugoio/hugo/releases" }}
{{ end }} {{ end }}
{{ if not hugo.IsExtended }}
{{ warnf "Hugo NexT 主题使用了 SCSS 框架,请到官方地址下载 Hugo Extended 版本https://github.com/gohugoio/hugo/releases" }}
{{ errorf "Because that use SCSS framework in Hugo NexT, Please download Hugo extended version on offical site: https://github.com/gohugoio/hugo/releases" }}
{{ end }}
{{ $globalVars := newScratch }} {{ $globalVars := newScratch }}
{{ $globalVars.Set "postsCount" (len (where .Page.Site.RegularPages "Section" "in" .Site.Params.mainSections)) }} {{ $globalVars.Set "postsCount" (len (where .Page.Site.RegularPages "Section" "in" .Site.Params.mainSections)) }}
{{ range .Site.Params.mainSections }}
{{ $globalVars.Set . (len (where $.Page.Site.RegularPages "Section" .))}}
{{ end }}
{{ $globalVars.Set "catsCount" (len .Site.Taxonomies.categories) }} {{ $globalVars.Set "catsCount" (len .Site.Taxonomies.categories) }}
{{ $globalVars.Set "tagsCount" (len .Site.Taxonomies.tags) }} {{ $globalVars.Set "tagsCount" (len .Site.Taxonomies.tags) }}
@ -25,20 +23,40 @@
{{ $globalVars.Set "router" $router }} {{ $globalVars.Set "router" $router }}
{{ $config := dict {{ $config := dict
"hostname" .Site.BaseURL "hostname" .Site.BaseURL
"root" "/" "root" "/"
"lang" .Site.LanguageCode "lang" .Site.LanguageCode
"vendor" (dict "plugins" $vendor "router" $router) "vendor" (dict "plugins" $vendor "router" $router)
"darkmode" .Site.Params.darkmode "darkmode" .Site.Params.darkmode
"version" .Site.Data.config.version "version" .Site.Data.config.version
"scheme" .Site.Params.scheme "scheme" .Site.Params.scheme
"sidebar" .Site.Params.sidebar "sidebar" .Site.Params.sidebar
"copybtn" .Site.Params.codeblock.copyBtn "copybtn" .Site.Params.codeblock.copyBtn
"bookmark" .Site.Params.bookmark "bookmark" .Site.Params.bookmark
"lazyload" .Site.Params.lazyload "lazyload" .Site.Params.lazyload
"motion" .Site.Params.motion "motion" .Site.Params.motion
"i18n" (dict
"placeholder" (T "SearchPh")
"empty" (T "SearchEmpty")
"hits_time" (T "SearchHitsTime")
"hits" (T "SearchHits")
)
}} }}
{{ if .Site.Params.localSearch.enable }}
{{ $localSearch := dict "localSearch" .Site.Params.localSearch }}
{{ $config = merge $config $localSearch }}
{{ end }}
{{ if .Site.Params.algoliaSearch.enable }}
{{ $algoliaSearch := dict
"js" .Site.Data.resources.algolia
"instantjs" .Site.Data.resources.instant
"cfg" .Site.Params.algoliaSearch
}}
{{ $config = merge $config (dict "algolia" $algoliaSearch) }}
{{ end }}
{{ with .Site.Params.waline }} {{ with .Site.Params.waline }}
{{ $waline := dict {{ $waline := dict
"js" $.Site.Data.resources.waline.js "js" $.Site.Data.resources.waline.js

View File

@ -6,8 +6,8 @@
<article itemscope itemtype="http://schema.org/Article"> <article itemscope itemtype="http://schema.org/Article">
<header class="post-header"> <header class="post-header">
<div class="post-meta-container"> <div class="post-meta-container">
{{ $month := .Date.Format "01-02" }} {{ $month := .Date.Format .Site.Params.monthFormat }}
<time itemprop="dateCreated" datetime="{{ .Date.Format "2006-01-02T15:04:05-07:00" }}" content="{{ $month }}"> <time itemprop="dateCreated" datetime="{{ .Date.Format .Site.Params.timeFormat }}" content="{{ $month }}">
{{ $month }} {{ $month }}
</time> </time>
</div> </div>
@ -18,7 +18,7 @@
<i class="fa fa-external-link-alt"></i> <i class="fa fa-external-link-alt"></i>
</a> </a>
{{- else }} {{- else }}
<a class="post-title-link" href="{{ .Permalink }}" itemprop="url"> <a class="post-title-link" href="{{ .RelPermalink | relLangURL }}" itemprop="url">
<span itemprop="name">{{ .Title }}</span> <span itemprop="name">{{ .Title }}</span>
</a> </a>
{{- end }} {{- end }}

View File

@ -25,15 +25,15 @@
<div class="post-nav"> <div class="post-nav">
<div class="post-nav-next post-nav-item"> <div class="post-nav-next post-nav-item">
{{- with .NextInSection }} {{- with .NextInSection }}
<a href="{{ .Permalink}}" rel="next" title="{{.Title}}"> <a href="{{ .RelPermalink | relLangURL }}" rel="next" title="{{ .Title }}">
<i class="fa fa-chevron-left"></i> {{.Title}} <i class="fa fa-chevron-left"></i> {{ .Title }}
</a> </a>
{{- end }} {{- end }}
</div> </div>
<div class="post-nav-prev post-nav-item"> <div class="post-nav-prev post-nav-item">
{{- with .PrevInSection }} {{- with .PrevInSection }}
<a href="{{ .Permalink}}" rel="prev" title="{{.Title}}"> <a href="{{ .RelPermalink | relLangURL }}" rel="prev" title="{{ .Title }}">
{{.Title}} {{ .Title }}
<i class="fa fa-chevron-right"></i> <i class="fa fa-chevron-right"></i>
</a> </a>
{{- end }} {{- end }}

View File

@ -64,8 +64,17 @@
{{- $utterancesjs := resources.Get "js/third-party/comments/utterances.js" }} {{- $utterancesjs := resources.Get "js/third-party/comments/utterances.js" }}
{{- $nextjs = $nextjs | append $utterancesjs }} {{- $nextjs = $nextjs | append $utterancesjs }}
{{- end }} {{- end }}
{{- if .Site.Params.localSearch.enable }}
{{- $search := resources.Get "js/third-party/search/local.js" }}
{{- $nextjs = $nextjs | append $search }}
{{ end }}
{{- if .Site.Params.algoliaSearch.enable }}
{{- $search := resources.Get "js/third-party/search/algolia.js" }}
{{- $nextjs = $nextjs | append $search }}
{{ end }}
{{- $nextjs = $nextjs | resources.Concat "js/main.js"}} {{- $nextjs = $nextjs | resources.Concat "js/main.js"}}
{{ if hugo.IsProduction }} {{ if hugo.IsProduction }}
{{- $nextjs = $nextjs | minify | fingerprint }} {{- $nextjs = $nextjs | minify | fingerprint }}
{{ end }} {{ end }}
<script type="text/javascript" src="{{ $nextjs.RelPermalink }}" defer></script> <script type="text/javascript" src="{{ $nextjs.RelPermalink }}" defer></script>

View File

@ -12,7 +12,7 @@
<div class="site-state-wrap site-overview-item animated"> <div class="site-state-wrap site-overview-item animated">
<nav class="site-state"> <nav class="site-state">
<div class="site-state-item site-state-posts"> <div class="site-state-item site-state-posts">
<a href="{{ "/posts/" | relLangURL }}"> <a href="{{ "/archives/" | relLangURL }}">
<span class="site-state-item-count">{{ .Scratch.Get "postsCount" }}</span> <span class="site-state-item-count">{{ .Scratch.Get "postsCount" }}</span>
<span class="site-state-item-name">{{ T "SbPostsLable" }}</span> <span class="site-state-item-name">{{ T "SbPostsLable" }}</span>
</a> </a>

View File

@ -0,0 +1,3 @@
<div class="note {{ .Get 0 }} {{ .Get 1 }}">
{{ .Inner | markdownify }}
</div>

View File

@ -0,0 +1,3 @@
<blockquote class="blockquote-center">
{{ .Inner | markdownify }}
</blockquote>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -1,130 +0,0 @@
/* global instantsearch, algoliasearch, CONFIG, pjax */
document.addEventListener('DOMContentLoaded', () => {
const { indexName, appID, apiKey, hits } = CONFIG.algolia;
const search = instantsearch({
indexName,
searchClient : algoliasearch(appID, apiKey),
searchFunction: helper => {
if (document.querySelector('.search-input').value) {
helper.search();
}
}
});
if (typeof pjax === 'object') {
search.on('render', () => {
pjax.refresh(document.querySelector('.algolia-hits'));
});
}
// Registering Widgets
search.addWidgets([
instantsearch.widgets.configure({
hitsPerPage: hits.per_page || 10
}),
instantsearch.widgets.searchBox({
container : '.search-input-container',
placeholder : CONFIG.i18n.placeholder,
// Hide default icons of algolia search
showReset : false,
showSubmit : false,
showLoadingIndicator: false,
cssClasses : {
input: 'search-input'
}
}),
instantsearch.widgets.stats({
container: '.algolia-stats',
templates: {
text: data => {
const stats = CONFIG.i18n.hits_time
.replace('${hits}', data.nbHits)
.replace('${time}', data.processingTimeMS);
return `<span>${stats}</span>
<img src="${CONFIG.images}/logo-algolia-nebula-blue-full.svg" alt="Algolia">`;
}
},
cssClasses: {
text: 'search-stats'
}
}),
instantsearch.widgets.hits({
container : '.algolia-hits',
escapeHTML: false,
templates : {
item: data => {
const { title, excerpt, excerptStrip, contentStripTruncate } = data._highlightResult;
let result = `<a href="${data.permalink}" class="search-result-title">${title.value}</a>`;
const content = excerpt || excerptStrip || contentStripTruncate;
if (content && content.value) {
const div = document.createElement('div');
div.innerHTML = content.value;
result += `<a href="${data.permalink}"><p class="search-result">${div.textContent.substring(0, 100)}...</p></a>`;
}
return result;
},
empty: data => {
return `<div class="algolia-hits-empty">
${CONFIG.i18n.empty.replace('${query}', data.query)}
</div>`;
}
},
cssClasses: {
list: 'search-result-list'
}
}),
instantsearch.widgets.pagination({
container: '.algolia-pagination',
scrollTo : false,
showFirst: false,
showLast : false,
templates: {
first : '<i class="fa fa-angle-double-left"></i>',
last : '<i class="fa fa-angle-double-right"></i>',
previous: '<i class="fa fa-angle-left"></i>',
next : '<i class="fa fa-angle-right"></i>'
},
cssClasses: {
list : ['pagination', 'algolia-pagination'],
item : 'pagination-item',
link : 'page-number',
selectedItem: 'current',
disabledItem: 'disabled-item'
}
})
]);
search.start();
// Handle and trigger popup window
document.querySelectorAll('.popup-trigger').forEach(element => {
element.addEventListener('click', () => {
document.body.classList.add('search-active');
setTimeout(() => document.querySelector('.search-input').focus(), 500);
});
});
// Monitor main search box
const onPopupClose = () => {
document.body.classList.remove('search-active');
};
document.querySelector('.search-pop-overlay').addEventListener('click', event => {
if (event.target === document.querySelector('.search-pop-overlay')) {
onPopupClose();
}
});
document.querySelector('.popup-btn-close').addEventListener('click', onPopupClose);
document.addEventListener('pjax:success', onPopupClose);
window.addEventListener('keyup', event => {
if (event.key === 'Escape') {
onPopupClose();
}
});
});

View File

@ -1,99 +0,0 @@
/* global CONFIG, pjax, LocalSearch */
document.addEventListener('DOMContentLoaded', () => {
if (!CONFIG.path) {
// Search DB path
console.warn('`hexo-generator-searchdb` plugin is not installed!');
return;
}
const localSearch = new LocalSearch({
path : CONFIG.path,
top_n_per_article: CONFIG.localsearch.top_n_per_article,
unescape : CONFIG.localsearch.unescape
});
const input = document.querySelector('.search-input');
const inputEventFunction = () => {
if (!localSearch.isfetched) return;
const searchText = input.value.trim().toLowerCase();
const keywords = searchText.split(/[-\s]+/);
const container = document.querySelector('.search-result-container');
let resultItems = [];
if (searchText.length > 0) {
// Perform local searching
resultItems = localSearch.getResultItems(keywords);
}
if (keywords.length === 1 && keywords[0] === '') {
container.classList.add('no-result');
container.innerHTML = '<div class="search-result-icon"><i class="fa fa-search fa-5x"></i></div>';
} else if (resultItems.length === 0) {
container.classList.add('no-result');
container.innerHTML = '<div class="search-result-icon"><i class="far fa-frown fa-5x"></i></div>';
} else {
resultItems.sort((left, right) => {
if (left.includedCount !== right.includedCount) {
return right.includedCount - left.includedCount;
} else if (left.hitCount !== right.hitCount) {
return right.hitCount - left.hitCount;
}
return right.id - left.id;
});
const stats = CONFIG.i18n.hits.replace('${hits}', resultItems.length);
container.classList.remove('no-result');
container.innerHTML = `<div class="search-stats">${stats}</div>
<hr>
<ul class="search-result-list">${resultItems.map(result => result.item).join('')}</ul>`;
if (typeof pjax === 'object') pjax.refresh(container);
}
};
localSearch.highlightSearchWords(document.querySelector('.post-body'));
if (CONFIG.localsearch.preload) {
localSearch.fetchData();
}
if (CONFIG.localsearch.trigger === 'auto') {
input.addEventListener('input', inputEventFunction);
} else {
document.querySelector('.search-icon').addEventListener('click', inputEventFunction);
input.addEventListener('keypress', event => {
if (event.key === 'Enter') {
inputEventFunction();
}
});
}
window.addEventListener('search:loaded', inputEventFunction);
// Handle and trigger popup window
document.querySelectorAll('.popup-trigger').forEach(element => {
element.addEventListener('click', () => {
document.body.classList.add('search-active');
// Wait for search-popup animation to complete
setTimeout(() => input.focus(), 500);
if (!localSearch.isfetched) localSearch.fetchData();
});
});
// Monitor main search box
const onPopupClose = () => {
document.body.classList.remove('search-active');
};
document.querySelector('.search-pop-overlay').addEventListener('click', event => {
if (event.target === document.querySelector('.search-pop-overlay')) {
onPopupClose();
}
});
document.querySelector('.popup-btn-close').addEventListener('click', onPopupClose);
document.addEventListener('pjax:success', () => {
localSearch.highlightSearchWords(document.querySelector('.post-body'));
onPopupClose();
});
window.addEventListener('keyup', event => {
if (event.key === 'Escape') {
onPopupClose();
}
});
});

View File

@ -1,4 +1,4 @@
name = "Hugo Next" name = "Hugo NexT"
license = "MIT" license = "MIT"
licenselink = "https://github.com/hugo-next/hugo-theme-next/blob/main/LICENSE" licenselink = "https://github.com/hugo-next/hugo-theme-next/blob/main/LICENSE"
description = "Easily & powerful theme for Hugo engine." description = "Easily & powerful theme for Hugo engine."