fix(ui): ArrangementDialog drag whole box, persist changes across switch, hover highlight
- Remove drag handle restriction — entire pill box is now draggable - Keep local copy of arrangements so edits survive switching between arrangements (was reading stale props after switch-back) - Highlight corresponding left pill when hovering right lyric preview
This commit is contained in:
parent
78b8fc2e3d
commit
852231ae01
|
|
@ -89,20 +89,40 @@ async function assignSong() {
|
||||||
|
|
||||||
/* ── State ── */
|
/* ── State ── */
|
||||||
|
|
||||||
|
// Local copy of arrangements so changes survive switching between arrangements
|
||||||
|
const localArrangements = ref(JSON.parse(JSON.stringify(props.arrangements)))
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.arrangements,
|
||||||
|
(newArr) => {
|
||||||
|
// Merge server updates (e.g. after create/clone/delete) but keep local edits for existing arrangements
|
||||||
|
const localById = Object.fromEntries(localArrangements.value.map((a) => [a.id, a]))
|
||||||
|
localArrangements.value = newArr.map((a) => localById[a.id] ?? JSON.parse(JSON.stringify(a)))
|
||||||
|
// Add any new arrangements not in local
|
||||||
|
for (const a of newArr) {
|
||||||
|
if (!localById[a.id]) {
|
||||||
|
localArrangements.value.push(JSON.parse(JSON.stringify(a)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
)
|
||||||
|
|
||||||
const currentArrangementId = ref(
|
const currentArrangementId = ref(
|
||||||
props.selectedArrangementId ?? props.arrangements.find((a) => a.is_default)?.id ?? props.arrangements[0]?.id ?? null,
|
props.selectedArrangementId ?? props.arrangements.find((a) => a.is_default)?.id ?? props.arrangements[0]?.id ?? null,
|
||||||
)
|
)
|
||||||
|
|
||||||
const currentArrangement = computed(() =>
|
const currentArrangement = computed(() =>
|
||||||
props.arrangements.find((a) => a.id === Number(currentArrangementId.value)) ?? null,
|
localArrangements.value.find((a) => a.id === Number(currentArrangementId.value)) ?? null,
|
||||||
)
|
)
|
||||||
|
|
||||||
const arrangementGroups = ref([])
|
const arrangementGroups = ref([])
|
||||||
|
const hoveredIndex = ref(null)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
currentArrangementId,
|
currentArrangementId,
|
||||||
(id) => {
|
(id) => {
|
||||||
const arr = props.arrangements.find((a) => a.id === Number(id))
|
const arr = localArrangements.value.find((a) => a.id === Number(id))
|
||||||
if (arr?.groups?.length) {
|
if (arr?.groups?.length) {
|
||||||
arrangementGroups.value = arr.groups.map((g, i) => ({ ...g, _uid: `${g.id}-${i}-${Date.now()}` }))
|
arrangementGroups.value = arr.groups.map((g, i) => ({ ...g, _uid: `${g.id}-${i}-${Date.now()}` }))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -212,6 +232,16 @@ function deleteArrangement() {
|
||||||
|
|
||||||
function saveArrangement() {
|
function saveArrangement() {
|
||||||
if (!currentArrangement.value) return
|
if (!currentArrangement.value) return
|
||||||
|
|
||||||
|
// Update local arrangements copy so changes survive switching
|
||||||
|
const localArr = localArrangements.value.find((a) => a.id === currentArrangement.value.id)
|
||||||
|
if (localArr) {
|
||||||
|
localArr.groups = arrangementGroups.value.map((g, i) => ({
|
||||||
|
...g,
|
||||||
|
order: i + 1,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
router.put(
|
router.put(
|
||||||
`/arrangements/${currentArrangement.value.id}`,
|
`/arrangements/${currentArrangement.value.id}`,
|
||||||
{
|
{
|
||||||
|
|
@ -454,7 +484,6 @@ function closeOnBackdrop(e) {
|
||||||
ghost-class="drag-ghost"
|
ghost-class="drag-ghost"
|
||||||
chosen-class="drag-chosen"
|
chosen-class="drag-chosen"
|
||||||
drag-class="drag-active"
|
drag-class="drag-active"
|
||||||
handle=".drag-handle"
|
|
||||||
class="flex flex-col gap-2"
|
class="flex flex-col gap-2"
|
||||||
@end="saveArrangement"
|
@end="saveArrangement"
|
||||||
>
|
>
|
||||||
|
|
@ -462,23 +491,13 @@ function closeOnBackdrop(e) {
|
||||||
v-for="(element, index) in arrangementGroups"
|
v-for="(element, index) in arrangementGroups"
|
||||||
:key="element._uid"
|
:key="element._uid"
|
||||||
data-testid="arrangement-pill"
|
data-testid="arrangement-pill"
|
||||||
class="flex items-center gap-2 rounded-lg border-2 px-3 py-2"
|
class="flex cursor-grab items-center gap-2 rounded-lg border-2 px-3 py-2"
|
||||||
|
:class="{ 'ring-2 ring-indigo-400 ring-offset-1': hoveredIndex === index }"
|
||||||
:style="{
|
:style="{
|
||||||
borderColor: element.color ?? '#6b7280',
|
borderColor: element.color ?? '#6b7280',
|
||||||
backgroundColor: (element.color ?? '#6b7280') + '20',
|
backgroundColor: (element.color ?? '#6b7280') + '20',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<!-- Drag handle -->
|
|
||||||
<span class="drag-handle cursor-grab text-gray-400 hover:text-gray-600">
|
|
||||||
<svg
|
|
||||||
class="h-4 w-4"
|
|
||||||
fill="currentColor"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
>
|
|
||||||
<path d="M7 2a2 2 0 10.001 4.001A2 2 0 007 2zm0 6a2 2 0 10.001 4.001A2 2 0 007 8zm0 6a2 2 0 10.001 4.001A2 2 0 007 14zm6-8a2 2 0 10-.001-4.001A2 2 0 0013 6zm0 2a2 2 0 10.001 4.001A2 2 0 0013 8zm0 6a2 2 0 10.001 4.001A2 2 0 0013 14z" />
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<!-- Group name -->
|
<!-- Group name -->
|
||||||
<span class="flex-1 text-sm font-medium">
|
<span class="flex-1 text-sm font-medium">
|
||||||
{{ element.name }}
|
{{ element.name }}
|
||||||
|
|
@ -562,10 +581,13 @@ function closeOnBackdrop(e) {
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-for="element in arrangementGroups"
|
v-for="(element, index) in arrangementGroups"
|
||||||
:key="element._uid"
|
:key="element._uid"
|
||||||
class="rounded-r-lg border-l-4 bg-white p-3 shadow-sm"
|
class="rounded-r-lg border-l-4 bg-white p-3 shadow-sm transition-shadow"
|
||||||
|
:class="{ 'ring-2 ring-indigo-400 ring-offset-1': hoveredIndex === index }"
|
||||||
:style="{ borderColor: element.color ?? '#6b7280' }"
|
:style="{ borderColor: element.color ?? '#6b7280' }"
|
||||||
|
@mouseenter="hoveredIndex = index"
|
||||||
|
@mouseleave="hoveredIndex = null"
|
||||||
>
|
>
|
||||||
<!-- Group name pill -->
|
<!-- Group name pill -->
|
||||||
<span
|
<span
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue