From 2a36a127328667a00f0b324fdc4e2992a57422f2 Mon Sep 17 00:00:00 2001 From: "Marc J. Schmidt" Date: Mon, 1 May 2023 19:50:26 +0200 Subject: [PATCH] feature(desktop-ui): add ProgressTracker UI component + new dui-section-header Also add new `.text-tabular` css class to display tabular numeric data nicely --- .../app/reactivate-change-detection.ts | 2 +- .../src/components/indicator/index.ts | 4 +- .../indicator/indicator.component.ts | 68 ++++++++++++++++++- .../desktop-ui/src/components/layout/index.ts | 3 + .../layout/section-header.component.scss | 21 ++++++ .../layout/section-header.component.ts | 23 +++++++ packages/desktop-ui/src/scss/dui.scss | 3 + 7 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 packages/desktop-ui/src/components/layout/section-header.component.scss create mode 100644 packages/desktop-ui/src/components/layout/section-header.component.ts diff --git a/packages/desktop-ui/src/components/app/reactivate-change-detection.ts b/packages/desktop-ui/src/components/app/reactivate-change-detection.ts index 5061d9170..944cfe83e 100644 --- a/packages/desktop-ui/src/components/app/reactivate-change-detection.ts +++ b/packages/desktop-ui/src/components/app/reactivate-change-detection.ts @@ -226,7 +226,7 @@ export function reactiveComponent() { * * Optionally @observe({unsubscribe: true}) unsubscribes the whole value as well (calling unsubscribe() on current value) on NgOnDestroy or when net property value is set. */ -export function observe(options: { unsubscribe?: true } = {}) { +export function observe(options: { unsubscribe?: true } = {}) { return function (target: T, propertyKey: string | symbol) { function unsub(value: any) { diff --git a/packages/desktop-ui/src/components/indicator/index.ts b/packages/desktop-ui/src/components/indicator/index.ts index 1c8f446e1..63a58b090 100644 --- a/packages/desktop-ui/src/components/indicator/index.ts +++ b/packages/desktop-ui/src/components/indicator/index.ts @@ -10,16 +10,18 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { IndicatorComponent } from './indicator.component'; +import { IndicatorComponent, ProgressIndicatorComponent } from './indicator.component'; export * from './indicator.component'; @NgModule({ declarations: [ IndicatorComponent, + ProgressIndicatorComponent, ], exports: [ IndicatorComponent, + ProgressIndicatorComponent, ], imports: [ CommonModule, diff --git a/packages/desktop-ui/src/components/indicator/indicator.component.ts b/packages/desktop-ui/src/components/indicator/indicator.component.ts index b6212bf50..271b0a7bc 100644 --- a/packages/desktop-ui/src/components/indicator/indicator.component.ts +++ b/packages/desktop-ui/src/components/indicator/indicator.component.ts @@ -8,7 +8,9 @@ * You should have received a copy of the MIT License along with this program. */ -import { Component, Input } from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnChanges, OnDestroy } from '@angular/core'; +import { ProgressTracker } from '@deepkit/core-rxjs'; +import { Subscription } from 'rxjs'; @Component({ selector: 'dui-indicator', @@ -20,3 +22,67 @@ import { Component, Input } from '@angular/core'; export class IndicatorComponent { @Input() step = 0; } + + +@Component({ + selector: 'dui-progress-indicator', + styles: [` + .indicator { + display: inline-flex; + align-items: center; + opacity: 1; + transition: opacity .3s ease-in-out; + } + + .indicator.vertical { + flex-direction: column; + align-items: flex-start; + } + + .label { + padding-left: 4px; + } + + .percentage { + display: inline-block; + width: 55px; + text-align: right; + } + + .hide { + opacity: 0; + } + `], + template: ` +
+ +
+ {{progressTracker.progress*100|number:'0.2-2'}}% - {{group.message}} +
+
+ ` +}) +export class ProgressIndicatorComponent implements OnChanges, OnDestroy { + @Input() progressTracker?: ProgressTracker; + @Input() display: 'horizontal' | 'vertical' = 'horizontal'; + + step: number = 0; + sub?: Subscription; + + constructor(private cd: ChangeDetectorRef) { + } + + ngOnChanges(): void { + if (this.sub) this.sub.unsubscribe(); + if (this.progressTracker) { + this.sub = this.progressTracker.subscribe(v => { + this.step = this.progressTracker!.progress; + this.cd.detectChanges(); + }); + } + } + + ngOnDestroy(): void { + if (this.sub) this.sub.unsubscribe(); + } +} diff --git a/packages/desktop-ui/src/components/layout/index.ts b/packages/desktop-ui/src/components/layout/index.ts index 5f7b50dcf..354e443de 100644 --- a/packages/desktop-ui/src/components/layout/index.ts +++ b/packages/desktop-ui/src/components/layout/index.ts @@ -10,16 +10,19 @@ import { NgModule } from '@angular/core'; import { LabelComponent, LabelGridComponent } from './label.component'; +import { SectionHeaderComponent } from './section-header.component'; @NgModule({ imports: [], exports: [ LabelComponent, LabelGridComponent, + SectionHeaderComponent, ], declarations: [ LabelComponent, LabelGridComponent, + SectionHeaderComponent, ], providers: [], }) diff --git a/packages/desktop-ui/src/components/layout/section-header.component.scss b/packages/desktop-ui/src/components/layout/section-header.component.scss new file mode 100644 index 000000000..ee6e375ee --- /dev/null +++ b/packages/desktop-ui/src/components/layout/section-header.component.scss @@ -0,0 +1,21 @@ +:host { + display: block; +} + +.title { + white-space: nowrap; + font-size: 12px; + padding: 4px 2px; + color: var(--color-black1); +} + +.line { + border-top: 1px solid var(--line-color-light); + height: 10px; +} + +:host.center { + .header { + text-align: center; + } +} diff --git a/packages/desktop-ui/src/components/layout/section-header.component.ts b/packages/desktop-ui/src/components/layout/section-header.component.ts new file mode 100644 index 000000000..10fef8f4f --- /dev/null +++ b/packages/desktop-ui/src/components/layout/section-header.component.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) Marc J. Schmidt + * This file is part of Deepkit and licensed under GNU GPL v3. See the LICENSE file for more information. + */ + +import {Component, Input} from "@angular/core"; + +@Component({ + selector: 'dui-section-header', + template: ` +
+ +
+
+ `, + host: { + '[class.center]': 'center !== false' + }, + styleUrls: ['./section-header.component.scss'] +}) +export class SectionHeaderComponent { + @Input() center: boolean | '' = false; +} diff --git a/packages/desktop-ui/src/scss/dui.scss b/packages/desktop-ui/src/scss/dui.scss index e78f2c5b5..294cde368 100644 --- a/packages/desktop-ui/src/scss/dui.scss +++ b/packages/desktop-ui/src/scss/dui.scss @@ -120,6 +120,9 @@ color: var(--text-light); } + .text-tabular { + font-variant-numeric: tabular-nums !important; + } input, textarea, select, button { font-size: 13px;