2022-03-28 10:26:35 +13:00
|
|
|
defmodule AshHqWeb.Pages.Docs do
|
2022-08-07 11:22:58 +12:00
|
|
|
@moduledoc "The page for showing documentation"
|
2022-08-04 01:53:59 +12:00
|
|
|
use Surface.Component
|
2022-03-28 10:26:35 +13:00
|
|
|
|
2022-04-01 05:36:44 +13:00
|
|
|
alias AshHqWeb.Components.{CalloutText, DocSidebar, RightNav, Tag}
|
2022-08-07 11:22:58 +12:00
|
|
|
alias AshHqWeb.DocRoutes
|
|
|
|
alias Phoenix.LiveView.JS
|
2022-06-06 06:03:45 +12:00
|
|
|
require Logger
|
2022-03-28 10:26:35 +13:00
|
|
|
|
2022-08-31 20:11:15 +12:00
|
|
|
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)
|
|
|
|
|
|
|
|
prop(library, :any)
|
|
|
|
prop(extension, :any)
|
|
|
|
prop(docs, :any)
|
|
|
|
prop(library_version, :any)
|
|
|
|
prop(guide, :any)
|
|
|
|
prop(doc_path, :list, default: [])
|
|
|
|
prop(dsls, :list, default: [])
|
|
|
|
prop(dsl, :any)
|
|
|
|
prop(options, :list, default: [])
|
|
|
|
prop(module, :any)
|
|
|
|
prop(remove_version, :event)
|
|
|
|
prop(add_version, :event)
|
|
|
|
prop(change_version, :event)
|
|
|
|
|
|
|
|
data(positional_options, :list)
|
2022-08-29 00:42:24 +12:00
|
|
|
|
2022-03-28 10:26:35 +13:00
|
|
|
@spec render(any) :: Phoenix.LiveView.Rendered.t()
|
|
|
|
def render(assigns) do
|
|
|
|
~F"""
|
2022-09-08 09:03:48 +12:00
|
|
|
<div class="flex flex-col xl:flex-row justify-center overflow-hidden w-screen h-screen pb-12">
|
|
|
|
<div class="xl:hidden flex flex-row justify-start w-full space-x-12 items-center border-b border-t border-gray-600 py-3">
|
2022-03-29 11:05:19 +13:00
|
|
|
<button class="dark:hover:text-gray-600" phx-click={show_sidebar()}>
|
|
|
|
<Heroicons.Outline.MenuIcon class="w-8 h-8 ml-4" />
|
|
|
|
</button>
|
|
|
|
{#if @doc_path && @doc_path != []}
|
|
|
|
<div class="flex flex-row space-x-1 items-center">
|
|
|
|
{#case @doc_path}
|
|
|
|
{#match [item]}
|
|
|
|
<div class="dark:text-white">
|
|
|
|
{item}
|
|
|
|
</div>
|
|
|
|
{#match path}
|
|
|
|
{#for item <- :lists.droplast(path)}
|
2022-03-30 05:12:28 +13:00
|
|
|
<span class="text-gray-400">
|
|
|
|
{item}
|
|
|
|
</span>
|
2022-03-29 11:05:19 +13:00
|
|
|
<Heroicons.Outline.ChevronRightIcon class="w-3 h-3" />
|
|
|
|
{/for}
|
2022-03-30 05:12:28 +13:00
|
|
|
<span class="dark:text-white">
|
2022-03-30 17:40:17 +13:00
|
|
|
<CalloutText>{List.last(path)}</CalloutText>
|
2022-03-30 05:12:28 +13:00
|
|
|
</span>
|
2022-03-29 11:05:19 +13:00
|
|
|
{/case}
|
|
|
|
</div>
|
|
|
|
{/if}
|
|
|
|
</div>
|
2022-08-31 20:11:15 +12:00
|
|
|
<span class="grid overflow-hidden xl:hidden z-40">
|
|
|
|
<div id="mobile-sidebar-container" class="overflow-hidden hidden fixed w-min h-full transition">
|
2022-03-30 05:12:28 +13:00
|
|
|
<DocSidebar
|
|
|
|
id="mobile-sidebar"
|
2022-08-31 20:11:15 +12:00
|
|
|
change_version={@change_version}
|
|
|
|
add_version={@add_version}
|
|
|
|
remove_version={@remove_version}
|
2022-03-30 05:12:28 +13:00
|
|
|
libraries={@libraries}
|
|
|
|
extension={@extension}
|
2022-04-01 19:43:09 +13:00
|
|
|
sidebar_state={@sidebar_state}
|
|
|
|
collapse_sidebar={@collapse_sidebar}
|
|
|
|
expand_sidebar={@expand_sidebar}
|
2022-03-30 17:40:17 +13:00
|
|
|
module={@module}
|
2022-03-30 05:12:28 +13:00
|
|
|
guide={@guide}
|
|
|
|
library={@library}
|
|
|
|
library_version={@library_version}
|
|
|
|
selected_versions={@selected_versions}
|
2022-03-30 17:40:17 +13:00
|
|
|
dsl={@dsl}
|
2022-03-30 05:12:28 +13:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</span>
|
2022-09-08 15:02:18 +12:00
|
|
|
<div class="grow w-screen overflow-hidden flex flex-row max-w-[1800px] h-full justify-between md:space-x-12 bg-white dark:bg-base-dark-900">
|
2022-09-08 09:03:48 +12:00
|
|
|
<div class="xl:border-r lg:pr-2 lg:pt-14">
|
2022-09-08 02:48:10 +12:00
|
|
|
<DocSidebar
|
|
|
|
id="sidebar"
|
|
|
|
class="hidden xl:block w-80 overflow-x-hidden custom-scrollbar"
|
|
|
|
change_version={@change_version}
|
|
|
|
add_version={@add_version}
|
|
|
|
remove_version={@remove_version}
|
|
|
|
module={@module}
|
|
|
|
libraries={@libraries}
|
|
|
|
extension={@extension}
|
|
|
|
sidebar_state={@sidebar_state}
|
|
|
|
collapse_sidebar={@collapse_sidebar}
|
|
|
|
expand_sidebar={@expand_sidebar}
|
|
|
|
guide={@guide}
|
|
|
|
library={@library}
|
|
|
|
library_version={@library_version}
|
|
|
|
selected_versions={@selected_versions}
|
|
|
|
dsl={@dsl}
|
|
|
|
/>
|
|
|
|
</div>
|
2022-03-30 05:12:28 +13:00
|
|
|
<div
|
|
|
|
id="docs-window"
|
2022-09-08 15:02:18 +12:00
|
|
|
class="w-full prose prose-xl max-w-4xl dark:bg-base-dark-900 dark:prose-invert overflow-y-auto overflow-x-visible md:pr-8 md:mt-14 px-4 md:px-auto custom-scrollbar"
|
2022-03-30 05:12:28 +13:00
|
|
|
phx-hook="Docs"
|
|
|
|
>
|
2022-09-06 07:57:35 +12:00
|
|
|
<div id="module-docs" class="w-full nav-anchor text-black dark:text-white relative py-4 md:py-auto">
|
2022-07-15 07:09:04 +12:00
|
|
|
{#if @module}
|
|
|
|
<h2>{@module.name}{render_source_code_link(assigns, @module, @library, @library_version)}</h2>
|
|
|
|
{/if}
|
2022-08-05 05:14:58 +12:00
|
|
|
{#if @library_version}
|
2022-08-31 07:08:23 +12:00
|
|
|
<div class="static mb-6 md:absolute right-2 top-2 border rounded-lg flex flex-row w-fit">
|
2022-09-08 15:02:18 +12:00
|
|
|
<div class="border-r pl-2 pr-2 dark:text-black bg-primary-light-600 dark:bg-primary-dark-600 rounded-l-lg">
|
2022-08-05 05:14:58 +12:00
|
|
|
{@library.name}
|
|
|
|
</div>
|
|
|
|
<div class="pl-2 pr-2 rounded-r-lg bg-gray-300 dark:bg-inherit">
|
|
|
|
{@library_version.version}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{/if}
|
2022-06-08 08:37:34 +12:00
|
|
|
{raw(render_replacements(assigns, @docs))}
|
2022-07-15 07:09:04 +12:00
|
|
|
{#if @dsl}
|
|
|
|
{#for {category, links} <- @dsl.links || %{}}
|
2022-07-26 13:24:43 +12:00
|
|
|
<h3>{String.capitalize(category)}</h3>
|
|
|
|
<ul>
|
|
|
|
{#for link <- links}
|
|
|
|
<li>
|
|
|
|
{raw(render_links("{{link:#{link}}}", assigns))}
|
|
|
|
</li>
|
|
|
|
{/for}
|
|
|
|
</ul>
|
2022-07-15 07:09:04 +12:00
|
|
|
{/for}
|
|
|
|
{/if}
|
2022-04-01 09:59:53 +13:00
|
|
|
</div>
|
2022-03-30 17:40:17 +13:00
|
|
|
{#if @module}
|
2022-07-15 07:09:04 +12:00
|
|
|
{render_functions(assigns, @module.functions, :callback, "Callbacks")}
|
|
|
|
{render_functions(assigns, @module.functions, :function, "Functions")}
|
|
|
|
{render_functions(assigns, @module.functions, :macro, "Macros")}
|
2022-03-30 17:40:17 +13:00
|
|
|
{/if}
|
2022-07-15 07:09:04 +12:00
|
|
|
{#case modules_in_scope(@dsl, @extension, @libraries, @selected_versions)}
|
|
|
|
{#match []}
|
|
|
|
{#match imports}
|
|
|
|
<h3>Imported Modules</h3>
|
|
|
|
{#for mod <- imports}
|
|
|
|
<ul>
|
|
|
|
<li>
|
2022-08-07 11:22:58 +12:00
|
|
|
<a href={DocRoutes.doc_link(mod, @selected_versions)}>{mod.name}</a>
|
2022-07-15 07:09:04 +12:00
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
{/for}
|
|
|
|
{/case}
|
|
|
|
{#case child_dsls(@extension, @dsl)}
|
|
|
|
{#match []}
|
|
|
|
{#match children}
|
2022-07-28 07:57:39 +12:00
|
|
|
<h3>
|
|
|
|
Nested DSLs
|
|
|
|
</h3>
|
|
|
|
<ul>
|
|
|
|
{#for child <- children}
|
|
|
|
<li>
|
2022-08-07 11:22:58 +12:00
|
|
|
<a href={DocRoutes.doc_link(child, @selected_versions)}>{child.name}</a>
|
2022-07-28 07:57:39 +12:00
|
|
|
</li>
|
|
|
|
{/for}
|
|
|
|
</ul>
|
2022-07-15 07:09:04 +12:00
|
|
|
{/case}
|
|
|
|
<div class="ml-2">
|
2022-07-28 07:57:39 +12:00
|
|
|
<table>
|
|
|
|
{#if !Enum.empty?(@options)}
|
|
|
|
{#if Enum.any?(@options, & &1.argument_index)}
|
|
|
|
<td colspan="100%">
|
|
|
|
<h3>
|
|
|
|
Arguments
|
|
|
|
</h3>
|
|
|
|
</td>
|
2022-07-26 13:24:43 +12:00
|
|
|
<tr>
|
|
|
|
<th>Name</th>
|
|
|
|
<th>Type</th>
|
|
|
|
<th>Doc</th>
|
|
|
|
<th>Links</th>
|
|
|
|
</tr>
|
2022-07-15 07:09:04 +12:00
|
|
|
{#for option <- positional_options(@options)}
|
2022-08-04 01:53:59 +12:00
|
|
|
<tr id={option.sanitized_path}>
|
2022-07-15 07:09:04 +12:00
|
|
|
<td>
|
|
|
|
<div class="flex flex-row items-baseline">
|
2022-08-29 00:42:24 +12:00
|
|
|
<a href={"##{DocRoutes.sanitize_name(option.name)}"}>
|
2022-07-15 07:09:04 +12:00
|
|
|
<Heroicons.Outline.LinkIcon class="h-3 m-3" />
|
|
|
|
</a>
|
2022-07-28 07:57:39 +12:00
|
|
|
<div class="flex flex-row space-x-2">
|
|
|
|
<CalloutText>{option.name}</CalloutText>
|
|
|
|
{render_tags(assigns, option)}
|
|
|
|
</div>
|
2022-07-15 07:09:04 +12:00
|
|
|
</div>
|
|
|
|
</td>
|
|
|
|
<td>
|
|
|
|
{option.type}
|
|
|
|
</td>
|
|
|
|
<td>
|
2022-08-23 11:44:21 +12:00
|
|
|
{raw(render_replacements(assigns, option.html_for))}
|
2022-07-15 07:09:04 +12:00
|
|
|
</td>
|
|
|
|
<td>
|
2022-07-28 07:57:39 +12:00
|
|
|
{raw(
|
|
|
|
Enum.map_join(
|
|
|
|
List.flatten(Map.values(option.links || %{})),
|
|
|
|
", ",
|
|
|
|
&render_links("{{link:#{&1}}}", assigns)
|
|
|
|
)
|
|
|
|
)}
|
2022-07-15 07:09:04 +12:00
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
{/for}
|
2022-07-28 07:57:39 +12:00
|
|
|
{/if}
|
|
|
|
<tr>
|
|
|
|
<td colspan="100%">
|
|
|
|
<h3>
|
|
|
|
Options
|
|
|
|
</h3>
|
|
|
|
</td>
|
|
|
|
</tr>
|
2022-07-26 14:17:39 +12:00
|
|
|
<tr>
|
|
|
|
<th>Name</th>
|
|
|
|
<th>Type</th>
|
|
|
|
<th>Doc</th>
|
|
|
|
<th>Links</th>
|
|
|
|
</tr>
|
2022-07-15 07:09:04 +12:00
|
|
|
{#for %{argument_index: nil} = option <- @options}
|
2022-08-04 01:53:59 +12:00
|
|
|
<tr id={option.sanitized_path}>
|
2022-03-30 17:40:17 +13:00
|
|
|
<td>
|
|
|
|
<div class="flex flex-row items-baseline">
|
2022-08-29 00:42:24 +12:00
|
|
|
<a href={"##{DocRoutes.sanitize_name(option.name)}"}>
|
2022-03-30 17:40:17 +13:00
|
|
|
<Heroicons.Outline.LinkIcon class="h-3 m-3" />
|
|
|
|
</a>
|
|
|
|
<CalloutText>{option.name}</CalloutText>
|
2022-07-26 18:47:03 +12:00
|
|
|
{render_tags(assigns, option)}
|
2022-03-30 17:40:17 +13:00
|
|
|
</div>
|
|
|
|
</td>
|
|
|
|
<td>
|
|
|
|
{option.type}
|
|
|
|
</td>
|
|
|
|
<td>
|
2022-08-23 11:44:21 +12:00
|
|
|
{raw(render_replacements(assigns, option.html_for))}
|
2022-03-30 17:40:17 +13:00
|
|
|
</td>
|
2022-07-26 13:24:43 +12:00
|
|
|
<td>
|
2022-07-28 07:57:39 +12:00
|
|
|
{raw(
|
|
|
|
Enum.map_join(
|
|
|
|
List.flatten(Map.values(option.links || %{})),
|
|
|
|
", ",
|
|
|
|
&render_links("{{link:#{&1}}}", assigns)
|
|
|
|
)
|
|
|
|
)}
|
2022-07-26 13:24:43 +12:00
|
|
|
</td>
|
2022-03-30 17:40:17 +13:00
|
|
|
</tr>
|
|
|
|
{/for}
|
2022-07-28 07:57:39 +12:00
|
|
|
{/if}
|
|
|
|
</table>
|
2022-07-15 07:09:04 +12:00
|
|
|
</div>
|
2022-03-28 10:26:35 +13:00
|
|
|
</div>
|
2022-04-01 05:36:44 +13:00
|
|
|
{#if @module}
|
2022-09-08 15:02:18 +12:00
|
|
|
<div class="lg:w-72 overflow-y-auto overflow-x-hidden dark:bg-base-dark-900 bg-opacity-70 mt-14 custom-scrollbar">
|
2022-04-02 08:11:17 +13:00
|
|
|
<RightNav functions={@module.functions} module={@module.name} />
|
2022-04-01 05:36:44 +13:00
|
|
|
</div>
|
2022-07-28 07:57:39 +12:00
|
|
|
{#else}
|
|
|
|
<div />
|
2022-04-01 05:36:44 +13:00
|
|
|
{/if}
|
2022-03-28 10:26:35 +13:00
|
|
|
</div>
|
2022-03-30 05:12:28 +13:00
|
|
|
</div>
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
2022-07-15 07:09:04 +12:00
|
|
|
defp render_source_code_link(assigns, module_or_function, library, library_version) do
|
|
|
|
~F"""
|
|
|
|
{#if module_or_function.file}
|
|
|
|
<a target="_blank" href={source_link(module_or_function, library, library_version)}>{"</>"}</a>
|
|
|
|
{/if}
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
|
|
|
defp modules_in_scope(nil, _, _, _), do: []
|
|
|
|
defp modules_in_scope(_, nil, _, _), do: []
|
|
|
|
|
|
|
|
defp modules_in_scope(dsl, %{dsls: dsls}, libraries, selected_versions) do
|
|
|
|
dsl_path = dsl.path ++ [dsl.name]
|
|
|
|
|
|
|
|
dsls
|
|
|
|
|> Enum.filter(fn potential_parent ->
|
|
|
|
List.starts_with?(dsl_path, potential_parent.path ++ [potential_parent.name])
|
|
|
|
end)
|
|
|
|
|> Enum.flat_map(fn dsl ->
|
|
|
|
dsl.imports || []
|
|
|
|
end)
|
|
|
|
|> Enum.flat_map(fn mod_name ->
|
2022-08-07 11:22:58 +12:00
|
|
|
case find_module(libraries, selected_versions, mod_name) do
|
2022-07-15 07:09:04 +12:00
|
|
|
nil ->
|
|
|
|
Logger.warn("No such module found called #{inspect(mod_name)}")
|
|
|
|
[]
|
|
|
|
|
|
|
|
module ->
|
|
|
|
[module]
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
2022-08-07 11:22:58 +12:00
|
|
|
defp find_module(libraries, selected_versions, mod_name) do
|
|
|
|
Enum.find_value(libraries, fn library ->
|
|
|
|
Enum.find_value(library.versions, fn version ->
|
|
|
|
if version.id == selected_versions[library.id] do
|
|
|
|
Enum.find(version.modules, &(&1.name == mod_name))
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
2022-07-15 07:09:04 +12:00
|
|
|
defp child_dsls(_, nil), do: []
|
|
|
|
defp child_dsls(nil, _), do: []
|
|
|
|
|
|
|
|
defp child_dsls(%{dsls: dsls}, dsl) do
|
|
|
|
dsl_path = dsl.path ++ [dsl.name]
|
|
|
|
dsl_path_count = Enum.count(dsl_path)
|
|
|
|
|
|
|
|
Enum.filter(dsls, fn potential_child ->
|
|
|
|
potential_child_path = potential_child.path ++ [potential_child.name]
|
|
|
|
|
|
|
|
List.starts_with?(potential_child_path, dsl_path) &&
|
|
|
|
Enum.count(potential_child_path) - dsl_path_count == 1
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
defp positional_options(options) do
|
|
|
|
options
|
|
|
|
|> Enum.filter(& &1.argument_index)
|
|
|
|
|> Enum.sort_by(& &1.argument_index)
|
|
|
|
end
|
|
|
|
|
|
|
|
defp render_functions(assigns, functions, type, header) do
|
2022-04-01 14:29:58 +13:00
|
|
|
~F"""
|
2022-07-15 07:09:04 +12:00
|
|
|
{#case Enum.filter(functions, &(&1.type == type))}
|
|
|
|
{#match []}
|
|
|
|
{#match functions}
|
|
|
|
<h1>{header}</h1>
|
|
|
|
{#for function <- functions}
|
2022-08-05 05:14:58 +12:00
|
|
|
<div class="rounded-lg bg-slate-400 dark:bg-slate-700 bg-opacity-50 px-2">
|
2022-07-15 07:09:04 +12:00
|
|
|
<p class="">
|
|
|
|
<div class="">
|
|
|
|
<div class="flex flex-row items-baseline">
|
2022-08-04 01:53:59 +12:00
|
|
|
<a href={"##{type}-#{function.sanitized_name}-#{function.arity}"}>
|
2022-07-15 07:09:04 +12:00
|
|
|
<Heroicons.Outline.LinkIcon class="h-3 m-3" />
|
|
|
|
</a>
|
2022-07-28 07:57:39 +12:00
|
|
|
<div
|
|
|
|
class="nav-anchor text-xl font-semibold mb-2"
|
2022-08-04 01:53:59 +12:00
|
|
|
id={"#{type}-#{function.sanitized_name}-#{function.arity}"}
|
2022-07-28 07:57:39 +12:00
|
|
|
>{function.name}/{function.arity} {render_source_code_link(assigns, function, @library, @library_version)}</div>
|
2022-07-15 07:09:04 +12:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{#for head <- function.heads}
|
|
|
|
<code class="makeup elixir">{head}</code>
|
|
|
|
{/for}
|
2022-08-23 11:44:21 +12:00
|
|
|
{raw(render_replacements(assigns, function.html_for))}
|
2022-07-15 07:09:04 +12:00
|
|
|
</p>
|
2022-04-01 14:29:58 +13:00
|
|
|
</div>
|
2022-07-15 07:09:04 +12:00
|
|
|
{/for}
|
|
|
|
{/case}
|
2022-04-01 14:29:58 +13:00
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
2022-07-15 07:09:04 +12:00
|
|
|
defp source_link(%AshHq.Docs.Module{file: file}, library, library_version) do
|
2022-09-08 03:42:48 +12:00
|
|
|
"https://github.com/ash-project/#{library.name}/tree/v#{library_version.version}/#{file}"
|
2022-07-15 07:09:04 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
defp source_link(%AshHq.Docs.Function{file: file, line: line}, library, library_version) do
|
|
|
|
if line do
|
2022-08-31 11:13:04 +12:00
|
|
|
"https://github.com/ash-project/#{library.name}/tree/v#{library_version.version}/#{file}#L#{line}"
|
2022-07-15 07:09:04 +12:00
|
|
|
else
|
2022-08-31 11:13:04 +12:00
|
|
|
"https://github.com/ash-project/#{library.name}/tree/v#{library_version.version}/#{file}"
|
2022-07-15 07:09:04 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-03-30 05:12:28 +13:00
|
|
|
def path_to_name(path, name) do
|
2022-08-07 11:22:58 +12:00
|
|
|
Enum.map_join(path ++ [name], "-", &DocRoutes.sanitize_name/1)
|
2022-03-30 05:12:28 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
defp render_tags(assigns, option) do
|
|
|
|
~F"""
|
|
|
|
{#if option.required}
|
|
|
|
<Tag color={:red}>
|
|
|
|
Required
|
|
|
|
</Tag>
|
|
|
|
{/if}
|
|
|
|
"""
|
|
|
|
end
|
|
|
|
|
2022-08-07 11:22:58 +12:00
|
|
|
def show_sidebar(js \\ %JS{}) do
|
|
|
|
js
|
2022-03-29 11:05:19 +13:00
|
|
|
|> JS.toggle(
|
|
|
|
to: "#mobile-sidebar-container",
|
2022-03-30 05:12:28 +13:00
|
|
|
in: {
|
|
|
|
"transition ease-in duration-100",
|
|
|
|
"opacity-0",
|
|
|
|
"opacity-100"
|
|
|
|
},
|
|
|
|
out: {
|
|
|
|
"transition ease-out duration-75",
|
|
|
|
"opacity-100",
|
|
|
|
"opacity-0"
|
|
|
|
}
|
2022-03-29 11:05:19 +13:00
|
|
|
)
|
2022-03-28 10:26:35 +13:00
|
|
|
end
|
|
|
|
|
2022-08-04 01:53:59 +12:00
|
|
|
defp render_replacements(_assigns, nil), do: ""
|
2022-03-28 10:26:35 +13:00
|
|
|
|
2022-06-08 08:37:34 +12:00
|
|
|
defp render_replacements(assigns, docs) do
|
|
|
|
docs
|
|
|
|
|> render_links(assigns)
|
|
|
|
|> render_mix_deps(assigns)
|
|
|
|
end
|
|
|
|
|
|
|
|
defp render_mix_deps(docs, assigns) do
|
2022-08-29 00:42:24 +12:00
|
|
|
String.replace(docs, ~r/(?!<code>){{mix_dep:.*}}(?!<\/code>)/, fn text ->
|
2022-06-08 08:37:34 +12:00
|
|
|
try do
|
|
|
|
"{{mix_dep:" <> library = String.trim_trailing(text, "}}")
|
2022-08-20 04:35:07 +12:00
|
|
|
|
|
|
|
"<pre><code>#{render_mix_dep(assigns, library, text)}</code></pre>"
|
2022-06-08 08:37:34 +12:00
|
|
|
rescue
|
|
|
|
e ->
|
2022-08-29 00:42:24 +12:00
|
|
|
Logger.error(
|
|
|
|
"Invalid link #{inspect(e)}\n#{Exception.format_stacktrace(__STACKTRACE__)}"
|
|
|
|
)
|
|
|
|
|
2022-06-08 08:37:34 +12:00
|
|
|
text
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
defp render_mix_dep(assigns, library, source) do
|
|
|
|
library =
|
|
|
|
Enum.find(assigns[:libraries], &(&1.name == library)) ||
|
|
|
|
raise "No such library in link: #{source}"
|
|
|
|
|
|
|
|
selected_versions = assigns[:selected_versions]
|
|
|
|
|
|
|
|
version =
|
|
|
|
if selected_versions[library.id] == "latest" do
|
2022-08-16 13:23:59 +12:00
|
|
|
AshHqWeb.Helpers.latest_version(library)
|
2022-06-08 08:37:34 +12:00
|
|
|
else
|
|
|
|
case Enum.find(library.versions, &(&1.id == selected_versions[library.id])) do
|
|
|
|
nil ->
|
|
|
|
nil
|
|
|
|
|
|
|
|
version ->
|
|
|
|
version
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-08-20 04:35:07 +12:00
|
|
|
case Version.parse(version.version) do
|
2022-08-31 20:11:15 +12:00
|
|
|
{:ok, %Version{pre: pre, build: build}}
|
2022-08-31 17:39:22 +12:00
|
|
|
when not is_nil(pre) or not is_nil(build) ->
|
|
|
|
~s({:#{library.name}, "~> #{version}"})
|
|
|
|
|
|
|
|
{:ok, %Version{major: major, minor: minor, patch: 0}} ->
|
2022-08-20 04:35:07 +12:00
|
|
|
~s({:#{library.name}, "~> #{major}.#{minor}"})
|
2022-06-08 08:37:34 +12:00
|
|
|
|
2022-08-20 04:35:07 +12:00
|
|
|
{:ok, version} ->
|
|
|
|
~s({:#{library.name}, "~> #{version}"})
|
2022-06-08 08:37:34 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defp render_links(docs, assigns) do
|
2022-08-29 00:42:24 +12:00
|
|
|
String.replace(docs, ~r/(?!<code>){{link:[^}]*}}(?!<\/code>)/, fn text ->
|
2022-06-06 06:03:45 +12:00
|
|
|
try do
|
|
|
|
"{{link:" <> rest = String.trim_trailing(text, "}}")
|
2022-08-20 04:35:07 +12:00
|
|
|
[library, type, item | rest] = String.split(rest, ":")
|
|
|
|
render_link(assigns, library, type, item, text, rest)
|
2022-06-06 06:03:45 +12:00
|
|
|
rescue
|
|
|
|
e ->
|
2022-08-29 00:42:24 +12:00
|
|
|
Logger.error(
|
|
|
|
"Invalid link #{inspect(e)}\n#{Exception.format_stacktrace(__STACKTRACE__)}"
|
|
|
|
)
|
|
|
|
|
2022-06-06 06:03:45 +12:00
|
|
|
text
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
2022-08-20 04:35:07 +12:00
|
|
|
defp render_link(assigns, library, type, item, source, rest) do
|
2022-06-06 06:03:45 +12:00
|
|
|
library =
|
|
|
|
Enum.find(assigns[:libraries], &(&1.name == library)) ||
|
|
|
|
raise "No such library in link: #{source}"
|
|
|
|
|
|
|
|
selected_versions = assigns[:selected_versions]
|
|
|
|
|
|
|
|
version =
|
2022-07-28 07:57:39 +12:00
|
|
|
if selected_versions[library.id] in ["latest", nil, ""] do
|
2022-06-08 08:37:34 +12:00
|
|
|
Enum.find(library.versions, &String.contains?(&1.version, ".")) ||
|
2022-07-28 07:57:39 +12:00
|
|
|
AshHqWeb.Helpers.latest_version(library)
|
2022-06-06 06:03:45 +12:00
|
|
|
else
|
|
|
|
case Enum.find(library.versions, &(&1.id == selected_versions[library.id])) do
|
|
|
|
nil ->
|
|
|
|
nil
|
|
|
|
|
|
|
|
version ->
|
|
|
|
version
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-15 07:09:04 +12:00
|
|
|
if is_nil(version) do
|
|
|
|
raise "no version for library"
|
2022-06-06 06:03:45 +12:00
|
|
|
else
|
2022-07-15 07:09:04 +12:00
|
|
|
case type do
|
|
|
|
"guide" ->
|
|
|
|
guide =
|
|
|
|
Enum.find(version.guides, &(&1.name == item)) ||
|
|
|
|
raise "No such guide in link: #{source}"
|
|
|
|
|
2022-08-20 04:35:07 +12:00
|
|
|
text = Enum.at(rest, 0) || item
|
|
|
|
|
2022-07-15 07:09:04 +12:00
|
|
|
"""
|
2022-08-20 04:35:07 +12:00
|
|
|
<a href="#{DocRoutes.doc_link(guide, assigns[:selected_versions])}">#{text}</a>
|
2022-07-15 07:09:04 +12:00
|
|
|
"""
|
|
|
|
|
|
|
|
"dsl" ->
|
2022-08-29 00:42:24 +12:00
|
|
|
path =
|
2022-07-15 07:09:04 +12:00
|
|
|
item
|
2022-08-29 00:42:24 +12:00
|
|
|
|> String.split(~r/[\/\.]/)
|
|
|
|
|
|
|
|
name =
|
|
|
|
path
|
2022-07-15 07:09:04 +12:00
|
|
|
|> Enum.join(".")
|
|
|
|
|
2022-08-29 00:42:24 +12:00
|
|
|
route = Enum.map_join(path, "/", &DocRoutes.sanitize_name/1)
|
|
|
|
|
|
|
|
"""
|
|
|
|
<a href="/docs/dsl/#{library.name}/#{version.version}/#{route}">#{name}</a>
|
|
|
|
"""
|
|
|
|
|
|
|
|
"option" ->
|
|
|
|
path =
|
|
|
|
item
|
|
|
|
|> String.split(~r/[\/\.]/)
|
|
|
|
|
|
|
|
name = Enum.join(path, ".")
|
|
|
|
|
|
|
|
dsl_path = path |> :lists.droplast() |> Enum.map_join("/", &DocRoutes.sanitize_name/1)
|
|
|
|
anchor = path |> Enum.map_join("/", &DocRoutes.sanitize_name/1)
|
|
|
|
|
2022-07-15 07:09:04 +12:00
|
|
|
"""
|
2022-08-29 00:42:24 +12:00
|
|
|
<a href="/docs/dsl/#{library.name}/#{version.version}/#{dsl_path}##{anchor}">#{name}</a>
|
2022-07-15 07:09:04 +12:00
|
|
|
"""
|
|
|
|
|
2022-07-26 13:24:43 +12:00
|
|
|
"module" ->
|
|
|
|
"""
|
2022-08-20 04:35:07 +12:00
|
|
|
<a href="/docs/module/#{library.name}/#{version.version}/#{DocRoutes.sanitize_name(item)}">#{item}</a>
|
2022-07-26 13:24:43 +12:00
|
|
|
"""
|
|
|
|
|
2022-07-26 13:50:44 +12:00
|
|
|
"extension" ->
|
|
|
|
"""
|
2022-08-20 04:35:07 +12:00
|
|
|
<a href="/docs/dsl/#{library.name}/#{version.version}/#{DocRoutes.sanitize_name(item)}">#{item}</a>
|
2022-07-26 13:50:44 +12:00
|
|
|
"""
|
|
|
|
|
2022-07-15 07:09:04 +12:00
|
|
|
type ->
|
|
|
|
raise "unimplemented link type #{inspect(type)} in #{source}"
|
|
|
|
end
|
2022-06-06 06:03:45 +12:00
|
|
|
end
|
|
|
|
end
|
2022-03-28 10:26:35 +13:00
|
|
|
end
|