Mercurial
changeset 208:5d3e116dd745
[MrJuneJune] made it more mobile friendly.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sun, 15 Feb 2026 12:33:54 -0800 |
| parents | 58d9b64d8dca |
| children | 3b47e82ac57e |
| files | mrjunejune/src/tools/index.html rich_editor/rich_editor.js |
| diffstat | 2 files changed, 170 insertions(+), 10 deletions(-) [+] |
line wrap: on
line diff
--- a/mrjunejune/src/tools/index.html Sun Feb 15 12:25:50 2026 -0800 +++ b/mrjunejune/src/tools/index.html Sun Feb 15 12:33:54 2026 -0800 @@ -11,9 +11,9 @@ <ul class="nav-list"> <li><a href="/tools/markdown_to_html">MarkDown to HTML</a></li> <li><a href="/tools/file_converter">Images to Webp / Video to Mp4</a></li> + <li><a href="/notes">Personal Notes</a></li> </ul> <h3> TODOs </h3> - <p> Probably should add this... </p> <ul class="nav-list"> <li>- Simple online LaTex editor.</li> <li>- Online HLS player.</li>
--- a/rich_editor/rich_editor.js Sun Feb 15 12:25:50 2026 -0800 +++ b/rich_editor/rich_editor.js Sun Feb 15 12:33:54 2026 -0800 @@ -87,9 +87,22 @@ return toolbar; } + function ensureViewportMeta() { + // Check if viewport meta tag exists + let viewport = document.querySelector('meta[name="viewport"]'); + if (!viewport) { + viewport = document.createElement('meta'); + viewport.name = 'viewport'; + viewport.content = 'width=device-width, initial-scale=1.0, maximum-scale=5.0'; + document.head.appendChild(viewport); + } + } + function createStyles() { if (document.getElementById('rich-editor-styles')) return; + ensureViewportMeta(); + const style = document.createElement('style'); style.id = 'rich-editor-styles'; style.textContent = ` @@ -294,6 +307,8 @@ color: #0078ff; pointer-events: none; z-index: 10; + padding: 20px; + text-align: center; } .rich-editor-status { @@ -311,6 +326,128 @@ ol,ul { padding: 16px; } + + /* Mobile optimizations */ + @media (max-width: 720px) { + .rich-editor-toolbar { + padding: 6px; + gap: 3px; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + + .rich-editor-btn { + min-width: 44px; + min-height: 44px; + padding: 8px; + flex-shrink: 0; + } + + .rich-editor-content { + min-height: 200px; + padding: 12px; + font-size: 16px; /* Prevents iOS zoom */ + line-height: 1.6; + } + + .rich-editor-content h1 { + font-size: 1.75em; + } + + .rich-editor-content h2 { + font-size: 1.5em; + } + + .rich-editor-content h3 { + font-size: 1.25em; + } + + .rich-editor-status { + font-size: 11px; + padding: 6px 8px; + } + + /* Mobile-friendly image resizing */ + .rich-editor-resize-handle { + width: 20px; + height: 20px; + border-width: 3px; + } + + .rich-editor-resize-handle.nw { + top: -10px; + left: -10px; + } + + .rich-editor-resize-handle.ne { + top: -10px; + right: -10px; + } + + .rich-editor-resize-handle.sw { + bottom: -10px; + left: -10px; + } + + .rich-editor-resize-handle.se { + bottom: -10px; + right: -10px; + } + + .rich-editor-size-input { + top: -40px; + padding: 6px 10px; + } + + .rich-editor-size-input input { + width: 70px; + padding: 4px 6px; + font-size: 16px; /* Prevents iOS zoom */ + } + + /* Better touch targets for images */ + .rich-editor-content img { + margin: 12px 0; + } + + /* Hide drop overlay text on small screens */ + .rich-editor-upload-overlay { + font-size: 16px; + } + + /* Make link/note dialogs mobile-friendly */ + .rich-editor-content a { + padding: 2px 0; + } + } + + /* Extra small devices */ + @media (max-width: 480px) { + .rich-editor-toolbar { + padding: 4px; + gap: 2px; + } + + .rich-editor-btn { + min-width: 40px; + min-height: 40px; + padding: 6px; + } + + .rich-editor-content { + padding: 10px; + font-size: 16px; + } + + .rich-editor-size-input { + font-size: 11px; + } + + .rich-editor-size-input input { + width: 60px; + font-size: 14px; + } + } `; document.head.appendChild(style); } @@ -776,12 +913,21 @@ handle.className = `rich-editor-resize-handle ${corner}`; handle.dataset.corner = corner; + // Mouse events handle.addEventListener('mousedown', (e) => { e.preventDefault(); e.stopPropagation(); this.startResize(e, img, corner); }); + // Touch events for mobile + handle.addEventListener('touchstart', (e) => { + e.preventDefault(); + e.stopPropagation(); + const touch = e.touches[0]; + this.startResize(touch, img, corner, true); + }); + wrapper.appendChild(handle); }); @@ -824,7 +970,7 @@ this.state.selectedImage = null; } - startResize(e, img, corner) { + startResize(e, img, corner, isTouch = false) { this.state.resizing = true; const startX = e.clientX; @@ -833,11 +979,14 @@ const startHeight = img.height; const aspectRatio = startWidth / startHeight; - const onMouseMove = (e) => { + const onMove = (e) => { if (!this.state.resizing) return; - let deltaX = e.clientX - startX; - let deltaY = e.clientY - startY; + const clientX = isTouch ? e.touches[0].clientX : e.clientX; + const clientY = isTouch ? e.touches[0].clientY : e.clientY; + + let deltaX = clientX - startX; + let deltaY = clientY - startY; // Adjust delta based on corner if (corner === 'nw' || corner === 'sw') { @@ -854,10 +1003,16 @@ this.resizeImage(img, newWidth, aspectRatio); }; - const onMouseUp = () => { + const onEnd = () => { this.state.resizing = false; - document.removeEventListener('mousemove', onMouseMove); - document.removeEventListener('mouseup', onMouseUp); + + if (isTouch) { + document.removeEventListener('touchmove', onMove); + document.removeEventListener('touchend', onEnd); + } else { + document.removeEventListener('mousemove', onMove); + document.removeEventListener('mouseup', onEnd); + } // Update width input const wrapper = img.parentElement; @@ -869,8 +1024,13 @@ if (this.debouncedSave) this.debouncedSave(); }; - document.addEventListener('mousemove', onMouseMove); - document.addEventListener('mouseup', onMouseUp); + if (isTouch) { + document.addEventListener('touchmove', onMove, { passive: false }); + document.addEventListener('touchend', onEnd); + } else { + document.addEventListener('mousemove', onMove); + document.addEventListener('mouseup', onEnd); + } } resizeImage(img, newWidth, aspectRatio = null) {