Improve list view and add cookie

This commit is contained in:
2023-11-27 16:49:59 +00:00
committed by Daniel Patterson
parent e31db2f5e8
commit cb7c15c345
5 changed files with 129 additions and 59 deletions

View File

@@ -30,6 +30,10 @@ topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
window.addEventListener("phx:page-loading-start", _info => topbar.show(300))
window.addEventListener("phx:page-loading-stop", _info => topbar.hide())
window.addEventListener("toggle_view_state", e => {
document.cookie = `user_display=${e.detail.grid ? "grid" : "list"}; SameSite=lax;`
})
// connect if there are any LiveViews on the page
liveSocket.connect()

16
lib/wish_web/layout.ex Normal file
View File

@@ -0,0 +1,16 @@
defmodule WishWeb.Plug.GetLayoutFromCookie do
import Plug.Conn
def init(_) do
%{}
end
def call(conn, _opts) do
conn = fetch_cookies(conn)
case conn.cookies["user_display"] do
nil -> conn
other -> conn |> put_session(:user_display, other)
end
end
end

View File

@@ -4,19 +4,19 @@ defmodule WishWeb.HomeLive.Index do
alias Wish.Wishlist
@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, :items, Wishlist.list_items()) |> assign(:display, :grid)}
def mount(_params, session, socket) do
grid? =
case Map.get(session, "user_display", "grid") do
"grid" -> true
_ -> false
end
{:ok, assign(socket, :items, Wishlist.list_items()) |> assign(:grid, grid?)}
end
@impl true
def handle_event("toggle", _, socket) do
new_state =
case socket.assigns.display do
:row -> :grid
:grid -> :row
end
{:noreply, assign(socket, :display, new_state)}
def handle_event("toggle_view_state", _, socket) do
{:noreply, assign(socket, :grid, !socket.assigns.grid)}
end
@impl true
@@ -25,7 +25,9 @@ defmodule WishWeb.HomeLive.Index do
case Wishlist.toggle_received(item) do
{:ok, updated_item} ->
{:noreply, assign(socket, :item, updated_item)}
index = Enum.find_index(socket.assigns.items, &(&1.id == updated_item.id))
updated_list = List.update_at(socket.assigns.items, index, fn _ -> updated_item end)
{:noreply, assign(socket, :items, updated_list)}
{:error, _} ->
{:noreply, socket}

View File

@@ -1,60 +1,104 @@
<.header>
Listing Items
<:actions>
<.button phx-click="toggle">
<.button phx-click={
JS.push("toggle_view_state")
|> JS.dispatch("toggle_view_state", detail: %{"grid" => !@grid})
}>
Toggle Display
</.button>
</:actions>
</.header>
<div
class={
case @display do
:grid -> "grid grid-cols-3 gap-2"
:row -> ""
end
}
id="items-grid"
>
<div
:for={item <- @items}
phx-click={JS.navigate(~p"/details/#{item}")}
class={[
"p-2 rounded hover:bg-zinc-100 active:bg-zinc-200",
case @display do
:grid -> "h-72"
:row -> "flex flex-row h-24"
end
]}
>
<div class="aspect-square flex flex-col justify-center">
<img
:if={item.image_url}
src={item.image_url}
alt={item.title}
height="224"
width="224"
class="rounded"
/>
</div>
<%= if item.received do %>
<div class="bg-red-400 text-white">
<.icon name="hero-check-circle" />Received
<%= if @grid do %>
<div class="grid grid-cols-3 gap-2" id="items-grid">
<div
:for={item <- @items}
phx-click={JS.navigate(~p"/details/#{item}")}
class="h-72 p-2 rounded hover:bg-zinc-100 active:bg-zinc-200"
,
>
<div class="aspect-square relative flex flex-col justify-center">
<img
:if={item.image_url}
src={item.image_url}
alt={item.title}
height="224"
width="224"
class="rounded"
/>
<%= if item.received do %>
<div class="bg-red-400 text-white absolute w-full h-7 bottom-0">
<.icon name="hero-check-circle" />Received
</div>
<% end %>
</div>
<% end %>
<div class="flex flex-row justify-between">
<%= item.title %>
<div phx-click={JS.toggle(to: "#dropdown-#{item.id}")} class="relative">
<.icon name="hero-ellipsis-vertical" class="w-7 h-7" />
<div
id={"dropdown-#{item.id}"}
class="absolute z-10 bg-white origin-top right-0 whitespace-nowrap"
phx-click={JS.push("toggle_received", value: %{"id" => item.id})}
hidden
>
Mark visible
<div class="flex flex-row justify-between">
<%= item.title %>
<div phx-click={JS.toggle(to: "#dropdown-#{item.id}")} class="relative">
<.icon name="hero-ellipsis-vertical" class="w-7 h-7" />
<div
id={"dropdown-#{item.id}"}
class="absolute z-10 w-40 bg-white origin-top right-0 whitespace-nowrap p-1 border rounded"
phx-click-away={JS.hide()}
hidden
>
<div
class="p-1 border border-white hover:bg-slate-100 hover:border-black select-none"
phx-click={
JS.push("toggle_received", value: %{"id" => item.id})
|> JS.hide(to: "#dropdown-#{item.id}")
}
>
Mark received
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<% else %>
<div class="flex flex-col space-y-4">
<div
:for={item <- @items}
class="grid grid-cols-8 grid-rows-4 h-24 p-1 border rounded"
phx-click={JS.navigate(~p"/details/#{item}")}
>
<div class="relative flex flex-col justify-center max-h-full h-full row-span-4">
<img
:if={item.image_url}
src={item.image_url}
alt={item.title}
class="max-h-full rounded"
/>
<%= if item.received do %>
<div class="absolute bg-red-400 text-xs text-white w-full h-7 bottom-0">
<.icon name="hero-check-circle" />Received
</div>
<% end %>
</div>
<div class="col-span-6 row-span-4 px-2">
<%= item.title %>
</div>
<div phx-click={JS.toggle(to: "#dropdown-#{item.id}")} class="relative">
<.icon name="hero-ellipsis-vertical" class="w-7 h-7" />
<div
id={"dropdown-#{item.id}"}
class="absolute z-10 w-40 bg-white origin-top right-0 whitespace-nowrap p-1 border rounded"
phx-click-away={JS.hide()}
hidden
>
<div
class="p-1 border border-white hover:bg-slate-100 hover:border-black select-none"
phx-click={
JS.push("toggle_received", value: %{"id" => item.id})
|> JS.hide(to: "#dropdown-#{item.id}")
}
>
Mark received
</div>
</div>
</div>
</div>
</div>
<% end %>

View File

@@ -17,8 +17,12 @@ defmodule WishWeb.Router do
plug :accepts, ["json"]
end
pipeline :get_layout do
plug WishWeb.Plug.GetLayoutFromCookie
end
scope "/", WishWeb do
pipe_through :browser
pipe_through [:browser, :get_layout]
live "/", HomeLive.Index, :index
live "/details/:id", HomeLive.Details, :index