ซ่อม text ไทย PDF (ActualText) + revalidatePath ทุก action + คีย์ลัด DEL + ตรายาง label บรรทัดเดียว

- โหลด PDF ผ่าน /api/pdf?fileId= ที่สร้าง ToUnicode CMap ใหม่บนสำเนาในหน่วยความจำ
  จาก ActualText ใน marked content (lib/pdf-actual-text.ts + unit tests) — แก้
  ฟอนต์ไทยที่ cmap เพี้ยน (คำสั่งศาล) ให้ textLayer select/copy/ค้นหา/ชื่อ bookmark
  ถูกต้องตั้งแต่ต้น ไฟล์ใน public/ ไม่ถูกแตะ (invariant #1) — PDF ปกติได้ bytes
  เดิม ไม่มี cost และ fail แล้ว PDFViewer fallback fetch ไฟล์ดิบเอง
- ข้อความจาก selection ห้าม selection.toString() ตรง ๆ: ใช้ selectionTextWithin
  เดินทีละอักษร เรียงตามตำแหน่งบนจอ (จัดการ Thai combining marks + ctrl ขยะ)
  ปิดท้ายด้วย sanitizePdfText ก่อนเก็บ DB/ชื่อ bookmark/คลิปบอร์ด (มี tests)
- mergeRectsByLine ใช้ median ความสูง rect คำนวณเกณฑ์บรรทัดแทนค่าคงที่
- Server Actions ทุกตัวที่เขียน DB เรียก revalidateFilePages (revalidatePath
  หน้า viewer+summary) คู่กับ publish event — แก้กด back แล้วเข้าไฟล์ใหม่ได้
  RSC payload เก่าจาก Router Cache ฝั่ง client จนต้อง hard refresh
- คีย์ลัด DEL/Backspace ลบ annotation ที่เลือกอยู่ (ของตัวเองเท่านั้น ข้ามเมื่อ
  focus อยู่ใน input/textarea/select/contenteditable)
- STAMP: ย่อฟอนต์ label ให้อยู่บรรทัดเดียวพอดีกรอบทั้งบนจอ (canvas measure) และ
  export PDF (stampFitFontSize แชร์กัน) + เพิ่ม handle ปรับขนาดตรายางในแผง
  selection (uniform scale + clamp รายแกน)
- sync invariant/กติกา: CLAUDE.md #4, rules/*.md, PLAN-FEAT.md (F3)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 2026-09-11 13:28:35 +07:00
parent 289d735bf3
commit 6fd3a1515f
19 changed files with 890 additions and 53 deletions

View file

@ -186,7 +186,7 @@ Index: `(file_id)`
### ฟีเจอร์เล็กที่เหลือ (สเปกย่อ — รายละเอียดการทำงานเต็มอยู่ในตาราง §4)
- **F3 E2 คีย์ลัด:** keydown listener ที่ `window` ใน PDFViewer — `H/D/C` สลับ tool, `B` bookmark, `Ctrl+Z`/`Ctrl+Shift+Z` undo/redo, `Esc` ปิด popup/deselect; **ข้ามเมื่อ `e.target` เป็น input/textarea/contenteditable**
- **F3 E2 คีย์ลัด:** keydown listener ที่ `window` ใน PDFViewer — `H/D/C` สลับ tool, `B` bookmark, `Ctrl+Z`/`Ctrl+Shift+Z` undo/redo, `Esc` ปิด popup/deselect, `DEL`/`Backspace` ลบรายการที่เลือก (ของตัวเองเท่านั้น); **ข้ามเมื่อ `e.target` เป็น input/textarea/contenteditable**
- **F4 A3 ซ่อน–แสดงรายคน:** state `userFilter: "all" | "mine" | <userId>` + dropdown รายชื่อ (จาก unique userId ใน annotations) — กรองทั้ง viewer และ sidebar ฝั่ง client ล้วน
- **F7 E1 สไตลัส/สัมผัส:** InkLayer ใช้ Pointer Events + `touch-none` อยู่แล้ว — เพิ่ม: pressure (`e.pressure` → `widths` per-point, render เป็น segment เมื่อมี widths), palm rejection (เมื่อเคยเห็น `pointerType === "pen"` → ละเว้น `touch` ในหน้านั้น)
- **F13 A6 แก้ไขข้อความ comment:** ปุ่ม "แก้ไข" ใน popover (เจ้าของเท่านั้น) → textarea → `updateAnnotation` (reuse F1)