From 953673d805715d71c184b7237868619321f27a81 Mon Sep 17 00:00:00 2001 From: Salih Date: Tue, 6 Feb 2024 10:09:06 +0300 Subject: [PATCH] Better navigation to "Next Step" in the documentation --- .../HtmlConverting/DocumentNavigationDto.cs | 7 ++ .../HtmlConverting/DocumentNavigationsDto.cs | 7 ++ .../IDocumentSectionRenderer.cs | 2 + .../ScribanDocumentSectionRenderer.cs | 75 +++++++++++++------ .../Pages/Documents/Project/Index.cshtml.cs | 18 +++++ 5 files changed, 87 insertions(+), 22 deletions(-) create mode 100644 modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationDto.cs create mode 100644 modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationsDto.cs diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationDto.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationDto.cs new file mode 100644 index 0000000000..bcfbdb5a25 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationDto.cs @@ -0,0 +1,7 @@ +namespace Volo.Docs.HtmlConverting; + +public class DocumentNavigationDto +{ + public string Name { get; set; } + public string Path { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationsDto.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationsDto.cs new file mode 100644 index 0000000000..ccee9b5d18 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationsDto.cs @@ -0,0 +1,7 @@ +namespace Volo.Docs.HtmlConverting; + +public class DocumentNavigationsDto +{ + public DocumentNavigationDto Previous { get; set; } + public DocumentNavigationDto Next { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs index 0738b4fd5c..73560a7273 100644 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs @@ -11,5 +11,7 @@ namespace Volo.Docs.HtmlConverting Task>> GetAvailableParametersAsync(string document); Task> GetPartialTemplatesInDocumentAsync(string documentContent); + + Task GetDocumentNavigationsAsync(string documentContent); } } diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs index 1ade06aa26..b28e42d611 100644 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs @@ -17,6 +17,7 @@ namespace Volo.Docs.HtmlConverting private const string JsonCloser = "````"; private const string DocsParam = "//[doc-params]"; private const string DocsTemplates = "//[doc-template]"; + private const string DocsNav = "//[doc-nav]"; public ILogger Logger { get; set; } @@ -41,7 +42,7 @@ namespace Volo.Docs.HtmlConverting var result = await scribanTemplate.RenderAsync(parameters); - return RemoveOptionsJson(result); + return RemoveOptionsJson(result, DocsParam, DocsNav); } public async Task>> GetAvailableParametersAsync(string document) @@ -53,7 +54,7 @@ namespace Volo.Docs.HtmlConverting return new Dictionary>(); } - var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection) = GetJsonBeginEndIndexesAndPureJson(document); + var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection) = GetJsonBeginEndIndexesAndPureJson(document, DocsParam); if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) { @@ -76,36 +77,42 @@ namespace Volo.Docs.HtmlConverting } } - private static string RemoveOptionsJson(string document) + private static string RemoveOptionsJson(string document, params string[] sectionNames) { - var orgDocument = document; - try + foreach (var sectionName in sectionNames) { - if (!document.Contains(JsonOpener) || !document.Contains(DocsParam)) + var orgDocument = document; + + try { - return orgDocument; - } + if (!document.Contains(JsonOpener) || !document.Contains(sectionName)) + { + continue; + } - var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection) = GetJsonBeginEndIndexesAndPureJson(document); + var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection) = GetJsonBeginEndIndexesAndPureJson(document, sectionName); - if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) + if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) + { + continue; + } + + document = document.Remove( + jsonBeginningIndex - JsonOpener.Length, + (jsonEndingIndex + JsonCloser.Length) - (jsonBeginningIndex - JsonOpener.Length) + ); + } + catch (Exception) { - return orgDocument; + document = orgDocument; } - - return document.Remove( - jsonBeginningIndex - JsonOpener.Length, - (jsonEndingIndex + JsonCloser.Length) - (jsonBeginningIndex - JsonOpener.Length) - ); - } - catch (Exception) - { - return orgDocument; } + + return document; } - private static (int, int, string) GetJsonBeginEndIndexesAndPureJson(string document) + private static (int, int, string) GetJsonBeginEndIndexesAndPureJson(string document, string sectionName) { var searchedIndex = 0; @@ -121,7 +128,7 @@ namespace Volo.Docs.HtmlConverting var jsonEndingIndex = document.Substring(jsonBeginningIndex).IndexOf(JsonCloser, StringComparison.Ordinal) + jsonBeginningIndex; var insideJsonSection = document[jsonBeginningIndex..jsonEndingIndex]; - if (insideJsonSection.IndexOf(DocsParam, StringComparison.Ordinal) < 0) + if (insideJsonSection.IndexOf(sectionName, StringComparison.Ordinal) < 0) { searchedIndex = jsonEndingIndex + JsonCloser.Length; continue; @@ -169,6 +176,30 @@ namespace Volo.Docs.HtmlConverting return await Task.FromResult(templates); } + public Task GetDocumentNavigationsAsync(string documentContent) + { + if (!documentContent.Contains(JsonOpener) || !documentContent.Contains(DocsNav)) + { + return Task.FromResult(new DocumentNavigationsDto()); + } + + var (jsonBeginningIndex, jsonEndingIndex, insideJsonSection) = GetJsonBeginEndIndexesAndPureJson(documentContent, DocsNav); + + if (jsonBeginningIndex < 0 || jsonEndingIndex <= 0 || string.IsNullOrWhiteSpace(insideJsonSection)) + { + return Task.FromResult(new DocumentNavigationsDto()); + } + + var pureJson = insideJsonSection.Replace(DocsNav, "").Trim(); + + if (!DocsJsonSerializerHelper.TryDeserialize(pureJson, out var navigationDocumentNames)) + { + throw new UserFriendlyException("ERROR-20200327: Cannot validate JSON content for `NavigationDocumentNames`!"); + } + + return Task.FromResult(navigationDocumentNames); + } + private static string SetPartialTemplates(string document, IReadOnlyCollection templates) { var newDocument = new StringBuilder(); diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs index 0ffa883d8d..05bc45b1b0 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs @@ -82,6 +82,8 @@ namespace Volo.Docs.Pages.Documents.Project public bool FullSearchEnabled { get; set; } public bool IsLatestVersion { get; private set; } + + public DocumentNavigationsDto DocumentNavigationsDto { get; private set; } private const int MaxDescriptionMetaTagLength = 200; private readonly IDocumentAppService _documentAppService; @@ -239,6 +241,20 @@ namespace Volo.Docs.Pages.Documents.Project DocumentsUrlPrefix + LanguageCode + "/" + ProjectName + "/" + DocsAppConsts.Latest + "/" + DocumentName; } + + public string CreateDocumentLink(string documentName) + { + return new StringBuilder() + .Append(DocumentsUrlPrefix) + .Append(LanguageCode) + .Append('/') + .Append(ProjectName) + .Append('/') + .Append(LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Version) + .Append('/') + .Append(documentName) + .ToString(); + } private IActionResult RedirectToDefaultLanguage() { @@ -508,6 +524,8 @@ namespace Volo.Docs.Pages.Documents.Project SetUserPreferences(); var partialTemplates = await GetDocumentPartialTemplatesAsync(); + + DocumentNavigationsDto = await _documentSectionRenderer.GetDocumentNavigationsAsync(Document.Content); Document.Content = await _documentSectionRenderer.RenderAsync(Document.Content, UserPreferences, partialTemplates); }