Stage seven, and the last of the PDF work. A PDF note now offers the document with your marks stamped in, the untouched original, or just the notes written beside it. pdf.js only reads, so writing needs pdf-lib — behind a dynamic import like pdf.js, so the bundle everyone downloads carries no PDF writer for the sake of people who never export one. Main bundle grew 6 kB; the 180 kB writer arrives only when used. The coordinate decision from stage four is what makes this a translation rather than a reconstruction: strokes were stored in page points from the start, the only space a PDF understands, so nothing has to be guessed back from screen pixels. Only the origin moves, PDF putting it at the bottom-left. The stored file is never modified — pdf-lib builds a new document — so a clean copy stays available however often it has been drawn on. The suite re-fetches the stored bytes after exporting and compares them, and checks the plain export is byte-identical to what was imported. Eraser strokes are dropped. On screen they remove ink by drawing in destination-out; a PDF content stream has no equivalent, and stamping them would put grey scribbles exactly where something had been rubbed out. The suite renders both files with pdf.js and counts dark pixels, 1633 against 2557. A larger file only proves bytes were added; this proves ink can be seen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
48 lines
1.3 KiB
JSON
48 lines
1.3 KiB
JSON
{
|
|
"name": "inknote-frontend",
|
|
"version": "1.0.0",
|
|
"private": true,
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "vite",
|
|
"build": "vite build",
|
|
"preview": "vite preview",
|
|
"test": "vitest run",
|
|
"test:watch": "vitest",
|
|
"typecheck": "tsc --noEmit",
|
|
"format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,css}'"
|
|
},
|
|
"dependencies": {
|
|
"@tiptap/extension-image": "^2.27.2",
|
|
"@tiptap/extension-link": "^2.27.2",
|
|
"@tiptap/extension-placeholder": "^2.27.2",
|
|
"@tiptap/extension-table": "^2.27.2",
|
|
"@tiptap/extension-table-cell": "^2.27.2",
|
|
"@tiptap/extension-table-header": "^2.27.2",
|
|
"@tiptap/extension-table-row": "^2.27.2",
|
|
"@tiptap/extension-task-item": "^2.27.2",
|
|
"@tiptap/extension-task-list": "^2.27.2",
|
|
"@tiptap/extension-underline": "^2.27.2",
|
|
"@tiptap/html": "^2.27.2",
|
|
"@tiptap/pm": "^2.27.2",
|
|
"@tiptap/react": "^2.27.2",
|
|
"@tiptap/starter-kit": "^2.27.2",
|
|
"@tiptap/suggestion": "^2.27.2",
|
|
"pdf-lib": "^1.17.1",
|
|
"pdfjs-dist": "^6.2.108",
|
|
"react": "^18.3.1",
|
|
"react-dom": "^18.3.1"
|
|
},
|
|
"devDependencies": {
|
|
"@types/react": "^18.3.31",
|
|
"@types/react-dom": "^18.3.7",
|
|
"@vitejs/plugin-react": "^4.3.1",
|
|
"fake-indexeddb": "^6.2.5",
|
|
"jsdom": "^25.0.1",
|
|
"prettier": "^3.9.6",
|
|
"typescript": "^5.9.3",
|
|
"vite": "^5.4.0",
|
|
"vitest": "^2.1.9"
|
|
}
|
|
}
|