Prechádzať zdrojové kódy

refactor: enhance post editor UI and component structure

Adam Jafarov 3 týždňov pred
rodič
commit
39bd2f8647
1 zmenil súbory, kde vykonal 58 pridanie a 28 odobranie
  1. 58 28
      src/components/PostEditor.jsx

+ 58 - 28
src/components/PostEditor.jsx

@@ -326,11 +326,17 @@ function PostEditor() {
 
         isScrollingRef.current = true;
         const { scrollTop, scrollHeight, clientHeight } = scrollContainer;
-        const scrollPercent = scrollHeight > clientHeight ? scrollTop / (scrollHeight - clientHeight) : 0;
+        const maxScroll = scrollHeight - clientHeight;
 
         const previewNode = previewRef.current;
-        if (previewNode.scrollHeight > previewNode.clientHeight) {
-            previewNode.scrollTop = scrollPercent * (previewNode.scrollHeight - previewNode.clientHeight);
+        const previewMaxScroll = previewNode.scrollHeight - previewNode.clientHeight;
+
+        // If at the end (or very close), snap to end
+        if (maxScroll <= 0 || scrollTop >= maxScroll - 2) {
+            previewNode.scrollTop = previewMaxScroll;
+        } else {
+            const scrollPercent = scrollHeight > clientHeight ? scrollTop / (scrollHeight - clientHeight) : 0;
+            previewNode.scrollTop = scrollPercent * previewMaxScroll;
         }
 
         setTimeout(() => { isScrollingRef.current = false; }, 50);
@@ -344,11 +350,22 @@ function PostEditor() {
         isScrollingRef.current = true;
         const previewNode = previewRef.current;
         const { scrollTop, scrollHeight, clientHeight } = previewNode;
-        const scrollPercent = scrollHeight > clientHeight ? scrollTop / (scrollHeight - clientHeight) : 0;
+        const maxScroll = scrollHeight - clientHeight;
 
         const scrollContainer = editorWrapperRef.current.querySelector('.w-md-editor-area');
-        if (scrollContainer && scrollContainer.scrollHeight > scrollContainer.clientHeight) {
-            scrollContainer.scrollTop = scrollPercent * (scrollContainer.scrollHeight - scrollContainer.clientHeight);
+        if (!scrollContainer) {
+            isScrollingRef.current = false;
+            return;
+        }
+
+        const editorMaxScroll = scrollContainer.scrollHeight - scrollContainer.clientHeight;
+
+        // If at the end (or very close), snap to end
+        if (maxScroll <= 0 || scrollTop >= maxScroll - 2) {
+            scrollContainer.scrollTop = editorMaxScroll;
+        } else {
+            const scrollPercent = scrollHeight > clientHeight ? scrollTop / (scrollHeight - clientHeight) : 0;
+            scrollContainer.scrollTop = scrollPercent * editorMaxScroll;
         }
 
         setTimeout(() => { isScrollingRef.current = false; }, 50);
@@ -387,32 +404,45 @@ function PostEditor() {
     }, [formData.title]);
 
 
-    // Scroll Sync & Flicker Effect
+    // Re-sync scroll when images finish loading (handles layout shifts)
     useEffect(() => {
-        if (activeTab === "preview" || viewMode === "split") {
-            const elements = document.querySelectorAll('[data-line]');
-            let target = null;
-            let maxLine = -1;
-
-            elements.forEach(el => {
-                const line = parseInt(el.getAttribute('data-line'), 10);
-                if (line <= cursorLine && line > maxLine) {
-                    maxLine = line;
-                    target = el;
-                }
-            });
+        if (viewMode !== "split" || !previewRef.current) return;
 
-            if (target) {
-                target.scrollIntoView({ behavior: 'smooth', block: 'center' });
+        const previewNode = previewRef.current;
+        const images = previewNode.querySelectorAll('img');
+
+        const handleImageLoad = () => {
+            // Small delay to let layout settle
+            setTimeout(() => {
+                // Re-apply current scroll sync from editor to preview
+                if (editorWrapperRef.current) {
+                    const scrollContainer = editorWrapperRef.current.querySelector('.w-md-editor-area');
+                    if (scrollContainer) {
+                        const { scrollTop, scrollHeight, clientHeight } = scrollContainer;
+                        const maxScroll = scrollHeight - clientHeight;
+                        const previewMaxScroll = previewNode.scrollHeight - previewNode.clientHeight;
+
+                        if (maxScroll > 0 && previewMaxScroll > 0) {
+                            const scrollPercent = scrollTop / maxScroll;
+                            previewNode.scrollTop = scrollPercent * previewMaxScroll;
+                        }
+                    }
+                }
+            }, 100);
+        };
 
-                // Add flicker effect
-                target.classList.add('highlight-pulse');
-                setTimeout(() => {
-                    target.classList.remove('highlight-pulse');
-                }, 1500);
+        images.forEach(img => {
+            if (!img.complete) {
+                img.addEventListener('load', handleImageLoad);
             }
-        }
-    }, [activeTab, cursorLine, viewMode]);
+        });
+
+        return () => {
+            images.forEach(img => {
+                img.removeEventListener('load', handleImageLoad);
+            });
+        };
+    }, [viewMode, sanitizedPreview]);
 
     return (
         <div className="min-h-screen theme-bg font-sans theme-text selection:bg-blue-100 selection:text-blue-900 flex flex-col transition-colors duration-300">