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 { BlockFiltersComponent } from '../components/block-filters/block-filters.component'; | ||||||
| import { AddressGroupComponent } from '../components/address-group/address-group.component'; | import { AddressGroupComponent } from '../components/address-group/address-group.component'; | ||||||
| import { TrackerComponent } from '../components/tracker/tracker.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 { SearchFormComponent } from '../components/search-form/search-form.component'; | ||||||
| import { AddressLabelsComponent } from '../components/address-labels/address-labels.component'; | import { AddressLabelsComponent } from '../components/address-labels/address-labels.component'; | ||||||
| import { FooterComponent } from '../components/footer/footer.component'; | import { FooterComponent } from '../components/footer/footer.component'; | ||||||
| @ -158,6 +159,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir | |||||||
|     TransactionsListComponent, |     TransactionsListComponent, | ||||||
|     AddressGroupComponent, |     AddressGroupComponent, | ||||||
|     TrackerComponent, |     TrackerComponent, | ||||||
|  |     TrackerBarComponent, | ||||||
|     SearchFormComponent, |     SearchFormComponent, | ||||||
|     AddressLabelsComponent, |     AddressLabelsComponent, | ||||||
|     FooterComponent, |     FooterComponent, | ||||||
| @ -292,6 +294,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir | |||||||
|     TransactionsListComponent, |     TransactionsListComponent, | ||||||
|     AddressGroupComponent, |     AddressGroupComponent, | ||||||
|     TrackerComponent, |     TrackerComponent, | ||||||
|  |     TrackerBarComponent, | ||||||
|     SearchFormComponent, |     SearchFormComponent, | ||||||
|     AddressLabelsComponent, |     AddressLabelsComponent, | ||||||
|     FooterComponent, |     FooterComponent, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user