From 852231ae011609dfa00e2e9d33481d5ddbc3d1e2 Mon Sep 17 00:00:00 2001 From: Thorsten Bus Date: Sun, 29 Mar 2026 16:34:30 +0200 Subject: [PATCH] fix(ui): ArrangementDialog drag whole box, persist changes across switch, hover highlight MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- resources/js/Components/ArrangementDialog.vue | 56 +++++++++++++------ 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/resources/js/Components/ArrangementDialog.vue b/resources/js/Components/ArrangementDialog.vue index 514febb..80af850 100644 --- a/resources/js/Components/ArrangementDialog.vue +++ b/resources/js/Components/ArrangementDialog.vue @@ -89,20 +89,40 @@ async function assignSong() { /* ── 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( props.selectedArrangementId ?? props.arrangements.find((a) => a.is_default)?.id ?? props.arrangements[0]?.id ?? null, ) 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 hoveredIndex = ref(null) watch( currentArrangementId, (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) { arrangementGroups.value = arr.groups.map((g, i) => ({ ...g, _uid: `${g.id}-${i}-${Date.now()}` })) } else { @@ -212,6 +232,16 @@ function deleteArrangement() { function saveArrangement() { 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( `/arrangements/${currentArrangement.value.id}`, { @@ -454,7 +484,6 @@ function closeOnBackdrop(e) { ghost-class="drag-ghost" chosen-class="drag-chosen" drag-class="drag-active" - handle=".drag-handle" class="flex flex-col gap-2" @end="saveArrangement" > @@ -462,23 +491,13 @@ function closeOnBackdrop(e) { v-for="(element, index) in arrangementGroups" :key="element._uid" 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="{ borderColor: element.color ?? '#6b7280', backgroundColor: (element.color ?? '#6b7280') + '20', }" > - - - - - - - {{ element.name }} @@ -562,10 +581,13 @@ function closeOnBackdrop(e) {