Compare commits

...
39 Commits
Author SHA1 Message Date
Jimmy Cai cd408279e4 release: 1.1.0 version 2020-11-08 00:28:30 +01:00
Jimmy CaiandGitHub f3107a35a7 Add Release Drafter Template 2020-11-07 14:06:00 +01:00
Jimmy CaiandGitHub 695260cf0d Set up release drafter action 2020-11-07 14:03:57 +01:00
Jimmy Cai 5bc567082b Add release-drafter 2020-11-07 13:53:11 +01:00
Jimmy CaiandGitHub 148f0ff8fe Merge pull request #19 from CaiJimmy/template-search
feat: local search
2020-11-06 12:19:33 +01:00
Jimmy Cai efa7ff14b7 refactor(search): remove .search-result--title style 2020-11-06 12:13:12 +01:00
Jimmy CaiandGitHub a81dac7bb0 Merge branch 'master' into template-search 2020-11-06 12:09:23 +01:00
Jimmy Cai c018f4967a feat(search): i18n support 2020-11-06 11:49:30 +01:00
Jimmy Cai f5d45458fd refactor(search): create Search class 2020-11-06 11:33:51 +01:00
Jimmy Cai b97e86a7a7 style: remove empty line in main.ts 2020-11-06 11:33:33 +01:00
Jimmy Cai 2736fec285 refactor: create createElement.ts 2020-11-06 11:12:48 +01:00
Jimmy CaiandGitHub 3db6df8f46 Merge pull request #46 from crateout/master
fix(article): related contents is showing hidden post
2020-11-06 10:36:23 +01:00
Ahmad YasserandGitHub 37a2090739 fix(article): related contents is showing hidden post 2020-11-06 16:19:26 +08:00
Ahmad YasserandGitHub a3f1d84c51 fix(article): related contents is showing hidden post 2020-11-06 11:10:30 +08:00
Jimmy CaiandGitHub b3df22940d Merge branch 'master' into template-search 2020-10-31 23:37:36 +01:00
Jimmy Cai be416830ad feat: add support for custom SCSS
closes https://github.com/CaiJimmy/hugo-theme-stack/issues/43
2020-10-31 23:36:16 +01:00
Jimmy CaiandGitHub c3b3c2f0ee Merge pull request #44 from CaiJimmy/refactor-rel-permalink
refactor: use relative link for hyperlinks
2020-10-31 23:28:28 +01:00
Jimmy Cai b5645f0180 refactor: use relative link for hyperlinks 2020-10-31 23:24:58 +01:00
Jimmy Cai d6b0f10241 fix(exampleSite): remove Instagram shortcode
ref https://github.com/gohugoio/hugo/issues/7866

closes https://github.com/CaiJimmy/hugo-theme-stack/issues/41
2020-10-26 17:38:16 +01:00
Jimmy CaiandGitHub c666c79800 Merge branch 'master' into template-search 2020-10-17 10:45:17 +02:00
Jimmy CaiandGitHub f7b61b9556 Merge pull request #39 from CaiJimmy/new-archive-widget
feat: new archive widget style
2020-10-17 10:43:55 +02:00
Jimmy Cai 5c55bd2d33 feat(widget): new archive widget style 2020-10-17 10:34:36 +02:00
Jimmy Cai 34cd7852bc refactor: remove partialCached from sidebar/right 2020-10-17 10:34:02 +02:00
Jimmy CaiandGitHub 49e568faac refactor: add .section-title (#36)
For the small title before the card

Remove .widget-title, .archive-date, .taxonomy-type from SCSS, as they all share the same style.
2020-10-12 20:49:56 +02:00
Jimmy Cai 26fedaebd2 refactor(search): include icon using helper/icon 2020-10-12 20:31:40 +02:00
Yasuhiro KobayashiandGitHub 26bdeb3afb feat(i18n): Add Japanese translation (#35) 2020-10-11 10:14:31 +02:00
Jimmy CaiandGitHub c266204f98 Merge branch 'master' into template-search 2020-10-10 10:05:31 +02:00
Jimmy CaiandGitHub 8e8509177d Merge branch 'master' into template-search 2020-10-09 19:12:50 +02:00
Jimmy CaiandGitHub 3bc73a8b48 Merge branch 'master' into template-search 2020-10-05 22:41:47 +02:00
Jimmy Cai 17d77155bf Merge branch 'master' into template-search 2020-10-04 16:27:22 +02:00
Jimmy Cai b027cbf5aa Merge branch 'master' into template-search 2020-10-04 16:05:02 +02:00
Jimmy Cai 84a15e1604 feat(search): return results at typing 2020-10-04 15:53:27 +02:00
Jimmy Cai 8aeb562bb3 feat(search): preload search.json 2020-10-04 15:45:23 +02:00
Jimmy Cai c19780280e feat: add "head" block 2020-09-26 23:00:48 +02:00
Jimmy Cai 6e48765d82 fix(search): HTML escape issue 2020-09-26 22:50:23 +02:00
Jimmy Cai 08102e2f69 feat(exampleSite): add search page and widget 2020-09-26 12:06:56 +02:00
Jimmy Cai 6fa69d7a2b feat: add search icon 2020-09-26 12:05:13 +02:00
Jimmy Cai 21f461ce78 feat(widget): add search widget 2020-09-26 11:40:52 +02:00
Jimmy Cai e5f96c8762 feat: add search template 2020-09-26 11:40:33 +02:00
38 changed files with 668 additions and 120 deletions
+31
View File
@@ -0,0 +1,31 @@
name-template: 'v$RESOLVED_VERSION 🌈'
tag-template: 'v$RESOLVED_VERSION'
categories:
- title: '🚀 Features'
labels:
- 'feature'
- 'enhancement'
- title: '🐛 Bug Fixes'
labels:
- 'fix'
- 'bugfix'
- 'bug'
- title: '🧰 Maintenance'
label: 'chore'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
version-resolver:
major:
labels:
- 'major'
minor:
labels:
- 'minor'
patch:
labels:
- 'patch'
default: patch
template: |
## Changes
$CHANGES
+16
View File
@@ -0,0 +1,16 @@
name: Release Drafter
on:
push:
# branches to consider in the event; optional, defaults to all
branches:
- master
jobs:
update_release_draft:
runs-on: ubuntu-latest
steps:
# Drafts your next Release notes as Pull Requests are merged into "master"
- uses: release-drafter/release-drafter@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-search" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z"/>
<circle cx="10" cy="10" r="7" />
<line x1="21" y1="21" x2="15" y2="15" />
</svg>

After

Width:  |  Height:  |  Size: 355 B

+1
View File
@@ -0,0 +1 @@
/* Place your custom SCSS in HUGO_SITE_FOLDER/assets/scss/custom.scss */
+7
View File
@@ -199,6 +199,13 @@
.article-time { .article-time {
font-size: 1.4rem; font-size: 1.4rem;
} }
.article-preview{
font-size: 1.4rem;
color: var(--card-text-color-tertiary);
margin-top: 10px;
line-height: 1.5;
}
} }
} }
-10
View File
@@ -1,15 +1,5 @@
.archives-group { .archives-group {
margin-bottom: var(--section-separation); margin-bottom: var(--section-separation);
.archives-date {
text-transform: uppercase;
margin-bottom: 10px;
font-size: 1.6rem;
font-weight: bold;
a {
color: var(--body-text-color);
}
}
} }
.template-archives { .template-archives {
+82
View File
@@ -0,0 +1,82 @@
.search-form {
margin-bottom: var(--section-separation);
position: relative;
--button-size: 80px;
&.widget {
--button-size: 60px;
label {
font-size: 1.3rem;
top: 10px;
}
input {
font-size: 1.5rem;
padding: 30px 20px 15px 20px;
}
}
p {
position: relative;
margin: 0;
}
label {
position: absolute;
top: 15px;
left: 20px;
font-size: 1.4rem;
color: var(--card-text-color-tertiary);
}
input {
padding: 40px 20px 20px;
border-radius: var(--card-border-radius);
background-color: var(--card-background);
box-shadow: var(--shadow-l1);
color: var(--card-text-color-main);
width: 100%;
border: 0;
-webkit-appearance: none;
transition: box-shadow 0.3s ease;
font-size: 1.8rem;
&:focus {
outline: 0;
box-shadow: var(--shadow-l2);
}
}
button {
position: absolute;
right: 0;
top: 0;
height: 100%;
width: var(--button-size);
cursor: pointer;
background-color: transparent;
border: 0;
padding: 0 10px;
&:focus {
outline: 0;
svg {
stroke-width: 2;
color: var(--accent-color);
}
}
svg {
color: var(--card-text-color-secondary);
stroke-width: 1.33;
transition: all 0.3s ease;
width: 20px;
height: 20px;
}
}
}
@@ -1,11 +1,3 @@
.taxonomy-type {
text-transform: uppercase;
color: var(--body-text-color);
font-weight: bold;
margin-bottom: 5px;
font-size: 1.6rem;
}
.taxonomy-card { .taxonomy-card {
border-radius: var(--card-border-radius); border-radius: var(--card-border-radius);
background-color: var(--card-background); background-color: var(--card-background);
+13 -23
View File
@@ -1,13 +1,4 @@
.widget { .widget {
.widget-title {
text-transform: uppercase;
color: var(--body-text-color);
font-weight: bold;
margin: 0;
margin-bottom: 10px;
font-size: 1.6rem;
}
.widget-icon { .widget-icon {
svg { svg {
width: 32px; width: 32px;
@@ -45,27 +36,26 @@
/* Archives widget */ /* Archives widget */
.widget.archives { .widget.archives {
.widget-archive--list {
border-radius: var(--card-border-radius);
box-shadow: var(--shadow-l1);
background-color: var(--card-background);
}
.archives-year { .archives-year {
margin-bottom: 10px; &:not(:last-of-type) {
border-bottom: 1.5px solid var(--card-separator-color);
}
a { a {
background-color: var(--card-background); font-size: 1.4rem;
padding: 15px 25px; padding: 18px 25px;
border-radius: var(--card-border-radius);
box-shadow: var(--shadow-l1);
display: flex; display: flex;
transition: box-shadow 0.3s ease;
&:hover {
box-shadow: var(--shadow-l2);
}
@media (max-width: $on-desktop-large) {
font-size: 1.4rem;
}
span.year { span.year {
flex: 1; flex: 1;
color: var(--card-text-color-main); color: var(--card-text-color-main);
font-weight: bold;
} }
span.count { span.count {
+18 -1
View File
@@ -23,6 +23,9 @@
@import "partials/layout/article.scss"; @import "partials/layout/article.scss";
@import "partials/layout/taxonomy.scss"; @import "partials/layout/taxonomy.scss";
@import "partials/layout/404.scss"; @import "partials/layout/404.scss";
@import "partials/layout/search.scss";
@import "custom.scss";
a { a {
text-decoration: none; text-decoration: none;
@@ -40,4 +43,18 @@ a {
box-shadow: 0px -10px 0px rgba(var(--link-background-color), var(--link-background-opacity-hover)) inset; box-shadow: 0px -10px 0px rgba(var(--link-background-color), var(--link-background-opacity-hover)) inset;
} }
} }
} }
.section-title {
text-transform: uppercase;
margin-top: 0;
margin-bottom: 10px;
display: block;
font-size: 1.6rem;
font-weight: bold;
color: var(--body-text-color);
a {
color: var(--body-text-color);
}
}
+34
View File
@@ -0,0 +1,34 @@
/**
* createElement
* Edited from:
* @link https://stackoverflow.com/a/42405694
*/
function createElement(tag, attrs, children) {
var element = document.createElement(tag);
for (let name in attrs) {
if (name && attrs.hasOwnProperty(name)) {
let value = attrs[name];
if (name == "dangerouslySetInnerHTML") {
element.innerHTML = value.__html;
}
else if (value === true) {
element.setAttribute(name, name);
} else if (value !== false && value != null) {
element.setAttribute(name, value.toString());
}
}
}
for (let i = 2; i < arguments.length; i++) {
let child = arguments[i];
if (child) {
element.appendChild(
child.nodeType == null ?
document.createTextNode(child.toString()) : child);
}
}
return element;
}
export default createElement;
+10 -1
View File
@@ -9,6 +9,7 @@
import { createGallery } from "./gallery" import { createGallery } from "./gallery"
import { getColor } from './color'; import { getColor } from './color';
import menu from './menu'; import menu from './menu';
import createElement from './createElement';
let Stack = { let Stack = {
init: () => { init: () => {
@@ -74,4 +75,12 @@ window.addEventListener('load', () => {
}, 0); }, 0);
}) })
window.Stack = Stack; declare global {
interface Window {
createElement: any;
Stack: any
}
}
window.Stack = Stack;
window.createElement = createElement;
+263
View File
@@ -0,0 +1,263 @@
interface pageData {
title: string,
date: string,
permalink: string,
content: string,
image?: string,
preview: string,
matchCount: number
}
/**
* Escape HTML tags as HTML entities
* Edited from:
* @link https://stackoverflow.com/a/5499821
*/
const tagsToReplace = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'…': '&hellip;'
};
function replaceTag(tag) {
return tagsToReplace[tag] || tag;
}
function replaceHTMLEnt(str) {
return str.replace(/[&<>"]/g, replaceTag);
}
function escapeRegExp(string) {
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
}
class Search {
private data: pageData[];
private form: HTMLFormElement;
private input: HTMLInputElement;
private list: HTMLDivElement;
private resultTitle: HTMLHeadElement;
private resultTitleTemplate: string;
constructor({ form, input, list, resultTitle, resultTitleTemplate }) {
this.form = form;
this.input = input;
this.list = list;
this.resultTitle = resultTitle;
this.resultTitleTemplate = resultTitleTemplate;
this.handleQueryString();
this.bindQueryStringChange();
this.bindSearchForm();
}
private async searchKeywords(keywords: string[]) {
const rawData = await this.getData();
let results: pageData[] = [];
/// Sort keywords by their length
keywords.sort((a, b) => {
return b.length - a.length
});
for (const item of rawData) {
let result = {
...item,
preview: '',
matchCount: 0
}
let matched = false;
for (const keyword of keywords) {
if (keyword === '') continue;
const regex = new RegExp(escapeRegExp(replaceHTMLEnt(keyword)), 'gi');
const contentMatch = regex.exec(result.content);
regex.lastIndex = 0; /// Reset regex
const titleMatch = regex.exec(result.title);
regex.lastIndex = 0; /// Reset regex
if (titleMatch) {
result.title = result.title.replace(regex, Search.marker);
}
if (titleMatch || contentMatch) {
matched = true;
++result.matchCount;
let start = 0,
end = 100;
if (contentMatch) {
start = contentMatch.index - 20;
end = contentMatch.index + 80
if (start < 0) start = 0;
}
if (result.preview.indexOf(keyword) !== -1) {
result.preview = result.preview.replace(regex, Search.marker);
}
else {
if (start !== 0) result.preview += `[...] `;
result.preview += `${result.content.slice(start, end).replace(regex, Search.marker)} `;
}
}
}
if (matched) {
result.preview += '[...]';
results.push(result);
}
}
/** Result with more matches appears first */
return results.sort((a, b) => {
return b.matchCount - a.matchCount;
});
}
public static marker(match) {
return '<mark>' + match + '</mark>';
}
private async doSearch(keywords: string[]) {
const startTime = performance.now();
const results = await this.searchKeywords(keywords);
this.clear();
for (const item of results) {
this.list.append(Search.render(item));
}
const endTime = performance.now();
this.resultTitle.innerText = this.generateResultTitle(results.length, ((endTime - startTime) / 1000).toPrecision(1));
}
private generateResultTitle(resultLen, time) {
return this.resultTitleTemplate.replace("#PAGES_COUNT", resultLen).replace("#TIME_SECONDS", time);
}
public async getData() {
if (!this.data) {
/// Not fetched yet
const jsonURL = this.form.dataset.json;
this.data = await fetch(jsonURL).then(res => res.json());
}
return this.data;
}
private bindSearchForm() {
let lastSearch = '';
const eventHandler = (e) => {
e.preventDefault();
const keywords = this.input.value;
Search.updateQueryString(keywords, true);
if (keywords === '') {
return this.clear();
}
if (lastSearch === keywords) return;
lastSearch = keywords;
this.doSearch(keywords.split(' '));
}
this.input.addEventListener('input', eventHandler);
this.input.addEventListener('compositionend', eventHandler);
}
private clear() {
this.list.innerHTML = '';
this.resultTitle.innerText = '';
}
private bindQueryStringChange() {
window.addEventListener('popstate', (e) => {
this.handleQueryString()
})
}
private handleQueryString() {
const pageURL = new URL(window.location.toString());
const keywords = pageURL.searchParams.get('keyword');
this.input.value = keywords;
if (keywords) {
this.doSearch(keywords.split(' '));
}
else {
this.clear()
}
}
private static updateQueryString(keywords: string, replaceState = false) {
const pageURL = new URL(window.location.toString());
if (keywords === '') {
pageURL.searchParams.delete('keyword')
}
else {
pageURL.searchParams.set('keyword', keywords);
}
if (replaceState) {
window.history.replaceState('', '', pageURL.toString());
}
else {
window.history.pushState('', '', pageURL.toString());
}
}
public static render(item: pageData) {
return <article>
<a href={item.permalink}>
<div class="article-details">
<h2 class="article-title" dangerouslySetInnerHTML={{ __html: item.title }}></h2>
<secion class="article-preview" dangerouslySetInnerHTML={{ __html: item.preview }}></secion>
</div>
{item.image &&
<div class="article-image">
<img src={item.image} loading="lazy" />
</div>
}
</a>
</article>;
}
}
declare global {
interface Window {
searchResultTitleTemplate: string;
}
}
window.addEventListener('load', () => {
setTimeout(function () {
const searchForm = document.querySelector('.search-form') as HTMLFormElement,
searchInput = searchForm.querySelector('input') as HTMLInputElement,
searchResultList = document.querySelector('.search-result--list') as HTMLDivElement,
searchResultTitle = document.querySelector('.search-result--title') as HTMLHeadingElement;
new Search({
form: searchForm,
input: searchInput,
list: searchResultList,
resultTitle: searchResultTitle,
resultTitleTemplate: window.searchResultTitleTemplate
});
}, 0);
})
export default Search;
+7 -1
View File
@@ -40,7 +40,7 @@ DefaultContentLanguage = "en" # Theme i18n support
theme = "preferred-color-scheme" theme = "preferred-color-scheme"
[params.widgets] [params.widgets]
enabled = ['archives', 'tag-cloud'] enabled = ['search', 'archives', 'tag-cloud']
[params.widgets.archives] [params.widgets.archives]
limit = 5 limit = 5
### Archives page relative URL ### Archives page relative URL
@@ -78,6 +78,12 @@ DefaultContentLanguage = "en" # Theme i18n support
url = "archives" url = "archives"
weight = -70 weight = -70
pre = "archives" pre = "archives"
[[menu.main]]
identifier = "search"
name = "Search"
url = "search"
weight = -60
pre = "search"
[related] [related]
includeNewer = true includeNewer = true
+8
View File
@@ -0,0 +1,8 @@
---
title: "Search"
slug: "search"
layout: "search"
outputs:
- html
- json
---
@@ -13,14 +13,6 @@ Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-manageme
<!--more--> <!--more-->
--- ---
## Instagram Simple Shortcode
{{< instagram_simple BGvuInzyFAe hidecaption >}}
<br>
---
## YouTube Privacy Enhanced Shortcode ## YouTube Privacy Enhanced Shortcode
{{< youtube ZJthWmvUzzc >}} {{< youtube ZJthWmvUzzc >}}
+10 -1
View File
@@ -20,4 +20,13 @@
other = "Not Found" other = "Not Found"
[notFoundSubtitle] [notFoundSubtitle]
other = "This page does not exist." other = "This page does not exist."
[searchTitle]
other = "Search"
[searchPlaceholder]
other = "Type something..."
[searchResultTitle]
other = "#PAGES_COUNT pages (#TIME_SECONDS seconds)"
+23
View File
@@ -0,0 +1,23 @@
[toggleMenu]
other = "メニューを開く・閉じる"
[relatedContents]
other = "関連するコンテンツ"
[lastUpdatedOn]
other = "最終更新"
[widgetArchivesTitle]
other = "アーカイブ"
[widgetArchivesMore]
other = "さらに見る"
[widgetTagCloudTitle]
other = "タグ"
[notFoundTitle]
other = "404 Not Found"
[notFoundSubtitle]
other = "指定されたページは存在しません。"
+10 -1
View File
@@ -20,4 +20,13 @@
other = "404 错误" other = "404 错误"
[notFoundSubtitle] [notFoundSubtitle]
other = "页面不存在" other = "页面不存在"
[searchTitle]
other = "搜索"
[searchPlaceholder]
other = "输入关键词..."
[searchResultTitle]
other = "#PAGES_COUNT 个结果 (用时 #TIME_SECONDS 秒)"
+7 -9
View File
@@ -2,14 +2,12 @@
{{ define "main" }} {{ define "main" }}
{{ $categories := ($.Site.GetPage "taxonomyTerm" "categories").Pages }} {{ $categories := ($.Site.GetPage "taxonomyTerm" "categories").Pages }}
{{ if $categories }} {{ if $categories }}
<div class="widget"> <h2 class="section-title">Categories</h2>
<h1 class="widget-title">Categories</h1> <div class="category-list">
<div class="category-list"> <div class="article-list--tile">
<div class="article-list--tile"> {{ range $categories }}
{{ range $categories }} {{ partial "article-list/tile" (dict "context" . "size" "250x150" "Type" "taxonomy") }}
{{ partial "article-list/tile" (dict "context" . "size" "250x150" "Type" "taxonomy") }} {{ end }}
{{ end }}
</div>
</div> </div>
</div> </div>
{{ end }} {{ end }}
@@ -21,7 +19,7 @@
{{ range $filtered.GroupByDate "2006" }} {{ range $filtered.GroupByDate "2006" }}
{{ $id := lower (replace .Key " " "-") }} {{ $id := lower (replace .Key " " "-") }}
<div class="archives-group" id="{{ $id }}"> <div class="archives-group" id="{{ $id }}">
<h3 class="archives-date"><a href="{{ $.Permalink }}#{{ $id }}">{{ .Key }}</a></h3> <h2 class="archives-date section-title"><a href="{{ $.RelPermalink }}#{{ $id }}">{{ .Key }}</a></h2>
<div class="article-list--compact"> <div class="article-list--compact">
{{ range .Pages }} {{ range .Pages }}
{{ partial "article-list/compact" . }} {{ partial "article-list/compact" . }}
+4 -1
View File
@@ -1,6 +1,9 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{{ .Site.LanguageCode }}"> <html lang="{{ .Site.LanguageCode }}">
{{- partial "head/head.html" . -}} <head>
{{- partial "head/head.html" . -}}
{{- block "head" . -}}{{ end }}
</head>
<body class="{{ block `body-class` . }}{{ end }}"> <body class="{{ block `body-class` . }}{{ end }}">
<div class="container flex on-phone--column align-items--flex-start {{ if .Site.Params.widgets.enabled }}extended{{ else }}compact{{ end }} {{ block `container-class` . }}{{end}}"> <div class="container flex on-phone--column align-items--flex-start {{ if .Site.Params.widgets.enabled }}extended{{ else }}compact{{ end }} {{ block `container-class` . }}{{end}}">
{{ partial "sidebar/left.html" . }} {{ partial "sidebar/left.html" . }}
+1 -1
View File
@@ -1,5 +1,5 @@
{{ define "main" }} {{ define "main" }}
<h3 class="taxonomy-type">{{ .Type | singularize | humanize }}</h3> <h3 class="taxonomy-type section-title">{{ .Type | singularize | humanize }}</h3>
<div class="taxonomy-card"> <div class="taxonomy-card">
<div class="taxonomy-details"> <div class="taxonomy-details">
<h3 class="taxonomy-count">{{ len .Pages }} post{{ if gt (len .Pages) 1 }}s{{ end }}</h3> <h3 class="taxonomy-count">{{ len .Pages }} post{{ if gt (len .Pages) 1 }}s{{ end }}</h3>
+1 -1
View File
@@ -15,5 +15,5 @@
{{ end }} {{ end }}
{{ define "right-sidebar" }} {{ define "right-sidebar" }}
{{ partialCached "sidebar/right.html" . }} {{ partial "sidebar/right.html" . }}
{{ end }} {{ end }}
+31
View File
@@ -0,0 +1,31 @@
{{ define "body-class" }}template-search{{ end }}
{{ define "head" }}
{{- with .OutputFormats.Get "json" -}}
<link rel="preload" href="{{ .Permalink }}" as="fetch" crossorigin="anonymous">
{{- end -}}
{{ end }}
{{ define "main" }}
<form action="{{ .Permalink }}" class="search-form"{{ with .OutputFormats.Get "json" -}} data-json="{{ .Permalink }}"{{- end }}>
<p>
<label>{{ T "searchTitle" }}</label>
<input name="keyword" placeholder="{{ T `searchPlaceholder` }}" />
</p>
<button title="Search">
{{ partial "helper/icon" "search" }}
</button>
</form>
<h3 class="search-result--title section-title"></h3>
<div class="search-result--list article-list--compact"></div>
<script>
window.searchResultTitleTemplate = "{{ T `searchResultTitle` }}"
</script>
{{- $opts := dict "minify" hugo.IsProduction "JSXFactory" "createElement" -}}
{{- $searchScript := resources.Get "ts/search.tsx" | js.Build $opts -}}
<script type="text/javascript" src="{{ $searchScript.RelPermalink }}" defer></script>
{{ partialCached "footer/footer" . }}
{{ end }}
+20
View File
@@ -0,0 +1,20 @@
{{- $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections -}}
{{- $notHidden := where .Site.RegularPages "Params.hidden" "!=" true -}}
{{- $filtered := ($pages | intersect $notHidden) -}}
{{- $result := slice -}}
{{- range $filtered -}}
{{- $data := dict "title" .Title "date" .Date "permalink" .Permalink "content" (.Plain) -}}
{{- $image := partialCached "helper/image" (dict "Context" . "Type" "articleList") .RelPermalink "articleList" -}}
{{- if and $image.exists $image.resource -}}
{{- $thumbnail := $image.resource.Fill "120x120" -}}
{{- $image := dict "image" (absURL $thumbnail.Permalink) -}}
{{- $data = merge $data $image -}}
{{ end }}
{{- $result = $result | append $data -}}
{{- end -}}
{{ jsonify $result }}
+1 -1
View File
@@ -1,5 +1,5 @@
<article> <article>
<a href="{{ .Permalink }}"> <a href="{{ .RelPermalink }}">
<div class="article-details"> <div class="article-details">
<h2 class="article-title"> <h2 class="article-title">
{{- .Title -}} {{- .Title -}}
+1 -1
View File
@@ -2,7 +2,7 @@
<article class="{{ if $image.exists }}has-image{{ end }}"> <article class="{{ if $image.exists }}has-image{{ end }}">
{{ if $image.exists }} {{ if $image.exists }}
<div class="article-image"> <div class="article-image">
<a href="{{ .Permalink }}"> <a href="{{ .RelPermalink }}">
{{ if $image.resource }} {{ if $image.resource }}
{{- $thumbnail := $image.resource.Fill "800x250" -}} {{- $thumbnail := $image.resource.Fill "800x250" -}}
{{- $thumbnailRetina := $image.resource.Fill "1600x500" -}} {{- $thumbnailRetina := $image.resource.Fill "1600x500" -}}
+1 -1
View File
@@ -1,6 +1,6 @@
{{ $image := partialCached "helper/image" (dict "Context" .context "Type" .Type) .context.RelPermalink .Type }} {{ $image := partialCached "helper/image" (dict "Context" .context "Type" .Type) .context.RelPermalink .Type }}
<article class="{{ if $image.exists }}has-image{{ end }}"> <article class="{{ if $image.exists }}has-image{{ end }}">
<a href="{{ .context.Permalink }}"> <a href="{{ .context.RelPermalink }}">
{{ if $image.exists }} {{ if $image.exists }}
<div class="article-image"> <div class="article-image">
@@ -7,7 +7,7 @@
{{ if and $image.exists $image.resource }} {{ if and $image.exists $image.resource }}
{{- $imageRaw := $image.resource | resources.Fingerprint "md5" -}} {{- $imageRaw := $image.resource | resources.Fingerprint "md5" -}}
{{- $20x := $imageRaw.Fill "20x20 smart" -}} {{- $20x := $imageRaw.Fill "20x20 smart" -}}
<a href="{{ .Permalink }}" <a href="{{ .RelPermalink }}"
class="color-tag" class="color-tag"
data-image="{{ $20x.RelPermalink }}" data-image="{{ $20x.RelPermalink }}"
data-key="{{ $context.Slug }}" data-key="{{ $context.Slug }}"
@@ -15,14 +15,14 @@
{{ .LinkTitle }} {{ .LinkTitle }}
</a> </a>
{{ else }} {{ else }}
<a href="{{ .Permalink }}">{{ .LinkTitle }}</a> <a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
{{ end }} {{ end }}
{{ end }} {{ end }}
</header> </header>
{{ end }} {{ end }}
<h2 class="article-title"> <h2 class="article-title">
<a href="{{ .Permalink }}"> <a href="{{ .RelPermalink }}">
{{- .Title -}} {{- .Title -}}
</a> </a>
</h2> </h2>
@@ -1,7 +1,7 @@
<aside class="widget related-contents--wrapper"> <aside class="related-contents--wrapper">
{{ $related := .Site.RegularPages.Related . | first 5 }} {{ $related := (where (.Site.RegularPages.Related .) "Params.hidden" "!=" true) | first 5 }}
{{ with $related }} {{ with $related }}
<h1 class="widget-title">{{ T "relatedContents" }}</h1> <h2 class="section-title">{{ T "relatedContents" }}</h2>
<div class="related-contents"> <div class="related-contents">
<div class="flex article-list--tile"> <div class="flex article-list--tile">
{{ range . }} {{ range . }}
@@ -10,4 +10,4 @@
</div> </div>
</div> </div>
{{ end }} {{ end }}
</aside> </aside>
@@ -1,7 +1,7 @@
{{ if .Params.Tags }} {{ if .Params.Tags }}
<section class="article-tags"> <section class="article-tags">
{{ range (.GetTerms "tags") }} {{ range (.GetTerms "tags") }}
<a href="{{ .Permalink }}">{{ .LinkTitle }}</a> <a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
{{ end }} {{ end }}
</section> </section>
{{ end }} {{ end }}
+1 -1
View File
@@ -2,7 +2,7 @@
<section class="copyright">&copy; {{ now.Format "2006" }} {{ .Site.Title }}</section> <section class="copyright">&copy; {{ now.Format "2006" }} {{ .Site.Title }}</section>
<section class="powerby"> <section class="powerby">
Built with <a href="https://gohugo.io/" target="_blank" rel="noopener">Hugo</a> <br /> Built with <a href="https://gohugo.io/" target="_blank" rel="noopener">Hugo</a> <br />
Theme <b><a href="https://github.com/CaiJimmy/hugo-theme-stack" target="_blank" rel="noopener" data-version="1.0.5">Stack</a></b> designed by Theme <b><a href="https://github.com/CaiJimmy/hugo-theme-stack" target="_blank" rel="noopener" data-version="1.1.0">Stack</a></b> designed by
<a href="https://jimmycai.com" target="_blank" rel="noopener">Jimmy</a> <a href="https://jimmycai.com" target="_blank" rel="noopener">Jimmy</a>
</section> </section>
</footer> </footer>
+18 -20
View File
@@ -1,22 +1,20 @@
<head> <meta charset='utf-8'>
<meta charset='utf-8'> <meta name='viewport' content='width=device-width, initial-scale=1'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
{{- $description := partialCached "data/description" . .RelPermalink -}}
<meta name='description' content='{{ $description }}'>
{{- $title := partialCached "data/title" . .RelPermalink -}} {{- $description := partialCached "data/description" . .RelPermalink -}}
<title>{{ $title }}</title> <meta name='description' content='{{ $description }}'>
<link rel='canonical' href='{{ .Permalink }}'>
{{- partial "head/style.html" . -}}
{{- partial "head/script.html" . -}}
{{- partial "head/opengraph/include.html" . -}}
{{- range .AlternativeOutputFormats -}} {{- $title := partialCached "data/title" . .RelPermalink -}}
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}"> <title>{{ $title }}</title>
{{- end -}}
<link rel='canonical' href='{{ .Permalink }}'>
{{- partial "head/custom.html" . -}}
</head> {{- partial "head/style.html" . -}}
{{- partial "head/script.html" . -}}
{{- partial "head/opengraph/include.html" . -}}
{{- range .AlternativeOutputFormats -}}
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">
{{- end -}}
{{- partial "head/custom.html" . -}}
+1 -1
View File
@@ -31,7 +31,7 @@
{{ $active := or (eq $currentPage.Title .Name) (or ($currentPage.HasMenuCurrent "main" .) ($currentPage.IsMenuCurrent "main" .)) }} {{ $active := or (eq $currentPage.Title .Name) (or ($currentPage.HasMenuCurrent "main" .) ($currentPage.IsMenuCurrent "main" .)) }}
<li {{ if $active }} class='current' {{ end }}> <li {{ if $active }} class='current' {{ end }}>
<a href='{{ .URL | absLangURL }}'> <a href='{{ .URL | relURL }}'>
{{ if .Pre }} {{ if .Pre }}
{{ partial "helper/icon" .Pre }} {{ partial "helper/icon" .Pre }}
{{ end }} {{ end }}
+18 -16
View File
@@ -2,24 +2,26 @@
<div class="widget-icon"> <div class="widget-icon">
{{ partial "helper/icon" "infinity" }} {{ partial "helper/icon" "infinity" }}
</div> </div>
<h1 class="widget-title">{{ T "widgetArchivesTitle" }}</h1> <h2 class="widget-title section-title">{{ T "widgetArchivesTitle" }}</h2>
{{ $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections }} {{ $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections }}
{{ $notHidden := where .Site.RegularPages "Params.hidden" "!=" true }} {{ $notHidden := where .Site.RegularPages "Params.hidden" "!=" true }}
{{ $filtered := ($pages | intersect $notHidden) }} {{ $filtered := ($pages | intersect $notHidden) }}
{{ $archives := $filtered.GroupByDate "2006" }} {{ $archives := $filtered.GroupByDate "2006" }}
{{ range $index, $item := first (add .Site.Params.widgets.archives.limit 1) ($archives) }} <div class="widget-archive--list">
{{- $id := lower (replace $item.Key " " "-") -}} {{ range $index, $item := first (add .Site.Params.widgets.archives.limit 1) ($archives) }}
<div class="archives-year"> {{- $id := lower (replace $item.Key " " "-") -}}
<a href="{{ $.Site.Params.widgets.archives.path | relLangURL }}#{{ $id }}"> <div class="archives-year">
{{ if eq $index $.Site.Params.widgets.archives.limit }} <a href="{{ $.Site.Params.widgets.archives.path | relLangURL }}#{{ $id }}">
<span class="year">{{ T "widgetArchivesMore" }}</span> {{ if eq $index $.Site.Params.widgets.archives.limit }}
{{ else }} <span class="year">{{ T "widgetArchivesMore" }}</span>
<span class="year">{{ .Key }}</span> {{ else }}
<span class="count">{{ len $item.Pages }}</span> <span class="year">{{ .Key }}</span>
{{ end }} <span class="count">{{ len $item.Pages }}</span>
</a> {{ end }}
</div> </a>
{{ end }} </div>
</section> {{ end }}
</div>
</section>
+10
View File
@@ -0,0 +1,10 @@
<form action="/search" class="search-form widget" {{ with .OutputFormats.Get "json" -}}data-json="{{ .Permalink }}" {{- end }}>
<p>
<label>{{ T "searchTitle" }}</label>
<input name="keyword" required placeholder="{{ T `searchPlaceholder` }}" />
<button title="Search">
{{ partial "helper/icon" "search" }}
</button>
</p>
</form>
+2 -2
View File
@@ -2,11 +2,11 @@
<div class="widget-icon"> <div class="widget-icon">
{{ partial "helper/icon" "tag" }} {{ partial "helper/icon" "tag" }}
</div> </div>
<h1 class="widget-title">{{ T "widgetTagCloudTitle" }}</h1> <h2 class="widget-title section-title">{{ T "widgetTagCloudTitle" }}</h2>
<div class="tagCloud-tags"> <div class="tagCloud-tags">
{{ range first .Site.Params.widgets.tagCloud.limit .Site.Taxonomies.tags.ByCount }} {{ range first .Site.Params.widgets.tagCloud.limit .Site.Taxonomies.tags.ByCount }}
<a href="{{ .Page.Permalink }}" class="font_size_{{ .Count }}"> <a href="{{ .Page.RelPermalink }}" class="font_size_{{ .Count }}">
{{ .Page.Title }} {{ .Page.Title }}
</a> </a>
{{ end }} {{ end }}
File diff suppressed because one or more lines are too long