Add 'Copy as Markdown' action

Remove smart quotes from Markdown export, closes #5303
This commit is contained in:
Tom Moor
2023-12-09 15:00:33 -05:00
parent f9c3b0e193
commit 3f3d7b4978
5 changed files with 55 additions and 13 deletions

View File

@@ -1,3 +1,4 @@
import copy from "copy-to-clipboard";
import invariant from "invariant";
import {
DownloadIcon,
@@ -24,10 +25,12 @@ import {
PublishIcon,
CommentIcon,
GlobeIcon,
CopyIcon,
} from "outline-icons";
import * as React from "react";
import { toast } from "sonner";
import { ExportContentType, TeamPreference } from "@shared/types";
import MarkdownHelper from "@shared/utils/MarkdownHelper";
import { getEventFiles } from "@shared/utils/files";
import SharePopover from "~/scenes/Document/components/SharePopover";
import DocumentDelete from "~/scenes/DocumentDelete";
@@ -111,6 +114,23 @@ export const createDocumentFromTemplate = createAction({
),
});
export const copyDocumentAsMarkdown = createAction({
name: ({ t }) => t("Copy as Markdown"),
section: DocumentSection,
icon: <CopyIcon />,
keywords: "clipboard",
visible: ({ activeDocumentId }) => !!activeDocumentId,
perform: ({ stores, activeDocumentId, t }) => {
const document = activeDocumentId
? stores.documents.get(activeDocumentId)
: undefined;
if (document) {
copy(MarkdownHelper.toMarkdown(document));
toast.success(t("Markdown copied to clipboard"));
}
},
});
export const createNestedDocument = createAction({
name: ({ t }) => t("New nested document"),
analyticsName: "New document",
@@ -889,6 +909,7 @@ export const rootDocumentActions = [
deleteDocument,
importDocument,
downloadDocument,
copyDocumentAsMarkdown,
starDocument,
unstarDocument,
publishDocument,

View File

@@ -10,6 +10,7 @@ import { Transaction } from "sequelize";
import * as Y from "yjs";
import textBetween from "@shared/editor/lib/textBetween";
import { AttachmentPreset } from "@shared/types";
import MarkdownHelper from "@shared/utils/MarkdownHelper";
import {
getCurrentDateAsString,
getCurrentDateTimeAsString,
@@ -88,13 +89,7 @@ export default class DocumentHelper {
* @returns The document title and content as a Markdown string
*/
static toMarkdown(document: Document | Revision) {
const text = document.text.replace(/\n\\\n/g, "\n\n");
if (document.version) {
return `# ${document.title}\n\n${text}`;
}
return text;
return MarkdownHelper.toMarkdown(document);
}
/**

View File

@@ -536,13 +536,8 @@ router.post(
contentType = "text/markdown";
content = DocumentHelper.toMarkdown(document);
} else {
contentType = "application/json";
content = DocumentHelper.toMarkdown(document);
}
if (contentType === "application/json") {
ctx.body = {
data: content,
data: DocumentHelper.toMarkdown(document),
};
return;
}

View File

@@ -20,6 +20,8 @@
"Open document": "Open document",
"New document": "New document",
"New from template": "New from template",
"Copy as Markdown": "Copy as Markdown",
"Markdown copied to clipboard": "Markdown copied to clipboard",
"New nested document": "New nested document",
"Publish": "Publish",
"Published {{ documentName }}": "Published {{ documentName }}",

View File

@@ -0,0 +1,29 @@
interface DocumentInterface {
emoji?: string | null;
title: string;
text: string;
}
export default class MarkdownHelper {
/**
* Returns the document as cleaned Markdown for export.
*
* @param document The document or revision to convert
* @returns The document title and content as a Markdown string
*/
static toMarkdown(document: DocumentInterface) {
const text = document.text
.replace(/\n\\\n/g, "\n\n")
.replace(/“/g, '"')
.replace(/”/g, '"')
.replace(//g, "'")
.replace(//g, "'")
.trim();
const title = `${document.emoji ? document.emoji + " " : ""}${
document.title
}`;
return `# ${title}\n\n${text}`;
}
}