|
@@ -313,67 +313,69 @@ function PostEditor() {
|
|
|
const [settingsOpen, setSettingsOpen] = useState(false);
|
|
const [settingsOpen, setSettingsOpen] = useState(false);
|
|
|
|
|
|
|
|
const previewRef = useRef(null);
|
|
const previewRef = useRef(null);
|
|
|
|
|
+ const editorWrapperRef = useRef(null);
|
|
|
const isScrollingRef = useRef(false);
|
|
const isScrollingRef = useRef(false);
|
|
|
|
|
|
|
|
- // Scroll Sync: Editor -> Preview
|
|
|
|
|
- const handleEditorScroll = (e) => {
|
|
|
|
|
- if (!previewRef.current || viewMode !== "split") return;
|
|
|
|
|
|
|
+ // Scroll Sync: Editor -> Preview (percentage-based)
|
|
|
|
|
+ const syncEditorToPreview = () => {
|
|
|
|
|
+ if (!previewRef.current || !editorWrapperRef.current || viewMode !== "split") return;
|
|
|
if (isScrollingRef.current) return;
|
|
if (isScrollingRef.current) return;
|
|
|
|
|
|
|
|
|
|
+ const scrollContainer = editorWrapperRef.current.querySelector('.w-md-editor-area');
|
|
|
|
|
+ if (!scrollContainer) return;
|
|
|
|
|
+
|
|
|
isScrollingRef.current = true;
|
|
isScrollingRef.current = true;
|
|
|
- const textarea = e.target;
|
|
|
|
|
- const { scrollTop, scrollHeight, clientHeight } = textarea;
|
|
|
|
|
|
|
+ const { scrollTop, scrollHeight, clientHeight } = scrollContainer;
|
|
|
|
|
+ const scrollPercent = scrollHeight > clientHeight ? scrollTop / (scrollHeight - clientHeight) : 0;
|
|
|
|
|
|
|
|
- const scrollPercent = scrollTop / (scrollHeight - clientHeight);
|
|
|
|
|
const previewNode = previewRef.current;
|
|
const previewNode = previewRef.current;
|
|
|
-
|
|
|
|
|
- if (previewNode) {
|
|
|
|
|
|
|
+ if (previewNode.scrollHeight > previewNode.clientHeight) {
|
|
|
previewNode.scrollTop = scrollPercent * (previewNode.scrollHeight - previewNode.clientHeight);
|
|
previewNode.scrollTop = scrollPercent * (previewNode.scrollHeight - previewNode.clientHeight);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
setTimeout(() => { isScrollingRef.current = false; }, 50);
|
|
setTimeout(() => { isScrollingRef.current = false; }, 50);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- // Scroll Sync: Preview -> Editor
|
|
|
|
|
- const handlePreviewScroll = (e) => {
|
|
|
|
|
- if (viewMode !== "split") return;
|
|
|
|
|
|
|
+ // Scroll Sync: Preview -> Editor (percentage-based)
|
|
|
|
|
+ const syncPreviewToEditor = () => {
|
|
|
|
|
+ if (!previewRef.current || !editorWrapperRef.current || viewMode !== "split") return;
|
|
|
if (isScrollingRef.current) return;
|
|
if (isScrollingRef.current) return;
|
|
|
|
|
|
|
|
isScrollingRef.current = true;
|
|
isScrollingRef.current = true;
|
|
|
- const previewNode = e.target;
|
|
|
|
|
|
|
+ const previewNode = previewRef.current;
|
|
|
const { scrollTop, scrollHeight, clientHeight } = previewNode;
|
|
const { scrollTop, scrollHeight, clientHeight } = previewNode;
|
|
|
|
|
+ const scrollPercent = scrollHeight > clientHeight ? scrollTop / (scrollHeight - clientHeight) : 0;
|
|
|
|
|
|
|
|
- const scrollPercent = scrollTop / (scrollHeight - clientHeight);
|
|
|
|
|
-
|
|
|
|
|
- if (editorWrapperRef.current) {
|
|
|
|
|
- const textarea = editorWrapperRef.current.querySelector('textarea');
|
|
|
|
|
- if (textarea) {
|
|
|
|
|
- textarea.scrollTop = scrollPercent * (textarea.scrollHeight - textarea.clientHeight);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const scrollContainer = editorWrapperRef.current.querySelector('.w-md-editor-area');
|
|
|
|
|
+ if (scrollContainer && scrollContainer.scrollHeight > scrollContainer.clientHeight) {
|
|
|
|
|
+ scrollContainer.scrollTop = scrollPercent * (scrollContainer.scrollHeight - scrollContainer.clientHeight);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
setTimeout(() => { isScrollingRef.current = false; }, 50);
|
|
setTimeout(() => { isScrollingRef.current = false; }, 50);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- // Handle Scroll Sync using capture on wrapper since MDEditor might consume scroll on textarea
|
|
|
|
|
- // or better, ensure we target the right element.
|
|
|
|
|
- // The previous textareaProps onScroll should have worked if `MDEditor` passes it.
|
|
|
|
|
- // Let's try attaching it to the editor wrapper with capture to be safe.
|
|
|
|
|
- const editorWrapperRef = useRef(null);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ // Attach scroll listeners to both containers
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
|
|
+ if (viewMode !== "split") return;
|
|
|
|
|
+
|
|
|
const wrapper = editorWrapperRef.current;
|
|
const wrapper = editorWrapperRef.current;
|
|
|
- if (!wrapper) return;
|
|
|
|
|
|
|
+ const preview = previewRef.current;
|
|
|
|
|
+ if (!wrapper || !preview) return;
|
|
|
|
|
|
|
|
- // Find the textarea inside the wrapper
|
|
|
|
|
- const textarea = wrapper.querySelector('textarea');
|
|
|
|
|
- if (!textarea) return;
|
|
|
|
|
|
|
+ const scrollContainer = wrapper.querySelector('.w-md-editor-area');
|
|
|
|
|
+ if (!scrollContainer) return;
|
|
|
|
|
|
|
|
- // Attach scroll listener manually to ensure it's registered
|
|
|
|
|
- const handleScroll = (e) => handleEditorScroll(e);
|
|
|
|
|
- textarea.addEventListener('scroll', handleScroll);
|
|
|
|
|
- return () => textarea.removeEventListener('scroll', handleScroll);
|
|
|
|
|
- }, [viewMode]); // Re-attach if viewMode changes (though refs persist)
|
|
|
|
|
|
|
+ const handleEditorScroll = () => syncEditorToPreview();
|
|
|
|
|
+ const handlePreviewScroll = () => syncPreviewToEditor();
|
|
|
|
|
+
|
|
|
|
|
+ scrollContainer.addEventListener('scroll', handleEditorScroll);
|
|
|
|
|
+ preview.addEventListener('scroll', handlePreviewScroll);
|
|
|
|
|
+
|
|
|
|
|
+ return () => {
|
|
|
|
|
+ scrollContainer.removeEventListener('scroll', handleEditorScroll);
|
|
|
|
|
+ preview.removeEventListener('scroll', handlePreviewScroll);
|
|
|
|
|
+ };
|
|
|
|
|
+ }, [viewMode]);
|
|
|
|
|
|
|
|
// Auto-resize title textarea
|
|
// Auto-resize title textarea
|
|
|
const titleRef = React.useRef(null);
|
|
const titleRef = React.useRef(null);
|
|
@@ -568,7 +570,6 @@ function PostEditor() {
|
|
|
{/* Preview Column - Keep always mounted but hidden if needed */}
|
|
{/* Preview Column - Keep always mounted but hidden if needed */}
|
|
|
<article
|
|
<article
|
|
|
ref={previewRef}
|
|
ref={previewRef}
|
|
|
- onScroll={handlePreviewScroll}
|
|
|
|
|
className={`markdown-content prose dark:prose-invert max-w-none prose-lg ${viewMode === "split" ? "border-l pl-6 border-gray-200 dark:border-gray-800" : ""} ${activeTab !== "preview" && viewMode !== "split" ? "hidden" : ""}`}
|
|
className={`markdown-content prose dark:prose-invert max-w-none prose-lg ${viewMode === "split" ? "border-l pl-6 border-gray-200 dark:border-gray-800" : ""} ${activeTab !== "preview" && viewMode !== "split" ? "hidden" : ""}`}
|
|
|
style={{
|
|
style={{
|
|
|
height: viewMode === "split" ? window.innerHeight * 0.8 : 'auto',
|
|
height: viewMode === "split" ? window.innerHeight * 0.8 : 'auto',
|