diff --git a/404.html b/404.html new file mode 100644 index 0000000..fd43e59 --- /dev/null +++ b/404.html @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Sorry! Post Not Found | ADY + + + + + + + + + + + + + +
+ +
+
+
+ + + + + +
+ + + + + + + +
+ +
+ +
+ + + + + +
+ +
+ + + + + +
+ + + +
+ + + + + + + +
+

+ Sorry! Post Not Found +

+ + +
+ + + + +
+ + +
+ + + + + + +
+
+ + + + + + +
+
+ + + + +
+ + 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..8ce53b1 --- /dev/null +++ b/archives/2024/04/index.html @@ -0,0 +1,294 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +歸檔 | ADY + + + + + + + + + + + + + +
+ +
+
+
+ + + + + +
+ + + + + + + +
+ +
+ +
+ + + + + +
+ +
+ + + + + +
+
+
+ 嗯..! 目前共有 1 篇文章。 繼續努力。 +
+ + +
+ 2024 +
+ + + + +
+
+ + + + +
+
+ + + + +
+ + 0% +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2024/index.html b/archives/2024/index.html new file mode 100644 index 0000000..e058773 --- /dev/null +++ b/archives/2024/index.html @@ -0,0 +1,294 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +歸檔 | ADY + + + + + + + + + + + + + +
+ +
+
+
+ + + + + +
+ + + + + + + +
+ +
+ +
+ + + + + +
+ +
+ + + + + +
+
+
+ 嗯..! 目前共有 1 篇文章。 繼續努力。 +
+ + +
+ 2024 +
+ + + + +
+
+ + + + +
+
+ + + + +
+ + 0% +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/index.html b/archives/index.html new file mode 100644 index 0000000..88b5d3f --- /dev/null +++ b/archives/index.html @@ -0,0 +1,294 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +歸檔 | ADY + + + + + + + + + + + + + +
+ +
+
+
+ + + + + +
+ + + + + + + +
+ +
+ +
+ + + + + +
+ +
+ + + + + +
+
+
+ 嗯..! 目前共有 1 篇文章。 繼續努力。 +
+ + +
+ 2024 +
+ + + + +
+
+ + + + +
+
+ + + + +
+ + 0% +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/css/main.css b/css/main.css new file mode 100644 index 0000000..b9a739b --- /dev/null +++ b/css/main.css @@ -0,0 +1,2915 @@ +: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; +} +.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-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; + } +} +.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..1e8fa8d --- /dev/null +++ b/en/first_post/index.html @@ -0,0 +1,322 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Sorry! Post Not Found | ADY + + + + + + + + + + + + + +
+ +
+
+
+ + + + + +
+ + + + + + + +
+ +
+ +
+ + + + + +
+ +
+ + + + + +
+ + + +
+ + + + + + + +
+

+ Sorry! Post Not Found +

+ + +
+ + + + +
+
+ + + + + +
+ + + +
+
+
+ + + + + + +
+
+ + + + +
+ + 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 + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + + + 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..eae10f6 --- /dev/null +++ b/index.html @@ -0,0 +1,332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +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} + Algolia`; + } + }, + cssClasses: { + text: 'search-stats' + } + }), + + instantsearch.widgets.hits({ + container : '.algolia-hits', + escapeHTML: false, + templates : { + item: data => { + const { title, excerpt, excerptStrip, contentStripTruncate } = data._highlightResult; + let result = `${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}
+
+ `; + 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..d7a00f8 --- /dev/null +++ b/search.xml @@ -0,0 +1,12 @@ + + + + 你好! 世界 + /zh-tw/first_post/ + 測試 i18n 語系使用
    +
  • 切換語系可對應至該語系同意一篇文章
  • +
  • 沒有該語系文章會產生 Post not found,但不是導至 404,所以可以來回切換語系
  • +
+]]>
+
+
diff --git a/zh-tw/first_post/index.html b/zh-tw/first_post/index.html new file mode 100644 index 0000000..1c298f4 --- /dev/null +++ b/zh-tw/first_post/index.html @@ -0,0 +1,338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +你好! 世界 | 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..3cc66d8 --- /dev/null +++ b/zh-tw/index.html @@ -0,0 +1,332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ADY + + + + + + + + + + + + + +
+ +
+
+
+ + + + + +
+ + + + + + + +
+ +
+ +
+ + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + +
+

+ +

+ + +
+ + + + +
+

測試 i18n 語系使用

    +
  • 切換語系可對應至該語系同意一篇文章
  • +
  • 沒有該語系文章會產生 Post not found,但不是導至 404,所以可以來回切換語系
  • +
+ + +
+ + + + + +
+
+ +
+
+
+ + + + + +
+
+ +
+ +
+ + +
+ + 0% +
+ + + + + + + + + + + + + + + + + + + + + + + + + +