mirror of
https://github.com/penpot/penpot.git
synced 2025-05-13 09:36:40 +02:00
♻️ Update notification component
This commit is contained in:
parent
de0cd5aa04
commit
1af2ec0b79
16 changed files with 440 additions and 274 deletions
|
@ -24,7 +24,6 @@
|
||||||
--color-accent-quaternary: var(--la-quaternary);
|
--color-accent-quaternary: var(--la-quaternary);
|
||||||
--color-component-highlight: var(--la-secondary);
|
--color-component-highlight: var(--la-secondary);
|
||||||
|
|
||||||
|
|
||||||
--color-success-background: var(--status-color-success-200);
|
--color-success-background: var(--status-color-success-200);
|
||||||
--color-success-foreground: var(--status-color-success-500);
|
--color-success-foreground: var(--status-color-success-500);
|
||||||
|
|
||||||
|
|
|
@ -1131,12 +1131,12 @@
|
||||||
:controls :inline-actions
|
:controls :inline-actions
|
||||||
:links [{:label (tr "workspace.updates.more-info")
|
:links [{:label (tr "workspace.updates.more-info")
|
||||||
:callback do-more-info}]
|
:callback do-more-info}]
|
||||||
:actions [{:label (tr "workspace.updates.update")
|
:actions [{:label (tr "workspace.updates.dismiss")
|
||||||
:type :primary
|
|
||||||
:callback do-update}
|
|
||||||
{:label (tr "workspace.updates.dismiss")
|
|
||||||
:type :secondary
|
:type :secondary
|
||||||
:callback do-dismiss}]
|
:callback do-dismiss}
|
||||||
|
{:label (tr "workspace.updates.update")
|
||||||
|
:type :primary
|
||||||
|
:callback do-update}]
|
||||||
:tag :sync-dialog)))))))
|
:tag :sync-dialog)))))))
|
||||||
|
|
||||||
(defn component-changed
|
(defn component-changed
|
||||||
|
|
|
@ -173,6 +173,6 @@
|
||||||
(if edata
|
(if edata
|
||||||
[:& static/exception-page {:data edata}]
|
[:& static/exception-page {:data edata}]
|
||||||
[:*
|
[:*
|
||||||
[:& msgs/notifications]
|
[:& msgs/notifications-hub]
|
||||||
(when route
|
(when route
|
||||||
[:& main-page {:route route :profile profile}])])]]))
|
[:& main-page {:route route :profile profile}])])]]))
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
[app.main.ui.components.forms :as fm]
|
[app.main.ui.components.forms :as fm]
|
||||||
[app.main.ui.components.link :as lk]
|
[app.main.ui.components.link :as lk]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.messages :as msgs]
|
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :refer [tr]]
|
[app.util.i18n :refer [tr]]
|
||||||
[app.util.keyboard :as k]
|
[app.util.keyboard :as k]
|
||||||
|
@ -158,10 +158,9 @@
|
||||||
[:*
|
[:*
|
||||||
(when-let [message @error]
|
(when-let [message @error]
|
||||||
[:div {:class (stl/css :error-wrapper)}
|
[:div {:class (stl/css :error-wrapper)}
|
||||||
[:& msgs/inline-notification
|
[:& context-notification
|
||||||
{:type :warning
|
{:type :warning
|
||||||
:content message
|
:content message
|
||||||
:on-close #(reset! error nil)
|
|
||||||
:data-test "login-banner"
|
:data-test "login-banner"
|
||||||
:role "alert"}]])
|
:role "alert"}]])
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
[app.main.ui.components.forms :as fm]
|
[app.main.ui.components.forms :as fm]
|
||||||
[app.main.ui.components.link :as lk]
|
[app.main.ui.components.link :as lk]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.messages :as msgs]
|
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||||
[app.util.i18n :refer [tr tr-html]]
|
[app.util.i18n :refer [tr tr-html]]
|
||||||
[app.util.router :as rt]
|
[app.util.router :as rt]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
(mf/defc demo-warning
|
(mf/defc demo-warning
|
||||||
[_]
|
[_]
|
||||||
[:div {:class (stl/css :banner)}
|
[:div {:class (stl/css :banner)}
|
||||||
[:& msgs/inline-notification
|
[:& context-notification
|
||||||
{:type :warning
|
{:type :warning
|
||||||
:content (tr "auth.demo-warning")}]])
|
:content (tr "auth.demo-warning")}]])
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
|
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||||
[app.main.worker :as uw]
|
[app.main.worker :as uw]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
|
@ -385,14 +386,12 @@
|
||||||
|
|
||||||
(when (and (= :importing (:status @state)) (not pending-import?))
|
(when (and (= :importing (:status @state)) (not pending-import?))
|
||||||
(if (> warning-files 0)
|
(if (> warning-files 0)
|
||||||
[:div {:class (stl/css-case :feedback-banner true
|
[:& context-notification
|
||||||
:warning true)}
|
{:type :warning
|
||||||
[:div {:class (stl/css :icon)} i/msg-warning-refactor]
|
:content (tr "dashboard.import.import-warning" warning-files success-files)}]
|
||||||
[:div {:class (stl/css :message)} (tr "dashboard.import.import-warning" warning-files success-files)]]
|
[:& context-notification
|
||||||
|
{:type :success
|
||||||
[:div {:class (stl/css :feedback-banner)}
|
:content (tr "dashboard.import.import-message" (i18n/c (if (some? template) 1 success-files)))}]))
|
||||||
[:div {:class (stl/css :icon)} i/msg-success-refactor]
|
|
||||||
[:div {:class (stl/css :message)} (tr "dashboard.import.import-message" (i18n/c (if (some? template) 1 success-files)))]]))
|
|
||||||
|
|
||||||
(for [file files]
|
(for [file files]
|
||||||
(let [editing? (and (some? (:file-id file))
|
(let [editing? (and (some? (:file-id file))
|
||||||
|
|
33
frontend/src/app/main/ui/dashboard/import.scss
vendored
33
frontend/src/app/main/ui/dashboard/import.scss
vendored
|
@ -29,39 +29,12 @@
|
||||||
|
|
||||||
.modal-content {
|
.modal-content {
|
||||||
@include bodyMedTipography;
|
@include bodyMedTipography;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: $s-16;
|
||||||
margin-bottom: $s-24;
|
margin-bottom: $s-24;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feedback-banner {
|
|
||||||
@include flexRow;
|
|
||||||
height: $s-32;
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: $s-24;
|
|
||||||
border-radius: $br-8;
|
|
||||||
background-color: var(--alert-background-color-success);
|
|
||||||
color: var(--alert-text-foreground-color-success);
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
@include flexCenter;
|
|
||||||
height: $s-24;
|
|
||||||
width: $s-24;
|
|
||||||
svg {
|
|
||||||
@extend .button-icon;
|
|
||||||
stroke: var(--alert-icon-foreground-color-success);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.message {
|
|
||||||
@include bodyMedTipography;
|
|
||||||
}
|
|
||||||
&.warning {
|
|
||||||
background-color: var(--alert-background-color-warning);
|
|
||||||
color: var(--alert-text-foreground-color-warning);
|
|
||||||
.icon svg {
|
|
||||||
stroke: var(--alert-icon-foreground-color-warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-buttons {
|
.action-buttons {
|
||||||
@extend .modal-action-btns;
|
@extend .modal-action-btns;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,128 +5,44 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.messages
|
(ns app.main.ui.messages
|
||||||
(:require-macros [app.main.style :as stl])
|
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
|
||||||
[app.common.data.macros :as dm]
|
|
||||||
[app.common.uuid :as uuid]
|
|
||||||
[app.main.data.messages :as dmsg]
|
[app.main.data.messages :as dmsg]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.link-button :as lb]
|
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.notifications.inline-notification :refer [inline-notification]]
|
||||||
|
[app.main.ui.notifications.toast-notification :refer [toast-notification]]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc banner
|
(mf/defc notifications-hub
|
||||||
[{:keys [type position status controls content links actions on-close data-test role] :as props}]
|
|
||||||
[:div {:class (stl/css-case :banner true
|
|
||||||
:warning (= type :warning)
|
|
||||||
:error (= type :error)
|
|
||||||
:success (= type :success)
|
|
||||||
:info (= type :info)
|
|
||||||
:fixed (= position :fixed)
|
|
||||||
:floating (= position :floating)
|
|
||||||
:inline (= position :inline)
|
|
||||||
:hide (= status :hide))}
|
|
||||||
[:div {:class (stl/css :wrapper)}
|
|
||||||
[:div {:class (stl/css :icon)}
|
|
||||||
(case type
|
|
||||||
:warning i/msg-neutral-refactor
|
|
||||||
:error i/delete-text-refactor
|
|
||||||
:success i/status-tick-refactor
|
|
||||||
:info i/help-refactor
|
|
||||||
i/delete-text-refactor)]
|
|
||||||
|
|
||||||
[:div {:class (stl/css-case :content true
|
|
||||||
:inline-actions (= controls :inline-actions)
|
|
||||||
:bottom-actions (= controls :bottom-actions))
|
|
||||||
:data-test data-test
|
|
||||||
:role role}
|
|
||||||
[:span {:class (stl/css :text)}
|
|
||||||
content
|
|
||||||
(for [[index link] (d/enumerate links)]
|
|
||||||
[:* {:key (dm/str "link-" index)}
|
|
||||||
" " [:& lb/link-button {:class (stl/css :link)
|
|
||||||
:on-click (:callback link)
|
|
||||||
:value (:label link)}]])]
|
|
||||||
|
|
||||||
(when (or (= controls :bottom-actions) (= controls :inline-actions))
|
|
||||||
|
|
||||||
[:div {:class (stl/css :actions)}
|
|
||||||
(for [action actions]
|
|
||||||
[:button {:key (uuid/next)
|
|
||||||
:class (stl/css-case :action-btn true
|
|
||||||
:primary (= :primary (:type action))
|
|
||||||
:secondary (= :secondary (:type action))
|
|
||||||
:danger (= :danger (:type action)))
|
|
||||||
:on-click (:callback action)}
|
|
||||||
(:label action)])])]
|
|
||||||
|
|
||||||
(when (= controls :close)
|
|
||||||
[:button {:class (stl/css :btn-close)
|
|
||||||
:on-click on-close} i/close-refactor])]])
|
|
||||||
|
|
||||||
(mf/defc notifications
|
|
||||||
[]
|
[]
|
||||||
(let [message (mf/deref refs/message)
|
(let [message (mf/deref refs/message)
|
||||||
on-close #(st/emit! dmsg/hide)
|
on-close #(st/emit! dmsg/hide)
|
||||||
_ (prn "message" message)]
|
|
||||||
|
toast-message {:type (or (:type message) :info)
|
||||||
|
:links (:links message)
|
||||||
|
:on-close on-close
|
||||||
|
:content (:content message)}
|
||||||
|
|
||||||
|
inline-message {:actions (:actions message)
|
||||||
|
:links (:links message)
|
||||||
|
:content (:content message)}
|
||||||
|
|
||||||
|
context-message {:actions (:actions message)
|
||||||
|
:links (:links message)
|
||||||
|
:content (:content message)}
|
||||||
|
|
||||||
|
;; TODO review this options
|
||||||
|
is-toast-msg (some? (:timeout message))
|
||||||
|
actions? (some? (:actions message))
|
||||||
|
inline? (and (some? (:position message)) (= :floating (:position message)))
|
||||||
|
close? (and (some? (:controls message)) (= :close (:controls message)))]
|
||||||
|
|
||||||
(when message
|
(when message
|
||||||
[:& banner (assoc message
|
(cond
|
||||||
:position (or (:position message) :fixed)
|
(and close? is-toast-msg)
|
||||||
:controls (if (some? (:controls message))
|
[:& toast-notification toast-message]
|
||||||
(:controls message)
|
(and actions? inline?)
|
||||||
:close)
|
[:& inline-notification inline-message]
|
||||||
:on-close on-close)])))
|
:else
|
||||||
|
[:& context-notification context-message]))))
|
||||||
(mf/defc inline-notification
|
|
||||||
{::mf/wrap [mf/memo]}
|
|
||||||
[{:keys [type content on-close actions data-test role] :as props}]
|
|
||||||
[:& banner {:type type
|
|
||||||
:position :inline
|
|
||||||
:status :visible
|
|
||||||
:controls (if (some? on-close)
|
|
||||||
:close
|
|
||||||
(if (some? actions)
|
|
||||||
:bottom-actions
|
|
||||||
:none))
|
|
||||||
:content content
|
|
||||||
:on-close on-close
|
|
||||||
:actions actions
|
|
||||||
:data-test data-test
|
|
||||||
:role role}])
|
|
||||||
|
|
||||||
|
|
||||||
(mf/defc context-notification
|
|
||||||
{::mf/wrap [mf/memo]}
|
|
||||||
[{:keys [type content on-close actions data-test role] :as props}]
|
|
||||||
[:& banner {:type type
|
|
||||||
:position :inline
|
|
||||||
:status :visible
|
|
||||||
:controls (if (some? on-close)
|
|
||||||
:close
|
|
||||||
(if (some? actions)
|
|
||||||
:bottom-actions
|
|
||||||
:none))
|
|
||||||
:content content
|
|
||||||
:on-close on-close
|
|
||||||
:actions actions
|
|
||||||
:data-test data-test
|
|
||||||
:role role}])
|
|
||||||
|
|
||||||
(mf/defc toast-notification
|
|
||||||
{::mf/wrap [mf/memo]}
|
|
||||||
[{:keys [type content on-close actions data-test role] :as props}]
|
|
||||||
[:& banner {:type type
|
|
||||||
:position :floating
|
|
||||||
:status :visible
|
|
||||||
:controls (if (some? on-close)
|
|
||||||
:close
|
|
||||||
(if (some? actions)
|
|
||||||
:bottom-actions
|
|
||||||
:none))
|
|
||||||
:content content
|
|
||||||
:on-close on-close
|
|
||||||
:actions actions
|
|
||||||
:data-test data-test
|
|
||||||
:role role}])
|
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.main.ui.notifications.context-notification
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.main.ui.components.link-button :as lb]
|
||||||
|
[app.main.ui.icons :as i]
|
||||||
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(def ^:private neutral-icon
|
||||||
|
(i/icon-xref :msg-neutral-refactor (stl/css :icon)))
|
||||||
|
|
||||||
|
(def ^:private error-icon
|
||||||
|
(i/icon-xref :delete-text-refactor (stl/css :icon)))
|
||||||
|
|
||||||
|
(def ^:private success-icon
|
||||||
|
(i/icon-xref :status-tick-refactor (stl/css :icon)))
|
||||||
|
|
||||||
|
(def ^:private info-icon
|
||||||
|
(i/icon-xref :help-refactor (stl/css :icon)))
|
||||||
|
|
||||||
|
(defn get-icon-by-type
|
||||||
|
[type]
|
||||||
|
(case type
|
||||||
|
:warning neutral-icon
|
||||||
|
:error error-icon
|
||||||
|
:success success-icon
|
||||||
|
:info info-icon
|
||||||
|
neutral-icon))
|
||||||
|
|
||||||
|
(mf/defc context-notification
|
||||||
|
"They are persistent, informative and non-actionable.
|
||||||
|
They are contextual messages in specific areas off the app"
|
||||||
|
|
||||||
|
{::mf/props :obj}
|
||||||
|
[{:keys [type content links] :as props}]
|
||||||
|
|
||||||
|
[:aside {:class (stl/css-case :context-notification true
|
||||||
|
:warning (= type :warning)
|
||||||
|
:error (= type :error)
|
||||||
|
:success (= type :success)
|
||||||
|
:info (= type :info))}
|
||||||
|
|
||||||
|
(get-icon-by-type type)
|
||||||
|
|
||||||
|
[:div {:class (stl/css :context-text)}
|
||||||
|
content]
|
||||||
|
|
||||||
|
[:nav {:class (stl/css :link-nav)}
|
||||||
|
(for [[index link] (d/enumerate links)]
|
||||||
|
;; TODO Review this component
|
||||||
|
[:& lb/link-button {:class (stl/css :link)
|
||||||
|
:on-click (:callback link)
|
||||||
|
:value (:label link)
|
||||||
|
:key (dm/str "link-" index)}])]])
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
@import "refactor/common-refactor.scss";
|
||||||
|
|
||||||
|
.context-notification {
|
||||||
|
--bg-color: var(--alert-background-color-default);
|
||||||
|
--fg-color: var(--alert-text-foreground-color-default);
|
||||||
|
--icon-color: var(--alert-icon-foreground-color-default);
|
||||||
|
--border-color: var(--alert-border-color-default);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: $s-16 auto 1fr;
|
||||||
|
gap: $s-8;
|
||||||
|
min-height: $s-32;
|
||||||
|
width: 100%;
|
||||||
|
padding: $s-8 $s-8 $s-8 $s-16;
|
||||||
|
border: $s-1 solid var(--border-color);
|
||||||
|
border-radius: $br-12;
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
--bg-color: var(--alert-background-color-warning);
|
||||||
|
--fg-color: var(--alert-text-foreground-color-warning);
|
||||||
|
--icon-color: var(--alert-icon-foreground-color-warning);
|
||||||
|
--border-color: var(--alert-border-color-warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
.success {
|
||||||
|
--bg-color: var(--alert-background-color-success);
|
||||||
|
--fg-color: var(--alert-text-foreground-color-success);
|
||||||
|
--icon-color: var(--alert-icon-foreground-color-success);
|
||||||
|
--border-color: var(--alert-border-color-success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
--bg-color: var(--alert-background-color-info);
|
||||||
|
--fg-color: var(--alert-text-foreground-color-info);
|
||||||
|
--icon-color: var(--alert-icon-foreground-color-info);
|
||||||
|
--border-color: var(--alert-border-color-info);
|
||||||
|
}
|
||||||
|
|
||||||
|
.default {
|
||||||
|
--bg-color: var(--alert-background-color-default);
|
||||||
|
--fg-color: var(--alert-text-foreground-color-default);
|
||||||
|
--icon-color: var(--alert-icon-foreground-color-default);
|
||||||
|
--border-color: var(--alert-border-color-default);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
--bg-color: var(--alert-background-color-error);
|
||||||
|
--fg-color: var(--alert-text-foreground-color-error);
|
||||||
|
--icon-color: var(--alert-icon-foreground-color-error);
|
||||||
|
--border-color: var(--alert-border-color-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
@extend .button-icon;
|
||||||
|
height: 100%;
|
||||||
|
stroke: var(--icon-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-nav {
|
||||||
|
align-self: center;
|
||||||
|
height: $s-24;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-text {
|
||||||
|
@include bodyMedTipography;
|
||||||
|
align-self: center;
|
||||||
|
color: var(--fg-color);
|
||||||
|
margin: auto 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
@include bodyMedTipography;
|
||||||
|
align-self: center;
|
||||||
|
height: $s-16;
|
||||||
|
margin: 0;
|
||||||
|
color: var(--modal-link-foreground-color);
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.main.ui.notifications.inline-notification
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.ui.components.link-button :as lb]
|
||||||
|
[app.main.ui.icons :as i]
|
||||||
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(def ^:private neutral-icon
|
||||||
|
(i/icon-xref :msg-neutral-refactor (stl/css :icon)))
|
||||||
|
|
||||||
|
|
||||||
|
(mf/defc inline-notification
|
||||||
|
"They are persistent messages and report a special situation
|
||||||
|
of the application and require user interaction to disappear."
|
||||||
|
|
||||||
|
{::mf/props :obj}
|
||||||
|
[{:keys [content actions links] :as props}]
|
||||||
|
[:aside {:class (stl/css :inline-notification)}
|
||||||
|
neutral-icon
|
||||||
|
|
||||||
|
[:div {:class (stl/css :inline-text)}
|
||||||
|
content]
|
||||||
|
|
||||||
|
(when (some? links)
|
||||||
|
[:nav {:class (stl/css :link-nav)}
|
||||||
|
(for [[index link] (d/enumerate links)]
|
||||||
|
[:& lb/link-button {:key (dm/str "link-" index)
|
||||||
|
:class (stl/css :link)
|
||||||
|
:on-click (:callback link)
|
||||||
|
:value (:label link)}])])
|
||||||
|
|
||||||
|
[:div {:class (stl/css :actions)}
|
||||||
|
(for [action actions]
|
||||||
|
[:button {:key (uuid/next)
|
||||||
|
:class (stl/css-case :action-btn true
|
||||||
|
:primary (= :primary (:type action))
|
||||||
|
:secondary (= :secondary (:type action))
|
||||||
|
:danger (= :danger (:type action)))
|
||||||
|
:on-click (:callback action)}
|
||||||
|
(:label action)])]])
|
|
@ -0,0 +1,79 @@
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
@import "refactor/common-refactor.scss";
|
||||||
|
|
||||||
|
.inline-notification {
|
||||||
|
--bg-color: var(--alert-background-color-default);
|
||||||
|
--fg-color: var(--alert-text-foreground-color-default);
|
||||||
|
--icon-color: var(--alert-icon-foreground-color-default);
|
||||||
|
--border-color: var(--alert-border-color-default);
|
||||||
|
@include alertShadow;
|
||||||
|
position: absolute;
|
||||||
|
top: $s-72;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: $s-16 auto 1fr auto;
|
||||||
|
gap: $s-8;
|
||||||
|
min-height: $s-48;
|
||||||
|
min-width: $s-640;
|
||||||
|
max-width: $s-712;
|
||||||
|
padding: $s-8 $s-8 $s-8 $s-16;
|
||||||
|
margin-inline: auto;
|
||||||
|
border: $s-1 solid var(--border-color);
|
||||||
|
border-radius: $br-12;
|
||||||
|
z-index: $z-index-modal;
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--fg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
@extend .button-icon;
|
||||||
|
height: 100%;
|
||||||
|
stroke: var(--icon-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline-text {
|
||||||
|
@include bodyMedTipography;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
@include bodyMedTipography;
|
||||||
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
color: var(--modal-link-foreground-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: none;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
gap: $s-8;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
@extend .button-tertiary;
|
||||||
|
@include uppercaseTitleTipography;
|
||||||
|
min-height: $s-32;
|
||||||
|
min-width: $s-32;
|
||||||
|
padding: $s-8 $s-24;
|
||||||
|
border: $s-1 solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn.primary {
|
||||||
|
@extend .button-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn.secondary {
|
||||||
|
@extend .button-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn.danger {
|
||||||
|
@extend .modal-danger-btn;
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.main.ui.notifications.toast-notification
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.main.ui.components.link-button :as lb]
|
||||||
|
[app.main.ui.icons :as i]
|
||||||
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(def ^:private neutral-icon
|
||||||
|
(i/icon-xref :msg-neutral-refactor (stl/css :icon)))
|
||||||
|
|
||||||
|
(def ^:private error-icon
|
||||||
|
(i/icon-xref :delete-text-refactor (stl/css :icon)))
|
||||||
|
|
||||||
|
(def ^:private success-icon
|
||||||
|
(i/icon-xref :status-tick-refactor (stl/css :icon)))
|
||||||
|
|
||||||
|
(def ^:private info-icon
|
||||||
|
(i/icon-xref :help-refactor (stl/css :icon)))
|
||||||
|
|
||||||
|
(def ^:private close-icon
|
||||||
|
(i/icon-xref :close-refactor (stl/css :close-icon)))
|
||||||
|
|
||||||
|
(defn get-icon-by-type
|
||||||
|
[type]
|
||||||
|
(case type
|
||||||
|
:warning neutral-icon
|
||||||
|
:error error-icon
|
||||||
|
:success success-icon
|
||||||
|
:info info-icon
|
||||||
|
neutral-icon))
|
||||||
|
|
||||||
|
(mf/defc toast-notification
|
||||||
|
"These are ephemeral elements that disappear when
|
||||||
|
the close button is pressed,
|
||||||
|
the page is refreshed,
|
||||||
|
the page is navigated to another page or
|
||||||
|
after 7 seconds, which is enough time to be read,
|
||||||
|
except for error messages that require user interaction."
|
||||||
|
|
||||||
|
{::mf/props :obj}
|
||||||
|
[{:keys [type content on-close links] :as props}]
|
||||||
|
|
||||||
|
[:aside {:class (stl/css-case :toast-notification true
|
||||||
|
:warning (= type :warning)
|
||||||
|
:error (= type :error)
|
||||||
|
:success (= type :success)
|
||||||
|
:info (= type :info))}
|
||||||
|
|
||||||
|
(get-icon-by-type type)
|
||||||
|
|
||||||
|
[:div {:class (stl/css :text)}
|
||||||
|
content]
|
||||||
|
|
||||||
|
(when (some? links)
|
||||||
|
[:nav {:class (stl/css :link-nav)}
|
||||||
|
(for [[index link] (d/enumerate links)]
|
||||||
|
[:& lb/link-button {:key (dm/str "link-" index)
|
||||||
|
:class (stl/css :link)
|
||||||
|
:on-click (:callback link)
|
||||||
|
:value (:label link)}])])
|
||||||
|
|
||||||
|
[:button {:class (stl/css :btn-close)
|
||||||
|
:on-click on-close}
|
||||||
|
close-icon]])
|
|
@ -6,18 +6,27 @@
|
||||||
|
|
||||||
@import "refactor/common-refactor.scss";
|
@import "refactor/common-refactor.scss";
|
||||||
|
|
||||||
.banner {
|
.toast-notification {
|
||||||
--bg-color: var(--alert-background-color-error);
|
--bg-color: var(--alert-background-color-default);
|
||||||
--fg-color: var(--alert-text-foreground-color-error);
|
--fg-color: var(--alert-text-foreground-color-default);
|
||||||
--icon-color: var(--alert-icon-foreground-color-error);
|
--icon-color: var(--alert-icon-foreground-color-default);
|
||||||
--border-color: var(--alert-border-color-error);
|
--border-color: var(--alert-border-color-default);
|
||||||
position: relative;
|
@include alertShadow;
|
||||||
display: flex;
|
position: fixed;
|
||||||
align-items: center;
|
top: $s-16;
|
||||||
border-radius: $br-8;
|
right: $s-16;
|
||||||
background-color: var(--bg-color);
|
display: grid;
|
||||||
|
grid-template-columns: $s-16 auto 1fr auto;
|
||||||
|
gap: $s-8;
|
||||||
|
min-height: $s-32;
|
||||||
|
min-width: $s-500;
|
||||||
|
max-width: calc(10 * $s-100);
|
||||||
|
padding: $s-8 $s-8 $s-8 $s-16;
|
||||||
border: $s-1 solid var(--border-color);
|
border: $s-1 solid var(--border-color);
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
border-radius: $br-12;
|
||||||
color: var(--fg-color);
|
color: var(--fg-color);
|
||||||
|
z-index: $z-index-alert;
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning {
|
.warning {
|
||||||
|
@ -48,76 +57,15 @@
|
||||||
--border-color: var(--alert-border-color-default);
|
--border-color: var(--alert-border-color-default);
|
||||||
}
|
}
|
||||||
|
|
||||||
.banner.info .icon {
|
.error {
|
||||||
--icon-color: var(--alert-icon-foreground-color-info);
|
--bg-color: var(--alert-background-color-error);
|
||||||
|
--fg-color: var(--alert-text-foreground-color-error);
|
||||||
|
--icon-color: var(--alert-icon-foreground-color-error);
|
||||||
|
--border-color: var(--alert-border-color-error);
|
||||||
}
|
}
|
||||||
|
|
||||||
.banner.info:hover .icon {
|
.link-nav {
|
||||||
--fg-color: var(--alert-text-foreground-color-neutral);
|
height: $s-24;
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: $s-8;
|
|
||||||
min-height: $s-32;
|
|
||||||
width: 100%;
|
|
||||||
padding: $s-8 0 $s-8 $s-16;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
@include flexCenter;
|
|
||||||
height: 100%;
|
|
||||||
svg {
|
|
||||||
@extend .button-icon;
|
|
||||||
stroke: var(--icon-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fixed {
|
|
||||||
@include alertShadow;
|
|
||||||
position: fixed;
|
|
||||||
top: $s-16;
|
|
||||||
right: $s-16;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: $s-48;
|
|
||||||
min-width: $s-500;
|
|
||||||
max-width: calc(10 * $s-100);
|
|
||||||
padding-inline-start: $s-16;
|
|
||||||
z-index: $z-index-alert;
|
|
||||||
}
|
|
||||||
|
|
||||||
.floating {
|
|
||||||
@include alertShadow;
|
|
||||||
position: absolute;
|
|
||||||
min-height: $s-32;
|
|
||||||
top: $s-72;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
width: $s-640;
|
|
||||||
margin-inline: auto;
|
|
||||||
z-index: $z-index-modal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline {
|
|
||||||
min-height: $s-32;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hide {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
@include flexRow;
|
|
||||||
gap: $s-8;
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
@include bodyMedTipography;
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
|
@ -126,31 +74,15 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.icon {
|
||||||
@include flexRow;
|
@extend .button-icon;
|
||||||
gap: $s-8;
|
height: 100%;
|
||||||
|
stroke: var(--icon-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn {
|
.text {
|
||||||
@extend .button-tertiary;
|
@include bodyMedTipography;
|
||||||
@include uppercaseTitleTipography;
|
align-self: center;
|
||||||
min-height: $s-32;
|
|
||||||
min-width: $s-32;
|
|
||||||
svg {
|
|
||||||
@extend .button-icon-small;
|
|
||||||
}
|
|
||||||
&.primary {
|
|
||||||
@extend .button-primary;
|
|
||||||
padding: $s-8 $s-24;
|
|
||||||
}
|
|
||||||
&.secondary {
|
|
||||||
@extend .button-secondary;
|
|
||||||
padding: $s-8 $s-24;
|
|
||||||
}
|
|
||||||
&.danger {
|
|
||||||
@extend .modal-danger-btn;
|
|
||||||
padding: $s-8 $s-24;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-close {
|
.btn-close {
|
||||||
|
@ -159,8 +91,9 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-width: $s-32;
|
min-width: $s-32;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
svg {
|
}
|
||||||
|
|
||||||
|
.close-icon {
|
||||||
@extend .button-icon;
|
@extend .button-icon;
|
||||||
stroke: var(--icon-color);
|
stroke: var(--icon-color);
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -17,7 +17,7 @@
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.forms :as fm]
|
[app.main.ui.components.forms :as fm]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.messages :as msgs]
|
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
|
@ -110,7 +110,7 @@
|
||||||
:on-click on-close} i/close-refactor]]
|
:on-click on-close} i/close-refactor]]
|
||||||
|
|
||||||
[:div {:class (stl/css :modal-content)}
|
[:div {:class (stl/css :modal-content)}
|
||||||
[:& msgs/inline-notification
|
[:& context-notification
|
||||||
{:type :info
|
{:type :info
|
||||||
:content (tr "modals.change-email.info" (:email profile))}]
|
:content (tr "modals.change-email.info" (:email profile))}]
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
[app.main.data.users :as du]
|
[app.main.data.users :as du]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.messages :as msgs]
|
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
:on-click on-close} i/close-refactor]]
|
:on-click on-close} i/close-refactor]]
|
||||||
|
|
||||||
[:div {:class (stl/css :modal-content)}
|
[:div {:class (stl/css :modal-content)}
|
||||||
[:& msgs/inline-notification
|
[:& context-notification
|
||||||
{:type :warning
|
{:type :warning
|
||||||
:content (tr "modals.delete-account.info")}]]
|
:content (tr "modals.delete-account.info")}]]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue