genesis+worker: design system Genesis ทั้งชุด + patch pdf.worker แก้ fake-space ไทย + ปิด review design/responsive/quality รอบ 2026-09-24 — (1) Genesis: ฟอนต์ General Sans self-host + DM Sans + Sarabun, AppNav 56px backdrop-blur แทน SessionBar, DotGrid หน้า login, palette/รัศมี/เงา/focus ตาม docs/DESIGN.md ครบทุกหน้า (2) postinstall scripts/patch-pdf-worker.mjs ถอด if (scaledDim) รอบ prevTransform ให้อัปเดตทุก glyph — กัน addFakeSpaces แทรก space กลางคำไทยใน PDF ที่ justify ด้วย letter-spacing + test กัน regression (tests/scripts/ + fixture thai_letterspacing.pdf, invariant #6) (3) ฟอร์มอัปโหลด + ช่องกลุ่ม typeId ทางเลือก — normDocumentGroup ที่ utils/external-file.ts เป็น single source ร่วมกับ N8 (4) token fixes: focus ring ปุ่ม pin + แถว bookmark ตามหน้า, ปุ่ม action ใน popup/composer/dialog เป็น rounded-md ทั้งคู่, selection preview เป็น tint ของ primary แทน blue-500 ดิบ, default สี shape/highlight รวมที่ utils/annotation-display, loading animate-pulse + จดข้อยกเว้น (เงา pin, font weights ของ viewer) ลง DESIGN.md (5) responsive: Export PDF max-lg:order-first ให้เห็นบน iPad, แถวบน header แถวเดียวเลื่อนได้บนจอแคบ, re-fit ความกว้างตอน toggle sidebar เฉพาะเมื่อยังไม่ซูมเอง, pin popover flip ขึ้นบนเมื่อใกล้ท้ายหน้า, toast hint ตอนสลับ tool กลางเอกสาร, ป้าย "ชนิด · ผู้ทำ" ของรายการผู้อื่นสำหรับจอสัมผัส (6) คุณภาพ: @layer ครอบ @media กันกฎ touch รั่ยไป desktop (Tailwind v3 ยก @layer ออกจาก media ทิ้ง wrapper — ยืนยันด้วย build จริง + วัดบนจอ), กฎ M5 ครอบ contenteditable กัน Safari zoom ตอนแก้ไข TEXTBOX บน iPad, COMMENT ใช้ box มาตราฐานเดียวตาม pin px จริง (render/scroll target/move-clamp/bookmark), ตัดหัวการ์ดซ้ำกับ h2 หน้ารายการ — พร้อมไฟล์ untracked ที่ postinstall/โค้ดอ้างถึงครบชุด (app/fonts/, AppNav, DotGrid, tests/) กัน fresh clone fail ที่ npm install (คำขอผู้ใช้ 2026-09-24)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
e254b935ce
commit
c5c6b65bd2
42 changed files with 1429 additions and 745 deletions
BIN
tests/fixtures/thai_letterspacing.pdf
vendored
Normal file
BIN
tests/fixtures/thai_letterspacing.pdf
vendored
Normal file
Binary file not shown.
68
tests/scripts/patch-pdf-worker.test.ts
Normal file
68
tests/scripts/patch-pdf-worker.test.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
// patch fake-space ไทยของ pdf.js worker — scripts/patch-pdf-worker.mjs (bug 2026-09-24):
|
||||
// pdf.js เก็บตำแหน่งอ้างอิง glyph ก่อนหน้า (prevTransform) เฉพาะ glyph ที่กว้าง ≠ 0
|
||||
// ทำให้ charSpacing ของสระบน-ล่าง/วรรณยุกต์ (glyph กว้าง 0) สะสมเป็น gap จน
|
||||
// addFakeSpaces แทรก " " กลางคำ ("ฉะนั้ น") — patch ถอด if ครอบการอัปเดตออก
|
||||
// ให้อัปเดตทุก glyph แทน
|
||||
|
||||
const ROOT = process.cwd();
|
||||
const WORKER = join(ROOT, "public", "pdf.worker.min.mjs");
|
||||
// ไฟล์ Word→PDF ที่ justify ด้วย letter-spacing ทุก glyph (มี charSpacing ~0.05×fontSize)
|
||||
// — เงื่อนไขที่ทำให้ heuristic ของ pdf.js แทรก fake space กลางคำไทย
|
||||
// (อยู่ใน tests/fixtures/ ไม่ใช่ public/samples/ — ไม่ให้ seed-samples สร้าง
|
||||
// รายการเอกสาร "ทดสอบ" บนหน้ารายการของทุก deploy)
|
||||
const SAMPLE = join(ROOT, "tests", "fixtures", "thai_letterspacing.pdf");
|
||||
|
||||
describe("public/pdf.worker.min.mjs — ผ่าน patch fake-space ไทย", () => {
|
||||
const code = readFileSync(WORKER, "utf8");
|
||||
|
||||
it("อัปเดต prevTransform ทุก glyph (รูปแบบก่อนแพตช์ C&&(h.prevTransform=…) หายไป)", () => {
|
||||
// หลัง patch: }h.prevTransform=getCurrentTextTransform(); (เคยถูก if ครอบ
|
||||
// จนเหลือ } ปิด block เปล่านำหน้า)
|
||||
expect(code).toMatch(
|
||||
/[;{}][A-Za-z$_][\w$]*\.prevTransform=getCurrentTextTransform\(\);/,
|
||||
);
|
||||
// ก่อน patch: C&&(h.prevTransform=getCurrentTextTransform());
|
||||
expect(code).not.toMatch(
|
||||
/&&\([A-Za-z$_][\w$]*\.prevTransform=getCurrentTextTransform\(\)\);/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getTextContent ผ่าน worker ที่ patch แล้ว — ไฟล์ justify letter-spacing", () => {
|
||||
it("ไม่มี fake space กลางคำไทย (space ตามด้วยสระ/วรรณยุกต์ = ผิดเสมอ)", async () => {
|
||||
const pdfjs = await import("pdfjs-dist/legacy/build/pdf.mjs");
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = pathToFileURL(WORKER).href;
|
||||
const doc = await pdfjs.getDocument({
|
||||
data: new Uint8Array(readFileSync(SAMPLE)),
|
||||
}).promise;
|
||||
|
||||
// space หน้า combining mark ไม่มีทางถูกต้องในภาษาไทย (mark ต้องเกาะฐานหน้า)
|
||||
const badRe = / [ัิีึืุู็่้๊๋์ํ]/;
|
||||
const offenders: string[] = [];
|
||||
let targetLine = "";
|
||||
for (let p = 1; p <= doc.numPages; p++) {
|
||||
const tc = await (await doc.getPage(p)).getTextContent();
|
||||
for (const item of tc.items) {
|
||||
if (!("str" in item)) continue;
|
||||
if (!targetLine && item.str.includes("ฉะนั้น")) targetLine = item.str;
|
||||
if (badRe.test(item.str)) {
|
||||
offenders.push(`p${p}: ${JSON.stringify(item.str.slice(0, 60))}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
expect(offenders).toEqual([]);
|
||||
|
||||
// บรรทัดเป้าหมาย (เคยได้ "ฉะนั้ น ให้ ท่ าน…คำฟ้ อง") — space จริง (glyph SPACE
|
||||
// ในไฟล์) คงอยู้ครบ ส่วนช่อง letter-spacing เล็ก ๆ ที่ไม่ใช่ space จริงติดกัน
|
||||
// ("ให้การแก้" — ในไฟล์ไม่มี space glyph ตรงนั้น)
|
||||
expect(targetLine).toBe(
|
||||
"ฉะนั้น ให้ ท่านทำคำให้การแก้คำฟ้อง พร้อมด้วยพยานหลักฐาน ๑ ชุด",
|
||||
);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue