feat(wordaddin): port Word add-in taskpane from poc
พอร์ต taskpane ของ Word add-in "e-Court Documents Versioning" จาก D:\word-addin-poc มาเป็น sibling app ที่ route /docedit/wordaddin: - wordaddin/ (client-only zone): services พอร์ตดิบทั้งชุด (authService/versioningService เป็น mock รอ backend จริง) + models + config - components/wordaddin/: WordAddinGate ฉีด office.js self-host (singleton กัน StrictMode double-inject + fallback timer ครอบเคส onReady เงียบ) และ TaskpaneApp state machine แปลง JSX เป็น Genesis design system - scripts/fetch-office-js.mjs (postinstall ตัวที่สาม): ดาวน์โหลด Office.js runtime ล่าสุดจาก CDN Microsoft ไป public/wordaddin/office-js/ (gitignore สร้างใหม่ได้ — npm @microsoft/office-js ตกรุ่นไม่มี Document.close) - middleware/basePath/root page: เปิด /wordaddin เป็น public (auth แยกจาก แอป note), root /docedit redirect ไป taskpane ยกเว้นลิงก์ e-Court N8 (?fileUrl=&fileId=&typeId=) ที่ยังส่งต่อ /note ตามเดิม - docker/web.Dockerfile รัน fetch-office-js ตอน build + npm scripts dev:https สำหรับ sideload ตาม docs/WORDADDIN-DEV.md Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
7a146d48be
commit
c401f4deb7
37 changed files with 11216 additions and 17 deletions
68
components/wordaddin/SaveControls.tsx
Normal file
68
components/wordaddin/SaveControls.tsx
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import { CircleCheck, Save, X } from "lucide-react";
|
||||
|
||||
import { MessageBar } from "./MessageBar";
|
||||
import { Spinner } from "./Spinner";
|
||||
|
||||
/**
|
||||
* FR-17/FR-18 — ปุ่ม [บันทึก] / [บันทึกและปิดเอกสาร] + สถานะการบันทึก (ใช้ทุก phase ตาม spec v10)
|
||||
* banner autoSaveError อยู่ที่นี่เพื่อให้เห็นทุก phase ไม่เฉพาะตอน tracking
|
||||
* พอร์ตจาก SaveControls ใน App.tsx ต้นฉบับ (D:\word-addin-poc\addin) — logic เดิม เปลี่ยนแค่ชั้นภาพ
|
||||
*/
|
||||
export function SaveControls({
|
||||
disabled,
|
||||
busy,
|
||||
status,
|
||||
error,
|
||||
autoSaveError,
|
||||
closeSupported,
|
||||
onSave,
|
||||
onSaveAndClose,
|
||||
}: {
|
||||
/** กำลังอยู่ใน flow อื่น (versioning) — ปิดปุ่มกันกดซ้อน */
|
||||
disabled: boolean;
|
||||
busy: boolean;
|
||||
status: "saving" | "saved" | null;
|
||||
error: string | null;
|
||||
autoSaveError: string | null;
|
||||
closeSupported: boolean;
|
||||
onSave: () => void;
|
||||
onSaveAndClose: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<button
|
||||
type="button"
|
||||
className="focus-ring inline-flex items-center gap-1.5 rounded-md border border-line bg-white px-3 py-1.5 text-sm text-ink transition hover:border-primary hover:text-primary disabled:pointer-events-none disabled:opacity-50"
|
||||
disabled={disabled || busy}
|
||||
onClick={onSave}
|
||||
>
|
||||
<Save className="size-4" aria-hidden />
|
||||
บันทึก
|
||||
</button>
|
||||
{closeSupported ? (
|
||||
<button
|
||||
type="button"
|
||||
className="focus-ring inline-flex items-center gap-1.5 rounded-md border border-line bg-white px-3 py-1.5 text-sm text-ink transition hover:border-primary hover:text-primary disabled:pointer-events-none disabled:opacity-50"
|
||||
disabled={disabled || busy}
|
||||
onClick={onSaveAndClose}
|
||||
>
|
||||
<X className="size-4" aria-hidden />
|
||||
บันทึกและปิดเอกสาร
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
{busy && status === "saving" ? <Spinner label="กำลังบันทึก…" /> : null}
|
||||
{!busy && status === "saved" ? (
|
||||
<p className="inline-flex items-center gap-1.5 text-sm text-ink-soft">
|
||||
<CircleCheck className="size-4 text-success-ink" aria-hidden />
|
||||
บันทึกแล้ว
|
||||
</p>
|
||||
) : null}
|
||||
{error ? <MessageBar intent="error">{error}</MessageBar> : null}
|
||||
{autoSaveError ? <MessageBar intent="warning">{autoSaveError}</MessageBar> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SaveControls;
|
||||
Loading…
Add table
Add a link
Reference in a new issue