From 953673d805715d71c184b7237868619321f27a81 Mon Sep 17 00:00:00 2001 From: Salih Date: Tue, 6 Feb 2024 10:09:06 +0300 Subject: [PATCH 1/8] 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); } From 3c1b92772edbfb48718ecf63fc71b4962dc57a53 Mon Sep 17 00:00:00 2001 From: Salih Date: Mon, 12 Feb 2024 14:11:42 +0300 Subject: [PATCH 2/8] Add design --- ...ng-Started-Create-Solution-Single-Layer.md | 20 ++++++++--- .../HtmlConverting/DocumentNavigationsDto.cs | 6 ++++ .../Pages/Documents/Project/Index.cshtml | 24 +++++++++++++ .../Pages/Documents/Project/Index.css.map | 1 + .../Pages/Documents/Project/Index.min.css.map | 1 + .../Pages/Documents/Project/index.css | 34 ++++++++++++++++--- .../Pages/Documents/Project/index.min.css | 2 +- .../Pages/Documents/Project/index.scss | 29 +++++++++++++++- 8 files changed, 106 insertions(+), 11 deletions(-) create mode 100644 modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.css.map create mode 100644 modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.min.css.map diff --git a/docs/en/Getting-Started-Create-Solution-Single-Layer.md b/docs/en/Getting-Started-Create-Solution-Single-Layer.md index 8c4a6d0d88..32021dfa0e 100644 --- a/docs/en/Getting-Started-Create-Solution-Single-Layer.md +++ b/docs/en/Getting-Started-Create-Solution-Single-Layer.md @@ -8,6 +8,20 @@ } ```` +````json +//[doc-nav] +{ + "Next": { + "Name": "Running the solution", + "Path": "Getting-Started-Running-Solution-Single-Layer" + }, + "Previous": { + "Name": "Introduction", + "Path": "Introduction" + } +} +```` + > This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference on top of this document. ## Create a New Project @@ -45,8 +59,4 @@ Configure(options => > Or you can delete that code since `Auto` is already the default behavior. -{{ end }} - -## Next Step - -* [Running the solution](Getting-Started-Running-Solution-Single-Layer.md) \ No newline at end of file +{{ end }} \ 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 index ccee9b5d18..d1f6335466 100644 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationsDto.cs +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationsDto.cs @@ -1,7 +1,13 @@ +using System; + namespace Volo.Docs.HtmlConverting; public class DocumentNavigationsDto { public DocumentNavigationDto Previous { get; set; } public DocumentNavigationDto Next { get; set; } + + public bool HasPrevious => Previous?.Path.IsNullOrEmpty() == false; + public bool HasNext => Next?.Path.IsNullOrEmpty() == false; + public bool HasValues => HasPrevious || HasNext; } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml index 83f4c7a775..c2cb7f36b0 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml @@ -388,6 +388,30 @@ } @Html.Raw(Model.Document.Content) + + @if (Model.DocumentNavigationsDto.HasValues) + { +
+ + }