Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd408279e4 | ||
|
|
f3107a35a7 | ||
|
|
695260cf0d | ||
|
|
5bc567082b | ||
|
|
148f0ff8fe | ||
|
|
efa7ff14b7 | ||
|
|
a81dac7bb0 | ||
|
|
c018f4967a | ||
|
|
f5d45458fd | ||
|
|
b97e86a7a7 | ||
|
|
2736fec285 | ||
|
|
3db6df8f46 | ||
|
|
37a2090739 | ||
|
|
a3f1d84c51 | ||
|
|
b3df22940d | ||
|
|
be416830ad | ||
|
|
c3b3c2f0ee | ||
|
|
b5645f0180 | ||
|
|
d6b0f10241 | ||
|
|
c666c79800 | ||
|
|
f7b61b9556 | ||
|
|
5c55bd2d33 | ||
|
|
34cd7852bc | ||
|
|
49e568faac | ||
|
|
26fedaebd2 | ||
|
|
26bdeb3afb | ||
|
|
c266204f98 | ||
|
|
8e8509177d | ||
|
|
3bc73a8b48 | ||
|
|
17d77155bf | ||
|
|
b027cbf5aa | ||
|
|
84a15e1604 | ||
|
|
8aeb562bb3 | ||
|
|
c19780280e | ||
|
|
6e48765d82 | ||
|
|
08102e2f69 | ||
|
|
6fa69d7a2b | ||
|
|
21f461ce78 | ||
|
|
e5f96c8762 |
@@ -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
|
||||
@@ -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 }}
|
||||
@@ -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 |
@@ -0,0 +1 @@
|
||||
/* Place your custom SCSS in HUGO_SITE_FOLDER/assets/scss/custom.scss */
|
||||
@@ -199,6 +199,13 @@
|
||||
.article-time {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.article-preview{
|
||||
font-size: 1.4rem;
|
||||
color: var(--card-text-color-tertiary);
|
||||
margin-top: 10px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
.archives-group {
|
||||
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 {
|
||||
|
||||
@@ -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 {
|
||||
border-radius: var(--card-border-radius);
|
||||
background-color: var(--card-background);
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
.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 {
|
||||
svg {
|
||||
width: 32px;
|
||||
@@ -45,27 +36,26 @@
|
||||
|
||||
/* Archives widget */
|
||||
.widget.archives {
|
||||
.widget-archive--list {
|
||||
border-radius: var(--card-border-radius);
|
||||
box-shadow: var(--shadow-l1);
|
||||
background-color: var(--card-background);
|
||||
}
|
||||
|
||||
.archives-year {
|
||||
margin-bottom: 10px;
|
||||
&:not(:last-of-type) {
|
||||
border-bottom: 1.5px solid var(--card-separator-color);
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: var(--card-background);
|
||||
padding: 15px 25px;
|
||||
border-radius: var(--card-border-radius);
|
||||
box-shadow: var(--shadow-l1);
|
||||
font-size: 1.4rem;
|
||||
padding: 18px 25px;
|
||||
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 {
|
||||
flex: 1;
|
||||
color: var(--card-text-color-main);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span.count {
|
||||
|
||||
+18
-1
@@ -23,6 +23,9 @@
|
||||
@import "partials/layout/article.scss";
|
||||
@import "partials/layout/taxonomy.scss";
|
||||
@import "partials/layout/404.scss";
|
||||
@import "partials/layout/search.scss";
|
||||
|
||||
@import "custom.scss";
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
@@ -40,4 +43,18 @@ a {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -9,6 +9,7 @@
|
||||
import { createGallery } from "./gallery"
|
||||
import { getColor } from './color';
|
||||
import menu from './menu';
|
||||
import createElement from './createElement';
|
||||
|
||||
let Stack = {
|
||||
init: () => {
|
||||
@@ -74,4 +75,12 @@ window.addEventListener('load', () => {
|
||||
}, 0);
|
||||
})
|
||||
|
||||
window.Stack = Stack;
|
||||
declare global {
|
||||
interface Window {
|
||||
createElement: any;
|
||||
Stack: any
|
||||
}
|
||||
}
|
||||
|
||||
window.Stack = Stack;
|
||||
window.createElement = createElement;
|
||||
@@ -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 = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
'…': '…'
|
||||
};
|
||||
|
||||
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;
|
||||
@@ -40,7 +40,7 @@ DefaultContentLanguage = "en" # Theme i18n support
|
||||
theme = "preferred-color-scheme"
|
||||
|
||||
[params.widgets]
|
||||
enabled = ['archives', 'tag-cloud']
|
||||
enabled = ['search', 'archives', 'tag-cloud']
|
||||
[params.widgets.archives]
|
||||
limit = 5
|
||||
### Archives page relative URL
|
||||
@@ -78,6 +78,12 @@ DefaultContentLanguage = "en" # Theme i18n support
|
||||
url = "archives"
|
||||
weight = -70
|
||||
pre = "archives"
|
||||
[[menu.main]]
|
||||
identifier = "search"
|
||||
name = "Search"
|
||||
url = "search"
|
||||
weight = -60
|
||||
pre = "search"
|
||||
|
||||
[related]
|
||||
includeNewer = true
|
||||
|
||||
@@ -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-->
|
||||
---
|
||||
|
||||
## Instagram Simple Shortcode
|
||||
|
||||
{{< instagram_simple BGvuInzyFAe hidecaption >}}
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
## YouTube Privacy Enhanced Shortcode
|
||||
|
||||
{{< youtube ZJthWmvUzzc >}}
|
||||
|
||||
+10
-1
@@ -20,4 +20,13 @@
|
||||
other = "Not Found"
|
||||
|
||||
[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)"
|
||||
@@ -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
@@ -20,4 +20,13 @@
|
||||
other = "404 错误"
|
||||
|
||||
[notFoundSubtitle]
|
||||
other = "页面不存在"
|
||||
other = "页面不存在"
|
||||
|
||||
[searchTitle]
|
||||
other = "搜索"
|
||||
|
||||
[searchPlaceholder]
|
||||
other = "输入关键词..."
|
||||
|
||||
[searchResultTitle]
|
||||
other = "#PAGES_COUNT 个结果 (用时 #TIME_SECONDS 秒)"
|
||||
@@ -2,14 +2,12 @@
|
||||
{{ define "main" }}
|
||||
{{ $categories := ($.Site.GetPage "taxonomyTerm" "categories").Pages }}
|
||||
{{ if $categories }}
|
||||
<div class="widget">
|
||||
<h1 class="widget-title">Categories</h1>
|
||||
<div class="category-list">
|
||||
<div class="article-list--tile">
|
||||
{{ range $categories }}
|
||||
{{ partial "article-list/tile" (dict "context" . "size" "250x150" "Type" "taxonomy") }}
|
||||
{{ end }}
|
||||
</div>
|
||||
<h2 class="section-title">Categories</h2>
|
||||
<div class="category-list">
|
||||
<div class="article-list--tile">
|
||||
{{ range $categories }}
|
||||
{{ partial "article-list/tile" (dict "context" . "size" "250x150" "Type" "taxonomy") }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -21,7 +19,7 @@
|
||||
{{ range $filtered.GroupByDate "2006" }}
|
||||
{{ $id := lower (replace .Key " " "-") }}
|
||||
<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">
|
||||
{{ range .Pages }}
|
||||
{{ partial "article-list/compact" . }}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ .Site.LanguageCode }}">
|
||||
{{- partial "head/head.html" . -}}
|
||||
<head>
|
||||
{{- partial "head/head.html" . -}}
|
||||
{{- block "head" . -}}{{ end }}
|
||||
</head>
|
||||
<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}}">
|
||||
{{ partial "sidebar/left.html" . }}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{{ 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-details">
|
||||
<h3 class="taxonomy-count">{{ len .Pages }} post{{ if gt (len .Pages) 1 }}s{{ end }}</h3>
|
||||
|
||||
+1
-1
@@ -15,5 +15,5 @@
|
||||
{{ end }}
|
||||
|
||||
{{ define "right-sidebar" }}
|
||||
{{ partialCached "sidebar/right.html" . }}
|
||||
{{ partial "sidebar/right.html" . }}
|
||||
{{ end }}
|
||||
@@ -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 }}
|
||||
@@ -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,5 +1,5 @@
|
||||
<article>
|
||||
<a href="{{ .Permalink }}">
|
||||
<a href="{{ .RelPermalink }}">
|
||||
<div class="article-details">
|
||||
<h2 class="article-title">
|
||||
{{- .Title -}}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<article class="{{ if $image.exists }}has-image{{ end }}">
|
||||
{{ if $image.exists }}
|
||||
<div class="article-image">
|
||||
<a href="{{ .Permalink }}">
|
||||
<a href="{{ .RelPermalink }}">
|
||||
{{ if $image.resource }}
|
||||
{{- $thumbnail := $image.resource.Fill "800x250" -}}
|
||||
{{- $thumbnailRetina := $image.resource.Fill "1600x500" -}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{{ $image := partialCached "helper/image" (dict "Context" .context "Type" .Type) .context.RelPermalink .Type }}
|
||||
<article class="{{ if $image.exists }}has-image{{ end }}">
|
||||
<a href="{{ .context.Permalink }}">
|
||||
<a href="{{ .context.RelPermalink }}">
|
||||
|
||||
{{ if $image.exists }}
|
||||
<div class="article-image">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{{ if and $image.exists $image.resource }}
|
||||
{{- $imageRaw := $image.resource | resources.Fingerprint "md5" -}}
|
||||
{{- $20x := $imageRaw.Fill "20x20 smart" -}}
|
||||
<a href="{{ .Permalink }}"
|
||||
<a href="{{ .RelPermalink }}"
|
||||
class="color-tag"
|
||||
data-image="{{ $20x.RelPermalink }}"
|
||||
data-key="{{ $context.Slug }}"
|
||||
@@ -15,14 +15,14 @@
|
||||
{{ .LinkTitle }}
|
||||
</a>
|
||||
{{ else }}
|
||||
<a href="{{ .Permalink }}">{{ .LinkTitle }}</a>
|
||||
<a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</header>
|
||||
{{ end }}
|
||||
|
||||
<h2 class="article-title">
|
||||
<a href="{{ .Permalink }}">
|
||||
<a href="{{ .RelPermalink }}">
|
||||
{{- .Title -}}
|
||||
</a>
|
||||
</h2>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<aside class="widget related-contents--wrapper">
|
||||
{{ $related := .Site.RegularPages.Related . | first 5 }}
|
||||
<aside class="related-contents--wrapper">
|
||||
{{ $related := (where (.Site.RegularPages.Related .) "Params.hidden" "!=" true) | first 5 }}
|
||||
{{ with $related }}
|
||||
<h1 class="widget-title">{{ T "relatedContents" }}</h1>
|
||||
<h2 class="section-title">{{ T "relatedContents" }}</h2>
|
||||
<div class="related-contents">
|
||||
<div class="flex article-list--tile">
|
||||
{{ range . }}
|
||||
@@ -10,4 +10,4 @@
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</aside>
|
||||
</aside>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{{ if .Params.Tags }}
|
||||
<section class="article-tags">
|
||||
{{ range (.GetTerms "tags") }}
|
||||
<a href="{{ .Permalink }}">{{ .LinkTitle }}</a>
|
||||
<a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
|
||||
{{ end }}
|
||||
</section>
|
||||
{{ end }}
|
||||
@@ -2,7 +2,7 @@
|
||||
<section class="copyright">© {{ now.Format "2006" }} {{ .Site.Title }}</section>
|
||||
<section class="powerby">
|
||||
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>
|
||||
</section>
|
||||
</footer>
|
||||
@@ -1,22 +1,20 @@
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
|
||||
{{- $description := partialCached "data/description" . .RelPermalink -}}
|
||||
<meta name='description' content='{{ $description }}'>
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
|
||||
{{- $title := partialCached "data/title" . .RelPermalink -}}
|
||||
<title>{{ $title }}</title>
|
||||
|
||||
<link rel='canonical' href='{{ .Permalink }}'>
|
||||
|
||||
{{- partial "head/style.html" . -}}
|
||||
{{- partial "head/script.html" . -}}
|
||||
{{- partial "head/opengraph/include.html" . -}}
|
||||
{{- $description := partialCached "data/description" . .RelPermalink -}}
|
||||
<meta name='description' content='{{ $description }}'>
|
||||
|
||||
{{- range .AlternativeOutputFormats -}}
|
||||
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">
|
||||
{{- end -}}
|
||||
|
||||
{{- partial "head/custom.html" . -}}
|
||||
</head>
|
||||
{{- $title := partialCached "data/title" . .RelPermalink -}}
|
||||
<title>{{ $title }}</title>
|
||||
|
||||
<link rel='canonical' href='{{ .Permalink }}'>
|
||||
|
||||
{{- 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" . -}}
|
||||
@@ -31,7 +31,7 @@
|
||||
{{ $active := or (eq $currentPage.Title .Name) (or ($currentPage.HasMenuCurrent "main" .) ($currentPage.IsMenuCurrent "main" .)) }}
|
||||
|
||||
<li {{ if $active }} class='current' {{ end }}>
|
||||
<a href='{{ .URL | absLangURL }}'>
|
||||
<a href='{{ .URL | relURL }}'>
|
||||
{{ if .Pre }}
|
||||
{{ partial "helper/icon" .Pre }}
|
||||
{{ end }}
|
||||
|
||||
@@ -2,24 +2,26 @@
|
||||
<div class="widget-icon">
|
||||
{{ partial "helper/icon" "infinity" }}
|
||||
</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 }}
|
||||
{{ $notHidden := where .Site.RegularPages "Params.hidden" "!=" true }}
|
||||
{{ $filtered := ($pages | intersect $notHidden) }}
|
||||
{{ $archives := $filtered.GroupByDate "2006" }}
|
||||
|
||||
{{ range $index, $item := first (add .Site.Params.widgets.archives.limit 1) ($archives) }}
|
||||
{{- $id := lower (replace $item.Key " " "-") -}}
|
||||
<div class="archives-year">
|
||||
<a href="{{ $.Site.Params.widgets.archives.path | relLangURL }}#{{ $id }}">
|
||||
{{ if eq $index $.Site.Params.widgets.archives.limit }}
|
||||
<span class="year">{{ T "widgetArchivesMore" }}</span>
|
||||
{{ else }}
|
||||
<span class="year">{{ .Key }}</span>
|
||||
<span class="count">{{ len $item.Pages }}</span>
|
||||
{{ end }}
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
</section>
|
||||
|
||||
<div class="widget-archive--list">
|
||||
{{ range $index, $item := first (add .Site.Params.widgets.archives.limit 1) ($archives) }}
|
||||
{{- $id := lower (replace $item.Key " " "-") -}}
|
||||
<div class="archives-year">
|
||||
<a href="{{ $.Site.Params.widgets.archives.path | relLangURL }}#{{ $id }}">
|
||||
{{ if eq $index $.Site.Params.widgets.archives.limit }}
|
||||
<span class="year">{{ T "widgetArchivesMore" }}</span>
|
||||
{{ else }}
|
||||
<span class="year">{{ .Key }}</span>
|
||||
<span class="count">{{ len $item.Pages }}</span>
|
||||
{{ end }}
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</section>
|
||||
@@ -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,11 +2,11 @@
|
||||
<div class="widget-icon">
|
||||
{{ partial "helper/icon" "tag" }}
|
||||
</div>
|
||||
<h1 class="widget-title">{{ T "widgetTagCloudTitle" }}</h1>
|
||||
<h2 class="widget-title section-title">{{ T "widgetTagCloudTitle" }}</h2>
|
||||
|
||||
<div class="tagCloud-tags">
|
||||
{{ 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 }}
|
||||
</a>
|
||||
{{ end }}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user