Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions samples/seed/articles/toc.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pdfFileName: seed.pdf
pdfCoverPage: ../pdf.html
items:
- name: Getting Started
href: docfx_getting_started.md
Expand Down
17 changes: 17 additions & 0 deletions samples/seed/pdf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<style>
@media print {
@page {
margin: 0 !important;
}
body {
-webkit-print-color-adjust: exact;
-moz-print-color-adjust: exact;
-ms-print-color-adjust: exact;
print-color-adjust: exact;
}
}
</style>
<div style='background-color: green; width: 100%; height: 100%; display: flex; flex-direction: column'>
<p style='flex: 1'></p>
<h1 style='align-self: end; margin: 1rem 2rem; color: antiquewhite'>DOCFX PDF SAMPLE</h1>
</div>
52 changes: 32 additions & 20 deletions src/Docfx.App/PdfBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ class Outline

public bool pdf { get; init; }
public string? pdfFileName { get; init; }
public string? pdfMargin { get; init; }
public bool pdfPrintBackground { get; init; }
public string? pdfCoverPage { get; init; }
}

public static Task Run(BuildJsonConfig config, string configDirectory, string? outputDirectory = null)
Expand Down Expand Up @@ -111,24 +110,22 @@ static async Task CreatePdf(IBrowser browser, Uri outlineUrl, Outline outline, s
var pageNumbers = new Dictionary<Outline, int>();
var nextPageNumbers = new Dictionary<Outline, int>();
var nextPageNumber = 1;
var margin = outline.pdfMargin ?? "0.4in";

await AnsiConsole.Progress().Columns(new SpinnerColumn(), new TaskDescriptionColumn { Alignment = Justify.Left }).StartAsync(async c =>
{
await Parallel.ForEachAsync(pages, async (item, CancellationToken) =>
{
var task = c.AddTask(item.url.PathAndQuery);
var page = await browser.NewPageAsync();
await page.GotoAsync(item.url.ToString());
var response = await page.GotoAsync(item.url.ToString());
if (response is null || !response.Ok)
throw new InvalidOperationException($"Failed to build PDF page [{response?.Status}]: {item.url}");

await page.AddScriptTagAsync(new() { Content = EnsureHeadingAnchorScript });
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
var bytes = await page.PdfAsync(new()
{
PrintBackground = outline.pdfPrintBackground,
Margin = new() { Bottom = margin, Top = margin, Left = margin, Right = margin },
});
var bytes = await page.PdfAsync();
File.WriteAllBytes(item.path, bytes);
task.Value = task.MaxValue;
task.StopTask();
});
});

Expand All @@ -137,21 +134,33 @@ await Parallel.ForEachAsync(pages, async (item, CancellationToken) =>

IEnumerable<(string path, Uri url, Outline node)> GetPages(Outline outline)
{
if (!string.IsNullOrEmpty(outline.pdfCoverPage))
{
var url = new Uri(outlineUrl, outline.pdfCoverPage);
if (url.Host == outlineUrl.Host)
yield return (GetFilePath(url), url, new() { href = outline.pdfCoverPage });
}

if (!string.IsNullOrEmpty(outline.href))
{
var url = new Uri(outlineUrl, outline.href);
if (url.Host == outlineUrl.Host)
{
var id = Convert.ToHexString(SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(url.ToString()))).Substring(0, 6).ToLower();
var name = Regex.Replace(url.PathAndQuery, "\\W", "-").Trim('-');
yield return (Path.Combine(tempDirectory, $"{name}-{id}.pdf"), url, outline);
}
yield return (GetFilePath(url), url, outline);
}

if (outline.items != null)
{
foreach (var item in outline.items)
foreach (var url in GetPages(item))
yield return url;
}
}

string GetFilePath(Uri url)
{
var id = Convert.ToHexString(SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(url.ToString()))).Substring(0, 6).ToLower();
var name = Regex.Replace(url.PathAndQuery, "\\W", "-").Trim('-');
return Path.Combine(tempDirectory, $"{name}-{id}.pdf");
}

void MergePdf()
Expand Down Expand Up @@ -254,11 +263,14 @@ IEnumerable<BookmarkNode> CreateBookmarks(Outline[]? items, int level = 0)
continue;
}

nextPageNumber = nextPageNumbers[item];
yield return new DocumentBookmarkNode(
item.name, level,
new(pageNumbers[item], ExplicitDestinationType.XyzCoordinates, ExplicitDestinationCoordinates.Empty),
CreateBookmarks(item.items, level + 1).ToArray());
if (!string.IsNullOrEmpty(item.name))
{
nextPageNumber = nextPageNumbers[item];
yield return new DocumentBookmarkNode(
item.name, level,
new(pageNumbers[item], ExplicitDestinationType.XyzCoordinates, ExplicitDestinationCoordinates.Empty),
CreateBookmarks(item.items, level + 1).ToArray());
}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions templates/modern/src/docfx.scss
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,9 @@ article {
display: none;
}
}

@media print {
@page {
margin: .4in;
}
}
10 changes: 10 additions & 0 deletions templates/modern/src/layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,18 @@ body[data-layout="landing"] {
padding-bottom: $main-padding-bottom;

>.content {
display: flex;
flex-direction: column;
width: 100%;

>:not(article) {
display: none;
}

>article {
flex: 1;
}

@include media-breakpoint-up(md) {
>article [id] {
scroll-margin-top: $header-height;
Expand All @@ -89,6 +95,10 @@ body[data-layout="landing"] {
}

@media print {
>main {
padding: 0 !important;
}

>header, >footer {
display: none;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
}
],
"pdfFileName": "seed.pdf",
"pdfCoverPage": "../pdf.html",
"_appName": "Seed",
"_appTitle": "docfx seed website",
"_enableSearch": true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"content": "{\"items\":[{\"name\":\"Getting Started\",\"href\":\"docfx_getting_started.html\",\"topicHref\":\"docfx_getting_started.html\"},{\"name\":\"Engineering Docs\",\"items\":[{\"name\":\"Section 1\"},{\"name\":\"Engineering Guidelines\",\"href\":\"engineering_guidelines.html\",\"topicHref\":\"engineering_guidelines.html\"},{\"name\":\"CSharp Coding Standards\",\"href\":\"csharp_coding_standards.html\",\"topicHref\":\"csharp_coding_standards.html\"}],\"expanded\":true},{\"name\":\"Markdown\",\"href\":\"markdown.html\",\"topicHref\":\"markdown.html\"},{\"name\":\"Microsoft Docs\",\"href\":\"https://docs.microsoft.com/en-us/\",\"topicHref\":\"https://docs.microsoft.com/en-us/\"}],\"pdfFileName\":\"seed.pdf\",\"pdf\":true}"
"content": "{\"items\":[{\"name\":\"Getting Started\",\"href\":\"docfx_getting_started.html\",\"topicHref\":\"docfx_getting_started.html\"},{\"name\":\"Engineering Docs\",\"items\":[{\"name\":\"Section 1\"},{\"name\":\"Engineering Guidelines\",\"href\":\"engineering_guidelines.html\",\"topicHref\":\"engineering_guidelines.html\"},{\"name\":\"CSharp Coding Standards\",\"href\":\"csharp_coding_standards.html\",\"topicHref\":\"csharp_coding_standards.html\"}],\"expanded\":true},{\"name\":\"Markdown\",\"href\":\"markdown.html\",\"topicHref\":\"markdown.html\"},{\"name\":\"Microsoft Docs\",\"href\":\"https://docs.microsoft.com/en-us/\",\"topicHref\":\"https://docs.microsoft.com/en-us/\"}],\"pdfFileName\":\"seed.pdf\",\"pdfCoverPage\":\"../pdf.html\",\"pdf\":true}"
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@
}
],
"pdfFileName": "seed.pdf",
"pdfCoverPage": "../pdf.html",
"pdf": true
}
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,11 @@
"title": "Namespace MRef | docfx seed website",
"keywords": "Namespace MRef Namespaces MRef.Demo"
},
"pdf.html": {
"href": "pdf.html",
"title": "DOCFX PDF SAMPLE | docfx seed website",
"keywords": "@media print { @page { margin: 0 !important; } body { -webkit-print-color-adjust: exact; -moz-print-color-adjust: exact; -ms-print-color-adjust: exact; print-color-adjust: exact; } } DOCFX PDF SAMPLE"
},
"restapi/contacts.html": {
"href": "restapi/contacts.html",
"title": "Contacts | docfx seed website",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"conceptual": "<style> \n@media print {\n @page {\n margin: 0 !important;\n }\n body {\n -webkit-print-color-adjust: exact;\n -moz-print-color-adjust: exact;\n -ms-print-color-adjust: exact;\n print-color-adjust: exact;\n }\n}\n</style>\n<div style='background-color: green; width: 100%; height: 100%; display: flex; flex-direction: column'>\n <p style='flex: 1'></p>\n <h1 style='align-self: end; margin: 1rem 2rem; color: antiquewhite'>DOCFX PDF SAMPLE</h1>\n</div>\n",
"type": "Conceptual",
"source": {
"remote": {
"path": "samples/seed/pdf.md",
"branch": "main",
"repo": "https://github.com/dotnet/docfx"
},
"startLine": 0.0,
"endLine": 0.0
},
"path": "pdf.md",
"documentation": {
"remote": {
"path": "samples/seed/pdf.md",
"branch": "main",
"repo": "https://github.com/dotnet/docfx"
},
"startLine": 0.0,
"endLine": 0.0
},
"_appName": "Seed",
"_appTitle": "docfx seed website",
"_enableSearch": true,
"pdf": true,
"rawTitle": "",
"title": "DOCFX PDF SAMPLE",
"wordCount": 3.0,
"_key": "pdf.md",
"_navKey": "~/toc.yml",
"_navPath": "toc.html",
"_navRel": "toc.html",
"_path": "pdf.html",
"_rel": "",
"_tocKey": "~/toc.yml",
"_tocPath": "toc.html",
"_tocRel": "toc.html",
"_disableToc": true,
"docurl": "https://github.com/dotnet/docfx/blob/main/samples/seed/pdf.md/#L1"
}