tavern-harness 0.1.20 → 0.1.21

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/CHANGELOG.md CHANGED
@@ -3,6 +3,26 @@
3
3
  > 本文件由 `scripts/changelog.mjs` 从 `changelog/v*.md` 生成,请勿手动编辑。
4
4
  > 版本对比链接见文末;源文件位于仓库 `changelog/` 目录。
5
5
 
6
+ ## [0.1.21] - 2026-10-26
7
+
8
+ ### 中文
9
+
10
+ #### 改进
11
+
12
+ - 移动端会话头部的操作按钮收进「更多操作」菜单(工作区文件、编辑对话、重置对话、导出游玩记录、删除对话),头部不再拥挤;主题切换按钮仍然直接显示
13
+ - 移动端会话标题可用的横向空间明显变大,长标题能显示更多内容
14
+ - 会话列表中的标题和副标题过长时改为末尾渐隐,不再用省略号生硬截断
15
+ - 会话头部的上下文用量标签字号略微收小,和标题搭配更协调
16
+
17
+ ### English
18
+
19
+ #### Changed
20
+
21
+ - On mobile, session header actions now collapse into a "More actions" menu (workspace files, edit, reset, export gameplay, delete), so the header is no longer cramped; the theme toggle stays one tap away
22
+ - Mobile session titles get noticeably more horizontal room, so long titles reveal more of their text
23
+ - Long session list titles and subtitles now fade out at the end instead of being cut off with an ellipsis
24
+ - The context usage badge in the session header uses a slightly smaller font so it sits better next to the title
25
+
6
26
  ## [0.1.20] - 2026-10-26
7
27
 
8
28
  ### 中文
@@ -588,6 +608,7 @@
588
608
  - Vite + React + Zustand + Dexie stack with browser-side local persistence
589
609
 
590
610
  <!-- 链接定义 -->
611
+ [0.1.21]: https://github.com/Rannichan/Tavern-Harness/compare/v0.1.20...v0.1.21
591
612
  [0.1.20]: https://github.com/Rannichan/Tavern-Harness/compare/v0.1.19...v0.1.20
592
613
  [0.1.19]: https://github.com/Rannichan/Tavern-Harness/compare/v0.1.18...v0.1.19
593
614
  [0.1.18]: https://github.com/Rannichan/Tavern-Harness/compare/v0.1.17...v0.1.18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tavern-harness",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
4
4
  "description": "Tavern Harness — 酒馆模式下的本地 AI Agent 助手(MyAgent-Android 的 Web 复刻)",
5
5
  "private": false,
6
6
  "type": "module",
package/src/App.tsx CHANGED
@@ -327,6 +327,8 @@ function SessionHeader({
327
327
  const [confirmDelete, setConfirmDelete] = useState(false);
328
328
  const [exportOpen, setExportOpen] = useState(false);
329
329
  const [showWorkspace, setShowWorkspace] = useState(false);
330
+ const [showMobileActions, setShowMobileActions] = useState(false);
331
+ const mobileActionsRef = useRef<HTMLDivElement>(null);
330
332
 
331
333
  const messages = useStore((s) => s.messages[session.id!] ?? []);
332
334
  const contextTokens = useMemo(() => {
@@ -350,6 +352,17 @@ function SessionHeader({
350
352
  || (themeMode === 'system' && document.documentElement.dataset.theme === 'dark');
351
353
  const toggleTheme = () => void setSettings({ themeMode: isDarkTheme ? 'light' : 'dark' });
352
354
 
355
+ useEffect(() => {
356
+ if (!showMobileActions) return;
357
+ const closeOnOutsidePointerDown = (event: PointerEvent) => {
358
+ if (!mobileActionsRef.current?.contains(event.target as Node)) {
359
+ setShowMobileActions(false);
360
+ }
361
+ };
362
+ document.addEventListener('pointerdown', closeOnOutsidePointerDown);
363
+ return () => document.removeEventListener('pointerdown', closeOnOutsidePointerDown);
364
+ }, [showMobileActions]);
365
+
353
366
  return (
354
367
  <div className="chat-header">
355
368
  <SessionVisual mode={session.mode} npcName={npcRef?.name ?? undefined} hue={npcRef?.avatarColorOrdinal ?? 0} imageUrl={npcRef?.avatarDataUrl} members={session.mode === 'GROUP' ? groupMemberAvatars : undefined} size="lg" />
@@ -361,7 +374,7 @@ function SessionHeader({
361
374
  </div>
362
375
  )}
363
376
  </div>
364
- <div className="chat-actions">
377
+ <div className="chat-actions" ref={mobileActionsRef}>
365
378
  <button className="btn-ghost icon-tooltip" title={t(usesPublicWorkspace ? 'header.workspaceRootHint' : 'header.workspaceHint')} onClick={() => setShowWorkspace(true)}>
366
379
  <Icon name="folder" size={17} />
367
380
  </button>
@@ -378,7 +391,17 @@ function SessionHeader({
378
391
  <Icon name="trash" size={17} />
379
392
  </button>
380
393
  <button
381
- className="btn-ghost icon-tooltip"
394
+ className="btn-ghost icon-tooltip chat-actions-more"
395
+ type="button"
396
+ title={t('header.moreActions')}
397
+ aria-label={t('header.moreActions')}
398
+ aria-expanded={showMobileActions}
399
+ onClick={() => setShowMobileActions(!showMobileActions)}
400
+ >
401
+ <Icon name="more" size={18} />
402
+ </button>
403
+ <button
404
+ className="btn-ghost icon-tooltip chat-theme-toggle"
382
405
  type="button"
383
406
  title={t(isDarkTheme ? 'header.switchToLightTip' : 'header.switchToDarkTip')}
384
407
  aria-label={t(isDarkTheme ? 'header.switchToLightTip' : 'header.switchToDarkTip')}
@@ -386,6 +409,25 @@ function SessionHeader({
386
409
  >
387
410
  <Icon name={isDarkTheme ? 'sun' : 'moon'} size={17} />
388
411
  </button>
412
+ {showMobileActions && (
413
+ <div className="chat-actions-menu card">
414
+ <button onClick={() => { setShowWorkspace(true); setShowMobileActions(false); }}>
415
+ <Icon name="folder" size={15} /> {t('header.workspaceAction')}
416
+ </button>
417
+ <button onClick={() => { setShowEdit(true); setShowMobileActions(false); }}>
418
+ <Icon name="pencil" size={15} /> {t('nav.editSession')}
419
+ </button>
420
+ <button onClick={() => { setConfirmReset(true); setShowMobileActions(false); }}>
421
+ <Icon name="refresh" size={15} /> {t('header.resetSessionTip')}
422
+ </button>
423
+ <button onClick={() => { setExportOpen(true); setShowMobileActions(false); }}>
424
+ <Icon name="share" size={15} /> {t('nav.exportGameplay')}
425
+ </button>
426
+ <button className="danger" onClick={() => { setConfirmDelete(true); setShowMobileActions(false); }}>
427
+ <Icon name="trash" size={15} /> {t('header.deleteTip')}
428
+ </button>
429
+ </div>
430
+ )}
389
431
  </div>
390
432
 
391
433
  {showEdit && <NewSessionMenu editingSession={session} onClose={() => setShowEdit(false)} />}
package/src/core/i18n.ts CHANGED
@@ -81,6 +81,8 @@ const MESSAGES: Record<LangKey, Record<string, string>> = {
81
81
  'header.modeStandard': '标准对话',
82
82
  'header.modeNpc': '角色对话',
83
83
  'header.modeGroup': '群聊',
84
+ 'header.moreActions': '更多操作',
85
+ 'header.workspaceAction': '工作区文件',
84
86
  'header.editSessionTip': '编辑对话设置',
85
87
  'header.resetSessionTip': '重置对话',
86
88
  'header.resetSessionTitle': '重置对话',
@@ -605,6 +607,8 @@ const MESSAGES: Record<LangKey, Record<string, string>> = {
605
607
  'header.modeStandard': '標準對話',
606
608
  'header.modeNpc': '角色對話',
607
609
  'header.modeGroup': '群聊',
610
+ 'header.moreActions': '更多操作',
611
+ 'header.workspaceAction': '工作區檔案',
608
612
  'header.editSessionTip': '編輯對話設定',
609
613
  'header.resetSessionTip': '重置對話',
610
614
  'header.resetSessionTitle': '重置對話',
@@ -1117,6 +1121,8 @@ const MESSAGES: Record<LangKey, Record<string, string>> = {
1117
1121
  'header.modeStandard': 'Standard chat',
1118
1122
  'header.modeNpc': 'Character chat',
1119
1123
  'header.modeGroup': 'Group chat',
1124
+ 'header.moreActions': 'More actions',
1125
+ 'header.workspaceAction': 'Workspace files',
1120
1126
  'header.editSessionTip': 'Edit conversation settings',
1121
1127
  'header.resetSessionTip': 'Reset conversation',
1122
1128
  'header.resetSessionTitle': 'Reset conversation',
@@ -1,7 +1,37 @@
1
1
  {
2
- "latest": "0.1.20",
2
+ "latest": "0.1.21",
3
3
  "repo": "https://github.com/Rannichan/Tavern-Harness",
4
4
  "entries": [
5
+ {
6
+ "version": "0.1.21",
7
+ "date": "2026-10-26",
8
+ "breaking": false,
9
+ "compare": "v0.1.20...v0.1.21",
10
+ "groups": {
11
+ "zh-CN": [
12
+ {
13
+ "kind": "changed",
14
+ "items": [
15
+ "移动端会话头部的操作按钮收进「更多操作」菜单(工作区文件、编辑对话、重置对话、导出游玩记录、删除对话),头部不再拥挤;主题切换按钮仍然直接显示",
16
+ "移动端会话标题可用的横向空间明显变大,长标题能显示更多内容",
17
+ "会话列表中的标题和副标题过长时改为末尾渐隐,不再用省略号生硬截断",
18
+ "会话头部的上下文用量标签字号略微收小,和标题搭配更协调"
19
+ ]
20
+ }
21
+ ],
22
+ "en": [
23
+ {
24
+ "kind": "changed",
25
+ "items": [
26
+ "On mobile, session header actions now collapse into a \"More actions\" menu (workspace files, edit, reset, export gameplay, delete), so the header is no longer cramped; the theme toggle stays one tap away",
27
+ "Mobile session titles get noticeably more horizontal room, so long titles reveal more of their text",
28
+ "Long session list titles and subtitles now fade out at the end instead of being cut off with an ellipsis",
29
+ "The context usage badge in the session header uses a slightly smaller font so it sits better next to the title"
30
+ ]
31
+ }
32
+ ]
33
+ }
34
+ },
5
35
  {
6
36
  "version": "0.1.20",
7
37
  "date": "2026-10-26",
@@ -573,9 +573,10 @@ body.resizing .sidebar-resizer {
573
573
  }
574
574
  .session-item .stitle-text {
575
575
  overflow: hidden;
576
- text-overflow: ellipsis;
577
576
  white-space: nowrap;
578
577
  min-width: 0;
578
+ -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 18px), transparent);
579
+ mask-image: linear-gradient(to right, #000 calc(100% - 18px), transparent);
579
580
  }
580
581
  .session-item .spinned {
581
582
  display: inline-flex;
@@ -615,7 +616,8 @@ body.resizing .sidebar-resizer {
615
616
  color: var(--text-faint);
616
617
  white-space: nowrap;
617
618
  overflow: hidden;
618
- text-overflow: ellipsis;
619
+ -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 18px), transparent);
620
+ mask-image: linear-gradient(to right, #000 calc(100% - 18px), transparent);
619
621
  }
620
622
  /* ---------- 会话区域(头部 + 滚动列表) ---------- */
621
623
  .session-section {
@@ -1072,6 +1074,7 @@ body.resizing .sidebar-resizer {
1072
1074
  }
1073
1075
  .chat-header .tsub-mode {
1074
1076
  flex-shrink: 0;
1077
+ font-size: 12px;
1075
1078
  font-weight: 700;
1076
1079
  color: var(--primary);
1077
1080
  }
@@ -1111,6 +1114,10 @@ body.resizing .sidebar-resizer {
1111
1114
  color: var(--danger);
1112
1115
  background: var(--danger-soft);
1113
1116
  }
1117
+ .chat-actions .chat-actions-more,
1118
+ .chat-actions-menu {
1119
+ display: none;
1120
+ }
1114
1121
 
1115
1122
  /* ---------- 卡片/仪表盘 ---------- */
1116
1123
  .dash-scroll {
@@ -1799,7 +1806,7 @@ hr.sep {
1799
1806
  }
1800
1807
 
1801
1808
  .chat-header .ttitle {
1802
- max-width: min(28vw, 180px);
1809
+ max-width: min(52vw, 260px);
1803
1810
  font-size: 15px;
1804
1811
  }
1805
1812
 
@@ -1808,16 +1815,67 @@ hr.sep {
1808
1815
  }
1809
1816
 
1810
1817
  .chat-actions {
1818
+ position: relative;
1811
1819
  flex: 0 0 auto;
1812
1820
  gap: 0;
1813
1821
  }
1814
1822
 
1823
+ .chat-actions .icon-tooltip:not(.chat-actions-more, .chat-theme-toggle) {
1824
+ display: none;
1825
+ }
1826
+
1827
+ .chat-actions .chat-actions-more {
1828
+ display: inline-flex;
1829
+ }
1830
+
1815
1831
  .chat-actions .icon-tooltip {
1816
1832
  width: 34px;
1817
1833
  height: 34px;
1818
1834
  flex-shrink: 0;
1819
1835
  }
1820
1836
 
1837
+ .chat-actions-menu {
1838
+ position: absolute;
1839
+ top: calc(100% + 6px);
1840
+ right: 0;
1841
+ z-index: 60;
1842
+ display: flex;
1843
+ flex-direction: column;
1844
+ min-width: 164px;
1845
+ padding: 6px;
1846
+ background: var(--surface);
1847
+ border: 1px solid var(--border);
1848
+ border-radius: 12px;
1849
+ box-shadow: var(--shadow-lg);
1850
+ }
1851
+
1852
+ .chat-actions-menu button {
1853
+ display: flex;
1854
+ align-items: center;
1855
+ gap: 9px;
1856
+ width: 100%;
1857
+ padding: 8px 10px;
1858
+ border: none;
1859
+ border-radius: 8px;
1860
+ background: none;
1861
+ color: var(--text);
1862
+ font-size: 13px;
1863
+ font-weight: 600;
1864
+ text-align: left;
1865
+ }
1866
+
1867
+ .chat-actions-menu button:hover {
1868
+ background: var(--surface-2);
1869
+ }
1870
+
1871
+ .chat-actions-menu button.danger {
1872
+ color: var(--danger);
1873
+ }
1874
+
1875
+ .chat-actions-menu button.danger:hover {
1876
+ background: var(--danger-soft);
1877
+ }
1878
+
1821
1879
  .chat-scroll {
1822
1880
  padding-top: 14px;
1823
1881
  }