mirror of
https://github.com/cotes2020/jekyll-theme-chirpy.git
synced 2025-12-19 14:14:17 +00:00
Compare commits
142 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20987f2afe | ||
|
|
39e4338839 | ||
|
|
33a1fa7cae | ||
|
|
00a27a1b85 | ||
|
|
5cdde7dbc5 | ||
|
|
c4b58e3502 | ||
|
|
9630fd647f | ||
|
|
e33547fe5d | ||
|
|
09b300bc62 | ||
|
|
9ffd997c3b | ||
|
|
37827d81e5 | ||
|
|
febc01db52 | ||
|
|
b2245492e6 | ||
|
|
f87fdd0ea0 | ||
|
|
fdbd7f02e3 | ||
|
|
75891e714f | ||
|
|
363a3d936b | ||
|
|
ddb48eda52 | ||
|
|
c17fba44f5 | ||
|
|
12c340e98b | ||
|
|
dcb0add47b | ||
|
|
f1c6d2a817 | ||
|
|
05ebfb705e | ||
|
|
8608147fb5 | ||
|
|
76d58fe0ff | ||
|
|
b77767f76e | ||
|
|
e0950fc973 | ||
|
|
778ebdf250 | ||
|
|
796c386037 | ||
|
|
72d93b132f | ||
|
|
e09831ba3e | ||
|
|
05e3689d17 | ||
|
|
d4a6d640bd | ||
|
|
2cfa54847a | ||
|
|
cd37f63a01 | ||
|
|
015d5670a1 | ||
|
|
63c51384df | ||
|
|
662cd331e3 | ||
|
|
d013c11c8d | ||
|
|
fe7afa379f | ||
|
|
c85e9e2394 | ||
|
|
bf16d6039a | ||
|
|
8c1be9f2f3 | ||
|
|
7808ee157c | ||
|
|
1914c786a0 | ||
|
|
44f552cbce | ||
|
|
7d48d32c7b | ||
|
|
9f8aeaadbf | ||
|
|
61bdca2db4 | ||
|
|
23be4162b3 | ||
|
|
01076cb1c2 | ||
|
|
3cc1510071 | ||
|
|
950839175a | ||
|
|
13bf51e03d | ||
|
|
ce96d7e251 | ||
|
|
7a7818b579 | ||
|
|
cef8a97384 | ||
|
|
2d649aae0e | ||
|
|
b7aa05d03a | ||
|
|
c5d5e1f75a | ||
|
|
319a082940 | ||
|
|
6044df4ff1 | ||
|
|
e5594525e7 | ||
|
|
e15eaaffe0 | ||
|
|
74cf57aaac | ||
|
|
cfe44f204b | ||
|
|
700fd5bad7 | ||
|
|
8e5fbb7a74 | ||
|
|
834931486d | ||
|
|
f865336c89 | ||
|
|
0f8e782bfd | ||
|
|
0a6c1fb251 | ||
|
|
75a3d7399b | ||
|
|
547b95cc7a | ||
|
|
2a7b56bb36 | ||
|
|
25c4166722 | ||
|
|
25b2ffa9ba | ||
|
|
8a2afae6ca | ||
|
|
6112b15b8e | ||
|
|
e24a0c73ba | ||
|
|
0f5abc82a2 | ||
|
|
795ff3f4c3 | ||
|
|
c41672b2e0 | ||
|
|
9cc62e703f | ||
|
|
19d6bafbe1 | ||
|
|
4ddd5c4370 | ||
|
|
9592146ca3 | ||
|
|
8a1568c27a | ||
|
|
388c1511d6 | ||
|
|
8849afe5cf | ||
|
|
f8390d4384 | ||
|
|
e4363871b5 | ||
|
|
b641b3f1f2 | ||
|
|
5dbda0c09f | ||
|
|
89b962557a | ||
|
|
5de0153df4 | ||
|
|
ed4d304cd2 | ||
|
|
48564bda8d | ||
|
|
b9d053b3cd | ||
|
|
cd258c92c3 | ||
|
|
6230d1d750 | ||
|
|
365abc6b3b | ||
|
|
79c65b3e44 | ||
|
|
6b34901d94 | ||
|
|
90693ff95e | ||
|
|
1a01c35e52 | ||
|
|
c335bc6ce7 | ||
|
|
f3ea7e9887 | ||
|
|
c13ec31163 | ||
|
|
bbbb66b489 | ||
|
|
74f16623c9 | ||
|
|
1127c43823 | ||
|
|
ea3a22e13c | ||
|
|
c0018b66f3 | ||
|
|
02e296ed75 | ||
|
|
4facf5b390 | ||
|
|
c5d11441bc | ||
|
|
96bdd7c1dd | ||
|
|
ba764c1380 | ||
|
|
c7cfde0930 | ||
|
|
13177979bb | ||
|
|
6a17a7d46c | ||
|
|
8c30b41e20 | ||
|
|
b2d1cb68db | ||
|
|
3589a6ee53 | ||
|
|
7efbed6a24 | ||
|
|
21d74f1183 | ||
|
|
d6d0098379 | ||
|
|
241bb4df78 | ||
|
|
82d8f2db98 | ||
|
|
9882244bd9 | ||
|
|
f243cbd858 | ||
|
|
d420b38329 | ||
|
|
ea2d238bd8 | ||
|
|
5234511a2f | ||
|
|
746a31e125 | ||
|
|
c45e031155 | ||
|
|
4a2b89d0b6 | ||
|
|
2a4fbf6a79 | ||
|
|
84ea68cab0 | ||
|
|
3ed5eb1ee0 | ||
|
|
d1a5b57e4d |
9
.github/DISCUSSION_TEMPLATE/general.yml
vendored
9
.github/DISCUSSION_TEMPLATE/general.yml
vendored
@@ -9,15 +9,6 @@ body:
|
|||||||
[contributing guidelines](https://github.com/cotes2020/jekyll-theme-chirpy/blob/master/docs/CONTRIBUTING.md).
|
[contributing guidelines](https://github.com/cotes2020/jekyll-theme-chirpy/blob/master/docs/CONTRIBUTING.md).
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
attributes:
|
|
||||||
label: What is the topic?
|
|
||||||
options:
|
|
||||||
- Sharing tips and tricks
|
|
||||||
- Just chatting
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Description
|
label: Description
|
||||||
|
|||||||
7
.github/DISCUSSION_TEMPLATE/ideas.yml
vendored
Normal file
7
.github/DISCUSSION_TEMPLATE/ideas.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: Please describe in detail what you want to share.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
2
.github/codeql/codeql-config.yml
vendored
Normal file
2
.github/codeql/codeql-config.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
paths-ignore:
|
||||||
|
- "assets/js"
|
||||||
15
.github/dependabot.yml
vendored
15
.github/dependabot.yml
vendored
@@ -2,20 +2,19 @@ version: 2
|
|||||||
updates:
|
updates:
|
||||||
- package-ecosystem: "bundler"
|
- package-ecosystem: "bundler"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
versioning-strategy: increase
|
|
||||||
groups:
|
|
||||||
bundler:
|
|
||||||
dependency-type: "production"
|
|
||||||
schedule:
|
schedule:
|
||||||
interval: "monthly"
|
interval: "weekly"
|
||||||
- package-ecosystem: "npm"
|
- package-ecosystem: "npm"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
versioning-strategy: increase
|
versioning-strategy: increase
|
||||||
groups:
|
groups:
|
||||||
npm:
|
npm:
|
||||||
dependency-type: "development"
|
update-types:
|
||||||
|
- "major"
|
||||||
|
- "minor"
|
||||||
|
- "patch"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "monthly"
|
interval: "weekly"
|
||||||
- package-ecosystem: "github-actions"
|
- package-ecosystem: "github-actions"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
groups:
|
groups:
|
||||||
@@ -23,4 +22,4 @@ updates:
|
|||||||
update-types:
|
update-types:
|
||||||
- "major"
|
- "major"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "monthly"
|
interval: "weekly"
|
||||||
|
|||||||
41
.github/workflows/cd.yml
vendored
41
.github/workflows/cd.yml
vendored
@@ -1,17 +1,40 @@
|
|||||||
name: CD
|
name: CD
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
|
||||||
- "v[0-9]+.[0-9]+.[0-9]+"
|
|
||||||
branches:
|
branches:
|
||||||
- docs
|
- production
|
||||||
|
tags-ignore:
|
||||||
|
- "**"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
launch:
|
release:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- run: |
|
- uses: actions/checkout@v4
|
||||||
curl -X POST -H "Accept: application/vnd.github+json" \
|
|
||||||
-H "Authorization: Bearer ${{ secrets.GH_PAT }}" \
|
- uses: ruby/setup-ruby@v1
|
||||||
https://api.github.com/repos/${{ secrets.BUILDER }}/dispatches \
|
with:
|
||||||
-d '{"event_type":"deploy", "client_payload":{"branch": "${{ github.ref_name }}"}}'
|
ruby-version: 3.3
|
||||||
|
bundler-cache: true
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: latest
|
||||||
|
|
||||||
|
- run: npm install
|
||||||
|
- run: npx semantic-release
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
GEM_HOST_API_KEY: ${{ secrets.GEM_HOST_API_KEY }}
|
||||||
|
|
||||||
|
publish:
|
||||||
|
needs: release
|
||||||
|
uses: ./.github/workflows/publish.yml
|
||||||
|
secrets:
|
||||||
|
GH_PAT: ${{ secrets.GH_PAT }}
|
||||||
|
BUILDER: ${{ secrets.BUILDER }}
|
||||||
|
|||||||
16
.github/workflows/ci.yml
vendored
16
.github/workflows/ci.yml
vendored
@@ -1,9 +1,9 @@
|
|||||||
name: "CI"
|
name: "CI"
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches-ignore:
|
branches:
|
||||||
- "production"
|
- "master"
|
||||||
- "docs"
|
- "hotfix/**"
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- ".github/**"
|
- ".github/**"
|
||||||
- "!.github/workflows/ci.yml"
|
- "!.github/workflows/ci.yml"
|
||||||
@@ -12,13 +12,15 @@ on:
|
|||||||
- "README.md"
|
- "README.md"
|
||||||
- "LICENSE"
|
- "LICENSE"
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
|
||||||
- "**"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
ruby: ["3.1", "3.2", "3.3"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -28,11 +30,13 @@ jobs:
|
|||||||
- name: Setup Ruby
|
- name: Setup Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3
|
ruby-version: ${{ matrix.ruby }}
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: latest
|
||||||
|
|
||||||
- name: Build Assets
|
- name: Build Assets
|
||||||
run: npm i && npm run build
|
run: npm i && npm run build
|
||||||
|
|||||||
14
.github/workflows/codeql.yml
vendored
14
.github/workflows/codeql.yml
vendored
@@ -2,11 +2,10 @@ name: "CodeQL"
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
paths: ["**.js"]
|
branches: ["master"]
|
||||||
|
paths: ["_javascript/**/*.js"]
|
||||||
pull_request:
|
pull_request:
|
||||||
paths: ["**.js"]
|
paths: ["_javascript/**/*.js"]
|
||||||
schedule:
|
|
||||||
- cron: "0 0 * * 5"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
analyze:
|
analyze:
|
||||||
@@ -29,16 +28,17 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: "${{ matrix.language }}"
|
languages: "${{ matrix.language }}"
|
||||||
|
config-file: .github/codeql/codeql-config.yml
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v2
|
uses: github/codeql-action/autobuild@v3
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v2
|
uses: github/codeql-action/analyze@v3
|
||||||
with:
|
with:
|
||||||
category: "/language:${{ matrix.language }}"
|
category: "/language:${{ matrix.language }}"
|
||||||
|
|||||||
4
.github/workflows/commitlint.yml
vendored
4
.github/workflows/commitlint.yml
vendored
@@ -6,6 +6,4 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
- uses: wagoid/commitlint-github-action@v6
|
||||||
fetch-depth: 0
|
|
||||||
- uses: wagoid/commitlint-github-action@v5
|
|
||||||
|
|||||||
22
.github/workflows/publish.yml
vendored
Normal file
22
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
name: Publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- docs
|
||||||
|
workflow_call:
|
||||||
|
secrets:
|
||||||
|
GH_PAT:
|
||||||
|
required: true
|
||||||
|
BUILDER:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
launch:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: |
|
||||||
|
curl -X POST -H "Accept: application/vnd.github+json" \
|
||||||
|
-H "Authorization: Bearer ${{ secrets.GH_PAT }}" \
|
||||||
|
https://api.github.com/repos/${{ secrets.BUILDER }}/dispatches \
|
||||||
|
-d '{"event_type":"deploy", "client_payload":{"branch": "${{ github.ref_name }}"}}'
|
||||||
32
.github/workflows/stale.yml
vendored
32
.github/workflows/stale.yml
vendored
@@ -8,23 +8,25 @@ permissions:
|
|||||||
issues: write
|
issues: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
STALE_LABEL: stale
|
||||||
|
EXEMPT_LABELS: "pending,planning,in progress"
|
||||||
|
MESSAGE: >
|
||||||
|
This conversation has been automatically marked as stale because it has not had recent activity.
|
||||||
|
It will be closed if no further activity occurs.
|
||||||
|
Thank you for your contributions.
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stale:
|
stale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v8
|
- uses: actions/stale@v9
|
||||||
with:
|
with:
|
||||||
days-before-stale: 30
|
# 60 days before marking issues/PRs stale
|
||||||
days-before-close: 1
|
days-before-close: -1 # does not close automatically
|
||||||
stale-issue-label: stale
|
stale-issue-label: ${{ env.STALE_LABEL }}
|
||||||
exempt-issue-labels: pending
|
exempt-issue-labels: ${{ env.EXEMPT_LABELS }}
|
||||||
stale-issue-message: >
|
stale-issue-message: ${{ env.MESSAGE }}
|
||||||
This issue has been automatically marked as stale because it has not had recent activity.
|
stale-pr-label: ${{ env.STALE_LABEL }}
|
||||||
It will be closed if no further activity occurs.
|
exempt-pr-labels: ${{ env.EXEMPT_LABELS }}
|
||||||
Thank you for your contributions.
|
stale-pr-message: ${{ env.MESSAGE }}
|
||||||
stale-pr-label: stale
|
|
||||||
exempt-pr-labels: pending
|
|
||||||
stale-pr-message: >
|
|
||||||
This PR has been automatically marked as stale because it has not had recent activity.
|
|
||||||
It will be closed if no further activity occurs.
|
|
||||||
Thank you for your contributions.
|
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup Pages
|
- name: Setup Pages
|
||||||
id: pages
|
id: pages
|
||||||
uses: actions/configure-pages@v3
|
uses: actions/configure-pages@v4
|
||||||
|
|
||||||
- name: Setup Ruby
|
- name: Setup Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3
|
ruby-version: 3.3
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
|
|
||||||
- name: Build site
|
- name: Build site
|
||||||
@@ -53,11 +53,11 @@ jobs:
|
|||||||
- name: Test site
|
- name: Test site
|
||||||
run: |
|
run: |
|
||||||
bundle exec htmlproofer _site \
|
bundle exec htmlproofer _site \
|
||||||
\-\-disable-external=true \
|
\-\-disable-external \
|
||||||
\-\-ignore-urls "/^http:\/\/127.0.0.1/,/^http:\/\/0.0.0.0/,/^http:\/\/localhost/"
|
\-\-ignore-urls "/^http:\/\/127.0.0.1/,/^http:\/\/0.0.0.0/,/^http:\/\/localhost/"
|
||||||
|
|
||||||
- name: Upload site artifact
|
- name: Upload site artifact
|
||||||
uses: actions/upload-pages-artifact@v1
|
uses: actions/upload-pages-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: "_site${{ steps.pages.outputs.base_path }}"
|
path: "_site${{ steps.pages.outputs.base_path }}"
|
||||||
|
|
||||||
@@ -70,4 +70,4 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
id: deployment
|
id: deployment
|
||||||
uses: actions/deploy-pages@v2
|
uses: actions/deploy-pages@v4
|
||||||
12
.github/workflows/style-lint.yml
vendored
12
.github/workflows/style-lint.yml
vendored
@@ -2,14 +2,10 @@ name: "Style Lint"
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches-ignore:
|
branches: ["master", "hotfix/**"]
|
||||||
- "production"
|
paths: ["_sass/**/*.scss"]
|
||||||
- "docs"
|
|
||||||
paths:
|
|
||||||
- "_sass/**/*.scss"
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths: ["_sass/**/*.scss"]
|
||||||
- "_sass/**/*.scss"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stylelint:
|
stylelint:
|
||||||
@@ -21,5 +17,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: latest
|
||||||
- run: npm i
|
- run: npm i
|
||||||
- run: npm test
|
- run: npm test
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -5,6 +5,7 @@ Gemfile.lock
|
|||||||
|
|
||||||
# Jekyll cache
|
# Jekyll cache
|
||||||
.jekyll-cache
|
.jekyll-cache
|
||||||
|
.jekyll-metadata
|
||||||
_site
|
_site
|
||||||
|
|
||||||
# RubyGems
|
# RubyGems
|
||||||
@@ -17,6 +18,9 @@ package-lock.json
|
|||||||
# IDE configurations
|
# IDE configurations
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
|
_sass/dist
|
||||||
assets/js/dist
|
assets/js/dist
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
npx --no -- commitlint -x $(npm root -g)/@commitlint/config-conventional --edit
|
npx --no -- commitlint --edit ${1}
|
||||||
|
|||||||
8
.markdownlint.json
Normal file
8
.markdownlint.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"commands-show-output": false,
|
||||||
|
"blanks-around-fences": false,
|
||||||
|
"line-length": false,
|
||||||
|
"no-inline-html": {
|
||||||
|
"allowed_elements": ["kbd", "sub"]
|
||||||
|
}
|
||||||
|
}
|
||||||
13
.vscode/extensions.json
vendored
Normal file
13
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
// Liquid tags auto-complete
|
||||||
|
"killalau.vscode-liquid-snippets",
|
||||||
|
// Liquid syntax highlighting and formatting
|
||||||
|
"Shopify.theme-check-vscode",
|
||||||
|
// Common formatter
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"foxundermoon.shell-format",
|
||||||
|
"stylelint.vscode-stylelint",
|
||||||
|
"yzhang.markdown-all-in-one"
|
||||||
|
]
|
||||||
|
}
|
||||||
27
.vscode/settings.json
vendored
Normal file
27
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
// Prettier
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"prettier.trailingComma": "none",
|
||||||
|
// Shopify Liquid
|
||||||
|
"files.associations": {
|
||||||
|
"*.html": "liquid"
|
||||||
|
},
|
||||||
|
"[markdown]": {
|
||||||
|
"editor.defaultFormatter": "yzhang.markdown-all-in-one"
|
||||||
|
},
|
||||||
|
// Formatter
|
||||||
|
"[html][liquid]": {
|
||||||
|
"editor.defaultFormatter": "Shopify.theme-check-vscode"
|
||||||
|
},
|
||||||
|
"[shellscript]": {
|
||||||
|
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||||
|
},
|
||||||
|
// Disable vscode built-in stylelint
|
||||||
|
"css.validate": false,
|
||||||
|
"scss.validate": false,
|
||||||
|
"less.validate": false,
|
||||||
|
// Stylint extension settings
|
||||||
|
"stylelint.snippet": ["css", "less", "postcss", "scss"],
|
||||||
|
"stylelint.validate": ["css", "less", "postcss", "scss"]
|
||||||
|
}
|
||||||
16
Gemfile
16
Gemfile
@@ -5,19 +5,5 @@ source "https://rubygems.org"
|
|||||||
gemspec
|
gemspec
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem "html-proofer", "~> 4.4"
|
gem "html-proofer", "~> 5.0"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
|
|
||||||
# and associated library.
|
|
||||||
platforms :mingw, :x64_mingw, :mswin, :jruby do
|
|
||||||
gem "tzinfo", ">= 1", "< 3"
|
|
||||||
gem "tzinfo-data"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Performance-booster for watching directories on Windows
|
|
||||||
gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin]
|
|
||||||
|
|
||||||
# Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem
|
|
||||||
# do not have a Java counterpart.
|
|
||||||
gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby]
|
|
||||||
|
|||||||
45
README.md
45
README.md
@@ -1,5 +1,7 @@
|
|||||||
|
<!-- markdownlint-disable-next-line -->
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
|
<!-- markdownlint-disable-next-line -->
|
||||||
# Chirpy Jekyll Theme
|
# Chirpy Jekyll Theme
|
||||||
|
|
||||||
A minimal, responsive, and feature-rich Jekyll theme for technical writing.
|
A minimal, responsive, and feature-rich Jekyll theme for technical writing.
|
||||||
@@ -10,7 +12,7 @@
|
|||||||
[][license]
|
[][license]
|
||||||
[](https://996.icu)
|
[](https://996.icu)
|
||||||
|
|
||||||
[**Live Demo →**][demo]
|
[**Live Demo** →][demo]
|
||||||
|
|
||||||
[][demo]
|
[][demo]
|
||||||
|
|
||||||
@@ -18,11 +20,7 @@
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
<details>
|
- Dark Theme
|
||||||
<summary>Click to expand/close details</summary>
|
|
||||||
|
|
||||||
|
|
||||||
- Dark / Light Theme Mode
|
|
||||||
- Localized UI language
|
- Localized UI language
|
||||||
- Pinned Posts on Home Page
|
- Pinned Posts on Home Page
|
||||||
- Hierarchical Categories
|
- Hierarchical Categories
|
||||||
@@ -32,17 +30,15 @@
|
|||||||
- Syntax Highlighting
|
- Syntax Highlighting
|
||||||
- Mathematical Expressions
|
- Mathematical Expressions
|
||||||
- Mermaid Diagrams & Flowcharts
|
- Mermaid Diagrams & Flowcharts
|
||||||
- Dark / Light Mode Images
|
- Dark Mode Images
|
||||||
- Embed Videos
|
- Embed Media
|
||||||
- Disqus / Giscus / Utterances Comments
|
- Comment Systems
|
||||||
- Built-in Search
|
- Built-in Search
|
||||||
- Atom Feeds
|
- Atom Feeds
|
||||||
- PWA
|
- PWA
|
||||||
- Google Analytics
|
- Web Analytics
|
||||||
- SEO & Performance Optimization
|
- SEO & Performance Optimization
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
To learn how to use, develop, and upgrade the project, please refer to the [Wiki][wiki].
|
To learn how to use, develop, and upgrade the project, please refer to the [Wiki][wiki].
|
||||||
@@ -55,22 +51,18 @@ For details, see the "[Contributing Guidelines][contribute-guide]".
|
|||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
This project was built primarily with the [Jekyll][jekyllrb] ecosystem,
|
### Contributors
|
||||||
[Bootstrap][bootstrap], [Font Awesome][icons], and some other [wonderful tools][lib].
|
|
||||||
The avatar and favicon design from [Clipart Max][image].
|
|
||||||
|
|
||||||
Many thanks to the [contributors][contributors] who participated in the development
|
Thanks to [all the contributors][contributors] involved in the development of the project!
|
||||||
and to the folks who reported bugs or shared ideas.
|
|
||||||
|
|
||||||
Last but not least, thanks to [JetBrains][jetbrains] for providing the _Open Source License_.
|
[][contributors]
|
||||||
|
<sub> — Made with [contrib.rocks](https://contrib.rocks)</sub>
|
||||||
|
|
||||||
## Sponsoring
|
### Third-Party Assets
|
||||||
|
|
||||||
If you like this project or have built something through it, please consider sponsoring it, and your support would be greatly appreciated.
|
This project is built on the [Jekyll][jekyllrb] ecosystem and some [great libraries][lib], and is developed using [VS Code][vscode] as well as tools provided by [JetBrains][jetbrains] under a non-commercial open-source software license.
|
||||||
|
|
||||||
[][ko-fi]
|
The avatar and favicon for the project's website are from [ClipartMAX][clipartmax].
|
||||||
[][donation]
|
|
||||||
[][donation]
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
@@ -81,14 +73,11 @@ This project is published under [MIT License][license].
|
|||||||
[codacy]: https://app.codacy.com/gh/cotes2020/jekyll-theme-chirpy/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade
|
[codacy]: https://app.codacy.com/gh/cotes2020/jekyll-theme-chirpy/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade
|
||||||
[license]: https://github.com/cotes2020/jekyll-theme-chirpy/blob/master/LICENSE
|
[license]: https://github.com/cotes2020/jekyll-theme-chirpy/blob/master/LICENSE
|
||||||
[jekyllrb]: https://jekyllrb.com/
|
[jekyllrb]: https://jekyllrb.com/
|
||||||
[bootstrap]: https://getbootstrap.com/
|
[clipartmax]: https://www.clipartmax.com/middle/m2i8b1m2K9Z5m2K9_ant-clipart-childrens-ant-cute/
|
||||||
[icons]: https://fontawesome.com/
|
|
||||||
[image]: https://www.clipartmax.com/middle/m2i8b1m2K9Z5m2K9_ant-clipart-childrens-ant-cute/
|
|
||||||
[demo]: https://cotes2020.github.io/chirpy-demo/
|
[demo]: https://cotes2020.github.io/chirpy-demo/
|
||||||
[wiki]: https://github.com/cotes2020/jekyll-theme-chirpy/wiki
|
[wiki]: https://github.com/cotes2020/jekyll-theme-chirpy/wiki
|
||||||
[contribute-guide]: https://github.com/cotes2020/jekyll-theme-chirpy/blob/master/docs/CONTRIBUTING.md
|
[contribute-guide]: https://github.com/cotes2020/jekyll-theme-chirpy/blob/master/docs/CONTRIBUTING.md
|
||||||
[contributors]: https://github.com/cotes2020/jekyll-theme-chirpy/graphs/contributors
|
[contributors]: https://github.com/cotes2020/jekyll-theme-chirpy/graphs/contributors
|
||||||
[lib]: https://github.com/cotes2020/chirpy-static-assets
|
[lib]: https://github.com/cotes2020/chirpy-static-assets
|
||||||
|
[vscode]: https://code.visualstudio.com/
|
||||||
[jetbrains]: https://www.jetbrains.com/?from=jekyll-theme-chirpy
|
[jetbrains]: https://www.jetbrains.com/?from=jekyll-theme-chirpy
|
||||||
[ko-fi]: https://ko-fi.com/coteschung/
|
|
||||||
[donation]: https://sponsor.cotes.page/
|
|
||||||
|
|||||||
65
_config.yml
65
_config.yml
@@ -44,13 +44,36 @@ social:
|
|||||||
# - https://www.facebook.com/username
|
# - https://www.facebook.com/username
|
||||||
# - https://www.linkedin.com/in/username
|
# - https://www.linkedin.com/in/username
|
||||||
|
|
||||||
google_site_verification: # fill in to your verification string
|
# Site Verification Settings
|
||||||
|
webmaster_verifications:
|
||||||
|
google: # fill in your Google verification code
|
||||||
|
bing: # fill in your Bing verification code
|
||||||
|
alexa: # fill in your Alexa verification code
|
||||||
|
yandex: # fill in your Yandex verification code
|
||||||
|
baidu: # fill in your Baidu verification code
|
||||||
|
facebook: # fill in your Facebook verification code
|
||||||
|
|
||||||
# ↑ --------------------------
|
# ↑ --------------------------
|
||||||
# The end of `jekyll-seo-tag` settings
|
# The end of `jekyll-seo-tag` settings
|
||||||
|
|
||||||
google_analytics:
|
# Web Analytics Settings
|
||||||
id: # fill in your Google Analytics ID
|
analytics:
|
||||||
|
google:
|
||||||
|
id: # fill in your Google Analytics ID
|
||||||
|
goatcounter:
|
||||||
|
id: # fill in your GoatCounter ID
|
||||||
|
umami:
|
||||||
|
id: # fill in your Umami ID
|
||||||
|
domain: # fill in your Umami domain
|
||||||
|
matomo:
|
||||||
|
id: # fill in your Matomo ID
|
||||||
|
domain: # fill in your Matomo domain
|
||||||
|
cloudflare:
|
||||||
|
id: # fill in your Cloudflare Web Analytics token
|
||||||
|
|
||||||
|
# Pageviews settings
|
||||||
|
pageviews:
|
||||||
|
provider: # now only supports 'goatcounter'
|
||||||
|
|
||||||
# Prefer color scheme setting.
|
# Prefer color scheme setting.
|
||||||
#
|
#
|
||||||
@@ -63,24 +86,29 @@ google_analytics:
|
|||||||
# light - Use the light color scheme
|
# light - Use the light color scheme
|
||||||
# dark - Use the dark color scheme
|
# dark - Use the dark color scheme
|
||||||
#
|
#
|
||||||
theme_mode: # [light|dark]
|
theme_mode: # [light | dark]
|
||||||
|
|
||||||
# The CDN endpoint for images.
|
# The CDN endpoint for media resources.
|
||||||
# Notice that once it is assigned, the CDN url
|
# Notice that once it is assigned, the CDN url
|
||||||
# will be added to all image (site avatar & posts' images) paths starting with '/'
|
# will be added to all media resources (site avatar, posts' images, audio and video files) paths starting with '/'
|
||||||
#
|
#
|
||||||
# e.g. 'https://cdn.com'
|
# e.g. 'https://cdn.com'
|
||||||
img_cdn: "https://chirpy-img.netlify.app"
|
cdn: "https://chirpy-img.netlify.app"
|
||||||
|
|
||||||
# the avatar on sidebar, support local or CORS resources
|
# the avatar on sidebar, support local or CORS resources
|
||||||
avatar: "/commons/avatar.jpg"
|
avatar: "/commons/avatar.jpg"
|
||||||
|
|
||||||
|
# The URL of the site-wide social preview image used in SEO `og:image` meta tag.
|
||||||
|
# It can be overridden by a customized `page.image` in front matter.
|
||||||
|
social_preview_image: # string, local or CORS resources
|
||||||
|
|
||||||
# boolean type, the global switch for TOC in posts.
|
# boolean type, the global switch for TOC in posts.
|
||||||
toc: true
|
toc: true
|
||||||
|
|
||||||
comments:
|
comments:
|
||||||
active: # The global switch for posts comments, e.g., 'disqus'. Keep it empty means disable
|
# Global switch for the post comment system. Keeping it empty means disabled.
|
||||||
# The active options are as follows:
|
provider: # [disqus | utterances | giscus]
|
||||||
|
# The provider options are as follows:
|
||||||
disqus:
|
disqus:
|
||||||
shortname: # fill with the Disqus shortname. › https://help.disqus.com/en/articles/1717111-what-s-a-shortname
|
shortname: # fill with the Disqus shortname. › https://help.disqus.com/en/articles/1717111-what-s-a-shortname
|
||||||
# utterances settings › https://utteranc.es/
|
# utterances settings › https://utteranc.es/
|
||||||
@@ -94,6 +122,7 @@ comments:
|
|||||||
category:
|
category:
|
||||||
category_id:
|
category_id:
|
||||||
mapping: # optional, default to 'pathname'
|
mapping: # optional, default to 'pathname'
|
||||||
|
strict: # optional, default to '0'
|
||||||
input_position: # optional, default to 'bottom'
|
input_position: # optional, default to 'bottom'
|
||||||
lang: # optional, default to the value of `site.lang`
|
lang: # optional, default to the value of `site.lang`
|
||||||
reactions_enabled: # optional, default to the value of `1`
|
reactions_enabled: # optional, default to the value of `1`
|
||||||
@@ -104,10 +133,17 @@ assets:
|
|||||||
enabled: # boolean, keep empty means false
|
enabled: # boolean, keep empty means false
|
||||||
# specify the Jekyll environment, empty means both
|
# specify the Jekyll environment, empty means both
|
||||||
# only works if `assets.self_host.enabled` is 'true'
|
# only works if `assets.self_host.enabled` is 'true'
|
||||||
env: # [development|production]
|
env: # [development | production]
|
||||||
|
|
||||||
pwa:
|
pwa:
|
||||||
enabled: true # the option for PWA feature
|
enabled: true # the option for PWA feature (installable)
|
||||||
|
cache:
|
||||||
|
enabled: true # the option for PWA offline cache
|
||||||
|
# Paths defined here will be excluded from the PWA cache.
|
||||||
|
# Usually its value is the `baseurl` of another website that
|
||||||
|
# shares the same domain name as the current website.
|
||||||
|
deny_paths:
|
||||||
|
# - "/example" # URLs match `<SITE_URL>/example/*` will not be cached by the PWA
|
||||||
|
|
||||||
paginate: 10
|
paginate: 10
|
||||||
|
|
||||||
@@ -117,6 +153,7 @@ baseurl: ""
|
|||||||
# ------------ The following options are not recommended to be modified ------------------
|
# ------------ The following options are not recommended to be modified ------------------
|
||||||
|
|
||||||
kramdown:
|
kramdown:
|
||||||
|
footnote_backlink: "↩︎"
|
||||||
syntax_highlighter: rouge
|
syntax_highlighter: rouge
|
||||||
syntax_highlighter_opts: # Rouge Options › https://github.com/jneen/rouge#full-options
|
syntax_highlighter_opts: # Rouge Options › https://github.com/jneen/rouge#full-options
|
||||||
css_class: highlight
|
css_class: highlight
|
||||||
@@ -153,10 +190,6 @@ defaults:
|
|||||||
values:
|
values:
|
||||||
layout: page
|
layout: page
|
||||||
permalink: /:title/
|
permalink: /:title/
|
||||||
- scope:
|
|
||||||
path: assets/img/favicons
|
|
||||||
values:
|
|
||||||
swcache: true
|
|
||||||
- scope:
|
- scope:
|
||||||
path: assets/js/dist
|
path: assets/js/dist
|
||||||
values:
|
values:
|
||||||
@@ -181,7 +214,7 @@ exclude:
|
|||||||
- tools
|
- tools
|
||||||
- README.md
|
- README.md
|
||||||
- LICENSE
|
- LICENSE
|
||||||
- rollup.config.js
|
- "*.config.js"
|
||||||
- package*.json
|
- package*.json
|
||||||
|
|
||||||
jekyll-archives:
|
jekyll-archives:
|
||||||
|
|||||||
18
_data/media.yml
Normal file
18
_data/media.yml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
- extension: mp3
|
||||||
|
mime_type: mpeg
|
||||||
|
- extension: mov
|
||||||
|
mime_type: quicktime
|
||||||
|
- extension: avi
|
||||||
|
mime_type: x-msvideo
|
||||||
|
- extension: mkv
|
||||||
|
mime_type: x-matroska
|
||||||
|
- extension: ogv
|
||||||
|
mime_type: ogg
|
||||||
|
- extension: weba
|
||||||
|
mime_type: webm
|
||||||
|
- extension: 3gp
|
||||||
|
mime_type: 3gpp
|
||||||
|
- extension: 3g2
|
||||||
|
mime_type: 3gpp2
|
||||||
|
- extension: mid
|
||||||
|
mime_type: midi
|
||||||
@@ -4,13 +4,6 @@ webfonts: /assets/lib/fonts/main.css
|
|||||||
|
|
||||||
# Libraries
|
# Libraries
|
||||||
|
|
||||||
jquery:
|
|
||||||
js: /assets/lib/jquery/jquery.min.js
|
|
||||||
|
|
||||||
bootstrap:
|
|
||||||
css: /assets/lib/bootstrap/bootstrap.min.css
|
|
||||||
js: /assets/lib/bootstrap/bootstrap.bundle.min.js
|
|
||||||
|
|
||||||
toc:
|
toc:
|
||||||
css: /assets/lib/tocbot/tocbot.min.css
|
css: /assets/lib/tocbot/tocbot.min.css
|
||||||
js: /assets/lib/tocbot/tocbot.min.js
|
js: /assets/lib/tocbot/tocbot.min.js
|
||||||
@@ -31,9 +24,9 @@ dayjs:
|
|||||||
relativeTime: /assets/lib/dayjs/plugin/relativeTime.min.js
|
relativeTime: /assets/lib/dayjs/plugin/relativeTime.min.js
|
||||||
localizedFormat: /assets/lib/dayjs/plugin/localizedFormat.min.js
|
localizedFormat: /assets/lib/dayjs/plugin/localizedFormat.min.js
|
||||||
|
|
||||||
magnific-popup:
|
glightbox:
|
||||||
css: /assets/lib/magnific-popup/magnific-popup.css
|
css: /assets/lib/glightbox/glightbox.min.css
|
||||||
js: /assets/lib/magnific-popup/jquery.magnific-popup.min.js
|
js: /assets/lib/glightbox/glightbox.min.js
|
||||||
|
|
||||||
lazy-polyfill:
|
lazy-polyfill:
|
||||||
css: /assets/lib/loading-attribute-polyfill/loading-attribute-polyfill.min.css
|
css: /assets/lib/loading-attribute-polyfill/loading-attribute-polyfill.min.css
|
||||||
|
|||||||
@@ -1,50 +1,47 @@
|
|||||||
# CDNs
|
# Resource Hints
|
||||||
|
resource_hints:
|
||||||
cdns:
|
|
||||||
# Google Fonts
|
|
||||||
- url: https://fonts.googleapis.com
|
- url: https://fonts.googleapis.com
|
||||||
|
links:
|
||||||
|
- rel: preconnect
|
||||||
|
- rel: dns-prefetch
|
||||||
- url: https://fonts.gstatic.com
|
- url: https://fonts.gstatic.com
|
||||||
args: crossorigin
|
links:
|
||||||
- url: https://fonts.googleapis.com
|
- rel: preconnect
|
||||||
# jsDelivr CDN
|
opts: [crossorigin]
|
||||||
|
- rel: dns-prefetch
|
||||||
- url: https://cdn.jsdelivr.net
|
- url: https://cdn.jsdelivr.net
|
||||||
|
links:
|
||||||
|
- rel: preconnect
|
||||||
|
- rel: dns-prefetch
|
||||||
|
|
||||||
# fonts
|
# Web Fonts
|
||||||
|
webfonts: https://fonts.googleapis.com/css2?family=Lato:wght@300;400&family=Source+Sans+Pro:wght@400;600;700;900&display=swap
|
||||||
webfonts: https://fonts.googleapis.com/css2?family=Lato&family=Source+Sans+Pro:wght@400;600;700;900&display=swap
|
|
||||||
|
|
||||||
# Libraries
|
# Libraries
|
||||||
|
|
||||||
jquery:
|
|
||||||
js: https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js
|
|
||||||
|
|
||||||
bootstrap:
|
|
||||||
css: https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css
|
|
||||||
js: https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js
|
|
||||||
|
|
||||||
toc:
|
toc:
|
||||||
css: https://cdn.jsdelivr.net/npm/tocbot@4.21.3/dist/tocbot.min.css
|
css: https://cdn.jsdelivr.net/npm/tocbot@4.27.20/dist/tocbot.min.css
|
||||||
js: https://cdn.jsdelivr.net/npm/tocbot@4.21.3/dist/tocbot.min.js
|
js: https://cdn.jsdelivr.net/npm/tocbot@4.27.20/dist/tocbot.min.js
|
||||||
|
|
||||||
fontawesome:
|
fontawesome:
|
||||||
css: https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.2/css/all.min.css
|
css: https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5.2/css/all.min.css
|
||||||
|
|
||||||
search:
|
search:
|
||||||
js: https://cdn.jsdelivr.net/npm/simple-jekyll-search@1.10.0/dest/simple-jekyll-search.min.js
|
js: https://cdn.jsdelivr.net/npm/simple-jekyll-search@1.10.0/dest/simple-jekyll-search.min.js
|
||||||
|
|
||||||
mermaid:
|
mermaid:
|
||||||
js: https://cdn.jsdelivr.net/npm/mermaid@10.6.0/dist/mermaid.min.js
|
js: https://cdn.jsdelivr.net/npm/mermaid@10.9.0/dist/mermaid.min.js
|
||||||
|
|
||||||
dayjs:
|
dayjs:
|
||||||
js:
|
js:
|
||||||
common: https://cdn.jsdelivr.net/npm/dayjs@1.11.10/dayjs.min.js
|
common: https://cdn.jsdelivr.net/npm/dayjs@1.11.11/dayjs.min.js
|
||||||
locale: https://cdn.jsdelivr.net/npm/dayjs@1.11.10/locale/:LOCALE.min.js
|
locale: https://cdn.jsdelivr.net/npm/dayjs@1.11.11/locale/:LOCALE.min.js
|
||||||
relativeTime: https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/relativeTime.min.js
|
relativeTime: https://cdn.jsdelivr.net/npm/dayjs@1.11.11/plugin/relativeTime.min.js
|
||||||
localizedFormat: https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/localizedFormat.min.js
|
localizedFormat: https://cdn.jsdelivr.net/npm/dayjs@1.11.11/plugin/localizedFormat.min.js
|
||||||
|
|
||||||
magnific-popup:
|
glightbox:
|
||||||
css: https://cdn.jsdelivr.net/npm/magnific-popup@1.1.0/dist/magnific-popup.min.css
|
css: https://cdn.jsdelivr.net/npm/glightbox@3.3.0/dist/css/glightbox.min.css
|
||||||
js: https://cdn.jsdelivr.net/npm/magnific-popup@1.1.0/dist/jquery.magnific-popup.min.js
|
js: https://cdn.jsdelivr.net/npm/glightbox@3.3.0/dist/js/glightbox.min.js
|
||||||
|
|
||||||
lazy-polyfill:
|
lazy-polyfill:
|
||||||
css: https://cdn.jsdelivr.net/npm/loading-attribute-polyfill@2.1.1/dist/loading-attribute-polyfill.min.css
|
css: https://cdn.jsdelivr.net/npm/loading-attribute-polyfill@2.1.1/dist/loading-attribute-polyfill.min.css
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ platforms:
|
|||||||
#
|
#
|
||||||
# - type: Weibo
|
# - type: Weibo
|
||||||
# icon: "fab fa-weibo"
|
# icon: "fab fa-weibo"
|
||||||
# link: "http://service.weibo.com/share/share.php?title=TITLE&url=URL"
|
# link: "https://service.weibo.com/share/share.php?title=TITLE&url=URL"
|
||||||
#
|
#
|
||||||
# - type: Mastodon
|
# - type: Mastodon
|
||||||
# icon: "fa-brands fa-mastodon"
|
# icon: "fa-brands fa-mastodon"
|
||||||
|
|||||||
7
_includes/analytics/cloudflare.html
Normal file
7
_includes/analytics/cloudflare.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<!-- Cloudflare Web Analytics -->
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
src="https://static.cloudflareinsights.com/beacon.min.js"
|
||||||
|
data-cf-beacon='{"token": "{{ site.analytics.cloudflare.id }}"}'
|
||||||
|
></script>
|
||||||
|
<!-- End Cloudflare Web Analytics -->
|
||||||
6
_includes/analytics/goatcounter.html
Normal file
6
_includes/analytics/goatcounter.html
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<!-- GoatCounter -->
|
||||||
|
<script
|
||||||
|
async
|
||||||
|
src="https://gc.zgo.at/count.js"
|
||||||
|
data-goatcounter="https://{{ site.analytics.goatcounter.id }}.goatcounter.com/count"
|
||||||
|
></script>
|
||||||
13
_includes/analytics/google.html
Normal file
13
_includes/analytics/google.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
|
<script defer src="https://www.googletagmanager.com/gtag/js?id={{ site.analytics.google.id }}"></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function (event) {
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag() {
|
||||||
|
dataLayer.push(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtag('js', new Date());
|
||||||
|
gtag('config', '{{ site.analytics.google.id }}');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
14
_includes/analytics/matomo.html
Normal file
14
_includes/analytics/matomo.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<!-- Matomo -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var _paq = window._paq = window._paq || [];
|
||||||
|
_paq.push(['trackPageView']);
|
||||||
|
_paq.push(['enableLinkTracking']);
|
||||||
|
(function() {
|
||||||
|
var u="//{{ site.analytics.matomo.domain }}/";
|
||||||
|
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
||||||
|
_paq.push(['setSiteId', {{ site.analytics.matomo.id }}]);
|
||||||
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||||
|
g.type='text/javascript'; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<!-- End Matomo Code -->
|
||||||
6
_includes/analytics/umami.html
Normal file
6
_includes/analytics/umami.html
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<!-- Umami -->
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
src="{{ site.analytics.umami.domain }}/script.js"
|
||||||
|
data-website-id="{{ site.analytics.umami.id }}"
|
||||||
|
></script>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- The comments switcher -->
|
<!-- The comments switcher -->
|
||||||
{% if page.comments and site.comments.active %}
|
{% if page.comments and site.comments.provider %}
|
||||||
{% capture path %}comments/{{ site.comments.active }}.html{% endcapture %}
|
{% capture path %}comments/{{ site.comments.provider }}.html{% endcapture %}
|
||||||
{% include {{ path }} %}
|
{% include {{ path }} %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
this.page.identifier = '{{ page.url }}';
|
this.page.identifier = '{{ page.url }}';
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Lazy loading */
|
{%- comment -%} Lazy loading {%- endcomment -%}
|
||||||
var disqus_observer = new IntersectionObserver(
|
var disqus_observer = new IntersectionObserver(
|
||||||
function (entries) {
|
function (entries) {
|
||||||
if (entries[0].isIntersecting) {
|
if (entries[0].isIntersecting) {
|
||||||
@@ -28,12 +28,12 @@
|
|||||||
{ threshold: [0] }
|
{ threshold: [0] }
|
||||||
);
|
);
|
||||||
|
|
||||||
disqus_observer.observe(document.querySelector('#disqus_thread'));
|
disqus_observer.observe(document.getElementById('disqus_thread'));
|
||||||
|
|
||||||
/* Auto switch theme */
|
{%- comment -%} Auto switch theme {%- endcomment -%}
|
||||||
function reloadDisqus() {
|
function reloadDisqus() {
|
||||||
if (event.source === window && event.data && event.data.direction === ModeToggle.ID) {
|
if (event.source === window && event.data && event.data.direction === ModeToggle.ID) {
|
||||||
/* Disqus hasn't been loaded */
|
{%- comment -%} Disqus hasn't been loaded {%- endcomment -%}
|
||||||
if (typeof DISQUS === 'undefined') {
|
if (typeof DISQUS === 'undefined') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.querySelector('.mode-toggle')) {
|
if (document.getElementById('mode-toggle')) {
|
||||||
window.addEventListener('message', reloadDisqus);
|
window.addEventListener('message', reloadDisqus);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
(function () {
|
(function () {
|
||||||
const origin = 'https://giscus.app';
|
const origin = 'https://giscus.app';
|
||||||
const iframe = 'iframe.giscus-frame';
|
|
||||||
const lightTheme = 'light';
|
const lightTheme = 'light';
|
||||||
const darkTheme = 'dark_dimmed';
|
const darkTheme = 'dark_dimmed';
|
||||||
|
|
||||||
@@ -25,6 +24,7 @@
|
|||||||
'data-category': '{{ site.comments.giscus.category }}',
|
'data-category': '{{ site.comments.giscus.category }}',
|
||||||
'data-category-id': '{{ site.comments.giscus.category_id }}',
|
'data-category-id': '{{ site.comments.giscus.category_id }}',
|
||||||
'data-mapping': '{{ site.comments.giscus.mapping | default: 'pathname' }}',
|
'data-mapping': '{{ site.comments.giscus.mapping | default: 'pathname' }}',
|
||||||
|
'data-strict' : '{{ site.comments.giscus.strict | default: '0' }}',
|
||||||
'data-reactions-enabled': '{{ site.comments.giscus.reactions_enabled | default: '1' }}',
|
'data-reactions-enabled': '{{ site.comments.giscus.reactions_enabled | default: '1' }}',
|
||||||
'data-emit-metadata': '0',
|
'data-emit-metadata': '0',
|
||||||
'data-theme': initTheme,
|
'data-theme': initTheme,
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
event.data &&
|
event.data &&
|
||||||
event.data.direction === ModeToggle.ID
|
event.data.direction === ModeToggle.ID
|
||||||
) {
|
) {
|
||||||
/* global theme mode changed */
|
{%- comment -%} global theme mode changed {%- endcomment -%}
|
||||||
const mode = event.data.message;
|
const mode = event.data.message;
|
||||||
const theme = mode === ModeToggle.DARK_MODE ? darkTheme : lightTheme;
|
const theme = mode === ModeToggle.DARK_MODE ? darkTheme : lightTheme;
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const giscus = document.querySelector(iframe).contentWindow;
|
const giscus = document.getElementsByClassName('giscus-frame')[0].contentWindow;
|
||||||
giscus.postMessage({ giscus: message }, origin);
|
giscus.postMessage({ giscus: message }, origin);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
(function () {
|
(function () {
|
||||||
const origin = 'https://utteranc.es';
|
const origin = 'https://utteranc.es';
|
||||||
const iframe = 'iframe.utterances-frame';
|
|
||||||
const lightTheme = 'github-light';
|
const lightTheme = 'github-light';
|
||||||
const darkTheme = 'github-dark';
|
const darkTheme = 'github-dark';
|
||||||
let initTheme = lightTheme;
|
let initTheme = lightTheme;
|
||||||
@@ -26,12 +25,12 @@
|
|||||||
addEventListener('message', (event) => {
|
addEventListener('message', (event) => {
|
||||||
let theme;
|
let theme;
|
||||||
|
|
||||||
/* credit to <https://github.com/utterance/utterances/issues/170#issuecomment-594036347> */
|
{%- comment -%} credit to <https://github.com/utterance/utterances/issues/170#issuecomment-594036347> {%- endcomment -%}
|
||||||
if (event.origin === origin) {
|
if (event.origin === origin) {
|
||||||
/* page initial */
|
{%- comment -%} page initial {%- endcomment -%}
|
||||||
theme = initTheme;
|
theme = initTheme;
|
||||||
} else if (event.source === window && event.data && event.data.direction === ModeToggle.ID) {
|
} else if (event.source === window && event.data && event.data.direction === ModeToggle.ID) {
|
||||||
/* global theme mode changed */
|
{%- comment -%} global theme mode changed {%- endcomment -%}
|
||||||
const mode = event.data.message;
|
const mode = event.data.message;
|
||||||
theme = mode === ModeToggle.DARK_MODE ? darkTheme : lightTheme;
|
theme = mode === ModeToggle.DARK_MODE ? darkTheme : lightTheme;
|
||||||
} else {
|
} else {
|
||||||
@@ -43,7 +42,7 @@
|
|||||||
theme: theme
|
theme: theme
|
||||||
};
|
};
|
||||||
|
|
||||||
const utterances = document.querySelector(iframe).contentWindow;
|
const utterances = document.getElementsByClassName('utterances-frame')[0].contentWindow;
|
||||||
utterances.postMessage(message, origin);
|
utterances.postMessage(message, origin);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
35
_includes/embed/audio.html
Normal file
35
_includes/embed/audio.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{% assign src = include.src | strip %}
|
||||||
|
{% assign title = include.title | strip %}
|
||||||
|
{% assign types = include.types | default: '' | strip | split: '|' %}
|
||||||
|
|
||||||
|
{% unless src contains '://' %}
|
||||||
|
{%- capture src -%}
|
||||||
|
{% include media-url.html src=src subpath=page.media_subpath %}
|
||||||
|
{%- endcapture -%}
|
||||||
|
{% endunless %}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<audio class="embed-audio" controls>
|
||||||
|
{% assign extension = src | split: '.' | last %}
|
||||||
|
{% assign types = extension | concat: types %}
|
||||||
|
|
||||||
|
{% assign ext_size = extension | size %}
|
||||||
|
{% assign src_size = src | size %}
|
||||||
|
{% assign slice_size = src_size | minus: ext_size %}
|
||||||
|
|
||||||
|
{% assign filepath = src | slice: 0, slice_size %}
|
||||||
|
|
||||||
|
{% for type in types %}
|
||||||
|
{% assign src = filepath | append: type %}
|
||||||
|
{% assign media_item = site.data.media | find: 'extension', type %}
|
||||||
|
{% assign mime_type = media_item.mime_type | default: type %}
|
||||||
|
<source src="{{ src }}" type="audio/{{ mime_type }}">
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
Your browser does not support the audio tag. Here is a
|
||||||
|
<a href="{{ src | strip }}">link to the audio file</a> instead.
|
||||||
|
</audio>
|
||||||
|
{% if title %}
|
||||||
|
<em>{{ title }}</em>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
9
_includes/embed/bilibili.html
Normal file
9
_includes/embed/bilibili.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<iframe
|
||||||
|
class="embed-video"
|
||||||
|
loading="lazy"
|
||||||
|
src="https://player.bilibili.com/player.html?bvid={{ include.id }}"
|
||||||
|
scrolling="no"
|
||||||
|
frameborder="0"
|
||||||
|
framespacing="0"
|
||||||
|
allowfullscreen="true"
|
||||||
|
></iframe>
|
||||||
59
_includes/embed/video.html
Normal file
59
_includes/embed/video.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
{% assign video_url = include.src %}
|
||||||
|
{% assign title = include.title %}
|
||||||
|
{% assign poster_url = include.poster %}
|
||||||
|
{% assign types = include.types | default: '' | strip | split: '|' %}
|
||||||
|
|
||||||
|
{% unless video_url contains '://' %}
|
||||||
|
{%- capture video_url -%}
|
||||||
|
{% include media-url.html src=video_url subpath=page.media_subpath %}
|
||||||
|
{%- endcapture -%}
|
||||||
|
{% endunless %}
|
||||||
|
|
||||||
|
{% if poster_url %}
|
||||||
|
{% unless poster_url contains '://' %}
|
||||||
|
{%- capture poster_url -%}
|
||||||
|
{% include media-url.html src=poster_url subpath=page.media_subpath %}
|
||||||
|
{%- endcapture -%}
|
||||||
|
{% endunless %}
|
||||||
|
{% assign poster = 'poster="' | append: poster_url | append: '"' %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% assign attributes = 'controls' %}
|
||||||
|
|
||||||
|
{% if include.autoplay %}
|
||||||
|
{% assign attributes = attributes | append: ' ' | append: 'autoplay' %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if include.loop %}
|
||||||
|
{% assign attributes = attributes | append: ' ' | append: 'loop' %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if include.muted %}
|
||||||
|
{% assign attributes = attributes | append: ' ' | append: 'muted' %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<video class="embed-video file" {{ poster }} {{ attributes }}>
|
||||||
|
{% assign extension = video_url | split: '.' | last %}
|
||||||
|
{% assign types = extension | concat: types %}
|
||||||
|
|
||||||
|
{% assign ext_size = extension | size %}
|
||||||
|
{% assign src_size = video_url | size %}
|
||||||
|
{% assign slice_size = src_size | minus: ext_size %}
|
||||||
|
|
||||||
|
{% assign filepath = video_url | slice: 0, slice_size %}
|
||||||
|
|
||||||
|
{% for type in types %}
|
||||||
|
{% assign src = filepath | append: type %}
|
||||||
|
{% assign media_item = site.data.media | find: 'extension', type %}
|
||||||
|
{% assign mime_type = media_item.mime_type | default: type %}
|
||||||
|
<source src="{{ src }}" type="video/{{ mime_type }}">
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
Your browser does not support the video tag. Here is a
|
||||||
|
<a href="{{ video_url | strip }}">link to the video file</a> instead.
|
||||||
|
</video>
|
||||||
|
{% if title %}
|
||||||
|
<em>{{ title }}</em>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<iframe
|
<iframe
|
||||||
class="embed-video youtube"
|
class="embed-video"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
src="https://www.youtube.com/embed/{{ include.id }}"
|
src="https://www.youtube.com/embed/{{ include.id }}"
|
||||||
title="YouTube video player"
|
title="YouTube video player"
|
||||||
|
|||||||
@@ -8,7 +8,9 @@
|
|||||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ favicon_path }}/apple-touch-icon.png">
|
<link rel="apple-touch-icon" sizes="180x180" href="{{ favicon_path }}/apple-touch-icon.png">
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ favicon_path }}/favicon-32x32.png">
|
<link rel="icon" type="image/png" sizes="32x32" href="{{ favicon_path }}/favicon-32x32.png">
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="{{ favicon_path }}/favicon-16x16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="{{ favicon_path }}/favicon-16x16.png">
|
||||||
<link rel="manifest" href="{{ favicon_path }}/site.webmanifest">
|
{% if site.pwa.enabled %}
|
||||||
|
<link rel="manifest" href="{{ favicon_path }}/site.webmanifest">
|
||||||
|
{% endif %}
|
||||||
<link rel="shortcut icon" href="{{ favicon_path }}/favicon.ico">
|
<link rel="shortcut icon" href="{{ favicon_path }}/favicon.ico">
|
||||||
<meta name="apple-mobile-web-app-title" content="{{ site.title }}">
|
<meta name="apple-mobile-web-app-title" content="{{ site.title }}">
|
||||||
<meta name="application-name" content="{{ site.title }}">
|
<meta name="application-name" content="{{ site.title }}">
|
||||||
|
|||||||
@@ -8,9 +8,15 @@
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
{{ '©' }}
|
{{- '©' }}
|
||||||
<time>{{ 'now' | date: '%Y' }}</time>
|
<time>{{ 'now' | date: '%Y' }}</time>
|
||||||
<a href="{{ site.social.links[0] }}">{{ site.social.name }}</a>.
|
|
||||||
|
{% if site.social.links %}
|
||||||
|
<a href="{{ site.social.links[0] }}">{{ site.social.name }}</a>.
|
||||||
|
{% else %}
|
||||||
|
<em class="fst-normal">{{ site.social.name }}</em>.
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if site.data.locales[include.lang].copyright.brief %}
|
{% if site.data.locales[include.lang].copyright.brief %}
|
||||||
<span
|
<span
|
||||||
data-bs-toggle="tooltip"
|
data-bs-toggle="tooltip"
|
||||||
@@ -28,7 +34,14 @@
|
|||||||
{%- endcapture -%}
|
{%- endcapture -%}
|
||||||
|
|
||||||
{%- capture _theme -%}
|
{%- capture _theme -%}
|
||||||
<a href="https://github.com/cotes2020/jekyll-theme-chirpy" target="_blank" rel="noopener">Chirpy</a>
|
<a
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
data-bs-placement="top"
|
||||||
|
title="v{{ theme.version }}"
|
||||||
|
href="https://github.com/cotes2020/jekyll-theme-chirpy"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>Chirpy</a>
|
||||||
{%- endcapture -%}
|
{%- endcapture -%}
|
||||||
|
|
||||||
{{ site.data.locales[include.lang].meta | replace: ':PLATFORM', _platform | replace: ':THEME', _theme }}
|
{{ site.data.locales[include.lang].meta | replace: ':PLATFORM', _platform | replace: ':THEME', _theme }}
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
<!--
|
|
||||||
The GA snippet
|
|
||||||
-->
|
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
|
||||||
<script defer src="https://www.googletagmanager.com/gtag/js?id={{ site.google_analytics.id }}"></script>
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function(event) {
|
|
||||||
window.dataLayer = window.dataLayer || [];
|
|
||||||
function gtag(){dataLayer.push(arguments);}
|
|
||||||
|
|
||||||
gtag('js', new Date());
|
|
||||||
gtag('config', '{{ site.google_analytics.id }}');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
<!-- The Head -->
|
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#f7f7f7">
|
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#f7f7f7">
|
||||||
@@ -11,29 +9,43 @@
|
|||||||
content="width=device-width, user-scalable=no initial-scale=1, shrink-to-fit=no, viewport-fit=cover"
|
content="width=device-width, user-scalable=no initial-scale=1, shrink-to-fit=no, viewport-fit=cover"
|
||||||
>
|
>
|
||||||
|
|
||||||
{% capture seo_tags %}
|
{%- capture seo_tags -%}
|
||||||
{% seo title=false %}
|
{% seo title=false %}
|
||||||
{% endcapture %}
|
{%- endcapture -%}
|
||||||
|
|
||||||
|
<!-- Setup Open Graph image -->
|
||||||
|
|
||||||
{% if page.image %}
|
{% if page.image %}
|
||||||
{% assign img = page.image.path | default: page.image %}
|
{% assign src = page.image.path | default: page.image %}
|
||||||
|
|
||||||
{% unless img contains '://' %}
|
{% unless src contains '://' %}
|
||||||
{% assign img_path = page.img_path | append: '/' | append: img | replace: '//', '/' %}
|
{%- capture img_url -%}
|
||||||
{% capture target %}"{{ img | absolute_url }}"{% endcapture %}
|
{% include media-url.html src=src subpath=page.media_subpath absolute=true %}
|
||||||
|
{%- endcapture -%}
|
||||||
|
|
||||||
{% if site.img_cdn contains '//' %}
|
{%- capture old_url -%}{{ src | absolute_url }}{%- endcapture -%}
|
||||||
<!-- it's a cross-origin URL -->
|
{%- capture new_url -%}{{ img_url }}{%- endcapture -%}
|
||||||
{% capture replacement %}"{{ site.img_cdn }}{{ img_path }}"{% endcapture %}
|
|
||||||
{% else %}
|
|
||||||
<!-- it's a local file path -->
|
|
||||||
{%- capture replacement -%}
|
|
||||||
"{{ site.img_cdn | append: '/' | append: img_path | replace: '//', '/' | absolute_url }}"
|
|
||||||
{%- endcapture -%}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% assign seo_tags = seo_tags | replace: target, replacement %}
|
{% assign seo_tags = seo_tags | replace: old_url, new_url %}
|
||||||
{% endunless %}
|
{% endunless %}
|
||||||
|
|
||||||
|
{% elsif site.social_preview_image %}
|
||||||
|
{%- capture img_url -%}
|
||||||
|
{% include media-url.html src=site.social_preview_image absolute=true %}
|
||||||
|
{%- endcapture -%}
|
||||||
|
|
||||||
|
{%- capture og_image -%}
|
||||||
|
<meta property="og:image" content="{{ img_url }}" />
|
||||||
|
{%- endcapture -%}
|
||||||
|
|
||||||
|
{%- capture twitter_image -%}
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta property="twitter:image" content="{{ img_url }}" />
|
||||||
|
{%- endcapture -%}
|
||||||
|
|
||||||
|
{% assign old_meta_clip = '<meta name="twitter:card" content="summary" />' %}
|
||||||
|
{% assign new_meta_clip = og_image | append: twitter_image %}
|
||||||
|
{% assign seo_tags = seo_tags | replace: old_meta_clip, new_meta_clip %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{{ seo_tags }}
|
{{ seo_tags }}
|
||||||
@@ -47,34 +59,30 @@
|
|||||||
|
|
||||||
{% include_cached favicons.html %}
|
{% include_cached favicons.html %}
|
||||||
|
|
||||||
{% if site.resources.ignore_env != jekyll.environment and site.resources.self_hosted %}
|
<!-- Resource Hints -->
|
||||||
<link href="{{ site.data.origin[type].webfonts | relative_url }}" rel="stylesheet">
|
{% unless site.assets.self_host.enabled %}
|
||||||
|
{% for hint in site.data.origin.cors.resource_hints %}
|
||||||
{% else %}
|
{% for link in hint.links %}
|
||||||
{% for cdn in site.data.origin[type].cdns %}
|
<link rel="{{ link.rel }}" href="{{ hint.url }}" {{ link.opts | join: ' ' }}>
|
||||||
<link rel="preconnect" href="{{ cdn.url }}" {{ cdn.args }}>
|
{% endfor %}
|
||||||
<link rel="dns-prefetch" href="{{ cdn.url }}" {{ cdn.args }}>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% endunless %}
|
||||||
<link rel="stylesheet" href="{{ site.data.origin[type].webfonts | relative_url }}">
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- GA -->
|
|
||||||
{% if jekyll.environment == 'production' and site.google_analytics.id != empty and site.google_analytics.id %}
|
|
||||||
<link rel="preconnect" href="https://www.google-analytics.com" crossorigin="use-credentials">
|
|
||||||
<link rel="dns-prefetch" href="https://www.google-analytics.com">
|
|
||||||
|
|
||||||
<link rel="preconnect" href="https://www.googletagmanager.com" crossorigin="anonymous">
|
|
||||||
<link rel="dns-prefetch" href="https://www.googletagmanager.com">
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Bootstrap -->
|
<!-- Bootstrap -->
|
||||||
<link rel="stylesheet" href="{{ site.data.origin[type].bootstrap.css | relative_url}}">
|
{% unless jekyll.environment == 'production' %}
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
|
||||||
|
{% endunless %}
|
||||||
|
|
||||||
<!-- Font Awesome -->
|
<!-- Theme style -->
|
||||||
|
<link rel="stylesheet" href="{{ '/assets/css/:THEME.css' | replace: ':THEME', site.theme | relative_url }}">
|
||||||
|
|
||||||
|
<!-- Web Font -->
|
||||||
|
<link rel="stylesheet" href="{{ site.data.origin[type].webfonts | relative_url }}">
|
||||||
|
|
||||||
|
<!-- Font Awesome Icons -->
|
||||||
<link rel="stylesheet" href="{{ site.data.origin[type].fontawesome.css | relative_url }}">
|
<link rel="stylesheet" href="{{ site.data.origin[type].fontawesome.css | relative_url }}">
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{ '/assets/css/:THEME.css' | replace: ':THEME', site.theme | relative_url }}">
|
<!-- 3rd-party Dependencies -->
|
||||||
|
|
||||||
{% if site.toc and page.toc %}
|
{% if site.toc and page.toc %}
|
||||||
<link rel="stylesheet" href="{{ site.data.origin[type].toc.css | relative_url }}">
|
<link rel="stylesheet" href="{{ site.data.origin[type].toc.css | relative_url }}">
|
||||||
@@ -85,8 +93,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if page.layout == 'page' or page.layout == 'post' %}
|
{% if page.layout == 'page' or page.layout == 'post' %}
|
||||||
<!-- Manific Popup -->
|
<!-- Image Popup -->
|
||||||
<link rel="stylesheet" href="{{ site.data.origin[type].magnific-popup.css | relative_url }}">
|
<link rel="stylesheet" href="{{ site.data.origin[type].glightbox.css | relative_url }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- JavaScript -->
|
<!-- JavaScript -->
|
||||||
|
|||||||
@@ -2,15 +2,12 @@
|
|||||||
|
|
||||||
<!-- commons -->
|
<!-- commons -->
|
||||||
|
|
||||||
{% assign urls = site.data.origin[type].jquery.js
|
{% assign urls = site.data.origin[type].search.js %}
|
||||||
| append: ','
|
|
||||||
| append: site.data.origin[type].bootstrap.js
|
|
||||||
| append: ','
|
|
||||||
| append: site.data.origin[type].search.js
|
|
||||||
%}
|
|
||||||
|
|
||||||
<!-- layout specified -->
|
<!-- layout specified -->
|
||||||
|
|
||||||
|
{% assign js_dist = '/assets/js/dist/' %}
|
||||||
|
|
||||||
{% if page.layout == 'post' or page.layout == 'page' or page.layout == 'home' %}
|
{% if page.layout == 'post' or page.layout == 'page' or page.layout == 'home' %}
|
||||||
{% assign urls = urls | append: ',' | append: site.data.origin[type]['lazy-polyfill'].js %}
|
{% assign urls = urls | append: ',' | append: site.data.origin[type]['lazy-polyfill'].js %}
|
||||||
|
|
||||||
@@ -18,7 +15,7 @@
|
|||||||
<!-- image lazy-loading & popup & clipboard -->
|
<!-- image lazy-loading & popup & clipboard -->
|
||||||
{% assign urls = urls
|
{% assign urls = urls
|
||||||
| append: ','
|
| append: ','
|
||||||
| append: site.data.origin[type]['magnific-popup'].js
|
| append: site.data.origin[type].glightbox.js
|
||||||
| append: ','
|
| append: ','
|
||||||
| append: site.data.origin[type].clipboard.js
|
| append: site.data.origin[type].clipboard.js
|
||||||
%}
|
%}
|
||||||
@@ -31,7 +28,7 @@
|
|||||||
or page.layout == 'category'
|
or page.layout == 'category'
|
||||||
or page.layout == 'tag'
|
or page.layout == 'tag'
|
||||||
%}
|
%}
|
||||||
{% assign locale = site.lang | split: '-' | first %}
|
{% assign locale = include.lang | split: '-' | first %}
|
||||||
|
|
||||||
{% assign urls = urls
|
{% assign urls = urls
|
||||||
| append: ','
|
| append: ','
|
||||||
@@ -65,42 +62,46 @@
|
|||||||
{% assign js = 'commons' %}
|
{% assign js = 'commons' %}
|
||||||
{% endcase %}
|
{% endcase %}
|
||||||
|
|
||||||
{% capture script %}/assets/js/dist/{{ js }}.min.js{% endcapture %}
|
{% capture script %}{{ js_dist }}{{ js }}.min.js{% endcapture %}
|
||||||
<script defer src="{{ script | relative_url }}"></script>
|
<script src="{{ script | relative_url }}"></script>
|
||||||
|
|
||||||
{% if page.math %}
|
{% if page.math %}
|
||||||
<!-- MathJax -->
|
<!-- MathJax -->
|
||||||
<script>
|
<script src="{{ '/assets/js/data/mathjax.js' | relative_url }}"></script>
|
||||||
/* see: <https://docs.mathjax.org/en/latest/options/input/tex.html#tex-options> */
|
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=es6"></script>
|
||||||
MathJax = {
|
|
||||||
tex: {
|
|
||||||
/* start/end delimiter pairs for in-line math */
|
|
||||||
inlineMath: [
|
|
||||||
['$', '$'],
|
|
||||||
['\\(', '\\)']
|
|
||||||
],
|
|
||||||
/* start/end delimiter pairs for display math */
|
|
||||||
displayMath: [
|
|
||||||
['$$', '$$'],
|
|
||||||
['\\[', '\\]']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
|
|
||||||
<script id="MathJax-script" async src="{{ site.data.origin[type].mathjax.js | relative_url }}"></script>
|
<script id="MathJax-script" async src="{{ site.data.origin[type].mathjax.js | relative_url }}"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Pageviews -->
|
||||||
|
{% if page.layout == 'post' %}
|
||||||
|
{% assign provider = site.pageviews.provider %}
|
||||||
|
|
||||||
|
{% if provider and provider != empty %}
|
||||||
|
{% case provider %}
|
||||||
|
{% when 'goatcounter' %}
|
||||||
|
{% if site.analytics[provider].id != empty and site.analytics[provider].id %}
|
||||||
|
{% include pageviews/{{ provider }}.html %}
|
||||||
|
{% endif %}
|
||||||
|
{% endcase %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if page.mermaid %}
|
||||||
|
{% include mermaid.html %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if jekyll.environment == 'production' %}
|
{% if jekyll.environment == 'production' %}
|
||||||
<!-- PWA -->
|
<!-- PWA -->
|
||||||
{% if site.pwa.enabled %}
|
{% if site.pwa.enabled %}
|
||||||
<script defer src="{{ '/app.js' | relative_url }}"></script>
|
<script defer src="{{ 'app.min.js' | prepend: js_dist | relative_url }}"></script>
|
||||||
{% else %}
|
|
||||||
<script defer src="{{ '/unregister.js' | relative_url }}"></script>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- GA -->
|
<!-- Web Analytics -->
|
||||||
{% if site.google_analytics.id != empty and site.google_analytics.id %}
|
{% for analytics in site.analytics %}
|
||||||
{% include google-analytics.html %}
|
{% capture str %}{{ analytics }}{% endcapture %}
|
||||||
{% endif %}
|
{% assign type = str | split: '{' | first %}
|
||||||
|
{% if site.analytics[type].id and site.analytics[type].id != empty %}
|
||||||
|
{% include analytics/{{ type }}.html %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
{% comment %}
|
{% comment %}
|
||||||
Detect appearance language and return it through variable "lang"
|
Detect appearance language and return it through variable "lang"
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
{% if site.data.locales[site.lang] %}
|
{% if site.data.locales[page.lang] %}
|
||||||
|
{% assign lang = page.lang %}
|
||||||
|
{% elsif site.data.locales[site.lang] %}
|
||||||
{% assign lang = site.lang %}
|
{% assign lang = site.lang %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% assign lang = 'en' %}
|
{% assign lang = 'en' %}
|
||||||
|
|||||||
37
_includes/media-url.html
Normal file
37
_includes/media-url.html
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{%- comment -%}
|
||||||
|
Generate media resource final URL based on `site.cdn`, `page.media_subpath`
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
src - required, basic media resources path
|
||||||
|
subpath - optional, relative path of media resources
|
||||||
|
absolute - optional, boolean, if true, generate absolute URL
|
||||||
|
|
||||||
|
Return:
|
||||||
|
media resources URL
|
||||||
|
{%- endcomment -%}
|
||||||
|
|
||||||
|
{% assign url = include.src %}
|
||||||
|
|
||||||
|
{%- if url -%}
|
||||||
|
{% unless url contains ':' %}
|
||||||
|
{%- comment -%} Add media resources subpath prefix {%- endcomment -%}
|
||||||
|
{% assign url = include.subpath | default: '' | append: '/' | append: url %}
|
||||||
|
|
||||||
|
{%- comment -%} Prepend CND URL {%- endcomment -%}
|
||||||
|
{% if site.cdn %}
|
||||||
|
{% assign url = site.cdn | append: '/' | append: url %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% assign url = url | replace: '///', '/' | replace: '//', '/' | replace: ':/', '://' %}
|
||||||
|
|
||||||
|
{% unless url contains '://' %}
|
||||||
|
{% if include.absolute %}
|
||||||
|
{% assign url = site.url | append: site.baseurl | append: url %}
|
||||||
|
{% else %}
|
||||||
|
{% assign url = site.baseurl | append: url %}
|
||||||
|
{% endif %}
|
||||||
|
{% endunless %}
|
||||||
|
{% endunless %}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
{{- url -}}
|
||||||
@@ -1,29 +1,33 @@
|
|||||||
<!-- mermaid-js loader -->
|
<!-- mermaid-js loader -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
(function () {
|
function updateMermaid(event) {
|
||||||
function updateMermaid(event) {
|
if (event.source === window && event.data && event.data.direction === ModeToggle.ID) {
|
||||||
if (event.source === window && event.data && event.data.direction === ModeToggle.ID) {
|
const mode = event.data.message;
|
||||||
const mode = event.data.message;
|
|
||||||
|
|
||||||
if (typeof mermaid === 'undefined') {
|
if (typeof mermaid === 'undefined') {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
let expectedTheme = mode === ModeToggle.DARK_MODE ? 'dark' : 'default';
|
|
||||||
let config = { theme: expectedTheme };
|
|
||||||
|
|
||||||
/* Re-render the SVG › <https://github.com/mermaid-js/mermaid/issues/311#issuecomment-332557344> */
|
|
||||||
$('.mermaid').each(function () {
|
|
||||||
let svgCode = $(this).prev().children().html();
|
|
||||||
$(this).removeAttr('data-processed');
|
|
||||||
$(this).html(svgCode);
|
|
||||||
});
|
|
||||||
|
|
||||||
mermaid.initialize(config);
|
|
||||||
mermaid.init(undefined, '.mermaid');
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
let expectedTheme = mode === ModeToggle.DARK_MODE ? 'dark' : 'default';
|
||||||
|
let config = { theme: expectedTheme };
|
||||||
|
|
||||||
|
{%- comment -%}
|
||||||
|
Re-render the SVG › <https://github.com/mermaid-js/mermaid/issues/311#issuecomment-332557344>
|
||||||
|
{%- endcomment -%}
|
||||||
|
const mermaidList = document.getElementsByClassName('mermaid');
|
||||||
|
|
||||||
|
[...mermaidList].forEach((elem) => {
|
||||||
|
const svgCode = elem.previousSibling.children.item(0).innerHTML;
|
||||||
|
elem.innerHTML = svgCode;
|
||||||
|
elem.removeAttribute('data-processed');
|
||||||
|
});
|
||||||
|
|
||||||
|
mermaid.initialize(config);
|
||||||
|
mermaid.init(undefined, '.mermaid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(function () {
|
||||||
let initTheme = 'default';
|
let initTheme = 'default';
|
||||||
const html = document.documentElement;
|
const html = document.documentElement;
|
||||||
|
|
||||||
@@ -35,15 +39,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mermaidConf = {
|
let mermaidConf = {
|
||||||
theme: initTheme /* <default|dark|forest|neutral> */
|
theme: initTheme {%- comment -%} <default | dark | forest | neutral> {%- endcomment -%}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Create mermaid tag */
|
{%- comment -%} Create mermaid tag {%- endcomment -%}
|
||||||
document.querySelectorAll('pre>code.language-mermaid').forEach((elem) => {
|
const basicList = document.getElementsByClassName('language-mermaid');
|
||||||
|
[...basicList].forEach((elem) => {
|
||||||
const svgCode = elem.textContent;
|
const svgCode = elem.textContent;
|
||||||
const backup = elem.parentElement;
|
const backup = elem.parentElement;
|
||||||
backup.classList.add('unloaded');
|
backup.classList.add('d-none');
|
||||||
/* create mermaid node */
|
{%- comment -%} create mermaid node {%- endcomment -%}
|
||||||
let mermaid = document.createElement('pre');
|
let mermaid = document.createElement('pre');
|
||||||
mermaid.classList.add('mermaid');
|
mermaid.classList.add('mermaid');
|
||||||
const text = document.createTextNode(svgCode);
|
const text = document.createTextNode(svgCode);
|
||||||
@@ -52,7 +57,6 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
mermaid.initialize(mermaidConf);
|
mermaid.initialize(mermaidConf);
|
||||||
|
|
||||||
window.addEventListener('message', updateMermaid);
|
window.addEventListener('message', updateMermaid);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -19,45 +19,32 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
if (this.hasMode) {
|
|
||||||
if (this.isDarkMode) {
|
|
||||||
if (!this.isSysDarkPrefer) {
|
|
||||||
this.setDark();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.isSysDarkPrefer) {
|
|
||||||
this.setLight();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
/* always follow the system prefers */
|
{%- comment -%} always follow the system prefers {%- endcomment -%}
|
||||||
this.sysDarkPrefers.addEventListener('change', () => {
|
this.sysDarkPrefers.addEventListener('change', () => {
|
||||||
if (self.hasMode) {
|
if (self.hasMode) {
|
||||||
if (self.isDarkMode) {
|
|
||||||
if (!self.isSysDarkPrefer) {
|
|
||||||
self.setDark();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (self.isSysDarkPrefer) {
|
|
||||||
self.setLight();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.clearMode();
|
self.clearMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.notify();
|
self.notify();
|
||||||
});
|
});
|
||||||
} /* constructor() */
|
|
||||||
|
if (!this.hasMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isDarkMode) {
|
||||||
|
this.setDark();
|
||||||
|
} else {
|
||||||
|
this.setLight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get sysDarkPrefers() {
|
get sysDarkPrefers() {
|
||||||
return window.matchMedia('(prefers-color-scheme: dark)');
|
return window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
}
|
}
|
||||||
|
|
||||||
get isSysDarkPrefer() {
|
get isPreferDark() {
|
||||||
return this.sysDarkPrefers.matches;
|
return this.sysDarkPrefers.matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,10 +52,6 @@
|
|||||||
return this.mode === ModeToggle.DARK_MODE;
|
return this.mode === ModeToggle.DARK_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isLightMode() {
|
|
||||||
return this.mode === ModeToggle.LIGHT_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
get hasMode() {
|
get hasMode() {
|
||||||
return this.mode != null;
|
return this.mode != null;
|
||||||
}
|
}
|
||||||
@@ -77,12 +60,12 @@
|
|||||||
return sessionStorage.getItem(ModeToggle.MODE_KEY);
|
return sessionStorage.getItem(ModeToggle.MODE_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get the current mode on screen */
|
{%- comment -%} get the current mode on screen {%- endcomment -%}
|
||||||
get modeStatus() {
|
get modeStatus() {
|
||||||
if (this.isDarkMode || (!this.hasMode && this.isSysDarkPrefer)) {
|
if (this.hasMode) {
|
||||||
return ModeToggle.DARK_MODE;
|
return this.mode;
|
||||||
} else {
|
} else {
|
||||||
return ModeToggle.LIGHT_MODE;
|
return this.isPreferDark ? ModeToggle.DARK_MODE : ModeToggle.LIGHT_MODE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +84,9 @@
|
|||||||
sessionStorage.removeItem(ModeToggle.MODE_KEY);
|
sessionStorage.removeItem(ModeToggle.MODE_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Notify another plugins that the theme mode has changed */
|
{%- comment -%}
|
||||||
|
Notify another plugins that the theme mode has changed
|
||||||
|
{%- endcomment -%}
|
||||||
notify() {
|
notify() {
|
||||||
window.postMessage(
|
window.postMessage(
|
||||||
{
|
{
|
||||||
@@ -114,21 +99,9 @@
|
|||||||
|
|
||||||
flipMode() {
|
flipMode() {
|
||||||
if (this.hasMode) {
|
if (this.hasMode) {
|
||||||
if (this.isSysDarkPrefer) {
|
this.clearMode();
|
||||||
if (this.isLightMode) {
|
|
||||||
this.clearMode();
|
|
||||||
} else {
|
|
||||||
this.setLight();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.isDarkMode) {
|
|
||||||
this.clearMode();
|
|
||||||
} else {
|
|
||||||
this.setDark();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (this.isSysDarkPrefer) {
|
if (this.isPreferDark) {
|
||||||
this.setLight();
|
this.setLight();
|
||||||
} else {
|
} else {
|
||||||
this.setDark();
|
this.setDark();
|
||||||
@@ -136,8 +109,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.notify();
|
this.notify();
|
||||||
} /* flipMode() */
|
}
|
||||||
} /* ModeToggle */
|
}
|
||||||
|
|
||||||
const modeToggle = new ModeToggle();
|
const modeToggle = new ModeToggle();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
19
_includes/pageviews/goatcounter.html
Normal file
19
_includes/pageviews/goatcounter.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<!-- Display GoatCounter pageviews -->
|
||||||
|
<script>
|
||||||
|
let pv = document.getElementById('pageviews');
|
||||||
|
|
||||||
|
if (pv !== null) {
|
||||||
|
const uri = location.pathname.replace(/\/$/, '');
|
||||||
|
const url = `https://{{ site.analytics.goatcounter.id }}.goatcounter.com/counter/${encodeURIComponent(uri)}.json`;
|
||||||
|
|
||||||
|
fetch(url)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
const count = data.count.replace(/\s/g, '');
|
||||||
|
pv.innerText = new Intl.NumberFormat().format(count);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
pv.innerText = '1';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
16
_includes/post-description.html
Normal file
16
_includes/post-description.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{%- comment -%}
|
||||||
|
Get post description or generate it from the post content.
|
||||||
|
{%- endcomment -%}
|
||||||
|
|
||||||
|
{%- assign max_length = include.max_length | default: 200 -%}
|
||||||
|
|
||||||
|
{%- capture description -%}
|
||||||
|
{%- if post.description -%}
|
||||||
|
{{- post.description -}}
|
||||||
|
{%- else -%}
|
||||||
|
{%- include no-linenos.html content=post.content -%}
|
||||||
|
{{- content | markdownify | strip_html -}}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endcapture -%}
|
||||||
|
|
||||||
|
{{- description | strip | truncate: max_length | escape -}}
|
||||||
@@ -48,23 +48,6 @@
|
|||||||
{% assign _img_content = null %}
|
{% assign _img_content = null %}
|
||||||
{% assign _img_snippets = _content | split: IMG_TAG %}
|
{% assign _img_snippets = _content | split: IMG_TAG %}
|
||||||
|
|
||||||
<!-- CDN URL -->
|
|
||||||
{% if site.img_cdn %}
|
|
||||||
{% if site.img_cdn contains '//' %}
|
|
||||||
{% assign _path_prefix = site.img_cdn %}
|
|
||||||
{% else %}
|
|
||||||
{% assign _path_prefix = site.img_cdn | relative_url %}
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
{% assign _path_prefix = site.baseurl %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Add image path -->
|
|
||||||
{% if page.img_path %}
|
|
||||||
{% assign _path = page.img_path | append: '/' | replace: '//', '/' %}
|
|
||||||
{% assign _path_prefix = _path_prefix | append: _path %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% for _img_snippet in _img_snippets %}
|
{% for _img_snippet in _img_snippets %}
|
||||||
{% if forloop.first %}
|
{% if forloop.first %}
|
||||||
{% assign _img_content = _img_snippet %}
|
{% assign _img_content = _img_snippet %}
|
||||||
@@ -113,6 +96,12 @@
|
|||||||
{% assign _final_src = null %}
|
{% assign _final_src = null %}
|
||||||
{% assign _lazyload = true %}
|
{% assign _lazyload = true %}
|
||||||
|
|
||||||
|
{%- capture _img_url -%}
|
||||||
|
{% include media-url.html src=_src subpath=page.media_subpath %}
|
||||||
|
{%- endcapture -%}
|
||||||
|
|
||||||
|
{% assign _path_prefix = _img_url | remove: _src %}
|
||||||
|
|
||||||
{% unless _src contains '//' %}
|
{% unless _src contains '//' %}
|
||||||
{% assign _final_src = _path_prefix | append: _src %}
|
{% assign _final_src = _path_prefix | append: _src %}
|
||||||
{% assign _src_alt = 'src="' | append: _path_prefix %}
|
{% assign _src_alt = 'src="' | append: _path_prefix %}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
{% assign match_posts = match_posts | push: site.tags[tag] | uniq %}
|
{% assign match_posts = match_posts | push: site.tags[tag] | uniq %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
{% assign match_posts = match_posts | reverse %}
|
||||||
{% assign last_index = match_posts.size | minus: 1 %}
|
{% assign last_index = match_posts.size | minus: 1 %}
|
||||||
{% assign score_list = '' | split: '' %}
|
{% assign score_list = '' | split: '' %}
|
||||||
|
|
||||||
@@ -81,10 +82,7 @@
|
|||||||
{% include datetime.html date=post.date lang=include.lang %}
|
{% include datetime.html date=post.date lang=include.lang %}
|
||||||
<h4 class="pt-0 my-2">{{ post.title }}</h4>
|
<h4 class="pt-0 my-2">{{ post.title }}</h4>
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
<p>
|
<p>{% include post-description.html %}</p>
|
||||||
{% include no-linenos.html content=post.content %}
|
|
||||||
{{ content | markdownify | strip_html | truncate: 200 | escape }}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
{% capture not_found %}<p class="mt-5">{{ site.data.locales[include.lang].search.no_results }}</p>{% endcapture %}
|
{% capture not_found %}<p class="mt-5">{{ site.data.locales[include.lang].search.no_results }}</p>{% endcapture %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
/* Note: dependent library will be loaded in `js-selector.html` */
|
{%- comment -%} Note: dependent library will be loaded in `js-selector.html` {%- endcomment -%}
|
||||||
SimpleJekyllSearch({
|
SimpleJekyllSearch({
|
||||||
searchInput: document.getElementById('search-input'),
|
searchInput: document.getElementById('search-input'),
|
||||||
resultsContainer: document.getElementById('search-results'),
|
resultsContainer: document.getElementById('search-results'),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<!-- The Search results -->
|
<!-- The Search results -->
|
||||||
|
|
||||||
<div id="search-result-wrapper" class="d-flex justify-content-center unloaded">
|
<div id="search-result-wrapper" class="d-flex justify-content-center d-none">
|
||||||
<div class="col-11 content">
|
<div class="col-11 content">
|
||||||
<div id="search-hints">
|
<div id="search-hints">
|
||||||
{% include_cached trending-tags.html %}
|
{% include_cached trending-tags.html %}
|
||||||
|
|||||||
@@ -3,18 +3,12 @@
|
|||||||
<aside aria-label="Sidebar" id="sidebar" class="d-flex flex-column align-items-end">
|
<aside aria-label="Sidebar" id="sidebar" class="d-flex flex-column align-items-end">
|
||||||
<header class="profile-wrapper">
|
<header class="profile-wrapper">
|
||||||
<a href="{{ '/' | relative_url }}" id="avatar" class="rounded-circle">
|
<a href="{{ '/' | relative_url }}" id="avatar" class="rounded-circle">
|
||||||
{% if site.avatar != empty and site.avatar %}
|
{%- if site.avatar != empty and site.avatar -%}
|
||||||
{% capture avatar_url %}
|
{%- capture avatar_url -%}
|
||||||
{% if site.avatar contains '://' %}
|
{% include media-url.html src=site.avatar %}
|
||||||
{{ site.avatar }}
|
{%- endcapture -%}
|
||||||
{% elsif site.img_cdn != empty and site.img_cdn %}
|
<img src="{{- avatar_url -}}" width="112" height="112" alt="avatar" onerror="this.style.display='none'">
|
||||||
{{ site.avatar | prepend: site.img_cdn }}
|
{%- endif -%}
|
||||||
{% else %}
|
|
||||||
{{ site.avatar | relative_url }}
|
|
||||||
{% endif %}
|
|
||||||
{% endcapture %}
|
|
||||||
<img src="{{ avatar_url | strip }}" width="112" height="112" alt="avatar" onerror="this.style.display='none'">
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<h1 class="site-title">
|
<h1 class="site-title">
|
||||||
@@ -50,7 +44,7 @@
|
|||||||
|
|
||||||
<div class="sidebar-bottom d-flex flex-wrap align-items-center w-100">
|
<div class="sidebar-bottom d-flex flex-wrap align-items-center w-100">
|
||||||
{% unless site.theme_mode %}
|
{% unless site.theme_mode %}
|
||||||
<button type="button" class="mode-toggle btn" aria-label="Switch Mode">
|
<button type="button" class="btn btn-link nav-link" aria-label="Switch Mode" id="mode-toggle">
|
||||||
<i class="fas fa-adjust"></i>
|
<i class="fas fa-adjust"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if enable_toc %}
|
{% if enable_toc %}
|
||||||
<section id="toc-wrapper" class="ps-0 pe-4">
|
<section id="toc-wrapper" class="d-none ps-0 pe-4">
|
||||||
<h2 class="panel-heading ps-3 pt-2 mb-2">{{- site.data.locales[include.lang].panel.toc -}}</h2>
|
<h2 class="panel-heading ps-3 mb-2">{{- site.data.locales[include.lang].panel.toc -}}</h2>
|
||||||
<nav id="toc"></nav>
|
<nav id="toc"></nav>
|
||||||
</section>
|
</section>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
{% if forloop.first %}
|
{% if forloop.first %}
|
||||||
<span>
|
<span>
|
||||||
<a href="{{ '/' | relative_url }}">
|
<a href="{{ '/' | relative_url }}">
|
||||||
{{ site.data.locales[include.lang].tabs.home | capitalize }}
|
{{- site.data.locales[include.lang].tabs.home | capitalize -}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@@ -30,8 +30,8 @@
|
|||||||
|
|
||||||
{% elsif page.layout == 'category' or page.layout == 'tag' %}
|
{% elsif page.layout == 'category' or page.layout == 'tag' %}
|
||||||
<span>
|
<span>
|
||||||
<a href="{{ item | relative_url }}">
|
<a href="{{ item | append: '/' | relative_url }}">
|
||||||
{{ site.data.locales[include.lang].tabs[item] | default: page.title }}
|
{{- site.data.locales[include.lang].tabs[item] | default: page.title -}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
<i class="fas fa-search fa-fw"></i>
|
<i class="fas fa-search fa-fw"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<search class="align-items-center ms-3 ms-lg-0">
|
<search id="search" class="align-items-center ms-3 ms-lg-0">
|
||||||
<i class="fas fa-search fa-fw"></i>
|
<i class="fas fa-search fa-fw"></i>
|
||||||
<input
|
<input
|
||||||
class="form-control"
|
class="form-control"
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
<!-- Get the last 5 posts from lastmod list. -->
|
<!-- Get 5 last posted/updated posts -->
|
||||||
|
|
||||||
{% assign MAX_SIZE = 5 %}
|
{% assign MAX_SIZE = 5 %}
|
||||||
|
|
||||||
{% assign all_list = '' | split: '' %}
|
{% assign all_list = '' | split: '' %}
|
||||||
|
|
||||||
{% for post in site.posts %}
|
{% for post in site.posts %}
|
||||||
{% if post.last_modified_at and post.last_modified_at != post.date %}
|
{% assign datetime = post.last_modified_at | default: post.date %}
|
||||||
{% capture elem %}
|
|
||||||
{{- post.last_modified_at | date: "%Y%m%d%H%M%S" -}}::{{- forloop.index0 -}}
|
{% capture elem %}
|
||||||
{% endcapture %}
|
{{- datetime | date: "%Y%m%d%H%M%S" -}}::{{- forloop.index0 -}}
|
||||||
{% assign all_list = all_list | push: elem %}
|
{% endcapture %}
|
||||||
{% endif %}
|
|
||||||
|
{% assign all_list = all_list | push: elem %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% assign all_list = all_list | sort | reverse %}
|
{% assign all_list = all_list | sort | reverse %}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
||||||
|
|
||||||
basic();
|
|
||||||
initSidebar();
|
initSidebar();
|
||||||
initTopbar();
|
initTopbar();
|
||||||
|
basic();
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
||||||
import { initLocaleDatetime, loadImg } from './modules/plugins';
|
import { initLocaleDatetime, loadImg } from './modules/plugins';
|
||||||
|
|
||||||
basic();
|
loadImg();
|
||||||
|
initLocaleDatetime();
|
||||||
initSidebar();
|
initSidebar();
|
||||||
initTopbar();
|
initTopbar();
|
||||||
initLocaleDatetime();
|
basic();
|
||||||
loadImg();
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
||||||
import { initLocaleDatetime } from './modules/plugins';
|
import { initLocaleDatetime } from './modules/plugins';
|
||||||
|
|
||||||
basic();
|
|
||||||
initSidebar();
|
initSidebar();
|
||||||
initTopbar();
|
initTopbar();
|
||||||
initLocaleDatetime();
|
initLocaleDatetime();
|
||||||
|
basic();
|
||||||
|
|||||||
@@ -3,18 +3,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export function back2top() {
|
export function back2top() {
|
||||||
const $window = $(window);
|
const btn = document.getElementById('back-to-top');
|
||||||
const $btn = $('#back-to-top');
|
|
||||||
|
|
||||||
$window.on('scroll', () => {
|
window.addEventListener('scroll', () => {
|
||||||
if ($window.scrollTop() > 50) {
|
if (window.scrollY > 50) {
|
||||||
$btn.fadeIn();
|
btn.classList.add('show');
|
||||||
} else {
|
} else {
|
||||||
$btn.fadeOut();
|
btn.classList.remove('show');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$btn.on('click', () => {
|
btn.addEventListener('click', () => {
|
||||||
$window.scrollTop(0);
|
window.scrollTo({ top: 0 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,36 @@
|
|||||||
/**
|
/**
|
||||||
* Tab 'Categories' expand/close effect.
|
* Tab 'Categories' expand/close effect.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'bootstrap/js/src/collapse.js';
|
||||||
|
|
||||||
const childPrefix = 'l_';
|
const childPrefix = 'l_';
|
||||||
const parentPrefix = 'h_';
|
const parentPrefix = 'h_';
|
||||||
const collapse = $('.collapse');
|
const children = document.getElementsByClassName('collapse');
|
||||||
|
|
||||||
export function categoryCollapse() {
|
export function categoryCollapse() {
|
||||||
/* close up top-category */
|
[...children].forEach((elem) => {
|
||||||
collapse.on('hide.bs.collapse', function () {
|
const id = parentPrefix + elem.id.substring(childPrefix.length);
|
||||||
/* Bootstrap collapse events. */ const parentId =
|
const parent = document.getElementById(id);
|
||||||
parentPrefix + $(this).attr('id').substring(childPrefix.length);
|
|
||||||
if (parentId) {
|
|
||||||
$(`#${parentId} .far.fa-folder-open`).attr(
|
|
||||||
'class',
|
|
||||||
'far fa-folder fa-fw'
|
|
||||||
);
|
|
||||||
$(`#${parentId} i.fas`).addClass('rotate');
|
|
||||||
$(`#${parentId}`).removeClass('hide-border-bottom');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* expand the top category */
|
// collapse sub-categories
|
||||||
collapse.on('show.bs.collapse', function () {
|
elem.addEventListener('hide.bs.collapse', () => {
|
||||||
const parentId =
|
if (parent) {
|
||||||
parentPrefix + $(this).attr('id').substring(childPrefix.length);
|
parent.querySelector('.far.fa-folder-open').className =
|
||||||
if (parentId) {
|
'far fa-folder fa-fw';
|
||||||
$(`#${parentId} .far.fa-folder`).attr(
|
parent.querySelector('.fas.fa-angle-down').classList.add('rotate');
|
||||||
'class',
|
parent.classList.remove('hide-border-bottom');
|
||||||
'far fa-folder-open fa-fw'
|
}
|
||||||
);
|
});
|
||||||
$(`#${parentId} i.fas`).removeClass('rotate');
|
|
||||||
$(`#${parentId}`).addClass('hide-border-bottom');
|
// expand sub-categories
|
||||||
}
|
elem.addEventListener('show.bs.collapse', () => {
|
||||||
|
if (parent) {
|
||||||
|
parent.querySelector('.far.fa-folder').className =
|
||||||
|
'far fa-folder-open fa-fw';
|
||||||
|
parent.querySelector('.fas.fa-angle-down').classList.remove('rotate');
|
||||||
|
parent.classList.add('hide-border-bottom');
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,107 +2,113 @@
|
|||||||
* Clipboard functions
|
* Clipboard functions
|
||||||
*
|
*
|
||||||
* Dependencies:
|
* Dependencies:
|
||||||
* - popper.js (https://github.com/popperjs/popper-core)
|
* clipboard.js (https://github.com/zenorocha/clipboard.js)
|
||||||
* - clipboard.js (https://github.com/zenorocha/clipboard.js)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import Tooltip from 'bootstrap/js/src/tooltip';
|
||||||
|
|
||||||
const clipboardSelector = '.code-header>button';
|
const clipboardSelector = '.code-header>button';
|
||||||
|
|
||||||
|
const ICON_DEFAULT = 'far fa-clipboard';
|
||||||
const ICON_SUCCESS = 'fas fa-check';
|
const ICON_SUCCESS = 'fas fa-check';
|
||||||
|
|
||||||
const ATTR_TIMEOUT = 'timeout';
|
const ATTR_TIMEOUT = 'timeout';
|
||||||
const ATTR_TITLE_SUCCEED = 'data-title-succeed';
|
const ATTR_TITLE_SUCCEED = 'data-title-succeed';
|
||||||
const ATTR_TITLE_ORIGIN = 'data-bs-original-title';
|
const ATTR_TITLE_ORIGIN = 'data-bs-original-title';
|
||||||
const TIMEOUT = 2000; // in milliseconds
|
const TIMEOUT = 2000; // in milliseconds
|
||||||
|
|
||||||
function isLocked(node) {
|
function isLocked(node) {
|
||||||
if ($(node)[0].hasAttribute(ATTR_TIMEOUT)) {
|
if (node.hasAttribute(ATTR_TIMEOUT)) {
|
||||||
let timeout = $(node).attr(ATTR_TIMEOUT);
|
let timeout = node.getAttribute(ATTR_TIMEOUT);
|
||||||
if (Number(timeout) > Date.now()) {
|
if (Number(timeout) > Date.now()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function lock(node) {
|
function lock(node) {
|
||||||
$(node).attr(ATTR_TIMEOUT, Date.now() + TIMEOUT);
|
node.setAttribute(ATTR_TIMEOUT, Date.now() + TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unlock(node) {
|
function unlock(node) {
|
||||||
$(node).removeAttr(ATTR_TIMEOUT);
|
node.removeAttribute(ATTR_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getIcon(btn) {
|
|
||||||
let iconNode = $(btn).children();
|
|
||||||
return iconNode.attr('class');
|
|
||||||
}
|
|
||||||
|
|
||||||
const ICON_DEFAULT = getIcon(clipboardSelector);
|
|
||||||
|
|
||||||
function showTooltip(btn) {
|
function showTooltip(btn) {
|
||||||
const succeedTitle = $(btn).attr(ATTR_TITLE_SUCCEED);
|
const succeedTitle = btn.getAttribute(ATTR_TITLE_SUCCEED);
|
||||||
$(btn).attr(ATTR_TITLE_ORIGIN, succeedTitle).tooltip('show');
|
btn.setAttribute(ATTR_TITLE_ORIGIN, succeedTitle);
|
||||||
|
Tooltip.getInstance(btn).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideTooltip(btn) {
|
function hideTooltip(btn) {
|
||||||
$(btn).tooltip('hide').removeAttr(ATTR_TITLE_ORIGIN);
|
Tooltip.getInstance(btn).hide();
|
||||||
|
btn.removeAttribute(ATTR_TITLE_ORIGIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSuccessIcon(btn) {
|
function setSuccessIcon(btn) {
|
||||||
let btnNode = $(btn);
|
const icon = btn.children[0];
|
||||||
let iconNode = btnNode.children();
|
icon.setAttribute('class', ICON_SUCCESS);
|
||||||
iconNode.attr('class', ICON_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resumeIcon(btn) {
|
function resumeIcon(btn) {
|
||||||
let btnNode = $(btn);
|
const icon = btn.children[0];
|
||||||
let iconNode = btnNode.children();
|
icon.setAttribute('class', ICON_DEFAULT);
|
||||||
iconNode.attr('class', ICON_DEFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initClipboard() {
|
function setCodeClipboard() {
|
||||||
// Initial the clipboard.js object
|
const clipboardList = document.querySelectorAll(clipboardSelector);
|
||||||
if ($(clipboardSelector).length) {
|
|
||||||
const clipboard = new ClipboardJS(clipboardSelector, {
|
|
||||||
target(trigger) {
|
|
||||||
let codeBlock = trigger.parentNode.nextElementSibling;
|
|
||||||
return codeBlock.querySelector('code .rouge-code');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const clipboardList = document.querySelectorAll(clipboardSelector);
|
if (clipboardList.length === 0) {
|
||||||
[...clipboardList].map(
|
return;
|
||||||
(elem) =>
|
|
||||||
new bootstrap.Tooltip(elem, {
|
|
||||||
placement: 'left'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
clipboard.on('success', (e) => {
|
|
||||||
e.clearSelection();
|
|
||||||
|
|
||||||
const trigger = e.trigger;
|
|
||||||
if (isLocked(trigger)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setSuccessIcon(trigger);
|
|
||||||
showTooltip(trigger);
|
|
||||||
lock(trigger);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
hideTooltip(trigger);
|
|
||||||
resumeIcon(trigger);
|
|
||||||
unlock(trigger);
|
|
||||||
}, TIMEOUT);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Post link sharing --- */
|
// Initial the clipboard.js object
|
||||||
|
const clipboard = new ClipboardJS(clipboardSelector, {
|
||||||
|
target: (trigger) => {
|
||||||
|
const codeBlock = trigger.parentNode.nextElementSibling;
|
||||||
|
return codeBlock.querySelector('code .rouge-code');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const btnCopyLink = $('#copy-link');
|
[...clipboardList].map(
|
||||||
|
(elem) =>
|
||||||
|
new Tooltip(elem, {
|
||||||
|
placement: 'left'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
btnCopyLink.on('click', (e) => {
|
clipboard.on('success', (e) => {
|
||||||
let target = $(e.target);
|
const trigger = e.trigger;
|
||||||
|
|
||||||
|
e.clearSelection();
|
||||||
|
|
||||||
|
if (isLocked(trigger)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSuccessIcon(trigger);
|
||||||
|
showTooltip(trigger);
|
||||||
|
lock(trigger);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
hideTooltip(trigger);
|
||||||
|
resumeIcon(trigger);
|
||||||
|
unlock(trigger);
|
||||||
|
}, TIMEOUT);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setLinkClipboard() {
|
||||||
|
const btnCopyLink = document.getElementById('copy-link');
|
||||||
|
|
||||||
|
if (btnCopyLink === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
btnCopyLink.addEventListener('click', (e) => {
|
||||||
|
const target = e.target;
|
||||||
|
|
||||||
if (isLocked(target)) {
|
if (isLocked(target)) {
|
||||||
return;
|
return;
|
||||||
@@ -110,21 +116,28 @@ export function initClipboard() {
|
|||||||
|
|
||||||
// Copy URL to clipboard
|
// Copy URL to clipboard
|
||||||
navigator.clipboard.writeText(window.location.href).then(() => {
|
navigator.clipboard.writeText(window.location.href).then(() => {
|
||||||
const defaultTitle = target.attr(ATTR_TITLE_ORIGIN);
|
const defaultTitle = target.getAttribute(ATTR_TITLE_ORIGIN);
|
||||||
const succeedTitle = target.attr(ATTR_TITLE_SUCCEED);
|
const succeedTitle = target.getAttribute(ATTR_TITLE_SUCCEED);
|
||||||
|
|
||||||
// Switch tooltip title
|
// Switch tooltip title
|
||||||
target.attr(ATTR_TITLE_ORIGIN, succeedTitle).tooltip('show');
|
target.setAttribute(ATTR_TITLE_ORIGIN, succeedTitle);
|
||||||
|
Tooltip.getInstance(target).show();
|
||||||
|
|
||||||
lock(target);
|
lock(target);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
target.attr(ATTR_TITLE_ORIGIN, defaultTitle);
|
target.setAttribute(ATTR_TITLE_ORIGIN, defaultTitle);
|
||||||
unlock(target);
|
unlock(target);
|
||||||
}, TIMEOUT);
|
}, TIMEOUT);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
btnCopyLink.on('mouseleave', function (e) {
|
btnCopyLink.addEventListener('mouseleave', (e) => {
|
||||||
const target = $(e.target);
|
Tooltip.getInstance(e.target).hide();
|
||||||
target.tooltip('hide');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function initClipboard() {
|
||||||
|
setCodeClipboard();
|
||||||
|
setLinkClipboard();
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const cover = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function removeCover(clzss) {
|
function removeCover(clzss) {
|
||||||
$(this).parent().removeClass(clzss);
|
this.parentElement.classList.remove(clzss);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleImage() {
|
function handleImage() {
|
||||||
@@ -30,32 +30,38 @@ function handleImage() {
|
|||||||
* Switches the LQIP with the real image URL.
|
* Switches the LQIP with the real image URL.
|
||||||
*/
|
*/
|
||||||
function switchLQIP() {
|
function switchLQIP() {
|
||||||
const $img = $(this);
|
const src = this.getAttribute(ATTR_DATA_SRC);
|
||||||
const src = $img.attr(ATTR_DATA_SRC);
|
this.setAttribute('src', encodeURI(src));
|
||||||
|
this.removeAttribute(ATTR_DATA_SRC);
|
||||||
$img.attr('src', encodeURI(src));
|
|
||||||
$img.removeAttr(ATTR_DATA_SRC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadImg() {
|
export function loadImg() {
|
||||||
const $images = $('article img');
|
const images = document.querySelectorAll('article img');
|
||||||
|
|
||||||
if ($images.length) {
|
if (images.length === 0) {
|
||||||
$images.on('load', handleImage);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
images.forEach((img) => {
|
||||||
|
img.addEventListener('load', handleImage);
|
||||||
|
});
|
||||||
|
|
||||||
// Images loaded from the browser cache do not trigger the 'load' event
|
// Images loaded from the browser cache do not trigger the 'load' event
|
||||||
$('article img[loading="lazy"]').each(function () {
|
document.querySelectorAll('article img[loading="lazy"]').forEach((img) => {
|
||||||
if (this.complete) {
|
if (img.complete) {
|
||||||
removeCover.call(this, cover.SHIMMER);
|
removeCover.call(img, cover.SHIMMER);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// LQIPs set by the data URI or WebP will not trigger the 'load' event,
|
// LQIPs set by the data URI or WebP will not trigger the 'load' event,
|
||||||
// so manually convert the URI to the URL of a high-resolution image.
|
// so manually convert the URI to the URL of a high-resolution image.
|
||||||
const $lqips = $(`article img[${ATTR_DATA_LQIP}="true"]`);
|
const lqips = document.querySelectorAll(
|
||||||
|
`article img[${ATTR_DATA_LQIP}="true"]`
|
||||||
|
);
|
||||||
|
|
||||||
if ($lqips.length) {
|
if (lqips.length) {
|
||||||
$lqips.each(switchLQIP);
|
lqips.forEach((lqip) => {
|
||||||
|
switchLQIP.call(lqip);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* Set up image popup
|
* Set up image popup
|
||||||
*
|
*
|
||||||
* See: https://github.com/dimsemenov/Magnific-Popup
|
* Dependencies: https://github.com/biati-digital/glightbox
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const IMG_CLASS = 'popup';
|
||||||
|
|
||||||
export function imgPopup() {
|
export function imgPopup() {
|
||||||
if ($('.popup') <= 0) {
|
if (document.getElementsByClassName(IMG_CLASS).length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.popup').magnificPopup({
|
GLightbox({ selector: `.${IMG_CLASS}` });
|
||||||
type: 'image',
|
|
||||||
closeOnContentClick: true,
|
|
||||||
showCloseBtn: false,
|
|
||||||
zoom: {
|
|
||||||
enabled: true,
|
|
||||||
duration: 300,
|
|
||||||
easing: 'ease-in-out'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,15 +15,15 @@ class LocaleHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get locale() {
|
static get locale() {
|
||||||
return $('html').attr('lang').substring(0, 2);
|
return document.documentElement.getAttribute('lang').substring(0, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getTimestamp(elem) {
|
static getTimestamp(elem) {
|
||||||
return Number(elem.attr(LocaleHelper.attrTimestamp)); // unix timestamp
|
return Number(elem.getAttribute(this.attrTimestamp)); // unix timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
static getDateFormat(elem) {
|
static getDateFormat(elem) {
|
||||||
return elem.attr(LocaleHelper.attrDateFormat);
|
return elem.getAttribute(this.attrDateFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,21 +31,23 @@ export function initLocaleDatetime() {
|
|||||||
dayjs.locale(LocaleHelper.locale);
|
dayjs.locale(LocaleHelper.locale);
|
||||||
dayjs.extend(window.dayjs_plugin_localizedFormat);
|
dayjs.extend(window.dayjs_plugin_localizedFormat);
|
||||||
|
|
||||||
$(`[${LocaleHelper.attrTimestamp}]`).each(function () {
|
document
|
||||||
const date = dayjs.unix(LocaleHelper.getTimestamp($(this)));
|
.querySelectorAll(`[${LocaleHelper.attrTimestamp}]`)
|
||||||
const text = date.format(LocaleHelper.getDateFormat($(this)));
|
.forEach((elem) => {
|
||||||
$(this).text(text);
|
const date = dayjs.unix(LocaleHelper.getTimestamp(elem));
|
||||||
$(this).removeAttr(LocaleHelper.attrTimestamp);
|
const text = date.format(LocaleHelper.getDateFormat(elem));
|
||||||
$(this).removeAttr(LocaleHelper.attrDateFormat);
|
elem.textContent = text;
|
||||||
|
elem.removeAttribute(LocaleHelper.attrTimestamp);
|
||||||
|
elem.removeAttribute(LocaleHelper.attrDateFormat);
|
||||||
|
|
||||||
// setup tooltips
|
// setup tooltips
|
||||||
const tooltip = $(this).attr('data-bs-toggle');
|
if (
|
||||||
if (typeof tooltip === 'undefined' || tooltip !== 'tooltip') {
|
elem.hasAttribute('data-bs-toggle') &&
|
||||||
return;
|
elem.getAttribute('data-bs-toggle') === 'tooltip'
|
||||||
}
|
) {
|
||||||
|
// see: https://day.js.org/docs/en/display/format#list-of-localized-formats
|
||||||
const tooltipText = date.format('llll'); // see: https://day.js.org/docs/en/display/format#list-of-localized-formats
|
const tooltipText = date.format('llll');
|
||||||
$(this).attr('data-bs-title', tooltipText);
|
elem.setAttribute('data-bs-title', tooltipText);
|
||||||
new bootstrap.Tooltip($(this));
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,14 @@
|
|||||||
/**
|
/**
|
||||||
* Add listener for theme mode toggle
|
* Add listener for theme mode toggle
|
||||||
*/
|
*/
|
||||||
const $toggleElem = $('.mode-toggle');
|
const toggle = document.getElementById('mode-toggle');
|
||||||
|
|
||||||
export function modeWatcher() {
|
export function modeWatcher() {
|
||||||
if ($toggleElem.length === 0) {
|
if (!toggle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$toggleElem.off().on('click', (e) => {
|
toggle.addEventListener('click', () => {
|
||||||
const $target = $(e.target);
|
modeToggle.flipMode();
|
||||||
let $btn =
|
|
||||||
$target.prop('tagName') === 'button'.toUpperCase()
|
|
||||||
? $target
|
|
||||||
: $target.parent();
|
|
||||||
|
|
||||||
modeToggle.flipMode(); // modeToggle: `_includes/mode-toggle.html`
|
|
||||||
$btn.trigger('blur'); // remove the clicking outline
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,121 +1,109 @@
|
|||||||
/**
|
/**
|
||||||
* This script make #search-result-wrapper switch to unloaded or shown automatically.
|
* This script make #search-result-wrapper switch to unloaded or shown automatically.
|
||||||
*/
|
*/
|
||||||
const $btnSbTrigger = $('#sidebar-trigger');
|
|
||||||
const $btnSearchTrigger = $('#search-trigger');
|
|
||||||
const $btnCancel = $('#search-cancel');
|
|
||||||
const $content = $('#main-wrapper>.container>.row');
|
|
||||||
const $topbarTitle = $('#topbar-title');
|
|
||||||
const $search = $('search');
|
|
||||||
const $resultWrapper = $('#search-result-wrapper');
|
|
||||||
const $results = $('#search-results');
|
|
||||||
const $input = $('#search-input');
|
|
||||||
const $hints = $('#search-hints');
|
|
||||||
const $viewport = $('html,body');
|
|
||||||
|
|
||||||
// class names
|
const btnSbTrigger = document.getElementById('sidebar-trigger');
|
||||||
const C_LOADED = 'loaded';
|
const btnSearchTrigger = document.getElementById('search-trigger');
|
||||||
const C_UNLOADED = 'unloaded';
|
const btnCancel = document.getElementById('search-cancel');
|
||||||
const C_FOCUS = 'input-focus';
|
const content = document.querySelectorAll('#main-wrapper>.container>.row');
|
||||||
const C_FLEX = 'd-flex';
|
const topbarTitle = document.getElementById('topbar-title');
|
||||||
|
const search = document.getElementById('search');
|
||||||
|
const resultWrapper = document.getElementById('search-result-wrapper');
|
||||||
|
const results = document.getElementById('search-results');
|
||||||
|
const input = document.getElementById('search-input');
|
||||||
|
const hints = document.getElementById('search-hints');
|
||||||
|
|
||||||
class ScrollBlocker {
|
// CSS class names
|
||||||
static offset = 0;
|
const LOADED = 'd-block';
|
||||||
static resultVisible = false;
|
const UNLOADED = 'd-none';
|
||||||
|
const FOCUS = 'input-focus';
|
||||||
|
const FLEX = 'd-flex';
|
||||||
|
|
||||||
static on() {
|
/* Actions in mobile screens (Sidebar hidden) */
|
||||||
ScrollBlocker.offset = window.scrollY;
|
|
||||||
$viewport.scrollTop(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static off() {
|
|
||||||
$viewport.scrollTop(ScrollBlocker.offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--- Actions in mobile screens (Sidebar hidden) ---*/
|
|
||||||
class MobileSearchBar {
|
class MobileSearchBar {
|
||||||
static on() {
|
static on() {
|
||||||
$btnSbTrigger.addClass(C_UNLOADED);
|
btnSbTrigger.classList.add(UNLOADED);
|
||||||
$topbarTitle.addClass(C_UNLOADED);
|
topbarTitle.classList.add(UNLOADED);
|
||||||
$btnSearchTrigger.addClass(C_UNLOADED);
|
btnSearchTrigger.classList.add(UNLOADED);
|
||||||
$search.addClass(C_FLEX);
|
search.classList.add(FLEX);
|
||||||
$btnCancel.addClass(C_LOADED);
|
btnCancel.classList.add(LOADED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static off() {
|
static off() {
|
||||||
$btnCancel.removeClass(C_LOADED);
|
btnCancel.classList.remove(LOADED);
|
||||||
$search.removeClass(C_FLEX);
|
search.classList.remove(FLEX);
|
||||||
$btnSbTrigger.removeClass(C_UNLOADED);
|
btnSbTrigger.classList.remove(UNLOADED);
|
||||||
$topbarTitle.removeClass(C_UNLOADED);
|
topbarTitle.classList.remove(UNLOADED);
|
||||||
$btnSearchTrigger.removeClass(C_UNLOADED);
|
btnSearchTrigger.classList.remove(UNLOADED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResultSwitch {
|
class ResultSwitch {
|
||||||
|
static resultVisible = false;
|
||||||
|
|
||||||
static on() {
|
static on() {
|
||||||
if (!ScrollBlocker.resultVisible) {
|
if (!this.resultVisible) {
|
||||||
// the block method must be called before $(#main-wrapper>.container) unloaded.
|
resultWrapper.classList.remove(UNLOADED);
|
||||||
ScrollBlocker.on();
|
content.forEach((el) => {
|
||||||
$resultWrapper.removeClass(C_UNLOADED);
|
el.classList.add(UNLOADED);
|
||||||
$content.addClass(C_UNLOADED);
|
});
|
||||||
ScrollBlocker.resultVisible = true;
|
this.resultVisible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static off() {
|
static off() {
|
||||||
if (ScrollBlocker.resultVisible) {
|
if (this.resultVisible) {
|
||||||
$results.empty();
|
results.innerHTML = '';
|
||||||
if ($hints.hasClass(C_UNLOADED)) {
|
|
||||||
$hints.removeClass(C_UNLOADED);
|
if (hints.classList.contains(UNLOADED)) {
|
||||||
|
hints.classList.remove(UNLOADED);
|
||||||
}
|
}
|
||||||
$resultWrapper.addClass(C_UNLOADED);
|
|
||||||
$content.removeClass(C_UNLOADED);
|
|
||||||
|
|
||||||
// now the release method must be called after $(#main-wrapper>.container) display
|
resultWrapper.classList.add(UNLOADED);
|
||||||
ScrollBlocker.off();
|
content.forEach((el) => {
|
||||||
|
el.classList.remove(UNLOADED);
|
||||||
$input.val('');
|
});
|
||||||
ScrollBlocker.resultVisible = false;
|
input.textContent = '';
|
||||||
|
this.resultVisible = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMobileView() {
|
function isMobileView() {
|
||||||
return $btnCancel.hasClass(C_LOADED);
|
return btnCancel.classList.contains(LOADED);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function displaySearch() {
|
export function displaySearch() {
|
||||||
$btnSearchTrigger.on('click', function () {
|
btnSearchTrigger.addEventListener('click', () => {
|
||||||
MobileSearchBar.on();
|
MobileSearchBar.on();
|
||||||
ResultSwitch.on();
|
ResultSwitch.on();
|
||||||
$input.trigger('focus');
|
input.focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
$btnCancel.on('click', function () {
|
btnCancel.addEventListener('click', () => {
|
||||||
MobileSearchBar.off();
|
MobileSearchBar.off();
|
||||||
ResultSwitch.off();
|
ResultSwitch.off();
|
||||||
});
|
});
|
||||||
|
|
||||||
$input.on('focus', function () {
|
input.addEventListener('focus', () => {
|
||||||
$search.addClass(C_FOCUS);
|
search.classList.add(FOCUS);
|
||||||
});
|
});
|
||||||
|
|
||||||
$input.on('focusout', function () {
|
input.addEventListener('focusout', () => {
|
||||||
$search.removeClass(C_FOCUS);
|
search.classList.remove(FOCUS);
|
||||||
});
|
});
|
||||||
|
|
||||||
$input.on('input', () => {
|
input.addEventListener('input', () => {
|
||||||
if ($input.val() === '') {
|
if (input.value === '') {
|
||||||
if (isMobileView()) {
|
if (isMobileView()) {
|
||||||
$hints.removeClass(C_UNLOADED);
|
hints.classList.remove(UNLOADED);
|
||||||
} else {
|
} else {
|
||||||
ResultSwitch.off();
|
ResultSwitch.off();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ResultSwitch.on();
|
ResultSwitch.on();
|
||||||
if (isMobileView()) {
|
if (isMobileView()) {
|
||||||
$hints.addClass(C_UNLOADED);
|
hints.classList.add(UNLOADED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
* Expand or close the sidebar in mobile screens.
|
* Expand or close the sidebar in mobile screens.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const $body = $('body');
|
|
||||||
const ATTR_DISPLAY = 'sidebar-display';
|
const ATTR_DISPLAY = 'sidebar-display';
|
||||||
|
|
||||||
class SidebarUtil {
|
class SidebarUtil {
|
||||||
@@ -10,9 +9,9 @@ class SidebarUtil {
|
|||||||
|
|
||||||
static toggle() {
|
static toggle() {
|
||||||
if (SidebarUtil.isExpanded === false) {
|
if (SidebarUtil.isExpanded === false) {
|
||||||
$body.attr(ATTR_DISPLAY, '');
|
document.body.setAttribute(ATTR_DISPLAY, '');
|
||||||
} else {
|
} else {
|
||||||
$body.removeAttr(ATTR_DISPLAY);
|
document.body.removeAttribute(ATTR_DISPLAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
SidebarUtil.isExpanded = !SidebarUtil.isExpanded;
|
SidebarUtil.isExpanded = !SidebarUtil.isExpanded;
|
||||||
@@ -20,6 +19,9 @@ class SidebarUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function sidebarExpand() {
|
export function sidebarExpand() {
|
||||||
$('#sidebar-trigger').on('click', SidebarUtil.toggle);
|
document
|
||||||
$('#mask').on('click', SidebarUtil.toggle);
|
.getElementById('sidebar-trigger')
|
||||||
|
.addEventListener('click', SidebarUtil.toggle);
|
||||||
|
|
||||||
|
document.getElementById('mask').addEventListener('click', SidebarUtil.toggle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export function toc() {
|
export function toc() {
|
||||||
if (document.querySelector('main h2')) {
|
if (document.querySelector('main h2, main h3')) {
|
||||||
// see: https://github.com/tscanlin/tocbot#usage
|
// see: https://github.com/tscanlin/tocbot#usage
|
||||||
tocbot.init({
|
tocbot.init({
|
||||||
tocSelector: '#toc',
|
tocSelector: '#toc',
|
||||||
@@ -9,5 +9,7 @@ export function toc() {
|
|||||||
orderedList: false,
|
orderedList: false,
|
||||||
scrollSmooth: false
|
scrollSmooth: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById('toc-wrapper').classList.remove('d-none');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
/**
|
import Tooltip from 'bootstrap/js/src/tooltip';
|
||||||
* Initial Bootstrap Tooltip.
|
|
||||||
*/
|
|
||||||
export function loadTooptip() {
|
export function loadTooptip() {
|
||||||
const tooltipTriggerList = document.querySelectorAll(
|
const tooltipTriggerList = document.querySelectorAll(
|
||||||
'[data-bs-toggle="tooltip"]'
|
'[data-bs-toggle="tooltip"]'
|
||||||
);
|
);
|
||||||
|
|
||||||
[...tooltipTriggerList].map(
|
[...tooltipTriggerList].map(
|
||||||
(tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl)
|
(tooltipTriggerEl) => new Tooltip(tooltipTriggerEl)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
||||||
import { loadImg, imgPopup, initClipboard } from './modules/plugins';
|
import { loadImg, imgPopup, initClipboard } from './modules/plugins';
|
||||||
|
|
||||||
basic();
|
|
||||||
initSidebar();
|
|
||||||
initTopbar();
|
|
||||||
loadImg();
|
loadImg();
|
||||||
imgPopup();
|
imgPopup();
|
||||||
|
initSidebar();
|
||||||
|
initTopbar();
|
||||||
initClipboard();
|
initClipboard();
|
||||||
|
basic();
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import {
|
|||||||
toc
|
toc
|
||||||
} from './modules/plugins';
|
} from './modules/plugins';
|
||||||
|
|
||||||
initSidebar();
|
|
||||||
initTopbar();
|
|
||||||
loadImg();
|
loadImg();
|
||||||
|
toc();
|
||||||
imgPopup();
|
imgPopup();
|
||||||
|
initSidebar();
|
||||||
initLocaleDatetime();
|
initLocaleDatetime();
|
||||||
initClipboard();
|
initClipboard();
|
||||||
toc();
|
initTopbar();
|
||||||
basic();
|
basic();
|
||||||
|
|||||||
3
_javascript/pwa/_frontmatter
Normal file
3
_javascript/pwa/_frontmatter
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
permalink: /:basename
|
||||||
|
---
|
||||||
51
_javascript/pwa/app.js
Normal file
51
_javascript/pwa/app.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { pwa, baseurl } from '../../_config.yml';
|
||||||
|
import Toast from 'bootstrap/js/src/toast';
|
||||||
|
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
if (pwa.enabled) {
|
||||||
|
const swUrl = `${baseurl}/sw.min.js`;
|
||||||
|
const notification = document.getElementById('notification');
|
||||||
|
const btnRefresh = notification.querySelector('.toast-body>button');
|
||||||
|
const popupWindow = Toast.getOrCreateInstance(notification);
|
||||||
|
|
||||||
|
navigator.serviceWorker.register(swUrl).then((registration) => {
|
||||||
|
// In case the user ignores the notification
|
||||||
|
if (registration.waiting) {
|
||||||
|
popupWindow.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
registration.addEventListener('updatefound', () => {
|
||||||
|
registration.installing.addEventListener('statechange', () => {
|
||||||
|
if (registration.waiting) {
|
||||||
|
if (navigator.serviceWorker.controller) {
|
||||||
|
popupWindow.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
btnRefresh.addEventListener('click', () => {
|
||||||
|
if (registration.waiting) {
|
||||||
|
registration.waiting.postMessage('SKIP_WAITING');
|
||||||
|
}
|
||||||
|
popupWindow.hide();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let refreshing = false;
|
||||||
|
|
||||||
|
// Detect controller change and refresh all the opened tabs
|
||||||
|
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||||
|
if (!refreshing) {
|
||||||
|
window.location.reload();
|
||||||
|
refreshing = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
navigator.serviceWorker.getRegistrations().then(function (registrations) {
|
||||||
|
for (let registration of registrations) {
|
||||||
|
registration.unregister();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
82
_javascript/pwa/sw.js
Normal file
82
_javascript/pwa/sw.js
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { baseurl } from '../../_config.yml';
|
||||||
|
|
||||||
|
importScripts(`${baseurl}/assets/js/data/swconf.js`);
|
||||||
|
|
||||||
|
const purge = swconf.purge;
|
||||||
|
|
||||||
|
function verifyUrl(url) {
|
||||||
|
const requestPath = new URL(url).pathname;
|
||||||
|
|
||||||
|
for (const path of swconf.denyPaths) {
|
||||||
|
if (requestPath.startsWith(path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.addEventListener('install', (event) => {
|
||||||
|
if (purge) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.waitUntil(
|
||||||
|
caches.open(swconf.cacheName).then((cache) => {
|
||||||
|
return cache.addAll(swconf.resources);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', (event) => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches.keys().then((keyList) => {
|
||||||
|
return Promise.all(
|
||||||
|
keyList.map((key) => {
|
||||||
|
if (purge) {
|
||||||
|
return caches.delete(key);
|
||||||
|
} else {
|
||||||
|
if (key !== swconf.cacheName) {
|
||||||
|
return caches.delete(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('message', (event) => {
|
||||||
|
if (event.data === 'SKIP_WAITING') {
|
||||||
|
self.skipWaiting();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('fetch', (event) => {
|
||||||
|
if (event.request.headers.has('range')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.respondWith(
|
||||||
|
caches.match(event.request).then((response) => {
|
||||||
|
if (response) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(event.request).then((response) => {
|
||||||
|
const url = event.request.url;
|
||||||
|
|
||||||
|
if (purge || event.request.method !== 'GET' || !verifyUrl(url)) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See: <https://developers.google.com/web/fundamentals/primers/service-workers#cache_and_return_requests>
|
||||||
|
let responseToCache = response.clone();
|
||||||
|
|
||||||
|
caches.open(swconf.cacheName).then((cache) => {
|
||||||
|
cache.put(event.request, responseToCache);
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
# Jekyll layout that compresses HTML
|
# Jekyll layout that compresses HTML
|
||||||
# v3.1.0
|
# v3.2.0
|
||||||
# http://jch.penibelst.de/
|
# http://jch.penibelst.de/
|
||||||
# © 2014–2015 Anatol Broder
|
# © 2014–2015 Anatol Broder
|
||||||
# MIT License
|
# MIT License
|
||||||
---
|
---
|
||||||
|
|
||||||
{% capture _LINE_FEED %}
|
{% capture _LINE_FEED %}
|
||||||
{% endcapture %}{% if site.compress_html.ignore.envs contains jekyll.environment or site.compress_html.ignore.envs == "all" %}{{ content }}{% else %}{% capture _content %}{{ content }}{% endcapture %}{% assign _profile = site.compress_html.profile %}{% if site.compress_html.endings == "all" %}{% assign _endings = "html head body li dt dd optgroup option colgroup caption thead tbody tfoot tr td th" | split: " " %}{% else %}{% assign _endings = site.compress_html.endings %}{% endif %}{% for _element in _endings %}{% capture _end %}</{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _end %}{% endfor %}{% if _profile and _endings %}{% assign _profile_endings = _content | size | plus: 1 %}{% endif %}{% for _element in site.compress_html.startings %}{% capture _start %}<{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _start %}{% endfor %}{% if _profile and site.compress_html.startings %}{% assign _profile_startings = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.comments == "all" %}{% assign _comments = "<!-- -->" | split: " " %}{% else %}{% assign _comments = site.compress_html.comments %}{% endif %}{% if _comments.size == 2 %}{% capture _comment_befores %}.{{ _content }}{% endcapture %}{% assign _comment_befores = _comment_befores | split: _comments.first %}{% for _comment_before in _comment_befores %}{% if forloop.first %}{% continue %}{% endif %}{% capture _comment_outside %}{% if _carry %}{{ _comments.first }}{% endif %}{{ _comment_before }}{% endcapture %}{% capture _comment %}{% unless _carry %}{{ _comments.first }}{% endunless %}{{ _comment_outside | split: _comments.last | first }}{% if _comment_outside contains _comments.last %}{{ _comments.last }}{% assign _carry = false %}{% else %}{% assign _carry = true %}{% endif %}{% endcapture %}{% assign _content = _content | remove_first: _comment %}{% endfor %}{% if _profile %}{% assign _profile_comments = _content | size | plus: 1 %}{% endif %}{% endif %}{% assign _pre_befores = _content | split: "<pre" %}{% assign _content = "" %}{% for _pre_before in _pre_befores %}{% assign _pres = _pre_before | split: "</pre>" %}{% assign _pres_after = "" %}{% if _pres.size != 0 %}{% if site.compress_html.blanklines %}{% assign _lines = _pres.last | split: _LINE_FEED %}{% capture _pres_after %}{% for _line in _lines %}{% assign _trimmed = _line | split: " " | join: " " %}{% if _trimmed != empty or forloop.last %}{% unless forloop.first %}{{ _LINE_FEED }}{% endunless %}{{ _line }}{% endif %}{% endfor %}{% endcapture %}{% else %}{% assign _pres_after = _pres.last | split: " " | join: " " %}{% endif %}{% endif %}{% capture _content %}{{ _content }}{% if _pre_before contains "</pre>" %}<pre{{ _pres.first }}</pre>{% endif %}{% unless _pre_before contains "</pre>" and _pres.size == 1 %}{{ _pres_after }}{% endunless %}{% endcapture %}{% endfor %}{% if _profile %}{% assign _profile_collapse = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.clippings == "all" %}{% assign _clippings = "html head title base link meta style body article section nav aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr blockquote ol ul li dl dt dd figure figcaption main div table caption colgroup col tbody thead tfoot tr td th" | split: " " %}{% else %}{% assign _clippings = site.compress_html.clippings %}{% endif %}{% for _element in _clippings %}{% assign _edges = " <e;<e; </e>;</e>;</e> ;</e>" | replace: "e", _element | split: ";" %}{% assign _content = _content | replace: _edges[0], _edges[1] | replace: _edges[2], _edges[3] | replace: _edges[4], _edges[5] %}{% endfor %}{% if _profile and _clippings %}{% assign _profile_clippings = _content | size | plus: 1 %}{% endif %}{{ _content }}{% if _profile %} <table id="compress_html_profile_{{ site.time | date: "%Y%m%d" }}" class="compress_html_profile"> <thead> <tr> <td>Step <td>Bytes <tbody> <tr> <td>raw <td>{{ content | size }}{% if _profile_endings %} <tr> <td>endings <td>{{ _profile_endings }}{% endif %}{% if _profile_startings %} <tr> <td>startings <td>{{ _profile_startings }}{% endif %}{% if _profile_comments %} <tr> <td>comments <td>{{ _profile_comments }}{% endif %}{% if _profile_collapse %} <tr> <td>collapse <td>{{ _profile_collapse }}{% endif %}{% if _profile_clippings %} <tr> <td>clippings <td>{{ _profile_clippings }}{% endif %} </table>{% endif %}{% endif %}
|
{% endcapture %}{% if site.compress_html.ignore.envs contains jekyll.environment or site.compress_html.ignore.envs == "all" or page.compress_html == false %}{{ content }}{% else %}{% capture _content %}{{ content }}{% endcapture %}{% assign _profile = site.compress_html.profile %}{% if site.compress_html.endings == "all" %}{% assign _endings = "html head body li dt dd optgroup option colgroup caption thead tbody tfoot tr td th" | split: " " %}{% else %}{% assign _endings = site.compress_html.endings %}{% endif %}{% for _element in _endings %}{% capture _end %}</{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _end %}{% endfor %}{% if _profile and _endings %}{% assign _profile_endings = _content | size | plus: 1 %}{% endif %}{% for _element in site.compress_html.startings %}{% capture _start %}<{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _start %}{% endfor %}{% if _profile and site.compress_html.startings %}{% assign _profile_startings = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.comments == "all" %}{% assign _comments = "<!-- -->" | split: " " %}{% else %}{% assign _comments = site.compress_html.comments %}{% endif %}{% if _comments.size == 2 %}{% capture _comment_befores %}.{{ _content }}{% endcapture %}{% assign _comment_befores = _comment_befores | split: _comments.first %}{% for _comment_before in _comment_befores %}{% if forloop.first %}{% continue %}{% endif %}{% capture _comment_outside %}{% if _carry %}{{ _comments.first }}{% endif %}{{ _comment_before }}{% endcapture %}{% capture _comment %}{% unless _carry %}{{ _comments.first }}{% endunless %}{{ _comment_outside | split: _comments.last | first }}{% if _comment_outside contains _comments.last %}{{ _comments.last }}{% assign _carry = false %}{% else %}{% assign _carry = true %}{% endif %}{% endcapture %}{% assign _content = _content | remove_first: _comment %}{% endfor %}{% if _profile %}{% assign _profile_comments = _content | size | plus: 1 %}{% endif %}{% endif %}{% assign _pre_befores = _content | split: "<pre" %}{% assign _content = "" %}{% for _pre_before in _pre_befores %}{% assign _pres = _pre_before | split: "</pre>" %}{% assign _pres_after = "" %}{% if _pres.size != 0 %}{% if site.compress_html.blanklines %}{% assign _lines = _pres.last | split: _LINE_FEED %}{% capture _pres_after %}{% for _line in _lines %}{% assign _trimmed = _line | split: " " | join: " " %}{% if _trimmed != empty or forloop.last %}{% unless forloop.first %}{{ _LINE_FEED }}{% endunless %}{{ _line }}{% endif %}{% endfor %}{% endcapture %}{% else %}{% assign _pres_after = _pres.last | split: " " | join: " " %}{% endif %}{% endif %}{% capture _content %}{{ _content }}{% if _pre_before contains "</pre>" %}<pre{{ _pres.first }}</pre>{% endif %}{% unless _pre_before contains "</pre>" and _pres.size == 1 %}{{ _pres_after }}{% endunless %}{% endcapture %}{% endfor %}{% if _profile %}{% assign _profile_collapse = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.clippings == "all" %}{% assign _clippings = "html head title base link meta style body article section nav aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr blockquote ol ul li dl dt dd figure figcaption main div table caption colgroup col tbody thead tfoot tr td th" | split: " " %}{% else %}{% assign _clippings = site.compress_html.clippings %}{% endif %}{% for _element in _clippings %}{% assign _edges = " <e;<e; </e>;</e>;</e> ;</e>" | replace: "e", _element | split: ";" %}{% assign _content = _content | replace: _edges[0], _edges[1] | replace: _edges[2], _edges[3] | replace: _edges[4], _edges[5] %}{% endfor %}{% if _profile and _clippings %}{% assign _profile_clippings = _content | size | plus: 1 %}{% endif %}{{ _content }}{% if _profile %} <table id="compress_html_profile_{{ site.time | date: "%Y%m%d" }}" class="compress_html_profile"> <thead> <tr> <td>Step <td>Bytes <tbody> <tr> <td>raw <td>{{ content | size }}{% if _profile_endings %} <tr> <td>endings <td>{{ _profile_endings }}{% endif %}{% if _profile_startings %} <tr> <td>startings <td>{{ _profile_startings }}{% endif %}{% if _profile_comments %} <tr> <td>comments <td>{{ _profile_comments }}{% endif %}{% if _profile_collapse %} <tr> <td>collapse <td>{{ _profile_collapse }}{% endif %}{% if _profile_clippings %} <tr> <td>clippings <td>{{ _profile_clippings }}{% endif %} </table>{% endif %}{% endif %}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ layout: compress
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- `site.alt_lang` can specify a language different from the UI -->
|
<!-- `site.alt_lang` can specify a language different from the UI -->
|
||||||
<html lang="{{ site.alt_lang | default: site.lang }}" {{ prefer_mode }}>
|
<html lang="{{ page.lang | default: site.alt_lang | default: site.lang }}" {{ prefer_mode }}>
|
||||||
{% include head.html %}
|
{% include head.html %}
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@@ -75,13 +75,8 @@ layout: compress
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- JavaScripts -->
|
<!-- JavaScripts -->
|
||||||
|
{% include js-selector.html lang=lang %}
|
||||||
|
|
||||||
{% include js-selector.html %}
|
{% include_cached search-loader.html lang=lang %}
|
||||||
|
|
||||||
{% if page.mermaid %}
|
|
||||||
{% include mermaid.html %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% include_cached search-loader.html %}
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ refactor: true
|
|||||||
{% if post.image %}
|
{% if post.image %}
|
||||||
{% assign src = post.image.path | default: post.image %}
|
{% assign src = post.image.path | default: post.image %}
|
||||||
{% unless src contains '//' %}
|
{% unless src contains '//' %}
|
||||||
{% assign src = post.img_path | append: '/' | append: src | replace: '//', '/' %}
|
{% assign src = post.media_subpath | append: '/' | append: src | replace: '//', '/' %}
|
||||||
{% endunless %}
|
{% endunless %}
|
||||||
|
|
||||||
{% assign alt = post.image.alt | xml_escape | default: 'Preview Image' %}
|
{% assign alt = post.image.alt | xml_escape | default: 'Preview Image' %}
|
||||||
@@ -72,10 +72,7 @@ refactor: true
|
|||||||
<h1 class="card-title my-2 mt-md-0">{{ post.title }}</h1>
|
<h1 class="card-title my-2 mt-md-0">{{ post.title }}</h1>
|
||||||
|
|
||||||
<div class="card-text content mt-0 mb-3">
|
<div class="card-text content mt-0 mb-3">
|
||||||
<p>
|
<p>{% include post-description.html %}</p>
|
||||||
{% include no-linenos.html content=post.content %}
|
|
||||||
{{ content | markdownify | strip_html | truncate: 200 | escape }}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="post-meta flex-grow-1 d-flex align-items-end">
|
<div class="post-meta flex-grow-1 d-flex align-items-end">
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ tail_includes:
|
|||||||
<article class="px-1">
|
<article class="px-1">
|
||||||
<header>
|
<header>
|
||||||
<h1 data-toc-skip>{{ page.title }}</h1>
|
<h1 data-toc-skip>{{ page.title }}</h1>
|
||||||
|
{% if page.description %}
|
||||||
|
<p class="post-desc fw-light mb-4">{{ page.description }}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="post-meta text-muted">
|
<div class="post-meta text-muted">
|
||||||
<!-- published date -->
|
<!-- published date -->
|
||||||
@@ -61,7 +64,11 @@ tail_includes:
|
|||||||
<em>
|
<em>
|
||||||
{% if authors %}
|
{% if authors %}
|
||||||
{% for author in authors %}
|
{% for author in authors %}
|
||||||
<a href="{{ site.data.authors[author].url }}">{{ site.data.authors[author].name }}</a>
|
{% if site.data.authors[author].url -%}
|
||||||
|
<a href="{{ site.data.authors[author].url }}">{{ site.data.authors[author].name }}</a>
|
||||||
|
{%- else -%}
|
||||||
|
{{ site.data.authors[author].name }}
|
||||||
|
{%- endif %}
|
||||||
{% unless forloop.last %}{{ '</em>, <em>' }}{% endunless %}
|
{% unless forloop.last %}{{ '</em>, <em>' }}{% endunless %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -70,12 +77,22 @@ tail_includes:
|
|||||||
</em>
|
</em>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<!-- read time -->
|
<div>
|
||||||
{% include read-time.html content=content prompt=true lang=lang %}
|
<!-- pageviews -->
|
||||||
|
{% if site.pageviews.provider and site.analytics[site.pageviews.provider].id %}
|
||||||
|
<span>
|
||||||
|
<em id="pageviews">
|
||||||
|
<i class="fas fa-spinner fa-spin small"></i>
|
||||||
|
</em>
|
||||||
|
{{ site.data.locales[lang].post.pageview_measure }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- read time -->
|
||||||
|
{% include read-time.html content=content prompt=true lang=lang %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- .d-flex -->
|
|
||||||
</div>
|
</div>
|
||||||
<!-- .post-meta -->
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: Text and Typography
|
title: Text and Typography
|
||||||
|
description: Examples of text, typography, math equations, diagrams, flowcharts, pictures, videos, and more.
|
||||||
author: cotes
|
author: cotes
|
||||||
date: 2019-08-08 11:33:00 +0800
|
date: 2019-08-08 11:33:00 +0800
|
||||||
categories: [Blogging, Demo]
|
categories: [Blogging, Demo]
|
||||||
@@ -13,10 +14,10 @@ image:
|
|||||||
alt: Responsive rendering of Chirpy theme on multiple devices.
|
alt: Responsive rendering of Chirpy theme on multiple devices.
|
||||||
---
|
---
|
||||||
|
|
||||||
This post is to show Markdown syntax rendering on [**Chirpy**](https://github.com/cotes2020/jekyll-theme-chirpy/fork), you can also use it as an example of writing. Now, let's start looking at text and typography.
|
|
||||||
|
|
||||||
## Headings
|
## Headings
|
||||||
|
|
||||||
|
<!-- markdownlint-capture -->
|
||||||
|
<!-- markdownlint-disable -->
|
||||||
# H1 - heading
|
# H1 - heading
|
||||||
{: .mt-4 .mb-0 }
|
{: .mt-4 .mb-0 }
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ This post is to show Markdown syntax rendering on [**Chirpy**](https://github.co
|
|||||||
|
|
||||||
#### H4 - heading
|
#### H4 - heading
|
||||||
{: data-toc-skip='' .mt-4 }
|
{: data-toc-skip='' .mt-4 }
|
||||||
|
<!-- markdownlint-restore -->
|
||||||
|
|
||||||
## Paragraph
|
## Paragraph
|
||||||
|
|
||||||
@@ -44,15 +46,15 @@ Quisque egestas convallis ipsum, ut sollicitudin risus tincidunt a. Maecenas int
|
|||||||
### Unordered list
|
### Unordered list
|
||||||
|
|
||||||
- Chapter
|
- Chapter
|
||||||
+ Section
|
- Section
|
||||||
* Paragraph
|
- Paragraph
|
||||||
|
|
||||||
### ToDo list
|
### ToDo list
|
||||||
|
|
||||||
- [ ] Job
|
- [ ] Job
|
||||||
+ [x] Step 1
|
- [x] Step 1
|
||||||
+ [x] Step 2
|
- [x] Step 2
|
||||||
+ [ ] Step 3
|
- [ ] Step 3
|
||||||
|
|
||||||
### Description list
|
### Description list
|
||||||
|
|
||||||
@@ -68,6 +70,8 @@ Moon
|
|||||||
|
|
||||||
## Prompts
|
## Prompts
|
||||||
|
|
||||||
|
<!-- markdownlint-capture -->
|
||||||
|
<!-- markdownlint-disable -->
|
||||||
> An example showing the `tip` type prompt.
|
> An example showing the `tip` type prompt.
|
||||||
{: .prompt-tip }
|
{: .prompt-tip }
|
||||||
|
|
||||||
@@ -79,14 +83,15 @@ Moon
|
|||||||
|
|
||||||
> An example showing the `danger` type prompt.
|
> An example showing the `danger` type prompt.
|
||||||
{: .prompt-danger }
|
{: .prompt-danger }
|
||||||
|
<!-- markdownlint-restore -->
|
||||||
|
|
||||||
## Tables
|
## Tables
|
||||||
|
|
||||||
| Company | Contact | Country |
|
| Company | Contact | Country |
|
||||||
|:-----------------------------|:-----------------|--------:|
|
| :--------------------------- | :--------------- | ------: |
|
||||||
| Alfreds Futterkiste | Maria Anders | Germany |
|
| Alfreds Futterkiste | Maria Anders | Germany |
|
||||||
| Island Trading | Helen Bennett | UK |
|
| Island Trading | Helen Bennett | UK |
|
||||||
| Magazzini Alimentari Riuniti | Giovanni Rovelli | Italy |
|
| Magazzini Alimentari Riuniti | Giovanni Rovelli | Italy |
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
@@ -108,7 +113,7 @@ Here is the `/path/to/the/file.extend`{: .filepath}.
|
|||||||
|
|
||||||
### Common
|
### Common
|
||||||
|
|
||||||
```
|
```text
|
||||||
This is a common code snippet, without syntax highlight and line number.
|
This is a common code snippet, without syntax highlight and line number.
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -134,7 +139,14 @@ fi;
|
|||||||
|
|
||||||
The mathematics powered by [**MathJax**](https://www.mathjax.org/):
|
The mathematics powered by [**MathJax**](https://www.mathjax.org/):
|
||||||
|
|
||||||
$$ \sum_{n=1}^\infty 1/n^2 = \frac{\pi^2}{6} $$
|
$$
|
||||||
|
\begin{equation}
|
||||||
|
\sum_{n=1}^\infty 1/n^2 = \frac{\pi^2}{6}
|
||||||
|
\label{eq:series}
|
||||||
|
\end{equation}
|
||||||
|
$$
|
||||||
|
|
||||||
|
We can reference the equation as \eqref{eq:series}.
|
||||||
|
|
||||||
When $a \ne 0$, there are two solutions to $ax^2 + bx + c = 0$ and they are
|
When $a \ne 0$, there are two solutions to $ax^2 + bx + c = 0$ and they are
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ Adding author information in `_data/authors.yml` (If your website doesn't have t
|
|||||||
```
|
```
|
||||||
{: file="_data/authors.yml" }
|
{: file="_data/authors.yml" }
|
||||||
|
|
||||||
|
|
||||||
And then use `author` to specify a single entry or `authors` to specify multiple entries:
|
And then use `author` to specify a single entry or `authors` to specify multiple entries:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -69,12 +68,23 @@ authors: [<author1_id>, <author2_id>] # for multiple entries
|
|||||||
---
|
---
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Having said that, the key `author` can also identify multiple entries.
|
Having said that, the key `author` can also identify multiple entries.
|
||||||
|
|
||||||
> The benefit of reading the author information from the file `_data/authors.yml`{: .filepath } is that the page will have the meta tag `twitter:creator`, which enriches the [Twitter Cards](https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started#card-and-content-attribution) and is good for SEO.
|
> The benefit of reading the author information from the file `_data/authors.yml`{: .filepath } is that the page will have the meta tag `twitter:creator`, which enriches the [Twitter Cards](https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started#card-and-content-attribution) and is good for SEO.
|
||||||
{: .prompt-info }
|
{: .prompt-info }
|
||||||
|
|
||||||
|
### Post Description
|
||||||
|
|
||||||
|
By default, the first words of the post are used to display on the home page for a list of posts, in the _Further Reading_ section, and in the XML of the RSS feed. If you don't want to display the auto-generated description for the post, you can customize it using the `description` field in the _Front Matter_ as follows:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
description: Short summary of the post.
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
Additionally, the `description` text will also be displayed under the post title on the post's page.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
By default, the **T**able **o**f **C**ontents (TOC) is displayed on the right panel of the post. If you want to turn it off globally, go to `_config.yml`{: .filepath} and set the value of variable `toc` to `false`. If you want to turn off TOC for a specific post, add the following to the post's [Front Matter](https://jekyllrb.com/docs/front-matter/):
|
By default, the **T**able **o**f **C**ontents (TOC) is displayed on the right panel of the post. If you want to turn it off globally, go to `_config.yml`{: .filepath} and set the value of variable `toc` to `false`. If you want to turn off TOC for a specific post, add the following to the post's [Front Matter](https://jekyllrb.com/docs/front-matter/):
|
||||||
@@ -97,55 +107,35 @@ comments: false
|
|||||||
---
|
---
|
||||||
```
|
```
|
||||||
|
|
||||||
## Mathematics
|
## Media
|
||||||
|
|
||||||
For website performance reasons, the mathematical feature won't be loaded by default. But it can be enabled by:
|
We refer to images, audio and video as media resources in _Chirpy_.
|
||||||
|
|
||||||
```yaml
|
### URL Prefix
|
||||||
---
|
|
||||||
math: true
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
After enabling the mathematical feature, you can add math equations with the following syntax:
|
From time to time we have to define duplicate URL prefixes for multiple resources in a post, which is a boring task that you can avoid by setting two parameters.
|
||||||
|
|
||||||
- **Block math** should be added with `$$ math $$` with **mandatory** blank lines before and after `$$`
|
- If you are using a CDN to host media files, you can specify the `cdn` in `_config.yml`{: .filepath }. The URLs of media resources for site avatar and posts are then prefixed with the CDN domain name.
|
||||||
- **Inline math** (in lines) should be added with `$$ math $$` without any blank line before or after `$$`
|
|
||||||
- **Inline math** (in lists) should be added with `\$$ math $$`
|
|
||||||
|
|
||||||
```markdown
|
```yaml
|
||||||
<!-- Block math, keep all blank lines -->
|
cdn: https://cdn.com
|
||||||
|
```
|
||||||
|
{: file='_config.yml' .nolineno }
|
||||||
|
|
||||||
$$
|
- To specify the resource path prefix for the current post/page range, set `media_subpath` in the _front matter_ of the post:
|
||||||
LaTeX_math_expression
|
|
||||||
$$
|
|
||||||
|
|
||||||
<!-- Inline math in lines, NO blank lines -->
|
```yaml
|
||||||
|
---
|
||||||
|
media_subpath: /path/to/media/
|
||||||
|
---
|
||||||
|
```
|
||||||
|
{: .nolineno }
|
||||||
|
|
||||||
"Lorem ipsum dolor sit amet, $$ LaTeX_math_expression $$ consectetur adipiscing elit."
|
The option `site.cdn` and `page.media_subpath` can be used individually or in combination to flexibly compose the final resource URL: `[site.cdn/][page.media_subpath/]file.ext`
|
||||||
|
|
||||||
<!-- Inline math in lists, escape the first `$` -->
|
### Images
|
||||||
|
|
||||||
1. \$$ LaTeX_math_expression $$
|
#### Caption
|
||||||
2. \$$ LaTeX_math_expression $$
|
|
||||||
3. \$$ LaTeX_math_expression $$
|
|
||||||
```
|
|
||||||
|
|
||||||
## Mermaid
|
|
||||||
|
|
||||||
[**Mermaid**](https://github.com/mermaid-js/mermaid) is a great diagram generation tool. To enable it on your post, add the following to the YAML block:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
mermaid: true
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you can use it like other markdown languages: surround the graph code with ```` ```mermaid ```` and ```` ``` ````.
|
|
||||||
|
|
||||||
## Images
|
|
||||||
|
|
||||||
### Caption
|
|
||||||
|
|
||||||
Add italics to the next line of an image, then it will become the caption and appear at the bottom of the image:
|
Add italics to the next line of an image, then it will become the caption and appear at the bottom of the image:
|
||||||
|
|
||||||
@@ -155,7 +145,7 @@ _Image Caption_
|
|||||||
```
|
```
|
||||||
{: .nolineno}
|
{: .nolineno}
|
||||||
|
|
||||||
### Size
|
#### Size
|
||||||
|
|
||||||
In order to prevent the page content layout from shifting when the image is loaded, we should set the width and height for each image.
|
In order to prevent the page content layout from shifting when the image is loaded, we should set the width and height for each image.
|
||||||
|
|
||||||
@@ -174,7 +164,7 @@ Starting from _Chirpy v5.0.0_, `height` and `width` support abbreviations (`heig
|
|||||||
```
|
```
|
||||||
{: .nolineno}
|
{: .nolineno}
|
||||||
|
|
||||||
### Position
|
#### Position
|
||||||
|
|
||||||
By default, the image is centered, but you can specify the position by using one of the classes `normal`, `left`, and `right`.
|
By default, the image is centered, but you can specify the position by using one of the classes `normal`, `left`, and `right`.
|
||||||
|
|
||||||
@@ -204,7 +194,7 @@ By default, the image is centered, but you can specify the position by using one
|
|||||||
```
|
```
|
||||||
{: .nolineno}
|
{: .nolineno}
|
||||||
|
|
||||||
### Dark/Light mode
|
#### Dark/Light mode
|
||||||
|
|
||||||
You can make images follow theme preferences in dark/light mode. This requires you to prepare two images, one for dark mode and one for light mode, and then assign them a specific class (`dark` or `light`):
|
You can make images follow theme preferences in dark/light mode. This requires you to prepare two images, one for dark mode and one for light mode, and then assign them a specific class (`dark` or `light`):
|
||||||
|
|
||||||
@@ -213,7 +203,7 @@ You can make images follow theme preferences in dark/light mode. This requires y
|
|||||||
{: .dark }
|
{: .dark }
|
||||||
```
|
```
|
||||||
|
|
||||||
### Shadow
|
#### Shadow
|
||||||
|
|
||||||
The screenshots of the program window can be considered to show the shadow effect:
|
The screenshots of the program window can be considered to show the shadow effect:
|
||||||
|
|
||||||
@@ -222,56 +212,7 @@ The screenshots of the program window can be considered to show the shadow effec
|
|||||||
```
|
```
|
||||||
{: .nolineno}
|
{: .nolineno}
|
||||||
|
|
||||||
### CDN URL
|
#### Preview Image
|
||||||
|
|
||||||
If you host the images on the CDN, you can save the time of repeatedly writing the CDN URL by assigning the variable `img_cdn` of `_config.yml`{: .filepath} file:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
img_cdn: https://cdn.com
|
|
||||||
```
|
|
||||||
{: file='_config.yml' .nolineno}
|
|
||||||
|
|
||||||
Once `img_cdn` is assigned, the CDN URL will be added to the path of all images (images of site avatar and posts) starting with `/`.
|
|
||||||
|
|
||||||
For instance, when using images:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||

|
|
||||||
```
|
|
||||||
{: .nolineno}
|
|
||||||
|
|
||||||
The parsing result will automatically add the CDN prefix `https://cdn.com` before the image path:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<img src="https://cdn.com/path/to/flower.png" alt="The flower">
|
|
||||||
```
|
|
||||||
{: .nolineno }
|
|
||||||
|
|
||||||
### Image Path
|
|
||||||
|
|
||||||
When a post contains many images, it will be a time-consuming task to repeatedly define the path of the images. To solve this, we can define this path in the YAML block of the post:
|
|
||||||
|
|
||||||
```yml
|
|
||||||
---
|
|
||||||
img_path: /img/path/
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
And then, the image source of Markdown can write the file name directly:
|
|
||||||
|
|
||||||
```md
|
|
||||||

|
|
||||||
```
|
|
||||||
{: .nolineno }
|
|
||||||
|
|
||||||
The output will be:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<img src="/img/path/flower.png" alt="The flower">
|
|
||||||
```
|
|
||||||
{: .nolineno }
|
|
||||||
|
|
||||||
### Preview Image
|
|
||||||
|
|
||||||
If you want to add an image at the top of the post, please provide an image with a resolution of `1200 x 630`. Please note that if the image aspect ratio does not meet `1.91 : 1`, the image will be scaled and cropped.
|
If you want to add an image at the top of the post, please provide an image with a resolution of `1200 x 630`. Please note that if the image aspect ratio does not meet `1.91 : 1`, the image will be scaled and cropped.
|
||||||
|
|
||||||
@@ -285,7 +226,7 @@ image:
|
|||||||
---
|
---
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that the [`img_path`](#image-path) can also be passed to the preview image, that is, when it has been set, the attribute `path` only needs the image file name.
|
Note that the [`media_subpath`](#url-prefix) can also be passed to the preview image, that is, when it has been set, the attribute `path` only needs the image file name.
|
||||||
|
|
||||||
For simple use, you can also just use `image` to define the path.
|
For simple use, you can also just use `image` to define the path.
|
||||||
|
|
||||||
@@ -295,7 +236,7 @@ image: /path/to/image
|
|||||||
---
|
---
|
||||||
```
|
```
|
||||||
|
|
||||||
### LQIP
|
#### LQIP
|
||||||
|
|
||||||
For preview images:
|
For preview images:
|
||||||
|
|
||||||
@@ -306,8 +247,7 @@ image:
|
|||||||
---
|
---
|
||||||
```
|
```
|
||||||
|
|
||||||
> You can observe LQIP in the preview image of post [_Text and Typography_](/posts/text-and-typography/).
|
> You can observe LQIP in the preview image of post \"[Text and Typography](../text-and-typography/)\".
|
||||||
|
|
||||||
|
|
||||||
For normal images:
|
For normal images:
|
||||||
|
|
||||||
@@ -316,6 +256,86 @@ For normal images:
|
|||||||
```
|
```
|
||||||
{: .nolineno }
|
{: .nolineno }
|
||||||
|
|
||||||
|
### Video
|
||||||
|
|
||||||
|
#### Social Media Platform
|
||||||
|
|
||||||
|
You can embed videos from social media platforms with the following syntax:
|
||||||
|
|
||||||
|
```liquid
|
||||||
|
{% include embed/{Platform}.html id='{ID}' %}
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `Platform` is the lowercase of the platform name, and `ID` is the video ID.
|
||||||
|
|
||||||
|
The following table shows how to get the two parameters we need in a given video URL, and you can also know the currently supported video platforms.
|
||||||
|
|
||||||
|
| Video URL | Platform | ID |
|
||||||
|
| -------------------------------------------------------------------------------------------------- | ---------- | :------------- |
|
||||||
|
| [https://www.**youtube**.com/watch?v=**H-B46URT4mg**](https://www.youtube.com/watch?v=H-B46URT4mg) | `youtube` | `H-B46URT4mg` |
|
||||||
|
| [https://www.**twitch**.tv/videos/**1634779211**](https://www.twitch.tv/videos/1634779211) | `twitch` | `1634779211` |
|
||||||
|
| [https://www.**bilibili**.com/video/**BV1Q44y1B7Wf**](https://www.bilibili.com/video/BV1Q44y1B7Wf) | `bilibili` | `BV1Q44y1B7Wf` |
|
||||||
|
|
||||||
|
#### Video Files
|
||||||
|
|
||||||
|
If you want to embed a video file directly, use the following syntax:
|
||||||
|
|
||||||
|
```liquid
|
||||||
|
{% include embed/video.html src='{URL}' %}
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `URL` is an URL to a video file e.g. `/path/to/sample/video.mp4`.
|
||||||
|
|
||||||
|
You can also specify additional attributes for the embedded video file. Here is a full list of attributes allowed.
|
||||||
|
|
||||||
|
- `poster='/path/to/poster.png'` — poster image for a video that is shown while video is downloading
|
||||||
|
- `title='Text'` — title for a video that appears below the video and looks same as for images
|
||||||
|
- `autoplay=true` — video automatically begins to play back as soon as it can
|
||||||
|
- `loop=true` — automatically seek back to the start upon reaching the end of the video
|
||||||
|
- `muted=true` — audio will be initially silenced
|
||||||
|
- `types` — specify the extensions of additional video formats separated by `|`. Ensure these files exist in the same directory as your primary video file.
|
||||||
|
|
||||||
|
Consider an example utilizing all of the above:
|
||||||
|
|
||||||
|
```liquid
|
||||||
|
{%
|
||||||
|
include embed/video.html
|
||||||
|
src='/path/to/video.mp4'
|
||||||
|
types='ogg|mov'
|
||||||
|
poster='poster.png'
|
||||||
|
title='Demo video'
|
||||||
|
autoplay=true
|
||||||
|
loop=true
|
||||||
|
muted=true
|
||||||
|
%}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Audios
|
||||||
|
|
||||||
|
If you want to embed an audio file directly, use the following syntax:
|
||||||
|
|
||||||
|
```liquid
|
||||||
|
{% include embed/audio.html src='{URL}' %}
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `URL` is an URL to an audio file e.g. `/path/to/audio.mp3`.
|
||||||
|
|
||||||
|
You can also specify additional attributes for the embedded audio file. Here is a full list of attributes allowed.
|
||||||
|
|
||||||
|
- `title='Text'` — title for an audio that appears below the audio and looks same as for images
|
||||||
|
- `types` — specify the extensions of additional audio formats separated by `|`. Ensure these files exist in the same directory as your primary audio file.
|
||||||
|
|
||||||
|
Consider an example utilizing all of the above:
|
||||||
|
|
||||||
|
```liquid
|
||||||
|
{%
|
||||||
|
include embed/audio.html
|
||||||
|
src='/path/to/audio.mp3'
|
||||||
|
types='ogg|wav|aac'
|
||||||
|
title='Demo audio'
|
||||||
|
%}
|
||||||
|
```
|
||||||
|
|
||||||
## Pinned Posts
|
## Pinned Posts
|
||||||
|
|
||||||
You can pin one or more posts to the top of the home page, and the fixed posts are sorted in reverse order according to their release date. Enable by:
|
You can pin one or more posts to the top of the home page, and the fixed posts are sorted in reverse order according to their release date. Enable by:
|
||||||
@@ -413,23 +433,74 @@ If you want to display the **Liquid** snippet, surround the liquid code with `{%
|
|||||||
|
|
||||||
Or adding `render_with_liquid: false` (Requires Jekyll 4.0 or higher) to the post's YAML block.
|
Or adding `render_with_liquid: false` (Requires Jekyll 4.0 or higher) to the post's YAML block.
|
||||||
|
|
||||||
## Videos
|
|
||||||
|
|
||||||
You can embed a video with the following syntax:
|
|
||||||
|
|
||||||
```liquid
|
|
||||||
{% include embed/{Platform}.html id='{ID}' %}
|
|
||||||
```
|
```
|
||||||
Where `Platform` is the lowercase of the platform name, and `ID` is the video ID.
|
|
||||||
|
|
||||||
The following table shows how to get the two parameters we need in a given video URL, and you can also know the currently supported video platforms.
|
## Mathematics
|
||||||
|
|
||||||
| Video URL | Platform | ID |
|
We use [**MathJax**][mathjax] to generate mathematics. For website performance reasons, the mathematical feature won't be loaded by default. But it can be enabled by:
|
||||||
|----------------------------------------------------------------------------------------------------|-----------|:--------------|
|
|
||||||
| [https://www.**youtube**.com/watch?v=**H-B46URT4mg**](https://www.youtube.com/watch?v=H-B46URT4mg) | `youtube` | `H-B46URT4mg` |
|
|
||||||
| [https://www.**twitch**.tv/videos/**1634779211**](https://www.twitch.tv/videos/1634779211) | `twitch` | `1634779211` |
|
|
||||||
|
|
||||||
|
[mathjax]: https://www.mathjax.org/
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
math: true
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
After enabling the mathematical feature, you can add math equations with the following syntax:
|
||||||
|
|
||||||
|
- **Block math** should be added with `$$ math $$` with **mandatory** blank lines before and after `$$`
|
||||||
|
- **Inserting equation numbering** should be added with `$$\begin{equation} math \end{equation}$$`
|
||||||
|
- **Referencing equation numbering** should be done with `\label{eq:label_name}` in the equation block and `\eqref{eq:label_name}` inline with text (see example below)
|
||||||
|
- **Inline math** (in lines) should be added with `$$ math $$` without any blank line before or after `$$`
|
||||||
|
- **Inline math** (in lists) should be added with `\$$ math $$`
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
<!-- Block math, keep all blank lines -->
|
||||||
|
|
||||||
|
$$
|
||||||
|
LaTeX_math_expression
|
||||||
|
$$
|
||||||
|
|
||||||
|
<!-- Equation numbering, keep all blank lines -->
|
||||||
|
|
||||||
|
$$
|
||||||
|
\begin{equation}
|
||||||
|
LaTeX_math_expression
|
||||||
|
\label{eq:label_name}
|
||||||
|
\end{equation}
|
||||||
|
$$
|
||||||
|
|
||||||
|
Can be referenced as \eqref{eq:label_name}.
|
||||||
|
|
||||||
|
<!-- Inline math in lines, NO blank lines -->
|
||||||
|
|
||||||
|
"Lorem ipsum dolor sit amet, $$ LaTeX_math_expression $$ consectetur adipiscing elit."
|
||||||
|
|
||||||
|
<!-- Inline math in lists, escape the first `$` -->
|
||||||
|
|
||||||
|
1. \$$ LaTeX_math_expression $$
|
||||||
|
2. \$$ LaTeX_math_expression $$
|
||||||
|
3. \$$ LaTeX_math_expression $$
|
||||||
|
```
|
||||||
|
|
||||||
|
> Starting with `v7.0.0`, configuration options for **MathJax** have been moved to file `assets/js/data/mathjax.js`{: .filepath }, and you can change the options as needed, such as adding [extensions][mathjax-exts].
|
||||||
|
> If you are building the site via `chirpy-starter`, copy that file from the gem installation directory (check with command `bundle info --path jekyll-theme-chirpy`) to the same directory in your repository.
|
||||||
|
{: .prompt-tip }
|
||||||
|
|
||||||
|
[mathjax-exts]: https://docs.mathjax.org/en/latest/input/tex/extensions/index.html
|
||||||
|
|
||||||
|
## Mermaid
|
||||||
|
|
||||||
|
[**Mermaid**](https://github.com/mermaid-js/mermaid) is a great diagram generation tool. To enable it on your post, add the following to the YAML block:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
mermaid: true
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can use it like other markdown languages: surround the graph code with ```` ```mermaid ```` and ```` ``` ````.
|
||||||
|
|
||||||
## Learn More
|
## Learn More
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
---
|
---
|
||||||
title: Getting Started
|
title: Getting Started
|
||||||
|
description: >-
|
||||||
|
Get started with Chirpy basics in this comprehensive overview.
|
||||||
|
You will learn how to install, configure, and use your first Chirpy-based website, as well as deploy it to a web server.
|
||||||
author: cotes
|
author: cotes
|
||||||
date: 2019-08-09 20:55:00 +0800
|
date: 2019-08-09 20:55:00 +0800
|
||||||
categories: [Blogging, Tutorial]
|
categories: [Blogging, Tutorial]
|
||||||
tags: [getting started]
|
tags: [getting started]
|
||||||
pin: true
|
pin: true
|
||||||
img_path: '/posts/20180809'
|
media_subpath: '/posts/20180809'
|
||||||
---
|
---
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
@@ -18,8 +21,8 @@ Follow the instructions in the [Jekyll Docs](https://jekyllrb.com/docs/installat
|
|||||||
|
|
||||||
There are two ways to create a new repository for this theme:
|
There are two ways to create a new repository for this theme:
|
||||||
|
|
||||||
- [**Using the Chirpy Starter**](#option-1-using-the-chirpy-starter) - Easy to upgrade, isolates irrelevant project files so you can focus on writing.
|
- [**Using the Chirpy Starter**](#option-1-using-the-chirpy-starter) — Easy to upgrade, isolates irrelevant project files so you can focus on writing.
|
||||||
- [**GitHub Fork**](#option-2-github-fork) - Convenient for custom development, but difficult to upgrade. Unless you are familiar with Jekyll and are determined to tweak or contribute to this project, this approach is not recommended.
|
- [**GitHub Fork**](#option-2-github-fork) — Convenient for custom development, but difficult to upgrade. Unless you are familiar with Jekyll and are determined to tweak or contribute to this project, this approach is not recommended.
|
||||||
|
|
||||||
#### Option 1. Using the Chirpy Starter
|
#### Option 1. Using the Chirpy Starter
|
||||||
|
|
||||||
@@ -29,7 +32,7 @@ Sign in to GitHub and browse to [**Chirpy Starter**][starter], click the button
|
|||||||
|
|
||||||
Sign in to GitHub to [fork **Chirpy**](https://github.com/cotes2020/jekyll-theme-chirpy/fork), and then rename it to `USERNAME.github.io` (`USERNAME` means your username).
|
Sign in to GitHub to [fork **Chirpy**](https://github.com/cotes2020/jekyll-theme-chirpy/fork), and then rename it to `USERNAME.github.io` (`USERNAME` means your username).
|
||||||
|
|
||||||
Next, clone your site to local machine. In order to build JavaScript files later, we need to install [Node.js][nodejs], and then run the tool:
|
Next, clone the repository to your local machine, make sure it has [Node.js][nodejs] installed, then go to the root directory of the repo and run the following command:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ bash tools/init
|
$ bash tools/init
|
||||||
@@ -42,7 +45,7 @@ The above command will:
|
|||||||
|
|
||||||
1. Check out the code to the [latest tag][latest-tag] (to ensure the stability of your site: as the code for the default branch is under development).
|
1. Check out the code to the [latest tag][latest-tag] (to ensure the stability of your site: as the code for the default branch is under development).
|
||||||
2. Remove non-essential sample files and take care of GitHub-related files.
|
2. Remove non-essential sample files and take care of GitHub-related files.
|
||||||
3. Build JavaScript files and export to `assets/js/dist/`{: .filepath }, then make them tracked by Git.
|
3. Build CSS/JS assets files and then make them tracked by Git.
|
||||||
4. Automatically create a new commit to save the changes above.
|
4. Automatically create a new commit to save the changes above.
|
||||||
|
|
||||||
### Installing Dependencies
|
### Installing Dependencies
|
||||||
@@ -101,7 +104,7 @@ Now you can choose _ONE_ of the following methods to deploy your Jekyll site.
|
|||||||
There are a few things to get ready for.
|
There are a few things to get ready for.
|
||||||
|
|
||||||
- If you're on the GitHub Free plan, keep your site repository public.
|
- If you're on the GitHub Free plan, keep your site repository public.
|
||||||
- If you have committed `Gemfile.lock`{: .filepath} to the repository, and your local machine is not running Linux, go the the root of your site and update the platform list of the lock-file:
|
- If you have committed `Gemfile.lock`{: .filepath} to the repository, and your local machine is not running Linux, go to the root of your site and update the platform list of the lock-file:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ bundle lock --add-platform x86_64-linux
|
$ bundle lock --add-platform x86_64-linux
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ The following table will help you understand the changes to the favicon files:
|
|||||||
| `*.PNG` | ✓ | ✗ |
|
| `*.PNG` | ✓ | ✗ |
|
||||||
| `*.ICO` | ✓ | ✗ |
|
| `*.ICO` | ✓ | ✗ |
|
||||||
|
|
||||||
|
<!-- markdownlint-disable-next-line -->
|
||||||
> ✓ means keep, ✗ means delete.
|
> ✓ means keep, ✗ means delete.
|
||||||
{: .prompt-info }
|
{: .prompt-info }
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
/*
|
/* The common styles */
|
||||||
The common styles
|
|
||||||
*/
|
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@media (prefers-color-scheme: light) {
|
@media (prefers-color-scheme: light) {
|
||||||
@@ -86,6 +84,10 @@ blockquote {
|
|||||||
padding-left: 1rem;
|
padding-left: 1rem;
|
||||||
color: var(--blockquote-text-color);
|
color: var(--blockquote-text-color);
|
||||||
|
|
||||||
|
> p:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
&[class^='prompt-'] {
|
&[class^='prompt-'] {
|
||||||
border-left: 0;
|
border-left: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -103,10 +105,6 @@ blockquote {
|
|||||||
text-rendering: auto;
|
text-rendering: auto;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
> p:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@include prompt('tip', '\f0eb', 'regular');
|
@include prompt('tip', '\f0eb', 'regular');
|
||||||
@@ -131,6 +129,11 @@ kbd {
|
|||||||
box-shadow: inset 0 -2px 0 var(--kbd-wrap-color);
|
box-shadow: inset 0 -2px 0 var(--kbd-wrap-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-color: var(--main-border-color);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
background-color: var(--main-bg);
|
background-color: var(--main-bg);
|
||||||
height: $footer-height;
|
height: $footer-height;
|
||||||
@@ -146,6 +149,10 @@ footer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
em {
|
||||||
|
@extend %text-highlight;
|
||||||
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
@@ -362,7 +369,6 @@ main {
|
|||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
@@ -548,16 +554,32 @@ main {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
|
||||||
@extend %rounded;
|
@extend %rounded;
|
||||||
|
|
||||||
&.youtube {
|
|
||||||
aspect-ratio: 16 / 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.twitch {
|
&.twitch {
|
||||||
aspect-ratio: 310 / 189;
|
aspect-ratio: 310 / 189;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.file {
|
||||||
|
display: block;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
margin: auto;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@extend %img-caption;
|
||||||
|
}
|
||||||
|
|
||||||
|
.embed-audio {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
@extend %img-caption;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- buttons --- */
|
/* --- buttons --- */
|
||||||
@@ -574,26 +596,6 @@ main {
|
|||||||
|
|
||||||
/* --- Effects classes --- */
|
/* --- Effects classes --- */
|
||||||
|
|
||||||
.loaded {
|
|
||||||
display: block !important;
|
|
||||||
|
|
||||||
@at-root .d-flex#{&} {
|
|
||||||
display: flex !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.unloaded {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.visible {
|
|
||||||
visibility: visible !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hidden {
|
|
||||||
visibility: hidden !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-grow-1 {
|
.flex-grow-1 {
|
||||||
flex-grow: 1 !important;
|
flex-grow: 1 !important;
|
||||||
}
|
}
|
||||||
@@ -640,28 +642,16 @@ main {
|
|||||||
|
|
||||||
.left {
|
.left {
|
||||||
float: left;
|
float: left;
|
||||||
margin: 0.75rem 1rem 1rem 0 !important;
|
margin: 0.75rem 1rem 1rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right {
|
.right {
|
||||||
float: right;
|
float: right;
|
||||||
margin: 0.75rem 0 1rem 1rem !important;
|
margin: 0.75rem 0 1rem 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Overriding --- */
|
/* --- Overriding --- */
|
||||||
|
|
||||||
/* magnific-popup */
|
|
||||||
|
|
||||||
figure .mfp-title {
|
|
||||||
text-align: center;
|
|
||||||
padding-right: 0;
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mfp-img {
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* mermaid */
|
/* mermaid */
|
||||||
.mermaid {
|
.mermaid {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -833,7 +823,10 @@ $btn-mb: 0.5rem;
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
box-shadow: var(--sidebar-border-color) 0 0 0 1px;
|
|
||||||
|
&:not(:focus-visible) {
|
||||||
|
box-shadow: var(--sidebar-border-color) 0 0 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--sidebar-hover-bg);
|
background-color: var(--sidebar-hover-bg);
|
||||||
@@ -854,10 +847,7 @@ $btn-mb: 0.5rem;
|
|||||||
line-height: $btn-size;
|
line-height: $btn-size;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mode-toggle {
|
#mode-toggle {
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
|
|
||||||
@extend %button;
|
@extend %button;
|
||||||
@extend %sidebar-links;
|
@extend %sidebar-links;
|
||||||
@extend %sidebar-link-hover;
|
@extend %sidebar-link-hover;
|
||||||
@@ -1136,7 +1126,8 @@ search {
|
|||||||
/* --- button back-to-top --- */
|
/* --- button back-to-top --- */
|
||||||
|
|
||||||
#back-to-top {
|
#back-to-top {
|
||||||
display: none;
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -1149,8 +1140,7 @@ search {
|
|||||||
height: $back2top-size;
|
height: $back2top-size;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border: 1px solid var(--btn-backtotop-border-color);
|
border: 1px solid var(--btn-backtotop-border-color);
|
||||||
transition: transform 0.2s ease-out;
|
transition: opacity 0.5s ease-in-out, transform 0.2s ease-out;
|
||||||
-webkit-transition: transform 0.2s ease-out;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: translate3d(0, -5px, 0);
|
transform: translate3d(0, -5px, 0);
|
||||||
@@ -1162,6 +1152,11 @@ search {
|
|||||||
position: relative;
|
position: relative;
|
||||||
bottom: 2px;
|
bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.show {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#notification {
|
#notification {
|
||||||
|
|||||||
@@ -104,10 +104,6 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
|
||||||
border-color: var(--main-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* categories */
|
/* categories */
|
||||||
.categories.card,
|
.categories.card,
|
||||||
.list-group-item {
|
.list-group-item {
|
||||||
|
|||||||
@@ -14,20 +14,33 @@
|
|||||||
padding-right: $pr;
|
padding-right: $pr;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 + .post-meta {
|
header {
|
||||||
> span + span::before {
|
.post-desc {
|
||||||
@include dot;
|
@extend %heading;
|
||||||
|
|
||||||
|
font-size: 1.125rem;
|
||||||
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
em,
|
.post-meta {
|
||||||
time {
|
span + span::before {
|
||||||
@extend %text-highlight;
|
@include dot;
|
||||||
}
|
|
||||||
|
|
||||||
em {
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
em,
|
||||||
|
time {
|
||||||
|
@extend %text-highlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
em {
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 + .post-meta {
|
||||||
|
margin-top: 1.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
_sass/main.bundle.scss
Normal file
2
_sass/main.bundle.scss
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
@import 'dist/bootstrap';
|
||||||
|
@import 'main';
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
---
|
---
|
||||||
---
|
---
|
||||||
|
|
||||||
@import 'main';
|
@import 'main
|
||||||
|
{%- if jekyll.environment == 'production' -%}
|
||||||
|
.bundle
|
||||||
|
{%- endif -%}
|
||||||
|
';
|
||||||
|
|
||||||
/* append your custom style below */
|
/* append your custom style below */
|
||||||
|
|||||||
@@ -45,14 +45,7 @@ permalink: /feed.xml
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if post.summary %}
|
<summary>{% include post-description.html max_length=400 %}</summary>
|
||||||
<summary>{{ post.summary | strip }}</summary>
|
|
||||||
{% else %}
|
|
||||||
<summary>
|
|
||||||
{% include no-linenos.html content=post.content %}
|
|
||||||
{{ content | strip_html | truncate: 400 }}
|
|
||||||
</summary>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</entry>
|
</entry>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
25
assets/js/data/mathjax.js
Normal file
25
assets/js/data/mathjax.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
layout: compress
|
||||||
|
# WARNING: Don't use '//' to comment out code, use '{% comment %}' and '{% endcomment %}' instead.
|
||||||
|
---
|
||||||
|
|
||||||
|
{%- comment -%}
|
||||||
|
See: <https://docs.mathjax.org/en/latest/options/input/tex.html#tex-options>
|
||||||
|
{%- endcomment -%}
|
||||||
|
|
||||||
|
MathJax = {
|
||||||
|
tex: {
|
||||||
|
{%- comment -%} start/end delimiter pairs for in-line math {%- endcomment -%}
|
||||||
|
inlineMath: [
|
||||||
|
['$', '$'],
|
||||||
|
['\\(', '\\)']
|
||||||
|
],
|
||||||
|
{%- comment -%} start/end delimiter pairs for display math {%- endcomment -%}
|
||||||
|
displayMath: [
|
||||||
|
['$$', '$$'],
|
||||||
|
['\\[', '\\]']
|
||||||
|
],
|
||||||
|
{%- comment -%} equation numbering {%- endcomment -%}
|
||||||
|
tags: 'ams'
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
---
|
|
||||||
layout: compress
|
|
||||||
# The list to be cached by PWA
|
|
||||||
---
|
|
||||||
|
|
||||||
const resource = [
|
|
||||||
/* --- CSS --- */
|
|
||||||
'{{ "/assets/css/:THEME.css" | replace: ':THEME', site.theme | relative_url }}',
|
|
||||||
|
|
||||||
/* --- PWA --- */
|
|
||||||
'{{ "/app.js" | relative_url }}',
|
|
||||||
'{{ "/sw.js" | relative_url }}',
|
|
||||||
|
|
||||||
/* --- HTML --- */
|
|
||||||
'{{ "/index.html" | relative_url }}',
|
|
||||||
'{{ "/404.html" | relative_url }}',
|
|
||||||
|
|
||||||
{% for tab in site.tabs %}
|
|
||||||
'{{ tab.url | relative_url }}',
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
/* --- Favicons & compressed JS --- */
|
|
||||||
{% assign cache_list = site.static_files | where: 'swcache', true %}
|
|
||||||
{% for file in cache_list %}
|
|
||||||
'{{ file.path | relative_url }}'{%- unless forloop.last -%},{%- endunless -%}
|
|
||||||
{% endfor %}
|
|
||||||
];
|
|
||||||
|
|
||||||
/* The request url with below domain will be cached */
|
|
||||||
const allowedDomains = [
|
|
||||||
{% if site.google_analytics.id != empty and site.google_analytics.id %}
|
|
||||||
'www.googletagmanager.com',
|
|
||||||
'www.google-analytics.com',
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
'{{ site.url | split: "//" | last }}',
|
|
||||||
|
|
||||||
{% if site.img_cdn contains '//' and site.img_cdn %}
|
|
||||||
'{{ site.img_cdn | split: '//' | last | split: '/' | first }}',
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
'fonts.gstatic.com',
|
|
||||||
'fonts.googleapis.com',
|
|
||||||
'cdn.jsdelivr.net',
|
|
||||||
'polyfill.io'
|
|
||||||
];
|
|
||||||
|
|
||||||
/* Requests that include the following path will be banned */
|
|
||||||
const denyUrls = [];
|
|
||||||
37
assets/js/data/swconf.js
Normal file
37
assets/js/data/swconf.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
layout: compress
|
||||||
|
permalink: '/:path/swconf.js'
|
||||||
|
# Note that this file will be fetched by the ServiceWorker, so it will not be cached.
|
||||||
|
---
|
||||||
|
|
||||||
|
const swconf = {
|
||||||
|
{% if site.pwa.cache.enabled %}
|
||||||
|
cacheName: 'chirpy-{{ "now" | date: "%s" }}',
|
||||||
|
|
||||||
|
{%- comment -%} Resources added to the cache during PWA installation. {%- endcomment -%}
|
||||||
|
resources: [
|
||||||
|
'{{ "/assets/css/:THEME.css" | replace: ':THEME', site.theme | relative_url }}',
|
||||||
|
'{{ "/" | relative_url }}',
|
||||||
|
{% for tab in site.tabs %}
|
||||||
|
'{{- tab.url | relative_url -}}',
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% assign cache_list = site.static_files | where: 'swcache', true %}
|
||||||
|
{% for file in cache_list %}
|
||||||
|
'{{ file.path | relative_url }}'{%- unless forloop.last -%},{%- endunless -%}
|
||||||
|
{% endfor %}
|
||||||
|
],
|
||||||
|
|
||||||
|
{%- comment -%} The request url with below path will not be cached. {%- endcomment -%}
|
||||||
|
denyPaths: [
|
||||||
|
{% for path in site.pwa.cache.deny_paths %}
|
||||||
|
{% unless path == empty %}
|
||||||
|
'{{ path | relative_url }}'{%- unless forloop.last -%},{%- endunless -%}
|
||||||
|
{% endunless %}
|
||||||
|
{% endfor %}
|
||||||
|
],
|
||||||
|
purge: false
|
||||||
|
{% else %}
|
||||||
|
purge: true
|
||||||
|
{% endif %}
|
||||||
|
};
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
---
|
|
||||||
layout: compress
|
|
||||||
permalink: '/app.js'
|
|
||||||
---
|
|
||||||
|
|
||||||
const $notification = $('#notification');
|
|
||||||
const $btnRefresh = $('#notification .toast-body>button');
|
|
||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
/* Registering Service Worker */
|
|
||||||
navigator.serviceWorker.register('{{ "/sw.js" | relative_url }}')
|
|
||||||
.then(registration => {
|
|
||||||
|
|
||||||
/* in case the user ignores the notification */
|
|
||||||
if (registration.waiting) {
|
|
||||||
$notification.toast('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
registration.addEventListener('updatefound', () => {
|
|
||||||
registration.installing.addEventListener('statechange', () => {
|
|
||||||
if (registration.waiting) {
|
|
||||||
if (navigator.serviceWorker.controller) {
|
|
||||||
$notification.toast('show');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$btnRefresh.click(() => {
|
|
||||||
if (registration.waiting) {
|
|
||||||
registration.waiting.postMessage('SKIP_WAITING');
|
|
||||||
}
|
|
||||||
$notification.toast('hide');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let refreshing = false;
|
|
||||||
|
|
||||||
/* Detect controller change and refresh all the opened tabs */
|
|
||||||
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
|
||||||
if (!refreshing) {
|
|
||||||
window.location.reload();
|
|
||||||
refreshing = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
---
|
|
||||||
layout: compress
|
|
||||||
permalink: '/sw.js'
|
|
||||||
# PWA service worker
|
|
||||||
---
|
|
||||||
|
|
||||||
self.importScripts('{{ "/assets/js/data/swcache.js" | relative_url }}');
|
|
||||||
|
|
||||||
const cacheName = 'chirpy-{{ "now" | date: "%s" }}';
|
|
||||||
|
|
||||||
function verifyDomain(url) {
|
|
||||||
for (const domain of allowedDomains) {
|
|
||||||
const regex = RegExp(`^http(s)?:\/\/${domain}\/`);
|
|
||||||
if (regex.test(url)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isExcluded(url) {
|
|
||||||
for (const item of denyUrls) {
|
|
||||||
if (url === item) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.addEventListener('install', (event) => {
|
|
||||||
event.waitUntil(
|
|
||||||
caches.open(cacheName).then((cache) => {
|
|
||||||
return cache.addAll(resource);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
self.addEventListener('activate', (event) => {
|
|
||||||
event.waitUntil(
|
|
||||||
caches.keys().then((keyList) => {
|
|
||||||
return Promise.all(
|
|
||||||
keyList.map((key) => {
|
|
||||||
if (key !== cacheName) {
|
|
||||||
return caches.delete(key);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
self.addEventListener('message', (event) => {
|
|
||||||
if (event.data === 'SKIP_WAITING') {
|
|
||||||
self.skipWaiting();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
self.addEventListener('fetch', (event) => {
|
|
||||||
event.respondWith(
|
|
||||||
caches.match(event.request).then((response) => {
|
|
||||||
if (response) {
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fetch(event.request).then((response) => {
|
|
||||||
const url = event.request.url;
|
|
||||||
|
|
||||||
if (
|
|
||||||
event.request.method !== 'GET' ||
|
|
||||||
!verifyDomain(url) ||
|
|
||||||
isExcluded(url)
|
|
||||||
) {
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* see: <https://developers.google.com/web/fundamentals/primers/service-workers#cache_and_return_requests> */
|
|
||||||
let responseToCache = response.clone();
|
|
||||||
|
|
||||||
caches.open(cacheName).then((cache) => {
|
|
||||||
/* console.log('[sw] Caching new resource: ' + event.request.url); */
|
|
||||||
cache.put(event.request, responseToCache);
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
---
|
|
||||||
layout: compress
|
|
||||||
permalink: '/unregister.js'
|
|
||||||
---
|
|
||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
navigator.serviceWorker.getRegistrations().then((registrations) => {
|
|
||||||
for (let reg of registrations) {
|
|
||||||
reg.unregister();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Submodule assets/lib updated: 97d95fdb5e...b9c58cf485
@@ -1,6 +1,134 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
## [7.0.1](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v7.0.0...v7.0.1) (2024-05-18)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **analytics:** goatcounter pv greater than 1K cannot be converted to numbers ([#1762](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1762)) ([33a1fa7](https://github.com/cotes2020/jekyll-theme-chirpy/commit/33a1fa7cae2181625e2f335708d59de4dd20ee7d))
|
||||||
|
* audio/video path apply variable `media_subpath` ([#1745](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1745)) ([00a27a1](https://github.com/cotes2020/jekyll-theme-chirpy/commit/00a27a1b85f665d0642b77babd54c6903fbdeb22))
|
||||||
|
|
||||||
|
## [7.0.0](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.5.5...v7.0.0) (2024-05-11)
|
||||||
|
|
||||||
|
### ⚠ BREAKING CHANGES
|
||||||
|
|
||||||
|
* optimize the resource hints (#1717)
|
||||||
|
* rename media-url file and related parameters (#1651)
|
||||||
|
* rename comment setting parameter (#1563)
|
||||||
|
* **analytics:** add post pageviews for GoatCounter (#1543)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add cloudflare web analytics ([#1723](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1723)) ([c17fba4](https://github.com/cotes2020/jekyll-theme-chirpy/commit/c17fba44f53767c9dfaa8d92cfc6e275e5977f8a))
|
||||||
|
* add support for embed video files ([#1558](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1558)) ([9592146](https://github.com/cotes2020/jekyll-theme-chirpy/commit/9592146ca392236e69ee358412ecc32ef1662127))
|
||||||
|
* add support for giscus strict title matching ([#1614](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1614)) ([700fd5b](https://github.com/cotes2020/jekyll-theme-chirpy/commit/700fd5bad7272dd950f861e8550215cd8fafb413))
|
||||||
|
* **analytics:** add post pageviews for GoatCounter ([#1543](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1543)) ([b641b3f](https://github.com/cotes2020/jekyll-theme-chirpy/commit/b641b3f1f2e54bcfe96d8dff46d4f94186492d98))
|
||||||
|
* **analytics:** add Umami and Matomo tracking codes ([#1658](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1658)) ([61bdca2](https://github.com/cotes2020/jekyll-theme-chirpy/commit/61bdca2db45179cd0d1b4b885a4c4864e3ffa3c1))
|
||||||
|
* change site verification settings ([#1561](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1561)) ([e436387](https://github.com/cotes2020/jekyll-theme-chirpy/commit/e4363871b5be0608d2b92b8aff482825a8044c1b))
|
||||||
|
* **deps:** move `MathJax` configuration to a separate file ([#1670](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1670)) ([44f552c](https://github.com/cotes2020/jekyll-theme-chirpy/commit/44f552cbcee83d037de0e59496bf6bb19eea2691))
|
||||||
|
* display theme version in footer ([#1611](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1611)) ([8349314](https://github.com/cotes2020/jekyll-theme-chirpy/commit/834931486dc3e5ed544ce4ff47cd1b2bc45f42fd))
|
||||||
|
* **i18n:** allow `page.lang` to override `site.lang` ([#1586](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1586)) ([547b95c](https://github.com/cotes2020/jekyll-theme-chirpy/commit/547b95cc7ae35018dadcc01b6eb1dc8c8943e67e))
|
||||||
|
* make post description customizable ([#1602](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1602)) ([f865336](https://github.com/cotes2020/jekyll-theme-chirpy/commit/f865336c896e0db34edf8482a53e0e5d8f07ff95))
|
||||||
|
* **media:** support audio and video tag with multi sources ([#1618](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1618)) ([23be416](https://github.com/cotes2020/jekyll-theme-chirpy/commit/23be4162b3f8598db14dc5b39726932ccf2cdc23))
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* make TOC title and entries visible at the same time ([#1711](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1711)) ([e0950fc](https://github.com/cotes2020/jekyll-theme-chirpy/commit/e0950fc973d029dc65d0bc1bd68f3d11242527c8))
|
||||||
|
* mode toggle not outlined when receiving keyboard focus ([#1690](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1690)) ([cd37f63](https://github.com/cotes2020/jekyll-theme-chirpy/commit/cd37f63a0144e0499ea991d3309da064ad5eccea))
|
||||||
|
* prevent footnote back arrow from becoming an emoji ([#1716](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1716)) ([8608147](https://github.com/cotes2020/jekyll-theme-chirpy/commit/8608147fb5037804695d93496c62f96b9c41e9cd))
|
||||||
|
* **pwa:** skip range requests in service worker ([#1672](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1672)) ([76d58fe](https://github.com/cotes2020/jekyll-theme-chirpy/commit/76d58fe0ffdc4bd1df35b60815e97560c3564700))
|
||||||
|
* search result prompt is empty ([#1583](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1583)) ([8a2afae](https://github.com/cotes2020/jekyll-theme-chirpy/commit/8a2afae6cab8fc9639be0a866b71699c8a80084c))
|
||||||
|
* use `https` for Weibo sharing URL ([#1612](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1612)) ([8e5fbb7](https://github.com/cotes2020/jekyll-theme-chirpy/commit/8e5fbb7a74d04a4b3cdde69bcc821f8ccd1a3bc0))
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
* improve \<hr> visibility in dark mode ([#1565](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1565)) ([4ddd5c4](https://github.com/cotes2020/jekyll-theme-chirpy/commit/4ddd5c437046a1e70cf396113e2351c452a25493))
|
||||||
|
* lean bootstrap javascript ([#1734](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1734)) ([ddb48ed](https://github.com/cotes2020/jekyll-theme-chirpy/commit/ddb48eda52827aae16aff720212d7b6d2d8647f9))
|
||||||
|
* rename comment setting parameter ([#1563](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1563)) ([f8390d4](https://github.com/cotes2020/jekyll-theme-chirpy/commit/f8390d4384600fb015728b1b186570fa58ca216f))
|
||||||
|
* replace jQuery with Vanilla JS ([#1681](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1681)) ([fe7afa3](https://github.com/cotes2020/jekyll-theme-chirpy/commit/fe7afa379f0af0ca98a207f85bdc0fa98575b1ad))
|
||||||
|
* simplify mode toggle script ([#1692](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1692)) ([d4a6d64](https://github.com/cotes2020/jekyll-theme-chirpy/commit/d4a6d640bd6d4ab185faf96c0255369a9903ee1d))
|
||||||
|
* tree shaking Bootstrap CSS ([#1736](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1736)) ([363a3d9](https://github.com/cotes2020/jekyll-theme-chirpy/commit/363a3d936bbd688fa4f28527e85ef7dd3fe3a79b))
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
* optimize the resource hints ([#1717](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1717)) ([dcb0add](https://github.com/cotes2020/jekyll-theme-chirpy/commit/dcb0add47bf1adf92215514f1ccfa4661d5215be))
|
||||||
|
* rename media-url file and related parameters ([#1651](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1651)) ([9f8aeaa](https://github.com/cotes2020/jekyll-theme-chirpy/commit/9f8aeaadbfef9967a9b0a9dd323d8bed46e14d9f))
|
||||||
|
|
||||||
|
## [6.5.5](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.5.4...v6.5.5) (2024-03-23)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **post:** correct the image URLs ([#1627](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1627)) ([2d649aa](https://github.com/cotes2020/jekyll-theme-chirpy/commit/2d649aae0e40a24db1ab0d46fa474294e96cb135))
|
||||||
|
|
||||||
|
## [6.5.4](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.5.3...v6.5.4) (2024-03-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* correct the attribute for the Twitter social image ([#1615](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1615)) ([cfe44f2](https://github.com/cotes2020/jekyll-theme-chirpy/commit/cfe44f204bcec8e05f498512ec50878e626a124f))
|
||||||
|
* **seo:** correct social preview image path inside `<meta>` tag ([#1623](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1623)) ([74cf57a](https://github.com/cotes2020/jekyll-theme-chirpy/commit/74cf57aaacf6674057e6f33240a22f4888cfe88f))
|
||||||
|
|
||||||
|
## [6.5.3](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.5.2...v6.5.3) (2024-03-07)
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
* replace `polyfill.io` with `cdnjs` hosted link ([#1598](https://github.com/cotes2020/jekyll-theme-chirpy/pull/1598)) ([75a3d73](https://github.com/cotes2020/jekyll-theme-chirpy/commit/75a3d7399b257256a09d602cbe01062fe1cdf68d))
|
||||||
|
|
||||||
|
## [6.5.2](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.5.1...v6.5.2) (2024-02-29)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* correct the base URL parameter name ([#1576](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1576)) ([19d6baf](https://github.com/cotes2020/jekyll-theme-chirpy/commit/19d6bafbe1a60614e0d63b961bc73c342a9f6f33)), closes [#1553](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1553)
|
||||||
|
|
||||||
|
## [6.5.1](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.5.0...v6.5.1) (2024-02-26)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* correct the generation of relative resource paths ([#1553](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1553)) ([89b9625](https://github.com/cotes2020/jekyll-theme-chirpy/commit/89b962557a56ccc13eba3c9c20b4270ee9d30042))
|
||||||
|
|
||||||
|
## [6.5.0](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.4.2...v6.5.0) (2024-02-14)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add `pwa.cache.*` option to precisely control caching ([#1501](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1501)) ([1127c43](https://github.com/cotes2020/jekyll-theme-chirpy/commit/1127c43823aac4db7fd80d5bb706ae7b1e129dc6))
|
||||||
|
* add analytics support for GoatCounter ([#1526](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1526)) ([90693ff](https://github.com/cotes2020/jekyll-theme-chirpy/commit/90693ff95e72ca4b5135a7b454a6ab521b995b3e))
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* correct the Twitter Card in social share preview ([#1498](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1498)) ([74f1662](https://github.com/cotes2020/jekyll-theme-chirpy/commit/74f16623c9c4877ef36ac52e8b69c19d1d9a82ba))
|
||||||
|
* missing "/" at the end of URLs for categories and tags in breadcrumb ([#1495](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1495)) ([02e296e](https://github.com/cotes2020/jekyll-theme-chirpy/commit/02e296ed75b7906b2d112c67f9054f5d71919de9))
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
* allow no social links to be configured ([#1494](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1494)) ([4facf5b](https://github.com/cotes2020/jekyll-theme-chirpy/commit/4facf5b390eeba612ca439f3354c5d2d881aac56))
|
||||||
|
* allow TOC to start at heading 3 ([#1512](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1512)) ([bbbb66b](https://github.com/cotes2020/jekyll-theme-chirpy/commit/bbbb66b489a3bf2b878947336fe894e8ea2ae3f5))
|
||||||
|
* enable equation numbering in MathJax ([#1520](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1520)) ([c13ec31](https://github.com/cotes2020/jekyll-theme-chirpy/commit/c13ec311636d5e057c6895e353e1c1a4e570f582))
|
||||||
|
|
||||||
|
## [6.4.2](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.4.1...v6.4.2) (2024-01-13)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* resume the `blockquote` display type ([#1480](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1480)) ([c7cfde0](https://github.com/cotes2020/jekyll-theme-chirpy/commit/c7cfde093020c73ca9a1b83437eb600379e05918)), closes [#1449](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1449)
|
||||||
|
|
||||||
|
## [6.4.1](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.4.0...v6.4.1) (2024-01-10)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* `og:image` URL is incorrect ([#1468](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1468)) ([b2d1cb6](https://github.com/cotes2020/jekyll-theme-chirpy/commit/b2d1cb68db659270aac537d2aa8d4b806fa6991d)), closes [#1463](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1463)
|
||||||
|
|
||||||
|
## [6.4.0](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.3.1...v6.4.0) (2024-01-10)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add bilibili embed video support ([#1406](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1406)) ([4a2b89d](https://github.com/cotes2020/jekyll-theme-chirpy/commit/4a2b89d0b698d672486349131a89025fa47afcb6))
|
||||||
|
* add site-wide social preview image settings ([#1463](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1463)) ([241bb4d](https://github.com/cotes2020/jekyll-theme-chirpy/commit/241bb4df7878cff7f82014df660874a1dcddba76))
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* image float breaks quotes and prompts ([#1449](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1449)) ([ea2d238](https://github.com/cotes2020/jekyll-theme-chirpy/commit/ea2d238bd8adc018256862e05a5092311c87a671)), closes [#1441](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1441)
|
||||||
|
* url-less authors should not have empty links ([#1410](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1410)) ([2a4fbf6](https://github.com/cotes2020/jekyll-theme-chirpy/commit/2a4fbf6a7925da610a75c498116da7cf9ba857d7)), closes [#1403](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1403)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
* include the latest posts in the "Recently Updated" list ([#1456](https://github.com/cotes2020/jekyll-theme-chirpy/issues/1456)) ([82d8f2d](https://github.com/cotes2020/jekyll-theme-chirpy/commit/82d8f2db984711f334f55b6af5098ec16770e824))
|
||||||
|
|
||||||
## [6.3.1](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.3.0...v6.3.1) (2023-11-12)
|
## [6.3.1](https://github.com/cotes2020/jekyll-theme-chirpy/compare/v6.3.0...v6.3.1) (2023-11-12)
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
|:----------|:---------:|
|
| :--------- | :-------: |
|
||||||
| `6.x` | ✓ |
|
| >= `7.0.0` | ✓ |
|
||||||
| < `6.0.0` | ✗ |
|
| <= `6.0.0` | ✗ |
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Gem::Specification.new do |spec|
|
Gem::Specification.new do |spec|
|
||||||
spec.name = "jekyll-theme-chirpy"
|
spec.name = "jekyll-theme-chirpy"
|
||||||
spec.version = "6.3.1"
|
spec.version = "7.0.1"
|
||||||
spec.authors = ["Cotes Chung"]
|
spec.authors = ["Cotes Chung"]
|
||||||
spec.email = ["cotes.chung@gmail.com"]
|
spec.email = ["cotes.chung@gmail.com"]
|
||||||
|
|
||||||
|
|||||||
137
package.json
137
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jekyll-theme-chirpy",
|
"name": "jekyll-theme-chirpy",
|
||||||
"version": "6.3.1",
|
"version": "7.0.1",
|
||||||
"description": "A minimal, responsive, and feature-rich Jekyll theme for technical writing.",
|
"description": "A minimal, responsive, and feature-rich Jekyll theme for technical writing.",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -13,24 +13,40 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/cotes2020/jekyll-theme-chirpy/",
|
"homepage": "https://github.com/cotes2020/jekyll-theme-chirpy/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "npx rimraf assets/js/dist",
|
"build": "concurrently npm:build:*",
|
||||||
"build": "NODE_ENV=production npx rollup -c --bundleConfigAsCjs",
|
"build:css": "purgecss -c purgecss.config.js",
|
||||||
"prewatch": "npx rimraf assets/js/dist",
|
"build:js": "rollup -c --bundleConfigAsCjs --environment BUILD:production",
|
||||||
"watch": "npx rollup -c --bundleConfigAsCjs -w",
|
"watch:js": "rollup -c --bundleConfigAsCjs -w",
|
||||||
"test": "npx stylelint _sass/**/*.scss",
|
"lint:scss": "stylelint _sass/**/*.scss",
|
||||||
"fixlint": "npm run test -- --fix"
|
"lint:fix:scss": "npm run lint:scss -- --fix",
|
||||||
|
"test": "npm run lint:scss"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@popperjs/core": "^2.11.8",
|
||||||
|
"bootstrap": "^5.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.23.2",
|
"@babel/core": "^7.24.5",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
"@babel/plugin-transform-class-properties": "^7.24.1",
|
||||||
"@babel/preset-env": "^7.23.2",
|
"@babel/preset-env": "^7.24.5",
|
||||||
|
"@commitlint/cli": "^19.3.0",
|
||||||
|
"@commitlint/config-conventional": "^19.2.2",
|
||||||
"@rollup/plugin-babel": "^6.0.4",
|
"@rollup/plugin-babel": "^6.0.4",
|
||||||
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"rimraf": "^5.0.5",
|
"@rollup/plugin-yaml": "^4.1.2",
|
||||||
"rollup": "^4.3.0",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"rollup-plugin-license": "^3.2.0",
|
"@semantic-release/exec": "^6.0.3",
|
||||||
"stylelint": "^15.11.0",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"stylelint-config-standard-scss": "^11.1.0"
|
"concurrently": "^8.2.2",
|
||||||
|
"conventional-changelog-conventionalcommits": "^7.0.2",
|
||||||
|
"husky": "^9.0.11",
|
||||||
|
"purgecss": "^6.0.0",
|
||||||
|
"rollup": "^4.17.2",
|
||||||
|
"rollup-plugin-license": "^3.3.1",
|
||||||
|
"semantic-release": "^23.1.1",
|
||||||
|
"stylelint": "^16.5.0",
|
||||||
|
"stylelint-config-standard-scss": "^13.1.0"
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"trailingComma": "none"
|
"trailingComma": "none"
|
||||||
@@ -41,6 +57,9 @@
|
|||||||
"not dead"
|
"not dead"
|
||||||
],
|
],
|
||||||
"commitlint": {
|
"commitlint": {
|
||||||
|
"extends": [
|
||||||
|
"@commitlint/config-conventional"
|
||||||
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"body-max-line-length": [
|
"body-max-line-length": [
|
||||||
0,
|
0,
|
||||||
@@ -83,24 +102,76 @@
|
|||||||
"media-feature-range-notation": "prefix"
|
"media-feature-range-notation": "prefix"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"standard-version": {
|
"release": {
|
||||||
"skip": {
|
"branches": [
|
||||||
"commit": true,
|
"production"
|
||||||
"tag": true
|
],
|
||||||
},
|
"plugins": [
|
||||||
"types": [
|
[
|
||||||
{
|
"@semantic-release/commit-analyzer",
|
||||||
"type": "feat",
|
{
|
||||||
"section": "Features"
|
"preset": "conventionalcommits"
|
||||||
},
|
}
|
||||||
{
|
],
|
||||||
"type": "fix",
|
[
|
||||||
"section": "Bug Fixes"
|
"@semantic-release/release-notes-generator",
|
||||||
},
|
{
|
||||||
{
|
"preset": "conventionalcommits",
|
||||||
"type": "perf",
|
"presetConfig": {
|
||||||
"section": "Improvements"
|
"types": [
|
||||||
}
|
{
|
||||||
|
"type": "feat",
|
||||||
|
"section": "Features"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "fix",
|
||||||
|
"section": "Bug Fixes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "perf",
|
||||||
|
"section": "Improvements"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "refactor",
|
||||||
|
"section": "Changes",
|
||||||
|
"hidden": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/changelog",
|
||||||
|
{
|
||||||
|
"changelogFile": "docs/CHANGELOG.md",
|
||||||
|
"changelogTitle": "# Changelog"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/npm",
|
||||||
|
{
|
||||||
|
"npmPublish": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/exec",
|
||||||
|
{
|
||||||
|
"prepareCmd": "bash tools/release --prepare",
|
||||||
|
"publishCmd": "bash tools/release"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/git",
|
||||||
|
{
|
||||||
|
"assets": [
|
||||||
|
"docs",
|
||||||
|
"package.json",
|
||||||
|
"*.gemspec"
|
||||||
|
],
|
||||||
|
"message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@semantic-release/github"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user