chore(react/type_widget): save SVG attachment

This commit is contained in:
Elian Doran 2025-09-20 14:00:58 +03:00
parent 02017ebd9d
commit bde7b753a0
No known key found for this signature in database
4 changed files with 26 additions and 13 deletions

View File

@ -27,6 +27,7 @@ export default function Mermaid(props: TypeWidgetProps) {
return ( return (
<SvgSplitEditor <SvgSplitEditor
attachmentName="mermaid-export"
renderSvg={renderSvg} renderSvg={renderSvg}
{...props} {...props}
/> />

View File

@ -17,7 +17,10 @@ export interface EditableCodeProps extends TypeWidgetProps {
debounceUpdate?: boolean; debounceUpdate?: boolean;
lineWrapping?: boolean; lineWrapping?: boolean;
updateInterval?: number; updateInterval?: number;
/** Invoked when the content of the note is changed, such as a different revision or a note switch. */
onContentChanged?: (content: string) => void; onContentChanged?: (content: string) => void;
/** Invoked after the content of the note has been uploaded to the server, using a spaced update. */
dataSaved?: () => void;
} }
export function ReadOnlyCode({ note, viewScope, ntxId, parentComponent }: TypeWidgetProps) { export function ReadOnlyCode({ note, viewScope, ntxId, parentComponent }: TypeWidgetProps) {
@ -43,7 +46,7 @@ export function ReadOnlyCode({ note, viewScope, ntxId, parentComponent }: TypeWi
) )
} }
export function EditableCode({ note, ntxId, debounceUpdate, parentComponent, updateInterval, onContentChanged, ...editorProps }: EditableCodeProps) { export function EditableCode({ note, ntxId, debounceUpdate, parentComponent, updateInterval, onContentChanged, dataSaved, ...editorProps }: EditableCodeProps) {
const editorRef = useRef<VanillaCodeMirror>(null); const editorRef = useRef<VanillaCodeMirror>(null);
const containerRef = useRef<HTMLPreElement>(null); const containerRef = useRef<HTMLPreElement>(null);
const [ vimKeymapEnabled ] = useTriliumOptionBool("vimKeymapEnabled"); const [ vimKeymapEnabled ] = useTriliumOptionBool("vimKeymapEnabled");
@ -57,6 +60,7 @@ export function EditableCode({ note, ntxId, debounceUpdate, parentComponent, upd
codeEditor.setMimeType(note.mime); codeEditor.setMimeType(note.mime);
codeEditor.clearHistory(); codeEditor.clearHistory();
}, },
dataSaved,
updateInterval updateInterval
}); });

View File

@ -2,8 +2,13 @@ import { useState } from "preact/hooks";
import { t } from "../../../services/i18n"; import { t } from "../../../services/i18n";
import SplitEditor, { PreviewButton, SplitEditorProps } from "./SplitEditor"; import SplitEditor, { PreviewButton, SplitEditorProps } from "./SplitEditor";
import { RawHtmlBlock } from "../../react/RawHtml"; import { RawHtmlBlock } from "../../react/RawHtml";
import server from "../../../services/server";
interface SvgSplitEditorProps extends Omit<SplitEditorProps, "previewContent"> { interface SvgSplitEditorProps extends Omit<SplitEditorProps, "previewContent"> {
/**
* The name of the note attachment (without .svg extension) that will be used for storing the preview.
*/
attachmentName: string;
/** /**
* Called upon when the SVG preview needs refreshing, such as when the editor has switched to a new note or the content has switched. * Called upon when the SVG preview needs refreshing, such as when the editor has switched to a new note or the content has switched.
* *
@ -14,7 +19,7 @@ interface SvgSplitEditorProps extends Omit<SplitEditorProps, "previewContent"> {
renderSvg(content: string): string | Promise<string>; renderSvg(content: string): string | Promise<string>;
} }
export default function SvgSplitEditor({ renderSvg, ...props }: SvgSplitEditorProps) { export default function SvgSplitEditor({ note, attachmentName, renderSvg, ...props }: SvgSplitEditorProps) {
const [ svg, setSvg ] = useState<string>(); const [ svg, setSvg ] = useState<string>();
const [ error, setError ] = useState<string | null | undefined>(); const [ error, setError ] = useState<string | null | undefined>();
@ -31,10 +36,24 @@ export default function SvgSplitEditor({ renderSvg, ...props }: SvgSplitEditorPr
} }
} }
function onSave() {
const payload = {
role: "image",
title: `${attachmentName}.svg`,
mime: "image/svg+xml",
content: svg,
position: 0
};
server.post(`notes/${note.noteId}/attachments?matchBy=title`, payload);
}
return ( return (
<SplitEditor <SplitEditor
note={note}
error={error} error={error}
onContentChanged={onContentChanged} onContentChanged={onContentChanged}
dataSaved={onSave}
previewContent={( previewContent={(
<RawHtmlBlock className="render-container" html={svg} /> <RawHtmlBlock className="render-container" html={svg} />
)} )}

View File

@ -95,15 +95,7 @@ export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTy
} }
#saveSvg() { #saveSvg() {
const payload = {
role: "image",
title: `${this.attachmentName}.svg`,
mime: "image/svg+xml",
content: this.svg,
position: 0
};
server.post(`notes/${this.noteId}/attachments?matchBy=title`, payload);
} }
cleanup(): void { cleanup(): void {
@ -112,9 +104,6 @@ export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTy
super.cleanup(); super.cleanup();
} }
/**
* Called to obtain the name of the note attachment (without .svg extension) that will be used for storing the preview.
*/
abstract get attachmentName(): string; abstract get attachmentName(): string;
/** /**