feat: some refactoring to make shell_live smaller
This commit is contained in:
286
lib/bds/desktop/shell_live/overlay_components.ex
Normal file
286
lib/bds/desktop/shell_live/overlay_components.ex
Normal file
@@ -0,0 +1,286 @@
|
||||
defmodule BDS.Desktop.ShellLive.OverlayComponents do
|
||||
@moduledoc false
|
||||
|
||||
use Phoenix.Component
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
alias BDS.Desktop.ShellData
|
||||
alias BDS.{I18n, Metadata, Repo}
|
||||
alias BDS.Media.Media
|
||||
alias BDS.Posts.{Post, Translation}
|
||||
alias BDS.Tags.Tag
|
||||
|
||||
embed_templates "overlay_html/*"
|
||||
|
||||
def context(assigns, tab_title, tab_subtitle) do
|
||||
project_id = assigns.projects.active_project_id
|
||||
metadata = project_metadata(project_id)
|
||||
current_tab = assigns.current_tab
|
||||
page_language = assigns.page_language
|
||||
posts = posts(project_id)
|
||||
media = media(project_id)
|
||||
|
||||
%{
|
||||
current_tab: %{type: current_tab.type, id: current_tab.id, title: tab_title, subtitle: tab_subtitle},
|
||||
current_post_language: source_language(current_tab, metadata),
|
||||
current_media_language: source_language(current_tab, metadata),
|
||||
posts: posts,
|
||||
media: media,
|
||||
post_media_ids: post_media_ids(current_tab),
|
||||
blog_languages: blog_languages(metadata),
|
||||
language_names: language_names(),
|
||||
language_flags: language_flags(),
|
||||
existing_translations: existing_translations(current_tab),
|
||||
ai_title: ShellData.translate("AI Suggestions", %{}, page_language),
|
||||
insert_link_title: ShellData.translate("Insert Link", %{}, page_language),
|
||||
insert_media_title: ShellData.translate("Insert Media", %{}, page_language),
|
||||
language_picker_title: ShellData.translate("Translate", %{}, page_language),
|
||||
gallery_title: tab_title,
|
||||
ai_fields: ai_fields(current_tab, tab_title, tab_subtitle, page_language),
|
||||
delete_details: delete_details(current_tab, page_language),
|
||||
merge_details: merge_details(project_id, page_language)
|
||||
}
|
||||
end
|
||||
|
||||
def kind("ai_suggestions"), do: :ai_suggestions
|
||||
def kind("insert_link"), do: :insert_link
|
||||
def kind("insert_media"), do: :insert_media
|
||||
def kind("language_picker"), do: :language_picker
|
||||
def kind("confirm_delete"), do: :confirm_delete
|
||||
def kind("confirm_merge"), do: :confirm_merge
|
||||
def kind("gallery"), do: :gallery
|
||||
def kind(_kind), do: nil
|
||||
|
||||
def tab("internal"), do: :internal
|
||||
def tab("external"), do: :external
|
||||
def tab(_tab), do: :internal
|
||||
|
||||
def markdown_link(text, url), do: "[#{text}](#{url})"
|
||||
|
||||
def translated(text, bindings \\ %{}), do: ShellData.translate(text, bindings, Process.get(:bds_ui_locale))
|
||||
|
||||
def project_metadata(nil), do: %{main_language: "en", blog_languages: []}
|
||||
|
||||
def project_metadata(project_id) do
|
||||
{:ok, metadata} = Metadata.get_project_metadata(project_id)
|
||||
metadata
|
||||
rescue
|
||||
_error -> %{main_language: "en", blog_languages: []}
|
||||
end
|
||||
|
||||
defp posts(nil), do: []
|
||||
|
||||
defp posts(project_id) do
|
||||
Repo.all(
|
||||
from post in Post,
|
||||
where: post.project_id == ^project_id,
|
||||
order_by: [desc: post.updated_at, desc: post.created_at],
|
||||
select: %{id: post.id, title: post.title, slug: post.slug, status: post.status, published_at: post.published_at, updated_at: post.updated_at, language: post.language}
|
||||
)
|
||||
|> Enum.map(fn post ->
|
||||
%{
|
||||
id: post.id,
|
||||
title: post.title || post.slug || post.id,
|
||||
status: Atom.to_string(post.status || :draft),
|
||||
canonical_url: canonical_post_url(post)
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
defp media(nil), do: []
|
||||
|
||||
defp media(project_id) do
|
||||
Repo.all(
|
||||
from media in Media,
|
||||
where: media.project_id == ^project_id,
|
||||
order_by: [desc: media.updated_at, desc: media.created_at],
|
||||
select: %{id: media.id, title: media.title, original_name: media.original_name, mime_type: media.mime_type, alt: media.alt, caption: media.caption}
|
||||
)
|
||||
|> Enum.map(fn media ->
|
||||
%{
|
||||
id: media.id,
|
||||
title: media.title || media.original_name || media.id,
|
||||
original_name: media.original_name || media.id,
|
||||
is_image: String.starts_with?(to_string(media.mime_type || ""), "image/"),
|
||||
thumbnail_url: "/media-thumbnail/#{media.id}",
|
||||
image_url: "/media-thumbnail/#{media.id}?size=large",
|
||||
alt_text: media.alt || media.caption || media.title
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
defp post_media_ids(%{type: :post, id: post_id}) do
|
||||
case Repo.query("SELECT media_id FROM post_media WHERE post_id = ? ORDER BY sort_order ASC, media_id ASC", [post_id]) do
|
||||
{:ok, %{rows: rows}} -> Enum.map(rows, fn [media_id] -> media_id end)
|
||||
_other -> []
|
||||
end
|
||||
rescue
|
||||
_error -> []
|
||||
end
|
||||
|
||||
defp post_media_ids(_tab), do: []
|
||||
|
||||
defp existing_translations(%{type: :post, id: post_id}) do
|
||||
Repo.all(
|
||||
from translation in Translation,
|
||||
where: translation.translation_for == ^post_id,
|
||||
select: {translation.language, translation.status}
|
||||
)
|
||||
|> Map.new(fn {language, status} -> {language, Atom.to_string(status || :draft)} end)
|
||||
rescue
|
||||
_error -> %{}
|
||||
end
|
||||
|
||||
defp existing_translations(_tab), do: %{}
|
||||
|
||||
defp blog_languages(metadata) do
|
||||
([metadata.main_language || "en"] ++ (metadata.blog_languages || []))
|
||||
|> Enum.reject(&is_nil/1)
|
||||
|> Enum.uniq()
|
||||
end
|
||||
|
||||
defp source_language(%{type: :post, id: post_id}, metadata) do
|
||||
case Repo.get(Post, post_id) do
|
||||
%Post{language: language} when is_binary(language) and language != "" -> language
|
||||
_other -> metadata.main_language || "en"
|
||||
end
|
||||
rescue
|
||||
_error -> metadata.main_language || "en"
|
||||
end
|
||||
|
||||
defp source_language(_tab, metadata), do: metadata.main_language || "en"
|
||||
|
||||
defp language_names do
|
||||
%{
|
||||
"en" => "English",
|
||||
"de" => "Deutsch",
|
||||
"fr" => "Francais",
|
||||
"it" => "Italiano",
|
||||
"es" => "Espanol"
|
||||
}
|
||||
end
|
||||
|
||||
defp language_flags do
|
||||
I18n.supported_languages()
|
||||
|> Enum.into(%{}, fn language -> {language.code, I18n.flag(language.code)} end)
|
||||
end
|
||||
|
||||
defp ai_fields(%{type: :post, id: post_id}, title, subtitle, page_language) do
|
||||
case Repo.get(Post, post_id) do
|
||||
%Post{} = post ->
|
||||
[
|
||||
%{key: "title", label: ShellData.translate("Title", %{}, page_language), current_value: post.title || title, suggested_value: refine_title(post.title || title), locked: false},
|
||||
%{key: "excerpt", label: ShellData.translate("Excerpt", %{}, page_language), current_value: post.excerpt || subtitle, suggested_value: refine_excerpt(post.title || title, post.excerpt || subtitle), locked: false},
|
||||
%{key: "slug", label: ShellData.translate("Slug", %{}, page_language), current_value: post.slug || slugify(post.title || title), suggested_value: refine_slug(post.slug || slugify(post.title || title)), locked: post.status == :published}
|
||||
]
|
||||
|
||||
_other ->
|
||||
[]
|
||||
end
|
||||
rescue
|
||||
_error -> []
|
||||
end
|
||||
|
||||
defp ai_fields(%{type: :media, id: media_id}, title, _subtitle, page_language) do
|
||||
case Repo.get(Media, media_id) do
|
||||
%Media{} = media ->
|
||||
[
|
||||
%{key: "title", label: ShellData.translate("Title", %{}, page_language), current_value: media.title || title, suggested_value: refine_title(media.title || title), locked: false},
|
||||
%{key: "alt", label: ShellData.translate("Alt Text", %{}, page_language), current_value: media.alt || "", suggested_value: media.alt || title, locked: false},
|
||||
%{key: "caption", label: ShellData.translate("Caption", %{}, page_language), current_value: media.caption || "", suggested_value: refine_excerpt(title, media.caption || title), locked: false}
|
||||
]
|
||||
|
||||
_other ->
|
||||
[]
|
||||
end
|
||||
rescue
|
||||
_error -> []
|
||||
end
|
||||
|
||||
defp ai_fields(_tab, _title, _subtitle, _page_language), do: []
|
||||
|
||||
defp delete_details(%{type: :media, id: media_id}, page_language) do
|
||||
entity_name =
|
||||
case Repo.get(Media, media_id) do
|
||||
%Media{} = media -> media.title || media.original_name || media.id
|
||||
_other -> media_id
|
||||
end
|
||||
|
||||
reference_list =
|
||||
case Repo.query("SELECT posts.title FROM posts JOIN post_media ON posts.id = post_media.post_id WHERE post_media.media_id = ? ORDER BY post_media.sort_order ASC, posts.updated_at DESC", [media_id]) do
|
||||
{:ok, %{rows: rows}} -> Enum.map(rows, fn [title] -> title || media_id end)
|
||||
_other -> []
|
||||
end
|
||||
|
||||
%{
|
||||
title: ShellData.translate("Delete Media", %{}, page_language),
|
||||
entity_name: entity_name,
|
||||
entity_type: "media",
|
||||
reference_list: reference_list
|
||||
}
|
||||
rescue
|
||||
_error -> %{title: ShellData.translate("Delete Media", %{}, page_language), entity_name: media_id, entity_type: "media", reference_list: []}
|
||||
end
|
||||
|
||||
defp delete_details(%{type: :tags}, page_language) do
|
||||
tag_name =
|
||||
Repo.one(from tag in Tag, order_by: [asc: tag.name], limit: 1, select: tag.name)
|
||||
|> Kernel.||("tag")
|
||||
|
||||
%{
|
||||
title: ShellData.translate("Delete Tag", %{}, page_language),
|
||||
entity_name: tag_name,
|
||||
entity_type: "tag",
|
||||
reference_list: []
|
||||
}
|
||||
rescue
|
||||
_error -> %{title: ShellData.translate("Delete Tag", %{}, page_language), entity_name: "tag", entity_type: "tag", reference_list: []}
|
||||
end
|
||||
|
||||
defp delete_details(_tab, page_language) do
|
||||
%{title: ShellData.translate("Delete", %{}, page_language), entity_name: "", entity_type: "item", reference_list: []}
|
||||
end
|
||||
|
||||
defp merge_details(project_id, page_language) do
|
||||
tags =
|
||||
Repo.all(from tag in Tag, where: tag.project_id == ^project_id, order_by: [asc: tag.name], limit: 3, select: tag.name)
|
||||
|
||||
target = List.first(tags) || "tag"
|
||||
|
||||
%{
|
||||
target: target,
|
||||
count: max(length(tags), 1),
|
||||
title: ShellData.translate("Merge Tags", %{}, page_language),
|
||||
message: ShellData.translate("Cannot be undone.", %{}, page_language)
|
||||
}
|
||||
rescue
|
||||
_error -> %{target: "tag", count: 1, title: ShellData.translate("Merge Tags", %{}, page_language), message: ShellData.translate("Cannot be undone.", %{}, page_language)}
|
||||
end
|
||||
|
||||
defp canonical_post_url(post) do
|
||||
timestamp = post.published_at || post.updated_at || System.system_time(:millisecond)
|
||||
date = DateTime.from_unix!(timestamp, :millisecond)
|
||||
"/#{date.year}/#{pad2(date.month)}/#{pad2(date.day)}/#{post.slug || post.id}"
|
||||
end
|
||||
|
||||
defp pad2(value), do: value |> Integer.to_string() |> String.pad_leading(2, "0")
|
||||
|
||||
defp refine_title(nil), do: ""
|
||||
defp refine_title(title), do: String.trim(title <> " Notes")
|
||||
|
||||
defp refine_excerpt(title, excerpt) do
|
||||
base = excerpt |> to_string() |> String.trim()
|
||||
if base == "", do: "#{title} overview", else: base <> "."
|
||||
end
|
||||
|
||||
defp refine_slug(slug), do: slug |> to_string() |> String.trim_trailing("-") |> Kernel.<>("-updated")
|
||||
|
||||
defp slugify(value) do
|
||||
value
|
||||
|> to_string()
|
||||
|> String.downcase()
|
||||
|> String.replace(~r/[^a-z0-9]+/u, "-")
|
||||
|> String.trim("-")
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user