@nguyenphp/antigravity-marketing 1.0.18 → 1.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +186 -78
- package/package.json +4 -3
- package/templates/.agent/skills/marketing-report-expert/SKILL.md +70 -0
- package/templates/.agent/skills/minimax-docx/LICENSE +21 -0
- package/templates/.agent/skills/minimax-docx/SKILL.md +274 -0
- package/templates/.agent/skills/minimax-docx/assets/styles/academic_styles.xml +250 -0
- package/templates/.agent/skills/minimax-docx/assets/styles/corporate_styles.xml +284 -0
- package/templates/.agent/skills/minimax-docx/assets/styles/default_styles.xml +449 -0
- package/templates/.agent/skills/minimax-docx/assets/xsd/aesthetic-rules.xsd +470 -0
- package/templates/.agent/skills/minimax-docx/assets/xsd/business-rules.xsd +130 -0
- package/templates/.agent/skills/minimax-docx/assets/xsd/common-types.xsd +159 -0
- package/templates/.agent/skills/minimax-docx/assets/xsd/wml-subset.xsd +589 -0
- package/templates/.agent/skills/minimax-docx/references/cjk_typography.md +357 -0
- package/templates/.agent/skills/minimax-docx/references/cjk_university_template_guide.md +184 -0
- package/templates/.agent/skills/minimax-docx/references/comments_guide.md +191 -0
- package/templates/.agent/skills/minimax-docx/references/design_good_bad_examples.md +829 -0
- package/templates/.agent/skills/minimax-docx/references/design_principles.md +819 -0
- package/templates/.agent/skills/minimax-docx/references/openxml_element_order.md +308 -0
- package/templates/.agent/skills/minimax-docx/references/openxml_encyclopedia_part1.md +4061 -0
- package/templates/.agent/skills/minimax-docx/references/openxml_encyclopedia_part2.md +2820 -0
- package/templates/.agent/skills/minimax-docx/references/openxml_encyclopedia_part3.md +3381 -0
- package/templates/.agent/skills/minimax-docx/references/openxml_namespaces.md +82 -0
- package/templates/.agent/skills/minimax-docx/references/openxml_units.md +72 -0
- package/templates/.agent/skills/minimax-docx/references/scenario_a_create.md +284 -0
- package/templates/.agent/skills/minimax-docx/references/scenario_b_edit_content.md +295 -0
- package/templates/.agent/skills/minimax-docx/references/scenario_c_apply_template.md +456 -0
- package/templates/.agent/skills/minimax-docx/references/track_changes_guide.md +200 -0
- package/templates/.agent/skills/minimax-docx/references/troubleshooting.md +506 -0
- package/templates/.agent/skills/minimax-docx/references/typography_guide.md +294 -0
- package/templates/.agent/skills/minimax-docx/references/xsd_validation_guide.md +158 -0
- package/templates/.agent/skills/minimax-docx/scripts/doc_to_docx.sh +40 -0
- package/templates/.agent/skills/minimax-docx/scripts/docx_preview.sh +37 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Cli/MiniMaxAIDocx.Cli.csproj +19 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Cli/Program.cs +18 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/AnalyzeCommand.cs +147 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/ApplyTemplateCommand.cs +322 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/CreateCommand.cs +324 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/DiffCommand.cs +155 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/EditContentCommand.cs +487 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/FixOrderCommand.cs +108 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/MergeRunsCommand.cs +122 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/ValidateCommand.cs +107 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/MiniMaxAIDocx.Core.csproj +15 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/CommentSynchronizer.cs +169 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/ElementOrder.cs +80 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/NamespaceConstants.cs +42 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/RunMerger.cs +81 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/StyleAnalyzer.cs +81 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/TrackChangesHelper.cs +99 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/UnitConverter.cs +23 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples.cs +1832 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch1.cs +910 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch2.cs +999 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch3.cs +1048 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch4.cs +1038 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/CharacterFormattingSamples.cs +1020 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/DocumentCreationSamples.cs +1121 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/FieldAndTocSamples.cs +624 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/FootnoteAndCommentSamples.cs +675 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/HeaderFooterSamples.cs +838 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ImageSamples.cs +917 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ListAndNumberingSamples.cs +826 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ParagraphFormattingSamples.cs +1199 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/StyleSystemSamples.cs +1487 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/TableSamples.cs +1163 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/TrackChangesSamples.cs +595 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/CjkHelper.cs +39 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/FontDefaults.cs +24 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/PageSizes.cs +20 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/BusinessRuleValidator.cs +224 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/GateCheckValidator.cs +148 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/ValidationResult.cs +23 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/XsdValidator.cs +69 -0
- package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.slnx +4 -0
- package/templates/.agent/skills/minimax-docx/scripts/env_check.sh +196 -0
- package/templates/.agent/skills/minimax-docx/scripts/setup.ps1 +274 -0
- package/templates/.agent/skills/minimax-docx/scripts/setup.sh +504 -0
- package/templates/.agent/skills/minimax-multimodal-toolkit/SKILL.md +359 -0
- package/templates/.agent/skills/minimax-pdf/README.md +222 -0
- package/templates/.agent/skills/minimax-pdf/SKILL.md +201 -0
- package/templates/.agent/skills/minimax-pdf/design/design.md +381 -0
- package/templates/.agent/skills/minimax-pdf/scripts/cover.py +1579 -0
- package/templates/.agent/skills/minimax-pdf/scripts/fill_inspect.py +200 -0
- package/templates/.agent/skills/minimax-pdf/scripts/fill_write.py +242 -0
- package/templates/.agent/skills/minimax-pdf/scripts/make.sh +491 -0
- package/templates/.agent/skills/minimax-pdf/scripts/merge.py +112 -0
- package/templates/.agent/skills/minimax-pdf/scripts/palette.py +559 -0
- package/templates/.agent/skills/minimax-pdf/scripts/reformat_parse.py +374 -0
- package/templates/.agent/skills/minimax-pdf/scripts/render_body.py +1055 -0
- package/templates/.agent/skills/minimax-pdf/scripts/render_cover.cjs +111 -0
- package/templates/.agent/skills/minimax-xlsx/SKILL.md +138 -0
- package/templates/.agent/skills/minimax-xlsx/references/create.md +691 -0
- package/templates/.agent/skills/minimax-xlsx/references/edit.md +684 -0
- package/templates/.agent/skills/minimax-xlsx/references/fix.md +37 -0
- package/templates/.agent/skills/minimax-xlsx/references/format.md +768 -0
- package/templates/.agent/skills/minimax-xlsx/references/ooxml-cheatsheet.md +231 -0
- package/templates/.agent/skills/minimax-xlsx/references/read-analyze.md +97 -0
- package/templates/.agent/skills/minimax-xlsx/references/validate.md +772 -0
- package/templates/.agent/skills/minimax-xlsx/scripts/formula_check.py +422 -0
- package/templates/.agent/skills/minimax-xlsx/scripts/libreoffice_recalc.py +248 -0
- package/templates/.agent/skills/minimax-xlsx/scripts/shared_strings_builder.py +163 -0
- package/templates/.agent/skills/minimax-xlsx/scripts/style_audit.py +575 -0
- package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_add_column.py +395 -0
- package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_insert_row.py +274 -0
- package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_pack.py +87 -0
- package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_reader.py +362 -0
- package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_shift_rows.py +396 -0
- package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_unpack.py +130 -0
- package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/[Content_Types].xml +9 -0
- package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/_rels/.rels +6 -0
- package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/_rels/workbook.xml.rels +19 -0
- package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/sharedStrings.xml +33 -0
- package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/styles.xml +160 -0
- package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/workbook.xml +30 -0
- package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/worksheets/sheet1.xml +70 -0
- package/templates/.agent/skills/pptx-generator/SKILL.md +249 -0
- package/templates/.agent/skills/pptx-generator/references/design-system.md +392 -0
- package/templates/.agent/skills/pptx-generator/references/editing.md +162 -0
- package/templates/.agent/skills/pptx-generator/references/pitfalls.md +112 -0
- package/templates/.agent/skills/pptx-generator/references/pptxgenjs.md +420 -0
- package/templates/.agent/skills/pptx-generator/references/slide-types.md +413 -0
- package/templates/.agent/skills/tutorial-video-expert/SKILL.md +88 -0
- package/templates/.agent/skills/ui-ux-pro-max/SKILL.md +170 -585
- package/templates/.agent/skills/vision-analysis/SKILL.md +174 -0
- package/templates/.agent/workflows/analyze.md +3 -0
- package/templates/.agent/workflows/brand-report.md +44 -0
- package/templates/.agent/workflows/report.md +49 -0
|
@@ -0,0 +1,1832 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// AestheticRecipeSamples.cs — Complete aesthetic recipes for document styling
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Each recipe is a self-contained, coordinated design system where fonts,
|
|
5
|
+
// sizes, spacing, colors, margins, and table styles all work in harmony.
|
|
6
|
+
//
|
|
7
|
+
// DESIGN PHILOSOPHY: Beauty comes from harmony, not individual choices.
|
|
8
|
+
// A 14pt heading is not inherently good or bad — it depends on body size,
|
|
9
|
+
// line spacing, margins, and color all working together.
|
|
10
|
+
//
|
|
11
|
+
// UNIT REFERENCE:
|
|
12
|
+
// Font size: half-points (22 = 11pt, 24 = 12pt, 32 = 16pt)
|
|
13
|
+
// Spacing: DXA = twentieths of a point (1440 DXA = 1 inch)
|
|
14
|
+
// Borders: eighth-points (4 = 0.5pt, 8 = 1pt, 12 = 1.5pt)
|
|
15
|
+
// Line spacing "line": 240ths of single spacing (240 = 1.0x, 276 = 1.15x)
|
|
16
|
+
// ============================================================================
|
|
17
|
+
|
|
18
|
+
using DocumentFormat.OpenXml;
|
|
19
|
+
using DocumentFormat.OpenXml.Packaging;
|
|
20
|
+
using DocumentFormat.OpenXml.Wordprocessing;
|
|
21
|
+
|
|
22
|
+
using WpPageSize = DocumentFormat.OpenXml.Wordprocessing.PageSize;
|
|
23
|
+
|
|
24
|
+
namespace MiniMaxAIDocx.Core.Samples;
|
|
25
|
+
|
|
26
|
+
/// <summary>
|
|
27
|
+
/// Complete aesthetic recipes — coordinated design systems where all parameters
|
|
28
|
+
/// work together. Each recipe is a full document style that can be applied as-is.
|
|
29
|
+
///
|
|
30
|
+
/// DESIGN PHILOSOPHY: Beauty comes from harmony, not individual choices.
|
|
31
|
+
/// A 14pt heading is not inherently good or bad — it depends on body size,
|
|
32
|
+
/// line spacing, margins, and color all working together.
|
|
33
|
+
///
|
|
34
|
+
/// These recipes encode tested, harmonious combinations.
|
|
35
|
+
/// </summary>
|
|
36
|
+
public static partial class AestheticRecipeSamples
|
|
37
|
+
{
|
|
38
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
39
|
+
// RECIPE 1: MODERN CORPORATE
|
|
40
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
41
|
+
|
|
42
|
+
/// <summary>
|
|
43
|
+
/// Recipe: Modern Corporate
|
|
44
|
+
/// Feel: Clean, confident, contemporary.
|
|
45
|
+
/// Best for: Business reports, proposals, internal documents.
|
|
46
|
+
///
|
|
47
|
+
/// Design rationale:
|
|
48
|
+
/// - 1.25x modular scale creates clear but not aggressive hierarchy
|
|
49
|
+
/// (body 11pt → H3 13pt → H2 16pt → H1 20pt, each step ~1.25x)
|
|
50
|
+
/// - Dark navy headings (#1F3864) convey authority without being harsh
|
|
51
|
+
/// - 1.15 line spacing is the sweet spot for sans-serif readability:
|
|
52
|
+
/// tight enough to look professional, open enough for comfortable scanning
|
|
53
|
+
/// - 8pt paragraph spacing creates rhythm without wasting vertical space
|
|
54
|
+
/// - Body text #333333 (not pure black) reduces eye strain on screens
|
|
55
|
+
/// - Sans-serif font family (Aptos/Calibri) signals modernity and clarity
|
|
56
|
+
/// - Light banded table rows (#F2F2F2) aid scanning without visual noise
|
|
57
|
+
/// </summary>
|
|
58
|
+
public static void CreateModernCorporateDocument(string outputPath)
|
|
59
|
+
{
|
|
60
|
+
using var doc = WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document);
|
|
61
|
+
|
|
62
|
+
var mainPart = doc.AddMainDocumentPart();
|
|
63
|
+
mainPart.Document = new Document(new Body());
|
|
64
|
+
var body = mainPart.Document.Body!;
|
|
65
|
+
|
|
66
|
+
// ── Styles ──
|
|
67
|
+
var stylesPart = mainPart.AddNewPart<StyleDefinitionsPart>();
|
|
68
|
+
stylesPart.Styles = new Styles();
|
|
69
|
+
var styles = stylesPart.Styles;
|
|
70
|
+
|
|
71
|
+
// DocDefaults: the foundation everything inherits from.
|
|
72
|
+
// Aptos is Word's new default (2023+); Calibri is the fallback for older systems.
|
|
73
|
+
styles.Append(new DocDefaults(
|
|
74
|
+
new RunPropertiesDefault(
|
|
75
|
+
new RunPropertiesBaseStyle(
|
|
76
|
+
new RunFonts
|
|
77
|
+
{
|
|
78
|
+
Ascii = "Aptos",
|
|
79
|
+
HighAnsi = "Aptos",
|
|
80
|
+
EastAsia = "SimSun",
|
|
81
|
+
ComplexScript = "Calibri"
|
|
82
|
+
},
|
|
83
|
+
new FontSize { Val = "22" }, // 11pt body default
|
|
84
|
+
new FontSizeComplexScript { Val = "22" },
|
|
85
|
+
new Color { Val = "333333" }, // Soft black — easier on eyes than #000000
|
|
86
|
+
new Languages { Val = "en-US", EastAsia = "zh-CN" }
|
|
87
|
+
)
|
|
88
|
+
),
|
|
89
|
+
new ParagraphPropertiesDefault(
|
|
90
|
+
new ParagraphPropertiesBaseStyle(
|
|
91
|
+
new SpacingBetweenLines
|
|
92
|
+
{
|
|
93
|
+
// 1.15x line spacing: the modern standard for sans-serif.
|
|
94
|
+
// 240 = single, so 276 = 1.15x. Word's default since 2013.
|
|
95
|
+
Line = "276",
|
|
96
|
+
LineRule = LineSpacingRuleValues.Auto,
|
|
97
|
+
After = "160" // 8pt after — enough rhythm, not too airy
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
));
|
|
102
|
+
|
|
103
|
+
// ── Normal style ──
|
|
104
|
+
styles.Append(CreateParagraphStyle(
|
|
105
|
+
styleId: "Normal",
|
|
106
|
+
styleName: "Normal",
|
|
107
|
+
isDefault: true,
|
|
108
|
+
uiPriority: 0
|
|
109
|
+
));
|
|
110
|
+
|
|
111
|
+
// ── Heading 1: 20pt Aptos Display, dark navy ──
|
|
112
|
+
// 20pt = 40 half-points. The 1.25x scale from 11pt body gives:
|
|
113
|
+
// 11 → 13.75 → 17.2 → 21.5. We round to 13, 16, 20 for clean numbers.
|
|
114
|
+
styles.Append(CreateHeadingStyle(
|
|
115
|
+
level: 1,
|
|
116
|
+
fontAscii: "Aptos Display",
|
|
117
|
+
fontHAnsi: "Aptos Display",
|
|
118
|
+
sizeHalfPts: "40", // 20pt
|
|
119
|
+
color: "1F3864", // Dark navy — authority without aggression
|
|
120
|
+
bold: false, // Large Display font doesn't need bold
|
|
121
|
+
spaceBefore: "480", // 24pt before — creates a clear section break
|
|
122
|
+
spaceAfter: "120", // 6pt after — tight coupling to content below
|
|
123
|
+
uiPriority: 9
|
|
124
|
+
));
|
|
125
|
+
|
|
126
|
+
// ── Heading 2: 16pt, dark navy, semi-bold ──
|
|
127
|
+
styles.Append(CreateHeadingStyle(
|
|
128
|
+
level: 2,
|
|
129
|
+
fontAscii: "Aptos Display",
|
|
130
|
+
fontHAnsi: "Aptos Display",
|
|
131
|
+
sizeHalfPts: "32", // 16pt
|
|
132
|
+
color: "1F3864",
|
|
133
|
+
bold: false,
|
|
134
|
+
spaceBefore: "360", // 18pt before
|
|
135
|
+
spaceAfter: "80", // 4pt after
|
|
136
|
+
uiPriority: 9
|
|
137
|
+
));
|
|
138
|
+
|
|
139
|
+
// ── Heading 3: 13pt, dark navy, bold ──
|
|
140
|
+
styles.Append(CreateHeadingStyle(
|
|
141
|
+
level: 3,
|
|
142
|
+
fontAscii: "Aptos",
|
|
143
|
+
fontHAnsi: "Aptos",
|
|
144
|
+
sizeHalfPts: "26", // 13pt
|
|
145
|
+
color: "1F3864",
|
|
146
|
+
bold: true, // Bold compensates for smaller size
|
|
147
|
+
spaceBefore: "240", // 12pt before
|
|
148
|
+
spaceAfter: "80", // 4pt after
|
|
149
|
+
uiPriority: 9
|
|
150
|
+
));
|
|
151
|
+
|
|
152
|
+
// ── ListBullet style ──
|
|
153
|
+
styles.Append(CreateParagraphStyle(
|
|
154
|
+
styleId: "ListBullet",
|
|
155
|
+
styleName: "List Bullet",
|
|
156
|
+
basedOn: "Normal",
|
|
157
|
+
uiPriority: 36
|
|
158
|
+
));
|
|
159
|
+
|
|
160
|
+
// ── Caption style: 9pt italic gray ──
|
|
161
|
+
styles.Append(CreateCaptionStyle(
|
|
162
|
+
fontSizeHalfPts: "18", // 9pt
|
|
163
|
+
color: "595959",
|
|
164
|
+
italic: true
|
|
165
|
+
));
|
|
166
|
+
|
|
167
|
+
// ── Page setup: Letter, 1in margins ──
|
|
168
|
+
// 1 inch = 1440 DXA. Letter = 8.5" x 11" = 12240 x 15840 DXA.
|
|
169
|
+
var sectPr = new SectionProperties(
|
|
170
|
+
new WpPageSize { Width = 12240U, Height = 15840U },
|
|
171
|
+
new PageMargin
|
|
172
|
+
{
|
|
173
|
+
Top = 1440, Bottom = 1440,
|
|
174
|
+
Left = 1440U, Right = 1440U,
|
|
175
|
+
Header = 720U, Footer = 720U, Gutter = 0U
|
|
176
|
+
}
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// ── Page numbers: bottom right, 9pt gray ──
|
|
180
|
+
AddPageNumberFooter(mainPart, sectPr,
|
|
181
|
+
alignment: JustificationValues.Right,
|
|
182
|
+
fontSizeHalfPts: "18", // 9pt — subordinate to body text
|
|
183
|
+
color: "808080", // Gray — page numbers are reference, not content
|
|
184
|
+
format: PageNumberFormat.Plain
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
// ── Sample content ──
|
|
188
|
+
AddSampleParagraph(body, "Modern Corporate Report", "Heading1");
|
|
189
|
+
|
|
190
|
+
AddSampleParagraph(body, "This document demonstrates the Modern Corporate aesthetic. "
|
|
191
|
+
+ "The clean sans-serif typography, dark navy headings, and generous but not "
|
|
192
|
+
+ "excessive spacing create a professional appearance suitable for business contexts.",
|
|
193
|
+
"Normal");
|
|
194
|
+
|
|
195
|
+
AddSampleParagraph(body, "Executive Summary", "Heading2");
|
|
196
|
+
|
|
197
|
+
AddSampleParagraph(body, "Key findings from our analysis indicate strong performance "
|
|
198
|
+
+ "across all divisions. Revenue grew 12% year-over-year while maintaining healthy "
|
|
199
|
+
+ "margins. The integration of new systems has improved operational efficiency.",
|
|
200
|
+
"Normal");
|
|
201
|
+
|
|
202
|
+
AddSampleParagraph(body, "Detailed Findings", "Heading2");
|
|
203
|
+
|
|
204
|
+
AddSampleParagraph(body, "Revenue Analysis", "Heading3");
|
|
205
|
+
|
|
206
|
+
AddSampleParagraph(body, "Quarter-over-quarter growth remained consistent, with Q3 "
|
|
207
|
+
+ "showing particularly strong performance in the enterprise segment.",
|
|
208
|
+
"Normal");
|
|
209
|
+
|
|
210
|
+
// ── Table: light top/bottom borders, banded rows, no vertical lines ──
|
|
211
|
+
body.Append(CreateModernCorporateTable(
|
|
212
|
+
new[] { "Division", "Revenue", "Growth", "Margin" },
|
|
213
|
+
new[]
|
|
214
|
+
{
|
|
215
|
+
new[] { "Enterprise", "$45.2M", "+15%", "42%" },
|
|
216
|
+
new[] { "Mid-Market", "$28.7M", "+11%", "38%" },
|
|
217
|
+
new[] { "SMB", "$12.1M", "+8%", "35%" }
|
|
218
|
+
}
|
|
219
|
+
));
|
|
220
|
+
|
|
221
|
+
AddSampleParagraph(body, "Table 1: Division Performance Summary", "Caption");
|
|
222
|
+
|
|
223
|
+
// Section properties must be last child of body
|
|
224
|
+
body.Append(sectPr);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/// <summary>
|
|
228
|
+
/// Modern Corporate table aesthetic: horizontal lines only, banded rows.
|
|
229
|
+
/// Design: top and bottom borders frame the data. Header has a bottom border.
|
|
230
|
+
/// No vertical lines — the eye follows horizontal rows naturally.
|
|
231
|
+
/// Subtle #F2F2F2 banding on alternate rows aids scanning without adding noise.
|
|
232
|
+
/// </summary>
|
|
233
|
+
private static Table CreateModernCorporateTable(string[] headers, string[][] data)
|
|
234
|
+
{
|
|
235
|
+
var table = new Table();
|
|
236
|
+
|
|
237
|
+
// Table properties: full width, horizontal-only borders
|
|
238
|
+
var tblPr = new TableProperties(
|
|
239
|
+
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
|
|
240
|
+
new TableBorders(
|
|
241
|
+
new TopBorder { Val = BorderValues.Single, Size = 8, Space = 0, Color = "BFBFBF" },
|
|
242
|
+
new BottomBorder { Val = BorderValues.Single, Size = 8, Space = 0, Color = "BFBFBF" },
|
|
243
|
+
new LeftBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
244
|
+
new RightBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
245
|
+
// Horizontal inside borders for row separation
|
|
246
|
+
new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "D9D9D9" },
|
|
247
|
+
// No vertical inside borders — cleaner look
|
|
248
|
+
new InsideVerticalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" }
|
|
249
|
+
),
|
|
250
|
+
// Cell padding: 28 DXA minimum each side for breathing room
|
|
251
|
+
new TableCellMarginDefault(
|
|
252
|
+
new TopMargin { Width = "28", Type = TableWidthUnitValues.Dxa },
|
|
253
|
+
new StartMargin { Width = "57", Type = TableWidthUnitValues.Dxa },
|
|
254
|
+
new BottomMargin { Width = "28", Type = TableWidthUnitValues.Dxa },
|
|
255
|
+
new EndMargin { Width = "57", Type = TableWidthUnitValues.Dxa }
|
|
256
|
+
)
|
|
257
|
+
);
|
|
258
|
+
table.Append(tblPr);
|
|
259
|
+
|
|
260
|
+
// Grid columns
|
|
261
|
+
var grid = new TableGrid();
|
|
262
|
+
int colWidth = 9360 / headers.Length;
|
|
263
|
+
foreach (var _ in headers)
|
|
264
|
+
grid.Append(new GridColumn { Width = colWidth.ToString() });
|
|
265
|
+
table.Append(grid);
|
|
266
|
+
|
|
267
|
+
// Header row
|
|
268
|
+
var headerRow = new TableRow();
|
|
269
|
+
foreach (var h in headers)
|
|
270
|
+
{
|
|
271
|
+
headerRow.Append(new TableCell(
|
|
272
|
+
new TableCellProperties(
|
|
273
|
+
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto },
|
|
274
|
+
// Header bottom border slightly heavier to separate from data
|
|
275
|
+
new TableCellBorders(
|
|
276
|
+
new BottomBorder { Val = BorderValues.Single, Size = 8, Space = 0, Color = "999999" }
|
|
277
|
+
)
|
|
278
|
+
),
|
|
279
|
+
new Paragraph(
|
|
280
|
+
new ParagraphProperties(
|
|
281
|
+
new SpacingBetweenLines { After = "0" }
|
|
282
|
+
),
|
|
283
|
+
new Run(
|
|
284
|
+
new RunProperties(new Bold()),
|
|
285
|
+
new Text(h)
|
|
286
|
+
)
|
|
287
|
+
)
|
|
288
|
+
));
|
|
289
|
+
}
|
|
290
|
+
table.Append(headerRow);
|
|
291
|
+
|
|
292
|
+
// Data rows with subtle banding
|
|
293
|
+
for (int i = 0; i < data.Length; i++)
|
|
294
|
+
{
|
|
295
|
+
var row = new TableRow();
|
|
296
|
+
foreach (var cell in data[i])
|
|
297
|
+
{
|
|
298
|
+
var tcPr = new TableCellProperties(
|
|
299
|
+
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto }
|
|
300
|
+
);
|
|
301
|
+
// Banded rows: every other row gets a very light gray background
|
|
302
|
+
// #F2F2F2 is subtle enough to not compete with content
|
|
303
|
+
if (i % 2 == 1)
|
|
304
|
+
{
|
|
305
|
+
tcPr.Append(new Shading
|
|
306
|
+
{
|
|
307
|
+
Val = ShadingPatternValues.Clear,
|
|
308
|
+
Color = "auto",
|
|
309
|
+
Fill = "F2F2F2"
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
row.Append(new TableCell(
|
|
314
|
+
tcPr,
|
|
315
|
+
new Paragraph(
|
|
316
|
+
new ParagraphProperties(
|
|
317
|
+
new SpacingBetweenLines { After = "0" }
|
|
318
|
+
),
|
|
319
|
+
new Run(new Text(cell))
|
|
320
|
+
)
|
|
321
|
+
));
|
|
322
|
+
}
|
|
323
|
+
table.Append(row);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return table;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
331
|
+
// RECIPE 2: ACADEMIC THESIS
|
|
332
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
333
|
+
|
|
334
|
+
/// <summary>
|
|
335
|
+
/// Recipe: Academic Thesis (APA-style)
|
|
336
|
+
/// Feel: Traditional, scholarly, readable for sustained long-form reading.
|
|
337
|
+
/// Best for: Dissertations, research papers, academic reports.
|
|
338
|
+
///
|
|
339
|
+
/// Design rationale:
|
|
340
|
+
/// - Times New Roman 12pt: the universal academic standard, optimized for
|
|
341
|
+
/// print legibility at reading distance. Serif fonts aid reading flow in
|
|
342
|
+
/// long-form text by creating horizontal "rails" for the eye.
|
|
343
|
+
/// - APA-style headings: size is UNIFORM (all 12pt) — hierarchy is expressed
|
|
344
|
+
/// through bold, italic, centering, and indentation rather than size change.
|
|
345
|
+
/// This is intentional: in academic writing, the text IS the content, and
|
|
346
|
+
/// headings are navigational aids, not visual statements.
|
|
347
|
+
/// - Double spacing (480 line units): required by most style guides for
|
|
348
|
+
/// annotation/editing room. Also improves readability for dense content.
|
|
349
|
+
/// - 0.5in first-line indent, no paragraph spacing: the classical paragraph
|
|
350
|
+
/// separator. Space-after is a modern convention; indent is the scholarly one.
|
|
351
|
+
/// - Left margin 1.5in for binding: physical theses are bound on the left.
|
|
352
|
+
/// - Three-line table (三线表): the academic standard — top rule, header rule,
|
|
353
|
+
/// bottom rule. No vertical lines. Clean and information-focused.
|
|
354
|
+
/// </summary>
|
|
355
|
+
public static void CreateAcademicThesisDocument(string outputPath)
|
|
356
|
+
{
|
|
357
|
+
using var doc = WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document);
|
|
358
|
+
|
|
359
|
+
var mainPart = doc.AddMainDocumentPart();
|
|
360
|
+
mainPart.Document = new Document(new Body());
|
|
361
|
+
var body = mainPart.Document.Body!;
|
|
362
|
+
|
|
363
|
+
// ── Styles ──
|
|
364
|
+
var stylesPart = mainPart.AddNewPart<StyleDefinitionsPart>();
|
|
365
|
+
stylesPart.Styles = new Styles();
|
|
366
|
+
var styles = stylesPart.Styles;
|
|
367
|
+
|
|
368
|
+
// DocDefaults: Times New Roman 12pt, double spacing
|
|
369
|
+
styles.Append(new DocDefaults(
|
|
370
|
+
new RunPropertiesDefault(
|
|
371
|
+
new RunPropertiesBaseStyle(
|
|
372
|
+
new RunFonts
|
|
373
|
+
{
|
|
374
|
+
Ascii = "Times New Roman",
|
|
375
|
+
HighAnsi = "Times New Roman",
|
|
376
|
+
EastAsia = "SimSun",
|
|
377
|
+
ComplexScript = "Times New Roman"
|
|
378
|
+
},
|
|
379
|
+
new FontSize { Val = "24" }, // 12pt (in half-points)
|
|
380
|
+
new FontSizeComplexScript { Val = "24" },
|
|
381
|
+
new Color { Val = "000000" }, // Pure black — academic standard
|
|
382
|
+
new Languages { Val = "en-US", EastAsia = "zh-CN" }
|
|
383
|
+
)
|
|
384
|
+
),
|
|
385
|
+
new ParagraphPropertiesDefault(
|
|
386
|
+
new ParagraphPropertiesBaseStyle(
|
|
387
|
+
new SpacingBetweenLines
|
|
388
|
+
{
|
|
389
|
+
// Double spacing: 480 = 2.0x (240 = single)
|
|
390
|
+
// This is the fundamental academic formatting requirement
|
|
391
|
+
Line = "480",
|
|
392
|
+
LineRule = LineSpacingRuleValues.Auto,
|
|
393
|
+
After = "0" // No space after — use first-line indent instead
|
|
394
|
+
},
|
|
395
|
+
// First-line indent: 0.5in = 720 DXA
|
|
396
|
+
// The traditional paragraph separator in academic writing
|
|
397
|
+
new Indentation { FirstLine = "720" }
|
|
398
|
+
)
|
|
399
|
+
)
|
|
400
|
+
));
|
|
401
|
+
|
|
402
|
+
// ── Normal style ──
|
|
403
|
+
styles.Append(CreateParagraphStyle(
|
|
404
|
+
styleId: "Normal",
|
|
405
|
+
styleName: "Normal",
|
|
406
|
+
isDefault: true,
|
|
407
|
+
uiPriority: 0
|
|
408
|
+
));
|
|
409
|
+
|
|
410
|
+
// ── APA Heading 1: 12pt bold, centered ──
|
|
411
|
+
// APA Level 1: Centered, Bold, Title Case
|
|
412
|
+
// Note: ALL headings are 12pt — hierarchy through formatting, not size.
|
|
413
|
+
styles.Append(CreateAcademicHeadingStyle(
|
|
414
|
+
level: 1,
|
|
415
|
+
sizeHalfPts: "24", // 12pt — same as body
|
|
416
|
+
bold: true,
|
|
417
|
+
italic: false,
|
|
418
|
+
centered: true,
|
|
419
|
+
spaceBefore: "480", // One blank double-spaced line before
|
|
420
|
+
spaceAfter: "0"
|
|
421
|
+
));
|
|
422
|
+
|
|
423
|
+
// ── APA Heading 2: 12pt bold, left-aligned ──
|
|
424
|
+
// APA Level 2: Flush Left, Bold, Title Case
|
|
425
|
+
styles.Append(CreateAcademicHeadingStyle(
|
|
426
|
+
level: 2,
|
|
427
|
+
sizeHalfPts: "24", // 12pt — same as body
|
|
428
|
+
bold: true,
|
|
429
|
+
italic: false,
|
|
430
|
+
centered: false,
|
|
431
|
+
spaceBefore: "480",
|
|
432
|
+
spaceAfter: "0"
|
|
433
|
+
));
|
|
434
|
+
|
|
435
|
+
// ── APA Heading 3: 12pt bold italic, left-aligned ──
|
|
436
|
+
// APA Level 3: Flush Left, Bold Italic, Title Case
|
|
437
|
+
styles.Append(CreateAcademicHeadingStyle(
|
|
438
|
+
level: 3,
|
|
439
|
+
sizeHalfPts: "24", // 12pt — same as body
|
|
440
|
+
bold: true,
|
|
441
|
+
italic: true,
|
|
442
|
+
centered: false,
|
|
443
|
+
spaceBefore: "480",
|
|
444
|
+
spaceAfter: "0"
|
|
445
|
+
));
|
|
446
|
+
|
|
447
|
+
// ── ListBullet style ──
|
|
448
|
+
styles.Append(CreateParagraphStyle(
|
|
449
|
+
styleId: "ListBullet",
|
|
450
|
+
styleName: "List Bullet",
|
|
451
|
+
basedOn: "Normal",
|
|
452
|
+
uiPriority: 36
|
|
453
|
+
));
|
|
454
|
+
|
|
455
|
+
// ── Caption style ──
|
|
456
|
+
styles.Append(CreateCaptionStyle(
|
|
457
|
+
fontSizeHalfPts: "24", // 12pt — same as body (APA requirement)
|
|
458
|
+
color: "000000",
|
|
459
|
+
italic: true
|
|
460
|
+
));
|
|
461
|
+
|
|
462
|
+
// ── Page setup: Letter, 1in margins, 1.5in left for binding ──
|
|
463
|
+
var sectPr = new SectionProperties(
|
|
464
|
+
new WpPageSize { Width = 12240U, Height = 15840U },
|
|
465
|
+
new PageMargin
|
|
466
|
+
{
|
|
467
|
+
Top = 1440, Bottom = 1440,
|
|
468
|
+
Left = 2160U, // 1.5in for binding margin
|
|
469
|
+
Right = 1440U,
|
|
470
|
+
Header = 720U, Footer = 720U, Gutter = 0U
|
|
471
|
+
}
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
// ── Page numbers: top right (APA style) ──
|
|
475
|
+
AddPageNumberFooter(mainPart, sectPr,
|
|
476
|
+
alignment: JustificationValues.Right,
|
|
477
|
+
fontSizeHalfPts: "24", // 12pt — APA requires same size
|
|
478
|
+
color: "000000",
|
|
479
|
+
format: PageNumberFormat.Plain,
|
|
480
|
+
isHeader: true // APA puts page numbers in header
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
// ── Sample content ──
|
|
484
|
+
// Title page heading — no first-line indent
|
|
485
|
+
body.Append(new Paragraph(
|
|
486
|
+
new ParagraphProperties(
|
|
487
|
+
new ParagraphStyleId { Val = "Heading1" },
|
|
488
|
+
new Indentation { FirstLine = "0" } // Override indent for headings
|
|
489
|
+
),
|
|
490
|
+
new Run(new Text("The Effects of Typography on Reading Comprehension"))
|
|
491
|
+
));
|
|
492
|
+
|
|
493
|
+
AddAcademicParagraph(body, "This study examines the relationship between typographic "
|
|
494
|
+
+ "choices and reading comprehension in academic documents. Previous research has "
|
|
495
|
+
+ "established that serif fonts facilitate sustained reading in printed materials, "
|
|
496
|
+
+ "though recent evidence suggests this advantage diminishes on high-resolution screens.");
|
|
497
|
+
|
|
498
|
+
AddAcademicParagraph(body, "The present investigation extends this work by examining "
|
|
499
|
+
+ "how the interaction of font choice, line spacing, and margin width affects both "
|
|
500
|
+
+ "comprehension accuracy and reading speed across different document lengths.");
|
|
501
|
+
|
|
502
|
+
body.Append(new Paragraph(
|
|
503
|
+
new ParagraphProperties(
|
|
504
|
+
new ParagraphStyleId { Val = "Heading2" },
|
|
505
|
+
new Indentation { FirstLine = "0" }
|
|
506
|
+
),
|
|
507
|
+
new Run(new Text("Method"))
|
|
508
|
+
));
|
|
509
|
+
|
|
510
|
+
body.Append(new Paragraph(
|
|
511
|
+
new ParagraphProperties(
|
|
512
|
+
new ParagraphStyleId { Val = "Heading3" },
|
|
513
|
+
new Indentation { FirstLine = "0" }
|
|
514
|
+
),
|
|
515
|
+
new Run(new Text("Participants"))
|
|
516
|
+
));
|
|
517
|
+
|
|
518
|
+
AddAcademicParagraph(body, "A total of 120 undergraduate students (M age = 21.3, "
|
|
519
|
+
+ "SD = 2.1) participated in exchange for course credit. All participants reported "
|
|
520
|
+
+ "normal or corrected-to-normal vision.");
|
|
521
|
+
|
|
522
|
+
// ── Three-line table (三线表) ──
|
|
523
|
+
body.Append(CreateThreeLineTable(
|
|
524
|
+
new[] { "Condition", "n", "M (RT)", "SD", "Accuracy %" },
|
|
525
|
+
new[]
|
|
526
|
+
{
|
|
527
|
+
new[] { "Serif / Double", "30", "142.3", "18.7", "94.2" },
|
|
528
|
+
new[] { "Serif / Single", "30", "156.8", "21.3", "91.8" },
|
|
529
|
+
new[] { "Sans / Double", "30", "148.1", "19.4", "92.7" },
|
|
530
|
+
new[] { "Sans / Single", "30", "161.2", "23.1", "89.4" }
|
|
531
|
+
}
|
|
532
|
+
));
|
|
533
|
+
|
|
534
|
+
body.Append(sectPr);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/// <summary>
|
|
538
|
+
/// Three-line table (三线表): the gold standard for academic data presentation.
|
|
539
|
+
/// Only three horizontal lines: top rule (1.5pt), header-bottom rule (0.75pt),
|
|
540
|
+
/// bottom rule (1.5pt). No vertical lines whatsoever.
|
|
541
|
+
/// This style focuses the reader on the data, not the grid.
|
|
542
|
+
/// </summary>
|
|
543
|
+
private static Table CreateThreeLineTable(string[] headers, string[][] data)
|
|
544
|
+
{
|
|
545
|
+
var table = new Table();
|
|
546
|
+
|
|
547
|
+
// Table properties: three horizontal rules only
|
|
548
|
+
var tblPr = new TableProperties(
|
|
549
|
+
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
|
|
550
|
+
new TableBorders(
|
|
551
|
+
// Top rule: 1.5pt (Size=12 in eighth-points)
|
|
552
|
+
new TopBorder { Val = BorderValues.Single, Size = 12, Space = 0, Color = "000000" },
|
|
553
|
+
// Bottom rule: 1.5pt
|
|
554
|
+
new BottomBorder { Val = BorderValues.Single, Size = 12, Space = 0, Color = "000000" },
|
|
555
|
+
// No left, right, or inside borders
|
|
556
|
+
new LeftBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
557
|
+
new RightBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
558
|
+
new InsideHorizontalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
559
|
+
new InsideVerticalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" }
|
|
560
|
+
),
|
|
561
|
+
new TableCellMarginDefault(
|
|
562
|
+
new TopMargin { Width = "28", Type = TableWidthUnitValues.Dxa },
|
|
563
|
+
new StartMargin { Width = "57", Type = TableWidthUnitValues.Dxa },
|
|
564
|
+
new BottomMargin { Width = "28", Type = TableWidthUnitValues.Dxa },
|
|
565
|
+
new EndMargin { Width = "57", Type = TableWidthUnitValues.Dxa }
|
|
566
|
+
)
|
|
567
|
+
);
|
|
568
|
+
table.Append(tblPr);
|
|
569
|
+
|
|
570
|
+
// Grid
|
|
571
|
+
var grid = new TableGrid();
|
|
572
|
+
int colWidth = 9360 / headers.Length;
|
|
573
|
+
foreach (var _ in headers)
|
|
574
|
+
grid.Append(new GridColumn { Width = colWidth.ToString() });
|
|
575
|
+
table.Append(grid);
|
|
576
|
+
|
|
577
|
+
// Header row: bottom border is the header rule (0.75pt = Size 6)
|
|
578
|
+
var headerRow = new TableRow();
|
|
579
|
+
foreach (var h in headers)
|
|
580
|
+
{
|
|
581
|
+
headerRow.Append(new TableCell(
|
|
582
|
+
new TableCellProperties(
|
|
583
|
+
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto },
|
|
584
|
+
new TableCellBorders(
|
|
585
|
+
new BottomBorder { Val = BorderValues.Single, Size = 6, Space = 0, Color = "000000" }
|
|
586
|
+
)
|
|
587
|
+
),
|
|
588
|
+
new Paragraph(
|
|
589
|
+
new ParagraphProperties(
|
|
590
|
+
new SpacingBetweenLines { After = "0", Line = "240", LineRule = LineSpacingRuleValues.Auto },
|
|
591
|
+
new Indentation { FirstLine = "0" },
|
|
592
|
+
new Justification { Val = JustificationValues.Center }
|
|
593
|
+
),
|
|
594
|
+
new Run(
|
|
595
|
+
new RunProperties(new Bold()),
|
|
596
|
+
new Text(h)
|
|
597
|
+
)
|
|
598
|
+
)
|
|
599
|
+
));
|
|
600
|
+
}
|
|
601
|
+
table.Append(headerRow);
|
|
602
|
+
|
|
603
|
+
// Data rows: no borders (only the table-level top/bottom apply)
|
|
604
|
+
foreach (var rowData in data)
|
|
605
|
+
{
|
|
606
|
+
var row = new TableRow();
|
|
607
|
+
foreach (var cell in rowData)
|
|
608
|
+
{
|
|
609
|
+
row.Append(new TableCell(
|
|
610
|
+
new TableCellProperties(
|
|
611
|
+
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto }
|
|
612
|
+
),
|
|
613
|
+
new Paragraph(
|
|
614
|
+
new ParagraphProperties(
|
|
615
|
+
new SpacingBetweenLines { After = "0", Line = "240", LineRule = LineSpacingRuleValues.Auto },
|
|
616
|
+
new Indentation { FirstLine = "0" },
|
|
617
|
+
new Justification { Val = JustificationValues.Center }
|
|
618
|
+
),
|
|
619
|
+
new Run(new Text(cell))
|
|
620
|
+
)
|
|
621
|
+
));
|
|
622
|
+
}
|
|
623
|
+
table.Append(row);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
return table;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/// <summary>Helper to add a body paragraph with first-line indent (academic style).</summary>
|
|
630
|
+
private static void AddAcademicParagraph(Body body, string text)
|
|
631
|
+
{
|
|
632
|
+
body.Append(new Paragraph(
|
|
633
|
+
new ParagraphProperties(
|
|
634
|
+
new ParagraphStyleId { Val = "Normal" }
|
|
635
|
+
),
|
|
636
|
+
new Run(new Text(text))
|
|
637
|
+
));
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
642
|
+
// RECIPE 3: EXECUTIVE BRIEF
|
|
643
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
644
|
+
|
|
645
|
+
/// <summary>
|
|
646
|
+
/// Recipe: Executive Brief
|
|
647
|
+
/// Feel: Premium, minimal, high white-space.
|
|
648
|
+
/// Best for: Board summaries, investor updates, C-suite communications.
|
|
649
|
+
///
|
|
650
|
+
/// Design rationale:
|
|
651
|
+
/// - Georgia (serif) body with Helvetica Neue/Arial headings: the serif/sans
|
|
652
|
+
/// contrast creates natural visual hierarchy. Georgia was designed specifically
|
|
653
|
+
/// for screen readability while maintaining elegance.
|
|
654
|
+
/// - 1.4x line spacing (336 line units): more generous than corporate, reflecting
|
|
655
|
+
/// the premium feel. Executives scan quickly; more air helps their eyes jump.
|
|
656
|
+
/// - 10pt generous paragraph spacing: creates distinct "thought blocks" that
|
|
657
|
+
/// support quick scanning without deep reading.
|
|
658
|
+
/// - 1.25in margins: extra breathing room signals "we can afford to waste paper."
|
|
659
|
+
/// White space IS the luxury. Content-to-margin ratio conveys status.
|
|
660
|
+
/// - #2C3E50 (dark blue-gray) for all text: sophisticated alternative to black.
|
|
661
|
+
/// Warm enough to not feel clinical, dark enough for print legibility.
|
|
662
|
+
/// - #E74C3C accent red: used sparingly for table headers, creates a single
|
|
663
|
+
/// focal point. The contrast draws the eye to data.
|
|
664
|
+
/// - Dark header table style: inverted header row makes the table structure
|
|
665
|
+
/// immediately scannable even in peripheral vision.
|
|
666
|
+
/// </summary>
|
|
667
|
+
public static void CreateExecutiveBriefDocument(string outputPath)
|
|
668
|
+
{
|
|
669
|
+
using var doc = WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document);
|
|
670
|
+
|
|
671
|
+
var mainPart = doc.AddMainDocumentPart();
|
|
672
|
+
mainPart.Document = new Document(new Body());
|
|
673
|
+
var body = mainPart.Document.Body!;
|
|
674
|
+
|
|
675
|
+
// ── Styles ──
|
|
676
|
+
var stylesPart = mainPart.AddNewPart<StyleDefinitionsPart>();
|
|
677
|
+
stylesPart.Styles = new Styles();
|
|
678
|
+
var styles = stylesPart.Styles;
|
|
679
|
+
|
|
680
|
+
// DocDefaults: Georgia 11pt, generous spacing
|
|
681
|
+
styles.Append(new DocDefaults(
|
|
682
|
+
new RunPropertiesDefault(
|
|
683
|
+
new RunPropertiesBaseStyle(
|
|
684
|
+
new RunFonts
|
|
685
|
+
{
|
|
686
|
+
// Georgia: designed by Matthew Carter for Microsoft.
|
|
687
|
+
// Optimized for screen clarity while retaining serif elegance.
|
|
688
|
+
Ascii = "Georgia",
|
|
689
|
+
HighAnsi = "Georgia",
|
|
690
|
+
EastAsia = "SimSun",
|
|
691
|
+
ComplexScript = "Arial"
|
|
692
|
+
},
|
|
693
|
+
new FontSize { Val = "22" }, // 11pt
|
|
694
|
+
new FontSizeComplexScript { Val = "22" },
|
|
695
|
+
new Color { Val = "2C3E50" }, // Dark blue-gray — sophisticated
|
|
696
|
+
new Languages { Val = "en-US", EastAsia = "zh-CN" }
|
|
697
|
+
)
|
|
698
|
+
),
|
|
699
|
+
new ParagraphPropertiesDefault(
|
|
700
|
+
new ParagraphPropertiesBaseStyle(
|
|
701
|
+
new SpacingBetweenLines
|
|
702
|
+
{
|
|
703
|
+
// 1.4x line spacing: the "executive reading" sweet spot.
|
|
704
|
+
// More air than corporate (1.15), less than academic (2.0).
|
|
705
|
+
// Facilitates scanning behavior common in executive reading.
|
|
706
|
+
Line = "336",
|
|
707
|
+
LineRule = LineSpacingRuleValues.Auto,
|
|
708
|
+
After = "200" // 10pt after — generous blocks
|
|
709
|
+
}
|
|
710
|
+
)
|
|
711
|
+
)
|
|
712
|
+
));
|
|
713
|
+
|
|
714
|
+
// ── Normal style ──
|
|
715
|
+
styles.Append(CreateParagraphStyle(
|
|
716
|
+
styleId: "Normal",
|
|
717
|
+
styleName: "Normal",
|
|
718
|
+
isDefault: true,
|
|
719
|
+
uiPriority: 0
|
|
720
|
+
));
|
|
721
|
+
|
|
722
|
+
// ── Heading 1: 22pt Helvetica Neue/Arial, bold ──
|
|
723
|
+
// Serif body + sans heading = natural hierarchy through font contrast
|
|
724
|
+
styles.Append(CreateHeadingStyle(
|
|
725
|
+
level: 1,
|
|
726
|
+
fontAscii: "Helvetica Neue",
|
|
727
|
+
fontHAnsi: "Helvetica Neue",
|
|
728
|
+
sizeHalfPts: "44", // 22pt
|
|
729
|
+
color: "2C3E50",
|
|
730
|
+
bold: false, // Large size is enough; bold would be heavy
|
|
731
|
+
spaceBefore: "480",
|
|
732
|
+
spaceAfter: "120",
|
|
733
|
+
uiPriority: 9
|
|
734
|
+
));
|
|
735
|
+
|
|
736
|
+
// ── Heading 2: 16pt Helvetica Neue/Arial ──
|
|
737
|
+
styles.Append(CreateHeadingStyle(
|
|
738
|
+
level: 2,
|
|
739
|
+
fontAscii: "Helvetica Neue",
|
|
740
|
+
fontHAnsi: "Helvetica Neue",
|
|
741
|
+
sizeHalfPts: "32", // 16pt
|
|
742
|
+
color: "2C3E50",
|
|
743
|
+
bold: false,
|
|
744
|
+
spaceBefore: "360",
|
|
745
|
+
spaceAfter: "80",
|
|
746
|
+
uiPriority: 9
|
|
747
|
+
));
|
|
748
|
+
|
|
749
|
+
// ── Heading 3: 12pt Helvetica Neue/Arial, bold ──
|
|
750
|
+
styles.Append(CreateHeadingStyle(
|
|
751
|
+
level: 3,
|
|
752
|
+
fontAscii: "Helvetica Neue",
|
|
753
|
+
fontHAnsi: "Helvetica Neue",
|
|
754
|
+
sizeHalfPts: "24", // 12pt
|
|
755
|
+
color: "2C3E50",
|
|
756
|
+
bold: true,
|
|
757
|
+
spaceBefore: "240",
|
|
758
|
+
spaceAfter: "80",
|
|
759
|
+
uiPriority: 9
|
|
760
|
+
));
|
|
761
|
+
|
|
762
|
+
// ── ListBullet style ──
|
|
763
|
+
styles.Append(CreateParagraphStyle(
|
|
764
|
+
styleId: "ListBullet",
|
|
765
|
+
styleName: "List Bullet",
|
|
766
|
+
basedOn: "Normal",
|
|
767
|
+
uiPriority: 36
|
|
768
|
+
));
|
|
769
|
+
|
|
770
|
+
// ── Caption style ──
|
|
771
|
+
styles.Append(CreateCaptionStyle(
|
|
772
|
+
fontSizeHalfPts: "18", // 9pt
|
|
773
|
+
color: "7F8C8D",
|
|
774
|
+
italic: true
|
|
775
|
+
));
|
|
776
|
+
|
|
777
|
+
// ── Page setup: Letter, 1.25in margins ──
|
|
778
|
+
// Extra-wide margins = premium feel. The white space says "confidence."
|
|
779
|
+
var sectPr = new SectionProperties(
|
|
780
|
+
new WpPageSize { Width = 12240U, Height = 15840U },
|
|
781
|
+
new PageMargin
|
|
782
|
+
{
|
|
783
|
+
Top = 1800, Bottom = 1800, // 1.25in
|
|
784
|
+
Left = 1800U, Right = 1800U, // 1.25in
|
|
785
|
+
Header = 720U, Footer = 720U, Gutter = 0U
|
|
786
|
+
}
|
|
787
|
+
);
|
|
788
|
+
|
|
789
|
+
// ── Page numbers: bottom center, 8pt ──
|
|
790
|
+
AddPageNumberFooter(mainPart, sectPr,
|
|
791
|
+
alignment: JustificationValues.Center,
|
|
792
|
+
fontSizeHalfPts: "16", // 8pt — nearly invisible, as intended
|
|
793
|
+
color: "BFBFBF", // Very light gray — page numbers are utility
|
|
794
|
+
format: PageNumberFormat.Plain
|
|
795
|
+
);
|
|
796
|
+
|
|
797
|
+
// ── Sample content ──
|
|
798
|
+
AddSampleParagraph(body, "Q3 Performance Summary", "Heading1");
|
|
799
|
+
|
|
800
|
+
AddSampleParagraph(body, "Revenue exceeded targets across all segments. The strategic "
|
|
801
|
+
+ "realignment initiated in Q1 is now delivering measurable results. Key metrics "
|
|
802
|
+
+ "are trending positively with strong forward indicators.",
|
|
803
|
+
"Normal");
|
|
804
|
+
|
|
805
|
+
AddSampleParagraph(body, "Key Metrics", "Heading2");
|
|
806
|
+
|
|
807
|
+
AddSampleParagraph(body, "The following table summarizes performance against targets. "
|
|
808
|
+
+ "All figures are in millions USD unless otherwise noted.",
|
|
809
|
+
"Normal");
|
|
810
|
+
|
|
811
|
+
// ── Executive table: dark header row (#2C3E50 + white text), no other borders ──
|
|
812
|
+
body.Append(CreateExecutiveTable(
|
|
813
|
+
new[] { "Metric", "Target", "Actual", "Variance" },
|
|
814
|
+
new[]
|
|
815
|
+
{
|
|
816
|
+
new[] { "Revenue", "$52.0M", "$54.8M", "+5.4%" },
|
|
817
|
+
new[] { "EBITDA", "$12.5M", "$13.1M", "+4.8%" },
|
|
818
|
+
new[] { "Net Margin", "24%", "23.9%", "-0.1pp" }
|
|
819
|
+
}
|
|
820
|
+
));
|
|
821
|
+
|
|
822
|
+
AddSampleParagraph(body, "Strategic Outlook", "Heading2");
|
|
823
|
+
|
|
824
|
+
AddSampleParagraph(body, "Market conditions remain favorable heading into Q4. "
|
|
825
|
+
+ "The pipeline is robust with several high-value opportunities expected to close "
|
|
826
|
+
+ "before year-end.",
|
|
827
|
+
"Normal");
|
|
828
|
+
|
|
829
|
+
AddSampleParagraph(body, "Risk Factors", "Heading3");
|
|
830
|
+
|
|
831
|
+
AddSampleParagraph(body, "Currency headwinds and supply chain constraints represent "
|
|
832
|
+
+ "the primary downside risks. Mitigation strategies are in place for both scenarios.",
|
|
833
|
+
"Normal");
|
|
834
|
+
|
|
835
|
+
body.Append(sectPr);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/// <summary>
|
|
839
|
+
/// Executive table style: dark header row with white text, no other borders.
|
|
840
|
+
/// The inverted header creates immediate scanability. The borderless body
|
|
841
|
+
/// lets data breathe. This is the "less is more" school of data presentation.
|
|
842
|
+
/// </summary>
|
|
843
|
+
private static Table CreateExecutiveTable(string[] headers, string[][] data)
|
|
844
|
+
{
|
|
845
|
+
var table = new Table();
|
|
846
|
+
|
|
847
|
+
var tblPr = new TableProperties(
|
|
848
|
+
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
|
|
849
|
+
// No table-level borders at all — the header shading does the work
|
|
850
|
+
new TableBorders(
|
|
851
|
+
new TopBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
852
|
+
new BottomBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
853
|
+
new LeftBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
854
|
+
new RightBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
855
|
+
new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "E0E0E0" },
|
|
856
|
+
new InsideVerticalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" }
|
|
857
|
+
),
|
|
858
|
+
new TableCellMarginDefault(
|
|
859
|
+
new TopMargin { Width = "57", Type = TableWidthUnitValues.Dxa },
|
|
860
|
+
new StartMargin { Width = "85", Type = TableWidthUnitValues.Dxa },
|
|
861
|
+
new BottomMargin { Width = "57", Type = TableWidthUnitValues.Dxa },
|
|
862
|
+
new EndMargin { Width = "85", Type = TableWidthUnitValues.Dxa }
|
|
863
|
+
)
|
|
864
|
+
);
|
|
865
|
+
table.Append(tblPr);
|
|
866
|
+
|
|
867
|
+
// Grid
|
|
868
|
+
var grid = new TableGrid();
|
|
869
|
+
int colWidth = 9360 / headers.Length;
|
|
870
|
+
foreach (var _ in headers)
|
|
871
|
+
grid.Append(new GridColumn { Width = colWidth.ToString() });
|
|
872
|
+
table.Append(grid);
|
|
873
|
+
|
|
874
|
+
// Header row: dark background (#2C3E50) + white text
|
|
875
|
+
var headerRow = new TableRow();
|
|
876
|
+
foreach (var h in headers)
|
|
877
|
+
{
|
|
878
|
+
headerRow.Append(new TableCell(
|
|
879
|
+
new TableCellProperties(
|
|
880
|
+
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto },
|
|
881
|
+
new Shading
|
|
882
|
+
{
|
|
883
|
+
Val = ShadingPatternValues.Clear,
|
|
884
|
+
Color = "auto",
|
|
885
|
+
Fill = "2C3E50" // Dark blue-gray header
|
|
886
|
+
},
|
|
887
|
+
// Override borders for header cells
|
|
888
|
+
new TableCellBorders(
|
|
889
|
+
new TopBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
890
|
+
new BottomBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
891
|
+
new LeftBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
892
|
+
new RightBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" }
|
|
893
|
+
)
|
|
894
|
+
),
|
|
895
|
+
new Paragraph(
|
|
896
|
+
new ParagraphProperties(
|
|
897
|
+
new SpacingBetweenLines { After = "0" }
|
|
898
|
+
),
|
|
899
|
+
new Run(
|
|
900
|
+
new RunProperties(
|
|
901
|
+
new Bold(),
|
|
902
|
+
new Color { Val = "FFFFFF" }, // White text on dark header
|
|
903
|
+
new RunFonts { Ascii = "Helvetica Neue", HighAnsi = "Helvetica Neue" }
|
|
904
|
+
),
|
|
905
|
+
new Text(h)
|
|
906
|
+
)
|
|
907
|
+
)
|
|
908
|
+
));
|
|
909
|
+
}
|
|
910
|
+
table.Append(headerRow);
|
|
911
|
+
|
|
912
|
+
// Data rows: clean, no borders (only inside-H from table properties)
|
|
913
|
+
foreach (var rowData in data)
|
|
914
|
+
{
|
|
915
|
+
var row = new TableRow();
|
|
916
|
+
foreach (var cell in rowData)
|
|
917
|
+
{
|
|
918
|
+
row.Append(new TableCell(
|
|
919
|
+
new TableCellProperties(
|
|
920
|
+
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto }
|
|
921
|
+
),
|
|
922
|
+
new Paragraph(
|
|
923
|
+
new ParagraphProperties(
|
|
924
|
+
new SpacingBetweenLines { After = "0" }
|
|
925
|
+
),
|
|
926
|
+
new Run(new Text(cell))
|
|
927
|
+
)
|
|
928
|
+
));
|
|
929
|
+
}
|
|
930
|
+
table.Append(row);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
return table;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
938
|
+
// RECIPE 4: CHINESE GOVERNMENT (公文 GB/T 9704)
|
|
939
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
940
|
+
|
|
941
|
+
/// <summary>
|
|
942
|
+
/// Recipe: Chinese Government Document (公文)
|
|
943
|
+
/// Feel: Formal, standardized, authoritative.
|
|
944
|
+
/// Best for: Government announcements, official communications, regulatory documents.
|
|
945
|
+
///
|
|
946
|
+
/// Design rationale (based on GB/T 9704-2012 standard):
|
|
947
|
+
/// - 仿宋_GB2312 三号 (16pt): the mandated body font. FangSong is a calligraphic
|
|
948
|
+
/// style that balances formality with readability in Chinese typography.
|
|
949
|
+
/// - 小标宋 二号 (22pt): the mandated title font. 小标宋体 is a specialized display
|
|
950
|
+
/// serif used exclusively in government documents for titles.
|
|
951
|
+
/// - Fixed 28pt line spacing (line="560"): government standard ensures uniform
|
|
952
|
+
/// page density of 22 lines per page. Every page looks identical.
|
|
953
|
+
/// - Margins T:37mm B:35mm L:28mm R:26mm: per GB/T 9704 specification.
|
|
954
|
+
/// Asymmetric left-right margins account for binding.
|
|
955
|
+
/// - Page size A4: Chinese government standard (unlike US Letter).
|
|
956
|
+
/// - All black text, no decorative elements: government documents derive
|
|
957
|
+
/// authority from standardization, not from visual design.
|
|
958
|
+
/// - Page numbers: bottom center, "-X-" format (e.g., "-3-") per standard.
|
|
959
|
+
/// - 28 chars per line, 22 lines per page: the density specification.
|
|
960
|
+
/// </summary>
|
|
961
|
+
public static void CreateChineseGovernmentDocument(string outputPath)
|
|
962
|
+
{
|
|
963
|
+
using var doc = WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document);
|
|
964
|
+
|
|
965
|
+
var mainPart = doc.AddMainDocumentPart();
|
|
966
|
+
mainPart.Document = new Document(new Body());
|
|
967
|
+
var body = mainPart.Document.Body!;
|
|
968
|
+
|
|
969
|
+
// ── Styles ──
|
|
970
|
+
var stylesPart = mainPart.AddNewPart<StyleDefinitionsPart>();
|
|
971
|
+
stylesPart.Styles = new Styles();
|
|
972
|
+
var styles = stylesPart.Styles;
|
|
973
|
+
|
|
974
|
+
// DocDefaults: 仿宋 16pt (三号), fixed 28pt line spacing
|
|
975
|
+
styles.Append(new DocDefaults(
|
|
976
|
+
new RunPropertiesDefault(
|
|
977
|
+
new RunPropertiesBaseStyle(
|
|
978
|
+
new RunFonts
|
|
979
|
+
{
|
|
980
|
+
// 仿宋_GB2312 is the standard; 仿宋 is the fallback on modern systems
|
|
981
|
+
Ascii = "FangSong",
|
|
982
|
+
HighAnsi = "FangSong",
|
|
983
|
+
EastAsia = "FangSong_GB2312",
|
|
984
|
+
ComplexScript = "FangSong"
|
|
985
|
+
},
|
|
986
|
+
new FontSize { Val = "32" }, // 16pt = 三号 (in half-points)
|
|
987
|
+
new FontSizeComplexScript { Val = "32" },
|
|
988
|
+
new Color { Val = "000000" },
|
|
989
|
+
new Languages { Val = "en-US", EastAsia = "zh-CN" }
|
|
990
|
+
)
|
|
991
|
+
),
|
|
992
|
+
new ParagraphPropertiesDefault(
|
|
993
|
+
new ParagraphPropertiesBaseStyle(
|
|
994
|
+
new SpacingBetweenLines
|
|
995
|
+
{
|
|
996
|
+
// Fixed 28pt line spacing per GB/T 9704
|
|
997
|
+
// 28pt * 20 = 560 DXA (line units in exact mode)
|
|
998
|
+
Line = "560",
|
|
999
|
+
LineRule = LineSpacingRuleValues.Exact,
|
|
1000
|
+
After = "0",
|
|
1001
|
+
Before = "0"
|
|
1002
|
+
}
|
|
1003
|
+
)
|
|
1004
|
+
)
|
|
1005
|
+
));
|
|
1006
|
+
|
|
1007
|
+
// ── Normal style ──
|
|
1008
|
+
styles.Append(CreateParagraphStyle(
|
|
1009
|
+
styleId: "Normal",
|
|
1010
|
+
styleName: "Normal",
|
|
1011
|
+
isDefault: true,
|
|
1012
|
+
uiPriority: 0
|
|
1013
|
+
));
|
|
1014
|
+
|
|
1015
|
+
// ── Title style (小标宋 二号 22pt) ──
|
|
1016
|
+
// Government document title uses a specialized display serif font.
|
|
1017
|
+
// 二号 = 22pt = 44 half-points.
|
|
1018
|
+
var titleStyle = new Style(
|
|
1019
|
+
new StyleName { Val = "heading 1" },
|
|
1020
|
+
new BasedOn { Val = "Normal" },
|
|
1021
|
+
new NextParagraphStyle { Val = "Normal" },
|
|
1022
|
+
new UIPriority { Val = 9 },
|
|
1023
|
+
new PrimaryStyle(),
|
|
1024
|
+
new StyleParagraphProperties(
|
|
1025
|
+
new KeepNext(),
|
|
1026
|
+
new KeepLines(),
|
|
1027
|
+
new Justification { Val = JustificationValues.Center },
|
|
1028
|
+
new SpacingBetweenLines
|
|
1029
|
+
{
|
|
1030
|
+
Line = "560", LineRule = LineSpacingRuleValues.Exact,
|
|
1031
|
+
Before = "0", After = "0"
|
|
1032
|
+
},
|
|
1033
|
+
new OutlineLevel { Val = 0 }
|
|
1034
|
+
),
|
|
1035
|
+
new StyleRunProperties(
|
|
1036
|
+
new RunFonts
|
|
1037
|
+
{
|
|
1038
|
+
// 小标宋体 is the government standard for titles.
|
|
1039
|
+
// Falls back to 华文中宋 or SimSun on systems without it.
|
|
1040
|
+
Ascii = "SimSun",
|
|
1041
|
+
HighAnsi = "SimSun",
|
|
1042
|
+
EastAsia = "FZXiaoBiaoSong-B05S",
|
|
1043
|
+
ComplexScript = "SimSun"
|
|
1044
|
+
},
|
|
1045
|
+
new FontSize { Val = "44" }, // 22pt = 二号
|
|
1046
|
+
new FontSizeComplexScript { Val = "44" },
|
|
1047
|
+
new Color { Val = "000000" }
|
|
1048
|
+
)
|
|
1049
|
+
)
|
|
1050
|
+
{ Type = StyleValues.Paragraph, StyleId = "Heading1", Default = false };
|
|
1051
|
+
styles.Append(titleStyle);
|
|
1052
|
+
|
|
1053
|
+
// ── Heading 2: 黑体 三号 (16pt) ──
|
|
1054
|
+
// 黑体 (SimHei) is the standard sans-serif for first-level section headings.
|
|
1055
|
+
var h2Style = new Style(
|
|
1056
|
+
new StyleName { Val = "heading 2" },
|
|
1057
|
+
new BasedOn { Val = "Normal" },
|
|
1058
|
+
new NextParagraphStyle { Val = "Normal" },
|
|
1059
|
+
new UIPriority { Val = 9 },
|
|
1060
|
+
new PrimaryStyle(),
|
|
1061
|
+
new StyleParagraphProperties(
|
|
1062
|
+
new KeepNext(),
|
|
1063
|
+
new KeepLines(),
|
|
1064
|
+
new SpacingBetweenLines
|
|
1065
|
+
{
|
|
1066
|
+
Line = "560", LineRule = LineSpacingRuleValues.Exact,
|
|
1067
|
+
Before = "0", After = "0"
|
|
1068
|
+
},
|
|
1069
|
+
new OutlineLevel { Val = 1 }
|
|
1070
|
+
),
|
|
1071
|
+
new StyleRunProperties(
|
|
1072
|
+
new RunFonts
|
|
1073
|
+
{
|
|
1074
|
+
Ascii = "SimHei",
|
|
1075
|
+
HighAnsi = "SimHei",
|
|
1076
|
+
EastAsia = "SimHei",
|
|
1077
|
+
ComplexScript = "SimHei"
|
|
1078
|
+
},
|
|
1079
|
+
new FontSize { Val = "32" }, // 16pt = 三号
|
|
1080
|
+
new FontSizeComplexScript { Val = "32" },
|
|
1081
|
+
new Color { Val = "000000" }
|
|
1082
|
+
)
|
|
1083
|
+
)
|
|
1084
|
+
{ Type = StyleValues.Paragraph, StyleId = "Heading2", Default = false };
|
|
1085
|
+
styles.Append(h2Style);
|
|
1086
|
+
|
|
1087
|
+
// ── Heading 3: 楷体 三号 (16pt) ──
|
|
1088
|
+
// 楷体 (KaiTi) for second-level section headings.
|
|
1089
|
+
var h3Style = new Style(
|
|
1090
|
+
new StyleName { Val = "heading 3" },
|
|
1091
|
+
new BasedOn { Val = "Normal" },
|
|
1092
|
+
new NextParagraphStyle { Val = "Normal" },
|
|
1093
|
+
new UIPriority { Val = 9 },
|
|
1094
|
+
new PrimaryStyle(),
|
|
1095
|
+
new StyleParagraphProperties(
|
|
1096
|
+
new KeepNext(),
|
|
1097
|
+
new KeepLines(),
|
|
1098
|
+
new SpacingBetweenLines
|
|
1099
|
+
{
|
|
1100
|
+
Line = "560", LineRule = LineSpacingRuleValues.Exact,
|
|
1101
|
+
Before = "0", After = "0"
|
|
1102
|
+
},
|
|
1103
|
+
new OutlineLevel { Val = 2 }
|
|
1104
|
+
),
|
|
1105
|
+
new StyleRunProperties(
|
|
1106
|
+
new RunFonts
|
|
1107
|
+
{
|
|
1108
|
+
Ascii = "KaiTi",
|
|
1109
|
+
HighAnsi = "KaiTi",
|
|
1110
|
+
EastAsia = "KaiTi_GB2312",
|
|
1111
|
+
ComplexScript = "KaiTi"
|
|
1112
|
+
},
|
|
1113
|
+
new FontSize { Val = "32" }, // 16pt = 三号
|
|
1114
|
+
new FontSizeComplexScript { Val = "32" },
|
|
1115
|
+
new Color { Val = "000000" }
|
|
1116
|
+
)
|
|
1117
|
+
)
|
|
1118
|
+
{ Type = StyleValues.Paragraph, StyleId = "Heading3", Default = false };
|
|
1119
|
+
styles.Append(h3Style);
|
|
1120
|
+
|
|
1121
|
+
// ── ListBullet style ──
|
|
1122
|
+
styles.Append(CreateParagraphStyle(
|
|
1123
|
+
styleId: "ListBullet",
|
|
1124
|
+
styleName: "List Bullet",
|
|
1125
|
+
basedOn: "Normal",
|
|
1126
|
+
uiPriority: 36
|
|
1127
|
+
));
|
|
1128
|
+
|
|
1129
|
+
// ── Caption style ──
|
|
1130
|
+
styles.Append(CreateCaptionStyle(
|
|
1131
|
+
fontSizeHalfPts: "32", // 三号 per standard
|
|
1132
|
+
color: "000000",
|
|
1133
|
+
italic: false // Chinese government docs do not use italic
|
|
1134
|
+
));
|
|
1135
|
+
|
|
1136
|
+
// ── Page setup: A4, GB/T 9704 margins ──
|
|
1137
|
+
// A4 = 210mm x 297mm = 11906 x 16838 DXA
|
|
1138
|
+
// Margins per GB/T 9704: T:37mm B:35mm L:28mm R:26mm
|
|
1139
|
+
// T: 37mm = 37 * 56.7 ≈ 2098 DXA
|
|
1140
|
+
// B: 35mm = 35 * 56.7 ≈ 1984 DXA
|
|
1141
|
+
// L: 28mm = 28 * 56.7 ≈ 1588 DXA
|
|
1142
|
+
// R: 26mm = 26 * 56.7 ≈ 1474 DXA
|
|
1143
|
+
var sectPr = new SectionProperties(
|
|
1144
|
+
new WpPageSize { Width = 11906U, Height = 16838U },
|
|
1145
|
+
new PageMargin
|
|
1146
|
+
{
|
|
1147
|
+
Top = 2098, Bottom = 1984,
|
|
1148
|
+
Left = 1588U, Right = 1474U,
|
|
1149
|
+
Header = 720U, Footer = 720U, Gutter = 0U
|
|
1150
|
+
}
|
|
1151
|
+
);
|
|
1152
|
+
|
|
1153
|
+
// ── Page numbers: bottom center, "-X-" format, 宋体 四号 (14pt) ──
|
|
1154
|
+
AddPageNumberFooter(mainPart, sectPr,
|
|
1155
|
+
alignment: JustificationValues.Center,
|
|
1156
|
+
fontSizeHalfPts: "28", // 14pt = 四号
|
|
1157
|
+
color: "000000",
|
|
1158
|
+
format: PageNumberFormat.DashSurrounded, // -X- format
|
|
1159
|
+
fontName: "SimSun" // 宋体 for page numbers
|
|
1160
|
+
);
|
|
1161
|
+
|
|
1162
|
+
// ── Sample content ──
|
|
1163
|
+
// Government document title
|
|
1164
|
+
body.Append(new Paragraph(
|
|
1165
|
+
new ParagraphProperties(
|
|
1166
|
+
new ParagraphStyleId { Val = "Heading1" }
|
|
1167
|
+
),
|
|
1168
|
+
new Run(new Text("关于加强文档排版规范化管理的通知"))
|
|
1169
|
+
));
|
|
1170
|
+
|
|
1171
|
+
// Body text
|
|
1172
|
+
body.Append(new Paragraph(
|
|
1173
|
+
new Run(new Text("各有关单位:") { Space = SpaceProcessingModeValues.Preserve })
|
|
1174
|
+
));
|
|
1175
|
+
|
|
1176
|
+
body.Append(new Paragraph(
|
|
1177
|
+
new ParagraphProperties(
|
|
1178
|
+
new Indentation { FirstLine = "640" } // 2 Chinese characters = 640 DXA at 16pt
|
|
1179
|
+
),
|
|
1180
|
+
new Run(new Text("为进一步规范公文格式,提高公文质量,根据《党政机关公文格式》"
|
|
1181
|
+
+ "(GB/T 9704-2012)的有关规定,现就加强文档排版规范化管理有关事项通知如下。"))
|
|
1182
|
+
));
|
|
1183
|
+
|
|
1184
|
+
body.Append(new Paragraph(
|
|
1185
|
+
new ParagraphProperties(
|
|
1186
|
+
new ParagraphStyleId { Val = "Heading2" }
|
|
1187
|
+
),
|
|
1188
|
+
new Run(new Text("一、总体要求"))
|
|
1189
|
+
));
|
|
1190
|
+
|
|
1191
|
+
body.Append(new Paragraph(
|
|
1192
|
+
new ParagraphProperties(
|
|
1193
|
+
new Indentation { FirstLine = "640" }
|
|
1194
|
+
),
|
|
1195
|
+
new Run(new Text("各单位应严格按照国家标准规定的格式要求制作公文,"
|
|
1196
|
+
+ "确保公文格式统一、规范、美观。公文用纸统一采用A4型纸,"
|
|
1197
|
+
+ "正文使用仿宋体三号字,行间距为固定值28磅。"))
|
|
1198
|
+
));
|
|
1199
|
+
|
|
1200
|
+
body.Append(new Paragraph(
|
|
1201
|
+
new ParagraphProperties(
|
|
1202
|
+
new ParagraphStyleId { Val = "Heading3" }
|
|
1203
|
+
),
|
|
1204
|
+
new Run(new Text("(一)字体要求"))
|
|
1205
|
+
));
|
|
1206
|
+
|
|
1207
|
+
body.Append(new Paragraph(
|
|
1208
|
+
new ParagraphProperties(
|
|
1209
|
+
new Indentation { FirstLine = "640" }
|
|
1210
|
+
),
|
|
1211
|
+
new Run(new Text("标题使用小标宋体二号字,一级标题使用黑体三号字,"
|
|
1212
|
+
+ "二级标题使用楷体三号字,正文使用仿宋体三号字。"))
|
|
1213
|
+
));
|
|
1214
|
+
|
|
1215
|
+
// ── Three-line table (三线表 is also used in Chinese government documents) ──
|
|
1216
|
+
body.Append(CreateThreeLineTable(
|
|
1217
|
+
new[] { "项目", "要求", "字体", "字号" },
|
|
1218
|
+
new[]
|
|
1219
|
+
{
|
|
1220
|
+
new[] { "标题", "居中", "小标宋体", "二号" },
|
|
1221
|
+
new[] { "一级标题", "左对齐", "黑体", "三号" },
|
|
1222
|
+
new[] { "二级标题", "左对齐", "楷体", "三号" },
|
|
1223
|
+
new[] { "正文", "两端对齐", "仿宋体", "三号" }
|
|
1224
|
+
}
|
|
1225
|
+
));
|
|
1226
|
+
|
|
1227
|
+
body.Append(sectPr);
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
|
|
1231
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
1232
|
+
// RECIPE 5: MINIMAL MODERN
|
|
1233
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
1234
|
+
|
|
1235
|
+
/// <summary>
|
|
1236
|
+
/// Recipe: Minimal Modern
|
|
1237
|
+
/// Feel: Scandinavian-inspired, lots of white space, geometric.
|
|
1238
|
+
/// Best for: Design documents, creative briefs, tech company communications.
|
|
1239
|
+
///
|
|
1240
|
+
/// Design rationale:
|
|
1241
|
+
/// - Inter/Segoe UI 10.5pt body: a geometric sans-serif designed for screens.
|
|
1242
|
+
/// 10.5pt is slightly smaller than standard, creating a more designed, intentional
|
|
1243
|
+
/// feel. The precision of geometric sans-serifs communicates clarity of thought.
|
|
1244
|
+
/// - H1 24pt light weight: large but thin creates a "whisper, don't shout" hierarchy.
|
|
1245
|
+
/// The size difference does the work; bold weight would be crude.
|
|
1246
|
+
/// - 1.5x line spacing (360 line units): very generous. Combined with 10.5pt body,
|
|
1247
|
+
/// this creates the characteristic "Scandinavian" feel of lots of air.
|
|
1248
|
+
/// - 12pt paragraph spacing: each paragraph is a distinct visual block separated
|
|
1249
|
+
/// by substantial white space. This supports the "one idea per paragraph" pattern.
|
|
1250
|
+
/// - 1.5in left/right margins: extreme horizontal compression creates a narrow
|
|
1251
|
+
/// text column (~5.5in wide, ~65 characters per line). This is the optimal
|
|
1252
|
+
/// line length for comfortable reading (60-75 chars).
|
|
1253
|
+
/// - #111111 headings, #444444 body: very slight differentiation. The hierarchy
|
|
1254
|
+
/// comes from size and weight, not color. This is the "less contrast, more
|
|
1255
|
+
/// sophistication" school.
|
|
1256
|
+
/// - #0066CC accent blue: a single accent color for interactive elements or emphasis.
|
|
1257
|
+
/// - Tables: header-only bottom border, nothing else. Maximum minimalism.
|
|
1258
|
+
/// </summary>
|
|
1259
|
+
public static void CreateMinimalModernDocument(string outputPath)
|
|
1260
|
+
{
|
|
1261
|
+
using var doc = WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document);
|
|
1262
|
+
|
|
1263
|
+
var mainPart = doc.AddMainDocumentPart();
|
|
1264
|
+
mainPart.Document = new Document(new Body());
|
|
1265
|
+
var body = mainPart.Document.Body!;
|
|
1266
|
+
|
|
1267
|
+
// ── Styles ──
|
|
1268
|
+
var stylesPart = mainPart.AddNewPart<StyleDefinitionsPart>();
|
|
1269
|
+
stylesPart.Styles = new Styles();
|
|
1270
|
+
var styles = stylesPart.Styles;
|
|
1271
|
+
|
|
1272
|
+
// DocDefaults: Inter/Segoe UI 10.5pt, very generous spacing
|
|
1273
|
+
styles.Append(new DocDefaults(
|
|
1274
|
+
new RunPropertiesDefault(
|
|
1275
|
+
new RunPropertiesBaseStyle(
|
|
1276
|
+
new RunFonts
|
|
1277
|
+
{
|
|
1278
|
+
// Inter is a Google Fonts geometric sans-serif designed for screens.
|
|
1279
|
+
// Segoe UI is the Windows system font fallback.
|
|
1280
|
+
Ascii = "Inter",
|
|
1281
|
+
HighAnsi = "Inter",
|
|
1282
|
+
EastAsia = "Microsoft YaHei",
|
|
1283
|
+
ComplexScript = "Segoe UI"
|
|
1284
|
+
},
|
|
1285
|
+
new FontSize { Val = "21" }, // 10.5pt — intentionally precise
|
|
1286
|
+
new FontSizeComplexScript { Val = "21" },
|
|
1287
|
+
new Color { Val = "444444" }, // Medium gray body — soft and modern
|
|
1288
|
+
new Languages { Val = "en-US", EastAsia = "zh-CN" }
|
|
1289
|
+
)
|
|
1290
|
+
),
|
|
1291
|
+
new ParagraphPropertiesDefault(
|
|
1292
|
+
new ParagraphPropertiesBaseStyle(
|
|
1293
|
+
new SpacingBetweenLines
|
|
1294
|
+
{
|
|
1295
|
+
// 1.5x line spacing: generous air for the minimal aesthetic.
|
|
1296
|
+
// Combined with narrow column width, this creates comfortable reading.
|
|
1297
|
+
Line = "360",
|
|
1298
|
+
LineRule = LineSpacingRuleValues.Auto,
|
|
1299
|
+
After = "240" // 12pt after — very generous paragraph separation
|
|
1300
|
+
}
|
|
1301
|
+
)
|
|
1302
|
+
)
|
|
1303
|
+
));
|
|
1304
|
+
|
|
1305
|
+
// ── Normal style ──
|
|
1306
|
+
styles.Append(CreateParagraphStyle(
|
|
1307
|
+
styleId: "Normal",
|
|
1308
|
+
styleName: "Normal",
|
|
1309
|
+
isDefault: true,
|
|
1310
|
+
uiPriority: 0
|
|
1311
|
+
));
|
|
1312
|
+
|
|
1313
|
+
// ── Heading 1: 24pt light ──
|
|
1314
|
+
// "Light" weight creates elegant, airy hierarchy. The size alone does the work.
|
|
1315
|
+
// Since OpenXML doesn't have a "light" weight, we achieve this by not using bold.
|
|
1316
|
+
// On systems with Inter, the regular weight already appears relatively light.
|
|
1317
|
+
styles.Append(CreateHeadingStyle(
|
|
1318
|
+
level: 1,
|
|
1319
|
+
fontAscii: "Inter",
|
|
1320
|
+
fontHAnsi: "Inter",
|
|
1321
|
+
sizeHalfPts: "48", // 24pt — large but not bold = "whispering loudly"
|
|
1322
|
+
color: "111111", // Near-black — just barely softened
|
|
1323
|
+
bold: false, // NO bold: the key to the minimal aesthetic
|
|
1324
|
+
spaceBefore: "480",
|
|
1325
|
+
spaceAfter: "120",
|
|
1326
|
+
uiPriority: 9
|
|
1327
|
+
));
|
|
1328
|
+
|
|
1329
|
+
// ── Heading 2: 16pt regular ──
|
|
1330
|
+
styles.Append(CreateHeadingStyle(
|
|
1331
|
+
level: 2,
|
|
1332
|
+
fontAscii: "Inter",
|
|
1333
|
+
fontHAnsi: "Inter",
|
|
1334
|
+
sizeHalfPts: "32", // 16pt
|
|
1335
|
+
color: "111111",
|
|
1336
|
+
bold: false,
|
|
1337
|
+
spaceBefore: "360",
|
|
1338
|
+
spaceAfter: "80",
|
|
1339
|
+
uiPriority: 9
|
|
1340
|
+
));
|
|
1341
|
+
|
|
1342
|
+
// ── Heading 3: 12pt medium ──
|
|
1343
|
+
// "Medium" is between regular and bold. We use bold here as the closest
|
|
1344
|
+
// approximation in OpenXML (true medium weight requires theme fonts).
|
|
1345
|
+
styles.Append(CreateHeadingStyle(
|
|
1346
|
+
level: 3,
|
|
1347
|
+
fontAscii: "Inter",
|
|
1348
|
+
fontHAnsi: "Inter",
|
|
1349
|
+
sizeHalfPts: "24", // 12pt
|
|
1350
|
+
color: "111111",
|
|
1351
|
+
bold: true, // Approximates "medium" weight
|
|
1352
|
+
spaceBefore: "240",
|
|
1353
|
+
spaceAfter: "80",
|
|
1354
|
+
uiPriority: 9
|
|
1355
|
+
));
|
|
1356
|
+
|
|
1357
|
+
// ── ListBullet style ──
|
|
1358
|
+
styles.Append(CreateParagraphStyle(
|
|
1359
|
+
styleId: "ListBullet",
|
|
1360
|
+
styleName: "List Bullet",
|
|
1361
|
+
basedOn: "Normal",
|
|
1362
|
+
uiPriority: 36
|
|
1363
|
+
));
|
|
1364
|
+
|
|
1365
|
+
// ── Caption style ──
|
|
1366
|
+
styles.Append(CreateCaptionStyle(
|
|
1367
|
+
fontSizeHalfPts: "18", // 9pt
|
|
1368
|
+
color: "999999",
|
|
1369
|
+
italic: false // Minimal style avoids italic
|
|
1370
|
+
));
|
|
1371
|
+
|
|
1372
|
+
// ── Page setup: Letter, wide left/right margins, normal top/bottom ──
|
|
1373
|
+
// Wide L/R margins create a narrow text column (~5.5in = ~65 chars per line).
|
|
1374
|
+
// This is the optimal line length for comfortable reading.
|
|
1375
|
+
var sectPr = new SectionProperties(
|
|
1376
|
+
new WpPageSize { Width = 12240U, Height = 15840U },
|
|
1377
|
+
new PageMargin
|
|
1378
|
+
{
|
|
1379
|
+
Top = 1440, Bottom = 1440, // 1in top/bottom
|
|
1380
|
+
Left = 2160U, Right = 2160U, // 1.5in left/right — narrow column
|
|
1381
|
+
Header = 720U, Footer = 720U, Gutter = 0U
|
|
1382
|
+
}
|
|
1383
|
+
);
|
|
1384
|
+
|
|
1385
|
+
// ── No page numbers for the minimal aesthetic ──
|
|
1386
|
+
// In production, add page numbers only if document exceeds 5 pages.
|
|
1387
|
+
// For this sample, we omit them entirely — the cleanest look.
|
|
1388
|
+
|
|
1389
|
+
// ── Sample content ──
|
|
1390
|
+
AddSampleParagraph(body, "Design System", "Heading1");
|
|
1391
|
+
|
|
1392
|
+
AddSampleParagraph(body, "A design system is a collection of reusable components "
|
|
1393
|
+
+ "and clear standards that can be assembled to build any number of applications. "
|
|
1394
|
+
+ "It reduces redundancy, creates consistency, and enables teams to build faster.",
|
|
1395
|
+
"Normal");
|
|
1396
|
+
|
|
1397
|
+
AddSampleParagraph(body, "Typography", "Heading2");
|
|
1398
|
+
|
|
1399
|
+
AddSampleParagraph(body, "Typography is the foundation of any design system. "
|
|
1400
|
+
+ "The type scale, spacing, and color choices establish the visual rhythm "
|
|
1401
|
+
+ "that all other elements follow.",
|
|
1402
|
+
"Normal");
|
|
1403
|
+
|
|
1404
|
+
AddSampleParagraph(body, "Type Scale", "Heading3");
|
|
1405
|
+
|
|
1406
|
+
AddSampleParagraph(body, "Our type scale uses a 1.5x ratio, creating clear "
|
|
1407
|
+
+ "hierarchy without excessive size variation. Each level is visually distinct "
|
|
1408
|
+
+ "yet feels part of a cohesive family.",
|
|
1409
|
+
"Normal");
|
|
1410
|
+
|
|
1411
|
+
// ── Minimal table: header bottom border only ──
|
|
1412
|
+
body.Append(CreateMinimalTable(
|
|
1413
|
+
new[] { "Token", "Value", "Usage" },
|
|
1414
|
+
new[]
|
|
1415
|
+
{
|
|
1416
|
+
new[] { "font-size-xs", "10.5pt", "Captions, metadata" },
|
|
1417
|
+
new[] { "font-size-sm", "12pt", "Secondary text" },
|
|
1418
|
+
new[] { "font-size-base", "10.5pt", "Body text" },
|
|
1419
|
+
new[] { "font-size-lg", "16pt", "Section headings" },
|
|
1420
|
+
new[] { "font-size-xl", "24pt", "Page titles" }
|
|
1421
|
+
}
|
|
1422
|
+
));
|
|
1423
|
+
|
|
1424
|
+
AddSampleParagraph(body, "Table 1 — Type scale tokens", "Caption");
|
|
1425
|
+
|
|
1426
|
+
AddSampleParagraph(body, "Color", "Heading2");
|
|
1427
|
+
|
|
1428
|
+
AddSampleParagraph(body, "Our palette is intentionally restrained. Two grays "
|
|
1429
|
+
+ "for text hierarchy, one accent blue for interactive elements, and generous "
|
|
1430
|
+
+ "white space as the primary design element.",
|
|
1431
|
+
"Normal");
|
|
1432
|
+
|
|
1433
|
+
body.Append(sectPr);
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
/// <summary>
|
|
1437
|
+
/// Minimal table: only the header row gets a bottom border.
|
|
1438
|
+
/// Everything else is borderless. Maximum restraint.
|
|
1439
|
+
/// The alignment and spacing do all the structural work.
|
|
1440
|
+
/// </summary>
|
|
1441
|
+
private static Table CreateMinimalTable(string[] headers, string[][] data)
|
|
1442
|
+
{
|
|
1443
|
+
var table = new Table();
|
|
1444
|
+
|
|
1445
|
+
var tblPr = new TableProperties(
|
|
1446
|
+
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
|
|
1447
|
+
// No borders at all at the table level
|
|
1448
|
+
new TableBorders(
|
|
1449
|
+
new TopBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
1450
|
+
new BottomBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
1451
|
+
new LeftBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
1452
|
+
new RightBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
1453
|
+
new InsideHorizontalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" },
|
|
1454
|
+
new InsideVerticalBorder { Val = BorderValues.None, Size = 0, Space = 0, Color = "auto" }
|
|
1455
|
+
),
|
|
1456
|
+
new TableCellMarginDefault(
|
|
1457
|
+
new TopMargin { Width = "40", Type = TableWidthUnitValues.Dxa },
|
|
1458
|
+
new StartMargin { Width = "57", Type = TableWidthUnitValues.Dxa },
|
|
1459
|
+
new BottomMargin { Width = "40", Type = TableWidthUnitValues.Dxa },
|
|
1460
|
+
new EndMargin { Width = "57", Type = TableWidthUnitValues.Dxa }
|
|
1461
|
+
)
|
|
1462
|
+
);
|
|
1463
|
+
table.Append(tblPr);
|
|
1464
|
+
|
|
1465
|
+
// Grid
|
|
1466
|
+
var grid = new TableGrid();
|
|
1467
|
+
int colWidth = 7920 / headers.Length; // narrower text area due to wide margins
|
|
1468
|
+
foreach (var _ in headers)
|
|
1469
|
+
grid.Append(new GridColumn { Width = colWidth.ToString() });
|
|
1470
|
+
table.Append(grid);
|
|
1471
|
+
|
|
1472
|
+
// Header row: only element with a visible border (bottom only)
|
|
1473
|
+
var headerRow = new TableRow();
|
|
1474
|
+
foreach (var h in headers)
|
|
1475
|
+
{
|
|
1476
|
+
headerRow.Append(new TableCell(
|
|
1477
|
+
new TableCellProperties(
|
|
1478
|
+
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto },
|
|
1479
|
+
new TableCellBorders(
|
|
1480
|
+
// Single thin bottom border — the only line in the entire table
|
|
1481
|
+
new BottomBorder { Val = BorderValues.Single, Size = 4, Space = 0, Color = "CCCCCC" }
|
|
1482
|
+
)
|
|
1483
|
+
),
|
|
1484
|
+
new Paragraph(
|
|
1485
|
+
new ParagraphProperties(
|
|
1486
|
+
new SpacingBetweenLines { After = "0" }
|
|
1487
|
+
),
|
|
1488
|
+
new Run(
|
|
1489
|
+
new RunProperties(
|
|
1490
|
+
new Color { Val = "111111" } // Slightly darker than body
|
|
1491
|
+
),
|
|
1492
|
+
new Text(h)
|
|
1493
|
+
)
|
|
1494
|
+
)
|
|
1495
|
+
));
|
|
1496
|
+
}
|
|
1497
|
+
table.Append(headerRow);
|
|
1498
|
+
|
|
1499
|
+
// Data rows: completely borderless
|
|
1500
|
+
foreach (var rowData in data)
|
|
1501
|
+
{
|
|
1502
|
+
var row = new TableRow();
|
|
1503
|
+
foreach (var cell in rowData)
|
|
1504
|
+
{
|
|
1505
|
+
row.Append(new TableCell(
|
|
1506
|
+
new TableCellProperties(
|
|
1507
|
+
new TableCellWidth { Width = "0", Type = TableWidthUnitValues.Auto }
|
|
1508
|
+
),
|
|
1509
|
+
new Paragraph(
|
|
1510
|
+
new ParagraphProperties(
|
|
1511
|
+
new SpacingBetweenLines { After = "0" }
|
|
1512
|
+
),
|
|
1513
|
+
new Run(new Text(cell))
|
|
1514
|
+
)
|
|
1515
|
+
));
|
|
1516
|
+
}
|
|
1517
|
+
table.Append(row);
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
return table;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
|
|
1524
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
1525
|
+
// SHARED HELPER METHODS
|
|
1526
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
1527
|
+
|
|
1528
|
+
/// <summary>
|
|
1529
|
+
/// Creates a basic paragraph style with minimal configuration.
|
|
1530
|
+
/// Used for Normal, ListBullet, and other simple styles.
|
|
1531
|
+
/// </summary>
|
|
1532
|
+
private static Style CreateParagraphStyle(
|
|
1533
|
+
string styleId,
|
|
1534
|
+
string styleName,
|
|
1535
|
+
bool isDefault = false,
|
|
1536
|
+
string? basedOn = null,
|
|
1537
|
+
int uiPriority = 0)
|
|
1538
|
+
{
|
|
1539
|
+
var style = new Style(
|
|
1540
|
+
new StyleName { Val = styleName },
|
|
1541
|
+
new UIPriority { Val = uiPriority },
|
|
1542
|
+
new PrimaryStyle()
|
|
1543
|
+
)
|
|
1544
|
+
{
|
|
1545
|
+
Type = StyleValues.Paragraph,
|
|
1546
|
+
StyleId = styleId,
|
|
1547
|
+
Default = isDefault ? true : false
|
|
1548
|
+
};
|
|
1549
|
+
|
|
1550
|
+
if (basedOn != null)
|
|
1551
|
+
style.Append(new BasedOn { Val = basedOn });
|
|
1552
|
+
|
|
1553
|
+
return style;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
/// <summary>
|
|
1557
|
+
/// Creates a heading style with full formatting configuration.
|
|
1558
|
+
/// All heading styles are based on "Normal" (not chained H2→H1)
|
|
1559
|
+
/// because each heading level has completely different formatting.
|
|
1560
|
+
/// </summary>
|
|
1561
|
+
private static Style CreateHeadingStyle(
|
|
1562
|
+
int level,
|
|
1563
|
+
string fontAscii,
|
|
1564
|
+
string fontHAnsi,
|
|
1565
|
+
string sizeHalfPts,
|
|
1566
|
+
string color,
|
|
1567
|
+
bool bold,
|
|
1568
|
+
string spaceBefore,
|
|
1569
|
+
string spaceAfter,
|
|
1570
|
+
int uiPriority)
|
|
1571
|
+
{
|
|
1572
|
+
var rPr = new StyleRunProperties(
|
|
1573
|
+
new RunFonts
|
|
1574
|
+
{
|
|
1575
|
+
Ascii = fontAscii,
|
|
1576
|
+
HighAnsi = fontHAnsi,
|
|
1577
|
+
EastAsia = "SimSun",
|
|
1578
|
+
ComplexScript = fontAscii
|
|
1579
|
+
},
|
|
1580
|
+
new FontSize { Val = sizeHalfPts },
|
|
1581
|
+
new FontSizeComplexScript { Val = sizeHalfPts },
|
|
1582
|
+
new Color { Val = color }
|
|
1583
|
+
);
|
|
1584
|
+
|
|
1585
|
+
if (bold)
|
|
1586
|
+
rPr.Append(new Bold());
|
|
1587
|
+
|
|
1588
|
+
var style = new Style(
|
|
1589
|
+
new StyleName { Val = $"heading {level}" },
|
|
1590
|
+
new BasedOn { Val = "Normal" },
|
|
1591
|
+
new NextParagraphStyle { Val = "Normal" },
|
|
1592
|
+
new UIPriority { Val = uiPriority },
|
|
1593
|
+
new PrimaryStyle(),
|
|
1594
|
+
new StyleParagraphProperties(
|
|
1595
|
+
new KeepNext(), // Don't orphan a heading at page bottom
|
|
1596
|
+
new KeepLines(), // Don't split a heading across pages
|
|
1597
|
+
new SpacingBetweenLines
|
|
1598
|
+
{
|
|
1599
|
+
Before = spaceBefore,
|
|
1600
|
+
After = spaceAfter
|
|
1601
|
+
},
|
|
1602
|
+
new OutlineLevel { Val = level - 1 } // OutlineLevel is 0-based
|
|
1603
|
+
),
|
|
1604
|
+
rPr
|
|
1605
|
+
)
|
|
1606
|
+
{
|
|
1607
|
+
Type = StyleValues.Paragraph,
|
|
1608
|
+
StyleId = $"Heading{level}",
|
|
1609
|
+
Default = false
|
|
1610
|
+
};
|
|
1611
|
+
|
|
1612
|
+
return style;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
/// <summary>
|
|
1616
|
+
/// Creates an APA-style heading where hierarchy is expressed through
|
|
1617
|
+
/// bold/italic/centering rather than font size changes.
|
|
1618
|
+
/// All headings remain 12pt — the same as body text.
|
|
1619
|
+
/// </summary>
|
|
1620
|
+
private static Style CreateAcademicHeadingStyle(
|
|
1621
|
+
int level,
|
|
1622
|
+
string sizeHalfPts,
|
|
1623
|
+
bool bold,
|
|
1624
|
+
bool italic,
|
|
1625
|
+
bool centered,
|
|
1626
|
+
string spaceBefore,
|
|
1627
|
+
string spaceAfter)
|
|
1628
|
+
{
|
|
1629
|
+
var rPr = new StyleRunProperties(
|
|
1630
|
+
new RunFonts
|
|
1631
|
+
{
|
|
1632
|
+
Ascii = "Times New Roman",
|
|
1633
|
+
HighAnsi = "Times New Roman",
|
|
1634
|
+
EastAsia = "SimSun",
|
|
1635
|
+
ComplexScript = "Times New Roman"
|
|
1636
|
+
},
|
|
1637
|
+
new FontSize { Val = sizeHalfPts },
|
|
1638
|
+
new FontSizeComplexScript { Val = sizeHalfPts },
|
|
1639
|
+
new Color { Val = "000000" }
|
|
1640
|
+
);
|
|
1641
|
+
|
|
1642
|
+
if (bold)
|
|
1643
|
+
rPr.Append(new Bold());
|
|
1644
|
+
if (italic)
|
|
1645
|
+
rPr.Append(new Italic());
|
|
1646
|
+
|
|
1647
|
+
var pPr = new StyleParagraphProperties(
|
|
1648
|
+
new KeepNext(),
|
|
1649
|
+
new KeepLines(),
|
|
1650
|
+
new SpacingBetweenLines
|
|
1651
|
+
{
|
|
1652
|
+
Before = spaceBefore,
|
|
1653
|
+
After = spaceAfter,
|
|
1654
|
+
Line = "480",
|
|
1655
|
+
LineRule = LineSpacingRuleValues.Auto
|
|
1656
|
+
},
|
|
1657
|
+
// No first-line indent for headings
|
|
1658
|
+
new Indentation { FirstLine = "0" },
|
|
1659
|
+
new OutlineLevel { Val = level - 1 }
|
|
1660
|
+
);
|
|
1661
|
+
|
|
1662
|
+
if (centered)
|
|
1663
|
+
pPr.Append(new Justification { Val = JustificationValues.Center });
|
|
1664
|
+
|
|
1665
|
+
var style = new Style(
|
|
1666
|
+
new StyleName { Val = $"heading {level}" },
|
|
1667
|
+
new BasedOn { Val = "Normal" },
|
|
1668
|
+
new NextParagraphStyle { Val = "Normal" },
|
|
1669
|
+
new UIPriority { Val = 9 },
|
|
1670
|
+
new PrimaryStyle(),
|
|
1671
|
+
pPr,
|
|
1672
|
+
rPr
|
|
1673
|
+
)
|
|
1674
|
+
{
|
|
1675
|
+
Type = StyleValues.Paragraph,
|
|
1676
|
+
StyleId = $"Heading{level}",
|
|
1677
|
+
Default = false
|
|
1678
|
+
};
|
|
1679
|
+
|
|
1680
|
+
return style;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
/// <summary>
|
|
1684
|
+
/// Creates a Caption style used below tables and figures.
|
|
1685
|
+
/// Captions are typically smaller and/or italic to visually subordinate them.
|
|
1686
|
+
/// </summary>
|
|
1687
|
+
private static Style CreateCaptionStyle(
|
|
1688
|
+
string fontSizeHalfPts,
|
|
1689
|
+
string color,
|
|
1690
|
+
bool italic)
|
|
1691
|
+
{
|
|
1692
|
+
var rPr = new StyleRunProperties(
|
|
1693
|
+
new FontSize { Val = fontSizeHalfPts },
|
|
1694
|
+
new FontSizeComplexScript { Val = fontSizeHalfPts },
|
|
1695
|
+
new Color { Val = color }
|
|
1696
|
+
);
|
|
1697
|
+
|
|
1698
|
+
if (italic)
|
|
1699
|
+
rPr.Append(new Italic());
|
|
1700
|
+
|
|
1701
|
+
return new Style(
|
|
1702
|
+
new StyleName { Val = "caption" },
|
|
1703
|
+
new BasedOn { Val = "Normal" },
|
|
1704
|
+
new UIPriority { Val = 35 },
|
|
1705
|
+
new PrimaryStyle(),
|
|
1706
|
+
new StyleParagraphProperties(
|
|
1707
|
+
new SpacingBetweenLines { After = "120" }
|
|
1708
|
+
),
|
|
1709
|
+
rPr
|
|
1710
|
+
)
|
|
1711
|
+
{
|
|
1712
|
+
Type = StyleValues.Paragraph,
|
|
1713
|
+
StyleId = "Caption",
|
|
1714
|
+
Default = false
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
/// <summary>
|
|
1719
|
+
/// Page number format options.
|
|
1720
|
+
/// </summary>
|
|
1721
|
+
private enum PageNumberFormat
|
|
1722
|
+
{
|
|
1723
|
+
/// <summary>Plain number: "1", "2", "3"</summary>
|
|
1724
|
+
Plain,
|
|
1725
|
+
/// <summary>Dash-surrounded: "-1-", "-2-", "-3-" (Chinese government standard)</summary>
|
|
1726
|
+
DashSurrounded
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
/// <summary>
|
|
1730
|
+
/// Adds a footer (or header) with page numbers to the document.
|
|
1731
|
+
///
|
|
1732
|
+
/// Page numbers use the PAGE simple field code. The footer/header is linked
|
|
1733
|
+
/// to the section via a FooterReference/HeaderReference in SectionProperties.
|
|
1734
|
+
///
|
|
1735
|
+
/// Architecture:
|
|
1736
|
+
/// 1. Create a FooterPart (or HeaderPart) on the MainDocumentPart
|
|
1737
|
+
/// 2. Add the page number content (Paragraph with SimpleField)
|
|
1738
|
+
/// 3. Get the relationship ID
|
|
1739
|
+
/// 4. Add FooterReference (or HeaderReference) to SectionProperties
|
|
1740
|
+
/// </summary>
|
|
1741
|
+
private static void AddPageNumberFooter(
|
|
1742
|
+
MainDocumentPart mainPart,
|
|
1743
|
+
SectionProperties sectPr,
|
|
1744
|
+
JustificationValues alignment,
|
|
1745
|
+
string fontSizeHalfPts,
|
|
1746
|
+
string color,
|
|
1747
|
+
PageNumberFormat format,
|
|
1748
|
+
bool isHeader = false,
|
|
1749
|
+
string? fontName = null)
|
|
1750
|
+
{
|
|
1751
|
+
var runProps = new RunProperties(
|
|
1752
|
+
new FontSize { Val = fontSizeHalfPts },
|
|
1753
|
+
new FontSizeComplexScript { Val = fontSizeHalfPts },
|
|
1754
|
+
new Color { Val = color }
|
|
1755
|
+
);
|
|
1756
|
+
|
|
1757
|
+
if (fontName != null)
|
|
1758
|
+
runProps.Append(new RunFonts { Ascii = fontName, HighAnsi = fontName, EastAsia = fontName });
|
|
1759
|
+
|
|
1760
|
+
// Build the paragraph content based on format
|
|
1761
|
+
var paragraph = new Paragraph(
|
|
1762
|
+
new ParagraphProperties(
|
|
1763
|
+
new Justification { Val = alignment }
|
|
1764
|
+
)
|
|
1765
|
+
);
|
|
1766
|
+
|
|
1767
|
+
if (format == PageNumberFormat.DashSurrounded)
|
|
1768
|
+
{
|
|
1769
|
+
// "-X-" format: literal dash + PAGE field + literal dash
|
|
1770
|
+
paragraph.Append(new Run(
|
|
1771
|
+
(RunProperties)runProps.CloneNode(true),
|
|
1772
|
+
new Text("-") { Space = SpaceProcessingModeValues.Preserve }
|
|
1773
|
+
));
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
// PAGE field — inserts the current page number
|
|
1777
|
+
paragraph.Append(new SimpleField(
|
|
1778
|
+
new Run((RunProperties)runProps.CloneNode(true), new Text("1"))
|
|
1779
|
+
)
|
|
1780
|
+
{ Instruction = " PAGE " });
|
|
1781
|
+
|
|
1782
|
+
if (format == PageNumberFormat.DashSurrounded)
|
|
1783
|
+
{
|
|
1784
|
+
paragraph.Append(new Run(
|
|
1785
|
+
(RunProperties)runProps.CloneNode(true),
|
|
1786
|
+
new Text("-") { Space = SpaceProcessingModeValues.Preserve }
|
|
1787
|
+
));
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
if (isHeader)
|
|
1791
|
+
{
|
|
1792
|
+
// Add as header
|
|
1793
|
+
var headerPart = mainPart.AddNewPart<HeaderPart>();
|
|
1794
|
+
headerPart.Header = new Header(paragraph);
|
|
1795
|
+
headerPart.Header.Save();
|
|
1796
|
+
|
|
1797
|
+
string headerPartId = mainPart.GetIdOfPart(headerPart);
|
|
1798
|
+
sectPr.Append(new HeaderReference
|
|
1799
|
+
{
|
|
1800
|
+
Type = HeaderFooterValues.Default,
|
|
1801
|
+
Id = headerPartId
|
|
1802
|
+
});
|
|
1803
|
+
}
|
|
1804
|
+
else
|
|
1805
|
+
{
|
|
1806
|
+
// Add as footer
|
|
1807
|
+
var footerPart = mainPart.AddNewPart<FooterPart>();
|
|
1808
|
+
footerPart.Footer = new Footer(paragraph);
|
|
1809
|
+
footerPart.Footer.Save();
|
|
1810
|
+
|
|
1811
|
+
string footerPartId = mainPart.GetIdOfPart(footerPart);
|
|
1812
|
+
sectPr.Append(new FooterReference
|
|
1813
|
+
{
|
|
1814
|
+
Type = HeaderFooterValues.Default,
|
|
1815
|
+
Id = footerPartId
|
|
1816
|
+
});
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
/// <summary>
|
|
1821
|
+
/// Helper to add a paragraph with a specific style.
|
|
1822
|
+
/// </summary>
|
|
1823
|
+
private static void AddSampleParagraph(Body body, string text, string styleId)
|
|
1824
|
+
{
|
|
1825
|
+
body.Append(new Paragraph(
|
|
1826
|
+
new ParagraphProperties(
|
|
1827
|
+
new ParagraphStyleId { Val = styleId }
|
|
1828
|
+
),
|
|
1829
|
+
new Run(new Text(text))
|
|
1830
|
+
));
|
|
1831
|
+
}
|
|
1832
|
+
}
|