From c354bc7be32e19ed783491e04e562f80bada96eb Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Sat, 6 Dec 2025 22:08:12 +0000
Subject: [PATCH] feat: page break command
---
.../components/slash-menu/menu-items.ts | 14 +++++++++++++
.../features/editor/extensions/extensions.ts | 3 +++
.../src/features/editor/styles/core.css | 15 ++++++++-----
.../src/features/editor/styles/print.css | 6 ++++++
.../src/collaboration/collaboration.util.ts | 3 +++
package.json | 1 +
packages/editor-ext/src/index.ts | 1 +
packages/editor-ext/src/lib/hr.ts | 21 +++++++++++++++++++
pnpm-lock.yaml | 3 +++
9 files changed, 62 insertions(+), 5 deletions(-)
create mode 100644 packages/editor-ext/src/lib/hr.ts
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 f56d7f04..14f26b9b 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
@@ -20,6 +20,7 @@ import {
IconCalendar,
IconAppWindow,
IconSitemap,
+ IconPageBreak,
} from "@tabler/icons-react";
import {
CommandProps,
@@ -153,6 +154,19 @@ const CommandGroups: SlashMenuGroupedItemsType = {
command: ({ editor, range }: CommandProps) =>
editor.chain().focus().deleteRange(range).setHorizontalRule().run(),
},
+ {
+ title: "Page break",
+ description: "Insert page break",
+ searchTerms: ["page break", "hr"],
+ icon: IconPageBreak,
+ command: ({ editor, range }: CommandProps) =>
+ editor
+ .chain()
+ .focus()
+ .deleteRange(range)
+ .insertContent('
')
+ .run(),
+ },
{
title: "Image",
description: "Upload any image from your device.",
diff --git a/apps/client/src/features/editor/extensions/extensions.ts b/apps/client/src/features/editor/extensions/extensions.ts
index ecdea2e7..2739fbca 100644
--- a/apps/client/src/features/editor/extensions/extensions.ts
+++ b/apps/client/src/features/editor/extensions/extensions.ts
@@ -46,6 +46,7 @@ import {
Heading,
Highlight,
UniqueID,
+ HorizontalRule,
} from "@docmost/editor-ext";
import {
randomElement,
@@ -108,7 +109,9 @@ export const mainExtensions = [
spellcheck: false,
},
},
+ horizontalRule: false,
}),
+ HorizontalRule,
Heading,
UniqueID.configure({
types: ["heading", "paragraph"],
diff --git a/apps/client/src/features/editor/styles/core.css b/apps/client/src/features/editor/styles/core.css
index 0aed878e..77443102 100644
--- a/apps/client/src/features/editor/styles/core.css
+++ b/apps/client/src/features/editor/styles/core.css
@@ -110,6 +110,14 @@
border-top: 1px solid #68cef8;
}
+ hr[data-type="pagebreak"] {
+ border-top: 1px dashed var(--mantine-color-dark-2) !important;
+ }
+
+ .ProseMirror[contenteditable="false"] hr[data-type="pagebreak"] {
+ display: none !important;
+ }
+
.ProseMirror-selectednode {
outline: 2px solid #70cff8;
}
@@ -186,7 +194,6 @@
margin-left: auto;
margin-right: auto;
}
-
}
.ProseMirror > h1,
@@ -195,13 +202,11 @@
.ProseMirror > h4,
.ProseMirror > h5,
.ProseMirror > h6 {
-
> .link-btn {
cursor: pointer;
position: relative;
-
}
-
+
> .link-btn > .link-btn-content {
opacity: 0;
position: absolute;
@@ -213,7 +218,7 @@
justify-content: center;
flex-direction: column;
}
-
+
&:hover > .link-btn > .link-btn-content {
opacity: 1;
}
diff --git a/apps/client/src/features/editor/styles/print.css b/apps/client/src/features/editor/styles/print.css
index c63e376b..de71700d 100644
--- a/apps/client/src/features/editor/styles/print.css
+++ b/apps/client/src/features/editor/styles/print.css
@@ -20,4 +20,10 @@
.tableWrapper {
overflow: hidden !important;
}
+
+ hr[data-type="pagebreak"] {
+ break-before: always;
+ page-break-before: always;
+ visibility: hidden;
+ }
}
diff --git a/apps/server/src/collaboration/collaboration.util.ts b/apps/server/src/collaboration/collaboration.util.ts
index 06133c3f..5d31b1af 100644
--- a/apps/server/src/collaboration/collaboration.util.ts
+++ b/apps/server/src/collaboration/collaboration.util.ts
@@ -36,6 +36,7 @@ import {
Highlight,
UniqueID,
addUniqueIdsToDoc,
+ HorizontalRule,
} from '@docmost/editor-ext';
import { generateText, getSchema, JSONContent } from '@tiptap/core';
import { generateHTML, generateJSON } from '../common/helpers/prosemirror/html';
@@ -48,7 +49,9 @@ export const tiptapExtensions = [
StarterKit.configure({
codeBlock: false,
heading: false,
+ horizontalRule: false,
}),
+ HorizontalRule,
Heading,
UniqueID.configure({
types: ['heading', 'paragraph'],
diff --git a/package.json b/package.json
index 30d29a58..a52d0b86 100644
--- a/package.json
+++ b/package.json
@@ -38,6 +38,7 @@
"@tiptap/extension-heading": "2.27.1",
"@tiptap/extension-highlight": "2.27.1",
"@tiptap/extension-history": "2.27.1",
+ "@tiptap/extension-horizontal-rule": "2.27.1",
"@tiptap/extension-image": "2.27.1",
"@tiptap/extension-link": "2.27.1",
"@tiptap/extension-list-item": "2.27.1",
diff --git a/packages/editor-ext/src/index.ts b/packages/editor-ext/src/index.ts
index 3ff99083..c1ce3503 100644
--- a/packages/editor-ext/src/index.ts
+++ b/packages/editor-ext/src/index.ts
@@ -23,3 +23,4 @@ export * from "./lib/subpages";
export * from "./lib/highlight";
export * from "./lib/heading/heading";
export * from "./lib/unique-id";
+export * from "./lib/hr";
diff --git a/packages/editor-ext/src/lib/hr.ts b/packages/editor-ext/src/lib/hr.ts
new file mode 100644
index 00000000..fe32f111
--- /dev/null
+++ b/packages/editor-ext/src/lib/hr.ts
@@ -0,0 +1,21 @@
+import { HorizontalRule as TiptapHorizontalRule } from "@tiptap/extension-horizontal-rule";
+
+export type HorizontalRuleType = "pageBreak";
+
+export const HorizontalRule = TiptapHorizontalRule.extend({
+ addAttributes() {
+ return {
+ type: {
+ default: null,
+ parseHTML: (element) => element.getAttribute("data-type"),
+ renderHTML: (attributes) => {
+ if (attributes.type) {
+ return {
+ "data-type": attributes.type,
+ };
+ }
+ },
+ },
+ };
+ },
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e04b7d17..fb148502 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -77,6 +77,9 @@ importers:
'@tiptap/extension-history':
specifier: 2.27.1
version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
+ '@tiptap/extension-horizontal-rule':
+ specifier: 2.27.1
+ version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
'@tiptap/extension-image':
specifier: 2.27.1
version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))