跳到正文
cccskills
免费在 GitHub 公开

block-print-system

Printing and PDF export for AI response blocks and messages via @ai-matrx/print. Use when adding a print button or BlockPrinter to a render block, wiring PrintOptionsDialog/usePrintOptions, captureBlockElement, or useDomCapturePrint, or when a print window shows no images or a print fails silently.

中文简介正在准备中。当前显示原文说明。

查看安装方法

包含的文件(1)

  • SKILL.md8.4 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Block Print System

Three-tier architecture for printing AI response messages, plus the reusable printing core that other surfaces build on. The core lives in the @ai-matrx/print npm package (extracted 2026-08-29; source aidream/apps/shared/print) — chat-specific tiers live with the conversation feature.

Architecture Overview

Tier 1 — Quick Print (prose only)
  printMarkdownContent() → regex → HTML window
  File: ../aidream/apps/shared/chat/src/conversation/utils/markdown-print.ts
  Limitation: ignores all custom blocks

Tier 2 — Full Message (DOM screenshot)
  useDomCapturePrint → html2canvas + jsPDF
  File: ../aidream/apps/shared/chat/src/conversation/hooks/useDomCapturePrint.ts
  Hook returns: { captureRef, isCapturing, progress, captureAsPDF, error }
  isCapturing must be wired to the menu item (disabled state + label change)

Tier 3 — Per-Block (best quality, block owns its output)
  Print button in each block's header → either HTML template printer or DOM capture
  Dialog + hook: @ai-matrx/print/react (PrintOptionsDialog, usePrintOptions)

The BlockPrinter Interface

Source of truth: @ai-matrx/print/core (BlockPrinter, PrintVariant, PrintSetting, PrintSettings)

interface BlockPrinter {
    label: string;
    variants: PrintVariant[];
    settings?: PrintSetting[];
    print: (data: unknown, variantId?: string, settings?: PrintSettings) => void | Promise<void>;
}

interface PrintVariant { id: string; label: string; description?: string; }

// PrintSetting is a discriminated union of FOUR control types (all support
// appliesTo?: string[] — which variantIds the setting shows for):
//   { type: "boolean"; id; label; description?; defaultValue }
//   { type: "range";   id; label; fromId; toId; defaultFrom; defaultTo; min?;
//     fromPlaceholder?; toPlaceholder? }   // two number inputs; writes TWO
//     settings-map keys (fromId/toId); 0 = "no bound" by convention
//   { type: "number";  id; label; defaultValue; min?; max? }  // single numeric input
//   { type: "select";  id; label; options: {value,label}[]; defaultValue }
//     // compact segmented one-of-N row

type PrintSettings = Record<string, boolean | string | number>;

If variants.length === 0 AND settings.length === 0, usePrintOptions calls print(data) immediately with no dialog. Otherwise the PrintOptionsDialog opens first (Dialog on desktop, Drawer on mobile).

Existing Printers

Block / surfaceStrategyFile
FlashcardsBlockHTML template@ai-matrx/print/flashcards (flashcardsPrinter)
MultipleChoiceQuizHTML templatecomponents/mardown-display/blocks/quiz/quiz-printer.ts
MathProblemBlockHTML templatecomponents/mardown-display/blocks/math/math-printer.ts
DiagramBlockHTML templatecomponents/mardown-display/blocks/diagram/diagram-printer.ts
PD rating reportHTML templatefeatures/legal/wc/pd-ratings/print/pd-report-printer.ts
Performance review reportHTML templatefeatures/employee-performance-reviews/review-report.ts
QR label sheetsHTML template (registry-driven grid)@ai-matrx/print/labels (qrLabelsPrinter) — Avery + roll stock QR labels; template registry, calibration page, LabelSheetPreview (in /react) + jsPDF lane
Various display blocksDOM captureinline in component via @ai-matrx/alchemy/operate/capture (captureDocumentPdf) + kit downloadFile

Adding an HTML Template Printer

  1. Create <block-name>-printer.ts alongside the component file.
  2. Import buildPrintDocument, openPrintWindow, escapeHtml, type BlockPrinter, type PrintSettings from @ai-matrx/print/core.
  3. Define variants and optional settings arrays.
  4. In print(data, variantId = "default", settings?):
    • Cast and guard: if (!typed?.items?.length) { openPrintWindow(buildPrintDocument("<p>No data.</p>", ...), "fallback"); return; }
    • Call escapeHtml() on every user string.
    • Read settings as: const show = (settings?.showX ?? false) as boolean.
  5. In the component: call usePrintOptions(printer, data) (from @ai-matrx/print/react), wire triggerPrint to a <Printer> button, render <PrintOptionsDialog> outside (not inside) the block wrapper.

Full examples in the package source (aidream/apps/shared/print/src/): flashcards.ts (variants + boolean settings + fit-text auto-shrink), labels.ts (all four setting types, inch-exact @page geometry, data-URI images).

Adding a DOM Capture Block

Required pattern — copy exactly:

const blockContentRef = useRef<HTMLDivElement>(null);
const [isPrinting, setIsPrinting] = useState(false);

const handlePrint = useCallback(async () => {
    if (!blockContentRef.current || isPrinting) return;
    setIsPrinting(true);
    try {
        const [{ captureDocumentPdf }, { downloadFile }] = await Promise.all([
            import('@ai-matrx/alchemy/operate/capture'),
            import('@ai-matrx/kit/download'),
        ]);
        downloadFile('filename.pdf', await captureDocumentPdf(blockContentRef.current, { orientation: 'portrait' }), 'application/pdf'); // or 'landscape'
    } catch (err) {
        console.error('[BlockName] Print failed:', err);
    } finally {
        setIsPrinting(false);
    }
}, [isPrinting]);

Key rules:

  • captureDocumentPdf(element, { orientation }) returns the PDF bytes (orientation: "landscape" | "portrait"); save them with kit downloadFile. App code never imports @ai-matrx/print/pdf directly (guard: pnpm check:alchemy-doors)
  • Always await it — missing await means errors are invisible silent rejections
  • Attach ref to the content container, not the whole block shell or a stats summary
  • disabled={isPrinting} on the button; show "Saving…" label while active
  • If the block has fullscreen mode, add a print button in the fullscreen header too — the regular toolbar is hidden

Wiring Tier 2 isCapturing

In the assistant-message component:

const { captureRef, isCapturing, captureAsPDF } = useDomCapturePrint();

Pass isCapturing to the message options menu as a prop. The menu item should be disabled and show "Generating PDF…" while true.

Key Utilities

All in @ai-matrx/print (/core, /pdf, /markdown, /react). Since 0.3.0 the markdown converter and the print stylesheet ship IN the package — there is no host seam, and re-adding one is the defect this repo already made three times:

  • buildPrintDocument(bodyHtml, title?, extraStyles?) → complete <!DOCTYPE html> string
  • openPrintWindow(htmlDoc, filename?) → popup window; falls back to .html download if popup blocked. The window is a fresh unauthenticated document — inline every image as a data URI, never fetch.
  • printHtmlContent(bodyHtml, title?, extraStyles?) → shorthand combo
  • markdownToPdfBlob(markdown) (/pdf) → styled multi-page PDF Blob, no arguments beyond the markdown
  • markdownToHtml / getMarkdownStylesheet / printMarkdown (/markdown) → the shipped converter, the two default stylesheets ("document" and "article"), and the one-call print window. Brand it with tokens; never fork the sheet.
  • captureDocumentPdf(el, opts) (@ai-matrx/alchemy/operate/capture) → loads print's DOM-capture engine and returns the PDF bytes
  • Fixed-geometry sheets (@page { size: …; margin: 0 }, inch-exact cells, screen-only "100% scale, no margins" banner, FIT_TEXT auto-shrink): patterns in the package's flashcards.ts (Avery 5388) and, generalized to a template registry, labels.ts

Common Bugs to Watch For

  1. Missing await on captureDocumentPdf — errors silently swallowed
  2. ref on wrong element — attach to content, not stats/header/outer shell
  3. Print button absent in fullscreen — must add to fullscreen header explicitly
  4. Missing settings param in print() — use settings?.key ?? defaultValue pattern
  5. isCapturing not wired — users get no feedback during Tier 2 PDF generation
  6. Fetched images in a print window — the window has no auth; only data URIs render

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Admin debug system wiring for the floating AdminIndicator's live debug data and Copy Full Context. Use when adding debug visibility to a route or feature, wiring useDebugContext or the debug panel, capturing console errors, or enabling the copy-context workflow for a page.

中文简介正在准备中。当前显示原文说明。

armanisadeghi/ai-matrx32026年10月22日 更新

Compact two-icon Copy / Copy-for-AI controls (components/agent-copy). Use when adding copy buttons to a row, card, list, or record; merging duplicate Copy/JSON/AI controls; continuing the copy rollout; or writing a Copy-for-AI payload. NOT for markdown content actions (use rich-document-actions).

中文简介正在准备中。当前显示原文说明。

armanisadeghi/ai-matrx32026年10月22日 更新

Disclosing a surface's existing fixed AI jobs in the shell's top Agents menu. Use when a page, panel, overlay, or window already runs a mandate behind a button, assist, automatic action, or mode; when the agent-disclosure guard names a file; or during a surface check.

中文简介正在准备中。当前显示原文说明。

armanisadeghi/ai-matrx32026年10月22日 更新

The watch-fix-rerun method for making an existing platform agent or automated process efficient and correct: baseline its ledger, run one unit yourself, fix the class behind every wasted call, rerun, record. Use when asked to improve, optimize, watch, or 'make efficient' an agent, a sandbox session, a sync job, or any recurring automated process.

中文简介正在准备中。当前显示原文说明。

armanisadeghi/ai-matrx32026年10月22日 更新

Redux state for agent execution and firing agent shortcuts. Use when editing features/agents/redux/, building agent UI, creating a conversation, touching assembleRequest or NDJSON stream state, wiring agent-state selectors, adding a per-conversation capability, or triggering a shortcut from a button, menu, or code (useShortcutTrigger, launchAgentExecution).

中文简介正在准备中。当前显示原文说明。

armanisadeghi/ai-matrx32026年10月22日 更新

The provision for a call site: the exhaustive menu of values that place in the code can realistically produce. Use before creating or fixing a mandate or agent that reasons about more than its own input, when deciding whether an agent can answer at all with what it is sent, or when its output 'looks right' but nobody checked it could be. NOT for building the agent (use create-agent).

中文简介正在准备中。当前显示原文说明。

armanisadeghi/ai-matrx32026年10月22日 更新

查看 armanisadeghi 的全部技能

报告此技能的问题