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.
- package/README.md +19 -12
- package/lib/client.js +66 -28
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# 📅
|
|
1
|
+
# 📅 DSH-活跃记录 — dsh-annual-activity
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/dsh-annual-activity) [](https://github.com/Moveharder/dsh_plugins)
|
|
4
4
|
|
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
```
|
|
9
9
|
DSH 会话头部右上角 ↓
|
|
10
|
-
… 项目 / 会话名
|
|
11
|
-
|
|
10
|
+
… 项目 / 会话名 ▦ ▢▯ … ⊞
|
|
11
|
+
│ │ └ 官方「打开右侧边栏」(corner 槽)
|
|
12
|
+
│ └──────── 官方「选择打开方式」(utilities 槽,order -10)
|
|
13
|
+
└─────────── 本插件入口(utilities 槽,order -100 → 该槽第一个子元素)
|
|
12
14
|
|
|
13
15
|
┌──────────────────────────────────────────────────────────────────────────────┐
|
|
14
|
-
│
|
|
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
|
-
|
|
29
|
-
|
|
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
|
-
| **头部入口** |
|
|
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
|
-
|
|
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,
|
|
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'
|
|
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
|
|
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,
|
|
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 = '
|
|
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', {
|
|
677
|
-
|
|
678
|
-
|
|
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
|
-
|
|
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;
|
|
773
|
+
border:none;border-radius:28px;
|
|
755
774
|
color:var(--dsw-alias-label-secondary,#4b5563);
|
|
756
|
-
transition:background .14s ease,color .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
|
-
|
|
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),
|
|
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),
|
|
823
|
-
.daa-col{display:flex;flex-direction:column;gap:
|
|
824
|
-
.daa-
|
|
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:
|
|
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
|
-
"description": "
|
|
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",
|