defmodule MusicLibraryWeb.ChartComponents do @moduledoc """ Chart components for the stats dashboard. """ use MusicLibraryWeb, :live_component @doc """ Renders a horizontal bar chart using CSS Grid. The label column auto-sizes to the widest label (up to 130px max), bars fill remaining space proportionally, and values are displayed to the right of each bar. ## Examples <.vertical_bar_chart data={[{"Artist 1", 5}, {"Artist 2", 3}]} label_fn={&elem(&1, 0)} value_fn={&elem(&1, 1)} color_class="bg-red-500" /> """ attr :data, :list, required: true attr :label_fn, :any, required: true attr :value_fn, :any, required: true attr :color_class, :string, required: true attr :class, :string, default: "" attr :datum_click, :any, default: nil, doc: "the function for handling phx-click on each datum" def vertical_bar_chart(assigns) when assigns.data != [] do assigns = assigns |> assign(:max_value, max_value(assigns.data, assigns.value_fn)) ~H"""
<%= for datum <- @data do %> <% percentage = bar_percentage(@value_fn.(datum), @max_value) %> <% label = to_string(@label_fn.(datum)) %> <%= if @datum_click do %>
<.bar_row label={label} percentage={percentage} value={@value_fn.(datum)} color_class={@color_class} grouped />
<% else %> <.bar_row label={label} percentage={percentage} value={@value_fn.(datum)} color_class={@color_class} /> <% end %> <% end %>
""" end def vertical_bar_chart(assigns) do ~H"""
{gettext("No data available")}
""" end attr :label, :string, required: true attr :percentage, :float, required: true attr :value, :any, required: true attr :color_class, :string, required: true attr :grouped, :boolean, default: false defp bar_row(assigns) do ~H"""
{@label}
{@value}
""" end defp max_value(data, value_fn) do max = Enum.max_by(data, value_fn) value_fn.(max) end defp bar_percentage(_value, max_value) when max_value == 0, do: 0.0 defp bar_percentage(value, max_value), do: value / max_value * 100 end