Site updated: 2023-04-26 14:12:07
|
|
@ -0,0 +1,188 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<title>随言碎语</title>
|
||||
|
||||
<subtitle>咕叽咕叽</subtitle>
|
||||
<link href="http://kiki.kim/atom.xml" rel="self"/>
|
||||
|
||||
<link href="http://kiki.kim/"/>
|
||||
<updated>2023-04-22T06:40:08.722Z</updated>
|
||||
<id>http://kiki.kim/</id>
|
||||
|
||||
<author>
|
||||
<name>小梦同学的blog</name>
|
||||
|
||||
</author>
|
||||
|
||||
<generator uri="https://hexo.io/">Hexo</generator>
|
||||
|
||||
<entry>
|
||||
<title>esxi常规配置</title>
|
||||
<link href="http://kiki.kim/2023/03/26/esxi%E5%B8%B8%E8%A7%84%E9%85%8D%E7%BD%AE/"/>
|
||||
<id>http://kiki.kim/2023/03/26/esxi%E5%B8%B8%E8%A7%84%E9%85%8D%E7%BD%AE/</id>
|
||||
<published>2023-03-26T03:45:22.000Z</published>
|
||||
<updated>2023-04-22T06:40:08.722Z</updated>
|
||||
|
||||
|
||||
<summary type="html"><p>esxi修改网卡顺序、网卡直通、修改安全策略、开机自动启动虚拟机。</p></summary>
|
||||
|
||||
|
||||
|
||||
|
||||
<category term="esxi" scheme="http://kiki.kim/tags/esxi/"/>
|
||||
|
||||
<category term="软路由" scheme="http://kiki.kim/tags/%E8%BD%AF%E8%B7%AF%E7%94%B1/"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<title>esxi安装homeassistant</title>
|
||||
<link href="http://kiki.kim/2023/03/24/esxi%E5%AE%89%E8%A3%85homeassistant/"/>
|
||||
<id>http://kiki.kim/2023/03/24/esxi%E5%AE%89%E8%A3%85homeassistant/</id>
|
||||
<published>2023-03-24T12:15:04.000Z</published>
|
||||
<updated>2023-04-22T08:51:44.267Z</updated>
|
||||
|
||||
|
||||
<summary type="html"><p>在esxi上安装homeassistant</p></summary>
|
||||
|
||||
|
||||
|
||||
|
||||
<category term="esxi" scheme="http://kiki.kim/tags/esxi/"/>
|
||||
|
||||
<category term="homeassistant" scheme="http://kiki.kim/tags/homeassistant/"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<title>esxi+openwrt作为旁路由</title>
|
||||
<link href="http://kiki.kim/2023/03/24/esxi%E5%AE%89%E8%A3%85openwrt/"/>
|
||||
<id>http://kiki.kim/2023/03/24/esxi%E5%AE%89%E8%A3%85openwrt/</id>
|
||||
<published>2023-03-24T12:15:04.000Z</published>
|
||||
<updated>2023-04-22T08:39:45.162Z</updated>
|
||||
|
||||
|
||||
<summary type="html"><p>在esxi上安装openwrt,并作为旁路由来使用。</p></summary>
|
||||
|
||||
|
||||
|
||||
|
||||
<category term="esxi" scheme="http://kiki.kim/tags/esxi/"/>
|
||||
|
||||
<category term="openwrt" scheme="http://kiki.kim/tags/openwrt/"/>
|
||||
|
||||
<category term="软路由" scheme="http://kiki.kim/tags/%E8%BD%AF%E8%B7%AF%E7%94%B1/"/>
|
||||
|
||||
<category term="旁路由" scheme="http://kiki.kim/tags/%E6%97%81%E8%B7%AF%E7%94%B1/"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<title>esxi安装群晖dsm7.1</title>
|
||||
<link href="http://kiki.kim/2023/03/24/esxi%E5%AE%89%E8%A3%85%E7%BE%A4%E6%99%96dsm7.1/"/>
|
||||
<id>http://kiki.kim/2023/03/24/esxi%E5%AE%89%E8%A3%85%E7%BE%A4%E6%99%96dsm7.1/</id>
|
||||
<published>2023-03-24T12:15:04.000Z</published>
|
||||
<updated>2023-04-22T08:51:15.950Z</updated>
|
||||
|
||||
|
||||
<summary type="html"><p>在esxi上安装DSM</p></summary>
|
||||
|
||||
|
||||
|
||||
|
||||
<category term="esxi" scheme="http://kiki.kim/tags/esxi/"/>
|
||||
|
||||
<category term="群晖" scheme="http://kiki.kim/tags/%E7%BE%A4%E6%99%96/"/>
|
||||
|
||||
<category term="DSM" scheme="http://kiki.kim/tags/DSM/"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<title>esxi+openwrt+dsm+homeassistant 软路由 all in one</title>
|
||||
<link href="http://kiki.kim/2023/03/23/esxi+openwrt+dsm+homeassistant-%E8%BD%AF%E8%B7%AF%E7%94%B1all-in-one/"/>
|
||||
<id>http://kiki.kim/2023/03/23/esxi+openwrt+dsm+homeassistant-%E8%BD%AF%E8%B7%AF%E7%94%B1all-in-one/</id>
|
||||
<published>2023-03-23T13:25:34.000Z</published>
|
||||
<updated>2023-04-24T04:53:03.818Z</updated>
|
||||
|
||||
|
||||
<summary type="html"><p>软路由 all in one,在J425小主机上安装esxi+openwrt+dsm+homeassistant,集软路由、网盘、智能家居控制于一体。</p></summary>
|
||||
|
||||
|
||||
|
||||
|
||||
<category term="esxi" scheme="http://kiki.kim/tags/esxi/"/>
|
||||
|
||||
<category term="homeassistant" scheme="http://kiki.kim/tags/homeassistant/"/>
|
||||
|
||||
<category term="openwrt" scheme="http://kiki.kim/tags/openwrt/"/>
|
||||
|
||||
<category term="dsm" scheme="http://kiki.kim/tags/dsm/"/>
|
||||
|
||||
<category term="软路由" scheme="http://kiki.kim/tags/%E8%BD%AF%E8%B7%AF%E7%94%B1/"/>
|
||||
|
||||
<category term="群晖" scheme="http://kiki.kim/tags/%E7%BE%A4%E6%99%96/"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<title>esxi8.0安装</title>
|
||||
<link href="http://kiki.kim/2023/03/23/esxi8.0%E5%AE%89%E8%A3%85/"/>
|
||||
<id>http://kiki.kim/2023/03/23/esxi8.0%E5%AE%89%E8%A3%85/</id>
|
||||
<published>2023-03-23T13:25:34.000Z</published>
|
||||
<updated>2023-04-24T01:37:17.777Z</updated>
|
||||
|
||||
|
||||
<summary type="html"><p>esxi 8.0的安装。</p></summary>
|
||||
|
||||
|
||||
|
||||
|
||||
<category term="esxi" scheme="http://kiki.kim/tags/esxi/"/>
|
||||
|
||||
<category term="软路由" scheme="http://kiki.kim/tags/%E8%BD%AF%E8%B7%AF%E7%94%B1/"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<title>VMware安装centos7</title>
|
||||
<link href="http://kiki.kim/2020/01/03/VMware%E5%AE%89%E8%A3%85centos7/"/>
|
||||
<id>http://kiki.kim/2020/01/03/VMware%E5%AE%89%E8%A3%85centos7/</id>
|
||||
<published>2020-01-03T13:25:34.000Z</published>
|
||||
<updated>2023-04-22T06:02:29.866Z</updated>
|
||||
|
||||
|
||||
<summary type="html"><p>在VMware Workstation上安装centos。</p></summary>
|
||||
|
||||
|
||||
|
||||
|
||||
<category term="VMware" scheme="http://kiki.kim/tags/VMware/"/>
|
||||
|
||||
<category term="centos" scheme="http://kiki.kim/tags/centos/"/>
|
||||
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<title>Hello World</title>
|
||||
<link href="http://kiki.kim/2019/12/30/hello-world/"/>
|
||||
<id>http://kiki.kim/2019/12/30/hello-world/</id>
|
||||
<published>2019-12-30T15:25:34.000Z</published>
|
||||
<updated>2023-04-22T05:46:03.233Z</updated>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<summary type="html"><p>欢迎来到我的博客,这是我的第一篇博客,由hexo+next构建。</p>
|
||||
</summary>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</entry>
|
||||
|
||||
</feed>
|
||||
|
|
@ -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: 400px;
|
||||
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 }}} */
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/* build time:Tue Apr 25 2023 15:41:31 GMT+0800 (GMT+08:00)*/
|
||||
.links-content{margin-top:1rem}.link-navigation::after{content:" ";display:block;clear:both}.card{width:130px;font-size:1rem;padding:0;border-radius:4px;transition-duration:.15s;margin-bottom:1rem;display:block;float:left;box-shadow:0 2px 6px 0 rgba(0,0,0,.12);background:#f5f5f5}.card{margin-left:16px}@media(max-width:567px){.card{margin-left:16px;width:calc((100% - 16px)/ 2)}.card:nth-child(2n+1){margin-left:0}.card:not(:nth-child(2n+1)){margin-left:16px}}@media(min-width:567px){.card{margin-left:16px;width:calc((100% - 32px)/ 3)}.card:nth-child(3n+1){margin-left:0}.card:not(:nth-child(3n+1)){margin-left:16px}}@media(min-width:768px){.card{margin-left:16px;width:calc((100% - 48px)/ 4)}.card:nth-child(4n+1){margin-left:0}.card:not(:nth-child(4n+1)){margin-left:16px}}@media(min-width:1200px){.card{margin-left:16px;width:calc((100% - 64px)/ 5)}.card:nth-child(5n+1){margin-left:0}.card:not(:nth-child(5n+1)){margin-left:16px}}.card:hover{transform:scale(1.1);box-shadow:0 2px 6px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04)}.card .thumb{width:100%;height:0;padding-bottom:100%;background-size:100% 100%!important}.posts-expand .post-body img{margin:0;padding:0;border:0}.card .card-header{display:block;text-align:center;padding:1rem .25rem;font-weight:500;color:#333;white-space:normal}.card .card-header a{font-style:normal;color:#2bbc8a;font-weight:700;text-decoration:none;border:0}.card .card-header a:hover{color:#d480aa;text-decoration:none;border:0}
|
||||
/* rebuild by neat */
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/* build time:Tue Apr 25 2023 15:41:35 GMT+0800 (GMT+08:00)*/
|
||||
body{margin-top:2rem}.use-motion .collection-header,.use-motion .comments,.use-motion .menu-item,.use-motion .pagination,.use-motion .post-block,.use-motion .post-body,.use-motion .post-header,.use-motion .sidebar,.use-motion .sidebar-inner{visibility:visible}.use-motion .column,.use-motion .footer,.use-motion .site-brand-container .toggle{opacity:initial}.use-motion .custom-logo-image,.use-motion .site-subtitle,.use-motion .site-title{opacity:initial;top:initial}.use-motion .logo-line{transform:scaleX(1)}.search-pop-overlay,.sidebar-nav{display:none}.sidebar-panel{display:block}.noscript-warning{background-color:#f55;color:#fff;font-family:sans-serif;font-size:1rem;font-weight:700;left:0;position:fixed;text-align:center;top:0;width:100%;z-index:50}
|
||||
/* rebuild by neat */
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 435 B |
|
After Width: | Height: | Size: 640 B |
|
After Width: | Height: | Size: 5.2 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" id="NexT" width="512" height="512" x="0" y="0" enable-background="new 0 0 512 512" version="1.1" viewBox="0 0 512 512" xml:space="preserve"><metadata id="metadata3390"/><path style="fill:#fff;fill-opacity:1" d="M 256.4,25.8 56.4,141.3 56,371.5 255.6,486.2 455.6,370.7 456,140.5 Z"/><path style="fill:#222;fill-opacity:1" id="path3384" d="M 256.4,25.8 56.4,141.3 56,371.5 255.6,486.2 455.6,370.7 456,140.5 Z m 92.6,328.8 -18.4,10.7 -18.6,-11 0,0 -112,-142.3 0,142.6 -18.4,10.7 -18.6,-11 0,-197 18.5,-10.6 18.5,10.8 0,0 112,144.5 0,-144.6 18.5,-10.6 18.5,10.8 z"/></svg>
|
||||
|
After Width: | Height: | Size: 647 B |
|
After Width: | Height: | Size: 74 KiB |
|
|
@ -0,0 +1,56 @@
|
|||
/* global CONFIG */
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
'use strict';
|
||||
|
||||
const doSaveScroll = () => {
|
||||
localStorage.setItem('bookmark' + location.pathname, window.scrollY);
|
||||
};
|
||||
|
||||
const scrollToMark = () => {
|
||||
let top = localStorage.getItem('bookmark' + location.pathname);
|
||||
top = parseInt(top, 10);
|
||||
// If the page opens with a specific hash, just jump out
|
||||
if (!isNaN(top) && location.hash === '') {
|
||||
// Auto scroll to the position
|
||||
window.anime({
|
||||
targets : document.scrollingElement,
|
||||
duration : 200,
|
||||
easing : 'linear',
|
||||
scrollTop: top
|
||||
});
|
||||
}
|
||||
};
|
||||
// Register everything
|
||||
const init = function(trigger) {
|
||||
// Create a link element
|
||||
const link = document.querySelector('.book-mark-link');
|
||||
// Scroll event
|
||||
window.addEventListener('scroll', () => link.classList.toggle('book-mark-link-fixed', window.scrollY === 0), { passive: true });
|
||||
// Register beforeunload event when the trigger is auto
|
||||
if (trigger === 'auto') {
|
||||
// Register beforeunload event
|
||||
window.addEventListener('beforeunload', doSaveScroll);
|
||||
document.addEventListener('pjax:send', doSaveScroll);
|
||||
}
|
||||
// Save the position by clicking the icon
|
||||
link.addEventListener('click', () => {
|
||||
doSaveScroll();
|
||||
window.anime({
|
||||
targets : link,
|
||||
duration: 200,
|
||||
easing : 'linear',
|
||||
top : -30,
|
||||
complete: () => {
|
||||
setTimeout(() => {
|
||||
link.style.top = '';
|
||||
}, 400);
|
||||
}
|
||||
});
|
||||
});
|
||||
scrollToMark();
|
||||
document.addEventListener('pjax:success', scrollToMark);
|
||||
};
|
||||
|
||||
init(CONFIG.bookmark.save);
|
||||
});
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/* global CONFIG */
|
||||
|
||||
(function() {
|
||||
const commentButton = document.querySelectorAll('.comment-button');
|
||||
commentButton.forEach(element => {
|
||||
const commentClass = element.classList[2];
|
||||
element.addEventListener('click', () => {
|
||||
commentButton.forEach(active => active.classList.toggle('active', active === element));
|
||||
document.querySelectorAll('.comment-position').forEach(active => active.classList.toggle('active', active.classList.contains(commentClass)));
|
||||
if (CONFIG.comments.storage) {
|
||||
localStorage.setItem('comments_active', commentClass);
|
||||
}
|
||||
});
|
||||
});
|
||||
let { activeClass } = CONFIG.comments;
|
||||
if (CONFIG.comments.storage) {
|
||||
activeClass = localStorage.getItem('comments_active') || activeClass;
|
||||
}
|
||||
if (activeClass) {
|
||||
const activeButton = document.querySelector(`.comment-button.${activeClass}`);
|
||||
if (activeButton) {
|
||||
activeButton.click();
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/* global CONFIG */
|
||||
|
||||
window.addEventListener('tabs:register', () => {
|
||||
let { activeClass } = CONFIG.comments;
|
||||
if (CONFIG.comments.storage) {
|
||||
activeClass = localStorage.getItem('comments_active') || activeClass;
|
||||
}
|
||||
if (activeClass) {
|
||||
const activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
|
||||
if (activeTab) {
|
||||
activeTab.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
if (CONFIG.comments.storage) {
|
||||
window.addEventListener('tabs:click', event => {
|
||||
if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
|
||||
const commentClass = event.target.classList[1];
|
||||
localStorage.setItem('comments_active', commentClass);
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
if (!window.NexT) window.NexT = {};
|
||||
|
||||
(function() {
|
||||
const className = 'next-config';
|
||||
|
||||
const staticConfig = {};
|
||||
let variableConfig = {};
|
||||
|
||||
const parse = text => JSON.parse(text || '{}');
|
||||
|
||||
const update = name => {
|
||||
const targetEle = document.querySelector(`.${className}[data-name="${name}"]`);
|
||||
if (!targetEle) return;
|
||||
const parsedConfig = parse(targetEle.text);
|
||||
if (name === 'main') {
|
||||
Object.assign(staticConfig, parsedConfig);
|
||||
} else {
|
||||
variableConfig[name] = parsedConfig;
|
||||
}
|
||||
};
|
||||
|
||||
update('main');
|
||||
|
||||
window.CONFIG = new Proxy({}, {
|
||||
get(overrideConfig, name) {
|
||||
let existing;
|
||||
if (name in staticConfig) {
|
||||
existing = staticConfig[name];
|
||||
} else {
|
||||
if (!(name in variableConfig)) update(name);
|
||||
existing = variableConfig[name];
|
||||
}
|
||||
|
||||
// For unset override and mixable existing
|
||||
if (!(name in overrideConfig) && typeof existing === 'object') {
|
||||
// Get ready to mix.
|
||||
overrideConfig[name] = {};
|
||||
}
|
||||
|
||||
if (name in overrideConfig) {
|
||||
const override = overrideConfig[name];
|
||||
|
||||
// When mixable
|
||||
if (typeof override === 'object' && typeof existing === 'object') {
|
||||
// Mix, proxy changes to the override.
|
||||
return new Proxy({ ...existing, ...override }, {
|
||||
set(target, prop, value) {
|
||||
target[prop] = value;
|
||||
override[prop] = value;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return override;
|
||||
}
|
||||
|
||||
// Only when not mixable and override hasn't been set.
|
||||
return existing;
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('pjax:success', () => {
|
||||
variableConfig = {};
|
||||
});
|
||||
})();
|
||||
|
|
@ -0,0 +1 @@
|
|||
"use strict";function updateCoords(e){pointerX=(e.clientX||e.touches[0].clientX)-canvasEl.getBoundingClientRect().left,pointerY=e.clientY||e.touches[0].clientY-canvasEl.getBoundingClientRect().top}function setParticuleDirection(e){var t=anime.random(0,360)*Math.PI/180,a=anime.random(50,180),n=[-1,1][anime.random(0,1)]*a;return{x:e.x+n*Math.cos(t),y:e.y+n*Math.sin(t)}}function createParticule(e,t){var a={};return a.x=e,a.y=t,a.color=colors[anime.random(0,colors.length-1)],a.radius=anime.random(16,32),a.endPos=setParticuleDirection(a),a.draw=function(){ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.fillStyle=a.color,ctx.fill()},a}function createCircle(e,t){var a={};return a.x=e,a.y=t,a.color="#F00",a.radius=.1,a.alpha=.5,a.lineWidth=6,a.draw=function(){ctx.globalAlpha=a.alpha,ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.lineWidth=a.lineWidth,ctx.strokeStyle=a.color,ctx.stroke(),ctx.globalAlpha=1},a}function renderParticule(e){for(var t=0;t<e.animatables.length;t++)e.animatables[t].target.draw()}function animateParticules(e,t){for(var a=createCircle(e,t),n=[],i=0;i<numberOfParticules;i++)n.push(createParticule(e,t));anime.timeline().add({targets:n,x:function(e){return e.endPos.x},y:function(e){return e.endPos.y},radius:.1,duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule}).add({targets:a,radius:anime.random(80,160),lineWidth:0,alpha:{value:0,easing:"linear",duration:anime.random(600,800)},duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule,offset:0})}function debounce(e,t){var a;return function(){var n=this,i=arguments;clearTimeout(a),a=setTimeout(function(){e.apply(n,i)},t)}}var canvasEl=document.querySelector(".fireworks");if(canvasEl){var ctx=canvasEl.getContext("2d"),numberOfParticules=30,pointerX=0,pointerY=0,tap="mousedown",colors=["#FF1461","#18FF92","#5A87FF","#FBF38C"],setCanvasSize=debounce(function(){canvasEl.width=2*window.innerWidth,canvasEl.height=2*window.innerHeight,canvasEl.style.width=window.innerWidth+"px",canvasEl.style.height=window.innerHeight+"px",canvasEl.getContext("2d").scale(2,2)},500),render=anime({duration:1/0,update:function(){ctx.clearRect(0,0,canvasEl.width,canvasEl.height)}});document.addEventListener(tap,function(e){"sidebar"!==e.target.id&&"toggle-sidebar"!==e.target.id&&"A"!==e.target.nodeName&&"IMG"!==e.target.nodeName&&(render.play(),updateCoords(e),animateParticules(pointerX,pointerY))},!1),setCanvasSize(),window.addEventListener("resize",setCanvasSize,!1)}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
class Circle {
|
||||
constructor({ origin, speed, color, angle, context }) {
|
||||
this.origin = origin
|
||||
this.position = { ...this.origin }
|
||||
this.color = color
|
||||
this.speed = speed
|
||||
this.angle = angle
|
||||
this.context = context
|
||||
this.renderCount = 0
|
||||
}
|
||||
|
||||
draw() {
|
||||
this.context.fillStyle = this.color
|
||||
this.context.beginPath()
|
||||
this.context.arc(this.position.x, this.position.y, 2, 0, Math.PI * 2)
|
||||
this.context.fill()
|
||||
}
|
||||
|
||||
move() {
|
||||
this.position.x = (Math.sin(this.angle) * this.speed) + this.position.x
|
||||
this.position.y = (Math.cos(this.angle) * this.speed) + this.position.y + (this.renderCount * 0.3)
|
||||
this.renderCount++
|
||||
}
|
||||
}
|
||||
|
||||
class Boom {
|
||||
constructor ({ origin, context, circleCount = 16, area }) {
|
||||
this.origin = origin
|
||||
this.context = context
|
||||
this.circleCount = circleCount
|
||||
this.area = area
|
||||
this.stop = false
|
||||
this.circles = []
|
||||
}
|
||||
|
||||
randomArray(range) {
|
||||
const length = range.length
|
||||
const randomIndex = Math.floor(length * Math.random())
|
||||
return range[randomIndex]
|
||||
}
|
||||
|
||||
randomColor() {
|
||||
const range = ['8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
|
||||
return '#' + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range)
|
||||
}
|
||||
|
||||
randomRange(start, end) {
|
||||
return (end - start) * Math.random() + start
|
||||
}
|
||||
|
||||
init() {
|
||||
for(let i = 0; i < this.circleCount; i++) {
|
||||
const circle = new Circle({
|
||||
context: this.context,
|
||||
origin: this.origin,
|
||||
color: this.randomColor(),
|
||||
angle: this.randomRange(Math.PI - 1, Math.PI + 1),
|
||||
speed: this.randomRange(1, 6)
|
||||
})
|
||||
this.circles.push(circle)
|
||||
}
|
||||
}
|
||||
|
||||
move() {
|
||||
this.circles.forEach((circle, index) => {
|
||||
if (circle.position.x > this.area.width || circle.position.y > this.area.height) {
|
||||
return this.circles.splice(index, 1)
|
||||
}
|
||||
circle.move()
|
||||
})
|
||||
if (this.circles.length == 0) {
|
||||
this.stop = true
|
||||
}
|
||||
}
|
||||
|
||||
draw() {
|
||||
this.circles.forEach(circle => circle.draw())
|
||||
}
|
||||
}
|
||||
|
||||
class CursorSpecialEffects {
|
||||
constructor() {
|
||||
this.computerCanvas = document.createElement('canvas')
|
||||
this.renderCanvas = document.createElement('canvas')
|
||||
|
||||
this.computerContext = this.computerCanvas.getContext('2d')
|
||||
this.renderContext = this.renderCanvas.getContext('2d')
|
||||
|
||||
this.globalWidth = window.innerWidth
|
||||
this.globalHeight = window.innerHeight
|
||||
|
||||
this.booms = []
|
||||
this.running = false
|
||||
}
|
||||
|
||||
handleMouseDown(e) {
|
||||
const boom = new Boom({
|
||||
origin: { x: e.clientX, y: e.clientY },
|
||||
context: this.computerContext,
|
||||
area: {
|
||||
width: this.globalWidth,
|
||||
height: this.globalHeight
|
||||
}
|
||||
})
|
||||
boom.init()
|
||||
this.booms.push(boom)
|
||||
this.running || this.run()
|
||||
}
|
||||
|
||||
handlePageHide() {
|
||||
this.booms = []
|
||||
this.running = false
|
||||
}
|
||||
|
||||
init() {
|
||||
const style = this.renderCanvas.style
|
||||
style.position = 'fixed'
|
||||
style.top = style.left = 0
|
||||
style.zIndex = '999999999999999999999999999999999999999999'
|
||||
style.pointerEvents = 'none'
|
||||
|
||||
style.width = this.renderCanvas.width = this.computerCanvas.width = this.globalWidth
|
||||
style.height = this.renderCanvas.height = this.computerCanvas.height = this.globalHeight
|
||||
|
||||
document.body.append(this.renderCanvas)
|
||||
|
||||
window.addEventListener('mousedown', this.handleMouseDown.bind(this))
|
||||
window.addEventListener('pagehide', this.handlePageHide.bind(this))
|
||||
}
|
||||
|
||||
run() {
|
||||
this.running = true
|
||||
if (this.booms.length == 0) {
|
||||
return this.running = false
|
||||
}
|
||||
|
||||
requestAnimationFrame(this.run.bind(this))
|
||||
|
||||
this.computerContext.clearRect(0, 0, this.globalWidth, this.globalHeight)
|
||||
this.renderContext.clearRect(0, 0, this.globalWidth, this.globalHeight)
|
||||
|
||||
this.booms.forEach((boom, index) => {
|
||||
if (boom.stop) {
|
||||
return this.booms.splice(index, 1)
|
||||
}
|
||||
boom.move()
|
||||
boom.draw()
|
||||
})
|
||||
this.renderContext.drawImage(this.computerCanvas, 0, 0, this.globalWidth, this.globalHeight)
|
||||
}
|
||||
}
|
||||
|
||||
const cursorSpecialEffects = new CursorSpecialEffects()
|
||||
cursorSpecialEffects.init()
|
||||
|
|
@ -0,0 +1 @@
|
|||
!function(e,t,a){function n(){c(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"),o(),r()}function r(){for(var e=0;e<d.length;e++)d[e].alpha<=0?(t.body.removeChild(d[e].el),d.splice(e,1)):(d[e].y--,d[e].scale+=.004,d[e].alpha-=.013,d[e].el.style.cssText="left:"+d[e].x+"px;top:"+d[e].y+"px;opacity:"+d[e].alpha+";transform:scale("+d[e].scale+","+d[e].scale+") rotate(45deg);background:"+d[e].color+";z-index:99999");requestAnimationFrame(r)}function o(){var t="function"==typeof e.onclick&&e.onclick;e.onclick=function(e){t&&t(),i(e)}}function i(e){var a=t.createElement("div");a.className="heart",d.push({el:a,x:e.clientX-5,y:e.clientY-5,scale:1,alpha:1,color:s()}),t.body.appendChild(a)}function c(e){var a=t.createElement("style");a.type="text/css";try{a.appendChild(t.createTextNode(e))}catch(t){a.styleSheet.cssText=e}t.getElementsByTagName("head")[0].appendChild(a)}function s(){return"rgb("+~~(255*Math.random())+","+~~(255*Math.random())+","+~~(255*Math.random())+")"}var d=[];e.requestAnimationFrame=function(){return e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)}}(),n()}(window,document);
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
var a_idx = 0;
|
||||
jQuery(document).ready(function($) {
|
||||
$("body").click(function(e) {
|
||||
var a = new Array("喜欢我", "不喜欢我");
|
||||
var $i = $("<span/>").text(a[a_idx]);
|
||||
var x = e.pageX,
|
||||
y = e.pageY;
|
||||
$i.css({
|
||||
"z-index": 99999,
|
||||
"top": y - 28,
|
||||
"left": x - a[a_idx].length * 8,
|
||||
"position": "absolute",
|
||||
"color": "#ff7a45"
|
||||
});
|
||||
$("body").append($i);
|
||||
$i.animate({
|
||||
"top": y - 180,
|
||||
"opacity": 0
|
||||
}, 1500, function() {
|
||||
$i.remove();
|
||||
});
|
||||
a_idx = (a_idx + 1) % a.length;
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 随机排列
|
||||
function shuffle(arr) {
|
||||
let i = arr.length;
|
||||
while (i) {
|
||||
let j = Math.floor(Math.random() * i--);
|
||||
[arr[j], arr[i]] = [arr[i], arr[j]];
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染数据
|
||||
function renderlink(data) {
|
||||
var name, avatar, site, li = "";
|
||||
shuffle(data);
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
name = data[i].name;
|
||||
avatar = data[i].avatar;
|
||||
site = data[i].site;
|
||||
li += '<div class="card">' + '<a href="' + site + '" target="_blank">' + '<div class="thumb" style="background: url( ' + avatar + ');">' + '</div>' + '</a>' + '<div class="card-header">' + '<div><a href="' + site + '" target="_blank">' + name + '</a></div>' + '</div>' + '</div>';
|
||||
}
|
||||
document.querySelector(".link-navigation").innerHTML = li;
|
||||
}
|
||||
|
||||
// 获取 json 文件
|
||||
fetch('/links/linklist.json')
|
||||
.then(response => response.json())
|
||||
.then(res => renderlink(res));
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/* global NexT, CONFIG */
|
||||
|
||||
NexT.motion = {};
|
||||
|
||||
NexT.motion.integrator = {
|
||||
queue: [],
|
||||
init : function() {
|
||||
this.queue = [];
|
||||
return this;
|
||||
},
|
||||
add: function(fn) {
|
||||
const sequence = fn();
|
||||
if (CONFIG.motion.async) this.queue.push(sequence);
|
||||
else this.queue = this.queue.concat(sequence);
|
||||
return this;
|
||||
},
|
||||
bootstrap: function() {
|
||||
if (!CONFIG.motion.async) this.queue = [this.queue];
|
||||
this.queue.forEach(sequence => {
|
||||
const timeline = window.anime.timeline({
|
||||
duration: 200,
|
||||
easing : 'linear'
|
||||
});
|
||||
sequence.forEach(item => {
|
||||
if (item.deltaT) timeline.add(item, item.deltaT);
|
||||
else timeline.add(item);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
NexT.motion.middleWares = {
|
||||
header: function() {
|
||||
const sequence = [];
|
||||
|
||||
function getMistLineSettings(targets) {
|
||||
sequence.push({
|
||||
targets,
|
||||
scaleX : [0, 1],
|
||||
duration: 500,
|
||||
deltaT : '-=200'
|
||||
});
|
||||
}
|
||||
|
||||
function pushToSequence(targets, sequenceQueue = false) {
|
||||
sequence.push({
|
||||
targets,
|
||||
opacity: 1,
|
||||
top : 0,
|
||||
deltaT : sequenceQueue ? '-=200' : '-=0'
|
||||
});
|
||||
}
|
||||
|
||||
pushToSequence('.column');
|
||||
CONFIG.scheme === 'Mist' && getMistLineSettings('.logo-line');
|
||||
CONFIG.scheme === 'Muse' && pushToSequence('.custom-logo-image');
|
||||
pushToSequence('.site-title');
|
||||
pushToSequence('.site-brand-container .toggle', true);
|
||||
pushToSequence('.site-subtitle');
|
||||
(CONFIG.scheme === 'Pisces' || CONFIG.scheme === 'Gemini') && pushToSequence('.custom-logo-image');
|
||||
|
||||
const menuItemTransition = CONFIG.motion.transition.menu_item;
|
||||
if (menuItemTransition) {
|
||||
document.querySelectorAll('.menu-item').forEach(targets => {
|
||||
sequence.push({
|
||||
targets,
|
||||
complete: () => targets.classList.add('animated', menuItemTransition),
|
||||
deltaT : '-=200'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return sequence;
|
||||
},
|
||||
|
||||
subMenu: function() {
|
||||
const subMenuItem = document.querySelectorAll('.sub-menu .menu-item');
|
||||
if (subMenuItem.length > 0) {
|
||||
subMenuItem.forEach(element => {
|
||||
element.classList.add('animated');
|
||||
});
|
||||
}
|
||||
return [];
|
||||
},
|
||||
|
||||
postList: function() {
|
||||
const sequence = [];
|
||||
const { post_block, post_header, post_body, coll_header } = CONFIG.motion.transition;
|
||||
|
||||
function animate(animation, elements) {
|
||||
if (!animation) return;
|
||||
elements.forEach(targets => {
|
||||
sequence.push({
|
||||
targets,
|
||||
complete: () => targets.classList.add('animated', animation),
|
||||
deltaT : '-=100'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll('.post-block').forEach(targets => {
|
||||
sequence.push({
|
||||
targets,
|
||||
complete: () => targets.classList.add('animated', post_block),
|
||||
deltaT : '-=100'
|
||||
});
|
||||
animate(coll_header, targets.querySelectorAll('.collection-header'));
|
||||
animate(post_header, targets.querySelectorAll('.post-header'));
|
||||
animate(post_body, targets.querySelectorAll('.post-body'));
|
||||
});
|
||||
|
||||
animate(post_block, document.querySelectorAll('.pagination, .comments'));
|
||||
|
||||
return sequence;
|
||||
},
|
||||
|
||||
sidebar: function() {
|
||||
const sequence = [];
|
||||
const sidebar = document.querySelectorAll('.sidebar-inner');
|
||||
const sidebarTransition = CONFIG.motion.transition.sidebar;
|
||||
// Only for Pisces | Gemini.
|
||||
if (sidebarTransition && (CONFIG.scheme === 'Pisces' || CONFIG.scheme === 'Gemini')) {
|
||||
sidebar.forEach(targets => {
|
||||
sequence.push({
|
||||
targets,
|
||||
complete: () => targets.classList.add('animated', sidebarTransition),
|
||||
deltaT : '-=100'
|
||||
});
|
||||
});
|
||||
}
|
||||
return sequence;
|
||||
},
|
||||
|
||||
footer: function() {
|
||||
return [{
|
||||
targets: document.querySelector('.footer'),
|
||||
opacity: 1
|
||||
}];
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/* global NexT, CONFIG */
|
||||
|
||||
NexT.boot = {};
|
||||
|
||||
NexT.boot.registerEvents = function() {
|
||||
|
||||
NexT.utils.registerScrollPercent();
|
||||
NexT.utils.registerCanIUseTag();
|
||||
|
||||
// Mobile top menu bar.
|
||||
document.querySelector('.site-nav-toggle .toggle').addEventListener('click', event => {
|
||||
event.currentTarget.classList.toggle('toggle-close');
|
||||
const siteNav = document.querySelector('.site-nav');
|
||||
if (!siteNav) return;
|
||||
siteNav.style.setProperty('--scroll-height', siteNav.scrollHeight + 'px');
|
||||
document.body.classList.toggle('site-nav-on');
|
||||
});
|
||||
|
||||
document.querySelectorAll('.sidebar-nav li').forEach((element, index) => {
|
||||
element.addEventListener('click', () => {
|
||||
NexT.utils.activateSidebarPanel(index);
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener('hashchange', () => {
|
||||
const tHash = location.hash;
|
||||
if (tHash !== '' && !tHash.match(/%\S{2}/)) {
|
||||
const target = document.querySelector(`.tabs ul.nav-tabs li a[href="${tHash}"]`);
|
||||
target && target.click();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
NexT.boot.refresh = function() {
|
||||
|
||||
/**
|
||||
* Register JS handlers by condition option.
|
||||
* Need to add config option in Front-End at 'scripts/helpers/next-config.js' file.
|
||||
*/
|
||||
CONFIG.prism && window.Prism.highlightAll();
|
||||
CONFIG.mediumzoom && window.mediumZoom('.post-body :not(a) > img, .post-body > img', {
|
||||
background: 'var(--content-bg-color)'
|
||||
});
|
||||
CONFIG.lazyload && window.lozad('.post-body img').observe();
|
||||
CONFIG.pangu && window.pangu.spacingPage();
|
||||
|
||||
CONFIG.exturl && NexT.utils.registerExtURL();
|
||||
NexT.utils.wrapTableWithBox();
|
||||
NexT.utils.registerCopyCode();
|
||||
NexT.utils.registerTabsTag();
|
||||
NexT.utils.registerActiveMenuItem();
|
||||
NexT.utils.registerLangSelect();
|
||||
NexT.utils.registerSidebarTOC();
|
||||
NexT.utils.registerPostReward();
|
||||
NexT.utils.registerVideoIframe();
|
||||
};
|
||||
|
||||
NexT.boot.motion = function() {
|
||||
// Define Motion Sequence & Bootstrap Motion.
|
||||
if (CONFIG.motion.enable) {
|
||||
NexT.motion.integrator
|
||||
.add(NexT.motion.middleWares.header)
|
||||
.add(NexT.motion.middleWares.postList)
|
||||
.add(NexT.motion.middleWares.sidebar)
|
||||
.add(NexT.motion.middleWares.footer)
|
||||
.bootstrap();
|
||||
}
|
||||
NexT.utils.updateSidebarPosition();
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
NexT.boot.registerEvents();
|
||||
NexT.boot.refresh();
|
||||
NexT.boot.motion();
|
||||
});
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/* global NexT, CONFIG, Pjax */
|
||||
|
||||
const pjax = new Pjax({
|
||||
selectors: [
|
||||
'head title',
|
||||
'script[type="application/json"]',
|
||||
// Precede .main-inner to prevent placeholder TOC changes asap
|
||||
'.post-toc-wrap',
|
||||
'.main-inner',
|
||||
'.languages',
|
||||
'.pjax'
|
||||
],
|
||||
switches: {
|
||||
'.post-toc-wrap': function(oldWrap, newWrap) {
|
||||
if (newWrap.querySelector('.post-toc')) {
|
||||
Pjax.switches.outerHTML.call(this, oldWrap, newWrap);
|
||||
} else {
|
||||
const curTOC = oldWrap.querySelector('.post-toc');
|
||||
if (curTOC) {
|
||||
curTOC.classList.add('placeholder-toc');
|
||||
}
|
||||
this.onSwitch();
|
||||
}
|
||||
}
|
||||
},
|
||||
analytics: false,
|
||||
cacheBust: false,
|
||||
scrollTo : !CONFIG.bookmark.enable
|
||||
});
|
||||
|
||||
document.addEventListener('pjax:success', () => {
|
||||
pjax.executeScripts(document.querySelectorAll('script[data-pjax]'));
|
||||
NexT.boot.refresh();
|
||||
// Define Motion Sequence & Bootstrap Motion.
|
||||
if (CONFIG.motion.enable) {
|
||||
NexT.motion.integrator
|
||||
.init()
|
||||
.add(NexT.motion.middleWares.subMenu)
|
||||
.add(NexT.motion.middleWares.postList)
|
||||
// Add sidebar-post-related transition.
|
||||
.add(NexT.motion.middleWares.sidebar)
|
||||
.bootstrap();
|
||||
}
|
||||
if (CONFIG.sidebar.display !== 'remove') {
|
||||
const hasTOC = document.querySelector('.post-toc:not(.placeholder-toc)');
|
||||
document.querySelector('.sidebar-inner').classList.toggle('sidebar-nav-active', hasTOC);
|
||||
NexT.utils.activateSidebarPanel(hasTOC ? 0 : 1);
|
||||
NexT.utils.updateSidebarPosition();
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
/* global CONFIG */
|
||||
|
||||
// https://developers.google.com/calendar/api/v3/reference/events/list
|
||||
(function() {
|
||||
// Initialization
|
||||
const calendar = {
|
||||
orderBy : 'startTime',
|
||||
showLocation: false,
|
||||
offsetMax : 72,
|
||||
offsetMin : 4,
|
||||
showDeleted : false,
|
||||
singleEvents: true,
|
||||
maxResults : 250
|
||||
};
|
||||
|
||||
// Read config form theme config file
|
||||
Object.assign(calendar, CONFIG.calendar);
|
||||
|
||||
const now = new Date();
|
||||
const timeMax = new Date();
|
||||
const timeMin = new Date();
|
||||
|
||||
timeMax.setHours(now.getHours() + calendar.offsetMax);
|
||||
timeMin.setHours(now.getHours() - calendar.offsetMin);
|
||||
|
||||
// Build URL
|
||||
const params = {
|
||||
key : calendar.api_key,
|
||||
orderBy : calendar.orderBy,
|
||||
timeMax : timeMax.toISOString(),
|
||||
timeMin : timeMin.toISOString(),
|
||||
showDeleted : calendar.showDeleted,
|
||||
singleEvents: calendar.singleEvents,
|
||||
maxResults : calendar.maxResults
|
||||
};
|
||||
|
||||
const request_url = new URL(`https://www.googleapis.com/calendar/v3/calendars/${calendar.calendar_id}/events`);
|
||||
Object.entries(params).forEach(param => request_url.searchParams.append(...param));
|
||||
|
||||
function getRelativeTime(current, previous) {
|
||||
const msPerMinute = 60 * 1000;
|
||||
const msPerHour = msPerMinute * 60;
|
||||
const msPerDay = msPerHour * 24;
|
||||
const msPerMonth = msPerDay * 30;
|
||||
const msPerYear = msPerDay * 365;
|
||||
|
||||
let elapsed = current - previous;
|
||||
const tense = elapsed > 0 ? ' ago' : ' later';
|
||||
|
||||
elapsed = Math.abs(elapsed);
|
||||
|
||||
if (elapsed < msPerHour) {
|
||||
return Math.round(elapsed / msPerMinute) + ' minutes' + tense;
|
||||
} else if (elapsed < msPerDay) {
|
||||
return Math.round(elapsed / msPerHour) + ' hours' + tense;
|
||||
} else if (elapsed < msPerMonth) {
|
||||
return 'about ' + Math.round(elapsed / msPerDay) + ' days' + tense;
|
||||
} else if (elapsed < msPerYear) {
|
||||
return 'about ' + Math.round(elapsed / msPerMonth) + ' months' + tense;
|
||||
}
|
||||
|
||||
return 'about ' + Math.round(elapsed / msPerYear) + ' years' + tense;
|
||||
}
|
||||
|
||||
function buildEventDOM(tense, event, start, end) {
|
||||
const durationFormat = {
|
||||
weekday: 'short',
|
||||
hour : '2-digit',
|
||||
minute : '2-digit'
|
||||
};
|
||||
const relativeTime = tense === 'now' ? 'NOW' : getRelativeTime(now, start);
|
||||
const duration = start.toLocaleTimeString([], durationFormat) + ' - ' + end.toLocaleTimeString([], durationFormat);
|
||||
|
||||
let location = '';
|
||||
if (calendar.showLocation && event.location) {
|
||||
location = `<span class="event-location event-details">${event.location}</span>`;
|
||||
}
|
||||
let description = '';
|
||||
if (event.description) {
|
||||
description = `<span class="event-description event-details">${event.description}</span>`;
|
||||
}
|
||||
|
||||
const eventContent = `<section class="event event-${tense}">
|
||||
<h2 class="event-summary">
|
||||
${event.summary}
|
||||
<span class="event-relative-time">${relativeTime}</span>
|
||||
</h2>
|
||||
${location}
|
||||
<span class="event-duration event-details">${duration}</span>
|
||||
${description}
|
||||
</section>`;
|
||||
return eventContent;
|
||||
}
|
||||
|
||||
function fetchData() {
|
||||
const eventList = document.querySelector('.event-list');
|
||||
if (!eventList) return;
|
||||
|
||||
fetch(request_url.href).then(response => {
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
if (data.items.length === 0) {
|
||||
eventList.innerHTML = '<hr>';
|
||||
return;
|
||||
}
|
||||
// Clean the event list
|
||||
eventList.innerHTML = '';
|
||||
let prevEnd = 0; // used to decide where to insert an <hr>
|
||||
const utc = new Date().getTimezoneOffset() * 60000;
|
||||
|
||||
data.items.forEach(event => {
|
||||
// Parse data
|
||||
const start = new Date(event.start.dateTime || (new Date(event.start.date).getTime() + utc));
|
||||
const end = new Date(event.end.dateTime || (new Date(event.end.date).getTime() + utc));
|
||||
|
||||
let tense = 'now';
|
||||
if (end < now) {
|
||||
tense = 'past';
|
||||
} else if (start > now) {
|
||||
tense = 'future';
|
||||
}
|
||||
|
||||
if (tense === 'future' && prevEnd < now) {
|
||||
eventList.insertAdjacentHTML('beforeend', '<hr>');
|
||||
}
|
||||
|
||||
eventList.insertAdjacentHTML('beforeend', buildEventDOM(tense, event, start, end));
|
||||
prevEnd = end;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fetchData();
|
||||
const fetchDataTimer = setInterval(fetchData, 60000);
|
||||
document.addEventListener('pjax:send', () => {
|
||||
clearInterval(fetchDataTimer);
|
||||
});
|
||||
})();
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/* global CONFIG */
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
const isRight = CONFIG.sidebar.position === 'right';
|
||||
|
||||
const sidebarToggleMotion = {
|
||||
mouse: {},
|
||||
init : function() {
|
||||
window.addEventListener('mousedown', this.mousedownHandler.bind(this));
|
||||
window.addEventListener('mouseup', this.mouseupHandler.bind(this));
|
||||
document.querySelector('.sidebar-dimmer').addEventListener('click', this.clickHandler.bind(this));
|
||||
document.querySelector('.sidebar-toggle').addEventListener('click', this.clickHandler.bind(this));
|
||||
window.addEventListener('sidebar:show', this.showSidebar);
|
||||
window.addEventListener('sidebar:hide', this.hideSidebar);
|
||||
},
|
||||
mousedownHandler: function(event) {
|
||||
this.mouse.X = event.pageX;
|
||||
this.mouse.Y = event.pageY;
|
||||
},
|
||||
mouseupHandler: function(event) {
|
||||
const deltaX = event.pageX - this.mouse.X;
|
||||
const deltaY = event.pageY - this.mouse.Y;
|
||||
const clickingBlankPart = Math.hypot(deltaX, deltaY) < 20 && event.target.matches('.main');
|
||||
// Fancybox has z-index property, but medium-zoom does not, so the sidebar will overlay the zoomed image.
|
||||
if (clickingBlankPart || event.target.matches('img.medium-zoom-image')) {
|
||||
this.hideSidebar();
|
||||
}
|
||||
},
|
||||
clickHandler: function() {
|
||||
document.body.classList.contains('sidebar-active') ? this.hideSidebar() : this.showSidebar();
|
||||
},
|
||||
showSidebar: function() {
|
||||
document.body.classList.add('sidebar-active');
|
||||
const animateAction = isRight ? 'fadeInRight' : 'fadeInLeft';
|
||||
document.querySelectorAll('.sidebar .animated').forEach((element, index) => {
|
||||
element.style.animationDelay = (100 * index) + 'ms';
|
||||
element.classList.remove(animateAction);
|
||||
setTimeout(() => {
|
||||
// Trigger a DOM reflow
|
||||
element.classList.add(animateAction);
|
||||
});
|
||||
});
|
||||
},
|
||||
hideSidebar: function() {
|
||||
document.body.classList.remove('sidebar-active');
|
||||
}
|
||||
};
|
||||
if (CONFIG.sidebar.display !== 'remove') sidebarToggleMotion.init();
|
||||
|
||||
function updateFooterPosition() {
|
||||
const footer = document.querySelector('.footer');
|
||||
const containerHeight = document.querySelector('.main').offsetHeight + footer.offsetHeight;
|
||||
footer.classList.toggle('footer-fixed', containerHeight <= window.innerHeight);
|
||||
}
|
||||
|
||||
updateFooterPosition();
|
||||
window.addEventListener('resize', updateFooterPosition);
|
||||
window.addEventListener('scroll', updateFooterPosition, { passive: true });
|
||||
});
|
||||
|
|
@ -0,0 +1 @@
|
|||
function addLoadEvent(func) {var oldonload = window.onload;if (typeof window.onload != 'function') {window.onload = func;} else {window.onload = function() {oldonload();func();}}}addLoadEvent(function() {console.log('tag cloud plugin rock and roll!'); try { TagCanvas.textFont = 'Trebuchet MS, Helvetica'; TagCanvas.textColour = '#333'; TagCanvas.textHeight = 25; TagCanvas.outlineColour = '#E2E1C1'; TagCanvas.outlineMethod = 'block'; TagCanvas.maxSpeed = 0.03; TagCanvas.minBrightness = 0.2; TagCanvas.depth = 0.92; TagCanvas.pulsateTo = 0.6; TagCanvas.initial = [0.1,-0.1]; TagCanvas.decel = 0.98; TagCanvas.reverse = true; TagCanvas.hideTags = false; TagCanvas.shadow = '#ccf'; TagCanvas.shadowBlur = 3; TagCanvas.weight = false; TagCanvas.imageScale = null; TagCanvas.fadeIn = 1000; TagCanvas.clickToFront = 600; TagCanvas.Start('resCanvas'); TagCanvas.tc['resCanvas'].Wheel(false)} catch(e) { console.log(e); document.getElementById('myCanvasContainer').style.display = 'none'; } });
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
/* global _hmt */
|
||||
|
||||
if (!window._hmt) window._hmt = [];
|
||||
|
||||
document.addEventListener('pjax:success', () => {
|
||||
_hmt.push(['_trackPageview', location.pathname]);
|
||||
});
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/* global CONFIG, dataLayer, gtag */
|
||||
|
||||
if (!CONFIG.google_analytics.only_pageview) {
|
||||
if (CONFIG.hostname === location.hostname) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
window.gtag = function() {
|
||||
dataLayer.push(arguments);
|
||||
};
|
||||
gtag('js', new Date());
|
||||
gtag('config', CONFIG.google_analytics.tracking_id);
|
||||
|
||||
document.addEventListener('pjax:success', () => {
|
||||
gtag('event', 'page_view', {
|
||||
page_location: location.href,
|
||||
page_path : location.pathname,
|
||||
page_title : document.title
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const sendPageView = () => {
|
||||
if (CONFIG.hostname !== location.hostname) return;
|
||||
const uid = localStorage.getItem('uid') || (Math.random() + '.' + Math.random());
|
||||
localStorage.setItem('uid', uid);
|
||||
navigator.sendBeacon('https://www.google-analytics.com/collect', new URLSearchParams({
|
||||
v : 1,
|
||||
tid: CONFIG.google_analytics.tracking_id,
|
||||
cid: uid,
|
||||
t : 'pageview',
|
||||
dp : encodeURIComponent(location.pathname)
|
||||
}));
|
||||
};
|
||||
document.addEventListener('pjax:complete', sendPageView);
|
||||
sendPageView();
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/* global CONFIG, gio */
|
||||
|
||||
if (!window.gio) {
|
||||
window.gio = function() {
|
||||
(window.gio.q = window.gio.q || []).push(arguments);
|
||||
};
|
||||
}
|
||||
|
||||
gio('init', `${CONFIG.growingio_analytics}`, {});
|
||||
gio('send');
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/* global CONFIG */
|
||||
|
||||
if (CONFIG.matomo.enable) {
|
||||
window._paq = window._paq || [];
|
||||
const _paq = window._paq;
|
||||
|
||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
const u = CONFIG.matomo.server_url;
|
||||
_paq.push(['setTrackerUrl', u + 'matomo.php']);
|
||||
_paq.push(['setSiteId', CONFIG.matomo.site_id]);
|
||||
const d = document;
|
||||
const g = d.createElement('script');
|
||||
const s = d.getElementsByTagName('script')[0];
|
||||
g.async = true;
|
||||
g.src = u + 'matomo.js';
|
||||
s.parentNode.insertBefore(g, s);
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/* global CONFIG, Chatra */
|
||||
|
||||
(function() {
|
||||
if (CONFIG.chatra.embed) {
|
||||
window.ChatraSetup = {
|
||||
mode : 'frame',
|
||||
injectTo: CONFIG.chatra.embed
|
||||
};
|
||||
}
|
||||
|
||||
window.ChatraID = CONFIG.chatra.id;
|
||||
|
||||
const chatButton = document.querySelector('.sidebar-button button');
|
||||
if (chatButton) {
|
||||
chatButton.addEventListener('click', () => {
|
||||
Chatra('openChat', true);
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
/* global CONFIG */
|
||||
|
||||
((window.gitter = {}).chat = {}).options = {
|
||||
room: CONFIG.gitter.room
|
||||
};
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/* global tidioChatApi */
|
||||
|
||||
(function() {
|
||||
const chatButton = document.querySelector('.sidebar-button button');
|
||||
if (chatButton) {
|
||||
chatButton.addEventListener('click', () => {
|
||||
tidioChatApi.open();
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/* global NexT, CONFIG */
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
const { appid, appkey } = CONFIG.changyan;
|
||||
const mainJs = 'https://cy-cdn.kuaizhan.com/upload/changyan.js';
|
||||
const countJs = `https://cy-cdn.kuaizhan.com/upload/plugins/plugins.list.count.js?clientId=${appid}`;
|
||||
|
||||
// Get the number of comments
|
||||
setTimeout(() => {
|
||||
return NexT.utils.getScript(countJs, {
|
||||
attributes: {
|
||||
async: true,
|
||||
id : 'cy_cmt_num'
|
||||
}
|
||||
});
|
||||
}, 0);
|
||||
|
||||
// When scroll to comment section
|
||||
if (CONFIG.page.comments && !CONFIG.page.isHome) {
|
||||
NexT.utils.loadComments('#SOHUCS')
|
||||
.then(() => {
|
||||
return NexT.utils.getScript(mainJs, {
|
||||
attributes: {
|
||||
async: true
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
window.changyan.api.config({
|
||||
appid,
|
||||
conf: appkey
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Failed to load Changyan', error);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/* global NexT, CONFIG, DISQUS */
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
|
||||
if (CONFIG.disqus.count) {
|
||||
if (window.DISQUSWIDGETS) {
|
||||
window.DISQUSWIDGETS.getCount({ reset: true });
|
||||
} else {
|
||||
// Defer loading until the whole page loading is completed
|
||||
NexT.utils.getScript(`https://${CONFIG.disqus.shortname}.disqus.com/count.js`, {
|
||||
attributes: { id: 'dsq-count-scr', defer: true }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (CONFIG.page.comments) {
|
||||
// `disqus_config` should be a global variable
|
||||
// See https://help.disqus.com/en/articles/1717084-javascript-configuration-variables
|
||||
window.disqus_config = function() {
|
||||
this.page.url = CONFIG.page.permalink;
|
||||
this.page.identifier = CONFIG.page.path;
|
||||
this.page.title = CONFIG.page.title;
|
||||
if (CONFIG.disqus.i18n.disqus !== 'disqus') {
|
||||
this.language = CONFIG.disqus.i18n.disqus;
|
||||
}
|
||||
};
|
||||
NexT.utils.loadComments('#disqus_thread').then(() => {
|
||||
if (window.DISQUS) {
|
||||
DISQUS.reset({
|
||||
reload: true,
|
||||
config: window.disqus_config
|
||||
});
|
||||
} else {
|
||||
NexT.utils.getScript(`https://${CONFIG.disqus.shortname}.disqus.com/embed.js`, {
|
||||
attributes: { dataset: { timestamp: '' + +new Date() } }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/* global NexT, CONFIG, DisqusJS */
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
if (!CONFIG.page.comments) return;
|
||||
|
||||
NexT.utils.loadComments('#disqus_thread')
|
||||
.then(() => NexT.utils.getScript(CONFIG.disqusjs.js, { condition: window.DisqusJS }))
|
||||
.then(() => {
|
||||
window.dsqjs = new DisqusJS({
|
||||
api : CONFIG.disqusjs.api || 'https://disqus.com/api/',
|
||||
apikey : CONFIG.disqusjs.apikey,
|
||||
shortname : CONFIG.disqusjs.shortname,
|
||||
url : CONFIG.page.permalink,
|
||||
identifier: CONFIG.page.path,
|
||||
title : CONFIG.page.title
|
||||
});
|
||||
window.dsqjs.render(document.querySelector('.disqusjs-container'));
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('pjax:send', () => {
|
||||
if (window.dsqjs) window.dsqjs.destroy();
|
||||
});
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/* global NexT, CONFIG, Gitalk */
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
if (!CONFIG.page.comments) return;
|
||||
|
||||
NexT.utils.loadComments('.gitalk-container')
|
||||
.then(() => NexT.utils.getScript(CONFIG.gitalk.js, {
|
||||
condition: window.Gitalk
|
||||
}))
|
||||
.then(() => {
|
||||
const gitalk = new Gitalk({
|
||||
clientID : CONFIG.gitalk.client_id,
|
||||
clientSecret : CONFIG.gitalk.client_secret,
|
||||
repo : CONFIG.gitalk.repo,
|
||||
owner : CONFIG.gitalk.github_id,
|
||||
admin : [CONFIG.gitalk.admin_user],
|
||||
id : CONFIG.gitalk.path_md5,
|
||||
proxy : CONFIG.gitalk.proxy,
|
||||
language : CONFIG.gitalk.language || window.navigator.language,
|
||||
distractionFreeMode: CONFIG.gitalk.distraction_free_mode
|
||||
});
|
||||
gitalk.render(document.querySelector('.gitalk-container'));
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
/* global NexT, CONFIG */
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
if (!CONFIG.page.comments) return;
|
||||
|
||||
NexT.utils.loadComments('#isso-thread')
|
||||
.then(() => NexT.utils.getScript(`${CONFIG.isso}js/embed.min.js`, {
|
||||
attributes: {
|
||||
dataset: {
|
||||
isso: `${CONFIG.isso}`
|
||||
}
|
||||
},
|
||||
parentNode: document.querySelector('#isso-thread')
|
||||
}));
|
||||
});
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/* global NexT, CONFIG, LivereTower */
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
if (!CONFIG.page.comments) return;
|
||||
|
||||
NexT.utils.loadComments('#lv-container').then(() => {
|
||||
window.livereOptions = {
|
||||
refer: CONFIG.page.path.replace(/index\.html$/, '')
|
||||
};
|
||||
|
||||
if (typeof LivereTower === 'function') return;
|
||||
|
||||
NexT.utils.getScript('https://cdn-city.livere.com/js/embed.dist.js', {
|
||||
attributes: {
|
||||
async: true
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
/* global NexT, CONFIG */
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
if (!CONFIG.page.comments) return;
|
||||
|
||||
NexT.utils.loadComments('.utterances-container')
|
||||
.then(() => NexT.utils.getScript('https://utteranc.es/client.js', {
|
||||
attributes: {
|
||||
async : true,
|
||||
crossOrigin : 'anonymous',
|
||||
'repo' : CONFIG.utterances.repo,
|
||||
'issue-term': CONFIG.utterances.issue_term,
|
||||
'theme' : CONFIG.utterances.theme
|
||||
},
|
||||
parentNode: document.querySelector('.utterances-container')
|
||||
}));
|
||||
});
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
document.addEventListener('page:loaded', () => {
|
||||
|
||||
/**
|
||||
* Wrap images with fancybox.
|
||||
*/
|
||||
document.querySelectorAll('.post-body :not(a) > img, .post-body > img').forEach(element => {
|
||||
const $image = $(element);
|
||||
const imageLink = $image.attr('data-src') || $image.attr('src');
|
||||
const $imageWrapLink = $image.wrap(`<a class="fancybox fancybox.image" href="${imageLink}" itemscope itemtype="http://schema.org/ImageObject" itemprop="url"></a>`).parent('a');
|
||||
if ($image.is('.post-gallery img')) {
|
||||
$imageWrapLink.attr('data-fancybox', 'gallery').attr('rel', 'gallery');
|
||||
} else if ($image.is('.group-picture img')) {
|
||||
$imageWrapLink.attr('data-fancybox', 'group').attr('rel', 'group');
|
||||
} else {
|
||||
$imageWrapLink.attr('data-fancybox', 'default').attr('rel', 'default');
|
||||
}
|
||||
|
||||
const imageTitle = $image.attr('title') || $image.attr('alt');
|
||||
if (imageTitle) {
|
||||
// Do not append image-caption if pandoc has already created a figcaption
|
||||
if (!$imageWrapLink.next('figcaption').length) {
|
||||
$imageWrapLink.append(`<p class="image-caption">${imageTitle}</p>`);
|
||||
}
|
||||
// Make sure img title tag will show correctly in fancybox
|
||||
$imageWrapLink.attr('title', imageTitle).attr('data-caption', imageTitle);
|
||||
}
|
||||
});
|
||||
|
||||
$.fancybox.defaults.hash = false;
|
||||
$('.fancybox').fancybox({
|
||||
loop : true,
|
||||
helpers: {
|
||||
overlay: {
|
||||
locked: false
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
/* global NexT, CONFIG */
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
if (!CONFIG.enableMath) return;
|
||||
|
||||
NexT.utils.getScript(CONFIG.katex.copy_tex_js).catch(() => {});
|
||||
});
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/* global NexT, CONFIG, MathJax */
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
if (!CONFIG.enableMath) return;
|
||||
|
||||
if (typeof MathJax === 'undefined') {
|
||||
window.MathJax = {
|
||||
tex: {
|
||||
inlineMath: { '[+]': [['$', '$']] },
|
||||
tags : CONFIG.mathjax.tags
|
||||
},
|
||||
options: {
|
||||
renderActions: {
|
||||
insertedScript: [200, () => {
|
||||
document.querySelectorAll('mjx-container').forEach(node => {
|
||||
const target = node.parentNode;
|
||||
if (target.nodeName.toLowerCase() === 'li') {
|
||||
target.parentNode.classList.add('has-jax');
|
||||
}
|
||||
});
|
||||
}, '', false]
|
||||
}
|
||||
}
|
||||
};
|
||||
NexT.utils.getScript(CONFIG.mathjax.js, {
|
||||
attributes: {
|
||||
defer: true
|
||||
}
|
||||
});
|
||||
} else {
|
||||
MathJax.startup.document.state(0);
|
||||
MathJax.typesetClear();
|
||||
MathJax.texReset();
|
||||
MathJax.typesetPromise();
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
/* global Pace */
|
||||
|
||||
Pace.options.restartOnPushState = false;
|
||||
|
||||
document.addEventListener('pjax:send', () => {
|
||||
Pace.restart();
|
||||
});
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/* global CONFIG, quicklink */
|
||||
|
||||
(function() {
|
||||
if (typeof CONFIG.quicklink.ignores === 'string') {
|
||||
const ignoresStr = `[${CONFIG.quicklink.ignores}]`;
|
||||
CONFIG.quicklink.ignores = JSON.parse(ignoresStr);
|
||||
}
|
||||
|
||||
let resetFn = null;
|
||||
|
||||
const onRefresh = () => {
|
||||
if (resetFn) resetFn();
|
||||
if (!CONFIG.quicklink.enable) return;
|
||||
|
||||
let ignoresArr = CONFIG.quicklink.ignores || [];
|
||||
if (!Array.isArray(ignoresArr)) {
|
||||
ignoresArr = [ignoresArr];
|
||||
}
|
||||
|
||||
resetFn = quicklink.listen({
|
||||
timeout : CONFIG.quicklink.timeout,
|
||||
priority: CONFIG.quicklink.priority,
|
||||
ignores : [
|
||||
uri => uri.includes('#'),
|
||||
uri => uri === CONFIG.quicklink.url,
|
||||
...ignoresArr
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
if (CONFIG.quicklink.delay) {
|
||||
window.addEventListener('load', onRefresh);
|
||||
document.addEventListener('pjax:success', onRefresh);
|
||||
} else {
|
||||
document.addEventListener('page:loaded', onRefresh);
|
||||
}
|
||||
})();
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/* global instantsearch, algoliasearch, CONFIG, pjax */
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const { indexName, appID, apiKey, hits } = CONFIG.algolia;
|
||||
|
||||
const search = instantsearch({
|
||||
indexName,
|
||||
searchClient : algoliasearch(appID, apiKey),
|
||||
searchFunction: helper => {
|
||||
if (document.querySelector('.search-input').value) {
|
||||
helper.search();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof pjax === 'object') {
|
||||
search.on('render', () => {
|
||||
pjax.refresh(document.querySelector('.algolia-hits'));
|
||||
});
|
||||
}
|
||||
|
||||
// Registering Widgets
|
||||
search.addWidgets([
|
||||
instantsearch.widgets.configure({
|
||||
hitsPerPage: hits.per_page || 10
|
||||
}),
|
||||
|
||||
instantsearch.widgets.searchBox({
|
||||
container : '.search-input-container',
|
||||
placeholder : CONFIG.i18n.placeholder,
|
||||
// Hide default icons of algolia search
|
||||
showReset : false,
|
||||
showSubmit : false,
|
||||
showLoadingIndicator: false,
|
||||
cssClasses : {
|
||||
input: 'search-input'
|
||||
}
|
||||
}),
|
||||
|
||||
instantsearch.widgets.stats({
|
||||
container: '.algolia-stats',
|
||||
templates: {
|
||||
text: data => {
|
||||
const stats = CONFIG.i18n.hits_time
|
||||
.replace('${hits}', data.nbHits)
|
||||
.replace('${time}', data.processingTimeMS);
|
||||
return `<span>${stats}</span>
|
||||
<img src="${CONFIG.images}/logo-algolia-nebula-blue-full.svg" alt="Algolia">`;
|
||||
}
|
||||
},
|
||||
cssClasses: {
|
||||
text: 'search-stats'
|
||||
}
|
||||
}),
|
||||
|
||||
instantsearch.widgets.hits({
|
||||
container : '.algolia-hits',
|
||||
escapeHTML: false,
|
||||
templates : {
|
||||
item: data => {
|
||||
const { title, excerpt, excerptStrip, contentStripTruncate } = data._highlightResult;
|
||||
let result = `<a href="${data.permalink}" class="search-result-title">${title.value}</a>`;
|
||||
const content = excerpt || excerptStrip || contentStripTruncate;
|
||||
if (content && content.value) {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = content.value;
|
||||
result += `<a href="${data.permalink}"><p class="search-result">${div.textContent.substring(0, 100)}...</p></a>`;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
empty: data => {
|
||||
return `<div class="algolia-hits-empty">
|
||||
${CONFIG.i18n.empty.replace('${query}', data.query)}
|
||||
</div>`;
|
||||
}
|
||||
},
|
||||
cssClasses: {
|
||||
list: 'search-result-list'
|
||||
}
|
||||
}),
|
||||
|
||||
instantsearch.widgets.pagination({
|
||||
container: '.algolia-pagination',
|
||||
scrollTo : false,
|
||||
showFirst: false,
|
||||
showLast : false,
|
||||
templates: {
|
||||
first : '<i class="fa fa-angle-double-left"></i>',
|
||||
last : '<i class="fa fa-angle-double-right"></i>',
|
||||
previous: '<i class="fa fa-angle-left"></i>',
|
||||
next : '<i class="fa fa-angle-right"></i>'
|
||||
},
|
||||
cssClasses: {
|
||||
list : ['pagination', 'algolia-pagination'],
|
||||
item : 'pagination-item',
|
||||
link : 'page-number',
|
||||
selectedItem: 'current',
|
||||
disabledItem: 'disabled-item'
|
||||
}
|
||||
})
|
||||
]);
|
||||
|
||||
search.start();
|
||||
|
||||
// Handle and trigger popup window
|
||||
document.querySelectorAll('.popup-trigger').forEach(element => {
|
||||
element.addEventListener('click', () => {
|
||||
document.body.classList.add('search-active');
|
||||
setTimeout(() => document.querySelector('.search-input').focus(), 500);
|
||||
});
|
||||
});
|
||||
|
||||
// Monitor main search box
|
||||
const onPopupClose = () => {
|
||||
document.body.classList.remove('search-active');
|
||||
};
|
||||
|
||||
document.querySelector('.search-pop-overlay').addEventListener('click', event => {
|
||||
if (event.target === document.querySelector('.search-pop-overlay')) {
|
||||
onPopupClose();
|
||||
}
|
||||
});
|
||||
document.querySelector('.popup-btn-close').addEventListener('click', onPopupClose);
|
||||
document.addEventListener('pjax:success', onPopupClose);
|
||||
window.addEventListener('keyup', event => {
|
||||
if (event.key === 'Escape') {
|
||||
onPopupClose();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/* global CONFIG, pjax, LocalSearch */
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (!CONFIG.path) {
|
||||
// Search DB path
|
||||
console.warn('`hexo-generator-searchdb` plugin is not installed!');
|
||||
return;
|
||||
}
|
||||
const localSearch = new LocalSearch({
|
||||
path : CONFIG.path,
|
||||
top_n_per_article: CONFIG.localsearch.top_n_per_article,
|
||||
unescape : CONFIG.localsearch.unescape
|
||||
});
|
||||
|
||||
const input = document.querySelector('.search-input');
|
||||
|
||||
const inputEventFunction = () => {
|
||||
if (!localSearch.isfetched) return;
|
||||
const searchText = input.value.trim().toLowerCase();
|
||||
const keywords = searchText.split(/[-\s]+/);
|
||||
const container = document.querySelector('.search-result-container');
|
||||
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.innerHTML = '<div class="search-result-icon"><i class="fa fa-search fa-5x"></i></div>';
|
||||
} else if (resultItems.length === 0) {
|
||||
container.classList.add('no-result');
|
||||
container.innerHTML = '<div class="search-result-icon"><i class="far fa-frown fa-5x"></i></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 = CONFIG.i18n.hits.replace('${hits}', resultItems.length);
|
||||
|
||||
container.classList.remove('no-result');
|
||||
container.innerHTML = `<div class="search-stats">${stats}</div>
|
||||
<hr>
|
||||
<ul class="search-result-list">${resultItems.map(result => result.item).join('')}</ul>`;
|
||||
if (typeof pjax === 'object') pjax.refresh(container);
|
||||
}
|
||||
};
|
||||
|
||||
localSearch.highlightSearchWords(document.querySelector('.post-body'));
|
||||
if (CONFIG.localsearch.preload) {
|
||||
localSearch.fetchData();
|
||||
}
|
||||
|
||||
if (CONFIG.localsearch.trigger === 'auto') {
|
||||
input.addEventListener('input', inputEventFunction);
|
||||
} else {
|
||||
document.querySelector('.search-icon').addEventListener('click', inputEventFunction);
|
||||
input.addEventListener('keypress', event => {
|
||||
if (event.key === 'Enter') {
|
||||
inputEventFunction();
|
||||
}
|
||||
});
|
||||
}
|
||||
window.addEventListener('search:loaded', inputEventFunction);
|
||||
|
||||
// Handle and trigger popup window
|
||||
document.querySelectorAll('.popup-trigger').forEach(element => {
|
||||
element.addEventListener('click', () => {
|
||||
document.body.classList.add('search-active');
|
||||
// Wait for search-popup animation to complete
|
||||
setTimeout(() => input.focus(), 500);
|
||||
if (!localSearch.isfetched) localSearch.fetchData();
|
||||
});
|
||||
});
|
||||
|
||||
// Monitor main search box
|
||||
const onPopupClose = () => {
|
||||
document.body.classList.remove('search-active');
|
||||
};
|
||||
|
||||
document.querySelector('.search-pop-overlay').addEventListener('click', event => {
|
||||
if (event.target === document.querySelector('.search-pop-overlay')) {
|
||||
onPopupClose();
|
||||
}
|
||||
});
|
||||
document.querySelector('.popup-btn-close').addEventListener('click', onPopupClose);
|
||||
document.addEventListener('pjax:success', () => {
|
||||
localSearch.highlightSearchWords(document.querySelector('.post-body'));
|
||||
onPopupClose();
|
||||
});
|
||||
window.addEventListener('keyup', event => {
|
||||
if (event.key === 'Escape') {
|
||||
onPopupClose();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/* global CONFIG, firebase */
|
||||
|
||||
firebase.initializeApp({
|
||||
apiKey : CONFIG.firestore.apiKey,
|
||||
projectId: CONFIG.firestore.projectId
|
||||
});
|
||||
|
||||
(function() {
|
||||
const getCount = (doc, increaseCount) => {
|
||||
// IncreaseCount will be false when not in article page
|
||||
return doc.get().then(d => {
|
||||
// Has no data, initialize count
|
||||
let count = d.exists ? d.data().count : 0;
|
||||
// If first view this article
|
||||
if (increaseCount) {
|
||||
// Increase count
|
||||
count++;
|
||||
doc.set({
|
||||
count
|
||||
});
|
||||
}
|
||||
return count;
|
||||
});
|
||||
};
|
||||
|
||||
const db = firebase.firestore();
|
||||
const articles = db.collection(CONFIG.firestore.collection);
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
|
||||
if (CONFIG.page.isPost) {
|
||||
// Fix issue #118
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent
|
||||
const title = document.querySelector('.post-title').textContent.trim();
|
||||
const doc = articles.doc(title);
|
||||
let increaseCount = CONFIG.hostname === location.hostname;
|
||||
if (localStorage.getItem(title)) {
|
||||
increaseCount = false;
|
||||
} else {
|
||||
// Mark as visited
|
||||
localStorage.setItem(title, true);
|
||||
}
|
||||
getCount(doc, increaseCount).then(count => {
|
||||
document.querySelector('.firestore-visitors-count').innerText = count;
|
||||
});
|
||||
} else if (CONFIG.page.isHome) {
|
||||
const promises = [...document.querySelectorAll('.post-title')].map(element => {
|
||||
const title = element.textContent.trim();
|
||||
const doc = articles.doc(title);
|
||||
return getCount(doc);
|
||||
});
|
||||
Promise.all(promises).then(counts => {
|
||||
const metas = document.querySelectorAll('.firestore-visitors-count');
|
||||
counts.forEach((val, idx) => {
|
||||
metas[idx].innerText = val;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/* global CONFIG */
|
||||
/* eslint-disable no-console */
|
||||
|
||||
(function() {
|
||||
const leancloudSelector = url => {
|
||||
url = encodeURI(url);
|
||||
return document.getElementById(url).querySelector('.leancloud-visitors-count');
|
||||
};
|
||||
|
||||
const addCount = Counter => {
|
||||
const visitors = document.querySelector('.leancloud_visitors');
|
||||
const url = decodeURI(visitors.id);
|
||||
const title = visitors.dataset.flagTitle;
|
||||
|
||||
Counter('get', `/classes/Counter?where=${encodeURIComponent(JSON.stringify({ url }))}`)
|
||||
.then(response => response.json())
|
||||
.then(({ results }) => {
|
||||
if (results.length > 0) {
|
||||
const counter = results[0];
|
||||
leancloudSelector(url).innerText = counter.time + 1;
|
||||
Counter('put', '/classes/Counter/' + counter.objectId, {
|
||||
time: {
|
||||
'__op' : 'Increment',
|
||||
'amount': 1
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to save visitor count', error);
|
||||
});
|
||||
} else if (CONFIG.leancloud_visitors.security) {
|
||||
leancloudSelector(url).innerText = 'Counter not initialized! More info at console err msg.';
|
||||
console.error('ATTENTION! LeanCloud counter has security bug, see how to solve it here: https://github.com/theme-next/hexo-leancloud-counter-security. \n However, you can still use LeanCloud without security, by setting `security` option to `false`.');
|
||||
} else {
|
||||
Counter('post', '/classes/Counter', { title, url, time: 1 })
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
leancloudSelector(url).innerText = 1;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to create', error);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('LeanCloud Counter Error', error);
|
||||
});
|
||||
};
|
||||
|
||||
const showTime = Counter => {
|
||||
const visitors = document.querySelectorAll('.leancloud_visitors');
|
||||
const entries = [...visitors].map(element => {
|
||||
return decodeURI(element.id);
|
||||
});
|
||||
|
||||
Counter('get', `/classes/Counter?where=${encodeURIComponent(JSON.stringify({ url: { '$in': entries } }))}`)
|
||||
.then(response => response.json())
|
||||
.then(({ results }) => {
|
||||
for (const url of entries) {
|
||||
const target = results.find(item => item.url === url);
|
||||
leancloudSelector(url).innerText = target ? target.time : 0;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('LeanCloud Counter Error', error);
|
||||
});
|
||||
};
|
||||
|
||||
const { app_id, app_key, server_url } = CONFIG.leancloud_visitors;
|
||||
const fetchData = api_server => {
|
||||
const Counter = (method, url, data) => {
|
||||
return fetch(`${api_server}/1.1${url}`, {
|
||||
method,
|
||||
headers: {
|
||||
'X-LC-Id' : app_id,
|
||||
'X-LC-Key' : app_key,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
};
|
||||
if (CONFIG.page.isPost) {
|
||||
if (CONFIG.hostname !== location.hostname) return;
|
||||
addCount(Counter);
|
||||
} else if (document.querySelectorAll('.post-title-link').length >= 1) {
|
||||
showTime(Counter);
|
||||
}
|
||||
};
|
||||
|
||||
let api_server;
|
||||
if (server_url) {
|
||||
api_server = server_url;
|
||||
} else if (app_id.slice(-9) === '-MdYXbMMI') {
|
||||
api_server = `https://${app_id.slice(0, 8).toLowerCase()}.api.lncldglobal.com`;
|
||||
}
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
if (api_server) {
|
||||
fetchData(api_server);
|
||||
} else {
|
||||
fetch(`https://app-router.leancloud.cn/2/route?appId=${app_id}`)
|
||||
.then(response => response.json())
|
||||
.then(({ api_server }) => {
|
||||
fetchData(`https://${api_server}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/* global NexT, CONFIG, mermaid */
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
const mermaidElements = document.querySelectorAll('.mermaid');
|
||||
if (mermaidElements.length) {
|
||||
NexT.utils.getScript(CONFIG.mermaid.js, {
|
||||
condition: window.mermaid
|
||||
}).then(() => {
|
||||
mermaidElements.forEach(element => {
|
||||
const newElement = document.createElement('div');
|
||||
newElement.innerHTML = element.innerHTML;
|
||||
newElement.className = element.className;
|
||||
const parent = element.parentNode;
|
||||
// Fix issue #347
|
||||
// Support mermaid inside backtick code block
|
||||
if (parent.matches('pre')) {
|
||||
parent.parentNode.replaceChild(newElement, parent);
|
||||
} else {
|
||||
parent.replaceChild(newElement, element);
|
||||
}
|
||||
});
|
||||
mermaid.initialize({
|
||||
theme : CONFIG.darkmode && window.matchMedia('(prefers-color-scheme: dark)').matches ? CONFIG.mermaid.theme.dark : CONFIG.mermaid.theme.light,
|
||||
logLevel : 4,
|
||||
flowchart: { curve: 'linear' },
|
||||
gantt : { axisFormat: '%m/%d/%Y' },
|
||||
sequence : { actorMargin: 50 }
|
||||
});
|
||||
mermaid.init();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/* global NexT, CONFIG, PDFObject */
|
||||
|
||||
document.addEventListener('page:loaded', () => {
|
||||
if (document.querySelectorAll('.pdf-container').length) {
|
||||
NexT.utils.getScript(CONFIG.pdf.object_url, {
|
||||
condition: window.PDFObject
|
||||
}).then(() => {
|
||||
document.querySelectorAll('.pdf-container').forEach(element => {
|
||||
PDFObject.embed(element.dataset.target, element, {
|
||||
pdfOpenParams: {
|
||||
navpanes : 0,
|
||||
toolbar : 0,
|
||||
statusbar: 0,
|
||||
pagemode : 'thumbs',
|
||||
view : 'FitH'
|
||||
},
|
||||
PDFJS_URL: CONFIG.pdf.url,
|
||||
height : element.dataset.height
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,452 @@
|
|||
/* global NexT, CONFIG */
|
||||
|
||||
HTMLElement.prototype.wrap = function(wrapper) {
|
||||
this.parentNode.insertBefore(wrapper, this);
|
||||
this.parentNode.removeChild(this);
|
||||
wrapper.appendChild(this);
|
||||
};
|
||||
|
||||
(function() {
|
||||
const onPageLoaded = () => document.dispatchEvent(
|
||||
new Event('page:loaded', {
|
||||
bubbles: true
|
||||
})
|
||||
);
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('readystatechange', onPageLoaded, { once: true });
|
||||
} else {
|
||||
onPageLoaded();
|
||||
}
|
||||
document.addEventListener('pjax:success', onPageLoaded);
|
||||
})();
|
||||
|
||||
NexT.utils = {
|
||||
|
||||
registerExtURL: function() {
|
||||
document.querySelectorAll('span.exturl').forEach(element => {
|
||||
const link = document.createElement('a');
|
||||
// https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings
|
||||
link.href = decodeURIComponent(atob(element.dataset.url).split('').map(c => {
|
||||
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
||||
}).join(''));
|
||||
link.rel = 'noopener external nofollow noreferrer';
|
||||
link.target = '_blank';
|
||||
link.className = element.className;
|
||||
link.title = element.title;
|
||||
link.innerHTML = element.innerHTML;
|
||||
element.parentNode.replaceChild(link, element);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* One-click copy code support.
|
||||
*/
|
||||
registerCopyCode: function() {
|
||||
let figure = document.querySelectorAll('figure.highlight');
|
||||
if (figure.length === 0) figure = document.querySelectorAll('pre:not(.mermaid)');
|
||||
figure.forEach(element => {
|
||||
element.querySelectorAll('.code .line span').forEach(span => {
|
||||
span.classList.forEach(name => {
|
||||
span.classList.replace(name, `hljs-${name}`);
|
||||
});
|
||||
});
|
||||
if (!CONFIG.copycode.enable) return;
|
||||
let target = element;
|
||||
if (CONFIG.copycode.style !== 'mac') target = element.querySelector('.table-container') || element;
|
||||
target.insertAdjacentHTML('beforeend', '<div class="copy-btn"><i class="fa fa-copy fa-fw"></i></div>');
|
||||
const button = element.querySelector('.copy-btn');
|
||||
button.addEventListener('click', () => {
|
||||
const lines = element.querySelector('.code') || element.querySelector('code');
|
||||
const code = lines.innerText;
|
||||
if (navigator.clipboard) {
|
||||
// https://caniuse.com/mdn-api_clipboard_writetext
|
||||
navigator.clipboard.writeText(code).then(() => {
|
||||
button.querySelector('i').className = 'fa fa-check-circle fa-fw';
|
||||
}, () => {
|
||||
button.querySelector('i').className = 'fa fa-times-circle fa-fw';
|
||||
});
|
||||
} else {
|
||||
const ta = document.createElement('textarea');
|
||||
ta.style.top = window.scrollY + 'px'; // Prevent page scrolling
|
||||
ta.style.position = 'absolute';
|
||||
ta.style.opacity = '0';
|
||||
ta.readOnly = true;
|
||||
ta.value = code;
|
||||
document.body.append(ta);
|
||||
ta.select();
|
||||
ta.setSelectionRange(0, code.length);
|
||||
ta.readOnly = false;
|
||||
const result = document.execCommand('copy');
|
||||
button.querySelector('i').className = result ? 'fa fa-check-circle fa-fw' : 'fa fa-times-circle fa-fw';
|
||||
ta.blur(); // For iOS
|
||||
button.blur();
|
||||
document.body.removeChild(ta);
|
||||
}
|
||||
});
|
||||
element.addEventListener('mouseleave', () => {
|
||||
setTimeout(() => {
|
||||
button.querySelector('i').className = 'fa fa-copy fa-fw';
|
||||
}, 300);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
wrapTableWithBox: function() {
|
||||
document.querySelectorAll('table').forEach(element => {
|
||||
const box = document.createElement('div');
|
||||
box.className = 'table-container';
|
||||
element.wrap(box);
|
||||
});
|
||||
},
|
||||
|
||||
registerVideoIframe: function() {
|
||||
document.querySelectorAll('iframe').forEach(element => {
|
||||
const supported = [
|
||||
'www.youtube.com',
|
||||
'player.vimeo.com',
|
||||
'player.youku.com',
|
||||
'player.bilibili.com',
|
||||
'www.tudou.com'
|
||||
].some(host => element.src.includes(host));
|
||||
if (supported && !element.parentNode.matches('.video-container')) {
|
||||
const box = document.createElement('div');
|
||||
box.className = 'video-container';
|
||||
element.wrap(box);
|
||||
const width = Number(element.width);
|
||||
const height = Number(element.height);
|
||||
if (width && height) {
|
||||
box.style.paddingTop = (height / width * 100) + '%';
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateActiveNav: function() {
|
||||
if (!Array.isArray(NexT.utils.sections)) return;
|
||||
let index = NexT.utils.sections.findIndex(element => {
|
||||
return element && element.getBoundingClientRect().top > 10;
|
||||
});
|
||||
if (index === -1) {
|
||||
index = NexT.utils.sections.length - 1;
|
||||
} else if (index > 0) {
|
||||
index--;
|
||||
}
|
||||
this.activateNavByIndex(index);
|
||||
},
|
||||
|
||||
registerScrollPercent: function() {
|
||||
const backToTop = document.querySelector('.back-to-top');
|
||||
const readingProgressBar = document.querySelector('.reading-progress-bar');
|
||||
// For init back to top in sidebar if page was scrolled after page refresh.
|
||||
window.addEventListener('scroll', () => {
|
||||
if (backToTop || readingProgressBar) {
|
||||
const contentHeight = document.body.scrollHeight - window.innerHeight;
|
||||
const scrollPercent = contentHeight > 0 ? Math.min(100 * window.scrollY / contentHeight, 100) : 0;
|
||||
if (backToTop) {
|
||||
backToTop.classList.toggle('back-to-top-on', Math.round(scrollPercent) >= 5);
|
||||
backToTop.querySelector('span').innerText = Math.round(scrollPercent) + '%';
|
||||
}
|
||||
if (readingProgressBar) {
|
||||
readingProgressBar.style.setProperty('--progress', scrollPercent.toFixed(2) + '%');
|
||||
}
|
||||
}
|
||||
this.updateActiveNav();
|
||||
}, { passive: true });
|
||||
|
||||
backToTop && backToTop.addEventListener('click', () => {
|
||||
window.anime({
|
||||
targets : document.scrollingElement,
|
||||
duration : 500,
|
||||
easing : 'linear',
|
||||
scrollTop: 0
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Tabs tag listener (without twitter bootstrap).
|
||||
*/
|
||||
registerTabsTag: function() {
|
||||
// Binding `nav-tabs` & `tab-content` by real time permalink changing.
|
||||
document.querySelectorAll('.tabs ul.nav-tabs .tab').forEach(element => {
|
||||
element.addEventListener('click', event => {
|
||||
event.preventDefault();
|
||||
// Prevent selected tab to select again.
|
||||
if (element.classList.contains('active')) return;
|
||||
const nav = element.parentNode;
|
||||
// Get the height of `tab-pane` which is activated before, and set it as the height of `tab-content` with extra margin / paddings.
|
||||
const tabContent = nav.nextElementSibling;
|
||||
tabContent.style.overflow = 'hidden';
|
||||
tabContent.style.transition = 'height 1s';
|
||||
// Comment system selection tab does not contain .active class.
|
||||
const activeTab = tabContent.querySelector('.active') || tabContent.firstElementChild;
|
||||
// Hight might be `auto`.
|
||||
const prevHeight = parseInt(window.getComputedStyle(activeTab).height.replace('px', ''), 10) || 0;
|
||||
const paddingTop = parseInt(window.getComputedStyle(activeTab).paddingTop.replace('px', ''), 10);
|
||||
const marginBottom = parseInt(window.getComputedStyle(activeTab.firstElementChild).marginBottom.replace('px', ''), 10);
|
||||
tabContent.style.height = prevHeight + paddingTop + marginBottom + 'px';
|
||||
// Add & Remove active class on `nav-tabs` & `tab-content`.
|
||||
[...nav.children].forEach(target => {
|
||||
target.classList.toggle('active', target === element);
|
||||
});
|
||||
// https://stackoverflow.com/questions/20306204/using-queryselector-with-ids-that-are-numbers
|
||||
const tActive = document.getElementById(element.querySelector('a').getAttribute('href').replace('#', ''));
|
||||
[...tActive.parentNode.children].forEach(target => {
|
||||
target.classList.toggle('active', target === tActive);
|
||||
});
|
||||
// Trigger event
|
||||
tActive.dispatchEvent(new Event('tabs:click', {
|
||||
bubbles: true
|
||||
}));
|
||||
// Get the height of `tab-pane` which is activated now.
|
||||
const hasScrollBar = document.body.scrollHeight > (window.innerHeight || document.documentElement.clientHeight);
|
||||
const currHeight = parseInt(window.getComputedStyle(tabContent.querySelector('.active')).height.replace('px', ''), 10);
|
||||
// Reset the height of `tab-content` and see the animation.
|
||||
tabContent.style.height = currHeight + paddingTop + marginBottom + 'px';
|
||||
// Change the height of `tab-content` may cause scrollbar show / disappear, which may result in the change of the `tab-pane`'s height
|
||||
setTimeout(() => {
|
||||
if ((document.body.scrollHeight > (window.innerHeight || document.documentElement.clientHeight)) !== hasScrollBar) {
|
||||
tabContent.style.transition = 'height 0.3s linear';
|
||||
// After the animation, we need reset the height of `tab-content` again.
|
||||
const currHeightAfterScrollBarChange = parseInt(window.getComputedStyle(tabContent.querySelector('.active')).height.replace('px', ''), 10);
|
||||
tabContent.style.height = currHeightAfterScrollBarChange + paddingTop + marginBottom + 'px';
|
||||
}
|
||||
// Remove all the inline styles, and let the height be adaptive again.
|
||||
setTimeout(() => {
|
||||
tabContent.style.transition = '';
|
||||
tabContent.style.height = '';
|
||||
}, 250);
|
||||
}, 1000);
|
||||
if (!CONFIG.stickytabs) return;
|
||||
const offset = nav.parentNode.getBoundingClientRect().top + window.scrollY + 10;
|
||||
window.anime({
|
||||
targets : document.scrollingElement,
|
||||
duration : 500,
|
||||
easing : 'linear',
|
||||
scrollTop: offset
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
window.dispatchEvent(new Event('tabs:register'));
|
||||
},
|
||||
|
||||
registerCanIUseTag: function() {
|
||||
// Get responsive height passed from iframe.
|
||||
window.addEventListener('message', ({ data }) => {
|
||||
if (typeof data === 'string' && data.includes('ciu_embed')) {
|
||||
const featureID = data.split(':')[1];
|
||||
const height = data.split(':')[2];
|
||||
document.querySelector(`iframe[data-feature=${featureID}]`).style.height = parseInt(height, 10) + 5 + 'px';
|
||||
}
|
||||
}, false);
|
||||
},
|
||||
|
||||
registerActiveMenuItem: function() {
|
||||
document.querySelectorAll('.menu-item a[href]').forEach(target => {
|
||||
const isSamePath = target.pathname === location.pathname || target.pathname === location.pathname.replace('index.html', '');
|
||||
const isSubPath = !CONFIG.root.startsWith(target.pathname) && location.pathname.startsWith(target.pathname);
|
||||
target.classList.toggle('menu-item-active', target.hostname === location.hostname && (isSamePath || isSubPath));
|
||||
});
|
||||
},
|
||||
|
||||
registerLangSelect: function() {
|
||||
const selects = document.querySelectorAll('.lang-select');
|
||||
selects.forEach(sel => {
|
||||
sel.value = CONFIG.page.lang;
|
||||
sel.addEventListener('change', () => {
|
||||
const target = sel.options[sel.selectedIndex];
|
||||
document.querySelectorAll('.lang-select-label span').forEach(span => {
|
||||
span.innerText = target.text;
|
||||
});
|
||||
// Disable Pjax to force refresh translation of menu item
|
||||
window.location.href = target.dataset.href;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
registerSidebarTOC: function() {
|
||||
this.sections = [...document.querySelectorAll('.post-toc:not(.placeholder-toc) li a.nav-link')].map(element => {
|
||||
const target = document.getElementById(decodeURI(element.getAttribute('href')).replace('#', ''));
|
||||
// TOC item animation navigate.
|
||||
element.addEventListener('click', event => {
|
||||
event.preventDefault();
|
||||
const offset = target.getBoundingClientRect().top + window.scrollY;
|
||||
window.anime({
|
||||
targets : document.scrollingElement,
|
||||
duration : 500,
|
||||
easing : 'linear',
|
||||
scrollTop: offset,
|
||||
complete : () => {
|
||||
history.pushState(null, document.title, element.href);
|
||||
}
|
||||
});
|
||||
});
|
||||
return target;
|
||||
});
|
||||
this.updateActiveNav();
|
||||
},
|
||||
|
||||
registerPostReward: function() {
|
||||
const button = document.querySelector('.reward-container button');
|
||||
if (!button) return;
|
||||
button.addEventListener('click', () => {
|
||||
document.querySelector('.post-reward').classList.toggle('active');
|
||||
});
|
||||
},
|
||||
|
||||
activateNavByIndex: function(index) {
|
||||
const nav = document.querySelector('.post-toc:not(.placeholder-toc) .nav');
|
||||
if (!nav) return;
|
||||
|
||||
const navItemList = nav.querySelectorAll('.nav-item');
|
||||
const target = navItemList[index];
|
||||
if (!target || target.classList.contains('active-current')) return;
|
||||
|
||||
const singleHeight = navItemList[navItemList.length - 1].offsetHeight;
|
||||
|
||||
nav.querySelectorAll('.active').forEach(navItem => {
|
||||
navItem.classList.remove('active', 'active-current');
|
||||
});
|
||||
target.classList.add('active', 'active-current');
|
||||
|
||||
let activateEle = target.querySelector('.nav-child') || target.parentElement;
|
||||
let navChildHeight = 0;
|
||||
|
||||
while (nav.contains(activateEle)) {
|
||||
if (activateEle.classList.contains('nav-item')) {
|
||||
activateEle.classList.add('active');
|
||||
} else { // .nav-child or .nav
|
||||
// scrollHeight isn't reliable for transitioning child items.
|
||||
// The last nav-item in a list has a margin-bottom of 5px.
|
||||
navChildHeight += (singleHeight * activateEle.childElementCount) + 5;
|
||||
activateEle.style.setProperty('--height', `${navChildHeight}px`);
|
||||
}
|
||||
activateEle = activateEle.parentElement;
|
||||
}
|
||||
|
||||
// Scrolling to center active TOC element if TOC content is taller then viewport.
|
||||
const tocElement = document.querySelector(CONFIG.scheme === 'Pisces' || CONFIG.scheme === 'Gemini' ? '.sidebar-panel-container' : '.sidebar');
|
||||
if (!document.querySelector('.sidebar-toc-active')) return;
|
||||
window.anime({
|
||||
targets : tocElement,
|
||||
duration : 200,
|
||||
easing : 'linear',
|
||||
scrollTop: tocElement.scrollTop - (tocElement.offsetHeight / 2) + target.getBoundingClientRect().top - tocElement.getBoundingClientRect().top
|
||||
});
|
||||
},
|
||||
|
||||
updateSidebarPosition: function() {
|
||||
if (window.innerWidth < 1200 || CONFIG.scheme === 'Pisces' || CONFIG.scheme === 'Gemini') return;
|
||||
// Expand sidebar on post detail page by default, when post has a toc.
|
||||
const hasTOC = document.querySelector('.post-toc:not(.placeholder-toc)');
|
||||
let display = CONFIG.page.sidebar;
|
||||
if (typeof display !== 'boolean') {
|
||||
// There's no definition sidebar in the page front-matter.
|
||||
display = CONFIG.sidebar.display === 'always' || (CONFIG.sidebar.display === 'post' && hasTOC);
|
||||
}
|
||||
if (display) {
|
||||
window.dispatchEvent(new Event('sidebar:show'));
|
||||
}
|
||||
},
|
||||
|
||||
activateSidebarPanel: function(index) {
|
||||
const sidebar = document.querySelector('.sidebar-inner');
|
||||
const activeClassNames = ['sidebar-toc-active', 'sidebar-overview-active'];
|
||||
if (sidebar.classList.contains(activeClassNames[index])) return;
|
||||
|
||||
const panelContainer = sidebar.querySelector('.sidebar-panel-container');
|
||||
const tocPanel = panelContainer.firstElementChild;
|
||||
const overviewPanel = panelContainer.lastElementChild;
|
||||
|
||||
let postTOCHeight = tocPanel.scrollHeight;
|
||||
// For TOC activation, try to use the animated TOC height
|
||||
if (index === 0) {
|
||||
const nav = tocPanel.querySelector('.nav');
|
||||
if (nav) {
|
||||
postTOCHeight = parseInt(nav.style.getPropertyValue('--height'), 10);
|
||||
}
|
||||
}
|
||||
const panelHeights = [
|
||||
postTOCHeight,
|
||||
overviewPanel.scrollHeight
|
||||
];
|
||||
panelContainer.style.setProperty('--inactive-panel-height', `${panelHeights[1 - index]}px`);
|
||||
panelContainer.style.setProperty('--active-panel-height', `${panelHeights[index]}px`);
|
||||
|
||||
sidebar.classList.replace(activeClassNames[1 - index], activeClassNames[index]);
|
||||
},
|
||||
|
||||
getScript: function(src, options = {}, legacyCondition) {
|
||||
if (typeof options === 'function') {
|
||||
return this.getScript(src, {
|
||||
condition: legacyCondition
|
||||
}).then(options);
|
||||
}
|
||||
const {
|
||||
condition = false,
|
||||
attributes: {
|
||||
id = '',
|
||||
async = false,
|
||||
defer = false,
|
||||
crossOrigin = '',
|
||||
dataset = {},
|
||||
...otherAttributes
|
||||
} = {},
|
||||
parentNode = null
|
||||
} = options;
|
||||
return new Promise((resolve, reject) => {
|
||||
if (condition) {
|
||||
resolve();
|
||||
} else {
|
||||
const script = document.createElement('script');
|
||||
|
||||
if (id) script.id = id;
|
||||
if (crossOrigin) script.crossOrigin = crossOrigin;
|
||||
script.async = async;
|
||||
script.defer = defer;
|
||||
Object.assign(script.dataset, dataset);
|
||||
Object.entries(otherAttributes).forEach(([name, value]) => {
|
||||
script.setAttribute(name, String(value));
|
||||
});
|
||||
|
||||
script.onload = resolve;
|
||||
script.onerror = reject;
|
||||
|
||||
if (typeof src === 'object') {
|
||||
const { url, integrity } = src;
|
||||
script.src = url;
|
||||
if (integrity) {
|
||||
script.integrity = integrity;
|
||||
script.crossOrigin = 'anonymous';
|
||||
}
|
||||
} else {
|
||||
script.src = src;
|
||||
}
|
||||
(parentNode || document.head).appendChild(script);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
loadComments: function(selector, legacyCallback) {
|
||||
if (legacyCallback) {
|
||||
return this.loadComments(selector).then(legacyCallback);
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
const element = document.querySelector(selector);
|
||||
if (!CONFIG.comments.lazyload || !element) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
const intersectionObserver = new IntersectionObserver((entries, observer) => {
|
||||
const entry = entries[0];
|
||||
if (!entry.isIntersecting) return;
|
||||
|
||||
resolve();
|
||||
observer.disconnect();
|
||||
});
|
||||
intersectionObserver.observe(element);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
(() => {
|
||||
'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';
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
})();
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 «NexT»
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<h1 align="center"><a href="https://github.com/HubSpot/pace">Progress bar</a> for <a href="https://github.com/theme-next">NexT</a></h1>
|
||||
|
||||
<h1 align="center">Installation</h1>
|
||||
|
||||
<h2>If you want to use the CDN instead of clone this repo, please jump to the Step 3.</h2>
|
||||
|
||||
<h2 align="center">Step 1 → Go to NexT dir</h2>
|
||||
|
||||
<p>Change dir to <strong>NexT</strong> directory. There must be <code>layout</code>, <code>source</code>, <code>languages</code> and other directories:</p>
|
||||
<pre><code class="sh">$ cd themes/next
|
||||
$ ls
|
||||
_config.yml crowdin.yml docs gulpfile.js languages layout LICENSE.md package.json README.md scripts source
|
||||
</code></pre>
|
||||
<h2 align="center">Step 2 → Get module</h2>
|
||||
|
||||
<p>Install module to <code>source/lib</code> directory:</p>
|
||||
<pre><code class="sh">$ git clone https://github.com/theme-next/theme-next-pace source/lib/pace
|
||||
</code></pre>
|
||||
<h2 align="center">Step 3 → Set it up</h2>
|
||||
|
||||
<p>Enable module in <strong>NexT</strong> <code>_config.yml</code> file and select your theme:</p>
|
||||
<pre><code class="yml">pace:
|
||||
enable: true
|
||||
# Themes list:
|
||||
# big-counter | bounce | barber-shop | center-atom | center-circle | center-radar | center-simple
|
||||
# corner-indicator | fill-left | flat-top | flash | loading-bar | mac-osx | material | minimal
|
||||
theme: minimal
|
||||
</code></pre>
|
||||
<p><strong>And, if you wants to use the CDN, then need to set:</strong> (you also need to find your corresponding theme css link in <a href="https://www.jsdelivr.com/package/npm/pace-js?path=themes">jsdelivr</a>)</p>
|
||||
<pre><code class="yml">vendors:
|
||||
...
|
||||
pace: //cdn.jsdelivr.net/npm/pace-js@1/pace.min.js
|
||||
pace_css: //cdn.jsdelivr.net/npm/pace-js@1/themes/blue/pace-theme-minimal.css
|
||||
</code></pre>
|
||||
<h1 align="center">Update</h1>
|
||||
|
||||
<pre><code class="sh">$ cd themes/next/source/lib/pace
|
||||
$ git pull
|
||||
</code></pre>
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace,.pace .pace-progress{width:100%;overflow:hidden}.pace,.pace .pace-activity{position:fixed;top:0;left:0}.pace{-webkit-pointer-events:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:2000;height:12px;background:#fff}.pace-inactive{display:none}.pace .pace-progress{background-color:#29d;position:fixed;top:0;bottom:0;right:100%}.pace .pace-activity{right:-32px;bottom:0;-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0);background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(.25,rgba(255,255,255,.2)),color-stop(.25,transparent),color-stop(.5,transparent),color-stop(.5,rgba(255,255,255,.2)),color-stop(.75,rgba(255,255,255,.2)),color-stop(.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.2) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.2) 50%,rgba(255,255,255,.2) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,.2) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.2) 50%,rgba(255,255,255,.2) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.2) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.2) 50%,rgba(255,255,255,.2) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.2) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.2) 50%,rgba(255,255,255,.2) 75%,transparent 75%,transparent);-webkit-background-size:32px 32px;-moz-background-size:32px 32px;-o-background-size:32px 32px;background-size:32px 32px;-webkit-animation:pace-theme-barber-shop-motion .5s linear infinite;-moz-animation:pace-theme-barber-shop-motion .5s linear infinite;-ms-animation:pace-theme-barber-shop-motion .5s linear infinite;-o-animation:pace-theme-barber-shop-motion .5s linear infinite;animation:pace-theme-barber-shop-motion .5s linear infinite}@-webkit-keyframes pace-theme-barber-shop-motion{0%{-webkit-transform:none;transform:none}100%{-webkit-transform:translate(-32px,0);transform:translate(-32px,0)}}@-moz-keyframes pace-theme-barber-shop-motion{0%{-moz-transform:none;transform:none}100%{-moz-transform:translate(-32px,0);transform:translate(-32px,0)}}@-o-keyframes pace-theme-barber-shop-motion{0%{-o-transform:none;transform:none}100%{-o-transform:translate(-32px,0);transform:translate(-32px,0)}}@-ms-keyframes pace-theme-barber-shop-motion{0%{-ms-transform:none;transform:none}100%{-ms-transform:translate(-32px,0);transform:translate(-32px,0)}}@keyframes pace-theme-barber-shop-motion{0%{transform:none}100%{transform:translate(-32px,0)}}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace{-webkit-pointer-events:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.pace.pace-inactive .pace-progress{display:none}.pace .pace-progress{position:fixed;z-index:2000;top:0;right:0;height:5rem;width:5rem;-webkit-transform:translate3d(0,0,0)!important;-ms-transform:translate3d(0,0,0)!important;transform:translate3d(0,0,0)!important}.pace .pace-progress:after{display:block;position:absolute;top:0;right:.5rem;content:attr(data-progress-text);font-family:"Helvetica Neue",sans-serif;font-weight:100;font-size:5rem;line-height:1;text-align:right;color:rgba(34,153,221,.19999999999999996)}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace{width:140px;height:300px;position:fixed;top:-90px;right:-20px;z-index:2000;-webkit-transform:scale(0);-moz-transform:scale(0);-ms-transform:scale(0);-o-transform:scale(0);transform:scale(0);opacity:0;-webkit-transition:all 2s linear 0s;-moz-transition:all 2s linear 0s;transition:all 2s linear 0s}.pace.pace-active{-webkit-transform:scale(.25);-moz-transform:scale(.25);-ms-transform:scale(.25);-o-transform:scale(.25);transform:scale(.25);opacity:1}.pace .pace-activity{width:140px;height:140px;border-radius:70px;background:#29d;position:absolute;top:0;z-index:1911;-webkit-animation:pace-bounce 1s infinite;-moz-animation:pace-bounce 1s infinite;-o-animation:pace-bounce 1s infinite;-ms-animation:pace-bounce 1s infinite;animation:pace-bounce 1s infinite}.pace .pace-progress{position:absolute;display:block;left:50%;bottom:0;z-index:1910;margin-left:-30px;width:60px;height:75px;background:rgba(20,20,20,.1);box-shadow:0 0 20px 35px rgba(20,20,20,.1);border-radius:30px/40px;-webkit-transform:scaleY(.3)!important;-moz-transform:scaleY(.3)!important;-ms-transform:scaleY(.3)!important;-o-transform:scaleY(.3)!important;transform:scaleY(.3)!important;-webkit-animation:pace-compress .5s infinite alternate;-moz-animation:pace-compress .5s infinite alternate;-o-animation:pace-compress .5s infinite alternate;-ms-animation:pace-compress .5s infinite alternate;animation:pace-compress .5s infinite alternate}@-webkit-keyframes pace-bounce{0%,100%,95%{top:0;-webkit-animation-timing-function:ease-in}50%{top:140px;height:140px;-webkit-animation-timing-function:ease-out}55%{top:160px;height:120px;border-radius:70px/60px;-webkit-animation-timing-function:ease-in}65%{top:120px;height:140px;border-radius:70px;-webkit-animation-timing-function:ease-out}}@-moz-keyframes pace-bounce{0%,100%,95%{top:0;-moz-animation-timing-function:ease-in}50%{top:140px;height:140px;-moz-animation-timing-function:ease-out}55%{top:160px;height:120px;border-radius:70px/60px;-moz-animation-timing-function:ease-in}65%{top:120px;height:140px;border-radius:70px;-moz-animation-timing-function:ease-out}}@keyframes pace-bounce{0%,100%,95%{top:0;animation-timing-function:ease-in}50%{top:140px;height:140px;animation-timing-function:ease-out}55%{top:160px;height:120px;border-radius:70px/60px;animation-timing-function:ease-in}65%{top:120px;height:140px;border-radius:70px;animation-timing-function:ease-out}}@-webkit-keyframes pace-compress{0%{bottom:0;margin-left:-30px;width:60px;height:75px;background:rgba(20,20,20,.1);box-shadow:0 0 20px 35px rgba(20,20,20,.1);border-radius:30px/40px;-webkit-animation-timing-function:ease-in}100%{bottom:30px;margin-left:-10px;width:20px;height:5px;background:rgba(20,20,20,.3);box-shadow:0 0 20px 35px rgba(20,20,20,.3);border-radius:20px;-webkit-animation-timing-function:ease-out}}@-moz-keyframes pace-compress{0%{bottom:0;margin-left:-30px;width:60px;height:75px;background:rgba(20,20,20,.1);box-shadow:0 0 20px 35px rgba(20,20,20,.1);border-radius:30px/40px;-moz-animation-timing-function:ease-in}100%{bottom:30px;margin-left:-10px;width:20px;height:5px;background:rgba(20,20,20,.3);box-shadow:0 0 20px 35px rgba(20,20,20,.3);border-radius:20px;-moz-animation-timing-function:ease-out}}@keyframes pace-compress{0%{bottom:0;margin-left:-30px;width:60px;height:75px;background:rgba(20,20,20,.1);box-shadow:0 0 20px 35px rgba(20,20,20,.1);border-radius:30px/40px;animation-timing-function:ease-in}100%{bottom:30px;margin-left:-10px;width:20px;height:5px;background:rgba(20,20,20,.3);box-shadow:0 0 20px 35px rgba(20,20,20,.3);border-radius:20px;animation-timing-function:ease-out}}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace,.pace .pace-progress{z-index:2000;height:60px;width:100px}.pace .pace-activity,.pace .pace-progress:before{border-radius:50%;display:block;position:absolute}.pace.pace-inactive{display:none}.pace{-webkit-pointer-events:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;position:fixed;margin:auto;top:0;left:0;right:0;bottom:0}.pace .pace-progress{position:absolute;-webkit-transform:translate3d(0,0,0)!important;-ms-transform:translate3d(0,0,0)!important;transform:translate3d(0,0,0)!important}.pace .pace-progress:before{content:attr(data-progress-text);text-align:center;color:#fff;background:#29d;font-family:"Helvetica Neue",sans-serif;font-size:14px;font-weight:100;line-height:1;padding:20% 0 7px;width:50%;height:40%;margin:10px 0 0 30px;z-index:999}.pace .pace-activity{font-size:15px;line-height:1;z-index:2000;-webkit-animation:pace-theme-center-atom-spin 2s linear infinite;-moz-animation:pace-theme-center-atom-spin 2s linear infinite;-o-animation:pace-theme-center-atom-spin 2s linear infinite;animation:pace-theme-center-atom-spin 2s linear infinite;border:5px solid #29d;content:' ';top:0;left:0;height:60px;width:100px}.pace .pace-activity:after,.pace .pace-activity:before{content:' ';display:block;position:absolute;top:-5px;left:-5px;height:60px;width:100px}.pace .pace-activity:after{border-radius:50%;border:5px solid #29d;-webkit-transform:rotate(60deg);-moz-transform:rotate(60deg);-o-transform:rotate(60deg);transform:rotate(60deg)}.pace .pace-activity:before{border-radius:50%;border:5px solid #29d;-webkit-transform:rotate(120deg);-moz-transform:rotate(120deg);-o-transform:rotate(120deg);transform:rotate(120deg)}@-webkit-keyframes pace-theme-center-atom-spin{0%{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(359deg)}}@-moz-keyframes pace-theme-center-atom-spin{0%{-moz-transform:rotate(0)}100%{-moz-transform:rotate(359deg)}}@-o-keyframes pace-theme-center-atom-spin{0%{-o-transform:rotate(0)}100%{-o-transform:rotate(359deg)}}@keyframes pace-theme-center-atom-spin{0%{transform:rotate(0)}100%{transform:rotate(359deg)}}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace,.pace .pace-progress{z-index:2000;left:0;top:0;height:6rem}.pace{-webkit-pointer-events:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;-webkit-perspective:12rem;-moz-perspective:12rem;-ms-perspective:12rem;-o-perspective:12rem;perspective:12rem;position:fixed;width:6rem;margin:auto;right:0;bottom:0}.pace.pace-inactive .pace-progress{display:none}.pace .pace-progress{display:block;position:absolute;width:6rem!important;line-height:6rem;font-size:2rem;border-radius:50%;background:rgba(34,153,221,.8);color:#fff;font-family:"Helvetica Neue",sans-serif;font-weight:100;text-align:center;-webkit-animation:pace-theme-center-circle-spin linear infinite 2s;-moz-animation:pace-theme-center-circle-spin linear infinite 2s;-ms-animation:pace-theme-center-circle-spin linear infinite 2s;-o-animation:pace-theme-center-circle-spin linear infinite 2s;animation:pace-theme-center-circle-spin linear infinite 2s;-webkit-transform-style:preserve-3d;-moz-transform-style:preserve-3d;-ms-transform-style:preserve-3d;-o-transform-style:preserve-3d;transform-style:preserve-3d}.pace .pace-progress:after{content:attr(data-progress-text);display:block}@-webkit-keyframes pace-theme-center-circle-spin{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(360deg)}}@-moz-keyframes pace-theme-center-circle-spin{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(360deg)}}@-ms-keyframes pace-theme-center-circle-spin{from{-ms-transform:rotateY(0)}to{-ms-transform:rotateY(360deg)}}@-o-keyframes pace-theme-center-circle-spin{from{-o-transform:rotateY(0)}to{-o-transform:rotateY(360deg)}}@keyframes pace-theme-center-circle-spin{from{transform:rotateY(0)}to{transform:rotateY(360deg)}}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace,.pace .pace-activity{z-index:2000;height:90px;width:90px}.pace{-webkit-pointer-events:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;position:fixed;margin:auto;top:0;left:0;right:0;bottom:0}.pace.pace-inactive .pace-activity{display:none}.pace .pace-activity,.pace .pace-activity:before{position:absolute;display:block;border-color:#29d transparent transparent;border-radius:50%}.pace .pace-activity{left:-30px;top:-30px;border-width:30px;border-style:double;-webkit-animation:spin 1s linear infinite;-moz-animation:spin 1s linear infinite;-o-animation:spin 1s linear infinite;animation:spin 1s linear infinite}.pace .pace-activity:before{content:' ';top:10px;left:10px;height:50px;width:50px;border-width:10px;border-style:solid}@-webkit-keyframes spin{100%{-webkit-transform:rotate(359deg)}}@-moz-keyframes spin{100%{-moz-transform:rotate(359deg)}}@-o-keyframes spin{100%{-moz-transform:rotate(359deg)}}@keyframes spin{100%{transform:rotate(359deg)}}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace{-webkit-pointer-events:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:2000;position:fixed;margin:auto;top:0;left:0;right:0;bottom:0;height:5px;width:200px;background:#fff;border:1px solid #29d;overflow:hidden}.pace .pace-progress{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;-o-box-sizing:border-box;box-sizing:border-box;-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0);max-width:200px;z-index:2000;display:block;position:absolute;top:0;right:100%;height:100%;width:100%;background:#29d}.pace.pace-inactive{display:none}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace{-webkit-pointer-events:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.pace .pace-activity{display:block;position:fixed;z-index:2000;top:0;right:0;width:300px;height:300px;background:#29d;-webkit-transition:-webkit-transform .3s;transition:transform .3s;-webkit-transform:translateX(100%) translateY(-100%) rotate(45deg);transform:translateX(100%) translateY(-100%) rotate(45deg);pointer-events:none}.pace.pace-active .pace-activity{-webkit-transform:translateX(50%) translateY(-50%) rotate(45deg);transform:translateX(50%) translateY(-50%) rotate(45deg)}.pace .pace-activity::after,.pace .pace-activity::before{-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;bottom:30px;left:50%;display:block;border:5px solid #fff;border-radius:50%;content:''}.pace .pace-activity::before{margin-left:-40px;width:80px;height:80px;border-right-color:rgba(0,0,0,.2);border-left-color:rgba(0,0,0,.2);-webkit-animation:pace-theme-corner-indicator-spin 3s linear infinite;animation:pace-theme-corner-indicator-spin 3s linear infinite}.pace .pace-activity::after{bottom:50px;margin-left:-20px;width:40px;height:40px;border-top-color:rgba(0,0,0,.2);border-bottom-color:rgba(0,0,0,.2);-webkit-animation:pace-theme-corner-indicator-spin 1s linear infinite;animation:pace-theme-corner-indicator-spin 1s linear infinite}@-webkit-keyframes pace-theme-corner-indicator-spin{0%{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(359deg)}}@keyframes pace-theme-corner-indicator-spin{0%{transform:rotate(0)}100%{transform:rotate(359deg)}}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace{-webkit-pointer-events:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.pace-inactive{display:none}.pace .pace-progress{background-color:rgba(34,153,221,.19999999999999996);position:fixed;z-index:-1;top:0;right:100%;bottom:0;width:100%}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace{-webkit-pointer-events:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.pace-inactive{display:none}.pace .pace-progress{background:#29d;position:fixed;z-index:2000;top:0;right:100%;width:100%;height:2px}.pace .pace-progress-inner{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;-webkit-transform:rotate(3deg) translate(0,-4px);-moz-transform:rotate(3deg) translate(0,-4px);-ms-transform:rotate(3deg) translate(0,-4px);-o-transform:rotate(3deg) translate(0,-4px);transform:rotate(3deg) translate(0,-4px)}.pace .pace-activity{display:block;position:fixed;z-index:2000;top:15px;right:15px;width:14px;height:14px;border:2px solid transparent;border-top-color:#29d;border-left-color:#29d;border-radius:10px;-webkit-animation:pace-spinner .4s linear infinite;-moz-animation:pace-spinner .4s linear infinite;-ms-animation:pace-spinner .4s linear infinite;-o-animation:pace-spinner .4s linear infinite;animation:pace-spinner .4s linear infinite}@-webkit-keyframes pace-spinner{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes pace-spinner{0%{-moz-transform:rotate(0);transform:rotate(0)}100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes pace-spinner{0%{-o-transform:rotate(0);transform:rotate(0)}100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes pace-spinner{0%{-ms-transform:rotate(0);transform:rotate(0)}100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes pace-spinner{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace{-webkit-pointer-events:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;position:fixed;top:0;left:0;width:100%;-webkit-transform:translate3d(0,-50px,0);-ms-transform:translate3d(0,-50px,0);transform:translate3d(0,-50px,0);-webkit-transition:-webkit-transform .5s ease-out;-ms-transition:-webkit-transform .5s ease-out;transition:transform .5s ease-out}.pace.pace-active{-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.pace .pace-progress{display:block;position:fixed;z-index:2000;top:0;right:100%;width:100%;height:10px;background:#29d;pointer-events:none}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace,.pace .pace-progress{width:100%;height:12px;overflow:hidden}.pace,.pace .pace-activity{position:fixed;top:0;left:0}.pace{-webkit-pointer-events:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:2000;background:#fff}.pace-inactive{display:none}.pace .pace-progress{background-color:#0087E1;position:fixed;top:0;right:100%;-webkit-border-radius:0 0 4px;-moz-border-radius:0 0 4px;-o-border-radius:0 0 4px;border-radius:0 0 4px;-webkit-box-shadow:inset -1px 0 #00558F,inset 0 -1px #00558F,inset 0 2px rgba(255,255,255,.5),inset 0 6px rgba(255,255,255,.3);-moz-box-shadow:inset -1px 0 #00558F,inset 0 -1px #00558F,inset 0 2px rgba(255,255,255,.5),inset 0 6px rgba(255,255,255,.3);-o-box-shadow:inset -1px 0 #00558F,inset 0 -1px #00558F,inset 0 2px rgba(255,255,255,.5),inset 0 6px rgba(255,255,255,.3);box-shadow:inset -1px 0 #00558F,inset 0 -1px #00558F,inset 0 2px rgba(255,255,255,.5),inset 0 6px rgba(255,255,255,.3)}.pace .pace-activity{right:-28px;bottom:0;-webkit-background-image:radial-gradient(rgba(255,255,255,.65) 0,rgba(255,255,255,.15) 100%);-moz-background-image:radial-gradient(rgba(255,255,255,.65) 0,rgba(255,255,255,.15) 100%);-o-background-image:radial-gradient(rgba(255,255,255,.65) 0,rgba(255,255,255,.15) 100%);background-image:radial-gradient(rgba(255,255,255,.65) 0,rgba(255,255,255,.15) 100%);-webkit-background-size:28px 100%;-moz-background-size:28px 100%;-o-background-size:28px 100%;background-size:28px 100%;-webkit-animation:pace-theme-mac-osx-motion .5s linear infinite;-moz-animation:pace-theme-mac-osx-motion .5s linear infinite;-ms-animation:pace-theme-mac-osx-motion .5s linear infinite;-o-animation:pace-theme-mac-osx-motion .5s linear infinite;animation:pace-theme-mac-osx-motion .5s linear infinite}@-webkit-keyframes pace-theme-mac-osx-motion{0%{-webkit-transform:none;transform:none}100%{-webkit-transform:translate(-28px,0);transform:translate(-28px,0)}}@-moz-keyframes pace-theme-mac-osx-motion{0%{-moz-transform:none;transform:none}100%{-moz-transform:translate(-28px,0);transform:translate(-28px,0)}}@-o-keyframes pace-theme-mac-osx-motion{0%{-o-transform:none;transform:none}100%{-o-transform:translate(-28px,0);transform:translate(-28px,0)}}@-ms-keyframes pace-theme-mac-osx-motion{0%{-ms-transform:none;transform:none}100%{-ms-transform:translate(-28px,0);transform:translate(-28px,0)}}@keyframes pace-theme-mac-osx-motion{0%{transform:none}100%{transform:translate(-28px,0)}}
|
||||
|
|
@ -0,0 +1 @@
|
|||
.pace{-webkit-pointer-events:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.pace-inactive{display:none}.pace .pace-progress{background:#29d;position:fixed;z-index:2000;top:0;right:100%;width:100%;height:2px}
|
||||
|
|
@ -0,0 +1 @@
|
|||
[{"name":"如鱼饮水,冷暖自知","site":"https://wangjiezhe.com","avatar":"https://gravatar.loli.net/avatar/e09cf54e933e5a690716e68961ff3b1c?s=512"},{"name":"如鱼饮水,冷暖自知","site":"https://wangjiezhe.com","avatar":"https://gravatar.loli.net/avatar/e09cf54e933e5a690716e68961ff3b1c?s=512"},{"name":"如鱼饮水,冷暖自知","site":"https://wangjiezhe.com","avatar":"https://gravatar.loli.net/avatar/e09cf54e933e5a690716e68961ff3b1c?s=512"}]
|
||||
|
|
@ -0,0 +1,476 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<search>
|
||||
<entry>
|
||||
<title>esxi+openwrt+dsm+homeassistant 软路由 all in one</title>
|
||||
<url>/2023/03/23/esxi+openwrt+dsm+homeassistant-%E8%BD%AF%E8%B7%AF%E7%94%B1all-in-one/</url>
|
||||
<content><![CDATA[<p>软路由 all in one,在J425小主机上安装esxi+openwrt+dsm+homeassistant,集软路由、网盘、智能家居控制于一体。</p>
|
||||
<span id="more"></span>
|
||||
|
||||
<h2 id="硬件介绍"><a href="#硬件介绍" class="headerlink" title="硬件介绍"></a>硬件介绍</h2><h2 id="软件安装"><a href="#软件安装" class="headerlink" title="软件安装"></a>软件安装</h2><ol>
|
||||
<li><a href="/2023/03/23/esxi8.0%E5%AE%89%E8%A3%85/" title="esxi8.0安装">esxi8.0安装</a></li>
|
||||
<li><a href="/2023/03/24/esxi%E5%AE%89%E8%A3%85openwrt/" title="esxi+openwrt作为旁路由">esxi+openwrt作为旁路由</a></li>
|
||||
<li><a href="/2023/03/24/esxi%E5%AE%89%E8%A3%85%E7%BE%A4%E6%99%96dsm7.1/" title="esxi安装群晖dsm7.1">esxi安装群晖dsm7.1</a></li>
|
||||
<li><a href="/2023/03/24/esxi%E5%AE%89%E8%A3%85homeassistant/" title="esxi安装homeassistant">esxi安装homeassistant</a></li>
|
||||
</ol>
|
||||
]]></content>
|
||||
<tags>
|
||||
<tag>esxi</tag>
|
||||
<tag>homeassistant</tag>
|
||||
<tag>openwrt</tag>
|
||||
<tag>dsm</tag>
|
||||
<tag>软路由</tag>
|
||||
<tag>群晖</tag>
|
||||
</tags>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>esxi常规配置</title>
|
||||
<url>/2023/03/26/esxi%E5%B8%B8%E8%A7%84%E9%85%8D%E7%BD%AE/</url>
|
||||
<content><![CDATA[<p>esxi修改网卡顺序、网卡直通、修改安全策略、开机自动启动虚拟机。</p>
|
||||
<span id="more"></span>
|
||||
|
||||
<h2 id="修改网卡顺序"><a href="#修改网卡顺序" class="headerlink" title="修改网卡顺序"></a>修改网卡顺序</h2><p>系统中网卡的显示顺序可能和实际的对应不上,可以修改相关的配置文件,让其能和实际的端口对上。</p>
|
||||
<p>先确定当前的顺序,以及希望修改后的顺序:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>实际网口名称</th>
|
||||
<th>ESXi中默认网口名称</th>
|
||||
<th>希望的网口名称</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td>eth0</td>
|
||||
<td>vmnic1</td>
|
||||
<td>vmnic0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>eth1</td>
|
||||
<td>vmnic2</td>
|
||||
<td>vmnic1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>eth2</td>
|
||||
<td>vmnic0</td>
|
||||
<td>vmnic2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>eth3</td>
|
||||
<td>vmnic3</td>
|
||||
<td>vmnic3</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<ol>
|
||||
<li><p>开启维护模式,和ssh连接。</p>
|
||||
</li>
|
||||
<li><p>查看系统中当前pci和逻辑pci对应的网卡名称</p>
|
||||
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@bogon:~] localcli --plugin-dir /usr/lib/vmware/esxcli/int/ deviceInternal alias list</span><br><span class="line">Bus type Bus address Alias</span><br><span class="line">------------------------------------</span><br><span class="line">pci m00008501 vmnic0</span><br><span class="line">pci m00008901 vmhba0</span><br><span class="line">pci p0000:04:00.0 vmnic3</span><br><span class="line">pci s00000003.00 vmnic1</span><br><span class="line">pci p0000:02:00.0 vmnic2</span><br><span class="line">logical pci#s00000003.00#0 vmnic1</span><br><span class="line">logical pci#m00008501#0 vmnic0</span><br><span class="line">logical pci#m00008901#0 vmhba0</span><br><span class="line">logical pci#p0000:02:00.0#0 vmnic2</span><br><span class="line">logical pci#p0000:04:00.0#0 vmnic3</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
|
||||
<li><p>修改网卡名称,这里pci和逻辑pci对应的名称要同时修改,并且要一致。</p>
|
||||
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[root@bogon:~] localcli --plugin-dir /usr/lib/vmware/esxcli/int/ deviceInternal alias store --bus-type pci --alias vmnic0 --bus-address s00000003.00</span><br><span class="line">[root@bogon:~] localcli --plugin-dir /usr/lib/vmware/esxcli/int/ deviceInternal alias store --bus-type logical --alias vmnic0 --bus-address "pci#s00000003.00#0"</span><br><span class="line"></span><br><span class="line">[root@bogon:~] localcli --plugin-dir /usr/lib/vmware/esxcli/int/ deviceInternal alias store --bus-type pci --alias vmnic1 --bus-address p0000:02:00.0</span><br><span class="line">[root@bogon:~] localcli --plugin-dir /usr/lib/vmware/esxcli/int/ deviceInternal alias store --bus-type logical --alias vmnic1 --bus-address "pci#p0000:02:00.0#0"</span><br><span class="line"></span><br><span class="line">[root@bogon:~] localcli --plugin-dir /usr/lib/vmware/esxcli/int/ deviceInternal alias store --bus-type pci --alias vmnic2 --bus-address m00008501</span><br><span class="line">[root@bogon:~] localcli --plugin-dir /usr/lib/vmware/esxcli/int/ deviceInternal alias store --bus-type logical --alias vmnic2 --bus-address "pci#m00008501#0"</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
|
||||
<li><p>重启机器</p>
|
||||
</li>
|
||||
</ol>
|
||||
<h2 id="网卡直通"><a href="#网卡直通" class="headerlink" title="网卡直通"></a>网卡直通</h2><p>安装软路由时,需要将网卡直通,从而发挥网卡的最大性能。</p>
|
||||
<ol>
|
||||
<li><p>进入esxi的管理页面</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422142105492.png" alt="image-20230422142105492"></p>
|
||||
</li>
|
||||
</ol>
|
||||
<div class="note primary"><p>注:至少要保留一个网口,用来作为esxi的管理网口,否则将无法登录esxi</p>
|
||||
</div>
|
||||
|
||||
<ol start="2">
|
||||
<li>选择需要直通的网口,进行切换即可</li>
|
||||
</ol>
|
||||
<h2 id="修改安全策略"><a href="#修改安全策略" class="headerlink" title="修改安全策略"></a>修改安全策略</h2><p>可能会出现虚拟机和esxi之间相互ping不通的情况,这是由于esxi的安全策略导致的</p>
|
||||
<ol>
|
||||
<li><p>依次点击网络->虚拟交换机->编辑vSwith0</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422143110862.png" alt="image-20230422143110862"></p>
|
||||
</li>
|
||||
<li><p>将安全选项中,混杂模式和伪传输改为接受</p>
|
||||
</li>
|
||||
</ol>
|
||||
<h2 id="开机自动启动虚拟机"><a href="#开机自动启动虚拟机" class="headerlink" title="开机自动启动虚拟机"></a>开机自动启动虚拟机</h2><p>设置开启后自动启动虚拟机,以及启动顺序</p>
|
||||
<p>1.依次点击主机->管理->系统->自动启动->编辑设置,将总开关打开</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422143559690.png" alt="image-20230422143559690"></p>
|
||||
<p>2.选择虚拟机,设置是否开机自启、调整启动的顺序和延迟启动时间。</p>
|
||||
<ul>
|
||||
<li>注:这里最好错开启动,不要同时启动,由依赖的虚拟机先启动。</li>
|
||||
</ul>
|
||||
]]></content>
|
||||
<tags>
|
||||
<tag>esxi</tag>
|
||||
<tag>软路由</tag>
|
||||
</tags>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>esxi安装homeassistant</title>
|
||||
<url>/2023/03/24/esxi%E5%AE%89%E8%A3%85homeassistant/</url>
|
||||
<content><![CDATA[<p>在esxi上安装homeassistant</p>
|
||||
<span id="more"></span>
|
||||
|
||||
<h2 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h2>]]></content>
|
||||
<tags>
|
||||
<tag>esxi</tag>
|
||||
<tag>homeassistant</tag>
|
||||
</tags>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>esxi+openwrt作为旁路由</title>
|
||||
<url>/2023/03/24/esxi%E5%AE%89%E8%A3%85openwrt/</url>
|
||||
<content><![CDATA[<p>在esxi上安装openwrt,并作为旁路由来使用。</p>
|
||||
<span id="more"></span>
|
||||
|
||||
<h2 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h2><ul>
|
||||
<li>starwindconverter.exe 用来将img转换为VMDK</li>
|
||||
<li>openwrt-x86-64-generic-squashfs-combined-efi.img.gz openwrt固件包</li>
|
||||
</ul>
|
||||
<h2 id="1-构建-获取openWRT"><a href="#1-构建-获取openWRT" class="headerlink" title="1. 构建/获取openWRT"></a>1. 构建/获取openWRT</h2><p>这里推荐使用<a href="https://supes.top/?version=22.03&target=x86/64&id=generic">supes.top</a> 自己选择需要的固件,然后进行构建。5分钟左右就能获取到自定义的固件。</p>
|
||||
<ol>
|
||||
<li>访问<a href="https://supes.top/?version=22.03&target=x86/64&id=generic">supes.top</a> 官网</li>
|
||||
</ol>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422145319548.png" alt="image-20230422145319548"></p>
|
||||
<ol start="2">
|
||||
<li><p>自己根据需求去构建,或者是直接下载构建好的通用包</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422145651697.png" alt="image-20230422145651697"></p>
|
||||
</li>
|
||||
</ol>
|
||||
<ul>
|
||||
<li>注:目前免费的用户,一天之内只能构建一次,有需求的可充值解锁。</li>
|
||||
</ul>
|
||||
<h2 id="2-转换固件为vmdk格式"><a href="#2-转换固件为vmdk格式" class="headerlink" title="2. 转换固件为vmdk格式"></a>2. 转换固件为vmdk格式</h2><ol>
|
||||
<li><p>解压<strong>openwrt-x86-64-generic-squashfs-combined-efi.img.gz</strong></p>
|
||||
</li>
|
||||
<li><p>解压后的文件是<strong>openwrt-x86-64-generic-squashfs-combined-efi.img</strong>,这个格式是无法在esxi中直接使用的,因此需要转一下</p>
|
||||
</li>
|
||||
<li><p>安装<strong>starwindconverter.exe</strong> ,没啥可交代的,一路next即可。</p>
|
||||
</li>
|
||||
<li><p>打开安装好的starwindconverter软件,选择<strong>local file->next</strong></p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422150336027.png" alt="image-20230422150336027"></p>
|
||||
</li>
|
||||
<li><p>选择解压后的<strong>openwrt-x86-64-generic-squashfs-combined-efi.img</strong></p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422150500119.png" alt="image-20230422150500119"></p>
|
||||
</li>
|
||||
<li><p>还是选择<strong>local file</strong></p>
|
||||
</li>
|
||||
</ol>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422150951371.png" alt="image-20230422150951371"></p>
|
||||
<ol start="7">
|
||||
<li><p>选择<strong>VMDK</strong></p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422151034204.png" alt="image-20230422151034204"></p>
|
||||
</li>
|
||||
<li><p>选择<strong>ESXI Server image</strong></p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422151136889.png" alt="image-20230422151136889"></p>
|
||||
</li>
|
||||
</ol>
|
||||
<p>9.选择** ESXI pre-allocates image**</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422151215810.png" alt="image-20230422151215810"></p>
|
||||
<p>10.选择输出的路径和名称,点击conver</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422151331578.png" alt="image-20230422151331578"></p>
|
||||
<p>11.转换完成后,会出来两个大小不一样的文件</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422151557911.png" alt="image-20230422151557911"></p>
|
||||
<h2 id="3-创建虚拟机"><a href="#3-创建虚拟机" class="headerlink" title="3. 创建虚拟机"></a>3. 创建虚拟机</h2><ol>
|
||||
<li><p>进入esxi的管理页面,依次点击虚拟机->创建虚拟机</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422151821830.png" alt="image-20230422151821830"></p>
|
||||
</li>
|
||||
<li><p>选择名称和客户机操作系统</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422152710801.png" alt="image-20230422152710801"></p>
|
||||
</li>
|
||||
</ol>
|
||||
<p>客户机操作系统系列: 选择Linux,客户机操作系统版本:其他Linux(64位)</p>
|
||||
<ol start="3">
|
||||
<li><p>选择存储,如果由多块硬盘,可选择安装的位置</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422152842237.png" alt="image-20230422152842237"></p>
|
||||
</li>
|
||||
<li><p>内存设置为1G,删除掉硬盘以及其他不需要的设备</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422153126229.png" alt="image-20230422153126229"></p>
|
||||
</li>
|
||||
<li><p>添加硬盘->现有硬盘</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422153403639.png" alt="image-20230422153403639"></p>
|
||||
</li>
|
||||
<li><p>将转换后的两个vmdk文件全部都上传上去(只会显示1个),然后选择上传的文件</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422153716292.png" alt="image-20230422153716292"></p>
|
||||
<ul>
|
||||
<li><p>注:如果需要网卡直通,可点击添加其他设备->PCI设备。</p>
|
||||
</li>
|
||||
<li><p>如果由多个网卡,但是这里无法点击,说明这个设别没有进行直通。如何直通可参考之前的文章 <a href="/2023/03/26/esxi%E5%B8%B8%E8%A7%84%E9%85%8D%E7%BD%AE/" title="esxi常规配置">esxi常规配置</a></p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422154249143.png" alt="image-20230422154249143"></p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p>点击下一步,确认一下配置,无误后点击完成即可。</p>
|
||||
</li>
|
||||
<li><p>选中虚拟机,点击打开电源,等待开机</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422154411639.png" alt="image-20230422154411639"></p>
|
||||
</li>
|
||||
<li><p>点击进入操作台,可看到openwrt已经正常启动,在浏览器中输入IP地址即可访问openwrt的管理页面。</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422154700759.png" alt="image-20230422154700759"></p>
|
||||
</li>
|
||||
</ol>
|
||||
<h2 id="4-配置opwrt作为旁路由"><a href="#4-配置opwrt作为旁路由" class="headerlink" title="4. 配置opwrt作为旁路由"></a>4. 配置opwrt作为旁路由</h2><p>由于是作为旁路由来使用的,所有wan口是不需要的,只需要LAN即可。</p>
|
||||
<ol>
|
||||
<li>进入openwrt的管理页面,依次点击<strong>网络</strong>-><strong>接口</strong>,将wan和wan6全部删除掉。</li>
|
||||
</ol>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422161227530.png" alt="image-20230422161227530"></p>
|
||||
<div class="note primary"><p>注:删除后,不要点击 保存并应用!!! 不要点击 保存并应用!!! 不要点击 保存并应用!!!</p>
|
||||
</div>
|
||||
|
||||
<ol start="2">
|
||||
<li>点击<strong>设备</strong>,选择<strong>br-lan</strong>,点击<strong>配置…</strong></li>
|
||||
</ol>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422161705488.png" alt="image-20230422161705488"></p>
|
||||
<ol start="3">
|
||||
<li><p>网桥端口中,将所有的网卡都勾选上</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422161814059.png" alt="image-20230422161814059"></p>
|
||||
</li>
|
||||
<li><p>回到接口页面,编辑lan</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422161955936.png" alt="image-20230422161955936"></p>
|
||||
</li>
|
||||
<li><p>确认里面的设备是<strong>br-lan</strong></p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422162141208.png" alt="image-20230422162141208"></p>
|
||||
</li>
|
||||
<li><p>保存后,点击最外层的<strong>保存并应用</strong></p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422162251244.png" alt="image-20230422162251244"></p>
|
||||
</li>
|
||||
<li><p>网络连接正常后,配置自己需要的服务,然后需要这些服务的设备,将openwrt作为网关就可以了。</p>
|
||||
</li>
|
||||
</ol>
|
||||
<h2 id="5-问题"><a href="#5-问题" class="headerlink" title="5. 问题"></a>5. 问题</h2><ol>
|
||||
<li><p>为什么不作为主路由使用,而是选择旁路由?</p>
|
||||
<figure class="highlight tex"><table><tr><td class="code"><pre><span class="line">1。主要还是看各自的需要来决定的,各有利弊。</span><br><span class="line">2.对我来说,只是想用一下它的插件功能,例如广告拦截,proxy等。</span><br><span class="line">3.即便是软路由整体挂了,也不会影响家里的其他设别的正常使用。</span><br></pre></td></tr></table></figure></li>
|
||||
<li><p>如何修改openwrt的地址?</p>
|
||||
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">1.修改lan口的ip地址</span><br><span class="line"></span><br><span class="line">[root@OpenWrt:03:52 PM ~] # cat /etc/config/network</span><br><span class="line"></span><br><span class="line">....</span><br><span class="line"></span><br><span class="line">config interface 'lan'</span><br><span class="line"> option device 'br-lan'</span><br><span class="line"> option proto 'static'</span><br><span class="line"> option netmask '255.255.255.0'</span><br><span class="line"> option ip6assign '60'</span><br><span class="line"> option ipaddr '10.1.100.254'</span><br><span class="line"> option gateway '10.1.100.1'</span><br><span class="line"> option dns '223.5.5.5'</span><br><span class="line"> option delegate '0'</span><br><span class="line"></span><br><span class="line">....</span><br><span class="line"></span><br><span class="line">2. 改完后保存退出,并reboot重启</span><br></pre></td></tr></table></figure></li>
|
||||
<li><p> 网卡直通后,无法访问openwrt的管理页面?</p>
|
||||
</li>
|
||||
</ol>
|
||||
<figure class="highlight tex"><table><tr><td class="code"><pre><span class="line">多张网卡直通后,可能会造成网卡识别混乱。</span><br><span class="line">如果当前无法访问,把网线拔了,可换个网口再试试,肯定会有一个是能够访问的。</span><br></pre></td></tr></table></figure>
|
||||
|
||||
]]></content>
|
||||
<tags>
|
||||
<tag>esxi</tag>
|
||||
<tag>openwrt</tag>
|
||||
<tag>软路由</tag>
|
||||
<tag>旁路由</tag>
|
||||
</tags>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>esxi安装群晖dsm7.1</title>
|
||||
<url>/2023/03/24/esxi%E5%AE%89%E8%A3%85%E7%BE%A4%E6%99%96dsm7.1/</url>
|
||||
<content><![CDATA[<p>在esxi上安装DSM</p>
|
||||
<span id="more"></span>
|
||||
|
||||
<h2 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h2>]]></content>
|
||||
<tags>
|
||||
<tag>esxi</tag>
|
||||
<tag>群晖</tag>
|
||||
<tag>DSM</tag>
|
||||
</tags>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>esxi8.0安装</title>
|
||||
<url>/2023/03/23/esxi8.0%E5%AE%89%E8%A3%85/</url>
|
||||
<content><![CDATA[<p>esxi 8.0的安装。</p>
|
||||
<span id="more"></span>
|
||||
|
||||
|
||||
|
||||
<h2 id="准备工具"><a href="#准备工具" class="headerlink" title="准备工具"></a>准备工具</h2><p>硬件:</p>
|
||||
<ul>
|
||||
<li>8G以上U盘一个</li>
|
||||
<li>待安装的主机一套 </li>
|
||||
</ul>
|
||||
<p>软件:</p>
|
||||
<ul>
|
||||
<li><p>rufus-3.15p.exe 用来刻录镜像</p>
|
||||
</li>
|
||||
<li><p>VMware-VMvisor-Installer-8.0.0-21203435.x86_64-Dell_Customized-A03.iso </p>
|
||||
<p>注:这里使用的是DELL定制版本,其他版本可从官网下载。操作步骤都是一样的</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="刻录镜像到启动U盘"><a href="#刻录镜像到启动U盘" class="headerlink" title="刻录镜像到启动U盘"></a>刻录镜像到启动U盘</h2><ol>
|
||||
<li>打开rufus-3.15p.exe<br> <img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422123404610.png" alt="image-20230422123404610"></li>
|
||||
<li>依次选择U盘,选择镜像文件,点击开始。</li>
|
||||
<li>写入完成后拔下U盘。</li>
|
||||
</ol>
|
||||
<h2 id="安装ESXI8-0"><a href="#安装ESXI8-0" class="headerlink" title="安装ESXI8.0"></a>安装ESXI8.0</h2><ol>
|
||||
<li><p>将写好的U盘插到机器上,开机进入bios页面,选择从U盘启动。</p>
|
||||
</li>
|
||||
<li><p>在加载页面按 <strong>SHIFT+O</strong> (5秒倒计时结束前按)</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422124229021.png" alt="image-20230422124229021"></p>
|
||||
</li>
|
||||
<li><p>输入<strong>autoParititionOSDataSize=8192</strong>设置缓存大小</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422130103695.png" alt="image-20230422130103695"></p>
|
||||
<ul>
|
||||
<li>注:如果不设置的话,默认是划分120G</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p>等待页面加载</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422130452177.png" alt="image-20230422130452177"></p>
|
||||
</li>
|
||||
<li><p>按回车确定,然后F11接受协议。</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422130636232.png" alt="image-20230422130636232"></p>
|
||||
</li>
|
||||
<li><p>选择安装的硬盘,建议安装到SSD盘</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422131134063.png" alt="image-20230422131134063"></p>
|
||||
</li>
|
||||
<li><p>如果之前安装过,会让选择安装方式。如果之前的不想要的,就直接选择第三个覆盖安装。(按空格选中,回车确定)</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422131415703.png" alt="image-20230422131415703"></p>
|
||||
</li>
|
||||
<li><p>键盘选择US Default</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422131519284.png" alt="image-20230422131519284"></p>
|
||||
</li>
|
||||
<li><p>设置root密码,并确认安装</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422131707324.png" alt="image-20230422131707324"></p>
|
||||
</li>
|
||||
<li><p>安装完成后,会提示拔出U盘并重启</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422131850437.png" alt="image-20230422131850437"></p>
|
||||
</li>
|
||||
<li><p>重启后显示下图的页面即表示成功了</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422131945389.png" alt="image-20230422131945389"></p>
|
||||
</li>
|
||||
</ol>
|
||||
<h2 id="给ESXi-设置为静态-IP"><a href="#给ESXi-设置为静态-IP" class="headerlink" title="给ESXi 设置为静态 IP"></a>给ESXi 设置为静态 IP</h2><ol>
|
||||
<li><p>按 F2 进入,提示需要输入账户密码,用户名为 root,密码为刚刚安装时设置的密码,然后回车。</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422132154911.png" alt="image-20230422132154911"></p>
|
||||
</li>
|
||||
<li><p>选择**configure management network **</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422132512778.png" alt="image-20230422132512778"></p>
|
||||
</li>
|
||||
<li><p>然后选择 IPV4 configuration 回车</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422132558114.png" alt="image-20230422132558114"></p>
|
||||
</li>
|
||||
<li><p>接着移动光标到第三项,随后按空格键确定选择</p>
|
||||
</li>
|
||||
<li><p>接着填入你需要设置的 ESXi 静态 IP 地址。</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422132853991.png" alt="image-20230422132853991"></p>
|
||||
</li>
|
||||
</ol>
|
||||
<p>第一行填入 esxi 的静态 IP,第二行填入子网掩码 255.255.255.0,第三行填写路由器的网关地址,设置好后回车即可。</p>
|
||||
<ol start="6">
|
||||
<li><p>打开浏览器,输入管理地址即可访问esxi系统</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422133642869.png" alt="image-20230422133642869"></p>
|
||||
</li>
|
||||
</ol>
|
||||
<h2 id="设置管理网口(多网卡)"><a href="#设置管理网口(多网卡)" class="headerlink" title="设置管理网口(多网卡)"></a>设置管理网口(多网卡)</h2><p>如果有多张网卡,可以指定哪个网口可以访问esxi的管理页面,没有指定的将无法访问。</p>
|
||||
<ol>
|
||||
<li><p>F2进入后,依次选择**configure management network **->**Network Adapters **</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422133918448.png" alt="image-20230422133918448"></p>
|
||||
</li>
|
||||
<li><p>选择网卡,这里可以选择多个,如果只选择了某一个,以后就只有插在这个网口上的机器能访问管理页面。</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422134113958.png" alt="image-20230422134113958"></p>
|
||||
</li>
|
||||
</ol>
|
||||
]]></content>
|
||||
<tags>
|
||||
<tag>esxi</tag>
|
||||
<tag>软路由</tag>
|
||||
</tags>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>VMware安装centos7</title>
|
||||
<url>/2020/01/03/VMware%E5%AE%89%E8%A3%85centos7/</url>
|
||||
<content><![CDATA[<p>在VMware Workstation上安装centos。</p>
|
||||
<span id="more"></span>
|
||||
|
||||
|
||||
|
||||
<h2 id="1-准备:"><a href="#1-准备:" class="headerlink" title="1. 准备:"></a>1. 准备:</h2><ul>
|
||||
<li><p>VMware Workstation</p>
|
||||
</li>
|
||||
<li><p>镜像文件:CentOS-7-x86_64-bin-DVD1.iso</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="2-新建虚拟机"><a href="#2-新建虚拟机" class="headerlink" title="2. 新建虚拟机"></a>2. 新建虚拟机</h2><ol>
|
||||
<li><p>新建虚拟机,选择自定义</p>
|
||||
<img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagese9f6f17438db749dd66af44fee83ea0cb30.jpg"/></li>
|
||||
<li><p>硬盘兼容性–<strong>默认</strong></p>
|
||||
</li>
|
||||
</ol>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422105921574.png" alt="image-20230422105921574"></p>
|
||||
<ol start="3">
|
||||
<li><p>稍后安装操作系统(需要在虚拟机安装完成之后,删除不需要的硬件,所以稍后安装操作系统)</p>
|
||||
</li>
|
||||
<li><p>择客户端操作系统:客户机操作系统–<strong>Linux版本centos 64位</strong></p>
|
||||
</li>
|
||||
<li><p><strong>处理器配置</strong>(CPU)和<strong>内存</strong>,按需要配置</p>
|
||||
</li>
|
||||
<li><p>网络类型–<strong>桥接网络</strong>(可以使虚拟机与主机使用同一网络)</p>
|
||||
</li>
|
||||
</ol>
|
||||
<ul>
|
||||
<li>注:若是NAT和仅主机模式,需要注意网卡的地址,创建的虚拟机和所使用的网卡在同一个网段。</li>
|
||||
</ul>
|
||||
<ol start="7">
|
||||
<li><p>选择I/O控制器类型、磁盘类型和创建新的虚拟磁盘(一般默认就行)</p>
|
||||
</li>
|
||||
<li><p>指定磁盘容量(不低于20G)</p>
|
||||
</li>
|
||||
<li><p>指定磁盘文件(.vmdk)文件</p>
|
||||
</li>
|
||||
<li><p>完成后,删除不必要的设备</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422111309578.png" alt="image-20230422111309578"></p>
|
||||
</li>
|
||||
<li><p>选中CD/DVD,使用ISO镜像文件-选择镜像文件</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422111531776.png" alt="image-20230422111531776"></p>
|
||||
</li>
|
||||
</ol>
|
||||
<p>12.确定后,打开这个虚拟机的电源</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422114456361.png" alt="image-20230422114456361"></p>
|
||||
<h2 id="3-进入centos7安装页面"><a href="#3-进入centos7安装页面" class="headerlink" title="3. 进入centos7安装页面"></a>3. 进入centos7安装页面</h2><ol>
|
||||
<li>选择<strong>install centos7</strong></li>
|
||||
</ol>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422111901398.png" alt="image-20230422111901398"></p>
|
||||
<ol start="2">
|
||||
<li>设置语言–使用<strong>中文-简体中文</strong>–点击<strong>继续</strong></li>
|
||||
</ol>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422114739708.png" alt="image-20230422114739708"></p>
|
||||
<ul>
|
||||
<li>注:如果这里选择了中文简体,那么<strong>键盘布局</strong>一定要选择<strong>英文</strong></li>
|
||||
</ul>
|
||||
<ol start="3">
|
||||
<li><p>进一步设置要安装的信息</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422115039348.png" alt="image-20230422115039348"></p>
|
||||
<p>软件选择:这里我们选择<strong>最小化</strong>安装,即只有最基础的系统,没有桌面</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422115156841.png" alt="image-20230422115156841"></p>
|
||||
</li>
|
||||
<li><p>系统安装位置,点进去进行自定义分区(如果没有特别的要求,默认分区也行)</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422115350829.png" alt="image-20230422115350829"><br>4.1 若需要自主分区,点击<strong>我要配置分区</strong><br><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422115507917.png" alt="image-20230422115507917"><br>4.2 选择标准分组,点击**+**<br><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422115613958.png" alt="image-20230422115613958"><br>4.3 依次添加新挂载点:/boot;swap;/;<br><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422115944392.png" alt="image-20230422115944392"><br><strong>注:</strong></p>
|
||||
<ul>
|
||||
<li>/boot 分区:是引导分区;作用:系统启动,在boot分区存放着grub,内核文件等,一般200M就够了。</li>
|
||||
<li>swap交换分区:内存扩展分区;一般也就2G 。</li>
|
||||
<li>/ 根目录:10G左右,数据一般也不会直接放在根目录下。</li>
|
||||
</ul>
|
||||
<p>4.4 点击完成,接受更改即可。</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422120644423.png" alt="image-20230422120644423"></p>
|
||||
</li>
|
||||
<li><p>关掉KDUMP</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422120802249.png" alt="image-20230422120802249"></p>
|
||||
</li>
|
||||
<li><p>配置网络和主机名</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422120925893.png" alt="image-20230422120925893"></p>
|
||||
<p>网络要根据自己的环境和需求去配置,配置后点击保存即可。</p>
|
||||
</li>
|
||||
<li><p>安全策略保持默认的即可,直接点击<strong>开始安装</strong></p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422121138262.png" alt="image-20230422121138262"></p>
|
||||
</li>
|
||||
<li><p>设置用户名和密码(主要是设置root密码,创建用户可以不做)</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422121219185.png" alt="image-20230422121219185"></p>
|
||||
<p>点击root密码,输入密码点击完成。</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422121357933.png" alt="image-20230422121357933"></p>
|
||||
</li>
|
||||
<li><p>点击重启,等待系统安装完成即可使用了</p>
|
||||
<p><img src="https://halliday.oss-cn-nanjing.aliyuncs.com/imagesimage-20230422121530317.png" alt="image-20230422121530317"></p>
|
||||
</li>
|
||||
</ol>
|
||||
]]></content>
|
||||
<tags>
|
||||
<tag>VMware</tag>
|
||||
<tag>centos</tag>
|
||||
</tags>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>Hello World</title>
|
||||
<url>/2019/12/30/hello-world/</url>
|
||||
<content><![CDATA[<p>欢迎来到我的博客,这是我的第一篇博客,由hexo+next构建。</p>
|
||||
]]></content>
|
||||
</entry>
|
||||
</search>
|
||||