rename to memex

This commit is contained in:
2022-07-25 19:31:54 -04:00
parent 65ec4286da
commit 1a423f703b
122 changed files with 416 additions and 416 deletions

View File

@ -0,0 +1,50 @@
defmodule MemexWeb.Components.InviteCard do
@moduledoc """
Display card for an invite
"""
use MemexWeb, :component
alias MemexWeb.Endpoint
def invite_card(assigns) do
~H"""
<div class="mx-4 my-2 px-8 py-4 flex flex-col justify-center items-center space-y-4
border border-gray-400 rounded-lg shadow-lg hover:shadow-md
transition-all duration-300 ease-in-out">
<h1 class="title text-xl">
<%= @invite.name %>
</h1>
<%= if @invite.disabled_at |> is_nil() do %>
<h2 class="title text-md">
<%= gettext("Uses Left:") %>
<%= @invite.uses_left || "Unlimited" %>
</h2>
<% else %>
<h2 class="title text-md">
<%= gettext("Invite Disabled") %>
</h2>
<% end %>
<div class="flex flex-row flex-wrap justify-center items-center">
<code
id={"code-#{@invite.id}"}
class="mx-2 my-1 text-xs px-4 py-2 rounded-lg text-center break-all text-gray-100 bg-primary-800"
>
<%= Routes.user_registration_url(Endpoint, :new, invite: @invite.token) %>
</code>
<%= if @code_actions do %>
<%= render_slot(@code_actions) %>
<% end %>
</div>
<%= if @inner_block do %>
<div class="flex space-x-4 justify-center items-center">
<%= render_slot(@inner_block) %>
</div>
<% end %>
</div>
"""
end
end

View File

@ -0,0 +1,87 @@
defmodule MemexWeb.Components.TableComponent do
@moduledoc """
Livecomponent that presents a resortable table
It takes the following required assigns:
- `:columns`: An array of maps containing the following keys
- `:label`: A gettext'd or otherwise user-facing string label for the
column. Can be nil
- `:key`: A string key used for sorting
- `:class`: Extra classes to be applied to the column element, if desired.
Optional
- `:sortable`: If false, will prevent the user from sorting with it.
Optional
- `:values`: An array of maps containing data for each row. Each map is
string-keyed with the associated column key to the following values:
- A single element, like string, integer or Phoenix.LiveView.Rendered
object, like returned from the ~H sigil
- A tuple, containing a custom value used for sorting, and the displayed
content.
"""
use MemexWeb, :live_component
alias Phoenix.LiveView.Socket
@impl true
@spec update(
%{
required(:columns) =>
list(%{
required(:label) => String.t() | nil,
required(:key) => String.t() | nil,
optional(:class) => String.t(),
optional(:sortable) => false
}),
required(:rows) =>
list(%{
(key :: String.t()) => any() | {custom_sort_value :: String.t(), value :: any()}
}),
optional(any()) => any()
},
Socket.t()
) :: {:ok, Socket.t()}
def update(%{columns: columns, rows: rows} = assigns, socket) do
initial_key = columns |> List.first() |> Map.get(:key)
rows = rows |> Enum.sort_by(fn row -> row |> Map.get(initial_key) end, :asc)
socket =
socket
|> assign(assigns)
|> assign(columns: columns, rows: rows, last_sort_key: initial_key, sort_mode: :asc)
{:ok, socket}
end
@impl true
def handle_event(
"sort_by",
%{"sort-key" => key},
%{assigns: %{rows: rows, last_sort_key: key, sort_mode: sort_mode}} = socket
) do
sort_mode = if sort_mode == :asc, do: :desc, else: :asc
rows = rows |> sort_by_custom_sort_value_or_value(key, sort_mode)
{:noreply, socket |> assign(sort_mode: sort_mode, rows: rows)}
end
def handle_event(
"sort_by",
%{"sort-key" => key},
%{assigns: %{rows: rows}} = socket
) do
rows = rows |> sort_by_custom_sort_value_or_value(key, :asc)
{:noreply, socket |> assign(last_sort_key: key, sort_mode: :asc, rows: rows)}
end
defp sort_by_custom_sort_value_or_value(rows, key, sort_mode) do
rows
|> Enum.sort_by(
fn row ->
case row |> Map.get(key) do
{custom_sort_key, _value} -> custom_sort_key
value -> value
end
end,
sort_mode
)
end
end

View File

@ -0,0 +1,52 @@
<div class="w-full overflow-x-auto border border-gray-600 rounded-lg shadow-lg bg-black">
<table class="min-w-full table-auto text-center bg-white">
<thead class="border-b border-primary-600">
<tr>
<%= for %{key: key, label: label} = column <- @columns do %>
<%= if column |> Map.get(:sortable, true) do %>
<th class={"p-2 #{column[:class]}"}>
<span
class="cursor-pointer"
phx-click="sort_by"
phx-value-sort-key={key}
phx-target={@myself}
>
<span class="underline"><%= label %></span>
<%= if @last_sort_key == key do %>
<%= case @sort_mode do %>
<% :asc -> %>
<i class="fas fa-sm fa-chevron-down"></i>
<% :desc -> %>
<i class="fas fa-sm fa-chevron-up"></i>
<% end %>
<% else %>
<i class="fas fa-sm fa-chevron-up opacity-0"></i>
<% end %>
</span>
</th>
<% else %>
<th class={"p-2 #{column[:class]}"}>
<%= label %>
</th>
<% end %>
<% end %>
</tr>
</thead>
<tbody>
<%= for values <- @rows do %>
<tr>
<%= for %{key: key} = value <- @columns do %>
<td class={"p-2 #{value[:class]}"}>
<%= case values |> Map.get(key) do %>
<% {_custom_sort_value, value} -> %>
<%= value %>
<% value -> %>
<%= value %>
<% end %>
</td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
</div>

View File

@ -0,0 +1,104 @@
defmodule MemexWeb.Components.Topbar do
@moduledoc """
Component that renders a topbar with user functions/links
"""
use MemexWeb, :component
alias Memex.Accounts
alias MemexWeb.{Endpoint, HomeLive}
def topbar(assigns) do
assigns =
%{results: [], title_content: nil, flash: nil, current_user: nil} |> Map.merge(assigns)
~H"""
<nav role="navigation" class="mb-8 px-8 py-4 w-full bg-primary-400">
<div class="flex flex-col sm:flex-row justify-between items-center">
<div class="mb-4 sm:mb-0 sm:mr-8 flex flex-row justify-start items-center space-x-2">
<%= live_redirect("Memex",
to: Routes.live_path(Endpoint, HomeLive),
class: "mx-2 my-1 leading-5 text-xl text-white hover:underline"
) %>
<%= if @title_content do %>
<span class="mx-2 my-1">
|
</span>
<%= @title_content %>
<% end %>
</div>
<hr class="mb-2 sm:hidden hr-light" />
<ul class="flex flex-row flex-wrap justify-center items-center
text-lg text-white text-ellipsis">
<%= if @current_user do %>
<form phx-change="suggest" phx-submit="search">
<input
type="text"
name="q"
class="input input-primary"
placeholder="Search"
list="results"
autocomplete="off"
/>
<datalist id="results">
<%= for {app, _vsn} <- @results do %>
<option value={app}>
"> <%= app %>
</option>
<% end %>
</datalist>
</form>
<%= if @current_user.role == :admin do %>
<li class="mx-2 my-1">
<%= live_redirect(gettext("Invites"),
to: Routes.invite_index_path(Endpoint, :index),
class: "text-white text-white hover:underline"
) %>
</li>
<% end %>
<li class="mx-2 my-1">
<%= live_redirect(@current_user.email,
to: Routes.user_settings_path(Endpoint, :edit),
class: "text-white text-white hover:underline truncate"
) %>
</li>
<li class="mx-2 my-1">
<%= link to: Routes.user_session_path(Endpoint, :delete),
method: :delete,
data: [confirm: dgettext("prompts", "Are you sure you want to log out?")] do %>
<i class="fas fa-sign-out-alt"></i>
<% end %>
</li>
<%= if @current_user.role == :admin and function_exported?(Routes, :live_dashboard_path, 2) do %>
<li class="mx-2 my-1">
<%= live_redirect to: Routes.live_dashboard_path(Endpoint, :home),
class: "text-white text-white hover:underline" do %>
<i class="fas fa-gauge"></i>
<% end %>
</li>
<% end %>
<% else %>
<%= if Accounts.allow_registration?() do %>
<li class="mx-2 my-1">
<%= live_redirect(dgettext("actions", "Register"),
to: Routes.user_registration_path(Endpoint, :new),
class: "text-white text-white hover:underline truncate"
) %>
</li>
<% end %>
<li class="mx-2 my-1">
<%= live_redirect(dgettext("actions", "Log in"),
to: Routes.user_session_path(Endpoint, :new),
class: "text-white text-white hover:underline truncate"
) %>
</li>
<% end %>
</ul>
</div>
</nav>
"""
end
end

View File

@ -0,0 +1,43 @@
defmodule MemexWeb.Components.UserCard do
@moduledoc """
Display card for a user
"""
use MemexWeb, :component
def user_card(assigns) do
~H"""
<div
id={"user-#{@user.id}"}
class="mx-4 my-2 px-8 py-4 flex flex-col justify-center items-center text-center
border border-gray-400 rounded-lg shadow-lg hover:shadow-md
transition-all duration-300 ease-in-out"
>
<h1 class="px-4 py-2 rounded-lg title text-xl break-all">
<%= @user.email %>
</h1>
<h3 class="px-4 py-2 rounded-lg title text-lg">
<p>
<%= if @user.confirmed_at |> is_nil() do %>
Email unconfirmed
<% else %>
User was confirmed at <%= @user.confirmed_at |> display_datetime() %>
<% end %>
</p>
<p>
<%= gettext("User registered on") %>
<%= @user.inserted_at |> display_datetime() %>
</p>
</h3>
<%= if @inner_block do %>
<div class="px-4 py-2 flex space-x-4 justify-center items-center">
<%= render_slot(@inner_block) %>
</div>
<% end %>
</div>
"""
end
end