From 1842c30fe02852f0382ba0ff4e4dd3a53a6b9c89 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 6 Jul 2024 07:21:41 -0400 Subject: [PATCH] feature: arbitrary severity levels --- README.md | 41 +++++++++++++++++++ assets/js/live_toast/live_toast.ts | 10 +---- demo/lib/demo_web/components/layouts.ex | 15 +++++++ .../demo_web/components/layouts/app.html.heex | 2 + demo/lib/demo_web/live/home_live.ex | 2 + demo/lib/demo_web/live/tabs/demo.html.heex | 9 ++++ lib/live_toast.ex | 27 ++++++------ lib/live_toast/components.ex | 23 +++++------ lib/live_toast/live_component.ex | 2 +- 9 files changed, 97 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 9eb8c0b..ad832f9 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,47 @@ And then use it to override the default styles: ``` +### Custom Severity Levels + +New Phoenix projects [use `:info` and `:error`](https://hexdocs.pm/phoenix/controllers.html#flash-messages) +as the default severity levels for flash messages, so this is likely what you're already using. If you need to add an +additional severity level, like `:warning`, you can pass a list of these values to the `kind` attribute: + +```heex + +``` + +If this value is not set, it defaults to `[:info, :error]`. + +Setting `kind` will allow these new severity levels to be displayed, but it won't change how they look. To do that, you +need to override [`toast_class_fn/1`](https://hexdocs.pm/live_toast/LiveToast.html#toast_class_fn/1). For example: + +```elixir +# Note that this is just the default with one line added to handle the new `:warning` level. +def custom_toast_class_fn(assigns) do + [ + # base classes + "bg-white group/toast z-100 pointer-events-auto relative w-full items-center justify-between origin-center overflow-hidden rounded-lg p-4 shadow-lg border col-start-1 col-end-1 row-start-1 row-end-2", + # start hidden if javascript is enabled + "[@media(scripting:enabled)]:opacity-0 [@media(scripting:enabled){[data-phx-main]_&}]:opacity-100", + # used to hide the disconnected flashes + if(assigns[:rest][:hidden] == true, do: "hidden", else: "flex"), + # override styles per severity + assigns[:kind] == :info && "text-black", + assigns[:kind] == :error && "!text-red-700 !bg-red-100 border-red-200", + assigns[:kind] == :warning && "!text-amber-700 !bg-amber-100 border-amber-200" + ] +end +``` + +Then just make sure you've passed it to the `live_group` component as seen above. + + ### JavaScript Options You can also change some options about the LiveView hook when it is initialized. Such as: diff --git a/assets/js/live_toast/live_toast.ts b/assets/js/live_toast/live_toast.ts index 41189d6..e58d639 100644 --- a/assets/js/live_toast/live_toast.ts +++ b/assets/js/live_toast/live_toast.ts @@ -10,15 +10,7 @@ function isHidden(el: HTMLElement | null) { } function isFlash(el: HTMLElement) { - if ( - ['server-error', 'client-error', 'flash-info', 'flash-error'].includes( - el.id, - ) - ) { - return true - } else { - return false - } + return el.dataset.component === 'flash' } // number of flashes that aren't hidden diff --git a/demo/lib/demo_web/components/layouts.ex b/demo/lib/demo_web/components/layouts.ex index f097226..413827d 100644 --- a/demo/lib/demo_web/components/layouts.ex +++ b/demo/lib/demo_web/components/layouts.ex @@ -3,4 +3,19 @@ defmodule DemoWeb.Layouts do use DemoWeb, :html embed_templates("layouts/*") + + def demo_toast_class_fn(assigns) do + [ + # base classes + "bg-white group/toast z-100 pointer-events-auto relative w-full items-center justify-between origin-center overflow-hidden rounded-lg p-4 shadow-lg border col-start-1 col-end-1 row-start-1 row-end-2", + # start hidden if javascript is enabled + "[@media(scripting:enabled)]:opacity-0 [@media(scripting:enabled){[data-phx-main]_&}]:opacity-100", + # used to hide the disconnected flashes + if(assigns[:rest][:hidden] == true, do: "hidden", else: "flex"), + # override styles per severity + assigns[:kind] == :info && "text-black", + assigns[:kind] == :error && "!text-red-700 !bg-red-100 border-red-200", + assigns[:kind] == :warn && "!text-amber-700 !bg-amber-100 border-amber-200" + ] + end end diff --git a/demo/lib/demo_web/components/layouts/app.html.heex b/demo/lib/demo_web/components/layouts/app.html.heex index b3ecc9d..5bef305 100644 --- a/demo/lib/demo_web/components/layouts/app.html.heex +++ b/demo/lib/demo_web/components/layouts/app.html.heex @@ -1,6 +1,8 @@
:info "error" -> :error + "warn" -> :warn end, body, title: title, @@ -135,6 +136,7 @@ defmodule DemoWeb.HomeLive do case kind do "info" -> :info "error" -> :error + "warn" -> :warn end, "This is a flash message." ) diff --git a/demo/lib/demo_web/live/tabs/demo.html.heex b/demo/lib/demo_web/live/tabs/demo.html.heex index a9abca0..6ae46bc 100644 --- a/demo/lib/demo_web/live/tabs/demo.html.heex +++ b/demo/lib/demo_web/live/tabs/demo.html.heex @@ -73,6 +73,15 @@ Error Flash
+ +

+ You can also use arbitrary severity levels. If you want to add another level like "warning", refer to [the documentation here](https://hexdocs.pm/live_toast/readme.html#custom-severity-levels). +

+
+ <.button phx-click="flash" phx-value-kind="warn"> + Warning Flash + +
diff --git a/lib/live_toast.ex b/lib/live_toast.ex index e700a40..fd4b688 100644 --- a/lib/live_toast.ex +++ b/lib/live_toast.ex @@ -26,9 +26,9 @@ defmodule LiveToast do kind: atom(), msg: binary(), title: binary() | nil, - icon: (map() -> binary()) | nil, - action: (map() -> binary()) | nil, - component: (map() -> binary()) | nil, + icon: component_fn() | nil, + action: component_fn() | nil, + component: component_fn() | nil, duration: non_neg_integer() | nil, container_id: binary() | nil, uuid: Ecto.UUID.t() | nil @@ -39,13 +39,13 @@ defmodule LiveToast do @typedoc "Set of public options to augment the default toast behavior." @type option() :: - {:title, binary()} - | {:icon, component_fn()} - | {:action, component_fn()} - | {:component, component_fn()} - | {:duration, non_neg_integer()} - | {:container_id, binary()} - | {:uuid, Ecto.UUID.t()} + {:title, binary() | nil} + | {:icon, component_fn() | nil} + | {:action, component_fn() | nil} + | {:component, component_fn() | nil} + | {:duration, non_neg_integer() | nil} + | {:container_id, binary() | nil} + | {:uuid, Ecto.UUID.t() | nil} @doc """ Send a new toast message to the LiveToast component. @@ -141,13 +141,13 @@ defmodule LiveToast do def toast_class_fn(assigns) do [ # base classes - "group/toast z-100 pointer-events-auto relative w-full items-center justify-between origin-center overflow-hidden rounded-lg p-4 shadow-lg border col-start-1 col-end-1 row-start-1 row-end-2", + "bg-white group/toast z-100 pointer-events-auto relative w-full items-center justify-between origin-center overflow-hidden rounded-lg p-4 shadow-lg border col-start-1 col-end-1 row-start-1 row-end-2", # start hidden if javascript is enabled "[@media(scripting:enabled)]:opacity-0 [@media(scripting:enabled){[data-phx-main]_&}]:opacity-100", # used to hide the disconnected flashes if(assigns[:rest][:hidden] == true, do: "hidden", else: "flex"), # override styles per severity - assigns[:kind] == :info && "bg-white text-black", + assigns[:kind] == :info && "text-black", assigns[:kind] == :error && "!text-red-700 !bg-red-100 border-red-200" ] end @@ -155,6 +155,7 @@ defmodule LiveToast do attr(:flash, :map, required: true, doc: "the map of flash messages") attr(:id, :string, default: "toast-group", doc: "the optional id of flash container") attr(:connected, :boolean, default: false, doc: "whether we're in a liveview or not") + attr(:kinds, :list, default: [:info, :error], doc: "the valid severity level kinds") attr(:corner, :atom, values: [:top_left, :top_right, :bottom_left, :bottom_right], @@ -181,6 +182,7 @@ defmodule LiveToast do corner={@corner} toast_class_fn={@toast_class_fn} f={@flash} + kinds={@kinds} /> """ end diff --git a/lib/live_toast/components.ex b/lib/live_toast/components.ex index 53982cd..6cde38d 100644 --- a/lib/live_toast/components.ex +++ b/lib/live_toast/components.ex @@ -119,29 +119,25 @@ defmodule LiveToast.Components do doc: "function to override the look of the toasts" ) + attr(:kinds, :list, required: true, doc: "the valid severity level kinds") + @doc false def flashes(assigns) do ~H""" <.toast + :for={level <- @kinds} + data-component="flash" corner={@corner} class_fn={@toast_class_fn} duration={0} - kind={:info} - title="Info" - phx-update="ignore" - flash={@f} - /> - <.toast - corner={@corner} - class_fn={@toast_class_fn} - duration={0} - kind={:error} - title="Error" + kind={level} + title={String.capitalize(to_string(level))} phx-update="ignore" flash={@f} /> <.toast + data-component="flash" corner={@corner} class_fn={@toast_class_fn} id="client-error" @@ -157,6 +153,7 @@ defmodule LiveToast.Components do <.toast + data-component="flash" corner={@corner} class_fn={@toast_class_fn} id="server-error" @@ -187,6 +184,8 @@ defmodule LiveToast.Components do doc: "function to override the look of the toasts" ) + attr(:kinds, :list, required: true, doc: "the valid severity level kinds") + # Used to render flashes-only on regular non-LV pages. @doc false def flash_group(assigns) do @@ -213,7 +212,7 @@ defmodule LiveToast.Components do ~H"""
- <.flashes f={@flash} corner={@corner} toast_class_fn={@toast_class_fn} /> + <.flashes f={@flash} corner={@corner} toast_class_fn={@toast_class_fn} kinds={@kinds} />
""" end diff --git a/lib/live_toast/live_component.ex b/lib/live_toast/live_component.ex index d0cb41f..3128526 100644 --- a/lib/live_toast/live_component.ex +++ b/lib/live_toast/live_component.ex @@ -99,7 +99,7 @@ defmodule LiveToast.LiveComponent do
- + """ end