Checkpoint

This commit is contained in:
Chris McCord 2021-11-01 23:25:28 -04:00
parent efa980033d
commit 1d37ec3c5c
4 changed files with 110 additions and 33 deletions

View file

@ -54,6 +54,16 @@ defmodule LiveBeatsWeb.LiveHelpers do
) )
end end
def hide(js \\ %JS{}, selector) do
JS.hide(js,
to: selector,
time: 300,
transition:
{"transition ease-in duration-300", "transform opacity-100 scale-100",
"transform opacity-0 scale-95"}
)
end
def show_dropdown(to) do def show_dropdown(to) do
JS.show( JS.show(
to: to, to: to,
@ -108,10 +118,14 @@ defmodule LiveBeatsWeb.LiveHelpers do
assigns = assigns =
assigns assigns
|> assign_new(:show, fn -> false end) |> assign_new(:show, fn -> false end)
|> assign_new(:title, fn -> [] end) |> assign_new(:loading, fn -> false end)
|> assign_new(:confirm, fn -> nil end)
|> assign_new(:cancel, fn -> nil end)
|> assign_new(:return_to, fn -> nil end) |> assign_new(:return_to, fn -> nil end)
|> assign_new(:on_cancel, fn -> %JS{} end)
|> assign_new(:on_confirm, fn -> %JS{} end)
# slots
|> assign_new(:title, fn -> [] end)
|> assign_new(:confirm, fn -> [] end)
|> assign_new(:cancel, fn -> [] end)
~H""" ~H"""
<div id={@id} class={"fixed z-10 inset-0 overflow-y-auto #{if @show, do: "fade-in", else: "hidden"}"} aria-labelledby="modal-title" role="dialog" aria-modal="true"> <div id={@id} class={"fixed z-10 inset-0 overflow-y-auto #{if @show, do: "fade-in", else: "hidden"}"} aria-labelledby="modal-title" role="dialog" aria-modal="true">
@ -120,18 +134,18 @@ defmodule LiveBeatsWeb.LiveHelpers do
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span> <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div <div
id={"#{@id}-content"} id={"#{@id}-content"}
class={"#{if @show, do: "fade-in-scale", else: "hidden"} sticky inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform sm:my-8 sm:align-middle lg:ml-48 sm:max-w-2xl sm:w-full sm:p-6"} class={"#{if @show, do: "fade-in-scale", else: "hidden"} sticky inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform sm:my-8 sm:align-middle sm:max-w-xl sm:w-full sm:p-6"}
phx-window-keydown={hide_modal(@id)} phx-key="escape" phx-window-keydown={hide_modal(@on_cancel, @id)} phx-key="escape"
phx-click-away={hide_modal(@id)} phx-click-away={hide_modal(@on_cancel, @id)}
> >
<%= if @return_to do %> <%= if @return_to do %>
<%= live_redirect "close", to: @return_to, data: [modal_return: true], class: "hidden" %> <%= live_redirect "close", to: @return_to, data: [modal_return: true], class: "hidden" %>
<% end %> <% end %>
<div class="sm:flex sm:items-start"> <div class="sm:flex sm:items-start">
<div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-green-100 sm:mx-0 sm:h-10 sm:w-10"> <div class={"mx-auto flex-shrink-0 flex items-center justify-center h-8 w-8 rounded-full bg-purple-100 sm:mx-0"}>
<!-- Heroicon name: outline/plus --> <!-- Heroicon name: outline/plus -->
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-green-600" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" class={"#{if @loading, do: "animate-ping"} h-6 w-6 text-purple-600"} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg> </svg>
</div> </div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left w-full mr-12"> <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left w-full mr-12">
@ -139,25 +153,32 @@ defmodule LiveBeatsWeb.LiveHelpers do
<%= render_slot(@title) %> <%= render_slot(@title) %>
</h3> </h3>
<div class="mt-2"> <div class="mt-2">
<p class="text-sm text-gray-500"> <p class={"text-sm text-gray-500 #{if @loading, do: "invisible"}"}>
<%= render_slot(@inner_block) %> <%= render_slot(@inner_block) %>
</p> </p>
</div> </div>
</div> </div>
</div> </div>
<div class="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse"> <div class={"mt-5 sm:mt-4 sm:flex sm:flex-row-reverse #{if @loading, do: "invisible"}"}>
<%= if @confirm do %> <%= for confirm <- @confirm do %>
<button type="button" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"> <button
<%= render_slot(@confirm) %> type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"
phx-click={@on_confirm |> hide_modal(@id)}
tabindex="1"
autofocus
>
<%= render_slot(confirm) %>
</button> </button>
<% end %> <% end %>
<%= if @cancel do %> <%= for cancel <- @cancel do %>
<button <button
type="button" type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:w-auto sm:text-sm" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:w-auto sm:text-sm"
phx-click={hide_modal(@id)} phx-click={hide_modal(@on_cancel, @id)}
tabindex="2"
> >
<%= render_slot(@cancel) %> <%= render_slot(cancel) %>
</button> </button>
<% end %> <% end %>
</div> </div>
@ -241,6 +262,8 @@ defmodule LiveBeatsWeb.LiveHelpers do
end end
def table(assigns) do def table(assigns) do
assigns = assign_new(assigns, :row_id, fn -> false end)
~H""" ~H"""
<div class="hidden mt-8 sm:block"> <div class="hidden mt-8 sm:block">
<div class="align-middle inline-block min-w-full border-b border-gray-200"> <div class="align-middle inline-block min-w-full border-b border-gray-200">
@ -257,7 +280,7 @@ defmodule LiveBeatsWeb.LiveHelpers do
</thead> </thead>
<tbody class="bg-white divide-y divide-gray-100"> <tbody class="bg-white divide-y divide-gray-100">
<%= for row <- @rows do %> <%= for row <- @rows do %>
<tr class="hover:bg-gray-50"> <tr id={@row_id && @row_id.(row)} class="hover:bg-gray-50">
<%= for {col, i} <- Enum.with_index(@col) do %> <%= for {col, i} <- Enum.with_index(@col) do %>
<td class={"px-6 py-3 whitespace-nowrap text-sm font-medium text-gray-900 #{if i == 0, do: "max-w-0 w-full"}"}> <td class={"px-6 py-3 whitespace-nowrap text-sm font-medium text-gray-900 #{if i == 0, do: "max-w-0 w-full"}"}>
<div class="flex items-center space-x-3 lg:pl-2"> <div class="flex items-center space-x-3 lg:pl-2">

View file

@ -0,0 +1,47 @@
defmodule LiveBeatsWeb.SongLive.DeleteDialogComponent do
use LiveBeatsWeb, :live_component
alias LiveBeats.MediaLibrary
def send_show(%MediaLibrary.Song{} = song) do
send_update(__MODULE__, id: "delete-modal", show: song)
end
@impl true
def render(assigns) do
~H"""
<div>
<.modal
id="delete-modal"
loading={is_nil(@song.id)}
on_confirm={JS.push("confirm-delete", value: %{id: @song.id}) |> hide("#song-#{@song.id}")}
on_cancel={JS.push("cancel", target: @myself)}>
Are you sure you want to delete "<%= @song.title %>"?
<:cancel>Cancel</:cancel>
<:confirm>Delete</:confirm>
</.modal>
</div>
"""
end
@impl true
def update(%{show: %MediaLibrary.Song{} = song}, socket) do
{:ok, assign(socket, song: song)}
end
def update(%{} = _assigns, socket) do
{:ok, assign_defaults(socket)}
end
@impl true
def handle_event("cancel", _, socket) do
IO.inspect({:cancel})
{:noreply, assign_defaults(socket)}
end
defp assign_defaults(socket) do
assign(socket, song: %MediaLibrary.Song{})
end
end

View file

@ -3,6 +3,7 @@ defmodule LiveBeatsWeb.SongLive.Index do
alias LiveBeats.MediaLibrary alias LiveBeats.MediaLibrary
alias LiveBeats.MediaLibrary.Song alias LiveBeats.MediaLibrary.Song
alias LiveBeatsWeb.SongLive.DeleteDialogComponent
def render(assigns) do def render(assigns) do
~H""" ~H"""
@ -10,7 +11,7 @@ defmodule LiveBeatsWeb.SongLive.Index do
Listing Songs Listing Songs
<:actions> <:actions>
<.button primary patch_to={Routes.song_index_path(@socket, :new)}>New Song</.button> <.button primary patch_to={Routes.song_index_path(@socket, :new)}>Upload Songs</.button>
</:actions> </:actions>
</.title_bar> </.title_bar>
@ -28,14 +29,16 @@ defmodule LiveBeatsWeb.SongLive.Index do
</.modal> </.modal>
<% end %> <% end %>
<.table rows={@songs}> <.live_component module={DeleteDialogComponent} id="delete-modal"/>
<.table rows={@songs} row_id={fn song -> "song-#{song.id}" end}>
<:col let={song} label="Title"><%= song.title %></:col> <:col let={song} label="Title"><%= song.title %></:col>
<:col let={song} label="Artist"><%= song.artist %></:col> <:col let={song} label="Artist"><%= song.artist %></:col>
<:col let={song} label="Duration"><%= song.duration %></:col> <:col let={song} label="Duration"><%= song.duration %></:col>
<:col let={song} label=""> <:col let={song} label="">
<.link redirect_to={Routes.song_show_path(@socket, :show, song)}>Show</.link> <.link redirect_to={Routes.song_show_path(@socket, :show, song)}>Show</.link>
<.link patch_to={Routes.song_index_path(@socket, :edit, song)}>Edit</.link> <.link patch_to={Routes.song_index_path(@socket, :edit, song)}>Edit</.link>
<.link phx-click={JS.push("delete", value: %{id: song.id})} data-confirm="Are you sure?">Delete</.link> <.link phx-click={JS.push("delete", value: %{id: song.id}) |> show_modal("delete-modal")}>Delete</.link>
</:col> </:col>
</.table> </.table>
""" """
@ -68,9 +71,13 @@ defmodule LiveBeatsWeb.SongLive.Index do
end end
def handle_event("delete", %{"id" => id}, socket) do def handle_event("delete", %{"id" => id}, socket) do
DeleteDialogComponent.send_show(MediaLibrary.get_song!(id))
{:noreply, socket}
end
def handle_event("confirm-delete", %{"id" => id}, socket) do
song = MediaLibrary.get_song!(id) song = MediaLibrary.get_song!(id)
{:ok, _} = MediaLibrary.delete_song(song) {:ok, _} = MediaLibrary.delete_song(song)
{:noreply, assign(socket, :songs, list_songs())} {:noreply, assign(socket, :songs, list_songs())}
end end

View file

@ -10,15 +10,15 @@
# We recommend using the bang functions (`insert!`, `update!` # We recommend using the bang functions (`insert!`, `update!`
# and so on) as they will fail if something goes wrong. # and so on) as they will fail if something goes wrong.
for title <- ~w(Chill Pop Hip-hop Electronic) do # for title <- ~w(Chill Pop Hip-hop Electronic) do
{:ok, _} = LiveBeats.MediaLibrary.create_genre(%{title: title}) # {:ok, _} = LiveBeats.MediaLibrary.create_genre(%{title: title})
end
# for i <- 1..20 do
# {:ok, _} =
# LiveBeats.MediaLibrary.create_song(%{
# artist: "Bonobo",
# title: "Black Sands #{i}",
# duration: 180_000
# })
# end # end
for i <- 1..20 do
{:ok, _} =
LiveBeats.MediaLibrary.create_song(%{
artist: "Bonobo",
title: "Black Sands #{i}",
duration: 180_000
})
end