feat: 版本机制; fix: fix: 绑定设备提示

This commit is contained in:
bietiaop 2024-08-20 13:29:19 +08:00
parent d34c1d8be1
commit 8425503797
16 changed files with 820 additions and 59 deletions

View file

@ -1,40 +1,54 @@
# 1.4.2
* 版本机制
# 1.4.1 # 1.4.1
* 绑定设备 * 绑定设备
* 优化部分代码 * 优化部分代码
# 1.4 # 1.4
* 添加 `练度统计` 功能,发送 `%练度统计``%练度` 查看 * 添加 `练度统计` 功能,发送 `%练度统计``%练度` 查看
# 1.3 # 1.3
* 添加驱动盘评分 * 添加驱动盘评分
# 1.2 # 1.2
* 添加伤害计算,支持目前为止所有 `驱动盘` 以及 `艾莲``朱鸢` 的伤害计算,`强攻武器` 支持 `B` 级以上。 * 添加伤害计算,支持目前为止所有 `驱动盘` 以及 `艾莲``朱鸢` 的伤害计算,`强攻武器` 支持 `B` 级以上。
* 修复攻略问题,若有对不上的问题,请“刷新攻略”。 * 修复攻略问题,若有对不上的问题,请“刷新攻略”。
# 1.1 # 1.1
* 支持自定义面板图,详情请查看 `README` * 支持自定义面板图,详情请查看 `README`
# 1.0 # 1.0
* 重构帮助指令,发送 `%帮助` * 重构帮助指令,发送 `%帮助`
# 0.3 # 0.3
* 修复攻略图角色“本”图片错误 * 修复攻略图角色“本”图片错误
* 将 `mysid` 比较转为字符串,解决部分适配问题 * 将 `mysid` 比较转为字符串,解决部分适配问题
# 0.2 # 0.2
* 添加“式舆防卫战”查询,发送 `%式舆防卫战` 或者 `%深渊` * 添加“式舆防卫战”查询,发送 `%式舆防卫战` 或者 `%深渊`
# 0.1 # 0.1
* 刷新角色面板图片版 * 刷新角色面板图片版
* 优化指令分配 * 优化指令分配
* 添加版本信息 * 添加版本信息
# 0.05 # 0.05
* 支持查看角色面板,发送 `%角色名/别名+面板` * 支持查看角色面板,发送 `%角色名/别名+面板`
* 修复一些问题 * 修复一些问题
# 0.04 # 0.04
* 支持获取抽卡链接,发送 `%获取抽卡链接` * 支持获取抽卡链接,发送 `%获取抽卡链接`
* 支持面板刷新,发送 `%刷新面板` * 支持面板刷新,发送 `%刷新面板`

View file

@ -189,6 +189,27 @@ const helpData = [
needSK: false, needSK: false,
commands: ['解绑设备'], commands: ['解绑设备'],
}, },
{
title: '更新日志',
desc: '查看插件的Commit日志',
needCK: false,
needSK: false,
commands: ['[插件]更新日志'],
},
{
title: '版本',
desc: '查看插件版本日志',
needCK: false,
needSK: false,
commands: ['[插件]版本'],
},
{
title: '检查更新',
desc: '检查插件是否更新',
needCK: false,
needSK: false,
commands: ['[插件]检查更新'],
},
], ],
}, },
]; ];

View file

@ -60,6 +60,18 @@ export class Panel extends ZZZPlugin {
reg: `${rulePrefix}删除(\\S+)(角色|面板)图(.+)$`, reg: `${rulePrefix}删除(\\S+)(角色|面板)图(.+)$`,
fnc: 'deleteCharacterImg', fnc: 'deleteCharacterImg',
}, },
{
reg: `${rulePrefix}(插件)?版本$`,
fnc: 'getChangeLog',
},
{
reg: `^${rulePrefix}(插件)?更新日志$`,
fnc: 'getCommitLog',
},
{
reg: `^${rulePrefix}(插件)?检查更新$`,
fnc: 'hasUpdate',
},
], ],
}); });
@ -75,5 +87,8 @@ export class Panel extends ZZZPlugin {
this.uploadCharacterImg = manage.panel.uploadCharacterImg; this.uploadCharacterImg = manage.panel.uploadCharacterImg;
this.getCharacterImages = manage.panel.getCharacterImages; this.getCharacterImages = manage.panel.getCharacterImages;
this.deleteCharacterImg = manage.panel.deleteCharacterImg; this.deleteCharacterImg = manage.panel.deleteCharacterImg;
this.getChangeLog = manage.version.getChangeLog;
this.getCommitLog = manage.version.getCommitLog;
this.hasUpdate = manage.version.hasUpdate;
} }
} }

View file

@ -8,10 +8,13 @@ import * as alias from './alias.js';
import * as panel from './panel.js'; import * as panel from './panel.js';
import * as version from './version.js';
export default { export default {
assets, assets,
guides, guides,
config, config,
alias, alias,
panel, panel,
version,
}; };

49
apps/manage/version.js Normal file
View file

@ -0,0 +1,49 @@
import version from '../../lib/version.js';
import render from '../../lib/render.js';
import { ZZZUpdate } from '../../lib/update.js';
import { pluginName } from '../../lib/path.js';
export async function getChangeLog() {
const versionData = version.changelogs;
await render(this.e, 'help/version.html', {
versionData,
});
return false;
}
export async function getCommitLog() {
if (!ZZZUpdate) return false;
let updatePlugin = new ZZZUpdate();
updatePlugin.e = this.e;
updatePlugin.reply = this.reply;
if (updatePlugin.getPlugin(pluginName)) {
try {
const commitData = await updatePlugin.getZZZAllLog();
await render(this.e, 'help/commit.html', {
commitData,
});
} catch (error) {
this.reply(`[${pluginName}]获取更新日志失败\n${error.message}`);
}
}
return true;
}
export async function hasUpdate() {
if (!ZZZUpdate) return false;
let updatePlugin = new ZZZUpdate();
updatePlugin.e = this.e;
updatePlugin.reply = this.reply;
if (updatePlugin.getPlugin(pluginName)) {
const result = await updatePlugin.hasUpdate();
if (result.hasUpdate) {
await this.reply(`[${pluginName}]有${result.logs.length || 1}个更新`);
await render(this.e, 'help/commit.html', {
commitData: result.logs,
});
} else {
await this.reply(`[${pluginName}]已是最新`);
}
}
return true;
}

View file

@ -1,15 +1,8 @@
import _ from 'lodash' import _ from 'lodash';
import { rulePrefix } from '../lib/common.js' import { rulePrefix } from '../lib/common.js';
import { pluginName } from '../lib/path.js' import { pluginName } from '../lib/path.js';
import settings from '../lib/settings.js' import settings from '../lib/settings.js';
import { ZZZUpdate } from '../lib/update.js';
let Update = null
try {
Update = (await import("../../other/update.js").catch(e => null))?.update
Update ||= (await import("../../system/apps/update.ts")).update
} catch (e) {
logger.error(`[${pluginName}]未获取到更新js ${logger.yellow("更新功能")} 将无法使用`)
}
export class update extends plugin { export class update extends plugin {
constructor() { constructor() {
@ -23,30 +16,15 @@ export class update extends plugin {
reg: `^${rulePrefix}(插件)?(强制)?更新(插件)?$`, reg: `^${rulePrefix}(插件)?(强制)?更新(插件)?$`,
fnc: 'update', fnc: 'update',
}, },
{
reg: `^${rulePrefix}(插件)?更新日志$`,
fnc: 'update_log',
}
], ],
}) });
} }
async update(e = this.e) { async update(e = this.e) {
if (!e.isMaster) return if (!e.isMaster || !ZZZUpdate) return false;
e.msg = `#${e.msg.includes("强制") ? "强制" : ""}更新${pluginName}` e.msg = `#${e.msg.includes('强制') ? '强制' : ''}更新${pluginName}`;
const up = new Update(e) const up = new ZZZUpdate(e);
up.e = e up.e = e;
return up.update() return up.update();
}
async update_log() {
let Update_Plugin = new Update()
Update_Plugin.e = this.e
Update_Plugin.reply = this.reply
if (Update_Plugin.getPlugin(pluginName)) {
this.e.reply(await Update_Plugin.getLog(pluginName))
}
return true
} }
} }

View file

@ -108,7 +108,7 @@ export class Panel extends ZZZPlugin {
'1. 使用抓包软件抓取米游社APP的请求', '1. 使用抓包软件抓取米游社APP的请求',
'2. 在请求头内找到【x-rpc-device_id】和【x-rpc-device_fp】', '2. 在请求头内找到【x-rpc-device_id】和【x-rpc-device_fp】',
'3. 自行构造如下格式的信息:', '3. 自行构造如下格式的信息:',
' {device_id: "x-rpc-device_id的内容", device_fp: "x-rpc-device_fp的内容"}', ' {"device_id": "x-rpc-device_id的内容", "device_fp": "x-rpc-device_fp的内容"}',
'4. 给机器人发送"%绑定设备"指令', '4. 给机器人发送"%绑定设备"指令',
'5. 机器人会提示发送设备信息', '5. 机器人会提示发送设备信息',
'6. 粘贴自行构造的信息发送', '6. 粘贴自行构造的信息发送',

105
lib/update.js Normal file
View file

@ -0,0 +1,105 @@
import _ from 'lodash';
import { pluginName } from '../lib/path.js';
import { mdLogLineToHTML } from '../utils/data.js';
let Update = null;
try {
Update = (await import('../../other/update.js').catch(e => null))?.update;
Update ||= (await import('../../system/apps/update.ts')).update;
} catch (e) {
logger.error(
`[${pluginName}]未获取到更新js ${logger.yellow('更新功能')} 将无法使用`
);
}
let ZZZUpdate = null;
/**
* @typedef {Object} CommitLog
* @property {string} commit 提交ID
* @property {string} date 提交时间
* @property {string} msg 提交信息
* @property {boolean} local 是否本地记录
* @property {current} boolean 是否当前版本
*/
/**
* @typedef {Object} UpdateInfo
* @property {boolean} hasUpdate 是否有更新
* @property {CommitLog[]} logs 更新日志
*/
if (Update) {
ZZZUpdate = class ZZZUpdate extends Update {
async handleLog(remote = false) {
let cmdStr = 'git log -100 --pretty="%h||%cd||%s" --date=format:"%F %T"';
if (remote) {
cmdStr =
'git log -100 --pretty="%h||%cd||%s" --date=format:"%F %T" origin/main';
}
const cm = await this.exec(cmdStr, pluginName);
if (cm.error) {
throw new Error(cm.error.message);
}
const logAll = cm.stdout.split('\n');
if (!logAll.length) {
throw new Error('未获取到更新日志');
}
/** @type CommitLog[] */
const log = [];
let current = true;
for (let str of logAll) {
str = str.split('||');
if (str[0] === this.oldCommitId) break;
if (str[2].includes('Merge')) continue;
/** @type CommitLog */
const commit = {
commit: str[0],
date: str[1],
msg: mdLogLineToHTML(str[2]),
local: !remote,
current: false,
};
if (!remote && current) {
commit.current = true;
current = false;
}
log.push(commit);
}
return log;
}
async getZZZLog() {
const log = await this.handleLog();
return log;
}
async getZZZRemoteLog() {
const log = await this.handleLog(true);
return log;
}
async getZZZAllLog() {
const localLog = await this.getZZZLog();
const remoteLog = await this.getZZZRemoteLog();
const logs = _.unionBy(localLog, remoteLog, 'commit');
logs.sort((a, b) => {
return new Date(b.date) - new Date(a.date);
});
return logs;
}
async hasUpdate() {
const logs = await this.getZZZAllLog();
const newLogs = logs.filter(log => !log.local);
/** @type UpdateInfo */
let result = {
hasUpdate: false,
logs: [],
};
if (newLogs.length) {
result.hasUpdate = true;
result.logs = newLogs;
}
return result;
}
};
}
export { ZZZUpdate };

View file

@ -2,6 +2,7 @@ import fs from 'fs';
import lodash from 'lodash'; import lodash from 'lodash';
import path from 'path'; import path from 'path';
import { pluginPath } from './path.js'; import { pluginPath } from './path.js';
import { mdLogLineToHTML } from '../utils/data.js';
// 更新日志文件位置 // 更新日志文件位置
const _logPath = path.join(pluginPath, 'CHANGELOG.md'); const _logPath = path.join(pluginPath, 'CHANGELOG.md');
@ -21,26 +22,6 @@ let versionCount = 4;
// 读取 package.json此处为读取Yunzai-Bot的package.json // 读取 package.json此处为读取Yunzai-Bot的package.json
let packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')); let packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
/**
* Markdown 行转换为 HTML
* @param {*} line
* @returns
*/
const getLine = function (line) {
// 去除行首空格和换行符
line = line.replace(/(^\s*\*|\r)/g, '');
// 替换行内代码块
line = line.replace(/\s*`([^`]+`)/g, '<span class="cmd">$1');
line = line.replace(/`\s*/g, '</span>');
// 替换行内加粗
line = line.replace(/\s*\*\*([^\*]+\*\*)/g, '<span class="strong">$1');
line = line.replace(/\*\*\s*/g, '</span>');
// 替换行内表示更新内容
line = line.replace(/ⁿᵉʷ/g, '<span class="new"></span>');
// 返回转换后的行内容HTML
return line;
};
// 尝试读取更新日志文件 // 尝试读取更新日志文件
try { try {
if (fs.existsSync(_logPath)) { if (fs.existsSync(_logPath)) {
@ -54,9 +35,9 @@ try {
let lastLine = {}; let lastLine = {};
lodash.forEach(logs, line => { lodash.forEach(logs, line => {
// 如果版本数量小于0返回false // 如果版本数量小于0返回false
if (versionCount <= -1) { // if (versionCount <= -1) {
return false; // return false;
} // }
// 匹配版本号 // 匹配版本号
const versionRet = /^#\s*([0-9a-zA-Z\\.~\s]+?)\s*$/.exec(line); const versionRet = /^#\s*([0-9a-zA-Z\\.~\s]+?)\s*$/.exec(line);
if (versionRet && versionRet[1]) { if (versionRet && versionRet[1]) {
@ -86,12 +67,12 @@ try {
// 如果行以 * 开头,表示更新内容 // 如果行以 * 开头,表示更新内容
if (/^\*/.test(line)) { if (/^\*/.test(line)) {
lastLine = { lastLine = {
title: getLine(line), title: mdLogLineToHTML(line),
logs: [], logs: [],
}; };
temp.logs.push(lastLine); temp.logs.push(lastLine);
} else if (/^\s{2,}\*/.test(line)) { } else if (/^\s{2,}\*/.test(line)) {
lastLine.logs.push(getLine(line)); lastLine.logs.push(mdLogLineToHTML(line));
} }
} }
}); });

141
resources/help/commit.css Normal file
View file

@ -0,0 +1,141 @@
@charset "UTF-8";
.special-title {
padding: 0;
font-size: 1.2em;
}
.card {
margin: 0 1em;
padding: 1em 0;
}
.card .list {
display: flex;
flex-direction: column;
gap: 0.5em;
font-size: 0.9em;
}
.card .list .item {
background-color: rgba(255, 255, 255, 0.1);
padding: 0.5em 1em;
border-radius: 0.5em;
border: 0.1em solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(0.5em);
position: relative;
}
.card .list .item .version {
filter: drop-shadow(0 0 0.05em #f0d480);
position: relative;
margin-bottom: 0.5em;
font-size: 0.8em;
display: flex;
}
.card .list .item .version .id {
background: linear-gradient(90deg, #ffe6b4, #f2c94c);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
position: relative;
margin-right: 0.5em;
}
.card .list .item .version .id::before {
content: "";
position: absolute;
width: 100%;
height: 0.2em;
bottom: 0;
left: 0;
background: linear-gradient(0deg, #f2c94c, #ffe6b4);
z-index: -1;
border-radius: 0.5em;
}
.card .list .item .version .time {
background: linear-gradient(90deg, #ffe6b4, #f2c94c);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
.card .list .item.current {
background-color: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(1.5em);
}
.card .list .item.current::after {
content: "当前版本";
font-size: 0.8em;
position: absolute;
right: 0.5em;
top: 0.5em;
color: #f2c94c;
opacity: 0.5;
}
.card .list .item.current .version {
filter: drop-shadow(0 0 0.1em rgba(231, 241, 35, 0.3));
font-size: 1em;
}
.card .list .item.current .version .id {
color: #f2784c;
background: none;
background-clip: unset;
-webkit-text-fill-color: unset;
font-size: 0.8em;
padding-top: 0.3em;
}
.card .list .item.current .version .id::before {
background: #f2784c;
}
.card .list .item.current .version .time {
background: linear-gradient(90deg, #f2784c, #ffbca4);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
.card .list .item.newc::after {
content: "NEW";
font-size: 0.4em;
background: linear-gradient(90deg, #f2c94c, #ffe6b4);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 0 0.05em #f0d480);
top: 1em;
right: 1em;
position: absolute;
border: 0.1em solid #f2c94c;
padding: 0.1em 0.3em 0.2em 0.3em;
border-radius: 0.5em;
}
.card .list .item .content {
font-size: 0.8em;
margin: 0 1em;
}
.card .list .item .cmd {
font-size: 0.8em;
background-color: rgba(255, 255, 255, 0.1);
padding: 0.2em 0.4em;
border-radius: 0.5em;
margin: 0em 0.3em;
border: 0.1em solid rgba(255, 255, 255, 0.1);
color: #cadc9e;
}
.card .list .item .strong {
color: #f2c94c;
}
.card .list .item .new {
position: relative;
}
.card .list .item .new::before {
content: "new";
font-size: 0.4em;
background: linear-gradient(90deg, #f2c94c, #ffe6b4);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 0 0.05em #f0d480);
bottom: 1.8em;
left: 0em;
position: relative;
border: 0.1em solid #f2c94c;
padding: 0em 0.3em 0.2em 0.3em;
border-radius: 0.5em;
}
/*# sourceMappingURL=commit.css.map */

View file

@ -0,0 +1,27 @@
{{extend defaultLayout}}
{{block 'css'}}
<link rel="stylesheet" href="{{@sys.currentPath}}/commit.css">
{{/block}}
{{block 'main'}}
<div class="card">
<% include(sys.specialTitle, {en: 'COMMIT' , cn: '更新日志' }) %>
<div class="list">
{{each commitData commit i}}
<div class="item {{commit.current ? 'current' : ''}} {{!commit.local ? 'newc' : ''}}">
<div class="version">
<div class="id no-zzz-font">{{commit.commit}}</div>
<div class="time">{{commit.date}}</div>
</div>
<div class="content no-zzz-font">
{{@commit.msg}}
</div>
</div>
{{/each}}
</div>
</div>
{{/block}}

139
resources/help/commit.scss Normal file
View file

@ -0,0 +1,139 @@
.special-title {
padding: 0;
font-size: 1.2em;
}
.card {
margin: 0 1em;
padding: 1em 0;
.list {
display: flex;
flex-direction: column;
gap: 0.5em;
font-size: 0.9em;
.item {
background-color: rgba(255, 255, 255, 0.1);
padding: 0.5em 1em;
border-radius: 0.5em;
border: 0.1em solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(0.5em);
position: relative;
.version {
filter: drop-shadow(0 0 0.05em #f0d480);
position: relative;
margin-bottom: 0.5em;
font-size: 0.8em;
display: flex;
.id {
background: linear-gradient(90deg, #ffe6b4, #f2c94c);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
position: relative;
margin-right: 0.5em;
&::before {
content: '';
position: absolute;
width: 100%;
height: 0.2em;
bottom: 0;
left: 0;
background: linear-gradient(0deg, #f2c94c, #ffe6b4);
z-index: -1;
border-radius: 0.5em;
}
}
.time {
background: linear-gradient(90deg, #ffe6b4, #f2c94c);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
}
&.current {
background-color: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(1.5em);
&::after {
content: '当前版本';
font-size: 0.8em;
position: absolute;
right: 0.5em;
top: 0.5em;
color: #f2c94c;
opacity: 0.5;
}
.version {
filter: drop-shadow(0 0 0.1em rgba(231, 241, 35, 0.3));
font-size: 1em;
.id {
color: #f2784c;
background: none;
background-clip: unset;
-webkit-text-fill-color: unset;
font-size: 0.8em;
padding-top: 0.3em;
&::before {
background: #f2784c;
}
}
.time {
background: linear-gradient(90deg, #f2784c, #ffbca4);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
&.newc {
&::after {
content: 'NEW';
font-size: 0.4em;
background: linear-gradient(90deg, #f2c94c, #ffe6b4);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 0 0.05em #f0d480);
top: 1em;
right: 1em;
position: absolute;
border: 0.1em solid #f2c94c;
padding: 0.1em 0.3em 0.2em 0.3em;
border-radius: 0.5em;
}
}
.content {
font-size: 0.8em;
margin: 0 1em;
}
.cmd {
font-size: 0.8em;
background-color: rgba(255, 255, 255, 0.1);
padding: 0.2em 0.4em;
border-radius: 0.5em;
margin: 0em 0.3em;
border: 0.1em solid rgba(255, 255, 255, 0.1);
color: #cadc9e;
}
.strong {
color: #f2c94c;
}
.new {
position: relative;
&::before {
content: 'new';
font-size: 0.4em;
background: linear-gradient(90deg, #f2c94c, #ffe6b4);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 0 0.05em #f0d480);
bottom: 1.8em;
left: 0em;
position: relative;
border: 0.1em solid #f2c94c;
padding: 0em 0.3em 0.2em 0.3em;
border-radius: 0.5em;
}
}
}
}
}

122
resources/help/version.css Normal file
View file

@ -0,0 +1,122 @@
@charset "UTF-8";
.special-title {
padding: 0;
font-size: 1.2em;
}
.card {
margin: 0 1em;
padding: 1em 0;
}
.card .list {
display: flex;
flex-direction: column;
gap: 0.5em;
}
.card .list .item {
background-color: rgba(255, 255, 255, 0.1);
padding: 0.5em 1em;
border-radius: 0.5em;
border: 0.1em solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(0.5em);
position: relative;
}
.card .list .item .version {
width: fit-content;
background: linear-gradient(90deg, #ffe6b4, #f2c94c);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 0 0.05em #f0d480);
position: relative;
margin-bottom: 0.5em;
font-size: 0.8em;
}
.card .list .item .version::before {
content: "";
position: absolute;
width: 2em;
height: 0.2em;
bottom: 0;
left: 0;
background: linear-gradient(0deg, #f2c94c, #ffe6b4);
z-index: -1;
border-radius: 0.5em;
}
.card .list .item:nth-child(1) {
background-color: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(1.5em);
}
.card .list .item:nth-child(1)::after {
content: "当前版本";
font-size: 0.8em;
position: absolute;
right: 0.5em;
top: 0.5em;
color: #f2c94c;
opacity: 0.5;
}
.card .list .item:nth-child(1) .version {
background: linear-gradient(90deg, #f2784c, #ffbca4);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 0 0.1em rgba(231, 241, 35, 0.3));
font-size: 1em;
}
.card .list .item:nth-child(1) .version::before {
background: #f2784c;
}
.card .list .item:nth-child(1) .version::after {
content: "";
position: absolute;
width: 0;
height: 0;
border-style: solid;
border-width: 0.3em 0.3em 0 0.3em;
border-color: #f2784c transparent transparent transparent;
bottom: -0.3em;
left: 0.7em;
}
.card .list .item .content {
font-size: 0.8em;
margin: 0 1em;
}
.card .list .item .content ul {
padding-left: 1em;
}
.card .list .item .content ul li {
margin: 0.1em 0;
}
.card .list .item .cmd {
font-size: 0.8em;
background-color: rgba(255, 255, 255, 0.1);
padding: 0.2em 0.4em;
border-radius: 0.5em;
margin: 0em 0.3em;
border: 0.1em solid rgba(255, 255, 255, 0.1);
color: #cadc9e;
}
.card .list .item .strong {
color: #f2c94c;
}
.card .list .item .new {
position: relative;
}
.card .list .item .new::before {
content: "new";
font-size: 0.4em;
background: linear-gradient(90deg, #f2c94c, #ffe6b4);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 0 0.05em #f0d480);
bottom: 1.8em;
left: 0em;
position: relative;
border: 0.1em solid #f2c94c;
padding: 0em 0.3em 0.2em 0.3em;
border-radius: 0.5em;
}
/*# sourceMappingURL=version.css.map */

View file

@ -0,0 +1,28 @@
{{extend defaultLayout}}
{{block 'css'}}
<link rel="stylesheet" href="{{@sys.currentPath}}/version.css">
{{/block}}
{{block 'main'}}
<div class="card">
<% include(sys.specialTitle, {en: 'VERSION' , cn: '版本日志' }) %>
<div class="list">
{{each versionData version i}}
<div class="item">
<div class="version">ver {{version.version}}</div>
<div class="content no-zzz-font">
<ul>
{{each version.logs log1 j}}
<li>{{@log1.title}}</li>
{{each log1.logs log2 k}}
<li>{{@log2.title}}</li>
{{/each}}
{{/each}}
</ul>
</div>
</div>
{{/each}}
</div>
</div>
{{/block}}

118
resources/help/version.scss Normal file
View file

@ -0,0 +1,118 @@
.special-title {
padding: 0;
font-size: 1.2em;
}
.card {
margin: 0 1em;
padding: 1em 0;
.list {
display: flex;
flex-direction: column;
gap: 0.5em;
.item {
background-color: rgba(255, 255, 255, 0.1);
padding: 0.5em 1em;
border-radius: 0.5em;
border: 0.1em solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(0.5em);
position: relative;
.version {
width: fit-content;
background: linear-gradient(90deg, #ffe6b4, #f2c94c);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 0 0.05em #f0d480);
position: relative;
margin-bottom: 0.5em;
font-size: 0.8em;
&::before {
content: '';
position: absolute;
width: 2em;
height: 0.2em;
bottom: 0;
left: 0;
background: linear-gradient(0deg, #f2c94c, #ffe6b4);
z-index: -1;
border-radius: 0.5em;
}
}
&:nth-child(1) {
background-color: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(1.5em);
&::after {
content: '当前版本';
font-size: 0.8em;
position: absolute;
right: 0.5em;
top: 0.5em;
color: #f2c94c;
opacity: 0.5;
}
.version {
background: linear-gradient(90deg, #f2784c, #ffbca4);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 0 0.1em rgba(231, 241, 35, 0.3));
font-size: 1em;
&::before {
background: #f2784c;
}
&::after {
content: '';
position: absolute;
width: 0;
height: 0;
border-style: solid;
border-width: 0.3em 0.3em 0 0.3em;
border-color: #f2784c transparent transparent transparent;
bottom: -0.3em;
left: 0.7em;
}
}
}
.content {
font-size: 0.8em;
margin: 0 1em;
ul {
padding-left: 1em;
li {
margin: 0.1em 0;
}
}
}
.cmd {
font-size: 0.8em;
background-color: rgba(255, 255, 255, 0.1);
padding: 0.2em 0.4em;
border-radius: 0.5em;
margin: 0em 0.3em;
border: 0.1em solid rgba(255, 255, 255, 0.1);
color: #cadc9e;
}
.strong {
color: #f2c94c;
}
.new {
position: relative;
&::before {
content: 'new';
font-size: 0.4em;
background: linear-gradient(90deg, #f2c94c, #ffe6b4);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
filter: drop-shadow(0 0 0.05em #f0d480);
bottom: 1.8em;
left: 0em;
position: relative;
border: 0.1em solid #f2c94c;
padding: 0em 0.3em 0.2em 0.3em;
border-radius: 0.5em;
}
}
}
}
}

View file

@ -25,3 +25,23 @@ export const generateSeed = (length = 16) => {
} }
return result; return result;
}; };
/**
* Markdown 日志行转换为 HTML
* @param {*} line
* @returns
*/
export const mdLogLineToHTML = function (line) {
// 去除行首空格和换行符
line = line.replace(/(^\s*\*|\r)/g, '');
// 替换行内代码块
line = line.replace(/\s*`([^`]+`)/g, '<span class="cmd">$1');
line = line.replace(/`\s*/g, '</span>');
// 替换行内加粗
line = line.replace(/\s*\*\*([^\*]+\*\*)/g, '<span class="strong">$1');
line = line.replace(/\*\*\s*/g, '</span>');
// 替换行内表示更新内容
line = line.replace(/ⁿᵉʷ/g, '<span class="new"></span>');
// 返回转换后的行内容HTML
return line.trim();
};