Compare commits
No commits in common. "main" and "v2.3" have entirely different histories.
43
.github/workflows/static.yml
vendored
43
.github/workflows/static.yml
vendored
@ -1,43 +0,0 @@
|
|||||||
# Simple workflow for deploying static content to GitHub Pages
|
|
||||||
name: Deploy static content to Pages
|
|
||||||
|
|
||||||
on:
|
|
||||||
# Runs on pushes targeting the default branch
|
|
||||||
push:
|
|
||||||
branches: ["main"]
|
|
||||||
|
|
||||||
# Allows you to run this workflow manually from the Actions tab
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pages: write
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
|
|
||||||
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
|
|
||||||
concurrency:
|
|
||||||
group: "pages"
|
|
||||||
cancel-in-progress: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
# Single deploy job since we're just deploying
|
|
||||||
deploy:
|
|
||||||
environment:
|
|
||||||
name: github-pages
|
|
||||||
url: ${{ steps.deployment.outputs.page_url }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Setup Pages
|
|
||||||
uses: actions/configure-pages@v5
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-pages-artifact@v3
|
|
||||||
with:
|
|
||||||
# Upload entire repository
|
|
||||||
path: '.'
|
|
||||||
- name: Deploy to GitHub Pages
|
|
||||||
id: deployment
|
|
||||||
uses: actions/deploy-pages@v4
|
|
||||||
116
CONIFG.md
Normal file
116
CONIFG.md
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
# 配置文件说明
|
||||||
|
|
||||||
|
### `config.json` 文件
|
||||||
|
|
||||||
|
里面的`key`值请不要修改,如没有其中的`value`值请填写`""`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
"title":"Meekdai",
|
||||||
|
"displayTitle":"eekdai",
|
||||||
|
"subTitle":"童话是一种生活态度,仅此而已。",
|
||||||
|
"homeUrl":"http://blog.meekdai.com",
|
||||||
|
"avatarUrl":"http://meekdai.com/avatar.jpg",
|
||||||
|
"faviconUrl":"http://meekdai.com/favicon.ico",
|
||||||
|
"email":"meekdai@163.com",
|
||||||
|
"startSite":"02/16/2015",
|
||||||
|
"filingNum":"浙ICP备20023628号",
|
||||||
|
"onePageListNum":15,
|
||||||
|
"singlePage":["link","about"],
|
||||||
|
"commentLabelColor":"#006b75",
|
||||||
|
"yearColorList":["#bc4c00", "#0969da", "#1f883d", "#A333D0"],
|
||||||
|
"i18n":"CN",
|
||||||
|
"GMEEK_VERSION":"v2.3"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `.github/workflows/Gmeek.yml` 文件
|
||||||
|
|
||||||
|
此文件保存到指定目录即可,无需修改。
|
||||||
|
|
||||||
|
```yml
|
||||||
|
name: build Gmeek
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
issues:
|
||||||
|
types: [opened, edited]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Generate blog
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event.repository.owner.id == github.event.sender.id
|
||||||
|
permissions: write-all
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup Pages
|
||||||
|
id: pages
|
||||||
|
uses: actions/configure-pages@v3
|
||||||
|
|
||||||
|
- name: Get config.json
|
||||||
|
run: |
|
||||||
|
echo "====== check config.josn file ======"
|
||||||
|
cat config.json
|
||||||
|
echo "====== check config.josn end ======"
|
||||||
|
sudo apt-get install jq
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
|
||||||
|
- name: Clone source code
|
||||||
|
run: |
|
||||||
|
git clone -b $(jq -r ".GMEEK_VERSION" config.json) https://github.com/Meekdai/Gmeek.git /opt/Gmeek
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r /opt/Gmeek/requirements.txt
|
||||||
|
|
||||||
|
- name: Generate new html
|
||||||
|
run: |
|
||||||
|
cp -r ./* /opt/Gmeek/
|
||||||
|
cd /opt/Gmeek/
|
||||||
|
python Gmeek.py ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} --issue_number '${{ github.event.issue.number }}'
|
||||||
|
cp -a /opt/Gmeek/docs ${{ github.workspace }}
|
||||||
|
cp -a /opt/Gmeek/backup ${{ github.workspace }}
|
||||||
|
cp /opt/Gmeek/blogBase.json ${{ github.workspace }}
|
||||||
|
|
||||||
|
- name: update html
|
||||||
|
run: |
|
||||||
|
git config --local user.email "$(jq -r ".email" config.json)"
|
||||||
|
git config --local user.name "${{ github.repository_owner }}"
|
||||||
|
git add .
|
||||||
|
git commit -a -m '🎉auto update by Gmeek action' || echo "nothing to commit"
|
||||||
|
git push || echo "nothing to push"
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v2
|
||||||
|
with:
|
||||||
|
path: 'docs/.'
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
name: Deploy blog
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
needs: build
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
concurrency:
|
||||||
|
group: "pages"
|
||||||
|
cancel-in-progress: false
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v2
|
||||||
|
|
||||||
|
```
|
||||||
334
Gmeek.py
334
Gmeek.py
@ -1,6 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
@ -8,18 +7,14 @@ import shutil
|
|||||||
import urllib
|
import urllib
|
||||||
import requests
|
import requests
|
||||||
import argparse
|
import argparse
|
||||||
import html
|
|
||||||
from github import Github
|
from github import Github
|
||||||
from xpinyin import Pinyin
|
from xpinyin import Pinyin
|
||||||
from feedgen.feed import FeedGenerator
|
from feedgen.feed import FeedGenerator
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
from transliterate import translit
|
|
||||||
from collections import OrderedDict
|
|
||||||
######################################################################################
|
######################################################################################
|
||||||
i18n={"Search":"Search","switchTheme":"switch theme","home":"home","comments":"comments","run":"run ","days":" days","Previous":"Previous","Next":"Next"}
|
i18n={"Search":"Search","switchTheme":"switch theme","link":"link","home":"home","comments":"comments","run":"run ","days":" days","Previous":"Previous","Next":"Next"}
|
||||||
i18nCN={"Search":"搜索","switchTheme":"切换主题","home":"首页","comments":"评论","run":"网站运行","days":"天","Previous":"上一页","Next":"下一页"}
|
i18nCN={"Search":"搜索","switchTheme":"切换主题","link":"友情链接","home":"首页","comments":"评论","run":"网站运行","days":"天","Previous":"上一页","Next":"下一页"}
|
||||||
i18nRU={"Search":"Поиск","switchTheme": "Сменить тему","home":"Главная","comments":"Комментарии","run":"работает ","days":" дней","Previous":"Предыдущая","Next":"Следующая"}
|
IconList={
|
||||||
IconBase={
|
|
||||||
"post":"M0 3.75C0 2.784.784 2 1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25Zm1.75-.25a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-8.5a.25.25 0 0 0-.25-.25ZM3.5 6.25a.75.75 0 0 1 .75-.75h7a.75.75 0 0 1 0 1.5h-7a.75.75 0 0 1-.75-.75Zm.75 2.25h4a.75.75 0 0 1 0 1.5h-4a.75.75 0 0 1 0-1.5Z",
|
"post":"M0 3.75C0 2.784.784 2 1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25Zm1.75-.25a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-8.5a.25.25 0 0 0-.25-.25ZM3.5 6.25a.75.75 0 0 1 .75-.75h7a.75.75 0 0 1 0 1.5h-7a.75.75 0 0 1-.75-.75Zm.75 2.25h4a.75.75 0 0 1 0 1.5h-4a.75.75 0 0 1 0-1.5Z",
|
||||||
"link":"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z",
|
"link":"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z",
|
||||||
"about":"M10.561 8.073a6.005 6.005 0 0 1 3.432 5.142.75.75 0 1 1-1.498.07 4.5 4.5 0 0 0-8.99 0 .75.75 0 0 1-1.498-.07 6.004 6.004 0 0 1 3.431-5.142 3.999 3.999 0 1 1 5.123 0ZM10.5 5a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z",
|
"about":"M10.561 8.073a6.005 6.005 0 0 1 3.432 5.142.75.75 0 1 1-1.498.07 4.5 4.5 0 0 0-8.99 0 .75.75 0 0 1-1.498-.07 6.004 6.004 0 0 1 3.431-5.142 3.999 3.999 0 1 1 5.123 0ZM10.5 5a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z",
|
||||||
@ -29,10 +24,7 @@ IconBase={
|
|||||||
"rss":"M2.002 2.725a.75.75 0 0 1 .797-.699C8.79 2.42 13.58 7.21 13.974 13.201a.75.75 0 0 1-1.497.098 10.502 10.502 0 0 0-9.776-9.776.747.747 0 0 1-.7-.798ZM2.84 7.05h-.002a7.002 7.002 0 0 1 6.113 6.111.75.75 0 0 1-1.49.178 5.503 5.503 0 0 0-4.8-4.8.75.75 0 0 1 .179-1.489ZM2 13a1 1 0 1 1 2 0 1 1 0 0 1-2 0Z",
|
"rss":"M2.002 2.725a.75.75 0 0 1 .797-.699C8.79 2.42 13.58 7.21 13.974 13.201a.75.75 0 0 1-1.497.098 10.502 10.502 0 0 0-9.776-9.776.747.747 0 0 1-.7-.798ZM2.84 7.05h-.002a7.002 7.002 0 0 1 6.113 6.111.75.75 0 0 1-1.49.178 5.503 5.503 0 0 0-4.8-4.8.75.75 0 0 1 .179-1.489ZM2 13a1 1 0 1 1 2 0 1 1 0 0 1-2 0Z",
|
||||||
"upload":"M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z M11.78 4.72a.749.749 0 1 1-1.06 1.06L8.75 3.811V9.5a.75.75 0 0 1-1.5 0V3.811L5.28 5.78a.749.749 0 1 1-1.06-1.06l3.25-3.25a.749.749 0 0 1 1.06 0l3.25 3.25Z",
|
"upload":"M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z M11.78 4.72a.749.749 0 1 1-1.06 1.06L8.75 3.811V9.5a.75.75 0 0 1-1.5 0V3.811L5.28 5.78a.749.749 0 1 1-1.06-1.06l3.25-3.25a.749.749 0 0 1 1.06 0l3.25 3.25Z",
|
||||||
"github":"M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z",
|
"github":"M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z",
|
||||||
"home":"M6.906.664a1.749 1.749 0 0 1 2.187 0l5.25 4.2c.415.332.657.835.657 1.367v7.019A1.75 1.75 0 0 1 13.25 15h-3.5a.75.75 0 0 1-.75-.75V9H7v5.25a.75.75 0 0 1-.75.75h-3.5A1.75 1.75 0 0 1 1 13.25V6.23c0-.531.242-1.034.657-1.366l5.25-4.2Zm1.25 1.171a.25.25 0 0 0-.312 0l-5.25 4.2a.25.25 0 0 0-.094.196v7.019c0 .138.112.25.25.25H5.5V8.25a.75.75 0 0 1 .75-.75h3.5a.75.75 0 0 1 .75.75v5.25h2.75a.25.25 0 0 0 .25-.25V6.23a.25.25 0 0 0-.094-.195Z",
|
"home":"M6.906.664a1.749 1.749 0 0 1 2.187 0l5.25 4.2c.415.332.657.835.657 1.367v7.019A1.75 1.75 0 0 1 13.25 15h-3.5a.75.75 0 0 1-.75-.75V9H7v5.25a.75.75 0 0 1-.75.75h-3.5A1.75 1.75 0 0 1 1 13.25V6.23c0-.531.242-1.034.657-1.366l5.25-4.2Zm1.25 1.171a.25.25 0 0 0-.312 0l-5.25 4.2a.25.25 0 0 0-.094.196v7.019c0 .138.112.25.25.25H5.5V8.25a.75.75 0 0 1 .75-.75h3.5a.75.75 0 0 1 .75.75v5.25h2.75a.25.25 0 0 0 .25-.25V6.23a.25.25 0 0 0-.094-.195Z"
|
||||||
"sync":"M1.705 8.005a.75.75 0 0 1 .834.656 5.5 5.5 0 0 0 9.592 2.97l-1.204-1.204a.25.25 0 0 1 .177-.427h3.646a.25.25 0 0 1 .25.25v3.646a.25.25 0 0 1-.427.177l-1.38-1.38A7.002 7.002 0 0 1 1.05 8.84a.75.75 0 0 1 .656-.834ZM8 2.5a5.487 5.487 0 0 0-4.131 1.869l1.204 1.204A.25.25 0 0 1 4.896 6H1.25A.25.25 0 0 1 1 5.75V2.104a.25.25 0 0 1 .427-.177l1.38 1.38A7.002 7.002 0 0 1 14.95 7.16a.75.75 0 0 1-1.49.178A5.5 5.5 0 0 0 8 2.5Z",
|
|
||||||
"copy":"M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z",
|
|
||||||
"check":"M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
|
|
||||||
}
|
}
|
||||||
######################################################################################
|
######################################################################################
|
||||||
class GMEEK():
|
class GMEEK():
|
||||||
@ -40,7 +32,6 @@ class GMEEK():
|
|||||||
self.options=options
|
self.options=options
|
||||||
|
|
||||||
self.root_dir='docs/'
|
self.root_dir='docs/'
|
||||||
self.static_dir='static/'
|
|
||||||
self.post_folder='post/'
|
self.post_folder='post/'
|
||||||
self.backup_dir='backup/'
|
self.backup_dir='backup/'
|
||||||
self.post_dir=self.root_dir+self.post_folder
|
self.post_dir=self.root_dir+self.post_folder
|
||||||
@ -48,22 +39,24 @@ class GMEEK():
|
|||||||
user = Github(self.options.github_token)
|
user = Github(self.options.github_token)
|
||||||
self.repo = self.get_repo(user, options.repo_name)
|
self.repo = self.get_repo(user, options.repo_name)
|
||||||
self.feed = FeedGenerator()
|
self.feed = FeedGenerator()
|
||||||
self.oldFeedString=''
|
|
||||||
|
|
||||||
self.labelColorDict=json.loads('{}')
|
self.labelColorDict=json.loads('{}')
|
||||||
for label in self.repo.get_labels():
|
for label in self.repo.get_labels():
|
||||||
self.labelColorDict[label.name]='#'+label.color
|
self.labelColorDict[label.name]='#'+label.color
|
||||||
|
|
||||||
print(self.labelColorDict)
|
print(self.labelColorDict)
|
||||||
self.defaultConfig()
|
|
||||||
|
|
||||||
|
config=json.loads(open('config.json', 'r', encoding='utf-8').read())
|
||||||
|
self.blogBase=config.copy()
|
||||||
|
self.blogBase["postListJson"]=json.loads('{}')
|
||||||
|
self.blogBase["singeListJson"]=json.loads('{}')
|
||||||
|
|
||||||
|
if self.blogBase["i18n"]=="CN":
|
||||||
|
self.i18n=i18nCN
|
||||||
|
else:
|
||||||
|
self.i18n=i18n
|
||||||
|
|
||||||
def cleanFile(self):
|
def cleanFile(self):
|
||||||
workspace_path = os.environ.get('GITHUB_WORKSPACE')
|
|
||||||
if os.path.exists(workspace_path+"/"+self.backup_dir):
|
|
||||||
shutil.rmtree(workspace_path+"/"+self.backup_dir)
|
|
||||||
|
|
||||||
if os.path.exists(workspace_path+"/"+self.root_dir):
|
|
||||||
shutil.rmtree(workspace_path+"/"+self.root_dir)
|
|
||||||
|
|
||||||
if os.path.exists(self.backup_dir):
|
if os.path.exists(self.backup_dir):
|
||||||
shutil.rmtree(self.backup_dir)
|
shutil.rmtree(self.backup_dir)
|
||||||
|
|
||||||
@ -74,148 +67,46 @@ class GMEEK():
|
|||||||
os.mkdir(self.root_dir)
|
os.mkdir(self.root_dir)
|
||||||
os.mkdir(self.post_dir)
|
os.mkdir(self.post_dir)
|
||||||
|
|
||||||
if os.path.exists(self.static_dir):
|
|
||||||
for item in os.listdir(self.static_dir):
|
|
||||||
src = os.path.join(self.static_dir, item)
|
|
||||||
dst = os.path.join(self.root_dir, item)
|
|
||||||
if os.path.isfile(src):
|
|
||||||
shutil.copy(src, dst)
|
|
||||||
print(f"Copied {item} to docs")
|
|
||||||
elif os.path.isdir(src):
|
|
||||||
shutil.copytree(src, dst)
|
|
||||||
print(f"Copied directory {item} to docs")
|
|
||||||
else:
|
|
||||||
print("static does not exist")
|
|
||||||
|
|
||||||
def defaultConfig(self):
|
|
||||||
dconfig={"singlePage":[],"startSite":"","filingNum":"","onePageListNum":15,"commentLabelColor":"#006b75","yearColorList":["#bc4c00", "#0969da", "#1f883d", "#A333D0"],"i18n":"CN","themeMode":"manual","dayTheme":"light","nightTheme":"dark","urlMode":"pinyin","script":"","style":"","head":"","indexScript":"","indexStyle":"","bottomText":"","showPostSource":1,"iconList":{},"UTC":+8,"rssSplit":"sentence","exlink":{},"needComment":1,"allHead":""}
|
|
||||||
config=json.loads(open('config.json', 'r', encoding='utf-8').read())
|
|
||||||
self.blogBase={**dconfig,**config}.copy()
|
|
||||||
self.blogBase["postListJson"]=json.loads('{}')
|
|
||||||
self.blogBase["singeListJson"]=json.loads('{}')
|
|
||||||
self.blogBase["labelColorDict"]=self.labelColorDict
|
|
||||||
if "displayTitle" not in self.blogBase:
|
|
||||||
self.blogBase["displayTitle"]=self.blogBase["title"]
|
|
||||||
|
|
||||||
if "faviconUrl" not in self.blogBase:
|
|
||||||
self.blogBase["faviconUrl"]=self.blogBase["avatarUrl"]
|
|
||||||
|
|
||||||
if "ogImage" not in self.blogBase:
|
|
||||||
self.blogBase["ogImage"]=self.blogBase["avatarUrl"]
|
|
||||||
|
|
||||||
if "primerCSS" not in self.blogBase:
|
|
||||||
self.blogBase["primerCSS"]="<link href='https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/Primer/21.0.7/primer.css' rel='stylesheet' />"
|
|
||||||
|
|
||||||
if "homeUrl" not in self.blogBase:
|
|
||||||
if str(self.repo.name).lower() == (str(self.repo.owner.login) + ".github.io").lower():
|
|
||||||
self.blogBase["homeUrl"] = f"https://{self.repo.name}"
|
|
||||||
else:
|
|
||||||
self.blogBase["homeUrl"] = f"https://{self.repo.owner.login}.github.io/{self.repo.name}"
|
|
||||||
print("GitHub Pages URL: ", self.blogBase["homeUrl"])
|
|
||||||
|
|
||||||
if self.blogBase["i18n"]=="CN":
|
|
||||||
self.i18n=i18nCN
|
|
||||||
elif self.blogBase["i18n"]=="RU":
|
|
||||||
self.i18n=i18nRU
|
|
||||||
else:
|
|
||||||
self.i18n=i18n
|
|
||||||
|
|
||||||
self.TZ=datetime.timezone(datetime.timedelta(hours=self.blogBase["UTC"]))
|
|
||||||
|
|
||||||
def get_repo(self,user:Github, repo:str):
|
def get_repo(self,user:Github, repo:str):
|
||||||
return user.get_repo(repo)
|
return user.get_repo(repo)
|
||||||
|
|
||||||
def markdown2html(self, mdstr):
|
def markdown2html(self,mdstr):
|
||||||
payload = {"text": mdstr, "mode": "gfm"}
|
payload = {"text": mdstr, "mode": "markdown"}
|
||||||
headers = {"Authorization": "token {}".format(self.options.github_token)}
|
ret=requests.post("https://api.github.com/markdown", json=payload,headers={"Authorzation":"token {}".format(self.options.github_token)})
|
||||||
try:
|
if ret.status_code==200:
|
||||||
response = requests.post("https://api.github.com/markdown", json=payload, headers=headers)
|
return ret.text
|
||||||
response.raise_for_status() # Raises an exception if status code is not 200
|
else:
|
||||||
return response.text
|
raise Exception("markdown2html error status_code=%d"%(ret.status_code))
|
||||||
except requests.RequestException as e:
|
|
||||||
raise Exception("markdown2html error: {}".format(e))
|
|
||||||
|
|
||||||
def renderHtml(self,template,blogBase,postListJson,htmlDir,icon):
|
def renderHtml(self,template,blogBase,postListJson,htmlDir):
|
||||||
file_loader = FileSystemLoader('templates')
|
file_loader = FileSystemLoader('templates')
|
||||||
env = Environment(loader=file_loader)
|
env = Environment(loader=file_loader)
|
||||||
template = env.get_template(template)
|
template = env.get_template(template)
|
||||||
output = template.render(blogBase=blogBase,postListJson=postListJson,i18n=self.i18n,IconList=icon)
|
output = template.render(blogBase=blogBase,postListJson=postListJson,i18n=self.i18n,IconList=IconList)
|
||||||
f = open(htmlDir, 'w', encoding='UTF-8')
|
f = open(htmlDir, 'w', encoding='UTF-8')
|
||||||
f.write(output)
|
f.write(output)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
def createPostHtml(self,issue):
|
def createPostHtml(self,issue):
|
||||||
mdFileName=re.sub(r'[<>:/\\|?*\"]|[\0-\31]', '-', issue["postTitle"])
|
f = open("backup/"+issue["postTitle"]+".md", 'r', encoding='UTF-8')
|
||||||
f = open(self.backup_dir+mdFileName+".md", 'r', encoding='UTF-8')
|
|
||||||
post_body=self.markdown2html(f.read())
|
post_body=self.markdown2html(f.read())
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
postBase=self.blogBase.copy()
|
postBase=self.blogBase.copy()
|
||||||
|
|
||||||
if '<math-renderer' in post_body:
|
|
||||||
post_body=re.sub(r'<math-renderer.*?>','',post_body)
|
|
||||||
post_body=re.sub(r'</math-renderer>','',post_body)
|
|
||||||
issue["script"]=issue["script"]+'<script>MathJax = {tex: {inlineMath: [["$", "$"]]}};</script><script async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>'
|
|
||||||
|
|
||||||
if '<p class="markdown-alert-title">' in post_body:
|
|
||||||
issue["style"]=issue["style"]+'<style>.markdown-alert{padding:0.5rem 1rem;margin-bottom:1rem;border-left:.25em solid var(--borderColor-default,var(--color-border-default));}.markdown-alert .markdown-alert-title {display:flex;font-weight:var(--base-text-weight-medium,500);align-items:center;line-height:1;}.markdown-alert>:first-child {margin-top:0;}.markdown-alert>:last-child {margin-bottom:0;}</style>'
|
|
||||||
alerts = {
|
|
||||||
'note': 'accent',
|
|
||||||
'tip': 'success',
|
|
||||||
'important': 'done',
|
|
||||||
'warning': 'attention',
|
|
||||||
'caution': 'danger'
|
|
||||||
}
|
|
||||||
|
|
||||||
for alert, style in alerts.items():
|
|
||||||
if f'markdown-alert-{alert}' in post_body:
|
|
||||||
issue["style"] += (
|
|
||||||
f'<style>.markdown-alert.markdown-alert-{alert} {{'
|
|
||||||
f'border-left-color:var(--borderColor-{style}-emphasis, var(--color-{style}-emphasis));'
|
|
||||||
f'background-color:var(--color-{style}-subtle);}}'
|
|
||||||
f'.markdown-alert.markdown-alert-{alert} .markdown-alert-title {{'
|
|
||||||
f'color: var(--fgColor-{style},var(--color-{style}-fg));}}</style>'
|
|
||||||
)
|
|
||||||
|
|
||||||
if '<code class="notranslate">Gmeek-html' in post_body:
|
|
||||||
post_body = re.sub(r'<code class="notranslate">Gmeek-html(.*?)</code>', lambda match: html.unescape(match.group(1)), post_body, flags=re.DOTALL)
|
|
||||||
|
|
||||||
postBase["postTitle"]=issue["postTitle"]
|
postBase["postTitle"]=issue["postTitle"]
|
||||||
postBase["postUrl"]=self.blogBase["homeUrl"]+"/"+issue["postUrl"]
|
|
||||||
postBase["description"]=issue["description"]
|
|
||||||
postBase["ogImage"]=issue["ogImage"]
|
|
||||||
postBase["postBody"]=post_body
|
postBase["postBody"]=post_body
|
||||||
postBase["commentNum"]=issue["commentNum"]
|
postBase["commentNum"]=issue["commentNum"]
|
||||||
postBase["style"]=issue["style"]
|
postBase["style"]=issue["style"]
|
||||||
postBase["script"]=issue["script"]
|
postBase["script"]=issue["script"]
|
||||||
postBase["head"]=issue["head"]
|
|
||||||
postBase["top"]=issue["top"]
|
postBase["top"]=issue["top"]
|
||||||
postBase["postSourceUrl"]=issue["postSourceUrl"]
|
postBase["postSourceUrl"]=issue["postSourceUrl"]
|
||||||
postBase["repoName"]=options.repo_name
|
postBase["repoName"]=options.repo_name
|
||||||
|
|
||||||
if issue["labels"][0] in self.blogBase["singlePage"]:
|
|
||||||
postBase["bottomText"]=''
|
|
||||||
|
|
||||||
if '<pre class="notranslate">' in post_body:
|
self.renderHtml('post.html',postBase,{},issue["htmlDir"])
|
||||||
keys=['sun','moon','sync','home','github','copy','check']
|
|
||||||
if '<div class="highlight' in post_body:
|
|
||||||
postBase["highlight"]=1
|
|
||||||
else:
|
|
||||||
postBase["highlight"]=2
|
|
||||||
else:
|
|
||||||
keys=['sun','moon','sync','home','github']
|
|
||||||
postBase["highlight"]=0
|
|
||||||
|
|
||||||
postIcon=dict(zip(keys, map(IconBase.get, keys)))
|
|
||||||
self.renderHtml('post.html',postBase,{},issue["htmlDir"],postIcon)
|
|
||||||
print("create postPage title=%s file=%s " % (issue["postTitle"],issue["htmlDir"]))
|
print("create postPage title=%s file=%s " % (issue["postTitle"],issue["htmlDir"]))
|
||||||
|
|
||||||
def createPlistHtml(self):
|
def createPlistHtml(self):
|
||||||
self.blogBase["postListJson"]=dict(sorted(self.blogBase["postListJson"].items(),key=lambda x:(x[1]["top"],x[1]["createdAt"]),reverse=True))#使列表由时间排序
|
self.blogBase["postListJson"]=dict(sorted(self.blogBase["postListJson"].items(),key=lambda x:(x[1]["top"],x[1]["createdAt"]),reverse=True))#使列表由时间排序
|
||||||
keys=list(OrderedDict.fromkeys(['sun', 'moon','sync', 'search', 'rss', 'upload', 'post'] + self.blogBase["singlePage"]))
|
|
||||||
plistIcon={**dict(zip(keys, map(IconBase.get, keys))),**self.blogBase["iconList"]}
|
|
||||||
keys=['sun','moon','sync','home','search','post']
|
|
||||||
tagIcon=dict(zip(keys, map(IconBase.get, keys)))
|
|
||||||
|
|
||||||
postNum=len(self.blogBase["postListJson"])
|
postNum=len(self.blogBase["postListJson"])
|
||||||
pageFlag=0
|
pageFlag=0
|
||||||
@ -237,7 +128,7 @@ class GMEEK():
|
|||||||
self.blogBase["prevUrl"]="/page%d.html" % pageFlag
|
self.blogBase["prevUrl"]="/page%d.html" % pageFlag
|
||||||
self.blogBase["nextUrl"]="disabled"
|
self.blogBase["nextUrl"]="disabled"
|
||||||
|
|
||||||
self.renderHtml('plist.html',self.blogBase,onePageList,htmlDir,plistIcon)
|
self.renderHtml('plist.html',self.blogBase,onePageList,htmlDir)
|
||||||
print("create "+htmlDir)
|
print("create "+htmlDir)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
@ -255,14 +146,11 @@ class GMEEK():
|
|||||||
self.blogBase["prevUrl"]="/page%d.html" % pageFlag
|
self.blogBase["prevUrl"]="/page%d.html" % pageFlag
|
||||||
self.blogBase["nextUrl"]="/page%d.html" % (pageFlag+2)
|
self.blogBase["nextUrl"]="/page%d.html" % (pageFlag+2)
|
||||||
|
|
||||||
self.renderHtml('plist.html',self.blogBase,onePageList,htmlDir,plistIcon)
|
self.renderHtml('plist.html',self.blogBase,onePageList,htmlDir)
|
||||||
print("create "+htmlDir)
|
print("create "+htmlDir)
|
||||||
|
|
||||||
pageFlag=pageFlag+1
|
pageFlag=pageFlag+1
|
||||||
|
|
||||||
self.renderHtml('tag.html',self.blogBase,onePageList,self.root_dir+"tag.html",tagIcon)
|
|
||||||
print("create tag.html")
|
|
||||||
|
|
||||||
def createFeedXml(self):
|
def createFeedXml(self):
|
||||||
self.blogBase["postListJson"]=dict(sorted(self.blogBase["postListJson"].items(),key=lambda x:x[1]["createdAt"],reverse=False))#使列表由时间排序
|
self.blogBase["postListJson"]=dict(sorted(self.blogBase["postListJson"].items(),key=lambda x:x[1]["createdAt"],reverse=False))#使列表由时间排序
|
||||||
feed = FeedGenerator()
|
feed = FeedGenerator()
|
||||||
@ -270,6 +158,7 @@ class GMEEK():
|
|||||||
feed.description(self.blogBase["subTitle"])
|
feed.description(self.blogBase["subTitle"])
|
||||||
feed.link(href=self.blogBase["homeUrl"])
|
feed.link(href=self.blogBase["homeUrl"])
|
||||||
feed.image(url=self.blogBase["avatarUrl"],title="avatar", link=self.blogBase["homeUrl"])
|
feed.image(url=self.blogBase["avatarUrl"],title="avatar", link=self.blogBase["homeUrl"])
|
||||||
|
feed.pubDate(time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()))
|
||||||
feed.copyright(self.blogBase["title"])
|
feed.copyright(self.blogBase["title"])
|
||||||
feed.managingEditor(self.blogBase["title"])
|
feed.managingEditor(self.blogBase["title"])
|
||||||
feed.webMaster(self.blogBase["title"])
|
feed.webMaster(self.blogBase["title"])
|
||||||
@ -291,67 +180,39 @@ class GMEEK():
|
|||||||
item.link(href=self.blogBase["homeUrl"]+"/"+self.blogBase["postListJson"][num]["postUrl"])
|
item.link(href=self.blogBase["homeUrl"]+"/"+self.blogBase["postListJson"][num]["postUrl"])
|
||||||
item.pubDate(time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(self.blogBase["postListJson"][num]["createdAt"])))
|
item.pubDate(time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(self.blogBase["postListJson"][num]["createdAt"])))
|
||||||
|
|
||||||
if self.oldFeedString!='':
|
|
||||||
feed.rss_file(self.root_dir+'new.xml')
|
|
||||||
newFeed=open(self.root_dir+'new.xml','r',encoding='utf-8')
|
|
||||||
new=newFeed.read()
|
|
||||||
newFeed.close()
|
|
||||||
|
|
||||||
new=re.sub(r'<lastBuildDate>.*?</lastBuildDate>','',new)
|
|
||||||
old=re.sub(r'<lastBuildDate>.*?</lastBuildDate>','',self.oldFeedString)
|
|
||||||
os.remove(self.root_dir+'new.xml')
|
|
||||||
|
|
||||||
if new==old:
|
|
||||||
print("====== rss xml no update ======")
|
|
||||||
feedFile=open(self.root_dir+'rss.xml',"w")
|
|
||||||
feedFile.write(self.oldFeedString)
|
|
||||||
feedFile.close()
|
|
||||||
return
|
|
||||||
|
|
||||||
print("====== create rss xml ======")
|
|
||||||
feed.rss_file(self.root_dir+'rss.xml')
|
feed.rss_file(self.root_dir+'rss.xml')
|
||||||
|
|
||||||
def addOnePostJson(self,issue):
|
def addOnePostJson(self,issue):
|
||||||
if len(issue.labels)>=1:
|
if len(issue.labels)==1:
|
||||||
if issue.labels[0].name in self.blogBase["singlePage"]:
|
if issue.labels[0].name in self.blogBase["singlePage"]:
|
||||||
listJsonName='singeListJson'
|
listJsonName='singeListJson'
|
||||||
htmlFile='{}.html'.format(self.createFileName(issue,useLabel=True))
|
gen_Html = 'docs/{}.html'.format(issue.labels[0].name)
|
||||||
gen_Html = self.root_dir+htmlFile
|
|
||||||
else:
|
else:
|
||||||
listJsonName='postListJson'
|
listJsonName='postListJson'
|
||||||
htmlFile='{}.html'.format(self.createFileName(issue))
|
gen_Html = self.post_dir+'{}.html'.format(Pinyin().get_pinyin(issue.title))
|
||||||
gen_Html = self.post_dir+htmlFile
|
|
||||||
|
|
||||||
postNum="P"+str(issue.number)
|
postNum="P"+str(issue.number)
|
||||||
self.blogBase[listJsonName][postNum]=json.loads('{}')
|
self.blogBase[listJsonName][postNum]=json.loads('{}')
|
||||||
self.blogBase[listJsonName][postNum]["htmlDir"]=gen_Html
|
self.blogBase[listJsonName][postNum]["htmlDir"]=gen_Html
|
||||||
self.blogBase[listJsonName][postNum]["labels"]=[label.name for label in issue.labels]
|
self.blogBase[listJsonName][postNum]["label"]=issue.labels[0].name
|
||||||
|
self.blogBase[listJsonName][postNum]["labelColor"]=self.labelColorDict[issue.labels[0].name]
|
||||||
self.blogBase[listJsonName][postNum]["postTitle"]=issue.title
|
self.blogBase[listJsonName][postNum]["postTitle"]=issue.title
|
||||||
self.blogBase[listJsonName][postNum]["postUrl"]=urllib.parse.quote(gen_Html[len(self.root_dir):])
|
self.blogBase[listJsonName][postNum]["postUrl"]=urllib.parse.quote(self.post_folder+'{}.html'.format(Pinyin().get_pinyin(issue.title)))
|
||||||
|
|
||||||
self.blogBase[listJsonName][postNum]["postSourceUrl"]="https://github.com/"+options.repo_name+"/issues/"+str(issue.number)
|
self.blogBase[listJsonName][postNum]["postSourceUrl"]="https://github.com/"+options.repo_name+"/issues/"+str(issue.number)
|
||||||
self.blogBase[listJsonName][postNum]["commentNum"]=issue.get_comments().totalCount
|
self.blogBase[listJsonName][postNum]["commentNum"]=issue.get_comments().totalCount
|
||||||
|
if self.blogBase["i18n"]=="CN":
|
||||||
if issue.body==None:
|
period="。"
|
||||||
self.blogBase[listJsonName][postNum]["description"]=''
|
|
||||||
self.blogBase[listJsonName][postNum]["wordCount"]=0
|
|
||||||
else:
|
else:
|
||||||
self.blogBase[listJsonName][postNum]["wordCount"]=len(issue.body)
|
period="."
|
||||||
if self.blogBase["rssSplit"]=="sentence":
|
self.blogBase[listJsonName][postNum]["description"]=issue.body.split(period)[0]+period
|
||||||
if self.blogBase["i18n"]=="CN":
|
|
||||||
period="。"
|
|
||||||
else:
|
|
||||||
period="."
|
|
||||||
else:
|
|
||||||
period=self.blogBase["rssSplit"]
|
|
||||||
self.blogBase[listJsonName][postNum]["description"]=issue.body.split(period)[0].replace("\"", "\'")+period
|
|
||||||
|
|
||||||
self.blogBase[listJsonName][postNum]["top"]=0
|
self.blogBase[listJsonName][postNum]["top"]=0
|
||||||
for event in issue.get_events():
|
for event in issue.get_events():
|
||||||
if event.event=="pinned":
|
if event.event=="pinned":
|
||||||
self.blogBase[listJsonName][postNum]["top"]=1
|
self.blogBase[listJsonName][postNum]["top"]=1
|
||||||
|
break
|
||||||
elif event.event=="unpinned":
|
elif event.event=="unpinned":
|
||||||
self.blogBase[listJsonName][postNum]["top"]=0
|
break
|
||||||
|
|
||||||
try:
|
try:
|
||||||
postConfig=json.loads(issue.body.split("\r\n")[-1:][0].split("##")[1])
|
postConfig=json.loads(issue.body.split("\r\n")[-1:][0].split("##")[1])
|
||||||
@ -364,42 +225,23 @@ class GMEEK():
|
|||||||
self.blogBase[listJsonName][postNum]["createdAt"]=postConfig["timestamp"]
|
self.blogBase[listJsonName][postNum]["createdAt"]=postConfig["timestamp"]
|
||||||
else:
|
else:
|
||||||
self.blogBase[listJsonName][postNum]["createdAt"]=int(time.mktime(issue.created_at.timetuple()))
|
self.blogBase[listJsonName][postNum]["createdAt"]=int(time.mktime(issue.created_at.timetuple()))
|
||||||
|
|
||||||
if "style" in postConfig:
|
if "style" in postConfig:
|
||||||
self.blogBase[listJsonName][postNum]["style"]=self.blogBase["style"]+str(postConfig["style"])
|
self.blogBase[listJsonName][postNum]["style"]=str(postConfig["style"])
|
||||||
else:
|
else:
|
||||||
self.blogBase[listJsonName][postNum]["style"]=self.blogBase["style"]
|
self.blogBase[listJsonName][postNum]["style"]=""
|
||||||
|
|
||||||
if "script" in postConfig:
|
if "script" in postConfig:
|
||||||
self.blogBase[listJsonName][postNum]["script"]=self.blogBase["script"]+str(postConfig["script"])
|
self.blogBase[listJsonName][postNum]["script"]=str(postConfig["script"])
|
||||||
else:
|
else:
|
||||||
self.blogBase[listJsonName][postNum]["script"]=self.blogBase["script"]
|
self.blogBase[listJsonName][postNum]["script"]=""
|
||||||
|
|
||||||
if "head" in postConfig:
|
|
||||||
self.blogBase[listJsonName][postNum]["head"]=self.blogBase["head"]+str(postConfig["head"])
|
|
||||||
else:
|
|
||||||
self.blogBase[listJsonName][postNum]["head"]=self.blogBase["head"]
|
|
||||||
|
|
||||||
if "ogImage" in postConfig:
|
|
||||||
self.blogBase[listJsonName][postNum]["ogImage"]=postConfig["ogImage"]
|
|
||||||
else:
|
|
||||||
self.blogBase[listJsonName][postNum]["ogImage"]=self.blogBase["ogImage"]
|
|
||||||
|
|
||||||
thisTime=datetime.datetime.fromtimestamp(self.blogBase[listJsonName][postNum]["createdAt"])
|
thisTime=datetime.datetime.fromtimestamp(self.blogBase[listJsonName][postNum]["createdAt"])
|
||||||
thisTime=thisTime.astimezone(self.TZ)
|
|
||||||
thisYear=thisTime.year
|
thisYear=thisTime.year
|
||||||
self.blogBase[listJsonName][postNum]["createdDate"]=thisTime.strftime("%Y-%m-%d")
|
self.blogBase[listJsonName][postNum]["createdDate"]=thisTime.strftime("%Y-%m-%d")
|
||||||
self.blogBase[listJsonName][postNum]["dateLabelColor"]=self.blogBase["yearColorList"][int(thisYear)%len(self.blogBase["yearColorList"])]
|
self.blogBase[listJsonName][postNum]["dateLabelColor"]=self.blogBase["yearColorList"][int(thisYear)%len(self.blogBase["yearColorList"])]
|
||||||
|
|
||||||
mdFileName=re.sub(r'[<>:/\\|?*\"]|[\0-\31]', '-', issue.title)
|
f = open("backup/"+issue.title+".md", 'w', encoding='UTF-8')
|
||||||
f = open(self.backup_dir+mdFileName+".md", 'w', encoding='UTF-8')
|
f.write(issue.body)
|
||||||
|
|
||||||
if issue.body==None:
|
|
||||||
f.write('')
|
|
||||||
else:
|
|
||||||
f.write(issue.body)
|
|
||||||
f.close()
|
f.close()
|
||||||
return listJsonName
|
|
||||||
|
|
||||||
def runAll(self):
|
def runAll(self):
|
||||||
print("====== start create static html ======")
|
print("====== start create static html ======")
|
||||||
@ -422,28 +264,11 @@ class GMEEK():
|
|||||||
def runOne(self,number_str):
|
def runOne(self,number_str):
|
||||||
print("====== start create static html ======")
|
print("====== start create static html ======")
|
||||||
issue=self.repo.get_issue(int(number_str))
|
issue=self.repo.get_issue(int(number_str))
|
||||||
if issue.state == "open":
|
self.addOnePostJson(issue)
|
||||||
listJsonName=self.addOnePostJson(issue)
|
self.createPostHtml(self.blogBase["postListJson"]["P"+number_str])
|
||||||
self.createPostHtml(self.blogBase[listJsonName]["P"+number_str])
|
self.createPlistHtml()
|
||||||
self.createPlistHtml()
|
self.createFeedXml()
|
||||||
self.createFeedXml()
|
print("====== create static html end ======")
|
||||||
print("====== create static html end ======")
|
|
||||||
else:
|
|
||||||
print("====== issue is closed ======")
|
|
||||||
|
|
||||||
def createFileName(self,issue,useLabel=False):
|
|
||||||
if useLabel==True:
|
|
||||||
fileName=issue.labels[0].name
|
|
||||||
else:
|
|
||||||
if self.blogBase["urlMode"]=="issue":
|
|
||||||
fileName=str(issue.number)
|
|
||||||
elif self.blogBase["urlMode"]=="ru_translit":
|
|
||||||
fileName=str(translit(issue.title, language_code='ru', reversed=True)).replace(' ', '-')
|
|
||||||
else:
|
|
||||||
fileName=Pinyin().get_pinyin(issue.title)
|
|
||||||
|
|
||||||
fileName=re.sub(r'[<>:/\\|?*\"]|[\0-\31]', '-', fileName)
|
|
||||||
return fileName
|
|
||||||
|
|
||||||
######################################################################################
|
######################################################################################
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
@ -458,68 +283,17 @@ if not os.path.exists("blogBase.json"):
|
|||||||
print("blogBase is not exists, runAll")
|
print("blogBase is not exists, runAll")
|
||||||
blog.runAll()
|
blog.runAll()
|
||||||
else:
|
else:
|
||||||
if os.path.exists(blog.root_dir+'rss.xml'):
|
|
||||||
oldFeedFile=open(blog.root_dir+'rss.xml','r',encoding='utf-8')
|
|
||||||
blog.oldFeedString=oldFeedFile.read()
|
|
||||||
oldFeedFile.close()
|
|
||||||
if options.issue_number=="0" or options.issue_number=="":
|
if options.issue_number=="0" or options.issue_number=="":
|
||||||
print("issue_number=='0', runAll")
|
print("issue_number=='0', runAll")
|
||||||
blog.runAll()
|
blog.runAll()
|
||||||
else:
|
else:
|
||||||
f=open("blogBase.json","r")
|
f=open("blogBase.json","r")
|
||||||
print("blogBase is exists and issue_number!=0, runOne")
|
print("blogBase is exists and issue_number!=0, runOne")
|
||||||
oldBlogBase=json.loads(f.read())
|
blog.blogBase=json.loads(f.read())
|
||||||
for key, value in oldBlogBase.items():
|
|
||||||
blog.blogBase[key] = value
|
|
||||||
f.close()
|
f.close()
|
||||||
blog.blogBase["labelColorDict"]=blog.labelColorDict
|
|
||||||
blog.runOne(options.issue_number)
|
blog.runOne(options.issue_number)
|
||||||
|
|
||||||
listFile=open("blogBase.json","w")
|
listFile=open("blogBase.json","w")
|
||||||
listFile.write(json.dumps(blog.blogBase))
|
listFile.write(json.dumps(blog.blogBase))
|
||||||
listFile.close()
|
listFile.close()
|
||||||
|
|
||||||
commentNumSum=0
|
|
||||||
wordCount=0
|
|
||||||
print("====== create postList.json file ======")
|
|
||||||
blog.blogBase["postListJson"]=dict(sorted(blog.blogBase["postListJson"].items(),key=lambda x:x[1]["createdAt"],reverse=True))#使列表由时间排序
|
|
||||||
for i in blog.blogBase["postListJson"]:
|
|
||||||
del blog.blogBase["postListJson"][i]["description"]
|
|
||||||
del blog.blogBase["postListJson"][i]["postSourceUrl"]
|
|
||||||
del blog.blogBase["postListJson"][i]["htmlDir"]
|
|
||||||
del blog.blogBase["postListJson"][i]["createdAt"]
|
|
||||||
del blog.blogBase["postListJson"][i]["script"]
|
|
||||||
del blog.blogBase["postListJson"][i]["style"]
|
|
||||||
del blog.blogBase["postListJson"][i]["top"]
|
|
||||||
del blog.blogBase["postListJson"][i]["ogImage"]
|
|
||||||
|
|
||||||
if 'head' in blog.blogBase["postListJson"][i]:
|
|
||||||
del blog.blogBase["postListJson"][i]["head"]
|
|
||||||
|
|
||||||
if 'commentNum' in blog.blogBase["postListJson"][i]:
|
|
||||||
commentNumSum=commentNumSum+blog.blogBase["postListJson"][i]["commentNum"]
|
|
||||||
del blog.blogBase["postListJson"][i]["commentNum"]
|
|
||||||
|
|
||||||
if 'wordCount' in blog.blogBase["postListJson"][i]:
|
|
||||||
wordCount=wordCount+blog.blogBase["postListJson"][i]["wordCount"]
|
|
||||||
del blog.blogBase["postListJson"][i]["wordCount"]
|
|
||||||
|
|
||||||
blog.blogBase["postListJson"]["labelColorDict"]=blog.labelColorDict
|
|
||||||
|
|
||||||
docListFile=open(blog.root_dir+"postList.json","w")
|
|
||||||
docListFile.write(json.dumps(blog.blogBase["postListJson"]))
|
|
||||||
docListFile.close()
|
|
||||||
|
|
||||||
if os.environ.get('GITHUB_EVENT_NAME')!='schedule':
|
|
||||||
print("====== update readme file ======")
|
|
||||||
workspace_path = os.environ.get('GITHUB_WORKSPACE')
|
|
||||||
readme="# %s :link: %s \r\n" % (blog.blogBase["title"],blog.blogBase["homeUrl"])
|
|
||||||
readme=readme+"### :page_facing_up: [%d](%s/tag.html) \r\n" % (len(blog.blogBase["postListJson"])-1,blog.blogBase["homeUrl"])
|
|
||||||
readme=readme+"### :speech_balloon: %d \r\n" % commentNumSum
|
|
||||||
readme=readme+"### :hibiscus: %d \r\n" % wordCount
|
|
||||||
readme=readme+"### :alarm_clock: %s \r\n" % datetime.datetime.now(blog.TZ).strftime('%Y-%m-%d %H:%M:%S')
|
|
||||||
readme=readme+"### Powered by :heart: [Gmeek](https://github.com/Meekdai/Gmeek)\r\n"
|
|
||||||
readmeFile=open(workspace_path+"/README.md","w")
|
|
||||||
readmeFile.write(readme)
|
|
||||||
readmeFile.close()
|
|
||||||
######################################################################################
|
######################################################################################
|
||||||
|
|||||||
21
LICENSE
21
LICENSE
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2024 Meekdai
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
16
README-en.md
16
README-en.md
@ -1,20 +1,18 @@
|
|||||||
**[简体中文](README.md)** | **English** | **[Русский](README-ru.md)**
|
**[简体中文](README.md)** | **English**
|
||||||
# Gmeek
|
# Gmeek
|
||||||
|
|
||||||
Gmeek is a Blog Generator based on `Github Pages` and `Github Issues` and `Github Actions`. No local deployment is required, and it only takes a few minutes to deploy.
|
Gmeek is a Blog Generator based on `Github Pages` and `Github Issues` and `Github Actions`. No local deployment is required, and it only takes a few minutes from building to writing.
|
||||||
|
|
||||||
- [Demo](http://meekdai.github.io/)
|
- [Demo](http://meekdai.github.io/)
|
||||||
- [Update Log](https://meekdai.github.io/post/Gmeek-geng-xin-ri-zhi.html)
|
- [Update Log](https://meekdai.github.io/post/Gmeek-geng-xin-ri-zhi.html)
|
||||||
- [Gmeek Get Started](https://blog.meekdai.com/post/Gmeek-kuai-su-shang-shou.html)
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
1. Click [Create a repository from template](https://github.com/new?template_name=Gmeek-template&template_owner=Meekdai), the recommended repository name is `XXX.github.io`,where `XXX` is your github username.
|
1. Create your own `XXX.github.io` repository. In the repository `Settings`, select `Github Actions` under `Pages->Build and deployment->Source`.
|
||||||
|
2. Create files `config.json` and `.github/workflows/Gmeek.yml` in the repository, copy the code in [link](CONIFG.md) and save them separately.
|
||||||
2. In the repository `Settings`, select `Github Actions` in `Pages->Build and deployment->Source`.
|
3. Delete redundant tags in Issues and create your own tags, such as `link`, `about`, `daily`, etc.
|
||||||
|
4. Open an issue and start writing. After saving the issue, the blog content will be automatically created. After a while, it can be accessed through https://XXX.github.io
|
||||||
3. Open an issue, start writing, and add a label. After saving the issue, blog content will be automatically created. After a while, it can be accessed through https://XXX.github.io
|
|
||||||
|
|
||||||
The above installation is just a guide, and some configuration details will be written later. If you have any questions, please submit [Issues](https://github.com/Meekdai/Gmeek/issues) in this repository
|
The above installation is just a guide, and some configuration details will be written later. If you have any questions, please submit [Issues](https://github.com/Meekdai/Gmeek/issues) in this repository
|
||||||
|
|
||||||
@ -25,7 +23,7 @@ The above installation is just a guide, and some configuration details will be w
|
|||||||
- The comment system used [utteranc.es](https://utteranc.es/)
|
- The comment system used [utteranc.es](https://utteranc.es/)
|
||||||
|
|
||||||
### Thanks
|
### Thanks
|
||||||
- [jinja2](https://jinja.palletsprojects.com/)
|
|
||||||
- [utteranc.es](https://utteranc.es/)
|
- [utteranc.es](https://utteranc.es/)
|
||||||
- [primer.style](https://primer.style/css)
|
- [primer.style](https://primer.style/css)
|
||||||
- [gitblog](https://github.com/yihong0618/gitblog)
|
- [gitblog](https://github.com/yihong0618/gitblog)
|
||||||
|
|||||||
31
README-ru.md
31
README-ru.md
@ -1,31 +0,0 @@
|
|||||||
**[简体中文](README.md)** | **[English](README-en.md)** | **Русский**
|
|
||||||
# Gmeek
|
|
||||||
|
|
||||||
Gmeek это блог генератор, использующий `Github Pages` и `Github Issues` и `Github Actions`. Никакого локального развертывания не требуется, и развертывание занимает всего несколько минут.
|
|
||||||
|
|
||||||
- [Пример](http://meekdai.github.io/)
|
|
||||||
- [Журнал обновлений](https://meekdai.github.io/post/Gmeek-geng-xin-ri-zhi.html)
|
|
||||||
- [Начать работу с Gmeek](https://blog.meekdai.com/post/Gmeek-kuai-su-shang-shou.html)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Установка
|
|
||||||
1. Нажмите [Create a repository from template](https://github.com/new?template_name=Gmeek-template&template_owner=Meekdai), рекомендуемое имя репозитория - `XXX.github.io`, где `XXX` это имя вашего профиля github.
|
|
||||||
|
|
||||||
2. В репозитории выберите `Settings`, выберите `Github Actions` в следующем месте `Pages->Build and deployment->Source`.
|
|
||||||
|
|
||||||
3. Откройте issue и начните писать, далее добавьте label. После сохранения issue, содержание блога будет создано автоматически. Через некоторое время к нему можно будет получить доступ через https://XXX.github.io
|
|
||||||
|
|
||||||
Приведенная выше установка является лишь кратким руководством, некоторые детали конфигурации будут написаны позже. Если у вас есть вопросы, пожалуйста, отправьте [Issues](https://github.com/Meekdai/Gmeek/issues) в этот репозиторий.
|
|
||||||
|
|
||||||
### Особенности
|
|
||||||
|
|
||||||
- Интерфейс UI имеет то же происхождение, что и Github, только внедрен собственный CSS Github:[primer.style](https://primer.style/css)
|
|
||||||
- После завершения написания блога в Issues автоматически запускаются Actions для выполнения задач развертывания.
|
|
||||||
- Система комментариев, используется [utteranc.es](https://utteranc.es/)
|
|
||||||
|
|
||||||
### Благодарность
|
|
||||||
- [jinja2](https://jinja.palletsprojects.com/)
|
|
||||||
- [utteranc.es](https://utteranc.es/)
|
|
||||||
- [primer.style](https://primer.style/css)
|
|
||||||
- [gitblog](https://github.com/yihong0618/gitblog)
|
|
||||||
56
README.md
56
README.md
@ -1,31 +1,21 @@
|
|||||||
**简体中文** | **[English](README-en.md)** | **[Русский](README-ru.md)**
|
**简体中文** | **[English](README-en.md)**
|
||||||
# Gmeek
|
# Gmeek
|
||||||
|
|
||||||
一个博客框架,超轻量级个人博客模板。完全基于`Github Pages` 、 `Github Issues` 和 `Github Actions`。不需要本地部署,从搭建到写作,只需要18秒,2步搭建好博客,第3步就是写作。
|
一个博客框架,超轻量级个人博客模板。完全基于`Github Pages` 、 `Github Issues` 和 `Github Actions`。不需要本地部署,从搭建到写作,只需要几分钟的时间,3步搭建好博客,第4步就是写作。
|
||||||
|
|
||||||
- [Demo页面](http://meekdai.github.io/)
|
- [Demo页面](http://meekdai.github.io/)
|
||||||
- [Gmeek更新日志](https://meekdai.github.io/post/Gmeek-geng-xin-ri-zhi.html)
|
- [更新日志](https://meekdai.github.io/post/Gmeek-geng-xin-ri-zhi.html)
|
||||||
- [Gmeek快速上手](https://blog.meekdai.com/post/Gmeek-kuai-su-shang-shou.html)
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### 安装
|
### 安装
|
||||||
|
|
||||||
1. 【创建仓库】点击[通过模板创建仓库](https://github.com/new?template_name=Gmeek-template&template_owner=Meekdai),建议仓库名称为`XXX.github.io`,其中`XXX`为你的github用户名。
|
1. 创建自己的`XXX.github.io`的仓库,在仓库的设置中`Pages->Build and deployment->Source`下面选择`Github Actions`。
|
||||||
|
2. 在仓库中创建文件`config.json`和`.github/workflows/Gmeek.yml`复制[链接](CONIFG.md)中的代码分别保存。
|
||||||
|
3. 在Issues中删除多余标签,创建自己的标签,如`link`、`about`、`日常`等。
|
||||||
|
4. 打开一篇issue,开始写作,并且添加一个标签,保存issue后会自动创建博客内容,片刻后可通过https://XXX.github.io 访问
|
||||||
|
|
||||||
2. 【启用Pages】在仓库的`Settings`中`Pages->Build and deployment->Source`下面选择`Github Actions`。
|
如果有问题可在本仓库提交[Issues](https://github.com/Meekdai/Gmeek/issues) 或者添加 QQ:`294977308`
|
||||||
|
|
||||||
3. 【开始写作】打开一篇issue,开始写作,并且**必须**添加一个`标签Label`(至少添加一个),再保存issue后会自动创建博客内容,片刻后可通过https://XXX.github.io 访问(可进入Actions页面查看构建进度)。
|
|
||||||
|
|
||||||
4. 【手动全局生成】这个步骤只有在修改`config.json`文件或者出现奇怪问题的时候,需要执行。
|
|
||||||
```
|
|
||||||
通过Actions->build Gmeek->Run workflow->里面的按钮全局重新生成一次
|
|
||||||
```
|
|
||||||
|
|
||||||
### 提交问题
|
|
||||||
|
|
||||||
1. 如果有问题可参考[Gmeek快速上手](https://blog.meekdai.com/post/Gmeek-kuai-su-shang-shou.html)
|
|
||||||
2. 在本仓库提交[Issues](https://github.com/Meekdai/Gmeek/issues)之前,请手动全局生成一次。如果还有错误,提交`Issues`后,我会帮忙查看构建流程,定位问题出处。
|
|
||||||
|
|
||||||
### 特性
|
### 特性
|
||||||
|
|
||||||
@ -34,11 +24,34 @@
|
|||||||
- 评论系统引入[utteranc.es](https://utteranc.es/)
|
- 评论系统引入[utteranc.es](https://utteranc.es/)
|
||||||
- 使用`jinja2`对html进行渲染,可通过模板自定义UI主题
|
- 使用`jinja2`对html进行渲染,可通过模板自定义UI主题
|
||||||
|
|
||||||
### 赞赏
|
### 说明
|
||||||
|
1. 请确保每一篇文章有且仅有一个`Label`,为了防止他人提交的Issue也被抓取生成文章。
|
||||||
|
|
||||||
|
2. 如果要导入以前的文章,如何设置发布时间呢?
|
||||||
|
如需上传旧博客的文章需要修改发布时间,可以在文章最后一行添加如下代码。里面的时间是采用时间戳的形式,可以用如下[网站](https://tool.lu/timestamp)转换。
|
||||||
|
```html
|
||||||
|
<!-- ##{"timestamp":1490764800}## -->
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 自定义单篇文章页面的`style`和`script`,同样是在文章最后一行添加如下代码,为JSON格式。
|
||||||
|
```html
|
||||||
|
<!-- ##{"style":"<style>#postBody{font-size:20px}</style>"}## -->
|
||||||
|
```
|
||||||
|
```html
|
||||||
|
<!-- ##{"script":"<script async src='//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js'></script>"}## -->
|
||||||
|
```
|
||||||
|
4. 可同时一起添加多种自定义参数:
|
||||||
|
```html
|
||||||
|
<!-- ##{"script":"<script async src='//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js'></script>","style":"<style>#postBody{font-size:20px}</style>","timestamp":1490764800}## -->
|
||||||
|
```
|
||||||
|
|
||||||
|
5. 如果修改过config.json里面的参数后,发现生成文章失败,或其他奇奇怪怪的问题。
|
||||||
|
建议通过Actions->build Gmeek->Run workflow->里面的按钮全局重新生成一次就行。
|
||||||
|
|
||||||
|
6. 置顶博客文章,只需要`Pin issue`即可。
|
||||||
|
|
||||||
|
|
||||||
如果本项目对你有帮助,可以用微信赞赏一下作者,让项目有继续更新维护下去的动力,谢谢!
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 鸣谢
|
### 鸣谢
|
||||||
- [jinja2](https://jinja.palletsprojects.com/)
|
- [jinja2](https://jinja.palletsprojects.com/)
|
||||||
@ -49,4 +62,3 @@
|
|||||||
### License
|
### License
|
||||||
|
|
||||||
请保留页面底部和console界面版权信息,谢谢!
|
请保留页面底部和console界面版权信息,谢谢!
|
||||||
|
|
||||||
|
|||||||
BIN
img/赞赏码.jpg
BIN
img/赞赏码.jpg
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB |
@ -1,16 +0,0 @@
|
|||||||
function createBSZ() {
|
|
||||||
var postBody = document.getElementById('postBody');
|
|
||||||
if (postBody){
|
|
||||||
postBody.insertAdjacentHTML('afterend','<div id="busuanzi_container_page_pv" style="display:none;float:left;margin-top:8px;font-size:small;">本文浏览量<span id="busuanzi_value_page_pv"></span>次</div>');
|
|
||||||
}
|
|
||||||
var runday = document.getElementById('runday');
|
|
||||||
runday.insertAdjacentHTML('afterend', '<div id="busuanzi_container_site_pv" style="display:none;">总浏览量<span id="busuanzi_value_site_pv"></span>次 • </div>');
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
createBSZ();
|
|
||||||
var element = document.createElement('script');
|
|
||||||
element.src = '//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js';
|
|
||||||
document.head.appendChild(element);
|
|
||||||
console.log("\n %c GmeekBSZ Plugins https://github.com/Meekdai/Gmeek \n","padding:5px 0;background:#bc4c00;color:#fff");
|
|
||||||
});
|
|
||||||
@ -1,100 +0,0 @@
|
|||||||
function createTOC() {
|
|
||||||
var tocElement = document.createElement('div');
|
|
||||||
tocElement.className = 'toc';
|
|
||||||
var contentContainer = document.getElementById('content');
|
|
||||||
|
|
||||||
const headings = contentContainer.querySelectorAll('h1, h2, h3, h4, h5, h6');
|
|
||||||
|
|
||||||
if (headings.length === 0) {
|
|
||||||
return; // 如果没有标题元素,则不创建TOC
|
|
||||||
}
|
|
||||||
|
|
||||||
tocElement.insertAdjacentHTML('afterbegin', '<div class="toc-title">文章目录</div>');
|
|
||||||
|
|
||||||
headings.forEach(heading => {
|
|
||||||
if (!heading.id) {
|
|
||||||
heading.id = heading.textContent.trim().replace(/\s+/g, '-').toLowerCase();
|
|
||||||
}
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = '#' + heading.id;
|
|
||||||
link.textContent = heading.textContent;
|
|
||||||
link.className = 'toc-link';
|
|
||||||
link.style.paddingLeft = `${(parseInt(heading.tagName.charAt(1)) - 1) * 10}px`;
|
|
||||||
tocElement.appendChild(link);
|
|
||||||
});
|
|
||||||
|
|
||||||
tocElement.insertAdjacentHTML('beforeend', '<a class="toc-end" onclick="window.scrollTo({top:0,behavior: \'smooth\'});">Top</a>');
|
|
||||||
contentContainer.prepend(tocElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
createTOC();
|
|
||||||
var css = `
|
|
||||||
.toc {
|
|
||||||
position:fixed;
|
|
||||||
top:130px;
|
|
||||||
left:50%;
|
|
||||||
transform: translateX(50%) translateX(320px);
|
|
||||||
width:200px;
|
|
||||||
border: 1px solid #e1e4e8;
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 10px;
|
|
||||||
overflow-y: auto;
|
|
||||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
||||||
max-height: 70vh;
|
|
||||||
}
|
|
||||||
.toc-title{
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: center;
|
|
||||||
border-bottom: 1px solid #ddd;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
.toc-end{
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
.toc a {
|
|
||||||
display: block;
|
|
||||||
color: var(--color-diff-blob-addition-num-text);
|
|
||||||
text-decoration: none;
|
|
||||||
padding: 5px 0;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.5;
|
|
||||||
border-bottom: 1px solid #e1e4e8;
|
|
||||||
}
|
|
||||||
.toc a:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
.toc a:hover {
|
|
||||||
background-color:var(--color-select-menu-tap-focus-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1249px)
|
|
||||||
{
|
|
||||||
.toc{
|
|
||||||
position:static;
|
|
||||||
top:auto;
|
|
||||||
left:auto;
|
|
||||||
transform:none;
|
|
||||||
padding:10px;
|
|
||||||
margin-bottom:20px;
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const style = document.createElement('style');
|
|
||||||
style.textContent = css;
|
|
||||||
document.head.appendChild(style);
|
|
||||||
|
|
||||||
window.onscroll = function() {
|
|
||||||
const backToTopButton = document.querySelector('.toc-end');
|
|
||||||
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
|
|
||||||
backToTopButton.style="visibility: visible;"
|
|
||||||
} else {
|
|
||||||
backToTopButton.style="visibility: hidden;"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log("\n %c GmeekTOC Plugins https://github.com/Meekdai/Gmeek \n","padding:5px 0;background:#C333D0;color:#fff");
|
|
||||||
});
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
function loadResource(type, attributes, callback) {
|
|
||||||
var element;
|
|
||||||
if (type === 'script') {
|
|
||||||
element = document.createElement('script');
|
|
||||||
element.src = attributes.src;
|
|
||||||
element.onload = callback;
|
|
||||||
} else if (type === 'link') {
|
|
||||||
element = document.createElement('link');
|
|
||||||
element.rel = attributes.rel;
|
|
||||||
element.href = attributes.href;
|
|
||||||
} else if (type === 'style') {
|
|
||||||
element = document.createElement('style');
|
|
||||||
element.rel = 'stylesheet';
|
|
||||||
element.appendChild(document.createTextNode(attributes.css));
|
|
||||||
}
|
|
||||||
document.head.appendChild(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createTOC() {
|
|
||||||
var tocElement = document.createElement('div');
|
|
||||||
tocElement.className = 'toc';
|
|
||||||
var contentContainer = document.getElementById('content');
|
|
||||||
if (contentContainer.firstChild) {
|
|
||||||
contentContainer.insertBefore(tocElement, contentContainer.firstChild);
|
|
||||||
} else {
|
|
||||||
contentContainer.appendChild(tocElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
createTOC();
|
|
||||||
var css = '.toc {position:fixed;top:130px;left:50%;transform: translateX(50%) translateX(300px);width:200px;padding-left:30px;}@media (max-width: 1249px) {.toc{position:static;top:auto;left:auto;transform:none;padding:10px;margin-bottom:20px;background-color:var(--color-open-muted);}}';
|
|
||||||
loadResource('style', {css: css});
|
|
||||||
|
|
||||||
loadResource('script', { src: 'https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.27.4/tocbot.min.js' }, function() {
|
|
||||||
tocbot.init({
|
|
||||||
tocSelector: '.toc',
|
|
||||||
contentSelector: '.markdown-body',
|
|
||||||
headingSelector: 'h1, h2, h3, h4, h5, h6',
|
|
||||||
scrollSmooth: true,
|
|
||||||
scrollSmoothOffset: -10,
|
|
||||||
headingsOffset: 10,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
loadResource('link', { rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.27.4/tocbot.css' });
|
|
||||||
|
|
||||||
const headings = document.querySelectorAll('.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6');
|
|
||||||
headings.forEach((heading) => {
|
|
||||||
if (!heading.id) {
|
|
||||||
heading.id = heading.textContent.trim().replace(/\s+/g, '-');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var footerPlaceholder = document.createElement('div');
|
|
||||||
footerPlaceholder.style.height = window.innerHeight + 'px';
|
|
||||||
document.body.appendChild(footerPlaceholder);
|
|
||||||
console.log("\n %c GmeekTocBot Plugins https://github.com/Meekdai/Gmeek \n","padding:5px 0;background:#C333D0;color:#fff");
|
|
||||||
});
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
function createVercount() {
|
|
||||||
var postBody = document.getElementById('postBody');
|
|
||||||
if (postBody){
|
|
||||||
postBody.insertAdjacentHTML('afterend','<div id="busuanzi_container_page_pv" style="display:none;float:left;margin-top:8px;font-size:small;">本文浏览量<span id="busuanzi_value_page_pv"></span>次</div>');
|
|
||||||
}
|
|
||||||
var runday = document.getElementById('runday');
|
|
||||||
runday.insertAdjacentHTML('afterend', '<span id="busuanzi_container_site_pv" style="display:none">总浏览量<span id="busuanzi_value_site_pv"></span>次 • </span>');
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
createVercount();
|
|
||||||
var element = document.createElement('script');
|
|
||||||
element.src = 'https://vercount.one/js';
|
|
||||||
document.head.appendChild(element);
|
|
||||||
console.log("\n %c GmeekVercount Plugins https://github.com/Meekdai/Gmeek \n","padding:5px 0;background:#bc4c00;color:#fff");
|
|
||||||
});
|
|
||||||
@ -1,158 +0,0 @@
|
|||||||
function loadResource(type, attributes) {
|
|
||||||
if (type === 'style') {
|
|
||||||
const style = document.createElement('style');
|
|
||||||
style.textContent = attributes.css;
|
|
||||||
document.head.appendChild(style);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createTOC() {
|
|
||||||
const tocElement = document.createElement('div');
|
|
||||||
tocElement.className = 'toc';
|
|
||||||
const contentContainer = document.querySelector('.markdown-body');
|
|
||||||
contentContainer.appendChild(tocElement);
|
|
||||||
|
|
||||||
const headings = contentContainer.querySelectorAll('h1, h2, h3, h4, h5, h6');
|
|
||||||
headings.forEach(heading => {
|
|
||||||
if (!heading.id) {
|
|
||||||
heading.id = heading.textContent.trim().replace(/\s+/g, '-').toLowerCase();
|
|
||||||
}
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = '#' + heading.id;
|
|
||||||
link.textContent = heading.textContent;
|
|
||||||
link.className = 'toc-link';
|
|
||||||
link.style.paddingLeft = `${(parseInt(heading.tagName.charAt(1)) - 1) * 10}px`;
|
|
||||||
tocElement.appendChild(link);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleTOC() {
|
|
||||||
const tocElement = document.querySelector('.toc');
|
|
||||||
const tocIcon = document.querySelector('.toc-icon');
|
|
||||||
if (tocElement) {
|
|
||||||
tocElement.classList.toggle('show');
|
|
||||||
tocIcon.classList.toggle('active');
|
|
||||||
tocIcon.textContent = tocElement.classList.contains('show') ? '✖' : '☰';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
createTOC();
|
|
||||||
const css = `
|
|
||||||
:root {
|
|
||||||
--toc-bg: #fff;
|
|
||||||
--toc-border: #e1e4e8;
|
|
||||||
--toc-text: #24292e;
|
|
||||||
--toc-hover: #f6f8fa;
|
|
||||||
--toc-icon-bg: #fff;
|
|
||||||
--toc-icon-color: #ad6598;
|
|
||||||
--toc-icon-active-bg: #813c85;
|
|
||||||
--toc-icon-active-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
--toc-bg: #2d333b;
|
|
||||||
--toc-border: #444c56;
|
|
||||||
--toc-text: #adbac7;
|
|
||||||
--toc-hover: #373e47;
|
|
||||||
--toc-icon-bg: #22272e;
|
|
||||||
--toc-icon-color: #ad6598;
|
|
||||||
--toc-icon-active-bg: #813c85;
|
|
||||||
--toc-icon-active-color: #adbac7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.toc {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 60px;
|
|
||||||
right: 20px;
|
|
||||||
width: 250px;
|
|
||||||
max-height: 70vh;
|
|
||||||
background-color: var(--toc-bg);
|
|
||||||
border: 1px solid var(--toc-border);
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 10px;
|
|
||||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
||||||
overflow-y: auto;
|
|
||||||
z-index: 1000;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transform: translateY(20px) scale(0.9);
|
|
||||||
transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s;
|
|
||||||
}
|
|
||||||
.toc.show {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
transform: translateY(0) scale(1);
|
|
||||||
}
|
|
||||||
.toc a {
|
|
||||||
display: block;
|
|
||||||
color: var(--toc-text);
|
|
||||||
text-decoration: none;
|
|
||||||
padding: 5px 0;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.5;
|
|
||||||
border-bottom: 1px solid var(--toc-border);
|
|
||||||
transition: background-color 0.2s ease, padding-left 0.2s ease;
|
|
||||||
}
|
|
||||||
.toc a:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
.toc a:hover {
|
|
||||||
background-color: var(--toc-hover);
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
.toc-icon {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
right: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 24px;
|
|
||||||
background-color: var(--toc-icon-bg);
|
|
||||||
color: var(--toc-icon-color);
|
|
||||||
border: 2px solid var(--toc-icon-color);
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
box-shadow: 0 1px 3px rgba(0,0,0,0.12);
|
|
||||||
z-index: 1001;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
user-select: none;
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
.toc-icon:hover {
|
|
||||||
transform: scale(1.1);
|
|
||||||
}
|
|
||||||
.toc-icon:active {
|
|
||||||
transform: scale(0.9);
|
|
||||||
}
|
|
||||||
.toc-icon.active {
|
|
||||||
background-color: var(--toc-icon-active-bg);
|
|
||||||
color: var(--toc-icon-active-color);
|
|
||||||
border-color: var(--toc-icon-active-bg);
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
loadResource('style', {css: css});
|
|
||||||
|
|
||||||
const tocIcon = document.createElement('div');
|
|
||||||
tocIcon.className = 'toc-icon';
|
|
||||||
tocIcon.textContent = '☰';
|
|
||||||
tocIcon.onclick = (e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
toggleTOC();
|
|
||||||
};
|
|
||||||
document.body.appendChild(tocIcon);
|
|
||||||
|
|
||||||
document.addEventListener('click', (e) => {
|
|
||||||
const tocElement = document.querySelector('.toc');
|
|
||||||
if (tocElement && tocElement.classList.contains('show') && !tocElement.contains(e.target) && !e.target.classList.contains('toc-icon')) {
|
|
||||||
toggleTOC();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,357 +0,0 @@
|
|||||||
(function() {
|
|
||||||
class Lightbox {
|
|
||||||
constructor(options = {}) {
|
|
||||||
this.options = Object.assign({
|
|
||||||
animationDuration: 300,
|
|
||||||
closeOnOverlayClick: true,
|
|
||||||
onOpen: null,
|
|
||||||
onClose: null,
|
|
||||||
onNavigate: null
|
|
||||||
}, options);
|
|
||||||
|
|
||||||
this.images = [];
|
|
||||||
this.currentIndex = 0;
|
|
||||||
this.isOpen = false;
|
|
||||||
this.zoomLevel = 1;
|
|
||||||
this.touchStartX = 0;
|
|
||||||
this.touchEndX = 0;
|
|
||||||
this.wheelTimer = null;
|
|
||||||
this.preloadedImages = {};
|
|
||||||
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this.createStyles();
|
|
||||||
this.createLightbox();
|
|
||||||
this.bindEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
createStyles() {
|
|
||||||
const style = document.createElement('style');
|
|
||||||
style.textContent = `
|
|
||||||
.lb-lightbox-overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: transparent;
|
|
||||||
backdrop-filter: blur(5px);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity ${this.options.animationDuration}ms ease;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 10000;
|
|
||||||
}
|
|
||||||
.lb-lightbox-overlay.active {
|
|
||||||
pointer-events: auto;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
.lb-lightbox-content-wrapper {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.lb-lightbox-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
|
||||||
transition: transform ${this.options.animationDuration}ms cubic-bezier(0.25, 0.1, 0.25, 1);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.lb-lightbox-image-wrapper {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.lb-lightbox-image {
|
|
||||||
max-width: 100%;
|
|
||||||
max-height: 100%;
|
|
||||||
height: auto;
|
|
||||||
object-fit: contain;
|
|
||||||
border-radius: 16px;
|
|
||||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
|
||||||
transition: transform ${this.options.animationDuration}ms cubic-bezier(0.25, 0.1, 0.25, 1), opacity ${this.options.animationDuration}ms ease;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
.lb-lightbox-nav, .lb-lightbox-close {
|
|
||||||
position: absolute;
|
|
||||||
background-color: rgba(255, 255, 255, 0.8);
|
|
||||||
color: #333;
|
|
||||||
border: none;
|
|
||||||
border-radius: 50%;
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
font-size: 30px;
|
|
||||||
z-index: 2;
|
|
||||||
transition: transform 0.2s ease;
|
|
||||||
}
|
|
||||||
.lb-lightbox-nav:hover {
|
|
||||||
transform: scale(1.1);
|
|
||||||
}
|
|
||||||
.lb-lightbox-prev {
|
|
||||||
left: 20px;
|
|
||||||
top: calc(50% - 25px);
|
|
||||||
}
|
|
||||||
.lb-lightbox-next {
|
|
||||||
right: 20px;
|
|
||||||
top: calc(50% - 25px);
|
|
||||||
}
|
|
||||||
.lb-lightbox-close {
|
|
||||||
top: 20px;
|
|
||||||
right: 20px;
|
|
||||||
}
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.lb-lightbox-nav, .lb-lightbox-close {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
document.head.appendChild(style);
|
|
||||||
}
|
|
||||||
|
|
||||||
createLightbox() {
|
|
||||||
this.overlay = document.createElement('div');
|
|
||||||
this.overlay.className = 'lb-lightbox-overlay';
|
|
||||||
|
|
||||||
this.contentWrapper = document.createElement('div');
|
|
||||||
this.contentWrapper.className = 'lb-lightbox-content-wrapper';
|
|
||||||
|
|
||||||
this.container = document.createElement('div');
|
|
||||||
this.container.className = 'lb-lightbox-container';
|
|
||||||
|
|
||||||
this.imageWrapper = document.createElement('div');
|
|
||||||
this.imageWrapper.className = 'lb-lightbox-image-wrapper';
|
|
||||||
|
|
||||||
this.image = document.createElement('img');
|
|
||||||
this.image.className = 'lb-lightbox-image';
|
|
||||||
|
|
||||||
this.prevButton = document.createElement('button');
|
|
||||||
this.prevButton.className = 'lb-lightbox-nav lb-lightbox-prev';
|
|
||||||
this.prevButton.innerHTML = '❮';
|
|
||||||
|
|
||||||
this.nextButton = document.createElement('button');
|
|
||||||
this.nextButton.className = 'lb-lightbox-nav lb-lightbox-next';
|
|
||||||
this.nextButton.innerHTML = '❯';
|
|
||||||
|
|
||||||
this.closeButton = document.createElement('button');
|
|
||||||
this.closeButton.className = 'lb-lightbox-close';
|
|
||||||
this.closeButton.innerHTML = '×';
|
|
||||||
|
|
||||||
this.imageWrapper.appendChild(this.image);
|
|
||||||
this.container.appendChild(this.imageWrapper);
|
|
||||||
this.contentWrapper.appendChild(this.container);
|
|
||||||
this.contentWrapper.appendChild(this.prevButton);
|
|
||||||
this.contentWrapper.appendChild(this.nextButton);
|
|
||||||
this.contentWrapper.appendChild(this.closeButton);
|
|
||||||
|
|
||||||
this.overlay.appendChild(this.contentWrapper);
|
|
||||||
document.body.appendChild(this.overlay);
|
|
||||||
|
|
||||||
this.closeButton.addEventListener('click', this.close.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
bindEvents() {
|
|
||||||
document.addEventListener('click', this.handleImageClick.bind(this), true);
|
|
||||||
this.overlay.addEventListener('click', this.handleOverlayClick.bind(this));
|
|
||||||
this.prevButton.addEventListener('click', this.showPreviousImage.bind(this));
|
|
||||||
this.nextButton.addEventListener('click', this.showNextImage.bind(this));
|
|
||||||
this.closeButton.addEventListener('click', this.close.bind(this));
|
|
||||||
document.addEventListener('keydown', this.handleKeyDown.bind(this));
|
|
||||||
this.overlay.addEventListener('wheel', this.handleWheel.bind(this));
|
|
||||||
this.overlay.addEventListener('touchstart', this.handleTouchStart.bind(this));
|
|
||||||
this.overlay.addEventListener('touchmove', this.handleTouchMove.bind(this));
|
|
||||||
this.overlay.addEventListener('touchend', this.handleTouchEnd.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
handleImageClick(event) {
|
|
||||||
const clickedImage = event.target.closest('img');
|
|
||||||
if (clickedImage && !this.isOpen) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
this.images = Array.from(document.querySelectorAll('.markdown-body img, table img'));
|
|
||||||
this.currentIndex = this.images.indexOf(clickedImage);
|
|
||||||
this.open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleOverlayClick(event) {
|
|
||||||
if (event.target === this.overlay && this.options.closeOnOverlayClick) {
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleKeyDown(event) {
|
|
||||||
if (!this.isOpen) return;
|
|
||||||
switch (event.key) {
|
|
||||||
case 'ArrowLeft':
|
|
||||||
this.showPreviousImage();
|
|
||||||
break;
|
|
||||||
case 'ArrowRight':
|
|
||||||
this.showNextImage();
|
|
||||||
break;
|
|
||||||
case 'Escape':
|
|
||||||
this.close();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleWheel(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
if (event.ctrlKey) {
|
|
||||||
this.zoomLevel += event.deltaY > 0 ? -0.1 : 0.1;
|
|
||||||
this.zoomLevel = Math.max(1, this.zoomLevel);
|
|
||||||
this.image.style.transform = `scale(${this.zoomLevel})`;
|
|
||||||
} else {
|
|
||||||
clearTimeout(this.wheelTimer);
|
|
||||||
this.wheelTimer = setTimeout(() => {
|
|
||||||
const delta = Math.sign(event.deltaY);
|
|
||||||
if (delta > 0) {
|
|
||||||
this.showNextImage();
|
|
||||||
} else {
|
|
||||||
this.showPreviousImage();
|
|
||||||
}
|
|
||||||
}, 50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTouchStart(event) {
|
|
||||||
this.touchStartX = event.touches[0].clientX;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTouchMove(event) {
|
|
||||||
this.touchEndX = event.touches[0].clientX;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTouchEnd() {
|
|
||||||
const difference = this.touchStartX - this.touchEndX;
|
|
||||||
if (Math.abs(difference) > 50) {
|
|
||||||
difference > 0 ? this.showNextImage() : this.showPreviousImage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open() {
|
|
||||||
this.isOpen = true;
|
|
||||||
this.overlay.classList.add('active');
|
|
||||||
this.showImage(this.images[this.currentIndex].src);
|
|
||||||
document.body.style.overflow = 'hidden';
|
|
||||||
if (typeof this.options.onOpen === 'function') {
|
|
||||||
this.options.onOpen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close() {
|
|
||||||
document.body.style.overflow = '';
|
|
||||||
this.overlay.classList.remove('active');
|
|
||||||
this.isOpen = false;
|
|
||||||
this.clearPreloadedImages();
|
|
||||||
if (typeof this.options.onClose === 'function') {
|
|
||||||
this.options.onClose();
|
|
||||||
}
|
|
||||||
this.unbindEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
showPreviousImage() {
|
|
||||||
if (this.currentIndex > 0) {
|
|
||||||
this.currentIndex--;
|
|
||||||
this.showImage(this.images[this.currentIndex].src);
|
|
||||||
this.resetButtonScale(this.prevButton);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showNextImage() {
|
|
||||||
if (this.currentIndex < this.images.length - 1) {
|
|
||||||
this.currentIndex++;
|
|
||||||
this.showImage(this.images[this.currentIndex].src);
|
|
||||||
this.resetButtonScale(this.nextButton);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resetButtonScale(button) {
|
|
||||||
button.style.transform = 'scale(1.1)';
|
|
||||||
setTimeout(() => {
|
|
||||||
button.style.transform = 'scale(1)';
|
|
||||||
}, 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
showImage(imgSrc) {
|
|
||||||
const newImage = new Image();
|
|
||||||
newImage.src = imgSrc;
|
|
||||||
|
|
||||||
newImage.onload = () => {
|
|
||||||
this.image.style.transition = `opacity ${this.options.animationDuration}ms ease`;
|
|
||||||
this.image.style.transform = 'scale(1)';
|
|
||||||
this.image.src = imgSrc;
|
|
||||||
this.image.style.opacity = '1';
|
|
||||||
|
|
||||||
this.preloadImages();
|
|
||||||
this.prevButton.style.display = this.currentIndex === 0 ? 'none' : 'block';
|
|
||||||
this.nextButton.style.display = this.currentIndex === this.images.length - 1 ? 'none' : 'block';
|
|
||||||
};
|
|
||||||
|
|
||||||
newImage.onerror = () => {
|
|
||||||
console.error('Failed to load image:', imgSrc);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
preloadImages() {
|
|
||||||
const preloadNext = this.currentIndex + 1;
|
|
||||||
const preloadPrev = this.currentIndex - 1;
|
|
||||||
|
|
||||||
if (preloadNext < this.images.length) {
|
|
||||||
this.preloadedImages[preloadNext] = new Image();
|
|
||||||
this.preloadedImages[preloadNext].src = this.images[preloadNext].src;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preloadPrev >= 0) {
|
|
||||||
this.preloadedImages[preloadPrev] = new Image();
|
|
||||||
this.preloadedImages[preloadPrev].src = this.images[preloadPrev].src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clearPreloadedImages() {
|
|
||||||
Object.keys(this.preloadedImages).forEach(key => {
|
|
||||||
this.preloadedImages[key].src = '';
|
|
||||||
});
|
|
||||||
this.preloadedImages = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
unbindEvents() {
|
|
||||||
document.removeEventListener('click', this.handleImageClick.bind(this), true);
|
|
||||||
this.overlay.removeEventListener('click', this.handleOverlayClick.bind(this));
|
|
||||||
this.prevButton.removeEventListener('click', this.showPreviousImage.bind(this));
|
|
||||||
this.nextButton.removeEventListener('click', this.showNextImage.bind(this));
|
|
||||||
this.closeButton.removeEventListener('click', this.close.bind(this));
|
|
||||||
document.removeEventListener('keydown', this.handleKeyDown.bind(this));
|
|
||||||
this.overlay.removeEventListener('wheel', this.handleWheel.bind(this));
|
|
||||||
this.overlay.removeEventListener('touchstart', this.handleTouchStart.bind(this));
|
|
||||||
this.overlay.removeEventListener('touchmove', this.handleTouchMove.bind(this));
|
|
||||||
this.overlay.removeEventListener('touchend', this.handleTouchEnd.bind(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.Lightbox = Lightbox;
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
new Lightbox();
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
@ -3,4 +3,3 @@ requests
|
|||||||
xpinyin
|
xpinyin
|
||||||
feedgen
|
feedgen
|
||||||
Jinja2
|
Jinja2
|
||||||
transliterate
|
|
||||||
@ -1,22 +1,32 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html data-color-mode="light" data-dark-theme="{{ blogBase['nightTheme'] }}" data-light-theme="{{ blogBase['dayTheme'] }}" lang={% if blogBase['i18n']=='CN' %}"zh-CN"{% elif blogBase['i18n']=='RU' %}"ru"{% else -%}"en"{%- endif -%}>
|
<html data-color-mode="light" data-dark-theme="dark" data-light-theme="light">
|
||||||
<head>
|
<head>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="content-type" />
|
<meta content="text/html; charset=utf-8" http-equiv="content-type" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
{{ blogBase['primerCSS'] }}
|
<link href="//cdn.staticfile.org/Primer/21.0.7/primer.css" rel="stylesheet" />
|
||||||
{{ blogBase['allHead'] }}
|
|
||||||
<link rel="icon" href="{{ blogBase['faviconUrl'] }}">
|
<link rel="icon" href="{{ blogBase['faviconUrl'] }}">
|
||||||
{%- if blogBase['themeMode']=='manual' -%}
|
|
||||||
<script>
|
<script>
|
||||||
let theme = localStorage.getItem("meek_theme") || "light";
|
if(localStorage.getItem("meek_theme")==null){}
|
||||||
document.documentElement.setAttribute("data-color-mode", theme);
|
else if(localStorage.getItem("meek_theme")=="dark"){document.getElementsByTagName("html")[0].attributes.getNamedItem("data-color-mode").value="dark";}
|
||||||
|
else if(localStorage.getItem("meek_theme")=="light"){document.getElementsByTagName("html")[0].attributes.getNamedItem("data-color-mode").value="light";}
|
||||||
</script>
|
</script>
|
||||||
{%- endif -%}
|
|
||||||
{% block head %}{% endblock %}
|
{% block head %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
<style>
|
<style>
|
||||||
body{box-sizing: border-box;min-width: 200px;max-width: 900px;margin: 20px auto;padding: 45px;font-size: 16px;font-family: sans-serif;line-height: 1.25;}
|
body{
|
||||||
|
box-sizing: border-box;
|
||||||
|
min-width: 200px;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 20px auto;
|
||||||
|
padding: 45px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {transition: 0.8s;}
|
||||||
|
.avatar:hover {transform: scale(1.15) rotate(360deg);}
|
||||||
#header{display:flex;padding-bottom:8px;border-bottom: 1px solid var(--borderColor-muted, var(--color-border-muted));margin-bottom: 16px;}
|
#header{display:flex;padding-bottom:8px;border-bottom: 1px solid var(--borderColor-muted, var(--color-border-muted));margin-bottom: 16px;}
|
||||||
#footer {margin-top:64px; text-align: center;font-size: small;}
|
#footer {margin-top:64px; text-align: center;font-size: small;}
|
||||||
|
|
||||||
@ -31,34 +41,33 @@ body{box-sizing: border-box;min-width: 200px;max-width: 900px;margin: 20px auto;
|
|||||||
<script>
|
<script>
|
||||||
var IconList={{ IconList }};
|
var IconList={{ IconList }};
|
||||||
var utterancesLoad=0;
|
var utterancesLoad=0;
|
||||||
{% if blogBase['themeMode']=='manual' %}
|
if(localStorage.getItem("meek_theme")==null){localStorage.setItem("meek_theme","light");changeLight();}
|
||||||
let themeSettings={
|
else if(localStorage.getItem("meek_theme")=="dark"){changeDark();}
|
||||||
"dark": ["dark","moon","#00f0ff","dark-blue"],
|
else if(localStorage.getItem("meek_theme")=="light"){changeLight();}
|
||||||
"light": ["light","sun","#ff5000","github-light"],
|
|
||||||
"auto": ["auto","sync","","preferred-color-scheme"]
|
function changeDark(){
|
||||||
};
|
document.getElementsByTagName("html")[0].attributes.getNamedItem("data-color-mode").value="dark";
|
||||||
function changeTheme(mode, icon, color, utheme){
|
document.getElementById("themeSwitch").setAttribute("d",value=IconList["moon"]);
|
||||||
document.documentElement.setAttribute("data-color-mode",mode);
|
document.getElementById("themeSwitch").parentNode.style.color="#00f0ff";
|
||||||
document.getElementById("themeSwitch").setAttribute("d",value=IconList[icon]);
|
if(utterancesLoad==1){utterancesTheme("dark-blue");}
|
||||||
document.getElementById("themeSwitch").parentNode.style.color=color;
|
}
|
||||||
if(utterancesLoad==1){utterancesTheme(utheme);}
|
function changeLight(){
|
||||||
|
document.getElementsByTagName("html")[0].attributes.getNamedItem("data-color-mode").value="light";
|
||||||
|
document.getElementById("themeSwitch").setAttribute("d",value=IconList["sun"]);
|
||||||
|
document.getElementById("themeSwitch").parentNode.style.color="#ff5000";
|
||||||
|
if(utterancesLoad==1){utterancesTheme("github-light");}
|
||||||
}
|
}
|
||||||
function modeSwitch(){
|
function modeSwitch(){
|
||||||
let currentMode=document.documentElement.getAttribute('data-color-mode');
|
if(document.getElementsByTagName("html")[0].attributes[0].value=="light"){changeDark();localStorage.setItem("meek_theme","dark");}
|
||||||
let newMode = currentMode === "light" ? "dark" : currentMode === "dark" ? "auto" : "light";
|
else{changeLight();localStorage.setItem("meek_theme","light");}
|
||||||
localStorage.setItem("meek_theme", newMode);
|
|
||||||
if(themeSettings[newMode]){
|
|
||||||
changeTheme(...themeSettings[newMode]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
function utterancesTheme(theme){
|
function utterancesTheme(theme){
|
||||||
const message={type:'set-theme',theme: theme};
|
const message = {type: 'set-theme',theme: theme};
|
||||||
const iframe=document.getElementsByClassName('utterances-frame')[0];
|
const iframe = document.getElementsByClassName('utterances-frame')[0];
|
||||||
iframe.contentWindow.postMessage(message,'https://utteranc.es');
|
iframe.contentWindow.postMessage(message, 'https://utteranc.es');
|
||||||
}
|
}
|
||||||
if(themeSettings[theme]){changeTheme(...themeSettings[theme]);}
|
|
||||||
{%- endif %}
|
console.log("\n %c Gmeek {{ blogBase['GMEEK_VERSION'] }} %c https://github.com/Meekdai/Gmeek \n\n", "color: #fff; background-image: linear-gradient(90deg, rgb(47, 172, 178) 0%, rgb(45, 190, 96) 100%); padding:5px 1px;", "background-image: linear-gradient(90deg, rgb(45, 190, 96) 0%, rgb(255, 255, 255) 100%); padding:5px 0;");
|
||||||
console.log("\n %c Gmeek {{ blogBase['GMEEK_VERSION'] }} https://github.com/Meekdai/Gmeek \n","padding:5px 0;background:#02d81d;color:#fff");
|
|
||||||
</script>
|
</script>
|
||||||
{% block script %}{% endblock %}
|
{% block script %}{% endblock %}
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -1,19 +1,14 @@
|
|||||||
<div id="footer1">Copyright © <span id="copyrightYear"></span> <a href="{{ blogBase['homeUrl'] }}">{{ blogBase['title'] }}</a></div>
|
Copyright © <span id="year"></span> <a href="{{ blogBase['homeUrl'] }}"> {{ blogBase['title'] }} </a><p> {{ blogBase['filingNum'] }} <span id="runday"></span>Powered by <a href="https://github.com/Meekdai/Gmeek" target="_blank">Gmeek</a></p>
|
||||||
<div id="footer2">
|
|
||||||
{%- if blogBase['filingNum']!='' -%}
|
|
||||||
<span id="filingNum"><a href="https://beian.miit.gov.cn/" target="_blank">{{ blogBase['filingNum'] }}</a> • </span>
|
|
||||||
{%- endif %}
|
|
||||||
<span id="runday"></span><span>Powered by <a href="https://meekdai.com/Gmeek.html" target="_blank">Gmeek</a></span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var now=new Date();
|
|
||||||
document.getElementById("copyrightYear").innerHTML=now.getFullYear();
|
|
||||||
|
|
||||||
if("{{ blogBase['startSite'] }}"!=""){
|
if("{{ blogBase['startSite'] }}"!=""){
|
||||||
|
var now=new Date();
|
||||||
var startSite=new Date("{{ blogBase['startSite'] }}");
|
var startSite=new Date("{{ blogBase['startSite'] }}");
|
||||||
var diff=now.getTime()-startSite.getTime();
|
var diff=now.getTime()-startSite.getTime();
|
||||||
var diffDay=Math.floor(diff/(1000*60*60*24));
|
var diffDay=Math.floor(diff/(1000*60*60*24));
|
||||||
document.getElementById("runday").innerHTML="{{ i18n['run'] }}"+diffDay+"{{ i18n['days'] }}"+" • ";
|
document.getElementById("year").innerHTML=now.getFullYear();
|
||||||
|
if("{{ blogBase['filingNum'] }}"!=""){document.getElementById("runday").innerHTML=" • "+"{{ i18n['run'] }}"+diffDay+"{{ i18n['days'] }}"+" • ";}
|
||||||
|
else{document.getElementById("runday").innerHTML="{{ i18n['run'] }}"+diffDay+"{{ i18n['days'] }}"+" • ";}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -1,81 +1,67 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<meta name="description" content="{{ blogBase['subTitle'] }}">
|
|
||||||
<meta property="og:title" content="{{ blogBase['title'] }}">
|
|
||||||
<meta property="og:description" content="{{ blogBase['subTitle'] }}">
|
|
||||||
<meta property="og:type" content="blog">
|
|
||||||
<meta property="og:url" content="{{ blogBase['homeUrl'] }}">
|
|
||||||
<meta property="og:image" content="{{ blogBase['ogImage'] }}">
|
|
||||||
<title>{{ blogBase['title'] }}</title>
|
<title>{{ blogBase['title'] }}</title>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
<style>
|
<style>
|
||||||
.avatar {transition: 0.8s;width:64px;height:64px;object-fit: cover;}
|
h1 a:not([href]){color:inherit;text-decoration:none;vertical-align: bottom;font-size:40px;font-family:Monaco;}
|
||||||
.avatar:hover{transform: scale(1.15) rotate(360deg);}
|
|
||||||
.title-left a{color:inherit;text-decoration:none;vertical-align: bottom;font-size:40px;font-weight: bold;font-family:Monaco;margin-left:8px;}
|
|
||||||
.title-right{display:flex;margin:auto 0 0 auto;}
|
.title-right{display:flex;margin:auto 0 0 auto;}
|
||||||
.title-right button{margin-right:8px;padding:16px;}
|
.title-right button{margin-right:8px;padding:16px;}
|
||||||
|
|
||||||
|
.subnav-search{margin-top:8px;margin-right:8px;}
|
||||||
|
.subnav-search-input{width:160px;border-top-right-radius:0px;border-bottom-right-radius:0px;}
|
||||||
|
.subnav-search button{padding:5px 8px;border-top-left-radius:0px;border-bottom-left-radius:0px;}
|
||||||
|
|
||||||
.title-right .circle{padding: 14px 16px;}
|
.title-right .circle{padding: 14px 16px;}
|
||||||
|
|
||||||
.SideNav{min-width: 360px;}
|
.SideNav{min-width: 360px;}
|
||||||
.SideNav-icon{margin-right: 16px}
|
.SideNav-icon{margin-right: 16px}
|
||||||
.SideNav-item .Label{color: #fff;margin-left:4px;}
|
.SideNav-item .Label{color: #fff;margin-left:8px;}
|
||||||
.d-flex{min-width:0;}
|
@media (max-width: 767px) {
|
||||||
.listTitle{overflow:hidden;white-space:nowrap;text-overflow: ellipsis;max-width: 100%;}
|
body { padding: 8px;}
|
||||||
.listLabels{white-space:nowrap;display:flex;}
|
h1 a:not([href]){font-size:24px;}
|
||||||
.listLabels object{max-height:16px;max-width:24px;}
|
.subnav-search form{display:none;}
|
||||||
|
.subnav-search svg{display:none;}
|
||||||
@media (max-width: 600px) {
|
|
||||||
body {padding: 8px;}
|
|
||||||
.avatar {width:40px;height:40px;}
|
|
||||||
.blogTitle{display:none;}
|
|
||||||
#buttonRSS{display:none;}
|
#buttonRSS{display:none;}
|
||||||
.LabelTime{display:none;}
|
.SideNav-item .listLabels{display:none;}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{{ blogBase['indexStyle'] }}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block header %}
|
{% block header %}
|
||||||
<div class="title-left">
|
<h1>
|
||||||
<img src="{{ blogBase['avatarUrl'] }}" class="avatar circle" id="avatarImg" alt="avatar">
|
<img src="{{ blogBase['avatarUrl'] }}" size="64" height="64" width="64" class="avatar circle" id="avatarImg">
|
||||||
{%- if blogBase['displayTitle']=='Meekdai' -%}
|
<a>{{ blogBase['displayTitle'] }}</a>
|
||||||
<a class="blogTitle" href="https://meekdai.com"><span style="font-size:0;">M</span>eekdai</a>
|
</h1>
|
||||||
{% else -%}
|
|
||||||
<a class="blogTitle">{{ blogBase['displayTitle'] }}</a>
|
|
||||||
{%- endif -%}
|
|
||||||
</div>
|
|
||||||
<div class="title-right">
|
<div class="title-right">
|
||||||
<a href="{{ blogBase['homeUrl'] }}/tag.html" id="buttonSearch" class="btn btn-invisible circle" title="{{ i18n['Search'] }}">
|
<div class="subnav-search">
|
||||||
<svg class="octicon" width="16" height="16" >
|
<form action="https://www.google.com/search" method="get" target="_blank">
|
||||||
<path id="pathSearch" fill-rule="evenodd"></path>
|
<input type="hidden" name="q" value="site:{{ blogBase['homeUrl'] }}">
|
||||||
|
<input type="search" name="q" class="form-control subnav-search-input float-left" aria-label="Search site" value="">
|
||||||
|
<button class="btn float-left" type="submit">{{ i18n['Search'] }}</button>
|
||||||
|
</form>
|
||||||
|
<svg class="subnav-search-icon octicon octicon-search" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true">
|
||||||
|
<path id="searchSVG" fill-rule="evenodd" d=""></path>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</div>
|
||||||
{% for key, value in blogBase['exlink'].items() -%}
|
|
||||||
<a href="{{ value }}" class="btn btn-invisible circle" title="{{ key }}" target="_blank">
|
|
||||||
<svg class="octicon" width="16" height="16" >
|
|
||||||
<path id="{{ key }}" fill-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{%- endfor %}
|
|
||||||
{% for num in blogBase['singeListJson'] -%}
|
{% for num in blogBase['singeListJson'] -%}
|
||||||
<a href="{{ blogBase['homeUrl'] }}/{{ blogBase['singeListJson'][num]['labels'][0] }}.html" class="btn btn-invisible circle" title="{{ blogBase['singeListJson'][num]['postTitle'] }}">
|
<a href="/{{ blogBase['singeListJson'][num]['label'] }}.html"><button class="btn btn-invisible circle" title="{{ blogBase['singeListJson'][num]['postTitle'] }}">
|
||||||
<svg class="octicon" width="16" height="16" >
|
<svg class="octicon" width="16" height="16" >
|
||||||
<path id="{{ blogBase['singeListJson'][num]['postTitle'] }}" fill-rule="evenodd"></path>
|
<path id="{{ blogBase['singeListJson'][num]['postTitle'] }}" fill-rule="evenodd"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</button></a>
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
<a href="{{ blogBase['homeUrl'] }}/rss.xml" target="_blank" id="buttonRSS" class="btn btn-invisible circle" title="RSS">
|
<a href="/rss.xml" target="_blank"><button id="buttonRSS" class="btn btn-invisible circle" title="RSS">
|
||||||
<svg class="octicon" width="16" height="16" >
|
<svg class="octicon" width="16" height="16" >
|
||||||
<path id="pathRSS" fill-rule="evenodd"></path>
|
<path id="pathRSS" fill-rule="evenodd"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</button></a>
|
||||||
<a class="btn btn-invisible circle" onclick="modeSwitch()" title="{{ i18n['switchTheme'] }}" {%- if blogBase['themeMode']=='fix' -%}style="display:none;"{%- endif -%}>
|
<button class="btn btn-invisible circle" onclick="modeSwitch()" title="{{ i18n['switchTheme'] }}">
|
||||||
<svg class="octicon" width="16" height="16" >
|
<svg class="octicon" width="16" height="16" >
|
||||||
<path id="themeSwitch" fill-rule="evenodd"></path>
|
<path id="themeSwitch" fill-rule="evenodd"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@ -87,14 +73,12 @@
|
|||||||
<div class="d-flex flex-items-center">
|
<div class="d-flex flex-items-center">
|
||||||
<svg class="SideNav-icon octicon" style="witdh:16px;height:16px"><path class="svgTop{{ postListJson[num]['top'] }}" d=""></path>
|
<svg class="SideNav-icon octicon" style="witdh:16px;height:16px"><path class="svgTop{{ postListJson[num]['top'] }}" d=""></path>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="listTitle">{{ postListJson[num]['postTitle']|e }}</span>
|
<span>{{ postListJson[num]['postTitle']|e }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="listLabels">
|
<div class="listLabels">
|
||||||
{% if postListJson[num]['commentNum']>0 %}<span class="Label" style="background-color:{{ blogBase['commentLabelColor'] }}">{{ postListJson[num]['commentNum'] }}</span>{% endif %}
|
{% if postListJson[num]['commentNum']>0 %}<span class="Label" style="background-color:{{ blogBase['commentLabelColor'] }}">{{ postListJson[num]['commentNum'] }}</span>{% endif %}
|
||||||
{% for label in postListJson[num]['labels'] -%}
|
<span class="Label" style="background-color:{{ postListJson[num]['labelColor'] }}">{{ postListJson[num]['label'] }}</span>
|
||||||
<span class="Label LabelName" style="background-color:{{ blogBase['labelColorDict'][label] }}"><object><a style="color:#fff" href="tag.html#{{ label }}">{{ label }}</a></object></span>
|
<span class="Label" style="background-color:{{ postListJson[num]['dateLabelColor'] }}">{{ postListJson[num]['createdDate'] }}</span>
|
||||||
{%- endfor %}
|
|
||||||
<span class="Label LabelTime" style="background-color:{{ postListJson[num]['dateLabelColor'] }}">{{ postListJson[num]['createdDate'] }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
@ -105,13 +89,13 @@
|
|||||||
{%- if blogBase['prevUrl']=='disabled' -%}
|
{%- if blogBase['prevUrl']=='disabled' -%}
|
||||||
<span class="previous_page" aria-disabled="true">{{ i18n['Previous'] }}</span>
|
<span class="previous_page" aria-disabled="true">{{ i18n['Previous'] }}</span>
|
||||||
{% else -%}
|
{% else -%}
|
||||||
<a class="previous_page" rel="previous" href="{{ blogBase['homeUrl'] }}{{ blogBase['prevUrl'] }}" aria-label="Previous Page">{{ i18n['Previous'] }}</a>
|
<a class="previous_page" rel="previous" href="{{ blogBase['prevUrl'] }}" aria-label="Previous Page">{{ i18n['Previous'] }}</a>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
|
|
||||||
{%- if blogBase['nextUrl']=='disabled' -%}
|
{%- if blogBase['nextUrl']=='disabled' -%}
|
||||||
<span class="next_page" aria-disabled="true">{{ i18n['Next'] }}</span>
|
<span class="next_page" aria-disabled="true">{{ i18n['Next'] }}</span>
|
||||||
{% else -%}
|
{% else -%}
|
||||||
<a class="next_page" rel="next" href="{{ blogBase['homeUrl'] }}{{ blogBase['nextUrl'] }}" aria-label="Next Page">{{ i18n['Next'] }}</a>
|
<a class="next_page" rel="next" href="{{ blogBase['nextUrl'] }}" aria-label="Next Page">{{ i18n['Next'] }}</a>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -121,7 +105,7 @@
|
|||||||
|
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script>
|
<script>
|
||||||
document.getElementById("pathSearch").setAttribute("d",IconList["search"]);
|
document.getElementById("searchSVG").setAttribute("d",IconList["search"]);
|
||||||
document.getElementById("pathRSS").setAttribute("d",IconList["rss"]);
|
document.getElementById("pathRSS").setAttribute("d",IconList["rss"]);
|
||||||
iconTOP=document.getElementsByClassName("svgTop1");
|
iconTOP=document.getElementsByClassName("svgTop1");
|
||||||
iconPost=document.getElementsByClassName("svgTop0");
|
iconPost=document.getElementsByClassName("svgTop0");
|
||||||
@ -133,13 +117,8 @@ for(var i=0;i<iconPost.length;i++){
|
|||||||
iconPost[i].setAttribute("d",IconList["post"]);
|
iconPost[i].setAttribute("d",IconList["post"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
{% for key, value in blogBase['exlink'].items() %}
|
|
||||||
document.getElementById("{{ key }}").setAttribute("d",value=IconList["{{ key }}"]);
|
|
||||||
{%- endfor %}
|
|
||||||
|
|
||||||
{% for num in blogBase['singeListJson'] -%}
|
{% for num in blogBase['singeListJson'] -%}
|
||||||
document.getElementById("{{ blogBase['singeListJson'][num]['postTitle'] }}").setAttribute("d",value=IconList["{{ blogBase['singeListJson'][num]['labels'][0] }}"]);
|
document.getElementById("{{ blogBase['singeListJson'][num]['postTitle'] }}").setAttribute("d",value=IconList["{{ blogBase['singeListJson'][num]['label'] }}"]);
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
</script>
|
</script>
|
||||||
{{ blogBase['indexScript'] }}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,20 +1,13 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<meta name="description" content="{{ blogBase['description'] }}">
|
|
||||||
<meta property="og:title" content="{{ blogBase['postTitle'] }}">
|
|
||||||
<meta property="og:description" content="{{ blogBase['description'] }}">
|
|
||||||
<meta property="og:type" content="article">
|
|
||||||
<meta property="og:url" content="{{ blogBase['postUrl'] }}">
|
|
||||||
<meta property="og:image" content="{{ blogBase['ogImage'] }}">
|
|
||||||
<title>{{ blogBase['postTitle'] }}</title>
|
<title>{{ blogBase['postTitle'] }}</title>
|
||||||
{% if blogBase['highlight']==1 %}<link href="//unpkg.com/@wooorm/starry-night@2.1.1/style/both.css" rel="stylesheet" />{% endif %}
|
<link href="//unpkg.com/@wooorm/starry-night@2.1.1/style/both.css" rel="stylesheet" />
|
||||||
{{ blogBase['head'] }}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
<style>
|
<style>
|
||||||
.postTitle{margin: auto 0;font-size:40px;font-weight:bold;}
|
h1 a:not([href]){color:inherit;text-decoration:none;vertical-align: bottom;font-size:40px;}
|
||||||
.title-right{display:flex;margin:auto 0 0 auto;}
|
.title-right{display:flex;margin:auto 0 0 auto;}
|
||||||
.title-right .circle{padding: 14px 16px;margin-right:8px;}
|
.title-right .circle{padding: 14px 16px;margin-right:8px;}
|
||||||
#postBody{border-bottom: 1px solid var(--color-border-default);padding-bottom:36px;}
|
#postBody{border-bottom: 1px solid var(--color-border-default);padding-bottom:36px;}
|
||||||
@ -22,64 +15,49 @@
|
|||||||
#cmButton{height:48px;margin-top:48px;}
|
#cmButton{height:48px;margin-top:48px;}
|
||||||
#comments{margin-top:64px;}
|
#comments{margin-top:64px;}
|
||||||
.g-emoji{font-size:24px;}
|
.g-emoji{font-size:24px;}
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 767px) {body {padding: 8px;}}
|
||||||
body {padding: 8px;}
|
|
||||||
.postTitle{font-size:24px;}
|
|
||||||
}
|
|
||||||
{% if blogBase['highlight']!=0 -%}
|
|
||||||
.copy-feedback {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
right: 50px;
|
|
||||||
color: var(--color-fg-on-emphasis);
|
|
||||||
background-color: var(--color-fg-muted);
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 5px 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
}{% endif %}
|
|
||||||
</style>
|
</style>
|
||||||
{{ blogBase['style'] }}
|
{{ blogBase['style'] }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block header %}
|
{% block header %}
|
||||||
<h1 class="postTitle">{{ blogBase['postTitle'] }}</h1>
|
<h1>
|
||||||
|
<a>{{ blogBase['postTitle'] }}</a>
|
||||||
|
</h1>
|
||||||
<div class="title-right">
|
<div class="title-right">
|
||||||
<a href="{{ blogBase['homeUrl'] }}" id="buttonHome" class="btn btn-invisible circle" title="{{ i18n['home'] }}">
|
|
||||||
<svg class="octicon" width="16" height="16">
|
|
||||||
<path id="pathHome" fill-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{% if blogBase['showPostSource']==1 %}
|
|
||||||
<a href="{{ blogBase['postSourceUrl'] }}" target="_blank" class="btn btn-invisible circle" title="Issue">
|
|
||||||
<svg class="octicon" width="16" height="16">
|
|
||||||
<path id="pathIssue" fill-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<a class="btn btn-invisible circle" onclick="modeSwitch();" title="{{ i18n['switchTheme'] }}" {%- if blogBase['themeMode']=='fix' -%}style="display:none;"{%- endif -%}>
|
<a href="/"><button id="buttonHome" class="btn btn-invisible circle" title="{{ i18n['home'] }}">
|
||||||
|
<svg class="octicon" width="16" height="16">
|
||||||
|
<path id="pathHome" fill-rule="evenodd" d="{{ IconList['home'] }}"></path>
|
||||||
|
</svg>
|
||||||
|
</button></a>
|
||||||
|
|
||||||
|
<a href="{{ blogBase['postSourceUrl'] }}" target="_blank"><button class="btn btn-invisible circle" title="Issue">
|
||||||
|
<svg class="octicon" width="16" height="16">
|
||||||
|
<path id="pathIssue" fill-rule="evenodd" d="{{ IconList['github'] }}"></path>
|
||||||
|
</svg>
|
||||||
|
</button></a>
|
||||||
|
|
||||||
|
<button class="btn btn-invisible circle" onclick="modeSwitch();" title="{{ i18n['switchTheme'] }}">
|
||||||
<svg class="octicon" width="16" height="16" >
|
<svg class="octicon" width="16" height="16" >
|
||||||
<path id="themeSwitch" fill-rule="evenodd"></path>
|
<path id="themeSwitch" fill-rule="evenodd"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="markdown-body" id="postBody">{{ blogBase['postBody'] }}</div>
|
<div class="markdown-body" id="postBody">
|
||||||
<div style="font-size:small;margin-top:8px;float:right;">{{ blogBase['bottomText'] }}</div>
|
{{ blogBase['postBody'] }}
|
||||||
{% if blogBase['needComment']==1 %}
|
</div>
|
||||||
<button class="btn btn-block" type="button" onclick="openComments()" id="cmButton">{{ i18n['comments'] }}</button>
|
<button class="btn btn-block" type="button" onclick="openComments()" id="cmButton">{{ i18n['comments'] }}</button>
|
||||||
<div class="comments" id="comments"></div>
|
<div class="comments" id="comments"></div>
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script>
|
<script>
|
||||||
document.getElementById("pathHome").setAttribute("d",IconList["home"]);
|
|
||||||
{% if blogBase['showPostSource']==1 %}document.getElementById("pathIssue").setAttribute("d",IconList["github"]);{% endif %}
|
|
||||||
{% if blogBase['commentNum']>0 -%}
|
{% if blogBase['commentNum']>0 -%}
|
||||||
cmButton=document.getElementById("cmButton");
|
cmButton=document.getElementById("cmButton");
|
||||||
span=document.createElement("span");
|
span=document.createElement("span");
|
||||||
@ -88,7 +66,6 @@ document.getElementById("pathHome").setAttribute("d",IconList["home"]);
|
|||||||
cmButton.appendChild(span);
|
cmButton.appendChild(span);
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
{% if blogBase['needComment']==1 %}
|
|
||||||
function openComments(){
|
function openComments(){
|
||||||
cm=document.getElementById("comments");
|
cm=document.getElementById("comments");
|
||||||
cmButton=document.getElementById("cmButton");
|
cmButton=document.getElementById("cmButton");
|
||||||
@ -101,13 +78,8 @@ function openComments(){
|
|||||||
script.setAttribute("src","https://utteranc.es/client.js");
|
script.setAttribute("src","https://utteranc.es/client.js");
|
||||||
script.setAttribute("repo","{{ blogBase['repoName'] }}");
|
script.setAttribute("repo","{{ blogBase['repoName'] }}");
|
||||||
script.setAttribute("issue-term","title");
|
script.setAttribute("issue-term","title");
|
||||||
{% if blogBase['themeMode']=='manual' %}
|
|
||||||
if(localStorage.getItem("meek_theme")=="dark"){script.setAttribute("theme","dark-blue");}
|
if(localStorage.getItem("meek_theme")=="dark"){script.setAttribute("theme","dark-blue");}
|
||||||
else if(localStorage.getItem("meek_theme")=="light") {script.setAttribute("theme","github-light");}
|
else{script.setAttribute("theme","github-light");}
|
||||||
else{script.setAttribute("theme","preferred-color-scheme");}
|
|
||||||
{% else %}
|
|
||||||
script.setAttribute("theme","{{ blogBase['nightTheme'] }}");
|
|
||||||
{% endif %}
|
|
||||||
script.setAttribute("crossorigin","anonymous");
|
script.setAttribute("crossorigin","anonymous");
|
||||||
script.setAttribute("async","");
|
script.setAttribute("async","");
|
||||||
cm.appendChild(script);
|
cm.appendChild(script);
|
||||||
@ -126,75 +98,9 @@ function iFrameLoading(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
{% if blogBase['highlight']!=0 -%}
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const createClipboardHTML = (codeContent, additionalClasses = '') => `
|
|
||||||
<pre class="notranslate"><code class="notranslate">${codeContent}</code></pre>
|
|
||||||
<div class="clipboard-container position-absolute right-0 top-0 ${additionalClasses}">
|
|
||||||
<clipboard-copy class="ClipboardButton btn m-2 p-0" role="button" style="display: inherit;">
|
|
||||||
<svg height="16" width="16" class="octicon octicon-copy m-2"><path d="${IconList["copy"]}"></path></svg>
|
|
||||||
<svg height="16" width="16" class="octicon octicon-check color-fg-success m-2 d-none"><path d="${IconList["check"]}"></path></svg>
|
|
||||||
</clipboard-copy>
|
|
||||||
<div class="copy-feedback">Copied!</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
const handleCodeElements = (selector = '') => {
|
|
||||||
document.querySelectorAll(selector).forEach(codeElement => {
|
|
||||||
const codeContent = codeElement.innerHTML;
|
|
||||||
const newStructure = document.createElement('div');
|
|
||||||
newStructure.className = 'snippet-clipboard-content position-relative overflow-auto';
|
|
||||||
newStructure.innerHTML = createClipboardHTML(codeContent);
|
|
||||||
|
|
||||||
const parentElement = codeElement.parentElement;
|
|
||||||
if (selector.includes('highlight')) {
|
|
||||||
parentElement.insertBefore(newStructure, codeElement.nextSibling);
|
|
||||||
parentElement.removeChild(codeElement);
|
|
||||||
} else {
|
|
||||||
parentElement.parentElement.replaceChild(newStructure, parentElement);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleCodeElements('pre.notranslate > code.notranslate');
|
|
||||||
handleCodeElements('div.highlight > pre.notranslate');
|
|
||||||
|
|
||||||
let currentFeedback = null;
|
|
||||||
document.querySelectorAll('clipboard-copy').forEach(copyButton => {
|
|
||||||
copyButton.addEventListener('click', () => {
|
|
||||||
const codeContent = copyButton.closest('.snippet-clipboard-content').innerText;
|
|
||||||
const tempTextArea = document.createElement('textarea');
|
|
||||||
tempTextArea.value = codeContent;
|
|
||||||
document.body.appendChild(tempTextArea);
|
|
||||||
tempTextArea.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
document.body.removeChild(tempTextArea);
|
|
||||||
|
|
||||||
const copyIcon = copyButton.querySelector('.octicon-copy');
|
|
||||||
const checkIcon = copyButton.querySelector('.octicon-check');
|
|
||||||
const copyFeedback = copyButton.nextElementSibling;
|
|
||||||
|
|
||||||
if (currentFeedback && currentFeedback !== copyFeedback) {currentFeedback.style.display = 'none';}
|
|
||||||
currentFeedback = copyFeedback;
|
|
||||||
|
|
||||||
copyIcon.classList.add('d-none');
|
|
||||||
checkIcon.classList.remove('d-none');
|
|
||||||
copyFeedback.style.display = 'block';
|
|
||||||
copyButton.style.borderColor = 'var(--color-success-fg)';
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
copyIcon.classList.remove('d-none');
|
|
||||||
checkIcon.classList.add('d-none');
|
|
||||||
copyFeedback.style.display = 'none';
|
|
||||||
copyButton.style.borderColor = '';
|
|
||||||
}, 2000);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{{ blogBase['script'] }}
|
{{ blogBase['script'] }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,221 +0,0 @@
|
|||||||
{% extends 'base.html' %}
|
|
||||||
{% block head %}
|
|
||||||
<meta name="description" content="{{ blogBase['title'] }} search page">
|
|
||||||
<title>{{ blogBase['title'] }} - Tag</title>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block style %}
|
|
||||||
<style>
|
|
||||||
.tagTitle{margin:auto 0;font-size:40px;font-weight:bold;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}
|
|
||||||
.title-right{display:flex;margin:auto 0 0 auto;}
|
|
||||||
.title-right .circle{padding: 14px 16px;margin-right:8px;}
|
|
||||||
|
|
||||||
.subnav-search{width:222px;margin-top:8px;margin-right:8px;}
|
|
||||||
.subnav-search-input{width:160px;border-top-right-radius:0px;border-bottom-right-radius:0px;}
|
|
||||||
.subnav-search button{padding:5px 8px;border-top-left-radius:0px;border-bottom-left-radius:0px;}
|
|
||||||
|
|
||||||
.SideNav-icon{margin-right:16px}
|
|
||||||
.Label{color: #fff;margin-left:4px;}
|
|
||||||
#taglabel .Label {margin-bottom:8px;}
|
|
||||||
.Counter{color:#fff;background-color:rgba(234, 238, 242, 0.5)}
|
|
||||||
|
|
||||||
.genTime{float: right;}
|
|
||||||
.d-flex{min-width:0;}
|
|
||||||
.listTitle{overflow:hidden;white-space:nowrap;text-overflow: ellipsis;max-width: 100%;}
|
|
||||||
.listLabels{white-space:nowrap;}
|
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
body { padding: 8px;}
|
|
||||||
.tagTitle{display:none;}
|
|
||||||
.LabelTime{display:none;}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block header %}
|
|
||||||
<span class="tagTitle"><span>Loading</span><span class="AnimatedEllipsis"></span></span>
|
|
||||||
<div class="title-right">
|
|
||||||
<div class="subnav-search">
|
|
||||||
<input type="search" class="form-control subnav-search-input float-left" aria-label="Search site" value="" style="height:32px;">
|
|
||||||
<button class="btn float-left" type="submit" onclick="javascript:searchShow()">{{ i18n['Search'] }}</button>
|
|
||||||
<svg class="subnav-search-icon octicon octicon-search" width="16" height="16" viewBox="0 0 16 16" aria-hidden="true">
|
|
||||||
<path id="searchSVG" fill-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<a href="{{ blogBase['homeUrl'] }}" id="buttonHome" class="btn btn-invisible circle" title="{{ i18n['home'] }}">
|
|
||||||
<svg class="octicon" width="16" height="16">
|
|
||||||
<path id="pathHome" fill-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
<a class="btn btn-invisible circle" onclick="modeSwitch()" title="{{ i18n['switchTheme'] }}" {%- if blogBase['themeMode']=='fix' -%}style="display:none;"{%- endif -%}>
|
|
||||||
<svg class="octicon" width="16" height="16" >
|
|
||||||
<path id="themeSwitch" fill-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div id="taglabel" style="margin-bottom:8px;"></div>
|
|
||||||
<nav class="SideNav"></nav>
|
|
||||||
<div class="notFind" style="display:none;font-size:24px;margin:8px;">Not Find</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block script %}
|
|
||||||
<script>
|
|
||||||
document.getElementById("pathHome").setAttribute("d",IconList["home"]);
|
|
||||||
document.getElementById("searchSVG").setAttribute("d",IconList["search"]);
|
|
||||||
|
|
||||||
tagList=[];
|
|
||||||
labelsCount={};
|
|
||||||
jsonData='';
|
|
||||||
let requestJson="postList.json"
|
|
||||||
let request=new XMLHttpRequest();
|
|
||||||
request.open("GET",requestJson);
|
|
||||||
request.responseType='text';
|
|
||||||
request.send();
|
|
||||||
request.onload=function(){
|
|
||||||
jsonData=JSON.parse(request.response);
|
|
||||||
console.log(jsonData);
|
|
||||||
showList(labelsCount);
|
|
||||||
setClassDisplay(decodeURI(window.location.hash.slice(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function showList(labelsCount){
|
|
||||||
let SideNav=document.getElementsByClassName("SideNav")[0];
|
|
||||||
SideNav.classList.add("border");
|
|
||||||
let taglabel=document.getElementById("taglabel");
|
|
||||||
|
|
||||||
jsonData['labelColorDict']["All"]="#000";
|
|
||||||
labelsCount["All"]=0;
|
|
||||||
for (let key in jsonData) {
|
|
||||||
if (key !== 'labelColorDict' && Array.isArray(jsonData[key]['labels'])) {
|
|
||||||
labelsCount["All"]++;
|
|
||||||
for (let label of jsonData[key]['labels']) {
|
|
||||||
labelsCount[label] = (labelsCount[label] || 0) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let sortedLabelsList = Object.keys(labelsCount).sort((a, b) => labelsCount[b] - labelsCount[a]);
|
|
||||||
for (let label of sortedLabelsList) {
|
|
||||||
tagList.push(label);
|
|
||||||
let showLabels = document.createElement("button");
|
|
||||||
showLabels.setAttribute("class", "Label");
|
|
||||||
showLabels.setAttribute("style", "background-color:" + jsonData['labelColorDict'][label]+";padding:4px;");
|
|
||||||
showLabels.innerHTML=" "+label+" ";
|
|
||||||
showLabels.setAttribute("onclick", "javascript:updateShowTag('" + label + "');");
|
|
||||||
|
|
||||||
let LabelNum=document.createElement("span");
|
|
||||||
LabelNum.setAttribute("class","Counter");
|
|
||||||
LabelNum.innerHTML=labelsCount[label];
|
|
||||||
showLabels.appendChild(LabelNum);
|
|
||||||
taglabel.appendChild(showLabels);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i in jsonData){
|
|
||||||
if(i!='labelColorDict'){
|
|
||||||
let div=document.createElement("div");
|
|
||||||
div.setAttribute("class","lists "+jsonData[i]['labels'].join(" "));
|
|
||||||
let item=document.createElement("a");
|
|
||||||
item.setAttribute("class","SideNav-item d-flex flex-items-center flex-justify-between");
|
|
||||||
item.setAttribute("href",jsonData[i]['postUrl']);
|
|
||||||
|
|
||||||
let center=document.createElement("div");
|
|
||||||
center.setAttribute("class","d-flex flex-items-center");
|
|
||||||
|
|
||||||
svg=document.createElementNS('http://www.w3.org/2000/svg','svg');
|
|
||||||
path=document.createElementNS("http://www.w3.org/2000/svg","path");
|
|
||||||
span=document.createElement("span");
|
|
||||||
svg.setAttributeNS(null,"class","SideNav-icon octicon");
|
|
||||||
svg.setAttributeNS(null,"style","width:16px;height:16px");
|
|
||||||
path.setAttributeNS(null, "d", IconList["post"]);
|
|
||||||
svg.appendChild(path);
|
|
||||||
|
|
||||||
let title=document.createElement("span");
|
|
||||||
title.setAttribute("class","listTitle");
|
|
||||||
title.innerHTML=jsonData[i]['postTitle'];
|
|
||||||
center.appendChild(svg);
|
|
||||||
center.appendChild(title);
|
|
||||||
|
|
||||||
let listLabels=document.createElement("div");
|
|
||||||
listLabels.setAttribute("class","listLabels");
|
|
||||||
|
|
||||||
for(label of jsonData[i]['labels']){
|
|
||||||
let LabelName=document.createElement("span");
|
|
||||||
LabelName.setAttribute("class","Label LabelName");
|
|
||||||
LabelName.setAttribute("style","background-color:"+jsonData['labelColorDict'][label]);
|
|
||||||
LabelName.innerHTML=label;
|
|
||||||
listLabels.appendChild(LabelName);
|
|
||||||
}
|
|
||||||
let LabelTime=document.createElement("span");
|
|
||||||
LabelTime.setAttribute("class","Label LabelTime");
|
|
||||||
LabelTime.setAttribute("style","background-color:"+jsonData[i]['dateLabelColor']);
|
|
||||||
LabelTime.innerHTML=jsonData[i]['createdDate'];
|
|
||||||
listLabels.appendChild(LabelTime);
|
|
||||||
|
|
||||||
item.appendChild(center);
|
|
||||||
item.appendChild(listLabels);
|
|
||||||
div.appendChild(item);
|
|
||||||
SideNav.appendChild(div);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateShowTag(label){
|
|
||||||
if(window.location.hash.slice(1)!=encodeURI(label)){
|
|
||||||
window.location.hash="#"+(label);
|
|
||||||
setClassDisplay(label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setClassDisplay(label){
|
|
||||||
let lists = document.getElementsByClassName("lists");
|
|
||||||
let tagTitle = document.getElementsByClassName("tagTitle")[0];
|
|
||||||
tagTitle.innerHTML="Tag #"+label;
|
|
||||||
document.title=label+" - {{ blogBase['title'] }}";
|
|
||||||
document.getElementsByClassName("subnav-search-input")[0].value='';
|
|
||||||
if(label=="All"){
|
|
||||||
for(let i = 0; i < lists.length; i++){lists[i].style.display='block';}
|
|
||||||
document.getElementsByClassName("notFind")[0].style.display='none';
|
|
||||||
}
|
|
||||||
else if(tagList.indexOf(label)!=-1){
|
|
||||||
for(let i = 0; i < lists.length; i++){
|
|
||||||
lists[i].style.display='none';
|
|
||||||
}
|
|
||||||
|
|
||||||
let labels = document.getElementsByClassName(label);
|
|
||||||
for(let i = 0; i < labels.length; i++){
|
|
||||||
labels[i].style.display='block';
|
|
||||||
}
|
|
||||||
document.getElementsByClassName("notFind")[0].style.display='none';
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
document.getElementsByClassName("subnav-search-input")[0].value=label;
|
|
||||||
searchShow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchShow(){
|
|
||||||
let lists = document.getElementsByClassName("lists");
|
|
||||||
let tagTitle = document.getElementsByClassName("tagTitle")[0];
|
|
||||||
let searchInput = document.getElementsByClassName("subnav-search-input")[0].value;
|
|
||||||
tagTitle.innerHTML="Search #"+searchInput;
|
|
||||||
if(searchInput==''){document.title="Search - {{ blogBase['title'] }}";}
|
|
||||||
else{document.title=searchInput+" - {{ blogBase['title'] }}";}
|
|
||||||
let a=0;
|
|
||||||
window.location.hash="#"+(searchInput);
|
|
||||||
for(let i = 0; i < lists.length; i++){
|
|
||||||
if(lists[i].childNodes[0].childNodes[0].childNodes[1].innerHTML.toUpperCase().indexOf(searchInput.toUpperCase())==-1){lists[i].style.display='none';}
|
|
||||||
else{lists[i].style.display='block';a=a+1;}
|
|
||||||
}
|
|
||||||
if(a==0){
|
|
||||||
let notFind=document.getElementsByClassName("notFind")[0];
|
|
||||||
notFind.style.display='block';
|
|
||||||
notFind.innerHTML='Not Find "'+searchInput+'"';
|
|
||||||
}
|
|
||||||
else{document.getElementsByClassName("notFind")[0].style.display='none';}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
Loading…
Reference in New Issue
Block a user