From d5d282c418b5322e08d11b57357c718551761a18 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Tue, 22 Apr 2025 16:41:18 +0800 Subject: [PATCH] Support preview --- .../app/VoloDocs.Web/VoloDocsWebModule.cs | 2 +- .../DocsDocumentPdfGeneratorController.cs | 6 ++- .../Pdf/DocsDocumentPdfGeneratorOptions.cs | 38 +++++++++++++---- .../Documents/Pdf/DocumentPdfGenerator.cs | 41 +++++++++++-------- .../Documents/Pdf/IText/ITextPdfRenderer.cs | 4 +- 5 files changed, 61 insertions(+), 30 deletions(-) diff --git a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs index a0996f51df..8702ac6500 100644 --- a/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs +++ b/modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs @@ -178,7 +178,7 @@ namespace VoloDocs.Web Configure(options => { options.BaseUrl = configuration["App:selfUrl"]; - options.CoverPagePath = "Index.md"; + options.IndexPagePath = "Index.md"; }); Configure(options => diff --git a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs index bfd5be9224..31ae2a2f44 100644 --- a/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs +++ b/modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs @@ -23,8 +23,10 @@ public class DocsDocumentPdfGeneratorController : DocsControllerBase, IDocumentP [HttpGet] [Route("pdf")] - public Task GeneratePdfAsync(DocumentPdfGeneratorInput input) + public async Task GeneratePdfAsync(DocumentPdfGeneratorInput input) { - return DocumentPdfGeneratorAppService.GeneratePdfAsync(input); + var streamContent = await DocumentPdfGeneratorAppService.GeneratePdfAsync(input); + Response.Headers.ContentDisposition = $"inline; filename=\"{streamContent.FileName}\""; + return streamContent; } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs index 0b9dcfcca6..59a25628ae 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs @@ -12,14 +12,34 @@ public class DocsDocumentPdfGeneratorOptions /// The HTML layout for the PDF document. /// public string HtmlLayout { get; set; } - public string HtmlStyles { get; set; } + + /// + /// The HTML style for the PDF document. + /// + public string HtmlStyle { get; set; } + + /// + /// The base URL for the PDF document. + /// Used for resolving relative links and images. + /// public string BaseUrl { get; set; } - public string CoverPagePath { get; set; } - public TimeSpan PdfFileCacheExpiration { get; set; } = TimeSpan.FromDays(1); - public Func CalculatePdfFileName { get; set; } = (project, version, languageCode) => - { - return $"{project.ShortName}_{version}_{languageCode}.pdf"; - }; + + /// + /// The path to the index page of the documentation. + /// + public string IndexPagePath { get; set; } + + /// + /// PDF file cache expiration time. + /// Default value is 24 hours. + /// + public TimeSpan PdfFileCacheExpiration { get; set; } = TimeSpan.FromHours(24); + + /// + /// The function to calculate the PDF file name. + /// Default is "{project.ShortName}_{version}_{languageCode}.pdf". + /// + public Func CalculatePdfFileName { get; set; } public DocsDocumentPdfGeneratorOptions() { @@ -36,7 +56,7 @@ public class DocsDocumentPdfGeneratorOptions "; - HtmlStyles = @" + HtmlStyle = @" body { margin: 20px; line-height: 1.6; font-family: Arial, sans-serif;} a { text-decoration: none; } .page { @@ -73,5 +93,7 @@ public class DocsDocumentPdfGeneratorOptions padding: 10px 20px; background: #f8fafc; }"; + + CalculatePdfFileName = (project, version, languageCode) => $"{project.ShortName}_{version}_{languageCode}.pdf"; } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs index f9b8185602..caa3dd38ff 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs @@ -115,7 +115,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency string languageCode, PdfDocumentNode parentPdfDocumentNode = null) { - var parameterCombinationsDocuments = new List(); + var groupedCombinationsDocuments = new Dictionary>(); foreach (var navigation in navigations) { if (navigation.IgnoreOnDownload) @@ -127,7 +127,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency var pdfDocumentNode = new PdfDocumentNode { Title = navigation.Text, - IgnoreOnOutline = navigation.Path == Options.Value.CoverPagePath + IgnoreOnOutline = navigation.Path == Options.Value.IndexPagePath }; if (!navigation.Path.IsNullOrWhiteSpace() && !navigation.HasChildItems) @@ -145,14 +145,20 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency if(parameters.Count <= 1) { - AddParameterCombinationsDocuments(parentPdfDocumentNode, parameterCombinationsDocuments); + AddParameterCombinationsDocuments(parentPdfDocumentNode, groupedCombinationsDocuments); } else { for (var i = 1; i < parameterCombinations.Count; i++) { var parameterCombination = parameterCombinations[i]; - parameterCombinationsDocuments.Add(new PdfDocumentNode + var key = parameterCombination.Select(x => $"{x.Key}_{x.Value}").JoinAsString("-"); + if (!groupedCombinationsDocuments.ContainsKey(key)) + { + groupedCombinationsDocuments[key] = []; + } + + groupedCombinationsDocuments[key].Add(new PdfDocumentNode { Document = document, Title = GetDocumentTitle(navigation.Text, document.Content, parameterCombination), @@ -179,7 +185,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency if (navigation == navigations.Last()) { - AddParameterCombinationsDocuments(parentPdfDocumentNode, parameterCombinationsDocuments); + AddParameterCombinationsDocuments(parentPdfDocumentNode, groupedCombinationsDocuments); } } catch (Exception e) @@ -189,15 +195,18 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency } } - private void AddParameterCombinationsDocuments(PdfDocumentNode parentPdfDocumentNode, List parameterCombinationsDocuments) + private void AddParameterCombinationsDocuments(PdfDocumentNode parentPdfDocumentNode, Dictionary> groupedCombinationsDocuments) { - if (parentPdfDocumentNode == null) - { - AllPdfDocumentNodes.AddRange(parameterCombinationsDocuments); - } - else - { - parentPdfDocumentNode.Children.AddRange(parameterCombinationsDocuments); + foreach (var combinations in groupedCombinationsDocuments) + { + if (parentPdfDocumentNode == null) + { + AllPdfDocumentNodes.AddRange(combinations.Value); + } + else + { + parentPdfDocumentNode.Children.AddRange(combinations.Value); + } } } @@ -218,11 +227,11 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency throw new UserFriendlyException($"Cannot validate navigation file '{project.NavigationDocumentName}' for the project {project.Name}."); } - if (!Options.Value.CoverPagePath.IsNullOrWhiteSpace()) + if (!Options.Value.IndexPagePath.IsNullOrWhiteSpace()) { navigation.Items.Insert(0, new NavigationNode { - Path = Options.Value.CoverPagePath + Path = Options.Value.IndexPagePath }); } @@ -376,7 +385,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency private string NormalizeMarkdownContent(string content) { - var pattern = @"````json\s*//$begin:math:display$doc-nav$end:math:display$[\s\S]*?````"; + var pattern = @"`{3,4}json\s*//\[doc-nav\][\s\S]*?`{3,4}"; return Regex.Replace(content, pattern, string.Empty, RegexOptions.IgnoreCase); } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs index 133d8b008f..2634a34724 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs @@ -31,15 +31,13 @@ public class ITextPdfRenderer : IPdfRenderer ,ITransientDependency var htmlBuilder = new StringBuilder(); htmlBuilder.Append(Options.Value.HtmlLayout); - htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.StylePlaceholder, Options.Value.HtmlStyles); + htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.StylePlaceholder, Options.Value.HtmlStyle); htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.ContentPlaceholder, htmlContent); var converter = new ConverterProperties(); var tagWorkerFactory = new HtmlIdTagWorkerFactory(pdfDocument); converter.SetTagWorkerFactory(tagWorkerFactory); - - await File.WriteAllTextAsync("/Users/liangshiweis/codes/test.html", htmlBuilder.ToString()); HtmlConverter.ConvertToDocument(htmlBuilder.ToString(), pdfDocument, converter); tagWorkerFactory.AddNamedDestinations();