Updated toggle component and moved MP index table to a liveview

This commit is contained in:
Kieran Eglin 2024-11-20 11:22:44 -08:00
parent 2d4b86de71
commit e893b71e20
No known key found for this signature in database
GPG key ID: 193984967FCF432D
7 changed files with 124 additions and 19 deletions

View file

@ -35,3 +35,10 @@ window.markVersionAsSeen = (versionString) => {
window.isVersionSeen = (versionString) => { window.isVersionSeen = (versionString) => {
return localStorage.getItem('seenVersion') === versionString return localStorage.getItem('seenVersion') === versionString
} }
window.dispatchFor = (elementOrId, eventName, detail = {}) => {
const element =
typeof elementOrId === 'string' ? document.getElementById(elementOrId) : elementOrId
element.dispatchEvent(new CustomEvent(eventName, { detail }))
}

View file

@ -39,7 +39,7 @@ let liveSocket = new LiveSocket(document.body.dataset.socketPath, Socket, {
} }
}, },
hooks: { hooks: {
supressEnterSubmission: { 'supress-enter-submission': {
mounted() { mounted() {
this.el.addEventListener('keypress', (event) => { this.el.addEventListener('keypress', (event) => {
if (event.key === 'Enter') { if (event.key === 'Enter') {
@ -47,6 +47,29 @@ let liveSocket = new LiveSocket(document.body.dataset.socketPath, Socket, {
} }
}) })
} }
},
'formless-input': {
mounted() {
const subscribedEvents = this.el.dataset.subscribe.split(' ')
const eventName = this.el.dataset.eventName || ''
const identifier = this.el.dataset.identifier || ''
subscribedEvents.forEach((domEvent) => {
this.el.addEventListener(domEvent, () => {
// This ensures that the event is pushed to the server after the input value has been updated
// so that the server has the most up-to-date value
setTimeout(() => {
this.pushEvent('formless-input', {
value: this.el.value,
id: identifier,
event: eventName,
dom_id: this.el.id,
dom_event: domEvent
})
}, 0)
})
})
}
} }
} }
}) })

View file

@ -0,0 +1,29 @@
defmodule Pinchflat.Profiles.ProfilesQuery do
@moduledoc """
Query helpers for the Profiles context.
These methods are made to be one-ish liners used
to compose queries. Each method should strive to do
_one_ thing. These don't need to be tested as
they are just building blocks for other functionality
which, itself, will be tested.
"""
import Ecto.Query, warn: false
alias Pinchflat.Profiles.MediaProfile
# This allows the module to be aliased and query methods to be used
# all in one go
# usage: use Pinchflat.Profiles.ProfilesQuery
defmacro __using__(_opts) do
quote do
import Ecto.Query, warn: false
alias unquote(__MODULE__)
end
end
def new do
MediaProfile
end
end

View file

@ -340,14 +340,15 @@ defmodule PinchflatWeb.CoreComponents do
end) end)
~H""" ~H"""
<div x-data={"{ enabled: #{@checked}}"}> <div x-data={"{ enabled: #{@checked}}"} class="">
<.label for={@id}> <.label :if={@label} for={@id}>
<%= @label %> <%= @label %>
<span :if={@label_suffix} class="text-xs text-bodydark"><%= @label_suffix %></span> <span :if={@label_suffix} class="text-xs text-bodydark"><%= @label_suffix %></span>
</.label> </.label>
<div class="relative"> <div class="relative flex flex-col">
<input type="hidden" id={@id} name={@name} x-bind:value="enabled" {@rest} /> <input type="hidden" id={@id} name={@name} x-bind:value="enabled" {@rest} />
<div class="inline-block cursor-pointer" @click="enabled = !enabled"> <%!-- This triggers a `change` event on the hidden input when the toggle is clicked --%>
<div class="inline-block cursor-pointer" @click={"enabled = !enabled; dispatchFor('#{@id}', 'change')"}>
<div x-bind:class="enabled && '!bg-primary'" class="block h-8 w-14 rounded-full bg-black"></div> <div x-bind:class="enabled && '!bg-primary'" class="block h-8 w-14 rounded-full bg-black"></div>
<div <div
x-bind:class="enabled && '!right-1 !translate-x-full'" x-bind:class="enabled && '!right-1 !translate-x-full'"

View file

@ -3,7 +3,7 @@ defmodule Pinchflat.UpgradeButtonLive do
def render(assigns) do def render(assigns) do
~H""" ~H"""
<form id="upgradeForm" phx-change="check_matching_text" phx-hook="supressEnterSubmission"> <form id="upgradeForm" phx-change="check_matching_text" phx-hook="supress-enter-submission">
<.input type="text" name="unlock-pro-textbox" value="" /> <.input type="text" name="unlock-pro-textbox" value="" />
</form> </form>

View file

@ -14,19 +14,7 @@
<div class="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark"> <div class="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
<div class="max-w-full overflow-x-auto"> <div class="max-w-full overflow-x-auto">
<div class="flex flex-col gap-10 min-w-max"> <div class="flex flex-col gap-10 min-w-max">
<.table rows={@media_profiles} table_class="text-black dark:text-white"> <%= live_render(@conn, PinchflatWeb.MediaProfiles.IndexTableLive) %>
<:col :let={media_profile} label="Name">
<.subtle_link href={~p"/media_profiles/#{media_profile.id}"}>
<%= media_profile.name %>
</.subtle_link>
</:col>
<:col :let={media_profile} label="Preferred Resolution">
<%= media_profile.preferred_resolution %>
</:col>
<:col :let={media_profile} label="" class="flex justify-end">
<.icon_link href={~p"/media_profiles/#{media_profile.id}/edit"} icon="hero-pencil-square" class="mr-4" />
</:col>
</.table>
</div> </div>
</div> </div>
</div> </div>

View file

@ -0,0 +1,57 @@
defmodule PinchflatWeb.MediaProfiles.IndexTableLive do
use PinchflatWeb, :live_view
use Pinchflat.Profiles.ProfilesQuery
alias Pinchflat.Repo
def render(assigns) do
~H"""
<.table rows={@media_profiles} table_class="text-black dark:text-white">
<:col :let={media_profile} label="Name">
<.subtle_link href={~p"/media_profiles/#{media_profile.id}"}>
<%= media_profile.name %>
</.subtle_link>
</:col>
<:col :let={media_profile} label="Preferred Resolution">
<%= media_profile.preferred_resolution %>
</:col>
<:col :let={media_profile} label="Enabled?">
<.input
name={"media_profile[#{media_profile.id}][enabled]"}
id={"media_profile_#{media_profile.id}_enabled"}
phx-hook="formless-input"
data-subscribe="change"
data-event-name="toggle_enabled"
data-identifier={media_profile.id}
type="toggle"
/>
</:col>
<:col :let={media_profile} label="" class="flex justify-end">
<.icon_link href={~p"/media_profiles/#{media_profile.id}/edit"} icon="hero-pencil-square" class="mr-4" />
</:col>
</.table>
"""
end
def mount(_params, _session, socket) do
new_assigns = %{
media_profiles: get_media_profiles()
}
{:ok, assign(socket, new_assigns)}
end
def handle_event("formless-input", %{"event" => "toggle_enabled"} = params, socket) do
# should_enable = params["value"] == "true"
IO.inspect(params)
{:noreply, socket}
end
defp get_media_profiles do
ProfilesQuery.new()
|> where([mp], is_nil(mp.marked_for_deletion_at))
|> order_by(asc: :name)
|> Repo.all()
end
end