Files
cobblemon-ui/lib/cobblemon_ui_web/live/battle_components.ex
Alex Mickelson 4a79cc1a38
All checks were successful
Build and Deploy / Build & Push Image (push) Successful in 36s
style upload
2026-03-16 21:27:55 -06:00

102 lines
4.5 KiB
Elixir

defmodule CobblemonUiWeb.BattleComponents do
use CobblemonUiWeb, :html
import CobblemonUiWeb.PokemonComponents, only: [tier_badge: 1]
attr :battle, :map, required: true
attr :player_id, :string, required: true
attr :tier_list, :map, default: %{}
def battle_panel(assigns) do
~H"""
<div class="rounded-xl overflow-hidden mb-6">
<%!-- Actors --%>
<div class="grid grid-cols-1 md:grid-cols-2">
<%= for {actor, idx} <- Enum.with_index(@battle.actors) do %>
<div class={[
"p-4",
if(actor.type == "player", do: "bg-primary/10", else: "bg-warning/10")
]}>
<%!-- Actor header --%>
<div class="flex items-center gap-2 mb-3">
<div class={[
"w-8 h-8 rounded-lg flex items-center justify-center shrink-0",
if(actor.type == "player", do: "bg-primary/20", else: "bg-warning/20")
]}>
<%= if actor.type == "player" do %>
<.icon name="hero-user" class="size-4 text-primary" />
<% else %>
<.icon name="hero-cpu-chip" class="size-4 text-warning" />
<% end %>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-bold text-base-content truncate">{actor.name}</p>
<p class={[
"text-[10px] uppercase font-semibold tracking-widest",
if(actor.type == "player", do: "text-primary/50", else: "text-warning/50")
]}>
{actor.type}
</p>
</div>
<span :if={idx == 0} class="hidden md:block text-xs font-black text-base-content/20">VS</span>
</div>
<%!-- Pokemon cards --%>
<div class="space-y-2">
<%= for poke <- actor.active_pokemon do %>
<% tier = Map.get(@tier_list, String.downcase(poke.species || ""), nil) %>
<% hp_pct = if poke.max_hp > 0, do: Float.round(poke.hp / poke.max_hp * 100, 1), else: 0.0 %>
<div class="flex items-center gap-3 rounded-lg p-2">
<%!-- Sprite with tier badge pinned to corner --%>
<div class="relative w-16 h-16 shrink-0">
<img
src={"https://img.rankedboost.com/wp-content/plugins/k-Pokemon/assets/sprites-official/#{String.downcase(poke.species || "")}.png"}
alt={poke.species}
class="w-16 h-16 object-contain drop-shadow-sm"
/>
<div class="absolute -bottom-1 -right-1">
<.tier_badge :if={tier} tier={tier} species={poke.species} compact={true} />
</div>
</div>
<%!-- Info --%>
<div class="flex-1 min-w-0">
<%!-- Name row --%>
<div class="flex items-center gap-1.5 mb-1.5">
<span class="text-sm font-bold text-base-content capitalize truncate">{poke.species}</span>
<span class="text-[10px] text-base-content/35 font-mono shrink-0">Lv.{poke.level}</span>
</div>
<%!-- HP bar --%>
<div class="w-full h-2 rounded-full bg-base-content/10 overflow-hidden mb-1">
<div
class={[
"h-full rounded-full transition-all duration-500",
cond do
poke.max_hp == 0 -> "bg-base-content/20"
hp_pct > 50 -> "bg-success"
hp_pct > 20 -> "bg-warning"
true -> "bg-error"
end
]}
style={"width: #{hp_pct}%"}
/>
</div>
<%!-- HP numbers --%>
<div class="flex items-center justify-between">
<span class="text-[10px] text-base-content/35 font-medium">HP</span>
<span class="text-[10px] font-mono text-base-content/40">
{poke.hp}/{poke.max_hp}
<span class="text-base-content/25 ml-1">({hp_pct}%)</span>
</span>
</div>
</div>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
"""
end
end