docs: dynaimc route for markdown docs

This commit is contained in:
ElderJames 2020-03-17 13:42:54 +08:00
parent 7c92f8eb14
commit 2087205bfc
22 changed files with 500 additions and 101 deletions

1
.gitignore vendored
View File

@ -344,3 +344,4 @@ package-lock.json
/components/wwwroot/js/ant-design-blazor.js
/components/wwwroot/js/ant-design-blazor.js.map
/site/AntBlazor.Docs/wwwroot/css/docs.css
/site/**/wwwroot/docs

View File

@ -20,7 +20,7 @@
<PackageLicenseExpression></PackageLicenseExpression>
<Authors>James Yeung</Authors>
<PackageIconUrl>https://raw.githubusercontent.com/ElderJames/ant-design-blazor/master/logo.svg?sanitize=true</PackageIconUrl>
<RootDir>..\</RootDir>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@ -33,23 +33,23 @@
<PackageReference Include="OneOf" Version="2.1.151" />
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(RootDir)node_modules') ">
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SolutionDir)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(RootDir)" Command="npm install" />
<Exec WorkingDirectory="$(SolutionDir)" Command="npm install" />
</Target>
<Target Name="DebugRunGulp" BeforeTargets="DebugEnsureNodeEnv" Condition=" '$(Configuration)' == 'Debug' And Exists('$(RootDir)node_modules') ">
<Exec WorkingDirectory="$(RootDir)" Command="npm run gulp:components" />
<Target Name="DebugRunGulp" BeforeTargets="DebugEnsureNodeEnv" Condition=" '$(Configuration)' == 'Debug' And Exists('$(SolutionDir)node_modules') ">
<Exec WorkingDirectory="$(SolutionDir)" Command="npm run gulp:components" />
</Target>
<Target Name="PublishRunGulp" AfterTargets="ComputeFilesToPublish">
<Exec WorkingDirectory="$(RootDir)" Command="npm install" />
<Exec WorkingDirectory="$(RootDir)" Command="npm run gulp:components" />
<Exec WorkingDirectory="$(SolutionDir)" Command="npm install" />
<Exec WorkingDirectory="$(SolutionDir)" Command="npm run gulp:components" />
</Target>
<ItemGroup>

View File

@ -82,10 +82,11 @@ namespace AntBlazor
}
/// <inheritdoc />
public void Dispose()
public override void Dispose()
{
// To avoid leaking memory, it's important to detach any event handlers in Dispose()
NavigationManger.LocationChanged -= OnLocationChanged;
base.Dispose();
}
private void UpdateCssClass()

View File

@ -3,7 +3,7 @@
<div class="pic-plus">
<img width="150" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
<span>+</span>
<img height="150" src="./assets/blazor.svg">
<img height="150" src="/docs/assets/blazor.svg">
</div>
<style>
@ -126,7 +126,7 @@
如果您在使用的过程中碰到问题,可以通过 [钉钉群](https://h5.dingtalk.com/circle/healthCheckin.html?corpId=dingccf128388c3ea40eda055e4784d35b88&2f46=c9b80ba5&origin=11) 寻求帮助,同时我们也鼓励资深用户通过下面的途径给新人提供帮助。
<img src="./assets/dingtalk.jpg" width="300">
<img src="/docs/assets/dingtalk.jpg" width="300">
## ☀️ 授权协议

View File

@ -22,4 +22,12 @@
<ItemGroup>
<ProjectReference Include="..\AntBlazor.Docs\AntBlazor.Docs.csproj" />
</ItemGroup>
<ItemGroup>
<DocFiles Include="$(SolutionDir)docs\**\*.*" />
</ItemGroup>
<Target Name="CopyDocs" BeforeTargets="Build">
<Copy SourceFiles="@(DocFiles)" DestinationFolder="$(ProjectDir)\wwwroot\docs\%(RecursiveDir)" ContinueOnError="true" />
</Target>
</Project>

View File

@ -8,4 +8,12 @@
<ItemGroup>
<ProjectReference Include="..\AntBlazor.Docs\AntBlazor.Docs.csproj" />
</ItemGroup>
<ItemGroup>
<DocFiles Include="$(SolutionDir)docs\**\*.*"></DocFiles>
</ItemGroup>
<Target Name="CopyDocs" BeforeTargets="Build">
<Copy SourceFiles="@(DocFiles)" DestinationFolder="$(ProjectDir)\wwwroot\docs\%(RecursiveDir)" ContinueOnError="true" />
</Target>
</Project>

View File

@ -1,13 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace AntBlazor.Docs.ServerApp
{

View File

@ -6,7 +6,6 @@
<IsPackable>true</IsPackable>
<RazorLangVersion>3.0</RazorLangVersion>
<BlazorLinkOnBuild>false</BlazorLinkOnBuild>
<RootDir>..\..\</RootDir>
</PropertyGroup>
<ItemGroup>
@ -17,22 +16,26 @@
<ProjectReference Include="..\..\components\AntBlazor.csproj" />
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(RootDir)node_modules') ">
<ItemGroup>
<Content Include="$(SolutionDir)docs\**" LinkBase="docs" />
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SolutionDir)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(RootDir)" Command="npm install" />
<Exec WorkingDirectory="$(SolutionDir)" Command="npm install" />
</Target>
<Target Name="DebugRunGulp" BeforeTargets="DebugEnsureNodeEnv" Condition=" '$(Configuration)' == 'Debug' And Exists('$(RootDir)node_modules') ">
<Exec WorkingDirectory="$(RootDir)" Command="npm run gulp:docs" />
<Target Name="DebugRunGulp" BeforeTargets="DebugEnsureNodeEnv" Condition=" '$(Configuration)' == 'Debug' And Exists('$(SolutionDir)node_modules') ">
<Exec WorkingDirectory="$(SolutionDir)" Command="npm run gulp:docs" />
</Target>
<Target Name="PublishRunGulp" AfterTargets="ComputeFilesToPublish">
<Exec WorkingDirectory="$(RootDir)" Command="npm install" />
<Exec WorkingDirectory="$(RootDir)" Command="npm run gulp:docs" />
<Exec WorkingDirectory="$(SolutionDir)" Command="npm install" />
<Exec WorkingDirectory="$(SolutionDir)" Command="npm run gulp:docs" />
</Target>
</Project>

View File

@ -1,26 +1,27 @@

@inject HttpClient HttpClient
@page "/docs/{fileName}"
<Markdown>
@markdown
</Markdown>
@inject NavigationManager NavigationManager
<article class="markdown">
<Markdown docUrl="@docUrl"></Markdown>
</article>
@code {
[Parameter] public string fileName { get; set; }
string docUrl => "https://raw.githubusercontent.com/NG-ZORRO/ng-zorro-antd/master/docs/introduce.zh-CN.md"; //fileName;
string docUrl { get; set; }
string markdown = "";
protected override async Task OnInitializedAsync()
protected override void OnInitialized()
{
if (!string.IsNullOrEmpty(docUrl))
if (!string.IsNullOrEmpty(fileName))
{
markdown = await this.HttpClient.GetStringAsync(docUrl);
var baseUrl = NavigationManager.ToAbsoluteUri(NavigationManager.BaseUri);
docUrl = new Uri(baseUrl, $"docs/{fileName}.md").ToString();
}
await base.OnInitializedAsync();
base.OnInitialized();
}
}

View File

@ -1,14 +0,0 @@

<Markdown>
<p align="center">
<a href="https://yangshunjie.com/ant-design-blazor/">
<img src="https://raw.githubusercontent.com/ElderJames/ant-design-blazor/master/logo.svg?sanitize=true">
</a>
</p>
<h1 align="center">Ant Design Blazor</h1>
<div align="center">
An enterprise-class UI components based on Ant Design and Blazor.
</div>
</Markdown>

View File

@ -71,21 +71,17 @@ namespace AntBlazor.Docs.Routing
private void Refresh()
{
var relativeUri = NavigationManager.ToBaseRelativePath(_location);
var parameters = ParseQueryString(relativeUri);
if (relativeUri.IndexOf('?') > -1)
{
relativeUri = relativeUri.Substring(0, relativeUri.IndexOf('?'));
}
var segments = relativeUri.Trim().Split('/', StringSplitOptions.RemoveEmptyEntries);
var matchResult = RouteManager.Match(segments);
var matchResult = RouteManager.Match(relativeUri);
if (matchResult.IsMatch)
{
var routeData = new RouteData(
matchResult.MatchedRoute.Handler,
parameters);
var routeData = new RouteData(matchResult.MatchedRoute.PageType, matchResult.MatchedRoute.Parameters);
_renderHandle.Render(Found(routeData));
}
@ -94,21 +90,5 @@ namespace AntBlazor.Docs.Routing
_renderHandle.Render(NotFound);
}
}
private Dictionary<string, object> ParseQueryString(string uri)
{
var querystring = new Dictionary<string, object>();
foreach (string kvp in uri.Substring(uri.IndexOf("?") + 1).Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
{
if (kvp != "" && kvp.Contains("="))
{
var pair = kvp.Split('=');
querystring.Add(pair[0], pair[1]);
}
}
return querystring;
}
}
}

View File

@ -1,4 +1,6 @@
namespace AntBlazor.Docs.Routing
using System.Collections.Generic;
namespace AntBlazor.Docs.Routing
{
public class MatchResult
{

View File

@ -1,13 +1,65 @@
using System;
using System.Collections.Generic;
namespace AntBlazor.Docs.Routing
{
public class Route
{
public string[] UriSegments { get; set; }
public Type Handler { get; set; }
public Type PageType { get; set; }
public MatchResult Match(string[] segments)
internal RouteTemplate Template { get; set; }
public string[] UnusedRouteParameterNames { get; set; }
public Dictionary<string, object> Parameters { get; set; }
public MatchResult Match(string[] segments, string relativeUri)
{
var parameters = ParseQueryString(relativeUri);
if (Template != null)
{
if (Template.Segments.Length != segments.Length)
{
return MatchResult.NoMatch();
}
for (var i = 0; i < Template.Segments.Length; i++)
{
var segment = Template.Segments[i];
var pathSegment = segments[i];
if (!segment.Match(pathSegment, out var matchedParameterValue))
{
return MatchResult.NoMatch();
}
else
{
if (segment.IsParameter)
{
parameters ??= new Dictionary<string, object>(StringComparer.Ordinal);
parameters[segment.Value] = matchedParameterValue;
}
}
}
// In addition to extracting parameter values from the URL, each route entry
// also knows which other parameters should be supplied with null values. These
// are parameters supplied by other route entries matching the same handler.
if (UnusedRouteParameterNames.Length > 0)
{
parameters ??= new Dictionary<string, object>(StringComparer.Ordinal);
foreach (var name in UnusedRouteParameterNames)
{
parameters[name] = null;
}
}
this.Parameters = parameters;
return MatchResult.Match(this);
}
else
{
if (segments.Length != UriSegments.Length)
{
@ -21,8 +73,27 @@ namespace AntBlazor.Docs.Routing
return MatchResult.NoMatch();
}
}
this.Parameters ??= new Dictionary<string, object>(StringComparer.Ordinal);
return MatchResult.Match(this);
}
}
private Dictionary<string, object> ParseQueryString(string uri)
{
// Parameters will be lazily initialized.
Dictionary<string, object> querystring = null;
foreach (string kvp in uri.Substring(uri.IndexOf("?", StringComparison.Ordinal) + 1).Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
{
if (kvp != "" && kvp.Contains("="))
{
var pair = kvp.Split('=');
querystring ??= new Dictionary<string, object>(StringComparer.Ordinal);
querystring.Add(pair[0], pair[1]);
}
}
return querystring;
}
}
}

View File

@ -0,0 +1,112 @@
using System;
using System.Collections.Concurrent;
using System.Globalization;
namespace AntBlazor.Docs.Routing
{
internal abstract class RouteConstraint
{
// note: the things that prevent this cache from growing unbounded is that
// we're the only caller to this code path, and the fact that there are only
// 8 possible instances that we create.
//
// The values passed in here for parsing are always static text defined in route attributes.
private static readonly ConcurrentDictionary<string, RouteConstraint> _cachedConstraints
= new ConcurrentDictionary<string, RouteConstraint>();
public abstract bool Match(string pathSegment, out object convertedValue);
public static RouteConstraint Parse(string template, string segment, string constraint)
{
if (string.IsNullOrEmpty(constraint))
{
throw new ArgumentException($"Malformed segment '{segment}' in route '{template}' contains an empty constraint.");
}
if (_cachedConstraints.TryGetValue(constraint, out var cachedInstance))
{
return cachedInstance;
}
else
{
var newInstance = CreateRouteConstraint(constraint);
if (newInstance != null)
{
// We've done to the work to create the constraint now, but it's possible
// we're competing with another thread. GetOrAdd can ensure only a single
// instance is returned so that any extra ones can be GC'ed.
return _cachedConstraints.GetOrAdd(constraint, newInstance);
}
else
{
throw new ArgumentException($"Unsupported constraint '{constraint}' in route '{template}'.");
}
}
}
private static RouteConstraint CreateRouteConstraint(string constraint)
{
switch (constraint)
{
case "bool":
return new TypeRouteConstraint<bool>(bool.TryParse);
case "datetime":
return new TypeRouteConstraint<DateTime>((string str, out DateTime result)
=> DateTime.TryParse(str, CultureInfo.InvariantCulture, DateTimeStyles.None, out result));
case "decimal":
return new TypeRouteConstraint<decimal>((string str, out decimal result)
=> decimal.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out result));
case "double":
return new TypeRouteConstraint<double>((string str, out double result)
=> double.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out result));
case "float":
return new TypeRouteConstraint<float>((string str, out float result)
=> float.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out result));
case "guid":
return new TypeRouteConstraint<Guid>(Guid.TryParse);
case "int":
return new TypeRouteConstraint<int>((string str, out int result)
=> int.TryParse(str, NumberStyles.Integer, CultureInfo.InvariantCulture, out result));
case "long":
return new TypeRouteConstraint<long>((string str, out long result)
=> long.TryParse(str, NumberStyles.Integer, CultureInfo.InvariantCulture, out result));
default:
return null;
}
}
}
internal class TypeRouteConstraint<T> : RouteConstraint
{
public delegate bool TryParseDelegate(string str, out T result);
private readonly TryParseDelegate _parser;
public TypeRouteConstraint(TryParseDelegate parser)
{
_parser = parser;
}
public override bool Match(string pathSegment, out object convertedValue)
{
if (_parser(pathSegment, out var result))
{
convertedValue = result;
return true;
}
else
{
convertedValue = null;
return false;
}
}
}
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using AntBlazor.core.Internal;
using Microsoft.AspNetCore.Components;
namespace AntBlazor.Docs.Routing
@ -23,29 +24,65 @@ namespace AntBlazor.Docs.Routing
if (pageType.FullName == null)
continue;
var uriSegments = pageType.FullName.Substring(pageType.FullName.IndexOf("Pages", StringComparison.Ordinal) + 6).Split('.');
var routeAttributes = pageType.GetCustomAttributes<RouteAttribute>(inherit: false);
if (!routeAttributes.Any())
{
var newRoute = new Route
{
UriSegments = pageType.FullName.Substring(pageType.FullName.IndexOf("Pages", StringComparison.Ordinal) + 6).Split('.'),
Handler = pageType
UriSegments = uriSegments,
PageType = pageType,
};
routesList.Add(newRoute);
continue;
}
var templates = routeAttributes.Select(t => t.Template).ToArray();
var parsedTemplates = templates.Select(TemplateParser.ParseTemplate).ToArray();
var allRouteParameterNames = parsedTemplates
.SelectMany(GetParameterNames)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
foreach (var parsedTemplate in parsedTemplates)
{
var unusedRouteParameterNames = allRouteParameterNames
.Except(GetParameterNames(parsedTemplate), StringComparer.OrdinalIgnoreCase)
.ToArray();
var newRoute = new Route
{
UriSegments = uriSegments,
PageType = pageType,
Template = parsedTemplate,
UnusedRouteParameterNames = unusedRouteParameterNames
};
routesList.Add(newRoute);
}
}
Routes = routesList.ToArray();
}
public MatchResult Match(string[] segments)
public MatchResult Match(string relativeUri)
{
var segments = relativeUri.Trim().Split('/', StringSplitOptions.RemoveEmptyEntries).Select(Uri.UnescapeDataString).ToArray();
if (segments.Length == 0)
{
var indexRoute = Routes.SingleOrDefault(x => x.Handler.FullName != null && x.Handler.FullName.ToLower().EndsWith("index"));
var indexRoute = Routes.SingleOrDefault(x => x.PageType.FullName != null && x.PageType.FullName.ToLower().EndsWith("index"));
if (indexRoute != null)
{
return MatchResult.Match(indexRoute);
}
}
foreach (var route in Routes)
{
var matchResult = route.Match(segments);
var matchResult = route.Match(segments, relativeUri);
if (matchResult.IsMatch)
{
@ -55,5 +92,13 @@ namespace AntBlazor.Docs.Routing
return MatchResult.NoMatch();
}
private static string[] GetParameterNames(RouteTemplate routeTemplate)
{
return routeTemplate.Segments
.Where(s => s.IsParameter)
.Select(s => s.Value)
.ToArray();
}
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace AntBlazor.Docs.Routing
{
[DebuggerDisplay("{TemplateText}")]
internal class RouteTemplate
{
public RouteTemplate(string templateText, TemplateSegment[] segments)
{
TemplateText = templateText;
Segments = segments;
}
public string TemplateText { get; }
public TemplateSegment[] Segments { get; }
}
}

View File

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Text;
using AntBlazor.Docs.Routing;
namespace AntBlazor.core.Internal
{
internal class TemplateParser
{
public static readonly char[] InvalidParameterNameCharacters =
new char[] { '*', '?', '{', '}', '=', '.' };
internal static RouteTemplate ParseTemplate(string template)
{
var originalTemplate = template;
template = template.Trim('/');
if (template == "")
{
// Special case "/";
return new RouteTemplate("/", Array.Empty<TemplateSegment>());
}
var segments = template.Split('/');
var templateSegments = new TemplateSegment[segments.Length];
for (int i = 0; i < segments.Length; i++)
{
var segment = segments[i];
if (string.IsNullOrEmpty(segment))
{
throw new InvalidOperationException(
$"Invalid template '{template}'. Empty segments are not allowed.");
}
if (segment[0] != '{')
{
if (segment[segment.Length - 1] == '}')
{
throw new InvalidOperationException(
$"Invalid template '{template}'. Missing '{{' in parameter segment '{segment}'.");
}
templateSegments[i] = new TemplateSegment(originalTemplate, segment, isParameter: false);
}
else
{
if (segment[segment.Length - 1] != '}')
{
throw new InvalidOperationException(
$"Invalid template '{template}'. Missing '}}' in parameter segment '{segment}'.");
}
if (segment.Length < 3)
{
throw new InvalidOperationException(
$"Invalid template '{template}'. Empty parameter name in segment '{segment}' is not allowed.");
}
var invalidCharacter = segment.IndexOfAny(InvalidParameterNameCharacters, 1, segment.Length - 2);
if (invalidCharacter != -1)
{
throw new InvalidOperationException(
$"Invalid template '{template}'. The character '{segment[invalidCharacter]}' in parameter segment '{segment}' is not allowed.");
}
templateSegments[i] = new TemplateSegment(originalTemplate, segment.Substring(1, segment.Length - 2), isParameter: true);
}
}
for (int i = 0; i < templateSegments.Length; i++)
{
var currentSegment = templateSegments[i];
if (!currentSegment.IsParameter)
{
continue;
}
for (int j = i + 1; j < templateSegments.Length; j++)
{
var nextSegment = templateSegments[j];
if (!nextSegment.IsParameter)
{
continue;
}
if (string.Equals(currentSegment.Value, nextSegment.Value, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
$"Invalid template '{template}'. The parameter '{currentSegment}' appears multiple times.");
}
}
}
return new RouteTemplate(template, templateSegments);
}
}
}

View File

@ -0,0 +1,63 @@
using System;
using System.Linq;
namespace AntBlazor.Docs.Routing
{
internal class TemplateSegment
{
public TemplateSegment(string template, string segment, bool isParameter)
{
IsParameter = isParameter;
if (!isParameter || segment.IndexOf(':') < 0)
{
Value = segment;
Constraints = Array.Empty<RouteConstraint>();
}
else
{
var tokens = segment.Split(':');
if (tokens[0].Length == 0)
{
throw new ArgumentException($"Malformed parameter '{segment}' in route '{template}' has no name before the constraints list.");
}
Value = tokens[0];
Constraints = tokens.Skip(1)
.Select(token => RouteConstraint.Parse(template, segment, token))
.ToArray();
}
}
// The value of the segment. The exact text to match when is a literal.
// The parameter name when its a segment
public string Value { get; }
public bool IsParameter { get; }
public RouteConstraint[] Constraints { get; }
public bool Match(string pathSegment, out object matchedParameterValue)
{
if (IsParameter)
{
matchedParameterValue = pathSegment;
foreach (var constraint in Constraints)
{
if (!constraint.Match(pathSegment, out matchedParameterValue))
{
return false;
}
}
return true;
}
else
{
matchedParameterValue = null;
return string.Equals(Value, pathSegment, StringComparison.OrdinalIgnoreCase);
}
}
}
}

View File

@ -9,7 +9,6 @@ namespace AntBlazor.Docs
{
services.AddAntBlazor();
services.AddSingleton<RouteManager>();
return services;
}
}

View File

@ -91,6 +91,11 @@
{
var baseUrl = NavigationManager.ToAbsoluteUri(NavigationManager.BaseUri);
MenuItems = await HttpClient.GetJsonAsync<MenuItem[]>(new Uri(baseUrl,"_content/AntBlazor.Docs/menu.json"));
var defaultUrl = MenuItems.FirstOrDefault(x => x.Default);
if (defaultUrl!=null)
{
NavigationManager.NavigateTo(defaultUrl.Url);
}
await base.OnInitializedAsync();
}

View File

@ -2,6 +2,7 @@
@using Markdig
@inherits ComponentBase
@inject HtmlRenderService HtmlRenderService
@inject HttpClient HttpClient
@((MarkupString)html)
@ -19,6 +20,11 @@
protected override async Task OnInitializedAsync()
{
if (!string.IsNullOrEmpty(docUrl))
{
markdown = await this.HttpClient.GetStringAsync(docUrl);
}
if (ChildContent != null)
{
markdown = await HtmlRenderService.RenderAsync(ChildContent);

View File

@ -1,10 +1,10 @@
[
//{
// "title": "Ant Design of Blazor",
// "type": "menuItem",
// "url": "docs/introduce",
// "default": true
//},
{
"title": "Ant Design of Blazor",
"type": "menuItem",
"url": "docs/introduce",
"default": true
},
{
"title": "Components",
"type": "subMenu",