Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 039973b974 | |||
| c8d9646110 | |||
| 069b29a57f | |||
| 0085366035 | |||
| f1d237e84a | |||
| 56677556cd | |||
| c6ffe1993e | |||
| 30adb3c33f | |||
| 5d67bbf88b | |||
| 6bfd851cdf |
@@ -101,6 +101,11 @@
|
|||||||
<line x1="5" y1="12" x2="19" y2="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
<line x1="5" y1="12" x2="19" y2="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
<polyline points="12 5 19 12 12 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
<polyline points="12 5 19 12 12 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
break;
|
break;
|
||||||
|
case "edit":
|
||||||
|
case "edit-2":
|
||||||
|
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
<path d="M18.5 2.5a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4 9.5-9.5z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
break;
|
||||||
case "log-out":
|
case "log-out":
|
||||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
break;
|
break;
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -5,11 +5,14 @@
|
|||||||
|
|
||||||
<div class="markdown-editor-container" style="height: @Height; width: @Width;">
|
<div class="markdown-editor-container" style="height: @Height; width: @Width;">
|
||||||
<div id="@EditorId" class="milkdown-editor-wrapper"></div>
|
<div id="@EditorId" class="milkdown-editor-wrapper"></div>
|
||||||
|
@if (ShowFetchButton)
|
||||||
|
{
|
||||||
<div class="editor-actions">
|
<div class="editor-actions">
|
||||||
<button type="button" @onclick="FetchContentAsync" class="nexus-btn">
|
<button type="button" @onclick="FetchContentAsync" class="nexus-btn">
|
||||||
Fetch Markdown Content
|
Fetch Markdown Content
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
@@ -17,6 +20,9 @@
|
|||||||
private IJSObjectReference? _module;
|
private IJSObjectReference? _module;
|
||||||
private DotNetObjectReference<MarkdownEditor>? _dotNetHelper;
|
private DotNetObjectReference<MarkdownEditor>? _dotNetHelper;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool ShowFetchButton { get; set; } = true;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string InitialMarkdown { get; set; } = string.Empty;
|
public string InitialMarkdown { get; set; } = string.Empty;
|
||||||
|
|
||||||
@@ -53,7 +59,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task FetchContentAsync()
|
public async Task FetchContentAsync()
|
||||||
{
|
{
|
||||||
if (_module is not null)
|
if (_module is not null)
|
||||||
{
|
{
|
||||||
@@ -116,10 +122,18 @@
|
|||||||
await _module.DisposeAsync();
|
await _module.DisposeAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (JSDisconnectedException)
|
||||||
|
{
|
||||||
|
// Fail silently during circuit disconnection
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
// Fail silently if JS runtime/module is already disposed
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Fail silently during page navigation/webview closures to avoid noisy logs
|
// Log other unexpected errors
|
||||||
Console.WriteLine($"[MarkdownEditor] Error during JS cleanup: {ex.Message}");
|
Console.WriteLine($"[MarkdownEditor] Unexpected error during JS cleanup: {ex.Message}");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -95,11 +95,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<span class="nav-text">Koncentry</span>
|
<span class="nav-text">Koncentry</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink class="nav-item" href="/dev/creator-test" @onclick="CloseMobileMenu" title="Kreator (Dev)" aria-label="Kreator (Dev)">
|
<NavLink class="nav-item" href="/creator" @onclick="CloseMobileMenu" title="Kreator" aria-label="Kreator">
|
||||||
<div class="nav-icon">
|
<div class="nav-icon">
|
||||||
<NexusIcon Name="edit" Size="20" />
|
<NexusIcon Name="edit" Size="20" />
|
||||||
</div>
|
</div>
|
||||||
<span class="nav-text">Kreator (Dev)</span>
|
<span class="nav-text">Kreator</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
@page "/creator"
|
||||||
|
@using Microsoft.AspNetCore.Authorization
|
||||||
|
@attribute [AllowAnonymous]
|
||||||
|
|
||||||
|
<PageTitle>Kreator Treści (Zen Mode)</PageTitle>
|
||||||
|
|
||||||
|
<div class="creator-fullscreen-wrapper">
|
||||||
|
<div class="creator-header">
|
||||||
|
<h1>Kreator Treści</h1>
|
||||||
|
<p class="subtitle">Zen publishing workspace mapping standard Markdown into clean visual blocks.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="milkdown-premium-container creator-workspace-card" spellcheck="false">
|
||||||
|
<div class="editor-growing-area">
|
||||||
|
<MarkdownEditor @ref="_editorRef" InitialMarkdown="@_initialMarkdown" OnSave="HandleSave" ShowFetchButton="false" Height="100%" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="creator-actions-bar">
|
||||||
|
<button type="button" @onclick="TriggerFetchAsync" class="nexus-btn premium-fetch-btn btn-nexus-premium">
|
||||||
|
<span>Fetch Markdown Content</span>
|
||||||
|
<svg class="arrow-icon" viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2.5" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<line x1="5" y1="12" x2="19" y2="12"></line>
|
||||||
|
<polyline points="12 5 19 12 12 19"></polyline>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (!string.IsNullOrEmpty(_savedMarkdown))
|
||||||
|
{
|
||||||
|
<div class="creator-preview-card">
|
||||||
|
<div class="preview-header">
|
||||||
|
<h3>Retrieved Markdown Preview</h3>
|
||||||
|
</div>
|
||||||
|
<div class="pre-wrapper">
|
||||||
|
<pre class="code-preview-block"><code>@_savedMarkdown</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private MarkdownEditor? _editorRef;
|
||||||
|
private string _savedMarkdown = string.Empty;
|
||||||
|
|
||||||
|
private readonly string _initialMarkdown = @"# Zen Mode Editor
|
||||||
|
|
||||||
|
Welcome to your dedicated workspace. This premium panel supports Notion-like WYSIWYG editing.
|
||||||
|
|
||||||
|
## Features:
|
||||||
|
- **Zero Distraction**: Simple elevation and border framing.
|
||||||
|
- **GFM Tables**: Consistent cell padding and hover striping.
|
||||||
|
- **Clean Code Blocks**: Pre-rendered base64 font-loaded code-preview blocks.
|
||||||
|
|
||||||
|
| Option | Active | Value |
|
||||||
|
| :--- | :---: | :--- |
|
||||||
|
| Zen Mode | Yes | High Focus |
|
||||||
|
| Responsive | Yes | 1200px Max |
|
||||||
|
| Theme Sync | Yes | Automatic |
|
||||||
|
|
||||||
|
Start writing your masterpiece...";
|
||||||
|
|
||||||
|
private async Task TriggerFetchAsync()
|
||||||
|
{
|
||||||
|
if (_editorRef is not null)
|
||||||
|
{
|
||||||
|
await _editorRef.FetchContentAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleSave(string markdown)
|
||||||
|
{
|
||||||
|
_savedMarkdown = markdown;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,349 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
Creator.razor.css - Isolated Styles for Zen Mode Creator Workspace
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/* 1. BOUNDARY & SCROLLING RE-ENGINEERING */
|
||||||
|
|
||||||
|
/* Strict flexbox layout context eliminating global browser scrollbars */
|
||||||
|
.creator-fullscreen-wrapper {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important; /* Likwidujemy sztuczne ograniczenia szerokości */
|
||||||
|
margin: 0;
|
||||||
|
padding: 1.5rem; /* Elastyczny, bezpieczny margines od krawędzi bocznych menu i ekranu */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: calc(100vh - 4rem);
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
gap: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.creator-header {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.creator-header h1 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-main);
|
||||||
|
margin: 0 0 0.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.creator-header .subtitle {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Full Viewport Workspace Card stretching smoothly */
|
||||||
|
.creator-workspace-card {
|
||||||
|
background-color: var(--bg-surface) !important;
|
||||||
|
border: 1px solid var(--border) !important;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 2rem;
|
||||||
|
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100% !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-growing-area {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Deep Cascading Overrides to target dynamic editor components */
|
||||||
|
|
||||||
|
::deep .markdown-editor-container {
|
||||||
|
height: 100% !important;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
flex-grow: 1 !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::deep .milkdown-editor-wrapper {
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
flex-grow: 1 !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force crepe and milkdown inner wrappers to stretch */
|
||||||
|
::deep .crepe,
|
||||||
|
::deep .milkdown {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
flex-grow: 1 !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pin the toolbar at the top */
|
||||||
|
::deep .crepe .toolbar,
|
||||||
|
::deep .milkdown-menu,
|
||||||
|
::deep .crepe-menu-wrapper {
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
background-color: var(--bg-base) !important;
|
||||||
|
border: 1px solid var(--border) !important;
|
||||||
|
border-radius: 12px !important;
|
||||||
|
padding: 0.5rem !important;
|
||||||
|
margin-bottom: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::deep .crepe .toolbar button:hover,
|
||||||
|
::deep .milkdown-menu button:hover,
|
||||||
|
::deep .crepe-menu-wrapper button:hover,
|
||||||
|
::deep .crepe .toolbar .button:hover,
|
||||||
|
::deep .milkdown-menu .button:hover {
|
||||||
|
color: var(--accent) !important;
|
||||||
|
background-color: rgba(16, 185, 129, 0.1) !important;
|
||||||
|
border-radius: var(--radius-sm, 4px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Relocate scrolling directly to ProseMirror editor layer and fix text clipping */
|
||||||
|
::deep .ProseMirror,
|
||||||
|
::deep .crepe .editor,
|
||||||
|
::deep .milkdown .editor {
|
||||||
|
position: relative !important;
|
||||||
|
top: 0 !important;
|
||||||
|
transform: none !important;
|
||||||
|
flex-grow: 1 !important;
|
||||||
|
overflow-y: auto !important;
|
||||||
|
padding: 1.5rem !important;
|
||||||
|
padding-right: 15px !important;
|
||||||
|
background-color: var(--bg-surface) !important;
|
||||||
|
color: var(--text-main) !important;
|
||||||
|
font-size: 1.1rem !important;
|
||||||
|
line-height: 1.7 !important;
|
||||||
|
outline: none !important;
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom narrow scrollbar mapped to var(--border) */
|
||||||
|
::deep .ProseMirror::-webkit-scrollbar,
|
||||||
|
::deep .crepe .editor::-webkit-scrollbar,
|
||||||
|
::deep .milkdown .editor::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::deep .ProseMirror::-webkit-scrollbar-track,
|
||||||
|
::deep .crepe .editor::-webkit-scrollbar-track,
|
||||||
|
::deep .milkdown .editor::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
::deep .ProseMirror::-webkit-scrollbar-thumb,
|
||||||
|
::deep .crepe .editor::-webkit-scrollbar-thumb,
|
||||||
|
::deep .milkdown .editor::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--border);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::deep .ProseMirror::-webkit-scrollbar-thumb:hover,
|
||||||
|
::deep .crepe .editor::-webkit-scrollbar-thumb:hover,
|
||||||
|
::deep .milkdown .editor::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Editorial Typography */
|
||||||
|
::deep .milkdown .editor h1,
|
||||||
|
::deep .crepe h1,
|
||||||
|
::deep .ProseMirror h1 {
|
||||||
|
margin-top: 1.8rem !important;
|
||||||
|
margin-bottom: 1rem !important;
|
||||||
|
font-size: 2.25rem !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
color: var(--text-main) !important;
|
||||||
|
line-height: 1.25 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::deep .milkdown .editor h2,
|
||||||
|
::deep .crepe h2,
|
||||||
|
::deep .ProseMirror h2 {
|
||||||
|
margin-top: 1.5rem !important;
|
||||||
|
margin-bottom: 0.8rem !important;
|
||||||
|
font-size: 1.6rem !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
color: var(--text-main) !important;
|
||||||
|
line-height: 1.3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::deep .milkdown .editor h3,
|
||||||
|
::deep .crepe h3,
|
||||||
|
::deep .ProseMirror h3 {
|
||||||
|
margin-top: 1.3rem !important;
|
||||||
|
margin-bottom: 0.7rem !important;
|
||||||
|
font-size: 1.3rem !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
color: var(--text-main) !important;
|
||||||
|
line-height: 1.35 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::deep .milkdown .editor code,
|
||||||
|
::deep .crepe code,
|
||||||
|
::deep .ProseMirror code {
|
||||||
|
background-color: rgba(16, 185, 129, 0.1) !important;
|
||||||
|
color: var(--accent) !important;
|
||||||
|
padding: 0.2rem 0.4rem !important;
|
||||||
|
border-radius: var(--radius-sm, 4px) !important;
|
||||||
|
font-family: 'Azeret Mono', monospace !important;
|
||||||
|
font-size: 0.85em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Premium GFM Table Layouts */
|
||||||
|
::deep .milkdown-premium-container table,
|
||||||
|
::deep .crepe table,
|
||||||
|
::deep .milkdown table,
|
||||||
|
::deep .ProseMirror table {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
border-collapse: collapse !important;
|
||||||
|
margin: 1.5rem 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::deep .milkdown-premium-container th,
|
||||||
|
::deep .crepe th,
|
||||||
|
::deep .milkdown th,
|
||||||
|
::deep .ProseMirror th,
|
||||||
|
::deep .milkdown-premium-container td,
|
||||||
|
::deep .crepe td,
|
||||||
|
::deep .milkdown td,
|
||||||
|
::deep .ProseMirror td {
|
||||||
|
padding: 14px 18px !important;
|
||||||
|
border: 1px solid var(--border) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::deep .milkdown-premium-container th,
|
||||||
|
::deep .crepe th,
|
||||||
|
::deep .milkdown th,
|
||||||
|
::deep .ProseMirror th {
|
||||||
|
background-color: var(--bg-base) !important;
|
||||||
|
color: var(--text-main) !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
text-align: left !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::deep .milkdown-premium-container td,
|
||||||
|
::deep .crepe td,
|
||||||
|
::deep .milkdown td,
|
||||||
|
::deep .ProseMirror td {
|
||||||
|
color: var(--text-main) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zebra row background tints (Dark Mode default) */
|
||||||
|
::deep .milkdown-premium-container tr:nth-child(even),
|
||||||
|
::deep .crepe tr:nth-child(even),
|
||||||
|
::deep .milkdown tr:nth-child(even),
|
||||||
|
::deep .ProseMirror tr:nth-child(even) {
|
||||||
|
background-color: rgba(255, 255, 255, 0.01) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zebra row background tints (Light Mode override) */
|
||||||
|
.theme-light ::deep .milkdown-premium-container tr:nth-child(even),
|
||||||
|
.theme-light ::deep .crepe tr:nth-child(even),
|
||||||
|
.theme-light ::deep .milkdown tr:nth-child(even),
|
||||||
|
.theme-light ::deep .ProseMirror tr:nth-child(even) {
|
||||||
|
background-color: rgba(0, 0, 0, 0.015) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lists and Task Lists */
|
||||||
|
::deep .crepe ul,
|
||||||
|
::deep .crepe ol,
|
||||||
|
::deep .milkdown ul,
|
||||||
|
::deep .milkdown ol,
|
||||||
|
::deep .ProseMirror ul,
|
||||||
|
::deep .ProseMirror ol {
|
||||||
|
line-height: 1.7 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Bottom Actions Panel locked at floor zone of the card structure */
|
||||||
|
.creator-actions-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
padding: 1rem 0 0 0;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-nexus-premium {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
background-color: var(--accent) !important;
|
||||||
|
background: var(--accent) !important;
|
||||||
|
color: #000000 !important;
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: var(--nexus-font-sans);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
min-height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-nexus-premium:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
filter: brightness(1.1);
|
||||||
|
box-shadow: 0 4px 15px var(--accent-glow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-nexus-premium:hover .arrow-icon {
|
||||||
|
transform: translateX(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow-icon {
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5. Dedicated Preview Card */
|
||||||
|
.creator-preview-card {
|
||||||
|
background: #121214;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
padding: 1.25rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
max-height: 180px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-header h3 {
|
||||||
|
margin: 0 0 0.75rem 0;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: var(--nexus-font-sans);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pre-wrapper {
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: auto;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-preview-block {
|
||||||
|
margin: 0;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
font-family: 'Azeret Mono', SFMono-Regular, Consolas, Menlo, monospace;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #e4e4e7;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
@page "/dev/creator-test"
|
|
||||||
@using Microsoft.AspNetCore.Authorization
|
|
||||||
@attribute [AllowAnonymous]
|
|
||||||
@inject HttpClient Http
|
|
||||||
|
|
||||||
<PageTitle>Markdown Creator Test</PageTitle>
|
|
||||||
|
|
||||||
<div class="creator-test-container glass-panel">
|
|
||||||
<div class="test-header">
|
|
||||||
<h1>Milkdown WYSIWYG Integration (Stage 2)</h1>
|
|
||||||
<p class="subtitle">Verifying secure image upload (drag & drop / paste) and backend XSS sanitization.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="editor-section">
|
|
||||||
<MarkdownEditor InitialMarkdown="@_initialMarkdown" OnSave="HandleSave" Height="400px" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="result-section">
|
|
||||||
<div class="result-header">
|
|
||||||
<h3>Retrieved Markdown Content</h3>
|
|
||||||
@if (!string.IsNullOrEmpty(_savedMarkdown))
|
|
||||||
{
|
|
||||||
<button type="button" @onclick="SanitizeContentAsync" class="nexus-btn secondary-btn">
|
|
||||||
Run XSS Guard Sanitization
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<p class="description">This block shows the content received from the editor when you click "Fetch Markdown Content".</p>
|
|
||||||
<div class="pre-wrapper">
|
|
||||||
@if (string.IsNullOrEmpty(_savedMarkdown))
|
|
||||||
{
|
|
||||||
<span class="placeholder">No content fetched yet. Click "Fetch Markdown Content" above to retrieve data.</span>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<pre><code>@_savedMarkdown</code></pre>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (!string.IsNullOrEmpty(_sanitizedMarkdown))
|
|
||||||
{
|
|
||||||
<div class="sanitized-container">
|
|
||||||
<h3>Sanitized Content (XSS Shielded)</h3>
|
|
||||||
<p class="description">This block shows the content after passing through the backend `HtmlSanitizer` API.</p>
|
|
||||||
<div class="pre-wrapper sanitized-wrapper">
|
|
||||||
<pre><code>@_sanitizedMarkdown</code></pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private readonly string _initialMarkdown = @"# Milkdown WYSIWYG Test Page (Stage 2)
|
|
||||||
|
|
||||||
This is a demonstration of the **Milkdown** editor embedded inside a Blazor WASM component.
|
|
||||||
|
|
||||||
## Secure Image Upload (Drag & Drop / Paste)
|
|
||||||
|
|
||||||
You can drag and drop or copy-paste an image (JPEG, PNG, WEBP) directly into this editor area. The file will be intercepted, sent as a byte stream to the backend `/api/media/upload` endpoint, validated for magic numbers and file size limits (max 5MB), saved locally, and rendered inside the editor.
|
|
||||||
|
|
||||||
## XSS Security Test
|
|
||||||
|
|
||||||
Here is some malicious HTML to test the backend XSS Guard:
|
|
||||||
<script>alert('xss')</script>
|
|
||||||
<img src=x onerror=alert(1)>
|
|
||||||
|
|
||||||
## GFM Features Support
|
|
||||||
|
|
||||||
The editor supports Github Flavored Markdown out-of-the-box:
|
|
||||||
|
|
||||||
1. **Task Lists**
|
|
||||||
- [x] Create reusable Blazor component
|
|
||||||
- [x] Configure ESM dynamic wrapper
|
|
||||||
- [x] Implement stage 2 features
|
|
||||||
|
|
||||||
2. **Tables**
|
|
||||||
|
|
||||||
| Feature | Stage 1 Status | Stage 2 Plan |
|
|
||||||
| :--- | :---: | :---: |
|
|
||||||
| WYSIWYG Mode | Active | Polish UI |
|
|
||||||
| C# Interop | Done | Auto-Sync |
|
|
||||||
| GFM Support | Verified | Custom Nodes |
|
|
||||||
|
|
||||||
Feel free to edit this text and click **Fetch Markdown Content** below!";
|
|
||||||
|
|
||||||
private string _savedMarkdown = string.Empty;
|
|
||||||
private string _sanitizedMarkdown = string.Empty;
|
|
||||||
|
|
||||||
private void HandleSave(string markdown)
|
|
||||||
{
|
|
||||||
_savedMarkdown = markdown;
|
|
||||||
_sanitizedMarkdown = string.Empty; // Reset sanitization result
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SanitizeContentAsync()
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(_savedMarkdown)) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var request = new NexusReader.Application.DTOs.Media.ValidateChapterRequest(_savedMarkdown);
|
|
||||||
var response = await Http.PostAsJsonAsync(
|
|
||||||
"/api/chapters/validate",
|
|
||||||
request,
|
|
||||||
NexusReader.Application.Common.AppJsonContext.Default.ValidateChapterRequest
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
var result = await response.Content.ReadFromJsonAsync<NexusReader.Application.DTOs.Media.ValidateChapterResponse>(
|
|
||||||
NexusReader.Application.Common.AppJsonContext.Default.ValidateChapterResponse
|
|
||||||
);
|
|
||||||
_sanitizedMarkdown = result?.SanitizedContent ?? string.Empty;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_sanitizedMarkdown = $"Error: {response.StatusCode}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_sanitizedMarkdown = $"Exception: {ex.Message}";
|
|
||||||
}
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
.creator-test-container {
|
|
||||||
max-width: 1000px;
|
|
||||||
margin: 2rem auto;
|
|
||||||
padding: 2rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.test-header h1 {
|
|
||||||
font-size: 1.75rem;
|
|
||||||
color: var(--text-main);
|
|
||||||
margin: 0 0 0.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.test-header .subtitle {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
color: var(--text-muted);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-section {
|
|
||||||
background: var(--bg-surface);
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
padding: 1.5rem;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.5rem;
|
|
||||||
background: rgba(255, 255, 255, 0.02);
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
padding: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
gap: 1rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-section h3 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
color: var(--text-main);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sanitized-container {
|
|
||||||
margin-top: 1.5rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.5rem;
|
|
||||||
border-top: 1px dashed var(--border);
|
|
||||||
padding-top: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sanitized-wrapper {
|
|
||||||
border-color: rgba(0, 255, 153, 0.25);
|
|
||||||
box-shadow: 0 0 10px rgba(0, 255, 153, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nexus-btn.secondary-btn {
|
|
||||||
background: rgba(255, 255, 255, 0.05);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nexus-btn.secondary-btn:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
box-shadow: 0 4px 15px rgba(255, 255, 255, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-section .description {
|
|
||||||
font-size: 0.85rem;
|
|
||||||
color: var(--text-muted);
|
|
||||||
margin: 0 0 0.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pre-wrapper {
|
|
||||||
background: #09090b;
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: var(--radius-md);
|
|
||||||
padding: 1.2rem;
|
|
||||||
max-height: 400px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pre-wrapper pre {
|
|
||||||
margin: 0;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-break: break-all;
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
color: #e4e4e7;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder {
|
|
||||||
color: var(--text-muted);
|
|
||||||
font-size: 0.9rem;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Merriweather:ital,wght@0,300;0,400;0,700;1,400&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Merriweather:ital,wght@0,300;0,400;0,700;1,400&family=Azeret+Mono:wght@300;400;500;600&display=swap');
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
/* Semantic design tokens - default to Modern Deep Dark (Dark Mode) */
|
/* Semantic design tokens - default to Modern Deep Dark (Dark Mode) */
|
||||||
@@ -60,9 +60,12 @@
|
|||||||
--nexus-node-concept-text: #e0e0e0;
|
--nexus-node-concept-text: #e0e0e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
::selection {
|
::selection,
|
||||||
background-color: var(--nexus-selection);
|
.ProseMirror ::selection,
|
||||||
color: inherit;
|
.ProseMirror::selection,
|
||||||
|
.ProseMirror *::selection {
|
||||||
|
background-color: var(--nexus-selection) !important;
|
||||||
|
color: inherit !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -445,3 +448,546 @@ h1:focus {
|
|||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
Selection Pop-up Menu & Crepe Toolbar Unification (SelectionAiPanel Style)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/* 1. Pop-up Containers (Glassmorphism Capsule) */
|
||||||
|
.milkdown-popover,
|
||||||
|
.popover,
|
||||||
|
.prosemirror-bubble-menu,
|
||||||
|
.milkdown .popover,
|
||||||
|
.milkdown-popover.popover,
|
||||||
|
.milkdown-toolbar {
|
||||||
|
background: rgba(24, 24, 28, 0.85) !important;
|
||||||
|
backdrop-filter: blur(12px) !important;
|
||||||
|
-webkit-backdrop-filter: blur(12px) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
padding: 4px 6px !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5), 0 12px 28px rgba(0, 0, 0, 0.4) !important;
|
||||||
|
display: inline-flex; /* Removed !important to allow Tippy.js to hide popovers via inline style */
|
||||||
|
align-items: center !important;
|
||||||
|
gap: 4px !important;
|
||||||
|
z-index: 10000 !important;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
animation: fadeInScaleGlobal 0.18s cubic-bezier(0.16, 1, 0.3, 1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Light Theme (Warm Paper) Overrides for Container */
|
||||||
|
.theme-light .milkdown-popover,
|
||||||
|
.theme-light .popover,
|
||||||
|
.theme-light .prosemirror-bubble-menu,
|
||||||
|
.theme-light .milkdown .popover,
|
||||||
|
.theme-light .milkdown-popover.popover,
|
||||||
|
.theme-light .milkdown-toolbar {
|
||||||
|
background: rgba(254, 254, 254, 0.95) !important;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.08) !important;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.04) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Button & Item Formatting (Reader Selection Toolbar Style) */
|
||||||
|
.milkdown-popover button,
|
||||||
|
.popover button,
|
||||||
|
.prosemirror-bubble-menu button,
|
||||||
|
.milkdown .popover button,
|
||||||
|
.milkdown-toolbar button {
|
||||||
|
text-transform: none !important;
|
||||||
|
font-size: 0.8rem !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
color: #e4e4e7 !important; /* zinc-200 */
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
padding: 6px 12px !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
cursor: pointer !important;
|
||||||
|
gap: 6px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Crepe's Specific Square Icon-Only Toolbar Items */
|
||||||
|
.milkdown-toolbar .toolbar-item {
|
||||||
|
text-transform: none !important;
|
||||||
|
color: #e4e4e7 !important; /* zinc-200 */
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||||
|
cursor: pointer !important;
|
||||||
|
width: 28px !important;
|
||||||
|
height: 28px !important;
|
||||||
|
padding: 6px !important;
|
||||||
|
display: inline-flex !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
align-items: center !important;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icon overrides inside buttons */
|
||||||
|
.milkdown-popover button svg,
|
||||||
|
.popover button svg,
|
||||||
|
.prosemirror-bubble-menu button svg,
|
||||||
|
.milkdown .popover button svg,
|
||||||
|
.milkdown-popover button i,
|
||||||
|
.popover button i,
|
||||||
|
.prosemirror-bubble-menu button i,
|
||||||
|
.milkdown .popover button i,
|
||||||
|
.milkdown-toolbar button svg,
|
||||||
|
.milkdown-toolbar .toolbar-item svg,
|
||||||
|
.milkdown-toolbar button i,
|
||||||
|
.milkdown-toolbar .toolbar-item i {
|
||||||
|
color: currentColor !important;
|
||||||
|
fill: currentColor !important;
|
||||||
|
width: 14px !important;
|
||||||
|
height: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover effects (zinc-200 / zinc-100 highlight) */
|
||||||
|
.milkdown-popover button:hover:not(.active),
|
||||||
|
.popover button:hover:not(.active),
|
||||||
|
.prosemirror-bubble-menu button:hover:not(.active),
|
||||||
|
.milkdown-toolbar button:hover:not(.active),
|
||||||
|
.milkdown-toolbar .toolbar-item:hover:not(.active) {
|
||||||
|
background: rgba(255, 255, 255, 0.05) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Active formatting state colors (var(--accent, #00ff99)) */
|
||||||
|
.milkdown-popover button.active,
|
||||||
|
.popover button.active,
|
||||||
|
.prosemirror-bubble-menu button.active,
|
||||||
|
.milkdown-popover button[aria-pressed="true"],
|
||||||
|
.popover button[aria-pressed="true"],
|
||||||
|
.prosemirror-bubble-menu button[aria-pressed="true"],
|
||||||
|
.milkdown-toolbar button.active,
|
||||||
|
.milkdown-toolbar .toolbar-item.active,
|
||||||
|
.milkdown-toolbar button[aria-pressed="true"],
|
||||||
|
.milkdown-toolbar .toolbar-item[aria-pressed="true"] {
|
||||||
|
color: var(--accent, #00ff99) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown-popover button.active:hover,
|
||||||
|
.popover button.active:hover,
|
||||||
|
.prosemirror-bubble-menu button.active:hover,
|
||||||
|
.milkdown-popover button[aria-pressed="true"]:hover,
|
||||||
|
.popover button[aria-pressed="true"]:hover,
|
||||||
|
.prosemirror-bubble-menu button[aria-pressed="true"]:hover,
|
||||||
|
.milkdown-toolbar button.active:hover,
|
||||||
|
.milkdown-toolbar .toolbar-item.active:hover,
|
||||||
|
.milkdown-toolbar button[aria-pressed="true"]:hover,
|
||||||
|
.milkdown-toolbar .toolbar-item[aria-pressed="true"]:hover {
|
||||||
|
background: rgba(0, 255, 153, 0.08) !important;
|
||||||
|
box-shadow: 0 0 12px rgba(0, 255, 153, 0.15) !important;
|
||||||
|
color: var(--accent, #00ff99) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Light Theme Overrides for Buttons */
|
||||||
|
.theme-light .milkdown-popover button,
|
||||||
|
.theme-light .popover button,
|
||||||
|
.theme-light .prosemirror-bubble-menu button,
|
||||||
|
.theme-light .milkdown-toolbar button,
|
||||||
|
.theme-light .milkdown-toolbar .toolbar-item {
|
||||||
|
color: #57524e !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown-popover button:hover:not(.active),
|
||||||
|
.theme-light .popover button:hover:not(.active),
|
||||||
|
.theme-light .prosemirror-bubble-menu button:hover:not(.active),
|
||||||
|
.theme-light .milkdown-toolbar button:hover:not(.active),
|
||||||
|
.theme-light .milkdown-toolbar .toolbar-item:hover:not(.active) {
|
||||||
|
background: rgba(0, 0, 0, 0.04) !important;
|
||||||
|
color: #1c1917 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown-popover button.active,
|
||||||
|
.theme-light .popover button.active,
|
||||||
|
.theme-light .prosemirror-bubble-menu button.active,
|
||||||
|
.theme-light .milkdown-popover button[aria-pressed="true"],
|
||||||
|
.theme-light .popover button[aria-pressed="true"],
|
||||||
|
.theme-light .prosemirror-bubble-menu button[aria-pressed="true"],
|
||||||
|
.theme-light .milkdown-toolbar button.active,
|
||||||
|
.theme-light .milkdown-toolbar .toolbar-item.active,
|
||||||
|
.theme-light .milkdown-toolbar button[aria-pressed="true"],
|
||||||
|
.theme-light .milkdown-toolbar .toolbar-item[aria-pressed="true"] {
|
||||||
|
color: #10b981 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown-popover button.active:hover,
|
||||||
|
.theme-light .popover button.active:hover,
|
||||||
|
.theme-light .prosemirror-bubble-menu button.active:hover,
|
||||||
|
.theme-light .milkdown-popover button[aria-pressed="true"]:hover,
|
||||||
|
.theme-light .popover button[aria-pressed="true"]:hover,
|
||||||
|
.theme-light .prosemirror-bubble-menu button[aria-pressed="true"]:hover,
|
||||||
|
.theme-light .milkdown-toolbar button.active:hover,
|
||||||
|
.theme-light .milkdown-toolbar .toolbar-item.active:hover,
|
||||||
|
.theme-light .milkdown-toolbar button[aria-pressed="true"]:hover,
|
||||||
|
.theme-light .milkdown-toolbar .toolbar-item[aria-pressed="true"]:hover {
|
||||||
|
background: rgba(16, 185, 129, 0.06) !important;
|
||||||
|
box-shadow: 0 0 12px rgba(16, 185, 129, 0.1) !important;
|
||||||
|
color: #10b981 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Dividers Alignment */
|
||||||
|
.milkdown-popover .divider,
|
||||||
|
.popover .divider,
|
||||||
|
.prosemirror-bubble-menu .divider,
|
||||||
|
.milkdown .popover .divider,
|
||||||
|
.milkdown-toolbar .divider {
|
||||||
|
width: 1px !important;
|
||||||
|
height: 16px !important;
|
||||||
|
background-color: rgba(255, 255, 255, 0.1) !important;
|
||||||
|
margin: 0 4px !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown-popover .divider,
|
||||||
|
.theme-light .popover .divider,
|
||||||
|
.theme-light .prosemirror-bubble-menu .divider,
|
||||||
|
.theme-light .milkdown-toolbar .divider {
|
||||||
|
background-color: rgba(0, 0, 0, 0.08) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
Editor Table & General Control Elements Theming (SelectionAiPanel Style)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/* 1. Cell Drag Handles (Column and Row Drag Handles) */
|
||||||
|
.milkdown .milkdown-table-block .cell-handle {
|
||||||
|
background-color: rgba(24, 24, 28, 0.85) !important;
|
||||||
|
backdrop-filter: blur(12px) !important;
|
||||||
|
-webkit-backdrop-filter: blur(12px) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important;
|
||||||
|
color: #e4e4e7 !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-table-block .cell-handle {
|
||||||
|
background-color: rgba(254, 254, 254, 0.95) !important;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.08) !important;
|
||||||
|
color: #57524e !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-table-block .cell-handle:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.15) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
border-color: var(--accent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-table-block .cell-handle:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.08) !important;
|
||||||
|
color: #1c1917 !important;
|
||||||
|
border-color: #10b981 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-table-block .cell-handle svg {
|
||||||
|
fill: currentColor !important;
|
||||||
|
color: currentColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Drag Handle Options Popup Menu (.button-group) */
|
||||||
|
.milkdown .milkdown-table-block .cell-handle .button-group {
|
||||||
|
background: rgba(24, 24, 28, 0.85) !important;
|
||||||
|
backdrop-filter: blur(12px) !important;
|
||||||
|
-webkit-backdrop-filter: blur(12px) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5), 0 12px 28px rgba(0, 0, 0, 0.4) !important;
|
||||||
|
padding: 4px !important;
|
||||||
|
gap: 4px !important;
|
||||||
|
display: flex; /* Removed !important to allow toggling via data-show attribute */
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-table-block .cell-handle .button-group {
|
||||||
|
background: rgba(254, 254, 254, 0.95) !important;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.08) !important;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.04) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-table-block .cell-handle .button-group button {
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||||
|
cursor: pointer !important;
|
||||||
|
width: 28px !important;
|
||||||
|
height: 28px !important;
|
||||||
|
padding: 6px !important;
|
||||||
|
display: inline-flex !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
align-items: center !important;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
color: #e4e4e7 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-table-block .cell-handle .button-group button {
|
||||||
|
color: #57524e !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-table-block .cell-handle .button-group button:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.05) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-table-block .cell-handle .button-group button:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.04) !important;
|
||||||
|
color: #1c1917 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-table-block .cell-handle .button-group button:active {
|
||||||
|
background: rgba(0, 255, 153, 0.08) !important;
|
||||||
|
color: var(--accent, #00ff99) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-table-block .cell-handle .button-group button:active {
|
||||||
|
background: rgba(16, 185, 129, 0.06) !important;
|
||||||
|
color: #10b981 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-table-block .cell-handle .button-group button svg {
|
||||||
|
color: currentColor !important;
|
||||||
|
fill: currentColor !important;
|
||||||
|
width: 14px !important;
|
||||||
|
height: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Table Column/Row Insertion Lines & Add Buttons */
|
||||||
|
.milkdown .milkdown-table-block .line-handle {
|
||||||
|
background-color: var(--accent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-table-block .line-handle {
|
||||||
|
background-color: #10b981 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-table-block .line-handle .add-button {
|
||||||
|
background-color: rgba(24, 24, 28, 0.85) !important;
|
||||||
|
backdrop-filter: blur(12px) !important;
|
||||||
|
-webkit-backdrop-filter: blur(12px) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||||||
|
color: #e4e4e7 !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-table-block .line-handle .add-button {
|
||||||
|
background-color: rgba(254, 254, 254, 0.95) !important;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.08) !important;
|
||||||
|
color: #57524e !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-table-block .line-handle .add-button:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.15) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
border-color: var(--accent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-table-block .line-handle .add-button:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.08) !important;
|
||||||
|
color: #1c1917 !important;
|
||||||
|
border-color: #10b981 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-table-block .line-handle .add-button svg {
|
||||||
|
width: 12px !important;
|
||||||
|
height: 12px !important;
|
||||||
|
color: currentColor !important;
|
||||||
|
fill: currentColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Paragraph Block Drag Handles */
|
||||||
|
.milkdown .milkdown-block-handle {
|
||||||
|
background-color: rgba(24, 24, 28, 0.85) !important;
|
||||||
|
backdrop-filter: blur(12px) !important;
|
||||||
|
-webkit-backdrop-filter: blur(12px) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
padding: 2px !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important;
|
||||||
|
display: flex; /* Removed !important to allow toggling */
|
||||||
|
gap: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-block-handle {
|
||||||
|
background-color: rgba(254, 254, 254, 0.95) !important;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.08) !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-block-handle .operation-item {
|
||||||
|
border-radius: 4px !important;
|
||||||
|
width: 24px !important;
|
||||||
|
height: 24px !important;
|
||||||
|
padding: 4px !important;
|
||||||
|
display: inline-flex !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
align-items: center !important;
|
||||||
|
color: #e4e4e7 !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-block-handle .operation-item {
|
||||||
|
color: #57524e !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-block-handle .operation-item:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.05) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-block-handle .operation-item:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.04) !important;
|
||||||
|
color: #1c1917 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-block-handle .operation-item.active {
|
||||||
|
background: rgba(0, 255, 153, 0.08) !important;
|
||||||
|
color: var(--accent, #00ff99) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-block-handle .operation-item.active {
|
||||||
|
background: rgba(16, 185, 129, 0.06) !important;
|
||||||
|
color: #10b981 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-block-handle .operation-item svg {
|
||||||
|
width: 14px !important;
|
||||||
|
height: 14px !important;
|
||||||
|
fill: currentColor !important;
|
||||||
|
color: currentColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5. Slash Commands Menu */
|
||||||
|
.milkdown .milkdown-slash-menu {
|
||||||
|
background: rgba(24, 24, 28, 0.85) !important;
|
||||||
|
backdrop-filter: blur(12px) !important;
|
||||||
|
-webkit-backdrop-filter: blur(12px) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5), 0 12px 28px rgba(0, 0, 0, 0.4) !important;
|
||||||
|
font-family: var(--nexus-font-sans) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-slash-menu {
|
||||||
|
background: rgba(254, 254, 254, 0.95) !important;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.08) !important;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.04) !important;
|
||||||
|
color: #2d2a26 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-slash-menu .tab-group ul li {
|
||||||
|
color: #a1a1aa !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-slash-menu .tab-group ul li {
|
||||||
|
color: #78716c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-slash-menu .tab-group ul li:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.05) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-slash-menu .tab-group ul li:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.04) !important;
|
||||||
|
color: #1c1917 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-slash-menu .tab-group ul li.selected {
|
||||||
|
background: rgba(0, 255, 153, 0.08) !important;
|
||||||
|
color: var(--accent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-slash-menu .tab-group ul li.selected {
|
||||||
|
background: rgba(16, 185, 129, 0.06) !important;
|
||||||
|
color: #10b981 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-slash-menu .menu-groups .menu-group li {
|
||||||
|
color: #e4e4e7 !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-slash-menu .menu-groups .menu-group li {
|
||||||
|
color: #57524e !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-slash-menu .menu-groups .menu-group li svg {
|
||||||
|
color: #a1a1aa !important;
|
||||||
|
fill: #a1a1aa !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-slash-menu .menu-groups .menu-group li svg {
|
||||||
|
color: #78716c !important;
|
||||||
|
fill: #78716c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-slash-menu .menu-groups .menu-group li.hover {
|
||||||
|
background: rgba(255, 255, 255, 0.05) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-slash-menu .menu-groups .menu-group li.hover {
|
||||||
|
background: rgba(0, 0, 0, 0.04) !important;
|
||||||
|
color: #1c1917 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-slash-menu .menu-groups .menu-group li.active {
|
||||||
|
background: rgba(0, 255, 153, 0.08) !important;
|
||||||
|
color: var(--accent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-slash-menu .menu-groups .menu-group li.active {
|
||||||
|
background: rgba(16, 185, 129, 0.06) !important;
|
||||||
|
color: #10b981 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milkdown .milkdown-slash-menu .menu-groups .menu-group li.active svg {
|
||||||
|
color: var(--accent) !important;
|
||||||
|
fill: var(--accent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light .milkdown .milkdown-slash-menu .menu-groups .menu-group li.active svg {
|
||||||
|
color: #10b981 !important;
|
||||||
|
fill: #10b981 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 6. Explicit Visibility State Overrides */
|
||||||
|
.milkdown-popover[data-show="false"],
|
||||||
|
.popover[data-show="false"],
|
||||||
|
.prosemirror-bubble-menu[data-show="false"],
|
||||||
|
.milkdown-toolbar[data-show="false"],
|
||||||
|
.milkdown-slash-menu[data-show="false"],
|
||||||
|
.milkdown-table-block .cell-handle .button-group[data-show="false"],
|
||||||
|
.milkdown-link-preview[data-show="false"],
|
||||||
|
.milkdown-link-edit[data-show="false"] {
|
||||||
|
display: none !important;
|
||||||
|
opacity: 0 !important;
|
||||||
|
visibility: hidden !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 7. Table Overflow Clipping Fix for Handles */
|
||||||
|
.milkdown .tableWrapper {
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,20 +1,20 @@
|
|||||||
// Map to keep track of active Crepe editor instances by elementId (container ID)
|
// Map to keep track of active Crepe editor instances by elementId (container ID)
|
||||||
const editors = new Map();
|
const editorCache = new Map();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously injects a stylesheet link tag into the document head
|
* Asynchronously injects a stylesheet link tag into the document head
|
||||||
* and returns a Promise that resolves when the stylesheet is fully loaded.
|
* and returns a Promise that resolves when the stylesheet is fully loaded.
|
||||||
*/
|
*/
|
||||||
async function injectStylesheet(url) {
|
async function ensureStylesheet(href) {
|
||||||
if (document.querySelector(`link[href="${url}"]`)) {
|
if (document.querySelector(`link[href="${href}"]`)) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const link = document.createElement('link');
|
const link = document.createElement('link');
|
||||||
link.rel = 'stylesheet';
|
link.rel = 'stylesheet';
|
||||||
link.href = url;
|
link.href = href;
|
||||||
link.onload = () => resolve();
|
link.onload = () => resolve();
|
||||||
link.onerror = (err) => reject(new Error(`Failed to load stylesheet: ${url}. ${err}`));
|
link.onerror = (err) => reject(new Error(`Failed to load stylesheet: ${href}. ${err}`));
|
||||||
document.head.appendChild(link);
|
document.head.appendChild(link);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -31,13 +31,16 @@ export async function initEditor(elementId, dotNetHelper, initialMarkdown) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Condition 2: Prevent FOUC by loading stylesheets before instantiating the editor
|
// Condition 2: Prevent FOUC by loading stylesheets before instantiating the editor
|
||||||
await Promise.all([
|
await ensureStylesheet('/_content/NexusReader.UI.Shared/css/vendor/milkdown-crepe.css');
|
||||||
injectStylesheet('https://esm.sh/@milkdown/crepe/theme/common/style.css'),
|
|
||||||
injectStylesheet('https://esm.sh/@milkdown/crepe/theme/frame.css')
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Dynamically import the Crepe ESM module
|
// Dynamically import the local JS bundle
|
||||||
const { Crepe } = await import('https://esm.sh/@milkdown/crepe');
|
await import('/_content/NexusReader.UI.Shared/js/vendor/milkdown-crepe.js');
|
||||||
|
|
||||||
|
// Get Crepe constructor from the global window.milkdownCrepe namespace
|
||||||
|
const Crepe = window.milkdownCrepe?.Crepe;
|
||||||
|
if (!Crepe) {
|
||||||
|
throw new Error("Crepe constructor not found on window.milkdownCrepe");
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the Crepe editor instance with custom ImageBlock upload handler
|
// Initialize the Crepe editor instance with custom ImageBlock upload handler
|
||||||
const crepe = new Crepe({
|
const crepe = new Crepe({
|
||||||
@@ -61,7 +64,7 @@ export async function initEditor(elementId, dotNetHelper, initialMarkdown) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Store the editor instance in the map
|
// Store the editor instance in the map
|
||||||
editors.set(elementId, crepe);
|
editorCache.set(elementId, crepe);
|
||||||
|
|
||||||
// Create the editor view asynchronously
|
// Create the editor view asynchronously
|
||||||
await crepe.create();
|
await crepe.create();
|
||||||
@@ -76,7 +79,7 @@ export async function initEditor(elementId, dotNetHelper, initialMarkdown) {
|
|||||||
* Retrieves the current Markdown content from a specific editor instance.
|
* Retrieves the current Markdown content from a specific editor instance.
|
||||||
*/
|
*/
|
||||||
export function getMarkdownContent(elementId) {
|
export function getMarkdownContent(elementId) {
|
||||||
const crepe = editors.get(elementId);
|
const crepe = editorCache.get(elementId);
|
||||||
if (!crepe) {
|
if (!crepe) {
|
||||||
console.warn(`[Milkdown] No editor instance found for element: ${elementId}`);
|
console.warn(`[Milkdown] No editor instance found for element: ${elementId}`);
|
||||||
return "";
|
return "";
|
||||||
@@ -88,7 +91,7 @@ export function getMarkdownContent(elementId) {
|
|||||||
* Safely disposes of the editor instance to prevent memory leaks in WASM.
|
* Safely disposes of the editor instance to prevent memory leaks in WASM.
|
||||||
*/
|
*/
|
||||||
export async function destroyEditor(elementId) {
|
export async function destroyEditor(elementId) {
|
||||||
const crepe = editors.get(elementId);
|
const crepe = editorCache.get(elementId);
|
||||||
if (crepe) {
|
if (crepe) {
|
||||||
try {
|
try {
|
||||||
await crepe.destroy();
|
await crepe.destroy();
|
||||||
@@ -96,6 +99,6 @@ export async function destroyEditor(elementId) {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[Milkdown] Error destroying editor for element "${elementId}":`, error);
|
console.error(`[Milkdown] Error destroying editor for element "${elementId}":`, error);
|
||||||
}
|
}
|
||||||
editors.delete(elementId);
|
editorCache.delete(elementId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user