由於整合了多個設定並更改了部分設定名稱,升級到 5.0 版本時,請重新設定 _config.yml 文件。

1. 新增 macstyle 設定,取消 mac / mac light 主題設定
2. 整合搜索相關設定
3. 修改程式碼區塊設定
4. 主頁文章新增多種版面配置
5. 新增說說頁面
6. 適配 hexo-blog-encrypt 加密插件
7. 改善手機端目錄的開啟效果
8. 新增平滑滾動功能
9. 支持以程式碼區塊方式撰寫 mermaid 圖表
10. 可自訂文章標題位置
11. 新增程式碼全螢幕按鈕
12. 友情連結頭像改為圓角設計
13. 優化程式碼,使用 hexo-util 的參數和 hexo 內建參數
14. 可自訂搜索框提示文字
15. 未設定選單時,不顯示側邊欄目錄和按鈕
16. 螢幕寬度超過 2000px 時,增加卡片高度
17. 根據語言設定調整字體:簡體中文使用雅黑,其他使用正黑體
18. 更新 plugins.yml
19. 全新的側邊欄界面設計
20. 新增 giscus 的 js 設定
21. 調整 utterances js 的設定位置
22. 新增 utterances option 設定
23. 修改 giscus 的主題設定
24. 多個界面元素改為圓角設計
25. 可選擇圓角或直角界面風格
26. 圖庫加載按鈕新增圖標
27. 改善標籤頁面的滑鼠懸停效果
28. 調整側邊欄的滑鼠懸停效果
29. 微調部分界面元素

1. 修復 Hexo 新版本下 Prism.js 無法正確高亮的問題
2. 修復文章標籤為空時可能出現的錯誤
3. 修正 mermaid 圖表可能出現的錯誤
4. 解決未設定選單時控制台報錯的問題
5. 修復 Algolia 搜索的每頁顯示數量設定無效的問題
6. 解決 Algolia 搜索結果出現滾動條的問題
7. 修正滾動條出現上下按鈕的問題
8. 修復圖庫遠程連結未加前綴的問題
9. 修正 label 標籤外掛右側多餘空格的問題
10. 解決 APlayer 報告內存洩漏的問題

1. 優化 PJAX 下的函數調用
2. 整體代碼優化
3. 提升兼容性
4. 改善 Lighthouse 評分
5. 在 PJAX 關閉時減少不必要的全局變量
6. 優化 Waline 的 import 兼容性
7. 改善頁面進入效果
8. 優化程式碼區塊工具列顯示邏輯
9. 改善不同螢幕寬度下文章標題位置的顯示
10. 優化標籤顏色生成算法,避免過暗或過亮
11. 調整 Artalk 和 Waline 在夜間模式下的字體顏色,與主題保持一致
12. 調整 Algolia 搜索加載動畫位置,避免換行
13. 優化 Algolia 搜索結果為空時的處理
14. 改善系列文章的滑鼠懸停效果
15. 優化 404 頁面代碼
16. 解決搜索和側邊欄開啟時窗口抖動的問題
17. 優化 tabs 標籤外掛的代碼和效能
18. 改善 tabs 中使用 gallery 標籤外掛時的圖片加載邏輯
19. 優化目錄滾動效果,使當前標題保持在中間
20. 調整螢幕寬度超過 1024px 時 gallerygroup 的顯示數量
This commit is contained in:
Jerry
2024-08-03 19:05:57 +08:00
parent 0d52505331
commit 06f543ed96
123 changed files with 2226 additions and 1792 deletions

View File

@@ -15,12 +15,16 @@
text-rendering: auto
-webkit-font-smoothing: antialiased
addBorderRadius(x = 6)
if hexo-config('rounded_corners_ui')
border-radius: unit(x, 'px')
// card hover
.cardHover
border-radius: 8px
background: var(--card-bg)
box-shadow: var(--card-box-shadow)
transition: all .3s
addBorderRadius(8)
&:hover
box-shadow: var(--card-hover-box-shadow)
@@ -37,11 +41,10 @@
.postImgHover
&:hover
.cover
opacity: .8
opacity: .7
transform: scale(1.1)
.cover
position: absolute
width: 100%
height: 100%
opacity: .4
@@ -96,6 +99,12 @@
transition: all 1s ease-in-out
@extend .fontawesomeIcon
.verticalCenter
position: absolute
top: 50%
width: 100%
transform: translate(0, -50%)
maxWidth600()
@media screen and (max-width: 600px)
{block}
@@ -112,6 +121,10 @@ maxWidth1024()
@media screen and (max-width: 1024px)
{block}
minWidth1024()
@media screen and (min-width: 1024px)
{block}
maxWidth900()
@media screen and (max-width: 900px)
{block}
@@ -261,4 +274,4 @@ if hexo-config('avatar.effect') == true
transform: translateX(200px)
100%
transform: translateX(0)
transform: translateX(0)

View File

@@ -15,7 +15,9 @@
--tab-button-hover-bg: $tab-button-hover-bg
--tab-button-active-bg: $tab-button-active-bg
--card-bg: $card-bg
--card-meta: $theme-meta-color
--sidebar-bg: $sidebar-background
--sidebar-menu-bg: $white
--btn-hover-color: $button-hover-color
--btn-color: $button-color
--btn-bg: $button-bg
@@ -39,6 +41,7 @@
body
position: relative
overflow-y: scroll
min-height: 100%
background: var(--global-bg)
color: var(--font-color)
@@ -52,6 +55,12 @@ body
user-select: none
-webkit-user-select: none
// scrollbar - firefox
@-moz-document url-prefix()
*
scrollbar-width: thin
scrollbar-color: var(--scrollbar-color) transparent
// scrollbar - chrome/safari
*::-webkit-scrollbar
width: 5px
@@ -63,11 +72,6 @@ body
*::-webkit-scrollbar-track
background-color: transparent
// scrollbar - firefox
*
scrollbar-width: thin
scrollbar-color: var(--scrollbar-color) transparent
input::placeholder
color: var(--font-color)
@@ -104,11 +108,34 @@ h6
overflow-x: scroll
margin: 0 0 20px
if hexo-config('rounded_corners_ui')
$borderRadius = 5px
border-radius: $borderRadius
table
border-radius: $borderRadius
thead > tr:first-child
th:first-child
border-top-left-radius: $borderRadius
th:last-child
border-top-right-radius: $borderRadius
tbody > tr:last-child
td:first-child
border-bottom-left-radius: $borderRadius
td:last-child
border-bottom-right-radius: $borderRadius
table
display: table
width: 100%
border-spacing: 0
border-collapse: collapse
border-collapse: separate
border-top: 1px solid var(--light-grey)
border-left: 1px solid var(--light-grey)
empty-cells: show
thead
@@ -118,6 +145,8 @@ table
td
padding: 6px 12px
border: 1px solid var(--light-grey)
border-top: none
border-left: none
vertical-align: middle
*::selection
@@ -147,8 +176,8 @@ if $site-name-font
#site-title,
#site-subtitle,
.site-name,
#aside-content .author-info__name,
#aside-content .author-info__description
#aside-content .author-info-name,
#aside-content .author-info-description
font-family: $site-name-font
.is-center
@@ -183,10 +212,11 @@ if hexo-config('lazyload.enable') && hexo-config('lazyload.blur') && !hexo-confi
blockquote
margin: 0 0 20px
padding: 12px 15px
border-left: 3px solid $blockquote-padding-color
padding: 7px 15px
border-left: 4px solid $blockquote-padding-color
background-color: var(--blockquote-bg)
color: var(--blockquote-color)
addBorderRadius()
footer
cite

View File

@@ -1,6 +1,6 @@
$highlight_theme = hexo-config('highlight_theme')
$highlight_macstyle = hexo-config('highlight_theme_macStyle')
wordWrap = $highlight_enable && !$highlight_line_number && hexo-config('code_word_wrap')
$highlight_theme = hexo-config('code_blocks.theme')
$highlight_macstyle = hexo-config('code_blocks.macStyle')
wordWrap = $highlight_enable && !$highlight_line_number && hexo-config('code_blocks.word_wrap')
@require 'theme'
@@ -47,9 +47,10 @@ $code-block
code
font-size: $code-font-size
font-family: $code-font-family !important
addBorderRadius()
code
padding: 2px 4px
padding: 2px 5px
background: $code-background
color: $code-foreground
@@ -66,6 +67,7 @@ $code-block
figure.highlight
@extend $code-block
position: relative
addBorderRadius()
pre
margin: 0
@@ -104,9 +106,10 @@ $code-block
background: var(--hltools-bg)
color: var(--hltools-color)
font-size: $code-font-size
overflow: hidden
& > *
margin: 0 3px
padding: 5px
i
cursor: pointer
@@ -124,7 +127,7 @@ $code-block
if !$highlight_macstyle
& > .macStyle
margin: 0
padding: 0
.code-lang
flex: 1
@@ -133,16 +136,17 @@ $code-block
font-size: 1.15em
user-select: none
-webkit-user-select: none
padding 2px
.copy-notice
padding-right: 2px
opacity: 0
transition: opacity .4s
if hexo-config('highlight_lang')
if hexo-config('code_blocks.language')
.code-lang
flex: 1
else if (!$highlight_macstyle && hexo-config('highlight_shrink') != 'none')
else if (!$highlight_macstyle && hexo-config('code_blocks.shrink') != 'none')
& > div:nth-child(2)
flex: 1
else
@@ -168,8 +172,6 @@ if $highlight_macstyle
-webkit-transform: translateZ(0)
.highlight-tools
padding: 0 10px
.macStyle
display: flex
@@ -191,15 +193,15 @@ if $highlight_macstyle
.mac-maximize
background: #35cd4b
if hexo-config('highlight_shrink') != 'none'
& > div:nth-child(2)
if hexo-config('code_blocks.shrink') != 'none'
& > :nth-child(2)
order: 8
&.closed
.expand
transform: rotate(90deg)
if hexo-config('highlight_height_limit')
if hexo-config('code_blocks.height_limit')
#article-container
.code-expand-btn
position: absolute
@@ -228,7 +230,7 @@ if hexo-config('highlight_height_limit')
& ~ table,
& ~ pre
overflow: hidden
height: unit(hexo-config('highlight_height_limit'), px)
height: unit(hexo-config('code_blocks.height_limit'), px)
@keyframes code-expand-key
0%
@@ -240,7 +242,7 @@ if hexo-config('highlight_height_limit')
100%
opacity: .6
if hexo-config('highlight_fullpage')
if hexo-config('code_blocks.fullpage')
#article-container
figure.highlight.code-fullpage
position: fixed

View File

@@ -1,6 +1,8 @@
figure.highlight
table
scrollbar-color: var(--hlscrollbar-bg) transparent
// scrollbar - firefox
@-moz-document url-prefix()
scrollbar-color: var(--hlscrollbar-bg) transparent
&::-webkit-scrollbar-thumb
background: var(--hlscrollbar-bg)

View File

@@ -6,7 +6,9 @@ if $highlight_theme != false
#article-container
pre[class*='language-']
scrollbar-color: var(--hlscrollbar-bg) transparent
// scrollbar - firefox
@-moz-document url-prefix()
scrollbar-color: var(--hlscrollbar-bg) transparent
&::-webkit-scrollbar-thumb
background: var(--hlscrollbar-bg)

View File

@@ -10,7 +10,7 @@
position: relative
line-height: $line-height-code-block
if hexo-config('code_word_wrap')
if hexo-config('code_blocks.word_wrap')
white-space: pre-wrap
else
white-space: inherit

View File

@@ -8,19 +8,14 @@
padding-right: 15px
+maxWidth900()
margin-top: 20px
width: 100%
> .card-widget:first-child
margin-top: 0
+maxWidth900()
margin-top: 20px
.card-widget
@extend .cardHover
position: relative
overflow: hidden
margin-top: 20px
margin-bottom: 20px
padding: 20px 24px
if hexo-config('aside.mobile') == false
@@ -28,16 +23,19 @@
&:not(#card-toc)
display: none
&:last-child
margin-bottom: 0
.card-info
.author-info
&__name
&-name
font-weight: 500
font-size: 1.57em
&__description
&-description
margin-top: -.42em
.card-info-data
.site-data
margin: 14px 0 4px
.card-info-social-icons
@@ -61,6 +59,7 @@
color: var(--btn-color)
text-align: center
line-height: 2.4
addBorderRadius(7)
&:hover
background-color: var(--btn-hover-color)
@@ -86,6 +85,7 @@
a
display: inline-block
padding: 0 4px
line-height: 1.8
&:hover
color: $text-hover !important
@@ -112,8 +112,9 @@
.thumbnail
overflow: hidden
width: w = 4.2em
width: w = 4em
height: w
addBorderRadius()
:first-child
@extend .imgHover
@@ -130,14 +131,14 @@
& > time,
& > .name
display: block
color: $theme-meta-color
font-size: 85%
color: var(--card-meta)
font-size: .85em
& > .title,
& > .comment
@extend .limit-more-line
color: var(--font-color)
font-size: 95%
// font-size: 95%
line-height: 1.5
-webkit-line-clamp: 2
@@ -158,13 +159,16 @@
a
display: flex
flex-direction: row
padding: 3px 10px
padding: 2px 8px
margin: 2px 0
color: var(--font-color)
transition: all .4s
transition: all .3s
addBorderRadius()
&:hover
padding: 3px 17px
padding: 2px 12px
background-color: var(--text-bg-hover)
color: var(--white)
span
@extend .limit-one-line
@@ -288,9 +292,10 @@
.toc-link
display: block
margin: 4px 0
padding: 1px 6px
padding: 1px 8px
color: var(--toc-link-color)
transition: all .2s ease-in-out
addBorderRadius()
&:hover
color: $theme-color
@@ -397,9 +402,9 @@
.card-recent-post
order: hexo-config('aside.card_recent_post.sort_order')
if hexo-config('newest_comments.sort_order')
if hexo-config('aside.card_newest_comments.sort_order')
#card-newest-comments
order: hexo-config('newest_comments.sort_order')
order: hexo-config('aside.card_newest_comments.sort_order')
if hexo-config('aside.card_categories.sort_order')
.card-categories

View File

@@ -1,17 +1,18 @@
// chat
if hexo-config('chat_btn') == true && hexo-config('chatra.enable')
#chatra:not(.chatra--expanded)
visibility: hidden !important
width: 1px !important
height: 1px !important
opacity: 0 !important
pointer-events: none
if hexo-config('chat.rightside_button') == true
if hexo-config('chat.use') == 'chatra'
#chatra:not(.chatra--expanded)
visibility: hidden !important
width: 1px !important
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
if hexo-config('chat.use') == 'messenger'
.fb_dialog,
.fb-customerchat
visibility: hidden !important
width: 1px !important
height: 1px !important
opacity: 0 !important
pointer-events: none

View File

@@ -5,7 +5,7 @@
background-position: bottom
background-size: cover
if hexo-config('footer_bg') != false && hexo-config('mask.footer')
if hexo-config('footer_img') != false && hexo-config('mask.footer')
&:before
position: absolute
width: 100%

View File

@@ -146,6 +146,7 @@
background: rgba(255, 255, 255, .8)
box-shadow: 0 5px 6px -5px alpha($grey, .6)
transition: transform .2s ease-in-out, opacity .2s ease-in-out
will-change: transform
#blog-info
color: var(--font-color)
@@ -345,10 +346,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
addBorderRadius(5)
&:before
position: absolute
@@ -364,13 +365,14 @@
&:hover
background: var(--text-bg-hover)
&:first-child
border-top-left-radius: 5px
border-top-right-radius: 5px
if hexo-config('rounded_corners_ui')
&:first-child
border-top-left-radius: 5px
border-top-right-radius: 5px
&:last-child
border-bottom-right-radius: 5px
border-bottom-left-radius: 5px
&:last-child
border-bottom-right-radius: 5px
border-bottom-left-radius: 5px
a
display: inline-block

View File

@@ -37,47 +37,40 @@
.prev-post,
.next-post
@extend .postImgHover
position: relative
overflow: hidden
width: 50%
height: 150px
+maxWidth768()
width: 100%
a
position: relative
display: block
overflow: hidden
height: 150px
&.pagination-post
overflow: hidden
margin-top: 40px
width: 100%
background: $dark-black
addBorderRadius()
.layout
& > .recent-posts
.pagination
& > *
display: inline-block
margin: 0 6px
width: w = 2.5em
height: w
line-height: w
.pagination
& > *
display: inline-block
margin: 0 6px
width: w = 2.5em
height: w
line-height: w
& > *:not(.space)
@extend .cardHover
& > *:not(.space)
@extend .cardHover
&:hover
background: var(--btn-hover-color)
color: var(--btn-color)
&:hover
background: var(--btn-hover-color)
color: var(--btn-color)
& > div:not(.recent-posts)
.pagination
.page-number
display: inline-block
margin: 0 4px
min-width: w = 24px
height: w
text-align: center
line-height: w
cursor: pointer
#archive
.pagination
margin-top: 30px
& > *:not(.space)
box-shadow: none

View File

@@ -87,6 +87,7 @@ beautify()
margin: 0 auto 20px
max-width: 100%
transition: filter 375ms ease-in .2s
addBorderRadius()
p
margin: 0 0 16px
@@ -98,7 +99,6 @@ beautify()
margin: 0 3px
padding: 3px 5px
border: 1px solid #b4b4b4
border-radius: 3px
background-color: #f8f8f8
box-shadow: 0 1px 3px rgba(0, 0, 0, .25), 0 2px 1px 0 rgba(255, 255, 255, .6) inset
color: #34495e
@@ -107,6 +107,7 @@ beautify()
font-size: .9em
font-family: Monaco, 'Ubuntu Mono', monospace
line-height: 1em
addBorderRadius(3)
if hexo-config('anchor.click_to_scroll')
h1,
@@ -181,7 +182,7 @@ beautify()
background: $light-blue
color: var(--white)
.post_share
.post-share
display: inline-block
float: right
margin: 8px 0 0
@@ -203,6 +204,7 @@ beautify()
padding: 10px 16px
border: 1px solid var(--light-grey)
transition: box-shadow .3s ease-in-out
addBorderRadius()
&:before
@extend .fontawesomeIcon
@@ -238,9 +240,9 @@ beautify()
position: relative
margin: 0 0 20px
padding: .5em 1.2em
border-radius: 3px
background-color: $noticeOutdate-bg
color: $noticeOutdate-color
addBorderRadius(3)
if hexo-config('noticeOutdate.style') == 'flat'
padding: .5em 1em .5em 2.6em

View File

@@ -7,7 +7,7 @@
font-size: 1.43em
& > .relatedPosts-list
& > div
& > a
position: relative
display: inline-block
overflow: hidden
@@ -17,6 +17,7 @@
background: $dark-black
vertical-align: bottom
@extend .postImgHover
addBorderRadius()
+maxWidth768()
margin: 2px
@@ -27,11 +28,8 @@
width: calc(100% - 4px)
.content
position: absolute
top: 50%
padding: 0 20px
width: 100%
transform: translate(0, -50%)
@extend .verticalCenter
.date
color: var(--light-grey)

View File

@@ -14,6 +14,7 @@
background: var(--btn-bg)
color: var(--btn-color)
cursor: pointer
addBorderRadius()
i
margin-right: 5px
@@ -33,12 +34,12 @@
display: none
padding: 0 0 15px
width: 100%
addBorderRadius()
.reward-all
display: inline-block
margin: 0
padding: 20px 10px
border-radius: 4px
background: var(--reward-pop)
&:before

View File

@@ -32,12 +32,12 @@
margin-bottom: 5px
width: w = 35px
height: w
border-radius: 5px
background-color: var(--btn-bg)
color: var(--btn-color)
text-align: center
font-size: 16px
line-height: w
addBorderRadius(5)
&:hover
background-color: var(--btn-hover-color)

View File

@@ -26,27 +26,33 @@
& > .avatar-img
margin: 20px auto
.sidebar-site-data
.site-data
padding: 0 10px
hr
margin: 20px auto
.menus_items
padding: 0 10px
margin: 20px
padding: 15px
background: var(--sidebar-menu-bg)
box-shadow: 0 0 1px 1px rgba(7, 17, 27, .05)
addBorderRadius(10)
.site-page
@extend .limit-one-line
position: relative
display: block
padding: 3px 28px 3px 20px
border-radius: 6px
margin: 4px 0
padding: 2px 23px 2px 15px
color: var(--font-color)
font-size: 1.15em
cursor: pointer
addBorderRadius(6)
&:hover
background: var(--text-bg-hover)
color: var(--white)
i:first-child
width: 15%
@@ -55,8 +61,8 @@
&.group
& > i:last-child
position: absolute
top: .78em
right: 13px
top: .6em
right: 10px
transition: transform .3s
&.hide

View File

@@ -79,31 +79,45 @@ if hexo-config('mermaid.enable')
margin: 0 0 .8em
padding: 6px 0 16px
.katex-display
overflow: auto hidden
padding: 5px
if hexo-config('math.use')
.katex-display
overflow: auto hidden
padding: 5px
if hexo-config('katex') && hexo-config('katex.hide_scrollbar')
&::-webkit-scrollbar
display: none
.katex-show
display: block
// Mathjax
mjx-container
overflow-x: auto
overflow-y: hidden
padding-bottom: 4px
max-width: 100%
.katex
display: none
&[display]
display: block !important
min-width: auto !important
&.katex-show
display: inline
&:not([display])
display: inline-grid !important
if hexo-config('math.hide_scrollbar')
.katex-display,
mjx-container
scrollbar-width: none
mjx-assistive-mml
right: 0
bottom: 0
&::-webkit-scrollbar
display: none
// Mathjax
mjx-container
overflow-x: auto
overflow-y: hidden
padding-bottom: 4px
max-width: 100%
&[display]
display: block !important
min-width: auto !important
&:not([display])
display: inline-grid !important
mjx-assistive-mml
right: 0
bottom: 0
.aplayer
color: $font-black

View File

@@ -16,6 +16,7 @@ if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
--tab-button-active-bg: #121212
--card-bg: #121212
--sidebar-bg: #121212
--sidebar-menu-bg: lighten(#121212, 5)
--btn-hover-color: lighten(#121212, 40)
--btn-color: alpha(#FFFFFF, .7)
--btn-bg: lighten(#121212, 5)
@@ -139,4 +140,21 @@ if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
#card-toc
+maxWidth900()
background: lighten(#121212, 5)
background: lighten(#121212, 5)
// artalk
.artalk.atk-dark-mode,
.atk-layer-wrap.atk-dark-mode
--at-color-font: alpha(#FFFFFF, .7)
--at-color-meta: alpha(#FFFFFF, .7)
--at-color-grey: alpha(#FFFFFF, .7)
.atk-send-btn,
.atk-badge
color: alpha(#FFFFFF, .7) !important
// waline
#waline-wrap
--waline-color: alpha(#FFFFFF, .7)
--waline-dark-grey: alpha(#FFFFFF, .7)
--waline-info-color: alpha(#FFFFFF, .5)

View File

@@ -37,11 +37,11 @@ if hexo-config('readmode')
z-index: 100
width: 40px
height: 40px
border-radius: 8px
background: var(--exit-btn-bg)
color: var(--exit-btn-color)
font-size: 16px
transition: background .3s
addBorderRadius(8)
+maxWidth768()
top: initial

View File

@@ -1,69 +1,66 @@
if hexo-config('error_404.enable')
.error404
#error-wrap
position: absolute
top: 50%
right: 0
left: 0
margin: 0 auto
padding: 60px 20px 0
max-width: 1000px
transform: translate(0, -50%)
.type-404
.error-content
@extend .cardHover
overflow: hidden
margin: 0 20px
height: 360px
.error-content
@extend .cardHover
+maxWidth768()
margin: 0
height: 500px
.error-img
display: inline-block
overflow: hidden
margin: 0 20px
height: 360px
width: 50%
height: 100%
+maxWidth768()
margin: 0
height: 500px
width: 100%
height: 45%
.error-img
display: inline-block
overflow: hidden
width: 50%
height: 100%
img
@extend .imgHover
background-color: $theme-color
.error-info
display: inline-flex
flex-direction: column
justify-content: center
align-content: center
width: 50%
height: 100%
vertical-align: top
text-align: center
if $site-name-font
font-family: $site-name-font
+maxWidth768()
width: 100%
height: 55%
.error_title
margin-top: -.6em
font-size: 9em
+maxWidth768()
width: 100%
height: 45%
font-size: 8em
img
@extend .imgHover
background-color: $theme-color
.error_subtitle
@extend .limit-more-line
margin-top: -3em
word-break: break-word
font-size: 1.6em
-webkit-line-clamp: 2
.error-info
display: inline-flex
flex-direction: column
justify-content: center
align-content: center
width: 50%
height: 100%
vertical-align: top
text-align: center
.nc
margin-top: 5%
padding: 0 20px
if $site-name-font
font-family: $site-name-font
+maxWidth768()
width: 100%
height: 55%
.error_title
margin-top: -.6em
font-size: 9em
+maxWidth768()
font-size: 8em
.error_subtitle
@extend .limit-more-line
margin-top: -3em
word-break: break-word
font-size: 1.6em
-webkit-line-clamp: 2
#footer
display: none
& + #rightside
display: none

View File

@@ -78,8 +78,8 @@
border-color: var(--pseudo-hover)
&-time
color: $theme-meta-color
font-size: 95%
color: var(--card-meta)
font-size: .85em
time
padding-left: 6px
@@ -88,7 +88,7 @@
&-title
@extend .limit-more-line
color: var(--font-color)
font-size: 1.1em
font-size: 1.05em
transition: all .3s
-webkit-line-clamp: 2
@@ -98,8 +98,13 @@
&-img
overflow: hidden
width: 80px
height: 80px
width: 100px
height: 70px
addBorderRadius()
+maxWidth768()
width: 70px
height: 70px
:first-child
@extend .imgHover

View File

@@ -16,7 +16,7 @@
.category-list-count
margin-left: 8px
color: $theme-meta-color
color: var(--card-meta)
&:before
content: '('

View File

@@ -20,7 +20,7 @@
+minWidth2000()
max-width: 70%
& > div:first-child:not(.recent-posts)
& > div:first-child:not(.nc)
@extend .cardHover
align-self: flex-start
padding: 50px 40px

View File

@@ -14,9 +14,9 @@
margin: 15px 7px
width: calc(100% / 3 - 15px)
height: 90px
border-radius: 8px
line-height: 17px
-webkit-transform: translateZ(0)
addBorderRadius(8)
+maxWidth1024()
width: calc(50% - 15px) !important
@@ -56,7 +56,7 @@
margin: 15px 10px
width: 60px
height: 60px
border-radius: 35px
border-radius: 7px
transition: width .3s ease-out
img

View File

@@ -1,21 +1,39 @@
$indexLayout = hexo-config('index_layout') || 1
$indexEnable = hexo-config('cover.index_enable')
#recent-posts
& > .recent-post-item:not(:first-child)
margin-top: 20px
& > .recent-post-item
.recent-post-item
@extend .cardHover
display: flex
flex-direction: row
align-items: center
position: relative
overflow: hidden
height: 16.8em
margin-bottom: 20px
+maxWidth768()
flex-direction: column
height: auto
if $indexLayout == 6 || ($indexLayout == 7)
display: inline-block
width: calc(100% / 2 - 8px)
vertical-align: top
+maxWidth768()
width: 100%
+minWidth2000()
width: calc(100% / 3 - 8px)
if $indexLayout == 1 || ($indexLayout == 2 || ($indexLayout == 3))
display: flex
flex-direction: row
align-items: center
height: 16.8em
+maxWidth768()
flex-direction: column
height: auto
+minWidth2000()
height: 18.8em
&:hover
img.post-bg
.post-bg
transform: scale(1.1)
&.ads-wrap
@@ -24,36 +42,77 @@
.post_cover
overflow: hidden
width: 42%
height: 100%
+maxWidth768()
if ($indexLayout != 5 && ($indexLayout != 7))
+maxWidth768()
width: 100%
height: 230px
if $indexLayout == 1 || ($indexLayout == 2 || ($indexLayout == 3))
width: 42%
height: 100%
&.right
order: 1
+maxWidth768()
order: 0
if $indexLayout == 4 || ($indexLayout == 5 || ($indexLayout == 6 || ($indexLayout == 7)))
width: 100%
height: 230px
if ($indexLayout == 5 || ($indexLayout == 7))
height: 17em
else
height: 230px
if ($indexLayout == 5 || ($indexLayout == 7)) && $indexEnable
&:before
position: absolute
z-index: 1
width: 100%
height: 100%
background-color: rgba(18, 18, 18, .4)
content: ''
backdrop-filter: blur(3px)
.post-bg
z-index: -4
@extend .imgHover
&.right
order: 1
+maxWidth768()
order: 0
& >.recent-post-info
padding: 0 40px
width: 58%
+maxWidth768()
padding: 20px 20px 30px
width: 100%
&.no-cover
width: 100%
if $indexLayout == 1 || ($indexLayout == 2 || ($indexLayout == 3))
padding: 0 40px
width: 58%
if $indexLayout == 4 || ($indexLayout == 5 || ($indexLayout == 6 || ($indexLayout == 7)))
padding: 30px 30px 25px
if ($indexLayout == 5 || ($indexLayout == 7)) && $indexEnable
&:not(.no-cover)
position: absolute
top: 50%
z-index: 2
width: 100%
color: var(--text-highlight-color)
transform: translateY(-50%)
--text-highlight-color: rgba(255, 255, 255, 1)
--card-meta: rgba(255, 255, 255, .7)
&.no-cover
+maxWidth768()
padding: 30px 20px
if $indexLayout == 1 || ($indexLayout == 2 || ($indexLayout == 3))
width: 100%
if $indexLayout == 4 || ($indexLayout == 5 || ($indexLayout == 6 || ($indexLayout == 7)))
padding: 35px 30px
& > .article-title
@extend .limit-more-line
color: var(--text-highlight-color)
@@ -75,7 +134,7 @@
& > .article-meta-wrap
margin: 6px 0
color: $theme-meta-color
color: var(--card-meta)
font-size: .9em
& > .post-meta-date
@@ -104,7 +163,7 @@
display: none
a
color: $theme-meta-color
color: var(--card-meta)
&:hover
color: $text-hover

View File

@@ -0,0 +1,53 @@
#article-container
.shuoshuo-item
@extend .cardHover
margin-bottom: 20px
padding: 35px 30px 30px
+maxWidth768()
padding: 25px 20px 20px
.shuoshuo-item-header
display: flex
align-items: center
.shuoshuo-avatar
overflow: hidden
width: 40px
height: 40px
border-radius: 40px
img
margin: 0
width: 100%
height: 100%
.shuoshuo-info
margin-left: 10px
line-height: 1.5
.shuoshuo-date
color: #858585
font-size: .8em
.shuoshuo-content
padding: 15px 0 10px
& > *:last-child
margin-bottom: 0
.shuoshuo-tag
display: inline-block
margin-right: 8px
padding: 0 8px
width: fit-content
border: 1px solid $light-blue
border-radius: 12px
color: $light-blue
font-size: .85em
cursor: default
transition: all .2s ease-in-out
&:hover
background: $light-blue
color: var(--white)

View File

@@ -2,12 +2,16 @@
&-list
a
display: inline-block
padding: 0 8px
margin: 2px
padding: 2px 7px
line-height: 1.7
transition: all .3s
addBorderRadius(5)
&:hover
color: $text-hover !important
transform: scale(1.1)
background: var(--btn-bg) !important
box-shadow: 2px 2px 6px rgba(0, 0, 0, .2)
color: var(--btn-color) !important
+maxWidth768()
zoom: .85

View File

@@ -10,6 +10,11 @@
background: var(--search-bg)
color: var(--search-input-color)
.ais-SearchBox-loadingIndicator
position: absolute
top: 18px
left: 67px
.ais-Hits-list
margin: 0
padding: 0
@@ -66,7 +71,7 @@
#algolia-hits
> div
overflow-y: scroll
overflow-y: overlay
margin: 0 -20px
padding: 0 22px
max-height: calc(80vh - 240px)

View File

@@ -7,9 +7,9 @@
margin-left: -300px
padding: 20px
width: 600px
border-radius: 8px
background: var(--search-bg)
--search-height: 100vh
addBorderRadius(8)
+maxWidth768()
top: 0
@@ -53,8 +53,7 @@
display: none
background: rgba($dark-black, .6)
if hexo-config('algolia_search.enable')
if hexo-config('search.use') == 'algolia_search'
@require 'algolia'
if hexo-config('local_search.enable')
else if hexo-config('search.use') == 'local_search'
@require 'local-search'

View File

@@ -10,6 +10,7 @@
background-color: var(--btn-beautify-color, $btn-default-color)
color: $btn-color
line-height: 2
addBorderRadius()
for $type in $color-types
&.{$type}

View File

@@ -6,13 +6,16 @@
margin: 6px 4px
width: calc(50% - 8px)
height: 250px
border-radius: 8px
border-radius: 10px
background: $dark-black
-webkit-transform: translate3d(0, 0, 0)
+maxWidth600()
width: calc(100% - 8px)
+minWidth1024()
width: calc(100% / 3 - 8px)
&:hover
img
opacity: .4
@@ -95,8 +98,12 @@
padding: 0 0 16px
.gallery-container
margin: 0 0 16px
margin: 0 0 20px
text-align: center
opacity: 0
&.loaded
opacity: 1
img
display: initial
@@ -109,18 +116,20 @@
button
margin-top: 25px
padding: 10px
width: 9em
border-radius: 5px
padding: 8px 14px
background: var(--btn-bg)
color: var(--btn-color)
font-weight: bold
font-size: 1.1em
transition: all .3s
addBorderRadius(5)
&:hover
background: var(--btn-hover-color)
i
margin-left: 4px
.loading-container
display: inline-block
overflow: hidden

View File

@@ -6,6 +6,7 @@
padding: 5px 18px
background: $tag-hide-bg
color: var(--white)
addBorderRadius()
&:hover
background-color: var(--btn-hover-color)
@@ -35,6 +36,7 @@
.toggle
margin-bottom: 20px
border: 1px solid $tag-hide-toggle-bg
addBorderRadius()
& > .toggle-button
padding: 6px 15px

View File

@@ -1,7 +1,7 @@
.hl-label
padding: 2px 4px
border-radius: 3px
color: $btn-color
addBorderRadius(3)
&.default
background-color: $btn-default-color

View File

@@ -0,0 +1,5 @@
#article-container
.series-items
a
&:hover
color: var(--pseudo-hover)

View File

@@ -6,6 +6,8 @@
border-right: 1px solid var(--tab-border-color)
border-bottom: 1px solid var(--tab-border-color)
border-left: 1px solid var(--tab-border-color)
addBorderRadius()
overflow: hidden
> .nav-tabs
display: flex

View File

@@ -13,8 +13,11 @@ $code-foreground = $themeColorEnable && hexo-config('theme_color.code_foreground
$code-background = $themeColorEnable && hexo-config('theme_color.code_background') ? convert(hexo-config('theme_color.code_background')) : rgba(27, 31, 35, .05)
$theme-toc-color = $themeColorEnable && hexo-config('theme_color.toc_color') ? convert(hexo-config('theme_color.toc_color')) : $strong-cyan
// font
$dafault-font-family = -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Lato, Roboto, 'PingFang SC', 'Microsoft YaHei', sans-serif
$dafault-code-font = consolas, Menlo, 'PingFang SC', 'Microsoft YaHei', sans-serif
$chinseFont = $language == 'zh-CN' ? 'Microsoft YaHei' : 'Microsoft JhengHei'
$dafault-font-family = -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Lato, Roboto, 'PingFang SC', $chinseFont, sans-serif
$dafault-code-font = consolas, Menlo, 'PingFang SC', $chinseFont, sans-serif
$font-family = hexo-config('font.font-family') ? unquote(hexo-config('font.font-family')) : $dafault-font-family
$code-font-family = hexo-config('font.code-font-family') ? unquote(hexo-config('font.code-font-family')) : $dafault-code-font
$site-name-font = hexo-config('blog_title_font.font-family') && unquote(hexo-config('blog_title_font.font-family'))
@@ -59,7 +62,7 @@ $sticky-color = $light-orange
$theme-meta-color = $themeColorEnable && hexo-config('theme_color.meta_color') ? convert(hexo-config('theme_color.meta_color')) : #858585
// sidebar
$sidebar-background = #f6f8fa
$sidebar-width = 300px
$sidebar-width = 330px
// aside
$toc-link-color = #666261
$toc-mobile-width = calc(100% - 80px)

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

BIN
source/img/error-page.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
source/img/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 B

View File

@@ -1,11 +1,9 @@
document.addEventListener('DOMContentLoaded', function () {
document.addEventListener('DOMContentLoaded', () => {
let headerContentWidth, $nav
let mobileSidebarOpen = false
const adjustMenu = init => {
const getAllWidth = ele => {
return Array.from(ele).reduce((width, i) => width + i.offsetWidth, 0)
}
const getAllWidth = ele => Array.from(ele).reduce((width, i) => width + i.offsetWidth, 0)
if (init) {
const blogInfoWidth = getAllWidth(document.querySelector('#blog-info > a').children)
@@ -27,16 +25,13 @@ document.addEventListener('DOMContentLoaded', function () {
// sidebar menus
const sidebarFn = {
open: () => {
btf.sidebarPaddingR()
document.body.style.overflow = 'hidden'
btf.overflowPaddingR.add()
btf.animateIn(document.getElementById('menu-mask'), 'to_show 0.5s')
document.getElementById('sidebar-menus').classList.add('open')
mobileSidebarOpen = true
},
close: () => {
const $body = document.body
$body.style.overflow = ''
$body.style.paddingRight = ''
btf.overflowPaddingR.remove()
btf.animateOut(document.getElementById('menu-mask'), 'to_hide 0.5s')
document.getElementById('sidebar-menus').classList.remove('open')
mobileSidebarOpen = false
@@ -72,7 +67,7 @@ document.addEventListener('DOMContentLoaded', function () {
const isPrismjs = plugin === 'prismjs'
const highlightShrinkClass = isHighlightShrink === true ? 'closed' : ''
const highlightShrinkEle = isHighlightShrink !== undefined ? '<div><i class="fas fa-angle-down expand"></i></div>' : ''
const highlightShrinkEle = isHighlightShrink !== undefined ? '<i class="fas fa-angle-down expand"></i>' : ''
const highlightCopyEle = highlightCopy ? '<div class="copy-notice"></div><i class="fas fa-paste copy-button"></i>' : ''
const highlightMacStyleEle = '<div class="macStyle"><div class="mac-close"></div><div class="mac-minimize"></div><div class="mac-maximize"></div></div>'
const highlightFullpageEle = highlightFullpage ? '<i class="fa-solid fa-up-right-and-down-left-from-center fullpage-button"></i>' : ''
@@ -111,9 +106,7 @@ document.addEventListener('DOMContentLoaded', function () {
$buttonParent.classList.remove('copy-true')
}
const highlightShrinkFn = ele => {
ele.classList.toggle('closed')
}
const highlightShrinkFn = ele => ele.classList.toggle('closed')
const codeFullpage = (item, clickEle) => {
const wrapEle = item.closest('figure.highlight')
@@ -124,47 +117,44 @@ document.addEventListener('DOMContentLoaded', function () {
clickEle.classList.toggle('fa-up-right-and-down-left-from-center', !isFullpage)
}
const highlightToolsFn = function (e) {
const highlightToolsFn = e => {
const $target = e.target.classList
if ($target.contains('expand')) highlightShrinkFn(this)
else if ($target.contains('copy-button')) highlightCopyFn(this, e.target)
else if ($target.contains('fullpage-button')) codeFullpage(this, e.target)
const currentElement = e.currentTarget
if ($target.contains('expand')) highlightShrinkFn(currentElement)
else if ($target.contains('copy-button')) highlightCopyFn(currentElement, e.target)
else if ($target.contains('fullpage-button')) codeFullpage(currentElement, e.target)
}
const expandCode = function () {
this.classList.toggle('expand-done')
}
const expandCode = e => e.currentTarget.classList.toggle('expand-done')
// 获取隐藏状态下元素的真高度
const getActualHeight = function (item) {
let tmp = []
let hidden = []
function fix() {
let current = item
while (current !== document.body && current != null) {
if (window.getComputedStyle(current).display === 'none') {
hidden.push(current)
}
current = current.parentNode
// 獲取隱藏狀態下元素的真高度
const getActualHeight = item => {
const hiddenElements = new Map()
const fix = () => {
let current = item
while (current !== document.body && current != null) {
if (window.getComputedStyle(current).display === 'none') {
hiddenElements.set(current, current.getAttribute('style') || '')
}
let style = 'visibility: hidden !important; display: block !important; '
hidden.forEach(function (elem) {
var thisStyle = elem.getAttribute('style') || ''
tmp.push(thisStyle)
elem.setAttribute('style', thisStyle ? thisStyle + ';' + style : style)
})
current = current.parentNode
}
const style = 'visibility: hidden !important; display: block !important;'
hiddenElements.forEach((originalStyle, elem) => {
elem.setAttribute('style', originalStyle ? originalStyle + ';' + style : style)
})
}
function restore() {
hidden.forEach((elem, idx) => {
let _tmp = tmp[idx]
if( _tmp === '' ) elem.removeAttribute('style')
else elem.setAttribute('style', _tmp)
})
const restore = () => {
hiddenElements.forEach((originalStyle, elem) => {
if (originalStyle === '') elem.removeAttribute('style')
else elem.setAttribute('style', originalStyle)
})
}
fix()
let height = item.offsetHeight
const height = item.offsetHeight
restore()
return height
}
@@ -236,7 +226,7 @@ document.addEventListener('DOMContentLoaded', function () {
* justified-gallery 圖庫排版
*/
const fetchUrl = async (url) => {
const fetchUrl = async url => {
const response = await fetch(url)
return await response.json()
}
@@ -254,10 +244,6 @@ document.addEventListener('DOMContentLoaded', function () {
// useRecycle: false
})
if (tabs) {
btf.addGlobalFn('igOfTabs', () => { ig.destroy() }, false, tabs)
}
const replaceDq = str => str.replace(/"/g, '&quot;') // replace double quotes to &quot;
const getItems = (nextGroupKey, count) => {
@@ -274,7 +260,7 @@ document.addEventListener('DOMContentLoaded', function () {
const alt = item.alt ? `alt="${replaceDq(item.alt)}"` : ''
const title = item.title ? `title="${replaceDq(item.title)}"` : ''
nextItems.push(`<div class="item ">
nextItems.push(`<div class="item">
<img src="${item.url}" data-grid-maintained-target="true" ${alt + title} />
</div>`)
}
@@ -284,16 +270,14 @@ document.addEventListener('DOMContentLoaded', function () {
const buttonText = GLOBAL_CONFIG.infinitegrid.buttonText
const addButton = item => {
const button = document.createElement('button')
button.textContent = buttonText
button.innerHTML = buttonText + '<i class="fa-solid fa-arrow-down"></i>'
const buttonFn = e => {
e.target.removeEventListener('click', buttonFn)
e.target.remove()
button.addEventListener('click', e => {
e.target.closest('button').remove()
btf.setLoading.add(item)
appendItem(ig.getGroups().length + 1, 10)
}
}, { once: true })
button.addEventListener('click', buttonFn)
item.insertAdjacentElement('afterend', button)
}
@@ -302,8 +286,22 @@ document.addEventListener('DOMContentLoaded', function () {
}
const maxGroupKey = Math.ceil(dataLength / 10)
let isLayoutHidden = false
const completeFn = e => {
if (tabs) {
const parentNode = item.parentNode
if (isLayoutHidden) {
parentNode.style.visibility = 'visible'
}
if (item.offsetHeight === 0) {
parentNode.style.visibility = 'hidden'
isLayoutHidden = true
}
}
const { updated, isResize, mounted } = e
if (!updated.length || !mounted.length || isResize) {
return
@@ -313,7 +311,7 @@ document.addEventListener('DOMContentLoaded', function () {
if (ig.getGroups().length === maxGroupKey) {
btf.setLoading.remove(item)
ig.off('renderComplete', completeFn)
!tabs && ig.off('renderComplete', completeFn)
return
}
@@ -342,29 +340,30 @@ document.addEventListener('DOMContentLoaded', function () {
ig.renderItems()
}
btf.addGlobalFn('justifiedGallery', () => { ig.destroy() })
btf.addGlobalFn('pjaxSendOnce', () => { ig.destroy() })
}
const addJustifiedGallery = async (ele, tabs = false) => {
const init = async () => {
for (const item of ele) {
if (btf.isHidden(item)) continue
if (tabs && item.classList.contains('loaded')) {
item.querySelector('.gallery-items').innerHTML = ''
const button = item.querySelector(':scope > button')
const loadingContainer = item.querySelector(':scope > .loading-container')
button && button.remove()
loadingContainer && loadingContainer.remove()
}
if (btf.isHidden(item) || item.classList.contains('loaded')) continue
const isButton = item.getAttribute('data-button') === 'true'
const text = item.firstElementChild.textContent
const children = item.firstElementChild
const text = children.textContent
children.textContent = ''
item.classList.add('loaded')
const content = item.getAttribute('data-type') === 'url' ? await fetchUrl(text) : JSON.parse(text)
runJustifiedGallery(item.lastElementChild, content, isButton, tabs)
try {
const content = item.getAttribute('data-type') === 'url' ? await fetchUrl(text) : JSON.parse(text)
runJustifiedGallery(children, content, isButton, tabs)
} catch (e) {
console.error('Gallery data parsing failed:', e)
}
}
}
if (!ele.length) return
if (typeof InfiniteGrid === 'function') {
init()
} else {
@@ -399,12 +398,18 @@ document.addEventListener('DOMContentLoaded', function () {
const isChatBtn = typeof chatBtn !== 'undefined'
const isShowPercent = GLOBAL_CONFIG.percent.rightside
// 當滾動條小于 56 的時候
if (document.body.scrollHeight <= innerHeight) {
$rightside.classList.add('rightside-show')
return
// 檢查文檔高度是否小於視窗高度
const checkDocumentHeight = () => {
if (document.body.scrollHeight <= innerHeight) {
$rightside.classList.add('rightside-show')
return true
}
return false
}
// 如果文檔高度小於視窗高度,直接返回
if (checkDocumentHeight()) return
// find the scroll direction
const scrollDirection = currentTop => {
const result = currentTop > initTop // true is down & false is up
@@ -444,10 +449,7 @@ document.addEventListener('DOMContentLoaded', function () {
}
isShowPercent && rightsideScrollPercent(currentTop)
if (document.body.scrollHeight <= innerHeight) {
$rightside.classList.add('rightside-show')
}
checkDocumentHeight()
}, 300)
btf.addEventListenerPjax(window, 'scroll', scrollTask, { passive: true })
@@ -487,13 +489,15 @@ document.addEventListener('DOMContentLoaded', function () {
btf.addEventListenerPjax($cardToc, 'click', tocItemClickFn)
autoScrollToc = item => {
const activePosition = item.getBoundingClientRect().top
const sidebarScrollTop = $cardToc.scrollTop
if (activePosition > (document.documentElement.clientHeight - 100)) {
$cardToc.scrollTop = sidebarScrollTop + 150
}
if (activePosition < 100) {
$cardToc.scrollTop = sidebarScrollTop - 150
const sidebarHeight = $cardToc.clientHeight
const itemOffsetTop = item.offsetTop
const itemHeight = item.clientHeight
const scrollTop = $cardToc.scrollTop
const offset = itemOffsetTop - scrollTop
const middlePosition = (sidebarHeight - itemHeight) / 2
if (offset !== middlePosition) {
$cardToc.scrollTop = scrollTop + (offset - middlePosition)
}
}
@@ -504,21 +508,23 @@ document.addEventListener('DOMContentLoaded', function () {
// find head position & add active class
const $articleList = $article.querySelectorAll('h1,h2,h3,h4,h5,h6')
let detectItem = ''
const findHeadPosition = top => {
if (top === 0) {
return false
}
if (top === 0) return false
let currentId = ''
let currentIndex = ''
$articleList.forEach((ele, index) => {
for (let i = 0; i < $articleList.length; i++) {
const ele = $articleList[i]
if (top > btf.getEleTop(ele) - 80) {
const id = ele.id
currentId = id ? '#' + encodeURI(id) : ''
currentIndex = index
currentIndex = i
} else {
break
}
})
}
if (detectItem === currentIndex) return
@@ -527,24 +533,21 @@ document.addEventListener('DOMContentLoaded', function () {
detectItem = currentIndex
if (isToc) {
$cardToc.querySelectorAll('.active').forEach(i => { i.classList.remove('active') })
$cardToc.querySelectorAll('.active').forEach(i => i.classList.remove('active'))
if (currentId === '') {
return
}
if (currentId) {
const currentActive = $tocLink[currentIndex]
currentActive.classList.add('active')
const currentActive = $tocLink[currentIndex]
currentActive.classList.add('active')
setTimeout(() => autoScrollToc(currentActive), 0)
setTimeout(() => {
autoScrollToc(currentActive)
}, 0)
if (isExpand) return
let parent = currentActive.parentNode
for (; !parent.matches('.toc'); parent = parent.parentNode) {
if (parent.matches('li')) parent.classList.add('active')
if (!isExpand) {
let parent = currentActive.parentNode
while (!parent.matches('.toc')) {
if (parent.matches('li')) parent.classList.add('active')
parent = parent.parentNode
}
}
}
}
}
@@ -630,7 +633,7 @@ document.addEventListener('DOMContentLoaded', function () {
btf.saveToLocal.set('aside-status', saveStatus, 2)
$htmlDom.toggle('hide-aside')
},
'mobile-toc-button': function (p, item) { // Show mobile toc
'mobile-toc-button': (p, item) => { // Show mobile toc
const tocEle = document.getElementById('card-toc')
tocEle.style.transition = 'transform 0.3s ease-in-out'
@@ -655,10 +658,10 @@ document.addEventListener('DOMContentLoaded', function () {
}
}
document.getElementById('rightside').addEventListener('click', function (e) {
document.getElementById('rightside').addEventListener('click', e => {
const $target = e.target.closest('[id]')
if ($target && rightSideFn[$target.id]) {
rightSideFn[$target.id](this, $target)
rightSideFn[$target.id](e.currentTarget, $target)
}
})
@@ -673,15 +676,17 @@ document.addEventListener('DOMContentLoaded', function () {
target.classList.toggle('hide')
}
document.querySelector('#sidebar-menus .menus_items').addEventListener('click', handleClickOfSubMenu)
const menusItems = document.querySelector('#sidebar-menus .menus_items')
menusItems && menusItems.addEventListener('click', handleClickOfSubMenu)
}
/**
* 手机端目录点击
*/
const openMobileMenu = () => {
const handleClick = () => { sidebarFn.open() }
btf.addEventListenerPjax(document.getElementById('toggle-menu'), 'click', handleClick)
const toggleMenu = document.getElementById('toggle-menu')
if (!toggleMenu) return
btf.addEventListenerPjax(toggleMenu, 'click', () => { sidebarFn.open() })
}
/**
@@ -749,62 +754,45 @@ document.addEventListener('DOMContentLoaded', function () {
const clickFnOfTagHide = () => {
const hideButtons = document.querySelectorAll('#article-container .hide-button')
if (!hideButtons.length) return
const handleClick = function (e) {
const $this = this
$this.classList.add('open')
const $fjGallery = $this.nextElementSibling.querySelectorAll('.gallery-container')
$fjGallery.length && addJustifiedGallery($fjGallery)
}
hideButtons.forEach(item => {
item.addEventListener('click', handleClick, { once: true })
})
hideButtons.forEach(item => item.addEventListener('click', e => {
const currentTarget = e.currentTarget
currentTarget.classList.add('open')
addJustifiedGallery(currentTarget.nextElementSibling.querySelectorAll('.gallery-container'))
}, { once: true }))
}
const tabsFn = () => {
const navTabsElement = document.querySelectorAll('#article-container .tabs')
if (!navTabsElement.length) return
const navTabsElements = document.querySelectorAll('#article-container .tabs')
if (!navTabsElements.length) return
const removeAndAddActiveClass = (elements, detect) => {
Array.from(elements).forEach(element => {
element.classList.remove('active')
if (element === detect || element.id === detect) {
element.classList.add('active')
}
const setActiveClass = (elements, activeIndex) => {
elements.forEach((el, index) => {
el.classList.toggle('active', index === activeIndex)
})
}
const addTabNavEventListener = (item, isJustifiedGallery) => {
const navClickHandler = function (e) {
const target = e.target.closest('button')
if (target.classList.contains('active')) return
removeAndAddActiveClass(this.children, target)
this.classList.remove('no-default')
const tabId = target.getAttribute('data-href')
const tabContent = this.nextElementSibling
removeAndAddActiveClass(tabContent.children, tabId)
if (isJustifiedGallery) {
btf.removeGlobalFnEvent('igOfTabs', this)
const justifiedGalleryItems = tabContent.querySelectorAll(`:scope > #${tabId} .gallery-container`)
justifiedGalleryItems.length && addJustifiedGallery(justifiedGalleryItems, this)
}
}
btf.addEventListenerPjax(item.firstElementChild, 'click', navClickHandler)
const handleNavClick = e => {
const target = e.target.closest('button')
if (!target || target.classList.contains('active')) return
const navItems = [...e.currentTarget.children]
const tabContents = [...e.currentTarget.nextElementSibling.children]
const indexOfButton = navItems.indexOf(target)
setActiveClass(navItems, indexOfButton)
e.currentTarget.classList.remove('no-default')
setActiveClass(tabContents, indexOfButton)
addJustifiedGallery(tabContents[indexOfButton].querySelectorAll('.gallery-container'), true)
}
const addTabToTopEventListener = item => {
const btnClickHandler = (e) => {
const target = e.target.closest('button')
if (!target) return
btf.scrollToDest(btf.getEleTop(item), 300)
const handleToTopClick = tabElement => e => {
if (e.target.closest('button')) {
btf.scrollToDest(btf.getEleTop(tabElement), 300)
}
btf.addEventListenerPjax(item.lastElementChild, 'click', btnClickHandler)
}
navTabsElement.forEach(item => {
const isJustifiedGallery = !!item.querySelectorAll('.gallery-container')
addTabNavEventListener(item, isJustifiedGallery)
addTabToTopEventListener(item)
navTabsElements.forEach(tabElement => {
btf.addEventListenerPjax(tabElement.firstElementChild, 'click', handleNavClick)
btf.addEventListenerPjax(tabElement.lastElementChild, 'click', handleToTopClick(tabElement))
})
}
@@ -812,7 +800,7 @@ document.addEventListener('DOMContentLoaded', function () {
const cardCategory = document.querySelector('#aside-cat-list.expandBtn')
if (!cardCategory) return
const handleToggleBtn = (e) => {
const handleToggleBtn = e => {
const target = e.target
if (target.nodeName === 'I') {
e.preventDefault()
@@ -825,10 +813,10 @@ document.addEventListener('DOMContentLoaded', function () {
const switchComments = () => {
const switchBtn = document.getElementById('switch-btn')
if (!switchBtn) return
let switchDone = false
const commentContainer = document.getElementById('post-comment')
const handleSwitchBtn = () => {
commentContainer.classList.toggle('move')
document.getElementById('post-comment').classList.toggle('move')
if (!switchDone && typeof loadOtherComment === 'function') {
switchDone = true
loadOtherComment()
@@ -865,28 +853,45 @@ document.addEventListener('DOMContentLoaded', function () {
}, 'lazyload')
}
const relativeDate = function (selector) {
const relativeDate = selector => {
selector.forEach(item => {
const timeVal = item.getAttribute('datetime')
item.textContent = btf.diffDate(timeVal, true)
item.textContent = btf.diffDate(item.getAttribute('datetime'), true)
item.style.display = 'inline'
})
}
const unRefreshFn = function () {
const justifiedIndexPostUI = () => {
const recentPostsElement = document.getElementById('recent-posts')
if (!(recentPostsElement && recentPostsElement.classList.contains('masonry'))) return
const init = () => {
const masonryItem = new InfiniteGrid.MasonryInfiniteGrid('.recent-post-items', {
gap: { horizontal: 10, vertical: 20 },
useTransform: true,
useResizeObserver: true
})
masonryItem.renderItems()
btf.addGlobalFn('pjaxCompleteOnce', () => { masonryItem.destroy() }, 'removeJustifiedIndexPostUI')
}
typeof InfiniteGrid === 'function' ? init() : btf.getScript(`${GLOBAL_CONFIG.infinitegrid.js}`).then(init)
}
const unRefreshFn = () => {
window.addEventListener('resize', () => {
adjustMenu(false)
mobileSidebarOpen && btf.isHidden(document.getElementById('toggle-menu')) && sidebarFn.close()
})
document.getElementById('menu-mask').addEventListener('click', e => { sidebarFn.close() })
const menuMask = document.getElementById('menu-mask')
menuMask && menuMask.addEventListener('click', () => { sidebarFn.close() })
clickFnOfSubMenu()
GLOBAL_CONFIG.islazyload && lazyloadImg()
GLOBAL_CONFIG.copyright !== undefined && addCopyright()
if (GLOBAL_CONFIG.autoDarkmode) {
window.matchMedia('(prefers-color-scheme: dark)').addListener(e => {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
if (btf.saveToLocal.get('theme') !== undefined) return
e.matches ? handleThemeChange('dark') : handleThemeChange('light')
})
@@ -896,11 +901,7 @@ document.addEventListener('DOMContentLoaded', function () {
const forPostFn = () => {
addHighlightTool()
addPhotoFigcaption()
btf.removeGlobalFnEvent('justifiedGallery')
const galleryContainer = document.querySelectorAll('#article-container .gallery-container')
galleryContainer.length && addJustifiedGallery(galleryContainer)
addJustifiedGallery(document.querySelectorAll('#article-container .gallery-container'))
runLightbox()
scrollFnToDo()
addTableWrap()
@@ -910,6 +911,7 @@ document.addEventListener('DOMContentLoaded', function () {
const refreshFn = () => {
initAdjust()
justifiedIndexPostUI()
if (GLOBAL_CONFIG_SITE.isPost) {
GLOBAL_CONFIG.noticeOutdate !== undefined && addPostOutdateNotice()

View File

@@ -1,43 +1,51 @@
window.addEventListener('load', () => {
const { algolia } = GLOBAL_CONFIG
const { appId, apiKey, indexName, hitsPerPage = 5, languages } = algolia
if (!appId || !apiKey || !indexName) {
return console.error('Algolia setting is invalid!')
}
const $searchMask = document.getElementById('search-mask')
const $searchDialog = document.querySelector('#algolia-search .search-dialog')
const animateElements = show => {
const action = show ? 'animateIn' : 'animateOut'
const maskAnimation = show ? 'to_show 0.5s' : 'to_hide 0.5s'
const dialogAnimation = show ? 'titleScale 0.5s' : 'search_close .5s'
btf[action]($searchMask, maskAnimation)
btf[action]($searchDialog, dialogAnimation)
}
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($searchDialog, 'titleScale 0.5s')
btf.overflowPaddingR.add()
animateElements(true)
setTimeout(() => { document.querySelector('#algolia-search .ais-SearchBox-input').focus() }, 100)
// shortcut: ESC
document.addEventListener('keydown', function f (event) {
const handleEscape = event => {
if (event.code === 'Escape') {
closeSearch()
document.removeEventListener('keydown', f)
document.removeEventListener('keydown', handleEscape)
}
})
}
document.addEventListener('keydown', handleEscape)
fixSafariHeight()
window.addEventListener('resize', fixSafariHeight)
}
const closeSearch = () => {
const bodyStyle = document.body.style
bodyStyle.width = ''
bodyStyle.overflow = ''
btf.animateOut($searchDialog, 'search_close .5s')
btf.animateOut($searchMask, 'to_hide 0.5s')
btf.overflowPaddingR.remove()
animateElements(false)
window.removeEventListener('resize', fixSafariHeight)
}
// fix safari
const fixSafariHeight = () => {
if (window.innerWidth < 768) {
$searchDialog.style.setProperty('--search-height', window.innerHeight + 'px')
}
}
const searchClickFn = () => {
btf.addEventListenerPjax(document.querySelector('#search-button > .search'), 'click', openSearch)
}
@@ -47,11 +55,9 @@ window.addEventListener('load', () => {
document.querySelector('#algolia-search .search-close-button').addEventListener('click', closeSearch)
}
const cutContent = content => {
if (content === '') return ''
const cutContent = (content) => {
if (!content) return ''
const firstOccur = content.indexOf('<mark>')
let start = firstOccur - 30
let end = firstOccur + 120
let pre = ''
@@ -70,108 +76,98 @@ window.addEventListener('load', () => {
post = '...'
}
const matchContent = pre + content.substring(start, end) + post
return matchContent
return `${pre}${content.substring(start, end)}${post}`
}
const algolia = GLOBAL_CONFIG.algolia
const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName
if (!isAlgoliaValid) {
return console.error('Algolia setting is invalid!')
}
const disableDiv = [
document.getElementById('algolia-hits'),
document.getElementById('algolia-pagination'),
document.querySelector('#algolia-info .algolia-stats')
]
const search = instantsearch({
indexName: algolia.indexName,
/* global algoliasearch */
searchClient: algoliasearch(algolia.appId, algolia.apiKey),
indexName,
searchClient: algoliasearch(appId, apiKey),
searchFunction (helper) {
helper.state.query && helper.search()
disableDiv.forEach(item => {
item.style.display = helper.state.query ? '' : 'none'
})
if (helper.state.query) helper.search()
}
})
const configure = instantsearch.widgets.configure({
hitsPerPage: 5
})
const searchBox = instantsearch.widgets.searchBox({
container: '#algolia-search-input',
showReset: false,
showSubmit: false,
placeholder: GLOBAL_CONFIG.algolia.languages.input_placeholder,
showLoadingIndicator: true
})
const hits = instantsearch.widgets.hits({
container: '#algolia-hits',
templates: {
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)
: ''
return `
<a href="${link}" class="algolia-hit-item-link">
<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 (
'<div id="algolia-hits-empty">' +
GLOBAL_CONFIG.algolia.languages.hits_empty.replace(/\$\{query}/, data.query) +
'</div>'
)
const widgets = [
instantsearch.widgets.configure({ hitsPerPage }),
instantsearch.widgets.searchBox({
container: '#algolia-search-input',
showReset: false,
showSubmit: false,
placeholder: languages.input_placeholder,
showLoadingIndicator: true
}),
instantsearch.widgets.hits({
container: '#algolia-hits',
templates: {
item (data) {
const link = 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)
: ''
return `
<a href="${link}" class="algolia-hit-item-link">
<span class="algolia-hits-item-title">${result.title.value || 'no-title'}</span>
${content ? `<div class="algolia-hit-item-content">${content}</div>` : ''}
</a>`
},
empty (data) {
return `<div id="algolia-hits-empty">${languages.hits_empty.replace(/\$\{query}/, data.query)}</div>`
}
}
}
})
const stats = instantsearch.widgets.stats({
container: '#algolia-info > .algolia-stats',
templates: {
text: function (data) {
const stats = GLOBAL_CONFIG.algolia.languages.hits_stats
.replace(/\$\{hits}/, data.nbHits)
.replace(/\$\{time}/, data.processingTimeMS)
return (
`<hr>${stats}`
)
}),
instantsearch.widgets.stats({
container: '#algolia-info > .algolia-stats',
templates: {
text (data) {
const stats = languages.hits_stats
.replace(/\$\{hits}/, data.nbHits)
.replace(/\$\{time}/, data.processingTimeMS)
return `<hr>${stats}`
}
}
}
})
const powerBy = instantsearch.widgets.poweredBy({
container: '#algolia-info > .algolia-poweredBy'
})
const pagination = instantsearch.widgets.pagination({
container: '#algolia-pagination',
totalPages: 5,
templates: {
first: '<i class="fas fa-angle-double-left"></i>',
last: '<i class="fas fa-angle-double-right"></i>',
previous: '<i class="fas fa-angle-left"></i>',
next: '<i class="fas fa-angle-right"></i>'
}
})
search.addWidgets([configure, searchBox, hits, stats, powerBy, pagination]) // add the widgets to the instantsearch instance
}),
instantsearch.widgets.poweredBy({
container: '#algolia-info > .algolia-poweredBy'
}),
instantsearch.widgets.pagination({
container: '#algolia-pagination',
totalPages: 5,
templates: {
first: '<i class="fas fa-angle-double-left"></i>',
last: '<i class="fas fa-angle-double-right"></i>',
previous: '<i class="fas fa-angle-left"></i>',
next: '<i class="fas fa-angle-right"></i>'
}
})
]
search.addWidgets(widgets)
search.start()
searchClickFn()
searchFnOnce()
window.addEventListener('pjax:complete', () => {
!btf.isHidden($searchMask) && closeSearch()
if (!btf.isHidden($searchMask)) closeSearch()
searchClickFn()
})
window.pjax && search.on('render', () => {
window.pjax.refresh(document.getElementById('algolia-hits'))
})
if (window.pjax) {
search.on('render', () => {
window.pjax.refresh(document.getElementById('algolia-hits'))
})
}
})

View File

@@ -301,9 +301,7 @@ window.addEventListener('load', () => {
}
const openSearch = () => {
const bodyStyle = document.body.style
bodyStyle.width = '100%'
bodyStyle.overflow = 'hidden'
btf.overflowPaddingR.add()
btf.animateIn($searchMask, 'to_show 0.5s')
btf.animateIn($searchDialog, 'titleScale 0.5s')
setTimeout(() => { input.focus() }, 300)
@@ -325,9 +323,7 @@ window.addEventListener('load', () => {
}
const closeSearch = () => {
const bodyStyle = document.body.style
bodyStyle.width = ''
bodyStyle.overflow = ''
btf.overflowPaddingR.remove()
btf.animateOut($searchDialog, 'search_close .5s')
btf.animateOut($searchMask, 'to_hide 0.5s')
window.removeEventListener('resize', fixSafariHeight)

File diff suppressed because one or more lines are too long

View File

@@ -47,12 +47,28 @@
return throttled
},
sidebarPaddingR: () => {
const innerWidth = window.innerWidth
const clientWidth = document.body.clientWidth
const paddingRight = innerWidth - clientWidth
if (innerWidth !== clientWidth) {
document.body.style.paddingRight = paddingRight + 'px'
overflowPaddingR: {
add: () => {
const innerWidth = window.innerWidth
const clientWidth = document.body.clientWidth
const paddingRight = innerWidth - clientWidth
if (paddingRight > 0) {
document.body.style.paddingRight = `${paddingRight}px`
document.body.style.overflow = 'hidden'
const menuElement = document.querySelector('#page-header.nav-fixed #menus')
if (menuElement) {
menuElement.style.paddingRight = `${paddingRight}px`
}
}
},
remove: () => {
document.body.style.paddingRight = ''
document.body.style.overflow = ''
const menuElement = document.querySelector('#page-header.nav-fixed #menus')
if (menuElement) {
menuElement.style.paddingRight = ''
}
}
},
@@ -69,28 +85,24 @@
})
},
diffDate: (d, more = false) => {
diffDate: (inputDate, more = false) => {
const dateNow = new Date()
const datePost = new Date(d)
const dateDiff = dateNow.getTime() - datePost.getTime()
const minute = 1000 * 60
const hour = minute * 60
const day = hour * 24
const month = day * 30
const datePost = new Date(inputDate)
const diffMs = dateNow - datePost
const diffSec = diffMs / 1000
const diffMin = diffSec / 60
const diffHour = diffMin / 60
const diffDay = diffHour / 24
const diffMonth = diffDay / 30
const { dateSuffix } = GLOBAL_CONFIG
if (!more) return parseInt(dateDiff / day)
if (!more) return Math.floor(diffDay)
const monthCount = dateDiff / month
const dayCount = dateDiff / day
const hourCount = dateDiff / hour
const minuteCount = dateDiff / minute
if (monthCount > 12) return datePost.toISOString().slice(0, 10)
if (monthCount >= 1) return `${parseInt(monthCount)} ${dateSuffix.month}`
if (dayCount >= 1) return `${parseInt(dayCount)} ${dateSuffix.day}`
if (hourCount >= 1) return `${parseInt(hourCount)} ${dateSuffix.hour}`
if (minuteCount >= 1) return `${parseInt(minuteCount)} ${dateSuffix.min}`
if (diffMonth > 24) return datePost.toISOString().slice(0, 10)
if (diffMonth >= 3) return `${Math.floor(diffMonth)} ${dateSuffix.month}`
if (diffDay >= 3) return `${Math.floor(diffDay)} ${dateSuffix.day}`
if (diffHour >= 3) return `${Math.floor(diffHour)} ${dateSuffix.hour}`
if (diffMin >= 1) return `${Math.floor(diffMin)} ${dateSuffix.min}`
return dateSuffix.just
},
@@ -109,7 +121,7 @@
},
scrollToDest: (pos, time = 500) => {
const currentPos = window.pageYOffset
const currentPos = window.scrollY
const isNavFixed = document.getElementById('page-header').classList.contains('fixed')
if (currentPos > pos || isNavFixed) pos = pos - 70
@@ -121,22 +133,16 @@
return
}
let start = null
pos = +pos
window.requestAnimationFrame(function step (currentTime) {
start = !start ? currentTime : start
const progress = currentTime - start
if (currentPos < pos) {
window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos)
} else {
window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time))
const startTime = performance.now()
const animate = currentTime => {
const timeElapsed = currentTime - startTime
const progress = Math.min(timeElapsed / time, 1)
window.scrollTo(0, currentPos + (pos - currentPos) * progress)
if (progress < 1) {
requestAnimationFrame(animate)
}
if (progress < time) {
window.requestAnimationFrame(step)
} else {
window.scrollTo(0, pos)
}
})
}
requestAnimationFrame(animate)
},
animateIn: (ele, text) => {
@@ -179,7 +185,7 @@
loadLightbox: ele => {
const service = GLOBAL_CONFIG.lightbox
if (service === 'mediumZoom') {
if (service === 'medium_zoom') {
mediumZoom(ele, { background: 'var(--zoom-bg)' })
}
@@ -243,7 +249,7 @@
}
},
updateAnchor: (anchor) => {
updateAnchor: anchor => {
if (anchor !== window.location.hash) {
if (!anchor) anchor = location.pathname
const title = GLOBAL_CONFIG_SITE.title
@@ -254,33 +260,37 @@
}
},
getScrollPercent: (currentTop, ele) => {
const docHeight = ele.clientHeight
const winHeight = document.documentElement.clientHeight
const headerHeight = ele.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
return percentage
},
getScrollPercent: (() => {
let docHeight, winHeight, headerHeight, contentMath
return (currentTop, ele) => {
if (!docHeight || ele.clientHeight !== docHeight) {
docHeight = ele.clientHeight
winHeight = window.innerHeight
headerHeight = ele.offsetTop
contentMath = Math.max(docHeight - winHeight, document.documentElement.scrollHeight - winHeight)
}
const scrollPercent = (currentTop - headerHeight) / contentMath
return Math.max(0, Math.min(100, Math.round(scrollPercent * 100)))
}
})(),
addEventListenerPjax: (ele, event, fn, option = false) => {
ele.addEventListener(event, fn, option)
btf.addGlobalFn('pjax', () => {
btf.addGlobalFn('pjaxSendOnce', () => {
ele.removeEventListener(event, fn, option)
})
},
removeGlobalFnEvent: (key, parent = window) => {
const { globalFn = {} } = parent
const keyObj = globalFn[key] || {}
const keyArr = Object.keys(keyObj)
if (!keyArr.length) return
keyArr.forEach(i => {
keyObj[i]()
})
delete parent.globalFn[key]
const globalFn = parent.globalFn || {}
const keyObj = globalFn[key]
if (!keyObj) return
Object.keys(keyObj).forEach(i => keyObj[i]())
delete globalFn[key]
}
}