mirror of
https://github.com/jerryc127/hexo-theme-butterfly.git
synced 2026-04-10 21:17:07 +08:00
Compare commits
80 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
496234c8ad | ||
|
|
8d5ca45948 | ||
|
|
04e36c8d8a | ||
|
|
5c2894d3d5 | ||
|
|
63353566d2 | ||
|
|
f0588a3967 | ||
|
|
0834720d32 | ||
|
|
183d01b9eb | ||
|
|
7e8d666bf7 | ||
|
|
49b6c7436c | ||
|
|
1e24c62f70 | ||
|
|
5e30032a5f | ||
|
|
47214b5a7c | ||
|
|
d62f047073 | ||
|
|
5a13f01649 | ||
|
|
09b7342882 | ||
|
|
4c9395666d | ||
|
|
f4d0687750 | ||
|
|
e80ecb43ef | ||
|
|
93f7461d28 | ||
|
|
841fbb0c5e | ||
|
|
247e62a418 | ||
|
|
8199e25215 | ||
|
|
b34eeb0425 | ||
|
|
63dc605794 | ||
|
|
a7d6d0fb80 | ||
|
|
768d9e370b | ||
|
|
a3e46f757b | ||
|
|
431b5fa7ce | ||
|
|
8a50b80527 | ||
|
|
3694ee01df | ||
|
|
c579dad041 | ||
|
|
5baf759749 | ||
|
|
532b74edde | ||
|
|
08fabdc2d1 | ||
|
|
6a50b62869 | ||
|
|
396fb102da | ||
|
|
929a5608d3 | ||
|
|
9a3b41912a | ||
|
|
0f915f47ef | ||
|
|
e2565a9f39 | ||
|
|
4cd26d183c | ||
|
|
f218a0a14a | ||
|
|
6c7debfd24 | ||
|
|
eb88a5bb4a | ||
|
|
f07823903f | ||
|
|
4bd5edd955 | ||
|
|
ecf4d341e6 | ||
|
|
5c0d578e4c | ||
|
|
21f71cd0f2 | ||
|
|
f775e97548 | ||
|
|
54a4fa381d | ||
|
|
bf3a43e62a | ||
|
|
274a499aff | ||
|
|
48781800f3 | ||
|
|
449fe2f876 | ||
|
|
06ab48f607 | ||
|
|
e0382c80ae | ||
|
|
a1589c0212 | ||
|
|
ff6fc30743 | ||
|
|
fef6dcf6c6 | ||
|
|
5fd171bab0 | ||
|
|
0b0cb38b59 | ||
|
|
65b1ad32c8 | ||
|
|
13cf15c369 | ||
|
|
6b7d0d9806 | ||
|
|
c17b0cb553 | ||
|
|
c866315b87 | ||
|
|
2404eee5c1 | ||
|
|
5e656b7072 | ||
|
|
a405217462 | ||
|
|
8cfa1665b9 | ||
|
|
d12f5be271 | ||
|
|
26f2c1b4e3 | ||
|
|
bb7fc446fc | ||
|
|
49e4903b34 | ||
|
|
91641646a7 | ||
|
|
4b8492a377 | ||
|
|
a36c9ca6d2 | ||
|
|
6361f28328 |
10
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
10
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -16,6 +16,16 @@ body:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: modify
|
||||
attributes:
|
||||
label: 是否修改过主题文件? || Has the theme files been modified?
|
||||
options:
|
||||
- 是 (Yes)
|
||||
- 不是 (No)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: browser
|
||||
attributes:
|
||||
|
||||
20
.github/stale.yml
vendored
20
.github/stale.yml
vendored
@@ -1,20 +0,0 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 30
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
- bug
|
||||
- enhancement
|
||||
- documentation
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
19
.github/workflows/stale.yml
vendored
Normal file
19
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
days-before-issue-stale: 30
|
||||
days-before-pr-stale: -1
|
||||
days-before-close: 7
|
||||
stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
|
||||
close-pr-message: 'This issue has not seen any activity since it was marked stale. Closing.'
|
||||
stale-issue-label: 'Stale'
|
||||
exempt-issue-labels: 'pinned,bug,enhancement,documentation,Plan'
|
||||
operations-per-run: 1000
|
||||
@@ -79,9 +79,9 @@ npm i hexo-theme-butterfly
|
||||
- [x] Related articles
|
||||
- [x] Displays outdated notice for a post
|
||||
- [x] Share (AddThis/Sharejs/Addtoany)
|
||||
- [X] Comment (Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42)
|
||||
- [X] Comment (Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42/artalk)
|
||||
- [x] Multiple Comment System Support
|
||||
- [x] Online Chats (Chatra/Tidio/Daovoice/Gitter/Crisp)
|
||||
- [x] Online Chats (Chatra/Tidio/Daovoice/Crisp/messenger)
|
||||
- [x] Web analytics
|
||||
- [x] Google AdSense
|
||||
- [x] Webmaster Verification
|
||||
@@ -89,7 +89,7 @@ npm i hexo-theme-butterfly
|
||||
- [x] Typewriter Effect: activate_power_mode
|
||||
- [x] Background effects (Canvas ribbon/canvas_ribbon_piao/canvas_nest)
|
||||
- [x] Mouse click effects (Fireworks/Heart/Text)
|
||||
- [x] Preloader/Loading Animation
|
||||
- [x] Preloader/Loading Animation/pace.js
|
||||
- [x] Busuanzi visitor counter
|
||||
- [x] Medium Zoom/Fancybox
|
||||
- [x] Mermaid
|
||||
|
||||
@@ -79,9 +79,9 @@ theme: butterfly
|
||||
- [x] 顯示相關文章
|
||||
- [x] 過期文章提醒
|
||||
- [x] 多種分享系統(AddThis/Sharejs/Addtoany)
|
||||
- [X] 多種評論系統(Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42)
|
||||
- [X] 多種評論系統(Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42/artalk)
|
||||
- [x] 支持雙評論部署
|
||||
- [x] 多種在線聊天(Chatra/Tidio/Daovoice/Gitter/Crisp)
|
||||
- [x] 多種在線聊天(Chatra/Tidio/Daovoice/Crisp/messenger)
|
||||
- [x] 多種分析系統
|
||||
- [x] 谷歌廣告/手動廣告位置
|
||||
- [x] 各種站長驗證(Google/Bing/Baidu/360/Yandex)
|
||||
@@ -89,7 +89,7 @@ theme: butterfly
|
||||
- [x] 打字特效 activate_power_mode
|
||||
- [x] 多種背景特效(靜止彩帶/動態彩帶/Canvas Nest)
|
||||
- [x] 多種鼠標點擊特效(煙花/文字/愛心)
|
||||
- [x] 內置一種 Preloader 加載動畫
|
||||
- [x] 內置一種 Preloader 加載動畫和 pace.js 加載動畫條
|
||||
- [x] 不蒜子訪問統計
|
||||
- [x] 兩種大圖模式(Medium Zoom/Fancybox)
|
||||
- [x] Mermaid 圖表顯示
|
||||
@@ -97,7 +97,7 @@ theme: butterfly
|
||||
- [x] 圖片懶加載
|
||||
- [x] Instantpage/Pangu/Snackbar彈窗/PWA......
|
||||
|
||||
## ✨ 贡献者
|
||||
## ✨ 貢獻者
|
||||
|
||||
<a href="https://github.com/jerryc127/hexo-theme-butterfly/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=jerryc127/hexo-theme-butterfly" />
|
||||
|
||||
493
_config.yml
493
_config.yml
@@ -1,7 +1,13 @@
|
||||
# Main menu navigation (導航目錄)
|
||||
# see https://butterfly.js.org/posts/4aa8abbe/#導航菜單
|
||||
# Navigation bar settings (導航欄設置)
|
||||
# see https://butterfly.js.org/posts/4aa8abbe/##導航欄設置-Navigation-bar-settings
|
||||
# --------------------------------------
|
||||
|
||||
nav:
|
||||
logo: # image
|
||||
display_title: true
|
||||
fixed: false # fixed navigation bar
|
||||
|
||||
# Menu 目錄
|
||||
menu:
|
||||
# Home: / || fas fa-home
|
||||
# Archives: /archives/ || fas fa-archive
|
||||
@@ -23,54 +29,12 @@ highlight_shrink: false # true: shrink the code blocks / false: expand the code
|
||||
highlight_height_limit: false # unit: px
|
||||
code_word_wrap: false
|
||||
|
||||
# copy settings
|
||||
# copyright: Add the copyright information after copied content (複製的內容後面加上版權信息)
|
||||
copy:
|
||||
enable: true
|
||||
copyright:
|
||||
enable: false
|
||||
limit_count: 50
|
||||
|
||||
# social settings (社交圖標設置)
|
||||
# Social Settings (社交圖標設置)
|
||||
# formal:
|
||||
# icon: link || the description
|
||||
# icon: link || the description || color
|
||||
social:
|
||||
# fab fa-github: https://github.com/xxxxx || Github
|
||||
# fas fa-envelope: mailto:xxxxxx@gmail.com || Email
|
||||
|
||||
# search (搜索)
|
||||
# see https://butterfly.js.org/posts/ceeb73f/#搜索系統
|
||||
# --------------------------------------
|
||||
|
||||
# Algolia search
|
||||
algolia_search:
|
||||
enable: false
|
||||
hits:
|
||||
per_page: 6
|
||||
|
||||
# Local search
|
||||
local_search:
|
||||
enable: false
|
||||
preload: false
|
||||
CDN:
|
||||
|
||||
# Math (數學)
|
||||
# --------------------------------------
|
||||
# About the per_page
|
||||
# if you set it to true, it will load mathjax/katex script in each page (true 表示每一頁都加載js)
|
||||
# if you set it to false, it will load mathjax/katex script according to your setting (add the 'mathjax: true' in page's front-matter)
|
||||
# (false 需要時加載,須在使用的 Markdown Front-matter 加上 mathjax: true)
|
||||
|
||||
# MathJax
|
||||
mathjax:
|
||||
enable: false
|
||||
per_page: false
|
||||
|
||||
# KaTeX
|
||||
katex:
|
||||
enable: false
|
||||
per_page: false
|
||||
hide_scrollbar: true
|
||||
# fab fa-github: https://github.com/xxxxx || Github || '#24292e'
|
||||
# fas fa-envelope: mailto:xxxxxx@gmail.com || Email || '#4a7dbe'
|
||||
|
||||
# Image (圖片設置)
|
||||
# --------------------------------------
|
||||
@@ -150,14 +114,6 @@ post_meta:
|
||||
tags: true # true or false 文章頁是否顯示標籤
|
||||
label: true # true or false 顯示描述性文字
|
||||
|
||||
# wordcount (字數統計)
|
||||
# see https://butterfly.js.org/posts/ceeb73f/#字數統計
|
||||
wordcount:
|
||||
enable: false
|
||||
post_wordcount: true
|
||||
min2read: true
|
||||
total_wordcount: true
|
||||
|
||||
# Display the article introduction on homepage
|
||||
# 1: description
|
||||
# 2: both (if the description exists, it will show description, or show the auto_excerpt)
|
||||
@@ -168,8 +124,23 @@ index_post_content:
|
||||
length: 500 # if you set method to 2 or 3, the length need to config
|
||||
|
||||
# anchor
|
||||
# when you scroll in post, the URL will update according to header id.
|
||||
anchor: false
|
||||
anchor:
|
||||
button:
|
||||
enable: false
|
||||
always_show: false
|
||||
icon: # the unicode value of Font Awesome icon, such as '\3423'
|
||||
auto_update: false # when you scroll in post, the URL will update according to header id.
|
||||
|
||||
# figcaption (圖片描述文字)
|
||||
photofigcaption: false
|
||||
|
||||
# copy settings
|
||||
# copyright: Add the copyright information after copied content (複製的內容後面加上版權信息)
|
||||
copy:
|
||||
enable: true
|
||||
copyright:
|
||||
enable: false
|
||||
limit_count: 50
|
||||
|
||||
# Post
|
||||
# --------------------------------------
|
||||
@@ -181,6 +152,7 @@ toc:
|
||||
number: true
|
||||
expand: false
|
||||
style_simple: false # for post
|
||||
scroll_percent: true
|
||||
|
||||
post_copyright:
|
||||
enable: true
|
||||
@@ -214,9 +186,6 @@ related_post:
|
||||
limit: 6 # Number of posts displayed
|
||||
date_type: created # or created or updated 文章日期顯示創建日或者更新日
|
||||
|
||||
# figcaption (圖片描述文字)
|
||||
photofigcaption: false
|
||||
|
||||
# post_pagination (分頁)
|
||||
# value: 1 || 2 || false
|
||||
# 1: The 'next post' will link to old post
|
||||
@@ -233,7 +202,183 @@ noticeOutdate:
|
||||
message_prev: It has been
|
||||
message_next: days since the last update, the content of the article may be outdated.
|
||||
|
||||
# Share System (分享功能)
|
||||
# Footer Settings
|
||||
# --------------------------------------
|
||||
footer:
|
||||
owner:
|
||||
enable: true
|
||||
since: 2020
|
||||
custom_text:
|
||||
copyright: true # Copyright of theme and framework
|
||||
|
||||
# aside (側邊欄)
|
||||
# --------------------------------------
|
||||
|
||||
aside:
|
||||
enable: true
|
||||
hide: false
|
||||
button: true
|
||||
mobile: true # display on mobile
|
||||
position: right # left or right
|
||||
display:
|
||||
archive: true
|
||||
tag: true
|
||||
category: true
|
||||
card_author:
|
||||
enable: true
|
||||
description:
|
||||
button:
|
||||
enable: true
|
||||
icon: fab fa-github
|
||||
text: Follow Me
|
||||
link: https://github.com/xxxxxx
|
||||
card_announcement:
|
||||
enable: true
|
||||
content: This is my Blog
|
||||
card_recent_post:
|
||||
enable: true
|
||||
limit: 5 # if set 0 will show all
|
||||
sort: date # date or updated
|
||||
sort_order: # Don't modify the setting unless you know how it works
|
||||
card_categories:
|
||||
enable: true
|
||||
limit: 8 # if set 0 will show all
|
||||
expand: none # none/true/false
|
||||
sort_order: # Don't modify the setting unless you know how it works
|
||||
card_tags:
|
||||
enable: true
|
||||
limit: 40 # if set 0 will show all
|
||||
color: false
|
||||
orderby: random # Order of tags, random/name/length
|
||||
order: 1 # Sort of order. 1, asc for ascending; -1, desc for descending
|
||||
sort_order: # Don't modify the setting unless you know how it works
|
||||
card_archives:
|
||||
enable: true
|
||||
type: monthly # yearly or monthly
|
||||
format: MMMM YYYY # eg: YYYY年MM月
|
||||
order: -1 # Sort of order. 1, asc for ascending; -1, desc for descending
|
||||
limit: 8 # if set 0 will show all
|
||||
sort_order: # Don't modify the setting unless you know how it works
|
||||
card_webinfo:
|
||||
enable: true
|
||||
post_count: true
|
||||
last_push_date: true
|
||||
sort_order: # Don't modify the setting unless you know how it works
|
||||
|
||||
# busuanzi count for PV / UV in site
|
||||
# 訪問人數
|
||||
busuanzi:
|
||||
site_uv: true
|
||||
site_pv: true
|
||||
page_pv: true
|
||||
|
||||
# Time difference between publish date and now (網頁運行時間)
|
||||
# Formal: Month/Day/Year Time or Year/Month/Day Time
|
||||
runtimeshow:
|
||||
enable: false
|
||||
publish_date:
|
||||
|
||||
# Aside widget - Newest Comments
|
||||
newest_comments:
|
||||
enable: false
|
||||
sort_order: # Don't modify the setting unless you know how it works
|
||||
limit: 6
|
||||
storage: 10 # unit: mins, save data to localStorage
|
||||
avatar: true
|
||||
|
||||
# Bottom right button (右下角按鈕)
|
||||
# --------------------------------------
|
||||
|
||||
# Conversion between Traditional and Simplified Chinese (簡繁轉換)
|
||||
translate:
|
||||
enable: false
|
||||
# The text of a button
|
||||
default: 繁
|
||||
# the language of website (1 - Traditional Chinese/ 2 - Simplified Chinese)
|
||||
defaultEncoding: 2
|
||||
# Time delay
|
||||
translateDelay: 0
|
||||
# The text of the button when the language is Simplified Chinese
|
||||
msgToTraditionalChinese: '繁'
|
||||
# The text of the button when the language is Traditional Chinese
|
||||
msgToSimplifiedChinese: '簡'
|
||||
|
||||
# Read Mode (閲讀模式)
|
||||
readmode: true
|
||||
|
||||
# dark mode
|
||||
darkmode:
|
||||
enable: true
|
||||
# Toggle Button to switch dark/light mode
|
||||
button: true
|
||||
# Switch dark/light mode automatically (自動切換 dark mode和 light mode)
|
||||
# autoChangeMode: 1 Following System Settings, if the system doesn't support dark mode, it will switch dark mode between 6 pm to 6 am
|
||||
# autoChangeMode: 2 Switch dark mode between 6 pm to 6 am
|
||||
# autoChangeMode: false
|
||||
autoChangeMode: false
|
||||
# Set the light mode time. The value is between 0 and 24. If not set, the default value is 6 and 18
|
||||
start: # 8
|
||||
end: # 22
|
||||
|
||||
# show scroll percent in scroll-to-top button
|
||||
rightside_scroll_percent: false
|
||||
|
||||
# Don't modify the following settings unless you know how they work (非必要請不要修改 )
|
||||
# Choose: readmode,translate,darkmode,hideAside,toc,chat,comment
|
||||
# Don't repeat 不要重複
|
||||
rightside_item_order:
|
||||
enable: false
|
||||
hide: # readmode,translate,darkmode,hideAside
|
||||
show: # toc,chat,comment
|
||||
|
||||
# Math (數學)
|
||||
# --------------------------------------
|
||||
# About the per_page
|
||||
# if you set it to true, it will load mathjax/katex script in each page (true 表示每一頁都加載js)
|
||||
# if you set it to false, it will load mathjax/katex script according to your setting (add the 'mathjax: true' in page's front-matter)
|
||||
# (false 需要時加載,須在使用的 Markdown Front-matter 加上 mathjax: true)
|
||||
|
||||
# MathJax
|
||||
mathjax:
|
||||
enable: false
|
||||
per_page: false
|
||||
|
||||
# KaTeX
|
||||
katex:
|
||||
enable: false
|
||||
per_page: false
|
||||
hide_scrollbar: true
|
||||
|
||||
# search (搜索)
|
||||
# see https://butterfly.js.org/posts/ceeb73f/#搜索系統
|
||||
# --------------------------------------
|
||||
|
||||
# Algolia search
|
||||
algolia_search:
|
||||
enable: false
|
||||
hits:
|
||||
per_page: 6
|
||||
|
||||
# Local search
|
||||
local_search:
|
||||
enable: false
|
||||
# Preload the search data when the page loads.
|
||||
preload: false
|
||||
# Show top n results per article, show all results by setting to -1
|
||||
top_n_per_article: 1
|
||||
# Unescape html strings to the readable one.
|
||||
unescape: false
|
||||
CDN:
|
||||
|
||||
# Docsearch
|
||||
docsearch:
|
||||
enable: false
|
||||
appId:
|
||||
apiKey:
|
||||
indexName:
|
||||
option:
|
||||
|
||||
# Share System (分享)
|
||||
# --------------------------------------
|
||||
|
||||
# AddThis
|
||||
@@ -259,7 +404,7 @@ addtoany:
|
||||
|
||||
comments:
|
||||
# Up to two comments system, the first will be shown as default
|
||||
# Choose: Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42
|
||||
# Choose: Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42/Artalk
|
||||
use: # Valine,Disqus
|
||||
text: true # Display the comment name next to the button
|
||||
# lazyload: The comment system will be load when comment element enters the browser's viewport.
|
||||
@@ -333,7 +478,7 @@ facebook_comments:
|
||||
user_id: # optional
|
||||
pageSize: 10 # The number of comments to show
|
||||
order_by: social # social/time/reverse_time
|
||||
lang: en_US # Language en_US/zh_CN/zh_TW and so on
|
||||
lang: zh_TW # Language en_US/zh_CN/zh_TW and so on
|
||||
|
||||
# Twikoo
|
||||
# https://github.com/imaegoo/twikoo
|
||||
@@ -361,6 +506,14 @@ remark42:
|
||||
siteId: # Your Site ID
|
||||
option:
|
||||
|
||||
# Artalk
|
||||
# https://artalk.js.org/guide/frontend/config.html
|
||||
artalk:
|
||||
server:
|
||||
site:
|
||||
visitor: false
|
||||
option:
|
||||
|
||||
# Chat Services
|
||||
# --------------------------------------
|
||||
|
||||
@@ -384,31 +537,23 @@ tidio:
|
||||
public_key:
|
||||
|
||||
# daovoice
|
||||
# http://daovoice.io/
|
||||
# http://dashboard.daovoice.io/app
|
||||
daovoice:
|
||||
enable: false
|
||||
app_id:
|
||||
|
||||
# gitter
|
||||
# https://gitter.im/
|
||||
gitter:
|
||||
enable: false
|
||||
room:
|
||||
|
||||
# crisp
|
||||
# https://crisp.chat/en/
|
||||
crisp:
|
||||
enable: false
|
||||
website_id:
|
||||
|
||||
# Footer Settings
|
||||
# --------------------------------------
|
||||
footer:
|
||||
owner:
|
||||
enable: true
|
||||
since: 2020
|
||||
custom_text:
|
||||
copyright: true # Copyright of theme and framework
|
||||
# messenger
|
||||
# https://developers.facebook.com/docs/messenger-platform/discovery/facebook-chat-plugin/
|
||||
messenger:
|
||||
enable: false
|
||||
pageID:
|
||||
lang: zh_TW # Language en_US/zh_CN/zh_TW and so on
|
||||
|
||||
# Analysis
|
||||
# --------------------------------------
|
||||
@@ -421,10 +566,6 @@ baidu_analytics:
|
||||
# https://analytics.google.com/analytics/web/
|
||||
google_analytics:
|
||||
|
||||
# CNZZ Analytics
|
||||
# https://www.umeng.com/
|
||||
cnzz_analytics:
|
||||
|
||||
# Cloudflare Analytics
|
||||
# https://www.cloudflare.com/zh-tw/web-analytics/
|
||||
cloudflare_analytics:
|
||||
@@ -510,6 +651,14 @@ rightside-bottom:
|
||||
# Enter transitions (開啓網頁進入效果)
|
||||
enter_transitions: true
|
||||
|
||||
# Typewriter Effect (打字效果)
|
||||
# https://github.com/disjukr/activate-power-mode
|
||||
activate_power_mode:
|
||||
enable: false
|
||||
colorful: true # open particle animation (冒光特效)
|
||||
shake: true # open shake (抖動特效)
|
||||
mobile: false
|
||||
|
||||
# Background effects (背景特效)
|
||||
# --------------------------------------
|
||||
|
||||
@@ -538,14 +687,6 @@ canvas_nest:
|
||||
count: 99 # the number of lines, default: 99.
|
||||
mobile: false
|
||||
|
||||
# Typewriter Effect (打字效果)
|
||||
# https://github.com/disjukr/activate-power-mode
|
||||
activate_power_mode:
|
||||
enable: false
|
||||
colorful: true # open particle animation (冒光特效)
|
||||
shake: true # open shake (抖動特效)
|
||||
mobile: false
|
||||
|
||||
# Mouse click effects: fireworks (鼠標點擊效果: 煙火特效)
|
||||
fireworks:
|
||||
enable: false
|
||||
@@ -604,12 +745,13 @@ subtitle:
|
||||
enable: false
|
||||
# Typewriter Effect (打字效果)
|
||||
effect: true
|
||||
# loop (循環打字)
|
||||
loop: true
|
||||
# Customize typed.js (配置typed.js)
|
||||
# https://github.com/mattboldt/typed.js/#customization
|
||||
typed_option:
|
||||
# source 調用第三方服務
|
||||
# source: false 關閉調用
|
||||
# source: 1 調用一言網的一句話(簡體) https://hitokoto.cn/
|
||||
# source: 2 調用一句網(簡體) http://yijuzhan.com/
|
||||
# source: 2 調用一句網(簡體) https://yijuzhan.com/
|
||||
# source: 3 調用今日詩詞(簡體) https://www.jinrishici.com/
|
||||
# subtitle 會先顯示 source , 再顯示 sub 的內容
|
||||
source: false
|
||||
@@ -617,119 +759,22 @@ subtitle:
|
||||
sub:
|
||||
|
||||
# Loading Animation (加載動畫)
|
||||
preloader: false
|
||||
|
||||
# aside (側邊欄)
|
||||
# --------------------------------------
|
||||
|
||||
aside:
|
||||
enable: true
|
||||
hide: false
|
||||
button: true
|
||||
mobile: true # display on mobile
|
||||
position: right # left or right
|
||||
display:
|
||||
archive: true
|
||||
tag: true
|
||||
category: true
|
||||
card_author:
|
||||
enable: true
|
||||
description:
|
||||
button:
|
||||
enable: true
|
||||
icon: fab fa-github
|
||||
text: Follow Me
|
||||
link: https://github.com/xxxxxx
|
||||
card_announcement:
|
||||
enable: true
|
||||
content: This is my Blog
|
||||
card_recent_post:
|
||||
enable: true
|
||||
limit: 5 # if set 0 will show all
|
||||
sort: date # date or updated
|
||||
sort_order: # Don't modify the setting unless you know how it works
|
||||
card_categories:
|
||||
enable: true
|
||||
limit: 8 # if set 0 will show all
|
||||
expand: none # none/true/false
|
||||
sort_order: # Don't modify the setting unless you know how it works
|
||||
card_tags:
|
||||
enable: true
|
||||
limit: 40 # if set 0 will show all
|
||||
color: false
|
||||
sort_order: # Don't modify the setting unless you know how it works
|
||||
card_archives:
|
||||
enable: true
|
||||
type: monthly # yearly or monthly
|
||||
format: MMMM YYYY # eg: YYYY年MM月
|
||||
order: -1 # Sort of order. 1, asc for ascending; -1, desc for descending
|
||||
limit: 8 # if set 0 will show all
|
||||
sort_order: # Don't modify the setting unless you know how it works
|
||||
card_webinfo:
|
||||
enable: true
|
||||
post_count: true
|
||||
last_push_date: true
|
||||
sort_order: # Don't modify the setting unless you know how it works
|
||||
|
||||
# busuanzi count for PV / UV in site
|
||||
# 訪問人數
|
||||
busuanzi:
|
||||
site_uv: true
|
||||
site_pv: true
|
||||
page_pv: true
|
||||
|
||||
# Time difference between publish date and now (網頁運行時間)
|
||||
# Formal: Month/Day/Year Time or Year/Month/Day Time
|
||||
runtimeshow:
|
||||
preloader:
|
||||
enable: false
|
||||
publish_date:
|
||||
# source
|
||||
# 1. fullpage-loading
|
||||
# 2. pace (progress bar)
|
||||
source: 1
|
||||
# pace theme (see https://codebyzach.github.io/pace/)
|
||||
pace_css_url:
|
||||
|
||||
# Aside widget - Newest Comments
|
||||
newest_comments:
|
||||
# wordcount (字數統計)
|
||||
# see https://butterfly.js.org/posts/ceeb73f/#字數統計
|
||||
wordcount:
|
||||
enable: false
|
||||
sort_order: # Don't modify the setting unless you know how it works
|
||||
limit: 6
|
||||
storage: 10 # unit: mins, save data to localStorage
|
||||
avatar: true
|
||||
|
||||
# Bottom right button (右下角按鈕)
|
||||
# --------------------------------------
|
||||
|
||||
# Conversion between Traditional and Simplified Chinese (簡繁轉換)
|
||||
translate:
|
||||
enable: false
|
||||
# The text of a button
|
||||
default: 繁
|
||||
# the language of website (1 - Traditional Chinese/ 2 - Simplified Chinese)
|
||||
defaultEncoding: 2
|
||||
# Time delay
|
||||
translateDelay: 0
|
||||
# The text of the button when the language is Simplified Chinese
|
||||
msgToTraditionalChinese: '繁'
|
||||
# The text of the button when the language is Traditional Chinese
|
||||
msgToSimplifiedChinese: '簡'
|
||||
|
||||
# Read Mode (閲讀模式)
|
||||
readmode: true
|
||||
|
||||
# dark mode
|
||||
darkmode:
|
||||
enable: true
|
||||
# Toggle Button to switch dark/light mode
|
||||
button: true
|
||||
# Switch dark/light mode automatically (自動切換 dark mode和 light mode)
|
||||
# autoChangeMode: 1 Following System Settings, if the system doesn't support dark mode, it will switch dark mode between 6 pm to 6 am
|
||||
# autoChangeMode: 2 Switch dark mode between 6 pm to 6 am
|
||||
# autoChangeMode: false
|
||||
autoChangeMode: false
|
||||
|
||||
# Don't modify the following settings unless you know how they work (非必要請不要修改 )
|
||||
# Choose: readmode,translate,darkmode,hideAside,toc,chat,comment
|
||||
# Don't repeat 不要重複
|
||||
rightside_item_order:
|
||||
enable: false
|
||||
hide: # readmode,translate,darkmode,hideAside
|
||||
show: # toc,chat,comment
|
||||
post_wordcount: true
|
||||
min2read: true
|
||||
total_wordcount: true
|
||||
|
||||
# Lightbox (圖片大圖查看模式)
|
||||
# --------------------------------------
|
||||
@@ -740,12 +785,18 @@ rightside_item_order:
|
||||
medium_zoom: false
|
||||
|
||||
# fancybox
|
||||
# http://fancyapps.com/fancybox/3/
|
||||
# https://fancyapps.com/fancybox/
|
||||
fancybox: true
|
||||
|
||||
# Tag Plugins settings (標籤外掛)
|
||||
# --------------------------------------
|
||||
|
||||
# abcjs (樂譜渲染)
|
||||
# See https://github.com/paulrosen/abcjs
|
||||
abcjs:
|
||||
enable: false
|
||||
per_page: true
|
||||
|
||||
# mermaid
|
||||
# see https://github.com/mermaid-js/mermaid
|
||||
mermaid:
|
||||
@@ -827,7 +878,16 @@ lazyload:
|
||||
|
||||
# Open graph meta tags
|
||||
# https://developers.facebook.com/docs/sharing/webmasters/
|
||||
Open_Graph_meta: true
|
||||
Open_Graph_meta:
|
||||
enable: true
|
||||
option:
|
||||
# twitter_card:
|
||||
# twitter_image:
|
||||
# twitter_id:
|
||||
# twitter_site:
|
||||
# google_plus:
|
||||
# fb_admins:
|
||||
# fb_app_id:
|
||||
|
||||
# Add the vendor prefixes to ensure compatibility
|
||||
css_prefix: true
|
||||
@@ -855,7 +915,7 @@ CDN:
|
||||
# when set it to local, you need to install hexo-butterfly-extjs
|
||||
third_party_provider: jsdelivr
|
||||
|
||||
# Add version number to CDN, true or false
|
||||
# Add version number to url, true or false
|
||||
version: false
|
||||
|
||||
# Custom format
|
||||
@@ -869,8 +929,10 @@ CDN:
|
||||
# translate:
|
||||
# local_search:
|
||||
# algolia_js:
|
||||
# algolia_search_v4:
|
||||
# instantsearch_v4:
|
||||
# algolia_search:
|
||||
# instantsearch:
|
||||
# docsearch_js:
|
||||
# docsearch_css:
|
||||
# pjax:
|
||||
# gitalk:
|
||||
# gitalk_css:
|
||||
@@ -881,6 +943,7 @@ CDN:
|
||||
# twikoo:
|
||||
# waline_js:
|
||||
# waline_css:
|
||||
# giscus:
|
||||
# sharejs:
|
||||
# sharejs_css:
|
||||
# mathjax:
|
||||
@@ -894,8 +957,8 @@ CDN:
|
||||
# instantpage:
|
||||
# typed:
|
||||
# pangu:
|
||||
# fancybox_css_v4:
|
||||
# fancybox_v4:
|
||||
# fancybox_css:
|
||||
# fancybox:
|
||||
# medium_zoom:
|
||||
# snackbar_css:
|
||||
# snackbar:
|
||||
@@ -903,7 +966,7 @@ CDN:
|
||||
# fireworks:
|
||||
# click_heart:
|
||||
# ClickShowText:
|
||||
# fontawesomeV6:
|
||||
# fontawesome:
|
||||
# flickr_justified_gallery_js:
|
||||
# flickr_justified_gallery_css:
|
||||
# aplayer_css:
|
||||
@@ -911,4 +974,8 @@ CDN:
|
||||
# meting_js:
|
||||
# prismjs_js:
|
||||
# prismjs_lineNumber_js:
|
||||
# prismjs_autoloader:
|
||||
# prismjs_autoloader:
|
||||
# artalk_js:
|
||||
# artalk_css:
|
||||
# busuanzi:
|
||||
# abcjs_basic_js:
|
||||
|
||||
@@ -45,6 +45,7 @@ search:
|
||||
local_search:
|
||||
input_placeholder: Search for Posts
|
||||
hits_empty: "We didn't find any results for the search: ${query}"
|
||||
hits_stats: '${hits} results found'
|
||||
|
||||
pagination:
|
||||
prev: Previous Post
|
||||
@@ -117,5 +118,6 @@ Snackbar:
|
||||
night_to_day: Light Mode Activated Manually
|
||||
|
||||
loading: Loading...
|
||||
load_more: Load More
|
||||
|
||||
error404: Page not found
|
||||
|
||||
@@ -45,6 +45,7 @@ search:
|
||||
local_search:
|
||||
input_placeholder: Search for Posts
|
||||
hits_empty: "We didn't find any results for the search: ${query}"
|
||||
hits_stats: '${hits} results found'
|
||||
|
||||
pagination:
|
||||
prev: Previous Post
|
||||
@@ -117,5 +118,6 @@ Snackbar:
|
||||
night_to_day: Light Mode Activated Manually
|
||||
|
||||
loading: Loading...
|
||||
load_more: Load More
|
||||
|
||||
error404: Page not found
|
||||
|
||||
@@ -46,6 +46,7 @@ search:
|
||||
local_search:
|
||||
input_placeholder: 搜索文章
|
||||
hits_empty: '找不到您查询的内容:${query}'
|
||||
hits_stats: '共找到 ${hits} 篇文章'
|
||||
|
||||
pagination:
|
||||
prev: 上一篇
|
||||
@@ -118,5 +119,6 @@ Snackbar:
|
||||
night_to_day: 你已切换为浅色模式
|
||||
|
||||
loading: 加载中...
|
||||
load_more: 加载更多
|
||||
|
||||
error404: 页面没有找到
|
||||
|
||||
@@ -46,7 +46,8 @@ search:
|
||||
local_search:
|
||||
input_placeholder: 搜尋文章
|
||||
hits_empty: '找不到您查詢的內容:${query}'
|
||||
|
||||
hits_stats: '共找到 ${hits} 篇文章'
|
||||
|
||||
pagination:
|
||||
prev: 上一篇
|
||||
next: 下一篇
|
||||
@@ -118,5 +119,6 @@ Snackbar:
|
||||
night_to_day: 你已切換為淺色模式
|
||||
|
||||
loading: 載入中...
|
||||
load_more: 載入更多
|
||||
|
||||
error404: 頁面沒有找到
|
||||
|
||||
@@ -8,7 +8,7 @@ div
|
||||
if theme.medium_zoom
|
||||
script(src=url_for(theme.asset.medium_zoom))
|
||||
else if theme.fancybox
|
||||
script(src=url_for(theme.asset.fancybox_v4))
|
||||
script(src=url_for(theme.asset.fancybox))
|
||||
|
||||
if theme.instantpage
|
||||
script(src=url_for(theme.asset.instantpage), type='module')
|
||||
@@ -22,17 +22,6 @@ div
|
||||
if theme.pangu.enable
|
||||
!= partial("includes/third-party/pangu.pug", {}, { cache: true })
|
||||
|
||||
//- search
|
||||
if theme.algolia_search.enable
|
||||
script(src=url_for(theme.asset.algolia_search_v4))
|
||||
script(src=url_for(theme.asset.instantsearch_v4))
|
||||
script(src=url_for(theme.asset.algolia_js))
|
||||
else if theme.local_search.enable
|
||||
script(src=url_for(theme.asset.local_search))
|
||||
|
||||
if theme.preloader
|
||||
!= partial("includes/loading/loading-js", {}, { cache: true })
|
||||
|
||||
.js-pjax
|
||||
if needLoadCountJs
|
||||
!= partial("includes/third-party/card-post-count/index", {}, { cache: true })
|
||||
@@ -42,6 +31,8 @@ div
|
||||
|
||||
include ./third-party/math/index.pug
|
||||
|
||||
include ./third-party/abcjs/index.pug
|
||||
|
||||
if commentsJsLoad
|
||||
include ./third-party/comments/js.pug
|
||||
|
||||
@@ -69,4 +60,6 @@ div
|
||||
!= partial("includes/third-party/pjax", {}, { cache: true })
|
||||
|
||||
if theme.busuanzi.site_uv || theme.busuanzi.site_pv || theme.busuanzi.page_pv
|
||||
script(async data-pjax src='//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js')
|
||||
script(async data-pjax src= theme.asset.busuanzi || '//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js')
|
||||
|
||||
!=partial('includes/third-party/search/index', {}, {cache: true})
|
||||
@@ -7,11 +7,6 @@
|
||||
|
||||
- var isSubtitle = config.subtitle ? ' - ' + config.subtitle : ''
|
||||
- var tabTitle = is_home() || !pageTitle ? config.title + isSubtitle : pageTitle + ' | ' + config.title
|
||||
|
||||
- var pageKeywords
|
||||
- if (page.keywords) pageKeywords = Array.isArray(page.keywords) ? (page.keywords).join(',') : ([]).join(',') || page.keywords
|
||||
- else if (page.tags && page.tags.length) pageKeywords = page.tags.data.map(function(tag) {return tag.name;}).join(',')
|
||||
- else pageKeywords = Array.isArray(config.keywords) ? (config.keywords).join(','): ([]).join(',') || config.keywords
|
||||
- var pageAuthor = config.email ? config.author + ',' + config.email : config.author
|
||||
- var pageCopyright = config.copyright || config.author
|
||||
- var themeColorLight = theme.theme_color && theme.theme_color.enable && theme.theme_color.meta_theme_color_light || '#ffffff'
|
||||
@@ -20,10 +15,8 @@
|
||||
|
||||
meta(charset='UTF-8')
|
||||
meta(http-equiv="X-UA-Compatible" content="IE=edge")
|
||||
meta(name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no")
|
||||
meta(name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover")
|
||||
title= tabTitle
|
||||
if pageKeywords
|
||||
meta(name="keywords" content=pageKeywords)
|
||||
meta(name="author" content=pageAuthor)
|
||||
meta(name="copyright" content=pageCopyright)
|
||||
meta(name ="format-detection" content="telephone=no")
|
||||
@@ -33,7 +26,7 @@ meta(name="theme-color" content=themeColor)
|
||||
include ./head/Open_Graph.pug
|
||||
|
||||
!=favicon_tag(theme.favicon || config.favicon)
|
||||
link(rel="canonical" href=urlNoIndex())
|
||||
link(rel="canonical" href=urlNoIndex(null,config.pretty_urls.trailing_index,config.pretty_urls.trailing_html))
|
||||
|
||||
//- 預解析
|
||||
!=partial('includes/head/preconnect', {}, {cache: true})
|
||||
@@ -47,13 +40,13 @@ if (theme.pwa && theme.pwa.enable)
|
||||
|
||||
//- main css
|
||||
link(rel='stylesheet', href=url_for(theme.asset.main_css))
|
||||
link(rel='stylesheet', href=url_for(theme.asset.fontawesomeV6) media="print" onload="this.media='all'")
|
||||
link(rel='stylesheet', href=url_for(theme.asset.fontawesome) media="print" onload="this.media='all'")
|
||||
|
||||
if (theme.snackbar && theme.snackbar.enable)
|
||||
link(rel='stylesheet', href=url_for(theme.asset.snackbar_css) media="print" onload="this.media='all'")
|
||||
|
||||
if theme.fancybox
|
||||
link(rel='stylesheet' href=url_for(theme.asset.fancybox_css_v4) media="print" onload="this.media='all'")
|
||||
link(rel='stylesheet' href=url_for(theme.asset.fancybox_css) media="print" onload="this.media='all'")
|
||||
|
||||
//- google_adsense
|
||||
!=partial('includes/head/google_adsense', {}, {cache: true})
|
||||
@@ -73,4 +66,4 @@ include ./head/noscript.pug
|
||||
|
||||
!=fragment_cache('injectHeadJs', function(){return inject_head_js()})
|
||||
|
||||
!=fragment_cache('injectHead', function(){return injectHtml(theme.inject.head)})
|
||||
!=fragment_cache('injectHead', function(){return injectHtml(theme.inject.head)})
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
if theme.Open_Graph_meta
|
||||
- let contentType = is_post() ? 'article' : 'website'
|
||||
- let metaImage = (page.cover || theme.avatar.img) ? full_url_for(page.cover || theme.avatar.img) : ''
|
||||
- let fb_appId = theme.facebook_comments.app_id || ''
|
||||
- let fb_admins = theme.facebook_comments.user_id || ''
|
||||
|
||||
!= open_graph({type: contentType, image: metaImage, fb_admins: fb_admins, fb_app_id: fb_appId})
|
||||
|
||||
if theme.Open_Graph_meta.enable
|
||||
-
|
||||
const coverVal = page.cover_type === 'img' ? page.cover : theme.avatar.img
|
||||
let ogOption = Object.assign({
|
||||
type: is_post() ? 'article' : 'website',
|
||||
image: coverVal ? full_url_for(coverVal) : '',
|
||||
fb_admins: theme.facebook_comments.user_id || '',
|
||||
fb_app_id: theme.facebook_comments.app_id || '',
|
||||
}, theme.Open_Graph_meta.option)
|
||||
-
|
||||
!= open_graph(ogOption)
|
||||
else
|
||||
meta(name="description" content=page_description())
|
||||
|
||||
|
||||
@@ -16,9 +16,6 @@ if theme.google_analytics
|
||||
gtag('js', new Date());
|
||||
gtag('config', '!{theme.google_analytics}');
|
||||
|
||||
if theme.cnzz_analytics
|
||||
script(async data-pjax src=`https://s4.cnzz.com/z_stat.php?id=${theme.cnzz_analytics}&web_id=${theme.cnzz_analytics}`)
|
||||
|
||||
if theme.cloudflare_analytics
|
||||
script(defer data-pjax src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon=`{"token": "${theme.cloudflare_analytics}"}`)
|
||||
|
||||
|
||||
@@ -21,9 +21,12 @@
|
||||
localSearch = JSON.stringify({
|
||||
path: theme.local_search.CDN ? theme.local_search.CDN : config.root + config.search.path,
|
||||
preload: theme.local_search.preload,
|
||||
top_n_per_article: theme.local_search.top_n_per_article,
|
||||
unescape: theme.local_search.unescape,
|
||||
languages: {
|
||||
// search languages
|
||||
hits_empty: _p("search.local_search.hits_empty"),
|
||||
hits_stats: _p("search.local_search.hits_stats"),
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -102,7 +105,7 @@ script.
|
||||
post: !{theme.post_meta.post.date_format === 'relative'}
|
||||
},
|
||||
runtime: '!{theme.runtimeshow.enable ? _p("aside.card_webinfo.runtime.unit") : ""}',
|
||||
date_suffix: {
|
||||
dateSuffix: {
|
||||
just: '!{_p("date_suffix.just")}',
|
||||
min: '!{_p("date_suffix.min")}',
|
||||
hour: '!{_p("date_suffix.hour")}',
|
||||
@@ -120,5 +123,9 @@ script.
|
||||
},
|
||||
isPhotoFigcaption: !{theme.photofigcaption},
|
||||
islazyload: !{theme.lazyload.enable},
|
||||
isAnchor: !{theme.anchor}
|
||||
isAnchor: !{theme.anchor.auto_update || false},
|
||||
percent: {
|
||||
toc: !{theme.toc.scroll_percent},
|
||||
rightside: !{theme.rightside_scroll_percent},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,6 @@ if theme.google_analytics
|
||||
if theme.baidu_analytics
|
||||
link(rel="preconnect" href="//hm.baidu.com")
|
||||
|
||||
if theme.cnzz_analytics
|
||||
link(rel="preconnect" href="//s4.cnzz.com")
|
||||
|
||||
if theme.cloudflare_analytics
|
||||
link(rel="preconnect" href="//static.cloudflareinsights.com")
|
||||
|
||||
@@ -18,5 +15,5 @@ if theme.microsoft_clarity
|
||||
if theme.blog_title_font && theme.blog_title_font.font_link && theme.blog_title_font.font_link.indexOf('//fonts.googleapis.com') != -1
|
||||
link(rel="preconnect" href="//fonts.googleapis.com" crossorigin='')
|
||||
|
||||
if theme.busuanzi.site_uv || theme.busuanzi.site_pv || theme.busuanzi.page_pv
|
||||
if !theme.asset.busuanzi && (theme.busuanzi.site_uv || theme.busuanzi.site_pv || theme.busuanzi.page_pv)
|
||||
link(rel="preconnect" href="//busuanzi.ibruce.info")
|
||||
@@ -1,6 +1,6 @@
|
||||
if !theme.disable_top_img && page.top_img !== false
|
||||
if is_post()
|
||||
- var top_img = page.top_img || page.cover || page.randomcover
|
||||
- var top_img = page.top_img || page.cover || theme.default_top_img
|
||||
else if is_page()
|
||||
- var top_img = page.top_img || theme.default_top_img
|
||||
else if is_tag()
|
||||
@@ -17,7 +17,7 @@ if !theme.disable_top_img && page.top_img !== false
|
||||
- var top_img = page.top_img || theme.default_top_img
|
||||
|
||||
if top_img !== false
|
||||
- var imgSource = top_img && top_img.indexOf('/') !== -1 ? `background-image: url('${url_for(top_img)}')` : `background: ${top_img}`
|
||||
- var imgSource = top_img && isImgOrUrl(top_img) ? `background-image: url('${url_for(top_img)}')` : `background: ${top_img}`
|
||||
- var bg_img = top_img ? imgSource : ''
|
||||
- var site_title = page.title || page.tag || page.category || config.title
|
||||
- var isHomeClass = is_home() ? 'full_page' : 'not-home-page'
|
||||
@@ -28,7 +28,9 @@ else
|
||||
- var top_img = false
|
||||
- var isHomeClass = 'not-top-img'
|
||||
|
||||
header#page-header(class=isHomeClass style=bg_img)
|
||||
- const isFixedClass = theme.nav.fixed ? ' fixed' : ''
|
||||
|
||||
header#page-header(class=`${isHomeClass+isFixedClass}` style=bg_img)
|
||||
!=partial('includes/header/nav', {}, {cache: true})
|
||||
if top_img !== false
|
||||
if is_post()
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
nav#nav
|
||||
span#blog_name
|
||||
a#site-name(href=url_for('/')) #[=config.title]
|
||||
span#blog-info
|
||||
a(href=url_for('/') title=config.title)
|
||||
if theme.nav.logo
|
||||
img.site-icon(src=url_for(theme.nav.logo))
|
||||
if theme.nav.display_title
|
||||
span.site-name=config.title
|
||||
|
||||
#menus
|
||||
if (theme.algolia_search.enable || theme.local_search.enable)
|
||||
if (theme.algolia_search.enable || theme.local_search.enable || theme.docsearch.enable)
|
||||
#search-button
|
||||
a.site-page.social-icon.search
|
||||
a.site-page.social-icon.search(href="javascript:void(0);")
|
||||
i.fas.fa-search.fa-fw
|
||||
span=' '+_p('search.title')
|
||||
!=partial('includes/header/menu_item', {}, {cache: true})
|
||||
|
||||
#toggle-menu
|
||||
a.site-page
|
||||
a.site-page(href="javascript:void(0);")
|
||||
i.fas.fa-bars.fa-fw
|
||||
|
||||
|
||||
|
||||
@@ -75,6 +75,10 @@
|
||||
+pvBlock('','','')
|
||||
span#twikoo_visitors
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
else if commentUse[0] === 'Artalk' && theme.artalk.visitor
|
||||
+pvBlock('','','')
|
||||
span#ArtalkPV
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
else if theme.busuanzi.page_pv
|
||||
+pvBlock('','post-meta-pv-cv','')
|
||||
span#busuanzi_value_page_pv
|
||||
@@ -130,9 +134,13 @@
|
||||
+countBlock
|
||||
a(href=url_for(page.path) + '#post-comment')
|
||||
span.fb-comments-count(data-href=urlNoIndex())
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
when 'Remark42'
|
||||
+countBlock
|
||||
a(href=url_for(page.path) + '#post-comment')
|
||||
span.remark42__counter(data-url=urlNoIndex())
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
when 'Artalk'
|
||||
+countBlock
|
||||
a(href=url_for(page.path) + '#post-comment')
|
||||
span.artalk-count
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
@@ -1,4 +1,4 @@
|
||||
each url, icon in theme.social
|
||||
a.social-icon(href=url_for(trim(url.split('||')[0])) target="_blank"
|
||||
title=url.split('||')[1] === undefined ? '' : trim(url.split('||')[1]))
|
||||
i(class=icon)
|
||||
i(class=icon style=url.split('||')[2] === undefined ? '' : `color: ${trim(url.split('||')[2]).replace(/[\'\"]/g, '')};`)
|
||||
@@ -8,8 +8,8 @@ html(lang=config.language data-theme=theme.display_mode class=htmlClassHideAside
|
||||
head
|
||||
include ./head.pug
|
||||
body
|
||||
if theme.preloader
|
||||
!=partial('includes/loading/loading', {}, {cache: true})
|
||||
if theme.preloader.enable
|
||||
!=partial('includes/loading/index', {}, {cache: true})
|
||||
|
||||
if theme.background
|
||||
#web_bg
|
||||
@@ -33,7 +33,7 @@ html(lang=config.language data-theme=theme.display_mode class=htmlClassHideAside
|
||||
if (footerBg === true)
|
||||
- var footer_bg = bg_img
|
||||
else
|
||||
- var footer_bg = theme.footer_bg.indexOf('/') !== -1 ? `background-image: url('${url_for(footerBg)}')` : `background: ${footerBg}`
|
||||
- var footer_bg = isImgOrUrl(theme.footer_bg) ? `background-image: url('${url_for(footerBg)}')` : `background: ${footerBg}`
|
||||
else
|
||||
- var footer_bg = ''
|
||||
|
||||
@@ -44,5 +44,4 @@ html(lang=config.language data-theme=theme.display_mode class=htmlClassHideAside
|
||||
include ./404.pug
|
||||
|
||||
include ./rightside.pug
|
||||
!=partial('includes/third-party/search/index', {}, {cache: true})
|
||||
include ./additional-js.pug
|
||||
29
layout/includes/loading/fullpage-loading.pug
Normal file
29
layout/includes/loading/fullpage-loading.pug
Normal file
@@ -0,0 +1,29 @@
|
||||
#loading-box
|
||||
.loading-left-bg
|
||||
.loading-right-bg
|
||||
.spinner-box
|
||||
.configure-border-1
|
||||
.configure-core
|
||||
.configure-border-2
|
||||
.configure-core
|
||||
.loading-word= _p('loading')
|
||||
|
||||
script.
|
||||
const preloader = {
|
||||
endLoading: () => {
|
||||
document.body.style.overflow = '';
|
||||
document.getElementById('loading-box').classList.add("loaded")
|
||||
},
|
||||
initLoading: () => {
|
||||
document.body.style.overflow = 'hidden';
|
||||
document.getElementById('loading-box').classList.remove("loaded")
|
||||
}
|
||||
}
|
||||
|
||||
preloader.initLoading()
|
||||
window.addEventListener('load',()=> { preloader.endLoading() })
|
||||
|
||||
if (!{theme.pjax && theme.pjax.enable}) {
|
||||
document.addEventListener('pjax:send', () => { preloader.initLoading() })
|
||||
document.addEventListener('pjax:complete', () => { preloader.endLoading() })
|
||||
}
|
||||
4
layout/includes/loading/index.pug
Normal file
4
layout/includes/loading/index.pug
Normal file
@@ -0,0 +1,4 @@
|
||||
if theme.preloader.source === 1
|
||||
include ./fullpage-loading.pug
|
||||
else
|
||||
include ./pace.pug
|
||||
@@ -1,13 +0,0 @@
|
||||
script.
|
||||
var preloader = {
|
||||
endLoading: () => {
|
||||
document.body.style.overflow = 'auto';
|
||||
document.getElementById('loading-box').classList.add("loaded")
|
||||
},
|
||||
initLoading: () => {
|
||||
document.body.style.overflow = '';
|
||||
document.getElementById('loading-box').classList.remove("loaded")
|
||||
|
||||
}
|
||||
}
|
||||
window.addEventListener('load',preloader.endLoading())
|
||||
@@ -1,9 +0,0 @@
|
||||
#loading-box
|
||||
.loading-left-bg
|
||||
.loading-right-bg
|
||||
.spinner-box
|
||||
.configure-border-1
|
||||
.configure-core
|
||||
.configure-border-2
|
||||
.configure-core
|
||||
.loading-word= _p('loading')
|
||||
11
layout/includes/loading/pace.pug
Normal file
11
layout/includes/loading/pace.pug
Normal file
@@ -0,0 +1,11 @@
|
||||
script.
|
||||
window.paceOptions = {
|
||||
restartOnPushState: false
|
||||
}
|
||||
|
||||
document.addEventListener('pjax:send', () => {
|
||||
Pace.restart()
|
||||
})
|
||||
|
||||
link(rel="stylesheet", href=url_for(theme.preloader.pace_css_url || theme.asset.pace_default_css))
|
||||
script(src=url_for(theme.asset.pace_js))
|
||||
@@ -11,7 +11,10 @@ mixin articleSort(posts)
|
||||
.article-sort-item(class=no_cover)
|
||||
if article.cover && theme.cover.archives_enable
|
||||
a.article-sort-item-img(href=url_for(article.path) title=title)
|
||||
img(src=url_for(article.cover) alt=title onerror=`this.onerror=null;this.src='${url_for(theme.error_img.post_page)}'`)
|
||||
if article.cover_type === 'img'
|
||||
img(src=url_for(article.cover) alt=title onerror=`this.onerror=null;this.src='${url_for(theme.error_img.post_page)}'`)
|
||||
else
|
||||
div(style=`background: ${article.cover}`)
|
||||
.article-sort-item-info
|
||||
.article-sort-item-time
|
||||
i.far.fa-calendar-alt
|
||||
|
||||
@@ -14,7 +14,10 @@ mixin postUI(posts)
|
||||
if post_cover && theme.cover.index_enable
|
||||
.post_cover(class=leftOrRight)
|
||||
a(href=url_for(link) title=title)
|
||||
img.post_bg(src=url_for(post_cover) onerror=`this.onerror=null;this.src='`+ url_for(theme.error_img.post_page) + `'` alt=title)
|
||||
if article.cover_type === 'img'
|
||||
img.post-bg(src=url_for(post_cover) onerror=`this.onerror=null;this.src='${url_for(theme.error_img.post_page)}'` alt=title)
|
||||
else
|
||||
div.post-bg(style=`background: ${post_cover}`)
|
||||
.recent-post-info(class=no_cover)
|
||||
a.article-title(href=url_for(link) title=title)= title
|
||||
.article-meta-wrap
|
||||
@@ -96,12 +99,16 @@ mixin postUI(posts)
|
||||
+countBlockInIndex
|
||||
a(href=url_for(link) + '#post-comment')
|
||||
span.fb-comments-count(data-href=urlNoIndex(article.permalink))
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
when 'Remark42'
|
||||
+countBlockInIndex
|
||||
a(href=url_for(link) + '#post-comment')
|
||||
span.remark42__counter(data-url=urlNoIndex(article.permalink))
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
when 'Artalk'
|
||||
+countBlockInIndex
|
||||
a(href=url_for(link) + '#post-comment')
|
||||
span.artalk-count(data-page-key=url_for(link))
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
|
||||
//- Display the article introduction on homepage
|
||||
case theme.index_post_content.method
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#article-container
|
||||
.flink
|
||||
- let pageContent = page.content
|
||||
if page.flink_url
|
||||
script.
|
||||
(()=>{
|
||||
@@ -35,6 +36,7 @@
|
||||
}
|
||||
|
||||
document.querySelector(".flink").insertAdjacentHTML("afterbegin", result)
|
||||
window.lazyLoadInstance && window.lazyLoadInstance.update()
|
||||
})
|
||||
})()
|
||||
|
||||
@@ -63,6 +65,6 @@
|
||||
|
||||
- result += `${className}${classDesc} <div class="flink-list">${listResult}</div>`
|
||||
|
||||
- page.content = result + page.content
|
||||
!= page.content
|
||||
- pageContent = result + pageContent
|
||||
!= pageContent
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
.tag-cloud-list.is-center
|
||||
!=cloudTags({source: site.tags, minfontsize: 1.2, maxfontsize: 2.1, limit: 0, unit: 'em'})
|
||||
!=cloudTags({source: site.tags, orderby: page.orderby || 'random', order: page.order || 1, minfontsize: 1.2, maxfontsize: 2.1, limit: 0, unit: 'em'})
|
||||
@@ -13,19 +13,23 @@ if is_post()
|
||||
if(prev)
|
||||
- var hasPageNext = next ? 'pull-left' : 'pull-full'
|
||||
.prev-post(class=hasPageNext)
|
||||
- var pagination_cover = prev.cover === false ? prev.randomcover : prev.cover
|
||||
a(href=url_for(prev.path))
|
||||
img.prev-cover(src=url_for(pagination_cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of previous post')
|
||||
a(href=url_for(prev.path) title=prev.title)
|
||||
if prev.cover_type === 'img'
|
||||
img.cover(src=url_for(prev.cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of previous post')
|
||||
else
|
||||
.cover(style=`background: ${prev.cover || 'var(--default-bg-color)'}`)
|
||||
.pagination-info
|
||||
.label=_p('pagination.prev')
|
||||
.prev_info=prev.title
|
||||
|
||||
if(next)
|
||||
- var hasPagePrev = prev ? 'pull-right' : 'pull-full'
|
||||
- var pagination_cover = next.cover == false ? next.randomcover : next.cover
|
||||
.next-post(class=hasPagePrev)
|
||||
a(href=url_for(next.path))
|
||||
img.next-cover(src=url_for(pagination_cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of next post')
|
||||
a(href=url_for(next.path) title=next.title)
|
||||
if next.cover_type === 'img'
|
||||
img.cover(src=url_for(next.cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of next post')
|
||||
else
|
||||
.cover(style=`background: ${next.cover || 'var(--default-bg-color)'}`)
|
||||
.pagination-info
|
||||
.label=_p('pagination.next')
|
||||
.next_info=next.title
|
||||
|
||||
@@ -57,4 +57,5 @@ mixin rightsideItem(array)
|
||||
+rightsideItem(showArray)
|
||||
|
||||
button#go-up(type="button" title=_p("rightside.back_to_top"))
|
||||
span.scroll-percent
|
||||
i.fas.fa-arrow-up
|
||||
15
layout/includes/third-party/abcjs/abcjs.pug
vendored
Normal file
15
layout/includes/third-party/abcjs/abcjs.pug
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
script.
|
||||
(() => {
|
||||
function abcjsInit() {
|
||||
function abcjsFn() {
|
||||
for (let abcContainer of document.getElementsByClassName("abc-music-sheet")) {
|
||||
ABCJS.renderAbc(abcContainer, abcContainer.innerHTML, {responsive: 'resize'})
|
||||
}
|
||||
}
|
||||
|
||||
typeof ABCJS === 'object' ? abcjsFn()
|
||||
: getScript('!{url_for(theme.asset.abcjs_basic_js)}').then(abcjsFn)
|
||||
}
|
||||
|
||||
window.pjax ? abcjsInit() : document.addEventListener('DOMContentLoaded', abcjsInit)
|
||||
})()
|
||||
6
layout/includes/third-party/abcjs/index.pug
vendored
Normal file
6
layout/includes/third-party/abcjs/index.pug
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
if theme.abcjs.enable
|
||||
if theme.abcjs.per_page
|
||||
if is_post() || is_page()
|
||||
include ./abcjs.pug
|
||||
else if page.abcjs
|
||||
include ./abcjs.pug
|
||||
20
layout/includes/third-party/card-post-count/artalk.pug
vendored
Normal file
20
layout/includes/third-party/card-post-count/artalk.pug
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
- const { server, site } = theme.artalk
|
||||
|
||||
script.
|
||||
(() => {
|
||||
const getArtalkCount = () => {
|
||||
const runWidget = () => {
|
||||
Artalk.LoadCountWidget({
|
||||
server: '!{server}',
|
||||
site: '!{site}',
|
||||
countEl: '.artalk-count'
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof Artalk === 'function') runWidget()
|
||||
else getScript('!{theme.asset.artalk_js}').then(runWidget)
|
||||
}
|
||||
|
||||
|
||||
window.pjax ? getArtalkCount() : window.addEventListener('load', getArtalkCount)
|
||||
})()
|
||||
@@ -1,10 +1,13 @@
|
||||
- const fbSDKVer = 'v16.0'
|
||||
- const fbSDK = theme.messenger.enable ? `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk/xfbml.customerchat.js#xfbml=1&version=${fbSDKVer}` : `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk.js#xfbml=1&version=${fbSDKVer}`
|
||||
|
||||
script.
|
||||
(()=>{
|
||||
function loadFBComment () {
|
||||
if (typeof FB === 'object') FB.XFBML.parse()
|
||||
if (typeof FB === 'object') FB.XFBML.parse(document.getElementById('recent-posts'))
|
||||
else {
|
||||
let ele = document.createElement('script')
|
||||
ele.setAttribute('src','https://connect.facebook.net/!{theme.facebook_comments.lang}/sdk.js#xfbml=1&version=v9.0')
|
||||
ele.setAttribute('src','!{fbSDK}')
|
||||
ele.setAttribute('async', 'true')
|
||||
ele.setAttribute('defer', 'true')
|
||||
ele.setAttribute('crossorigin', 'anonymous')
|
||||
|
||||
@@ -11,4 +11,6 @@ case theme.comments.use[0]
|
||||
when 'Facebook Comments'
|
||||
include ./fb.pug
|
||||
when 'Remark42'
|
||||
include ./remark42.pug
|
||||
include ./remark42.pug
|
||||
when 'Artalk'
|
||||
include ./artalk.pug
|
||||
@@ -10,7 +10,7 @@ script.
|
||||
const waline = Waline.init(initData)
|
||||
}
|
||||
|
||||
if (typeof Waline === 'function') initWaline()
|
||||
if (typeof Waline === 'object') initWaline()
|
||||
else getScript('!{url_for(theme.asset.waline_js)}').then(initWaline)
|
||||
}
|
||||
|
||||
|
||||
43
layout/includes/third-party/chat/gitter.pug
vendored
43
layout/includes/third-party/chat/gitter.pug
vendored
@@ -1,43 +0,0 @@
|
||||
if theme.chat_btn
|
||||
script.
|
||||
((window.gitter = {}).chat = {}).options = {
|
||||
disableDefaultChat: true,
|
||||
};
|
||||
document.addEventListener('gitter-sidecar-ready', (e) => {
|
||||
const GitterChat = e.detail.Chat
|
||||
let chat
|
||||
|
||||
function initGitter () {
|
||||
chat = new GitterChat({
|
||||
room: '#{theme.gitter.room}',
|
||||
activationElement: '#chat_btn'
|
||||
});
|
||||
}
|
||||
|
||||
initGitter()
|
||||
|
||||
if (!{theme.pjax.enable}) {
|
||||
document.addEventListener('pjax:complete', () => {
|
||||
chat.destroy()
|
||||
initGitter()
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
else
|
||||
script.
|
||||
((window.gitter = {}).chat = {}).options = {
|
||||
room: '#{theme.gitter.room}',
|
||||
};
|
||||
|
||||
if (!{theme.chat_hide_show}) {
|
||||
function chatBtnHide () {
|
||||
document.getElementsByClassName('gitter-open-chat-button')[0].style.display= 'none'
|
||||
}
|
||||
|
||||
function chatBtnShow () {
|
||||
document.getElementsByClassName('gitter-open-chat-button')[0].style.display= 'block'
|
||||
}
|
||||
}
|
||||
|
||||
script(src="https://sidecar.gitter.im/dist/sidecar.v1.js" async defer)
|
||||
6
layout/includes/third-party/chat/index.pug
vendored
6
layout/includes/third-party/chat/index.pug
vendored
@@ -4,7 +4,7 @@ else if theme.tidio && theme.tidio.enable
|
||||
include ./tidio.pug
|
||||
else if theme.daovoice && theme.daovoice.enable
|
||||
include ./daovoice.pug
|
||||
else if theme.gitter && theme.gitter.enable
|
||||
include ./gitter.pug
|
||||
else if theme.crisp && theme.crisp.enable
|
||||
include ./crisp.pug
|
||||
include ./crisp.pug
|
||||
else if theme.messenger && theme.messenger.enable
|
||||
include ./messenger.pug
|
||||
42
layout/includes/third-party/chat/messenger.pug
vendored
Normal file
42
layout/includes/third-party/chat/messenger.pug
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
- let { pageID, lang } = theme.messenger
|
||||
- lang = theme.comments.use && theme.comments.use.includes('Facebook Comments') ? theme.facebook_comments.lang : lang
|
||||
|
||||
#fb-customer-chat.fb-customerchat(page_id=pageID attribution='biz_inbox')
|
||||
|
||||
script.
|
||||
document.getElementById('fb-root') ? '' : document.body.insertAdjacentHTML('afterend', '<div id="fb-root"></div>')
|
||||
|
||||
window.fbAsyncInit = function() {
|
||||
FB.init({
|
||||
xfbml: true,
|
||||
version: 'v16.0'
|
||||
});
|
||||
};
|
||||
|
||||
(function(d, s, id) {
|
||||
var js, fjs = d.getElementsByTagName(s)[0];
|
||||
if (d.getElementById(id)) return;
|
||||
js = d.createElement(s); js.id = id;
|
||||
js.src = 'https://connect.facebook.net/!{lang}/sdk/xfbml.customerchat.js';
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
}(document, 'script', 'facebook-jssdk'));
|
||||
|
||||
if (!{theme.chat_btn}) {
|
||||
var chatBtnFn = () => {
|
||||
var chatBtn = document.getElementById("chat_btn")
|
||||
chatBtn.addEventListener("click", function(){
|
||||
FB.CustomerChat.show();
|
||||
});
|
||||
}
|
||||
chatBtnFn()
|
||||
} else {
|
||||
if (!{theme.chat_hide_show}) {
|
||||
function chatBtnHide () {
|
||||
FB.CustomerChat.hide()
|
||||
}
|
||||
function chatBtnShow () {
|
||||
FB.CustomerChat.show(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
layout/includes/third-party/comments/artalk.pug
vendored
Normal file
38
layout/includes/third-party/comments/artalk.pug
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
- const { server, site, option } = theme.artalk
|
||||
|
||||
script.
|
||||
function loadArtalk () {
|
||||
function initArtalk () {
|
||||
window.artalkItem = new Artalk(Object.assign({
|
||||
el: '#artalk-wrap',
|
||||
server: '!{server}',
|
||||
site: '!{site}',
|
||||
pageKey: location.pathname,
|
||||
darkMode: document.documentElement.getAttribute('data-theme') === 'dark',
|
||||
countEl: '.artalk-count'
|
||||
},!{JSON.stringify(option)}))
|
||||
}
|
||||
|
||||
if (typeof window.artalkItem === 'object') setTimeout(()=>{initArtalk()},200)
|
||||
else {
|
||||
getCSS('!{theme.asset.artalk_css}')
|
||||
typeof Artalk !== 'function' ? getScript('!{theme.asset.artalk_js}').then(initArtalk)
|
||||
: setTimeout(()=>{initArtalk()},200)
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('darkmode').addEventListener('click',()=> {
|
||||
if (typeof window.artalkItem !== 'object') return
|
||||
let isDark = document.documentElement.getAttribute('data-theme') === 'dark'
|
||||
window.artalkItem.setDarkMode(!isDark)
|
||||
})
|
||||
|
||||
|
||||
if ('!{theme.comments.use[0]}' === 'Artalk' || !!{theme.comments.lazyload}) {
|
||||
if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('artalk-wrap'), loadArtalk)
|
||||
else loadArtalk()
|
||||
} else {
|
||||
function loadOtherComment () {
|
||||
loadArtalk()
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,6 @@
|
||||
|
||||
script.
|
||||
function loadDisqusjs () {
|
||||
function addDisqusjsCSS () {
|
||||
const ele = document.createElement('link')
|
||||
ele.rel = 'stylesheet'
|
||||
ele.href= '!{url_for(theme.asset.disqusjs_css)}'
|
||||
document.getElementsByTagName('head')[0].appendChild(ele)
|
||||
}
|
||||
|
||||
function initDisqusjs () {
|
||||
window.disqusjs = null
|
||||
disqusjs = new DisqusJS(Object.assign({
|
||||
@@ -34,7 +27,7 @@ script.
|
||||
|
||||
if (window.disqusJsLoad) initDisqusjs()
|
||||
else {
|
||||
addDisqusjsCSS()
|
||||
getCSS('!{url_for(theme.asset.disqusjs_css)}')
|
||||
getScript('!{url_for(theme.asset.disqusjs)}').then(initDisqusjs)
|
||||
window.disqusJsLoad = true
|
||||
}
|
||||
|
||||
@@ -1,16 +1,26 @@
|
||||
#fb-root
|
||||
- const fbSDKVer = 'v16.0'
|
||||
- const fbSDK = theme.messenger.enable ? `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk/xfbml.customerchat.js#xfbml=1&version=${fbSDKVer}` : `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk.js#xfbml=1&version=${fbSDKVer}`
|
||||
|
||||
script.
|
||||
function loadFBComment () {
|
||||
var themeNow = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
|
||||
document.getElementsByClassName('fb-comments')[0].setAttribute('data-colorscheme',themeNow)
|
||||
document.getElementById('fb-root') ? '' : document.body.insertAdjacentHTML('afterend', '<div id="fb-root"></div>')
|
||||
|
||||
if (typeof FB === 'object') FB.XFBML.parse()
|
||||
const themeNow = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
|
||||
const $fbComment = document.getElementsByClassName('fb-comments')[0]
|
||||
$fbComment.setAttribute('data-colorscheme',themeNow)
|
||||
$fbComment.setAttribute('data-href', '!{urlNoIndex(page.permalink)}')
|
||||
|
||||
if (typeof FB === 'object') {
|
||||
FB.XFBML.parse(document.getElementsByClassName('post-meta-commentcount')[0])
|
||||
FB.XFBML.parse(document.getElementById('post-comment'))
|
||||
}
|
||||
else {
|
||||
let ele = document.createElement('script')
|
||||
ele.setAttribute('src','https://connect.facebook.net/!{theme.facebook_comments.lang}/sdk.js#xfbml=1&version=v13.0&appId=!{theme.facebook_comments.app_id}&autoLogAppEvents=1')
|
||||
ele.setAttribute('src','!{fbSDK}')
|
||||
ele.setAttribute('async', 'true')
|
||||
ele.setAttribute('defer', 'true')
|
||||
ele.setAttribute('crossorigin', 'anonymous')
|
||||
ele.setAttribute('id', 'facebook-jssdk')
|
||||
document.getElementById('fb-root').insertAdjacentElement('afterbegin',ele)
|
||||
}
|
||||
}
|
||||
|
||||
28
layout/includes/third-party/comments/giscus.pug
vendored
28
layout/includes/third-party/comments/giscus.pug
vendored
@@ -1,16 +1,20 @@
|
||||
- const { repo, repo_id, category_id, option } = theme.giscus
|
||||
- const themes = theme.giscus.theme
|
||||
script.
|
||||
function loadGiscus () {
|
||||
let nowTheme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{themes.dark}' : '!{themes.light}'
|
||||
- const { repo, repo_id, category_id, theme:themes, option } = theme.giscus
|
||||
- const giscusUrl = theme.asset.giscus || 'https://giscus.app/client.js'
|
||||
- const giscusOriginUrl = new URL(giscusUrl).origin
|
||||
|
||||
script.
|
||||
function getGiscusTheme () {
|
||||
return document.documentElement.getAttribute('data-theme') === 'dark' ? '!{themes.dark}' : '!{themes.light}'
|
||||
}
|
||||
|
||||
function loadGiscus () {
|
||||
const config = Object.assign({
|
||||
src: 'https://giscus.app/client.js',
|
||||
src: '!{giscusUrl}',
|
||||
'data-repo': '!{repo}',
|
||||
'data-repo-id': '!{repo_id}',
|
||||
'data-category-id': '!{category_id}',
|
||||
'data-mapping': 'pathname',
|
||||
'data-theme': nowTheme,
|
||||
'data-theme': getGiscusTheme(),
|
||||
'data-reactions-enabled': '1',
|
||||
crossorigin: 'anonymous',
|
||||
async: true
|
||||
@@ -24,17 +28,15 @@ script.
|
||||
}
|
||||
|
||||
function changeGiscusTheme () {
|
||||
const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{themes.dark}' : '!{themes.light}'
|
||||
|
||||
function sendMessage(message) {
|
||||
const iframe = document.querySelector('iframe.giscus-frame');
|
||||
if (!iframe) return;
|
||||
iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app');
|
||||
const iframe = document.querySelector('iframe.giscus-frame')
|
||||
if (!iframe) return
|
||||
iframe.contentWindow.postMessage({ giscus: message }, '!{giscusOriginUrl}')
|
||||
}
|
||||
|
||||
sendMessage({
|
||||
setConfig: {
|
||||
theme: theme
|
||||
theme: getGiscusTheme()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
script.
|
||||
function addGitalkSource () {
|
||||
const ele = document.createElement('link')
|
||||
ele.rel = 'stylesheet'
|
||||
ele.href= '!{url_for(theme.asset.gitalk_css)}'
|
||||
document.getElementsByTagName('head')[0].appendChild(ele)
|
||||
}
|
||||
|
||||
function loadGitalk () {
|
||||
function initGitalk () {
|
||||
var gitalk = new Gitalk(Object.assign({
|
||||
@@ -23,7 +16,7 @@ script.
|
||||
|
||||
if (typeof Gitalk === 'function') initGitalk()
|
||||
else {
|
||||
addGitalkSource()
|
||||
getCSS('!{url_for(theme.asset.gitalk_css)}')
|
||||
getScript('!{url_for(theme.asset.gitalk)}').then(initGitalk)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,3 +42,5 @@ hr
|
||||
data-width="100%")
|
||||
when 'Remark42'
|
||||
#remark42
|
||||
when 'Artalk'
|
||||
#artalk-wrap
|
||||
|
||||
4
layout/includes/third-party/comments/js.pug
vendored
4
layout/includes/third-party/comments/js.pug
vendored
@@ -19,6 +19,8 @@ each name in theme.comments.use
|
||||
when 'Giscus'
|
||||
!=partial('includes/third-party/comments/giscus', {}, {cache: true})
|
||||
when 'Facebook Comments'
|
||||
!=partial('includes/third-party/comments/facebook_comments', {}, {cache: true})
|
||||
include ./facebook_comments.pug
|
||||
when 'Remark42'
|
||||
!=partial('includes/third-party/comments/remark42', {}, {cache: true})
|
||||
when 'Artalk'
|
||||
!=partial('includes/third-party/comments/artalk', {}, {cache: true})
|
||||
18
layout/includes/third-party/comments/waline.pug
vendored
18
layout/includes/third-party/comments/waline.pug
vendored
@@ -3,13 +3,6 @@
|
||||
|
||||
script.
|
||||
function loadWaline () {
|
||||
function insertCSS () {
|
||||
const link = document.createElement("link")
|
||||
link.rel = "stylesheet"
|
||||
link.href = "!{url_for(theme.asset.waline_css)}"
|
||||
document.head.appendChild(link)
|
||||
}
|
||||
|
||||
function initWaline () {
|
||||
const waline = Waline.init(Object.assign({
|
||||
el: '#waline-wrap',
|
||||
@@ -21,10 +14,15 @@ script.
|
||||
}, !{JSON.stringify(option)}))
|
||||
}
|
||||
|
||||
if (typeof Waline === 'function') initWaline()
|
||||
const walineCSSLoad = document.getElementById('waline-css')
|
||||
|
||||
if (typeof Waline === 'object') {
|
||||
walineCSSLoad ? initWaline() : getCSS('!{url_for(theme.asset.waline_css)}','waline-css').then(initWaline)
|
||||
}
|
||||
else {
|
||||
insertCSS()
|
||||
getScript('!{url_for(theme.asset.waline_js)}').then(initWaline)
|
||||
getCSS('!{url_for(theme.asset.waline_css)}','waline-css').then(() => {
|
||||
getScript('!{url_for(theme.asset.waline_js)}').then(initWaline)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
13
layout/includes/third-party/math/mathjax.pug
vendored
13
layout/includes/third-party/math/mathjax.pug
vendored
@@ -7,7 +7,7 @@ script.
|
||||
tags: 'ams'
|
||||
},
|
||||
chtml: {
|
||||
scale: 1.2
|
||||
scale: 1.1
|
||||
},
|
||||
options: {
|
||||
renderActions: {
|
||||
@@ -23,12 +23,11 @@ script.
|
||||
}
|
||||
}, ''],
|
||||
insertScript: [200, () => {
|
||||
document.querySelectorAll('mjx-container:not\([display]\)').forEach(node => {
|
||||
const target = node.parentNode
|
||||
if (target.nodeName.toLowerCase() === 'li') {
|
||||
target.parentNode.classList.add('has-jax')
|
||||
document.querySelectorAll('mjx-container').forEach(node => {
|
||||
if (node.hasAttribute('display')) {
|
||||
btf.wrap(node, 'div', { class: 'mathjax-overflow' })
|
||||
} else {
|
||||
target.classList.add('has-jax')
|
||||
btf.wrap(node, 'span', { class: 'mathjax-overflow' })
|
||||
}
|
||||
});
|
||||
}, '', false]
|
||||
@@ -44,5 +43,5 @@ script.
|
||||
} else {
|
||||
MathJax.startup.document.state(0)
|
||||
MathJax.texReset()
|
||||
MathJax.typeset()
|
||||
MathJax.typesetPromise()
|
||||
}
|
||||
89
layout/includes/third-party/newest-comments/artalk.pug
vendored
Normal file
89
layout/includes/third-party/newest-comments/artalk.pug
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
- const { server, site, option } = theme.artalk
|
||||
- const avatarCdn = option !== null && option.gravatar ? option.gravatar.mirror : 'https://sdn.geekzu.org/avatar/'
|
||||
- const avatarDefault = option !== null && option.gravatar ? option.gravatar.default : 'mp'
|
||||
|
||||
script.
|
||||
window.addEventListener('load', () => {
|
||||
const changeContent = (content) => {
|
||||
if (content === '') return content
|
||||
|
||||
content = content.replace(/<img.*?src="(.*?)"?[^\>]+>/ig, '[!{_p("aside.card_newest_comments.image")}]') // replace image link
|
||||
content = content.replace(/<a[^>]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi, '[!{_p("aside.card_newest_comments.link")}]') // replace url
|
||||
content = content.replace(/<pre><code>.*?<\/pre>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code
|
||||
content = content.replace(/<[^>]+>/g,"") // remove html tag
|
||||
|
||||
if (content.length > 150) {
|
||||
content = content.substring(0,150) + '...'
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
const generateHtml = array => {
|
||||
let result = ''
|
||||
|
||||
if (array.length) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
result += '<div class=\'aside-list-item\'>'
|
||||
|
||||
if (!{theme.newest_comments.avatar}) {
|
||||
const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}'
|
||||
result += `<a href='${array[i].url}' class='thumbnail'><img ${name}='${array[i].avatar}' alt='${array[i].nick}'></a>`
|
||||
}
|
||||
|
||||
result += `<div class='content'>
|
||||
<a class='comment' href='${array[i].url}' title='${array[i].content}'>${array[i].content}</a>
|
||||
<div class='name'><span>${array[i].nick} / </span><time datetime="${array[i].date}">${btf.diffDate(array[i].date, true)}</time></div>
|
||||
</div></div>`
|
||||
}
|
||||
} else {
|
||||
result += '!{_p("aside.card_newest_comments.zero")}'
|
||||
}
|
||||
|
||||
let $dom = document.querySelector('#card-newest-comments .aside-list')
|
||||
$dom.innerHTML= result
|
||||
window.lazyLoadInstance && window.lazyLoadInstance.update()
|
||||
window.pjax && window.pjax.refresh($dom)
|
||||
}
|
||||
|
||||
const headerList = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Origin': window.location.origin
|
||||
}
|
||||
}
|
||||
|
||||
const getComment = () => {
|
||||
fetch('!{server}/api/stat?type=latest_comments&limit=!{theme.newest_comments.limit}&site_name=!{site}', headerList)
|
||||
.then(response => response.json())
|
||||
.then(d => {
|
||||
const artalk = d.data.map(function (e) {
|
||||
return {
|
||||
'avatar': '!{avatarCdn}' + e.email_encrypted + '?d=!{avatarDefault}',
|
||||
'content': changeContent(e.content_marked),
|
||||
'nick': e.nick,
|
||||
'url': e.page_url,
|
||||
'date': e.date,
|
||||
}
|
||||
})
|
||||
saveToLocal.set('artalk-newest-comments', JSON.stringify(artalk), !{theme.newest_comments.storage}/(60*24))
|
||||
generateHtml(artalk)
|
||||
}).catch(e => {
|
||||
const $dom = document.querySelector('#card-newest-comments .aside-list')
|
||||
$dom.innerHTML= "!{_p('aside.card_newest_comments.error')}"
|
||||
})
|
||||
}
|
||||
|
||||
const newestCommentInit = () => {
|
||||
if (document.querySelector('#card-newest-comments .aside-list')) {
|
||||
const data = saveToLocal.get('artalk-newest-comments')
|
||||
if (data) {
|
||||
generateHtml(JSON.parse(data))
|
||||
} else {
|
||||
getComment()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newestCommentInit()
|
||||
document.addEventListener('pjax:complete', newestCommentInit)
|
||||
})
|
||||
@@ -25,4 +25,6 @@ if use
|
||||
- userRepo = theme.utterances.repo
|
||||
include ./github-issues.pug
|
||||
when 'Remark42'
|
||||
include ./remark42.pug
|
||||
include ./remark42.pug
|
||||
when 'Artalk'
|
||||
include ./artalk.pug
|
||||
@@ -64,7 +64,7 @@ script.
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof Waline === 'function') loadWaline()
|
||||
if (typeof Waline === 'object') loadWaline()
|
||||
else getScript('!{url_for(theme.asset.waline_js)}').then(loadWaline)
|
||||
}
|
||||
|
||||
|
||||
5
layout/includes/third-party/pjax.pug
vendored
5
layout/includes/third-party/pjax.pug
vendored
@@ -7,7 +7,7 @@ if theme.pjax.exclude
|
||||
|
||||
- let choose = theme.comments.use
|
||||
if choose
|
||||
if theme.Open_Graph_meta && (choose.includes('Livere') || choose.includes('Utterances') || choose.includes('Giscus'))
|
||||
if theme.Open_Graph_meta.enable && (choose.includes('Livere') || choose.includes('Utterances') || choose.includes('Giscus'))
|
||||
- pjaxSelectors.unshift('meta[property="og:image"]', 'meta[property="og:title"]', 'meta[property="og:url"]')
|
||||
if choose.includes('Utterances') || choose.includes('Giscus')
|
||||
- pjaxSelectors.unshift('link[rel="canonical"]')
|
||||
@@ -30,7 +30,6 @@ script.
|
||||
window.tocScrollFn && window.removeEventListener('scroll', window.tocScrollFn)
|
||||
window.scrollCollect && window.removeEventListener('scroll', scrollCollect)
|
||||
|
||||
typeof preloader === 'object' && preloader.initLoading()
|
||||
document.getElementById('rightside').style.cssText = "opacity: ''; transform: ''"
|
||||
|
||||
if (window.aplayers) {
|
||||
@@ -76,8 +75,6 @@ script.
|
||||
|
||||
// prismjs
|
||||
typeof Prism === 'object' && Prism.highlightAll()
|
||||
|
||||
typeof preloader === 'object' && preloader.endLoading()
|
||||
})
|
||||
|
||||
document.addEventListener('pjax:error', (e) => {
|
||||
|
||||
@@ -16,3 +16,7 @@
|
||||
.algolia-poweredBy
|
||||
|
||||
#search-mask
|
||||
|
||||
script(src=url_for(theme.asset.algolia_search))
|
||||
script(src=url_for(theme.asset.instantsearch))
|
||||
script(src=url_for(theme.asset.algolia_js))
|
||||
27
layout/includes/third-party/search/docsearch.pug
vendored
Normal file
27
layout/includes/third-party/search/docsearch.pug
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
- const { appId, apiKey, indexName, option } = theme.docsearch
|
||||
|
||||
.docsearch-wrap
|
||||
#docsearch(style="display:none")
|
||||
link(rel="stylesheet" href=url_for(theme.asset.docsearch_css))
|
||||
script(src=url_for(theme.asset.docsearch_js))
|
||||
script.
|
||||
(() => {
|
||||
docsearch(Object.assign({
|
||||
appId: '!{appId}',
|
||||
apiKey: '!{apiKey}',
|
||||
indexName: '!{indexName}',
|
||||
container: '#docsearch',
|
||||
}, !{JSON.stringify(option)}))
|
||||
|
||||
|
||||
const searchClickFn = () => {
|
||||
document.querySelector('#search-button > .search').addEventListener('click', () => {
|
||||
document.querySelector('.DocSearch-Button').click()
|
||||
})
|
||||
}
|
||||
|
||||
searchClickFn()
|
||||
window.addEventListener('pjax:complete', searchClickFn)
|
||||
})()
|
||||
|
||||
|
||||
4
layout/includes/third-party/search/index.pug
vendored
4
layout/includes/third-party/search/index.pug
vendored
@@ -1,4 +1,6 @@
|
||||
if theme.algolia_search.enable
|
||||
include ./algolia.pug
|
||||
else if theme.local_search.enable
|
||||
include ./local-search.pug
|
||||
include ./local-search.pug
|
||||
else if theme.docsearch.enable
|
||||
include ./docsearch.pug
|
||||
@@ -15,6 +15,8 @@
|
||||
.local-search-box
|
||||
input(placeholder=_p("search.local_search.input_placeholder") type="text").local-search-box--input
|
||||
hr
|
||||
#local-search-results
|
||||
#local-search-results.no-result
|
||||
#local-search-stats-wrap
|
||||
#search-mask
|
||||
|
||||
#search-mask
|
||||
script(src=url_for(theme.asset.local_search))
|
||||
@@ -1,3 +1,4 @@
|
||||
.social-share(data-image=url_for(page.cover|| theme.avatar.img) data-sites= theme.sharejs.sites)
|
||||
- const coverVal = page.cover_type === 'img' ? page.cover : theme.avatar.img
|
||||
.social-share(data-image=url_for(coverVal) data-sites= theme.sharejs.sites)
|
||||
link(rel='stylesheet' href=url_for(theme.asset.sharejs_css) media="print" onload="this.media='all'")
|
||||
script(src=url_for(theme.asset.sharejs) defer)
|
||||
104
layout/includes/third-party/subtitle.pug
vendored
104
layout/includes/third-party/subtitle.pug
vendored
@@ -1,6 +1,30 @@
|
||||
- const { effect,loop,source,sub } = theme.subtitle
|
||||
- const { effect,source,sub,typed_option } = theme.subtitle
|
||||
- let subContent = sub || new Array()
|
||||
|
||||
script.
|
||||
window.typedJSFn = {
|
||||
init: (str) => {
|
||||
window.typed = new Typed('#subtitle', Object.assign({
|
||||
strings: str,
|
||||
startDelay: 300,
|
||||
typeSpeed: 150,
|
||||
loop: true,
|
||||
backSpeed: 50,
|
||||
}, !{JSON.stringify(typed_option)}))
|
||||
},
|
||||
run: (subtitleType) => {
|
||||
if (!{effect}) {
|
||||
if (typeof Typed === 'function') {
|
||||
subtitleType()
|
||||
} else {
|
||||
getScript('!{url_for(theme.asset.typed)}').then(subtitleType)
|
||||
}
|
||||
} else {
|
||||
subtitleType()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case source
|
||||
when 1
|
||||
script.
|
||||
@@ -12,28 +36,13 @@ case source
|
||||
const from = '出自 ' + data.from
|
||||
const sub = !{JSON.stringify(subContent)}
|
||||
sub.unshift(data.hitokoto, from)
|
||||
window.typed = new Typed('#subtitle', {
|
||||
strings: sub,
|
||||
startDelay: 300,
|
||||
typeSpeed: 150,
|
||||
loop: !{loop},
|
||||
backSpeed: 50,
|
||||
})
|
||||
typedJSFn.init(sub)
|
||||
} else {
|
||||
document.getElementById('subtitle').innerHTML = data.hitokoto
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!{effect}) {
|
||||
if (typeof Typed === 'function') {
|
||||
subtitleType()
|
||||
} else {
|
||||
getScript('!{url_for(theme.asset.typed)}').then(subtitleType)
|
||||
}
|
||||
} else {
|
||||
subtitleType()
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
|
||||
when 2
|
||||
script.
|
||||
@@ -44,28 +53,13 @@ case source
|
||||
const from = '出自 ' + str[1]
|
||||
const sub = !{JSON.stringify(subContent)}
|
||||
sub.unshift(con, from)
|
||||
window.typed = new Typed('#subtitle', {
|
||||
strings: sub,
|
||||
startDelay: 300,
|
||||
typeSpeed: 150,
|
||||
loop: !{loop},
|
||||
backSpeed: 50,
|
||||
})
|
||||
typedJSFn.init(sub)
|
||||
} else {
|
||||
document.getElementById('subtitle').innerHTML = con
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!{effect}) {
|
||||
if (typeof Typed === 'function') {
|
||||
subtitleType()
|
||||
} else {
|
||||
getScript('!{url_for(theme.asset.typed)}').then(subtitleType)
|
||||
}
|
||||
} else {
|
||||
subtitleType()
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
|
||||
when 3
|
||||
script.
|
||||
@@ -76,53 +70,23 @@ case source
|
||||
const sub = !{JSON.stringify(subContent)}
|
||||
const content = result.data.content
|
||||
sub.unshift(content)
|
||||
window.typed = new Typed('#subtitle', {
|
||||
strings: sub,
|
||||
startDelay: 300,
|
||||
typeSpeed: 150,
|
||||
loop: !{loop},
|
||||
backSpeed: 50,
|
||||
})
|
||||
typedJSFn.init(sub)
|
||||
} else {
|
||||
document.getElementById('subtitle').innerHTML = result.data.content
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (!{effect}) {
|
||||
if (typeof Typed === 'function') {
|
||||
subtitleType()
|
||||
} else {
|
||||
getScript('!{url_for(theme.asset.typed)}').then(subtitleType)
|
||||
}
|
||||
} else {
|
||||
subtitleType()
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
|
||||
default
|
||||
- subContent = subContent.length ? subContent : new Array(config.subtitle)
|
||||
script.
|
||||
function subtitleType () {
|
||||
if (!{effect}) {
|
||||
window.typed = new Typed("#subtitle", {
|
||||
strings: !{JSON.stringify(subContent)},
|
||||
startDelay: 300,
|
||||
typeSpeed: 150,
|
||||
loop: !{loop},
|
||||
backSpeed: 50
|
||||
})
|
||||
if (!{effect}) {
|
||||
typedJSFn.init(!{JSON.stringify(subContent)})
|
||||
} else {
|
||||
document.getElementById("subtitle").innerHTML = '!{subContent[0]}'
|
||||
}
|
||||
}
|
||||
|
||||
if (!{effect}) {
|
||||
if (typeof Typed === 'function') {
|
||||
subtitleType()
|
||||
} else {
|
||||
getScript('!{url_for(theme.asset.typed)}').then(subtitleType)
|
||||
}
|
||||
} else {
|
||||
subtitleType()
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
@@ -14,7 +14,10 @@ if theme.aside.card_recent_post.enable
|
||||
.aside-list-item(class=no_cover)
|
||||
if post_cover && theme.cover.aside_enable
|
||||
a.thumbnail(href=url_for(link) title=title)
|
||||
img(src=url_for(post_cover) onerror=`this.onerror=null;this.src='${url_for(theme.error_img.post_page)}'` alt=title)
|
||||
if article.cover_type === 'img'
|
||||
img(src=url_for(post_cover) onerror=`this.onerror=null;this.src='${url_for(theme.error_img.post_page)}'` alt=title)
|
||||
else
|
||||
div(style=`background: ${post_cover}`)
|
||||
.content
|
||||
a.title(href=url_for(link) title=title)= title
|
||||
if theme.aside.card_recent_post.sort === 'updated'
|
||||
|
||||
@@ -5,8 +5,10 @@ if theme.aside.card_tags.enable
|
||||
i.fas.fa-tags
|
||||
span= _p('aside.card_tags')
|
||||
|
||||
- let tagLimit = theme.aside.card_tags.limit === 0 ? 0 : theme.aside.card_tags.limit || 40
|
||||
- let { limit, orderby, order } = theme.aside.card_tags
|
||||
- limit = limit === 0 ? 0 : limit || 40
|
||||
|
||||
if theme.aside.card_tags.color
|
||||
.card-tag-cloud!= cloudTags({source: site.tags, minfontsize: 1.15, maxfontsize: 1.45, limit: tagLimit, unit: 'em'})
|
||||
.card-tag-cloud!= cloudTags({source: site.tags, orderby: orderby, order: order, minfontsize: 1.15, maxfontsize: 1.45, limit: limit, unit: 'em'})
|
||||
else
|
||||
.card-tag-cloud!= tagcloud({min_font: 1.1, max_font: 1.5, amount: tagLimit , color: true, start_color: '#999', end_color: '#99a9bf', unit: 'em'})
|
||||
.card-tag-cloud!= tagcloud({orderby: orderby, order: order, min_font: 1.1, max_font: 1.5, amount: limit , color: true, start_color: '#999', end_color: '#99a9bf', unit: 'em'})
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
//- page
|
||||
!=partial('includes/widget/card_author', {}, {cache: true})
|
||||
!=partial('includes/widget/card_announcement', {}, {cache: true})
|
||||
!=partial('includes/widget/card_top_self', {}, {cache: true})
|
||||
!=partial('includes/widget/card_top_self', {}, {cache: true})
|
||||
|
||||
.sticky_layout
|
||||
if showToc
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hexo-theme-butterfly",
|
||||
"version": "4.3.1",
|
||||
"version": "4.8.1",
|
||||
"description": "A Simple and Card UI Design theme for Hexo",
|
||||
"main": "package.json",
|
||||
"scripts": {
|
||||
|
||||
94
plugins.yml
94
plugins.yml
@@ -1,11 +1,11 @@
|
||||
algolia_search_v4:
|
||||
algolia_search:
|
||||
name: algoliasearch
|
||||
file: dist/algoliasearch-lite.umd.js
|
||||
version: 4.13.1
|
||||
instantsearch_v4:
|
||||
version: 4.17.0
|
||||
instantsearch:
|
||||
name: instantsearch.js
|
||||
file: dist/instantsearch.production.min.js
|
||||
version: 4.42.0
|
||||
version: 4.54.0
|
||||
pjax:
|
||||
name: pjax
|
||||
file: pjax.min.js
|
||||
@@ -13,11 +13,11 @@ pjax:
|
||||
gitalk:
|
||||
name: gitalk
|
||||
file: dist/gitalk.min.js
|
||||
version: 1.7.2
|
||||
version: 1.8.0
|
||||
gitalk_css:
|
||||
name: gitalk
|
||||
file: dist/gitalk.css
|
||||
version: 1.7.2
|
||||
version: 1.8.0
|
||||
blueimp_md5:
|
||||
name: blueimp-md5
|
||||
file: js/md5.min.js
|
||||
@@ -25,29 +25,29 @@ blueimp_md5:
|
||||
valine:
|
||||
name: valine
|
||||
file: dist/Valine.min.js
|
||||
version: 1.4.18
|
||||
version: 1.5.1
|
||||
disqusjs:
|
||||
name: disqusjs
|
||||
file: dist/browser/disqusjs.es2015.umd.min.js
|
||||
version: 3.0.1
|
||||
version: 3.0.2
|
||||
disqusjs_css:
|
||||
name: disqusjs
|
||||
file: dist/browser/styles/disqusjs.css
|
||||
version: 3.0.1
|
||||
version: 3.0.2
|
||||
twikoo:
|
||||
name: twikoo
|
||||
file: dist/twikoo.all.min.js
|
||||
version: 1.5.11
|
||||
version: 1.6.14
|
||||
waline_js:
|
||||
name: '@waline/client'
|
||||
file: dist/waline.js
|
||||
other_name: waline
|
||||
version: 2.6.1
|
||||
version: 2.14.9
|
||||
waline_css:
|
||||
name: '@waline/client'
|
||||
file: dist/waline.css
|
||||
other_name: waline
|
||||
version: 2.6.1
|
||||
version: 2.14.9
|
||||
sharejs:
|
||||
name: butterfly-extsrc
|
||||
file: sharejs/dist/js/social-share.min.js
|
||||
@@ -64,16 +64,16 @@ katex:
|
||||
name: katex
|
||||
file: dist/katex.min.css
|
||||
other_name: KaTeX
|
||||
version: 0.16.0
|
||||
version: 0.16.4
|
||||
katex_copytex:
|
||||
name: katex
|
||||
file: dist/contrib/copy-tex.min.js
|
||||
other_name: KaTeX
|
||||
version: 0.16.0
|
||||
version: 0.16.4
|
||||
mermaid:
|
||||
name: mermaid
|
||||
file: dist/mermaid.min.js
|
||||
version: 9.1.2
|
||||
version: 9.4.3
|
||||
canvas_ribbon:
|
||||
name: butterfly-extsrc
|
||||
file: dist/canvas-ribbon.min.js
|
||||
@@ -105,33 +105,33 @@ ClickShowText:
|
||||
lazyload:
|
||||
name: vanilla-lazyload
|
||||
file: dist/lazyload.iife.min.js
|
||||
version: 17.3.1
|
||||
version: 17.8.3
|
||||
instantpage:
|
||||
name: instant.page
|
||||
file: instantpage.js
|
||||
version: 5.1.0
|
||||
version: 5.2.0
|
||||
typed:
|
||||
name: typed.js
|
||||
file: lib/typed.min.js
|
||||
version: 2.0.12
|
||||
file: dist/typed.umd.js
|
||||
version: 2.0.15
|
||||
pangu:
|
||||
name: pangu
|
||||
file: dist/browser/pangu.min.js
|
||||
version: 4.0.7
|
||||
fancybox_css_v4:
|
||||
fancybox_css:
|
||||
name: '@fancyapps/ui'
|
||||
file: dist/fancybox.css
|
||||
version: 4.0.27
|
||||
file: dist/fancybox/fancybox.css
|
||||
version: 5.0.15
|
||||
other_name: fancyapps-ui
|
||||
fancybox_v4:
|
||||
fancybox:
|
||||
name: '@fancyapps/ui'
|
||||
file: dist/fancybox.umd.js
|
||||
version: 4.0.27
|
||||
file: dist/fancybox/fancybox.umd.js
|
||||
version: 5.0.15
|
||||
other_name: fancyapps-ui
|
||||
medium_zoom:
|
||||
name: medium-zoom
|
||||
file: dist/medium-zoom.min.js
|
||||
version: 1.0.6
|
||||
version: 1.0.8
|
||||
snackbar_css:
|
||||
name: node-snackbar
|
||||
file: dist/snackbar.min.css
|
||||
@@ -140,11 +140,11 @@ snackbar:
|
||||
name: node-snackbar
|
||||
file: dist/snackbar.min.js
|
||||
version: 0.1.16
|
||||
fontawesomeV6:
|
||||
fontawesome:
|
||||
name: '@fortawesome/fontawesome-free'
|
||||
file: css/all.min.css
|
||||
other_name: font-awesome
|
||||
version: 6.1.1
|
||||
version: 6.4.0
|
||||
flickr_justified_gallery_js:
|
||||
name: flickr-justified-gallery
|
||||
file: dist/fjGallery.min.js
|
||||
@@ -169,14 +169,46 @@ prismjs_js:
|
||||
name: prismjs
|
||||
file: prism.js
|
||||
other_name: prism
|
||||
version: 1.28.0
|
||||
version: 1.29.0
|
||||
prismjs_lineNumber_js:
|
||||
name: prismjs
|
||||
file: plugins/line-numbers/prism-line-numbers.min.js
|
||||
other_name: prism
|
||||
version: 1.28.0
|
||||
version: 1.29.0
|
||||
prismjs_autoloader:
|
||||
name: prismjs
|
||||
file: plugins/autoloader/prism-autoloader.min.js
|
||||
other_name: prism
|
||||
version: 1.28.0
|
||||
version: 1.29.0
|
||||
artalk_js:
|
||||
name: artalk
|
||||
file: dist/Artalk.js
|
||||
version: 2.5.4
|
||||
artalk_css:
|
||||
name: artalk
|
||||
file: dist/Artalk.css
|
||||
version: 2.5.4
|
||||
pace_js:
|
||||
name: pace-js
|
||||
other_name: pace
|
||||
file: pace.min.js
|
||||
version: 1.2.4
|
||||
pace_default_css:
|
||||
name: pace-js
|
||||
other_name: pace
|
||||
file: themes/blue/pace-theme-minimal.css
|
||||
version: 1.2.4
|
||||
docsearch_js:
|
||||
name: '@docsearch/js'
|
||||
other_name: docsearch-js
|
||||
file: dist/umd/index.js
|
||||
version: 3.3.3
|
||||
docsearch_css:
|
||||
name: '@docsearch/css'
|
||||
other_name: docsearch-css
|
||||
file: dist/style.css
|
||||
version: 3.3.3
|
||||
abcjs_basic_js:
|
||||
name: abcjs
|
||||
file: dist/abcjs-basic-min.js
|
||||
version: 6.2.0
|
||||
|
||||
@@ -12,7 +12,7 @@ hexo.extend.filter.register('before_generate', () => {
|
||||
const themeConfig = hexo.theme.config
|
||||
const { CDN } = themeConfig
|
||||
|
||||
const thirdPartySrc = hexo.render.renderSync({ path: path.join(hexo.theme_dir,'/plugins.yml'), engine: 'yaml'})
|
||||
const thirdPartySrc = hexo.render.renderSync({ path: path.join(hexo.theme_dir, '/plugins.yml'), engine: 'yaml' })
|
||||
const internalSrc = {
|
||||
main: {
|
||||
name: 'hexo-theme-butterfly',
|
||||
@@ -41,20 +41,19 @@ hexo.extend.filter.register('before_generate', () => {
|
||||
}
|
||||
}
|
||||
|
||||
const minFile = (file) => {
|
||||
const minFile = file => {
|
||||
return file.replace(/(?<!\.min)\.(js|css)$/g, ext => '.min' + ext)
|
||||
}
|
||||
|
||||
const createCDNLink = (data, type, cond = '') => {
|
||||
Object.keys(data).map(key => {
|
||||
Object.keys(data).forEach(key => {
|
||||
let { name, version, file, other_name } = data[key]
|
||||
|
||||
const min_file = minFile(file)
|
||||
const cdnjs_name = other_name || name
|
||||
const cdnjs_file = file.replace(/^[lib|dist]*\/|browser\//g, '')
|
||||
const min_cdnjs_file = minFile(cdnjs_file)
|
||||
if (cond === 'internal') file = `source/${file}`
|
||||
const verType = CDN.version ? `@${version}` : ''
|
||||
const min_file = minFile(file)
|
||||
const verType = CDN.version ? (type === 'local' ? `?v=${version}` : `@${version}`) : ''
|
||||
|
||||
const value = {
|
||||
version,
|
||||
@@ -65,18 +64,19 @@ hexo.extend.filter.register('before_generate', () => {
|
||||
min_cdnjs_file,
|
||||
cdnjs_name
|
||||
}
|
||||
|
||||
const cdnSource = {
|
||||
local: cond === 'internal' ? cdnjs_file : `/pluginsSrc/${name}/${file}`,
|
||||
local: cond === 'internal' ? `${cdnjs_file + verType}` : `/pluginsSrc/${name}/${file + verType}`,
|
||||
jsdelivr: `https://cdn.jsdelivr.net/npm/${name}${verType}/${min_file}`,
|
||||
unpkg: `https://unpkg.com/${name}${verType}/${file}`,
|
||||
cdnjs: `https://cdnjs.cloudflare.com/ajax/libs/${cdnjs_name}/${version}/${min_cdnjs_file}`,
|
||||
custom: (CDN.custom_format || '').replace(/\$\{(.+?)\}/g, (match, $1) => value[$1])
|
||||
}
|
||||
|
||||
|
||||
data[key] = cdnSource[type]
|
||||
})
|
||||
|
||||
if (cond === 'internal') data['main_css'] = 'css/index.css'
|
||||
if (cond === 'internal') data.main_css = 'css/index.css' + (CDN.version ? `?v=${version}` : '')
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -89,6 +89,9 @@ hexo.extend.filter.register('before_generate', () => {
|
||||
return obj
|
||||
}
|
||||
|
||||
themeConfig.asset = Object.assign(createCDNLink(internalSrc,CDN.internal_provider,'internal'),
|
||||
createCDNLink(thirdPartySrc,CDN.third_party_provider), deleteNullValue(CDN.option))
|
||||
themeConfig.asset = Object.assign(
|
||||
createCDNLink(internalSrc, CDN.internal_provider, 'internal'),
|
||||
createCDNLink(thirdPartySrc, CDN.third_party_provider),
|
||||
deleteNullValue(CDN.option)
|
||||
)
|
||||
})
|
||||
|
||||
@@ -11,4 +11,4 @@ hexo.extend.filter.register('before_generate', () => {
|
||||
}
|
||||
const newArray = use.map(item => item.toLowerCase().replace(/\b[a-z]/g, s => s.toUpperCase()))
|
||||
themeConfig.comments.use = newArray
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
const logger = require('hexo-log')()
|
||||
|
||||
hexo.extend.filter.register('before_generate', () => {
|
||||
// Get first two digits of the Hexo version number
|
||||
const hexoVer = hexo.version.replace(/(^.*\..*)\..*/, '$1')
|
||||
const logger = hexo.log
|
||||
|
||||
if (hexoVer < 5.3) {
|
||||
logger.error('Please update Hexo to V5.3.0 or higher!')
|
||||
@@ -13,7 +12,9 @@ hexo.extend.filter.register('before_generate', () => {
|
||||
if (hexo.locals.get) {
|
||||
const data = hexo.locals.get('data')
|
||||
if (data && data.butterfly) {
|
||||
logger.error(" 'butterfly.yml' is deprecated. Please use '_config.butterfly.yml' ")
|
||||
logger.error(
|
||||
" 'butterfly.yml' is deprecated. Please use '_config.butterfly.yml' "
|
||||
)
|
||||
logger.error(" 'butterfly.yml' 已經棄用,請使用 '_config.butterfly.yml' ")
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
const logger = require('hexo-log')()
|
||||
|
||||
hexo.on('ready', () => {
|
||||
const { version } = require('../../package.json')
|
||||
logger.info(`
|
||||
hexo.log.info(`
|
||||
===================================================================
|
||||
|
||||
##### # # ##### ##### ###### ##### ###### # # #
|
||||
# # # # # # # # # # # # #
|
||||
##### # # # # ##### # # ##### # #
|
||||
# # # # # # # ##### # # #
|
||||
# # # # # # # # # # # #
|
||||
##### #### # # ###### # # # ###### #
|
||||
|
||||
##### # # ##### ##### ###### ##### ###### # # #
|
||||
# # # # # # # # # # # # #
|
||||
##### # # # # ##### # # ##### # #
|
||||
# # # # # # # ##### # # #
|
||||
# # # # # # # # # # # #
|
||||
##### #### # # ###### # # # ###### #
|
||||
${version}
|
||||
===================================================================`)
|
||||
})
|
||||
|
||||
@@ -6,40 +6,40 @@
|
||||
'use strict'
|
||||
|
||||
hexo.extend.filter.register('before_post_render', function (data) {
|
||||
const { config } = this
|
||||
if (config.post_asset_folder) {
|
||||
const imgTestReg = /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/
|
||||
const imgTestReg = /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/i
|
||||
let randomCover
|
||||
let coverVal = data.cover
|
||||
|
||||
// Add path to top_img and cover if post_asset_folder is enabled
|
||||
if (hexo.config.post_asset_folder) {
|
||||
const topImg = data.top_img
|
||||
const cover = data.cover
|
||||
if (topImg && topImg.indexOf('/') === -1 && imgTestReg.test(topImg)) data.top_img = data.path + topImg
|
||||
if (cover && cover.indexOf('/') === -1) data.cover = data.path + cover
|
||||
if (coverVal && coverVal.indexOf('/') === -1 && imgTestReg.test(coverVal)) data.cover = data.path + coverVal
|
||||
}
|
||||
|
||||
if (data.cover === false) {
|
||||
data.randomcover = randomCover()
|
||||
return data
|
||||
const randomCoverFn = () => {
|
||||
const theme = hexo.theme.config
|
||||
if (!(theme.cover && theme.cover.default_cover)) return false
|
||||
if (!Array.isArray(theme.cover.default_cover)) return theme.cover.default_cover
|
||||
const num = Math.floor(Math.random() * theme.cover.default_cover.length)
|
||||
return theme.cover.default_cover[num]
|
||||
}
|
||||
|
||||
if (coverVal === false) return data
|
||||
|
||||
// If cover is not set, use random cover
|
||||
if (!coverVal) {
|
||||
randomCover = randomCoverFn()
|
||||
data.cover = randomCover
|
||||
coverVal = randomCover // update coverVal
|
||||
}
|
||||
|
||||
if (coverVal) {
|
||||
if (coverVal.indexOf('//') !== -1 || imgTestReg.test(coverVal)) {
|
||||
data.cover_type = 'img'
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
data.cover = data.cover || randomCover()
|
||||
return data
|
||||
})
|
||||
|
||||
function randomCover () {
|
||||
const theme = hexo.theme.config
|
||||
let cover
|
||||
let num
|
||||
|
||||
if (theme.cover && theme.cover.default_cover) {
|
||||
if (!Array.isArray(theme.cover.default_cover)) {
|
||||
cover = theme.cover.default_cover
|
||||
return cover
|
||||
} else {
|
||||
num = Math.floor(Math.random() * theme.cover.default_cover.length)
|
||||
cover = theme.cover.default_cover[num]
|
||||
return cover
|
||||
}
|
||||
} else {
|
||||
cover = theme.default_top_img || 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
|
||||
return cover
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
hexo.extend.helper.register('findArchiveLength', function (func) {
|
||||
const allPostsLength = this.site.posts.length;
|
||||
if (hexo.config.archive_generator && hexo.config.archive_generator.enable === false ) return allPostsLength
|
||||
const allPostsLength = this.site.posts.length
|
||||
if (hexo.config.archive_generator && hexo.config.archive_generator.enable === false) return allPostsLength
|
||||
const { yearly, monthly, daily } = hexo.config.archive_generator
|
||||
const { year, month, day } = this.page
|
||||
if (yearly === false || !year) return allPostsLength
|
||||
|
||||
const posts = this.site.posts.sort('date')
|
||||
|
||||
const compareFunc = (type,y1,m1,d1,y2,m2,d2) => {
|
||||
const compareFunc = (type, y1, m1, d1, y2, m2, d2) => {
|
||||
if (type === 'year') {
|
||||
return y1 === y2
|
||||
} else if (type === 'month') {
|
||||
@@ -18,15 +18,15 @@ hexo.extend.helper.register('findArchiveLength', function (func) {
|
||||
}
|
||||
|
||||
const generateDateObj = (type) => {
|
||||
let dateObj = []
|
||||
const dateObj = []
|
||||
let length = 0
|
||||
|
||||
posts.forEach(post => {
|
||||
let date = post.date.clone()
|
||||
const date = post.date.clone()
|
||||
const year = date.year()
|
||||
const month = date.month() + 1
|
||||
const day = date.date()
|
||||
let lastData = dateObj[length - 1]
|
||||
const lastData = dateObj[length - 1]
|
||||
|
||||
if (!lastData || !compareFunc(type, lastData.year, lastData.month, lastData.day, year, month, day)) {
|
||||
const name = type === 'year' ? year : type === 'month' ? `${year}-${month}` : `${year}-${month}-${day}`
|
||||
@@ -40,12 +40,12 @@ hexo.extend.helper.register('findArchiveLength', function (func) {
|
||||
} else {
|
||||
lastData.count++
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
return dateObj
|
||||
}
|
||||
|
||||
const data = func('createArchiveObj', ()=> {
|
||||
const data = func('createArchiveObj', () => {
|
||||
const yearObj = yearly ? generateDateObj('year') : []
|
||||
const monthObj = monthly ? generateDateObj('month') : []
|
||||
const dayObj = daily ? generateDateObj('day') : []
|
||||
@@ -55,4 +55,4 @@ hexo.extend.helper.register('findArchiveLength', function (func) {
|
||||
|
||||
const name = month ? day ? `${year}-${month}-${day}` : `${year}-${month}` : year
|
||||
return data.find(item => item.name === name).count
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
|
||||
hexo.extend.helper.register('inject_head_js', function () {
|
||||
const { darkmode, aside } = this.theme
|
||||
|
||||
const start = darkmode.start ? darkmode.start : 6
|
||||
const end = darkmode.end ? darkmode.end : 18
|
||||
const { theme_color } = hexo.theme.config
|
||||
const themeColorLight = theme_color && theme_color.enable && theme_color.meta_theme_color_light || '#ffffff'
|
||||
const themeColorDark = theme_color && theme_color.enable && theme_color.meta_theme_color_dark || '#0d0d0d'
|
||||
const themeColorLight = (theme_color && theme_color.enable && theme_color.meta_theme_color_light) || '#ffffff'
|
||||
const themeColorDark = (theme_color && theme_color.enable && theme_color.meta_theme_color_dark) || '#0d0d0d'
|
||||
|
||||
const localStore = `
|
||||
win.saveToLocal = {
|
||||
@@ -60,6 +61,23 @@ hexo.extend.helper.register('inject_head_js', function () {
|
||||
})
|
||||
`
|
||||
|
||||
const getCSS = `
|
||||
win.getCSS = (url,id = false) => new Promise((resolve, reject) => {
|
||||
const link = document.createElement('link')
|
||||
link.rel = 'stylesheet'
|
||||
link.href = url
|
||||
if (id) link.id = id
|
||||
link.onerror = reject
|
||||
link.onload = link.onreadystatechange = function() {
|
||||
const loadState = this.readyState
|
||||
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
|
||||
link.onload = link.onreadystatechange = null
|
||||
resolve()
|
||||
}
|
||||
document.head.appendChild(link)
|
||||
})
|
||||
`
|
||||
|
||||
let darkmodeJs = ''
|
||||
if (darkmode.enable) {
|
||||
darkmodeJs = `
|
||||
@@ -93,7 +111,7 @@ hexo.extend.helper.register('inject_head_js', function () {
|
||||
else if (isNotSpecified || hasNoSupport) {
|
||||
const now = new Date()
|
||||
const hour = now.getHours()
|
||||
const isNight = hour <= 6 || hour >= 18
|
||||
const isNight = hour <= ${start} || hour >= ${end}
|
||||
isNight ? activateDarkMode() : activateLightMode()
|
||||
}
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
|
||||
@@ -108,7 +126,7 @@ hexo.extend.helper.register('inject_head_js', function () {
|
||||
darkmodeJs += `
|
||||
const now = new Date()
|
||||
const hour = now.getHours()
|
||||
const isNight = hour <= 6 || hour >= 18
|
||||
const isNight = hour <= ${start} || hour >= ${end}
|
||||
if (t === undefined) isNight ? activateDarkMode() : activateLightMode()
|
||||
else if (t === 'light') activateLightMode()
|
||||
else activateDarkMode()
|
||||
@@ -144,5 +162,5 @@ hexo.extend.helper.register('inject_head_js', function () {
|
||||
detectApple()
|
||||
`
|
||||
|
||||
return `<script>(win=>{${localStore + getScript + darkmodeJs + asideStatus + detectApple}})(window)</script>`
|
||||
return `<script>(win=>{${localStore + getScript + getCSS + darkmodeJs + asideStatus + detectApple}})(window)</script>`
|
||||
})
|
||||
|
||||
@@ -24,11 +24,8 @@ hexo.extend.helper.register('page_description', function () {
|
||||
|
||||
hexo.extend.helper.register('cloudTags', function (options = {}) {
|
||||
const env = this
|
||||
let source = options.source
|
||||
const minfontsize = options.minfontsize
|
||||
const maxfontsize = options.maxfontsize
|
||||
const limit = options.limit
|
||||
const unit = options.unit || 'px'
|
||||
let { source, minfontsize, maxfontsize, limit, unit, orderby, order } = options
|
||||
unit = unit || 'px'
|
||||
|
||||
let result = ''
|
||||
if (limit > 0) {
|
||||
@@ -43,7 +40,7 @@ hexo.extend.helper.register('cloudTags', function (options = {}) {
|
||||
})
|
||||
|
||||
const length = sizes.length - 1
|
||||
source.forEach(tag => {
|
||||
source.sort(orderby, order).forEach(tag => {
|
||||
const ratio = length ? sizes.indexOf(tag.length) / length : 0
|
||||
const size = minfontsize + ((maxfontsize - minfontsize) * ratio)
|
||||
let style = `font-size: ${parseFloat(size.toFixed(2))}${unit};`
|
||||
@@ -54,8 +51,8 @@ hexo.extend.helper.register('cloudTags', function (options = {}) {
|
||||
return result
|
||||
})
|
||||
|
||||
hexo.extend.helper.register('urlNoIndex', function (url = null) {
|
||||
return prettyUrls(url || this.url, { trailing_index: false, trailing_html: false })
|
||||
hexo.extend.helper.register('urlNoIndex', function (url = null, trailingIndex = false, trailingHtml = false) {
|
||||
return prettyUrls(url || this.url, { trailing_index: trailingIndex, trailing_html: trailingHtml })
|
||||
})
|
||||
|
||||
hexo.extend.helper.register('md5', function (path) {
|
||||
@@ -74,8 +71,8 @@ hexo.extend.helper.register('injectHtml', function (data) {
|
||||
hexo.extend.helper.register('findArchivesTitle', function (page, menu, date) {
|
||||
if (page.year) {
|
||||
const dateStr = page.month ? `${page.year}-${page.month}` : `${page.year}`
|
||||
const date_format = page.month ? hexo.theme.config.aside.card_archives.format : 'YYYY'
|
||||
return date(dateStr, date_format)
|
||||
const dateFormat = page.month ? hexo.theme.config.aside.card_archives.format : 'YYYY'
|
||||
return date(dateStr, dateFormat)
|
||||
}
|
||||
|
||||
const defaultTitle = this._p('page.archives')
|
||||
@@ -95,3 +92,11 @@ hexo.extend.helper.register('findArchivesTitle', function (page, menu, date) {
|
||||
|
||||
return loop(menu) || defaultTitle
|
||||
})
|
||||
|
||||
hexo.extend.helper.register('isImgOrUrl', function (path) {
|
||||
const imgTestReg = /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/i
|
||||
if (path.indexOf('//') !== -1 || imgTestReg.test(path)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
@@ -15,7 +15,7 @@ hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
|
||||
title: post.title,
|
||||
path: post.path,
|
||||
cover: post.cover,
|
||||
randomcover: post.randomcover,
|
||||
cover_type: post.cover_type,
|
||||
weight: 1,
|
||||
updated: post.updated,
|
||||
created: post.date
|
||||
@@ -50,13 +50,14 @@ hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
|
||||
result += '<div class="relatedPosts-list">'
|
||||
|
||||
for (let i = 0; i < Math.min(relatedPosts.length, limitNum); i++) {
|
||||
const cover =
|
||||
relatedPosts[i].cover === false
|
||||
? relatedPosts[i].randomcover
|
||||
: relatedPosts[i].cover
|
||||
const cover = relatedPosts[i].cover || 'var(--default-bg-color)'
|
||||
const title = this.escape_html(relatedPosts[i].title)
|
||||
result += `<div><a href="${this.url_for(relatedPosts[i].path)}" title="${title}">`
|
||||
result += `<img class="cover" src="${this.url_for(cover)}" alt="cover">`
|
||||
if (relatedPosts[i].cover_type === 'img') {
|
||||
result += `<img class="cover" src="${this.url_for(cover)}" alt="cover">`
|
||||
} else {
|
||||
result += `<div class="cover" style="background: ${cover}"></div>`
|
||||
}
|
||||
if (dateType === 'created') {
|
||||
result += `<div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> ${this.date(relatedPosts[i].created, hexoConfig.date_format)}</div>`
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/**
|
||||
* Butterfly
|
||||
* galleryGroup and allery
|
||||
* galleryGroup and gallery
|
||||
* {% galleryGroup [name] [descr] [url] [img] %}
|
||||
* {% gallery [lazyload],[rowHeight],[limit] %}
|
||||
* {% gallery url,[url],[lazyload],[rowHeight],[limit] %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
@@ -8,13 +11,45 @@
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
function gallery (args, content) {
|
||||
return `<div class="fj-gallery">${hexo.render.renderSync({ text: content, engine: 'markdown' }).split('\n').join('')}
|
||||
</div>`
|
||||
const { data, languages } = hexo.theme.i18n
|
||||
args = args.join(' ').split(',')
|
||||
let rowHeight, limit, lazyload, type, dataStr
|
||||
|
||||
if (args[0] === 'url') {
|
||||
[type, dataStr, lazyload, rowHeight = 220, limit = 10] = args // url,[link],[lazyload],[rowHeight],[limit]
|
||||
} else {
|
||||
[lazyload, rowHeight = 220, limit = 10] = args // [lazyload],[rowHeight],[limit]
|
||||
const regex = /!\[(.*?)\]\(([^\s]*)\s*(?:["'](.*?)["']?)?\s*\)/g
|
||||
let m
|
||||
const arr = []
|
||||
while ((m = regex.exec(content)) !== null) {
|
||||
if (m.index === regex.lastIndex) {
|
||||
regex.lastIndex++
|
||||
}
|
||||
arr.push({
|
||||
url: m[2],
|
||||
alt: m[1],
|
||||
title: m[3]
|
||||
})
|
||||
}
|
||||
|
||||
dataStr = JSON.stringify(arr)
|
||||
}
|
||||
|
||||
type = type ? ' url' : ' data'
|
||||
const lazyloadClass = lazyload === 'true' ? 'lazyload' : ''
|
||||
|
||||
return `<div class="gallery">
|
||||
<div class="fj-gallery ${lazyloadClass + type}" data-rowHeight="${rowHeight}" data-limit="${limit}">
|
||||
<span class="gallery-data">${dataStr}</span>
|
||||
</div>
|
||||
<button class="gallery-load-more"><span>${data[languages[0]].load_more}</span><i class="fa-solid fa-arrow-down"></i></button>
|
||||
</div>`
|
||||
}
|
||||
|
||||
function galleryGroup (args) {
|
||||
const name = args[0]
|
||||
const desrc = args[1]
|
||||
const descr = args[1]
|
||||
const url = urlFor(args[2])
|
||||
const img = urlFor(args[3])
|
||||
|
||||
@@ -23,7 +58,7 @@ function galleryGroup (args) {
|
||||
<img class="gallery-group-img no-lightbox" src='${img}' alt="Group Image Gallery">
|
||||
<figcaption>
|
||||
<div class="gallery-group-name">${name}</div>
|
||||
<p>${desrc}</p>
|
||||
<p>${descr}</p>
|
||||
<a href='${url}'></a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
|
||||
22
scripts/tag/score.js
Normal file
22
scripts/tag/score.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Music Score
|
||||
* {% score %}
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function score(args, content) {
|
||||
function escapeHtmlTags(s) {
|
||||
let lookup = {
|
||||
'&': "&",
|
||||
'"': """,
|
||||
'\'': "'",
|
||||
'<': "<",
|
||||
'>': ">"
|
||||
};
|
||||
return s.replace(/[&"'<>]/g, c => lookup[c]);
|
||||
}
|
||||
return `<div class="abc-music-sheet">${escapeHtmlTags(content)}</div>`;
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('score', score, {ends: true});
|
||||
@@ -36,11 +36,11 @@
|
||||
|
||||
.postImgHover
|
||||
&:hover
|
||||
img
|
||||
.cover
|
||||
opacity: .8
|
||||
transform: scale(1.1)
|
||||
|
||||
img
|
||||
.cover
|
||||
position: absolute
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
--hr-before-color: lighten($theme-hr-color, 30%)
|
||||
--search-bg: $search-bg
|
||||
--search-input-color: $search-input-color
|
||||
--search-result-title: $search-result-title
|
||||
--search-a-color: $search-a-color
|
||||
--preloader-bg: $preloader-bg
|
||||
--preloader-color: $preloader-word-color
|
||||
--tab-border-color: $tab-border-color
|
||||
@@ -33,6 +33,7 @@
|
||||
--pseudo-hover: $pseudo-hover
|
||||
--headline-presudo: #a0a0a0
|
||||
--scrollbar-color: $scrollbar-color
|
||||
--default-bg-color: $theme-color
|
||||
|
||||
body
|
||||
position: relative
|
||||
@@ -49,8 +50,8 @@ body
|
||||
|
||||
// scrollbar - chrome/safari
|
||||
*::-webkit-scrollbar
|
||||
width: 8px
|
||||
height: 8px
|
||||
width: 5px
|
||||
height: 5px
|
||||
|
||||
*::-webkit-scrollbar-thumb
|
||||
background: var(--scrollbar-color)
|
||||
@@ -165,7 +166,7 @@ a
|
||||
if $site-name-font
|
||||
#site-title,
|
||||
#site-subtitle,
|
||||
#site-name,
|
||||
.site-name,
|
||||
#aside-content .author-info__name,
|
||||
#aside-content .author-info__description
|
||||
font-family: $site-name-font
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
transition: all .3s
|
||||
|
||||
&:hover
|
||||
transform: rotate(540deg)
|
||||
transform: rotate(360deg)
|
||||
|
||||
#card-info-btn
|
||||
display: block
|
||||
@@ -115,7 +115,7 @@
|
||||
width: w = 4.2em
|
||||
height: w
|
||||
|
||||
& > img
|
||||
:first-child
|
||||
@extend .imgHover
|
||||
|
||||
.content
|
||||
@@ -291,8 +291,8 @@
|
||||
background: $theme-toc-color
|
||||
color: $toc-active-color
|
||||
|
||||
:only-child
|
||||
> .card-widget
|
||||
.sticky_layout:only-child
|
||||
> :first-child
|
||||
margin-top: 0
|
||||
|
||||
.card-more-btn
|
||||
|
||||
@@ -6,3 +6,12 @@ if hexo-config('chat_btn') == true && hexo-config('chatra.enable')
|
||||
height: 1px !important
|
||||
opacity: 0 !important
|
||||
pointer-events: none
|
||||
|
||||
if hexo-config('chat_btn') == true && hexo-config('messenger.enable')
|
||||
.fb_dialog,
|
||||
.fb-customerchat
|
||||
visibility: hidden !important
|
||||
width: 1px !important
|
||||
height: 1px !important
|
||||
opacity: 0 !important
|
||||
pointer-events: none
|
||||
@@ -1,6 +1,6 @@
|
||||
#footer
|
||||
position: relative
|
||||
background: $light-blue
|
||||
background-color: $light-blue
|
||||
background-attachment: scroll
|
||||
background-position: bottom
|
||||
background-size: cover
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
background: rgba(255, 255, 255, .8)
|
||||
box-shadow: 0 5px 6px -5px rgba(133, 133, 133, .6)
|
||||
|
||||
a
|
||||
a,
|
||||
.site-name
|
||||
color: var(--font-color)
|
||||
text-shadow: none
|
||||
|
||||
@@ -137,8 +138,16 @@
|
||||
box-shadow: 0 5px 6px -5px alpha($grey, .6)
|
||||
transition: transform .2s ease-in-out, opacity .2s ease-in-out
|
||||
|
||||
#blog-info
|
||||
color: var(--font-color)
|
||||
|
||||
&:hover
|
||||
color: $light-blue
|
||||
|
||||
.site-name
|
||||
text-shadow: none
|
||||
|
||||
a,
|
||||
#site-name,
|
||||
#toggle-menu
|
||||
color: var(--font-color)
|
||||
text-shadow: none
|
||||
@@ -146,7 +155,12 @@
|
||||
&:hover
|
||||
color: $light-blue
|
||||
|
||||
&.nav-visible
|
||||
&.fixed
|
||||
#nav
|
||||
top: 0
|
||||
transition: all .5s
|
||||
|
||||
&.nav-visible:not(.fixed)
|
||||
#nav
|
||||
transition: all .5s
|
||||
transform: translate3d(0, 100%, 0)
|
||||
@@ -156,6 +170,19 @@
|
||||
top: 70px
|
||||
transition: top .5s
|
||||
|
||||
&.fixed
|
||||
#nav
|
||||
position: fixed
|
||||
|
||||
& + .layout
|
||||
& > .aside-content > .sticky_layout
|
||||
top: 70px
|
||||
transition: top .5s
|
||||
|
||||
#card-toc
|
||||
.toc-content
|
||||
max-height: calc(100vh - 170px)
|
||||
|
||||
#page
|
||||
h1.page-title
|
||||
margin: 8px 0 20px
|
||||
@@ -253,8 +280,15 @@
|
||||
&.show
|
||||
opacity: 1
|
||||
|
||||
#blog_name
|
||||
#blog-info
|
||||
flex: 1
|
||||
color: var(--light-grey)
|
||||
@extend .limit-one-line
|
||||
|
||||
.site-icon
|
||||
margin-right: 6px
|
||||
height: 36px
|
||||
vertical-align: middle
|
||||
|
||||
#toggle-menu
|
||||
display: none
|
||||
@@ -270,10 +304,9 @@
|
||||
&:hover
|
||||
color: var(--white)
|
||||
|
||||
#site-name
|
||||
.site-name
|
||||
text-shadow: 2px 2px 4px rgba($dark-black, .15)
|
||||
font-weight: bold
|
||||
cursor: pointer
|
||||
|
||||
.menus_items
|
||||
display: inline
|
||||
@@ -301,10 +334,10 @@
|
||||
margin-top: 8px
|
||||
padding: 0
|
||||
width: max-content
|
||||
border-radius: 5px
|
||||
background-color: var(--sidebar-bg)
|
||||
box-shadow: 0 5px 20px -4px rgba($dark-black, .5)
|
||||
animation: sub_menus .3s .1s ease both
|
||||
border-radius: 5px
|
||||
|
||||
&:before
|
||||
position: absolute
|
||||
@@ -321,9 +354,13 @@
|
||||
background: var(--text-bg-hover)
|
||||
|
||||
&:first-child
|
||||
border-radius: 5px 5px 0 0
|
||||
border-top-left-radius: 5px
|
||||
border-top-right-radius: 5px
|
||||
|
||||
&:last-child
|
||||
border-radius: 0 0 5px 5px
|
||||
border-bottom-right-radius: 5px
|
||||
border-bottom-left-radius: 5px
|
||||
|
||||
a
|
||||
display: inline-block
|
||||
padding: 8px 16px
|
||||
@@ -369,4 +406,4 @@
|
||||
|
||||
&:hover
|
||||
&:after
|
||||
width: 100%
|
||||
width: 100%
|
||||
@@ -1,4 +1,4 @@
|
||||
if hexo-config('preloader')
|
||||
if hexo-config('preloader.enable') && hexo-config('preloader.source') == 1
|
||||
.loading-bg
|
||||
position: fixed
|
||||
z-index: 1000
|
||||
|
||||
@@ -102,31 +102,35 @@ beautify()
|
||||
font-family: Monaco, 'Ubuntu Mono', monospace
|
||||
line-height: 1em
|
||||
|
||||
if hexo-config('anchor')
|
||||
if hexo-config('anchor.button.enable')
|
||||
a.headerlink
|
||||
&:after
|
||||
@extend .fontawesomeIcon
|
||||
float: right
|
||||
color: var(--headline-presudo)
|
||||
content: '\f0c1'
|
||||
content: $archor-button-icon
|
||||
font-size: .95em
|
||||
opacity: 0
|
||||
transition: all .3s
|
||||
|
||||
&:hover
|
||||
&:after
|
||||
color: var(--pseudo-hover)
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6
|
||||
&:hover
|
||||
a.headerlink
|
||||
&:after
|
||||
opacity: 1
|
||||
if !hexo-config('anchor.button.always_show')
|
||||
a.headerlink
|
||||
&:after
|
||||
opacity: 0
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6
|
||||
&:hover
|
||||
a.headerlink
|
||||
&:after
|
||||
opacity: 1
|
||||
|
||||
ol,
|
||||
ul
|
||||
@@ -140,15 +144,26 @@ beautify()
|
||||
p
|
||||
margin: 0 0 8px
|
||||
|
||||
> :last-child
|
||||
margin-bottom: 0 !important
|
||||
|
||||
hr
|
||||
margin: 20px 0
|
||||
|
||||
if hexo-config('beautify.enable')
|
||||
if hexo-config('beautify.field') == 'site'
|
||||
beautify()
|
||||
else if hexo-config('beautify.field') == 'post'
|
||||
&.post-content
|
||||
beautify()
|
||||
else
|
||||
hr
|
||||
margin: 20px 0
|
||||
border: 1px inset
|
||||
width 100%
|
||||
|
||||
> :last-child
|
||||
margin-bottom: 0 !important
|
||||
&:before
|
||||
content: none
|
||||
|
||||
#post
|
||||
.tag_share
|
||||
|
||||
@@ -47,3 +47,22 @@
|
||||
+maxWidth900()
|
||||
#hide-aside-btn
|
||||
display: none
|
||||
|
||||
if hexo-config('rightside_scroll_percent')
|
||||
#go-up
|
||||
.scroll-percent
|
||||
display: none
|
||||
|
||||
&.show-percent
|
||||
.scroll-percent
|
||||
display: block
|
||||
|
||||
& + i
|
||||
display: none
|
||||
|
||||
&:hover
|
||||
.scroll-percent
|
||||
display: none
|
||||
|
||||
& + i
|
||||
display: block
|
||||
|
||||
@@ -25,11 +25,8 @@
|
||||
--waline-theme-color: $button-bg
|
||||
--waline-active-color: $button-hover-color
|
||||
|
||||
.vuser
|
||||
transition: all .5s
|
||||
|
||||
&:hover
|
||||
transform: rotate(360deg)
|
||||
.wl-comment-actions > button:not(last-child)
|
||||
padding-right: 4px
|
||||
|
||||
if hexo-config('valine.bg')
|
||||
#vcomment
|
||||
@@ -84,12 +81,16 @@ if hexo-config('waline.bg')
|
||||
&::-webkit-scrollbar
|
||||
display: none
|
||||
|
||||
// mathjax
|
||||
mjx-container[display],
|
||||
.has-jax
|
||||
// Mathjax
|
||||
.mathjax-overflow
|
||||
overflow-x: auto
|
||||
overflow-y: hidden
|
||||
line-height: normal !important
|
||||
|
||||
span.mathjax-overflow
|
||||
display: inline-block
|
||||
padding: 0 2px
|
||||
max-width: 100%
|
||||
vertical-align: bottom
|
||||
|
||||
.aplayer
|
||||
color: $font-black
|
||||
@@ -112,4 +113,16 @@ mjx-container[display],
|
||||
content: none
|
||||
|
||||
.snackbar-css
|
||||
border-radius: 5px !important
|
||||
border-radius: 5px !important
|
||||
|
||||
.abc-music-sheet
|
||||
margin: 0 0 20px
|
||||
opacity: 0
|
||||
transition: opacity .3s
|
||||
|
||||
&.abcjs-container
|
||||
opacity: 1
|
||||
|
||||
+maxWidth768()
|
||||
.fancybox__toolbar__column.is-middle
|
||||
display: none
|
||||
|
||||
@@ -6,7 +6,7 @@ if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
|
||||
--hr-before-color: alpha(#FFFFFF, .7)
|
||||
--search-bg: #121212
|
||||
--search-input-color: alpha(#FFFFFF, .7)
|
||||
--search-result-title: alpha(#FFFFFF, .9)
|
||||
--search-a-color: alpha(#FFFFFF, .7)
|
||||
--preloader-bg: darken(#121212, 2)
|
||||
--preloader-color: alpha(#FFFFFF, .7)
|
||||
--tab-border-color: #2c2c2c
|
||||
|
||||
@@ -106,7 +106,7 @@ if hexo-config('readmode')
|
||||
color: var(--font-color) !important
|
||||
|
||||
.hljs
|
||||
background: var(-highlight-bg) !important
|
||||
background: var(--highlight-bg) !important
|
||||
|
||||
h1,
|
||||
h2,
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
width: 80px
|
||||
height: 80px
|
||||
|
||||
img
|
||||
:first-child
|
||||
@extend .imgHover
|
||||
|
||||
&-info
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
padding: 20px 5px
|
||||
|
||||
+minWidth2000()
|
||||
max-width: 1500px
|
||||
max-width: 1700px
|
||||
|
||||
& > div:first-child:not(.recent-posts)
|
||||
@extend .cardHover
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
height: auto
|
||||
|
||||
&:hover
|
||||
img.post_bg
|
||||
img.post-bg
|
||||
transform: scale(1.1)
|
||||
|
||||
&.ads-wrap
|
||||
@@ -31,7 +31,7 @@
|
||||
width: 100%
|
||||
height: 230px
|
||||
|
||||
img.post_bg
|
||||
.post-bg
|
||||
@extend .imgHover
|
||||
|
||||
&.right
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
@extend .list-beauty
|
||||
|
||||
a
|
||||
color: var(--search-result-title)
|
||||
color: var(--search-a-color)
|
||||
|
||||
&:hover
|
||||
color: $search-color
|
||||
@@ -26,12 +26,15 @@
|
||||
color: $search-keyword-highlight
|
||||
font-weight: bold
|
||||
|
||||
.algolia-hits-item-title
|
||||
font-weight: 600
|
||||
|
||||
.algolia-hit-item-content
|
||||
margin: 0 0 8px
|
||||
word-break: break-all
|
||||
word-break: break-word
|
||||
|
||||
.ais-Pagination
|
||||
margin: 20px 0 0
|
||||
margin: 15px 0 0
|
||||
padding: 0
|
||||
text-align: center
|
||||
|
||||
@@ -61,20 +64,16 @@
|
||||
.ais-Pagination-item--disabled
|
||||
visibility: hidden
|
||||
|
||||
.algolia-logo
|
||||
padding-top: 2px
|
||||
width: 80px
|
||||
height: 30px
|
||||
|
||||
#algolia-hits
|
||||
> div
|
||||
overflow-y: scroll
|
||||
|
||||
+minWidth768()
|
||||
max-height: calc(80vh - 240px)
|
||||
margin: 0 -20px
|
||||
padding: 0 22px
|
||||
max-height: calc(80vh - 240px)
|
||||
|
||||
+maxWidth768()
|
||||
height: calc(100vh - 260px)
|
||||
max-height: none
|
||||
height: calc(var(--search-height) - 265px)
|
||||
|
||||
#algolia-info
|
||||
div
|
||||
@@ -82,10 +81,7 @@
|
||||
|
||||
.algolia-poweredBy
|
||||
float: right
|
||||
vertical-align: text-top
|
||||
|
||||
.apple
|
||||
#algolia-search
|
||||
#algolia-hits
|
||||
> div
|
||||
+maxWidth768()
|
||||
height: calc(90vh - 260px)
|
||||
svg
|
||||
height: 1.1em
|
||||
@@ -9,6 +9,7 @@
|
||||
width: 600px
|
||||
border-radius: 8px
|
||||
background: var(--search-bg)
|
||||
--search-height: 100vh
|
||||
|
||||
+maxWidth768()
|
||||
top: 0
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
.search-wrap
|
||||
display: none
|
||||
|
||||
.local-search__hit-item
|
||||
.local-search-hit-item
|
||||
position: relative
|
||||
padding-left: 24px
|
||||
line-height: 1.7
|
||||
@@ -43,25 +43,32 @@
|
||||
|
||||
a
|
||||
display: block
|
||||
color: var(--search-result-title)
|
||||
font-weight: 600
|
||||
cursor: pointer
|
||||
color: var(--search-a-color)
|
||||
|
||||
&:hover
|
||||
color: $search-color
|
||||
|
||||
.search-result
|
||||
margin: 0 8px 8px 0
|
||||
word-break: break-all
|
||||
.search-result-title
|
||||
font-weight: 600
|
||||
|
||||
.search-keyword
|
||||
color: $search-keyword-highlight
|
||||
font-weight: bold
|
||||
.search-result
|
||||
margin: 0 0 8px
|
||||
word-break: break-word
|
||||
|
||||
.search-result-list
|
||||
overflow-y: auto
|
||||
max-height: calc(80vh - 130px)
|
||||
overflow-y: overlay
|
||||
margin: 0 -20px
|
||||
padding: 0 22px
|
||||
max-height: calc(80vh - 200px)
|
||||
|
||||
+maxWidth768()
|
||||
padding-bottom: 40px
|
||||
max-height: 75vh !important
|
||||
max-height: calc(var(--search-height) - 220px) !important
|
||||
|
||||
.no-result
|
||||
& + #local-search-stats-wrap
|
||||
display: none
|
||||
|
||||
.search-keyword
|
||||
background: transparent
|
||||
color: $search-keyword-highlight
|
||||
font-weight: bold
|
||||
@@ -94,9 +94,46 @@
|
||||
overflow: auto
|
||||
padding: 0 0 16px
|
||||
|
||||
.fj-gallery
|
||||
.gallery
|
||||
margin: 0 0 16px
|
||||
opacity: 0
|
||||
text-align: center
|
||||
|
||||
.img-alt
|
||||
display: none
|
||||
.fj-gallery
|
||||
opacity: 0
|
||||
|
||||
.img-alt
|
||||
display: none
|
||||
|
||||
&.lazyload
|
||||
+ button
|
||||
display: inline-block
|
||||
|
||||
.gallery-data
|
||||
display: none
|
||||
|
||||
button
|
||||
display: none
|
||||
margin-top: 25px
|
||||
padding: 10px
|
||||
width: 9em
|
||||
border-radius: 5px
|
||||
background: var(--btn-bg)
|
||||
color: var(--btn-color)
|
||||
font-weight: bold
|
||||
font-size: 1.1em
|
||||
transition: all .3s
|
||||
|
||||
& > *
|
||||
transition: all .4s
|
||||
|
||||
i
|
||||
width: 0
|
||||
opacity: 0
|
||||
|
||||
&:hover
|
||||
background: var(--btn-hover-color)
|
||||
|
||||
i
|
||||
margin-left: 2px
|
||||
width: 20px
|
||||
opacity: 1
|
||||
|
||||
@@ -71,7 +71,7 @@ $button-hover-color = $themeColorEnable && hexo-config('theme_color.button_hover
|
||||
$button-bg = $theme-color
|
||||
$pseudo-hover = $button-hover-color
|
||||
// scrollbar
|
||||
$scrollbar-color= $themeColorEnable && hexo-config('theme_color.scrollbar_color') ? convert(hexo-config('theme_color.scrollbar_color')) : $theme-color
|
||||
$scrollbar-color = $themeColorEnable && hexo-config('theme_color.scrollbar_color') ? convert(hexo-config('theme_color.scrollbar_color')) : $theme-color
|
||||
// table
|
||||
$table-thead-bg = #99a9bf
|
||||
// reward
|
||||
@@ -82,7 +82,7 @@ $search-bg = #f6f8fa
|
||||
$search-input-color = $font-black
|
||||
$search-color = $theme-color
|
||||
$search-keyword-highlight = #F47466
|
||||
$search-result-title = $font-black
|
||||
$search-a-color = $font-black
|
||||
// comments
|
||||
$comments-switch-first-text = $bright-blue
|
||||
$comments-switch-second-text = $light-orange
|
||||
@@ -180,4 +180,6 @@ $tab-active-border-color = $theme-color
|
||||
$tab-button-active-bg = $card-bg
|
||||
$tab-to-top-color = #99a9bf
|
||||
// Tag Plugins - timeline
|
||||
$timeline-default-color = $theme-color
|
||||
$timeline-default-color = $theme-color
|
||||
// archor
|
||||
$archor-button-icon = hexo-config('anchor.button.icon') ? hexo-config('anchor.button.icon') : '\f0c1'
|
||||
@@ -1,21 +1,24 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
let blogNameWidth, menusWidth, searchWidth, $nav
|
||||
let headerContentWidth, $nav
|
||||
let mobileSidebarOpen = false
|
||||
|
||||
const adjustMenu = (init) => {
|
||||
const adjustMenu = init => {
|
||||
const getAllWidth = ele => {
|
||||
let width = 0
|
||||
ele.length && Array.from(ele).forEach(i => { width += i.offsetWidth })
|
||||
return width
|
||||
}
|
||||
|
||||
if (init) {
|
||||
blogNameWidth = document.getElementById('site-name').offsetWidth
|
||||
const $menusEle = document.querySelectorAll('#menus .menus_item')
|
||||
menusWidth = 0
|
||||
$menusEle.length && $menusEle.forEach(i => { menusWidth += i.offsetWidth })
|
||||
const $searchEle = document.querySelector('#search-button')
|
||||
searchWidth = $searchEle ? $searchEle.offsetWidth : 0
|
||||
const blogInfoWidth = getAllWidth(document.querySelector('#blog-info > a').children)
|
||||
const menusWidth = getAllWidth(document.getElementById('menus').children)
|
||||
headerContentWidth = blogInfoWidth + menusWidth
|
||||
$nav = document.getElementById('nav')
|
||||
}
|
||||
|
||||
let hideMenuIndex = ''
|
||||
if (window.innerWidth < 768) hideMenuIndex = true
|
||||
else hideMenuIndex = blogNameWidth + menusWidth + searchWidth > $nav.offsetWidth - 120
|
||||
if (window.innerWidth <= 768) hideMenuIndex = true
|
||||
else hideMenuIndex = headerContentWidth > $nav.offsetWidth - 120
|
||||
|
||||
if (hideMenuIndex) {
|
||||
$nav.classList.add('hide-menu')
|
||||
@@ -229,26 +232,79 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
* justified-gallery 圖庫排版
|
||||
*/
|
||||
const runJustifiedGallery = function (ele) {
|
||||
ele.forEach(item => {
|
||||
const $imgList = item.querySelectorAll('img')
|
||||
|
||||
$imgList.forEach(i => {
|
||||
const dataLazySrc = i.getAttribute('data-lazy-src')
|
||||
if (dataLazySrc) i.src = dataLazySrc
|
||||
btf.wrap(i, 'div', { class: 'fj-gallery-item' })
|
||||
const htmlStr = arr => {
|
||||
let str = ''
|
||||
const replaceDq = str => str.replace(/"/g, '"') // replace double quotes to "
|
||||
arr.forEach(i => {
|
||||
const alt = i.alt ? `alt="${replaceDq(i.alt)}"` : ''
|
||||
const title = i.title ? `title="${replaceDq(i.title)}"` : ''
|
||||
str += `<div class="fj-gallery-item"><img src="${i.url}" ${alt + title}"></div>`
|
||||
})
|
||||
})
|
||||
return str
|
||||
}
|
||||
|
||||
const lazyloadFn = (i, arr, limit) => {
|
||||
const loadItem = limit
|
||||
const arrLength = arr.length
|
||||
if (arrLength > loadItem) i.insertAdjacentHTML('beforeend', htmlStr(arr.splice(0, loadItem)))
|
||||
else {
|
||||
i.insertAdjacentHTML('beforeend', htmlStr(arr))
|
||||
i.classList.remove('lazyload')
|
||||
}
|
||||
return arrLength > loadItem ? loadItem : arrLength
|
||||
}
|
||||
|
||||
const fetchUrl = async (url) => {
|
||||
const response = await fetch(url)
|
||||
return await response.json()
|
||||
}
|
||||
|
||||
const runJustifiedGallery = (item, arr) => {
|
||||
if (!item.classList.contains('lazyload')) item.innerHTML = htmlStr(arr)
|
||||
else {
|
||||
const limit = item.getAttribute('data-limit')
|
||||
lazyloadFn(item, arr, limit)
|
||||
const clickBtnFn = () => {
|
||||
const lastItemLength = lazyloadFn(item, arr, limit)
|
||||
fjGallery(item, 'appendImages', item.querySelectorAll(`.fj-gallery-item:nth-last-child(-n+${lastItemLength})`))
|
||||
btf.loadLightbox(item.querySelectorAll('img'))
|
||||
lastItemLength < limit && item.nextElementSibling.removeEventListener('click', clickBtnFn)
|
||||
}
|
||||
item.nextElementSibling.addEventListener('click', clickBtnFn)
|
||||
}
|
||||
btf.initJustifiedGallery(item)
|
||||
btf.loadLightbox(item.querySelectorAll('img'))
|
||||
}
|
||||
|
||||
const addJustifiedGallery = () => {
|
||||
ele.forEach(item => {
|
||||
item.classList.contains('url')
|
||||
? fetchUrl(item.textContent).then(res => { runJustifiedGallery(item, res) })
|
||||
: runJustifiedGallery(item, JSON.parse(item.textContent))
|
||||
})
|
||||
}
|
||||
|
||||
if (window.fjGallery) {
|
||||
setTimeout(() => { btf.initJustifiedGallery(ele) }, 100)
|
||||
addJustifiedGallery()
|
||||
return
|
||||
}
|
||||
|
||||
const newEle = document.createElement('link')
|
||||
newEle.rel = 'stylesheet'
|
||||
newEle.href = GLOBAL_CONFIG.source.justifiedGallery.css
|
||||
document.body.appendChild(newEle)
|
||||
getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`).then(() => { btf.initJustifiedGallery(ele) })
|
||||
getCSS(`${GLOBAL_CONFIG.source.justifiedGallery.css}`)
|
||||
getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`).then(addJustifiedGallery)
|
||||
}
|
||||
|
||||
/**
|
||||
* rightside scroll percent
|
||||
*/
|
||||
const rightsideScrollPercent = currentTop => {
|
||||
const perNum = btf.getScrollPercent(currentTop, document.body)
|
||||
const $goUp = document.getElementById('go-up')
|
||||
if (perNum < 95) {
|
||||
$goUp.classList.add('show-percent')
|
||||
$goUp.querySelector('.scroll-percent').textContent = perNum
|
||||
} else {
|
||||
$goUp.classList.remove('show-percent')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,41 +332,44 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
const $header = document.getElementById('page-header')
|
||||
const isChatBtnHide = typeof chatBtnHide === 'function'
|
||||
const isChatBtnShow = typeof chatBtnShow === 'function'
|
||||
const isShowPercent = GLOBAL_CONFIG.percent.rightside
|
||||
|
||||
window.scrollCollect = () => {
|
||||
return btf.throttle(function (e) {
|
||||
const currentTop = window.scrollY || document.documentElement.scrollTop
|
||||
const isDown = scrollDirection(currentTop)
|
||||
if (currentTop > 56) {
|
||||
if (isDown) {
|
||||
if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible')
|
||||
if (isChatBtnShow && isChatShow === true) {
|
||||
chatBtnHide()
|
||||
isChatShow = false
|
||||
}
|
||||
} else {
|
||||
if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible')
|
||||
if (isChatBtnHide && isChatShow === false) {
|
||||
chatBtnShow()
|
||||
isChatShow = true
|
||||
}
|
||||
}
|
||||
$header.classList.add('nav-fixed')
|
||||
if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') {
|
||||
$rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)'
|
||||
const scrollTask = btf.throttle(() => {
|
||||
const currentTop = window.scrollY || document.documentElement.scrollTop
|
||||
const isDown = scrollDirection(currentTop)
|
||||
if (currentTop > 56) {
|
||||
if (isDown) {
|
||||
if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible')
|
||||
if (isChatBtnShow && isChatShow === true) {
|
||||
chatBtnHide()
|
||||
isChatShow = false
|
||||
}
|
||||
} else {
|
||||
if (currentTop === 0) {
|
||||
$header.classList.remove('nav-fixed', 'nav-visible')
|
||||
if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible')
|
||||
if (isChatBtnHide && isChatShow === false) {
|
||||
chatBtnShow()
|
||||
isChatShow = true
|
||||
}
|
||||
$rightside.style.cssText = "opacity: ''; transform: ''"
|
||||
}
|
||||
|
||||
if (document.body.scrollHeight <= innerHeight) {
|
||||
$header.classList.add('nav-fixed')
|
||||
if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') {
|
||||
$rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)'
|
||||
}
|
||||
}, 200)()
|
||||
}
|
||||
} else {
|
||||
if (currentTop === 0) {
|
||||
$header.classList.remove('nav-fixed', 'nav-visible')
|
||||
}
|
||||
$rightside.style.cssText = "opacity: ''; transform: ''"
|
||||
}
|
||||
|
||||
isShowPercent && rightsideScrollPercent(currentTop)
|
||||
|
||||
if (document.body.scrollHeight <= innerHeight) {
|
||||
$rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)'
|
||||
}
|
||||
}, 200)
|
||||
|
||||
window.scrollCollect = scrollTask
|
||||
|
||||
window.addEventListener('scroll', scrollCollect)
|
||||
}
|
||||
@@ -325,26 +384,15 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
if (!($article && (isToc || isAnchor))) return
|
||||
|
||||
let $tocLink, $cardToc, scrollPercent, autoScrollToc, isExpand
|
||||
let $tocLink, $cardToc, autoScrollToc, $tocPercentage, isExpand
|
||||
|
||||
if (isToc) {
|
||||
const $cardTocLayout = document.getElementById('card-toc')
|
||||
$cardToc = $cardTocLayout.getElementsByClassName('toc-content')[0]
|
||||
$tocLink = $cardToc.querySelectorAll('.toc-link')
|
||||
const $tocPercentage = $cardTocLayout.querySelector('.toc-percentage')
|
||||
$tocPercentage = $cardTocLayout.querySelector('.toc-percentage')
|
||||
isExpand = $cardToc.classList.contains('is-expand')
|
||||
|
||||
scrollPercent = currentTop => {
|
||||
const docHeight = $article.clientHeight
|
||||
const winHeight = document.documentElement.clientHeight
|
||||
const headerHeight = $article.offsetTop
|
||||
const contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : (document.documentElement.scrollHeight - winHeight)
|
||||
const scrollPercent = (currentTop - headerHeight) / (contentMath)
|
||||
const scrollPercentRounded = Math.round(scrollPercent * 100)
|
||||
const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded
|
||||
$tocPercentage.textContent = percentage
|
||||
}
|
||||
|
||||
window.mobileToc = {
|
||||
open: () => {
|
||||
$cardTocLayout.style.cssText = 'animation: toc-open .3s; opacity: 1; right: 55px'
|
||||
@@ -433,13 +481,14 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
}
|
||||
|
||||
// main of scroll
|
||||
window.tocScrollFn = function () {
|
||||
return btf.throttle(function () {
|
||||
const currentTop = window.scrollY || document.documentElement.scrollTop
|
||||
isToc && scrollPercent(currentTop)
|
||||
findHeadPosition(currentTop)
|
||||
}, 100)()
|
||||
}
|
||||
window.tocScrollFn = btf.throttle(() => {
|
||||
const currentTop = window.scrollY || document.documentElement.scrollTop
|
||||
if (isToc && GLOBAL_CONFIG.percent.toc) {
|
||||
$tocPercentage.textContent = btf.getScrollPercent(currentTop, $article)
|
||||
}
|
||||
findHeadPosition(currentTop)
|
||||
}, 100)
|
||||
|
||||
window.addEventListener('scroll', tocScrollFn)
|
||||
}
|
||||
|
||||
@@ -477,7 +526,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
// handle some cases
|
||||
typeof utterancesTheme === 'function' && utterancesTheme()
|
||||
typeof changeGiscusTheme === 'function' && changeGiscusTheme()
|
||||
typeof FB === 'object' && window.loadFBComment()
|
||||
typeof FB === 'object' && window.loadFBComment && window.loadFBComment()
|
||||
typeof runMermaid === 'function' && window.runMermaid()
|
||||
},
|
||||
showOrHideBtn: (e) => { // rightside 點擊設置 按鈕 展開
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
window.addEventListener('load', () => {
|
||||
const $searchMask = document.getElementById('search-mask')
|
||||
const $searchDialog = document.querySelector('#algolia-search .search-dialog')
|
||||
|
||||
const openSearch = () => {
|
||||
const bodyStyle = document.body.style
|
||||
bodyStyle.width = '100%'
|
||||
bodyStyle.overflow = 'hidden'
|
||||
btf.animateIn(document.getElementById('search-mask'), 'to_show 0.5s')
|
||||
btf.animateIn(document.querySelector('#algolia-search .search-dialog'), 'titleScale 0.5s')
|
||||
btf.animateIn($searchMask, 'to_show 0.5s')
|
||||
btf.animateIn($searchDialog, 'titleScale 0.5s')
|
||||
setTimeout(() => { document.querySelector('#algolia-search .ais-SearchBox-input').focus() }, 100)
|
||||
|
||||
// shortcut: ESC
|
||||
@@ -14,22 +17,33 @@ window.addEventListener('load', () => {
|
||||
document.removeEventListener('keydown', f)
|
||||
}
|
||||
})
|
||||
|
||||
fixSafariHeight()
|
||||
window.addEventListener('resize', fixSafariHeight)
|
||||
}
|
||||
|
||||
const closeSearch = () => {
|
||||
const bodyStyle = document.body.style
|
||||
bodyStyle.width = ''
|
||||
bodyStyle.overflow = ''
|
||||
btf.animateOut(document.querySelector('#algolia-search .search-dialog'), 'search_close .5s')
|
||||
btf.animateOut(document.getElementById('search-mask'), 'to_hide 0.5s')
|
||||
btf.animateOut($searchDialog, 'search_close .5s')
|
||||
btf.animateOut($searchMask, 'to_hide 0.5s')
|
||||
window.removeEventListener('resize', fixSafariHeight)
|
||||
}
|
||||
|
||||
// fix safari
|
||||
const fixSafariHeight = () => {
|
||||
if (window.innerWidth < 768) {
|
||||
$searchDialog.style.setProperty('--search-height', window.innerHeight + 'px')
|
||||
}
|
||||
}
|
||||
|
||||
const searchClickFn = () => {
|
||||
document.querySelector('#search-button > .search').addEventListener('click', openSearch)
|
||||
}
|
||||
|
||||
const searchClickFnOnce = () => {
|
||||
document.getElementById('search-mask').addEventListener('click', closeSearch)
|
||||
const searchFnOnce = () => {
|
||||
$searchMask.addEventListener('click', closeSearch)
|
||||
document.querySelector('#algolia-search .search-close-button').addEventListener('click', closeSearch)
|
||||
}
|
||||
|
||||
@@ -56,7 +70,7 @@ window.addEventListener('load', () => {
|
||||
post = '...'
|
||||
}
|
||||
|
||||
let matchContent = pre + content.substring(start, end) + post
|
||||
const matchContent = pre + content.substring(start, end) + post
|
||||
return matchContent
|
||||
}
|
||||
|
||||
@@ -68,10 +82,11 @@ window.addEventListener('load', () => {
|
||||
|
||||
const search = instantsearch({
|
||||
indexName: algolia.indexName,
|
||||
/* global algoliasearch */
|
||||
searchClient: algoliasearch(algolia.appId, algolia.apiKey),
|
||||
searchFunction(helper) {
|
||||
searchFunction (helper) {
|
||||
helper.state.query && helper.search()
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const configure = instantsearch.widgets.configure({
|
||||
@@ -89,21 +104,21 @@ window.addEventListener('load', () => {
|
||||
const hits = instantsearch.widgets.hits({
|
||||
container: '#algolia-hits',
|
||||
templates: {
|
||||
item(data) {
|
||||
item (data) {
|
||||
const link = data.permalink ? data.permalink : (GLOBAL_CONFIG.root + data.path)
|
||||
const result = data._highlightResult
|
||||
const content = result.contentStripTruncate
|
||||
? cutContent(result.contentStripTruncate.value)
|
||||
: result.contentStrip
|
||||
? cutContent(result.contentStrip.value)
|
||||
: result.content
|
||||
? cutContent(result.content.value)
|
||||
: ''
|
||||
? cutContent(result.contentStripTruncate.value)
|
||||
: result.contentStrip
|
||||
? cutContent(result.contentStrip.value)
|
||||
: result.content
|
||||
? cutContent(result.content.value)
|
||||
: ''
|
||||
return `
|
||||
<a href="${link}" class="algolia-hit-item-link">
|
||||
${result.title.value || 'no-title'}
|
||||
</a>
|
||||
<p class="algolia-hit-item-content">${content}</p>`
|
||||
<span class="algolia-hits-item-title">${result.title.value || 'no-title'}</span>
|
||||
<p class="algolia-hit-item-content">${content}</p>
|
||||
</a>`
|
||||
},
|
||||
empty: function (data) {
|
||||
return (
|
||||
@@ -130,7 +145,7 @@ window.addEventListener('load', () => {
|
||||
})
|
||||
|
||||
const powerBy = instantsearch.widgets.poweredBy({
|
||||
container: '#algolia-info > .algolia-poweredBy',
|
||||
container: '#algolia-info > .algolia-poweredBy'
|
||||
})
|
||||
|
||||
const pagination = instantsearch.widgets.pagination({
|
||||
@@ -144,16 +159,15 @@ window.addEventListener('load', () => {
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
search.addWidgets([configure,searchBox,hits,stats,powerBy,pagination]) // add the widgets to the instantsearch instance
|
||||
search.addWidgets([configure, searchBox, hits, stats, powerBy, pagination]) // add the widgets to the instantsearch instance
|
||||
|
||||
search.start()
|
||||
|
||||
searchClickFn()
|
||||
searchClickFnOnce()
|
||||
searchFnOnce()
|
||||
|
||||
window.addEventListener('pjax:complete', () => {
|
||||
getComputedStyle(document.querySelector('#algolia-search .search-dialog')).display === 'block' && closeSearch()
|
||||
!btf.isHidden($searchMask) && closeSearch()
|
||||
searchClickFn()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,17 +1,311 @@
|
||||
/**
|
||||
* Refer to hexo-generator-searchdb
|
||||
* https://github.com/next-theme/hexo-generator-searchdb/blob/main/dist/search.js
|
||||
* Modified by hexo-theme-butterfly
|
||||
*/
|
||||
|
||||
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 120 characters. The maxlength of .search-input is 80.
|
||||
const start = Math.max(0, position - 20)
|
||||
const end = Math.min(content.length, position + 100)
|
||||
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 += `<div class="local-search-hit-item"><a href="${url.href}"><span class="search-result-title">${this.highlightKeyword(title, slicesOfTitle[0])}</span>`
|
||||
} else {
|
||||
resultItem += `<div class="local-search-hit-item"><a href="${url.href}"><span class="search-result-title">${title}</span>`
|
||||
}
|
||||
|
||||
slicesOfContent.forEach(slice => {
|
||||
resultItem += `<p class="search-result">${this.highlightKeyword(content, slice)}...</p></a>`
|
||||
})
|
||||
|
||||
resultItem += '</div>'
|
||||
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, .mermaid')) 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')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
// Search
|
||||
const { path, top_n_per_article, unescape, languages } = GLOBAL_CONFIG.localSearch
|
||||
const localSearch = new LocalSearch({
|
||||
path,
|
||||
top_n_per_article,
|
||||
unescape
|
||||
})
|
||||
|
||||
const input = document.querySelector('#local-search-input input')
|
||||
const statsItem = document.getElementById('local-search-stats-wrap')
|
||||
const $loadingStatus = document.getElementById('loading-status')
|
||||
|
||||
const inputEventFunction = () => {
|
||||
if (!localSearch.isfetched) return
|
||||
const searchText = input.value.trim().toLowerCase()
|
||||
if (searchText !== '') $loadingStatus.innerHTML = '<i class="fas fa-spinner fa-pulse"></i>'
|
||||
const keywords = searchText.split(/[-\s]+/)
|
||||
const container = document.getElementById('local-search-results')
|
||||
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.textContent = ''
|
||||
} else if (resultItems.length === 0) {
|
||||
container.textContent = ''
|
||||
statsItem.innerHTML = `<div class="search-result-stats">${languages.hits_empty.replace(/\$\{query}/, searchText)}</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 = languages.hits_stats.replace(/\$\{hits}/, resultItems.length)
|
||||
|
||||
container.classList.remove('no-result')
|
||||
container.innerHTML = `<div class="search-result-list">${resultItems.map(result => result.item).join('')}</div>`
|
||||
statsItem.innerHTML = `<hr><div class="search-result-stats">${stats}</div>`
|
||||
window.pjax && window.pjax.refresh(container)
|
||||
}
|
||||
|
||||
$loadingStatus.innerHTML = ''
|
||||
}
|
||||
|
||||
let loadFlag = false
|
||||
let dataObj = []
|
||||
const $searchMask = document.getElementById('search-mask')
|
||||
const $searchDialog = document.querySelector('#local-search .search-dialog')
|
||||
|
||||
// fix safari
|
||||
const fixSafariHeight = () => {
|
||||
if (window.innerWidth < 768) {
|
||||
$searchDialog.style.setProperty('--search-height', window.innerHeight + 'px')
|
||||
}
|
||||
}
|
||||
|
||||
const openSearch = () => {
|
||||
const bodyStyle = document.body.style
|
||||
bodyStyle.width = '100%'
|
||||
bodyStyle.overflow = 'hidden'
|
||||
btf.animateIn($searchMask, 'to_show 0.5s')
|
||||
btf.animateIn(document.querySelector('#local-search .search-dialog'), 'titleScale 0.5s')
|
||||
setTimeout(() => { document.querySelector('#local-search-input input').focus() }, 100)
|
||||
btf.animateIn($searchDialog, 'titleScale 0.5s')
|
||||
setTimeout(() => { input.focus() }, 300)
|
||||
if (!loadFlag) {
|
||||
search()
|
||||
!localSearch.isfetched && localSearch.fetchData()
|
||||
input.addEventListener('input', inputEventFunction)
|
||||
loadFlag = true
|
||||
}
|
||||
// shortcut: ESC
|
||||
@@ -21,168 +315,46 @@ window.addEventListener('load', () => {
|
||||
document.removeEventListener('keydown', f)
|
||||
}
|
||||
})
|
||||
|
||||
fixSafariHeight()
|
||||
window.addEventListener('resize', fixSafariHeight)
|
||||
}
|
||||
|
||||
const closeSearch = () => {
|
||||
const bodyStyle = document.body.style
|
||||
bodyStyle.width = ''
|
||||
bodyStyle.overflow = ''
|
||||
btf.animateOut(document.querySelector('#local-search .search-dialog'), 'search_close .5s')
|
||||
btf.animateOut($searchDialog, 'search_close .5s')
|
||||
btf.animateOut($searchMask, 'to_hide 0.5s')
|
||||
window.removeEventListener('resize', fixSafariHeight)
|
||||
}
|
||||
|
||||
const searchClickFn = () => {
|
||||
document.querySelector('#search-button > .search').addEventListener('click', openSearch)
|
||||
}
|
||||
|
||||
const searchClickFnOnce = () => {
|
||||
const searchFnOnce = () => {
|
||||
document.querySelector('#local-search .search-close-button').addEventListener('click', closeSearch)
|
||||
$searchMask.addEventListener('click', closeSearch)
|
||||
if (GLOBAL_CONFIG.localSearch.preload) dataObj = fetchData(GLOBAL_CONFIG.localSearch.path)
|
||||
}
|
||||
|
||||
// check url is json or not
|
||||
const isJson = url => {
|
||||
const reg = /\.json$/
|
||||
return reg.test(url)
|
||||
}
|
||||
|
||||
const fetchData = async (path) => {
|
||||
let data = []
|
||||
const response = await fetch(path)
|
||||
if (isJson(path)) {
|
||||
data = await response.json()
|
||||
} else {
|
||||
const res = await response.text()
|
||||
const t = await new window.DOMParser().parseFromString(res, 'text/xml')
|
||||
const a = await t
|
||||
data = [...a.querySelectorAll('entry')].map(item =>{
|
||||
return {
|
||||
title: item.querySelector('title').textContent,
|
||||
content: item.querySelector('content') && item.querySelector('content').textContent,
|
||||
url: item.querySelector('url').textContent
|
||||
}
|
||||
})
|
||||
if (GLOBAL_CONFIG.localSearch.preload) {
|
||||
localSearch.fetchData()
|
||||
}
|
||||
if (response.ok) {
|
||||
const $loadDataItem = document.getElementById('loading-database')
|
||||
$loadDataItem.nextElementSibling.style.display = 'block'
|
||||
$loadDataItem.remove()
|
||||
}
|
||||
return data
|
||||
localSearch.highlightSearchWords(document.getElementById('article-container'))
|
||||
}
|
||||
|
||||
const search = () => {
|
||||
if (!GLOBAL_CONFIG.localSearch.preload) {
|
||||
dataObj = fetchData(GLOBAL_CONFIG.localSearch.path)
|
||||
}
|
||||
|
||||
const $input = document.querySelector('#local-search-input input')
|
||||
const $resultContent = document.getElementById('local-search-results')
|
||||
const $loadingStatus = document.getElementById('loading-status')
|
||||
|
||||
$input.addEventListener('input', function () {
|
||||
const keywords = this.value.trim().toLowerCase().split(/[\s]+/)
|
||||
if (keywords[0] !== '') $loadingStatus.innerHTML = '<i class="fas fa-spinner fa-pulse"></i>'
|
||||
|
||||
$resultContent.innerHTML = ''
|
||||
let str = '<div class="search-result-list">'
|
||||
if (keywords.length <= 0) return
|
||||
let count = 0
|
||||
// perform local searching
|
||||
dataObj.then(data => {
|
||||
data.forEach(data => {
|
||||
let isMatch = true
|
||||
let dataTitle = data.title ? data.title.trim().toLowerCase() : ''
|
||||
const dataContent = data.content ? data.content.trim().replace(/<[^>]+>/g, '').toLowerCase() : ''
|
||||
const dataUrl = data.url.startsWith('/') ? data.url : GLOBAL_CONFIG.root + data.url
|
||||
let indexTitle = -1
|
||||
let indexContent = -1
|
||||
let firstOccur = -1
|
||||
// only match articles with not empty titles and contents
|
||||
if (dataTitle !== '' || dataContent !== '') {
|
||||
keywords.forEach((keyword, i) => {
|
||||
indexTitle = dataTitle.indexOf(keyword)
|
||||
indexContent = dataContent.indexOf(keyword)
|
||||
if (indexTitle < 0 && indexContent < 0) {
|
||||
isMatch = false
|
||||
} else {
|
||||
if (indexContent < 0) {
|
||||
indexContent = 0
|
||||
}
|
||||
if (i === 0) {
|
||||
firstOccur = indexContent
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
isMatch = false
|
||||
}
|
||||
|
||||
// show search results
|
||||
if (isMatch) {
|
||||
if (firstOccur >= 0) {
|
||||
// cut out 130 characters
|
||||
// let start = firstOccur - 30 < 0 ? 0 : firstOccur - 30
|
||||
// let end = firstOccur + 50 > dataContent.length ? dataContent.length : firstOccur + 50
|
||||
let start = firstOccur - 30
|
||||
let end = firstOccur + 100
|
||||
let pre = ''
|
||||
let post = ''
|
||||
|
||||
if (start < 0) {
|
||||
start = 0
|
||||
}
|
||||
|
||||
if (start === 0) {
|
||||
end = 100
|
||||
} else {
|
||||
pre = '...'
|
||||
}
|
||||
|
||||
if (end > dataContent.length) {
|
||||
end = dataContent.length
|
||||
} else {
|
||||
post = '...'
|
||||
}
|
||||
|
||||
let matchContent = dataContent.substring(start, end)
|
||||
|
||||
// highlight all keywords
|
||||
keywords.forEach(keyword => {
|
||||
const regS = new RegExp(keyword, 'gi')
|
||||
matchContent = matchContent.replace(regS, '<span class="search-keyword">' + keyword + '</span>')
|
||||
dataTitle = dataTitle.replace(regS, '<span class="search-keyword">' + keyword + '</span>')
|
||||
})
|
||||
|
||||
str += '<div class="local-search__hit-item"><a href="' + dataUrl + '" class="search-result-title">' + dataTitle + '</a>'
|
||||
count += 1
|
||||
|
||||
if (dataContent !== '') {
|
||||
str += '<p class="search-result">' + pre + matchContent + post + '</p>'
|
||||
}
|
||||
}
|
||||
str += '</div>'
|
||||
}
|
||||
})
|
||||
if (count === 0) {
|
||||
str += '<div id="local-search__hits-empty">' + GLOBAL_CONFIG.localSearch.languages.hits_empty.replace(/\$\{query}/, this.value.trim()) +
|
||||
'</div>'
|
||||
}
|
||||
str += '</div>'
|
||||
$resultContent.innerHTML = str
|
||||
if (keywords[0] !== '') $loadingStatus.innerHTML = ''
|
||||
window.pjax && window.pjax.refresh($resultContent)
|
||||
})
|
||||
})
|
||||
}
|
||||
window.addEventListener('search:loaded', () => {
|
||||
const $loadDataItem = document.getElementById('loading-database')
|
||||
$loadDataItem.nextElementSibling.style.display = 'block'
|
||||
$loadDataItem.remove()
|
||||
})
|
||||
|
||||
searchClickFn()
|
||||
searchClickFnOnce()
|
||||
searchFnOnce()
|
||||
|
||||
// pjax
|
||||
window.addEventListener('pjax:complete', () => {
|
||||
!btf.isHidden($searchMask) && closeSearch()
|
||||
localSearch.highlightSearchWords(document.getElementById('article-container'))
|
||||
searchClickFn()
|
||||
})
|
||||
})
|
||||
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user