From d1fdfb140cc440664f77a24886172f9976a05a31 Mon Sep 17 00:00:00 2001 From: soryu Date: Tue, 28 Apr 2026 19:12:52 +0100 Subject: feat: revert broken directive PRs, re-implement Lexical document orchestrator (#98) * feat: soryu-co/soryu - makima: Revert broken directive PRs and verify clean build * feat: soryu-co/soryu - makima: Re-implement frontend: Lexical document editor with feature flag and base components * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: Add contract blocks, expandable log rows, and interaction controls * WIP: heartbeat checkpoint * feat: soryu-co/soryu - makima: End-to-end build verification and integration polish --- .../src/components/document/AutoSavePlugin.tsx | 140 --------------------- 1 file changed, 140 deletions(-) delete mode 100644 frontend/src/components/document/AutoSavePlugin.tsx (limited to 'frontend/src/components/document/AutoSavePlugin.tsx') diff --git a/frontend/src/components/document/AutoSavePlugin.tsx b/frontend/src/components/document/AutoSavePlugin.tsx deleted file mode 100644 index d3d0eb5..0000000 --- a/frontend/src/components/document/AutoSavePlugin.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import { useEffect, useRef, useState, useCallback } from 'react'; -import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; -import { UNDO_COMMAND } from 'lexical'; - -const COUNTDOWN_DURATION_MS = 3000; -const TICK_INTERVAL_MS = 50; - -interface AutoSavePluginProps { - onAutoSave: (content: string) => void; - getContent: () => string; - enabled?: boolean; -} - -export default function AutoSavePlugin({ - onAutoSave, - getContent, - enabled = true, -}: AutoSavePluginProps) { - const [editor] = useLexicalComposerContext(); - const [countdown, setCountdown] = useState(null); - const timerRef = useRef | null>(null); - const startTimeRef = useRef(0); - const pendingContentRef = useRef(''); - const lastSavedContentRef = useRef(''); - - const clearTimer = useCallback(() => { - if (timerRef.current !== null) { - clearInterval(timerRef.current); - timerRef.current = null; - } - setCountdown(null); - }, []); - - const cancelCountdown = useCallback(() => { - clearTimer(); - }, [clearTimer]); - - const startCountdown = useCallback( - (content: string) => { - pendingContentRef.current = content; - clearTimer(); - - startTimeRef.current = Date.now(); - setCountdown(COUNTDOWN_DURATION_MS); - - timerRef.current = setInterval(() => { - const elapsed = Date.now() - startTimeRef.current; - const remaining = COUNTDOWN_DURATION_MS - elapsed; - - if (remaining <= 0) { - clearTimer(); - lastSavedContentRef.current = pendingContentRef.current; - onAutoSave(pendingContentRef.current); - } else { - setCountdown(remaining); - } - }, TICK_INTERVAL_MS); - }, - [clearTimer, onAutoSave] - ); - - // Listen for editor updates (content changes) - useEffect(() => { - if (!enabled) return; - - const unregister = editor.registerUpdateListener(({ editorState, dirtyElements, dirtyLeaves }) => { - // Only trigger on actual content changes - if (dirtyElements.size === 0 && dirtyLeaves.size === 0) return; - - const content = getContent(); - if (content !== lastSavedContentRef.current) { - startCountdown(content); - } - }); - - return unregister; - }, [editor, enabled, getContent, startCountdown]); - - // Listen for undo command to cancel countdown - useEffect(() => { - const unregister = editor.registerCommand( - UNDO_COMMAND, - () => { - cancelCountdown(); - return false; // Don't prevent the undo from executing - }, - 1 // COMMAND_PRIORITY_LOW - ); - - return unregister; - }, [editor, cancelCountdown]); - - // Listen for Escape key to cancel countdown - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - if (e.key === 'Escape' && countdown !== null) { - e.preventDefault(); - cancelCountdown(); - } - }; - - document.addEventListener('keydown', handleKeyDown); - return () => document.removeEventListener('keydown', handleKeyDown); - }, [countdown, cancelCountdown]); - - // Cleanup on unmount - useEffect(() => { - return () => { - if (timerRef.current !== null) { - clearInterval(timerRef.current); - } - }; - }, []); - - if (countdown === null) return null; - - const progressPercent = (countdown / COUNTDOWN_DURATION_MS) * 100; - const secondsLeft = Math.ceil(countdown / 1000); - - return ( -
- - Saving in {secondsLeft}s... Esc to cancel - -
-
-
- -
- ); -} -- cgit v1.2.3