koishi-plugin-cchess 2.4.0 → 2.4.1
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/DESIGN_SYSTEM.md +2 -2
- package/lib/index.js +55 -24
- package/lib/ux.d.ts +13 -2
- package/package.json +1 -1
package/DESIGN_SYSTEM.md
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
- 视觉、组件、形状、排版与语义颜色以 [Material 3 / Expressive](https://m3.material.io/) 为准。
|
|
8
8
|
- [Apple HIG](https://developer.apple.com/design/human-interface-guidelines/accessibility) 用于操作反馈、平台惯例、可恢复性与可访问性,不引入 Apple 视觉组件。
|
|
9
9
|
- [WCAG 2.2 AA](https://www.w3.org/TR/WCAG22/) 用于非文本内容、颜色与对比度、时间限制、输入错误和破坏性操作审查。
|
|
10
|
-
- 色彩使用 Google Material Color Utilities 0.4.0 的 HCT 与 Tonal Spot 动态角色,明确使用 2025 色彩规范。历史 `lch` API 名仅用于源码兼容,计算已经统一为 HCT
|
|
10
|
+
- 色彩使用 Google Material Color Utilities 0.4.0 的 HCT 与 Tonal Spot 动态角色,明确使用 2025 色彩规范。历史 `lch` API 名仅用于源码兼容,计算已经统一为 HCT。彩色角色(primary / secondary / tertiary / error 及其容器)走官方 Tonal Spot;中性面(surface 系列、on-surface 系列、outline 系列)由 HCT 按本设计系统的色调重算——表面留住一点源色味道、文字取深色档,避免成片近白、文字偏浅的发晃感。
|
|
11
11
|
- `m3.ts` 是角色颜色、字阶、间距、圆角、层级和基础组件的唯一源文件。`material-color*.ts` 是固定版本的官方算法生成物,授权见 `THIRD_PARTY_NOTICES.md`。
|
|
12
12
|
- 不额外添加静态截图无法表达的动画;基础 CSS 禁用减少动态效果偏好下的动画和过渡。
|
|
13
13
|
|
|
14
14
|
## 输出、交互与内容
|
|
15
15
|
|
|
16
|
-
1.
|
|
16
|
+
1. 图文模式只发渲染图,不附文字;完整文字只在用户切到「文字」模式时出现。图片的等价文字随图片标记,切换到文字模式时展开,因此不会在群里重复刷屏。
|
|
17
17
|
2. `插件主指令.显示 文字` / `插件主指令.显示 图文` 切换个人显示偏好;同一机器人中的这些插件共享选择。设置保存在内存,重启恢复图文。文本回复不能把后续条目无提示地压掉;较长管理列表分页。
|
|
18
18
|
3. 裸输入必须符合词法、对局状态及参与条件。多个插件匹配时不执行,要求明确完整指令;完整指令继续可用。
|
|
19
19
|
4. 回复说明当前结果、未完成原因和可执行的下一步,不用管理员日志替代用户可用的反馈。退款、赔付与渲染失败不能伪装成功。
|
package/lib/index.js
CHANGED
|
@@ -57,9 +57,10 @@ function usePresentation(ctx, command) {
|
|
|
57
57
|
});
|
|
58
58
|
return {
|
|
59
59
|
textOnly: /* @__PURE__ */ __name((session) => shared.modes.get(userKey(session)) === true, "textOnly"),
|
|
60
|
+
/** 图文模式只给图片;图片缺失或用户选了文字模式时才退回文字。 */
|
|
60
61
|
present(session, image, text) {
|
|
61
62
|
if (!image || shared.modes.get(userKey(session))) return text;
|
|
62
|
-
return
|
|
63
|
+
return import_koishi.h.normalize(image);
|
|
63
64
|
}
|
|
64
65
|
};
|
|
65
66
|
}
|
|
@@ -86,15 +87,42 @@ async function directInputConflict(ctx, session) {
|
|
|
86
87
|
return true;
|
|
87
88
|
}
|
|
88
89
|
__name(directInputConflict, "directInputConflict");
|
|
90
|
+
var IMAGE_TEXT_TYPE = "ux-image-text";
|
|
91
|
+
function imageText(text) {
|
|
92
|
+
return (0, import_koishi.h)(IMAGE_TEXT_TYPE, {}, import_koishi.h.normalize(text));
|
|
93
|
+
}
|
|
94
|
+
__name(imageText, "imageText");
|
|
95
|
+
function isImage(element) {
|
|
96
|
+
return element.type === "img" || element.type === "image";
|
|
97
|
+
}
|
|
98
|
+
__name(isImage, "isImage");
|
|
99
|
+
function isImageText(element) {
|
|
100
|
+
return element.type === IMAGE_TEXT_TYPE;
|
|
101
|
+
}
|
|
102
|
+
__name(isImageText, "isImageText");
|
|
103
|
+
function imagesOnly(content) {
|
|
104
|
+
const walk = /* @__PURE__ */ __name((elements) => elements.flatMap((element) => {
|
|
105
|
+
if (isImageText(element)) return [];
|
|
106
|
+
if (isImage(element) || !element.children.length) return [element];
|
|
107
|
+
return [(0, import_koishi.h)(element.type, element.attrs, walk(element.children))];
|
|
108
|
+
}), "walk");
|
|
109
|
+
return walk(import_koishi.h.normalize(content));
|
|
110
|
+
}
|
|
111
|
+
__name(imagesOnly, "imagesOnly");
|
|
89
112
|
function withoutImages(content) {
|
|
90
113
|
const walk = /* @__PURE__ */ __name((elements) => elements.flatMap((element) => {
|
|
91
|
-
if (element
|
|
114
|
+
if (isImage(element)) return [];
|
|
115
|
+
if (isImageText(element)) return walk(element.children);
|
|
92
116
|
if (element.children.length) return [(0, import_koishi.h)(element.type, element.attrs, walk(element.children))];
|
|
93
117
|
return [element];
|
|
94
118
|
}), "walk");
|
|
95
119
|
return walk(import_koishi.h.normalize(content));
|
|
96
120
|
}
|
|
97
121
|
__name(withoutImages, "withoutImages");
|
|
122
|
+
function choosePresentation(content, textOnly) {
|
|
123
|
+
return textOnly ? withoutImages(content) : imagesOnly(content);
|
|
124
|
+
}
|
|
125
|
+
__name(choosePresentation, "choosePresentation");
|
|
98
126
|
|
|
99
127
|
// src/index.ts
|
|
100
128
|
var import_koishi2 = require("koishi");
|
|
@@ -5106,9 +5134,13 @@ function harmonize(hex, tone, chroma = 48, fallbackHue = 0) {
|
|
|
5106
5134
|
}
|
|
5107
5135
|
__name(harmonize, "harmonize");
|
|
5108
5136
|
var SPACING = { xs: 4, sm: 8, md: 12, lg: 16, xl: 24, xxl: 32 };
|
|
5137
|
+
var NEUTRAL_CHROMA = 6;
|
|
5138
|
+
var NEUTRAL_VARIANT_CHROMA = 12;
|
|
5109
5139
|
function scheme(hue, dark = false, options = {}) {
|
|
5110
5140
|
const source = Hct.from(hue, options.chroma ?? 56, 50);
|
|
5111
5141
|
const dynamic = new SchemeTonalSpot(source, dark, 0, "2025");
|
|
5142
|
+
const neutral = /* @__PURE__ */ __name((tone) => hexFromArgb(Hct.from(hue, NEUTRAL_CHROMA, tone).toInt()), "neutral");
|
|
5143
|
+
const variant = /* @__PURE__ */ __name((tone) => hexFromArgb(Hct.from(hue, NEUTRAL_VARIANT_CHROMA, tone).toInt()), "variant");
|
|
5112
5144
|
return {
|
|
5113
5145
|
primary: hexFromArgb(dynamic.primary),
|
|
5114
5146
|
onPrimary: hexFromArgb(dynamic.onPrimary),
|
|
@@ -5126,23 +5158,23 @@ function scheme(hue, dark = false, options = {}) {
|
|
|
5126
5158
|
onError: hexFromArgb(dynamic.onError),
|
|
5127
5159
|
errorContainer: hexFromArgb(dynamic.errorContainer),
|
|
5128
5160
|
onErrorContainer: hexFromArgb(dynamic.onErrorContainer),
|
|
5129
|
-
background:
|
|
5130
|
-
onBackground:
|
|
5131
|
-
surface:
|
|
5132
|
-
onSurface:
|
|
5133
|
-
surfaceVariant:
|
|
5134
|
-
onSurfaceVariant:
|
|
5135
|
-
surfaceDim:
|
|
5136
|
-
surfaceBright:
|
|
5137
|
-
surfaceContainerLowest:
|
|
5138
|
-
surfaceContainerLow:
|
|
5139
|
-
surfaceContainer:
|
|
5140
|
-
surfaceContainerHigh:
|
|
5141
|
-
surfaceContainerHighest:
|
|
5142
|
-
outline:
|
|
5143
|
-
outlineVariant:
|
|
5144
|
-
inverseSurface:
|
|
5145
|
-
inverseOnSurface:
|
|
5161
|
+
background: dark ? neutral(6) : neutral(97),
|
|
5162
|
+
onBackground: dark ? neutral(90) : neutral(10),
|
|
5163
|
+
surface: dark ? neutral(6) : neutral(97),
|
|
5164
|
+
onSurface: dark ? neutral(90) : neutral(10),
|
|
5165
|
+
surfaceVariant: dark ? variant(30) : variant(90),
|
|
5166
|
+
onSurfaceVariant: dark ? variant(80) : variant(30),
|
|
5167
|
+
surfaceDim: dark ? neutral(6) : neutral(88),
|
|
5168
|
+
surfaceBright: dark ? neutral(24) : neutral(98),
|
|
5169
|
+
surfaceContainerLowest: dark ? neutral(4) : neutral(100),
|
|
5170
|
+
surfaceContainerLow: dark ? neutral(10) : neutral(96),
|
|
5171
|
+
surfaceContainer: dark ? neutral(12) : neutral(94),
|
|
5172
|
+
surfaceContainerHigh: dark ? neutral(17) : neutral(92),
|
|
5173
|
+
surfaceContainerHighest: dark ? neutral(22) : neutral(90),
|
|
5174
|
+
outline: dark ? variant(60) : variant(50),
|
|
5175
|
+
outlineVariant: dark ? variant(30) : variant(80),
|
|
5176
|
+
inverseSurface: dark ? neutral(90) : neutral(20),
|
|
5177
|
+
inverseOnSurface: dark ? neutral(20) : neutral(95),
|
|
5146
5178
|
inversePrimary: hexFromArgb(dynamic.inversePrimary),
|
|
5147
5179
|
scrim: hexFromArgb(dynamic.scrim),
|
|
5148
5180
|
shadow: hexFromArgb(dynamic.shadow)
|
|
@@ -5970,13 +6002,12 @@ function apply(ctx, config) {
|
|
|
5970
6002
|
}));
|
|
5971
6003
|
const text = `棋盘:轮到${convertTurnToString(game.turn)}。坐标 a–i 自左向右,0–9 自红方底线向黑方。
|
|
5972
6004
|
${pieces.join(";")}`;
|
|
5973
|
-
|
|
5974
|
-
if (config.disableImages) return description;
|
|
6005
|
+
if (config.disableImages) return text;
|
|
5975
6006
|
try {
|
|
5976
|
-
return import_koishi2.h.image(await drawChessBoard(channelId), imageMimeType).toString() +
|
|
6007
|
+
return import_koishi2.h.image(await drawChessBoard(channelId), imageMimeType).toString() + imageText(import_koishi2.h.text(text)).toString();
|
|
5977
6008
|
} catch (error) {
|
|
5978
6009
|
logger.warn("棋盘图片生成失败:%s", error.message);
|
|
5979
|
-
return
|
|
6010
|
+
return text;
|
|
5980
6011
|
}
|
|
5981
6012
|
}
|
|
5982
6013
|
__name(renderBoard, "renderBoard");
|
|
@@ -7261,7 +7292,7 @@ ${pieces.join(";")}`;
|
|
|
7261
7292
|
const sentMessages = {};
|
|
7262
7293
|
async function sendMessage(session, message) {
|
|
7263
7294
|
const { bot, channelId } = session;
|
|
7264
|
-
const [messageId] = await session.send(presentation.textOnly(session)
|
|
7295
|
+
const [messageId] = await session.send(choosePresentation(message, presentation.textOnly(session)));
|
|
7265
7296
|
if (presentation.textOnly(session) || config.retractDelay === 0 || !messageId) return;
|
|
7266
7297
|
const previousMessageId = sentMessages[channelId];
|
|
7267
7298
|
sentMessages[channelId] = messageId;
|
package/lib/ux.d.ts
CHANGED
|
@@ -3,9 +3,10 @@ type Owner = {
|
|
|
3
3
|
name: string;
|
|
4
4
|
matches: (session: Session) => boolean | Promise<boolean>;
|
|
5
5
|
};
|
|
6
|
-
/**
|
|
6
|
+
/** 图文模式默认只发渲染图;完整文字只在用户切到「文字」模式时出现。偏好只影响本人。 */
|
|
7
7
|
export declare function usePresentation(ctx: Context, command: string): {
|
|
8
8
|
textOnly: (session: Session) => boolean;
|
|
9
|
+
/** 图文模式只给图片;图片缺失或用户选了文字模式时才退回文字。 */
|
|
9
10
|
present(session: Session, image: h.Fragment | null | undefined, text: h.Fragment): h.Fragment;
|
|
10
11
|
};
|
|
11
12
|
/** Plugins register their active input grammar; overlapping messages are never executed. */
|
|
@@ -14,7 +15,17 @@ export declare function directInputConflict(ctx: Context, session: Session): Pro
|
|
|
14
15
|
/** No hidden time limit: users can extend the non-game input step without losing context. */
|
|
15
16
|
export declare function promptInput(session: Session, instruction: string): Promise<string | undefined>;
|
|
16
17
|
export declare const IMAGE_FAILURE = "\u56FE\u7247\u6682\u65F6\u65E0\u6CD5\u751F\u6210\uFF0C\u5DF2\u4FDD\u7559\u6587\u5B57\u5185\u5BB9\u3002\u53EF\u4EE5\u7A0D\u540E\u91CD\u8BD5\uFF1B\u82E5\u6301\u7EED\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u3002";
|
|
17
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* 渲染图的等价文字。图文模式随图片一起丢掉、文字模式展开成正文,
|
|
20
|
+
* 因此它永远不会原样发到聊天平台。
|
|
21
|
+
*/
|
|
22
|
+
export declare const IMAGE_TEXT_TYPE = "ux-image-text";
|
|
23
|
+
export declare function imageText(text: h.Fragment): h;
|
|
24
|
+
/** 图文模式:保留图片与普通文字,去掉图片的等价文字。 */
|
|
25
|
+
export declare function imagesOnly(content: h.Fragment): h[];
|
|
26
|
+
/** 文字模式:去掉图片,把等价文字展开成普通文本。 */
|
|
18
27
|
export declare function withoutImages(content: h.Fragment): h[];
|
|
28
|
+
/** 发送前的统一选择:文字模式去掉图片,图文模式去掉等价文字。 */
|
|
29
|
+
export declare function choosePresentation(content: h.Fragment, textOnly: boolean): h[];
|
|
19
30
|
export declare function isTextOnly(ctx: Context, session: Session): boolean;
|
|
20
31
|
export {};
|