add theme

This commit is contained in:
2025-08-12 12:19:25 +08:00
parent 8c06923a46
commit ac0d1944ab
227 changed files with 18962 additions and 0 deletions

View File

@@ -0,0 +1,280 @@
.limit-one-line
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
.limit-more-line
display: -webkit-box
overflow: hidden
-webkit-box-orient: vertical
.fontawesomeIcon
display: inline-block
font-weight: 600
font-family: 'Font Awesome 7 Free', 'Font Awesome 6 Free'
text-rendering: auto
-webkit-font-smoothing: antialiased
addBorderRadius(x = 6, hide = false)
if hexo-config('rounded_corners_ui')
border-radius: unit(x, 'px')
if hide
overflow: hidden
// card hover
.cardHover
background: var(--card-bg)
box-shadow: var(--card-box-shadow)
transition: all .3s
addBorderRadius(8)
&:hover
box-shadow: var(--card-hover-box-shadow)
.imgHover
width: 100%
height: 100%
transition: filter 375ms ease-in .2s, transform .6s
object-fit: cover
&:hover
transform: scale(1.1)
.postImgHover
&:hover
.cover
opacity: .5
transform: scale(1.1)
.cover
width: 100%
height: 100%
opacity: .4
transition: all .6s, filter 375ms ease-in .2s
object-fit: cover
.list-beauty
list-style: none
li
position: relative
padding: .12em .4em .12em 1.4em
&:hover
&:before
border-color: var(--pseudo-hover)
&:before
position: absolute
top: .67em
left: 0
width: w = .43em
height: h = w
border: .5 * w solid $light-blue
border-radius: w
background: transparent
content: ''
cursor: pointer
transition: all .3s ease-out
.custom-hr
position: relative
margin: 40px auto
border: 2px dashed var(--hr-border)
if hexo-config('hr_icon.enable')
width: calc(100% - 4px)
&:hover
&:before
left: calc(95% - 20px)
&:before
position: absolute
top: $hr-icon-top
left: 5%
z-index: 1
color: var(--hr-before-color)
content: $hr-icon
font-size: 20px
line-height: 1
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}
maxWidth768()
@media screen and (max-width: 768px)
{block}
minWidth768()
@media screen and (min-width: 768px)
{block}
maxWidth1024()
@media screen and (max-width: 1024px)
{block}
minWidth1024()
@media screen and (min-width: 1024px)
{block}
maxWidth900()
@media screen and (max-width: 900px)
{block}
minWidth901()
@media screen and (min-width: 901px)
{block}
minWidth900()
@media screen and (min-width: 900px)
{block}
minWidth2000()
@media screen and (min-width: 2000px)
{block}
// animation
if hexo-config('enter_transitions')
#content-inner,
#footer
animation: bottom-top 1s
#page-header:not(.full_page),
#nav.show
animation: header-effect 1s
#site-title,
#site-subtitle
animation: titleScale 1s
canvas:not(#ribbon-canvas),
#web_bg
animation: to_show 4s
#ribbon-canvas
animation: ribbon_to_show 4s
#sidebar-menus
&.open
for i in 1 2 3 4
> :nth-child({i})
animation: sidebarItem (i / 5s)
.scroll-down-effects
animation: scroll-down-effect 1.5s infinite
if hexo-config('avatar.effect') == true
.avatar-img
animation: avatar_turn_around 2s linear infinite
.reward-main
animation: donate_effcet .3s .1s ease both
@keyframes scroll-down-effect
0%
opacity: .4
transform: translate(0, 0)
50%
opacity: 1
transform: translate(0, -16px)
100%
opacity: .4
transform: translate(0, 0)
@keyframes header-effect
0%
transform: translateY(-35px)
100%
transform: translateY(0)
@keyframes bottom-top
0%
transform: translateY(35px)
100%
transform: translateY(0)
@keyframes titleScale
0%
opacity: 0
transform: scale(.7)
100%
opacity: 1
transform: scale(1)
@keyframes search_close
0%
opacity: 1
transform: scale(1)
100%
opacity: 0
transform: scale(.7)
@keyframes to_show
0%
opacity: 0
100%
opacity: 1
@keyframes to_hide
0%
opacity: 1
100%
opacity: 0
@keyframes ribbon_to_show
0%
opacity: 0
100%
opacity: hexo-config('canvas_ribbon.alpha')
@keyframes avatar_turn_around
from
transform: rotate(0)
to
transform: rotate(360deg)
@keyframes sub_menus
0%
opacity: 0
transform: translateY(10px)
100%
opacity: 1
transform: translateY(0)
@keyframes donate_effcet
0%
opacity: 0
transform: translateY(-20px)
100%
opacity: 1
transform: translateY(0)
@keyframes sidebarItem
0%
transform: translateX(200px)
100%
transform: translateX(0)

View File

@@ -0,0 +1,228 @@
:root
--global-font-size: $font-size
--global-bg: $body-bg
--font-color: $font-black
--hr-border: lighten($theme-hr-color, 50%)
--hr-before-color: lighten($theme-hr-color, 30%)
--search-bg: $search-bg
--search-input-color: $search-input-color
--search-a-color: $search-a-color
--preloader-bg: $preloader-bg
--preloader-color: $preloader-word-color
--tab-border-color: $tab-border-color
--tab-button-bg: $tab-button-bg
--tab-button-color: $tab-button-color
--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
--text-bg-hover: rgba($text-bg-hover, .7)
--light-grey: $light-grey
--dark-grey: $dark-grey
--white: $white
--text-highlight-color: $text-highlight-color
--blockquote-color: $blockquote-color
--blockquote-bg: $blockquote-background-color
--reward-pop: $reward-pop-up-bg
--toc-link-color: $toc-link-color
--card-box-shadow: 0 3px 8px 6px rgba(7, 17, 27, .05)
--card-hover-box-shadow: 0 3px 8px 6px rgba(7, 17, 27, .09)
--pseudo-hover: $pseudo-hover
--headline-presudo: #a0a0a0
--scrollbar-color: $scrollbar-color
--default-bg-color: $theme-color
--zoom-bg: #fff
--mark-bg: alpha($dark-black, .3)
body
position: relative
overflow-y: scroll
min-height: 100%
background: var(--global-bg)
color: var(--font-color)
font-size: var(--global-font-size)
font-family: $font-family
line-height: $text-line-height
-webkit-tap-highlight-color: rgba(0, 0, 0, 0)
scroll-behavior: smooth
if !hexo-config('copy.enable')
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
height: 5px
*::-webkit-scrollbar-thumb
background: var(--scrollbar-color)
*::-webkit-scrollbar-track
background-color: transparent
input::placeholder
color: var(--font-color)
if hexo-config('background')
#web_bg
position: fixed
z-index: -999
width: 100%
height: 100%
background-attachment: local
background-position: center
background-size: cover
background-repeat: no-repeat
h1,
h2,
h3,
h4,
h5,
h6
position: relative
margin: 20px 0 14px
color: var(--text-highlight-color)
font-weight: bold
code
font-size: inherit !important
*
box-sizing: border-box
.table-wrap
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: separate
border-top: 1px solid var(--light-grey)
border-left: 1px solid var(--light-grey)
empty-cells: show
thead
background: alpha($table-thead-bg, 10%)
th,
td
padding: 6px 12px
border: 1px solid var(--light-grey)
border-top: none
border-left: none
vertical-align: middle
*::selection
background: $theme-text-selection-color
color: #F7F7F7
button
padding: 0
outline: 0
border: none
background: none
cursor: pointer
touch-action: manipulation
a
color: $a-link-color
text-decoration: none
word-wrap: break-word
transition: all .2s
overflow-wrap: break-word
&:hover
color: $light-blue
// font
if $site-name-font
#site-title,
#site-subtitle,
.site-name,
#aside-content .author-info-name,
#aside-content .author-info-description
font-family: $site-name-font
.text-center
text-align: center
.text-right
text-align: right
img
&[src=''],
&:not([src])
opacity: 0
// lazyload blur
if hexo-config('lazyload.enable') && hexo-config('lazyload.blur') && !hexo-config('lazyload.placeholder')
img
&[data-lazy-src]:not(.loaded)
filter: blur(8px) brightness(1)
&[data-lazy-src].error
filter: none
.img-alt
margin: -10px 0 10px
color: #858585
&:hover
text-decoration: none !important
blockquote
margin: 0 0 20px
padding: 7px 15px
border-left: 4px solid $blockquote-padding-color
background-color: var(--blockquote-bg)
color: var(--blockquote-color)
addBorderRadius()
footer
cite
&:before
padding: 0 5px
content: ''
& > :last-child
margin-bottom: 0 !important
.fa-fw
width: 1.25em
text-align: center

View File

@@ -0,0 +1,281 @@
$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'
:root
--hl-color: $highlight-foreground
--hl-bg: $highlight-background
--hltools-bg: $highlight-tools.bg-color
--hltools-color: $highlight-tools.color
--hlnumber-bg: $highlight-gutter.bg-color
--hlnumber-color: $highlight-gutter.color
--hlscrollbar-bg: $highlight-scrollbar
--hlexpand-bg: linear-gradient(180deg, rgba($highlight-background, .6), rgba($highlight-background, .9))
[data-theme='dark']
--hl-color: alpha(#FFFFFF, .7)
--hl-bg: lighten(#121212, 2)
--hltools-bg: lighten(#121212, 3)
--hltools-color: #90a4ae
--hlnumber-bg: lighten(#121212, 2)
--hlnumber-color: alpha(#FFFFFF, .4)
--hlscrollbar-bg: lighten(#121212, 5)
--hlexpand-bg: linear-gradient(180deg, rgba(lighten(#121212, 2), .6), rgba(lighten(#121212, 2), .9))
if $highlight_enable
@require 'highlight/index'
if $prismjs_enable
@require 'prismjs/index'
$code-block
overflow: auto
margin: 0 0 20px
padding: 0
background: var(--hl-bg)
color: var(--hl-color)
line-height: $line-height-code-block
if wordWrap
counter-reset: line
white-space: pre-wrap
.container
pre,
code
font-size: $code-font-size
font-family: $code-font-family !important
addBorderRadius()
code
padding: 2px 5px
background: $code-background
color: $code-foreground
pre
@extend $code-block
padding: 10px 20px
code
padding: 0
background: none
color: var(--hl-color)
text-shadow: none
figure.highlight
@extend $code-block
position: relative
addBorderRadius()
pre
margin: 0
padding: 8px 0
border: none
figcaption,
.caption
padding: 6px 0 2px 14px
font-size: $code-font-size
line-height: 1em
a
float: right
padding-right: 10px
color: var(--hl-color)
&:hover
border-bottom-color: var(--hl-color)
&.copy-true
user-select: all
-webkit-user-select: all
& > table,
& > pre
display: block !important
opacity: 0
.highlight-tools
display: flex
align-items: center
padding: 0 8px
min-height: 24px
height: 2.15em
background: var(--hltools-bg)
color: var(--hltools-color)
font-size: $code-font-size
overflow: hidden
& > *
padding: 5px
i
cursor: pointer
transition: all .3s
&:hover
color: $theme-color
&.closed
& ~ *
display: none
.expand
transform: rotate(-90deg)
if !$highlight_macstyle
& > .macStyle
padding: 0
.code-lang
flex: 1
text-transform: uppercase
font-weight: bold
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('code_blocks.language')
.code-lang
flex: 1
else if (!$highlight_macstyle && hexo-config('code_blocks.shrink') != 'none')
& > div:nth-child(2)
flex: 1
else
.macStyle
flex: 1
.gutter
user-select: none
-webkit-user-select: none
.gist table
width: auto
td
border: none
if $highlight_macstyle
.container
figure.highlight
margin: 0 0 24px
border-radius: 7px
box-shadow: 0 5px 10px 0 $highlight-mac-border
-webkit-transform: translateZ(0)
.highlight-tools
.macStyle
display: flex
& > *
margin-right: 8px
width: 12px
height: 12px
border-radius: 50%
& > :last-child
margin-right: 5px
.mac-close
background: #fc625d
.mac-minimize
background: #fdbc40
.mac-maximize
background: #35cd4b
if hexo-config('code_blocks.shrink') != 'none'
& > :nth-child(2)
order: 8
&.closed
.expand
transform: rotate(90deg)
if hexo-config('code_blocks.height_limit')
.container
.code-expand-btn
position: absolute
bottom: 0
z-index: 10
width: 100%
background: var(--hlexpand-bg)
text-align: center
font-size: $code-font-size
cursor: pointer
i
padding: 6px 0
color: var(--hlnumber-color)
animation: code-expand-key 1.2s infinite
&.expand-done
& > i
transform: rotate(180deg)
& + table,
& + pre
margin-bottom: 1.8em
&:not(.expand-done)
& ~ table,
& ~ pre
overflow: hidden
height: unit(hexo-config('code_blocks.height_limit'), px)
@keyframes code-expand-key
0%
opacity: .6
50%
opacity: .1
100%
opacity: .6
if hexo-config('code_blocks.fullpage')
.container
figure.highlight.code-fullpage
position: fixed
top: 0
right: 0
bottom: 0
left: 0
z-index: 9999
margin: 0
border-radius: 0
animation: code-fullpage .3s
.code-expand-btn,
.expand
display: none
.highlight-tools
& ~ pre,
& ~ table
display: block
overflow: auto
height: calc(100vh - 2.15em)
margin-bottom: 0
@keyframes code-fullpage
0%,
100%
transform: translateX(0)
20%,
60%
transform: translateX(-5px)
40%,
80%
transform: translateX(5px)

View File

@@ -0,0 +1,81 @@
figure.highlight
table
// scrollbar - firefox
@-moz-document url-prefix()
scrollbar-color: var(--hlscrollbar-bg) transparent
&::-webkit-scrollbar-thumb
background: var(--hlscrollbar-bg)
pre .deletion
color: $highlight-deletion
pre .addition
color: $highlight-addition
pre .meta
color: $highlight-purple
pre
.comment
color: $highlight-comment
.variable,
.attribute,
.regexp,
.ruby .constant,
.xml .tag .title,
.xml .pi,
.xml .doctype,
.html .doctype,
.css .id,
.tag .name,
.css .class,
.css .pseudo
color: $highlight-red
.tag
color: $highlight-aqua
.number,
.preprocessor,
.literal,
.params,
.constant,
.command
color: $highlight-orange
.built_in
color: $highlight-yellow
.ruby .class .title,
.css .rules .attribute,
.string,
.value,
.inheritance,
.header,
.ruby .symbol,
.xml .cdata,
.special,
.number,
.formula
color: $highlight-green
.keyword,
.title,
.css .hexcolor
color: $highlight-aqua
.function,
.python .decorator,
.python .title,
.ruby .function .title,
.ruby .title .keyword,
.perl .sub,
.javascript .title,
.coffeescript .title
color: $highlight-blue
.tag .attr,
.javascript .function
color: $highlight-purple

View File

@@ -0,0 +1,39 @@
if $highlight_theme != false
@require 'diff'
.container
figure.highlight
.line
if wordWrap
&:before
display: inline-block
padding: 0 6px 0 0
min-width: 30px
color: var(--hlnumber-color)
content: counter(line)
counter-increment: line
text-align: left
&.marked
background-color: $highlight-selection
table
display: block
overflow: auto
border: none
td
padding: 0
border: none
.gutter pre
padding-right: 10px
padding-left: 10px
background-color: var(--hlnumber-bg)
color: var(--hlnumber-color)
text-align: right
.code pre
padding-right: 10px
padding-left: 10px
width: 100%

View File

@@ -0,0 +1,302 @@
if $highlight_theme == 'light'
// prism-base16-ateliersulphurpool.light
pre[class*='language-']
.token.function
color: #ffb62c
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata
color: rgba(149, 165, 166, .8)
.token.punctuation
color: #5e6687
.token.namespace
opacity: .7
.token.operator,
.token.boolean,
.token.number
color: #c76b29
.token.property
color: #c08b30
.token.tag
color: #3d8fd1
.token.string
color: #22a2c9
.token.selector
color: #6679cc
.token.attr-name
color: #c76b29
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string
color: #22a2c9
.token.attr-value,
.token.keyword,
.token.control,
.token.directive,
.token.unit
color: #ac9739
.token.statement,
.token.regex,
.token.atrule
color: #22a2c9
.token.placeholder,
.token.variable
color: #3d8fd1
.token.deleted
text-decoration: line-through
.token.inserted
border-bottom: 1px dotted #202746
text-decoration: none
.token.italic
font-style: italic
.token.important,
.token.bold
font-weight: bold
.token.important
color: #c94922
.token.entity
cursor: help
pre > code.highlight
outline: .4em solid #c94922
outline-offset: .4em
if $highlight_theme == 'darker'
// prism-atom-dark
pre[class*='language-']
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata
color: #7C7C7C
.token.punctuation
color: #c5c8c6
.namespace
opacity: .7
.token.property,
.token.keyword,
.token.tag
color: #96CBFE
.token.class-name
color: #FFFFB6
.token.boolean,
.token.constant
color: #99CC99
.token.symbol,
.token.deleted
color: #f92672
.token.number
color: #FF73FD
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted
color: #A8FF60
.token.variable
color: #C6C5FE
.token.operator
color: #EDEDED
.token.entity
color: #FFFFB6
cursor: help
.token.url
color: #96CBFE
.language-css .token.string,
.style .token.string
color: #87C38A
.token.atrule,
.token.attr-value
color: #F9EE98
.token.function
color: #DAD085
.token.regex
color: #E9C062
.token.important
color: #fd971f
.token.important,
.token.bold
font-weight: bold
.token.italic
font-style: italic
if $highlight_theme == 'pale night'
// prism-dracula
pre[class*='language-']
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata
color: #6272a4
.token.punctuation
color: #f8f8f2
.namespace
opacity: .7
.token.property,
.token.tag,
.token.constant,
.token.symbol,
.token.deleted
color: #ff79c6
.token.boolean,
.token.number
color: #bd93f9
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted
color: #50fa7b
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable
color: #f8f8f2
.token.atrule,
.token.attr-value,
.token.function,
.token.class-name
color: #f1fa8c
.token.keyword
color: #8be9fd
.token.regex,
.token.important
color: #ffb86c
.token.important,
.token.bold
font-weight: bold
.token.italic
font-style: italic
.token.entity
cursor: help
if $highlight_theme == 'ocean'
// prism-material-oceanic
pre[class*='language-']
&.language-css > code,
&.language-sass > code,
&.language-scss > code
color: #fd9170 !important
.namespace
opacity: .7
.token.atrule,
.token.symbol,
.token.constant,
.token.boolean,
.token.function
color: #c792ea
.token.attr-name,
.token.builtin,
.token.class
color: #ffcb6b
.token.attr-value,
.token.attribute,
.token.pseudo-class,
.token.pseudo-element,
.token.string
color: #c3e88d
.token.cdata,
.token.property,
.token.char,
.token.inserted
color: #80cbc4
.token.class-name,
.token.color,
.token.hexcode,
.token.regex
color: #f2ff00
.token.comment,
.token.prolog,
.token.doctype
color: #546e7a
.token.deleted,
.token.variable,
.token.entity,
.token.selector,
.token.tag,
.token.unit
color: #f07178
.token.id
color: #c792ea
font-weight: bold
.token.important
color: #c792ea
font-weight: bold
.token.keyword
color: #c792ea
font-style: italic
.token.number,
.token.url
color: #fd9170
.token.operator,
.token.punctuation
color: #89ddff

View File

@@ -0,0 +1,24 @@
if $prismjs_line_number
@require 'line-number'
if $highlight_theme != false
@require 'diff'
.container
pre[class*='language-']
// scrollbar - firefox
@-moz-document url-prefix()
scrollbar-color: var(--hlscrollbar-bg) transparent
&::-webkit-scrollbar-thumb
background: var(--hlscrollbar-bg)
&:not(.line-numbers)
padding: 10px 20px
.caption
margin-left: -3.8em
padding: 4px 16px !important
a
padding: 0 !important

View File

@@ -0,0 +1,42 @@
.container
pre[class*='language-']
&.line-numbers
position: relative
padding-left: 3.8em
counter-reset: linenumber
line-height: $line-height-code-block
> code
position: relative
line-height: $line-height-code-block
if hexo-config('code_blocks.word_wrap')
white-space: pre-wrap
else
white-space: inherit
word-wrap: normal
word-break: normal
overflow-wrap: normal
.line-numbers-rows
position: absolute
top: 0
left: -3.8em
width: 3em
letter-spacing: -1px
font-size: 100%
pointer-events: none
user-select: none
-webkit-user-select: none
& > span
display: block
counter-increment: linenumber
pointer-events: none
&:before
display: block
padding-right: .8em
color: var(--hlnumber-color)
content: counter(linenumber)
text-align: right

View File

@@ -0,0 +1,121 @@
if $highlight_theme == 'darker'
$highlight-background = #212121
$highlight-selection = #61616150
$highlight-foreground = #EEFFFF
$highlight-mac-border = rgba(0, 0, 0, .4)
$highlight-gutter = {
color: alpha($highlight-foreground, .5),
bg-color: $highlight-background
}
$highlight-tools = {
color: alpha($highlight-foreground, .8),
bg-color: darken($highlight-background, 2)
}
$highlight-scrollbar = lighten($highlight-background, 8)
if $highlight_enable
$highlight-comment = #969896
$highlight-red = #FF5370
$highlight-orange = #F78C6C
$highlight-yellow = #FFCB6B
$highlight-green = #C3E88D
$highlight-aqua = #89DDFF
$highlight-blue = #82AAFF
$highlight-purple = #C792EA
$highlight-deletion = #BF42BF
$highlight-addition = #105EDE
if $highlight_theme == 'pale night'
$highlight-background = #292D3E
$highlight-selection = #717CB450
$highlight-foreground = #A6ACCD
$highlight-mac-border = rgba($highlight-background, .4)
$highlight-gutter = {
color: alpha($highlight-foreground, .5),
bg-color: $highlight-background
}
$highlight-tools = {
color: $highlight-foreground,
bg-color: darken($highlight-background, 2)
}
$highlight-scrollbar = lighten($highlight-background, 8)
if $highlight_enable
$highlight-comment = #676E95
$highlight-red = #FF5370
$highlight-orange = #F78C6C
$highlight-yellow = #FFCB6B
$highlight-green = #C3E88D
$highlight-aqua = #89DDFF
$highlight-blue = #82AAFF
$highlight-purple = #C792EA
$highlight-deletion = #BF42BF
$highlight-addition = #105EDE
if $highlight_theme == 'ocean'
$highlight-background = #0F111A
$highlight-selection = #717CB450
$highlight-foreground = #8F93A2
$highlight-mac-border = rgba($highlight-background, .4)
$highlight-gutter = {
color: alpha($highlight-foreground, .5),
bg-color: $highlight-background
}
$highlight-tools = {
color: $highlight-foreground,
bg-color: darken($highlight-background, 2)
}
$highlight-scrollbar = lighten($highlight-background, 8)
if $highlight_enable
$highlight-comment = rgba(101, 115, 126, .8)
$highlight-red = #FF5370
$highlight-orange = #F78C6C
$highlight-yellow = #FFCB6B
$highlight-green = #C3E88D
$highlight-aqua = #89DDFF
$highlight-blue = #82AAFF
$highlight-purple = #C792EA
$highlight-deletion = #BF42BF
$highlight-addition = #105EDE
if $highlight_theme == 'light'
$highlight-background = #F6F8FA
$highlight-selection = #80CBC440
$highlight-foreground = #90A4AE
$highlight-mac-border = rgba(144, 164, 174, .4)
$highlight-tools = {
color: $highlight-foreground,
bg-color: darken($highlight-background, 5)
}
$highlight-gutter = {
color: alpha($highlight-foreground, .5),
bg-color: $highlight-background
}
$highlight-scrollbar = darken($highlight-background, 8)
if $highlight_enable
$highlight-comment = rgba(149, 165, 166, .8)
$highlight-red = #E53935
$highlight-orange = #F76D47
$highlight-yellow = #FFB62C
$highlight-green = #91B859
$highlight-aqua = #39ADB5
$highlight-blue = #6182B8
$highlight-purple = #7C4DFF
$highlight-deletion = #BF42BF
$highlight-addition = #105EDE
if $highlight_theme == false
$highlight-background = #F6F8FA
$highlight-foreground = #90A4AE
$highlight-selection = #80CBC440
$highlight-gutter = {
color: alpha($highlight-foreground, .5),
bg-color: $highlight-background
}
$highlight-tools = {
color: $highlight-foreground,
bg-color: darken($highlight-background, 5)
}
$highlight-scrollbar = darken($highlight-background, 8)

View File

@@ -0,0 +1,150 @@
// ===================
// 🌗 使
// ===================
:root
// ai_summary
--liushen-title-font-color: #0883b7
--liushen-maskbg: rgba(255, 255, 255, 0.85)
--liushen-ai-bg: conic-gradient(from 1.5708rad at 50% 50%, #d6b300 0%, #42A2FF 54%, #d6b300 100%)
// card
--liushen-card-secondbg: #f1f3f8
// text
--liushen-text: #4c4948
--liushen-secondtext: #3c3c43cc
[data-theme='dark']
// ai_summary
--liushen-title-font-color: #0883b7
--liushen-maskbg: rgba(0, 0, 0, 0.85)
--liushen-ai-bg: conic-gradient(from 1.5708rad at 50% 50%, rgba(214, 178, 0, 0.46) 0%, rgba(66, 161, 255, 0.53) 54%, rgba(214, 178, 0, 0.49) 100%)
// card
--liushen-card-secondbg: #3e3f41
// text
--liushen-text: #ffffffb3
--liushen-secondtext: #a1a2b8
// ===================
// 📘 AI
// ===================
if hexo-config('ai_summary.enable')
.ai-summary
background-color var(--liushen-maskbg)
background var(--liushen-card-secondbg)
border-radius 12px
padding 8px 8px 12px 8px
line-height 1.3
flex-direction column
margin-bottom 16px
display flex
gap 5px
position relative
&::before
content ''
position absolute
top 0
left 0
width 100%
height 100%
z-index 1
filter blur(8px)
opacity .4
background-image var(--liushen-ai-bg)
transform scaleX(1) scaleY(.95) translateY(2px)
&::after
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2;
border-radius: 12px;
background: var(--liushen-maskbg);
.ai-explanation
z-index 10
padding 8px 12px
font-size 15px
line-height 1.4
color var(--liushen-text)
text-align justify
//
&::after
content ''
display inline-block
width 8px
height 2px
margin-left 2px
background var(--liushen-text)
vertical-align bottom
animation blink-underline 1s ease-in-out infinite
transition all .3s
position relative
bottom 3px
//
// .char
// display inline-block
// opacity 0
// animation chat-float .5s ease forwards
.ai-title
z-index 10
font-size 14px
display flex
border-radius 8px
align-items center
position relative
padding 0 12px
cursor default
user-select none
.ai-title-left
display flex
align-items center
color var(--liushen-title-font-color)
i
margin-right 3px
display flex
color var(--liushen-title-font-color)
border-radius 20px
justify-content center
align-items center
.ai-title-text
font-weight 500
.ai-tag
color var(--liushen-secondtext)
font-weight 300
margin-left auto
display flex
align-items center
justify-content center
transition .3s
//
// @keyframes chat-float
// 0%
// opacity 0
// transform translateY(20px)
// 100%
// opacity 1
// transform translateY(0)
//
@keyframes blink-underline
0%, 100%
opacity 1
50%
opacity 0

View File

@@ -0,0 +1,424 @@
#aside-content
width: 26%
+minWidth900()
if hexo-config('aside.position') == 'right'
padding-left: 15px
else
padding-right: 15px
+maxWidth900()
margin-top: 20px
width: 100%
.card-widget
@extend .cardHover
position: relative
overflow: hidden
margin-bottom: 20px
padding: 20px 24px
if hexo-config('aside.mobile') == false
+maxWidth768()
&:not(#card-toc)
display: none
// &:last-child
// margin-bottom: 0
.card-info
.author-info
&-name
font-weight: 500
font-size: 1.57em
&-description
margin-top: -.42em
.site-data
margin: 14px 0 4px
.card-info-social-icons
margin: 6px 0 -6px
.social-icon
margin: 0 10px
color: var(--font-color)
font-size: 1.4em
i
transition: all .3s
&:hover
transform: rotate(360deg)
#card-info-btn
display: block
margin-top: 14px
background-color: var(--btn-bg)
color: var(--btn-color)
text-align: center
line-height: 2.4
addBorderRadius(7)
&:hover
background-color: var(--btn-hover-color)
span
padding-left: 10px
.item-headline
padding-bottom: 6px
font-size: 1.2em
span
margin-left: 6px
.sticky_layout
+minWidth900()
position: sticky
position: -webkit-sticky
top: 20px
transition: top .3s
.card-tag-cloud
a
display: inline-block
padding: 0 4px
line-height: 1.8
&:hover
color: $text-hover !important
.aside-list
& > span
display: block
margin-bottom: 10px
text-align: center
& > .aside-list-item
display: flex
align-items: center
padding: 6px 0
&:first-child
padding-top: 0
&:not(:last-child)
border-bottom: 1px dashed #f5f5f5
&:last-child
padding-bottom: 0
.thumbnail
overflow: hidden
width: w = 4em
height: w
addBorderRadius()
:first-child
@extend .imgHover
.content
flex: 1
padding-left: 10px
word-break: break-all
& > .name
@extend .limit-more-line
-webkit-line-clamp: 1
& > time,
& > .name
display: block
color: var(--card-meta)
font-size: .85em
& > .title,
& > .comment
@extend .limit-more-line
color: var(--font-color)
// font-size: 95%
line-height: 1.5
-webkit-line-clamp: 2
&:hover
color: $text-hover
&.no-cover
min-height: 4.4em
.card-archives ul.card-archive-list,
.card-categories ul.card-category-list
margin: 0
padding: 0
list-style: none
.card-archives ul.card-archive-list > .card-archive-list-item,
.card-categories ul.card-category-list > .card-category-list-item
a
display: flex
flex-direction: row
margin: 2px 0
padding: 2px 8px
color: var(--font-color)
transition: all .3s
addBorderRadius()
&:hover
padding: 2px 12px
background-color: var(--text-bg-hover)
color: var(--white)
span
@extend .limit-one-line
&:first-child
flex: 1
.card-categories
.card-category-list
&.child
padding: 0 0 0 16px
> .parent
> a
&.expand
i
transform: rotate(-90deg)
& + .child
display: block
.card-category-list
&-name
width: 70% !important
&-count
width: calc(100% - 70% - 20px)
text-align: right
i
float: right
margin-right: -.5em
padding: .5em
transition: transform .3s
transform: rotate(0)
if hexo-config('aside.card_categories.expand') == false
> .child
display: none
.card-webinfo
.webinfo
.webinfo-item
display: flex
align-items: center
padding: 2px 10px 0
div
&:first-child
flex: 1
padding-right: 20px
// toc
#card-toc
+minWidth901()
right: 0 !important
+maxWidth900()
position: fixed
right: 55px
bottom: 30px
z-index: 100
max-width: $toc-mobile-maxWidth
max-height: calc(100% - 60px)
width: $toc-mobile-width
transition: none
transform: scale(0)
transform-origin: right bottom
&.open
transform: scale(1)
.toc-percentage
float: right
margin-top: -9px
color: #a9a9a9
font-style: italic
font-size: 140%
.toc-content
overflow-y: scroll
overflow-y: overlay
margin: 0 -24px
max-height: calc(100vh - 120px)
width: calc(100% + 48px)
+maxWidth900()
max-height: calc(100vh - 140px)
& > *
margin: 0 20px !important
& > .toc-item > .toc-child
margin-left: 10px
padding-left: 10px
border-left: 1px solid var(--dark-grey)
&:not(.is-expand)
.toc-child
display: none
+maxWidth900()
display: block !important
.toc-item
&.active
.toc-child
display: block
ol,
li
list-style: none
> ol
padding: 0 !important
ol
margin: 0
padding-left: 18px
.toc-link
display: block
margin: 4px 0
padding: 1px 8px
color: var(--toc-link-color)
transition: all .2s ease-in-out
addBorderRadius()
&:hover
color: $theme-color
&.active
background: $theme-toc-color
color: $toc-active-color
.sticky_layout:only-child
> :first-child
margin-top: 0
.card-more-btn
float: right
color: inherit
&:hover
animation: more-btn-move 1s infinite
.card-announcement
.item-headline
i
color: #FF0000
.avatar-img
overflow: hidden
margin: 0 auto
width: 110px
height: 110px
border-radius: 70px
img
width: 100%
height: 100%
transition: filter 375ms ease-in .2s, transform .3s
object-fit: cover
&:hover
transform: rotate(360deg)
.site-data
display: table
width: 100%
table-layout: fixed
& > a
display: table-cell
div
transition: all .3s
&:hover
div
color: $theme-color !important
.headline
@extend .limit-one-line
color: var(--font-color)
font-size: .95em
.length-num
margin-top: -.45em
color: var(--text-highlight-color)
font-size: 1.2em
@keyframes more-btn-move
0%,
100%
transform: translateX(0)
50%
transform: translateX(3px)
@keyframes toc-open
0%
transform: scale(.7)
100%
transform: scale(1)
@keyframes toc-close
0%
transform: scale(1)
100%
transform: scale(.7)
+minWidth900()
html.hide-aside
.layout
justify-content: center
> .aside-content
display: none
> div:first-child
width: 80%
.page
.sticky_layout
display: flex
flex-direction: column
if hexo-config('aside.card_recent_post.sort_order')
.card-recent-post
order: hexo-config('aside.card_recent_post.sort_order')
if hexo-config('aside.card_newest_comments.sort_order')
#card-newest-comments
order: hexo-config('aside.card_newest_comments.sort_order')
if hexo-config('aside.card_categories.sort_order')
.card-categories
order: hexo-config('aside.card_categories.sort_order')
if hexo-config('aside.card_tags.sort_order')
.card-tags
order: hexo-config('aside.card_tags.sort_order')
if hexo-config('aside.card_archives.sort_order')
.card-archives
order: hexo-config('aside.card_archives.sort_order')
if hexo-config('aside.card_webinfo.sort_order')
.card-webinfo
order: hexo-config('aside.card_webinfo.sort_order')

View File

@@ -0,0 +1,9 @@
// chat
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

View File

@@ -0,0 +1,81 @@
#post-comment
.comment-head
margin-bottom: 20px
&:after
display: block
clear: both
content: ''
.comment-headline
display: inline-block
vertical-align: middle
font-weight: 700
font-size: 1.43em
.comment-switch
display: inline-block
if hexo-config('comments.text')
float: right
margin: 2px auto 0
padding: 4px 16px
width: max-content
border-radius: 8px
background: $comments-switch-bg
else
vertical-align: middle
> span
display: none
.first-comment
color: $comments-switch-first-text
.second-comment
color: $comments-switch-second-text
#switch-btn
position: relative
display: inline-block
margin: -4px 8px 0
width: 42px
height: 22px
border-radius: 34px
background-color: $comments-switch-first-text
vertical-align: middle
cursor: pointer
transition: .4s
&:before
position: absolute
bottom: 4px
left: 4px
width: 14px
height: 14px
border-radius: 50%
background-color: $comments-switch-round
content: ''
transition: .4s
.comment-wrap
> div
animation: tabshow .5s
&:nth-child(2)
display: none
&.move
#switch-btn
background-color: $comments-switch-second-text
&:before
transform: translateX(20px)
.comment-wrap
> div
&:first-child
display: none
&:last-child
display: block

View File

@@ -0,0 +1,87 @@
#footer
position: relative
background-color: $light-blue
background-attachment: scroll
background-position: bottom
background-size: cover
if hexo-config('footer_img') != false && hexo-config('mask.footer')
&:before
position: absolute
width: 100%
height: 100%
background-color: var(--mark-bg)
content: ''
& > *
position: relative
color: var(--light-grey)
a
color: var(--light-grey)
transition: all .3s ease-in-out
&:hover
color: $light-blue
.footer-separator
margin: 0 4px
.icp-icon
padding: 0 4px
max-height: 1.4em
width: auto
vertical-align: text-bottom
.footer-flex
display: flex
flex-direction: row
flex-wrap: wrap
justify-content: space-between
margin: 0 auto
padding: 40px 60px
max-width: 1200px
width: 100%
text-align: left
gap: 13px
+maxWidth768()
padding: 30px
gap: 10px
.footer-flex-items
flex-shrink: 0
min-width: 100px
text-align: left
white-space: nowrap
.footer-flex-title
margin-bottom: 5px
white-space: nowrap
font-weight: 600
font-size: 1.4em
.footer-flex-item
margin: 10px 0
white-space: nowrap
a
display: block
white-space: nowrap
.footer-other
padding: 40px 20px
width: 100%
text-align: center
if hexo-config('footer.nav')
padding: 10px 8px
background-color: rgba(0, 0, 0, .1)
.copyright,
.framework-info,
.footer_custom_text
font-size: .9em
else
.framework-info
display: block

View File

@@ -0,0 +1,463 @@
#page-header
position: relative
width: 100%
background-color: $light-blue
background-position: center center
background-size: cover
background-repeat: no-repeat
transition: all .5s
if hexo-config('mask.header')
&:not(.not-top-img):before
position: absolute
width: 100%
height: 100%
background-color: var(--mark-bg)
content: ''
// index
&.full_page
height: $index_top_img_height
background-attachment: fixed
#site-info
position: absolute
top: $index_site_info_top
padding: 0 10px
width: 100%
#site-title,
#site-subtitle,
#scroll-down .scroll-down-effects
text-align: center
text-shadow: 2px 2px 4px rgba(0, 0, 0, .15)
line-height: 1.5
#site-title
margin: 0
color: var(--white)
font-size: 1.85em
+minWidth768()
font-size: 2.85em
#site-subtitle
color: var(--light-grey)
font-size: 1.15em
+minWidth768()
font-size: 1.72em
#site_social_icons
display: none
margin: 0 auto
text-align: center
+maxWidth768()
display: block
.social-icon
margin: 0 10px
color: var(--light-grey)
text-shadow: 2px 2px 4px rgba(0, 0, 0, .15)
font-size: 1.43em
#scroll-down
position: absolute
bottom: 10px
width: 100%
cursor: pointer
.scroll-down-effects
position: relative
width: 100%
color: var(--light-grey)
font-size: 20px
// page
&.not-home-page
height: 400px
+maxWidth768()
height: 280px
#page-site-info
position: absolute
top: 200px
padding: 0 10px
width: 100%
+maxWidth768()
top: 140px
// post
&.post-bg
height: 400px
+maxWidth768()
height: 360px
#post-info
position: absolute
width: 100%
if hexo-config('post_meta.post.position') == 'center'
top: calc(50% + 30px)
padding: 0 8%
text-align: center
transform: translateY(-50%)
+maxWidth768()
padding: 0 15px
else
bottom: 30px
& > *
margin: 0 auto
padding: 0 15px
max-width: 1200px
@media screen and (min-width: 768px) and (max-width: 1300px)
padding: 0 30px
+minWidth2000()
max-width: 70%
&.not-top-img
margin-bottom: 10px
height: 60px
background: 0
.title-seo
display: none
#nav
background: rgba(255, 255, 255, .8)
box-shadow: 0 5px 6px -5px rgba(133, 133, 133, .6)
a,
span.site-page,
.site-name
color: var(--font-color)
text-shadow: none
&.nav-fixed
#nav
position: fixed
top: -60px
z-index: 91
background: rgba(255, 255, 255, .7)
box-shadow: 0 5px 6px -5px alpha($grey, .6)
transition: transform .2s ease-in-out, opacity .2s ease-in-out
will-change: transform
backdrop-filter: blur(7px)
#blog-info
color: var(--font-color)
&:hover
color: $light-blue
.site-name
text-shadow: none
& > a:first-child
display: none
& > a:last-child
display: inline
a,
span.site-page,
#toggle-menu
color: var(--font-color)
text-shadow: none
&:hover
color: $light-blue
&.fixed
#nav
top: 0
transition: all .5s
&.nav-visible:not(.fixed)
#nav
transition: all .5s
transform: translate3d(0, 100%, 0)
& + .layout
& > .aside-content > .sticky_layout
top: 70px
transition: top .5s
&.fixed
#nav
position: fixed
& + .layout
& > .aside-content > .sticky_layout
top: 70px
transition: top .5s
#card-toc
.toc-content
max-height: calc(100vh - 170px)
#page
.page-title
margin: 0 0 10px
font-weight: bold
font-size: 2em
// for not top_img
#post
& > #post-info
margin-bottom: 30px
.post-title
padding-bottom: 4px
border-bottom: 1px solid var(--light-grey)
color: var(--text-highlight-color)
.post-edit-link
float: right
#post-meta,
#post-meta a
color: #78818a
#post-info
.post-title
@extend .limit-more-line
margin-bottom: 8px
color: var(--white)
font-weight: normal
font-size: 2.5em
line-height: 1.5
-webkit-line-clamp: 3
+maxWidth768()
font-size: 2.1em
.post-edit-link
padding-left: 10px
#post-meta
color: var(--light-grey)
font-size: 95%
+minWidth768()
> .meta-secondline
> span:first-child
display: none
+maxWidth768()
font-size: 90%
> .meta-firstline,
> .meta-secondline
display: inline
.post-meta
&-separator
margin: 0 5px
&-icon
margin-right: 4px
&-label
if hexo-config('post_meta.post.label')
margin-right: 4px
else
display: none
a
color: var(--light-grey)
transition: all .3s ease-out
&:hover
color: $text-hover
text-decoration: underline
if hexo-config('post_meta.post.date_format') == 'relative'
time
display: none
#nav
position: absolute
top: 0
z-index: 90
display: flex
align-items: center
padding: 0 36px
width: 100%
height: 60px
font-size: 1.3em
opacity: 0
transition: all .5s
+maxWidth768()
padding: 0 16px
&.show
opacity: 1
#blog-info
flex: 1
color: var(--light-grey)
@extend .limit-one-line
.site-icon
margin-right: 6px
height: 36px
vertical-align: middle
.nav-page-title
display: none
#toggle-menu
display: none
padding: 2px 0 0 6px
vertical-align: top
&:hover
color: var(--white)
a,
span.site-page
color: var(--light-grey)
&:hover
color: var(--white)
.site-name
text-shadow: 2px 2px 4px rgba($dark-black, .15)
font-weight: bold
.menus_items
display: inline
.menus_item
position: relative
display: inline-block
padding: 0 0 0 14px
&:hover
.menus_item_child
display: block
& > span > i:last-child
transform: rotate(180deg)
& > span > i:last-child
padding: 4px
transition: transform .3s
.menus_item_child
position: absolute
right: 0
display: none
margin-top: 8px
padding: 0
width: max-content
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
top: -8px
left: 0
width: 100%
height: 20px
content: ''
li
list-style: none
&:hover
background: var(--text-bg-hover)
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
a
display: inline-block
padding: 8px 16px
width: 100%
color: var(--font-color) !important
text-shadow: none !important
&.hide-menu
#toggle-menu
display: inline-block !important
.site-page
font-size: inherit
.menus_items
display: none
#search-button span:not(.site-page)
display: none
#search-button
display: inline
padding: 0 0 0 14px
.site-page
position: relative
padding-bottom: 6px
text-shadow: 1px 1px 2px rgba($dark-black, .3)
font-size: .78em
cursor: pointer
&:not(.child)
&:after
position: absolute
bottom: 0
left: 0
z-index: -1
width: 0
height: 3px
background-color: lighten($theme-color, 30%)
content: ''
transition: all .3s ease-in-out
addBorderRadius()
&:hover
&:after
width: 100%
.nav-page-title
position: relative
overflow: hidden
& > :first-child,
& > :last-child
display: inline-block
transition: all .3s ease-in-out
& > :last-child
position: absolute
top: 50%
left: 0
opacity: 0
transform: translateY(-50%) translateY(-10px)
&:hover
& > :last-child
opacity: 1
transform: translateY(-50%) translateY(0)
& > :first-child
opacity: 0
transform: translateY(10px)

View File

@@ -0,0 +1,95 @@
if hexo-config('preloader.enable') && hexo-config('preloader.source') == 1
.loading-bg
position: fixed
z-index: 1000
width: 50%
height: 100%
background-color: var(--preloader-bg)
#loading-box
.loading-left-bg
@extend .loading-bg
.loading-right-bg
@extend .loading-bg
right: 0
.spinner-box
position: fixed
z-index: 1001
display: flex
justify-content: center
align-items: center
width: 100%
height: 100vh
.configure-border-1
position: absolute
padding: 3px
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
.loading-left-bg
transition: all .5s
transform: translate(-100%, 0)
.loading-right-bg
transition: all .5s
transform: translate(100%, 0)
.spinner-box
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)

View File

@@ -0,0 +1,106 @@
#pagination
.pagination
margin-top: 20px
text-align: center
.page-number
&.current
background: $theme-paginator-color
color: var(--white)
.full-width
width: 100% !important
.pagination-related
height: 150px
+minWidth768()
flex: 1
.info-1
.info-item-2
-webkit-line-clamp: 1
.info-2
.info-item-1
-webkit-line-clamp: 2
&.pagination-post
overflow: hidden
margin-top: 40px
width: 100%
addBorderRadius()
display: flex
+maxWidth768()
flex-direction: column
.layout
.pagination
& > *
display: inline-block
margin: 0 6px
width: w = 2.5em
height: w
line-height: w
& > *:not(.space)
@extend .cardHover
&:hover
background: var(--btn-hover-color)
color: var(--btn-color)
#archive
.pagination
margin-top: 30px
& > *:not(.space)
box-shadow: none
.pagination-related
position: relative
display: inline-block
overflow: hidden
background: $dark-black
vertical-align: bottom
@extend .postImgHover
&.next-post
.info
text-align: right
.info
.info-1,
.info-2
@extend .verticalCenter
padding: 20px 40px
color: var(--white)
transition: transform .3s, opacity .3s
.info-1
.info-item-1
color: var(--light-grey)
text-transform: uppercase
font-size: 90%
.info-item-2
@extend .limit-more-line
color: var(--white)
font-weight: 500
.info-2
opacity: 0
transform: translate(0, 0)
.info-item-1
@extend .limit-more-line
&:not(.no-desc):hover
.info-1
opacity: 0
transform: translate(0, -100%)
.info-2
opacity: 1
transform: translate(0, -50%)

View File

@@ -0,0 +1,264 @@
beautify()
headStyle(fontsize)
padding-left: unit(fontsize + 8, 'px')
&:before
font-size: unit(fontsize - 2, 'px')
&:hover
padding-left: unit(fontsize + 12, 'px')
h1,
h2,
h3,
h4,
h5,
h6
transition: all .2s ease-out
&:before
position: absolute
top: calc(50% - 7px)
left: 0
color: $title-prefix-icon-color
content: $title-prefix-icon
line-height: 1
transition: all .2s ease-out
@extend .fontawesomeIcon
&:hover
&:before
color: $light-blue
h1
headStyle(20)
h2
headStyle(18)
h3
headStyle(16)
h4
headStyle(14)
h5
headStyle(12)
h6
headStyle(12)
ol,
ul
p
margin: 0 0 8px
li
&::marker
color: $light-blue
font-weight: 600
font-size: 1.05em
&:hover
&::marker
color: var(--pseudo-hover)
ul > li
list-style-type: circle
hr
@extend .custom-hr
.container
word-wrap: break-word
overflow-wrap: break-word
if hexo-config('text_align_justify')
text-align: justify
a
color: $theme-link-color
&:hover
text-decoration: underline
img
display: block
margin: 0 auto 20px
max-width: 100%
transition: filter 375ms ease-in .2s
addBorderRadius()
p
margin: 0 0 16px
iframe
margin: 0 0 20px
kbd
margin: 0 3px
padding: 3px 5px
border: 1px solid #b4b4b4
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
white-space: nowrap
font-weight: 600
font-size: .9em
font-family: Monaco, 'Ubuntu Mono', monospace
line-height: 1em
addBorderRadius(3)
if hexo-config('anchor.click_to_scroll')
h1,
h2,
h3,
h4,
h5,
h6
width: fit-content
a:not(.headerlink)
position: relative
z-index: 10
a.headerlink
position: absolute
top: 0
right: 0
bottom: 0
left: 0
width: 100%
height: 100%
ol,
ul
ol,
ul
padding-left: 20px
li
margin: 4px 0
p
margin: 0 0 8px
> :last-child
margin-bottom: 0 !important
hr
margin: 20px 0
if hexo-config('beautify.enable')
if hexo-config('beautify.field') == 'site'
beautify()
else if hexo-config('beautify.field') == 'post'
&.post-content
beautify()
#post
.tag_share
&:after
display: block
clear: both
content: ''
.post-meta
&__tag-list
display: inline-block
&__tags
display: inline-block
margin: 8px 8px 8px 0
padding: 0 12px
width: fit-content
border: 1px solid $light-blue
border-radius: 12px
color: $light-blue
font-size: .85em
transition: all .2s ease-in-out
&:hover
background: $light-blue
color: var(--white)
.post-share
display: inline-block
float: right
margin: 8px 0 0
width: fit-content
.social-share
font-size: .85em
.social-share-icon
margin: 0 4px
width: w = 1.85em
height: w
font-size: 1.2em
line-height: w
.post-copyright
position: relative
margin: 40px 0 10px
padding: 10px 16px
border: 1px solid var(--light-grey)
transition: box-shadow .3s ease-in-out
addBorderRadius()
&:before
@extend .fontawesomeIcon
position: absolute
top: 2px
right: 12px
color: $theme-color
content: '\f1f9'
font-size: 1.3em
&:hover
box-shadow: 0 0 8px 0 rgba(232, 237, 250, .6), 0 2px 4px 0 rgba(232, 237, 250, .5)
.post-copyright
&-meta
color: $light-blue
font-weight: bold
i
margin-right: 3px
&-info
padding-left: 6px
a
text-decoration: underline
word-break: break-word
&:hover
text-decoration: none
#post-outdate-notice
position: relative
margin: 0 0 20px
padding: .5em 1.2em
background-color: $noticeOutdate-bg
color: $noticeOutdate-color
addBorderRadius(3)
.num
padding: 0 4px
if hexo-config('noticeOutdate.style') == 'flat'
padding: .5em 1em .5em 2.6em
border-left: 5px solid $noticeOutdate-border
&:before
@extend .fontawesomeIcon
position: absolute
top: 50%
left: .9em
color: $noticeOutdate-border
content: '\f071'
transform: translateY(-50%)
.ads-wrap
margin: 40px 0

View File

@@ -0,0 +1,31 @@
.relatedPosts
margin-top: 40px
& > .headline
margin-bottom: 5px
font-weight: 700
font-size: 1.43em
& > .relatedPosts-list
& > a
margin: 3px
width: calc(33.333% - 6px)
height: 200px
addBorderRadius()
+maxWidth768()
margin: 2px
width: calc(50% - 4px)
height: 150px
+maxWidth600()
width: calc(100% - 4px)
.info
.info-1
.info-item-2
-webkit-line-clamp: 2
.info-2
.info-item-1
-webkit-line-clamp: 3

View File

@@ -0,0 +1,78 @@
.post-reward
position: relative
margin-top: 80px
width: 100%
text-align: center
pointer-events: none
& > *
pointer-events: auto
.reward-button
display: inline-block
padding: 4px 24px
background: var(--btn-bg)
color: var(--btn-color)
cursor: pointer
addBorderRadius()
i
margin-right: 5px
&:hover
.reward-button
background: var(--btn-hover-color)
& > .reward-main
display: block
.reward-main
position: absolute
bottom: 40px
left: 0
z-index: 100
display: none
padding: 0 0 15px
width: 100%
addBorderRadius()
.reward-all
display: inline-block
margin: 0
padding: 20px 10px
background: var(--reward-pop)
&:before
position: absolute
bottom: -10px
left: 0
width: 100%
height: 20px
content: ''
&:after
position: absolute
right: 0
bottom: 2px
left: 0
margin: 0 auto
width: 0
height: 0
border-top: 13px solid var(--reward-pop)
border-right: 13px solid transparent
border-left: 13px solid transparent
content: ''
.reward-item
display: inline-block
padding: 0 8px
list-style-type: none
vertical-align: top
img
width: 130px
height: 130px
.post-qr-code-desc
width: 130px
color: $reward-pop-up-color

View File

@@ -0,0 +1,72 @@
#rightside
position: fixed
right: -48px
bottom: $rightside-bottom
z-index: 100
opacity: 0
transition: all .5s
&.rightside-show
opacity: .8
transform: translate(-58px, 0)
#rightside-config-hide
height: 0
opacity: 0
transition: transform .4s
transform: translate(45px, 0)
&.show
height: auto
opacity: 1
transform: translate(0, 0)
&.status
height: auto
opacity: 1
& > div
& > button,
& > a
display: block
margin-bottom: 5px
width: w = 35px
height: w
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)
#mobile-toc-button
display: none
+maxWidth900()
display: block
+maxWidth900()
#hide-aside-btn
display: none
if hexo-config('rightside_scroll_percent')
#go-up
.scroll-percent
display: none
&.show-percent
.scroll-percent
display: block
& + i
display: none
&:hover
.scroll-percent
display: none
& + i
display: block

View File

@@ -0,0 +1,78 @@
#sidebar
#menu-mask
position: fixed
z-index: 102
display: none
width: 100%
height: 100%
background: alpha($dark-black, .8)
#sidebar-menus
position: fixed
top: 0
right: -($sidebar-width)
z-index: 103
overflow-x: hidden
overflow-y: scroll
padding-left: 5px
width: $sidebar-width
height: 100%
background: var(--sidebar-bg)
transition: all .5s
&.open
transform: translate3d(-100%, 0, 0)
& > .avatar-img
margin: 20px auto
.site-data
padding: 0 10px
hr
margin: 20px auto
.menus_items
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
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%
text-align: left
&.group
& > i:last-child
position: absolute
top: .6em
right: 10px
transition: transform .3s
&.hide
& > i:last-child
transform: rotate(90deg)
& + .menus_item_child
display: none
.menus_item_child
margin: 0
padding-left: 25px
list-style: none

View File

@@ -0,0 +1,187 @@
#vcomment
font-size: 1.1em
.vbtn
border: none
background: var(--btn-bg)
color: var(--btn-color)
&:hover
background: var(--btn-hover-color)
.vimg
transition: all .3s
&:hover
transform: rotate(360deg)
.vcards .vcard .vcontent.expand
&:before,
&:after
z-index: 22
#waline-wrap
--waline-font-size: 1.1em
--waline-theme-color: $button-bg
--waline-active-color: $button-hover-color
.wl-comment-actions > button:not(last-child)
padding-right: 4px
if hexo-config('valine.bg')
#vcomment
textarea
background: url(hexo-config('valine.bg')) 100% 100% no-repeat
&:focus
background-image: none
if hexo-config('waline.bg')
#waline-wrap
textarea
background: url(hexo-config('waline.bg')) 100% 100% no-repeat
&:focus
background-image: none
.twikoo
.tk-content
p
margin: 3px 0
.fireworks
position: fixed
top: 0
left: 0
z-index: $fireworks-zIndex
pointer-events: none
.medium-zoom-image--opened
z-index: 99999 !important
margin: 0 !important
.medium-zoom-overlay
z-index: 99999 !important
if hexo-config('mermaid.enable')
.mermaid-wrap
margin: 0 0 20px
text-align: center
& > svg
height: 100%
if hexo-config('mermaid.code_write')
pre > code.mermaid
display: none
if hexo-config('chartjs.enable')
.chartjs-container
display: flex
flex-direction: column
justify-content: center
align-items: center
margin: 0 0 20px
text-align: center
gap: 20px
+maxWidth600()
.chartjs-wrap
width: 100% !important
&.chartjs-abreast
flex-direction: row
+maxWidth600()
flex-direction: column
.chartjs-wrap
width: -webkit-fill-available
canvas
display: inline-block !important
.utterances,
.fb-comments iframe
width: 100% !important
#gitalk-container
.gt-meta
margin: 0 0 .8em
padding: 6px 0 16px
if hexo-config('math.use')
.katex-display
overflow: auto hidden
padding: 5px
.katex-show
display: block
.katex
display: none
&.katex-show
display: inline
if hexo-config('math.hide_scrollbar')
.katex-display,
mjx-container
scrollbar-width: none
&::-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
.container
.aplayer
margin: 0 0 20px
if hexo-config('beautify.enable')
ol,
ul
margin: 0
padding: 0
li
margin: 0
padding: 0 15px
&:before
content: none
.snackbar-container.snackbar-css
addBorderRadius(5)
opacity: .85 !important
.abc-music-sheet
margin: 0 0 20px
opacity: 0
transition: opacity .3s
&.abcjs-container
opacity: 1
+maxWidth768()
.fancybox__toolbar__column.is-middle
display: none

View File

@@ -0,0 +1,160 @@
if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
[data-theme='dark']
--global-bg: darken(#121212, 2)
--font-color: alpha(#FFFFFF, .7)
--hr-border: alpha(#FFFFFF, .4)
--hr-before-color: alpha(#FFFFFF, .7)
--search-bg: #121212
--search-input-color: alpha(#FFFFFF, .7)
--search-a-color: alpha(#FFFFFF, .7)
--preloader-bg: darken(#121212, 2)
--preloader-color: alpha(#FFFFFF, .7)
--tab-border-color: #2c2c2c
--tab-button-bg: #2c2c2c
--tab-button-color: alpha(#FFFFFF, .7)
--tab-button-hover-bg: lighten(#121212, 15)
--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)
--text-bg-hover: lighten(#121212, 15)
--light-grey: alpha(#FFFFFF, .7)
--dark-grey: alpha(#FFFFFF, .2)
--white: alpha(#FFFFFF, .9)
--text-highlight-color: alpha(#FFFFFF, .9)
--blockquote-color: alpha(#FFFFFF, .7)
--blockquote-bg: lighten(#121212, 10)
--reward-pop: lighten(#121212, 10)
--toc-link-color: alpha(#FFFFFF, .6)
--scrollbar-color: lighten(#121212, 25)
--timeline-bg: lighten(#121212, 5)
--zoom-bg: #121212
--mark-bg: alpha($dark-black, .6)
#web_bg:before
position: absolute
width: 100%
height: 100%
background-color: alpha($dark-black, .7)
content: ''
.container
code
background: #2c2c2c
pre > code
background: lighten(#121212, 2)
figure.highlight
box-shadow: none
.note
code
background: $code-background
.aplayer
filter: brightness(.8)
kbd
border-color: #696969
background-color: #525252
color: #e2f1ff
//
#page-header
&.nav-fixed > #nav,
&.not-top-img > #nav
background: alpha(#121212, .8)
box-shadow: 0 5px 6px -5px rgba(133, 133, 133, 0)
#post-comment
.comment-switch
if hexo-config('comments.text')
background: #2c2c2c !important
#switch-btn
filter: brightness(.8)
// note
if hexo-config('note.style') == 'modern' || hexo-config('note.style') == 'flat'
.note
filter: brightness(.8)
// hide-tags
.hide-button,
.btn-beautify,
.hl-label,
#post-outdate-notice,
.error-img,
.container iframe,
.gist,
.ads-wrap
filter: brightness(.8)
img
if hexo-config('lazyload.enable') && hexo-config('lazyload.blur') && !hexo-config('lazyload.placeholder')
filter: blur(0) brightness(.8)
else
filter: brightness(.8)
#aside-content .aside-list > .aside-list-item:not(:last-child)
border-bottom: 1px dashed alpha(#FFFFFF, .1)
// Gitalk
#gitalk-container
filter: brightness(.8)
svg
fill: alpha(#FFFFFF, .9) !important
// Disqusjs
#disqusjs
#dsqjs
&:hover,
&:focus,
.dsqjs-tab-active,
.dsqjs-no-comment
color: alpha(#FFFFFF, .7)
.dsqjs-order-label
background-color: lighten(#121212, 5)
.dsqjs-post-body
color: alpha(#FFFFFF, .7)
code,
pre
background: #2c2c2c
blockquote
color: alpha(#FFFFFF, .7)
#artitalk_main #lazy
background: #121212
#operare_artitalk .c2
background: #121212
#card-toc
+maxWidth900()
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

@@ -0,0 +1,185 @@
if hexo-config('readmode')
.read-mode
--font-color: #4c4948
--readmode-light-color: #fff
--white: #4c4948
--light-grey: #4c4948
--gray: #d6dbdf
--hr-border: #d6dbdf
--hr-before-color: darken(#d6dbdf, 10)
--highlight-bg: #f7f7f7
--exit-btn-bg: #C0C0C0
--exit-btn-color: #fff
--exit-btn-hover: darken(#C0C0C0, 20)
--pseudo-hover: none
[data-theme='dark']
.read-mode
--font-color: rgba(255, 255, 255, .7)
--readmode-light-color: #0d0d0d
--white: rgba(255, 255, 255, .9)
--light-grey: rgba(255, 255, 255, .7)
--gray: rgba(255, 255, 255, .7)
--hr-border: rgba(255, 255, 255, .5)
--hr-before-color: rgba(255, 255, 255, .7)
--highlight-bg: #171717
--exit-btn-bg: #1f1f1f
--exit-btn-color: rgba(255, 255, 255, .9)
--exit-btn-hover: lighten(#1f1f1f, 20)
.read-mode
background: var(--readmode-light-color)
.exit-readmode
position: fixed
top: 30px
right: 30px
z-index: 100
width: 40px
height: 40px
background: var(--exit-btn-bg)
color: var(--exit-btn-color)
font-size: 16px
transition: background .3s
addBorderRadius(8)
+maxWidth768()
top: initial
bottom: 30px
&:hover
background: var(--exit-btn-hover)
#aside-content
display: none
#page-header.post-bg
background: none !important
&:before
opacity: 0
& > #post-info
text-align: center
#post
margin: 0 auto
background: transparent
box-shadow: none
&:hover
box-shadow: none
& > canvas
display: none !important
.highlight-tools,
#footer,
#post > *:not(#post-info):not(.post-content),
#nav,
#post-outdate-notice,
#web_bg,
#rightside,
.not-top-img
display: none !important
.container
a
color: #99a9bf
pre,
.highlight:not(.js-file-line-container)
background: var(--highlight-bg) !important
*
color: var(--font-color) !important
figure.highlight
border-radius: 0 !important
box-shadow: none !important
& > :not(.highlight-tools)
display: block !important
.line:before
color: var(--font-color) !important
.hljs
background: var(--highlight-bg) !important
h1,
h2,
h3,
h4,
h5,
h6
padding: 0
&:before
content: ''
&:hover
padding: 0
ul,
li,
ol
&:hover:before
transform: none !important
ol,
li
&:before
background: transparent !important
color: var(--font-color) !important
ul
>li
&:before
border-color: var(--gray) !important
.tabs
border: 2px solid var(--tab-border-color)
> .nav-tabs
background: transparent
> .tab
border-top: none !important
> .tab-contents .tab-item-content.active
animation: none
code
color: var(--font-color)
blockquote
border-color: var(--gray)
background-color: var(--readmode-light-color)
kbd
border: 1px solid var(--gray)
background-color: transparent
box-shadow: none
color: var(--font-color)
.hide-toggle
border: 1px solid var(--gray) !important
.hide-button,
.btn-beautify,
.hl-label
border: 1px solid var(--gray) !important
background: var(--readmode-light-color) !important
color: var(--font-color) !important
.note
border: 2px solid var(--gray)
border-left-color: var(--gray) !important
filter: none
background-color: var(--readmode-light-color) !important
color: var(--font-color)
&:before,
.note-icon
color: var(--font-color)

View File

@@ -0,0 +1,66 @@
if hexo-config('error_404.enable')
.type-404
.error-content
@extend .cardHover
overflow: hidden
margin: 0 20px
height: 360px
+maxWidth768()
margin: 0
height: 500px
.error-img
display: inline-block
overflow: hidden
width: 50%
height: 100%
+maxWidth768()
width: 100%
height: 45%
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()
font-size: 8em
.error_subtitle
@extend .limit-more-line
margin-top: -3em
word-break: break-word
font-size: 1.6em
-webkit-line-clamp: 2
.nc
margin-top: 5%
padding: 0 20px
#footer
display: none
& + #rightside
display: none

View File

@@ -0,0 +1,115 @@
.article-sort
margin-left: 10px
padding-left: 20px
border-left: 2px solid lighten($light-blue, 20)
&-title
position: relative
margin-left: 10px
padding-bottom: 20px
padding-left: 20px
font-size: 1.72em
&:hover
&:before
border-color: var(--pseudo-hover)
&:before
position: absolute
top: calc(((100% - 36px) / 2))
left: -9px
z-index: 1
width: w = 10px
height: h = w
border: .5 * w solid $light-blue
border-radius: w
background: var(--card-bg)
content: ''
line-height: h
transition: all .2s ease-in-out
&:after
position: absolute
bottom: 0
left: 0
z-index: 0
width: 2px
height: 1.5em
background: lighten($light-blue, 20)
content: ''
&-item
position: relative
display: flex
align-items: center
margin: 0 0 20px 10px
transition: all .2s ease-in-out
&:hover
&:before
border-color: var(--pseudo-hover)
&:before
$w = 6px
position: absolute
left: calc(-20px - 17px)
width: w = $w
height: h = w
border: .5 * w solid $light-blue
border-radius: w
background: var(--card-bg)
content: ''
transition: all .2s ease-in-out
&.no-article-cover
height: 80px
.article-sort-item-info
padding: 0
&.year
font-size: 1.43em
margin-bottom: 10px
&:hover
&:before
border-color: $light-blue
&:before
border-color: var(--pseudo-hover)
&-time
color: var(--card-meta)
font-size: .85em
time
padding-left: 6px
cursor: default
&-title
@extend .limit-more-line
color: var(--font-color)
font-size: 1.05em
transition: all .3s
-webkit-line-clamp: 2
&:hover
color: $text-hover
transform: translateX(10px)
&-img
overflow: hidden
width: 100px
height: 70px
addBorderRadius()
+maxWidth768()
width: 70px
height: 70px
:first-child
@extend .imgHover
&-info
flex: 1
padding: 0 16px

View File

@@ -0,0 +1,37 @@
.category-lists
.category-title
font-size: 2.57em
+maxWidth768()
font-size: 2em
.category-list
margin-bottom: 0
a
color: var(--font-color)
&:hover
color: $text-hover
.category-list-count
margin-left: 8px
color: var(--card-meta)
&:before
content: '('
&:after
content: ')'
ul
padding: 0 0 0 20px
@extend .list-beauty
ul
padding-left: 4px
li
position: relative
margin: 6px 0
padding: .12em .4em .12em 1.4em

View File

@@ -0,0 +1,60 @@
#body-wrap
display: flex
flex-direction: column
min-height: 100vh
.layout
display: flex
flex: 1 auto
margin: 0 auto
padding: 40px 15px
max-width: 1200px
width: 100%
+maxWidth900()
flex-direction: column
+maxWidth768()
padding: 20px 5px
+minWidth2000()
max-width: 70%
& > div:first-child:not(.nc)
@extend .cardHover
align-self: flex-start
padding: 50px 40px
+maxWidth768()
padding: 36px 14px
& > div:first-child
width: 74%
transition: all .3s
+maxWidth900()
width: 100% !important
if hexo-config('aside.position') == 'left'
+minWidth900()
order: 2
// aside
&.hide-aside
max-width: 1000px
+minWidth2000()
max-width: 1300px
& > div
width: 100% !important
// for apple device
.apple
#page-header.full_page
background-attachment: scroll !important
.recent-post-item,
.avatar-img,
.flink-item-icon
transform: translateZ(0)

View File

@@ -0,0 +1,87 @@
.container
.flink
margin-bottom: 20px
.flink-list
overflow: auto
padding: 10px 10px 0
text-align: center
& > .flink-list-item
position: relative
float: left
overflow: hidden
margin: 15px 7px
width: calc(100% / 3 - 15px)
height: 90px
line-height: 17px
-webkit-transform: translateZ(0)
addBorderRadius(8)
+maxWidth1024()
width: calc(50% - 15px) !important
+maxWidth600()
width: calc(100% - 15px) !important
&:hover
.flink-item-icon
margin-left: -10px
width: 0
&:before
position: absolute
top: 0
right: 0
bottom: 0
left: 0
z-index: -1
background: var(--text-bg-hover)
content: ''
transition: transform .3s ease-out
transform: scale(0)
&:hover:before,
&:focus:before,
&:active:before
transform: scale(1)
a
color: var(--font-color)
text-decoration: none
.flink-item-icon
float: left
overflow: hidden
margin: 15px 10px
width: 60px
height: 60px
border-radius: 7px
transition: width .3s ease-out
img
width: 100%
height: 100%
transition: filter 375ms ease-in .2s, transform .3s
object-fit: cover
.img-alt
display: none
.flink-item-name
@extend .limit-one-line
padding: 16px 10px 0 0
height: 40px
font-weight: bold
font-size: 1.43em
.flink-item-desc
@extend .limit-one-line
padding: 16px 10px 16px 0
height: 50px
font-size: .93em
.flink-name
margin-bottom: 5px
font-weight: bold
font-size: 1.5em

View File

@@ -0,0 +1,175 @@
$indexLayout = hexo-config('index_layout') || 1
$indexEnable = hexo-config('cover.index_enable')
#recent-posts
.recent-post-item
@extend .cardHover
position: relative
overflow: hidden
margin-bottom: 20px
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
.post-bg
transform: scale(1.1)
&.ads-wrap
display: block !important
height: auto !important
.post_cover
overflow: hidden
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%
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
& >.recent-post-info
+maxWidth768()
padding: 20px 20px 30px
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)
font-size: 1.55em
line-height: 1.4
transition: all .2s ease-in-out
-webkit-line-clamp: 2
.sticky
margin-right: 10px
color: $sticky-color
transform: rotate(45deg)
+maxWidth768()
font-size: 1.43em
&:hover
color: $text-hover
& > .article-meta-wrap
margin: 6px 0
color: var(--card-meta)
font-size: .9em
& > .post-meta-date
cursor: default
i
margin: 0 4px 0 0
.fa-spinner
margin: 0
.article-meta-label
if hexo-config('post_meta.page.label')
padding-right: 4px
else
display: none
.article-meta-separator
margin: 0 6px
.article-meta-link
margin: 0 4px
if hexo-config('post_meta.page.date_format') == 'relative'
time
display: none
a
color: var(--card-meta)
&:hover
color: $text-hover
text-decoration: underline
& > .content
@extend .limit-more-line
-webkit-line-clamp: 2
word-break: break-word

View File

@@ -0,0 +1,78 @@
#rightMenu
display: none
position: fixed
width: 160px
height: fit-content
top: 10%
left: 10%
background-color: var(--icat-maskbgdeep)
backdrop-filter: blur(20px) saturate(1.5)
transform: translateZ(0)
border: var(--style-border)
border-radius: 8px
z-index: 99994
box-shadow: var(--icat-shadow-black)
transition: border 0.3s
user-select: none
&:hover
border: var(--style-border-hover-always)
.rightMenu-group
padding: 6px 6px
&:not(:nth-last-child(1))
border-bottom: 1px solid var(--icat-card-border)
&.rightMenu-small
display: flex
justify-content: space-between
&.rightMenu-line
.rightMenu-item
display: flex
height: 40px
padding: 0 4px
align-items: center
transition: .6s
.rightMenu-item
height: 30px
border-radius: 6px
transition: .3s
color: var(--font-color)
cursor: pointer
*
height: 40px
line-height: 40px
&:not(:last-child)
margin-bottom: 4px
&:hover
background-color: var(--icat-blue)
color: var(--icat-white)
i
display: inline-block
text-align: center
line-height: 30px
width: 30px
height: 30px
padding: 0 5px
#rightMenu .rightMenu-group .rightMenu-item .icat-refresh,
#rightMenu .rightMenu-group .rightMenu-item .icat-changing-over,
#rightMenu .rightMenu-group .rightMenu-item .icat-simple-complex
font-weight: 900
#rightMenu-mask
position: fixed
width: 100vw
height: 100vh
background: 0 0
top: 0
left: 0
display: none
z-index: 998

View File

@@ -0,0 +1,78 @@
#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
cursor: default
.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-footer
display: flex
align-items: center
&.flex-between
justify-content: space-between
&.flex-end
justify-content: flex-end
.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)
.shuoshuo-comment-btn
padding: 2px
color: #90a4ae
cursor: pointer
&:hover
color: $light-blue
.shuoshuo-comment
padding-top: 10px
&.no-comment
display: none

View File

@@ -0,0 +1,27 @@
.tag-cloud
&-list
a
display: inline-block
margin: 2px
padding: 2px 7px
line-height: 1.7
transition: all .3s
addBorderRadius(5)
&:hover
background: var(--btn-bg) !important
box-shadow: 2px 2px 6px rgba(0, 0, 0, .2)
color: var(--btn-color) !important
+maxWidth768()
zoom: .85
&-title
font-size: 2.57em
+maxWidth768()
font-size: 2em
.page-title
& + .tag-cloud-list
text-align: left

View File

@@ -0,0 +1,93 @@
#algolia-search
.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
margin: 0
padding: 0
@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
div
display: inline
.algolia-poweredBy
float: right
vertical-align: text-top
svg
height: 1.1em

View File

@@ -0,0 +1,56 @@
.search-dialog
position: fixed
top: 10%
left: 50%
z-index: 1001
display: none
margin-left: -300px
padding: 20px
width: 600px
background: var(--search-bg)
--search-height: 100vh
addBorderRadius(8)
+maxWidth768()
top: 0
left: 0
margin: 0
width: 100%
height: 100%
border-radius: 0
.search-nav
margin: 0 0 14px
color: $search-color
font-size: 1.4em
line-height: 1
.search-dialog-title
margin-right: 10px
.search-close-button
float: right
color: $grey
transition: color .2s ease-in-out
&:hover
color: $search-color
hr
margin: 15px auto
@extend .custom-hr
#search-mask
position: fixed
top: 0
right: 0
bottom: 0
left: 0
z-index: 1000
display: none
background: rgba($dark-black, .6)
if hexo-config('search.use') == 'algolia_search'
@require 'algolia'
else if hexo-config('search.use') == 'local_search'
@require 'local-search'

View File

@@ -0,0 +1,57 @@
#local-search
.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
overflow-y: overlay
margin: 0 -20px
padding: 0 22px
max-height: calc(80vh - 180px)
+maxWidth768()
max-height: calc(var(--search-height) - 190px) !important
.search-keyword
background: transparent
color: $search-keyword-highlight
font-weight: 600

View File

@@ -0,0 +1,56 @@
.container
.btn-center
margin: 0 0 20px
text-align: center
.btn-beautify
display: inline-block
margin: 0 4px 6px
padding: 0 15px
background-color: var(--btn-beautify-color, $btn-default-color)
color: $btn-color
line-height: 2
addBorderRadius()
for $type in $color-types
&.{$type}
--btn-beautify-color: lookup('$tagsP-' + $type + '-color')
&:hover
background-color: var(--btn-hover-color)
i + span
margin-left: 6px
&:not(.block) + .btn-beautify:not(.block)
margin: 0 4px 20px
&.block
display: block
margin: 0 0 20px
width: fit-content
width: -moz-fit-content
&.center
margin: 0 auto 20px
&.right
margin: 0 0 20px auto
&.larger
padding: 6px 15px
&:hover
text-decoration: none
&.outline
border: 1px solid transparent
border-color: var(--btn-beautify-color, $btn-default-color)
background-color: transparent
color: var(--btn-beautify-color, $btn-default-color)
&:hover
background-color: var(--btn-beautify-color, $btn-default-color)
&:hover
color: white !important

View File

@@ -0,0 +1,218 @@
.container
figure.gallery-group
position: relative
float: left
overflow: hidden
margin: 6px 4px
width: calc(50% - 8px)
height: 250px
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
transform: translate3d(0, 0, 0)
.gallery-group-name::after
transform: translate3d(0, 0, 0)
p
opacity: 1
transform: translate3d(0, 0, 0)
img
position: relative
margin: 0
max-width: none
width: calc(100% + 20px)
height: 250px
backface-visibility: hidden
opacity: .8
transition: all .3s, filter 375ms ease-in .2s
transform: translate3d(-10px, 0, 0)
object-fit: cover
figcaption
position: absolute
top: 0
left: 0
padding: 30px
width: 100%
height: 100%
color: $gallery-color
text-transform: uppercase
backface-visibility: hidden
& > a
position: absolute
top: 0
right: 0
bottom: 0
left: 0
z-index: 1000
opacity: 0
p
@extend .limit-more-line
margin: 0
padding: 8px 0 0
letter-spacing: 1px
font-size: 1.1em
line-height: 1.5
opacity: 0
transition: opacity .35s, transform .35s
transform: translate3d(100%, 0, 0)
-webkit-line-clamp: 4
.gallery-group-name
@extend .limit-more-line
position: relative
margin: 0
padding: 8px 0
font-weight: bold
font-size: 1.65em
line-height: 1.5
-webkit-line-clamp: 2
&:after
position: absolute
bottom: 0
left: 0
width: 100%
height: 2px
background: $gallery-color
content: ''
transition: transform .35s
transform: translate3d(-100%, 0, 0)
.gallery-group-main
overflow: auto
padding: 0 0 16px
.gallery-container
margin: 0 0 20px
text-align: center
opacity: 0
&.loaded
opacity: 1
img
display: initial
margin: 0
width: 100%
height: 100%
.gallery-data
display: none
button
margin-top: 25px
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: 8px
i
margin-left: 4px
transition: all .3s
.loading-container
display: inline-block
overflow: hidden
width: 154px
height: 154px
.loading-item
position: relative
width: 100%
height: 100%
backface-visibility: hidden
transform: translateZ(0) scale(1)
transform-origin: 0 0
div
position: absolute
width: 30.8px
height: 30.8px
border-radius: 50%
background: #e15b64
transform: translate(61.6px, 61.6px) scale(1)
animation: loading-ball 1.92s infinite cubic-bezier(0, .5, .5, 1)
&:nth-child(1)
background: #f47e60
transform: translate(113.96px, 61.6px) scale(1)
animation: loading-ball-r .48s infinite cubic-bezier(0, .5, .5, 1), loading-ball-c 1.92s infinite step-start
&:nth-child(2)
background: #e15b64
animation-delay: -.48s
&:nth-child(3)
background: #f47e60
animation-delay: -.96s
&:nth-child(4)
background: #f8b26a
animation-delay: -1.44s
&:nth-child(5)
background: #abbd81
animation-delay: -1.92s
@keyframes loading-ball
0%
transform: translate(9.24px, 61.6px) scale(0)
25%
transform: translate(9.24px, 61.6px) scale(0)
50%
transform: translate(9.24px, 61.6px) scale(1)
75%
transform: translate(61.6px, 61.6px) scale(1)
100%
transform: translate(113.96px, 61.6px) scale(1)
@keyframes loading-ball-r
0%
transform: translate(113.96px, 61.6px) scale(1)
100%
transform: translate(113.96px, 61.6px) scale(0)
@keyframes loading-ball-c
0%
background: #e15b64
25%
background: #abbd81
50%
background: #f8b26a
75%
background: #f47e60
100%
background: #e15b64

View File

@@ -0,0 +1,30 @@
// pullquote
blockquote
&.pullquote
position: relative
max-width: 45%
font-size: 110%
&.left
float: left
margin: 1em .5em 0 0
&.right
float: right
margin: 1em 0 0 .5em
// hexo tag video
.video-container
position: relative
overflow: hidden
margin-bottom: 16px
padding-top: 56.25%
height: 0
iframe
position: absolute
top: 0
left: 0
margin-top: 0
width: 100%
height: 100%

View File

@@ -0,0 +1,48 @@
// tag-hide
.hide-inline,
.hide-block
& > .hide-button
display: inline-block
padding: 5px 18px
background: $tag-hide-bg
color: var(--white)
addBorderRadius()
&:hover
background-color: var(--btn-hover-color)
&.open
display: none
& + div
display: block
& + span
display: inline
& > .hide-content
display: none
.hide-inline
& > .hide-button
margin: 0 6px
& > .hide-content
margin: 0 6px
.hide-block
margin: 0 0 16px
.toggle
margin-bottom: 20px
border: 1px solid $tag-hide-toggle-bg
addBorderRadius(5, true)
& > .toggle-button
padding: 6px 15px
background: $tag-hide-toggle-bg
color: #1F2D3D
cursor: pointer
& > .toggle-content
margin: 30px 24px

View File

@@ -0,0 +1,6 @@
.container
.inline-img
display: inline
margin: 0 3px
height: 1.1em
vertical-align: text-bottom

View File

@@ -0,0 +1,11 @@
.hl-label
padding: 2px 4px
color: $btn-color
addBorderRadius(3)
&.default
background-color: $btn-default-color
for $type in $color-types
&.{$type}
background-color: lookup('$tagsP-' + $type + '-color')

View File

@@ -0,0 +1,78 @@
:root
--tag-link-bg-color white
--tag-link-text-color black
--tag-link-border-color white
--tag-link-hover-bg-color rgb(141, 216, 233)
--tag-link-hover-border-color black
--tag-link-tips-border-color black
--tag-link-sitename-color rgb(144, 144, 144)
--tag-link-hover-sitename-color black
[data-theme=dark]
--tag-link-bg-color #2d2d2d
--tag-link-text-color white
--tag-link-border-color black
--tag-link-hover-bg-color #339297
--tag-link-hover-border-color white
--tag-link-tips-border-color white
--tag-link-sitename-color rgb(144, 144, 144)
--tag-link-hover-sitename-color white
#article-container
.tag-Link
background var(--tag-link-bg-color)
border-radius 12px !important
display flex
border 1px solid var(--tag-link-border-color)
flex-direction column
padding 0.5rem 1rem
margin-top 1rem
text-decoration none !important
color var(--tag-link-text-color)
margin-bottom 10px
transition background-color 0.3s, border-color 0.3s, box-shadow 0.3s
&:hover
border-color var(--tag-link-hover-border-color)
background-color var(--tag-link-hover-bg-color)
box-shadow 0 0 5px rgba(0, 0, 0, 0.2)
.tag-link-tips
color var(--tag-link-text-color)
border-bottom 1px solid var(--tag-link-tips-border-color)
padding-bottom 4px
font-size 0.6rem
font-weight normal
.tag-link-bottom
display flex
margin-top 0.5rem
align-items center
justify-content space-around
.tag-link-left
width 60px
min-width 60px
height 60px
background-size cover
border-radius 25%
.tag-link-right
margin-left 1rem
.tag-link-title
font-size 1rem
line-height 1.2
.tag-link-sitename
font-size 0.7rem
color var(--tag-link-sitename-color)
font-weight normal
margin-top 4px
transition color 0.3s
&:hover .tag-link-sitename
color var(--tag-link-hover-sitename-color)
i
margin-left auto

View File

@@ -0,0 +1,124 @@
.note
$note-icons = hexo-config('note.icons')
position: relative
margin: 0 0 20px
padding: 15px
if hexo-config('note.border_radius') is a 'unit'
border-radius: unit(hexo-config('note.border_radius'), px)
&.icon-padding
padding-left: 3em
& > .note-icon
position: absolute
top: calc(50% - .5em)
left: .8em
font-size: larger
for $type in $color-types
&.{$type}
&:not(.disabled)
border-left-color: lookup('$tagsP-' + $type + '-color') !important
&.modern
border-left-color: transparent !important
color: lookup('$tagsP-' + $type + '-color')
&:not(.simple)
background: lighten(lookup('$tagsP-' + $type + '-color'), 85%) !important
& > .note-icon
color: lookup('$tagsP-' + $type + '-color')
&.simple
border: 1px solid #EEEEEE
border-left-width: 5px
&.modern
border: 1px solid transparent !important
background-color: #f5f5f5
color: $font-black
&.flat
border: initial
border-left: 5px solid #EEEEEE
background-color: lighten(#EEEEEE, 65%)
color: $font-black
h2,
h3,
h4,
h5,
h6
if $note-icons
margin-top: 3px
else
margin-top: 0
margin-bottom: 0
padding-top: 0 !important
border-bottom: initial
p,
ul,
ol,
table,
pre,
blockquote,
img
&:first-child
margin-top: 0 !important
&:last-child
margin-bottom: 0 !important
.img-alt
margin: 5px 0 10px
if $note-icons
&:not(.no-icon)
padding-left: 3em
&::before
position: absolute
top: calc(50% - .95em)
left: .8em
font-size: larger
@extend .fontawesomeIcon
for $type in $note-types
&.{$type}
&.flat
background: lookup('$note-' + $type + '-bg')
&.modern
border-color: lookup('$note-modern-' + $type + '-border')
background: lookup('$note-modern-' + $type + '-bg')
color: lookup('$note-modern-' + $type + '-text')
a
&:not(.btn)
color: lookup('$note-modern-' + $type + '-text')
&:hover
color: lookup('$note-modern-' + $type + '-hover')
&:not(.modern)
border-left-color: lookup('$note-' + $type + '-border')
h2,
h3,
h4,
h5,
h6
color: lookup('$note-' + $type + '-text')
if $note-icons
&:not(.no-icon)
&::before
content: lookup('$note-' + $type + '-icon')
&:not(.modern)
&::before
color: lookup('$note-' + $type + '-text')

View File

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

View File

@@ -0,0 +1,77 @@
.container
.tabs
position: relative
margin: 0 0 20px
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
flex-wrap: wrap
margin: 0
padding: 0
background: var(--tab-button-bg)
> .tab
flex-grow: 1
padding: 8px 18px
border-top: 2px solid var(--tab-border-color)
background: var(--tab-button-bg)
color: var(--tab-button-color)
line-height: 2
transition: all .4s
i
width: 1.5em
&.active
border-top: 2px solid $tab-active-border-color
background: var(--tab-button-active-bg)
cursor: default
&:not(.active)
&:hover
border-top: 2px solid var(--tab-button-hover-bg)
background: var(--tab-button-hover-bg)
&.no-default
& ~ .tab-to-top
display: none
> .tab-contents
.tab-item-content
position: relative
display: none
padding: 36px 24px 10px
+maxWidth768()
padding: 24px 14px
&.active
display: block
animation: tabshow .5s
> :last-child
margin-bottom: 0
> .tab-to-top
padding: 0 16px 10px 0
width: 100%
text-align: right
button
color: $tab-to-top-color
&:hover
color: $tab-to-top-hover-color
@keyframes tabshow
0%
transform: translateY(15px)
100%
transform: translateY(0)

View File

@@ -0,0 +1,68 @@
.container
.timeline
margin: 0 10px 20px
padding: 14px 0 5px 20px
border-left: 2px solid var(--timeline-color, $theme-color)
for $type in $color-types
&.{$type}
--timeline-color: lookup('$tagsP-' + $type + '-color')
--timeline-bg: s('rgba(%s,%s,%s, 0.2)', red(lookup('$tagsP-' + $type + '-color')), green(lookup('$tagsP-' + $type + '-color')), blue(lookup('$tagsP-' + $type + '-color')))
.timeline-item
margin: 0 0 15px
&:hover
.item-circle
&:before
border-color: var(--timeline-color, $theme-color)
&.headline
.timeline-item-title
.item-circle
> p
font-weight: 600
font-size: 1.2em
&:before
left: -28px
border: 4px solid var(--timeline-color, $theme-color)
&:hover
.item-circle
&:before
border-color: var(--pseudo-hover)
.timeline-item-title
position: relative
.item-circle
&:before
position: absolute
top: 50%
left: -27px
width: 6px
height: 6px
border: 3px solid var(--pseudo-hover)
border-radius: 50%
background: var(--card-bg)
content: ''
transition: all .3s
transform: translate(0, -50%)
> p
margin: 0 0 8px
font-weight: 500
.timeline-item-content
position: relative
padding: 12px 15px
border-radius: 8px
background: var(--timeline-bg, lighten($theme-color, 85%))
font-size: .93em
& > :last-child
margin-bottom: 0
& + .timeline
margin-top: -20px

View File

@@ -0,0 +1,180 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
html {
line-height: 1.15;
-webkit-text-size-adjust: 100%
}
body {
margin: 0
}
main {
display: block
}
h1 {
font-size: 2em;
margin: .67em 0
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible
}
pre {
font-family: monospace, monospace;
font-size: 1em
}
a {
background-color: transparent
}
abbr[title] {
border-bottom: none;
text-decoration: underline;
text-decoration: underline dotted
}
b,
strong {
font-weight: bolder
}
code,
kbd,
samp {
font-family: monospace, monospace;
font-size: 1em
}
small {
font-size: 80%
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline
}
sub {
bottom: -.25em
}
sup {
top: -.5em
}
img {
border-style: none
}
button,
input,
optgroup,
select,
textarea {
font-family: inherit;
font-size: 100%;
line-height: 1.15;
margin: 0
}
button,
input {
overflow: visible
}
button,
select {
text-transform: none
}
[type=button],
[type=reset],
[type=submit],
button {
-webkit-appearance: button
}
[type=button]::-moz-focus-inner,
[type=reset]::-moz-focus-inner,
[type=submit]::-moz-focus-inner,
button::-moz-focus-inner {
border-style: none;
padding: 0
}
[type=button]:-moz-focusring,
[type=reset]:-moz-focusring,
[type=submit]:-moz-focusring,
button:-moz-focusring {
outline: 1px dotted ButtonText
}
fieldset {
padding: .35em .75em .625em
}
legend {
box-sizing: border-box;
color: inherit;
display: table;
max-width: 100%;
padding: 0;
white-space: normal
}
progress {
vertical-align: baseline
}
textarea {
overflow: auto
}
[type=checkbox],
[type=radio] {
box-sizing: border-box;
padding: 0
}
[type=number]::-webkit-inner-spin-button,
[type=number]::-webkit-outer-spin-button {
height: auto
}
[type=search] {
-webkit-appearance: textfield;
outline-offset: -2px
}
[type=search]::-webkit-search-decoration {
-webkit-appearance: none
}
::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit
}
details {
display: block
}
summary {
display: list-item
}
template {
display: none
}
[hidden] {
display: none
}

View File

@@ -0,0 +1,222 @@
/* 浅色主题变量覆盖 -------------------------------- */
:root {
--anzhiyu-main: #a0d2eb; /* 主强调色:柔和天空蓝 */
--anzhiyu-main-op: rgba(160, 210, 235, 0.6);
--anzhiyu-main-op-deep: rgba(160, 210, 235, 0.4);
--anzhiyu-main-op-light: rgba(160, 210, 235, 0.2);
--efu-card-bg: #fdfdfd; /* 卡片背景:几乎白 */
--efu-fontcolor: #444; /* 主文本:深灰 */
--efu-secondtext: #999; /* 次级文本:浅灰 */
}
.card-widget {
padding: 10px!important;
max-height: calc(100vh - 100px);
}
.card-times a, .card-times div {
color: var(--efu-fontcolor);
}
#card-widget-calendar .item-content {
display: flex;
}
#calendar-area-left {
width: 45%;
}
#calendar-area-right {
width: 55%;
}
#calendar-area-left, #calendar-area-right {
height: 100%;
padding: 8px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
}
#calendar-main {
width: 100%;
}
#calendar-week {
height: 1.2rem;
font-size: 14px;
letter-spacing: 1px;
font-weight: 700;
align-items: center;
display: flex;
}
#calendar-date {
height: 3rem;
line-height: 1.3;
font-size: 64px;
letter-spacing: 3px;
color: var(--anzhiyu-main);
font-weight: 700;
align-items: center;
display: flex;
position: relative;
top: calc(50% - 2.1rem);
}
#calendar-lunar, #calendar-solar {
height: 1rem;
font-size: 12px;
align-items: center;
display: flex;
position: absolute;
}
#calendar-solar {
bottom: 2.1rem;
}
#calendar-lunar {
bottom: 1rem;
color: var(--efu-secondtext);
}
#calendar-main a {
height: 1rem;
width: 1rem;
border-radius: 50%;
font-size: 12px;
line-height: 12px;
display: flex;
justify-content: center;
align-items: center;
}
#calendar-main a.now {
background: var(--anzhiyu-main);
color: var(--efu-card-bg);
}
#calendar-main .calendar-rh a {
color: var(--efu-secondtext);
}
.calendar-r0, .calendar-r1, .calendar-r2, .calendar-r3, .calendar-r4, .calendar-r5, .calendar-rh {
height: 1.2rem;
display: flex;
}
.calendar-d0, .calendar-d1, .calendar-d2, .calendar-d3, .calendar-d4, .calendar-d5, .calendar-d6 {
width: calc(100% / 7);
display: flex;
justify-content: center;
align-items: center;
}
#card-widget-schedule .item-content {
display: flex;
}
#schedule-area-left, #schedule-area-right {
height: 100px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#schedule-area-left {
width: 30%;
}
#schedule-area-right {
width: 70%;
padding: 0 5px;
}
.schedule-r0, .schedule-r1, .schedule-r2 {
height: 2rem;
width: 100%;
align-items: center;
display: flex;
}
.schedule-d0 {
width: 30px;
margin-right: 5px;
text-align: center;
font-size: 12px;
}
.schedule-d1 {
width: calc(100% - 35px);
height: 1.5rem;
align-items: center;
display: flex;
}
progress::-webkit-progress-bar {
background: linear-gradient(to right, var(--anzhiyu-main-op-deep), var(--anzhiyu-main-op), var(--anzhiyu-main-op-light));
border-radius: 5px;
overflow: hidden;
}
progress::-webkit-progress-value {
background: var(--anzhiyu-main);
border-radius: 5px;
}
.aside-span1, .aside-span2 {
height: 1rem;
font-size: 12px;
z-index: 1;
display: flex;
align-items: center;
position: absolute;
}
.aside-span1 {
margin-left: 5px;
}
.aside-span2 {
right: 20px;
color: var(--efu-secondtext);
}
.aside-span2 a {
margin: 0 3px;
}
#pBar_month, #pBar_week, #pBar_year {
width: 100%;
border-radius: 5px;
height: 100%;
}
#schedule-date, #schedule-days, #schedule-title {
display: flex;
align-items: center;
}
#schedule-title {
height: 25px;
line-height: 1;
font-size: 14px;
font-weight: 700;
}
#schedule-days {
height: 40px;
line-height: 1;
font-size: 30px;
font-weight: 900;
color: var(--anzhiyu-main);
}
#schedule-date {
height: 20px;
line-height: 1;
font-size: 12px;
color: var(--efu-secondtext);
}

View File

@@ -0,0 +1,5 @@
@font-face {
font-family: 'gkai';
font-display: swap;
src: url('gkai.woff2') format("woff2");
}

Binary file not shown.

View File

@@ -0,0 +1,15 @@
if hexo-config('css_prefix')
@import 'nib'
@import '_third-party/normalize.min.css'
// project
@import 'var'
@import '_global/*'
@import '_highlight/highlight'
@import '_page/*'
@import '_layout/*'
@import '_tags/*'
@import '_mode/*'
// search
@import '_search/index'

View File

@@ -0,0 +1,83 @@
/* rightMenu */
[data-theme='light'] #rightMenu{
display: none;
position: fixed;
width: 160px;
height: fit-content;
top: 10%;
left: 10%;
background-color: var(--card-bg);
border: 1px solid rgb(210,210,210);;
border-radius: 8px;
z-index: 100;
box-shadow: 3px 3px 5px #88888894;
background-color: var(--june-white-acrylic1);
backdrop-filter: blur(30px);
}
[data-theme='dark'] #rightMenu{
display: none;
position: fixed;
width: 160px;
height: fit-content;
top: 10%;
left: 10%;
background-color: var(--card-bg);
border: 1px solid rgb(210,210,210);;
border-radius: 8px;
z-index: 100;
box-shadow: 3px 3px 5px #88888894;
background-color: var(--june-black-acrylic1);
backdrop-filter: blur(30px);
}
#rightMenu .rightMenu-group{
padding: 7px 6px;
}
#rightMenu .rightMenu-group:not(:nth-last-child(1)){
border-bottom: 1px solid rgb(180,180,180);
}
#rightMenu .rightMenu-group.rightMenu-small{
display: flex;
justify-content: space-between;
}
#rightMenu .rightMenu-group .rightMenu-item{
height: 30px;
line-height: 30px;
border-radius: 8px;
transition: 0.3s;
color: var(--font-color);
}
#rightMenu .rightMenu-group.rightMenu-line .rightMenu-item{
display: flex;
height: 40px;
line-height: 40px;
padding: 0 4px;
}
#rightMenu .rightMenu-group .rightMenu-item:hover{
background-color: var(--text-bg-hover);
box-shadow: 0px 0px 5px var(--june-border);
}
#rightMenu .rightMenu-group .rightMenu-item i{
display: inline-block;
text-align: center;
line-height: 30px;
width: 30px;
height: 30px;
padding: 0 5px;
}
#rightMenu .rightMenu-group .rightMenu-item span{
line-height: 30px;
}
#rightMenu:hover{
border: 1px solid var(--june-theme);
}
#rightMenu .rightMenu-group.rightMenu-line .rightMenu-item *{
height: 40px;
line-height: 40px;
}
.rightMenu-group.hide{
display: none;
}
.rightMenu-item:hover{
color:white!important;
background-color:var(--june-theme)!important;
}

View File

@@ -0,0 +1,292 @@
/* 卡片初始化 */
#talk .talk_item {
width: calc(33.333% - 6px);
background: var(--liushen-card-bg);
border: var(--liushen-card-border);
box-shadow: var(--card-box-shadow);
transition: box-shadow .3s ease-in-out;
border-radius: 12px;
display: flex;
flex-direction: column;
padding: 20px;
margin-bottom: 9px;
margin-right: 9px;
}
#talk .talk_item:hover {
box-shadow: var(--card-hover-box-shadow);
}
@media (max-width: 900px) {
#talk .talk_item {
width: calc(50% - 5px);
}
}
@media (max-width: 450px) {
#talk .talk_item {
width: calc(100%);
}
}
#talk{
position: relative;
width: 100%;
box-sizing: border-box;
}
#talk .talk_meta .avatar {
margin: 0 !important;
width: 60px;
height: 60px;
border-radius: 12px;
}
#talk .talk_bottom,
#talk .talk_meta {
display: flex;
align-items: center;
}
#talk .talk_meta {
display: flex;
align-items: center;
width: 100%;
padding-bottom: 10px;
border-bottom: 1px dashed grey; /* 添加灰色虚线边框 */
}
#talk .talk_bottom {
margin-top: 15px;
padding-top: 10px;
border-top: 1px dashed grey; /* 添加灰色虚线边框 */
justify-content: space-between;
}
#talk .talk_meta .info {
display: flex;
flex-direction: column;
margin-left: 10px;
}
#talk .talk_meta .info .talk_nick {
color: #6dbdc3;
font-size: 1.2rem;
}
#talk .talk_meta .info svg.is-badge.icon {
width: 15px;
padding-top: 3px;
}
#talk .talk_meta .info span.talk_date {
opacity: .6;
}
#talk .talk_item .talk_content {
margin-top: 10px;
}
#talk .talk_item .talk_content .zone_imgbox {
display: flex;
flex-wrap: wrap;
--w: calc(25% - 8px);
gap: 10px;
margin-top: 10px;
}
#talk .talk_item .talk_content .zone_imgbox a {
display: block;
border-radius: 12px;
width: var(--w);
aspect-ratio: 1/1;
position: relative;
}
#talk .talk_item .talk_content .zone_imgbox a:first-child {
width: 100%;
aspect-ratio: 1.8;
}
#talk .talk_item .talk_content .zone_imgbox img {
border-radius: 10px;
width: 100%;
height: 100%;
margin: 0 !important;
object-fit: cover;
}
/* 底部 */
#talk .talk_item .talk_bottom {
opacity: .9;
}
#talk .talk_item .talk_bottom .icon {
float: right;
transition: all .3s;
}
#talk .talk_item .talk_bottom .icon:hover {
color: #49b1f5;
}
#talk .talk_item .talk_bottom span.talk_tag,
#talk .talk_item .talk_bottom span.location_tag {
font-size: 14px;
background-color: var(--liushen-card-secondbg);
border-radius: 12px;
padding: 3px 15px 3px 10px;
transition: box-shadow 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
#talk .talk_item .talk_bottom span.location_tag {
margin-left: 5px;
}
#talk .talk_item .talk_bottom span.talk_tag:hover,
#talk .talk_item .talk_bottom span.location_tag:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
#talk .talk_item .talk_content>a {
margin: 0 3px;
color: #ff7d73 !important;
}
#talk .talk_item .talk_content>a:hover{
text-decoration: none !important;
color: #ff5143 !important
}
@media screen and (max-width: 900px) {
#talk .talk_item .talk_content .zone_imgbox {
--w: calc(33% - 5px);
}
#talk .talk_item #post-comment{
margin: 0 3px
}
}
@media screen and (max-width: 768px) {
.zone_imgbox {
gap: 6px;
}
.zone_imgbox {
--w: calc(50% - 3px);
}
span.talk_date {
font-size: 14px;
}
}
#talk .talk_item .talk_content .douban-card {
margin-top: 10px !important;
text-decoration: none;
align-items: center;
border-radius: 12px;
color: #faebd7;
display: flex;
justify-content: center;
margin: 10px;
max-width: 400px;
overflow: hidden;
padding: 15px;
position: relative;
}
.douban-card .douban-card-bgimg {
background-position: 50%;
background-repeat: no-repeat;
background-size: 100%;
filter: blur(15px) brightness(.6);
height: 115%;
position: absolute;
width: 115%;
}
.douban-card .douban-card-left {
align-items: center;
display: flex;
flex-direction: column;
position: relative;
}
.douban-card .douban-card-left .douban-card-img {
transition: all .5s ease;
height: 130px;
position: relative;
width: 80px;
background-position: 50%;
background-repeat: no-repeat;
background-size: 100%;
}
.douban-card .douban-card-left:hover .douban-card-img {
filter: blur(5px) brightness(.6);
transform: perspective(800px) rotateX(180deg);
}
.douban-card .douban-card-right {
color: #faebd7;
display: flex;
flex-direction: column;
font-size: 14px;
line-height: 1.5;
margin-left: 12px;
position: relative;
}
.douban-card .douban-card-right .douban-card-item {
margin-top: 4px;
max-width: 95%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 外链卡片 */
#talk .talk_item .talk_content .shuoshuo-external-link {
/* 无下划线 */
width: 100%;
height: 80px;
margin-top: 10px;
border-radius: 12px;
background-color: var(--liushen-card-secondbg);
color: var(--liushen-card-text);
border: var(--liushen-card-border);
transition: background-color .3s ease-in-out;
}
.shuoshuo-external-link:hover {
background-color: var(--liushen-button-hover-bg);
}
.shuoshuo-external-link .external-link {
display: flex;
color: var(--liushen-text) !important;
width: 100%;
height: 100%;
}
.shuoshuo-external-link .external-link:hover {
color: white !important;
}
.shuoshuo-external-link .external-link:hover {
text-decoration: none !important;
}
.shuoshuo-external-link .external-link-left {
width: 60px;
height: 60px;
margin: 10px;
border-radius: 12px;
background-size: cover;
background-position: center;
}
.shuoshuo-external-link .external-link-right {
display: flex;
flex-direction: column;
justify-content: center;
width: calc(100% - 80px);
padding: 10px;
}
.shuoshuo-external-link .external-link-right .external-link-title {
font-size: 1.0rem;
font-weight: 800;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.shuoshuo-external-link .external-link-right i {
margin-left: 5px;
}
.limit {
width: 100%;
text-align: center;
margin-top: 30px;
}

View File

@@ -0,0 +1,295 @@
/* #card-newest-comments img {border-radius: 10px; /* 设置最新评论圆角半径为10px可以根据需要调整} */
/* 说说轮播 */
#bber-talk {
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/* 说说轮播 */
[data-theme=dark] #bber-talk {
background: linear-gradient(-45deg, rgba(24, 40, 72, .7),
rgba(35, 37, 58, .8),
rgba(35, 37, 58, .8),
rgba(24, 40, 72, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/* 侧边栏个人信息卡片动态渐变色 */
#aside-content>.card-widget.card-info {
position: relative;
z-index: 1; /* 确保原内容在上层显示 */
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
#aside-content > .card-widget.card-info::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(to bottom,
rgba(255, 255, 255, 0.0),
rgba(255, 255, 255, 0.3),
rgba(255, 255, 255, 0.6),
rgba(255, 255, 255, 0.7)),
url('/config/img/dog.jpg'); /* 鼠标悬停时显示的背景图片 */
background-size: cover;
background-repeat: no-repeat;
opacity: 0.5;
transition: opacity 0.8s; /* 过渡效果持续时间 */
z-index: -1;
}
[data-theme=dark] #aside-content > .card-widget.card-info::before {
background: linear-gradient(to bottom,
rgba(24, 40, 72, .1),
rgba(35, 37, 58, .3),
rgba(35, 37, 58, .6),
rgba(24, 40, 72, .7)),
url('/config/img/dog.jpg'); /* 鼠标悬停时显示的背景图片 */
background-size: cover;
background-repeat: no-repeat;
}
#aside-content > .card-widget.card-info:hover::before {
opacity: 1;
}
/* 卡片动态效果,好好看哈哈 */
#aside-content div.card-widget.card-info .avatar-img {
transition: opacity 0.3s ease; /* 添加渐变效果 */
}
#aside-content div.card-widget.card-info .avatar-img:hover {
opacity: 0; /* 鼠标移上去时完全透明 */
}
#card-info-btn:hover, #card-info-btn:hover .icon, #card-info-btn:hover span {
transform: scale(1.1); /* 鼠标悬停时放大到110% */
}
[data-theme=dark] #aside-content>.card-widget.card-info {
background: linear-gradient(-45deg, rgba(24, 40, 72, .6),
rgba(35, 37, 58, .5),
rgba(35, 37, 58, .5),
rgba(24, 40, 72, .6));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/* 侧边栏公告栏卡片渐变色 */
#aside-content>.card-widget.card-announcement {
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
[data-theme=dark] #aside-content>.card-widget.card-announcement {
background: linear-gradient(-45deg, rgba(24, 40, 72, .7),
rgba(35, 37, 58, .8),
rgba(35, 37, 58, .8),
rgba(24, 40, 72, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/* 侧边栏目录最新文章卡片渐变色 */
#aside-content>.sticky_layout>.card-widget {
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
[data-theme=dark] #aside-content>.sticky_layout>.card-widget {
background: linear-gradient(-45deg, rgba(24, 40, 72, .7),
rgba(35, 37, 58, .8),
rgba(35, 37, 58, .8),
rgba(24, 40, 72, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/* 侧边栏欢迎卡片渐变色 */
#aside-content>.card-widget.welcomeBoxClass {
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
[data-theme=dark] #aside-content>.card-widget.welcomeBoxClass {
background: linear-gradient(-45deg, rgba(24, 40, 72, .7),
rgba(35, 37, 58, .8),
rgba(35, 37, 58, .8),
rgba(24, 40, 72, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/* 公告卡片渐变色 */
#recent-posts>#noticeList {
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
[data-theme=dark] #recent-posts>#noticeList {
background: linear-gradient(-45deg, rgba(24, 40, 72, .7),
rgba(35, 37, 58, .8),
rgba(35, 37, 58, .8),
rgba(24, 40, 72, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/* 个人信息Follow me按钮 */
#aside-content>.card-widget.card-info>#card-info-btn {
background-color: #3eb8be;
border-radius: 10px;
}
/*文章页面*/
.layout>#post {
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
[data-theme=dark] .layout>#post {
background: linear-gradient(-45deg, rgba(24, 40, 72, .7),
rgba(35, 37, 58, .8),
rgba(35, 37, 58, .8),
rgba(24, 40, 72, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/*主页文章预览页面*/
#recent-posts>.recent-post-item {
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
[data-theme=dark] #recent-posts>.recent-post-item {
background: linear-gradient(-45deg, rgba(24, 40, 72, .7),
rgba(35, 37, 58, .8),
rgba(35, 37, 58, .8),
rgba(24, 40, 72, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/*分类页面*/
.layout>#page {
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px); 兼容性前缀,适用于一些旧版本的浏览器 */
}
[data-theme=dark] .layout>#page {
background: linear-gradient(-45deg, rgba(24, 40, 72, .7),
rgba(35, 37, 58, .8),
rgba(35, 37, 58, .8),
rgba(24, 40, 72, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px); 兼容性前缀,适用于一些旧版本的浏览器 */
}
/*时间轴页面*/
.layout>#archive {
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
[data-theme=dark] .layout>#archive {
background: linear-gradient(-45deg, rgba(24, 40, 72, .7),
rgba(35, 37, 58, .8),
rgba(35, 37, 58, .8),
rgba(24, 40, 72, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/*分类点进去的页面*/
.layout>#category {
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
[data-theme=dark] .layout>#category {
background: linear-gradient(-45deg, rgba(24, 40, 72, .7),
rgba(35, 37, 58, .8),
rgba(35, 37, 58, .8),
rgba(24, 40, 72, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
/*标签点进去的页面*/
.layout>#tag {
background: linear-gradient(-45deg, rgba(255, 255, 255, .7),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .8),
rgba(255, 255, 255, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
[data-theme=dark] .layout>#tag {
background: linear-gradient(-45deg, rgba(24, 40, 72, .7),
rgba(35, 37, 58, .8),
rgba(35, 37, 58, .8),
rgba(24, 40, 72, .7));
/* backdrop-filter: blur(10px); 应用高斯模糊效果,可以根据需要调整模糊程度 */
/* -webkit-backdrop-filter: blur(10px);兼容性前缀,适用于一些旧版本的浏览器 */
}
.layout.hide-aside {
max-width: 1200px;
}
/* 设置黑夜的时候,社交按钮为白色 */
[data-theme=dark] .social-icon i {
color: rgba(188, 188, 188) !important; /* 设置为白色 */
}

View File

@@ -0,0 +1,186 @@
// color
$bright-blue = #49B1F5
$strong-cyan = #00c4b6
$light-orange = #FF7242
$light-red = #F47466
$themeColorEnable = hexo-config('theme_color') && hexo-config('theme_color.enable')
$theme-color = $themeColorEnable && hexo-config('theme_color.main') ? convert(hexo-config('theme_color.main')) : $bright-blue
$theme-paginator-color = $themeColorEnable && hexo-config('theme_color.paginator') ? convert(hexo-config('theme_color.paginator')) : $strong-cyan
$theme-text-selection-color = $themeColorEnable && hexo-config('theme_color.text_selection') ? convert(hexo-config('theme_color.text_selection')) : $strong-cyan
$theme-link-color = $themeColorEnable && hexo-config('theme_color.link_color') ? convert(hexo-config('theme_color.link_color')) : $bright-blue
$theme-hr-color = $themeColorEnable && hexo-config('theme_color.hr_color') ? convert(hexo-config('theme_color.hr_color')) : $bright-blue
$code-foreground = $themeColorEnable && hexo-config('theme_color.code_foreground') ? convert(hexo-config('theme_color.code_foreground')) : $light-red
$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
$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-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
$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'))
// hr
$hrEnable = hexo-config('hr_icon') && hexo-config('hr_icon.enable')
$hr-icon = $hrEnable && hexo-config('hr_icon.icon') ? hexo-config('hr_icon.icon') : '\f0c4'
$hr-icon-top = $hrEnable && hexo-config('hr_icon.icon_top') ? convert(hexo-config('hr_icon.icon_top')) : -10px
// page beautify
$beautifyEnable = hexo-config('beautify.enable')
$title-prefix-icon = $beautifyEnable && hexo-config('beautify.title_prefix_icon') ? hexo-config('beautify.title_prefix_icon') : '\f0c1'
$title-prefix-icon-color = $beautifyEnable && hexo-config('beautify.title_prefix_icon_color') ? convert(hexo-config('beautify.title_prefix_icon_color')) : $light-red
// Global Variables
$font-size = hexo-config('font.global_font_size') ? convert(hexo-config('font.global_font_size')) : 14px
$code-font-size = hexo-config('font.code_font_size') ? convert(hexo-config('font.code_font_size')) : var(--global-font-size)
$font-color = #1F2D3D
$text-line-height = 2
$index_top_img_height = hexo-config('index_top_img_height') ? convert(hexo-config('index_top_img_height')) : 100vh
$index_site_info_top = hexo-config('index_site_info_top') ? convert(hexo-config('index_site_info_top')) : 43%
// Global color & SVG
$light-blue = $theme-color
$dark-black = #000000
$light-grey = #EEEEEE
$grey = #858585
$dark-grey = #cacaca
$white = #FFFFFF
$whitesmoke = #f5f5f5
$font-black = #4C4948
$card-bg = $white
$text-highlight-color = $font-color
$text-hover = $theme-color
$text-bg-hover = $theme-color
// code
$line-height-code-block = 1.6
$blockquote-color = #6a737d
$blockquote-padding-color = $themeColorEnable && hexo-config('theme_color.blockquote_padding_color') ? convert(hexo-config('theme_color.blockquote_padding_color')) : #49B1F5
$blockquote-background-color = $themeColorEnable && hexo-config('theme_color.blockquote_background_color') ? alpha(convert(hexo-config('theme_color.blockquote_background_color')), .1) : alpha($blockquote-padding-color, .1)
// page
$body-bg = #fff
$a-link-color = #99a9bf
$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 = 330px
// aside
$toc-link-color = #666261
$toc-mobile-width = calc(100% - 80px)
$toc-mobile-maxWidth = 380px
$toc-active-color = #fff
// Button
$button-color = #fff
$button-hover-color = $themeColorEnable && hexo-config('theme_color.button_hover') ? convert(hexo-config('theme_color.button_hover')) : $light-orange
$button-bg = $theme-color
$pseudo-hover = $button-hover-color
// scrollbar
$scrollbar-color = $themeColorEnable && hexo-config('theme_color.scrollbar_color') ? convert(hexo-config('theme_color.scrollbar_color')) : $theme-color
// table
$table-thead-bg = #99a9bf
// reward
$reward-pop-up-bg = #f5f5f5
$reward-pop-up-color = #858585
// search
$search-bg = #f6f8fa
$search-input-color = $font-black
$search-color = $theme-color
$search-keyword-highlight = #F47466
$search-a-color = $font-black
// comments
$comments-switch-first-text = $bright-blue
$comments-switch-second-text = $light-orange
$comments-switch-round = #fff
$comments-switch-bg = #f6f8fa
// noticeOutdate
$noticeOutdate-bg = #ffe6e6
$noticeOutdate-color = #ff6666
$noticeOutdate-border = #ff8080
// gallery
$gallery-color = #fff
// tag-hide
$tag-hide-bg = $theme-color
$tag-hide-toggle-bg = #f0f0f0
// preloader
$preloader-bg = #37474f
$preloader-word-color = #fff
// rightside
$rightside-bottom = hexo-config('rightside_bottom') ? convert(hexo-config('rightside_bottom')) : 40px
// fireworks
$fireworks-zIndex = hexo-config('fireworks.zIndex') ? hexo-config('fireworks.zIndex') : 99999
// Tag Plugins - Note
hexo-config('note.light_bg_offset') is a 'unit' ? ($lbg = unit(hexo-config('note.light_bg_offset'), '%')) : ($lbg = 0)
$note-types = 'default' 'primary' 'info' 'success' 'warning' 'danger'
// Default
$note-default-border = #777
$note-default-bg = lighten(spin($note-default-border, 0), 94% + $lbg)
$note-default-text = $note-default-border
$note-default-icon = '\f0a9'
$note-modern-default-border = #e1e1e1
$note-modern-default-bg = lighten(spin($note-modern-default-border, 10), 60% + ($lbg * 4))
$note-modern-default-text = #666
$note-modern-default-hover = darken(spin($note-modern-default-text, -10), 32%)
// Primary
$note-primary-border = #6f42c1
$note-primary-bg = lighten(spin($note-primary-border, 10), 92% + $lbg)
$note-primary-text = $note-primary-border
$note-primary-icon = '\f055'
$note-modern-primary-border = #e1c2ff
$note-modern-primary-bg = lighten(spin($note-modern-primary-border, 10), 40% + ($lbg * 4))
$note-modern-primary-text = #6f42c1
$note-modern-primary-hover = darken(spin($note-modern-primary-text, -10), 22%)
// Info
$note-info-border = #428bca
$note-info-bg = lighten(spin($note-info-border, -10), 91% + $lbg)
$note-info-text = $note-info-border
$note-info-icon = '\f05a'
$note-modern-info-border = #b3e5ef
$note-modern-info-bg = lighten(spin($note-modern-info-border, 10), 50% + ($lbg * 4))
$note-modern-info-text = #31708f
$note-modern-info-hover = darken(spin($note-modern-info-text, -10), 32%)
// Success
$note-success-border = #5cb85c
$note-success-bg = lighten(spin($note-success-border, 10), 90% + $lbg)
$note-success-text = $note-success-border
$note-success-icon = '\f058'
$note-modern-success-border = #d0e6be
$note-modern-success-bg = lighten(spin($note-modern-success-border, 10), 40% + ($lbg * 4))
$note-modern-success-text = #3c763d
$note-modern-success-hover = darken(spin($note-modern-success-text, -10), 27%)
// Warning
$note-warning-border = #f0ad4e
$note-warning-bg = lighten(spin($note-warning-border, 10), 88% + $lbg)
$note-warning-text = $note-warning-border
$note-warning-icon = '\f06a'
$note-modern-warning-border = #fae4cd
$note-modern-warning-bg = lighten(spin($note-modern-warning-border, 10), 43% + ($lbg * 4))
$note-modern-warning-text = #8a6d3b
$note-modern-warning-hover = darken(spin($note-modern-warning-text, -10), 18%)
// Danger
$note-danger-border = #d9534f
$note-danger-bg = lighten(spin($note-danger-border, -10), 92% + $lbg)
$note-danger-text = $note-danger-border
$note-danger-icon = '\f056'
$note-modern-danger-border = #ebcdd2
$note-modern-danger-bg = lighten(spin($note-modern-danger-border, 10), 35% + ($lbg * 4))
$note-modern-danger-text = #a94442
$note-modern-danger-hover = darken(spin($note-modern-danger-text, -10), 22%)
// Tag Plugins - Button/note
$color-types = 'blue' 'pink' 'red' 'purple' 'orange' 'green'
$btn-color = #fff
$btn-default-color = #777
$tagsP-blue-color = #428bca
$tagsP-pink-color = #FF69B4
$tagsP-red-color = #FF0000
$tagsP-orange-color = #FF8C00
$tagsP-purple-color = #6f42c1
$tagsP-green-color = #5cb85c
// Tag Plugins - Tab
$tab-border-color = #f0f0f0
$tab-button-bg = #f0f0f0
$tab-button-color = $font-color
$tab-button-hover-bg = darken($tab-border-color, 8)
$tab-active-border-color = $theme-color
$tab-button-active-bg = $card-bg
$tab-to-top-color = #99a9bf
$tab-to-top-hover-color = $theme-color
// Tag Plugins - timeline
$timeline-default-color = $theme-color

View File

@@ -0,0 +1,25 @@
#welcome-info {
overflow: hidden;
border-radius: 14px;
--kouseki-welcome-color: #49B1F5;
--kouseki-ip-color: #49B1F5;
--kouseki-gl-size: 16px!important;
}
/* 给 IP 地址的 span 再包一层,便于选择器定位 */
/* JS 原文已经生成 <b><span>IP</span></b>,这里我们给这个 span 加类名 ip-mask */
/* 如果你不方便改 HTML可直接用属性选择器#welcome-info b span:nth-child(1) */
#welcome-info b span.ip-mask {
display: inline-block;
filter: blur(6px);
transition: filter .3s ease;
cursor: pointer;
user-select: none; /* 防止复制到模糊文本 */
}
/* 鼠标悬停或点击时(:active立即清晰 */
#welcome-info b span.ip-mask:hover,
#welcome-info b span.ip-mask:active {
filter: blur(0);
}
/* 如果想做成「必须点一下才永久清晰」,把 :hover 去掉即可 */

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -0,0 +1,65 @@
// 打字机效果
function typeTextMachineStyle(text, targetSelector, options = {}) {
const {
delay = 50,
startDelay = 2000,
onComplete = null,
clearBefore = true,
eraseBefore = true, // 新增:是否以打字机方式清除原文本
eraseDelay = 30, // 新增:删除每个字符的间隔
} = options;
const el = document.querySelector(targetSelector);
if (!el || typeof text !== "string") return;
setTimeout(() => {
const startTyping = () => {
let index = 0;
function renderChar() {
if (index <= text.length) {
el.textContent = text.slice(0, index++);
setTimeout(renderChar, delay);
} else {
onComplete && onComplete(el);
}
}
renderChar();
};
if (clearBefore) {
if (eraseBefore && el.textContent.length > 0) {
let currentText = el.textContent;
let eraseIndex = currentText.length;
function eraseChar() {
if (eraseIndex > 0) {
el.textContent = currentText.slice(0, --eraseIndex);
setTimeout(eraseChar, eraseDelay);
} else {
startTyping(); // 删除完毕后开始打字
}
}
eraseChar();
} else {
el.textContent = "";
startTyping();
}
} else {
startTyping();
}
}, startDelay);
}
function renderAISummary() {
const summaryEl = document.querySelector('.ai-summary .ai-explanation');
if (!summaryEl) return;
const summaryText = summaryEl.getAttribute('data-summary');
if (summaryText) {
typeTextMachineStyle(summaryText, ".ai-summary .ai-explanation"); // 如果需要切换,在这里调用另一个函数即可
}
}
document.addEventListener('pjax:complete', renderAISummary);
document.addEventListener('DOMContentLoaded', renderAISummary);

View File

@@ -0,0 +1,111 @@
document.addEventListener("DOMContentLoaded", () => {
initializeCard();
});
document.addEventListener("pjax:complete", () => {
initializeCard();
});
function initializeCard() {
cardTimes();
cardRefreshTimes();
}
let year, month, week, date, dates, weekStr, monthStr, asideTime, asideDay, asideDayNum, animalYear, ganzhiYear, lunarMon, lunarDay;
const now = new Date();
function cardRefreshTimes() {
const e = document.getElementById("card-widget-schedule");
if (e) {
asideDay = (now - asideTime) / 1e3 / 60 / 60 / 24;
e.querySelector("#pBar_year").value = asideDay;
e.querySelector("#p_span_year").innerHTML = (asideDay / 365 * 100).toFixed(1) + "%";
e.querySelector(".schedule-r0 .schedule-d1 .aside-span2").innerHTML = `还剩<a> ${(365 - asideDay).toFixed(0)} </a>天`;
e.querySelector("#pBar_month").value = date;
e.querySelector("#pBar_month").max = dates;
e.querySelector("#p_span_month").innerHTML = (date / dates * 100).toFixed(1) + "%";
e.querySelector(".schedule-r1 .schedule-d1 .aside-span2").innerHTML = `还剩<a> ${(dates - date)} </a>天`;
e.querySelector("#pBar_week").value = week === 0 ? 7 : week;
e.querySelector("#p_span_week").innerHTML = ((week === 0 ? 7 : week) / 7 * 100).toFixed(1) + "%";
e.querySelector(".schedule-r2 .schedule-d1 .aside-span2").innerHTML = `还剩<a> ${(7 - (week === 0 ? 7 : week))} </a>天`;
}
}
function cardTimes() {
year = now.getFullYear();
month = now.getMonth();
week = now.getDay();
date = now.getDate();
const e = document.getElementById("card-widget-calendar");
if (e) {
const isLeapYear = year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
weekStr = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"][week];
const monthData = [
{ month: "1月", days: 31 },
{ month: "2月", days: isLeapYear ? 29 : 28 },
{ month: "3月", days: 31 },
{ month: "4月", days: 30 },
{ month: "5月", days: 31 },
{ month: "6月", days: 30 },
{ month: "7月", days: 31 },
{ month: "8月", days: 31 },
{ month: "9月", days: 30 },
{ month: "10月", days: 31 },
{ month: "11月", days: 30 },
{ month: "12月", days: 31 }
];
monthStr = monthData[month].month;
dates = monthData[month].days;
const t = (week + 8 - date % 7) % 7;
let n = "", d = false, s = 7 - t;
const o = (dates - s) % 7 === 0 ? Math.floor((dates - s) / 7) + 1 : Math.floor((dates - s) / 7) + 2;
const c = e.querySelector("#calendar-main");
const l = e.querySelector("#calendar-date");
l.style.fontSize = ["64px", "48px", "36px"][Math.min(o - 3, 2)];
for (let i = 0; i < o; i++) {
if (!c.querySelector(`.calendar-r${i}`)) {
c.innerHTML += `<div class='calendar-r${i}'></div>`;
}
for (let j = 0; j < 7; j++) {
if (i === 0 && j === t) {
n = 1;
d = true;
}
const r = n === date ? " class='now'" : "";
if (!c.querySelector(`.calendar-r${i} .calendar-d${j} a`)) {
c.querySelector(`.calendar-r${i}`).innerHTML += `<div class='calendar-d${j}'><a${r}>${n}</a></div>`;
}
if (n >= dates) {
n = "";
d = false;
}
if (d) {
n += 1;
}
}
}
const lunarDate = chineseLunar.solarToLunar(new Date(year, month, date));
animalYear = chineseLunar.format(lunarDate, "A");
ganzhiYear = chineseLunar.format(lunarDate, "T").slice(0, -1);
lunarMon = chineseLunar.format(lunarDate, "M");
lunarDay = chineseLunar.format(lunarDate, "d");
const newYearDate = new Date("2026/02/16 00:00:00");
const daysUntilNewYear = Math.floor((newYearDate - now) / 1e3 / 60 / 60 / 24);
asideTime = new Date(`${new Date().getFullYear()}/01/01 00:00:00`);
asideDay = (now - asideTime) / 1e3 / 60 / 60 / 24;
asideDayNum = Math.floor(asideDay);
const weekNum = week - asideDayNum % 7 >= 0 ? Math.ceil(asideDayNum / 7) : Math.ceil(asideDayNum / 7) + 1;
e.querySelector("#calendar-week").innerHTML = `${weekNum}周&nbsp;${weekStr}`;
e.querySelector("#calendar-date").innerHTML = date.toString().padStart(2, "0");
e.querySelector("#calendar-solar").innerHTML = `${year}${monthStr}&nbsp;第${asideDay.toFixed(0)}`;
e.querySelector("#calendar-lunar").innerHTML = `${ganzhiYear}${animalYear}年&nbsp;${lunarMon}${lunarDay}`;
document.getElementById("schedule-days").innerHTML = daysUntilNewYear;
}
}

View File

@@ -0,0 +1,930 @@
document.addEventListener('DOMContentLoaded', () => {
let headerContentWidth, $nav
let mobileSidebarOpen = false
const adjustMenu = init => {
const getAllWidth = ele => Array.from(ele).reduce((width, i) => width + i.offsetWidth, 0)
if (init) {
const blogInfoWidth = getAllWidth(document.querySelector('#blog-info > a').children)
const menusWidth = getAllWidth(document.getElementById('menus').children)
headerContentWidth = blogInfoWidth + menusWidth
$nav = document.getElementById('nav')
}
const hideMenuIndex = window.innerWidth <= 768 || headerContentWidth > $nav.offsetWidth - 120
$nav.classList.toggle('hide-menu', hideMenuIndex)
}
// 初始化header
const initAdjust = () => {
adjustMenu(true)
$nav.classList.add('show')
}
// sidebar menus
const sidebarFn = {
open: () => {
btf.overflowPaddingR.add()
btf.animateIn(document.getElementById('menu-mask'), 'to_show 0.5s')
document.getElementById('sidebar-menus').classList.add('open')
mobileSidebarOpen = true
},
close: () => {
btf.overflowPaddingR.remove()
btf.animateOut(document.getElementById('menu-mask'), 'to_hide 0.5s')
document.getElementById('sidebar-menus').classList.remove('open')
mobileSidebarOpen = false
}
}
/**
* 首頁top_img底下的箭頭
*/
const scrollDownInIndex = () => {
const handleScrollToDest = () => {
btf.scrollToDest(document.getElementById('content-inner').offsetTop, 300)
}
const $scrollDownEle = document.getElementById('scroll-down')
$scrollDownEle && btf.addEventListenerPjax($scrollDownEle, 'click', handleScrollToDest)
}
/**
* 代碼
* 只適用於Hexo默認的代碼渲染
*/
const addHighlightTool = () => {
const highLight = GLOBAL_CONFIG.highlight
if (!highLight) return
const { highlightCopy, highlightLang, highlightHeightLimit, highlightFullpage, highlightMacStyle, plugin } = highLight
const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink
const isShowTool = highlightCopy || highlightLang || isHighlightShrink !== undefined || highlightFullpage || highlightMacStyle
const $figureHighlight = plugin === 'highlight.js' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]')
if (!((isShowTool || highlightHeightLimit) && $figureHighlight.length)) return
const isPrismjs = plugin === 'prismjs'
const highlightShrinkClass = isHighlightShrink === true ? 'closed' : ''
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>' : ''
const alertInfo = (ele, text) => {
if (GLOBAL_CONFIG.Snackbar !== undefined) {
btf.snackbarShow(text)
} else {
ele.textContent = text
ele.style.opacity = 1
setTimeout(() => { ele.style.opacity = 0 }, 800)
}
}
const copy = async (text, ctx) => {
try {
await navigator.clipboard.writeText(text)
alertInfo(ctx, GLOBAL_CONFIG.copy.success)
} catch (err) {
console.error('Failed to copy: ', err)
alertInfo(ctx, GLOBAL_CONFIG.copy.noSupport)
}
}
// click events
const highlightCopyFn = (ele, clickEle) => {
const $buttonParent = ele.parentNode
$buttonParent.classList.add('copy-true')
const preCodeSelector = isPrismjs ? 'pre code' : 'table .code pre'
const codeElement = $buttonParent.querySelector(preCodeSelector)
if (!codeElement) return
copy(codeElement.innerText, clickEle.previousElementSibling)
$buttonParent.classList.remove('copy-true')
}
const highlightShrinkFn = ele => ele.classList.toggle('closed')
const codeFullpage = (item, clickEle) => {
const wrapEle = item.closest('figure.highlight')
const isFullpage = wrapEle.classList.toggle('code-fullpage')
document.body.style.overflow = isFullpage ? 'hidden' : ''
clickEle.classList.toggle('fa-down-left-and-up-right-to-center', isFullpage)
clickEle.classList.toggle('fa-up-right-and-down-left-from-center', !isFullpage)
}
const highlightToolsFn = e => {
const $target = e.target.classList
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 = e => e.currentTarget.classList.toggle('expand-done')
// 獲取隱藏狀態下元素的真實高度
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') || '')
}
current = current.parentNode
}
const style = 'visibility: hidden !important; display: block !important;'
hiddenElements.forEach((originalStyle, elem) => {
elem.setAttribute('style', originalStyle ? originalStyle + ';' + style : style)
})
}
const restore = () => {
hiddenElements.forEach((originalStyle, elem) => {
if (originalStyle === '') elem.removeAttribute('style')
else elem.setAttribute('style', originalStyle)
})
}
fix()
const height = item.offsetHeight
restore()
return height
}
const createEle = (lang, item) => {
const fragment = document.createDocumentFragment()
if (isShowTool) {
const hlTools = document.createElement('div')
hlTools.className = `highlight-tools ${highlightShrinkClass}`
hlTools.innerHTML = highlightMacStyleEle + highlightShrinkEle + lang + highlightCopyEle + highlightFullpageEle
btf.addEventListenerPjax(hlTools, 'click', highlightToolsFn)
fragment.appendChild(hlTools)
}
if (highlightHeightLimit && getActualHeight(item) > highlightHeightLimit + 30) {
const ele = document.createElement('div')
ele.className = 'code-expand-btn'
ele.innerHTML = '<i class="fas fa-angle-double-down"></i>'
btf.addEventListenerPjax(ele, 'click', expandCode)
fragment.appendChild(ele)
}
isPrismjs ? item.parentNode.insertBefore(fragment, item) : item.insertBefore(fragment, item.firstChild)
}
$figureHighlight.forEach(item => {
let langName = ''
if (isPrismjs) btf.wrap(item, 'figure', { class: 'highlight' })
if (!highlightLang) {
createEle('', item)
return
}
if (isPrismjs) {
langName = item.getAttribute('data-language') || 'Code'
} else {
langName = item.getAttribute('class').split(' ')[1]
if (langName === 'plain' || langName === undefined) langName = 'Code'
}
createEle(`<div class="code-lang">${langName}</div>`, item)
})
}
/**
* PhotoFigcaption
*/
const addPhotoFigcaption = () => {
if (!GLOBAL_CONFIG.isPhotoFigcaption) return
document.querySelectorAll('#article-container img').forEach(item => {
const altValue = item.title || item.alt
if (!altValue) return
const ele = document.createElement('div')
ele.className = 'img-alt text-center'
ele.textContent = altValue
item.insertAdjacentElement('afterend', ele)
})
}
/**
* Lightbox
*/
const runLightbox = () => {
btf.loadLightbox(document.querySelectorAll('#article-container img:not(.no-lightbox)'))
}
/**
* justified-gallery 圖庫排版
*/
const fetchUrl = async url => {
try {
const response = await fetch(url)
return await response.json()
} catch (error) {
console.error('Failed to fetch URL:', error)
return []
}
}
const runJustifiedGallery = (container, data, config) => {
const { isButton, limit, firstLimit, tabs } = config
const dataLength = data.length
const maxGroupKey = Math.ceil((dataLength - firstLimit) / limit + 1)
// Gallery configuration
const igConfig = {
gap: 5,
isConstantSize: true,
sizeRange: [150, 600],
// useResizeObserver: true,
// observeChildren: true,
useTransform: true
// useRecycle: false
}
const ig = new InfiniteGrid.JustifiedInfiniteGrid(container, igConfig)
let isLayoutHidden = false
// Utility functions
const sanitizeString = str => (str && str.replace(/"/g, '&quot;')) || ''
const createImageItem = item => {
const alt = item.alt ? `alt="${sanitizeString(item.alt)}"` : ''
const title = item.title ? `title="${sanitizeString(item.title)}"` : ''
return `<div class="item">
<img src="${item.url}" data-grid-maintained-target="true" ${alt} ${title} />
</div>`
}
const getItems = (nextGroupKey, count, isFirst = false) => {
const startIndex = isFirst ? (nextGroupKey - 1) * count : (nextGroupKey - 2) * count + firstLimit
return data.slice(startIndex, startIndex + count).map(createImageItem)
}
// Load more button
const addLoadMoreButton = container => {
const button = document.createElement('button')
button.innerHTML = `${GLOBAL_CONFIG.infinitegrid.buttonText}<i class="fa-solid fa-arrow-down"></i>`
button.addEventListener('click', () => {
button.remove()
btf.setLoading.add(container)
appendItems(ig.getGroups().length + 1, limit)
}, { once: true })
container.insertAdjacentElement('afterend', button)
}
const appendItems = (nextGroupKey, count, isFirst) => {
ig.append(getItems(nextGroupKey, count, isFirst), nextGroupKey)
}
// Event handlers
const handleRenderComplete = e => {
if (tabs) {
const parentNode = container.parentNode
if (isLayoutHidden) {
parentNode.style.visibility = 'visible'
}
if (container.offsetHeight === 0) {
parentNode.style.visibility = 'hidden'
isLayoutHidden = true
}
}
const { updated, isResize, mounted } = e
if (!updated.length || !mounted.length || isResize) return
btf.loadLightbox(container.querySelectorAll('img:not(.medium-zoom-image)'))
if (ig.getGroups().length === maxGroupKey) {
btf.setLoading.remove(container)
!tabs && ig.off('renderComplete', handleRenderComplete)
return
}
if (isButton) {
btf.setLoading.remove(container)
addLoadMoreButton(container)
}
}
const handleRequestAppend = btf.debounce(e => {
const nextGroupKey = (+e.groupKey || 0) + 1
if (nextGroupKey === 1) appendItems(nextGroupKey, firstLimit, true)
else appendItems(nextGroupKey, limit)
if (nextGroupKey === maxGroupKey) ig.off('requestAppend', handleRequestAppend)
}, 300)
btf.setLoading.add(container)
ig.on('renderComplete', handleRenderComplete)
if (isButton) {
appendItems(1, firstLimit, true)
} else {
ig.on('requestAppend', handleRequestAppend)
ig.renderItems()
}
btf.addGlobalFn('pjaxSendOnce', () => ig.destroy())
}
const addJustifiedGallery = async (elements, tabs = false) => {
if (!elements.length) return
const initGallery = async () => {
for (const element of elements) {
if (btf.isHidden(element) || element.classList.contains('loaded')) continue
const config = {
isButton: element.getAttribute('data-button') === 'true',
limit: parseInt(element.getAttribute('data-limit'), 10),
firstLimit: parseInt(element.getAttribute('data-first'), 10),
tabs
}
const container = element.firstElementChild
const content = container.textContent
container.textContent = ''
element.classList.add('loaded')
try {
const data = element.getAttribute('data-type') === 'url' ? await fetchUrl(content) : JSON.parse(content)
runJustifiedGallery(container, data, config)
} catch (error) {
console.error('Gallery data parsing failed:', error)
}
}
}
if (typeof InfiniteGrid === 'function') {
await initGallery()
} else {
await btf.getScript(GLOBAL_CONFIG.infinitegrid.js)
await initGallery()
}
}
/**
* rightside scroll percent
*/
const rightsideScrollPercent = currentTop => {
const scrollPercent = btf.getScrollPercent(currentTop, document.body)
const goUpElement = document.getElementById('go-up')
if (scrollPercent < 95) {
goUpElement.classList.add('show-percent')
goUpElement.querySelector('.scroll-percent').textContent = scrollPercent
} else {
goUpElement.classList.remove('show-percent')
}
}
/**
* 滾動處理
*/
const scrollFn = () => {
const $rightside = document.getElementById('rightside')
const innerHeight = window.innerHeight + 56
let initTop = 0
const $header = document.getElementById('page-header')
const isChatBtn = typeof chatBtn !== 'undefined'
const isShowPercent = GLOBAL_CONFIG.percent.rightside
// 檢查文檔高度是否小於視窗高度
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
initTop = currentTop
return result
}
let flag = ''
const scrollTask = btf.throttle(() => {
const currentTop = window.scrollY || document.documentElement.scrollTop
const isDown = scrollDirection(currentTop)
if (currentTop > 56) {
if (flag === '') {
$header.classList.add('nav-fixed')
$rightside.classList.add('rightside-show')
}
if (isDown) {
if (flag !== 'down') {
$header.classList.remove('nav-visible')
isChatBtn && window.chatBtn.hide()
flag = 'down'
}
} else {
if (flag !== 'up') {
$header.classList.add('nav-visible')
isChatBtn && window.chatBtn.show()
flag = 'up'
}
}
} else {
flag = ''
if (currentTop === 0) {
$header.classList.remove('nav-fixed', 'nav-visible')
}
$rightside.classList.remove('rightside-show')
}
isShowPercent && rightsideScrollPercent(currentTop)
checkDocumentHeight()
}, 300)
btf.addEventListenerPjax(window, 'scroll', scrollTask, { passive: true })
}
/**
* toc,anchor
*/
const scrollFnToDo = () => {
const isToc = GLOBAL_CONFIG_SITE.isToc
const isAnchor = GLOBAL_CONFIG.isAnchor
const $article = document.getElementById('article-container')
if (!($article && (isToc || isAnchor))) return
let $tocLink, $cardToc, autoScrollToc, $tocPercentage, isExpand
if (isToc) {
const $cardTocLayout = document.getElementById('card-toc')
$cardToc = $cardTocLayout.querySelector('.toc-content')
$tocLink = $cardToc.querySelectorAll('.toc-link')
$tocPercentage = $cardTocLayout.querySelector('.toc-percentage')
isExpand = $cardToc.classList.contains('is-expand')
// toc元素點擊
const tocItemClickFn = e => {
const target = e.target.closest('.toc-link')
if (!target) return
e.preventDefault()
btf.scrollToDest(btf.getEleTop(document.getElementById(decodeURI(target.getAttribute('href')).replace('#', ''))), 300)
if (window.innerWidth < 900) {
$cardTocLayout.classList.remove('open')
}
}
btf.addEventListenerPjax($cardToc, 'click', tocItemClickFn)
autoScrollToc = item => {
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)
}
}
// 處理 hexo-blog-encrypt 事件
$cardToc.style.display = 'block'
}
// 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
let currentId = ''
let currentIndex = ''
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 = i
} else {
break
}
}
if (detectItem === currentIndex) return
if (isAnchor) btf.updateAnchor(currentId)
detectItem = currentIndex
if (isToc) {
$cardToc.querySelectorAll('.active').forEach(i => i.classList.remove('active'))
if (currentId) {
const currentActive = $tocLink[currentIndex]
currentActive.classList.add('active')
setTimeout(() => autoScrollToc(currentActive), 0)
if (!isExpand) {
let parent = currentActive.parentNode
while (!parent.matches('.toc')) {
if (parent.matches('li')) parent.classList.add('active')
parent = parent.parentNode
}
}
}
}
}
// main of scroll
const tocScrollFn = btf.throttle(() => {
const currentTop = window.scrollY || document.documentElement.scrollTop
if (isToc && GLOBAL_CONFIG.percent.toc) {
$tocPercentage.textContent = btf.getScrollPercent(currentTop, $article)
}
findHeadPosition(currentTop)
}, 100)
btf.addEventListenerPjax(window, 'scroll', tocScrollFn, { passive: true })
}
const handleThemeChange = mode => {
const globalFn = window.globalFn || {}
const themeChange = globalFn.themeChange || {}
if (!themeChange) {
return
}
Object.keys(themeChange).forEach(key => {
const themeChangeFn = themeChange[key]
if (['disqus', 'disqusjs'].includes(key)) {
setTimeout(() => themeChangeFn(mode), 300)
} else {
themeChangeFn(mode)
}
})
}
/**
* Rightside
*/
const rightSideFn = {
readmode: () => { // read mode
const $body = document.body
const newEle = document.createElement('button')
const exitReadMode = () => {
$body.classList.remove('read-mode')
newEle.remove()
newEle.removeEventListener('click', exitReadMode)
}
$body.classList.add('read-mode')
newEle.type = 'button'
newEle.className = 'fas fa-sign-out-alt exit-readmode'
newEle.addEventListener('click', exitReadMode)
$body.appendChild(newEle)
},
darkmode: () => { // switch between light and dark mode
const willChangeMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'
if (willChangeMode === 'dark') {
btf.activateDarkMode()
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)
} else {
btf.activateLightMode()
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day)
}
btf.saveToLocal.set('theme', willChangeMode, 2)
handleThemeChange(willChangeMode)
},
'rightside-config': item => { // Show or hide rightside-hide-btn
const hideLayout = item.firstElementChild
if (hideLayout.classList.contains('show')) {
hideLayout.classList.add('status')
setTimeout(() => {
hideLayout.classList.remove('status')
}, 300)
}
hideLayout.classList.toggle('show')
},
'go-up': () => { // Back to top
btf.scrollToDest(0, 500)
},
'hide-aside-btn': () => { // Hide aside
const $htmlDom = document.documentElement.classList
const saveStatus = $htmlDom.contains('hide-aside') ? 'show' : 'hide'
btf.saveToLocal.set('aside-status', saveStatus, 2)
$htmlDom.toggle('hide-aside')
},
'mobile-toc-button': (p, item) => { // Show mobile toc
const tocEle = document.getElementById('card-toc')
tocEle.style.transition = 'transform 0.3s ease-in-out'
const tocEleHeight = tocEle.clientHeight
const btData = item.getBoundingClientRect()
const tocEleBottom = window.innerHeight - btData.bottom - 30
if (tocEleHeight > tocEleBottom) {
tocEle.style.transformOrigin = `right ${tocEleHeight - tocEleBottom - btData.height / 2}px`
}
tocEle.classList.toggle('open')
tocEle.addEventListener('transitionend', () => {
tocEle.style.cssText = ''
}, { once: true })
},
'chat-btn': () => { // Show chat
window.chatBtnFn()
},
translateLink: () => { // switch between traditional and simplified chinese
window.translateFn.translatePage()
}
}
document.getElementById('rightside').addEventListener('click', e => {
const $target = e.target.closest('[id]')
if ($target && rightSideFn[$target.id]) {
rightSideFn[$target.id](e.currentTarget, $target)
}
})
/**
* menu
* 側邊欄sub-menu 展開/收縮
*/
const clickFnOfSubMenu = () => {
const handleClickOfSubMenu = e => {
const target = e.target.closest('.site-page.group')
if (!target) return
target.classList.toggle('hide')
}
const menusItems = document.querySelector('#sidebar-menus .menus_items')
menusItems && menusItems.addEventListener('click', handleClickOfSubMenu)
}
/**
* 手机端目录点击
*/
const openMobileMenu = () => {
const toggleMenu = document.getElementById('toggle-menu')
if (!toggleMenu) return
btf.addEventListenerPjax(toggleMenu, 'click', () => { sidebarFn.open() })
}
/**
* 複製時加上版權信息
*/
const addCopyright = () => {
const { limitCount, languages } = GLOBAL_CONFIG.copyright
const handleCopy = (e) => {
e.preventDefault()
const copyFont = window.getSelection(0).toString()
let textFont = copyFont
if (copyFont.length > limitCount) {
textFont = `${copyFont}\n\n\n${languages.author}\n${languages.link}${window.location.href}\n${languages.source}\n${languages.info}`
}
if (e.clipboardData) {
return e.clipboardData.setData('text', textFont)
} else {
return window.clipboardData.setData('text', textFont)
}
}
document.body.addEventListener('copy', handleCopy)
}
/**
* 網頁運行時間
*/
const addRuntime = () => {
const $runtimeCount = document.getElementById('runtimeshow')
if ($runtimeCount) {
const publishDate = $runtimeCount.getAttribute('data-publishDate')
$runtimeCount.textContent = `${btf.diffDate(publishDate)} ${GLOBAL_CONFIG.runtime}`
}
}
/**
* 最後一次更新時間
*/
const addLastPushDate = () => {
const $lastPushDateItem = document.getElementById('last-push-date')
if ($lastPushDateItem) {
const lastPushDate = $lastPushDateItem.getAttribute('data-lastPushDate')
$lastPushDateItem.textContent = btf.diffDate(lastPushDate, true)
}
}
/**
* table overflow
*/
const addTableWrap = () => {
const $table = document.querySelectorAll('#article-container table')
if (!$table.length) return
$table.forEach(item => {
if (!item.closest('.highlight')) {
btf.wrap(item, 'div', { class: 'table-wrap' })
}
})
}
/**
* tag-hide
*/
const clickFnOfTagHide = () => {
const hideButtons = document.querySelectorAll('#article-container .hide-button')
if (!hideButtons.length) return
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 navTabsElements = document.querySelectorAll('#article-container .tabs')
if (!navTabsElements.length) return
const setActiveClass = (elements, activeIndex) => {
elements.forEach((el, index) => {
el.classList.toggle('active', index === activeIndex)
})
}
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 handleToTopClick = tabElement => e => {
if (e.target.closest('button')) {
btf.scrollToDest(btf.getEleTop(tabElement), 300)
}
}
navTabsElements.forEach(tabElement => {
btf.addEventListenerPjax(tabElement.firstElementChild, 'click', handleNavClick)
btf.addEventListenerPjax(tabElement.lastElementChild, 'click', handleToTopClick(tabElement))
})
}
const toggleCardCategory = () => {
const cardCategory = document.querySelector('#aside-cat-list.expandBtn')
if (!cardCategory) return
const handleToggleBtn = e => {
const target = e.target
if (target.nodeName === 'I') {
e.preventDefault()
target.parentNode.classList.toggle('expand')
}
}
btf.addEventListenerPjax(cardCategory, 'click', handleToggleBtn, true)
}
const addPostOutdateNotice = () => {
const ele = document.getElementById('post-outdate-notice')
if (!ele) return
const { limitDay, messagePrev, messageNext, postUpdate } = JSON.parse(ele.getAttribute('data'))
const diffDay = btf.diffDate(postUpdate)
if (diffDay >= limitDay) {
ele.textContent = `${messagePrev} ${diffDay} ${messageNext}`
ele.hidden = false
}
}
const lazyloadImg = () => {
window.lazyLoadInstance = new LazyLoad({
elements_selector: 'img',
threshold: 0,
data_src: 'lazy-src'
})
btf.addGlobalFn('pjaxComplete', () => {
window.lazyLoadInstance.update()
}, 'lazyload')
}
const relativeDate = selector => {
selector.forEach(item => {
item.textContent = btf.diffDate(item.getAttribute('datetime'), true)
item.style.display = 'inline'
})
}
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()
})
const menuMask = document.getElementById('menu-mask')
menuMask && menuMask.addEventListener('click', () => { sidebarFn.close() })
clickFnOfSubMenu()
GLOBAL_CONFIG.islazyloadPlugin && lazyloadImg()
GLOBAL_CONFIG.copyright !== undefined && addCopyright()
if (GLOBAL_CONFIG.autoDarkmode) {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
if (btf.saveToLocal.get('theme') !== undefined) return
e.matches ? handleThemeChange('dark') : handleThemeChange('light')
})
}
}
const forPostFn = () => {
addHighlightTool()
addPhotoFigcaption()
addJustifiedGallery(document.querySelectorAll('#article-container .gallery-container'))
runLightbox()
scrollFnToDo()
addTableWrap()
clickFnOfTagHide()
tabsFn()
}
const refreshFn = () => {
initAdjust()
justifiedIndexPostUI()
if (GLOBAL_CONFIG_SITE.pageType === 'post') {
addPostOutdateNotice()
GLOBAL_CONFIG.relativeDate.post && relativeDate(document.querySelectorAll('#post-meta time'))
} else {
GLOBAL_CONFIG.relativeDate.homepage && relativeDate(document.querySelectorAll('#recent-posts time'))
GLOBAL_CONFIG.runtime && addRuntime()
addLastPushDate()
toggleCardCategory()
}
GLOBAL_CONFIG_SITE.pageType === 'home' && scrollDownInIndex()
scrollFn()
forPostFn()
GLOBAL_CONFIG_SITE.pageType !== 'shuoshuo' && btf.switchComments(document)
openMobileMenu()
}
btf.addGlobalFn('pjaxComplete', refreshFn, 'refreshFn')
refreshFn()
unRefreshFn()
// 處理 hexo-blog-encrypt 事件
window.addEventListener('hexo-blog-decrypt', e => {
forPostFn()
window.translateFn.translateInitialization()
Object.values(window.globalFn.encrypt).forEach(fn => {
fn()
})
})
})

View File

@@ -0,0 +1,13 @@
function randomPost() {
fetch('/sitemap.xml').then(res => res.text()).then(str => (new window.DOMParser()).parseFromString(str, "text/xml")).then(data => {
let ls = data.querySelectorAll('url loc');
let locationHref,locSplit;
do {
locationHref = ls[Math.floor(Math.random() * ls.length)].innerHTML
locSplit = locationHref.split('/')[3] || ''
} while (locSplit !== 'posts');
//若所有文章都如 https://…….com/posts/2022/07/…… 格式,主域名后字符是 posts则循环条件改为
//while (locSplit !== 'posts');
location.href = locationHref
})
}

View File

@@ -0,0 +1,332 @@
function setMask() {//设置遮罩层
if (document.getElementsByClassName("rmMask")[0] !== undefined) {
return document.getElementsByClassName("rmMask")[0];
}
mask = document.createElement('div');
mask.className = "rmMask";
mask.style.width = window.innerWidth + 'px';
mask.style.height = window.innerHeight + 'px';
mask.style.background = '#fff';
mask.style.opacity = '.0';
mask.style.position = 'fixed';
mask.style.top = '0';
mask.style.left = '0';
mask.style.zIndex = 998;
document.body.appendChild(mask);
document.getElementById("rightMenu").style.zIndex = 19198;
return mask;
}
function insertAtCursor(myField, myValue) {
//IE 浏览器
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
sel.select();
}
//FireFox、Chrome等
else if (myField.selectionStart || myField.selectionStart === '0') {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
// 保存滚动条
var restoreTop = myField.scrollTop;
myField.value = myField.value.substring(0, startPos) + myValue + myField.value.substring(endPos, myField.value.length);
if (restoreTop > 0) {
myField.scrollTop = restoreTop;
}
myField.focus();
myField.selectionStart = startPos + myValue.length;
myField.selectionEnd = startPos + myValue.length;
} else {
myField.value += myValue;
myField.focus();
}
}
let rmf = {};
rmf.showRightMenu = function (isTrue, x = 0, y = 0) {
let $rightMenu = $('#rightMenu');
$rightMenu.css('top', x + 'px').css('left', y + 'px');
if (isTrue) {
$rightMenu.show();
} else {
$rightMenu.hide();
}
}
rmf.switchDarkMode = function () {
const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
if (nowMode === 'light') {
activateDarkMode()
saveToLocal.set('theme', 'dark', 2)
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)
} else {
activateLightMode()
saveToLocal.set('theme', 'light', 2)
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day)
}
// handle some cases
typeof utterancesTheme === 'function' && utterancesTheme()
typeof FB === 'object' && window.loadFBComment()
window.DISQUS && document.getElementById('disqus_thread').children.length && setTimeout(() => window.disqusReset(), 200)
switchPostChart();
};
rmf.copyWordsLink = function () {
const decodedUrl = decodeURIComponent(window.location.href); // 解码 URL
navigator.clipboard.writeText(decodedUrl)
.then(() => {
Snackbar.show({
text: '链接复制成功!快去分享吧!',
pos: 'top-right',
showAction: false
});
})
};
rmf.switchReadMode = function () {
const $body = document.body
$body.classList.add('read-mode')
const newEle = document.createElement('button')
newEle.type = 'button'
newEle.className = 'fas fa-sign-out-alt exit-readmode'
$body.appendChild(newEle)
function clickFn() {
$body.classList.remove('read-mode')
newEle.remove()
newEle.removeEventListener('click', clickFn)
}
newEle.addEventListener('click', clickFn)
}
//复制选中文字
rmf.copySelect = function () {
navigator.clipboard.writeText(document.getSelection().toString()).then(() => {
Snackbar.show({
text: '已复制选中文字!',
pos: 'top-right',
showAction: false,
});
});
}
//回到顶部
rmf.scrollToTop = function () {
document.getElementsByClassName("menus_items")[1].setAttribute("style", "");
document.getElementById("name-container").setAttribute("style", "display:none");
btf.scrollToDest(0, 500);
}
rmf.translate = function () {
document.getElementById("translateLink").click();
}
rmf.searchinThisPage = () => {
let mask = setMask(); // 确保 mask 元素存在于 document.body 中
document.getElementsByClassName("local-search-box--input")[0].value = window.getSelection().toString();
document.getElementsByClassName("search")[0].click();
var evt = document.createEvent("HTMLEvents");
evt.initEvent("input", false, false);
document.getElementsByClassName("local-search-box--input")[0].dispatchEvent(evt);
// 在尝试移除 mask 元素之前检查它是否存在于 document.body 中
if (document.body.contains(mask)) {
document.body.removeChild(mask);
}
}
document.body.addEventListener('touchmove', function (e) {
}, {passive: false});
function popupMenu() {
//window.oncontextmenu=function(){return false;}
window.oncontextmenu = function (event) {
Snackbar.show({
text: '按住 Ctrl 再点击右键,即可恢复原界面哦',
pos: 'bottom-left',
showAction: false
});
if (event.ctrlKey || document.body.clientWidth < 900) return true;
$('.rightMenu-group.hide').hide();
if (document.getSelection().toString()) {
$('#menu-text').show();
}
if (document.getElementById('post')) {
$('#menu-post').show();
} else {
if (document.getElementById('page')) {
$('#menu-post').show();
}
}
var el = window.document.body;
el = event.target;
var a = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w.-]+)+[\w\-._~:\/?#[\]@!$&'*+,;=]+$/
if (a.test(window.getSelection().toString()) && el.tagName !== "A") {
$('#menu-too').show()
}
if (el.tagName === 'A') {
$('#menu-to').show()
rmf.open = function () {
if (el.href.indexOf("http://") === -1 && el.href.indexOf("https://") === -1 || el.href.indexOf("blog.june-pj.cn") !== -1) {
pjax.loadUrl(el.href)
} else {
location.href = el.href
}
}
rmf.openWithNewTab = function () {
window.open(el.href);
// window.location.reload();
}
rmf.copyLink = function () {
const url = el.href;
navigator.clipboard.writeText(url);
Snackbar.show({
text: '链接复制成功!快去分享吧!',
pos: 'top-right',
showAction: false
});
};
}
if (el.tagName === 'IMG') {
$('#menu-img').show()
rmf.openWithNewTab = function () {
window.open(el.src);
// window.location.reload();
}
rmf.click = function () {
el.click()
}
rmf.copyLink = function () {
const url = el.src
navigator.clipboard.writeText(url);
Snackbar.show({
text: '链接复制成功!快去分享吧!',
pos: 'top-right',
showAction: false
});
}
rmf.saveAs = function () {
var a = document.createElement('a');
a.href = el.src;
// 获取图片的文件名部分
a.download = el.src.split('/').pop(); // 使用图片的文件名作为下载文件名
a.style.display = 'none'; // 隐藏下载链接
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
} else if (el.tagName === "TEXTAREA" || el.tagName === "INPUT") {
$('#menu-paste').show();
// rmf.paste=function(){
// input.addEventListener('paste', async event => {
// event.preventDefault();
// const text = await navigator.clipboard.readText();
// el.value+=text;
// });
// }
rmf.paste = function () {
navigator.permissions
.query({
name: 'clipboard-read'
})
.then(result => {
if (result.state === 'granted' || result.state === 'prompt') {
//读取剪贴板
navigator.clipboard.readText().then(text => {
console.log(text)
insertAtCursor(el, text)
})
} else {
Snackbar.show({
text: '请允许读取剪贴板!',
pos: 'top-center',
showAction: false,
})
}
})
}
}
let pageX = event.clientX + 10;
let pageY = event.clientY;
let rmWidth = $('#rightMenu').width();
let rmHeight = $('#rightMenu').height();
if (pageX + rmWidth > window.innerWidth) {
pageX -= rmWidth + 10;
}
if (pageY + rmHeight > window.innerHeight) {
pageY -= pageY + rmHeight - window.innerHeight;
}
mask = setMask();
window.onscroll = () => {
rmf.showRightMenu(false);
window.onscroll = () => {
}
if (document.body.contains(mask)) {
document.body.removeChild(mask);
}
}
$(".rightMenu-item").click(() => {
if (document.body.contains(mask)) {
document.body.removeChild(mask);
}
});
$(window).resize(() => {
rmf.showRightMenu(false);
if (document.body.contains(mask)) {
document.body.removeChild(mask);
}
});
mask.onclick = () => {
if (document.body.contains(mask)) {
document.body.removeChild(mask);
}
};
rmf.showRightMenu(true, pageY, pageX);
return false;
};
window.addEventListener('click', function () {
rmf.showRightMenu(false);
});
}
if (!(navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
popupMenu()
}
const box = document.documentElement
function addLongtabListener(target, callback) {
let timer = 0 // 初始化timer
target.ontouchstart = () => {
timer = 0 // 重置timer
timer = setTimeout(() => {
callback();
timer = 0
}, 380) // 超时器能成功执行,说明是长按
}
target.ontouchmove = () => {
clearTimeout(timer) // 如果来到这里,说明是滑动
timer = 0
}
target.ontouchend = () => { // 到这里如果timer有值说明此触摸时间不足380ms是点击
if (timer) {
clearTimeout(timer)
}
}
}
addLongtabListener(box, popupMenu)

View File

@@ -0,0 +1,174 @@
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 = () => {
btf.overflowPaddingR.add()
animateElements(true)
setTimeout(() => { document.querySelector('#algolia-search .ais-SearchBox-input').focus() }, 100)
const handleEscape = event => {
if (event.code === 'Escape') {
closeSearch()
document.removeEventListener('keydown', handleEscape)
}
}
document.addEventListener('keydown', handleEscape)
fixSafariHeight()
window.addEventListener('resize', fixSafariHeight)
}
const closeSearch = () => {
btf.overflowPaddingR.remove()
animateElements(false)
window.removeEventListener('resize', fixSafariHeight)
}
const searchClickFn = () => {
btf.addEventListenerPjax(document.querySelector('#search-button > .search'), 'click', openSearch)
}
const searchFnOnce = () => {
$searchMask.addEventListener('click', closeSearch)
document.querySelector('#algolia-search .search-close-button').addEventListener('click', closeSearch)
}
const cutContent = (content) => {
if (!content) return ''
const firstOccur = content.indexOf('<mark>')
let start = firstOccur - 30
let end = firstOccur + 120
let pre = ''
let post = ''
if (start <= 0) {
start = 0
end = 140
} else {
pre = '...'
}
if (end > content.length) {
end = content.length
} else {
post = '...'
}
return `${pre}${content.substring(start, end)}${post}`
}
const disableDiv = [
document.getElementById('algolia-hits'),
document.getElementById('algolia-pagination'),
document.querySelector('#algolia-info .algolia-stats')
]
const searchClient = typeof algoliasearch === 'function' ? algoliasearch : window['algoliasearch/lite'].liteClient
const search = instantsearch({
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 = [
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>`
}
}
}),
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}`
}
}
}),
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', () => {
if (!btf.isHidden($searchMask)) closeSearch()
searchClickFn()
})
if (window.pjax) {
search.on('render', () => {
window.pjax.refresh(document.getElementById('algolia-hits'))
})
}
})

View File

@@ -0,0 +1,360 @@
/**
* Refer to hexo-generator-searchdb
* https://github.com/next-theme/hexo-generator-searchdb/blob/main/dist/search.js
* Modified by hexo-theme-butterfly
*/
class LocalSearch {
constructor ({
path = '',
unescape = false,
top_n_per_article = 1
}) {
this.path = path
this.unescape = unescape
this.top_n_per_article = top_n_per_article
this.isfetched = false
this.datas = null
}
getIndexByWord (words, text, caseSensitive = false) {
const index = []
const included = new Set()
if (!caseSensitive) {
text = text.toLowerCase()
}
words.forEach(word => {
if (this.unescape) {
const div = document.createElement('div')
div.innerText = word
word = div.innerHTML
}
const wordLen = word.length
if (wordLen === 0) return
let startPosition = 0
let position = -1
if (!caseSensitive) {
word = word.toLowerCase()
}
while ((position = text.indexOf(word, startPosition)) > -1) {
index.push({ position, word })
included.add(word)
startPosition = position + wordLen
}
})
// Sort index by position of keyword
index.sort((left, right) => {
if (left.position !== right.position) {
return left.position - right.position
}
return right.word.length - left.word.length
})
return [index, included]
}
// Merge hits into slices
mergeIntoSlice (start, end, index) {
let item = index[0]
let { position, word } = item
const hits = []
const count = new Set()
while (position + word.length <= end && index.length !== 0) {
count.add(word)
hits.push({
position,
length: word.length
})
const wordEnd = position + word.length
// Move to next position of hit
index.shift()
while (index.length !== 0) {
item = index[0]
position = item.position
word = item.word
if (wordEnd > position) {
index.shift()
} else {
break
}
}
}
return {
hits,
start,
end,
count: count.size
}
}
// Highlight title and content
highlightKeyword (val, slice) {
let result = ''
let index = slice.start
for (const { position, length } of slice.hits) {
result += val.substring(index, position)
index = position + length
result += `<mark class="search-keyword">${val.substr(position, length)}</mark>`
}
result += val.substring(index, slice.end)
return result
}
getResultItems (keywords) {
const resultItems = []
this.datas.forEach(({ title, content, url }) => {
// The number of different keywords included in the article.
const [indexOfTitle, keysOfTitle] = this.getIndexByWord(keywords, title)
const [indexOfContent, keysOfContent] = this.getIndexByWord(keywords, content)
const includedCount = new Set([...keysOfTitle, ...keysOfContent]).size
// Show search results
const hitCount = indexOfTitle.length + indexOfContent.length
if (hitCount === 0) return
const slicesOfTitle = []
if (indexOfTitle.length !== 0) {
slicesOfTitle.push(this.mergeIntoSlice(0, title.length, indexOfTitle))
}
let slicesOfContent = []
while (indexOfContent.length !== 0) {
const item = indexOfContent[0]
const { position } = item
// Cut out 120 characters. The maxlength of .search-input is 80.
const start = Math.max(0, position - 20)
const end = Math.min(content.length, position + 100)
slicesOfContent.push(this.mergeIntoSlice(start, end, indexOfContent))
}
// Sort slices in content by included keywords' count and hits' count
slicesOfContent.sort((left, right) => {
if (left.count !== right.count) {
return right.count - left.count
} else if (left.hits.length !== right.hits.length) {
return right.hits.length - left.hits.length
}
return left.start - right.start
})
// Select top N slices in content
const upperBound = parseInt(this.top_n_per_article, 10)
if (upperBound >= 0) {
slicesOfContent = slicesOfContent.slice(0, upperBound)
}
let resultItem = ''
url = new URL(url, location.origin)
url.searchParams.append('highlight', keywords.join(' '))
if (slicesOfTitle.length !== 0) {
resultItem += `<li class="local-search-hit-item"><a href="${url.href}"><span class="search-result-title">${this.highlightKeyword(title, slicesOfTitle[0])}</span>`
} else {
resultItem += `<li class="local-search-hit-item"><a href="${url.href}"><span class="search-result-title">${title}</span>`
}
slicesOfContent.forEach(slice => {
resultItem += `<p class="search-result">${this.highlightKeyword(content, slice)}...</p></a>`
})
resultItem += '</li>'
resultItems.push({
item: resultItem,
id: resultItems.length,
hitCount,
includedCount
})
})
return resultItems
}
fetchData () {
const isXml = !this.path.endsWith('json')
fetch(this.path)
.then(response => response.text())
.then(res => {
// Get the contents from search data
this.isfetched = true
this.datas = isXml
? [...new DOMParser().parseFromString(res, 'text/xml').querySelectorAll('entry')].map(element => ({
title: element.querySelector('title').textContent,
content: element.querySelector('content').textContent,
url: element.querySelector('url').textContent
}))
: JSON.parse(res)
// Only match articles with non-empty titles
this.datas = this.datas.filter(data => data.title).map(data => {
data.title = data.title.trim()
data.content = data.content ? data.content.trim().replace(/<[^>]+>/g, '') : ''
data.url = decodeURIComponent(data.url).replace(/\/{2,}/g, '/')
return data
})
// Remove loading animation
window.dispatchEvent(new Event('search:loaded'))
})
}
// Highlight by wrapping node in mark elements with the given class name
highlightText (node, slice, className) {
const val = node.nodeValue
let index = slice.start
const children = []
for (const { position, length } of slice.hits) {
const text = document.createTextNode(val.substring(index, position))
index = position + length
const mark = document.createElement('mark')
mark.className = className
mark.appendChild(document.createTextNode(val.substr(position, length)))
children.push(text, mark)
}
node.nodeValue = val.substring(index, slice.end)
children.forEach(element => {
node.parentNode.insertBefore(element, node)
})
}
// Highlight the search words provided in the url in the text
highlightSearchWords (body) {
const params = new URL(location.href).searchParams.get('highlight')
const keywords = params ? params.split(' ') : []
if (!keywords.length || !body) return
const walk = document.createTreeWalker(body, NodeFilter.SHOW_TEXT, null)
const allNodes = []
while (walk.nextNode()) {
if (!walk.currentNode.parentNode.matches('button, select, textarea, .mermaid')) allNodes.push(walk.currentNode)
}
allNodes.forEach(node => {
const [indexOfNode] = this.getIndexByWord(keywords, node.nodeValue)
if (!indexOfNode.length) return
const slice = this.mergeIntoSlice(0, node.nodeValue.length, indexOfNode)
this.highlightText(node, slice, 'search-keyword')
})
}
}
window.addEventListener('load', () => {
// Search
const { path, top_n_per_article, unescape, languages } = GLOBAL_CONFIG.localSearch
const localSearch = new LocalSearch({
path,
top_n_per_article,
unescape
})
const input = document.querySelector('#local-search-input input')
const statsItem = document.getElementById('local-search-stats-wrap')
const $loadingStatus = document.getElementById('loading-status')
const isXml = !path.endsWith('json')
const inputEventFunction = () => {
if (!localSearch.isfetched) return
let searchText = input.value.trim().toLowerCase()
isXml && (searchText = searchText.replace(/</g, '&lt;').replace(/>/g, '&gt;'))
if (searchText !== '') $loadingStatus.innerHTML = '<i class="fas fa-spinner fa-pulse"></i>'
const keywords = searchText.split(/[-\s]+/)
const container = document.getElementById('local-search-results')
let resultItems = []
if (searchText.length > 0) {
// Perform local searching
resultItems = localSearch.getResultItems(keywords)
}
if (keywords.length === 1 && keywords[0] === '') {
container.textContent = ''
statsItem.textContent = ''
} else if (resultItems.length === 0) {
container.textContent = ''
const statsDiv = document.createElement('div')
statsDiv.className = 'search-result-stats'
statsDiv.textContent = languages.hits_empty.replace(/\$\{query}/, searchText)
statsItem.innerHTML = statsDiv.outerHTML
} else {
resultItems.sort((left, right) => {
if (left.includedCount !== right.includedCount) {
return right.includedCount - left.includedCount
} else if (left.hitCount !== right.hitCount) {
return right.hitCount - left.hitCount
}
return right.id - left.id
})
const stats = languages.hits_stats.replace(/\$\{hits}/, resultItems.length)
container.innerHTML = `<ol class="search-result-list">${resultItems.map(result => result.item).join('')}</ol>`
statsItem.innerHTML = `<hr><div class="search-result-stats">${stats}</div>`
window.pjax && window.pjax.refresh(container)
}
$loadingStatus.textContent = ''
}
let loadFlag = false
const $searchMask = document.getElementById('search-mask')
const $searchDialog = document.querySelector('#local-search .search-dialog')
// fix safari
const fixSafariHeight = () => {
if (window.innerWidth < 768) {
$searchDialog.style.setProperty('--search-height', window.innerHeight + 'px')
}
}
const openSearch = () => {
btf.overflowPaddingR.add()
btf.animateIn($searchMask, 'to_show 0.5s')
btf.animateIn($searchDialog, 'titleScale 0.5s')
setTimeout(() => { input.focus() }, 300)
if (!loadFlag) {
!localSearch.isfetched && localSearch.fetchData()
input.addEventListener('input', inputEventFunction)
loadFlag = true
}
// shortcut: ESC
document.addEventListener('keydown', function f (event) {
if (event.code === 'Escape') {
closeSearch()
document.removeEventListener('keydown', f)
}
})
fixSafariHeight()
window.addEventListener('resize', fixSafariHeight)
}
const closeSearch = () => {
btf.overflowPaddingR.remove()
btf.animateOut($searchDialog, 'search_close .5s')
btf.animateOut($searchMask, 'to_hide 0.5s')
window.removeEventListener('resize', fixSafariHeight)
}
const searchClickFn = () => {
btf.addEventListenerPjax(document.querySelector('#search-button > .search'), 'click', openSearch)
}
const searchFnOnce = () => {
document.querySelector('#local-search .search-close-button').addEventListener('click', closeSearch)
$searchMask.addEventListener('click', closeSearch)
if (GLOBAL_CONFIG.localSearch.preload) {
localSearch.fetchData()
}
localSearch.highlightSearchWords(document.getElementById('article-container'))
}
window.addEventListener('search:loaded', () => {
const $loadDataItem = document.getElementById('loading-database')
$loadDataItem.nextElementSibling.style.display = 'block'
$loadDataItem.remove()
})
searchClickFn()
searchFnOnce()
// pjax
window.addEventListener('pjax:complete', () => {
!btf.isHidden($searchMask) && closeSearch()
localSearch.highlightSearchWords(document.getElementById('article-container'))
searchClickFn()
})
})

View File

@@ -0,0 +1,415 @@
function renderTalks() {
const talkContainer = document.querySelector('#talk');
const domain = 'https://mm.biss.click';
if (!talkContainer) return;
talkContainer.innerHTML = '';
const generateIconSVG = () => {
return `<svg viewBox="0 0 512 512"xmlns="http://www.w3.org/2000/svg"class="is-badge icon"><path d="m512 268c0 17.9-4.3 34.5-12.9 49.7s-20.1 27.1-34.6 35.4c.4 2.7.6 6.9.6 12.6 0 27.1-9.1 50.1-27.1 69.1-18.1 19.1-39.9 28.6-65.4 28.6-11.4 0-22.3-2.1-32.6-6.3-8 16.4-19.5 29.6-34.6 39.7-15 10.2-31.5 15.2-49.4 15.2-18.3 0-34.9-4.9-49.7-14.9-14.9-9.9-26.3-23.2-34.3-40-10.3 4.2-21.1 6.3-32.6 6.3-25.5 0-47.4-9.5-65.7-28.6-18.3-19-27.4-42.1-27.4-69.1 0-3 .4-7.2 1.1-12.6-14.5-8.4-26-20.2-34.6-35.4-8.5-15.2-12.8-31.8-12.8-49.7 0-19 4.8-36.5 14.3-52.3s22.3-27.5 38.3-35.1c-4.2-11.4-6.3-22.9-6.3-34.3 0-27 9.1-50.1 27.4-69.1s40.2-28.6 65.7-28.6c11.4 0 22.3 2.1 32.6 6.3 8-16.4 19.5-29.6 34.6-39.7 15-10.1 31.5-15.2 49.4-15.2s34.4 5.1 49.4 15.1c15 10.1 26.6 23.3 34.6 39.7 10.3-4.2 21.1-6.3 32.6-6.3 25.5 0 47.3 9.5 65.4 28.6s27.1 42.1 27.1 69.1c0 12.6-1.9 24-5.7 34.3 16 7.6 28.8 19.3 38.3 35.1 9.5 15.9 14.3 33.4 14.3 52.4zm-266.9 77.1 105.7-158.3c2.7-4.2 3.5-8.8 2.6-13.7-1-4.9-3.5-8.8-7.7-11.4-4.2-2.7-8.8-3.6-13.7-2.9-5 .8-9 3.2-12 7.4l-93.1 140-42.9-42.8c-3.8-3.8-8.2-5.6-13.1-5.4-5 .2-9.3 2-13.1 5.4-3.4 3.4-5.1 7.7-5.1 12.9 0 5.1 1.7 9.4 5.1 12.9l58.9 58.9 2.9 2.3c3.4 2.3 6.9 3.4 10.3 3.4 6.7-.1 11.8-2.9 15.2-8.7z"fill="#1da1f2"></path></svg>`;
}
const waterfall = (a) => {
function b(a, b) {
var c = window.getComputedStyle(b);
return parseFloat(c["margin" + a]) || 0
}
function c(a) {
return a + "px"
}
function d(a) {
return parseFloat(a.style.top)
}
function e(a) {
return parseFloat(a.style.left)
}
function f(a) {
return a.clientWidth
}
function g(a) {
return a.clientHeight
}
function h(a) {
return d(a) + g(a) + b("Bottom", a)
}
function i(a) {
return e(a) + f(a) + b("Right", a)
}
function j(a) {
a = a.sort(function (a, b) {
return h(a) === h(b) ? e(b) - e(a) : h(b) - h(a)
})
}
function k(b) {
f(a) != t && (b.target.removeEventListener(b.type, arguments.callee), waterfall(a))
}
"string" == typeof a && (a = document.querySelector(a));
var l = [].map.call(a.children, function (a) {
return a.style.position = "absolute", a
});
a.style.position = "relative";
var m = [];
l.length && (l[0].style.top = "0px", l[0].style.left = c(b("Left", l[0])), m.push(l[0]));
for (var n = 1; n < l.length; n++) {
var o = l[n - 1],
p = l[n],
q = i(o) + f(p) <= f(a);
if (!q) break;
p.style.top = o.style.top, p.style.left = c(i(o) + b("Left", p)), m.push(p)
}
for (; n < l.length; n++) {
j(m);
var p = l[n],
r = m.pop();
p.style.top = c(h(r) + b("Top", p)), p.style.left = c(e(r)), m.push(p)
}
j(m);
var s = m[0];
a.style.height = c(h(s) + b("Bottom", s));
var t = f(a);
window.addEventListener ? window.addEventListener("resize", k) : document.body.onresize = k
};
const fetchAndRenderTalks = () => {
const url = 'https://mm.biss.click/api/memo/list';
const cacheKey = 'talksCache';
const cacheTimeKey = 'talksCacheTime';
const cacheDuration = 30 * 60 * 1000; // 半个小时 (30 分钟)
const cachedData = localStorage.getItem(cacheKey);
const cachedTime = localStorage.getItem(cacheTimeKey);
const currentTime = new Date().getTime();
// 判断缓存是否有效
if (cachedData && cachedTime && (currentTime - cachedTime < cacheDuration)) {
const data = JSON.parse(cachedData);
renderTalks(data); // 使用缓存渲染数据
} else {
if (talkContainer) {
talkContainer.innerHTML = '';
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
size: 30
})
})
.then(res => res.json())
.then(data => {
if (data.code === 0 && data.data && Array.isArray(data.data.list)) {
// 缓存数据
localStorage.setItem(cacheKey, JSON.stringify(data.data.list));
localStorage.setItem(cacheTimeKey, currentTime.toString());
renderTalks(data.data.list); // 渲染数据
}
})
.catch(error => {
console.error('Error fetching data:', error);
});
}
}
// 渲染函数
function renderTalks(list) {
// 确保 data 是一个数组
if (Array.isArray(list)) {
let items = list.map(item => formatTalk(item, url));
items.forEach(item => talkContainer.appendChild(generateTalkElement(item)));
waterfall('#talk');
} else {
console.error('Data is not an array:', list);
}
}
};
const formatTalk = (item, url) => {
let date = formatTime(new Date(item.createdAt).toString());
let content = item.content;
let imgs = item.imgs ? item.imgs.split(',') : [];
let text = content;
content = text.replace(/\[(.*?)\]\((.*?)\)/g, `<a href="$2">@$1</a>`)
.replace(/- \[ \]/g, '⚪')
.replace(/- \[x\]/g, '⚫');
// 保留换行符,转换 \n 为 <br>
content = content.replace(/\n/g, '<br>');
// 将content用一个类包裹便于后续处理
content = `<div class="talk_content_text">${content}</div>`;
if (imgs.length > 0) {
const imgDiv = document.createElement('div');
imgDiv.className = 'zone_imgbox';
imgs.forEach(e => {
const imgLink = document.createElement('a');
const imgUrl = domain + e;
imgLink.href = imgUrl;
imgLink.setAttribute('data-fancybox', 'gallery');
imgLink.className = 'fancybox';
imgLink.setAttribute('data-thumb', e);
const imgTag = document.createElement('img');
imgTag.src = domain + e;
imgLink.appendChild(imgTag);
imgDiv.appendChild(imgLink);
});
content += imgDiv.outerHTML;
}
// 外链分享功能
if (item.externalUrl) {
const externalUrl = item.externalUrl;
const externalTitle = item.externalTitle;
const externalFavicon = item.externalFavicon;
const externalContainer = `
<div class="shuoshuo-external-link">
<a class="external-link" href="${externalUrl}" target="_blank" rel="external nofollow noopener noreferrer">
<div class="external-link-left" style="background-image: url(${externalFavicon})"></div>
<div class="external-link-right">
<div class="external-link-title">${externalTitle}</div>
<div>点击跳转<i class="fa-solid fa-angle-right"></i></div>
</div>
</a>
</div>`;
content += externalContainer;
}
const ext = JSON.parse(item.ext || '{}');
if (ext.music && ext.music.id) {
const music = ext.music;
const musicUrl = music.api.replace(':server', music.server)
.replace(':type', music.type)
.replace(':id', music.id);
content += `
<meting-js server="${music.server}" type="${music.type}" id="${music.id}" api="${music.api}"></meting-js>
`;
}
if (ext.doubanMovie && ext.doubanMovie.id) {
const doubanMovie = ext.doubanMovie;
const doubanMovieUrl = doubanMovie.url;
const doubanTitle = doubanMovie.title;
// const doubanDesc = doubanMovie.desc || '暂无描述';
const doubanImage = doubanMovie.image;
const doubanDirector = doubanMovie.director || '未知导演';
const doubanRating = doubanMovie.rating || '暂无评分';
// const doubanReleaseDate = doubanMovie.releaseDate || '未知上映时间';
// const doubanActors = doubanMovie.actors || '未知演员';
const doubanRuntime = doubanMovie.runtime || '未知时长';
content += `
<a class="douban-card" href="${doubanMovieUrl}" target="_blank">
<div class="douban-card-bgimg" style="background-image: url('${doubanImage}');"></div>
<div class="douban-card-left">
<div class="douban-card-img" style="background-image: url('${doubanImage}');"></div>
</div>
<div class="douban-card-right">
<div class="douban-card-item"><span>电影名: </span><strong>${doubanTitle}</strong></div>
<div class="douban-card-item"><span>导演: </span><span>${doubanDirector}</span></div>
<div class="douban-card-item"><span>评分: </span><span>${doubanRating}</span></div>
<div class="douban-card-item"><span>时长: </span><span>${doubanRuntime}</span></div>
</div>
</a>
`;
}
if (ext.doubanBook && ext.doubanBook.id) {
const doubanBook = ext.doubanBook;
const bookUrl = doubanBook.url;
const bookTitle = doubanBook.title;
// const bookDesc = doubanBook.desc;
const bookImage = doubanBook.image;
const bookAuthor = doubanBook.author;
const bookRating = doubanBook.rating;
const bookPubDate = doubanBook.pubDate;
const bookTemplate = `
<a class="douban-card" href="${bookUrl}" target="_blank">
<div class="douban-card-bgimg" style="background-image: url('${bookImage}');"></div>
<div class="douban-card-left">
<div class="douban-card-img" style="background-image: url('${bookImage}');"></div>
</div>
<div class="douban-card-right">
<div class="douban-card-item">
<span>书名: </span><strong>${bookTitle}</strong>
</div>
<div class="douban-card-item">
<span>作者: </span><span>${bookAuthor}</span>
</div>
<div class="douban-card-item">
<span>出版年份: </span><span>${bookPubDate}</span>
</div>
<div class="douban-card-item">
<span>评分: </span><span>${bookRating}</span>
</div>
</div>
</a>
`;
content += bookTemplate;
}
if (ext.video && ext.video.type) {
const videoType = ext.video.type;
const videoUrl = ext.video.value;
if (videoType === 'bilibili') {
// Bilibili 视频模板
// 从形如https://www.bilibili.com/video/BV1VGAPeAEMQ/?vd_source=91b3158d27d98ff41f842508c3794a13 的链接中提取视频 BV1VGAPeAEMQ
const biliTemplate = `
<div style="position: relative; padding: 30% 45%; margin-top: 10px;">
<iframe
style="position: absolute; width: 100%; height: 100%; left: 0; top: 0; border-radius: 12px;"
src="${videoUrl}&autoplay=0"
scrolling="no"
frameborder="no"
allowfullscreen>
</iframe>
</div>
`;
// 将模板插入到 DOM 中
content += biliTemplate;
} else if (videoType === 'youtube') {
// YouTube 视频模板
// 从形如https://youtu.be/2V6lvCUPT8I?si=DVhUas6l6qlAr6Ru的链接中提取视频 ID2V6lvCUPT8I
const youtubeTemplate = `
<div style="position: relative; padding: 30% 45%; margin-top: 10px;">
<iframe width="100%"
style="position: absolute; width: 100%; height: 100%; left: 0; top: 0; border-radius: 12px;"
src="${videoUrl}"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen>
</iframe>
</div>
`;
// 将模板插入到 DOM 中
content += youtubeTemplate;
}
}
return {
content: content,
user: item.user.nickname || '匿名',
avatar: item.user.avatarUrl || 'https://p.liiiu.cn/i/2024/03/29/66061417537af.png',
date: date,
location: item.location || '山西',
tags: item.tags ? item.tags.split(',').filter(tag => tag.trim() !== '') : ['无标签'],
text: content.replace(/\[(.*?)\]\((.*?)\)/g, '[链接]' + `${imgs.length ? '[图片]' : ''}`)
};
};
const generateTalkElement = (item) => {
const talkItem = document.createElement('div');
talkItem.className = 'talk_item';
const talkMeta = document.createElement('div');
talkMeta.className = 'talk_meta';
const avatar = document.createElement('img');
avatar.className = 'no-lightbox avatar';
avatar.src = item.avatar;
const info = document.createElement('div');
info.className = 'info';
const talkNick = document.createElement('span');
talkNick.className = 'talk_nick';
talkNick.innerHTML = `${item.user} ${generateIconSVG()}`;
const talkDate = document.createElement('span');
talkDate.className = 'talk_date';
talkDate.textContent = item.date;
const talkContent = document.createElement('div');
talkContent.className = 'talk_content';
talkContent.innerHTML = item.content;
const talkBottom = document.createElement('div');
talkBottom.className = 'talk_bottom';
const TagContainer = document.createElement('div');
const talkTag = document.createElement('span');
talkTag.className = 'talk_tag';
talkTag.textContent = `🏷️${item.tags}`;
const locationTag = document.createElement('span');
locationTag.className = 'location_tag';
locationTag.textContent = `🌍${item.location}`;
TagContainer.appendChild(talkTag);
TagContainer.appendChild(locationTag);
const commentLink = document.createElement('a');
commentLink.href = 'javascript:;';
commentLink.onclick = () => goComment(item.text);
const commentIcon = document.createElement('span');
commentIcon.className = 'icon';
const commentIconInner = document.createElement('i');
commentIconInner.className = 'fa-solid fa-message fa-fw';
commentIcon.appendChild(commentIconInner);
commentLink.appendChild(commentIcon);
talkMeta.appendChild(avatar);
info.appendChild(talkNick);
info.appendChild(talkDate);
talkMeta.appendChild(info);
talkItem.appendChild(talkMeta);
talkItem.appendChild(talkContent);
talkBottom.appendChild(TagContainer);
talkBottom.appendChild(commentLink);
talkItem.appendChild(talkBottom);
return talkItem;
};
const goComment = (e) => {
const match = e.match(/<div class="talk_content_text">([\s\S]*?)<\/div>/);
const textContent = match ? match[1] : "";
const n = document.querySelector(".atk-textarea");
n.value = `> ${textContent}\n\n`;
n.focus();
btf.snackbarShow("已为您引用该说说,不删除空格效果更佳");
// const n = document.querySelector(".atk-textarea");
// n.value = `> ${e}\n\n`;
// n.focus();
// btf.snackbarShow("已为您引用该说说,不删除空格效果更佳");
};
const formatTime = (time) => {
const d = new Date(time);
const ls = [
d.getFullYear(),
d.getMonth() + 1,
d.getDate(),
d.getHours(),
d.getMinutes(),
d.getSeconds(),
];
const r = ls.map((a) => (a.toString().length === 1 ? '0' + a : a));
return `${r[0]}-${r[1]}-${r[2]} ${r[3]}:${r[4]}`;
};
fetchAndRenderTalks();
}
renderTalks();
// function whenDOMReady() {
// const talkContainer = document.querySelector('#talk');
// talkContainer.innerHTML = '';
// fetchAndRenderTalks();
// }
// whenDOMReady();
// document.addEventListener("pjax:complete", whenDOMReady);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,668 @@
//get请求
$.ajax({
type: 'get',
url: 'https://apis.map.qq.com/ws/location/v1/ip',
data: {
key: 'JOCBZ-5FCRV-CWTP7-5HXTF-OODC2-2PF6R',
output: 'jsonp',
callback: '?',
},
dataType: 'jsonp',
success: function (res) {
window.ipLocation = res;
}
})
function getDistance(e1, n1, e2, n2) {
const R = 6371
const { sin, cos, asin, PI, hypot } = Math
let getPoint = (e, n) => {
e *= PI / 180
n *= PI / 180
return { x: cos(n) * cos(e), y: cos(n) * sin(e), z: sin(n) }
}
let a = getPoint(e1, n1)
let b = getPoint(e2, n2)
let c = hypot(a.x - b.x, a.y - b.y, a.z - b.z)
let r = asin(c / 2) * 2 * R
return Math.round(r);
}
function showWelcome() {
let dist = getDistance(112.92358, 35.79807, ipLocation.result.location.lng, ipLocation.result.location.lat); //这里记得换成自己的经纬度
let pos = ipLocation.result.ad_info.nation;
let ip;
let posdesc;
//根据国家、省份、城市信息自定义欢迎语
switch (ipLocation.result.ad_info.nation) {
case "日本":
posdesc = "よろしく,一起去看樱花吗";
break;
case "美国":
posdesc = "Let us live in peace!";
break;
case "英国":
posdesc = "想同你一起夜乘伦敦眼";
break;
case "俄罗斯":
posdesc = "干了这瓶伏特加!";
break;
case "法国":
posdesc = "C'est La Vie";
break;
case "德国":
posdesc = "Die Zeit verging im Fluge.";
break;
case "澳大利亚":
posdesc = "一起去大堡礁吧!";
break;
case "加拿大":
posdesc = "拾起一片枫叶赠予你";
break;
case "中国":
pos = ipLocation.result.ad_info.province + " " + ipLocation.result.ad_info.city + " " + ipLocation.result.ad_info.district;
ip = ipLocation.result.ip;
switch (ipLocation.result.ad_info.province) {
/* 4 直辖市 */
case "北京市":
posdesc = "北——京——欢迎你~~~";
break;
case "天津市":
posdesc = "讲段相声吧";
break;
case "上海市":
posdesc = "众所周知,中国只有两个城市";
break;
case "重庆市":
posdesc = "8D魔幻城市导航听了都摇头";
break;
/* 河北 */
case "河北省":
switch (ipLocation.result.ad_info.city) {
case "石家庄市": posdesc = "正宗安徽牛肉板面发源地!"; break;
case "唐山市": posdesc = "烧烤配麻糖,工业风拿捏了"; break;
case "秦皇岛市": posdesc = "阿那亚的孤独图书馆,假装在圣托里尼"; break;
case "邯郸市": posdesc = "学步桥警告:别邯郸学步嗷"; break;
case "邢台市": posdesc = "太行山最绿的地儿,懂行的都去天河山"; break;
case "保定市": posdesc = "驴火宇宙中心,加焖子才够味"; break;
case "张家口市": posdesc = "崇礼滑雪,冬天也要整点‘雪’业"; break;
case "承德市": posdesc = "避暑山庄:皇上都说凉快"; break;
case "沧州市": posdesc = "武术之乡,八极拳申请出战"; break;
case "廊坊市": posdesc = "北京的后花园,通勤两小时"; break;
case "衡水市": posdesc = "衡水老白干,一杯就上头"; break;
default: posdesc = "山势巍巍成壁垒,天下雄关铁马金戈由此向,无限江山";
}
break;
/* 山西 */
case "山西省":
switch (ipLocation.result.ad_info.city) {
case "太原市": posdesc = "秋叶蓝不城"; break;
case "大同市": posdesc = "刀削面配兔头,碳水快乐星球"; break;
case "阳泉市": posdesc = "刘慈欣老家,三体人从这儿起飞"; break;
case "长治市": posdesc = "上党从来天下脊,撸串配潞酒"; break;
case "晋城市": posdesc = "一方水土养一方人,晋城话说给晋城人..."; break;
case "朔州市": posdesc = "右玉羊肉,吃草羊的天花板"; break;
case "晋中市": posdesc = "平遥古城拍拍照,晋商票号走一遭"; break;
case "运城市": posdesc = "关公老家,天天‘义’起来"; break;
case "忻州市": posdesc = "五台山拜佛,顺便许个愿"; break;
case "临汾市": posdesc = "洪洞大槐树,寻根问祖集中地"; break;
case "吕梁市": posdesc = "杏花村汾酒,喝出魏晋风骨"; break;
default: posdesc = "展开坐具长三尺,已占山河五百余";
}
break;
/* 内蒙古 */
case "内蒙古自治区":
switch (ipLocation.result.ad_info.city) {
case "呼和浩特市": posdesc = "来碗羊杂碎,草原的早晨醒啦"; break;
case "包头市": posdesc = "稀土之都,钢铁侠看了都眼馋"; break;
case "乌海市": posdesc = "沙漠里看海,赛博朋克即视感"; break;
case "赤峰市": posdesc = "对夹夹一切,赤峰人的汉堡"; break;
case "通辽市": posdesc = "科尔沁风干牛肉,越嚼越上头"; break;
case "鄂尔多斯市": posdesc = "羊绒衫暖和,土豪也多"; break;
case "呼伦贝尔市": posdesc = "大草原配套马杆,汉子诚不欺我"; break;
case "巴彦淖尔市": posdesc = "河套面粉,馒头好吃到哭"; break;
case "乌兰察布市": posdesc = "土豆开会,薯条自由"; break;
case "兴安盟": posdesc = "阿尔山秋景,美到内存爆炸"; break;
case "锡林郭勒盟": posdesc = "羊肉届鄙视链顶端"; break;
case "阿拉善盟": posdesc = "左手沙漠右手胡杨YYDS"; break;
default: posdesc = "天苍苍,野茫茫,风吹草低见牛羊";
}
break;
/* 辽宁 */
case "辽宁省":
switch (ipLocation.result.ad_info.city) {
case "沈阳市": posdesc = "鸡架老雪花,沈阳人的快乐水"; break;
case "大连市": posdesc = "浪漫之都,海鲜吃到扶墙"; break;
case "鞍山市": posdesc = "鞍钢硬朗,千山更硬朗"; break;
case "抚顺市": posdesc = "煤都往事,麻辣拌续命"; break;
case "本溪市": posdesc = "本溪水洞,东北地下艺术宫殿"; break;
case "丹东市": posdesc = "草莓超大颗,对岸就是朝鲜"; break;
case "锦州市": posdesc = "锦州烧烤,小串卷一切"; break;
case "营口市": posdesc = "东北小三亚,鲅鱼圈冲鸭"; break;
case "阜新市": posdesc = "玛瑙之都,剁手也要买"; break;
case "辽阳市": posdesc = "白塔青年,古城也很潮"; break;
case "盘锦市": posdesc = "蟹稻共生盘锦螃蟹YYDS"; break;
case "铁岭市": posdesc = "宇宙的尽头,李雪琴盖章"; break;
case "朝阳市": posdesc = "古生物化石,恐龙看了都点赞"; break;
case "葫芦岛市": posdesc = "兴城海滨,东北人自己的马尔代夫"; break;
default: posdesc = "我想吃烤鸡架!";
}
break;
/* 吉林 */
case "吉林省":
switch (ipLocation.result.ad_info.city) {
case "长春市": posdesc = "汽车之城东北F4老大"; break;
case "吉林市": posdesc = "雾凇奇观,冬日限定皮肤"; break;
case "四平市": posdesc = "李连贵熏肉大饼,碳水+脂肪的双重暴击"; break;
case "辽源市": posdesc = "袜子走天下,辽源制造"; break;
case "通化市": posdesc = "葡萄酒之乡,干杯老铁"; break;
case "白山市": posdesc = "长白山天池,水怪等你合影"; break;
case "松原市": posdesc = "查干湖冬捕,一网几十万斤"; break;
case "白城市": posdesc = "向海鹤舞丹顶鹤的T台"; break;
case "延边州": posdesc = "朝鲜族美食宇宙中心,冷面泡菜的快乐老家"; break;
default: posdesc = "状元阁就是东北烧烤之王";
}
break;
/* 黑龙江 */
case "黑龙江省":
switch (ipLocation.result.ad_info.city) {
case "哈尔滨市": posdesc = "中央大街走一走,俄式风情拿捏"; break;
case "齐齐哈尔市": posdesc = "BBQ烤肉配鹤舞真·鹤城"; break;
case "鸡西市": posdesc = "刀削面加辣,鸡西人的乡愁"; break;
case "鹤岗市": posdesc = "房价白菜,躺平圣地"; break;
case "双鸭山市": posdesc = "宝清大白板,瓜子界天花板"; break;
case "大庆市": posdesc = "铁人精神+坑烤,香到犯规"; break;
case "伊春市": posdesc = "林都氧吧,每一口都是洗肺"; break;
case "佳木斯市": posdesc = "蔓越莓老家,洋气得很"; break;
case "七台河市": posdesc = "短道速滑冠军制造机"; break;
case "牡丹江市": posdesc = "镜泊湖跳水,瀑布下饺子"; break;
case "黑河市": posdesc = "早市买大列巴,对岸俄国即视感"; break;
case "绥化市": posdesc = "寒地黑土,东北粮仓"; break;
case "大兴安岭地区": posdesc = "找北请到漠河,泼水成冰"; break;
default: posdesc = "很喜欢哈尔滨大剧院";
}
break;
/* 江苏 */
case "江苏省":
switch (ipLocation.result.ad_info.city) {
case "南京市": posdesc = "这是我挺想去的城市啦"; break;
case "无锡市": posdesc = "太湖明珠,酱排骨甜到心坎"; break;
case "徐州市": posdesc = "地锅鸡+烧烤,苏北硬核碳水"; break;
case "常州市": posdesc = "恐龙园冲鸭,暴龙陪你自拍"; break;
case "苏州市": posdesc = "上有天堂,下有苏杭"; break;
case "南通市": posdesc = "教育卷王,学霸生产线"; break;
case "连云港市": posdesc = "花果山见猴哥,连岛看海"; break;
case "淮安市": posdesc = "世界美食之都,盱眙龙虾冲"; break;
case "盐城市": posdesc = "丹顶鹤与麋鹿的双厨狂喜"; break;
case "扬州市": posdesc = "早上皮包水,晚上水包皮"; break;
case "镇江市": posdesc = "香醋摆不坏,肴肉不当菜"; break;
case "泰州市": posdesc = "早茶三巨头,烫干丝安排"; break;
case "宿迁市": posdesc = "刘强东老家,客服之都"; break;
default: posdesc = "散装是必须要散装的";
}
break;
/* 浙江 */
case "浙江省":
switch (ipLocation.result.ad_info.city) {
case "杭州市": posdesc = "西湖醋鱼警告,不好吃别打我"; break;
case "宁波市": posdesc = "汤圆加海鲜,甜咸永动机"; break;
case "温州市": posdesc = "江南皮革厂回归,老板没跑"; break;
case "嘉兴市": posdesc = "粽子宇宙中心肉粽yyds"; break;
case "湖州市": posdesc = "安吉白茶配太湖蟹,双倍快乐"; break;
case "绍兴市": posdesc = "孔乙己的茴香豆,加酒不加水"; break;
case "金华市": posdesc = "义乌小商品,买全球卖全球"; break;
case "衢州市": posdesc = "三头一掌,辣到灵魂出窍"; break;
case "舟山市": posdesc = "东海小黄鱼,鲜到眉毛掉"; break;
case "台州市": posdesc = "糯叽叽嵌糕,台州人的汉堡"; break;
case "丽水市": posdesc = "云和梯田,摄影佬的卷王"; break;
default: posdesc = "东风渐绿西湖柳,雁已还人未南归";
}
break;
/* 安徽 */
case "安徽省":
switch (ipLocation.result.ad_info.city) {
case "合肥市": posdesc = "风投之城,赌出来的霸都"; break;
case "芜湖市": posdesc = "芜湖起飞,起飞~"; break;
case "蚌埠市": posdesc = "蚌埠住了,真的住了"; break;
case "淮南市": posdesc = "牛肉汤+烧饼,淮南人的早晨"; break;
case "马鞍山市": posdesc = "因钢设市,李白终老于此"; break;
case "淮北市": posdesc = "口子窖,喝出安徽的烈"; break;
case "铜陵市": posdesc = "铜都,铜臭味儿香得很"; break;
case "安庆市": posdesc = "黄梅戏一开嗓,谁不说家乡好"; break;
case "黄山市": posdesc = "迎客松打卡,腿已断"; break;
case "滁州市": posdesc = "琅琊山醉翁亭,欧阳修都说赞"; break;
case "阜阳市": posdesc = "格拉条界的天花板,碳水炸弹"; break;
case "宿州市": posdesc = "砀山梨,一口下去全是汁"; break;
case "六安市": posdesc = "六安瓜片,茶香飘出皖西"; break;
case "亳州市": posdesc = "华佗故里,药材香飘全国"; break;
case "池州市": posdesc = "九华山许愿,佛系青年集合"; break;
case "宣城市": posdesc = "文房四宝之乡,笔墨纸砚管够"; break;
default: posdesc = "蚌埠住了,芜湖起飞";
}
break;
/* 福建 */
case "福建省":
switch (ipLocation.result.ad_info.city) {
case "福州市": posdesc = "佛跳墙警告,香到隔壁台湾"; break;
case "厦门市": posdesc = "鼓浪屿挤爆,网红拍照机位排队"; break;
case "莆田市": posdesc = "假鞋之都,真香定律"; break;
case "三明市": posdesc = "沙县小吃出三明,全球开店"; break;
case "泉州市": posdesc = "宋元东方第一大港,蟳蜅女簪花围"; break;
case "漳州市": posdesc = "四果汤+卤面,闽南胃的天堂"; break;
case "南平市": posdesc = "武夷山岩茶,一泡就破产"; break;
case "龙岩市": posdesc = "客家土楼,大鱼海棠取景地"; break;
case "宁德市": posdesc = "霞浦滩涂,摄影佬的卷王"; break;
default: posdesc = "井邑白云间,岩城远带山";
}
break;
/* 江西 */
case "江西省":
switch (ipLocation.result.ad_info.city) {
case "南昌市": posdesc = "拌粉+瓦罐汤,南昌人的早晨"; break;
case "景德镇市": posdesc = "千年瓷都,买瓷器按斤称"; break;
case "萍乡市": posdesc = "武功山金顶,云海配帐篷"; break;
case "九江市": posdesc = "庐山恋,爱情开始的地方"; break;
case "新余市": posdesc = "钢铁之城,仙女湖许愿"; break;
case "鹰潭市": posdesc = "龙虎山天师府,道家仙气"; break;
case "赣州市": posdesc = "脐橙管饱,客家围屋走一圈"; break;
case "吉安市": posdesc = "井冈山红色之旅,星星之火"; break;
case "宜春市": posdesc = "月亮之都,温汤富硒"; break;
case "抚州市": posdesc = "才子之乡,王安石汤显祖"; break;
case "上饶市": posdesc = "婺源油菜花,摄影内存告急"; break;
default: posdesc = "落霞与孤鹜齐飞,秋水共长天一色";
}
break;
/* 山东 */
case "山东省":
switch (ipLocation.result.ad_info.city) {
case "济南市": posdesc = "大明湖夏雨荷,你还记得吗"; break;
case "青岛市": posdesc = "哈啤酒吃嘎啦,塑料袋打酒"; break;
case "淄博市": posdesc = "烧烤三件套,灵魂蘸料"; break;
case "枣庄市": posdesc = "台儿庄古城,辣子鸡真香"; break;
case "东营市": posdesc = "黄河入海口,看鸳鸯锅"; break;
case "烟台市": posdesc = "张裕葡萄酒,微醺在海边"; break;
case "潍坊市": posdesc = "风筝之都,天上全是佩奇"; break;
case "济宁市": posdesc = "曲阜三孔,拜见孔夫子"; break;
case "泰安市": posdesc = "泰山十八盘,腿抖到明年"; break;
case "威海市": posdesc = "干净到反光,韩餐便宜哭"; break;
case "日照市": posdesc = "日出先照,海鲜吃到撑"; break;
case "临沂市": posdesc = "物流之都,煎饼卷宇宙"; break;
case "德州市": posdesc = "德州扒鸡,高铁必带"; break;
case "聊城市": posdesc = "东昌湖配阿胶,补血又浪漫"; break;
case "滨州市": posdesc = "沾化冬枣,甜过初恋"; break;
case "菏泽市": posdesc = "牡丹甲天下,曹州烧饼酥掉渣"; break;
default: posdesc = "遥望齐州九点烟,一泓海水杯中泻";
}
break;
/* 河南 */
case "河南省":
switch (ipLocation.result.ad_info.city) {
case "郑州市": posdesc = "豫州之域,天地之中"; break;
case "开封市": posdesc = "刚正不阿包青天"; break;
case "洛阳市": posdesc = "洛阳牡丹甲天下"; break;
case "平顶山市": posdesc = "中原大佛,抬头颈椎病好了"; break;
case "安阳市": posdesc = "甲骨文老家,文字博物馆走起"; break;
case "鹤壁市": posdesc = "朝歌夜弦,封神榜起源"; break;
case "新乡市": posdesc = "比干庙打卡忠臣Buff"; break;
case "焦作市": posdesc = "云台山瀑布,飞流直下三千尺"; break;
case "濮阳市": posdesc = "中华龙乡,杂技之乡"; break;
case "许昌市": posdesc = "曹魏故都,胖东来逛断腿"; break;
case "漯河市": posdesc = "卫龙辣条,童年回忆杀"; break;
case "三门峡市": posdesc = "天鹅之城,黄河第一坝"; break;
case "南阳市": posdesc = "臣本布衣,躬耕于南阳此南阳非彼南阳!"; break;
case "商丘市": posdesc = "火文化起源,燧人氏钻木取火"; break;
case "信阳市": posdesc = "毛尖茶香,热干面河南分面"; break;
case "周口市": posdesc = "老子故里,胡辣汤配油条"; break;
case "驻马店市": posdesc = "峰峰有奇石,石石挟仙气嵖岈山的花很美哦!"; break;
case "济源市": posdesc = "愚公移山,山还在人已富"; break;
default: posdesc = "可否带我品尝河南烩面啦?";
}
break;
/* 湖北 */
case "湖北省":
switch (ipLocation.result.ad_info.city) {
case "武汉市": posdesc = "热干面配豆皮,过早天堂"; break;
case "黄石市": posdesc = "矿冶古都,仙岛湖打卡"; break;
case "十堰市": posdesc = "武当山修仙,问道金顶"; break;
case "宜昌市": posdesc = "三峡大坝,国之重器"; break;
case "襄阳市": posdesc = "郭靖守过的城,牛肉面管饱"; break;
case "鄂州市": posdesc = "武昌鱼原产地,真香警告"; break;
case "荆门市": posdesc = "明显陵+漳河鱼,历史与美食"; break;
case "孝感市": posdesc = "麻糖米酒,孝感人自带甜味"; break;
case "荆州市": posdesc = "荆州古城,关羽大意失荆州"; break;
case "黄冈市": posdesc = "红安将军县!辈出将才!"; break;
case "咸宁市": posdesc = "温泉泡到爽,桂花糕管够"; break;
case "随州市": posdesc = "炎帝故里,编钟一响谁与争锋"; break;
case "恩施州": posdesc = "恩施大峡谷,一炷香镇楼"; break;
case "仙桃市": posdesc = "体操之乡,李小双李大双"; break;
case "潜江市": posdesc = "油焖大虾,夜宵霸主"; break;
case "天门市": posdesc = "蒸菜三蒸,香到邻居敲门"; break;
case "神农架林区": posdesc = "野人出没,注意熊出没"; break;
default: posdesc = "来碗热干面~";
}
break;
/* 湖南 */
case "湖南省":
switch (ipLocation.result.ad_info.city) {
case "长沙市": posdesc = "74751长沙斯塔克"; break;
case "株洲市": posdesc = "火车拖来的城市,湘菜也硬核"; break;
case "湘潭市": posdesc = "毛氏红烧肉,伟人同款"; break;
case "衡阳市": posdesc = "南岳衡山,寿比南山"; break;
case "邵阳市": posdesc = "邵阳米粉,辣到灵魂出窍"; break;
case "岳阳市": posdesc = "岳阳楼记,先天下之忧而忧"; break;
case "常德市": posdesc = "常德牛肉粉,嗦粉人集合"; break;
case "张家界市": posdesc = "阿凡达取景地,悬浮山真香"; break;
case "益阳市": posdesc = "安化黑茶,越陈越香"; break;
case "郴州市": posdesc = "雾漫小东江,摄影佬天堂"; break;
case "永州市": posdesc = "柳宗元打call永州之野产异蛇"; break;
case "怀化市": posdesc = "芷江受降坊,历史不能忘"; break;
case "娄底市": posdesc = "蚩尤故里,梅山文化"; break;
case "湘西州": posdesc = "凤凰古城,沈从文笔下的边城"; break;
default: posdesc = "74751长沙斯塔克";
}
break;
/* 广东 */
case "广东省":
switch (ipLocation.result.ad_info.city) {
case "广州市": posdesc = "看小蛮腰,喝早茶了嘛~"; break;
case "韶关市": posdesc = "丹霞山阳元石,脸红心跳"; break;
case "深圳市": posdesc = "今天你逛商场了嘛~"; break;
case "珠海市": posdesc = "情侣路走断腿,日月贝打卡"; break;
case "汕头市": posdesc = "牛肉丸弹到飞起,粿条管够"; break;
case "佛山市": posdesc = "无影脚黄飞鸿,顺德美食天堂"; break;
case "江门市": posdesc = "开平碉楼,让子弹飞取景"; break;
case "湛江市": posdesc = "生蚝按盆吃,快乐似神仙"; break;
case "茂名市": posdesc = "荔枝之乡,杨贵妃同款"; break;
case "肇庆市": posdesc = "七星岩+鼎湖山,天然氧吧"; break;
case "惠州市": posdesc = "双月湾冲浪,巽寮湾发呆"; break;
case "梅州市": posdesc = "客家娘酒,酿出乡愁"; break;
case "汕尾市": posdesc = "二马路夜市,吃到扶墙"; break;
case "河源市": posdesc = "万绿湖绿出屏,矿泉水直接喝"; break;
case "阳江市": posdesc = "阳春合水!博主家乡~ 欢迎来玩~"; break;
case "清远市": posdesc = "清远鸡滑到筷子夹不住"; break;
case "东莞市": posdesc = "世界工厂,潮玩之都"; break;
case "中山市": posdesc = "孙中山故里,乳鸽脆皮流油"; break;
case "潮州市": posdesc = "牛肉火锅+粿条,潮汕味拉满"; break;
case "揭阳市": posdesc = "普宁豆干,外酥里嫩"; break;
case "云浮市": posdesc = "石材王国,云石艺术"; break;
default: posdesc = "来两斤福建人~";
}
break;
/* 广西 */
case "广西壮族自治区":
switch (ipLocation.result.ad_info.city) {
case "南宁市": posdesc = "友仔友女,撩螺咩?"; break;
case "柳州市": posdesc = "螺蛳粉真香,鼻子先流泪"; break;
case "桂林市": posdesc = "桂林山水甲天下"; break;
case "梧州市": posdesc = "龟苓膏原产地,苦尽甘来"; break;
case "北海市": posdesc = "银滩冲浪,涠洲岛潜水"; break;
case "防城港市": posdesc = "京族三岛,中国最后的海上吉普赛"; break;
case "钦州市": posdesc = "大蚝自由,烧烤配啤酒"; break;
case "贵港市": posdesc = "荷美覃塘,莲藕排骨汤"; break;
case "玉林市": posdesc = "狗肉节争议,牛腩粉真香"; break;
case "百色市": posdesc = "芒果之乡,甜过初恋"; break;
case "贺州市": posdesc = "黄姚古镇,发圈假装在江南"; break;
case "河池市": posdesc = "巴马长寿村,吸氧续命"; break;
case "来宾市": posdesc = "世界瑶都,瑶族风情"; break;
case "崇左市": posdesc = "德天跨国瀑布,越南一步之遥"; break;
default: posdesc = "桂林山水甲天下";
}
break;
/* 海南 */
case "海南省":
switch (ipLocation.result.ad_info.city) {
case "海口市": posdesc = "老爸茶一坐一下午,悠闲省"; break;
case "三亚市": posdesc = "椰梦长廊,潜水看珊瑚"; break;
case "三沙市": posdesc = "祖国最南端,海景房缺房"; break;
case "儋州市": posdesc = "东坡书院,海南文化担当"; break;
case "五指山市": posdesc = "黎族三月三,竹竿舞跳起来"; break;
case "琼海市": posdesc = "博鳌论坛,高端大气上档次"; break;
case "文昌市": posdesc = "航天发射场,看火箭飞天"; break;
case "万宁市": posdesc = "日月湾冲浪,浪到飞起"; break;
case "东方市": posdesc = "鱼鳞洲灯塔,最美晚霞"; break;
case "定安县": posdesc = "仙沟牛肉,现切现涮"; break;
case "屯昌县": posdesc = "油画之乡,艺术气息"; break;
case "澄迈县": posdesc = "富硒福地,长寿老人扎堆"; break;
case "临高县": posdesc = "临高角灯塔,海南最北端"; break;
case "白沙县": posdesc = "绿茶飘香,天然氧吧"; break;
case "昌江县": posdesc = "木棉花开,红满山坡"; break;
case "乐东县": posdesc = "莺歌海盐场,天空之镜"; break;
case "陵水县": posdesc = "清水湾会唱歌的沙滩"; break;
case "保亭县": posdesc = "七仙岭温泉,泡到不想走"; break;
case "琼中县": posdesc = "黎母山探秘,雨林徒步"; break;
default: posdesc = "朝观日出逐白浪,夕看云起收霞光";
}
break;
/* 四川 */
case "四川省":
switch (ipLocation.result.ad_info.city) {
case "成都市": posdesc = "巴适得板,熊猫儿等你"; break;
case "自贡市": posdesc = "恐龙之乡,盐帮菜辣哭"; break;
case "攀枝花市": posdesc = "阳光花城,芒果甜到爆"; break;
case "泸州市": posdesc = "1573国窖喝出高级感"; break;
case "德阳市": posdesc = "三星堆上新,外星人实锤"; break;
case "绵阳市": posdesc = "科技城+米粉,文武双全"; break;
case "广元市": posdesc = "剑门关鸟道,腿抖到明年"; break;
case "遂宁市": posdesc = "观音故里,灵泉寺许愿"; break;
case "内江市": posdesc = "大千故里,蜜饯甜到齁"; break;
case "乐山市": posdesc = "大佛脚底下吃跷脚牛肉"; break;
case "南充市": posdesc = "川北凉粉,辣到喷火"; break;
case "眉山市": posdesc = "东坡肘子,肥而不腻"; break;
case "宜宾市": posdesc = "五粮液配燃面,上头"; break;
case "广安市": posdesc = "邓小平故里,红色之旅"; break;
case "达州市": posdesc = "灯影牛肉,薄如纸片"; break;
case "雅安市": posdesc = "熊猫老家,三雅文化"; break;
case "巴中市": posdesc = "光雾山红叶,美到窒息"; break;
case "资阳市": posdesc = "安岳柠檬,酸爽炸裂"; break;
case "阿坝州": posdesc = "九寨沟归来不看水"; break;
case "甘孜州": posdesc = "丁真家乡,理塘打卡"; break;
case "凉山州": posdesc = "西昌烧烤,火盆边撸串"; break;
default: posdesc = "康康川妹子";
}
break;
/* 贵州 */
case "贵州省":
switch (ipLocation.result.ad_info.city) {
case "贵阳市": posdesc = "避暑之都,丝娃娃卷一切"; break;
case "六盘水市": posdesc = "凉都19℃夏天盖被子"; break;
case "遵义市": posdesc = "遵义会议,红色圣地"; break;
case "安顺市": posdesc = "黄果树瀑布,水帘洞打卡"; break;
case "毕节市": posdesc = "百里杜鹃,花海刷屏"; break;
case "铜仁市": posdesc = "梵净山蘑菇石,天空之城"; break;
case "黔西南州": posdesc = "万峰林骑行,最美喀斯特"; break;
case "黔东南州": posdesc = "千户苗寨,银饰叮当"; break;
case "黔南州": posdesc = "天眼FAST找外星人"; break;
default: posdesc = "茅台学生再塞200";
}
break;
/* 云南 */
case "云南省":
switch (ipLocation.result.ad_info.city) {
case "昆明市": posdesc = "春城无处不飞花,过桥米线管饱"; break;
case "曲靖市": posdesc = "宣威火腿,云腿月饼香"; break;
case "玉溪市": posdesc = "红塔山+抚仙湖,烟与湖"; break;
case "保山市": posdesc = "腾冲温泉,火山热海"; break;
case "昭通市": posdesc = "苹果之城,丑苹果甜到心"; break;
case "丽江市": posdesc = "古城艳遇,玉龙雪山蓝月谷"; break;
case "普洱市": posdesc = "左手咖啡右手茶,人生赢家"; break;
case "临沧市": posdesc = "冰岛老寨,普洱茶天花板"; break;
case "楚雄州": posdesc = "彝人古镇,火把节狂欢"; break;
case "红河州": posdesc = "元阳梯田,光影天堂"; break;
case "文山州": posdesc = "普者黑荷花,三生三世"; break;
case "西双版纳州": posdesc = "星光夜市,傣味烧烤"; break;
case "大理州": posdesc = "苍山雪洱海月,风花雪月"; break;
case "德宏州": posdesc = "芒市泡鲁达,缅味十足"; break;
case "怒江州": posdesc = "丙中洛人神共居,世外桃源"; break;
case "迪庆州": posdesc = "香格里拉,心中的日月"; break;
default: posdesc = "玉龙飞舞云缠绕,万仞冰川直耸天";
}
break;
/* 西藏 */
case "西藏自治区":
switch (ipLocation.result.ad_info.city) {
case "拉萨市": posdesc = "日光之城,布达拉宫朝圣"; break;
case "日喀则市": posdesc = "珠峰大本营8848.86打卡"; break;
case "昌都市": posdesc = "然乌湖倒影318此生必驾"; break;
case "林芝市": posdesc = "桃花沟十里桃林,三生三世"; break;
case "山南市": posdesc = "羊卓雍措,天鹅之湖"; break;
case "那曲市": posdesc = "羌塘草原,藏羚羊奔跑"; break;
case "阿里地区": posdesc = "冈仁波齐转山,信仰之旅"; break;
default: posdesc = "躺在茫茫草原上,仰望蓝天";
}
break;
/* 陕西 */
case "陕西省":
switch (ipLocation.result.ad_info.city) {
case "西安市": posdesc = "碳水之都,肉夹馍配冰峰"; break;
case "铜川市": posdesc = "药王故里,孙思邈养生"; break;
case "宝鸡市": posdesc = "青铜器博物院,何尊镇馆"; break;
case "咸阳市": posdesc = "秦始皇老家biangbiang面"; break;
case "渭南市": posdesc = "华山论剑,险中求胜"; break;
case "延安市": posdesc = "宝塔山+枣园,红色之旅"; break;
case "汉中市": posdesc = "油菜花田,汉人老家"; break;
case "榆林市": posdesc = "镇北台+榆林豆腐,塞上江南"; break;
case "安康市": posdesc = "瀛湖烤鱼,陕南小江南"; break;
case "商洛市": posdesc = "金丝峡漂流,天然空调"; break;
default: posdesc = "来份臊子面加馍";
}
break;
/* 甘肃 */
case "甘肃省":
switch (ipLocation.result.ad_info.city) {
case "兰州市": posdesc = "一碗牛肉面,拉开甘肃序幕"; break;
case "嘉峪关市": posdesc = "天下第一雄关,长城终点"; break;
case "金昌市": posdesc = "镍都金昌,紫金花海"; break;
case "白银市": posdesc = "黄河石林,大自然的鬼斧神工"; break;
case "天水市": posdesc = "麦积山石窟,东方雕塑馆"; break;
case "武威市": posdesc = "马踏飞燕,中国旅游标志"; break;
case "张掖市": posdesc = "七彩丹霞,打翻调色盘"; break;
case "平凉市": posdesc = "崆峒山论剑,武侠梦"; break;
case "酒泉市": posdesc = "敦煌飞天,卫星发射"; break;
case "庆阳市": posdesc = "香包刺绣,陇绣一绝"; break;
case "定西市": posdesc = "马铃薯之乡,洋芋擦擦"; break;
case "陇南市": posdesc = "官鹅沟秋景,陇上小九寨"; break;
case "临夏州": posdesc = "刘家峡水库,蓝到犯规"; break;
case "甘南州": posdesc = "扎尕那石城,神仙居住"; break;
default: posdesc = "羌笛何须怨杨柳,春风不度玉门关";
}
break;
/* 青海 */
case "青海省":
switch (ipLocation.result.ad_info.city) {
case "西宁市": posdesc = "青海湖骑行,塔尔寺转经"; break;
case "海东市": posdesc = "喇家遗址一碗4000年前的面条"; break;
case "海北州": posdesc = "门源花海,金色海洋"; break;
case "黄南州": posdesc = "热贡艺术,唐卡小镇"; break;
case "海南州": posdesc = "龙羊峡大坝,黄河第一坝"; break;
case "果洛州": posdesc = "年保玉则,天神后花园"; break;
case "玉树州": posdesc = "三江之源,可可西里"; break;
case "海西州": posdesc = "茶卡盐湖,天空之镜"; break;
default: posdesc = "牛肉干和老酸奶都好好吃";
}
break;
/* 宁夏 */
case "宁夏回族自治区":
switch (ipLocation.result.ad_info.city) {
case "银川市": posdesc = "塞上江南,手抓羊排"; break;
case "石嘴山市": posdesc = "沙湖苇舟,鸟的天堂"; break;
case "吴忠市": posdesc = "早茶拉面,吴忠人的早晨"; break;
case "固原市": posdesc = "六盘山红军长征,红色之旅"; break;
case "中卫市": posdesc = "沙坡头滑沙,黄河飞索"; break;
default: posdesc = "大漠孤烟直,长河落日圆";
}
break;
/* 新疆 */
case "新疆维吾尔自治区":
switch (ipLocation.result.ad_info.city) {
case "乌鲁木齐市": posdesc = "国际大巴扎,烤包子真香"; break;
case "克拉玛依市": posdesc = "黑油山,石油之城"; break;
case "吐鲁番市": posdesc = "火焰山+葡萄沟,冰火两重天"; break;
case "哈密市": posdesc = "哈密瓜原产地,甜到齁"; break;
case "昌吉州": posdesc = "天山天池,王母娘娘洗脚盆"; break;
case "博尔塔拉州": posdesc = "赛里木湖,大西洋最后一滴泪"; break;
case "巴音郭楞州": posdesc = "巴音布鲁克,九曲十八弯"; break;
case "阿克苏地区": posdesc = "冰糖心苹果,甜到心坎"; break;
case "克孜勒苏州": posdesc = "帕米尔高原,冰山上的来客"; break;
case "喀什地区": posdesc = "古城开城仪式,一秒穿越"; break;
case "和田地区": posdesc = "和田玉买买提,剁手之旅"; break;
case "伊犁州": posdesc = "杏花沟花海,美到窒息"; break;
case "塔城地区": posdesc = "手抓肉大盘,吃肉不吃蒜"; break;
case "阿勒泰地区": posdesc = "喀纳斯湖怪,等你来找"; break;
default: posdesc = "驼铃古道丝绸路,胡马犹闻唐汉风";
}
break;
/* 港澳台 */
case "台湾省":
posdesc = "我在这头,大陆在那头";
break;
case "香港特别行政区":
posdesc = "永定贼有残留地鬼嚎,迎击光非岁玉";
break;
case "澳门特别行政区":
posdesc = "性感荷官,在线发牌";
break;
/* 兜底 */
default:
posdesc = "带我去你的城市逛逛吧!";
}
break;
default:
posdesc = "带我去你的国家逛逛吧";
break;
}
//根据本地时间切换欢迎语
let timeChange;
let date = new Date();
if (date.getHours() >= 5 && date.getHours() < 11) timeChange = "<span>🌤️ 早上好,一日之计在于晨</span>";
else if (date.getHours() >= 11 && date.getHours() < 13) timeChange = "<span>☀️ 中午好,记得午休喔~</span>";
else if (date.getHours() >= 13 && date.getHours() < 17) timeChange = "<span>🕞 下午好,饮茶先啦!</span>";
else if (date.getHours() >= 17 && date.getHours() < 19) timeChange = "<span>🚶‍♂️ 即将下班,记得按时吃饭~</span>";
else if (date.getHours() >= 19 && date.getHours() < 23) timeChange = "<span>🌙 晚上好,夜生活嗨起来!</span>";
else timeChange = "夜深了,早点休息,少熬夜";
// 新增ipv6显示为指定内容
if (ip.includes(":")) {
ip = "<br>好复杂,咱看不懂~(ipv6)";
}
try {
//自定义文本和需要放的位置
document.getElementById("welcome-info").innerHTML =
`欢迎来自 <b><span style="color: var(--kouseki-ip-color);font-size: var(--kouseki-gl-size)">${pos}</span></b> 的小友💖<br>${posdesc}🍂<br>当前位置距博主约 <b><span style="color: var(--kouseki-ip-color)">${dist}</span></b> 公里!<br>您的IP地址为<b><span class="ip-mask">${ip}</span></b><br>${timeChange} <br>`;
} catch (err) {
console.log("Pjax无法获取元素")
}
}
window.onload = showWelcome;
// 如果使用了pjax在加上下面这行代码
document.addEventListener('pjax:complete', showWelcome);

View File

@@ -0,0 +1,350 @@
(() => {
const btfFn = {
debounce: (func, wait = 0, immediate = false) => {
let timeout
return (...args) => {
const later = () => {
timeout = null
if (!immediate) func(...args)
}
const callNow = immediate && !timeout
clearTimeout(timeout)
timeout = setTimeout(later, wait)
if (callNow) func(...args)
}
},
throttle: function (func, wait, options = {}) {
let timeout, context, args
let previous = 0
const later = () => {
previous = options.leading === false ? 0 : new Date().getTime()
timeout = null
func.apply(context, args)
if (!timeout) context = args = null
}
const throttled = (...params) => {
const now = new Date().getTime()
if (!previous && options.leading === false) previous = now
const remaining = wait - (now - previous)
context = this
args = params
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout)
timeout = null
}
previous = now
func.apply(context, args)
if (!timeout) context = args = null
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining)
}
}
return throttled
},
overflowPaddingR: {
add: () => {
const paddingRight = window.innerWidth - document.body.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 = ''
}
}
},
snackbarShow: (text, showAction = false, duration = 2000) => {
const { position, bgLight, bgDark } = GLOBAL_CONFIG.Snackbar
const bg = document.documentElement.getAttribute('data-theme') === 'light' ? bgLight : bgDark
Snackbar.show({
text,
backgroundColor: bg,
showAction,
duration,
pos: position,
customClass: 'snackbar-css'
})
},
diffDate: (inputDate, more = false) => {
const dateNow = new Date()
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 Math.floor(diffDay)
if (diffMonth > 12) return datePost.toISOString().slice(0, 10)
if (diffMonth >= 1) return `${Math.floor(diffMonth)} ${dateSuffix.month}`
if (diffDay >= 1) return `${Math.floor(diffDay)} ${dateSuffix.day}`
if (diffHour >= 1) return `${Math.floor(diffHour)} ${dateSuffix.hour}`
if (diffMin >= 1) return `${Math.floor(diffMin)} ${dateSuffix.min}`
return dateSuffix.just
},
loadComment: (dom, callback) => {
if ('IntersectionObserver' in window) {
const observerItem = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
callback()
observerItem.disconnect()
}
}, { threshold: [0] })
observerItem.observe(dom)
} else {
callback()
}
},
scrollToDest: (pos, time = 500) => {
const currentPos = window.scrollY
const isNavFixed = document.getElementById('page-header').classList.contains('fixed')
if (currentPos > pos || isNavFixed) pos = pos - 70
if ('scrollBehavior' in document.documentElement.style) {
window.scrollTo({
top: pos,
behavior: 'smooth'
})
return
}
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)
}
}
requestAnimationFrame(animate)
},
animateIn: (ele, animation) => {
ele.style.display = 'block'
ele.style.animation = animation
},
animateOut: (ele, animation) => {
const handleAnimationEnd = () => {
ele.style.display = ''
ele.style.animation = ''
ele.removeEventListener('animationend', handleAnimationEnd)
}
ele.addEventListener('animationend', handleAnimationEnd)
ele.style.animation = animation
},
wrap: (selector, eleType, options) => {
const createEle = document.createElement(eleType)
for (const [key, value] of Object.entries(options)) {
createEle.setAttribute(key, value)
}
selector.parentNode.insertBefore(createEle, selector)
createEle.appendChild(selector)
},
isHidden: ele => ele.offsetHeight === 0 && ele.offsetWidth === 0,
getEleTop: ele => {
let actualTop = ele.offsetTop
let current = ele.offsetParent
while (current !== null) {
actualTop += current.offsetTop
current = current.offsetParent
}
return actualTop
},
loadLightbox: ele => {
const service = GLOBAL_CONFIG.lightbox
if (service === 'medium_zoom') {
mediumZoom(ele, { background: 'var(--zoom-bg)' })
return
}
if (service === 'fancybox') {
Array.from(ele).forEach(i => {
if (i.parentNode.tagName !== 'A') {
const dataSrc = i.dataset.lazySrc || i.src
const dataCaption = i.title || i.alt || ''
btf.wrap(i, 'a', { href: dataSrc, 'data-fancybox': 'gallery', 'data-caption': dataCaption, 'data-thumb': dataSrc })
}
})
if (!window.fancyboxRun) {
let options = ''
if (Fancybox.version < '6') {
options = {
Hash: false,
Thumbs: {
showOnStart: false
},
Images: {
Panzoom: {
maxScale: 4
}
},
Carousel: {
transition: 'slide'
},
Toolbar: {
display: {
left: ['infobar'],
middle: [
'zoomIn',
'zoomOut',
'toggle1to1',
'rotateCCW',
'rotateCW',
'flipX',
'flipY'
],
right: ['slideshow', 'thumbs', 'close']
}
}
}
} else {
options = {
Hash: false,
Carousel: {
transition: 'slide',
Thumbs: {
showOnStart: false
},
Toolbar: {
display: {
left: ['counter'],
middle: [
'zoomIn',
'zoomOut',
'toggle1to1',
'rotateCCW',
'rotateCW',
'flipX',
'flipY',
"reset"
],
right: ['autoplay', 'thumbs', 'close']
}
},
Zoomable: {
Panzoom: {
maxScale: 4
}
}
}
}
}
Fancybox.bind('[data-fancybox]', options)
window.fancyboxRun = true
}
}
},
setLoading: {
add: ele => {
const html = `
<div class="loading-container">
<div class="loading-item">
<div></div><div></div><div></div><div></div><div></div>
</div>
</div>
`
ele.insertAdjacentHTML('afterend', html)
},
remove: ele => {
ele.nextElementSibling.remove()
}
},
updateAnchor: anchor => {
if (anchor !== window.location.hash) {
if (!anchor) anchor = location.pathname
const title = GLOBAL_CONFIG_SITE.title
window.history.replaceState({
url: location.href,
title
}, title, anchor)
}
},
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('pjaxSendOnce', () => {
ele.removeEventListener(event, fn, option)
})
},
removeGlobalFnEvent: (key, parent = window) => {
const globalFn = parent.globalFn || {}
const keyObj = globalFn[key]
if (!keyObj) return
Object.keys(keyObj).forEach(i => keyObj[i]())
delete globalFn[key]
},
switchComments: (el = document, path) => {
const switchBtn = el.querySelector('#switch-btn')
if (!switchBtn) return
let switchDone = false
const postComment = el.querySelector('#post-comment')
const handleSwitchBtn = () => {
postComment.classList.toggle('move')
if (!switchDone && typeof loadOtherComment === 'function') {
switchDone = true
loadOtherComment(el, path)
}
}
btf.addEventListenerPjax(switchBtn, 'click', handleSwitchBtn)
}
}
window.btf = { ...window.btf, ...btfFn }
})()