Compare commits

..

No commits in common. "main" and "v2.3" have entirely different histories.
main ... v2.3

20 changed files with 323 additions and 1557 deletions

View File

@ -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
View 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
View File

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
import os
import re
import json
import time
import datetime
@ -8,18 +7,14 @@ import shutil
import urllib
import requests
import argparse
import html
from github import Github
from xpinyin import Pinyin
from feedgen.feed import FeedGenerator
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"}
i18nCN={"Search":"搜索","switchTheme":"切换主题","home":"首页","comments":"评论","run":"网站运行","days":"","Previous":"上一页","Next":"下一页"}
i18nRU={"Search":"Поиск","switchTheme": "Сменить тему","home":"Главная","comments":"Комментарии","run":"работает ","days":" дней","Previous":"Предыдущая","Next":"Следующая"}
IconBase={
i18n={"Search":"Search","switchTheme":"switch theme","link":"link","home":"home","comments":"comments","run":"run ","days":" days","Previous":"Previous","Next":"Next"}
i18nCN={"Search":"搜索","switchTheme":"切换主题","link":"友情链接","home":"首页","comments":"评论","run":"网站运行","days":"","Previous":"上一页","Next":"下一页"}
IconList={
"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",
"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",
"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",
"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"
"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"
}
######################################################################################
class GMEEK():
@ -40,7 +32,6 @@ class GMEEK():
self.options=options
self.root_dir='docs/'
self.static_dir='static/'
self.post_folder='post/'
self.backup_dir='backup/'
self.post_dir=self.root_dir+self.post_folder
@ -48,22 +39,24 @@ class GMEEK():
user = Github(self.options.github_token)
self.repo = self.get_repo(user, options.repo_name)
self.feed = FeedGenerator()
self.oldFeedString=''
self.labelColorDict=json.loads('{}')
for label in self.repo.get_labels():
self.labelColorDict[label.name]='#'+label.color
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):
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):
shutil.rmtree(self.backup_dir)
@ -74,148 +67,46 @@ class GMEEK():
os.mkdir(self.root_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):
return user.get_repo(repo)
def markdown2html(self, mdstr):
payload = {"text": mdstr, "mode": "gfm"}
headers = {"Authorization": "token {}".format(self.options.github_token)}
try:
response = requests.post("https://api.github.com/markdown", json=payload, headers=headers)
response.raise_for_status() # Raises an exception if status code is not 200
return response.text
except requests.RequestException as e:
raise Exception("markdown2html error: {}".format(e))
def markdown2html(self,mdstr):
payload = {"text": mdstr, "mode": "markdown"}
ret=requests.post("https://api.github.com/markdown", json=payload,headers={"Authorzation":"token {}".format(self.options.github_token)})
if ret.status_code==200:
return ret.text
else:
raise Exception("markdown2html error status_code=%d"%(ret.status_code))
def renderHtml(self,template,blogBase,postListJson,htmlDir,icon):
def renderHtml(self,template,blogBase,postListJson,htmlDir):
file_loader = FileSystemLoader('templates')
env = Environment(loader=file_loader)
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.write(output)
f.close()
def createPostHtml(self,issue):
mdFileName=re.sub(r'[<>:/\\|?*\"]|[\0-\31]', '-', issue["postTitle"])
f = open(self.backup_dir+mdFileName+".md", 'r', encoding='UTF-8')
f = open("backup/"+issue["postTitle"]+".md", 'r', encoding='UTF-8')
post_body=self.markdown2html(f.read())
f.close()
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["postUrl"]=self.blogBase["homeUrl"]+"/"+issue["postUrl"]
postBase["description"]=issue["description"]
postBase["ogImage"]=issue["ogImage"]
postBase["postBody"]=post_body
postBase["commentNum"]=issue["commentNum"]
postBase["style"]=issue["style"]
postBase["script"]=issue["script"]
postBase["head"]=issue["head"]
postBase["top"]=issue["top"]
postBase["postSourceUrl"]=issue["postSourceUrl"]
postBase["repoName"]=options.repo_name
if issue["labels"][0] in self.blogBase["singlePage"]:
postBase["bottomText"]=''
if '<pre class="notranslate">' in post_body:
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)
self.renderHtml('post.html',postBase,{},issue["htmlDir"])
print("create postPage title=%s file=%s " % (issue["postTitle"],issue["htmlDir"]))
def createPlistHtml(self):
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"])
pageFlag=0
@ -237,7 +128,7 @@ class GMEEK():
self.blogBase["prevUrl"]="/page%d.html" % pageFlag
self.blogBase["nextUrl"]="disabled"
self.renderHtml('plist.html',self.blogBase,onePageList,htmlDir,plistIcon)
self.renderHtml('plist.html',self.blogBase,onePageList,htmlDir)
print("create "+htmlDir)
break
else:
@ -255,14 +146,11 @@ class GMEEK():
self.blogBase["prevUrl"]="/page%d.html" % pageFlag
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)
pageFlag=pageFlag+1
self.renderHtml('tag.html',self.blogBase,onePageList,self.root_dir+"tag.html",tagIcon)
print("create tag.html")
def createFeedXml(self):
self.blogBase["postListJson"]=dict(sorted(self.blogBase["postListJson"].items(),key=lambda x:x[1]["createdAt"],reverse=False))#使列表由时间排序
feed = FeedGenerator()
@ -270,6 +158,7 @@ class GMEEK():
feed.description(self.blogBase["subTitle"])
feed.link(href=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.managingEditor(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.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')
def addOnePostJson(self,issue):
if len(issue.labels)>=1:
if len(issue.labels)==1:
if issue.labels[0].name in self.blogBase["singlePage"]:
listJsonName='singeListJson'
htmlFile='{}.html'.format(self.createFileName(issue,useLabel=True))
gen_Html = self.root_dir+htmlFile
gen_Html = 'docs/{}.html'.format(issue.labels[0].name)
else:
listJsonName='postListJson'
htmlFile='{}.html'.format(self.createFileName(issue))
gen_Html = self.post_dir+htmlFile
gen_Html = self.post_dir+'{}.html'.format(Pinyin().get_pinyin(issue.title))
postNum="P"+str(issue.number)
self.blogBase[listJsonName][postNum]=json.loads('{}')
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]["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]["commentNum"]=issue.get_comments().totalCount
if issue.body==None:
self.blogBase[listJsonName][postNum]["description"]=''
self.blogBase[listJsonName][postNum]["wordCount"]=0
if self.blogBase["i18n"]=="CN":
period=""
else:
self.blogBase[listJsonName][postNum]["wordCount"]=len(issue.body)
if self.blogBase["rssSplit"]=="sentence":
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
period="."
self.blogBase[listJsonName][postNum]["description"]=issue.body.split(period)[0]+period
self.blogBase[listJsonName][postNum]["top"]=0
for event in issue.get_events():
if event.event=="pinned":
self.blogBase[listJsonName][postNum]["top"]=1
break
elif event.event=="unpinned":
self.blogBase[listJsonName][postNum]["top"]=0
break
try:
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"]
else:
self.blogBase[listJsonName][postNum]["createdAt"]=int(time.mktime(issue.created_at.timetuple()))
if "style" in postConfig:
self.blogBase[listJsonName][postNum]["style"]=self.blogBase["style"]+str(postConfig["style"])
self.blogBase[listJsonName][postNum]["style"]=str(postConfig["style"])
else:
self.blogBase[listJsonName][postNum]["style"]=self.blogBase["style"]
self.blogBase[listJsonName][postNum]["style"]=""
if "script" in postConfig:
self.blogBase[listJsonName][postNum]["script"]=self.blogBase["script"]+str(postConfig["script"])
self.blogBase[listJsonName][postNum]["script"]=str(postConfig["script"])
else:
self.blogBase[listJsonName][postNum]["script"]=self.blogBase["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"]
self.blogBase[listJsonName][postNum]["script"]=""
thisTime=datetime.datetime.fromtimestamp(self.blogBase[listJsonName][postNum]["createdAt"])
thisTime=thisTime.astimezone(self.TZ)
thisYear=thisTime.year
self.blogBase[listJsonName][postNum]["createdDate"]=thisTime.strftime("%Y-%m-%d")
self.blogBase[listJsonName][postNum]["dateLabelColor"]=self.blogBase["yearColorList"][int(thisYear)%len(self.blogBase["yearColorList"])]
mdFileName=re.sub(r'[<>:/\\|?*\"]|[\0-\31]', '-', issue.title)
f = open(self.backup_dir+mdFileName+".md", 'w', encoding='UTF-8')
if issue.body==None:
f.write('')
else:
f.write(issue.body)
f = open("backup/"+issue.title+".md", 'w', encoding='UTF-8')
f.write(issue.body)
f.close()
return listJsonName
def runAll(self):
print("====== start create static html ======")
@ -422,28 +264,11 @@ class GMEEK():
def runOne(self,number_str):
print("====== start create static html ======")
issue=self.repo.get_issue(int(number_str))
if issue.state == "open":
listJsonName=self.addOnePostJson(issue)
self.createPostHtml(self.blogBase[listJsonName]["P"+number_str])
self.createPlistHtml()
self.createFeedXml()
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
self.addOnePostJson(issue)
self.createPostHtml(self.blogBase["postListJson"]["P"+number_str])
self.createPlistHtml()
self.createFeedXml()
print("====== create static html end ======")
######################################################################################
parser = argparse.ArgumentParser()
@ -458,68 +283,17 @@ if not os.path.exists("blogBase.json"):
print("blogBase is not exists, runAll")
blog.runAll()
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=="":
print("issue_number=='0', runAll")
blog.runAll()
else:
f=open("blogBase.json","r")
print("blogBase is exists and issue_number!=0, runOne")
oldBlogBase=json.loads(f.read())
for key, value in oldBlogBase.items():
blog.blogBase[key] = value
blog.blogBase=json.loads(f.read())
f.close()
blog.blogBase["labelColorDict"]=blog.labelColorDict
blog.runOne(options.issue_number)
listFile=open("blogBase.json","w")
listFile.write(json.dumps(blog.blogBase))
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
View File

@ -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.

View File

@ -1,20 +1,18 @@
**[简体中文](README.md)** | **English** | **[Русский](README-ru.md)**
**[简体中文](README.md)** | **English**
# 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/)
- [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)
![dark](img/dark.jpg)
### 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.
2. In the repository `Settings`, select `Github Actions` in `Pages->Build and deployment->Source`.
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
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.
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
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/)
### Thanks
- [jinja2](https://jinja.palletsprojects.com/)
- [utteranc.es](https://utteranc.es/)
- [primer.style](https://primer.style/css)
- [gitblog](https://github.com/yihong0618/gitblog)

View File

@ -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)
![dark](img/dark.jpg)
### Установка
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)

View File

@ -1,31 +1,21 @@
**简体中文** | **[English](README-en.md)** | **[Русский](README-ru.md)**
**简体中文** | **[English](README-en.md)**
# Gmeek
一个博客框架,超轻量级个人博客模板。完全基于`Github Pages` 、 `Github Issues``Github Actions`。不需要本地部署,从搭建到写作,只需要18秒2步搭建好博客第3步就是写作。
一个博客框架,超轻量级个人博客模板。完全基于`Github Pages` 、 `Github Issues``Github Actions`。不需要本地部署,从搭建到写作,只需要几分钟的时间3步搭建好博客第4步就是写作。
- [Demo页面](http://meekdai.github.io/)
- [Gmeek更新日志](https://meekdai.github.io/post/Gmeek-geng-xin-ri-zhi.html)
- [Gmeek快速上手](https://blog.meekdai.com/post/Gmeek-kuai-su-shang-shou.html)
- [更新日志](https://meekdai.github.io/post/Gmeek-geng-xin-ri-zhi.html)
![light](img/light.jpg)
### 安装
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`。
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`后,我会帮忙查看构建流程,定位问题出处。
如果有问题可在本仓库提交[Issues](https://github.com/Meekdai/Gmeek/issues) 或者添加 QQ`294977308`
### 特性
@ -34,11 +24,34 @@
- 评论系统引入[utteranc.es](https://utteranc.es/)
- 使用`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`即可。
如果本项目对你有帮助,可以用微信赞赏一下作者,让项目有继续更新维护下去的动力,谢谢!
![赞赏码](img/赞赏码.jpg)
### 鸣谢
- [jinja2](https://jinja.palletsprojects.com/)
@ -49,4 +62,3 @@
### License
请保留页面底部和console界面版权信息谢谢

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -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");
});

View File

@ -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");
});

View File

@ -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");
});

View File

@ -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");
});

View File

@ -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();
}
});
});

View File

@ -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 = '&#10094;';
this.nextButton = document.createElement('button');
this.nextButton.className = 'lb-lightbox-nav lb-lightbox-next';
this.nextButton.innerHTML = '&#10095;';
this.closeButton = document.createElement('button');
this.closeButton.className = 'lb-lightbox-close';
this.closeButton.innerHTML = '&times;';
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();
});
})();

View File

@ -3,4 +3,3 @@ requests
xpinyin
feedgen
Jinja2
transliterate

View File

@ -1,22 +1,32 @@
<!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>
<meta content="text/html; charset=utf-8" http-equiv="content-type" />
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
{{ blogBase['primerCSS'] }}
{{ blogBase['allHead'] }}
<link href="//cdn.staticfile.org/Primer/21.0.7/primer.css" rel="stylesheet" />
<link rel="icon" href="{{ blogBase['faviconUrl'] }}">
{%- if blogBase['themeMode']=='manual' -%}
<script>
let theme = localStorage.getItem("meek_theme") || "light";
document.documentElement.setAttribute("data-color-mode", theme);
if(localStorage.getItem("meek_theme")==null){}
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>
{%- endif -%}
{% block head %}{% endblock %}
</head>
<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;}
#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>
var IconList={{ IconList }};
var utterancesLoad=0;
{% if blogBase['themeMode']=='manual' %}
let themeSettings={
"dark": ["dark","moon","#00f0ff","dark-blue"],
"light": ["light","sun","#ff5000","github-light"],
"auto": ["auto","sync","","preferred-color-scheme"]
};
function changeTheme(mode, icon, color, utheme){
document.documentElement.setAttribute("data-color-mode",mode);
document.getElementById("themeSwitch").setAttribute("d",value=IconList[icon]);
document.getElementById("themeSwitch").parentNode.style.color=color;
if(utterancesLoad==1){utterancesTheme(utheme);}
if(localStorage.getItem("meek_theme")==null){localStorage.setItem("meek_theme","light");changeLight();}
else if(localStorage.getItem("meek_theme")=="dark"){changeDark();}
else if(localStorage.getItem("meek_theme")=="light"){changeLight();}
function changeDark(){
document.getElementsByTagName("html")[0].attributes.getNamedItem("data-color-mode").value="dark";
document.getElementById("themeSwitch").setAttribute("d",value=IconList["moon"]);
document.getElementById("themeSwitch").parentNode.style.color="#00f0ff";
if(utterancesLoad==1){utterancesTheme("dark-blue");}
}
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(){
let currentMode=document.documentElement.getAttribute('data-color-mode');
let newMode = currentMode === "light" ? "dark" : currentMode === "dark" ? "auto" : "light";
localStorage.setItem("meek_theme", newMode);
if(themeSettings[newMode]){
changeTheme(...themeSettings[newMode]);
}
if(document.getElementsByTagName("html")[0].attributes[0].value=="light"){changeDark();localStorage.setItem("meek_theme","dark");}
else{changeLight();localStorage.setItem("meek_theme","light");}
}
function utterancesTheme(theme){
const message={type:'set-theme',theme: theme};
const iframe=document.getElementsByClassName('utterances-frame')[0];
iframe.contentWindow.postMessage(message,'https://utteranc.es');
const message = {type: 'set-theme',theme: theme};
const iframe = document.getElementsByClassName('utterances-frame')[0];
iframe.contentWindow.postMessage(message, 'https://utteranc.es');
}
if(themeSettings[theme]){changeTheme(...themeSettings[theme]);}
{%- endif %}
console.log("\n %c Gmeek {{ blogBase['GMEEK_VERSION'] }} https://github.com/Meekdai/Gmeek \n","padding:5px 0;background:#02d81d;color:#fff");
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;");
</script>
{% block script %}{% endblock %}
</html>

View File

@ -1,19 +1,14 @@
<div id="footer1">Copyright © <span id="copyrightYear"></span> <a href="{{ blogBase['homeUrl'] }}">{{ blogBase['title'] }}</a></div>
<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>
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>
<script>
var now=new Date();
document.getElementById("copyrightYear").innerHTML=now.getFullYear();
if("{{ blogBase['startSite'] }}"!=""){
var now=new Date();
var startSite=new Date("{{ blogBase['startSite'] }}");
var diff=now.getTime()-startSite.getTime();
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>

View File

@ -1,81 +1,67 @@
{% extends 'base.html' %}
{% 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>
{% endblock %}
{% block style %}
<style>
.avatar {transition: 0.8s;width:64px;height:64px;object-fit: cover;}
.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;}
h1 a:not([href]){color:inherit;text-decoration:none;vertical-align: bottom;font-size:40px;font-family:Monaco;}
.title-right{display:flex;margin:auto 0 0 auto;}
.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;}
.SideNav{min-width: 360px;}
.SideNav-icon{margin-right: 16px}
.SideNav-item .Label{color: #fff;margin-left:4px;}
.d-flex{min-width:0;}
.listTitle{overflow:hidden;white-space:nowrap;text-overflow: ellipsis;max-width: 100%;}
.listLabels{white-space:nowrap;display:flex;}
.listLabels object{max-height:16px;max-width:24px;}
@media (max-width: 600px) {
body {padding: 8px;}
.avatar {width:40px;height:40px;}
.blogTitle{display:none;}
.SideNav-item .Label{color: #fff;margin-left:8px;}
@media (max-width: 767px) {
body { padding: 8px;}
h1 a:not([href]){font-size:24px;}
.subnav-search form{display:none;}
.subnav-search svg{display:none;}
#buttonRSS{display:none;}
.LabelTime{display:none;}
.SideNav-item .listLabels{display:none;}
}
</style>
{{ blogBase['indexStyle'] }}
{% endblock %}
{% block header %}
<div class="title-left">
<img src="{{ blogBase['avatarUrl'] }}" class="avatar circle" id="avatarImg" alt="avatar">
{%- if blogBase['displayTitle']=='Meekdai' -%}
<a class="blogTitle" href="https://meekdai.com"><span style="font-size:0;">M</span>eekdai</a>
{% else -%}
<a class="blogTitle">{{ blogBase['displayTitle'] }}</a>
{%- endif -%}
</div>
<h1>
<img src="{{ blogBase['avatarUrl'] }}" size="64" height="64" width="64" class="avatar circle" id="avatarImg">
<a>{{ blogBase['displayTitle'] }}</a>
</h1>
<div class="title-right">
<a href="{{ blogBase['homeUrl'] }}/tag.html" id="buttonSearch" class="btn btn-invisible circle" title="{{ i18n['Search'] }}">
<svg class="octicon" width="16" height="16" >
<path id="pathSearch" fill-rule="evenodd"></path>
<div class="subnav-search">
<form action="https://www.google.com/search" method="get" target="_blank">
<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>
</a>
{% 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 %}
</div>
{% 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" >
<path id="{{ blogBase['singeListJson'][num]['postTitle'] }}" fill-rule="evenodd"></path>
</svg>
</a>
</button></a>
{%- 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" >
<path id="pathRSS" 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 -%}>
</button></a>
<button class="btn btn-invisible circle" onclick="modeSwitch()" title="{{ i18n['switchTheme'] }}">
<svg class="octicon" width="16" height="16" >
<path id="themeSwitch" fill-rule="evenodd"></path>
</svg>
</a>
</button>
</div>
{% endblock %}
@ -87,14 +73,12 @@
<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>
<span class="listTitle">{{ postListJson[num]['postTitle']|e }}</span>
<span>{{ postListJson[num]['postTitle']|e }}</span>
</div>
<div class="listLabels">
{% 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 LabelName" style="background-color:{{ blogBase['labelColorDict'][label] }}"><object><a style="color:#fff" href="tag.html#{{ label }}">{{ label }}</a></object></span>
{%- endfor %}
<span class="Label LabelTime" style="background-color:{{ postListJson[num]['dateLabelColor'] }}">{{ postListJson[num]['createdDate'] }}</span>
<span class="Label" style="background-color:{{ postListJson[num]['labelColor'] }}">{{ postListJson[num]['label'] }}</span>
<span class="Label" style="background-color:{{ postListJson[num]['dateLabelColor'] }}">{{ postListJson[num]['createdDate'] }}</span>
</div>
</a>
{%- endfor %}
@ -105,13 +89,13 @@
{%- if blogBase['prevUrl']=='disabled' -%}
<span class="previous_page" aria-disabled="true">{{ i18n['Previous'] }}</span>
{% 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 -%}
{%- if blogBase['nextUrl']=='disabled' -%}
<span class="next_page" aria-disabled="true">{{ i18n['Next'] }}</span>
{% 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 -%}
</div>
@ -121,7 +105,7 @@
{% block script %}
<script>
document.getElementById("pathSearch").setAttribute("d",IconList["search"]);
document.getElementById("searchSVG").setAttribute("d",IconList["search"]);
document.getElementById("pathRSS").setAttribute("d",IconList["rss"]);
iconTOP=document.getElementsByClassName("svgTop1");
iconPost=document.getElementsByClassName("svgTop0");
@ -133,13 +117,8 @@ for(var i=0;i<iconPost.length;i++){
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'] -%}
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 %}
</script>
{{ blogBase['indexScript'] }}
{% endblock %}

View File

@ -1,20 +1,13 @@
{% extends 'base.html' %}
{% 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>
{% if blogBase['highlight']==1 %}<link href="//unpkg.com/@wooorm/starry-night@2.1.1/style/both.css" rel="stylesheet" />{% endif %}
{{ blogBase['head'] }}
<link href="//unpkg.com/@wooorm/starry-night@2.1.1/style/both.css" rel="stylesheet" />
{% endblock %}
{% block 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 .circle{padding: 14px 16px;margin-right:8px;}
#postBody{border-bottom: 1px solid var(--color-border-default);padding-bottom:36px;}
@ -22,64 +15,49 @@
#cmButton{height:48px;margin-top:48px;}
#comments{margin-top:64px;}
.g-emoji{font-size:24px;}
@media (max-width: 600px) {
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 %}
@media (max-width: 767px) {body {padding: 8px;}}
</style>
{{ blogBase['style'] }}
{% endblock %}
{% block header %}
<h1 class="postTitle">{{ blogBase['postTitle'] }}</h1>
<h1>
<a>{{ blogBase['postTitle'] }}</a>
</h1>
<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" >
<path id="themeSwitch" fill-rule="evenodd"></path>
</svg>
</a>
</button>
</div>
{% endblock %}
{% block content %}
<div class="markdown-body" id="postBody">{{ blogBase['postBody'] }}</div>
<div style="font-size:small;margin-top:8px;float:right;">{{ blogBase['bottomText'] }}</div>
{% if blogBase['needComment']==1 %}
<div class="markdown-body" id="postBody">
{{ blogBase['postBody'] }}
</div>
<button class="btn btn-block" type="button" onclick="openComments()" id="cmButton">{{ i18n['comments'] }}</button>
<div class="comments" id="comments"></div>
{% endif %}
{% endblock %}
{% block 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 -%}
cmButton=document.getElementById("cmButton");
span=document.createElement("span");
@ -88,7 +66,6 @@ document.getElementById("pathHome").setAttribute("d",IconList["home"]);
cmButton.appendChild(span);
{%- endif %}
{% if blogBase['needComment']==1 %}
function openComments(){
cm=document.getElementById("comments");
cmButton=document.getElementById("cmButton");
@ -101,13 +78,8 @@ function openComments(){
script.setAttribute("src","https://utteranc.es/client.js");
script.setAttribute("repo","{{ blogBase['repoName'] }}");
script.setAttribute("issue-term","title");
{% if blogBase['themeMode']=='manual' %}
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","preferred-color-scheme");}
{% else %}
script.setAttribute("theme","{{ blogBase['nightTheme'] }}");
{% endif %}
else{script.setAttribute("theme","github-light");}
script.setAttribute("crossorigin","anonymous");
script.setAttribute("async","");
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>
{{ blogBase['script'] }}
{% endblock %}

View File

@ -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="&nbsp;&nbsp;"+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 %}