koishi-plugin-wordle-game 4.2.0 → 4.2.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 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 [...import_koishi.h.normalize(image), (0, import_koishi.h)("p", {}, import_koishi.h.normalize(text))];
63
+ return import_koishi.h.normalize(image);
63
64
  }
64
65
  };
65
66
  }
@@ -96,15 +97,42 @@ async function promptInput(session, instruction) {
96
97
  }
97
98
  }
98
99
  __name(promptInput, "promptInput");
100
+ var IMAGE_TEXT_TYPE = "ux-image-text";
101
+ function imageText(text) {
102
+ return (0, import_koishi.h)(IMAGE_TEXT_TYPE, {}, import_koishi.h.normalize(text));
103
+ }
104
+ __name(imageText, "imageText");
105
+ function isImage(element) {
106
+ return element.type === "img" || element.type === "image";
107
+ }
108
+ __name(isImage, "isImage");
109
+ function isImageText(element) {
110
+ return element.type === IMAGE_TEXT_TYPE;
111
+ }
112
+ __name(isImageText, "isImageText");
113
+ function imagesOnly(content) {
114
+ const walk = /* @__PURE__ */ __name((elements) => elements.flatMap((element) => {
115
+ if (isImageText(element)) return [];
116
+ if (isImage(element) || !element.children.length) return [element];
117
+ return [(0, import_koishi.h)(element.type, element.attrs, walk(element.children))];
118
+ }), "walk");
119
+ return walk(import_koishi.h.normalize(content));
120
+ }
121
+ __name(imagesOnly, "imagesOnly");
99
122
  function withoutImages(content) {
100
123
  const walk = /* @__PURE__ */ __name((elements) => elements.flatMap((element) => {
101
- if (element.type === "img" || element.type === "image") return [];
124
+ if (isImage(element)) return [];
125
+ if (isImageText(element)) return walk(element.children);
102
126
  if (element.children.length) return [(0, import_koishi.h)(element.type, element.attrs, walk(element.children))];
103
127
  return [element];
104
128
  }), "walk");
105
129
  return walk(import_koishi.h.normalize(content));
106
130
  }
107
131
  __name(withoutImages, "withoutImages");
132
+ function choosePresentation(content, textOnly) {
133
+ return textOnly ? withoutImages(content) : imagesOnly(content);
134
+ }
135
+ __name(choosePresentation, "choosePresentation");
108
136
  function isTextOnly(ctx, session) {
109
137
  return state(ctx).modes.get(userKey(session)) === true;
110
138
  }
@@ -709,7 +737,7 @@ __name(processExtraGameRecords, "processExtraGameRecords");
709
737
  async function sendMessage(g, session, message) {
710
738
  const config = g.config;
711
739
  const { bot, channelId } = session;
712
- const [messageId] = await session.send(isTextOnly(g.ctx, session) ? withoutImages(message) : message);
740
+ const [messageId] = await session.send(choosePresentation(message, isTextOnly(g.ctx, session)));
713
741
  if (!isTextOnly(g.ctx, session) && config.retractDelay > 0 && messageId) {
714
742
  const prevMessage = g.lastMessageInfo.get(channelId);
715
743
  if (prevMessage) {
@@ -5804,9 +5832,13 @@ function onColor(background) {
5804
5832
  }
5805
5833
  __name(onColor, "onColor");
5806
5834
  var SPACING = { xs: 4, sm: 8, md: 12, lg: 16, xl: 24, xxl: 32 };
5835
+ var NEUTRAL_CHROMA = 6;
5836
+ var NEUTRAL_VARIANT_CHROMA = 12;
5807
5837
  function scheme(hue, dark = false, options = {}) {
5808
5838
  const source = Hct.from(hue, options.chroma ?? 56, 50);
5809
5839
  const dynamic = new SchemeTonalSpot(source, dark, 0, "2025");
5840
+ const neutral = /* @__PURE__ */ __name((tone) => hexFromArgb(Hct.from(hue, NEUTRAL_CHROMA, tone).toInt()), "neutral");
5841
+ const variant = /* @__PURE__ */ __name((tone) => hexFromArgb(Hct.from(hue, NEUTRAL_VARIANT_CHROMA, tone).toInt()), "variant");
5810
5842
  return {
5811
5843
  primary: hexFromArgb(dynamic.primary),
5812
5844
  onPrimary: hexFromArgb(dynamic.onPrimary),
@@ -5824,23 +5856,23 @@ function scheme(hue, dark = false, options = {}) {
5824
5856
  onError: hexFromArgb(dynamic.onError),
5825
5857
  errorContainer: hexFromArgb(dynamic.errorContainer),
5826
5858
  onErrorContainer: hexFromArgb(dynamic.onErrorContainer),
5827
- background: hexFromArgb(dynamic.background),
5828
- onBackground: hexFromArgb(dynamic.onBackground),
5829
- surface: hexFromArgb(dynamic.surface),
5830
- onSurface: hexFromArgb(dynamic.onSurface),
5831
- surfaceVariant: hexFromArgb(dynamic.surfaceVariant),
5832
- onSurfaceVariant: hexFromArgb(dynamic.onSurfaceVariant),
5833
- surfaceDim: hexFromArgb(dynamic.surfaceDim),
5834
- surfaceBright: hexFromArgb(dynamic.surfaceBright),
5835
- surfaceContainerLowest: hexFromArgb(dynamic.surfaceContainerLowest),
5836
- surfaceContainerLow: hexFromArgb(dynamic.surfaceContainerLow),
5837
- surfaceContainer: hexFromArgb(dynamic.surfaceContainer),
5838
- surfaceContainerHigh: hexFromArgb(dynamic.surfaceContainerHigh),
5839
- surfaceContainerHighest: hexFromArgb(dynamic.surfaceContainerHighest),
5840
- outline: hexFromArgb(dynamic.outline),
5841
- outlineVariant: hexFromArgb(dynamic.outlineVariant),
5842
- inverseSurface: hexFromArgb(dynamic.inverseSurface),
5843
- inverseOnSurface: hexFromArgb(dynamic.inverseOnSurface),
5859
+ background: dark ? neutral(6) : neutral(97),
5860
+ onBackground: dark ? neutral(90) : neutral(10),
5861
+ surface: dark ? neutral(6) : neutral(97),
5862
+ onSurface: dark ? neutral(90) : neutral(10),
5863
+ surfaceVariant: dark ? variant(30) : variant(90),
5864
+ onSurfaceVariant: dark ? variant(80) : variant(30),
5865
+ surfaceDim: dark ? neutral(6) : neutral(88),
5866
+ surfaceBright: dark ? neutral(24) : neutral(98),
5867
+ surfaceContainerLowest: dark ? neutral(4) : neutral(100),
5868
+ surfaceContainerLow: dark ? neutral(10) : neutral(96),
5869
+ surfaceContainer: dark ? neutral(12) : neutral(94),
5870
+ surfaceContainerHigh: dark ? neutral(17) : neutral(92),
5871
+ surfaceContainerHighest: dark ? neutral(22) : neutral(90),
5872
+ outline: dark ? variant(60) : variant(50),
5873
+ outlineVariant: dark ? variant(30) : variant(80),
5874
+ inverseSurface: dark ? neutral(90) : neutral(20),
5875
+ inverseOnSurface: dark ? neutral(20) : neutral(95),
5844
5876
  inversePrimary: hexFromArgb(dynamic.inversePrimary),
5845
5877
  scrim: hexFromArgb(dynamic.scrim),
5846
5878
  shadow: hexFromArgb(dynamic.shadow)
@@ -6136,13 +6168,14 @@ __name(resource, "resource");
6136
6168
  // src/services/renderer.ts
6137
6169
  var HUE = 142;
6138
6170
  var imageDescriptions = /* @__PURE__ */ new WeakMap();
6139
- function imageText(buffer) {
6171
+ function imageText2(buffer) {
6140
6172
  return imageDescriptions.get(buffer) ?? "棋盘说明暂不可用,可发送「wordle.查询进度」。";
6141
6173
  }
6142
- __name(imageText, "imageText");
6174
+ __name(imageText2, "imageText");
6143
6175
  function imageMessage(buffer, type) {
6144
- const text = imageText(buffer) ?? "图片内容请使用「wordle.查询进度」查询。";
6145
- return (0, import_koishi3.h)("p", {}, [...buffer.length ? [import_koishi3.h.image(buffer, type)] : [], (0, import_koishi3.h)("p", {}, import_koishi3.h.text(text))]);
6176
+ const text = imageText2(buffer) ?? "图片内容请使用「wordle.查询进度」查询。";
6177
+ if (!buffer.length) return (0, import_koishi3.h)("p", {}, import_koishi3.h.text(text));
6178
+ return (0, import_koishi3.h)("p", {}, [import_koishi3.h.image(buffer, type), imageText(import_koishi3.h.text(text))]);
6146
6179
  }
6147
6180
  __name(imageMessage, "imageMessage");
6148
6181
  var PANEL_WIDTH = 611;
@@ -17556,7 +17589,7 @@ function generateEmptyGridHtmlForHandle(rowNum, tileNum) {
17556
17589
  __name(generateEmptyGridHtmlForHandle, "generateEmptyGridHtmlForHandle");
17557
17590
  function generateImageTags(buffers) {
17558
17591
  return buffers.map((buffer, index) => {
17559
- const description = `棋盘 ${index + 1}:${imageText(buffer)}`;
17592
+ const description = `棋盘 ${index + 1}:${imageText2(buffer)}`;
17560
17593
  if (!buffer.length) return `<p>${import_koishi4.h.escape(description)}</p>`;
17561
17594
  return `<img src="data:image/png;base64,${buffer.toString("base64")}" alt="${import_koishi4.h.escape(description)}">`;
17562
17595
  }).join("\n");
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
- /** Default output is an image plus its usable text equivalent. Preferences affect this user only. */
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
- /** Preserve companion text when image messages are switched to text mode. */
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 {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-wordle-game",
3
3
  "description": "Koishi 多词库猜词游戏,包含经典、汉兜、Numberle 等模式。",
4
- "version": "4.2.0",
4
+ "version": "4.2.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [