Merge pull request #5149 from mempool/mononaut/accurate-timestamps-hover
Accurate timestamps on hover
This commit is contained in:
		
						commit
						8382a27a7c
					
				| @ -27,6 +27,7 @@ import { ShortenStringPipe } from './shared/pipes/shorten-string-pipe/shorten-st | ||||
| import { CapAddressPipe } from './shared/pipes/cap-address-pipe/cap-address-pipe'; | ||||
| import { AppPreloadingStrategy } from './app.preloading-strategy'; | ||||
| import { ServicesApiServices } from './services/services-api.service'; | ||||
| import { DatePipe } from '@angular/common'; | ||||
| 
 | ||||
| const providers = [ | ||||
|   ElectrsApiService, | ||||
| @ -45,6 +46,7 @@ const providers = [ | ||||
|   FiatShortenerPipe, | ||||
|   FiatCurrencyPipe, | ||||
|   CapAddressPipe, | ||||
|   DatePipe, | ||||
|   AppPreloadingStrategy, | ||||
|   ServicesApiServices, | ||||
|   PreloadService, | ||||
|  | ||||
| @ -35,7 +35,7 @@ | ||||
|               {{ (acceleration.feeDelta) | number }} <span class="symbol" i18n="shared.sat|sat">sat</span> | ||||
|             </td> | ||||
|             <td class="time text-right"> | ||||
|               <app-time kind="since" [time]="acceleration.added" [fastRender]="true"></app-time> | ||||
|               <app-time kind="since" [time]="acceleration.added" [fastRender]="true" [showTooltip]="true"></app-time> | ||||
|             </td> | ||||
|           </ng-container> | ||||
|           <ng-container *ngIf="!pending"> | ||||
| @ -55,7 +55,7 @@ | ||||
|               <span *ngIf="acceleration.status.includes('failed')" class="badge badge-danger" i18n="accelerator.canceled">Failed <span *ngIf="acceleration.status === 'failed_provisional'">🔄</span></span> | ||||
|             </td> | ||||
|             <td class="date text-right" *ngIf="!this.widget"> | ||||
|               <app-time kind="since" [time]="acceleration.added" [fastRender]="true"></app-time> | ||||
|               <app-time kind="since" [time]="acceleration.added" [fastRender]="true" [showTooltip]="true"></app-time> | ||||
|             </td> | ||||
|           </ng-container> | ||||
|         </tr> | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
|       </td> | ||||
|       <td class="table-cell-satoshis"><app-amount [satoshis]="transaction.value" digitsInfo="1.2-4" [noFiat]="true"></app-amount></td> | ||||
|       <td class="table-cell-fiat" ><app-fiat [value]="transaction.value" [blockConversion]="transaction.price" digitsInfo="1.0-0"></app-fiat></td> | ||||
|       <td class="table-cell-date"><app-time kind="since" [time]="transaction.time" [fastRender]="true"></app-time></td> | ||||
|       <td class="table-cell-date"><app-time kind="since" [time]="transaction.time" [fastRender]="true" [showTooltip]="true"></app-time></td> | ||||
|     </tr> | ||||
|   </tbody> | ||||
|   <div class=""> </div> | ||||
|  | ||||
| @ -158,7 +158,7 @@ | ||||
|                   <tbody *ngIf="blocks$ | async as blocks; else blocksSkeleton"> | ||||
|                     <tr *ngFor="let block of blocks; let i = index; trackBy: trackByBlock"> | ||||
|                       <td class="table-cell-height" ><a [routerLink]="['/block' | relativeUrl, block.id]" [state]="{ data: { block: block } }">{{ block.height }}</a></td> | ||||
|                       <td class="table-cell-mined" ><app-time kind="since" [time]="block.timestamp" [fastRender]="true"></app-time></td> | ||||
|                       <td class="table-cell-mined" ><app-time kind="since" [time]="block.timestamp" [fastRender]="true" [showTooltip]="true"></app-time></td> | ||||
|                       <td class="table-cell-transaction-count">{{ block.tx_count | number }}</td> | ||||
|                       <td class="table-cell-size"> | ||||
|                         <div class="progress"> | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
|           <a [routerLink]="['/block' | relativeUrl, diffChange.height]">{{ diffChange.height }}</a> | ||||
|         </td> | ||||
|         <td class="date text-left"> | ||||
|           <app-time kind="since" [time]="diffChange.timestamp" [fastRender]="true" [precision]="1"></app-time> | ||||
|           <app-time kind="since" [time]="diffChange.timestamp" [fastRender]="true" [precision]="1" [showTooltip]="true"></app-time> | ||||
|         </td> | ||||
|         <td class="text-right">{{ diffChange.difficultyShorten }}</td> | ||||
|         <td class="text-right" [style]="diffChange.change >= 0 ? 'color: #42B747' : 'color: #B74242'"> | ||||
|  | ||||
| @ -26,7 +26,7 @@ | ||||
|               <app-amount [satoshis]="utxo.amount" [noFiat]="true" [forceBtc]="true"></app-amount> | ||||
|             </td> | ||||
|             <td class="timestamp text-left widget"> | ||||
|               <app-time kind="since" [time]="utxo.blocktime"></app-time> | ||||
|               <app-time kind="since" [time]="utxo.blocktime" [showTooltip]="true"></app-time> | ||||
|             </td> | ||||
|           </tr> | ||||
|         </ng-container> | ||||
|  | ||||
| @ -31,7 +31,7 @@ | ||||
|               </ng-container> | ||||
|             </td> | ||||
|             <td class="timestamp text-left widget"> | ||||
|               <app-time kind="since" [time]="peg.blocktime"></app-time> | ||||
|               <app-time kind="since" [time]="peg.blocktime" [showTooltip]="true"></app-time> | ||||
|             </td> | ||||
|             <td class="amount text-right widget" [ngClass]="{'credit': peg.amount > 0, 'debit': peg.amount < 0, 'glow-effect': peg.amount < 0 && peg.bitcoinaddress && !peg.bitcointxid}"> | ||||
|               <app-amount [satoshis]="peg.amount" [noFiat]="true" [forceBtc]="true" [addPlus]="true"></app-amount> | ||||
|  | ||||
| @ -197,7 +197,7 @@ | ||||
|             ‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm:ss' }} | ||||
|           </td> | ||||
|           <td class="mined"> | ||||
|             <app-time kind="since" [time]="block.timestamp" [fastRender]="true"></app-time> | ||||
|             <app-time kind="since" [time]="block.timestamp" [fastRender]="true" [showTooltip]="true"></app-time> | ||||
|           </td> | ||||
|           <td class="coinbase"> | ||||
|             <span class="badge badge-secondary scriptmessage longer"> | ||||
|  | ||||
| @ -23,7 +23,7 @@ | ||||
|             <span *ngIf="tree.mined" class="badge badge-success" i18n="transaction.rbf.mined">Mined</span> | ||||
|             <span *ngIf="tree.fullRbf" class="badge badge-info" i18n="transaction.full-rbf">Full RBF</span> | ||||
|           </span> | ||||
|           <app-time kind="since" [time]="tree.time"></app-time> | ||||
|           <app-time kind="since" [time]="tree.time" [showTooltip]="true"></app-time> | ||||
|         </p> | ||||
|         <div class="timeline-wrapper" [class.mined]="tree.mined"> | ||||
|           <app-rbf-timeline [replacements]="tree"></app-rbf-timeline> | ||||
|  | ||||
							
								
								
									
										1
									
								
								frontend/src/app/components/time/time.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								frontend/src/app/components/time/time.component.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| <span [ngbTooltip]="tooltip">{{ text }}</span> | ||||
| @ -1,15 +1,17 @@ | ||||
| import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnChanges } from '@angular/core'; | ||||
| import { StateService } from '../../services/state.service'; | ||||
| import { dates } from '../../shared/i18n/dates'; | ||||
| import { DatePipe } from '@angular/common'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'app-time', | ||||
|   template: `{{ text }}`, | ||||
|   templateUrl: './time.component.html', | ||||
|   changeDetection: ChangeDetectionStrategy.OnPush | ||||
| }) | ||||
| export class TimeComponent implements OnInit, OnChanges, OnDestroy { | ||||
|   interval: number; | ||||
|   text: string; | ||||
|   tooltip: string; | ||||
|   precisionThresholds = { | ||||
|     year: 100, | ||||
|     month: 18, | ||||
| @ -26,6 +28,7 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy { | ||||
|   @Input() kind: 'plain' | 'since' | 'until' | 'span' | 'before' | 'within' = 'plain'; | ||||
|   @Input() fastRender = false; | ||||
|   @Input() fixedRender = false; | ||||
|   @Input() showTooltip = false; | ||||
|   @Input() relative = false; | ||||
|   @Input() precision: number = 0; | ||||
|   @Input() numUnits: number = 1; | ||||
| @ -36,6 +39,7 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy { | ||||
|   constructor( | ||||
|     private ref: ChangeDetectorRef, | ||||
|     private stateService: StateService, | ||||
|     private datePipe: DatePipe, | ||||
|   ) { | ||||
|       this.intervals = { | ||||
|         year: 31536000, | ||||
| @ -78,13 +82,20 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy { | ||||
|     switch (this.kind) { | ||||
|       case 'since': | ||||
|         seconds = Math.floor((+new Date() - +new Date(this.dateString || this.time * 1000)) / 1000); | ||||
|         this.tooltip = this.datePipe.transform(new Date(this.dateString || this.time * 1000), 'yyyy-MM-dd HH:mm'); | ||||
|         break; | ||||
|       case 'until': | ||||
|       case 'within': | ||||
|         seconds = (+new Date(this.time) - +new Date()) / 1000; | ||||
|         this.tooltip = this.datePipe.transform(new Date(this.time), 'yyyy-MM-dd HH:mm'); | ||||
|         break; | ||||
|       default: | ||||
|         seconds = Math.floor(this.time); | ||||
|         this.tooltip = ''; | ||||
|     } | ||||
| 
 | ||||
|     if (!this.showTooltip || this.relative) { | ||||
|       this.tooltip = ''; | ||||
|     } | ||||
| 
 | ||||
|     if (seconds < 1 && this.kind === 'span') { | ||||
|  | ||||
| @ -59,7 +59,7 @@ | ||||
|             <div class="label" i18n="transaction.first-seen|Transaction first seen">First seen</div> | ||||
|             <div class="value"> | ||||
|               @if (transactionTime > 0) { | ||||
|                 <i><app-time kind="since" [time]="transactionTime" [fastRender]="true"></app-time></i> | ||||
|                 <i><app-time kind="since" [time]="transactionTime" [fastRender]="true" [showTooltip]="true"></app-time></i> | ||||
|               } @else { | ||||
|                 <span class="skeleton-loader" style="max-width: 50%;"></span> | ||||
|               } | ||||
| @ -86,7 +86,7 @@ | ||||
|             <div class="value"> | ||||
|               ‎{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }} | ||||
|               <div class="lg-inline"> | ||||
|                 <i class="symbol">(<app-time kind="since" [time]="tx.status.block_time" [fastRender]="true"></app-time>)</i> | ||||
|                 <i class="symbol">(<app-time kind="since" [time]="tx.status.block_time" [fastRender]="true" [showTooltip]="true"></app-time>)</i> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|  | ||||
| @ -450,7 +450,7 @@ | ||||
|     @if (transactionTime > 0) { | ||||
|       <tr> | ||||
|         <td i18n="transaction.confirmed|Transaction Confirmed state">Confirmed</td> | ||||
|         <td><app-time kind="span" [time]="tx.status.block_time - transactionTime" [fastRender]="true" [relative]="true"></app-time></td> | ||||
|         <td><app-time kind="span" [time]="tx.status.block_time" [fastRender]="true" [showTooltip]="true"></app-time></td> | ||||
|       </tr> | ||||
|     } | ||||
|   } @else { | ||||
| @ -464,7 +464,7 @@ | ||||
|   } @else if (transactionTime > 0) { | ||||
|     <tr> | ||||
|       <td i18n="transaction.first-seen|Transaction first seen">First seen</td> | ||||
|       <td><i><app-time kind="since" [time]="transactionTime" [fastRender]="true"></app-time></i></td> | ||||
|       <td><i><app-time kind="since" [time]="transactionTime" [fastRender]="true" [showTooltip]="true"></app-time></i></td> | ||||
|     </tr> | ||||
|   } @else { | ||||
|     <tr> | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|     <div> | ||||
|       <ng-template [ngIf]="tx.status.confirmed">‎{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }}</ng-template> | ||||
|       <ng-template [ngIf]="!tx.status.confirmed && tx.firstSeen"> | ||||
|         <i><app-time kind="since" [time]="tx.firstSeen" [fastRender]="true"></app-time></i> | ||||
|         <i><app-time kind="since" [time]="tx.firstSeen" [fastRender]="true" [showTooltip]="true"></app-time></i> | ||||
|       </ng-template> | ||||
|     </div> | ||||
|   </div> | ||||
|  | ||||
| @ -110,7 +110,7 @@ | ||||
|               <tbody *ngIf="blocks$ | async as blocks; else blocksSkeleton"> | ||||
|                 <tr *ngFor="let block of blocks; let i = index; trackBy: trackByBlock"> | ||||
|                   <td class="table-cell-height" ><a [routerLink]="['/block' | relativeUrl, block.id]" [state]="{ data: { block: block } }">{{ block.height }}</a></td> | ||||
|                   <td class="table-cell-mined" ><app-time kind="since" [time]="block.timestamp" [fastRender]="true"></app-time></td> | ||||
|                   <td class="table-cell-mined" ><app-time kind="since" [time]="block.timestamp" [fastRender]="true" [showTooltip]="true"></app-time></td> | ||||
|                   <td class="table-cell-transaction-count">{{ block.tx_count | number }}</td> | ||||
|                   <td class="table-cell-size"> | ||||
|                     <div class="progress"> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user