feat(workspace): activate write lock immediately on bullet drag-and-drop start
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 58s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 58s
This commit is contained in:
1 parent
09725611b5
commit
0008e9c420
1 file changed
+73
-2
@@ -198,6 +198,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
const idleUnlockTimerRef = useRef<any>(null);
|
const idleUnlockTimerRef = useRef<any>(null);
|
||||||
const currentDocIdRef = useRef<string | null>(null);
|
const currentDocIdRef = useRef<string | null>(null);
|
||||||
const isEditorFocusedRef = useRef(false);
|
const isEditorFocusedRef = useRef(false);
|
||||||
|
const isDraggingBlockRef = useRef(false);
|
||||||
|
|
||||||
const blockInputRefs = useRef<Record<string, HTMLTextAreaElement | HTMLInputElement | null>>({});
|
const blockInputRefs = useRef<Record<string, HTMLTextAreaElement | HTMLInputElement | null>>({});
|
||||||
|
|
||||||
@@ -339,8 +340,15 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
pendingSaveDocRef.current = null;
|
pendingSaveDocRef.current = null;
|
||||||
setSaveState('saved');
|
setSaveState('saved');
|
||||||
}
|
}
|
||||||
if (!isEditorFocusedRef.current && holdsLockRef.current) {
|
if (!isEditorFocusedRef.current && !isDraggingBlockRef.current && holdsLockRef.current) {
|
||||||
releaseMyLock();
|
if (idleUnlockTimerRef.current) {
|
||||||
|
clearTimeout(idleUnlockTimerRef.current);
|
||||||
|
}
|
||||||
|
idleUnlockTimerRef.current = setTimeout(async () => {
|
||||||
|
if (!isEditorFocusedRef.current && !isDraggingBlockRef.current && holdsLockRef.current) {
|
||||||
|
await releaseMyLock();
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1940,6 +1948,18 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
// Drag & Drop Handlers on the Bullet row / Grip / Dot
|
// Drag & Drop Handlers on the Bullet row / Grip / Dot
|
||||||
const handleBlockDragStart = (e: React.DragEvent, blockId: string) => {
|
const handleBlockDragStart = (e: React.DragEvent, blockId: string) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
if (isReadOnly) {
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isDraggingBlockRef.current = true;
|
||||||
|
if (idleUnlockTimerRef.current) {
|
||||||
|
clearTimeout(idleUnlockTimerRef.current);
|
||||||
|
idleUnlockTimerRef.current = null;
|
||||||
|
}
|
||||||
|
// Activate write lock immediately upon dragging
|
||||||
|
ensureLock();
|
||||||
|
|
||||||
e.dataTransfer.setData('application/mindsift-block-id', blockId);
|
e.dataTransfer.setData('application/mindsift-block-id', blockId);
|
||||||
e.dataTransfer.setData('text/plain', blockId);
|
e.dataTransfer.setData('text/plain', blockId);
|
||||||
e.dataTransfer.effectAllowed = 'move';
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
@@ -1990,6 +2010,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
draggingBlockId;
|
draggingBlockId;
|
||||||
|
|
||||||
const position = explicitPosition || dragOverBlockTarget?.position || 'after';
|
const position = explicitPosition || dragOverBlockTarget?.position || 'after';
|
||||||
|
isDraggingBlockRef.current = false;
|
||||||
setDraggingBlockId(null);
|
setDraggingBlockId(null);
|
||||||
setDragOverBlockTarget(null);
|
setDragOverBlockTarget(null);
|
||||||
|
|
||||||
@@ -2054,6 +2075,16 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
persistDocument({ ...selectedDoc, blocks }, true);
|
persistDocument({ ...selectedDoc, blocks }, true);
|
||||||
|
|
||||||
|
if (idleUnlockTimerRef.current) {
|
||||||
|
clearTimeout(idleUnlockTimerRef.current);
|
||||||
|
}
|
||||||
|
idleUnlockTimerRef.current = setTimeout(async () => {
|
||||||
|
if (!isEditorFocusedRef.current && !isDraggingBlockRef.current && holdsLockRef.current) {
|
||||||
|
await flushPendingSave();
|
||||||
|
await releaseMyLock();
|
||||||
|
}
|
||||||
|
}, 2500);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Export full document as portable Logseq-indented Markdown
|
// Export full document as portable Logseq-indented Markdown
|
||||||
@@ -3559,10 +3590,30 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
{/* Drag Handle on hover - tightened spacing to the bullet */}
|
{/* Drag Handle on hover - tightened spacing to the bullet */}
|
||||||
<div
|
<div
|
||||||
draggable={!isReadOnly}
|
draggable={!isReadOnly}
|
||||||
|
onMouseDown={() => {
|
||||||
|
if (!isReadOnly) {
|
||||||
|
if (idleUnlockTimerRef.current) {
|
||||||
|
clearTimeout(idleUnlockTimerRef.current);
|
||||||
|
idleUnlockTimerRef.current = null;
|
||||||
|
}
|
||||||
|
isDraggingBlockRef.current = true;
|
||||||
|
ensureLock();
|
||||||
|
}
|
||||||
|
}}
|
||||||
onDragStart={(e) => !isReadOnly && handleBlockDragStart(e, block.id)}
|
onDragStart={(e) => !isReadOnly && handleBlockDragStart(e, block.id)}
|
||||||
onDragEnd={() => {
|
onDragEnd={() => {
|
||||||
|
isDraggingBlockRef.current = false;
|
||||||
setDraggingBlockId(null);
|
setDraggingBlockId(null);
|
||||||
setDragOverBlockTarget(null);
|
setDragOverBlockTarget(null);
|
||||||
|
if (idleUnlockTimerRef.current) {
|
||||||
|
clearTimeout(idleUnlockTimerRef.current);
|
||||||
|
}
|
||||||
|
idleUnlockTimerRef.current = setTimeout(async () => {
|
||||||
|
if (!isEditorFocusedRef.current && !isDraggingBlockRef.current && holdsLockRef.current) {
|
||||||
|
await flushPendingSave();
|
||||||
|
await releaseMyLock();
|
||||||
|
}
|
||||||
|
}, 2500);
|
||||||
}}
|
}}
|
||||||
className="opacity-0 group-hover:opacity-100 flex items-center pt-1 text-faint hover:text-accent cursor-grab active:cursor-grabbing flex-shrink-0 -ml-1 mr-0.5"
|
className="opacity-0 group-hover:opacity-100 flex items-center pt-1 text-faint hover:text-accent cursor-grab active:cursor-grabbing flex-shrink-0 -ml-1 mr-0.5"
|
||||||
title="Ziehen zum Verschieben"
|
title="Ziehen zum Verschieben"
|
||||||
@@ -3591,10 +3642,30 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
{/* Interactive Bullet Dot (Click: Zoom-in! Drag: Reorder! Drop on it: Nest as child!) */}
|
{/* Interactive Bullet Dot (Click: Zoom-in! Drag: Reorder! Drop on it: Nest as child!) */}
|
||||||
<div
|
<div
|
||||||
draggable={!isReadOnly}
|
draggable={!isReadOnly}
|
||||||
|
onMouseDown={() => {
|
||||||
|
if (!isReadOnly) {
|
||||||
|
if (idleUnlockTimerRef.current) {
|
||||||
|
clearTimeout(idleUnlockTimerRef.current);
|
||||||
|
idleUnlockTimerRef.current = null;
|
||||||
|
}
|
||||||
|
isDraggingBlockRef.current = true;
|
||||||
|
ensureLock();
|
||||||
|
}
|
||||||
|
}}
|
||||||
onDragStart={(e) => !isReadOnly && handleBlockDragStart(e, block.id)}
|
onDragStart={(e) => !isReadOnly && handleBlockDragStart(e, block.id)}
|
||||||
onDragEnd={() => {
|
onDragEnd={() => {
|
||||||
|
isDraggingBlockRef.current = false;
|
||||||
setDraggingBlockId(null);
|
setDraggingBlockId(null);
|
||||||
setDragOverBlockTarget(null);
|
setDragOverBlockTarget(null);
|
||||||
|
if (idleUnlockTimerRef.current) {
|
||||||
|
clearTimeout(idleUnlockTimerRef.current);
|
||||||
|
}
|
||||||
|
idleUnlockTimerRef.current = setTimeout(async () => {
|
||||||
|
if (!isEditorFocusedRef.current && !isDraggingBlockRef.current && holdsLockRef.current) {
|
||||||
|
await flushPendingSave();
|
||||||
|
await releaseMyLock();
|
||||||
|
}
|
||||||
|
}, 2500);
|
||||||
}}
|
}}
|
||||||
onDragOver={(e) => {
|
onDragOver={(e) => {
|
||||||
if (!isReadOnly && draggingBlockId && draggingBlockId !== block.id) {
|
if (!isReadOnly && draggingBlockId && draggingBlockId !== block.id) {
|
||||||
|
|||||||
Reference in new issue
Block a user