defmodule CobblemonUiWeb.PokemonComponents do use CobblemonUiWeb, :html attr :pokemon, :map, required: true attr :index, :integer, required: true attr :compact, :boolean, default: false attr :tier, :string, default: nil def pokemon_card(%{pokemon: nil} = assigns) do ~H"""
Empty
""" end def pokemon_card(assigns) do ~H"""

{@pokemon.species || "Unknown"}

Lv. {@pokemon.level || "?"}

<.tier_badge :if={@tier} tier={@tier} species={@pokemon.species} compact={@compact} />
?
<.icon name="hero-sparkles" class={[ "text-warning", if(@compact, do: "size-3", else: "size-4") ]} />
{@pokemon.nature} {gender_symbol(@pokemon.gender)}
""" end attr :pokemon, :map, required: true attr :index, :integer, required: true attr :tier, :string, default: nil attr :types, :list, default: [] attr :evo_tiers, :list, default: [] def pc_pokemon_card(assigns) do ~H"""
<%!-- Sprite --%>
{@pokemon.species}
<%!-- Info --%>
{@pokemon.species || "Unknown"} <.tier_badge :if={@tier} tier={@tier} species={@pokemon.species} compact={true} />

Lv. {@pokemon.level || "?"}

<%!-- Types --%>
{type}
<%!-- Evolution tiers --%>
Evo <%= for evo <- @evo_tiers do %>
{evo.species} {evo.species} <.tier_badge :if={evo.tier} tier={evo.tier} species={evo.species} compact={true} />
<% end %>
""" end attr :tier, :string, required: true attr :species, :string, required: true attr :compact, :boolean, default: false def tier_badge(assigns) do ~H""" "bg-red-500/20 text-red-400 ring-1 ring-red-500/30 hover:bg-red-500/30" "A" -> "bg-orange-500/20 text-orange-400 ring-1 ring-orange-500/30 hover:bg-orange-500/30" "B" -> "bg-yellow-500/20 text-yellow-400 ring-1 ring-yellow-500/30 hover:bg-yellow-500/30" "C" -> "bg-green-500/20 text-green-400 ring-1 ring-green-500/30 hover:bg-green-500/30" "D" -> "bg-blue-500/20 text-blue-400 ring-1 ring-blue-500/30 hover:bg-blue-500/30" _ -> "bg-base-300/30 text-base-content/40 ring-1 ring-base-300/40" end ]} > {@tier} """ end attr :pokemon, :map, required: true attr :tier, :string, default: nil def pokemon_detail(assigns) do ~H"""
<%!-- Detail header --%>
{@pokemon.species}

{@pokemon.species || "Unknown"} <.tier_badge :if={@tier} tier={@tier} species={@pokemon.species} /> <.icon name="hero-arrow-down-tray" class="size-3" /> tier unavailable

Level {@pokemon.level || "?"} · {String.capitalize(@pokemon.form || "default")} form

<%!-- Info Column --%>

Details

<.stat_pill label="Nature" value={@pokemon.nature} /> <.stat_pill label="Ability" value={@pokemon.ability} /> <.stat_pill label="Gender" value={@pokemon.gender} /> <.stat_pill label="Friendship" value={@pokemon.friendship} />
<%!-- Moves --%>

Moves

{format_move(move)}
No moves
<%!-- Stats Column --%>
<%!-- IVs --%>

IVs

<.stat_bar :for={{stat, val} <- stat_list(@pokemon.ivs)} label={format_stat(stat)} value={val} max={31} />
<%!-- EVs --%>

EVs ({ev_total(@pokemon.evs)}/510)

<.stat_bar :for={{stat, val} <- stat_list(@pokemon.evs)} label={format_stat(stat)} value={val} max={252} />
""" end attr :label, :string, required: true attr :value, :any, required: true def stat_pill(assigns) do ~H"""

{@label}

{@value || "—"}

""" end attr :label, :string, required: true attr :value, :integer, required: true attr :max, :integer, required: true def stat_bar(assigns) do pct = if assigns.max > 0, do: min(assigns.value / assigns.max * 100, 100), else: 0 color = cond do pct >= 90 -> "bg-success" pct >= 60 -> "bg-info" pct >= 30 -> "bg-warning" true -> "bg-error/70" end assigns = assign(assigns, pct: pct, color: color) ~H"""
{@label}
{@value}
""" end # --- Type Chart Component --- alias CobblemonUi.TypeChart def type_chart(assigns) do chart = TypeChart.defensive_chart() types = TypeChart.types() assigns = assign(assigns, chart: chart, types: types) ~H"""
<.icon name="hero-table-cells" class="size-5 text-primary/80" />

Type Chart

Weaknesses & Resistances

<.type_chart_card :for={t <- @types} type_name={t} matchups={@chart[t]} />
""" end attr :type_name, :string, required: true attr :matchups, :map, required: true def type_chart_card(assigns) do ~H"""
<%!-- Type icon circle --%>
{@type_name}
<%!-- Weakness / Resistance rows --%>

{@type_name}

<%!-- Weakness row --%>
Weak
<.type_mini_icon :for={t <- @matchups.weak_to} type_name={t} />
<%!-- Resistance row --%>
Resist
<.type_mini_icon :for={t <- @matchups.resists} type_name={t} />
<%!-- Immune row (only if applicable) --%>
Immune
<.type_mini_icon :for={t <- @matchups.immune_to} type_name={t} />
""" end attr :type_name, :string, required: true def type_mini_icon(assigns) do ~H""" {@type_name} """ end # --- Helpers --- defp gender_symbol("male"), do: "♂" defp gender_symbol("female"), do: "♀" defp gender_symbol(_), do: "—" defp gender_color("male"), do: "text-info" defp gender_color("female"), do: "text-error" defp gender_color(_), do: "text-base-content/40" defp format_move(move) when is_binary(move), do: String.replace(move, "_", " ") defp format_move(_), do: "—" defp format_stat(:hp), do: "HP" defp format_stat(:attack), do: "ATK" defp format_stat(:defense), do: "DEF" defp format_stat(:special_attack), do: "SPA" defp format_stat(:special_defense), do: "SPD" defp format_stat(:speed), do: "SPE" defp format_stat(other), do: to_string(other) defp stat_list(stats) when is_map(stats) do [:hp, :attack, :defense, :special_attack, :special_defense, :speed] |> Enum.map(fn key -> {key, Map.get(stats, key, 0)} end) end defp stat_list(_), do: [] defp ev_total(evs) when is_map(evs), do: evs |> Map.values() |> Enum.sum() defp ev_total(_), do: 0 end