From bb51e37893894decc1c7dad9a4bb933e05272f44 Mon Sep 17 00:00:00 2001 From: Ma'sum Date: Sat, 29 Aug 2026 21:16:07 +0700 Subject: [PATCH] feat: redesign CLI summary UI, add example configurations, and update documentation --- .../cli/markforge/docs/full-all-properties.md | 2 +- apps/cli/markforge/examples/1-minimal.ts | 37 +++ apps/cli/markforge/examples/2-intermediate.ts | 73 ++++++ apps/cli/markforge/examples/3-full-custom.ts | 178 ++++++++++++++ .../cli/markforge/examples/4-low-level-ast.ts | 64 +++++ apps/cli/markforge/markforge.full-config.ts | 28 ++- apps/cli/markforge/package.json | 7 +- .../src/content/docs/markforge/changelog.mdx | 31 ++- .../content/docs/markforge/configuration.mdx | 83 ++++++- .../docs/src/content/docs/markforge/index.mdx | 47 ++-- .../content/docs/markforge/installation.mdx | 2 +- .../docs/src/content/docs/markforge/usage.mdx | 143 +++++++++-- packages/markforge/README.md | 42 +++- packages/markforge/package.json | 2 +- packages/markforge/src/config/loadConfig.ts | 3 +- .../markforge/src/config/resolveConfig.ts | 121 ++++++++++ packages/markforge/src/config/types.ts | 94 ++++++++ .../markforge/src/core/docx/docxBuilder.ts | 226 +++++++++++++++++- .../markforge/src/core/html/htmlBuilder.ts | 173 +++++++++++++- packages/markforge/src/index.ts | 7 + packages/markforge/src/ui/App.tsx | 12 +- packages/markforge/src/ui/Header.tsx | 94 ++++++-- packages/markforge/src/ui/SummaryTable.tsx | 97 ++++++-- packages/markforge/src/version.ts | 2 +- packages/markforge/test/allProperties.test.ts | 66 ++++- packages/markforge/test/config.test.ts | 27 +++ .../test/mermaidAndWatermark.test.ts | 2 +- packages/rn-qr-code/README.md | 2 +- 28 files changed, 1537 insertions(+), 128 deletions(-) create mode 100644 apps/cli/markforge/examples/1-minimal.ts create mode 100644 apps/cli/markforge/examples/2-intermediate.ts create mode 100644 apps/cli/markforge/examples/3-full-custom.ts create mode 100644 apps/cli/markforge/examples/4-low-level-ast.ts diff --git a/apps/cli/markforge/docs/full-all-properties.md b/apps/cli/markforge/docs/full-all-properties.md index 9337e90..b760f18 100644 --- a/apps/cli/markforge/docs/full-all-properties.md +++ b/apps/cli/markforge/docs/full-all-properties.md @@ -1,7 +1,7 @@ --- title: "Unified Platform Architecture & Document Suite" subtitle: "Enterprise Specification & Feature Validation Guide" -author: "Masum RPG" +author: "Ma'sum" company: "Masum Dev Technologies" version: "1.0.0" date: "2026-08-29" diff --git a/apps/cli/markforge/examples/1-minimal.ts b/apps/cli/markforge/examples/1-minimal.ts new file mode 100644 index 0000000..95b787d --- /dev/null +++ b/apps/cli/markforge/examples/1-minimal.ts @@ -0,0 +1,37 @@ +/** + * Example 1: Minimal Programmatic Usage + * + * Compiles a Markdown string or file with zero configuration. + * Uses default corporate styling and outputs to .temp/example-minimal/ + */ +import { compileMarkdown } from "@masumdev/markforge"; + +async function run() { + console.log("=== MarkForge: Minimal Programmatic Compilation ==="); + + const markdown = ` +# Minimal Programmatic Document + +This document was generated programmatically with **MarkForge** using minimal configuration. + +- Zero configuration required +- Auto-detects paper size and margins +- Generates Word DOCX, PDF, and HTML +`; + + const result = await compileMarkdown(markdown, { + to: ["docx", "pdf", "html"], + outputDir: "./.temp/example-minimal", + metadata: { + title: "Minimal Example Document", + author: "Ma'sum", + }, + }); + + console.log(`Compilation completed in ${result.durationMs}ms:`); + for (const file of result.files) { + console.log(`- [${file.format.toUpperCase()}] ${file.fileName} (${file.sizeBytes} bytes)`); + } +} + +run().catch(console.error); diff --git a/apps/cli/markforge/examples/2-intermediate.ts b/apps/cli/markforge/examples/2-intermediate.ts new file mode 100644 index 0000000..254e580 --- /dev/null +++ b/apps/cli/markforge/examples/2-intermediate.ts @@ -0,0 +1,73 @@ +/** + * Example 2: Intermediate Programmatic Usage + * + * Demonstrates themes, syntax highlighting palettes, TOC, custom margins, + * and live progress logging callback. + */ +import { + compileMarkdown, + OutputFormat, + Theme, + SyntaxTheme, + PaperSizeEnum, +} from "@masumdev/markforge"; + +async function run() { + console.log("=== MarkForge: Intermediate Programmatic Compilation ==="); + + const markdownContent = ` +# Technical Architecture Overview + +Welcome to the intermediate programmatic specification. + +## Core Microservices + +Here is the TypeScript microservice interface: + +\`\`\`typescript +export interface ServiceNode { + id: string; + endpoint: string; + activeConnections: number; +} +\`\`\` + +> [!NOTE] +> All network traffic across nodes is encrypted via mTLS. +`; + + const result = await compileMarkdown( + markdownContent, + { + to: [OutputFormat.DOCX, OutputFormat.PDF, OutputFormat.HTML], + outputDir: "./.temp/example-intermediate", + theme: Theme.CORPORATE, + syntaxTheme: SyntaxTheme.DRACULA, + paperSize: PaperSizeEnum.A4, + toc: true, + margins: { + top: "2.5cm", + bottom: "2.5cm", + left: "2.5cm", + right: "2.5cm", + }, + metadata: { + title: "Technical Architecture Overview", + subtitle: "Microservices & Edge Network", + author: "Ma'sum", + company: "Masum Dev Technologies", + version: "1.2.0", + }, + }, + (status) => { + console.log(`[PROGRESS] ${status}`); + } + ); + + console.log(`\nCompiled ${result.files.length} documents in ${result.durationMs}ms:`); + for (const file of result.files) { + console.log(`- [${file.format.toUpperCase()}] ${file.fileName} (${file.sizeBytes} bytes)`); + } +} + +run().catch(console.error); diff --git a/apps/cli/markforge/examples/3-full-custom.ts b/apps/cli/markforge/examples/3-full-custom.ts new file mode 100644 index 0000000..5bdd12e --- /dev/null +++ b/apps/cli/markforge/examples/3-full-custom.ts @@ -0,0 +1,178 @@ +/** + * Example 3: Full Enterprise Programmatic Usage + * + * Demonstrates 100% of all properties: + * - Dynamic metadata tokens ({title}, {author}, {company}, {version}, {date}, {page}, {pages}) + * - Per-zone header and footer customization (left, center, right, dividers) + * - 100% unselectable vector watermark (Canvas-to-PNG raster) + * - Signatures and approval blocks (Lembar Pengesahan) + * - Custom ThemeProps color tokens + * - Live progress callback + */ +import { + compileMarkdown, + OutputFormat, + Orientation, + PaperSizeEnum, + SyntaxTheme, + type MarkforgeConfig, +} from "@masumdev/markforge"; + +async function run() { + console.log("=== MarkForge: Full Enterprise Programmatic Compilation ==="); + + const markdown = `--- +title: "Enterprise Cloud Infrastructure Agreement" +subtitle: "High-Availability Multi-Region Architecture" +author: "Ma'sum" +company: "Masum Dev Technologies" +version: "2.0.0" +date: "2026-08-29" +lang: "en" +--- + +# Executive Summary + +This formal document verifies all enterprise capabilities of the MarkForge engine. + +## Infrastructure Diagram + +\`\`\`mermaid +flowchart LR + Client[Web Client] --> Gateway[API Gateway] + Gateway --> ServiceA[Auth Service] + Gateway --> ServiceB[Billing Service] +\`\`\` + +## Configuration Code + +\`\`\`typescript +export const clusterConfig = { + region: "ap-southeast-1", + nodes: 12, + ha: true, +}; +\`\`\` + +> [!IMPORTANT] +> Formal authorization signatures are attached at the end of this document. +`; + + const config: MarkforgeConfig = { + to: [OutputFormat.DOCX, OutputFormat.PDF, OutputFormat.HTML], + outputDir: "./.temp/example-full", + orientation: Orientation.PORTRAIT, + paperSize: PaperSizeEnum.A4, + toc: true, + syntaxTheme: SyntaxTheme.GITHUB_DARK, + embedImages: true, + bundleHtml: true, + + // Custom Theme Props Palette + theme: { + primaryColor: "#0D998D", + primaryDark: "#008073", + primaryLight: "#D9F1F0", + backgroundColor: "#FFFFFF", + textColor: "#0F172A", + textMuted: "#64748B", + borderColor: "#E2E8F0", + cardBackground: "#F8FAFC", + codeBackground: "#0F172A", + codeText: "#F8FAFC", + fontFamily: "'Segoe UI', Roboto, sans-serif", + fontMono: "'Cascadia Code', Consolas, monospace", + }, + + margins: { + top: "3cm", + bottom: "3cm", + left: "2.5cm", + right: "2.5cm", + }, + + // 100% Unselectable PDF & Visual Watermark + watermark: { + text: "CONFIDENTIAL DRAFT", + color: "#E11D48", + opacity: 0.08, + fontSize: 52, + rotate: -45, + }, + + // Custom Header Zones with Dynamic Tokens + header: { + left: { + text: "{company} | {title}", + color: "#0D998D", + fontSize: 9, + bold: true, + }, + center: "Confidential Reference", + right: { + text: "v{version}", + color: "#94A3B8", + fontSize: 8.5, + italic: true, + }, + divider: true, + dividerColor: "#CBD5E1", + }, + + // Custom Footer Zones with Dynamic Tokens & Page Numbering + footer: { + left: { + text: "Author: {author}", + color: "#64748B", + fontSize: 8.5, + }, + center: "{date}", + right: { + text: "Page {page} of {pages}", + color: "#0D998D", + fontSize: 9, + bold: true, + }, + divider: true, + dividerColor: "#CBD5E1", + }, + + // Formal Signatures & Approval Block (Lembar Pengesahan) + signatures: { + align: "space-between", + style: "line", + borderColor: "#CBD5E1", + items: [ + { + title: "Prepared by", + name: "{author}", + role: "Lead Platform Architect", + date: "{date}", + }, + { + title: "Reviewed by", + name: "Sarah Jenkins", + role: "Head of Infrastructure", + date: "{date}", + }, + { + title: "Approved by", + name: "Dr. Alexander Wright", + role: "Chief Technology Officer", + date: true, + }, + ], + }, + }; + + const result = await compileMarkdown(markdown, config, (msg) => { + console.log(`[COMPILING] ${msg}`); + }); + + console.log(`\nCompilation successful in ${result.durationMs}ms:`); + for (const f of result.files) { + console.log(`- [${f.format.toUpperCase()}] ${f.filePath} (${f.sizeBytes} bytes)`); + } +} + +run().catch(console.error); diff --git a/apps/cli/markforge/examples/4-low-level-ast.ts b/apps/cli/markforge/examples/4-low-level-ast.ts new file mode 100644 index 0000000..c3c99ab --- /dev/null +++ b/apps/cli/markforge/examples/4-low-level-ast.ts @@ -0,0 +1,64 @@ +/** + * Example 4: Low-Level AST & In-Memory Buffer Builders + * + * Demonstrates direct low-level document compilation without writing files to disk. + * Returns raw binary Buffers (DOCX, PDF) and HTML markup strings. + */ +import * as fs from "node:fs"; +import { + parseMarkdownDocument, + buildDocxDocument, + buildPdfDocument, + buildHtmlDocument, + resolveDocumentConfig, + Theme, +} from "@masumdev/markforge"; + +async function run() { + console.log("=== MarkForge: Low-Level AST & Buffer Pipeline ==="); + + const rawMarkdown = ` +# Low-Level In-Memory Compilation + +This markdown is ingested directly into an AST node tree. + +- Node parsing +- In-memory binary generation +- Direct buffer retrieval +`; + + // 1. Parse Markdown into structured AST + const parsedDoc = parseMarkdownDocument(rawMarkdown); + console.log(`- AST generated with ${parsedDoc.nodes.length} nodes and ${parsedDoc.tocEntries.length} TOC entries`); + + // 2. Resolve document configuration + const resolvedConfig = resolveDocumentConfig(parsedDoc.metadata, { + theme: Theme.CORPORATE, + toc: true, + metadata: { + title: "In-Memory Buffer Spec", + author: "Ma'sum", + }, + }); + + // 3. Build documents independently in parallel + const [docxBuffer, pdfBuffer, htmlString] = await Promise.all([ + buildDocxDocument(parsedDoc, resolvedConfig), + buildPdfDocument(parsedDoc, resolvedConfig), + buildHtmlDocument(parsedDoc, resolvedConfig), + ]); + + console.log(`- DOCX Buffer generated : ${docxBuffer.byteLength} bytes (PK header: ${docxBuffer.subarray(0, 4).toString("hex")})`); + console.log(`- PDF Buffer generated : ${pdfBuffer.byteLength} bytes (PDF header: ${pdfBuffer.subarray(0, 5).toString("utf-8")})`); + console.log(`- HTML String generated : ${Buffer.byteLength(htmlString, "utf-8")} bytes`); + + // Optional: write to disk + fs.mkdirSync("./.temp/example-ast", { recursive: true }); + fs.writeFileSync("./.temp/example-ast/in-memory-doc.docx", docxBuffer); + fs.writeFileSync("./.temp/example-ast/in-memory-doc.pdf", pdfBuffer); + fs.writeFileSync("./.temp/example-ast/in-memory-doc.html", htmlString, "utf-8"); + + console.log("All in-memory buffers saved to ./.temp/example-ast/"); +} + +run().catch(console.error); diff --git a/apps/cli/markforge/markforge.full-config.ts b/apps/cli/markforge/markforge.full-config.ts index 87a1530..434ae88 100644 --- a/apps/cli/markforge/markforge.full-config.ts +++ b/apps/cli/markforge/markforge.full-config.ts @@ -105,11 +105,37 @@ export default defineConfig({ embedImages: true, bundleHtml: true, + // Document signature & approval blocks (1 to 4 signatory slots with customizable style and alignment) + signatures: { + align: "space-between", + style: "line", + items: [ + { + title: "Prepared by", + name: "{author}", + role: "Lead Platform Architect", + date: "{date}", + }, + { + title: "Reviewed by", + name: "Sarah Jenkins", + role: "Head of Engineering", + date: "{date}", + }, + { + title: "Approved by", + name: "Dr. Alexander Wright", + role: "Chief Technology Officer", + date: "{date}", + }, + ], + }, + // Fallback metadata dictionary metadata: { title: "Complete MarkForge Reference Manual", subtitle: "Enterprise Document Compiler & Visual Architecture", - author: "Masum RPG", + author: "Ma'sum", company: "Masum Dev Technologies", version: "1.0.0", date: "2026-08-29", diff --git a/apps/cli/markforge/package.json b/apps/cli/markforge/package.json index 73c2dd7..ca42c1d 100644 --- a/apps/cli/markforge/package.json +++ b/apps/cli/markforge/package.json @@ -13,7 +13,12 @@ "test:auto": "bun ../../../packages/markforge/dist/cli.mjs ./docs/sample.md", "build:sample": "bun ../../../packages/markforge/dist/cli.mjs ./docs/sample.md --to docx,pdf,html -o .temp/output", "build:spec": "bun ../../../packages/markforge/dist/cli.mjs ./docs/full-specification.md --to docx,pdf,html -o .temp/output", - "watch": "bun ../../../packages/markforge/dist/cli.mjs ./docs/sample.md --watch -o .temp/output" + "watch": "bun ../../../packages/markforge/dist/cli.mjs ./docs/sample.md --watch -o .temp/output", + "example:minimal": "bun ./examples/1-minimal.ts", + "example:intermediate": "bun ./examples/2-intermediate.ts", + "example:full": "bun ./examples/3-full-custom.ts", + "example:ast": "bun ./examples/4-low-level-ast.ts", + "example:all": "bun run example:minimal && bun run example:intermediate && bun run example:full && bun run example:ast" }, "dependencies": { "@masumdev/markforge": "workspace:*" diff --git a/apps/docs/src/content/docs/markforge/changelog.mdx b/apps/docs/src/content/docs/markforge/changelog.mdx index a80fb73..97e5bc0 100644 --- a/apps/docs/src/content/docs/markforge/changelog.mdx +++ b/apps/docs/src/content/docs/markforge/changelog.mdx @@ -6,10 +6,39 @@ sidebar: description: Release history and version notes for @masumdev/markforge. --- +## [0.3.0] - 2026-08-29 + +### Features & Enhancements + +- **100% Unselectable Vector Watermarks in PDF**: + - Replaced SVG text nodes with dynamic high-DPI HTML5 Canvas 2D rasterization (`canvas.toDataURL('image/png')` at 3x DPR). + - Emitted as a pure PNG Image XObject background layer in Chromium PDF, completely eliminating selectable text layer glyphs. + - Ensures clean cursor dragging and text selection across all PDF reader applications. +- **Comprehensive Programmatic API Suite**: + - Added full programmatic compilation examples in `apps/cli/markforge/examples/`: + - `1-minimal.ts`: Zero-configuration Markdown-to-MultiFormat execution. + - `2-intermediate.ts`: Themes, syntax palettes, TOC, and live progress callbacks. + - `3-full-custom.ts`: 100% feature utilization including dynamic tokens, per-zone header/footer slots, watermarks, signatures, and `ThemeProps`. + - `4-low-level-ast.ts`: Direct in-memory binary `Buffer` generation (`DOCX`, `PDF`, and `HTML`) without writing to disk. +- **Terminal CLI ASCII Redesign & Author Branding**: + - Modernized Ink CLI layout with clean ASCII borders and tree-style file summaries. + - Added author attribution (`Author: Ma'sum (@masumrpg)`) and direct repository links. + - Removed all emojis across CLI terminal outputs for maximum shell compatibility. +- **Author Identity & Workspace Normalization**: + - Replaced all legacy author references with `Ma'sum` and updated GitHub profiles to `https://github.com/masumrpg`. + +--- + ## [0.2.5] - 2026-08-29 -### 🚀 Features & Enhancements +### Features & Enhancements +- **Document Signatures & Approval Blocks (`signatures`)**: + - Add formal approval and sign-off blocks (*Lembar Pengesahan / Tanda Tangan*) with 1 to 4 signatory slots. + - Multi-alignment support (`left`, `center`, `right`, `space-between`). + - Multiple visual styles: `line` (classic underline divider), `box` (bordered card), and `clean` (borderless). + - Dynamic token interpolation (`{author}`, `{company}`, `{date}`, etc.) and optional digital signature image/seal embedding. + - Consistent and responsive rendering across **DOCX (Word)**, **Chromium PDF**, and **HTML**. - **Native Word Paragraph TabStops for Running Headers & Footers**: Replaced 3-column table headers and footers with native Microsoft Word OpenXML `TabStopType.CENTER` and `TabStopType.RIGHT` paragraph architecture. Eliminates 100% of table gridline boundaries/box outlines in LibreOffice Writer, Google Docs, and Microsoft Word when dividers are disabled. - **Synchronized Header & Footer Divider Lines**: Solid horizontal separator lines render cleanly via `border.bottom` / `border.top` on Word paragraphs and fixed print dividers (`@media print`) on Chromium PDF. - **DOCX Visual & Typography Overhaul**: diff --git a/apps/docs/src/content/docs/markforge/configuration.mdx b/apps/docs/src/content/docs/markforge/configuration.mdx index aef9bd0..1165ead 100644 --- a/apps/docs/src/content/docs/markforge/configuration.mdx +++ b/apps/docs/src/content/docs/markforge/configuration.mdx @@ -124,7 +124,7 @@ export default defineConfig({ metadata: { title: "Unified Platform Architecture & Document Suite", subtitle: "Enterprise Specification & Feature Validation Guide", - author: "Masum RPG", + author: "Ma'sum", company: "Masum Dev Technologies", version: "1.0.0", date: "2026-08-29", @@ -201,9 +201,88 @@ Variables defined in `metadata` or Markdown frontmatter can be referenced inside | :--- | :--- | :--- | | `{title}` | Document title | `Platform Reference Guide` | | `{subtitle}` | Document subtitle | `Enterprise Architecture` | -| `{author}` | Author name | `Masum RPG` | +| `{author}` | Author name | `Ma'sum` | | `{version}` | Document version | `1.0.0` | | `{date}` | Document date | `2026-08-29` | | `{company}` | Company or organization | `Masum Dev Technologies` | | `{page}` | Current page number (Footers only) | `1` | | `{pages}` | Total pages count (Footers only) | `4` | + +--- + +## Signatures & Approval Blocks (`signatures`) + +Add formal corporate approval and signature sections (*Lembar Pengesahan / Tanda Tangan*) at the end of documents with support for 1 to 4 signatory slots, variable token substitution, and custom visual styling: + +```typescript +export default defineConfig({ + signatures: { + align: "space-between", // "left" | "center" | "right" | "space-between" + style: "line", // "line" | "box" | "clean" + borderColor: "#CBD5E1", + items: [ + { + title: "Prepared by", + name: "{author}", + role: "Lead Platform Architect", + date: "{date}", + }, + { + title: "Reviewed by", + name: "Sarah Jenkins", + role: "Head of Engineering", + date: "{date}", + }, + { + title: "Approved by", + name: "Dr. Alexander Wright", + role: "Chief Technology Officer", + date: "{date}", + }, + ], + }, +}); +``` + +### Signature Block Properties + +| Property | Type | Default | Description | +| :--- | :--- | :--- | :--- | +| `items` | `SignatureItem[]` | **Required** | Array of 1 to 4 signature item definitions | +| `align` | `SignatureAlign` | `"space-between"` / `"right"` | Alignment (`"left"`, `"center"`, `"right"`, `"space-between"`) | +| `style` | `SignatureStyle` | `"line"` | Visual style: `"line"` (underline divider), `"box"` (bordered card), `"clean"` (borderless) | +| `borderColor` | `string` | `"#CBD5E1"` | Color of the separator line or bounding box border | +| `titleColor` | `string` | `"#64748B"` | Color of the title label (e.g. "Prepared by") | +| `nameColor` | `string` | `"#0F172A"` | Color of the signatory name | +| `roleColor` | `string` | `"#64748B"` | Color of the role and date labels | +| `spacingBefore` | `string \| number` | `"2.5rem"` | Top spacing before the signature block | + +### `SignatureItem` Properties + +| Property | Type | Description | +| :--- | :--- | :--- | +| `title` | `string` | Title or sign-off label above signature (e.g. `"Prepared by"`, `"Approved by"`) | +| `name` | `string` | Signatory person name (supports metadata tokens like `{author}`) | +| `role` | `string` | Signatory job title, role, or department (e.g. `"Lead Platform Architect"`) | +| `date` | `string \| boolean` | Date string, `{date}` token, or `true` for auto-formatted current date | +| `image` | `string` | Optional signature image path, URL, or Base64 data URI (digital seal or handwritten signature) | +| `signatureHeight` | `number \| string` | Blank height reserved for physical handwriting signature (default: `60px`) | + +### Frontmatter Quick Definition + +Signatures can also be defined directly inside document frontmatter: + +```markdown +--- +title: "Service Level Agreement" +author: "Ma'sum" +signatures: + align: right + style: box + items: + - title: "Authorized Signature" + name: "{author}" + role: "Lead Platform Architect" + date: true +--- +``` diff --git a/apps/docs/src/content/docs/markforge/index.mdx b/apps/docs/src/content/docs/markforge/index.mdx index 8c714ab..9e03cae 100644 --- a/apps/docs/src/content/docs/markforge/index.mdx +++ b/apps/docs/src/content/docs/markforge/index.mdx @@ -11,22 +11,22 @@ import { Card, CardGrid } from '@astrojs/starlight/components'; **MarkForge** is an enterprise-grade Markdown & MDX document publishing engine and CLI. It compiles a single Markdown source into pixel-perfect **Microsoft Word (DOCX)**, **PDF**, and **standalone HTML** — with native Mermaid diagrams, GitHub-style callout alert boxes, dual-theme syntax highlighting, customizable `ThemeProps`, per-zone header/footer slots, and an interactive Ink terminal UI. - + Generate `.docx`, `.pdf`, and `.html` simultaneously from a single Markdown source. - + Flagship cyan corporate design system + full custom colors and fonts via `ThemeProps`. - + Granular color, font size, font family, bold, and italic controls per `left`, `center`, and `right` slot. - + Flowcharts, sequence diagrams, gantt charts, and class diagrams — rendered and embedded natively. - + GitHub-style `> [!NOTE]`, `> [!TIP]`, `> [!IMPORTANT]`, `> [!WARNING]`, `> [!CAUTION]` with rich colored styling. - + Dark theme for PDF/HTML, Light theme for DOCX — optimized per document format. @@ -37,23 +37,24 @@ import { Card, CardGrid } from '@astrojs/starlight/components'; | Element | DOCX | PDF | HTML | | :--- | :---: | :---: | :---: | -| Headings H1–H6 | ✅ | ✅ | ✅ | -| Paragraphs & inline formatting | ✅ | ✅ | ✅ | -| GFM Tables | ✅ | ✅ | ✅ | -| Ordered & unordered lists | ✅ | ✅ | ✅ | -| Checklists (`- [x]`) | ✅ | ✅ | ✅ | -| Blockquotes | ✅ | ✅ | ✅ | -| **Callout / Alert Boxes** | ✅ | ✅ | ✅ | -| Code blocks (syntax highlighted) | ✅ | ✅ | ✅ | -| Inline code | ✅ | ✅ | ✅ | -| **Mermaid Diagrams** | ✅ | ✅ | ✅ | -| Images (local / URL / Base64) | ✅ | ✅ | ✅ | -| Horizontal rules | ✅ | ✅ | ✅ | -| Bold, italic, strikethrough | ✅ | ✅ | ✅ | -| Auto Table of Contents | ✅ | ✅ | ✅ | -| **Header & Footer (per-zone slots)** | ✅ | ✅ | — | -| Embedded ` ${watermarkHtml}
-${bodyHtml}
+${bodyHtml}${signaturesHtml} ${mermaidScript} `; diff --git a/packages/markforge/src/index.ts b/packages/markforge/src/index.ts index 9df4444..2149bdb 100644 --- a/packages/markforge/src/index.ts +++ b/packages/markforge/src/index.ts @@ -23,6 +23,7 @@ export { resolveDocumentConfig, replaceDocumentTokens, normalizeWatermark, + normalizeSignatures, normalizeHeaderFooter, normalizeHeaderFooterSlot, PAPER_DIMENSIONS_TWIP, @@ -33,6 +34,8 @@ export type { NormalizedWatermark, NormalizedHeaderFooter, NormalizedHeaderFooterZone, + NormalizedSignatureItem, + NormalizedSignatureBlock, } from "./config/resolveConfig.js"; export { OutputFormat, @@ -56,6 +59,10 @@ export type { DocumentLayoutConfig, FrontmatterMetadata, WatermarkOptions, + SignatureAlign, + SignatureStyle, + SignatureItem, + SignatureBlockConfig, GeneratedOutputFile, CompilationResult, } from "./config/types.js"; diff --git a/packages/markforge/src/ui/App.tsx b/packages/markforge/src/ui/App.tsx index f3bacf3..bf06a2e 100644 --- a/packages/markforge/src/ui/App.tsx +++ b/packages/markforge/src/ui/App.tsx @@ -41,9 +41,19 @@ export const App: React.FC = ({ inputFile, config, onComplete }) => { run(); }, [inputFile, config, onComplete]); + const targetFormats = Array.isArray(config.to) + ? (config.to as string[]) + : config.to + ? [String(config.to)] + : ["docx", "pdf"]; + return ( -
+
diff --git a/packages/markforge/src/ui/Header.tsx b/packages/markforge/src/ui/Header.tsx index 02dae70..91011f5 100644 --- a/packages/markforge/src/ui/Header.tsx +++ b/packages/markforge/src/ui/Header.tsx @@ -1,16 +1,32 @@ import React from "react"; +import * as path from "node:path"; import { Box, Text } from "ink"; import { MARKFORGE_VERSION } from "../version.js"; - import type { MarkforgeTheme } from "../config/types.js"; export interface HeaderProps { inputFile?: string; theme?: MarkforgeTheme; + targetFormats?: string[]; +} + +function formatDisplayPath(p?: string): string { + if (!p) return ""; + try { + const rel = path.relative(process.cwd(), p); + return rel && !rel.startsWith("..") && rel.length < p.length ? `./${rel}` : p; + } catch { + return p; + } } -export const Header: React.FC = ({ inputFile, theme = "corporate" }) => { - const themeLabel = typeof theme === "object" ? "custom (ThemeProps)" : String(theme || "corporate"); +export const Header: React.FC = ({ + inputFile, + theme = "corporate", + targetFormats = ["docx", "pdf"], +}) => { + const themeLabel = + typeof theme === "object" ? "Custom (ThemeProps)" : String(theme || "corporate"); return ( @@ -18,26 +34,68 @@ export const Header: React.FC = ({ inputFile, theme = "corporate" } borderStyle="round" borderColor="cyan" paddingX={2} - paddingY={0} + paddingY={1} flexDirection="column" > - - - MARKFORGE DOCUMENT ENGINE - - v{MARKFORGE_VERSION} + {/* Top Header Row */} + + + + MARKFORGE + + | Document Publishing Engine + + + + {" "}v{MARKFORGE_VERSION}{" "} + + - {inputFile && ( - - Source: - - {inputFile} + + {/* Source & Configuration Info */} + + {inputFile && ( + + Source: + + {formatDisplayPath(inputFile)} + + + )} + + + + Theme: + + {themeLabel} + + + {targetFormats && targetFormats.length > 0 && ( + + Targets: + + {targetFormats.map((f) => f.toUpperCase()).join(", ")} + + + )} + + + + {/* Author & GitHub Footer in Header Box */} + + + Author: + + Ma'sum + + (@masumrpg) + + + GitHub: + + https://github.com/masumrpg - )} - - Theme: - {themeLabel} diff --git a/packages/markforge/src/ui/SummaryTable.tsx b/packages/markforge/src/ui/SummaryTable.tsx index 6838413..892dd31 100644 --- a/packages/markforge/src/ui/SummaryTable.tsx +++ b/packages/markforge/src/ui/SummaryTable.tsx @@ -1,4 +1,5 @@ import React from "react"; +import * as path from "node:path"; import { Box, Text } from "ink"; import type { CompilationResult } from "../config/types.js"; @@ -14,6 +15,16 @@ export function formatBytes(bytes: number): string { return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`; } +function formatDisplayPath(p?: string): string { + if (!p) return ""; + try { + const rel = path.relative(process.cwd(), p); + return rel && !rel.startsWith("..") && rel.length < p.length ? `./${rel}` : p; + } catch { + return p; + } +} + export const SummaryTable: React.FC = ({ result }) => { if (!result) return null; @@ -28,28 +39,59 @@ export const SummaryTable: React.FC = ({ result }) => { paddingY={1} flexDirection="column" > - - - {hasErrors ? "[COMPILATION ERRORS]" : "[COMPILATION SUCCESSFUL]"} - - {result.durationMs}ms + {/* Status header */} + + + + {hasErrors ? "[COMPILATION FAILED]" : "[COMPILATION SUCCESSFUL]"} + + + + Duration: + + {result.durationMs}ms + + - - - Output Documents ({result.files.length}): - - {result.files.map((f, i) => ( - - - [{f.format.toUpperCase()}] - {f.filePath} - - {formatBytes(f.sizeBytes)} - - ))} - + {/* Output Documents List */} + {result.files.length > 0 && ( + + + Generated Documents ({result.files.length}): + + {result.files.map((f, i) => { + const formatColor = + f.format === "docx" ? "blue" : f.format === "pdf" ? "red" : "yellow"; + const paddedBadge = `[${f.format.toUpperCase()}]`.padEnd(7, " "); + return ( + + + + + {paddedBadge} + + + {f.fileName} + + + + {formatBytes(f.sizeBytes)} + + + + + └─ {formatDisplayPath(f.filePath)} + + + + ); + })} + + )} + + {/* Errors list */} {hasErrors && ( @@ -62,6 +104,23 @@ export const SummaryTable: React.FC = ({ result }) => { ))} )} + + {/* Bottom credits */} + + + Author: + + Ma'sum + + (@masumrpg) + + + GitHub: + + https://github.com/masumrpg + + + ); diff --git a/packages/markforge/src/version.ts b/packages/markforge/src/version.ts index bbb4f5b..9511b08 100644 --- a/packages/markforge/src/version.ts +++ b/packages/markforge/src/version.ts @@ -26,7 +26,7 @@ try { } /** Hardcoded fallback — only used if package.json cannot be found at runtime. */ -const FALLBACK_VERSION = "0.2.2"; +const FALLBACK_VERSION = "0.3.0"; /** * Walks up the directory tree from `fromDir` to find the nearest diff --git a/packages/markforge/test/allProperties.test.ts b/packages/markforge/test/allProperties.test.ts index d7eee83..a997217 100644 --- a/packages/markforge/test/allProperties.test.ts +++ b/packages/markforge/test/allProperties.test.ts @@ -25,7 +25,7 @@ describe("All Properties Comprehensive Test Suite", () => { const fullMarkdown = `--- title: "Unified Platform Architecture" subtitle: "High-Performance Document Engine" -author: "Masum RPG" +author: "Ma'sum" date: "2026-08-29" version: "1.0.0" company: "Masum Dev" @@ -108,7 +108,7 @@ export function initializeEngine(): EngineConfig { // Metadata & Dynamic tokens expect(resolved.title).toBe("Unified Platform Architecture"); expect(resolved.subtitle).toBe("High-Performance Document Engine"); - expect(resolved.author).toBe("Masum RPG"); + expect(resolved.author).toBe("Ma'sum"); expect(resolved.date).toBe("2026-08-29"); expect(resolved.version).toBe("1.0.0"); expect(resolved.company).toBe("Masum Dev"); @@ -135,7 +135,7 @@ export function initializeEngine(): EngineConfig { expect(resolved.header?.right?.text).toBe("v1.0.0"); // Footers with replaced tokens - expect(resolved.footer?.left?.text).toBe("Author: Masum RPG"); + expect(resolved.footer?.left?.text).toBe("Author: Ma'sum"); // Table of Contents & Watermark expect(resolved.toc).toBe(true); @@ -169,7 +169,7 @@ export function initializeEngine(): EngineConfig { // Header metadata area expect(html).toContain('

Unified Platform Architecture

'); expect(html).toContain('
High-Performance Document Engine
'); - expect(html).toContain("Author: Masum RPG"); + expect(html).toContain("Author: Ma'sum"); expect(html).toContain("Version: 1.0.0"); expect(html).toContain("Date: 2026-08-29"); @@ -182,13 +182,11 @@ export function initializeEngine(): EngineConfig { expect(html).toContain(".custom-brand { color: #33CDCF; font-weight: bold; }"); expect(html).toContain('
Verified with Custom Brand CSS
'); - // Watermark CSS & Element + // Watermark CSS & Canvas Bitmap Element expect(html).toContain(".document-watermark"); + expect(html).toContain("markforge-watermark"); expect(html).toContain("STRICTLY CONFIDENTIAL"); - expect(html).toContain("color: #E11D48"); - expect(html).toContain("opacity: 0.15"); - expect(html).toContain("rotate(-35deg)"); - expect(html).toContain("font-size: 48pt"); + expect(html).toContain("#E11D48"); // Callout boxes with color styling expect(html).toContain("callout-NOTE"); @@ -253,5 +251,55 @@ export function initializeEngine(): EngineConfig { expect(fs.existsSync(pdfFile!.filePath)).toBe(true); expect(fs.existsSync(htmlFile!.filePath)).toBe(true); }); + + it("6. renders signature & approval block across DOCX, PDF, and HTML correctly", async () => { + const mdWithSignatures = `--- +title: "Approved Contract Specification" +author: "Ma'sum" +signatures: + align: "space-between" + style: "line" + items: + - title: "Prepared by" + name: "{author}" + role: "Lead Platform Architect" + date: "2026-08-29" + - title: "Approved by" + name: "Alex Johnson" + role: "Chief Technology Officer" + date: true +--- + +# Contract Overview +This document contains formal signature approval blocks. +`; + + const doc = parseMarkdownDocument(mdWithSignatures); + const resolved = resolveDocumentConfig(doc.metadata, {}); + + expect(resolved.signatures).toBeDefined(); + expect(resolved.signatures?.items.length).toBe(2); + expect(resolved.signatures?.items[0].name).toBe("Ma'sum"); + expect(resolved.signatures?.items[1].name).toBe("Alex Johnson"); + + // HTML Output Verification + const html = await buildHtmlDocument(doc, resolved); + expect(html).toContain("markforge-signatures"); + expect(html).toContain("Prepared by"); + expect(html).toContain("Approved by"); + expect(html).toContain("Ma'sum"); + expect(html).toContain("Alex Johnson"); + expect(html).toContain("Chief Technology Officer"); + + // DOCX Output Verification + const docxBuf = await buildDocxDocument(doc, resolved); + expect(docxBuf).toBeInstanceOf(Buffer); + expect(docxBuf.length).toBeGreaterThan(1000); + + // PDF Output Verification + const pdfBuf = await buildPdfDocument(doc, resolved); + expect(pdfBuf).toBeInstanceOf(Buffer); + expect(pdfBuf.subarray(0, 5).toString()).toBe("%PDF-"); + }); }); diff --git a/packages/markforge/test/config.test.ts b/packages/markforge/test/config.test.ts index 1cb4f3b..fcd8c54 100644 --- a/packages/markforge/test/config.test.ts +++ b/packages/markforge/test/config.test.ts @@ -156,6 +156,33 @@ describe("config", () => { expect(resolved.header?.left?.text).toBe("Frontmatter Title"); // token replaced! expect(resolved.header?.right?.text).toBe("Monorepo Team"); // token replaced! expect(resolved.watermark?.text).toBe("DRAFT"); + + // 4. Signatures normalization & resolution test + const { normalizeSignatures } = await import("../src/config/resolveConfig.js"); + const sigResolved = normalizeSignatures( + { + align: "right", + style: "box", + items: [ + { + title: "Approved by", + name: "{author}", + role: "Chief Architect", + date: "2026-08-29", + }, + ], + }, + { author: "Ma'sum" } + ); + + expect(sigResolved).toBeDefined(); + expect(sigResolved?.align).toBe("right"); + expect(sigResolved?.style).toBe("box"); + expect(sigResolved?.items.length).toBe(1); + expect(sigResolved?.items[0].name).toBe("Ma'sum"); + expect(sigResolved?.items[0].title).toBe("Approved by"); + expect(sigResolved?.items[0].role).toBe("Chief Architect"); + expect(sigResolved?.items[0].date).toBe("2026-08-29"); }); }); diff --git a/packages/markforge/test/mermaidAndWatermark.test.ts b/packages/markforge/test/mermaidAndWatermark.test.ts index fcd917c..c4ee9c1 100644 --- a/packages/markforge/test/mermaidAndWatermark.test.ts +++ b/packages/markforge/test/mermaidAndWatermark.test.ts @@ -29,9 +29,9 @@ describe("Mermaid & Watermark Engine", () => { }, }); expect(html).toContain("document-watermark"); + expect(html).toContain("markforge-watermark"); expect(html).toContain("INTERNAL ONLY"); expect(html).toContain("#33CDCF"); - expect(html).toContain("rotate(-30deg)"); }); it("renders mermaid in HTML with mermaid script loader", async () => { diff --git a/packages/rn-qr-code/README.md b/packages/rn-qr-code/README.md index b44cfae..28c0de5 100644 --- a/packages/rn-qr-code/README.md +++ b/packages/rn-qr-code/README.md @@ -103,4 +103,4 @@ import { Skeleton } from "@masumdev/rn-ui"; ## License -MIT © [Ma'sum](https://github.com/masumdev) +MIT © [Ma'sum](https://github.com/masumrpg)