epic-ux-design #1
@@ -132,6 +132,9 @@ export function AutoLabelSuggestionDialog({
|
|||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
<DialogContent className="max-w-md">
|
<DialogContent className="max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle className="sr-only">{t('ai.autoLabels.analyzing')}</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
<div className="flex flex-col items-center justify-center py-12">
|
<div className="flex flex-col items-center justify-center py-12">
|
||||||
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
||||||
<p className="mt-4 text-sm text-muted-foreground">
|
<p className="mt-4 text-sm text-muted-foreground">
|
||||||
|
|||||||
@@ -184,6 +184,11 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const localNotesRef = useRef<Note[]>(localNotes)
|
||||||
|
useEffect(() => {
|
||||||
|
localNotesRef.current = localNotes
|
||||||
|
}, [localNotes])
|
||||||
|
|
||||||
const handleDragStart = useCallback((event: DragStartEvent) => {
|
const handleDragStart = useCallback((event: DragStartEvent) => {
|
||||||
setActiveId(event.active.id as string);
|
setActiveId(event.active.id as string);
|
||||||
startDrag(event.active.id as string);
|
startDrag(event.active.id as string);
|
||||||
@@ -196,25 +201,25 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
|
|||||||
|
|
||||||
if (!over || active.id === over.id) return;
|
if (!over || active.id === over.id) return;
|
||||||
|
|
||||||
setLocalNotes(prev => {
|
const reordered = arrayMove(
|
||||||
const oldIndex = prev.findIndex(n => n.id === active.id);
|
localNotesRef.current,
|
||||||
const newIndex = prev.findIndex(n => n.id === over.id);
|
localNotesRef.current.findIndex(n => n.id === active.id),
|
||||||
if (oldIndex === -1 || newIndex === -1) return prev;
|
localNotesRef.current.findIndex(n => n.id === over.id),
|
||||||
return arrayMove(prev, oldIndex, newIndex);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
// Persist new order to DB (sans revalidation pour éviter le flash)
|
if (reordered.length === 0) return;
|
||||||
setLocalNotes(current => {
|
|
||||||
const ids = current.map(n => n.id);
|
setLocalNotes(reordered);
|
||||||
updateFullOrderWithoutRevalidation(ids).catch(err => {
|
// Persist order outside of setState to avoid "setState in render" warning
|
||||||
console.error('Failed to persist order:', err);
|
const ids = reordered.map(n => n.id);
|
||||||
});
|
updateFullOrderWithoutRevalidation(ids).catch(err => {
|
||||||
return current;
|
console.error('Failed to persist order:', err);
|
||||||
});
|
});
|
||||||
}, [endDrag]);
|
}, [endDrag]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DndContext
|
<DndContext
|
||||||
|
id="masonry-dnd"
|
||||||
sensors={sensors}
|
sensors={sensors}
|
||||||
collisionDetection={closestCenter}
|
collisionDetection={closestCenter}
|
||||||
onDragStart={handleDragStart}
|
onDragStart={handleDragStart}
|
||||||
|
|||||||
@@ -370,6 +370,7 @@ export function NotesTabsView({ notes, onEdit, currentNotebookId }: NotesTabsVie
|
|||||||
aria-label={t('notes.viewTabs')}
|
aria-label={t('notes.viewTabs')}
|
||||||
>
|
>
|
||||||
<DndContext
|
<DndContext
|
||||||
|
id="notes-tabs-dnd"
|
||||||
sensors={sensors}
|
sensors={sensors}
|
||||||
collisionDetection={closestCenter}
|
collisionDetection={closestCenter}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
|
|||||||
Reference in New Issue
Block a user