feat: add markdown editor component with extensible toolbar system
Release NuGet Packages / pack-and-push (release) Successful in 3m28s
Release NuGet Packages / pack-and-push (release) Successful in 3m28s
- Add SbMarkdownEditor component with EasyMDE and CodeMirror integration - Implement IMdToolbarContributor interface for extensible toolbar customization - Add MdToolbarService and MdToolbarOptions for toolbar management - Include vendor libraries (CodeMirror, EasyMDE, Mermaid, Highlight.js) - Add markdown editor interop and JavaScript integration - Refactor SbMarkdownViewer to support both embedded and standalone modes - Add demo page and localization keys for markdown editor - Normalize whitespace and line endings across all component files
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# SbMarkdownViewer
|
||||
|
||||
Renders markdown content as HTML using the Markdig library. Supports advanced markdown extensions including tables, task lists, and code blocks.
|
||||
Renders markdown content as HTML using client-side marked.js (offline). Supports mermaid diagrams, syntax highlighting, and alert callouts.
|
||||
|
||||
## Parameters
|
||||
|
||||
@@ -17,7 +17,7 @@ Renders markdown content as HTML using the Markdig library. Supports advanced ma
|
||||
|
||||
## Markdown Features
|
||||
|
||||
The component uses Markdig with advanced extensions enabled, supporting:
|
||||
The component uses marked.js with GFM support, loaded offline from SufiBlazor vendor assets:
|
||||
|
||||
- **Standard Markdown**: Headings, paragraphs, lists, links, images, emphasis
|
||||
- **Extended Syntax**: Tables, task lists, strikethrough
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
# SbMarkdownEditor
|
||||
|
||||
A markdown editor built on EasyMDE (CodeMirror 5 + marked.js) with live preview, offline mermaid/highlight.js rendering, source mode, AI diff review, and toolbar contributors.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| Value | string | `""` | Markdown content (two-way bindable) |
|
||||
| ValueChanged | EventCallback\<string\> | - | Fired when markdown changes |
|
||||
| ValueHtml | string? | null | Rendered HTML from preview (optional two-way bind) |
|
||||
| ValueHtmlChanged | EventCallback\<string?\> | - | Fired when preview HTML changes |
|
||||
| ReadOnly | bool | false | Read-only editor |
|
||||
| Disabled | bool | false | Disabled state |
|
||||
| Placeholder | string? | null | Placeholder text |
|
||||
| EnablePreview | bool | true | Enable live preview (ignored in source mode) |
|
||||
| EnableMermaid | bool | true | Render ` ```mermaid ` blocks in preview |
|
||||
| EnableHighlight | bool | true | Syntax-highlight fenced code blocks |
|
||||
| HighlightTheme | string | `"github"` | highlight.js theme (`github`, `github-dark`, …) |
|
||||
| EditorMode | SbMarkdownEditorMode | Markdown | `Markdown` or `Source` (raw HTML / templates) |
|
||||
| UseToolbarContributors | bool | false | Include items from `IMdToolbarContributor` services |
|
||||
| HideToolbar | bool | false | Hide the Blazor-rendered toolbar |
|
||||
| ToolbarItems | IReadOnlyList\<SbMarkdownToolbarItem\>? | null | Fixed custom toolbar (overrides defaults) |
|
||||
| MinHeight | string? | `"200px"` | Minimum editor height |
|
||||
| MaxHeight | string? | null | Maximum editor height |
|
||||
| FallbackRows | int | 12 | Textarea rows when JS assets fail to load |
|
||||
| IsDiffReview | bool | false | Merge-style diff review mode |
|
||||
| OriginalValue | string | `""` | Left/original pane in diff mode |
|
||||
| SuggestedValue | string | `""` | Right/modified pane in diff mode |
|
||||
| SuggestedValueChanged | EventCallback\<string\> | - | Fired when user edits suggested side |
|
||||
| OnApplyChanges / OnDiscardChanges | EventCallback | - | Host callbacks for diff actions |
|
||||
| OnShortcut | EventCallback\<string\> | - | Keyboard shortcuts (`save`, `preview`) |
|
||||
| RightToLeft | bool | false | RTL layout |
|
||||
| Class / Style | string? | null | Container styling |
|
||||
|
||||
## Events
|
||||
|
||||
| Event | Description |
|
||||
|-------|-------------|
|
||||
| ValueChanged | Markdown text changed |
|
||||
| ValueHtmlChanged | Preview HTML changed (when preview enabled) |
|
||||
| SuggestedValueChanged | Modified side changed in diff mode |
|
||||
| OnShortcut | `Ctrl/Cmd+S` → `save`, `Ctrl/Cmd+P` → `preview` |
|
||||
|
||||
## CSS Classes
|
||||
|
||||
- `sb-markdown-editor` — Root container
|
||||
- `sb-markdown-editor__toolbar` — Custom toolbar
|
||||
- `sb-markdown-editor__toolbar-btn` — Toolbar button
|
||||
- `sb-markdown-editor__textarea` — EasyMDE host textarea
|
||||
- `sb-markdown-editor__diff-host` — CodeMirror MergeView host
|
||||
- `sb-markdown-editor--diff` — Diff review mode
|
||||
- `sb-markdown-editor--source` — Source / raw mode
|
||||
|
||||
## Preview Features
|
||||
|
||||
Offline assets under `_content/SufiChain.SufiBlazor/vendor/`:
|
||||
|
||||
- **EasyMDE** — Editing, side-by-side preview, fullscreen
|
||||
- **marked.js** — GFM markdown parsing
|
||||
- **highlight.js** — Fenced code block syntax highlighting
|
||||
- **mermaid** — Diagram rendering in preview
|
||||
- **CodeMirror MergeView** — Diff review (red/green merge UI)
|
||||
|
||||
Alert callouts via fenced blocks: `note`, `tip`, `warn`, `alert`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic editor with toolbar
|
||||
|
||||
```razor
|
||||
<SbMarkdownEditor @bind-Value="_content"
|
||||
MinHeight="320px"
|
||||
UseToolbarContributors="true"
|
||||
EnableMermaid="true"
|
||||
EnableHighlight="true" />
|
||||
```
|
||||
|
||||
### Mermaid & syntax highlighting
|
||||
|
||||
Toggle **Preview** or **Side by Side** in the toolbar to render diagrams and code:
|
||||
|
||||
````markdown
|
||||
```csharp
|
||||
public class Example { }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A --> B
|
||||
```
|
||||
````
|
||||
|
||||
### Source mode (HTML email templates)
|
||||
|
||||
```razor
|
||||
<SbMarkdownEditor @bind-Value="_htmlTemplate"
|
||||
EditorMode="SbMarkdownEditorMode.Source"
|
||||
EnablePreview="false"
|
||||
UseToolbarContributors="true" />
|
||||
```
|
||||
|
||||
### Diff review (AI copilot)
|
||||
|
||||
```razor
|
||||
<SbMarkdownEditor IsDiffReview="true"
|
||||
OriginalValue="@_original"
|
||||
SuggestedValue="@_suggested"
|
||||
SuggestedValueChanged="@((v) => _suggested = v)" />
|
||||
|
||||
<SbStack Direction="SbStackDirection.Row" Gap="2">
|
||||
<SbButton OnClick="ApplySuggested">Apply</SbButton>
|
||||
<SbButton Variant="SbButtonVariant.Outlined" OnClick="DiscardSuggested">Discard</SbButton>
|
||||
</SbStack>
|
||||
```
|
||||
|
||||
### Without toolbar
|
||||
|
||||
```razor
|
||||
<SbMarkdownEditor @bind-Value="_note"
|
||||
HideToolbar="true"
|
||||
EnablePreview="false"
|
||||
MinHeight="180px" />
|
||||
```
|
||||
|
||||
## Toolbar Extensibility
|
||||
|
||||
Set `UseToolbarContributors="true"` and register contributors with `AddMdToolbarContributor<T>()`.
|
||||
|
||||
### Implementing a contributor
|
||||
|
||||
```csharp
|
||||
public class MyMdToolbarContributor : IMdToolbarContributor
|
||||
{
|
||||
public int Order => 150;
|
||||
|
||||
public Task ConfigureToolbarAsync(MdToolbarContext context)
|
||||
{
|
||||
context.Items.Add(new MdToolbarContributedItem
|
||||
{
|
||||
Id = "insert-snippet",
|
||||
Group = "insert",
|
||||
Order = 20,
|
||||
Icon = "📝",
|
||||
Tooltip = "Insert snippet",
|
||||
OnClickAsync = async ctx =>
|
||||
{
|
||||
await ctx.InsertTextAsync?.Invoke("**snippet**")!;
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Register in your module:
|
||||
|
||||
```csharp
|
||||
context.Services.AddMdToolbarContributor<MyMdToolbarContributor>();
|
||||
```
|
||||
|
||||
### Action context helpers
|
||||
|
||||
- `InsertTextAsync(text)` — Insert at cursor
|
||||
- `InsertImageMarkdownAsync(url, alt)` — ``
|
||||
- `InsertLinkMarkdownAsync(url, text)` — `[text](url)`
|
||||
- `GetValueAsync()` / `GetSelectionAsync()`
|
||||
|
||||
## File Manager integration
|
||||
|
||||
Use `SufiChain.SufiAbp.FileManager.MarkdownEditor` for gallery image and file attachment toolbar buttons. See **FileManagerMarkdownEditorIntegration** documentation.
|
||||
|
||||
```razor
|
||||
<FileGalleryHost />
|
||||
|
||||
<SbMarkdownEditor @bind-Value="_content"
|
||||
UseToolbarContributors="true" />
|
||||
```
|
||||
|
||||
## Related components
|
||||
|
||||
- **SbMarkdownViewer** — Read-only client-side markdown rendering (same marked/mermaid/highlight stack)
|
||||
- **SbRichTextEditor** — HTML rich text editor (Quill.js)
|
||||
|
||||
## Notes
|
||||
|
||||
- Requires interactive render mode (Blazor Server / WebAssembly).
|
||||
- Vendor bundles are loaded on demand via `sufiblazor-markdown-editor.js`.
|
||||
- KomTheme registers `SufiBlazor.MarkdownEditor` bundle for EasyMDE CSS/JS preloading.
|
||||
Reference in New Issue
Block a user