defmodule PhilomenaWeb.ProfileView do use PhilomenaWeb, :view def award_order(awards) do Enum.sort_by(awards, &{&1.badge.priority, DateTime.to_unix(&1.awarded_on)}, &>=/2) end def badge_image(badge, options \\ []) do img_tag(badge_url_root() <> "/" <> badge.image, options) end def current?(%{id: id}, %{id: id}), do: true def current?(_user1, _user2), do: false def manages_awards?(conn), do: can?(conn, :create, Philomena.Badges.Award) def manages_links?(conn, user), do: can?(conn, :edit_links, user) def should_see_link?(conn, user, link), do: link.public or can?(conn, :edit, link) or current?(user, conn.assigns.current_user) def link_block_class(%{public: false}), do: "block__content--destroyed" def link_block_class(_link), do: nil def award_title(%{badge_name: nil} = award), do: award.badge.title def award_title(%{badge_name: ""} = award), do: award.badge.title def award_title(award), do: award.badge_name def commission_status(%{open: true}), do: "Open" def commission_status(_commission), do: "Closed" defp sparkline_y(val, max) do # Filter out negative values calc = max(val, 0) # Lerp or 0 if not present height = zero_div(calc * 20, max) # In SVG coords, y grows down 20 - height end def sparkline_data(data, width \\ 375, height \\ 20) do # Normalize range max = max(Enum.max(data), 0) sx = width / 90 sy = height / 20 factor = 100 / 90 content_tag :svg, id: "js-graph-svg", width: "100%", preserveAspectRatio: "xMinYMin", viewBox: "0 0 #{width} #{height}" do first = List.first(data) last = List.last(data) first_y = sparkline_y(first, max) * sy last_y = sparkline_y(last, max) * sy indexed_data = data |> Enum.with_index() points = indexed_data |> Enum.chunk_every(2, 1, :discard) |> Enum.map(fn [{cv, ci}, {nv, ni}] -> cy = sparkline_y(cv, max) ny = sparkline_y(nv, max) "C #{ci * sx + 0.5 * sx},#{cy * sy} #{ni * sx - 0.5 * sx},#{ny * sy} #{ni * sx},#{ny * sy}" end) |> Enum.join("") circles = for {val, i} <- indexed_data do y = sparkline_y(val, max) * sy content_tag :circle, class: "barline__dot", cx: "#{i * factor}%", cy: y * sy + 1.25, r: 2.5 do content_tag(:title, val) end end graph = content_tag(:path, "", id: "js-graph", class: "barline__bar", d: "M0,#{first_y}#{points}L#{width - sx},#{last_y}L#{width - sx},#{height}L0,#{height}L0,#{first_y}" ) [graph, circles] end end def tag_disjunction(tags) do tags |> Enum.map(& &1.name) |> Enum.uniq() |> Enum.join(" || ") end def can_ban?(conn), do: can?(conn, :index, Philomena.Bans.User) def can_index_user?(conn), do: can?(conn, :index, Philomena.Users.User) def can_read_mod_notes?(conn), do: can?(conn, :index, Philomena.ModNotes.ModNote) def enabled_text(true), do: "Enabled" def enabled_text(_else), do: "Disabled" def user_abbrv(%{name: name} = user) do abbrv = String.upcase(initials_abbrv(name) || uppercase_abbrv(name) || first_letters_abbrv(name)) abbrv = "(" <> abbrv <> ")" link(abbrv, to: ~p"/profiles/#{user}") end def user_abbrv(_user), do: content_tag(:span, "(n/a)") defp initials_abbrv(name) do case String.split(name, " ", parts: 4) do [ <>, <>, <>, <> ] -> <> [<>, <>, <>] -> <> [<>, <>] -> <> _ -> nil end end defp uppercase_abbrv(name) do case Regex.scan(~r/([A-Z])/, name, capture: :all_but_first) do [] -> nil list -> list |> Enum.take(4) |> Enum.join() end end defp first_letters_abbrv(name) do String.slice(name, 0, 4) end defp zero_div(_num, 0), do: 0 defp zero_div(num, den), do: div(num, den) defp badge_url_root do Application.get_env(:philomena, :badge_url_root) end end