Compare commits
No commits in common. "a05f289b5ef003c1208a3b348b8c21e56114babc" and "f2f4c0531d706a1894bcc0e0f1acfd6ee7d61c1c" have entirely different histories.
a05f289b5e
...
f2f4c0531d
7 changed files with 83 additions and 274 deletions
|
@ -3,12 +3,9 @@ defmodule FreediveWeb.HomeLive do
|
||||||
|
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<.block class="px-2 py-4">
|
<.section>
|
||||||
<.panel is-info>
|
<.panel is-info>
|
||||||
<.panel_heading>
|
<.panel_heading>Home</.panel_heading>
|
||||||
Home
|
|
||||||
</.panel_heading>
|
|
||||||
|
|
||||||
<.panel_tabs is-hidden-mobile>
|
<.panel_tabs is-hidden-mobile>
|
||||||
<a class="is-active">All</a>
|
<a class="is-active">All</a>
|
||||||
<a>Compute</a>
|
<a>Compute</a>
|
||||||
|
@ -16,22 +13,21 @@ defmodule FreediveWeb.HomeLive do
|
||||||
<a>Network</a>
|
<a>Network</a>
|
||||||
<a>System</a>
|
<a>System</a>
|
||||||
</.panel_tabs>
|
</.panel_tabs>
|
||||||
|
|
||||||
<.panel_tabs is-hidden-tablet>
|
<.panel_tabs is-hidden-tablet>
|
||||||
<a title="All" is-active>
|
<a class="is-active" title="All">
|
||||||
<.icon for="all" color="auto" />
|
<.icon for="infinity" color="auto" />
|
||||||
</a>
|
</a>
|
||||||
<a title="Compute">
|
<a title="Compute">
|
||||||
<.icon for="compute" color="auto" />
|
<.icon for="binary" color="auto" />
|
||||||
</a>
|
</a>
|
||||||
<a title="Storage">
|
<a title="Storage">
|
||||||
<.icon for="storage" color="auto" />
|
<.icon for="hard-drive" color="auto" />
|
||||||
</a>
|
</a>
|
||||||
<a title="Network">
|
<a title="Network">
|
||||||
<.icon for="network" color="auto" />
|
<.icon for="earth" color="auto" />
|
||||||
</a>
|
</a>
|
||||||
<a title="System">
|
<a title="System">
|
||||||
<.icon for="system" color="auto" />
|
<.icon for="bot" color="auto" />
|
||||||
</a>
|
</a>
|
||||||
</.panel_tabs>
|
</.panel_tabs>
|
||||||
|
|
||||||
|
@ -44,10 +40,11 @@ defmodule FreediveWeb.HomeLive do
|
||||||
name="search"
|
name="search"
|
||||||
value={@query}
|
value={@query}
|
||||||
/>
|
/>
|
||||||
<.icon for="search" size="1.5rem" aria-hidden="true" is-left />
|
<span class="icon is-left">
|
||||||
|
<Lucideicons.search aria-hidden="true" />
|
||||||
|
</span>
|
||||||
</.control>
|
</.control>
|
||||||
</.panel_block>
|
</.panel_block>
|
||||||
|
|
||||||
<.link patch={~p"/services"} class="panel-block pt-1">
|
<.link patch={~p"/services"} class="panel-block pt-1">
|
||||||
<span class="panel-icon">
|
<span class="panel-icon">
|
||||||
<.icon for="puzzle" color="auto" aria-hidden="true" />
|
<.icon for="puzzle" color="auto" aria-hidden="true" />
|
||||||
|
@ -67,32 +64,12 @@ defmodule FreediveWeb.HomeLive do
|
||||||
<span class="mt-2 ml-2">Software updates</span>
|
<span class="mt-2 ml-2">Software updates</span>
|
||||||
</.link>
|
</.link>
|
||||||
</.panel>
|
</.panel>
|
||||||
</.block>
|
|
||||||
<.section>
|
|
||||||
<.box>
|
|
||||||
<.button phx-click="color" phx-value-enable="true">
|
|
||||||
Color
|
|
||||||
</.button>
|
|
||||||
<.button phx-click="color" phx-value-enable="false">
|
|
||||||
Grayscale
|
|
||||||
</.button>
|
|
||||||
</.box>
|
|
||||||
</.section>
|
</.section>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
def mount(_params, _session, socket) do
|
def mount(_params, _session, socket) do
|
||||||
socket = assign(socket, query: "all")
|
socket = assign(socket, query: "")
|
||||||
{:ok, socket}
|
{:ok, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_event("color", %{"enable" => "true"}, socket) do
|
|
||||||
Freedive.Features.enable(:colorhash)
|
|
||||||
{:noreply, assign(socket, query: "color")}
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("color", %{"enable" => "false"}, socket) do
|
|
||||||
Freedive.Features.disable(:colorhash)
|
|
||||||
{:noreply, assign(socket, query: "grayscale")}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,80 +1,79 @@
|
||||||
defmodule FreediveWeb.LiliformLive do
|
defmodule FreediveWeb.LiliformLive do
|
||||||
defmacro __using__(opts) do
|
|
||||||
quote location: :keep, bind_quoted: [opts: opts] do
|
|
||||||
use FreediveWeb, :live_view
|
use FreediveWeb, :live_view
|
||||||
@behaviour FreediveWeb.LiliformLive
|
|
||||||
@filters_all [
|
|
||||||
%{
|
|
||||||
title: "All",
|
|
||||||
icon: "all",
|
|
||||||
active: false,
|
|
||||||
key: :all
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
def(mount(_params, _session, socket)) do
|
def render(assigns) do
|
||||||
items = items()
|
~H"""
|
||||||
filters = filters()
|
<.block class="px-2 py-4">
|
||||||
socket = assign(socket, :opts, Keyword.get(unquote(opts), :opts, []))
|
<.panel is-info>
|
||||||
socket = assign(socket, :items_all, items)
|
<.panel_heading>
|
||||||
|
Home
|
||||||
|
</.panel_heading>
|
||||||
|
|
||||||
socket =
|
<.panel_tabs is-hidden-mobile>
|
||||||
assign(
|
<a class="is-active">All</a>
|
||||||
socket,
|
<a>Compute</a>
|
||||||
:items,
|
<a>Storage</a>
|
||||||
FreediveWeb.LiliformLive.filter(
|
<a>Network</a>
|
||||||
items,
|
<a>System</a>
|
||||||
FreediveWeb.LiliformLive.get_active_filter(filters)
|
</.panel_tabs>
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
socket = assign(socket, :filters, @filters_all ++ filters)
|
<.panel_tabs is-hidden-tablet>
|
||||||
socket = assign(socket, :query, "")
|
<a title="All" is-active>
|
||||||
|
<.icon for="all" color="auto" />
|
||||||
|
</a>
|
||||||
|
<a title="Compute">
|
||||||
|
<.icon for="compute" color="auto" />
|
||||||
|
</a>
|
||||||
|
<a title="Storage">
|
||||||
|
<.icon for="storage" color="auto" />
|
||||||
|
</a>
|
||||||
|
<a title="Network">
|
||||||
|
<.icon for="network" color="auto" />
|
||||||
|
</a>
|
||||||
|
<a title="System">
|
||||||
|
<.icon for="system" color="auto" />
|
||||||
|
</a>
|
||||||
|
</.panel_tabs>
|
||||||
|
|
||||||
|
<.panel_block>
|
||||||
|
<.control has-icons-left>
|
||||||
|
<input
|
||||||
|
class="input is-info"
|
||||||
|
type="text"
|
||||||
|
placeholder="Search"
|
||||||
|
name="search"
|
||||||
|
value={@query}
|
||||||
|
/>
|
||||||
|
<.icon for="search" size="1.5rem" aria-hidden="true" is-left />
|
||||||
|
</.control>
|
||||||
|
</.panel_block>
|
||||||
|
</.panel>
|
||||||
|
</.block>
|
||||||
|
<.section>
|
||||||
|
<.box>
|
||||||
|
<.button phx-click="color" phx-value-enable="true">
|
||||||
|
Color
|
||||||
|
</.button>
|
||||||
|
<.button phx-click="color" phx-value-enable="false">
|
||||||
|
Grayscale
|
||||||
|
</.button>
|
||||||
|
</.box>
|
||||||
|
</.section>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
def mount(_params, _session, socket) do
|
||||||
|
socket = assign(socket, query: "all")
|
||||||
{:ok, socket}
|
{:ok, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
def(handle_event("search", %{"value" => query}, socket)) do
|
def handle_event("color", %{"enable" => "true"}, socket) do
|
||||||
items = search(query)
|
Freedive.Features.enable(:colorhash)
|
||||||
socket = assign(socket, :items, items)
|
{:noreply, assign(socket, query: "color")}
|
||||||
{:noreply, socket}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def(handle_event("filter", %{"key" => key}, socket)) do
|
def handle_event("color", %{"enable" => "false"}, socket) do
|
||||||
key = String.to_existing_atom(key)
|
Freedive.Features.disable(:colorhash)
|
||||||
items = FreediveWeb.LiliformLive.filter(socket.assigns.items_all, key)
|
{:noreply, assign(socket, query: "grayscale")}
|
||||||
socket = assign(socket, :items, items)
|
|
||||||
|
|
||||||
socket =
|
|
||||||
assign(
|
|
||||||
socket,
|
|
||||||
:filters,
|
|
||||||
Enum.map(socket.assigns.filters, fn filter ->
|
|
||||||
Map.put(filter, :active, filter.key == key)
|
|
||||||
end)
|
|
||||||
)
|
|
||||||
|
|
||||||
{:noreply, socket}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@callback items() :: [map]
|
|
||||||
@callback filters() :: [map]
|
|
||||||
@callback search(query :: String.t()) :: [map]
|
|
||||||
|
|
||||||
def filter(items, key) do
|
|
||||||
case key do
|
|
||||||
:all ->
|
|
||||||
items
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
Enum.filter(items, fn item ->
|
|
||||||
Map.get(item, key) == true
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_active_filter(filters) do
|
|
||||||
filters |> Enum.find(& &1.active) |> Map.get(:key)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
defmodule FreediveWeb.ServiceLive do
|
|
||||||
use FreediveWeb.LiliformLive
|
|
||||||
|
|
||||||
def render(assigns) do
|
|
||||||
~H"""
|
|
||||||
<.block class="px-2 py-4">
|
|
||||||
<.page name="Services" filters={@filters}>
|
|
||||||
<FreediveWeb.ServiceLive.Item.items_block items={@items} />
|
|
||||||
</.page>
|
|
||||||
</.block>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
def items() do
|
|
||||||
[
|
|
||||||
%{
|
|
||||||
name: "sshd",
|
|
||||||
path: "/services/ssh",
|
|
||||||
icon: "blocks",
|
|
||||||
description: "Secure Shell Daemon",
|
|
||||||
enabled: true,
|
|
||||||
running: true
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
name: "pf",
|
|
||||||
path: "/services/pf",
|
|
||||||
icon: "shield",
|
|
||||||
description: "Packet Filter",
|
|
||||||
enabled: true,
|
|
||||||
running: true
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
name: "ntpdate",
|
|
||||||
path: "/services/ntp",
|
|
||||||
icon: "clock",
|
|
||||||
description: "Network Time Protocol Daemon",
|
|
||||||
enabled: true,
|
|
||||||
running: false
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
name: "httpd",
|
|
||||||
path: "/services/httpd",
|
|
||||||
icon: "globe",
|
|
||||||
description: "Hypertext Transfer Protocol Daemon",
|
|
||||||
enabled: false,
|
|
||||||
running: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
def filters() do
|
|
||||||
[
|
|
||||||
%{
|
|
||||||
title: "Running",
|
|
||||||
key: :running,
|
|
||||||
icon: "circle-play",
|
|
||||||
active: true
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
title: "Enabled",
|
|
||||||
key: :enabled,
|
|
||||||
icon: "circle-check",
|
|
||||||
active: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
def search(query) do
|
|
||||||
items()
|
|
||||||
|> Enum.filter(fn item ->
|
|
||||||
String.contains?(String.downcase(item.name), String.downcase(query))
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defmodule FreediveWeb.ServiceLive.Item do
|
|
||||||
use Liliform.Component
|
|
||||||
import Liliform.Icon
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Returns a list of items.
|
|
||||||
"""
|
|
||||||
attr :items, :list, default: [], doc: "items"
|
|
||||||
|
|
||||||
def items_block(assigns) do
|
|
||||||
~H"""
|
|
||||||
<%= for item <- @items do %>
|
|
||||||
<.link patch={item.path} class="panel-block pt-1">
|
|
||||||
<span class="panel-icon">
|
|
||||||
<.icon for={item.icon} color="auto" aria-hidden="true" />
|
|
||||||
</span>
|
|
||||||
<div class="mt-2 ml-2"><%= item.name %></div>
|
|
||||||
</.link>
|
|
||||||
<% end %>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -69,7 +69,7 @@ defmodule FreediveWeb.Router do
|
||||||
live_session :require_authenticated_user,
|
live_session :require_authenticated_user,
|
||||||
on_mount: [{FreediveWeb.UserAuth, :ensure_authenticated}] do
|
on_mount: [{FreediveWeb.UserAuth, :ensure_authenticated}] do
|
||||||
live "/", HomeLive
|
live "/", HomeLive
|
||||||
live "/services", ServiceLive
|
live "/liliform", LiliformLive
|
||||||
live "/users/settings", UserSettingsLive, :edit
|
live "/users/settings", UserSettingsLive, :edit
|
||||||
live "/users/settings/confirm_email/:token", UserSettingsLive, :confirm_email
|
live "/users/settings/confirm_email/:token", UserSettingsLive, :confirm_email
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,7 +15,6 @@ defmodule Liliform do
|
||||||
import Liliform.Label
|
import Liliform.Label
|
||||||
import Liliform.Media
|
import Liliform.Media
|
||||||
import Liliform.Navbar
|
import Liliform.Navbar
|
||||||
import Liliform.Page
|
|
||||||
import Liliform.Panel
|
import Liliform.Panel
|
||||||
import Liliform.Section
|
import Liliform.Section
|
||||||
import Liliform.SimpleForm
|
import Liliform.SimpleForm
|
||||||
|
|
|
@ -21,6 +21,7 @@ defmodule Liliform.Colorhash do
|
||||||
"""
|
"""
|
||||||
def hsl(input, raw: true) do
|
def hsl(input, raw: true) do
|
||||||
if Features.enabled?(:colorhash) do
|
if Features.enabled?(:colorhash) do
|
||||||
|
Logger.debug("Colorhash enabled")
|
||||||
input = String.downcase(input) <> @seed
|
input = String.downcase(input) <> @seed
|
||||||
hash = :erlang.phash2(input, 2_147_483_647)
|
hash = :erlang.phash2(input, 2_147_483_647)
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ defmodule Liliform.Colorhash do
|
||||||
|
|
||||||
{hue, saturation, lightness}
|
{hue, saturation, lightness}
|
||||||
else
|
else
|
||||||
|
Logger.debug("Colorhash disabled")
|
||||||
@default_color
|
@default_color
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
defmodule Liliform.Page do
|
|
||||||
use Liliform.Component
|
|
||||||
import Liliform.Icon
|
|
||||||
import Liliform.Panel
|
|
||||||
import Liliform.Control
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Renders a panel as page.
|
|
||||||
"""
|
|
||||||
attr :name, :string, required: true, doc: "page name"
|
|
||||||
attr :class, :string, default: "", doc: "additional classes"
|
|
||||||
attr :filters, :list, default: [], doc: "filters"
|
|
||||||
attr :query, :string, default: "", doc: "search query"
|
|
||||||
attr :rest, :global
|
|
||||||
|
|
||||||
slot :inner_block, required: true
|
|
||||||
|
|
||||||
def page(assigns) do
|
|
||||||
assigns =
|
|
||||||
assigns
|
|
||||||
|> set_bulma_classes()
|
|
||||||
|
|
||||||
~H"""
|
|
||||||
<.panel class={@class} {@rest} is-info>
|
|
||||||
<.panel_heading>
|
|
||||||
<%= @name %>
|
|
||||||
</.panel_heading>
|
|
||||||
|
|
||||||
<.panel_tabs is-hidden-mobile>
|
|
||||||
<%= for filter <- @filters do %>
|
|
||||||
<a
|
|
||||||
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>
|
|
||||||
<%= for filter <- @filters do %>
|
|
||||||
<a
|
|
||||||
title={filter.title}
|
|
||||||
class={if filter.active, do: "is-active"}
|
|
||||||
phx-click="filter"
|
|
||||||
phx-value-key={filter.key}
|
|
||||||
>
|
|
||||||
<.icon for={filter.icon} color="auto" />
|
|
||||||
</a>
|
|
||||||
<% end %>
|
|
||||||
</.panel_tabs>
|
|
||||||
|
|
||||||
<.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>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in a new issue