this will now end up in "src/public/app-dist/excalidraw/fonts/"
excalidraw *needs* the fonts to be in a folder called "fonts" as it appends the "EXCALIDRAW_ASSET_PATH" variable with "fonts" automatically -> therefore switch names around to fix the issue
* remove useless symlinks to non-existing files (npm, npx -> the actual file gets deleted by "rm -r $BUILD_DIR/node/lib/node_modules/npm"
=> fixes#1499
(this time fully ;-))
* remove unused corepack
* remove useless CHANGELOG.md (LICENSE and README.md should of course still remain)
all of its functionality has been "absorbed" by the cross-platform copy-dist and cleanupNodeModules scripts, that can be used for all of our builds now
this is necessary, since for Docker and electron-forge, we need to run this as an extra step after copy-dist
for electron-forge: after it is done with its own "pruning", as we otherwise would need to also take care of certain electron related pruning
for Docker: as a last step in the build stage
* image-q/demo -> doesn't exist anymore (and even if it did - previous cleanup step, would've removed this anyways)
* @excalidraw/excalidraw/dist/* -> updated to point to the dev folder
* boxicons -> only fonts and css folders are used, so remove the other ones
* jimp -> updated paths and removed non-existent path
fixing here for historical reasons, next step is to move these over to copy-dist.ts
previously this was loaded from the node_modules folder and was exposed via a static asset path
-> since we got rid of this with the last commit, we need to instead let webpack bundle it "importing" the css here
=> rename css class name to match upstream
the class name got changed from ".mind-elixir → .map-container" by upstream via 294c2d5bb0
partially addresses #1464 → this allows us to see the node-menu sidebar again
%~dp0 always contains a trailing backslash. The way %DIR% is used in the following line, the trailing slash should be stripped. Alternatively, `%DIR%\\` may be replaced with `%DIR%`, but I would advice against. It is ok to have `%~dp0trilium-data`, which is a conventional pattern. Once %~dp0 is replaced with %DIR% (which is not really warranted here), stripping the trailing slash right after assignment is preferable.
electron-forge does not like, if we get rid of devDeps ourselves already it seems.
It *wants* to do it itself, otherwise build fails…
It does seem to correctly strip all the devDeps though, at least there's that.
since we build TS and webpack ourselves and are not using any electron-forge plugins (at least at the moment) -> we should use the "build" folder as build context for electron-forge:
in comparison to running electron-forge in the root folder of the project, this avoids electron-forge from packing the source code multiple times (e.g. once as uncompiled TS, then as compiled JS, and then (partially) a third time as webpack bundled JS files), same as some of the assets.
to achieve this, we run our usual TS/Webpack build process, but then install the npm dependencies *inside* the build folder (as otherwise electron-forge would choke on the missing node_modules it and abort building).
In theory we could avoid cd-ing into the build folder, by providing the "dir" as argument to electron-forge's CLI -- BUT that wouldn't play well with our CI, where we are passing --arch and --platform options to it, which need to come *before* the dir argument.
since we now cd into the "build" folder, we also need to adjust the path in package.json "main" again
if we don't exit, it will just log the issue - however we *want* it to fail it there is an error, so that it doesn't continue in the CI
alternative would be to rethrow the error, but then we'd print the error into the logs twice :-)
closes https://github.com/TriliumNext/Notes/issues/1413
this is caused by recently reverting the output of "build:prepare-dist" from "dist" to "build"
-> this is just a temporary fix -> I am working in parallel already on an improved electron-forge build process, whihc will be ready by end of the week
this will allow for cleaner separation -> build for the output from the build stage (i.e. TS/Webpack + asset copying) and dist for the archive format of the build folder
in this case using "{}" allows all primitive values, which seems to be what is required here.
so let's disable the rule "@typescript-eslint/no-empty-object-type" for this line
this is now handled fully inside Docker.
exception for "test_docker" job in "main-docker"
-> it seems that one needs to be there still, since it runs Playwright tests from outside the container
same changes as for the "non-alpine" Dockerfile previously commited, but adapted to Alpine.
this Dockerfile is aimed at production builds, i.e. trying to keep size as small as possible at the cost of "rebuild speed", due to missed docker cache opportunities.
Build Stage:
* do the complete build inside docker as oposed to the previous "hybrid", where tsc was run locally and the output got copied into the Docker build stage → you can now build this with Docker, without having to install the whole node/TS env locally
* build into a "build" subfolder, for easier clean up during build stage
* get rid of now unnecessary extra file/asset handling, as this is now handled by `npm run build:prepare-dist`
* no `npm prune` needed here, as we delete the whole build folder anyways in the last build step
Runtime stage:
* move the "electron" dep removal from the builder stage to the runtime stage, before installing the dependencies
* move to `npm ci` for reproducible installations – but only installing runtime deps here
* get rid of now unnecessary copying commands from the builder stage, as everything is now neatly available in "/usr/src/app"
this Dockerfile is aimed at production builds, i.e. trying to keep size as small as possible at the cost of "rebuild speed", due to missed docker cache opportunities.
Build Stage:
* do the complete build inside docker as oposed to the previous "hybrid", where tsc was run locally and the output got copied into the Docker build stage → you can now build this with Docker, without having to install the whole node/TS env locally
* build into a "build" subfolder, for easier clean up during build stage
* get rid of now unnecessary extra file/asset handling, as this is now handled by `npm run build:prepare-dist`
* no `npm prune` needed here, as we delete the whole build folder anyways in the last build step
Runtime stage:
* move the "electron" dep removal from the builder stage to the runtime stage, before installing the dependencies
* move to `npm ci` for reproducible installations – but only installing runtime deps here
* get rid of now unnecessary copying commands from the builder stage, as everything is now neatly available in "/usr/src/app"
there's no benefit from stripping "node_modules/" from the string, to later add it again using the `DEST_DIR_NODE_MODULES` constant
=> just copy directly into the `DEST_DIR` folder and preserver the `node_modules` part in the path
stop the build folder from being copied into the dist/src subfolder
→ there is no sense in doing that
→ the contents of the build folder are corretly copied previously already (see line 26ff)
since we build into the build folder -> we should also clean the folder before building as well
also it makes sense to run tsc first, as it runs faster, so if there's any TS errors, we will have a faster failing build
as per https://webpack.js.org/configuration/devtool/#production
serving the `source-map` file to "normal" users seems to be not recommended, so instead let's go with `nosources-source-map`:
a) this drastically reduces app-dist folder size from 20MB down to 8.7MB
b) it still allows for stack traces
this prevents tsc from unnecessarily transpiling the frontend part as well:
previously it was transpiled by tsc, but the files got discarded and replaced by the files built by webpack.
speeds up tsc command a bit as well:
from 14 seconds to ~8 secs
since it is not used in server side code and it is bundled by webpack, it is only needed during build stage -> devDependency
on server-side we use i18next and i18next-fs-backend -> so these need to stay in dependencies
since we don't export the full i18n object (not sure why?),
I had to add an additional export "getCurrentLanguage"
-> needs to be a function, because otherwise it will be a static value (being set to undefined),
which is *not* what we want
commented out for now, because it currently does not make sense yet.
This will be working, when I change webpack output to the "build" folder
instead of the current (messy) way, where it outputs into src/public/app-dist
@@ -37,6 +37,7 @@ Feel free to join our official conversations. We would love to hear what feature
* Fast and easy [navigation between notes](https://triliumnext.github.io/Docs/Wiki/note-navigation), full text search and [note hoisting](https://triliumnext.github.io/Docs/Wiki/note-hoisting)
* Note [attributes](https://triliumnext.github.io/Docs/Wiki/attributes) can be used for note organization, querying and advanced [scripting](https://triliumnext.github.io/Docs/Wiki/scripts)
* Direct OpenID and TOTP integration for more secure login
* [Synchronization](https://triliumnext.github.io/Docs/Wiki/synchronization) with self-hosted sync server
* there's a [3rd party service for hosting synchronisation server](https://trilium.cc/paid-hosting)
* [Sharing](https://triliumnext.github.io/Docs/Wiki/sharing) (publishing) notes to public internet
To use TriliumNext on a mobile device, you can use a mobile web browser to access the mobile interface of a server installation (see below).
* Use a mobile web browser to access the mobile interface of a server installation (see below)
* Use of a mobile app is not yet supported ([see here](https://github.com/TriliumNext/Notes/issues/72)) to track mobile improvements.
If you prefer a native Android app, you can use [TriliumDroid](https://apt.izzysoft.de/fdroid/index/apk/eu.fliegendewurst.triliumdroid). Report bugs and missing features at [their repository](https://github.com/FliegendeWurst/TriliumDroid).
See issue https://github.com/TriliumNext/Notes/issues/72 for more information on mobile app support.
### Server
@@ -107,7 +109,8 @@ npm run server:start
### Documentation
Head on over to our [Docs repo](https://github.com/TriliumNext/Docs)
We are currently transitioning to a new documentation mechanism.
Meanwhile you can still view the [archived Docs repository](https://github.com/TriliumNext/Docs).
description: "This is the internal sync server API used by Trilium Notes / TriliumNext Notes.\n\n_If you're looking for the officially supported External Trilium API, see [here](https://triliumnext.github.io/Docs/Wiki/etapi.html)._\n\nThis page does not yet list all routes. For a full list, see the [route controller](https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/routes.ts).",
"This is the internal sync server API used by Trilium Notes / TriliumNext Notes.\n\n_If you're looking for the officially supported External Trilium API, see [here](https://triliumnext.github.io/Docs/Wiki/etapi.html)._\n\nThis page does not yet list all routes. For a full list, see the [route controller](https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/routes.ts).",
for(constnoteIdofsql.getColumn(`SELECT noteId FROM note_contents`)){
constrow=sql.getRow(`SELECT noteId, content, dateModified, utcDateModified FROM note_contents WHERE noteId = ?`,[noteId]);
for(constnoteIdofsql.getColumn<string>(`SELECT noteId FROM note_contents`)){
constrow=sql.getRow<NoteContentsRow>(`SELECT noteId, content, dateModified, utcDateModified FROM note_contents WHERE noteId = ?`,[noteId]);
constblobId=utils.hashedBlobId(row.content);
if(!existingBlobIds.has(blobId)){
@@ -28,7 +41,7 @@ module.exports = () => {
}
for(constnoteRevisionIdofsql.getColumn(`SELECT noteRevisionId FROM note_revision_contents`)){
constrow=sql.getRow(`SELECT noteRevisionId, content, utcDateModified FROM note_revision_contents WHERE noteRevisionId = ?`,[noteRevisionId]);
constrow=sql.getRow<NoteRevisionContents>(`SELECT noteRevisionId, content, utcDateModified FROM note_revision_contents WHERE noteRevisionId = ?`,[noteRevisionId]);
constblobId=utils.hashedBlobId(row.content);
if(!existingBlobIds.has(blobId)){
@@ -44,7 +57,7 @@ module.exports = () => {
sql.execute("UPDATE entity_changes SET entityName = 'blobs', entityId = ? WHERE entityName = 'note_revision_contents' AND entityId = ?",[blobId,row.noteRevisionId]);
}else{
// duplicates
sql.execute("DELETE FROM entity_changes WHERE entityName = 'note_revision_contents' AND entityId = ?",[row.noteId]);
sql.execute("DELETE FROM entity_changes WHERE entityName = 'note_revision_contents' AND entityId = ?",[row.noteRevisionId]);
}
sql.execute("UPDATE note_revisions SET blobId = ? WHERE noteRevisionId = ?",[blobId,row.noteRevisionId]);
Trilium offers advanced functionality through [Scripts](../Note%20Types/Code/Scripts.md) and [Promoted Attributes](Attributes/Promoted%20Attributes.md). To illustrate these features, we've prepared several showcases available in the [demo notes](Database.md):
It's important to note that these examples are not natively supported by Trilium out of the box; instead, they demonstrate what you can build within Trilium.
A common pattern in note-taking is that a lot of notes will be centered around a certain date - e.g. you have some tasks which needs to be done on a certain date, you have meeting minutes from a certain date, you have your thoughts etc. and it all revolves around a date on which they occurred. For this reason, it makes sense to create a certain "day workspace" which will centralize all those notes relevant for a certain date.
For this, Trilium provides a concept of "day note". Trilium semi-automatically generates a single note for each day. Under this note you can save all those relevant notes.
Select an existing day note, and the menubar contains a calendar widget. Select any day to create a note for that day.

This pattern works well also because of [Cloning Notes](../../Basic%20Concepts%20and%20Features/Notes/Cloning%20Notes.md) functionality - note can appear in multiple places in the note tree, so besides appearing under day note, it can also be categorized into other notes.
## Demo

You can see the structure of day notes appearing under "Journal" note - there's a note for the whole year 2017, under it, you have "12 - December" which then contains "18 - Monday". This is our "day note" which contains some text in its content and also has some child notes (some of them are from [Task manager](Task%20Manager.md)).
You can also notice how this day note has [promoted attribute](../Attributes/Promoted%20Attributes.md) "weight" where you can track your daily weight. This data is then used in [Weight tracker](Weight%20Tracker.md).
## Templates
Trilium provides [template](../Attributes/Template.md) functionality, and it could be used together with day notes.
You can define one of the following relations on the root of the journal (identified by `#calendarRoot` label):
* yearTemplate
* monthTemplate
* dateTemplate
All of these are relations. When Trilium creates a new note for year or month or date, it will take a look at the root and attach a corresponding `~template` relation to the newly created role. Using this, you can e.g. create your daily template with e.g. checkboxes for daily routine etc.
## Date pattern
It's possible to customize the title of generated date notes by defining a `#datePattern` label on a root calendar note (identified by `#calendarRoot` label). Following are possible values:
*`{dayInMonthPadded} - {weekDay}` day notes are named e.g. "24 - Monday"
*`{dayInMonthPadded}: {weekDay3}` day notes are named e.g. "24: Mon"
*`{dayInMonthPadded}: {weekDay2}` day notes are named e.g. "24: Mo"
*`{isoDate} - {weekDay}` day notes are named e.g. "2020-12-24 - Monday"
*`{ordinal}` is replaced with the ordinal date (e.g. 1st, 2nd, 3rd) etc.
## Month pattern
It is also possible to customize the title of generated month notes through the `#monthPattern` attribute, much like `#datePattern`. The options are:
*`{isoMonth}` results in an ISO 8061 formatted month (e.g. "2025-03" for March 2025)
*`{monthNumberPadded}` results in a number like `09` for September, and `11` for November
*`{month}` results in the full month name (e.g. `September` or `October`)
*`{shortMonth3}` is replaced with the first 3 letters of the month, e.g. Jan, Feb, etc.
*`{shortMonth4}` is replaced with the first 4 letters of the month, e.g. Sept, Octo, etc.
The default is `{monthNumberPadded} - {month}`
## Implementation
Trilium has some special support for day notes in the form of [backend Script API](https://triliumnext.github.io/Notes/backend_api/BackendScriptApi.html) - see e.g. getDayNote() function.
Day (and year, month) notes are created with a label - e.g. `#dateNote="2018-08-16"` this can then be used by other scripts to add new notes to day note etc.
Journal also has relation `child:child:child:template=Day template` (see \[\[attribute inheritance\]\]) which effectively adds \[\[template\]\] to day notes (grand-grand-grand children of Journal).
Task Manager is a [promoted attributes](../Attributes/Promoted%20Attributes.md) and [scripts](../../Note%20Types/Code/Scripts.md)showcase present in the [demo notes](../Database.md).
## Demo

Task Manager manages outstanding (TODO) tasks and finished tasks (non-empty doneDate attribute). Outstanding tasks are further categorized by location and arbitrary tags - whenever you change tag attribute in the task note, this task is then automatically moved to appropriate location.
Task Manager also integrates with [day notes](Day%20Notes.md) - notes are [cloned](../../Basic%20Concepts%20and%20Features/Notes/Cloning%20Notes.md) into day note to both todoDate note and doneDate note (with [prefix](../../Basic%20Concepts%20and%20Features/Navigation/Tree%20Concepts.md) of either "TODO" or "DONE").
## Implementation
New tasks are created in the TODO note which has `~child:template` [relation](../Attributes.md)(see [attribute inheritance](../Attributes/Attribute%20Inheritance.md)) pointing to the task template.
### Attributes
Task template defines several [promoted attributes](../Attributes/Promoted%20Attributes.md) - todoDate, doneDate, tags, location. Importantly it also defines `~runOnAttributeChange` relation - [event](../../Note%20Types/Code/Events.md) handler which is run on attribute change. This [script](../../Note%20Types/Code/Scripts.md) handles when e.g. we fill out the doneDate attribute - meaning the task is done and should be moved to "Done" note and removed from TODO, locations and tags.
### New task button
There's also "button" note which contains simple script which adds a button to create new note (task) in the TODO note.
```
api.addButtonToToolbar({
title: 'New task',
icon: 'check',
shortcut: 'alt+n',
action: async () => {
// creating notes is backend (server) responsibility so we need to pass
// we got an ID of newly created note and we want to immediatelly display it
await api.activateNewNote(taskNoteId);
}
});
```
### CSS
In the demo screenshot above you may notice that TODO tasks are in red color and DONE tasks are green.
This is done by having this CSS [code note](../../Note%20Types/Code.md) which defines extra CSS classes:
```
span.fancytree-node.todo .fancytree-title {
color: red !important;
}
span.fancytree-node.done .fancytree-title {
color: green !important;
}
```
This [code note](../../Note%20Types/Code.md) has `#appCss` [label](../Attributes.md)which is recognized by Trilium on startup and loaded as CSS into the application.
Second part of this functionality is based in event handler described above which assigns `#cssClass` label to the task to either "done" or "todo" based on the task status.
The `Weight Tracker` is a [Script API](../../Note%20Types/Code/Script%20API.md) showcase present in the [demo notes](../Database.md).
By adding `weight` as a [promoted attribute](../Attributes/Promoted%20Attributes.md) in the [template](../Attributes/Template.md) from which [day notes](Day%20Notes.md) are created, you can aggregate the data and plot weight change over time.
## Implementation
The `Weight Tracker` note in the screenshot above is of the type `Render Note`. That type of note doesn't have any useful content itself. Instead it is a placeholder where a [script](../../Note%20Types/Code/Scripts.md) can render its output.
Scripts for `Render Notes` are defined in a [relation](../Attributes.md) called `~renderNote`. In this example, it's the `Weight Tracker`'s child `Implementation`. The Implementation consists of two [code notes](../../Note%20Types/Code.md) that contain some HTML and JavaScript respectively, which load all the notes with a `weight` attribute and display their values in a chart.
To actually render the chart, we're using a third party library called [chart.js](https://www.chartjs.org/)which is imported as an attachment, since it's not built into Trilium.
### Code
Here's the content of the script which is placed in a [code note](../../Note%20Types/Code.md) of type `JS Frontend`:
## How to remove the Weight Tracker button from the top bar
In the link map of the `Weight Tracker`, there is a note called `Button`. Open it and delete or comment out its contents. The `Weight Tracker` button will disappear after you restart Trilium.
In Trilium, attributes are key-value pairs assigned to notes, providing additional metadata or functionality. There are two primary types of attributes:
1.**Labels**: Simple key-value text records
2.**Relations**: Named links to other notes
These attributes play a crucial role in organizing, categorising, and enhancing the functionality of notes.

## Labels
Labels in Trilium can be used for a variety of purposes:
***Metadata**: Assign labels with optional values for categorization, such as `#year=1999`, `#genre="sci-fi"`, or `#author="Neal Stephenson"`
***Configuration**: Labels can configure advanced features or settings
***Scripts and Plugins**: Used to tag notes with special metadata, such as the "weight" attribute in the [Weight Tracker](Advanced%20Showcases/Weight%20Tracker.md)
Labels are also searchable, enhancing note retrieval.
### Common Labels for Advanced Configuration
*`**disableVersioning**`: Disables automatic versioning, ideal for large, unimportant notes like script libraries
*`**versioningLimit**`: Used to limit the number of revisions for a single note
*`**calendarRoot**`: Marks the note as the root for [day notes](Advanced%20Showcases/Day%20Notes.md). Only one note should carry this label
*`**archived**`: Hides notes from default search results and dialogs
*`**excludeFromExport**`: Excludes notes and their subtrees from export operations
*`**run**`: Specifies events to trigger scripts (e.g., `frontendStartup`, `hourly`)
*`**runAtHour**`: Defines specific hours for scripts to run, used with `#run=hourly`
*`**disableInclusion**`: Prevents a script from being included in parent script executions
*`**sorted**`: Automatically sorts child notes alphabetically by title
*`**top**`: Keeps the note at the top of its parent's list, useful with `sorted`
*`**hidePromotedAttributes**`: Hides certain attributes in the note's display
*`**readOnly**`: Sets the note to read-only mode, applicable to text and code notes
*`**autoReadOnlyDisabled**`: Disables automatic read-only mode for large notes
*`**appCss**`: Marks CSS notes used to modify Trilium’s appearance
*`**appTheme**`: Marks full CSS themes available in Trilium's options
*`**cssClass**`: Adds a CSS class to the note's representation in the tree
*`**iconClass**`: Adds a CSS class to the note's icon, useful for distinguishing notes visually. See [note icons](../Basic%20Concepts%20and%20Features/Notes/Note%20Icons.md)
*`**pageSize**`: Specifies the number of items per page in note listings
*`**customRequestHandler**`**and**`**customResourceProvider**`: Refer to [Custom request handler](Custom%20Request%20Handler.md)
*`**widget**`: Marks a note as a custom widget, added to Trilium's component tree
*`**workspace**`**and related attributes**: See [Workspace](../Basic%20Concepts%20and%20Features/Navigation/Workspace.md) for more details
*`**searchHome**`: Specifies the parent for new search notes
*`**inbox**`: Designates a default location for new notes created via the sidebar
*`**sqlConsoleHome**`: Default location for SQL console notes
*`**bookmarked**`**and**`**bookmarkFolder**`: See [Bookmarks](../Basic%20Concepts%20and%20Features/Navigation/Bookmarks.md)
*`**shareXXX**`: See [Sharing](Sharing.md)
*`**keyboardShortcut**`: Assigns a keyboard shortcut to open the note
*`**displayRelations**`**and**`**hideRelations**`: Manages the display of note relations
*`**titleTemplate**`: See [Default note title](Default%20Note%20Title.md)
*`**template**`: Makes the note available as a template
*`**toc**`: Controls the visibility of the table of contents
*`**color**`: Defines the color of the note in the tree and links
*`**hideChildrenOverview**`: Hides child notes in the parent note's editor
*`**viewType**`: Sets the view of child notes (grid or list)
## Relations
Relations define connections between notes, similar to links.
### Uses
***Metadata Relationships**: For example, linking a book note to an author note
***Scripting**: Attaching scripts to events or conditions related to the note
### Common Relations
***Event-based Relations**: Such as `runOnNoteCreation` or `runOnNoteChange`, which trigger scripts on specific actions
***Other Relations**: Include `template`, `renderNote`, `widget`, and sharing-related relations
## Multiplicity
Attributes in Trilium can be "multivalued", meaning multiple attributes with the same name can coexist.
## Attribute Definitions and Promoted Attributes
Special labels create "label/attribute" definitions, enhancing the organization and management of attributes. For more details, see [Promoted attributes](Attributes/Promoted%20Attributes.md).
## Attribute Inheritance
Trilium supports attribute inheritance, allowing child notes to inherit attributes from their parents. For more information, see [Attribute inheritance](Attributes/Attribute%20Inheritance.md).
In Trilium, attributes can be automatically inherited by child notes if they have the `isInheritable` flag set to `true`. This means the attribute (a key-value pair) is applied to the note and all its descendants.
### Example Use Case
The `archived` label can be set to be inheritable, allowing you to hide a whole subtree of notes from searches and other dialogs by applying this label at the top level.
## 2\. Copying Inheritance
Copying inheritance differs from standard inheritance by using a `child:` prefix in the attribute name. This prefix causes new child notes to automatically receive specific attributes from the parent note. These attributes are independent of the parent and will persist even if the note is moved elsewhere.
### How to Use
***Syntax:**`#child:attributeName`
***Chained Inheritance:** You can chain this inheritance, such as `#child:child:attributeName`, where each child down the hierarchy receives the appropriate attribute.
### Example
If a parent note has the label `#child:exampleAttribute`, all newly created child notes will inherit the `#exampleAttribute` label. This can be useful for setting default properties for notes in a specific section.
## 3\. Template Inheritance
Attributes can also be inherited from [templates](Template.md). When a new note is created using a template, it inherits the attributes defined in that template. This is particularly useful for maintaining consistency across notes that follow a similar structure or function.
Promoted attributes are [attributes](../Attributes.md) which are considered important and thus are "promoted" onto the main note UI. See example below:

You can see the note having kind of form with several fields. Each of these is just regular attribute, the only difference is that they appear on the note itself.
Attributes can be pretty useful since they allow for querying and script automation etc. but they are also inconveniently hidden. This allows you to select few of the important ones and push them to the front of the user.
Now, how do we make attribute to appear on the UI?
## Attribute definition
Attribute is always name-value pair where both name and value are strings.
_Attribute definition_ specifies how should this value be interpreted - is it just string, or is it a date? Should we allow multiple values or note? And importantly, should we _promote_ the attribute or not?

You can notice tag attribute definition. These "definition" attributes define how the "value" attributes should behave.
So there's one attribute for value and one for definition. But notice how definition attribute is [Inheritable](Attribute%20Inheritance.md), meaning that it's also applied to all descendant note. So in a way, this definition is used for the whole subtree while "value" attributes are applied only for this note.
### Inverse relation
Some relations always occur in pairs - my favorite example is on the family. If you have a note representing husband and note representing wife, then there might be a relation between those two of `isPartnerOf`. This is bidirectional relationship - meaning that if a relation is pointing from husband to wife then there should be always another relation pointing from wife to husband.
Another example is with parent - child relationship. Again these always occur in pairs, but in this case it's not exact same relation - the one going from parent to child might be called `isParentOf` and the other one going from child to parent might be called `isChildOf`.
Relation definition allows you to specify such "inverse relation" - for the relation you just define you specify which is the inverse relation. Note that in the second example we should have two relation definitions - one for `isParentOf` which defines `isChildOf` as inverse relation and then second relation definition for `isChildOf` which defines `isParentOf` as inverse relation.
What this does internally is that whenever we save a relation which has defined inverse relation, we check that this inverse relation exists on the relation target note. Similarly, when we delete relation, we also delete inverse relation on the target note.
A template in Trilium serves as a predefined structure for other notes, referred to as instance notes. Assigning a template to a note brings three main effects:
1.**Attribute Inheritance**: All attributes from the template note are [inherited](Attribute%20Inheritance.md) by the instance notes. Even attributes with `#isInheritable=false` are inherited by the instance notes, although only inheritable attributes are further inherited by the children of the instance notes.
2.**Content Duplication**: The content of the template note is copied to the instance note, provided the instance note is empty at the time of template assignment.
3.**Child Note Duplication**: All child notes of the template are deep-duplicated to the instance note.
## Example
A typical example would be a "Book" template note, which might include:
***Promoted Attributes**: Such as publication year, author, etc. (see [promoted attributes](Promoted%20Attributes.md)).
***Outline**: An outline for a book review, including sections like themes, conclusion, etc.
***Child Notes**: Additional notes for highlights, summary, etc.
An instance note is a note related to a template note. This relationship means the instance note's content is initialized from the template, and all attributes from the template are inherited.
For the template to appear in the menu, the template note must have the `#template` label. Do not confuse this with the `~template` relation, which links the instance note to the template note. If you use [workspaces](../../Basic%20Concepts%20and%20Features/Navigation/Workspace.md), you can also mark templates with `#workspaceTemplate` to display them only in the workspace.
Templates can also be added or changed after note creation by creating a `~template` relation pointing to the desired template note.
## Additional Notes
From a visual perspective, templates can define `#iconClass` and `#cssClass` attributes, allowing all instance notes (e.g., books) to display a specific icon and CSS style.
Explore the concept further in the [demo notes](../Database.md), including examples like the [Relation Map](../../Note%20Types/Relation%20Map.md), [Task Manager](../Advanced%20Showcases/Task%20Manager.md), and [Day Notes](../Advanced%20Showcases/Day%20Notes.md).
Additionally, see [default note title](../Default%20Note%20Title.md) for creating title templates. Note templates and title templates can be combined by creating a `#titleTemplate` for a template note.
# Configuration (config.ini or environment variables)
Trilium supports configuration via a file named `config.ini` and environment variables. Please review the file named [config-sample.ini](https://github.com/TriliumNext/Notes/blob/develop/config-sample.ini) in the [Notes](https://github.com/TriliumNext/Notes) repository to see what values are supported.
You can provide the same values via environment variables instead of the `config.ini` file, and these environment variables use the following format:
1. Environment variables should be prefixed with `TRILIUM_` and use underscores to represent the INI section structure.
2. The format is: `TRILIUM_<SECTION>_<KEY>=<VALUE>`
3. The environment variables will override any matching values from config.ini
For example, if you have this in your config.ini:
```
[Network]
host=localhost
port=8080
```
You can override these values using environment variables:
```
TRILIUM_NETWORK_HOST=0.0.0.0
TRILIUM_NETWORK_PORT=9000
```
The code will:
1. First load the `config.ini` file as before
2. Then scan all environment variables for ones starting with `TRILIUM_`
3. Parse these variables into section/key pairs
4. Merge them with the config from the file, with environment variables taking precedence
Trilium provides a mechanism for [scripts](../Note%20Types/Code/Scripts.md) to open a public REST endpoint. This opens a way for various integrations with other services - a simple example would be creating new note from Slack by issuing a slash command (e.g. `/trilium buy milk`).
## Create note from outside Trilium
Let's take a look at an example. The goal is to provide a REST endpoint to which we can send title and content and Trilium will create a note.
We'll start with creating a JavaScript backend [code note](../Note%20Types/Code.md) containing:
```
const {req, res} = api;
const {secret, title, content} = req.body;
if (req.method == 'POST' && secret === 'secret-password') {
// notes must be saved somewhere in the tree hierarchy specified by a parent note.
// This is defined by a relation from this code note to the "target" parent note
// alternetively you can just use constant noteId for simplicity (get that from "Note Info" dialog of the desired parent note)
This script note has also following two attributes:
* label `#customRequestHandler` with value `create-note`
* relation `~targetNote` pointing to a note where new notes should be saved
### Explanation
Let's test this by using an HTTP client to send a request:
```
POST http://my.trilium.org/custom/create-note
Content-Type: application/json
{
"secret": "secret-password",
"title": "hello",
"content": "world"
}+++++++++++++++++++++++++++++++++++++++++++++++
```
Notice the `/custom` part in the request path - Trilium considers any request with this prefix as "custom" and tries to find a matching handler by looking at all notes which have `customRequestHandler` [label](Attributes.md). Value of this label then contains a regular expression which will match the request path (in our case trivial regex "create-note").
Trilium will then find our code note created above and execute it. `api.req`, `api.res` are set to [request](https://expressjs.com/en/api.html#req) and [response](https://expressjs.com/en/api.html#res)objects from which we can get details of the request and also respond.
In the code note we check the request method and then use trivial authentication - keep in mind that these endpoints are by default totally unauthenticated, and you need to take care of this yourself.
Once we pass these checks we will just create the desired note using [Script API](../Note%20Types/Code/Script%20API.md).
## Custom resource provider
Another common use case is that you want to just expose a file note - in such case you create label `customResourceProvider` (value is again path regex).
For more information, see[Custom Resource Providers](Custom%20Resource%20Providers.md).
## Advanced concepts
`api.req` and `api.res` are Express.js objects - you can always look into its [documentation](https://expressjs.com/en/api.html) for details.
### Parameters
REST request paths often contain parameters in the URL, e.g.:
```
http://my.trilium.org/custom/notes/123
```
The last part is dynamic so the matching of the URL must also be dynamic - for this reason the matching is done with regular expressions. Following `customRequestHandler` value would match it:
```
notes/([0-9]+)
```
Additionally, this also defines a matching group with the use of parenthesis which then makes it easier to extract the value. The matched groups are available in `api.pathParams`:
```
const noteId = api.pathParams[0];
```
Often you also need query params (as in e.g. `http://my.trilium.org/custom/notes?noteId=123`), you can get those with standard express `req.query.noteId`.
A custom resource provider allows any file imported into Trilium (images, fonts, stylesheets) to be publicly accessible via a URL.
A potential use case for this is to add embed a custom font alongside a theme.
## Steps for creating a custom resource provider
1. Import a file such as an image or a font into Trilium by drag & drop.
2. Select the file and go to the _Owned Attributes_ section.
3. Add the label `#customResourceProvider=hello`.
4. To test if it is working, use a browser to navigate to `<protocol>://<host>/custom/hello` (where `<protocol>` is either `http` or `https` based on your setup, and `<host>` is the host or IP to your Trilium server instance). If you are running the TriliumNext application without a server, use `http://localhost:37840` as the base URL.
5. If everything went well, at the previous step the browser should have downloaded the file uploaded in the first step.
Instead of `hello`, the name can be:
* A path, such as `fonts/Roboto.ttf`, which would be accessible via `<host>/custom/fonts/Roboto.ttf`.
* As a more advanced use case, a regular expression to match multiple routes, such as `hello/.*` which will be accessible via `/custom/hello/1`, `/custom/hello/2`, `/custom/hello/world`, etc.
## Using it in a theme
For example, if you have a custom font to be imported by the theme, first upload a font file into Trilium and assign it the `#customResourceProvider=fonts/myfont.ttf` attribute.
Your Trilium data is stored in a [SQLite](https://www.sqlite.org) database which contains all notes, tree structure, metadata, and most of the configuration. The database file is named `document.db` and is stored in the application's default[Data directory](../Installation%20%26%20Setup/Data%20directory.md).
## Demo Notes
When you run Trilium for the first time, it will generate a new database containing demo notes. These notes showcase its many features, such as:
There are some cases in which you may want to restore the original demo notes. For example, if you experimented with some of the more advanced features and want to see the original reference, or if you simply want to explore the latest version of the demo notes, which might showcase new features.
You can easily restore the demo notes by using Trilium's built-in import feature by importing them:
* Download [this .zip archive](https://github.com/TriliumNext/Notes/raw/develop/db/demo.zip) with the latest version of the demo notes
* Right click on any note in your tree under which you would like the demo notes to be imported
* Click "Import into note"
* Select the .zip archive to import it
## Manually Modifying the Database
Trilium provides a lot of flexibility, and with it, opportunities for advanced users to tweak it. If you need to explore or modify the database directly, you can use a tool such as [SQLite Browser](https://sqlitebrowser.org/) to work directly on the database file.
See[Manually altering the database](Database/Manually%20altering%20the%20database.md)for more information.
## How to Reset the Database
If you are experimenting with Trilium and want to return it to its original state, you can do that by deleting the current database. When you restart the application, it will generate a new database containing the original demo notes.
To delete the database, simply go to the [data directory](../Installation%20%26%20Setup/Data%20directory.md) and delete the `document.db` file (and any other files starting with `document.db`).
If you do not need to preserve any configurations that might be stored in the `config.ini` file, you can just delete all of the [data directory's](../Installation%20%26%20Setup/Data%20directory.md) contents to fully restore the application to its original state. You can also review the [configuration](Configuration%20\(config.ini%20or%20e.md) file to provide all `config.ini` values as environment variables instead.
There are some situations where modifying the SQLite database that Trilium uses is desirable.
If you are doing any advanced development or troubleshooting where you manually modify the database, you might want to consider creating backups of your `document.db` file.
## Modifying it internally using the SQL Console
The SQL Console is Trilium's built-in database editor.
Sometimes the SQL Console cannot be used (for example if the application cannot start).
When making external modifications, consider closing the desktop application. If modifying the server database, then stop the service or Docker container.
### Using DB Browser for SQLite
DB Browser for SQLite is a cross-platform editor that can be used to alter the database using a graphical user interface.
To do so:
1. In the main menu, select File → Open database… and navigate to the database in the[Data directory](../../Installation%20%26%20Setup/Data%20directory.md).
2. Select the _Execute SQL_ tab.
3. Type in the desired SQL statement.
4. Press the "Play" button in the toolbar underneath the "Execute SQL" tab (or F5 key).
5. Press "Write Changes" in the main toolbar.
6. Close the application or close the database.

### Using the SQLite CLI
First, start the SQLite 3 CLI by specifying the path to the database:
```
sqlite3 ~/.local/share/trilium-data/document.db
```
* In the prompt simply type the statement and make sure it ends with a `;` character.
The SQL Console is Trilium's built-in database editor.
It can be accessed by going to the [global menu](../../../Basic%20Concepts%20and%20Features/UI%20Elements) → Advanced → Open SQL Console.

### Interaction
* Hovering the mouse over one of the tables listed at the top of the document will show the columns and their data type.
* Only one SQL statement can be run at once.
* To run the statement, press the icon.
* For queries that return a result, the data will displayed in a table.

### Saved SQL console
SQL queries or commands can be saved into a dedicated note.
To do so, simply write the query and press the button. Once saved, the note will appear in[Day Notes](../../Advanced%20Showcases/Day%20Notes.md).
* The SQL expression will not be displayed by default, but it can still be viewed by going to the note context menu and selecting _Note source_.
* The expression cannot be modified. If needed, recreate it by copying the statement back into the SQL console and then saving it again.
When a new note is created, its name is by default "new note". In some cases, it can be desirable to have a different or even a dynamic default note title.
For this use case, Trilium (since v0.52) supports `#titleTemplate` [label](Attributes.md). You can create such a label for a given note, assign it a value, and this value will be used as a default title when creating child notes. As with other labels, you can make it inheritable to apply recursively, and you can even place it on the root note to have it applied globally everywhere.
As an example use case, imagine you collect books you've read in a given year like this:
* 2022 Books
* Neal Stephenson: Anathem, 2008
* Franz Kafka: Die Verwandlung, 1915
Now, to the parent note "2022 Books" you can assign label `#titleTemplate="[Author name]: [Book title], [Publication year]"`.
And all children of "2022 Books" will be created with initial title "\[Author name\]: \[Book title\], \[Publication year\]". There's no artificial intelligence here, the idea is to just prompt you to manually fill in the pieces of information into the note title by yourself.
## Dynamic value
The value of `#titleTemplate` is evaluated at the point of note's creation as a JavaScript string, which means it can be enriched with the help of JS string interpolation with dynamic data.
As an example, imagine you collect server outage incidents and write some notes. It looks like this:
* Incidents
* 2022-05-09: System crash
* 2022-05-15: Backup delay
You can automatize the date assignment by assigning a label `#titleTemplate="${now.format('YYYY-MM-DD')}: "` to the parent note "Incidents". Whenever a new child note is created, the title template is evaluated with the injected [now](https://day.js.org/docs/en/display/format) object.
Second variable injected is [parentNote](https://triliumnext.github.io/Notes/backend_api/BNote.html), an example could be `#titleTemplate="${parentNote.getLabelValue('authorName')}'s literary works"`.
See also \[\[[template](Attributes/Template.md)\]\] which provides similar capabilities, including default note's content.
ETAPI is Trilium's public/external REST API. It is available since Trilium v0.50.
The documentation is in OpenAPI format, available [here](https://github.com/TriliumNext/Notes/blob/master/src/etapi/etapi.openapi.yaml).
## API clients
As an alternative to calling the API directly, there are client libraries to simplify this
* [trilium-py](https://github.com/Nriver/trilium-py), you can use Python to communicate with Trilium.
## Authentication
All operations have to be authenticated using a token. You can get this token either from Options -> ETAPI or programmatically using the `/auth/login` REST call (see the [spec](https://github.com/TriliumNext/Notes/blob/master/src/etapi/etapi.openapi.yaml)):
```
GET https://myserver.com/etapi/app-info
Authorization: ETAPITOKEN
```
Alternatively, since 0.56 you can also use basic auth format:
```
GET https://myserver.com/etapi/app-info
Authorization: Basic BATOKEN
```
* Where `BATOKEN = BASE64(username + ':' + password)` - this is a standard Basic Auth serialization
* Where `username` is "etapi"
* And `password` is the generated ETAPI token described above.
Basic Auth is meant to be used with tools which support only basic auth.
## Interaction using Bash scripts
It is possible to write simple Bash scripts to interact with Trilium. As an example, here's how to obtain the HTML content of a note:
Note map is a visualisation of connections between notes.
This provides an insight into a structure ("web") of notes.
There are two types of note map:
* Link Map, which shows relations between notes.
* Note Map, which shows the hierarchical tree structure.
## Link Map
Shows [relations](Attributes.md) between notes:

## Tree Map
Shows hierarchical map of notes:

## Dedicated note type
Apart from the note map feature which can be accessed from any note, it is also possible to create a dedicated note which will display the relations in full screen. See[Note Map](../Note%20Types/Note%20Map.md)for more information.
## See also
[Relation map](../Note%20Types/Relation%20Map.md) is a similar concept, with some differences:
* note map is automatically generated while relation map must be created manually
* relation map is a type of note while a link map is just virtual visualization
## Understanding the source code of the different notes
Internally, the structure of the content of each note is different based on the[Note Types](../Note%20Types).
For example:
* [Text Notes](#root/_hidden/_options/_optionsTextNotes)are represented internally as HTML, using the[CKEditor](Technologies%20used/CKEditor.md)representation. Note that due to the custom plugins, some HTML elements are specific to Trilium only, for example the admonitions.
* [Code Notes](#root/_hidden/_options/_optionsCodeNotes)are plain text and are represented internally as-is.
* [Geo map](../Note%20Types/Geo%20map.md)notes contain only minimal information (viewport, zoom) as a JSON.
* [Canvas](../Note%20Types/Canvas.md)notes are represented as JSON, with Trilium's own information alongside with[Excalidraw](Technologies%20used/Excalidraw.md)'s internal JSON representation format.
* [Mind Map](../Note%20Types/Mind%20Map.md)notes are represented as JSON, with the internal format of[MindElixir](Technologies%20used/MindElixir.md).
Note that some information is also stored as[Attachments](../Attachments). For example[Canvas](../Note%20Types/Canvas.md)notes use the attachments feature to store the custom libraries, and alongside with[Mind Map](../Note%20Types/Mind%20Map.md)and other similar note types it stores an SVG representation of the content for use in other features such as including in other notes, shared notes, etc.
Here's part of the HTML representation of this note, as it's stored in the database (but prettified).
```html
<h2>
Understanding the source code of the different notes
</h2>
<p>
Internally, the structure of the content of each note is different based on the
<aclass="reference-link"href="../Note%20Types">
Note Types
</a>
.
</p>
```
## Viewing the source code
It is possible to view the source code of a note by pressing the contextual menu in[Note buttons](../Basic%20Concepts%20and%20Features/UI%20Elements/Note%20buttons.md)and selecting _Note source_.

The source code will be displayed in a new tab.
For some note types, such as text notes, the source code is also formatted in order to be more easily readable.
## Modifying the source code
It is possible to modify the source code of a note directly, however not via the _Note source_ functionality.
To do so:
1. Change the note type from the real note type (e.g. Canvas, Geo Type) to Code (plain text) or the corresponding format such as JSON or HTML.
2. Confirm the warning about changing the note type.
3. The source code will appear, make the necessary modifications.
4. Change the note type back to the real note type.
> [!WARNING]
> Depending on the changes made, there is a risk that the note will not render properly. It's best to save a revision before making any big changes.
>
> If the note does not render properly, modify the source code again or revert to a prior revision. Since the error handling for unexpected changes might not always be perfect, it be required to refresh the application.
Trilium allows you to share selected notes as **publicly accessible** read-only documents. This feature is particularly useful for publishing content directly from your Trilium notes, making it accessible to others online.
## Prerequisites
To use the sharing feature, you must have a [server installation](../Installation%20%26%20Setup/Server%20Installation.md) of Trilium. This is necessary because the notes will be hosted from the server.
## How to Share a Note
1.**Enable Sharing**: To share a note, toggle the `Shared` switch within the note's interface. Once sharing is enabled, an URL will appear, which you can click to access the shared note.
2.**Access the Shared Note**: The link provided will open the note in your browser. If your server is not configured with a public IP, the URL will refer to `localhost (127.0.0.1)`.
When you share a note, you actually share the entire subtree of notes beneath it. If the note has child notes, they will also be included in the shared content. For example, sharing the "Formatting" subtree will display a page with basic navigation for exploring all the notes within that subtree.
You can view a list of all shared notes by clicking on "Show Shared Notes Subtree." This allows you to manage and navigate through all the notes you have made public.
## Security Considerations
Shared notes are published on the open internet and can be accessed by anyone with the URL. The URL's randomness does not provide security, so it is crucial not to share sensitive information through this feature.
### Password Protection
To protect shared notes with a username and password, you can use the `#shareCredentials` attribute. Add this label to the note with the format `#shareCredentials="username:password"`. To protect an entire subtree, make sure the label is [inheritable](Attributes/Attribute%20Inheritance.md).
## Advanced Sharing Options
### Customizing the Appearance of Shared Notes
The default shared page is basic in design, but you can customize it using your own CSS:
***Custom CSS**: Link a CSS [code note](../Note%20Types/Code.md) to the shared page by adding a `~shareCss` relation to the note. If you want this style to apply to the entire subtree, make the label inheritable. You can hide the CSS code note from the tree navigation by adding the `#shareHiddenFromTree` label.
***Omitting Default CSS**: For extensive styling changes, use the `#shareOmitDefaultCss` label to avoid conflicts with Trilium's [default stylesheet](../Basic%20Concepts%20and%20Features/Themes.md).
### Adding JavaScript
You can inject custom JavaScript into the shared note using the `~shareJs` relation. This allows you to access note attributes or traverse the note tree using the `fetchNote()` API, which retrieves note data based on its ID.
Shared notes typically have URLs like `http://domain.tld/share/knvU8aJy4dJ7`, where the last part is the note's ID. You can make these URLs more user-friendly by adding the `#shareAlias` label to individual notes (e.g., `#shareAlias=highlighting`). This will change the URL to `http://domain.tld/share/highlighting`.
**Important**:
1. Ensure that aliases are unique.
2. Using slashes (`/`) within aliases to create subpaths is not supported.
### Viewing and Managing Shared Notes
All shared notes are grouped under an automatically managed "Shared Notes" section. From here, you can view, share, or unshare notes by moving or cloning them within this section.
To customize the favicon for your shared pages, create a relation `~shareFavicon` pointing to a file note containing the favicon (e.g., in `.ico` format).
### Sharing a Note as the Root
You can designate a specific note or folder as the root of your shared content by adding the `#shareRoot` label. This note will be linked when visiting `[http://domain.tld/share](http://domain/share)`, making it easier to use Trilium as a fully-fledged website. Consider combining this with the `#shareIndex` label, which will display a list of all shared notes.
## Additional Options
***Raw Note Sharing**: Use the `#shareRaw` label to share a note without any HTML wrapper.
***Disallow Robot Indexing**: Add the `#shareDisallowRobotIndexing` label to prevent search engines from indexing the shared page by including a `noindex, follow` meta tag and `X-Robots-Tag: noindex` header.
***Shared Notes Index**: For text notes with the `#shareIndex` label, the content will display a list of all shared note roots.
## Limitations
While the sharing feature is powerful, it has some limitations:
***No Relation Map Support**
***Book Notes**: Only show a list of child notes.
***Code Notes**: No syntax highlighting.
***Static Note Tree**
***Protected Notes**: Cannot be shared.
***Include Notes**: Not supported.
Some of these limitations may be addressed in future updates.
When accessing a shared note, Trilium will render it as a web page. Sometimes it's desirable to serve the content directly so that it can be used in a script or downloaded by the user.
| A note displayed as a web page (HTML) | A note displayed as a raw format |
One core aspect of Trilium that allows it to have support for multiple[Note Types](../Note%20Types)is the fact that it makes use of various off-the-shelf or reusable libraries.
The sub-pages showcase some of the technologies used, for a better understanding of how Trilium works but also to credit the developers of that particular technology.
The CKEditor is the WYSIWYG (standing for What You See Is What You Get) editor behind[Text](../../Note%20Types/Text.md)notes.
Their website is [ckeditor.com](https://ckeditor.com/).
CKEditor by itself is a commercial product, but the core is open-source. As described in [its documentation](https://ckeditor.com/docs/ckeditor5/latest/features/index.html), the editor supports quite a large number of features. Do note that not all the features are enabled in Trilium.
## Premium features
Some features are marked as premium in the CKEditor feature set. This means that they cannot be used without a license.
Trilium cannot benefit from any of these premium features as they require a commercial license, however we are in discussions with the CKEditor team to allow us to use a subset of these premium features such as [Slash commands](https://ckeditor.com/docs/ckeditor5/latest/features/slash-commands.html).
## Plugins
The CKEditor ecosystem is quite extensible, in the sense that custom plugins can be written to extend the functionality of the editor beyond its original scope.
Trilium makes use of such features:
* The math feature is added by a version of [isaul32/ckeditor5-math: Math feature for CKEditor 5.](https://github.com/isaul32/ckeditor5-math) modified by us to fit our needs.
* We also make use of modified upstream plugins such as [ckeditor/ckeditor5-mermaid](https://github.com/ckeditor/ckeditor5-mermaid) to allow inline Mermaid code.
* [mlewand/ckeditor5-keyboard-marker: Plugin adds support for the keyboard input element (<kbd>) to CKEditor 5.](https://github.com/mlewand/ckeditor5-keyboard-marker)
* A modified version of [ThomasAitken/ckeditor5-footnotes: Footnotes plugin for CKEditor5](https://github.com/ThomasAitken/ckeditor5-footnotes) to allow footnotes.
Apart from that, Trilium also has its own set of specific plugins such as:
[Excalidraw](https://excalidraw.com/) is the technology behind the[Canvas](../../Note%20Types/Canvas.md)notes. The source code of the library is available on [GitHub](https://github.com/excalidraw/excalidraw).
We are using an unmodified version of it, so it shares the same [issues](https://github.com/excalidraw/excalidraw/issues) as the original.
MindElixir is the library we are using for the[Mind Map](../../Note%20Types/Mind%20Map.md)note types.
The main library is available on [GitHub as mind-elixir-core](https://github.com/SSShooter/mind-elixir-core/issues).
The library is embedded as-is without additional modifications.
Issues with its functionality should generally be reported [upstream](https://github.com/ssshooter/mind-elixir-core).
## Plugins
MindElixir supports plugins, and one such plugin we are making use of is [SSShooter/node-menu: A node menu plugin of mind-elixir](https://github.com/SSShooter/node-menu), which allows editing the fonts, colors, links of nodes.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.