From d8b7589d3978cb6c4601ad983f08f6326e5ce4d8 Mon Sep 17 00:00:00 2001 From: Jason Wallace Date: Fri, 16 Aug 2024 13:04:13 +0200 Subject: [PATCH] Add a success dialog variant (#1841) Resolves https://github.com/tiny-pilot/tinypilot/issues/1639 Based on a [PR review discussion](https://codeapprove.com/pr/tiny-pilot/tinypilot/1833#thread-59475250-2fc2-4e74-9b4f-359067e9a3c8), this PR adds an event (i.e., `DialogVariantChangedEvent`) that allows us to change the dialog's visual variant style in order to make it more engaging for the user. For example, we can now change the dialog variant when a successful state is reached: Screen Shot 2024-08-14 at 16 44 18 Review
on CodeApprove --- app/static/css/style.css | 1 + app/static/js/events.js | 16 ++++++++++ .../custom-elements/overlay-panel.html | 31 ++++++++++++++----- .../custom-elements/shutdown-dialog.html | 2 ++ .../custom-elements/update-dialog.html | 2 ++ .../custom-elements/wifi-dialog.html | 3 ++ app/templates/styleguide.html | 30 ++++++++++++++++++ 7 files changed, 77 insertions(+), 8 deletions(-) diff --git a/app/static/css/style.css b/app/static/css/style.css index 76aac7042..219fd206d 100644 --- a/app/static/css/style.css +++ b/app/static/css/style.css @@ -38,6 +38,7 @@ --brand-green-dark: hsl(var(--brand-hue-green), 43%, 33%); --brand-green-light: hsl(var(--brand-hue-green), 34%, 70%); --brand-green-bright: hsl(var(--brand-hue-green), 70%, 45%); + --brand-green-background: hsl(var(--brand-hue-green), 54%, 95%); /* This is the green color that is used in the logo. It should only be scarcely used outside the logo, for example for brand- or marketing-related diff --git a/app/static/js/events.js b/app/static/js/events.js index 239fac148..cd97b75d7 100644 --- a/app/static/js/events.js +++ b/app/static/js/events.js @@ -49,6 +49,22 @@ export class DialogCloseStateChangedEvent extends CustomEvent { } } +export class DialogVariantChangedEvent extends CustomEvent { + /** + * Event that advises a visual variant style change of the dialog. + * @param {("default"|"danger"|"success")} variant + */ + constructor(variant) { + super("dialog-variant-changed", { + detail: { + variant, + }, + bubbles: true, + composed: true, + }); + } +} + export class VideoStreamingModeChangedEvent extends CustomEvent { /** * Event, which indicates that the video streaming mode has changed. diff --git a/app/templates/custom-elements/overlay-panel.html b/app/templates/custom-elements/overlay-panel.html index 23c85bf04..eb73ebc81 100644 --- a/app/templates/custom-elements/overlay-panel.html +++ b/app/templates/custom-elements/overlay-panel.html @@ -50,6 +50,11 @@ border-top: 0.4rem solid var(--brand-red-bright); background-color: var(--brand-red-background); } + + :host([variant="success"]) #panel { + border-top: 0.4rem solid var(--brand-green-bright); + background-color: var(--brand-green-background); + } @@ -80,6 +85,11 @@ dialog: this.shadowRoot.querySelector("#panel"), }; this.show = this.show.bind(this); + this._initialAttributes = { + variant: this.getAttribute("variant") || "default", + showCloseButton: this.hasAttribute("show-close-button") || true, + }; + this.shadowRoot.addEventListener("dialog-closed", () => this.show(false) ); @@ -87,18 +97,15 @@ // This event is further handled in `app.js`. this.show(false) ); - - this.setAttribute("show-close-button", ""); this.shadowRoot.addEventListener( "dialog-close-state-changed", - (e) => { - if (e.detail.canBeClosed) { - this.setAttribute("show-close-button", ""); - } else { - this.removeAttribute("show-close-button"); - } + (evt) => { + this.toggleAttribute("show-close-button", evt.detail.canBeClosed); } ); + this.shadowRoot.addEventListener("dialog-variant-changed", (evt) => { + this.setAttribute("variant", evt.detail.variant); + }); this.shadowRoot .querySelector("#close-button") .addEventListener("click", () => this.show(false)); @@ -110,6 +117,14 @@ } show(isShown = true) { + // Restore element's initial attributes that might have been changed + // programmatically. + this.setAttribute("variant", this._initialAttributes.variant); + this.toggleAttribute( + "show-close-button", + this._initialAttributes.showCloseButton + ); + if (isShown) { this._elements.dialog.showModal(); this._injectEvent( diff --git a/app/templates/custom-elements/shutdown-dialog.html b/app/templates/custom-elements/shutdown-dialog.html index 50f0c7eed..dfbc5f713 100644 --- a/app/templates/custom-elements/shutdown-dialog.html +++ b/app/templates/custom-elements/shutdown-dialog.html @@ -61,6 +61,7 @@

Shutdown Complete

DialogClosedEvent, DialogFailedEvent, DialogCloseStateChangedEvent, + DialogVariantChangedEvent, } from "/js/events.js"; import { shutdown } from "/js/controllers.js"; @@ -134,6 +135,7 @@

Shutdown Complete

// that it's done after 30 seconds. setTimeout(() => { this._state = this._states.SHUTDOWN_COMPLETE; + this.dispatchEvent(new DialogVariantChangedEvent("success")); }, 30 * 1000); } }) diff --git a/app/templates/custom-elements/update-dialog.html b/app/templates/custom-elements/update-dialog.html index b8de6c31c..6f9a9a2e4 100644 --- a/app/templates/custom-elements/update-dialog.html +++ b/app/templates/custom-elements/update-dialog.html @@ -117,6 +117,7 @@

Update Complete

DialogClosedEvent, DialogFailedEvent, DialogCloseStateChangedEvent, + DialogVariantChangedEvent, } from "/js/events.js"; import { UpdateLogsStreamer } from "/js/updatelogs.js"; import { @@ -289,6 +290,7 @@

Update Complete

this._state = this._states.UPDATE_FINISHED; this._elements.updateLogs.textContent += "Update is now complete.\n"; + this.dispatchEvent(new DialogVariantChangedEvent("success")); }) .catch((error) => { this.dispatchEvent( diff --git a/app/templates/custom-elements/wifi-dialog.html b/app/templates/custom-elements/wifi-dialog.html index d4c77e725..951141180 100644 --- a/app/templates/custom-elements/wifi-dialog.html +++ b/app/templates/custom-elements/wifi-dialog.html @@ -153,6 +153,7 @@

Wi-Fi Credentials Removed

DialogClosedEvent, DialogFailedEvent, DialogCloseStateChangedEvent, + DialogVariantChangedEvent, } from "/js/events.js"; import { getNetworkStatus, @@ -334,6 +335,7 @@

Wi-Fi Credentials Removed

return; } this._state = this._states.SUCCESS_ENABLED; + this.dispatchEvent(new DialogVariantChangedEvent("success")); } async _disable() { @@ -350,6 +352,7 @@

Wi-Fi Credentials Removed

return; } this._state = this._states.SUCCESS_DISABLED; + this.dispatchEvent(new DialogVariantChangedEvent("success")); } } ); diff --git a/app/templates/styleguide.html b/app/templates/styleguide.html index e390cd255..32120f1e1 100644 --- a/app/templates/styleguide.html +++ b/app/templates/styleguide.html @@ -143,6 +143,10 @@

Colors

class="colorcard" style="background-color: var(--brand-green-light)" > +

Secondary State document.getElementById("error-overlay").show(); }); + + +

Example Success Message

+

+ This overlay style is used for when the user reaches a successful + state. +

+ +
+ +

Loading States

When the overlay is in a loading state, we generally do not want the