Skip to content

Commit 60d713f

Browse files
Ubuntuclaude
andcommitted
feat(desktop/transcript): burn down #332 deferred — running-state/Stop, lifecycle overflow, hover actions, timestamps, skeletons, clamp, chrome i18n
Clears the deferred list from the #332 first pass (6a83324): - Running-state + composer Stop: poll the agent's lifecycle status (getAgent, 5s); the status strip gains a running dot + status word, the lifecycle bar shows a contextual primary (Stop while running / Resume while paused), and the composer's primary action becomes Stop when running with an empty draft (typing swaps back to Send). - Lifecycle-bar overflow: the five always-on buttons collapse to one primary + an overflow (⋯) menu (pause/resume/stop + terminate/archive as ConfirmButtons), closed on outside-click / Escape. - Per-message hover actions: copy + quote-into-composer on assistant text and director input (quote blockquote-prefixes and pushes to the composer via an inject signal). (insert-to-note is an AgentCompanion affordance — N/A in this surface, which has no note target.) - Timestamps: message rows render a relative time (absolute on hover) — the row `ts` the hub already emits, finally shown. (Full turn-grouping containers remain a heavier follow-up; turn.result dividers + per-row time cover the ask.) - Skeleton feed: shimmer cards replace the "Loading…" line. - Collapse rework: long assistant text clamps behind a fade with a Show more/less toggle instead of a <details> with a redundant dimmed preview. - Chrome i18n: the transcript's tool verbs, labels, and the code-block copy button route through i18n (en + zh). (RunReport i18n stays part of #318.) quoteToComposer is useCallback-stable so it doesn't defeat EventCard's memo (#311). Build (tsc + vite) + lint-desktop-tokens clean. Not device-tested. Co-Authored-By: Claude Opus 4.8 <[email protected]>
1 parent 6a83324 commit 60d713f

7 files changed

Lines changed: 529 additions & 79 deletions

File tree

desktop/src/i18n/index.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,27 @@ const en: Dict = {
252252
'tx.tokOut': 'out',
253253
'tx.new': 'new',
254254
'tx.latest': 'Latest',
255+
'tx.more': 'More actions',
256+
'tx.copy': 'Copy',
257+
'tx.copied': 'Copied',
258+
'tx.quote': 'Quote',
259+
'tx.showMore': 'Show more',
260+
'tx.showLess': 'Show less',
261+
'tx.arguments': 'Arguments',
262+
'tx.result': 'Result',
263+
'tx.errorLabel': 'Error',
264+
'tx.denied': 'Denied',
265+
'tx.thinking': 'Thinking…',
266+
'tx.session': 'Session',
267+
'tx.done': 'Done',
268+
'tx.verb.ran': 'Ran',
269+
'tx.verb.read': 'Read',
270+
'tx.verb.wrote': 'Wrote',
271+
'tx.verb.edited': 'Edited',
272+
'tx.verb.searched': 'Searched',
273+
'tx.verb.listed': 'Listed',
274+
'tx.verb.fetched': 'Fetched',
275+
'tx.now': 'now',
255276
'composer.attach': 'Attach file or image',
256277
'composer.unsupported': '{name}: unsupported file type',
257278
'composer.readFailed': '{name}: could not read file',
@@ -1504,6 +1525,27 @@ const zh: Dict = {
15041525
'tx.tokOut': '输出',
15051526
'tx.new': '新',
15061527
'tx.latest': '最新',
1528+
'tx.more': '更多操作',
1529+
'tx.copy': '复制',
1530+
'tx.copied': '已复制',
1531+
'tx.quote': '引用',
1532+
'tx.showMore': '展开',
1533+
'tx.showLess': '收起',
1534+
'tx.arguments': '参数',
1535+
'tx.result': '结果',
1536+
'tx.errorLabel': '错误',
1537+
'tx.denied': '已拒绝',
1538+
'tx.thinking': '思考中…',
1539+
'tx.session': '会话',
1540+
'tx.done': '完成',
1541+
'tx.verb.ran': '运行',
1542+
'tx.verb.read': '读取',
1543+
'tx.verb.wrote': '写入',
1544+
'tx.verb.edited': '编辑',
1545+
'tx.verb.searched': '搜索',
1546+
'tx.verb.listed': '列出',
1547+
'tx.verb.fetched': '获取',
1548+
'tx.now': '刚刚',
15071549
'composer.attach': '附加文件或图片',
15081550
'composer.unsupported': '{name}:不支持的文件类型',
15091551
'composer.readFailed': '{name}:无法读取文件',

desktop/src/styles/partials/04-library-nav.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,12 @@ button.small,
926926
color: var(--text-muted);
927927
background: var(--surface-sunken, var(--bg));
928928
}
929+
.transcript-status .ts-state {
930+
display: inline-flex;
931+
align-items: center;
932+
gap: var(--spacing-s4);
933+
text-transform: capitalize;
934+
}
929935
.transcript-status .ts-model {
930936
color: var(--text-secondary);
931937
font-weight: 600;

desktop/src/styles/partials/05-transcript-boards.css

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,155 @@
494494
color: var(--text-muted);
495495
font-style: italic;
496496
}
497+
498+
/* #332 clamp long assistant text behind a fade + a Show more/less toggle
499+
(rec 11). */
500+
.ev-clamp-body {
501+
position: relative;
502+
}
503+
.ev-clamp:not(.expanded) .ev-clamp-body {
504+
max-height: 15em;
505+
overflow: hidden;
506+
-webkit-mask-image: linear-gradient(to bottom, black 72%, transparent);
507+
mask-image: linear-gradient(to bottom, black 72%, transparent);
508+
}
509+
.ev-clamp-toggle {
510+
margin-top: var(--spacing-s4);
511+
padding: 0;
512+
background: none;
513+
border: none;
514+
color: var(--accent-text);
515+
cursor: pointer;
516+
font-size: var(--font-size-label);
517+
font-weight: 600;
518+
}
519+
.ev-clamp-toggle:hover {
520+
text-decoration: underline;
521+
}
522+
523+
/* #332 message footer — a relative timestamp (absolute on hover) + hover-revealed
524+
actions (copy / quote). */
525+
.ev-meta {
526+
display: flex;
527+
align-items: center;
528+
gap: var(--spacing-s8);
529+
margin-top: var(--spacing-s4);
530+
min-height: 18px;
531+
}
532+
.ev--user .ev-meta {
533+
justify-content: flex-end;
534+
}
535+
.ev-time {
536+
font-size: var(--font-size-label);
537+
color: var(--text-muted);
538+
font-variant-numeric: tabular-nums;
539+
}
540+
.ev-actions {
541+
display: inline-flex;
542+
align-items: center;
543+
gap: var(--spacing-s2);
544+
opacity: 0;
545+
transition: opacity 0.12s var(--ease);
546+
}
547+
.ev:hover .ev-actions,
548+
.ev-actions:focus-within {
549+
opacity: 1;
550+
}
551+
.ev-act {
552+
display: inline-flex;
553+
align-items: center;
554+
justify-content: center;
555+
width: 22px;
556+
height: 22px;
557+
padding: 0;
558+
background: none;
559+
border: none;
560+
color: var(--text-muted);
561+
cursor: pointer;
562+
border-radius: var(--radius-xs);
563+
}
564+
.ev-act:hover {
565+
background: var(--hover);
566+
color: var(--text);
567+
}
568+
569+
/* #332 lifecycle overflow menu — a dropdown off the ⋯ button. */
570+
.life-overflow {
571+
position: relative;
572+
display: inline-flex;
573+
}
574+
.life-menu {
575+
position: absolute;
576+
top: calc(100% + 4px);
577+
right: 0;
578+
z-index: 20;
579+
min-width: 150px;
580+
display: flex;
581+
flex-direction: column;
582+
gap: 2px;
583+
padding: 4px;
584+
background: var(--surface);
585+
border: 1px solid var(--border);
586+
border-radius: var(--radius-md);
587+
box-shadow: var(--sh-3);
588+
}
589+
.life-menu button {
590+
text-align: left;
591+
justify-content: flex-start;
592+
background: none;
593+
border: none;
594+
box-shadow: none;
595+
padding: var(--spacing-s4) var(--spacing-s8);
596+
font-size: var(--font-size-caption);
597+
border-radius: var(--radius-sm);
598+
}
599+
.life-menu button:hover {
600+
background: var(--hover);
601+
}
602+
603+
/* #332 composer Stop-while-running — the primary action turns destructive. */
604+
.composer .composer-stop {
605+
background: var(--danger);
606+
color: var(--accent-ink);
607+
}
608+
609+
/* #332 skeleton feed — shimmer cards instead of a "Loading…" line (rec 14). */
610+
.feed-skeleton {
611+
flex: 1 1 0;
612+
min-height: 0;
613+
overflow: hidden;
614+
padding-top: var(--spacing-s8);
615+
}
616+
.sk-card {
617+
display: flex;
618+
flex-direction: column;
619+
gap: var(--spacing-s8);
620+
padding: var(--spacing-s4) 0;
621+
}
622+
.sk-line {
623+
height: 12px;
624+
border-radius: var(--radius-sm);
625+
background: linear-gradient(90deg, var(--surface), var(--hover), var(--surface));
626+
background-size: 200% 100%;
627+
animation: sk-shimmer 1.3s ease-in-out infinite;
628+
}
629+
.sk-line.w40 {
630+
width: 40%;
631+
}
632+
.sk-line.w60 {
633+
width: 60%;
634+
}
635+
.sk-line.w90 {
636+
width: 90%;
637+
}
638+
@keyframes sk-shimmer {
639+
0% {
640+
background-position: 200% 0;
641+
}
642+
100% {
643+
background-position: -200% 0;
644+
}
645+
}
497646
.ev-input .ev-from {
498647
display: inline-block;
499648
color: var(--color-terminal-yellow);

0 commit comments

Comments
 (0)