diff --git a/.editorconfig b/.editorconfig
index c0aba9b74..c965ea8c0 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -8,6 +8,9 @@ indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
+[*.sh]
+end_of_line = lf
+
[{server,translation}.json]
charset = utf-8
end_of_line = lf
diff --git a/.gitattributes b/.gitattributes
index e9d640721..7b00e7d63 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,17 +1,21 @@
+# Mark files as auto-generated to simplify reviews.
package-lock.json linguist-generated=true
**/package-lock.json linguist-generated=true
+apps/server/src/assets/doc_notes/en/User[[:space:]]Guide/** linguist-generated
-apps/server/src/assets/doc_notes/en/User[[:space:]]Guide/** linguist-generated=true
+# Ignore from GitHub language stats.
apps/server/src/assets/doc_notes/en/User[[:space:]]Guide/**/*.html eol=lf
+apps/server/src/assets/doc_notes/** linguist-vendored=true
+apps/edit-docs/demo/** linguist-vendored=true
+docs/** linguist-vendored=true
+# Normalize line endings.
docs/**/*.md eol=lf
docs/**/*.json eol=lf
-
demo/**/*.html eol=lf
demo/**/*.json eol=lf
demo/**/*.svg eol=lf
demo/**/*.txt eol=lf
demo/**/*.js eol=lf
demo/**/*.css eol=lf
-
-apps/client/src/libraries/** linguist-vendored
\ No newline at end of file
+*.sh eol=lf
diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml
index 6497ebb96..0b3f768de 100644
--- a/.github/workflows/dev.yml
+++ b/.github/workflows/dev.yml
@@ -39,7 +39,7 @@ jobs:
- uses: nrwl/nx-set-shas@v4
- name: Check affected
- run: pnpm nx affected -t build rebuild-deps
+ run: pnpm nx affected --verbose -t typecheck build rebuild-deps
report-electron-size:
name: Report Electron size
@@ -128,7 +128,7 @@ jobs:
- run: pnpm install --frozen-lockfile
- name: Run the unit tests
- run: pnpm run test
+ run: pnpm run test:all
build_docker:
name: Build Docker image
diff --git a/.github/workflows/main-docker.yml b/.github/workflows/main-docker.yml
index 84bea09e2..f06e7b3e9 100644
--- a/.github/workflows/main-docker.yml
+++ b/.github/workflows/main-docker.yml
@@ -53,7 +53,7 @@ jobs:
run: pnpm install --frozen-lockfile
- name: Install Playwright Browsers
- run: npx playwright install --with-deps
+ run: pnpx playwright install --with-deps
- name: Run the TypeScript build
run: pnpm run server:build
@@ -62,7 +62,7 @@ jobs:
uses: docker/build-push-action@v6
with:
context: apps/server
- file: ${{ matrix.dockerfile }}
+ file: apps/server/${{ matrix.dockerfile }}
load: true
tags: ${{ env.TEST_TAG }}
cache-from: type=gha
@@ -70,7 +70,7 @@ jobs:
- name: Validate container run output
run: |
- CONTAINER_ID=$(docker run -d --log-driver=journald --rm --network=host -e TRILIUM_PORT=8082 --volume ./integration-tests/db:/home/node/trilium-data --name trilium_local ${{ env.TEST_TAG }})
+ CONTAINER_ID=$(docker run -d --log-driver=journald --rm --network=host -e TRILIUM_PORT=8082 --volume ./apps/server/spec/db:/home/node/trilium-data --name trilium_local ${{ env.TEST_TAG }})
echo "Container ID: $CONTAINER_ID"
- name: Wait for the healthchecks to pass
@@ -82,7 +82,7 @@ jobs:
require-healthy: true
- name: Run Playwright tests
- run: TRILIUM_DOCKER=1 npx playwright test
+ run: TRILIUM_DOCKER=1 TRILIUM_PORT=8082 pnpx nx run server-e2e:e2e
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
@@ -129,7 +129,6 @@ jobs:
- name: Set TEST_TAG to lowercase
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
-
- name: Checkout repository
uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
@@ -142,6 +141,9 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
+ - name: Run the TypeScript build
+ run: pnpm run server:build
+
- name: Update build info
run: pnpm run chore:update-build-info
@@ -184,7 +186,7 @@ jobs:
uses: docker/build-push-action@v6
with:
context: apps/server
- file: ${{ matrix.dockerfile }}
+ file: apps/server/${{ matrix.dockerfile }}
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 47d8e57e3..597f1173d 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -33,11 +33,11 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
- - run: npx playwright install --with-deps
+ - run: pnpx playwright install --with-deps
- uses: nrwl/nx-set-shas@v4
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
# - run: npx nx-cloud record -- echo Hello World
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
# When you enable task distribution, run the e2e-ci task instead of e2e
- - run: npx nx affected -t e2e
+ - run: pnpx nx affected -t e2e
diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 000000000..156ca6d39
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+22.16.0
\ No newline at end of file
diff --git a/.nxignore b/.nxignore
index 7290b55e6..bac1baa0e 100644
--- a/.nxignore
+++ b/.nxignore
@@ -1,2 +1,7 @@
_regroup
-_regroup_monorepo
\ No newline at end of file
+_regroup_monorepo
+
+# Asset copying respects .gitignore / .nxignore for some reason.
+# See https://github.com/nrwl/nx/issues/20309
+!dist
+!node_modules
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 60b3455da..5a2764983 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -24,5 +24,9 @@
},
"github-actions.workflows.pinned.workflows": [
".github/workflows/nightly.yml"
- ]
+ ],
+ "typescript.validate.enable": true,
+ "typescript.tsserver.experimental.enableProjectDiagnostics": true,
+ "typescript.tsdk": "node_modules/typescript/lib",
+ "typescript.enablePromptUseWorkspaceTsdk": true
}
\ No newline at end of file
diff --git a/README.md b/README.md
index 496ce506b..ce0b930bc 100644
--- a/README.md
+++ b/README.md
@@ -4,15 +4,47 @@
[English](./README.md) | [Chinese](./docs/README-ZH_CN.md) | [Russian](./docs/README.ru.md) | [Japanese](./docs/README.ja.md) | [Italian](./docs/README.it.md) | [Spanish](./docs/README.es.md)
-TriliumNext Notes is an open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases.
+TriliumNext Notes is a free and open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases.
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for quick overview:
+## 🎁 Features
+
+* Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://triliumnext.github.io/Docs/Wiki/cloning-notes))
+* Rich WYSIWYG note editor including e.g. tables, images and [math](https://triliumnext.github.io/Docs/Wiki/text-notes) with markdown [autoformat](https://triliumnext.github.io/Docs/Wiki/text-notes#autoformat)
+* Support for editing [notes with source code](https://triliumnext.github.io/Docs/Wiki/code-notes), including syntax highlighting
+* 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)
+* Seamless [note versioning](https://triliumnext.github.io/Docs/Wiki/note-revisions)
+* 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)
+* UI available in English, German, Spanish, French, Romanian, and Chinese (simplified and traditional)
+* Direct [OpenID and TOTP integration](.docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Server%20Installation/Multi-Factor%20Authentication.md") 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
+* Strong [note encryption](https://triliumnext.github.io/Docs/Wiki/protected-notes) with per-note granularity
+* Sketching diagrams, based on [Excalidraw](https://excalidraw.com/) (note type "canvas")
+* [Relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map) and [link maps](https://triliumnext.github.io/Docs/Wiki/link-map) for visualizing notes and their relations
+* Mind maps, based on [Mind Elixir](https://docs.mind-elixir.com/)
+* [Geo maps](./docs/User%20Guide/User%20Guide/Note%20Types/Geo%20Map.md) with location pins and GPX tracks
+* [Scripting](https://triliumnext.github.io/Docs/Wiki/scripts) - see [Advanced showcases](https://triliumnext.github.io/Docs/Wiki/advanced-showcases)
+* [REST API](https://triliumnext.github.io/Docs/Wiki/etapi) for automation
+* Scales well in both usability and performance upwards of 100 000 notes
+* Touch optimized [mobile frontend](https://triliumnext.github.io/Docs/Wiki/mobile-frontend) for smartphones and tablets
+* Built-in [dark theme](https://triliumnext.github.io/Docs/Wiki/themes), support for user themes
+* [Evernote](https://triliumnext.github.io/Docs/Wiki/evernote-import) and [Markdown import & export](https://triliumnext.github.io/Docs/Wiki/markdown)
+* [Web Clipper](https://triliumnext.github.io/Docs/Wiki/web-clipper) for easy saving of web content
+* Customizable UI (sidebar buttons, user-defined widgets, ...)
+
+✨ Check out the following third-party resources/communities for more TriliumNext related goodies:
+
+- [awesome-trilium](https://github.com/Nriver/awesome-trilium) for 3rd party themes, scripts, plugins and more.
+- [TriliumRocks!](https://trilium.rocks/) for tutorials, guides, and much more.
+
## ⚠️ Why TriliumNext?
-[The original Trilium project is in maintenance mode](https://github.com/zadam/trilium/issues/4620)
+[The original Trilium project is in maintenance mode](https://github.com/zadam/trilium/issues/4620).
### Migrating from Trilium?
@@ -20,53 +52,49 @@ There are no special migration steps to migrate from a zadam/Trilium instance to
Versions up to and including [v0.90.4](https://github.com/TriliumNext/Notes/releases/tag/v0.90.4) are compatible with the latest zadam/trilium version of [v0.63.7](https://github.com/zadam/trilium/releases/tag/v0.63.7). Any later versions of TriliumNext have their sync versions incremented.
+## 📖 Documentation
+
+We're currently in the progress of moving the documentation to in-app (hit the `F1` key within Trilium). As a result, there may be some missing parts until we've completed the migration. If you'd prefer to navigate through the documentation within GitHub, you can navigate the [User Guide](./docs/User%20Guide/User%20Guide/) documentation.
+
+Below are some quick links for your convenience to navigate the documentation:
+- [Server installation](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation.md)
+ - [Docker installation](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation/1.%20Installing%20the%20server/Using%20Docker.md)
+- [Upgrading TriliumNext](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Upgrading%20TriliumNext.md)
+- [Concepts and Features - Note](./docs/User%20Guide/User%20Guide/Basic%20Concepts%20and%20Features/Notes.md)
+- [Patterns of personal knowledge base](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge)
+
+Until we finish reorganizing the documentation, you may also want to [browse the old documentation](https://triliumnext.github.io/Docs).
+
## 💬 Discuss with us
Feel free to join our official conversations. We would love to hear what features, suggestions, or issues you may have!
-- [Matrix](https://matrix.to/#/#triliumnext:matrix.org) (For synchronous discussions)
+- [Matrix](https://matrix.to/#/#triliumnext:matrix.org) (For synchronous discussions.)
- The `General` Matrix room is also bridged to [XMPP](xmpp:discuss@trilium.thisgreat.party?join)
-- [Github Discussions](https://github.com/TriliumNext/Notes/discussions) (For Asynchronous discussions)
-- [Wiki](https://triliumnext.github.io/Docs/) (For common how-to questions and user guides)
-
-## 🎁 Features
-
-* Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://triliumnext.github.io/Docs/Wiki/cloning-notes))
-* Rich WYSIWYG note editing including e.g. tables, images and [math](https://triliumnext.github.io/Docs/Wiki/text-notes) with markdown [autoformat](https://triliumnext.github.io/Docs/Wiki/text-notes#autoformat)
-* Support for editing [notes with source code](https://triliumnext.github.io/Docs/Wiki/code-notes), including syntax highlighting
-* 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)
-* Seamless [note versioning](https://triliumnext.github.io/Docs/Wiki/note-revisions)
-* 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
-* Strong [note encryption](https://triliumnext.github.io/Docs/Wiki/protected-notes) with per-note granularity
-* Sketching diagrams with built-in Excalidraw (note type "canvas")
-* [Relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map) and [link maps](https://triliumnext.github.io/Docs/Wiki/link-map) for visualizing notes and their relations
-* [Scripting](https://triliumnext.github.io/Docs/Wiki/scripts) - see [Advanced showcases](https://triliumnext.github.io/Docs/Wiki/advanced-showcases)
-* [REST API](https://triliumnext.github.io/Docs/Wiki/etapi) for automation
-* Scales well in both usability and performance upwards of 100 000 notes
-* Touch optimized [mobile frontend](https://triliumnext.github.io/Docs/Wiki/mobile-frontend) for smartphones and tablets
-* [Night theme](https://triliumnext.github.io/Docs/Wiki/themes)
-* [Evernote](https://triliumnext.github.io/Docs/Wiki/evernote-import) and [Markdown import & export](https://triliumnext.github.io/Docs/Wiki/markdown)
-* [Web Clipper](https://triliumnext.github.io/Docs/Wiki/web-clipper) for easy saving of web content
-
-✨ Check out the following third-party resources/communities for more TriliumNext related goodies:
-
-- [awesome-trilium](https://github.com/Nriver/awesome-trilium) for 3rd party themes, scripts, plugins and more.
-- [TriliumRocks!](https://trilium.rocks/) for tutorials, guides, and much more.
+- [Github Discussions](https://github.com/TriliumNext/Notes/discussions) (For asynchronous discussions.)
+- [Github Issues](https://github.com/TriliumNext/Notes/issues) (For bug reports and feature requests.)
## 🏗 Installation
-### Desktop
+### Windows / MacOS
-To use TriliumNext on your desktop machine (Linux, MacOS, and Windows) you have a few options:
+Download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Notes/releases/latest), unzip the package and run the `trilium` executable.
-* Download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Notes/releases/latest), unzip the package and run the ```trilium``` executable.
-* Access TriliumNext via the web interface of a server installation (see below)
- * Currently only the latest versions of Chrome & Firefox are supported (and tested).
-* TriliumNext is also provided as a Flatpak, but not yet published on FlatHub.
+### Linux
+
+If your distribution is listed in the table below, use your distribution's package.
+
+[](https://repology.org/project/triliumnext/versions)
+
+You may also download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Notes/releases/latest), unzip the package and run the `trilium` executable.
+
+TriliumNext is also provided as a Flatpak, but not yet published on FlatHub.
+
+### Browser (any OS)
+
+If you use a server installation (see below), you can directly access the web interface (which is almost identical to the desktop app).
+
+Currently only the latest versions of Chrome & Firefox are supported (and tested).
### Mobile
@@ -80,28 +108,43 @@ See issue https://github.com/TriliumNext/Notes/issues/72 for more information on
To install TriliumNext on your own server (including via Docker from [Dockerhub](https://hub.docker.com/r/triliumnext/notes)) follow [the server installation docs](https://triliumnext.github.io/Docs/Wiki/server-installation).
-## 📝 Documentation
-
-[See wiki for complete list of documentation pages.](https://triliumnext.github.io/Docs)
-
-You can also read [Patterns of personal knowledge base](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge) to get some inspiration on how you might use TriliumNext.
## 💻 Contribute
### Code
+Download the repository, install dependencies using `pnpm` and then run the server (available at http://localhost:8080):
```shell
git clone https://github.com/TriliumNext/Notes.git
cd Notes
-npm install
-npm run server:start
+pnpm install
+pnpm run server:start
+```
+
+### Documentation
+
+Download the repository, install dependencies using `pnpm` and then run the environment required to edit the documentation:
+```shell
+git clone https://github.com/TriliumNext/Notes.git
+cd Notes
+pnpm install
+pnpm nx run edit-docs:edit-docs
+```
+
+### Building the Executable
+Download the repository, install dependencies using `pnpm` and then build the desktop app for Windows:
+```shell
+git clone https://github.com/TriliumNext/Notes.git
+cd Notes
+pnpm install
+pnpm nx --project=desktop electron-forge:make -- --arch=x64 --platform=win32
```
For more details, see the [development docs](https://github.com/TriliumNext/Notes/blob/develop/docs/Developer%20Guide/Developer%20Guide/Building%20and%20deployment/Running%20a%20development%20build.md).
-### Documentation
+### Developer Documentation
-See the [documentation guide](https://github.com/TriliumNext/Notes/blob/develop/docs/Developer%20Guide/Developer%20Guide/Documentation.md) for details.
+Please view the [documentation guide](./docs/Developer%20Guide/Developer%20Guide/Environment%20Setup.md) for details. If you have more questions, feel free to reach out via the links described in the "Discuss with us" section above.
## 👏 Shoutouts
@@ -119,4 +162,6 @@ Support for the TriliumNext organization will be possible in the near future. Fo
## 🔑 License
+Copyright 2017-2025 zadam, Elian Doran, and other contributors
+
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
diff --git a/_regroup/ckeditor5-build-trilium/ckeditor-content.css b/_regroup/ckeditor5-build-trilium/ckeditor-content.css
deleted file mode 100644
index 94d440047..000000000
--- a/_regroup/ckeditor5-build-trilium/ckeditor-content.css
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
- * CKEditor 5 (v41.0.0) content styles.
- * Generated on Fri, 26 Jan 2024 10:23:49 GMT.
- * For more information, check out https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/content-styles.html
- */
-
-:root {
- --ck-color-image-caption-background: hsl(0, 0%, 97%);
- --ck-color-image-caption-text: hsl(0, 0%, 20%);
- --ck-color-mention-background: hsla(341, 100%, 30%, 0.1);
- --ck-color-mention-text: hsl(341, 100%, 30%);
- --ck-color-selector-caption-background: hsl(0, 0%, 97%);
- --ck-color-selector-caption-text: hsl(0, 0%, 20%);
- --ck-highlight-marker-blue: hsl(201, 97%, 72%);
- --ck-highlight-marker-green: hsl(120, 93%, 68%);
- --ck-highlight-marker-pink: hsl(345, 96%, 73%);
- --ck-highlight-marker-yellow: hsl(60, 97%, 73%);
- --ck-highlight-pen-green: hsl(112, 100%, 27%);
- --ck-highlight-pen-red: hsl(0, 85%, 49%);
- --ck-image-style-spacing: 1.5em;
- --ck-inline-image-style-spacing: calc(var(--ck-image-style-spacing) / 2);
- --ck-todo-list-checkmark-size: 16px;
-}
-
-/* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */
-.ck-content .table .ck-table-resized {
- table-layout: fixed;
-}
-/* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */
-.ck-content .table table {
- overflow: hidden;
-}
-/* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */
-.ck-content .table td,
-.ck-content .table th {
- overflow-wrap: break-word;
- position: relative;
-}
-/* @ckeditor/ckeditor5-table/theme/table.css */
-.ck-content .table {
- margin: 0.9em auto;
- display: table;
-}
-/* @ckeditor/ckeditor5-table/theme/table.css */
-.ck-content .table table {
- border-collapse: collapse;
- border-spacing: 0;
- width: 100%;
- height: 100%;
- border: 1px double hsl(0, 0%, 70%);
-}
-/* @ckeditor/ckeditor5-table/theme/table.css */
-.ck-content .table table td,
-.ck-content .table table th {
- min-width: 2em;
- padding: .4em;
- border: 1px solid hsl(0, 0%, 75%);
-}
-/* @ckeditor/ckeditor5-table/theme/table.css */
-.ck-content .table table th {
- font-weight: bold;
- background: hsla(0, 0%, 0%, 5%);
-}
-/* @ckeditor/ckeditor5-table/theme/table.css */
-.ck-content[dir="rtl"] .table th {
- text-align: right;
-}
-/* @ckeditor/ckeditor5-table/theme/table.css */
-.ck-content[dir="ltr"] .table th {
- text-align: left;
-}
-/* @ckeditor/ckeditor5-table/theme/tablecaption.css */
-.ck-content .table > figcaption {
- display: table-caption;
- caption-side: top;
- word-break: break-word;
- text-align: center;
- color: var(--ck-color-selector-caption-text);
- background-color: var(--ck-color-selector-caption-background);
- padding: .6em;
- font-size: .75em;
- outline-offset: -1px;
-}
-/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
-.ck-content .page-break {
- position: relative;
- clear: both;
- padding: 5px 0;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
-.ck-content .page-break::after {
- content: '';
- position: absolute;
- border-bottom: 2px dashed hsl(0, 0%, 77%);
- width: 100%;
-}
-/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
-.ck-content .page-break__label {
- position: relative;
- z-index: 1;
- padding: .3em .6em;
- display: block;
- text-transform: uppercase;
- border: 1px solid hsl(0, 0%, 77%);
- border-radius: 2px;
- font-family: Helvetica, Arial, Tahoma, Verdana, Sans-Serif;
- font-size: 0.75em;
- font-weight: bold;
- color: hsl(0, 0%, 20%);
- background: hsl(0, 0%, 100%);
- box-shadow: 2px 2px 1px hsla(0, 0%, 0%, 0.15);
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-/* @ckeditor/ckeditor5-media-embed/theme/mediaembed.css */
-.ck-content .media {
- clear: both;
- margin: 0.9em 0;
- display: block;
- min-width: 15em;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list {
- list-style: none;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list li {
- position: relative;
- margin-bottom: 5px;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list li .todo-list {
- margin-top: 5px;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label > input {
- -webkit-appearance: none;
- display: inline-block;
- position: relative;
- width: var(--ck-todo-list-checkmark-size);
- height: var(--ck-todo-list-checkmark-size);
- vertical-align: middle;
- border: 0;
- left: -25px;
- margin-right: -15px;
- right: 0;
- margin-left: 0;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content[dir=rtl] .todo-list .todo-list__label > input {
- left: 0;
- margin-right: 0;
- right: -25px;
- margin-left: -15px;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label > input::before {
- display: block;
- position: absolute;
- box-sizing: border-box;
- content: '';
- width: 100%;
- height: 100%;
- border: 1px solid hsl(0, 0%, 20%);
- border-radius: 2px;
- transition: 250ms ease-in-out box-shadow;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label > input::after {
- display: block;
- position: absolute;
- box-sizing: content-box;
- pointer-events: none;
- content: '';
- left: calc( var(--ck-todo-list-checkmark-size) / 3 );
- top: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
- width: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
- height: calc( var(--ck-todo-list-checkmark-size) / 2.6 );
- border-style: solid;
- border-color: transparent;
- border-width: 0 calc( var(--ck-todo-list-checkmark-size) / 8 ) calc( var(--ck-todo-list-checkmark-size) / 8 ) 0;
- transform: rotate(45deg);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label > input[checked]::before {
- background: hsl(126, 64%, 41%);
- border-color: hsl(126, 64%, 41%);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label > input[checked]::after {
- border-color: hsl(0, 0%, 100%);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label .todo-list__label__description {
- vertical-align: middle;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label.todo-list__label_without-description input[type=checkbox] {
- position: absolute;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > input,
-.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input {
- cursor: pointer;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > input:hover::before, .ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input:hover::before {
- box-shadow: 0 0 0 5px hsla(0, 0%, 0%, 0.1);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input {
- -webkit-appearance: none;
- display: inline-block;
- position: relative;
- width: var(--ck-todo-list-checkmark-size);
- height: var(--ck-todo-list-checkmark-size);
- vertical-align: middle;
- border: 0;
- left: -25px;
- margin-right: -15px;
- right: 0;
- margin-left: 0;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content[dir=rtl] .todo-list .todo-list__label > span[contenteditable=false] > input {
- left: 0;
- margin-right: 0;
- right: -25px;
- margin-left: -15px;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input::before {
- display: block;
- position: absolute;
- box-sizing: border-box;
- content: '';
- width: 100%;
- height: 100%;
- border: 1px solid hsl(0, 0%, 20%);
- border-radius: 2px;
- transition: 250ms ease-in-out box-shadow;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input::after {
- display: block;
- position: absolute;
- box-sizing: content-box;
- pointer-events: none;
- content: '';
- left: calc( var(--ck-todo-list-checkmark-size) / 3 );
- top: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
- width: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
- height: calc( var(--ck-todo-list-checkmark-size) / 2.6 );
- border-style: solid;
- border-color: transparent;
- border-width: 0 calc( var(--ck-todo-list-checkmark-size) / 8 ) calc( var(--ck-todo-list-checkmark-size) / 8 ) 0;
- transform: rotate(45deg);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input[checked]::before {
- background: hsl(126, 64%, 41%);
- border-color: hsl(126, 64%, 41%);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input[checked]::after {
- border-color: hsl(0, 0%, 100%);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label.todo-list__label_without-description input[type=checkbox] {
- position: absolute;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ol {
- list-style-type: decimal;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ol ol {
- list-style-type: lower-latin;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ol ol ol {
- list-style-type: lower-roman;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ol ol ol ol {
- list-style-type: upper-latin;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ol ol ol ol ol {
- list-style-type: upper-roman;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ul {
- list-style-type: disc;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ul ul {
- list-style-type: circle;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ul ul ul {
- list-style-type: square;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ul ul ul ul {
- list-style-type: square;
-}
-/* @ckeditor/ckeditor5-image/theme/image.css */
-.ck-content .image {
- display: table;
- clear: both;
- text-align: center;
- margin: 0.9em auto;
- min-width: 50px;
-}
-/* @ckeditor/ckeditor5-image/theme/image.css */
-.ck-content .image img {
- display: block;
- margin: 0 auto;
- max-width: 100%;
- min-width: 100%;
- height: auto;
-}
-/* @ckeditor/ckeditor5-image/theme/image.css */
-.ck-content .image-inline {
- /*
- * Normally, the .image-inline would have "display: inline-block" and "img { width: 100% }" (to follow the wrapper while resizing).;
- * Unfortunately, together with "srcset", it gets automatically stretched up to the width of the editing root.
- * This strange behavior does not happen with inline-flex.
- */
- display: inline-flex;
- max-width: 100%;
- align-items: flex-start;
-}
-/* @ckeditor/ckeditor5-image/theme/image.css */
-.ck-content .image-inline picture {
- display: flex;
-}
-/* @ckeditor/ckeditor5-image/theme/image.css */
-.ck-content .image-inline picture,
-.ck-content .image-inline img {
- flex-grow: 1;
- flex-shrink: 1;
- max-width: 100%;
-}
-/* @ckeditor/ckeditor5-image/theme/imageresize.css */
-.ck-content img.image_resized {
- height: auto;
-}
-/* @ckeditor/ckeditor5-image/theme/imageresize.css */
-.ck-content .image.image_resized {
- max-width: 100%;
- display: block;
- box-sizing: border-box;
-}
-/* @ckeditor/ckeditor5-image/theme/imageresize.css */
-.ck-content .image.image_resized img {
- width: 100%;
-}
-/* @ckeditor/ckeditor5-image/theme/imageresize.css */
-.ck-content .image.image_resized > figcaption {
- display: block;
-}
-/* @ckeditor/ckeditor5-image/theme/imagecaption.css */
-.ck-content .image > figcaption {
- display: table-caption;
- caption-side: bottom;
- word-break: break-word;
- color: var(--ck-color-image-caption-text);
- background-color: var(--ck-color-image-caption-background);
- padding: .6em;
- font-size: .75em;
- outline-offset: -1px;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-block-align-left,
-.ck-content .image-style-block-align-right {
- max-width: calc(100% - var(--ck-image-style-spacing));
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-align-left,
-.ck-content .image-style-align-right {
- clear: none;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-side {
- float: right;
- margin-left: var(--ck-image-style-spacing);
- max-width: 50%;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-align-left {
- float: left;
- margin-right: var(--ck-image-style-spacing);
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-align-center {
- margin-left: auto;
- margin-right: auto;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-align-right {
- float: right;
- margin-left: var(--ck-image-style-spacing);
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-block-align-right {
- margin-right: 0;
- margin-left: auto;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-block-align-left {
- margin-left: 0;
- margin-right: auto;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content p + .image-style-align-left,
-.ck-content p + .image-style-align-right,
-.ck-content p + .image-style-side {
- margin-top: 0;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-inline.image-style-align-left,
-.ck-content .image-inline.image-style-align-right {
- margin-top: var(--ck-inline-image-style-spacing);
- margin-bottom: var(--ck-inline-image-style-spacing);
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-inline.image-style-align-left {
- margin-right: var(--ck-inline-image-style-spacing);
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-inline.image-style-align-right {
- margin-left: var(--ck-inline-image-style-spacing);
-}
-/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
-.ck-content .marker-yellow {
- background-color: var(--ck-highlight-marker-yellow);
-}
-/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
-.ck-content .marker-green {
- background-color: var(--ck-highlight-marker-green);
-}
-/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
-.ck-content .marker-pink {
- background-color: var(--ck-highlight-marker-pink);
-}
-/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
-.ck-content .marker-blue {
- background-color: var(--ck-highlight-marker-blue);
-}
-/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
-.ck-content .pen-red {
- color: var(--ck-highlight-pen-red);
- background-color: transparent;
-}
-/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
-.ck-content .pen-green {
- color: var(--ck-highlight-pen-green);
- background-color: transparent;
-}
-/* @ckeditor/ckeditor5-block-quote/theme/blockquote.css */
-.ck-content blockquote {
- overflow: hidden;
- padding-right: 1.5em;
- padding-left: 1.5em;
- margin-left: 0;
- margin-right: 0;
- font-style: italic;
- border-left: solid 5px hsl(0, 0%, 80%);
-}
-/* @ckeditor/ckeditor5-block-quote/theme/blockquote.css */
-.ck-content[dir="rtl"] blockquote {
- border-left: 0;
- border-right: solid 5px hsl(0, 0%, 80%);
-}
-/* @ckeditor/ckeditor5-basic-styles/theme/code.css */
-.ck-content code {
- background-color: hsla(0, 0%, 78%, 0.3);
- padding: .15em;
- border-radius: 2px;
-}
-/* @ckeditor/ckeditor5-font/theme/fontsize.css */
-.ck-content .text-tiny {
- font-size: .7em;
-}
-/* @ckeditor/ckeditor5-font/theme/fontsize.css */
-.ck-content .text-small {
- font-size: .85em;
-}
-/* @ckeditor/ckeditor5-font/theme/fontsize.css */
-.ck-content .text-big {
- font-size: 1.4em;
-}
-/* @ckeditor/ckeditor5-font/theme/fontsize.css */
-.ck-content .text-huge {
- font-size: 1.8em;
-}
-/* @ckeditor/ckeditor5-mention/theme/mention.css */
-.ck-content .mention {
- background: var(--ck-color-mention-background);
- color: var(--ck-color-mention-text);
-}
-/* @ckeditor/ckeditor5-horizontal-line/theme/horizontalline.css */
-.ck-content hr {
- margin: 15px 0;
- height: 4px;
- background: hsl(0, 0%, 87%);
- border: 0;
-}
-/* @ckeditor/ckeditor5-code-block/theme/codeblock.css */
-.ck-content pre {
- padding: 1em;
- text-align: left;
- direction: ltr;
- tab-size: 4;
- white-space: pre-wrap;
- font-style: normal;
- min-width: 200px;
- border: 0px;
- border-radius: 6px;
- box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.2);
-}
-.ck-content pre:not(.hljs) {
- color: hsl(0, 0%, 20.8%);
- background: hsla(0, 0%, 78%, 0.3);
-}
-/* @ckeditor/ckeditor5-code-block/theme/codeblock.css */
-.ck-content pre code {
- background: unset;
- padding: 0;
- border-radius: 0;
-}
-@media print {
- /* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
- .ck-content .page-break {
- padding: 0;
- }
- /* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
- .ck-content .page-break::after {
- display: none;
- }
-}
diff --git a/_regroup/demo/style.css b/_regroup/demo/style.css
deleted file mode 100644
index 0ebbae93d..000000000
--- a/_regroup/demo/style.css
+++ /dev/null
@@ -1,593 +0,0 @@
-/* !!!!!! TRILIUM CUSTOM CHANGES !!!!!! */
-
-.printed-content .ck-widget__selection-handle, .printed-content .ck-widget__type-around { /* gets rid of triangles: https://github.com/zadam/trilium/issues/1129 */
- display: none;
-}
-
-.page-break {
- page-break-after: always;
-}
-
-.printed-content .page-break:after,
-.printed-content .page-break > * {
- display: none !important;
-}
-
-.ck-content li p {
- margin: 0 !important;
-}
-
-.admonition {
- --accent-color: var(--card-border-color);
- border: 1px solid var(--accent-color);
- box-shadow: var(--card-box-shadow);
- background: var(--card-background-color);
- border-radius: 0.5em;
- padding: 1em;
- margin: 1.25em 0;
- position: relative;
- overflow: hidden;
-}
-
-.admonition p:last-child {
- margin-bottom: 0;
-}
-
-.admonition p, h2 {
- margin-top: 0;
-}
-
-.admonition.note { --accent-color: #69c7ff; }
-.admonition.tip { --accent-color: #40c025; }
-.admonition.important { --accent-color: #9839f7; }
-.admonition.caution { --accent-color: #ff2e2e; }
-.admonition.warning { --accent-color: #e2aa03; }
-
-/*
- * CKEditor 5 (v41.0.0) content styles.
- * Generated on Fri, 26 Jan 2024 10:23:49 GMT.
- * For more information, check out https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/content-styles.html
- */
-
-:root {
- --ck-color-image-caption-background: hsl(0, 0%, 97%);
- --ck-color-image-caption-text: hsl(0, 0%, 20%);
- --ck-color-mention-background: hsla(341, 100%, 30%, 0.1);
- --ck-color-mention-text: hsl(341, 100%, 30%);
- --ck-color-selector-caption-background: hsl(0, 0%, 97%);
- --ck-color-selector-caption-text: hsl(0, 0%, 20%);
- --ck-highlight-marker-blue: hsl(201, 97%, 72%);
- --ck-highlight-marker-green: hsl(120, 93%, 68%);
- --ck-highlight-marker-pink: hsl(345, 96%, 73%);
- --ck-highlight-marker-yellow: hsl(60, 97%, 73%);
- --ck-highlight-pen-green: hsl(112, 100%, 27%);
- --ck-highlight-pen-red: hsl(0, 85%, 49%);
- --ck-image-style-spacing: 1.5em;
- --ck-inline-image-style-spacing: calc(var(--ck-image-style-spacing) / 2);
- --ck-todo-list-checkmark-size: 16px;
-}
-
-/* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */
-.ck-content .table .ck-table-resized {
- table-layout: fixed;
-}
-/* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */
-.ck-content .table table {
- overflow: hidden;
-}
-/* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */
-.ck-content .table td,
-.ck-content .table th {
- overflow-wrap: break-word;
- position: relative;
-}
-/* @ckeditor/ckeditor5-table/theme/table.css */
-.ck-content .table {
- margin: 0.9em auto;
- display: table;
-}
-/* @ckeditor/ckeditor5-table/theme/table.css */
-.ck-content .table table {
- border-collapse: collapse;
- border-spacing: 0;
- width: 100%;
- height: 100%;
- border: 1px double hsl(0, 0%, 70%);
-}
-/* @ckeditor/ckeditor5-table/theme/table.css */
-.ck-content .table table td,
-.ck-content .table table th {
- min-width: 2em;
- padding: .4em;
- border: 1px solid hsl(0, 0%, 75%);
-}
-/* @ckeditor/ckeditor5-table/theme/table.css */
-.ck-content .table table th {
- font-weight: bold;
- background: hsla(0, 0%, 0%, 5%);
-}
-/* @ckeditor/ckeditor5-table/theme/table.css */
-.ck-content[dir="rtl"] .table th {
- text-align: right;
-}
-/* @ckeditor/ckeditor5-table/theme/table.css */
-.ck-content[dir="ltr"] .table th {
- text-align: left;
-}
-/* @ckeditor/ckeditor5-table/theme/tablecaption.css */
-.ck-content .table > figcaption {
- display: table-caption;
- caption-side: top;
- word-break: break-word;
- text-align: center;
- color: var(--ck-color-selector-caption-text);
- background-color: var(--ck-color-selector-caption-background);
- padding: .6em;
- font-size: .75em;
- outline-offset: -1px;
-}
-/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
-.ck-content .page-break {
- position: relative;
- clear: both;
- padding: 5px 0;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
-.ck-content .page-break::after {
- content: '';
- position: absolute;
- border-bottom: 2px dashed hsl(0, 0%, 77%);
- width: 100%;
-}
-/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
-.ck-content .page-break__label {
- position: relative;
- z-index: 1;
- padding: .3em .6em;
- display: block;
- text-transform: uppercase;
- border: 1px solid hsl(0, 0%, 77%);
- border-radius: 2px;
- font-family: Helvetica, Arial, Tahoma, Verdana, Sans-Serif;
- font-size: 0.75em;
- font-weight: bold;
- color: hsl(0, 0%, 20%);
- background: hsl(0, 0%, 100%);
- box-shadow: 2px 2px 1px hsla(0, 0%, 0%, 0.15);
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-/* @ckeditor/ckeditor5-media-embed/theme/mediaembed.css */
-.ck-content .media {
- clear: both;
- margin: 0.9em 0;
- display: block;
- min-width: 15em;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list {
- list-style: none;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list li {
- position: relative;
- margin-bottom: 5px;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list li .todo-list {
- margin-top: 5px;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label > input {
- -webkit-appearance: none;
- display: inline-block;
- position: relative;
- width: var(--ck-todo-list-checkmark-size);
- height: var(--ck-todo-list-checkmark-size);
- vertical-align: middle;
- border: 0;
- left: -25px;
- margin-right: -15px;
- right: 0;
- margin-left: 0;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content[dir=rtl] .todo-list .todo-list__label > input {
- left: 0;
- margin-right: 0;
- right: -25px;
- margin-left: -15px;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label > input::before {
- display: block;
- position: absolute;
- box-sizing: border-box;
- content: '';
- width: 100%;
- height: 100%;
- border: 1px solid hsl(0, 0%, 20%);
- border-radius: 2px;
- transition: 250ms ease-in-out box-shadow;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label > input::after {
- display: block;
- position: absolute;
- box-sizing: content-box;
- pointer-events: none;
- content: '';
- left: calc( var(--ck-todo-list-checkmark-size) / 3 );
- top: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
- width: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
- height: calc( var(--ck-todo-list-checkmark-size) / 2.6 );
- border-style: solid;
- border-color: transparent;
- border-width: 0 calc( var(--ck-todo-list-checkmark-size) / 8 ) calc( var(--ck-todo-list-checkmark-size) / 8 ) 0;
- transform: rotate(45deg);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label > input[checked]::before {
- background: hsl(126, 64%, 41%);
- border-color: hsl(126, 64%, 41%);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label > input[checked]::after {
- border-color: hsl(0, 0%, 100%);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label .todo-list__label__description {
- vertical-align: middle;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-content .todo-list .todo-list__label.todo-list__label_without-description input[type=checkbox] {
- position: absolute;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > input,
-.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input {
- cursor: pointer;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > input:hover::before, .ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input:hover::before {
- box-shadow: 0 0 0 5px hsla(0, 0%, 0%, 0.1);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input {
- -webkit-appearance: none;
- display: inline-block;
- position: relative;
- width: var(--ck-todo-list-checkmark-size);
- height: var(--ck-todo-list-checkmark-size);
- vertical-align: middle;
- border: 0;
- left: -25px;
- margin-right: -15px;
- right: 0;
- margin-left: 0;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content[dir=rtl] .todo-list .todo-list__label > span[contenteditable=false] > input {
- left: 0;
- margin-right: 0;
- right: -25px;
- margin-left: -15px;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input::before {
- display: block;
- position: absolute;
- box-sizing: border-box;
- content: '';
- width: 100%;
- height: 100%;
- border: 1px solid hsl(0, 0%, 20%);
- border-radius: 2px;
- transition: 250ms ease-in-out box-shadow;
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input::after {
- display: block;
- position: absolute;
- box-sizing: content-box;
- pointer-events: none;
- content: '';
- left: calc( var(--ck-todo-list-checkmark-size) / 3 );
- top: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
- width: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
- height: calc( var(--ck-todo-list-checkmark-size) / 2.6 );
- border-style: solid;
- border-color: transparent;
- border-width: 0 calc( var(--ck-todo-list-checkmark-size) / 8 ) calc( var(--ck-todo-list-checkmark-size) / 8 ) 0;
- transform: rotate(45deg);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input[checked]::before {
- background: hsl(126, 64%, 41%);
- border-color: hsl(126, 64%, 41%);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input[checked]::after {
- border-color: hsl(0, 0%, 100%);
-}
-/* @ckeditor/ckeditor5-list/theme/todolist.css */
-.ck-editor__editable.ck-content .todo-list .todo-list__label.todo-list__label_without-description input[type=checkbox] {
- position: absolute;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ol {
- list-style-type: decimal;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ol ol {
- list-style-type: lower-latin;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ol ol ol {
- list-style-type: lower-roman;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ol ol ol ol {
- list-style-type: upper-latin;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ol ol ol ol ol {
- list-style-type: upper-roman;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ul {
- list-style-type: disc;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ul ul {
- list-style-type: circle;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ul ul ul {
- list-style-type: square;
-}
-/* @ckeditor/ckeditor5-list/theme/list.css */
-.ck-content ul ul ul ul {
- list-style-type: square;
-}
-/* @ckeditor/ckeditor5-image/theme/image.css */
-.ck-content .image {
- display: table;
- clear: both;
- text-align: center;
- margin: 0.9em auto;
- min-width: 50px;
-}
-/* @ckeditor/ckeditor5-image/theme/image.css */
-.ck-content .image img {
- display: block;
- margin: 0 auto;
- max-width: 100%;
- min-width: 100%;
- height: auto;
-}
-/* @ckeditor/ckeditor5-image/theme/image.css */
-.ck-content .image-inline {
- /*
- * Normally, the .image-inline would have "display: inline-block" and "img { width: 100% }" (to follow the wrapper while resizing).;
- * Unfortunately, together with "srcset", it gets automatically stretched up to the width of the editing root.
- * This strange behavior does not happen with inline-flex.
- */
- display: inline-flex;
- max-width: 100%;
- align-items: flex-start;
-}
-/* @ckeditor/ckeditor5-image/theme/image.css */
-.ck-content .image-inline picture {
- display: flex;
-}
-/* @ckeditor/ckeditor5-image/theme/image.css */
-.ck-content .image-inline picture,
-.ck-content .image-inline img {
- flex-grow: 1;
- flex-shrink: 1;
- max-width: 100%;
-}
-/* @ckeditor/ckeditor5-image/theme/imageresize.css */
-.ck-content img.image_resized {
- height: auto;
-}
-/* @ckeditor/ckeditor5-image/theme/imageresize.css */
-.ck-content .image.image_resized {
- max-width: 100%;
- display: block;
- box-sizing: border-box;
-}
-/* @ckeditor/ckeditor5-image/theme/imageresize.css */
-.ck-content .image.image_resized img {
- width: 100%;
-}
-/* @ckeditor/ckeditor5-image/theme/imageresize.css */
-.ck-content .image.image_resized > figcaption {
- display: block;
-}
-/* @ckeditor/ckeditor5-image/theme/imagecaption.css */
-.ck-content .image > figcaption {
- display: table-caption;
- caption-side: bottom;
- word-break: break-word;
- color: var(--ck-color-image-caption-text);
- background-color: var(--ck-color-image-caption-background);
- padding: .6em;
- font-size: .75em;
- outline-offset: -1px;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-block-align-left,
-.ck-content .image-style-block-align-right {
- max-width: calc(100% - var(--ck-image-style-spacing));
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-align-left,
-.ck-content .image-style-align-right {
- clear: none;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-side {
- float: right;
- margin-left: var(--ck-image-style-spacing);
- max-width: 50%;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-align-left {
- float: left;
- margin-right: var(--ck-image-style-spacing);
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-align-center {
- margin-left: auto;
- margin-right: auto;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-align-right {
- float: right;
- margin-left: var(--ck-image-style-spacing);
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-block-align-right {
- margin-right: 0;
- margin-left: auto;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-style-block-align-left {
- margin-left: 0;
- margin-right: auto;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content p + .image-style-align-left,
-.ck-content p + .image-style-align-right,
-.ck-content p + .image-style-side {
- margin-top: 0;
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-inline.image-style-align-left,
-.ck-content .image-inline.image-style-align-right {
- margin-top: var(--ck-inline-image-style-spacing);
- margin-bottom: var(--ck-inline-image-style-spacing);
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-inline.image-style-align-left {
- margin-right: var(--ck-inline-image-style-spacing);
-}
-/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
-.ck-content .image-inline.image-style-align-right {
- margin-left: var(--ck-inline-image-style-spacing);
-}
-/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
-.ck-content .marker-yellow {
- background-color: var(--ck-highlight-marker-yellow);
-}
-/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
-.ck-content .marker-green {
- background-color: var(--ck-highlight-marker-green);
-}
-/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
-.ck-content .marker-pink {
- background-color: var(--ck-highlight-marker-pink);
-}
-/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
-.ck-content .marker-blue {
- background-color: var(--ck-highlight-marker-blue);
-}
-/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
-.ck-content .pen-red {
- color: var(--ck-highlight-pen-red);
- background-color: transparent;
-}
-/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
-.ck-content .pen-green {
- color: var(--ck-highlight-pen-green);
- background-color: transparent;
-}
-/* @ckeditor/ckeditor5-block-quote/theme/blockquote.css */
-.ck-content blockquote {
- overflow: hidden;
- padding-right: 1.5em;
- padding-left: 1.5em;
- margin-left: 0;
- margin-right: 0;
- font-style: italic;
- border-left: solid 5px hsl(0, 0%, 80%);
-}
-/* @ckeditor/ckeditor5-block-quote/theme/blockquote.css */
-.ck-content[dir="rtl"] blockquote {
- border-left: 0;
- border-right: solid 5px hsl(0, 0%, 80%);
-}
-/* @ckeditor/ckeditor5-basic-styles/theme/code.css */
-.ck-content code {
- background-color: hsla(0, 0%, 78%, 0.3);
- padding: .15em;
- border-radius: 2px;
-}
-/* @ckeditor/ckeditor5-font/theme/fontsize.css */
-.ck-content .text-tiny {
- font-size: .7em;
-}
-/* @ckeditor/ckeditor5-font/theme/fontsize.css */
-.ck-content .text-small {
- font-size: .85em;
-}
-/* @ckeditor/ckeditor5-font/theme/fontsize.css */
-.ck-content .text-big {
- font-size: 1.4em;
-}
-/* @ckeditor/ckeditor5-font/theme/fontsize.css */
-.ck-content .text-huge {
- font-size: 1.8em;
-}
-/* @ckeditor/ckeditor5-mention/theme/mention.css */
-.ck-content .mention {
- background: var(--ck-color-mention-background);
- color: var(--ck-color-mention-text);
-}
-/* @ckeditor/ckeditor5-horizontal-line/theme/horizontalline.css */
-.ck-content hr {
- margin: 15px 0;
- height: 4px;
- background: hsl(0, 0%, 87%);
- border: 0;
-}
-/* @ckeditor/ckeditor5-code-block/theme/codeblock.css */
-.ck-content pre {
- padding: 1em;
- text-align: left;
- direction: ltr;
- tab-size: 4;
- white-space: pre-wrap;
- font-style: normal;
- min-width: 200px;
- border: 0px;
- border-radius: 6px;
- box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.2);
-}
-.ck-content pre:not(.hljs) {
- color: hsl(0, 0%, 20.8%);
- background: hsla(0, 0%, 78%, 0.3);
-}
-/* @ckeditor/ckeditor5-code-block/theme/codeblock.css */
-.ck-content pre code {
- background: unset;
- padding: 0;
- border-radius: 0;
-}
-@media print {
- /* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
- .ck-content .page-break {
- padding: 0;
- }
- /* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
- .ck-content .page-break::after {
- display: none;
- }
-}
diff --git a/_regroup/jsdoc-conf.json b/_regroup/jsdoc-conf.json
deleted file mode 100644
index b61bbacb6..000000000
--- a/_regroup/jsdoc-conf.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "templates": {
- "default": {
- "includeDate": false
- }
- }
-}
diff --git a/_regroup/package.json b/_regroup/package.json
index d3680bc02..80e210e1d 100644
--- a/_regroup/package.json
+++ b/_regroup/package.json
@@ -36,12 +36,12 @@
},
"devDependencies": {
"@playwright/test": "1.52.0",
- "@stylistic/eslint-plugin": "4.2.0",
+ "@stylistic/eslint-plugin": "4.4.0",
"@types/express": "5.0.1",
- "@types/node": "22.15.17",
+ "@types/node": "22.15.29",
"@types/yargs": "17.0.33",
- "@vitest/coverage-v8": "3.1.3",
- "eslint": "9.26.0",
+ "@vitest/coverage-v8": "3.1.4",
+ "eslint": "9.27.0",
"eslint-plugin-simple-import-sort": "12.1.1",
"esm": "3.2.25",
"jsdoc": "4.0.4",
@@ -49,7 +49,7 @@
"rcedit": "4.0.1",
"rimraf": "6.0.1",
"tslib": "2.8.1",
- "typedoc": "0.28.4",
+ "typedoc": "0.28.5",
"typedoc-plugin-missing-exports": "4.0.0"
},
"optionalDependencies": {
diff --git a/_regroup/test-etapi/api-metrics.http b/_regroup/test-etapi/api-metrics.http
new file mode 100644
index 000000000..78aee7217
--- /dev/null
+++ b/_regroup/test-etapi/api-metrics.http
@@ -0,0 +1,43 @@
+### Test regular API metrics endpoint (requires session authentication)
+
+### Get metrics from regular API (default Prometheus format)
+GET {{triliumHost}}/api/metrics
+
+> {%
+client.test("API metrics endpoint returns Prometheus format by default", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ client.assert(response.headers["content-type"].includes("text/plain"), "Content-Type should be text/plain");
+ client.assert(response.body.includes("trilium_info"), "Should contain trilium_info metric");
+ client.assert(response.body.includes("trilium_notes_total"), "Should contain trilium_notes_total metric");
+ client.assert(response.body.includes("# HELP"), "Should contain HELP comments");
+ client.assert(response.body.includes("# TYPE"), "Should contain TYPE comments");
+});
+%}
+
+### Get metrics in JSON format
+GET {{triliumHost}}/api/metrics?format=json
+
+> {%
+client.test("API metrics endpoint returns JSON when requested", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ client.assert(response.headers["content-type"].includes("application/json"), "Content-Type should be application/json");
+ client.assert(response.body.version, "Version info not present");
+ client.assert(response.body.database, "Database info not present");
+ client.assert(response.body.timestamp, "Timestamp not present");
+ client.assert(typeof response.body.database.totalNotes === 'number', "Total notes should be a number");
+ client.assert(typeof response.body.database.activeNotes === 'number', "Active notes should be a number");
+ client.assert(response.body.noteTypes, "Note types breakdown not present");
+ client.assert(response.body.attachmentTypes, "Attachment types breakdown not present");
+ client.assert(response.body.statistics, "Statistics not present");
+});
+%}
+
+### Test invalid format parameter
+GET {{triliumHost}}/api/metrics?format=xml
+
+> {%
+client.test("Invalid format parameter returns error", function() {
+ client.assert(response.status === 500, "Response status should be 500");
+ client.assert(response.body.message.includes("prometheus"), "Error message should mention supported formats");
+});
+%}
\ No newline at end of file
diff --git a/_regroup/test-etapi/metrics.http b/_regroup/test-etapi/metrics.http
new file mode 100644
index 000000000..24435f954
--- /dev/null
+++ b/_regroup/test-etapi/metrics.http
@@ -0,0 +1,82 @@
+### Test ETAPI metrics endpoint
+
+# First login to get a token
+POST {{triliumHost}}/etapi/auth/login
+Content-Type: application/json
+
+{
+ "password": "{{password}}"
+}
+
+> {%
+client.test("Login successful", function() {
+ client.assert(response.status === 201, "Response status is not 201");
+ client.assert(response.body.authToken, "Auth token not present");
+ client.global.set("authToken", response.body.authToken);
+});
+%}
+
+### Get metrics with authentication (default Prometheus format)
+GET {{triliumHost}}/etapi/metrics
+Authorization: {{authToken}}
+
+> {%
+client.test("Metrics endpoint returns Prometheus format by default", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ client.assert(response.headers["content-type"].includes("text/plain"), "Content-Type should be text/plain");
+ client.assert(response.body.includes("trilium_info"), "Should contain trilium_info metric");
+ client.assert(response.body.includes("trilium_notes_total"), "Should contain trilium_notes_total metric");
+ client.assert(response.body.includes("# HELP"), "Should contain HELP comments");
+ client.assert(response.body.includes("# TYPE"), "Should contain TYPE comments");
+});
+%}
+
+### Get metrics in JSON format
+GET {{triliumHost}}/etapi/metrics?format=json
+Authorization: {{authToken}}
+
+> {%
+client.test("Metrics endpoint returns JSON when requested", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ client.assert(response.headers["content-type"].includes("application/json"), "Content-Type should be application/json");
+ client.assert(response.body.version, "Version info not present");
+ client.assert(response.body.database, "Database info not present");
+ client.assert(response.body.timestamp, "Timestamp not present");
+ client.assert(typeof response.body.database.totalNotes === 'number', "Total notes should be a number");
+ client.assert(typeof response.body.database.activeNotes === 'number', "Active notes should be a number");
+});
+%}
+
+### Get metrics in Prometheus format explicitly
+GET {{triliumHost}}/etapi/metrics?format=prometheus
+Authorization: {{authToken}}
+
+> {%
+client.test("Metrics endpoint returns Prometheus format when requested", function() {
+ client.assert(response.status === 200, "Response status is not 200");
+ client.assert(response.headers["content-type"].includes("text/plain"), "Content-Type should be text/plain");
+ client.assert(response.body.includes("trilium_info"), "Should contain trilium_info metric");
+ client.assert(response.body.includes("trilium_notes_total"), "Should contain trilium_notes_total metric");
+});
+%}
+
+### Test invalid format parameter
+GET {{triliumHost}}/etapi/metrics?format=xml
+Authorization: {{authToken}}
+
+> {%
+client.test("Invalid format parameter returns error", function() {
+ client.assert(response.status === 400, "Response status should be 400");
+ client.assert(response.body.code === "INVALID_FORMAT", "Error code should be INVALID_FORMAT");
+ client.assert(response.body.message.includes("prometheus"), "Error message should mention supported formats");
+});
+%}
+
+### Test without authentication (should fail)
+GET {{triliumHost}}/etapi/metrics
+
+> {%
+client.test("Metrics endpoint requires authentication", function() {
+ client.assert(response.status === 401, "Response status should be 401");
+});
+%}
\ No newline at end of file
diff --git a/_regroup/trilium.iml b/_regroup/trilium.iml
deleted file mode 100644
index bfa02661b..000000000
--- a/_regroup/trilium.iml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/apps/client/package.json b/apps/client/package.json
index ca4953cf1..a1e4c9c6a 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -10,7 +10,7 @@
"url": "https://github.com/TriliumNext/Notes"
},
"dependencies": {
- "@eslint/js": "9.26.0",
+ "@eslint/js": "9.27.0",
"@excalidraw/excalidraw": "0.18.0",
"@fullcalendar/core": "6.1.17",
"@fullcalendar/daygrid": "6.1.17",
@@ -22,28 +22,33 @@
"@mind-elixir/node-menu": "1.0.5",
"@popperjs/core": "2.11.8",
"@triliumnext/ckeditor5": "workspace:*",
+ "@triliumnext/codemirror": "workspace:*",
"@triliumnext/commons": "workspace:*",
+ "@triliumnext/highlightjs": "workspace:*",
+ "autocomplete.js": "0.38.1",
"bootstrap": "5.3.6",
+ "boxicons": "2.1.4",
"dayjs": "1.11.13",
"dayjs-plugin-utc": "0.1.2",
"debounce": "2.2.0",
"draggabilly": "3.0.0",
- "eslint-linter-browserify": "9.26.0",
- "force-graph": "1.49.5",
- "globals": "16.1.0",
- "i18next": "25.1.2",
+ "force-graph": "1.49.6",
+ "globals": "16.2.0",
+ "i18next": "25.2.1",
"i18next-http-backend": "3.0.2",
"jquery": "3.7.1",
"jquery-hotkeys": "0.2.2",
"jquery.fancytree": "2.38.5",
"jsplumb": "2.15.6",
+ "katex": "0.16.22",
"knockout": "3.5.1",
"leaflet": "1.9.4",
"leaflet-gpx": "2.2.0",
"mark.js": "8.11.1",
- "marked": "15.0.11",
+ "marked": "15.0.12",
"mermaid": "11.6.0",
- "mind-elixir": "4.5.2",
+ "mind-elixir": "4.6.0",
+ "normalize.css": "8.0.1",
"panzoom": "9.4.3",
"react": "19.1.0",
"react-dom": "19.1.0",
@@ -55,13 +60,15 @@
"@ckeditor/ckeditor5-inspector": "4.1.0",
"@types/bootstrap": "5.2.10",
"@types/jquery": "3.5.32",
- "@types/leaflet": "1.9.17",
+ "@types/leaflet": "1.9.18",
"@types/leaflet-gpx": "1.3.7",
- "@types/react": "19.1.3",
- "@types/react-dom": "19.1.3",
+ "@types/mark.js": "8.11.12",
+ "@types/react": "19.1.6",
+ "@types/react-dom": "19.1.5",
"copy-webpack-plugin": "13.0.0",
- "happy-dom": "17.4.7",
- "script-loader": "0.7.2"
+ "happy-dom": "17.5.6",
+ "script-loader": "0.7.2",
+ "vite-plugin-static-copy": "3.0.0"
},
"nx": {
"name": "client"
diff --git a/apps/client/src/components/app_context.ts b/apps/client/src/components/app_context.ts
index 1855876d3..f7a5dfb1e 100644
--- a/apps/client/src/components/app_context.ts
+++ b/apps/client/src/components/app_context.ts
@@ -27,6 +27,7 @@ import type EditableTextTypeWidget from "../widgets/type_widgets/editable_text.j
import type { NativeImage, TouchBar } from "electron";
import TouchBarComponent from "./touch_bar.js";
import type { CKTextEditor } from "@triliumnext/ckeditor5";
+import type CodeMirror from "@triliumnext/codemirror";
interface Layout {
getRootWidget: (appContext: AppContext) => RootWidget;
@@ -191,7 +192,7 @@ export type CommandMappings = {
ExecuteCommandData & {
callback?: GetTextEditorCallback;
};
- executeWithCodeEditor: CommandData & ExecuteCommandData;
+ executeWithCodeEditor: CommandData & ExecuteCommandData;
/**
* Called upon when attempting to retrieve the content element of a {@link NoteContext}.
* Generally should not be invoked manually, as it is used by {@link NoteContext.getContentElement}.
@@ -283,6 +284,9 @@ export type CommandMappings = {
type EventMappings = {
initialRenderComplete: {};
frocaReloaded: {};
+ setLeftPaneVisibility: {
+ leftPaneVisible: boolean | null;
+ }
protectedSessionStarted: {};
notesReloaded: {
noteIds: string[];
diff --git a/apps/client/src/components/note_context.ts b/apps/client/src/components/note_context.ts
index 8cca352c7..9630756ae 100644
--- a/apps/client/src/components/note_context.ts
+++ b/apps/client/src/components/note_context.ts
@@ -11,6 +11,7 @@ import type { ViewScope } from "../services/link.js";
import type FNote from "../entities/fnote.js";
import type TypeWidget from "../widgets/type_widgets/type_widget.js";
import type { CKTextEditor } from "@triliumnext/ckeditor5";
+import type CodeMirror from "@triliumnext/codemirror";
export interface SetNoteOpts {
triggerSwitchEvent?: unknown;
@@ -158,6 +159,9 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
}
saveToRecentNotes(resolvedNotePath: string) {
+ if (options.is("databaseReadonly")) {
+ return;
+ }
setTimeout(async () => {
// we include the note in the recent list only if the user stayed on the note at least 5 seconds
if (resolvedNotePath && resolvedNotePath === this.notePath) {
@@ -253,6 +257,10 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
return false;
}
+ if (options.is("databaseReadonly")) {
+ return true;
+ }
+
if (this.note.isLabelTruthy("readOnly")) {
return true;
}
@@ -331,7 +339,7 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
async getCodeEditor() {
return this.timeout(
- new Promise((resolve) =>
+ new Promise((resolve) =>
appContext.triggerCommand("executeWithCodeEditor", {
resolve,
ntxId: this.ntxId
diff --git a/apps/client/src/components/root_command_executor.ts b/apps/client/src/components/root_command_executor.ts
index 1e16fae81..8e7df9494 100644
--- a/apps/client/src/components/root_command_executor.ts
+++ b/apps/client/src/components/root_command_executor.ts
@@ -78,15 +78,15 @@ export default class RootCommandExecutor extends Component {
}
hideLeftPaneCommand() {
- options.save(`leftPaneVisible`, "false");
+ appContext.triggerEvent("setLeftPaneVisibility", { leftPaneVisible: false });
}
showLeftPaneCommand() {
- options.save(`leftPaneVisible`, "true");
+ appContext.triggerEvent("setLeftPaneVisibility", { leftPaneVisible: true });
}
toggleLeftPaneCommand() {
- options.toggle("leftPaneVisible");
+ appContext.triggerEvent("setLeftPaneVisibility", { leftPaneVisible: null });
}
async showBackendLogCommand() {
diff --git a/apps/client/src/components/tab_manager.ts b/apps/client/src/components/tab_manager.ts
index cf2876a5a..fa83470ce 100644
--- a/apps/client/src/components/tab_manager.ts
+++ b/apps/client/src/components/tab_manager.ts
@@ -44,6 +44,9 @@ export default class TabManager extends Component {
if (!appContext.isMainWindow) {
return;
}
+ if (options.is("databaseReadonly")) {
+ return;
+ }
const openNoteContexts = this.noteContexts
.map((nc) => nc.getPojoState())
diff --git a/apps/client/src/components/touch_bar.ts b/apps/client/src/components/touch_bar.ts
index 4afe65151..7bf10d7f1 100644
--- a/apps/client/src/components/touch_bar.ts
+++ b/apps/client/src/components/touch_bar.ts
@@ -54,7 +54,7 @@ export default class TouchBarComponent extends Component {
#refreshTouchBar() {
const { TouchBar } = this.remote;
const parentComponent = this.lastFocusedComponent;
- let touchBar = null;
+ let touchBar: Electron.CrossProcessExports.TouchBar | null = null;
if (this.$activeModal?.length) {
touchBar = this.#buildModalTouchBar();
diff --git a/apps/client/src/desktop.ts b/apps/client/src/desktop.ts
index 51c69aa70..1a0f7e8a9 100644
--- a/apps/client/src/desktop.ts
+++ b/apps/client/src/desktop.ts
@@ -11,6 +11,9 @@ import options from "./services/options.js";
import type ElectronRemote from "@electron/remote";
import type Electron from "electron";
import "./stylesheets/bootstrap.scss";
+import "boxicons/css/boxicons.min.css";
+import "jquery-hotkeys";
+import "autocomplete.js/index_jquery.js";
await appContext.earlyInit();
diff --git a/apps/client/src/entities/fnote.ts b/apps/client/src/entities/fnote.ts
index e968dcae9..9e215821d 100644
--- a/apps/client/src/entities/fnote.ts
+++ b/apps/client/src/entities/fnote.ts
@@ -789,7 +789,7 @@ class FNote {
*/
async getRelationTargets(name: string) {
const relations = this.getRelations(name);
- const targets = [];
+ const targets: (FNote | null)[] = [];
for (const relation of relations) {
targets.push(await this.froca.getNote(relation.value));
diff --git a/apps/client/src/libraries/codemirror/eslint.js b/apps/client/src/libraries/codemirror/eslint.js
deleted file mode 100644
index 403cb4e54..000000000
--- a/apps/client/src/libraries/codemirror/eslint.js
+++ /dev/null
@@ -1,74 +0,0 @@
-// CodeMirror, copyright (c) by Marijn Haverbeke and others
-// Distributed under an MIT license: http://codemirror.net/LICENSE
-
-(function(mod) {
- if (typeof exports == "object" && typeof module == "object") // CommonJS
- mod(require("../../lib/codemirror"));
- else if (typeof define == "function" && define.amd) // AMD
- define(["../../lib/codemirror"], mod);
- else // Plain browser env
- mod(CodeMirror);
-})(function(CodeMirror) {
- "use strict";
-
- async function validatorHtml(text, options) {
- const result = /
-
-
-
-
-
-
-
-
-
-
-
+
@@ -64,14 +52,8 @@
-
-
-
-