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
|
|
@ -3,6 +3,8 @@
|
|||
// ฟอร์ม login (mock e-Court) — เรียก server action login แล้ว router.replace(next ?? "/")
|
||||
// (pattern ตาม UploadFileForm: useTransition + error state + ข้อความ fallback ตอน transport fail)
|
||||
// next = path วนกลับหลัง login (N8 D5 — ผ่าน sanitizeNextPath จากหน้า login มาแล้ว)
|
||||
// Genesis (docs/DESIGN.md): การ์ด surface 12px radius ขอบ line ไม่มีเงาระดับ static /
|
||||
// input ผ่าน .genesis-input / ปุ่ม primary hover ขึ้น 1px + glow ฟ้า (shadow-btn-glow)
|
||||
import { useRef, useState, useTransition } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
|
|
@ -11,11 +13,12 @@ import Select from "@/components/Select";
|
|||
import { MOCK_USERS } from "@/utils/user";
|
||||
|
||||
// text input ของแอป — text-base (16px) เสมอ: กัน iOS auto-zoom ตอน focus บน iPad
|
||||
// (ทับ text-sm ของ .genesis-input — utility อยู่หลัง @layer components ชนะเสมอ)
|
||||
// error ตาม spec Inputs: ขอบเปลี่ยนเป็นแดง (ring ยังเป็นฟ้าตาม focus ring หลัก)
|
||||
const INPUT_CLASS =
|
||||
"mt-1 block w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-base text-slate-900 placeholder:text-slate-400 transition focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/30 disabled:cursor-not-allowed disabled:bg-slate-50 aria-invalid:border-red-600 aria-invalid:focus:ring-red-600/30";
|
||||
"genesis-input mt-1 block w-full text-base transition aria-invalid:border-error";
|
||||
// dropdown ผู้ใช้ — เหมือน INPUT_CLASS แต่ไม่มี mt-1 (Select ครอบ div.relative: มาร์จินที่ wrapper ข้างนอกแทน)
|
||||
const SELECT_CLASS =
|
||||
"block w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-base text-slate-900 transition focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/30 disabled:cursor-not-allowed disabled:bg-slate-50";
|
||||
const SELECT_CLASS = "genesis-input block w-full text-base transition";
|
||||
|
||||
export default function LoginForm({ next }: { next: string | null }) {
|
||||
const router = useRouter();
|
||||
|
|
@ -48,23 +51,29 @@ export default function LoginForm({ next }: { next: string | null }) {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-sm rounded-xl border border-slate-200 bg-white p-6 shadow-sm">
|
||||
{/* brand lockup เดียวกับ header หน้ารายการ (ลดขนาดตัวอักษรให้พอการ์ดแคบ) */}
|
||||
<div className="w-full max-w-sm rounded-xl border border-line bg-white p-8">
|
||||
{/* brand lockup เดียวกับ nav หน้ารายการ — tile JN น้ำเงินคือแบรนด์มาร์กของระบบ
|
||||
(หน้าสรุปแถบน้ำเงิน 2026-09-17 สืบต่อจาก tile นี้) ชื่อแบรนด์เป็น ink ตามกฎ
|
||||
"blue เฉพาะของ interactive" ของ Genesis */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-primary text-base font-bold text-white shadow-sm">
|
||||
<div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-lg bg-primary text-base font-bold text-white">
|
||||
JN
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-lg font-bold leading-tight text-primary">Judge's Note</p>
|
||||
<p className="text-xs text-slate-500">ระบบ PDF Annotation สำหรับ e-Court</p>
|
||||
<div className="min-w-0">
|
||||
<p className="font-display text-lg font-bold leading-tight text-ink">
|
||||
Judge's Note
|
||||
</p>
|
||||
<p className="mt-0.5 text-xs text-ink-soft">
|
||||
ระบบ PDF Annotation สำหรับ e-Court
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 className="mt-6 text-lg font-semibold text-slate-900">เข้าสู่ระบบ</h1>
|
||||
<h1 className="font-display mt-8 text-subhead text-ink">เข้าสู่ระบบ</h1>
|
||||
|
||||
<form onSubmit={onSubmit} className="mt-4">
|
||||
<form onSubmit={onSubmit} className="mt-5">
|
||||
<div>
|
||||
<label htmlFor="username" className="text-sm font-semibold text-slate-700">
|
||||
<label htmlFor="username" className="block text-sm font-medium text-ink">
|
||||
ชื่อผู้ใช้
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
|
|
@ -92,7 +101,7 @@ export default function LoginForm({ next }: { next: string | null }) {
|
|||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<label htmlFor="password" className="text-sm font-semibold text-slate-700">
|
||||
<label htmlFor="password" className="block text-sm font-medium text-ink">
|
||||
รหัสผ่าน
|
||||
</label>
|
||||
<input
|
||||
|
|
@ -111,19 +120,20 @@ export default function LoginForm({ next }: { next: string | null }) {
|
|||
<button
|
||||
type="submit"
|
||||
disabled={pending}
|
||||
className="mt-6 w-full rounded-md bg-primary px-4 py-2.5 text-sm font-medium text-white transition hover:opacity-90 disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1"
|
||||
className="focus-ring mt-6 w-full rounded-md bg-primary px-4 py-2.5 text-sm font-medium text-white transition hover:-translate-y-px hover:bg-primary-hover hover:shadow-btn-glow disabled:pointer-events-none disabled:opacity-50"
|
||||
>
|
||||
{pending ? "กำลังตรวจสอบ…" : "เข้าสู่ระบบ"}
|
||||
</button>
|
||||
|
||||
{/* รหัสผ่านทดสอบ — รายชื่อเห็นใน dropdown แล้ว เหลือบอกแค่รหัสผ่าน (mock ไม่มีระบบสมัคร) */}
|
||||
<p className="mt-5 rounded-md bg-slate-50 px-3 py-2 text-xs text-slate-500">
|
||||
{/* รหัสผ่านทดสอบ — รายชื่อเห็นใน dropdown แล้ว เหลือบอกแค่รหัสผ่าน (mock ไม่มีระบบสมัคร)
|
||||
กล่อง metadata 8px radius ตาม Genesis (พื้นเทาโปร่งจาง ไม่ใช่การเน้น) */}
|
||||
<p className="mt-5 rounded-lg bg-ink/[0.04] px-3 py-2.5 text-xs leading-relaxed text-ink-soft">
|
||||
รหัสผ่านทดสอบ:{" "}
|
||||
<span className="font-semibold text-slate-700">Demo1234</span>
|
||||
<span className="font-semibold text-ink">Demo1234</span>
|
||||
</p>
|
||||
|
||||
{error && (
|
||||
<p role="alert" className="mt-3 text-xs text-red-600">
|
||||
<p role="alert" className="mt-3 text-xs text-error-ink">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue