Compare commits

...

266 Commits
v2.3 ... main

Author SHA1 Message Date
Meekdai
35263fd99d 修改首页h1标签为div 2024-08-16 12:07:27 +08:00
Meekdai
f7ea52be7f 修复关闭状态的issue编辑后会被抓取的BUG 2024-08-15 18:19:40 +08:00
Meekdai
8beb6d388a Update plist.html 2024-08-14 14:15:36 +08:00
Meekdai
9f02e2620b Update post.html 2024-08-11 22:17:33 +08:00
Meekdai
6722f61728 Update GmeekTOC.js 2024-08-06 18:41:23 +08:00
Meekdai
2e78ea21dc Update GmeekTOC.js 2024-08-06 17:11:16 +08:00
Meekdai
f2916398ce 添加代码复制按钮 2024-08-02 16:45:35 +08:00
Meekdai
1ff10bc070 Update GmeekVercount.js 2024-07-31 08:53:37 +08:00
Meekdai
82cd2aee91 Create GmeekVercount.js 2024-07-31 08:50:28 +08:00
Meekdai
15d5ea1e7d 如果文章中没有标题属性,则不创建TOC 2024-07-29 10:15:23 +08:00
Meekdai
f733212c4b
Merge pull request #157 from tiengming/patch-1
Update lightbox.js
2024-07-26 20:46:27 +08:00
tiengming
841223f4f3
Update lightbox.js
1. 对于超大图完全显示
2. 按住ctrl+鼠标滚轮实现缩放。
3. 优化表格内图片显示不全问题。
4. 透明背景+高斯模糊,实现兼容不同主题。
2024-07-26 08:23:59 +08:00
Meekdai
72df0007a9 修复新增label无颜色的BUG 2024-07-25 16:40:16 +08:00
Meekdai
1efcf279d5
Merge pull request #151 from tiengming/main
新增灯箱插件
2024-07-24 22:29:08 +08:00
Meekdai
ee38206dbb
Update static.yml 2024-07-24 22:23:45 +08:00
Meekdai
b3ad18e700
Update static.yml 2024-07-24 22:18:36 +08:00
Meekdai
94fbc885b4
Update static.yml 2024-07-24 22:17:32 +08:00
Meekdai
caeccdb4ce
Update static.yml 2024-07-24 22:14:19 +08:00
Meekdai
5016b545de
Update static.yml 2024-07-24 22:05:43 +08:00
Meekdai
fb5cedb23e
Create static.yml 2024-07-24 21:56:40 +08:00
tiengming
a2daa78448
Update lightbox.js 2024-07-24 19:24:43 +08:00
tiengming
a2e40e84d4
Create lightbox.js
来个灯箱插件,预览看看:https://code.buxiantang.top/post/ji-yu-CloudFlare%20workers-ying-yong-jin-xing-AI-hui-tu.html
2024-07-24 19:09:30 +08:00
Meekdai
0e2ba5db7a 添加修改一些TOC插件 2024-07-24 14:55:37 +08:00
Meekdai
148a6aaf78 Update Gmeek.py 2024-07-19 15:40:24 +08:00
Meekdai
30e09c6aab 添加head配置,用于配置自定义文章页head内容 2024-07-19 15:17:21 +08:00
Meekdai
a23cfe26be 添加allHead配置,用于自定义所有页面的head标签 2024-07-19 15:06:27 +08:00
Meekdai
1bb985b92e 优化底部信息 2024-07-19 14:41:03 +08:00
Meekdai
39ae055491 添加不蒜子插件 2024-07-19 14:29:14 +08:00
Meekdai
ffd230c109 修复只有标题没有文章内容导致的获取字数失败的BUG 2024-07-11 09:15:58 +08:00
Meekdai
bd7ec11c32 修改底部a标签空格的BUG 2024-07-06 21:25:36 +08:00
Meekdai
0841323a0d Update GmeekTOC.js 2024-07-03 18:31:27 +08:00
Meekdai
78ce8e048b Update GmeekTOC.js 2024-07-02 17:25:06 +08:00
Meekdai
6affa0c5e1 Create GmeekTOC.js 2024-07-02 16:07:39 +08:00
Meekdai
fdfbf2a42e Update Gmeek.py 2024-07-01 22:17:51 +08:00
Meekdai
600898f139 修改static文件拷贝策略 2024-07-01 22:12:28 +08:00
Meekdai
4d9fe5ac8f needComment用于配置是否需要评论功能 2024-07-01 16:49:30 +08:00
Meekdai
e93fd1b946 Update Gmeek.py 2024-07-01 16:42:20 +08:00
Meekdai
ad55a2b0c0 Update Gmeek.py 2024-07-01 16:39:12 +08:00
Meekdai
00574fa648 添加static文件夹,用于存放用户自定义文件 2024-07-01 16:29:46 +08:00
Meekdai
4341f82b5d Update Gmeek.py 2024-07-01 16:01:53 +08:00
Meekdai
f24c0743e9 Update Gmeek.py 2024-07-01 15:58:31 +08:00
Meekdai
49a4a46eb0 通过primerCSS自定义CDN的地址
默认使用南科大 https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/Primer/21.0.7/primer.css
2024-07-01 15:46:38 +08:00
Meekdai
9eaeb4ad9f Create LICENSE 2024-07-01 15:29:51 +08:00
Meekdai
8e6813fd7c Update Gmeek.py 2024-05-31 14:30:20 +08:00
Meekdai
4b25932edc Update Gmeek.py 2024-05-31 14:12:00 +08:00
Meekdai
7c3232fcb1 Update README.md 2024-05-30 16:20:38 +08:00
Meekdai
245d9af1ca change img 2024-05-30 16:16:33 +08:00
Meekdai
1ed8b84565 use html 2024-05-29 09:13:48 +08:00
Meekdai
1636f68819 Update Gmeek.py 2024-05-28 22:22:44 +08:00
Meekdai
f8fcd03fdb add beautifulsoup4 2024-05-28 22:19:03 +08:00
Meekdai
b3c7e297c4 Update Gmeek.py 2024-05-28 22:15:49 +08:00
Meekdai
61d2309b2a Update Gmeek.py 2024-05-28 21:42:03 +08:00
Meekdai
a7e4e685c0 Update Gmeek.py 2024-05-28 21:40:26 +08:00
Meekdai
88e434cb26 添加文章页自定义html标签
##{"html":""}##
2024-05-28 18:13:41 +08:00
Meekdai
be545404f2 Update Gmeek.py 2024-05-28 17:20:52 +08:00
Meekdai
e0c5923dcb 添加5种alerts功能样式
具体可参考下面的链接
https://docs.github.com/zh/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts
2024-05-28 17:16:53 +08:00
Meekdai
0cc2674a4d 添加赞赏码 2024-05-28 09:13:35 +08:00
Meekdai
52a9d3b67c 添加首页script和style自定义功能
通过indexScript和indexStyle来配置
2024-05-22 09:18:01 +08:00
Meekdai
8131149b55 修复文章description里包含双引号导致的BUG 2024-05-20 09:36:03 +08:00
Meekdai
039e785ef5 修复 width 拼写错误 2024-04-28 09:54:43 +08:00
Meekdai
03ee911f40
Update README.md 2024-04-10 14:28:56 +08:00
Meekdai
d7b5949340 修复仓库名称大小写敏感的BUG 2024-04-10 10:56:44 +08:00
Meekdai
aaf6d1670f ogImage字段添加到首页 2024-04-09 13:45:29 +08:00
Meekdai
98b8114b32 通过文章页自定义ogImage字段来配置分享预览图片
默认为avatarUrl
2024-04-09 13:28:50 +08:00
Meekdai
d2aff31483 og:image 2024-04-09 12:08:12 +08:00
Meekdai
4959661d0b og:image 2024-04-09 11:54:48 +08:00
Meekdai
d7f01816ba Update post.html 2024-04-09 11:22:54 +08:00
Meekdai
91dacffe12 添加Open Graph协议内容,让分享博客链接有预览 2024-04-09 09:57:37 +08:00
Meekdai
bd75753a73 Update plist.html 2024-04-07 14:07:31 +08:00
Meekdai
4132a239a7 优化配置文件读取,使得新添加不报错 2024-04-07 13:54:34 +08:00
Meekdai
79d8dfb086 自定义外部链接按钮 2024-04-07 13:38:45 +08:00
Meekdai
3f384abfbc 修复页面右上角圆形按钮超出边界还能点击的BUG 2024-04-07 11:56:19 +08:00
Meekdai
95e6fb3e25 修改主页标签间距 2024-04-07 11:35:16 +08:00
Meekdai
db0ccd2b5d 调整Tag页面样式 2024-04-07 10:54:57 +08:00
Meekdai
ae95ed6a82 Tag页面标签显示文章数量,并且以多到少排列 2024-04-07 10:39:06 +08:00
Meekdai
a32a663320 修复readme显示文章数量不对的BUG 2024-04-07 09:59:10 +08:00
Meekdai
0a1d0a8b94 😅 2024-04-03 17:41:06 +08:00
Meekdai
eeba5e0259 自动更新yml文件 2024-04-03 17:11:15 +08:00
Meekdai
2399aa660f MathJax行内公式删除括号 2024-04-03 14:28:25 +08:00
Meekdai
abaa9ea06e
Update README.md 2024-04-03 09:20:00 +08:00
Meekdai
ee4ab509a2
Update README.md 2024-04-03 09:18:59 +08:00
Meekdai
d741d46eec
Update README.md 2024-04-03 09:18:06 +08:00
Meekdai
887aaf4831
Update README.md 2024-04-02 21:47:14 +08:00
Meekdai
fbd85539e5 Update tag.html 2024-04-02 18:36:33 +08:00
Meekdai
2866af55b4 Update tag.html 2024-04-02 18:34:57 +08:00
Meekdai
668435a637 Update tag.html 2024-04-02 18:22:48 +08:00
Meekdai
d6f9b0804a Update tag.html 2024-04-02 18:10:52 +08:00
Meekdai
9def4814f9 Update tag.html 2024-04-02 18:07:39 +08:00
Meekdai
ddad57bc46 Update tag.html 2024-04-02 17:52:37 +08:00
Meekdai
11ce33e617 添加多label支持 2024-04-02 17:41:34 +08:00
Meekdai
38c90b9ab6 Update base.html 2024-04-02 16:34:40 +08:00
Meekdai
a2183cf4be Update post.html 2024-04-02 16:20:54 +08:00
Meekdai
a548882b31 精简changeTheme函数 2024-04-02 16:12:39 +08:00
Meekdai
a15d7932d9 Update base.html 2024-04-02 14:15:26 +08:00
Meekdai
fdce24ca68 Update base.html 2024-04-02 14:09:00 +08:00
Meekdai
f252d0f16e 通过themeMode配置主题模式修改
目前默认为manual,和固定主题fix
2024-04-02 14:01:54 +08:00
Meekdai
f184fd3b7a Update base.html 2024-04-02 11:51:32 +08:00
Meekdai
e5af352964 Update base.html 2024-04-02 11:49:12 +08:00
Meekdai
6e8e04c634 通过themeMode配置主题模式
目前默认为manual,另外可选跟随系统auto,和固定主题fix
2024-04-02 11:41:48 +08:00
Meekdai
5cebb6fd72 采用rssSplit用来自定义截取RSS输出
默认为sentence,为截取文章第一句话。
2024-04-02 10:02:29 +08:00
Meekdai
aa86583194 以有序的方式排列plistIcon 2024-04-02 09:45:11 +08:00
Meekdai
b9a47920db 标题带有不合法符号修复 2024-04-02 09:14:54 +08:00
Meekdai
725b96aa7e 通过rssMode来配置RSS输出第一句还是全文
rssMode默认配置为sentence,可以配置为all
2024-04-01 16:49:20 +08:00
Meekdai
c90f747ca6 Update Gmeek.py 2024-04-01 15:50:44 +08:00
Meekdai
9234c74350 Update Gmeek.py 2024-04-01 15:46:40 +08:00
Meekdai
eb406080f0 Update Gmeek.py 2024-04-01 15:22:09 +08:00
Meekdai
150e6f130f Update Gmeek.py 2024-04-01 15:15:13 +08:00
Meekdai
cfcd46f2a7 Update Gmeek.py 2024-04-01 15:09:55 +08:00
Meekdai
c65115c298 Update Gmeek.py 2024-04-01 14:57:05 +08:00
Meekdai
4b5d4d8674 Update Gmeek.py 2024-04-01 14:49:46 +08:00
Meekdai
698d8c1c4c Update Gmeek.py 2024-04-01 14:47:13 +08:00
Meekdai
a96474eb5f 修复由于修改文章标题导致旧文章依旧存在的BUG 2024-04-01 14:35:58 +08:00
Meekdai
222729c853 修复MathJax行内公式显示不正常的BUG 2024-04-01 14:12:24 +08:00
Meekdai
3fe6856fd6 about和link内置图标 2024-03-26 14:30:37 +08:00
Meekdai
8ec5cd7660 Update Gmeek.py 2024-03-26 12:06:29 +08:00
Meekdai
2520e643cd 修复全局script配置会在文章页出现2次的BUG 2024-03-26 11:00:38 +08:00
Meekdai
0e26eb37cc Update Gmeek.py 2024-03-26 10:48:32 +08:00
Meekdai
e940a34d36 添加自定义icon功能
"iconList":{"circle":"M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13Z","dash":"M2 7.75A.75.75 0 0 1 2.75 7h10a.75.75 0 0 1 0 1.5h-10A.75.75 0 0 1 2 7.75Z"},
2024-03-26 10:36:29 +08:00
Meekdai
ddb92e7ac1 删除不必要的i18n 2024-03-26 09:53:15 +08:00
Meekdai
ecb2d25dee tag页面删除冗余icon图标 2024-03-26 09:13:35 +08:00
Meekdai
fd81262713 修改staticfile.net
受org域名备案影响主域名更新为 staticfile.net , org老域名不再维护请用户尽快更换为net。
2024-03-25 17:55:37 +08:00
Meekdai
e37edc2af5 删除冗余icon地址 2024-03-25 17:28:58 +08:00
Meekdai
adb49e6f3f 全局script也包含到主页中 2024-03-25 17:26:17 +08:00
Meekdai
bf24312ca6
Update README.md 2024-03-25 12:01:48 +08:00
Meekdai
6f034169b1 Update README.md 2024-03-18 17:41:28 +08:00
Meekdai
6b97f811da Update README.md 2024-03-18 17:30:43 +08:00
Meekdai
f74498fc30 Update README.md 2024-03-14 17:25:09 +08:00
Meekdai
f62030696e 修复时区不同导致的日期显示错误问题 2024-03-14 14:36:40 +08:00
Meekdai
fad9e5f5e3 GITHUB_EVENT_NAME 判断 2024-03-14 14:13:09 +08:00
Meekdai
2e6b2fbbf6 add Created Time and UTC 2024-03-14 13:25:04 +08:00
Meekdai
3315462448 Update Gmeek.py 2024-03-14 11:11:47 +08:00
Meekdai
14a57bd25e add wordCount 2024-03-14 10:59:05 +08:00
Meekdai
4b22bc41ac add Statistics 2024-03-14 10:22:00 +08:00
Meekdai
994097e150 Update Gmeek.py 2024-03-14 09:11:40 +08:00
Meekdai
caac9c9dfe print GITHUB_WORKSPACE 2024-03-14 09:03:22 +08:00
Meekdai
4330e64d7d Update Gmeek.py 2024-03-13 15:04:04 +08:00
Meekdai
20db67dcd9 Update Gmeek.py 2024-03-13 15:00:22 +08:00
Meekdai
7b66777d00 Update Gmeek.py 2024-03-13 14:11:03 +08:00
Meekdai
807cfb7e10 Update Gmeek.py 2024-03-13 14:01:24 +08:00
Meekdai
8336d89834 Update Gmeek.py 2024-03-13 13:59:35 +08:00
Meekdai
8bd18d07d4 Update Gmeek.py 2024-03-13 13:55:24 +08:00
Meekdai
c48f2fa38f 添加readme展示 2024-03-13 13:53:49 +08:00
Meekdai
60ee77d1ff Update Gmeek.py 2024-03-13 11:50:49 +08:00
Meekdai
f5701d7be3 尝试获取github pages url 2024-03-13 11:41:32 +08:00
Meekdai
e2d5b0f05d 优化config.json文件,进一步减少必要的配置 2024-03-13 11:29:48 +08:00
Meekdai
7a13c48a9d 优化markdown2html函数 2024-03-13 10:03:18 +08:00
Meekdai
519af2d118 加载tag页面时,添加loading
因为postList.json在之后可能会越来越大,加载时间也会增加
2024-03-08 11:42:18 +08:00
Meekdai
fb631270bf 修改tag页面title显示错误的bug 2024-03-08 10:53:09 +08:00
Meekdai
79cdce1ff8 Update README-en.md 2024-03-08 10:46:50 +08:00
Meekdai
85fa76d845
Merge pull request #38 from KerbsOpenSource/main
Russian language support
2024-03-08 10:42:13 +08:00
KerbsOpenSource
619e88eef0 Address review comments in PR #38 2024-03-08 05:18:32 +03:00
Vadim Kerbs
1a34d7db5b
mini local fix 2024-03-08 04:03:08 +03:00
KerbsOpenSource
ce6e2f5275 Added localization into Russian 2024-03-08 02:30:17 +03:00
KerbsOpenSource
74d2dd4e71 Added localization into Russian 2024-03-07 23:41:39 +03:00
KerbsOpenSource
0c09abc327 Added documentation in Russian 2024-03-07 23:39:02 +03:00
Meekdai
3a9a014adc
Merge pull request #32 from ZhaoTim/patch-1
feat: 优化首页的用户头像图片的展示比例
2024-02-22 13:36:02 +08:00
zhaomeicheng
729d83b999
feat: 优化首页的用户头像图片的展示比例 2024-02-22 11:59:58 +08:00
Meekdai
0896ba2e8a Update Gmeek.py 2024-01-30 16:36:36 +08:00
Meekdai
7825683636 修复singeListJson文章的RSS地址错误的BUG 2024-01-30 16:21:17 +08:00
Meekdai
47a33a939f showPostSource来配置是否显示github源链接 2024-01-29 13:23:02 +08:00
Meekdai
0d65cfba26 Update README.md 2024-01-26 10:55:13 +08:00
Meekdai
d411c8ff36 Update README.md 2024-01-26 10:46:47 +08:00
Meekdai
02e8d193e7 Update README.md 2024-01-26 10:44:51 +08:00
Meekdai
24e0bc876d Update Gmeek.py 2024-01-26 10:42:33 +08:00
Meekdai
19e900fa7f Update README.md 2024-01-26 10:35:10 +08:00
Meekdai
051d230678 singlePage不添加bottomText 2024-01-26 10:29:10 +08:00
Meekdai
5cde4f52e1 文章页添加bottomText配置 2024-01-25 17:47:41 +08:00
Meekdai
a69ac9f9c1 Update README-en.md 2024-01-05 16:22:07 +08:00
Meekdai
3d893d110e Update README-en.md 2024-01-05 16:04:58 +08:00
Meekdai
2ed0a6cafc 优化description 2023-12-28 09:31:07 +08:00
Meekdai
14e31c8b3e 文章页标题使用h1标签 2023-12-28 09:21:01 +08:00
Meekdai
10fef99327 修复手机端搜索框高度问题 2023-12-26 17:16:52 +08:00
Meekdai
f82996fa5a Update Gmeek.py 2023-12-21 11:29:04 +08:00
Meekdai
d881e4fdb3 Update Gmeek.py 2023-12-21 11:27:15 +08:00
Meekdai
b911db95f8 Update Gmeek.py 2023-12-21 11:09:21 +08:00
Meekdai
6ea211db05 Update Gmeek.py 2023-12-21 11:07:49 +08:00
Meekdai
5e2e881d04 判断rss是否需要更新 2023-12-21 10:41:53 +08:00
Meekdai
a797b9a396 Update Gmeek.py 2023-12-20 22:12:36 +08:00
Meekdai
f1a94cada3 添加mathjax 2023-12-20 22:03:10 +08:00
Meekdai
3587c22378 修复取消置顶后文章依旧置顶的BUG 2023-12-16 13:50:24 +08:00
Meekdai
13a08e4dd8 解决CLS布局偏移问题 2023-12-16 09:01:45 +08:00
Meekdai
7ed365fc72
Merge pull request #11 from katelynn620/main
fix: Add homeUrl to some links
2023-12-15 22:58:38 +08:00
Meekdai
58e516bce3 Update README.md 2023-12-15 22:53:33 +08:00
Meekdai
e63a781858 Update footer.html 2023-12-15 22:52:23 +08:00
Meekdai
2ccff657e1 Update footer.html 2023-12-15 22:51:23 +08:00
Meekdai
dfff3bc199 Update README.md 2023-12-15 22:38:54 +08:00
Meekdai
22ac983335 Update README.md 2023-12-15 22:36:00 +08:00
Meekdai
1321046bb1 解决只有标题没有文章内容抓取失败的BUG 2023-12-15 22:32:53 +08:00
Meekdai
fd2a49ebbe 解决只有标题没有文章内容抓取失败的BUG 2023-12-15 22:27:32 +08:00
Meekdai
2a93089d72 添加全局文章页script和style 2023-12-14 22:03:41 +08:00
Meekdai
d2f84b539e 解决只有标题没有文章内容抓取失败的BUG 2023-12-14 21:54:35 +08:00
Meekdai
54925a8868 添加description 2023-12-14 21:52:32 +08:00
Meekdai
bccc2e6a8f 添加lang与alt 2023-12-14 21:50:40 +08:00
Meekdai
eccc091c09 Update README.md 2023-12-14 17:07:13 +08:00
Kiyomi
0c4ea07c56 fix: Add homeUrl to some links 2023-12-01 02:53:01 +00:00
Meekdai
00c5ea0fbf Update tag.html 2023-11-22 16:31:36 +08:00
Meekdai
8722e4f800 Update tag.html 2023-11-22 16:08:08 +08:00
Meekdai
9af7e00b2b 添加not find 2023-11-22 15:57:46 +08:00
Meekdai
f3e40d3761 修复tab栏显示 2023-11-22 15:24:58 +08:00
Meekdai
4d177fb34b 优化搜索框尺寸排布 2023-11-22 15:15:36 +08:00
Meekdai
d2a53f6cd4 修改手机端显示大小 2023-11-22 15:03:39 +08:00
Meekdai
3e95b51cc7 删除首页搜索框转到tag页面 2023-11-22 14:44:05 +08:00
Meekdai
bf28ad41c5 修复大小写不敏感 2023-11-22 14:19:30 +08:00
Meekdai
55211a6eda Update tag.html 2023-11-22 14:06:11 +08:00
Meekdai
712cea94f1 Update tag.html 2023-11-22 13:57:28 +08:00
Meekdai
f3ec0f9c28 Update tag.html 2023-11-22 13:53:15 +08:00
Meekdai
2f245e7987 tag添加搜索框 2023-11-22 13:49:39 +08:00
Meekdai
2cbd584a44 修改头像大小 2023-11-22 13:13:27 +08:00
Meekdai
6e15cc8437 精简docs的json文件提升加载速度 2023-11-22 12:34:37 +08:00
Meekdai
ea1ae75251 docs内json文件排序 2023-11-22 12:15:37 +08:00
Meekdai
356a3b5b57 Update plist.html 2023-11-22 11:38:49 +08:00
Meekdai
3234fb2a63 取消Monaco字体 2023-11-22 11:19:02 +08:00
Meekdai
ab1a59677b 标题显示调整 2023-11-22 11:14:45 +08:00
Meekdai
814caef4fc title使用span标签 2023-11-22 11:00:38 +08:00
Meekdai
033dcf0e08 取消h1的a标签下划线 2023-11-22 10:47:33 +08:00
Meekdai
305862dfeb 修改h1字体大小 2023-11-22 10:35:35 +08:00
Meekdai
b6539d148c Update tag.html 2023-11-22 10:29:28 +08:00
Meekdai
f1584f9e9e 添加All标签按钮 2023-11-22 10:16:17 +08:00
Meekdai
ebc61593a0 标题过长不换行,用省略号 2023-11-22 10:00:02 +08:00
Meekdai
c9ad72dbe0 优化布局 2023-11-22 09:43:03 +08:00
Meekdai
595c1c8879 Update tag.html 2023-11-22 09:26:45 +08:00
Meekdai
656c97bc03 Update tag.html 2023-11-22 09:15:12 +08:00
Meekdai
547d4137de Update tag.html 2023-11-21 22:52:13 +08:00
Meekdai
826850ccd8 Update tag.html 2023-11-21 22:43:44 +08:00
Meekdai
c786987543 Update tag.html 2023-11-21 22:39:15 +08:00
Meekdai
2ee940313f Update tag.html 2023-11-21 22:35:06 +08:00
Meekdai
2754066085 Update tag.html 2023-11-21 22:28:11 +08:00
Meekdai
dbbc15e095 Update tag.html 2023-11-21 22:18:44 +08:00
Meekdai
d970382ebb 监听hash变化刷新页面 2023-11-21 22:12:49 +08:00
Meekdai
6280f10b12 Update tag.html 2023-11-21 21:24:13 +08:00
Meekdai
3c6d1d3932 Update tag.html 2023-11-21 21:16:15 +08:00
Meekdai
199121d3f1 Update tag.html 2023-11-21 21:02:49 +08:00
Meekdai
93e0487703 顶部添加所有Tag标签 2023-11-21 18:17:59 +08:00
Meekdai
95fdccf3b6 Update tag.html 2023-11-21 17:42:19 +08:00
Meekdai
c7571e20d0 Update tag.html 2023-11-21 17:39:38 +08:00
Meekdai
f50524bdb5 tag删除搜索框 2023-11-21 17:37:02 +08:00
Meekdai
5333cd189c Update plist.html 2023-11-21 17:33:34 +08:00
Meekdai
9b5a8a8d62 Update plist.html 2023-11-21 17:27:31 +08:00
Meekdai
506d918264 Update plist.html 2023-11-21 17:22:42 +08:00
Meekdai
bce294921c plist 添加链接到 tag 2023-11-21 17:16:33 +08:00
Meekdai
224c59fc20 Update tag.html 2023-11-21 17:10:41 +08:00
Meekdai
c2cc3beb43 Update tag.html 2023-11-21 17:03:31 +08:00
Meekdai
e67297b6fd Update tag.html 2023-11-21 16:58:14 +08:00
Meekdai
6e7ca11645 add tag 2023-11-21 16:47:25 +08:00
Meekdai
772f4960f5 Update Gmeek.py 2023-11-21 16:11:38 +08:00
Meekdai
764f495ca6 blogBase.json放入docs文件夹 2023-11-21 15:45:06 +08:00
Meekdai
a38123450a
Merge pull request #9 from shyn/patch-1
markdown 渲染使用gfm模式,支持GitHub的所有语法
2023-11-17 16:21:44 +08:00
shyn
b4ef9defdc
markdown 渲染使用gfm模式,支持GitHub的所有语法
#6 
https://github.com/Meekdai/Gmeek/issues/6#issuecomment-1737281658
2023-11-17 15:54:47 +08:00
Meekdai
ccffc5a5d2
Update README.md 2023-11-13 18:02:58 +08:00
Meekdai
0632986060 再一次简化搭建流程,真18秒搭建完成 2023-11-13 17:53:17 +08:00
Meekdai
9306186f85 添加urlMode配置说明 2023-11-13 16:18:17 +08:00
Meekdai
919a924141 通过urlMode配置文章URL模式
目前pinyin和issue可选
2023-11-05 21:07:24 +08:00
Meekdai
dd3455f423 升级版本号到v2.5 2023-11-02 17:36:46 +08:00
Meekdai
098e765011 备案号判断 2023-11-02 16:37:33 +08:00
Meekdai
fe917e7316 如果存在备案号,添加链接到工信部备案官网 2023-11-02 16:29:40 +08:00
呆瓜云
9df8c8560d Revert "可上传自定义静态页面项目"
This reverts commit c5b846a16e.
2023-10-13 15:26:26 +08:00
呆瓜云
417a02d4cc 修复h2 h3 h4 标签颜色变化
由github api 导致,发现markdown转html 有细微变化
2023-10-08 13:23:44 +08:00
呆瓜云
c5b846a16e 可上传自定义静态页面项目 2023-09-22 10:58:51 +08:00
呆瓜云
131c0aa8e8 修复单页面runOne报错的BUG 2023-09-08 11:06:44 +08:00
Meekdai
1372d195fc Update Gmeek.py 2023-09-05 22:13:08 +08:00
Meekdai
2915079ab3 没有代码高亮需求的文章不加载高亮CSS 2023-09-05 22:11:23 +08:00
Meekdai
a447a824d8
Update CONIFG.md 2023-09-05 21:57:13 +08:00
呆瓜云
ac0478cf06 添加nightTheme和dayTheme配置 2023-09-05 17:23:28 +08:00
呆瓜云
c4561b6a74 config配置文件精简,添加配置Theme参数 2023-09-05 17:17:27 +08:00
Meekdai
369543e155
Update README.md 2023-09-04 11:00:48 +08:00
Meekdai
7f1d03ce59
Update README.md 2023-09-04 10:28:07 +08:00
20 changed files with 1553 additions and 319 deletions

43
.github/workflows/static.yml vendored Normal file
View File

@ -0,0 +1,43 @@
# 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
View File

@ -1,116 +0,0 @@
# 配置文件说明
### `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,5 +1,6 @@
# -*- coding: utf-8 -*-
import os
import re
import json
import time
import datetime
@ -7,14 +8,18 @@ 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","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={
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={
"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",
@ -24,7 +29,10 @@ IconList={
"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"
"home":"M6.906.664a1.749 1.749 0 0 1 2.187 0l5.25 4.2c.415.332.657.835.657 1.367v7.019A1.75 1.75 0 0 1 13.25 15h-3.5a.75.75 0 0 1-.75-.75V9H7v5.25a.75.75 0 0 1-.75.75h-3.5A1.75 1.75 0 0 1 1 13.25V6.23c0-.531.242-1.034.657-1.366l5.25-4.2Zm1.25 1.171a.25.25 0 0 0-.312 0l-5.25 4.2a.25.25 0 0 0-.094.196v7.019c0 .138.112.25.25.25H5.5V8.25a.75.75 0 0 1 .75-.75h3.5a.75.75 0 0 1 .75.75v5.25h2.75a.25.25 0 0 0 .25-.25V6.23a.25.25 0 0 0-.094-.195Z",
"sync":"M1.705 8.005a.75.75 0 0 1 .834.656 5.5 5.5 0 0 0 9.592 2.97l-1.204-1.204a.25.25 0 0 1 .177-.427h3.646a.25.25 0 0 1 .25.25v3.646a.25.25 0 0 1-.427.177l-1.38-1.38A7.002 7.002 0 0 1 1.05 8.84a.75.75 0 0 1 .656-.834ZM8 2.5a5.487 5.487 0 0 0-4.131 1.869l1.204 1.204A.25.25 0 0 1 4.896 6H1.25A.25.25 0 0 1 1 5.75V2.104a.25.25 0 0 1 .427-.177l1.38 1.38A7.002 7.002 0 0 1 14.95 7.16a.75.75 0 0 1-1.49.178A5.5 5.5 0 0 0 8 2.5Z",
"copy":"M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z",
"check":"M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
}
######################################################################################
class GMEEK():
@ -32,6 +40,7 @@ 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
@ -39,24 +48,22 @@ 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)
@ -67,46 +74,148 @@ 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": "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 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 renderHtml(self,template,blogBase,postListJson,htmlDir):
def renderHtml(self,template,blogBase,postListJson,htmlDir,icon):
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=IconList)
output = template.render(blogBase=blogBase,postListJson=postListJson,i18n=self.i18n,IconList=icon)
f = open(htmlDir, 'w', encoding='UTF-8')
f.write(output)
f.close()
def createPostHtml(self,issue):
f = open("backup/"+issue["postTitle"]+".md", 'r', encoding='UTF-8')
mdFileName=re.sub(r'[<>:/\\|?*\"]|[\0-\31]', '-', issue["postTitle"])
f = open(self.backup_dir+mdFileName+".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"]=''
self.renderHtml('post.html',postBase,{},issue["htmlDir"])
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)
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
@ -128,7 +237,7 @@ class GMEEK():
self.blogBase["prevUrl"]="/page%d.html" % pageFlag
self.blogBase["nextUrl"]="disabled"
self.renderHtml('plist.html',self.blogBase,onePageList,htmlDir)
self.renderHtml('plist.html',self.blogBase,onePageList,htmlDir,plistIcon)
print("create "+htmlDir)
break
else:
@ -146,11 +255,14 @@ 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)
self.renderHtml('plist.html',self.blogBase,onePageList,htmlDir,plistIcon)
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()
@ -158,7 +270,6 @@ 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"])
@ -180,39 +291,67 @@ 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'
gen_Html = 'docs/{}.html'.format(issue.labels[0].name)
htmlFile='{}.html'.format(self.createFileName(issue,useLabel=True))
gen_Html = self.root_dir+htmlFile
else:
listJsonName='postListJson'
gen_Html = self.post_dir+'{}.html'.format(Pinyin().get_pinyin(issue.title))
htmlFile='{}.html'.format(self.createFileName(issue))
gen_Html = self.post_dir+htmlFile
postNum="P"+str(issue.number)
self.blogBase[listJsonName][postNum]=json.loads('{}')
self.blogBase[listJsonName][postNum]["htmlDir"]=gen_Html
self.blogBase[listJsonName][postNum]["label"]=issue.labels[0].name
self.blogBase[listJsonName][postNum]["labelColor"]=self.labelColorDict[issue.labels[0].name]
self.blogBase[listJsonName][postNum]["labels"]=[label.name for label in issue.labels]
self.blogBase[listJsonName][postNum]["postTitle"]=issue.title
self.blogBase[listJsonName][postNum]["postUrl"]=urllib.parse.quote(self.post_folder+'{}.html'.format(Pinyin().get_pinyin(issue.title)))
self.blogBase[listJsonName][postNum]["postUrl"]=urllib.parse.quote(gen_Html[len(self.root_dir):])
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 self.blogBase["i18n"]=="CN":
period=""
else:
period="."
self.blogBase[listJsonName][postNum]["description"]=issue.body.split(period)[0]+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]["top"]=0
for event in issue.get_events():
if event.event=="pinned":
self.blogBase[listJsonName][postNum]["top"]=1
break
elif event.event=="unpinned":
break
self.blogBase[listJsonName][postNum]["top"]=0
try:
postConfig=json.loads(issue.body.split("\r\n")[-1:][0].split("##")[1])
@ -225,23 +364,42 @@ 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"]=str(postConfig["style"])
self.blogBase[listJsonName][postNum]["style"]=self.blogBase["style"]+str(postConfig["style"])
else:
self.blogBase[listJsonName][postNum]["style"]=""
self.blogBase[listJsonName][postNum]["style"]=self.blogBase["style"]
if "script" in postConfig:
self.blogBase[listJsonName][postNum]["script"]=str(postConfig["script"])
self.blogBase[listJsonName][postNum]["script"]=self.blogBase["script"]+str(postConfig["script"])
else:
self.blogBase[listJsonName][postNum]["script"]=""
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)
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"])]
f = open("backup/"+issue.title+".md", 'w', encoding='UTF-8')
f.write(issue.body)
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.close()
return listJsonName
def runAll(self):
print("====== start create static html ======")
@ -264,11 +422,28 @@ class GMEEK():
def runOne(self,number_str):
print("====== start create static html ======")
issue=self.repo.get_issue(int(number_str))
self.addOnePostJson(issue)
self.createPostHtml(self.blogBase["postListJson"]["P"+number_str])
self.createPlistHtml()
self.createFeedXml()
print("====== create static html end ======")
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
######################################################################################
parser = argparse.ArgumentParser()
@ -283,17 +458,68 @@ 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")
blog.blogBase=json.loads(f.read())
oldBlogBase=json.loads(f.read())
for key, value in oldBlogBase.items():
blog.blogBase[key] = value
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 Normal file
View File

@ -0,0 +1,21 @@
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,18 +1,20 @@
**[简体中文](README.md)** | **English**
**[简体中文](README.md)** | **English** | **[Русский](README-ru.md)**
# 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 from building to writing.
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.
- [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. 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
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
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
@ -23,7 +25,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)

31
README-ru.md Normal file
View File

@ -0,0 +1,31 @@
**[简体中文](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,21 +1,31 @@
**简体中文** | **[English](README-en.md)**
**简体中文** | **[English](README-en.md)** | **[Русский](README-ru.md)**
# Gmeek
一个博客框架,超轻量级个人博客模板。完全基于`Github Pages` 、 `Github Issues``Github Actions`。不需要本地部署,从搭建到写作,只需要几分钟的时间3步搭建好博客第4步就是写作。
一个博客框架,超轻量级个人博客模板。完全基于`Github Pages` 、 `Github Issues``Github Actions`。不需要本地部署,从搭建到写作,只需要18秒2步搭建好博客第3步就是写作。
- [Demo页面](http://meekdai.github.io/)
- [更新日志](https://meekdai.github.io/post/Gmeek-geng-xin-ri-zhi.html)
- [Gmeek更新日志](https://meekdai.github.io/post/Gmeek-geng-xin-ri-zhi.html)
- [Gmeek快速上手](https://blog.meekdai.com/post/Gmeek-kuai-su-shang-shou.html)
![light](img/light.jpg)
### 安装
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 访问
1. 【创建仓库】点击[通过模板创建仓库](https://github.com/new?template_name=Gmeek-template&template_owner=Meekdai),建议仓库名称为`XXX.github.io`,其中`XXX`为你的github用户名。
如果有问题可在本仓库提交[Issues](https://github.com/Meekdai/Gmeek/issues) 或者添加 QQ`294977308`
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`后,我会帮忙查看构建流程,定位问题出处。
### 特性
@ -24,34 +34,11 @@
- 评论系统引入[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/)
@ -62,3 +49,4 @@
### License
请保留页面底部和console界面版权信息谢谢

BIN
img/赞赏码.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

16
plugins/GmeekBSZ.js Normal file
View File

@ -0,0 +1,16 @@
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");
});

100
plugins/GmeekTOC.js Normal file
View File

@ -0,0 +1,100 @@
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");
});

59
plugins/GmeekTocBot.js Normal file
View File

@ -0,0 +1,59 @@
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");
});

16
plugins/GmeekVercount.js Normal file
View File

@ -0,0 +1,16 @@
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");
});

158
plugins/articletoc.js Normal file
View File

@ -0,0 +1,158 @@
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();
}
});
});

357
plugins/lightbox.js Normal file
View File

@ -0,0 +1,357 @@
(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,3 +3,4 @@ requests
xpinyin
feedgen
Jinja2
transliterate

View File

@ -1,32 +1,22 @@
<!DOCTYPE html>
<html data-color-mode="light" data-dark-theme="dark" data-light-theme="light">
<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 -%}>
<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">
<link href="//cdn.staticfile.org/Primer/21.0.7/primer.css" rel="stylesheet" />
{{ blogBase['primerCSS'] }}
{{ blogBase['allHead'] }}
<link rel="icon" href="{{ blogBase['faviconUrl'] }}">
{%- if blogBase['themeMode']=='manual' -%}
<script>
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";}
let theme = localStorage.getItem("meek_theme") || "light";
document.documentElement.setAttribute("data-color-mode", theme);
</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;
}
.avatar {transition: 0.8s;}
.avatar:hover {transform: scale(1.15) rotate(360deg);}
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;}
#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;}
@ -41,33 +31,34 @@ body{
<script>
var IconList={{ IconList }};
var utterancesLoad=0;
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");}
{% 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);}
}
function modeSwitch(){
if(document.getElementsByTagName("html")[0].attributes[0].value=="light"){changeDark();localStorage.setItem("meek_theme","dark");}
else{changeLight();localStorage.setItem("meek_theme","light");}
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]);
}
}
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');
}
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;");
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");
</script>
{% block script %}{% endblock %}
</html>

View File

@ -1,14 +1,19 @@
Copyright © <span id="year"></span> <a href="{{ blogBase['homeUrl'] }}"> {{ blogBase['title'] }} </a><p> {{ blogBase['filingNum'] }} <span id="runday"></span>Powered by <a href="https://github.com/Meekdai/Gmeek" target="_blank">Gmeek</a></p>
<div id="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>
<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("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'] }}"+" • ";}
document.getElementById("runday").innerHTML="{{ i18n['run'] }}"+diffDay+"{{ i18n['days'] }}"+" • ";
}
</script>

View File

@ -1,67 +1,81 @@
{% 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>
h1 a:not([href]){color:inherit;text-decoration:none;vertical-align: bottom;font-size:40px;font-family:Monaco;}
.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;}
.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: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;}
.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;}
#buttonRSS{display:none;}
.SideNav-item .listLabels{display:none;}
.LabelTime{display:none;}
}
</style>
{{ blogBase['indexStyle'] }}
{% endblock %}
{% block header %}
<h1>
<img src="{{ blogBase['avatarUrl'] }}" size="64" height="64" width="64" class="avatar circle" id="avatarImg">
<a>{{ blogBase['displayTitle'] }}</a>
</h1>
<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>
<div class="title-right">
<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>
<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>
</svg>
</div>
</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 %}
{% for num in blogBase['singeListJson'] -%}
<a href="/{{ blogBase['singeListJson'][num]['label'] }}.html"><button class="btn btn-invisible circle" title="{{ blogBase['singeListJson'][num]['postTitle'] }}">
<a href="{{ blogBase['homeUrl'] }}/{{ blogBase['singeListJson'][num]['labels'][0] }}.html" 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>
</button></a>
</a>
{%- endfor %}
<a href="/rss.xml" target="_blank"><button id="buttonRSS" class="btn btn-invisible circle" title="RSS">
<a href="{{ blogBase['homeUrl'] }}/rss.xml" target="_blank" id="buttonRSS" class="btn btn-invisible circle" title="RSS">
<svg class="octicon" width="16" height="16" >
<path id="pathRSS" fill-rule="evenodd"></path>
</svg>
</button></a>
<button class="btn btn-invisible circle" onclick="modeSwitch()" title="{{ i18n['switchTheme'] }}">
</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>
</button>
</a>
</div>
{% endblock %}
@ -73,12 +87,14 @@ h1 a:not([href]){color:inherit;text-decoration:none;vertical-align: bottom;font-
<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>{{ postListJson[num]['postTitle']|e }}</span>
<span class="listTitle">{{ 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 %}
<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>
{% 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>
</div>
</a>
{%- endfor %}
@ -89,13 +105,13 @@ h1 a:not([href]){color:inherit;text-decoration:none;vertical-align: bottom;font-
{%- if blogBase['prevUrl']=='disabled' -%}
<span class="previous_page" aria-disabled="true">{{ i18n['Previous'] }}</span>
{% else -%}
<a class="previous_page" rel="previous" href="{{ blogBase['prevUrl'] }}" aria-label="Previous Page">{{ i18n['Previous'] }}</a>
<a class="previous_page" rel="previous" href="{{ blogBase['homeUrl'] }}{{ 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['nextUrl'] }}" aria-label="Next Page">{{ i18n['Next'] }}</a>
<a class="next_page" rel="next" href="{{ blogBase['homeUrl'] }}{{ blogBase['nextUrl'] }}" aria-label="Next Page">{{ i18n['Next'] }}</a>
{%- endif -%}
</div>
@ -105,7 +121,7 @@ h1 a:not([href]){color:inherit;text-decoration:none;vertical-align: bottom;font-
{% block script %}
<script>
document.getElementById("searchSVG").setAttribute("d",IconList["search"]);
document.getElementById("pathSearch").setAttribute("d",IconList["search"]);
document.getElementById("pathRSS").setAttribute("d",IconList["rss"]);
iconTOP=document.getElementsByClassName("svgTop1");
iconPost=document.getElementsByClassName("svgTop0");
@ -117,8 +133,13 @@ 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]['label'] }}"]);
document.getElementById("{{ blogBase['singeListJson'][num]['postTitle'] }}").setAttribute("d",value=IconList["{{ blogBase['singeListJson'][num]['labels'][0] }}"]);
{%- endfor %}
</script>
{{ blogBase['indexScript'] }}
{% endblock %}

View File

@ -1,13 +1,20 @@
{% 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>
<link href="//unpkg.com/@wooorm/starry-night@2.1.1/style/both.css" rel="stylesheet" />
{% 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 %}
<style>
h1 a:not([href]){color:inherit;text-decoration:none;vertical-align: bottom;font-size:40px;}
.postTitle{margin: auto 0;font-size:40px;font-weight:bold;}
.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;}
@ -15,49 +22,64 @@ h1 a:not([href]){color:inherit;text-decoration:none;vertical-align: bottom;font-
#cmButton{height:48px;margin-top:48px;}
#comments{margin-top:64px;}
.g-emoji{font-size:24px;}
@media (max-width: 767px) {body {padding: 8px;}}
@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 %}
</style>
{{ blogBase['style'] }}
{% endblock %}
{% block header %}
<h1>
<a>{{ blogBase['postTitle'] }}</a>
</h1>
<h1 class="postTitle">{{ blogBase['postTitle'] }}</h1>
<div class="title-right">
<a href="/"><button id="buttonHome" class="btn btn-invisible circle" title="{{ i18n['home'] }}">
<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" d="{{ IconList['home'] }}"></path>
<path id="pathHome" fill-rule="evenodd"></path>
</svg>
</button></a>
<a href="{{ blogBase['postSourceUrl'] }}" target="_blank"><button class="btn btn-invisible circle" title="Issue">
</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" d="{{ IconList['github'] }}"></path>
<path id="pathIssue" fill-rule="evenodd"></path>
</svg>
</button></a>
</a>
{% endif %}
<button class="btn btn-invisible circle" onclick="modeSwitch();" title="{{ i18n['switchTheme'] }}">
<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>
</button>
</a>
</div>
{% endblock %}
{% block content %}
<div class="markdown-body" id="postBody">
{{ blogBase['postBody'] }}
</div>
<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");
@ -66,6 +88,7 @@ h1 a:not([href]){color:inherit;text-decoration:none;vertical-align: bottom;font-
cmButton.appendChild(span);
{%- endif %}
{% if blogBase['needComment']==1 %}
function openComments(){
cm=document.getElementById("comments");
cmButton=document.getElementById("cmButton");
@ -78,8 +101,13 @@ 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{script.setAttribute("theme","github-light");}
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 %}
script.setAttribute("crossorigin","anonymous");
script.setAttribute("async","");
cm.appendChild(script);
@ -98,9 +126,75 @@ 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 %}

221
templates/tag.html Normal file
View File

@ -0,0 +1,221 @@
{% 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 %}