mirror of
https://github.com/zadam/trilium.git
synced 2025-12-11 18:04:24 +01:00
feat(ckeditor/watchdog): functional copy to clipboard button
This commit is contained in:
parent
75a1fcc933
commit
397fb785d6
@ -205,7 +205,8 @@
|
|||||||
"info": {
|
"info": {
|
||||||
"modalTitle": "Info message",
|
"modalTitle": "Info message",
|
||||||
"closeButton": "Close",
|
"closeButton": "Close",
|
||||||
"okButton": "OK"
|
"okButton": "OK",
|
||||||
|
"copy_to_clipboard": "Copy to clipboard"
|
||||||
},
|
},
|
||||||
"jump_to_note": {
|
"jump_to_note": {
|
||||||
"search_placeholder": "Search for note by its name or type > for commands...",
|
"search_placeholder": "Search for note by its name or type > for commands...",
|
||||||
|
|||||||
@ -8,11 +8,19 @@ import { useTriliumEvent } from "../react/hooks";
|
|||||||
import { isValidElement } from "preact";
|
import { isValidElement } from "preact";
|
||||||
import { ConfirmWithMessageOptions } from "./confirm";
|
import { ConfirmWithMessageOptions } from "./confirm";
|
||||||
import "./info.css";
|
import "./info.css";
|
||||||
|
import server from "../../services/server";
|
||||||
|
import { ToMarkdownResponse } from "@triliumnext/commons";
|
||||||
|
import { copyTextWithToast } from "../../services/clipboard_ext";
|
||||||
|
|
||||||
|
export interface InfoExtraProps extends Partial<Pick<ModalProps, "size" | "title">> {
|
||||||
|
/** Adds a button in the footer that allows easily copying the content of the infobox to clipboard. */
|
||||||
|
copyToClipboardButton?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export type InfoExtraProps = Partial<Pick<ModalProps, "size" | "title">>;
|
|
||||||
export type InfoProps = ConfirmWithMessageOptions & InfoExtraProps;
|
export type InfoProps = ConfirmWithMessageOptions & InfoExtraProps;
|
||||||
|
|
||||||
export default function InfoDialog() {
|
export default function InfoDialog() {
|
||||||
|
const modalRef = useRef<HTMLDivElement>(null);
|
||||||
const [ opts, setOpts ] = useState<EventData<"showInfoDialog">>();
|
const [ opts, setOpts ] = useState<EventData<"showInfoDialog">>();
|
||||||
const [ shown, setShown ] = useState(false);
|
const [ shown, setShown ] = useState(false);
|
||||||
const okButtonRef = useRef<HTMLButtonElement>(null);
|
const okButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
@ -31,11 +39,28 @@ export default function InfoDialog() {
|
|||||||
setShown(false);
|
setShown(false);
|
||||||
}}
|
}}
|
||||||
onShown={() => okButtonRef.current?.focus?.()}
|
onShown={() => okButtonRef.current?.focus?.()}
|
||||||
footer={<Button
|
modalRef={modalRef}
|
||||||
buttonRef={okButtonRef}
|
footer={<>
|
||||||
text={t("info.okButton")}
|
{opts?.copyToClipboardButton && (
|
||||||
onClick={() => setShown(false)}
|
<Button
|
||||||
/>}
|
text={t("info.copy_to_clipboard")}
|
||||||
|
icon="bx bx-copy"
|
||||||
|
onClick={async () => {
|
||||||
|
const htmlContent = modalRef.current?.querySelector<HTMLDivElement>(".modal-body")?.innerHTML;
|
||||||
|
if (!htmlContent) return;
|
||||||
|
|
||||||
|
const { markdownContent } = await server.post<ToMarkdownResponse>("other/to-markdown", { htmlContent });
|
||||||
|
copyTextWithToast(markdownContent);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
buttonRef={okButtonRef}
|
||||||
|
text={t("info.okButton")}
|
||||||
|
onClick={() => setShown(false)}
|
||||||
|
/>
|
||||||
|
</>}
|
||||||
show={shown}
|
show={shown}
|
||||||
stackable
|
stackable
|
||||||
scrollable
|
scrollable
|
||||||
|
|||||||
@ -7,15 +7,12 @@ import Modal from "../react/Modal";
|
|||||||
import Button from "../react/Button";
|
import Button from "../react/Button";
|
||||||
import { useTriliumEvent } from "../react/hooks";
|
import { useTriliumEvent } from "../react/hooks";
|
||||||
import { CKEditorApi } from "../type_widgets/text/CKEditorWithWatchdog";
|
import { CKEditorApi } from "../type_widgets/text/CKEditorWithWatchdog";
|
||||||
|
import { RenderMarkdownResponse } from "@triliumnext/commons";
|
||||||
|
|
||||||
export interface MarkdownImportOpts {
|
export interface MarkdownImportOpts {
|
||||||
editorApi: CKEditorApi;
|
editorApi: CKEditorApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RenderMarkdownResponse {
|
|
||||||
htmlContent: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function MarkdownImportDialog() {
|
export default function MarkdownImportDialog() {
|
||||||
const markdownImportTextArea = useRef<HTMLTextAreaElement>(null);
|
const markdownImportTextArea = useRef<HTMLTextAreaElement>(null);
|
||||||
const editorApiRef = useRef<CKEditorApi>(null);
|
const editorApiRef = useRef<CKEditorApi>(null);
|
||||||
|
|||||||
@ -310,10 +310,11 @@ function useWatchdogCrashHandling() {
|
|||||||
dialog.info(<>
|
dialog.info(<>
|
||||||
<p>{t("editable_text.editor_crashed_details_intro")}</p>
|
<p>{t("editable_text.editor_crashed_details_intro")}</p>
|
||||||
<h3>{t("editable_text.editor_crashed_details_title")}</h3>
|
<h3>{t("editable_text.editor_crashed_details_title")}</h3>
|
||||||
<pre>{formattedCrash}</pre>
|
<pre><code class="language-application-json">{formattedCrash}</code></pre>
|
||||||
</>, {
|
</>, {
|
||||||
title: t("editable_text.editor_crashed_title"),
|
title: t("editable_text.editor_crashed_title"),
|
||||||
size: "lg"
|
size: "lg",
|
||||||
|
copyToClipboardButton: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@ import type { Request } from "express";
|
|||||||
|
|
||||||
import becca from "../../becca/becca.js";
|
import becca from "../../becca/becca.js";
|
||||||
import markdownService from "../../services/import/markdown.js";
|
import markdownService from "../../services/import/markdown.js";
|
||||||
|
import markdown from "../../services/export/markdown.js";
|
||||||
|
import { RenderMarkdownResponse, ToMarkdownResponse } from "@triliumnext/commons";
|
||||||
|
|
||||||
function getIconUsage() {
|
function getIconUsage() {
|
||||||
const iconClassToCountMap: Record<string, number> = {};
|
const iconClassToCountMap: Record<string, number> = {};
|
||||||
@ -29,13 +31,20 @@ function getIconUsage() {
|
|||||||
|
|
||||||
function renderMarkdown(req: Request) {
|
function renderMarkdown(req: Request) {
|
||||||
const { markdownContent } = req.body;
|
const { markdownContent } = req.body;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
htmlContent: markdownService.renderToHtml(markdownContent, "")
|
htmlContent: markdownService.renderToHtml(markdownContent, "")
|
||||||
};
|
} satisfies RenderMarkdownResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMarkdown(req: Request) {
|
||||||
|
const { htmlContent } = req.body;
|
||||||
|
return {
|
||||||
|
markdownContent: markdown.toMarkdown(htmlContent)
|
||||||
|
} satisfies ToMarkdownResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getIconUsage,
|
getIconUsage,
|
||||||
renderMarkdown
|
renderMarkdown,
|
||||||
|
toMarkdown
|
||||||
};
|
};
|
||||||
|
|||||||
@ -348,6 +348,7 @@ function register(app: express.Application) {
|
|||||||
route(GET, "/api/fonts", [auth.checkApiAuthOrElectron], fontsRoute.getFontCss);
|
route(GET, "/api/fonts", [auth.checkApiAuthOrElectron], fontsRoute.getFontCss);
|
||||||
apiRoute(GET, "/api/other/icon-usage", otherRoute.getIconUsage);
|
apiRoute(GET, "/api/other/icon-usage", otherRoute.getIconUsage);
|
||||||
apiRoute(PST, "/api/other/render-markdown", otherRoute.renderMarkdown);
|
apiRoute(PST, "/api/other/render-markdown", otherRoute.renderMarkdown);
|
||||||
|
apiRoute(PST, "/api/other/to-markdown", otherRoute.toMarkdown);
|
||||||
apiRoute(GET, "/api/recent-changes/:ancestorNoteId", recentChangesApiRoute.getRecentChanges);
|
apiRoute(GET, "/api/recent-changes/:ancestorNoteId", recentChangesApiRoute.getRecentChanges);
|
||||||
apiRoute(GET, "/api/edited-notes/:date", revisionsApiRoute.getEditedNotesOnDate);
|
apiRoute(GET, "/api/edited-notes/:date", revisionsApiRoute.getEditedNotesOnDate);
|
||||||
|
|
||||||
|
|||||||
@ -277,3 +277,11 @@ export interface NoteMapPostResponse {
|
|||||||
export interface UpdateAttributeResponse {
|
export interface UpdateAttributeResponse {
|
||||||
attributeId: string;
|
attributeId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RenderMarkdownResponse {
|
||||||
|
htmlContent: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ToMarkdownResponse {
|
||||||
|
markdownContent: string;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user