mirror of
https://github.com/penpot/penpot.git
synced 2025-04-16 00:41:25 -05:00
♻️ Create shared notification utility component
This commit is contained in:
parent
9660307f00
commit
5c32ec8cfa
9 changed files with 157 additions and 258 deletions
|
@ -21,6 +21,7 @@
|
|||
[app.main.ui.ds.foundations.utilities.token.token-status :refer [token-status-icon* token-status-list]]
|
||||
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
|
||||
[app.main.ui.ds.notifications.actionable :refer [actionable*]]
|
||||
[app.main.ui.ds.notifications.shared.notification-pill :refer [notification-pill*]]
|
||||
[app.main.ui.ds.notifications.toast :refer [toast*]]
|
||||
[app.main.ui.ds.product.autosaved-milestone :refer [autosaved-milestone*]]
|
||||
[app.main.ui.ds.product.avatar :refer [avatar*]]
|
||||
|
@ -54,6 +55,7 @@
|
|||
:Text text*
|
||||
:TabSwitcher tab-switcher*
|
||||
:Toast toast*
|
||||
:NotificationPill notification-pill*
|
||||
:Actionable actionable*
|
||||
:TokenStatusIcon token-status-icon*
|
||||
:Swatch swatch*
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
;; 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.ds.notifications.shared.notification-pill
|
||||
(:require-macros
|
||||
[app.main.style :as stl])
|
||||
(:require
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn icons-by-level
|
||||
[level]
|
||||
(case level
|
||||
:info i/info
|
||||
:warning i/msg-neutral
|
||||
:error i/delete-text
|
||||
:success i/status-tick
|
||||
i/info))
|
||||
|
||||
(def ^:private schema:notification-pill
|
||||
[:map
|
||||
[:level [:enum :info :warning :error :success]]
|
||||
[:type [:enum :toast :context]]])
|
||||
|
||||
(mf/defc notification-pill*
|
||||
{::mf/props :obj
|
||||
::mf/schema schema:notification-pill}
|
||||
[{:keys [level type children]}]
|
||||
(let [class (stl/css-case :notification-pill true
|
||||
:type-toast (= type :toast)
|
||||
:type-context (= type :context)
|
||||
:level-warning (= level :warning)
|
||||
:level-error (= level :error)
|
||||
:level-success (= level :success)
|
||||
:level-info (= level :info))
|
||||
icon-id (icons-by-level level)]
|
||||
[:div {:class class}
|
||||
[:> i/icon* {:icon-id icon-id :class (stl/css :icon)}]
|
||||
children]))
|
|
@ -0,0 +1,68 @@
|
|||
// 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
|
||||
|
||||
@use "../../_sizes.scss" as *;
|
||||
@use "../../_borders.scss" as *;
|
||||
@use "../../typography.scss" as *;
|
||||
|
||||
.notification-pill {
|
||||
@include use-typography("body-medium");
|
||||
|
||||
--notification-bg-color: var(--color-background-primary);
|
||||
--notification-fg-color: var(--color-foreground-primary);
|
||||
--notification-border-color: var(--color-background-quaternary);
|
||||
--notification-padding: var(--sp-l);
|
||||
--notification-icon-color: var(--color-foreground-secondary);
|
||||
--notification-icon-margin: var(--sp-xxs);
|
||||
|
||||
background-color: var(--notification-bg-color);
|
||||
border: $b-1 solid var(--notification-border-color);
|
||||
border-radius: $br-8;
|
||||
padding: var(--notification-padding);
|
||||
|
||||
display: flex;
|
||||
gap: var(--sp-s);
|
||||
|
||||
color: var(--notification-fg-color);
|
||||
}
|
||||
|
||||
.type-toast {
|
||||
padding-inline-end: var(--sp-xxxl);
|
||||
}
|
||||
|
||||
.level-info {
|
||||
--notification-bg-color: var(--color-background-info);
|
||||
--notification-fg-color: var(--color-foreground-primary);
|
||||
--notification-border-color: var(--color-accent-info);
|
||||
--notification-icon-color: var(--color-accent-info);
|
||||
}
|
||||
|
||||
.level-error {
|
||||
--notification-bg-color: var(--color-background-error);
|
||||
--notification-fg-color: var(--color-foreground-primary);
|
||||
--notification-border-color: var(--color-accent-error);
|
||||
--notification-icon-color: var(--color-accent-error);
|
||||
}
|
||||
|
||||
.level-warning {
|
||||
--notification-bg-color: var(--color-background-warning);
|
||||
--notification-fg-color: var(--color-foreground-warning);
|
||||
--notification-border-color: var(--color-accent-warning);
|
||||
--notification-icon-color: var(--color-accent-warning);
|
||||
}
|
||||
|
||||
.level-success {
|
||||
--notification-bg-color: var(--color-background-success);
|
||||
--notification-fg-color: var(--color-foreground-success);
|
||||
--notification-border-color: var(--color-accent-success);
|
||||
--notification-icon-color: var(--color-accent-success);
|
||||
}
|
||||
|
||||
.icon {
|
||||
flex-shrink: 0;
|
||||
color: var(--notification-icon-color);
|
||||
margin-block-start: var(--notification-icon-margin);
|
||||
}
|
|
@ -9,37 +9,35 @@
|
|||
[app.common.data.macros :as dm]
|
||||
[app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.notifications.shared.notification-pill :refer [notification-pill*]]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private icons-by-level
|
||||
{"info" i/info
|
||||
"warning" i/msg-neutral
|
||||
"error" i/delete-text
|
||||
"success" i/status-tick})
|
||||
|
||||
(def ^:private schema:toast
|
||||
[:map
|
||||
[:class {:optional true} :string]
|
||||
[:level {:optional true}
|
||||
[:maybe [:enum "info" "warning" "error" "success"]]]
|
||||
[:type {:optional true} [:maybe [:enum :toast :context]]]
|
||||
[:level {:optional true} [:maybe [:enum :info :warning :error :success]]]
|
||||
[:on-close {:optional true} fn?]])
|
||||
|
||||
(mf/defc toast*
|
||||
{::mf/props :obj
|
||||
::mf/schema schema:toast}
|
||||
[{:keys [class level children on-close] :rest props}]
|
||||
(let [class (dm/str (stl/css-case :toast true
|
||||
:toast-info (= level "info")
|
||||
:toast-warning (= level "warning")
|
||||
:toast-error (= level "error")
|
||||
:toast-success (= level "success")) " " class)
|
||||
icon-id (or (get icons-by-level level) i/msg-neutral)
|
||||
props (mf/spread-props props {:class class})]
|
||||
[{:keys [class level type children on-close] :rest props}]
|
||||
(let [class (dm/str class " " (stl/css-case :toast true))
|
||||
level (if (string? level)
|
||||
(keyword level)
|
||||
(d/nilv level :info))
|
||||
type (or type :context)
|
||||
props (mf/spread-props props {:class class
|
||||
:role "alert"
|
||||
:aria-live "polite"})]
|
||||
[:> "aside" props
|
||||
[:*
|
||||
[:> i/icon* {:icon-id icon-id :class (stl/css :icon)}]
|
||||
children
|
||||
[:> notification-pill* {:level level :type type} children]
|
||||
;; TODO: this should be a buttom from the DS, but this variant is not designed yet.
|
||||
;; https://tree.taiga.io/project/penpot/task/8492
|
||||
[:> "button" {:on-click on-close :aria-label "Close" :class (stl/css :close-button)} [:> i/icon* {:icon-id i/close}]]]]))
|
||||
[:> "button" {:on-click on-close
|
||||
:aria-label "Close"
|
||||
:class (stl/css :close-button)}
|
||||
[:> i/icon* {:icon-id i/close}]]]))
|
||||
|
|
|
@ -7,72 +7,33 @@
|
|||
@use "../_sizes.scss" as *;
|
||||
@use "../_borders.scss" as *;
|
||||
@use "../typography.scss" as *;
|
||||
@use "../spacing.scss" as *;
|
||||
@use "../z-index.scss" as *;
|
||||
|
||||
.toast {
|
||||
@include use-typography("body-medium");
|
||||
|
||||
--toast-bg-color: var(--color-background-primary);
|
||||
--toast-fg-color: var(--color-foreground-primary);
|
||||
--toast-border-color: var(--color-background-quaternary);
|
||||
--toast-padding: var(--sp-l);
|
||||
--toast-icon-color: var(--color-foreground-secondary);
|
||||
--toast-icon-margin: var(--sp-xxs);
|
||||
--toast-vertical-index: var(--z-index-notifications);
|
||||
--toast-inset-block-start-position: var(--sp-l);
|
||||
--toast-inset-inline-end-position: var(--sp-l);
|
||||
|
||||
min-inline-size: $sz-224;
|
||||
max-inline-size: $sz-480;
|
||||
background-color: var(--toast-bg-color);
|
||||
border: $b-1 solid var(--toast-border-color);
|
||||
border-radius: $br-8;
|
||||
padding: var(--toast-padding);
|
||||
|
||||
display: inline-grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
column-gap: var(--sp-s);
|
||||
align-items: flex-start;
|
||||
|
||||
color: var(--toast-fg-color);
|
||||
}
|
||||
|
||||
.toast-info {
|
||||
--toast-bg-color: var(--color-background-info);
|
||||
--toast-fg-color: var(--color-foreground-primary);
|
||||
--toast-border-color: var(--color-accent-info);
|
||||
--toast-icon-color: var(--color-accent-info);
|
||||
}
|
||||
|
||||
.toast-error {
|
||||
--toast-bg-color: var(--color-background-error);
|
||||
--toast-fg-color: var(--color-foreground-primary);
|
||||
--toast-border-color: var(--color-accent-error);
|
||||
--toast-icon-color: var(--color-accent-error);
|
||||
}
|
||||
|
||||
.toast-warning {
|
||||
--toast-bg-color: var(--color-background-warning);
|
||||
--toast-fg-color: var(--color-foreground-primary);
|
||||
--toast-border-color: var(--color-accent-warning);
|
||||
--toast-icon-color: var(--color-accent-warning);
|
||||
}
|
||||
|
||||
.toast-success {
|
||||
--toast-bg-color: var(--color-background-success);
|
||||
--toast-fg-color: var(--color-foreground-primary);
|
||||
--toast-border-color: var(--color-accent-success);
|
||||
--toast-icon-color: var(--color-accent-success);
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: var(--toast-icon-color);
|
||||
margin-block-start: var(--toast-icon-margin);
|
||||
display: block;
|
||||
position: fixed;
|
||||
inset-block-start: var(--toast-inset-block-start-position);
|
||||
inset-inline-end: var(--toast-inset-inline-end-position);
|
||||
z-index: var(--toast-vertical-index);
|
||||
}
|
||||
|
||||
.close-button {
|
||||
appearance: none;
|
||||
width: $sz-16;
|
||||
height: $sz-16;
|
||||
display: inline-grid;
|
||||
place-content: center;
|
||||
position: absolute;
|
||||
top: var(--sp-l);
|
||||
right: var(--sp-l);
|
||||
background: none;
|
||||
border: none;
|
||||
background: var(--toast-bg-color);
|
||||
color: var(--toast-icon-color);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
import * as React from "react";
|
||||
import Components from "@target/components";
|
||||
import { action } from "@storybook/addon-actions";
|
||||
|
||||
const { Toast } = Components;
|
||||
|
||||
|
@ -19,13 +20,12 @@ export default {
|
|||
},
|
||||
args: {
|
||||
children: "Lorem ipsum",
|
||||
onClose: () => {
|
||||
alert("Close callback");
|
||||
},
|
||||
type: "toast",
|
||||
onClose: action("on-close"),
|
||||
},
|
||||
parameters: {
|
||||
controls: {
|
||||
exclude: ["onClose"],
|
||||
exclude: ["onClose", "type"],
|
||||
},
|
||||
},
|
||||
render: ({ ...args }) => <Toast {...args} />,
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
(:require
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.ds.notifications.toast :refer [toast*]]
|
||||
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||
[app.main.ui.notifications.inline-notification :refer [inline-notification]]
|
||||
[app.main.ui.notifications.toast-notification :refer [toast-notification]]
|
||||
[okulary.core :as l]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
@ -26,16 +26,16 @@
|
|||
inline? (or (= :inline (:type notification))
|
||||
(= :floating (:position notification)))
|
||||
toast? (or (= :toast (:type notification))
|
||||
(some? (:timeout notification)))]
|
||||
(some? (:timeout notification)))
|
||||
content (or (:content notification) "")]
|
||||
|
||||
(when notification
|
||||
(cond
|
||||
toast?
|
||||
[:& toast-notification
|
||||
[:> toast*
|
||||
{:level (or (:level notification) :info)
|
||||
:links (:links notification)
|
||||
:on-close on-close
|
||||
:content (:content notification)}]
|
||||
:type (:type notification)
|
||||
:on-close on-close} content]
|
||||
|
||||
inline?
|
||||
[:& inline-notification
|
||||
|
@ -51,8 +51,7 @@
|
|||
:content (:content notification)}]
|
||||
|
||||
:else
|
||||
[:& toast-notification
|
||||
[:> toast*
|
||||
{:level (or (:level notification) :info)
|
||||
:links (:links notification)
|
||||
:on-close on-close
|
||||
:content (:content notification)}]))))
|
||||
:type (:type notification)
|
||||
:on-close on-close} content]))))
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
;; 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 (stl/css :icon)))
|
||||
|
||||
(def ^:private error-icon
|
||||
(i/icon-xref :delete-text (stl/css :icon)))
|
||||
|
||||
(def ^:private success-icon
|
||||
(i/icon-xref :status-tick (stl/css :icon)))
|
||||
|
||||
(def ^:private info-icon
|
||||
(i/icon-xref :help (stl/css :icon)))
|
||||
|
||||
(def ^:private close-icon
|
||||
(i/icon-xref :close (stl/css :close-icon)))
|
||||
|
||||
(defn get-icon-by-level
|
||||
[level]
|
||||
(case level
|
||||
: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 [level content on-close links] :as props}]
|
||||
|
||||
[:aside {:class (stl/css-case :toast-notification true
|
||||
:warning (= level :warning)
|
||||
:error (= level :error)
|
||||
:success (= level :success)
|
||||
:info (= level :info))}
|
||||
|
||||
(get-icon-by-level level)
|
||||
|
||||
[: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]])
|
|
@ -1,100 +0,0 @@
|
|||
// 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";
|
||||
|
||||
.toast-notification {
|
||||
--toast-notification-bg-color: var(--alert-background-color-default);
|
||||
--toast-notification-fg-color: var(--alert-text-foreground-color-default);
|
||||
--toast-notification-icon-color: var(--alert-icon-foreground-color-default);
|
||||
--toast-notification-border-color: var(--alert-border-color-default);
|
||||
@include alertShadow;
|
||||
position: fixed;
|
||||
top: $s-16;
|
||||
right: $s-16;
|
||||
display: grid;
|
||||
grid-template-columns: $s-16 1fr auto;
|
||||
gap: $s-8;
|
||||
min-height: $s-32;
|
||||
min-width: $s-228;
|
||||
max-width: $s-400;
|
||||
padding: $s-8;
|
||||
border: $s-1 solid var(--toast-notification-border-color);
|
||||
background-color: var(--toast-notification-bg-color);
|
||||
border-radius: $br-8;
|
||||
color: var(--toast-notification-fg-color);
|
||||
z-index: $z-index-alert;
|
||||
}
|
||||
|
||||
.warning {
|
||||
--toast-notification-bg-color: var(--alert-background-color-warning);
|
||||
--toast-notification-fg-color: var(--alert-text-foreground-color-warning);
|
||||
--toast-notification-icon-color: var(--alert-icon-foreground-color-warning);
|
||||
--toast-notification-border-color: var(--alert-border-color-warning);
|
||||
}
|
||||
|
||||
.success {
|
||||
--toast-notification-bg-color: var(--alert-background-color-success);
|
||||
--toast-notification-fg-color: var(--alert-text-foreground-color-success);
|
||||
--toast-notification-icon-color: var(--alert-icon-foreground-color-success);
|
||||
--toast-notification-border-color: var(--alert-border-color-success);
|
||||
}
|
||||
|
||||
.info {
|
||||
--toast-notification-bg-color: var(--alert-background-color-info);
|
||||
--toast-notification-fg-color: var(--alert-text-foreground-color-info);
|
||||
--toast-notification-icon-color: var(--alert-icon-foreground-color-info);
|
||||
--toast-notification-border-color: var(--alert-border-color-info);
|
||||
}
|
||||
|
||||
.default {
|
||||
--toast-notification-bg-color: var(--alert-background-color-default);
|
||||
--toast-notification-fg-color: var(--alert-text-foreground-color-default);
|
||||
--toast-notification-icon-color: var(--alert-icon-foreground-color-default);
|
||||
--toast-notification-border-color: var(--alert-border-color-default);
|
||||
}
|
||||
|
||||
.error {
|
||||
--toast-notification-bg-color: var(--alert-background-color-error);
|
||||
--toast-notification-fg-color: var(--alert-text-foreground-color-error);
|
||||
--toast-notification-icon-color: var(--alert-icon-foreground-color-error);
|
||||
--toast-notification-border-color: var(--alert-border-color-error);
|
||||
}
|
||||
|
||||
.link-nav {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.link {
|
||||
@include bodySmallTypography;
|
||||
color: var(--modal-link-foreground-color);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
@extend .button-icon;
|
||||
align-self: flex-start;
|
||||
stroke: var(--toast-notification-icon-color);
|
||||
}
|
||||
|
||||
.text {
|
||||
@include bodySmallTypography;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
@include buttonStyle;
|
||||
align-self: flex-start;
|
||||
width: $s-16;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
@extend .button-icon;
|
||||
stroke: var(--toast-notification-icon-color);
|
||||
}
|
Loading…
Add table
Reference in a new issue