Compare commits

..

No commits in common. "c1c428d524e155b2b42faa8a64b2edde4dca88b1" and "09213f5294ef7b7f0e5ae6e7bea31a7cb4369841" have entirely different histories.

6 changed files with 67 additions and 204 deletions

View file

@ -6,8 +6,4 @@
.size-256 { .size-256 {
height: 256px; height: 256px;
width: 256px; width: 256px;
}
.is-fullwidth {
width: 100%;
} }

View file

@ -17,8 +17,6 @@ defmodule FreediveWeb.LiliformLive do
filters = filters() filters = filters()
socket = assign(socket, :opts, Keyword.get(unquote(opts), :opts, [])) socket = assign(socket, :opts, Keyword.get(unquote(opts), :opts, []))
socket = assign(socket, :items_all, items) socket = assign(socket, :items_all, items)
socket = assign(socket, :selected_item, nil)
socket = assign(socket, :details, nil)
socket = socket =
assign( assign(
@ -36,28 +34,8 @@ defmodule FreediveWeb.LiliformLive do
end end
def(handle_event("search", %{"value" => query}, socket)) do def(handle_event("search", %{"value" => query}, socket)) do
filtered_items = items = search(query)
FreediveWeb.LiliformLive.filter( socket = assign(socket, :items, items)
socket.assigns.items_all,
FreediveWeb.LiliformLive.get_active_filter(socket.assigns.filters)
)
searched_items = search(filtered_items, query)
socket = assign(socket, :items, searched_items)
socket =
case Kernel.length(Map.keys(searched_items)) == 1 do
true ->
IO.inspect(Map.keys(searched_items) |> List.first())
assign(socket, %{
selected_item: Map.get(searched_items, Map.keys(searched_items) |> List.first()),
details: true
})
false ->
assign(socket, %{selected_item: nil, details: nil})
end
{:noreply, socket} {:noreply, socket}
end end
@ -70,45 +48,19 @@ defmodule FreediveWeb.LiliformLive do
assign( assign(
socket, socket,
:filters, :filters,
FreediveWeb.LiliformLive.update_active_filter(socket.assigns.filters, key) Enum.map(socket.assigns.filters, fn filter ->
Map.put(filter, :active, filter.key == key)
end)
) )
{:noreply, socket} {:noreply, socket}
end end
def(handle_event("tap", %{"name" => item_name}, socket)) do
# 1 tap to select, 2 taps for details
item = socket.assigns.items[item_name]
socket =
case socket.assigns.selected_item do
nil ->
assign(socket, :selected_item, item)
selected ->
case selected.name == item_name do
true ->
case socket.assigns.details do
nil ->
assign(socket, :details, true)
_ ->
assign(socket, %{selected_item: item, details: nil})
end
false ->
assign(socket, %{selected_item: item, details: nil})
end
end
{:noreply, socket}
end
end end
end end
@callback items() :: [map] @callback items() :: [map]
@callback filters() :: [map] @callback filters() :: [map]
@callback search(items :: [map], query :: String.t()) :: [map] @callback search(query :: String.t()) :: [map]
def filter(items, key) do def filter(items, key) do
case key do case key do
@ -116,20 +68,13 @@ defmodule FreediveWeb.LiliformLive do
items items
_ -> _ ->
items Enum.filter(items, fn item ->
|> Enum.filter(fn {_name, item} -> item[key] == true end) Map.get(item, key) == true
|> Enum.into(%{}, fn {name, item} -> {name, item} end) end)
end end
end end
def get_active_filter(filters) do def get_active_filter(filters) do
filters |> Enum.find(& &1.active) |> Map.get(:key) filters |> Enum.find(& &1.active) |> Map.get(:key)
end end
def update_active_filter(filters, key) do
filters
|> Enum.map(fn filter ->
Map.put(filter, :active, filter.key == key)
end)
end
end end

View file

@ -3,19 +3,15 @@ defmodule FreediveWeb.ServiceLive do
def render(assigns) do def render(assigns) do
~H""" ~H"""
<.page name="Services" filters={@filters} details={@details}> <.page name="Services" filters={@filters}>
<FreediveWeb.ServiceLive.Components.items_block <FreediveWeb.ServiceLive.Item.items_block items={@items} />
items={@items}
selected_item={@selected_item}
details={@details}
/>
</.page> </.page>
""" """
end end
def items() do def items() do
%{ [
"sshd" => %{ %{
name: "sshd", name: "sshd",
path: "/services/ssh", path: "/services/ssh",
icon: "blocks", icon: "blocks",
@ -23,7 +19,7 @@ defmodule FreediveWeb.ServiceLive do
enabled: true, enabled: true,
running: true running: true
}, },
"pf" => %{ %{
name: "pf", name: "pf",
path: "/services/pf", path: "/services/pf",
icon: "shield", icon: "shield",
@ -31,7 +27,7 @@ defmodule FreediveWeb.ServiceLive do
enabled: true, enabled: true,
running: true running: true
}, },
"ntpdate" => %{ %{
name: "ntpdate", name: "ntpdate",
path: "/services/ntp", path: "/services/ntp",
icon: "clock", icon: "clock",
@ -39,7 +35,7 @@ defmodule FreediveWeb.ServiceLive do
enabled: true, enabled: true,
running: false running: false
}, },
"httpd" => %{ %{
name: "httpd", name: "httpd",
path: "/services/httpd", path: "/services/httpd",
icon: "globe", icon: "globe",
@ -47,7 +43,7 @@ defmodule FreediveWeb.ServiceLive do
enabled: false, enabled: false,
running: false running: false
} }
} ]
end end
def filters() do def filters() do
@ -67,73 +63,27 @@ defmodule FreediveWeb.ServiceLive do
] ]
end end
def search(items, query) do def search(query) do
items items()
|> Enum.filter(fn {name, _item} -> |> Enum.filter(fn item ->
String.contains?(String.downcase(name), String.downcase(query)) String.contains?(String.downcase(item.name), String.downcase(query))
end) end)
|> Enum.into(%{}, fn {name, item} -> {name, item} end)
end end
end end
defmodule FreediveWeb.ServiceLive.Components do defmodule FreediveWeb.ServiceLive.Item do
use Liliform.Component use Liliform.Component
import Liliform.Icon import Liliform.Icon
import Liliform.Panel
import Liliform.Title
@doc """ @doc """
Returns items as panel-blocks. Returns items as panel-blocks.
""" """
attr :items, :list, default: [], doc: "items" attr :items, :list, default: [], doc: "items"
attr :selected_item, :string, default: nil, doc: "selected item"
attr :details, :string, default: nil, doc: "details"
def items_block(%{details: true} = assigns) do
~H"""
<.link
class="panel-block pt-1 has-background-light"
phx-click="tap"
phx-value-name={@selected_item.name}
>
<span class="panel-icon">
<.icon for="arrow-left" aria-hidden="true" has-text-dark />
</span>
<div class="mt-2 ml-2">Back</div>
</.link>
<.panel_block_div>
<div class="column is-narrow">
<.icon for={@selected_item.name} color="auto" aria-hidden="true" />
</div>
<div class="columns is-vcentered is-fullwidth">
<div class="column is-narrow">
<.title>
<%= @selected_item.name %>
</.title>
</div>
<div class="column">
<.subtitle>
<%= @selected_item.description %>
</.subtitle>
</div>
<div class="column is-narrow">
<.icon for="running" color="auto" aria-hidden="true" />
<.icon for="enabled" color="auto" aria-hidden="true" />
</div>
</div>
</.panel_block_div>
"""
end
def items_block(assigns) do def items_block(assigns) do
~H""" ~H"""
<%= for {_name, item} <- @items do %> <%= for item <- @items do %>
<.link <.link patch={item.path} class="panel-block pt-1">
class={"panel-block pt-1 #{if @selected_item != nil and @selected_item.name == item.name, do: "has-background-info-light"}"}
phx-click="tap"
phx-value-name={item.name}
>
<span class="panel-icon"> <span class="panel-icon">
<.icon for={item.icon} color="auto" aria-hidden="true" /> <.icon for={item.icon} color="auto" aria-hidden="true" />
</span> </span>

View file

@ -135,12 +135,6 @@ defmodule Liliform.Icon do
"system" -> :bot "system" -> :bot
"account" -> :user "account" -> :user
"all" -> :infinity "all" -> :infinity
"pf" -> :shield
"sshd" -> :lock
"ntpdate" -> :clock
"httpd" -> :globe
"running" -> :circle_play
"enabled" -> :circle_check
lucide_name -> String.to_atom(lucide_name) lucide_name -> String.to_atom(lucide_name)
end end
end end

View file

@ -11,7 +11,6 @@ defmodule Liliform.Page do
attr :name, :string, required: true, doc: "page name" attr :name, :string, required: true, doc: "page name"
attr :class, :string, default: "", doc: "additional classes" attr :class, :string, default: "", doc: "additional classes"
attr :filters, :list, default: [], doc: "filters" attr :filters, :list, default: [], doc: "filters"
attr :details, :string, default: nil, doc: "details"
attr :query, :string, default: "", doc: "search query" attr :query, :string, default: "", doc: "search query"
attr :rest, :global attr :rest, :global
@ -24,52 +23,52 @@ defmodule Liliform.Page do
~H""" ~H"""
<.block class="px-2 py-4"> <.block class="px-2 py-4">
<.panel class={@class} {@rest} is-info>
<.panel_heading>
<%= @name %>
</.panel_heading>
<%= if @details == nil do %> <.panel class={@class} {@rest} is-info>
<.panel_tabs is-hidden-mobile> <.panel_heading>
<%= for filter <- @filters do %> <%= @name %>
<a </.panel_heading>
class={if filter.active, do: "is-active"}
phx-click="filter"
phx-value-key={filter.key}
>
<%= filter.title %>
</a>
<% end %>
</.panel_tabs>
<.panel_tabs is-hidden-tablet> <.panel_tabs is-hidden-mobile>
<%= for filter <- @filters do %> <%= for filter <- @filters do %>
<a <a
title={filter.title} class={if filter.active, do: "is-active"}
class={if filter.active, do: "is-active"} phx-click="filter"
phx-click="filter" phx-value-key={filter.key}
phx-value-key={filter.key} >
> <%= filter.title %>
<.icon for={filter.icon} color="auto" /> </a>
</a>
<% end %>
</.panel_tabs>
<% end %> <% end %>
<.panel_block> </.panel_tabs>
<.control has-icons-left>
<input <.panel_tabs is-hidden-tablet>
class="input is-info" <%= for filter <- @filters do %>
type="text" <a
placeholder="Search" title={filter.title}
name="search" class={if filter.active, do: "is-active"}
value={@query} phx-click="filter"
phx-keyup="search" phx-value-key={filter.key}
/> >
<.icon for="search" size="1.5rem" aria-hidden="true" is-left /> <.icon for={filter.icon} color="auto" />
</.control> </a>
</.panel_block> <% end %>
<%= render_slot(@inner_block) %> </.panel_tabs>
</.panel>
<.panel_block>
<.control has-icons-left>
<input
class="input is-info"
type="text"
placeholder="Search"
name="search"
value={@query}
phx-keyup="search"
/>
<.icon for="search" size="1.5rem" aria-hidden="true" is-left />
</.control>
</.panel_block>
<%= render_slot(@inner_block) %>
</.panel>
</.block> </.block>
""" """
end end

View file

@ -54,26 +54,6 @@ defmodule Liliform.Panel do
assigns assigns
|> set_bulma_classes() |> set_bulma_classes()
~H"""
<a class={["panel-block", @class]} {@rest}>
<%= render_slot(@inner_block) %>
</a>
"""
end
@doc """
Renders a panel-block-div.
"""
attr :class, :string, default: "", doc: "additional classes"
attr :rest, :global
slot :inner_block, required: true
def panel_block_div(assigns) do
assigns =
assigns
|> set_bulma_classes()
~H""" ~H"""
<div class={["panel-block", @class]} {@rest}> <div class={["panel-block", @class]} {@rest}>
<%= render_slot(@inner_block) %> <%= render_slot(@inner_block) %>
@ -81,7 +61,6 @@ defmodule Liliform.Panel do
""" """
end end
@doc """ @doc """
Renders a panel-tabs. Renders a panel-tabs.
""" """