Compare commits
253 commits
Author | SHA1 | Date | |
---|---|---|---|
13f0eb7280 | |||
d549f0cb87 | |||
cd45cc4a60 | |||
75b7685363 | |||
d8e552fd18 | |||
59019bdaa8 | |||
245289e9ad | |||
0c8e50fb0e | |||
6dbf715aa5 | |||
8a9e09466c | |||
e7dd94c311 | |||
7fa39d2f17 | |||
b6723d6264 | |||
f650f0a582 | |||
7849a547cb | |||
89ddb9e9cd | |||
777ef6db0b | |||
9f587e71e7 | |||
e3f34bc6b7 | |||
4a02ad7692 | |||
17d29037ed | |||
dcf4b27a7a | |||
cef6f9be05 | |||
3b99e02782 | |||
e88eab0942 | |||
3e67e3a310 | |||
99dd009236 | |||
771c31cf6c | |||
cfb7af6313 | |||
22021775b6 | |||
8c239f8039 | |||
b0f2e6967c | |||
|
597b7f054d | ||
1892da053d | |||
4bdbf6d9da | |||
f489cd0531 | |||
7d0ea7f93c | |||
c2c1533c68 | |||
e81ba8b0aa | |||
02bbfa90fc | |||
94428ce0b2 | |||
dd99a9b433 | |||
bce4c71cce | |||
fe46634caa | |||
83e59fb385 | |||
a3a04dffa0 | |||
91c83197db | |||
2ea71d8f73 | |||
d216e1a03a | |||
288d1913c5 | |||
eead5f22b6 | |||
edf3c165e2 | |||
3ed4068a7a | |||
1fe8819a62 | |||
0127f66910 | |||
83abc30953 | |||
c842599b98 | |||
b099d6493a | |||
e15d0bc7ba | |||
c3fe15207b | |||
7b5e366190 | |||
1fa85ad116 | |||
cd795de254 | |||
1072e90309 | |||
0207c69dbb | |||
51162e0e83 | |||
8b1448ece2 | |||
75d8a58d5a | |||
3d7143e248 | |||
46c29e2d36 | |||
10482e2043 | |||
9b182762ac | |||
a80fa4eb04 | |||
1a1b06f8b6 | |||
45df394a6c | |||
2ac5780dd7 | |||
aaacb23922 | |||
ed410399da | |||
05847520e3 | |||
2258c29d38 | |||
74ebe95d84 | |||
3b986e5083 | |||
638dd5f9df | |||
a177cd0ebd | |||
0f3cc1cad7 | |||
dda7b9798d | |||
1a2bb1a04b | |||
ee7a1c179c | |||
a572d95fbc | |||
484213fe0c | |||
377d05a32c | |||
2b94110af6 | |||
43aeb033ec | |||
77266430d2 | |||
df3e411f6a | |||
22864c548c | |||
3e054ea47d | |||
642d32128a | |||
e16fbdea5a | |||
eda0c75632 | |||
d071e85a14 | |||
0b5346c623 | |||
|
d51345e297 | ||
|
2f844978aa | ||
|
42dea8ee29 | ||
|
86b13c917f | ||
c357435a9e | |||
c0d583aa9e | |||
effb91dff2 | |||
|
4ef3cd8efc | ||
|
c7f967529c | ||
|
74ed06321c | ||
|
d4f7f39ece | ||
|
c1bd9eb9ee | ||
|
6f461132c0 | ||
|
03e302cbf6 | ||
|
8a064a5e5a | ||
|
740bd84c51 | ||
|
93f616b25d | ||
|
e6b87d2811 | ||
|
73749067c5 | ||
|
fd0df8320f | ||
|
fbcdf8ce85 | ||
|
fac6116af1 | ||
|
5a63244721 | ||
|
3ab3b844d2 | ||
|
367262e74d | ||
|
cbc93193e1 | ||
|
a784f0a0f9 | ||
|
a2bf5dc58e | ||
|
8b7dba71e3 | ||
|
fc3d101258 | ||
|
604e01eb36 | ||
|
31e19c6d0f | ||
|
5f4dab1745 | ||
|
8cfd721494 | ||
|
64c7262245 | ||
|
707a209424 | ||
|
80bd7928a0 | ||
|
83689021be | ||
|
befc4ce9c5 | ||
|
bf6c996c4e | ||
|
99eaf6089e | ||
|
efd2941ce0 | ||
|
7f83c3d00d | ||
|
d74bfaeda2 | ||
|
23729c9c8f | ||
|
e347d0632f | ||
|
35fdea0c4f | ||
|
5c5910f1fc | ||
|
b641b36480 | ||
|
979f86cf64 | ||
|
8c30f0a9c3 | ||
|
e4db1a176f | ||
|
e3a78b6243 | ||
|
8673e1335f | ||
|
a07a57ec92 | ||
|
db9e58bab2 | ||
|
e6532ad864 | ||
|
fbba0a4204 | ||
|
c876731901 | ||
|
9ca7519239 | ||
|
0709854dc8 | ||
|
f1d35832f4 | ||
|
cf853f14e4 | ||
|
7ca9c59784 | ||
|
250880c088 | ||
|
88b844ce80 | ||
|
3b46629dc0 | ||
|
1e3d4a6323 | ||
|
1c5fa0880d | ||
|
64ae7a3671 | ||
|
0102abae06 | ||
|
6cb1a5ac52 | ||
|
20987f2afe | ||
|
39e4338839 | ||
|
33a1fa7cae | ||
|
00a27a1b85 | ||
|
5cdde7dbc5 | ||
|
c4b58e3502 | ||
|
9630fd647f | ||
|
90a4cc76bb | ||
|
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 | ||
|
c5d5e1f75a | ||
|
319a082940 | ||
|
6044df4ff1 | ||
|
700fd5bad7 | ||
|
8e5fbb7a74 | ||
|
834931486d | ||
|
f865336c89 | ||
|
0f8e782bfd | ||
|
547b95cc7a | ||
|
2a7b56bb36 | ||
|
25c4166722 | ||
|
25b2ffa9ba | ||
|
8a2afae6ca | ||
|
6112b15b8e | ||
|
e24a0c73ba | ||
|
0f5abc82a2 | ||
|
4ddd5c4370 | ||
|
9592146ca3 | ||
|
8a1568c27a | ||
|
f8390d4384 | ||
|
e4363871b5 | ||
|
b641b3f1f2 | ||
|
5dbda0c09f |
216 changed files with 3209 additions and 1719 deletions
18
.cpanel.yml
18
.cpanel.yml
|
@ -1,18 +0,0 @@
|
|||
deployment:
|
||||
tasks:
|
||||
- /bin/cp _site/404.html ~/public_html
|
||||
- /bin/cp _site/feed.xml ~/public_html
|
||||
- /bin/cp _site/index.html ~/public_html
|
||||
- /bin/cp _site/redirects.json ~/public_html
|
||||
- /bin/cp _site/robots.txt ~/public_html
|
||||
- /bin/cp _site/sitemap.xml ~/public_html
|
||||
- /bin/cp _site/sw.min.js ~/public_html
|
||||
- /bin/cp -R _site/about ~/public_html
|
||||
- /bin/cp -R _site/archives ~/public_html
|
||||
- /bin/cp -R _site/assets ~/public_html
|
||||
- /bin/cp -R _site/categories ~/public_html
|
||||
- /bin/cp -R _site/donate ~/public_html
|
||||
- /bin/cp -R _site/norobots ~/public_html
|
||||
- /bin/cp -R _site/now ~/public_html
|
||||
- /bin/cp -R _site/posts ~/public_html
|
||||
- /bin/cp -R _site/tags ~/public_html
|
64
.forgejo/workflows/build_and_test.yml
Normal file
64
.forgejo/workflows/build_and_test.yml
Normal file
|
@ -0,0 +1,64 @@
|
|||
name: "Build and Deploy Test Version (with Drafts) - next.asandikci.com"
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- .gitignore
|
||||
- README.md
|
||||
- LICENSE
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-drafts-and-deploy:
|
||||
runs-on: docker
|
||||
container:
|
||||
image: git.asandikci.com/docker-images/website_builder:latest
|
||||
steps:
|
||||
- name: Git Clone
|
||||
run: |
|
||||
git clone https://git.asandikci.com/asandikci.com/web
|
||||
ls -la ./web
|
||||
|
||||
- name: Build Site (with Drafts!)
|
||||
run: |
|
||||
cd web
|
||||
bundle install
|
||||
bundle exec jekyll b --drafts
|
||||
ls -la
|
||||
pwd
|
||||
env:
|
||||
JEKYLL_ENV: "production"
|
||||
|
||||
# TODO: WILL BE FIXED
|
||||
# - name: Test Site
|
||||
# run: |
|
||||
# cd web
|
||||
# bundle exec htmlproofer _site \
|
||||
# \-\-disable-external \
|
||||
# \-\-ignore-urls "/^http:\/\/127.0.0.1/,/^http:\/\/0.0.0.0/,/^http:\/\/localhost/"
|
||||
|
||||
- name: Deploy
|
||||
run: |
|
||||
mkdir deploy && cd deploy
|
||||
cp -rfv ../web/_site .
|
||||
cd _site
|
||||
|
||||
# CURRENTLY USING PURE STFP FOR AUTH ONLY
|
||||
# TODO: CHANGE THIS
|
||||
echo '${{ secrets.SFTP_PASSWORD }}' > ~/.passwd
|
||||
chmod 0400 ~/.passwd
|
||||
sshpass -f ~/.passwd sftp -oBatchMode=no -o StrictHostKeyChecking=accept-new -b - ${{ secrets.SFTP_USERNAME }}@${{ vars.SFTP_HOST }} << !
|
||||
bye
|
||||
!
|
||||
lftp --user ${{ secrets.SFTP_USERNAME }} --password ${{ secrets.SFTP_PASSWORD }} sftp://${{ vars.SFTP_HOST }} -e "mirror -R --delete . www/"
|
67
.forgejo/workflows/deploy_prod.yml
Normal file
67
.forgejo/workflows/deploy_prod.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
name: "Build and Deploy PRODUCTION Version - asandikci.com"
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-and-push-prod:
|
||||
runs-on: docker
|
||||
container:
|
||||
image: git.asandikci.com/docker-images/website_builder:latest
|
||||
steps:
|
||||
- name: Git Clone
|
||||
run: |
|
||||
git clone https://git.asandikci.com/asandikci.com/web
|
||||
ls -la ./web
|
||||
|
||||
- name: Build Site
|
||||
run: |
|
||||
cd web
|
||||
bundle install
|
||||
bundle exec jekyll b
|
||||
env:
|
||||
JEKYLL_ENV: "production"
|
||||
|
||||
- name: Push to "website" branch
|
||||
run: |
|
||||
mkdir website_branch && cd website_branch
|
||||
git clone https://git.asandikci.com/asandikci.com/web
|
||||
cd web
|
||||
git checkout website
|
||||
rm -rfv ./_site/
|
||||
cp -rfv ../../web/_site .
|
||||
git config --global user.name "Aliberk Sandıkçı (CI)"
|
||||
git config --global user.email git+ci@asandikci.com
|
||||
git add -A
|
||||
git commit --all --message "Updated! [CI]"
|
||||
git push https://asandikci:${{ secrets.PUSH_KEY }}@git.asandikci.com/asandikci.com/web
|
||||
|
||||
|
||||
publish:
|
||||
runs-on: docker
|
||||
container:
|
||||
image: git.asandikci.com/docker-images/website_builder:latest
|
||||
steps:
|
||||
- name: Checkout & Deploy
|
||||
run: |
|
||||
git clone https://git.asandikci.com/asandikci.com/web
|
||||
cd web
|
||||
git checkout website
|
||||
cd _site
|
||||
echo '${{ secrets.SFTP_PASSWORD_PROD }}' > ~/.passwd
|
||||
chmod 0400 ~/.passwd
|
||||
sshpass -f ~/.passwd sftp -oBatchMode=no -o StrictHostKeyChecking=accept-new -b - ${{ secrets.SFTP_USERNAME_PROD }}@${{ vars.SFTP_HOST_PROD }} << !
|
||||
put -r . www/
|
||||
bye
|
||||
!
|
||||
|
||||
## TODO: WILL BE REPLACED WITH NEW LFTP SETUP !!!
|
|
@ -1,73 +0,0 @@
|
|||
name: "Build and Deploy"
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
paths-ignore:
|
||||
- .gitignore
|
||||
- README.md
|
||||
- LICENSE
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
# submodules: true
|
||||
# If using the 'assets' git submodule from Chirpy Starter, uncomment above
|
||||
# (See: https://github.com/cotes2020/chirpy-starter/tree/main/assets)
|
||||
|
||||
- name: Setup Pages
|
||||
id: pages
|
||||
uses: actions/configure-pages@v4
|
||||
|
||||
- name: Setup Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.2
|
||||
bundler-cache: true
|
||||
|
||||
- name: Build site
|
||||
run: bundle exec jekyll b -d "_site${{ steps.pages.outputs.base_path }}"
|
||||
env:
|
||||
JEKYLL_ENV: "production"
|
||||
|
||||
- name: Test site
|
||||
run: |
|
||||
bundle exec htmlproofer _site \
|
||||
\-\-disable-external=true \
|
||||
\-\-ignore-urls "/^http:\/\/127.0.0.1/,/^http:\/\/0.0.0.0/,/^http:\/\/localhost/"
|
||||
|
||||
- name: Upload site artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: "_site${{ steps.pages.outputs.base_path }}"
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -5,7 +5,8 @@ Gemfile.lock
|
|||
|
||||
# Jekyll cache
|
||||
.jekyll-cache
|
||||
# _site
|
||||
.jekyll-metadata
|
||||
_site
|
||||
|
||||
# RubyGems
|
||||
*.gem
|
||||
|
@ -16,5 +17,10 @@ package-lock.json
|
|||
|
||||
# IDE configurations
|
||||
.idea
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/tasks.json
|
||||
|
||||
# Misc
|
||||
#_sass/dist
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
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"]
|
||||
}
|
||||
}
|
11
.vscode/extensions.json
vendored
11
.vscode/extensions.json
vendored
|
@ -1,12 +1,3 @@
|
|||
{
|
||||
"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"
|
||||
]
|
||||
"recommendations": ["ms-vscode-remote.remote-containers"]
|
||||
}
|
||||
|
|
14
.vscode/settings.json
vendored
14
.vscode/settings.json
vendored
|
@ -2,23 +2,29 @@
|
|||
// 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"
|
||||
"editor.defaultFormatter": "mkhl.shfmt"
|
||||
},
|
||||
// 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"]
|
||||
"stylelint.snippet": ["css", "scss"],
|
||||
"stylelint.validate": ["css", "scss"],
|
||||
// Run tasks in macOS
|
||||
"terminal.integrated.profiles.osx": {
|
||||
"zsh": { "path": "/bin/zsh", "args": ["-l", "-i"] }
|
||||
}
|
||||
}
|
||||
|
|
64
.vscode/tasks.json
vendored
Normal file
64
.vscode/tasks.json
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Run Jekyll Server",
|
||||
"type": "shell",
|
||||
"command": "./tools/run.sh",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"detail": "Runs the Jekyll server with live reload."
|
||||
},
|
||||
{
|
||||
"label": "Build Jekyll Site",
|
||||
"type": "shell",
|
||||
"command": "./tools/test.sh",
|
||||
"group": {
|
||||
"kind": "build"
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"detail": "Build the Jekyll site for production."
|
||||
},
|
||||
{
|
||||
"label": "Build JS (watch)",
|
||||
"type": "shell",
|
||||
"command": "npm run watch:js",
|
||||
"group": {
|
||||
"kind": "build"
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"detail": "Build JS files in watch mode."
|
||||
},
|
||||
{
|
||||
"label": "Build CSS",
|
||||
"type": "shell",
|
||||
"command": "npm run build:css",
|
||||
"group": {
|
||||
"kind": "build"
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"detail": "Build CSS files."
|
||||
},
|
||||
{
|
||||
"label": "Build JS & CSS",
|
||||
"type": "shell",
|
||||
"command": "npm run build",
|
||||
"group": {
|
||||
"kind": "build"
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"detail": "Build JS & CSS for production."
|
||||
},
|
||||
{
|
||||
"label": "Run Jekyll Server + Build JS (watch)",
|
||||
"dependsOn": ["Run Jekyll Server", "Build JS (watch)"],
|
||||
"group": {
|
||||
"kind": "build"
|
||||
},
|
||||
"detail": "Runs both the Jekyll server with live reload and build JS files in watch mode."
|
||||
}
|
||||
]
|
||||
}
|
6
Dockerfile
Normal file
6
Dockerfile
Normal file
|
@ -0,0 +1,6 @@
|
|||
FROM bitnami/minideb:bookworm-arm64
|
||||
|
||||
RUN apt update -y
|
||||
RUN apt upgrade -y
|
||||
RUN apt install nodejs sshpass ruby jekyll ruby-html-proofer -y
|
||||
|
13
Gemfile
13
Gemfile
|
@ -4,20 +4,11 @@ source "https://rubygems.org"
|
|||
|
||||
gemspec
|
||||
|
||||
group :test do
|
||||
gem "html-proofer", "~> 4.4"
|
||||
end
|
||||
gem "html-proofer", "~> 5.0", group: :test
|
||||
|
||||
# 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]
|
||||
gem "wdm", "~> 0.2.0", :platforms => [:mingw, :x64_mingw, :mswin]
|
||||
|
|
25
README.md
25
README.md
|
@ -1,14 +1,16 @@
|
|||
<!-- markdownlint-disable-next-line -->
|
||||
<div align="center">
|
||||
|
||||
<!-- markdownlint-disable-next-line -->
|
||||
# Chirpy Jekyll Theme
|
||||
|
||||
A minimal, responsive, and feature-rich Jekyll theme for technical writing.
|
||||
|
||||
[![Gem Version](https://img.shields.io/gem/v/jekyll-theme-chirpy?color=brightgreen)][gem]
|
||||
[![CI](https://github.com/cotes2020/jekyll-theme-chirpy/actions/workflows/ci.yml/badge.svg?branch=master&event=push)][ci]
|
||||
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/4e556876a3c54d5e8f2d2857c4f43894)][codacy]
|
||||
[![GitHub license](https://img.shields.io/github/license/cotes2020/jekyll-theme-chirpy.svg)][license]
|
||||
[![996.icu](https://img.shields.io/badge/link-996.icu-%23FF4D5B.svg)](https://996.icu)
|
||||
[![CI](https://img.shields.io/github/actions/workflow/status/cotes2020/jekyll-theme-chirpy/ci.yml?logo=github)][ci]
|
||||
[![Codacy Badge](https://img.shields.io/codacy/grade/4e556876a3c54d5e8f2d2857c4f43894?logo=codacy)][codacy]
|
||||
[![GitHub license](https://img.shields.io/github/license/cotes2020/jekyll-theme-chirpy?color=goldenrod)][license]
|
||||
[![Gem Version](https://img.shields.io/gem/v/jekyll-theme-chirpy?&logo=RubyGems&logoColor=ghostwhite&label=gem&color=orange)][gem]
|
||||
[![Open in Dev Containers](https://img.shields.io/badge/Dev_Containers-Open-deepskyblue?logo=linuxcontainers)][open-container]
|
||||
|
||||
[**Live Demo** →][demo]
|
||||
|
||||
|
@ -18,7 +20,7 @@
|
|||
|
||||
## Features
|
||||
|
||||
- Dark / Light Theme Mode
|
||||
- Dark Theme
|
||||
- Localized UI language
|
||||
- Pinned Posts on Home Page
|
||||
- Hierarchical Categories
|
||||
|
@ -28,13 +30,13 @@
|
|||
- Syntax Highlighting
|
||||
- Mathematical Expressions
|
||||
- Mermaid Diagrams & Flowcharts
|
||||
- Dark / Light Mode Images
|
||||
- Embed Videos
|
||||
- Disqus / Giscus / Utterances Comments
|
||||
- Dark Mode Images
|
||||
- Embed Media
|
||||
- Comment Systems
|
||||
- Built-in Search
|
||||
- Atom Feeds
|
||||
- PWA
|
||||
- Google Analytics / GoatCounter
|
||||
- Web Analytics
|
||||
- SEO & Performance Optimization
|
||||
|
||||
## Documentation
|
||||
|
@ -54,7 +56,7 @@ For details, see the "[Contributing Guidelines][contribute-guide]".
|
|||
Thanks to [all the contributors][contributors] involved in the development of the project!
|
||||
|
||||
[![all-contributors](https://contrib.rocks/image?repo=cotes2020/jekyll-theme-chirpy&columns=16)][contributors]
|
||||
<sub> —— Made with [contrib.rocks](https://contrib.rocks)</sub>
|
||||
<sub> — Made with [contrib.rocks](https://contrib.rocks)</sub>
|
||||
|
||||
### Third-Party Assets
|
||||
|
||||
|
@ -70,6 +72,7 @@ This project is published under [MIT License][license].
|
|||
[ci]: https://github.com/cotes2020/jekyll-theme-chirpy/actions/workflows/ci.yml?query=event%3Apush+branch%3Amaster
|
||||
[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
|
||||
[open-container]: https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/cotes2020/jekyll-theme-chirpy
|
||||
[jekyllrb]: https://jekyllrb.com/
|
||||
[clipartmax]: https://www.clipartmax.com/middle/m2i8b1m2K9Z5m2K9_ant-clipart-childrens-ant-cute/
|
||||
[demo]: https://cotes2020.github.io/chirpy-demo/
|
||||
|
|
31
_config.yml
31
_config.yml
|
@ -15,18 +15,28 @@ baseurl: "/"
|
|||
|
||||
forgejo:
|
||||
username: asandikci
|
||||
domain: 'git.aliberksandikci.com.tr'
|
||||
domain: "git.asandikci.com"
|
||||
|
||||
github:
|
||||
username: asandikci
|
||||
|
||||
social:
|
||||
name: Aliberk Sandıkçı
|
||||
email: contact@aliberksandikci.com.tr
|
||||
links:
|
||||
- https://git.aliberksandikci.com.tr/asandikci
|
||||
- https://git.asandikci.com/asandikci
|
||||
- https://github.com/asandikci
|
||||
- https://mastodon.social/@asandikci
|
||||
- https://www.linkedin.com/in/asandikci
|
||||
|
||||
theme_mode: # [light | dark]
|
||||
|
||||
# Web Analytics Settings
|
||||
analytics:
|
||||
umami:
|
||||
id: 80f4b239-3529-46be-b7a1-df82c6967a87
|
||||
domain: https://analytics.yayindasin.org
|
||||
|
||||
# the avatar on sidebar, support local or CORS resources
|
||||
avatar: https://asandikci.com/assets/img/pp.png
|
||||
|
||||
|
@ -38,8 +48,9 @@ social_preview_image: # string, local or CORS resources
|
|||
toc: true
|
||||
|
||||
comments:
|
||||
active: # The global switch for posts comments, e.g., 'disqus'. Keep it empty means disable
|
||||
# The active options are as follows:
|
||||
# Global switch for the post-comment system. Keeping it empty means disabled.
|
||||
provider: # [disqus | utterances | giscus]
|
||||
# The provider options are as follows:
|
||||
disqus:
|
||||
shortname: # fill with the Disqus shortname. › https://help.disqus.com/en/articles/1717111-what-s-a-shortname
|
||||
# utterances settings › https://utteranc.es/
|
||||
|
@ -53,6 +64,7 @@ comments:
|
|||
category:
|
||||
category_id:
|
||||
mapping: # optional, default to 'pathname'
|
||||
strict: # optional, default to '0'
|
||||
input_position: # optional, default to 'bottom'
|
||||
lang: # optional, default to the value of `site.lang`
|
||||
reactions_enabled: # optional, default to the value of `1`
|
||||
|
@ -66,9 +78,9 @@ assets:
|
|||
env: # [development | production]
|
||||
|
||||
pwa:
|
||||
enabled: true # the option for PWA feature (installable)
|
||||
enabled: true # The option for PWA feature (installable)
|
||||
cache:
|
||||
enabled: true # the option for PWA offline 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.
|
||||
|
@ -80,6 +92,7 @@ paginate: 10
|
|||
# ------------ The following options are not recommended to be modified ------------------
|
||||
|
||||
kramdown:
|
||||
footnote_backlink: "↩︎"
|
||||
syntax_highlighter: rouge
|
||||
syntax_highlighter_opts: # Rouge Options › https://github.com/jneen/rouge#full-options
|
||||
css_class: highlight
|
||||
|
@ -116,10 +129,6 @@ defaults:
|
|||
values:
|
||||
layout: page
|
||||
permalink: /:title/
|
||||
- scope:
|
||||
path: assets/js/dist
|
||||
values:
|
||||
swcache: true
|
||||
|
||||
sass:
|
||||
style: compressed
|
||||
|
@ -140,7 +149,7 @@ exclude:
|
|||
- tools
|
||||
- README.md
|
||||
- LICENSE
|
||||
- rollup.config.js
|
||||
- "*.config.js"
|
||||
- package*.json
|
||||
|
||||
jekyll-archives:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
- type: forgejo
|
||||
icon: "fa-solid fa-code-branch"
|
||||
url: 'https://git.aliberksandikci.com.tr/'
|
||||
url: 'https://git.asandikci.com/'
|
||||
|
||||
- type: xmpp
|
||||
icon: 'fa fa-xmpp'
|
||||
|
@ -28,10 +28,27 @@
|
|||
icon: 'fa fa-instagram'
|
||||
url: 'https://instagram.com/aliberksandikci'
|
||||
|
||||
- type: codeberg
|
||||
icon: 'fl-codeberg'
|
||||
url: 'https://codeberg.org/asandikci'
|
||||
# - type: codeberg
|
||||
# icon: 'fl-codeberg'
|
||||
# url: 'https://codeberg.org/asandikci'
|
||||
|
||||
- type: github
|
||||
icon: 'fab fa-github'
|
||||
url: 'https://github.com/asandikci'
|
||||
|
||||
- type: rss
|
||||
icon: "fas fa-rss"
|
||||
noblank: true
|
||||
|
||||
#
|
||||
# - type: bluesky
|
||||
# icon: 'fa-brands fa-bluesky'
|
||||
# url: '' # Fill with your Bluesky profile link
|
||||
#
|
||||
# - type: reddit
|
||||
# icon: 'fa-brands fa-reddit'
|
||||
# url: '' # Fill with your Reddit profile link
|
||||
#
|
||||
# - type: threads
|
||||
# icon: 'fa-brands fa-threads'
|
||||
# url: '' # Fill with your Threads profile link
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: باستخدام :PLATFORM السمة :THEME
|
||||
|
||||
not_found:
|
||||
statment: عذرا, الرابط التالي غير صالح أو انه يشير إلى صفحة غير موجودة.
|
||||
statement: عذرا, الرابط التالي غير صالح أو انه يشير إلى صفحة غير موجودة.
|
||||
|
||||
notification:
|
||||
update_found: يتوفر اصدار جديد للمحتوى.
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: Създадено чрез :PLATFORM и :THEME тема
|
||||
|
||||
not_found:
|
||||
statment: Съжалявам, но на този URL адрес няма налично съдържание.
|
||||
statement: Съжалявам, но на този URL адрес няма налично съдържание.
|
||||
|
||||
notification:
|
||||
update_found: Налична е нова версия на съдържанието.
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: Použití :PLATFORM s motivem :THEME
|
||||
|
||||
not_found:
|
||||
statment: Omlouváme se, adresu URL jsme špatně umístili nebo odkazuje na něco, co neexistuje.
|
||||
statement: Omlouváme se, adresu URL jsme špatně umístili nebo odkazuje na něco, co neexistuje.
|
||||
|
||||
notification:
|
||||
update_found: Je k dispozici nová verze obsahu.
|
||||
|
|
|
@ -42,7 +42,7 @@ copyright:
|
|||
meta: Powered by :PLATFORM with :THEME theme
|
||||
|
||||
not_found:
|
||||
statment: Entschuldigung, dieser Link verweist auf keine vorhandene Ressource.
|
||||
statement: Entschuldigung, dieser Link verweist auf keine vorhandene Ressource.
|
||||
|
||||
notification:
|
||||
update_found: Eine neue Version ist verfügbar.
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: Αξιοποιώντας την :PLATFORM theme :THEME
|
||||
|
||||
not_found:
|
||||
statment: Συγνώμη, έχουμε τοποθετήσει λάθος αυτήν την διεύθυνση URL ή υποδεικνύει κάτι που δεν υπάρχει.
|
||||
statement: Συγνώμη, έχουμε τοποθετήσει λάθος αυτήν την διεύθυνση URL ή υποδεικνύει κάτι που δεν υπάρχει.
|
||||
|
||||
notification:
|
||||
update_found: Υπάρχει διαθέσιμη μια νέα έκδοση του περιεχομένου.
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: Using the :THEME theme for :PLATFORM.
|
||||
|
||||
not_found:
|
||||
statment: Sorry, we've misplaced that URL or it's pointing to something that doesn't exist.
|
||||
statement: Sorry, we've misplaced that URL or it's pointing to something that doesn't exist.
|
||||
|
||||
notification:
|
||||
update_found: A new version of content is available.
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: Hecho con :PLATFORM usando el tema :THEME
|
||||
|
||||
not_found:
|
||||
statment: Lo sentimos, hemos perdido esa URL o apunta a algo que no existe.
|
||||
statement: Lo sentimos, hemos perdido esa URL o apunta a algo que no existe.
|
||||
|
||||
notification:
|
||||
update_found: Hay una nueva versión de contenido disponible.
|
||||
|
|
|
@ -42,7 +42,7 @@ copyright:
|
|||
meta: Käytetään :PLATFORM iä Teema :THEME
|
||||
|
||||
not_found:
|
||||
statment: Valitettavasti tällä URL-osoitteella ei ole saatavilla sisältöä.
|
||||
statement: Valitettavasti tällä URL-osoitteella ei ole saatavilla sisältöä.
|
||||
|
||||
notification:
|
||||
update_found: Uusi versio sisällöstä on saatavilla.
|
||||
|
|
|
@ -14,7 +14,7 @@ tabs:
|
|||
categories: Catégories
|
||||
tags: Tags
|
||||
archives: Archives
|
||||
about: A propos de
|
||||
about: À propos
|
||||
|
||||
# the text displayed in the search bar & search results
|
||||
search:
|
||||
|
@ -32,18 +32,18 @@ copyright:
|
|||
license:
|
||||
template: Cet article est sous licence :LICENSE_NAME par l'auteur.
|
||||
name: CC BY 4.0
|
||||
link: https://creativecommons.org/licenses/by/4.0/
|
||||
link: https://creativecommons.org/licenses/by/4.0/deed.fr
|
||||
|
||||
# Displayed in the footer
|
||||
brief: Certains droits réservés.
|
||||
verbose: >-
|
||||
Sauf mention contraire, les articles de ce site sont publiés sous licence
|
||||
Sauf mention contraire, les articles de ce site sont publiés
|
||||
sous la licence Creative Commons Attribution 4.0 International (CC BY 4.0) par l'auteur.
|
||||
|
||||
meta: Propulsé par :PLATFORM avec le thème :THEME
|
||||
|
||||
not_found:
|
||||
statment: Désolé, nous avons égaré cette URL ou elle pointe vers quelque chose qui n'existe pas.
|
||||
statement: Désolé, nous avons égaré cette URL ou elle pointe vers quelque chose qui n'existe pas.
|
||||
|
||||
notification:
|
||||
update_found: Une nouvelle version du contenu est disponible.
|
||||
|
|
|
@ -14,24 +14,23 @@ tabs:
|
|||
categories: Kategóriák
|
||||
tags: Címkék
|
||||
archives: Archívum
|
||||
about: Rólam
|
||||
about: Bemutatkozás
|
||||
|
||||
# the text displayed in the search bar & search results
|
||||
search:
|
||||
hint: keresés
|
||||
cancel: Mégse
|
||||
no_results: Oops! Nincs találat a keresésre.
|
||||
no_results: Hoppá! Nincs találat a keresésre.
|
||||
|
||||
panel:
|
||||
lastmod: Legutóbb frissítve
|
||||
trending_tags: Népszerű Címkék
|
||||
toc: Tartalom
|
||||
links: Blog linkek
|
||||
|
||||
copyright:
|
||||
# Shown at the bottom of the post
|
||||
license:
|
||||
template: A bejegyzés :LICENSE_NAME licenccel rendelkezik.
|
||||
template: A bejegyzést a szerző :LICENSE_NAME licenc alatt engedélyezte.
|
||||
name: CC BY 4.0
|
||||
link: https://creativecommons.org/licenses/by/4.0/
|
||||
|
||||
|
@ -42,10 +41,10 @@ copyright:
|
|||
Creative Commons Attribution 4.0 International (CC BY 4.0) licenccel rendelkeznek,
|
||||
hacsak másképp nincs jelezve.
|
||||
|
||||
meta: Készítve :PLATFORM motorral :THEME témával
|
||||
meta: Készítve :THEME témával a :PLATFORM platformra.
|
||||
|
||||
not_found:
|
||||
statment: Sajnáljuk, az URL-t rosszul helyeztük el, vagy valami nem létezőre mutat.
|
||||
statement: Sajnáljuk, az URL-t rosszul helyeztük el, vagy valami nem létezőre mutat.
|
||||
|
||||
notification:
|
||||
update_found: Elérhető a tartalom új verziója.
|
||||
|
@ -73,7 +72,21 @@ post:
|
|||
title: Link másolása
|
||||
succeed: Link sikeresen másolva!
|
||||
|
||||
# Date time format.
|
||||
# See: <http://strftime.net/>, <https://day.js.org/docs/en/display/format>
|
||||
df:
|
||||
post:
|
||||
strftime: "%Y. %B. %e."
|
||||
dayjs: "YYYY. MMMM D."
|
||||
archives:
|
||||
strftime: "%B"
|
||||
dayjs: "MMM"
|
||||
|
||||
# categories page
|
||||
categories:
|
||||
category_measure: kategória
|
||||
post_measure: bejegyzés
|
||||
category_measure:
|
||||
singular: kategória
|
||||
plural: kategória
|
||||
post_measure:
|
||||
singular: bejegyzés
|
||||
plural: bejegyzés
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: Didukung oleh :PLATFORM dengan tema :THEME
|
||||
|
||||
not_found:
|
||||
statment: Maaf, kami gagal menemukan URL itu atau memang mengarah ke sesuatu yang tidak ada.
|
||||
statement: Maaf, kami gagal menemukan URL itu atau memang mengarah ke sesuatu yang tidak ada.
|
||||
|
||||
notification:
|
||||
update_found: Versi konten baru tersedia.
|
||||
|
|
|
@ -42,7 +42,7 @@ copyright:
|
|||
|
||||
meta: Servizio offerto da :PLATFORM con tema :THEME
|
||||
not_found:
|
||||
statment: Ci scusiamo, non è stato possibile trovare l'URL in questione. Potrebbe puntare ad una pagina non esistente.
|
||||
statement: Ci scusiamo, non è stato possibile trovare l'URL in questione. Potrebbe puntare ad una pagina non esistente.
|
||||
|
||||
notification:
|
||||
update_found: Nuova versione del contenuto disponibile.
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: Powered by :PLATFORM with :THEME theme
|
||||
|
||||
not_found:
|
||||
statment: 해당 URL은 존재하지 않습니다.
|
||||
statement: 해당 URL은 존재하지 않습니다.
|
||||
|
||||
notification:
|
||||
update_found: 새 버전의 콘텐츠를 사용할 수 있습니다.
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: Powered by :PLATFORM with :THEME theme
|
||||
|
||||
not_found:
|
||||
statment: ဝမ်းနည်းပါသည်၊ ကျွန်ုပ်တို့သည် အဆိုပါ URL ကို မှားယွင်းစွာ နေရာချထားခြင်း သို့မဟုတ် ၎င်းသည် မရှိသောအရာကို ညွှန်ပြနေပါသည်။
|
||||
statement: ဝမ်းနည်းပါသည်၊ ကျွန်ုပ်တို့သည် အဆိုပါ URL ကို မှားယွင်းစွာ နေရာချထားခြင်း သို့မဟုတ် ၎င်းသည် မရှိသောအရာကို ညွှန်ပြနေပါသည်။
|
||||
|
||||
notification:
|
||||
update_found: အကြောင်းအရာဗားရှင်းအသစ်ကို ရနိုင်ပါပြီ။
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: Feito com :PLATFORM usando o tema :THEME
|
||||
|
||||
not_found:
|
||||
statment: Desculpe, a página não foi encontrada.
|
||||
statement: Desculpe, a página não foi encontrada.
|
||||
|
||||
notification:
|
||||
update_found: Uma nova versão do conteúdo está disponível.
|
||||
|
|
|
@ -42,7 +42,7 @@ copyright:
|
|||
meta: Использует тему :THEME для :PLATFORM
|
||||
|
||||
not_found:
|
||||
statment: Извините, мы перепутали URL-адрес или он указывает на что-то несуществующее.
|
||||
statement: Извините, мы перепутали URL-адрес или он указывает на что-то несуществующее.
|
||||
|
||||
notification:
|
||||
update_found: Доступна новая версия контента.
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: Uporabljena :PLATFORM tema :THEME #Using the :PLATFORM theme :THEME
|
||||
|
||||
not_found:
|
||||
statment: Oprostite, hiperpovezava je neustrezna ali vsebina ne obstajata. #Sorry, we've misplaced that URL or it's pointing to something that doesn't exist.
|
||||
statement: Oprostite, hiperpovezava je neustrezna ali vsebina ne obstajata. #Sorry, we've misplaced that URL or it's pointing to something that doesn't exist.
|
||||
|
||||
notification:
|
||||
update_found: Novejša različica vsebine je na voljo. #A new version of content is available.
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: Byggd med :PLATFORM och temat :THEME
|
||||
|
||||
not_found:
|
||||
statment: Ursäkta, vi har tappat bort den här webbadressen eller så pekar den på något som inte längre finns.
|
||||
statement: Ursäkta, vi har tappat bort den här webbadressen eller så pekar den på något som inte längre finns.
|
||||
|
||||
notification:
|
||||
update_found: Det finns en ny version av innehållet.
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: กำลังใช้ธีมของ :PLATFORM ชื่อ :THEME
|
||||
|
||||
not_found:
|
||||
statment: ขออภัย เราวาง URL นั้นไว้ผิดที่ หรือมันชี้ไปยังสิ่งที่ไม่มีอยู่
|
||||
statement: ขออภัย เราวาง URL นั้นไว้ผิดที่ หรือมันชี้ไปยังสิ่งที่ไม่มีอยู่
|
||||
|
||||
notification:
|
||||
update_found: มีเวอร์ชันใหม่ของเนื้อหา
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: :PLATFORM ve :THEME teması
|
||||
|
||||
not_found:
|
||||
statment: Üzgünüz, bu linki yanlış yerleştirdik veya var olmayan bir şeye işaret ediyor.
|
||||
statement: Üzgünüz, bu linki yanlış yerleştirdik veya var olmayan bir şeye işaret ediyor.
|
||||
|
||||
notification:
|
||||
update_found: İçeriğin yeni bir sürümü mevcut.
|
||||
|
|
|
@ -43,7 +43,7 @@ copyright:
|
|||
meta: Powered by :PLATFORM with :THEME theme
|
||||
|
||||
not_found:
|
||||
statment: Вибачте, це посилання вказує на ресурс, що не існує.
|
||||
statement: Вибачте, це посилання вказує на ресурс, що не існує.
|
||||
|
||||
notification:
|
||||
update_found: Доступна нова версія вмісту.
|
||||
|
|
|
@ -42,7 +42,7 @@ copyright:
|
|||
meta: Trang web này được tạo bởi :PLATFORM với chủ đề :THEME
|
||||
|
||||
not_found:
|
||||
statment: Xin lỗi, chúng tôi đã đặt nhầm URL hoặc đường dẫn trỏ đến một trang nào đó không tồn tại.
|
||||
statement: Xin lỗi, chúng tôi đã đặt nhầm URL hoặc đường dẫn trỏ đến một trang nào đó không tồn tại.
|
||||
|
||||
notification:
|
||||
update_found: Đã có phiên bản mới của nội dung.
|
||||
|
|
|
@ -42,7 +42,7 @@ copyright:
|
|||
meta: 本站采用 :PLATFORM 主题 :THEME
|
||||
|
||||
not_found:
|
||||
statment: 抱歉,我们放错了该 URL,或者它指向了不存在的内容。
|
||||
statement: 抱歉,我们放错了该 URL,或者它指向了不存在的内容。
|
||||
|
||||
notification:
|
||||
update_found: 发现新版本的内容。
|
||||
|
|
|
@ -42,7 +42,7 @@ copyright:
|
|||
meta: 本網站使用 :PLATFORM 產生,採用 :THEME 主題
|
||||
|
||||
not_found:
|
||||
statment: 抱歉,您可能正在存取一個已被移動的 URL,或者它從未存在。
|
||||
statement: 抱歉,您可能正在存取一個已被移動的 URL,或者它從未存在。
|
||||
|
||||
notification:
|
||||
update_found: 發現新版本更新。
|
||||
|
|
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
|
||||
|
||||
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:
|
||||
css: /assets/lib/tocbot/tocbot.min.css
|
||||
js: /assets/lib/tocbot/tocbot.min.js
|
||||
|
@ -27,13 +20,13 @@ mermaid:
|
|||
dayjs:
|
||||
js:
|
||||
common: /assets/lib/dayjs/dayjs.min.js
|
||||
locale: /assets/lib/dayjs/locale/en.min.js
|
||||
relativeTime: /assets/lib/dayjs/plugin/relativeTime.min.js
|
||||
localizedFormat: /assets/lib/dayjs/plugin/localizedFormat.min.js
|
||||
locale: /assets/lib/dayjs/locale/en.js
|
||||
relativeTime: /assets/lib/dayjs/plugin/relativeTime.js
|
||||
localizedFormat: /assets/lib/dayjs/plugin/localizedFormat.js
|
||||
|
||||
magnific-popup:
|
||||
css: /assets/lib/magnific-popup/magnific-popup.css
|
||||
js: /assets/lib/magnific-popup/jquery.magnific-popup.min.js
|
||||
glightbox:
|
||||
css: /assets/lib/glightbox/glightbox.min.css
|
||||
js: /assets/lib/glightbox/glightbox.min.js
|
||||
|
||||
lazy-polyfill:
|
||||
css: /assets/lib/loading-attribute-polyfill/loading-attribute-polyfill.min.css
|
||||
|
|
|
@ -1,32 +1,27 @@
|
|||
# CDNs
|
||||
|
||||
cdns:
|
||||
# Google Fonts
|
||||
# Resource Hints
|
||||
resource_hints:
|
||||
- url: https://fonts.googleapis.com
|
||||
links:
|
||||
- rel: preconnect
|
||||
- rel: dns-prefetch
|
||||
- url: https://fonts.gstatic.com
|
||||
args: crossorigin
|
||||
- url: https://fonts.googleapis.com
|
||||
# jsDelivr CDN
|
||||
links:
|
||||
- rel: preconnect
|
||||
opts: [crossorigin]
|
||||
- rel: dns-prefetch
|
||||
- url: https://cdn.jsdelivr.net
|
||||
# polyfill.io for math (cdnjs.cloudflare.com/polyfill)
|
||||
- url: https://cdnjs.cloudflare.com
|
||||
links:
|
||||
- rel: preconnect
|
||||
- rel: dns-prefetch
|
||||
|
||||
# fonts
|
||||
|
||||
webfonts: https://fonts.googleapis.com/css2?family=Lato&family=Source+Sans+Pro:wght@400;600;700;900&display=swap
|
||||
# Web Fonts
|
||||
webfonts: https://fonts.googleapis.com/css2?family=Lato:wght@300;400&family=Source+Sans+Pro:wght@400;600;700;900&display=swap
|
||||
|
||||
# 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:
|
||||
css: https://cdn.jsdelivr.net/npm/tocbot@4.25.0/dist/tocbot.min.css
|
||||
js: https://cdn.jsdelivr.net/npm/tocbot@4.25.0/dist/tocbot.min.js
|
||||
css: https://cdn.jsdelivr.net/npm/tocbot@4.29.0/dist/tocbot.min.css
|
||||
js: https://cdn.jsdelivr.net/npm/tocbot@4.29.0/dist/tocbot.min.js
|
||||
|
||||
fontlogos:
|
||||
css: https://cdn.jsdelivr.net/npm/font-logos@1/assets/font-logos.css
|
||||
|
@ -35,7 +30,7 @@ forkawesome:
|
|||
css: https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css
|
||||
|
||||
fontawesome:
|
||||
css: https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5.2/css/all.min.css
|
||||
css: https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.6.0/css/all.min.css
|
||||
|
||||
ballooncss:
|
||||
css: https://unpkg.com/balloon-css/balloon.min.css
|
||||
|
@ -44,18 +39,18 @@ search:
|
|||
js: https://cdn.jsdelivr.net/npm/simple-jekyll-search@1.10.0/dest/simple-jekyll-search.min.js
|
||||
|
||||
mermaid:
|
||||
js: https://cdn.jsdelivr.net/npm/mermaid@10.8.0/dist/mermaid.min.js
|
||||
js: https://cdn.jsdelivr.net/npm/mermaid@11.0.2/dist/mermaid.min.js
|
||||
|
||||
dayjs:
|
||||
js:
|
||||
common: https://cdn.jsdelivr.net/npm/dayjs@1.11.10/dayjs.min.js
|
||||
locale: https://cdn.jsdelivr.net/npm/dayjs@1.11.10/locale/:LOCALE.min.js
|
||||
relativeTime: https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/relativeTime.min.js
|
||||
localizedFormat: https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/localizedFormat.min.js
|
||||
common: https://cdn.jsdelivr.net/npm/dayjs@1.11.13/dayjs.min.js
|
||||
locale: https://cdn.jsdelivr.net/npm/dayjs@1.11.13/locale/:LOCALE.js
|
||||
relativeTime: https://cdn.jsdelivr.net/npm/dayjs@1.11.13/plugin/relativeTime.js
|
||||
localizedFormat: https://cdn.jsdelivr.net/npm/dayjs@1.11.13/plugin/localizedFormat.js
|
||||
|
||||
magnific-popup:
|
||||
css: https://cdn.jsdelivr.net/npm/magnific-popup@1.1.0/dist/magnific-popup.min.css
|
||||
js: https://cdn.jsdelivr.net/npm/magnific-popup@1.1.0/dist/jquery.magnific-popup.min.js
|
||||
glightbox:
|
||||
css: https://cdn.jsdelivr.net/npm/glightbox@3.3.0/dist/css/glightbox.min.css
|
||||
js: https://cdn.jsdelivr.net/npm/glightbox@3.3.0/dist/js/glightbox.min.js
|
||||
|
||||
lazy-polyfill:
|
||||
css: https://cdn.jsdelivr.net/npm/loading-attribute-polyfill@2.1.1/dist/loading-attribute-polyfill.min.css
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
platforms:
|
||||
|
||||
- type: Linkedin
|
||||
icon: "fab fa-linkedin"
|
||||
link: "https://www.linkedin.com/sharing/share-offsite/?url=URL"
|
||||
|
@ -28,3 +27,50 @@ platforms:
|
|||
- type: Telegram
|
||||
icon: "fab fa-telegram"
|
||||
link: "https://t.me/share/url?url=URL&text=TITLE"
|
||||
|
||||
- type: Bluesky
|
||||
icon: "fa-brands fa-bluesky"
|
||||
link: "https://bsky.app/intent/compose?text=TITLE%20URL"
|
||||
|
||||
- type: Reddit
|
||||
icon: "fa-brands fa-square-reddit"
|
||||
link: "https://www.reddit.com/submit?url=URL&title=TITLE"
|
||||
|
||||
- type: Threads
|
||||
icon: "fa-brands fa-square-threads"
|
||||
link: "https://www.threads.net/intent/post?text=TITLE%20URL"
|
||||
|
||||
# Uncomment below if you need to.
|
||||
#
|
||||
# - type: Linkedin
|
||||
# icon: "fab fa-linkedin"
|
||||
# link: "https://www.linkedin.com/sharing/share-offsite/?url=URL"
|
||||
#
|
||||
# - type: Weibo
|
||||
# icon: "fab fa-weibo"
|
||||
# link: "https://service.weibo.com/share/share.php?title=TITLE&url=URL"
|
||||
#
|
||||
# - type: Mastodon
|
||||
# icon: "fa-brands fa-mastodon"
|
||||
# # See: https://github.com/justinribeiro/share-to-mastodon#properties
|
||||
# instances:
|
||||
# - label: mastodon.social
|
||||
# link: "https://mastodon.social/"
|
||||
# - label: mastodon.online
|
||||
# link: "https://mastodon.online/"
|
||||
# - label: fosstodon.org
|
||||
# link: "https://fosstodon.org/"
|
||||
# - label: photog.social
|
||||
# link: "https://photog.social/"
|
||||
#
|
||||
# - type: Bluesky
|
||||
# icon: "fa-brands fa-bluesky"
|
||||
# link: "https://bsky.app/intent/compose?text=TITLE%20URL"
|
||||
#
|
||||
# - type: Reddit
|
||||
# icon: "fa-brands fa-square-reddit"
|
||||
# link: "https://www.reddit.com/submit?url=URL&title=TITLE"
|
||||
#
|
||||
# - type: Threads
|
||||
# icon: "fa-brands fa-square-threads"
|
||||
# link: "https://www.threads.net/intent/post?text=TITLE%20URL"
|
||||
|
|
56
_drafts/2024-07-22-pardus-ve-windows.md
Normal file
56
_drafts/2024-07-22-pardus-ve-windows.md
Normal file
|
@ -0,0 +1,56 @@
|
|||
---
|
||||
title: "Pardus/Linux Yanına Windows Kurulumu"
|
||||
date: 2024-07-22 10:00:00 +3000
|
||||
categories: Linux
|
||||
tags: pardus linux
|
||||
author: asandikci
|
||||
image:
|
||||
path: https://4.bp.blogspot.com/-7lTiQNNrJjI/WAojkdqEvNI/AAAAAAAAAVI/IcAysrVEssYmTxQIi7t6nCRy5TtQXCXHACLcB/w1200-h630-p-k-no-nu/112159e69714e8cab4e1ab16f57447cb5e2559476e001.jpg
|
||||
alt: "Pardus ve Windows"
|
||||
---
|
||||
|
||||
GNU/Linux - Pardus işletim sistemi bir bilgisayar kullanıcısının isteyebileceği her türlü programı/kolaylığı sağlamakta. Lakin çeşitli programların yapımcıları tarafından Linux için desteklenmemesi (Adobe Programları gibi) veya oyunlarda bulunan çeşitli hile engelleme sistemlerinin Linux için portlanmamış olması (Valorant, LOL, Roblox vb.) sebebi ile Windows bir makineye hâlen bağımlılığınız bulunuyor olabilir. Bu tarz bir durumda **Pardus ile Windows'u birlikte kullanmak** gibi çok güzel bir seçeneğe sahibiz. Eğer Pardus'u denemek için indirdiyseniz silip Windows kurmadan önce bu seçeneği bir değerlendirin derim. Eğer yeterince disk alanınız varsa (ben en az 256GiB öneriyorum) **dual boot** dediğimiz iki sistemi aynı anda kullanma işlemini gerçekleştirmeniz için bu yazıyı yazmak istedim. Kolaylıklar dilerim
|
||||
|
||||
### Not
|
||||
|
||||
Bu yazı, Pardus'un yanına -> Windows kurmak içindir. Eğer Windows'un yanına -> Pardus kurmak istiyorsanız, Pardus sitesindeki yazıyı takip edebiliirsiniz: https://www.pardus.org.tr/windows-ile-dual-boot-olusturma/
|
||||
|
||||
### Windows'a bağımlığınızın olup olmadığını öğrenin !
|
||||
|
||||
Linux'te oynayabileceğiniz / oynayamayacağınız oyunlar: https://protondb.com
|
||||
Desteklenen / Desteklenmeyen anticheat sistemleri: https://areweanticheatyet.com/
|
||||
Popüler uygulamalara alternatifler: https://alternativeto.net
|
||||
|
||||
# Ön Gereklilikler
|
||||
|
||||
- En az 1 USB Bellek
|
||||
- Pardus/Linux Kurulu bir makine (**64 Bit**)
|
||||
- Mümkünse Ortalama/Hızlı bir internet bağlantısı _veya_ sabır
|
||||
|
||||
## Uyarı
|
||||
|
||||
- Sisteminizdeki önemli dosyaları yedek almanızı öneriyorum. Bu işlem kurulu olan Pardus sistemine _ufak bir ihtimal de olsa_ zarar verebilir
|
||||
|
||||
### Tahmini Süre
|
||||
|
||||
- 2-3 Saat (imaj dosyalarının indirilmesi hariç)
|
||||
|
||||
# Adımlar
|
||||
|
||||
- **Ventoy** programını Pardus mağaza üzerinden indiriniz ve Ventoy programını USB belleğinize kurunuz.
|
||||
- Pardus/Linux sisteminizin yerini azaltmak için GParted uygulamasının **imaj (.iso)** dosyasını indiriniz, dosyanın doğruluğunu kontrol ediniz ve Ventoy'a (USB belleğinize) atınız.
|
||||
- indirme linki: <https://downloads.sourceforge.net/gparted/gparted-live-1.6.0-3-amd64.iso>
|
||||
- dosya kontrol linki: <https://gparted.org/gparted-live/stable/CHECKSUMS.TXT>
|
||||
- tüm indirme seçenekleri: <https://gparted.org/download.php>
|
||||
- Windows veya Pardus'un yanına kurmak istediğiniz herhangi bir İmaj (.iso) dosyasını indirin. Bu imaj dosyasını da Ventoy'a (USB Belleğinize) atınız
|
||||
- Son olarak olası bir sıkıntıda GRUB (başlatma) ekranına erişim için BootRepair uygulamasının imaj dosyasını indirip USB Belleğe atınız (zorunlu değil ama kurtarma adımları için hayat kurtarabilir). İndirme linki: <https://sourceforge.net/projects/boot-repair-cd/files/latest/download>
|
||||
|
||||
- Tüm İndirme ve USB Belleğe atma işlemleri bittiğinde dosyaları doğrulamak için mümkünse Hash değerlerini kontrol edin. Veya en azından `sync` komutunu herhangi bir terminalde çalıştırarak komutun sonlanmasını bekleyin (duruma göre 15dk+ bekletebilir). Bu komut tüm verilerin USB Belleğe yazıldığında emin olmanızı sağlar. Sonrasında USB Belleğinizi isterseniz çıkarabilirsiniz.
|
||||
- USB Belleğinizi cihazınıza takın. Bilgisayarınızı Yeniden başlatın ve Boot Tuşuna basarak cihazınızın başlatma menüsüne girin. Sonrasında _Ventoy_, _USB_ veya USB belleğinizin markasının isminin olduğu seçeneği seçiniz.
|
||||
- Eğer her şey yolunda giderse içinde 3 tane .iso dosyasının bulunduğu bir ekran açılmış olacak. İlk önce Gparted (`gparted-live*.iso`) dosyasını seçiniz.
|
||||
|
||||
### Sıradaki adımlar Kısaca (sonradan güncellenecek)
|
||||
|
||||
- GParted üzerinden Pardus'un kurulu olduğu diski küçültün
|
||||
- Windows'u kalan boş alana kurun
|
||||
- Kurulum sonrasında ya BootRepair uygulamasını kullanın ya da Pardus'a bir şekilde girip boot-repair komutunu kullanın
|
14
_drafts/2024-07-31-tusas-gezisi.md
Normal file
14
_drafts/2024-07-31-tusas-gezisi.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
title: "TUSAŞ Gezisi"
|
||||
date: 2024-07-31 10:00:00 +3000
|
||||
categories: Trip
|
||||
tags: tusaş trip
|
||||
author: asandikci
|
||||
image:
|
||||
path: https://trthaberstatic.cdn.wp.trt.com.tr/resimler/2022000/tusas-trt-haber-2022093.jpg
|
||||
alt: "Türk Havacılık ve Uzay Sanayii AŞ"
|
||||
---
|
||||
|
||||
Geçtiğimiz gün, 2024 tercih dönemi kapsamında bilgilendirme amaçlı TUSAŞ'ın düzenlediği geziye okulum İzmir Fen Lisesi adına katıldım. Her ne kadar havacılık konusunda pek bir bilgim olmasa da aldığım notlardan ve geziye dair deneyimlerim ile ilgili ufak bir yazı yazmak istedim. İyi okumalar
|
||||
|
||||
7 otobüs olarak TUSAŞ'a doğru yola çıktık. Girişte telefonlarımız toplandı ve otobüslerden inip konferans salonuna geçtik.
|
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 -->
|
7
_includes/analytics/fathom.html
Normal file
7
_includes/analytics/fathom.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
<!-- Fathom -->
|
||||
<script
|
||||
src="https://cdn.usefathom.com/script.js"
|
||||
data-site="{{ site.analytics.fathom.id }}"
|
||||
defer>
|
||||
</script>
|
||||
<!-- End Fathom Code -->
|
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 -->
|
||||
{% if page.comments and site.comments.active %}
|
||||
{% capture path %}comments/{{ site.comments.active }}.html{% endcapture %}
|
||||
{% if page.comments and site.comments.provider %}
|
||||
{% capture path %}comments/{{ site.comments.provider }}.html{% endcapture %}
|
||||
{% include {{ path }} %}
|
||||
{% endif %}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
this.page.identifier = '{{ page.url }}';
|
||||
};
|
||||
|
||||
/* Lazy loading */
|
||||
{%- comment -%} Lazy loading {%- endcomment -%}
|
||||
var disqus_observer = new IntersectionObserver(
|
||||
function (entries) {
|
||||
if (entries[0].isIntersecting) {
|
||||
|
@ -28,12 +28,12 @@
|
|||
{ 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() {
|
||||
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') {
|
||||
return;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (document.querySelector('.mode-toggle')) {
|
||||
if (document.getElementById('mode-toggle')) {
|
||||
window.addEventListener('message', reloadDisqus);
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<script type="text/javascript">
|
||||
(function () {
|
||||
const origin = 'https://giscus.app';
|
||||
const iframe = 'iframe.giscus-frame';
|
||||
const lightTheme = 'light';
|
||||
const darkTheme = 'dark_dimmed';
|
||||
|
||||
|
@ -18,6 +17,12 @@
|
|||
initTheme = darkTheme;
|
||||
}
|
||||
|
||||
let lang = '{{ site.comments.giscus.lang | default: lang }}';
|
||||
{%- comment -%} https://github.com/giscus/giscus/tree/main/locales {%- endcomment -%}
|
||||
if (lang.length > 2 && !lang.startsWith('zh')) {
|
||||
lang = lang.slice(0, 2);
|
||||
}
|
||||
|
||||
let giscusAttributes = {
|
||||
src: 'https://giscus.app/client.js',
|
||||
'data-repo': '{{ site.comments.giscus.repo}}',
|
||||
|
@ -25,11 +30,12 @@
|
|||
'data-category': '{{ site.comments.giscus.category }}',
|
||||
'data-category-id': '{{ site.comments.giscus.category_id }}',
|
||||
'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-emit-metadata': '0',
|
||||
'data-theme': initTheme,
|
||||
'data-input-position': '{{ site.comments.giscus.input_position | default: 'bottom' }}',
|
||||
'data-lang': '{{ site.comments.giscus.lang | default: lang }}',
|
||||
'data-lang': lang,
|
||||
'data-loading': 'lazy',
|
||||
crossorigin: 'anonymous',
|
||||
async: ''
|
||||
|
@ -47,7 +53,7 @@
|
|||
event.data &&
|
||||
event.data.direction === ModeToggle.ID
|
||||
) {
|
||||
/* global theme mode changed */
|
||||
{%- comment -%} global theme mode changed {%- endcomment -%}
|
||||
const mode = event.data.message;
|
||||
const theme = mode === ModeToggle.DARK_MODE ? darkTheme : lightTheme;
|
||||
|
||||
|
@ -57,7 +63,7 @@
|
|||
}
|
||||
};
|
||||
|
||||
const giscus = document.querySelector(iframe).contentWindow;
|
||||
const giscus = document.getElementsByClassName('giscus-frame')[0].contentWindow;
|
||||
giscus.postMessage({ giscus: message }, origin);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
<script type="text/javascript">
|
||||
(function () {
|
||||
const origin = 'https://utteranc.es';
|
||||
const iframe = 'iframe.utterances-frame';
|
||||
const lightTheme = 'github-light';
|
||||
const darkTheme = 'github-dark';
|
||||
let initTheme = lightTheme;
|
||||
|
@ -26,12 +25,12 @@
|
|||
addEventListener('message', (event) => {
|
||||
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) {
|
||||
/* page initial */
|
||||
{%- comment -%} page initial {%- endcomment -%}
|
||||
theme = initTheme;
|
||||
} 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;
|
||||
theme = mode === ModeToggle.DARK_MODE ? darkTheme : lightTheme;
|
||||
} else {
|
||||
|
@ -43,7 +42,7 @@
|
|||
theme: theme
|
||||
};
|
||||
|
||||
const utterances = document.querySelector(iframe).contentWindow;
|
||||
const utterances = document.getElementsByClassName('utterances-frame')[0].contentWindow;
|
||||
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>
|
|
@ -1,10 +1,9 @@
|
|||
<iframe
|
||||
class="embed-video bilibili"
|
||||
class="embed-video"
|
||||
loading="lazy"
|
||||
src="https://player.bilibili.com/player.html?bvid={{ include.id }}"
|
||||
scrolling="no"
|
||||
border="0"
|
||||
frameborder="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
|
||||
class="embed-video youtube"
|
||||
class="embed-video"
|
||||
loading="lazy"
|
||||
src="https://www.youtube.com/embed/{{ include.id }}"
|
||||
title="YouTube video player"
|
||||
|
|
|
@ -34,7 +34,14 @@
|
|||
{%- endcapture -%}
|
||||
|
||||
{%- 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 -%}
|
||||
|
||||
{{ site.data.locales[include.lang].meta | replace: ':PLATFORM', _platform | replace: ':THEME', _theme }}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<!-- GoatCounter -->
|
||||
|
||||
<script
|
||||
data-goatcounter="https://{{ site.goatcounter.id }}.goatcounter.com/count"
|
||||
async
|
||||
src="https://gc.zgo.at/count.js"
|
||||
></script>
|
||||
|
|
@ -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,120 +1,128 @@
|
|||
<head>
|
||||
<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: dark)" content="#1b1b1e">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<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: dark)"
|
||||
content="#1b1b1e"
|
||||
/>
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta
|
||||
name="apple-mobile-web-app-status-bar-style"
|
||||
content="black-translucent"
|
||||
/>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, user-scalable=no initial-scale=1, shrink-to-fit=no, viewport-fit=cover"
|
||||
>
|
||||
/>
|
||||
|
||||
{%- capture seo_tags -%}
|
||||
{% seo title=false %}
|
||||
{%- endcapture -%}
|
||||
{%- capture seo_tags -%} {% seo title=false %} {%- endcapture -%}
|
||||
|
||||
<!-- Setup Open Graph image -->
|
||||
|
||||
{% if page.image %}
|
||||
{% assign src = page.image.path | default: page.image %}
|
||||
|
||||
{% unless src contains '://' %}
|
||||
{%- capture img_url -%}
|
||||
{% include img-url.html src=src img_path=page.img_path absolute=true %}
|
||||
{%- endcapture -%}
|
||||
|
||||
{%- capture old_url -%}{{ src | absolute_url }}{%- endcapture -%}
|
||||
{%- capture new_url -%}{{ img_url }}{%- endcapture -%}
|
||||
|
||||
{% assign seo_tags = seo_tags | replace: old_url, new_url %}
|
||||
{% endunless %}
|
||||
|
||||
{% elsif site.social_preview_image %}
|
||||
{%- capture img_url -%}
|
||||
{% include img-url.html src=site.social_preview_image absolute=true %}
|
||||
{%- endcapture -%}
|
||||
|
||||
{%- capture og_image -%}
|
||||
{% if page.image %} {% assign src = page.image.path | default: page.image %}
|
||||
{% unless src contains '://' %} {%- capture img_url -%} {% include
|
||||
media-url.html src=src subpath=page.media_subpath absolute=true %} {%-
|
||||
endcapture -%} {%- capture old_url -%}{{ src | absolute_url }}{%- endcapture
|
||||
-%} {%- capture new_url -%}{{ img_url }}{%- endcapture -%} {% assign seo_tags
|
||||
= seo_tags | replace: old_url, new_url %} {% 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 -%}
|
||||
{%- 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 %}
|
||||
|
||||
{{ seo_tags }}
|
||||
{%- 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 %} {{
|
||||
seo_tags }}
|
||||
|
||||
<title>
|
||||
{%- unless page.layout == 'home' -%}
|
||||
{{ page.title | append: ' | ' }}
|
||||
{%- endunless -%}
|
||||
{{ site.title }}
|
||||
{%- unless page.layout == 'home' -%} {{ page.title | append: ' | ' }} {%-
|
||||
endunless -%} {{ site.title }}
|
||||
</title>
|
||||
|
||||
{% include_cached favicons.html %}
|
||||
|
||||
{% if site.resources.ignore_env != jekyll.environment and site.resources.self_hosted %}
|
||||
<link href="{{ site.data.origin[type].webfonts | relative_url }}" rel="stylesheet">
|
||||
|
||||
{% else %}
|
||||
{% for cdn in site.data.origin[type].cdns %}
|
||||
<link rel="preconnect" href="{{ cdn.url }}" {{ cdn.args }}>
|
||||
<link rel="dns-prefetch" href="{{ cdn.url }}" {{ cdn.args }}>
|
||||
{% endfor %}
|
||||
|
||||
<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 %}
|
||||
<!-- Resource Hints -->
|
||||
{% unless site.assets.self_host.enabled %} {% for hint in
|
||||
site.data.origin.cors.resource_hints %} {% for link in hint.links %} <link
|
||||
rel="{{ link.rel }}" href="{{ hint.url }}" {{ link.opts | join: ' ' }}> {%
|
||||
endfor %} {% endfor %} {% endunless %}
|
||||
|
||||
<!-- 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 Logos -->
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].fontlogos.css | relative_url }}" >
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="{{ site.data.origin[type].fontlogos.css | relative_url }}"
|
||||
/>
|
||||
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].fontawesome.css | relative_url }}">
|
||||
<!-- Font Awesome Icons -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="{{ site.data.origin[type].fontawesome.css | relative_url }}"
|
||||
/>
|
||||
|
||||
<!-- Fork Awesome -->
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].forkawesome.css | relative_url }}" integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY=" crossorigin="anonymous">
|
||||
<!-- Fork Awesome [added by asandikci] -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="{{ site.data.origin[type].forkawesome.css | relative_url }}"
|
||||
integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY="
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
|
||||
<!-- Balloon CSS -->
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].ballooncss.css | relative_url }}">
|
||||
<!-- Balloon CSS [added by asandikci] -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="{{ site.data.origin[type].ballooncss.css | relative_url }}"
|
||||
/>
|
||||
|
||||
<link rel="stylesheet" href="{{ '/assets/css/:THEME.css' | replace: ':THEME', site.theme | relative_url }}">
|
||||
<!-- 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 }}"
|
||||
/>
|
||||
|
||||
{% if site.toc and page.toc %}
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].toc.css | relative_url }}">
|
||||
{% endif %}
|
||||
|
||||
{% if page.layout == 'post' or page.layout == 'page' or page.layout == 'home' %}
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type]['lazy-polyfill'].css | relative_url }}">
|
||||
{% endif %}
|
||||
|
||||
{% if page.layout == 'page' or page.layout == 'post' %}
|
||||
<!-- Manific Popup -->
|
||||
<link rel="stylesheet" href="{{ site.data.origin[type].magnific-popup.css | relative_url }}">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="{{ site.data.origin[type].toc.css | relative_url }}"
|
||||
/>
|
||||
{% endif %} {% if page.layout == 'post' or page.layout == 'page' or
|
||||
page.layout == 'home' %}
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="{{ site.data.origin[type]['lazy-polyfill'].css | relative_url }}"
|
||||
/>
|
||||
{% endif %} {% if page.layout == 'page' or page.layout == 'post' %}
|
||||
<!-- Image Popup -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="{{ site.data.origin[type].glightbox.css | relative_url }}"
|
||||
/>
|
||||
{% endif %}
|
||||
|
||||
<!-- JavaScript -->
|
||||
|
||||
{% unless site.theme_mode %}
|
||||
{% include mode-toggle.html %}
|
||||
{% endunless %}
|
||||
|
||||
{% include metadata-hook.html %}
|
||||
{% unless site.theme_mode %} {% include mode-toggle.html %} {% endunless %} {%
|
||||
include metadata-hook.html %}
|
||||
</head>
|
||||
|
|
|
@ -3,17 +3,10 @@
|
|||
<!-- commons -->
|
||||
<script src="/assets/js/user/copy.js"></script>
|
||||
|
||||
{% assign urls = site.data.origin[type].jquery.js
|
||||
| append: ','
|
||||
| append: site.data.origin[type].bootstrap.js
|
||||
| append: ','
|
||||
| append: site.data.origin[type].search.js
|
||||
%}
|
||||
{% assign urls = site.data.origin[type].search.js %}
|
||||
|
||||
<!-- layout specified -->
|
||||
|
||||
{% assign js_dist = '/assets/js/dist/' %}
|
||||
|
||||
{% if page.layout == 'post' or page.layout == 'page' or page.layout == 'home' %}
|
||||
{% assign urls = urls | append: ',' | append: site.data.origin[type]['lazy-polyfill'].js %}
|
||||
|
||||
|
@ -21,7 +14,7 @@
|
|||
<!-- image lazy-loading & popup & clipboard -->
|
||||
{% assign urls = urls
|
||||
| append: ','
|
||||
| append: site.data.origin[type]['magnific-popup'].js
|
||||
| append: site.data.origin[type].glightbox.js
|
||||
| append: ','
|
||||
| append: site.data.origin[type].clipboard.js
|
||||
%}
|
||||
|
@ -34,7 +27,7 @@
|
|||
or page.layout == 'category'
|
||||
or page.layout == 'tag'
|
||||
%}
|
||||
{% assign locale = site.lang | split: '-' | first %}
|
||||
{% assign locale = include.lang | split: '-' | first %}
|
||||
|
||||
{% assign urls = urls
|
||||
| append: ','
|
||||
|
@ -68,47 +61,50 @@
|
|||
{% assign js = 'commons' %}
|
||||
{% endcase %}
|
||||
|
||||
{% capture script %}{{ js_dist }}{{ js }}.min.js{% endcapture %}
|
||||
<script defer src="{{ script | relative_url }}"></script>
|
||||
{% capture script %}/assets/js/dist/{{ js }}.min.js{% endcapture %}
|
||||
|
||||
<script src="{{ script | relative_url }}"></script>
|
||||
|
||||
{% if page.math %}
|
||||
<!-- MathJax -->
|
||||
<script>
|
||||
/* see: <https://docs.mathjax.org/en/latest/options/input/tex.html#tex-options> */
|
||||
MathJax = {
|
||||
tex: {
|
||||
/* start/end delimiter pairs for in-line math */
|
||||
inlineMath: [
|
||||
['$', '$'],
|
||||
['\\(', '\\)']
|
||||
],
|
||||
/* start/end delimiter pairs for display math */
|
||||
displayMath: [
|
||||
['$$', '$$'],
|
||||
['\\[', '\\]']
|
||||
],
|
||||
/* equation numbering */
|
||||
tags: 'ams'
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script src="{{ '/assets/js/data/mathjax.js' | relative_url }}"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=es6"></script>
|
||||
<script id="MathJax-script" async src="{{ site.data.origin[type].mathjax.js | relative_url }}"></script>
|
||||
{% 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' %}
|
||||
<!-- PWA -->
|
||||
{% if site.pwa.enabled %}
|
||||
<script defer src="{{ 'app.min.js' | prepend: js_dist | relative_url }}"></script>
|
||||
<script
|
||||
defer
|
||||
src="{{ 'app.min.js' | relative_url }}?baseurl={{ site.baseurl | default: '' }}®ister={{ site.pwa.cache.enabled }}"
|
||||
></script>
|
||||
{% endif %}
|
||||
|
||||
<!-- GA -->
|
||||
{% if site.google_analytics.id != empty and site.google_analytics.id %}
|
||||
{% include google-analytics.html %}
|
||||
{% endif %}
|
||||
|
||||
<!-- GoatCounter -->
|
||||
{% if site.goatcounter.id != empty and site.goatcounter.id %}
|
||||
{% include goatcounter.html %}
|
||||
<!-- Web Analytics -->
|
||||
{% for analytics in site.analytics %}
|
||||
{% capture str %}{{ analytics }}{% endcapture %}
|
||||
{% assign type = str | split: '{' | first %}
|
||||
{% if site.analytics[type].id and site.analytics[type].id != empty %}
|
||||
{% include analytics/{{ type }}.html %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
{% comment %}
|
||||
Detect appearance language and return it through variable "lang"
|
||||
{% 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 %}
|
||||
{% else %}
|
||||
{% assign lang = 'en' %}
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
{%- comment -%}
|
||||
Generate image final URL based on `site.img_cdn`, `page.img_path`
|
||||
Generate media resource final URL based on `site.cdn`, `page.media_subpath`
|
||||
|
||||
Arguments:
|
||||
src - required, basic image path
|
||||
img_path - optional, relative path of image
|
||||
src - required, basic media resources path
|
||||
subpath - optional, relative path of media resources
|
||||
absolute - optional, boolean, if true, generate absolute URL
|
||||
|
||||
Return:
|
||||
image URL
|
||||
media resources URL
|
||||
{%- endcomment -%}
|
||||
|
||||
{% assign url = include.src %}
|
||||
|
||||
{%- if url -%}
|
||||
{% unless url contains ':' %}
|
||||
{%- comment -%} Add page image path prefix {%- endcomment -%}
|
||||
{% assign url = include.img_path | default: '' | append: '/' | append: url %}
|
||||
{%- comment -%} Add media resources subpath prefix {%- endcomment -%}
|
||||
{% assign url = include.subpath | default: '' | append: '/' | append: url %}
|
||||
|
||||
{%- comment -%} Prepend CND URL {%- endcomment -%}
|
||||
{% if site.img_cdn %}
|
||||
{% assign url = site.img_cdn | append: '/' | append: url %}
|
||||
{% if site.cdn %}
|
||||
{% assign url = site.cdn | append: '/' | append: url %}
|
||||
{% endif %}
|
||||
|
||||
{% assign url = url | replace: '///', '/' | replace: '//', '/' | replace: ':/', '://' %}
|
|
@ -1,6 +1,5 @@
|
|||
<!-- mermaid-js loader -->
|
||||
<script type="text/javascript">
|
||||
(function () {
|
||||
function updateMermaid(event) {
|
||||
if (event.source === window && event.data && event.data.direction === ModeToggle.ID) {
|
||||
const mode = event.data.message;
|
||||
|
@ -12,11 +11,15 @@
|
|||
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);
|
||||
{%- 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);
|
||||
|
@ -24,6 +27,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
(function () {
|
||||
let initTheme = 'default';
|
||||
const html = document.documentElement;
|
||||
|
||||
|
@ -35,15 +39,16 @@
|
|||
}
|
||||
|
||||
let mermaidConf = {
|
||||
theme: initTheme /* <default|dark|forest|neutral> */
|
||||
theme: initTheme {%- comment -%} <default | dark | forest | neutral> {%- endcomment -%}
|
||||
};
|
||||
|
||||
/* Create mermaid tag */
|
||||
document.querySelectorAll('pre>code.language-mermaid').forEach((elem) => {
|
||||
{%- comment -%} Create mermaid tag {%- endcomment -%}
|
||||
const basicList = document.getElementsByClassName('language-mermaid');
|
||||
[...basicList].forEach((elem) => {
|
||||
const svgCode = elem.textContent;
|
||||
const backup = elem.parentElement;
|
||||
backup.classList.add('unloaded');
|
||||
/* create mermaid node */
|
||||
backup.classList.add('d-none');
|
||||
{%- comment -%} create mermaid node {%- endcomment -%}
|
||||
let mermaid = document.createElement('pre');
|
||||
mermaid.classList.add('mermaid');
|
||||
const text = document.createTextNode(svgCode);
|
||||
|
@ -52,7 +57,6 @@
|
|||
});
|
||||
|
||||
mermaid.initialize(mermaidConf);
|
||||
|
||||
window.addEventListener('message', updateMermaid);
|
||||
})();
|
||||
</script>
|
||||
|
|
|
@ -19,45 +19,32 @@
|
|||
}
|
||||
|
||||
constructor() {
|
||||
if (this.hasMode) {
|
||||
if (this.isDarkMode) {
|
||||
if (!this.isSysDarkPrefer) {
|
||||
this.setDark();
|
||||
let self = this;
|
||||
|
||||
{%- comment -%} always follow the system prefers {%- endcomment -%}
|
||||
this.sysDarkPrefers.addEventListener('change', () => {
|
||||
if (self.hasMode) {
|
||||
self.clearMode();
|
||||
}
|
||||
self.notify();
|
||||
});
|
||||
|
||||
if (!this.hasMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isDarkMode) {
|
||||
this.setDark();
|
||||
} else {
|
||||
if (this.isSysDarkPrefer) {
|
||||
this.setLight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let self = this;
|
||||
|
||||
/* always follow the system prefers */
|
||||
this.sysDarkPrefers.addEventListener('change', () => {
|
||||
if (self.hasMode) {
|
||||
if (self.isDarkMode) {
|
||||
if (!self.isSysDarkPrefer) {
|
||||
self.setDark();
|
||||
}
|
||||
} else {
|
||||
if (self.isSysDarkPrefer) {
|
||||
self.setLight();
|
||||
}
|
||||
}
|
||||
|
||||
self.clearMode();
|
||||
}
|
||||
|
||||
self.notify();
|
||||
});
|
||||
} /* constructor() */
|
||||
|
||||
get sysDarkPrefers() {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)');
|
||||
}
|
||||
|
||||
get isSysDarkPrefer() {
|
||||
get isPreferDark() {
|
||||
return this.sysDarkPrefers.matches;
|
||||
}
|
||||
|
||||
|
@ -65,10 +52,6 @@
|
|||
return this.mode === ModeToggle.DARK_MODE;
|
||||
}
|
||||
|
||||
get isLightMode() {
|
||||
return this.mode === ModeToggle.LIGHT_MODE;
|
||||
}
|
||||
|
||||
get hasMode() {
|
||||
return this.mode != null;
|
||||
}
|
||||
|
@ -77,12 +60,12 @@
|
|||
return sessionStorage.getItem(ModeToggle.MODE_KEY);
|
||||
}
|
||||
|
||||
/* get the current mode on screen */
|
||||
{%- comment -%} get the current mode on screen {%- endcomment -%}
|
||||
get modeStatus() {
|
||||
if (this.isDarkMode || (!this.hasMode && this.isSysDarkPrefer)) {
|
||||
return ModeToggle.DARK_MODE;
|
||||
if (this.hasMode) {
|
||||
return this.mode;
|
||||
} else {
|
||||
return ModeToggle.LIGHT_MODE;
|
||||
return this.isPreferDark ? ModeToggle.DARK_MODE : ModeToggle.LIGHT_MODE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +84,9 @@
|
|||
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() {
|
||||
window.postMessage(
|
||||
{
|
||||
|
@ -114,21 +99,9 @@
|
|||
|
||||
flipMode() {
|
||||
if (this.hasMode) {
|
||||
if (this.isSysDarkPrefer) {
|
||||
if (this.isLightMode) {
|
||||
this.clearMode();
|
||||
} else {
|
||||
this.setLight();
|
||||
}
|
||||
} else {
|
||||
if (this.isDarkMode) {
|
||||
this.clearMode();
|
||||
} else {
|
||||
this.setDark();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.isSysDarkPrefer) {
|
||||
if (this.isPreferDark) {
|
||||
this.setLight();
|
||||
} else {
|
||||
this.setDark();
|
||||
|
@ -136,8 +109,8 @@
|
|||
}
|
||||
|
||||
this.notify();
|
||||
} /* flipMode() */
|
||||
} /* ModeToggle */
|
||||
}
|
||||
}
|
||||
|
||||
const modeToggle = new ModeToggle();
|
||||
</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 -}}
|
|
@ -97,7 +97,7 @@
|
|||
{% assign _lazyload = true %}
|
||||
|
||||
{%- capture _img_url -%}
|
||||
{% include img-url.html src=_src img_path=page.img_path %}
|
||||
{% include media-url.html src=_src subpath=page.media_subpath %}
|
||||
{%- endcapture -%}
|
||||
|
||||
{% assign _path_prefix = _img_url | remove: _src %}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
{% assign match_posts = match_posts | push: site.tags[tag] | uniq %}
|
||||
{% endfor %}
|
||||
|
||||
{% assign match_posts = match_posts | reverse %}
|
||||
{% assign last_index = match_posts.size | minus: 1 %}
|
||||
{% assign score_list = '' | split: '' %}
|
||||
|
||||
|
@ -81,10 +82,7 @@
|
|||
{% include datetime.html date=post.date lang=include.lang %}
|
||||
<h4 class="pt-0 my-2">{{ post.title }}</h4>
|
||||
<div class="text-muted">
|
||||
<p>
|
||||
{% include no-linenos.html content=post.content %}
|
||||
{{ content | markdownify | strip_html | truncate: 200 | escape }}
|
||||
</p>
|
||||
<p>{% include post-description.html %}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
{% capture not_found %}<p class="mt-5">{{ site.data.locales[include.lang].search.no_results }}</p>{% endcapture %}
|
||||
|
||||
<script>
|
||||
/* Note: dependent library will be loaded in `js-selector.html` */
|
||||
{%- comment -%} Note: dependent library will be loaded in `js-selector.html` {%- endcomment -%}
|
||||
SimpleJekyllSearch({
|
||||
searchInput: document.getElementById('search-input'),
|
||||
resultsContainer: document.getElementById('search-results'),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!-- 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 id="search-hints">
|
||||
{% include_cached trending-tags.html %}
|
||||
|
|
|
@ -5,15 +5,13 @@
|
|||
<a href="{{ '/' | relative_url }}" id="avatar" class="rounded-circle">
|
||||
{%- if site.avatar != empty and site.avatar -%}
|
||||
{%- capture avatar_url -%}
|
||||
{% include img-url.html src=site.avatar %}
|
||||
{% include media-url.html src=site.avatar %}
|
||||
{%- endcapture -%}
|
||||
<img src="{{- avatar_url -}}" width="112" height="112" alt="avatar" onerror="this.style.display='none'">
|
||||
{%- endif -%}
|
||||
</a>
|
||||
|
||||
<h1 class="site-title">
|
||||
<a href="{{ '/' | relative_url }}">{{ site.title }}</a>
|
||||
</h1>
|
||||
<a class="site-title d-block" href="{{ '/' | relative_url }}">{{ site.title }}</a>
|
||||
<p class="site-subtitle fst-italic mb-0">{{ site.tagline }}</p>
|
||||
</header>
|
||||
<!-- .profile-wrapper -->
|
||||
|
@ -44,7 +42,7 @@
|
|||
|
||||
<div class="sidebar-bottom d-flex flex-wrap align-items-center w-100">
|
||||
{% 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>
|
||||
</button>
|
||||
|
||||
|
|
10
_includes/toc-status.html
Normal file
10
_includes/toc-status.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
{% comment %}
|
||||
Determine TOC state and return it through variable "enable_toc"
|
||||
{% endcomment %}
|
||||
|
||||
{% assign enable_toc = false %}
|
||||
{% if site.toc and page.toc %}
|
||||
{% if page.content contains '<h2' or page.content contains '<h3' %}
|
||||
{% assign enable_toc = true %}
|
||||
{% endif %}
|
||||
{% endif %}
|
|
@ -1,13 +1,8 @@
|
|||
{% assign enable_toc = false %}
|
||||
{% if site.toc and page.toc %}
|
||||
{% if page.content contains '<h2' or page.content contains '<h3' %}
|
||||
{% assign enable_toc = true %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% include toc-status.html %}
|
||||
|
||||
{% if enable_toc %}
|
||||
<section id="toc-wrapper" class="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>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
<i class="fas fa-search fa-fw"></i>
|
||||
</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>
|
||||
<input
|
||||
class="form-control"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Chirpy v<%= pkg.version %> | © 2019 <%= pkg.author %> | <%= pkg.license %> Licensed | <%= pkg.homepage %>
|
|
@ -1,5 +1,5 @@
|
|||
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
||||
|
||||
basic();
|
||||
initSidebar();
|
||||
initTopbar();
|
||||
basic();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
||||
import { initLocaleDatetime, loadImg } from './modules/plugins';
|
||||
|
||||
basic();
|
||||
loadImg();
|
||||
initLocaleDatetime();
|
||||
initSidebar();
|
||||
initTopbar();
|
||||
initLocaleDatetime();
|
||||
loadImg();
|
||||
basic();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
||||
import { initLocaleDatetime } from './modules/plugins';
|
||||
|
||||
basic();
|
||||
initSidebar();
|
||||
initTopbar();
|
||||
initLocaleDatetime();
|
||||
basic();
|
||||
|
|
|
@ -3,18 +3,17 @@
|
|||
*/
|
||||
|
||||
export function back2top() {
|
||||
const $window = $(window);
|
||||
const $btn = $('#back-to-top');
|
||||
const btn = document.getElementById('back-to-top');
|
||||
|
||||
$window.on('scroll', () => {
|
||||
if ($window.scrollTop() > 50) {
|
||||
$btn.fadeIn();
|
||||
window.addEventListener('scroll', () => {
|
||||
if (window.scrollY > 50) {
|
||||
btn.classList.add('show');
|
||||
} else {
|
||||
$btn.fadeOut();
|
||||
btn.classList.remove('show');
|
||||
}
|
||||
});
|
||||
|
||||
$btn.on('click', () => {
|
||||
$window.scrollTop(0);
|
||||
btn.addEventListener('click', () => {
|
||||
window.scrollTo({ top: 0 });
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
/**
|
||||
* Tab 'Categories' expand/close effect.
|
||||
*/
|
||||
|
||||
import 'bootstrap/js/src/collapse.js';
|
||||
|
||||
const childPrefix = 'l_';
|
||||
const parentPrefix = 'h_';
|
||||
const collapse = $('.collapse');
|
||||
const children = document.getElementsByClassName('collapse');
|
||||
|
||||
export function categoryCollapse() {
|
||||
/* close up top-category */
|
||||
collapse.on('hide.bs.collapse', function () {
|
||||
/* Bootstrap collapse events. */ const parentId =
|
||||
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');
|
||||
[...children].forEach((elem) => {
|
||||
const id = parentPrefix + elem.id.substring(childPrefix.length);
|
||||
const parent = document.getElementById(id);
|
||||
|
||||
// collapse sub-categories
|
||||
elem.addEventListener('hide.bs.collapse', () => {
|
||||
if (parent) {
|
||||
parent.querySelector('.far.fa-folder-open').className =
|
||||
'far fa-folder fa-fw';
|
||||
parent.querySelector('.fas.fa-angle-down').classList.add('rotate');
|
||||
parent.classList.remove('hide-border-bottom');
|
||||
}
|
||||
});
|
||||
|
||||
/* expand the top category */
|
||||
collapse.on('show.bs.collapse', function () {
|
||||
const parentId =
|
||||
parentPrefix + $(this).attr('id').substring(childPrefix.length);
|
||||
if (parentId) {
|
||||
$(`#${parentId} .far.fa-folder`).attr(
|
||||
'class',
|
||||
'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,85 +2,88 @@
|
|||
* Clipboard functions
|
||||
*
|
||||
* 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 ICON_DEFAULT = 'far fa-clipboard';
|
||||
const ICON_SUCCESS = 'fas fa-check';
|
||||
|
||||
const ATTR_TIMEOUT = 'timeout';
|
||||
const ATTR_TITLE_SUCCEED = 'data-title-succeed';
|
||||
const ATTR_TITLE_ORIGIN = 'data-bs-original-title';
|
||||
const TIMEOUT = 2000; // in milliseconds
|
||||
|
||||
function isLocked(node) {
|
||||
if ($(node)[0].hasAttribute(ATTR_TIMEOUT)) {
|
||||
let timeout = $(node).attr(ATTR_TIMEOUT);
|
||||
if (node.hasAttribute(ATTR_TIMEOUT)) {
|
||||
let timeout = node.getAttribute(ATTR_TIMEOUT);
|
||||
if (Number(timeout) > Date.now()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function lock(node) {
|
||||
$(node).attr(ATTR_TIMEOUT, Date.now() + TIMEOUT);
|
||||
node.setAttribute(ATTR_TIMEOUT, Date.now() + TIMEOUT);
|
||||
}
|
||||
|
||||
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) {
|
||||
const succeedTitle = $(btn).attr(ATTR_TITLE_SUCCEED);
|
||||
$(btn).attr(ATTR_TITLE_ORIGIN, succeedTitle).tooltip('show');
|
||||
const succeedTitle = btn.getAttribute(ATTR_TITLE_SUCCEED);
|
||||
btn.setAttribute(ATTR_TITLE_ORIGIN, succeedTitle);
|
||||
Tooltip.getInstance(btn).show();
|
||||
}
|
||||
|
||||
function hideTooltip(btn) {
|
||||
$(btn).tooltip('hide').removeAttr(ATTR_TITLE_ORIGIN);
|
||||
Tooltip.getInstance(btn).hide();
|
||||
btn.removeAttribute(ATTR_TITLE_ORIGIN);
|
||||
}
|
||||
|
||||
function setSuccessIcon(btn) {
|
||||
let btnNode = $(btn);
|
||||
let iconNode = btnNode.children();
|
||||
iconNode.attr('class', ICON_SUCCESS);
|
||||
const icon = btn.children[0];
|
||||
icon.setAttribute('class', ICON_SUCCESS);
|
||||
}
|
||||
|
||||
function resumeIcon(btn) {
|
||||
let btnNode = $(btn);
|
||||
let iconNode = btnNode.children();
|
||||
iconNode.attr('class', ICON_DEFAULT);
|
||||
const icon = btn.children[0];
|
||||
icon.setAttribute('class', ICON_DEFAULT);
|
||||
}
|
||||
|
||||
export function initClipboard() {
|
||||
function setCodeClipboard() {
|
||||
const clipboardList = document.querySelectorAll(clipboardSelector);
|
||||
|
||||
if (clipboardList.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initial the clipboard.js object
|
||||
if ($(clipboardSelector).length) {
|
||||
const clipboard = new ClipboardJS(clipboardSelector, {
|
||||
target(trigger) {
|
||||
let codeBlock = trigger.parentNode.nextElementSibling;
|
||||
target: (trigger) => {
|
||||
const codeBlock = trigger.parentNode.nextElementSibling;
|
||||
return codeBlock.querySelector('code .rouge-code');
|
||||
}
|
||||
});
|
||||
|
||||
const clipboardList = document.querySelectorAll(clipboardSelector);
|
||||
[...clipboardList].map(
|
||||
(elem) =>
|
||||
new bootstrap.Tooltip(elem, {
|
||||
new Tooltip(elem, {
|
||||
placement: 'left'
|
||||
})
|
||||
);
|
||||
|
||||
clipboard.on('success', (e) => {
|
||||
const trigger = e.trigger;
|
||||
|
||||
e.clearSelection();
|
||||
|
||||
const trigger = e.trigger;
|
||||
if (isLocked(trigger)) {
|
||||
return;
|
||||
}
|
||||
|
@ -95,14 +98,17 @@ export function initClipboard() {
|
|||
unlock(trigger);
|
||||
}, TIMEOUT);
|
||||
});
|
||||
}
|
||||
|
||||
function setLinkClipboard() {
|
||||
const btnCopyLink = document.getElementById('copy-link');
|
||||
|
||||
if (btnCopyLink === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* --- Post link sharing --- */
|
||||
|
||||
const btnCopyLink = $('#copy-link');
|
||||
|
||||
btnCopyLink.on('click', (e) => {
|
||||
let target = $(e.target);
|
||||
btnCopyLink.addEventListener('click', (e) => {
|
||||
const target = e.target;
|
||||
|
||||
if (isLocked(target)) {
|
||||
return;
|
||||
|
@ -110,21 +116,28 @@ export function initClipboard() {
|
|||
|
||||
// Copy URL to clipboard
|
||||
navigator.clipboard.writeText(window.location.href).then(() => {
|
||||
const defaultTitle = target.attr(ATTR_TITLE_ORIGIN);
|
||||
const succeedTitle = target.attr(ATTR_TITLE_SUCCEED);
|
||||
const defaultTitle = target.getAttribute(ATTR_TITLE_ORIGIN);
|
||||
const succeedTitle = target.getAttribute(ATTR_TITLE_SUCCEED);
|
||||
|
||||
// Switch tooltip title
|
||||
target.attr(ATTR_TITLE_ORIGIN, succeedTitle).tooltip('show');
|
||||
target.setAttribute(ATTR_TITLE_ORIGIN, succeedTitle);
|
||||
Tooltip.getInstance(target).show();
|
||||
|
||||
lock(target);
|
||||
|
||||
setTimeout(() => {
|
||||
target.attr(ATTR_TITLE_ORIGIN, defaultTitle);
|
||||
target.setAttribute(ATTR_TITLE_ORIGIN, defaultTitle);
|
||||
unlock(target);
|
||||
}, TIMEOUT);
|
||||
});
|
||||
});
|
||||
|
||||
btnCopyLink.on('mouseleave', function (e) {
|
||||
const target = $(e.target);
|
||||
target.tooltip('hide');
|
||||
btnCopyLink.addEventListener('mouseleave', (e) => {
|
||||
Tooltip.getInstance(e.target).hide();
|
||||
});
|
||||
}
|
||||
|
||||
export function initClipboard() {
|
||||
setCodeClipboard();
|
||||
setLinkClipboard();
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ const cover = {
|
|||
};
|
||||
|
||||
function removeCover(clzss) {
|
||||
$(this).parent().removeClass(clzss);
|
||||
this.parentElement.classList.remove(clzss);
|
||||
}
|
||||
|
||||
function handleImage() {
|
||||
|
@ -30,32 +30,38 @@ function handleImage() {
|
|||
* Switches the LQIP with the real image URL.
|
||||
*/
|
||||
function switchLQIP() {
|
||||
const $img = $(this);
|
||||
const src = $img.attr(ATTR_DATA_SRC);
|
||||
|
||||
$img.attr('src', encodeURI(src));
|
||||
$img.removeAttr(ATTR_DATA_SRC);
|
||||
const src = this.getAttribute(ATTR_DATA_SRC);
|
||||
this.setAttribute('src', encodeURI(src));
|
||||
this.removeAttribute(ATTR_DATA_SRC);
|
||||
}
|
||||
|
||||
export function loadImg() {
|
||||
const $images = $('article img');
|
||||
const images = document.querySelectorAll('article img');
|
||||
|
||||
if ($images.length) {
|
||||
$images.on('load', handleImage);
|
||||
if (images.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
images.forEach((img) => {
|
||||
img.addEventListener('load', handleImage);
|
||||
});
|
||||
|
||||
// Images loaded from the browser cache do not trigger the 'load' event
|
||||
$('article img[loading="lazy"]').each(function () {
|
||||
if (this.complete) {
|
||||
removeCover.call(this, cover.SHIMMER);
|
||||
document.querySelectorAll('article img[loading="lazy"]').forEach((img) => {
|
||||
if (img.complete) {
|
||||
removeCover.call(img, cover.SHIMMER);
|
||||
}
|
||||
});
|
||||
|
||||
// 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.
|
||||
const $lqips = $(`article img[${ATTR_DATA_LQIP}="true"]`);
|
||||
const lqips = document.querySelectorAll(
|
||||
`article img[${ATTR_DATA_LQIP}="true"]`
|
||||
);
|
||||
|
||||
if ($lqips.length) {
|
||||
$lqips.each(switchLQIP);
|
||||
if (lqips.length) {
|
||||
lqips.forEach((lqip) => {
|
||||
switchLQIP.call(lqip);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,60 @@
|
|||
/**
|
||||
* Set up image popup
|
||||
*
|
||||
* See: https://github.com/dimsemenov/Magnific-Popup
|
||||
* Dependencies: https://github.com/biati-digital/glightbox
|
||||
*/
|
||||
|
||||
const html = document.documentElement;
|
||||
const lightImages = '.popup:not(.dark)';
|
||||
const darkImages = '.popup:not(.light)';
|
||||
let selector = lightImages;
|
||||
|
||||
function updateImages(current, reverse) {
|
||||
if (selector === lightImages) {
|
||||
selector = darkImages;
|
||||
} else {
|
||||
selector = lightImages;
|
||||
}
|
||||
|
||||
if (reverse === null) {
|
||||
reverse = GLightbox({ selector: `${selector}` });
|
||||
}
|
||||
|
||||
[current, reverse] = [reverse, current];
|
||||
}
|
||||
|
||||
export function imgPopup() {
|
||||
if ($('.popup') <= 0) {
|
||||
if (document.querySelector('.popup') === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('.popup').magnificPopup({
|
||||
type: 'image',
|
||||
closeOnContentClick: true,
|
||||
showCloseBtn: false,
|
||||
zoom: {
|
||||
enabled: true,
|
||||
duration: 300,
|
||||
easing: 'ease-in-out'
|
||||
const hasDualImages = !(
|
||||
document.querySelector('.popup.light') === null &&
|
||||
document.querySelector('.popup.dark') === null
|
||||
);
|
||||
|
||||
if (
|
||||
(html.hasAttribute('data-mode') &&
|
||||
html.getAttribute('data-mode') === 'dark') ||
|
||||
(!html.hasAttribute('data-mode') &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
) {
|
||||
selector = darkImages;
|
||||
}
|
||||
|
||||
let current = GLightbox({ selector: `${selector}` });
|
||||
|
||||
if (hasDualImages && document.getElementById('mode-toggle')) {
|
||||
let reverse = null;
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
if (
|
||||
event.source === window &&
|
||||
event.data &&
|
||||
event.data.direction === ModeToggle.ID
|
||||
) {
|
||||
updateImages(current, reverse);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,15 @@ class LocaleHelper {
|
|||
}
|
||||
|
||||
static get locale() {
|
||||
return $('html').attr('lang').substring(0, 2);
|
||||
return document.documentElement.getAttribute('lang').substring(0, 2);
|
||||
}
|
||||
|
||||
static getTimestamp(elem) {
|
||||
return Number(elem.attr(LocaleHelper.attrTimestamp)); // unix timestamp
|
||||
return Number(elem.getAttribute(this.attrTimestamp)); // unix timestamp
|
||||
}
|
||||
|
||||
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.extend(window.dayjs_plugin_localizedFormat);
|
||||
|
||||
$(`[${LocaleHelper.attrTimestamp}]`).each(function () {
|
||||
const date = dayjs.unix(LocaleHelper.getTimestamp($(this)));
|
||||
const text = date.format(LocaleHelper.getDateFormat($(this)));
|
||||
$(this).text(text);
|
||||
$(this).removeAttr(LocaleHelper.attrTimestamp);
|
||||
$(this).removeAttr(LocaleHelper.attrDateFormat);
|
||||
document
|
||||
.querySelectorAll(`[${LocaleHelper.attrTimestamp}]`)
|
||||
.forEach((elem) => {
|
||||
const date = dayjs.unix(LocaleHelper.getTimestamp(elem));
|
||||
const text = date.format(LocaleHelper.getDateFormat(elem));
|
||||
elem.textContent = text;
|
||||
elem.removeAttribute(LocaleHelper.attrTimestamp);
|
||||
elem.removeAttribute(LocaleHelper.attrDateFormat);
|
||||
|
||||
// setup tooltips
|
||||
const tooltip = $(this).attr('data-bs-toggle');
|
||||
if (typeof tooltip === 'undefined' || tooltip !== 'tooltip') {
|
||||
return;
|
||||
if (
|
||||
elem.hasAttribute('data-bs-toggle') &&
|
||||
elem.getAttribute('data-bs-toggle') === 'tooltip'
|
||||
) {
|
||||
// see: https://day.js.org/docs/en/display/format#list-of-localized-formats
|
||||
const tooltipText = date.format('llll');
|
||||
elem.setAttribute('data-bs-title', tooltipText);
|
||||
}
|
||||
|
||||
const tooltipText = date.format('llll'); // see: https://day.js.org/docs/en/display/format#list-of-localized-formats
|
||||
$(this).attr('data-bs-title', tooltipText);
|
||||
new bootstrap.Tooltip($(this));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,21 +1,14 @@
|
|||
/**
|
||||
* Add listener for theme mode toggle
|
||||
*/
|
||||
const $toggleElem = $('.mode-toggle');
|
||||
const toggle = document.getElementById('mode-toggle');
|
||||
|
||||
export function modeWatcher() {
|
||||
if ($toggleElem.length === 0) {
|
||||
if (!toggle) {
|
||||
return;
|
||||
}
|
||||
|
||||
$toggleElem.off().on('click', (e) => {
|
||||
const $target = $(e.target);
|
||||
let $btn =
|
||||
$target.prop('tagName') === 'button'.toUpperCase()
|
||||
? $target
|
||||
: $target.parent();
|
||||
|
||||
modeToggle.flipMode(); // modeToggle: `_includes/mode-toggle.html`
|
||||
$btn.trigger('blur'); // remove the clicking outline
|
||||
toggle.addEventListener('click', () => {
|
||||
modeToggle.flipMode();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,121 +1,109 @@
|
|||
/**
|
||||
* This script make #search-result-wrapper switch to unloaded or shown automatically.
|
||||
* This script make #search-result-wrapper switch to unload 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 C_LOADED = 'loaded';
|
||||
const C_UNLOADED = 'unloaded';
|
||||
const C_FOCUS = 'input-focus';
|
||||
const C_FLEX = 'd-flex';
|
||||
const btnSbTrigger = document.getElementById('sidebar-trigger');
|
||||
const btnSearchTrigger = document.getElementById('search-trigger');
|
||||
const btnCancel = document.getElementById('search-cancel');
|
||||
const content = document.querySelectorAll('#main-wrapper>.container>.row');
|
||||
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 {
|
||||
static offset = 0;
|
||||
static resultVisible = false;
|
||||
// CSS class names
|
||||
const LOADED = 'd-block';
|
||||
const UNLOADED = 'd-none';
|
||||
const FOCUS = 'input-focus';
|
||||
const FLEX = 'd-flex';
|
||||
|
||||
static on() {
|
||||
ScrollBlocker.offset = window.scrollY;
|
||||
$viewport.scrollTop(0);
|
||||
}
|
||||
|
||||
static off() {
|
||||
$viewport.scrollTop(ScrollBlocker.offset);
|
||||
}
|
||||
}
|
||||
|
||||
/*--- Actions in mobile screens (Sidebar hidden) ---*/
|
||||
/* Actions in mobile screens (Sidebar hidden) */
|
||||
class MobileSearchBar {
|
||||
static on() {
|
||||
$btnSbTrigger.addClass(C_UNLOADED);
|
||||
$topbarTitle.addClass(C_UNLOADED);
|
||||
$btnSearchTrigger.addClass(C_UNLOADED);
|
||||
$search.addClass(C_FLEX);
|
||||
$btnCancel.addClass(C_LOADED);
|
||||
btnSbTrigger.classList.add(UNLOADED);
|
||||
topbarTitle.classList.add(UNLOADED);
|
||||
btnSearchTrigger.classList.add(UNLOADED);
|
||||
search.classList.add(FLEX);
|
||||
btnCancel.classList.add(LOADED);
|
||||
}
|
||||
|
||||
static off() {
|
||||
$btnCancel.removeClass(C_LOADED);
|
||||
$search.removeClass(C_FLEX);
|
||||
$btnSbTrigger.removeClass(C_UNLOADED);
|
||||
$topbarTitle.removeClass(C_UNLOADED);
|
||||
$btnSearchTrigger.removeClass(C_UNLOADED);
|
||||
btnCancel.classList.remove(LOADED);
|
||||
search.classList.remove(FLEX);
|
||||
btnSbTrigger.classList.remove(UNLOADED);
|
||||
topbarTitle.classList.remove(UNLOADED);
|
||||
btnSearchTrigger.classList.remove(UNLOADED);
|
||||
}
|
||||
}
|
||||
|
||||
class ResultSwitch {
|
||||
static resultVisible = false;
|
||||
|
||||
static on() {
|
||||
if (!ScrollBlocker.resultVisible) {
|
||||
// the block method must be called before $(#main-wrapper>.container) unloaded.
|
||||
ScrollBlocker.on();
|
||||
$resultWrapper.removeClass(C_UNLOADED);
|
||||
$content.addClass(C_UNLOADED);
|
||||
ScrollBlocker.resultVisible = true;
|
||||
if (!this.resultVisible) {
|
||||
resultWrapper.classList.remove(UNLOADED);
|
||||
content.forEach((el) => {
|
||||
el.classList.add(UNLOADED);
|
||||
});
|
||||
this.resultVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
static off() {
|
||||
if (ScrollBlocker.resultVisible) {
|
||||
$results.empty();
|
||||
if ($hints.hasClass(C_UNLOADED)) {
|
||||
$hints.removeClass(C_UNLOADED);
|
||||
if (this.resultVisible) {
|
||||
results.innerHTML = '';
|
||||
|
||||
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
|
||||
ScrollBlocker.off();
|
||||
|
||||
$input.val('');
|
||||
ScrollBlocker.resultVisible = false;
|
||||
resultWrapper.classList.add(UNLOADED);
|
||||
content.forEach((el) => {
|
||||
el.classList.remove(UNLOADED);
|
||||
});
|
||||
input.textContent = '';
|
||||
this.resultVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isMobileView() {
|
||||
return $btnCancel.hasClass(C_LOADED);
|
||||
return btnCancel.classList.contains(LOADED);
|
||||
}
|
||||
|
||||
export function displaySearch() {
|
||||
$btnSearchTrigger.on('click', function () {
|
||||
btnSearchTrigger.addEventListener('click', () => {
|
||||
MobileSearchBar.on();
|
||||
ResultSwitch.on();
|
||||
$input.trigger('focus');
|
||||
input.focus();
|
||||
});
|
||||
|
||||
$btnCancel.on('click', function () {
|
||||
btnCancel.addEventListener('click', () => {
|
||||
MobileSearchBar.off();
|
||||
ResultSwitch.off();
|
||||
});
|
||||
|
||||
$input.on('focus', function () {
|
||||
$search.addClass(C_FOCUS);
|
||||
input.addEventListener('focus', () => {
|
||||
search.classList.add(FOCUS);
|
||||
});
|
||||
|
||||
$input.on('focusout', function () {
|
||||
$search.removeClass(C_FOCUS);
|
||||
input.addEventListener('focusout', () => {
|
||||
search.classList.remove(FOCUS);
|
||||
});
|
||||
|
||||
$input.on('input', () => {
|
||||
if ($input.val() === '') {
|
||||
input.addEventListener('input', () => {
|
||||
if (input.value === '') {
|
||||
if (isMobileView()) {
|
||||
$hints.removeClass(C_UNLOADED);
|
||||
hints.classList.remove(UNLOADED);
|
||||
} else {
|
||||
ResultSwitch.off();
|
||||
}
|
||||
} else {
|
||||
ResultSwitch.on();
|
||||
if (isMobileView()) {
|
||||
$hints.addClass(C_UNLOADED);
|
||||
hints.classList.add(UNLOADED);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,24 +2,21 @@
|
|||
* Expand or close the sidebar in mobile screens.
|
||||
*/
|
||||
|
||||
const $body = $('body');
|
||||
const ATTR_DISPLAY = 'sidebar-display';
|
||||
const $sidebar = document.getElementById('sidebar');
|
||||
const $trigger = document.getElementById('sidebar-trigger');
|
||||
const $mask = document.getElementById('mask');
|
||||
|
||||
class SidebarUtil {
|
||||
static isExpanded = false;
|
||||
static #isExpanded = false;
|
||||
|
||||
static toggle() {
|
||||
if (SidebarUtil.isExpanded === false) {
|
||||
$body.attr(ATTR_DISPLAY, '');
|
||||
} else {
|
||||
$body.removeAttr(ATTR_DISPLAY);
|
||||
}
|
||||
|
||||
SidebarUtil.isExpanded = !SidebarUtil.isExpanded;
|
||||
this.#isExpanded = !this.#isExpanded;
|
||||
document.body.toggleAttribute('sidebar-display', this.#isExpanded);
|
||||
$sidebar.classList.toggle('z-2', this.#isExpanded);
|
||||
$mask.classList.toggle('d-none', !this.#isExpanded);
|
||||
}
|
||||
}
|
||||
|
||||
export function sidebarExpand() {
|
||||
$('#sidebar-trigger').on('click', SidebarUtil.toggle);
|
||||
$('#mask').on('click', SidebarUtil.toggle);
|
||||
$trigger.onclick = $mask.onclick = () => SidebarUtil.toggle();
|
||||
}
|
||||
|
|
|
@ -1,13 +1,33 @@
|
|||
export function toc() {
|
||||
if (document.querySelector('main h2, main h3')) {
|
||||
// see: https://github.com/tscanlin/tocbot#usage
|
||||
tocbot.init({
|
||||
tocSelector: '#toc',
|
||||
contentSelector: '.content',
|
||||
ignoreSelector: '[data-toc-skip]',
|
||||
headingSelector: 'h2, h3, h4',
|
||||
orderedList: false,
|
||||
scrollSmooth: false
|
||||
});
|
||||
import { TocMobile as mobile } from './toc/toc-mobile';
|
||||
import { TocDesktop as desktop } from './toc/toc-desktop';
|
||||
|
||||
const desktopMode = matchMedia('(min-width: 1200px)');
|
||||
|
||||
function refresh(e) {
|
||||
if (e.matches) {
|
||||
if (mobile.popupOpened) {
|
||||
mobile.hidePopup();
|
||||
}
|
||||
|
||||
desktop.refresh();
|
||||
} else {
|
||||
mobile.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (document.querySelector('main>article[data-toc="true"]') === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid create multiple instances of Tocbot. Ref: <https://github.com/tscanlin/tocbot/issues/203>
|
||||
if (desktopMode.matches) {
|
||||
desktop.init();
|
||||
} else {
|
||||
mobile.init();
|
||||
}
|
||||
|
||||
desktopMode.onchange = refresh;
|
||||
}
|
||||
|
||||
export { init as initToc };
|
||||
|
|
22
_javascript/modules/components/toc/toc-desktop.js
Normal file
22
_javascript/modules/components/toc/toc-desktop.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
export class TocDesktop {
|
||||
/* Tocbot options Ref: https://github.com/tscanlin/tocbot#usage */
|
||||
static options = {
|
||||
tocSelector: '#toc',
|
||||
contentSelector: '.content',
|
||||
ignoreSelector: '[data-toc-skip]',
|
||||
headingSelector: 'h2, h3, h4',
|
||||
orderedList: false,
|
||||
scrollSmooth: false,
|
||||
headingsOffset: 16 * 2 // 2rem
|
||||
};
|
||||
|
||||
static refresh() {
|
||||
tocbot.refresh(this.options);
|
||||
}
|
||||
|
||||
static init() {
|
||||
if (document.getElementById('toc-wrapper')) {
|
||||
tocbot.init(this.options);
|
||||
}
|
||||
}
|
||||
}
|
125
_javascript/modules/components/toc/toc-mobile.js
Normal file
125
_javascript/modules/components/toc/toc-mobile.js
Normal file
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
* TOC button, topbar and popup for mobile devices
|
||||
*/
|
||||
|
||||
const $tocBar = document.getElementById('toc-bar');
|
||||
const $soloTrigger = document.getElementById('toc-solo-trigger');
|
||||
const $triggers = document.getElementsByClassName('toc-trigger');
|
||||
const $popup = document.getElementById('toc-popup');
|
||||
const $btnClose = document.getElementById('toc-popup-close');
|
||||
|
||||
const SCROLL_LOCK = 'overflow-hidden';
|
||||
const CLOSING = 'closing';
|
||||
|
||||
export class TocMobile {
|
||||
static #invisible = true;
|
||||
static #barHeight = 16 * 3; // 3rem
|
||||
|
||||
static options = {
|
||||
tocSelector: '#toc-popup-content',
|
||||
contentSelector: '.content',
|
||||
ignoreSelector: '[data-toc-skip]',
|
||||
headingSelector: 'h2, h3, h4',
|
||||
orderedList: false,
|
||||
scrollSmooth: false,
|
||||
collapseDepth: 4,
|
||||
headingsOffset: this.#barHeight
|
||||
};
|
||||
|
||||
static initBar() {
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
$tocBar.classList.toggle('invisible', entry.isIntersecting);
|
||||
});
|
||||
},
|
||||
{ rootMargin: `-${this.#barHeight}px 0px 0px 0px` }
|
||||
);
|
||||
|
||||
observer.observe($soloTrigger);
|
||||
this.#invisible = false;
|
||||
}
|
||||
|
||||
static listenAnchors() {
|
||||
const $anchors = document.getElementsByClassName('toc-link');
|
||||
[...$anchors].forEach((anchor) => {
|
||||
anchor.onclick = () => this.hidePopup();
|
||||
});
|
||||
}
|
||||
|
||||
static refresh() {
|
||||
if (this.#invisible) {
|
||||
this.initComponents();
|
||||
}
|
||||
tocbot.refresh(this.options);
|
||||
this.listenAnchors();
|
||||
}
|
||||
|
||||
static get popupOpened() {
|
||||
return $popup.open;
|
||||
}
|
||||
|
||||
static showPopup() {
|
||||
this.lockScroll(true);
|
||||
$popup.showModal();
|
||||
const activeItem = $popup.querySelector('li.is-active-li');
|
||||
activeItem.scrollIntoView({ block: 'center' });
|
||||
}
|
||||
|
||||
static hidePopup() {
|
||||
$popup.toggleAttribute(CLOSING);
|
||||
|
||||
$popup.addEventListener(
|
||||
'animationend',
|
||||
() => {
|
||||
$popup.toggleAttribute(CLOSING);
|
||||
$popup.close();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
this.lockScroll(false);
|
||||
}
|
||||
|
||||
static lockScroll(enable) {
|
||||
document.documentElement.classList.toggle(SCROLL_LOCK, enable);
|
||||
document.body.classList.toggle(SCROLL_LOCK, enable);
|
||||
}
|
||||
|
||||
static clickBackdrop(event) {
|
||||
if ($popup.hasAttribute(CLOSING)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rect = event.target.getBoundingClientRect();
|
||||
if (
|
||||
event.clientX < rect.left ||
|
||||
event.clientX > rect.right ||
|
||||
event.clientY < rect.top ||
|
||||
event.clientY > rect.bottom
|
||||
) {
|
||||
this.hidePopup();
|
||||
}
|
||||
}
|
||||
|
||||
static initComponents() {
|
||||
this.initBar();
|
||||
|
||||
[...$triggers].forEach((trigger) => {
|
||||
trigger.onclick = () => this.showPopup();
|
||||
});
|
||||
|
||||
$popup.onclick = (e) => this.clickBackdrop(e);
|
||||
$btnClose.onclick = () => this.hidePopup();
|
||||
$popup.oncancel = (e) => {
|
||||
e.preventDefault();
|
||||
this.hidePopup();
|
||||
};
|
||||
}
|
||||
|
||||
static init() {
|
||||
tocbot.init(this.options);
|
||||
this.listenAnchors();
|
||||
this.initComponents();
|
||||
}
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
/**
|
||||
* Initial Bootstrap Tooltip.
|
||||
*/
|
||||
import Tooltip from 'bootstrap/js/src/tooltip';
|
||||
|
||||
export function loadTooptip() {
|
||||
const tooltipTriggerList = document.querySelectorAll(
|
||||
'[data-bs-toggle="tooltip"]'
|
||||
);
|
||||
|
||||
[...tooltipTriggerList].map(
|
||||
(tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl)
|
||||
(tooltipTriggerEl) => new Tooltip(tooltipTriggerEl)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,4 +3,4 @@ export { initClipboard } from './components/clipboard';
|
|||
export { loadImg } from './components/img-loading';
|
||||
export { imgPopup } from './components/img-popup';
|
||||
export { initLocaleDatetime } from './components/locale-datetime';
|
||||
export { toc } from './components/toc';
|
||||
export { initToc } from './components/toc';
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
||||
import { loadImg, imgPopup, initClipboard } from './modules/plugins';
|
||||
|
||||
basic();
|
||||
initSidebar();
|
||||
initTopbar();
|
||||
loadImg();
|
||||
imgPopup();
|
||||
initSidebar();
|
||||
initTopbar();
|
||||
initClipboard();
|
||||
basic();
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
import { basic, initSidebar, initTopbar } from './modules/layouts';
|
||||
import { basic, initTopbar, initSidebar } from './modules/layouts';
|
||||
|
||||
import {
|
||||
loadImg,
|
||||
imgPopup,
|
||||
initLocaleDatetime,
|
||||
initClipboard,
|
||||
toc
|
||||
initToc
|
||||
} from './modules/plugins';
|
||||
|
||||
initSidebar();
|
||||
initTopbar();
|
||||
loadImg();
|
||||
initToc();
|
||||
imgPopup();
|
||||
initSidebar();
|
||||
initLocaleDatetime();
|
||||
initClipboard();
|
||||
toc();
|
||||
initTopbar();
|
||||
basic();
|
||||
|
|
|
@ -1,43 +1,44 @@
|
|||
---
|
||||
layout: compress
|
||||
permalink: /assets/js/dist/:basename.min.js
|
||||
---
|
||||
import Toast from 'bootstrap/js/src/toast';
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
const isEnabled = '{{ site.pwa.enabled }}' === 'true';
|
||||
// Get Jekyll config from URL parameters
|
||||
const src = new URL(document.currentScript.src);
|
||||
const register = src.searchParams.get('register');
|
||||
const baseUrl = src.searchParams.get('baseurl');
|
||||
|
||||
if (isEnabled) {
|
||||
const swUrl = '{{ '/sw.min.js' | relative_url }}';
|
||||
const $notification = $('#notification');
|
||||
const $btnRefresh = $('#notification .toast-body>button');
|
||||
if (register) {
|
||||
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) => {
|
||||
{% comment %}In case the user ignores the notification{% endcomment %}
|
||||
// Restore the update window that was last manually closed by the user
|
||||
if (registration.waiting) {
|
||||
$notification.toast('show');
|
||||
popupWindow.show();
|
||||
}
|
||||
|
||||
registration.addEventListener('updatefound', () => {
|
||||
registration.installing.addEventListener('statechange', () => {
|
||||
if (registration.waiting) {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
$notification.toast('show');
|
||||
popupWindow.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$btnRefresh.on('click', () => {
|
||||
btnRefresh.addEventListener('click', () => {
|
||||
if (registration.waiting) {
|
||||
registration.waiting.postMessage('SKIP_WAITING');
|
||||
}
|
||||
$notification.toast('hide');
|
||||
popupWindow.hide();
|
||||
});
|
||||
});
|
||||
|
||||
let refreshing = false;
|
||||
|
||||
{% comment %}Detect controller change and refresh all the opened tabs{% endcomment %}
|
||||
// Detect controller change and refresh all the opened tabs
|
||||
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||
if (!refreshing) {
|
||||
window.location.reload();
|
|
@ -1,32 +1,23 @@
|
|||
---
|
||||
layout: compress
|
||||
permalink: /:basename.min.js
|
||||
# PWA service worker
|
||||
---
|
||||
importScripts('./assets/js/data/swconf.js');
|
||||
|
||||
const swconfUrl = '{{ '/assets/js/data/swconf.js' | relative_url }}';
|
||||
|
||||
importScripts(swconfUrl);
|
||||
const purge = swconf.purge;
|
||||
|
||||
function verifyHost(url) {
|
||||
for (const host of swconf.allowHosts) {
|
||||
const regex = RegExp(`^http(s)?://${host}/`);
|
||||
if (regex.test(url)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const interceptor = swconf.interceptor;
|
||||
|
||||
function verifyUrl(url) {
|
||||
if (!verifyHost(url)) {
|
||||
const requestUrl = new URL(url);
|
||||
const requestPath = requestUrl.pathname;
|
||||
|
||||
if (!requestUrl.protocol.startsWith('http')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const requestPath = new URL(url).pathname;
|
||||
for (const prefix of interceptor.urlPrefixes) {
|
||||
if (requestUrl.href.startsWith(prefix)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const path of swconf.denyPaths) {
|
||||
for (const path of interceptor.paths) {
|
||||
if (requestPath.startsWith(path)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -34,10 +25,6 @@ function verifyUrl(url) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!purge) {
|
||||
swconf.allowHosts.push(location.host);
|
||||
}
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
if (purge) {
|
||||
return;
|
||||
|
@ -75,6 +62,10 @@ self.addEventListener('message', (event) => {
|
|||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
if (event.request.headers.has('range')) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.respondWith(
|
||||
caches.match(event.request).then((response) => {
|
||||
if (response) {
|
||||
|
@ -88,7 +79,7 @@ self.addEventListener('fetch', (event) => {
|
|||
return response;
|
||||
}
|
||||
|
||||
{% comment %}See: <https://developers.google.com/web/fundamentals/primers/service-workers#cache_and_return_requests>{% endcomment %}
|
||||
// See: <https://developers.google.com/web/fundamentals/primers/service-workers#cache_and_return_requests>
|
||||
let responseToCache = response.clone();
|
||||
|
||||
caches.open(swconf.cacheName).then((cache) => {
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue