mirror of
https://github.com/ash-project/ash_hq.git
synced 2024-09-20 05:13:23 +12:00
WIP
This commit is contained in:
parent
c6c05c0fa1
commit
de97413240
26 changed files with 1829 additions and 157 deletions
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -11,8 +11,10 @@
|
||||||
"noreply",
|
"noreply",
|
||||||
"ossp",
|
"ossp",
|
||||||
"plainto",
|
"plainto",
|
||||||
|
"postprocessor",
|
||||||
"setweight",
|
"setweight",
|
||||||
"tailwindcss",
|
"tailwindcss",
|
||||||
|
"topbar",
|
||||||
"trgm",
|
"trgm",
|
||||||
"tsquery",
|
"tsquery",
|
||||||
"tsvector",
|
"tsvector",
|
||||||
|
|
|
@ -97,63 +97,3 @@
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-in-scale {
|
|
||||||
animation: 0.2s ease-in 0s normal forwards 1 fade-in-scale-keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-out-scale {
|
|
||||||
animation: 0.2s ease-out 0s normal forwards 1 fade-out-scale-keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-in {
|
|
||||||
animation: 0.2s ease-out 0s normal forwards 1 fade-in-keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-out {
|
|
||||||
animation: 0.2s ease-out 0s normal forwards 1 fade-out-keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fade-in-scale-keys {
|
|
||||||
0% {
|
|
||||||
scale: 0.95;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
scale: 1.0;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fade-out-scale-keys {
|
|
||||||
0% {
|
|
||||||
scale: 1.0;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
scale: 0.95;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fade-in-keys {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fade-out-keys {
|
|
||||||
0% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,8 +22,8 @@ import "phoenix_html"
|
||||||
import {Socket} from "phoenix"
|
import {Socket} from "phoenix"
|
||||||
import {LiveSocket} from "phoenix_live_view"
|
import {LiveSocket} from "phoenix_live_view"
|
||||||
import topbar from "../vendor/topbar"
|
import topbar from "../vendor/topbar"
|
||||||
|
import mermaid from "mermaid"
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').matches
|
mermaid.init(".mermaid")
|
||||||
|
|
||||||
const Hooks = {};
|
const Hooks = {};
|
||||||
|
|
||||||
|
@ -42,6 +42,16 @@ Hooks.ColorTheme = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Hooks.Docs = {
|
||||||
|
mounted() {
|
||||||
|
console.log(this.el)
|
||||||
|
mermaid.init(".mermaid")
|
||||||
|
},
|
||||||
|
beforeUpdate() {
|
||||||
|
console.log(this.el)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
Hooks.CmdK = {
|
Hooks.CmdK = {
|
||||||
mounted() {
|
mounted() {
|
||||||
window.addEventListener("keydown", (event) => {
|
window.addEventListener("keydown", (event) => {
|
||||||
|
@ -115,6 +125,7 @@ window.addEventListener("phx:selected-versions", (e) => {
|
||||||
// connect if there are any LiveViews on the page
|
// connect if there are any LiveViews on the page
|
||||||
liveSocket.connect()
|
liveSocket.connect()
|
||||||
|
|
||||||
|
|
||||||
// expose liveSocket on window for web console debug logs and latency simulation:
|
// expose liveSocket on window for web console debug logs and latency simulation:
|
||||||
// >> liveSocket.enableDebug()
|
// >> liveSocket.enableDebug()
|
||||||
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
|
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
|
||||||
|
|
1444
assets/package-lock.json
generated
1444
assets/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -11,6 +11,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/typography": "^0.5.2",
|
"@tailwindcss/typography": "^0.5.2",
|
||||||
|
"mermaid": "^8.14.0",
|
||||||
"smooth-scroll-into-view-if-needed": "^1.1.33"
|
"smooth-scroll-into-view-if-needed": "^1.1.33"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ defmodule AshHq.Docs.Extensions.RenderMarkdown.Changes.RenderMarkdown do
|
||||||
if Ash.Changeset.changing_attribute?(changeset, opts[:source]) do
|
if Ash.Changeset.changing_attribute?(changeset, opts[:source]) do
|
||||||
source = Ash.Changeset.get_attribute(changeset, opts[:source])
|
source = Ash.Changeset.get_attribute(changeset, opts[:source])
|
||||||
|
|
||||||
case Earmark.as_html(source) do
|
case AshHq.Docs.Extensions.RenderMarkdown.as_html(source) do
|
||||||
{:error, _, error_messages} ->
|
{:error, _, error_messages} ->
|
||||||
Ash.Changeset.add_error(
|
Ash.Changeset.add_error(
|
||||||
changeset,
|
changeset,
|
||||||
|
@ -18,6 +18,7 @@ defmodule AshHq.Docs.Extensions.RenderMarkdown.Changes.RenderMarkdown do
|
||||||
|
|
||||||
{:ok, html_doc, _} ->
|
{:ok, html_doc, _} ->
|
||||||
html_doc = AshHq.Docs.Extensions.RenderMarkdown.Highlighter.highlight(html_doc)
|
html_doc = AshHq.Docs.Extensions.RenderMarkdown.Highlighter.highlight(html_doc)
|
||||||
|
|
||||||
Ash.Changeset.force_change_attribute(changeset, opts[:destination], html_doc)
|
Ash.Changeset.force_change_attribute(changeset, opts[:destination], html_doc)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
|
@ -41,7 +41,7 @@ defmodule AshHq.Docs.Extensions.RenderMarkdown.Highlighter do
|
||||||
formatter_options: [highlight_tag: "span"]
|
formatter_options: [highlight_tag: "span"]
|
||||||
)
|
)
|
||||||
|
|
||||||
~s(<pre><code class="makeup #{lang}">#{highlighted}</code></pre>)
|
~s(<pre><code class="makeup #{lang} highlight">#{highlighted}</code></pre>)
|
||||||
end
|
end
|
||||||
|
|
||||||
entities = [{"&", ?&}, {"<", ?<}, {">", ?>}, {""", ?"}, {"'", ?'}]
|
entities = [{"&", ?&}, {"<", ?<}, {">", ?>}, {""", ?"}, {"'", ?'}]
|
||||||
|
|
|
@ -15,20 +15,78 @@ defmodule AshHq.Docs.Extensions.RenderMarkdown do
|
||||||
sections: [@render_markdown],
|
sections: [@render_markdown],
|
||||||
transformers: [AshHq.Docs.Extensions.RenderMarkdown.Transformers.AddRenderMarkdownStructure]
|
transformers: [AshHq.Docs.Extensions.RenderMarkdown.Transformers.AddRenderMarkdownStructure]
|
||||||
|
|
||||||
def attributes(resource) do
|
def render_attributes(resource) do
|
||||||
Ash.Dsl.Extension.get_opt(resource, [:render_markdown], :attributes, [])
|
Ash.Dsl.Extension.get_opt(resource, [:render_markdown], :render_attributes, [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def render!(%resource{} = record, key, on_demand? \\ false) do
|
def render!(%resource{} = record, key, on_demand? \\ false) do
|
||||||
cond do
|
cond do
|
||||||
attributes(resource)[key] ->
|
render_attributes(resource)[key] ->
|
||||||
Map.get(record, attributes(resource)[key])
|
Map.get(record, render_attributes(resource)[key])
|
||||||
|
|
||||||
on_demand? ->
|
on_demand? ->
|
||||||
Earmark.as_html!(Map.get(record, key) || "")
|
as_html!(Map.get(record, key) || "")
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
raise "#{resource} dos not render #{key} as markdown. Pass the `on_demand?` argument as `true` to render it dynamically."
|
raise "#{resource} dos not render #{key} as markdown. Pass the `on_demand?` argument as `true` to render it dynamically."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def as_html!(text) do
|
||||||
|
text
|
||||||
|
|> Earmark.as_html!(postprocessor: &add_ids/1)
|
||||||
|
|> AshHq.Docs.Extensions.RenderMarkdown.Highlighter.highlight()
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_html(text) do
|
||||||
|
text
|
||||||
|
|> Earmark.as_html(postprocessor: &add_ids/1)
|
||||||
|
|> case do
|
||||||
|
{:ok, html_doc, errors} ->
|
||||||
|
{:ok, AshHq.Docs.Extensions.RenderMarkdown.Highlighter.highlight(html_doc), errors}
|
||||||
|
|
||||||
|
{:error, html_doc, errors} ->
|
||||||
|
{:error, html_doc, errors}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp add_ids({tag, attrs, [contents], meta} = node)
|
||||||
|
when tag in ["h1", "h2", "h3", "h4", "h5", "h6"] and is_binary(contents) do
|
||||||
|
if meta[:handled] do
|
||||||
|
node
|
||||||
|
else
|
||||||
|
new_attrs = Enum.reject(attrs, fn {key, _} -> key == "id" end)
|
||||||
|
|
||||||
|
id = String.downcase(String.replace(contents, ~r/[^A-Za-z0-9_]/, "-"))
|
||||||
|
new_attrs = [{"id", id} | new_attrs]
|
||||||
|
|
||||||
|
{"div", [{"class", "flex flex-row items-center"}],
|
||||||
|
[
|
||||||
|
{"a", [{"href", "##{id}"}],
|
||||||
|
[
|
||||||
|
{"svg",
|
||||||
|
[
|
||||||
|
{"xmlns", "http://www.w3.org/2000/svg"},
|
||||||
|
{"class", "h-6 w-6"},
|
||||||
|
{"fill", "none"},
|
||||||
|
{"viewBox", "0 0 24 24"},
|
||||||
|
{"stroke", "currentColor"},
|
||||||
|
{"stroke-width", "2"}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{"path",
|
||||||
|
[
|
||||||
|
{"stroke-linecap", "round"},
|
||||||
|
{"stroke-linejoin", "round"},
|
||||||
|
{"d",
|
||||||
|
"M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"}
|
||||||
|
], [], %{}}
|
||||||
|
], %{}}
|
||||||
|
], %{}},
|
||||||
|
{tag, new_attrs, [contents], %{handled: true}}
|
||||||
|
], %{}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp add_ids(other), do: other
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,15 +4,18 @@ defmodule AshHq.Docs.Extensions.RenderMarkdown.Transformers.AddRenderMarkdownStr
|
||||||
|
|
||||||
def transform(resource, dsl) do
|
def transform(resource, dsl) do
|
||||||
resource
|
resource
|
||||||
|> AshHq.Docs.Extensions.RenderMarkdown.attributes()
|
|> AshHq.Docs.Extensions.RenderMarkdown.render_attributes()
|
||||||
|> Enum.reduce({:ok, dsl}, fn {source, destination}, {:ok, dsl} ->
|
|> Enum.reduce({:ok, dsl}, fn {source, destination}, {:ok, dsl} ->
|
||||||
{:ok,
|
{:ok,
|
||||||
dsl
|
dsl
|
||||||
|> allow_nil_input(resource, destination)
|
|> allow_nil_input(resource, destination)
|
||||||
|> Transformer.add_entity([:changes], :change,
|
|> Transformer.add_entity(
|
||||||
|
[:changes],
|
||||||
|
Transformer.build_entity!(Ash.Resource.Dsl, [:changes], :change,
|
||||||
change:
|
change:
|
||||||
{AshHq.Docs.Extensions.RenderMarkdown.Changes.RenderMarkdown,
|
{AshHq.Docs.Extensions.RenderMarkdown.Changes.RenderMarkdown,
|
||||||
source: source, destination: destination}
|
source: source, destination: destination}
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,7 @@ defmodule AshHq.Docs.Extensions.Search.Transformers.AddSearchStructure do
|
||||||
def transform(resource, dsl_state) do
|
def transform(resource, dsl_state) do
|
||||||
config = %{
|
config = %{
|
||||||
name_attribute: AshHq.Docs.Extensions.Search.name_attribute(resource),
|
name_attribute: AshHq.Docs.Extensions.Search.name_attribute(resource),
|
||||||
doc_attribute: AshHq.Docs.Extensions.Search.name_attribute(resource),
|
doc_attribute: AshHq.Docs.Extensions.Search.doc_attribute(resource),
|
||||||
library_version_attribute: AshHq.Docs.Extensions.Search.library_version_attribute(resource)
|
library_version_attribute: AshHq.Docs.Extensions.Search.library_version_attribute(resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ defmodule AshHq.Docs.Extensions.Search.Transformers.AddSearchStructure do
|
||||||
calculation:
|
calculation:
|
||||||
Ash.Query.expr(
|
Ash.Query.expr(
|
||||||
fragment(
|
fragment(
|
||||||
"ts_headline('simple', ?, plainto_tsquery('simple', ?), 'StartSel=\"<span class=\"\"search-hit\"\">\", StopSel=</span>')",
|
"ts_headline('english', ?, plainto_tsquery('english', ?), 'MaxFragments=3,StartSel=\"<span class=\"\"search-hit\"\">\", StopSel=</span>')",
|
||||||
^ref(config.doc_attribute),
|
^ref(config.doc_attribute),
|
||||||
^arg(:query)
|
^arg(:query)
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,7 +4,7 @@ defmodule AshHq.Docs.Dsl do
|
||||||
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
|
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
|
||||||
|
|
||||||
render_markdown do
|
render_markdown do
|
||||||
render_attributes doc: :html_doc
|
render_attributes doc: :doc_html
|
||||||
end
|
end
|
||||||
|
|
||||||
search do
|
search do
|
||||||
|
|
|
@ -4,12 +4,12 @@ defmodule AshHq.Docs.Extension do
|
||||||
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
|
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
|
||||||
|
|
||||||
render_markdown do
|
render_markdown do
|
||||||
render_attributes doc: :html_doc
|
render_attributes doc: :doc_html
|
||||||
end
|
end
|
||||||
|
|
||||||
# search :load_for_search do
|
search do
|
||||||
|
load_for_search library_version: [:library_display_name, :library_name]
|
||||||
# end
|
end
|
||||||
|
|
||||||
postgres do
|
postgres do
|
||||||
table "extensions"
|
table "extensions"
|
||||||
|
|
|
@ -45,7 +45,7 @@ defmodule AshHq.Docs.Guide do
|
||||||
end
|
end
|
||||||
|
|
||||||
calculations do
|
calculations do
|
||||||
calculate :url_safe_name, :string, expr(fragment("replace(?, ' ', '-')", name))
|
calculate :url_safe_name, :string, expr(fragment("lower(replace(?, ' ', '-'))", name))
|
||||||
end
|
end
|
||||||
|
|
||||||
relationships do
|
relationships do
|
||||||
|
|
|
@ -4,7 +4,7 @@ defmodule AshHq.Docs.Option do
|
||||||
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
|
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
|
||||||
|
|
||||||
render_markdown do
|
render_markdown do
|
||||||
render_attributes doc: :html_doc
|
render_attributes doc: :doc_html
|
||||||
end
|
end
|
||||||
|
|
||||||
search do
|
search do
|
||||||
|
|
|
@ -24,7 +24,7 @@ defmodule AshHqWeb.Components.DocSidebar do
|
||||||
to={Routes.library_link(library, selected_version_name(library, @selected_versions))}
|
to={Routes.library_link(library, selected_version_name(library, @selected_versions))}
|
||||||
class={
|
class={
|
||||||
"flex items-center p-2 text-base font-normal text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700",
|
"flex items-center p-2 text-base font-normal text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700",
|
||||||
"dark:bg-gray-600": !@extension && @library && library.id == @library.id
|
"dark:bg-gray-600": !@guide && !@extension && @library && library.id == @library.id
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Heroicons.Outline.CollectionIcon class="w-6 h-6" />
|
<Heroicons.Outline.CollectionIcon class="w-6 h-6" />
|
||||||
|
|
49
lib/ash_hq_web/components/progressive_heading.ex
Normal file
49
lib/ash_hq_web/components/progressive_heading.ex
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
defmodule AshHqWeb.Components.ProgressiveHeading do
|
||||||
|
use Surface.Component
|
||||||
|
|
||||||
|
prop depth, :integer, required: true
|
||||||
|
slot default, required: true
|
||||||
|
|
||||||
|
def render(assigns) do
|
||||||
|
~F"""
|
||||||
|
{#case @depth}
|
||||||
|
{#match 1}
|
||||||
|
<h1>
|
||||||
|
<#slot />
|
||||||
|
</h1>
|
||||||
|
{#match 2}
|
||||||
|
<h2>
|
||||||
|
<#slot />
|
||||||
|
</h2>
|
||||||
|
{#match 3}
|
||||||
|
<h3>
|
||||||
|
<#slot />
|
||||||
|
</h3>
|
||||||
|
{#match 4}
|
||||||
|
<h4>
|
||||||
|
<#slot />
|
||||||
|
</h4>
|
||||||
|
{#match 5}
|
||||||
|
<h5>
|
||||||
|
<#slot />
|
||||||
|
</h5>
|
||||||
|
{#match 6}
|
||||||
|
<h6>
|
||||||
|
<#slot />
|
||||||
|
</h6>
|
||||||
|
{#match 7}
|
||||||
|
<span>
|
||||||
|
<#slot />
|
||||||
|
</span>
|
||||||
|
{#match 8}
|
||||||
|
<span>
|
||||||
|
<#slot />
|
||||||
|
</span>
|
||||||
|
{#match 9}
|
||||||
|
<span>
|
||||||
|
<#slot />
|
||||||
|
</span>
|
||||||
|
{/case}
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
|
@ -23,7 +23,7 @@ defmodule AshHqWeb.Components.Search do
|
||||||
<div
|
<div
|
||||||
id={@id}
|
id={@id}
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
class="absolute flex justify-center align-middle w-screen h-screen backdrop-blur-sm pb-8 bg-white bg-opacity-10"
|
class="absolute flex justify-center align-middle w-screen h-full backdrop-blur-sm pb-8 bg-white bg-opacity-10"
|
||||||
phx-hook="CmdK"
|
phx-hook="CmdK"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@ -59,9 +59,9 @@ defmodule AshHqWeb.Components.Search do
|
||||||
<Label field={library.id}>
|
<Label field={library.id}>
|
||||||
{library.display_name}
|
{library.display_name}
|
||||||
</Label>
|
</Label>
|
||||||
<div>
|
<div class="pb-2">
|
||||||
<Select
|
<Select
|
||||||
class="text-black"
|
class="text-black form-select rounded-md pt-1 py-2 w-3/4"
|
||||||
name={"versions[#{library.id}]"}
|
name={"versions[#{library.id}]"}
|
||||||
selected={Map.get(@selected_versions, library.id)}
|
selected={Map.get(@selected_versions, library.id)}
|
||||||
options={Enum.map(library.versions, &{&1.version, &1.id})}
|
options={Enum.map(library.versions, &{&1.version, &1.id})}
|
||||||
|
@ -229,6 +229,11 @@ defmodule AshHqWeb.Components.Search do
|
||||||
} ->
|
} ->
|
||||||
"#{library_display_name} #{version}"
|
"#{library_display_name} #{version}"
|
||||||
|
|
||||||
|
%AshHq.Docs.Extension{
|
||||||
|
library_version: %{version: version, library_display_name: library_display_name}
|
||||||
|
} ->
|
||||||
|
"#{library_display_name} #{version}"
|
||||||
|
|
||||||
%AshHq.Docs.LibraryVersion{library_display_name: library_display_name, version: version} ->
|
%AshHq.Docs.LibraryVersion{library_display_name: library_display_name, version: version} ->
|
||||||
"#{library_display_name} #{version}"
|
"#{library_display_name} #{version}"
|
||||||
end)
|
end)
|
||||||
|
|
14
lib/ash_hq_web/components/tag.ex
Normal file
14
lib/ash_hq_web/components/tag.ex
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
defmodule AshHqWeb.Components.Tag do
|
||||||
|
use Surface.Component
|
||||||
|
|
||||||
|
prop color, :atom, values: [:red]
|
||||||
|
slot default
|
||||||
|
|
||||||
|
def render(assigns) do
|
||||||
|
~F"""
|
||||||
|
<div class={"rounded-xl p-1", "bg-red-300 text-black": @color == :red}>
|
||||||
|
<#slot/>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,7 +2,8 @@ defmodule AshHqWeb.Pages.Docs do
|
||||||
use Surface.LiveComponent
|
use Surface.LiveComponent
|
||||||
|
|
||||||
alias Phoenix.LiveView.JS
|
alias Phoenix.LiveView.JS
|
||||||
alias AshHqWeb.Components.DocSidebar
|
alias AshHqWeb.Components.{CalloutText, DocSidebar, ProgressiveHeading, Tag}
|
||||||
|
alias AshHqWeb.Routes
|
||||||
|
|
||||||
prop params, :map, required: true
|
prop params, :map, required: true
|
||||||
prop change_versions, :event, required: true
|
prop change_versions, :event, required: true
|
||||||
|
@ -15,12 +16,13 @@ defmodule AshHqWeb.Pages.Docs do
|
||||||
data library_version, :any
|
data library_version, :any
|
||||||
data guide, :any
|
data guide, :any
|
||||||
data doc_path, :list, default: []
|
data doc_path, :list, default: []
|
||||||
|
data dsls, :list, default: []
|
||||||
|
|
||||||
@spec render(any) :: Phoenix.LiveView.Rendered.t()
|
@spec render(any) :: Phoenix.LiveView.Rendered.t()
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~F"""
|
~F"""
|
||||||
<div class="h-full w-full flex flex-col bg-light-grid dark:bg-dark-grid">
|
<div class="grow h-full w-full flex flex-col">
|
||||||
<div class="md:hidden flex flex-row justify-start space-x-12 mt-2 items-center border-b border-t border-gray-600 py-3 mb-10">
|
<div class="lg:hidden flex flex-row justify-start space-x-12 items-center border-b border-t border-gray-600 py-3">
|
||||||
<button class="dark:hover:text-gray-600" phx-click={show_sidebar()}>
|
<button class="dark:hover:text-gray-600" phx-click={show_sidebar()}>
|
||||||
<Heroicons.Outline.MenuIcon class="w-8 h-8 ml-4" />
|
<Heroicons.Outline.MenuIcon class="w-8 h-8 ml-4" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -33,55 +35,169 @@ defmodule AshHqWeb.Pages.Docs do
|
||||||
</div>
|
</div>
|
||||||
{#match path}
|
{#match path}
|
||||||
{#for item <- :lists.droplast(path)}
|
{#for item <- :lists.droplast(path)}
|
||||||
<span class="text-gray-500">
|
<span class="text-gray-400">
|
||||||
{item}</span>
|
{item}
|
||||||
|
</span>
|
||||||
<Heroicons.Outline.ChevronRightIcon class="w-3 h-3" />
|
<Heroicons.Outline.ChevronRightIcon class="w-3 h-3" />
|
||||||
{/for}
|
{/for}
|
||||||
<span class="dark:text-white" />
|
<span class="dark:text-white">
|
||||||
|
<CalloutText>{List.last(path)}</CalloutText>
|
||||||
|
</span>
|
||||||
{/case}
|
{/case}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div id="mobile-sidebar-container" class="hidden md:hidden relative w-screen h-full backdrop-blur-lg transition">
|
<span class="lg:hidden">
|
||||||
<div>
|
<div
|
||||||
|
id="mobile-sidebar-container"
|
||||||
|
class="hidden fixed w-min h-full bg-primary-black transition"
|
||||||
|
>
|
||||||
<DocSidebar
|
<DocSidebar
|
||||||
id="mobile-sidebar"
|
id="mobile-sidebar"
|
||||||
class="absolute left-0 top-0"
|
|
||||||
libraries={@libraries}
|
libraries={@libraries}
|
||||||
extension={@extension}
|
extension={@extension}
|
||||||
|
dsls={@dsls}
|
||||||
guide={@guide}
|
guide={@guide}
|
||||||
library={@library}
|
library={@library}
|
||||||
library_version={@library_version}
|
library_version={@library_version}
|
||||||
selected_versions={@selected_versions}
|
selected_versions={@selected_versions}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</span>
|
||||||
<div class="grow flex flex-row h-full justify-center space-x-12">
|
<div class="grow flex flex-row h-full justify-center space-x-12">
|
||||||
<DocSidebar
|
<DocSidebar
|
||||||
id="sidebar"
|
id="sidebar"
|
||||||
class="hidden md:block"
|
class="hidden lg:block mt-10"
|
||||||
libraries={@libraries}
|
libraries={@libraries}
|
||||||
extension={@extension}
|
extension={@extension}
|
||||||
|
dsls={@dsls}
|
||||||
guide={@guide}
|
guide={@guide}
|
||||||
library={@library}
|
library={@library}
|
||||||
library_version={@library_version}
|
library_version={@library_version}
|
||||||
selected_versions={@selected_versions}
|
selected_versions={@selected_versions}
|
||||||
/>
|
/>
|
||||||
<div class="grow w-full prose prose-zinc md:prose-lg lg:prose-xl dark:prose-invert">
|
<div
|
||||||
|
id="docs-window"
|
||||||
|
class="grow w-full prose lg:max-w-3xl xl:max-w-5xl dark:prose-invert overflow-y-scroll overflow-x-visible"
|
||||||
|
phx-hook="Docs"
|
||||||
|
>
|
||||||
{raw(@docs)}
|
{raw(@docs)}
|
||||||
|
{#if !Enum.empty?(@dsls)}
|
||||||
|
<h1>Dsl Documentation</h1>
|
||||||
|
{render_dsl_docs(assigns, @dsls)}
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp render_dsl_docs(assigns, dsls, path \\ [], depth \\ nil) do
|
||||||
|
count = Enum.count(path)
|
||||||
|
depth = depth || count + 4
|
||||||
|
|
||||||
|
~F"""
|
||||||
|
{#for dsl <- Enum.filter(dsls, &(&1.path == path)) |> Enum.sort_by(& &1.order)}
|
||||||
|
<div class={"w-full pl-2 border-gray-800 border-l", "ml-2": count > 0}>
|
||||||
|
<div id={path_to_name(dsl.path, dsl.name)} class="flex flex-row items-center">
|
||||||
|
<a href={"##{path_to_name(dsl.path, dsl.name)}"}><Heroicons.Outline.LinkIcon class="h-4 w-4" /></a>
|
||||||
|
{render_path(assigns, dsl.path, dsl.name)}
|
||||||
|
</div>
|
||||||
|
{render_options(assigns, get_options(dsl, @options), depth)}
|
||||||
|
{raw(AshHq.Docs.Extensions.RenderMarkdown.render!(dsl, :doc))}
|
||||||
|
{render_dsl_docs(assigns, dsls, path ++ [dsl.name], depth + 1)}
|
||||||
|
</div>
|
||||||
|
{/for}
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
def path_to_name(path, name) do
|
||||||
|
Enum.map_join(path ++ [name], "-", &Routes.sanitize_name/1)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp render_options(assigns, [], _) do
|
||||||
|
~F"""
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp render_options(assigns, options, depth) do
|
||||||
|
~F"""
|
||||||
|
<div class="ml-2">
|
||||||
|
<table>
|
||||||
|
{#for option <- options}
|
||||||
|
<tr id={path_to_name(option.path, option.name)}>
|
||||||
|
<td>
|
||||||
|
<div class="flex flex-row items-baseline">
|
||||||
|
<a href={"##{path_to_name(option.path, option.name)}"}>
|
||||||
|
<Heroicons.Outline.LinkIcon class="h-3 m-3" />
|
||||||
|
</a>
|
||||||
|
<CalloutText>{option.name}</CalloutText>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{option.type}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{render_tags(assigns, option)}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{raw(AshHq.Docs.Extensions.RenderMarkdown.render!(option, :doc))}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/for}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp render_path(assigns, path, name) do
|
||||||
|
~F"""
|
||||||
|
<div class="flex flex-row space-x-1 items-center">
|
||||||
|
{#for item <- path}
|
||||||
|
<span class="text-gray-400">
|
||||||
|
{item}</span>
|
||||||
|
<Heroicons.Outline.ChevronRightIcon class="w-3 h-3" />
|
||||||
|
{/for}
|
||||||
|
<span class="dark:text-white">
|
||||||
|
<CalloutText>
|
||||||
|
{name}
|
||||||
|
</CalloutText>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp render_tags(assigns, option) do
|
||||||
|
~F"""
|
||||||
|
{#if option.required}
|
||||||
|
<Tag color={:red}>
|
||||||
|
Required
|
||||||
|
</Tag>
|
||||||
|
{/if}
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_options(dsl, options) do
|
||||||
|
Enum.filter(options, fn option ->
|
||||||
|
List.starts_with?(option.path, dsl.path ++ [dsl.name]) &&
|
||||||
|
Enum.count(option.path) - Enum.count(dsl.path) == 1
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
def show_sidebar() do
|
def show_sidebar() do
|
||||||
%JS{}
|
%JS{}
|
||||||
|> JS.toggle(
|
|> JS.toggle(
|
||||||
to: "#mobile-sidebar-container",
|
to: "#mobile-sidebar-container",
|
||||||
in: {"fade-in duration-100 transition", "hidden", "block"},
|
in: {
|
||||||
out: {"fade-out duration-100 transition", "block", "hidden"},
|
"transition ease-in duration-100",
|
||||||
time: 100
|
"opacity-0",
|
||||||
|
"opacity-100"
|
||||||
|
},
|
||||||
|
out: {
|
||||||
|
"transition ease-out duration-75",
|
||||||
|
"opacity-100",
|
||||||
|
"opacity-0"
|
||||||
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -109,24 +225,31 @@ defmodule AshHqWeb.Pages.Docs do
|
||||||
cond do
|
cond do
|
||||||
socket.assigns.extension ->
|
socket.assigns.extension ->
|
||||||
assign(socket,
|
assign(socket,
|
||||||
docs: Earmark.as_html!(socket.assigns.extension.doc),
|
docs: AshHq.Docs.Extensions.RenderMarkdown.render!(socket.assigns.extension, :doc),
|
||||||
doc_path: [socket.assigns.library.name, socket.assigns.extension.name]
|
doc_path: [socket.assigns.library.name, socket.assigns.extension.name],
|
||||||
|
dsls: socket.assigns.extension.dsls,
|
||||||
|
options: socket.assigns.extension.options
|
||||||
)
|
)
|
||||||
|
|
||||||
socket.assigns.guide ->
|
socket.assigns.guide ->
|
||||||
assign(socket,
|
assign(socket,
|
||||||
docs: Earmark.as_html!(socket.assigns.guide.text),
|
docs: AshHq.Docs.Extensions.RenderMarkdown.render!(socket.assigns.guide, :text),
|
||||||
doc_path: [socket.assigns.library.name, socket.assigns.guide.name]
|
doc_path: [socket.assigns.library.name, socket.assigns.guide.name],
|
||||||
|
dsls: [],
|
||||||
|
options: []
|
||||||
)
|
)
|
||||||
|
|
||||||
socket.assigns.library_version ->
|
socket.assigns.library_version ->
|
||||||
assign(socket,
|
assign(socket,
|
||||||
docs: Earmark.as_html!(socket.assigns.library_version.doc),
|
docs:
|
||||||
doc_path: [socket.assigns.library.name]
|
AshHq.Docs.Extensions.RenderMarkdown.render!(socket.assigns.library_version, :doc),
|
||||||
|
doc_path: [socket.assigns.library.name],
|
||||||
|
dsls: [],
|
||||||
|
options: []
|
||||||
)
|
)
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
assign(socket, docs: "", doc_path: [])
|
assign(socket, docs: "", doc_path: [], dsls: [])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -137,7 +260,7 @@ defmodule AshHqWeb.Pages.Docs do
|
||||||
assign(socket,
|
assign(socket,
|
||||||
extension:
|
extension:
|
||||||
Enum.find(extensions, fn extension ->
|
Enum.find(extensions, fn extension ->
|
||||||
extension.name == socket.assigns[:params]["extension"]
|
Routes.sanitize_name(extension.name) == socket.assigns[:params]["extension"]
|
||||||
end)
|
end)
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
|
@ -149,16 +272,6 @@ defmodule AshHqWeb.Pages.Docs do
|
||||||
{:ok, socket}
|
{:ok, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp selected_version(library, selected_versions) do
|
|
||||||
case Enum.find(library.versions, &(&1.id == selected_versions[library.id])) do
|
|
||||||
nil ->
|
|
||||||
nil
|
|
||||||
|
|
||||||
version ->
|
|
||||||
version.version
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp get_extensions(library, selected_versions) do
|
defp get_extensions(library, selected_versions) do
|
||||||
case Enum.find(library.versions, &(&1.id == selected_versions[library.id])) do
|
case Enum.find(library.versions, &(&1.id == selected_versions[library.id])) do
|
||||||
nil ->
|
nil ->
|
||||||
|
@ -171,8 +284,11 @@ defmodule AshHqWeb.Pages.Docs do
|
||||||
|
|
||||||
defp assign_library(socket) do
|
defp assign_library(socket) do
|
||||||
if !socket.assigns[:library] ||
|
if !socket.assigns[:library] ||
|
||||||
socket.assigns.params["library"] != socket.assigns.library.name do
|
socket.assigns.params["library"] != Routes.sanitize_name(socket.assigns.library.name) do
|
||||||
case Enum.find(socket.assigns.libraries, &(&1.name == socket.assigns.params["library"])) do
|
case Enum.find(
|
||||||
|
socket.assigns.libraries,
|
||||||
|
&(Routes.sanitize_name(&1.name) == socket.assigns.params["library"])
|
||||||
|
) do
|
||||||
nil ->
|
nil ->
|
||||||
assign(socket, library: nil, library_version: nil)
|
assign(socket, library: nil, library_version: nil)
|
||||||
|
|
||||||
|
@ -180,7 +296,10 @@ defmodule AshHqWeb.Pages.Docs do
|
||||||
socket =
|
socket =
|
||||||
if socket.assigns[:params]["version"] do
|
if socket.assigns[:params]["version"] do
|
||||||
library_version =
|
library_version =
|
||||||
Enum.find(library.versions, &(&1.version == socket.assigns[:params]["version"]))
|
Enum.find(
|
||||||
|
library.versions,
|
||||||
|
&(Routes.sanitize_name(&1.version) == socket.assigns[:params]["version"])
|
||||||
|
)
|
||||||
|
|
||||||
if library_version do
|
if library_version do
|
||||||
new_selected_versions =
|
new_selected_versions =
|
||||||
|
|
|
@ -26,8 +26,8 @@ defmodule AshHqWeb.Pages.Home do
|
||||||
<div>⌘ K</div>
|
<div>⌘ K</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<div class="pt-6 pb-6 w-full hidden md:block">
|
<div class="pt-6 pb-6 w-full hidden sm:block">
|
||||||
<div class="flex flex-row justify-center space-x-24 xl:space-x-32">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-10">
|
||||||
<CodeExample
|
<CodeExample
|
||||||
id="define-a-resource"
|
id="define-a-resource"
|
||||||
class="grow min-w-fit max-w-[1000px]"
|
class="grow min-w-fit max-w-[1000px]"
|
||||||
|
|
|
@ -1,34 +1,49 @@
|
||||||
defmodule AshHqWeb.Routes do
|
defmodule AshHqWeb.Routes do
|
||||||
def guide_link(library, version, guide) do
|
def guide_link(library, version, guide) do
|
||||||
"/docs/guides/#{library.name}/#{version}/#{guide}"
|
"/docs/guides/#{sanitize_name(library.name)}/#{sanitize_name(version)}/#{sanitize_name(guide)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def library_link(library, nil) do
|
||||||
|
"/docs/dsl/#{sanitize_name(library.name)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def library_link(library, name) do
|
def library_link(library, name) do
|
||||||
"/docs/dsl/#{library.name}/#{name}"
|
"/docs/dsl/#{sanitize_name(library.name)}/#{sanitize_name(name)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def extension_link(library, name, extension) do
|
def extension_link(library, name, extension) do
|
||||||
"/docs/dsl/#{library.name}/#{name}/#{extension}"
|
"/docs/dsl/#{sanitize_name(library.name)}/#{sanitize_name(name)}/#{sanitize_name(extension)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def doc_link(%AshHq.Docs.Guide{
|
def doc_link(%AshHq.Docs.Guide{
|
||||||
url_safe_name: url_safe_name,
|
url_safe_name: url_safe_name,
|
||||||
library_version: %{library_name: library_name, version: version}
|
library_version: %{library_name: library_name, version: version}
|
||||||
}) do
|
}) do
|
||||||
"/docs/guides/#{library_name}/#{version}/#{url_safe_name}"
|
"/docs/guides/#{sanitize_name(library_name)}/#{sanitize_name(version)}/#{url_safe_name}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def doc_link(%AshHq.Docs.LibraryVersion{library_name: library_name, version: version}) do
|
def doc_link(%AshHq.Docs.LibraryVersion{library_name: library_name, version: version}) do
|
||||||
"/docs/dsl/#{library_name}/#{version}"
|
"/docs/dsl/#{sanitize_name(library_name)}/#{sanitize_name(version)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def doc_link(%AshHq.Docs.Extension{
|
||||||
|
library_version: %{library_name: library_name, version: version},
|
||||||
|
name: name
|
||||||
|
}) do
|
||||||
|
"/docs/dsl/#{sanitize_name(library_name)}/#{sanitize_name(version)}/#{sanitize_name(name)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def doc_link(item) do
|
def doc_link(item) do
|
||||||
case item.path do
|
case item.path do
|
||||||
[] ->
|
[] ->
|
||||||
"/docs/dsl/#{item.library_name}/#{item.version_name}/#{item.extension_name}"
|
"/docs/dsl/#{sanitize_name(item.library_name)}/#{sanitize_name(item.version_name)}/#{sanitize_name(item.extension_name)}##{sanitize_name(item.name)}"
|
||||||
|
|
||||||
path ->
|
path ->
|
||||||
"/docs/dsl/#{item.library_name}/#{item.version_name}/#{item.extension_name}?path=#{Enum.join(path, ".")}"
|
"/docs/dsl/#{sanitize_name(item.library_name)}/#{sanitize_name(item.version_name)}/#{sanitize_name(item.extension_name)}##{Enum.map_join(path ++ [item.name], "-", &sanitize_name/1)}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sanitize_name(name) do
|
||||||
|
String.downcase(String.replace(name, ~r/[^A-Za-z0-9_]/, "-"))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,9 +7,11 @@
|
||||||
<%= csrf_meta_tag() %>
|
<%= csrf_meta_tag() %>
|
||||||
<%= live_title_tag assigns[:page_title] || "Ash Framework" %>
|
<%= live_title_tag assigns[:page_title] || "Ash Framework" %>
|
||||||
<link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/app.css")}/>
|
<link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/app.css")}/>
|
||||||
<script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body class="h-full">
|
<body class="h-full">
|
||||||
<%= @inner_content %>
|
<%= @inner_content %>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
||||||
|
<script>mermaid.init(".mermaid")</script>
|
||||||
|
<script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -29,9 +29,9 @@ defmodule AshHqWeb.AppViewLive do
|
||||||
<button id="search-button" class="hidden" phx-click={AshHqWeb.AppViewLive.toggle_search()} />
|
<button id="search-button" class="hidden" phx-click={AshHqWeb.AppViewLive.toggle_search()} />
|
||||||
<div
|
<div
|
||||||
id="main-container"
|
id="main-container"
|
||||||
class="h-full bg-white dark:bg-primary-black dark:text-silver-phoenix overflow-x-hidden"
|
class="h-screen flex flex-col bg-white dark:bg-primary-black dark:text-silver-phoenix overflow-x-hidden overflow-clip"
|
||||||
>
|
>
|
||||||
<div class="flex justify-between pt-4 px-4">
|
<div class={"flex justify-between pt-4 px-4", "w-full border-b bg-white dark:bg-primary-black pb-4 top-0": @live_action == :docs_dsl}>
|
||||||
<div class="flex flex-row align-baseline">
|
<div class="flex flex-row align-baseline">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<img class="h-10 hidden dark:block" src="/images/ash-framework-dark.png">
|
<img class="h-10 hidden dark:block" src="/images/ash-framework-dark.png">
|
||||||
|
@ -40,7 +40,7 @@ defmodule AshHqWeb.AppViewLive do
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row align-middle items-center space-x-2">
|
<div class="flex flex-row align-middle items-center space-x-2">
|
||||||
<a
|
<a
|
||||||
href="/docs/guides/ash/main/Getting-Started"
|
href="/docs/guides/ash/main/getting-started"
|
||||||
class="dark:text-gray-400 dark:hover:text-gray-200 hover:text-gray-600"
|
class="dark:text-gray-400 dark:hover:text-gray-200 hover:text-gray-600"
|
||||||
>Get Started</a>
|
>Get Started</a>
|
||||||
<div>|</div>
|
<div>|</div>
|
||||||
|
@ -198,9 +198,17 @@ defmodule AshHqWeb.AppViewLive do
|
||||||
js
|
js
|
||||||
|> JS.dispatch("js:noscroll-main", to: "#search-box")
|
|> JS.dispatch("js:noscroll-main", to: "#search-box")
|
||||||
|> JS.toggle(
|
|> JS.toggle(
|
||||||
in: "fade-in transition",
|
to: "#search-box",
|
||||||
out: "fade-out transition",
|
in: {
|
||||||
to: "#search-box"
|
"transition ease-in duration-100",
|
||||||
|
"opacity-0",
|
||||||
|
"opacity-100"
|
||||||
|
},
|
||||||
|
out: {
|
||||||
|
"transition ease-out duration-75",
|
||||||
|
"opacity-100",
|
||||||
|
"opacity-0"
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|> JS.dispatch("js:focus", to: "#search-input")
|
|> JS.dispatch("js:focus", to: "#search-input")
|
||||||
end
|
end
|
||||||
|
|
2
mix.exs
2
mix.exs
|
@ -38,7 +38,7 @@ defmodule AshHq.MixProject do
|
||||||
# {:ash_postgres, github: "ash-project/ash_postgres"},
|
# {:ash_postgres, github: "ash-project/ash_postgres"},
|
||||||
{:ash_postgres, path: "../ash_postgres"},
|
{:ash_postgres, path: "../ash_postgres"},
|
||||||
{:ash_phoenix, github: "ash-project/ash_phoenix"},
|
{:ash_phoenix, github: "ash-project/ash_phoenix"},
|
||||||
{:earmark, "~> 1.4"},
|
{:earmark, "~> 1.5.0-pre1"},
|
||||||
{:ecto, git: "https://github.com/elixir-ecto/ecto.git", override: true},
|
{:ecto, git: "https://github.com/elixir-ecto/ecto.git", override: true},
|
||||||
{:surface, "~> 0.7.3"},
|
{:surface, "~> 0.7.3"},
|
||||||
{:surface_heroicons, "~> 0.6.0"},
|
{:surface_heroicons, "~> 0.6.0"},
|
||||||
|
|
2
mix.lock
2
mix.lock
|
@ -12,7 +12,7 @@
|
||||||
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
|
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
|
||||||
"db_connection": {:hex, :db_connection, "2.4.2", "f92e79aff2375299a16bcb069a14ee8615c3414863a6fef93156aee8e86c2ff3", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4fe53ca91b99f55ea249693a0229356a08f4d1a7931d8ffa79289b145fe83668"},
|
"db_connection": {:hex, :db_connection, "2.4.2", "f92e79aff2375299a16bcb069a14ee8615c3414863a6fef93156aee8e86c2ff3", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4fe53ca91b99f55ea249693a0229356a08f4d1a7931d8ffa79289b145fe83668"},
|
||||||
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
|
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
|
||||||
"earmark": {:hex, :earmark, "1.4.24", "1923e201c3742af421860b983560967cc3e3deacc59c12966bc991a5435565e6", [:mix], [{:earmark_parser, "~> 1.4.25", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "9724242f241f2ad634756d8f2bb57a3d0992cedd10c51842fa655703b4da7c67"},
|
"earmark": {:hex, :earmark, "1.5.0-pre1", "e04aca73692bc3cda3429d6df99c8dae2bf76411e5e76d006a4bc04ac81ef1c1", [:mix], [{:earmark_parser, "~> 1.4.21", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "26ec0473ad2ef995b9672f89309a7a4952887f69b78cfc7af14e320bc6546bfa"},
|
||||||
"earmark_parser": {:hex, :earmark_parser, "1.4.25", "2024618731c55ebfcc5439d756852ec4e85978a39d0d58593763924d9a15916f", [:mix], [], "hexpm", "56749c5e1c59447f7b7a23ddb235e4b3defe276afc220a6227237f3efe83f51e"},
|
"earmark_parser": {:hex, :earmark_parser, "1.4.25", "2024618731c55ebfcc5439d756852ec4e85978a39d0d58593763924d9a15916f", [:mix], [], "hexpm", "56749c5e1c59447f7b7a23ddb235e4b3defe276afc220a6227237f3efe83f51e"},
|
||||||
"ecto": {:git, "https://github.com/elixir-ecto/ecto.git", "cda1172063753dea764e9c8ad80757dae5d1a4a7", []},
|
"ecto": {:git, "https://github.com/elixir-ecto/ecto.git", "cda1172063753dea764e9c8ad80757dae5d1a4a7", []},
|
||||||
"ecto_sql": {:hex, :ecto_sql, "3.7.2", "55c60aa3a06168912abf145c6df38b0295c34118c3624cf7a6977cd6ce043081", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0 or ~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c218ea62f305dcaef0b915fb56583195e7b91c91dcfb006ba1f669bfacbff2a"},
|
"ecto_sql": {:hex, :ecto_sql, "3.7.2", "55c60aa3a06168912abf145c6df38b0295c34118c3624cf7a6977cd6ce043081", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0 or ~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c218ea62f305dcaef0b915fb56583195e7b91c91dcfb006ba1f669bfacbff2a"},
|
||||||
|
|
|
@ -13,8 +13,8 @@ defmodule AshHq.Repo.Migrations.AddTsvectorIndices do
|
||||||
for {table, {header, text}} <- @config do
|
for {table, {header, text}} <- @config do
|
||||||
execute """
|
execute """
|
||||||
CREATE INDEX #{table}_search_index ON #{table} USING GIN((
|
CREATE INDEX #{table}_search_index ON #{table} USING GIN((
|
||||||
setweight(to_tsvector('simple', #{header}), 'A') ||
|
setweight(to_tsvector('english', #{header}), 'A') ||
|
||||||
setweight(to_tsvector('simple', #{text}), 'D')
|
setweight(to_tsvector('english', #{text}), 'D')
|
||||||
));
|
));
|
||||||
""",
|
""",
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in a new issue