Site updated: 2023-09-22 21:57:09

This commit is contained in:
Jason 2023-09-22 21:57:28 +08:00
parent ef766f86eb
commit 2ebf0cc0f6
950 changed files with 56869 additions and 0 deletions

192
404.html Normal file

File diff suppressed because one or more lines are too long

192
archives/2023/03/index.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

192
archives/2023/04/index.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

192
archives/2023/05/index.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

192
archives/2023/06/index.html Normal file

File diff suppressed because one or more lines are too long

192
archives/2023/07/index.html Normal file

File diff suppressed because one or more lines are too long

192
archives/2023/08/index.html Normal file

File diff suppressed because one or more lines are too long

192
archives/2023/09/index.html Normal file

File diff suppressed because one or more lines are too long

192
archives/2023/index.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

192
archives/index.html Normal file

File diff suppressed because one or more lines are too long

192
archives/page/2/index.html Normal file

File diff suppressed because one or more lines are too long

192
archives/page/3/index.html Normal file

File diff suppressed because one or more lines are too long

192
archives/page/4/index.html Normal file

File diff suppressed because one or more lines are too long

192
archives/page/5/index.html Normal file

File diff suppressed because one or more lines are too long

192
archives/page/6/index.html Normal file

File diff suppressed because one or more lines are too long

192
archives/page/7/index.html Normal file

File diff suppressed because one or more lines are too long

283
baidusitemap.xml Normal file
View File

@ -0,0 +1,283 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://jasonsgong.gitee.io/posts/32696.html</loc>
<lastmod>2023-09-22</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/24183.html</loc>
<lastmod>2023-09-22</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/8957.html</loc>
<lastmod>2023-09-21</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/29985.html</loc>
<lastmod>2023-09-21</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/25154.html</loc>
<lastmod>2023-09-19</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/39654.html</loc>
<lastmod>2023-09-18</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/53088.html</loc>
<lastmod>2023-09-14</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/64695.html</loc>
<lastmod>2023-09-14</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/5727.html</loc>
<lastmod>2023-09-12</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/19306.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/63724.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/60685.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/18459.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/28118.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/63587.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/20683.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/48020.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/21883.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/17259.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/24637.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/53306.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/50465.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/24606.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/73.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/19270.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/29367.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/50908.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/62439.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/26768.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/22654.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/56742.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/32679.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/32246.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/855.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/12929.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/38823.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/64205.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/47407.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/13813.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/54835.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/60780.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/30127.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/6932.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/1530.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/1416.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/13579.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/47003.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/51007.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/14438.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/17772.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/63333.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/1727.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/36397.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/45572.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/432.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/28687.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/60684.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/3661.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/35630.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/27166.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/46306.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/22202.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/7353.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/29250.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/31385.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/11844.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/6319.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/46317.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/40445.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
<url>
<loc>https://jasonsgong.gitee.io/posts/45726.html</loc>
<lastmod>2023-09-11</lastmod>
</url>
</urlset>

194
categories/index.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

749
css/hbe.style.css Normal file
View File

@ -0,0 +1,749 @@
.hbe,
.hbe:after,
.hbe:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.hbe-container{
margin: 0 auto;
overflow: hidden;
}
.hbe-content {
text-align: center;
font-size: 150%;
padding: 1em 0;
}
.hbe-input {
position: relative;
z-index: 1;
display: inline-block;
margin: 1em;
width: 80%;
min-width: 200px;
vertical-align: top;
}
.hbe-input-field {
line-height: normal;
font-size: 100%;
margin: 0;
position: relative;
display: block;
float: right;
padding: 0.8em;
width: 60%;
border: none;
border-radius: 0;
background: #f0f0f0;
color: #aaa;
font-weight: 400;
font-family: "Avenir Next", "Helvetica Neue", Helvetica, Arial, sans-serif;
-webkit-appearance: none; /* for box shadows to show on iOS */
}
.hbe-input-field:focus {
outline: none;
}
.hbe-input-label {
display: inline-block;
float: right;
padding: 0 1em;
width: 40%;
color: #696969;
font-weight: bold;
font-size: 70.25%;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.hbe-input-label-content {
position: relative;
display: block;
padding: 1.6em 0;
width: 100%;
}
.hbe-graphic {
position: absolute;
top: 0;
left: 0;
fill: none;
}
/* hbe button in post page */
.hbe-button {
width: 130px;
height: 40px;
background: linear-gradient(to bottom, #4eb5e5 0%,#389ed5 100%); /* W3C */
border: none;
border-radius: 5px;
position: relative;
border-bottom: 4px solid #2b8bc6;
color: #fbfbfb;
font-weight: 600;
font-family: 'Open Sans', sans-serif;
text-shadow: 1px 1px 1px rgba(0,0,0,.4);
font-size: 15px;
text-align: left;
text-indent: 5px;
box-shadow: 0px 3px 0px 0px rgba(0,0,0,.2);
cursor: pointer;
display: block;
margin: 0 auto;
margin-bottom: 20px;
}
.hbe-button:active {
box-shadow: 0px 2px 0px 0px rgba(0,0,0,.2);
top: 1px;
}
.hbe-button:after {
content: "";
width: 0;
height: 0;
display: block;
border-top: 20px solid #187dbc;
border-bottom: 20px solid #187dbc;
border-left: 16px solid transparent;
border-right: 20px solid #187dbc;
position: absolute;
opacity: 0.6;
right: 0;
top: 0;
border-radius: 0 5px 5px 0;
}
/* hbe button in post page */
/* default theme {{{ */
.hbe-input-default {
overflow: hidden;
}
.hbe-input-field-default {
width: 100%;
background: transparent;
padding: 0.5em;
margin-bottom: 2em;
color: #f9f7f6;
z-index: 100;
opacity: 0;
}
.hbe-input-label-default {
width: 100%;
position: absolute;
text-align: left;
padding: 0.5em 0;
pointer-events: none;
font-size: 1em;
}
.hbe-input-label-default::before,
.hbe-input-label-default::after {
content: '';
position: absolute;
width: 100%;
left: 0;
}
.hbe-input-label-default::before {
height: 100%;
background: #666666;
top: 0;
-webkit-transform: translate3d(0, -100%, 0);
transform: translate3d(0, -100%, 0);
-webkit-transition: -webkit-transform 0.2s;
transition: transform 0.2s;
}
.hbe-input-label-default::after {
height: 2px;
background: #666666;
top: 100%;
-webkit-transition: opacity 0.2s;
transition: opacity 0.2s;
}
.hbe-input-label-content-default {
padding: 0;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transition: -webkit-transform 0.2s, color 0.2s;
transition: transform 0.2s, color 0.2s;
}
.hbe-input-field-default:focus,
.hbe-input--filled .hbe-input-field-default {
opacity: 1;
-webkit-transition: opacity 0s 0.2s;
transition: opacity 0s 0.2s;
}
.hbe-input-label-default::before,
.hbe-input-label-default::after,
.hbe-input-label-content-default,
.hbe-input-field-default:focus,
.hbe-input--filled .hbe-input-field-default {
-webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1);
transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1);
}
.hbe-input-field-default:focus + .hbe-input-label-default::before,
.hbe-input--filled .hbe-input-label-default::before {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
.hbe-input-field-default:focus + .hbe-input-label-default::after,
.hbe-input--filled .hbe-input-label-default::after {
opacity: 0;
}
.hbe-input-field-default:focus + .hbe-input-label-default .hbe-input-label-content-default,
.hbe-input--filled .hbe-input-label-default .hbe-input-label-content-default {
color: #555555;
-webkit-transform: translate3d(0, 2.1em, 0) scale3d(0.65, 0.65, 1);
transform: translate3d(0, 2.1em, 0) scale3d(0.65, 0.65, 1);
}
/* default theme }}} */
/* up theme {{{ */
.hbe-input-up {
overflow: hidden;
padding-top: 2em;
}
.hbe-input-field-up {
width: 100%;
background: transparent;
opacity: 0;
padding: 0.35em;
z-index: 100;
color: #837482;
}
.hbe-input-label-up {
width: 100%;
bottom: 0;
position: absolute;
pointer-events: none;
text-align: left;
color: #8E9191;
padding: 0 0.5em;
}
.hbe-input-label-up::before {
content: '';
position: absolute;
width: 100%;
height: 4em;
top: 100%;
left: 0;
background: #fff;
border-top: 4px solid #9B9F9F;
-webkit-transform: translate3d(0, -3px, 0);
transform: translate3d(0, -3px, 0);
-webkit-transition: -webkit-transform 0.4s;
transition: transform 0.4s;
-webkit-transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1);
transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1);
}
.hbe-input-label-content-up {
padding: 0.5em 0;
-webkit-transform-origin: 0% 100%;
transform-origin: 0% 100%;
-webkit-transition: -webkit-transform 0.4s, color 0.4s;
transition: transform 0.4s, color 0.4s;
-webkit-transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1);
transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1);
}
.hbe-input-field-up:focus,
.input--filled .hbe-input-field-up {
cursor: text;
opacity: 1;
-webkit-transition: opacity 0s 0.4s;
transition: opacity 0s 0.4s;
}
.hbe-input-field-up:focus + .hbe-input-label-up::before,
.input--filled .hbe-input-label-up::before {
-webkit-transition-delay: 0.05s;
transition-delay: 0.05s;
-webkit-transform: translate3d(0, -3.3em, 0);
transform: translate3d(0, -3.3em, 0);
}
.hbe-input-field-up:focus + .hbe-input-label-up .hbe-input-label-content-up,
.input--filled .hbe-input-label-content-up {
color: #6B6E6E;
-webkit-transform: translate3d(0, -3.3em, 0) scale3d(0.81, 0.81, 1);
transform: translate3d(0, -3.3em, 0) scale3d(0.81, 0.81, 1);
}
/* up theme }}} */
/* wave theme {{{ */
.hbe-input-wave {
overflow: hidden;
padding-top: 1em;
}
.hbe-input-field-wave {
padding: 0.5em 0em 0.25em;
width: 100%;
background: transparent;
color: #9da8b2;
font-size: 1.25em;
}
.hbe-input-label-wave {
position: absolute;
top: 0.95em;
font-size: 0.85em;
left: 0;
display: block;
width: 100%;
text-align: left;
padding: 0em;
pointer-events: none;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transition: -webkit-transform 0.2s 0.15s, color 1s;
transition: transform 0.2s 0.15s, color 1s;
-webkit-transition-timing-function: ease-out;
transition-timing-function: ease-out;
}
.hbe-graphic-wave {
stroke: #92989e;
pointer-events: none;
-webkit-transition: -webkit-transform 0.7s, stroke 0.7s;
transition: transform 0.7s, stroke 0.7s;
-webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1);
transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1);
}
.hbe-input-field-wave:focus + .hbe-input-label-wave,
.input--filled .hbe-input-label-wave {
color: #333;
-webkit-transform: translate3d(0, -1.25em, 0) scale3d(0.75, 0.75, 1);
transform: translate3d(0, -1.25em, 0) scale3d(0.75, 0.75, 1);
}
.hbe-input-field-wave:focus ~ .hbe-graphic-wave,
.input--filled .graphic-wave {
stroke: #333;
-webkit-transform: translate3d(-66.6%, 0, 0);
transform: translate3d(-66.6%, 0, 0);
}
/* wave theme }}} */
/* flip theme {{{ */
.hbe-input-field-flip {
width: 100%;
background-color: #d0d1d0;
border: 2px solid transparent;
-webkit-transition: background-color 0.25s, border-color 0.25s;
transition: background-color 0.25s, border-color 0.25s;
}
.hbe-input-label-flip {
width: 100%;
text-align: left;
position: absolute;
bottom: 100%;
pointer-events: none;
overflow: hidden;
padding: 0 1.25em;
-webkit-transform: translate3d(0, 3em, 0);
transform: translate3d(0, 3em, 0);
-webkit-transition: -webkit-transform 0.25s;
transition: transform 0.25s ;
-webkit-transition-timing-function: ease-in-out;
transition-timing-function: ease-in-out;
}
.hbe-input-label-content-flip {
color: #8B8C8B;
padding: 0.25em 0;
-webkit-transition: -webkit-transform 0.25s;
transition: transform 0.25s;
-webkit-transition-timing-function: ease-in-out;
transition-timing-function: ease-in-out;
}
.hbe-input-label-content-flip::after {
content: attr(data-content);
position: absolute;
font-weight: 800;
bottom: 100%;
left: 0;
height: 100%;
width: 100%;
color: #666666;
padding: 0.25em 0;
letter-spacing: 1px;
font-size: 1em;
}
.hbe-input-field-flip:focus + .hbe-input-label-flip,
.input--filled .hbe-input-label-flip {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
.hbe-input-field-flip:focus + .hbe-input-label-flip .hbe-input-label-content-flip,
.input--filled .hbe-input-label-content-flip {
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
}
.hbe-input-field-flip:focus + .hbe-input-field-flip,
.input--filled .hbe-input-field-flip {
background-color: transparent;
border-color: #666666;
}
/* flip theme }}} */
/* xray theme {{{ */
.hbe-input-xray {
overflow: hidden;
padding-bottom: 2.5em;
}
.hbe-input-field-xray {
padding: 0;
margin-top: 1.2em;
width: 100%;
background: transparent;
color: #84AF9B ;
font-size: 1.55em;
}
.hbe-input-label-xray {
position: absolute;
top: 2em;
left: 0;
display: block;
width: 100%;
text-align: left;
padding: 0em;
letter-spacing: 1px;
color: #84AF9B ;
pointer-events: none;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transition: -webkit-transform 0.2s 0.1s, color 0.3s;
transition: transform 0.2s 0.1s, color 0.3s;
-webkit-transition-timing-function: ease-out;
transition-timing-function: ease-out;
}
.hbe-graphic-xray {
stroke: #84AF9B ;
pointer-events: none;
stroke-width: 2px;
top: 1.25em;
bottom: 0px;
height: 3.275em;
-webkit-transition: -webkit-transform 0.7s, stroke 0.7s;
transition: transform 0.7s, stroke 0.7s;
-webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1);
transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1);
}
.hbe-input-field-xray:focus + .hbe-input-label-xray,
.input--filled .hbe-input-label-xray {
color: #84AF9B ;
-webkit-transform: translate3d(0, 3.5em, 0) scale3d(0.85, 0.85, 1);
transform: translate3d(0, 3.5em, 0) scale3d(0.85, 0.85, 1);
}
.hbe-input-field-xray:focus ~ .hbe-graphic-xray,
.input--filled .graphic-xray {
stroke: #84AF9B ;
-webkit-transform: translate3d(-66.6%, 0, 0);
transform: translate3d(-66.6%, 0, 0);
}
/* xray theme }}} */
/* blink theme {{{ */
.hbe-input-blink {
padding-top: 1em;
}
.hbe-input-field-blink {
width: 100%;
padding: 0.8em 0.5em;
background: transparent;
border: 2px solid;
color: #8781bd;
-webkit-transition: border-color 0.25s;
transition: border-color 0.25s;
}
.hbe-input-label-blink {
width: 100%;
position: absolute;
top: 0;
text-align: left;
overflow: hidden;
padding: 0;
pointer-events: none;
-webkit-transform: translate3d(0, 3em, 0);
transform: translate3d(0, 3em, 0);
}
.hbe-input-label-content-blink {
padding: 0 1em;
font-weight: 400;
color: #b5b5b5;
}
.hbe-input-label-content-blink::after {
content: attr(data-content);
position: absolute;
top: -200%;
left: 0;
color: #8781bd ;
font-weight: 800;
}
.hbe-input-field-blink:focus,
.input--filled .hbe-input-field-blink {
border-color: #8781bd ;
}
.hbe-input-field-blink:focus + .hbe-input-label-blink,
.input--filled .hbe-input-label-blink {
-webkit-animation: anim-blink-1 0.25s forwards;
animation: anim-blink-1 0.25s forwards;
}
.hbe-input-field-blink:focus + .hbe-input-label-blink .hbe-input-label-content-blink,
.input--filled .hbe-input-label-content-blink {
-webkit-animation: anim-blink-2 0.25s forwards ease-in;
animation: anim-blink-2 0.25s forwards ease-in;
}
@-webkit-keyframes anim-blink-1 {
0%, 70% {
-webkit-transform: translate3d(0, 3em, 0);
transform: translate3d(0, 3em, 0);
}
71%, 100% {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
@-webkit-keyframes anim-blink-2 {
0% {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
70%, 71% {
-webkit-transform: translate3d(0, 125%, 0);
transform: translate3d(0, 125%, 0);
opacity: 0;
-webkit-animation-timing-function: ease-out;
}
100% {
color: transparent;
-webkit-transform: translate3d(0, 200%, 0);
transform: translate3d(0, 200%, 0);
}
}
@keyframes anim-blink-1 {
0%, 70% {
-webkit-transform: translate3d(0, 3em, 0);
transform: translate3d(0, 3em, 0);
}
71%, 100% {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
@keyframes anim-blink-2 {
0% {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
70%, 71% {
-webkit-transform: translate3d(0, 125%, 0);
transform: translate3d(0, 125%, 0);
opacity: 0;
-webkit-animation-timing-function: ease-out;
}
100% {
color: transparent;
-webkit-transform: translate3d(0, 200%, 0);
transform: translate3d(0, 200%, 0);
}
}
/* blink theme }}} */
/* surge theme {{{ */
.hbe-input-surge {
overflow: hidden;
padding-bottom: 1em;
}
.hbe-input-field-surge {
padding: 0.25em 0.5em;
margin-top: 1.25em;
width: 100%;
background: transparent;
color: #D0D0D0;
font-size: 1.55em;
opacity: 0;
}
.hbe-input-label-surge {
width: 100%;
text-align: left;
position: absolute;
top: 1em;
pointer-events: none;
overflow: hidden;
padding: 0 0.25em;
-webkit-transform: translate3d(1em, 2.75em, 0);
transform: translate3d(1em, 2.75em, 0);
-webkit-transition: -webkit-transform 0.3s;
transition: transform 0.3s;
}
.hbe-input-label-content-surge {
color: #A4A5A6;
padding: 0.4em 0 0.25em;
-webkit-transition: -webkit-transform 0.3s;
transition: transform 0.3s;
}
.hbe-input-label-content-surge::after {
content: attr(data-content);
position: absolute;
font-weight: 800;
top: 100%;
left: 0;
height: 100%;
width: 100%;
color: #2C3E50;
padding: 0.25em 0;
letter-spacing: 1px;
font-size: 0.85em;
}
.hbe-graphic-surge {
fill: #2C3E50;
pointer-events: none;
top: 1em;
bottom: 0px;
height: 4.5em;
z-index: -1;
-webkit-transition: -webkit-transform 0.7s, fill 0.7s;
transition: transform 0.7s, fill 0.7s;
-webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1);
transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1);
}
.hbe-input-field-surge:focus,
.input--filled .hbe-input-field-surge {
-webkit-transition: opacity 0s 0.35s;
transition: opacity 0s 0.35s;
opacity: 1;
}
.hbe-input-field-surge:focus + .hbe-input-label-surge,
.input--filled .hbe-input-label-surge {
-webkit-transition-delay: 0.15s;
transition-delay: 0.15s;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
.hbe-input-field-surge:focus + .hbe-input-label-surge .hbe-input-label-content-surge,
.input--filled .hbe-input-label-content-surge {
-webkit-transition-delay: 0.15s;
transition-delay: 0.15s;
-webkit-transform: translate3d(0, -100%, 0);
transform: translate3d(0, -100%, 0);
}
.hbe-input-field-surge:focus ~ .hbe-graphic-surge,
.input--filled .graphic-surge {
fill: #2C3E50;
-webkit-transform: translate3d(-66.6%, 0, 0);
transform: translate3d(-66.6%, 0, 0);
}
/* surge theme }}} */
/* shrink theme {{{ */
.hbe-input-field-shrink {
width: 100%;
background: transparent;
padding: 0.5em 0;
margin-bottom: 2em;
color: #2C3E50;
}
.hbe-input-label-shrink {
width: 100%;
position: absolute;
text-align: left;
font-size: 1em;
padding: 10px 0 5px;
pointer-events: none;
}
.hbe-input-label-shrink::after {
content: '';
position: absolute;
width: 100%;
height: 7px;
background: #B7C3AC;
left: 0;
top: 100%;
-webkit-transform-origin: 50% 100%;
transform-origin: 50% 100%;
-webkit-transition: -webkit-transform 0.3s, background-color 0.3s;
transition: transform 0.3s, background-color 0.3s;
}
.hbe-input-label-content-shrink {
padding: 0;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transition: -webkit-transform 0.3s, color 0.3s;
transition: transform 0.3s, color 0.3s;
}
.hbe-input-field-shrink:focus + .hbe-input-label-shrink::after,
.input--filled .hbe-input-label-shrink::after {
background: #84AF9B;
-webkit-transform: scale3d(1, 0.25, 1);
transform: scale3d(1, 0.25, 1);
}
.hbe-input-field-shrink:focus + .hbe-input-label-shrink .hbe-input-label-content-shrink,
.input--filled .hbe-input-label-shrink .hbe-input-label-content-shrink {
color: #84AF9B;
-webkit-transform: translate3d(0, 2em, 0) scale3d(0.655, 0.655, 1);
transform: translate3d(0, 2em, 0) scale3d(0.655, 0.655, 1);
}
/* shrink theme }}} */

5924
css/index.css Normal file

File diff suppressed because it is too large Load Diff

BIN
img/1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

BIN
img/2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
img/3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 KiB

BIN
img/4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

BIN
img/404.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
img/5.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
img/avatar.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 KiB

BIN
img/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

BIN
img/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

BIN
img/图标.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

355
index.html Normal file

File diff suppressed because one or more lines are too long

827
js/main.js Normal file
View File

@ -0,0 +1,827 @@
document.addEventListener('DOMContentLoaded', function () {
let headerContentWidth, $nav
let mobileSidebarOpen = false
const adjustMenu = init => {
const getAllWidth = ele => {
let width = 0
ele.length && Array.from(ele).forEach(i => { width += i.offsetWidth })
return width
}
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')
}
let hideMenuIndex = ''
if (window.innerWidth <= 768) hideMenuIndex = true
else hideMenuIndex = headerContentWidth > $nav.offsetWidth - 120
if (hideMenuIndex) {
$nav.classList.add('hide-menu')
} else {
$nav.classList.remove('hide-menu')
}
}
// 初始化header
const initAdjust = () => {
adjustMenu(true)
$nav.classList.add('show')
}
// sidebar menus
const sidebarFn = {
open: () => {
btf.sidebarPaddingR()
document.body.style.overflow = 'hidden'
btf.animateIn(document.getElementById('menu-mask'), 'to_show 0.5s')
document.getElementById('sidebar-menus').classList.add('open')
mobileSidebarOpen = true
},
close: () => {
const $body = document.body
$body.style.overflow = ''
$body.style.paddingRight = ''
btf.animateOut(document.getElementById('menu-mask'), 'to_hide 0.5s')
document.getElementById('sidebar-menus').classList.remove('open')
mobileSidebarOpen = false
}
}
/**
* 首頁top_img底下的箭頭
*/
const scrollDownInIndex = () => {
const $scrollDownEle = document.getElementById('scroll-down')
$scrollDownEle && $scrollDownEle.addEventListener('click', function () {
btf.scrollToDest(document.getElementById('content-inner').offsetTop, 300)
})
}
/**
* 代碼
* 只適用於Hexo默認的代碼渲染
*/
const addHighlightTool = function () {
const highLight = GLOBAL_CONFIG.highlight
if (!highLight) return
const { highlightCopy, highlightLang, highlightHeightLimit, plugin } = highLight
const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink
const isShowTool = highlightCopy || highlightLang || isHighlightShrink !== undefined
const $figureHighlight = plugin === 'highlighjs' ? 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 ${highlightShrinkClass}"></i>` : ''
const highlightCopyEle = highlightCopy ? '<div class="copy-notice"></div><i class="fas fa-paste copy-button"></i>' : ''
const copy = (text, ctx) => {
if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
document.execCommand('copy')
if (GLOBAL_CONFIG.Snackbar !== undefined) {
btf.snackbarShow(GLOBAL_CONFIG.copy.success)
} else {
const prevEle = ctx.previousElementSibling
prevEle.textContent = GLOBAL_CONFIG.copy.success
prevEle.style.opacity = 1
setTimeout(() => { prevEle.style.opacity = 0 }, 700)
}
} else {
if (GLOBAL_CONFIG.Snackbar !== undefined) {
btf.snackbarShow(GLOBAL_CONFIG.copy.noSupport)
} else {
ctx.previousElementSibling.textContent = GLOBAL_CONFIG.copy.noSupport
}
}
}
// click events
const highlightCopyFn = (ele) => {
const $buttonParent = ele.parentNode
$buttonParent.classList.add('copy-true')
const selection = window.getSelection()
const range = document.createRange()
const preCodeSelector = isPrismjs ? 'pre code' : 'table .code pre'
range.selectNodeContents($buttonParent.querySelectorAll(`${preCodeSelector}`)[0])
selection.removeAllRanges()
selection.addRange(range)
const text = selection.toString()
copy(text, ele.lastChild)
selection.removeAllRanges()
$buttonParent.classList.remove('copy-true')
}
const highlightShrinkFn = (ele) => {
const $nextEle = [...ele.parentNode.children].slice(1)
ele.firstChild.classList.toggle('closed')
if (btf.isHidden($nextEle[$nextEle.length - 1])) {
$nextEle.forEach(e => { e.style.display = 'block' })
} else {
$nextEle.forEach(e => { e.style.display = 'none' })
}
}
const highlightToolsFn = function (e) {
const $target = e.target.classList
if ($target.contains('expand')) highlightShrinkFn(this)
else if ($target.contains('copy-button')) highlightCopyFn(this)
}
const expandCode = function () {
this.classList.toggle('expand-done')
}
function createEle (lang, item, service) {
const fragment = document.createDocumentFragment()
if (isShowTool) {
const hlTools = document.createElement('div')
hlTools.className = `highlight-tools ${highlightShrinkClass}`
hlTools.innerHTML = highlightShrinkEle + lang + highlightCopyEle
hlTools.addEventListener('click', highlightToolsFn)
fragment.appendChild(hlTools)
}
if (highlightHeightLimit && item.offsetHeight > highlightHeightLimit + 30) {
const ele = document.createElement('div')
ele.className = 'code-expand-btn'
ele.innerHTML = '<i class="fas fa-angle-double-down"></i>'
ele.addEventListener('click', expandCode)
fragment.appendChild(ele)
}
if (service === 'hl') {
item.insertBefore(fragment, item.firstChild)
} else {
item.parentNode.insertBefore(fragment, item)
}
}
if (isPrismjs) {
$figureHighlight.forEach(item => {
if (highlightLang) {
const langName = item.getAttribute('data-language') || 'Code'
const highlightLangEle = `<div class="code-lang">${langName}</div>`
btf.wrap(item, 'figure', { class: 'highlight' })
createEle(highlightLangEle, item)
} else {
btf.wrap(item, 'figure', { class: 'highlight' })
createEle('', item)
}
})
} else {
$figureHighlight.forEach(function (item) {
if (highlightLang) {
let langName = item.getAttribute('class').split(' ')[1]
if (langName === 'plain' || langName === undefined) langName = 'Code'
const highlightLangEle = `<div class="code-lang">${langName}</div>`
createEle(highlightLangEle, item, 'hl')
} else {
createEle('', item, 'hl')
}
})
}
}
/**
* PhotoFigcaption
*/
function addPhotoFigcaption () {
document.querySelectorAll('#article-container img').forEach(function (item) {
const parentEle = item.parentNode
const altValue = item.title || item.alt
if (altValue && !parentEle.parentNode.classList.contains('justified-gallery')) {
const ele = document.createElement('div')
ele.className = 'img-alt is-center'
ele.textContent = altValue
parentEle.insertBefore(ele, item.nextSibling)
}
})
}
/**
* Lightbox
*/
const runLightbox = () => {
btf.loadLightbox(document.querySelectorAll('#article-container img:not(.no-lightbox)'))
}
/**
* justified-gallery 圖庫排版
*/
const runJustifiedGallery = function (ele) {
const htmlStr = arr => {
let str = ''
const replaceDq = str => str.replace(/"/g, '&quot;') // replace double quotes to &quot;
arr.forEach(i => {
const alt = i.alt ? `alt="${replaceDq(i.alt)}"` : ''
const title = i.title ? `title="${replaceDq(i.title)}"` : ''
str += `<div class="fj-gallery-item"><img src="${i.url}" ${alt + title}"></div>`
})
return str
}
const lazyloadFn = (i, arr, limit) => {
const loadItem = limit
const arrLength = arr.length
if (arrLength > loadItem) i.insertAdjacentHTML('beforeend', htmlStr(arr.splice(0, loadItem)))
else {
i.insertAdjacentHTML('beforeend', htmlStr(arr))
i.classList.remove('lazyload')
}
return arrLength > loadItem ? loadItem : arrLength
}
const fetchUrl = async (url) => {
const response = await fetch(url)
return await response.json()
}
const runJustifiedGallery = (item, arr) => {
if (!item.classList.contains('lazyload')) item.innerHTML = htmlStr(arr)
else {
const limit = item.getAttribute('data-limit')
lazyloadFn(item, arr, limit)
const clickBtnFn = () => {
const lastItemLength = lazyloadFn(item, arr, limit)
fjGallery(item, 'appendImages', item.querySelectorAll(`.fj-gallery-item:nth-last-child(-n+${lastItemLength})`))
btf.loadLightbox(item.querySelectorAll('img'))
lastItemLength < limit && item.nextElementSibling.removeEventListener('click', clickBtnFn)
}
item.nextElementSibling.addEventListener('click', clickBtnFn)
}
btf.initJustifiedGallery(item)
btf.loadLightbox(item.querySelectorAll('img'))
}
const addJustifiedGallery = () => {
ele.forEach(item => {
item.classList.contains('url')
? fetchUrl(item.textContent).then(res => { runJustifiedGallery(item, res) })
: runJustifiedGallery(item, JSON.parse(item.textContent))
})
}
if (window.fjGallery) {
addJustifiedGallery()
return
}
getCSS(`${GLOBAL_CONFIG.source.justifiedGallery.css}`)
getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`).then(addJustifiedGallery)
}
/**
* rightside scroll percent
*/
const rightsideScrollPercent = currentTop => {
const perNum = btf.getScrollPercent(currentTop, document.body)
const $goUp = document.getElementById('go-up')
if (perNum < 95) {
$goUp.classList.add('show-percent')
$goUp.querySelector('.scroll-percent').textContent = perNum
} else {
$goUp.classList.remove('show-percent')
}
}
/**
* 滾動處理
*/
const scrollFn = function () {
const $rightside = document.getElementById('rightside')
const innerHeight = window.innerHeight + 56
let initTop = 0
let isChatShow = true
const $header = document.getElementById('page-header')
const isChatBtn = typeof chatBtn !== 'undefined'
const isShowPercent = GLOBAL_CONFIG.percent.rightside
// 當滾動條小于 56 的時候
if (document.body.scrollHeight <= innerHeight) {
$rightside.style.cssText = 'opacity: 1; transform: translateX(-58px)'
return
}
// find the scroll direction
const scrollDirection = currentTop => {
const result = currentTop > initTop // true is down & false is up
initTop = currentTop
return result
}
const scrollTask = btf.throttle(() => {
const currentTop = window.scrollY || document.documentElement.scrollTop
const isDown = scrollDirection(currentTop)
if (currentTop > 56) {
if (isDown) {
if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible')
if (isChatBtn && isChatShow === true) {
window.chatBtn.hide()
isChatShow = false
}
} else {
if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible')
if (isChatBtn && isChatShow === false) {
window.chatBtn.show()
isChatShow = true
}
}
$header.classList.add('nav-fixed')
if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') {
$rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)'
}
} else {
if (currentTop === 0) {
$header.classList.remove('nav-fixed', 'nav-visible')
}
$rightside.style.cssText = "opacity: ''; transform: ''"
}
isShowPercent && rightsideScrollPercent(currentTop)
if (document.body.scrollHeight <= innerHeight) {
$rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)'
}
}, 200)
window.scrollCollect = scrollTask
window.addEventListener('scroll', scrollCollect)
}
/**
* toc,anchor
*/
const scrollFnToDo = function () {
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.getElementsByClassName('toc-content')[0]
$tocLink = $cardToc.querySelectorAll('.toc-link')
$tocPercentage = $cardTocLayout.querySelector('.toc-percentage')
isExpand = $cardToc.classList.contains('is-expand')
window.mobileToc = {
open: () => {
$cardTocLayout.style.cssText = 'animation: toc-open .3s; opacity: 1; right: 55px'
},
close: () => {
$cardTocLayout.style.animation = 'toc-close .2s'
setTimeout(() => {
$cardTocLayout.style.cssText = "opacity:''; animation: ''; right: ''"
}, 100)
}
}
// toc元素點擊
$cardToc.addEventListener('click', e => {
e.preventDefault()
const target = e.target.classList
if (target.contains('toc-content')) return
const $target = target.contains('toc-link')
? e.target
: e.target.parentElement
btf.scrollToDest(btf.getEleTop(document.getElementById(decodeURI($target.getAttribute('href')).replace('#', ''))), 300)
if (window.innerWidth < 900) {
window.mobileToc.close()
}
})
autoScrollToc = item => {
const activePosition = item.getBoundingClientRect().top
const sidebarScrollTop = $cardToc.scrollTop
if (activePosition > (document.documentElement.clientHeight - 100)) {
$cardToc.scrollTop = sidebarScrollTop + 150
}
if (activePosition < 100) {
$cardToc.scrollTop = sidebarScrollTop - 150
}
}
}
// find head position & add active class
const list = $article.querySelectorAll('h1,h2,h3,h4,h5,h6')
let detectItem = ''
const findHeadPosition = function (top) {
if (top === 0) {
return false
}
let currentId = ''
let currentIndex = ''
list.forEach(function (ele, index) {
if (top > btf.getEleTop(ele) - 80) {
const id = ele.id
currentId = id ? '#' + encodeURI(id) : ''
currentIndex = index
}
})
if (detectItem === currentIndex) return
if (isAnchor) btf.updateAnchor(currentId)
detectItem = currentIndex
if (isToc) {
$cardToc.querySelectorAll('.active').forEach(i => { i.classList.remove('active') })
if (currentId === '') {
return
}
const currentActive = $tocLink[currentIndex]
currentActive.classList.add('active')
setTimeout(() => {
autoScrollToc(currentActive)
}, 0)
if (isExpand) return
let parent = currentActive.parentNode
for (; !parent.matches('.toc'); parent = parent.parentNode) {
if (parent.matches('li')) parent.classList.add('active')
}
}
}
// main of scroll
window.tocScrollFn = btf.throttle(() => {
const currentTop = window.scrollY || document.documentElement.scrollTop
if (isToc && GLOBAL_CONFIG.percent.toc) {
$tocPercentage.textContent = btf.getScrollPercent(currentTop, $article)
}
findHeadPosition(currentTop)
}, 100)
window.addEventListener('scroll', tocScrollFn)
}
const modeChangeFn = mode => {
if (!window.themeChange) {
return
}
const turnMode = item => window.themeChange[item](mode)
Object.keys(window.themeChange).forEach(item => {
if (['disqus', 'disqusjs'].includes(item)) {
setTimeout(() => turnMode(item), 300)
} else {
turnMode(item)
}
})
}
/**
* Rightside
*/
const rightSideFn = {
switchReadMode: () => { // read-mode
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)
const clickFn = () => {
$body.classList.remove('read-mode')
newEle.remove()
newEle.removeEventListener('click', clickFn)
}
newEle.addEventListener('click', clickFn)
},
switchDarkMode: () => { // Switch Between Light And Dark Mode
const willChangeMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'
if (willChangeMode === 'dark') {
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)
}
modeChangeFn(willChangeMode)
},
showOrHideBtn: (e) => { // rightside 點擊設置 按鈕 展開
const rightsideHideClassList = document.getElementById('rightside-config-hide').classList
rightsideHideClassList.toggle('show')
if (e.classList.contains('show')) {
rightsideHideClassList.add('status')
setTimeout(() => {
rightsideHideClassList.remove('status')
}, 300)
}
e.classList.toggle('show')
},
scrollToTop: () => { // Back to top
btf.scrollToDest(0, 500)
},
hideAsideBtn: () => { // Hide aside
const $htmlDom = document.documentElement.classList
const saveStatus = $htmlDom.contains('hide-aside') ? 'show' : 'hide'
saveToLocal.set('aside-status', saveStatus, 2)
$htmlDom.toggle('hide-aside')
},
runMobileToc: () => {
if (window.getComputedStyle(document.getElementById('card-toc')).getPropertyValue('opacity') === '0') window.mobileToc.open()
else window.mobileToc.close()
},
toggleChatDisplay: () => {
window.chatBtnFn()
}
}
document.getElementById('rightside').addEventListener('click', function (e) {
const $target = e.target.id ? e.target : e.target.parentNode
switch ($target.id) {
case 'go-up':
rightSideFn.scrollToTop()
break
case 'rightside_config':
rightSideFn.showOrHideBtn($target)
break
case 'mobile-toc-button':
rightSideFn.runMobileToc()
break
case 'readmode':
rightSideFn.switchReadMode()
break
case 'darkmode':
rightSideFn.switchDarkMode()
break
case 'hide-aside-btn':
rightSideFn.hideAsideBtn()
break
case 'chat-btn':
rightSideFn.toggleChatDisplay()
break
default:
break
}
})
/**
* menu
* 側邊欄sub-menu 展開/收縮
*/
const clickFnOfSubMenu = () => {
document.querySelectorAll('#sidebar-menus .site-page.group').forEach(function (item) {
item.addEventListener('click', function () {
this.classList.toggle('hide')
})
})
}
/**
* 複製時加上版權信息
*/
const addCopyright = () => {
const copyright = GLOBAL_CONFIG.copyright
document.body.oncopy = (e) => {
e.preventDefault()
const copyFont = window.getSelection(0).toString()
let textFont = copyFont
if (copyFont.length > copyright.limitCount) {
textFont = `${copyFont}\n\n\n${copyright.languages.author}\n${copyright.languages.link}${window.location.href}\n${copyright.languages.source}\n${copyright.languages.info}`
}
if (e.clipboardData) {
return e.clipboardData.setData('text', textFont)
} else {
return window.clipboardData.setData('text', textFont)
}
}
}
/**
* 網頁運行時間
*/
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 :not(.highlight) > table, #article-container > table')
if ($table.length) {
$table.forEach(item => {
btf.wrap(item, 'div', { class: 'table-wrap' })
})
}
}
/**
* tag-hide
*/
const clickFnOfTagHide = function () {
const $hideInline = document.querySelectorAll('#article-container .hide-button')
if ($hideInline.length) {
$hideInline.forEach(function (item) {
item.addEventListener('click', function (e) {
const $this = this
$this.classList.add('open')
const $fjGallery = $this.nextElementSibling.querySelectorAll('.fj-gallery')
$fjGallery.length && btf.initJustifiedGallery($fjGallery)
})
})
}
}
const tabsFn = {
clickFnOfTabs: function () {
document.querySelectorAll('#article-container .tab > button').forEach(function (item) {
item.addEventListener('click', function (e) {
const $this = this
const $tabItem = $this.parentNode
if (!$tabItem.classList.contains('active')) {
const $tabContent = $tabItem.parentNode.nextElementSibling
const $siblings = btf.siblings($tabItem, '.active')[0]
$siblings && $siblings.classList.remove('active')
$tabItem.classList.add('active')
const tabId = $this.getAttribute('data-href').replace('#', '')
const childList = [...$tabContent.children]
childList.forEach(item => {
if (item.id === tabId) item.classList.add('active')
else item.classList.remove('active')
})
const $isTabJustifiedGallery = $tabContent.querySelectorAll(`#${tabId} .fj-gallery`)
if ($isTabJustifiedGallery.length > 0) {
btf.initJustifiedGallery($isTabJustifiedGallery)
}
}
})
})
},
backToTop: () => {
document.querySelectorAll('#article-container .tabs .tab-to-top').forEach(function (item) {
item.addEventListener('click', function () {
btf.scrollToDest(btf.getEleTop(btf.getParents(this, '.tabs')), 300)
})
})
}
}
const toggleCardCategory = function () {
const $cardCategory = document.querySelectorAll('#aside-cat-list .card-category-list-item.parent i')
if ($cardCategory.length) {
$cardCategory.forEach(function (item) {
item.addEventListener('click', function (e) {
e.preventDefault()
const $this = this
$this.classList.toggle('expand')
const $parentEle = $this.parentNode.nextElementSibling
if (btf.isHidden($parentEle)) {
$parentEle.style.display = 'block'
} else {
$parentEle.style.display = 'none'
}
})
})
}
}
const switchComments = function () {
let switchDone = false
const $switchBtn = document.querySelector('#comment-switch > .switch-btn')
$switchBtn && $switchBtn.addEventListener('click', function () {
this.classList.toggle('move')
document.querySelectorAll('#post-comment > .comment-wrap > div').forEach(function (item) {
if (btf.isHidden(item)) {
item.style.cssText = 'display: block;animation: tabshow .5s'
} else {
item.style.cssText = "display: none;animation: ''"
}
})
if (!switchDone && typeof loadOtherComment === 'function') {
switchDone = true
loadOtherComment()
}
})
}
const addPostOutdateNotice = function () {
const data = GLOBAL_CONFIG.noticeOutdate
const diffDay = btf.diffDate(GLOBAL_CONFIG_SITE.postUpdate)
if (diffDay >= data.limitDay) {
const ele = document.createElement('div')
ele.className = 'post-outdate-notice'
ele.textContent = data.messagePrev + ' ' + diffDay + ' ' + data.messageNext
const $targetEle = document.getElementById('article-container')
if (data.position === 'top') {
$targetEle.insertBefore(ele, $targetEle.firstChild)
} else {
$targetEle.appendChild(ele)
}
}
}
const lazyloadImg = () => {
window.lazyLoadInstance = new LazyLoad({
elements_selector: 'img',
threshold: 0,
data_src: 'lazy-src'
})
}
const relativeDate = function (selector) {
selector.forEach(item => {
const timeVal = item.getAttribute('datetime')
item.textContent = btf.diffDate(timeVal, true)
item.style.display = 'inline'
})
}
const unRefreshFn = function () {
window.addEventListener('resize', () => {
adjustMenu(false)
btf.isHidden(document.getElementById('toggle-menu')) && mobileSidebarOpen && sidebarFn.close()
})
document.getElementById('menu-mask').addEventListener('click', e => { sidebarFn.close() })
clickFnOfSubMenu()
GLOBAL_CONFIG.islazyload && lazyloadImg()
GLOBAL_CONFIG.copyright !== undefined && addCopyright()
if (GLOBAL_CONFIG.autoDarkmode) {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
if (saveToLocal.get('theme') !== undefined) return
e.matches ? modeChangeFn('dark') : modeChangeFn('light')
})
}
}
window.refreshFn = function () {
initAdjust()
if (GLOBAL_CONFIG_SITE.isPost) {
GLOBAL_CONFIG.noticeOutdate !== undefined && 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()
}
scrollFnToDo()
GLOBAL_CONFIG_SITE.isHome && scrollDownInIndex()
addHighlightTool()
GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption()
scrollFn()
const $jgEle = document.querySelectorAll('#article-container .fj-gallery')
$jgEle.length && runJustifiedGallery($jgEle)
runLightbox()
addTableWrap()
clickFnOfTagHide()
tabsFn.clickFnOfTabs()
tabsFn.backToTop()
switchComments()
document.getElementById('toggle-menu').addEventListener('click', () => { sidebarFn.open() })
}
refreshFn()
unRefreshFn()
})

177
js/search/algolia.js Normal file
View File

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

360
js/search/local-search.js Normal file
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 += `<div class="local-search-hit-item"><a href="${url.href}"><span class="search-result-title">${this.highlightKeyword(title, slicesOfTitle[0])}</span>`
} else {
resultItem += `<div class="local-search-hit-item"><a href="${url.href}"><span class="search-result-title">${title}</span>`
}
slicesOfContent.forEach(slice => {
resultItem += `<p class="search-result">${this.highlightKeyword(content, slice)}...</p></a>`
})
resultItem += '</div>'
resultItems.push({
item: resultItem,
id: resultItems.length,
hitCount,
includedCount
})
})
return resultItems
}
fetchData () {
const isXml = !this.path.endsWith('json')
fetch(this.path)
.then(response => response.text())
.then(res => {
// Get the contents from search data
this.isfetched = true
this.datas = isXml
? [...new DOMParser().parseFromString(res, 'text/xml').querySelectorAll('entry')].map(element => ({
title: element.querySelector('title').textContent,
content: element.querySelector('content').textContent,
url: element.querySelector('url').textContent
}))
: JSON.parse(res)
// Only match articles with non-empty titles
this.datas = this.datas.filter(data => data.title).map(data => {
data.title = data.title.trim()
data.content = data.content ? data.content.trim().replace(/<[^>]+>/g, '') : ''
data.url = decodeURIComponent(data.url).replace(/\/{2,}/g, '/')
return data
})
// Remove loading animation
window.dispatchEvent(new Event('search:loaded'))
})
}
// Highlight by wrapping node in mark elements with the given class name
highlightText (node, slice, className) {
const val = node.nodeValue
let index = slice.start
const children = []
for (const { position, length } of slice.hits) {
const text = document.createTextNode(val.substring(index, position))
index = position + length
const mark = document.createElement('mark')
mark.className = className
mark.appendChild(document.createTextNode(val.substr(position, length)))
children.push(text, mark)
}
node.nodeValue = val.substring(index, slice.end)
children.forEach(element => {
node.parentNode.insertBefore(element, node)
})
}
// Highlight the search words provided in the url in the text
highlightSearchWords (body) {
const params = new URL(location.href).searchParams.get('highlight')
const keywords = params ? params.split(' ') : []
if (!keywords.length || !body) return
const walk = document.createTreeWalker(body, NodeFilter.SHOW_TEXT, null)
const allNodes = []
while (walk.nextNode()) {
if (!walk.currentNode.parentNode.matches('button, select, textarea, .mermaid')) allNodes.push(walk.currentNode)
}
allNodes.forEach(node => {
const [indexOfNode] = this.getIndexByWord(keywords, node.nodeValue)
if (!indexOfNode.length) return
const slice = this.mergeIntoSlice(0, node.nodeValue.length, indexOfNode)
this.highlightText(node, slice, 'search-keyword')
})
}
}
window.addEventListener('load', () => {
// Search
const { path, top_n_per_article, unescape, languages } = GLOBAL_CONFIG.localSearch
const localSearch = new LocalSearch({
path,
top_n_per_article,
unescape
})
const input = document.querySelector('#local-search-input input')
const statsItem = document.getElementById('local-search-stats-wrap')
const $loadingStatus = document.getElementById('loading-status')
const inputEventFunction = () => {
if (!localSearch.isfetched) return
const searchText = input.value.trim().toLowerCase()
if (searchText !== '') $loadingStatus.innerHTML = '<i class="fas fa-spinner fa-pulse"></i>'
const keywords = searchText.split(/[-\s]+/)
const container = document.getElementById('local-search-results')
let resultItems = []
if (searchText.length > 0) {
// Perform local searching
resultItems = localSearch.getResultItems(keywords)
}
if (keywords.length === 1 && keywords[0] === '') {
container.classList.add('no-result')
container.textContent = ''
} else if (resultItems.length === 0) {
container.textContent = ''
statsItem.innerHTML = `<div class="search-result-stats">${languages.hits_empty.replace(/\$\{query}/, searchText)}</div>`
} else {
resultItems.sort((left, right) => {
if (left.includedCount !== right.includedCount) {
return right.includedCount - left.includedCount
} else if (left.hitCount !== right.hitCount) {
return right.hitCount - left.hitCount
}
return right.id - left.id
})
const stats = languages.hits_stats.replace(/\$\{hits}/, resultItems.length)
container.classList.remove('no-result')
container.innerHTML = `<div class="search-result-list">${resultItems.map(result => result.item).join('')}</div>`
statsItem.innerHTML = `<br><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 = () => {
const bodyStyle = document.body.style
bodyStyle.width = '100%'
bodyStyle.overflow = 'hidden'
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 = () => {
const bodyStyle = document.body.style
bodyStyle.width = ''
bodyStyle.overflow = ''
btf.animateOut($searchDialog, 'search_close .5s')
btf.animateOut($searchMask, 'to_hide 0.5s')
window.removeEventListener('resize', fixSafariHeight)
}
const searchClickFn = () => {
document.querySelector('#search-button > .search').addEventListener('click', openSearch)
}
const 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()
})
})

115
js/tw_cn.js Normal file

File diff suppressed because one or more lines are too long

307
js/utils.js Normal file
View File

@ -0,0 +1,307 @@
const btf = {
debounce: function (func, wait, immediate) {
let timeout
return function () {
const context = this
const args = arguments
const later = function () {
timeout = null
if (!immediate) func.apply(context, args)
}
const callNow = immediate && !timeout
clearTimeout(timeout)
timeout = setTimeout(later, wait)
if (callNow) func.apply(context, args)
}
},
throttle: function (func, wait, options) {
let timeout, context, args
let previous = 0
if (!options) options = {}
const later = function () {
previous = options.leading === false ? 0 : new Date().getTime()
timeout = null
func.apply(context, args)
if (!timeout) context = args = null
}
const throttled = function () {
const now = new Date().getTime()
if (!previous && options.leading === false) previous = now
const remaining = wait - (now - previous)
context = this
args = arguments
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
},
sidebarPaddingR: () => {
const innerWidth = window.innerWidth
const clientWidth = document.body.clientWidth
const paddingRight = innerWidth - clientWidth
if (innerWidth !== clientWidth) {
document.body.style.paddingRight = paddingRight + 'px'
}
},
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: (d, more = false) => {
const dateNow = new Date()
const datePost = new Date(d)
const dateDiff = dateNow.getTime() - datePost.getTime()
const minute = 1000 * 60
const hour = minute * 60
const day = hour * 24
const month = day * 30
const { dateSuffix } = GLOBAL_CONFIG
if (!more) return parseInt(dateDiff / day)
const monthCount = dateDiff / month
const dayCount = dateDiff / day
const hourCount = dateDiff / hour
const minuteCount = dateDiff / minute
if (monthCount > 12) return datePost.toISOString().slice(0, 10)
if (monthCount >= 1) return `${parseInt(monthCount)} ${dateSuffix.month}`
if (dayCount >= 1) return `${parseInt(dayCount)} ${dateSuffix.day}`
if (hourCount >= 1) return `${parseInt(hourCount)} ${dateSuffix.hour}`
if (minuteCount >= 1) return `${parseInt(minuteCount)} ${dateSuffix.min}`
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.pageYOffset
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
}
let start = null
pos = +pos
window.requestAnimationFrame(function step (currentTime) {
start = !start ? currentTime : start
const progress = currentTime - start
if (currentPos < pos) {
window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos)
} else {
window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time))
}
if (progress < time) {
window.requestAnimationFrame(step)
} else {
window.scrollTo(0, pos)
}
})
},
animateIn: (ele, text) => {
ele.style.display = 'block'
ele.style.animation = text
},
animateOut: (ele, text) => {
ele.addEventListener('animationend', function f () {
ele.style.display = ''
ele.style.animation = ''
ele.removeEventListener('animationend', f)
})
ele.style.animation = text
},
getParents: (elem, selector) => {
for (; elem && elem !== document; elem = elem.parentNode) {
if (elem.matches(selector)) return elem
}
return null
},
siblings: (ele, selector) => {
return [...ele.parentNode.children].filter((child) => {
if (selector) {
return child !== ele && child.matches(selector)
}
return child !== ele
})
},
/**
* @param {*} selector
* @param {*} eleType the type of create element
* @param {*} options object key: value
*/
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)
},
unwrap: el => {
const parent = el.parentNode
if (parent && parent !== document.body) {
parent.replaceChild(el, parent)
}
},
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 === 'mediumZoom') {
mediumZoom(ele, { background: 'var(--zoom-bg)' })
}
if (service === 'fancybox') {
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) {
Fancybox.bind('[data-fancybox]', {
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']
}
}
})
window.fancyboxRun = true
}
}
},
initJustifiedGallery: function (selector) {
const runJustifiedGallery = i => {
if (!btf.isHidden(i)) {
fjGallery(i, {
itemSelector: '.fj-gallery-item',
rowHeight: i.getAttribute('data-rowHeight'),
gutter: 4,
onJustify: function () {
this.$container.style.opacity = '1'
}
})
}
}
if (Array.from(selector).length === 0) runJustifiedGallery(selector)
else selector.forEach(i => { runJustifiedGallery(i) })
},
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: (currentTop, ele) => {
const docHeight = ele.clientHeight
const winHeight = document.documentElement.clientHeight
const headerHeight = ele.offsetTop
const contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : (document.documentElement.scrollHeight - winHeight)
const scrollPercent = (currentTop - headerHeight) / (contentMath)
const scrollPercentRounded = Math.round(scrollPercent * 100)
const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded
return percentage
},
addModeChange: (name, fn) => {
if (window.themeChange && window.themeChange[name]) return
window.themeChange = {
...window.themeChange,
[name]: fn
}
}
}

297
lib/hbe.js Normal file
View File

@ -0,0 +1,297 @@
(() => {
'use strict';
const cryptoObj = window.crypto || window.msCrypto;
const storage = window.localStorage;
const storageName = 'hexo-blog-encrypt:#' + window.location.pathname;
const keySalt = textToArray('hexo-blog-encrypt的作者们都是大帅比!');
const ivSalt = textToArray('hexo-blog-encrypt是地表最强Hexo加密插件!');
// As we can't detect the wrong password with AES-CBC,
// so adding an empty div and check it when decrption.
const knownPrefix = "<hbe-prefix></hbe-prefix>";
const mainElement = document.getElementById('hexo-blog-encrypt');
const wrongPassMessage = mainElement.dataset['wpm'];
const wrongHashMessage = mainElement.dataset['whm'];
const dataElement = mainElement.getElementsByTagName('script')['hbeData'];
const encryptedData = dataElement.innerText;
const HmacDigist = dataElement.dataset['hmacdigest'];
function hexToArray(s) {
return new Uint8Array(s.match(/[\da-f]{2}/gi).map((h => {
return parseInt(h, 16);
})));
}
function textToArray(s) {
var i = s.length;
var n = 0;
var ba = new Array()
for (var j = 0; j < i;) {
var c = s.codePointAt(j);
if (c < 128) {
ba[n++] = c;
j++;
} else if ((c > 127) && (c < 2048)) {
ba[n++] = (c >> 6) | 192;
ba[n++] = (c & 63) | 128;
j++;
} else if ((c > 2047) && (c < 65536)) {
ba[n++] = (c >> 12) | 224;
ba[n++] = ((c >> 6) & 63) | 128;
ba[n++] = (c & 63) | 128;
j++;
} else {
ba[n++] = (c >> 18) | 240;
ba[n++] = ((c >> 12) & 63) | 128;
ba[n++] = ((c >> 6) & 63) | 128;
ba[n++] = (c & 63) | 128;
j += 2;
}
}
return new Uint8Array(ba);
}
function arrayBufferToHex(arrayBuffer) {
if (typeof arrayBuffer !== 'object' || arrayBuffer === null || typeof arrayBuffer.byteLength !== 'number') {
throw new TypeError('Expected input to be an ArrayBuffer')
}
var view = new Uint8Array(arrayBuffer)
var result = ''
var value
for (var i = 0; i < view.length; i++) {
value = view[i].toString(16)
result += (value.length === 1 ? '0' + value : value)
}
return result
}
async function getExecutableScript(oldElem) {
let out = document.createElement('script');
const attList = ['type', 'text', 'src', 'crossorigin', 'defer', 'referrerpolicy'];
attList.forEach((att) => {
if (oldElem[att])
out[att] = oldElem[att];
})
return out;
}
async function convertHTMLToElement(content) {
let out = document.createElement('div');
out.innerHTML = content;
out.querySelectorAll('script').forEach(async (elem) => {
elem.replaceWith(await getExecutableScript(elem));
});
return out;
}
function getKeyMaterial(password) {
let encoder = new TextEncoder();
return cryptoObj.subtle.importKey(
'raw',
encoder.encode(password),
{
'name': 'PBKDF2',
},
false,
[
'deriveKey',
'deriveBits',
]
);
}
function getHmacKey(keyMaterial) {
return cryptoObj.subtle.deriveKey({
'name': 'PBKDF2',
'hash': 'SHA-256',
'salt': keySalt.buffer,
'iterations': 1024
}, keyMaterial, {
'name': 'HMAC',
'hash': 'SHA-256',
'length': 256,
}, true, [
'verify',
]);
}
function getDecryptKey(keyMaterial) {
return cryptoObj.subtle.deriveKey({
'name': 'PBKDF2',
'hash': 'SHA-256',
'salt': keySalt.buffer,
'iterations': 1024,
}, keyMaterial, {
'name': 'AES-CBC',
'length': 256,
}, true, [
'decrypt',
]);
}
function getIv(keyMaterial) {
return cryptoObj.subtle.deriveBits({
'name': 'PBKDF2',
'hash': 'SHA-256',
'salt': ivSalt.buffer,
'iterations': 512,
}, keyMaterial, 16 * 8);
}
async function verifyContent(key, content) {
const encoder = new TextEncoder();
const encoded = encoder.encode(content);
let signature = hexToArray(HmacDigist);
const result = await cryptoObj.subtle.verify({
'name': 'HMAC',
'hash': 'SHA-256',
}, key, signature, encoded);
console.log(`Verification result: ${result}`);
if (!result) {
alert(wrongHashMessage);
console.log(`${wrongHashMessage}, got `, signature, ` but proved wrong.`);
}
return result;
}
async function decrypt(decryptKey, iv, hmacKey) {
let typedArray = hexToArray(encryptedData);
const result = await cryptoObj.subtle.decrypt({
'name': 'AES-CBC',
'iv': iv,
}, decryptKey, typedArray.buffer).then(async (result) => {
const decoder = new TextDecoder();
const decoded = decoder.decode(result);
// check the prefix, if not then we can sure here is wrong password.
if (!decoded.startsWith(knownPrefix)) {
throw "Decode successfully but not start with KnownPrefix.";
}
const hideButton = document.createElement('button');
hideButton.textContent = 'Encrypt again';
hideButton.type = 'button';
hideButton.classList.add("hbe-button");
hideButton.addEventListener('click', () => {
window.localStorage.removeItem(storageName);
window.location.reload();
});
document.getElementById('hexo-blog-encrypt').style.display = 'inline';
document.getElementById('hexo-blog-encrypt').innerHTML = '';
document.getElementById('hexo-blog-encrypt').appendChild(await convertHTMLToElement(decoded));
document.getElementById('hexo-blog-encrypt').appendChild(hideButton);
// support html5 lazyload functionality.
document.querySelectorAll('img').forEach((elem) => {
if (elem.getAttribute("data-src") && !elem.src) {
elem.src = elem.getAttribute('data-src');
}
});
// support theme-next refresh
window.NexT && NexT.boot && typeof NexT.boot.refresh === 'function' && NexT.boot.refresh();
// TOC part
var tocDiv = document.getElementById("toc-div");
if (tocDiv) {
tocDiv.style.display = 'inline';
}
var tocDivs = document.getElementsByClassName('toc-div-class');
if (tocDivs && tocDivs.length > 0) {
for (var idx = 0; idx < tocDivs.length; idx++) {
tocDivs[idx].style.display = 'inline';
}
}
// trigger event
var event = new Event('hexo-blog-decrypt');
window.dispatchEvent(event);
return await verifyContent(hmacKey, decoded);
}).catch((e) => {
alert(wrongPassMessage);
console.log(e);
return false;
});
return result;
}
function hbeLoader() {
const oldStorageData = JSON.parse(storage.getItem(storageName));
if (oldStorageData) {
console.log(`Password got from localStorage(${storageName}): `, oldStorageData);
const sIv = hexToArray(oldStorageData.iv).buffer;
const sDk = oldStorageData.dk;
const sHmk = oldStorageData.hmk;
cryptoObj.subtle.importKey('jwk', sDk, {
'name': 'AES-CBC',
'length': 256,
}, true, [
'decrypt',
]).then((dkCK) => {
cryptoObj.subtle.importKey('jwk', sHmk, {
'name': 'HMAC',
'hash': 'SHA-256',
'length': 256,
}, true, [
'verify',
]).then((hmkCK) => {
decrypt(dkCK, sIv, hmkCK).then((result) => {
if (!result) {
storage.removeItem(storageName);
}
});
});
});
}
mainElement.addEventListener('keydown', async (event) => {
if (event.isComposing || event.keyCode === 13) {
const password = document.getElementById('hbePass').value;
const keyMaterial = await getKeyMaterial(password);
const hmacKey = await getHmacKey(keyMaterial);
const decryptKey = await getDecryptKey(keyMaterial);
const iv = await getIv(keyMaterial);
decrypt(decryptKey, iv, hmacKey).then((result) => {
console.log(`Decrypt result: ${result}`);
if (result) {
cryptoObj.subtle.exportKey('jwk', decryptKey).then((dk) => {
cryptoObj.subtle.exportKey('jwk', hmacKey).then((hmk) => {
const newStorageData = {
'dk': dk,
'iv': arrayBufferToHex(iv),
'hmk': hmk,
};
storage.setItem(storageName, JSON.stringify(newStorageData));
});
});
}
});
}
});
}
hbeLoader();
})();

204
notice/index.html Normal file
View File

@ -0,0 +1,204 @@
<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>公告 | The Blog</title><meta name="author" content="Jason"><meta name="copyright" content="Jason"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="2023 03-1 建立博客 09-10 改进博客中图片的存储方案 09-11 博客增加百度访问统计功能 09-12 博客中增加公告页">
<meta property="og:type" content="website">
<meta property="og:title" content="公告">
<meta property="og:url" content="https://jasonsgong.gitee.io/notice/index.html">
<meta property="og:site_name" content="The Blog">
<meta property="og:description" content="2023 03-1 建立博客 09-10 改进博客中图片的存储方案 09-11 博客增加百度访问统计功能 09-12 博客中增加公告页">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://jasonsgong.gitee.io/img/5.jpg">
<meta property="article:published_time" content="2023-09-12T05:52:08.000Z">
<meta property="article:modified_time" content="2023-09-12T03:17:10.000Z">
<meta property="article:author" content="Jason">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://jasonsgong.gitee.io/img/5.jpg"><link rel="shortcut icon" href="/img/%E5%9B%BE%E6%A0%87.png"><link rel="canonical" href="https://jasonsgong.gitee.io/notice/index.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//hm.baidu.com"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox/fancybox.min.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?863f84ff1342665d6b55193272aea7b2";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script><script>const GLOBAL_CONFIG = {
root: '/',
algolia: undefined,
localSearch: {"path":"/search.xml","preload":true,"top_n_per_article":1,"unescape":false,"languages":{"hits_empty":"找不到您查询的内容:${query}","hits_stats":"共找到 ${hits} 篇文章"}},
translate: undefined,
noticeOutdate: undefined,
highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":400},
copy: {
success: '复制成功',
error: '复制错误',
noSupport: '浏览器不支持'
},
relativeDate: {
homepage: true,
post: true
},
runtime: '天',
dateSuffix: {
just: '刚刚',
min: '分钟前',
hour: '小时前',
day: '天前',
month: '个月前'
},
copyright: undefined,
lightbox: 'mediumZoom',
Snackbar: {"chs_to_cht":"你已切换为繁体","cht_to_chs":"你已切换为简体","day_to_night":"你已切换为深色模式","night_to_day":"你已切换为浅色模式","bgLight":"#008080","bgDark":"#008080","position":"top-center"},
source: {
justifiedGallery: {
js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
}
},
isPhotoFigcaption: false,
islazyload: false,
isAnchor: false,
percent: {
toc: true,
rightside: false,
},
autoDarkmode: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
title: '公告',
isPost: false,
isHome: false,
isHighlightShrink: false,
isToc: false,
postUpdate: '2023-09-12 11:17:10'
}</script><noscript><style type="text/css">
#nav {
opacity: 1
}
.justified-gallery img {
opacity: 1
}
#recent-posts time,
#post-meta time {
display: inline !important
}
</style></noscript><script>(win=>{
win.saveToLocal = {
set: function setWithExpiry(key, value, ttl) {
if (ttl === 0) return
const now = new Date()
const expiryDay = ttl * 86400000
const item = {
value: value,
expiry: now.getTime() + expiryDay,
}
localStorage.setItem(key, JSON.stringify(item))
},
get: function getWithExpiry(key) {
const itemStr = localStorage.getItem(key)
if (!itemStr) {
return undefined
}
const item = JSON.parse(itemStr)
const now = new Date()
if (now.getTime() > item.expiry) {
localStorage.removeItem(key)
return undefined
}
return item.value
}
}
win.getScript = url => new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
script.async = true
script.onerror = reject
script.onload = script.onreadystatechange = function() {
const loadState = this.readyState
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
script.onload = script.onreadystatechange = null
resolve()
}
document.head.appendChild(script)
})
win.getCSS = (url,id = false) => new Promise((resolve, reject) => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = url
if (id) link.id = id
link.onerror = reject
link.onload = link.onreadystatechange = function() {
const loadState = this.readyState
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
link.onload = link.onreadystatechange = null
resolve()
}
document.head.appendChild(link)
})
win.activateDarkMode = function () {
document.documentElement.setAttribute('data-theme', 'dark')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
}
}
win.activateLightMode = function () {
document.documentElement.setAttribute('data-theme', 'light')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
}
}
const t = saveToLocal.get('theme')
if (t === 'dark') activateDarkMode()
else if (t === 'light') activateLightMode()
const asideStatus = saveToLocal.get('aside-status')
if (asideStatus !== undefined) {
if (asideStatus === 'hide') {
document.documentElement.classList.add('hide-aside')
} else {
document.documentElement.classList.remove('hide-aside')
}
}
const detectApple = () => {
if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
document.documentElement.classList.add('apple')
}
}
detectApple()
})(window)</script><!-- hexo injector head_end start --><link rel="stylesheet" href="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiperstyle.css" media="print" onload="this.media='all'"><!-- hexo injector head_end end --><meta name="generator" content="Hexo 6.3.0"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="/img/avatar.jpg" onerror="onerror=null;src='/img/loading.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">70</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">37</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">6</div></a></div><br/><div class="menus_items"><div class="menus_item"><a class="site-page" target="_blank" rel="noopener" href="https://gitee.com/JasonsGong/jasonsgong/pages"><i class="fa-fw fas fa-sync-alt"></i><span> 更新</span></a></div><div class="menus_item"><a class="site-page" target="_blank" rel="noopener" href="https://www.tutorialspoint.com/compile_java8_online.php"><i class="fa-fw fas fa-code"></i><span> 代码</span></a></div><div class="menus_item"><a class="site-page" href="/notice/"><i class="fa-fw far fa-paper-plane"></i><span> 公告</span></a></div><div class="menus_item"><a class="site-page" href="/website/bookmarks.html"><i class="fa-fw fas fa-desktop"></i><span> 网址</span></a></div><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div></div></div></div><div class="page" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog-info"><a href="/" title="The Blog"><span class="site-name">The Blog</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" target="_blank" rel="noopener" href="https://gitee.com/JasonsGong/jasonsgong/pages"><i class="fa-fw fas fa-sync-alt"></i><span> 更新</span></a></div><div class="menus_item"><a class="site-page" target="_blank" rel="noopener" href="https://www.tutorialspoint.com/compile_java8_online.php"><i class="fa-fw fas fa-code"></i><span> 代码</span></a></div><div class="menus_item"><a class="site-page" href="/notice/"><i class="fa-fw far fa-paper-plane"></i><span> 公告</span></a></div><div class="menus_item"><a class="site-page" href="/website/bookmarks.html"><i class="fa-fw fas fa-desktop"></i><span> 网址</span></a></div><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout hide-aside" id="content-inner"><div id="page"><h1 class="page-title">公告</h1><div id="article-container"><div class="timeline green"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>2023</p>
</div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>03-1</p>
</div></div><div class='timeline-item-content'><p>建立博客</p>
</div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>09-10</p>
</div></div><div class='timeline-item-content'><p>改进博客中图片的存储方案</p>
</div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>09-11</p>
</div></div><div class='timeline-item-content'><p>博客增加百度访问统计功能</p>
</div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>09-12</p>
</div></div><div class='timeline-item-content'><p>博客中增加公告页</p>
</div></div></div>
</div></div></main><footer id="footer"><div id="footer-wrap"><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/medium-zoom/dist/medium-zoom.min.js"></script><script src="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.js"></script><div class="js-pjax"></div><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span> 数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><br/><div class="no-result" id="local-search-results"></div><div id="local-search-stats-wrap"></div></div></div><div id="search-mask"></div><script src="/js/search/local-search.js"></script></div></div><!-- hexo injector body_end start --><script data-pjax>
function butterfly_swiper_injector_config(){
var parent_div_git = document.getElementById('recent-posts');
var item_html = '<div class="recent-post-item" style="height: auto;width: 100%"><div class="blog-slider swiper-container-fade swiper-container-horizontal" id="swiper_container"><div class="blog-slider__wrp swiper-wrapper" style="transition-duration: 0ms;"><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="posts/19306.html" alt=""><img width="48" height="48" src="/img/1.jpg" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2023-04-21</span><a class="blog-slider__title" href="posts/19306.html" alt="">Docker容器化技术</a><div class="blog-slider__text">Docker</div><a class="blog-slider__button" href="posts/19306.html" alt="">详情 </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="posts/47003.html" alt=""><img width="48" height="48" src="/img/1.jpg" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2023-03-10</span><a class="blog-slider__title" href="posts/47003.html" alt="">常用正则表达式大全</a><div class="blog-slider__text">正则表达式</div><a class="blog-slider__button" href="posts/47003.html" alt="">详情 </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="posts/20683.html" alt=""><img width="48" height="48" src="/img/3.jpg" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2023-06-05</span><a class="blog-slider__title" href="posts/20683.html" alt="">Linux中开发环境的搭建</a><div class="blog-slider__text">环境搭建</div><a class="blog-slider__button" href="posts/20683.html" alt="">详情 </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="posts/63333.html" alt=""><img width="48" height="48" src="/img/1.jpg" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2023-06-03</span><a class="blog-slider__title" href="posts/63333.html" alt="">开发环境的搭建</a><div class="blog-slider__text">环境搭建</div><a class="blog-slider__button" href="posts/63333.html" alt="">详情 </a></div></div></div><div class="blog-slider__pagination swiper-pagination-clickable swiper-pagination-bullets"></div></div></div>';
parent_div_git.insertAdjacentHTML("afterbegin",item_html)
}
var elist = 'undefined'.split(',');
var cpage = location.pathname;
var epage = '/';
var flag = 0;
for (var i=0;i<elist.length;i++){
if (cpage.includes(elist[i])){
flag++;
}
}
if ((epage ==='all')&&(flag == 0)){
butterfly_swiper_injector_config();
}
else if (epage === cpage){
butterfly_swiper_injector_config();
}
</script><script defer src="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.js"></script><script defer data-pjax src="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper_init.js"></script><!-- hexo injector body_end end --></body></html>

315
page/2/index.html Normal file

File diff suppressed because one or more lines are too long

403
page/3/index.html Normal file

File diff suppressed because one or more lines are too long

276
page/4/index.html Normal file

File diff suppressed because one or more lines are too long

271
page/5/index.html Normal file

File diff suppressed because one or more lines are too long

307
page/6/index.html Normal file

File diff suppressed because one or more lines are too long

235
page/7/index.html Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

BIN
pdf/Java8实战.pdf Normal file

Binary file not shown.

BIN
pdf/Java开发_AAA_N年.pdf Normal file

Binary file not shown.

Binary file not shown.

BIN
pdf/MyBatis.pdf Normal file

Binary file not shown.

BIN
pdf/MySQL-基础篇.pdf Normal file

Binary file not shown.

BIN
pdf/MySQL-运维篇.pdf Normal file

Binary file not shown.

BIN
pdf/MySQL-进阶篇.pdf Normal file

Binary file not shown.

BIN
pdf/MySQL5.7.19安装.pdf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
pdf/SSM整合.pdf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
pdf/简历.pdf Normal file

Binary file not shown.

BIN
pdf/简历模板_CN.pdf Normal file

Binary file not shown.

Binary file not shown.

BIN
pdf/精通Linux.第2版.pdf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
pictures/1573636765632.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
pictures/1573649804623.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Some files were not shown because too many files have changed in this diff Show More