Monorepo for Tangled
at 74318eac9fdd72cf69e916276814351931ed0dcb 113 lines 3.6 kB view raw
1{{ define "fragments/resizable" }} 2 <script> 3 class ResizablePanel { 4 constructor(resizerElement) { 5 this.resizer = resizerElement; 6 this.isResizing = false; 7 this.type = resizerElement.dataset.resizer; 8 this.targetId = resizerElement.dataset.target; 9 this.target = document.getElementById(this.targetId); 10 this.min = parseInt(resizerElement.dataset.min) || 100; 11 this.max = parseInt(resizerElement.dataset.max) || Infinity; 12 13 this.direction = resizerElement.dataset.direction || 'before'; // 'before' or 'after' 14 15 this.handleMouseDown = this.handleMouseDown.bind(this); 16 this.handleMouseMove = this.handleMouseMove.bind(this); 17 this.handleMouseUp = this.handleMouseUp.bind(this); 18 19 this.init(); 20 } 21 22 init() { 23 this.resizer.addEventListener('mousedown', this.handleMouseDown); 24 } 25 26 handleMouseDown(e) { 27 e.preventDefault(); 28 this.isResizing = true; 29 this.resizer.classList.add('resizing'); 30 document.body.style.cursor = this.type === 'vertical' ? 'col-resize' : 'row-resize'; 31 document.body.style.userSelect = 'none'; 32 33 this.startX = e.clientX; 34 this.startY = e.clientY; 35 this.startWidth = this.target.offsetWidth; 36 this.startHeight = this.target.offsetHeight; 37 38 document.addEventListener('mousemove', this.handleMouseMove); 39 document.addEventListener('mouseup', this.handleMouseUp); 40 } 41 42 handleMouseMove(e) { 43 if (!this.isResizing) return; 44 45 if (this.type === 'vertical') { 46 let newWidth; 47 48 if (this.direction === 'after') { 49 const deltaX = this.startX - e.clientX; 50 newWidth = this.startWidth + deltaX; 51 } else { 52 const deltaX = e.clientX - this.startX; 53 newWidth = this.startWidth + deltaX; 54 } 55 56 if (newWidth >= this.min && newWidth <= this.max) { 57 this.target.style.width = newWidth + 'px'; 58 this.target.style.flexShrink = '0'; 59 } 60 } else { 61 let newHeight; 62 63 if (this.direction === 'after') { 64 const deltaY = this.startY - e.clientY; 65 newHeight = this.startHeight + deltaY; 66 } else { 67 const deltaY = e.clientY - this.startY; 68 newHeight = this.startHeight + deltaY; 69 } 70 71 if (newHeight >= this.min && newHeight <= this.max) { 72 this.target.style.height = newHeight + 'px'; 73 } 74 } 75 } 76 77 handleMouseUp() { 78 if (!this.isResizing) return; 79 80 this.isResizing = false; 81 this.resizer.classList.remove('resizing'); 82 document.body.style.cursor = ''; 83 document.body.style.userSelect = ''; 84 85 document.removeEventListener('mousemove', this.handleMouseMove); 86 document.removeEventListener('mouseup', this.handleMouseUp); 87 } 88 89 destroy() { 90 this.resizer.removeEventListener('mousedown', this.handleMouseDown); 91 document.removeEventListener('mousemove', this.handleMouseMove); 92 document.removeEventListener('mouseup', this.handleMouseUp); 93 } 94 } 95 96 function initializeResizers() { 97 const resizers = document.querySelectorAll('[data-resizer]'); 98 const instances = []; 99 100 resizers.forEach(resizer => { 101 instances.push(new ResizablePanel(resizer)); 102 }); 103 104 return instances; 105 } 106 107 if (document.readyState === 'loading') { 108 document.addEventListener('DOMContentLoaded', initializeResizers); 109 } else { 110 initializeResizers(); 111 } 112 </script> 113{{ end }}