Table printing support (#7833)
Some checks are pending
Checks / main (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Documentation / Build and Deploy Documentation (push) Waiting to run
Dev / Test development (push) Waiting to run
Dev / Build Docker image (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile) (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile.alpine) (push) Blocked by required conditions
/ Check Docker build (Dockerfile) (push) Waiting to run
/ Check Docker build (Dockerfile.alpine) (push) Waiting to run
/ Build Docker images (Dockerfile, ubuntu-24.04-arm, linux/arm64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.alpine, ubuntu-latest, linux/amd64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v7) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v8) (push) Blocked by required conditions
/ Merge manifest lists (push) Blocked by required conditions
playwright / E2E tests on linux-arm64 (push) Waiting to run
playwright / E2E tests on linux-x64 (push) Waiting to run

This commit is contained in:
Elian Doran 2025-11-21 23:11:11 +02:00 committed by GitHub
commit f72ce697a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 236 additions and 132 deletions

View File

@ -14,6 +14,7 @@ import { WebSocketMessage } from "@triliumnext/commons";
import froca from "../../services/froca";
import PresentationView from "./presentation";
import { ListPrintView } from "./legacy/ListPrintView";
import TablePrintView from "./table/TablePrintView";
interface NoteListProps {
note: FNote | null | undefined;
@ -117,9 +118,13 @@ function getComponentByViewType(viewType: ViewTypeOptions, props: ViewModeProps<
case "geoMap":
return <GeoView {...props} />;
case "calendar":
return <CalendarView {...props} />
return <CalendarView {...props} />;
case "table":
return <TableView {...props} />
if (props.media !== "print") {
return <TableView {...props} />;
} else {
return <TablePrintView {...props} />;
}
case "board":
return <BoardView {...props} />
case "presentation":

View File

@ -0,0 +1,20 @@
.table-print-view .tabulator-print-table table,
.table-print-view .tabulator-print-table th,
.table-print-view .tabulator-print-table tr,
.table-print-view .tabulator-print-table td {
border: 1px solid black;
border-collapse: collapse;
}
.table-print-view .tabulator-print-table th {
background-color: #f0f0f0;
}
.table-print-view .tabulator-print-table th,
.table-print-view .tabulator-print-table td {
padding: 0.25rem 0.5rem;
}
.table-print-view .tabulator-print-table td[aria-checked] svg path {
fill: currentColor;
}

View File

@ -0,0 +1,49 @@
import { useEffect, useRef, useState } from "preact/hooks";
import { ViewModeProps } from "../interface";
import useData, { TableConfig } from "./data";
import { ExportModule, FormatModule, Tabulator as VanillaTabulator} from 'tabulator-tables';
import Tabulator from "./tabulator";
import { RawHtmlBlock } from "../../react/RawHtml";
import "./TablePrintView.css";
export default function TablePrintView({ note, noteIds, viewConfig, onReady }: ViewModeProps<TableConfig>) {
const tabulatorRef = useRef<VanillaTabulator>(null);
const { columnDefs, rowData, hasChildren } = useData(note, noteIds, viewConfig, undefined, () => {});
const [ html, setHtml ] = useState<string>();
useEffect(() => {
if (!html) return;
onReady?.();
}, [ html ]);
return rowData && (
<>
<h1>{note.title}</h1>
<div className="table-print-view">
{!html ? (
<Tabulator
tabulatorRef={tabulatorRef}
className="table-print-view-container"
modules={[ ExportModule, FormatModule ]}
columns={columnDefs ?? []}
data={rowData}
index="branchId"
dataTree={hasChildren}
printAsHtml={true}
printStyled={false}
onReady={() => {
const tabulator = tabulatorRef.current;
if (!tabulator) return;
setHtml(tabulator.getHtml());
}}
/>
) : (
<RawHtmlBlock html={html} />
)}
</div>
</>
)
}

View File

@ -0,0 +1,77 @@
import type { ColumnDefinition } from "tabulator-tables";
import FNote from "../../../entities/fnote";
import { useNoteLabelBoolean, useNoteLabelInt, useTriliumEvent } from "../../react/hooks";
import { useEffect, useState } from "preact/hooks";
import getAttributeDefinitionInformation, { buildRowDefinitions, TableData } from "./rows";
import froca from "../../../services/froca";
import { buildColumnDefinitions } from "./columns";
import attributes from "../../../services/attributes";
import { RefObject } from "preact";
export interface TableConfig {
tableData: {
columns?: ColumnDefinition[];
};
}
export default function useData(note: FNote, noteIds: string[], viewConfig: TableConfig | undefined, newAttributePosition: RefObject<number | undefined> | undefined, resetNewAttributePosition: () => void) {
const [ maxDepth ] = useNoteLabelInt(note, "maxNestingDepth");
const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived");
const [ columnDefs, setColumnDefs ] = useState<ColumnDefinition[]>();
const [ rowData, setRowData ] = useState<TableData[]>();
const [ hasChildren, setHasChildren ] = useState<boolean>();
const [ isSorted ] = useNoteLabelBoolean(note, "sorted");
const [ movableRows, setMovableRows ] = useState(false);
async function refresh() {
const info = getAttributeDefinitionInformation(note);
// Ensure all note IDs are loaded.
await froca.getNotes(noteIds);
const { definitions: rowData, hasSubtree: hasChildren, rowNumber } = await buildRowDefinitions(note, info, includeArchived, maxDepth);
const columnDefs = buildColumnDefinitions({
info,
movableRows,
existingColumnData: viewConfig?.tableData?.columns,
rowNumberHint: rowNumber,
position: newAttributePosition?.current ?? undefined
});
setColumnDefs(columnDefs);
setRowData(rowData);
setHasChildren(hasChildren);
resetNewAttributePosition();
}
useEffect(() => { refresh() }, [ note, noteIds, maxDepth, movableRows ]);
useTriliumEvent("entitiesReloaded", ({ loadResults}) => {
if (glob.device === "print") return;
// React to column changes.
if (loadResults.getAttributeRows().find(attr =>
attr.type === "label" &&
(attr.name?.startsWith("label:") || attr.name?.startsWith("relation:")) &&
attributes.isAffecting(attr, note))) {
refresh();
return;
}
// React to external row updates.
if (loadResults.getBranchRows().some(branch => branch.parentNoteId === note.noteId || noteIds.includes(branch.parentNoteId ?? ""))
|| loadResults.getNoteIds().some(noteId => noteIds.includes(noteId))
|| loadResults.getAttributeRows().some(attr => noteIds.includes(attr.noteId!))
|| loadResults.getAttributeRows().some(attr => attr.name === "archived" && attr.noteId && noteIds.includes(attr.noteId))) {
refresh();
return;
}
});
// Identify if movable rows.
useEffect(() => {
setMovableRows(!isSorted && note.type !== "search" && !hasChildren);
}, [ isSorted, note, hasChildren ]);
return { columnDefs, rowData, movableRows, hasChildren };
}

View File

@ -1,10 +1,9 @@
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "preact/hooks";
import { ViewModeProps } from "../interface";
import { buildColumnDefinitions } from "./columns";
import getAttributeDefinitionInformation, { buildRowDefinitions, TableData } from "./rows";
import { useLegacyWidget, useNoteLabelBoolean, useNoteLabelInt, useTriliumEvent } from "../../react/hooks";
import { TableData } from "./rows";
import { useLegacyWidget } from "../../react/hooks";
import Tabulator from "./tabulator";
import { Tabulator as VanillaTabulator, SortModule, FormatModule, InteractionModule, EditModule, ResizeColumnsModule, FrozenColumnsModule, PersistenceModule, MoveColumnsModule, MoveRowsModule, ColumnDefinition, DataTreeModule, Options, RowComponent} from 'tabulator-tables';
import { Tabulator as VanillaTabulator, SortModule, FormatModule, InteractionModule, EditModule, ResizeColumnsModule, FrozenColumnsModule, PersistenceModule, MoveColumnsModule, MoveRowsModule, DataTreeModule, Options, RowComponent} from 'tabulator-tables';
import { useContextMenu } from "./context_menu";
import { ParentComponent } from "../../react/react_utils";
import FNote from "../../../entities/fnote";
@ -14,16 +13,8 @@ import "./index.css";
import useRowTableEditing from "./row_editing";
import useColTableEditing from "./col_editing";
import AttributeDetailWidget from "../../attribute_widgets/attribute_detail";
import attributes from "../../../services/attributes";
import { RefObject } from "preact";
import SpacedUpdate from "../../../services/spaced_update";
import froca from "../../../services/froca";
interface TableConfig {
tableData: {
columns?: ColumnDefinition[];
};
}
import useData, { TableConfig } from "./data";
export default function TableView({ note, noteIds, notePath, viewConfig, saveConfig }: ViewModeProps<TableConfig>) {
const tabulatorRef = useRef<VanillaTabulator>(null);
@ -118,67 +109,7 @@ function usePersistence(viewConfig: TableConfig | null | undefined, saveConfig:
return () => {
spacedUpdate.updateNowIfNecessary();
};
}, [ viewConfig, saveConfig ])
}, [ viewConfig, saveConfig ]);
return persistenceProps;
}
function useData(note: FNote, noteIds: string[], viewConfig: TableConfig | undefined, newAttributePosition: RefObject<number | undefined>, resetNewAttributePosition: () => void) {
const [ maxDepth ] = useNoteLabelInt(note, "maxNestingDepth") ?? -1;
const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived");
const [ columnDefs, setColumnDefs ] = useState<ColumnDefinition[]>();
const [ rowData, setRowData ] = useState<TableData[]>();
const [ hasChildren, setHasChildren ] = useState<boolean>();
const [ isSorted ] = useNoteLabelBoolean(note, "sorted");
const [ movableRows, setMovableRows ] = useState(false);
async function refresh() {
const info = getAttributeDefinitionInformation(note);
// Ensure all note IDs are loaded.
await froca.getNotes(noteIds);
const { definitions: rowData, hasSubtree: hasChildren, rowNumber } = await buildRowDefinitions(note, info, includeArchived, maxDepth);
const columnDefs = buildColumnDefinitions({
info,
movableRows,
existingColumnData: viewConfig?.tableData?.columns,
rowNumberHint: rowNumber,
position: newAttributePosition.current ?? undefined
});
setColumnDefs(columnDefs);
setRowData(rowData);
setHasChildren(hasChildren);
resetNewAttributePosition();
}
useEffect(() => { refresh() }, [ note, noteIds, maxDepth, movableRows ]);
useTriliumEvent("entitiesReloaded", ({ loadResults}) => {
// React to column changes.
if (loadResults.getAttributeRows().find(attr =>
attr.type === "label" &&
(attr.name?.startsWith("label:") || attr.name?.startsWith("relation:")) &&
attributes.isAffecting(attr, note))) {
refresh();
return;
}
// React to external row updates.
if (loadResults.getBranchRows().some(branch => branch.parentNoteId === note.noteId || noteIds.includes(branch.parentNoteId ?? ""))
|| loadResults.getNoteIds().some(noteId => noteIds.includes(noteId))
|| loadResults.getAttributeRows().some(attr => noteIds.includes(attr.noteId!))
|| loadResults.getAttributeRows().some(attr => attr.name === "archived" && attr.noteId && noteIds.includes(attr.noteId))) {
refresh();
return;
}
});
// Identify if movable rows.
useEffect(() => {
setMovableRows(!isSorted && note.type !== "search" && !hasChildren);
}, [ isSorted, note, hasChildren ]);
return { columnDefs, rowData, movableRows, hasChildren };
}

View File

@ -14,9 +14,10 @@ interface TableProps<T> extends Omit<Options, "data" | "footerElement" | "index"
events?: Partial<EventCallBackMethods>;
index: keyof T;
footerElement?: string | HTMLElement | JSX.Element;
onReady?: () => void;
}
export default function Tabulator<T>({ className, columns, data, modules, tabulatorRef: externalTabulatorRef, footerElement, events, index, dataTree, ...restProps }: TableProps<T>) {
export default function Tabulator<T>({ className, columns, data, modules, tabulatorRef: externalTabulatorRef, footerElement, events, index, dataTree, onReady, ...restProps }: TableProps<T>) {
const parentComponent = useContext(ParentComponent);
const containerRef = useRef<HTMLDivElement>(null);
const tabulatorRef = useRef<VanillaTabulator>(null);
@ -43,6 +44,7 @@ export default function Tabulator<T>({ className, columns, data, modules, tabula
tabulator.on("tableBuilt", () => {
tabulatorRef.current = tabulator;
externalTabulatorRef.current = tabulator;
onReady?.();
});
return () => tabulator.destroy();

View File

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

View File

@ -59,9 +59,9 @@ class="admonition note">
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>
<ul>
<li data-list-item-id="e05b1bc3a57c550c493c8b1030c301673">To print in landscape mode instead of portrait (useful for big diagrams
<li data-list-item-id="e2c3a384e6b36708d7eab0be86e6b390f">To print in landscape mode instead of portrait (useful for big diagrams
or slides), add <code>#printLandscape</code>.</li>
<li data-list-item-id="e6d7f6bb720e1f94994aa178881885dbd">By default, the resulting PDF will be in Letter format. It is possible
<li data-list-item-id="e697b50e94a0cf5748434ade36b74bd2a">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,
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>
@ -71,12 +71,12 @@ class="admonition note">
</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>
by using&nbsp;<a class="reference-link" href="#root/_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="ea89c798776f96c4b224dffec2518a4ab">First create a collection.</li>
<li data-list-item-id="efb4061e38e2b1ca6c9be16fd1c8a4c76">Configure it to use&nbsp;<a class="reference-link" href="#root/_help_mULW0Q3VojwY">List View</a>.</li>
<li
data-list-item-id="ebeea878f04af6f1da53fc0e8a80caf2d">Print the collection note normally.</li>
data-list-item-id="ecaad5f90dcbfd65da21689c54b063ff9">Print the collection note normally.</li>
</ol>
<p>The resulting collection will contain all the children of the collection,
while maintaining the hierarchy.</p>
@ -86,9 +86,9 @@ class="admonition note">
href="#root/_help_4TIF1oA4VQRO">Options</a>&nbsp;and assigning a key combination
for:</p>
<ul>
<li class="ck-list-marker-italic" data-list-item-id="e9595278e625ee8de30a6e88fb00d48e3"><em>Print Active Note</em>
<li class="ck-list-marker-italic" data-list-item-id="e0ad1793aca0023d3a01e12bafb1809b7"><em>Print Active Note</em>
</li>
<li class="ck-list-marker-italic" data-list-item-id="e981d4cf371e1ff69416a796d88e88709"><em>Export Active Note as PDF</em>
<li class="ck-list-marker-italic" data-list-item-id="edf28e69abc7a3d73fdc5f7deec99521c"><em>Export Active Note as PDF</em>
</li>
</ul>
<h2>Constraints &amp; limitations</h2>
@ -96,28 +96,39 @@ class="admonition note">
supported when printing, in which case the <em>Print</em> and <em>Export as PDF</em> options
will be disabled.</p>
<ul>
<li data-list-item-id="e82f01875cc03dcdab5328121654d815c">For&nbsp;<a class="reference-link" href="#root/_help_6f9hih2hXXZk">Code</a>&nbsp;notes:
<li data-list-item-id="eb24570f2dbcda191d4069b16b4aaf5bd">For&nbsp;<a class="reference-link" href="#root/_help_6f9hih2hXXZk">Code</a>&nbsp;notes:
<ul>
<li data-list-item-id="eea76e6bf545a3b54270ff86a74ca0d8d">Line numbers are not printed.</li>
<li data-list-item-id="edea65d8d3dedd354431e1e3a5dcd2e08">Syntax highlighting is enabled, however a default theme (Visual Studio)
<li data-list-item-id="e7bf313b83ebbf1b58063d146d50d40aa">Line numbers are not printed.</li>
<li data-list-item-id="e7d63b2d4beb4adb1f3a7ad7b01613ddb">Syntax highlighting is enabled, however a default theme (Visual Studio)
is enforced.</li>
</ul>
</li>
<li data-list-item-id="ec32cca86e4b0e2f75a2f1a06d2219e0b">For&nbsp;<a class="reference-link" href="#root/_help_GTwFsgaA0lCt">Collections</a>:
<li data-list-item-id="e45945585853cb2a279892dc88074356a">For&nbsp;<a class="reference-link" href="#root/_help_GTwFsgaA0lCt">Collections</a>,
the following are supported:
<ul>
<li data-list-item-id="e0e1fc82e1141d3f4a609699e228ccc73"><a class="reference-link" href="#root/pOsGYCXsbNQG/GTwFsgaA0lCt/_help_mULW0Q3VojwY">List View</a>&nbsp;is
supported, allowing to print multiple notes at once while preserving hierarchy
(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
<li data-list-item-id="e879b581c17cf870f98b8f37ae819afc9"><a class="reference-link" href="#root/_help_mULW0Q3VojwY">List View</a>, allowing
to print multiple notes at once while preserving hierarchy (similar to
a book).</li>
<li data-list-item-id="e93230bc1582a7cb07e5ae606dd505486"><a class="reference-link" href="#root/_help_zP3PMqaG71Ct">Presentation</a>,
where each slide/sub-note is displayed.</li>
<li data-list-item-id="ea457b15c29b7dc8b9b1dfa22d6bbcb35"><a class="reference-link" href="#root/pOsGYCXsbNQG/GTwFsgaA0lCt/_help_2FvYrpmOXm29">Table</a>,
where the table is rendered in a print-friendly way.
<ul>
<li data-list-item-id="ed64b8fd7568613fde935f7d1a3cc88a2">Tables that are too complex (especially if they have multiple columns)
might not fit properly, however tables with a large number of rows are
supported thanks to pagination.&nbsp;</li>
<li data-list-item-id="e48fe6df48b7d8b4dd8f71f16167c31f3">Consider printing in landscape mode, or using <code>#printLandscape</code> if
exporting to PDF.</li>
</ul>
</li>
<li data-list-item-id="ea6e788358ba1007f66e3bc29e1e49c12">The rest of the collections are not supported, but we plan to add support
for all the collection types at some point.</li>
</ul>
</li>
<li data-list-item-id="ee721d0145486818bd914a26594699cbd">Using&nbsp;<a class="reference-link" href="#root/_help_AlhDUqhENtH7">Custom app-wide CSS</a>&nbsp;for
<li data-list-item-id="e95bd83615311f18f479a403939dbec58">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.
<ul>
<li data-list-item-id="e2e1228d8d62cbdc8e96a7cbc9655c2ca">We plan to introduce a new mechanism specifically for a print CSS.</li>
<li data-list-item-id="e9e2e9710e9155be07904a540cf0fb763">We plan to introduce a new mechanism specifically for a print CSS.</li>
</ul>
</li>
</ul>
@ -128,10 +139,10 @@ class="admonition note">
printing.</p>
<p>To do so:</p>
<ul>
<li data-list-item-id="ea90c233190428f0aacfcca4abe2f6b18">Create a CSS <a href="#root/_help_6f9hih2hXXZk">code note</a>.</li>
<li data-list-item-id="ec0756dfa1ce83087dd2c9bcc289d234b">On the note being printed, apply the <code>~printCss</code> relation to
<li data-list-item-id="ec8d2d5ae1a26cee897f2b9d56ed7ea32">Create a CSS <a href="#root/_help_6f9hih2hXXZk">code note</a>.</li>
<li data-list-item-id="ea03a880dca8e360a1a2ae108f64d5c68">On the note being printed, apply the <code>~printCss</code> relation to
point to the newly created CSS code note.</li>
<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;
<li data-list-item-id="e9e8ec1b600ea8928a871010e349a2cb4">To apply the CSS to multiple notes, consider using <a href="#root/_help_bwZpz2ajCEwO">inheritable attributes</a> or&nbsp;
<a
class="reference-link" href="#root/_help_KC1HB96bqqHX">Templates</a>.</li>
</ul>
@ -142,11 +153,11 @@ class="admonition note">
}</code></pre>
<p>To remark:</p>
<ul>
<li data-list-item-id="ec7fa7fb43c85ba65185b42a9ed590da7">Multiple CSS notes can be add by using multiple <code>~printCss</code> relations.</li>
<li data-list-item-id="e0d7b17407d4a25fe03ab4a76aea5f9c1">Multiple CSS notes can be add by using multiple <code>~printCss</code> relations.</li>
<li
data-list-item-id="e1db64e345bbaf53151b84a69ff91376f">If the note pointing to the <code>printCss</code> doesn't have the right
data-list-item-id="e5989879c4432018bf90fecc5e31e090b">If the note pointing to the <code>printCss</code> doesn't have the right
note type or mime type, it will be ignored.</li>
<li data-list-item-id="e8b2d24c4a6781c5516d0551f51b3947b">If migrating from a previous version where&nbsp;<a class="reference-link"
<li data-list-item-id="e5536508d3645ba81244d16e75aca8c86">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
the style-sheet is used only for printing.</li>
</ul>

View File

@ -12,22 +12,21 @@
as a single continuous document.</p>
<h2>Interaction</h2>
<ul>
<li data-list-item-id="ee85c9dce1f91b700d8f13bdc9500bc62">Each note can be expanded or collapsed by clicking on the arrow to the
<li>Each note can be expanded or collapsed by clicking on the arrow to the
left of the title.</li>
<li data-list-item-id="e84faa71c2b0bf22a09490b35134f2687">In the&nbsp;<a class="reference-link" href="#root/_help_BlN9DFI679QC">Ribbon</a>,
<li>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
all notes easily.</li>
</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>Since v0.100.0, list collections can be <a href="#root/_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
<li>The table of contents of the PDF will reflect the structure of the notes.</li>
<li>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,5 +1,5 @@
# Documentation
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">
There are multiple types of documentation for Trilium:<img class="image-style-align-right" src="api/images/8e2EXlB1gooL/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 _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers.

View File

@ -4062,66 +4062,73 @@
{
"type": "relation",
"name": "internalLink",
"value": "4TIF1oA4VQRO",
"value": "GTwFsgaA0lCt",
"isInheritable": false,
"position": 40
},
{
"type": "relation",
"name": "internalLink",
"value": "KSZ04uQ2D1St",
"value": "mULW0Q3VojwY",
"isInheritable": false,
"position": 50
},
{
"type": "relation",
"name": "internalLink",
"value": "6f9hih2hXXZk",
"value": "4TIF1oA4VQRO",
"isInheritable": false,
"position": 60
},
{
"type": "relation",
"name": "internalLink",
"value": "GTwFsgaA0lCt",
"value": "KSZ04uQ2D1St",
"isInheritable": false,
"position": 70
},
{
"type": "relation",
"name": "internalLink",
"value": "zP3PMqaG71Ct",
"value": "6f9hih2hXXZk",
"isInheritable": false,
"position": 80
},
{
"type": "relation",
"name": "internalLink",
"value": "AlhDUqhENtH7",
"value": "zP3PMqaG71Ct",
"isInheritable": false,
"position": 90
},
{
"type": "relation",
"name": "internalLink",
"value": "bwZpz2ajCEwO",
"value": "AlhDUqhENtH7",
"isInheritable": false,
"position": 100
},
{
"type": "relation",
"name": "internalLink",
"value": "KC1HB96bqqHX",
"value": "bwZpz2ajCEwO",
"isInheritable": false,
"position": 110
},
{
"type": "relation",
"name": "internalLink",
"value": "0ESUbbAxVnoK",
"value": "KC1HB96bqqHX",
"isInheritable": false,
"position": 120
},
{
"type": "relation",
"name": "internalLink",
"value": "0ESUbbAxVnoK",
"isInheritable": false,
"position": 130
},
{
"type": "label",
"name": "iconClass",
@ -4139,9 +4146,9 @@
{
"type": "relation",
"name": "internalLink",
"value": "mULW0Q3VojwY",
"value": "2FvYrpmOXm29",
"isInheritable": false,
"position": 130
"position": 140
}
],
"format": "markdown",
@ -10472,6 +10479,13 @@
"isInheritable": false,
"position": 20
},
{
"type": "relation",
"name": "internalLink",
"value": "NRnIZmSMc5sj",
"isInheritable": false,
"position": 30
},
{
"type": "label",
"name": "iconClass",
@ -10485,13 +10499,6 @@
"value": "list",
"isInheritable": false,
"position": 30
},
{
"type": "relation",
"name": "internalLink",
"value": "NRnIZmSMc5sj",
"isInheritable": false,
"position": 40
}
],
"format": "markdown",

View File

@ -73,9 +73,12 @@ Not all <a class="reference-link" href="../../Note%20Types.md">Note Types</a> 
* For <a class="reference-link" href="../../Note%20Types/Code.md">Code</a> notes:
* Line numbers are not printed.
* Syntax highlighting is enabled, however a default theme (Visual Studio) is enforced.
* For <a class="reference-link" href="../../Collections.md">Collections</a>:
* <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).
* <a class="reference-link" href="../../Collections/Presentation.md">Presentation</a> is also supported, where each slide/subnote is displayed.
* For <a class="reference-link" href="../../Collections.md">Collections</a>, the following are supported:
* <a class="reference-link" href="../../Collections/List%20View.md">List View</a>, allowing to print multiple notes at once while preserving hierarchy (similar to a book).
* <a class="reference-link" href="../../Collections/Presentation.md">Presentation</a>, where each slide/sub-note is displayed.
* <a class="reference-link" href="../../Collections/Table.md">Table</a>, where the table is rendered in a print-friendly way.
* Tables that are too complex (especially if they have multiple columns) might not fit properly, however tables with a large number of rows are supported thanks to pagination.
* Consider printing in landscape mode, or using `#printLandscape` if exporting to PDF.
* 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.
* We plan to introduce a new mechanism specifically for a print CSS.