Browse Source

Merge pull request #18990 from abpframework/issue-17775

Better navigation to "Next Step" in the documentation
pull/19027/head
Gizem Mutu Kurt 3 years ago
committed by GitHub
parent
commit
4bc79fa930
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 20
      docs/en/Getting-Started-Create-Solution-Single-Layer.md
  2. 4
      modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json
  3. 7
      modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationDto.cs
  4. 13
      modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationsDto.cs
  5. 2
      modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs
  6. 79
      modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs
  7. 32
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml
  8. 18
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs
  9. 1
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.css.map
  10. 1
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.min.css.map
  11. 23
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.css
  12. 2
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.min.css
  13. 18
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.scss

20
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": "Setup Your Development Environment",
"Path": "Getting-Started-Setup-Environment-Single-Layer"
}
}
````
> 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. > 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 ## Create a New Project
@ -45,8 +59,4 @@ Configure<AbpUnitOfWorkDefaultOptions>(options =>
> Or you can delete that code since `Auto` is already the default behavior. > Or you can delete that code since `Auto` is already the default behavior.
{{ end }} {{ end }}
## Next Step
* [Running the solution](Getting-Started-Running-Solution-Single-Layer.md)

4
modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json

@ -37,6 +37,8 @@
"Preview": "preview", "Preview": "preview",
"Search": "Search", "Search": "Search",
"SearchResults": "Search Results", "SearchResults": "Search Results",
"SearchInTheAllDocuments": "Search in the all documents" "SearchInTheAllDocuments": "Search in the all documents",
"Next": "Next",
"Previous": "Previous"
} }
} }

7
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; }
}

13
modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentNavigationsDto.cs

@ -0,0 +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;
}

2
modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs

@ -11,5 +11,7 @@ namespace Volo.Docs.HtmlConverting
Task<Dictionary<string, List<string>>> GetAvailableParametersAsync(string document); Task<Dictionary<string, List<string>>> GetAvailableParametersAsync(string document);
Task<List<DocumentPartialTemplateWithValuesDto>> GetPartialTemplatesInDocumentAsync(string documentContent); Task<List<DocumentPartialTemplateWithValuesDto>> GetPartialTemplatesInDocumentAsync(string documentContent);
Task<DocumentNavigationsDto> GetDocumentNavigationsAsync(string documentContent);
} }
} }

79
modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs

@ -17,6 +17,7 @@ namespace Volo.Docs.HtmlConverting
private const string JsonCloser = "````"; private const string JsonCloser = "````";
private const string DocsParam = "//[doc-params]"; private const string DocsParam = "//[doc-params]";
private const string DocsTemplates = "//[doc-template]"; private const string DocsTemplates = "//[doc-template]";
private const string DocsNav = "//[doc-nav]";
public ILogger<ScribanDocumentSectionRenderer> Logger { get; set; } public ILogger<ScribanDocumentSectionRenderer> Logger { get; set; }
@ -41,71 +42,87 @@ namespace Volo.Docs.HtmlConverting
var result = await scribanTemplate.RenderAsync(parameters); var result = await scribanTemplate.RenderAsync(parameters);
return RemoveOptionsJson(result); return RemoveOptionsJson(result, DocsParam, DocsNav);
} }
public async Task<Dictionary<string, List<string>>> GetAvailableParametersAsync(string document) public Task<Dictionary<string, List<string>>> GetAvailableParametersAsync(string document)
{
return GetSectionAsync<Dictionary<string, List<string>>>(document, DocsParam);
}
public Task<DocumentNavigationsDto> GetDocumentNavigationsAsync(string documentContent)
{
return GetSectionAsync<DocumentNavigationsDto>(documentContent, DocsNav);
}
protected virtual async Task<T> GetSectionAsync<T>(string document, string sectionName) where T : new()
{ {
try try
{ {
if (!document.Contains(JsonOpener) || !document.Contains(DocsParam)) if (!document.Contains(JsonOpener) || !document.Contains(sectionName))
{ {
return new Dictionary<string, List<string>>(); return new T();
} }
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))
{ {
return new Dictionary<string, List<string>>(); return new T();
} }
var pureJson = insideJsonSection.Replace(DocsParam, "").Trim(); var pureJson = insideJsonSection.Replace(sectionName, "").Trim();
if (!DocsJsonSerializerHelper.TryDeserialize<Dictionary<string, List<string>>>(pureJson, out var availableParameters)) if (!DocsJsonSerializerHelper.TryDeserialize<T>(pureJson, out var section))
{ {
throw new UserFriendlyException("ERROR-20200327: Cannot validate JSON content for `AvailableParameters`!"); throw new UserFriendlyException($"ERROR-20200327: Cannot validate JSON content for `{sectionName}`!");
} }
return await Task.FromResult(availableParameters); return await Task.FromResult(section);
} }
catch (Exception) catch (Exception)
{ {
Logger.LogWarning("Unable to parse parameters of document."); Logger.LogWarning("Unable to parse parameters of document.");
return new Dictionary<string, List<string>>(); return new T();
} }
} }
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; var searchedIndex = 0;
@ -121,7 +138,7 @@ namespace Volo.Docs.HtmlConverting
var jsonEndingIndex = document.Substring(jsonBeginningIndex).IndexOf(JsonCloser, StringComparison.Ordinal) + jsonBeginningIndex; var jsonEndingIndex = document.Substring(jsonBeginningIndex).IndexOf(JsonCloser, StringComparison.Ordinal) + jsonBeginningIndex;
var insideJsonSection = document[jsonBeginningIndex..jsonEndingIndex]; var insideJsonSection = document[jsonBeginningIndex..jsonEndingIndex];
if (insideJsonSection.IndexOf(DocsParam, StringComparison.Ordinal) < 0) if (insideJsonSection.IndexOf(sectionName, StringComparison.Ordinal) < 0)
{ {
searchedIndex = jsonEndingIndex + JsonCloser.Length; searchedIndex = jsonEndingIndex + JsonCloser.Length;
continue; continue;

32
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml

@ -388,6 +388,38 @@
</abp-alert> </abp-alert>
} }
@Html.Raw(Model.Document.Content) @Html.Raw(Model.Document.Content)
@if (Model.DocumentNavigationsDto.HasValues)
{
<hr class="my-4"/>
<div class="row navigation">
<div class="col-6">
@if (Model.DocumentNavigationsDto.HasPrevious)
{
<a class="prev-link" href="@Model.CreateDocumentLink(Model.DocumentNavigationsDto.Previous.Path)">
<span class="desc d-block">
<i class="fa fa-chevron-left me-1"></i>
@L["Previous"]
</span>
<span class="title d-block">@Model.DocumentNavigationsDto.Previous.Name</span>
</a>
}
</div>
<div class="col-6">
@if (Model.DocumentNavigationsDto.HasNext)
{
<a class="next-link text-end" href="@Model.CreateDocumentLink(Model.DocumentNavigationsDto.Next.Path)">
<span class="desc d-block">
@L["Next"]
<i class="fa fa-chevron-right ms-1"></i>
</span>
<span class="title d-block">@Model.DocumentNavigationsDto.Next.Name</span>
</a>
}
</div>
</div>
}
</article> </article>
<div id="crawler_link" style="display:none;"> <div id="crawler_link" style="display:none;">

18
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 FullSearchEnabled { get; set; }
public bool IsLatestVersion { get; private set; } public bool IsLatestVersion { get; private set; }
public DocumentNavigationsDto DocumentNavigationsDto { get; private set; }
private const int MaxDescriptionMetaTagLength = 200; private const int MaxDescriptionMetaTagLength = 200;
private readonly IDocumentAppService _documentAppService; private readonly IDocumentAppService _documentAppService;
@ -253,6 +255,20 @@ namespace Volo.Docs.Pages.Documents.Project
DocumentsUrlPrefix + LanguageCode + "/" + ProjectName + "/" + DocumentsUrlPrefix + LanguageCode + "/" + ProjectName + "/" +
DocsAppConsts.Latest + "/" + DocumentName; 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() private IActionResult RedirectToDefaultLanguage()
{ {
@ -522,6 +538,8 @@ namespace Volo.Docs.Pages.Documents.Project
SetUserPreferences(); SetUserPreferences();
var partialTemplates = await GetDocumentPartialTemplatesAsync(); var partialTemplates = await GetDocumentPartialTemplatesAsync();
DocumentNavigationsDto = await _documentSectionRenderer.GetDocumentNavigationsAsync(Document.Content);
Document.Content = await _documentSectionRenderer.RenderAsync(Document.Content, UserPreferences, partialTemplates); Document.Content = await _documentSectionRenderer.RenderAsync(Document.Content, UserPreferences, partialTemplates);
} }

1
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.css.map

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["index.scss"],"names":[],"mappings":"AACI;EACI;EACA;EACA;;;AAKJ;EACI;;;AAMA;EACI;;AACA;EACI;;AAGR;EACI;EACA;EACA","file":"Index.css"}

1
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.min.css.map

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["index.scss"],"names":[],"mappings":"AACI,8BACI,4BACA,4CACA,uBAKJ,+BACI,0CAMA,0DACI,cACA,kEACI,eAGR,4DACI,gBACA,eACA","file":"Index.min.css"}

23
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.css

@ -1,8 +1,23 @@
.code-toolbar .line-highlight { .code-toolbar .line-highlight {
margin-top: 1.5em !important; margin-top: 1.5em !important;
background: rgba(233, 237, 241, 0.34) !important; background: rgba(233, 237, 241, 0.34) !important;
padding: 1px !important; } padding: 1px !important;
}
.input-group .input-group-text{ .input-group .input-group-text {
background-color: transparent!important; background-color: transparent !important;
} }
.navigation .next-link .desc, .navigation .prev-link .desc {
color: #0D6EFD;
}
.navigation .next-link .desc .fa, .navigation .prev-link .desc .fa {
font-size: 12px;
}
.navigation .next-link .title, .navigation .prev-link .title {
font-weight: 600;
font-size: 18px;
color: #0B1621;
}
/*# sourceMappingURL=Index.css.map */

2
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.min.css

@ -1 +1 @@
.code-toolbar .line-highlight{margin-top:1.5em !important;background:rgba(233,237,241,.34) !important;padding:1px !important;} .input-group .input-group-text{background-color: transparent!important;} .code-toolbar .line-highlight{margin-top:1.5em !important;background:rgba(233,237,241,.34) !important;padding:1px !important}.input-group .input-group-text{background-color:rgba(0,0,0,0) !important}.navigation .next-link .desc,.navigation .prev-link .desc{color:#0d6efd}.navigation .next-link .desc .fa,.navigation .prev-link .desc .fa{font-size:12px}.navigation .next-link .title,.navigation .prev-link .title{font-weight:600;font-size:18px;color:#0b1621}/*# sourceMappingURL=Index.min.css.map */

18
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.scss

@ -10,4 +10,20 @@
.input-group-text{ .input-group-text{
background-color: transparent!important; background-color: transparent!important;
} }
} }
.navigation {
.next-link, .prev-link {
.desc {
color: #0D6EFD;
.fa{
font-size: 12px;
}
}
.title {
font-weight: 600;
font-size: 18px;
color: #0B1621;
}
}
}

Loading…
Cancel
Save