viewer: ซ่อน tool มาร์กข้อความเมื่อไฟล์ไม่มีข้อความให้คลุม — ทั้งไฟล์รูปภาพ (N3) และ PDF สแกนล้วน (คำขอผู้ใช้ 2026-09-22)
- hideHighlightTool = ไฟล์ภาพ หรือ scannedOnly (ทุกหน้าที่ render แล้วไม่มี span เลย) ซ่อนทั้งปุ่ม HIGHLIGHT และเมนูรูปแบบมาร์ก ผ่าน visibleTools ที่กรอง TOOLS - scannedOnly เป็น latch: entry ของ pageSpanCount สะสมต่อหน้า ไม่ลบตอน virtualization unmount (รีเซ็ตเฉพาะตอนสลับไฟล์) — เคยเจอหน้ามีข้อความแม้หน้าเดียว ปุ่มกลับมาค้าง (ไฟล์ผสมสแกนนำหน้าโผล่ครั้งเดียวพอ ไม่โผล่-หายตามหน้าที่เปิดดู) - กันทางเข้าที่เหลือของ tool นี้: คีย์ลัด H โดน guard ที่ switchTool และ tool ที่ค้าง active ถูก reset กลับ select 2 จุด (effect ตอน scannedOnly กลายเป็น true ระหว่าง ใช้งาน + ตอนสลับมาเป็นไฟล์ภาพขณะ tool active — dynamic param เปลี่ยน Next reuse component ไม่ reset state) - แถบ hint M6 ภาพสแกน เหลือเป็น defensive ช่วง transition เท่านั้น - sync .claude/rules/pdf-viewer.md (กติกา N3 แถว toolbar) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
3a06557bd4
commit
9ba8f0a8ec
2 changed files with 35 additions and 9 deletions
|
|
@ -1468,6 +1468,20 @@ export default function PDFViewer({
|
|||
);
|
||||
}, []);
|
||||
|
||||
// PDF สแกนล้วน — ซ่อน tool มาร์กข้อความเหมือนไฟล์ภาพ (คำขอผู้ใช้ 2026-09-22):
|
||||
// "ทุกหน้าที่ render แล้วไม่มี span เลย" โดย entry ของ pageSpanCount สะสมต่อหน้า
|
||||
// และไม่ถูกลบตอน virtualization unmount (รีเซ็ตเฉพาะตอนสลับไฟล์) จึงเป็น latch
|
||||
// ธรรมชาติ — เคยเจอหน้าที่มีข้อความแม้หน้าเดียว ไฟล์นี้ถือว่ามีข้อความ ปุ่มกลับ
|
||||
// มาและไม่หายอีก (ไฟล์ผสมที่สแกนนำหน้า: ซ่อนช่วงแรก โผล่ครั้งเดียวเมื่อถึงหน้า
|
||||
// ข้อความ — ดีกว่าปุ่มโผล่-หายตามหน้าที่กำลังเปิดดู)
|
||||
const scannedOnly =
|
||||
Object.keys(pageSpanCount).length > 0 && Object.values(pageSpanCount).every((n) => n === 0);
|
||||
// ระหว่างอยู่ tool มาร์กข้อความแล้วผลว่าเป็นไฟล์สแกน (เช่น กด H ตอนหน้าแรกยัง
|
||||
// ไม่ render) — กลับเครื่องมือเลือกให้ ไม่ค้างเป็น tool ที่ปุ่มหายไปแล้ว
|
||||
useEffect(() => {
|
||||
if (scannedOnly) setTool((prev) => (prev === "highlight" ? "select" : prev));
|
||||
}, [scannedOnly]);
|
||||
|
||||
// F8: Export PDF — ดาวน์โหลดเงียบ ๆ ในแท็บเดิม (เดิม window.open _blank จะแวบแท็บใหม่
|
||||
// และ error พา viewer ไปโผล่แท็บนั้น): fetch เป็น blob แล้วกด <a download> โดยรับชื่อ
|
||||
// ไฟล์จาก Content-Disposition ของ route (รองรับภาษาไทยผ่าน filename*) — พัง = toast ในหน้า
|
||||
|
|
@ -1523,6 +1537,10 @@ export default function PDFViewer({
|
|||
if (fileKindFromUrl(file.pdfUrl) === "image") {
|
||||
setDoc(null);
|
||||
setPdfjs(null);
|
||||
// สลับจากไฟล์ PDF ที่ tool มาร์กข้อความ active อยู่มาเป็นไฟล์ภาพ (dynamic param
|
||||
// เปลี่ยน = Next reuse component เดิม ไม่ reset state): tool นี้ถูกซ่อนบนไฟล์
|
||||
// ภาพ ต้องกลับไปเครื่องมือเลือก ไม่งั้นค้างเป็น tool ที่กดไม่ได้
|
||||
setTool((prev) => (prev === "highlight" ? "select" : prev));
|
||||
const objectUrls: string[] = [];
|
||||
// URL จริงที่ browser ใช้โหลดไฟล์ (fetch/img.src ตรง — ต้องเติม basePath เอง)
|
||||
const fileUrl = withBasePath(file.pdfUrl);
|
||||
|
|
@ -2828,6 +2846,9 @@ export default function PDFViewer({
|
|||
}
|
||||
|
||||
function switchTool(t: Tool) {
|
||||
// ไฟล์ภาพ/ไฟล์สแกนล้วน: มาร์กข้อความใช้ไม่ได้ (ไม่มีข้อความให้คลุม) — ปุ่มถูกซ่อน
|
||||
// ไปแล้ว เหลือทางเข้า tool นี้คือคีย์ลัด H จึงกันตรงนี้ให้จบ (สลับ tool อื่นไม่กระทบ)
|
||||
if (t === "highlight" && hideHighlightTool) return;
|
||||
setTool(t);
|
||||
// M4: ปิดเมนูเพราะเปลี่ยน tool — คลิกที่ตามมาต้องไม่กลายเป็นการวางรายการ (เฉพาะเมื่อ
|
||||
// มีเมนูเปิดจริง: คลิกปุ่ม tool เดี่ยวไม่มีเมนูให้ปิด ไม่ต้อง mark กันกลืนคลิกแรก)
|
||||
|
|
@ -2869,6 +2890,13 @@ export default function PDFViewer({
|
|||
|
||||
// ─── Render ────────────────────────────────────────────────────────────────
|
||||
|
||||
// N3 ไฟล์ภาพ + PDF สแกนล้วน (คำขอผู้ใช้ 2026-09-22): ไม่มีข้อความให้คลุม — ซ่อน tool
|
||||
// มาร์กข้อความ (ไฮไลต์/เส้นใต้/ขีดฆ่า/ขยุกขยิก) ทั้งปุ่มและเมนูรูปแบบ — กันเข้าทาง
|
||||
// คีย์ลัด H ที่ switchTool และ reset tool ที่ค้างอยู่ (effect ของแต่ละกรณี)
|
||||
const isImageFile = fileKindFromUrl(file.pdfUrl) === "image";
|
||||
const hideHighlightTool = isImageFile || scannedOnly;
|
||||
const visibleTools = hideHighlightTool ? TOOLS.filter((t) => t.key !== "highlight") : TOOLS;
|
||||
|
||||
// ค่าปากกาปัจจุบันรวมเป็นก้อนเดียว — ใช้ทั้ง live preview และตอนบันทึกเส้นใหม่
|
||||
const drawStyle = {
|
||||
color: drawColor,
|
||||
|
|
@ -3073,8 +3101,8 @@ export default function PDFViewer({
|
|||
UX review 2026-09-09: บน desktop ปุ่ม wrap ภายในกรอบได้ / M5 2026-09-14:
|
||||
จอแคบเป็นแถวเดียว ไหลตามแถบทั้งแถวที่เลื่อนแนวนอน */}
|
||||
<div className="flex max-lg:shrink-0 flex-wrap gap-0.5 rounded-lg border border-slate-300 max-lg:flex-nowrap">
|
||||
{TOOLS.map(({ key, label, text, Icon }, i) => {
|
||||
const corner = i === 0 ? "rounded-l-lg" : i === TOOLS.length - 1 ? "rounded-r-lg" : "";
|
||||
{visibleTools.map(({ key, label, text, Icon }, i) => {
|
||||
const corner = i === 0 ? "rounded-l-lg" : i === visibleTools.length - 1 ? "rounded-r-lg" : "";
|
||||
const activeCls = `${
|
||||
tool === key ? "bg-primary text-white" : "text-slate-500 hover:bg-slate-100"
|
||||
} ${FOCUS_RING_CLS}`;
|
||||
|
|
@ -3806,12 +3834,10 @@ export default function PDFViewer({
|
|||
setGrabbing(false);
|
||||
}}
|
||||
>
|
||||
{/* M6: hint ไฟล์สแกน — ทุกหน้าที่ render แล้วไม่มี span เลย (virtualization เห็นเฉพาะ
|
||||
หน้าใกล้ viewport — ไฟล์ผสมหน้าสแกน/หน้า text จึงพูดแบบระดับ "หน้าที่เปิดดู" เท่านั้น)
|
||||
โชว์เฉพาะตอน tool highlight เพื่อไม่รบกวน tool อื่น — คดีศาลมี PDF สแกนเยอะ */}
|
||||
{tool === "highlight" &&
|
||||
Object.keys(pageSpanCount).length > 0 &&
|
||||
Object.values(pageSpanCount).every((n) => n === 0) && (
|
||||
{/* M6: hint ไฟล์สแกน — เดิมโชว์ตอน tool highlight บนหน้าที่ไม่มีข้อความ ตอนนี้
|
||||
ไฟล์สแกนล้วน (scannedOnly) ซ่อนปุ่ม+reset tool ไปแล้ว แถบจึงเหลือเป็น
|
||||
defensive ช่วง transition สั้น ๆ เท่านั้น (คดีศาลมี PDF สแกนเยอะ) */}
|
||||
{tool === "highlight" && scannedOnly && (
|
||||
<p className="mb-3 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-700">
|
||||
หน้าที่เปิดดูเป็นภาพสแกน ไม่มีข้อความให้คลุมไฮไลต์ — ใช้การวาดเส้นหรือกล่องข้อความแทนได้
|
||||
</p>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue