mirror of
https://github.com/zadam/trilium.git
synced 2025-10-19 22:58:52 +02:00
Merge branch 'develop' into calendar
This commit is contained in:
commit
bf70b949a6
44
.dprint.json
44
.dprint.json
@ -1,44 +0,0 @@
|
||||
{
|
||||
"typescript": {
|
||||
"indentWidth": 4,
|
||||
"quoteStyle": "preferDouble",
|
||||
"semiColons": "prefer",
|
||||
"quoteProps": "asNeeded",
|
||||
"newLineKind": "lf",
|
||||
"lineWidth": 200,
|
||||
"trailingCommas": "never",
|
||||
"arrayPattern.spaceAround": true,
|
||||
"arrayExpression.spaceAround": true
|
||||
},
|
||||
"json": {
|
||||
},
|
||||
"markdown": {
|
||||
},
|
||||
"dockerfile": {
|
||||
},
|
||||
"malva": {
|
||||
},
|
||||
"markup": {
|
||||
},
|
||||
"yaml": {
|
||||
},
|
||||
"excludes": [
|
||||
"**/node_modules",
|
||||
"**/*-lock.json",
|
||||
"*.html",
|
||||
"*.md",
|
||||
"*.yml",
|
||||
"libraries/*",
|
||||
"docs/*",
|
||||
"src/public/app/doc_notes"
|
||||
],
|
||||
"plugins": [
|
||||
"https://plugins.dprint.dev/typescript-0.94.0.wasm",
|
||||
"https://plugins.dprint.dev/json-0.20.0.wasm",
|
||||
"https://plugins.dprint.dev/markdown-0.18.0.wasm",
|
||||
"https://plugins.dprint.dev/dockerfile-0.3.2.wasm",
|
||||
"https://plugins.dprint.dev/g-plane/malva-v0.11.1.wasm",
|
||||
"https://plugins.dprint.dev/g-plane/markup_fmt-v0.19.0.wasm",
|
||||
"https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.0.wasm"
|
||||
]
|
||||
}
|
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@ -4,6 +4,7 @@
|
||||
"editorconfig.editorconfig",
|
||||
"vitest.explorer",
|
||||
"ms-playwright.playwright",
|
||||
"tobermory.es6-string-html"
|
||||
"tobermory.es6-string-html",
|
||||
"dbaeumer.vscode-eslint"
|
||||
]
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"formatVersion": 2,
|
||||
"appVersion": "0.92.4",
|
||||
"appVersion": "0.92.5-beta",
|
||||
"files": [
|
||||
{
|
||||
"isClone": false,
|
||||
@ -1433,28 +1433,28 @@
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "BlN9DFI679QC",
|
||||
"value": "vZWERwf8U3nx",
|
||||
"isInheritable": false,
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "vZWERwf8U3nx",
|
||||
"value": "4FahAwuGTAwC",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "4FahAwuGTAwC",
|
||||
"value": "0vhv7lsOLy82",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "0vhv7lsOLy82",
|
||||
"value": "BlN9DFI679QC",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
@ -3058,6 +3058,20 @@
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "QxEyIjRBizuC",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "UYuUB1ZekNQU",
|
||||
"isInheritable": false,
|
||||
"position": 70
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "shareAlias",
|
||||
@ -3085,20 +3099,6 @@
|
||||
"value": "",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "UYuUB1ZekNQU",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "QxEyIjRBizuC",
|
||||
"isInheritable": false,
|
||||
"position": 70
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
@ -3231,14 +3231,14 @@
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "QxEyIjRBizuC",
|
||||
"value": "6f9hih2hXXZk",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "6f9hih2hXXZk",
|
||||
"value": "QxEyIjRBizuC",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
@ -3324,44 +3324,44 @@
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "6f9hih2hXXZk",
|
||||
"value": "QxEyIjRBizuC",
|
||||
"isInheritable": false,
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "4TIF1oA4VQRO",
|
||||
"value": "6f9hih2hXXZk",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "nRhnJkTT8cPs",
|
||||
"value": "4TIF1oA4VQRO",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "s8alTXmpFR61",
|
||||
"value": "nRhnJkTT8cPs",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "s8alTXmpFR61",
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "iconClass",
|
||||
"value": "bx bx-code",
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "QxEyIjRBizuC",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
@ -4091,48 +4091,62 @@
|
||||
"type": "text",
|
||||
"mime": "text/markdown",
|
||||
"attributes": [
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "zEY4DaJG4YT5",
|
||||
"isInheritable": false,
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "OFXdgB2nNk1F",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "wX4HbRucYSDD",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "imageLink",
|
||||
"value": "EH6qNioOHeyT",
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "imageLink",
|
||||
"value": "xeZPrfi77XPu",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "imageLink",
|
||||
"value": "N98UhifxrVpZ",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "BFs8mudNFgCS",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "zEY4DaJG4YT5",
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "OFXdgB2nNk1F",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "wX4HbRucYSDD",
|
||||
"isInheritable": false,
|
||||
"position": 70
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "BCkXAVs63Ttv",
|
||||
"isInheritable": false,
|
||||
"position": 80
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "shareAlias",
|
||||
@ -4146,20 +4160,6 @@
|
||||
"value": "bx bxs-network-chart",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "BFs8mudNFgCS",
|
||||
"isInheritable": false,
|
||||
"position": 80
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "BCkXAVs63Ttv",
|
||||
"isInheritable": false,
|
||||
"position": 90
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
@ -4190,19 +4190,19 @@
|
||||
"type": "text",
|
||||
"mime": "text/html",
|
||||
"attributes": [
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "BCkXAVs63Ttv",
|
||||
"isInheritable": false,
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "iconClass",
|
||||
"value": "bx bxs-network-chart",
|
||||
"isInheritable": false,
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "BCkXAVs63Ttv",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
@ -5916,23 +5916,23 @@
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "iRwzGnHPzonm",
|
||||
"value": "bdUJEHsAPYQR",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "iRwzGnHPzonm",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "shareAlias",
|
||||
"value": "note-map",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "bdUJEHsAPYQR",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
@ -6887,21 +6887,21 @@
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "KSZ04uQ2D1St",
|
||||
"value": "_optionsTextNotes",
|
||||
"isInheritable": false,
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "_optionsTextNotes",
|
||||
"value": "_optionsCodeNotes",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "_optionsCodeNotes",
|
||||
"value": "KSZ04uQ2D1St",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
@ -6929,21 +6929,21 @@
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "gBbsAeiuUxI5",
|
||||
"value": "H0mM1lTxF9JI",
|
||||
"isInheritable": false,
|
||||
"position": 70
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "N4IDkixaDG9C",
|
||||
"value": "gBbsAeiuUxI5",
|
||||
"isInheritable": false,
|
||||
"position": 80
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "H0mM1lTxF9JI",
|
||||
"value": "N4IDkixaDG9C",
|
||||
"isInheritable": false,
|
||||
"position": 90
|
||||
},
|
||||
|
@ -35,7 +35,7 @@ Basic Auth is meant to be used with tools which support only basic auth.
|
||||
|
||||
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:
|
||||
|
||||
```sh
|
||||
```
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Configuration
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Note Map (Link map, Tree map)
|
||||
# Note Map (Link map, Tree map)
|
||||
Note map is a visualisation of connections between notes.
|
||||
|
||||
This provides an insight into a structure ("web") of notes.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Note source
|
||||
# Note source
|
||||
## 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).
|
||||
@ -15,7 +15,7 @@ Note that some information is also stored as [Attachments](../Attachments). For
|
||||
|
||||
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>
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Technologies used
|
||||
# Technologies used
|
||||
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.
|
@ -1,4 +1,4 @@
|
||||
# CKEditor
|
||||
# CKEditor
|
||||
## Editor core
|
||||
|
||||
The CKEditor is the WYSIWYG (standing for What You See Is What You Get) editor behind [Text](../../Note%20Types/Text.md) notes.
|
||||
@ -21,7 +21,7 @@ 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)
|
||||
* [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:
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Excalidraw
|
||||
# Excalidraw
|
||||
[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.
|
@ -1,4 +1,4 @@
|
||||
# Leaflet
|
||||
# Leaflet
|
||||
Leaflet is the library behind [Geo map](../../Note%20Types/Geo%20map.md) notes.
|
||||
|
||||
## Plugins
|
||||
|
@ -1,4 +1,4 @@
|
||||
# MindElixir
|
||||
# MindElixir
|
||||
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).
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Evernote
|
||||
# Evernote
|
||||
Trilium can import ENEX files which are used by Evernote for backup/export. One ENEX file represents content (notes and resources) of one notebook.
|
||||
|
||||
## Export ENEX from Evernote
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Markdown
|
||||
# Markdown
|
||||
Trilium Notes supports importing Markdown restricted to the [CommonMark specification](https://spec.commonmark.org/current/) (where [tables are not supported](https://github.com/TriliumNext/Notes/issues/2026))
|
||||
|
||||
## Import
|
||||
|
@ -1,4 +1,4 @@
|
||||
# OneNote
|
||||
# OneNote
|
||||
**This page describes a method to migrate via EverNote Legacy, but this app is no longer available/working.**
|
||||
|
||||
## Prep Onenote notes for best compatibility
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Keyboard Shortcuts
|
||||
# Keyboard Shortcuts
|
||||
This is supposed to be a complete list of keyboard shortcuts. Note that some of these may work only in certain contexts (e.g. in tree pane or note editor).
|
||||
|
||||
It is also possible to configure most keyboard shortcuts in Options -> Keyboard shortcuts. Using `global:` prefix, you can assign a shortcut which will work even without Trilium being in focus (requires app restart to take effect).
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Bookmarks
|
||||
# Bookmarks
|
||||
To easily access selected notes, you can bookmark them. See demo:
|
||||
|
||||

|
||||
|
@ -1,4 +1,4 @@
|
||||
# Note Hoisting
|
||||
# Note Hoisting
|
||||
Hoisting is a standard outliner feature which allows you to focus on (or "zoom into") a specific note and its subtree by hiding all parent and sibling notes. Demo:
|
||||
|
||||

|
||||
|
@ -1,4 +1,4 @@
|
||||
# Note Navigation
|
||||
# Note Navigation
|
||||
One of the Trilium's goals is to provide fast and comfortable navigation between notes.
|
||||
|
||||
## Backwards and forward
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Search
|
||||
# Search
|
||||
## Local Search
|
||||
|
||||
Local search allows you to search within the currently displayed note. To initiate a local search, press <kbd>Ctrl</kbd> + <kbd>F</kbd>. If using a web browser, this will be handled by the browser's native search functionality. In the desktop (electron) version, a separate dialog will apear.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Tree Concepts
|
||||
# Tree Concepts
|
||||
This page explains the basic concepts related to the tree structure of notes in TriliumNext.
|
||||
|
||||
## Note
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Workspace
|
||||
# Workspace
|
||||
Workspace is a concept built up on top of [note hoisting](Note%20Hoisting.md). It is based on the idea that a user has several distinct spheres of interest. An example might be "Personal" and "Work", these two spheres are quite distinct and don't interact together. When I focus on Work, I don't really care about personal notes.
|
||||
|
||||
So far workspace consists of these features:
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Notes
|
||||
# Notes
|
||||
Note is a central entity in Trilium. Main attributes of note are title and content.
|
||||
|
||||
### Note types
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Archived Notes
|
||||
# Archived Notes
|
||||
Archived notes are notes which have `archived` [attribute](../../Advanced%20Usage/Attributes.md) - either directly or [inherited](../../Advanced%20Usage/Attributes/Attribute%20Inheritance.md).
|
||||
|
||||
Such notes are then by default not shown in the autocomplete and in the full text [search](../Navigation/Search.md).
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Attachments
|
||||
# Attachments
|
||||
A [note](../Notes.md) in Trilium can _own_ one or more attachments, which can be either images or files. These attachments can be displayed or linked within the note that owns them.
|
||||
|
||||
This can be especially useful to include dependencies for your [scripts](../../Note%20Types/Code/Scripts.md). The [Weight Tracker](../../Advanced%20Usage/Advanced%20Showcases/Weight%20Tracker.md) shows how to use [chartjs](https://chartjs.org/) which is attached to the [script note](#root/HcUYTojFohtb).
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Cloning Notes
|
||||
# Cloning Notes
|
||||
## Motivation
|
||||
|
||||
Trilium's core feature is the ability to structure your notes into hierarchical tree-like structure.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Export as PDF
|
||||
# Export as PDF
|
||||

|
||||
|
||||
Screenshot of the note contextual menu indicating the “Export as PDF” option.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Note Icons
|
||||
# Note Icons
|
||||
Icons are useful for distinguishing notes. At the technical level, they are set by the `iconClass` attribute which adds a CSS class to the note. For example `#iconClass="bx bx-calendar"` will show a calendar instead of the default page or folder icon. Looking up and remembering the css class names is not necessary. While editing a note, click on the icon next to the title to bring up a chooser gallery:
|
||||
|
||||

|
||||
|
@ -1,4 +1,4 @@
|
||||
# Note Revisions
|
||||
# Note Revisions
|
||||
Trilium supports seamless versioning of notes by storing snapshots ("revisions") of notes at regular intervals.
|
||||
|
||||
## Note Revisions Snapshot Interval
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Protected Notes
|
||||
# Protected Notes
|
||||
Trilium is designed to store a wide variety of data, including sensitive information such as personal journals, credentials, or confidential documents. To safeguard this type of content, Trilium offers the option to protect notes, which involves the following measures:
|
||||
|
||||
* **Encryption:** Protected notes are encrypted using a key derived from your password. This ensures that without the correct password, protected notes remain indecipherable. Even if someone gains access to your Trilium [database](../../Advanced%20Usage/Database.md), they won't be able to read your encrypted notes.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Read-Only Notes
|
||||
# Read-Only Notes
|
||||
Both [text](../../Note%20Types/Text.md) and [code](../../Note%20Types/Code.md) notes in Trilium can be set to read-only. When a note is in read-only mode, it is presented to the user in a non-editable view, with the option to switch to editing mode if needed.
|
||||
|
||||
## Setting Read-Only Mode with a Label
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Sorting Notes
|
||||
# Sorting Notes
|
||||
## Sorting Notes
|
||||
|
||||
You can sort notes by right-clicking the parent note in the note tree and selecting Advanced -> Sort notes by ... This will sort existing notes, but will not automatically sort future notes added to this parent note
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Themes
|
||||
# Themes
|
||||
## Default Themes
|
||||
|
||||
Trilium comes with a couple pre-installed color themes, with the default being a light theme. To switch to a dark theme or any other available theme, navigate to the Options menu (accessible via the app icon in the top-left corner), select the Appearance tab, and choose your preferred theme.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Theme Gallery
|
||||
# Theme Gallery
|
||||
These are user-created themes which were made publicly available:
|
||||
|
||||
## Legacy Themes
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Global menu
|
||||
# Global menu
|
||||
The global menu configures the current window (zoom, keeping the window on top) and offers access to some more advanced options.
|
||||
|
||||

|
||||
|
@ -1,4 +1,4 @@
|
||||
# Launch Bar
|
||||
# Launch Bar
|
||||
## Position of the Launch bar
|
||||
|
||||
Depending on the layout selected, the launcher bar will either be on the left side of the screen with buttons displayed vertically or at the top of the screen. See [Vertical and horizontal layout](Vertical%20and%20horizontal%20layout.md) for more information.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Note Tree
|
||||
# Note Tree
|
||||
This page explains how to manipulate the note tree in TriliumNext, focusing on moving notes.
|
||||
|
||||

|
||||
|
@ -1,4 +1,4 @@
|
||||
# Note buttons
|
||||
# Note buttons
|
||||
To the right of the [Ribbon](Ribbon.md) there are a few more buttons: 
|
||||
|
||||
* The Note Revisions button displays the [Note Revisions](../Notes/Note%20Revisions.md) for that particular note.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Ribbon
|
||||
# Ribbon
|
||||

|
||||
|
||||
The ribbon allows changing options, attributes and viewing information about the current note.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Vertical and horizontal layout
|
||||
# Vertical and horizontal layout
|
||||
## Layouts
|
||||
|
||||
Trilium supports two different layouts, based on your preference.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Zen mode
|
||||
# Zen mode
|
||||

|
||||
|
||||
Screenshot of Zen Mode activated on a Windows 11 system with native title bar off and background effects on.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Note Map
|
||||
# Note Map
|
||||
A Note map is a note type which displays a standalone version of the feature of the same name: [Note Map (Link map, Tree map)](../Advanced%20Usage/Note%20Map%20\(Link%20map%2C%20Tree%20map\).md).
|
||||
|
||||
Once created, the note map will display the relations between notes. Only the notes that are part of the parent of the note map will be displayed (including their children).
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Relation Map
|
||||
# Relation Map
|
||||
Relation map is a type of [Note](../Basic%20Concepts%20and%20Features/Notes.md) which visualizes notes and their [relations](../Advanced%20Usage/Attributes.md). See an example:
|
||||
|
||||
## Development process demo
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Developer-specific formatting
|
||||
# Developer-specific formatting
|
||||
### Inline code
|
||||
|
||||
Inline code formats text using a monospace font to indicate technical content in a sentence such as code, paths, etc.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Code blocks
|
||||
# Code blocks
|
||||

|
||||
|
||||
The code blocks feature allows entering pieces of code in text notes.
|
||||
|
@ -25,3 +25,40 @@ test("Complete help in search", async ({ page, context }) => {
|
||||
const popup = await popupPromise;
|
||||
expect(popup.url()).toBe("https://triliumnext.github.io/Docs/Wiki/search.html");
|
||||
});
|
||||
|
||||
test("In-app-help works in English", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
|
||||
await app.currentNoteSplit.press("F1");
|
||||
const title = "User Guide";
|
||||
await expect(app.noteTreeHoistedNote).toContainText(title);
|
||||
await expect(app.currentNoteSplitTitle).toHaveValue(title);
|
||||
|
||||
app.noteTree.getByText("Troubleshooting").click();
|
||||
await expect(app.currentNoteSplitTitle).toHaveValue("Troubleshooting");
|
||||
await app.currentNoteSplitContent.locator("p").first().waitFor({ state: "visible" });
|
||||
expect(await app.currentNoteSplitContent.locator("p").count()).toBeGreaterThan(10);
|
||||
});
|
||||
|
||||
test("In-app-help works in other languages", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
try {
|
||||
await app.goto();
|
||||
await app.setOption("locale", "cn");
|
||||
await app.goto();
|
||||
|
||||
await app.currentNoteSplit.press("F1");
|
||||
const title = "用户指南";
|
||||
await expect(app.noteTreeHoistedNote).toContainText(title);
|
||||
await expect(app.currentNoteSplitTitle).toHaveValue(title);
|
||||
|
||||
app.noteTree.getByText("Troubleshooting").click();
|
||||
await expect(app.currentNoteSplitTitle).toHaveValue("Troubleshooting");
|
||||
await app.currentNoteSplitContent.locator("p").first().waitFor({ state: "visible" });
|
||||
expect(await app.currentNoteSplitContent.locator("p").count()).toBeGreaterThan(10);
|
||||
} finally {
|
||||
// Ensure English is set after each locale change to avoid any leaks to other tests.
|
||||
await app.setOption("locale", "en");
|
||||
}
|
||||
});
|
||||
|
@ -57,3 +57,46 @@ test("Can drag tab to new window", async ({ page, context }) => {
|
||||
const popupApp = new App(popup, context);
|
||||
await expect(popupApp.getActiveTab()).toHaveText(NOTE_TITLE);
|
||||
});
|
||||
|
||||
test("Tabs are restored in right order", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
|
||||
// Open three tabs.
|
||||
await app.closeAllTabs();
|
||||
await app.goToNoteInNewTab("Code notes");
|
||||
await app.addNewTab();
|
||||
await app.goToNoteInNewTab("Text notes");
|
||||
await app.addNewTab();
|
||||
await app.goToNoteInNewTab("Mermaid");
|
||||
|
||||
// Select the mid one.
|
||||
await app.getTab(1).click();
|
||||
|
||||
// Refresh the page and check the order.
|
||||
await app.goto( { preserveTabs: true });
|
||||
await expect(app.getTab(0)).toContainText("Code notes");
|
||||
await expect(app.getTab(1)).toContainText("Text notes");
|
||||
await expect(app.getTab(2)).toContainText("Mermaid");
|
||||
|
||||
// Check the note tree has the right active node.
|
||||
await expect(app.noteTreeActiveNote).toContainText("Text notes");
|
||||
});
|
||||
|
||||
test("Empty tabs are cleared out", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
|
||||
// Open three tabs.
|
||||
await app.closeAllTabs();
|
||||
await app.addNewTab();
|
||||
await app.goToNoteInNewTab("Code notes");
|
||||
await app.addNewTab();
|
||||
await app.addNewTab();
|
||||
|
||||
// Refresh the page and check the order.
|
||||
await app.goto({ preserveTabs: true });
|
||||
|
||||
// Expect no empty tabs.
|
||||
expect(await app.tabBar.locator(".note-tab-wrapper").count()).toBe(1);
|
||||
});
|
||||
|
@ -4,6 +4,7 @@ import type { BrowserContext } from "@playwright/test";
|
||||
interface GotoOpts {
|
||||
url?: string;
|
||||
isMobile?: boolean;
|
||||
preserveTabs?: boolean;
|
||||
}
|
||||
|
||||
const BASE_URL = "http://127.0.0.1:8082";
|
||||
@ -14,8 +15,12 @@ export default class App {
|
||||
|
||||
readonly tabBar: Locator;
|
||||
readonly noteTree: Locator;
|
||||
readonly noteTreeActiveNote: Locator;
|
||||
readonly noteTreeHoistedNote: Locator;
|
||||
readonly launcherBar: Locator;
|
||||
readonly currentNoteSplit: Locator;
|
||||
readonly currentNoteSplitTitle: Locator;
|
||||
readonly currentNoteSplitContent: Locator;
|
||||
readonly sidebar: Locator;
|
||||
|
||||
constructor(page: Page, context: BrowserContext) {
|
||||
@ -24,12 +29,16 @@ export default class App {
|
||||
|
||||
this.tabBar = page.locator(".tab-row-widget-container");
|
||||
this.noteTree = page.locator(".tree-wrapper");
|
||||
this.noteTreeActiveNote = this.noteTree.locator(".fancytree-node.fancytree-active");
|
||||
this.noteTreeHoistedNote = this.noteTree.locator(".fancytree-node", { has: page.locator(".unhoist-button") });
|
||||
this.launcherBar = page.locator("#launcher-container");
|
||||
this.currentNoteSplit = page.locator(".note-split:not(.hidden-ext)");
|
||||
this.currentNoteSplitTitle = this.currentNoteSplit.locator(".note-title");
|
||||
this.currentNoteSplitContent = this.currentNoteSplit.locator(".note-detail-printable.visible");
|
||||
this.sidebar = page.locator("#right-pane");
|
||||
}
|
||||
|
||||
async goto({ url, isMobile }: GotoOpts = {}) {
|
||||
async goto({ url, isMobile, preserveTabs }: GotoOpts = {}) {
|
||||
await this.context.addCookies([
|
||||
{
|
||||
url: BASE_URL,
|
||||
@ -47,7 +56,9 @@ export default class App {
|
||||
// Wait for the page to load.
|
||||
if (url === "/") {
|
||||
await expect(this.page.locator(".tree")).toContainText("Trilium Integration Test");
|
||||
await this.closeAllTabs();
|
||||
if (!preserveTabs) {
|
||||
await this.closeAllTabs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ import { initializeTranslations } from "./src/services/i18n.js";
|
||||
import archiver, { type Archiver } from "archiver";
|
||||
import type { WriteStream } from "fs";
|
||||
import debounce from "./src/public/app/services/debounce.js";
|
||||
import { extractZip, importData, initializeDatabase, startElectron } from "./electron-utils.js";
|
||||
import { extractZip, initializeDatabase, startElectron } from "./electron-utils.js";
|
||||
|
||||
const NOTE_ID_USER_GUIDE = "pOsGYCXsbNQG";
|
||||
const markdownPath = path.join("docs", "User Guide");
|
||||
@ -16,8 +16,7 @@ const htmlPath = path.join("src", "public", "app", "doc_notes", "en", "User Guid
|
||||
async function main() {
|
||||
await initializeTranslations();
|
||||
const zipBuffer = await createImportZip();
|
||||
await initializeDatabase();
|
||||
await importData(zipBuffer, NOTE_ID_USER_GUIDE, "User Guide", "The sub-children of this note are automatically synced.");
|
||||
await initializeDatabase(zipBuffer);
|
||||
await startElectron();
|
||||
await registerHandlers();
|
||||
}
|
||||
|
@ -3,12 +3,12 @@ import fs from "fs/promises";
|
||||
import fsExtra from "fs-extra";
|
||||
import path from "path";
|
||||
|
||||
export async function initializeDatabase() {
|
||||
export async function initializeDatabase(customDbBuffer?: Buffer) {
|
||||
const sqlInit = (await import("./src/services/sql_init.js")).default;
|
||||
|
||||
cls.init(() => {
|
||||
if (!sqlInit.isDbInitialized()) {
|
||||
sqlInit.createInitialDatabase(true);
|
||||
sqlInit.createInitialDatabase(true, customDbBuffer);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -17,48 +17,6 @@ export async function startElectron() {
|
||||
await import("./electron-main.js");
|
||||
}
|
||||
|
||||
export function importData(input: Buffer, rootId: string, rootTitle: string, rootContent: string) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
cls.init(async () => {
|
||||
const beccaLoader = ((await import("./src/becca/becca_loader.js")).default);
|
||||
const notes = ((await import("./src/services/notes.js")).default);
|
||||
beccaLoader.load();
|
||||
const becca = ((await import("./src/becca/becca.js")).default);
|
||||
const utils = ((await import("./src/services/utils.js")).default);
|
||||
const eraseService = ((await import("./src/services/erase.js")).default);
|
||||
const deleteId = utils.randomString(10);
|
||||
|
||||
const existingNote = becca.getNote(rootId);
|
||||
if (existingNote) {
|
||||
existingNote.deleteNote(deleteId);
|
||||
}
|
||||
eraseService.eraseNotesWithDeleteId(deleteId);
|
||||
|
||||
const { note } = notes.createNewNoteWithTarget("into", "none_root", {
|
||||
parentNoteId: "root",
|
||||
noteId: rootId,
|
||||
title: rootTitle,
|
||||
content: rootContent,
|
||||
type: "text"
|
||||
});
|
||||
|
||||
const TaskContext = (await import("./src/services/task_context.js")).default;
|
||||
const { importZip } = ((await import("./src/services/import/zip.js")).default);
|
||||
const context = new TaskContext("no-report");
|
||||
await importZip(context, input, note, { preserveIds: true });
|
||||
|
||||
const { runOnDemandChecks } = (await import("./src/services/consistency_checks.js")).default;
|
||||
await runOnDemandChecks(true);
|
||||
|
||||
becca.reset();
|
||||
beccaLoader.load();
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export async function extractZip(zipFilePath: string, outputPath: string) {
|
||||
const deferred = (await import("./src/services/utils.js")).deferred;
|
||||
|
||||
|
@ -24,10 +24,11 @@ export default tseslint.config(
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"argsIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_",
|
||||
argsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_"
|
||||
}
|
||||
]
|
||||
],
|
||||
"sort-imports": [ "error", { ignoreCase: false } ]
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -35,6 +36,7 @@ export default tseslint.config(
|
||||
"build/*",
|
||||
"dist/*",
|
||||
"docs/*",
|
||||
"demo/*",
|
||||
"libraries/*",
|
||||
"src/public/app-dist/*",
|
||||
"src/public/app/doc_notes/*"
|
||||
|
48
eslint.format.config.js
Normal file
48
eslint.format.config.js
Normal file
@ -0,0 +1,48 @@
|
||||
import stylistic from "@stylistic/eslint-plugin";
|
||||
import tsParser from "@typescript-eslint/parser";
|
||||
|
||||
// eslint config just for formatting rules
|
||||
// potentially to be merged with the linting rules into one single config,
|
||||
// once we have fixed the majority of lint errors
|
||||
|
||||
// Go to https://eslint.style/rules/default/${rule_without_prefix} to check the rule details
|
||||
export const stylisticRules = {
|
||||
"@stylistic/indent": [ "error", 4 ],
|
||||
"@stylistic/quotes": [ "error", "double", { avoidEscape: true, allowTemplateLiterals: "always" } ],
|
||||
"@stylistic/semi": [ "error", "always" ],
|
||||
"@stylistic/quote-props": [ "error", "consistent-as-needed" ],
|
||||
"@stylistic/max-len": [ "error", { code: 100 } ],
|
||||
"@stylistic/comma-dangle": [ "error", "never" ],
|
||||
"@stylistic/linebreak-style": [ "error", "unix" ],
|
||||
"@stylistic/array-bracket-spacing": [ "error", "always" ],
|
||||
"@stylistic/object-curly-spacing": [ "error", "always" ],
|
||||
"@stylistic/padded-blocks": [ "error", { classes: "always" } ]
|
||||
};
|
||||
|
||||
export default [
|
||||
{
|
||||
files: [ "**/*.{js,ts,mjs,cjs}" ],
|
||||
languageOptions: {
|
||||
parser: tsParser
|
||||
},
|
||||
plugins: {
|
||||
"@stylistic": stylistic
|
||||
},
|
||||
rules: {
|
||||
...stylisticRules
|
||||
}
|
||||
},
|
||||
{
|
||||
ignores: [
|
||||
"build/*",
|
||||
"dist/*",
|
||||
"docs/*",
|
||||
"demo/*",
|
||||
"libraries/*",
|
||||
// TriliumNextTODO: check if we want to format packages here as well - for now skipping it
|
||||
"packages/*",
|
||||
"src/public/app-dist/*",
|
||||
"src/public/app/doc_notes/*"
|
||||
]
|
||||
}
|
||||
];
|
176
package-lock.json
generated
176
package-lock.json
generated
@ -117,6 +117,7 @@
|
||||
"@mind-elixir/node-menu": "1.0.5",
|
||||
"@playwright/test": "1.51.1",
|
||||
"@popperjs/core": "2.11.8",
|
||||
"@stylistic/eslint-plugin": "4.2.0",
|
||||
"@types/archiver": "6.0.3",
|
||||
"@types/better-sqlite3": "7.6.12",
|
||||
"@types/bootstrap": "5.2.10",
|
||||
@ -201,8 +202,7 @@
|
||||
"webpack-dev-middleware": "7.4.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"appdmg": "0.6.6",
|
||||
"dprint": "0.49.1"
|
||||
"appdmg": "0.6.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
@ -574,123 +574,6 @@
|
||||
"node": ">=14.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dprint/darwin-arm64": {
|
||||
"version": "0.49.1",
|
||||
"resolved": "https://registry.npmjs.org/@dprint/darwin-arm64/-/darwin-arm64-0.49.1.tgz",
|
||||
"integrity": "sha512-ib6KcJWo/M5RJWXOQKhP664FG1hAvG7nrbkh+j8n+oXdzmbyDdXTP+zW+aM3/sIQUkGaZky1xy1j2VeScMEEHQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@dprint/darwin-x64": {
|
||||
"version": "0.49.1",
|
||||
"resolved": "https://registry.npmjs.org/@dprint/darwin-x64/-/darwin-x64-0.49.1.tgz",
|
||||
"integrity": "sha512-vIVgnYxV7YYa1d6Uyz707RbgB9rwefGPam+rzaueFNPQjdOxPOTQDuMEJDS+Z3BlI00MfeoupIfIUGsXoM4dpQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@dprint/linux-arm64-glibc": {
|
||||
"version": "0.49.1",
|
||||
"resolved": "https://registry.npmjs.org/@dprint/linux-arm64-glibc/-/linux-arm64-glibc-0.49.1.tgz",
|
||||
"integrity": "sha512-ZeIh6qMPWLBBifDtU0XadpK36b4WoaTqCOt0rWKfoTjq1RAt78EgqETWp43Dbr6et/HvTgYdoWF0ZNEu2FJFFA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@dprint/linux-arm64-musl": {
|
||||
"version": "0.49.1",
|
||||
"resolved": "https://registry.npmjs.org/@dprint/linux-arm64-musl/-/linux-arm64-musl-0.49.1.tgz",
|
||||
"integrity": "sha512-/nuRyx+TykN6MqhlSCRs/t3o1XXlikiwTc9emWdzMeLGllYvJrcht9gRJ1/q1SqwCFhzgnD9H7roxxfji1tc+Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@dprint/linux-riscv64-glibc": {
|
||||
"version": "0.49.1",
|
||||
"resolved": "https://registry.npmjs.org/@dprint/linux-riscv64-glibc/-/linux-riscv64-glibc-0.49.1.tgz",
|
||||
"integrity": "sha512-RHBqrnvGO+xW4Oh0QuToBqWtkXMcfjqa1TqbBFF03yopFzZA2oRKX83PhjTWgd/IglaOns0BgmaLJy/JBSxOfQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@dprint/linux-x64-glibc": {
|
||||
"version": "0.49.1",
|
||||
"resolved": "https://registry.npmjs.org/@dprint/linux-x64-glibc/-/linux-x64-glibc-0.49.1.tgz",
|
||||
"integrity": "sha512-MjFE894mIQXOKBencuakKyzAI4KcDe/p0Y9lRp9YSw/FneR4QWH9VBH90h8fRxcIlWMArjFFJJAtsBnn5qgxeg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@dprint/linux-x64-musl": {
|
||||
"version": "0.49.1",
|
||||
"resolved": "https://registry.npmjs.org/@dprint/linux-x64-musl/-/linux-x64-musl-0.49.1.tgz",
|
||||
"integrity": "sha512-CvGBWOksHgrL1uzYqtPFvZz0+E82BzgoCIEHJeuYaveEn37qWZS5jqoCm/vz6BfoivE1dVuyyOT78Begj9KxkQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@dprint/win32-arm64": {
|
||||
"version": "0.49.1",
|
||||
"resolved": "https://registry.npmjs.org/@dprint/win32-arm64/-/win32-arm64-0.49.1.tgz",
|
||||
"integrity": "sha512-gQa4s82lMcXjfdxjWBQun6IJlXdPZZaIj2/2cqXWVEOYPKxAZ/JvGzt2pPG+i73h9KHjNLIV8M9ckqEH3oHufg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@dprint/win32-x64": {
|
||||
"version": "0.49.1",
|
||||
"resolved": "https://registry.npmjs.org/@dprint/win32-x64/-/win32-x64-0.49.1.tgz",
|
||||
"integrity": "sha512-nPU6+hoVze5JJlgET7woYWElBw0IUaB/9XKTaglknQuUUfsmD75D9pkgJTxdIxl9Bg/i5O7c9wb3Nj4XNiTIfw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@electron-forge/cli": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@electron-forge/cli/-/cli-7.8.0.tgz",
|
||||
@ -4554,6 +4437,39 @@
|
||||
"url": "https://github.com/sindresorhus/is?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@stylistic/eslint-plugin": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-4.2.0.tgz",
|
||||
"integrity": "sha512-8hXezgz7jexGHdo5WN6JBEIPHCSFyyU4vgbxevu4YLVS5vl+sxqAAGyXSzfNDyR6xMNSH5H1x67nsXcYMOHtZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/utils": "^8.23.0",
|
||||
"eslint-visitor-keys": "^4.2.0",
|
||||
"espree": "^10.3.0",
|
||||
"estraverse": "^5.3.0",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@stylistic/eslint-plugin/node_modules/picomatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/@szmarczak/http-timer": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
|
||||
@ -9507,28 +9423,6 @@
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dprint": {
|
||||
"version": "0.49.1",
|
||||
"resolved": "https://registry.npmjs.org/dprint/-/dprint-0.49.1.tgz",
|
||||
"integrity": "sha512-pO9XH79SyXybj2Vhc9ITZMEI8cJkdlQQRoD8oEfPH6Jjpp/7WX5kIgECVd3DBOjjAdCSiW6R47v3gJBx/qZVkw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"dprint": "bin.js"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@dprint/darwin-arm64": "0.49.1",
|
||||
"@dprint/darwin-x64": "0.49.1",
|
||||
"@dprint/linux-arm64-glibc": "0.49.1",
|
||||
"@dprint/linux-arm64-musl": "0.49.1",
|
||||
"@dprint/linux-riscv64-glibc": "0.49.1",
|
||||
"@dprint/linux-x64-glibc": "0.49.1",
|
||||
"@dprint/linux-x64-musl": "0.49.1",
|
||||
"@dprint/win32-arm64": "0.49.1",
|
||||
"@dprint/win32-x64": "0.49.1"
|
||||
}
|
||||
},
|
||||
"node_modules/draggabilly": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/draggabilly/-/draggabilly-3.0.0.tgz",
|
||||
|
14
package.json
14
package.json
@ -36,8 +36,8 @@
|
||||
"electron:start-prod-nix-no-dir": "electron-rebuild --version 33.3.1 && npm run build:prepare-dist && cross-env TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./dist/electron-main.js --inspect=5858 .\"",
|
||||
"electron:qstart": "npm run electron:switch && npm run electron:start",
|
||||
"electron:switch": "electron-rebuild",
|
||||
"docs:edit": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data-docs TRILIUM_ENV=dev TRILIUM_PORT=37741 electron ./electron-docs-main.ts .",
|
||||
"docs:edit-nix": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data-docs TRILIUM_PORT=37741 TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./electron-docs-main.ts .\"",
|
||||
"docs:edit": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data-docs TRILIUM_ENV=dev TRILIUM_INTEGRATION_TEST=memory-no-store TRILIUM_PORT=37741 electron ./electron-docs-main.ts .",
|
||||
"docs:edit-nix": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data-docs TRILIUM_PORT=37741 TRILIUM_ENV=dev TRILIUM_INTEGRATION_TEST=memory-no-store nix-shell -p electron_33 --run \"electron ./electron-docs-main.ts .\"",
|
||||
"demo:edit": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data-demo TRILIUM_ENV=dev TRILIUM_INTEGRATION_TEST=memory-no-store TRILIUM_PORT=37741 electron ./electron-edit-demo.ts .",
|
||||
"electron-forge:start": "npm run build:prepare-dist && cd ./build && electron-forge start",
|
||||
"electron-forge:make": "npm run build:prepare-dist && cross-env DEBUG=electron-windows-installer:* electron-forge make ./build",
|
||||
@ -59,8 +59,8 @@
|
||||
"test:integration-mem-db": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
|
||||
"test:integration-mem-db-dev": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
|
||||
"dev:watch-dist": "tsx ./bin/watch-dist.ts",
|
||||
"dev:format-check": "dprint check",
|
||||
"dev:format-fix": "dprint fmt",
|
||||
"dev:format-check": "eslint -c eslint.format.config.js .",
|
||||
"dev:format-fix": "eslint -c eslint.format.config.js . --fix",
|
||||
"dev:linter-check": "eslint .",
|
||||
"dev:linter-fix": "eslint . --fix",
|
||||
"chore:update-build-info": "tsx bin/update-build-info.ts",
|
||||
@ -174,6 +174,7 @@
|
||||
"@mind-elixir/node-menu": "1.0.5",
|
||||
"@playwright/test": "1.51.1",
|
||||
"@popperjs/core": "2.11.8",
|
||||
"@stylistic/eslint-plugin": "4.2.0",
|
||||
"@types/archiver": "6.0.3",
|
||||
"@types/better-sqlite3": "7.6.12",
|
||||
"@types/bootstrap": "5.2.10",
|
||||
@ -219,7 +220,7 @@
|
||||
"bootstrap": "5.3.3",
|
||||
"copy-webpack-plugin": "13.0.0",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "7.1.2",
|
||||
"css-loader": "7.1.2",
|
||||
"electron": "35.1.2",
|
||||
"eslint": "9.23.0",
|
||||
"esm": "3.2.25",
|
||||
@ -258,7 +259,6 @@
|
||||
"webpack-dev-middleware": "7.4.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"appdmg": "0.6.6",
|
||||
"dprint": "0.49.1"
|
||||
"appdmg": "0.6.6"
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ export default class TabManager extends Component {
|
||||
|
||||
const filteredNoteContexts = noteContextsToOpen.filter((openTab: NoteContextState) => {
|
||||
const noteId = treeService.getNoteIdFromUrl(openTab.notePath);
|
||||
if (noteId && !(noteId in froca.notes)) {
|
||||
if (!noteId || !(noteId in froca.notes)) {
|
||||
// note doesn't exist so don't try to open tab for it
|
||||
return false;
|
||||
}
|
||||
|
@ -14,8 +14,10 @@ export default function renderDoc(note: FNote) {
|
||||
// fallback to english doc if no translation available
|
||||
if (status === "error") {
|
||||
const fallbackUrl = getUrl(docName, "en");
|
||||
$content.load(fallbackUrl, () => processContent(fallbackUrl, $content));
|
||||
resolve($content);
|
||||
$content.load(fallbackUrl, () => {
|
||||
processContent(fallbackUrl, $content)
|
||||
resolve($content);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import "../stylesheets/bootstrap.scss";
|
||||
import "../stylesheets/auth.css";
|
||||
|
||||
// @TriliumNextTODO: is this even needed anymore?
|
||||
// @ts-ignore - module = undefined
|
||||
|
@ -11,6 +11,7 @@ const TPL = /*html*/`
|
||||
.global-menu {
|
||||
width: 53px;
|
||||
height: 53px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.global-menu .dropdown-menu {
|
||||
|
@ -11,7 +11,19 @@ export default class LauncherContainer extends FlexContainer<LauncherWidget> {
|
||||
super(isHorizontalLayout ? "row" : "column");
|
||||
|
||||
this.id("launcher-container");
|
||||
this.css(isHorizontalLayout ? "width" : "height", "100%");
|
||||
|
||||
if (isHorizontalLayout) {
|
||||
this.css("width", "100%");
|
||||
this.css("height", "100%");
|
||||
this.css("overflow-x", "auto");
|
||||
this.css("overflow-y", "hidden");
|
||||
} else {
|
||||
this.css("height", "100%");
|
||||
this.css("overflow-x", "hidden");
|
||||
this.css("overflow-y", "auto");
|
||||
}
|
||||
|
||||
this.css("scrollbar-gutter", "stable both-edges");
|
||||
this.filling();
|
||||
this.isHorizontalLayout = isHorizontalLayout;
|
||||
|
||||
|
@ -16,7 +16,7 @@ const TPL = /*html*/`
|
||||
<form class="protected-session-password-form">
|
||||
<div class="modal-body">
|
||||
<label for="protected-session-password" class="col-form-label">${t("protected_session_password.form_label")}</label>
|
||||
<input id="protected-session-password" class="form-control protected-session-password" type="password">
|
||||
<input id="protected-session-password" class="form-control protected-session-password" type="password" autocomplete="current-password">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary">${t("protected_session_password.start_button")}</button>
|
||||
|
@ -82,7 +82,6 @@ class NoteContextAwareWidget extends BasicWidget {
|
||||
async refreshWithNote(note: FNote | null | undefined) {}
|
||||
|
||||
async noteSwitchedEvent({ noteContext, notePath }: EventData<"noteSwitched">) {
|
||||
this.noteContext = noteContext;
|
||||
// if notePath does not match, then the noteContext has been switched to another note in the meantime
|
||||
if (noteContext.notePath === notePath) {
|
||||
await this.noteSwitched();
|
||||
|
@ -20,7 +20,7 @@ const TPL = /*html*/`
|
||||
<form class="protected-session-password-form">
|
||||
<div class="form-group">
|
||||
<label for="protected-session-password-in-detail">${t("protected_session.enter_password_instruction")}</label>
|
||||
<input id="protected-session-password-in-detail" class="form-control protected-session-password" type="password" autofocus>
|
||||
<input id="protected-session-password-in-detail" class="form-control protected-session-password" type="password" autofocus autocomplete="current-password">
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary">${t("protected_session.start_session_button")}</button>
|
||||
|
3
src/public/stylesheets/auth.css
Normal file
3
src/public/stylesheets/auth.css
Normal file
@ -0,0 +1,3 @@
|
||||
.set-password .form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
@ -1177,6 +1177,10 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
||||
left: calc(-100% + 10px);
|
||||
}
|
||||
|
||||
.right-dropdown-widget {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#launcher-pane.horizontal .right-dropdown-widget {
|
||||
width: 53px;
|
||||
}
|
||||
@ -1288,6 +1292,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
||||
border: none;
|
||||
color: var(--launcher-pane-text-color);
|
||||
background-color: var(--launcher-pane-background-color);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#launcher-pane.vertical .launcher-button {
|
||||
@ -1302,6 +1307,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
||||
|
||||
#launcher-pane.horizontal .quick-search {
|
||||
width: 350px;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
#launcher-pane .icon-action:hover {
|
||||
|
@ -7,7 +7,7 @@ function setRecoveryCodes(req: Request) {
|
||||
return { success: success, message: 'Recovery codes set!' };
|
||||
}
|
||||
|
||||
function veryifyRecoveryCode(req: Request) {
|
||||
function verifyRecoveryCode(req: Request) {
|
||||
const success = recovery_codes.verifyRecoveryCode(req.body.recovery_code_guess);
|
||||
|
||||
return { success: success };
|
||||
@ -59,7 +59,7 @@ function getUsedRecoveryCodes() {
|
||||
export default {
|
||||
setRecoveryCodes,
|
||||
generateRecoveryCodes,
|
||||
veryifyRecoveryCode,
|
||||
verifyRecoveryCode,
|
||||
checkForRecoveryKeys,
|
||||
getUsedRecoveryCodes
|
||||
};
|
@ -124,7 +124,7 @@ function register(app: express.Application) {
|
||||
apiRoute(GET, '/api/oauth/validate', openID.isTokenValid);
|
||||
|
||||
apiRoute(PST, '/api/totp_recovery/set', recoveryCodes.setRecoveryCodes);
|
||||
apiRoute(PST, '/api/totp_recovery/verify', recoveryCodes.veryifyRecoveryCode);
|
||||
apiRoute(PST, '/api/totp_recovery/verify', recoveryCodes.verifyRecoveryCode);
|
||||
apiRoute(GET, '/api/totp_recovery/generate', recoveryCodes.generateRecoveryCodes);
|
||||
apiRoute(GET, '/api/totp_recovery/enabled', recoveryCodes.checkForRecoveryKeys);
|
||||
apiRoute(GET, '/api/totp_recovery/used', recoveryCodes.getUsedRecoveryCodes);
|
||||
|
@ -127,4 +127,10 @@ second line 2</code></pre><ul><li>Hello</li><li>world</li></ul><ol><li>Hello</li
|
||||
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
it("does not escape unneeded characters", () => {
|
||||
const input = `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.`;
|
||||
const expected = `<p>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.</p>`;
|
||||
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -82,7 +82,7 @@ function renderToHtml(content: string, title: string) {
|
||||
|
||||
// h1 handling needs to come before sanitization
|
||||
html = importUtils.handleH1(html, title);
|
||||
// html = htmlSanitizer.sanitize(html);
|
||||
html = htmlSanitizer.sanitize(html);
|
||||
|
||||
// Remove slash for self-closing tags to match CKEditor's approach.
|
||||
html = html.replace(/<(\w+)([^>]*)\s+\/>/g, "<$1$2>");
|
||||
|
@ -64,13 +64,19 @@ async function initDbConnection() {
|
||||
dbReady.resolve();
|
||||
}
|
||||
|
||||
async function createInitialDatabase(preserveIds?: boolean) {
|
||||
/**
|
||||
* Applies the database schema, creating the necessary tables and importing the demo content.
|
||||
*
|
||||
* @param preserveIds `true` if the note IDs from the meta file should be preserved, or `false` to generate new ones (normal behaviour).
|
||||
* @param customDbBuffer a custom database buffer to use, otherwise the default demo one is going to be used.
|
||||
*/
|
||||
async function createInitialDatabase(preserveIds?: boolean, customDbBuffer?: Buffer) {
|
||||
if (isDbInitialized()) {
|
||||
throw new Error("DB is already initialized");
|
||||
}
|
||||
|
||||
const schema = fs.readFileSync(`${resourceDir.DB_INIT_DIR}/schema.sql`, "utf-8");
|
||||
const demoFile = fs.readFileSync(`${resourceDir.DB_INIT_DIR}/demo.zip`);
|
||||
const demoFile = customDbBuffer ?? fs.readFileSync(`${resourceDir.DB_INIT_DIR}/demo.zip`);
|
||||
|
||||
let rootNote!: BNote;
|
||||
|
||||
|
@ -3,8 +3,8 @@ import options from './options.js';
|
||||
import totpEncryptionService from './encryption/totp_encryption.js';
|
||||
|
||||
function isTotpEnabled(): boolean {
|
||||
return options.getOption('mfaEnabled') === "true" &&
|
||||
options.getOption('mfaMethod') === "totp" &&
|
||||
return options.getOptionOrNull('mfaEnabled') === "true" &&
|
||||
options.getOptionOrNull('mfaMethod') === "totp" &&
|
||||
totpEncryptionService.isTotpSecretSet();
|
||||
}
|
||||
|
||||
|
@ -156,6 +156,8 @@ async function createMainWindow(app: App) {
|
||||
y: mainWindowState.y,
|
||||
width: mainWindowState.width,
|
||||
height: mainWindowState.height,
|
||||
minWidth: 500,
|
||||
minHeight: 400,
|
||||
title: "TriliumNext Notes",
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
@ -185,7 +187,7 @@ async function createMainWindow(app: App) {
|
||||
if (lastFocusedWindow.isMinimized()) {
|
||||
lastFocusedWindow.restore();
|
||||
}
|
||||
lastFocusedWindow.show();
|
||||
lastFocusedWindow.show();
|
||||
lastFocusedWindow.focus();
|
||||
}
|
||||
});
|
||||
@ -255,9 +257,12 @@ function getIcon() {
|
||||
|
||||
async function createSetupWindow() {
|
||||
const { BrowserWindow } = await import("electron"); // should not be statically imported
|
||||
const width = 750;
|
||||
const height = 650;
|
||||
setupWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 800,
|
||||
width,
|
||||
height,
|
||||
resizable: false,
|
||||
title: "TriliumNext Notes Setup",
|
||||
icon: getIcon(),
|
||||
webPreferences: {
|
||||
|
@ -34,14 +34,14 @@
|
||||
<div class="form-group">
|
||||
<label for="password"><%= t("login.password") %></label>
|
||||
<div class="controls">
|
||||
<input id="password" name="password" placeholder="" class="form-control" type="password" autofocus>
|
||||
<input id="password" name="password" placeholder="" class="form-control" type="password" autocomplete="current-password" autofocus>
|
||||
</div>
|
||||
</div>
|
||||
<% if( totpEnabled ) { %>
|
||||
<div class="form-group">
|
||||
<label for="totpToken">TOTP Token</label>
|
||||
<div class="controls">
|
||||
<input id="totpToken" name="totpToken" placeholder="" class="form-control" type="text" required />
|
||||
<input id="totpToken" name="totpToken" placeholder="" class="form-control" type="text" autocomplete="one-time-code" required />
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
|
@ -13,7 +13,7 @@
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="container set-password">
|
||||
<div class="col-xs-12 col-sm-10 col-md-6 col-lg-4 col-xl-4 mx-auto pt-4">
|
||||
<h1><%= t("set_password.heading") %></h1>
|
||||
|
||||
@ -29,13 +29,13 @@
|
||||
<div class="form-group">
|
||||
<label for="password1"><%= t("set_password.password") %></label>
|
||||
<div class="controls">
|
||||
<input id="password1" name="password1" placeholder="" class="form-control" type="password">
|
||||
<input id="password1" name="password1" placeholder="" class="form-control" type="password" autocomplete="new-password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password2"><%= t("set_password.password-confirmation") %></label>
|
||||
<div class="controls">
|
||||
<input id="password2" name="password2" placeholder="" class="form-control" type="password">
|
||||
<input id="password2" name="password2" placeholder="" class="form-control" type="password" autocomplete="new-password">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true
|
||||
},
|
||||
"include": ["./src/**/*.js", "./src/**/*.ts", "./*.ts", "./spec/**/*.ts"],
|
||||
"include": ["./src/**/*.js", "./src/**/*.ts", "./*.ts", "./*.js", "./spec/**/*.ts"],
|
||||
"exclude": ["./node_modules/**/*", "./spec-es6/**/*.ts"],
|
||||
"files": ["src/types.d.ts", "src/public/app/types.d.ts"]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user