/** * ui/utils.js - Shared UI utilities */ /** * makeDraggable - Helper to make an element draggable by its header or itself */ export function makeDraggable(el, headerSelector) { const header = headerSelector ? el.querySelector(headerSelector) : el; if (!header) return; let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; header.onmousedown = dragMouseDown; header.style.cursor = 'move'; function dragMouseDown(e) { // Don't prevent default on inputs, buttons, or sliders inside if (['INPUT', 'BUTTON', 'SELECT', 'TEXTAREA'].includes(e.target.tagName)) return; pos3 = e.clientX; pos4 = e.clientY; document.onmouseup = closeDragElement; document.onmousemove = elementDrag; } function elementDrag(e) { e.preventDefault(); pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; el.style.top = (el.offsetTop - pos2) + "px"; el.style.left = (el.offsetLeft - pos1) + "px"; el.style.bottom = 'auto'; // Break fixed constraints el.style.right = 'auto'; } function closeDragElement() { document.onmouseup = null; document.onmousemove = null; } } /** * showConfirmModal - Displays a professional confirmation modal * @param {Object} options { title, message, onConfirm, showDontAskAgain } */ export function showConfirmModal({ title, message, onConfirm, onCancel, showDontAskAgain = false, checkboxKey = '' }) { const overlay = document.createElement('div'); overlay.className = 'modal-overlay glass-panel active'; overlay.style.zIndex = '10000'; const modal = document.createElement('div'); modal.className = 'modal-content animate-up'; modal.style.width = '320px'; modal.style.padding = '0'; modal.innerHTML = ` `; overlay.appendChild(modal); document.body.appendChild(overlay); const close = () => overlay.remove(); modal.querySelector('#modal-cancel').onclick = () => { close(); if (onCancel) onCancel(); }; modal.querySelector('#modal-confirm').onclick = () => { const dontAsk = modal.querySelector('#dont-ask-again')?.checked; if (dontAsk && checkboxKey) { import('../settings/store.js').then(m => m.updateSetting(checkboxKey, false)); } close(); if (onConfirm) onConfirm(); }; overlay.onclick = (e) => { if (e.target === overlay) close(); }; } import { showToast as coreShowToast } from './toast.js'; /** * showToast - Compatibility wrapper for modularized toast */ export function showToast(message, type = 'info', duration = 3500) { coreShowToast(message, type, duration); }