Compare commits
No commits in common. "c1c428d524e155b2b42faa8a64b2edde4dca88b1" and "09213f5294ef7b7f0e5ae6e7bea31a7cb4369841" have entirely different histories.
c1c428d524
...
09213f5294
6 changed files with 67 additions and 204 deletions
|
@ -7,7 +7,3 @@
|
||||||
height: 256px;
|
height: 256px;
|
||||||
width: 256px;
|
width: 256px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-fullwidth {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in a new issue