feat: implement stage 1 of Milkdown WYSIWYG editor integration

This commit is contained in:
2026-06-08 13:47:06 +02:00
parent 9fddafa423
commit 79fc43d592
5 changed files with 411 additions and 0 deletions
@@ -0,0 +1,97 @@
@using Microsoft.JSInterop
@implements IAsyncDisposable
@inject IJSRuntime JS
<div class="markdown-editor-container" style="height: @Height; width: @Width;">
<div id="@EditorId" class="milkdown-editor-wrapper"></div>
<div class="editor-actions">
<button type="button" @onclick="FetchContentAsync" class="nexus-btn">
Fetch Markdown Content
</button>
</div>
</div>
@code {
private readonly string EditorId = $"milkdown-editor-{Guid.NewGuid():N}";
private IJSObjectReference? _module;
private DotNetObjectReference<MarkdownEditor>? _dotNetHelper;
[Parameter]
public string InitialMarkdown { get; set; } = string.Empty;
[Parameter]
public EventCallback<string> OnSave { get; set; }
[Parameter]
public string Height { get; set; } = "500px";
[Parameter]
public string Width { get; set; } = "100%";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
_dotNetHelper = DotNetObjectReference.Create(this);
try
{
// Import the isolated JavaScript module
_module = await JS.InvokeAsync<IJSObjectReference>(
"import",
"./_content/NexusReader.UI.Shared/js/milkdownWrapper.js"
);
// Call the initialization function in the wrapper
await _module.InvokeVoidAsync("initEditor", EditorId, _dotNetHelper, InitialMarkdown);
}
catch (Exception ex)
{
// Log the exception gracefully and do not crash the component
Console.WriteLine($"[MarkdownEditor] Error initializing Milkdown editor: {ex.Message}");
}
}
}
private async Task FetchContentAsync()
{
if (_module is not null)
{
try
{
// Retrieve the updated markdown from JS
var markdown = await _module.InvokeAsync<string>("getMarkdownContent", EditorId);
if (OnSave.HasDelegate)
{
await OnSave.InvokeAsync(markdown);
}
}
catch (Exception ex)
{
Console.WriteLine($"[MarkdownEditor] Error fetching markdown content: {ex.Message}");
}
}
}
public async ValueTask DisposeAsync()
{
try
{
if (_module is not null)
{
// Clean up the JS editor instance to prevent memory leaks
await _module.InvokeVoidAsync("destroyEditor", EditorId);
await _module.DisposeAsync();
}
}
catch (Exception ex)
{
// Fail silently during page navigation/webview closures to avoid noisy logs
Console.WriteLine($"[MarkdownEditor] Error during JS cleanup: {ex.Message}");
}
finally
{
_dotNetHelper?.Dispose();
}
}
}