@@ -18,6 +18,8 @@ export type TimelineEventState = "complete" | "error" | "inprogress" | "delayed"
18
18
19
19
type TimelineLineVariant = "light" | "normal" ;
20
20
21
+ type TimelineStyle = "normal" | "diminished" ;
22
+
21
23
type TimelineEventVariant =
22
24
| "start-cap"
23
25
| "dot-hollow"
@@ -317,6 +319,7 @@ export type RunTimelineEventProps = {
317
319
state ?: "complete" | "error" | "inprogress" ;
318
320
variant ?: TimelineEventVariant ;
319
321
helpText ?: string ;
322
+ style ?: TimelineStyle ;
320
323
} ;
321
324
322
325
export function RunTimelineEvent ( {
@@ -325,11 +328,12 @@ export function RunTimelineEvent({
325
328
state,
326
329
variant = "dot-hollow" ,
327
330
helpText,
331
+ style = "normal" ,
328
332
} : RunTimelineEventProps ) {
329
333
return (
330
334
< div className = "grid h-5 grid-cols-[1.125rem_1fr] gap-1 text-sm" >
331
335
< div className = "relative flex flex-col items-center justify-center" >
332
- < EventMarker variant = { variant } state = { state } />
336
+ < EventMarker variant = { variant } state = { state } style = { style } />
333
337
</ div >
334
338
< div className = "flex items-baseline justify-between gap-3" >
335
339
< TooltipProvider disableHoverableContent >
@@ -355,38 +359,53 @@ export function RunTimelineEvent({
355
359
function EventMarker ( {
356
360
variant,
357
361
state,
362
+ style,
358
363
} : {
359
364
variant : TimelineEventVariant ;
360
365
state ?: TimelineEventState ;
366
+ style ?: TimelineStyle ;
361
367
} ) {
368
+ let bgClass = "bg-text-dimmed" ;
369
+ switch ( state ) {
370
+ case "complete" :
371
+ bgClass = "bg-success" ;
372
+ break ;
373
+ case "error" :
374
+ bgClass = "bg-error" ;
375
+ break ;
376
+ case "delayed" :
377
+ bgClass = "bg-text-dimmed" ;
378
+ break ;
379
+ case "inprogress" :
380
+ bgClass = style === "normal" ? "bg-pending" : "bg-text-dimmed" ;
381
+ break ;
382
+ }
383
+
384
+ let borderClass = "border-text-dimmed" ;
385
+ switch ( state ) {
386
+ case "complete" :
387
+ borderClass = "border-success" ;
388
+ break ;
389
+ case "error" :
390
+ borderClass = "border-error" ;
391
+ break ;
392
+ case "delayed" :
393
+ borderClass = "border-text-dimmed" ;
394
+ break ;
395
+ case "inprogress" :
396
+ borderClass = style === "normal" ? "border-pending" : "border-text-dimmed" ;
397
+ break ;
398
+ default :
399
+ borderClass = "border-text-dimmed" ;
400
+ break ;
401
+ }
402
+
362
403
switch ( variant ) {
363
404
case "start-cap" :
364
405
return (
365
406
< >
366
- < div
367
- className = { cn (
368
- "h-full w-[0.4375rem] border-b" ,
369
- state === "complete"
370
- ? "border-success"
371
- : state === "error"
372
- ? "border-error"
373
- : state === "inprogress"
374
- ? "border-pending"
375
- : "border-text-dimmed"
376
- ) }
377
- />
378
- < div
379
- className = { cn (
380
- "relative h-full w-px" ,
381
- state === "complete"
382
- ? "bg-success"
383
- : state === "error"
384
- ? "bg-error"
385
- : state === "inprogress"
386
- ? "bg-pending"
387
- : "bg-text-dimmed"
388
- ) }
389
- >
407
+ < div className = { cn ( "h-full w-[0.4375rem] border-b" , borderClass ) } />
408
+ < div className = { cn ( "relative h-full w-px" , bgClass ) } >
390
409
{ state === "inprogress" && (
391
410
< div
392
411
className = "absolute inset-0 h-full w-full animate-tile-scroll opacity-30"
@@ -402,18 +421,7 @@ function EventMarker({
402
421
case "dot-hollow" :
403
422
return (
404
423
< >
405
- < div
406
- className = { cn (
407
- "relative h-full w-px" ,
408
- state === "complete"
409
- ? "bg-success"
410
- : state === "error"
411
- ? "bg-error"
412
- : state === "inprogress"
413
- ? "bg-pending"
414
- : "bg-text-dimmed"
415
- ) }
416
- >
424
+ < div className = { cn ( "relative h-full w-px" , bgClass ) } >
417
425
{ state === "inprogress" && (
418
426
< div
419
427
className = "absolute inset-0 h-full w-full animate-tile-scroll-offset opacity-30"
@@ -425,29 +433,9 @@ function EventMarker({
425
433
) }
426
434
</ div >
427
435
< div
428
- className = { cn (
429
- "size-[0.3125rem] min-h-[0.3125rem] rounded-full border" ,
430
- state === "complete"
431
- ? "border-success"
432
- : state === "error"
433
- ? "border-error"
434
- : state === "inprogress"
435
- ? "border-pending"
436
- : "border-text-dimmed"
437
- ) }
436
+ className = { cn ( "size-[0.3125rem] min-h-[0.3125rem] rounded-full border" , borderClass ) }
438
437
/>
439
- < div
440
- className = { cn (
441
- "relative h-full w-px" ,
442
- state === "complete"
443
- ? "bg-success"
444
- : state === "error"
445
- ? "bg-error"
446
- : state === "inprogress"
447
- ? "bg-pending"
448
- : "bg-text-dimmed"
449
- ) }
450
- >
438
+ < div className = { cn ( "relative h-full w-px" , bgClass ) } >
451
439
{ state === "inprogress" && (
452
440
< div
453
441
className = "absolute inset-0 h-full w-full animate-tile-scroll-offset opacity-30"
@@ -461,28 +449,10 @@ function EventMarker({
461
449
</ >
462
450
) ;
463
451
case "dot-solid" :
464
- return (
465
- < div
466
- className = { cn (
467
- "size-[0.3125rem] rounded-full" ,
468
- state === "complete" ? "bg-success" : state === "error" ? "bg-error" : "bg-text-dimmed"
469
- ) }
470
- />
471
- ) ;
452
+ return < div className = { cn ( "size-[0.3125rem] rounded-full" , bgClass ) } /> ;
472
453
case "start-cap-thick" :
473
454
return (
474
- < div
475
- className = { cn (
476
- "relative h-full w-[0.4375rem] rounded-t-[0.125rem]" ,
477
- state === "complete"
478
- ? "bg-success"
479
- : state === "error"
480
- ? "bg-error"
481
- : state === "inprogress"
482
- ? "bg-pending"
483
- : "bg-text-dimmed"
484
- ) }
485
- >
455
+ < div className = { cn ( "relative h-full w-[0.4375rem] rounded-t-[0.125rem]" , bgClass ) } >
486
456
{ state === "inprogress" && (
487
457
< div
488
458
className = "absolute inset-0 h-full w-full animate-tile-scroll-offset opacity-30"
@@ -495,14 +465,7 @@ function EventMarker({
495
465
</ div >
496
466
) ;
497
467
case "end-cap-thick" :
498
- return (
499
- < div
500
- className = { cn (
501
- "h-full w-[0.4375rem] rounded-b-[0.125rem]" ,
502
- state === "complete" ? "bg-success" : state === "error" ? "bg-error" : "bg-text-dimmed"
503
- ) }
504
- />
505
- ) ;
468
+ return < div className = { cn ( "h-full w-[0.4375rem] rounded-b-[0.125rem]" , bgClass ) } /> ;
506
469
default :
507
470
return < div className = { cn ( "size-[0.3125rem] rounded-full bg-yellow-500" ) } /> ;
508
471
}
@@ -512,13 +475,19 @@ export type RunTimelineLineProps = {
512
475
title : ReactNode ;
513
476
state ?: TimelineEventState ;
514
477
variant ?: TimelineLineVariant ;
478
+ style ?: TimelineStyle ;
515
479
} ;
516
480
517
- export function RunTimelineLine ( { title, state, variant = "normal" } : RunTimelineLineProps ) {
481
+ export function RunTimelineLine ( {
482
+ title,
483
+ state,
484
+ variant = "normal" ,
485
+ style = "normal" ,
486
+ } : RunTimelineLineProps ) {
518
487
return (
519
488
< div className = "grid h-6 grid-cols-[1.125rem_1fr] gap-1 text-xs" >
520
489
< div className = "flex items-stretch justify-center" >
521
- < LineMarker state = { state } variant = { variant } />
490
+ < LineMarker state = { state } variant = { variant } style = { style } />
522
491
</ div >
523
492
< div className = "flex items-center justify-between gap-3" >
524
493
< span className = "text-text-dimmed" > { title } </ span >
@@ -530,27 +499,35 @@ export function RunTimelineLine({ title, state, variant = "normal" }: RunTimelin
530
499
function LineMarker ( {
531
500
state,
532
501
variant,
502
+ style,
533
503
} : {
534
504
state ?: TimelineEventState ;
535
505
variant : TimelineLineVariant ;
506
+ style ?: TimelineStyle ;
536
507
} ) {
508
+ let containerClass = "bg-text-dimmed" ;
509
+ switch ( state ) {
510
+ case "complete" :
511
+ containerClass = "bg-success" ;
512
+ break ;
513
+ case "error" :
514
+ containerClass = "bg-error" ;
515
+ break ;
516
+ case "delayed" :
517
+ containerClass = "bg-text-dimmed" ;
518
+ break ;
519
+ case "inprogress" :
520
+ containerClass =
521
+ style === "normal"
522
+ ? "rounded-b-[0.125rem] bg-pending"
523
+ : "rounded-b-[0.125rem] bg-text-dimmed" ;
524
+ break ;
525
+ }
526
+
537
527
switch ( variant ) {
538
528
case "normal" :
539
529
return (
540
- < div
541
- className = { cn (
542
- "relative w-[0.4375rem]" ,
543
- state === "complete"
544
- ? "bg-success"
545
- : state === "error"
546
- ? "bg-error"
547
- : state === "delayed"
548
- ? "bg-text-dimmed"
549
- : state === "inprogress"
550
- ? "rounded-b-[0.125rem] bg-pending"
551
- : "bg-text-dimmed"
552
- ) }
553
- >
530
+ < div className = { cn ( "relative w-[0.4375rem]" , containerClass ) } >
554
531
{ state === "inprogress" && (
555
532
< div
556
533
className = "absolute inset-0 h-full w-full animate-tile-scroll opacity-30"
@@ -564,20 +541,7 @@ function LineMarker({
564
541
) ;
565
542
case "light" :
566
543
return (
567
- < div
568
- className = { cn (
569
- "relative w-px" ,
570
- state === "complete"
571
- ? "bg-success"
572
- : state === "error"
573
- ? "bg-error"
574
- : state === "delayed"
575
- ? "bg-text-dimmed"
576
- : state === "inprogress"
577
- ? "bg-pending"
578
- : "bg-text-dimmed"
579
- ) }
580
- >
544
+ < div className = { cn ( "relative w-px" , containerClass ) } >
581
545
{ state === "inprogress" && (
582
546
< div
583
547
className = "absolute inset-0 h-full w-full animate-tile-scroll opacity-30"
@@ -600,6 +564,7 @@ export type SpanTimelineProps = {
600
564
inProgress : boolean ;
601
565
isError : boolean ;
602
566
events ?: TimelineSpanEvent [ ] ;
567
+ style ?: TimelineStyle ;
603
568
} ;
604
569
605
570
export type SpanTimelineState = "error" | "pending" | "complete" ;
@@ -610,6 +575,7 @@ export function SpanTimeline({
610
575
inProgress,
611
576
isError,
612
577
events,
578
+ style = "diminished" ,
613
579
} : SpanTimelineProps ) {
614
580
const state = isError ? "error" : inProgress ? "inprogress" : undefined ;
615
581
@@ -630,6 +596,7 @@ export function SpanTimeline({
630
596
variant = { event . markerVariant }
631
597
state = { state }
632
598
helpText = { event . helpText }
599
+ style = { style }
633
600
/>
634
601
< RunTimelineLine
635
602
title = {
@@ -641,6 +608,7 @@ export function SpanTimeline({
641
608
}
642
609
variant = { event . lineVariant }
643
610
state = { state }
611
+ style = { style }
644
612
/>
645
613
</ Fragment >
646
614
) ;
@@ -658,12 +626,14 @@ export function SpanTimeline({
658
626
variant = { "start-cap-thick" }
659
627
state = { state }
660
628
helpText = { getHelpTextForEvent ( "Started" ) }
629
+ style = { style }
661
630
/>
662
631
{ state === "inprogress" ? (
663
632
< RunTimelineLine
664
633
title = { < LiveTimer startTime = { startTime } /> }
665
634
state = { state }
666
635
variant = { visibleEvents . length > 0 ? "light" : "normal" }
636
+ style = { style }
667
637
/>
668
638
) : (
669
639
< >
@@ -674,6 +644,7 @@ export function SpanTimeline({
674
644
) }
675
645
state = { isError ? "error" : undefined }
676
646
variant = "normal"
647
+ style = { style }
677
648
/>
678
649
< RunTimelineEvent
679
650
title = "Finished"
@@ -686,6 +657,7 @@ export function SpanTimeline({
686
657
state = { isError ? "error" : undefined }
687
658
variant = "end-cap-thick"
688
659
helpText = { getHelpTextForEvent ( "Finished" ) }
660
+ style = { style }
689
661
/>
690
662
</ >
691
663
) }
0 commit comments