Merge branch 'main' of https://github.com/TriliumNext/Trilium into feat/ui-improvements

This commit is contained in:
Adorian Doran 2025-11-03 23:44:18 +02:00
commit dcc5b9f422
112 changed files with 2265 additions and 2203 deletions

View File

@ -10,6 +10,7 @@ on:
paths:
- 'docs/**'
- 'apps/edit-docs/**'
- 'apps/build-docs/**'
- 'packages/share-theme/**'
# Allow manual triggering from Actions tab
@ -23,6 +24,7 @@ on:
paths:
- 'docs/**'
- 'apps/edit-docs/**'
- 'apps/build-docs/**'
- 'packages/share-theme/**'
jobs:
@ -60,6 +62,8 @@ jobs:
- name: Validate Built Site
run: |
test -f site/index.html || (echo "ERROR: site/index.html not found" && exit 1)
test -f site/developer-guide/index.html || (echo "ERROR: site/developer-guide/index.html not found" && exit 1)
echo "✓ User Guide and Developer Guide built successfully"
- name: Deploy
uses: ./.github/actions/deploy-to-cloudflare-pages

View File

@ -14,17 +14,12 @@ import BuildContext from "./context.js";
const DOCS_ROOT = "../../../docs";
const OUTPUT_DIR = "../../site";
async function buildDocsInner() {
const i18n = await import("@triliumnext/server/src/services/i18n.js");
await i18n.initializeTranslations();
async function importAndExportDocs(sourcePath: string, outputSubDir: string) {
const note = await importData(sourcePath);
const sqlInit = (await import("../../server/src/services/sql_init.js")).default;
await sqlInit.createInitialDatabase(true);
const note = await importData(join(__dirname, DOCS_ROOT, "User Guide"));
// Export
const zipFilePath = "output.zip";
// Use a meaningful name for the temporary zip file
const zipName = outputSubDir || "user-guide";
const zipFilePath = `output-${zipName}.zip`;
try {
const { exportToZip } = (await import("@triliumnext/server/src/services/export/zip.js")).default;
const branch = note.getParentBranches()[0];
@ -36,25 +31,50 @@ async function buildDocsInner() {
const fileOutputStream = fsExtra.createWriteStream(zipFilePath);
await exportToZip(taskContext, branch, "share", fileOutputStream);
await waitForStreamToFinish(fileOutputStream);
await extractZip(zipFilePath, OUTPUT_DIR);
// Output to root directory if outputSubDir is empty, otherwise to subdirectory
const outputPath = outputSubDir ? join(OUTPUT_DIR, outputSubDir) : OUTPUT_DIR;
await extractZip(zipFilePath, outputPath);
} finally {
if (await fsExtra.exists(zipFilePath)) {
await fsExtra.rm(zipFilePath);
}
}
}
async function buildDocsInner() {
const i18n = await import("@triliumnext/server/src/services/i18n.js");
await i18n.initializeTranslations();
const sqlInit = (await import("../../server/src/services/sql_init.js")).default;
await sqlInit.createInitialDatabase(true);
// Wait for becca to be loaded before importing data
const beccaLoader = await import("../../server/src/becca/becca_loader.js");
await beccaLoader.beccaLoaded;
// Build User Guide
console.log("Building User Guide...");
await importAndExportDocs(join(__dirname, DOCS_ROOT, "User Guide"), "user-guide");
// Build Developer Guide
console.log("Building Developer Guide...");
await importAndExportDocs(join(__dirname, DOCS_ROOT, "Developer Guide"), "developer-guide");
// Copy favicon.
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "favicon.ico"));
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "user-guide", "favicon.ico"));
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "developer-guide", "favicon.ico"));
console.log("Documentation built successfully!");
}
export async function importData(path: string) {
const buffer = await createImportZip(path);
const importService = (await import("@triliumnext/server/src/services/import/zip.js")).default;
const TaskContext = (await import("@triliumnext/server/src/services/task_context.js")).default;
const importService = (await import("../../server/src/services/import/zip.js")).default;
const TaskContext = (await import("../../server/src/services/task_context.js")).default;
const context = new TaskContext("no-progress-reporting", "importNotes", null);
const becca = (await import("@triliumnext/server/src/becca/becca.js")).default;
const becca = (await import("../../server/src/becca/becca.js")).default;
const rootNote = becca.getRoot();
if (!rootNote) {

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="refresh" content="0; url=/user-guide">
<title>Redirecting...</title>
</head>
<body>
<p>If you are not redirected automatically, <a href="/user-guide">click here</a>.</p>
</body>
</html>

View File

@ -1,7 +1,7 @@
import { join } from "path";
import BuildContext from "./context";
import buildSwagger from "./swagger";
import { existsSync, mkdirSync, rmSync } from "fs";
import { cpSync, existsSync, mkdirSync, rmSync } from "fs";
import buildDocs from "./build-docs";
import buildScriptApi from "./script-api";
@ -21,6 +21,9 @@ async function main() {
await buildDocs(context);
buildSwagger(context);
buildScriptApi(context);
// Copy index file.
cpSync(join(__dirname, "index.html"), join(context.baseDir, "index.html"));
}
main();

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
<aside class="admonition tip">
<p>For a quick start, consult the&nbsp;<a class="reference-link" href="#root/pgxEVkzLl1OP/_help_9qPsTWBorUhQ">API Reference</a>.</p>
<p>For a quick start, consult the&nbsp;<a class="reference-link" href="#root/_help_9qPsTWBorUhQ">API Reference</a>.</p>
</aside>
<p>ETAPI is Trilium's public/external REST API. It is available since Trilium
v0.50.</p>
@ -7,7 +7,7 @@
<p>As an alternative to calling the API directly, there are client libraries
to simplify this</p>
<ul>
<li data-list-item-id="e3342ddfa108f6c8c6c47d7d3da8b02fa"><a href="https://github.com/Nriver/trilium-py">trilium-py</a>, you can
<li><a href="https://github.com/Nriver/trilium-py">trilium-py</a>, you can
use Python to communicate with Trilium.</li>
</ul>
<h2>Obtaining a token</h2>
@ -25,10 +25,10 @@ Authorization: ETAPITOKEN</code></pre>
<p>Since v0.56 you can also use basic auth format:</p><pre><code class="language-text-x-trilium-auto">GET https://myserver.com/etapi/app-info
Authorization: Basic BATOKEN</code></pre>
<ul>
<li data-list-item-id="ec59ac570a3d2a846da38378a5f2428ed">Where <code>BATOKEN = BASE64(username + ':' + password)</code> - this is
<li>Where <code>BATOKEN = BASE64(username + ':' + password)</code> - this is
a standard Basic Auth serialization</li>
<li data-list-item-id="e18e2e73ebecc949dd4a51cd9f8bb0b91">Where <code>username</code> is "etapi"</li>
<li data-list-item-id="ee892223f95cef4a53caec5477ab31edb">And <code>password</code> is the generated ETAPI token described above.</li>
<li>Where <code>username</code> is "etapi"</li>
<li>And <code>password</code> is the generated ETAPI token described above.</li>
</ul>
<p>Basic Auth is meant to be used with tools which support only basic auth.</p>
<h2>Interaction using Bash scripts</h2>
@ -44,10 +44,10 @@ NOTE_ID="i6ra4ZshJhgN"
curl "$SERVER/etapi/notes/$NOTE_ID/content" -H "Authorization: $TOKEN" </code></pre>
<p>Make sure to replace the values of:</p>
<ul>
<li data-list-item-id="e68020f83acc951e180bb405d149a64a5"><code>TOKEN</code> with your ETAPI token.</li>
<li data-list-item-id="ef4c31df5f6d18811e7de0ee8ff95f3a7"><code>SERVER</code> with the correct protocol, host name and port to your
<li><code>TOKEN</code> with your ETAPI token.</li>
<li><code>SERVER</code> with the correct protocol, host name and port to your
Trilium instance.</li>
<li data-list-item-id="e25086bb4c54d32259f987f9366e22204"><code>NOTE_ID</code> with an existing note ID to download.</li>
<li><code>NOTE_ID</code> with an existing note ID to download.</li>
</ul>
<p>As another example, to obtain a .zip export of a note and place it in
a directory called <code>out</code>, simply replace the last statement in

View File

@ -0,0 +1,15 @@
<p>Safe mode is triggered by setting the <code>TRILIUM_SAFE_MODE</code> environment
variable to a truthy value, usually <code>1</code>.</p>
<p>In each artifact there is a <code>trilium-safe-mode.sh</code> (or <code>.bat</code>)
script to enable it.</p>
<p>What it does:</p>
<ul>
<li data-list-item-id="e9c42a70a65d868a17df3413c17b7e6cf">Disables <code>customWidget</code> launcher types in <code>app/widgets/containers/launcher.js</code>.</li>
<li
data-list-item-id="ecd3fb5a4737b444e0c850eaea3877261">Disables the running of <code>mobileStartup</code> or <code>frontendStartup</code> scripts.</li>
<li
data-list-item-id="ea137da7a8e7ea33537b6ccf972a24728">Displays the root note instead of the previously saved session.</li>
<li
data-list-item-id="eae25286d35c9c22f543fddb8475d09aa">Disables the running of <code>backendStartup</code>, <code>hourly</code>, <code>daily</code> scripts
and checks for the hidden subtree.</li>
</ul>

View File

@ -0,0 +1,64 @@
<p>Since TriliumNext 0.94.1, the desktop and server applications can be built
using <a href="https://nixos.org/">Nix</a>.</p>
<h2>System requirements</h2>
<p>Installation of Nix on Mac or Linux (<a href="https://nixos.org/download/">download page</a>).
About 3-4 gigabytes of additional storage space, for build artifacts.</p>
<h2>Run directly</h2>
<p>Using <a href="https://nix.dev/manual/nix/stable/command-ref/new-cli/nix3-run.html">nix run</a>,
the desktop app can be started as: <code>nix run github:TriliumNext/Trilium/v0.95.0</code>
</p>
<p>Running the server requires explicitly specifying the desired package: <code>nix run github:TriliumNext/Trilium/v0.95.0#server</code>
</p>
<p>Instead of a version (<code>v0.95.0</code> above), you can also specify
a commit hash (or a branch name). This makes it easy to test development
builds.</p>
<h2>Install on NixOS</h2>
<p>Add to your <code>flake.nix</code>:</p><pre><code class="language-text-x-trilium-auto">{
inputs = {
nixpkgs.url = # ...;
trilium-notes = {
url = "github:TriliumNext/Trilium/v0.95.0";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
{
self,
# ...
trilium-notes,
...
}:
{
nixosConfigurations = {
"nixos" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
];
specialArgs = {
inherit
trilium-notes
;
};
};
};
};
}
</code></pre>
<p>Add to your <code>configuration.nix</code>:</p><pre><code class="language-text-x-trilium-auto">{
# ...
trilium-notes,
...
}:
{
# ...
services.trilium-server.package = trilium-notes.packages.x86_64-linux.server;
environment.systemPackages = [
trilium-notes.packages.x86_64-linux.desktop
];
}</code></pre>
<p>The flake aims to be compatible with the latest NixOS stable and unstable.</p>

View File

@ -0,0 +1 @@
<p>This is a clone of a note. Go to its <a href="../Desktop%20Installation/Nix%20flake.html">primary location</a>.</p>

View File

@ -1,7 +1,6 @@
<aside class="admonition tip">
<p>For a quick understanding of the Mermaid syntax, see&nbsp;<a class="reference-link"
href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/s1aBHPd79XYj/_help_WWgeUaBb7UfC">Syntax reference</a>&nbsp;(official
documentation).</p>
href="#root/_help_WWgeUaBb7UfC">Syntax reference</a>&nbsp;(official documentation).</p>
</aside>
<figure class="image image-style-align-center">
<img style="aspect-ratio:886/663;" src="2_Mermaid Diagrams_image.png"
@ -15,9 +14,9 @@
<p>Depending on the chart being edited and user preference, there are two
layouts supported by the Mermaid note type:</p>
<ul>
<li data-list-item-id="e5998f20495a1079ee7b6e284dc4d14e4">Horizontal, where the source code (editable part) is on the left side
<li>Horizontal, where the source code (editable part) is on the left side
of the screen and the preview is to the right.</li>
<li data-list-item-id="ebebfbd8cf2125c70056e3e9075d8681e">Vertical, where the source code is at the bottom of the screen and the
<li>Vertical, where the source code is at the bottom of the screen and the
preview is at the top.</li>
</ul>
<p>It's possible to switch between the two layouts at any time by pressing
@ -25,48 +24,44 @@
<img src="Mermaid Diagrams_image.png">icon in the&nbsp;<a class="reference-link" href="#root/_help_XpOYSgsLkTJy">Floating buttons</a>&nbsp;area.</p>
<h2>Interaction</h2>
<ul>
<li data-list-item-id="e67d8f093c4793e19e2ade2d58728ae81">The source code of the diagram (in Mermaid format) is displayed on the
<li>The source code of the diagram (in Mermaid format) is displayed on the
left or bottom side of the note (depending on the layout).
<ul>
<li data-list-item-id="e4d777ef787093815b961d734021ccc55">Changing the diagram code will refresh automatically the diagram.</li>
<li>Changing the diagram code will refresh automatically the diagram.</li>
</ul>
</li>
<li data-list-item-id="e6faf589831e3252f8cda42f62248377a">The preview of the diagram is displayed at the right or top side of the
<li>The preview of the diagram is displayed at the right or top side of the
note (depending on the layout):
<ul>
<li data-list-item-id="e1dc5994137e511eb29657629d9e729a3">There are dedicated buttons at the bottom-right of the preview to control
<li>There are dedicated buttons at the bottom-right of the preview to control
the zoom in, zoom out or re-center the diagram:
<img src="1_Mermaid Diagrams_image.png">
</li>
<li data-list-item-id="e51812ca016db170ceb6814007a60eb10">The preview can be moved around by holding the left mouse button and dragging.</li>
<li
data-list-item-id="e617128e494ed43ca5d0f5c749a8c9208">Zooming can also be done by using the scroll wheel.</li>
<li data-list-item-id="e7b87c55d329003996861f24d8d162b85">The zoom and position on the preview will remain fixed as the diagram
changes, to be able to work more easily with large diagrams.</li>
</ul>
<li>The preview can be moved around by holding the left mouse button and dragging.</li>
<li>Zooming can also be done by using the scroll wheel.</li>
<li>The zoom and position on the preview will remain fixed as the diagram
changes, to be able to work more easily with large diagrams.</li>
</ul>
</li>
<li data-list-item-id="e11cf4ecd9d2408ce5a46b949dea40b06">The size of the source/preview panes can be adjusted by hovering over
<li>The size of the source/preview panes can be adjusted by hovering over
the border between them and dragging it with the mouse.</li>
<li data-list-item-id="ebc96b0fe8366ef4e00561de1c866d53b">In the&nbsp;<a class="reference-link" href="#root/_help_XpOYSgsLkTJy">Floating buttons</a>&nbsp;area:
<li>In the&nbsp;<a class="reference-link" href="#root/_help_XpOYSgsLkTJy">Floating buttons</a>&nbsp;area:
<ul>
<li data-list-item-id="e12f31dc31db3c8be1fe87822ca2f451e">The source/preview can be laid out left-right or bottom-top via the <em>Move editing pane to the left / bottom</em> option.</li>
<li
data-list-item-id="ed29e7616e6c77105103a68b1e8a6f7b3">Press <em>Lock editing</em> to automatically mark the note as read-only.
<li>The source/preview can be laid out left-right or bottom-top via the <em>Move editing pane to the left / bottom</em> option.</li>
<li>Press <em>Lock editing</em> to automatically mark the note as read-only.
In this mode, the code pane is hidden and the diagram is displayed full-size.
Similarly, press <em>Unlock editing</em> to mark a read-only note as editable.</li>
<li
data-list-item-id="e2bc7d5d8d1f8f02e61a6d86a3faae3b4">Press the <em>Copy image reference to the clipboard</em> to be able to insert
the image representation of the diagram into a text note. See&nbsp;<a class="reference-link"
href="#root/_help_0Ofbk1aSuVRu">Image references</a>&nbsp;for more information.</li>
<li
data-list-item-id="ecaac01dc52bce394f720be2826e82026">Press the <em>Export diagram as SVG</em> to download a scalable/vector rendering
of the diagram. Can be used to present the diagram without degrading when
zooming.</li>
<li data-list-item-id="e9c815090884a394d60e06628b9e38add">Press the <em>Export diagram as PNG</em> to download a normal image (at
<li>Press the <em>Copy image reference to the clipboard</em> to be able to insert
the image representation of the diagram into a text note. See&nbsp;<a class="reference-link"
href="#root/_help_0Ofbk1aSuVRu">Image references</a>&nbsp;for more information.</li>
<li>Press the <em>Export diagram as SVG</em> to download a scalable/vector rendering
of the diagram. Can be used to present the diagram without degrading when
zooming.</li>
<li>Press the <em>Export diagram as PNG</em> to download a normal image (at
1x scale, raster) of the diagram. Can be used to send the diagram in more
traditional channels such as e-mail.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>Errors in the diagram</h2>
<p>If there is an error in the source code, the error will be displayed in

View File

@ -253,6 +253,10 @@ async function exportToZip(taskContext: TaskContext<"export">, branch: BBranch,
for (let i = 0; i < targetPath.length - 1; i++) {
const meta = noteIdToMeta[targetPath[i]];
if (meta === rootMeta && format === "share") {
continue;
}
if (meta.dirFileName) {
url += `${encodeURIComponent(meta.dirFileName)}/`;
}
@ -371,10 +375,12 @@ async function exportToZip(taskContext: TaskContext<"export">, branch: BBranch,
}
if (noteMeta.children?.length || 0 > 0) {
const directoryPath = filePathPrefix + noteMeta.dirFileName;
const directoryPath = filePathPrefix !== "" || format !== "share" ? filePathPrefix + noteMeta.dirFileName : "";
// create directory
archive.append("", { name: `${directoryPath}/`, date: dateUtils.parseDateTime(note.utcDateModified) });
if (directoryPath) {
archive.append("", { name: `${directoryPath}/`, date: dateUtils.parseDateTime(note.utcDateModified) });
}
for (const childMeta of noteMeta.children || []) {
saveNote(childMeta, `${directoryPath}/`);

View File

@ -27,6 +27,7 @@ export default class ShareThemeExportProvider extends ZipExportProvider {
private assetsMeta: NoteMeta[] = [];
private indexMeta: NoteMeta | null = null;
private searchIndex: Map<string, SearchIndexEntry> = new Map();
private rootMeta: NoteMeta | null = null;
prepareMeta(metaFile: NoteMetaFile): void {
const assets = [
@ -50,6 +51,7 @@ export default class ShareThemeExportProvider extends ZipExportProvider {
noImport: true,
dataFileName: "index.html"
};
this.rootMeta = metaFile.files[0];
metaFile.files.push(this.indexMeta);
}
@ -58,7 +60,7 @@ export default class ShareThemeExportProvider extends ZipExportProvider {
if (!noteMeta?.notePath?.length) {
throw new Error("Missing note path.");
}
const basePath = "../".repeat(noteMeta.notePath.length - 1);
const basePath = "../".repeat(Math.max(0, noteMeta.notePath.length - 2));
let searchContent = "";
if (note) {
@ -71,6 +73,9 @@ export default class ShareThemeExportProvider extends ZipExportProvider {
if (typeof content === "string") {
content = content.replace(/href="[^"]*\.\/([a-zA-Z0-9_\/]{12})[^"]*"/g, (match, id) => {
if (match.includes("/assets/")) return match;
if (id === this.rootMeta?.noteId) {
return `href="${basePath}"`;
}
return `href="#root/${id}"`;
});
content = this.rewriteFn(content, noteMeta);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
# Developer Guide
This documentation is intended for developers planning to implement new features or maintain the Trilium Notes application, as it describes the architecture of the application.
For the user-facing documentation, including how to write scripts and the various APIs, consult the [user guide](https://docs.triliumnotes.org/user-guide/) instead.

View File

@ -2,7 +2,7 @@
The main workflow of the CI:
* Builds the Docker image and publishes in the GitHub Docker registry.
* Builds using a portion of the [delivery script](../../Build%20deliveries%20locally.md) artifacts for the following platforms:
* Builds using a portion of the [delivery script](../../Building/Build%20deliveries%20locally.md) artifacts for the following platforms:
* Windows `x86_64` as .zip file
* Windows `x86_64` installer (using Squirrel)
* macOS `x86_64` and `aarch64`.

View File

@ -0,0 +1,2 @@
# attributes
<table><thead><tr><th>Column Name</th><th>Data Type</th><th>Nullity</th><th>Default value</th><th>Description</th></tr></thead><tbody><tr><th><code>attributeId</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>Unique Id of the attribute (e.g. <code>qhC1vzU4nwSE</code>), can also have a special unique ID for&nbsp;<a class="reference-link" href="#root/r11Bh3uxFGRj">Special notes</a>&nbsp;(e.g. <code>_lbToday_liconClass</code>).</td></tr><tr><th><code>noteId</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The ID of the <a href="notes.md">note</a> this atttribute belongs to</td></tr><tr><th><code>type</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The type of attribute (<code>label</code> or <code>relation</code>).</td></tr><tr><th><code>name</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The name/key of the attribute.</td></tr><tr><th><code>value</code></th><td>Text</td><td>Non-null</td><td><code>""</code></td><td><ul><li>For <code>label</code> attributes, a free-form value of the attribute.</li><li>For <code>relation</code> attributes, the ID of the <a href="notes.md">note</a> the relation is pointing to.</li></ul></td></tr><tr><th><code>position</code></th><td>Integer</td><td>Non-null</td><td>0</td><td>The position of the attribute compared to the other attributes. Some predefined attributes such as <code>originalFileName</code> have a value of 1000.</td></tr><tr><th><code>utcDateModified</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>Modification date in UTC format (e.g. <code>2023-11-08 16:43:44.204Z</code>)</td></tr><tr><th><code>isDeleted</code></th><td>Integer</td><td>Non-null</td><td>&nbsp;</td><td><code>1</code> if the entity is <a href="../Deleted%20notes.md">deleted</a>, <code>0</code> otherwise.</td></tr><tr><th><code>deleteId</code></th><td>Text</td><td>Nullable</td><td><code>null</code></td><td>&nbsp;</td></tr><tr><th><code>isInheritable</code></th><td>Integer</td><td>Nullable</td><td>0</td><td>&nbsp;</td></tr></tbody></table>

View File

@ -0,0 +1,2 @@
# blobs
<table><thead><tr><th>Column Name</th><th>Data Type</th><th>Nullity</th><th>Default value</th><th>Description</th></tr></thead><tbody><tr><th><code>blobId</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td><p>The unique ID of the blob (e.g. <code>XXbfAJXqWrYnSXcelLFA</code>).</p><aside class="admonition important"><p>The ID is actually a hash of the content, see <code>AbstractBeccaEntity#saveBlob</code>! It is a logic error to modify an existing blob.</p></aside></td></tr><tr><th><code>content</code></th><td>Text</td><td>Nullable</td><td><code>null</code></td><td><p>The content of the blob, can be either:</p><ul><li data-list-item-id="e1f1b8623c64f95f19751bbe494063d0f">text (for plain text notes or HTML notes).</li><li data-list-item-id="e5bbdee6fe5e5b12361fc74e339c9f1db">binary (for images and other types of attachments)</li></ul></td></tr><tr><th><code>dateModified</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>Creation date with timezone offset (e.g. <code>2023-11-08 18:43:44.204+0200</code>)</td></tr><tr><th><code>utcDateModified</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td><p>Creation date in UTC format (e.g. <code>2023-11-08 16:43:44.204Z</code>).</p><p>Blobs cannot be modified, so this timestamp specifies when the blob was created.</p></td></tr></tbody></table>

View File

@ -0,0 +1,22 @@
# Demo document
The demo document is an exported .zip that resides in `apps/server/src/assets/db/demo.zip`.
During on-boarding, if the user selects that they are a new user then the `demo.zip` is imported into the root note.
## Modifying the document
1. In the Git root, run `pnpm edit-docs:edit-demo`.
2. Wait for the desktop application to show up with the docs.
3. Simply make the needed modifications.
4. Wait for a few seconds for the change to be processed in the background.
5. Commit the change in Git.
## Testing the changes
1. Run:
```
rm -r data
pnpm server:start
```
2. And then do the on-boarding again.

View File

@ -21,7 +21,7 @@ These are stored in `images`:
## App icons
<table><thead><tr><th>Name</th><th>Resolution</th><th>Description</th></tr></thead><tbody><tr><td><code>ios/apple-touch-icon.png</code></td><td>180x180</td><td>Used as <code>apple-touch-icon</code>, but only in <code>login.ejs</code> and <code>set_password.ejs</code> for some reason.</td></tr><tr><td><code>mac/icon.icns</code></td><td>512x512</td><td>Provided as <code>--icon</code> to <code>electron-packager</code> for <code>mac-arm64</code> and <code>mac-x64</code> <a href="../Old%20documentation/Build%20deliveries%20locally.md">builds</a>.</td></tr><tr><td><code>png/128x128.png</code></td><td>128x128</td><td>Used in <code>linux-x64</code> <a href="../Old%20documentation/Build%20deliveries%20locally.md">build</a>, to provide an <code>icon.png</code>.</td></tr><tr><td><code>png/256x256-dev.png</code></td><td>256x256</td><td>Used by the Electron window icon, if in dev mode.</td></tr><tr><td><code>png/256x256.png</code></td><td>Used by the Electron window icon, if not in dev mode.</td></tr><tr><td><code>win/icon.ico</code></td><td><ul><li>ICO 16x16</li><li>ICO 32x32</li><li>ICO 48x48</li><li>ICO 64x64</li><li>ICO 128x128</li><li>PNG 256x256</li></ul></td><td><ul><li>Used by the <code>win-x64</code> <a href="../Old%20documentation/Build%20deliveries%20locally.md">build</a>.</li><li>Used by Squirrel Windows installer for: setup icon, app icon, control panel icon</li><li>Used as the favicon.</li></ul></td></tr><tr><td><code>win/setup-banner.gif</code></td><td>640x480</td><td>Used by the Squirrel Windows installer during the installation process. Has only one frame.</td></tr></tbody></table>
<table><thead><tr><th>Name</th><th>Resolution</th><th>Description</th></tr></thead><tbody><tr><td><code>ios/apple-touch-icon.png</code></td><td>180x180</td><td>Used as <code>apple-touch-icon</code>, but only in <code>login.ejs</code> and <code>set_password.ejs</code> for some reason.</td></tr><tr><td><code>mac/icon.icns</code></td><td>512x512</td><td>Provided as <code>--icon</code> to <code>electron-packager</code> for <code>mac-arm64</code> and <code>mac-x64</code> <a href="../Building/Build%20deliveries%20locally.md">builds</a>.</td></tr><tr><td><code>png/128x128.png</code></td><td>128x128</td><td>Used in <code>linux-x64</code> <a href="../Building/Build%20deliveries%20locally.md">build</a>, to provide an <code>icon.png</code>.</td></tr><tr><td><code>png/256x256-dev.png</code></td><td>256x256</td><td>Used by the Electron window icon, if in dev mode.</td></tr><tr><td><code>png/256x256.png</code></td><td>Used by the Electron window icon, if not in dev mode.</td></tr><tr><td><code>win/icon.ico</code></td><td><ul><li>ICO 16x16</li><li>ICO 32x32</li><li>ICO 48x48</li><li>ICO 64x64</li><li>ICO 128x128</li><li>PNG 256x256</li></ul></td><td><ul><li>Used by the <code>win-x64</code> <a href="../Building/Build%20deliveries%20locally.md">build</a>.</li><li>Used by Squirrel Windows installer for: setup icon, app icon, control panel icon</li><li>Used as the favicon.</li></ul></td></tr><tr><td><code>win/setup-banner.gif</code></td><td>640x480</td><td>Used by the Squirrel Windows installer during the installation process. Has only one frame.</td></tr></tbody></table>
## Additional locations where the branding is used

View File

@ -41,7 +41,7 @@ Go to `src/becca/entities/rows.ts` and add the new note type to `ALLOWED_NOTE_TY
## Final steps
* Update the <a class="reference-link" href="../Demo%20document.md">Demo document</a> to showcase the new note type.
* Update the <a class="reference-link" href="../../Demo%20document.md">Demo document</a> to showcase the new note type.
## Troubleshooting

View File

@ -0,0 +1,43 @@
# Options
## Read an option
Add the import to the service (make sure the relative path is correct):
```javascript
import options from "../../services/options.js";
```
Them simply read the option:
```javascript
this.firstDayOfWeek = options.getInt("firstDayOfWeek");
```
## Adding new options
### Checkbox option
Refer to this example in `backup.tsx`:
```javascript
export function AutomaticBackup() {
const [ dailyBackupEnabled, setDailyBackupEnabled ] = useTriliumOptionBool("dailyBackupEnabled");
return (
<OptionsSection title={t("backup.automatic_backup")}>
<FormMultiGroup label={t("backup.automatic_backup_description")}>
<FormCheckbox
name="daily-backup-enabled"
label={t("backup.enable_daily_backup")}
currentValue={dailyBackupEnabled} onChange={setDailyBackupEnabled}
/>
</FormMultiGroup>
<FormText>{t("backup.backup_recommendation")}</FormText>
</OptionsSection>
)
}
```
> [!TIP]
> To trigger a UI refresh (e.g. `utils#reloadFrontendApp`), simply pass a `true` as the second argument to `useTriliumOption` methods.

View File

@ -0,0 +1,18 @@
# Printing and exporting to PDF
Note printing is handled by `note_detail.js`, in the `printActiveNoteEvent` method. Exporting to PDF works similarly.
## How it works
Both printing and exporting as PDF use the same mechanism: a note is rendered individually in a separate webpage that is then sent to the browser or the Electron application either for printing or exporting as PDF.
The webpage that renders a single note can actually be accessed in a web browser. For example `http://localhost:8080/#root/WWRGzqHUfRln/RRZsE9Al8AIZ?ntxId=0o4fzk` becomes `http://localhost:8080/?print#root/WWRGzqHUfRln/RRZsE9Al8AIZ`.
Accessing the print note in a web browser allows for easy debugging to understand why a particular note doesn't render well. The mechanism for rendering is similar to the one used in <a class="reference-link" href="#root/0ESUbbAxVnoK">Note List</a>.
## Syntax highlighting
Syntax highlighting for code blocks is supported as well:
* It works by injecting a Highlight.js stylesheet into the print.
* The theme used is hard-coded (the _Visual Studio Light theme_, at the time of writing) in order not to have a dark background in print.
* <a class="reference-link" href="Syntax%20highlighting.md">Syntax highlighting</a> is handled by the content renderer.

View File

@ -0,0 +1,6 @@
# Protected entities
The following entities can be made protected, via their `isProtected` flag:
* <a class="reference-link" href="Database%20structure/attachments.md">attachments</a>
* <a class="reference-link" href="Database%20structure/notes.md">notes</a>
* <a class="reference-link" href="Database%20structure/revisions.md">revisions</a>

View File

@ -0,0 +1,34 @@
# Build deliveries locally
## Building the desktop
Go to `apps/desktop`, and:
* To generate the packages, run `pnpm electron-forge:make`.
* To only build the Flatpak, run `pnpm electron-forge:make-flatpak`.
* To only build without packaging it, run `pnpm electron-forge:package`.
## Building the server
Go to `apps/server` and run `pnpm package` to run the build script. The built artifacts will appear in `apps/server/dist`, whereas the packaged build will be available in `apps/server/out`.
## On NixOS
Under NixOS the following `nix-shell` is needed:
```
nix-shell -p jq
```
For Linux builds:
```
nix-shell -p jq fakeroot dpkg
```
To test the Linux builds, use `steam-run`:
```javascript
$ NIXPKGS_ALLOW_UNFREE=1 nix-shell -p steam-run
[nix-shell] cd dist/trilium-linux-x64
[nix-shell] steam-run ./trilium
```

View File

@ -0,0 +1,4 @@
# Build information
* Provides context about when the build was made and the corresponding Git revision.
* The information is displayed to the client when going in the about dialog.
* The build information is hard-coded in `apps/server/src/services/build.ts`. This file is generated automatically via `chore:update-build-info` which itself is run automatically whenever making a build in the CI.

View File

@ -0,0 +1,8 @@
# Docker
To build the server for Docker:
* Go to `apps/server` and run:
* `pnpm docker-build-debian` or
* `pnpm docker-build-alpine`.
* Similarly, to build the rootless versions: `pnpm docker-build-rootless-debian` or `pnpm docker-build-rootless-alpine`.
* To not only build but also run the Docker container, simply replace `docker-build` with `docker-start` (e.g. `pnpm docker-start-debian`).

View File

@ -0,0 +1,17 @@
# Documentation
## Automation
The documentation is built via `apps/build-docs`:
1. The output directory is cleared.
2. The User Guide and the Developer Guide are built.
1. The documentation from the repo is archived and imported into an in-memory instance.
2. The documentation is exported using the shared theme.
3. The API docs (internal and ETAPI) are statically rendered via Redocly.
4. The script API is generated via `typedoc`
The `deploy-docs` workflow triggers the documentation build and uploads it to CloudFlare Pages.
## Building locally
In the Git root, run `pnpm docs:build`. The built documentation will be available in `site` at Git root.

View File

@ -0,0 +1,10 @@
# Live reload (HMR)
Trilium uses Vite's HMR (hot module reloading) mechanism.
## Server live reload
If running the server using `pnpm server:start`, the server will watch for changes. For React components, they will be hot-reloaded without requiring a refresh. For other services, it will reload the page.
## Desktop live reload
`pnpm desktop:start` acts the same as `pnpm server:start` with hot-reloading for client-side changes. Changes on the desktop side require a complete re-run of the `pnpm desktop:start` command.

View File

@ -0,0 +1,33 @@
# Running a development build
First, follow the <a class="reference-link" href="../Environment%20Setup.md">Environment Setup</a>.
## Client
The client is not meant to be run by itself, despite being described as an app. See the documentation on the server instead.
## Server
* To run the server in development mode, run `server:start`. The dev port is `8080`.
* To run the server in production mode (with its own copy of the assets), run `server:start-prod`.
* To build for Docker, see <a class="reference-link" href="Docker.md">Docker</a>.
To run with a custom port, change the `TRILIUM_PORT` environment variable from the `package.json`.
## Desktop
* To run in development mode, use `pnpm desktop:start`.
* To run in production mode, use `pnpm desktop:start-prod`.
## Safe mode
Safe mode is off by default, to enable it temporarily on a Unix shell, prepend the environment variable setting:
```
pnpm cross-env TRILIUM_SAFE_MODE=1 pnpm server:start
```
## Running on NixOS
When doing development, the Electron binary retrieved from NPM is not going to be compatible with NixOS, resulting in errors when trying to run it. However Trilium handles it automatically when running `pnpm desktop:start`.
If there's no `electron` the system path it will attempt to use `nix-shell` to obtain it.

View File

@ -1,4 +0,0 @@
# Build information
* Provides context about when the build was made and the corresponding Git revision.
* The information is displayed to the client when going in the about dialog.
* The build information is hard-coded in `src/services/build.ts`. This file is generated automatically via `npm run update-build-info` which itself is run automatically whenever making a build in the CI, or a [local delivery](../Old%20documentation/Build%20deliveries%20locally.md).

View File

@ -1,2 +0,0 @@
# attributes
<table><thead><tr><th>Column Name</th><th>Data Type</th><th>Nullity</th><th>Default value</th><th>Description</th></tr></thead><tbody><tr><th><code>attributeId</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>Unique Id of the attribute (e.g. <code>qhC1vzU4nwSE</code>), can also have a special unique ID for&nbsp;<a class="reference-link" href="../Special%20notes.md">Special notes</a>&nbsp;(e.g. <code>_lbToday_liconClass</code>).</td></tr><tr><th><code>noteId</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The ID of the <a href="notes.md">note</a> this atttribute belongs to</td></tr><tr><th><code>type</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The type of attribute (<code>label</code> or <code>relation</code>).</td></tr><tr><th><code>name</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The name/key of the attribute.</td></tr><tr><th><code>value</code></th><td>Text</td><td>Non-null</td><td><code>""</code></td><td><ul><li>For <code>label</code> attributes, a free-form value of the attribute.</li><li>For <code>relation</code> attributes, the ID of the <a href="notes.md">note</a> the relation is pointing to.</li></ul></td></tr><tr><th><code>position</code></th><td>Integer</td><td>Non-null</td><td>0</td><td>The position of the attribute compared to the other attributes. Some predefined attributes such as <code>originalFileName</code> have a value of 1000.</td></tr><tr><th><code>utcDateModified</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>Modification date in UTC format (e.g. <code>2023-11-08 16:43:44.204Z</code>)</td></tr><tr><th><code>isDeleted</code></th><td>Integer</td><td>Non-null</td><td>&nbsp;</td><td><code>1</code> if the entity is <a href="../Deleted%20notes.md">deleted</a>, <code>0</code> otherwise.</td></tr><tr><th><code>deleteId</code></th><td>Text</td><td>Nullable</td><td><code>null</code></td><td>&nbsp;</td></tr><tr><th><code>isInheritable</code></th><td>Integer</td><td>Nullable</td><td>0</td><td>&nbsp;</td></tr></tbody></table>

View File

@ -1,2 +0,0 @@
# blobs
<table><thead><tr><th>Column Name</th><th>Data Type</th><th>Nullity</th><th>Default value</th><th>Description</th></tr></thead><tbody><tr><th><code>blobId</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The unique ID of the blob (e.g. <code>XXbfAJXqWrYnSXcelLFA</code>).<p>Important: this ID is actually a hash of the content, see <code>AbstractBeccaEntity#saveBlob</code>! It is a logic error to modify an existing blob.</p></td></tr><tr><th><code>content</code></th><td>Text</td><td>Nullable</td><td><code>null</code></td><td><p>The content of the blob, can be either:</p><ul><li>text (for plain text notes or HTML notes).</li><li>binary (for images and other types of attachments)</li></ul></td></tr><tr><th><code>dateModified</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>Creation date with timezone offset (e.g. <code>2023-11-08 18:43:44.204+0200</code>)</td></tr><tr><th><code>utcDateModified</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>Creation date in UTC format (e.g. <code>2023-11-08 16:43:44.204Z</code>).<p>Blobs cannot be modified, so this timestamp specifies when the blob was created.</p></td></tr></tbody></table>

View File

@ -1,19 +0,0 @@
# Demo document
The demo document is an exported .zip that resides in `db/demo.zip`.
During on-boarding, if the user selects that they are a new user then the `demo.zip` is imported into the root note.
## Modifying the document
On a dev server, remove all your existing notes in order to ensure a clean setup. Right click → Import to note and select the .zip file in `db/demo.zip`. Make sure to disable “Safe import”.
After making the necessary modifications, simply export the “Trilium Demo” note as “HTML in ZIP archive” and replace `db/demo.zip` with the newly exported one.
## Testing the changes
```
rm -r data
npm run start-server
```
And then do the on-boarding again.

View File

@ -1,18 +0,0 @@
# Docker
To run a Docker build:
```
./bin/builder-docker.sh
```
To run the built Docker image:
```
sudo docker run -p 8081:8080 triliumnext/trilium:v0.90.6-beta
```
To enter a shell in the Docker container:
```
sudo docker run -it --entrypoint=/bin/sh zadam/trilium:0.63-latest
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 KiB

View File

@ -1,8 +0,0 @@
# Icons on Mac
Looks great in Finder:
<figure class="image"><img src="Icons on Mac_image.png"></figure>
Looks great in Dock:
<figure class="image"><img src="1_Icons on Mac_image.png"></figure>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

View File

@ -1,15 +0,0 @@
# Adaptive icon
| | |
| --- | --- |
| Before | <figure class="image"><img src="1_Adaptive icon_image.png"></figure> |
| After | <figure class="image"><img src="6_Adaptive icon_image.png"></figure> |
| With new scale | <figure class="image"><img src="4_Adaptive icon_image.png"></figure> |
## Scale
| | |
| --- | --- |
| 0.9 | <figure class="image"><img src="2_Adaptive icon_image.png"></figure> |
| 0.85 | <figure class="image"><img src="5_Adaptive icon_image.png"></figure> |
| 0.8 | <figure class="image"><img src="Adaptive icon_image.png"></figure> |
| 0.75 | <figure class="image"><img src="3_Adaptive icon_image.png"></figure> |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -1,50 +0,0 @@
# Slightly blurry icon on Mac
Slightly blurry in extended preview on Mac
<figure class="image"><img src="1_Slightly blurry icon on Ma.png"></figure>
In the screenshot, the icon is around 650px whereas the closest image we have is 512px, so that might explain the blur. Adding an `ic10` (`1024x1024`, aka `512x512@2x` to see what happens).
Before:
```
File: ../images/app-icons/mac/icon.icns
ic09: 62069 bytes, png: 512x512
```
After:
```
File: ../images/app-icons/mac/icon.icns
icp4: 1140 bytes, png: 16x16
icp5: 1868 bytes, png: 32x32
ic07: 9520 bytes, png: 128x128
ic09: 62069 bytes, png: 512x512
ic10: 180442 bytes, png: 512x512@2x
```
Even with a 1024x1024 icon, the image is still blurry.
Comparing the `.icns` file from the Electron build reveals that the `.icns` file has been tampered with:
<table><thead><tr><th>The <code>electron.icns</code> from the resulting build</th><th>The icon source</th></tr></thead><tbody><tr><td><pre><code class="language-text-plain">File: images/app-icons/mac/electron.icns
icp4: 1140 bytes, png: 16x16
icp5: 1868 bytes, png: 32x32
ic07: 9520 bytes, png: 128x128
ic09: 62069 bytes, png: 512x512
ic10: 180442 bytes, png: 512x512@2x</code></pre></td><td><pre><code class="language-text-plain">File: images/app-icons/mac/icon.icns
icp4: 1648 bytes, png: 16x16
icp5: 4364 bytes, png: 32x32
ic07: 26273 bytes, png: 128x128
ic09: 206192 bytes, png: 512x512
ic10: 716034 bytes, png: 512x512@2x</code></pre></td></tr></tbody></table>
The bluriness might come from the image itself: [https://stackoverflow.com/questions/54030521/convert-svg-to-png-with-sharp-edges](https://stackoverflow.com/questions/54030521/convert-svg-to-png-with-sharp-edges) 
Rendering with Inkscape (left) vs ImageMagick (right):
<figure class="image"><img src="2_Slightly blurry icon on Ma.png"></figure>
Now in macOS it's also rendering quite nicely:
<figure class="image"><img src="Slightly blurry icon on Ma.png"></figure>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 KiB

View File

@ -1,27 +0,0 @@
# Removed icons
The following icons were removed:
## Main images
These are stored in `images`:
| Name | Resolution | Description |
| --- | --- | --- |
| `icon-black.png` | 36x36 | Does not appear to be used. |
| `icon-color.png` | 36x36 | Used only by some tests in `test-etapi`. |
| `icon-grey.png` | 36x36 | Does not appear to be used. |
| `icon.svg` | 210x297 | Does not appear to be used. |
## App icons
| Name | Resolution | Description |
| --- | --- | --- |
| `png/16x16-bw.png` | 16x16 | Do not appear to be used. |
| `png/16x16.png` | | |
| `png/24x24.png` | 24x24 | |
| `png/32x32.png` | 32x32 | |
| `png/48x48.png` | 48x48 | |
| `png/64x64.png` | 64x64 | |
| `png/96x96.png` | 96x96 | |
| `png/512x512.png` | 512x512 | Does not appear to be used. |
| `win/setup-banner.xcf` | | GIMP source for `win/setup-banner.gif`. Provided only for future editing. |

View File

@ -1,20 +0,0 @@
# Live reload
## Server live reload
If running the server using `npm run start-server`, the server will watch for changes in `src/public` and trigger a frontend reload if that occurs.
## Electron live reload
Similarly, `npm run start-electron` supports live refresh  as well.
However, a core difference is that Electron watches `dist/src/public` instead of `src/public` since Electron runs on its own copy of the files.
To ameliorate that, a separate watch script has been implemented which automatically copies files from `src/public` to `dist/src/public` whenever a change is detected. To run it:
```
npm run
```
## Technical details
* This mechanism is managed at server level by watching for changes in`services/ws.ts`.

View File

@ -1,30 +0,0 @@
# Note types
The note type is defined by the `type` column in <a class="reference-link" href="Database/notes.md">notes</a>.
Possible types:
<table class="ck-table-resized"><colgroup><col> <col> <col> <col> <col></colgroup><thead><tr><th>Note Type</th><th><code>type</code> value</th><th>Corresponding MIME type</th><th>Content of the note's blob</th><th>Relevant attributes</th></tr></thead><tbody><tr><th>Text</th><td><code>text</code></td><td>&nbsp;</td><td>The HTML of the note.</td><td>&nbsp;</td></tr><tr><th><a href="https://github.com/zadam/trilium/wiki/Relation-map">Relation Map&nbsp;</a></th><td><code>relationMap</code></td><td><code>application/json</code></td><td><p>A JSON describing the note:</p><pre><code class="language-text-plain">{
"notes": [
{
"noteId": "gFQDL11KEm9G",
"x": 142,
"y": 405
},
{
"noteId": "8GcjEKyrrCgl",
"x": 100.10406374385552,
"y": 757.0364424520196
}
],
"transform": {
"scale": 0.3,
"x": 480.29766098682165,
"y": 116.83892021963081
}
}</code></pre></td><td>None</td></tr><tr><th><a href="https://github.com/zadam/trilium/wiki/Scripts">Render Note</a></th><td><code>render</code></td><td><code>text/html</code> or blank.</td><td>An empty blob.</td><td><code>~renderNote</code> pointing to the HTML note to render.</td></tr><tr><th>Canvas</th><td><code>canvas</code></td><td><code>application/json</code></td><td><pre><code class="language-text-plain">{
"appState": {},
"elemenets": {},
"files": {},
"type": "excalidraw",
"version": 2
}</code></pre></td><td>None</td></tr><tr><th>Mermaid Diagram</th><td><code>mermaid</code></td><td><code>text/mermaid</code> or <code>text/plain</code></td><td>The plain text content of the Mermaid diagram.</td><td>None</td></tr><tr><th>Book</th><td><code>book</code></td><td><code>text/html</code> or blank.</td><td>An empty blob.</td><td><ul><li><code>#viewType</code> which can be either <code>grid</code> or <code>list</code>.</li><li><code>#expanded</code></li></ul><p>both options are shown to the user via the “Book Properties” ribbon widget.</p></td></tr><tr><th>Web View</th><td><code>webView</code></td><td>blank</td><td>An empty blob.</td><td><code>#webViewSrc</code> pointing to an URL to render.</td></tr><tr><th>Code</th><td><code>code</code></td><td>Depends on the language (e.g. <code>text/plain</code>, <code>text/x-markdown</code>, <code>text/x-c++src</code>).</td><td>The plain text content.</td><td>&nbsp;</td></tr></tbody></table>

View File

@ -1,14 +0,0 @@
# Options
## Read an option
Add the import to the service (make sure the relative path is correct):
```javascript
import options from "../../services/options.js";
```
Them simply read the option:
```javascript
this.firstDayOfWeek = options.getInt("firstDayOfWeek");
```

View File

@ -1,37 +0,0 @@
# Check box option
In the TPL:
```
<div class="options-section">
<h4>Background effects</h4>
<p>On the desktop application, it's possible to use a semi-transparent background tinted in the colors of the user's wallpaper to add a touch of color.</p>
<div class="col-6 side-checkbox">
<label class="form-check">
<input type="checkbox" class="background-effects form-check-input" />
Enable background effects (Windows 11 only)
</label>
</div>
</div>
```
In `doRender()`:
```
doRender() {
this.$backgroundEffects = this.$widget.find("input.background-effects");
this.$backgroundEffects.on("change", () => this.updateCheckboxOption("backgroundEffects", this.$backgroundEffects));
}
```
In `optionsLoaded(options)`:
```
async optionsLoaded(options) {
this.setCheckboxState(this.$backgroundEffects, options.backgroundEffects);
}
```

View File

@ -1,36 +0,0 @@
# Displaying the option in settings
Go to `src/public/app/widgets/type_widgets/options` and select a corresponding category, such as `appearance` and edit one of the JS files.
For example, to create a select:
First, modify the template (`TPL`), to add the new widget:
```
<div class="col-6">
<label>First day of the week</label>
<select class="first-day-of-week-select form-control">
<option value="0">Sunday</option>
<option value="1">Monday</option>
</select>
</div>
```
Secondly, create a reference to the new element in `doRender()`:
```
this.$firstDayOfWeek = this.$widget.find(".first-day-of-week-select");
```
Then in `optionsLoaded` adjust the value to the one set in the database:
```
this.$firstDayOfWeek.val(options.firstDayOfWeek);
```
To actually update the option, add a listener in `doRender`:
```
this.$firstDayOfWeek.on("change", () => {
this.updateOption("firstDayOfWeek", this.$firstDayOfWeek.val());
});
```

View File

@ -1,10 +0,0 @@
# Refresh widget with option change
To make a widget react to a change of a given option, simply add the following to the widget:
```javascript
async entitiesReloadedEvent({loadResults}) {
if (loadResults.getOptionNames().includes("firstDayOfWeek")) {
// Do something.
}
}
```

View File

@ -1,12 +0,0 @@
# Trigger UI refresh
Call `utils.reloadFrontendApp`, but make sure to wait for the option to be saved first.
```
this.$backgroundEffects.on("change", async () => {
await this.updateCheckboxOption("backgroundEffects", this.$backgroundEffects);
utils.reloadFrontendApp("background effect change");
});
```

View File

@ -1,15 +0,0 @@
# Printing
Note printing is handled by `note_detail.js`, in the `printActiveNoteEvent` method.
The application uses the [`print-this`](https://www.npmjs.com/package/print-this) library to isolate `.note-detail-printable:visible` and prepare it for printing.
Some scripts like KaTeX are manually injected in the footer, and the CSS to be used is manually defined. The most important one is `print.css`.
## Syntax highlighting
Syntax highlighting for code blocks is supported as well:
* It works by injecting a Highlight.js stylesheet into the print.
* The theme used is hard-coded (the _Visual Studio Light theme_, at the time of writing) in order not to have a dark background in print.
* The Highlight.js library is not needed since the `.note-detail-printable` which is rendered already has the `.hljs` classes added to it in order to achieve the syntax highlighting.
* The user's choice of whether to enable syntax highlighting is also respected.

View File

@ -1,6 +0,0 @@
# Protected entities
The following entities can be made protected, via their `isProtected` flag:
* <a class="reference-link" href="Database/attachments.md">attachments</a>
* <a class="reference-link" href="Database/notes.md">notes</a>
* <a class="reference-link" href="Database/revisions.md">revisions</a>

View File

@ -26,8 +26,11 @@ As a quick heads-up of some differences when compared to `npm`:
Run `pnpm i` at the top of the `Notes` repository to install the dependencies.
> [!NOTE]
> Dependencies are kept up to date periodically in the project. Generally it's a good rule to do `pnpm i` after each `git pull` on the main branch.
## IDE
Our recommended IDE for working on TriliumNext is Visual Studio Code (or VSCodium if you are looking for a fully open-source alternative).
Our recommended IDE for working on Trilium is Visual Studio Code (or VSCodium if you are looking for a fully open-source alternative).
By default we include a number of suggested extensions which should appear when opening the repository in VS Code. Most of the extensions are for integrating various technologies we are using such as Playwright and Vitest for testing and NX for mono-repo management.
By default we include a number of suggested extensions which should appear when opening the repository in VS Code. Most of the extensions are for integrating various technologies we are using such as Playwright and Vitest for testing or for <a class="reference-link" href="Architecture/Internationalisation%20%20Translat.md">Internationalisation / Translations</a>.

View File

@ -1,32 +0,0 @@
# Build deliveries locally
In the project root:
| Platform | Architecture | Application | Build command |
| --- | --- | --- | --- |
| macOS | x86\_64 | Desktop / Electron app | `./bin/build-mac-x64.sh` |
| ARM 64 | Desktop / Electron app | `./bin/build-mac-arm64.sh` | |
| Linux | x86\_64 | Desktop / Electron app | `./bin/build-linux-x64.sh` |
| Server | `./bin/build-server.sh` | | |
| Windows | x86\_64 | Desktop / Electron app | `./bin/build-win-x64.sh` |
Under NixOS the following `nix-shell` is needed:
```
nix-shell -p jq
```
For Linux builds:
```
nix-shell -p jq fakeroot dpkg
```
The resulting build will be in the `dist` directory under the project root.
### Testing the Linux builds under NixOS
<table><thead><tr><th>Desktop client</th><th>Server</th></tr></thead><tbody><tr><td><pre><code class="language-text-plain">$ NIXPKGS_ALLOW_UNFREE=1 nix-shell -p steam-run
[nix-shell] cd dist/trilium-linux-x64
[nix-shell] steam-run ./trilium</code></pre></td><td><pre><code class="language-text-plain">$ NIXPKGS_ALLOW_UNFREE=1 nix-shell -p steam-run
[nix-shell] cd dist/trilium-linux-x64-server
[nix-shell] steam-run ./trilium.sh</code></pre></td></tr></tbody></table>

View File

@ -1,2 +0,0 @@
# Build deliveries locally
This is a clone of a note. Go to its [primary location](../Build%20deliveries%20locally.md).

View File

@ -1,34 +0,0 @@
# Documentation
Development notes are published on [triliumnext.github.io/Notes](https://triliumnext.github.io/Notes) by the CI using GitHub Pages.
The GitHub Pages deployment works by taking the files from the Notes repository, in the `docs` directory.
## How it works
There is a script that uses `wget` to download all the files from a share, that means:
1. You must have a local instance of Trilium Notes server.
2. You must have the documentation imported, up to date and shared.
Note that currently the documentation source file is not distributed (the note export), until a way is found to automate this process. Contact `eliandoran` should you require to obtain a copy of the documentation.
## Setting up `.env` file
Go to `bin/docs` and copy `.env.example` to `.env` and edit it:
1. Change the `SHARE_PROTOCOL` to either `http` or `https` depending on your setup.
2. Change `SHARE_HOST` to match the domain name or the URL to the host (without the protocol or any slashes).
Generally `ROOT_NOTE_ID` should not be changed since the note ID must match if the files were imported correctly.
## Triggering a build
Run:
```
./bin/docs/prepare.sh
```
This will attempt to download all the notes from the share URL and put them in `docs`, rewritten for GitHub Pages.
Commit the results and follow the normal development process to push them.

View File

@ -1,2 +0,0 @@
# Releasing a version
This is a clone of a note. Go to its [primary location](../Releasing%20a%20version.md).

View File

@ -1,2 +0,0 @@
# Running a development build
This is a clone of a note. Go to its [primary location](../Running%20a%20development%20build.md).

View File

@ -1,116 +0,0 @@
# Adding a new client library
In the past some libraries have been copy-pasted (and adapted if needed) to the repository. However, new libraries must be obtained exclusively through npm.
The first step is to install the desired library. As an example we are going to install `i18next`:
```
npm i i18next
```
### Step 1. Understanding the structure of the import
After installing the dependency, it's important to know how it's structured. You can do this by looking at the directory structure of the newly imported dependency:
```
$ tree node_modules/i18next
node_modules/i18next
├── dist
│ ├── cjs
│ │ └── i18next.js
│ ├── esm
│ │ ├── i18next.bundled.js
│ │ ├── i18next.js
│ │ └── package.json
│ └── umd
│ ├── i18next.js
│ └── i18next.min.js
├── i18next.js
├── i18next.min.js
├── index.d.mts
├── index.d.ts
├── index.js
├── index.v4.d.ts
├── LICENSE
├── package.json
├── README.md
└── typescript
├── helpers.d.ts
├── options.d.ts
├── t.d.ts
└── t.v4.d.ts
```
Generally you should be looking for a `.min.js` file. Note that the `esm` and `cjs` variants generally don't work, we are looking for the classic, no module dependency.
### Step 2. Exposing the library from the server
The library must be delivered by the server and this is done via `src/routes/assets.ts`. In the `register` function, add a new entry near the bottom of the function:
```javascript
app.use(`/${assetPath}/node_modules/i18next/`, persistentCacheStatic(path.join(srcRoot, "..", 'node_modules/i18next/')));
```
### Step 3. Adding it to the library loader
The library loader is a client module which is in charge of downloading the library from the server and importing it. The loader is located in `src/public/app/services/library_loader.js`.
To add a new library, start by creating a constant for it, with the value pointing to the minified JS identified at the first step:
```javascript
const I18NEXT = {
js: [
"node_modules/i18next/i18next.min.js"
]
};
```
Then add it to the `export default` section:
```diff
export default {
requireCss,
requireLibrary,
CKEDITOR,
CODE_MIRROR,
ESLINT,
RELATION_MAP,
PRINT_THIS,
CALENDAR_WIDGET,
KATEX,
WHEEL_ZOOM,
FORCE_GRAPH,
MERMAID,
EXCALIDRAW,
- MARKJS
+ MARKJS,
+ I18NEXT
}
```
### Step 4. Using the library
To import the library, simply use the following mechanism:
```diff
import library_loader from "./library_loader.js";
await library_loader.requireLibrary(library_loader.I18NEXT);
```
Make sure to replace `I18NEXT` with the library that was created at the previous steps.
Note that because we are not using a module management mechanism such as ES Modules or Common.js modules, the `requireLibrary` method does not actually return anything. 
To benefit from the library, it must export on its own an object in `window`.
In the case of `i18next`, it sets `window.i18next` and that can be used directly:
```diff
i18next.init({});
```
### Step 5. Adding Electron support
For Electron, the `node_modules` are copied as a separate step by `bin/copy-dist.ts`.
Scroll all the way down to the `nodeModulesFolder` and append an entry for the newly added libraries.

View File

@ -1,8 +0,0 @@
# Having a simpler packaging system
The current build scripts are a bit complicated and maintaining them is not easy.
[Electron Forge](https://www.electronforge.io/) seems more mature and has a boatload of features, including Flatpak, snaps, Windows installers & more.
Have a look also at the [Plugins](https://www.electronforge.io/config/plugins) section since there are quite a few interesting things there as well.
Afterwards consider running a new round of <a class="reference-link" href="#root/GAP7blNiSoX3/ftdNqJtBT1RD">Reducing binary size</a>, especially taking into consideration removing of the unnecessary locales.

Some files were not shown because too many files have changed in this diff Show More