source
This commit is contained in:
@@ -181,6 +181,60 @@ if hexo-config('avatar.effect') == true
|
|||||||
.reward-main
|
.reward-main
|
||||||
animation: donate_effcet .3s .1s ease both
|
animation: donate_effcet .3s .1s ease both
|
||||||
|
|
||||||
|
.btn-effects
|
||||||
|
position: relative
|
||||||
|
overflow: hidden
|
||||||
|
transition: all .3s cubic-bezier(.4, 0, .2, 1)
|
||||||
|
transform: translateZ(0)
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, .15)
|
||||||
|
text-decoration: none
|
||||||
|
transform: translateY(-1px) scale(1.02)
|
||||||
|
|
||||||
|
&:active
|
||||||
|
transition-duration: .1s
|
||||||
|
transform: translateY(0) scale(.98)
|
||||||
|
|
||||||
|
i
|
||||||
|
display: inline-block
|
||||||
|
vertical-align: middle
|
||||||
|
transition: all .3s cubic-bezier(.4, 0, .2, 1)
|
||||||
|
|
||||||
|
&:hover i
|
||||||
|
animation: buttonIconBounce .6s ease-in-out
|
||||||
|
|
||||||
|
i + span
|
||||||
|
margin-left: 6px
|
||||||
|
vertical-align: middle
|
||||||
|
transition: margin-left .3s cubic-bezier(.4, 0, .2, 1)
|
||||||
|
|
||||||
|
&:hover i + span
|
||||||
|
margin-left: 8px
|
||||||
|
|
||||||
|
&::before
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
left: -100%
|
||||||
|
z-index: 1
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .2), transparent)
|
||||||
|
content: ''
|
||||||
|
transition: left .5s cubic-bezier(.4, 0, .2, 1)
|
||||||
|
|
||||||
|
&:hover::before
|
||||||
|
left: 100%
|
||||||
|
|
||||||
|
& > *
|
||||||
|
position: relative
|
||||||
|
z-index: 2
|
||||||
|
|
||||||
|
.btn-effects-large
|
||||||
|
&:hover
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 0, .2)
|
||||||
|
transform: translateY(-2px) scale(1.03)
|
||||||
|
|
||||||
@keyframes scroll-down-effect
|
@keyframes scroll-down-effect
|
||||||
0%
|
0%
|
||||||
opacity: .4
|
opacity: .4
|
||||||
@@ -278,3 +332,17 @@ if hexo-config('avatar.effect') == true
|
|||||||
|
|
||||||
100%
|
100%
|
||||||
transform: translateX(0)
|
transform: translateX(0)
|
||||||
|
|
||||||
|
@keyframes buttonIconBounce
|
||||||
|
0%,
|
||||||
|
100%
|
||||||
|
transform: translateY(0) scale(1)
|
||||||
|
|
||||||
|
25%
|
||||||
|
transform: translateY(-3px) scale(1.1) rotateZ(-5deg)
|
||||||
|
|
||||||
|
50%
|
||||||
|
transform: translateY(0) scale(1.05) rotateZ(0)
|
||||||
|
|
||||||
|
75%
|
||||||
|
transform: translateY(-1px) scale(1.02) rotateZ(2deg)
|
||||||
@@ -39,6 +39,65 @@
|
|||||||
--zoom-bg: #fff
|
--zoom-bg: #fff
|
||||||
--mark-bg: alpha($dark-black, .3)
|
--mark-bg: alpha($dark-black, .3)
|
||||||
|
|
||||||
|
// tags plugin
|
||||||
|
:root
|
||||||
|
--btn-color: $btn-color
|
||||||
|
--btn-default-color: $btn-default-color
|
||||||
|
--tags-blue-color: $tagsP-blue-color
|
||||||
|
--tags-blue-color-lighten: lighten($tagsP-blue-color, 85%)
|
||||||
|
--tags-pink-color: $tagsP-pink-color
|
||||||
|
--tags-pink-color-lighten: lighten($tagsP-pink-color, 85%)
|
||||||
|
--tags-red-color: $tagsP-red-color
|
||||||
|
--tags-red-color-lighten: lighten($tagsP-red-color, 85%)
|
||||||
|
--tags-orange-color: $tagsP-orange-color
|
||||||
|
--tags-orange-color-lighten: lighten($tagsP-orange-color, 85%)
|
||||||
|
--tags-purple-color: $tagsP-purple-color
|
||||||
|
--tags-purple-color-lighten: lighten($tagsP-purple-color, 85%)
|
||||||
|
--tags-green-color: $tagsP-green-color
|
||||||
|
--tags-green-color-lighten: lighten($tagsP-green-color, 85%)
|
||||||
|
--note-default-border: $note-default-border
|
||||||
|
--note-default-bg: $note-default-bg
|
||||||
|
--note-default-text: $note-default-text
|
||||||
|
--note-modern-default-border: $note-modern-default-border
|
||||||
|
--note-modern-default-bg: $note-modern-default-bg
|
||||||
|
--note-modern-default-text: $note-modern-default-text
|
||||||
|
--note-modern-default-hover: $note-modern-default-hover
|
||||||
|
--note-primary-border: $note-primary-border
|
||||||
|
--note-primary-bg: $note-primary-bg
|
||||||
|
--note-primary-text: $note-primary-text
|
||||||
|
--note-modern-primary-border: $note-modern-primary-border
|
||||||
|
--note-modern-primary-bg: $note-modern-primary-bg
|
||||||
|
--note-modern-primary-text: $note-modern-primary-text
|
||||||
|
--note-modern-primary-hover: $note-modern-primary-hover
|
||||||
|
--note-info-border: $note-info-border
|
||||||
|
--note-info-bg: $note-info-bg
|
||||||
|
--note-info-text: $note-info-text
|
||||||
|
--note-modern-info-border: $note-modern-info-border
|
||||||
|
--note-modern-info-bg: $note-modern-info-bg
|
||||||
|
--note-modern-info-text: $note-modern-info-text
|
||||||
|
--note-modern-info-hover: $note-modern-info-hover
|
||||||
|
--note-success-border: $note-success-border
|
||||||
|
--note-success-bg: $note-success-bg
|
||||||
|
--note-success-text: $note-success-text
|
||||||
|
--note-modern-success-border: $note-modern-success-border
|
||||||
|
--note-modern-success-bg: $note-modern-success-bg
|
||||||
|
--note-modern-success-text: $note-modern-success-text
|
||||||
|
--note-modern-success-hover: $note-modern-success-hover
|
||||||
|
--note-warning-border: $note-warning-border
|
||||||
|
--note-warning-bg: $note-warning-bg
|
||||||
|
--note-warning-text: $note-warning-text
|
||||||
|
--note-modern-warning-border: $note-modern-warning-border
|
||||||
|
--note-modern-warning-bg: $note-modern-warning-bg
|
||||||
|
--note-modern-warning-text: $note-modern-warning-text
|
||||||
|
--note-modern-warning-hover: $note-modern-warning-hover
|
||||||
|
--note-danger-border: $note-danger-border
|
||||||
|
--note-danger-bg: $note-danger-bg
|
||||||
|
--note-danger-text: $note-danger-text
|
||||||
|
--note-modern-danger-border: $note-modern-danger-border
|
||||||
|
--note-modern-danger-bg: $note-modern-danger-bg
|
||||||
|
--note-modern-danger-text: $note-modern-danger-text
|
||||||
|
--note-modern-danger-hover: $note-modern-danger-hover
|
||||||
|
|
||||||
body
|
body
|
||||||
position: relative
|
position: relative
|
||||||
overflow-y: scroll
|
overflow-y: scroll
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
text-align: center
|
text-align: center
|
||||||
line-height: 2.4
|
line-height: 2.4
|
||||||
addBorderRadius(7)
|
addBorderRadius(7)
|
||||||
|
@extend .btn-effects
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
background-color: var(--btn-hover-color)
|
background-color: var(--btn-hover-color)
|
||||||
@@ -180,6 +181,11 @@
|
|||||||
.card-category-list
|
.card-category-list
|
||||||
&.child
|
&.child
|
||||||
padding: 0 0 0 16px
|
padding: 0 0 0 16px
|
||||||
|
overflow: hidden
|
||||||
|
max-height: 0
|
||||||
|
opacity: 0
|
||||||
|
visibility: hidden
|
||||||
|
transition: max-height .3s ease, opacity .3s ease
|
||||||
|
|
||||||
> .parent
|
> .parent
|
||||||
> a
|
> a
|
||||||
@@ -188,7 +194,9 @@
|
|||||||
transform: rotate(-90deg)
|
transform: rotate(-90deg)
|
||||||
|
|
||||||
& + .child
|
& + .child
|
||||||
display: block
|
max-height: 1000px
|
||||||
|
opacity: 1
|
||||||
|
visibility: visible
|
||||||
|
|
||||||
.card-category-list
|
.card-category-list
|
||||||
&-name
|
&-name
|
||||||
@@ -207,7 +215,9 @@
|
|||||||
|
|
||||||
if hexo-config('aside.card_categories.expand') == false
|
if hexo-config('aside.card_categories.expand') == false
|
||||||
> .child
|
> .child
|
||||||
display: none
|
max-height: 0
|
||||||
|
opacity: 0
|
||||||
|
visibility: hidden
|
||||||
|
|
||||||
.card-webinfo
|
.card-webinfo
|
||||||
.webinfo
|
.webinfo
|
||||||
|
|||||||
@@ -1,45 +1,95 @@
|
|||||||
if hexo-config('preloader')
|
if hexo-config('preloader.enable') && hexo-config('preloader.source') == 1
|
||||||
.loading-bg
|
.loading-bg
|
||||||
display: flex;
|
position: fixed
|
||||||
width: 100%;
|
z-index: 1000
|
||||||
height: 100%;
|
width: 50%
|
||||||
position: fixed;
|
height: 100%
|
||||||
background: #f0f0f2;
|
background-color: var(--preloader-bg)
|
||||||
z-index: 1001;
|
|
||||||
opacity: 1;
|
|
||||||
transition: .3s;
|
|
||||||
|
|
||||||
#loading-box
|
#loading-box
|
||||||
.loading-img
|
.loading-left-bg
|
||||||
width: 100px;
|
@extend .loading-bg
|
||||||
height: 100px;
|
|
||||||
border-radius: 50%;
|
.loading-right-bg
|
||||||
margin: auto;
|
@extend .loading-bg
|
||||||
border: 4px solid #f0f0f2;
|
right: 0
|
||||||
animation-duration: .3s;
|
|
||||||
animation-name: loadingAction;
|
.spinner-box
|
||||||
animation-iteration-count: infinite;
|
position: fixed
|
||||||
animation-direction: alternate;
|
z-index: 1001
|
||||||
.loading-image-dot
|
display: flex
|
||||||
width: 30px;
|
justify-content: center
|
||||||
height: 30px;
|
align-items: center
|
||||||
background: #6bdf8f;
|
width: 100%
|
||||||
position: absolute;
|
height: 100vh
|
||||||
border-radius: 50%;
|
|
||||||
border: 6px solid #fff;
|
.configure-border-1
|
||||||
top: 50%;
|
position: absolute
|
||||||
left: 50%;
|
padding: 3px
|
||||||
transform: translate(18px, 24px);
|
width: 115px
|
||||||
|
height: 115px
|
||||||
|
background: #ffab91
|
||||||
|
animation: configure-clockwise 3s ease-in-out 0s infinite alternate
|
||||||
|
|
||||||
|
.configure-border-2
|
||||||
|
left: -115px
|
||||||
|
padding: 3px
|
||||||
|
width: 115px
|
||||||
|
height: 115px
|
||||||
|
background: rgb(63, 249, 220)
|
||||||
|
transform: rotate(45deg)
|
||||||
|
animation: configure-xclockwise 3s ease-in-out 0s infinite alternate
|
||||||
|
|
||||||
|
.loading-word
|
||||||
|
position: absolute
|
||||||
|
color: var(--preloader-color)
|
||||||
|
font-size: 16px
|
||||||
|
|
||||||
|
.configure-core
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
|
background-color: var(--preloader-bg)
|
||||||
|
|
||||||
&.loaded
|
&.loaded
|
||||||
.loading-bg
|
.loading-left-bg
|
||||||
opacity: 0;
|
transition: all .5s
|
||||||
z-index: -1000;
|
transform: translate(-100%, 0)
|
||||||
|
|
||||||
@keyframes loadingAction
|
.loading-right-bg
|
||||||
0% {
|
transition: all .5s
|
||||||
opacity: 1;
|
transform: translate(100%, 0)
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
.spinner-box
|
||||||
opacity: .4;
|
display: none
|
||||||
}
|
|
||||||
|
@keyframes configure-clockwise
|
||||||
|
0%
|
||||||
|
transform: rotate(0)
|
||||||
|
|
||||||
|
25%
|
||||||
|
transform: rotate(90deg)
|
||||||
|
|
||||||
|
50%
|
||||||
|
transform: rotate(180deg)
|
||||||
|
|
||||||
|
75%
|
||||||
|
transform: rotate(270deg)
|
||||||
|
|
||||||
|
100%
|
||||||
|
transform: rotate(360deg)
|
||||||
|
|
||||||
|
@keyframes configure-xclockwise
|
||||||
|
0%
|
||||||
|
transform: rotate(45deg)
|
||||||
|
|
||||||
|
25%
|
||||||
|
transform: rotate(-45deg)
|
||||||
|
|
||||||
|
50%
|
||||||
|
transform: rotate(-135deg)
|
||||||
|
|
||||||
|
75%
|
||||||
|
transform: rotate(-225deg)
|
||||||
|
|
||||||
|
100%
|
||||||
|
transform: rotate(-315deg)
|
||||||
|
|||||||
@@ -15,9 +15,12 @@
|
|||||||
color: var(--btn-color)
|
color: var(--btn-color)
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
addBorderRadius()
|
addBorderRadius()
|
||||||
|
@extend .btn-effects
|
||||||
|
@extend .btn-effects-large
|
||||||
|
|
||||||
i
|
i
|
||||||
margin-right: 5px
|
margin-right: 5px
|
||||||
|
vertical-align: baseline
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
.reward-button
|
.reward-button
|
||||||
@@ -28,7 +31,7 @@
|
|||||||
|
|
||||||
.reward-main
|
.reward-main
|
||||||
position: absolute
|
position: absolute
|
||||||
bottom: 40px
|
bottom: 50px
|
||||||
left: 0
|
left: 0
|
||||||
z-index: 100
|
z-index: 100
|
||||||
display: none
|
display: none
|
||||||
|
|||||||
@@ -38,10 +38,14 @@
|
|||||||
font-size: 16px
|
font-size: 16px
|
||||||
line-height: w
|
line-height: w
|
||||||
addBorderRadius(5)
|
addBorderRadius(5)
|
||||||
|
@extend .btn-effects
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
background-color: var(--btn-hover-color)
|
background-color: var(--btn-hover-color)
|
||||||
|
|
||||||
|
i
|
||||||
|
vertical-align: baseline
|
||||||
|
|
||||||
#mobile-toc-button
|
#mobile-toc-button
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
@@ -54,19 +58,52 @@
|
|||||||
|
|
||||||
if hexo-config('rightside_scroll_percent')
|
if hexo-config('rightside_scroll_percent')
|
||||||
#go-up
|
#go-up
|
||||||
|
position: relative
|
||||||
|
|
||||||
.scroll-percent
|
.scroll-percent
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
left: 0
|
||||||
display: none
|
display: none
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
|
opacity: 0
|
||||||
|
transition: all .4s cubic-bezier(.4, 0, .2, 1)
|
||||||
|
transform: scale(.8)
|
||||||
|
|
||||||
|
i
|
||||||
|
position: relative
|
||||||
|
z-index: 1
|
||||||
|
width: 100%
|
||||||
|
opacity: 1
|
||||||
|
transition: all .4s cubic-bezier(.4, 0, .2, 1)
|
||||||
|
transform: scale(1)
|
||||||
|
|
||||||
&.show-percent
|
&.show-percent
|
||||||
.scroll-percent
|
.scroll-percent
|
||||||
display: block
|
display: block
|
||||||
|
opacity: 1
|
||||||
|
transform: scale(1)
|
||||||
|
animation: fadeInScale .4s ease-out
|
||||||
|
|
||||||
& + i
|
i
|
||||||
display: none
|
opacity: 0
|
||||||
|
transform: scale(.8)
|
||||||
|
|
||||||
&:hover
|
&:hover.show-percent
|
||||||
.scroll-percent
|
.scroll-percent
|
||||||
display: none
|
opacity: 0
|
||||||
|
transform: scale(.8)
|
||||||
|
|
||||||
& + i
|
i
|
||||||
display: block
|
opacity: 1 !important
|
||||||
|
transform: scale(1) !important
|
||||||
|
|
||||||
|
@keyframes fadeInScale
|
||||||
|
from
|
||||||
|
opacity: 0
|
||||||
|
transform: scale(.8)
|
||||||
|
|
||||||
|
to
|
||||||
|
opacity: 1
|
||||||
|
transform: scale(1)
|
||||||
@@ -38,8 +38,7 @@
|
|||||||
background: var(--sidebar-menu-bg)
|
background: var(--sidebar-menu-bg)
|
||||||
box-shadow: 0 0 1px 1px rgba(7, 17, 27, .05)
|
box-shadow: 0 0 1px 1px rgba(7, 17, 27, .05)
|
||||||
addBorderRadius(10)
|
addBorderRadius(10)
|
||||||
.menus_item
|
|
||||||
margin: 10px 0
|
|
||||||
.site-page
|
.site-page
|
||||||
@extend .limit-one-line
|
@extend .limit-one-line
|
||||||
position: relative
|
position: relative
|
||||||
@@ -50,20 +49,17 @@
|
|||||||
font-size: 1.15em
|
font-size: 1.15em
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
addBorderRadius(6)
|
addBorderRadius(6)
|
||||||
border: var(--icat-style-border-always)
|
|
||||||
background: var(--icat-essay-card-bg)
|
|
||||||
font-size: 14px
|
|
||||||
border-radius: 12px
|
|
||||||
|
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
background: var(--text-bg-hover)
|
background: var(--text-bg-hover)
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, .1)
|
||||||
color: var(--white)
|
color: var(--white)
|
||||||
|
transition: all .2s ease
|
||||||
|
transform: translateX(3px)
|
||||||
|
|
||||||
i:first-child
|
i:first-child
|
||||||
width: 15%
|
width: 15%
|
||||||
text-align: left
|
text-align: left
|
||||||
padding-left: 10px
|
|
||||||
|
|
||||||
&.group
|
&.group
|
||||||
& > i:last-child
|
& > i:last-child
|
||||||
@@ -77,34 +73,25 @@
|
|||||||
transform: rotate(90deg)
|
transform: rotate(90deg)
|
||||||
|
|
||||||
& + .menus_item_child
|
& + .menus_item_child
|
||||||
display: none
|
overflow: hidden
|
||||||
|
max-height: 0
|
||||||
|
opacity: 0
|
||||||
|
transform: scaleY(0)
|
||||||
|
transform-origin: top
|
||||||
|
|
||||||
.menus_item_child
|
.menus_item_child
|
||||||
margin: 0
|
margin: 0
|
||||||
padding-left: 25px
|
padding-left: 25px
|
||||||
|
max-height: 0
|
||||||
list-style: none
|
list-style: none
|
||||||
|
opacity: 0
|
||||||
|
transition: transform .3s ease, opacity .3s ease, max-height .3s ease
|
||||||
|
transform: scaleY(0)
|
||||||
|
transform-origin: top
|
||||||
|
will-change: transform, opacity, max-height
|
||||||
|
|
||||||
#sidebar
|
// 當父元素沒有 .hide 類時,顯示子目錄
|
||||||
#sidebar-menus
|
.site-page.group:not(.hide) + .menus_item_child
|
||||||
.icat_menus_item
|
max-height: 1000px
|
||||||
display: inline-block
|
opacity: 1
|
||||||
width: 50%
|
transform: scaleY(1)
|
||||||
|
|
||||||
.site-page
|
|
||||||
text-align: center
|
|
||||||
margin: 4px
|
|
||||||
display: flex
|
|
||||||
flex-direction: column
|
|
||||||
align-items: center
|
|
||||||
padding: 8px 0
|
|
||||||
border-radius: 12px
|
|
||||||
font-size: 14px
|
|
||||||
|
|
||||||
i:first-child
|
|
||||||
padding-left: 0
|
|
||||||
|
|
||||||
& > .icat-essay
|
|
||||||
font-weight: 500
|
|
||||||
|
|
||||||
span
|
|
||||||
margin-top: -8px
|
|
||||||
@@ -33,6 +33,56 @@ if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
|
|||||||
--timeline-bg: lighten(#121212, 5)
|
--timeline-bg: lighten(#121212, 5)
|
||||||
--zoom-bg: #121212
|
--zoom-bg: #121212
|
||||||
--mark-bg: alpha($dark-black, .6)
|
--mark-bg: alpha($dark-black, .6)
|
||||||
|
--btn-color: darken($btn-color, 20%)
|
||||||
|
--btn-default-color: lighten($btn-default-color, 20%)
|
||||||
|
--tags-blue-color: desaturate(darken($tagsP-blue-color, 20%), 25%)
|
||||||
|
--tags-blue-color-lighten: rgba(66, 139, 202, .15)
|
||||||
|
--tags-pink-color: desaturate(darken($tagsP-pink-color, 22%), 30%)
|
||||||
|
--tags-pink-color-lighten: rgba(255, 105, 180, .15)
|
||||||
|
--tags-red-color: desaturate(darken($tagsP-red-color, 25%), 28%)
|
||||||
|
--tags-red-color-lighten: rgba(255, 0, 0, .15)
|
||||||
|
--tags-orange-color: desaturate(darken($tagsP-orange-color, 22%), 32%)
|
||||||
|
--tags-orange-color-lighten: rgba(255, 140, 0, .15)
|
||||||
|
--tags-purple-color: desaturate(darken($tagsP-purple-color, 18%), 30%)
|
||||||
|
--tags-purple-color-lighten: rgba(111, 66, 193, .15)
|
||||||
|
--tags-green-color: desaturate(darken($tagsP-green-color, 20%), 28%)
|
||||||
|
--tags-green-color-lighten: rgba(92, 184, 92, .15)
|
||||||
|
--note-default-border: $note-dark-default-border
|
||||||
|
--note-default-bg: $note-dark-default-bg
|
||||||
|
--note-default-text: $note-dark-default-text
|
||||||
|
--note-modern-default-border: $note-dark-modern-default-border
|
||||||
|
--note-modern-default-bg: $note-dark-modern-default-bg
|
||||||
|
--note-modern-default-text: $note-dark-modern-default-text
|
||||||
|
--note-primary-border: $note-dark-primary-border
|
||||||
|
--note-primary-bg: $note-dark-primary-bg
|
||||||
|
--note-primary-text: $note-dark-primary-text
|
||||||
|
--note-modern-primary-border: $note-dark-modern-primary-border
|
||||||
|
--note-modern-primary-bg: $note-dark-modern-primary-bg
|
||||||
|
--note-modern-primary-text: $note-dark-modern-primary-text
|
||||||
|
--note-info-border: $note-dark-info-border
|
||||||
|
--note-info-bg: $note-dark-info-bg
|
||||||
|
--note-info-text: $note-dark-info-text
|
||||||
|
--note-modern-info-border: $note-dark-modern-info-border
|
||||||
|
--note-modern-info-bg: $note-dark-modern-info-bg
|
||||||
|
--note-modern-info-text: $note-dark-modern-info-text
|
||||||
|
--note-success-border: $note-dark-success-border
|
||||||
|
--note-success-bg: $note-dark-success-bg
|
||||||
|
--note-success-text: $note-dark-success-text
|
||||||
|
--note-modern-success-border: $note-dark-modern-success-border
|
||||||
|
--note-modern-success-bg: $note-dark-modern-success-bg
|
||||||
|
--note-modern-success-text: $note-dark-modern-success-text
|
||||||
|
--note-warning-border: $note-dark-warning-border
|
||||||
|
--note-warning-bg: $note-dark-warning-bg
|
||||||
|
--note-warning-text: $note-dark-warning-text
|
||||||
|
--note-modern-warning-border: $note-dark-modern-warning-border
|
||||||
|
--note-modern-warning-bg: $note-dark-modern-warning-bg
|
||||||
|
--note-modern-warning-text: $note-dark-modern-warning-text
|
||||||
|
--note-danger-border: $note-dark-danger-border
|
||||||
|
--note-danger-bg: $note-dark-danger-bg
|
||||||
|
--note-danger-text: $note-dark-danger-text
|
||||||
|
--note-modern-danger-border: $note-dark-modern-danger-border
|
||||||
|
--note-modern-danger-bg: $note-dark-modern-danger-bg
|
||||||
|
--note-modern-danger-text: $note-dark-modern-danger-text
|
||||||
|
|
||||||
#web_bg:before
|
#web_bg:before
|
||||||
position: absolute
|
position: absolute
|
||||||
@@ -78,23 +128,17 @@ if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
|
|||||||
#switch-btn
|
#switch-btn
|
||||||
filter: brightness(.8)
|
filter: brightness(.8)
|
||||||
|
|
||||||
// note
|
|
||||||
if hexo-config('note.style') == 'modern' || hexo-config('note.style') == 'flat'
|
|
||||||
.note
|
|
||||||
filter: brightness(.8)
|
|
||||||
|
|
||||||
// hide-tags
|
// hide-tags
|
||||||
.hide-button,
|
.hide-button,
|
||||||
.btn-beautify,
|
|
||||||
.hl-label,
|
|
||||||
#post-outdate-notice,
|
#post-outdate-notice,
|
||||||
.error-img,
|
.error-img,
|
||||||
.container iframe,
|
.container iframe,
|
||||||
.gist,
|
.gist,
|
||||||
.ads-wrap
|
.ads-wrap,
|
||||||
|
.tag-cloud-list > a
|
||||||
filter: brightness(.8)
|
filter: brightness(.8)
|
||||||
|
|
||||||
img
|
img:not(.cover)
|
||||||
if hexo-config('lazyload.enable') && hexo-config('lazyload.blur') && !hexo-config('lazyload.placeholder')
|
if hexo-config('lazyload.enable') && hexo-config('lazyload.blur') && !hexo-config('lazyload.placeholder')
|
||||||
filter: blur(0) brightness(.8)
|
filter: blur(0) brightness(.8)
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
padding: 20px 5px
|
padding: 20px 5px
|
||||||
|
|
||||||
+minWidth2000()
|
+minWidth2000()
|
||||||
max-width: 70%
|
max-width: 60%
|
||||||
|
|
||||||
& > div:first-child:not(.nc)
|
& > div:first-child:not(.nc)
|
||||||
@extend .cardHover
|
@extend .cardHover
|
||||||
|
|||||||
@@ -76,3 +76,110 @@
|
|||||||
|
|
||||||
&.no-comment
|
&.no-comment
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
|
.shuoshuo-navigation
|
||||||
|
display: flex
|
||||||
|
justify-content: center
|
||||||
|
align-items: center
|
||||||
|
margin-top: 20px
|
||||||
|
padding: 20px 0
|
||||||
|
|
||||||
|
button
|
||||||
|
display: flex
|
||||||
|
justify-content: center
|
||||||
|
align-items: center
|
||||||
|
width: 2.7em
|
||||||
|
height: 2.7em
|
||||||
|
background-color: var(--btn-bg)
|
||||||
|
color: var(--btn-color)
|
||||||
|
font-size: .9em
|
||||||
|
line-height: 2.5em
|
||||||
|
transition: all .2s ease-in-out
|
||||||
|
addBorderRadius(6)
|
||||||
|
|
||||||
|
&:not(:disabled)
|
||||||
|
@extend .btn-effects
|
||||||
|
|
||||||
|
&:hover:not(:disabled)
|
||||||
|
background-color: var(--btn-hover-color)
|
||||||
|
|
||||||
|
&:disabled
|
||||||
|
background: #f5f5f5
|
||||||
|
color: #ccc
|
||||||
|
opacity: .5
|
||||||
|
cursor: not-allowed
|
||||||
|
|
||||||
|
.shuoshuo-page-info
|
||||||
|
margin: 0 15px
|
||||||
|
color: #858585
|
||||||
|
white-space: nowrap
|
||||||
|
font-size: .9em
|
||||||
|
|
||||||
|
.shuoshuo-page-input
|
||||||
|
margin-right: 12px
|
||||||
|
padding: 0 15px
|
||||||
|
height: 2.7em
|
||||||
|
border: 1px solid var(--btn-bg)
|
||||||
|
background: var(--card-bg)
|
||||||
|
color: #858585
|
||||||
|
text-align: center
|
||||||
|
font-size: .9em
|
||||||
|
transition: all .2s ease-in-out
|
||||||
|
addBorderRadius(6)
|
||||||
|
|
||||||
|
&:focus
|
||||||
|
outline: none
|
||||||
|
border-width: 2px
|
||||||
|
|
||||||
|
&::placeholder
|
||||||
|
color: transparent
|
||||||
|
|
||||||
|
/* 隱藏 number 輸入框的上下箭頭 */
|
||||||
|
&::-webkit-outer-spin-button,
|
||||||
|
&::-webkit-inner-spin-button
|
||||||
|
margin: 0
|
||||||
|
-webkit-appearance: none
|
||||||
|
|
||||||
|
/* Firefox */
|
||||||
|
-moz-appearance: textfield
|
||||||
|
|
||||||
|
/* 當作為頁碼按鈕時的樣式 */
|
||||||
|
&.shuoshuo-page-num
|
||||||
|
min-width: 40px
|
||||||
|
width: 40px
|
||||||
|
border: none
|
||||||
|
background: $light-blue
|
||||||
|
color: var(--white)
|
||||||
|
font-weight: 500
|
||||||
|
cursor: text
|
||||||
|
|
||||||
|
&:focus
|
||||||
|
border: 1px solid $light-blue
|
||||||
|
background: var(--white)
|
||||||
|
color: #333
|
||||||
|
|
||||||
|
/* 超出範圍時的紅色樣式 */
|
||||||
|
&.invalid
|
||||||
|
border-color: #ff4757
|
||||||
|
background-color: #ffeaea
|
||||||
|
color: #ff4757
|
||||||
|
animation: shake .5s ease-in-out
|
||||||
|
|
||||||
|
/* 震動動畫 */
|
||||||
|
@keyframes shake
|
||||||
|
0%,
|
||||||
|
100%
|
||||||
|
transform: translateX(0)
|
||||||
|
|
||||||
|
10%,
|
||||||
|
30%,
|
||||||
|
50%,
|
||||||
|
70%,
|
||||||
|
90%
|
||||||
|
transform: translateX(-2px)
|
||||||
|
|
||||||
|
20%,
|
||||||
|
40%,
|
||||||
|
60%,
|
||||||
|
80%
|
||||||
|
transform: translateX(2px)
|
||||||
|
|||||||
@@ -1,27 +1,91 @@
|
|||||||
.tag-cloud
|
.tag-cloud
|
||||||
&-list
|
&-list
|
||||||
|
animation: tagsFadeIn .6s cubic-bezier(.4, 0, .2, 1)
|
||||||
|
|
||||||
|
&:hover a:not(:hover)
|
||||||
|
opacity: .7
|
||||||
|
transform: scale(.98)
|
||||||
|
|
||||||
a
|
a
|
||||||
|
position: relative
|
||||||
display: inline-block
|
display: inline-block
|
||||||
margin: 2px
|
margin: 5px
|
||||||
padding: 2px 7px
|
padding: 3px 12px
|
||||||
line-height: 1.7
|
line-height: 1.7
|
||||||
transition: all .3s
|
transition: all .3s cubic-bezier(.4, 0, .2, 1)
|
||||||
addBorderRadius(5)
|
addBorderRadius(7)
|
||||||
|
overflow: hidden
|
||||||
|
color: white
|
||||||
|
transform: translateY(0) scale(1)
|
||||||
|
will-change: transform, background-color, box-shadow
|
||||||
|
|
||||||
|
&::before
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
left: -100%
|
||||||
|
z-index: -1
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .1), transparent)
|
||||||
|
content: ''
|
||||||
|
transition: left .6s cubic-bezier(.4, 0, .2, 1)
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
background: var(--btn-bg) !important
|
background: var(--btn-hover-color) !important
|
||||||
box-shadow: 2px 2px 6px rgba(0, 0, 0, .2)
|
box-shadow:
|
||||||
|
0 6px 20px rgba(0, 0, 0, .12),
|
||||||
|
0 4px 8px rgba(0, 0, 0, .08),
|
||||||
|
0 0 0 1px rgba(255, 255, 255, .05)
|
||||||
color: var(--btn-color) !important
|
color: var(--btn-color) !important
|
||||||
|
transform: translateY(-2px) scale(1.02)
|
||||||
|
|
||||||
|
&::before
|
||||||
|
left: 100%
|
||||||
|
|
||||||
|
&:active
|
||||||
|
box-shadow:
|
||||||
|
0 3px 8px rgba(0, 0, 0, .15),
|
||||||
|
0 1px 3px rgba(0, 0, 0, .1)
|
||||||
|
transition: all .15s cubic-bezier(.4, 0, .2, 1)
|
||||||
|
transform: translateY(-1px) scale(.98)
|
||||||
|
|
||||||
+maxWidth768()
|
+maxWidth768()
|
||||||
zoom: .85
|
zoom: .85
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
transform: translateY(-1px) scale(1.01)
|
||||||
|
|
||||||
|
&:active
|
||||||
|
transform: translateY(0) scale(.99)
|
||||||
|
|
||||||
|
&::before
|
||||||
|
display: none
|
||||||
|
|
||||||
&-title
|
&-title
|
||||||
font-size: 2.57em
|
font-size: 2.57em
|
||||||
|
animation: titleSlideIn .8s cubic-bezier(.4, 0, .2, 1)
|
||||||
|
|
||||||
+maxWidth768()
|
+maxWidth768()
|
||||||
font-size: 2em
|
font-size: 2em
|
||||||
|
|
||||||
|
@keyframes tagsFadeIn
|
||||||
|
from
|
||||||
|
opacity: 0
|
||||||
|
transform: translateY(20px)
|
||||||
|
|
||||||
|
to
|
||||||
|
opacity: 1
|
||||||
|
transform: translateY(0)
|
||||||
|
|
||||||
|
@keyframes titleSlideIn
|
||||||
|
from
|
||||||
|
opacity: 0
|
||||||
|
transform: translateX(-30px)
|
||||||
|
|
||||||
|
to
|
||||||
|
opacity: 1
|
||||||
|
transform: translateX(0)
|
||||||
|
|
||||||
.page-title
|
.page-title
|
||||||
& + .tag-cloud-list
|
& + .tag-cloud-list
|
||||||
text-align: left
|
text-align: left
|
||||||
|
|||||||
@@ -1,93 +1,13 @@
|
|||||||
#algolia-search
|
#algolia-search
|
||||||
.search-dialog
|
.search-dialog
|
||||||
.ais-SearchBox
|
|
||||||
input
|
|
||||||
padding: 5px 14px
|
|
||||||
width: 100%
|
|
||||||
outline: none
|
|
||||||
border: 2px solid $search-color
|
|
||||||
border-radius: 40px
|
|
||||||
background: var(--search-bg)
|
|
||||||
color: var(--search-input-color)
|
|
||||||
|
|
||||||
.ais-SearchBox-loadingIndicator
|
|
||||||
position: absolute
|
|
||||||
top: 18px
|
|
||||||
left: 67px
|
|
||||||
|
|
||||||
.ais-Hits-list
|
.ais-Hits-list
|
||||||
margin: 0
|
+maxWidth768()
|
||||||
padding: 0
|
min-height: calc(var(--search-height) - 245px)
|
||||||
@extend .list-beauty
|
|
||||||
|
|
||||||
a
|
|
||||||
color: var(--search-a-color)
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
color: $search-color
|
|
||||||
|
|
||||||
mark
|
|
||||||
background: transparent
|
|
||||||
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-word
|
|
||||||
|
|
||||||
.ais-Pagination
|
|
||||||
margin: 15px 0 0
|
|
||||||
padding: 0
|
|
||||||
text-align: center
|
|
||||||
|
|
||||||
.ais-Pagination-list
|
|
||||||
margin: 0
|
|
||||||
padding: 0
|
|
||||||
list-style: none
|
|
||||||
|
|
||||||
.ais-Pagination-item
|
|
||||||
display: inline
|
|
||||||
margin: 0 4px
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
.ais-Pagination-link
|
|
||||||
display: inline-block
|
|
||||||
min-width: 24px
|
|
||||||
height: 24px
|
|
||||||
text-align: center
|
|
||||||
line-height: 24px
|
|
||||||
addBorderRadius()
|
|
||||||
|
|
||||||
.ais-Pagination-item--selected
|
|
||||||
a
|
|
||||||
background: $theme-paginator-color
|
|
||||||
color: #eee
|
|
||||||
cursor: default
|
|
||||||
|
|
||||||
.ais-Pagination-item--disabled
|
|
||||||
visibility: hidden
|
|
||||||
|
|
||||||
#algolia-hits
|
|
||||||
> div
|
|
||||||
overflow-y: overlay
|
|
||||||
margin: 0 -20px
|
|
||||||
padding: 0 22px
|
|
||||||
max-height: calc(80vh - 220px)
|
|
||||||
|
|
||||||
+maxWidth768()
|
|
||||||
max-height: none
|
|
||||||
height: calc(var(--search-height) - 235px)
|
|
||||||
|
|
||||||
#algolia-info
|
#algolia-info
|
||||||
div
|
|
||||||
display: inline
|
|
||||||
|
|
||||||
.algolia-poweredBy
|
.algolia-poweredBy
|
||||||
float: right
|
float: right
|
||||||
vertical-align: text-top
|
padding-top: 2px
|
||||||
|
|
||||||
svg
|
svg
|
||||||
height: 1.1em
|
height: 1.1em
|
||||||
@@ -20,22 +20,174 @@
|
|||||||
border-radius: 0
|
border-radius: 0
|
||||||
|
|
||||||
.search-nav
|
.search-nav
|
||||||
margin: 0 0 14px
|
display: flex
|
||||||
|
justify-content: space-between
|
||||||
|
align-items: center
|
||||||
|
margin-bottom: 14px
|
||||||
color: $search-color
|
color: $search-color
|
||||||
font-size: 1.4em
|
font-size: 1.4em
|
||||||
line-height: 1
|
line-height: 1
|
||||||
|
|
||||||
.search-dialog-title
|
.search-dialog-title
|
||||||
margin-right: 10px
|
margin-right: 4px
|
||||||
|
|
||||||
|
#loading-status
|
||||||
|
&[hidden]
|
||||||
|
display: none !important
|
||||||
|
|
||||||
.search-close-button
|
.search-close-button
|
||||||
float: right
|
flex: 1
|
||||||
color: $grey
|
color: $grey
|
||||||
transition: color .2s ease-in-out
|
text-align: right
|
||||||
|
transition: all .2s ease
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
color: $search-color
|
color: $search-color
|
||||||
|
|
||||||
|
.local-search-input,
|
||||||
|
#algolia-search-input
|
||||||
|
margin: 0 auto
|
||||||
|
max-width: 100%
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
input,
|
||||||
|
.ais-SearchBox-input
|
||||||
|
padding: 5px 14px
|
||||||
|
width: 100%
|
||||||
|
outline: none
|
||||||
|
border: 2px solid $search-color
|
||||||
|
border-radius: 40px
|
||||||
|
background: var(--search-bg)
|
||||||
|
color: var(--search-input-color)
|
||||||
|
-webkit-appearance: none
|
||||||
|
|
||||||
|
&::placeholder
|
||||||
|
color: var(--text-color)
|
||||||
|
|
||||||
|
.search-result-list,
|
||||||
|
.ais-Hits-list
|
||||||
|
overflow-y: overlay
|
||||||
|
margin: 0 -20px
|
||||||
|
padding: 0 22px
|
||||||
|
max-height: calc(80vh - 220px)
|
||||||
|
|
||||||
|
.local-search-hit-item,
|
||||||
|
.ais-Hits-item
|
||||||
|
display: flex
|
||||||
|
align-items: flex-start
|
||||||
|
margin: 3px 0
|
||||||
|
line-height: 1.8
|
||||||
|
transition: all .2s ease-in-out
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
transform: translateY(-1px)
|
||||||
|
|
||||||
|
&:not([value])::before
|
||||||
|
display: none
|
||||||
|
|
||||||
|
&[value]::before
|
||||||
|
display: inline-flex
|
||||||
|
flex-shrink: 0
|
||||||
|
justify-content: center
|
||||||
|
align-items: center
|
||||||
|
margin-right: 6px
|
||||||
|
margin-top: 3px
|
||||||
|
min-width: 24px
|
||||||
|
color: $search-color
|
||||||
|
content: attr(value) '.'
|
||||||
|
font-weight: bold
|
||||||
|
font-style: italic
|
||||||
|
font-size: .9em
|
||||||
|
|
||||||
|
&::marker
|
||||||
|
content: none
|
||||||
|
|
||||||
|
a
|
||||||
|
flex: 1
|
||||||
|
color: var(--search-a-color)
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
color: $search-color
|
||||||
|
|
||||||
|
.search-result-title,
|
||||||
|
.algolia-hits-item-title
|
||||||
|
font-weight: 600
|
||||||
|
|
||||||
|
.search-result,
|
||||||
|
.algolia-hit-item-content
|
||||||
|
margin: 0 0 8px
|
||||||
|
word-break: break-all
|
||||||
|
font-size: .9em
|
||||||
|
|
||||||
|
.ais-Pagination
|
||||||
|
margin: 15px 0 0
|
||||||
|
padding: 0
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
.ais-Pagination-list
|
||||||
|
display: flex
|
||||||
|
flex-wrap: wrap
|
||||||
|
justify-content: center
|
||||||
|
align-items: center
|
||||||
|
margin: 0
|
||||||
|
padding: 0
|
||||||
|
list-style: none
|
||||||
|
gap: 6px
|
||||||
|
|
||||||
|
.ais-Pagination-item
|
||||||
|
display: flex
|
||||||
|
padding: 0
|
||||||
|
|
||||||
|
&:not(.ais-Pagination-item--selected):not(.ais-Pagination-item--ellipsis):not(.ais-Pagination-item--disabled)
|
||||||
|
.ais-Pagination-link:hover
|
||||||
|
background: var(--btn-hover-color)
|
||||||
|
transform: translateY(-1px)
|
||||||
|
|
||||||
|
.ais-Pagination-link
|
||||||
|
display: inline-flex
|
||||||
|
justify-content: center
|
||||||
|
align-items: center
|
||||||
|
padding: 4px 8px
|
||||||
|
min-width: 28px
|
||||||
|
height: 28px
|
||||||
|
border-radius: 6px
|
||||||
|
background: var(--btn-bg)
|
||||||
|
color: var(--btn-color)
|
||||||
|
transition: all .2s ease
|
||||||
|
|
||||||
|
&.ais-Pagination-link--disabled
|
||||||
|
opacity: .3
|
||||||
|
cursor: not-allowed
|
||||||
|
|
||||||
|
i
|
||||||
|
font-size: 12px
|
||||||
|
|
||||||
|
.ais-Pagination-item--selected
|
||||||
|
.ais-Pagination-link
|
||||||
|
background: $theme-paginator-color
|
||||||
|
font-weight: 600
|
||||||
|
cursor: default
|
||||||
|
|
||||||
|
.ais-Pagination-item--ellipsis
|
||||||
|
.ais-Pagination-link
|
||||||
|
padding: 4px 2px
|
||||||
|
border: none
|
||||||
|
background: transparent
|
||||||
|
color: var(--text-color)
|
||||||
|
cursor: default
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background: transparent
|
||||||
|
transform: none
|
||||||
|
|
||||||
|
.ais-Pagination-item--disabled
|
||||||
|
.ais-Pagination-link
|
||||||
|
opacity: .4
|
||||||
|
|
||||||
|
+maxWidth768()
|
||||||
|
.ais-Pagination-list
|
||||||
|
gap: 4px
|
||||||
|
|
||||||
hr
|
hr
|
||||||
margin: 15px auto
|
margin: 15px auto
|
||||||
@extend .custom-hr
|
@extend .custom-hr
|
||||||
@@ -50,6 +202,38 @@
|
|||||||
display: none
|
display: none
|
||||||
background: rgba($dark-black, .6)
|
background: rgba($dark-black, .6)
|
||||||
|
|
||||||
|
.search-result-stats,
|
||||||
|
.ais-Stats-text
|
||||||
|
margin: 15px 0 0
|
||||||
|
color: var(--text-color)
|
||||||
|
text-align: center
|
||||||
|
font-size: .9em
|
||||||
|
|
||||||
|
.search-keyword
|
||||||
|
background: transparent
|
||||||
|
color: $search-keyword-highlight
|
||||||
|
font-weight: 600
|
||||||
|
|
||||||
|
.search-loading
|
||||||
|
display: flex
|
||||||
|
justify-content: center
|
||||||
|
align-items: center
|
||||||
|
padding: 20px
|
||||||
|
color: var(--text-color)
|
||||||
|
|
||||||
|
&::before
|
||||||
|
width: 16px
|
||||||
|
height: 16px
|
||||||
|
border: 2px solid var(--text-color)
|
||||||
|
border-top-color: transparent
|
||||||
|
border-radius: 50%
|
||||||
|
content: ''
|
||||||
|
animation: spin 1s linear infinite
|
||||||
|
|
||||||
|
@keyframes spin
|
||||||
|
to
|
||||||
|
transform: rotate(360deg)
|
||||||
|
|
||||||
if hexo-config('search.use') == 'algolia_search'
|
if hexo-config('search.use') == 'algolia_search'
|
||||||
@require 'algolia'
|
@require 'algolia'
|
||||||
else if hexo-config('search.use') == 'local_search'
|
else if hexo-config('search.use') == 'local_search'
|
||||||
|
|||||||
@@ -1,57 +1,18 @@
|
|||||||
#local-search
|
#local-search
|
||||||
.search-dialog
|
.search-dialog
|
||||||
.local-search-box
|
|
||||||
margin: 0 auto
|
|
||||||
max-width: 100%
|
|
||||||
width: 100%
|
|
||||||
|
|
||||||
input
|
|
||||||
padding: 5px 14px
|
|
||||||
width: 100%
|
|
||||||
outline: none
|
|
||||||
border: 2px solid $search-color
|
|
||||||
border-radius: 40px
|
|
||||||
background: var(--search-bg)
|
|
||||||
color: var(--search-input-color)
|
|
||||||
-webkit-appearance: none
|
|
||||||
|
|
||||||
.search-wrap
|
|
||||||
display: none
|
|
||||||
|
|
||||||
.local-search-hit-item
|
|
||||||
margin-left: 24px
|
|
||||||
padding-left: 3px
|
|
||||||
line-height: 1.8
|
|
||||||
|
|
||||||
&::marker
|
|
||||||
color: $search-color
|
|
||||||
font-weight: bold
|
|
||||||
font-style: italic
|
|
||||||
|
|
||||||
a
|
|
||||||
color: var(--search-a-color)
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
color: $search-color
|
|
||||||
|
|
||||||
.search-result-title
|
|
||||||
font-weight: 600
|
|
||||||
|
|
||||||
.search-result
|
|
||||||
margin: 0 0 8px
|
|
||||||
word-break: break-all
|
|
||||||
font-size: .9em
|
|
||||||
|
|
||||||
.search-result-list
|
.search-result-list
|
||||||
overflow-y: overlay
|
|
||||||
margin: 0 -20px
|
|
||||||
padding: 0 22px
|
|
||||||
max-height: calc(80vh - 180px)
|
|
||||||
|
|
||||||
+maxWidth768()
|
+maxWidth768()
|
||||||
max-height: calc(var(--search-height) - 190px) !important
|
if hexo-config('search.local_search.pagination.enable')
|
||||||
|
min-height: calc(var(--search-height) - 255px) !important
|
||||||
|
else
|
||||||
|
max-height: calc(var(--search-height) - 200px) !important
|
||||||
|
|
||||||
.search-keyword
|
#local-search-stats
|
||||||
background: transparent
|
.search-result-stats
|
||||||
color: $search-keyword-highlight
|
text-align: left
|
||||||
font-weight: 600
|
|
||||||
|
.search-keyword
|
||||||
|
font-weight: 600
|
||||||
|
|
||||||
|
#loading-database ~ *
|
||||||
|
visibility: hidden
|
||||||
@@ -7,21 +7,20 @@
|
|||||||
display: inline-block
|
display: inline-block
|
||||||
margin: 0 4px 6px
|
margin: 0 4px 6px
|
||||||
padding: 0 15px
|
padding: 0 15px
|
||||||
background-color: var(--btn-beautify-color, $btn-default-color)
|
background-color: var(--btn-beautify-color, var(--btn-default-color))
|
||||||
color: $btn-color
|
color: var(--btn-color, $btn-color)
|
||||||
|
vertical-align: top
|
||||||
line-height: 2
|
line-height: 2
|
||||||
addBorderRadius()
|
addBorderRadius()
|
||||||
|
@extend .btn-effects
|
||||||
|
|
||||||
for $type in $color-types
|
for $type in $color-types
|
||||||
&.{$type}
|
&.{$type}
|
||||||
--btn-beautify-color: lookup('$tagsP-' + $type + '-color')
|
--btn-beautify-color: unquote('var(--tags-' + $type + '-color)')
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
background-color: var(--btn-hover-color)
|
background-color: var(--btn-hover-color)
|
||||||
|
|
||||||
i + span
|
|
||||||
margin-left: 6px
|
|
||||||
|
|
||||||
&:not(.block) + .btn-beautify:not(.block)
|
&:not(.block) + .btn-beautify:not(.block)
|
||||||
margin: 0 4px 20px
|
margin: 0 4px 20px
|
||||||
|
|
||||||
@@ -39,18 +38,26 @@
|
|||||||
|
|
||||||
&.larger
|
&.larger
|
||||||
padding: 6px 15px
|
padding: 6px 15px
|
||||||
|
@extend .btn-effects-large
|
||||||
&:hover
|
|
||||||
text-decoration: none
|
|
||||||
|
|
||||||
&.outline
|
&.outline
|
||||||
border: 1px solid transparent
|
border: 1px solid transparent
|
||||||
border-color: var(--btn-beautify-color, $btn-default-color)
|
border-color: var(--btn-beautify-color, var(--btn-default-color))
|
||||||
background-color: transparent
|
background-color: transparent
|
||||||
color: var(--btn-beautify-color, $btn-default-color)
|
color: var(--btn-beautify-color, var(--btn-default-color))
|
||||||
|
|
||||||
|
i,
|
||||||
|
span
|
||||||
|
transition: color .3s cubic-bezier(.4, 0, .2, 1)
|
||||||
|
|
||||||
|
&::before
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(0, 0, 0, .1), transparent)
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
background-color: var(--btn-beautify-color, $btn-default-color)
|
border-color: var(--btn-beautify-color, var(--btn-default-color))
|
||||||
|
background-color: var(--btn-beautify-color, var(--btn-default-color))
|
||||||
|
color: var(--btn-color) !important
|
||||||
|
|
||||||
&:hover
|
i,
|
||||||
color: white !important
|
span
|
||||||
|
color: var(--btn-color)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
background: $tag-hide-bg
|
background: $tag-hide-bg
|
||||||
color: var(--white)
|
color: var(--white)
|
||||||
addBorderRadius()
|
addBorderRadius()
|
||||||
|
@extend .btn-effects
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
background-color: var(--btn-hover-color)
|
background-color: var(--btn-hover-color)
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
.hl-label
|
.hl-label
|
||||||
padding: 2px 4px
|
padding: 2px 4px
|
||||||
color: $btn-color
|
color: var(--btn-color, $btn-color)
|
||||||
addBorderRadius(3)
|
addBorderRadius(3)
|
||||||
|
|
||||||
&.default
|
&.default
|
||||||
background-color: $btn-default-color
|
background-color: var(--btn-default-color)
|
||||||
|
|
||||||
for $type in $color-types
|
for $type in $color-types
|
||||||
&.{$type}
|
&.{$type}
|
||||||
background-color: lookup('$tagsP-' + $type + '-color')
|
background-color: unquote('var(--tags-' + $type + '-color)')
|
||||||
|
|||||||
@@ -19,32 +19,32 @@
|
|||||||
for $type in $color-types
|
for $type in $color-types
|
||||||
&.{$type}
|
&.{$type}
|
||||||
&:not(.disabled)
|
&:not(.disabled)
|
||||||
border-left-color: lookup('$tagsP-' + $type + '-color') !important
|
border-left-color: unquote('var(--tags-' + $type + '-color)') !important
|
||||||
|
|
||||||
&.modern
|
&.modern
|
||||||
border-left-color: transparent !important
|
border-left-color: transparent !important
|
||||||
color: lookup('$tagsP-' + $type + '-color')
|
color: unquote('var(--tags-' + $type + '-color)')
|
||||||
|
|
||||||
&:not(.simple)
|
&:not(.simple)
|
||||||
background: lighten(lookup('$tagsP-' + $type + '-color'), 85%) !important
|
background: unquote('var(--tags-' + $type + '-color-lighten)')
|
||||||
|
|
||||||
& > .note-icon
|
& > .note-icon
|
||||||
color: lookup('$tagsP-' + $type + '-color')
|
color: unquote('var(--tags-' + $type + '-color)')
|
||||||
|
|
||||||
&.simple
|
&.simple
|
||||||
border: 1px solid #EEEEEE
|
border: 1px solid var(--note-default-border)
|
||||||
border-left-width: 5px
|
border-left-width: 5px
|
||||||
|
|
||||||
&.modern
|
&.modern
|
||||||
border: 1px solid transparent !important
|
border: 1px solid transparent !important
|
||||||
background-color: #f5f5f5
|
background-color: var(--note-modern-default-bg)
|
||||||
color: $font-black
|
color: var(--note-modern-default-text)
|
||||||
|
|
||||||
&.flat
|
&.flat
|
||||||
border: initial
|
border: initial
|
||||||
border-left: 5px solid #EEEEEE
|
border-left: 5px solid var(--note-default-border)
|
||||||
background-color: lighten(#EEEEEE, 65%)
|
background-color: var(--note-default-bg)
|
||||||
color: $font-black
|
color: var(--note-default-text)
|
||||||
|
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
@@ -90,29 +90,30 @@
|
|||||||
for $type in $note-types
|
for $type in $note-types
|
||||||
&.{$type}
|
&.{$type}
|
||||||
&.flat
|
&.flat
|
||||||
background: lookup('$note-' + $type + '-bg')
|
background: unquote('var(--note-' + $type + '-bg)')
|
||||||
|
color: var(--font-color)
|
||||||
|
|
||||||
&.modern
|
&.modern
|
||||||
border-color: lookup('$note-modern-' + $type + '-border')
|
border-color: unquote('var(--note-modern-' + $type + '-border)') !important
|
||||||
background: lookup('$note-modern-' + $type + '-bg')
|
background: unquote('var(--note-modern-' + $type + '-bg)')
|
||||||
color: lookup('$note-modern-' + $type + '-text')
|
color: unquote('var(--note-modern-' + $type + '-text)')
|
||||||
|
|
||||||
a
|
a
|
||||||
&:not(.btn)
|
&:not(.btn)
|
||||||
color: lookup('$note-modern-' + $type + '-text')
|
color: unquote('var(--note-modern-' + $type + '-text)')
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
color: lookup('$note-modern-' + $type + '-hover')
|
color: unquote('var(--note-modern-' + $type + '-hover)')
|
||||||
|
|
||||||
&:not(.modern)
|
&:not(.modern)
|
||||||
border-left-color: lookup('$note-' + $type + '-border')
|
border-left-color: unquote('var(--note-' + $type + '-border)')
|
||||||
|
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
h4,
|
h4,
|
||||||
h5,
|
h5,
|
||||||
h6
|
h6
|
||||||
color: lookup('$note-' + $type + '-text')
|
color: unquote('var(--note-' + $type + '-text)')
|
||||||
|
|
||||||
if $note-icons
|
if $note-icons
|
||||||
&:not(.no-icon)
|
&:not(.no-icon)
|
||||||
@@ -121,4 +122,4 @@
|
|||||||
|
|
||||||
&:not(.modern)
|
&:not(.modern)
|
||||||
&::before
|
&::before
|
||||||
color: lookup('$note-' + $type + '-text')
|
color: unquote('var(--note-' + $type + '-text)')
|
||||||
|
|||||||
@@ -13,11 +13,9 @@ $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)
|
$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
|
$theme-toc-color = $themeColorEnable && hexo-config('theme_color.toc_color') ? convert(hexo-config('theme_color.toc_color')) : $strong-cyan
|
||||||
// font
|
// font
|
||||||
|
|
||||||
$chineseFont = $language == 'zh-CN' ? 'Microsoft YaHei' : 'Microsoft JhengHei'
|
$chineseFont = $language == 'zh-CN' ? 'Microsoft YaHei' : 'Microsoft JhengHei'
|
||||||
$default-font-family = -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Lato, Roboto, 'PingFang SC', $chineseFont, sans-serif
|
$default-font-family = -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Lato, Roboto, 'PingFang SC', $chineseFont, sans-serif
|
||||||
$default-code-font = consolas, Menlo, monospace, 'PingFang SC', $chineseFont, sans-serif
|
$default-code-font = consolas, Menlo, monospace, 'PingFang SC', $chineseFont, sans-serif
|
||||||
|
|
||||||
$font-family = hexo-config('font.font_family') ? unquote(hexo-config('font.font_family')) : $default-font-family
|
$font-family = hexo-config('font.font_family') ? unquote(hexo-config('font.font_family')) : $default-font-family
|
||||||
$code-font-family = hexo-config('font.code_font_family') ? unquote(hexo-config('font.code_font_family')) : $default-code-font
|
$code-font-family = hexo-config('font.code_font_family') ? unquote(hexo-config('font.code_font_family')) : $default-code-font
|
||||||
$site-name-font = hexo-config('blog_title_font.font_family') && unquote(hexo-config('blog_title_font.font_family'))
|
$site-name-font = hexo-config('blog_title_font.font_family') && unquote(hexo-config('blog_title_font.font_family'))
|
||||||
@@ -184,3 +182,52 @@ $tab-to-top-color = #99a9bf
|
|||||||
$tab-to-top-hover-color = $theme-color
|
$tab-to-top-hover-color = $theme-color
|
||||||
// Tag Plugins - timeline
|
// Tag Plugins - timeline
|
||||||
$timeline-default-color = $theme-color
|
$timeline-default-color = $theme-color
|
||||||
|
// note - darkmode
|
||||||
|
// Default
|
||||||
|
$note-dark-default-border = #5a5a5a
|
||||||
|
$note-dark-default-bg = #2b2b2b
|
||||||
|
$note-dark-default-text = #b3b3b3
|
||||||
|
$note-dark-modern-default-border = #9a9a9a
|
||||||
|
$note-dark-modern-default-bg = #353535
|
||||||
|
$note-dark-modern-default-text = #c4c4c4
|
||||||
|
$note-dark-modern-default-hover = #d0d0d0
|
||||||
|
// Primary
|
||||||
|
$note-dark-primary-border = #5935a1
|
||||||
|
$note-dark-primary-bg = #2e1c3e
|
||||||
|
$note-dark-primary-text = #a47dd4
|
||||||
|
$note-dark-modern-primary-border = #9985cc
|
||||||
|
$note-dark-modern-primary-bg = #3c2d4c
|
||||||
|
$note-dark-modern-primary-text = #b693e6
|
||||||
|
$note-dark-modern-primary-hover = #c9a8f0
|
||||||
|
// Info
|
||||||
|
$note-dark-info-border = #346fa2
|
||||||
|
$note-dark-info-bg = #1f2e3b
|
||||||
|
$note-dark-info-text = #7bb3db
|
||||||
|
$note-dark-modern-info-border = #7ca8b5
|
||||||
|
$note-dark-modern-info-bg = #2b3c44
|
||||||
|
$note-dark-modern-info-text = #8fc6e0
|
||||||
|
$note-dark-modern-info-hover = #a3d4ea
|
||||||
|
// Success
|
||||||
|
$note-dark-success-border = #4a944a
|
||||||
|
$note-dark-success-bg = #202e20
|
||||||
|
$note-dark-success-text = #82c682
|
||||||
|
$note-dark-modern-success-border = #8bb087
|
||||||
|
$note-dark-modern-success-bg = #2c3d2c
|
||||||
|
$note-dark-modern-success-text = #96d196
|
||||||
|
$note-dark-modern-success-hover = #a8dca8
|
||||||
|
// Warning
|
||||||
|
$note-dark-warning-border = #c08a3e
|
||||||
|
$note-dark-warning-bg = #3e301f
|
||||||
|
$note-dark-warning-text = #e6ba6b
|
||||||
|
$note-dark-modern-warning-border = #b8a285
|
||||||
|
$note-dark-modern-warning-bg = #4b3c2b
|
||||||
|
$note-dark-modern-warning-text = #d4b373
|
||||||
|
$note-dark-modern-warning-hover = #e0c080
|
||||||
|
// Danger
|
||||||
|
$note-dark-danger-border = #b34440
|
||||||
|
$note-dark-danger-bg = #3b201f
|
||||||
|
$note-dark-danger-text = #e67572
|
||||||
|
$note-dark-modern-danger-border = #c7898c
|
||||||
|
$note-dark-modern-danger-bg = #4d2b2e
|
||||||
|
$note-dark-modern-danger-text = #d98b8e
|
||||||
|
$note-dark-modern-danger-hover = #e59fa2
|
||||||
@@ -698,7 +698,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const addCopyright = () => {
|
const addCopyright = () => {
|
||||||
const { limitCount, languages } = GLOBAL_CONFIG.copyright
|
const { limitCount, languages } = GLOBAL_CONFIG.copyright
|
||||||
|
|
||||||
const handleCopy = (e) => {
|
const handleCopy = e => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
const copyFont = window.getSelection(0).toString()
|
const copyFont = window.getSelection(0).toString()
|
||||||
let textFont = copyFont
|
let textFont = copyFont
|
||||||
@@ -893,27 +893,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
tabsFn()
|
tabsFn()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 自己写的,实现功能切换类别表
|
|
||||||
*/
|
|
||||||
const setCategoryBarActive = () => {
|
|
||||||
const categoryBar = document.querySelector("#category-bar");
|
|
||||||
const currentPath = decodeURIComponent(window.location.pathname);
|
|
||||||
const isHomePage = currentPath === GLOBAL_CONFIG.root;
|
|
||||||
|
|
||||||
if (categoryBar) {
|
|
||||||
const categoryItems = categoryBar.querySelectorAll(".category-bar-item");
|
|
||||||
categoryItems.forEach(item => item.classList.remove("select"));
|
|
||||||
|
|
||||||
const activeItemId = isHomePage ? "category-bar-home" : currentPath.split("/").slice(-2, -1)[0];
|
|
||||||
const activeItem = document.getElementById(activeItemId);
|
|
||||||
|
|
||||||
if (activeItem) {
|
|
||||||
activeItem.classList.add("select");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const refreshFn = () => {
|
const refreshFn = () => {
|
||||||
initAdjust()
|
initAdjust()
|
||||||
justifiedIndexPostUI()
|
justifiedIndexPostUI()
|
||||||
@@ -926,7 +905,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
GLOBAL_CONFIG.runtime && addRuntime()
|
GLOBAL_CONFIG.runtime && addRuntime()
|
||||||
addLastPushDate()
|
addLastPushDate()
|
||||||
toggleCardCategory()
|
toggleCardCategory()
|
||||||
setCategoryBarActive()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLOBAL_CONFIG_SITE.pageType === 'home' && scrollDownInIndex()
|
GLOBAL_CONFIG_SITE.pageType === 'home' && scrollDownInIndex()
|
||||||
|
|||||||
@@ -26,7 +26,12 @@ window.addEventListener('load', () => {
|
|||||||
const openSearch = () => {
|
const openSearch = () => {
|
||||||
btf.overflowPaddingR.add()
|
btf.overflowPaddingR.add()
|
||||||
animateElements(true)
|
animateElements(true)
|
||||||
setTimeout(() => { document.querySelector('#algolia-search .ais-SearchBox-input').focus() }, 100)
|
showLoading(false)
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const searchInput = document.querySelector('#algolia-search-input .ais-SearchBox-input')
|
||||||
|
if (searchInput) searchInput.focus()
|
||||||
|
}, 100)
|
||||||
|
|
||||||
const handleEscape = event => {
|
const handleEscape = event => {
|
||||||
if (event.code === 'Escape') {
|
if (event.code === 'Escape') {
|
||||||
@@ -55,9 +60,38 @@ window.addEventListener('load', () => {
|
|||||||
document.querySelector('#algolia-search .search-close-button').addEventListener('click', closeSearch)
|
document.querySelector('#algolia-search .search-close-button').addEventListener('click', closeSearch)
|
||||||
}
|
}
|
||||||
|
|
||||||
const cutContent = (content) => {
|
const cutContent = content => {
|
||||||
if (!content) return ''
|
if (!content) return ''
|
||||||
const firstOccur = content.indexOf('<mark>')
|
|
||||||
|
let contentStr = ''
|
||||||
|
if (typeof content === 'string') {
|
||||||
|
contentStr = content.trim()
|
||||||
|
} else if (typeof content === 'object') {
|
||||||
|
if (content.value !== undefined) {
|
||||||
|
contentStr = String(content.value).trim()
|
||||||
|
if (!contentStr) return ''
|
||||||
|
} else if (content.matchedWords || content.matchLevel || content.fullyHighlighted !== undefined) {
|
||||||
|
return ''
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
contentStr = JSON.stringify(content).trim()
|
||||||
|
if (contentStr === '{}' || contentStr === '[]' || contentStr === '""') {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (content.toString && typeof content.toString === 'function') {
|
||||||
|
contentStr = content.toString().trim()
|
||||||
|
if (contentStr === '[object Object]' || contentStr === '[object Array]') {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstOccur = contentStr.indexOf('<mark>')
|
||||||
let start = firstOccur - 30
|
let start = firstOccur - 30
|
||||||
let end = firstOccur + 120
|
let end = firstOccur + 120
|
||||||
let pre = ''
|
let pre = ''
|
||||||
@@ -70,94 +104,454 @@ window.addEventListener('load', () => {
|
|||||||
pre = '...'
|
pre = '...'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end > content.length) {
|
if (end > contentStr.length) {
|
||||||
end = content.length
|
end = contentStr.length
|
||||||
} else {
|
} else {
|
||||||
post = '...'
|
post = '...'
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${pre}${content.substring(start, end)}${post}`
|
// Ensure we don't cut off HTML tags in the middle
|
||||||
|
let substr = contentStr.substring(start, end)
|
||||||
|
|
||||||
|
// Handle tag completeness
|
||||||
|
// Check for incomplete opening tags at the beginning
|
||||||
|
const firstCloseBracket = substr.indexOf('>')
|
||||||
|
const firstOpenBracket = substr.indexOf('<')
|
||||||
|
|
||||||
|
// If there's a closing bracket but no opening bracket before it, we've cut a tag
|
||||||
|
if (firstCloseBracket !== -1 && (firstOpenBracket === -1 || firstCloseBracket < firstOpenBracket)) {
|
||||||
|
substr = substr.substring(firstCloseBracket + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for incomplete closing tags at the end
|
||||||
|
const lastOpenBracket = substr.lastIndexOf('<')
|
||||||
|
const lastCloseBracket = substr.lastIndexOf('>')
|
||||||
|
|
||||||
|
// If there's an opening bracket after the last closing bracket, we've cut a tag
|
||||||
|
if (lastOpenBracket !== -1 && lastOpenBracket > lastCloseBracket) {
|
||||||
|
substr = substr.substring(0, lastOpenBracket)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Balance tags in the substring
|
||||||
|
const tagStack = []
|
||||||
|
let balancedStr = ''
|
||||||
|
let i = 0
|
||||||
|
|
||||||
|
while (i < substr.length) {
|
||||||
|
if (substr[i] === '<') {
|
||||||
|
// Check if it's a closing tag
|
||||||
|
if (substr[i + 1] === '/') {
|
||||||
|
const closeTagEnd = substr.indexOf('>', i)
|
||||||
|
if (closeTagEnd !== -1) {
|
||||||
|
const closeTagName = substr.substring(i + 2, closeTagEnd)
|
||||||
|
// Remove matching opening tag from stack
|
||||||
|
for (let j = tagStack.length - 1; j >= 0; j--) {
|
||||||
|
if (tagStack[j] === closeTagName) {
|
||||||
|
tagStack.splice(j, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
balancedStr += substr.substring(i, closeTagEnd + 1)
|
||||||
|
i = closeTagEnd + 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if (substr.substr(i, 2) === '<!' || (substr.indexOf('/>', i) !== -1 && substr.indexOf('/>', i) < substr.indexOf('>', i))) {
|
||||||
|
const tagEnd = substr.indexOf('>', i)
|
||||||
|
if (tagEnd !== -1) {
|
||||||
|
balancedStr += substr.substring(i, tagEnd + 1)
|
||||||
|
i = tagEnd + 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const tagEnd = substr.indexOf('>', i)
|
||||||
|
if (tagEnd !== -1) {
|
||||||
|
const tagName = substr.substring(i + 1, (substr.indexOf(' ', i) > -1 && substr.indexOf(' ', i) < tagEnd)
|
||||||
|
? substr.indexOf(' ', i)
|
||||||
|
: tagEnd).split(/\s/)[0]
|
||||||
|
tagStack.push(tagName)
|
||||||
|
balancedStr += substr.substring(i, tagEnd + 1)
|
||||||
|
i = tagEnd + 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
balancedStr += substr[i]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close any unclosed tags
|
||||||
|
while (tagStack.length > 0) {
|
||||||
|
const tagName = tagStack.pop()
|
||||||
|
balancedStr += `</${tagName}>`
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we removed content from the beginning, add prefix
|
||||||
|
if (start > 0 || pre) {
|
||||||
|
const actualFirstOpenBracket = contentStr.indexOf('<', start > 0 ? start - 30 : 0)
|
||||||
|
const actualFirstMark = contentStr.indexOf('<mark>', start > 0 ? start - 30 : 0)
|
||||||
|
|
||||||
|
if (actualFirstOpenBracket !== -1 &&
|
||||||
|
(actualFirstMark === -1 || actualFirstOpenBracket < actualFirstMark)) {
|
||||||
|
pre = '...'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
substr = balancedStr
|
||||||
|
return `${pre}${substr}${post}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const disableDiv = [
|
// Helper function to handle Algolia highlight results
|
||||||
document.getElementById('algolia-hits'),
|
const extractHighlightValue = highlightObj => {
|
||||||
document.getElementById('algolia-pagination'),
|
if (!highlightObj) return ''
|
||||||
document.querySelector('#algolia-info .algolia-stats')
|
|
||||||
]
|
|
||||||
|
|
||||||
const searchClient = typeof algoliasearch === 'function' ? algoliasearch : window['algoliasearch/lite'].liteClient
|
if (typeof highlightObj === 'string') {
|
||||||
const search = instantsearch({
|
return highlightObj.trim()
|
||||||
indexName,
|
|
||||||
searchClient: searchClient(appId, apiKey),
|
|
||||||
searchFunction (helper) {
|
|
||||||
disableDiv.forEach(item => {
|
|
||||||
item.style.display = helper.state.query ? '' : 'none'
|
|
||||||
})
|
|
||||||
if (helper.state.query) helper.search()
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const widgets = [
|
if (typeof highlightObj === 'object' && highlightObj.value !== undefined) {
|
||||||
instantsearch.widgets.configure({ hitsPerPage }),
|
return String(highlightObj.value).trim()
|
||||||
instantsearch.widgets.searchBox({
|
}
|
||||||
container: '#algolia-search-input',
|
|
||||||
showReset: false,
|
return ''
|
||||||
showSubmit: false,
|
}
|
||||||
placeholder: languages.input_placeholder,
|
|
||||||
showLoadingIndicator: true
|
// Initialize Algolia client
|
||||||
}),
|
let searchClient
|
||||||
instantsearch.widgets.hits({
|
|
||||||
container: '#algolia-hits',
|
if (window['algoliasearch/lite'] && typeof window['algoliasearch/lite'].liteClient === 'function') {
|
||||||
templates: {
|
searchClient = window['algoliasearch/lite'].liteClient(appId, apiKey)
|
||||||
item (data) {
|
} else if (typeof window.algoliasearch === 'function') {
|
||||||
const link = data.permalink || (GLOBAL_CONFIG.root + data.path)
|
searchClient = window.algoliasearch(appId, apiKey)
|
||||||
const result = data._highlightResult
|
} else {
|
||||||
const content = result.contentStripTruncate
|
return console.error('Algolia search client not found!')
|
||||||
? cutContent(result.contentStripTruncate.value)
|
}
|
||||||
: result.contentStrip
|
|
||||||
? cutContent(result.contentStrip.value)
|
if (!searchClient) {
|
||||||
: result.content
|
return console.error('Failed to initialize Algolia search client')
|
||||||
? cutContent(result.content.value)
|
}
|
||||||
: ''
|
|
||||||
return `
|
// Search state
|
||||||
<a href="${link}" class="algolia-hit-item-link">
|
let currentQuery = ''
|
||||||
<span class="algolia-hits-item-title">${result.title.value || 'no-title'}</span>
|
|
||||||
${content ? `<div class="algolia-hit-item-content">${content}</div>` : ''}
|
// Show loading state
|
||||||
</a>`
|
const showLoading = show => {
|
||||||
},
|
const loadingIndicator = document.getElementById('loading-status')
|
||||||
empty (data) {
|
if (loadingIndicator) {
|
||||||
return `<div id="algolia-hits-empty">${languages.hits_empty.replace(/\$\{query}/, data.query)}</div>`
|
loadingIndicator.hidden = !show
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache frequently used elements
|
||||||
|
const elements = {
|
||||||
|
get searchInput () { return document.querySelector('#algolia-search-input .ais-SearchBox-input') },
|
||||||
|
get hits () { return document.getElementById('algolia-hits') },
|
||||||
|
get hitsEmpty () { return document.getElementById('algolia-hits-empty') },
|
||||||
|
get hitsList () { return document.querySelector('#algolia-hits .ais-Hits-list') },
|
||||||
|
get hitsWrapper () { return document.querySelector('#algolia-hits .ais-Hits') },
|
||||||
|
get pagination () { return document.getElementById('algolia-pagination') },
|
||||||
|
get paginationList () { return document.querySelector('#algolia-pagination .ais-Pagination-list') },
|
||||||
|
get stats () { return document.querySelector('#algolia-info .ais-Stats-text') },
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show/hide search results area
|
||||||
|
const toggleResultsVisibility = hasResults => {
|
||||||
|
elements.pagination.style.display = hasResults ? '' : 'none'
|
||||||
|
elements.stats.style.display = hasResults ? '' : 'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render search results
|
||||||
|
const renderHits = (hits, query, page = 0) => {
|
||||||
|
if (hits.length === 0 && query) {
|
||||||
|
elements.hitsEmpty.textContent = languages.hits_empty.replace(/\$\{query}/, query)
|
||||||
|
elements.hitsEmpty.style.display = ''
|
||||||
|
elements.hitsWrapper.style.display = 'none'
|
||||||
|
elements.stats.style.display = 'none'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.hitsEmpty.style.display = 'none'
|
||||||
|
|
||||||
|
const hitsHTML = hits.map((hit, index) => {
|
||||||
|
const itemNumber = page * hitsPerPage + index + 1
|
||||||
|
const link = hit.permalink || (GLOBAL_CONFIG.root + hit.path)
|
||||||
|
const result = hit._highlightResult || hit
|
||||||
|
|
||||||
|
// Content extraction
|
||||||
|
let content = ''
|
||||||
|
try {
|
||||||
|
if (result.contentStripTruncate) {
|
||||||
|
content = cutContent(result.contentStripTruncate)
|
||||||
|
} else if (result.contentStrip) {
|
||||||
|
content = cutContent(result.contentStrip)
|
||||||
|
} else if (result.content) {
|
||||||
|
content = cutContent(result.content)
|
||||||
|
} else if (hit.contentStripTruncate) {
|
||||||
|
content = cutContent(hit.contentStripTruncate)
|
||||||
|
} else if (hit.contentStrip) {
|
||||||
|
content = cutContent(hit.contentStrip)
|
||||||
|
} else if (hit.content) {
|
||||||
|
content = cutContent(hit.content)
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
content = ''
|
||||||
}
|
}
|
||||||
}),
|
|
||||||
instantsearch.widgets.stats({
|
// Title handling
|
||||||
container: '#algolia-info > .algolia-stats',
|
let title = 'no-title'
|
||||||
templates: {
|
try {
|
||||||
text (data) {
|
if (result.title) {
|
||||||
const stats = languages.hits_stats
|
title = extractHighlightValue(result.title) || 'no-title'
|
||||||
.replace(/\$\{hits}/, data.nbHits)
|
} else if (hit.title) {
|
||||||
.replace(/\$\{time}/, data.processingTimeMS)
|
title = extractHighlightValue(hit.title) || 'no-title'
|
||||||
return `<hr>${stats}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!title || title === 'no-title') {
|
||||||
|
if (typeof hit.title === 'string' && hit.title.trim()) {
|
||||||
|
title = hit.title.trim()
|
||||||
|
} else if (hit.title && typeof hit.title === 'object' && hit.title.value) {
|
||||||
|
title = String(hit.title.value).trim() || 'no-title'
|
||||||
|
} else {
|
||||||
|
title = 'no-title'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
title = 'no-title'
|
||||||
}
|
}
|
||||||
}),
|
|
||||||
instantsearch.widgets.poweredBy({
|
return `
|
||||||
container: '#algolia-info > .algolia-poweredBy'
|
<li class="ais-Hits-item" value="${itemNumber}">
|
||||||
}),
|
<a href="${link}" class="algolia-hit-item-link">
|
||||||
instantsearch.widgets.pagination({
|
<span class="algolia-hits-item-title">${title}</span>
|
||||||
container: '#algolia-pagination',
|
${content ? `<div class="algolia-hit-item-content">${content}</div>` : ''}
|
||||||
totalPages: 5,
|
</a>
|
||||||
templates: {
|
</li>`
|
||||||
first: '<i class="fas fa-angle-double-left"></i>',
|
}).join('')
|
||||||
last: '<i class="fas fa-angle-double-right"></i>',
|
|
||||||
previous: '<i class="fas fa-angle-left"></i>',
|
elements.hitsList.innerHTML = hitsHTML
|
||||||
next: '<i class="fas fa-angle-right"></i>'
|
elements.hitsWrapper.style.display = query ? '' : 'none'
|
||||||
|
|
||||||
|
if (hits.length > 0) {
|
||||||
|
elements.stats.style.display = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render pagination
|
||||||
|
const renderPagination = (page, nbPages) => {
|
||||||
|
if (nbPages <= 1) {
|
||||||
|
elements.pagination.style.display = 'none'
|
||||||
|
elements.paginationList.innerHTML = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.pagination.style.display = 'block'
|
||||||
|
|
||||||
|
const isFirstPage = page === 0
|
||||||
|
const isLastPage = page === nbPages - 1
|
||||||
|
|
||||||
|
// Responsive page display
|
||||||
|
const isMobile = window.innerWidth < 768
|
||||||
|
const maxVisiblePages = isMobile ? 3 : 5
|
||||||
|
let startPage = Math.max(0, page - Math.floor(maxVisiblePages / 2))
|
||||||
|
const endPage = Math.min(nbPages - 1, startPage + maxVisiblePages - 1)
|
||||||
|
|
||||||
|
// Adjust starting page to maintain max visible pages
|
||||||
|
if (endPage - startPage + 1 < maxVisiblePages) {
|
||||||
|
startPage = Math.max(0, endPage - maxVisiblePages + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
let pagesHTML = ''
|
||||||
|
|
||||||
|
// Only add ellipsis and first page when there are many pages
|
||||||
|
if (nbPages > maxVisiblePages && startPage > 0) {
|
||||||
|
pagesHTML += `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--page">
|
||||||
|
<a class="ais-Pagination-link" aria-label="Page 1" href="#" data-page="0">1</a>
|
||||||
|
</li>`
|
||||||
|
if (startPage > 1) {
|
||||||
|
pagesHTML += `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--ellipsis">
|
||||||
|
<span class="ais-Pagination-link">...</span>
|
||||||
|
</li>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add middle page numbers
|
||||||
|
for (let i = startPage; i <= endPage; i++) {
|
||||||
|
const isSelected = i === page
|
||||||
|
if (isSelected) {
|
||||||
|
pagesHTML += `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--page ais-Pagination-item--selected">
|
||||||
|
<span class="ais-Pagination-link" aria-label="Page ${i + 1}">${i + 1}</span>
|
||||||
|
</li>`
|
||||||
|
} else {
|
||||||
|
pagesHTML += `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--page">
|
||||||
|
<a class="ais-Pagination-link" aria-label="Page ${i + 1}" href="#" data-page="${i}">${i + 1}</a>
|
||||||
|
</li>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only add ellipsis and last page when there are many pages
|
||||||
|
if (nbPages > maxVisiblePages && endPage < nbPages - 1) {
|
||||||
|
if (endPage < nbPages - 2) {
|
||||||
|
pagesHTML += `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--ellipsis">
|
||||||
|
<span class="ais-Pagination-link">...</span>
|
||||||
|
</li>`
|
||||||
|
}
|
||||||
|
pagesHTML += `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--page">
|
||||||
|
<a class="ais-Pagination-link" aria-label="Page ${nbPages}" href="#" data-page="${nbPages - 1}">${nbPages}</a>
|
||||||
|
</li>`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbPages > 1) {
|
||||||
|
elements.paginationList.innerHTML = `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--previousPage ${isFirstPage ? 'ais-Pagination-item--disabled' : ''}">
|
||||||
|
${isFirstPage
|
||||||
|
? '<span class="ais-Pagination-link ais-Pagination-link--disabled" aria-label="Previous Page"><i class="fas fa-angle-left"></i></span>'
|
||||||
|
: `<a class="ais-Pagination-link" aria-label="Previous Page" href="#" data-page="${page - 1}"><i class="fas fa-angle-left"></i></a>`
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
${pagesHTML}
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--nextPage ${isLastPage ? 'ais-Pagination-item--disabled' : ''}">
|
||||||
|
${isLastPage
|
||||||
|
? '<span class="ais-Pagination-link ais-Pagination-link--disabled" aria-label="Next Page"><i class="fas fa-angle-right"></i></span>'
|
||||||
|
: `<a class="ais-Pagination-link" aria-label="Next Page" href="#" data-page="${page + 1}"><i class="fas fa-angle-right"></i></a>`
|
||||||
|
}
|
||||||
|
</li>`
|
||||||
|
elements.pagination.style.display = currentQuery ? '' : 'none'
|
||||||
|
} else {
|
||||||
|
elements.pagination.style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render statistics
|
||||||
|
const renderStats = (nbHits, processingTimeMS, query) => {
|
||||||
|
if (query) {
|
||||||
|
const stats = languages.hits_stats
|
||||||
|
.replace(/\$\{hits}/, nbHits)
|
||||||
|
.replace(/\$\{time}/, processingTimeMS)
|
||||||
|
elements.stats.innerHTML = `<hr>${stats}`
|
||||||
|
elements.stats.style.display = ''
|
||||||
|
} else {
|
||||||
|
elements.stats.style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform search
|
||||||
|
const performSearch = async (query, page = 0) => {
|
||||||
|
if (!query.trim()) {
|
||||||
|
currentQuery = ''
|
||||||
|
renderHits([], '', 0)
|
||||||
|
renderPagination(0, 0)
|
||||||
|
renderStats(0, 0, '')
|
||||||
|
toggleResultsVisibility(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
showLoading(true)
|
||||||
|
currentQuery = query
|
||||||
|
|
||||||
|
try {
|
||||||
|
let result
|
||||||
|
|
||||||
|
if (searchClient && typeof searchClient.search === 'function') {
|
||||||
|
// v5 multi-index search
|
||||||
|
const searchResult = await searchClient.search([{
|
||||||
|
indexName,
|
||||||
|
query,
|
||||||
|
params: {
|
||||||
|
page,
|
||||||
|
hitsPerPage,
|
||||||
|
highlightPreTag: '<mark>',
|
||||||
|
highlightPostTag: '</mark>',
|
||||||
|
attributesToHighlight: ['title', 'content', 'contentStrip', 'contentStripTruncate']
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
result = searchResult.results[0]
|
||||||
|
} else if (searchClient && typeof searchClient.initIndex === 'function') {
|
||||||
|
// v4 single-index search
|
||||||
|
const index = searchClient.initIndex(indexName)
|
||||||
|
result = await index.search(query, {
|
||||||
|
page,
|
||||||
|
hitsPerPage,
|
||||||
|
highlightPreTag: '<mark>',
|
||||||
|
highlightPostTag: '</mark>',
|
||||||
|
attributesToHighlight: ['title', 'content', 'contentStrip', 'contentStripTruncate']
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new Error('Algolia: No compatible search method available')
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHits(result.hits || [], query, page)
|
||||||
|
|
||||||
|
const actualNbPages = result.nbHits <= hitsPerPage ? 1 : (result.nbPages || 0)
|
||||||
|
renderPagination(page, actualNbPages)
|
||||||
|
renderStats(result.nbHits || 0, result.processingTimeMS || 0, query)
|
||||||
|
|
||||||
|
const hasResults = result.hits && result.hits.length > 0
|
||||||
|
toggleResultsVisibility(hasResults)
|
||||||
|
|
||||||
|
// Refresh Pjax links
|
||||||
|
if (window.pjax) {
|
||||||
|
window.pjax.refresh(document.getElementById('algolia-hits'))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Algolia search error:', error)
|
||||||
|
renderHits([], query, page)
|
||||||
|
renderPagination(0, 0)
|
||||||
|
renderStats(0, 0, query)
|
||||||
|
} finally {
|
||||||
|
showLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debounced search
|
||||||
|
let searchTimeout
|
||||||
|
const debouncedSearch = (query, delay = 300) => {
|
||||||
|
clearTimeout(searchTimeout)
|
||||||
|
searchTimeout = setTimeout(() => performSearch(query), delay)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize search box and events
|
||||||
|
const initializeSearch = () => {
|
||||||
|
showLoading(false)
|
||||||
|
|
||||||
|
if (elements.searchInput) {
|
||||||
|
elements.searchInput.addEventListener('input', e => {
|
||||||
|
const query = e.target.value
|
||||||
|
debouncedSearch(query)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchForm = document.querySelector('#algolia-search-input .ais-SearchBox-form')
|
||||||
|
if (searchForm) {
|
||||||
|
searchForm.addEventListener('submit', e => {
|
||||||
|
e.preventDefault()
|
||||||
|
const query = elements.searchInput.value
|
||||||
|
performSearch(query)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pagination event delegation
|
||||||
|
elements.pagination.addEventListener('click', e => {
|
||||||
|
e.preventDefault()
|
||||||
|
const link = e.target.closest('a[data-page]')
|
||||||
|
if (link) {
|
||||||
|
const page = parseInt(link.dataset.page, 10)
|
||||||
|
if (!isNaN(page) && currentQuery) {
|
||||||
|
performSearch(currentQuery, page)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
]
|
|
||||||
|
|
||||||
search.addWidgets(widgets)
|
// Initial state
|
||||||
search.start()
|
toggleResultsVisibility(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize
|
||||||
|
initializeSearch()
|
||||||
searchClickFn()
|
searchClickFn()
|
||||||
searchFnOnce()
|
searchFnOnce()
|
||||||
|
|
||||||
@@ -165,10 +559,4 @@ window.addEventListener('load', () => {
|
|||||||
if (!btf.isHidden($searchMask)) closeSearch()
|
if (!btf.isHidden($searchMask)) closeSearch()
|
||||||
searchClickFn()
|
searchClickFn()
|
||||||
})
|
})
|
||||||
|
|
||||||
if (window.pjax) {
|
|
||||||
search.on('render', () => {
|
|
||||||
window.pjax.refresh(document.getElementById('algolia-hits'))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -156,10 +156,10 @@ class LocalSearch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
slicesOfContent.forEach(slice => {
|
slicesOfContent.forEach(slice => {
|
||||||
resultItem += `<p class="search-result">${this.highlightKeyword(content, slice)}...</p></a>`
|
resultItem += `<p class="search-result">${this.highlightKeyword(content, slice)}...</p>`
|
||||||
})
|
})
|
||||||
|
|
||||||
resultItem += '</li>'
|
resultItem += '</a></li>'
|
||||||
resultItems.push({
|
resultItems.push({
|
||||||
item: resultItem,
|
item: resultItem,
|
||||||
id: resultItems.length,
|
id: resultItems.length,
|
||||||
@@ -236,40 +236,229 @@ class LocalSearch {
|
|||||||
|
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
// Search
|
// Search
|
||||||
const { path, top_n_per_article, unescape, languages } = GLOBAL_CONFIG.localSearch
|
const { path, top_n_per_article, unescape, languages, pagination } = GLOBAL_CONFIG.localSearch
|
||||||
|
const enablePagination = pagination && pagination.enable
|
||||||
const localSearch = new LocalSearch({
|
const localSearch = new LocalSearch({
|
||||||
path,
|
path,
|
||||||
top_n_per_article,
|
top_n_per_article,
|
||||||
unescape
|
unescape
|
||||||
})
|
})
|
||||||
|
|
||||||
const input = document.querySelector('#local-search-input input')
|
const input = document.querySelector('.local-search-input input')
|
||||||
const statsItem = document.getElementById('local-search-stats-wrap')
|
const statsItem = document.getElementById('local-search-stats')
|
||||||
const $loadingStatus = document.getElementById('loading-status')
|
const $loadingStatus = document.getElementById('loading-status')
|
||||||
const isXml = !path.endsWith('json')
|
const isXml = !path.endsWith('json')
|
||||||
|
|
||||||
|
// Pagination variables (only initialize if pagination is enabled)
|
||||||
|
let currentPage = 0
|
||||||
|
const hitsPerPage = pagination.hitsPerPage || 10
|
||||||
|
|
||||||
|
let currentResultItems = []
|
||||||
|
|
||||||
|
if (!enablePagination) {
|
||||||
|
// If pagination is disabled, we don't need these variables
|
||||||
|
currentPage = undefined
|
||||||
|
currentResultItems = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache frequently used elements
|
||||||
|
const elements = {
|
||||||
|
get pagination () { return document.getElementById('local-search-pagination') },
|
||||||
|
get paginationList () { return document.querySelector('#local-search-pagination .ais-Pagination-list') }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show/hide search results area
|
||||||
|
const toggleResultsVisibility = hasResults => {
|
||||||
|
if (enablePagination) {
|
||||||
|
elements.pagination.style.display = hasResults ? '' : 'none'
|
||||||
|
} else {
|
||||||
|
elements.pagination.style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render search results for current page
|
||||||
|
const renderResults = (searchText, resultItems) => {
|
||||||
|
const container = document.getElementById('local-search-results')
|
||||||
|
|
||||||
|
// Determine items to display based on pagination mode
|
||||||
|
const itemsToDisplay = enablePagination
|
||||||
|
? currentResultItems.slice(currentPage * hitsPerPage, (currentPage + 1) * hitsPerPage)
|
||||||
|
: resultItems
|
||||||
|
|
||||||
|
// Handle empty page in pagination mode
|
||||||
|
if (enablePagination && itemsToDisplay.length === 0 && currentResultItems.length > 0) {
|
||||||
|
currentPage = 0
|
||||||
|
renderResults(searchText, resultItems)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add numbering to items
|
||||||
|
const numberedItems = itemsToDisplay.map((result, index) => {
|
||||||
|
const itemNumber = enablePagination
|
||||||
|
? currentPage * hitsPerPage + index + 1
|
||||||
|
: index + 1
|
||||||
|
return result.item.replace(
|
||||||
|
'<li class="local-search-hit-item">',
|
||||||
|
`<li class="local-search-hit-item" value="${itemNumber}">`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
container.innerHTML = `<ol class="search-result-list">${numberedItems.join('')}</ol>`
|
||||||
|
|
||||||
|
// Update stats
|
||||||
|
const displayCount = enablePagination ? currentResultItems.length : resultItems.length
|
||||||
|
const stats = languages.hits_stats.replace(/\$\{hits}/, displayCount)
|
||||||
|
statsItem.innerHTML = `<hr><div class="search-result-stats">${stats}</div>`
|
||||||
|
|
||||||
|
// Handle pagination
|
||||||
|
if (enablePagination) {
|
||||||
|
const nbPages = Math.ceil(currentResultItems.length / hitsPerPage)
|
||||||
|
renderPagination(currentPage, nbPages, searchText)
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasResults = resultItems.length > 0
|
||||||
|
toggleResultsVisibility(hasResults)
|
||||||
|
|
||||||
|
window.pjax && window.pjax.refresh(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render pagination
|
||||||
|
const renderPagination = (page, nbPages, query) => {
|
||||||
|
if (nbPages <= 1) {
|
||||||
|
elements.pagination.style.display = 'none'
|
||||||
|
elements.paginationList.innerHTML = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.pagination.style.display = 'block'
|
||||||
|
|
||||||
|
const isFirstPage = page === 0
|
||||||
|
const isLastPage = page === nbPages - 1
|
||||||
|
|
||||||
|
// Responsive page display
|
||||||
|
const isMobile = window.innerWidth < 768
|
||||||
|
const maxVisiblePages = isMobile ? 3 : 5
|
||||||
|
let startPage = Math.max(0, page - Math.floor(maxVisiblePages / 2))
|
||||||
|
const endPage = Math.min(nbPages - 1, startPage + maxVisiblePages - 1)
|
||||||
|
|
||||||
|
// Adjust starting page to maintain max visible pages
|
||||||
|
if (endPage - startPage + 1 < maxVisiblePages) {
|
||||||
|
startPage = Math.max(0, endPage - maxVisiblePages + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
let pagesHTML = ''
|
||||||
|
|
||||||
|
// Only add ellipsis and first page when there are many pages
|
||||||
|
if (nbPages > maxVisiblePages && startPage > 0) {
|
||||||
|
pagesHTML += `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--page">
|
||||||
|
<a class="ais-Pagination-link" aria-label="Page 1" href="#" data-page="0">1</a>
|
||||||
|
</li>`
|
||||||
|
if (startPage > 1) {
|
||||||
|
pagesHTML += `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--ellipsis">
|
||||||
|
<span class="ais-Pagination-link">...</span>
|
||||||
|
</li>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add middle page numbers
|
||||||
|
for (let i = startPage; i <= endPage; i++) {
|
||||||
|
const isSelected = i === page
|
||||||
|
if (isSelected) {
|
||||||
|
pagesHTML += `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--page ais-Pagination-item--selected">
|
||||||
|
<span class="ais-Pagination-link" aria-label="Page ${i + 1}">${i + 1}</span>
|
||||||
|
</li>`
|
||||||
|
} else {
|
||||||
|
pagesHTML += `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--page">
|
||||||
|
<a class="ais-Pagination-link" aria-label="Page ${i + 1}" href="#" data-page="${i}">${i + 1}</a>
|
||||||
|
</li>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only add ellipsis and last page when there are many pages
|
||||||
|
if (nbPages > maxVisiblePages && endPage < nbPages - 1) {
|
||||||
|
if (endPage < nbPages - 2) {
|
||||||
|
pagesHTML += `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--ellipsis">
|
||||||
|
<span class="ais-Pagination-link">...</span>
|
||||||
|
</li>`
|
||||||
|
}
|
||||||
|
pagesHTML += `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--page">
|
||||||
|
<a class="ais-Pagination-link" aria-label="Page ${nbPages}" href="#" data-page="${nbPages - 1}">${nbPages}</a>
|
||||||
|
</li>`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbPages > 1) {
|
||||||
|
elements.paginationList.innerHTML = `
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--previousPage ${isFirstPage ? 'ais-Pagination-item--disabled' : ''}">
|
||||||
|
${isFirstPage
|
||||||
|
? '<span class="ais-Pagination-link ais-Pagination-link--disabled" aria-label="Previous Page"><i class="fas fa-angle-left"></i></span>'
|
||||||
|
: `<a class="ais-Pagination-link" aria-label="Previous Page" href="#" data-page="${page - 1}"><i class="fas fa-angle-left"></i></a>`
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
${pagesHTML}
|
||||||
|
<li class="ais-Pagination-item ais-Pagination-item--nextPage ${isLastPage ? 'ais-Pagination-item--disabled' : ''}">
|
||||||
|
${isLastPage
|
||||||
|
? '<span class="ais-Pagination-link ais-Pagination-link--disabled" aria-label="Next Page"><i class="fas fa-angle-right"></i></span>'
|
||||||
|
: `<a class="ais-Pagination-link" aria-label="Next Page" href="#" data-page="${page + 1}"><i class="fas fa-angle-right"></i></a>`
|
||||||
|
}
|
||||||
|
</li>`
|
||||||
|
} else {
|
||||||
|
elements.pagination.style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear search results and stats
|
||||||
|
const clearSearchResults = () => {
|
||||||
|
const container = document.getElementById('local-search-results')
|
||||||
|
container.textContent = ''
|
||||||
|
statsItem.textContent = ''
|
||||||
|
toggleResultsVisibility(false)
|
||||||
|
if (enablePagination) {
|
||||||
|
currentResultItems = []
|
||||||
|
currentPage = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show no results message
|
||||||
|
const showNoResults = searchText => {
|
||||||
|
const container = document.getElementById('local-search-results')
|
||||||
|
container.textContent = ''
|
||||||
|
const statsDiv = document.createElement('div')
|
||||||
|
statsDiv.className = 'search-result-stats'
|
||||||
|
statsDiv.textContent = languages.hits_empty.replace(/\$\{query}/, searchText)
|
||||||
|
statsItem.innerHTML = statsDiv.outerHTML
|
||||||
|
toggleResultsVisibility(false)
|
||||||
|
if (enablePagination) {
|
||||||
|
currentResultItems = []
|
||||||
|
currentPage = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const inputEventFunction = () => {
|
const inputEventFunction = () => {
|
||||||
if (!localSearch.isfetched) return
|
if (!localSearch.isfetched) return
|
||||||
let searchText = input.value.trim().toLowerCase()
|
let searchText = input.value.trim().toLowerCase()
|
||||||
isXml && (searchText = searchText.replace(/</g, '<').replace(/>/g, '>'))
|
isXml && (searchText = searchText.replace(/</g, '<').replace(/>/g, '>'))
|
||||||
if (searchText !== '') $loadingStatus.innerHTML = '<i class="fas fa-spinner fa-pulse"></i>'
|
|
||||||
|
if (searchText !== '') $loadingStatus.hidden = false
|
||||||
|
|
||||||
const keywords = searchText.split(/[-\s]+/)
|
const keywords = searchText.split(/[-\s]+/)
|
||||||
const container = document.getElementById('local-search-results')
|
|
||||||
let resultItems = []
|
let resultItems = []
|
||||||
|
|
||||||
if (searchText.length > 0) {
|
if (searchText.length > 0) {
|
||||||
// Perform local searching
|
|
||||||
resultItems = localSearch.getResultItems(keywords)
|
resultItems = localSearch.getResultItems(keywords)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keywords.length === 1 && keywords[0] === '') {
|
if (keywords.length === 1 && keywords[0] === '') {
|
||||||
container.textContent = ''
|
clearSearchResults()
|
||||||
statsItem.textContent = ''
|
|
||||||
} else if (resultItems.length === 0) {
|
} else if (resultItems.length === 0) {
|
||||||
container.textContent = ''
|
showNoResults(searchText)
|
||||||
const statsDiv = document.createElement('div')
|
|
||||||
statsDiv.className = 'search-result-stats'
|
|
||||||
statsDiv.textContent = languages.hits_empty.replace(/\$\{query}/, searchText)
|
|
||||||
statsItem.innerHTML = statsDiv.outerHTML
|
|
||||||
} else {
|
} else {
|
||||||
|
// Sort results by relevance
|
||||||
resultItems.sort((left, right) => {
|
resultItems.sort((left, right) => {
|
||||||
if (left.includedCount !== right.includedCount) {
|
if (left.includedCount !== right.includedCount) {
|
||||||
return right.includedCount - left.includedCount
|
return right.includedCount - left.includedCount
|
||||||
@@ -279,14 +468,14 @@ window.addEventListener('load', () => {
|
|||||||
return right.id - left.id
|
return right.id - left.id
|
||||||
})
|
})
|
||||||
|
|
||||||
const stats = languages.hits_stats.replace(/\$\{hits}/, resultItems.length)
|
if (enablePagination) {
|
||||||
|
currentResultItems = resultItems
|
||||||
container.innerHTML = `<ol class="search-result-list">${resultItems.map(result => result.item).join('')}</ol>`
|
currentPage = 0
|
||||||
statsItem.innerHTML = `<hr><div class="search-result-stats">${stats}</div>`
|
}
|
||||||
window.pjax && window.pjax.refresh(container)
|
renderResults(searchText, resultItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
$loadingStatus.textContent = ''
|
$loadingStatus.hidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let loadFlag = false
|
let loadFlag = false
|
||||||
@@ -340,11 +529,29 @@ window.addEventListener('load', () => {
|
|||||||
localSearch.fetchData()
|
localSearch.fetchData()
|
||||||
}
|
}
|
||||||
localSearch.highlightSearchWords(document.getElementById('article-container'))
|
localSearch.highlightSearchWords(document.getElementById('article-container'))
|
||||||
|
|
||||||
|
// Pagination event delegation - only add if pagination is enabled
|
||||||
|
if (enablePagination) {
|
||||||
|
elements.pagination.addEventListener('click', e => {
|
||||||
|
e.preventDefault()
|
||||||
|
const link = e.target.closest('a[data-page]')
|
||||||
|
if (link) {
|
||||||
|
const page = parseInt(link.dataset.page, 10)
|
||||||
|
if (!isNaN(page) && currentResultItems.length > 0) {
|
||||||
|
currentPage = page
|
||||||
|
renderResults(input.value.trim().toLowerCase(), currentResultItems)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial state
|
||||||
|
toggleResultsVisibility(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('search:loaded', () => {
|
window.addEventListener('search:loaded', () => {
|
||||||
const $loadDataItem = document.getElementById('loading-database')
|
const $loadDataItem = document.getElementById('loading-database')
|
||||||
$loadDataItem.nextElementSibling.style.display = 'block'
|
$loadDataItem.nextElementSibling.style.visibility = 'visible'
|
||||||
$loadDataItem.remove()
|
$loadDataItem.remove()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -106,7 +106,7 @@
|
|||||||
|
|
||||||
loadComment: (dom, callback) => {
|
loadComment: (dom, callback) => {
|
||||||
if ('IntersectionObserver' in window) {
|
if ('IntersectionObserver' in window) {
|
||||||
const observerItem = new IntersectionObserver((entries) => {
|
const observerItem = new IntersectionObserver(entries => {
|
||||||
if (entries[0].isIntersecting) {
|
if (entries[0].isIntersecting) {
|
||||||
callback()
|
callback()
|
||||||
observerItem.disconnect()
|
observerItem.disconnect()
|
||||||
@@ -249,7 +249,7 @@
|
|||||||
'rotateCW',
|
'rotateCW',
|
||||||
'flipX',
|
'flipX',
|
||||||
'flipY',
|
'flipY',
|
||||||
"reset"
|
'reset'
|
||||||
],
|
],
|
||||||
right: ['autoplay', 'thumbs', 'close']
|
right: ['autoplay', 'thumbs', 'close']
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user