From cbe40ac1128eedcda30812285cbec003acb8adc1 Mon Sep 17 00:00:00 2001 From: Hsieh Chin Fan Date: Sat, 21 Sep 2024 16:40:22 +0800 Subject: refactor: layout class * put class Layout and OverlayLayout together * apply extend on OverlayLayout * rename layouts: "none" -> "normal", "side" -> "side-by-side" --- src/Layout.mjs | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/Layout.mjs (limited to 'src/Layout.mjs') diff --git a/src/Layout.mjs b/src/Layout.mjs new file mode 100644 index 0000000..20e8a23 --- /dev/null +++ b/src/Layout.mjs @@ -0,0 +1,117 @@ +import PlainDraggable from 'plain-draggable' +import { onRemove } from './utils' + +export class Layout { + constructor(options = {}) { + if (!options.name) throw Error("Layout name is not given") + this.name = options.name + this.enterHandler = options.enterHandler + this.leaveHandler = options.leaveHandler + } + valueOf = () => this.name +} + +export class OverlayLayout extends Layout { + name = "overlay" + + enterHandler = (dumbymap) => { + const container = dumbymap.htmlHolder + const moveIntoDraggable = (block) => { + // Create draggable block + const draggableBlock = document.createElement('div') + draggableBlock.classList.add('draggable-block') + draggableBlock.innerHTML = ` +
+
\u2630
+
+
+
\u2795
+
\u2796
+
+ ` + + // Add draggable part + const draggablePart = draggableBlock.querySelector('.draggable') + draggablePart.title = 'Use middle-click to remove block' + draggablePart.onmouseup = (e) => { + if (e.button === 1) { + // Hide block with middle click + draggableBlock.style.display = "none"; + } + } + + // Set elements + draggableBlock.appendChild(draggablePart) + draggableBlock.appendChild(block) + container.appendChild(draggableBlock) + + // Add draggable instance + const draggableInstance = new PlainDraggable(draggableBlock, { + handle: draggablePart, + snap: { x: { step: 20 }, y: { step: 20 } }, + }) + + // Plus/Minus font-size of content + const plusButton = draggableBlock.querySelector('#plus-font-size') + plusButton.onclick = () => { + const fontSize = parseFloat(getComputedStyle(block).fontSize) / 16 + block.style.fontSize = `${fontSize + 0.1}rem` + } + const minusButton = draggableBlock.querySelector('#minus-font-size') + minusButton.onclick = () => { + const fontSize = parseFloat(getComputedStyle(block).fontSize) / 16 + block.style.fontSize = `${fontSize - 0.1}rem` + } + draggableInstance.onDragStart = () => { + plusButton.style.opacity = '0' + minusButton.style.opacity = '0' + } + draggableInstance.onDragEnd = () => { + plusButton.style = '' + minusButton.style = '' + } + + // Reposition draggable instance when resized + new ResizeObserver(() => { + try { + draggableInstance.position(); + } catch (_) { + null + } + }).observe(draggableBlock); + + // Callback for remove + onRemove(draggableBlock, () => { + draggableInstance.remove() + }) + + return draggableInstance + } + + // Create draggable blocks and set each position by previous one + let [x, y] = [0, 0] + dumbymap.blocks.map(moveIntoDraggable) + .forEach(draggable => { + draggable.left = x + draggable.top = y + const rect = draggable.element.getBoundingClientRect() + x += rect.width + 30 + if (x > window.innerWidth) { + y += 200 + x = x % window.innerWidth + } + }) + } + leaveHandler = (dumbymap) => { + const container = dumbymap.htmlHolder + const resumeFromDraggable = (block) => { + const draggableContainer = block.closest('.draggable-block') + if (!draggableContainer) return + container.appendChild(block) + block.removeAttribute('style') + draggableContainer.remove() + } + dumbymap.blocks.forEach(resumeFromDraggable) + } +} + -- cgit v1.2.3-70-g09d2