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
|
|
@ -84,11 +84,10 @@ function pageSummaryLine(b: PageBucket): string {
|
|||
return parts.length > 0 ? `${parts.join(" · ")} · โดย ${whoLabel}` : `โดย ${whoLabel}`;
|
||||
}
|
||||
|
||||
/** focus ring ร่วมของทุกลิงก์ในหน้า — จอสัมผัสได้ 44px อัตโนมัติจากกฎ
|
||||
* `main.summary-page a`/`button` ใน globals.css (ห้ามถอด class summary-page
|
||||
* ของ <main>) */
|
||||
const RING_CLS =
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1";
|
||||
/** focus ring ร่วมของทุกลิงก์ในหน้า — Genesis .focus-ring (outline น้ำเงินทึบ 2px
|
||||
* + offset ตาม spec Elevation); จอสัมผัสได้ 44px อัตโนมัติจากกฎ
|
||||
* `main.summary-page a`/`button` ใน globals.css (ห้ามถอด class summary-page ของ <main>) */
|
||||
const RING_CLS = "focus-ring";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
|
|
@ -177,7 +176,7 @@ export default async function SummaryPage({
|
|||
<main className="summary-page mx-auto max-w-3xl px-4 py-6 lg:max-w-6xl lg:px-8">
|
||||
{/* หัวกระดาษสำนวน — แถบน้ำเงินสืบต่อจาก tile JN ของแบรนด์ (หน้ารายการ/login):
|
||||
ชื่อรายงาน + ชื่อแฟ้ม + สถิติในที่เดียว แล้วปิดท้ายด้วยเส้นคั่นบาง */}
|
||||
<header className="rounded-xl bg-primary px-5 py-4 text-white shadow-sm sm:px-6">
|
||||
<header className="rounded-xl bg-primary px-5 py-4 text-white sm:px-6">
|
||||
<h1 className="text-lg font-semibold leading-snug">สรุปหมายเหตุ</h1>
|
||||
<p className="mt-0.5 break-words text-sm text-white/85">{file.title}</p>
|
||||
{pages.length > 0 && (
|
||||
|
|
@ -194,7 +193,7 @@ export default async function SummaryPage({
|
|||
<div className="mt-3 flex flex-wrap items-center justify-between gap-x-2 gap-y-1 print:hidden">
|
||||
<Link
|
||||
href={`/annotate/${id}`}
|
||||
className={`inline-flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-sm text-slate-700 shadow-sm hover:border-slate-300 hover:bg-slate-50 ${RING_CLS}`}
|
||||
className={`inline-flex items-center gap-1.5 rounded-md border border-line bg-white px-3 py-1.5 text-sm text-ink hover:border-ink-faint hover:bg-ink/[0.03] ${RING_CLS}`}
|
||||
>
|
||||
<ArrowLeft aria-hidden className="h-3.5 w-3.5" />
|
||||
กลับหน้าอ่าน
|
||||
|
|
@ -203,7 +202,7 @@ export default async function SummaryPage({
|
|||
{/* F16/D3: export สรุปเป็น CSV (UTF-8 BOM) */}
|
||||
<a
|
||||
href={withBasePath(`/api/annotations/export-csv?fileId=${id}`)}
|
||||
className={`flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-sm text-slate-700 shadow-sm hover:border-slate-300 hover:bg-slate-50 ${RING_CLS}`}
|
||||
className={`flex items-center gap-1.5 rounded-md border border-line bg-white px-3 py-1.5 text-sm text-ink hover:border-ink-faint hover:bg-ink/[0.03] ${RING_CLS}`}
|
||||
>
|
||||
<FileDown aria-hidden className="h-3.5 w-3.5" />
|
||||
ส่งออกสรุป (CSV)
|
||||
|
|
@ -212,7 +211,7 @@ export default async function SummaryPage({
|
|||
"ส่งออกสรุป (CSV)" ข้างบน ไม่ต้องพึ่ง title tooltip ที่จอสัมผัสใช้ไม่ได้) */}
|
||||
<a
|
||||
href={withBasePath(`/api/bookmarks/export?fileId=${id}`)}
|
||||
className={`flex items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-sm text-slate-700 shadow-sm hover:border-slate-300 hover:bg-slate-50 ${RING_CLS}`}
|
||||
className={`flex items-center gap-1.5 rounded-md border border-line bg-white px-3 py-1.5 text-sm text-ink hover:border-ink-faint hover:bg-ink/[0.03] ${RING_CLS}`}
|
||||
>
|
||||
<Braces aria-hidden className="h-3.5 w-3.5" />
|
||||
ส่งออก Bookmark (JSON)
|
||||
|
|
@ -221,17 +220,17 @@ export default async function SummaryPage({
|
|||
</div>
|
||||
|
||||
{pages.length === 0 ? (
|
||||
<div className="mt-5 rounded-xl border border-dashed border-slate-300 bg-white/70 p-10 text-center">
|
||||
<ClipboardList aria-hidden className="mx-auto h-8 w-8 text-slate-300" />
|
||||
<p className="mt-3 text-sm font-medium text-slate-600">
|
||||
<div className="mt-5 rounded-xl border border-dashed border-line bg-white/70 p-10 text-center">
|
||||
<ClipboardList aria-hidden className="mx-auto h-8 w-8 text-ink-faint" />
|
||||
<p className="mt-3 text-sm font-medium text-ink-soft">
|
||||
ยังไม่มี Annotation หรือ Bookmark ในไฟล์นี้
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-slate-500">
|
||||
<p className="mt-1 text-xs text-ink-soft">
|
||||
เปิดหน้าอ่านเพื่อมาร์กข้อความ วาดเส้น ใส่คอมเมนต์ หรือคั่นหน้า
|
||||
</p>
|
||||
<Link
|
||||
href={`/annotate/${id}`}
|
||||
className={`mt-4 inline-flex rounded-md bg-primary px-4 py-2 text-sm font-medium text-white hover:opacity-90 ${RING_CLS}`}
|
||||
className={`mt-4 inline-flex rounded-md bg-primary px-4 py-2 text-sm font-medium text-white transition hover:-translate-y-px hover:bg-primary-hover hover:shadow-btn-glow ${RING_CLS}`}
|
||||
>
|
||||
เปิดหน้าอ่าน
|
||||
</Link>
|
||||
|
|
@ -242,37 +241,37 @@ export default async function SummaryPage({
|
|||
ไปบนมือถือ (aside ด้านล่างแสดงเฉพาะ lg) ใช้ <details> ได้หุบ/กาง + keyboard
|
||||
โดยไม่มี JS เพิ่ม — จุดไข่ปลา + ผู้ร่วมทำ ภาษาเดียวกับ desktop (จอ lg กับ
|
||||
ตอนพิมพ์ซ่อน — display:none ไม่กินช่องของกริด) */}
|
||||
<details className="group rounded-xl border border-slate-200 bg-white shadow-sm lg:hidden print:hidden">
|
||||
<summary className="flex cursor-pointer list-none items-center justify-between rounded-md px-4 py-3 text-sm font-semibold text-slate-800 hover:text-primary [&::-webkit-details-marker]:hidden">
|
||||
<details className="group rounded-xl border border-line bg-white lg:hidden print:hidden">
|
||||
<summary className="flex cursor-pointer list-none items-center justify-between rounded-md px-4 py-3 text-sm font-semibold text-ink hover:text-primary [&::-webkit-details-marker]:hidden">
|
||||
รายการตามหน้าและผู้ร่วมทำ
|
||||
<ChevronDown
|
||||
aria-hidden
|
||||
className="h-4 w-4 shrink-0 text-slate-400 transition-transform group-open:rotate-180 motion-reduce:transition-none"
|
||||
className="h-4 w-4 shrink-0 text-ink-faint transition-transform group-open:rotate-180 motion-reduce:transition-none"
|
||||
/>
|
||||
</summary>
|
||||
<nav
|
||||
aria-label="รายการตามหน้า"
|
||||
className="flex flex-col gap-0.5 border-t border-slate-100 px-2 pb-2 pt-2"
|
||||
className="flex flex-col gap-0.5 border-t border-line/70 px-2 pb-2 pt-2"
|
||||
>
|
||||
{pages.map(([pi, b]) => (
|
||||
<a
|
||||
key={pi}
|
||||
href={`#page-${pi + 1}`}
|
||||
aria-label={`หน้า ${pi + 1}, ${b.anns.length + b.bms.length} รายการ`}
|
||||
className={`flex items-end gap-1.5 rounded-md px-2 py-2 text-sm text-slate-600 hover:text-primary ${RING_CLS}`}
|
||||
className={`flex items-end gap-1.5 rounded-md px-2 py-2 text-sm text-ink-soft hover:text-primary ${RING_CLS}`}
|
||||
>
|
||||
<span className="leading-5">หน้า {pi + 1}</span>
|
||||
<span
|
||||
aria-hidden
|
||||
className="mb-1.5 min-w-4 flex-1 border-b border-dotted border-slate-400"
|
||||
className="mb-1.5 min-w-4 flex-1 border-b border-dotted border-ink-faint"
|
||||
/>
|
||||
<span className="leading-5 tabular-nums text-slate-500">
|
||||
<span className="leading-5 tabular-nums text-ink-soft">
|
||||
{b.anns.length + b.bms.length}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
<p className="border-t border-slate-100 px-4 py-3 text-xs leading-relaxed text-slate-600">
|
||||
<p className="border-t border-line/70 px-4 py-3 text-xs leading-relaxed text-ink-soft">
|
||||
ผู้ร่วมทำ: {allParticipants.join(" · ")}
|
||||
</p>
|
||||
</details>
|
||||
|
|
@ -281,32 +280,32 @@ export default async function SummaryPage({
|
|||
เป็นการ์ดชุดเดียวกับ <details> มือถือและการ์ดรายหน้า (แสดงเฉพาะหน้าที่มี
|
||||
รายการ ≥ 1 ตามหลัก minimize choices; max-h กันเอกสารหลายสิบหน้าสูงเกินจอ
|
||||
— ครึ่งล่างของ sticky กดไม่ได้ตลอดกาล) */}
|
||||
<aside className="hidden rounded-xl border border-slate-200 bg-white p-4 shadow-sm lg:sticky lg:top-6 lg:block lg:max-h-[calc(100vh-3rem)] lg:overflow-y-auto">
|
||||
<h2 className="text-sm font-semibold text-slate-800">รายการตามหน้า</h2>
|
||||
<aside className="hidden rounded-xl border border-line bg-white p-4 lg:sticky lg:top-6 lg:block lg:max-h-[calc(100vh-3rem)] lg:overflow-y-auto">
|
||||
<h2 className="text-sm font-semibold text-ink">รายการตามหน้า</h2>
|
||||
<nav aria-label="รายการตามหน้า" className="mt-2 flex flex-col gap-1">
|
||||
{pages.map(([pi, b]) => (
|
||||
<a
|
||||
key={pi}
|
||||
href={`#page-${pi + 1}`}
|
||||
aria-label={`หน้า ${pi + 1}, ${b.anns.length + b.bms.length} รายการ`}
|
||||
className={`flex items-end gap-1.5 rounded-md px-1 text-sm text-slate-600 hover:text-primary ${RING_CLS}`}
|
||||
className={`flex items-end gap-1.5 rounded-md px-1 text-sm text-ink-soft hover:text-primary ${RING_CLS}`}
|
||||
>
|
||||
<span className="leading-5">หน้า {pi + 1}</span>
|
||||
<span
|
||||
aria-hidden
|
||||
className="mb-1.5 min-w-4 flex-1 border-b border-dotted border-slate-400"
|
||||
className="mb-1.5 min-w-4 flex-1 border-b border-dotted border-ink-faint"
|
||||
/>
|
||||
<span className="leading-5 tabular-nums text-slate-500">
|
||||
<span className="leading-5 tabular-nums text-ink-soft">
|
||||
{b.anns.length + b.bms.length}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
<h2 className="mt-6 border-t border-slate-300/60 pt-4 text-sm font-semibold text-slate-800">
|
||||
<h2 className="mt-6 border-t border-line pt-4 text-sm font-semibold text-ink">
|
||||
ผู้ร่วมทำ
|
||||
</h2>
|
||||
<p className="mt-1.5 px-1 text-xs leading-relaxed text-slate-600">
|
||||
<p className="mt-1.5 px-1 text-xs leading-relaxed text-ink-soft">
|
||||
{allParticipants.join(" · ")}
|
||||
</p>
|
||||
</aside>
|
||||
|
|
@ -322,15 +321,18 @@ export default async function SummaryPage({
|
|||
key={pi}
|
||||
id={`page-${pi + 1}`}
|
||||
aria-labelledby={`page-${pi + 1}-title`}
|
||||
className="scroll-mt-6 grid grid-cols-[2.75rem_1fr] rounded-xl border border-slate-200 bg-white shadow-sm sm:grid-cols-[3.75rem_1fr]"
|
||||
className="scroll-mt-6 grid grid-cols-[2.75rem_1fr] rounded-xl border border-line bg-white sm:grid-cols-[3.75rem_1fr]"
|
||||
>
|
||||
{/* ขอบ folio — "หน้า" เล็ก + เลขใหญ่ชิดเส้นดิ่ง */}
|
||||
<div className="border-r border-slate-100 py-4 pl-3 pr-2 text-right sm:pl-4">
|
||||
<div className="border-r border-line/60 py-4 pl-3 pr-2 text-right sm:pl-4">
|
||||
<h2 id={`page-${pi + 1}-title`} className="tabular-nums">
|
||||
<span className="block text-[11px] leading-none text-slate-500">
|
||||
<span className="block text-[11px] leading-none text-ink-soft">
|
||||
หน้า
|
||||
</span>
|
||||
<span className="mt-1 block text-2xl font-semibold leading-none text-primary">
|
||||
{/* เลขหน้าเป็น ink ไม่ใช่ primary — Genesis "น้ำเงินเฉพาะของ
|
||||
interactive" (ตัดสินใจพร้อม exception list ใน DESIGN.md
|
||||
2026-09-23) ความเด่นมาจากขนาด 2xl semibold tabular-nums */}
|
||||
<span className="mt-1 block text-2xl font-semibold leading-none text-ink">
|
||||
{pi + 1}
|
||||
</span>
|
||||
</h2>
|
||||
|
|
@ -341,7 +343,7 @@ export default async function SummaryPage({
|
|||
<div className="min-w-0 py-3 pl-3 pr-3 sm:pl-4 sm:pr-5 sm:py-4">
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm leading-relaxed text-slate-600">
|
||||
<p className="text-sm leading-relaxed text-ink-soft">
|
||||
{pageSummaryLine(b)}
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -358,7 +360,7 @@ export default async function SummaryPage({
|
|||
{b.bms.length > 0 && (
|
||||
<div className="mt-2">
|
||||
<CollapsibleBlock kind="bookmark" count={b.bms.length}>
|
||||
<ul className="divide-y divide-slate-100">
|
||||
<ul className="divide-y divide-line/70">
|
||||
{b.bms.map((bm) => {
|
||||
const parent = bm.parentId
|
||||
? bookmarkById.get(bm.parentId)
|
||||
|
|
@ -367,25 +369,25 @@ export default async function SummaryPage({
|
|||
<li key={bm.id} className="ml-4">
|
||||
<Link
|
||||
href={`/annotate/${id}?page=${pi + 1}`}
|
||||
className={`group -mx-2 flex items-start gap-2 rounded-lg px-2 py-2.5 transition hover:bg-slate-50 ${RING_CLS}`}
|
||||
className={`group -mx-2 flex items-start gap-2 rounded-lg px-2 py-2.5 transition hover:bg-ink/[0.03] ${RING_CLS}`}
|
||||
>
|
||||
<Bookmark
|
||||
aria-hidden
|
||||
className="mt-1 h-4 w-4 shrink-0 text-amber-500"
|
||||
className="mt-1 h-4 w-4 shrink-0 text-warning-ink"
|
||||
/>
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="block whitespace-pre-wrap break-words text-sm font-medium leading-snug text-slate-800">
|
||||
<span className="block whitespace-pre-wrap break-words text-sm font-medium leading-snug text-ink">
|
||||
{bm.title}
|
||||
</span>
|
||||
<span className="mt-0.5 block truncate text-xs text-slate-500">
|
||||
<span className="mt-0.5 block truncate text-xs text-ink-soft">
|
||||
โดย {bm.userName || "ไม่ทราบชื่อ"}
|
||||
{parent ? ` · ใน: ${parent.title}` : ""}
|
||||
</span>
|
||||
{bm.note && (
|
||||
<span className="mt-0.5 flex items-start gap-1 text-xs leading-relaxed text-slate-500">
|
||||
<span className="mt-0.5 flex items-start gap-1 text-xs leading-relaxed text-ink-soft">
|
||||
<StickyNote
|
||||
aria-hidden
|
||||
className="mt-0.5 h-3 w-3 shrink-0 text-amber-400"
|
||||
className="mt-0.5 h-3 w-3 shrink-0 text-warning-ink"
|
||||
/>
|
||||
<span className="line-clamp-2 whitespace-pre-wrap break-words">
|
||||
{bm.note}
|
||||
|
|
@ -395,7 +397,7 @@ export default async function SummaryPage({
|
|||
</span>
|
||||
<ChevronRight
|
||||
aria-hidden
|
||||
className="mt-1.5 h-4 w-4 shrink-0 text-slate-300 group-hover:text-slate-400"
|
||||
className="mt-1.5 h-4 w-4 shrink-0 text-ink-faint group-hover:text-ink"
|
||||
/>
|
||||
</Link>
|
||||
</li>
|
||||
|
|
@ -410,35 +412,35 @@ export default async function SummaryPage({
|
|||
{b.anns.length > 0 && (
|
||||
<div className={b.bms.length > 0 ? "mt-3" : "mt-2"}>
|
||||
<CollapsibleBlock kind="annotation" count={b.anns.length}>
|
||||
<ul className="divide-y divide-slate-100">
|
||||
<ul className="divide-y divide-line/70">
|
||||
{b.anns.map((a) => (
|
||||
<li key={a.id} className="ml-4">
|
||||
<Link
|
||||
href={`/annotate/${id}?ann=${a.id}`}
|
||||
className={`group -mx-2 flex items-start gap-2 rounded-lg px-2 py-2.5 transition hover:bg-slate-50 ${RING_CLS}`}
|
||||
className={`group -mx-2 flex items-start gap-2 rounded-lg px-2 py-2.5 transition hover:bg-ink/[0.03] ${RING_CLS}`}
|
||||
>
|
||||
<AnnotationTypeIcon
|
||||
type={a.type}
|
||||
data={a.data}
|
||||
className="mt-1 h-4 w-4 shrink-0 text-slate-500"
|
||||
className="mt-1 h-4 w-4 shrink-0 text-ink-soft"
|
||||
/>
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="block whitespace-pre-wrap break-words text-sm leading-snug text-slate-800">
|
||||
<span className="block whitespace-pre-wrap break-words text-sm leading-snug text-ink">
|
||||
{annotationPreviewText(a)}
|
||||
{a.type === "COMMENT" && a.resolved && (
|
||||
<span className="ml-1.5 whitespace-nowrap rounded border border-emerald-600/50 bg-emerald-50 px-1.5 py-0.5 text-xs text-emerald-700">
|
||||
<span className="ml-1.5 whitespace-nowrap rounded border border-success/40 bg-success/10 px-1.5 py-0.5 text-xs font-medium text-success-ink">
|
||||
จัดการแล้ว
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
<span className="mt-0.5 block text-xs text-slate-500">
|
||||
<span className="mt-0.5 block text-xs text-ink-soft">
|
||||
{annotationTypeLabel(a)} · โดย {a.userName}
|
||||
</span>
|
||||
{annotationNote(a) && (
|
||||
<span className="mt-0.5 flex items-start gap-1 text-xs leading-relaxed text-slate-500">
|
||||
<span className="mt-0.5 flex items-start gap-1 text-xs leading-relaxed text-ink-soft">
|
||||
<StickyNote
|
||||
aria-hidden
|
||||
className="mt-0.5 h-3 w-3 shrink-0 text-amber-400"
|
||||
className="mt-0.5 h-3 w-3 shrink-0 text-warning-ink"
|
||||
/>
|
||||
<span className="line-clamp-2 whitespace-pre-wrap break-words">
|
||||
{annotationNote(a)}
|
||||
|
|
@ -448,7 +450,7 @@ export default async function SummaryPage({
|
|||
</span>
|
||||
<ChevronRight
|
||||
aria-hidden
|
||||
className="mt-1.5 h-4 w-4 shrink-0 text-slate-300 group-hover:text-slate-400"
|
||||
className="mt-1.5 h-4 w-4 shrink-0 text-ink-faint group-hover:text-ink"
|
||||
/>
|
||||
</Link>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@ export default async function AnnotateEntryPage({
|
|||
<main className="mx-auto max-w-2xl px-4 py-10 sm:px-8">
|
||||
<div
|
||||
role="alert"
|
||||
className="rounded-xl border border-red-200 bg-red-50 p-4 text-sm text-red-700"
|
||||
className="rounded-lg border border-error/30 bg-error/10 p-4 text-sm text-error-ink"
|
||||
>
|
||||
เปิดเอกสารจากลิงก์ไม่สำเร็จ: {result.error}
|
||||
</div>
|
||||
<Link
|
||||
href="/"
|
||||
className="mt-4 inline-block rounded-md bg-primary px-4 py-2 text-sm font-medium text-white transition hover:opacity-90"
|
||||
className="focus-ring mt-4 inline-block rounded-md bg-primary px-4 py-2 text-sm font-medium text-white transition hover:-translate-y-px hover:bg-primary-hover hover:shadow-btn-glow"
|
||||
>
|
||||
กลับหน้ารายการ
|
||||
</Link>
|
||||
|
|
@ -46,15 +46,15 @@ export default async function AnnotateEntryPage({
|
|||
// ไม่มี fileUrl เลย — ไม่มีอะไรให้เปิด (route จริงของ viewer อยู่ที่ /annotate/[id])
|
||||
return (
|
||||
<main className="mx-auto max-w-2xl px-4 py-10 sm:px-8">
|
||||
<div className="rounded-xl border border-slate-200 bg-white p-6 text-sm text-slate-600">
|
||||
ไม่ได้ระบุลิงก์เอกสาร — ใช้ <code className="rounded bg-slate-100 px-1">
|
||||
<div className="rounded-xl border border-line bg-white p-6 text-sm text-ink-soft">
|
||||
ไม่ได้ระบุลิงก์เอกสาร — ใช้ <code className="rounded bg-ink/[0.05] px-1">
|
||||
/annotate?fileUrl=…&fileId=…&typeId=…
|
||||
</code>{" "}
|
||||
หรือเลือกไฟล์จากหน้ารายการ
|
||||
</div>
|
||||
<Link
|
||||
href="/"
|
||||
className="mt-4 inline-block rounded-md bg-primary px-4 py-2 text-sm font-medium text-white transition hover:opacity-90"
|
||||
className="focus-ring mt-4 inline-block rounded-md bg-primary px-4 py-2 text-sm font-medium text-white transition hover:-translate-y-px hover:bg-primary-hover hover:shadow-btn-glow"
|
||||
>
|
||||
กลับหน้ารายการ
|
||||
</Link>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue