diff rich_editor/rich_editor.js @ 208:5d3e116dd745

[MrJuneJune] made it more mobile friendly.
author MrJuneJune <me@mrjunejune.com>
date Sun, 15 Feb 2026 12:33:54 -0800
parents 240337164a80
children
line wrap: on
line diff
--- 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) {