koishi-plugin-ciyi 2.0.0 → 2.1.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.
Files changed (3) hide show
  1. package/README.md +4 -4
  2. package/lib/index.js +233 -86
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # koishi-plugin-ciyi
2
2
 
3
- 词意猜词:每天一个两字词,在群里开猜
3
+ 词意 · 每天一个两字词,在群里开猜
4
4
 
5
5
  ## 安装
6
6
 
@@ -15,11 +15,11 @@ yarn add koishi-plugin-ciyi
15
15
  | 指令 | 说明 |
16
16
  | --- | --- |
17
17
  | `ciyi` | 玩法 |
18
- | `ciyi.猜 <词>` | 开始今日游戏并提交猜测 |
18
+ | `ciyi.猜 <词>` | 开始今日对局并报一个两字词 |
19
19
  | `ciyi.裸词 [开/关]` | 切换本频道无前缀续猜 |
20
- | `ciyi.排行榜` | 猜中次数排行 |
20
+ | `ciyi.排行榜` | 累计猜中排行榜 |
21
21
 
22
- 首次用 `ciyi.猜 <词>` 开题,之后可直接发送两字词继续猜。裸词设置只对当前群生效,重启后恢复默认。
22
+ 首次用 `ciyi.猜 <词>` 开题,之后可直接发送两字词继续猜。裸词设置只对当前频道生效,重启后恢复默认。
23
23
 
24
24
  ## 许可证
25
25
 
package/lib/index.js CHANGED
@@ -203,6 +203,25 @@ var SHAPE = {
203
203
  full: 9999
204
204
  };
205
205
  var FONT_STACK = '"Roboto Flex", "Roboto", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", system-ui, sans-serif';
206
+ var MONO_STACK = '"Roboto Mono", "JetBrains Mono", "SF Mono", "Cascadia Mono", Consolas, "Noto Sans Mono", monospace';
207
+ var TYPE = {
208
+ displayLarge: { size: 57, line: 64, weight: 400, tracking: -0.25 },
209
+ displayMedium: { size: 45, line: 52, weight: 400, tracking: 0 },
210
+ displaySmall: { size: 36, line: 44, weight: 400, tracking: 0 },
211
+ headlineLarge: { size: 32, line: 40, weight: 400, tracking: 0 },
212
+ headlineMedium: { size: 28, line: 36, weight: 400, tracking: 0 },
213
+ headlineSmall: { size: 24, line: 32, weight: 400, tracking: 0 },
214
+ titleLarge: { size: 22, line: 28, weight: 400, tracking: 0 },
215
+ titleMedium: { size: 16, line: 24, weight: 500, tracking: 0.15 },
216
+ titleSmall: { size: 14, line: 20, weight: 500, tracking: 0.1 },
217
+ bodyLarge: { size: 16, line: 24, weight: 400, tracking: 0.5 },
218
+ bodyMedium: { size: 14, line: 20, weight: 400, tracking: 0.25 },
219
+ bodySmall: { size: 12, line: 16, weight: 400, tracking: 0.4 },
220
+ labelLarge: { size: 14, line: 20, weight: 500, tracking: 0.1 },
221
+ labelMedium: { size: 12, line: 16, weight: 500, tracking: 0.5 },
222
+ labelSmall: { size: 11, line: 16, weight: 500, tracking: 0.5 }
223
+ };
224
+ var EMPHASIZED_WEIGHT = { display: 600, headline: 600, title: 600, label: 600 };
206
225
  var MEDAL = {
207
226
  gold: lch(58, 52, 85),
208
227
  silver: lch(66, 5, 260),
@@ -247,11 +266,13 @@ var C = {
247
266
  primary: SCHEME.primary,
248
267
  onPrimary: SCHEME.onPrimary,
249
268
  primaryContainer: SCHEME.primaryContainer,
250
- onPrimaryContainer: SCHEME.onPrimaryContainer
269
+ onPrimaryContainer: SCHEME.onPrimaryContainer,
270
+ secondaryContainer: SCHEME.secondaryContainer,
271
+ onSecondaryContainer: SCHEME.onSecondaryContainer
251
272
  };
252
273
  var FRESH = lch(94, 14, HUE);
253
274
  var FONT_SANS = FONT_STACK;
254
- var FONT_NUM = FONT_STACK;
275
+ var FONT_NUM = `${MONO_STACK},${FONT_STACK}`;
255
276
  function s(n) {
256
277
  return Math.round(n * SCALE);
257
278
  }
@@ -317,7 +338,7 @@ function textRight(ctx, text, x, y, font, color, offsetY = 0) {
317
338
  }
318
339
  __name(textRight, "textRight");
319
340
  function fontSizeOf(font) {
320
- return Number(font.match(/([\d.]+)px/)?.[1] ?? s(12));
341
+ return Number(font.match(/([\d.]+)px/)?.[1] ?? s(TYPE.bodySmall.size));
321
342
  }
322
343
  __name(fontSizeOf, "fontSizeOf");
323
344
  function textWidth(text, fontSize) {
@@ -378,9 +399,30 @@ async function toPng(service, innerW, innerH, draw) {
378
399
  }
379
400
  __name(toPng, "toPng");
380
401
  var GRID = {
381
- sm: { cell: 26, gap: 4, font: 15, border: 1 },
382
- md: { cell: 34, gap: 4, font: 20, border: 1 },
383
- lg: { cell: 78, gap: 9, font: 46, border: 1.5 }
402
+ sm: {
403
+ cell: 26,
404
+ gap: 4,
405
+ border: 1,
406
+ font: TYPE.labelLarge.size,
407
+ weight: EMPHASIZED_WEIGHT.label,
408
+ radius: SHAPE.extraSmall
409
+ },
410
+ md: {
411
+ cell: 34,
412
+ gap: 4,
413
+ border: 1,
414
+ font: TYPE.titleLarge.size,
415
+ weight: EMPHASIZED_WEIGHT.title,
416
+ radius: SHAPE.small
417
+ },
418
+ lg: {
419
+ cell: 78,
420
+ gap: 9,
421
+ border: 1.5,
422
+ font: TYPE.displayMedium.size,
423
+ weight: EMPHASIZED_WEIGHT.display,
424
+ radius: SHAPE.large
425
+ }
384
426
  };
385
427
  function gridWidth(word, size) {
386
428
  const g = GRID[size];
@@ -389,9 +431,9 @@ function gridWidth(word, size) {
389
431
  return s(g.cell * n + g.gap * (n - 1));
390
432
  }
391
433
  __name(gridWidth, "gridWidth");
392
- function drawGridCell(ctx, x, y, size, ch, mode, fontSize, borderW) {
434
+ function drawGridCell(ctx, x, y, size, ch, mode, g) {
393
435
  const half = size / 2;
394
- const radius = Math.min(s(SHAPE.large), Math.max(s(SHAPE.extraSmall), size * 0.2));
436
+ const radius = s(g.radius);
395
437
  if (mode === "mk") {
396
438
  fillRound(ctx, x, y, size, size, radius, C.surfaceContainerHighest);
397
439
  ctx.save();
@@ -404,20 +446,20 @@ function drawGridCell(ctx, x, y, size, ch, mode, fontSize, borderW) {
404
446
  size - s(1),
405
447
  radius,
406
448
  C.outline,
407
- s(borderW)
449
+ s(g.border)
408
450
  );
409
451
  ctx.restore();
410
452
  return;
411
453
  }
412
454
  fillRound(ctx, x, y, size, size, radius, C.surfaceContainerHigh);
413
455
  if (ch) {
414
- const fs = s(fontSize);
456
+ const fs = s(g.font);
415
457
  textCenter(
416
458
  ctx,
417
459
  ch,
418
460
  x + half,
419
461
  y + half,
420
- `600 ${fs}px ${FONT_SANS}`,
462
+ `${g.weight} ${fs}px ${FONT_SANS}`,
421
463
  C.onSurface,
422
464
  cjkOffset(fs)
423
465
  );
@@ -430,15 +472,15 @@ function drawWordGrid(ctx, x, y, word, size, mask) {
430
472
  const gap = s(g.gap);
431
473
  const chars = Array.from(word || "");
432
474
  if (chars.length === 0) {
433
- textCenter(ctx, "—", x + s(14), y + cell / 2, `${s(13)}px ${FONT_SANS}`, C.onSurfaceVariant);
475
+ textCenter(ctx, "—", x + s(14), y + cell / 2, `${s(TYPE.bodySmall.size)}px ${FONT_SANS}`, C.onSurfaceVariant);
434
476
  return s(28);
435
477
  }
436
478
  let cx = x;
437
479
  for (let i = 0; i < chars.length; i++) {
438
480
  if (i === mask) {
439
- drawGridCell(ctx, cx, y, cell, null, "mk", g.font, g.border);
481
+ drawGridCell(ctx, cx, y, cell, null, "mk", g);
440
482
  } else {
441
- drawGridCell(ctx, cx, y, cell, chars[i], "on", g.font, g.border);
483
+ drawGridCell(ctx, cx, y, cell, chars[i], "on", g);
442
484
  }
443
485
  cx += cell + gap;
444
486
  }
@@ -447,12 +489,12 @@ function drawWordGrid(ctx, x, y, word, size, mask) {
447
489
  __name(drawWordGrid, "drawWordGrid");
448
490
  function drawSeal(ctx, x, y, size, lines) {
449
491
  fillRound(ctx, x, y, size, size, s(SHAPE.extraLarge), C.primary);
450
- const fs = s(19);
492
+ const fs = s(TYPE.titleLarge.size);
451
493
  const lh = fs * 1.06;
452
494
  const total = lh * lines.length;
453
495
  let cy = y + size / 2 - total / 2 + lh / 2;
454
496
  for (const line of lines) {
455
- textCenter(ctx, line, x + size / 2, cy, `600 ${fs}px ${FONT_SANS}`, C.onPrimary);
497
+ textCenter(ctx, line, x + size / 2, cy, `${EMPHASIZED_WEIGHT.title} ${fs}px ${FONT_SANS}`, C.onPrimary);
456
498
  cy += lh;
457
499
  }
458
500
  }
@@ -465,13 +507,20 @@ function drawHeader(ctx, innerX, innerY, innerW, sub, right) {
465
507
  const h2 = padTop + sealSize + padBottom;
466
508
  drawSeal(ctx, innerX + padX, innerY + padTop, sealSize, ["词", "意"]);
467
509
  const brandX = innerX + padX + sealSize + s(15);
468
- textLeft(ctx, "词意", brandX, innerY + padTop + s(14), `700 ${s(26)}px ${FONT_SANS}`, C.onSurface);
510
+ textLeft(
511
+ ctx,
512
+ "词意",
513
+ brandX,
514
+ innerY + padTop + s(14),
515
+ `${EMPHASIZED_WEIGHT.headline} ${s(TYPE.headlineMedium.size)}px ${FONT_SANS}`,
516
+ C.onSurface
517
+ );
469
518
  textLeft(
470
519
  ctx,
471
520
  "ci yi",
472
521
  brandX,
473
522
  innerY + padTop + s(36),
474
- `italic ${s(10)}px ${FONT_NUM}`,
523
+ `italic ${s(TYPE.labelSmall.size)}px ${FONT_SANS}`,
475
524
  C.onSurfaceVariant
476
525
  );
477
526
  const subRight = right ? innerX + innerW - padX - s(150) : innerX + innerW - padX;
@@ -481,13 +530,27 @@ function drawHeader(ctx, innerX, innerY, innerW, sub, right) {
481
530
  brandX,
482
531
  innerY + padTop + s(58),
483
532
  subRight - brandX,
484
- `${s(12.5)}px ${FONT_SANS}`,
533
+ `${s(TYPE.bodySmall.size)}px ${FONT_SANS}`,
485
534
  C.onSurfaceVariant
486
535
  );
487
536
  if (right) {
488
537
  const rx = innerX + innerW - padX;
489
- textRight(ctx, right.big, rx, innerY + padTop + s(16), `700 ${s(31)}px ${FONT_NUM}`, C.primary);
490
- textRight(ctx, right.cap, rx, innerY + padTop + s(44), `${s(10.5)}px ${FONT_SANS}`, C.onSurfaceVariant);
538
+ textRight(
539
+ ctx,
540
+ right.big,
541
+ rx,
542
+ innerY + padTop + s(16),
543
+ `${EMPHASIZED_WEIGHT.headline} ${s(TYPE.headlineLarge.size)}px ${FONT_NUM}`,
544
+ C.primary
545
+ );
546
+ textRight(
547
+ ctx,
548
+ right.cap,
549
+ rx,
550
+ innerY + padTop + s(44),
551
+ `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`,
552
+ C.onSurfaceVariant
553
+ );
491
554
  }
492
555
  const lineY = innerY + h2;
493
556
  ctx.strokeStyle = C.outlineVariant;
@@ -525,16 +588,16 @@ function drawFooter(ctx, innerX, y, innerW, legendItems, tip) {
525
588
  for (const { tier, range } of legendItems) {
526
589
  fillRound(ctx, lx, cy - s(4.5), s(9), s(9), s(SHAPE.full), tier.color);
527
590
  lx += s(9) + s(6);
528
- textLeft(ctx, tier.name, lx, cy, `${s(11.5)}px ${FONT_SANS}`, C.onSurfaceVariant);
529
- lx += textWidth(tier.name, s(11.5)) + s(4);
530
- textLeft(ctx, range, lx, cy, `${s(11)}px ${FONT_NUM}`, C.onSurfaceVariant);
531
- lx += textWidth(range, s(11)) + s(13);
591
+ textLeft(ctx, tier.name, lx, cy, `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`, C.onSurfaceVariant);
592
+ lx += textWidth(tier.name, s(TYPE.labelSmall.size)) + s(4);
593
+ textLeft(ctx, range, lx, cy, `${s(TYPE.labelSmall.size)}px ${FONT_NUM}`, C.onSurfaceVariant);
594
+ lx += textWidth(range, s(TYPE.labelSmall.size)) + s(13);
532
595
  }
533
- const tipFont = `${s(11.5)}px ${FONT_SANS}`;
596
+ const tipFont = `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`;
534
597
  const maxTipWidth = legendItems.length ? s(145) : innerW - padX * 2;
535
598
  textRight(
536
599
  ctx,
537
- ellipsize(tip, maxTipWidth, s(11.5)),
600
+ ellipsize(tip, maxTipWidth, s(TYPE.labelSmall.size)),
538
601
  innerX + innerW - padX,
539
602
  cy,
540
603
  tipFont,
@@ -551,17 +614,24 @@ function drawLegendFull(ctx, x, y, w) {
551
614
  const cx = x + i % 2 * colW;
552
615
  const cy = y + Math.floor(i / 2) * rowH;
553
616
  fillRound(ctx, cx, cy - s(4.5), s(9), s(9), s(SHAPE.full), t.color);
554
- textLeft(ctx, t.name, cx + s(15), cy, `${s(11.5)}px ${FONT_SANS}`, C.onSurfaceVariant);
555
- textLeft(ctx, tierRange(i), cx + s(52), cy, `${s(11)}px ${FONT_NUM}`, C.onSurfaceVariant);
556
- textLeft(ctx, t.note, cx + s(100), cy, `${s(11.5)}px ${FONT_SANS}`, C.onSurfaceVariant);
617
+ textLeft(ctx, t.name, cx + s(15), cy, `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`, C.onSurfaceVariant);
618
+ textLeft(ctx, tierRange(i), cx + s(52), cy, `${s(TYPE.labelSmall.size)}px ${FONT_NUM}`, C.onSurfaceVariant);
619
+ textLeft(ctx, t.note, cx + s(100), cy, `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`, C.onSurfaceVariant);
557
620
  }
558
621
  return rowH * Math.ceil(TIERS.length / 2) + s(8);
559
622
  }
560
623
  __name(drawLegendFull, "drawLegendFull");
561
624
  function drawSectionTitle(ctx, x, y, w, title) {
562
625
  fillRound(ctx, x, y - s(1), s(3), s(12), s(SHAPE.full), C.primary);
563
- textLeft(ctx, title, x + s(15), y + s(5), `600 ${s(11.5)}px ${FONT_SANS}`, C.onSurfaceVariant);
564
- const tw = textWidth(title, s(11.5));
626
+ textLeft(
627
+ ctx,
628
+ title,
629
+ x + s(15),
630
+ y + s(5),
631
+ `${EMPHASIZED_WEIGHT.label} ${s(TYPE.labelMedium.size)}px ${FONT_SANS}`,
632
+ C.onSurfaceVariant
633
+ );
634
+ const tw = textWidth(title, s(TYPE.labelMedium.size));
565
635
  ctx.strokeStyle = C.outlineVariant;
566
636
  ctx.lineWidth = s(1);
567
637
  ctx.beginPath();
@@ -581,7 +651,7 @@ function drawNearBar(ctx, x, y, pct, tier) {
581
651
  const gap = s(3);
582
652
  const fillW = Math.max(barH, barW * pct / 100);
583
653
  const top = y - barH / 2;
584
- fillRound(ctx, x, top, fillW, barH, barH / 2, tier.color);
654
+ fillRound(ctx, x, top, fillW, barH, s(SHAPE.full), tier.color);
585
655
  if (fillW + gap < barW) {
586
656
  fillRound(
587
657
  ctx,
@@ -589,11 +659,18 @@ function drawNearBar(ctx, x, y, pct, tier) {
589
659
  top,
590
660
  barW - fillW - gap,
591
661
  barH,
592
- barH / 2,
662
+ s(SHAPE.full),
593
663
  C.surfaceContainerHighest
594
664
  );
595
665
  }
596
- textLeft(ctx, tier.name, x + barW + s(9), y, `600 ${s(12.5)}px ${FONT_SANS}`, tier.color);
666
+ textLeft(
667
+ ctx,
668
+ tier.name,
669
+ x + barW + s(9),
670
+ y,
671
+ `${EMPHASIZED_WEIGHT.label} ${s(TYPE.labelMedium.size)}px ${FONT_SANS}`,
672
+ tier.color
673
+ );
597
674
  }
598
675
  __name(drawNearBar, "drawNearBar");
599
676
  function measureBoard(opts) {
@@ -633,10 +710,10 @@ function drawBoardTable(ctx, x, y, w, opts, rowH) {
633
710
  const rk0 = nb1 + cols.nb;
634
711
  const mt0 = rk0 + cols.rk;
635
712
  const noX = bx + s(2);
636
- const meterBlockW = s(88) + s(9) + textWidth("咫尺", s(12.5));
713
+ const meterBlockW = s(88) + s(9) + textWidth("咫尺", s(TYPE.labelMedium.size));
637
714
  const mtX = mt0 + Math.max(0, (cols.mt - meterBlockW) / 2);
638
715
  const headY = y;
639
- const fs = s(10.5);
716
+ const fs = s(TYPE.labelSmall.size);
640
717
  textLeft(ctx, "序", noX, headY, `${fs}px ${FONT_SANS}`, C.onSurfaceVariant);
641
718
  textCenter(ctx, "更近 ◀", nb0 + cols.nb / 2, headY, `${fs}px ${FONT_SANS}`, C.onSurfaceVariant);
642
719
  textCenter(ctx, "猜测", gw0 + cols.gw / 2, headY, `${fs}px ${FONT_SANS}`, C.onSurfaceVariant);
@@ -653,7 +730,7 @@ function drawBoardTable(ctx, x, y, w, opts, rowH) {
653
730
  `…… 另有 ${row.gapBefore} 词未列`,
654
731
  cx + tableW / 2,
655
732
  ry + s(10),
656
- `${s(11.5)}px ${FONT_SANS}`,
733
+ `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`,
657
734
  C.onSurfaceVariant
658
735
  );
659
736
  ctx.strokeStyle = C.outlineVariant;
@@ -683,7 +760,7 @@ function drawBoardTable(ctx, x, y, w, opts, rowH) {
683
760
  String(ordinal).padStart(2, "0"),
684
761
  noX,
685
762
  midY,
686
- `${s(13)}px ${FONT_NUM}`,
763
+ `${s(TYPE.labelMedium.size)}px ${FONT_NUM}`,
687
764
  C.onSurfaceVariant
688
765
  );
689
766
  const nbX = nb0 + (cols.nb - gridWidth(history.leftHint, "sm")) / 2;
@@ -693,12 +770,12 @@ function drawBoardTable(ctx, x, y, w, opts, rowH) {
693
770
  const rbX = nb1 + (cols.nb - gridWidth(history.rightHint, "sm")) / 2;
694
771
  drawWordGrid(ctx, rbX, midY - s(13), history.rightHint, "sm", 1);
695
772
  const rankText = String(history.rank);
696
- const rankFont = `700 ${s(21)}px ${FONT_NUM}`;
697
- const rankWidth = textWidth(rankText, s(21));
698
- const hashW = textWidth("#", s(13));
773
+ const rankFont = `${EMPHASIZED_WEIGHT.title} ${s(TYPE.titleLarge.size)}px ${FONT_NUM}`;
774
+ const rankWidth = textWidth(rankText, s(TYPE.titleLarge.size));
775
+ const hashW = textWidth("#", s(TYPE.labelMedium.size));
699
776
  const rankBlock = hashW + s(3) + rankWidth;
700
777
  const rankLeft = rk0 + (cols.rk - rankBlock) / 2;
701
- textLeft(ctx, "#", rankLeft, midY, `${s(13)}px ${FONT_NUM}`, C.onSurfaceVariant);
778
+ textLeft(ctx, "#", rankLeft, midY, `${s(TYPE.labelMedium.size)}px ${FONT_NUM}`, C.onSurfaceVariant);
702
779
  textLeft(ctx, rankText, rankLeft + hashW + s(3), midY, rankFont, tier.color);
703
780
  drawNearBar(ctx, mtX, midY, pct, tier);
704
781
  ry += rowH;
@@ -740,31 +817,59 @@ function renderIntroCard(service, opts) {
740
817
  y += s(11);
741
818
  const p1h = s(104);
742
819
  drawPanel(ctx, ix + s(22), y, iw - s(44), p1h);
743
- textLeft(ctx, "开始", ix + s(38), y + s(24), `${s(14)}px ${FONT_SANS}`, C.primary);
744
- textLeft(ctx, "ciyi.猜 山水", ix + s(96), y + s(24), `${s(13.5)}px ${FONT_NUM}`, C.onSurface);
820
+ textLeft(ctx, "开始", ix + s(38), y + s(24), `${s(TYPE.labelLarge.size)}px ${FONT_SANS}`, C.primary);
821
+ textLeft(
822
+ ctx,
823
+ "ciyi.猜 山水",
824
+ ix + s(96),
825
+ y + s(24),
826
+ `${s(TYPE.labelLarge.size)}px ${FONT_SANS}`,
827
+ C.onSurface
828
+ );
745
829
  textLeftFit(
746
830
  ctx,
747
831
  `开题并报一个两字词${opts.middleware ? ";开题后可直接发词" : ""}`,
748
832
  ix + s(230),
749
833
  y + s(24),
750
834
  iw - s(268),
751
- `${s(14)}px ${FONT_SANS}`,
835
+ `${s(TYPE.bodyMedium.size)}px ${FONT_SANS}`,
836
+ C.onSurface
837
+ );
838
+ textLeft(ctx, "切换", ix + s(38), y + s(52), `${s(TYPE.labelLarge.size)}px ${FONT_SANS}`, C.primary);
839
+ textLeft(
840
+ ctx,
841
+ "ciyi.裸词 开/关",
842
+ ix + s(96),
843
+ y + s(52),
844
+ `${s(TYPE.labelLarge.size)}px ${FONT_SANS}`,
752
845
  C.onSurface
753
846
  );
754
- textLeft(ctx, "切换", ix + s(38), y + s(52), `${s(14)}px ${FONT_SANS}`, C.primary);
755
- textLeft(ctx, "ciyi.裸词 开/关", ix + s(96), y + s(52), `${s(13.5)}px ${FONT_NUM}`, C.onSurface);
756
847
  textLeftFit(
757
848
  ctx,
758
849
  "临时改本频道的续猜方式",
759
850
  ix + s(230),
760
851
  y + s(52),
761
852
  iw - s(268),
762
- `${s(14)}px ${FONT_SANS}`,
853
+ `${s(TYPE.bodyMedium.size)}px ${FONT_SANS}`,
854
+ C.onSurface
855
+ );
856
+ textLeft(ctx, "排行", ix + s(38), y + s(80), `${s(TYPE.labelLarge.size)}px ${FONT_SANS}`, C.primary);
857
+ textLeft(
858
+ ctx,
859
+ "ciyi.排行榜",
860
+ ix + s(96),
861
+ y + s(80),
862
+ `${s(TYPE.labelLarge.size)}px ${FONT_SANS}`,
863
+ C.onSurface
864
+ );
865
+ textLeft(
866
+ ctx,
867
+ "看谁猜中得最多",
868
+ ix + s(230),
869
+ y + s(80),
870
+ `${s(TYPE.bodyMedium.size)}px ${FONT_SANS}`,
763
871
  C.onSurface
764
872
  );
765
- textLeft(ctx, "排行", ix + s(38), y + s(80), `${s(14)}px ${FONT_SANS}`, C.primary);
766
- textLeft(ctx, "ciyi.排行榜", ix + s(96), y + s(80), `${s(13.5)}px ${FONT_NUM}`, C.onSurface);
767
- textLeft(ctx, "看谁猜中得最多", ix + s(230), y + s(80), `${s(14)}px ${FONT_SANS}`, C.onSurface);
768
873
  y += p1h + s(19);
769
874
  y += drawSectionTitle(ctx, ix + s(22), y, iw - s(44), "读板");
770
875
  y += s(11);
@@ -788,7 +893,7 @@ function renderIntroCard(service, opts) {
788
893
  "这一行是说:「企业」与今日答案的意思相近程度,排在第 467 位。",
789
894
  ix + s(38),
790
895
  y + s(104),
791
- `${s(12)}px ${FONT_SANS}`,
896
+ `${s(TYPE.bodySmall.size)}px ${FONT_SANS}`,
792
897
  C.onSurfaceVariant
793
898
  );
794
899
  textLeft(
@@ -796,7 +901,7 @@ function renderIntroCard(service, opts) {
796
901
  "两侧空格各藏一字:左邻更近,右邻更远。",
797
902
  ix + s(38),
798
903
  y + s(126),
799
- `${s(12)}px ${FONT_SANS}`,
904
+ `${s(TYPE.bodySmall.size)}px ${FONT_SANS}`,
800
905
  C.onSurfaceVariant
801
906
  );
802
907
  textLeft(
@@ -804,7 +909,7 @@ function renderIntroCard(service, opts) {
804
909
  "名次越小,离答案越近;#1 就是答案本身。",
805
910
  ix + s(38),
806
911
  y + s(148),
807
- `${s(12)}px ${FONT_SANS}`,
912
+ `${s(TYPE.bodySmall.size)}px ${FONT_SANS}`,
808
913
  C.onSurfaceVariant
809
914
  );
810
915
  y += sampleH + s(19);
@@ -827,7 +932,7 @@ function renderIntroCard(service, opts) {
827
932
  "一日一词,猜中即止,次日零点换题",
828
933
  ix + s(22),
829
934
  iy + ih - s(30),
830
- `${s(11.5)}px ${FONT_SANS}`,
935
+ `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`,
831
936
  C.onSurfaceVariant
832
937
  );
833
938
  });
@@ -842,37 +947,44 @@ function renderWinCard(service, opts) {
842
947
  const revealH = s(130);
843
948
  drawPanel(ctx, ix + s(22), y, iw - s(44), revealH);
844
949
  drawSeal(ctx, ix + iw - s(80), y - s(13), s(42), ["中"]);
845
- textLeft(ctx, "今日答案", ix + s(38), y + s(24), `${s(11.5)}px ${FONT_SANS}`, C.onSurfaceVariant);
950
+ textLeft(ctx, "今日答案", ix + s(38), y + s(24), `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`, C.onSurfaceVariant);
846
951
  drawWordGrid(ctx, ix + s(38), y + s(40), opts.answer, "lg");
847
952
  const ax = ix + iw - s(310);
848
953
  if (opts.neighbors.length) {
849
- textLeft(ctx, "意思最近的几个词", ax, y + s(24), `${s(11.5)}px ${FONT_SANS}`, C.onSurfaceVariant);
954
+ textLeft(ctx, "意思最近的几个词", ax, y + s(24), `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`, C.onSurfaceVariant);
850
955
  let nx = ax;
851
956
  let ny = y + s(48);
852
- const chipFont = `${s(14)}px ${FONT_SANS}`;
957
+ const chipFont = `${s(TYPE.labelLarge.size)}px ${FONT_SANS}`;
853
958
  const chipRight = ix + iw - s(38);
854
959
  for (const word of opts.neighbors) {
855
- const fittedWord = ellipsize(word, s(116), s(14));
856
- const pw = textWidth(fittedWord, s(14)) + s(20);
960
+ const fittedWord = ellipsize(word, s(116), s(TYPE.labelLarge.size));
961
+ const pw = textWidth(fittedWord, s(TYPE.labelLarge.size)) + s(20);
857
962
  if (nx !== ax && nx + pw > chipRight) {
858
963
  nx = ax;
859
964
  ny += s(36);
860
965
  }
861
966
  if (ny + s(14) > y + revealH - s(12)) break;
862
- fillRound(ctx, nx, ny - s(14), pw, s(28), s(SHAPE.full), SCHEME.secondaryContainer);
967
+ fillRound(ctx, nx, ny - s(14), pw, s(28), s(SHAPE.full), C.secondaryContainer);
863
968
  textCenter(
864
969
  ctx,
865
970
  fittedWord,
866
971
  nx + pw / 2,
867
972
  ny,
868
973
  chipFont,
869
- SCHEME.onSecondaryContainer,
870
- cjkOffset(s(14))
974
+ C.onSecondaryContainer,
975
+ cjkOffset(s(TYPE.labelLarge.size))
871
976
  );
872
977
  nx += pw + s(7);
873
978
  }
874
979
  } else {
875
- textLeft(ctx, "今日一词,就此收笔。", ax, y + s(50), `${s(13.5)}px ${FONT_SANS}`, C.onSurfaceVariant);
980
+ textLeft(
981
+ ctx,
982
+ "今日一词,就此收笔。",
983
+ ax,
984
+ y + s(50),
985
+ `${s(TYPE.bodyMedium.size)}px ${FONT_SANS}`,
986
+ C.onSurfaceVariant
987
+ );
876
988
  }
877
989
  y += revealH + s(14);
878
990
  const statW = (iw - s(44) - s(20)) / 3;
@@ -884,11 +996,32 @@ function renderWinCard(service, opts) {
884
996
  for (let i = 0; i < 3; i++) {
885
997
  const sx = ix + s(22) + i * (statW + s(10));
886
998
  drawPanel(ctx, sx, y, statW, s(56));
887
- textLeft(ctx, stats[i].n, sx + s(14), y + s(22), `700 ${s(23)}px ${FONT_NUM}`, C.primary);
999
+ textLeft(
1000
+ ctx,
1001
+ stats[i].n,
1002
+ sx + s(14),
1003
+ y + s(22),
1004
+ `${EMPHASIZED_WEIGHT.headline} ${s(TYPE.headlineSmall.size)}px ${FONT_NUM}`,
1005
+ C.primary
1006
+ );
888
1007
  if (stats[i].u) {
889
- textLeft(ctx, stats[i].u, sx + s(14) + textWidth(stats[i].n, s(23)) + s(3), y + s(26), `${s(12)}px ${FONT_SANS}`, C.onSurfaceVariant);
1008
+ textLeft(
1009
+ ctx,
1010
+ stats[i].u,
1011
+ sx + s(14) + textWidth(stats[i].n, s(TYPE.headlineSmall.size)) + s(3),
1012
+ y + s(26),
1013
+ `${s(TYPE.labelMedium.size)}px ${FONT_SANS}`,
1014
+ C.onSurfaceVariant
1015
+ );
890
1016
  }
891
- textLeft(ctx, stats[i].c, sx + s(14), y + s(44), `${s(10.5)}px ${FONT_SANS}`, C.onSurfaceVariant);
1017
+ textLeft(
1018
+ ctx,
1019
+ stats[i].c,
1020
+ sx + s(14),
1021
+ y + s(44),
1022
+ `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`,
1023
+ C.onSurfaceVariant
1024
+ );
892
1025
  }
893
1026
  const quip = opts.closest === null ? "一击即中,今日无需第二次落笔" : `从 #${opts.closest} 一步跨到 #1`;
894
1027
  const footerTip = opts.canStartToday ? "ciyi.猜 山水 · 开启今日新题" : "明日零点换新题 · ciyi.排行榜";
@@ -900,8 +1033,8 @@ function renderWinCard(service, opts) {
900
1033
  [],
901
1034
  footerTip
902
1035
  );
903
- const footerFont = `${s(11.5)}px ${FONT_SANS}`;
904
- const footerTipWidth = textWidth(footerTip, s(11.5));
1036
+ const footerFont = `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`;
1037
+ const footerTipWidth = textWidth(footerTip, s(TYPE.labelSmall.size));
905
1038
  textLeftFit(
906
1039
  ctx,
907
1040
  `${opts.username} 拿下今日一词 · ${quip}`,
@@ -941,10 +1074,10 @@ function renderRankCard(service, opts) {
941
1074
  if (!opts.entries.length) {
942
1075
  textCenter(
943
1076
  ctx,
944
- "榜上无名。",
1077
+ "排行榜还空着",
945
1078
  panelX + panelW / 2,
946
1079
  y + s(31),
947
- `${s(13.5)}px ${FONT_SANS}`,
1080
+ `${s(TYPE.bodyMedium.size)}px ${FONT_SANS}`,
948
1081
  C.onSurfaceVariant
949
1082
  );
950
1083
  textCenter(
@@ -952,7 +1085,7 @@ function renderRankCard(service, opts) {
952
1085
  "今日第一个猜中的人,会写在这里。",
953
1086
  panelX + panelW / 2,
954
1087
  y + s(61),
955
- `${s(13.5)}px ${FONT_SANS}`,
1088
+ `${s(TYPE.bodyMedium.size)}px ${FONT_SANS}`,
956
1089
  C.onSurfaceVariant
957
1090
  );
958
1091
  } else {
@@ -974,35 +1107,49 @@ function renderRankCard(service, opts) {
974
1107
  const px = contentLeft;
975
1108
  const py = midY - posSize / 2;
976
1109
  const podium = [MEDAL.gold, MEDAL.silver, MEDAL.bronze];
977
- const pc = i < 3 ? { bg: podium[i], fg: "#ffffff" } : { bg: C.surfaceContainerHighest, fg: C.onSurfaceVariant };
1110
+ const pc = i < 3 ? { bg: podium[i], fg: C.onPrimary } : { bg: C.surfaceContainerHighest, fg: C.onSurfaceVariant };
978
1111
  fillRound(ctx, px, py, posSize, posSize, s(SHAPE.full), pc.bg);
979
- textCenter(ctx, String(i + 1), px + posSize / 2, midY, `600 ${s(14)}px ${FONT_NUM}`, pc.fg);
1112
+ textCenter(
1113
+ ctx,
1114
+ String(i + 1),
1115
+ px + posSize / 2,
1116
+ midY,
1117
+ `${EMPHASIZED_WEIGHT.label} ${s(TYPE.labelLarge.size)}px ${FONT_NUM}`,
1118
+ pc.fg
1119
+ );
980
1120
  const name2 = e.username || "无名氏";
981
1121
  const nameX = px + posSize + s(14);
982
- const nameFont = `${s(15)}px ${FONT_SANS}`;
1122
+ const nameFont = `${s(TYPE.titleMedium.size)}px ${FONT_SANS}`;
983
1123
  const score = String(e.score);
984
- const unitFont = s(11.5);
1124
+ const unitFont = s(TYPE.labelSmall.size);
985
1125
  const unitW = textWidth("次", unitFont);
986
- const scoreFont = s(19);
1126
+ const scoreFont = s(TYPE.titleLarge.size);
987
1127
  const scoreRight = contentRight - unitW - s(8);
988
1128
  const scoreLeft = scoreRight - textWidth(score, scoreFont);
989
- const meWidth = e.me ? textWidth("我", s(10.5)) + s(18) : 0;
1129
+ const meWidth = e.me ? textWidth("我", s(TYPE.labelSmall.size)) + s(18) : 0;
990
1130
  const fittedName = ellipsize(
991
1131
  name2,
992
1132
  Math.max(0, scoreLeft - s(16) - nameX - meWidth),
993
- s(15)
1133
+ s(TYPE.titleMedium.size)
994
1134
  );
995
1135
  textLeft(ctx, fittedName, nameX, midY, nameFont, C.onSurface);
996
1136
  if (e.me) {
997
- const nw = textWidth(fittedName, s(15));
998
- textLeft(ctx, "我", nameX + nw + s(8), midY, `${s(10.5)}px ${FONT_SANS}`, C.primary);
1137
+ const nw = textWidth(fittedName, s(TYPE.titleMedium.size));
1138
+ textLeft(
1139
+ ctx,
1140
+ "我",
1141
+ nameX + nw + s(8),
1142
+ midY,
1143
+ `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`,
1144
+ C.primary
1145
+ );
999
1146
  }
1000
1147
  textRight(
1001
1148
  ctx,
1002
1149
  score,
1003
1150
  scoreRight,
1004
1151
  midY,
1005
- `700 ${scoreFont}px ${FONT_NUM}`,
1152
+ `${EMPHASIZED_WEIGHT.title} ${scoreFont}px ${FONT_NUM}`,
1006
1153
  C.onSurface
1007
1154
  );
1008
1155
  textRight(ctx, "次", contentRight, midY, `${unitFont}px ${FONT_SANS}`, C.onSurfaceVariant);
@@ -1014,7 +1161,7 @@ function renderRankCard(service, opts) {
1014
1161
  `…… 另有 ${opts.hidden} 人在榜`,
1015
1162
  contentLeft,
1016
1163
  ry + s(16),
1017
- `${s(11.5)}px ${FONT_SANS}`,
1164
+ `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`,
1018
1165
  C.onSurfaceVariant
1019
1166
  );
1020
1167
  }
@@ -1032,7 +1179,7 @@ function renderRankCard(service, opts) {
1032
1179
  "每猜中一日之词,记一次",
1033
1180
  panelX,
1034
1181
  iy + ih - s(30),
1035
- `${s(11.5)}px ${FONT_SANS}`,
1182
+ `${s(TYPE.labelSmall.size)}px ${FONT_SANS}`,
1036
1183
  C.onSurfaceVariant
1037
1184
  );
1038
1185
  });
@@ -1310,7 +1457,7 @@ function apply(ctx, cfg) {
1310
1457
  __name(middlewareSwitchText, "middlewareSwitchText");
1311
1458
  function winText(o) {
1312
1459
  return textCard(
1313
- "猜中了 · 今日已封题",
1460
+ "🏆 猜中了 · 今日已封题",
1314
1461
  `答案 ${o.answer}`,
1315
1462
  [
1316
1463
  `猜测 ${o.attempts} 次`,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-ciyi",
3
- "description": "Koishi 的词意猜词插件。",
4
- "version": "2.0.0",
3
+ "description": "Koishi 插件 · 词意。",
4
+ "version": "2.1.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [