Spaces:
Sleeping
Sleeping
defmodule ChaiWeb.CoreComponents do | |
@moduledoc """ | |
Provides core UI components. | |
""" | |
use Phoenix.Component | |
alias Phoenix.LiveView.JS | |
@doc """ | |
Renders flash notices. | |
## Examples | |
<.flash kind={:info} flash={@flash} /> | |
<.flash kind={:info} phx-mounted={show("#flash")}>Welcome Back!</.flash> | |
""" | |
attr :id, :string, default: "flash", doc: "the optional id of flash container" | |
attr :flash, :map, default: %{}, doc: "the map of flash messages to display" | |
attr :title, :string, default: nil | |
attr :kind, :atom, values: [:info, :error], doc: "used for styling and flash lookup" | |
attr :autoshow, :boolean, default: true, doc: "whether to auto show the flash on mount" | |
attr :close, :boolean, default: true, doc: "whether the flash can be closed" | |
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the flash container" | |
slot :inner_block, doc: "the optional inner block that renders the flash message" | |
def flash(assigns) do | |
~H""" | |
<div | |
:if={msg = render_slot(@inner_block) || Phoenix.Flash.get(@flash, @kind)} | |
id={@id} | |
phx-mounted={@autoshow && show("##{@id}")} | |
phx-click={JS.push("lv:clear-flash", value: %{key: @kind}) |> hide("##{@id}")} | |
role="alert" | |
class={[ | |
"fixed hidden top-2 right-2 w-80 sm:w-96 z-50 rounded-lg p-3 shadow-md shadow-zinc-900/5 ring-1", | |
@kind == :info && "bg-emerald-50 text-emerald-800 ring-emerald-500 fill-cyan-900", | |
@kind == :error && "bg-rose-50 p-3 text-rose-900 shadow-md ring-rose-500 fill-rose-900" | |
]} | |
{@rest} | |
> | |
<p :if={@title} class="flex items-center gap-1.5 text-[0.8125rem] font-semibold leading-6"> | |
<.icon :if={@kind == :info} name="hero-information-circle-mini" class="w-4 h-4" /> | |
<.icon :if={@kind == :error} name="hero-exclamation-circle-mini" class="w-4 h-4" /> | |
<%= @title %> | |
</p> | |
<p class="mt-2 text-[0.8125rem] leading-5"><%= msg %></p> | |
<button :if={@close} type="button" class="group absolute top-2 right-1 p-2" aria-label="close"> | |
<.icon name="hero-x-mark-solid" class="w-5 h-5 opacity-40 group-hover:opacity-70" /> | |
</button> | |
</div> | |
""" | |
end | |
@doc """ | |
Shows the flash group with standard titles and content. | |
## Examples | |
<.flash_group flash={@flash} /> | |
""" | |
attr :flash, :map, required: true, doc: "the map of flash messages" | |
def flash_group(assigns) do | |
~H""" | |
<.flash kind={:info} title="Success!" flash={@flash} /> | |
<.flash kind={:error} title="Error!" flash={@flash} /> | |
<.flash | |
id="disconnected" | |
kind={:error} | |
title="We can't find the internet" | |
close={false} | |
autoshow={false} | |
phx-disconnected={show("#disconnected")} | |
phx-connected={hide("#disconnected")} | |
> | |
Attempting to reconnect <.icon name="hero-arrow-path" class="ml-1 w-3 h-3 animate-spin" /> | |
</.flash> | |
""" | |
end | |
@doc """ | |
Renders a [Hero Icon](https://heroicons.com). | |
Hero icons come in three styles – outline, solid, and mini. | |
By default, the outline style is used, but solid an mini may | |
be applied by using the `-solid` and `-mini` suffix. | |
You can customize the size and colors of the icons by setting | |
width, height, and background color classes. | |
Icons are extracted from your `priv/hero_icons` directory and bundled | |
within your compiled app.css by the plugin in your `assets/tailwind.config.js`. | |
## Examples | |
<.icon name="hero-cake" /> | |
<.icon name="hero-cake-solid" /> | |
<.icon name="hero-cake-mini" /> | |
<.icon name="hero-bolt" class="bg-blue-500 w-10 h-10" /> | |
""" | |
attr :name, :string, required: true | |
attr :class, :string, default: nil | |
def icon(%{name: "hero-" <> _} = assigns) do | |
~H""" | |
<span class={[@name, @class]} /> | |
""" | |
end | |
## JS Commands | |
def show(js \\ %JS{}, selector) do | |
JS.show(js, | |
to: selector, | |
transition: | |
{"transition-all transform ease-out duration-300", | |
"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95", | |
"opacity-100 translate-y-0 sm:scale-100"} | |
) | |
end | |
def hide(js \\ %JS{}, selector) do | |
JS.hide(js, | |
to: selector, | |
time: 200, | |
transition: | |
{"transition-all transform ease-in duration-200", | |
"opacity-100 translate-y-0 sm:scale-100", | |
"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"} | |
) | |
end | |
end | |