summaryrefslogtreecommitdiff
path: root/frontend/src/components/document/AutoSavePlugin.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components/document/AutoSavePlugin.tsx')
-rw-r--r--frontend/src/components/document/AutoSavePlugin.tsx140
1 files changed, 0 insertions, 140 deletions
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<number | null>(null);
- const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
- const startTimeRef = useRef<number>(0);
- const pendingContentRef = useRef<string>('');
- const lastSavedContentRef = useRef<string>('');
-
- 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 (
- <div className="autosave-bar">
- <span className="autosave-bar-text">
- Saving in {secondsLeft}s... <kbd>Esc</kbd> to cancel
- </span>
- <div className="autosave-bar-progress-track">
- <div
- className="autosave-bar-progress-fill"
- style={{ width: `${progressPercent}%` }}
- />
- </div>
- <button
- className="autosave-bar-cancel"
- onClick={cancelCountdown}
- type="button"
- >
- Cancel
- </button>
- </div>
- );
-}