Add pizza tracker component
This commit is contained in:
		
							parent
							
								
									61a308cbc6
								
							
						
					
					
						commit
						2eac3e6555
					
				| @ -0,0 +1,11 @@ | ||||
| <div class="tracker-bar" [class.transitions]="transitionsEnabled"> | ||||
|   <div class="stage {{ stages.waiting.state }}">Sent</div> | ||||
|   <div class="divider left-{{ stages.waiting.state }} right-{{ stages.pending.state }}"></div> | ||||
|   <div class="stage {{ stages.pending.state }}">Pending</div> | ||||
|   <div class="divider left-{{ stages.pending.state }} right-{{ stages.soon.state }}"></div> | ||||
|   <div class="stage {{ stages.soon.state }}">Soon</div> | ||||
|   <div class="divider left-{{ stages.soon.state }} right-{{ stages.next.state }}"></div> | ||||
|   <div class="stage {{ stages.next.state }}">Next block</div> | ||||
|   <div class="divider left-{{ stages.next.state }} right-{{ stages.confirmed.state }}"></div> | ||||
|   <div class="stage {{ stages.confirmed.state }}">Confirmed</div> | ||||
| </div> | ||||
							
								
								
									
										136
									
								
								frontend/src/app/components/tracker/tracker-bar.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								frontend/src/app/components/tracker/tracker-bar.component.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,136 @@ | ||||
| .tracker-bar { | ||||
|   width: 100%; | ||||
|   display: flex; | ||||
|   flex-direction: row; | ||||
| 
 | ||||
|   --div-left-color: var(--box-bg); | ||||
|   --div-right-color: var(--box-bg); | ||||
|   --stage-color: var(--box-bg); | ||||
| 
 | ||||
|   font-size: clamp(5px, 2.5vw, 15px); | ||||
|   height: clamp(15px, 7.5vw, 45px); | ||||
| 
 | ||||
|   .stage { | ||||
|     overflow: hidden; | ||||
|     border-top: solid 2px var(--stat-box-bg); | ||||
|     border-bottom: solid 2px var(--stat-box-bg); | ||||
|     background: var(--stage-color); | ||||
|     color: var(--transparent-fg); | ||||
|     padding: 1em; | ||||
|     flex-grow: 1; | ||||
|     flex-shrink: 1; | ||||
|     overflow: hidden; | ||||
|     text-wrap: nowrap; | ||||
|     text-overflow: hidden; | ||||
|     white-space: no-break; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
| 
 | ||||
|     &:first-child { | ||||
|       border-left: solid 2px var(--stat-box-bg); | ||||
|       border-top-left-radius: 1.6em; | ||||
|       border-bottom-left-radius: 1.6em; | ||||
|       padding-left: 1.6em; | ||||
|     } | ||||
|     &:last-child { | ||||
|       border-right: solid 2px var(--stat-box-bg); | ||||
|       border-top-right-radius: 1.6em; | ||||
|       border-bottom-right-radius: 1.6em; | ||||
|     } | ||||
|     &:nth-child(4n + 3) { | ||||
|       --stage-color: var(--secondary); | ||||
|     } | ||||
|     &.done { | ||||
|       --stage-color: var(--primary); | ||||
|       color: white; | ||||
|     } | ||||
|     &.current { | ||||
|       --stage-color: var(--tertiary); | ||||
|       color: white; | ||||
|     } | ||||
|     &.next { | ||||
|       animation: 1s linear alternate infinite pulse-next; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .divider { | ||||
|     position: relative; | ||||
|     overflow: hidden; | ||||
|     flex-shrink: 0; | ||||
|     flex-grow: 0; | ||||
|     background: var(--stat-box-bg); | ||||
|     border-top: solid 2px var(--stat-box-bg); | ||||
|     border-bottom: solid 2px var(--stat-box-bg); | ||||
| 
 | ||||
|     &.left-done { | ||||
|       --div-left-color: var(--primary); | ||||
|     } | ||||
|     &.left-current { | ||||
|       --div-left-color: var(--tertiary); | ||||
|     } | ||||
|     &.left-blank, &.left-next { | ||||
|       &:nth-child(4n + 0) { | ||||
|         --div-left-color: var(--secondary); | ||||
|       } | ||||
|     } | ||||
|     &.left-next { | ||||
|       animation: 1s linear alternate infinite pulse-next-top; | ||||
|     } | ||||
|     &.right-done { | ||||
|       --div-right-color: var(--primary); | ||||
|     } | ||||
|     &.right-current { | ||||
|       --div-right-color: var(--tertiary); | ||||
|     } | ||||
|     &.right-blank, &.right-next { | ||||
|       &:nth-child(4n + 2) { | ||||
|         --div-right-color: var(--secondary); | ||||
|       } | ||||
|     } | ||||
|     &.right-next { | ||||
|       animation: 1s linear alternate infinite pulse-next-bottom; | ||||
|     } | ||||
| 
 | ||||
|     &::after, &::before { | ||||
|       content: ''; | ||||
|       width: 100%; | ||||
|       height: 100%; | ||||
|       display: block; | ||||
|       position: absolute; | ||||
|       transform: skew(160deg) translate(58%); | ||||
|       background: var(--div-right-color); | ||||
|     } | ||||
|     &::before { | ||||
|       transform: skew(160deg) translate(-58%); | ||||
|       background: var(--div-left-color); | ||||
|     } | ||||
| 
 | ||||
|     width: clamp(5px, 2.5vw, 15px); | ||||
|   } | ||||
| 
 | ||||
|   &.transitions { | ||||
|     .stage, .divider, .divider::before, .divider::after { | ||||
|       transition: color 500ms, border-color 500ms, background-color 500ms; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @keyframes pulse-next { | ||||
|   to { | ||||
|     border-color: var(--tertiary); | ||||
|     text-shadow: 0 0 0.8em var(--tertiary); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @keyframes pulse-next-top { | ||||
|   to { | ||||
|     border-top-color: var(--tertiary); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @keyframes pulse-next-bottom { | ||||
|   to { | ||||
|     border-bottom-color: var(--tertiary); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										72
									
								
								frontend/src/app/components/tracker/tracker-bar.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								frontend/src/app/components/tracker/tracker-bar.component.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | ||||
| import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; | ||||
| 
 | ||||
| export type TrackerStage = 'waiting' | 'pending' | 'soon' | 'next' | 'confirmed'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'app-tracker-bar', | ||||
|   templateUrl: './tracker-bar.component.html', | ||||
|   styleUrls: ['./tracker-bar.component.scss'], | ||||
|   changeDetection: ChangeDetectionStrategy.OnPush | ||||
| }) | ||||
| export class TrackerBarComponent implements OnInit, OnChanges { | ||||
|   @Input() stage: TrackerStage = 'waiting'; | ||||
| 
 | ||||
|   transitionsEnabled: boolean = false; | ||||
|    | ||||
|   stages = { | ||||
|     waiting: { | ||||
|       state: 'blank', | ||||
|     }, | ||||
|     pending: { | ||||
|       state: 'blank', | ||||
|     }, | ||||
|     soon: { | ||||
|       state: 'blank', | ||||
|     }, | ||||
|     next: { | ||||
|       state: 'blank', | ||||
|     }, | ||||
|     confirmed: { | ||||
|       state: 'blank', | ||||
|     }, | ||||
|   }; | ||||
|   stageOrder: TrackerStage[] = ['waiting', 'pending', 'soon', 'next', 'confirmed']; | ||||
| 
 | ||||
|   constructor ( | ||||
|     private cd: ChangeDetectorRef, | ||||
|   ) {} | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
|     this.setStage(); | ||||
|     setTimeout(() => { | ||||
|       this.transitionsEnabled = true; | ||||
|     }, 100) | ||||
|   } | ||||
| 
 | ||||
|   ngOnChanges(changes: SimpleChanges): void { | ||||
|     if (changes.stage) { | ||||
|       this.setStage(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   setStage() { | ||||
|     let matched = 0; | ||||
|     for (let stage of this.stageOrder) { | ||||
|       if (stage === this.stage) { | ||||
|         this.stages[stage].state = 'current'; | ||||
|         matched = 1; | ||||
|       } else { | ||||
|         if (matched > 1) { | ||||
|           this.stages[stage].state = 'blank'; | ||||
|         } else if (matched) { | ||||
|           this.stages[stage].state = 'next'; | ||||
|           matched++; | ||||
|         } else { | ||||
|           this.stages[stage].state = 'done'; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     this.stages = this.stages; | ||||
|     this.cd.markForCheck(); | ||||
|   } | ||||
| } | ||||
| @ -51,6 +51,7 @@ import { BlockOverviewTooltipComponent } from '../components/block-overview-tool | ||||
| import { BlockFiltersComponent } from '../components/block-filters/block-filters.component'; | ||||
| import { AddressGroupComponent } from '../components/address-group/address-group.component'; | ||||
| import { TrackerComponent } from '../components/tracker/tracker.component'; | ||||
| import { TrackerBarComponent } from '../components/tracker/tracker-bar.component'; | ||||
| import { SearchFormComponent } from '../components/search-form/search-form.component'; | ||||
| import { AddressLabelsComponent } from '../components/address-labels/address-labels.component'; | ||||
| import { FooterComponent } from '../components/footer/footer.component'; | ||||
| @ -158,6 +159,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir | ||||
|     TransactionsListComponent, | ||||
|     AddressGroupComponent, | ||||
|     TrackerComponent, | ||||
|     TrackerBarComponent, | ||||
|     SearchFormComponent, | ||||
|     AddressLabelsComponent, | ||||
|     FooterComponent, | ||||
| @ -292,6 +294,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir | ||||
|     TransactionsListComponent, | ||||
|     AddressGroupComponent, | ||||
|     TrackerComponent, | ||||
|     TrackerBarComponent, | ||||
|     SearchFormComponent, | ||||
|     AddressLabelsComponent, | ||||
|     FooterComponent, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user