Files
skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples.cs
shihao 6487becf60 Initial commit: add all skills files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 16:52:49 +08:00

1833 lines
76 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================================
// AestheticRecipeSamples.cs — Complete aesthetic recipes for document styling
// ============================================================================
// Each recipe is a self-contained, coordinated design system where fonts,
// sizes, spacing, colors, margins, and table styles all work in harmony.
//
// DESIGN PHILOSOPHY: Beauty comes from harmony, not individual choices.
// A 14pt heading is not inherently good or bad — it depends on body size,
// line spacing, margins, and color all working together.
//
// UNIT REFERENCE:
// Font size: half-points (22 = 11pt, 24 = 12pt, 32 = 16pt)
// Spacing: DXA = twentieths of a point (1440 DXA = 1 inch)
// Borders: eighth-points (4 = 0.5pt, 8 = 1pt, 12 = 1.5pt)
// Line spacing "line": 240ths of single spacing (240 = 1.0x, 276 = 1.15x)
// ============================================================================
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using WpPageSize = DocumentFormat.OpenXml.Wordprocessing.PageSize;
namespace MiniMaxAIDocx.Core.Samples;
/// <summary>
/// Complete aesthetic recipes — coordinated design systems where all parameters
/// work together. Each recipe is a full document style that can be applied as-is.
///
/// DESIGN PHILOSOPHY: Beauty comes from harmony, not individual choices.
/// A 14pt heading is not inherently good or bad — it depends on body size,
/// line spacing, margins, and color all working together.
///
/// These recipes encode tested, harmonious combinations.
/// </summary>
public static partial class AestheticRecipeSamples
{
// ════════════════════════════════════════════════════════════════════════
// RECIPE 1: MODERN CORPORATE
// ════════════════════════════════════════════════════════════════════════
/// <summary>
/// Recipe: Modern Corporate
/// Feel: Clean, confident, contemporary.
/// Best for: Business reports, proposals, internal documents.
///
/// Design rationale:
/// - 1.25x modular scale creates clear but not aggressive hierarchy
/// (body 11pt → H3 13pt → H2 16pt → H1 20pt, each step ~1.25x)
/// - Dark navy headings (#1F3864) convey authority without being harsh
/// - 1.15 line spacing is the sweet spot for sans-serif readability:
/// tight enough to look professional, open enough for comfortable scanning
/// - 8pt paragraph spacing creates rhythm without wasting vertical space
/// - Body text #333333 (not pure black) reduces eye strain on screens
/// - Sans-serif font family (Aptos/Calibri) signals modernity and clarity
/// - Light banded table rows (#F2F2F2) aid scanning without visual noise
/// </summary>
public static void CreateModernCorporateDocument(string outputPath)
{
using var doc = WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document);
var mainPart = doc.AddMainDocumentPart();
mainPart.Document = new Document(new Body());
var body = mainPart.Document.Body!;
// ── Styles ──
var stylesPart = mainPart.AddNewPart<StyleDefinitionsPart>();
stylesPart.Styles = new Styles();
var styles = stylesPart.Styles;
// DocDefaults: the foundation everything inherits from.
// Aptos is Word's new default (2023+); Calibri is the fallback for older systems.
styles.Append(new DocDefaults(
new RunPropertiesDefault(
new RunPropertiesBaseStyle(
new RunFonts
{
Ascii = "Aptos",
HighAnsi = "Aptos",
EastAsia = "SimSun",
ComplexScript = "Calibri"
},
new FontSize { Val = "22" }, // 11pt body default
new FontSizeComplexScript { Val = "22" },
new Color { Val = "333333" }, // Soft black — easier on eyes than #000000
new Languages { Val = "en-US", EastAsia = "zh-CN" }
)
),
new ParagraphPropertiesDefault(
new ParagraphPropertiesBaseStyle(
new SpacingBetweenLines
{
// 1.15x line spacing: the modern standard for sans-serif.
// 240 = single, so 276 = 1.15x. Word's default since 2013.
Line = "276",
LineRule = LineSpacingRuleValues.Auto,
After = "160" // 8pt after — enough rhythm, not too airy
}
)
)
));
// ── Normal style ──
styles.Append(CreateParagraphStyle(
styleId: "Normal",
styleName: "Normal",
isDefault: true,
uiPriority: 0
));
// ── Heading 1: 20pt Aptos Display, dark navy ──
// 20pt = 40 half-points. The 1.25x scale from 11pt body gives:
// 11 → 13.75 → 17.2 → 21.5. We round to 13, 16, 20 for clean numbers.
styles.Append(CreateHeadingStyle(
level: 1,
fontAscii: "Aptos Display",
fontHAnsi: "Aptos Display",
sizeHalfPts: "40", // 20pt
color: "1F3864", // Dark navy — authority without aggression
bold: false, // Large Display font doesn't need bold
spaceBefore: "480", // 24pt before — creates a clear section break
spaceAfter: "120", // 6pt after — tight coupling to content below
uiPriority: 9
));
// ── Heading 2: 16pt, dark navy, semi-bold ──
styles.Append(CreateHeadingStyle(
level: 2,
fontAscii: "Aptos Display",
fontHAnsi: "Aptos Display",
sizeHalfPts: "32", // 16pt
color: "1F3864",
bold: false,
spaceBefore: "360", // 18pt before
spaceAfter: "80", // 4pt after
uiPriority: 9
));
// ── Heading 3: 13pt, dark navy, bold ──
styles.Append(CreateHeadingStyle(
level: 3,
fontAscii: "Aptos",
fontHAnsi: "Aptos",
sizeHalfPts: "26", // 13pt
color: "1F3864",
bold: true, // Bold compensates for smaller size
spaceBefore: "240", // 12pt before
spaceAfter: "80", // 4pt after
uiPriority: 9
));
// ── ListBullet style ──
styles.Append(CreateParagraphStyle(
styleId: "ListBullet",
styleName: "List Bullet",
basedOn: "Normal",
uiPriority: 36
));
// ── Caption style: 9pt italic gray ──
styles.Append(CreateCaptionStyle(
fontSizeHalfPts: "18", // 9pt
color: "595959",
italic: true
));
// ── Page setup: Letter, 1in margins ──
// 1 inch = 1440 DXA. Letter = 8.5" x 11" = 12240 x 15840 DXA.
var sectPr = new SectionProperties(
new WpPageSize { Width = 12240U, Height = 15840U },
new PageMargin
{
Top = 1440, Bottom = 1440,
Left = 1440U, Right = 1440U,
Header = 720U, Footer = 720U, Gutter = 0U
}
);
// ── Page numbers: bottom right, 9pt gray ──
AddPageNumberFooter(mainPart, sectPr,
alignment: JustificationValues.Right,
fontSizeHalfPts: "18", // 9pt — subordinate to body text
color: "808080", // Gray — page numbers are reference, not content
format: PageNumberFormat.Plain
);
// ── Sample content ──
AddSampleParagraph(body, "Modern Corporate Report", "Heading1");
AddSampleParagraph(body, "This document demonstrates the Modern Corporate aesthetic. "
+ "The clean sans-serif typography, dark navy headings, and generous but not "
+ "excessive spacing create a professional appearance suitable for business contexts.",
"Normal");
AddSampleParagraph(body, "Executive Summary", "Heading2");
AddSampleParagraph(body, "Key findings from our analysis indicate strong performance "
+ "across all divisions. Revenue grew 12% year-over-year while maintaining healthy "
+ "margins. The integration of new systems has improved operational efficiency.",
"Normal");
AddSampleParagraph(body, "Detailed Findings", "Heading2");
AddSampleParagraph(body, "Revenue Analysis", "Heading3");
AddSampleParagraph(body, "Quarter-over-quarter growth remained consistent, with Q3 "
+ "showing particularly strong performance in the enterprise segment.",
"Normal");
// ── Table: light top/bottom borders, banded rows, no vertical lines ──
body.Append(CreateModernCorporateTable(
new[] { "Division", "Revenue", "Growth", "Margin" },
new[]
{
new[] { "Enterprise", "$45.2M", "+15%", "42%" },
new[] { "Mid-Market", "$28.7M", "+11%", "38%" },
new[] { "SMB", "$12.1M", "+8%", "35%" }
}
));
AddSampleParagraph(body, "Table 1: Division Performance Summary", "Caption");
// Section properties must be last child of body
body.Append(sectPr);
}
/// <summary>
/// Modern Corporate table aesthetic: horizontal lines only, banded rows.
/// Design: top and bottom borders frame the data. Header has a bottom border.
/// No vertical lines — the eye follows horizontal rows naturally.
/// Subtle #F2F2F2 banding on alternate rows aids scanning without adding noise.
/// </summary>
private static Table CreateModernCorporateTable(string[] headers, string[][] data)
{
var table = new Table();
// Table properties: full width, horizontal-only borders
var tblPr = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
new TableBorders(
new TopBorder { Val = BorderValues.Single, Size = 8, Space = 0, Color = "BFBFBF" },
new BottomBorder { Val = BorderValues.Single, Size = 8, Space = 0, Color = "BFBFBF" },
new LeftBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new RightBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
// Horizontal inside borders for row separation
new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "D9D9D9" },
// No vertical inside borders — cleaner look
new InsideVerticalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" }
),
// Cell padding: 28 DXA minimum each side for breathing room
new TableCellMarginDefault(
new TopMargin { Width = "28", Type = TableWidthUnitValues.Dxa },
new StartMargin { Width = "57", Type = TableWidthUnitValues.Dxa },
new BottomMargin { Width = "28", Type = TableWidthUnitValues.Dxa },
new EndMargin { Width = "57", Type = TableWidthUnitValues.Dxa }
)
);
table.Append(tblPr);
// Grid columns
var grid = new TableGrid();
int colWidth = 9360 / headers.Length;
foreach (var _ in headers)
grid.Append(new GridColumn { Width = colWidth.ToString() });
table.Append(grid);
// Header row
var headerRow = new TableRow();
foreach (var h in headers)
{
headerRow.Append(new TableCell(
new TableCellProperties(
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto },
// Header bottom border slightly heavier to separate from data
new TableCellBorders(
new BottomBorder { Val = BorderValues.Single, Size = 8, Space = 0, Color = "999999" }
)
),
new Paragraph(
new ParagraphProperties(
new SpacingBetweenLines { After = "0" }
),
new Run(
new RunProperties(new Bold()),
new Text(h)
)
)
));
}
table.Append(headerRow);
// Data rows with subtle banding
for (int i = 0; i < data.Length; i++)
{
var row = new TableRow();
foreach (var cell in data[i])
{
var tcPr = new TableCellProperties(
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto }
);
// Banded rows: every other row gets a very light gray background
// #F2F2F2 is subtle enough to not compete with content
if (i % 2 == 1)
{
tcPr.Append(new Shading
{
Val = ShadingPatternValues.Clear,
Color = "auto",
Fill = "F2F2F2"
});
}
row.Append(new TableCell(
tcPr,
new Paragraph(
new ParagraphProperties(
new SpacingBetweenLines { After = "0" }
),
new Run(new Text(cell))
)
));
}
table.Append(row);
}
return table;
}
// ════════════════════════════════════════════════════════════════════════
// RECIPE 2: ACADEMIC THESIS
// ════════════════════════════════════════════════════════════════════════
/// <summary>
/// Recipe: Academic Thesis (APA-style)
/// Feel: Traditional, scholarly, readable for sustained long-form reading.
/// Best for: Dissertations, research papers, academic reports.
///
/// Design rationale:
/// - Times New Roman 12pt: the universal academic standard, optimized for
/// print legibility at reading distance. Serif fonts aid reading flow in
/// long-form text by creating horizontal "rails" for the eye.
/// - APA-style headings: size is UNIFORM (all 12pt) — hierarchy is expressed
/// through bold, italic, centering, and indentation rather than size change.
/// This is intentional: in academic writing, the text IS the content, and
/// headings are navigational aids, not visual statements.
/// - Double spacing (480 line units): required by most style guides for
/// annotation/editing room. Also improves readability for dense content.
/// - 0.5in first-line indent, no paragraph spacing: the classical paragraph
/// separator. Space-after is a modern convention; indent is the scholarly one.
/// - Left margin 1.5in for binding: physical theses are bound on the left.
/// - Three-line table (三线表): the academic standard — top rule, header rule,
/// bottom rule. No vertical lines. Clean and information-focused.
/// </summary>
public static void CreateAcademicThesisDocument(string outputPath)
{
using var doc = WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document);
var mainPart = doc.AddMainDocumentPart();
mainPart.Document = new Document(new Body());
var body = mainPart.Document.Body!;
// ── Styles ──
var stylesPart = mainPart.AddNewPart<StyleDefinitionsPart>();
stylesPart.Styles = new Styles();
var styles = stylesPart.Styles;
// DocDefaults: Times New Roman 12pt, double spacing
styles.Append(new DocDefaults(
new RunPropertiesDefault(
new RunPropertiesBaseStyle(
new RunFonts
{
Ascii = "Times New Roman",
HighAnsi = "Times New Roman",
EastAsia = "SimSun",
ComplexScript = "Times New Roman"
},
new FontSize { Val = "24" }, // 12pt (in half-points)
new FontSizeComplexScript { Val = "24" },
new Color { Val = "000000" }, // Pure black — academic standard
new Languages { Val = "en-US", EastAsia = "zh-CN" }
)
),
new ParagraphPropertiesDefault(
new ParagraphPropertiesBaseStyle(
new SpacingBetweenLines
{
// Double spacing: 480 = 2.0x (240 = single)
// This is the fundamental academic formatting requirement
Line = "480",
LineRule = LineSpacingRuleValues.Auto,
After = "0" // No space after — use first-line indent instead
},
// First-line indent: 0.5in = 720 DXA
// The traditional paragraph separator in academic writing
new Indentation { FirstLine = "720" }
)
)
));
// ── Normal style ──
styles.Append(CreateParagraphStyle(
styleId: "Normal",
styleName: "Normal",
isDefault: true,
uiPriority: 0
));
// ── APA Heading 1: 12pt bold, centered ──
// APA Level 1: Centered, Bold, Title Case
// Note: ALL headings are 12pt — hierarchy through formatting, not size.
styles.Append(CreateAcademicHeadingStyle(
level: 1,
sizeHalfPts: "24", // 12pt — same as body
bold: true,
italic: false,
centered: true,
spaceBefore: "480", // One blank double-spaced line before
spaceAfter: "0"
));
// ── APA Heading 2: 12pt bold, left-aligned ──
// APA Level 2: Flush Left, Bold, Title Case
styles.Append(CreateAcademicHeadingStyle(
level: 2,
sizeHalfPts: "24", // 12pt — same as body
bold: true,
italic: false,
centered: false,
spaceBefore: "480",
spaceAfter: "0"
));
// ── APA Heading 3: 12pt bold italic, left-aligned ──
// APA Level 3: Flush Left, Bold Italic, Title Case
styles.Append(CreateAcademicHeadingStyle(
level: 3,
sizeHalfPts: "24", // 12pt — same as body
bold: true,
italic: true,
centered: false,
spaceBefore: "480",
spaceAfter: "0"
));
// ── ListBullet style ──
styles.Append(CreateParagraphStyle(
styleId: "ListBullet",
styleName: "List Bullet",
basedOn: "Normal",
uiPriority: 36
));
// ── Caption style ──
styles.Append(CreateCaptionStyle(
fontSizeHalfPts: "24", // 12pt — same as body (APA requirement)
color: "000000",
italic: true
));
// ── Page setup: Letter, 1in margins, 1.5in left for binding ──
var sectPr = new SectionProperties(
new WpPageSize { Width = 12240U, Height = 15840U },
new PageMargin
{
Top = 1440, Bottom = 1440,
Left = 2160U, // 1.5in for binding margin
Right = 1440U,
Header = 720U, Footer = 720U, Gutter = 0U
}
);
// ── Page numbers: top right (APA style) ──
AddPageNumberFooter(mainPart, sectPr,
alignment: JustificationValues.Right,
fontSizeHalfPts: "24", // 12pt — APA requires same size
color: "000000",
format: PageNumberFormat.Plain,
isHeader: true // APA puts page numbers in header
);
// ── Sample content ──
// Title page heading — no first-line indent
body.Append(new Paragraph(
new ParagraphProperties(
new ParagraphStyleId { Val = "Heading1" },
new Indentation { FirstLine = "0" } // Override indent for headings
),
new Run(new Text("The Effects of Typography on Reading Comprehension"))
));
AddAcademicParagraph(body, "This study examines the relationship between typographic "
+ "choices and reading comprehension in academic documents. Previous research has "
+ "established that serif fonts facilitate sustained reading in printed materials, "
+ "though recent evidence suggests this advantage diminishes on high-resolution screens.");
AddAcademicParagraph(body, "The present investigation extends this work by examining "
+ "how the interaction of font choice, line spacing, and margin width affects both "
+ "comprehension accuracy and reading speed across different document lengths.");
body.Append(new Paragraph(
new ParagraphProperties(
new ParagraphStyleId { Val = "Heading2" },
new Indentation { FirstLine = "0" }
),
new Run(new Text("Method"))
));
body.Append(new Paragraph(
new ParagraphProperties(
new ParagraphStyleId { Val = "Heading3" },
new Indentation { FirstLine = "0" }
),
new Run(new Text("Participants"))
));
AddAcademicParagraph(body, "A total of 120 undergraduate students (M age = 21.3, "
+ "SD = 2.1) participated in exchange for course credit. All participants reported "
+ "normal or corrected-to-normal vision.");
// ── Three-line table (三线表) ──
body.Append(CreateThreeLineTable(
new[] { "Condition", "n", "M (RT)", "SD", "Accuracy %" },
new[]
{
new[] { "Serif / Double", "30", "142.3", "18.7", "94.2" },
new[] { "Serif / Single", "30", "156.8", "21.3", "91.8" },
new[] { "Sans / Double", "30", "148.1", "19.4", "92.7" },
new[] { "Sans / Single", "30", "161.2", "23.1", "89.4" }
}
));
body.Append(sectPr);
}
/// <summary>
/// Three-line table (三线表): the gold standard for academic data presentation.
/// Only three horizontal lines: top rule (1.5pt), header-bottom rule (0.75pt),
/// bottom rule (1.5pt). No vertical lines whatsoever.
/// This style focuses the reader on the data, not the grid.
/// </summary>
private static Table CreateThreeLineTable(string[] headers, string[][] data)
{
var table = new Table();
// Table properties: three horizontal rules only
var tblPr = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
new TableBorders(
// Top rule: 1.5pt (Size=12 in eighth-points)
new TopBorder { Val = BorderValues.Single, Size = 12, Space = 0, Color = "000000" },
// Bottom rule: 1.5pt
new BottomBorder { Val = BorderValues.Single, Size = 12, Space = 0, Color = "000000" },
// No left, right, or inside borders
new LeftBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new RightBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new InsideHorizontalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new InsideVerticalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" }
),
new TableCellMarginDefault(
new TopMargin { Width = "28", Type = TableWidthUnitValues.Dxa },
new StartMargin { Width = "57", Type = TableWidthUnitValues.Dxa },
new BottomMargin { Width = "28", Type = TableWidthUnitValues.Dxa },
new EndMargin { Width = "57", Type = TableWidthUnitValues.Dxa }
)
);
table.Append(tblPr);
// Grid
var grid = new TableGrid();
int colWidth = 9360 / headers.Length;
foreach (var _ in headers)
grid.Append(new GridColumn { Width = colWidth.ToString() });
table.Append(grid);
// Header row: bottom border is the header rule (0.75pt = Size 6)
var headerRow = new TableRow();
foreach (var h in headers)
{
headerRow.Append(new TableCell(
new TableCellProperties(
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto },
new TableCellBorders(
new BottomBorder { Val = BorderValues.Single, Size = 6, Space = 0, Color = "000000" }
)
),
new Paragraph(
new ParagraphProperties(
new SpacingBetweenLines { After = "0", Line = "240", LineRule = LineSpacingRuleValues.Auto },
new Indentation { FirstLine = "0" },
new Justification { Val = JustificationValues.Center }
),
new Run(
new RunProperties(new Bold()),
new Text(h)
)
)
));
}
table.Append(headerRow);
// Data rows: no borders (only the table-level top/bottom apply)
foreach (var rowData in data)
{
var row = new TableRow();
foreach (var cell in rowData)
{
row.Append(new TableCell(
new TableCellProperties(
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto }
),
new Paragraph(
new ParagraphProperties(
new SpacingBetweenLines { After = "0", Line = "240", LineRule = LineSpacingRuleValues.Auto },
new Indentation { FirstLine = "0" },
new Justification { Val = JustificationValues.Center }
),
new Run(new Text(cell))
)
));
}
table.Append(row);
}
return table;
}
/// <summary>Helper to add a body paragraph with first-line indent (academic style).</summary>
private static void AddAcademicParagraph(Body body, string text)
{
body.Append(new Paragraph(
new ParagraphProperties(
new ParagraphStyleId { Val = "Normal" }
),
new Run(new Text(text))
));
}
// ════════════════════════════════════════════════════════════════════════
// RECIPE 3: EXECUTIVE BRIEF
// ════════════════════════════════════════════════════════════════════════
/// <summary>
/// Recipe: Executive Brief
/// Feel: Premium, minimal, high white-space.
/// Best for: Board summaries, investor updates, C-suite communications.
///
/// Design rationale:
/// - Georgia (serif) body with Helvetica Neue/Arial headings: the serif/sans
/// contrast creates natural visual hierarchy. Georgia was designed specifically
/// for screen readability while maintaining elegance.
/// - 1.4x line spacing (336 line units): more generous than corporate, reflecting
/// the premium feel. Executives scan quickly; more air helps their eyes jump.
/// - 10pt generous paragraph spacing: creates distinct "thought blocks" that
/// support quick scanning without deep reading.
/// - 1.25in margins: extra breathing room signals "we can afford to waste paper."
/// White space IS the luxury. Content-to-margin ratio conveys status.
/// - #2C3E50 (dark blue-gray) for all text: sophisticated alternative to black.
/// Warm enough to not feel clinical, dark enough for print legibility.
/// - #E74C3C accent red: used sparingly for table headers, creates a single
/// focal point. The contrast draws the eye to data.
/// - Dark header table style: inverted header row makes the table structure
/// immediately scannable even in peripheral vision.
/// </summary>
public static void CreateExecutiveBriefDocument(string outputPath)
{
using var doc = WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document);
var mainPart = doc.AddMainDocumentPart();
mainPart.Document = new Document(new Body());
var body = mainPart.Document.Body!;
// ── Styles ──
var stylesPart = mainPart.AddNewPart<StyleDefinitionsPart>();
stylesPart.Styles = new Styles();
var styles = stylesPart.Styles;
// DocDefaults: Georgia 11pt, generous spacing
styles.Append(new DocDefaults(
new RunPropertiesDefault(
new RunPropertiesBaseStyle(
new RunFonts
{
// Georgia: designed by Matthew Carter for Microsoft.
// Optimized for screen clarity while retaining serif elegance.
Ascii = "Georgia",
HighAnsi = "Georgia",
EastAsia = "SimSun",
ComplexScript = "Arial"
},
new FontSize { Val = "22" }, // 11pt
new FontSizeComplexScript { Val = "22" },
new Color { Val = "2C3E50" }, // Dark blue-gray — sophisticated
new Languages { Val = "en-US", EastAsia = "zh-CN" }
)
),
new ParagraphPropertiesDefault(
new ParagraphPropertiesBaseStyle(
new SpacingBetweenLines
{
// 1.4x line spacing: the "executive reading" sweet spot.
// More air than corporate (1.15), less than academic (2.0).
// Facilitates scanning behavior common in executive reading.
Line = "336",
LineRule = LineSpacingRuleValues.Auto,
After = "200" // 10pt after — generous blocks
}
)
)
));
// ── Normal style ──
styles.Append(CreateParagraphStyle(
styleId: "Normal",
styleName: "Normal",
isDefault: true,
uiPriority: 0
));
// ── Heading 1: 22pt Helvetica Neue/Arial, bold ──
// Serif body + sans heading = natural hierarchy through font contrast
styles.Append(CreateHeadingStyle(
level: 1,
fontAscii: "Helvetica Neue",
fontHAnsi: "Helvetica Neue",
sizeHalfPts: "44", // 22pt
color: "2C3E50",
bold: false, // Large size is enough; bold would be heavy
spaceBefore: "480",
spaceAfter: "120",
uiPriority: 9
));
// ── Heading 2: 16pt Helvetica Neue/Arial ──
styles.Append(CreateHeadingStyle(
level: 2,
fontAscii: "Helvetica Neue",
fontHAnsi: "Helvetica Neue",
sizeHalfPts: "32", // 16pt
color: "2C3E50",
bold: false,
spaceBefore: "360",
spaceAfter: "80",
uiPriority: 9
));
// ── Heading 3: 12pt Helvetica Neue/Arial, bold ──
styles.Append(CreateHeadingStyle(
level: 3,
fontAscii: "Helvetica Neue",
fontHAnsi: "Helvetica Neue",
sizeHalfPts: "24", // 12pt
color: "2C3E50",
bold: true,
spaceBefore: "240",
spaceAfter: "80",
uiPriority: 9
));
// ── ListBullet style ──
styles.Append(CreateParagraphStyle(
styleId: "ListBullet",
styleName: "List Bullet",
basedOn: "Normal",
uiPriority: 36
));
// ── Caption style ──
styles.Append(CreateCaptionStyle(
fontSizeHalfPts: "18", // 9pt
color: "7F8C8D",
italic: true
));
// ── Page setup: Letter, 1.25in margins ──
// Extra-wide margins = premium feel. The white space says "confidence."
var sectPr = new SectionProperties(
new WpPageSize { Width = 12240U, Height = 15840U },
new PageMargin
{
Top = 1800, Bottom = 1800, // 1.25in
Left = 1800U, Right = 1800U, // 1.25in
Header = 720U, Footer = 720U, Gutter = 0U
}
);
// ── Page numbers: bottom center, 8pt ──
AddPageNumberFooter(mainPart, sectPr,
alignment: JustificationValues.Center,
fontSizeHalfPts: "16", // 8pt — nearly invisible, as intended
color: "BFBFBF", // Very light gray — page numbers are utility
format: PageNumberFormat.Plain
);
// ── Sample content ──
AddSampleParagraph(body, "Q3 Performance Summary", "Heading1");
AddSampleParagraph(body, "Revenue exceeded targets across all segments. The strategic "
+ "realignment initiated in Q1 is now delivering measurable results. Key metrics "
+ "are trending positively with strong forward indicators.",
"Normal");
AddSampleParagraph(body, "Key Metrics", "Heading2");
AddSampleParagraph(body, "The following table summarizes performance against targets. "
+ "All figures are in millions USD unless otherwise noted.",
"Normal");
// ── Executive table: dark header row (#2C3E50 + white text), no other borders ──
body.Append(CreateExecutiveTable(
new[] { "Metric", "Target", "Actual", "Variance" },
new[]
{
new[] { "Revenue", "$52.0M", "$54.8M", "+5.4%" },
new[] { "EBITDA", "$12.5M", "$13.1M", "+4.8%" },
new[] { "Net Margin", "24%", "23.9%", "-0.1pp" }
}
));
AddSampleParagraph(body, "Strategic Outlook", "Heading2");
AddSampleParagraph(body, "Market conditions remain favorable heading into Q4. "
+ "The pipeline is robust with several high-value opportunities expected to close "
+ "before year-end.",
"Normal");
AddSampleParagraph(body, "Risk Factors", "Heading3");
AddSampleParagraph(body, "Currency headwinds and supply chain constraints represent "
+ "the primary downside risks. Mitigation strategies are in place for both scenarios.",
"Normal");
body.Append(sectPr);
}
/// <summary>
/// Executive table style: dark header row with white text, no other borders.
/// The inverted header creates immediate scanability. The borderless body
/// lets data breathe. This is the "less is more" school of data presentation.
/// </summary>
private static Table CreateExecutiveTable(string[] headers, string[][] data)
{
var table = new Table();
var tblPr = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
// No table-level borders at all — the header shading does the work
new TableBorders(
new TopBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new BottomBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new LeftBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new RightBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "E0E0E0" },
new InsideVerticalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" }
),
new TableCellMarginDefault(
new TopMargin { Width = "57", Type = TableWidthUnitValues.Dxa },
new StartMargin { Width = "85", Type = TableWidthUnitValues.Dxa },
new BottomMargin { Width = "57", Type = TableWidthUnitValues.Dxa },
new EndMargin { Width = "85", Type = TableWidthUnitValues.Dxa }
)
);
table.Append(tblPr);
// Grid
var grid = new TableGrid();
int colWidth = 9360 / headers.Length;
foreach (var _ in headers)
grid.Append(new GridColumn { Width = colWidth.ToString() });
table.Append(grid);
// Header row: dark background (#2C3E50) + white text
var headerRow = new TableRow();
foreach (var h in headers)
{
headerRow.Append(new TableCell(
new TableCellProperties(
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto },
new Shading
{
Val = ShadingPatternValues.Clear,
Color = "auto",
Fill = "2C3E50" // Dark blue-gray header
},
// Override borders for header cells
new TableCellBorders(
new TopBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new BottomBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new LeftBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new RightBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" }
)
),
new Paragraph(
new ParagraphProperties(
new SpacingBetweenLines { After = "0" }
),
new Run(
new RunProperties(
new Bold(),
new Color { Val = "FFFFFF" }, // White text on dark header
new RunFonts { Ascii = "Helvetica Neue", HighAnsi = "Helvetica Neue" }
),
new Text(h)
)
)
));
}
table.Append(headerRow);
// Data rows: clean, no borders (only inside-H from table properties)
foreach (var rowData in data)
{
var row = new TableRow();
foreach (var cell in rowData)
{
row.Append(new TableCell(
new TableCellProperties(
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto }
),
new Paragraph(
new ParagraphProperties(
new SpacingBetweenLines { After = "0" }
),
new Run(new Text(cell))
)
));
}
table.Append(row);
}
return table;
}
// ════════════════════════════════════════════════════════════════════════
// RECIPE 4: CHINESE GOVERNMENT (公文 GB/T 9704)
// ════════════════════════════════════════════════════════════════════════
/// <summary>
/// Recipe: Chinese Government Document (公文)
/// Feel: Formal, standardized, authoritative.
/// Best for: Government announcements, official communications, regulatory documents.
///
/// Design rationale (based on GB/T 9704-2012 standard):
/// - 仿宋_GB2312 三号 (16pt): the mandated body font. FangSong is a calligraphic
/// style that balances formality with readability in Chinese typography.
/// - 小标宋 二号 (22pt): the mandated title font. 小标宋体 is a specialized display
/// serif used exclusively in government documents for titles.
/// - Fixed 28pt line spacing (line="560"): government standard ensures uniform
/// page density of 22 lines per page. Every page looks identical.
/// - Margins T:37mm B:35mm L:28mm R:26mm: per GB/T 9704 specification.
/// Asymmetric left-right margins account for binding.
/// - Page size A4: Chinese government standard (unlike US Letter).
/// - All black text, no decorative elements: government documents derive
/// authority from standardization, not from visual design.
/// - Page numbers: bottom center, "-X-" format (e.g., "-3-") per standard.
/// - 28 chars per line, 22 lines per page: the density specification.
/// </summary>
public static void CreateChineseGovernmentDocument(string outputPath)
{
using var doc = WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document);
var mainPart = doc.AddMainDocumentPart();
mainPart.Document = new Document(new Body());
var body = mainPart.Document.Body!;
// ── Styles ──
var stylesPart = mainPart.AddNewPart<StyleDefinitionsPart>();
stylesPart.Styles = new Styles();
var styles = stylesPart.Styles;
// DocDefaults: 仿宋 16pt (三号), fixed 28pt line spacing
styles.Append(new DocDefaults(
new RunPropertiesDefault(
new RunPropertiesBaseStyle(
new RunFonts
{
// 仿宋_GB2312 is the standard; 仿宋 is the fallback on modern systems
Ascii = "FangSong",
HighAnsi = "FangSong",
EastAsia = "FangSong_GB2312",
ComplexScript = "FangSong"
},
new FontSize { Val = "32" }, // 16pt = 三号 (in half-points)
new FontSizeComplexScript { Val = "32" },
new Color { Val = "000000" },
new Languages { Val = "en-US", EastAsia = "zh-CN" }
)
),
new ParagraphPropertiesDefault(
new ParagraphPropertiesBaseStyle(
new SpacingBetweenLines
{
// Fixed 28pt line spacing per GB/T 9704
// 28pt * 20 = 560 DXA (line units in exact mode)
Line = "560",
LineRule = LineSpacingRuleValues.Exact,
After = "0",
Before = "0"
}
)
)
));
// ── Normal style ──
styles.Append(CreateParagraphStyle(
styleId: "Normal",
styleName: "Normal",
isDefault: true,
uiPriority: 0
));
// ── Title style (小标宋 二号 22pt) ──
// Government document title uses a specialized display serif font.
// 二号 = 22pt = 44 half-points.
var titleStyle = new Style(
new StyleName { Val = "heading 1" },
new BasedOn { Val = "Normal" },
new NextParagraphStyle { Val = "Normal" },
new UIPriority { Val = 9 },
new PrimaryStyle(),
new StyleParagraphProperties(
new KeepNext(),
new KeepLines(),
new Justification { Val = JustificationValues.Center },
new SpacingBetweenLines
{
Line = "560", LineRule = LineSpacingRuleValues.Exact,
Before = "0", After = "0"
},
new OutlineLevel { Val = 0 }
),
new StyleRunProperties(
new RunFonts
{
// 小标宋体 is the government standard for titles.
// Falls back to 华文中宋 or SimSun on systems without it.
Ascii = "SimSun",
HighAnsi = "SimSun",
EastAsia = "FZXiaoBiaoSong-B05S",
ComplexScript = "SimSun"
},
new FontSize { Val = "44" }, // 22pt = 二号
new FontSizeComplexScript { Val = "44" },
new Color { Val = "000000" }
)
)
{ Type = StyleValues.Paragraph, StyleId = "Heading1", Default = false };
styles.Append(titleStyle);
// ── Heading 2: 黑体 三号 (16pt) ──
// 黑体 (SimHei) is the standard sans-serif for first-level section headings.
var h2Style = new Style(
new StyleName { Val = "heading 2" },
new BasedOn { Val = "Normal" },
new NextParagraphStyle { Val = "Normal" },
new UIPriority { Val = 9 },
new PrimaryStyle(),
new StyleParagraphProperties(
new KeepNext(),
new KeepLines(),
new SpacingBetweenLines
{
Line = "560", LineRule = LineSpacingRuleValues.Exact,
Before = "0", After = "0"
},
new OutlineLevel { Val = 1 }
),
new StyleRunProperties(
new RunFonts
{
Ascii = "SimHei",
HighAnsi = "SimHei",
EastAsia = "SimHei",
ComplexScript = "SimHei"
},
new FontSize { Val = "32" }, // 16pt = 三号
new FontSizeComplexScript { Val = "32" },
new Color { Val = "000000" }
)
)
{ Type = StyleValues.Paragraph, StyleId = "Heading2", Default = false };
styles.Append(h2Style);
// ── Heading 3: 楷体 三号 (16pt) ──
// 楷体 (KaiTi) for second-level section headings.
var h3Style = new Style(
new StyleName { Val = "heading 3" },
new BasedOn { Val = "Normal" },
new NextParagraphStyle { Val = "Normal" },
new UIPriority { Val = 9 },
new PrimaryStyle(),
new StyleParagraphProperties(
new KeepNext(),
new KeepLines(),
new SpacingBetweenLines
{
Line = "560", LineRule = LineSpacingRuleValues.Exact,
Before = "0", After = "0"
},
new OutlineLevel { Val = 2 }
),
new StyleRunProperties(
new RunFonts
{
Ascii = "KaiTi",
HighAnsi = "KaiTi",
EastAsia = "KaiTi_GB2312",
ComplexScript = "KaiTi"
},
new FontSize { Val = "32" }, // 16pt = 三号
new FontSizeComplexScript { Val = "32" },
new Color { Val = "000000" }
)
)
{ Type = StyleValues.Paragraph, StyleId = "Heading3", Default = false };
styles.Append(h3Style);
// ── ListBullet style ──
styles.Append(CreateParagraphStyle(
styleId: "ListBullet",
styleName: "List Bullet",
basedOn: "Normal",
uiPriority: 36
));
// ── Caption style ──
styles.Append(CreateCaptionStyle(
fontSizeHalfPts: "32", // 三号 per standard
color: "000000",
italic: false // Chinese government docs do not use italic
));
// ── Page setup: A4, GB/T 9704 margins ──
// A4 = 210mm x 297mm = 11906 x 16838 DXA
// Margins per GB/T 9704: T:37mm B:35mm L:28mm R:26mm
// T: 37mm = 37 * 56.7 ≈ 2098 DXA
// B: 35mm = 35 * 56.7 ≈ 1984 DXA
// L: 28mm = 28 * 56.7 ≈ 1588 DXA
// R: 26mm = 26 * 56.7 ≈ 1474 DXA
var sectPr = new SectionProperties(
new WpPageSize { Width = 11906U, Height = 16838U },
new PageMargin
{
Top = 2098, Bottom = 1984,
Left = 1588U, Right = 1474U,
Header = 720U, Footer = 720U, Gutter = 0U
}
);
// ── Page numbers: bottom center, "-X-" format, 宋体 四号 (14pt) ──
AddPageNumberFooter(mainPart, sectPr,
alignment: JustificationValues.Center,
fontSizeHalfPts: "28", // 14pt = 四号
color: "000000",
format: PageNumberFormat.DashSurrounded, // -X- format
fontName: "SimSun" // 宋体 for page numbers
);
// ── Sample content ──
// Government document title
body.Append(new Paragraph(
new ParagraphProperties(
new ParagraphStyleId { Val = "Heading1" }
),
new Run(new Text("关于加强文档排版规范化管理的通知"))
));
// Body text
body.Append(new Paragraph(
new Run(new Text("各有关单位:") { Space = SpaceProcessingModeValues.Preserve })
));
body.Append(new Paragraph(
new ParagraphProperties(
new Indentation { FirstLine = "640" } // 2 Chinese characters = 640 DXA at 16pt
),
new Run(new Text("为进一步规范公文格式,提高公文质量,根据《党政机关公文格式》"
+ "GB/T 9704-2012的有关规定现就加强文档排版规范化管理有关事项通知如下。"))
));
body.Append(new Paragraph(
new ParagraphProperties(
new ParagraphStyleId { Val = "Heading2" }
),
new Run(new Text("一、总体要求"))
));
body.Append(new Paragraph(
new ParagraphProperties(
new Indentation { FirstLine = "640" }
),
new Run(new Text("各单位应严格按照国家标准规定的格式要求制作公文,"
+ "确保公文格式统一、规范、美观。公文用纸统一采用A4型纸"
+ "正文使用仿宋体三号字行间距为固定值28磅。"))
));
body.Append(new Paragraph(
new ParagraphProperties(
new ParagraphStyleId { Val = "Heading3" }
),
new Run(new Text("(一)字体要求"))
));
body.Append(new Paragraph(
new ParagraphProperties(
new Indentation { FirstLine = "640" }
),
new Run(new Text("标题使用小标宋体二号字,一级标题使用黑体三号字,"
+ "二级标题使用楷体三号字,正文使用仿宋体三号字。"))
));
// ── Three-line table (三线表 is also used in Chinese government documents) ──
body.Append(CreateThreeLineTable(
new[] { "项目", "要求", "字体", "字号" },
new[]
{
new[] { "标题", "居中", "小标宋体", "二号" },
new[] { "一级标题", "左对齐", "黑体", "三号" },
new[] { "二级标题", "左对齐", "楷体", "三号" },
new[] { "正文", "两端对齐", "仿宋体", "三号" }
}
));
body.Append(sectPr);
}
// ════════════════════════════════════════════════════════════════════════
// RECIPE 5: MINIMAL MODERN
// ════════════════════════════════════════════════════════════════════════
/// <summary>
/// Recipe: Minimal Modern
/// Feel: Scandinavian-inspired, lots of white space, geometric.
/// Best for: Design documents, creative briefs, tech company communications.
///
/// Design rationale:
/// - Inter/Segoe UI 10.5pt body: a geometric sans-serif designed for screens.
/// 10.5pt is slightly smaller than standard, creating a more designed, intentional
/// feel. The precision of geometric sans-serifs communicates clarity of thought.
/// - H1 24pt light weight: large but thin creates a "whisper, don't shout" hierarchy.
/// The size difference does the work; bold weight would be crude.
/// - 1.5x line spacing (360 line units): very generous. Combined with 10.5pt body,
/// this creates the characteristic "Scandinavian" feel of lots of air.
/// - 12pt paragraph spacing: each paragraph is a distinct visual block separated
/// by substantial white space. This supports the "one idea per paragraph" pattern.
/// - 1.5in left/right margins: extreme horizontal compression creates a narrow
/// text column (~5.5in wide, ~65 characters per line). This is the optimal
/// line length for comfortable reading (60-75 chars).
/// - #111111 headings, #444444 body: very slight differentiation. The hierarchy
/// comes from size and weight, not color. This is the "less contrast, more
/// sophistication" school.
/// - #0066CC accent blue: a single accent color for interactive elements or emphasis.
/// - Tables: header-only bottom border, nothing else. Maximum minimalism.
/// </summary>
public static void CreateMinimalModernDocument(string outputPath)
{
using var doc = WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document);
var mainPart = doc.AddMainDocumentPart();
mainPart.Document = new Document(new Body());
var body = mainPart.Document.Body!;
// ── Styles ──
var stylesPart = mainPart.AddNewPart<StyleDefinitionsPart>();
stylesPart.Styles = new Styles();
var styles = stylesPart.Styles;
// DocDefaults: Inter/Segoe UI 10.5pt, very generous spacing
styles.Append(new DocDefaults(
new RunPropertiesDefault(
new RunPropertiesBaseStyle(
new RunFonts
{
// Inter is a Google Fonts geometric sans-serif designed for screens.
// Segoe UI is the Windows system font fallback.
Ascii = "Inter",
HighAnsi = "Inter",
EastAsia = "Microsoft YaHei",
ComplexScript = "Segoe UI"
},
new FontSize { Val = "21" }, // 10.5pt — intentionally precise
new FontSizeComplexScript { Val = "21" },
new Color { Val = "444444" }, // Medium gray body — soft and modern
new Languages { Val = "en-US", EastAsia = "zh-CN" }
)
),
new ParagraphPropertiesDefault(
new ParagraphPropertiesBaseStyle(
new SpacingBetweenLines
{
// 1.5x line spacing: generous air for the minimal aesthetic.
// Combined with narrow column width, this creates comfortable reading.
Line = "360",
LineRule = LineSpacingRuleValues.Auto,
After = "240" // 12pt after — very generous paragraph separation
}
)
)
));
// ── Normal style ──
styles.Append(CreateParagraphStyle(
styleId: "Normal",
styleName: "Normal",
isDefault: true,
uiPriority: 0
));
// ── Heading 1: 24pt light ──
// "Light" weight creates elegant, airy hierarchy. The size alone does the work.
// Since OpenXML doesn't have a "light" weight, we achieve this by not using bold.
// On systems with Inter, the regular weight already appears relatively light.
styles.Append(CreateHeadingStyle(
level: 1,
fontAscii: "Inter",
fontHAnsi: "Inter",
sizeHalfPts: "48", // 24pt — large but not bold = "whispering loudly"
color: "111111", // Near-black — just barely softened
bold: false, // NO bold: the key to the minimal aesthetic
spaceBefore: "480",
spaceAfter: "120",
uiPriority: 9
));
// ── Heading 2: 16pt regular ──
styles.Append(CreateHeadingStyle(
level: 2,
fontAscii: "Inter",
fontHAnsi: "Inter",
sizeHalfPts: "32", // 16pt
color: "111111",
bold: false,
spaceBefore: "360",
spaceAfter: "80",
uiPriority: 9
));
// ── Heading 3: 12pt medium ──
// "Medium" is between regular and bold. We use bold here as the closest
// approximation in OpenXML (true medium weight requires theme fonts).
styles.Append(CreateHeadingStyle(
level: 3,
fontAscii: "Inter",
fontHAnsi: "Inter",
sizeHalfPts: "24", // 12pt
color: "111111",
bold: true, // Approximates "medium" weight
spaceBefore: "240",
spaceAfter: "80",
uiPriority: 9
));
// ── ListBullet style ──
styles.Append(CreateParagraphStyle(
styleId: "ListBullet",
styleName: "List Bullet",
basedOn: "Normal",
uiPriority: 36
));
// ── Caption style ──
styles.Append(CreateCaptionStyle(
fontSizeHalfPts: "18", // 9pt
color: "999999",
italic: false // Minimal style avoids italic
));
// ── Page setup: Letter, wide left/right margins, normal top/bottom ──
// Wide L/R margins create a narrow text column (~5.5in = ~65 chars per line).
// This is the optimal line length for comfortable reading.
var sectPr = new SectionProperties(
new WpPageSize { Width = 12240U, Height = 15840U },
new PageMargin
{
Top = 1440, Bottom = 1440, // 1in top/bottom
Left = 2160U, Right = 2160U, // 1.5in left/right — narrow column
Header = 720U, Footer = 720U, Gutter = 0U
}
);
// ── No page numbers for the minimal aesthetic ──
// In production, add page numbers only if document exceeds 5 pages.
// For this sample, we omit them entirely — the cleanest look.
// ── Sample content ──
AddSampleParagraph(body, "Design System", "Heading1");
AddSampleParagraph(body, "A design system is a collection of reusable components "
+ "and clear standards that can be assembled to build any number of applications. "
+ "It reduces redundancy, creates consistency, and enables teams to build faster.",
"Normal");
AddSampleParagraph(body, "Typography", "Heading2");
AddSampleParagraph(body, "Typography is the foundation of any design system. "
+ "The type scale, spacing, and color choices establish the visual rhythm "
+ "that all other elements follow.",
"Normal");
AddSampleParagraph(body, "Type Scale", "Heading3");
AddSampleParagraph(body, "Our type scale uses a 1.5x ratio, creating clear "
+ "hierarchy without excessive size variation. Each level is visually distinct "
+ "yet feels part of a cohesive family.",
"Normal");
// ── Minimal table: header bottom border only ──
body.Append(CreateMinimalTable(
new[] { "Token", "Value", "Usage" },
new[]
{
new[] { "font-size-xs", "10.5pt", "Captions, metadata" },
new[] { "font-size-sm", "12pt", "Secondary text" },
new[] { "font-size-base", "10.5pt", "Body text" },
new[] { "font-size-lg", "16pt", "Section headings" },
new[] { "font-size-xl", "24pt", "Page titles" }
}
));
AddSampleParagraph(body, "Table 1 — Type scale tokens", "Caption");
AddSampleParagraph(body, "Color", "Heading2");
AddSampleParagraph(body, "Our palette is intentionally restrained. Two grays "
+ "for text hierarchy, one accent blue for interactive elements, and generous "
+ "white space as the primary design element.",
"Normal");
body.Append(sectPr);
}
/// <summary>
/// Minimal table: only the header row gets a bottom border.
/// Everything else is borderless. Maximum restraint.
/// The alignment and spacing do all the structural work.
/// </summary>
private static Table CreateMinimalTable(string[] headers, string[][] data)
{
var table = new Table();
var tblPr = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
// No borders at all at the table level
new TableBorders(
new TopBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new BottomBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new LeftBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new RightBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new InsideHorizontalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
new InsideVerticalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" }
),
new TableCellMarginDefault(
new TopMargin { Width = "40", Type = TableWidthUnitValues.Dxa },
new StartMargin { Width = "57", Type = TableWidthUnitValues.Dxa },
new BottomMargin { Width = "40", Type = TableWidthUnitValues.Dxa },
new EndMargin { Width = "57", Type = TableWidthUnitValues.Dxa }
)
);
table.Append(tblPr);
// Grid
var grid = new TableGrid();
int colWidth = 7920 / headers.Length; // narrower text area due to wide margins
foreach (var _ in headers)
grid.Append(new GridColumn { Width = colWidth.ToString() });
table.Append(grid);
// Header row: only element with a visible border (bottom only)
var headerRow = new TableRow();
foreach (var h in headers)
{
headerRow.Append(new TableCell(
new TableCellProperties(
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto },
new TableCellBorders(
// Single thin bottom border — the only line in the entire table
new BottomBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "CCCCCC" }
)
),
new Paragraph(
new ParagraphProperties(
new SpacingBetweenLines { After = "0" }
),
new Run(
new RunProperties(
new Color { Val = "111111" } // Slightly darker than body
),
new Text(h)
)
)
));
}
table.Append(headerRow);
// Data rows: completely borderless
foreach (var rowData in data)
{
var row = new TableRow();
foreach (var cell in rowData)
{
row.Append(new TableCell(
new TableCellProperties(
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto }
),
new Paragraph(
new ParagraphProperties(
new SpacingBetweenLines { After = "0" }
),
new Run(new Text(cell))
)
));
}
table.Append(row);
}
return table;
}
// ════════════════════════════════════════════════════════════════════════
// SHARED HELPER METHODS
// ════════════════════════════════════════════════════════════════════════
/// <summary>
/// Creates a basic paragraph style with minimal configuration.
/// Used for Normal, ListBullet, and other simple styles.
/// </summary>
private static Style CreateParagraphStyle(
string styleId,
string styleName,
bool isDefault = false,
string? basedOn = null,
int uiPriority = 0)
{
var style = new Style(
new StyleName { Val = styleName },
new UIPriority { Val = uiPriority },
new PrimaryStyle()
)
{
Type = StyleValues.Paragraph,
StyleId = styleId,
Default = isDefault ? true : false
};
if (basedOn != null)
style.Append(new BasedOn { Val = basedOn });
return style;
}
/// <summary>
/// Creates a heading style with full formatting configuration.
/// All heading styles are based on "Normal" (not chained H2→H1)
/// because each heading level has completely different formatting.
/// </summary>
private static Style CreateHeadingStyle(
int level,
string fontAscii,
string fontHAnsi,
string sizeHalfPts,
string color,
bool bold,
string spaceBefore,
string spaceAfter,
int uiPriority)
{
var rPr = new StyleRunProperties(
new RunFonts
{
Ascii = fontAscii,
HighAnsi = fontHAnsi,
EastAsia = "SimSun",
ComplexScript = fontAscii
},
new FontSize { Val = sizeHalfPts },
new FontSizeComplexScript { Val = sizeHalfPts },
new Color { Val = color }
);
if (bold)
rPr.Append(new Bold());
var style = new Style(
new StyleName { Val = $"heading {level}" },
new BasedOn { Val = "Normal" },
new NextParagraphStyle { Val = "Normal" },
new UIPriority { Val = uiPriority },
new PrimaryStyle(),
new StyleParagraphProperties(
new KeepNext(), // Don't orphan a heading at page bottom
new KeepLines(), // Don't split a heading across pages
new SpacingBetweenLines
{
Before = spaceBefore,
After = spaceAfter
},
new OutlineLevel { Val = level - 1 } // OutlineLevel is 0-based
),
rPr
)
{
Type = StyleValues.Paragraph,
StyleId = $"Heading{level}",
Default = false
};
return style;
}
/// <summary>
/// Creates an APA-style heading where hierarchy is expressed through
/// bold/italic/centering rather than font size changes.
/// All headings remain 12pt — the same as body text.
/// </summary>
private static Style CreateAcademicHeadingStyle(
int level,
string sizeHalfPts,
bool bold,
bool italic,
bool centered,
string spaceBefore,
string spaceAfter)
{
var rPr = new StyleRunProperties(
new RunFonts
{
Ascii = "Times New Roman",
HighAnsi = "Times New Roman",
EastAsia = "SimSun",
ComplexScript = "Times New Roman"
},
new FontSize { Val = sizeHalfPts },
new FontSizeComplexScript { Val = sizeHalfPts },
new Color { Val = "000000" }
);
if (bold)
rPr.Append(new Bold());
if (italic)
rPr.Append(new Italic());
var pPr = new StyleParagraphProperties(
new KeepNext(),
new KeepLines(),
new SpacingBetweenLines
{
Before = spaceBefore,
After = spaceAfter,
Line = "480",
LineRule = LineSpacingRuleValues.Auto
},
// No first-line indent for headings
new Indentation { FirstLine = "0" },
new OutlineLevel { Val = level - 1 }
);
if (centered)
pPr.Append(new Justification { Val = JustificationValues.Center });
var style = new Style(
new StyleName { Val = $"heading {level}" },
new BasedOn { Val = "Normal" },
new NextParagraphStyle { Val = "Normal" },
new UIPriority { Val = 9 },
new PrimaryStyle(),
pPr,
rPr
)
{
Type = StyleValues.Paragraph,
StyleId = $"Heading{level}",
Default = false
};
return style;
}
/// <summary>
/// Creates a Caption style used below tables and figures.
/// Captions are typically smaller and/or italic to visually subordinate them.
/// </summary>
private static Style CreateCaptionStyle(
string fontSizeHalfPts,
string color,
bool italic)
{
var rPr = new StyleRunProperties(
new FontSize { Val = fontSizeHalfPts },
new FontSizeComplexScript { Val = fontSizeHalfPts },
new Color { Val = color }
);
if (italic)
rPr.Append(new Italic());
return new Style(
new StyleName { Val = "caption" },
new BasedOn { Val = "Normal" },
new UIPriority { Val = 35 },
new PrimaryStyle(),
new StyleParagraphProperties(
new SpacingBetweenLines { After = "120" }
),
rPr
)
{
Type = StyleValues.Paragraph,
StyleId = "Caption",
Default = false
};
}
/// <summary>
/// Page number format options.
/// </summary>
private enum PageNumberFormat
{
/// <summary>Plain number: "1", "2", "3"</summary>
Plain,
/// <summary>Dash-surrounded: "-1-", "-2-", "-3-" (Chinese government standard)</summary>
DashSurrounded
}
/// <summary>
/// Adds a footer (or header) with page numbers to the document.
///
/// Page numbers use the PAGE simple field code. The footer/header is linked
/// to the section via a FooterReference/HeaderReference in SectionProperties.
///
/// Architecture:
/// 1. Create a FooterPart (or HeaderPart) on the MainDocumentPart
/// 2. Add the page number content (Paragraph with SimpleField)
/// 3. Get the relationship ID
/// 4. Add FooterReference (or HeaderReference) to SectionProperties
/// </summary>
private static void AddPageNumberFooter(
MainDocumentPart mainPart,
SectionProperties sectPr,
JustificationValues alignment,
string fontSizeHalfPts,
string color,
PageNumberFormat format,
bool isHeader = false,
string? fontName = null)
{
var runProps = new RunProperties(
new FontSize { Val = fontSizeHalfPts },
new FontSizeComplexScript { Val = fontSizeHalfPts },
new Color { Val = color }
);
if (fontName != null)
runProps.Append(new RunFonts { Ascii = fontName, HighAnsi = fontName, EastAsia = fontName });
// Build the paragraph content based on format
var paragraph = new Paragraph(
new ParagraphProperties(
new Justification { Val = alignment }
)
);
if (format == PageNumberFormat.DashSurrounded)
{
// "-X-" format: literal dash + PAGE field + literal dash
paragraph.Append(new Run(
(RunProperties)runProps.CloneNode(true),
new Text("-") { Space = SpaceProcessingModeValues.Preserve }
));
}
// PAGE field — inserts the current page number
paragraph.Append(new SimpleField(
new Run((RunProperties)runProps.CloneNode(true), new Text("1"))
)
{ Instruction = " PAGE " });
if (format == PageNumberFormat.DashSurrounded)
{
paragraph.Append(new Run(
(RunProperties)runProps.CloneNode(true),
new Text("-") { Space = SpaceProcessingModeValues.Preserve }
));
}
if (isHeader)
{
// Add as header
var headerPart = mainPart.AddNewPart<HeaderPart>();
headerPart.Header = new Header(paragraph);
headerPart.Header.Save();
string headerPartId = mainPart.GetIdOfPart(headerPart);
sectPr.Append(new HeaderReference
{
Type = HeaderFooterValues.Default,
Id = headerPartId
});
}
else
{
// Add as footer
var footerPart = mainPart.AddNewPart<FooterPart>();
footerPart.Footer = new Footer(paragraph);
footerPart.Footer.Save();
string footerPartId = mainPart.GetIdOfPart(footerPart);
sectPr.Append(new FooterReference
{
Type = HeaderFooterValues.Default,
Id = footerPartId
});
}
}
/// <summary>
/// Helper to add a paragraph with a specific style.
/// </summary>
private static void AddSampleParagraph(Body body, string text, string styleId)
{
body.Append(new Paragraph(
new ParagraphProperties(
new ParagraphStyleId { Val = styleId }
),
new Run(new Text(text))
));
}
}