Compare commits

..

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

16 changed files with 210 additions and 1222 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

214
Gmeek.py
View File

@ -8,18 +8,16 @@ 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":"下一页"}
i18nRU={"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 +27,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 +35,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
@ -54,16 +48,10 @@ class GMEEK():
for label in self.repo.get_labels():
self.labelColorDict[label.name]='#'+label.color
print(self.labelColorDict)
self.defaultConfig()
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,40 +62,20 @@ 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":""}
dconfig={"singlePage":[],"startSite":"","filingNum":"","onePageListNum":15,"commentLabelColor":"#006b75","yearColorList":["#bc4c00", "#0969da", "#1f883d", "#A333D0"],"i18n":"CN","dayTheme":"light","nightTheme":"dark","urlMode":"pinyin","script":"","style":"","bottomText":"","showPostSource":1,"UTC":+8}
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():
if str(self.repo.name) == (str(self.repo.owner.login)+".github.io"):
self.blogBase["homeUrl"] = f"https://{self.repo.name}"
else:
self.blogBase["homeUrl"] = f"https://{self.repo.owner.login}.github.io/{self.repo.name}"
@ -135,18 +103,17 @@ class GMEEK():
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')
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()
@ -155,67 +122,30 @@ class GMEEK():
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["script"]=postBase["script"]+'<script async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>'
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["script"]=postBase["script"]+issue["script"]
postBase["top"]=issue["top"]
postBase["postSourceUrl"]=issue["postSourceUrl"]
postBase["repoName"]=options.repo_name
if issue["labels"][0] in self.blogBase["singlePage"]:
if "highlight" in post_body:
postBase["highlight"]=1
else:
postBase["highlight"]=0
if issue["label"] 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 +167,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,12 +185,12 @@ 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)
self.renderHtml('tag.html',self.blogBase,onePageList,self.root_dir+"tag.html")
print("create tag.html")
def createFeedXml(self):
@ -277,10 +207,10 @@ class GMEEK():
for num in self.blogBase["singeListJson"]:
item=feed.add_item()
item.guid(self.blogBase["homeUrl"]+"/"+self.blogBase["singeListJson"][num]["postUrl"],permalink=True)
item.guid(self.blogBase["homeUrl"]+"/"+self.blogBase["singeListJson"][num]["label"]+".html",permalink=True)
item.title(self.blogBase["singeListJson"][num]["postTitle"])
item.description(self.blogBase["singeListJson"][num]["description"])
item.link(href=self.blogBase["homeUrl"]+"/"+self.blogBase["singeListJson"][num]["postUrl"])
item.link(href=self.blogBase["homeUrl"]+"/"+self.blogBase["singeListJson"][num]["label"]+".html")
item.pubDate(time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(self.blogBase["singeListJson"][num]["createdAt"])))
for num in self.blogBase["postListJson"]:
@ -312,39 +242,43 @@ class GMEEK():
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 = self.root_dir+'{}.html'.format(issue.labels[0].name)
else:
listJsonName='postListJson'
htmlFile='{}.html'.format(self.createFileName(issue))
gen_Html = self.post_dir+htmlFile
if self.blogBase["urlMode"]=="issue":
gen_Html = self.post_dir+'{}.html'.format(str(issue.number))
elif self.blogBase["urlMode"]=="ru_translit":
gen_Html = self.post_dir+'{}.html'.format(str(translit(issue.title, language_code='ru', reversed=True)).replace(' ', '-'))
else:
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):])
if self.blogBase["urlMode"]=="issue":
self.blogBase[listJsonName][postNum]["postUrl"]=urllib.parse.quote(self.post_folder+'{}.html'.format(str(issue.number)))
elif self.blogBase["urlMode"]=="ru_translit":
self.blogBase[listJsonName][postNum]["postUrl"]=urllib.parse.quote(self.post_folder+'{}.html'.format(str(translit(issue.title, language_code='ru', reversed=True)).replace(' ', '-')))
else:
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
self.blogBase[listJsonName][postNum]["wordCount"]=len(issue.body)
if self.blogBase["i18n"]=="CN":
period=""
else:
period="."
if issue.body==None:
self.blogBase[listJsonName][postNum]["description"]=''
self.blogBase[listJsonName][postNum]["wordCount"]=0
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
self.blogBase[listJsonName][postNum]["description"]=issue.body.split(period)[0]+period
self.blogBase[listJsonName][postNum]["top"]=0
for event in issue.get_events():
@ -375,15 +309,6 @@ class GMEEK():
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"]
thisTime=datetime.datetime.fromtimestamp(self.blogBase[listJsonName][postNum]["createdAt"])
thisTime=thisTime.astimezone(self.TZ)
@ -391,8 +316,7 @@ class GMEEK():
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')
f = open("backup/"+issue.title+".md", 'w', encoding='UTF-8')
if issue.body==None:
f.write('')
@ -422,28 +346,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
listJsonName=self.addOnePostJson(issue)
self.createPostHtml(self.blogBase[listJsonName]["P"+number_str])
self.createPlistHtml()
self.createFeedXml()
print("====== create static html end ======")
######################################################################################
parser = argparse.ArgumentParser()
@ -468,11 +375,8 @@ else:
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")
@ -491,10 +395,6 @@ for i in blog.blogBase["postListJson"]:
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"]
@ -504,8 +404,6 @@ for i in blog.blogBase["postListJson"]:
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()
@ -514,7 +412,7 @@ 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+"### :page_facing_up: [%d](%s/tag.html) \r\n" % (len(blog.blogBase["postListJson"]),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')

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

@ -13,19 +13,18 @@
1. 【创建仓库】点击[通过模板创建仓库](https://github.com/new?template_name=Gmeek-template&template_owner=Meekdai),建议仓库名称为`XXX.github.io`,其中`XXX`为你的github用户名。
2. 【启用Pages】在仓库的`Settings`中`Pages->Build and deployment->Source`下面选择`Github Actions`。
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->里面的按钮全局重新生成一次
```
3. 【开始写作】打开一篇issue开始写作并且添加一个标签保存issue后会自动创建博客内容片刻后可通过https://XXX.github.io 访问
### 提交问题
1. 如果有问题可参考[Gmeek快速上手](https://blog.meekdai.com/post/Gmeek-kuai-su-shang-shou.html)
2. 在本仓库提交[Issues](https://github.com/Meekdai/Gmeek/issues)之前,请手动全局生成一次。如果还有错误,提交`Issues`后,我会帮忙查看构建流程,定位问题出处。
3. 手动全局生成一次方法:
```
通过Actions->build Gmeek->Run workflow->里面的按钮全局重新生成一次
```
### 特性
@ -34,12 +33,6 @@
- 评论系统引入[utteranc.es](https://utteranc.es/)
- 使用`jinja2`对html进行渲染可通过模板自定义UI主题
### 赞赏
如果本项目对你有帮助,可以用微信赞赏一下作者,让项目有继续更新维护下去的动力,谢谢!
![赞赏码](img/赞赏码.jpg)
### 鸣谢
- [jinja2](https://jinja.palletsprojects.com/)
- [utteranc.es](https://utteranc.es/)
@ -49,4 +42,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

@ -4,15 +4,13 @@
<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>
@ -31,34 +29,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,20 @@
<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>
{%- if blogBase['filingNum']!='' -%}
<a href="https://beian.miit.gov.cn/" target="_blank">{{ blogBase['filingNum'] }}</a>
{%- endif %}
<span id="runday"></span>Powered by <a href="https://meekdai.com/Gmeek.html" 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,11 +1,6 @@
{% 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 %}
@ -13,17 +8,17 @@
<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;}
#header h1 a{color:inherit;text-decoration:none;vertical-align: bottom;font-size:40px;font-family:Monaco;margin-left:8px;}
.title-right{display:flex;margin:auto 0 0 auto;}
.title-right button{margin-right:8px;padding:16px;}
.title-right .circle{padding: 14px 16px;}
.SideNav{min-width: 360px;}
.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;}
.listTitle{overflow:hidden;white-space:nowrap;text-overflow: ellipsis;max-width: 100%;}
.listLabels{white-space:nowrap;display:flex;}
.listLabels{white-space:nowrap;}
.listLabels object{max-height:16px;max-width:24px;}
@media (max-width: 600px) {
@ -34,48 +29,40 @@
.LabelTime{display:none;}
}
</style>
{{ blogBase['indexStyle'] }}
{% endblock %}
{% block header %}
<div class="title-left">
<h1>
<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>
{%- if blogBase['displayTitle']=='eekdai' -%}
<a class="blogTitle" href="https://meekdai.com">{{ blogBase['displayTitle'] }}</a>
{% else -%}
<a class="blogTitle">{{ blogBase['displayTitle'] }}</a>
{%- endif -%}
</div>
</h1>
<div class="title-right">
<a href="{{ blogBase['homeUrl'] }}/tag.html" id="buttonSearch" class="btn btn-invisible circle" title="{{ i18n['Search'] }}">
<a href="{{ blogBase['homeUrl'] }}/tag.html"><button id="buttonSearch" class="btn btn-invisible circle" title="{{ i18n['Search'] }}">
<svg class="octicon" width="16" height="16" >
<path id="pathSearch" fill-rule="evenodd"></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 %}
</button></a>
{% 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['homeUrl'] }}/{{ 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="{{ blogBase['homeUrl'] }}/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 %}
@ -91,9 +78,7 @@
</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 LabelName" style="background-color:{{ postListJson[num]['labelColor'] }}"><object><a style="color:#fff" href="{{ blogBase['homeUrl'] }}/tag.html#{{ postListJson[num]['label'] }}">{{ postListJson[num]['label'] }}</a></object></span>
<span class="Label LabelTime" style="background-color:{{ postListJson[num]['dateLabelColor'] }}">{{ postListJson[num]['createdDate'] }}</span>
</div>
</a>
@ -133,13 +118,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,15 +1,9 @@
{% 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'] }}">
<meta name="description" content="{{ blogBase['postTitle'] }}">
<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'] }}
{% endblock %}
{% block style %}
@ -26,18 +20,6 @@
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>
{{ blogBase['style'] }}
@ -45,24 +27,26 @@
{% block header %}
<h1 class="postTitle">{{ blogBase['postTitle'] }}</h1>
<div class="title-right">
<a href="{{ blogBase['homeUrl'] }}" id="buttonHome" class="btn btn-invisible circle" title="{{ i18n['home'] }}">
<a href="{{ blogBase['homeUrl'] }}"><button id="buttonHome" class="btn btn-invisible circle" title="{{ i18n['home'] }}">
<svg class="octicon" width="16" height="16">
<path id="pathHome" fill-rule="evenodd"></path>
<path id="pathHome" fill-rule="evenodd" d="{{ IconList['home'] }}"></path>
</svg>
</a>
</button></a>
{% if blogBase['showPostSource']==1 %}
<a href="{{ blogBase['postSourceUrl'] }}" target="_blank" class="btn btn-invisible circle" title="Issue">
<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"></path>
<path id="pathIssue" fill-rule="evenodd" d="{{ IconList['github'] }}"></path>
</svg>
</a>
</button></a>
{% endif %}
<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" >
<path id="themeSwitch" fill-rule="evenodd"></path>
</svg>
</a>
</button>
</div>
{% endblock %}
@ -70,16 +54,13 @@
{% 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 %}
<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 +69,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 +81,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 +101,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

@ -14,11 +14,8 @@
.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)}
.SideNav-icon{margin-right: 16px}
.Label{color: #fff;margin-left:8px;}
.genTime{float: right;}
.d-flex{min-width:0;}
.listTitle{overflow:hidden;white-space:nowrap;text-overflow: ellipsis;max-width: 100%;}
@ -39,35 +36,33 @@
<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>
<path id="searchSVG" fill-rule="evenodd" d=""></path>
</svg>
</div>
<a href="{{ blogBase['homeUrl'] }}" id="buttonHome" class="btn btn-invisible circle" title="{{ i18n['home'] }}">
<a href="{{ blogBase['homeUrl'] }}"><button id="buttonHome" class="btn btn-invisible circle" title="{{ i18n['home'] }}">
<svg class="octicon" width="16" height="16">
<path id="pathHome" fill-rule="evenodd"></path>
<path id="pathHome" fill-rule="evenodd" d="{{ IconList['home'] }}"></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 %}
{% block content %}
<div id="taglabel" style="margin-bottom:8px;"></div>
<div id="tagLable" style="margin-bottom: 16px;"></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();
@ -77,88 +72,74 @@ request.send();
request.onload=function(){
jsonData=JSON.parse(request.response);
console.log(jsonData);
showList(labelsCount);
showList();
setClassDisplay(decodeURI(window.location.hash.slice(1)));
}
function showList(labelsCount){
function showList(){
let SideNav=document.getElementsByClassName("SideNav")[0];
SideNav.classList.add("border");
let taglabel=document.getElementById("taglabel");
SideNav.setAttribute("class","SideNav border");
let tagLable=document.getElementById("tagLable");
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;
}
}
if(tagList.length==0){
let showLabels=document.createElement("button");
showLabels.setAttribute("class","Label");
showLabels.setAttribute("style","background-color:#000");
showLabels.innerHTML="All";
showLabels.setAttribute("onclick","javascript:updateShowTag('All');");
tagLable.appendChild(showLabels);
}
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);
if(!(tagList.includes(jsonData[i]['label']))){
tagList.push(jsonData[i]['label']);
let showLabels=document.createElement("button");
showLabels.setAttribute("class","Label");
showLabels.setAttribute("style","background-color:"+jsonData[i]['labelColor']);
showLabels.innerHTML=jsonData[i]['label'];
showLabels.setAttribute("onclick","javascript:updateShowTag('"+jsonData[i]['label']+"');");
tagLable.appendChild(showLabels);
}
let div=document.createElement("div");
div.setAttribute("class","lists "+jsonData[i]['label']);
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","witdh: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");
let LabelName=document.createElement("span");
LabelName.setAttribute("class","Label LabelName");
LabelName.setAttribute("style","background-color:"+jsonData[i]['labelColor']);
LabelName.innerHTML=jsonData[i]['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);
}
}
@ -169,29 +150,29 @@ function updateShowTag(label){
}
}
function setClassDisplay(label){
function setClassDisplay(lable){
let lists = document.getElementsByClassName("lists");
let tagTitle = document.getElementsByClassName("tagTitle")[0];
tagTitle.innerHTML="Tag #"+label;
document.title=label+" - {{ blogBase['title'] }}";
tagTitle.innerHTML="Tag #"+lable;
document.title=lable+" - {{ blogBase['title'] }}";
document.getElementsByClassName("subnav-search-input")[0].value='';
if(label=="All"){
if(lable=="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){
else if(tagList.indexOf(lable)!=-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';
let lables = document.getElementsByClassName(lable);
for(let i = 0; i < lables.length; i++){
lables[i].style.display='block';
}
document.getElementsByClassName("notFind")[0].style.display='none';
}
else{
document.getElementsByClassName("subnav-search-input")[0].value=label;
document.getElementsByClassName("subnav-search-input")[0].value=lable;
searchShow();
}
}