defmodule AshHqWeb.Pages.Docs do
use Surface.LiveComponent
alias Phoenix.LiveView.JS
alias AshHqWeb.Components.{CalloutText, DocSidebar, RightNav, Tag}
alias AshHqWeb.Routes
prop params, :map, required: true
prop change_versions, :event, required: true
prop selected_versions, :map, required: true
prop libraries, :list, default: []
prop uri, :string
prop sidebar_state, :map, required: true
prop collapse_sidebar, :event, required: true
prop expand_sidebar, :event, required: true
data library, :any
data extension, :any
data docs, :any
data library_version, :any
data guide, :any
data doc_path, :list, default: []
data dsls, :list, default: []
data dsl, :any
data options, :list, default: []
data module, :any
@spec render(any) :: Phoenix.LiveView.Rendered.t()
def render(assigns) do
~F"""
{#if @doc_path && @doc_path != []}
{#case @doc_path}
{#match [item]}
{item}
{#match path}
{#for item <- :lists.droplast(path)}
{item}
{/for}
{List.last(path)}
{/case}
{/if}
"""
end
defp render_functions(assigns, functions, type) do
~F"""
{#for function <- Enum.filter(functions, &(&1.type == type))}
{function.name}/{function.arity}
{#for head <- function.heads}
{head}
{/for}
{raw(AshHq.Docs.Extensions.RenderMarkdown.render!(function, :doc))}
{/for}
"""
end
def path_to_name(path, name) do
Enum.map_join(path ++ [name], "-", &Routes.sanitize_name/1)
end
defp render_tags(assigns, option) do
~F"""
{#if option.required}
Required
{/if}
"""
end
def show_sidebar() do
%JS{}
|> JS.toggle(
to: "#mobile-sidebar-container",
in: {
"transition ease-in duration-100",
"opacity-0",
"opacity-100"
},
out: {
"transition ease-out duration-75",
"opacity-100",
"opacity-0"
}
)
end
def update(assigns, socket) do
{:ok,
socket
|> assign(assigns)
|> assign_library()
|> assign_extension()
|> assign_guide()
|> assign_module()
|> assign_dsl()
|> assign_docs()}
end
defp assign_guide(socket) do
guide =
if socket.assigns[:params]["guide"] && socket.assigns.library_version do
Enum.find(socket.assigns.library_version.guides, fn guide ->
guide.url_safe_name == socket.assigns[:params]["guide"]
end)
end
assign(socket, :guide, guide)
end
defp assign_dsl(socket) do
case socket.assigns[:params]["dsl_path"] do
nil ->
assign(socket, :dsl, nil)
path ->
dsl =
Enum.find(
socket.assigns.extension.dsls,
fn dsl ->
Enum.map(dsl.path, &Routes.sanitize_name/1) ++ [Routes.sanitize_name(dsl.name)] ==
path
end
)
new_state = Map.put(socket.assigns.sidebar_state, dsl.id, "open")
unless socket.assigns.sidebar_state[dsl.id] == "open" do
send(self(), {:new_sidebar_state, new_state})
end
socket
|> assign(
:dsl,
dsl
)
end
end
defp assign_module(socket) do
if socket.assigns.library && socket.assigns.library_version &&
socket.assigns[:params]["module"] do
module =
Enum.find(
socket.assigns.library_version.modules,
&(Routes.sanitize_name(&1.name) == socket.assigns[:params]["module"])
)
assign(socket,
module: module
)
else
assign(socket, :module, nil)
end
end
defp assign_docs(socket) do
cond do
socket.assigns.module ->
assign(socket,
docs: AshHq.Docs.Extensions.RenderMarkdown.render!(socket.assigns.module, :doc),
doc_path: [socket.assigns.library.name, socket.assigns.module.name],
options: []
)
socket.assigns.dsl ->
assign(socket,
docs: AshHq.Docs.Extensions.RenderMarkdown.render!(socket.assigns.dsl, :doc),
doc_path:
[
socket.assigns.library.name,
socket.assigns.extension.name
] ++ socket.assigns.dsl.path ++ [socket.assigns.dsl.name],
options:
Enum.filter(
socket.assigns.extension.options,
&(&1.path == socket.assigns.dsl.path ++ [socket.assigns.dsl.name])
)
)
socket.assigns.extension ->
assign(socket,
docs: AshHq.Docs.Extensions.RenderMarkdown.render!(socket.assigns.extension, :doc),
doc_path: [socket.assigns.library.name, socket.assigns.extension.name],
options: []
)
socket.assigns.guide ->
assign(socket,
docs: AshHq.Docs.Extensions.RenderMarkdown.render!(socket.assigns.guide, :text),
doc_path: [socket.assigns.library.name, socket.assigns.guide.name],
options: []
)
socket.assigns.library_version ->
assign(socket,
docs:
AshHq.Docs.Extensions.RenderMarkdown.render!(socket.assigns.library_version, :doc),
doc_path: [socket.assigns.library.name],
options: []
)
true ->
assign(socket, docs: "", doc_path: [], dsls: [])
end
end
defp assign_extension(socket) do
if socket.assigns.library && socket.assigns[:params]["extension"] do
extensions = get_extensions(socket.assigns.library, socket.assigns.selected_versions)
assign(socket,
extension:
Enum.find(extensions, fn extension ->
Routes.sanitize_name(extension.name) == socket.assigns[:params]["extension"]
end)
)
else
assign(socket, :extension, nil)
end
end
def mount(socket) do
{:ok, socket}
end
defp get_extensions(library, selected_versions) do
case Enum.find(library.versions, &(&1.id == selected_versions[library.id])) do
nil ->
[]
version ->
version.extensions
end
end
defp assign_library(socket) do
if !socket.assigns[:library] ||
socket.assigns.params["library"] != Routes.sanitize_name(socket.assigns.library.name) do
case Enum.find(
socket.assigns.libraries,
&(Routes.sanitize_name(&1.name) == socket.assigns.params["library"])
) do
nil ->
assign(socket, library: nil, library_version: nil)
library ->
socket =
if socket.assigns[:params]["version"] do
library_version =
Enum.find(
library.versions,
&(Routes.sanitize_name(&1.version) == socket.assigns[:params]["version"])
)
if library_version do
new_selected_versions =
Map.put(socket.assigns.selected_versions, library.id, library_version.id)
assign(
socket,
selected_versions: new_selected_versions,
library_version: library_version
)
|> push_event("selected-versions", new_selected_versions)
else
assign(socket, :library_version, nil)
end
else
assign(socket, :library_version, nil)
end
assign(socket, :library, library)
end
else
socket
end
end
end