diff --git a/frontend/src/app/main/ui/ds.cljs b/frontend/src/app/main/ui/ds.cljs
index d30c77969..abd34f5c1 100644
--- a/frontend/src/app/main/ui/ds.cljs
+++ b/frontend/src/app/main/ui/ds.cljs
@@ -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.context-notification :refer [context-notification*]]
[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*]]
@@ -55,6 +56,7 @@
:Text text*
:TabSwitcher tab-switcher*
:Toast toast*
+ :ContextNotification context-notification*
:NotificationPill notification-pill*
:Actionable actionable*
:TokenStatusIcon token-status-icon*
diff --git a/frontend/src/app/main/ui/ds/notifications/actionable.scss b/frontend/src/app/main/ui/ds/notifications/actionable.scss
index ca2b2eb0f..ed11f7b11 100644
--- a/frontend/src/app/main/ui/ds/notifications/actionable.scss
+++ b/frontend/src/app/main/ui/ds/notifications/actionable.scss
@@ -27,4 +27,10 @@
justify-content: space-between;
padding: var(--actionable-padding);
padding-inline-start: var(--sp-l);
+
+ // Targets the potential links included by the creator in the children props.
+ & a {
+ color: var(--color-accent-primary);
+ text-decoration: none;
+ }
}
diff --git a/frontend/src/app/main/ui/ds/notifications/context-notification.stories.jsx b/frontend/src/app/main/ui/ds/notifications/context-notification.stories.jsx
new file mode 100644
index 000000000..14ac864b3
--- /dev/null
+++ b/frontend/src/app/main/ui/ds/notifications/context-notification.stories.jsx
@@ -0,0 +1,100 @@
+// 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 * as React from "react";
+import Components from "@target/components";
+
+const { ContextNotification } = Components;
+
+export default {
+ title: "Notifications/ContextNotification",
+ component: ContextNotification,
+ argTypes: {
+ children: {
+ control: { type: "text" },
+ },
+ appearance: {
+ options: ["neutral", "ghost"],
+ control: { type: "select" },
+ },
+ level: {
+ options: ["info", "error", "warning", "success"],
+ control: { type: "select" },
+ },
+ },
+ args: {
+ children: "Lorem ipsum",
+ isHtml: false,
+ type: "context",
+ appearance: "neutral",
+ level: "info",
+ },
+ parameters: {
+ controls: {
+ exclude: ["type", "isHtml"],
+ },
+ },
+ render: ({ ...args }) => ,
+};
+
+export const Default = {};
+
+export const WithLongerText = {
+ args: {
+ children:
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent lorem ante, bibendum sed ex.",
+ },
+ parameters: {
+ controls: { exclude: ["isHtml"] },
+ },
+};
+
+export const WithHTML = {
+ args: {
+ children:
+ "Lorem ipsum dolor sit amet, Praesent lorem ante, bibendum sed ex.",
+ isHtml: true,
+ },
+ parameters: {
+ controls: { exclude: ["isHtml"] },
+ },
+};
+
+export const Info = {
+ args: {
+ level: "info",
+ },
+ parameters: {
+ controls: { exclude: ["level", "isHtml"] },
+ },
+};
+
+export const Error = {
+ args: {
+ level: "error",
+ },
+ parameters: {
+ controls: { exclude: ["level", "isHtml"] },
+ },
+};
+
+export const Warning = {
+ args: {
+ level: "warning",
+ },
+ parameters: {
+ controls: { exclude: ["level", "isHtml"] },
+ },
+};
+
+export const Success = {
+ args: {
+ level: "success",
+ },
+ parameters: {
+ controls: { exclude: ["level", "isHtml"] },
+ },
+};
diff --git a/frontend/src/app/main/ui/ds/notifications/context_notification.cljs b/frontend/src/app/main/ui/ds/notifications/context_notification.cljs
new file mode 100644
index 000000000..fc867f898
--- /dev/null
+++ b/frontend/src/app/main/ui/ds/notifications/context_notification.cljs
@@ -0,0 +1,53 @@
+;; 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.context-notification
+ (:require-macros [app.main.style :as stl])
+ (:require
+ [app.common.data :as d]
+ [app.common.data.macros :as dm]
+ [app.main.ui.ds.notifications.shared.notification-pill :refer [notification-pill*]]
+ [rumext.v2 :as mf]))
+
+(def ^:private schema:context-notification
+ [:map
+ [:class {:optional true} :string]
+ [:type {:optional true} [:maybe [:enum :toast :context]]]
+ [:appearance {:optional true} [:enum :neutral :ghost]]
+ [:level {:optional true} [:maybe [:enum :info :warning :error :success]]]
+ [:is-html {:optional true} :boolean]])
+
+(mf/defc context-notification*
+ "Persistent notifications, they do not disappear.
+ These are contextual messages in specific areas of the tool, usually in modals and Dashboard area, and are mainly informative."
+ {::mf/props :obj
+ ::mf/schema schema:context-notification}
+ [{:keys [class type appearance level is-html children] :rest props}]
+ (let [class (dm/str class " " (stl/css-case :contextual-notification true
+ :contain-html is-html
+ :level-warning (= level :warning)
+ :level-error (= level :error)
+ :level-success (= level :success)
+ :level-info (= level :info)))
+ level (if (string? level)
+ (keyword level)
+ (d/nilv level :info))
+ type (if (string? type)
+ (keyword type)
+ (d/nilv type :context))
+ appearance (if (string? appearance)
+ (keyword appearance)
+ (d/nilv appearance :neutral))
+ is-html (or is-html false)
+ props (mf/spread-props props {:class class
+ :role "alert"
+ :aria-live "polite"})]
+ [:> "aside" props
+ [:> notification-pill* {:level level
+ :type type
+ :is-html is-html
+ :appearance appearance} children]]))
+
diff --git a/frontend/src/app/main/ui/ds/notifications/context_notification.css b/frontend/src/app/main/ui/ds/notifications/context_notification.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.cljs b/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.cljs
index b86afb6ac..6fc6064c8 100644
--- a/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.cljs
+++ b/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.cljs
@@ -23,20 +23,31 @@
(def ^:private schema:notification-pill
[:map
[:level [:enum :info :warning :error :success]]
- [:type [:enum :toast :context]]])
+ [:type [:enum :toast :context]]
+ [:appearance {:optional true} [:enum :neutral :ghost]]
+ [:is-html {:optional true} :boolean]])
(mf/defc notification-pill*
{::mf/props :obj
::mf/schema schema:notification-pill}
- [{:keys [level type children]}]
+ [{:keys [level type is-html appearance children]}]
(let [class (stl/css-case :notification-pill true
+ :appearance-neutral (= appearance :neutral)
+ :appearance-ghost (= appearance :ghost)
:type-toast (= type :toast)
:type-context (= type :context)
:level-warning (= level :warning)
:level-error (= level :error)
:level-success (= level :success)
:level-info (= level :info))
+ is-html (or is-html false)
icon-id (icons-by-level level)]
[:div {:class class}
[:> i/icon* {:icon-id icon-id :class (stl/css :icon)}]
- children]))
+ ;; The content can arrive in markdown format, in these cases
+ ;; we will use the prop is-html to true to indicate it and
+ ;; that the html injection is performed and the necessary css classes are applied.
+ (if is-html
+ [:div {:class (stl/css :context-text)
+ :dangerouslySetInnerHTML #js {:__html children}}]
+ children)]))
diff --git a/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.scss b/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.scss
index 290ec44e7..200dd1e6e 100644
--- a/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.scss
+++ b/frontend/src/app/main/ui/ds/notifications/shared/notification_pill.scss
@@ -27,12 +27,22 @@
gap: var(--sp-s);
color: var(--notification-fg-color);
+
+ // Targets the potential links included by the creator in the children props.
+ & a {
+ color: var(--color-accent-primary);
+ text-decoration: none;
+ }
}
.type-toast {
padding-inline-end: var(--sp-xxxl);
}
+.appearance-ghost {
+ background-color: transparent;
+}
+
.level-info {
--notification-bg-color: var(--color-background-info);
--notification-fg-color: var(--color-foreground-primary);
diff --git a/frontend/src/app/main/ui/ds/notifications/toast.cljs b/frontend/src/app/main/ui/ds/notifications/toast.cljs
index 2dfad3352..e0ff541c7 100644
--- a/frontend/src/app/main/ui/ds/notifications/toast.cljs
+++ b/frontend/src/app/main/ui/ds/notifications/toast.cljs
@@ -19,25 +19,40 @@
[:class {:optional true} :string]
[:type {:optional true} [:maybe [:enum :toast :context]]]
[:level {:optional true} [:maybe [:enum :info :warning :error :success]]]
+ [:appearance {:optional true} [:enum :neutral :ghost]]
+ [:is-html {:optional true} :boolean]
[:on-close {:optional true} fn?]])
(mf/defc toast*
{::mf/props :obj
::mf/schema schema:toast}
- [{:keys [class level type children on-close] :rest props}]
- (let [class (dm/str class " " (stl/css-case :toast true))
+ [{:keys [class level appearance type is-html children on-close] :rest props}]
+ (let [class (dm/str class " " (stl/css :toast))
level (if (string? level)
(keyword level)
(d/nilv level :info))
- type (or type :context)
+ type (if (string? type)
+ (keyword type)
+ (d/nilv type :context))
+ appearance (if (string? appearance)
+ (keyword appearance)
+ (d/nilv appearance :neutral))
+ is-html (or is-html false)
props (mf/spread-props props {:class class
:role "alert"
:aria-live "polite"})]
[:> "aside" props
- [:> notification-pill* {:level level :type type} children]
+ [:> notification-pill* {:level level
+ :type type
+ :is-html is-html
+ :appearance appearance} 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)}
+ :class (stl/css-case :close-button true
+ :level-warning (= level :warning)
+ :level-error (= level :error)
+ :level-success (= level :success)
+ :level-info (= level :info))}
[:> i/icon* {:icon-id i/close}]]]))
diff --git a/frontend/src/app/main/ui/ds/notifications/toast.scss b/frontend/src/app/main/ui/ds/notifications/toast.scss
index 44f4edf95..a572aac07 100644
--- a/frontend/src/app/main/ui/ds/notifications/toast.scss
+++ b/frontend/src/app/main/ui/ds/notifications/toast.scss
@@ -26,6 +26,22 @@
z-index: var(--toast-vertical-index);
}
+.level-info {
+ --toast-icon-color: var(--color-accent-info);
+}
+
+.level-error {
+ --toast-icon-color: var(--color-accent-error);
+}
+
+.level-warning {
+ --toast-icon-color: var(--color-accent-warning);
+}
+
+.level-success {
+ --toast-icon-color: var(--color-accent-success);
+}
+
.close-button {
appearance: none;
width: $sz-16;
diff --git a/frontend/src/app/main/ui/ds/notifications/toast.stories.jsx b/frontend/src/app/main/ui/ds/notifications/toast.stories.jsx
index 7afeb2d1b..daf2df4ee 100644
--- a/frontend/src/app/main/ui/ds/notifications/toast.stories.jsx
+++ b/frontend/src/app/main/ui/ds/notifications/toast.stories.jsx
@@ -40,6 +40,17 @@ export const WithLongerText = {
},
};
+export const WithHTML = {
+ args: {
+ children:
+ "Lorem ipsum dolor sit amet, Praesent lorem ante, bibendum sed ex.",
+ isHtml: true,
+ },
+ parameters: {
+ controls: { exclude: ["isHtml"] },
+ },
+};
+
export const Info = {
args: {
level: "info",