diff --git a/404.html b/404.html
new file mode 100644
index 0000000..ebfeee2
--- /dev/null
+++ b/404.html
@@ -0,0 +1,344 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Sorry! Post Not Found | ADY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CNAME b/CNAME
new file mode 100644
index 0000000..d95266b
--- /dev/null
+++ b/CNAME
@@ -0,0 +1 @@
+blog.ady.tw
\ No newline at end of file
diff --git a/archives/2024/04/index.html b/archives/2024/04/index.html
new file mode 100644
index 0000000..3653a61
--- /dev/null
+++ b/archives/2024/04/index.html
@@ -0,0 +1,341 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+歸檔 | ADY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/archives/2024/index.html b/archives/2024/index.html
new file mode 100644
index 0000000..687c0b4
--- /dev/null
+++ b/archives/2024/index.html
@@ -0,0 +1,341 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+歸檔 | ADY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/archives/index.html b/archives/index.html
new file mode 100644
index 0000000..64b59b2
--- /dev/null
+++ b/archives/index.html
@@ -0,0 +1,341 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+歸檔 | ADY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/css/main.css b/css/main.css
new file mode 100644
index 0000000..69e7da4
--- /dev/null
+++ b/css/main.css
@@ -0,0 +1,2973 @@
+:root {
+ --body-bg-color: #eee;
+ --content-bg-color: #fff;
+ --card-bg-color: #f5f5f5;
+ --text-color: #555;
+ --blockquote-color: #666;
+ --link-color: #555;
+ --link-hover-color: #222;
+ --brand-color: #fff;
+ --brand-hover-color: #fff;
+ --table-row-odd-bg-color: #f9f9f9;
+ --table-row-hover-bg-color: #f5f5f5;
+ --menu-item-bg-color: #f5f5f5;
+ --theme-color: #222;
+ --btn-default-bg: #fff;
+ --btn-default-color: #555;
+ --btn-default-border-color: #555;
+ --btn-default-hover-bg: #222;
+ --btn-default-hover-color: #fff;
+ --btn-default-hover-border-color: #222;
+ --highlight-background: #f3f3f3;
+ --highlight-foreground: #444;
+ --highlight-gutter-background: #e1e1e1;
+ --highlight-gutter-foreground: #555;
+ color-scheme: light;
+}
+@media (prefers-color-scheme: dark) {
+ :root {
+ --body-bg-color: #282828;
+ --content-bg-color: #333;
+ --card-bg-color: #555;
+ --text-color: #ccc;
+ --blockquote-color: #bbb;
+ --link-color: #ccc;
+ --link-hover-color: #eee;
+ --brand-color: #ddd;
+ --brand-hover-color: #ddd;
+ --table-row-odd-bg-color: #282828;
+ --table-row-hover-bg-color: #363636;
+ --menu-item-bg-color: #555;
+ --theme-color: #222;
+ --btn-default-bg: #222;
+ --btn-default-color: #ccc;
+ --btn-default-border-color: #555;
+ --btn-default-hover-bg: #666;
+ --btn-default-hover-color: #ccc;
+ --btn-default-hover-border-color: #666;
+ --highlight-background: #1c1b1b;
+ --highlight-foreground: #fff;
+ --highlight-gutter-background: #323131;
+ --highlight-gutter-foreground: #e8e8e8;
+ color-scheme: dark;
+ }
+ img {
+ opacity: 0.75;
+ }
+ img:hover {
+ opacity: 0.9;
+ }
+ iframe {
+ color-scheme: light;
+ }
+}
+html {
+ line-height: 1.15; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+body {
+ margin: 0;
+}
+main {
+ display: block;
+}
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+hr {
+ box-sizing: content-box; /* 1 */
+ height: 0; /* 1 */
+ overflow: visible; /* 2 */
+}
+pre {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+a {
+ background: transparent;
+}
+abbr[title] {
+ border-bottom: none; /* 1 */
+ text-decoration: underline; /* 2 */
+ text-decoration: underline dotted; /* 2 */
+}
+b,
+strong {
+ font-weight: bolder;
+}
+code,
+kbd,
+samp {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+small {
+ font-size: 80%;
+}
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+sub {
+ bottom: -0.25em;
+}
+sup {
+ top: -0.5em;
+}
+img {
+ border-style: none;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 1 */
+ line-height: 1.15; /* 1 */
+ margin: 0; /* 2 */
+}
+button,
+input {
+/* 1 */
+ overflow: visible;
+}
+button,
+select {
+/* 1 */
+ text-transform: none;
+}
+button,
+[type='button'],
+[type='reset'],
+[type='submit'] {
+ -webkit-appearance: button;
+}
+button::-moz-focus-inner,
+[type='button']::-moz-focus-inner,
+[type='reset']::-moz-focus-inner,
+[type='submit']::-moz-focus-inner {
+ border-style: none;
+ padding: 0;
+}
+button:-moz-focusring,
+[type='button']:-moz-focusring,
+[type='reset']:-moz-focusring,
+[type='submit']:-moz-focusring {
+ outline: 1px dotted ButtonText;
+}
+fieldset {
+ padding: 0.35em 0.75em 0.625em;
+}
+legend {
+ box-sizing: border-box; /* 1 */
+ color: inherit; /* 2 */
+ display: table; /* 1 */
+ max-width: 100%; /* 1 */
+ padding: 0; /* 3 */
+ white-space: normal; /* 1 */
+}
+progress {
+ vertical-align: baseline;
+}
+textarea {
+ overflow: auto;
+}
+[type='checkbox'],
+[type='radio'] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+[type='number']::-webkit-inner-spin-button,
+[type='number']::-webkit-outer-spin-button {
+ height: auto;
+}
+[type='search'] {
+ outline-offset: -2px; /* 2 */
+ -webkit-appearance: textfield; /* 1 */
+}
+[type='search']::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+::-webkit-file-upload-button {
+ font: inherit; /* 2 */
+ -webkit-appearance: button; /* 1 */
+}
+details {
+ display: block;
+}
+summary {
+ display: list-item;
+}
+template {
+ display: none;
+}
+[hidden] {
+ display: none;
+}
+::selection {
+ background: #262a30;
+ color: #eee;
+}
+html,
+body {
+ height: 100%;
+}
+body {
+ background: var(--body-bg-color);
+ box-sizing: border-box;
+ color: var(--text-color);
+ font-family: Lato, 'PingFang SC', 'Microsoft YaHei', sans-serif;
+ font-size: 1em;
+ line-height: 2;
+ min-height: 100%;
+ position: relative;
+ transition: padding 0.2s ease-in-out;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-family: Lato, 'PingFang SC', 'Microsoft YaHei', sans-serif;
+ font-weight: bold;
+ line-height: 1.5;
+ margin: 30px 0 15px;
+}
+h1 {
+ font-size: 1.5em;
+}
+h2 {
+ font-size: 1.375em;
+}
+h3 {
+ font-size: 1.25em;
+}
+h4 {
+ font-size: 1.125em;
+}
+h5 {
+ font-size: 1em;
+}
+h6 {
+ font-size: 0.875em;
+}
+p {
+ margin: 0 0 20px;
+}
+a {
+ border-bottom: 1px solid #999;
+ color: var(--link-color);
+ cursor: pointer;
+ outline: 0;
+ text-decoration: none;
+ overflow-wrap: break-word;
+}
+a:hover {
+ border-bottom-color: var(--link-hover-color);
+ color: var(--link-hover-color);
+}
+iframe,
+img,
+video,
+embed {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ max-width: 100%;
+}
+hr {
+ background-image: repeating-linear-gradient(-45deg, #ddd, #ddd 4px, transparent 4px, transparent 8px);
+ border: 0;
+ height: 3px;
+ margin: 40px 0;
+}
+blockquote {
+ border-left: 4px solid #ddd;
+ color: var(--blockquote-color);
+ margin: 0;
+ padding: 0 15px;
+}
+blockquote cite::before {
+ content: '-';
+ padding: 0 5px;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin: 0;
+ padding: 0;
+}
+.table-container {
+ overflow: auto;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+ font-size: 0.875em;
+ margin: 0 0 20px;
+ width: 100%;
+}
+tbody tr:nth-of-type(odd) {
+ background: var(--table-row-odd-bg-color);
+}
+tbody tr:hover {
+ background: var(--table-row-hover-bg-color);
+}
+caption,
+th,
+td {
+ padding: 8px;
+}
+th,
+td {
+ border: 1px solid #ddd;
+ border-bottom: 3px solid #ddd;
+}
+th {
+ font-weight: 700;
+ padding-bottom: 10px;
+}
+td {
+ border-bottom-width: 1px;
+}
+.btn {
+ background: var(--btn-default-bg);
+ border: 2px solid var(--btn-default-border-color);
+ border-radius: 2px;
+ color: var(--btn-default-color);
+ display: inline-block;
+ font-size: 0.875em;
+ line-height: 2;
+ padding: 0 20px;
+ transition: background-color 0.2s ease-in-out;
+}
+.btn:hover {
+ background: var(--btn-default-hover-bg);
+ border-color: var(--btn-default-hover-border-color);
+ color: var(--btn-default-hover-color);
+}
+.btn + .btn {
+ margin: 0 0 8px 8px;
+}
+.btn .fa-fw {
+ text-align: left;
+ width: 1.285714285714286em;
+}
+.toggle {
+ line-height: 0;
+}
+.toggle .toggle-line {
+ background: #fff;
+ display: block;
+ height: 2px;
+ left: 0;
+ position: relative;
+ top: 0;
+ transition: all 0.4s;
+ width: 100%;
+}
+.toggle .toggle-line:first-child {
+ margin-top: 1px;
+}
+.toggle .toggle-line:not(:first-child) {
+ margin-top: 4px;
+}
+.toggle.toggle-arrow :first-child {
+ left: 50%;
+ top: 2px;
+ transform: rotate(45deg);
+ width: 50%;
+}
+.toggle.toggle-arrow :last-child {
+ left: 50%;
+ top: -2px;
+ transform: rotate(-45deg);
+ width: 50%;
+}
+.toggle.toggle-close :nth-child(2) {
+ opacity: 0;
+}
+.toggle.toggle-close :first-child {
+ top: 6px;
+ transform: rotate(45deg);
+}
+.toggle.toggle-close :last-child {
+ top: -6px;
+ transform: rotate(-45deg);
+}
+pre code.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 1em
+}
+code.hljs {
+ padding: 3px 5px
+}
+/*!
+ Theme: Default
+ Description: Original highlight.js style
+ Author: (c) Ivan Sagalaev
+ Maintainer: @highlightjs/core-team
+ Website: https://highlightjs.org/
+ License: see project LICENSE
+ Touched: 2021
+*/
+/*
+This is left on purpose making default.css the single file that can be lifted
+as-is from the repository directly without the need for a build step
+
+Typically this "required" baseline CSS is added by `makestuff.js` during build.
+*/
+pre code.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 1em
+}
+code.hljs {
+ padding: 3px 5px
+}
+/* end baseline CSS */
+.hljs {
+ background: #F3F3F3;
+ color: #444
+}
+/* Base color: saturation 0; */
+.hljs-subst {
+ /* default */
+
+}
+/* purposely ignored */
+.hljs-formula,
+.hljs-attr,
+.hljs-property,
+.hljs-params {
+
+}
+.hljs-comment {
+ color: #697070
+}
+.hljs-tag,
+.hljs-punctuation {
+ color: #444a
+}
+.hljs-tag .hljs-name,
+.hljs-tag .hljs-attr {
+ color: #444
+}
+.hljs-keyword,
+.hljs-attribute,
+.hljs-selector-tag,
+.hljs-meta .hljs-keyword,
+.hljs-doctag,
+.hljs-name {
+ font-weight: bold
+}
+/* User color: hue: 0 */
+.hljs-type,
+.hljs-string,
+.hljs-number,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-quote,
+.hljs-template-tag,
+.hljs-deletion {
+ color: #880000
+}
+.hljs-title,
+.hljs-section {
+ color: #880000;
+ font-weight: bold
+}
+.hljs-regexp,
+.hljs-symbol,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-link,
+.hljs-selector-attr,
+.hljs-operator,
+.hljs-selector-pseudo {
+ color: #ab5656
+}
+/* Language color: hue: 90; */
+.hljs-literal {
+ color: #695
+}
+.hljs-built_in,
+.hljs-bullet,
+.hljs-code,
+.hljs-addition {
+ color: #397300
+}
+/* Meta color: hue: 200 */
+.hljs-meta {
+ color: #1f7199
+}
+.hljs-meta .hljs-string {
+ color: #38a
+}
+/* Misc effects */
+.hljs-emphasis {
+ font-style: italic
+}
+.hljs-strong {
+ font-weight: bold
+}
+@media (prefers-color-scheme: dark) {
+pre code.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 1em
+}
+code.hljs {
+ padding: 3px 5px
+}
+/*!
+ Theme: StackOverflow Dark
+ Description: Dark theme as used on stackoverflow.com
+ Author: stackoverflow.com
+ Maintainer: @Hirse
+ Website: https://github.com/StackExchange/Stacks
+ License: MIT
+ Updated: 2021-05-15
+
+ Updated for @stackoverflow/stacks v0.64.0
+ Code Blocks: /blob/v0.64.0/lib/css/components/_stacks-code-blocks.less
+ Colors: /blob/v0.64.0/lib/css/exports/_stacks-constants-colors.less
+*/
+.hljs {
+ /* var(--highlight-color) */
+ color: #ffffff;
+ /* var(--highlight-bg) */
+ background: #1c1b1b
+}
+.hljs-subst {
+ /* var(--highlight-color) */
+ color: #ffffff
+}
+.hljs-comment {
+ /* var(--highlight-comment) */
+ color: #999999
+}
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-meta .hljs-keyword,
+.hljs-doctag,
+.hljs-section {
+ /* var(--highlight-keyword) */
+ color: #88aece
+}
+.hljs-attr {
+ /* var(--highlight-attribute); */
+ color: #88aece
+}
+.hljs-attribute {
+ /* var(--highlight-symbol) */
+ color: #c59bc1
+}
+.hljs-name,
+.hljs-type,
+.hljs-number,
+.hljs-selector-id,
+.hljs-quote,
+.hljs-template-tag {
+ /* var(--highlight-namespace) */
+ color: #f08d49
+}
+.hljs-selector-class {
+ /* var(--highlight-keyword) */
+ color: #88aece
+}
+.hljs-string,
+.hljs-regexp,
+.hljs-symbol,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-link,
+.hljs-selector-attr {
+ /* var(--highlight-variable) */
+ color: #b5bd68
+}
+.hljs-meta,
+.hljs-selector-pseudo {
+ /* var(--highlight-keyword) */
+ color: #88aece
+}
+.hljs-built_in,
+.hljs-title,
+.hljs-literal {
+ /* var(--highlight-literal) */
+ color: #f08d49
+}
+.hljs-bullet,
+.hljs-code {
+ /* var(--highlight-punctuation) */
+ color: #cccccc
+}
+.hljs-meta .hljs-string {
+ /* var(--highlight-variable) */
+ color: #b5bd68
+}
+.hljs-deletion {
+ /* var(--highlight-deletion) */
+ color: #de7176
+}
+.hljs-addition {
+ /* var(--highlight-addition) */
+ color: #76c490
+}
+.hljs-emphasis {
+ font-style: italic
+}
+.hljs-strong {
+ font-weight: bold
+}
+.hljs-formula,
+.hljs-operator,
+.hljs-params,
+.hljs-property,
+.hljs-punctuation,
+.hljs-tag {
+ /* purposely ignored */
+
+}
+}
+code,
+kbd,
+figure.highlight,
+pre {
+ background: var(--highlight-background);
+ color: var(--highlight-foreground);
+}
+figure.highlight,
+pre {
+ line-height: 1.6;
+ margin: 0 auto 20px;
+}
+figure.highlight figcaption,
+pre .caption,
+pre figcaption {
+ background: var(--highlight-gutter-background);
+ color: var(--highlight-foreground);
+ display: flow-root;
+ font-size: 0.875em;
+ line-height: 1.2;
+ padding: 0.5em;
+}
+figure.highlight figcaption a,
+pre .caption a,
+pre figcaption a {
+ color: var(--highlight-foreground);
+ float: right;
+}
+figure.highlight figcaption a:hover,
+pre .caption a:hover,
+pre figcaption a:hover {
+ border-bottom-color: var(--highlight-foreground);
+}
+pre,
+code {
+ font-family: consolas, Menlo, monospace, 'PingFang SC', 'Microsoft YaHei';
+}
+code {
+ border-radius: 3px;
+ font-size: 0.875em;
+ padding: 2px 4px;
+ overflow-wrap: break-word;
+}
+kbd {
+ border: 2px solid #ccc;
+ border-radius: 0.2em;
+ box-shadow: 0.1em 0.1em 0.2em rgba(0,0,0,0.1);
+ font-family: inherit;
+ padding: 0.1em 0.3em;
+ white-space: nowrap;
+}
+figure.highlight {
+ overflow: auto;
+ position: relative;
+}
+figure.highlight pre {
+ border: 0;
+ margin: 0;
+ padding: 10px 0;
+}
+figure.highlight table {
+ border: 0;
+ margin: 0;
+ width: auto;
+}
+figure.highlight td {
+ border: 0;
+ padding: 0;
+}
+figure.highlight .gutter {
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+}
+figure.highlight .gutter pre {
+ background: var(--highlight-gutter-background);
+ color: var(--highlight-gutter-foreground);
+ padding-left: 10px;
+ padding-right: 10px;
+ text-align: right;
+}
+figure.highlight .code pre {
+ padding-left: 10px;
+ width: 100%;
+}
+figure.highlight .marked {
+ background: rgba(0,0,0,0.3);
+}
+pre .caption,
+pre figcaption {
+ margin-bottom: 10px;
+}
+.gist table {
+ width: auto;
+}
+.gist table td {
+ border: 0;
+}
+pre {
+ overflow: auto;
+ padding: 10px;
+}
+pre code {
+ background: none;
+ padding: 0;
+ text-shadow: none;
+}
+.blockquote-center {
+ border-left: 0;
+ margin: 40px 0;
+ padding: 0;
+ position: relative;
+ text-align: center;
+}
+.blockquote-center::before,
+.blockquote-center::after {
+ left: 0;
+ line-height: 1;
+ opacity: 0.6;
+ position: absolute;
+ width: 100%;
+}
+.blockquote-center::before {
+ border-top: 1px solid #ccc;
+ text-align: left;
+ top: -20px;
+ content: '\f10d';
+ font-family: 'Font Awesome 6 Free';
+ font-weight: 900;
+}
+.blockquote-center::after {
+ border-bottom: 1px solid #ccc;
+ bottom: -20px;
+ text-align: right;
+ content: '\f10e';
+ font-family: 'Font Awesome 6 Free';
+ font-weight: 900;
+}
+.blockquote-center p,
+.blockquote-center div {
+ text-align: center;
+}
+.group-picture {
+ margin-bottom: 20px;
+}
+.group-picture .group-picture-row {
+ display: flex;
+ gap: 3px;
+ margin-bottom: 3px;
+}
+.group-picture .group-picture-column {
+ flex: 1;
+}
+.group-picture .group-picture-column img {
+ height: 100%;
+ margin: 0;
+ object-fit: cover;
+ width: 100%;
+}
+.post-body .label {
+ color: #555;
+ padding: 0 2px;
+}
+.post-body .label.default {
+ background: #f0f0f0;
+}
+.post-body .label.primary {
+ background: #efe6f7;
+}
+.post-body .label.info {
+ background: #e5f2f8;
+}
+.post-body .label.success {
+ background: #e7f4e9;
+}
+.post-body .label.warning {
+ background: #fcf6e1;
+}
+.post-body .label.danger {
+ background: #fae8eb;
+}
+.post-body .link-grid {
+ display: grid;
+ grid-gap: 1.5rem;
+ gap: 1.5rem;
+ grid-template-columns: 1fr 1fr;
+ margin-bottom: 20px;
+ padding: 1rem;
+}
+@media (max-width: 767px) {
+ .post-body .link-grid {
+ grid-template-columns: 1fr;
+ }
+}
+.post-body .link-grid .link-grid-container {
+ border: solid #ddd;
+ box-shadow: 1rem 1rem 0.5rem rgba(0,0,0,0.5);
+ min-height: 5rem;
+ min-width: 0;
+ padding: 0.5rem;
+ position: relative;
+ transition: background 0.3s;
+}
+.post-body .link-grid .link-grid-container:hover {
+ animation: next-shake 0.5s;
+ background: var(--card-bg-color);
+}
+.post-body .link-grid .link-grid-container:active {
+ box-shadow: 0.5rem 0.5rem 0.25rem rgba(0,0,0,0.5);
+ transform: translate(0.2rem, 0.2rem);
+}
+.post-body .link-grid .link-grid-container .link-grid-image {
+ border: 1px solid #ddd;
+ border-radius: 50%;
+ box-sizing: border-box;
+ height: 5rem;
+ padding: 3px;
+ position: absolute;
+ width: 5rem;
+}
+.post-body .link-grid .link-grid-container p {
+ margin: 0 1rem 0 6rem;
+}
+.post-body .link-grid .link-grid-container p:first-of-type {
+ font-size: 1.2em;
+}
+.post-body .link-grid .link-grid-container p:last-of-type {
+ font-size: 0.8em;
+ line-height: 1.3rem;
+ opacity: 0.7;
+}
+.post-body .link-grid .link-grid-container a {
+ border: 0;
+ height: 100%;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+@keyframes next-shake {
+ 0% {
+ transform: translate(1pt, 1pt) rotate(0deg);
+ }
+ 10% {
+ transform: translate(-1pt, -2pt) rotate(-1deg);
+ }
+ 20% {
+ transform: translate(-3pt, 0pt) rotate(1deg);
+ }
+ 30% {
+ transform: translate(3pt, 2pt) rotate(0deg);
+ }
+ 40% {
+ transform: translate(1pt, -1pt) rotate(1deg);
+ }
+ 50% {
+ transform: translate(-1pt, 2pt) rotate(-1deg);
+ }
+ 60% {
+ transform: translate(-3pt, 1pt) rotate(0deg);
+ }
+ 70% {
+ transform: translate(3pt, 1pt) rotate(-1deg);
+ }
+ 80% {
+ transform: translate(-1pt, -1pt) rotate(1deg);
+ }
+ 90% {
+ transform: translate(1pt, 2pt) rotate(0deg);
+ }
+ 100% {
+ transform: translate(1pt, -2pt) rotate(-1deg);
+ }
+}
+.post-body .note {
+ border-radius: 3px;
+ margin-bottom: 20px;
+ padding: 1em;
+ position: relative;
+ border: 1px solid #eee;
+ border-left-width: 5px;
+}
+.post-body .note summary {
+ cursor: pointer;
+ outline: 0;
+}
+.post-body .note summary p {
+ display: inline;
+}
+.post-body .note h2,
+.post-body .note h3,
+.post-body .note h4,
+.post-body .note h5,
+.post-body .note h6 {
+ border-bottom: initial;
+ margin: 0;
+ padding-top: 0;
+}
+.post-body .note :first-child {
+ margin-top: 0;
+}
+.post-body .note :last-child {
+ margin-bottom: 0;
+}
+.post-body .note.default {
+ border-left-color: #777;
+}
+.post-body .note.default h2,
+.post-body .note.default h3,
+.post-body .note.default h4,
+.post-body .note.default h5,
+.post-body .note.default h6 {
+ color: #777;
+}
+.post-body .note.primary {
+ border-left-color: #6f42c1;
+}
+.post-body .note.primary h2,
+.post-body .note.primary h3,
+.post-body .note.primary h4,
+.post-body .note.primary h5,
+.post-body .note.primary h6 {
+ color: #6f42c1;
+}
+.post-body .note.info {
+ border-left-color: #428bca;
+}
+.post-body .note.info h2,
+.post-body .note.info h3,
+.post-body .note.info h4,
+.post-body .note.info h5,
+.post-body .note.info h6 {
+ color: #428bca;
+}
+.post-body .note.success {
+ border-left-color: #5cb85c;
+}
+.post-body .note.success h2,
+.post-body .note.success h3,
+.post-body .note.success h4,
+.post-body .note.success h5,
+.post-body .note.success h6 {
+ color: #5cb85c;
+}
+.post-body .note.warning {
+ border-left-color: #f0ad4e;
+}
+.post-body .note.warning h2,
+.post-body .note.warning h3,
+.post-body .note.warning h4,
+.post-body .note.warning h5,
+.post-body .note.warning h6 {
+ color: #f0ad4e;
+}
+.post-body .note.danger {
+ border-left-color: #d9534f;
+}
+.post-body .note.danger h2,
+.post-body .note.danger h3,
+.post-body .note.danger h4,
+.post-body .note.danger h5,
+.post-body .note.danger h6 {
+ color: #d9534f;
+}
+.post-body .tabs {
+ margin-bottom: 20px;
+}
+.post-body .tabs,
+.tabs-comment {
+ padding-top: 10px;
+}
+.post-body .tabs ul.nav-tabs,
+.tabs-comment ul.nav-tabs {
+ background: var(--content-bg-color);
+ display: flex;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ margin: 0;
+ padding: 0;
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 5;
+}
+@media (max-width: 413px) {
+ .post-body .tabs ul.nav-tabs,
+ .tabs-comment ul.nav-tabs {
+ display: block;
+ margin-bottom: 5px;
+ }
+}
+.post-body .tabs ul.nav-tabs li.tab,
+.tabs-comment ul.nav-tabs li.tab {
+ border-bottom: 1px solid #ddd;
+ border-left: 1px solid transparent;
+ border-right: 1px solid transparent;
+ border-radius: 0 0 0 0;
+ border-top: 3px solid transparent;
+ flex-grow: 1;
+ list-style-type: none;
+}
+@media (max-width: 413px) {
+ .post-body .tabs ul.nav-tabs li.tab,
+ .tabs-comment ul.nav-tabs li.tab {
+ border-bottom: 1px solid transparent;
+ border-left: 3px solid transparent;
+ border-right: 1px solid transparent;
+ border-top: 1px solid transparent;
+ }
+}
+@media (max-width: 413px) {
+ .post-body .tabs ul.nav-tabs li.tab,
+ .tabs-comment ul.nav-tabs li.tab {
+ border-radius: 0;
+ }
+}
+.post-body .tabs ul.nav-tabs li.tab a,
+.tabs-comment ul.nav-tabs li.tab a {
+ border-bottom: initial;
+ display: block;
+ line-height: 1.8;
+ padding: 0.25em 0.75em;
+ text-align: center;
+ transition: all 0.2s ease-out;
+}
+.post-body .tabs ul.nav-tabs li.tab a i[class^='fa'],
+.tabs-comment ul.nav-tabs li.tab a i[class^='fa'] {
+ width: 1.285714285714286em;
+}
+.post-body .tabs ul.nav-tabs li.tab.active,
+.tabs-comment ul.nav-tabs li.tab.active {
+ border-bottom-color: transparent;
+ border-left-color: #ddd;
+ border-right-color: #ddd;
+ border-top-color: #fc6423;
+}
+@media (max-width: 413px) {
+ .post-body .tabs ul.nav-tabs li.tab.active,
+ .tabs-comment ul.nav-tabs li.tab.active {
+ border-bottom-color: #ddd;
+ border-left-color: #fc6423;
+ border-right-color: #ddd;
+ border-top-color: #ddd;
+ }
+}
+.post-body .tabs ul.nav-tabs li.tab.active a,
+.tabs-comment ul.nav-tabs li.tab.active a {
+ cursor: default;
+}
+.post-body .tabs .tab-content,
+.tabs-comment .tab-content {
+ border: 1px solid #ddd;
+ border-radius: 0 0 0 0;
+ border-top-color: transparent;
+}
+@media (max-width: 413px) {
+ .post-body .tabs .tab-content,
+ .tabs-comment .tab-content {
+ border-radius: 0;
+ border-top-color: #ddd;
+ }
+}
+.post-body .tabs .tab-content .tab-pane,
+.tabs-comment .tab-content .tab-pane {
+ padding: 20px 20px 0;
+}
+.post-body .tabs .tab-content .tab-pane:not(.active),
+.tabs-comment .tab-content .tab-pane:not(.active) {
+ display: none;
+}
+.pagination .prev,
+.pagination .next,
+.pagination .page-number,
+.pagination .space {
+ display: inline-block;
+ margin: -1px 10px 0;
+ padding: 0 10px;
+}
+@media (max-width: 767px) {
+ .pagination .prev,
+ .pagination .next,
+ .pagination .page-number,
+ .pagination .space {
+ margin: 0 5px;
+ }
+}
+.pagination .page-number.current {
+ background: #ccc;
+ border-color: #ccc;
+ color: var(--content-bg-color);
+}
+.pagination {
+ border-top: 1px solid #eee;
+ margin: 120px 0 0;
+ text-align: center;
+}
+.pagination .prev,
+.pagination .next,
+.pagination .page-number {
+ border-bottom: 0;
+ border-top: 1px solid #eee;
+ transition: border-color 0.2s ease-in-out;
+}
+.pagination .prev:hover,
+.pagination .next:hover,
+.pagination .page-number:hover {
+ border-top-color: var(--link-hover-color);
+}
+@media (max-width: 767px) {
+ .pagination {
+ border-top: 0;
+ }
+ .pagination .prev,
+ .pagination .next,
+ .pagination .page-number {
+ border-bottom: 1px solid #eee;
+ border-top: 0;
+ }
+ .pagination .prev:hover,
+ .pagination .next:hover,
+ .pagination .page-number:hover {
+ border-bottom-color: var(--link-hover-color);
+ }
+}
+.pagination .space {
+ margin: 0;
+ padding: 0;
+}
+.comments {
+ margin-top: 60px;
+ overflow: hidden;
+}
+.comment-button-group {
+ display: flex;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ justify-content: center;
+ margin: 1em 0;
+}
+.comment-button-group .comment-button {
+ margin: 0.1em 0.2em;
+}
+.comment-button-group .comment-button.active {
+ background: var(--btn-default-hover-bg);
+ border-color: var(--btn-default-hover-border-color);
+ color: var(--btn-default-hover-color);
+}
+.comment-position {
+ display: none;
+}
+.comment-position.active {
+ display: block;
+}
+.tabs-comment {
+ margin-top: 4em;
+ padding-top: 0;
+}
+.tabs-comment .comments {
+ margin-top: 0;
+ padding-top: 0;
+}
+.headband {
+ background: var(--theme-color);
+ height: 3px;
+}
+@media (max-width: 991px) {
+ .headband {
+ display: none;
+ }
+}
+.site-brand-container {
+ display: flex;
+ flex-shrink: 0;
+ padding: 0 10px;
+}
+.use-motion .column,
+.use-motion .site-brand-container .toggle {
+ opacity: 0;
+}
+.site-meta {
+ flex-grow: 1;
+ text-align: center;
+}
+@media (max-width: 767px) {
+ .site-meta {
+ text-align: center;
+ }
+}
+.custom-logo-image {
+ margin-top: 20px;
+}
+@media (max-width: 991px) {
+ .custom-logo-image {
+ display: none;
+ }
+}
+.brand {
+ border-bottom: 0;
+ color: var(--brand-color);
+ display: inline-block;
+ padding: 0;
+}
+.brand:hover {
+ color: var(--brand-hover-color);
+}
+.site-title {
+ font-family: Lato, 'PingFang SC', 'Microsoft YaHei', sans-serif;
+ font-size: 1.375em;
+ font-weight: normal;
+ line-height: 1.5;
+ margin: 0;
+}
+.site-subtitle {
+ color: #ddd;
+ font-size: 0.8125em;
+ margin: 10px 10px 0;
+}
+.use-motion .site-title,
+.use-motion .site-subtitle,
+.use-motion .custom-logo-image {
+ opacity: 0;
+ position: relative;
+ top: -10px;
+}
+.site-nav-toggle,
+.site-nav-right {
+ display: none;
+}
+@media (max-width: 767px) {
+ .site-nav-toggle,
+ .site-nav-right {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ }
+}
+.site-nav-toggle .toggle,
+.site-nav-right .toggle {
+ color: var(--text-color);
+ padding: 10px;
+ width: 22px;
+}
+.site-nav-toggle .toggle .toggle-line,
+.site-nav-right .toggle .toggle-line {
+ background: var(--text-color);
+ border-radius: 1px;
+}
+@media (max-width: 767px) {
+ .site-nav {
+ --scroll-height: 0;
+ height: 0;
+ overflow: hidden;
+ transition: 0.2s ease-in-out;
+ transition-property: height, visibility;
+ visibility: hidden;
+ }
+ body:not(.site-nav-on) .site-nav .animated {
+ animation: none;
+ }
+ body.site-nav-on .site-nav {
+ height: var(--scroll-height);
+ visibility: unset;
+ }
+}
+.menu {
+ margin: 0;
+ padding: 1em 0;
+ text-align: center;
+}
+.menu-item {
+ display: inline-block;
+ list-style: none;
+ margin: 0 10px;
+}
+@media (max-width: 767px) {
+ .menu-item {
+ display: block;
+ margin-top: 10px;
+ }
+ .menu-item.menu-item-search {
+ display: none;
+ }
+}
+.menu-item a {
+ border-bottom: 0;
+ display: block;
+ font-size: 0.8125em;
+ transition: border-color 0.2s ease-in-out;
+}
+.menu-item a:hover,
+.menu-item a.menu-item-active {
+ background: var(--menu-item-bg-color);
+}
+.menu-item i[class^='fa'] {
+ margin-right: 8px;
+}
+.menu-item .badge {
+ display: inline-block;
+ font-weight: bold;
+ line-height: 1;
+ margin-left: 0.35em;
+ margin-top: 0.35em;
+ text-align: center;
+ white-space: nowrap;
+}
+@media (max-width: 767px) {
+ .menu-item .badge {
+ float: right;
+ margin-left: 0;
+ }
+}
+.use-motion .menu-item {
+ visibility: hidden;
+}
+.github-corner :hover .octo-arm {
+ animation: octocat-wave 560ms ease-in-out;
+}
+.github-corner svg {
+ color: #fff;
+ fill: var(--theme-color);
+ position: absolute;
+ right: 0;
+ top: 0;
+ z-index: 5;
+}
+@media (max-width: 991px) {
+ .github-corner {
+ display: none;
+ }
+ .github-corner svg {
+ color: var(--theme-color);
+ fill: #fff;
+ }
+ .github-corner .github-corner:hover .octo-arm {
+ animation: none;
+ }
+ .github-corner .github-corner .octo-arm {
+ animation: octocat-wave 560ms ease-in-out;
+ }
+}
+@keyframes octocat-wave {
+ 0%, 100% {
+ transform: rotate(0);
+ }
+ 20%, 60% {
+ transform: rotate(-25deg);
+ }
+ 40%, 80% {
+ transform: rotate(10deg);
+ }
+}
+.sidebar-inner {
+ color: #999;
+ padding: 18px 10px;
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+.cc-license .cc-opacity {
+ border-bottom: 0;
+ opacity: 0.7;
+}
+.cc-license .cc-opacity:hover {
+ opacity: 0.9;
+}
+.cc-license img {
+ display: inline-block;
+}
+.site-author-image {
+ border: 1px solid #eee;
+ max-width: 120px;
+ padding: 2px;
+ border-radius: 50%;
+}
+.site-author-name {
+ color: var(--text-color);
+ font-weight: 600;
+ margin: 0;
+}
+.site-description {
+ color: #999;
+ font-size: 0.8125em;
+ margin-top: 0;
+}
+.links-of-author a {
+ font-size: 0.8125em;
+}
+.sidebar .sidebar-button:not(:first-child) {
+ margin-top: 15px;
+}
+.sidebar .sidebar-button button {
+ background: transparent;
+ color: #fc6423;
+ cursor: pointer;
+ line-height: 2;
+ padding: 0 15px;
+ border: 1px solid #fc6423;
+ border-radius: 4px;
+}
+.sidebar .sidebar-button button:hover {
+ background: #fc6423;
+ color: #fff;
+}
+.sidebar .sidebar-button button i[class^='fa'] {
+ margin-right: 5px;
+}
+.links-of-blogroll {
+ font-size: 0.8125em;
+}
+.links-of-blogroll-title {
+ font-size: 0.875em;
+ font-weight: 600;
+}
+.links-of-blogroll-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+.sidebar-nav {
+ font-size: 0.875em;
+ height: 0;
+ margin: 0;
+ overflow: hidden;
+ padding-left: 0;
+ pointer-events: none;
+ transition: 0.2s ease-in-out;
+ transition-property: height, visibility;
+ visibility: hidden;
+}
+.sidebar-nav-active .sidebar-nav {
+ height: calc(2em + 1px);
+ pointer-events: unset;
+ visibility: unset;
+}
+.sidebar-nav li {
+ border-bottom: 1px solid transparent;
+ color: var(--text-color);
+ cursor: pointer;
+ display: inline-block;
+ transition: 0.2s ease-in-out;
+ transition-property: border-bottom-color, color;
+}
+.sidebar-nav li.sidebar-nav-overview {
+ margin-left: 10px;
+}
+.sidebar-nav li:hover {
+ color: #fc6423;
+}
+.sidebar-toc-active .sidebar-nav-toc,
+.sidebar-overview-active .sidebar-nav-overview {
+ border-bottom-color: #fc6423;
+ color: #fc6423;
+ transition-delay: 0.2s;
+}
+.sidebar-toc-active .sidebar-nav-toc:hover,
+.sidebar-overview-active .sidebar-nav-overview:hover {
+ color: #fc6423;
+}
+.sidebar-panel-container {
+ align-items: start;
+ display: grid;
+ flex: 1;
+ overflow-x: hidden;
+ overflow-y: auto;
+ padding-top: 0;
+ transition: padding-top 0.2s ease-in-out;
+}
+.sidebar-nav-active .sidebar-panel-container {
+ padding-top: 20px;
+}
+.sidebar-panel {
+ animation: deactivate-sidebar-panel 0.2s ease-in-out;
+ grid-area: 1/1;
+ height: 0;
+ opacity: 0;
+ overflow: hidden;
+ pointer-events: none;
+ transform: translateY(0);
+ transition: 0.2s ease-in-out;
+ transition-delay: 0s;
+ transition-property: opacity, transform, visibility;
+ visibility: hidden;
+}
+.sidebar-nav-active .sidebar-panel,
+.sidebar-overview-active .sidebar-panel.post-toc-wrap {
+ transform: translateY(-20px);
+}
+.sidebar-overview-active:not(.sidebar-nav-active) .sidebar-panel.post-toc-wrap {
+ transition-delay: 0s, 0.2s, 0s;
+}
+.sidebar-overview-active .sidebar-panel.site-overview-wrap,
+.sidebar-toc-active .sidebar-panel.post-toc-wrap {
+ animation-name: activate-sidebar-panel;
+ height: auto;
+ opacity: 1;
+ pointer-events: unset;
+ transform: translateY(0);
+ transition-delay: 0.2s, 0.2s, 0s;
+ visibility: unset;
+}
+.sidebar-panel.site-overview-wrap {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ gap: 10px;
+ justify-content: flex-start;
+}
+@keyframes deactivate-sidebar-panel {
+ from {
+ height: var(--inactive-panel-height, 0);
+ }
+ to {
+ height: var(--active-panel-height, 0);
+ }
+}
+@keyframes activate-sidebar-panel {
+ from {
+ height: var(--inactive-panel-height, auto);
+ }
+ to {
+ height: var(--active-panel-height, auto);
+ }
+}
+.sidebar-toggle {
+ bottom: 61px;
+ height: 16px;
+ padding: 5px;
+ width: 16px;
+ background: #222;
+ cursor: pointer;
+ opacity: 0.6;
+ position: fixed;
+ z-index: 30;
+ right: 30px;
+}
+@media (max-width: 991px) {
+ .sidebar-toggle {
+ right: 20px;
+ }
+}
+.sidebar-toggle:hover {
+ opacity: 0.8;
+}
+@media (max-width: 991px) {
+ .sidebar-toggle {
+ opacity: 0.8;
+ }
+}
+.sidebar-toggle:hover .toggle-line {
+ background: #fc6423;
+}
+@media (any-hover: hover) {
+ body:not(.sidebar-active) .sidebar-toggle:hover :first-child {
+ left: 50%;
+ top: 2px;
+ transform: rotate(45deg);
+ width: 50%;
+ }
+ body:not(.sidebar-active) .sidebar-toggle:hover :last-child {
+ left: 50%;
+ top: -2px;
+ transform: rotate(-45deg);
+ width: 50%;
+ }
+}
+.sidebar-active .sidebar-toggle :nth-child(2) {
+ opacity: 0;
+}
+.sidebar-active .sidebar-toggle :first-child {
+ top: 6px;
+ transform: rotate(45deg);
+}
+.sidebar-active .sidebar-toggle :last-child {
+ top: -6px;
+ transform: rotate(-45deg);
+}
+.post-toc {
+ font-size: 0.875em;
+}
+.post-toc ol {
+ list-style: none;
+ margin: 0;
+ padding: 0 2px 0 10px;
+ text-align: left;
+}
+.post-toc ol > :last-child {
+ margin-bottom: 5px;
+}
+.post-toc ol > ol {
+ padding-left: 0;
+}
+.post-toc ol a {
+ transition: all 0.2s ease-in-out;
+}
+.post-toc .nav-item {
+ line-height: 1.8;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.post-toc .nav .nav-child {
+ --height: 0;
+ height: 0;
+ opacity: 0;
+ overflow: hidden;
+ transition-property: height, opacity, visibility;
+ transition: 0.2s ease-in-out;
+ visibility: hidden;
+}
+.post-toc .nav .active > .nav-child {
+ height: var(--height, auto);
+ opacity: 1;
+ visibility: unset;
+}
+.post-toc .nav .active > a {
+ border-bottom-color: #fc6423;
+ color: #fc6423;
+}
+.post-toc .nav .active-current > a {
+ color: #fc6423;
+}
+.post-toc .nav .active-current > a:hover {
+ color: #fc6423;
+}
+.site-state {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ line-height: 1.4;
+}
+.site-state-item {
+ padding: 0 15px;
+}
+.site-state-item a {
+ border-bottom: 0;
+ display: block;
+}
+.site-state-item-count {
+ display: block;
+ font-size: 1em;
+ font-weight: 600;
+}
+.site-state-item-name {
+ color: #999;
+ font-size: 0.8125em;
+}
+.footer {
+ color: #999;
+ font-size: 0.875em;
+ padding: 20px 0;
+ transition: 0.2s ease-in-out;
+ transition-property: left, right;
+}
+.footer.footer-fixed {
+ bottom: 0;
+ left: 0;
+ position: absolute;
+ right: 0;
+}
+.footer-inner {
+ box-sizing: border-box;
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ margin: 0 auto;
+ width: calc(100% - 20px);
+}
+@media (max-width: 767px) {
+ .footer-inner {
+ width: auto;
+ }
+}
+@media (min-width: 1200px) {
+ .footer-inner {
+ width: 1160px;
+ }
+}
+@media (min-width: 1600px) {
+ .footer-inner {
+ width: 73%;
+ }
+}
+.use-motion .footer {
+ opacity: 0;
+}
+.languages {
+ display: inline-block;
+ font-size: 1.125em;
+ position: relative;
+}
+.languages .lang-select-label span {
+ margin: 0 0.5em;
+}
+.languages .lang-select {
+ height: 100%;
+ left: 0;
+ opacity: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+.with-love {
+ color: #f00;
+ display: inline-block;
+ margin: 0 5px;
+}
+@keyframes icon-animate {
+ 0%, 100% {
+ transform: scale(1);
+ }
+ 10%, 30% {
+ transform: scale(0.9);
+ }
+ 20%, 40%, 60%, 80% {
+ transform: scale(1.1);
+ }
+ 50%, 70% {
+ transform: scale(1.1);
+ }
+}
+.back-to-top {
+ font-size: 12px;
+ align-items: center;
+ bottom: -100px;
+ color: #fff;
+ display: flex;
+ height: 26px;
+ transition: bottom 0.2s ease-in-out;
+ background: #222;
+ cursor: pointer;
+ opacity: 0.6;
+ position: fixed;
+ z-index: 30;
+ right: 30px;
+}
+.back-to-top span {
+ margin-right: 8px;
+ display: none;
+}
+.back-to-top .fa {
+ text-align: center;
+ width: 26px;
+}
+@media (max-width: 991px) {
+ .back-to-top {
+ right: 20px;
+ }
+}
+.back-to-top:hover {
+ opacity: 0.8;
+}
+@media (max-width: 991px) {
+ .back-to-top {
+ opacity: 0.8;
+ }
+}
+.back-to-top:hover {
+ color: #fc6423;
+}
+.back-to-top.back-to-top-on {
+ bottom: 30px;
+}
+.rtl.post-body p,
+.rtl.post-body a,
+.rtl.post-body h1,
+.rtl.post-body h2,
+.rtl.post-body h3,
+.rtl.post-body h4,
+.rtl.post-body h5,
+.rtl.post-body h6,
+.rtl.post-body li,
+.rtl.post-body ul,
+.rtl.post-body ol {
+ direction: rtl;
+ font-family: UKIJ Ekran;
+}
+.rtl.post-title {
+ font-family: UKIJ Ekran;
+}
+.post-button {
+ margin-top: 40px;
+ text-align: center;
+}
+.use-motion .post-block,
+.use-motion .pagination,
+.use-motion .comments {
+ visibility: hidden;
+}
+.use-motion .post-header {
+ visibility: hidden;
+}
+.use-motion .post-body {
+ visibility: hidden;
+}
+.use-motion .collection-header {
+ visibility: hidden;
+}
+.posts-collapse .post-content {
+ margin-bottom: 35px;
+ margin-left: 35px;
+ position: relative;
+}
+@media (max-width: 767px) {
+ .posts-collapse .post-content {
+ margin-left: 0;
+ margin-right: 0;
+ }
+}
+.posts-collapse .post-content .collection-title {
+ font-size: 1.125em;
+ position: relative;
+}
+.posts-collapse .post-content .collection-title::before {
+ background: #999;
+ border: 1px solid #fff;
+ margin-left: -6px;
+ margin-top: -4px;
+ position: absolute;
+ top: 50%;
+ border-radius: 50%;
+ content: ' ';
+ height: 10px;
+ width: 10px;
+}
+.posts-collapse .post-content .collection-year {
+ font-size: 1.5em;
+ font-weight: bold;
+ margin: 60px 0;
+ position: relative;
+}
+.posts-collapse .post-content .collection-year::before {
+ background: #bbb;
+ margin-left: -4px;
+ margin-top: -4px;
+ position: absolute;
+ top: 50%;
+ border-radius: 50%;
+ content: ' ';
+ height: 8px;
+ width: 8px;
+}
+.posts-collapse .post-content .collection-header {
+ display: block;
+ margin-left: 20px;
+}
+.posts-collapse .post-content .collection-header small {
+ color: #bbb;
+ margin-left: 5px;
+}
+.posts-collapse .post-content .post-header {
+ border-bottom: 1px dashed #ccc;
+ margin: 30px 2px 0;
+ padding-left: 15px;
+ position: relative;
+ transition: border 0.2s ease-in-out;
+}
+.posts-collapse .post-content .post-header::before {
+ background: #bbb;
+ border: 1px solid #fff;
+ left: -6px;
+ position: absolute;
+ top: 0.75em;
+ transition: background 0.2s ease-in-out;
+ border-radius: 50%;
+ content: ' ';
+ height: 6px;
+ width: 6px;
+}
+.posts-collapse .post-content .post-header:hover {
+ border-bottom-color: #666;
+}
+.posts-collapse .post-content .post-header:hover::before {
+ background: #222;
+}
+.posts-collapse .post-content .post-meta-container {
+ display: inline;
+ font-size: 0.75em;
+ margin-right: 10px;
+}
+.posts-collapse .post-content .post-title {
+ display: inline;
+}
+.posts-collapse .post-content .post-title a {
+ border-bottom: 0;
+ color: var(--link-color);
+}
+.posts-collapse .post-content::before {
+ background: #f5f5f5;
+ content: ' ';
+ height: 100%;
+ margin-left: -2px;
+ position: absolute;
+ top: 1.25em;
+ width: 4px;
+}
+.post-body {
+ font-family: Lato, 'PingFang SC', 'Microsoft YaHei', sans-serif;
+ overflow-wrap: break-word;
+}
+@media (min-width: 1200px) {
+ .post-body {
+ font-size: 1.125em;
+ }
+}
+@media (min-width: 992px) {
+ .post-body {
+ text-align: justify;
+ }
+}
+@media (max-width: 991px) {
+ .post-body {
+ text-align: justify;
+ }
+}
+.post-body h1 .header-anchor,
+.post-body h2 .header-anchor,
+.post-body h3 .header-anchor,
+.post-body h4 .header-anchor,
+.post-body h5 .header-anchor,
+.post-body h6 .header-anchor,
+.post-body h1 .headerlink,
+.post-body h2 .headerlink,
+.post-body h3 .headerlink,
+.post-body h4 .headerlink,
+.post-body h5 .headerlink,
+.post-body h6 .headerlink {
+ border-bottom-style: none;
+ color: inherit;
+ float: right;
+ font-size: 0.875em;
+ margin-left: 10px;
+ opacity: 0;
+}
+.post-body h1 .header-anchor::before,
+.post-body h2 .header-anchor::before,
+.post-body h3 .header-anchor::before,
+.post-body h4 .header-anchor::before,
+.post-body h5 .header-anchor::before,
+.post-body h6 .header-anchor::before,
+.post-body h1 .headerlink::before,
+.post-body h2 .headerlink::before,
+.post-body h3 .headerlink::before,
+.post-body h4 .headerlink::before,
+.post-body h5 .headerlink::before,
+.post-body h6 .headerlink::before {
+ content: '\f0c1';
+ font-family: 'Font Awesome 6 Free';
+ font-weight: 900;
+}
+.post-body h1:hover .header-anchor,
+.post-body h2:hover .header-anchor,
+.post-body h3:hover .header-anchor,
+.post-body h4:hover .header-anchor,
+.post-body h5:hover .header-anchor,
+.post-body h6:hover .header-anchor,
+.post-body h1:hover .headerlink,
+.post-body h2:hover .headerlink,
+.post-body h3:hover .headerlink,
+.post-body h4:hover .headerlink,
+.post-body h5:hover .headerlink,
+.post-body h6:hover .headerlink {
+ opacity: 0.5;
+}
+.post-body h1:hover .header-anchor:hover,
+.post-body h2:hover .header-anchor:hover,
+.post-body h3:hover .header-anchor:hover,
+.post-body h4:hover .header-anchor:hover,
+.post-body h5:hover .header-anchor:hover,
+.post-body h6:hover .header-anchor:hover,
+.post-body h1:hover .headerlink:hover,
+.post-body h2:hover .headerlink:hover,
+.post-body h3:hover .headerlink:hover,
+.post-body h4:hover .headerlink:hover,
+.post-body h5:hover .headerlink:hover,
+.post-body h6:hover .headerlink:hover {
+ opacity: 1;
+}
+.post-body .exturl .fa {
+ font-size: 0.875em;
+ margin-left: 4px;
+}
+.post-body img + figcaption,
+.post-body .fancybox + figcaption {
+ color: #999;
+ font-size: 0.875em;
+ font-weight: bold;
+ line-height: 1;
+ margin: -15px auto 15px;
+ text-align: center;
+}
+.post-body iframe,
+.post-body img,
+.post-body video,
+.post-body embed {
+ margin-bottom: 20px;
+}
+.post-body .video-container {
+ height: 0;
+ margin-bottom: 20px;
+ overflow: hidden;
+ padding-top: 75%;
+ position: relative;
+ width: 100%;
+}
+.post-body .video-container iframe,
+.post-body .video-container object,
+.post-body .video-container embed {
+ height: 100%;
+ left: 0;
+ margin: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+.post-gallery {
+ display: flex;
+ min-height: 200px;
+}
+.post-gallery .post-gallery-image {
+ flex: 1;
+}
+.post-gallery .post-gallery-image:not(:first-child) {
+ clip-path: polygon(40px 0, 100% 0, 100% 100%, 0 100%);
+ margin-left: -20px;
+}
+.post-gallery .post-gallery-image:not(:last-child) {
+ margin-right: -20px;
+}
+.post-gallery .post-gallery-image img {
+ height: 100%;
+ object-fit: cover;
+ opacity: 1;
+ width: 100%;
+}
+.posts-expand .post-gallery {
+ margin-bottom: 60px;
+}
+.posts-collapse .post-gallery {
+ margin: 15px 0;
+}
+.posts-expand .post-header {
+ font-size: 1.125em;
+ margin-bottom: 60px;
+ text-align: center;
+}
+.posts-expand .post-title {
+ font-size: 1.5em;
+ font-weight: normal;
+ margin: initial;
+ overflow-wrap: break-word;
+}
+.posts-expand .post-title-link {
+ border-bottom: 0;
+ color: var(--link-color);
+ display: inline-block;
+ position: relative;
+}
+.posts-expand .post-title-link::before {
+ background: var(--link-color);
+ bottom: 0;
+ content: '';
+ height: 2px;
+ left: 0;
+ position: absolute;
+ transform: scaleX(0);
+ transition: transform 0.2s ease-in-out;
+ width: 100%;
+}
+.posts-expand .post-title-link:hover::before {
+ transform: scaleX(1);
+}
+.posts-expand .post-title-link .fa {
+ font-size: 0.875em;
+ margin-left: 5px;
+}
+.post-sticky-flag {
+ display: inline-block;
+ margin-right: 8px;
+ transform: rotate(30deg);
+}
+.posts-expand .post-meta-container {
+ color: #999;
+ font-family: Lato, 'PingFang SC', 'Microsoft YaHei', sans-serif;
+ font-size: 0.75em;
+ margin-top: 3px;
+}
+.posts-expand .post-meta-container .post-description {
+ font-size: 0.875em;
+ margin-top: 2px;
+}
+.posts-expand .post-meta-container time {
+ border-bottom: 1px dashed #999;
+}
+.post-meta {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+}
+:not(.post-meta-break) + .post-meta-item::before {
+ content: '|';
+ margin: 0 0.5em;
+}
+.post-meta-item-icon {
+ margin-right: 3px;
+}
+@media (max-width: 991px) {
+ .post-meta-item-text {
+ display: none;
+ }
+}
+.post-meta-break {
+ flex-basis: 100%;
+ height: 0;
+}
+.post-nav {
+ border-top: 1px solid #eee;
+ display: flex;
+ gap: 30px;
+ justify-content: space-between;
+ margin-top: 1em;
+ padding: 10px 5px 0;
+}
+.post-nav-item {
+ flex: 1;
+}
+.post-nav-item a {
+ border-bottom: 0;
+ display: block;
+ font-size: 0.875em;
+ line-height: 1.6;
+}
+.post-nav-item a:active {
+ top: 2px;
+}
+.post-nav-item .fa {
+ font-size: 0.75em;
+}
+.post-nav-item:first-child .fa {
+ margin-right: 5px;
+}
+.post-nav-item:last-child {
+ text-align: right;
+}
+.post-nav-item:last-child .fa {
+ margin-left: 5px;
+}
+.post-footer {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+.post-eof {
+ background: #ccc;
+ height: 1px;
+ margin: 80px auto 60px;
+ width: 8%;
+}
+.post-block:last-of-type .post-eof {
+ display: none;
+}
+.post-copyright ul {
+ list-style: none;
+ overflow: hidden;
+ padding: 0.5em 1em;
+ position: relative;
+ background: var(--card-bg-color);
+ border-left: 3px solid #ff2a2a;
+ margin: 1em 0 0;
+}
+.post-copyright ul::after {
+ content: '\f25e';
+ font-family: 'Font Awesome 6 Brands';
+ font-size: 200px;
+ opacity: 0.1;
+ position: absolute;
+ right: -50px;
+ top: -150px;
+}
+.post-tags {
+ margin-top: 40px;
+ text-align: center;
+}
+.post-tags a {
+ display: inline-block;
+ font-size: 0.8125em;
+}
+.post-tags a:not(:last-child) {
+ margin-right: 10px;
+}
+.social-like {
+ border-top: 1px solid #eee;
+ font-size: 0.875em;
+ margin-top: 1em;
+ padding-top: 1em;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+}
+.social-like a {
+ border-bottom: none;
+}
+.reward-container {
+ margin: 1em 0 0;
+ padding: 1em 0;
+ text-align: center;
+}
+.reward-container button {
+ background: transparent;
+ color: #fc6423;
+ cursor: pointer;
+ line-height: 2;
+ padding: 0 15px;
+ border: 2px solid #fc6423;
+ border-radius: 2px;
+ outline: 0;
+ transition: all 0.2s ease-in-out;
+ vertical-align: text-top;
+}
+.reward-container button:hover {
+ background: #fc6423;
+ color: #fff;
+}
+.post-reward {
+ display: none;
+ padding-top: 20px;
+}
+.post-reward.active {
+ display: block;
+}
+.post-reward div {
+ display: inline-block;
+}
+.post-reward div span {
+ display: block;
+}
+.post-reward img {
+ display: inline-block;
+ margin: 0.8em 2em 0;
+ max-width: 100%;
+ width: 180px;
+}
+@keyframes next-roll {
+ from {
+ transform: rotateZ(30deg);
+ }
+ to {
+ transform: rotateZ(-30deg);
+ }
+}
+.category-all-page .category-all-title {
+ text-align: center;
+}
+.category-all-page .category-all {
+ margin-top: 20px;
+}
+.category-all-page .category-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+.category-all-page .category-list-item {
+ margin: 5px 10px;
+}
+.category-all-page .category-list-count {
+ color: #bbb;
+}
+.category-all-page .category-list-count::before {
+ content: ' (';
+}
+.category-all-page .category-list-count::after {
+ content: ') ';
+}
+.category-all-page .category-list-child {
+ padding-left: 10px;
+}
+.event-list hr {
+ background: #222;
+ margin: 20px 0 45px;
+}
+.event-list hr::after {
+ background: #222;
+ color: #fff;
+ content: 'NOW';
+ display: inline-block;
+ font-weight: bold;
+ padding: 0 5px;
+}
+.event-list .event {
+ --event-background: #222;
+ --event-foreground: #bbb;
+ --event-title: #fff;
+ background: var(--event-background);
+ padding: 15px;
+}
+.event-list .event .event-summary {
+ border-bottom: 0;
+ color: var(--event-title);
+ margin: 0;
+ padding: 0 0 0 35px;
+ position: relative;
+}
+.event-list .event .event-summary::before {
+ animation: dot-flash 1s alternate infinite ease-in-out;
+ background: var(--event-title);
+ left: 0;
+ margin-top: -6px;
+ position: absolute;
+ top: 50%;
+ border-radius: 50%;
+ content: ' ';
+ height: 12px;
+ width: 12px;
+}
+.event-list .event:nth-of-type(odd) .event-summary::before {
+ animation-delay: 0.5s;
+}
+.event-list .event:not(:last-child) {
+ margin-bottom: 20px;
+}
+.event-list .event .event-relative-time {
+ color: var(--event-foreground);
+ display: inline-block;
+ font-size: 12px;
+ font-weight: normal;
+ padding-left: 12px;
+}
+.event-list .event .event-details {
+ color: var(--event-foreground);
+ display: block;
+ line-height: 18px;
+ padding: 6px 0 6px 35px;
+}
+.event-list .event .event-details::before {
+ color: var(--event-foreground);
+ display: inline-block;
+ margin-right: 9px;
+ width: 14px;
+ font-family: 'Font Awesome 6 Free';
+ font-weight: 900;
+}
+.event-list .event .event-details.event-location::before {
+ content: '\f041';
+}
+.event-list .event .event-details.event-duration::before {
+ content: '\f017';
+}
+.event-list .event .event-details.event-description::before {
+ content: '\f024';
+}
+.event-list .event-past {
+ --event-background: #f5f5f5;
+ --event-foreground: #999;
+ --event-title: #222;
+}
+@keyframes dot-flash {
+ from {
+ opacity: 1;
+ transform: scale(1);
+ }
+ to {
+ opacity: 0;
+ transform: scale(0.8);
+ }
+}
+ul.breadcrumb {
+ font-size: 0.75em;
+ list-style: none;
+ margin: 1em 0;
+ padding: 0 2em;
+ text-align: center;
+}
+ul.breadcrumb li {
+ display: inline;
+}
+ul.breadcrumb li:not(:first-child)::before {
+ content: '/\00a0';
+ font-weight: normal;
+ padding: 0.5em;
+}
+ul.breadcrumb li:last-child {
+ font-weight: bold;
+}
+.tag-cloud {
+ text-align: center;
+}
+.tag-cloud a {
+ display: inline-block;
+ margin: 10px;
+}
+.tag-cloud-0 {
+ border-bottom-color: #aaa;
+ color: #aaa;
+}
+.tag-cloud-1 {
+ border-bottom-color: #9a9a9a;
+ color: #9a9a9a;
+}
+.tag-cloud-2 {
+ border-bottom-color: #8b8b8b;
+ color: #8b8b8b;
+}
+.tag-cloud-3 {
+ border-bottom-color: #7c7c7c;
+ color: #7c7c7c;
+}
+.tag-cloud-4 {
+ border-bottom-color: #6c6c6c;
+ color: #6c6c6c;
+}
+.tag-cloud-5 {
+ border-bottom-color: #5d5d5d;
+ color: #5d5d5d;
+}
+.tag-cloud-6 {
+ border-bottom-color: #4e4e4e;
+ color: #4e4e4e;
+}
+.tag-cloud-7 {
+ border-bottom-color: #3e3e3e;
+ color: #3e3e3e;
+}
+.tag-cloud-8 {
+ border-bottom-color: #2f2f2f;
+ color: #2f2f2f;
+}
+.tag-cloud-9 {
+ border-bottom-color: #202020;
+ color: #202020;
+}
+.tag-cloud-10 {
+ border-bottom-color: #111;
+ color: #111;
+}
+@media (prefers-color-scheme: dark) {
+ .tag-cloud-0 {
+ border-bottom-color: #555;
+ color: #555;
+ }
+ .tag-cloud-1 {
+ border-bottom-color: #646464;
+ color: #646464;
+ }
+ .tag-cloud-2 {
+ border-bottom-color: #737373;
+ color: #737373;
+ }
+ .tag-cloud-3 {
+ border-bottom-color: #828282;
+ color: #828282;
+ }
+ .tag-cloud-4 {
+ border-bottom-color: #929292;
+ color: #929292;
+ }
+ .tag-cloud-5 {
+ border-bottom-color: #a1a1a1;
+ color: #a1a1a1;
+ }
+ .tag-cloud-6 {
+ border-bottom-color: #b0b0b0;
+ color: #b0b0b0;
+ }
+ .tag-cloud-7 {
+ border-bottom-color: #c0c0c0;
+ color: #c0c0c0;
+ }
+ .tag-cloud-8 {
+ border-bottom-color: #cfcfcf;
+ color: #cfcfcf;
+ }
+ .tag-cloud-9 {
+ border-bottom-color: #dedede;
+ color: #dedede;
+ }
+ .tag-cloud-10 {
+ border-bottom-color: #eee;
+ color: #eee;
+ }
+}
+.utterances {
+ max-width: unset;
+}
+.search-active {
+ overflow: hidden;
+}
+.search-pop-overlay {
+ background: rgba(0,0,0,0);
+ display: flex;
+ height: 100%;
+ left: 0;
+ position: fixed;
+ top: 0;
+ transition: visibility 0.4s, background 0.4s;
+ visibility: hidden;
+ width: 100%;
+ z-index: 40;
+}
+.search-active .search-pop-overlay {
+ background: rgba(0,0,0,0.3);
+ visibility: visible;
+}
+.search-popup {
+ background: var(--card-bg-color);
+ border-radius: 5px;
+ height: 80%;
+ margin: auto;
+ transform: scale(0);
+ transition: transform 0.4s;
+ width: 700px;
+}
+.search-active .search-popup {
+ transform: scale(1);
+}
+@media (max-width: 767px) {
+ .search-popup {
+ border-radius: 0;
+ height: 100%;
+ width: 100%;
+ }
+}
+.search-popup .search-icon,
+.search-popup .popup-btn-close {
+ color: #999;
+ font-size: 18px;
+ padding: 0 10px;
+}
+.search-popup .popup-btn-close {
+ cursor: pointer;
+}
+.search-popup .popup-btn-close:hover .fa {
+ color: #222;
+}
+.search-popup .search-header {
+ background: #eee;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+ display: flex;
+ padding: 5px;
+}
+@media (prefers-color-scheme: dark) {
+ .search-popup .search-header {
+ background: #666;
+ }
+}
+.search-popup input.search-input {
+ background: transparent;
+ border: 0;
+ outline: 0;
+ width: 100%;
+}
+.search-popup input.search-input::-webkit-search-cancel-button {
+ display: none;
+}
+.search-popup .search-result-container {
+ height: calc(100% - 55px);
+ overflow: auto;
+ padding: 5px 25px;
+}
+.search-popup .search-result-container hr {
+ margin: 5px 0 10px;
+}
+.search-popup .search-result-container hr:first-child {
+ display: none;
+}
+.search-popup .search-result-list {
+ margin: 0 5px;
+ padding: 0;
+}
+.search-popup a.search-result-title {
+ font-weight: bold;
+}
+.search-popup p.search-result {
+ border-bottom: 1px dashed #ccc;
+ padding: 5px 0;
+}
+.search-popup .search-input-container {
+ flex-grow: 1;
+ padding: 2px;
+}
+.search-popup .no-result {
+ display: flex;
+}
+.search-popup .search-result-list {
+ width: 100%;
+}
+.search-popup .search-result-icon {
+ color: #ccc;
+ margin: auto;
+}
+mark.search-keyword {
+ background: transparent;
+ border-bottom: 1px dashed #ff2a2a;
+ color: #ff2a2a;
+ font-weight: bold;
+}
+.use-motion .animated {
+ animation-fill-mode: none;
+ visibility: inherit;
+}
+.use-motion .sidebar .animated {
+ animation-fill-mode: both;
+}
+header.header {
+ background: var(--content-bg-color);
+ border-radius: initial;
+ box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12);
+}
+@media (max-width: 991px) {
+ header.header {
+ border-radius: initial;
+ }
+}
+.main {
+ align-items: stretch;
+ display: flex;
+ justify-content: space-between;
+ margin: 0 auto;
+ width: calc(100% - 20px);
+}
+@media (max-width: 767px) {
+ .main {
+ width: auto;
+ }
+}
+@media (min-width: 1200px) {
+ .main {
+ width: 1160px;
+ }
+}
+@media (min-width: 1600px) {
+ .main {
+ width: 73%;
+ }
+}
+@media (max-width: 991px) {
+ .main {
+ display: block;
+ width: auto;
+ }
+}
+.main-inner {
+ border-radius: initial;
+ box-sizing: border-box;
+ width: calc(100% - 252px);
+}
+@media (max-width: 991px) {
+ .main-inner {
+ border-radius: initial;
+ width: 100%;
+ }
+}
+.footer-inner {
+ padding-left: 252px;
+}
+@media (max-width: 991px) {
+ .footer-inner {
+ padding-left: 0;
+ padding-right: 0;
+ width: auto;
+ }
+}
+.column {
+ width: 240px;
+}
+@media (max-width: 991px) {
+ .column {
+ width: auto;
+ }
+}
+.site-brand-container {
+ background: var(--theme-color);
+}
+@media (max-width: 991px) {
+ .site-nav-on .site-brand-container {
+ box-shadow: 0 0 16px rgba(0,0,0,0.5);
+ }
+}
+.site-meta {
+ padding: 20px 0;
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .site-nav-toggle,
+ .site-nav-right {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ }
+}
+.site-nav-toggle .toggle,
+.site-nav-right .toggle {
+ color: #fff;
+}
+.site-nav-toggle .toggle .toggle-line,
+.site-nav-right .toggle .toggle-line {
+ background: #fff;
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .site-nav {
+ --scroll-height: 0;
+ height: 0;
+ overflow: hidden;
+ transition: 0.2s ease-in-out;
+ transition-property: height, visibility;
+ visibility: hidden;
+ }
+ body:not(.site-nav-on) .site-nav .animated {
+ animation: none;
+ }
+ body.site-nav-on .site-nav {
+ height: var(--scroll-height);
+ visibility: unset;
+ }
+}
+.menu .menu-item {
+ display: block;
+ margin: 0;
+}
+.menu .menu-item a {
+ padding: 5px 20px;
+ position: relative;
+ text-align: left;
+ transition-property: background-color;
+}
+@media (max-width: 991px) {
+ .menu .menu-item.menu-item-search {
+ display: none;
+ }
+}
+.menu .menu-item .badge {
+ background: #ccc;
+ border-radius: 10px;
+ color: var(--content-bg-color);
+ float: right;
+ padding: 2px 5px;
+ text-shadow: 1px 1px 0 rgba(0,0,0,0.1);
+}
+.main-menu .menu-item-active::after {
+ background: #bbb;
+ border-radius: 50%;
+ content: ' ';
+ height: 6px;
+ margin-top: -3px;
+ position: absolute;
+ right: 15px;
+ top: 50%;
+ width: 6px;
+}
+.sub-menu {
+ margin: 0;
+ padding: 6px 0;
+}
+.sub-menu .menu-item {
+ display: inline-block;
+}
+.sub-menu .menu-item a {
+ background: transparent;
+ margin: 5px 10px;
+ padding: initial;
+}
+.sub-menu .menu-item a:hover {
+ background: transparent;
+ color: #fc6423;
+}
+.sub-menu .menu-item-active {
+ border-bottom-color: #fc6423;
+ color: #fc6423;
+}
+.sub-menu .menu-item-active:hover {
+ border-bottom-color: #fc6423;
+}
+.sidebar {
+ position: -webkit-sticky;
+ position: sticky;
+ top: 12px;
+}
+@media (max-width: 991px) {
+ .sidebar {
+ display: none;
+ }
+}
+.sidebar-inner {
+ background: var(--content-bg-color);
+ border-radius: initial;
+ box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12), 0 -1px 0.5px 0 rgba(0,0,0,0.09);
+ box-sizing: border-box;
+ color: var(--text-color);
+ margin-top: 12px;
+ max-height: calc(100vh - 24px);
+ visibility: hidden;
+}
+.site-state-item {
+ padding: 0 10px;
+}
+.sidebar .sidebar-button {
+ border-bottom: 1px dotted #ccc;
+ border-top: 1px dotted #ccc;
+}
+.sidebar .sidebar-button button {
+ border: 0;
+ color: #fc6423;
+ display: block;
+ width: 100%;
+}
+.sidebar .sidebar-button button:hover {
+ background: none;
+ border: 0;
+ color: #e34603;
+}
+.links-of-author {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+}
+.links-of-author-item {
+ margin: 5px 0 0;
+}
+.links-of-author-item a {
+ box-sizing: border-box;
+ display: inline-block;
+ max-width: 100%;
+ overflow: hidden;
+ padding: 0 5px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.links-of-author-item a {
+ border-bottom: 0;
+ border-radius: 4px;
+ display: block;
+}
+.links-of-author-item a:hover {
+ background: var(--body-bg-color);
+}
+.main-inner .sub-menu,
+.main-inner .post-block,
+.main-inner .tabs-comment,
+.main-inner > .comments,
+.main-inner .comment-position .comments,
+.main-inner .pagination {
+ background: var(--content-bg-color);
+ border-radius: initial;
+ box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12);
+}
+.main-inner .post-block:not(:first-child):not(:first-child) {
+ border-radius: initial;
+ box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12), 0 -1px 0.5px 0 rgba(0,0,0,0.09);
+ margin-top: 12px;
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .main-inner .post-block:not(:first-child):not(:first-child) {
+ margin-top: 10px;
+ }
+}
+@media (max-width: 767px) {
+ .main-inner .post-block:not(:first-child):not(:first-child) {
+ margin-top: 8px;
+ }
+}
+.main-inner .tabs-comment,
+.main-inner > .comments,
+.main-inner .comment-position .comments,
+.main-inner .pagination {
+ border-radius: initial;
+ box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12), 0 -1px 0.5px 0 rgba(0,0,0,0.09);
+ margin-top: 12px;
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .main-inner .tabs-comment,
+ .main-inner > .comments,
+ .main-inner .comment-position .comments,
+ .main-inner .pagination {
+ margin-top: 10px;
+ }
+}
+@media (max-width: 767px) {
+ .main-inner .tabs-comment,
+ .main-inner > .comments,
+ .main-inner .comment-position .comments,
+ .main-inner .pagination {
+ margin-top: 8px;
+ }
+}
+.post-block,
+.comments {
+ padding: 40px;
+}
+.post-eof {
+ display: none;
+}
+.pagination {
+ border-top: initial;
+ padding: 10px 0;
+}
+.post-body h1,
+.post-body h2 {
+ border-bottom: 1px solid #eee;
+}
+.post-body h3 {
+ border-bottom: 1px dotted #eee;
+}
+@media (min-width: 768px) and (max-width: 991px) {
+ .main-inner {
+ padding: 10px;
+ }
+ .posts-expand .post-button {
+ margin-top: 20px;
+ }
+ .post-block {
+ padding: 20px;
+ }
+ .comments {
+ padding: 10px 20px;
+ }
+}
+@media (max-width: 767px) {
+ .main-inner {
+ padding: 8px;
+ }
+ .posts-expand .post-button {
+ margin: 12px 0;
+ }
+ .post-block {
+ padding: 12px;
+ }
+ .comments {
+ padding: 10px 12px;
+ }
+}
diff --git a/css/noscript.css b/css/noscript.css
new file mode 100644
index 0000000..6418c57
--- /dev/null
+++ b/css/noscript.css
@@ -0,0 +1,48 @@
+body {
+ margin-top: 2rem;
+}
+.use-motion .menu-item,
+.use-motion .sidebar,
+.use-motion .sidebar-inner,
+.use-motion .post-block,
+.use-motion .pagination,
+.use-motion .comments,
+.use-motion .post-header,
+.use-motion .post-body,
+.use-motion .collection-header {
+ visibility: visible;
+}
+.use-motion .column,
+.use-motion .site-brand-container .toggle,
+.use-motion .footer {
+ opacity: initial;
+}
+.use-motion .site-title,
+.use-motion .site-subtitle,
+.use-motion .custom-logo-image {
+ 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: bold;
+ left: 0;
+ position: fixed;
+ text-align: center;
+ top: 0;
+ width: 100%;
+ z-index: 50;
+}
diff --git a/en/first-post/index.html b/en/first-post/index.html
new file mode 100644
index 0000000..993aedb
--- /dev/null
+++ b/en/first-post/index.html
@@ -0,0 +1,338 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Sorry! Post Not Found | ADY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/en/index.html b/en/index.html
new file mode 100644
index 0000000..02107c4
--- /dev/null
+++ b/en/index.html
@@ -0,0 +1,335 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ADY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/en/test/index.html b/en/test/index.html
new file mode 100644
index 0000000..2f5b74f
--- /dev/null
+++ b/en/test/index.html
@@ -0,0 +1,365 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test (英文) | ADY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/github-card-lib/githubcard.js b/github-card-lib/githubcard.js
new file mode 100644
index 0000000..5059f3a
--- /dev/null
+++ b/github-card-lib/githubcard.js
@@ -0,0 +1 @@
+(function(e){var t="//lab.lepture.com/github-cards/";var r,i=0;var a=e.getElementsByTagName("meta");var n,l,c,d;for(r=0;r
+
+
diff --git a/images/logo-algolia-nebula-blue-full.svg b/images/logo-algolia-nebula-blue-full.svg
new file mode 100644
index 0000000..886c422
--- /dev/null
+++ b/images/logo-algolia-nebula-blue-full.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/images/logo.svg b/images/logo.svg
new file mode 100644
index 0000000..992c1a5
--- /dev/null
+++ b/images/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..3c083b3
--- /dev/null
+++ b/index.html
@@ -0,0 +1,416 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ADY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
測試 i18n 語系使用
+- 切換語系可對應至該語系同一篇文章
+- 沒有該語系文章會產生 Post not found,但不是導至 404,所以可以來回切換語系
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/js/bookmark.js b/js/bookmark.js
new file mode 100644
index 0000000..8e3ae6a
--- /dev/null
+++ b/js/bookmark.js
@@ -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);
+});
diff --git a/js/comments-buttons.js b/js/comments-buttons.js
new file mode 100644
index 0000000..505c21b
--- /dev/null
+++ b/js/comments-buttons.js
@@ -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();
+ }
+ }
+})();
diff --git a/js/comments.js b/js/comments.js
new file mode 100644
index 0000000..4045e8c
--- /dev/null
+++ b/js/comments.js
@@ -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);
+ });
+}
diff --git a/js/config.js b/js/config.js
new file mode 100644
index 0000000..caa0075
--- /dev/null
+++ b/js/config.js
@@ -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 = {};
+ });
+})();
diff --git a/js/motion.js b/js/motion.js
new file mode 100644
index 0000000..aad22db
--- /dev/null
+++ b/js/motion.js
@@ -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
+ }];
+ }
+};
diff --git a/js/next-boot.js b/js/next-boot.js
new file mode 100644
index 0000000..fceb80b
--- /dev/null
+++ b/js/next-boot.js
@@ -0,0 +1,79 @@
+/* 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();
+ }
+ });
+
+ window.addEventListener('tabs:click', e => {
+ NexT.utils.registerCodeblock(e.target);
+ });
+};
+
+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.registerCodeblock();
+ 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();
+});
diff --git a/js/pjax.js b/js/pjax.js
new file mode 100644
index 0000000..f81a6a0
--- /dev/null
+++ b/js/pjax.js
@@ -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();
+ }
+});
diff --git a/js/schedule.js b/js/schedule.js
new file mode 100644
index 0000000..8f0c26c
--- /dev/null
+++ b/js/schedule.js
@@ -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 = `${event.location}`;
+ }
+ let description = '';
+ if (event.description) {
+ description = `${event.description}`;
+ }
+
+ const eventContent = `
+
+ ${event.summary}
+ ${relativeTime}
+
+ ${location}
+ ${duration}
+ ${description}
+ `;
+ 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 = '
';
+ return;
+ }
+ // Clean the event list
+ eventList.innerHTML = '';
+ let prevEnd = 0; // used to decide where to insert an
+ 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', '
');
+ }
+
+ eventList.insertAdjacentHTML('beforeend', buildEventDOM(tense, event, start, end));
+ prevEnd = end;
+ });
+ });
+ }
+
+ fetchData();
+ const fetchDataTimer = setInterval(fetchData, 60000);
+ document.addEventListener('pjax:send', () => {
+ clearInterval(fetchDataTimer);
+ });
+})();
diff --git a/js/schemes/muse.js b/js/schemes/muse.js
new file mode 100644
index 0000000..ba60b51
--- /dev/null
+++ b/js/schemes/muse.js
@@ -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 });
+});
diff --git a/js/third-party/addtoany.js b/js/third-party/addtoany.js
new file mode 100644
index 0000000..f9009f8
--- /dev/null
+++ b/js/third-party/addtoany.js
@@ -0,0 +1,8 @@
+/* global NexT */
+
+document.addEventListener('page:loaded', () => {
+ NexT.utils.getScript('https://static.addtoany.com/menu/page.js', { condition: window.a2a })
+ .then(() => {
+ window.a2a.init();
+ });
+});
diff --git a/js/third-party/analytics/baidu-analytics.js b/js/third-party/analytics/baidu-analytics.js
new file mode 100644
index 0000000..c10e7d0
--- /dev/null
+++ b/js/third-party/analytics/baidu-analytics.js
@@ -0,0 +1,7 @@
+/* global _hmt */
+
+if (!window._hmt) window._hmt = [];
+
+document.addEventListener('pjax:success', () => {
+ _hmt.push(['_trackPageview', location.pathname]);
+});
diff --git a/js/third-party/analytics/google-analytics.js b/js/third-party/analytics/google-analytics.js
new file mode 100644
index 0000000..8601806
--- /dev/null
+++ b/js/third-party/analytics/google-analytics.js
@@ -0,0 +1,53 @@
+/* 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);
+ fetch(
+ 'https://www.google-analytics.com/mp/collect?' + new URLSearchParams({
+ api_secret : CONFIG.google_analytics.measure_protocol_api_secret,
+ measurement_id: CONFIG.google_analytics.tracking_id
+ }),
+ {
+ method : 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ client_id: uid,
+ events : [
+ {
+ name : 'page_view',
+ params: {
+ page_location: location.href,
+ page_title : document.title
+ }
+ }
+ ]
+ }),
+ mode: 'no-cors'
+ }
+ );
+ };
+ document.addEventListener('pjax:complete', sendPageView);
+ sendPageView();
+}
diff --git a/js/third-party/analytics/growingio.js b/js/third-party/analytics/growingio.js
new file mode 100644
index 0000000..0460833
--- /dev/null
+++ b/js/third-party/analytics/growingio.js
@@ -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');
diff --git a/js/third-party/analytics/matomo.js b/js/third-party/analytics/matomo.js
new file mode 100644
index 0000000..290a3e0
--- /dev/null
+++ b/js/third-party/analytics/matomo.js
@@ -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);
+}
diff --git a/js/third-party/chat/chatra.js b/js/third-party/chat/chatra.js
new file mode 100644
index 0000000..e495b8e
--- /dev/null
+++ b/js/third-party/chat/chatra.js
@@ -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);
+ });
+ }
+})();
diff --git a/js/third-party/chat/tidio.js b/js/third-party/chat/tidio.js
new file mode 100644
index 0000000..bffb918
--- /dev/null
+++ b/js/third-party/chat/tidio.js
@@ -0,0 +1,10 @@
+/* global tidioChatApi */
+
+(function() {
+ const chatButton = document.querySelector('.sidebar-button button');
+ if (chatButton) {
+ chatButton.addEventListener('click', () => {
+ tidioChatApi.open();
+ });
+ }
+})();
diff --git a/js/third-party/comments/changyan.js b/js/third-party/comments/changyan.js
new file mode 100644
index 0000000..18a1be4
--- /dev/null
+++ b/js/third-party/comments/changyan.js
@@ -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);
+ });
+ }
+});
diff --git a/js/third-party/comments/disqus.js b/js/third-party/comments/disqus.js
new file mode 100644
index 0000000..4d1ca9e
--- /dev/null
+++ b/js/third-party/comments/disqus.js
@@ -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() } }
+ });
+ }
+ });
+ }
+
+});
diff --git a/js/third-party/comments/disqusjs.js b/js/third-party/comments/disqusjs.js
new file mode 100644
index 0000000..d8401ee
--- /dev/null
+++ b/js/third-party/comments/disqusjs.js
@@ -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();
+});
diff --git a/js/third-party/comments/gitalk.js b/js/third-party/comments/gitalk.js
new file mode 100644
index 0000000..08d07f4
--- /dev/null
+++ b/js/third-party/comments/gitalk.js
@@ -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'));
+ });
+});
diff --git a/js/third-party/comments/isso.js b/js/third-party/comments/isso.js
new file mode 100644
index 0000000..2c70601
--- /dev/null
+++ b/js/third-party/comments/isso.js
@@ -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')
+ }));
+});
diff --git a/js/third-party/comments/livere.js b/js/third-party/comments/livere.js
new file mode 100644
index 0000000..c4bcd2e
--- /dev/null
+++ b/js/third-party/comments/livere.js
@@ -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
+ }
+ });
+ });
+});
diff --git a/js/third-party/comments/utterances.js b/js/third-party/comments/utterances.js
new file mode 100644
index 0000000..332ee05
--- /dev/null
+++ b/js/third-party/comments/utterances.js
@@ -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')
+ }));
+});
diff --git a/js/third-party/fancybox.js b/js/third-party/fancybox.js
new file mode 100644
index 0000000..178db4b
--- /dev/null
+++ b/js/third-party/fancybox.js
@@ -0,0 +1,35 @@
+/* global Fancybox */
+
+document.addEventListener('page:loaded', () => {
+
+ /**
+ * Wrap images with fancybox.
+ */
+ document.querySelectorAll('.post-body :not(a) > img, .post-body > img').forEach(image => {
+ const imageLink = image.dataset.src || image.src;
+ const imageWrapLink = document.createElement('a');
+ imageWrapLink.classList.add('fancybox');
+ imageWrapLink.href = imageLink;
+ imageWrapLink.setAttribute('itemscope', '');
+ imageWrapLink.setAttribute('itemtype', 'http://schema.org/ImageObject');
+ imageWrapLink.setAttribute('itemprop', 'url');
+
+ let dataFancybox = 'default';
+ if (image.closest('.post-gallery') !== null) {
+ dataFancybox = 'gallery';
+ } else if (image.closest('.group-picture') !== null) {
+ dataFancybox = 'group';
+ }
+ imageWrapLink.dataset.fancybox = dataFancybox;
+
+ const imageTitle = image.title || image.alt;
+ if (imageTitle) {
+ imageWrapLink.title = imageTitle;
+ // Make sure img captions will show correctly in fancybox
+ imageWrapLink.dataset.caption = imageTitle;
+ }
+ image.wrap(imageWrapLink);
+ });
+
+ Fancybox.bind('[data-fancybox]');
+});
diff --git a/js/third-party/math/katex.js b/js/third-party/math/katex.js
new file mode 100644
index 0000000..ad745b1
--- /dev/null
+++ b/js/third-party/math/katex.js
@@ -0,0 +1,7 @@
+/* global NexT, CONFIG */
+
+document.addEventListener('page:loaded', () => {
+ if (!CONFIG.enableMath) return;
+
+ NexT.utils.getScript(CONFIG.katex.copy_tex_js).catch(() => {});
+});
diff --git a/js/third-party/math/mathjax.js b/js/third-party/math/mathjax.js
new file mode 100644
index 0000000..fe4d448
--- /dev/null
+++ b/js/third-party/math/mathjax.js
@@ -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();
+ }
+});
diff --git a/js/third-party/pace.js b/js/third-party/pace.js
new file mode 100644
index 0000000..c22d59f
--- /dev/null
+++ b/js/third-party/pace.js
@@ -0,0 +1,7 @@
+/* global Pace */
+
+Pace.options.restartOnPushState = false;
+
+document.addEventListener('pjax:send', () => {
+ Pace.restart();
+});
diff --git a/js/third-party/quicklink.js b/js/third-party/quicklink.js
new file mode 100644
index 0000000..2543ad1
--- /dev/null
+++ b/js/third-party/quicklink.js
@@ -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);
+ }
+})();
diff --git a/js/third-party/search/algolia-search.js b/js/third-party/search/algolia-search.js
new file mode 100644
index 0000000..12a554c
--- /dev/null
+++ b/js/third-party/search/algolia-search.js
@@ -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 `${stats}
+ `;
+ }
+ },
+ cssClasses: {
+ text: 'search-stats'
+ }
+ }),
+
+ instantsearch.widgets.hits({
+ container : '.algolia-hits',
+ escapeHTML: false,
+ templates : {
+ item: data => {
+ const { title, excerpt, excerptStrip, contentStripTruncate } = data._highlightResult;
+ let result = `${title.value}`;
+ const content = excerpt || excerptStrip || contentStripTruncate;
+ if (content && content.value) {
+ const div = document.createElement('div');
+ div.innerHTML = content.value;
+ result += `${div.textContent.substring(0, 100)}...
`;
+ }
+ return result;
+ },
+ empty: data => {
+ return `
+ ${CONFIG.i18n.empty.replace('${query}', data.query)}
+
`;
+ }
+ },
+ cssClasses: {
+ list: 'search-result-list'
+ }
+ }),
+
+ instantsearch.widgets.pagination({
+ container: '.algolia-pagination',
+ scrollTo : false,
+ showFirst: false,
+ showLast : false,
+ templates: {
+ first : '',
+ last : '',
+ previous: '',
+ next : ''
+ },
+ 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();
+ }
+ });
+});
diff --git a/js/third-party/search/local-search.js b/js/third-party/search/local-search.js
new file mode 100644
index 0000000..92a264d
--- /dev/null
+++ b/js/third-party/search/local-search.js
@@ -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 = '
';
+ } else if (resultItems.length === 0) {
+ container.classList.add('no-result');
+ container.innerHTML = '
';
+ } 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 = `${stats}
+
+ ${resultItems.map(result => result.item).join('')}
`;
+ 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();
+ }
+ });
+});
diff --git a/js/third-party/statistics/firestore.js b/js/third-party/statistics/firestore.js
new file mode 100644
index 0000000..3ea7ba6
--- /dev/null
+++ b/js/third-party/statistics/firestore.js
@@ -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;
+ });
+ });
+ }
+ });
+})();
diff --git a/js/third-party/statistics/lean-analytics.js b/js/third-party/statistics/lean-analytics.js
new file mode 100644
index 0000000..8397112
--- /dev/null
+++ b/js/third-party/statistics/lean-analytics.js
@@ -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}`);
+ });
+ }
+ });
+})();
diff --git a/js/third-party/tags/mermaid.js b/js/third-party/tags/mermaid.js
new file mode 100644
index 0000000..54f6288
--- /dev/null
+++ b/js/third-party/tags/mermaid.js
@@ -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.run();
+ });
+ }
+});
diff --git a/js/third-party/tags/pdf.js b/js/third-party/tags/pdf.js
new file mode 100644
index 0000000..7e82891
--- /dev/null
+++ b/js/third-party/tags/pdf.js
@@ -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
+ });
+ });
+ });
+ }
+});
diff --git a/js/third-party/tags/wavedrom.js b/js/third-party/tags/wavedrom.js
new file mode 100644
index 0000000..ddd9a1d
--- /dev/null
+++ b/js/third-party/tags/wavedrom.js
@@ -0,0 +1,13 @@
+/* global NexT, CONFIG, WaveDrom */
+
+document.addEventListener('page:loaded', () => {
+ NexT.utils.getScript(CONFIG.wavedrom.js, {
+ condition: window.WaveDrom
+ }).then(() => {
+ NexT.utils.getScript(CONFIG.wavedrom_skin.js, {
+ condition: window.WaveSkin
+ }).then(() => {
+ WaveDrom.ProcessAll();
+ });
+ });
+});
diff --git a/js/utils.js b/js/utils.js
new file mode 100644
index 0000000..808d838
--- /dev/null
+++ b/js/utils.js
@@ -0,0 +1,489 @@
+/* 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);
+ });
+ },
+
+ registerCodeblock: function(element) {
+ const inited = !!element;
+ let figure = (inited ? element : document).querySelectorAll('figure.highlight');
+ let isHljsWithWrap = true;
+ if (figure.length === 0) {
+ figure = document.querySelectorAll('pre:not(.mermaid)');
+ isHljsWithWrap = false;
+ }
+ figure.forEach(element => {
+ if (!inited) {
+ let span = element.querySelectorAll('.code .line span');
+ if (span.length === 0) {
+ // Hljs without line_number and wrap
+ span = element.querySelectorAll('code.highlight span');
+ }
+ span.forEach(s => {
+ s.classList.forEach(name => {
+ s.classList.replace(name, `hljs-${name}`);
+ });
+ });
+ }
+ const height = parseInt(window.getComputedStyle(element).height.replace('px', ''), 10);
+ const needFold = CONFIG.fold.enable && (height > CONFIG.fold.height);
+ if (!needFold && !CONFIG.copycode.enable) return;
+ let target;
+ if (isHljsWithWrap && CONFIG.copycode.style === 'mac') {
+ target = element;
+ } else {
+ let box = element.querySelector('.code-container');
+ if (!box) {
+ // https://github.com/next-theme/hexo-theme-next/issues/98
+ // https://github.com/next-theme/hexo-theme-next/pull/508
+ const container = element.querySelector('.table-container') || element;
+ box = document.createElement('div');
+ box.className = 'code-container';
+ container.wrap(box);
+
+ // add "notranslate" to prevent Google Translate from translating it, which also completely messes up the layout
+ box.classList.add('notranslate');
+ }
+ target = box;
+ }
+ if (needFold && !target.classList.contains('unfold')) {
+ target.classList.add('highlight-fold');
+ target.insertAdjacentHTML('beforeend', '
');
+ target.querySelector('.expand-btn').addEventListener('click', () => {
+ target.classList.remove('highlight-fold');
+ target.classList.add('unfold');
+ });
+ }
+ if (inited || !CONFIG.copycode.enable) return;
+ // One-click copy code support.
+ target.insertAdjacentHTML('beforeend', '
');
+ const button = target.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);
+ });
+ }
+};
diff --git a/placeholder b/placeholder
deleted file mode 100644
index e69de29..0000000
diff --git a/search.xml b/search.xml
new file mode 100644
index 0000000..d0d2c95
--- /dev/null
+++ b/search.xml
@@ -0,0 +1,24 @@
+
+
+
+ test (英文)
+ /en/test/
+
+
+
+ test (中文)
+ /zh-tw/test/
+
+
+
+ 你好! 世界
+ /zh-tw/first-post/
+
+
+測試 i18n 語系使用
+- 切換語系可對應至該語系同一篇文章
+- 沒有該語系文章會產生 Post not found,但不是導至 404,所以可以來回切換語系
+
+]]>
+
+
diff --git a/zh-tw/first-post/image.png b/zh-tw/first-post/image.png
new file mode 100644
index 0000000..63b0933
Binary files /dev/null and b/zh-tw/first-post/image.png differ
diff --git a/zh-tw/first-post/index.html b/zh-tw/first-post/index.html
new file mode 100644
index 0000000..8bcdaab
--- /dev/null
+++ b/zh-tw/first-post/index.html
@@ -0,0 +1,376 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+你好! 世界 | ADY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
測試 i18n 語系使用
+- 切換語系可對應至該語系同一篇文章
+- 沒有該語系文章會產生 Post not found,但不是導至 404,所以可以來回切換語系
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/zh-tw/index.html b/zh-tw/index.html
new file mode 100644
index 0000000..5fe4767
--- /dev/null
+++ b/zh-tw/index.html
@@ -0,0 +1,416 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ADY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
測試 i18n 語系使用
+- 切換語系可對應至該語系同一篇文章
+- 沒有該語系文章會產生 Post not found,但不是導至 404,所以可以來回切換語系
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/zh-tw/test/index.html b/zh-tw/test/index.html
new file mode 100644
index 0000000..d5c4649
--- /dev/null
+++ b/zh-tw/test/index.html
@@ -0,0 +1,368 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test (中文) | ADY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+