defmodule MemexWeb.CoreComponents do @moduledoc """ Provides core UI components. """ use PhoenixHTMLHelpers use Phoenix.Component use MemexWeb, :verified_routes import MemexWeb.{Gettext, HTMLHelpers} alias Memex.{Accounts, Accounts.Invite, Accounts.User} alias Memex.Contexts.Context alias Memex.Notes.Note alias Memex.Pipelines.{Pipeline, Steps.Step} alias Phoenix.HTML alias Phoenix.LiveView.JS embed_templates("core_components/*") attr :title_content, :string, default: nil attr :current_user, User, default: nil def topbar(assigns) attr :return_to, :string, required: true slot(:inner_block) @doc """ Renders a live component inside a modal. The rendered modal receives a `:return_to` option to properly update the URL when the modal is closed. ## Examples <.modal return_to={~p"/\#{<%= schema.plural %>}"}> <.live_component module={<%= inspect context.web_module %>.<%= inspect Module.concat(schema.web_namespace, schema.alias) %>Live.FormComponent} id={@<%= schema.singular %>.id || :new} title={@page_title} action={@live_action} return_to={~p"/\#{<%= schema.singular %>}"} <%= schema.singular %>: @<%= schema.singular %> /> """ def modal(assigns) defp hide_modal(js \\ %JS{}) do js |> JS.hide(to: "#modal", transition: "fade-out") |> JS.hide(to: "#modal-bg", transition: "fade-out") |> JS.hide(to: "#modal-content", transition: "fade-out-scale") end attr :action, :string, required: true attr :value, :boolean, required: true attr :id, :string, default: nil slot(:inner_block) @doc """ A toggle button element that can be directed to a liveview or a live_component's `handle_event/3`. ## Examples <.toggle_button action="my_liveview_action" value={@some_value}> Toggle me! <.toggle_button action="my_live_component_action" target={@myself} value={@some_value}> Whatever you want """ def toggle_button(assigns) attr :user, User, required: true slot(:inner_block, required: true) def user_card(assigns) attr :invite, Invite, required: true attr :use_count, :integer, default: nil attr :current_user, User, required: true slot(:inner_block) slot(:code_actions) def invite_card(assigns) attr :id, :string, required: true attr :datetime, :any, required: true, doc: "A `DateTime` struct or nil" @doc """ Phoenix.Component for a
#{link}" end ) end # replaces triple links like [[[slug-title]]] defp replace_triple_links(content, _record) do Regex.replace( ~r/(^|[^\[])\[\[\[([\p{L}\p{N}\-]+)\]\]\]($|[^\]])/, content, fn _whole_match, prefix, slug, suffix -> link = link( "[[[#{slug}]]]", to: ~p"/note/#{slug}", class: "link inline" ) |> HTML.Safe.to_iodata() |> IO.iodata_to_binary() "#{prefix}
#{link}#{suffix}" end ) end # replaces double links like [[slug-title]] defp replace_double_links(content, record) do Regex.replace( ~r/(^|[^\[])\[\[([\p{L}\p{N}\-]+)\]\]($|[^\]])/, content, fn _whole_match, prefix, slug, suffix -> target = case record do %Pipeline{} -> ~p"/context/#{slug}" %Step{} -> ~p"/context/#{slug}" _context -> ~p"/note/#{slug}" end link = link( "[[#{slug}]]", to: target, class: "link inline" ) |> HTML.Safe.to_iodata() |> IO.iodata_to_binary() "#{prefix}
#{link}#{suffix}" end ) end # replaces single links like [slug-title] defp replace_single_links(content, record) do Regex.replace( ~r/(^|[^\[])\[([\p{L}\p{N}\-]+)\]($|[^\]])/, content, fn _whole_match, prefix, slug, suffix -> target = case record do %Pipeline{} -> ~p"/pipeline/#{slug}" %Step{} -> ~p"/pipeline/#{slug}" %Context{} -> ~p"/context/#{slug}" _note -> ~p"/note/#{slug}" end link = link( "[#{slug}]", to: target, class: "link inline" ) |> HTML.Safe.to_iodata() |> IO.iodata_to_binary() "#{prefix}
#{link}#{suffix}" end ) end end