Embed another page's LIVE content into a host page (it updates when the source
changes, not a static copy). A page can be flagged a template for discovery in
the picker; any accessible page can be embedded.
Server:
- migrations: pages.is_template (+ partial index) and page_template_references
(whole-page back-refs); db.d.ts/entity types hand-merged (db.d.ts is curated).
- POST /pages/toggle-template (CASL Edit) flips is_template; is_template is
returned by findById + the sidebar tree select so the tree menu label
reflects state. Search suggestions gain an onlyTemplates filter for the picker.
- POST /pages/template/lookup ({sourcePageIds[]}, <=50): returns each accessible
source's {title, icon, slugId, content, sourceUpdatedAt} with comment marks
stripped (same access path as transclusion: filterViewerAccessiblePageIds;
inaccessible -> no_access, missing -> not_found; error path -> not_found, never
raw content).
- reference sync (collectPageEmbedsFromPmJson + syncPageTemplateReferences) on
the Yjs save hook; duplicatePage remaps pageEmbed.sourcePageId + inserts refs.
Known MVP gap: REST content updates don't resync refs (lookup uses in-doc ids).
Client:
- pageEmbed node (editor-ext, registered in BOTH client + server schemas);
read-only NodeView with a batching lookup; '/Embed page' slash + template
picker (self-embed prevented); 'Make/Unset template' in the tree node menu.
- Cycle guard: an ancestry-chain context + depth cap (5) render a 'circular
embed' placeholder instead of recursing.
- Public shares show a placeholder (no public lookup in MVP).
MVP excludes (follow-ups): public-share lookup, unsync->static copy, server-side
expansion for export/RAG, MCP schema mirror, point-in-time snapshots.
Implements docs/page-templates-plan.md (MVP, variant A).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds an htmlEmbed block node that renders and executes raw HTML/CSS/JS in the
wiki origin (e.g. an analytics tracker) — the owner-chosen variant C. Because
this is stored-XSS by design, only workspace admins/owners may get such a node
persisted; everyone executes it when reading.
- Node (editor-ext): htmlEmbed atom/isolating block; source stored base64 in
data-source for lossless HTML<->JSON round-trip. renderHTML emits only the
encoded marker (never inlines raw markup), so generateHTML/export/search are
not themselves injection vectors. Registered in BOTH client extensions and
server tiptapExtensions. Markdown round-trip via an <!--html-embed:b64-->
comment (turndown) + a marked rule.
- Client NodeView: injects source and re-creates <script> elements so they
actually run; edit modal; renders in read-only/share too. Slash item is
admin-gated (adminOnly filtered by the user's workspace role).
- SERVER ENFORCEMENT (the real control — UI gating alone is insufficient):
stripHtmlEmbedNodes() removes htmlEmbed from any document persisted by a
non-admin, applied at every write path that introduces content from an
untrusted author: collab onStoreDocument, REST/MCP/AI updatePageContent,
single-file import, zip/multi-file import, page duplication, and transclusion
unsync. Page restore introduces no new content. Public share/readonly viewers
render fetched (already-stripped) content and do NOT open a collab socket, so
the only residual is a transient broadcast window to concurrent authenticated
editors (documented).
Implements docs/arbitrary-html-embed-plan.md (variant C).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* autojoiner
* fix marked
* return clipboardTextSerializer as markdown
* fix clipboardTextSerializer for single lines
* cleanup two preceeding spaces in ordered lists item
* fix extra paragraph in task list
* don't zip sinple page exports
The upstream TipTap Code extension input rule regex /(^|[^`])`([^`]+)`(?!`)$/
uses a capture group (^|[^`]) that includes the character preceding the
opening backtick in the full match. When markInputRule processes this,
it deletes everything from the match start to the code content, which
removes that preceding character along with the backtick delimiters.
For example, typing foo(`bar` would result in foo`bar` (formatted)
instead of the expected foo(`bar` (formatted) — the ( is lost.
Fix: disable the built-in Code extension from StarterKit and register it
separately with a corrected regex that uses a lookbehind assertion
(?:^|(?<=[^`])) instead of a capture group. The lookbehind asserts the
preceding character without including it in the match, so markInputRule
only deletes the backtick delimiters.
Functionally tested on Firefox and Chrome.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: new image menu
* switch to resizable side handles
* use pixels
* refactor excalidraw and drawio menu
* support image resize undo
* video resize
* callout menu refresh
* refresh table menus
* fix color scheme
* fix: patch @tiptap/core ResizableNodeView to prevent resize sticking after mouseup
* feat: columns
* notes callout
* focus on first column
* capture tab key in column
* fix print
* hide columns menu when some nodes are focused
* fix print
* fix columns
* selective placeholder
* fix blockquote
* quote
* fix callout in columns
* feat: add heading extension with unique ID support and scroll functionality
* Added unique id for heading
* remove baseUrl heading storage
* move heading to extensions package
* WIP
* support anchors in mentions
* enhance scrolling functionality
* nodeId function
* fix nanoid import
* Bring unique-id extension local
* fixes
* fix internal link scroll in public pages
* add unique id server side
* rename mention anchor to anchorId
* capture first anchorId on paste
---------
Co-authored-by: Romik <40670677+RomikMakavana@users.noreply.github.com>
* #1196/feat: add text background highlight
* unify text color
* dark mode support
* unify text color and highlight
* dark mode support for color selector trigger
* fix see through in color selector dark mode
* fix selection highlight in dark mode
* brown color
* clean up
---------
Co-authored-by: sanua356 <sanek.pankratov356@gmail.com>
* chore: add dev container
* feat: add drag handle when hovering cell
* feat: add column drag and drop
* feat: add support for row drag and drop
* refactor: extract preview controllers
* fix: hover issue
* refactor: add handle controller
* chore: f
* chore: remove log
* chore: remove dev files
* feat: hide other drop indicators when table dnd working
* feat: add auto scroll and bug fix
* chore: f
* fix: firefox
- Support multiple content types in table cells and headers: paragraphs, headings, lists (bullet/ordered/task), blockquotes, callouts, images, videos, attachments, math blocks, toggles, and code blocks
- Add custom table extension with smart Tab key handling for list indentation within tables
- Preserve default table navigation when not in lists
* feat: add toggle header cell button to table cell menu
Added ability to toggle header cells directly from the table cell menu. This enhancement includes:
- New toggle header cell button with IconTableRow icon
- Consistent UI/UX with existing table menu patterns
- Proper internationalization support
* fix: typo in aria-label for toggle header cell button
* feat: add table cell background color picker
- Extended TableCell and TableHeader to support backgroundColor attribute
- Created TableBackgroundColor component with 21 color options
- Integrated color picker into table cell menu using Mantine UI
- Added support for both regular cells and header cells
- Updated imports to use custom TableHeader from @docmost/editor-ext
* feat: add text alignment to table cell menu
- Created TableTextAlignment component with left, center, and right alignment options
- Integrated alignment selector into table cell menu
- Shows current alignment icon in the button
- Displays checkmark next to active alignment in dropdown
* background colors
* table background color in dark mode
* add bg color name
* rename color attribute
* increase minimum table width
* feat: page find and replace
* * Refactor search and replace directory
* bugfix scroll
* Fix search and replace functionality for macOS and improve UX
- Fixed cmd+f shortcut to work on macOS (using 'Mod' key instead of 'Control')
- Added search functionality to title editor
- Fixed "Not found" message showing when search term is empty
- Fixed tooltip error when clicking replace button
- Changed replace button from icon to text for consistency
- Reduced width of search input fields for better UI
- Fixed result index after replace operation to prevent out-of-bounds error
- Added missing translation strings for search and replace dialog
- Updated tooltip to show platform-specific shortcuts (⌘F on Mac, Ctrl-F on others)
* Hide replace functionality for users with view-only permissions
- Added editable prop to SearchAndReplaceDialog component
- Pass editable state from PageEditor to SearchAndReplaceDialog
- Conditionally render replace button based on edit permissions
- Hide replace input section for view-only users
- Disable Alt+R shortcut when user lacks edit permissions
* Fix search dialog not closing properly when navigating away
- Clear all state (search text, replace text) when closing dialog
- Reset replace button visibility state on close
- Clear editor search term to remove highlights
- Ensure dialog closes properly when route changes
* fix: preserve text marks (comments, etc.) when replacing text in search and replace
- Collect all marks that span the text being replaced using nodesBetween
- Apply collected marks to the replacement text to maintain formatting
- Fixes issue where comment marks were being removed during text replacement
* ignore type error
---------
Co-authored-by: Philipinho <16838612+Philipinho@users.noreply.github.com>
* Work on mentions
* fix: properly parse page slug
* fix editor suggestion bugs
* mentions must start with whitespace
* add icon to page mention render
* feat: backlinks - WIP
* UI - WIP
* permissions check
* use FTS for page suggestion
* cleanup
* WIP
* page title fallback
* feat: handle internal link paste
* link styling
* WIP
* Switch back to LIKE operator for search suggestion
* WIP
* scope to workspaceId
* still create link for pages not found
* select necessary columns
* cleanups
* feat: support i18n
* feat: wip support i18n
* feat: complete space translation
* feat: complete page translation
* feat: update space translation
* feat: update workspace translation
* feat: update group translation
* feat: update workspace translation
* feat: update page translation
* feat: update user translation
* chore: update pnpm-lock
* feat: add query translation
* refactor: merge to single file
* chore: remove necessary code
* feat: save language to BE
* fix: only load current language
* feat: save language to locale column
* fix: cleanups
* add language menu to preferences page
* new translations
* translate editor
* Translate editor placeholders
* translate space selection component
---------
Co-authored-by: Philip Okugbe <phil@docmost.com>
Co-authored-by: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
* update tiptap version
* excalidraw init
* cleanup
* better file handling and other fixes
* use different modal to fix excalidraw cursor position issue
* see https://github.com/excalidraw/excalidraw/issues/7312
* fix websocket in vite dev mode
* WIP
* add align attribute
* fix table
* menu icons
* Render image in excalidraw html
* add size to custom SVG components
* rewrite undefined font urls
* reduce space between list items
* reduce spacing
* Make inline code readable in dark mode
* Disable spellcheck in code
* fix numbered list in toggle block