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