Browse Source

Add SEO section extraction and usage for documents

Introduces support for extracting SEO metadata from document content by adding a new DocumentSeoDto, updating renderers to handle a new [doc-seo] section, and exposing this data in the project document page. The page now uses the SEO description if available, improving meta tag generation. Also adds error handling for scrollspy initialization in vs.js.
pull/23940/head
SALİH ÖZKARA 10 months ago
parent
commit
9b6f7da8d2
  1. 3
      modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/ScribanDocumentSectionRenderer.cs
  2. 6
      modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentSeoDto.cs
  3. 2
      modules/docs/src/Volo.Docs.Web/HtmlConverting/IWebDocumentSectionRenderer.cs
  4. 5
      modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanWebDocumentSectionRenderer.cs
  5. 21
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs
  6. 11
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Scripts/vs.js

3
modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/Rendering/ScribanDocumentSectionRenderer.cs

@ -22,6 +22,7 @@ public class ScribanDocumentSectionRenderer : IDocumentSectionRenderer
protected const string DocsParam = "//[doc-params]";
protected const string DocsTemplates = "//[doc-template]";
protected const string DocsNav = "//[doc-nav]";
protected const string DocsSeo = "//[doc-seo]";
public ILogger<ScribanDocumentSectionRenderer> Logger { get; set; }
@ -49,7 +50,7 @@ public class ScribanDocumentSectionRenderer : IDocumentSectionRenderer
var result = await scribanTemplate.RenderAsync(parameters);
return RemoveOptionsJson(result, DocsParam, DocsNav);
return RemoveOptionsJson(result, DocsParam, DocsNav, DocsSeo);
}
public Task<Dictionary<string, List<string>>> GetAvailableParametersAsync(string document)

6
modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentSeoDto.cs

@ -0,0 +1,6 @@
namespace Volo.Docs.HtmlConverting;
public class DocumentSeoDto
{
public string Description { get; set; }
}

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

@ -10,5 +10,7 @@ namespace Volo.Docs.HtmlConverting
Task<List<DocumentPartialTemplateWithValues>> GetPartialTemplatesInDocumentAsync(string documentContent);
Task<DocumentNavigationsDto> GetDocumentNavigationsAsync(string documentContent);
Task<DocumentSeoDto> GetDocumentSeoAsync(string documentContent);
}
}

5
modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanWebDocumentSectionRenderer.cs

@ -11,6 +11,11 @@ namespace Volo.Docs.HtmlConverting
return GetSectionAsync<DocumentNavigationsDto>(documentContent, DocsNav);
}
public Task<DocumentSeoDto> GetDocumentSeoAsync(string documentContent)
{
return GetSectionAsync<DocumentSeoDto>(documentContent, DocsSeo);
}
public async Task<List<DocumentPartialTemplateWithValues>> GetPartialTemplatesInDocumentAsync(
string documentContent)
{

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

@ -99,6 +99,8 @@ namespace Volo.Docs.Pages.Documents.Project
public bool HasDownloadPdf { get; set; }
public DocumentNavigationsDto DocumentNavigationsDto { get; private set; }
public DocumentSeoDto DocumentSeoDto { get; private set; }
private const int MaxDescriptionMetaTagLength = 200;
private const int TocLevelCount = 2;
@ -542,7 +544,7 @@ namespace Volo.Docs.Pages.Documents.Project
DocumentNameWithExtension = Document.Name;
SetDocumentPageTitle();
await ConvertDocumentContentToHtmlAsync();
await ConvertDocumentContentToHtmlAsync();
return true;
}
@ -587,6 +589,7 @@ namespace Volo.Docs.Pages.Documents.Project
var partialTemplates = await GetDocumentPartialTemplatesAsync();
DocumentNavigationsDto = await _webDocumentSectionRenderer.GetDocumentNavigationsAsync(Document.Content);
DocumentSeoDto = await _webDocumentSectionRenderer.GetDocumentSeoAsync(Document.Content);
try
{
@ -600,11 +603,12 @@ namespace Volo.Docs.Pages.Documents.Project
else
{
DocumentNavigationsDto = new DocumentNavigationsDto();
}
if (Document != null && !Document.Content.IsNullOrEmpty())
{
TocItems = _tocGeneratorService.GenerateTocItems(Document.Content, TocLevelCount);
DocumentSeoDto = new DocumentSeoDto();
}
if (Document != null && !Document.Content.IsNullOrEmpty())
{
TocItems = _tocGeneratorService.GenerateTocItems(Document.Content, TocLevelCount);
}
var converter = _documentToHtmlConverterFactory.Create<DocumentToHtmlConverterContext>(Document.Format ?? Project.Format);
@ -888,6 +892,11 @@ namespace Volo.Docs.Pages.Documents.Project
return null;
}
if (DocumentSeoDto?.Description.IsNullOrWhiteSpace() == false)
{
return DocumentSeoDto.Description;
}
var firstParagraph = new Regex(@"<p>(.*?)</p>", RegexOptions.IgnoreCase);
var match = firstParagraph.Match(Document.Content);
if (!match.Success)

11
modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Scripts/vs.js

@ -63,10 +63,13 @@
var $myNav = $('#docs-sticky-index');
$('body').scrollspy({
target: $myNav,
offset:100
});
try {
$('body').scrollspy({
target: $myNav,
offset:100
});
} catch {
}
$('#docs-sticky-index a').on('click', function (event) {
if (this.hash !== '') {

Loading…
Cancel
Save