diff --git a/frontend/src/components/WorkbookViewer.tsx b/frontend/src/components/WorkbookViewer.tsx index 656f4f0..e55b6d0 100644 --- a/frontend/src/components/WorkbookViewer.tsx +++ b/frontend/src/components/WorkbookViewer.tsx @@ -8,7 +8,7 @@ import { api } from "@/lib/api"; // Types // ───────────────────────────────────────────────────────────────────────────── -type Tool = "select" | "pen" | "highlighter" | "text"; +type Tool = "select" | "pen" | "highlighter" | "text" | "eraser"; type ViewMode = "pan" | "draw"; type FitMode = "width" | "height"; type ScrollMode = "single" | "continuous"; @@ -565,6 +565,18 @@ export default function WorkbookViewer({ pdfId }: Props) { fc.renderAll(); }); break; + + case "eraser": + fc.isDrawingMode = false; + fc.selection = false; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + fc.on("mouse:down", (options: any) => { + if (!options.target) return; + fc.remove(options.target); + addedObjects.current = addedObjects.current.filter(o => o !== options.target); + fc.renderAll(); + }); + break; } }, [isReady, mode, tool, penColor, strokeWidth]); @@ -602,6 +614,12 @@ export default function WorkbookViewer({ pdfId }: Props) { const t = new fabric.IText("Text", { left: pointer.x, top: pointer.y, fontSize: 20, fill: penColorRef.current, fontFamily: "Arial, sans-serif", padding: 4 }); fc.add(t); fc.setActiveObject(t); t.enterEditing(); t.selectAll(); fc.renderAll(); }); break; + case "eraser": + fc.isDrawingMode = false; fc.selection = false; + fc.on("mouse:down", (options: any) => { + if (!options.target) return; + fc.remove(options.target); fc.renderAll(); + }); break; } }); }, [isReady, scrollMode, mode, tool, penColor, strokeWidth]); @@ -700,254 +718,244 @@ export default function WorkbookViewer({ pdfId }: Props) { {/* ── Sticky Toolbar ──────────────────────────────────────────────────── */}
-
+
- {/* Back button + title */} - - - {pdfTitle} - + {/* Scrollable tools strip */} +
-
- - {/* Thumbnail panel toggle */} - - -
- - {/* Fit mode buttons */} -
+ {/* Back button + title */} - -
- -
- - {/* Scroll mode toggle */} -
- - -
- -
- - {/* Page navigation */} -
- - {isReady ? ( - - { - const v = Number(e.target.value); - if (v >= 1 && v <= totalPages) goToPage(v); - }} - onFocus={(e) => e.target.select()} - className="w-10 text-center text-xs border border-gray-300 rounded px-1 py-0.5 focus:outline-none focus:border-blue-500 [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none" - /> - / {totalPages} - - ) : ( - - )} + + {pdfTitle} + + +
+ + {/* Thumbnail toggle */} -
-
+
- {/* Pan / Draw mode toggle */} -
- - -
- - {/* Drawing tools — only shown in Draw mode */} - {mode === "draw" && ( - <> -
- - {/* Tool buttons */} -
- {/* Select */} - - - - - {/* Pen */} - - - - - {/* Highlighter */} - - - - - {/* Text */} - - - -
- - {/* Color picker */} - setPenColor(e.target.value)} - title="Color" - className="w-7 h-7 rounded cursor-pointer border border-gray-300 p-0.5 bg-white" - /> - - {/* Stroke width slider */} - setStrokeWidth(Number(e.target.value))} - className="w-16 accent-blue-600" - title={`Stroke width: ${strokeWidth}`} - /> - -
- - {/* Undo */} + {/* Fit mode */} +
+ +
+ +
+ + {/* Scroll mode */} +
+ + +
+ +
+ + {/* Page navigation */} +
+ - - {/* Clear page */} + {isReady ? ( + + { + const v = Number(e.target.value); + if (v >= 1 && v <= totalPages) goToPage(v); + }} + onFocus={(e) => e.target.select()} + className="w-10 text-center text-xs border border-gray-300 rounded px-1 py-0.5 focus:outline-none focus:border-blue-500 [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none" + /> + / {totalPages} + + ) : ( + + )} - - )} +
- {/* Save button — far right */} -
+
+ + {/* Pan / Draw mode toggle */} +
+ + +
+ + {/* Drawing tools — inline, visible only in draw mode */} + {mode === "draw" && ( + <> +
+ +
+ + + + + + + + + + + + + + + +
+ + setPenColor(e.target.value)} + title="Color" + className="w-7 h-7 rounded cursor-pointer border border-gray-300 p-0.5 bg-white flex-shrink-0" + /> + + setStrokeWidth(Number(e.target.value))} + className="w-20 accent-blue-600 flex-shrink-0" + title={`Stroke width: ${strokeWidth}`} + /> + +
+ + + + + + )} +
+ + {/* Save — fixed right, never scrolls away */} +
{saveNotice && ( - - ✓ Saved - + ✓ Saved )}