mirror of
https://gitee.com/LongbowEnterprise/BootstrapBlazor.git
synced 2024-12-05 13:39:39 +08:00
!3640 doc(#I672IC): update DemoBlock component support get code snippet from Demo component
* feat: 基础组件 DemoBlock/Pre 支持获取代码片段新方式 * feat: 实现通过 Demo 参数获取源码逻辑 * feat: 增加 Converter 负责讲配置名字转化为 Type
This commit is contained in:
parent
e64f940f90
commit
a5f6173a0d
@ -8,13 +8,13 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
@ChildContent
|
||||
@RenderChildContent
|
||||
</div>
|
||||
@if (ShowCode)
|
||||
{
|
||||
<div class="card-footer">
|
||||
<div class="card-footer-code collapse" id="@Id">
|
||||
<Pre @key="@RazorFileName" CodeFile="@RazorFileName" BlockTitle="@BlockTitle"></Pre>
|
||||
<Pre @key="@RazorFileName" CodeFile="@RazorFileName" BlockTitle="@BlockTitle" Demo="@Demo"></Pre>
|
||||
</div>
|
||||
<a class="card-footer-control collapsed" href="#@Id" data-bs-toggle="collapse" role="button" aria-label="show code">
|
||||
<i class="fa-solid fa-caret-up"></i>
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
using BootstrapBlazor.Shared.Services;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace BootstrapBlazor.Shared.Components;
|
||||
@ -36,6 +37,12 @@ public sealed partial class DemoBlock
|
||||
[Parameter]
|
||||
public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 示例代码片段 默认 null 未设置
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string? Demo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否显示代码块 默认 true 显示
|
||||
/// </summary>
|
||||
@ -52,6 +59,10 @@ public sealed partial class DemoBlock
|
||||
[NotNull]
|
||||
private IStringLocalizer<DemoBlock>? Localizer { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private DemoComponentConverter? ComponentConverter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 友好链接锚点名称
|
||||
/// </summary>
|
||||
@ -70,4 +81,15 @@ public sealed partial class DemoBlock
|
||||
Title ??= Localizer[nameof(Title)];
|
||||
TooltipText ??= Localizer[nameof(TooltipText)];
|
||||
}
|
||||
|
||||
private RenderFragment RenderChildContent => builder =>
|
||||
{
|
||||
builder.AddContent(0, ChildContent);
|
||||
|
||||
if (ComponentConverter.TryParse(Demo, out var t))
|
||||
{
|
||||
builder.OpenComponent(1, t);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -46,6 +46,12 @@ public partial class Pre
|
||||
[Parameter]
|
||||
public string? BlockTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 示例代码片段 默认 null 未设置
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string? Demo { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IStringLocalizer<Pre>? Localizer { get; set; }
|
||||
@ -103,9 +109,10 @@ public partial class Pre
|
||||
|
||||
private async Task GetCodeAsync()
|
||||
{
|
||||
// 优先查找 Demo 值
|
||||
if (!string.IsNullOrEmpty(CodeFile))
|
||||
{
|
||||
var code = await Example.GetCodeAsync(CodeFile, BlockTitle);
|
||||
var code = await Example.GetCodeAsync(CodeFile, BlockTitle, Demo);
|
||||
if (!string.IsNullOrEmpty(code))
|
||||
{
|
||||
ChildContent = builder =>
|
||||
|
@ -31,6 +31,22 @@ internal static class CacheManagerExtensions
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得 指定代码文件当前文化设置的本地化资源集合
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="codeFile"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<LocalizedString> GetDemoLocalizedStrings(this ICacheManager cache, string codeFile, JsonLocalizationOptions options)
|
||||
{
|
||||
var key = $"Snippet-{CultureInfo.CurrentUICulture.Name}-{nameof(GetLocalizedStrings)}-{codeFile}";
|
||||
return cache.GetOrCreate(key, entry =>
|
||||
{
|
||||
return Utility.GetJsonStringByTypeName(options, typeof(CodeSnippetService).Assembly, $"BootstrapBlazor.Shared.{codeFile}");
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得 指定代码文件内当前代码块当前文化的代码片段
|
||||
/// </summary>
|
||||
@ -50,4 +66,10 @@ internal static class CacheManagerExtensions
|
||||
var key = $"Snippet-{CultureInfo.CurrentUICulture.Name}-{nameof(GetContentFromFileAsync)}-{codeFile}";
|
||||
return cache.GetOrCreateAsync(key, entry => factory(entry));
|
||||
}
|
||||
|
||||
public static Task<string> GetContentFromDemoAsync(this ICacheManager cache, string demo, Func<ICacheEntry, Task<string>> factory)
|
||||
{
|
||||
var key = $"{nameof(GetContentFromDemoAsync)}-Demos-{demo}";
|
||||
return cache.GetOrCreateAsync(key, entry => factory(entry));
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,10 @@ public static class ServicesExtensions
|
||||
services.AddSingleton(typeof(IDataService<>), typeof(TableDemoDataService<>));
|
||||
services.AddSingleton(typeof(ILookupService), typeof(DemoLookupService));
|
||||
services.AddSingleton<MockDataTableDynamicService>();
|
||||
|
||||
// 增加代码示例服务
|
||||
services.AddSingleton<DemoComponentConverter>();
|
||||
|
||||
services.AddSingleton<MenuService>();
|
||||
services.AddScoped<FanControllerDataService>();
|
||||
|
||||
|
@ -51,12 +51,12 @@ class CodeSnippetService
|
||||
/// 获得示例源码方法
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<string> GetCodeAsync(string codeFile, string? blockTitle)
|
||||
public async Task<string> GetCodeAsync(string codeFile, string? blockTitle, string? demo)
|
||||
{
|
||||
var content = "";
|
||||
try
|
||||
{
|
||||
var payload = await GetContentFromFile(codeFile);
|
||||
var payload = await GetContentFromDemo(demo) ?? await GetContentFromFile(codeFile);
|
||||
|
||||
if (blockTitle != null)
|
||||
{
|
||||
@ -136,6 +136,35 @@ class CodeSnippetService
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string?> GetContentFromDemo(string? demo) => string.IsNullOrEmpty(demo)
|
||||
? null
|
||||
: await CacheManager.GetContentFromDemoAsync(demo, async entry =>
|
||||
{
|
||||
var payload = "";
|
||||
|
||||
if (IsDevelopment)
|
||||
{
|
||||
payload = await ReadDemoTextAsync(demo);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OperatingSystem.IsBrowser())
|
||||
{
|
||||
Client.BaseAddress = new Uri($"{ServerUrl}/api/");
|
||||
payload = await Client.GetStringAsync($"Code?fileName={demo}");
|
||||
}
|
||||
else
|
||||
{
|
||||
payload = await Client.GetStringAsync(demo);
|
||||
}
|
||||
}
|
||||
|
||||
// 将资源文件信息替换
|
||||
CacheManager.GetDemoLocalizedStrings(demo, LocalizerOptions).ToList().ForEach(l => payload = ReplacePayload(payload, l));
|
||||
payload = ReplaceSymbols(payload);
|
||||
return payload;
|
||||
});
|
||||
|
||||
private Task<string> GetContentFromFile(string codeFile) => CacheManager.GetContentFromFileAsync(codeFile, async entry =>
|
||||
{
|
||||
var payload = "";
|
||||
@ -159,21 +188,22 @@ class CodeSnippetService
|
||||
if (Path.GetExtension(codeFile) == ".razor")
|
||||
{
|
||||
// 将资源文件信息替换
|
||||
CacheManager.GetLocalizedStrings(codeFile, LocalizerOptions).ToList().ForEach(ReplacePayload);
|
||||
payload = payload.Replace("@@", "@")
|
||||
.Replace("<", "<")
|
||||
.Replace(">", ">");
|
||||
CacheManager.GetLocalizedStrings(codeFile, LocalizerOptions).ToList().ForEach(l => payload = ReplacePayload(payload, l));
|
||||
payload = ReplaceSymbols(payload);
|
||||
}
|
||||
return payload;
|
||||
|
||||
void ReplacePayload(LocalizedString l)
|
||||
{
|
||||
payload = payload.Replace($"@(((MarkupString)Localizer[\"{l.Name}\"].Value).ToString())", l.Value)
|
||||
.Replace($"@((MarkupString)Localizer[\"{l.Name}\"].Value)", l.Value)
|
||||
.Replace($"@Localizer[\"{l.Name}\"]", l.Value);
|
||||
}
|
||||
});
|
||||
|
||||
private static string ReplaceSymbols(string payload) => payload
|
||||
.Replace("@@", "@")
|
||||
.Replace("<", "<")
|
||||
.Replace(">", ">");
|
||||
|
||||
private static string ReplacePayload(string payload, LocalizedString l) => payload
|
||||
.Replace($"@(((MarkupString)Localizer[\"{l.Name}\"].Value).ToString())", l.Value)
|
||||
.Replace($"@((MarkupString)Localizer[\"{l.Name}\"].Value)", l.Value)
|
||||
.Replace($"@Localizer[\"{l.Name}\"]", l.Value);
|
||||
|
||||
private async Task<string> ReadFileTextAsync(string codeFile)
|
||||
{
|
||||
var payload = "";
|
||||
@ -186,4 +216,18 @@ class CodeSnippetService
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
private async Task<string> ReadDemoTextAsync(string codeFile)
|
||||
{
|
||||
var payload = "";
|
||||
var paths = new string[] { "..", "BootstrapBlazor.Shared", "Demos" };
|
||||
var folder = Path.Combine(ContentRootPath, string.Join(Path.DirectorySeparatorChar, paths));
|
||||
var file = Path.Combine(folder, codeFile.Replace('.', Path.DirectorySeparatorChar));
|
||||
file = $"{file}.razor";
|
||||
if (File.Exists(file))
|
||||
{
|
||||
payload = await File.ReadAllTextAsync(file);
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
// Website: https://www.blazor.zone or https://argozhang.github.io/
|
||||
|
||||
namespace BootstrapBlazor.Shared.Services;
|
||||
|
||||
internal class DemoComponentConverter
|
||||
{
|
||||
private static Dictionary<string, Type>? Cache { get; set; }
|
||||
|
||||
public bool TryParse(string? name, [NotNullWhen(true)] out Type? type)
|
||||
{
|
||||
type = null;
|
||||
name = name?.Split('.').LastOrDefault();
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
Cache ??= BuildDemoTable();
|
||||
if (!string.IsNullOrEmpty(name) && Cache.ContainsKey(name))
|
||||
{
|
||||
type = Cache[name];
|
||||
}
|
||||
}
|
||||
return type != null;
|
||||
}
|
||||
|
||||
private Dictionary<string, Type> BuildDemoTable() => GetType().Assembly.GetExportedTypes().Where(i => i.Namespace?.Contains(".Demos.") ?? false).ToDictionary(i => i.Name);
|
||||
}
|
Loading…
Reference in New Issue
Block a user