mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-06 20:15:17 +02:00
feat: introduce plugin presets for PlateEditor, allowing flexible configuration of editor features
This commit is contained in:
parent
fed500ce34
commit
e34921eac4
4 changed files with 111 additions and 32 deletions
|
|
@ -466,6 +466,7 @@ export default function EditorPage() {
|
||||||
<div className="flex-1 min-h-0">
|
<div className="flex-1 min-h-0">
|
||||||
<PlateEditor
|
<PlateEditor
|
||||||
key={documentId}
|
key={documentId}
|
||||||
|
preset="full"
|
||||||
markdown={document?.source_markdown ?? ""}
|
markdown={document?.source_markdown ?? ""}
|
||||||
onMarkdownChange={handleMarkdownChange}
|
onMarkdownChange={handleMarkdownChange}
|
||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,17 @@
|
||||||
|
|
||||||
import { useEffect, useMemo, useRef } from "react";
|
import { useEffect, useMemo, useRef } from "react";
|
||||||
import { MarkdownPlugin, remarkMdx } from "@platejs/markdown";
|
import { MarkdownPlugin, remarkMdx } from "@platejs/markdown";
|
||||||
|
import type { AnyPluginConfig } from "platejs";
|
||||||
import { createPlatePlugin, Key, Plate, usePlateEditor } from "platejs/react";
|
import { createPlatePlugin, Key, Plate, usePlateEditor } from "platejs/react";
|
||||||
import remarkGfm from "remark-gfm";
|
import remarkGfm from "remark-gfm";
|
||||||
import remarkMath from "remark-math";
|
import remarkMath from "remark-math";
|
||||||
|
|
||||||
import { AutoformatKit } from "@/components/editor/plugins/autoformat-kit";
|
import { type EditorPreset, presetMap } from "@/components/editor/presets";
|
||||||
import { BasicNodesKit } from "@/components/editor/plugins/basic-nodes-kit";
|
|
||||||
import { CalloutKit } from "@/components/editor/plugins/callout-kit";
|
|
||||||
import { CodeBlockKit } from "@/components/editor/plugins/code-block-kit";
|
|
||||||
import { DndKit } from "@/components/editor/plugins/dnd-kit";
|
|
||||||
import { FixedToolbarKit } from "@/components/editor/plugins/fixed-toolbar-kit";
|
|
||||||
import { FloatingToolbarKit } from "@/components/editor/plugins/floating-toolbar-kit";
|
|
||||||
import { LinkKit } from "@/components/editor/plugins/link-kit";
|
|
||||||
import { ListKit } from "@/components/editor/plugins/list-kit";
|
|
||||||
import { MathKit } from "@/components/editor/plugins/math-kit";
|
|
||||||
import { SelectionKit } from "@/components/editor/plugins/selection-kit";
|
|
||||||
import { SlashCommandKit } from "@/components/editor/plugins/slash-command-kit";
|
|
||||||
import { TableKit } from "@/components/editor/plugins/table-kit";
|
|
||||||
import { ToggleKit } from "@/components/editor/plugins/toggle-kit";
|
|
||||||
import { Editor, EditorContainer } from "@/components/ui/editor";
|
import { Editor, EditorContainer } from "@/components/ui/editor";
|
||||||
import { escapeMdxExpressions } from "@/components/editor/utils/escape-mdx";
|
import { escapeMdxExpressions } from "@/components/editor/utils/escape-mdx";
|
||||||
import { EditorSaveContext } from "@/components/editor/editor-save-context";
|
import { EditorSaveContext } from "@/components/editor/editor-save-context";
|
||||||
|
|
||||||
interface PlateEditorProps {
|
export interface PlateEditorProps {
|
||||||
/** Markdown string to load as initial content */
|
/** Markdown string to load as initial content */
|
||||||
markdown?: string;
|
markdown?: string;
|
||||||
/** Called when the editor content changes, with serialized markdown */
|
/** Called when the editor content changes, with serialized markdown */
|
||||||
|
|
@ -44,7 +32,7 @@ interface PlateEditorProps {
|
||||||
editorVariant?: "default" | "demo" | "fullWidth" | "none";
|
editorVariant?: "default" | "demo" | "fullWidth" | "none";
|
||||||
/** Additional className for the container */
|
/** Additional className for the container */
|
||||||
className?: string;
|
className?: string;
|
||||||
/** Save callback. When provided, a save button appears in the toolbar on unsaved changes. */
|
/** Save callback. When provided, ⌘+S / Ctrl+S shortcut is registered and save button appears. */
|
||||||
onSave?: () => void;
|
onSave?: () => void;
|
||||||
/** Whether there are unsaved changes */
|
/** Whether there are unsaved changes */
|
||||||
hasUnsavedChanges?: boolean;
|
hasUnsavedChanges?: boolean;
|
||||||
|
|
@ -52,6 +40,20 @@ interface PlateEditorProps {
|
||||||
isSaving?: boolean;
|
isSaving?: boolean;
|
||||||
/** Start the editor in editing mode instead of viewing mode. Ignored when readOnly is true. */
|
/** Start the editor in editing mode instead of viewing mode. Ignored when readOnly is true. */
|
||||||
defaultEditing?: boolean;
|
defaultEditing?: boolean;
|
||||||
|
/**
|
||||||
|
* Plugin preset to use. Controls which plugin kits are loaded.
|
||||||
|
* - "full" – all plugins (toolbars, slash commands, DnD, etc.)
|
||||||
|
* - "minimal" – core formatting only (no fixed toolbar, slash commands, DnD, block selection)
|
||||||
|
* - "readonly" – rendering support for all rich content, no editing UI
|
||||||
|
* @default "full"
|
||||||
|
*/
|
||||||
|
preset?: EditorPreset;
|
||||||
|
/**
|
||||||
|
* Additional plugins to append after the preset plugins.
|
||||||
|
* Use this to inject feature-specific plugins (e.g. approve/reject blocks)
|
||||||
|
* without modifying the core editor component.
|
||||||
|
*/
|
||||||
|
extraPlugins?: AnyPluginConfig[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PlateEditor({
|
export function PlateEditor({
|
||||||
|
|
@ -66,6 +68,8 @@ export function PlateEditor({
|
||||||
hasUnsavedChanges = false,
|
hasUnsavedChanges = false,
|
||||||
isSaving = false,
|
isSaving = false,
|
||||||
defaultEditing = false,
|
defaultEditing = false,
|
||||||
|
preset = "full",
|
||||||
|
extraPlugins = [],
|
||||||
}: PlateEditorProps) {
|
}: PlateEditorProps) {
|
||||||
const lastMarkdownRef = useRef(markdown);
|
const lastMarkdownRef = useRef(markdown);
|
||||||
|
|
||||||
|
|
@ -76,7 +80,8 @@ export function PlateEditor({
|
||||||
onSaveRef.current = onSave;
|
onSaveRef.current = onSave;
|
||||||
}, [onSave]);
|
}, [onSave]);
|
||||||
|
|
||||||
// Stable Plate plugin for ⌘+S / Ctrl+S save shortcut
|
// Stable Plate plugin for ⌘+S / Ctrl+S save shortcut.
|
||||||
|
// Only included when onSave is provided.
|
||||||
const SaveShortcutPlugin = useMemo(
|
const SaveShortcutPlugin = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createPlatePlugin({
|
createPlatePlugin({
|
||||||
|
|
@ -94,27 +99,20 @@ export function PlateEditor({
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Resolve the plugin set from the chosen preset
|
||||||
|
const presetPlugins = presetMap[preset];
|
||||||
|
|
||||||
// When readOnly is forced, always start in readOnly.
|
// When readOnly is forced, always start in readOnly.
|
||||||
// Otherwise, respect defaultEditing to decide initial mode.
|
// Otherwise, respect defaultEditing to decide initial mode.
|
||||||
// The user can still toggle between editing/viewing via ModeToolbarButton.
|
// The user can still toggle between editing/viewing via ModeToolbarButton.
|
||||||
const editor = usePlateEditor({
|
const editor = usePlateEditor({
|
||||||
readOnly: readOnly || !defaultEditing,
|
readOnly: readOnly || !defaultEditing,
|
||||||
plugins: [
|
plugins: [
|
||||||
...BasicNodesKit,
|
...presetPlugins,
|
||||||
...TableKit,
|
// Only register save shortcut when a save handler is provided
|
||||||
...ListKit,
|
...(onSave ? [SaveShortcutPlugin] : []),
|
||||||
...CodeBlockKit,
|
// Consumer-provided extra plugins
|
||||||
...LinkKit,
|
...extraPlugins,
|
||||||
...CalloutKit,
|
|
||||||
...ToggleKit,
|
|
||||||
...MathKit,
|
|
||||||
...SelectionKit,
|
|
||||||
...SlashCommandKit,
|
|
||||||
...FixedToolbarKit,
|
|
||||||
...FloatingToolbarKit,
|
|
||||||
...AutoformatKit,
|
|
||||||
...DndKit,
|
|
||||||
SaveShortcutPlugin,
|
|
||||||
MarkdownPlugin.configure({
|
MarkdownPlugin.configure({
|
||||||
options: {
|
options: {
|
||||||
remarkPlugins: [remarkGfm, remarkMath, remarkMdx],
|
remarkPlugins: [remarkGfm, remarkMath, remarkMdx],
|
||||||
|
|
|
||||||
79
surfsense_web/components/editor/presets.ts
Normal file
79
surfsense_web/components/editor/presets.ts
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import type { AnyPluginConfig } from "platejs";
|
||||||
|
|
||||||
|
import { AutoformatKit } from "@/components/editor/plugins/autoformat-kit";
|
||||||
|
import { BasicNodesKit } from "@/components/editor/plugins/basic-nodes-kit";
|
||||||
|
import { CalloutKit } from "@/components/editor/plugins/callout-kit";
|
||||||
|
import { CodeBlockKit } from "@/components/editor/plugins/code-block-kit";
|
||||||
|
import { DndKit } from "@/components/editor/plugins/dnd-kit";
|
||||||
|
import { FixedToolbarKit } from "@/components/editor/plugins/fixed-toolbar-kit";
|
||||||
|
import { FloatingToolbarKit } from "@/components/editor/plugins/floating-toolbar-kit";
|
||||||
|
import { LinkKit } from "@/components/editor/plugins/link-kit";
|
||||||
|
import { ListKit } from "@/components/editor/plugins/list-kit";
|
||||||
|
import { MathKit } from "@/components/editor/plugins/math-kit";
|
||||||
|
import { SelectionKit } from "@/components/editor/plugins/selection-kit";
|
||||||
|
import { SlashCommandKit } from "@/components/editor/plugins/slash-command-kit";
|
||||||
|
import { TableKit } from "@/components/editor/plugins/table-kit";
|
||||||
|
import { ToggleKit } from "@/components/editor/plugins/toggle-kit";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full preset – every plugin kit enabled.
|
||||||
|
* Used by the Documents editor and Reports editor (rich editing experience).
|
||||||
|
*/
|
||||||
|
export const fullPreset: AnyPluginConfig[] = [
|
||||||
|
...BasicNodesKit,
|
||||||
|
...TableKit,
|
||||||
|
...ListKit,
|
||||||
|
...CodeBlockKit,
|
||||||
|
...LinkKit,
|
||||||
|
...CalloutKit,
|
||||||
|
...ToggleKit,
|
||||||
|
...MathKit,
|
||||||
|
...SelectionKit,
|
||||||
|
...SlashCommandKit,
|
||||||
|
...FixedToolbarKit,
|
||||||
|
...FloatingToolbarKit,
|
||||||
|
...AutoformatKit,
|
||||||
|
...DndKit,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimal preset – lightweight editing with core formatting only.
|
||||||
|
* No fixed toolbar, no slash commands, no DnD, no block selection.
|
||||||
|
* Ideal for inline editors like human-in-the-loop agent actions.
|
||||||
|
*/
|
||||||
|
export const minimalPreset: AnyPluginConfig[] = [
|
||||||
|
...BasicNodesKit,
|
||||||
|
...ListKit,
|
||||||
|
...CodeBlockKit,
|
||||||
|
...LinkKit,
|
||||||
|
...FloatingToolbarKit,
|
||||||
|
...AutoformatKit,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read-only preset – rendering support for all rich content, but no editing UI.
|
||||||
|
* No toolbars, no autoformat, no DnD, no slash commands, no block selection.
|
||||||
|
* Ideal for pure display / viewer contexts.
|
||||||
|
*/
|
||||||
|
export const readonlyPreset: AnyPluginConfig[] = [
|
||||||
|
...BasicNodesKit,
|
||||||
|
...TableKit,
|
||||||
|
...ListKit,
|
||||||
|
...CodeBlockKit,
|
||||||
|
...LinkKit,
|
||||||
|
...CalloutKit,
|
||||||
|
...ToggleKit,
|
||||||
|
...MathKit,
|
||||||
|
];
|
||||||
|
|
||||||
|
/** All available preset names */
|
||||||
|
export type EditorPreset = "full" | "minimal" | "readonly";
|
||||||
|
|
||||||
|
/** Map from preset name to plugin array */
|
||||||
|
export const presetMap: Record<EditorPreset, AnyPluginConfig[]> = {
|
||||||
|
full: fullPreset,
|
||||||
|
minimal: minimalPreset,
|
||||||
|
readonly: readonlyPreset,
|
||||||
|
};
|
||||||
|
|
@ -438,6 +438,7 @@ function ReportPanelContent({
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<PlateEditor
|
<PlateEditor
|
||||||
|
preset="full"
|
||||||
markdown={reportContent.content}
|
markdown={reportContent.content}
|
||||||
onMarkdownChange={setEditedMarkdown}
|
onMarkdownChange={setEditedMarkdown}
|
||||||
readOnly={false}
|
readOnly={false}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue