hexo-theme-shokax 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,15 +25,17 @@ shokaX的社区资源导航和插件仓库为[awesome-shokaX](https://github.com
25
25
  | PWA支持 | ✅ | JSD拆分 | ✅ |
26
26
  | 注入API | ✅ | 社区插件系统 | ✅ |
27
27
  | 自定义字体 | ✅* | 自定义样式 | ✅* |
28
- | 多种评论系统支持 | ✅ | 用户行为分析支持 | |
28
+ | 多种评论系统支持 | ✅ | AI生成文章概括 | 🔬 |
29
29
  | 底部备案号 | ✅ | 自定义页尾 | ✅* |
30
30
  | CSS渐变封面 | ✅ | typescript支持 | ✅ |
31
31
 
32
32
  备注:
33
33
  - *: 需要使用注入API实现
34
+ - 🔬: 实验中,可能存在问题
34
35
 
35
36
 
36
37
  ## 🔧 如何安装?
38
+ 注意: 本项目需要 node.js 18.x 或更高版本才能运行 \
37
39
  建议使用[ShokaX-CLI](https://github.com/zkz098/shokaX-CLI) ,执行下列命令即可:
38
40
  ```bash
39
41
  npm i shokax-cli --location=global
@@ -58,7 +60,7 @@ github仓库建议通过右边的 releases 下载,步骤为:
58
60
  - [Easy hexo](https://easyhexo.com/)
59
61
 
60
62
  # 许可证
61
- 许可证: GPL 3 \
63
+ 许可证: GPL 3 or later \
62
64
  [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fzkz098%2Fhexo-theme-shokaX.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fzkz098%2Fhexo-theme-shokaX?ref=badge_large)
63
65
 
64
66
  ## 特别说明
@@ -77,3 +79,6 @@ GPL许可证主要目的是限制修改后的分发行为,避免未经许可
77
79
 
78
80
  ## 特别鸣谢
79
81
  [<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.png" width="25%">](https://jb.gg/OpenSourceSupport)
82
+
83
+ ## 其他信息
84
+ ![Star history chart](https://api.star-history.com/svg?repos=theme-shoka-x/hexo-theme-shokaX&type=Date)
package/README_en.MD CHANGED
@@ -1,25 +1,56 @@
1
+ If the repository address you are visiting is zkz098/hexo-theme-shokaX, please switch to the latest address: theme-shoka-x/hexo-theme-shokaX.
2
+
1
3
  # hexo-theme-shokaX
2
4
  [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fzkz098%2Fhexo-theme-shokaX.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fzkz098%2Fhexo-theme-shokaX?ref=badge_shield)
3
- ![LICENSE]( https://img.shields.io/github/license/zkz098/hexo-theme-shokaX)
4
- ![stars](https://img.shields.io/github/stars/zkz098/hexo-theme-shokaX)
5
+ ![LICENSE]( https://img.shields.io/github/license/theme-shoka-x/hexo-theme-shokaX)
6
+ ![stars](https://img.shields.io/github/stars/theme-shoka-x/hexo-theme-shokaX)
5
7
  ![version](https://shields.io/npm/v/hexo-theme-shokax)
8
+ ![build](https://img.shields.io/github/actions/workflow/status/theme-shoka-x/hexo-theme-shokaX/build-theme.yml)
9
+
10
+ Language: [简体中文](./README.md) | English \
11
+ This project is a secondary development version of shoka (spiritual sequel), dedicated to improving performance and optimizing modding experience.
12
+ The reason for its birth is that shoka has not been updated for two years, with a large backlog of bugs and feature requests.
13
+
14
+ The community resource navigation and plugin repository for shokaX is awesome-shokaX.
15
+
16
+ ## 💬 Differences with shoka
17
+ The original shoka used javascript+Native+nunjucks technology, while shokaX uses typescript+Vue 3+Pug technology and has changed a lot of hard-to-access CDN links.
18
+
19
+ ## ✨ Feature List
20
+ | Feature Name | Implementation Status | Feature Name | Implementation Status |
21
+ |:-------------------------------:|:---------------------:|:------------------------------:|:---------------------:|
22
+ | PWA Support | ✅ | JSD Splitting | ✅ |
23
+ | Injection API | ✅ | Community Plugin System | ✅ |
24
+ | Custom Fonts | ✅* | Custom Styles | ✅* |
25
+ | Multiple Comment System Support | ✅ | User Behavior Analysis Support | ✅ |
26
+ | Record Number at the Bottom | ✅ | Custom Footer | ✅* |
27
+ | CSS Gradient Cover | ✅ | Typescript Support | ✅ |
6
28
 
7
- 语言(language): [简体中文](./README.md) | English \
8
- This project is a secondary development version of Shoka, dedicated to improving performance and optimizing the development experience. \
9
- This project is in a period of intensive development, but the github repository version is basically available. \
10
- Please refer to the wiki for secondary development and common problems.
11
- Starting with `0.0.2-alpha2`, `lantern` and `qweather` have been migrated as plugins.
12
- The plugin system is complete, see [awesome-shokaX](https://github.com/zkz098/awesome-shokaX) for how to use it.
29
+ Remarks:
30
+ - *: Requires implementation using Injection API.
13
31
 
14
- ## How to install?
15
- [ShokaX-CLI](https://github.com/zkz098/shokaX-CLI) is recommended:
32
+ ## 🔧 How to Install?
33
+ It is recommended to use [ShokaX-CLI](https://github.com/zkz098/shokaX-CLI) and execute the following command:
16
34
  ```bash
17
35
  npm i shokax-cli --location=global
18
- # hexo init
19
- SXC install -r=github shokaX
36
+ # hexo init initializes the environment
37
+ SXC install shokaX
20
38
  ```
39
+ [Click here](https://docs.kaitaku.xyz/guide/#%E9%85%8D%E7%BD%AE%E4%B8%BB%E9%A2%98) for the next configuration steps.
40
+
41
+ It is recommended to download the GitHub repository from the Releases on the right-hand side, as follows:
42
+
43
+ - Click on the Latest version in Releases
44
+ - Download the Source code(zip) in Assets
45
+ - Unzip to use as the theme
21
46
 
22
47
  # License
23
- License: BSD-3-Clause \
48
+ license: GPL 3 or later
24
49
  [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fzkz098%2Fhexo-theme-shokaX.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fzkz098%2Fhexo-theme-shokaX?ref=badge_large)
25
50
 
51
+ ## Contributors
52
+
53
+ [![](https://contributors-img.web.app/image?repo=zkz098/hexo-theme-shokaX)](https://github.com/zkz098/hexo-theme-shokaX/graphs/contributors)
54
+
55
+ ## Special thanks
56
+ [<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.png" width="25%">](https://jb.gg/OpenSourceSupport)
package/_config.yml CHANGED
@@ -198,6 +198,18 @@ giscus:
198
198
  commentTheme:
199
199
  lang:
200
200
 
201
+ summary:
202
+ enable: false
203
+ introduce: "我是基于ChatGPT-turbo-3.5实现的AI助手,在此网站上负责整理和概括文章" # AI自我介绍
204
+ mode: openai # openai/custom
205
+ pricing: "trial" # trial为试用模板(3 RPM);pay为即用即付模板(60 RPM)
206
+ openai:
207
+ remote: "https://api.openai.com"
208
+ apikey: "key"
209
+ custom:
210
+ remote: "http://localhost:8000"
211
+
212
+
201
213
  # Social Links
202
214
  # Usage: `Key: permalink || icon || color`
203
215
  # Key is the link label showing to end users.
@@ -340,7 +352,7 @@ advVendors:
340
352
  pace:
341
353
  src: bytedance:pace/1.0.2/pace.min.js
342
354
  pjax:
343
- src: baomitu:pjax/0.2.8/pjax.min.js
355
+ src: npm:theme-shokax-pjax@latest/pjax.shokax.min.js
344
356
  fetch:
345
357
  src: npm:whatwg-fetch@3.4.0/dist/fetch.umd.js
346
358
  anime:
@@ -392,7 +404,7 @@ vendors:
392
404
 
393
405
  js:
394
406
  pace: npm/pace-js@1.0.2/pace.min.js # ok
395
- pjax: npm/pjax@0.2.8/pjax.min.js # ok
407
+ pjax: npm/theme-shokax-pjax@latest/pjax.shokax.min.js # ok
396
408
  fetch: npm/whatwg-fetch@3.4.0/dist/fetch.umd.min.js # ok
397
409
  anime: npm/theme-shokax-anime@latest/anime.shokax.min.js
398
410
  algolia: npm/algoliasearch@4/dist/algoliasearch-lite.umd.js # ok
@@ -1,6 +1,5 @@
1
1
  mixin PMRender(item, full)
2
2
  - full ||= false
3
- //- 下方的_content为暴力修复法,在未来需要重写
4
3
  div(class="meta")
5
4
  - var create_title = __('post.created') + __('symbol.colon') + full_date(item.date)
6
5
  span(class="item" title=create_title)
@@ -12,6 +12,19 @@ article(itemscope itemtype="http://schema.org/Article" class="post block" lang=t
12
12
  div(class="gallery" itemscope itemtype="http://schema.org/ImageGallery")
13
13
  each photo in post.photos
14
14
  img(data-src=_image_url(photo, post.path) itemprop="contentUrl")
15
+ if theme.summary.enable && page.layout === 'post'
16
+ div(class='tabs' id='summary')
17
+ div(class="show-btn")
18
+ div(class="nav")
19
+ ul(class="special")
20
+ div(class="tab" data-id="summary" data-title="自我介绍")
21
+ p
22
+ != get_introduce()
23
+ div(class="tab active" data-id="summary" data-title="文章概括")
24
+ p
25
+ != get_summary(page)
26
+
27
+
15
28
  != post.content
16
29
  if post.tags && post.tags.length
17
30
  div(class="tags")
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "hexo-theme-shokax",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "a hexo theme based on shoka",
5
5
  "main": "index.js",
6
- "repository": "https://github.com/zkz098/hexo-theme-shokaX",
6
+ "repository": "https://github.com/theme-shoka-x/hexo-theme-shokaX",
7
7
  "author": "Chou kaitaku",
8
8
  "license": "GPL-3.0-or-later",
9
9
  "scripts": {
@@ -34,12 +34,12 @@
34
34
  "hexo-fs": "^4.1.1",
35
35
  "hexo-util": "^3.0.1",
36
36
  "instantsearch.js": "^4.54.1",
37
- "pjax": "^0.2.8",
38
37
  "theme-shokax-anime": "^0.0.4",
38
+ "theme-shokax-pjax": "^0.0.2",
39
39
  "typescript": "^5.0.4",
40
40
  "vue": "^3.2.47",
41
41
  "vuepress": "2.0.0-beta.61",
42
- "vuepress-plugin-sitemap2": "2.0.0-beta.205"
42
+ "vuepress-plugin-sitemap2": "2.0.0-beta.206"
43
43
  },
44
44
  "dependencies": {
45
45
  "js-yaml": "^4.1.0",
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const node_fs_1 = __importDefault(require("node:fs"));
7
+ function getContent(post) {
8
+ return post?.raw ?? post?._content ?? post.content;
9
+ }
10
+ let db;
11
+ function postMessage(path, content, dbPath, startMessage) {
12
+ if (node_fs_1.default.existsSync('summary.json')) {
13
+ db = JSON.parse(node_fs_1.default.readFileSync('summary.json'));
14
+ }
15
+ else {
16
+ db = {};
17
+ }
18
+ const config = hexo.theme.config.summary;
19
+ if (config.enable) {
20
+ if (typeof db?.[path] !== 'undefined' && typeof db?.[path]?.[dbPath] !== 'undefined') {
21
+ return db[path][dbPath];
22
+ }
23
+ else {
24
+ if (typeof db?.[path] === 'undefined') {
25
+ db[path] = {};
26
+ }
27
+ else {
28
+ db[path][dbPath] = '';
29
+ }
30
+ }
31
+ if (config.mode === 'openai') {
32
+ const request = () => {
33
+ fetch(`${config.openai.remote}/v1/chat/completions`, {
34
+ method: 'POST',
35
+ headers: requestHeaders,
36
+ body: JSON.stringify(requestBody)
37
+ }).then((response) => {
38
+ if (!response.ok) {
39
+ throw Error('ERROR: Failed to get summary from Openai API');
40
+ }
41
+ response.json().then((data) => {
42
+ const summary = data.choices[0].message.content;
43
+ try {
44
+ db[path][dbPath] = summary;
45
+ }
46
+ catch (e) {
47
+ db ??= {};
48
+ db[path] ??= {};
49
+ db[path][dbPath] ??= '';
50
+ console.log(db[path]);
51
+ db[path][dbPath] = summary;
52
+ }
53
+ node_fs_1.default.writeFileSync('summary.json', JSON.stringify(db));
54
+ if (node_fs_1.default.existsSync('requested.lock')) {
55
+ node_fs_1.default.unlinkSync('requested.lock');
56
+ }
57
+ return summary;
58
+ });
59
+ });
60
+ };
61
+ const checkTime = (waitTime) => {
62
+ if (node_fs_1.default.existsSync('request.lock')) {
63
+ if (node_fs_1.default.existsSync('requested.lock')) {
64
+ setTimeout(checkTime, 1000 * waitTime);
65
+ return;
66
+ }
67
+ node_fs_1.default.writeFileSync('requested.lock', '');
68
+ setTimeout(request, 1000 * 2.5 * waitTime);
69
+ node_fs_1.default.unlinkSync('request.lock');
70
+ }
71
+ else {
72
+ node_fs_1.default.writeFileSync('request.lock', '');
73
+ request();
74
+ }
75
+ };
76
+ const requestHeaders = {
77
+ 'Content-Type': 'application/json',
78
+ Authorization: `Bearer ${config.openai.apikey}`
79
+ };
80
+ const requestBody = {
81
+ model: 'gpt-3.5-turbo',
82
+ messages: [{ role: 'user', content: `${startMessage} ${content}` }],
83
+ temperature: 0.7
84
+ };
85
+ if (config.pricing === 'trial') {
86
+ hexo.log.info('Requesting OpenAI API... (3 RPM mode)');
87
+ hexo.log.info('It may take 20 minutes or more (depending on the number of articles, each one takes 25 seconds)');
88
+ checkTime(10);
89
+ }
90
+ else {
91
+ hexo.log.info('Requesting OpenAI API... (60 RPM mode)');
92
+ checkTime(0.5);
93
+ }
94
+ }
95
+ else {
96
+ }
97
+ }
98
+ }
99
+ hexo.extend.helper.register('get_summary', (post) => {
100
+ return postMessage(post.path, getContent(post), 'summary', '请为下述文章提供一份200字以内的概括,使用中文回答且尽可能简洁: ');
101
+ });
102
+ hexo.extend.helper.register('get_introduce', () => {
103
+ return hexo.theme.config.summary.introduce;
104
+ });
@@ -6,8 +6,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const injects_1 = __importDefault(require("./lib/injects"));
7
7
  const node_https_1 = __importDefault(require("node:https"));
8
8
  const package_json_1 = require("../../package.json");
9
+ const node_fs_1 = __importDefault(require("node:fs"));
9
10
  hexo.on('generateBefore', () => {
10
11
  (0, injects_1.default)(hexo);
12
+ if (node_fs_1.default.existsSync('request.lock')) {
13
+ node_fs_1.default.unlinkSync('request.lock');
14
+ }
15
+ if (node_fs_1.default.existsSync('requested.lock')) {
16
+ node_fs_1.default.unlinkSync('requested.lock');
17
+ }
11
18
  });
12
19
  hexo.on('generateAfter', () => {
13
20
  node_https_1.default.get('https://api.github.com/repos/theme-shoka-x/hexo-theme-shokaX/releases/latest', {
@@ -14,6 +14,13 @@
14
14
  overflow-x: auto;
15
15
  }
16
16
 
17
+ ul.special::before {
18
+ font-family: ic;
19
+ content: "\e652";
20
+ font-size: x-large;
21
+ padding-left: 1em;
22
+ }
23
+
17
24
  li {
18
25
  position: relative;
19
26
  cursor: pointer;
@@ -27,20 +34,20 @@
27
34
  position: absolute;
28
35
  left: 50%;
29
36
  right: 50%;
30
- top: auto;
37
+ top: 2em;
31
38
  bottom: 0;
32
39
  transition: all .2s ease-in-out;
33
40
  width: auto;
34
41
  height: auto;
35
42
  background: none;
36
- border-radius: 0;
43
+ border-radius: 10px;
37
44
  border-bottom: .125rem solid transparent;
38
45
  }
39
46
 
40
47
  &.active::before {
41
48
  left: 0;
42
49
  right: 0;
43
- border-bottom-color: var(--note-hover, var(--primary-color));
50
+ border-bottom-color: var(--primary-color);
44
51
  }
45
52
  }
46
53
  }
@@ -61,7 +61,7 @@ Object.assign(HTMLElement.prototype, {
61
61
  }
62
62
  return this.getBoundingClientRect().width;
63
63
  },
64
- top: function () {
64
+ getTop: function () {
65
65
  return this.getBoundingClientRect().top;
66
66
  },
67
67
  left: function () {
@@ -296,7 +296,7 @@ const pageScroll = function (target, offset, complete) {
296
296
  targets: typeof offset === 'number' ? target.parentNode : document.scrollingElement,
297
297
  duration: 500,
298
298
  easing: 'easeInOutQuad',
299
- scrollTop: offset || (typeof target === 'number' ? target : (target ? target.top() + document.documentElement.scrollTop - siteNavHeight : 0)),
299
+ scrollTop: offset || (typeof target === 'number' ? target : (target ? target.getTop() + document.documentElement.scrollTop - siteNavHeight : 0)),
300
300
  complete: function () {
301
301
  complete && complete();
302
302
  }
@@ -72,7 +72,7 @@ const postFancybox = function (p) {
72
72
  $dom.each(p + ' p.gallery', function (element) {
73
73
  const box = document.createElement('div');
74
74
  box.className = 'gallery';
75
- box.attr('data-height', element.attr('data-height') || 220);
75
+ box.attr('data-height', String(element.attr('data-height') || 220));
76
76
  box.innerHTML = element.innerHTML.replace(/<br>/g, '');
77
77
  element.parentNode.insertBefore(box, element);
78
78
  element.remove();
@@ -405,7 +405,7 @@ const tabFormat = function () {
405
405
  target.addClass('active');
406
406
  });
407
407
  box.appendChild(element);
408
- element.attr('data-ready', true);
408
+ element.attr('data-ready', String(true));
409
409
  });
410
410
  };
411
411
  const loadComments = function () {
@@ -666,7 +666,6 @@ const siteInit = function () {
666
666
  '.leancloud-recent-comment',
667
667
  'script[data-config]'
668
668
  ],
669
- analytics: false,
670
669
  cacheBust: false
671
670
  });
672
671
  CONFIG.quicklink.ignores = LOCAL.ignores;
@@ -496,7 +496,7 @@ const mediaPlayer = function (t, config) {
496
496
  }
497
497
  playlist.index = index;
498
498
  };
499
- const random = function () {
499
+ const random = () => {
500
500
  const p = utils.random(total);
501
501
  if (playlist.index !== p) {
502
502
  playlist.index = p;
@@ -532,7 +532,7 @@ const mediaPlayer = function (t, config) {
532
532
  this.init();
533
533
  }
534
534
  },
535
- init: () => {
535
+ init: function () {
536
536
  const item = playlist.current();
537
537
  if (!item || item.error) {
538
538
  this.mode();
@@ -608,7 +608,7 @@ const mediaPlayer = function (t, config) {
608
608
  el: null,
609
609
  data: null,
610
610
  index: 0,
611
- create: (box) => {
611
+ create: function (box) {
612
612
  const current = playlist.index;
613
613
  const raw = playlist.current().lrc;
614
614
  const callback = function (body) {