feat: smart note history with manual/auto modes, delete entries, i18n fixes
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 1m16s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 1m16s
- Add noteHistoryMode setting (manual default / auto) with DB migration - Manual mode: commit button in editor toolbar creates snapshots on demand - Auto mode: smart snapshots with 20-char diff threshold + 5min cooldown, structural changes (color, pin, archive, labels) bypass cooldown - Add delete individual history entries from history modal - Fix sidebar: Notes nav no longer active on notebook pages - Fix sidebar icon: replace filled Lightbulb with outlined FileText - Fix title suggestions: change from amber to sky blue color scheme - Fix hydration mismatch: add suppressHydrationWarning on locale dates - Complete i18n: add history, sort, and AI chat translations for all 16 languages - Translate French AI assistant section (40+ keys) from English to French - Update README with new features and stack info Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,9 @@ interface MasonryGridProps {
|
||||
onEdit?: (note: Note, readOnly?: boolean) => void;
|
||||
onSizeChange?: (noteId: string, size: 'small' | 'medium' | 'large') => void;
|
||||
isTrashView?: boolean;
|
||||
noteHistoryEnabled?: boolean;
|
||||
noteHistoryMode?: 'manual' | 'auto';
|
||||
onOpenHistory?: (note: Note) => void;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
@@ -53,6 +56,8 @@ interface SortableNoteProps {
|
||||
isDragging?: boolean;
|
||||
isOverlay?: boolean;
|
||||
isTrashView?: boolean;
|
||||
noteHistoryEnabled?: boolean;
|
||||
onOpenHistory?: (note: Note) => void;
|
||||
}
|
||||
|
||||
const SortableNoteItem = memo(function SortableNoteItem({
|
||||
@@ -64,6 +69,8 @@ const SortableNoteItem = memo(function SortableNoteItem({
|
||||
isDragging,
|
||||
isOverlay,
|
||||
isTrashView,
|
||||
noteHistoryEnabled,
|
||||
onOpenHistory,
|
||||
}: SortableNoteProps) {
|
||||
const {
|
||||
attributes,
|
||||
@@ -98,6 +105,8 @@ const SortableNoteItem = memo(function SortableNoteItem({
|
||||
isDragging={isDragging}
|
||||
isTrashView={isTrashView}
|
||||
onSizeChange={(newSize) => onSizeChange(note.id, newSize)}
|
||||
noteHistoryEnabled={noteHistoryEnabled}
|
||||
onOpenHistory={onOpenHistory}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -114,6 +123,8 @@ interface SortableGridSectionProps {
|
||||
onDragStartNote: (noteId: string) => void;
|
||||
onDragEndNote: () => void;
|
||||
isTrashView?: boolean;
|
||||
noteHistoryEnabled?: boolean;
|
||||
onOpenHistory?: (note: Note) => void;
|
||||
}
|
||||
|
||||
const SortableGridSection = memo(function SortableGridSection({
|
||||
@@ -124,6 +135,8 @@ const SortableGridSection = memo(function SortableGridSection({
|
||||
onDragStartNote,
|
||||
onDragEndNote,
|
||||
isTrashView,
|
||||
noteHistoryEnabled,
|
||||
onOpenHistory,
|
||||
}: SortableGridSectionProps) {
|
||||
const ids = useMemo(() => notes.map(n => n.id), [notes]);
|
||||
|
||||
@@ -140,6 +153,8 @@ const SortableGridSection = memo(function SortableGridSection({
|
||||
onDragEndNote={onDragEndNote}
|
||||
isDragging={draggedNoteId === note.id}
|
||||
isTrashView={isTrashView}
|
||||
noteHistoryEnabled={noteHistoryEnabled}
|
||||
onOpenHistory={onOpenHistory}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -150,7 +165,14 @@ const SortableGridSection = memo(function SortableGridSection({
|
||||
// ─────────────────────────────────────────────
|
||||
// Main MasonryGrid component
|
||||
// ─────────────────────────────────────────────
|
||||
export function MasonryGrid({ notes, onEdit, onSizeChange, isTrashView }: MasonryGridProps) {
|
||||
export function MasonryGrid({
|
||||
notes,
|
||||
onEdit,
|
||||
onSizeChange,
|
||||
isTrashView,
|
||||
noteHistoryEnabled = false,
|
||||
onOpenHistory,
|
||||
}: MasonryGridProps) {
|
||||
const { t } = useLanguage();
|
||||
const [editingNote, setEditingNote] = useState<{ note: Note; readOnly?: boolean } | null>(null);
|
||||
const { startDrag, endDrag, draggedNoteId } = useNotebookDrag();
|
||||
@@ -261,6 +283,8 @@ export function MasonryGrid({ notes, onEdit, onSizeChange, isTrashView }: Masonr
|
||||
onDragStartNote={startDrag}
|
||||
onDragEndNote={endDrag}
|
||||
isTrashView={isTrashView}
|
||||
noteHistoryEnabled={noteHistoryEnabled}
|
||||
onOpenHistory={onOpenHistory}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -280,6 +304,8 @@ export function MasonryGrid({ notes, onEdit, onSizeChange, isTrashView }: Masonr
|
||||
onDragStartNote={startDrag}
|
||||
onDragEndNote={endDrag}
|
||||
isTrashView={isTrashView}
|
||||
noteHistoryEnabled={noteHistoryEnabled}
|
||||
onOpenHistory={onOpenHistory}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -294,6 +320,8 @@ export function MasonryGrid({ notes, onEdit, onSizeChange, isTrashView }: Masonr
|
||||
onEdit={handleEdit}
|
||||
isDragging={true}
|
||||
onSizeChange={(newSize) => handleSizeChange(activeNote.id, newSize)}
|
||||
noteHistoryEnabled={noteHistoryEnabled}
|
||||
onOpenHistory={onOpenHistory}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
Reference in New Issue
Block a user