defmodule AshHqWeb.AppViewLive do use Surface.LiveView, container: {:div, class: "h-full"} alias AshHqWeb.Components.{Search, SearchBar} alias AshHqWeb.Pages.{Docs, Home} alias Phoenix.LiveView.JS require Ash.Query data configured_theme, :string, default: :system data searching, :boolean, default: false data selected_versions, :map, default: %{} data libraries, :list, default: [] data selected_types, :map, default: %{} data sidebar_state, :map, default: %{} def render(assigns) do ~F"""
{#case @live_action} {#match :home} {#match :docs_dsl} {/case} """ end def handle_params(params, uri, socket) do {:noreply, assign(socket, params: params, uri: uri)} end def handle_event("collapse_sidebar", %{"id" => id}, socket) do new_state = Map.put(socket.assigns.sidebar_state, id, "closed") {:noreply, socket |> assign(:sidebar_state, new_state) |> push_event("js:sidebar-state", new_state)} end def handle_event("expand_sidebar", %{"id" => id}, socket) do new_state = Map.put(socket.assigns.sidebar_state, id, "open") {:noreply, socket |> assign(:sidebar_state, new_state) |> push_event("sidebar-state", new_state)} end def handle_event("change-versions", %{"versions" => versions}, socket) do {:noreply, socket |> assign(:selected_versions, versions) |> load_docs() |> push_event("selected-versions", versions)} end def handle_event("change-types", %{"types" => types}, socket) do types = types |> Enum.filter(fn {_, value} -> value == "true" end) |> Enum.map(&elem(&1, 0)) {:noreply, socket |> assign( :selected_types, types ) |> push_event("selected-types", %{types: types})} end def handle_event("toggle_theme", _, socket) do theme = case socket.assigns.configured_theme do "light" -> "dark" "dark" -> "light" end {:noreply, socket |> assign(:configured_theme, theme) |> push_event("set_theme", %{theme: theme})} end def handle_info({:new_sidebar_state, new_state}, socket) do {:noreply, socket |> assign(:sidebar_state, new_state) |> push_event("sidebar-state", new_state)} end defp load_docs(socket) do new_libraries = socket.assigns.libraries |> Enum.map(fn library -> Map.update!(library, :versions, fn versions -> Enum.map(versions, fn version -> if version.id == socket.assigns[:selected_versions][library.id] do dsls_query = Ash.Query.sort(AshHq.Docs.Dsl, order: :asc) options_query = Ash.Query.sort(AshHq.Docs.Option, order: :asc) functions_query = Ash.Query.sort(AshHq.Docs.Function, name: :asc, arity: :asc) modules_query = AshHq.Docs.Module |> Ash.Query.sort(order: :asc) |> Ash.Query.load(functions: functions_query) extensions_query = AshHq.Docs.Extension |> Ash.Query.sort(order: :asc) |> Ash.Query.load(options: options_query, dsls: dsls_query) AshHq.Docs.load!(version, extensions: extensions_query, guides: :url_safe_name, modules: modules_query ) else version end end) end) end) assign(socket, :libraries, new_libraries) end def mount(_params, session, socket) do configured_theme = session["theme"] || "dark" configured_library_versions = case session["selected_versions"] do nil -> %{} "" -> %{} value -> value |> String.split(",") |> Map.new(fn str -> str |> String.split(":") |> List.to_tuple() end) end all_types = AshHq.Docs.Extensions.Search.Types.types() selected_types = case session["selected_types"] do nil -> AshHq.Docs.Extensions.Search.Types.types() types -> types |> String.split(",") |> Enum.filter(&(&1 in all_types)) end sidebar_state = case session["sidebar_state"] do nil -> %{} value -> value |> String.split(",") |> Map.new(fn str -> str |> String.split(":") |> List.to_tuple() end) end socket = socket |> assign(:selected_versions, configured_library_versions) |> AshPhoenix.LiveView.keep_live( :libraries, fn _socket -> versions_query = AshHq.Docs.LibraryVersion |> Ash.Query.sort(version: :desc) |> Ash.Query.filter(processed == true) |> Ash.Query.deselect(:data) AshHq.Docs.Library.read!(load: [versions: versions_query]) end, after_fetch: fn results, socket -> selected_versions = Enum.reduce(results, socket.assigns[:selected_versions] || %{}, fn library, acc -> case Enum.at(library.versions, 0) do nil -> acc version -> Map.put_new(acc, library.id, version.id) end end) socket |> assign( :selected_versions, selected_versions ) |> assign( :selected_types, selected_types ) |> push_event("selected_versions", selected_versions) |> push_event("selected_types", %{types: selected_types}) end ) |> load_docs() {:ok, assign(socket, configured_theme: configured_theme, sidebar_state: sidebar_state)} end def toggle_search(js \\ %JS{}) do js |> JS.dispatch("js:noscroll-main", to: "#search-box") |> JS.toggle( to: "#search-box", in: { "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") end def close_search(js \\ %JS{}) do js |> JS.dispatch("js:noscroll-main", to: "#search-box") |> JS.hide( transition: "fade-out", to: "#search-box" ) |> JS.dispatch("js:focus", to: "#search-input") end end