defmodule Web.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