From 7f81b839550d822d48e23fae3574acc19afd8776 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 20 Nov 2025 20:13:20 +0200 Subject: [PATCH 01/16] chore(print/list): get note titles to render --- .../src/widgets/collections/NoteList.tsx | 8 ++++++-- .../collections/legacy/ListOrGridView.tsx | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/client/src/widgets/collections/NoteList.tsx b/apps/client/src/widgets/collections/NoteList.tsx index 1d5a96810..860886a0f 100644 --- a/apps/client/src/widgets/collections/NoteList.tsx +++ b/apps/client/src/widgets/collections/NoteList.tsx @@ -2,7 +2,7 @@ import { allViewTypes, ViewModeMedia, ViewModeProps, ViewTypeOptions } from "./i import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useTriliumEvent } from "../react/hooks"; import FNote from "../../entities/fnote"; import "./NoteList.css"; -import { ListView, GridView } from "./legacy/ListOrGridView"; +import { ListView, GridView, ListPrintView } from "./legacy/ListOrGridView"; import { useEffect, useRef, useState } from "preact/hooks"; import GeoView from "./geomap"; import ViewModeStorage from "./view_mode_storage"; @@ -103,7 +103,11 @@ export function CustomNoteList({ note, viewType, isEnabled: shouldEnable, notePa function getComponentByViewType(viewType: ViewTypeOptions, props: ViewModeProps) { switch (viewType) { case "list": - return ; + if (props.media !== "print") { + return ; + } else { + return ; + } case "grid": return ; case "geoMap": diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx index ef37b6685..db5a88593 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx @@ -11,6 +11,7 @@ import tree from "../../../services/tree"; import link from "../../../services/link"; import { t } from "../../../services/i18n"; import attribute_renderer from "../../../services/attribute_renderer"; +import froca from "../../../services/froca"; export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { const [ isExpanded ] = useNoteLabelBoolean(note, "expanded"); @@ -34,6 +35,25 @@ export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens } ); } +export function ListPrintView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { + const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); + const [ notes, setNotes ] = useState(); + + useEffect(() => { + froca.getNotes(noteIds).then(setNotes); + }, [noteIds]); + + return ( +
+ +
+ ); +} + export function GridView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); const { pageNotes, ...pagination } = usePagination(note, noteIds); From 73e7fa0f85ede19c2ec8626f7c4bb7a6194b4793 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 20 Nov 2025 20:15:44 +0200 Subject: [PATCH 02/16] chore(print/list): get note content to render --- .../src/widgets/collections/legacy/ListOrGridView.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx index db5a88593..55415e7c1 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx @@ -47,7 +47,13 @@ export function ListPrintView({ note, noteIds: unfilteredNoteIds, highlightedTok
From c95cb79672e7c1a49c51013bd50bf39aa2738b6d Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 20 Nov 2025 20:17:20 +0200 Subject: [PATCH 03/16] chore(print/list): enable print dialog --- .../src/widgets/collections/legacy/ListOrGridView.tsx | 8 +++++++- apps/client/src/widgets/ribbon/NoteActions.tsx | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx index 55415e7c1..80087f584 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx @@ -35,7 +35,7 @@ export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens } ); } -export function ListPrintView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { +export function ListPrintView({ note, noteIds: unfilteredNoteIds, highlightedTokens, onReady }: ViewModeProps<{}>) { const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); const [ notes, setNotes ] = useState(); @@ -43,6 +43,12 @@ export function ListPrintView({ note, noteIds: unfilteredNoteIds, highlightedTok froca.getNotes(noteIds).then(setNotes); }, [noteIds]); + useEffect(() => { + if (notes && onReady) { + onReady(); + } + }, [ notes, onReady ]); + return (
From f4d6e98d61127038662bf6941b83900e788ef656 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 20 Nov 2025 21:06:25 +0200 Subject: [PATCH 12/16] feat(print/list): rewrite links --- apps/client/src/services/link.ts | 44 ++++++++++--------- .../collections/legacy/ListPrintView.tsx | 12 +++++ 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/apps/client/src/services/link.ts b/apps/client/src/services/link.ts index 9af93b313..a596e7136 100644 --- a/apps/client/src/services/link.ts +++ b/apps/client/src/services/link.ts @@ -467,28 +467,30 @@ function getReferenceLinkTitleSync(href: string) { } } -// TODO: Check why the event is not supported. -//@ts-ignore -$(document).on("click", "a", goToLink); -// TODO: Check why the event is not supported. -//@ts-ignore -$(document).on("auxclick", "a", goToLink); // to handle the middle button -// TODO: Check why the event is not supported. -//@ts-ignore -$(document).on("contextmenu", "a", linkContextMenu); -// TODO: Check why the event is not supported. -//@ts-ignore -$(document).on("dblclick", "a", goToLink); +if (glob.device !== "print") { + // TODO: Check why the event is not supported. + //@ts-ignore + $(document).on("click", "a", goToLink); + // TODO: Check why the event is not supported. + //@ts-ignore + $(document).on("auxclick", "a", goToLink); // to handle the middle button + // TODO: Check why the event is not supported. + //@ts-ignore + $(document).on("contextmenu", "a", linkContextMenu); + // TODO: Check why the event is not supported. + //@ts-ignore + $(document).on("dblclick", "a", goToLink); -$(document).on("mousedown", "a", (e) => { - if (e.which === 2) { - // prevent paste on middle click - // https://github.com/zadam/trilium/issues/2995 - // https://developer.mozilla.org/en-US/docs/Web/API/Element/auxclick_event#preventing_default_actions - e.preventDefault(); - return false; - } -}); + $(document).on("mousedown", "a", (e) => { + if (e.which === 2) { + // prevent paste on middle click + // https://github.com/zadam/trilium/issues/2995 + // https://developer.mozilla.org/en-US/docs/Web/API/Element/auxclick_event#preventing_default_actions + e.preventDefault(); + return false; + } + }); +} export default { getNotePathFromUrl, diff --git a/apps/client/src/widgets/collections/legacy/ListPrintView.tsx b/apps/client/src/widgets/collections/legacy/ListPrintView.tsx index 07750a87b..d4fa36133 100644 --- a/apps/client/src/widgets/collections/legacy/ListPrintView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListPrintView.tsx @@ -29,6 +29,7 @@ export function ListPrintView({ note, noteIds: unfilteredNoteIds, onReady }: Vie insertPageTitle(contentEl, note.title); rewriteHeadings(contentEl, depth); + rewriteLinks(contentEl); notesWithContent.push({ note, content: { __html: contentEl.innerHTML } }); @@ -84,3 +85,14 @@ function rewriteHeadings(contentEl: HTMLElement, depth: number) { headingEl.replaceWith(newHeadingEl); } } + +function rewriteLinks(contentEl: HTMLElement) { + const linkEls = contentEl.querySelectorAll("a"); + for (const linkEl of linkEls) { + const href = linkEl.getAttribute("href"); + if (href && href.startsWith("#root/")) { + const noteId = href.split("/").at(-1); + linkEl.setAttribute("href", `#note-${noteId}`); + } + } +} From 25a51a71a0df0ca9666576c0a12709630ae0cb10 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 20 Nov 2025 21:20:24 +0200 Subject: [PATCH 13/16] feat(print/list): unlink references to notes that are not printed --- .../collections/legacy/ListPrintView.tsx | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/apps/client/src/widgets/collections/legacy/ListPrintView.tsx b/apps/client/src/widgets/collections/legacy/ListPrintView.tsx index d4fa36133..a2b9d5319 100644 --- a/apps/client/src/widgets/collections/legacy/ListPrintView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListPrintView.tsx @@ -8,11 +8,12 @@ import { useFilteredNoteIds } from "./utils"; interface NotesWithContent { note: FNote; - content: { __html: string }; + contentEl: HTMLElement; } export function ListPrintView({ note, noteIds: unfilteredNoteIds, onReady }: ViewModeProps<{}>) { const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); + const noteIdsSet = new Set(); const [ notesWithContent, setNotesWithContent ] = useState(); useLayoutEffect(() => { @@ -29,9 +30,8 @@ export function ListPrintView({ note, noteIds: unfilteredNoteIds, onReady }: Vie insertPageTitle(contentEl, note.title); rewriteHeadings(contentEl, depth); - rewriteLinks(contentEl); - - notesWithContent.push({ note, content: { __html: contentEl.innerHTML } }); + noteIdsSet.add(note.noteId); + notesWithContent.push({ note, contentEl }); if (note.hasChildren()) { const imageLinks = note.getRelations("imageLink"); @@ -46,6 +46,12 @@ export function ListPrintView({ note, noteIds: unfilteredNoteIds, onReady }: Vie for (const note of notes) { await processNote(note, 1); } + + // After all notes are processed, rewrite links + for (const { contentEl } of notesWithContent) { + rewriteLinks(contentEl, noteIdsSet); + } + setNotesWithContent(notesWithContent); }); }, [noteIds]); @@ -61,8 +67,8 @@ export function ListPrintView({ note, noteIds: unfilteredNoteIds, onReady }: Vie
@@ -86,13 +92,21 @@ function rewriteHeadings(contentEl: HTMLElement, depth: number) { } } -function rewriteLinks(contentEl: HTMLElement) { +function rewriteLinks(contentEl: HTMLElement, noteIdsSet: Set) { const linkEls = contentEl.querySelectorAll("a"); for (const linkEl of linkEls) { const href = linkEl.getAttribute("href"); if (href && href.startsWith("#root/")) { const noteId = href.split("/").at(-1); - linkEl.setAttribute("href", `#note-${noteId}`); + + if (noteId && noteIdsSet.has(noteId)) { + linkEl.setAttribute("href", `#note-${noteId}`); + } else { + // Link to note not in the print view, remove link but keep text + const spanEl = document.createElement("span"); + spanEl.innerHTML = linkEl.innerHTML; + linkEl.replaceWith(spanEl); + } } } } From 8b4e76832f3bb33ee705b0e409f899c0e5a32e3f Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 20 Nov 2025 21:28:55 +0200 Subject: [PATCH 14/16] docs(user): update documentation regarding printing multiple notes --- .../Notes/Printing & Exporting as PDF.html | 53 +++++++++++-------- .../User Guide/Collections/List View.html | 17 +++++- .../Custom Widgets/Right pane widget.html | 9 ++-- .../Developer Guide/Documentation.md | 2 +- docs/User Guide/!!!meta.json | 14 +++++ .../Notes/Printing & Exporting as PDF.md | 10 ++++ .../User Guide/Collections/List View.md | 13 ++++- 7 files changed, 88 insertions(+), 30 deletions(-) diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.html index c0cf16ba9..f0c704785 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.html @@ -4,7 +4,6 @@
Screenshot of the note contextual menu indicating the “Export as PDF” option.
-

Printing

This feature allows printing of notes. It works on both the desktop client, but also on the web.

@@ -60,9 +59,9 @@ class="admonition note"> orientation, size. However, there are a few Attributes to adjust some of the settings:

    -
  • To print in landscape mode instead of portrait (useful for big diagrams +
  • To print in landscape mode instead of portrait (useful for big diagrams or slides), add #printLandscape.
  • -
  • By default, the resulting PDF will be in Letter format. It is possible +
  • By default, the resulting PDF will be in Letter format. It is possible to adjust it to another page size via the #printPageSize attribute, with one of the following values: A0, A1, A2, A3, A4, A5, A6, Legal, Letter, Tabloid, Ledger.
@@ -70,15 +69,26 @@ class="admonition note">

These options have no effect when used with the printing feature, since the user-defined settings are used instead.

+

Printing multiple notes

+

Since v0.100.0, it is possible to print more than one note at the time + by using Collections:

+
    +
  1. First create a collection.
  2. +
  3. Configure it to use List View.
  4. +
  5. Print the collection note normally.
  6. +
+

The resulting collection will contain all the children of the collection, + while maintaining the hierarchy.

Keyboard shortcut

It's possible to trigger both printing and export as PDF from the keyboard by going to Keyboard shortcuts in Options and assigning a key combination for:

    -
  • Print Active Note +
  • Print Active Note
  • -
  • Export Active Note as PDF +
  • Export Active Note as PDF

Constraints & limitations

@@ -86,24 +96,24 @@ class="admonition note"> supported when printing, in which case the Print and Export as PDF options will be disabled.

    -
  • For Code notes: +
  • For Code notes:
      -
    • Line numbers are not printed.
    • -
    • Syntax highlighting is enabled, however a default theme (Visual Studio) +
    • Line numbers are not printed.
    • +
    • Syntax highlighting is enabled, however a default theme (Visual Studio) is enforced.
  • -
  • For Collections: +
  • For Collections:
      -
    • Only Presentation is +
    • Only Presentation is currently supported.
    • -
    • We plan to add support for all the collection types at some point.
    • +
    • We plan to add support for all the collection types at some point.
  • -
  • Using Custom app-wide CSS for +
  • Using Custom app-wide CSS for printing is not longer supported, due to a more stable but isolated mechanism.
      -
    • We plan to introduce a new mechanism specifically for a print CSS.
    • +
    • We plan to introduce a new mechanism specifically for a print CSS.
@@ -114,10 +124,10 @@ class="admonition note"> printing.

To do so:

    -
  • Create a CSS code note.
  • -
  • On the note being printed, apply the ~printCss relation to +
  • Create a CSS code note.
  • +
  • On the note being printed, apply the ~printCss relation to point to the newly created CSS code note.
  • -
  • To apply the CSS to multiple notes, consider using inheritable attributes or  +
  • To apply the CSS to multiple notes, consider using inheritable attributes or  Templates.
@@ -128,12 +138,13 @@ class="admonition note"> }

To remark:

    -
  • Multiple CSS notes can be add by using multiple ~printCss relations.
  • -
  • If the note pointing to the printCss doesn't have the right +
  • Multiple CSS notes can be add by using multiple ~printCss relations.
  • +
  • If the note pointing to the printCss doesn't have the right note type or mime type, it will be ignored.
  • -
  • If migrating from a previous version where Custom app-wide CSS, there's no need for @media print {  since - the style-sheet is used only for printing.
  • +
  • If migrating from a previous version where Custom app-wide CSS, there's no need for @media print {  since + the style-sheet is used only for printing.

Under the hood

Both printing and exporting as PDF use the same mechanism: a note is rendered diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections/List View.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections/List View.html index f3e4926b4..64c09e024 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections/List View.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections/List View.html @@ -12,9 +12,22 @@ as a single continuous document.

Interaction

    -
  • Each note can be expanded or collapsed by clicking on the arrow to the +
  • Each note can be expanded or collapsed by clicking on the arrow to the left of the title.
  • -
  • In the Ribbon, +
  • In the Ribbon, in the Collection tab there are options to expand and to collapse all notes easily.
  • +
+

Printing and exporting to PDF

+

Since v0.100.0, list collections can be printed or exported to PDF.

+

A printed list collection will print all the notes in the collection, + in the right order and preserving the full hierarchy.

+

If exported to PDF within the desktop application, there is additional + functionality:

+
    +
  • The table of contents of the PDF will reflect the structure of the notes.
  • +
  • Reference and inline links to other notes within the same hierarchy will + be functional (will jump to the corresponding page). If a link refers to + a note that is not in the printed hierarchy, it will be unlinked.
\ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.html index 393a9a60a..27437786f 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget.html @@ -1,13 +1,12 @@
    -
  • doRender must not be overridden, instead doRenderBody() has +
  • doRender must not be overridden, instead doRenderBody() has to be overridden.
      -
    • doRenderBody can optionally be async.
    • +
    • doRenderBody can optionally be async.
  • -
  • parentWidget() must be set to “rightPane”.
  • -
  • widgetTitle() getter can optionally be overriden, otherwise +
  • parentWidget() must be set to “rightPane”.
  • +
  • widgetTitle() getter can optionally be overriden, otherwise the widget will be displayed as “Untitled widget”.
const template = `<div>Hi</div>`;
 
diff --git a/docs/Developer Guide/Developer Guide/Documentation.md b/docs/Developer Guide/Developer Guide/Documentation.md
index 93ee33d7a..b8eca125b 100644
--- a/docs/Developer Guide/Developer Guide/Documentation.md	
+++ b/docs/Developer Guide/Developer Guide/Documentation.md	
@@ -1,5 +1,5 @@
 # Documentation
-There are multiple types of documentation for Trilium:
+There are multiple types of documentation for Trilium:
 
 *   The _User Guide_ represents the user-facing documentation. This documentation can be browsed by users directly from within Trilium, by pressing F1.
 *   The _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers.
diff --git a/docs/User Guide/!!!meta.json b/docs/User Guide/!!!meta.json
index 91af437e1..7b77cb46a 100644
--- a/docs/User Guide/!!!meta.json	
+++ b/docs/User Guide/!!!meta.json	
@@ -4135,6 +4135,13 @@
                                             "value": "printing-and-pdf-export",
                                             "isInheritable": false,
                                             "position": 110
+                                        },
+                                        {
+                                            "type": "relation",
+                                            "name": "internalLink",
+                                            "value": "mULW0Q3VojwY",
+                                            "isInheritable": false,
+                                            "position": 130
                                         }
                                     ],
                                     "format": "markdown",
@@ -10478,6 +10485,13 @@
                                     "value": "list",
                                     "isInheritable": false,
                                     "position": 30
+                                },
+                                {
+                                    "type": "relation",
+                                    "name": "internalLink",
+                                    "value": "NRnIZmSMc5sj",
+                                    "isInheritable": false,
+                                    "position": 40
                                 }
                             ],
                             "format": "markdown",
diff --git a/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.md b/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.md
index 21fbe12e6..d8cbe4bfa 100644
--- a/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.md	
+++ b/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.md	
@@ -49,6 +49,16 @@ When exporting to PDF, there are no customizable settings such as page orientati
 > [!NOTE]
 > These options have no effect when used with the printing feature, since the user-defined settings are used instead.
 
+## Printing multiple notes
+
+Since v0.100.0, it is possible to print more than one note at the time by using Collections:
+
+1.  First create a collection.
+2.  Configure it to use List View.
+3.  Print the collection note normally.
+
+The resulting collection will contain all the children of the collection, while maintaining the hierarchy.
+
 ## Keyboard shortcut
 
 It's possible to trigger both printing and export as PDF from the keyboard by going to _Keyboard shortcuts_ in Options and assigning a key combination for:
diff --git a/docs/User Guide/User Guide/Collections/List View.md b/docs/User Guide/User Guide/Collections/List View.md
index 76fd15820..86cb59806 100644
--- a/docs/User Guide/User Guide/Collections/List View.md	
+++ b/docs/User Guide/User Guide/Collections/List View.md	
@@ -8,4 +8,15 @@ In the example above, the "Node.js" note on the left panel contains several chil
 ## Interaction
 
 *   Each note can be expanded or collapsed by clicking on the arrow to the left of the title.
-*   In the Ribbon, in the _Collection_ tab there are options to expand and to collapse all notes easily.
\ No newline at end of file
+*   In the Ribbon, in the _Collection_ tab there are options to expand and to collapse all notes easily.
+
+## Printing and exporting to PDF
+
+Since v0.100.0, list collections can be [printed or exported to PDF](../Basic%20Concepts%20and%20Features/Notes/Printing%20%26%20Exporting%20as%20PDF.md).
+
+A printed list collection will print all the notes in the collection, in the right order and preserving the full hierarchy.
+
+If exported to PDF within the desktop application, there is additional functionality:
+
+*   The table of contents of the PDF will reflect the structure of the notes.
+*   Reference and inline links to other notes within the same hierarchy will be functional (will jump to the corresponding page). If a link refers to a note that is not in the printed hierarchy, it will be unlinked.
\ No newline at end of file

From 049721bbfe5c877f4082acc58218529272e8dfeb Mon Sep 17 00:00:00 2001
From: Elian Doran 
Date: Thu, 20 Nov 2025 21:32:06 +0200
Subject: [PATCH 15/16] docs(user): update limitations for printing/exporting

---
 .../Notes/Printing & Exporting as PDF.html             | 10 +++++++---
 .../Notes/Printing & Exporting as PDF.md               |  5 +++--
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.html
index f0c704785..35ae5862b 100644
--- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.html	
+++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.html	
@@ -105,9 +105,13 @@ class="admonition note">
     
     
  • For Collections:
      -
    • Only Presentation is - currently supported.
    • -
    • We plan to add support for all the collection types at some point.
    • +
    • List View is + supported, allowing to print multiple notes at once while preserving hierarchy + (similar to a book).
    • +
    • Presentation is + also supported, where each slide/subnote is displayed.
    • +
    • The rest of the collections are not supported, but we plan to add support + for all the collection types at some point.
  • Using Custom app-wide CSS for diff --git a/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.md b/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.md index d8cbe4bfa..083ad6ec7 100644 --- a/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.md +++ b/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF.md @@ -74,8 +74,9 @@ Not all Note Types  * Line numbers are not printed. * Syntax highlighting is enabled, however a default theme (Visual Studio) is enforced. * For Collections: - * Only Presentation is currently supported. - * We plan to add support for all the collection types at some point. + * List View is supported, allowing to print multiple notes at once while preserving hierarchy (similar to a book). + * Presentation is also supported, where each slide/subnote is displayed. + * The rest of the collections are not supported, but we plan to add support for all the collection types at some point. * Using Custom app-wide CSS for printing is not longer supported, due to a more stable but isolated mechanism. * We plan to introduce a new mechanism specifically for a print CSS. From be115c74c3626fd4d47d56fbb84166813d98ad4c Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 20 Nov 2025 21:42:50 +0200 Subject: [PATCH 16/16] chore(print/list): address review --- .../widgets/collections/legacy/ListOrGridView.tsx | 8 ++------ .../src/widgets/collections/legacy/ListPrintView.tsx | 12 +++++------- apps/client/src/widgets/collections/legacy/utils.ts | 9 ++++++++- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx index 9017c99ba..749036598 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx @@ -11,7 +11,7 @@ import tree from "../../../services/tree"; import link from "../../../services/link"; import { t } from "../../../services/i18n"; import attribute_renderer from "../../../services/attribute_renderer"; -import { useFilteredNoteIds } from "./utils"; +import { filterChildNotes, useFilteredNoteIds } from "./utils"; export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { const [ isExpanded ] = useNoteLabelBoolean(note, "expanded"); @@ -161,14 +161,10 @@ function NoteContent({ note, trim, noChildrenList, highlightedTokens }: { note: } function NoteChildren({ note, parentNote, highlightedTokens }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined }) { - const imageLinks = note.getRelations("imageLink"); const [ childNotes, setChildNotes ] = useState(); useEffect(() => { - note.getChildNotes().then(childNotes => { - const filteredChildNotes = childNotes.filter((childNote) => !imageLinks.find((rel) => rel.value === childNote.noteId)); - setChildNotes(filteredChildNotes); - }); + filterChildNotes(note).then(setChildNotes); }, [ note ]); return childNotes?.map(childNote => ) diff --git a/apps/client/src/widgets/collections/legacy/ListPrintView.tsx b/apps/client/src/widgets/collections/legacy/ListPrintView.tsx index a2b9d5319..77a354d0d 100644 --- a/apps/client/src/widgets/collections/legacy/ListPrintView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListPrintView.tsx @@ -1,10 +1,9 @@ import { useEffect, useLayoutEffect, useState } from "preact/hooks"; -import { RawHtmlBlock } from "../../react/RawHtml"; import froca from "../../../services/froca"; import type FNote from "../../../entities/fnote"; import content_renderer from "../../../services/content_renderer"; import type { ViewModeProps } from "../interface"; -import { useFilteredNoteIds } from "./utils"; +import { filterChildNotes, useFilteredNoteIds } from "./utils"; interface NotesWithContent { note: FNote; @@ -13,10 +12,11 @@ interface NotesWithContent { export function ListPrintView({ note, noteIds: unfilteredNoteIds, onReady }: ViewModeProps<{}>) { const noteIds = useFilteredNoteIds(note, unfilteredNoteIds); - const noteIdsSet = new Set(); const [ notesWithContent, setNotesWithContent ] = useState(); useLayoutEffect(() => { + const noteIdsSet = new Set(); + froca.getNotes(noteIds).then(async (notes) => { const notesWithContent: NotesWithContent[] = []; @@ -34,9 +34,7 @@ export function ListPrintView({ note, noteIds: unfilteredNoteIds, onReady }: Vie notesWithContent.push({ note, contentEl }); if (note.hasChildren()) { - const imageLinks = note.getRelations("imageLink"); - const childNotes = await note.getChildNotes(); - const filteredChildNotes = childNotes.filter((childNote) => !imageLinks.find((rel) => rel.value === childNote.noteId)); + const filteredChildNotes = await filterChildNotes(note); for (const childNote of filteredChildNotes) { await processNote(childNote, depth + 1); } @@ -82,7 +80,7 @@ function insertPageTitle(contentEl: HTMLElement, title: string) { } function rewriteHeadings(contentEl: HTMLElement, depth: number) { - const headings = contentEl.querySelectorAll("h1, h2, h3, h4, h5, h6") + const headings = contentEl.querySelectorAll("h1, h2, h3, h4, h5, h6"); for (const headingEl of headings) { const currentLevel = parseInt(headingEl.tagName.substring(1), 10); const newLevel = Math.min(currentLevel + depth, 6); diff --git a/apps/client/src/widgets/collections/legacy/utils.ts b/apps/client/src/widgets/collections/legacy/utils.ts index 6592c9cd9..6432ce1d2 100644 --- a/apps/client/src/widgets/collections/legacy/utils.ts +++ b/apps/client/src/widgets/collections/legacy/utils.ts @@ -9,5 +9,12 @@ export function useFilteredNoteIds(note: FNote, noteIds: string[]) { const includedLinks = note ? note.getRelations().filter((rel) => rel.name === "imageLink" || rel.name === "includeNoteLink") : []; const includedNoteIds = new Set(includedLinks.map((rel) => rel.value)); return noteIds.filter((noteId) => !includedNoteIds.has(noteId) && noteId !== "_hidden"); - }, noteIds); + }, [ note, noteIds ]); +} + +export async function filterChildNotes(note: FNote) { + const imageLinks = note.getRelations("imageLink"); + const imageLinkNoteIds = new Set(imageLinks.map(rel => rel.value)); + const childNotes = await note.getChildNotes(); + return childNotes.filter((childNote) => !imageLinkNoteIds.has(childNote.noteId)); }