From aa5d52ad3e1e17c03506c0325020c7ee90dcf90f Mon Sep 17 00:00:00 2001 From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com> Date: Sat, 20 Jun 2026 14:22:54 +0100 Subject: [PATCH 1/2] feat(editor): add /time slash command to insert current time (#2290) --- .../public/locales/en-US/translation.json | 2 ++ .../components/slash-menu/menu-items.ts | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json index a182138ac..aa20b9144 100644 --- a/apps/client/public/locales/en-US/translation.json +++ b/apps/client/public/locales/en-US/translation.json @@ -398,6 +398,8 @@ "Insert mermaid diagram": "Insert mermaid diagram", "Insert and design Drawio diagrams": "Insert and design Drawio diagrams", "Insert current date": "Insert current date", + "Time": "Time", + "Insert current time": "Insert current time", "Draw and sketch excalidraw diagrams": "Draw and sketch excalidraw diagrams", "Multiple": "Multiple", "Turn into": "Turn into", diff --git a/apps/client/src/features/editor/components/slash-menu/menu-items.ts b/apps/client/src/features/editor/components/slash-menu/menu-items.ts index 1f05dc62f..a85f4a710 100644 --- a/apps/client/src/features/editor/components/slash-menu/menu-items.ts +++ b/apps/client/src/features/editor/components/slash-menu/menu-items.ts @@ -21,6 +21,7 @@ import { IconMenu4, IconPageBreak, IconCalendar, + IconClock, IconAppWindow, IconSitemap, IconColumns3, @@ -474,6 +475,25 @@ const CommandGroups: SlashMenuGroupedItemsType = { .run(); }, }, + { + title: "Time", + description: "Insert current time", + searchTerms: ["time", "now", "clock"], + icon: IconClock, + command: ({ editor, range }: CommandProps) => { + const currentTime = new Date().toLocaleTimeString(i18n.language, { + hour: "numeric", + minute: "numeric", + }); + + editor + .chain() + .focus() + .deleteRange(range) + .insertContent(currentTime) + .run(); + }, + }, { title: "Status", description: "Insert inline status badge.", From 510199cf040ea6b987061b47a37d4d617873640b Mon Sep 17 00:00:00 2001 From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com> Date: Sat, 20 Jun 2026 14:23:56 +0100 Subject: [PATCH 2/2] feat(ee): docx word export (#2294) * vendorize prosemirror-docx - wip * feat(ee): docx word export * sync --- .../src/components/common/export-modal.tsx | 90 +- apps/client/src/ee/features.ts | 1 + .../features/page/services/page-service.ts | 19 + .../src/features/page/types/page.types.ts | 1 + apps/client/src/lib/api-client.ts | 6 +- apps/client/tsconfig.json | 4 +- apps/server/package.json | 41 +- apps/server/src/common/features.ts | 1 + apps/server/src/ee | 2 +- package.json | 43 +- packages/editor-ext/package.json | 1 + packages/editor-ext/src/index.ts | 4 + .../src/lib/prosemirror-docx/README.md | 167 ++++ .../src/lib/prosemirror-docx/index.ts | 24 + .../src/lib/prosemirror-docx/numbering.ts | 47 + .../src/lib/prosemirror-docx/schema.ts | 250 +++++ .../src/lib/prosemirror-docx/serializer.ts | 925 ++++++++++++++++++ .../src/lib/prosemirror-docx/types.ts | 34 + .../src/lib/prosemirror-docx/utils.ts | 91 ++ pnpm-lock.yaml | 123 ++- 20 files changed, 1771 insertions(+), 103 deletions(-) create mode 100644 packages/editor-ext/src/lib/prosemirror-docx/README.md create mode 100644 packages/editor-ext/src/lib/prosemirror-docx/index.ts create mode 100644 packages/editor-ext/src/lib/prosemirror-docx/numbering.ts create mode 100644 packages/editor-ext/src/lib/prosemirror-docx/schema.ts create mode 100644 packages/editor-ext/src/lib/prosemirror-docx/serializer.ts create mode 100644 packages/editor-ext/src/lib/prosemirror-docx/types.ts create mode 100644 packages/editor-ext/src/lib/prosemirror-docx/utils.ts diff --git a/apps/client/src/components/common/export-modal.tsx b/apps/client/src/components/common/export-modal.tsx index 2a83debf9..bbd58b64d 100644 --- a/apps/client/src/components/common/export-modal.tsx +++ b/apps/client/src/components/common/export-modal.tsx @@ -6,13 +6,21 @@ import { Select, Switch, Divider, + Tooltip, + Badge, } from "@mantine/core"; -import { exportPage } from "@/features/page/services/page-service.ts"; +import { + exportPage, + exportPageToDocx, +} from "@/features/page/services/page-service.ts"; import { useState } from "react"; import { ExportFormat } from "@/features/page/types/page.types.ts"; import { notifications } from "@mantine/notifications"; import { exportSpace } from "@/features/space/services/space-service"; import { useTranslation } from "react-i18next"; +import { Feature } from "@/ee/features"; +import { useHasFeature } from "@/ee/hooks/use-feature"; +import { useUpgradeLabel } from "@/ee/hooks/use-upgrade-label"; interface ExportModalProps { id: string; @@ -32,17 +40,25 @@ export default function ExportModal({ const [includeAttachments, setIncludeAttachments] = useState(false); const [isExporting, setIsExporting] = useState(false); const { t } = useTranslation(); + const upgradeLabel = useUpgradeLabel(); + const isDocx = format === ExportFormat.Docx; + const docxEntitled = useHasFeature(Feature.DOCX_EXPORT); + const blockedByLicense = isDocx && !docxEntitled; const handleExport = async () => { setIsExporting(true); try { if (type === "page") { - await exportPage({ - pageId: id, - format, - includeChildren, - includeAttachments, - }); + if (format === ExportFormat.Docx) { + await exportPageToDocx({ pageId: id }); + } else { + await exportPage({ + pageId: id, + format, + includeChildren, + includeAttachments, + }); + } } if (type === "space") { await exportSpace({ spaceId: id, format, includeAttachments }); @@ -88,10 +104,15 @@ export default function ExportModal({
{t("Format")}
- + - {type === "page" && ( + {type === "page" && !isDocx && ( <> @@ -143,7 +164,16 @@ export default function ExportModal({ - + + + @@ -154,23 +184,49 @@ export default function ExportModal({ interface ExportFormatSelection { format: ExportFormat; onChange: (value: string) => void; + includeDocx?: boolean; + docxEntitled?: boolean; } -function ExportFormatSelection({ format, onChange }: ExportFormatSelection) { +function ExportFormatSelection({ + format, + onChange, + includeDocx, + docxEntitled, +}: ExportFormatSelection) { const { t } = useTranslation(); + const data = [ + { value: "markdown", label: "Markdown" }, + { value: "html", label: "HTML" }, + ...(includeDocx + ? [{ value: "docx", label: "Word (.docx)", disabled: !docxEntitled }] + : []), + ]; + return (