]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Feature: compact toasts (#4545)
authorshamoon <4887959+shamoon@users.noreply.github.com>
Mon, 13 Nov 2023 21:17:44 +0000 (13:17 -0800)
committerGitHub <noreply@github.com>
Mon, 13 Nov 2023 21:17:44 +0000 (21:17 +0000)
src-ui/messages.xlf
src-ui/src/app/app.component.ts
src-ui/src/app/components/admin/settings/settings.component.ts
src-ui/src/app/components/common/toasts/toasts.component.html
src-ui/src/app/components/common/toasts/toasts.component.scss
src-ui/src/app/components/common/toasts/toasts.component.spec.ts
src-ui/src/app/components/common/toasts/toasts.component.ts
src-ui/src/app/services/toast.service.ts
src-ui/src/theme.scss

index 2d83d93229c1cbce0bbc7153f2f6e764d43c11d1..06fd9a5020acbac2cef0a74055b8cc2c55baecf2 100644 (file)
           <context context-type="linenumber">13</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="9103526311244275943" datatype="html">
-        <source>Document added</source>
+      <trans-unit id="3527354815023530656" datatype="html">
+        <source>Document <x id="PH" equiv-text="status.filename"/> was added to Paperless-ngx.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
           <context context-type="linenumber">83</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">93</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="9204248378636247318" datatype="html">
-        <source>Document <x id="PH" equiv-text="status.filename"/> was added to paperless.</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">85</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">95</context>
+          <context context-type="linenumber">92</context>
         </context-group>
       </trans-unit>
       <trans-unit id="1931214133925051574" datatype="html">
         <source>Open document</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">86</context>
+          <context context-type="linenumber">85</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.html</context>
         <source>Could not add <x id="PH" equiv-text="status.filename"/>: <x id="PH_1" equiv-text="status.message"/></source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">109</context>
-        </context-group>
-      </trans-unit>
-      <trans-unit id="1710712016675379662" datatype="html">
-        <source>New document detected</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">124</context>
+          <context context-type="linenumber">107</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="587031278561344416" datatype="html">
-        <source>Document <x id="PH" equiv-text="status.filename"/> is being processed by paperless.</source>
+      <trans-unit id="1218124467712564468" datatype="html">
+        <source>Document <x id="PH" equiv-text="status.filename"/> is being processed by Paperless-ngx.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">126</context>
+          <context context-type="linenumber">122</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2501522447884928778" datatype="html">
         <source>Prev</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">131</context>
+          <context context-type="linenumber">128</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3885497195825665706" datatype="html">
         <source>Next</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">132</context>
+          <context context-type="linenumber">129</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
         <source>End</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">133</context>
+          <context context-type="linenumber">130</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3909462337752654810" datatype="html">
         <source>The dashboard can be used to show saved views, such as an &apos;Inbox&apos;. Those settings are found under Settings &gt; Saved Views once you have created some.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">139</context>
+          <context context-type="linenumber">136</context>
         </context-group>
       </trans-unit>
       <trans-unit id="9075755296812854717" datatype="html">
         <source>Drag-and-drop documents here to start uploading or place them in the consume folder. You can also drag-and-drop documents anywhere on all other pages of the web app. Once you do, Paperless-ngx will start training its machine learning algorithms.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">146</context>
+          <context context-type="linenumber">143</context>
         </context-group>
       </trans-unit>
       <trans-unit id="7495498057594070122" datatype="html">
         <source>The documents list shows all of your documents and allows for filtering as well as bulk-editing. There are three different view styles: list, small cards and large cards. A list of documents currently opened for editing is shown in the sidebar.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">151</context>
+          <context context-type="linenumber">148</context>
         </context-group>
       </trans-unit>
       <trans-unit id="1334220418719920556" datatype="html">
         <source>The filtering tools allow you to quickly find documents using various searches, dates, tags, etc.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">158</context>
+          <context context-type="linenumber">155</context>
         </context-group>
       </trans-unit>
       <trans-unit id="5427326625898532358" datatype="html">
         <source>Any combination of filters can be saved as a &apos;view&apos; which can then be displayed on the dashboard and / or sidebar.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">164</context>
+          <context context-type="linenumber">161</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2804886236408698479" datatype="html">
         <source>Tags, correspondents, document types and storage paths can all be managed using these pages. They can also be created from the document edit view.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">169</context>
+          <context context-type="linenumber">166</context>
         </context-group>
       </trans-unit>
       <trans-unit id="7851939076947092983" datatype="html">
         <source>Manage e-mail accounts and rules for automatically importing documents.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">177</context>
+          <context context-type="linenumber">174</context>
         </context-group>
       </trans-unit>
       <trans-unit id="1347174817382304718" datatype="html">
         <source>Consumption templates give you finer control over the document ingestion process.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">185</context>
+          <context context-type="linenumber">182</context>
         </context-group>
       </trans-unit>
       <trans-unit id="4680387114119209483" datatype="html">
         <source>File Tasks shows you documents that have been consumed, are waiting to be, or may have failed during the process.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">193</context>
+          <context context-type="linenumber">190</context>
         </context-group>
       </trans-unit>
       <trans-unit id="1453710303796913192" datatype="html">
         <source>Check out the settings for various tweaks to the web app and toggle settings for saved views.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">201</context>
+          <context context-type="linenumber">198</context>
         </context-group>
       </trans-unit>
       <trans-unit id="7172877665285340082" datatype="html">
         <source>Thank you! 🙏</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">209</context>
+          <context context-type="linenumber">206</context>
         </context-group>
       </trans-unit>
       <trans-unit id="7354947513482088740" datatype="html">
         <source>There are &lt;em&gt;tons&lt;/em&gt; more features and info we didn&apos;t cover here, but this should get you started. Check out the documentation or visit the project on GitHub to learn more or to report issues.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">211</context>
+          <context context-type="linenumber">208</context>
         </context-group>
       </trans-unit>
       <trans-unit id="4270528545616947218" datatype="html">
         <source>Lastly, on behalf of every contributor to this community-supported project, thank you for using Paperless-ngx!</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/app.component.ts</context>
-          <context context-type="linenumber">213</context>
+          <context context-type="linenumber">210</context>
         </context-group>
       </trans-unit>
       <trans-unit id="4804785061014590286" datatype="html">
           <context context-type="linenumber">370</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="3891152409365583719" datatype="html">
-        <source>Settings saved</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
-          <context context-type="linenumber">492</context>
-        </context-group>
-      </trans-unit>
       <trans-unit id="7217000812750597833" datatype="html">
         <source>Settings were saved successfully.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
-          <context context-type="linenumber">493</context>
+          <context context-type="linenumber">492</context>
         </context-group>
       </trans-unit>
       <trans-unit id="525012668859298131" datatype="html">
         <source>Settings were saved successfully. Reload is required to apply some changes.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
-          <context context-type="linenumber">497</context>
+          <context context-type="linenumber">496</context>
         </context-group>
       </trans-unit>
       <trans-unit id="8491974984518503778" datatype="html">
         <source>Reload now</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
-          <context context-type="linenumber">498</context>
+          <context context-type="linenumber">497</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3011185103048412841" datatype="html">
         <source>An error occurred while saving settings.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
-          <context context-type="linenumber">508</context>
+          <context context-type="linenumber">507</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/app-frame/app-frame.component.ts</context>
         <source>Use system language</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
-          <context context-type="linenumber">516</context>
+          <context context-type="linenumber">515</context>
         </context-group>
       </trans-unit>
       <trans-unit id="7729897675462249787" datatype="html">
         <source>Use date format of display language</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
-          <context context-type="linenumber">523</context>
+          <context context-type="linenumber">522</context>
         </context-group>
       </trans-unit>
       <trans-unit id="5260584511980773458" datatype="html">
         <source>Error while storing settings on server.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/admin/settings/settings.component.ts</context>
-          <context context-type="linenumber">546</context>
+          <context context-type="linenumber">545</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2991443309752293110" datatype="html">
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/common/toasts/toasts.component.html</context>
-          <context context-type="linenumber">14</context>
-        </context-group>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/services/toast.service.ts</context>
-          <context context-type="linenumber">37</context>
+          <context context-type="linenumber">18</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2159130950882492111" datatype="html">
         <source>Status</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/common/toasts/toasts.component.html</context>
-          <context context-type="linenumber">12</context>
+          <context context-type="linenumber">16</context>
         </context-group>
       </trans-unit>
       <trans-unit id="6732151329960766506" datatype="html">
         <source>Copy Raw Error</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/common/toasts/toasts.component.html</context>
-          <context context-type="linenumber">23</context>
+          <context context-type="linenumber">27</context>
         </context-group>
       </trans-unit>
       <trans-unit id="1865646076514070962" datatype="html">
           <context context-type="linenumber">542</context>
         </context-group>
       </trans-unit>
-      <trans-unit id="5037437391296624618" datatype="html">
-        <source>Information</source>
-        <context-group purpose="location">
-          <context context-type="sourcefile">src/app/services/toast.service.ts</context>
-          <context context-type="linenumber">46</context>
-        </context-group>
-      </trans-unit>
       <trans-unit id="3852289441366561594" datatype="html">
         <source>Connecting...</source>
         <context-group purpose="location">
index fb54665f095f4e2a1bec153b06d8a7a834862b52..28ce87929b46bbd20c344ddc26c86e901972b34c 100644 (file)
@@ -80,9 +80,8 @@ export class AppComponent implements OnInit, OnDestroy {
             )
           ) {
             this.toastService.show({
-              title: $localize`Document added`,
+              content: $localize`Document ${status.filename} was added to Paperless-ngx.`,
               delay: 10000,
-              content: $localize`Document ${status.filename} was added to paperless.`,
               actionName: $localize`Open document`,
               action: () => {
                 this.router.navigate(['documents', status.documentId])
@@ -90,9 +89,8 @@ export class AppComponent implements OnInit, OnDestroy {
             })
           } else {
             this.toastService.show({
-              title: $localize`Document added`,
+              content: $localize`Document ${status.filename} was added to Paperless-ngx.`,
               delay: 10000,
-              content: $localize`Document ${status.filename} was added to paperless.`,
             })
           }
         }
@@ -121,9 +119,8 @@ export class AppComponent implements OnInit, OnDestroy {
           )
         ) {
           this.toastService.show({
-            title: $localize`New document detected`,
+            content: $localize`Document ${status.filename} is being processed by Paperless-ngx.`,
             delay: 5000,
-            content: $localize`Document ${status.filename} is being processed by paperless.`,
           })
         }
       })
index 3a7f837f360e0cd529f5bcba5523803451689c2b..2d3960dc5419361119107fff6321473ea7b02c20 100644 (file)
@@ -489,7 +489,6 @@ export class SettingsComponent
           this.documentListViewService.updatePageSize()
           this.settings.updateAppearanceSettings()
           let savedToast: Toast = {
-            title: $localize`Settings saved`,
             content: $localize`Settings were saved successfully.`,
             delay: 5000,
           }
index dd75455e0add423ccae6b3aab39cb17e2efd9380..2372911aebde53c3ce5e3adf62b6f3208ca758c5 100644 (file)
@@ -1,30 +1,43 @@
 <ngb-toast
   *ngFor="let toast of toasts"
-  [header]="toast.title" [autohide]="true" [delay]="toast.delay"
+  [autohide]="true" [delay]="toast.delay"
   [class]="toast.classname"
+  [class.mb-2]="true"
+  (shown)="onShow(toast)"
   (hidden)="toastService.closeToast(toast)">
-  <p>{{toast.content}}</p>
-  <details *ngIf="toast.error">
-    <div class="p-3">
-      <dl class="row" *ngIf="isDetailedError(toast.error)">
-        <dt class="col-sm-3 fw-normal text-end">URL</dt>
-        <dd class="col-sm-9">{{ toast.error.url }}</dd>
-        <dt class="col-sm-3 fw-normal text-end" i18n>Status</dt>
-        <dd class="col-sm-9">{{ toast.error.status }} <em>{{ toast.error.statusText }}</em></dd>
-        <dt class="col-sm-3 fw-normal text-end" i18n>Error</dt>
-        <dd class="col-sm-9">{{ getErrorText(toast.error) }}</dd>
-      </dl>
-      <div class="row">
-        <div class="col offset-sm-3">
-          <button class="btn btn-sm btn-outline-dark" (click)="copyError(toast.error)">
-            <svg class="sidebaricon" fill="currentColor">
-              <use *ngIf="!copied" xlink:href="assets/bootstrap-icons.svg#clipboard" />
-              <use *ngIf="copied" xlink:href="assets/bootstrap-icons.svg#clipboard-check" />
-            </svg>&nbsp;<ng-container i18n>Copy Raw Error</ng-container>
-          </button>
+  <ngb-progressbar class="position-absolute h-100 w-100 top-90 start-0 bottom-0 end-0 pe-none" type="dark" [max]="toast.delay" [value]="toast.delayRemaining"></ngb-progressbar>
+  <span class="visually-hidden">{{ toast.delayRemaining / 1000 | number: '1.0-0' }} seconds</span>
+  <div class="d-flex align-items-top">
+    <svg class="sidebaricon-sm mt-1 me-2 flex-shrink-0" fill="currentColor">
+      <use *ngIf="!toast.error" xlink:href="assets/bootstrap-icons.svg#info-circle"/>
+      <use *ngIf="toast.error" xlink:href="assets/bootstrap-icons.svg#exclamation-triangle"/>
+    </svg>
+    <div>
+      <p class="mb-0">{{toast.content}}</p>
+      <details *ngIf="toast.error">
+        <div class="mt-2">
+          <dl class="row mb-0" *ngIf="isDetailedError(toast.error)">
+            <dt class="col-sm-3 fw-normal text-end">URL</dt>
+            <dd class="col-sm-9">{{ toast.error.url }}</dd>
+            <dt class="col-sm-3 fw-normal text-end" i18n>Status</dt>
+            <dd class="col-sm-9">{{ toast.error.status }} <em>{{ toast.error.statusText }}</em></dd>
+            <dt class="col-sm-3 fw-normal text-end" i18n>Error</dt>
+            <dd class="col-sm-9">{{ getErrorText(toast.error) }}</dd>
+          </dl>
+          <div class="row">
+            <div class="col offset-sm-3">
+              <button class="btn btn-sm btn-outline-dark" (click)="copyError(toast.error)">
+                <svg class="sidebaricon" fill="currentColor">
+                  <use *ngIf="!copied" xlink:href="assets/bootstrap-icons.svg#clipboard" />
+                  <use *ngIf="copied" xlink:href="assets/bootstrap-icons.svg#clipboard-check" />
+                </svg>&nbsp;<ng-container i18n>Copy Raw Error</ng-container>
+              </button>
+            </div>
+          </div>
         </div>
-      </div>
+      </details>
+      <p class="mb-0 mt-2" *ngIf="toast.action"><button class="btn btn-sm btn-outline-secondary" (click)="toastService.closeToast(toast); toast.action()">{{toast.actionName}}</button></p>
     </div>
-  </details>
-  <p class="mb-0" *ngIf="toast.action"><button class="btn btn-sm btn-outline-secondary" (click)="toastService.closeToast(toast); toast.action()">{{toast.actionName}}</button></p>
+    <button type="button" class="btn-close ms-auto flex-shrink-0" data-bs-dismiss="toast" aria-label="Close" (click)="toastService.closeToast(toast);"></button>
+  </div>
 </ngb-toast>
index 52f8f89579220b680223a7e2b42a53ab3f30b69c..463f964956f95d92e1fb51959dd986a1c3cffe76 100644 (file)
@@ -2,7 +2,7 @@
   position: fixed;
   top: 0;
   right: 0;
-  margin: 0.5em;
+  margin: 0.3em;
   z-index: 1200;
 }
 
   display: block; // this corrects an ng-bootstrap bug that prevented animations
 }
 
-::ng-deep .toast.error .toast-header {
-  background-color: hsla(350, 79%, 40%, 0.8); // bg-danger
-  border-color: black;
+::ng-deep .toast-body {
+  position: relative;
+}
+
+::ng-deep .toast.error {
+  border-color: hsla(350, 79%, 40%, 0.4); // bg-danger
 }
 
 ::ng-deep .toast.error .toast-body {
   background-color: hsla(350, 79%, 40%, 0.8); // bg-danger
+  border-top-left-radius: inherit;
+  border-top-right-radius: inherit;
   border-bottom-left-radius: inherit;
   border-bottom-right-radius: inherit;
 }
+
+.progress {
+  background-color: var(--pngx-primary);
+  opacity: .07;
+}
index 9181240e8c3f6072aa0e3d52612ae96abdfee956..bf42dc21106041b78eb0d03e2a4d852ca7de5433 100644 (file)
@@ -3,6 +3,7 @@ import {
   discardPeriodicTasks,
   fakeAsync,
   flush,
+  tick,
 } from '@angular/core/testing'
 import { ToastService } from 'src/app/services/toast.service'
 import { ToastsComponent } from './toasts.component'
@@ -14,18 +15,15 @@ import { Clipboard } from '@angular/cdk/clipboard'
 
 const toasts = [
   {
-    title: 'Title',
-    content: 'content',
+    content: 'foo bar',
     delay: 5000,
   },
   {
-    title: 'Error 1',
     content: 'Error 1 content',
     delay: 5000,
     error: 'Error 1 string',
   },
   {
-    title: 'Error 2',
     content: 'Error 2 content',
     delay: 5000,
     error: {
@@ -75,8 +73,7 @@ describe('ToastsComponent', () => {
 
     expect(spy).toHaveBeenCalled()
     expect(component.toasts).toContainEqual({
-      title: 'Title',
-      content: 'content',
+      content: 'foo bar',
       delay: 5000,
     })
 
@@ -89,13 +86,24 @@ describe('ToastsComponent', () => {
     component.ngOnInit()
     fixture.detectChanges()
 
-    expect(fixture.nativeElement.textContent).toContain('Title')
+    expect(fixture.nativeElement.textContent).toContain('foo bar')
 
     component.ngOnDestroy()
     flush()
     discardPeriodicTasks()
   }))
 
+  it('should countdown toast', fakeAsync(() => {
+    component.ngOnInit()
+    fixture.detectChanges()
+    component.onShow(toasts[0])
+    tick(5000)
+    expect(component.toasts[0].delayRemaining).toEqual(0)
+    component.ngOnDestroy()
+    flush()
+    discardPeriodicTasks()
+  }))
+
   it('should show an error if given with toast', fakeAsync(() => {
     component.ngOnInit()
     fixture.detectChanges()
@@ -134,6 +142,9 @@ describe('ToastsComponent', () => {
       'Error string no detail'
     )
     expect(component.getErrorText('Error string')).toEqual('')
+    expect(
+      component.getErrorText({ error: { message: 'foo error bar' } })
+    ).toContain('{"message":"foo error bar"}')
     expect(
       component.getErrorText({ error: new Array(205).join('a') })
     ).toContain('...')
index d271c7f7dac9b814de02e65edc4620b0c1f352c4..dac65c37f20666d8152057d20706310b0abfad2f 100644 (file)
@@ -1,5 +1,5 @@
 import { Component, OnDestroy, OnInit } from '@angular/core'
-import { Subscription } from 'rxjs'
+import { Subscription, interval, take } from 'rxjs'
 import { Toast, ToastService } from 'src/app/services/toast.service'
 import { Clipboard } from '@angular/cdk/clipboard'
 
@@ -20,6 +20,8 @@ export class ToastsComponent implements OnInit, OnDestroy {
 
   public copied: boolean = false
 
+  public seconds: number = 0
+
   ngOnDestroy(): void {
     this.subscription?.unsubscribe()
   }
@@ -37,6 +39,20 @@ export class ToastsComponent implements OnInit, OnDestroy {
     })
   }
 
+  onShow(toast: Toast) {
+    const refreshInterval = 150
+    const delay = toast.delay - 500 // for fade animation
+
+    interval(refreshInterval)
+      .pipe(take(delay / refreshInterval))
+      .subscribe((count) => {
+        toast.delayRemaining = Math.max(
+          0,
+          delay - refreshInterval * (count + 1)
+        )
+      })
+  }
+
   public isDetailedError(error: any): boolean {
     return (
       typeof error === 'object' &&
index b1caaf9b5b106f65ba8bb5fd14293c0eef762ad1..16c534b5c4f20e8f922a5d946b1d524e1a112bcc 100644 (file)
@@ -2,12 +2,12 @@ import { Injectable } from '@angular/core'
 import { Subject } from 'rxjs'
 
 export interface Toast {
-  title: string
-
   content: string
 
   delay: number
 
+  delayRemaining?: number
+
   action?: any
 
   actionName?: string
@@ -34,7 +34,6 @@ export class ToastService {
 
   showError(content: string, error: any = null, delay: number = 10000) {
     this.show({
-      title: $localize`Error`,
       content: content,
       delay: delay,
       classname: 'error',
@@ -43,7 +42,7 @@ export class ToastService {
   }
 
   showInfo(content: string, delay: number = 5000) {
-    this.show({ title: $localize`Information`, content: content, delay: delay })
+    this.show({ content: content, delay: delay })
   }
 
   closeToast(toast: Toast) {
index 095b83d20a89daf9cf99b906229fe5fd42a52b58..0518f9bbebb12b4b8fe4d6a74641c02bc7c26527 100644 (file)
@@ -249,12 +249,11 @@ $form-check-radio-checked-bg-image-dark: url("data:image/svg+xml,<svg xmlns='htt
     filter: invert(1) grayscale(100%) brightness(200%);
   }
 
-  .toast, .toast-header {
-    background-color: hsla(var(--pngx-primary), calc(var(--pngx-primary-lightness) - 15%), 0.8);
+  .toast {
+    background-color: hsla(var(--pngx-primary), calc(var(--pngx-primary-lightness) - 15%), 0.9);
   }
 
   .toast,
-  .toast .toast-header,
   .toast .btn,
   .toast .btn-close {
     color: var(--pngx-primary-text-contrast);