defmodule Uikit.Components do @moduledoc """ Provides UIkit components for Phoenix applications. This module offers a collection of function components that wrap standard UIkit elements, making them easy to use within Phoenix LiveView and HEEx templates. ## Prerequisites Ensure that UIkit CSS and JS are loaded in your application. See the `README.md` for installation instructions. ## Usage Import this module in your web interface (e.g., `lib/my_app_web.ex`): defp html_helpers do quote do # ... import Uikit.Components # ... end end """ use Phoenix.Component @doc """ Renders a UIkit button. Supports standard button styles and can function as a link if `href`, `navigate`, or `patch` attributes are provided. ## Examples <.uk_button>Default <.uk_button variant="primary">Primary <.uk_button variant="danger" size="small">Small Danger <.uk_button href="/home">Link Button """ attr :variant, :string, default: "default", values: ~w(default primary secondary danger text link), doc: "The visual style of the button." attr :size, :string, default: nil, values: [nil, "small", "large"], doc: "The size of the button." attr :type, :string, default: "button", doc: "The HTML type of the button (submit, reset, button)." attr :class, :string, default: nil, doc: "Additional CSS classes." attr :rest, :global, include: ~w(href navigate patch method download), doc: "Global attributes or link-specific attributes." slot :inner_block, required: true, doc: "The content of the button." def uk_button(assigns) do class = [ "uk-button", "uk-button-#{assigns.variant}", assigns.size && "uk-button-#{assigns.size}", assigns.class ] assigns = assign(assigns, :class, class) if assigns.rest[:href] || assigns.rest[:navigate] || assigns.rest[:patch] do ~H""" <.link class={@class} {@rest}> {render_slot(@inner_block)} """ else ~H""" """ end end @doc """ Renders a UIkit badge. Badges are used to highlight information, such as counts or labels. ## Examples <.uk_badge>1 <.uk_badge class="uk-label-success">100 """ attr :class, :string, default: nil, doc: "Additional CSS classes." attr :rest, :global, doc: "Global attributes." slot :inner_block, required: true, doc: "The content of the badge." def uk_badge(assigns) do ~H""" {render_slot(@inner_block)} """ end @doc """ Renders a UIkit card. Cards are layout boxes with modifiers for style and size. They can contain a header, body, and footer. ## Examples <.uk_card> <:header> <.uk_card_title>Title <:body> Content <:footer> Footer content """ attr :variant, :string, default: "default", values: ~w(default primary secondary), doc: "The style variant of the card." attr :size, :string, default: nil, values: [nil, "small", "large"], doc: "The padding size of the card." attr :hover, :boolean, default: false, doc: "Whether to add a hover effect." attr :class, :string, default: nil, doc: "Additional CSS classes." attr :rest, :global, doc: "Global attributes." slot :header, doc: "The card header content." slot :body, doc: "The card body content." slot :footer, doc: "The card footer content." slot :inner_block, doc: "Inner content, if not using structured slots." def uk_card(assigns) do ~H"""
{render_slot(@header)}
{render_slot(@body)}
{render_slot(@inner_block)}
""" end @doc """ Renders a title for the card component. """ attr :class, :string, default: nil, doc: "Additional CSS classes." attr :rest, :global, doc: "Global attributes." slot :inner_block, required: true, doc: "The title text." def uk_card_title(assigns) do ~H"""

{render_slot(@inner_block)}

""" end @doc """ Renders a UIkit container. Containers constrain the width of the content and center it. ## Examples <.uk_container size="small"> Content """ attr :size, :string, default: nil, values: [nil, "xsmall", "small", "large", "xlarge", "expand"], doc: "The max-width of the container." attr :class, :string, default: nil, doc: "Additional CSS classes." attr :rest, :global, doc: "Global attributes." slot :inner_block, required: true, doc: "The container content." def uk_container(assigns) do ~H"""
{render_slot(@inner_block)}
""" end @doc """ Renders a UIkit grid. The grid component creates a responsive, fluid and nestable grid layout. ## Examples <.uk_grid gap="small" match>
Item 1
Item 2
""" attr :gap, :string, default: nil, values: [nil, "small", "medium", "large", "collapse"], doc: "The grid gap size." attr :divider, :boolean, default: false, doc: "Whether to show a divider between cells." attr :match, :boolean, default: false, doc: "Whether to match the height of grid cells." attr :masonry, :string, default: nil, values: [nil, "pack", "next", "true"], doc: "Enables masonry layout." attr :class, :string, default: nil, doc: "Additional CSS classes." attr :rest, :global, doc: "Global attributes." slot :inner_block, required: true, doc: "The grid items." def uk_grid(assigns) do grid_opts = if assigns.masonry do "masonry: #{assigns.masonry}" else true end assigns = assign(assigns, :grid_opts, grid_opts) ~H"""
{render_slot(@inner_block)}
""" end @doc """ Renders a UIkit sortable container. Enables drag and drop reordering of items. Requires the `Sortable` hook for LiveView integration. ## Examples <.uk_sortable id="my-sortable" group="my-group" grid phx-hook="Sortable">
Item 1
Item 2
""" attr :id, :string, required: true, doc: "The DOM ID of the container (required for hooks)." attr :group, :string, default: nil, doc: "The group name for dragging between lists." attr :animation, :integer, default: nil, doc: "Animation duration in milliseconds." attr :threshold, :integer, default: nil, doc: "Mouse move threshold before dragging starts." attr :handle, :string, default: nil, doc: "Selector for the drag handle." attr :cls_custom, :string, default: nil, doc: "Custom class for the dragged item." attr :grid, :boolean, default: false, doc: "Whether to apply the grid component behavior." attr :class, :string, default: nil, doc: "Additional CSS classes." attr :rest, :global, doc: "Global attributes (e.g. phx-hook)." slot :inner_block, required: true, doc: "The sortable items." def uk_sortable(assigns) do sortable_opts = [ assigns.group && "group: #{assigns.group}", assigns.animation && "animation: #{assigns.animation}", assigns.threshold && "threshold: #{assigns.threshold}", assigns.handle && "handle: #{assigns.handle}", assigns.cls_custom && "cls-custom: #{assigns.cls_custom}" ] |> Enum.reject(&is_nil/1) |> Enum.join("; ") assigns = assign(assigns, :sortable_opts, sortable_opts) ~H"""
{render_slot(@inner_block)}
""" end end