Printable list collection (#7812)

This commit is contained in:
Elian Doran 2025-11-20 21:52:55 +02:00 committed by GitHub
commit 26a009b397
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 259 additions and 73 deletions

View File

@ -467,6 +467,7 @@ function getReferenceLinkTitleSync(href: string) {
} }
} }
if (glob.device !== "print") {
// TODO: Check why the event is not supported. // TODO: Check why the event is not supported.
//@ts-ignore //@ts-ignore
$(document).on("click", "a", goToLink); $(document).on("click", "a", goToLink);
@ -489,6 +490,7 @@ $(document).on("mousedown", "a", (e) => {
return false; return false;
} }
}); });
}
export default { export default {
getNotePathFromUrl, getNotePathFromUrl,

View File

@ -13,6 +13,7 @@ import { subscribeToMessages, unsubscribeToMessage as unsubscribeFromMessage } f
import { WebSocketMessage } from "@triliumnext/commons"; import { WebSocketMessage } from "@triliumnext/commons";
import froca from "../../services/froca"; import froca from "../../services/froca";
import PresentationView from "./presentation"; import PresentationView from "./presentation";
import { ListPrintView } from "./legacy/ListPrintView";
interface NoteListProps { interface NoteListProps {
note: FNote | null | undefined; note: FNote | null | undefined;
@ -103,7 +104,11 @@ export function CustomNoteList({ note, viewType, isEnabled: shouldEnable, notePa
function getComponentByViewType(viewType: ViewTypeOptions, props: ViewModeProps<any>) { function getComponentByViewType(viewType: ViewTypeOptions, props: ViewModeProps<any>) {
switch (viewType) { switch (viewType) {
case "list": case "list":
if (props.media !== "print") {
return <ListView {...props} />; return <ListView {...props} />;
} else {
return <ListPrintView {...props} />;
}
case "grid": case "grid":
return <GridView {...props} />; return <GridView {...props} />;
case "geoMap": case "geoMap":

View File

@ -1,4 +1,4 @@
import { useEffect, useMemo, useRef, useState } from "preact/hooks"; import { useEffect, useRef, useState } from "preact/hooks";
import FNote from "../../../entities/fnote"; import FNote from "../../../entities/fnote";
import Icon from "../../react/Icon"; import Icon from "../../react/Icon";
import { ViewModeProps } from "../interface"; import { ViewModeProps } from "../interface";
@ -11,6 +11,7 @@ import tree from "../../../services/tree";
import link from "../../../services/link"; import link from "../../../services/link";
import { t } from "../../../services/i18n"; import { t } from "../../../services/i18n";
import attribute_renderer from "../../../services/attribute_renderer"; import attribute_renderer from "../../../services/attribute_renderer";
import { filterChildNotes, useFilteredNoteIds } from "./utils";
export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) {
const [ isExpanded ] = useNoteLabelBoolean(note, "expanded"); const [ isExpanded ] = useNoteLabelBoolean(note, "expanded");
@ -160,30 +161,15 @@ function NoteContent({ note, trim, noChildrenList, highlightedTokens }: { note:
} }
function NoteChildren({ note, parentNote, highlightedTokens }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined }) { function NoteChildren({ note, parentNote, highlightedTokens }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined }) {
const imageLinks = note.getRelations("imageLink");
const [ childNotes, setChildNotes ] = useState<FNote[]>(); const [ childNotes, setChildNotes ] = useState<FNote[]>();
useEffect(() => { useEffect(() => {
note.getChildNotes().then(childNotes => { filterChildNotes(note).then(setChildNotes);
const filteredChildNotes = childNotes.filter((childNote) => !imageLinks.find((rel) => rel.value === childNote.noteId));
setChildNotes(filteredChildNotes);
});
}, [ note ]); }, [ note ]);
return childNotes?.map(childNote => <ListNoteCard note={childNote} parentNote={parentNote} highlightedTokens={highlightedTokens} />) return childNotes?.map(childNote => <ListNoteCard note={childNote} parentNote={parentNote} highlightedTokens={highlightedTokens} />)
} }
/**
* Filters the note IDs for the legacy view to filter out subnotes that are already included in the note content such as images, included notes.
*/
function useFilteredNoteIds(note: FNote, noteIds: string[]) {
return useMemo(() => {
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);
}
function getNotePath(parentNote: FNote, childNote: FNote) { function getNotePath(parentNote: FNote, childNote: FNote) {
if (parentNote.type === "search") { if (parentNote.type === "search") {
// for search note parent, we want to display a non-search path // for search note parent, we want to display a non-search path

View File

@ -0,0 +1,110 @@
import { useEffect, useLayoutEffect, useState } from "preact/hooks";
import froca from "../../../services/froca";
import type FNote from "../../../entities/fnote";
import content_renderer from "../../../services/content_renderer";
import type { ViewModeProps } from "../interface";
import { filterChildNotes, useFilteredNoteIds } from "./utils";
interface NotesWithContent {
note: FNote;
contentEl: HTMLElement;
}
export function ListPrintView({ note, noteIds: unfilteredNoteIds, onReady }: ViewModeProps<{}>) {
const noteIds = useFilteredNoteIds(note, unfilteredNoteIds);
const [ notesWithContent, setNotesWithContent ] = useState<NotesWithContent[]>();
useLayoutEffect(() => {
const noteIdsSet = new Set<string>();
froca.getNotes(noteIds).then(async (notes) => {
const notesWithContent: NotesWithContent[] = [];
async function processNote(note: FNote, depth: number) {
const content = await content_renderer.getRenderedContent(note, {
trim: false,
noChildrenList: true
});
const contentEl = content.$renderedContent[0];
insertPageTitle(contentEl, note.title);
rewriteHeadings(contentEl, depth);
noteIdsSet.add(note.noteId);
notesWithContent.push({ note, contentEl });
if (note.hasChildren()) {
const filteredChildNotes = await filterChildNotes(note);
for (const childNote of filteredChildNotes) {
await processNote(childNote, depth + 1);
}
}
}
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]);
useEffect(() => {
if (notesWithContent && onReady) {
onReady();
}
}, [ notesWithContent, onReady ]);
return (
<div class="note-list list-print-view">
<div class="note-list-container use-tn-links">
<h1>{note.title}</h1>
{notesWithContent?.map(({ note: childNote, contentEl }) => (
<section id={`note-${childNote.noteId}`} class="note" dangerouslySetInnerHTML={{ __html: contentEl.innerHTML }} />
))}
</div>
</div>
);
}
function insertPageTitle(contentEl: HTMLElement, title: string) {
const pageTitleEl = document.createElement("h1");
pageTitleEl.textContent = title;
contentEl.prepend(pageTitleEl);
}
function rewriteHeadings(contentEl: HTMLElement, depth: number) {
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);
const newHeadingEl = document.createElement(`h${newLevel}`);
newHeadingEl.innerHTML = headingEl.innerHTML;
headingEl.replaceWith(newHeadingEl);
}
}
function rewriteLinks(contentEl: HTMLElement, noteIdsSet: Set<string>) {
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);
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);
}
}
}
}

View File

@ -0,0 +1,20 @@
import { useMemo } from "preact/hooks";
import FNote from "../../../entities/fnote";
/**
* Filters the note IDs for the legacy view to filter out subnotes that are already included in the note content such as images, included notes.
*/
export function useFilteredNoteIds(note: FNote, noteIds: string[]) {
return useMemo(() => {
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");
}, [ 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));
}

View File

@ -49,7 +49,7 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
const canBeConvertedToAttachment = note?.isEligibleForConversionToAttachment(); const canBeConvertedToAttachment = note?.isEligibleForConversionToAttachment();
const isSearchable = ["text", "code", "book", "mindMap", "doc"].includes(note.type); const isSearchable = ["text", "code", "book", "mindMap", "doc"].includes(note.type);
const isInOptionsOrHelp = note?.noteId.startsWith("_options") || note?.noteId.startsWith("_help"); const isInOptionsOrHelp = note?.noteId.startsWith("_options") || note?.noteId.startsWith("_help");
const isPrintable = ["text", "code"].includes(note.type) || (note.type === "book" && note.getLabelValue("viewType") === "presentation"); const isPrintable = ["text", "code"].includes(note.type) || (note.type === "book" && ["presentation", "list"].includes(note.getLabelValue("viewType") ?? ""));
const isElectron = getIsElectron(); const isElectron = getIsElectron();
const isMac = getIsMac(); const isMac = getIsMac();
const hasSource = ["text", "code", "relationMap", "mermaid", "canvas", "mindMap", "aiChat"].includes(note.type); const hasSource = ["text", "code", "relationMap", "mermaid", "canvas", "mindMap", "aiChat"].includes(note.type);

View File

@ -4,7 +4,6 @@
<figcaption>Screenshot of the note contextual menu indicating the “Export as PDF” <figcaption>Screenshot of the note contextual menu indicating the “Export as PDF”
option.</figcaption> option.</figcaption>
</figure> </figure>
<h2>Printing</h2> <h2>Printing</h2>
<p>This feature allows printing of notes. It works on both the desktop client, <p>This feature allows printing of notes. It works on both the desktop client,
but also on the web.</p> but also on the web.</p>
@ -60,9 +59,9 @@ class="admonition note">
orientation, size. However, there are a few&nbsp;<a class="reference-link" orientation, size. However, there are a few&nbsp;<a class="reference-link"
href="#root/_help_zEY4DaJG4YT5">Attributes</a>&nbsp;to adjust some of the settings:</p> href="#root/_help_zEY4DaJG4YT5">Attributes</a>&nbsp;to adjust some of the settings:</p>
<ul> <ul>
<li>To print in landscape mode instead of portrait (useful for big diagrams <li data-list-item-id="e05b1bc3a57c550c493c8b1030c301673">To print in landscape mode instead of portrait (useful for big diagrams
or slides), add <code>#printLandscape</code>.</li> or slides), add <code>#printLandscape</code>.</li>
<li>By default, the resulting PDF will be in Letter format. It is possible <li data-list-item-id="e6d7f6bb720e1f94994aa178881885dbd">By default, the resulting PDF will be in Letter format. It is possible
to adjust it to another page size via the <code>#printPageSize</code> attribute, to adjust it to another page size via the <code>#printPageSize</code> attribute,
with one of the following values: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.</li> with one of the following values: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.</li>
</ul> </ul>
@ -70,15 +69,26 @@ class="admonition note">
<p>These options have no effect when used with the printing feature, since <p>These options have no effect when used with the printing feature, since
the user-defined settings are used instead.</p> the user-defined settings are used instead.</p>
</aside> </aside>
<h2>Printing multiple notes</h2>
<p>Since v0.100.0, it is possible to print more than one note at the time
by using&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/_help_GTwFsgaA0lCt">Collections</a>:</p>
<ol>
<li data-list-item-id="e1caaf943b13fd4764f93c58ea5f4f0c4">First create a collection.</li>
<li data-list-item-id="e3593024c9c69c3d26295d1e0152c813d">Configure it to use&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/GTwFsgaA0lCt/_help_mULW0Q3VojwY">List View</a>.</li>
<li
data-list-item-id="ebeea878f04af6f1da53fc0e8a80caf2d">Print the collection note normally.</li>
</ol>
<p>The resulting collection will contain all the children of the collection,
while maintaining the hierarchy.</p>
<h2>Keyboard shortcut</h2> <h2>Keyboard shortcut</h2>
<p>It's possible to trigger both printing and export as PDF from the keyboard <p>It's possible to trigger both printing and export as PDF from the keyboard
by going to&nbsp;<em>Keyboard shortcuts</em>&nbsp;in&nbsp;<a class="reference-link" by going to&nbsp;<em>Keyboard shortcuts</em>&nbsp;in&nbsp;<a class="reference-link"
href="#root/_help_4TIF1oA4VQRO">Options</a>&nbsp;and assigning a key combination href="#root/_help_4TIF1oA4VQRO">Options</a>&nbsp;and assigning a key combination
for:</p> for:</p>
<ul> <ul>
<li><em>Print Active Note</em> <li class="ck-list-marker-italic" data-list-item-id="e9595278e625ee8de30a6e88fb00d48e3"><em>Print Active Note</em>
</li> </li>
<li><em>Export Active Note as PDF</em> <li class="ck-list-marker-italic" data-list-item-id="e981d4cf371e1ff69416a796d88e88709"><em>Export Active Note as PDF</em>
</li> </li>
</ul> </ul>
<h2>Constraints &amp; limitations</h2> <h2>Constraints &amp; limitations</h2>
@ -86,24 +96,28 @@ class="admonition note">
supported when printing, in which case the <em>Print</em> and <em>Export as PDF</em> options supported when printing, in which case the <em>Print</em> and <em>Export as PDF</em> options
will be disabled.</p> will be disabled.</p>
<ul> <ul>
<li>For&nbsp;<a class="reference-link" href="#root/_help_6f9hih2hXXZk">Code</a>&nbsp;notes: <li data-list-item-id="e82f01875cc03dcdab5328121654d815c">For&nbsp;<a class="reference-link" href="#root/_help_6f9hih2hXXZk">Code</a>&nbsp;notes:
<ul> <ul>
<li>Line numbers are not printed.</li> <li data-list-item-id="eea76e6bf545a3b54270ff86a74ca0d8d">Line numbers are not printed.</li>
<li>Syntax highlighting is enabled, however a default theme (Visual Studio) <li data-list-item-id="edea65d8d3dedd354431e1e3a5dcd2e08">Syntax highlighting is enabled, however a default theme (Visual Studio)
is enforced.</li> is enforced.</li>
</ul> </ul>
</li> </li>
<li>For&nbsp;<a class="reference-link" href="#root/_help_GTwFsgaA0lCt">Collections</a>: <li data-list-item-id="ec32cca86e4b0e2f75a2f1a06d2219e0b">For&nbsp;<a class="reference-link" href="#root/_help_GTwFsgaA0lCt">Collections</a>:
<ul> <ul>
<li>Only&nbsp;<a class="reference-link" href="#root/_help_zP3PMqaG71Ct">Presentation</a>&nbsp;is <li data-list-item-id="e0e1fc82e1141d3f4a609699e228ccc73"><a class="reference-link" href="#root/pOsGYCXsbNQG/GTwFsgaA0lCt/_help_mULW0Q3VojwY">List View</a>&nbsp;is
currently supported.</li> supported, allowing to print multiple notes at once while preserving hierarchy
<li>We plan to add support for all the collection types at some point.</li> (similar to a book).</li>
<li data-list-item-id="ee114b8468eaf24bce451f5ec4bda3da4"><a class="reference-link" href="#root/_help_zP3PMqaG71Ct">Presentation</a>&nbsp;is
also supported, where each slide/subnote is displayed.</li>
<li data-list-item-id="e4efe886c3ca1d19a49196340d9e1f6c8">The rest of the collections are not supported, but we plan to add support
for all the collection types at some point.</li>
</ul> </ul>
</li> </li>
<li>Using&nbsp;<a class="reference-link" href="#root/_help_AlhDUqhENtH7">Custom app-wide CSS</a>&nbsp;for <li data-list-item-id="ee721d0145486818bd914a26594699cbd">Using&nbsp;<a class="reference-link" href="#root/_help_AlhDUqhENtH7">Custom app-wide CSS</a>&nbsp;for
printing is not longer supported, due to a more stable but isolated mechanism. printing is not longer supported, due to a more stable but isolated mechanism.
<ul> <ul>
<li>We plan to introduce a new mechanism specifically for a print CSS.</li> <li data-list-item-id="e2e1228d8d62cbdc8e96a7cbc9655c2ca">We plan to introduce a new mechanism specifically for a print CSS.</li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -114,10 +128,10 @@ class="admonition note">
printing.</p> printing.</p>
<p>To do so:</p> <p>To do so:</p>
<ul> <ul>
<li>Create a CSS <a href="#root/_help_6f9hih2hXXZk">code note</a>.</li> <li data-list-item-id="ea90c233190428f0aacfcca4abe2f6b18">Create a CSS <a href="#root/_help_6f9hih2hXXZk">code note</a>.</li>
<li>On the note being printed, apply the <code>~printCss</code> relation to <li data-list-item-id="ec0756dfa1ce83087dd2c9bcc289d234b">On the note being printed, apply the <code>~printCss</code> relation to
point to the newly created CSS code note.</li> point to the newly created CSS code note.</li>
<li>To apply the CSS to multiple notes, consider using <a href="#root/_help_bwZpz2ajCEwO">inheritable attributes</a> or&nbsp; <li data-list-item-id="ed05b40a29e6b442327bf439286096ac6">To apply the CSS to multiple notes, consider using <a href="#root/_help_bwZpz2ajCEwO">inheritable attributes</a> or&nbsp;
<a <a
class="reference-link" href="#root/_help_KC1HB96bqqHX">Templates</a>.</li> class="reference-link" href="#root/_help_KC1HB96bqqHX">Templates</a>.</li>
</ul> </ul>
@ -128,10 +142,11 @@ class="admonition note">
}</code></pre> }</code></pre>
<p>To remark:</p> <p>To remark:</p>
<ul> <ul>
<li>Multiple CSS notes can be add by using multiple <code>~printCss</code> relations.</li> <li data-list-item-id="ec7fa7fb43c85ba65185b42a9ed590da7">Multiple CSS notes can be add by using multiple <code>~printCss</code> relations.</li>
<li>If the note pointing to the <code>printCss</code> doesn't have the right <li
data-list-item-id="e1db64e345bbaf53151b84a69ff91376f">If the note pointing to the <code>printCss</code> doesn't have the right
note type or mime type, it will be ignored.</li> note type or mime type, it will be ignored.</li>
<li>If migrating from a previous version where&nbsp;<a class="reference-link" <li data-list-item-id="e8b2d24c4a6781c5516d0551f51b3947b">If migrating from a previous version where&nbsp;<a class="reference-link"
href="#root/_help_AlhDUqhENtH7">Custom app-wide CSS</a>, there's no need for <code>@media print {</code> since href="#root/_help_AlhDUqhENtH7">Custom app-wide CSS</a>, there's no need for <code>@media print {</code> since
the style-sheet is used only for printing.</li> the style-sheet is used only for printing.</li>
</ul> </ul>

View File

@ -12,9 +12,22 @@
as a single continuous document.</p> as a single continuous document.</p>
<h2>Interaction</h2> <h2>Interaction</h2>
<ul> <ul>
<li>Each note can be expanded or collapsed by clicking on the arrow to the <li data-list-item-id="ee85c9dce1f91b700d8f13bdc9500bc62">Each note can be expanded or collapsed by clicking on the arrow to the
left of the title.</li> left of the title.</li>
<li>In the&nbsp;<a class="reference-link" href="#root/_help_BlN9DFI679QC">Ribbon</a>, <li data-list-item-id="e84faa71c2b0bf22a09490b35134f2687">In the&nbsp;<a class="reference-link" href="#root/_help_BlN9DFI679QC">Ribbon</a>,
in the <em>Collection</em> tab there are options to expand and to collapse in the <em>Collection</em> tab there are options to expand and to collapse
all notes easily.</li> all notes easily.</li>
</ul> </ul>
<h2>Printing and exporting to PDF</h2>
<p>Since v0.100.0, list collections can be <a href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/BFs8mudNFgCS/_help_NRnIZmSMc5sj">printed or exported to PDF</a>.</p>
<p>A printed list collection will print all the notes in the collection,
in the right order and preserving the full hierarchy.</p>
<p>If exported to PDF within the desktop application, there is additional
functionality:</p>
<ul>
<li data-list-item-id="ec4b9a29dd7f601d1415b3ca9fa414fde">The table of contents of the PDF will reflect the structure of the notes.</li>
<li
data-list-item-id="ef5fa5e9c68e7cbdf9a5e468b406e298a">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.</li>
</ul>

View File

@ -1,13 +1,12 @@
<ul> <ul>
<li data-list-item-id="ef125f092e6b27dc2c8486d195be8be39"><code>doRender</code> must not be overridden, instead <code>doRenderBody()</code> has <li><code>doRender</code> must not be overridden, instead <code>doRenderBody()</code> has
to be overridden. to be overridden.
<ul> <ul>
<li data-list-item-id="e632e4415d4439f862124dc2e024093db"><code>doRenderBody</code> can optionally be <code>async</code>.</li> <li><code>doRenderBody</code> can optionally be <code>async</code>.</li>
</ul> </ul>
</li> </li>
<li data-list-item-id="eef79d03bdc04d4869f6ee69f9086931f"><code>parentWidget()</code> must be set to <code>“rightPane”</code>.</li> <li><code>parentWidget()</code> must be set to <code>“rightPane”</code>.</li>
<li <li><code>widgetTitle()</code> getter can optionally be overriden, otherwise
data-list-item-id="e1bbd084dfcfdea1a8061159b8dcffd44"><code>widgetTitle()</code> getter can optionally be overriden, otherwise
the widget will be displayed as “Untitled widget”.</li> the widget will be displayed as “Untitled widget”.</li>
</ul><pre><code class="language-text-x-trilium-auto">const template = `&lt;div&gt;Hi&lt;/div&gt;`; </ul><pre><code class="language-text-x-trilium-auto">const template = `&lt;div&gt;Hi&lt;/div&gt;`;

View File

@ -1,5 +1,5 @@
# Documentation # Documentation
There are multiple types of documentation for Trilium:<img class="image-style-align-right" src="api/images/veLUtimyaTkr/Documentation_image.png" width="205" height="162"> There are multiple types of documentation for Trilium:<img class="image-style-align-right" src="api/images/CJFtZbAX4Otj/Documentation_image.png" width="205" height="162">
* The _User Guide_ represents the user-facing documentation. This documentation can be browsed by users directly from within Trilium, by pressing <kbd>F1</kbd>. * The _User Guide_ represents the user-facing documentation. This documentation can be browsed by users directly from within Trilium, by pressing <kbd>F1</kbd>.
* The _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers. * The _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers.

View File

@ -4135,6 +4135,13 @@
"value": "printing-and-pdf-export", "value": "printing-and-pdf-export",
"isInheritable": false, "isInheritable": false,
"position": 110 "position": 110
},
{
"type": "relation",
"name": "internalLink",
"value": "mULW0Q3VojwY",
"isInheritable": false,
"position": 130
} }
], ],
"format": "markdown", "format": "markdown",
@ -10478,6 +10485,13 @@
"value": "list", "value": "list",
"isInheritable": false, "isInheritable": false,
"position": 30 "position": 30
},
{
"type": "relation",
"name": "internalLink",
"value": "NRnIZmSMc5sj",
"isInheritable": false,
"position": 40
} }
], ],
"format": "markdown", "format": "markdown",

View File

@ -49,6 +49,16 @@ When exporting to PDF, there are no customizable settings such as page orientati
> [!NOTE] > [!NOTE]
> These options have no effect when used with the printing feature, since the user-defined settings are used instead. > 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 <a class="reference-link" href="../../Collections.md">Collections</a>:
1. First create a collection.
2. Configure it to use <a class="reference-link" href="../../Collections/List%20View.md">List View</a>.
3. Print the collection note normally.
The resulting collection will contain all the children of the collection, while maintaining the hierarchy.
## Keyboard shortcut ## Keyboard shortcut
It's possible to trigger both printing and export as PDF from the keyboard by going to _Keyboard shortcuts_ in <a class="reference-link" href="../UI%20Elements/Options.md">Options</a> and assigning a key combination for: It's possible to trigger both printing and export as PDF from the keyboard by going to _Keyboard shortcuts_ in <a class="reference-link" href="../UI%20Elements/Options.md">Options</a> and assigning a key combination for:
@ -64,8 +74,9 @@ Not all <a class="reference-link" href="../../Note%20Types.md">Note Types</a> 
* Line numbers are not printed. * Line numbers are not printed.
* Syntax highlighting is enabled, however a default theme (Visual Studio) is enforced. * Syntax highlighting is enabled, however a default theme (Visual Studio) is enforced.
* For <a class="reference-link" href="../../Collections.md">Collections</a>: * For <a class="reference-link" href="../../Collections.md">Collections</a>:
* Only <a class="reference-link" href="../../Collections/Presentation.md">Presentation</a> is currently supported. * <a class="reference-link" href="../../Collections/List%20View.md">List View</a> is supported, allowing to print multiple notes at once while preserving hierarchy (similar to a book).
* We plan to add support for all the collection types at some point. * <a class="reference-link" href="../../Collections/Presentation.md">Presentation</a> 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 <a class="reference-link" href="../../Theme%20development/Custom%20app-wide%20CSS.md">Custom app-wide CSS</a> for printing is not longer supported, due to a more stable but isolated mechanism. * Using <a class="reference-link" href="../../Theme%20development/Custom%20app-wide%20CSS.md">Custom app-wide CSS</a> 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.

View File

@ -9,3 +9,14 @@ In the example above, the "Node.js" note on the left panel contains several chil
* Each note can be expanded or collapsed by clicking on the arrow to the left of the title. * Each note can be expanded or collapsed by clicking on the arrow to the left of the title.
* In the <a class="reference-link" href="../Basic%20Concepts%20and%20Features/UI%20Elements/Ribbon.md">Ribbon</a>, in the _Collection_ tab there are options to expand and to collapse all notes easily. * In the <a class="reference-link" href="../Basic%20Concepts%20and%20Features/UI%20Elements/Ribbon.md">Ribbon</a>, 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.