defmodule CMSWeb.CoreComponents do
@moduledoc """
Provides core UI components.
"""
use Phoenix.Component
attr :class, :string, default: nil
attr :global, :global
slot :inner_block
def title(assigns) do
~H"""
<h1 class={["font-bold text-xl mb-3", @class]} {@global}>{render_slot(@inner_block)}</h1>
"""
end
attr :class, :string, default: nil
attr :global, :global
slot :inner_block
def subtitle(assigns) do
~H"""
<h2 class={["font-bold text-lg mb-2", @class]} {@global}>{render_slot(@inner_block)}</h2>
"""
end
attr :class, :string, default: nil
attr :global, :global,
include: ~w[navigate patch href replace method csrf_token download hreflang referrerpolicy rel target type]
slot :inner_block
def a(assigns) do
~H"""
<.link class={["hover:underline", @class]} {@global}>{render_slot(@inner_block)}</.link>
"""
end
attr :class, :string, default: nil
attr :type, :string, default: "button"
attr :global, :global
slot :inner_block
def button(assigns) do
~H"""
<button type={@type} class={["hover:underline", @class]} {@global}>
{render_slot(@inner_block)}
</button>
"""
end
attr :class, :string, default: nil
attr :field, Phoenix.HTML.FormField, required: true
attr :type, :string, default: "text"
attr :global, :global, include: ~w[required placeholder]
def input(%{type: "textarea"} = assigns) do
~H"""
<textarea
class={["px-2 py-1 border border-gray-400 rounded", @class]}
id={@field.id}
name={@field.name}
{@global}
>{@field.value}</textarea>
"""
end
def input(assigns) do
~H"""
<input
class={["px-2 py-1 border border-gray-400 rounded", @class]}
type={@type}
id={@field.id}
name={@field.name}
value={@field.value}
{@global}
/>
"""
end
@doc """
Renders a [Heroicon](https://heroicons.com).
Heroicons come in three styles – outline, solid, and mini.
By default, the outline style is used, but solid and 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 the `deps/heroicons` directory and bundled within
your compiled app.css by the plugin in your `assets/tailwind.config.js`.
## Examples
<.icon name="hero-x-mark-solid" />
<.icon name="hero-arrow-path" class="ml-1 w-3 h-3 animate-spin" />
"""
attr :name, :string, required: true
attr :class, :string, default: nil
def icon(%{name: "hero-" <> _} = assigns) do
~H"""
<span class={[@name, @class]} />
"""
end
attr :format, :string, required: true
attr :value, :any, default: nil
attr :formatter, :atom, default: :default
attr :timezone, :string, default: "America/New_York"
attr :global, :global
def timex(%{value: nil} = assigns) do
~H"""
<time datetime="">--</time>
"""
end
def timex(%{value: value, timezone: timezone} = assigns) do
assigns =
assign_new(assigns, :local_value, fn ->
case value do
%DateTime{} = datetime ->
datetime
%NaiveDateTime{} = naive ->
naive
|> DateTime.from_naive!("Etc/UTC")
|> DateTime.shift_zone!(timezone)
end
end)
~H"""
<time
datetime={Timex.format!(@local_value, "{ISO:Extended}")}
title={Timex.format!(@local_value, "{Mshort} {D}, {YYYY}, {h12}:{m} {AM} {Zabbr}")}
{@global}
>
{Timex.format!(@local_value, @format, timex_formatter(@formatter))}
</time>
"""
end
defp timex_formatter(formatter) do
Module.concat(Timex.Format.DateTime.Formatters, :string.titlecase("#{formatter}"))
end
end