From e48feed9c880afdcb0527b317e236b42520cc684 Mon Sep 17 00:00:00 2001 From: kunalja Date: Thu, 12 Jun 2025 00:42:08 -0400 Subject: [PATCH] draggable --- src/modals/TextInputModal.ts | 117 ++++++++++++++++++++++++++++++++++- styles.css | 28 +++++++++ 2 files changed, 144 insertions(+), 1 deletion(-) diff --git a/src/modals/TextInputModal.ts b/src/modals/TextInputModal.ts index f2f0de5..804688c 100644 --- a/src/modals/TextInputModal.ts +++ b/src/modals/TextInputModal.ts @@ -15,6 +15,11 @@ export class TextInputModal extends Modal { // Track the current variant position in the editor private currentFrom: EditorPosition | null; private currentTo: EditorPosition | null; + + // Drag and drop properties + private draggedElement: HTMLElement | null = null; + private draggedIndex: number = -1; + private dragOverIndex: number = -1; constructor( app: App, @@ -350,7 +355,7 @@ export class TextInputModal extends Modal { } }); - // Drag handle icon for reordering (visual only for now) + // Drag handle icon for reordering const dragHandle = variantRow.createEl('button', { cls: 'variant-editor-drag-handle clickable-icon', attr: { @@ -364,6 +369,116 @@ export class TextInputModal extends Modal { placement: 'top' }); + // Don't add drag functionality to the "Add a variant" row + if (!isLastEmptyRow) { + // Make the drag handle draggable + dragHandle.setAttribute('draggable', 'true'); + + // Drag start event + dragHandle.addEventListener('dragstart', (e) => { + this.draggedElement = variantRow; + this.draggedIndex = index; + + // Add dragging class for visual feedback + variantRow.classList.add('dragging'); + + // Create an invisible drag image to replace the default one + const dragGhost = document.createElement('div'); + dragGhost.classList.add('variant-editor-drag-ghost'); + document.body.appendChild(dragGhost); + + // Set the custom drag image + if (e.dataTransfer) { + e.dataTransfer.effectAllowed = 'move'; + e.dataTransfer.setData('text/plain', index.toString()); + e.dataTransfer.setDragImage(dragGhost, 0, 0); + + // Clean up the ghost element after a short delay + setTimeout(() => { + document.body.removeChild(dragGhost); + }, 0); + } + }); + + // Drag end event + dragHandle.addEventListener('dragend', () => { + if (this.draggedElement) { + this.draggedElement.classList.remove('dragging'); + this.draggedElement = null; + this.draggedIndex = -1; + + // Remove drag-over class from all rows + const allRows = this.variantContainer.querySelectorAll('.variant-editor-row'); + allRows.forEach(row => row.classList.remove('drag-over')); + } + }); + + // Drag over event for the row + variantRow.addEventListener('dragover', (e) => { + e.preventDefault(); + e.stopPropagation(); + + // Only process if we have a dragged element + if (!this.draggedElement || this.draggedIndex === index) return; + + // Add visual indicator + variantRow.classList.add('drag-over'); + + // Update the dragOverIndex + this.dragOverIndex = index; + }); + + // Drag leave event + variantRow.addEventListener('dragleave', () => { + variantRow.classList.remove('drag-over'); + }); + + // Drop event + variantRow.addEventListener('drop', (e) => { + e.preventDefault(); + e.stopPropagation(); + + // Only process if we have a dragged element + if (!this.draggedElement || this.draggedIndex === index) return; + + // Remove visual indicator + variantRow.classList.remove('drag-over'); + + // Move the variant in the array + const draggedVariant = this.variants[this.draggedIndex]; + + // Remove the dragged variant + this.variants.splice(this.draggedIndex, 1); + + // Insert at the new position + this.variants.splice(index, 0, draggedVariant); + + // Update active index if needed + if (this.activeVariantIndex === this.draggedIndex) { + this.activeVariantIndex = index; + } else if (this.activeVariantIndex > this.draggedIndex && this.activeVariantIndex <= index) { + this.activeVariantIndex--; + } else if (this.activeVariantIndex < this.draggedIndex && this.activeVariantIndex >= index) { + this.activeVariantIndex++; + } + + // Update lastNonEmptyVariantIndex if needed + if (this.lastNonEmptyVariantIndex === this.draggedIndex) { + this.lastNonEmptyVariantIndex = index; + } else if (this.lastNonEmptyVariantIndex > this.draggedIndex && this.lastNonEmptyVariantIndex <= index) { + this.lastNonEmptyVariantIndex--; + } else if (this.lastNonEmptyVariantIndex < this.draggedIndex && this.lastNonEmptyVariantIndex >= index) { + this.lastNonEmptyVariantIndex++; + } + + // Re-render with the new order + this.renderVariantInputs(this.activeVariantIndex); + + // Update the editor with the new order + this.updateVariantsInEditor(); + }); + } + // Input for the variant - placeholder text varies by index const placeholder = index === 0 ? 'Original text' : index === this.variants.length - 1 && variant.trim() === '' ? 'Add a variant' : diff --git a/styles.css b/styles.css index 47bdcb0..eb8f5ba 100644 --- a/styles.css +++ b/styles.css @@ -245,6 +245,34 @@ background-color: rgba(var(--interactive-accent-rgb), 0.1); } +/* Drag and drop styling */ +.variant-editor-row.dragging { + opacity: 0.4; + border: 1px dashed var(--interactive-accent); + background-color: rgba(var(--interactive-accent-rgb), 0.1); +} + +/* Hide the drag ghost image */ +.variant-editor-drag-ghost { + opacity: 0; + position: absolute; + height: 0; + width: 0; + overflow: hidden; +} + +.variant-editor-row.drag-over { + border-top: 2px solid var(--interactive-accent); + margin-top: 2px; +} + +/* Special handling for active rows with drag-over to make indicator visible over rainbow */ +.variant-editor-row-active.drag-over { + box-shadow: 0 -4px 0 0 var(--interactive-accent); + border-top: none; +} + + /* Delete button styling */ .variant-editor-delete-button { background: none !important;