// ============================================================================
// 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;
///
/// 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.
///
public static partial class AestheticRecipeSamples
{
// ════════════════════════════════════════════════════════════════════════
// RECIPE 1: MODERN CORPORATE
// ════════════════════════════════════════════════════════════════════════
///
/// 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
///
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();
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);
}
///
/// 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.
///
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
// ════════════════════════════════════════════════════════════════════════
///
/// 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.
///
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();
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);
}
///
/// 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.
///
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;
}
/// Helper to add a body paragraph with first-line indent (academic style).
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
// ════════════════════════════════════════════════════════════════════════
///
/// 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.
///
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();
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);
}
///
/// 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.
///
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)
// ════════════════════════════════════════════════════════════════════════
///
/// 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.
///
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();
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
// ════════════════════════════════════════════════════════════════════════
///
/// 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.
///
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();
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);
}
///
/// 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.
///
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
// ════════════════════════════════════════════════════════════════════════
///
/// Creates a basic paragraph style with minimal configuration.
/// Used for Normal, ListBullet, and other simple styles.
///
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;
}
///
/// 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.
///
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;
}
///
/// 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.
///
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;
}
///
/// Creates a Caption style used below tables and figures.
/// Captions are typically smaller and/or italic to visually subordinate them.
///
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
};
}
///
/// Page number format options.
///
private enum PageNumberFormat
{
/// Plain number: "1", "2", "3"
Plain,
/// Dash-surrounded: "-1-", "-2-", "-3-" (Chinese government standard)
DashSurrounded
}
///
/// 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
///
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.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.Footer = new Footer(paragraph);
footerPart.Footer.Save();
string footerPartId = mainPart.GetIdOfPart(footerPart);
sectPr.Append(new FooterReference
{
Type = HeaderFooterValues.Default,
Id = footerPartId
});
}
}
///
/// Helper to add a paragraph with a specific style.
///
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))
));
}
}