UX audit ทั้งแอป + typography audit 2026-09-16: toast แจ้ง error การบันทึก (H1 — เดิมรายการหายเงียบ + ReplyBox เก็บ draft ตอน fail), คำเตือน redaction แสดงทุกขนาดจอ (H2), toolbar แสดงชื่อ tool active + aria-pressed บนจอสัมผัส (H3/M9), ปุ่ม popover จิ้มง่าย 36px + focus ring เติมครบ (H4) + M1-M9 (ปิด sidebar ตอน navigate, bookmark หัวแถวจอเล็ก, hint โหมดมาร์กบนจอสัมผัส, การ์ดหน้ารายการคลิกได้ทั้งใบ, เช็ค 100MB ฝั่ง client, feedback ✓/pending ตอนบันทึก bookmark, dropdown วางที่ sort ตามหน้า+เลขหน้า, slate-500 แทน slate-400) + webfont Sarabun ผ่าน next/font self-host 400/600 (Option B — แสดงผลตรงกันทุกอุปกรณ์ รวม TEXTBOX ที่ผูก stack นี้) + NumberCombo preset เป็น chips แทน dropdown ล้นเมนู (L2) + leading-relaxed/13px ข้อความไทยที่ wrap + tabular-nums + prefers-reduced-motion (L7) + L1/L4/L5 + แถว bookmark แสดงชื่อผู้บันทึกเหมือนผลการค้นหา

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-09-16 14:28:53 +07:00
parent a020e96bda
commit 21b9958600
10 changed files with 351 additions and 158 deletions

View file

@ -1,6 +1,6 @@
import Link from "next/link";
import { asc } from "drizzle-orm";
import { FileImage, FileText } from "lucide-react";
import { ChevronRight, FileImage, FileText } from "lucide-react";
import { db } from "@/db";
import { files } from "@/db/schema";
@ -48,7 +48,7 @@ export default async function HomePage() {
<div className="mt-8 flex items-baseline justify-between">
<h2 className="text-sm font-semibold text-slate-700">เอกสาร</h2>
{rows.length > 0 && (
<span className="text-xs text-slate-400">{rows.length} ไฟล์</span>
<span className="text-xs tabular-nums text-slate-500">{rows.length} ไฟล์</span>
)}
</div>
<UploadFileForm />
@ -59,7 +59,7 @@ export default async function HomePage() {
<p className="mt-3 text-sm font-medium text-slate-500">
ยังไม่มีไฟล์ในระบบ
</p>
<p className="mt-1 text-xs text-slate-400">
<p className="mt-1 text-xs text-slate-500">
รัน /sync-db เพื่อ seed ไฟล์ตัวอย่าง
</p>
</div>
@ -68,7 +68,7 @@ export default async function HomePage() {
{rows.map((f) => (
<li
key={f.id}
className="group flex items-center gap-3 rounded-xl border border-slate-200 bg-white p-4 shadow-sm transition hover:border-primary/30 hover:shadow-md"
className="group relative flex items-center gap-3 rounded-xl border border-slate-200 bg-white p-4 shadow-sm transition hover:border-primary/30 hover:shadow-md"
>
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10">
{imageFormatFromUrl(f.pdfUrl) ? (
@ -81,19 +81,21 @@ export default async function HomePage() {
<span className="block break-all line-clamp-2 text-sm font-medium text-slate-900">
{f.title}
</span>
<span className="mt-0.5 block text-xs text-slate-400">
<span className="mt-0.5 block text-xs text-slate-500">
<span className="mr-1.5 rounded bg-slate-100 px-1 py-0.5 font-medium text-slate-500">
{kindBadge(f.pdfUrl)}
</span>
{new Date(f.createdAt).toLocaleString("th-TH")}
</span>
</span>
<ChevronRight aria-hidden className="h-4 w-4 shrink-0 text-slate-400" />
{/* M4 (UX audit 2026-09-16): ลิงก์กางเต็มการ์ด — จอสัมผัสจิ้มตรงไหนก็เข้าได้
(เดิมปุ่ม "Annotate" ~30px อย่างเดียว และเป็นภาษาอังกฤษใน UI ไทย) */}
<Link
href={`/annotate/${f.id}`}
className="shrink-0 rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-white transition hover:opacity-90"
>
Annotate
</Link>
className="absolute inset-0 rounded-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1"
aria-label={`เปิด ${f.title}`}
/>
</li>
))}
</ul>