feat(sufi-blazor): introduce sb mark editor unified editing surface
This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
@namespace SufiChain.SufiBlazor.Components.Forms
|
||||||
|
@using SufiChain.SufiBlazor.Contracts.Editors
|
||||||
|
|
||||||
|
<SbMarkdownEditor Value="@Value"
|
||||||
|
ValueChanged="@ValueChanged"
|
||||||
|
ValueHtml="@ValueHtml"
|
||||||
|
ValueHtmlChanged="@ValueHtmlChanged"
|
||||||
|
ReadOnly="@ReadOnly"
|
||||||
|
Disabled="@Disabled"
|
||||||
|
Placeholder="@Placeholder"
|
||||||
|
Class="@Class"
|
||||||
|
Style="@Style"
|
||||||
|
RightToLeft="@RightToLeft"
|
||||||
|
EnablePreview="@EnablePreview"
|
||||||
|
EnableMermaid="@EnableMermaid"
|
||||||
|
EnableHighlight="@EnableHighlight"
|
||||||
|
HighlightTheme="@HighlightTheme"
|
||||||
|
EditorMode="@ResolveEditorMode()"
|
||||||
|
SourceLanguage="@ResolveSourceLanguage()"
|
||||||
|
UseToolbarContributors="@UseToolbarContributors"
|
||||||
|
IncludeDefaultToolbarItems="@IncludeDefaultToolbarItems"
|
||||||
|
HideToolbar="@HideToolbar"
|
||||||
|
ToolbarItems="@ToolbarItems"
|
||||||
|
OnShortcut="@OnShortcut"
|
||||||
|
MinHeight="@MinHeight"
|
||||||
|
MaxHeight="@MaxHeight"
|
||||||
|
FallbackRows="@FallbackRows"
|
||||||
|
IsDiffReview="@IsDiffReview"
|
||||||
|
OriginalValue="@OriginalValue"
|
||||||
|
SuggestedValue="@SuggestedValue"
|
||||||
|
SuggestedValueChanged="@SuggestedValueChanged"
|
||||||
|
OnApplyChanges="@OnApplyChanges"
|
||||||
|
OnDiscardChanges="@OnDiscardChanges"
|
||||||
|
AdditionalAttributes="@AdditionalAttributes" />
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using SufiChain.SufiBlazor.Contracts.Editors;
|
||||||
|
|
||||||
|
namespace SufiChain.SufiBlazor.Components.Forms;
|
||||||
|
|
||||||
|
public partial class SbMarkEditor
|
||||||
|
{
|
||||||
|
[Parameter] public string Value { get; set; } = string.Empty;
|
||||||
|
[Parameter] public EventCallback<string> ValueChanged { get; set; }
|
||||||
|
[Parameter] public string? ValueHtml { get; set; }
|
||||||
|
[Parameter] public EventCallback<string?> ValueHtmlChanged { get; set; }
|
||||||
|
[Parameter] public bool ReadOnly { get; set; }
|
||||||
|
[Parameter] public bool Disabled { get; set; }
|
||||||
|
[Parameter] public string? Placeholder { get; set; }
|
||||||
|
[Parameter] public string? Class { get; set; }
|
||||||
|
[Parameter] public string? Style { get; set; }
|
||||||
|
[Parameter] public bool RightToLeft { get; set; }
|
||||||
|
[Parameter] public bool EnablePreview { get; set; } = true;
|
||||||
|
[Parameter] public bool EnableMermaid { get; set; } = true;
|
||||||
|
[Parameter] public bool EnableHighlight { get; set; } = true;
|
||||||
|
[Parameter] public string HighlightTheme { get; set; } = "github";
|
||||||
|
[Parameter] public SbMarkEditorMode Mode { get; set; } = SbMarkEditorMode.Markdown;
|
||||||
|
[Parameter] public string? SourceLanguage { get; set; }
|
||||||
|
[Parameter] public bool UseToolbarContributors { get; set; }
|
||||||
|
[Parameter] public bool IncludeDefaultToolbarItems { get; set; } = true;
|
||||||
|
[Parameter] public bool HideToolbar { get; set; }
|
||||||
|
[Parameter] public IReadOnlyList<SbMarkdownToolbarItem>? ToolbarItems { get; set; }
|
||||||
|
[Parameter] public EventCallback<string> OnShortcut { get; set; }
|
||||||
|
[Parameter] public string? MinHeight { get; set; } = "200px";
|
||||||
|
[Parameter] public string? MaxHeight { get; set; }
|
||||||
|
[Parameter] public int FallbackRows { get; set; } = 12;
|
||||||
|
[Parameter] public bool IsDiffReview { get; set; }
|
||||||
|
[Parameter] public string OriginalValue { get; set; } = string.Empty;
|
||||||
|
[Parameter] public string SuggestedValue { get; set; } = string.Empty;
|
||||||
|
[Parameter] public EventCallback<string> SuggestedValueChanged { get; set; }
|
||||||
|
[Parameter] public EventCallback OnApplyChanges { get; set; }
|
||||||
|
[Parameter] public EventCallback OnDiscardChanges { get; set; }
|
||||||
|
[Parameter(CaptureUnmatchedValues = true)]
|
||||||
|
public Dictionary<string, object>? AdditionalAttributes { get; set; }
|
||||||
|
|
||||||
|
private SbMarkdownEditorMode ResolveEditorMode()
|
||||||
|
{
|
||||||
|
return Mode switch
|
||||||
|
{
|
||||||
|
SbMarkEditorMode.Source => SbMarkdownEditorMode.Source,
|
||||||
|
SbMarkEditorMode.Markup => SbMarkdownEditorMode.Source,
|
||||||
|
_ => SbMarkdownEditorMode.Markdown
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? ResolveSourceLanguage()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(SourceLanguage))
|
||||||
|
{
|
||||||
|
return SourceLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Mode switch
|
||||||
|
{
|
||||||
|
SbMarkEditorMode.Markup => "html",
|
||||||
|
SbMarkEditorMode.Source => "html",
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace SufiChain.SufiBlazor.Contracts.Editors;
|
||||||
|
|
||||||
|
public enum SbMarkEditorMode
|
||||||
|
{
|
||||||
|
Markdown,
|
||||||
|
Markup,
|
||||||
|
Source
|
||||||
|
}
|
||||||
@@ -323,6 +323,7 @@ export async function initEditor(textarea, dotNetRef, options) {
|
|||||||
easyOptions.preview = false;
|
easyOptions.preview = false;
|
||||||
easyOptions.sideBySideFullscreen = false;
|
easyOptions.sideBySideFullscreen = false;
|
||||||
} else {
|
} else {
|
||||||
|
easyOptions.sideBySideFullscreen = false;
|
||||||
easyOptions.previewRender = buildPreviewRender(options);
|
easyOptions.previewRender = buildPreviewRender(options);
|
||||||
easyOptions.renderingConfig.markedOptions = {
|
easyOptions.renderingConfig.markedOptions = {
|
||||||
highlight: buildHighlightFn(options.enableHighlight, options.enableMermaid)
|
highlight: buildHighlightFn(options.enableHighlight, options.enableMermaid)
|
||||||
@@ -435,6 +436,20 @@ export function insertTextAtCursor(editorId, text) {
|
|||||||
cm.focus();
|
cm.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleContainerFullscreen(stored) {
|
||||||
|
const wrapper = stored.easyMDE.codemirror.getWrapperElement();
|
||||||
|
const container = wrapper?.closest('.sb-markdown-editor');
|
||||||
|
if (!container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
container.classList.toggle('sb-markdown-editor--fullscreen');
|
||||||
|
document.documentElement.classList.toggle(
|
||||||
|
'sb-markdown-editor-fullscreen-active',
|
||||||
|
container.classList.contains('sb-markdown-editor--fullscreen'));
|
||||||
|
stored.easyMDE.codemirror.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
export function execAction(editorId, action, value) {
|
export function execAction(editorId, action, value) {
|
||||||
const stored = editors.get(editorId);
|
const stored = editors.get(editorId);
|
||||||
if (!stored) {
|
if (!stored) {
|
||||||
@@ -457,7 +472,7 @@ export function execAction(editorId, action, value) {
|
|||||||
case 'image': easyMDE.drawImage(); break;
|
case 'image': easyMDE.drawImage(); break;
|
||||||
case 'preview': easyMDE.togglePreview(); break;
|
case 'preview': easyMDE.togglePreview(); break;
|
||||||
case 'side-by-side': easyMDE.toggleSideBySide(); break;
|
case 'side-by-side': easyMDE.toggleSideBySide(); break;
|
||||||
case 'fullscreen': easyMDE.toggleFullScreen(); break;
|
case 'fullscreen': toggleContainerFullscreen(stored); break;
|
||||||
case 'undo': easyMDE.codemirror.undo(); break;
|
case 'undo': easyMDE.codemirror.undo(); break;
|
||||||
case 'redo': easyMDE.codemirror.redo(); break;
|
case 'redo': easyMDE.codemirror.redo(); break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -8445,6 +8445,55 @@ body.sb-resizing {
|
|||||||
color: var(--sb-color-text);
|
color: var(--sb-color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sb-markdown-editor .EasyMDEContainer.sided--no-fullscreen {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sb-markdown-editor .EasyMDEContainer.sided--no-fullscreen .CodeMirror-sided,
|
||||||
|
.sb-markdown-editor .EasyMDEContainer.sided--no-fullscreen .editor-preview-side {
|
||||||
|
flex: 1 1 50%;
|
||||||
|
width: 50% !important;
|
||||||
|
min-width: 20rem;
|
||||||
|
position: static !important;
|
||||||
|
inset: auto !important;
|
||||||
|
height: auto;
|
||||||
|
max-height: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sb-markdown-editor .EasyMDEContainer.sided--no-fullscreen .editor-preview-active-side {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sb-markdown-editor-fullscreen-active,
|
||||||
|
.sb-markdown-editor-fullscreen-active body {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sb-markdown-editor.sb-markdown-editor--fullscreen {
|
||||||
|
position: fixed;
|
||||||
|
inset: var(--sb-space-4);
|
||||||
|
z-index: 2000;
|
||||||
|
min-height: auto;
|
||||||
|
background: var(--sb-color-surface);
|
||||||
|
box-shadow: var(--sb-shadow-xl, 0 24px 64px rgba(15, 23, 42, 0.22));
|
||||||
|
}
|
||||||
|
|
||||||
|
.sb-markdown-editor.sb-markdown-editor--fullscreen .EasyMDEContainer {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sb-markdown-editor.sb-markdown-editor--fullscreen .EasyMDEContainer .CodeMirror {
|
||||||
|
height: calc(100vh - 9rem) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sb-markdown-editor.sb-markdown-editor--fullscreen .EasyMDEContainer.sided--no-fullscreen .CodeMirror-sided,
|
||||||
|
.sb-markdown-editor.sb-markdown-editor--fullscreen .EasyMDEContainer.sided--no-fullscreen .editor-preview-side {
|
||||||
|
height: calc(100vh - 9rem) !important;
|
||||||
|
}
|
||||||
|
|
||||||
.sb-markdown-viewer pre,
|
.sb-markdown-viewer pre,
|
||||||
.sb-markdown-viewer code {
|
.sb-markdown-viewer code {
|
||||||
font-family: var(--sb-font-family-mono, monospace);
|
font-family: var(--sb-font-family-mono, monospace);
|
||||||
|
|||||||
Reference in New Issue
Block a user