Diff hunks + thread context on review comments; preview env links; hide matrix placeholder

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DgBEW6qAwgn2fcQbA2f4ZQ
This commit is contained in:
Joshua Coles
2026-07-28 14:51:01 +00:00
co-authored by Claude Fable 5
parent df0e82e372
commit d14b6ebed3
11 changed files with 170 additions and 15 deletions
+5
View File
@@ -20,6 +20,11 @@ export default function PrCard({ pr, unread }: { pr: PrSnapshot; unread: number
{pr.branch}
</span>
<span>{relativeTime(pr.updatedAt)}</span>
{pr.previewUrl && (
<a className="preview-link" href={pr.previewUrl} target="_blank" rel="noreferrer">
preview ↗
</a>
)}
</div>
<div className="chips-row">
<ReviewBadge pr={pr} />
+39 -6
View File
@@ -62,14 +62,43 @@ function KindLabel({ event }: { event: TimelineEvent }) {
if (event.kind === 'review_comment') {
return (
<span>
commented{event.path ? ' on ' : ''}
{event.path && <span className="path">{event.path.split('/').pop()}</span>}
{event.inReplyTo ? 'replied' : 'commented'}
{event.path ? ' on ' : ''}
{event.path && (
<span className="path" title={event.path}>
{event.path.split('/').pop()}
</span>
)}
</span>
);
}
return <span>commented</span>;
}
function DiffHunk({ hunk }: { hunk: string }) {
return (
<pre className="tl-diff">
{hunk.split('\n').map((line, i) => (
<span
key={i}
className={
line.startsWith('+')
? 'diff-add'
: line.startsWith('-')
? 'diff-del'
: line.startsWith('@@')
? 'diff-meta'
: ''
}
>
{line || ' '}
{'\n'}
</span>
))}
</pre>
);
}
export default function Timeline() {
const [unreadOnly, setUnreadOnly] = useState(false);
const queryClient = useQueryClient();
@@ -144,14 +173,18 @@ export default function Timeline() {
readMutation.mutate({ id: e.id, read: !e.read });
}}
/>
<div>
<div className="tl-content">
<div className="tl-kind">
<KindLabel event={e} />
</div>
{e.diffHunk && !e.inReplyTo && <DiffHunk hunk={e.diffHunk} />}
{e.inReplyTo && (
<div className="tl-reply-ctx">
↳ <span className="actor">{e.inReplyTo.actor}</span>:{' '}
{e.inReplyTo.bodyExcerpt}
<div className="tl-thread">
{e.diffHunk && <DiffHunk hunk={e.diffHunk} />}
<div className="tl-reply-ctx">
<span className="actor">{e.inReplyTo.actor}</span>{' '}
{e.inReplyTo.bodyExcerpt}
</div>
</div>
)}
{e.bodyExcerpt && <div className="body">{e.bodyExcerpt}</div>}
+57 -2
View File
@@ -288,6 +288,19 @@ button {
white-space: nowrap;
}
.preview-link {
color: var(--accent);
text-decoration: none;
font-weight: 600;
border: 1px solid var(--border);
border-radius: 4px;
padding: 0 5px;
}
.preview-link:hover {
border-color: var(--accent);
}
.unread-pill {
background: var(--unread);
color: #fff;
@@ -580,11 +593,20 @@ a.check-row:hover {
background: var(--unread);
}
.tl-content {
min-width: 0;
flex: 1;
}
.tl-thread {
border-left: 2px solid var(--hairline);
padding-left: 8px;
margin: 3px 0;
}
.tl-reply-ctx {
font-size: 12px;
color: var(--ink-muted);
border-left: 2px solid var(--hairline);
padding-left: 7px;
margin: 2px 0;
display: -webkit-box;
-webkit-line-clamp: 2;
@@ -597,6 +619,39 @@ a.check-row:hover {
font-weight: 600;
}
.tl-diff {
margin: 3px 0;
padding: 6px 8px;
border: 1px solid var(--hairline);
border-radius: 6px;
background: var(--page);
font-family: ui-monospace, monospace;
font-size: 11px;
line-height: 1.5;
overflow-x: auto;
white-space: pre;
max-height: 160px;
overflow-y: auto;
}
.tl-diff .diff-add {
color: var(--status-pass-text);
background: var(--chip-pass-bg);
display: inline-block;
min-width: 100%;
}
.tl-diff .diff-del {
color: var(--status-fail-text);
background: var(--chip-fail-bg);
display: inline-block;
min-width: 100%;
}
.tl-diff .diff-meta {
color: var(--ink-muted);
}
.tl-item .body {
color: var(--ink-secondary);
font-size: 13px;