dsh-annual-activity 1.1.4 → 1.1.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.
Files changed (3) hide show
  1. package/README.md +19 -12
  2. package/lib/client.js +66 -28
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # 📅 全年活跃记录 — dsh-annual-activity
1
+ # 📅 DSH-活跃记录 — dsh-annual-activity
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/dsh-annual-activity?color=blue)](https://www.npmjs.com/package/dsh-annual-activity) [![GitHub](https://img.shields.io/badge/source-GitHub-181717?logo=github)](https://github.com/Moveharder/dsh_plugins)
4
4
 
@@ -7,11 +7,13 @@
7
7
 
8
8
  ```
9
9
  DSH 会话头部右上角 ↓
10
- … 项目 / 会话名 ▦ ▢▯ ← ▦ 本插件入口(14 天迷你热力图)
11
- ▢▯ 是官方「打开右侧边栏」
10
+ … 项目 / 会话名 ▦ ▢▯ … ⊞
11
+ │ │ └ 官方「打开右侧边栏」(corner 槽)
12
+ │ └──────── 官方「选择打开方式」(utilities 槽,order -10)
13
+ └─────────── 本插件入口(utilities 槽,order -100 → 该槽第一个子元素)
12
14
 
13
15
  ┌──────────────────────────────────────────────────────────────────────────────┐
14
- │ 全年活跃记录 24 天活跃 · 活跃率 9% ‹ 2026 年 ▾ › ✕ │
16
+ │ DSH-活跃记录 24 天活跃 · 活跃率 9% ‹ 2026 ▾ › ✕ │
15
17
  │ ──────────────────────────────────────────────────────────────────────────── │
16
18
  │ 24 天 9% 6 周 5 天 未活跃 ▢▢▢▢▢ 活跃 │
17
19
  │ 活跃 活跃率 连登 最长连续 │
@@ -24,11 +26,15 @@
24
26
  └──────────────────────────────────────────────────────────────────────────────┘
25
27
  ```
26
28
 
27
- 入口在**会话头部右上角**:紧挨「打开右侧边栏」按钮的左边,同高同圆角(28×28)。
28
- 图标是**最近 14 天的迷你热力图**(等级越高颜色越深);按钮带常驻底色与 1px 细边
29
- (用官方 token,深浅主题都跟随),悬停加深一档。鼠标悬浮时说明浮层出现在**按钮下方**
30
- (不会遮挡按钮与会话标题),显示今日 / 今年 / 连登摘要;点击展开上面的年度面板。
31
- 有新版本时按钮右上角带一个小圆点。
29
+ 入口在**会话头部右上角的最左侧**:注册在 `conversation.session.header.utilities` 槽,
30
+ `order: -100` 让它成为该槽容器的**第一个子元素**,排在官方「选择打开方式」
31
+ (`.CAgGvG_split`,`order: -10`)之前;同高同圆角(28×28)。
32
+ 图标是**最近 14 天的迷你热力图**(等级越高颜色越深);按钮带常驻底色
33
+ (用官方 token,深浅主题都跟随),悬停加深一档,**不使用 `box-shadow` 描边**。
34
+ 鼠标悬浮时说明浮层出现在**按钮下方**(不会遮挡按钮与会话标题),显示今日 / 今年 /
35
+ 连登摘要;点击展开上面的年度面板。有新版本时按钮右上角带一个小圆点。
36
+ 挂载后会**立刻**拉取一次数据(不等面板打开),在此之前按钮显示 14 格**呼吸骨架**,
37
+ 所以任何时刻它都不会是一个空按钮。
32
38
 
33
39
  ## 安装
34
40
 
@@ -70,11 +76,11 @@ dsh plugin --profile web remove dsh-annual-activity
70
76
 
71
77
  | 区域 | 说明 |
72
78
  | --- | --- |
73
- | **头部入口** | 会话右上角、「打开右侧边栏」左侧;14 天迷你热力图字形 + 悬浮摘要;有更新时带圆点 |
74
- | **标题行** | `N 天活跃 · 活跃率 X%`,右侧是**年份切换**(`‹ 2026 年 ▾ ›`,多于一年时可下拉直选)与关闭按钮 |
79
+ | **头部入口** | 会话右上角最左侧(utilities 槽第一个子元素,官方「选择打开方式」之前);14 天迷你热力图字形 + 悬浮摘要;有更新时带圆点 |
80
+ | **标题行** | `N 天活跃 · 活跃率 X%`,右侧是**年份切换**(`‹ 2026 ▾ ›`,只显示年份数字;多于一年时可下拉直选)与关闭按钮 |
75
81
  | **统计行** | 活跃天数 / 活跃率 / **周连登** / 年内最长连续天数 |
76
82
  | **图例** | 未活跃 → 活跃 的 5 级色块,悬浮可看每级阈值 |
77
- | **热力图** | 一周一列(周一在顶),最多 53 列;今天的格子有独立描边;悬浮任一格看当天明细 |
83
+ | **热力图** | 一周一列(周一在顶),最多 53 列;**列宽自适应铺满面板宽度**(不会在右侧留白,窄到放不下才横向滚动);今天的格子有独立描边;悬浮任一格看当天明细 |
78
84
  | **底部** | 数据更新时间、时区口径、跨年累计(轮次 / tokens / 会话数)、手动 ⟳ 重扫、⚙ 设置 |
79
85
 
80
86
  关闭方式:右上角 `✕` / 点击遮罩空白处 / `Esc`。
@@ -153,6 +159,7 @@ dsh plugin --profile web remove dsh-annual-activity
153
159
  | 现象 | 原因 / 处理 |
154
160
  | --- | --- |
155
161
  | 会话右上角没有入口按钮 | 先看 `curl http://127.0.0.1:3080/activity/hello`:404 说明 Host 层没装配(`--dump-config` 确认 `activity` 行存在、没被 `disabled: true`);若 Host 正常,浏览器半区需**重启 dsh web**(客户端 bundle 在启动时注入 `__DSH_BOOT__`)。入口注册在 `conversation.session.header.utilities` 槽,只有会话页头部存在时才可见 |
162
+ | 入口按钮是个「空按钮」 | 正常情况下不该出现:挂载后**立刻**拉一次 `/activity/pull`,数据到达前画 14 格**呼吸骨架**。若骨架一直呼吸,说明拉取没回来(看 Network 里 `/activity/pull`);若骨架变成琥珀色静止,说明 `state.error` 非空——Host 路由没装配 |
156
163
  | 面板显示「host 未就绪:…(重试中…)」 | Host 路由未注册或已被禁用;入口仍在,恢复后自动接上 |
157
164
  | 数字全是 0 / 只有今天有数据 | `$DSH_HOME` 指向了别的目录。插件默认读 `$DSH_HOME/sessions`,其次 `~/.dsh/sessions`;可用 `DSH_ACTIVITY_ROOT` 覆盖 |
158
165
  | 今天色块没变深 | 面板打开时 20s 轮询一次;点底部 ⟳ 可立即重扫(有 5s 最小间隔限流) |
package/lib/client.js CHANGED
@@ -95,6 +95,12 @@ window.__ModuleLoader__.load({
95
95
  return out;
96
96
  }
97
97
 
98
+ /**
99
+ * 数据未到时的字形骨架:固定 14 格占位(不区分「未来格」),
100
+ * 配合 .daa-glyph-loading 的呼吸动画表示「正在加载」。
101
+ */
102
+ const GLYPH_SKELETON = Array.from({ length: 14 }, () => ({ level: 0 }));
103
+
98
104
  /**
99
105
  * 把一年的数据排成 GitHub 风格的热力图网格:列 = 周(周一在顶),最多 53 列。
100
106
  * 首列前用 null 占位,使 1 月 1 日落在它真实的星期行上。
@@ -227,7 +233,10 @@ window.__ModuleLoader__.load({
227
233
  if (timer) return;
228
234
  // 面板打开时 20s 一次(今天的新活动很快可见),关闭时 3 分钟一次保活
229
235
  const tick = () => { void pull(); timer = setTimeout(tick, state.panelOpen ? 20000 : 180000); };
230
- timer = setTimeout(tick, state.panelOpen ? 1000 : 8000);
236
+ // 首次订阅必须**立刻**拉一次:入口按钮的字形就靠这份数据渲染,等 8s 会让
237
+ // 按钮在页面刚打开的一段时间里看起来是个空按钮(像是坏了)。延迟 0 而不是
238
+ // 直接调用,是为了避免在订阅(React effect / 渲染期)中同步 setState。
239
+ timer = setTimeout(tick, 0);
231
240
  }
232
241
 
233
242
  return {
@@ -348,11 +357,13 @@ window.__ModuleLoader__.load({
348
357
  // ==================== 小组件 ====================
349
358
 
350
359
  function HeatCell(props) {
351
- const { day, rec, isToday, size, onHover } = props;
360
+ const { day, rec, isToday, onHover } = props;
352
361
  const ref = React.useRef(null);
353
362
 
363
+ // 尺寸交给 CSS(列宽 minmax(9px,1fr) + aspect-ratio:1)——写死像素会让网格
364
+ // 与卡片内容宽对不齐,日历右侧留白。
354
365
  if (!day) {
355
- return React.createElement('div', { className: 'daa-cell daa-cell-pad', style: { width: size, height: size } });
366
+ return React.createElement('div', { className: 'daa-cell daa-cell-pad' });
356
367
  }
357
368
  const level = levelOfDay(rec);
358
369
  const cls = 'daa-cell daa-l' + level + (isToday ? ' daa-today' : '');
@@ -365,7 +376,6 @@ window.__ModuleLoader__.load({
365
376
  return React.createElement('div', {
366
377
  ref,
367
378
  className: cls,
368
- style: { width: size, height: size },
369
379
  onMouseEnter: onEnter,
370
380
  onMouseLeave: () => { if (onHover) onHover(null); },
371
381
  'aria-label': day + (rec ? ' 活跃 ' + (rec.turns || 0) + ' 轮' : ' 未活跃'),
@@ -424,7 +434,7 @@ window.__ModuleLoader__.load({
424
434
  title: years.length > 1 ? '切换年份' : '仅记录到这一年',
425
435
  onClick: () => years.length > 1 && setOpen(!open),
426
436
  },
427
- React.createElement('span', null, year + ' 年'),
437
+ React.createElement('span', null, String(year)),
428
438
  years.length > 1 ? React.createElement('span', { className: 'daa-year-caret' }, '▾') : null),
429
439
  React.createElement('button', {
430
440
  type: 'button', className: 'daa-year-btn', disabled: !hasNext,
@@ -436,7 +446,7 @@ window.__ModuleLoader__.load({
436
446
  key: y, type: 'button',
437
447
  className: 'daa-year-item' + (y === year ? ' on' : ''),
438
448
  onClick: () => { setOpen(false); onPick(y); },
439
- }, y + ' 年', y === currentYear ? React.createElement('span', { className: 'daa-year-badge' }, '今年') : null))) : null,
449
+ }, String(y), y === currentYear ? React.createElement('span', { className: 'daa-year-badge' }, '今年') : null))) : null,
440
450
  React.createElement('button', { type: 'button', className: 'daa-close', title: '关闭 (Esc)', onClick: onClose }, '✕'));
441
451
  }
442
452
 
@@ -516,11 +526,11 @@ window.__ModuleLoader__.load({
516
526
  style: { zIndex: Z_PORTAL },
517
527
  onMouseDown: (e) => { if (e.target === e.currentTarget) onClose(); },
518
528
  },
519
- React.createElement('div', { className: 'daa-card', role: 'dialog', 'aria-label': summary || '全年活跃记录' },
529
+ React.createElement('div', { className: 'daa-card', role: 'dialog', 'aria-label': summary || 'DSH-活跃记录' },
520
530
  // ---- 头部 ----
521
531
  React.createElement('div', { className: 'daa-head' },
522
532
  React.createElement('div', { className: 'daa-head-l' },
523
- React.createElement('span', { className: 'daa-title' }, '全年活跃记录'),
533
+ React.createElement('span', { className: 'daa-title' }, 'DSH-活跃记录'),
524
534
  React.createElement('span', { className: 'daa-sub' },
525
535
  fmtInt(stats0.activeDays) + ' 天活跃 · 活跃率 ' + fmtPercent(stats0.rate))),
526
536
  React.createElement('div', { className: 'daa-head-r' },
@@ -542,7 +552,7 @@ window.__ModuleLoader__.load({
542
552
  React.createElement('div', { className: 'daa-grid', style: gridStyle },
543
553
  weeks.map((week, ci) => React.createElement('div', { className: 'daa-col', key: ci },
544
554
  week.map((day, ri) => React.createElement(HeatCell, {
545
- key: ri, day, rec: day ? byDay[day] : null, size: 11, isToday: day === today, onHover: setTip,
555
+ key: ri, day, rec: day ? byDay[day] : null, isToday: day === today, onHover: setTip,
546
556
  })))))),
547
557
 
548
558
  // ---- 底部 ----
@@ -645,8 +655,11 @@ window.__ModuleLoader__.load({
645
655
  const curStats = data && data.yearStats ? data.yearStats[data.currentYear] : null;
646
656
  const meta = metaState.meta;
647
657
  const updateAvailable = !!(meta && meta.updateAvailable);
658
+ // 还没拿到数据时画骨架:'loading' 呼吸、'error' 用警示色(host 路由没装配)
659
+ const pending = !data;
660
+ const glyphMode = pending ? (state.error ? 'error' : 'loading') : 'ok';
648
661
 
649
- const title = '全年活跃记录 (dsh-annual-activity)'
662
+ const title = 'DSH-活跃记录 (dsh-annual-activity)'
650
663
  + (data
651
664
  ? ':' + fmtInt(curStats ? curStats.activeDays : 0) + ' 天活跃 · 活跃率 ' + fmtPercent(curStats ? curStats.rate : 0)
652
665
  + ' · 今日 ' + (rec ? fmtInt(rec.turns) + ' 轮' : '未活跃')
@@ -666,16 +679,21 @@ window.__ModuleLoader__.load({
666
679
  ref: btnRef,
667
680
  type: 'button',
668
681
  className: 'daa-hbtn' + (open ? ' on' : ''),
669
- 'aria-label': '全年活跃记录',
682
+ 'aria-label': 'DSH-活跃记录' + (pending ? '(数据加载中)' : ''),
683
+ 'aria-busy': pending ? 'true' : undefined,
670
684
  // 刻意不设原生 title:浏览器自带的提示框会浮在按钮上方并遮挡按钮,
671
685
  // 提示改由下方自绘浮层承担(EntryTip)。
672
686
  onClick: () => setOpen(!open),
673
687
  onMouseEnter: onEnter,
674
688
  onMouseLeave: () => setTip(null),
675
689
  },
676
- React.createElement('span', { className: 'daa-glyph', 'aria-hidden': 'true' },
677
- glyphCells(byDay).map((c, i) => React.createElement('span', {
678
- key: i, className: 'daa-glyph-cell' + (c.level < 0 ? ' daa-glyph-void' : ' daa-l' + c.level),
690
+ React.createElement('span', {
691
+ className: 'daa-glyph' + (pending ? ' daa-glyph-' + glyphMode : ''),
692
+ 'aria-hidden': 'true',
693
+ },
694
+ (pending ? GLYPH_SKELETON : glyphCells(byDay)).map((c, i) => React.createElement('span', {
695
+ key: i,
696
+ className: 'daa-glyph-cell' + (pending ? '' : c.level < 0 ? ' daa-glyph-void' : ' daa-l' + c.level),
679
697
  }))),
680
698
  updateAvailable ? React.createElement('span', { className: 'daa-hbtn-dot', 'aria-label': '有新版本' }) : null),
681
699
  tip ? portalToBody(React.createElement(EntryTip, { tip })) : null,
@@ -747,30 +765,40 @@ window.__ModuleLoader__.load({
747
765
  color:var(--dsh-text-1,#1f2937);}
748
766
  /* ---------- 头部入口按钮(对齐「打开右侧边栏」:28×28 / radius 28 / 16px 图标)
749
767
  官方按钮是纯透明底,放在标题行里太「隐形」,所以这里给一个比悬停态更浅的
750
- 常驻底色 + 一层细边(同样是官方 token,深色主题自动跟随)。---------- */
768
+ 常驻底色(官方 token,深色主题自动跟随)。刻意不用 box-shadow:描边在浅色
769
+ 主题下显脏,纯色底 + 悬停加深一档已经足够区分层级,也更贴近官方按钮观感。 */
751
770
  .daa-hbtn{position:relative;box-sizing:border-box;width:28px;height:28px;flex:none;padding:6px;
752
771
  display:inline-flex;align-items:center;justify-content:center;cursor:pointer;
753
772
  background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06));
754
- border:none;border-radius:28px;box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l2,rgba(0,0,0,.10));
773
+ border:none;border-radius:28px;
755
774
  color:var(--dsw-alias-label-secondary,#4b5563);
756
- transition:background .14s ease,color .14s ease,box-shadow .14s ease;}
775
+ transition:background .14s ease,color .14s ease;}
757
776
  .daa-hbtn:hover{background:var(--dsw-alias-interactive-bg-active,rgba(38,49,72,.10));
758
- box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l3,rgba(0,0,0,.16));
759
777
  color:var(--dsw-alias-label-primary,#111827);}
760
778
  .daa-hbtn.on{background:var(--dsw-alias-interactive-bg-active,rgba(38,49,72,.10));
761
- box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l3,rgba(0,0,0,.16));
762
779
  color:var(--dsw-alias-label-primary,#111827);}
763
780
  .daa-glyph{display:grid;grid-template-columns:repeat(7,2px);grid-template-rows:repeat(2,2px);gap:1px;}
764
781
  .daa-glyph-cell{width:2px;height:2px;border-radius:.5px;}
765
782
  .daa-glyph-void{background:transparent;}
783
+ /* 数据还没到时画 14 格骨架并做呼吸动画:否则「全 0 级」的浅灰几乎看不见,
784
+ 入口按钮会像个坏掉的空按钮(页面刚打开、还没点开过面板时最明显)。 */
785
+ .daa-glyph-loading{animation:daa-glyph-pulse 1.2s ease-in-out infinite;}
786
+ .daa-glyph-loading .daa-glyph-cell{background:var(--dsw-alias-border-l2,rgba(0,0,0,.14));}
787
+ /* host 路由没装配时骨架不再呼吸,改用警示色,避免一直「转圈」像是卡住了 */
788
+ .daa-glyph-error .daa-glyph-cell{background:var(--dsw-alias-state-business-primary,#f59e0b);opacity:.55;}
789
+ @keyframes daa-glyph-pulse{0%,100%{opacity:.4}50%{opacity:1}}
790
+ /* 「有新版本」圆点:不加 box-shadow 描边环,琥珀色在深浅两套底色上都够醒目 */
766
791
  .daa-hbtn-dot{position:absolute;top:2px;right:2px;width:7px;height:7px;border-radius:50%;
767
- background:var(--dsw-alias-state-business-primary,#f59e0b);
768
- box-shadow:0 0 0 1.5px var(--dsw-alias-bg-layer-1,#fff);}
792
+ background:var(--dsw-alias-state-business-primary,#f59e0b);}
769
793
  /* ---------- 遮罩 + 卡片 ---------- */
770
794
  .daa-backdrop{position:fixed;inset:0;pointer-events:auto;background:rgba(15,23,42,.42);
771
795
  display:flex;align-items:center;justify-content:center;padding:24px;animation:daa-fade .14s ease-out;}
772
796
  @keyframes daa-fade{from{opacity:0}to{opacity:1}}
773
- .daa-card{position:relative;width:min(828px,calc(100vw - 40px));max-height:calc(100vh - 48px);overflow:auto;
797
+ /* box-sizing:border-box 是显式声明的:面板总宽就等于这里的 760px(含内边距与描边),
798
+ 不依赖宿主是否提供全局 reset。min-width:0 也是必须的:卡片是 flex item,默认
799
+ min-width:auto 会取内容的 min-content 宽度,内容偏宽时会把卡片顶得比 760px 还宽。
800
+ 改宽度时注意热力图要跟着放得下——见 .daa-grid 的自适应列宽。 */
801
+ .daa-card{position:relative;box-sizing:border-box;min-width:0;width:min(760px,calc(100vw - 40px));max-height:calc(100vh - 48px);overflow:auto;
774
802
  background:var(--dsh-surface-1,#fff);border:1px solid var(--dsh-border,#e8eaee);border-radius:14px;
775
803
  box-shadow:0 24px 64px rgba(15,23,42,.26);padding:16px 20px 12px;
776
804
  animation:daa-pop .16s cubic-bezier(.2,.9,.3,1.2);}
@@ -816,12 +844,17 @@ window.__ModuleLoader__.load({
816
844
  .daa-legend-cap{padding:0 3px;}
817
845
  .daa-legend-cell{width:11px;height:11px;border-radius:3px;display:inline-block;}
818
846
  /* ---------- 热力图 ---------- */
847
+ /* 列宽用 minmax(9px,1fr) 自适应:网格铺满卡片内容宽,最后一列的右边缘正好落在内容区
848
+ 右边界上,因此**日历右侧不会留下一条空白**(固定列宽 + 左对齐会留下
849
+ 「内容宽 − 53×列宽 − 52×间距」的空档,实测有 31~73px)。9px 是下限:窄到放不下时
850
+ 由 .daa-heat 出横向滚动条,而不是把格子压成看不清的碎片。 */
819
851
  .daa-heat{overflow-x:auto;overflow-y:hidden;padding-bottom:2px;}
820
- .daa-months{display:grid;grid-template-columns:repeat(var(--daa-cols,53),11px);gap:3px;margin-bottom:6px;min-width:max-content;}
852
+ .daa-months{display:grid;grid-template-columns:repeat(var(--daa-cols,53),minmax(9px,1fr));gap:2px;margin-bottom:6px;}
821
853
  .daa-month{font-size:11.5px;color:var(--dsh-text-3,#9aa1ab);white-space:nowrap;line-height:1;overflow:visible;}
822
- .daa-grid{display:grid;grid-template-columns:repeat(var(--daa-cols,53),11px);gap:3px;min-width:max-content;}
823
- .daa-col{display:flex;flex-direction:column;gap:3px;}
824
- .daa-cell{border-radius:3px;position:relative;background:#eef0f2;transition:transform .1s ease,box-shadow .1s ease;}
854
+ .daa-grid{display:grid;grid-template-columns:repeat(var(--daa-cols,53),minmax(9px,1fr));gap:2px;}
855
+ .daa-col{display:flex;flex-direction:column;gap:2px;}
856
+ /* 格子尺寸由列宽决定(正方形),不再写死像素——见 .daa-grid 的列定义 */
857
+ .daa-cell{width:100%;aspect-ratio:1/1;border-radius:3px;position:relative;background:#eef0f2;transition:transform .1s ease,box-shadow .1s ease;}
825
858
  .daa-cell-pad{background:transparent;}
826
859
  .daa-cell:not(.daa-cell-pad):hover{transform:scale(1.18);box-shadow:0 0 0 1.5px rgba(22,163,74,.45);}
827
860
  .daa-today{box-shadow:inset 0 0 0 1.5px #16a34a;}
@@ -893,7 +926,6 @@ window.__ModuleLoader__.load({
893
926
  .daa-setup-btn,.daa-setup-notice{
894
927
  background:var(--dsh-surface-1,#1b1e24);border-color:var(--dsh-border,#2f343d);}
895
928
  .daa-setup{background:var(--dsh-surface-2,#171a1f);border-color:var(--dsh-border,#2f343d);}
896
- .daa-hbtn-dot{box-shadow:0 0 0 1.5px var(--dsh-surface-1,#1b1e24);}
897
929
  .daa-l0{background:#2a2f37;}
898
930
  .daa-foot,.daa-toolbar,.daa-setup-foot{border-color:var(--dsh-border,#2f343d);}
899
931
  .daa-error{background:#3a2a12;border-color:#7c5310;color:#fbbf24;}
@@ -927,8 +959,14 @@ window.__ModuleLoader__.load({
927
959
  // corner 槽(「打开右侧边栏」按钮所在处)渲染,所以这个入口会落在
928
960
  // 那个按钮的左边、同一行内。按钮尺寸/圆角/色板都与 corner 里的
929
961
  // 官方按钮保持一致(28×28、图标 16px、interactive-bg-hover 悬停底色)。
962
+ //
963
+ // order 决定槽内顺序:renderer 按 order 升序渲染(`sort((a,b)=>a.order-b.order)`),
964
+ // 这些条目都渲染在 `[data-slot="conversation.session.header.utilities"]`
965
+ // 这个 display:contents 锚点下、成为 flex 容器的直接子元素。官方
966
+ // 「选择打开方式」的分裂按钮(.CAgGvG_split)用 -10、官方会话日志导出
967
+ // 用默认 0,所以这里取 -100,让本入口成为该容器的**第一个**子元素。
930
968
  slots.inject('conversation.session.header.utilities', () => slots.register(
931
- { name: 'conversation.session.header.utilities', id: 'annual-activity', order: 50 },
969
+ { name: 'conversation.session.header.utilities', id: 'annual-activity', order: -100 },
932
970
  () => React.createElement(HeaderEntry, null)
933
971
  ));
934
972
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-annual-activity",
3
- "version": "1.1.4",
4
- "description": "全年活跃记录 (Annual Activity) — 一个纯本地的 DSH 活跃度统计面板:Host 半区扫描 $DSH_HOME/sessions 下的历史会话日志,按本地日期聚合每一天的活跃天/轮次/工具调用/Token 消耗,Client 半区以「年度热力图」面板渲染(统计行 + 5 级色块 + 月份轴 + 年份切换 + 连登统计),数据全部来自本机会话文件,不联网、不上报。",
3
+ "version": "1.1.5",
4
+ "description": "DSH-活跃记录 (Annual Activity) — 一个纯本地的 DSH 活跃度统计面板:Host 半区扫描 $DSH_HOME/sessions 下的历史会话日志,按本地日期聚合每一天的活跃天/轮次/工具调用/Token 消耗,Client 半区以「年度热力图」面板渲染(统计行 + 5 级色块 + 月份轴 + 年份切换 + 连登统计),数据全部来自本机会话文件,不联网、不上报。",
5
5
  "author": "spartaattack",
6
6
  "type": "module",
7
7
  "main": "lib/index.js",