defmodule BDS.Desktop.ShellLive.SidebarComponents do @moduledoc false use Phoenix.Component alias BDS.Desktop.ShellData alias BDS.Desktop.UILocale alias BDS.UI.Registry def sidebar_content(assigns) do UILocale.put(assigns.page_language) assigns = prepare_filter_assigns(assigns) ~H""" <%= render_sidebar_filters(assigns) %> <%= render_sidebar_body(assigns) %> <%= render_sidebar_load_more(assigns) %> """ end def filters_enabled?(sidebar_data) do sidebar_data |> Map.get(:filters) |> then(&(is_map(&1) and Map.get(&1, :enabled, false))) end def filters_visible?(sidebar_data) do sidebar_data |> Map.get(:filters, %{}) |> Map.get(:filter_panel_visible, false) end defp prepare_filter_assigns(assigns) do filters = Map.get(assigns.sidebar_data, :filters) if is_map(filters) and Map.get(filters, :enabled) do selected = Map.get(filters, :selected, %{}) assigns |> assign(:sidebar_filters_config, filters) |> assign(:selected_filters, selected) |> assign(:filter_panel_visible, Map.get(filters, :filter_panel_visible, false)) |> assign(:archive_collapsed, Map.get(filters, :archive_collapsed, true)) |> assign(:tags_collapsed, Map.get(filters, :tags_collapsed, true)) |> assign(:categories_collapsed, Map.get(filters, :categories_collapsed, true)) |> assign(:expanded_year, Map.get(filters, :expanded_year)) |> assign(:year_groups, group_year_month_counts(Map.get(filters, :year_month_counts, []))) else assigns end end defp render_sidebar_filters(assigns) do filters = Map.get(assigns.sidebar_data, :filters) if is_map(filters) and Map.get(filters, :enabled) do ~H""" <%= if Map.get(@sidebar_filters_config, :has_active_filters) do %>
<%= translated(@sidebar_filters_config.results_label) %>: <%= @sidebar_filters_config.loaded_count %>/<%= @sidebar_filters_config.total_count %>
<% end %> <%= if @filter_panel_visible do %> <%= if Enum.any?(@year_groups) do %>
<%= if @archive_collapsed, do: "▶", else: "▼" %> <%= translated(@sidebar_filters_config.archive_label) %> <%= if Map.get(@selected_filters, :year) do %> <% end %>
<%= unless @archive_collapsed do %>
<%= for year_group <- @year_groups do %>
<%= if @expanded_year == year_group.year, do: "▼", else: "▶" %> <%= year_group.year %> <%= year_group.count %>
<%= if @expanded_year == year_group.year do %>
<%= for month_entry <- year_group.months do %> <% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= if Enum.any?(Map.get(@sidebar_filters_config, :available_tags, [])) do %>
<%= if @tags_collapsed, do: "▶", else: "▼" %> <%= translated(@sidebar_filters_config.tags_label) %> <%= if Enum.any?(Map.get(@selected_filters, :tags, [])) do %> <% end %>
<%= unless @tags_collapsed do %>
<%= for tag <- Map.get(@sidebar_filters_config, :available_tags, []) do %> <% end %>
<% end %>
<% end %> <%= if Enum.any?(Map.get(@sidebar_filters_config, :available_categories, [])) do %>
<%= if @categories_collapsed, do: "▶", else: "▼" %> <%= translated(@sidebar_filters_config.categories_label) %> <%= if Enum.any?(Map.get(@selected_filters, :categories, [])) do %> <% end %>
<%= unless @categories_collapsed do %>
<%= for category <- Map.get(@sidebar_filters_config, :available_categories, []) do %> <% end %>
<% end %>
<% end %>
<% end %> """ else ~H""" """ end end defp render_sidebar_load_more(assigns) do filters = Map.get(assigns.sidebar_data, :filters, %{}) if Map.get(filters, :has_more) do ~H""" """ else ~H""" """ end end defp render_sidebar_body(assigns) do case assigns.sidebar_data.layout do "post_list" -> render_post_sidebar(assigns) "media_grid" -> render_media_sidebar(assigns) "entity_list" -> render_entity_sidebar(assigns) "nav_list" -> render_nav_sidebar(assigns) _other -> render_default_sidebar(assigns) end end defp render_post_sidebar(assigns) do ~H""" <%= for section <- Map.get(@sidebar_data, :sections, []) do %> <% end %> <%= if Enum.empty?(Map.get(@sidebar_data, :sections, [])) do %> <% end %> """ end defp render_media_sidebar(assigns) do ~H""" <%= if Enum.any?(Map.get(@sidebar_data, :items, [])) do %> <% else %> <% end %> """ end defp render_entity_sidebar(assigns) do ~H""" <%= if Enum.any?(Map.get(@sidebar_data, :items, [])) do %>
<%= for item <- Map.get(@sidebar_data, :items, []) do %> <%= if item.route in ["templates", "chat"] do %>
<% else %> <% end %> <% end %>
<% else %> <% end %> """ end defp render_nav_sidebar(assigns) do ~H"""
<%= for item <- Map.get(@sidebar_data, :items, []) do %> <% end %>
""" end defp render_default_sidebar(assigns) do ~H""" <%= for section <- Map.get(@sidebar_data, :sections, []) do %> <% end %> """ end defp translated(text, bindings \\ %{}), do: ShellData.translate(text, bindings, BDS.Desktop.UILocale.current()) defp template_sidebar?(sidebar_data), do: Map.get(sidebar_data, :title) == "Templates" defp group_year_month_counts(entries) do entries |> Enum.group_by(& &1.year) |> Enum.map(fn {year, months} -> %{ year: year, count: Enum.reduce(months, 0, fn entry, acc -> acc + (entry.count || 0) end), months: Enum.sort_by(months, &(-&1.month)) } end) |> Enum.sort_by(&(-&1.year)) end defp sidebar_filter_tag_color(filters_config, tag) do filters_config |> Map.get(:available_tag_colors, %{}) |> Map.get(tag) |> normalize_sidebar_filter_color() end defp sidebar_filter_chip_style(filters_config, tag) do case sidebar_filter_tag_color(filters_config, tag) do nil -> nil color -> "background-color: #{color}; color: #{sidebar_filter_contrast_color(color)}; border-color: #{color};" end end defp normalize_sidebar_filter_color(nil), do: nil defp normalize_sidebar_filter_color(""), do: nil defp normalize_sidebar_filter_color("#" <> rest = color) when byte_size(rest) == 6 do if String.match?(rest, ~r/\A[0-9a-fA-F]{6}\z/), do: color, else: nil end defp normalize_sidebar_filter_color(_color), do: nil defp sidebar_filter_contrast_color("#" <> rgb) do <> = rgb {red, _} = Integer.parse(r, 16) {green, _} = Integer.parse(g, 16) {blue, _} = Integer.parse(b, 16) luminance = (red * 299 + green * 587 + blue * 114) / 1000 if luminance > 150, do: "#1e1e1e", else: "#ffffff" end defp sidebar_filter_contrast_color(_color), do: "#ffffff" defp format_sidebar_timestamp(nil), do: "" defp format_sidebar_timestamp(timestamp) do timestamp |> DateTime.from_unix!(:millisecond) |> Calendar.strftime("%x") end defp image_media?(item), do: String.starts_with?(to_string(item.mime_type || ""), "image/") defp media_thumbnail_class(item) do if image_media?(item), do: "media-thumbnail has-image", else: "media-thumbnail" end defp media_thumbnail_glyph(mime_type) do case String.split(to_string(mime_type || ""), "/", parts: 2) do ["image", _rest] -> "IMG" ["video", _rest] -> "VID" ["audio", _rest] -> "AUD" ["application", _rest] -> "DOC" _other -> "FILE" end end defp sidebar_item_selected?(workbench, route, id) do route_atom = sidebar_route_atom(route) workbench.active_tab == {route_atom, tab_id_for_route(route_atom, id)} end defp sidebar_route_atom(route) when is_atom(route), do: route defp sidebar_route_atom(route) when is_binary(route), do: BDS.BoundedAtoms.editor_route(route, :dashboard) defp tab_id_for_route(route, id) do case Registry.editor_route(route) do %{singleton: true} -> Atom.to_string(route) _other -> id end end end