Sort a notebook, import Markdown back, and stop the page shrinking in Draw
The paper measurably shrank on switching to Draw — 733px to 460px on the same screen. The editor was a flex item at its default `flex: 0 1 auto`, so its width was its widest row's: the toolbar. Swapping a dozen formatting buttons for six drawing ones collapsed it. It now fills the pane, so the width is a property of the window. Each notebook remembers how its notes are ordered, on the server rather than per device. The manual order has to survive being looked away from, so `reindex` renumbers every note in the notebook rather than the filtered view, and dragging is switched off while a search narrows the list. Reordering has its own route: `PUT /notes/:id` would bump `updated_at` and snapshot a version, so a drag would move a note to the top of "last changed" and spend a slot of its history. Markdown and our own ZIP archives come back as notes, with their images re-uploaded as attachments. A drawing returns as the PNG it was exported as — vectors are not recoverable from pixels — and the import says so rather than leaving it to be discovered. Writing the parser turned up a real bug in the exporter: blocks were emitted with no blank line between them, so a list after a list became one list and a quote after an item was read as part of it. Creating or importing from "All Notes" now asks which notebook instead of silently taking the first one. The web-link prompt is a real dialog: a bare domain becomes https, javascript: is refused with a reason. The PDF viewer's hide-drawing control is a labelled button rather than a filled-or-hollow dot, and the export icon points down into a tray like every other download. 186 unit tests, 179 browser checks across eleven suites, including a new `offline` suite that loads the app cold with the network off. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3acb8b66a4
commit
0a0864c58b
27 files changed
+2962
-86
No files matched your search
@@ -3,6 +3,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import * as sync from "../syncEngine";
|
||||
import * as searchIndex from "../search";
|
||||
import { sameStrokeDoc } from "../features/drawing/strokes.js";
|
||||
import { reindex } from "../features/notes/noteSort";
|
||||
import type { Backlink, NoteContent, NoteMeta, Notebook, StrokeDoc, User } from "../types";
|
||||
|
||||
/** How often the whole account is reconciled with the server. */
|
||||
@@ -44,6 +45,8 @@ export interface NoteData {
|
||||
permanentDeleteNote: (id: string) => Promise<void>;
|
||||
emptyTrash: () => Promise<void>;
|
||||
moveNote: (id: string, folderId: string) => Promise<void>;
|
||||
/** Drag-to-reorder within a notebook; only meaningful in manual sort. */
|
||||
reorderNotes: (dragId: string, targetId: string) => void;
|
||||
|
||||
createNotebook: (fields: { name: string; cover: number }) => Promise<Notebook>;
|
||||
updateNotebook: (id: string, updates: Partial<Notebook>) => Promise<void>;
|
||||
@@ -261,6 +264,25 @@ export function useNoteData(user: User | null, activeNote: string | null): NoteD
|
||||
setNotes((p) => p.map((n) => (n.id === id ? { ...n, folderId } : n)));
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Puts one note where another was, in the user's own order.
|
||||
*
|
||||
* The new positions are computed over *every* note in that notebook, taken
|
||||
* from the store rather than from whatever the list is currently showing. A
|
||||
* search or a filter must never be able to renumber the notes it is hiding.
|
||||
*/
|
||||
const reorderNotes = useCallback((dragId: string, targetId: string) => {
|
||||
const dragged = notesRef.current.find((n) => n.id === dragId);
|
||||
if (!dragged) return;
|
||||
const inNotebook = notesRef.current.filter((n) => !n.trashed && n.folderId === dragged.folderId);
|
||||
const order = reindex(inNotebook, dragId, targetId);
|
||||
if (!order) return;
|
||||
|
||||
const position = new Map(order.map((id, i) => [id, i]));
|
||||
setNotes((p) => p.map((n) => (position.has(n.id) ? { ...n, sortOrder: position.get(n.id)! } : n)));
|
||||
void sync.reorderNotes(order);
|
||||
}, []);
|
||||
|
||||
/* ── Notebooks ── */
|
||||
|
||||
const createNotebook = useCallback(async (fields: { name: string; cover: number }) => {
|
||||
@@ -311,6 +333,7 @@ export function useNoteData(user: User | null, activeNote: string | null): NoteD
|
||||
permanentDeleteNote,
|
||||
emptyTrash,
|
||||
moveNote,
|
||||
reorderNotes,
|
||||
createNotebook,
|
||||
updateNotebook,
|
||||
deleteNotebook,
|
||||
|
||||
Reference in new issue
Block a user