feat(export): add export loading state and copy as markdown (#1867)

* feat: add loading state to export

* feat: copy as markdown

* preserve taskList comment
This commit is contained in:
Philip Okugbe
2026-01-24 23:30:17 +00:00
committed by GitHub
parent 657fdf8cb7
commit aa6a046aa6
10 changed files with 89 additions and 34 deletions
@@ -29,6 +29,7 @@
"Choose your preferred interface language.": "Choose your preferred interface language.",
"Choose your preferred page width.": "Choose your preferred page width.",
"Confirm": "Confirm",
"Copy as Markdown": "Copy as Markdown",
"Copy link": "Copy link",
"Create": "Create",
"Create group": "Create group",
@@ -253,6 +254,7 @@
"Export failed:": "Export failed:",
"export error": "export error",
"Export page": "Export page",
"Export successful": "Export successful",
"Export space": "Export space",
"Export {{type}}": "Export {{type}}",
"File exceeds the {{limit}} attachment limit": "File exceeds the {{limit}} attachment limit",
@@ -30,9 +30,11 @@ export default function ExportModal({
const [format, setFormat] = useState<ExportFormat>(ExportFormat.Markdown);
const [includeChildren, setIncludeChildren] = useState<boolean>(false);
const [includeAttachments, setIncludeAttachments] = useState<boolean>(false);
const [isExporting, setIsExporting] = useState<boolean>(false);
const { t } = useTranslation();
const handleExport = async () => {
setIsExporting(true);
try {
if (type === "page") {
await exportPage({
@@ -45,6 +47,9 @@ export default function ExportModal({
if (type === "space") {
await exportSpace({ spaceId: id, format, includeAttachments });
}
notifications.show({
message: t("Export successful"),
});
onClose();
} catch (err) {
notifications.show({
@@ -52,6 +57,8 @@ export default function ExportModal({
color: "red",
});
console.error("export error", err);
} finally {
setIsExporting(false);
}
};
@@ -136,7 +143,7 @@ export default function ExportModal({
<Button onClick={onClose} variant="default">
{t("Cancel")}
</Button>
<Button onClick={handleExport}>{t("Export")}</Button>
<Button onClick={handleExport} loading={isExporting}>{t("Export")}</Button>
</Group>
</Modal.Body>
</Modal.Content>
@@ -7,6 +7,7 @@ import {
IconHistory,
IconLink,
IconList,
IconMarkdown,
IconMessage,
IconPrinter,
IconTrash,
@@ -28,6 +29,7 @@ import { useDeletePageModal } from "@/features/page/hooks/use-delete-page-modal.
import { PageWidthToggle } from "@/features/user/components/page-width-pref.tsx";
import { Trans, useTranslation } from "react-i18next";
import ExportModal from "@/components/common/export-modal";
import { htmlToMarkdown } from "@docmost/editor-ext";
import {
pageEditorAtom,
yjsConnectionStatusAtom,
@@ -129,6 +131,15 @@ function PageActionMenu({ readOnly }: PageActionMenuProps) {
notifications.show({ message: t("Link copied") });
};
const handleCopyAsMarkdown = () => {
if (!pageEditor) return;
const html = pageEditor.getHTML();
const markdown = htmlToMarkdown(html);
const title = page?.title ? `# ${page.title}\n\n` : "";
clipboard.copy(`${title}${markdown}`);
notifications.show({ message: t("Copied") });
};
const handlePrint = () => {
setTimeout(() => {
window.print();
@@ -166,6 +177,13 @@ function PageActionMenu({ readOnly }: PageActionMenuProps) {
>
{t("Copy link")}
</Menu.Item>
<Menu.Item
leftSection={<IconMarkdown size={16} />}
onClick={handleCopyAsMarkdown}
>
{t("Copy as Markdown")}
</Menu.Item>
<Menu.Divider />
<Menu.Item leftSection={<IconArrowsHorizontal size={16} />}>