Skip to content

Commit c94988d

Browse files
Show the build as a status card
The Build tab's cramped status row becomes an inset card: the state glyph and title with the task count, the coding agent's live activity, one progress segment per task, and a footer naming who started the build, when, and the machine it runs on, with the action on the right. The machine's online dot shows only to the build's starter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 8809b41 commit c94988d

3 files changed

Lines changed: 458 additions & 125 deletions

File tree

‎apps/web/src/build-view.css‎

Lines changed: 181 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,196 @@
5454
font-variant-numeric: tabular-nums;
5555
}
5656

57-
.build-activity {
57+
/*
58+
* The build's status card: title and count, what the agent is doing, one segment per task, then who
59+
* started it, the machine it runs on and the action, under a rule that runs edge to edge.
60+
*/
61+
.build-card {
62+
display: grid;
63+
gap: calc(var(--spacing) * 3);
64+
padding: calc(var(--spacing) * 3) calc(var(--spacing) * 4);
65+
border: var(--edge-width) solid var(--color-edge);
66+
border-radius: var(--radius-xl);
67+
background: var(--color-inset);
68+
font-size: var(--text-sm);
69+
}
70+
71+
.build-card-top {
5872
display: flex;
59-
flex-wrap: wrap;
60-
gap: var(--spacing) calc(var(--spacing) * 3);
61-
margin: calc(var(--spacing) * 2) 0 0;
73+
min-width: 0;
74+
align-items: center;
75+
gap: calc(var(--spacing) * 2);
76+
margin: 0;
77+
}
78+
79+
.build-card-title {
80+
min-width: 0;
81+
flex: 1;
82+
color: var(--color-text-primary);
83+
font-weight: var(--font-weight-medium);
84+
}
85+
86+
.build-card-count {
87+
flex: none;
88+
color: var(--color-text-tertiary);
89+
font-size: var(--text-xs);
90+
font-variant-numeric: tabular-nums;
91+
}
92+
93+
.build-card-detail {
94+
display: flex;
95+
min-width: 0;
96+
margin: 0;
6297
color: var(--color-text-secondary);
6398
font-size: var(--text-xs);
64-
overflow-wrap: anywhere;
6599
}
66100

67-
.build-activity time {
101+
/* The activity line sits close under the title, above the segments. */
102+
.build-card-top + .build-card-detail {
103+
margin-block-start: calc(var(--spacing) * -2);
104+
}
105+
106+
.build-card-ticker {
107+
min-width: 0;
108+
overflow: hidden;
109+
text-overflow: ellipsis;
110+
white-space: nowrap;
111+
}
112+
113+
.build-card-check {
114+
width: var(--icon-size-default);
115+
height: var(--icon-size-default);
116+
flex: none;
117+
color: var(--color-success-icon);
118+
}
119+
120+
/* A build that is live breathes; the words beside it say what it is doing. */
121+
@keyframes build-card-breathe {
122+
50% {
123+
opacity: var(--opacity-quiet);
124+
}
125+
}
126+
127+
/* One segment per task: green when done, and green with a soft lighter sweep while it runs. */
128+
@keyframes build-card-sweep {
129+
from {
130+
background-position: 100% 0;
131+
}
132+
to {
133+
background-position: -100% 0;
134+
}
135+
}
136+
137+
.build-card-segments {
138+
display: flex;
139+
gap: var(--spacing);
140+
}
141+
142+
.build-card-segments > span {
143+
height: var(--spacing);
144+
flex: 1;
145+
border-radius: var(--radius-full);
146+
background: var(--color-selected-strong);
147+
transition: background-color var(--duration-base) var(--ease-out);
148+
}
149+
150+
.build-card-segments > span:is([data-state="completed"], [data-state="in_progress"]) {
151+
background: var(--color-success-graphic);
152+
}
153+
154+
.build-card-segments > span[data-state="blocked"] {
155+
background: var(--color-warning-graphic);
156+
}
157+
158+
@media (prefers-reduced-motion: no-preference) {
159+
.build-card-spin {
160+
animation: button-loader-spin calc(var(--duration-base) * 4) linear infinite;
161+
}
162+
163+
.build-card-ticker {
164+
animation: build-fade var(--duration-linger) var(--ease-out);
165+
}
166+
167+
.build-card .build-glyph[data-live] {
168+
animation: build-card-breathe calc(var(--duration-linger) * 6) var(--motion-move) infinite;
169+
}
170+
171+
.build-card-segments > span[data-state="in_progress"] {
172+
background: linear-gradient(
173+
90deg,
174+
var(--color-success-graphic) 0%,
175+
var(--color-success-graphic) 30%,
176+
color-mix(in srgb, var(--color-success-graphic) 55%, var(--color-page)) 50%,
177+
var(--color-success-graphic) 70%,
178+
var(--color-success-graphic) 100%
179+
);
180+
background-size: 250% 100%;
181+
animation: build-card-sweep calc(var(--duration-linger) * 8) linear infinite;
182+
}
183+
}
184+
185+
.build-card-foot {
186+
display: flex;
187+
flex-wrap: wrap;
188+
align-items: center;
189+
gap: calc(var(--spacing) * 3) calc(var(--spacing) * 5);
190+
margin-inline: calc(var(--spacing) * -4);
191+
padding: calc(var(--spacing) * 3) calc(var(--spacing) * 4) 0;
192+
border-block-start: var(--edge-width) solid var(--color-edge);
193+
font-size: var(--text-xs);
194+
}
195+
196+
.build-card-person,
197+
.build-card-machine {
198+
display: inline-flex;
199+
min-width: 0;
200+
align-items: center;
201+
gap: calc(var(--spacing) * 2);
202+
}
203+
204+
.build-card-person-name {
205+
color: var(--color-text-secondary);
206+
font-weight: var(--font-weight-medium);
207+
}
208+
209+
.build-card-quiet {
68210
color: var(--color-text-tertiary);
69211
font-variant-numeric: tabular-nums;
70212
}
71213

214+
.build-card-machine {
215+
color: var(--color-text-secondary);
216+
}
217+
218+
.build-card-machine-name {
219+
min-width: 0;
220+
overflow: hidden;
221+
text-overflow: ellipsis;
222+
white-space: nowrap;
223+
}
224+
225+
/* A 6px state dot, smaller than the shared glyph's, ringed in the card's inset surface. */
226+
.build-card-machine .machine-glyph-dot {
227+
width: calc(var(--spacing) * 1.5);
228+
height: calc(var(--spacing) * 1.5);
229+
right: calc(var(--spacing) * -0.75);
230+
bottom: calc(var(--spacing) * -0.75);
231+
border-width: calc(var(--spacing) * 0.375);
232+
border-color: var(--color-inset);
233+
}
234+
235+
/* Stop's square, drawn in the button's ink. */
236+
.build-card-stop {
237+
width: calc(var(--spacing) * 2);
238+
height: calc(var(--spacing) * 2);
239+
flex: none;
240+
background: currentColor;
241+
}
242+
243+
.build-card + .build-tasks {
244+
margin-block-start: calc(var(--spacing) * 6);
245+
}
246+
72247
/* Tasks drafted for an earlier revision stay readable but recede. */
73248
.build-tasks[data-stale] {
74249
opacity: var(--opacity-quiet);

0 commit comments

Comments
 (0)