mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2025-02-05 14:49:06 +00:00
Temporarily added MudBlazor.Markdown to the solution
This is necessary due to issue https://github.com/MyNihongo/MudBlazor.Markdown/issues/247 I created a PR as well: https://github.com/MyNihongo/MudBlazor.Markdown/pull/246
This commit is contained in:
parent
6f9326a827
commit
c84184e5d1
152
MudBlazor.Markdown/Components/MudCodeHighlight.razor.cs
Normal file
152
MudBlazor.Markdown/Components/MudCodeHighlight.razor.cs
Normal file
@ -0,0 +1,152 @@
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
|
||||
namespace MudBlazor;
|
||||
|
||||
public partial class MudCodeHighlight : MudComponentBase, IDisposable
|
||||
{
|
||||
private ElementReference _ref;
|
||||
private CodeBlockTheme _theme;
|
||||
private IMudMarkdownThemeService? _themeService;
|
||||
private bool _isFirstThemeSet;
|
||||
|
||||
/// <summary>
|
||||
/// Code text to render
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Language of the <see cref="Text"/>
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Language { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Theme of the code block.<br/>
|
||||
/// Browse available themes here: https://highlightjs.org/static/demo/ <br/>
|
||||
/// Default is <see cref="CodeBlockTheme.Default"/>
|
||||
/// </summary>
|
||||
#if NET7_0
|
||||
#pragma warning disable BL0007
|
||||
#endif
|
||||
[Parameter]
|
||||
public CodeBlockTheme Theme
|
||||
{
|
||||
get => _theme;
|
||||
set
|
||||
{
|
||||
if (_theme == value)
|
||||
return;
|
||||
|
||||
_theme = value;
|
||||
Task.Run(SetThemeAsync);
|
||||
}
|
||||
}
|
||||
#if NET7_0
|
||||
#pragma warning restore BL0007
|
||||
#endif
|
||||
|
||||
[Inject]
|
||||
private IJSRuntime Js { get; init; } = default!;
|
||||
|
||||
[Inject]
|
||||
private IServiceProvider? ServiceProvider { get; init; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_themeService != null)
|
||||
_themeService.CodeBlockThemeChanged -= OnCodeBlockThemeChanged;
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected override bool ShouldRender() =>
|
||||
!string.IsNullOrEmpty(Text);
|
||||
|
||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||
{
|
||||
var i = 0;
|
||||
|
||||
builder.OpenElement(i++, "div");
|
||||
builder.AddAttribute(i++, "class", "snippet-clipboard-content overflow-auto");
|
||||
|
||||
// Copy button
|
||||
builder.OpenComponent<MudIconButton>(i++);
|
||||
builder.AddAttribute(i++, nameof(MudIconButton.Icon), Icons.Material.Rounded.ContentCopy);
|
||||
builder.AddAttribute(i++, nameof(MudIconButton.Variant), Variant.Filled);
|
||||
builder.AddAttribute(i++, nameof(MudIconButton.Color), Color.Primary);
|
||||
builder.AddAttribute(i++, nameof(MudIconButton.Size), Size.Medium);
|
||||
builder.AddAttribute(i++, nameof(MudIconButton.Class), "snippet-clipboard-copy-icon m-2");
|
||||
builder.AddAttribute(i++, nameof(MudIconButton.OnClick), EventCallback.Factory.Create<MouseEventArgs>(this, CopyTextToClipboardAsync));
|
||||
builder.CloseComponent();
|
||||
|
||||
// Code block
|
||||
builder.OpenElement(i++, "pre");
|
||||
builder.OpenElement(i++, "code");
|
||||
|
||||
if (!string.IsNullOrEmpty(Language))
|
||||
builder.AddAttribute(i++, "class", $"language-{Language}");
|
||||
|
||||
builder.AddElementReferenceCapture(i++, x => _ref = x);
|
||||
builder.AddContent(i++, Text);
|
||||
|
||||
builder.CloseElement();
|
||||
builder.CloseElement();
|
||||
builder.CloseElement();
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
_themeService = ServiceProvider?.GetService<IMudMarkdownThemeService>();
|
||||
|
||||
if (_themeService != null)
|
||||
_themeService.CodeBlockThemeChanged += OnCodeBlockThemeChanged;
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (!firstRender)
|
||||
return;
|
||||
|
||||
await Js.InvokeVoidAsync("highlightCodeElement", _ref)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (!_isFirstThemeSet)
|
||||
{
|
||||
await SetThemeAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCodeBlockThemeChanged(object? sender, CodeBlockTheme e) =>
|
||||
Theme = e;
|
||||
|
||||
private async Task SetThemeAsync()
|
||||
{
|
||||
var stylesheetPath = Theme.GetStylesheetPath();
|
||||
|
||||
await Js.InvokeVoidAsync("setHighlightStylesheet", stylesheetPath)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
_isFirstThemeSet = true;
|
||||
}
|
||||
|
||||
private async Task CopyTextToClipboardAsync(MouseEventArgs args)
|
||||
{
|
||||
var ok = await Js.InvokeAsync<bool>("copyTextToClipboard", Text)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (ok)
|
||||
return;
|
||||
|
||||
var clipboardService = ServiceProvider?.GetService<IMudMarkdownClipboardService>();
|
||||
|
||||
if (clipboardService != null)
|
||||
{
|
||||
await clipboardService.CopyToClipboardAsync(Text)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
76
MudBlazor.Markdown/Components/MudLinkButton.razor.cs
Normal file
76
MudBlazor.Markdown/Components/MudLinkButton.razor.cs
Normal file
@ -0,0 +1,76 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
internal sealed class MudLinkButton : MudComponentBase
|
||||
{
|
||||
private string Classname =>
|
||||
new CssBuilder("mud-typography mud-link")
|
||||
.AddClass($"mud-{Color.ToDescriptionString()}-text")
|
||||
.AddClass($"mud-link-underline-{Underline.ToDescriptionString()}")
|
||||
.AddClass($"mud-typography-{Typo.ToDescriptionString()}")
|
||||
.AddClass("mud-link-disabled", IsDisabled)
|
||||
.AddClass(Class)
|
||||
.Build();
|
||||
|
||||
/// <summary>
|
||||
/// The color of the component. It supports the theme colors.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Color Color { get; set; } = Color.Primary;
|
||||
|
||||
/// <summary>
|
||||
/// Typography variant to use.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Typo Typo { get; set; } = Typo.body1;
|
||||
|
||||
/// <summary>
|
||||
/// Controls when the link should have an underline.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Underline Underline { get; set; } = Underline.Hover;
|
||||
|
||||
/// <summary>
|
||||
/// If true, the navlink will be disabled.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool IsDisabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Child content of component.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Command executed on click
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public ICommand? Command { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parameter passed to the command
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public object? CommandParameter { get; set; }
|
||||
|
||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||
{
|
||||
var i = 0;
|
||||
|
||||
builder.OpenElement(i++, "span");
|
||||
builder.AddAttribute(i++, "class", Classname);
|
||||
builder.AddAttribute(i++, "style", Style);
|
||||
builder.AddAttribute(i++, "onclick", EventCallback.Factory.Create(this, OnClick));
|
||||
builder.AddContent(i++, ChildContent);
|
||||
builder.CloseElement();
|
||||
}
|
||||
|
||||
private void OnClick()
|
||||
{
|
||||
if (IsDisabled)
|
||||
return;
|
||||
|
||||
if (Command?.CanExecute(CommandParameter) ?? false)
|
||||
Command.Execute(CommandParameter);
|
||||
}
|
||||
}
|
77
MudBlazor.Markdown/Components/MudMarkdownDetails.razor.cs
Normal file
77
MudBlazor.Markdown/Components/MudMarkdownDetails.razor.cs
Normal file
@ -0,0 +1,77 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
/// <summary>
|
||||
/// For some reason MudExpansionPanels eternally tried to dispose all panels, therefore, RenderFragment was called infinitely<br/>
|
||||
/// Created this component in order to bypass that weird behaviour
|
||||
/// </summary>
|
||||
internal sealed class MudMarkdownDetails : ComponentBase
|
||||
{
|
||||
private int _elementIndex;
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment? TitleContent { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
private bool IsExpanded { get; set; }
|
||||
|
||||
private string IconClasses => new CssBuilder("mud-expand-panel-icon")
|
||||
.AddClass("mud-transform", IsExpanded)
|
||||
.Build();
|
||||
|
||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||
{
|
||||
_elementIndex = 0;
|
||||
|
||||
builder.OpenElement(_elementIndex++, "div");
|
||||
builder.AddAttribute(_elementIndex++, "class", "mud-expand-panel mud-elevation-1 mud-expand-panel-border");
|
||||
|
||||
BuildTitle(builder);
|
||||
BuildContent(builder);
|
||||
|
||||
builder.CloseElement();
|
||||
}
|
||||
|
||||
private void BuildTitle(RenderTreeBuilder builder)
|
||||
{
|
||||
builder.OpenElement(_elementIndex++, "div");
|
||||
builder.AddAttribute(_elementIndex++, "class", "mud-expand-panel-header mud-ripple");
|
||||
builder.AddAttribute(_elementIndex++, "onclick", EventCallback.Factory.Create(this, OnHeaderClick));
|
||||
|
||||
// Text
|
||||
builder.OpenElement(_elementIndex++, "div");
|
||||
builder.AddAttribute(_elementIndex++, "class", "mud-expand-panel-text");
|
||||
builder.AddContent(_elementIndex++, TitleContent);
|
||||
builder.CloseElement();
|
||||
|
||||
// Collapse icon
|
||||
builder.OpenComponent<MudIcon>(_elementIndex++);
|
||||
builder.AddAttribute(_elementIndex++, nameof(MudIcon.Icon), Icons.Material.Filled.ExpandMore);
|
||||
builder.AddAttribute(_elementIndex++, "class", IconClasses);
|
||||
builder.CloseComponent();
|
||||
|
||||
builder.CloseElement();
|
||||
}
|
||||
|
||||
private void BuildContent(RenderTreeBuilder builder)
|
||||
{
|
||||
builder.OpenComponent<MudCollapse>(_elementIndex++);
|
||||
builder.AddAttribute(_elementIndex++, nameof(MudCollapse.Expanded), IsExpanded);
|
||||
|
||||
builder.AddAttribute(_elementIndex++, nameof(MudCollapse.ChildContent), (RenderFragment)(contentBuilder =>
|
||||
{
|
||||
contentBuilder.OpenElement(_elementIndex++, "div");
|
||||
contentBuilder.AddAttribute(_elementIndex++, "class", "mud-expand-panel-content");
|
||||
contentBuilder.AddContent(_elementIndex++, ChildContent);
|
||||
contentBuilder.CloseElement();
|
||||
}));
|
||||
|
||||
builder.CloseComponent();
|
||||
}
|
||||
|
||||
private void OnHeaderClick()
|
||||
{
|
||||
IsExpanded = !IsExpanded;
|
||||
}
|
||||
}
|
64
MudBlazor.Markdown/Components/MudMathJax.razor.cs
Normal file
64
MudBlazor.Markdown/Components/MudMathJax.razor.cs
Normal file
@ -0,0 +1,64 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
internal sealed class MudMathJax : ComponentBase
|
||||
{
|
||||
private const string ScriptId = "mudblazor-markdown-mathjax";
|
||||
|
||||
[Parameter]
|
||||
public string Delimiter { get; set; } = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public StringSlice Value { get; set; }
|
||||
|
||||
[Inject]
|
||||
private IJSRuntime Js { get; init; } = default!;
|
||||
|
||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||
{
|
||||
var elementIndex = 0;
|
||||
|
||||
var delimiter = GetDelimiter(Delimiter);
|
||||
|
||||
builder.AddContent(elementIndex++, delimiter.Start);
|
||||
builder.AddContent(elementIndex++, Value);
|
||||
builder.AddContent(elementIndex, delimiter.End);
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
await Js.InvokeVoidAsync("appendMathJaxScript", ScriptId)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await Js.InvokeVoidAsync("refreshMathJaxScript")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static MathDelimiter GetDelimiter(in string delimiter) =>
|
||||
delimiter switch
|
||||
{
|
||||
"$" => new MathDelimiter("\\(", "\\)"),
|
||||
"$$" => new MathDelimiter(delimiter),
|
||||
_ => new MathDelimiter(delimiter)
|
||||
};
|
||||
|
||||
private readonly ref struct MathDelimiter
|
||||
{
|
||||
public MathDelimiter(string delimiter)
|
||||
{
|
||||
Start = End = delimiter;
|
||||
}
|
||||
|
||||
public MathDelimiter(string start, string end)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
}
|
||||
|
||||
public string Start { get; }
|
||||
|
||||
public string End { get; }
|
||||
}
|
||||
}
|
247
MudBlazor.Markdown/Enums/CodeBlockTheme.cs
Normal file
247
MudBlazor.Markdown/Enums/CodeBlockTheme.cs
Normal file
@ -0,0 +1,247 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
public enum CodeBlockTheme : ushort
|
||||
{
|
||||
Default = 0,
|
||||
A11yDark,
|
||||
A11yLight,
|
||||
Agate,
|
||||
AnOldHope,
|
||||
Androidstudio,
|
||||
ArduinoLight,
|
||||
Arta,
|
||||
Ascetic,
|
||||
AtomOneDarkReasonable,
|
||||
AtomOneDark,
|
||||
AtomOneLight,
|
||||
BrownPaper,
|
||||
CodepenEmbed,
|
||||
ColorBrewer,
|
||||
Dark,
|
||||
Devibeans,
|
||||
Docco,
|
||||
Far,
|
||||
Foundation,
|
||||
GithubDarkDimmed,
|
||||
GithubDark,
|
||||
Github,
|
||||
Gml,
|
||||
Googlecode,
|
||||
GradientDark,
|
||||
GradientLight,
|
||||
Grayscale,
|
||||
Hybrid,
|
||||
Idea,
|
||||
IrBlack,
|
||||
IsblEditorDark,
|
||||
IsblEditorLight,
|
||||
KimbieDark,
|
||||
KimbieLight,
|
||||
Lightfair,
|
||||
Lioshi,
|
||||
Magula,
|
||||
MonoBlue,
|
||||
MonokaiSublime,
|
||||
Monokai,
|
||||
NightOwl,
|
||||
NnfxDark,
|
||||
NnfxLight,
|
||||
Nord,
|
||||
Obsidian,
|
||||
ParaisoDark,
|
||||
ParaisoLight,
|
||||
Pojoaque,
|
||||
Purebasic,
|
||||
QtcreatorDark,
|
||||
QtcreatorLight,
|
||||
Rainbow,
|
||||
Routeros,
|
||||
SchoolBook,
|
||||
ShadesOfPurple,
|
||||
Srcery,
|
||||
StackoverflowDark,
|
||||
StackoverflowLight,
|
||||
Sunburst,
|
||||
TomorrowNightBlue,
|
||||
TomorrowNightBright,
|
||||
Vs,
|
||||
Vs2015,
|
||||
Xcode,
|
||||
Xt256,
|
||||
ApathyBase16,
|
||||
ApprenticeBase16,
|
||||
AshesBase16,
|
||||
AtelierCaveLightBase16,
|
||||
AtelierCaveBase16,
|
||||
AtelierDuneLightBase16,
|
||||
AtelierDuneBase16,
|
||||
AtelierEstuaryLightBase16,
|
||||
AtelierEstuaryBase16,
|
||||
AtelierForestLightBase16,
|
||||
AtelierForestBase16,
|
||||
AtelierHeathLightBase16,
|
||||
AtelierHeathBase16,
|
||||
AtelierLakesideLightBase16,
|
||||
AtelierLakesideBase16,
|
||||
AtelierPlateauLightBase16,
|
||||
AtelierPlateauBase16,
|
||||
AtelierSavannaLightBase16,
|
||||
AtelierSavannaBase16,
|
||||
AtelierSeasideLightBase16,
|
||||
AtelierSeasideBase16,
|
||||
AtelierSulphurpoolLightBase16,
|
||||
AtelierSulphurpoolBase16,
|
||||
AtlasBase16,
|
||||
BespinBase16,
|
||||
BlackMetalBathoryBase16,
|
||||
BlackMetalBurzumBase16,
|
||||
BlackMetalDarkFuneralBase16,
|
||||
BlackMetalGorgorothBase16,
|
||||
BlackMetalImmortalBase16,
|
||||
BlackMetalKholdBase16,
|
||||
BlackMetalMardukBase16,
|
||||
BlackMetalMayhemBase16,
|
||||
BlackMetalNileBase16,
|
||||
BlackMetalVenomBase16,
|
||||
BlackMetalBase16,
|
||||
BrewerBase16,
|
||||
BrightBase16,
|
||||
BrogrammerBase16,
|
||||
BrushTreesDarkBase16,
|
||||
BrushTreesBase16,
|
||||
ChalkBase16,
|
||||
CircusBase16,
|
||||
ClassicDarkBase16,
|
||||
ClassicLightBase16,
|
||||
CodeschoolBase16,
|
||||
ColorsBase16,
|
||||
CupcakeBase16,
|
||||
CupertinoBase16,
|
||||
DanqingBase16,
|
||||
DarculaBase16,
|
||||
DarkVioletBase16,
|
||||
DarkmossBase16,
|
||||
DarktoothBase16,
|
||||
DecafBase16,
|
||||
DefaultDarkBase16,
|
||||
DefaultLightBase16,
|
||||
DirtyseaBase16,
|
||||
DraculaBase16,
|
||||
EdgeDarkBase16,
|
||||
EdgeLightBase16,
|
||||
EightiesBase16,
|
||||
EmbersBase16,
|
||||
EquilibriumDarkBase16,
|
||||
EquilibriumGrayDarkBase16,
|
||||
EquilibriumGrayLightBase16,
|
||||
EquilibriumLightBase16,
|
||||
EspressoBase16,
|
||||
EvaDimBase16,
|
||||
EvaBase16,
|
||||
FlatBase16,
|
||||
FramerBase16,
|
||||
FruitSodaBase16,
|
||||
GigavoltBase16,
|
||||
GithubBase16,
|
||||
GoogleDarkBase16,
|
||||
GoogleLightBase16,
|
||||
GrayscaleDarkBase16,
|
||||
GrayscaleLightBase16,
|
||||
GreenScreenBase16,
|
||||
GruvboxDarkHardBase16,
|
||||
GruvboxDarkMediumBase16,
|
||||
GruvboxDarkPaleBase16,
|
||||
GruvboxDarkSoftBase16,
|
||||
GruvboxLightHardBase16,
|
||||
GruvboxLightMediumBase16,
|
||||
GruvboxLightSoftBase16,
|
||||
HardcoreBase16,
|
||||
Harmonic16DarkBase16,
|
||||
Harmonic16LightBase16,
|
||||
HeetchDarkBase16,
|
||||
HeetchLightBase16,
|
||||
HeliosBase16,
|
||||
HopscotchBase16,
|
||||
HorizonDarkBase16,
|
||||
HorizonLightBase16,
|
||||
HumanoidDarkBase16,
|
||||
HumanoidLightBase16,
|
||||
IaDarkBase16,
|
||||
IaLightBase16,
|
||||
IcyDarkBase16,
|
||||
IrBlackBase16,
|
||||
IsotopeBase16,
|
||||
KimberBase16,
|
||||
LondonTubeBase16,
|
||||
MacintoshBase16,
|
||||
MarrakeshBase16,
|
||||
MateriaBase16,
|
||||
MaterialDarkerBase16,
|
||||
MaterialLighterBase16,
|
||||
MaterialPalenightBase16,
|
||||
MaterialVividBase16,
|
||||
MaterialBase16,
|
||||
MellowPurpleBase16,
|
||||
MexicoLightBase16,
|
||||
MochaBase16,
|
||||
MonokaiBase16,
|
||||
NebulaBase16,
|
||||
NordBase16,
|
||||
NovaBase16,
|
||||
OceanBase16,
|
||||
OceanicnextBase16,
|
||||
OneLightBase16,
|
||||
OnedarkBase16,
|
||||
OutrunDarkBase16,
|
||||
PapercolorDarkBase16,
|
||||
PapercolorLightBase16,
|
||||
ParaisoBase16,
|
||||
PasqueBase16,
|
||||
PhdBase16,
|
||||
PicoBase16,
|
||||
PopBase16,
|
||||
PorpleBase16,
|
||||
QualiaBase16,
|
||||
RailscastsBase16,
|
||||
RebeccaBase16,
|
||||
RosPineDawnBase16,
|
||||
RosPineMoonBase16,
|
||||
RosPineBase16,
|
||||
SagelightBase16,
|
||||
SandcastleBase16,
|
||||
SetiUiBase16,
|
||||
ShapeshifterBase16,
|
||||
SilkDarkBase16,
|
||||
SilkLightBase16,
|
||||
SnazzyBase16,
|
||||
SolarFlareLightBase16,
|
||||
SolarFlareBase16,
|
||||
SolarizedDarkBase16,
|
||||
SolarizedLightBase16,
|
||||
SpacemacsBase16,
|
||||
SummercampBase16,
|
||||
SummerfruitDarkBase16,
|
||||
SummerfruitLightBase16,
|
||||
SynthMidnightTerminalDarkBase16,
|
||||
SynthMidnightTerminalLightBase16,
|
||||
T3024Base16,
|
||||
TangoBase16,
|
||||
TenderBase16,
|
||||
TomorrowNightBase16,
|
||||
TomorrowBase16,
|
||||
TwilightBase16,
|
||||
UnikittyDarkBase16,
|
||||
UnikittyLightBase16,
|
||||
VulcanBase16,
|
||||
Windows10LightBase16,
|
||||
Windows10Base16,
|
||||
Windows95LightBase16,
|
||||
Windows95Base16,
|
||||
WindowsHighContrastLightBase16,
|
||||
WindowsHighContrastBase16,
|
||||
WindowsNtLightBase16,
|
||||
WindowsNtBase16,
|
||||
WoodlandBase16,
|
||||
XcodeDuskBase16,
|
||||
ZenburnBase16
|
||||
}
|
252
MudBlazor.Markdown/Extensions/CodeBlockThemeEx.cs
Normal file
252
MudBlazor.Markdown/Extensions/CodeBlockThemeEx.cs
Normal file
@ -0,0 +1,252 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
internal static class CodeBlockThemeEx
|
||||
{
|
||||
public static string GetStylesheetPath(this CodeBlockTheme @this) =>
|
||||
@this switch
|
||||
{
|
||||
CodeBlockTheme.A11yDark => "a11y-dark.min.css",
|
||||
CodeBlockTheme.A11yLight => "a11y-light.min.css",
|
||||
CodeBlockTheme.Agate => "agate.min.css",
|
||||
CodeBlockTheme.AnOldHope => "an-old-hope.min.css",
|
||||
CodeBlockTheme.Androidstudio => "androidstudio.min.css",
|
||||
CodeBlockTheme.ArduinoLight => "arduino-light.min.css",
|
||||
CodeBlockTheme.Arta => "arta.min.css",
|
||||
CodeBlockTheme.Ascetic => "ascetic.min.css",
|
||||
CodeBlockTheme.AtomOneDarkReasonable => "atom-one-dark-reasonable.min.css",
|
||||
CodeBlockTheme.AtomOneDark => "atom-one-dark.min.css",
|
||||
CodeBlockTheme.AtomOneLight => "atom-one-light.min.css",
|
||||
CodeBlockTheme.BrownPaper => "brown-paper.min.css",
|
||||
CodeBlockTheme.CodepenEmbed => "codepen-embed.min.css",
|
||||
CodeBlockTheme.ColorBrewer => "color-brewer.min.css",
|
||||
CodeBlockTheme.Dark => "dark.min.css",
|
||||
CodeBlockTheme.Default => "default.min.css",
|
||||
CodeBlockTheme.Devibeans => "devibeans.min.css",
|
||||
CodeBlockTheme.Docco => "docco.min.css",
|
||||
CodeBlockTheme.Far => "far.min.css",
|
||||
CodeBlockTheme.Foundation => "foundation.min.css",
|
||||
CodeBlockTheme.GithubDarkDimmed => "github-dark-dimmed.min.css",
|
||||
CodeBlockTheme.GithubDark => "github-dark.min.css",
|
||||
CodeBlockTheme.Github => "github.min.css",
|
||||
CodeBlockTheme.Gml => "gml.min.css",
|
||||
CodeBlockTheme.Googlecode => "googlecode.min.css",
|
||||
CodeBlockTheme.GradientDark => "gradient-dark.min.css",
|
||||
CodeBlockTheme.GradientLight => "gradient-light.min.css",
|
||||
CodeBlockTheme.Grayscale => "grayscale.min.css",
|
||||
CodeBlockTheme.Hybrid => "hybrid.min.css",
|
||||
CodeBlockTheme.Idea => "idea.min.css",
|
||||
CodeBlockTheme.IrBlack => "ir-black.min.css",
|
||||
CodeBlockTheme.IsblEditorDark => "isbl-editor-dark.min.css",
|
||||
CodeBlockTheme.IsblEditorLight => "isbl-editor-light.min.css",
|
||||
CodeBlockTheme.KimbieDark => "kimbie-dark.min.css",
|
||||
CodeBlockTheme.KimbieLight => "kimbie-light.min.css",
|
||||
CodeBlockTheme.Lightfair => "lightfair.min.css",
|
||||
CodeBlockTheme.Lioshi => "lioshi.min.css",
|
||||
CodeBlockTheme.Magula => "magula.min.css",
|
||||
CodeBlockTheme.MonoBlue => "mono-blue.min.css",
|
||||
CodeBlockTheme.MonokaiSublime => "monokai-sublime.min.css",
|
||||
CodeBlockTheme.Monokai => "monokai.min.css",
|
||||
CodeBlockTheme.NightOwl => "night-owl.min.css",
|
||||
CodeBlockTheme.NnfxDark => "nnfx-dark.min.css",
|
||||
CodeBlockTheme.NnfxLight => "nnfx-light.min.css",
|
||||
CodeBlockTheme.Nord => "nord.min.css",
|
||||
CodeBlockTheme.Obsidian => "obsidian.min.css",
|
||||
CodeBlockTheme.ParaisoDark => "paraiso-dark.min.css",
|
||||
CodeBlockTheme.ParaisoLight => "paraiso-light.min.css",
|
||||
CodeBlockTheme.Pojoaque => "pojoaque.min.css",
|
||||
CodeBlockTheme.Purebasic => "purebasic.min.css",
|
||||
CodeBlockTheme.QtcreatorDark => "qtcreator-dark.min.css",
|
||||
CodeBlockTheme.QtcreatorLight => "qtcreator-light.min.css",
|
||||
CodeBlockTheme.Rainbow => "rainbow.min.css",
|
||||
CodeBlockTheme.Routeros => "routeros.min.css",
|
||||
CodeBlockTheme.SchoolBook => "school-book.min.css",
|
||||
CodeBlockTheme.ShadesOfPurple => "shades-of-purple.min.css",
|
||||
CodeBlockTheme.Srcery => "srcery.min.css",
|
||||
CodeBlockTheme.StackoverflowDark => "stackoverflow-dark.min.css",
|
||||
CodeBlockTheme.StackoverflowLight => "stackoverflow-light.min.css",
|
||||
CodeBlockTheme.Sunburst => "sunburst.min.css",
|
||||
CodeBlockTheme.TomorrowNightBlue => "tomorrow-night-blue.min.css",
|
||||
CodeBlockTheme.TomorrowNightBright => "tomorrow-night-bright.min.css",
|
||||
CodeBlockTheme.Vs => "vs.min.css",
|
||||
CodeBlockTheme.Vs2015 => "vs2015.min.css",
|
||||
CodeBlockTheme.Xcode => "xcode.min.css",
|
||||
CodeBlockTheme.Xt256 => "xt256.min.css",
|
||||
CodeBlockTheme.ApathyBase16 => "base16/apathy.min.css",
|
||||
CodeBlockTheme.ApprenticeBase16 => "base16/apprentice.min.css",
|
||||
CodeBlockTheme.AshesBase16 => "base16/ashes.min.css",
|
||||
CodeBlockTheme.AtelierCaveLightBase16 => "base16/atelier-cave-light.min.css",
|
||||
CodeBlockTheme.AtelierCaveBase16 => "base16/atelier-cave.min.css",
|
||||
CodeBlockTheme.AtelierDuneLightBase16 => "base16/atelier-dune-light.min.css",
|
||||
CodeBlockTheme.AtelierDuneBase16 => "base16/atelier-dune.min.css",
|
||||
CodeBlockTheme.AtelierEstuaryLightBase16 => "base16/atelier-estuary-light.min.css",
|
||||
CodeBlockTheme.AtelierEstuaryBase16 => "base16/atelier-estuary.min.css",
|
||||
CodeBlockTheme.AtelierForestLightBase16 => "base16/atelier-forest-light.min.css",
|
||||
CodeBlockTheme.AtelierForestBase16 => "base16/atelier-forest.min.css",
|
||||
CodeBlockTheme.AtelierHeathLightBase16 => "base16/atelier-heath-light.min.css",
|
||||
CodeBlockTheme.AtelierHeathBase16 => "base16/atelier-heath.min.css",
|
||||
CodeBlockTheme.AtelierLakesideLightBase16 => "base16/atelier-lakeside-light.min.css",
|
||||
CodeBlockTheme.AtelierLakesideBase16 => "base16/atelier-lakeside.min.css",
|
||||
CodeBlockTheme.AtelierPlateauLightBase16 => "base16/atelier-plateau-light.min.css",
|
||||
CodeBlockTheme.AtelierPlateauBase16 => "base16/atelier-plateau.min.css",
|
||||
CodeBlockTheme.AtelierSavannaLightBase16 => "base16/atelier-savanna-light.min.css",
|
||||
CodeBlockTheme.AtelierSavannaBase16 => "base16/atelier-savanna.min.css",
|
||||
CodeBlockTheme.AtelierSeasideLightBase16 => "base16/atelier-seaside-light.min.css",
|
||||
CodeBlockTheme.AtelierSeasideBase16 => "base16/atelier-seaside.min.css",
|
||||
CodeBlockTheme.AtelierSulphurpoolLightBase16 => "base16/atelier-sulphurpool-light.min.css",
|
||||
CodeBlockTheme.AtelierSulphurpoolBase16 => "base16/atelier-sulphurpool.min.css",
|
||||
CodeBlockTheme.AtlasBase16 => "base16/atlas.min.css",
|
||||
CodeBlockTheme.BespinBase16 => "base16/bespin.min.css",
|
||||
CodeBlockTheme.BlackMetalBathoryBase16 => "base16/black-metal-bathory.min.css",
|
||||
CodeBlockTheme.BlackMetalBurzumBase16 => "base16/black-metal-burzum.min.css",
|
||||
CodeBlockTheme.BlackMetalDarkFuneralBase16 => "base16/black-metal-dark-funeral.min.css",
|
||||
CodeBlockTheme.BlackMetalGorgorothBase16 => "base16/black-metal-gorgoroth.min.css",
|
||||
CodeBlockTheme.BlackMetalImmortalBase16 => "base16/black-metal-immortal.min.css",
|
||||
CodeBlockTheme.BlackMetalKholdBase16 => "base16/black-metal-khold.min.css",
|
||||
CodeBlockTheme.BlackMetalMardukBase16 => "base16/black-metal-marduk.min.css",
|
||||
CodeBlockTheme.BlackMetalMayhemBase16 => "base16/black-metal-mayhem.min.css",
|
||||
CodeBlockTheme.BlackMetalNileBase16 => "base16/black-metal-nile.min.css",
|
||||
CodeBlockTheme.BlackMetalVenomBase16 => "base16/black-metal-venom.min.css",
|
||||
CodeBlockTheme.BlackMetalBase16 => "base16/black-metal.min.css",
|
||||
CodeBlockTheme.BrewerBase16 => "base16/brewer.min.css",
|
||||
CodeBlockTheme.BrightBase16 => "base16/bright.min.css",
|
||||
CodeBlockTheme.BrogrammerBase16 => "base16/brogrammer.min.css",
|
||||
CodeBlockTheme.BrushTreesDarkBase16 => "base16/brush-trees-dark.min.css",
|
||||
CodeBlockTheme.BrushTreesBase16 => "base16/brush-trees.min.css",
|
||||
CodeBlockTheme.ChalkBase16 => "base16/chalk.min.css",
|
||||
CodeBlockTheme.CircusBase16 => "base16/circus.min.css",
|
||||
CodeBlockTheme.ClassicDarkBase16 => "base16/classic-dark.min.css",
|
||||
CodeBlockTheme.ClassicLightBase16 => "base16/classic-light.min.css",
|
||||
CodeBlockTheme.CodeschoolBase16 => "base16/codeschool.min.css",
|
||||
CodeBlockTheme.ColorsBase16 => "base16/colors.min.css",
|
||||
CodeBlockTheme.CupcakeBase16 => "base16/cupcake.min.css",
|
||||
CodeBlockTheme.CupertinoBase16 => "base16/cupertino.min.css",
|
||||
CodeBlockTheme.DanqingBase16 => "base16/danqing.min.css",
|
||||
CodeBlockTheme.DarculaBase16 => "base16/darcula.min.css",
|
||||
CodeBlockTheme.DarkVioletBase16 => "base16/dark-violet.min.css",
|
||||
CodeBlockTheme.DarkmossBase16 => "base16/darkmoss.min.css",
|
||||
CodeBlockTheme.DarktoothBase16 => "base16/darktooth.min.css",
|
||||
CodeBlockTheme.DecafBase16 => "base16/decaf.min.css",
|
||||
CodeBlockTheme.DefaultDarkBase16 => "base16/default-dark.min.css",
|
||||
CodeBlockTheme.DefaultLightBase16 => "base16/default-light.min.css",
|
||||
CodeBlockTheme.DirtyseaBase16 => "base16/dirtysea.min.css",
|
||||
CodeBlockTheme.DraculaBase16 => "base16/dracula.min.css",
|
||||
CodeBlockTheme.EdgeDarkBase16 => "base16/edge-dark.min.css",
|
||||
CodeBlockTheme.EdgeLightBase16 => "base16/edge-light.min.css",
|
||||
CodeBlockTheme.EightiesBase16 => "base16/eighties.min.css",
|
||||
CodeBlockTheme.EmbersBase16 => "base16/embers.min.css",
|
||||
CodeBlockTheme.EquilibriumDarkBase16 => "base16/equilibrium-dark.min.css",
|
||||
CodeBlockTheme.EquilibriumGrayDarkBase16 => "base16/equilibrium-gray-dark.min.css",
|
||||
CodeBlockTheme.EquilibriumGrayLightBase16 => "base16/equilibrium-gray-light.min.css",
|
||||
CodeBlockTheme.EquilibriumLightBase16 => "base16/equilibrium-light.min.css",
|
||||
CodeBlockTheme.EspressoBase16 => "base16/espresso.min.css",
|
||||
CodeBlockTheme.EvaDimBase16 => "base16/eva-dim.min.css",
|
||||
CodeBlockTheme.EvaBase16 => "base16/eva.min.css",
|
||||
CodeBlockTheme.FlatBase16 => "base16/flat.min.css",
|
||||
CodeBlockTheme.FramerBase16 => "base16/framer.min.css",
|
||||
CodeBlockTheme.FruitSodaBase16 => "base16/fruit-soda.min.css",
|
||||
CodeBlockTheme.GigavoltBase16 => "base16/gigavolt.min.css",
|
||||
CodeBlockTheme.GithubBase16 => "base16/github.min.css",
|
||||
CodeBlockTheme.GoogleDarkBase16 => "base16/google-dark.min.css",
|
||||
CodeBlockTheme.GoogleLightBase16 => "base16/google-light.min.css",
|
||||
CodeBlockTheme.GrayscaleDarkBase16 => "base16/grayscale-dark.min.css",
|
||||
CodeBlockTheme.GrayscaleLightBase16 => "base16/grayscale-light.min.css",
|
||||
CodeBlockTheme.GreenScreenBase16 => "base16/green-screen.min.css",
|
||||
CodeBlockTheme.GruvboxDarkHardBase16 => "base16/gruvbox-dark-hard.min.css",
|
||||
CodeBlockTheme.GruvboxDarkMediumBase16 => "base16/gruvbox-dark-medium.min.css",
|
||||
CodeBlockTheme.GruvboxDarkPaleBase16 => "base16/gruvbox-dark-pale.min.css",
|
||||
CodeBlockTheme.GruvboxDarkSoftBase16 => "base16/gruvbox-dark-soft.min.css",
|
||||
CodeBlockTheme.GruvboxLightHardBase16 => "base16/gruvbox-light-hard.min.css",
|
||||
CodeBlockTheme.GruvboxLightMediumBase16 => "base16/gruvbox-light-medium.min.css",
|
||||
CodeBlockTheme.GruvboxLightSoftBase16 => "base16/gruvbox-light-soft.min.css",
|
||||
CodeBlockTheme.HardcoreBase16 => "base16/hardcore.min.css",
|
||||
CodeBlockTheme.Harmonic16DarkBase16 => "base16/harmonic16-dark.min.css",
|
||||
CodeBlockTheme.Harmonic16LightBase16 => "base16/harmonic16-light.min.css",
|
||||
CodeBlockTheme.HeetchDarkBase16 => "base16/heetch-dark.min.css",
|
||||
CodeBlockTheme.HeetchLightBase16 => "base16/heetch-light.min.css",
|
||||
CodeBlockTheme.HeliosBase16 => "base16/helios.min.css",
|
||||
CodeBlockTheme.HopscotchBase16 => "base16/hopscotch.min.css",
|
||||
CodeBlockTheme.HorizonDarkBase16 => "base16/horizon-dark.min.css",
|
||||
CodeBlockTheme.HorizonLightBase16 => "base16/horizon-light.min.css",
|
||||
CodeBlockTheme.HumanoidDarkBase16 => "base16/humanoid-dark.min.css",
|
||||
CodeBlockTheme.HumanoidLightBase16 => "base16/humanoid-light.min.css",
|
||||
CodeBlockTheme.IaDarkBase16 => "base16/ia-dark.min.css",
|
||||
CodeBlockTheme.IaLightBase16 => "base16/ia-light.min.css",
|
||||
CodeBlockTheme.IcyDarkBase16 => "base16/icy-dark.min.css",
|
||||
CodeBlockTheme.IrBlackBase16 => "base16/ir-black.min.css",
|
||||
CodeBlockTheme.IsotopeBase16 => "base16/isotope.min.css",
|
||||
CodeBlockTheme.KimberBase16 => "base16/kimber.min.css",
|
||||
CodeBlockTheme.LondonTubeBase16 => "base16/london-tube.min.css",
|
||||
CodeBlockTheme.MacintoshBase16 => "base16/macintosh.min.css",
|
||||
CodeBlockTheme.MarrakeshBase16 => "base16/marrakesh.min.css",
|
||||
CodeBlockTheme.MateriaBase16 => "base16/materia.min.css",
|
||||
CodeBlockTheme.MaterialDarkerBase16 => "base16/material-darker.min.css",
|
||||
CodeBlockTheme.MaterialLighterBase16 => "base16/material-lighter.min.css",
|
||||
CodeBlockTheme.MaterialPalenightBase16 => "base16/material-palenight.min.css",
|
||||
CodeBlockTheme.MaterialVividBase16 => "base16/material-vivid.min.css",
|
||||
CodeBlockTheme.MaterialBase16 => "base16/material.min.css",
|
||||
CodeBlockTheme.MellowPurpleBase16 => "base16/mellow-purple.min.css",
|
||||
CodeBlockTheme.MexicoLightBase16 => "base16/mexico-light.min.css",
|
||||
CodeBlockTheme.MochaBase16 => "base16/mocha.min.css",
|
||||
CodeBlockTheme.MonokaiBase16 => "base16/monokai.min.css",
|
||||
CodeBlockTheme.NebulaBase16 => "base16/nebula.min.css",
|
||||
CodeBlockTheme.NordBase16 => "base16/nord.min.css",
|
||||
CodeBlockTheme.NovaBase16 => "base16/nova.min.css",
|
||||
CodeBlockTheme.OceanBase16 => "base16/ocean.min.css",
|
||||
CodeBlockTheme.OceanicnextBase16 => "base16/oceanicnext.min.css",
|
||||
CodeBlockTheme.OneLightBase16 => "base16/one-light.min.css",
|
||||
CodeBlockTheme.OnedarkBase16 => "base16/onedark.min.css",
|
||||
CodeBlockTheme.OutrunDarkBase16 => "base16/outrun-dark.min.css",
|
||||
CodeBlockTheme.PapercolorDarkBase16 => "base16/papercolor-dark.min.css",
|
||||
CodeBlockTheme.PapercolorLightBase16 => "base16/papercolor-light.min.css",
|
||||
CodeBlockTheme.ParaisoBase16 => "base16/paraiso.min.css",
|
||||
CodeBlockTheme.PasqueBase16 => "base16/pasque.min.css",
|
||||
CodeBlockTheme.PhdBase16 => "base16/phd.min.css",
|
||||
CodeBlockTheme.PicoBase16 => "base16/pico.min.css",
|
||||
CodeBlockTheme.PopBase16 => "base16/pop.min.css",
|
||||
CodeBlockTheme.PorpleBase16 => "base16/porple.min.css",
|
||||
CodeBlockTheme.QualiaBase16 => "base16/qualia.min.css",
|
||||
CodeBlockTheme.RailscastsBase16 => "base16/railscasts.min.css",
|
||||
CodeBlockTheme.RebeccaBase16 => "base16/rebecca.min.css",
|
||||
CodeBlockTheme.RosPineDawnBase16 => "base16/ros-pine-dawn.min.css",
|
||||
CodeBlockTheme.RosPineMoonBase16 => "base16/ros-pine-moon.min.css",
|
||||
CodeBlockTheme.RosPineBase16 => "base16/ros-pine.min.css",
|
||||
CodeBlockTheme.SagelightBase16 => "base16/sagelight.min.css",
|
||||
CodeBlockTheme.SandcastleBase16 => "base16/sandcastle.min.css",
|
||||
CodeBlockTheme.SetiUiBase16 => "base16/seti-ui.min.css",
|
||||
CodeBlockTheme.ShapeshifterBase16 => "base16/shapeshifter.min.css",
|
||||
CodeBlockTheme.SilkDarkBase16 => "base16/silk-dark.min.css",
|
||||
CodeBlockTheme.SilkLightBase16 => "base16/silk-light.min.css",
|
||||
CodeBlockTheme.SnazzyBase16 => "base16/snazzy.min.css",
|
||||
CodeBlockTheme.SolarFlareLightBase16 => "base16/solar-flare-light.min.css",
|
||||
CodeBlockTheme.SolarFlareBase16 => "base16/solar-flare.min.css",
|
||||
CodeBlockTheme.SolarizedDarkBase16 => "base16/solarized-dark.min.css",
|
||||
CodeBlockTheme.SolarizedLightBase16 => "base16/solarized-light.min.css",
|
||||
CodeBlockTheme.SpacemacsBase16 => "base16/spacemacs.min.css",
|
||||
CodeBlockTheme.SummercampBase16 => "base16/summercamp.min.css",
|
||||
CodeBlockTheme.SummerfruitDarkBase16 => "base16/summerfruit-dark.min.css",
|
||||
CodeBlockTheme.SummerfruitLightBase16 => "base16/summerfruit-light.min.css",
|
||||
CodeBlockTheme.SynthMidnightTerminalDarkBase16 => "base16/synth-midnight-terminal-dark.min.css",
|
||||
CodeBlockTheme.SynthMidnightTerminalLightBase16 => "base16/synth-midnight-terminal-light.min.css",
|
||||
CodeBlockTheme.T3024Base16 => "base16/t3024.min.css",
|
||||
CodeBlockTheme.TangoBase16 => "base16/tango.min.css",
|
||||
CodeBlockTheme.TenderBase16 => "base16/tender.min.css",
|
||||
CodeBlockTheme.TomorrowNightBase16 => "base16/tomorrow-night.min.css",
|
||||
CodeBlockTheme.TomorrowBase16 => "base16/tomorrow.min.css",
|
||||
CodeBlockTheme.TwilightBase16 => "base16/twilight.min.css",
|
||||
CodeBlockTheme.UnikittyDarkBase16 => "base16/unikitty-dark.min.css",
|
||||
CodeBlockTheme.UnikittyLightBase16 => "base16/unikitty-light.min.css",
|
||||
CodeBlockTheme.VulcanBase16 => "base16/vulcan.min.css",
|
||||
CodeBlockTheme.Windows10LightBase16 => "base16/windows-10-light.min.css",
|
||||
CodeBlockTheme.Windows10Base16 => "base16/windows-10.min.css",
|
||||
CodeBlockTheme.Windows95LightBase16 => "base16/windows-95-light.min.css",
|
||||
CodeBlockTheme.Windows95Base16 => "base16/windows-95.min.css",
|
||||
CodeBlockTheme.WindowsHighContrastLightBase16 => "base16/windows-high-contrast-light.min.css",
|
||||
CodeBlockTheme.WindowsHighContrastBase16 => "base16/windows-high-contrast.min.css",
|
||||
CodeBlockTheme.WindowsNtLightBase16 => "base16/windows-nt-light.min.css",
|
||||
CodeBlockTheme.WindowsNtBase16 => "base16/windows-nt.min.css",
|
||||
CodeBlockTheme.WoodlandBase16 => "base16/woodland.min.css",
|
||||
CodeBlockTheme.XcodeDuskBase16 => "base16/xcode-dusk.min.css",
|
||||
CodeBlockTheme.ZenburnBase16 => "base16/zenburn.min.css",
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
25
MudBlazor.Markdown/Extensions/EmphasisInlineEx.cs
Normal file
25
MudBlazor.Markdown/Extensions/EmphasisInlineEx.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace MudBlazor;
|
||||
|
||||
internal static class EmphasisInlineEx
|
||||
{
|
||||
public static bool TryGetEmphasisElement(this EmphasisInline emphasis, out string value)
|
||||
{
|
||||
const string italics = "i", bold = "b";
|
||||
|
||||
value = emphasis.DelimiterChar switch
|
||||
{
|
||||
'*' => emphasis.DelimiterCount switch
|
||||
{
|
||||
1 => italics,
|
||||
2 => bold,
|
||||
_ => string.Empty
|
||||
},
|
||||
'_' => italics,
|
||||
_ => string.Empty
|
||||
};
|
||||
|
||||
return !string.IsNullOrEmpty(value);
|
||||
}
|
||||
}
|
30
MudBlazor.Markdown/Extensions/FencedCodeBlockEx.cs
Normal file
30
MudBlazor.Markdown/Extensions/FencedCodeBlockEx.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System.Text;
|
||||
using Markdig.Syntax;
|
||||
|
||||
namespace MudBlazor;
|
||||
|
||||
internal static class FencedCodeBlockEx
|
||||
{
|
||||
public static string CreateCodeBlockText(this FencedCodeBlock @this)
|
||||
{
|
||||
if (@this.Lines.Count == 0)
|
||||
return string.Empty;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
foreach (var line in @this.Lines)
|
||||
{
|
||||
var str = line.ToString();
|
||||
|
||||
if (string.IsNullOrEmpty(str))
|
||||
continue;
|
||||
|
||||
if (sb.Length != 0)
|
||||
sb.AppendLine();
|
||||
|
||||
sb.Append(str);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
45
MudBlazor.Markdown/Extensions/HeadingBlockEx.cs
Normal file
45
MudBlazor.Markdown/Extensions/HeadingBlockEx.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace MudBlazor;
|
||||
|
||||
internal static class HeadingBlockEx
|
||||
{
|
||||
private const char JoinChar = '-';
|
||||
private static readonly string[] EscapeChars = { "+", ":", "&" };
|
||||
|
||||
public static string? BuildIdString(this HeadingBlock @this)
|
||||
{
|
||||
if (@this.Inline == null)
|
||||
return null;
|
||||
|
||||
var slices = @this.Inline
|
||||
.Select(static x => x.GetStringContent())
|
||||
.Where(static x => x.Length > 0);
|
||||
|
||||
return string.Join(JoinChar, slices);
|
||||
}
|
||||
|
||||
private static string GetStringContent(this Inline @this)
|
||||
{
|
||||
var slice = @this switch
|
||||
{
|
||||
LiteralInline x => x.Content,
|
||||
_ => StringSlice.Empty
|
||||
};
|
||||
|
||||
return PrepareStringContent(slice.ToString());
|
||||
}
|
||||
|
||||
private static string PrepareStringContent(this string @this)
|
||||
{
|
||||
var words = @this.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
var str = string.Join(JoinChar, words).ToLower();
|
||||
|
||||
for (var i = 0; i < EscapeChars.Length; i++)
|
||||
str = str.Replace(EscapeChars[i], string.Empty);
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
25
MudBlazor.Markdown/Extensions/HtmlBlockEx.cs
Normal file
25
MudBlazor.Markdown/Extensions/HtmlBlockEx.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using Markdig.Syntax;
|
||||
|
||||
namespace MudBlazor;
|
||||
|
||||
internal static class HtmlBlockEx
|
||||
{
|
||||
public static bool TryGetDetails(this HtmlBlock @this, out HtmlDetailsData htmlDetailsData)
|
||||
{
|
||||
htmlDetailsData = new HtmlDetailsData();
|
||||
|
||||
// Closing `>` for <details> is missing because there might be attributes for this tag
|
||||
if (!@this.Lines.StartsAndEndsWith("<details", "</details>", out var range))
|
||||
return false;
|
||||
|
||||
// Closing `>` for <summary> is missing because there might be attributes for this tag
|
||||
var summaryEndIndex = @this.Lines.TryGetContent("<summary", "</summary>", range.Start, out var headerContent);
|
||||
if (summaryEndIndex.Line == -1)
|
||||
return false;
|
||||
|
||||
var dataContent = @this.Lines.GetContent(summaryEndIndex, range.End);
|
||||
|
||||
htmlDetailsData = new HtmlDetailsData(headerContent, dataContent);
|
||||
return true;
|
||||
}
|
||||
}
|
13
MudBlazor.Markdown/Extensions/MathInlineEx.cs
Normal file
13
MudBlazor.Markdown/Extensions/MathInlineEx.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using Markdig.Extensions.Mathematics;
|
||||
|
||||
namespace MudBlazor;
|
||||
|
||||
internal static class MathInlineEx
|
||||
{
|
||||
public static string GetDelimiter(this MathInline @this) =>
|
||||
string.Create(@this.DelimiterCount, @this.Delimiter, static (span, c) =>
|
||||
{
|
||||
for (var i = 0; i < span.Length; i++)
|
||||
span[i] = c;
|
||||
});
|
||||
}
|
28
MudBlazor.Markdown/Extensions/StringEx.cs
Normal file
28
MudBlazor.Markdown/Extensions/StringEx.cs
Normal file
@ -0,0 +1,28 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
internal static class StringEx
|
||||
{
|
||||
public static bool IsExternalUri(this string? @this, string? baseUri)
|
||||
{
|
||||
if (string.IsNullOrEmpty(@this) || string.IsNullOrEmpty(baseUri))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
var uri = new Uri(@this, UriKind.RelativeOrAbsolute);
|
||||
return uri.IsAbsoluteUri && !@this.StartsWith(baseUri);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static int ParseOrDefault(this string? @this)
|
||||
{
|
||||
if (!int.TryParse(@this, out var intValue))
|
||||
intValue = 0;
|
||||
|
||||
return intValue;
|
||||
}
|
||||
}
|
27
MudBlazor.Markdown/Extensions/StringLineEx.cs
Normal file
27
MudBlazor.Markdown/Extensions/StringLineEx.cs
Normal file
@ -0,0 +1,27 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
internal static class StringLineEx
|
||||
{
|
||||
public static int IndexOf(this StringLine @this, string value, int startIndex = 0)
|
||||
{
|
||||
const int notFoundIndex = -1;
|
||||
|
||||
if (@this.Slice.Length < value.Length)
|
||||
return notFoundIndex;
|
||||
|
||||
for (var i = startIndex; i <= @this.Slice.Length - value.Length; i++)
|
||||
{
|
||||
var j = 0;
|
||||
for (; j < value.Length; j++)
|
||||
{
|
||||
if (@this.Slice[@this.Position + i + j] != value[j])
|
||||
break;
|
||||
}
|
||||
|
||||
if (j == value.Length)
|
||||
return i;
|
||||
}
|
||||
|
||||
return notFoundIndex;
|
||||
}
|
||||
}
|
131
MudBlazor.Markdown/Extensions/StringLineGroupEx.cs
Normal file
131
MudBlazor.Markdown/Extensions/StringLineGroupEx.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using System.Text;
|
||||
|
||||
namespace MudBlazor;
|
||||
|
||||
internal static class StringLineGroupEx
|
||||
{
|
||||
public static bool StartsAndEndsWith(this StringLineGroup @this, in string startsWith, in string endsWith, out StringLineGroupRange range)
|
||||
{
|
||||
range = new StringLineGroupRange();
|
||||
|
||||
if (@this.Count == 0)
|
||||
return false;
|
||||
|
||||
const int firstLineIndex = 0;
|
||||
var lastLineIndex = @this.Count - 1;
|
||||
|
||||
// Starts with
|
||||
var firstLine = @this.Lines[firstLineIndex];
|
||||
if (firstLine.Slice.Length < startsWith.Length)
|
||||
return false;
|
||||
|
||||
var startIndex = 0;
|
||||
for (;startIndex < startsWith.Length; startIndex++)
|
||||
if (firstLine.Slice[firstLine.Position + startIndex] != startsWith[startIndex])
|
||||
return false;
|
||||
|
||||
// Ends with
|
||||
var lastLine = @this.Lines[lastLineIndex];
|
||||
if (lastLine.Slice.Length < endsWith.Length)
|
||||
return false;
|
||||
|
||||
var endIndex = lastLine.Slice.Length - 1;
|
||||
for (var i = endsWith.Length - 1; i >= 0; i--, endIndex--)
|
||||
if (endsWith[i] != lastLine.Slice[lastLine.Position + endIndex])
|
||||
return false;
|
||||
|
||||
range = new StringLineGroupRange(
|
||||
new StringLineGroupIndex(firstLineIndex, startIndex),
|
||||
new StringLineGroupIndex(lastLineIndex, endIndex));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static StringLineGroupIndex TryGetContent(this StringLineGroup @this, in string startsWith, in string endsWith, in StringLineGroupIndex startIndex, out string content)
|
||||
{
|
||||
var endIndex = new StringLineGroupIndex(-1, -1);
|
||||
|
||||
var isFound = false;
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
for (var i = startIndex.Line; i < @this.Count; i++)
|
||||
{
|
||||
for (var j = i == startIndex.Line ? startIndex.Index : 0; j < @this.Lines[i].Slice.Length; j++)
|
||||
{
|
||||
if (!isFound)
|
||||
{
|
||||
var start = @this.Lines[i].IndexOf(startsWith);
|
||||
if (start == -1)
|
||||
continue;
|
||||
|
||||
isFound = true;
|
||||
j = @this.Lines[i].IndexOf(">", start);
|
||||
}
|
||||
else
|
||||
{
|
||||
var end = @this.Lines[i].IndexOf(endsWith);
|
||||
if (end == -1)
|
||||
{
|
||||
var strValue = @this.Lines[i].ToString().Trim();
|
||||
stringBuilder.Append(strValue);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
var strValue = @this.Lines[i].Slice.AsSpan()[j..end].ToString().Trim();
|
||||
stringBuilder.Append(strValue);
|
||||
|
||||
endIndex = new StringLineGroupIndex(i, end + endsWith.Length);
|
||||
goto Return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Return:
|
||||
content = stringBuilder.ToString();
|
||||
return endIndex;
|
||||
}
|
||||
|
||||
public static string GetContent(this StringLineGroup @this, in StringLineGroupIndex startIndex, in StringLineGroupIndex endIndex)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
for (var i = startIndex.Line; i <= endIndex.Line; i++)
|
||||
{
|
||||
if (i == startIndex.Line)
|
||||
{
|
||||
if (i == endIndex.Line)
|
||||
{
|
||||
var strValue = @this.Lines[i].Slice.AsSpan()[startIndex.Index..endIndex.Index].ToString().Trim();
|
||||
stringBuilder.Append(strValue);
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
var strValue = @this.Lines[i].Slice.AsSpan()[startIndex.Index..].ToString().Trim();
|
||||
stringBuilder.Append(strValue);
|
||||
}
|
||||
}
|
||||
else if (i == endIndex.Line)
|
||||
{
|
||||
if (endIndex.Index == -1)
|
||||
break;
|
||||
|
||||
var strValue = @this.Lines[i].Slice.AsSpan()[..endIndex.Index].ToString().Trim();
|
||||
stringBuilder.Append(strValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stringBuilder.Length != 0)
|
||||
stringBuilder.AppendLine();
|
||||
|
||||
var strValue = @this.Lines[i].ToString().Trim();
|
||||
stringBuilder.Append(strValue);
|
||||
}
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
24
MudBlazor.Markdown/Helpers/MudMarkdownStyling.cs
Normal file
24
MudBlazor.Markdown/Helpers/MudMarkdownStyling.cs
Normal file
@ -0,0 +1,24 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
public sealed class MudMarkdownStyling
|
||||
{
|
||||
public TableStyling Table { get; } = new();
|
||||
|
||||
public sealed class TableStyling
|
||||
{
|
||||
/// <summary>
|
||||
/// If true, striped table rows will be used.
|
||||
/// </summary>
|
||||
public bool IsStriped { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If true, table's cells will have left/right borders.
|
||||
/// </summary>
|
||||
public bool IsBordered { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Child content of component.
|
||||
/// </summary>
|
||||
public int Elevation { set; get; } = 1;
|
||||
}
|
||||
}
|
14
MudBlazor.Markdown/Models/HtmlDetailsData.cs
Normal file
14
MudBlazor.Markdown/Models/HtmlDetailsData.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
internal readonly ref struct HtmlDetailsData
|
||||
{
|
||||
public HtmlDetailsData(string header, string content)
|
||||
{
|
||||
Header = header;
|
||||
Content = content;
|
||||
}
|
||||
|
||||
public string Header { get; }
|
||||
|
||||
public string Content { get; }
|
||||
}
|
14
MudBlazor.Markdown/Models/StringLineGroupIndex.cs
Normal file
14
MudBlazor.Markdown/Models/StringLineGroupIndex.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
internal readonly ref struct StringLineGroupIndex
|
||||
{
|
||||
public StringLineGroupIndex(int line, int index)
|
||||
{
|
||||
Line = line;
|
||||
Index = index;
|
||||
}
|
||||
|
||||
public int Line { get; }
|
||||
|
||||
public int Index { get; }
|
||||
}
|
14
MudBlazor.Markdown/Models/StringLineGroupRange.cs
Normal file
14
MudBlazor.Markdown/Models/StringLineGroupRange.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
internal readonly ref struct StringLineGroupRange
|
||||
{
|
||||
public StringLineGroupRange(StringLineGroupIndex start, StringLineGroupIndex end)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
}
|
||||
|
||||
public StringLineGroupIndex Start { get; }
|
||||
|
||||
public StringLineGroupIndex End { get; }
|
||||
}
|
47
MudBlazor.Markdown/MudBlazor.Markdown.csproj
Normal file
47
MudBlazor.Markdown/MudBlazor.Markdown.csproj
Normal file
@ -0,0 +1,47 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>MudBlazor</RootNamespace>
|
||||
<Version>0.1.3</Version>
|
||||
<Authors>MyNihongo</Authors>
|
||||
<Description>Markdown component for MudBlazor (https://mudblazor.com/)</Description>
|
||||
<Copyright>Copyright © 2023 MyNihongo</Copyright>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryUrl>https://github.com/MyNihongo/MudBlazor.Markdown</RepositoryUrl>
|
||||
<PackageProjectUrl>https://mudblazor.com/</PackageProjectUrl>
|
||||
<PackageIcon>favico.png</PackageIcon>
|
||||
<PackageTags>mudblazor, blazor, markdown</PackageTags>
|
||||
<GeneratePackageOnBuild Condition="'$(Configuration)'=='Release'">true</GeneratePackageOnBuild>
|
||||
<PackageReleaseNotes>https://github.com/MyNihongo/MudBlazor.Markdown/releases</PackageReleaseNotes>
|
||||
<Title>MudBlazor Markdown</Title>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Markdig" Version="0.33.0" />
|
||||
<PackageReference Include="MudBlazor" Version="6.11.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent" Condition="'$(Configuration)'=='Release'">
|
||||
<Exec Command="npm run build" />
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\..\favico.png" Pack="true" PackagePath="\" />
|
||||
<None Include="..\..\README.md" Pack="true" PackagePath="\" />
|
||||
<Content Remove="**\package*.json" />
|
||||
<None Remove="*.csproj.DotSettings" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
10
MudBlazor.Markdown/MudBlazor.Markdown.csproj.DotSettings
Normal file
10
MudBlazor.Markdown/MudBlazor.Markdown.csproj.DotSettings
Normal file
@ -0,0 +1,10 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=components/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=enums/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=extensions/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=helpers/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cinterfaces/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=services_005Cregistration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=utils/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
500
MudBlazor.Markdown/MudMarkdown.razor.cs
Normal file
500
MudBlazor.Markdown/MudMarkdown.razor.cs
Normal file
@ -0,0 +1,500 @@
|
||||
using Markdig.Extensions.Mathematics;
|
||||
using Markdig.Extensions.Tables;
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
using Microsoft.AspNetCore.Components.Routing;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
|
||||
namespace MudBlazor;
|
||||
|
||||
public class MudMarkdown : ComponentBase, IDisposable
|
||||
{
|
||||
protected IMudMarkdownThemeService? ThemeService;
|
||||
|
||||
protected MarkdownPipeline? Pipeline;
|
||||
protected bool EnableLinkNavigation;
|
||||
protected int ElementIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Markdown text to be rendered in the component.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Value { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum width (in pixels) for a table cell.<br/>
|
||||
/// If <see langword="null" /> or negative the minimum width is not applied.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int? TableCellMinWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Command which is invoked when a link is clicked.<br/>
|
||||
/// If <see langword="null" /> a link is opened in the browser.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public ICommand? LinkCommand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Theme of the code block.<br/>
|
||||
/// Browse available themes here: https://highlightjs.org/static/demo/
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public CodeBlockTheme CodeBlockTheme { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Override the original URL address of the <see cref="LinkInline"/>.<br/>
|
||||
/// If a function is not provided <see cref="LinkInline.Url"/> is used
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<LinkInline, string?>? OverrideLinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Typography variant to use for Heading Level 1-6.<br/>
|
||||
/// If a function is not provided a default typo for each level is set (e.g. for <h1> it will be <see cref="Typo.h1"/>, etc.)
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<Typo, Typo>? OverrideHeaderTypo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Override default styling of the markdown component
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public MudMarkdownStyling Styling { get; set; } = new();
|
||||
|
||||
[Parameter]
|
||||
public MarkdownPipeline? MarkdownPipeline { get; set; }
|
||||
|
||||
[Inject]
|
||||
protected NavigationManager? NavigationManager { get; init; }
|
||||
|
||||
[Inject]
|
||||
protected IJSRuntime JsRuntime { get; init; } = default!;
|
||||
|
||||
[Inject]
|
||||
protected IServiceProvider? ServiceProvider { get; init; }
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (NavigationManager != null)
|
||||
NavigationManager.LocationChanged -= NavigationManagerOnLocationChanged;
|
||||
|
||||
if (ThemeService != null)
|
||||
ThemeService.CodeBlockThemeChanged -= OnCodeBlockThemeChanged;
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Value))
|
||||
return;
|
||||
|
||||
ElementIndex = 0;
|
||||
|
||||
var pipeline = GetMarkdownPipeLine();
|
||||
var parsedText = Markdown.Parse(Value, pipeline);
|
||||
if (parsedText.Count == 0)
|
||||
return;
|
||||
|
||||
builder.OpenElement(ElementIndex++, "article");
|
||||
builder.AddAttribute(ElementIndex++, "class", "mud-markdown-body");
|
||||
RenderMarkdown(parsedText, builder);
|
||||
builder.CloseElement();
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
ThemeService = ServiceProvider?.GetService<IMudMarkdownThemeService>();
|
||||
|
||||
if (ThemeService != null)
|
||||
ThemeService.CodeBlockThemeChanged += OnCodeBlockThemeChanged;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (!firstRender || !EnableLinkNavigation || NavigationManager == null)
|
||||
return;
|
||||
|
||||
var args = new LocationChangedEventArgs(NavigationManager.Uri, true);
|
||||
NavigationManagerOnLocationChanged(NavigationManager, args);
|
||||
NavigationManager.LocationChanged += NavigationManagerOnLocationChanged;
|
||||
}
|
||||
|
||||
protected virtual void RenderMarkdown(ContainerBlock container, RenderTreeBuilder builder)
|
||||
{
|
||||
for (var i = 0; i < container.Count; i++)
|
||||
{
|
||||
switch (container[i])
|
||||
{
|
||||
case ParagraphBlock paragraph:
|
||||
{
|
||||
RenderParagraphBlock(paragraph, builder);
|
||||
break;
|
||||
}
|
||||
case HeadingBlock heading:
|
||||
{
|
||||
var typo = (Typo)heading.Level;
|
||||
typo = OverrideHeaderTypo?.Invoke(typo) ?? typo;
|
||||
|
||||
EnableLinkNavigation = true;
|
||||
|
||||
var id = heading.BuildIdString();
|
||||
RenderParagraphBlock(heading, builder, typo, id);
|
||||
|
||||
break;
|
||||
}
|
||||
case QuoteBlock quote:
|
||||
{
|
||||
builder.OpenElement(ElementIndex++, "blockquote");
|
||||
RenderMarkdown(quote, builder);
|
||||
builder.CloseElement();
|
||||
break;
|
||||
}
|
||||
case Table table:
|
||||
{
|
||||
RenderTable(table, builder);
|
||||
break;
|
||||
}
|
||||
case ListBlock list:
|
||||
{
|
||||
RenderList(list, builder);
|
||||
break;
|
||||
}
|
||||
case ThematicBreakBlock:
|
||||
{
|
||||
builder.OpenComponent<MudDivider>(ElementIndex++);
|
||||
builder.CloseComponent();
|
||||
break;
|
||||
}
|
||||
case FencedCodeBlock code:
|
||||
{
|
||||
var text = code.CreateCodeBlockText();
|
||||
|
||||
// Necessary to prevent Blazor from crashing when the code block is empty.
|
||||
// It seems that Blazor does not like empty attributes.
|
||||
if(string.IsNullOrWhiteSpace(text))
|
||||
break;
|
||||
|
||||
builder.OpenComponent<MudCodeHighlight>(ElementIndex++);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudCodeHighlight.Text), text);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudCodeHighlight.Language), code.Info ?? string.Empty);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudCodeHighlight.Theme), CodeBlockTheme);
|
||||
builder.CloseComponent();
|
||||
|
||||
break;
|
||||
}
|
||||
case HtmlBlock html:
|
||||
{
|
||||
if (html.TryGetDetails(out var detailsData))
|
||||
RenderDetailsHtml(builder, detailsData.Header, detailsData.Content);
|
||||
else
|
||||
RenderHtml(builder, html.Lines);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
OnRenderMarkdownBlockDefault(container[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders a markdown block which is not covered by the switch-case block in <see cref="RenderMarkdown"/>
|
||||
/// </summary>
|
||||
protected virtual void OnRenderMarkdownBlockDefault(Markdig.Syntax.Block block)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void RenderParagraphBlock(LeafBlock paragraph, RenderTreeBuilder builder, Typo typo = Typo.body1, string? id = null)
|
||||
{
|
||||
if (paragraph.Inline == null)
|
||||
return;
|
||||
|
||||
builder.OpenComponent<MudText>(ElementIndex++);
|
||||
|
||||
if (!string.IsNullOrEmpty(id))
|
||||
builder.AddAttribute(ElementIndex++, "id", id);
|
||||
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudText.Typo), typo);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudText.ChildContent), (RenderFragment)(contentBuilder => RenderInlines(paragraph.Inline, contentBuilder)));
|
||||
builder.CloseComponent();
|
||||
}
|
||||
|
||||
protected virtual void RenderInlines(ContainerInline inlines, RenderTreeBuilder builder)
|
||||
{
|
||||
foreach (var inline in inlines)
|
||||
{
|
||||
switch (inline)
|
||||
{
|
||||
case LiteralInline x:
|
||||
{
|
||||
builder.AddContent(ElementIndex++, x.Content);
|
||||
break;
|
||||
}
|
||||
case HtmlInline x:
|
||||
{
|
||||
builder.AddMarkupContent(ElementIndex++, x.Tag);
|
||||
break;
|
||||
}
|
||||
case LineBreakInline:
|
||||
{
|
||||
builder.OpenElement(ElementIndex++, "br");
|
||||
builder.CloseElement();
|
||||
break;
|
||||
}
|
||||
case CodeInline x:
|
||||
{
|
||||
builder.OpenElement(ElementIndex++, "code");
|
||||
builder.AddContent(ElementIndex++, x.Content);
|
||||
builder.CloseElement();
|
||||
break;
|
||||
}
|
||||
case EmphasisInline x:
|
||||
{
|
||||
if (!x.TryGetEmphasisElement(out var elementName))
|
||||
continue;
|
||||
|
||||
builder.OpenElement(ElementIndex++, elementName);
|
||||
RenderInlines(x, builder);
|
||||
builder.CloseElement();
|
||||
break;
|
||||
}
|
||||
case LinkInline x:
|
||||
{
|
||||
var url = OverrideLinkUrl?.Invoke(x) ?? x.Url;
|
||||
|
||||
if (x.IsImage)
|
||||
{
|
||||
var alt = x
|
||||
.OfType<LiteralInline>()
|
||||
.Select(static x => x.Content);
|
||||
|
||||
builder.OpenComponent<MudImage>(ElementIndex++);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudImage.Class), "rounded-lg");
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudImage.Src), url);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudImage.Alt), string.Join(null, alt));
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudImage.Elevation), 25);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
else if (LinkCommand == null)
|
||||
{
|
||||
builder.OpenComponent<MudLink>(ElementIndex++);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudLink.Href), url);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudLink.ChildContent), (RenderFragment)(linkBuilder => RenderInlines(x, linkBuilder)));
|
||||
|
||||
if (url.IsExternalUri(NavigationManager?.BaseUri))
|
||||
{
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudLink.Target), "_blank");
|
||||
builder.AddAttribute(ElementIndex++, "rel", "noopener noreferrer");
|
||||
}
|
||||
// (prevent scrolling to the top of the page)
|
||||
// custom implementation only for links on the same page
|
||||
else if (url?.StartsWith('#') ?? false)
|
||||
{
|
||||
builder.AddEventPreventDefaultAttribute(ElementIndex++, "onclick", true);
|
||||
builder.AddAttribute(ElementIndex++, "onclick", EventCallback.Factory.Create<MouseEventArgs>(this, () =>
|
||||
{
|
||||
if (NavigationManager == null)
|
||||
return;
|
||||
|
||||
var uriBuilder = new UriBuilder(NavigationManager.Uri)
|
||||
{
|
||||
Fragment = url,
|
||||
};
|
||||
var args = new LocationChangedEventArgs(uriBuilder.Uri.AbsoluteUri, true);
|
||||
NavigationManagerOnLocationChanged(NavigationManager, args);
|
||||
}));
|
||||
}
|
||||
|
||||
builder.CloseComponent();
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.OpenComponent<MudLinkButton>(ElementIndex++);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudLinkButton.Command), LinkCommand);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudLinkButton.CommandParameter), url);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudLinkButton.ChildContent), (RenderFragment)(linkBuilder => RenderInlines(x, linkBuilder)));
|
||||
builder.CloseComponent();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MathInline x:
|
||||
{
|
||||
builder.OpenComponent<MudMathJax>(ElementIndex++);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudMathJax.Delimiter), x.GetDelimiter());
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudMathJax.Value), x.Content);
|
||||
builder.CloseComponent();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
OnRenderInlinesDefault(inline, builder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders inline block which is not covered by the switch-case block in <see cref="RenderInlines"/>
|
||||
/// </summary>
|
||||
protected virtual void OnRenderInlinesDefault(Inline inline, RenderTreeBuilder builder)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void RenderTable(Table table, RenderTreeBuilder builder)
|
||||
{
|
||||
// First child is columns
|
||||
if (table.Count < 2)
|
||||
return;
|
||||
|
||||
builder.OpenComponent<MudSimpleTable>(ElementIndex++);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudSimpleTable.Style), "overflow-x: auto;");
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudSimpleTable.Striped), Styling.Table.IsStriped);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudSimpleTable.Bordered), Styling.Table.IsBordered);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudSimpleTable.Elevation), Styling.Table.Elevation);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudSimpleTable.ChildContent), (RenderFragment)(contentBuilder =>
|
||||
{
|
||||
// thread
|
||||
contentBuilder.OpenElement(ElementIndex++, "thead");
|
||||
RenderTableRow((TableRow)table[0], "th", contentBuilder, TableCellMinWidth);
|
||||
contentBuilder.CloseElement();
|
||||
|
||||
// tbody
|
||||
contentBuilder.OpenElement(ElementIndex++, "tbody");
|
||||
for (var j = 1; j < table.Count; j++)
|
||||
{
|
||||
RenderTableRow((TableRow)table[j], "td", contentBuilder);
|
||||
}
|
||||
|
||||
contentBuilder.CloseElement();
|
||||
}));
|
||||
builder.CloseComponent();
|
||||
}
|
||||
|
||||
protected virtual void RenderTableRow(TableRow row, string cellElementName, RenderTreeBuilder builder, int? minWidth = null)
|
||||
{
|
||||
builder.OpenElement(ElementIndex++, "tr");
|
||||
|
||||
for (var j = 0; j < row.Count; j++)
|
||||
{
|
||||
var cell = (TableCell)row[j];
|
||||
builder.OpenElement(ElementIndex++, cellElementName);
|
||||
|
||||
if (minWidth is > 0)
|
||||
builder.AddAttribute(ElementIndex++, "style", $"min-width:{minWidth}px");
|
||||
|
||||
if (cell.Count != 0 && cell[0] is ParagraphBlock paragraphBlock)
|
||||
RenderParagraphBlock(paragraphBlock, builder);
|
||||
|
||||
builder.CloseElement();
|
||||
}
|
||||
|
||||
builder.CloseElement();
|
||||
}
|
||||
|
||||
protected virtual void RenderList(ListBlock list, RenderTreeBuilder builder)
|
||||
{
|
||||
if (list.Count == 0)
|
||||
return;
|
||||
|
||||
var elementName = list.IsOrdered ? "ol" : "ul";
|
||||
var orderStart = list.OrderedStart.ParseOrDefault();
|
||||
|
||||
builder.OpenElement(ElementIndex++, elementName);
|
||||
|
||||
if (orderStart > 1)
|
||||
{
|
||||
builder.AddAttribute(ElementIndex++, "start", orderStart);
|
||||
}
|
||||
|
||||
for (var i = 0; i < list.Count; i++)
|
||||
{
|
||||
var block = (ListItemBlock)list[i];
|
||||
|
||||
for (var j = 0; j < block.Count; j++)
|
||||
{
|
||||
switch (block[j])
|
||||
{
|
||||
case ListBlock x:
|
||||
{
|
||||
RenderList(x, builder);
|
||||
break;
|
||||
}
|
||||
case ParagraphBlock x:
|
||||
{
|
||||
builder.OpenElement(ElementIndex++, "li");
|
||||
RenderParagraphBlock(x, builder);
|
||||
builder.CloseElement();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
OnRenderListDefault(block[j], builder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder.CloseElement();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders a markdown block which is not covered by the switch-case block in <see cref="RenderList"/>
|
||||
/// </summary>
|
||||
protected virtual void OnRenderListDefault(Markdig.Syntax.Block block, RenderTreeBuilder builder)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void RenderDetailsHtml(in RenderTreeBuilder builder, in string header, in string content)
|
||||
{
|
||||
var headerHtml = Markdown.Parse(header, Pipeline);
|
||||
var contentHtml = Markdown.Parse(content);
|
||||
|
||||
builder.OpenComponent<MudMarkdownDetails>(ElementIndex++);
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudMarkdownDetails.TitleContent), (RenderFragment)(titleBuilder => RenderMarkdown(headerHtml, titleBuilder)));
|
||||
builder.AddAttribute(ElementIndex++, nameof(MudMarkdownDetails.ChildContent), (RenderFragment)(contentBuilder => RenderMarkdown(contentHtml, contentBuilder)));
|
||||
builder.CloseComponent();
|
||||
}
|
||||
|
||||
protected virtual void RenderHtml(in RenderTreeBuilder builder, in StringLineGroup lines)
|
||||
{
|
||||
var markupString = new MarkupString(lines.ToString());
|
||||
builder.AddContent(ElementIndex, markupString);
|
||||
}
|
||||
|
||||
private async void NavigationManagerOnLocationChanged(object? sender, LocationChangedEventArgs e)
|
||||
{
|
||||
var idFragment = new Uri(e.Location, UriKind.Absolute).Fragment;
|
||||
if (!idFragment.StartsWith('#') || idFragment.Length < 2)
|
||||
return;
|
||||
|
||||
idFragment = idFragment[1..];
|
||||
|
||||
await JsRuntime.InvokeVoidAsync("scrollToElementId", idFragment)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private void OnCodeBlockThemeChanged(object? sender, CodeBlockTheme e) =>
|
||||
CodeBlockTheme = e;
|
||||
|
||||
private MarkdownPipeline GetMarkdownPipeLine()
|
||||
{
|
||||
if (MarkdownPipeline != null)
|
||||
return MarkdownPipeline;
|
||||
|
||||
return Pipeline ??= new MarkdownPipelineBuilder()
|
||||
.UseAdvancedExtensions()
|
||||
.Build();
|
||||
}
|
||||
}
|
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_AMS-Regular.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_AMS-Regular.woff
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Fraktur-Bold.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Fraktur-Bold.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Fraktur-Regular.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Fraktur-Regular.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Main-Bold.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Main-Bold.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Main-Italic.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Main-Italic.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Main-Regular.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Main-Regular.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Math-BoldItalic.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Math-BoldItalic.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Math-Italic.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Math-Italic.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Math-Regular.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Math-Regular.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_SansSerif-Bold.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_SansSerif-Bold.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_SansSerif-Italic.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_SansSerif-Italic.woff
Normal file
Binary file not shown.
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Script-Regular.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Script-Regular.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Size1-Regular.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Size1-Regular.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Size2-Regular.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Size2-Regular.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Size3-Regular.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Size3-Regular.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Size4-Regular.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Size4-Regular.woff
Normal file
Binary file not shown.
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Vector-Bold.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Vector-Bold.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Vector-Regular.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Vector-Regular.woff
Normal file
Binary file not shown.
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Zero.woff
Normal file
BIN
MudBlazor.Markdown/Resources/Fonts/MathJax_Zero.woff
Normal file
Binary file not shown.
1
MudBlazor.Markdown/Resources/MudBlazor.Markdown.MathJax.min.js
vendored
Normal file
1
MudBlazor.Markdown/Resources/MudBlazor.Markdown.MathJax.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
110
MudBlazor.Markdown/Resources/MudBlazor.Markdown.css
Normal file
110
MudBlazor.Markdown/Resources/MudBlazor.Markdown.css
Normal file
@ -0,0 +1,110 @@
|
||||
/* Code */
|
||||
.mud-markdown-body code:not(.hljs) {
|
||||
background: var(--mud-palette-overlay-dark);
|
||||
color: var(--mud-palette-text-primary) !important;
|
||||
padding: 2.5px 7.5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* This component is public, so apply styling in all places, not only within mud-markdown-body */
|
||||
pre code.hljs {
|
||||
display: block !important;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.mud-markdown-body .snippet-clipboard-content {
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.mud-markdown-body .snippet-clipboard-content:hover > .snippet-clipboard-copy-icon {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.mud-markdown-body .snippet-clipboard-content .snippet-clipboard-copy-icon {
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* Quote */
|
||||
.mud-markdown-body blockquote {
|
||||
border-left: .25em solid var(--mud-palette-text-disabled);
|
||||
color: var(--mud-palette-text-secondary);
|
||||
background-color: var(--mud-palette-drawer-background);
|
||||
padding: 0.25em 1em;
|
||||
margin: 0.5em 0 1.25em;
|
||||
}
|
||||
|
||||
.mud-markdown-body blockquote p {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/* Table */
|
||||
.mud-markdown-body table {
|
||||
margin: 1.25em 0;
|
||||
}
|
||||
|
||||
/* Link */
|
||||
.mud-markdown-body .mud-link:hover {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
/* List */
|
||||
.mud-markdown-body ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.mud-markdown-body ul, .mud-markdown-body ol {
|
||||
padding-left: 2em;
|
||||
margin-bottom: 1.25em !important;
|
||||
}
|
||||
|
||||
.mud-markdown-body ul ul {
|
||||
list-style-type: circle;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.mud-markdown-body ul ul ul {
|
||||
list-style-type: square;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.mud-markdown-body li {
|
||||
display: list-item !important;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
/* Headers */
|
||||
.mud-markdown-body h1, .mud-markdown-body h2 {
|
||||
border-bottom: 1px solid var(--mud-palette-text-disabled);
|
||||
padding-bottom: 0.125em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
|
||||
.mud-markdown-body h1, .mud-markdown-body h2, .mud-markdown-body h3, .mud-markdown-body h4, .mud-markdown-body h5, .mud-markdown-body h6 {
|
||||
scroll-margin-top: 5rem;
|
||||
margin-top: 0.25em;
|
||||
word-wrap: break-word;
|
||||
margin-bottom: 0.3em !important;
|
||||
}
|
||||
|
||||
.mud-markdown-body .mud-divider {
|
||||
margin: 0.5em 0;
|
||||
height: 0.25em;
|
||||
}
|
||||
|
||||
/* Paragraphs */
|
||||
.mud-markdown-body p {
|
||||
margin-bottom: 1.25em !important;
|
||||
}
|
||||
|
||||
.mud-markdown-body li p, .mud-markdown-body .mud-expand-panel p {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/* Images */
|
||||
.mud-markdown-body img {
|
||||
max-width: 100%;
|
||||
}
|
87
MudBlazor.Markdown/Resources/MudBlazor.Markdown.js
Normal file
87
MudBlazor.Markdown/Resources/MudBlazor.Markdown.js
Normal file
@ -0,0 +1,87 @@
|
||||
import hljs from "highlight.js";
|
||||
|
||||
const codeStylesDir = "code-styles";
|
||||
const codeStylesSegment = `/MudBlazor.Markdown/${codeStylesDir}/`;
|
||||
|
||||
window.highlightCodeElement = function (element) {
|
||||
hljs.highlightElement(element);
|
||||
}
|
||||
|
||||
window.setHighlightStylesheet = function (stylesheetPath) {
|
||||
let isFound = false;
|
||||
const stylesheets = document.querySelectorAll("link[rel='stylesheet']");
|
||||
|
||||
for (let i = 0; i < stylesheets.length; i++) {
|
||||
const href = stylesheets[i].getAttribute("href");
|
||||
|
||||
if (!href) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const index = href.indexOf(codeStylesSegment);
|
||||
|
||||
if (index !== -1) {
|
||||
if (!isFound) {
|
||||
isFound = true;
|
||||
const newHref = href.substring(0, index + codeStylesSegment.length) + stylesheetPath;
|
||||
stylesheets[i].setAttribute("href", newHref);
|
||||
} else {
|
||||
stylesheets[i].remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFound) {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = `_content/MudBlazor.Markdown/${codeStylesDir}/${stylesheetPath}`;
|
||||
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
}
|
||||
|
||||
window.scrollToElementId = function (elementId) {
|
||||
const element = document.getElementById(elementId);
|
||||
if (element) {
|
||||
const elementIdHref = `#${elementId}`;
|
||||
if (!window.location.pathname.endsWith(elementIdHref)) {
|
||||
history.replaceState(null, "", window.location.pathname + elementIdHref);
|
||||
}
|
||||
|
||||
element.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "start",
|
||||
inline: "nearest"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.appendMathJaxScript = function (scriptId) {
|
||||
if (document.getElementById(scriptId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const script = document.createElement("script");
|
||||
script.id = scriptId;
|
||||
script.type = "text/javascript";
|
||||
script.src = "_content/MudBlazor.Markdown/MudBlazor.Markdown.MathJax.min.js";
|
||||
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
window.refreshMathJaxScript = function () {
|
||||
try {
|
||||
MathJax.typeset();
|
||||
} catch (e) {
|
||||
// swallow since in some cases MathJax might not be initialized
|
||||
}
|
||||
}
|
||||
|
||||
window.copyTextToClipboard = async function (text) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
public interface IMudMarkdownClipboardService
|
||||
{
|
||||
ValueTask CopyToClipboardAsync(string text);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
public interface IMudMarkdownThemeService
|
||||
{
|
||||
event EventHandler<CodeBlockTheme> CodeBlockThemeChanged;
|
||||
|
||||
void SetCodeBlockTheme(CodeBlockTheme theme);
|
||||
}
|
9
MudBlazor.Markdown/Services/MudMarkdownThemeService.cs
Normal file
9
MudBlazor.Markdown/Services/MudMarkdownThemeService.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
internal sealed class MudMarkdownThemeService : IMudMarkdownThemeService
|
||||
{
|
||||
public event EventHandler<CodeBlockTheme>? CodeBlockThemeChanged;
|
||||
|
||||
public void SetCodeBlockTheme(CodeBlockTheme theme) =>
|
||||
CodeBlockThemeChanged?.Invoke(this, theme);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
namespace MudBlazor;
|
||||
|
||||
public static class ServiceCollectionEx
|
||||
{
|
||||
public static IServiceCollection AddMudMarkdownServices(this IServiceCollection @this)
|
||||
{
|
||||
return @this.AddScoped<IMudMarkdownThemeService, MudMarkdownThemeService>();
|
||||
}
|
||||
|
||||
public static IServiceCollection AddMudMarkdownClipboardService<T>(this IServiceCollection @this)
|
||||
where T : class, IMudMarkdownClipboardService
|
||||
{
|
||||
return @this.AddScoped<IMudMarkdownClipboardService, T>();
|
||||
}
|
||||
}
|
12
MudBlazor.Markdown/_Usings.cs
Normal file
12
MudBlazor.Markdown/_Usings.cs
Normal file
@ -0,0 +1,12 @@
|
||||
global using System.Windows.Input;
|
||||
global using Markdig;
|
||||
global using Markdig.Helpers;
|
||||
global using Microsoft.AspNetCore.Components;
|
||||
global using Microsoft.AspNetCore.Components.Rendering;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using Microsoft.JSInterop;
|
||||
global using MudBlazor.Extensions;
|
||||
global using MudBlazor.Utilities;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("MudBlazor.Markdown.Tests")]
|
47
MudBlazor.Markdown/gulpfile.js
Normal file
47
MudBlazor.Markdown/gulpfile.js
Normal file
@ -0,0 +1,47 @@
|
||||
const { src, dest, series } = require("gulp");
|
||||
const webpack = require("webpack-stream");
|
||||
const rename = require("gulp-rename");
|
||||
const minifyCss = require("gulp-clean-css");
|
||||
const changeCase = require("change-case");
|
||||
const all = require("gulp-all");
|
||||
|
||||
function fonts() {
|
||||
return src("Resources/Fonts/*.woff")
|
||||
.pipe(dest("wwwroot/output/chtml/fonts/woff-v2"));
|
||||
}
|
||||
|
||||
function cssMain() {
|
||||
return src("Resources/*.css")
|
||||
.pipe(minifyCss())
|
||||
.pipe(rename({ extname: ".min.css" }))
|
||||
.pipe(dest("wwwroot"));
|
||||
}
|
||||
|
||||
function cssCodeStyles() {
|
||||
return src("Resources/CodeStyles/src/**/*.css")
|
||||
.pipe(minifyCss({ level: { 1: { specialComments: "0" } } }))
|
||||
.pipe(rename(function (path) {
|
||||
path.dirname = changeCase.camelCase(path.dirname);
|
||||
path.extname = ".min.css";
|
||||
}))
|
||||
.pipe(dest("wwwroot/code-styles"));
|
||||
}
|
||||
|
||||
function img() {
|
||||
return src("Resources/CodeStyles/src/**/*.{png,jpg}")
|
||||
.pipe(dest("wwwroot/code-styles"));
|
||||
}
|
||||
|
||||
function jsMain() {
|
||||
const mainJs = src("Resources/MudBlazor.Markdown.js")
|
||||
.pipe(webpack({ mode: "production" }))
|
||||
.pipe(rename({ basename: "MudBlazor.Markdown", extname: ".min.js" }))
|
||||
.pipe(dest("wwwroot"));
|
||||
|
||||
const mathJax = src("Resources/MudBlazor.Markdown.MathJax.min.js")
|
||||
.pipe(dest("wwwroot"));
|
||||
|
||||
return all(mainJs, mathJax);
|
||||
}
|
||||
|
||||
exports.default = series(fonts, cssMain, cssCodeStyles, img, jsMain);
|
9070
MudBlazor.Markdown/package-lock.json
generated
Normal file
9070
MudBlazor.Markdown/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
MudBlazor.Markdown/package.json
Normal file
27
MudBlazor.Markdown/package.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "mudblazor.markdown",
|
||||
"version": "1.0.0",
|
||||
"description": "Markdown component for MudBlazor (https://mudblazor.com/)",
|
||||
"keywords": [
|
||||
"mudblazor",
|
||||
"markdown",
|
||||
"blazor"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "gulp"
|
||||
},
|
||||
"author": "MyNihongo",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"change-case": "^4.1.2",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-all": "^1.1.0",
|
||||
"gulp-clean-css": "^4.3.0",
|
||||
"gulp-rename": "^2.0.0",
|
||||
"webpack": "^5.89.0",
|
||||
"webpack-stream": "^7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"highlight.js": "^11.9.0"
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MindWork AI Studio", "MindWork AI Studio\MindWork AI Studio.csproj", "{059FDFCC-7D0B-474E-9F20-B9C437DF1CDD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MudBlazor.Markdown", "..\MudBlazor.Markdown\MudBlazor.Markdown.csproj", "{9402C391-AFEE-431B-BDD4-107890772036}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -12,5 +14,9 @@ Global
|
||||
{059FDFCC-7D0B-474E-9F20-B9C437DF1CDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{059FDFCC-7D0B-474E-9F20-B9C437DF1CDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{059FDFCC-7D0B-474E-9F20-B9C437DF1CDD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9402C391-AFEE-431B-BDD4-107890772036}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9402C391-AFEE-431B-BDD4-107890772036}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9402C391-AFEE-431B-BDD4-107890772036}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9402C391-AFEE-431B-BDD4-107890772036}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -14,7 +14,9 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MudBlazor" Version="6.19.1" />
|
||||
<PackageReference Include="MudBlazor.Markdown" Version="0.1.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\MudBlazor.Markdown\MudBlazor.Markdown.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
Loading…
Reference in New Issue
Block a user