Compare commits

...

121 Commits

Author SHA1 Message Date
Jakob Schlanstedt
8ee59e9daa refactor(suggestion): improve naming 2025-11-28 22:53:24 +01:00
Jakob Schlanstedt
4e5c26371e fix(note_create): use correct API for intoDefaultLocation 2025-11-28 22:53:24 +01:00
Jakob Schlanstedt
436146d829 fix(note_create): warn message 2025-11-28 22:53:24 +01:00
Jakob Schlanstedt
315fcecf57 fix(include_note): fix wrongly merged code 2025-11-28 22:53:24 +01:00
Jakob Schlanstedt
0a57e6e154 fix(NoteAutocomplete): use new API 2025-11-28 22:53:24 +01:00
Jakob Schlanstedt
bdcb84a394 fix(EditableTest): cutIntoNoteCommand createNote to new API 2025-11-28 22:53:23 +01:00
Jakob Schlanstedt
213c36ba84 fix(EditableTest): Fix EdtableText to use new API 2025-11-28 22:53:22 +01:00
Jakob Schlanstedt
995e765276 fix(translation): missing ',' 2025-11-28 22:52:03 +01:00
Jakob Schlanstedt
8e81c38c14 fix(translation): restore missing translations 2025-11-28 22:52:03 +01:00
Jakob Schlanstedt
7378fa4cbd fix(createNoteFromAction): don't overwrite promptForType but use the variable instead 2025-11-28 22:52:02 +01:00
Jakob Schlanstedt
af8a5ff0c9 refactor(note_create) use correct terminology link not url 2025-11-28 22:52:02 +01:00
Jakob Schlanstedt
eca5a4a072 refactor(url -> link): let link refer to url and path.
before there was polysemy in word url that is now resolved by making
link hypernym to url and path.
2025-11-28 22:52:02 +01:00
Jakob Schlanstedt
71b3ad5027 refactor(note_create): Inbox -> Default naming in functions, parameters and types 2025-11-28 22:52:02 +01:00
Jakob Schlanstedt
7864168adc fix(AttributeEditor): wrong order of Arguments 2025-11-28 22:52:01 +01:00
Jakob Schlanstedt
f8090d9217 feat(search): add create into inbox to search 2025-11-28 22:52:01 +01:00
Jakob Schlanstedt
09aa22c74b refactor(autocomplete-pipline): refactor autocomplete -> create -> select pipeline 2025-11-28 22:52:01 +01:00
Jakob Schlanstedt
8fc8f97879 refactor(create-note-naming): simplify naming 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
547cdff510 style(jump_to_note): remove dead case to improve readability 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
cdd08d6971 style(row_editing comments): make inline comment proper doc 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
b3cf9c8f2d style(unused-imports): Remove unused-imports 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
feefa389b4 test(server-e2e): fix test for new create note option 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
f65be4f368 fix(note_autocomplete): fix wrong definition of types, and resulting bugs esp. improving row editing 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
77a014109e fix(note_autocomplete): fix attributes not linking 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
d3db48c99b refactor(note-create): remove as typecast 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
7e4833e893 fix(note-autocomplete): logic error hidden by as typecast 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
470d7eee31 fix(type-checker): remove as casts hiding type-errors thus bugs. Solve subsequent found bugs 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
aada631c0f fix(note_autocomplete): fix wrong type of target 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
bc4186d216 fix(note_create): type casting 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
c2a27eff2c refactor(note_autocomplete): simplify big switch statement removing duplicate logic 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
ca24408a13 fix(root-command-executor): fix regression in root_command_executor 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
b9e19e524a fix(typecheck-proven incorrectness): typecheck caught incorrectness through pnpm typecheck 2025-11-28 22:52:00 +01:00
contributor
09c8a778f5 createNote: better typing without cast and never type 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
3438f1103d refactor(note-create): remove small redundancy 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
82a3be06d1 fix(note-create): fix type definition for CreateNoteWithUrlOpts 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
f0dead5390 refactor(note-create): remove unnecessary deep hierarchy 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
b0fdb9fef2 refactor(note-create): replace 'at' with 'with' 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
71009bddc7 refactor(note-create): simplify createNote switch to equivalent small ifs 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
66e499a2e1 refactor(note-create): replace enum with optional fields 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
a5ef5eee2f refactor(note_create): simplify type implementation and documentation 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
bcb29d22f5 docs(note_create): further clarify type system 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
6ad2b49ab3 docs: remove comments duplicating code 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
656e7c069d refactor(create_note): rename types to fit ontological concepts better 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
00aa470bf2 fix(Omit in types): remove Omit from types to make hierarchy logical consistent and resulting errors from corrected logic. 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
c6ed0b43fc docs(note_create): improve clarification of type system 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
3d8a4d2553 docs(note_create): improve documentation for type checking system 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
42ab0eb804 fix(note_create): fix type hierarchy inheriting from wrong type and improve its documentation 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
d80d06a9b8 refactor(note_create): cleanup by removing unused import 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
3c39026739 refactor(note_create): reorder function order to simplify diff 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
72c17b22df refactor(note_create): improve comments for type system 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
dd1aa23cb6 refactor(note_create): clarify type system 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
ecdf243e63 refactor: cleanup comments 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
1e15585a24 refactor(typeerror): resolve typeerrors by refactoring code 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
9d40c0cb26 fix(note-type-chooser): fix note type chooser, unnecessary stick to old chosen path 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
e41e24b044 refactor(create-note): centralize and add advanced type checking to create-note with and without prompt 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
a15d661fd7 fix(jump_to_note): fix enum typescript error in switch statement 2025-11-28 22:52:00 +01:00
contributor
cb5954e8c7 fix typings for creating a note using mentions in ckeditor 2025-11-28 22:52:00 +01:00
contributor
2b55db05e1 rename MentionAction to CreateNoteAction and move to packages/common 2025-11-28 22:52:00 +01:00
Jakob Schlanstedt
74bf93059c refactor(ECMAScript Modules jsimport convention): refactor newly created imports to js convention
https://nodejs.org/api/esm.html#import-specifiers
2025-11-28 22:51:59 +01:00
Jakob Schlanstedt
384d8c9c37 refactor(note-create): change order of noteCreate intoPath and intoInbox to improve code compatibility 2025-11-28 22:51:59 +01:00
Jakob Schlanstedt
1bb6149dbe feat(search): add create into inbox to search 2025-11-28 22:51:59 +01:00
Elian Doran
3cc64b5764
fix(mobile/context_menu): note color picker not working
Some checks are pending
Checks / main (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Dev / Test development (push) Waiting to run
Dev / Build Docker image (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile) (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile.alpine) (push) Blocked by required conditions
/ Check Docker build (Dockerfile) (push) Waiting to run
/ Check Docker build (Dockerfile.alpine) (push) Waiting to run
/ Build Docker images (Dockerfile, ubuntu-24.04-arm, linux/arm64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.alpine, ubuntu-latest, linux/amd64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v7) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v8) (push) Blocked by required conditions
/ Merge manifest lists (push) Blocked by required conditions
playwright / E2E tests on linux-arm64 (push) Waiting to run
playwright / E2E tests on linux-x64 (push) Waiting to run
2025-11-28 23:43:16 +02:00
Elian Doran
19cf07564f
style(mobile/context_menu): taller height + small animation when expanding items 2025-11-28 23:21:31 +02:00
Elian Doran
5847ce5c14
feat(dev): enable CSS source maps 2025-11-28 23:21:14 +02:00
Elian Doran
a7ad45635e
style(mobile/context_menu): clean up border radiuses 2025-11-28 21:27:06 +02:00
Elian Doran
781215394e
refactor(mobile/context_menu): unify styles 2025-11-28 21:24:51 +02:00
Elian Doran
0aafdca999
style(mobile/context_menu): improve backdrop 2025-11-28 21:21:07 +02:00
Elian Doran
18d3cb6f0c
style(mobile/context_menu): dark submenu style 2025-11-28 21:14:06 +02:00
Elian Doran
263a96e8b7
style(mobile/context_menu): improve submenu style 2025-11-28 20:57:42 +02:00
Elian Doran
27d5009486
style(mobile/context_menu): disable hover color 2025-11-28 20:44:29 +02:00
Elian Doran
2e431b1135
chore(deps): update dependency electron to v38.7.2 (#7873)
Some checks are pending
Checks / main (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Documentation / Build and Deploy Documentation (push) Waiting to run
Dev / Test development (push) Waiting to run
Dev / Build Docker image (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile) (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile.alpine) (push) Blocked by required conditions
/ Check Docker build (Dockerfile) (push) Waiting to run
/ Check Docker build (Dockerfile.alpine) (push) Waiting to run
/ Build Docker images (Dockerfile, ubuntu-24.04-arm, linux/arm64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.alpine, ubuntu-latest, linux/amd64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v7) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v8) (push) Blocked by required conditions
/ Merge manifest lists (push) Blocked by required conditions
playwright / E2E tests on linux-arm64 (push) Waiting to run
playwright / E2E tests on linux-x64 (push) Waiting to run
2025-11-28 11:26:12 +02:00
Elian Doran
e2ec27250c
chore(deps): update dependency happy-dom to v20.0.11 (#7874) 2025-11-28 08:24:15 +02:00
Elian Doran
1228eda5ea
chore(deps): update pnpm to v10.24.0 (#7875) 2025-11-28 08:23:01 +02:00
renovate[bot]
435794df73
chore(deps): update pnpm to v10.24.0 2025-11-28 01:16:30 +00:00
renovate[bot]
7e3d0639f7
chore(deps): update dependency happy-dom to v20.0.11 2025-11-28 01:16:18 +00:00
renovate[bot]
86b0005821
chore(deps): update dependency electron to v38.7.2 2025-11-28 01:15:07 +00:00
Elian Doran
2fb78275f7
Translations update from Hosted Weblate (#7871)
Some checks failed
Checks / main (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Dev / Test development (push) Waiting to run
Dev / Build Docker image (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile) (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile.alpine) (push) Blocked by required conditions
/ Check Docker build (Dockerfile) (push) Waiting to run
/ Check Docker build (Dockerfile.alpine) (push) Waiting to run
/ Build Docker images (Dockerfile, ubuntu-24.04-arm, linux/arm64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.alpine, ubuntu-latest, linux/amd64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v7) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v8) (push) Blocked by required conditions
/ Merge manifest lists (push) Blocked by required conditions
playwright / E2E tests on linux-arm64 (push) Waiting to run
playwright / E2E tests on linux-x64 (push) Waiting to run
Deploy website / Build & deploy website (push) Has been cancelled
2025-11-27 21:52:13 +02:00
Elian Doran
98f421c697
Apply suggestions from code review
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-11-27 21:49:17 +02:00
Francis C.
a5572b7d45
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1635 of 1635 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-11-27 20:42:07 +01:00
Manfred Manni
fdecbaaa6a
Translated using Weblate (German)
Currently translated at 100.0% (389 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/de/
2025-11-27 20:42:06 +01:00
green
c6afd7fa24
Translated using Weblate (Japanese)
Currently translated at 100.0% (1635 of 1635 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-11-27 20:42:06 +01:00
Tomas Adamek
5cad522a60
Translated using Weblate (Czech)
Currently translated at 5.3% (88 of 1635 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/cs/
2025-11-27 20:42:05 +01:00
Tomas Adamek
82f64677cb
Translated using Weblate (Czech)
Currently translated at 27.2% (106 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/cs/
2025-11-27 20:42:04 +01:00
Manfred Manni
3ee086a063
Translated using Weblate (German)
Currently translated at 99.7% (1631 of 1635 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/de/
2025-11-27 20:42:03 +01:00
Francis C.
13da444a69
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (1635 of 1635 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hant/
2025-11-27 20:42:02 +01:00
Tomas Adamek
b51ceaaadc
Translated using Weblate (Czech)
Currently translated at 65.1% (99 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/cs/
2025-11-27 20:42:01 +01:00
Elian Doran
2024c72209
i18n(client): two missing translations for dialogs 2025-11-27 21:41:24 +02:00
Elian Doran
b5959c55e1
chore(client): remove redundant log 2025-11-27 21:12:47 +02:00
Elian Doran
16f0ac97f4
fix(ckeditor): revert workaround which breaks shift-selection 2025-11-27 20:39:59 +02:00
Elian Doran
073c02ee0c
fix(ckeditor): Cmd+Up/Down not working properly 2025-11-27 20:00:15 +02:00
Elian Doran
786f0db4bb
fix(ckeditor): move block interfering with normal shortcut (closes #6964) 2025-11-27 19:37:21 +02:00
Elian Doran
6958e4b74f
feat(desktop): collapse spacing in full screen 2025-11-27 18:24:00 +02:00
Elian Doran
22c4fba665
docs(user): improve documentation on tree keyboard shortcuts
Some checks are pending
Checks / main (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Documentation / Build and Deploy Documentation (push) Waiting to run
Dev / Test development (push) Waiting to run
Dev / Build Docker image (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile) (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile.alpine) (push) Blocked by required conditions
/ Check Docker build (Dockerfile) (push) Waiting to run
/ Check Docker build (Dockerfile.alpine) (push) Waiting to run
/ Build Docker images (Dockerfile, ubuntu-24.04-arm, linux/arm64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.alpine, ubuntu-latest, linux/amd64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v7) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v8) (push) Blocked by required conditions
/ Merge manifest lists (push) Blocked by required conditions
playwright / E2E tests on linux-arm64 (push) Waiting to run
playwright / E2E tests on linux-x64 (push) Waiting to run
2025-11-27 14:22:45 +02:00
Elian Doran
f7c0e56cec
Translations update from Hosted Weblate (#7867)
Some checks are pending
Checks / main (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Documentation / Build and Deploy Documentation (push) Waiting to run
Dev / Test development (push) Waiting to run
Dev / Build Docker image (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile) (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile.alpine) (push) Blocked by required conditions
/ Check Docker build (Dockerfile) (push) Waiting to run
/ Check Docker build (Dockerfile.alpine) (push) Waiting to run
/ Build Docker images (Dockerfile, ubuntu-24.04-arm, linux/arm64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.alpine, ubuntu-latest, linux/amd64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v7) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v8) (push) Blocked by required conditions
/ Merge manifest lists (push) Blocked by required conditions
playwright / E2E tests on linux-arm64 (push) Waiting to run
playwright / E2E tests on linux-x64 (push) Waiting to run
Deploy website / Build & deploy website (push) Waiting to run
2025-11-27 07:35:08 +02:00
Elian Doran
5f423cd22e
Apply suggestions from code review
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-11-27 07:34:46 +02:00
Hosted Weblate
282b3a109c
Update translation files
Updated by "Remove blank strings" add-on in Weblate.

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/
2025-11-27 05:14:32 +00:00
Tomas Adamek
dddb051d8b
Translated using Weblate (Czech)
Currently translated at 26.3% (40 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/cs/
2025-11-27 05:14:31 +00:00
Vedat Botuk
63d3706003
Translated using Weblate (Turkish)
Currently translated at 7.2% (11 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/tr/
2025-11-27 05:14:30 +00:00
Tomas Adamek
22ca2494f5
Translated using Weblate (Czech)
Currently translated at 18.5% (72 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/cs/
2025-11-27 05:14:29 +00:00
Aitanuqui
a0f02b6877
Translated using Weblate (Spanish)
Currently translated at 100.0% (1635 of 1635 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/es/
2025-11-27 05:14:28 +00:00
Vedat Botuk
487fcff61f
Translated using Weblate (Turkish)
Currently translated at 9.3% (11 of 118 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/tr/
2025-11-27 05:14:27 +00:00
Elian Doran
bfb8897188
Translated using Weblate (Romanian)
Currently translated at 100.0% (1635 of 1635 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ro/
2025-11-27 05:14:26 +00:00
Francis C.
ce1ccf378a
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (1635 of 1635 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hant/
2025-11-27 05:14:25 +00:00
Francis C.
96d5ee3d46
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1635 of 1635 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-11-27 05:14:23 +00:00
Tomas Adamek
6f3771e7cd
Translated using Weblate (Czech)
Currently translated at 25.6% (39 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/cs/
2025-11-27 05:14:22 +00:00
Tomas Adamek
e6b00b05a2
Translated using Weblate (Czech)
Currently translated at 3.3% (54 of 1635 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/cs/
2025-11-27 05:14:21 +00:00
Tomas Adamek
148d0afe81
Translated using Weblate (Czech)
Currently translated at 11.0% (43 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/cs/
2025-11-27 05:14:20 +00:00
Aitanuqui
c5d63dbdb9
Translated using Weblate (Spanish)
Currently translated at 99.7% (1631 of 1635 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/es/
2025-11-27 05:14:18 +00:00
Tomas Adamek
1af072b059
Translated using Weblate (Czech)
Currently translated at 36.4% (43 of 118 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/cs/
2025-11-27 05:14:17 +00:00
Hosted Weblate
a6a8fdd2f8
Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/
2025-11-27 05:14:16 +00:00
Andreas Haan
8836021ff9
Translated using Weblate (German)
Currently translated at 99.9% (1631 of 1632 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/de/
2025-11-27 05:14:14 +00:00
Andreas Haan
915803c5be
Translated using Weblate (German)
Currently translated at 99.7% (388 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/de/
2025-11-27 05:14:13 +00:00
green
cd95d43457
Translated using Weblate (Japanese)
Currently translated at 100.0% (1632 of 1632 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-11-27 05:14:11 +00:00
Andreas Haan
35af5fd13c
Translated using Weblate (German)
Currently translated at 39.4% (60 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/de/
2025-11-27 05:14:10 +00:00
Elian Doran
35e602f75f
style(mobile/context_menu): increase size and padding 2025-11-27 07:13:23 +02:00
Elian Doran
b4f0a1acc0
style(mobile/context_menu): card-style design on next theme 2025-11-26 21:54:35 +02:00
Elian Doran
7b7e9f6868
fix(context_menu): no bottom padding on mobile 2025-11-26 21:26:52 +02:00
Elian Doran
de3892950c
fix(context_menu): 1px overflow in height on mobile 2025-11-26 21:24:03 +02:00
Elian Doran
5c53826da3
fix(context_menu): color picker not dismissing on mobile 2025-11-26 21:20:27 +02:00
Elian Doran
d358073081
fix(global_menu): toggling advanced hides the menu most of the time 2025-11-26 20:44:53 +02:00
Elian Doran
d2d7fd7c4c
fix(context_menu): toggling submenu hides the menu most of the time 2025-11-26 20:35:02 +02:00
Elian Doran
706da768e2
chore(collections/board): hide "Add new column" while loading 2025-11-26 19:47:15 +02:00
79 changed files with 1755 additions and 793 deletions

View File

@ -9,7 +9,7 @@
"keywords": [],
"author": "Elian Doran <contact@eliandoran.me>",
"license": "AGPL-3.0-only",
"packageManager": "pnpm@10.23.0",
"packageManager": "pnpm@10.24.0",
"devDependencies": {
"@redocly/cli": "2.12.0",
"archiver": "7.0.1",

View File

@ -77,7 +77,7 @@
"@types/reveal.js": "5.2.1",
"@types/tabulator-tables": "6.3.0",
"copy-webpack-plugin": "13.0.1",
"happy-dom": "20.0.10",
"happy-dom": "20.0.11",
"script-loader": "0.7.2",
"vite-plugin-static-copy": "3.1.4"
}

View File

@ -25,7 +25,7 @@ import TouchBarComponent from "./touch_bar.js";
import type { CKTextEditor } from "@triliumnext/ckeditor5";
import type CodeMirror from "@triliumnext/codemirror";
import { StartupChecks } from "./startup_checks.js";
import type { CreateNoteOpts } from "../services/note_create.js";
import type { CreateNoteOpts, CreateNoteWithLinkOpts } from "../services/note_create.js";
import { ColumnComponent } from "tabulator-tables";
import { ChooseNoteTypeCallback } from "../widgets/dialogs/note_type_chooser.jsx";
import type RootContainer from "../widgets/containers/root_container.js";
@ -359,8 +359,7 @@ export type CommandMappings = {
// Table view
addNewRow: CommandData & {
customOpts: CreateNoteOpts;
parentNotePath?: string;
customOpts?: CreateNoteWithLinkOpts;
};
addNewTableColumn: CommandData & {
columnToEdit?: ColumnComponent;

View File

@ -11,6 +11,7 @@ import froca from "../services/froca.js";
import linkService from "../services/link.js";
import { t } from "../services/i18n.js";
import { CreateChildrenResponse, SqlExecuteResponse } from "@triliumnext/commons";
import noteCreateService from "../services/note_create.js";
export default class Entrypoints extends Component {
constructor() {
@ -24,23 +25,9 @@ export default class Entrypoints extends Component {
}
async createNoteIntoInboxCommand() {
const inboxNote = await dateNoteService.getInboxNote();
if (!inboxNote) {
console.warn("Missing inbox note.");
return;
}
const { note } = await server.post<CreateChildrenResponse>(`notes/${inboxNote.noteId}/children?target=into`, {
content: "",
type: "text",
isProtected: inboxNote.isProtected && protectedSessionHolder.isProtectedSessionAvailable()
});
await ws.waitForMaxKnownEntityChangeId();
await appContext.tabManager.openTabWithNoteWithHoisting(note.noteId, { activate: true });
appContext.triggerEvent("focusAndSelectTitle", { isNewNote: true });
await noteCreateService.createNote(
{ target: "default" }
);
}
async toggleNoteHoistingCommand({ noteId = appContext.tabManager.getActiveContextNoteId() }) {

View File

@ -48,10 +48,15 @@ export default class MainTreeExecutors extends Component {
return;
}
await noteCreateService.createNote(activeNoteContext.notePath, {
isProtected: activeNoteContext.note.isProtected,
saveSelection: false
});
await noteCreateService.createNote(
{
target: "into",
parentNoteLink: activeNoteContext.notePath,
isProtected: activeNoteContext.note.isProtected,
saveSelection: false,
promptForType: false,
}
);
}
async createNoteAfterCommand() {
@ -72,11 +77,14 @@ export default class MainTreeExecutors extends Component {
return;
}
await noteCreateService.createNote(parentNotePath, {
target: "after",
targetBranchId: node.data.branchId,
isProtected: isProtected,
saveSelection: false
});
await noteCreateService.createNote(
{
target: "after",
parentNoteLink: parentNotePath,
targetBranchId: node.data.branchId,
isProtected: isProtected,
saveSelection: false
}
);
}
}

View File

@ -45,7 +45,7 @@ export default class RootCommandExecutor extends Component {
}
async searchInSubtreeCommand({ notePath }: CommandListenerData<"searchInSubtree">) {
const noteId = treeService.getNoteIdFromUrl(notePath);
const noteId = treeService.getNoteIdFromLink(notePath);
this.searchNotesCommand({ ancestorNoteId: noteId });
}
@ -240,14 +240,18 @@ export default class RootCommandExecutor extends Component {
// Create a new AI Chat note at the root level
const rootNoteId = "root";
const result = await noteCreateService.createNote(rootNoteId, {
title: "New AI Chat",
type: "aiChat",
content: JSON.stringify({
messages: [],
title: "New AI Chat"
})
});
const result = await noteCreateService.createNote(
{
parentNoteLink: rootNoteId,
target: "into",
title: "New AI Chat",
type: "aiChat",
content: JSON.stringify({
messages: [],
title: "New AI Chat"
}),
}
);
if (!result.note) {
toastService.showError("Failed to create AI Chat note");

View File

@ -74,10 +74,10 @@ export default class TabManager extends Component {
// preload all notes at once
await froca.getNotes([...noteContextsToOpen.flatMap((tab: NoteContextState) =>
[treeService.getNoteIdFromUrl(tab.notePath), tab.hoistedNoteId])], true);
[treeService.getNoteIdFromLink(tab.notePath), tab.hoistedNoteId])], true);
const filteredNoteContexts = noteContextsToOpen.filter((openTab: NoteContextState) => {
const noteId = treeService.getNoteIdFromUrl(openTab.notePath);
const noteId = treeService.getNoteIdFromLink(openTab.notePath);
if (!noteId || !(noteId in froca.notes)) {
// note doesn't exist so don't try to open tab for it
return false;

View File

@ -58,6 +58,7 @@ function initOnElectron() {
initDarkOrLightMode(style);
initTransparencyEffects(style, currentWindow);
initFullScreenDetection(currentWindow);
if (options.get("nativeTitleBarVisible") !== "true") {
initTitleBarButtons(style, currentWindow);
@ -87,6 +88,11 @@ function initTitleBarButtons(style: CSSStyleDeclaration, currentWindow: Electron
}
}
function initFullScreenDetection(currentWindow: Electron.BrowserWindow) {
currentWindow.on("enter-full-screen", () => document.body.classList.add("full-screen"));
currentWindow.on("leave-full-screen", () => document.body.classList.remove("full-screen"));
}
function initTransparencyEffects(style: CSSStyleDeclaration, currentWindow: Electron.BrowserWindow) {
if (window.glob.platform === "win32") {
const material = style.getPropertyValue("--background-material");

View File

@ -238,6 +238,7 @@ class ContextMenu {
private createCustomMenuItem(item: CustomMenuItem) {
const element = document.createElement("li");
element.classList.add("dropdown-custom-item");
element.onclick = () => this.hide();
render(h(item.componentFn, {}), element);
return element;
}
@ -298,8 +299,6 @@ class ContextMenu {
// important to use mousedown instead of click since the former does not change focus
// (especially important for focused text for spell check)
.on("mousedown", (e) => {
e.stopPropagation();
if (e.which !== 1) {
// only left click triggers menu items
return false;
@ -313,6 +312,11 @@ class ContextMenu {
return false;
}
// Prevent submenu from failing to expand on mobile
if (!("items" in item && item.items)) {
this.hide();
}
if ("handler" in item && item.handler) {
item.handler(item, e);
}
@ -324,16 +328,6 @@ class ContextMenu {
return false;
});
$item.on("mouseup", (e) => {
// Prevent submenu from failing to expand on mobile
if (!this.isMobile || !("items" in item && item.items)) {
e.stopPropagation();
// Hide the content menu on mouse up to prevent the mouse event from propagating to the elements below.
this.hide();
return false;
}
});
if ("enabled" in item && item.enabled !== undefined && !item.enabled) {
$item.addClass("disabled");
}

View File

@ -76,7 +76,7 @@
position: relative;
display: flex;
justify-content: center;
overflow: hidden;
}
.note-color-picker .custom-color-cell.custom-color-cell-empty {

View File

@ -8,6 +8,7 @@ import Color, { ColorInstance } from "color";
import Debouncer from "../../utils/debouncer";
import FNote from "../../entities/fnote";
import froca from "../../services/froca";
import { isMobile } from "../../services/utils";
const COLOR_PALETTE = [
"#e64d4d", "#e6994d", "#e5e64d", "#99e64d", "#4de64d", "#4de699",
@ -62,13 +63,13 @@ export default function NoteColorPicker(props: NoteColorPickerProps) {
} else {
attributes.removeOwnedLabelByName(note, "color");
}
setCurrentColor(color);
}
}, [note, currentColor]);
return <div className="note-color-picker">
<ColorCell className="color-cell-reset"
tooltip={t("note-color.clear-color")}
color={null}
@ -81,8 +82,8 @@ export default function NoteColorPicker(props: NoteColorPickerProps) {
<path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" />
</svg>
</ColorCell>
{COLOR_PALETTE.map((color) => (
<ColorCell key={color}
tooltip={t("note-color.set-color")}
@ -128,7 +129,6 @@ function CustomColorCell(props: ColorCellProps) {
const colorInput = useRef<HTMLInputElement>(null);
const colorInputDebouncer = useRef<Debouncer<string | null> | null>(null);
const callbackRef = useRef(props.onSelect);
const isSafari = useRef(/^((?!chrome|android).)*safari/i.test(navigator.userAgent));
useEffect(() => {
colorInputDebouncer.current = new Debouncer(250, (color) => {
@ -160,13 +160,13 @@ function CustomColorCell(props: ColorCellProps) {
}, [pickedColor]);
return <div style={`--foreground: ${getForegroundColor(props.color)};`}
onClick={(e) => {
// The color picker dropdown will close on Safari if the parent context menu is
onClick={isMobile() ? (e) => {
// The color picker dropdown will close on some browser if the parent context menu is
// dismissed, so stop the click propagation to prevent dismissing the menu.
isSafari.current && e.stopPropagation();
}}>
e.stopPropagation();
} : undefined}>
<ColorCell {...props}
color={pickedColor}
color={pickedColor}
className={clsx("custom-color-cell", {
"custom-color-cell-empty": (pickedColor === null)
})}
@ -201,4 +201,4 @@ function tryParseColor(colorStr: string): ColorInstance | null {
}
return null;
}
}

View File

@ -283,21 +283,31 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
const parentNotePath = treeService.getNotePath(this.node.getParent());
const isProtected = treeService.getParentProtectedStatus(this.node);
noteCreateService.createNote(parentNotePath, {
target: "after",
targetBranchId: this.node.data.branchId,
type: type,
isProtected: isProtected,
templateNoteId: templateNoteId
});
noteCreateService.createNote(
{
target: "after",
parentNoteLink: parentNotePath,
targetBranchId: this.node.data.branchId,
type: type,
isProtected: isProtected,
templateNoteId: templateNoteId,
promptForType: false,
}
);
} else if (command === "insertChildNote") {
const parentNotePath = treeService.getNotePath(this.node);
noteCreateService.createNote(parentNotePath, {
type: type,
isProtected: this.node.data.isProtected,
templateNoteId: templateNoteId
});
noteCreateService.createNote(
{
target: "into",
parentNoteLink: parentNotePath,
type: type,
isProtected: this.node.data.isProtected,
templateNoteId: templateNoteId,
promptForType: false,
}
);
} else if (command === "openNoteInSplit") {
const subContexts = appContext.tabManager.getActiveContext()?.getSubContexts();
const { ntxId } = subContexts?.[subContexts.length - 1] ?? {};

View File

@ -50,7 +50,7 @@ async function checkNoteAccess(notePath: string, noteContext: NoteContext) {
const hoistedNoteId = noteContext.hoistedNoteId;
if (!resolvedNotePath.includes(hoistedNoteId) && (!resolvedNotePath.includes("_hidden") || resolvedNotePath.includes("_lbBookmarks"))) {
const noteId = treeService.getNoteIdFromUrl(resolvedNotePath);
const noteId = treeService.getNoteIdFromLink(resolvedNotePath);
if (!noteId) {
return false;
}

View File

@ -261,7 +261,7 @@ export function parseNavigationStateFromUrl(url: string | undefined) {
return {
notePath,
noteId: treeService.getNoteIdFromUrl(notePath),
noteId: treeService.getNoteIdFromLink(notePath),
ntxId,
hoistedNoteId,
viewScope,

View File

@ -5,6 +5,24 @@ import froca from "./froca.js";
import { t } from "./i18n.js";
import commandRegistry from "./command_registry.js";
import type { MentionFeedObjectItem } from "@triliumnext/ckeditor5";
import { CreateNoteAction } from "@triliumnext/commons"
import FNote from "../entities/fnote.js";
/**
* Extends CKEditor's MentionFeedObjectItem with extra fields used by Trilium.
* These additional props (like action, notePath, name, etc.) carry note
* metadata and legacy compatibility info needed for custom autocomplete
* and link insertion behavior beyond CKEditors base mention support.
*/
type ExtendedMentionFeedObjectItem = MentionFeedObjectItem & {
action?: string;
noteTitle?: string;
name?: string;
link?: string;
notePath?: string;
parentNoteId?: string;
highlightedNotePathTitle?: string;
};
// this key needs to have this value, so it's hit by the tooltip
const SELECTED_NOTE_PATH_KEY = "data-note-path";
@ -23,14 +41,39 @@ function getSearchDelay(notesCount: number): number {
}
let searchDelay = getSearchDelay(notesCount);
// TODO: Deduplicate with server.
// String values ensure stable, human-readable identifiers across serialization (JSON, CKEditor, logs).
export enum SuggestionAction {
// These values intentionally mirror CreateNoteAction string values 1:1.
// This overlap ensures that when a suggestion triggers a note creation callback,
// the receiving features (e.g. note creation handlers, CKEditor mentions) can interpret
// the action type consistently
CreateNote = CreateNoteAction.CreateNote,
CreateChildNote = CreateNoteAction.CreateChildNote,
CreateAndLinkNote = CreateNoteAction.CreateAndLinkNote,
CreateAndLinkChildNote = CreateNoteAction.CreateAndLinkChildNote,
SearchNotes = "search-notes",
ExternalLink = "external-link",
Command = "command",
}
export enum SuggestionMode {
SuggestNothing = "nothing",
SuggestCreateOnly = "create-only",
SuggestCreateAndLink = "create-and-link"
}
// NOTE: Previously marked for deduplication with a server-side type,
// but review on 2025-10-12 (using `rg Suggestion`) found no corresponding
// server implementation.
// This interface appears to be client-only.
export interface Suggestion {
noteTitle?: string;
externalLink?: string;
notePathTitle?: string;
notePath?: string;
highlightedNotePathTitle?: string;
action?: string | "create-note" | "search-notes" | "external-link" | "command";
action?: SuggestionAction;
parentNoteId?: string;
icon?: string;
commandId?: string;
@ -43,7 +86,7 @@ export interface Suggestion {
export interface Options {
container?: HTMLElement | null;
fastSearch?: boolean;
allowCreatingNotes?: boolean;
suggestionMode?: SuggestionMode;
allowJumpToSearchNotes?: boolean;
allowExternalLinks?: boolean;
/** If set, hides the right-side button corresponding to go to selected note. */
@ -54,110 +97,160 @@ export interface Options {
isCommandPalette?: boolean;
}
async function autocompleteSourceForCKEditor(queryText: string) {
return await new Promise<MentionFeedObjectItem[]>((res, rej) => {
async function autocompleteSourceForCKEditor(
queryText: string,
suggestionMode: SuggestionMode
): Promise<MentionFeedObjectItem[]> {
// Wrap the callback-based autocompleteSource in a Promise for async/await
const rows = await new Promise<Suggestion[]>((resolve) => {
autocompleteSource(
queryText,
(rows) => {
res(
rows.map((row) => {
return {
action: row.action,
noteTitle: row.noteTitle,
id: `@${row.notePathTitle}`,
name: row.notePathTitle || "",
link: `#${row.notePath}`,
notePath: row.notePath,
highlightedNotePathTitle: row.highlightedNotePathTitle
};
})
);
},
(suggestions) => resolve(suggestions),
{
allowCreatingNotes: true
suggestionMode,
}
);
});
// Map internal suggestions to CKEditor mention feed items
return rows.map((row): ExtendedMentionFeedObjectItem => ({
action: row.action?.toString(),
noteTitle: row.noteTitle,
id: `@${row.notePathTitle}`,
name: row.notePathTitle || "",
link: `#${row.notePath}`,
notePath: row.notePath,
parentNoteId: row.parentNoteId,
highlightedNotePathTitle: row.highlightedNotePathTitle
}));
}
async function autocompleteSource(term: string, cb: (rows: Suggestion[]) => void, options: Options = {}) {
async function autocompleteSource(
term: string,
callback: (rows: Suggestion[]) => void,
options: Options = {}
) {
// Check if we're in command mode
if (options.isCommandPalette && term.startsWith(">")) {
const commandQuery = term.substring(1).trim();
// Get commands (all if no query, filtered if query provided)
const commands = commandQuery.length === 0
? commandRegistry.getAllCommands()
: commandRegistry.searchCommands(commandQuery);
const commands =
commandQuery.length === 0
? commandRegistry.getAllCommands()
: commandRegistry.searchCommands(commandQuery);
// Convert commands to suggestions
const commandSuggestions: Suggestion[] = commands.map(cmd => ({
action: "command",
const commandSuggestions: Suggestion[] = commands.map((cmd) => ({
action: SuggestionAction.Command,
commandId: cmd.id,
noteTitle: cmd.name,
notePathTitle: `>${cmd.name}`,
highlightedNotePathTitle: cmd.name,
commandDescription: cmd.description,
commandShortcut: cmd.shortcut,
icon: cmd.icon
icon: cmd.icon,
}));
cb(commandSuggestions);
callback(commandSuggestions);
return;
}
const fastSearch = options.fastSearch === false ? false : true;
if (fastSearch === false) {
if (term.trim().length === 0) {
return;
}
cb([
const fastSearch = options.fastSearch !== false;
const trimmedTerm = term.trim();
const activeNoteId = appContext.tabManager.getActiveContextNoteId();
if (!fastSearch && trimmedTerm.length === 0) return;
if (!fastSearch) {
callback([
{
noteTitle: term,
highlightedNotePathTitle: t("quick-search.searching")
}
noteTitle: trimmedTerm,
highlightedNotePathTitle: t("quick-search.searching"),
},
]);
}
const activeNoteId = appContext.tabManager.getActiveContextNoteId();
const length = term.trim().length;
let results = await server.get<Suggestion[]>(`autocomplete?query=${encodeURIComponent(term)}&activeNoteId=${activeNoteId}&fastSearch=${fastSearch}`);
let results = await server.get<Suggestion[]>(
`autocomplete?query=${encodeURIComponent(trimmedTerm)}&activeNoteId=${activeNoteId}&fastSearch=${fastSearch}`
);
options.fastSearch = true;
if (length >= 1 && options.allowCreatingNotes) {
results = [
{
action: "create-note",
noteTitle: term,
parentNoteId: activeNoteId || "root",
highlightedNotePathTitle: t("note_autocomplete.create-note", { term })
} as Suggestion
].concat(results);
}
if (length >= 1 && options.allowJumpToSearchNotes) {
results = results.concat([
{
action: "search-notes",
noteTitle: term,
highlightedNotePathTitle: `${t("note_autocomplete.search-for", { term })} <kbd style='color: var(--muted-text-color); background-color: transparent; float: right;'>Ctrl+Enter</kbd>`
// --- Create Note suggestions ---
if (trimmedTerm.length >= 1) {
switch (options.suggestionMode) {
case SuggestionMode.SuggestCreateOnly: {
results = [
{
action: SuggestionAction.CreateNote,
noteTitle: trimmedTerm,
parentNoteId: "inbox",
highlightedNotePathTitle: t("note_autocomplete.create-note", { term: trimmedTerm }),
},
{
action: SuggestionAction.CreateChildNote,
noteTitle: trimmedTerm,
parentNoteId: activeNoteId || "root",
highlightedNotePathTitle: t("note_autocomplete.create-child-note", { term: trimmedTerm }),
},
...results,
];
break;
}
]);
case SuggestionMode.SuggestCreateAndLink: {
results = [
{
action: SuggestionAction.CreateAndLinkNote,
noteTitle: trimmedTerm,
parentNoteId: "inbox",
highlightedNotePathTitle: t("note_autocomplete.create-and-link-note", { term: trimmedTerm }),
},
{
action: SuggestionAction.CreateAndLinkChildNote,
noteTitle: trimmedTerm,
parentNoteId: activeNoteId || "root",
highlightedNotePathTitle: t("note_autocomplete.create-and-link-child-note", { term: trimmedTerm }),
},
...results,
];
break;
}
default:
// CreateMode.None or undefined → no creation suggestions
break;
}
}
if (term.match(/^[a-z]+:\/\/.+/i) && options.allowExternalLinks) {
// --- Jump to Search Notes ---
if (trimmedTerm.length >= 1 && options.allowJumpToSearchNotes) {
results = [
...results,
{
action: SuggestionAction.SearchNotes,
noteTitle: trimmedTerm,
highlightedNotePathTitle: `${t("note_autocomplete.search-for", {
term: trimmedTerm,
})} <kbd style='color: var(--muted-text-color); background-color: transparent; float: right;'>Ctrl+Enter</kbd>`,
},
];
}
// --- External Link suggestion ---
if (/^[a-z]+:\/\/.+/i.test(trimmedTerm) && options.allowExternalLinks) {
results = [
{
action: "external-link",
externalLink: term,
highlightedNotePathTitle: t("note_autocomplete.insert-external-link", { term })
} as Suggestion
].concat(results);
action: SuggestionAction.ExternalLink,
externalLink: trimmedTerm,
highlightedNotePathTitle: t("note_autocomplete.insert-external-link", { term: trimmedTerm }),
},
...results,
];
}
cb(results);
callback(results);
}
function clearText($el: JQuery<HTMLElement>) {
@ -198,6 +291,85 @@ function fullTextSearch($el: JQuery<HTMLElement>, options: Options) {
$el.autocomplete("val", searchString);
}
function renderCommandSuggestion(s: Suggestion): string {
const icon = s.icon || "bx bx-terminal";
const shortcut = s.commandShortcut
? `<kbd class="command-shortcut">${s.commandShortcut}</kbd>`
: "";
return `
<div class="command-suggestion">
<span class="command-icon ${icon}"></span>
<div class="command-content">
<div class="command-name">${s.highlightedNotePathTitle}</div>
${s.commandDescription ? `<div class="command-description">${s.commandDescription}</div>` : ""}
</div>
${shortcut}
</div>
`;
}
function renderNoteSuggestion(s: Suggestion): string {
const actionClass =
s.action === SuggestionAction.SearchNotes ? "search-notes-action" : "";
const iconClass = (() => {
switch (s.action) {
case SuggestionAction.SearchNotes:
return "bx bx-search";
case SuggestionAction.CreateAndLinkNote:
case SuggestionAction.CreateNote:
return "bx bx-plus";
case SuggestionAction.CreateAndLinkChildNote:
case SuggestionAction.CreateChildNote:
return "bx bx-plus";
case SuggestionAction.ExternalLink:
return "bx bx-link-external";
default:
return s.icon ?? "bx bx-note";
}
})();
return `
<div class="note-suggestion ${actionClass}" style="display:inline-flex; align-items:center;">
<span class="icon ${iconClass}" style="display:inline-block; vertical-align:middle; line-height:1; margin-right:0.4em;"></span>
<span class="text" style="display:inline-block; vertical-align:middle;">
<span class="search-result-title">${s.highlightedNotePathTitle}</span>
${s.highlightedAttributeSnippet
? `<span class="search-result-attributes">${s.highlightedAttributeSnippet}</span>`
: ""}
</span>
</div>
`;
}
function renderSuggestion(suggestion: Suggestion): string {
return suggestion.action === SuggestionAction.Command
? renderCommandSuggestion(suggestion)
: renderNoteSuggestion(suggestion);
}
function mapSuggestionToCreateNoteAction(
action: SuggestionAction
): CreateNoteAction | null {
switch (action) {
case SuggestionAction.CreateNote:
return CreateNoteAction.CreateNote;
case SuggestionAction.CreateAndLinkNote:
return CreateNoteAction.CreateAndLinkNote;
case SuggestionAction.CreateChildNote:
return CreateNoteAction.CreateChildNote;
case SuggestionAction.CreateAndLinkChildNote:
return CreateNoteAction.CreateAndLinkChildNote;
default:
return null;
}
}
function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
if ($el.hasClass("note-autocomplete-input")) {
// clear any event listener added in previous invocation of this function
@ -283,24 +455,21 @@ function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
$el.autocomplete(
{
...autocompleteOptions,
appendTo: document.querySelector("body"),
appendTo: document.body,
hint: false,
autoselect: true,
// openOnFocus has to be false, otherwise re-focus (after return from note type chooser dialog) forces
// re-querying of the autocomplete source which then changes the currently selected suggestion
openOnFocus: false,
minLength: 0,
tabAutocomplete: false
tabAutocomplete: false,
},
[
{
source: (term, cb) => {
source: (term, callback) => {
clearTimeout(debounceTimeoutId);
debounceTimeoutId = setTimeout(() => {
if (isComposingInput) {
return;
if (!isComposingInput) {
autocompleteSource(term, callback, options);
}
autocompleteSource(term, cb, options);
}, searchDelay);
if (searchDelay === 0) {
@ -308,109 +477,85 @@ function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
}
},
displayKey: "notePathTitle",
templates: {
suggestion: (suggestion) => {
if (suggestion.action === "command") {
let html = `<div class="command-suggestion">`;
html += `<span class="command-icon ${suggestion.icon || "bx bx-terminal"}"></span>`;
html += `<div class="command-content">`;
html += `<div class="command-name">${suggestion.highlightedNotePathTitle}</div>`;
if (suggestion.commandDescription) {
html += `<div class="command-description">${suggestion.commandDescription}</div>`;
}
html += `</div>`;
if (suggestion.commandShortcut) {
html += `<kbd class="command-shortcut">${suggestion.commandShortcut}</kbd>`;
}
html += '</div>';
return html;
}
// Add special class for search-notes action
const actionClass = suggestion.action === "search-notes" ? "search-notes-action" : "";
// Choose appropriate icon based on action
let iconClass = suggestion.icon ?? "bx bx-note";
if (suggestion.action === "search-notes") {
iconClass = "bx bx-search";
} else if (suggestion.action === "create-note") {
iconClass = "bx bx-plus";
} else if (suggestion.action === "external-link") {
iconClass = "bx bx-link-external";
}
// Simplified HTML structure without nested divs
let html = `<div class="note-suggestion ${actionClass}">`;
html += `<span class="icon ${iconClass}"></span>`;
html += `<span class="text">`;
html += `<span class="search-result-title">${suggestion.highlightedNotePathTitle}</span>`;
// Add attribute snippet inline if available
if (suggestion.highlightedAttributeSnippet) {
html += `<span class="search-result-attributes">${suggestion.highlightedAttributeSnippet}</span>`;
}
html += `</span>`;
html += `</div>`;
return html;
}
},
// we can't cache identical searches because notes can be created / renamed, new recent notes can be added
cache: false
}
templates: { suggestion: renderSuggestion },
cache: false,
},
]
);
// TODO: Types fail due to "autocomplete:selected" not being registered in type definitions.
($el as any).on("autocomplete:selected", async (event: Event, suggestion: Suggestion) => {
if (suggestion.action === "command") {
async function doCommand() {
$el.autocomplete("close");
$el.trigger("autocomplete:commandselected", [suggestion]);
return;
}
if (suggestion.action === "external-link") {
async function doExternalLink() {
$el.setSelectedNotePath(null);
$el.setSelectedExternalLink(suggestion.externalLink);
$el.autocomplete("val", suggestion.externalLink);
$el.autocomplete("close");
$el.trigger("autocomplete:externallinkselected", [suggestion]);
}
async function resolveSuggestionNotePathUnderCurrentHoist(note: FNote) {
const hoisted = appContext.tabManager.getActiveContext()?.hoistedNoteId;
suggestion.notePath = note.getBestNotePathString(hoisted);
}
async function doSearchNotes() {
const searchString = suggestion.noteTitle;
appContext.triggerCommand("searchNotes", { searchString });
}
async function selectNoteFromAutocomplete(suggestion: Suggestion) {
$el.setSelectedNotePath(suggestion.notePath);
$el.setSelectedExternalLink(null);
$el.autocomplete("val", suggestion.noteTitle);
$el.autocomplete("close");
$el.trigger("autocomplete:externallinkselected", [suggestion]);
return;
$el.trigger("autocomplete:noteselected", [suggestion]);
}
if (suggestion.action === "create-note") {
const { success, noteType, templateNoteId, notePath } = await noteCreateService.chooseNoteType();
if (!success) {
switch (suggestion.action) {
case SuggestionAction.Command:
await doCommand();
return;
case SuggestionAction.ExternalLink:
await doExternalLink();
break;
case SuggestionAction.CreateNote:
case SuggestionAction.CreateAndLinkNote:
case SuggestionAction.CreateChildNote:
case SuggestionAction.CreateAndLinkChildNote: {
const createNoteAction = mapSuggestionToCreateNoteAction(
suggestion.action
)!;
const { note } = await noteCreateService.createNoteFromAction(
createNoteAction,
true,
suggestion.noteTitle,
suggestion.parentNoteId,
);
if (!note) break;
await resolveSuggestionNotePathUnderCurrentHoist(note);
await selectNoteFromAutocomplete(suggestion);
break;
}
const { note } = await noteCreateService.createNote( notePath || suggestion.parentNoteId, {
title: suggestion.noteTitle,
activate: false,
type: noteType,
templateNoteId: templateNoteId
});
const hoistedNoteId = appContext.tabManager.getActiveContext()?.hoistedNoteId;
suggestion.notePath = note?.getBestNotePathString(hoistedNoteId);
case SuggestionAction.SearchNotes:
await doSearchNotes();
break;
default:
await selectNoteFromAutocomplete(suggestion);
}
if (suggestion.action === "search-notes") {
const searchString = suggestion.noteTitle;
appContext.triggerCommand("searchNotes", { searchString });
return;
}
$el.setSelectedNotePath(suggestion.notePath);
$el.setSelectedExternalLink(null);
$el.autocomplete("val", suggestion.noteTitle);
$el.autocomplete("close");
$el.trigger("autocomplete:noteselected", [suggestion]);
});
$el.on("autocomplete:closed", () => {

View File

@ -10,8 +10,63 @@ import type FNote from "../entities/fnote.js";
import type FBranch from "../entities/fbranch.js";
import type { ChooseNoteTypeResponse } from "../widgets/dialogs/note_type_chooser.js";
import type { CKTextEditor } from "@triliumnext/ckeditor5";
import dateNoteService from "../services/date_notes.js";
import { CreateNoteAction } from "@triliumnext/commons";
export interface CreateNoteOpts {
/**
* Defines the type hierarchy and rules for valid argument combinations
* accepted by `note_create`.
*
* ## Overview
* Each variant extends `CreateNoteOpts` and enforces specific constraints to
* ensure only valid note creation options are allowed at compile time.
*
* ## Type Safety
* The `PromptingRule` ensures that `promptForType` and `type` stay mutually
* exclusive (if prompting, `type` is undefined).
*
* The type system prevents invalid argument mixes by design successful type
* checks guarantee a valid state, following CurryHoward correspondence
* principles (types as proofs).
*
* ## Maintenance
* If adding or modifying `Opts`, ensure:
* - All valid combinations are represented (avoid *false negatives*).
* - No invalid ones slip through (avoid *false positives*).
*
* Hierarchy (general specific):
* - CreateNoteOpts
* - CreateNoteWithUrlOpts
* - CreateNoteIntoDefaultOpts
*/
/** enforces a truth rule:
* - If `promptForType` is true `type` must be undefined.
* - If `promptForType` is false `type` must be defined.
*/
type PromptingRule = {
promptForType: true;
type?: never;
} | {
promptForType?: false;
/**
* The note type (e.g. "text", "code", "image", "mermaid", etc.).
*
* If omitted, the server will automatically default to `"text"`.
* TypeScript still enforces explicit typing unless `promptForType` is true,
* to encourage clarity at the call site.
*/
type?: string;
};
/**
* Base type for all note creation options (domain hypernym).
* All specific note option types extend from this.
*
* Combine with `&` to ensure valid logical combinations.
*/
type CreateNoteBase = {
isProtected?: boolean;
saveSelection?: boolean;
title?: string | null;
@ -21,10 +76,34 @@ export interface CreateNoteOpts {
templateNoteId?: string;
activate?: boolean;
focus?: "title" | "content";
target?: string;
targetBranchId?: string;
textEditor?: CKTextEditor;
}
} & PromptingRule;
/*
* Defines options for creating a note at a specific path.
* Serves as a base for "into", "before", and "after" variants,
* sharing common URL-related fields.
*/
export type CreateNoteWithLinkOpts =
| (CreateNoteBase & {
target: "into";
parentNoteLink?: string;
// No branch ID needed for "into"
})
| (CreateNoteBase & {
target: "before" | "after";
// Either an Url or a Path
parentNoteLink?: string;
// Required for "before"/"after"
targetBranchId: string;
});
export type CreateNoteIntoDefaultOpts = CreateNoteBase & {
target: "default";
parentNoteLink?: never;
};
export type CreateNoteOpts = CreateNoteWithLinkOpts | CreateNoteIntoDefaultOpts;
interface Response {
// TODO: Deduplicate with server once we have client/server architecture.
@ -37,7 +116,141 @@ interface DuplicateResponse {
note: FNote;
}
async function createNote(parentNotePath: string | undefined, options: CreateNoteOpts = {}) {
// The low level note creation
async function createNote(
options: CreateNoteOpts
): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
let resolvedOptions = { ...options };
// handle prompts centrally to write once fix for all
if (options.promptForType) {
const maybeResolvedOptions = await promptForType(options);
if (!maybeResolvedOptions) {
return { note: null, branch: undefined };
}
resolvedOptions = maybeResolvedOptions;
}
switch(resolvedOptions.target) {
case "default":
return createNoteIntoDefaultLocation(resolvedOptions);
case "into":
case "before":
case "after":
return createNoteWithLink(resolvedOptions);
}
}
// A wrapper to standardize note creation
async function createNoteFromAction(
action: CreateNoteAction,
promptForType: boolean,
title: string | undefined,
parentNoteLink: string | undefined,
): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
switch (action) {
case CreateNoteAction.CreateNote: {
const resp = await createNote(
{
target: "default",
title: title,
activate: true,
promptForType,
}
);
return resp;
}
case CreateNoteAction.CreateAndLinkNote: {
const resp = await createNote(
{
target: "default",
title,
activate: false,
promptForType,
}
);
return resp;
}
case CreateNoteAction.CreateChildNote: {
if (!parentNoteLink) {
console.warn("createNoteFromAction: Missing parentNoteLink");
return { note: null, branch: undefined };
}
const resp = await createNote(
{
target: "into",
parentNoteLink,
title,
activate: true,
promptForType,
},
);
return resp
}
case CreateNoteAction.CreateAndLinkChildNote: {
if (!parentNoteLink) {
console.warn("createNoteFromAction: Missing parentNoteLink");
return { note: null, branch: undefined };
}
const resp = await createNote(
{
target: "into",
parentNoteLink: parentNoteLink,
title,
activate: false,
promptForType,
},
)
return resp;
}
default:
console.warn("Unknown CreateNoteAction:", action);
return { note: null, branch: undefined };
}
}
async function promptForType(
options: CreateNoteOpts
) : Promise<CreateNoteOpts | null> {
const { success, noteType, templateNoteId, notePath } = await chooseNoteType();
if (!success) {
return null;
}
let resolvedOptions: CreateNoteOpts = {
...options,
promptForType: false,
type: noteType,
templateNoteId,
};
if (notePath) {
resolvedOptions = {
...resolvedOptions,
target: "into",
parentNoteLink: notePath,
};
}
return resolvedOptions;
}
/**
* Creates a new note under a specified parent note path.
*
* @param target - Mirrors the `createNote` API in apps/server/src/routes/api/notes.ts.
* @param options - Note creation options
* @returns A promise resolving with the created note and its branch.
*/
async function createNoteWithLink(
options: CreateNoteWithLinkOpts
): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
options = Object.assign(
{
activate: true,
@ -61,7 +274,8 @@ async function createNote(parentNotePath: string | undefined, options: CreateNot
[options.title, options.content] = parseSelectedHtml(options.textEditor.getSelectedHtml());
}
const parentNoteId = treeService.getNoteIdFromUrl(parentNotePath);
const parentNoteLink = options.parentNoteLink;
const parentNoteId = treeService.getNoteIdFromLink(parentNoteLink);
if (options.type === "mermaid" && !options.content && !options.templateNoteId) {
options.content = `graph TD;
@ -71,7 +285,12 @@ async function createNote(parentNotePath: string | undefined, options: CreateNot
C-->D;`;
}
const { note, branch } = await server.post<Response>(`notes/${parentNoteId}/children?target=${options.target}&targetBranchId=${options.targetBranchId || ""}`, {
const query =
options.target === "into"
? `target=${options.target}`
: `target=${options.target}&targetBranchId=${options.targetBranchId}`;
const { note, branch } = await server.post<Response>(`notes/${parentNoteId}/children?${query}`, {
title: options.title,
content: options.content || "",
isProtected: options.isProtected,
@ -89,7 +308,7 @@ async function createNote(parentNotePath: string | undefined, options: CreateNot
const activeNoteContext = appContext.tabManager.getActiveContext();
if (activeNoteContext && options.activate) {
await activeNoteContext.setNote(`${parentNotePath}/${note.noteId}`);
await activeNoteContext.setNote(`${parentNoteId}/${note.noteId}`);
if (options.focus === "title") {
appContext.triggerEvent("focusAndSelectTitle", { isNewNote: true });
@ -107,25 +326,46 @@ async function createNote(parentNotePath: string | undefined, options: CreateNot
};
}
/**
* Creates a new note inside the user's Inbox.
*
* @param {CreateNoteIntoDefaultOpts} [options] - Optional settings such as title, type, template, or content.
* @returns {Promise<{ note: FNote | null; branch: FBranch | undefined }>}
* Resolves with the created note and its branch, or `{ note: null, branch: undefined }` if the inbox is missing.
*/
async function createNoteIntoDefaultLocation(
options: CreateNoteIntoDefaultOpts
): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
const inboxNote = await dateNoteService.getInboxNote();
if (!inboxNote) {
console.warn("Missing inbox note.");
// always return a defined object
return { note: null, branch: undefined };
}
if (options.isProtected === undefined) {
options.isProtected =
inboxNote.isProtected && protectedSessionHolder.isProtectedSessionAvailable();
}
const result = await createNoteWithLink(
{
...options,
target: "into",
parentNoteLink: inboxNote.getBestNotePathString(),
}
);
return result;
}
async function chooseNoteType() {
return new Promise<ChooseNoteTypeResponse>((res) => {
appContext.triggerCommand("chooseNoteType", { callback: res });
});
}
async function createNoteWithTypePrompt(parentNotePath: string, options: CreateNoteOpts = {}) {
const { success, noteType, templateNoteId, notePath } = await chooseNoteType();
if (!success) {
return;
}
options.type = noteType;
options.templateNoteId = templateNoteId;
return await createNote(notePath || parentNotePath, options);
}
/* If the first element is heading, parse it out and use it as a new heading. */
function parseSelectedHtml(selectedHtml: string) {
const dom = $.parseHTML(selectedHtml);
@ -146,7 +386,7 @@ function parseSelectedHtml(selectedHtml: string) {
}
async function duplicateSubtree(noteId: string, parentNotePath: string) {
const parentNoteId = treeService.getNoteIdFromUrl(parentNotePath);
const parentNoteId = treeService.getNoteIdFromLink(parentNotePath);
const { note } = await server.post<DuplicateResponse>(`notes/${noteId}/duplicate/${parentNoteId}`);
await ws.waitForMaxKnownEntityChangeId();
@ -159,7 +399,6 @@ async function duplicateSubtree(noteId: string, parentNotePath: string) {
export default {
createNote,
createNoteWithTypePrompt,
createNoteFromAction,
duplicateSubtree,
chooseNoteType
};

View File

@ -92,7 +92,7 @@ async function resolveNotePathToSegments(notePath: string, hoistedNoteId = "root
if (effectivePathSegments.includes(hoistedNoteId) && effectivePathSegments.includes('root')) {
return effectivePathSegments;
} else {
const noteId = getNoteIdFromUrl(notePath);
const noteId = getNoteIdFromLink(notePath);
if (!noteId) {
throw new Error(`Unable to find note with ID: ${noteId}.`);
}
@ -129,7 +129,7 @@ function getParentProtectedStatus(node: Fancytree.FancytreeNode) {
return hoistedNoteService.isHoistedNode(node) ? false : node.getParent().data.isProtected;
}
function getNoteIdFromUrl(urlOrNotePath: string | null | undefined) {
function getNoteIdFromLink(urlOrNotePath: string | null | undefined) {
if (!urlOrNotePath) {
return null;
}
@ -306,7 +306,7 @@ export default {
getParentProtectedStatus,
getNotePath,
getNotePathTitleComponents,
getNoteIdFromUrl,
getNoteIdFromLink,
getNoteIdAndParentIdFromUrl,
getBranchIdFromUrl,
getNoteTitle,

View File

@ -439,7 +439,8 @@ body.desktop .tabulator-popup-container,
}
body.desktop .dropdown-menu:not(#context-menu-container) .dropdown-item,
body #context-menu-container .dropdown-item > span {
body #context-menu-container .dropdown-item > span,
body.mobile .dropdown .dropdown-submenu > span {
display: flex;
align-items: center;
}
@ -1315,11 +1316,11 @@ body.mobile #context-menu-container.mobile-bottom-menu {
inset-inline-end: 0 !important;
bottom: 0 !important;
top: unset !important;
max-height: 70vh;
max-height: 90vh;
overflow: auto !important;
user-select: none;
-webkit-user-select: none;
padding-bottom: env(safe-area-inset-bottom) !important;
padding-bottom: max(env(safe-area-inset-bottom), var(--padding, var(--menu-padding-size))) !important;
}
body.mobile .dropdown-menu {
@ -2008,7 +2009,7 @@ body.electron.platform-darwin:not(.native-titlebar) .tab-row-container {
-webkit-app-region: drag;
}
body.electron.platform-darwin:not(.native-titlebar) #tab-row-left-spacer {
body.electron.platform-darwin:not(.native-titlebar):not(.full-screen) #tab-row-left-spacer {
width: 80px;
}

View File

@ -119,17 +119,6 @@ body.backdrop-effects-disabled {
font-size: 0.9rem !important;
}
body.mobile .dropdown-menu {
backdrop-filter: var(--dropdown-backdrop-filter);
border-radius: var(--dropdown-border-radius);
position: relative;
}
body.mobile .dropdown-menu .dropdown-menu {
backdrop-filter: unset !important;
border-radius: unset !important;
}
body.desktop .dropdown-menu::before,
:root .ck.ck-dropdown__panel::before,
:root .excalidraw .popover::before,
@ -157,17 +146,12 @@ body.desktop .dropdown-submenu .dropdown-menu::before {
content: unset;
}
body.mobile .dropdown-submenu .dropdown-menu {
background: transparent !important;
}
body.desktop .dropdown-submenu .dropdown-menu {
backdrop-filter: var(--dropdown-backdrop-filter);
background: transparent;
}
.dropdown-item,
body.mobile .dropdown-submenu .dropdown-toggle,
.excalidraw .context-menu .context-menu-item {
--menu-item-start-padding: 8px;
--menu-item-end-padding: 22px;
@ -201,10 +185,6 @@ body.mobile .dropdown-item:not(:last-of-type) {
margin-bottom: 0.5em;
}
body.mobile .dropdown-submenu:hover {
background: transparent !important;
}
html body .dropdown-item.disabled,
html body .dropdown-item[disabled] {
color: var(--menu-text-color) !important;
@ -321,17 +301,102 @@ body.desktop .dropdown-menu.static .dropdown-item.active {
--active-item-text-color: var(--menu-text-color);
}
/* #region Mobile tweaks for dropdown menus */
body.mobile #context-menu-cover {
transition: background-color 150ms ease-in;
&.show {
background: rgba(0, 0, 0, 0.7);
}
}
body.mobile .dropdown-menu {
--dropdown-menu-padding-vertical: 0.7em;
--dropdown-menu-padding-horizontal: 1em;
--hover-item-background-color: var(--card-background-color);
font-size: 1em !important;
backdrop-filter: var(--dropdown-backdrop-filter);
border-radius: var(--dropdown-border-radius) var(--dropdown-border-radius) 0 0;
position: relative;
.dropdown-toggle::after {
top: 0.5em;
right: var(--dropdown-menu-padding-horizontal);
transform: translateX(50%) rotate(90deg);
}
.dropdown-item.submenu-open .dropdown-toggle::after {
transform: rotate(270deg);
}
.dropdown-item,
.dropdown-custom-item {
margin-bottom: 0;
padding: var(--dropdown-menu-padding-vertical) var(--dropdown-menu-padding-horizontal) !important;
background: var(--card-background-color);
border-bottom: 1px solid var(--main-border-color) !important;
border-radius: 0;
}
.dropdown-item:first-of-type,
.dropdown-divider + .dropdown-item,
.dropdown-custom-item:first-of-type,
.dropdown-divider + .dropdown-custom-item {
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
.dropdown-item:last-of-type,
.dropdown-item:has(+ .dropdown-divider),
.dropdown-custom-item:last-of-type,
.dropdown-custom-item:has(+ .dropdown-divider) {
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom: 0 !important;
}
.dropdown-divider {
visibility: hidden;
}
.dropdown-submenu {
padding: 0 !important;
backdrop-filter: unset !important;
.dropdown-toggle {
padding: var(--dropdown-menu-padding-vertical) var(--dropdown-menu-padding-horizontal);
}
.dropdown-menu {
--menu-background-color: rgba(0, 0, 0, 0.15);
border-radius: 0;
max-height: 0;
transition: max-height 100ms ease-in;
display: block !important;
&.show {
max-height: 1000px;
}
.dropdown-item {
background: transparent;
}
}
&.submenu-open {
.dropdown-toggle {
padding-bottom: var(--dropdown-menu-padding-vertical);
}
}
}
}
/* #endregion */
body.desktop .dropdown-menu .dropdown-toggle::after {
height: 100%;
}
body.mobile .dropdown-menu .dropdown-toggle::after {
transform: rotate(90deg);
}
body.mobile .dropdown-menu .dropdown-item.submenu-open .dropdown-toggle::after {
transform: rotate(270deg);
}
/* Dropdown item button (used in zoom buttons in global menu) */

View File

@ -230,7 +230,6 @@
"geo-map": "الخريطة الجغرافية",
"collapse_all_notes": "طي كل الملاحظات",
"include_archived_notes": "عرض الملاحظات المؤرشفة",
"expand_all_children": "توسيع جميع العناصر الفرعية",
"presentation": "عرض تقديمي",
"invalid_view_type": "نوع العرض {{type}} غير صالح"
},

View File

@ -764,7 +764,6 @@
"grid": "网格",
"list": "列表",
"collapse_all_notes": "折叠所有笔记",
"expand_all_children": "展开所有子项",
"collapse": "折叠",
"expand": "展开",
"invalid_view_type": "无效的查看类型 '{{type}}'",
@ -774,7 +773,11 @@
"geo-map": "地理地图",
"board": "看板",
"include_archived_notes": "展示归档笔记",
"presentation": "演示"
"presentation": "演示",
"expand_tooltip": "展开此集合的直接子代(单层深度)。点击右方箭头以查看更多选项。",
"expand_first_level": "展开直接子代",
"expand_nth_level": "展开 {{depth}} 层",
"expand_all_levels": "展开所有层级"
},
"edited_notes": {
"no_edited_notes_found": "今天还没有编辑过的笔记...",
@ -1151,7 +1154,10 @@
"unit": "字符"
},
"code_mime_types": {
"title": "下拉菜单可用的MIME文件类型"
"title": "下拉菜单可用的MIME文件类型",
"tooltip_syntax_highlighting": "语法高亮",
"tooltip_code_block_syntax": "文本笔记中的代码块",
"tooltip_code_note_syntax": "代码笔记"
},
"vim_key_bindings": {
"use_vim_keybindings_in_code_notes": "Vim 快捷键",
@ -1695,7 +1701,8 @@
"copy-link": "复制链接",
"paste": "粘贴",
"paste-as-plain-text": "以纯文本粘贴",
"search_online": "用 {{searchEngine}} 搜索 \"{{term}}\""
"search_online": "用 {{searchEngine}} 搜索 \"{{term}}\"",
"search_in_trilium": "在 Trilium 中搜索「{{term}}」"
},
"image_context_menu": {
"copy_reference_to_clipboard": "复制引用到剪贴板",

View File

@ -43,7 +43,7 @@
"link_title_arbitrary": "titulek odkazu může být změněn libovolně"
},
"branch_prefix": {
"prefix": "Prefix: ",
"prefix": "Předpona: ",
"save": "Uložit",
"edit_branch_prefix": "Upravit prefix větve",
"edit_branch_prefix_multiple": "Upravit prefix větve pro {{count}} větví",
@ -63,24 +63,59 @@
"bulk_actions_executed": "Hromadné akce byly úspěšně provedeny.",
"labels": "Štítky",
"relations": "Relace",
"other": "Ostatní"
"other": "Ostatní",
"none_yet": "Zatím žádné akce... přidejte akci kliknutím na jednu z dostupných výše."
},
"confirm": {
"cancel": "Zrušit",
"ok": "OK"
"ok": "OK",
"confirmation": "Potvrzení",
"are_you_sure_remove_note": "Opravdu chcete odstranit poznámku „{{title}}“ z mapy vztahů?",
"if_you_dont_check": "Pokud tuto možnost nezaškrtnete, poznámka bude odstraněna pouze z mapy vztahů.",
"also_delete_note": "Odstraňte také poznámku"
},
"delete_notes": {
"cancel": "Zrušit",
"ok": "OK",
"close": "Zavřít"
"close": "Zavřít",
"delete_notes_preview": "Odstranit náhled poznámek",
"delete_all_clones_description": "Odstraňte také všechny klony (lze vrátit zpět v nedávných změnách)",
"erase_notes_description": "Normální (měkké) smazání pouze označí poznámky jako smazané a lze je během určité doby obnovit (v dialogovém okně posledních změn). Zaškrtnutím této možnosti se poznámky okamžitě vymažou a nebude možné je obnovit.",
"erase_notes_warning": "Trvale smažte poznámky (nelze vrátit zpět), včetně všech klonů. Tím se vynutí opětovné načtení aplikace.",
"notes_to_be_deleted": "Následující poznámky budou smazány ({{notesCount}})",
"no_note_to_delete": "Žádná poznámka nebude smazána (pouze klony).",
"broken_relations_to_be_deleted": "Následující vazby budou přerušeny a smazány ({{relationCount}})",
"deleted_relation_text": "Poznámka {{- note}} (bude smazána) je odkazována vazbou {{- relation}} pocházející z {{- source}}."
},
"export": {
"close": "Zavřít"
"close": "Zavřít",
"export_note_title": "Exportovat poznámku",
"export_type_subtree": "Tato poznámka a všechny její odvozené poznámky",
"format_html": "HTML doporučeno, protože zachovává veškeré formátování",
"format_html_zip": "HTML v archivu ZIP toto se doporučuje, protože se tak zachová veškeré formátování.",
"format_markdown": "Markdown zachovává většinu formátování.",
"format_opml": "OPML formát pro výměnu osnov pouze pro text. Formátování, obrázky a soubory nejsou zahrnuty.",
"opml_version_1": "OPML v1.0 pouze prostý text",
"opml_version_2": "OPML v2.0 umožňuje také HTML",
"export_type_single": "Pouze tato poznámka bez jejích potomků",
"export": "Exportovat",
"choose_export_type": "Nejprve vyberte typ exportu",
"export_status": "Stav exportu",
"export_in_progress": "Export probíhá: {{progressCount}}",
"export_finished_successfully": "Export byl úspěšně dokončen.",
"format_pdf": "PDF pro tisk nebo sdílení.",
"share-format": "HTML pro publikování na webu používá stejný motiv jako sdílené poznámky, ale lze jej publikovat jako statický web."
},
"clone_to": {
"clone_notes_to": "Klonovat poznámky do...",
"help_on_links": "Nápověda k odkazům",
"notes_to_clone": "Poznámky na klonování",
"search_for_note_by_its_name": "hledat poznámku dle jejího názvu"
"search_for_note_by_its_name": "hledat poznámku dle jejího názvu",
"prefix_optional": "Předpona (volitelná)",
"target_parent_note": "Zaměřit rodičovskou poznámku",
"cloned_note_prefix_title": "Klonovaná poznámka se zobrazí ve stromu poznámek s danou předponou",
"clone_to_selected_note": "Klonovat vybranou poznámku",
"no_path_to_clone_to": "Žádná cest pro klonování.",
"note_cloned": "Poznámka: „{{clonedTitle}}“ bylo naklonováno do „{{targetTitle}}“"
}
}

View File

@ -39,7 +39,9 @@
"help_on_tree_prefix": "Hilfe zum Baumpräfix",
"prefix": "Präfix: ",
"save": "Speichern",
"branch_prefix_saved": "Zweigpräfix wurde gespeichert."
"branch_prefix_saved": "Zweigpräfix wurde gespeichert.",
"branch_prefix_saved_multiple": "Der Zweigpräfix wurde für {{count}} Zweige gespeichert.",
"edit_branch_prefix_multiple": "Präfix für {{count}} Zweige bearbeiten"
},
"bulk_actions": {
"bulk_actions": "Massenaktionen",
@ -684,7 +686,8 @@
"convert_into_attachment_failed": "Konvertierung der Notiz '{{title}}' fehlgeschlagen.",
"convert_into_attachment_successful": "Notiz '{{title}}' wurde als Anhang konvertiert.",
"convert_into_attachment_prompt": "Bist du dir sicher, dass du die Notiz '{{title}}' in ein Anhang der übergeordneten Notiz konvertieren möchtest?",
"print_pdf": "Export als PDF..."
"print_pdf": "Export als PDF...",
"open_note_on_server": "Öffne Notiz auf dem Server"
},
"onclick_button": {
"no_click_handler": "Das Schaltflächen-Widget „{{componentId}}“ hat keinen definierten Klick-Handler"
@ -757,7 +760,6 @@
"grid": "Gitter",
"list": "Liste",
"collapse_all_notes": "Alle Notizen einklappen",
"expand_all_children": "Unternotizen ausklappen",
"collapse": "Einklappen",
"expand": "Ausklappen",
"invalid_view_type": "Ungültiger Ansichtstyp „{{type}}“",
@ -767,7 +769,8 @@
"geo-map": "Weltkarte",
"board": "Tafel",
"include_archived_notes": "Zeige archivierte Notizen",
"presentation": "Präsentation"
"presentation": "Präsentation",
"expand_all_levels": "Alle Ebenen erweitern"
},
"edited_notes": {
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
@ -1104,7 +1107,8 @@
"title": "Inhaltsbreite",
"default_description": "Trilium begrenzt standardmäßig die maximale Inhaltsbreite, um die Lesbarkeit für maximierte Bildschirme auf Breitbildschirmen zu verbessern.",
"max_width_label": "Maximale Inhaltsbreite in Pixel",
"max_width_unit": "Pixel"
"max_width_unit": "Pixel",
"centerContent": "Inhalt zentriert halten"
},
"native_title_bar": {
"title": "Native Titelleiste (App-Neustart erforderlich)",
@ -1143,7 +1147,10 @@
"unit": "Zeichen"
},
"code_mime_types": {
"title": "Verfügbare MIME-Typen im Dropdown-Menü"
"title": "Verfügbare MIME-Typen im Dropdown-Menü",
"tooltip_syntax_highlighting": "Syntaxhervorhebung",
"tooltip_code_block_syntax": "Code-Blöcke in Textnotizen",
"tooltip_code_note_syntax": "Code-Notizen"
},
"vim_key_bindings": {
"use_vim_keybindings_in_code_notes": "Verwende VIM-Tastenkombinationen in Codenotizen (kein Ex-Modus)",
@ -1654,7 +1661,8 @@
"copy-link": "Link kopieren",
"paste": "Einfügen",
"paste-as-plain-text": "Als unformatierten Text einfügen",
"search_online": "Suche nach \"{{term}}\" mit {{searchEngine}} starten"
"search_online": "Suche nach \"{{term}}\" mit {{searchEngine}} starten",
"search_in_trilium": "Suche nach \"{{term}}\" in Trilium"
},
"image_context_menu": {
"copy_reference_to_clipboard": "Referenz in Zwischenablage kopieren",
@ -2028,7 +2036,8 @@
"new-item-placeholder": "Notiz Titel eingeben...",
"add-column-placeholder": "Spaltenname eingeben...",
"edit-note-title": "Klicke zum Editieren des Notiz-Titels",
"edit-column-title": "Klicke zum Editieren des Spalten-Titels"
"edit-column-title": "Klicke zum Editieren des Spalten-Titels",
"column-already-exists": "Die Spalte ist auf dem Board bereits vorhanden."
},
"command_palette": {
"tree-action-name": "Struktur: {{name}}",
@ -2078,5 +2087,19 @@
"edit-slide": "Folie bearbeiten",
"start-presentation": "Präsentation starten",
"slide-overview": "Übersicht der Folien ein-/ausblenden"
},
"read-only-info": {
"read-only-note": "Aktuell wird eine Notiz nur im Lese-Modus angezeigt.",
"auto-read-only-note": "Diese Notiz wird im Nur-Lesen-Modus angezeigt, um ein schnelleres Laden zu ermöglichen.",
"auto-read-only-learn-more": "Mehr erfahren",
"edit-note": "Notiz bearbeiten"
},
"calendar_view": {
"delete_note": "Notiz löschen..."
},
"note-color": {
"clear-color": "Notizfarbe entfernen",
"set-color": "Notizfarbe wählen",
"set-custom-color": "Eigene Notizfarbe wählen"
}
}

View File

@ -1727,7 +1727,8 @@
"refresh-saved-search-results": "Refresh saved search results",
"create-child-note": "Create child note",
"unhoist": "Unhoist",
"toggle-sidebar": "Toggle sidebar"
"toggle-sidebar": "Toggle sidebar",
"dropping-not-allowed": "Dropping notes into this location is not allowed."
},
"title_bar_buttons": {
"window-on-top": "Keep Window on Top"
@ -1830,7 +1831,8 @@
"duplicate-launcher": "Duplicate launcher <kbd data-command=\"duplicateSubtree\">"
},
"editable-text": {
"auto-detect-language": "Auto-detected"
"auto-detect-language": "Auto-detected",
"keeps-crashing": "Editing component keeps crashing. Please try restarting Trilium. If problem persists, consider creating a bug report."
},
"highlighting": {
"title": "Code Blocks",
@ -1895,7 +1897,10 @@
},
"note_autocomplete": {
"search-for": "Search for \"{{term}}\"",
"create-note": "Create and link child note \"{{term}}\"",
"create-child-note": "Create child note \"{{term}}\"",
"create-note": "Create note \"{{term}}\"",
"create-and-link-child-note": "Create and link child note \"{{term}}\"",
"create-and-link-note": "Create and link note \"{{term}}\"",
"insert-external-link": "Insert external link to \"{{term}}\"",
"clear-text-field": "Clear text field",
"show-recent-notes": "Show recent notes",

View File

@ -690,7 +690,8 @@
"convert_into_attachment_failed": "La conversión de nota '{{title}}' falló.",
"convert_into_attachment_successful": "La nota '{{title}}' ha sido convertida a un archivo adjunto.",
"convert_into_attachment_prompt": "¿Está seguro que desea convertir la nota '{{title}}' en un archivo adjunto de la nota padre?",
"print_pdf": "Exportar como PDF..."
"print_pdf": "Exportar como PDF...",
"open_note_on_server": "Abrir nota en el servidor"
},
"onclick_button": {
"no_click_handler": "El widget de botón '{{componentId}}' no tiene un controlador de clics definido"
@ -763,7 +764,6 @@
"grid": "Cuadrícula",
"list": "Lista",
"collapse_all_notes": "Contraer todas las notas",
"expand_all_children": "Ampliar todas las subnotas",
"collapse": "Colapsar",
"expand": "Expandir",
"invalid_view_type": "Tipo de vista inválida '{{type}}'",
@ -773,7 +773,11 @@
"geo-map": "Mapa Geo",
"board": "Tablero",
"include_archived_notes": "Mostrar notas archivadas",
"presentation": "Presentación"
"presentation": "Presentación",
"expand_tooltip": "Expande las notas hijas inmediatas de esta colección (un nivel). Para más opciones, pulsa la flecha a la derecha.",
"expand_first_level": "Expandir hijos inmediatos",
"expand_nth_level": "Expandir {{depth}} niveles",
"expand_all_levels": "Expandir todos los niveles"
},
"edited_notes": {
"no_edited_notes_found": "Aún no hay notas editadas en este día...",
@ -1301,7 +1305,10 @@
"title": "Editor"
},
"code_mime_types": {
"title": "Tipos MIME disponibles en el menú desplegable"
"title": "Tipos MIME disponibles en el menú desplegable",
"tooltip_syntax_highlighting": "Resaltado de sintaxis",
"tooltip_code_block_syntax": "Bloques de código en notas de texto",
"tooltip_code_note_syntax": "Notas de código"
},
"vim_key_bindings": {
"use_vim_keybindings_in_code_notes": "Atajos de teclas de Vim",
@ -1851,7 +1858,8 @@
"copy-link": "Copiar enlace",
"paste": "Pegar",
"paste-as-plain-text": "Pegar como texto plano",
"search_online": "Buscar \"{{term}}\" con {{searchEngine}}"
"search_online": "Buscar \"{{term}}\" con {{searchEngine}}",
"search_in_trilium": "Buscar \"{{term}}\" en Trilium"
},
"image_context_menu": {
"copy_reference_to_clipboard": "Copiar referencia al portapapeles",
@ -1992,7 +2000,8 @@
"add-column-placeholder": "Ingresar título de la columna...",
"edit-note-title": "Haga clic para editar el título de la nota",
"edit-column-title": "Haga clic para editar el título de la columna",
"remove-from-board": "Eliminar del tablero"
"remove-from-board": "Eliminar del tablero",
"column-already-exists": "Esta columna ya existe en el tablero."
},
"content_renderer": {
"open_externally": "Abrir externamente"
@ -2092,5 +2101,10 @@
},
"calendar_view": {
"delete_note": "Eliminar nota..."
},
"note-color": {
"clear-color": "Borrar color de nota",
"set-color": "Asignar color de nota",
"set-custom-color": "Asignar color de nota personalizado"
}
}

View File

@ -762,7 +762,6 @@
"grid": "Grille",
"list": "Liste",
"collapse_all_notes": "Réduire toutes les notes",
"expand_all_children": "Développer tous les enfants",
"collapse": "Réduire",
"expand": "Développer",
"invalid_view_type": "Type de vue non valide '{{type}}'",

View File

@ -1337,7 +1337,6 @@
"grid": "Griglia",
"list": "Lista",
"collapse_all_notes": "Comprimi tutte le note",
"expand_all_children": "Espandi tutti i bambini",
"collapse": "Crollo",
"expand": "Espandere",
"book_properties": "Proprietà della raccolta",

View File

@ -531,7 +531,6 @@
"grid": "グリッド",
"list": "リスト",
"collapse_all_notes": "すべてのノートを折りたたむ",
"expand_all_children": "すべての子を展開",
"collapse": "折りたたむ",
"expand": "展開",
"book_properties": "コレクションプロパティ",
@ -542,7 +541,11 @@
"geo-map": "ジオマップ",
"board": "ボード",
"include_archived_notes": "アーカイブされたノートを表示",
"presentation": "プレゼンテーション"
"presentation": "プレゼンテーション",
"expand_tooltip": "このコレクションの直下の子1階層下を展開します。その他のオプションについては、右側の矢印を押してください。",
"expand_first_level": "直下の子を展開",
"expand_nth_level": "{{depth}} 階層下まで展開",
"expand_all_levels": "すべての階層を展開"
},
"note_types": {
"geo-map": "ジオマップ",
@ -1301,7 +1304,8 @@
"copy-link": "リンクをコピー",
"paste": "貼り付け",
"paste-as-plain-text": "プレーンテキストで貼り付け",
"search_online": "{{searchEngine}} で \"{{term}}\" を検索"
"search_online": "{{searchEngine}} で \"{{term}}\" を検索",
"search_in_trilium": "Triliumで「{{term}}」を検索"
},
"duration": {
"seconds": "秒",

View File

@ -165,7 +165,6 @@
"view_type": "Typ widoku",
"grid": "Siatka",
"collapse_all_notes": "Zwiń wszystkie notatki",
"expand_all_children": "Rozwiń wszystkie dzieci",
"collapse": "Zwiń",
"expand": "Rozwiń",
"book_properties": "Właściwości kolekcji",

View File

@ -739,7 +739,6 @@
"grid": "Grade",
"list": "Lista",
"collapse_all_notes": "Recolher todas as notas",
"expand_all_children": "Expandir todos os filhos",
"collapse": "Recolher",
"expand": "Expandir",
"book_properties": "Propriedades da Coleção",

View File

@ -1004,7 +1004,6 @@
"grid": "Grade",
"list": "Lista",
"collapse_all_notes": "Recolher todas as notas",
"expand_all_children": "Expandir todos os filhos",
"collapse": "Recolher",
"expand": "Expandir",
"book_properties": "Propriedades da Coleção",

View File

@ -279,7 +279,6 @@
"collapse": "Minimizează",
"collapse_all_notes": "Minimizează toate notițele",
"expand": "Expandează",
"expand_all_children": "Expandează toate subnotițele",
"grid": "Grilă",
"invalid_view_type": "Mod de afișare incorect „{{type}}”",
"list": "Listă",
@ -290,7 +289,11 @@
"geo-map": "Hartă geografică",
"board": "Tablă Kanban",
"include_archived_notes": "Afișează notițele arhivate",
"presentation": "Prezentare"
"presentation": "Prezentare",
"expand_tooltip": "Expandează subnotițele directe ale acestei colecții (un singur nivel de adâncime). Pentru mai multe opțiuni, apăsați săgeata din dreapta.",
"expand_first_level": "Expandează subnotițele directe",
"expand_nth_level": "Expandează pe {{depth}} nivele",
"expand_all_levels": "Expandează pe toate nivelele"
},
"bookmark_switch": {
"bookmark": "Semn de carte",
@ -384,7 +387,10 @@
"trilium_api_docs_button_title": "Deschide documentația API pentru Trilium"
},
"code_mime_types": {
"title": "Tipuri MIME disponibile în meniul derulant"
"title": "Tipuri MIME disponibile în meniul derulant",
"tooltip_syntax_highlighting": "Evidențiere de sintaxă",
"tooltip_code_block_syntax": "Blocuri de cod în notițe text",
"tooltip_code_note_syntax": "Notițe de tip cod"
},
"confirm": {
"also_delete_note": "Șterge și notița",
@ -1659,7 +1665,8 @@
"cut": "Decupează",
"paste": "Lipește",
"paste-as-plain-text": "Lipește doar textul",
"search_online": "Caută „{{term}}” cu {{searchEngine}}"
"search_online": "Caută „{{term}}” cu {{searchEngine}}",
"search_in_trilium": "Caută „{{term}}” în Trilium"
},
"image_context_menu": {
"copy_image_to_clipboard": "Copiază imaginea în clipboard",
@ -2096,7 +2103,7 @@
"calendar_view": {
"delete_note": "Șterge notița..."
},
"note-color": {
"note-color": {
"clear-color": "Înlăturați culoarea notiței",
"set-color": "Setați culoarea notiței",
"set-custom-color": "Setați culoare personalizată pentru notiță"

View File

@ -1013,7 +1013,6 @@
"book_properties": "Свойства коллекции",
"geo-map": "Карта",
"invalid_view_type": "Недопустимый тип представления '{{type}}'",
"expand_all_children": "Развернуть все дочерние элементы",
"collapse_all_notes": "Свернуть все заметки",
"include_archived_notes": "Показать заархивированные заметки"
},

View File

@ -761,7 +761,6 @@
"grid": "網格",
"list": "列表",
"collapse_all_notes": "收摺所有筆記",
"expand_all_children": "展開所有子項",
"collapse": "收摺",
"expand": "展開",
"invalid_view_type": "無效的查看類型 '{{type}}'",
@ -771,7 +770,11 @@
"geo-map": "地理地圖",
"board": "看板",
"include_archived_notes": "顯示已封存筆記",
"presentation": "簡報"
"presentation": "簡報",
"expand_tooltip": "展開此集合的直接子級(單層深度)。按下右側箭頭以查看更多選項。",
"expand_first_level": "展開直接子級",
"expand_nth_level": "展開 {{depth}} 層",
"expand_all_levels": "展開所有層級"
},
"edited_notes": {
"no_edited_notes_found": "今天還沒有編輯過的筆記...",
@ -1148,7 +1151,10 @@
"unit": "字元"
},
"code_mime_types": {
"title": "下拉選單可用的 MIME 文件類型"
"title": "下拉選單可用的 MIME 文件類型",
"tooltip_syntax_highlighting": "語法高亮顯示",
"tooltip_code_block_syntax": "文字筆記中的程式碼區塊",
"tooltip_code_note_syntax": "程式碼筆記"
},
"vim_key_bindings": {
"use_vim_keybindings_in_code_notes": "Vim 快捷鍵",
@ -1654,7 +1660,8 @@
"copy-link": "複製連結",
"paste": "貼上",
"paste-as-plain-text": "以純文字貼上",
"search_online": "用 {{searchEngine}} 搜尋 \"{{term}}\""
"search_online": "用 {{searchEngine}} 搜尋 \"{{term}}\"",
"search_in_trilium": "在 Trilium 中搜尋「{{term}}」"
},
"image_context_menu": {
"copy_reference_to_clipboard": "複製引用到剪貼簿",

View File

@ -867,7 +867,6 @@
"grid": "Сітка",
"list": "Список",
"collapse_all_notes": "Згорнути всі нотатки",
"expand_all_children": "Розгорнути всі дочірні",
"collapse": "Згорнути",
"expand": "Розгорнути",
"book_properties": "Властивості Колекції",

View File

@ -3,7 +3,7 @@ import server from "../../services/server.js";
import froca from "../../services/froca.js";
import linkService from "../../services/link.js";
import attributeAutocompleteService from "../../services/attribute_autocomplete.js";
import noteAutocompleteService from "../../services/note_autocomplete.js";
import noteAutocompleteService, { SuggestionMode } from "../../services/note_autocomplete.js";
import promotedAttributeDefinitionParser from "../../services/promoted_attribute_definition_parser.js";
import NoteContextAwareWidget from "../note_context_aware_widget.js";
import SpacedUpdate from "../../services/spaced_update.js";
@ -429,7 +429,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget {
this.$rowTargetNote = this.$widget.find(".attr-row-target-note");
this.$inputTargetNote = this.$widget.find(".attr-input-target-note");
noteAutocompleteService.initNoteAutocomplete(this.$inputTargetNote, { allowCreatingNotes: true }).on("autocomplete:noteselected", (event, suggestion, dataset) => {
noteAutocompleteService.initNoteAutocomplete(this.$inputTargetNote, { suggestionMode: SuggestionMode.SuggestCreateAndLink }).on("autocomplete:noteselected", (event, suggestion, dataset) => {
if (!suggestion.notePath) {
return false;
}

View File

@ -7,7 +7,7 @@ import branches from "../../../services/branches";
import { executeBulkActions } from "../../../services/bulk_action";
import froca from "../../../services/froca";
import { t } from "../../../services/i18n";
import note_create from "../../../services/note_create";
import note_create from "../../../services/note_create.js";
import server from "../../../services/server";
import { ColumnMap } from "./data";
@ -39,9 +39,11 @@ export default class BoardApi {
const parentNotePath = this.parentNote.noteId;
// Create a new note as a child of the parent note
const { note: newNote, branch: newBranch } = await note_create.createNote(parentNotePath, {
const { note: newNote, branch: newBranch } = await note_create.createNote({
target: "into",
parentNoteLink: parentNotePath,
activate: false,
title
title,
});
if (newNote && newBranch) {
@ -139,13 +141,17 @@ export default class BoardApi {
async insertRowAtPosition(
column: string,
relativeToBranchId: string,
direction: "before" | "after") {
const { note, branch } = await note_create.createNote(this.parentNote.noteId, {
activate: false,
targetBranchId: relativeToBranchId,
target: direction,
title: t("board_view.new-item")
});
direction: "before" | "after"
) {
const { note, branch } = await note_create.createNote(
{
target: direction,
parentNoteLink: this.parentNote.noteId,
activate: false,
targetBranchId: relativeToBranchId,
title: t("board_view.new-item"),
}
);
if (!note || !branch) {
throw new Error("Failed to create note");

View File

@ -57,12 +57,18 @@ export function openNoteContextMenu(api: Api, event: ContextMenuEvent, note: FNo
{
title: t("board_view.insert-above"),
uiIcon: "bx bx-list-plus",
handler: () => api.insertRowAtPosition(column, branchId, "before")
handler: () => api.insertRowAtPosition(
column,
branchId,
"before")
},
{
title: t("board_view.insert-below"),
uiIcon: "bx bx-empty",
handler: () => api.insertRowAtPosition(column, branchId, "after")
handler: () => api.insertRowAtPosition(
column,
branchId,
"after")
},
{ kind: "separator" },
{

View File

@ -15,6 +15,7 @@ import FormTextArea from "../../react/FormTextArea";
import FNote from "../../../entities/fnote";
import NoteAutocomplete from "../../react/NoteAutocomplete";
import toast from "../../../services/toast";
import { SuggestionMode } from "../../../services/note_autocomplete";
export interface BoardViewData {
columns?: BoardColumnData[];
@ -164,12 +165,12 @@ export default function BoardView({ note: parentNote, noteIds, viewConfig, saveC
onWheel={onWheelHorizontalScroll}
>
<BoardViewContext.Provider value={boardViewContext}>
<div
{byColumn && columns && <div
className="board-view-container"
onDragOver={handleColumnDragOver}
onDrop={handleContainerDrop}
>
{byColumn && columns?.map((column, index) => (
{columns.map((column, index) => (
<>
{columnDropPosition === index && (
<div className="column-drop-placeholder show" />
@ -191,7 +192,7 @@ export default function BoardView({ note: parentNote, noteIds, viewConfig, saveC
)}
<AddNewColumn api={api} isInRelationMode={isInRelationMode} />
</div>
</div>}
</BoardViewContext.Provider>
</div>
)
@ -298,7 +299,7 @@ export function TitleEditor({ currentValue, placeholder, save, dismiss, mode, is
noteId={currentValue ?? ""}
opts={{
hideAllButtons: true,
allowCreatingNotes: true
suggestionMode: SuggestionMode.SuggestCreateAndLink
}}
onKeyDown={(e) => {
if (e.key === "Escape") {

View File

@ -6,6 +6,7 @@ import Icon from "../../react/Icon.jsx";
import { useEffect, useRef, useState } from "preact/hooks";
import froca from "../../../services/froca.js";
import NoteAutocomplete from "../../react/NoteAutocomplete.jsx";
import { SuggestionMode } from "../../../services/note_autocomplete.js";
type ColumnType = LabelType | "relation";
@ -227,7 +228,7 @@ function RelationEditor({ cell, success }: EditorOpts) {
inputRef={inputRef}
noteId={cell.getValue()}
opts={{
allowCreatingNotes: true,
suggestionMode: SuggestionMode.SuggestCreateAndLink,
hideAllButtons: true
}}
noteIdChanged={success}

View File

@ -181,8 +181,8 @@ export function showRowContextMenu(parentComponent: Component, e: MouseEvent, ro
uiIcon: "bx bx-horizontal-left bx-rotate-90",
enabled: !sorters.length,
handler: () => parentComponent?.triggerCommand("addNewRow", {
parentNotePath: parentNoteId,
customOpts: {
parentNoteLink: parentNoteId,
target: "before",
targetBranchId: rowData.branchId,
}
@ -194,9 +194,12 @@ export function showRowContextMenu(parentComponent: Component, e: MouseEvent, ro
handler: async () => {
const branchId = row.getData().branchId;
const note = await froca.getBranch(branchId)?.getNote();
if (!note) {
return;
}
parentComponent?.triggerCommand("addNewRow", {
parentNotePath: note?.noteId,
customOpts: {
parentNoteLink: note.noteId,
target: "after",
targetBranchId: branchId,
}
@ -208,8 +211,8 @@ export function showRowContextMenu(parentComponent: Component, e: MouseEvent, ro
uiIcon: "bx bx-horizontal-left bx-rotate-270",
enabled: !sorters.length,
handler: () => parentComponent?.triggerCommand("addNewRow", {
parentNotePath: parentNoteId,
customOpts: {
parentNoteLink: parentNoteId,
target: "after",
targetBranchId: rowData.branchId,
}

View File

@ -1,6 +1,6 @@
import { EventCallBackMethods, RowComponent, Tabulator } from "tabulator-tables";
import { CommandListenerData } from "../../../components/app_context";
import note_create, { CreateNoteOpts } from "../../../services/note_create";
import note_create from "../../../services/note_create";
import { useLegacyImperativeHandlers } from "../../react/hooks";
import { RefObject } from "preact";
import { setAttribute, setLabel } from "../../../services/attributes";
@ -9,17 +9,23 @@ import server from "../../../services/server";
import branches from "../../../services/branches";
import AttributeDetailWidget from "../../attribute_widgets/attribute_detail";
/**
* Hook for handling row table editing, including adding new rows.
*/
export default function useRowTableEditing(api: RefObject<Tabulator>, attributeDetailWidget: AttributeDetailWidget, parentNotePath: string): Partial<EventCallBackMethods> {
// Adding new rows
useLegacyImperativeHandlers({
addNewRowCommand({ customOpts, parentNotePath: customNotePath }: CommandListenerData<"addNewRow">) {
const notePath = customNotePath ?? parentNotePath;
if (notePath) {
const opts: CreateNoteOpts = {
activate: false,
...customOpts
}
note_create.createNote(notePath, opts).then(({ branch }) => {
addNewRowCommand({ customOpts }: CommandListenerData<"addNewRow">) {
if (!customOpts) {
customOpts = {
target: "into",
};
}
const noteUrl = customOpts.parentNoteLink ?? parentNotePath;
if (noteUrl) {
customOpts.parentNoteLink = noteUrl;
customOpts.activate = false;
note_create.createNote(customOpts).then(({ branch }) => {
if (branch) {
setTimeout(() => {
if (!api.current) return;
@ -27,6 +33,7 @@ export default function useRowTableEditing(api: RefObject<Tabulator>, attributeD
}, 100);
}
})
}
}
});

View File

@ -5,7 +5,7 @@ import FormRadioGroup from "../react/FormRadioGroup";
import NoteAutocomplete from "../react/NoteAutocomplete";
import { useRef, useState, useEffect } from "preact/hooks";
import tree from "../../services/tree";
import note_autocomplete, { Suggestion } from "../../services/note_autocomplete";
import note_autocomplete, { SuggestionMode, Suggestion } from "../../services/note_autocomplete";
import { logError } from "../../services/ws";
import FormGroup from "../react/FormGroup.js";
import { refToJQuerySelector } from "../react/react_utils";
@ -58,7 +58,7 @@ export default function AddLinkDialog() {
}
if (suggestion.notePath) {
const noteId = tree.getNoteIdFromUrl(suggestion.notePath);
const noteId = tree.getNoteIdFromLink(suggestion.notePath);
if (noteId) {
setDefaultLinkTitle(noteId);
}
@ -133,7 +133,7 @@ export default function AddLinkDialog() {
onChange={setSuggestion}
opts={{
allowExternalLinks: true,
allowCreatingNotes: true
suggestionMode: SuggestionMode.SuggestCreateAndLink,
}}
/>
</FormGroup>

View File

@ -5,7 +5,7 @@ import FormRadioGroup from "../react/FormRadioGroup";
import Modal from "../react/Modal";
import NoteAutocomplete from "../react/NoteAutocomplete";
import Button from "../react/Button";
import { Suggestion, triggerRecentNotes } from "../../services/note_autocomplete";
import { SuggestionMode, Suggestion, triggerRecentNotes } from "../../services/note_autocomplete.js";
import tree from "../../services/tree";
import froca from "../../services/froca";
import { useTriliumEvent } from "../react/hooks";
@ -50,7 +50,7 @@ export default function IncludeNoteDialog() {
inputRef={autoCompleteRef}
opts={{
hideGoToSelectedNoteButton: true,
allowCreatingNotes: true
suggestionMode: SuggestionMode.SuggestCreateOnly,
}}
/>
</FormGroup>
@ -71,7 +71,7 @@ export default function IncludeNoteDialog() {
}
async function includeNote(notePath: string, editorApi: CKEditorApi, boxSize: BoxSize) {
const noteId = tree.getNoteIdFromUrl(notePath);
const noteId = tree.getNoteIdFromLink(notePath);
if (!noteId) {
return;
}

View File

@ -3,7 +3,7 @@ import Button from "../react/Button";
import NoteAutocomplete from "../react/NoteAutocomplete";
import { t } from "../../services/i18n";
import { useRef, useState } from "preact/hooks";
import note_autocomplete, { Suggestion } from "../../services/note_autocomplete";
import note_autocomplete, { SuggestionMode, Suggestion } from "../../services/note_autocomplete.js";
import appContext from "../../components/app_context";
import commandRegistry from "../../services/command_registry";
import { refToJQuerySelector } from "../react/react_utils";
@ -12,34 +12,53 @@ import shortcutService from "../../services/shortcuts";
const KEEP_LAST_SEARCH_FOR_X_SECONDS = 120;
type Mode = "last-search" | "recent-notes" | "commands";
enum Mode {
LastSearch,
RecentNotes,
Commands,
}
export default function JumpToNoteDialogComponent() {
const [ mode, setMode ] = useState<Mode>();
const [ lastOpenedTs, setLastOpenedTs ] = useState<number>(0);
const containerRef = useRef<HTMLDivElement>(null);
const autocompleteRef = useRef<HTMLInputElement>(null);
const [ isCommandMode, setIsCommandMode ] = useState(mode === "commands");
const [ isCommandMode, setIsCommandMode ] = useState(mode === Mode.Commands);
const [ initialText, setInitialText ] = useState(isCommandMode ? "> " : "");
const actualText = useRef<string>(initialText);
const [ shown, setShown ] = useState(false);
async function openDialog(commandMode: boolean) {
async function openDialog(requestedMode: Mode) {
let newMode: Mode;
let initialText = "";
if (commandMode) {
newMode = "commands";
initialText = ">";
} else if (Date.now() - lastOpenedTs <= KEEP_LAST_SEARCH_FOR_X_SECONDS * 1000 && actualText.current) {
// if you open the Jump To dialog soon after using it previously, it can often mean that you
// actually want to search for the same thing (e.g., you opened the wrong note at first try)
// so we'll keep the content.
// if it's outside of this time limit, then we assume it's a completely new search and show recent notes instead.
newMode = "last-search";
initialText = actualText.current;
} else {
newMode = "recent-notes";
switch (requestedMode) {
case Mode.Commands:
newMode = Mode.Commands;
initialText = ">";
break;
case Mode.LastSearch:
// if you open the Jump To dialog soon after using it previously, it can often mean that you
// actually want to search for the same thing (e.g., you opened the wrong note at first try)
// so we'll keep the content.
// if it's outside of this time limit, then we assume it's a completely new search and show recent notes instead.
if (Date.now() - lastOpenedTs <= KEEP_LAST_SEARCH_FOR_X_SECONDS * 1000 && actualText.current) {
newMode = Mode.LastSearch;
initialText = actualText.current;
} else {
newMode = Mode.RecentNotes;
}
break;
default:
if (Date.now() - lastOpenedTs <= KEEP_LAST_SEARCH_FOR_X_SECONDS * 1000 && actualText.current) {
newMode = Mode.LastSearch;
initialText = actualText.current;
} else {
newMode = Mode.RecentNotes;
}
break;
}
if (mode !== newMode) {
@ -51,14 +70,14 @@ export default function JumpToNoteDialogComponent() {
setLastOpenedTs(Date.now());
}
useTriliumEvent("jumpToNote", () => openDialog(false));
useTriliumEvent("commandPalette", () => openDialog(true));
useTriliumEvent("jumpToNote", () => openDialog(Mode.RecentNotes));
useTriliumEvent("commandPalette", () => openDialog(Mode.Commands));
async function onItemSelected(suggestion?: Suggestion | null) {
if (!suggestion) {
return;
}
setShown(false);
if (suggestion.notePath) {
appContext.tabManager.getActiveContext()?.setNote(suggestion.notePath);
@ -70,12 +89,12 @@ export default function JumpToNoteDialogComponent() {
function onShown() {
const $autoComplete = refToJQuerySelector(autocompleteRef);
switch (mode) {
case "last-search":
case Mode.LastSearch:
break;
case "recent-notes":
case Mode.RecentNotes:
note_autocomplete.showRecentNotes($autoComplete);
break;
case "commands":
case Mode.Commands:
note_autocomplete.showAllCommands($autoComplete);
break;
}
@ -83,7 +102,7 @@ export default function JumpToNoteDialogComponent() {
$autoComplete
.trigger("focus")
.trigger("select");
// Add keyboard shortcut for full search
shortcutService.bindElShortcut($autoComplete, "ctrl+return", () => {
if (!isCommandMode) {
@ -91,7 +110,7 @@ export default function JumpToNoteDialogComponent() {
}
});
}
async function showInFullSearch() {
try {
setShown(false);
@ -116,7 +135,7 @@ export default function JumpToNoteDialogComponent() {
container={containerRef}
text={initialText}
opts={{
allowCreatingNotes: true,
suggestionMode: SuggestionMode.SuggestCreateOnly,
hideGoToSelectedNoteButton: true,
allowJumpToSearchNotes: true,
isCommandPalette: true
@ -129,9 +148,9 @@ export default function JumpToNoteDialogComponent() {
/>}
onShown={onShown}
onHidden={() => setShown(false)}
footer={!isCommandMode && <Button
className="show-in-full-text-button"
text={t("jump_to_note.search_button")}
footer={!isCommandMode && <Button
className="show-in-full-text-button"
text={t("jump_to_note.search_button")}
keyboardShortcut="Ctrl+Enter"
onClick={showInFullSearch}
/>}

View File

@ -7,7 +7,7 @@ import { useEffect, useState } from "preact/hooks";
import note_types from "../../services/note_types";
import { MenuCommandItem, MenuItem } from "../../menus/context_menu";
import { TreeCommandNames } from "../../menus/tree_context_menu";
import { Suggestion } from "../../services/note_autocomplete";
import { SuggestionMode, Suggestion } from "../../services/note_autocomplete.js";
import Badge from "../react/Badge";
import { useTriliumEvent } from "../react/hooks";
@ -76,6 +76,7 @@ export default function NoteTypeChooserDialogComponent() {
onHidden={() => {
callback?.({ success: false });
setShown(false);
setParentNote(null);
}}
show={shown}
stackable
@ -85,7 +86,7 @@ export default function NoteTypeChooserDialogComponent() {
onChange={setParentNote}
placeholder={t("note_type_chooser.search_placeholder")}
opts={{
allowCreatingNotes: false,
suggestionMode: SuggestionMode.SuggestNothing,
hideGoToSelectedNoteButton: true,
allowJumpToSearchNotes: false,
}}

View File

@ -5,7 +5,7 @@ import BasicWidget from "../basic_widget.js";
import toastService from "../../services/toast.js";
import appContext from "../../components/app_context.js";
import server from "../../services/server.js";
import noteAutocompleteService from "../../services/note_autocomplete.js";
import noteAutocompleteService, { SuggestionMode } from "../../services/note_autocomplete.js";
import { TPL, addMessageToChat, showSources, hideSources, showLoadingIndicator, hideLoadingIndicator } from "./ui.js";
import { formatMarkdown } from "./utils.js";
@ -163,7 +163,7 @@ export default class LlmChatPanel extends BasicWidget {
const mentionSetup: MentionFeed[] = [
{
marker: "@",
feed: (queryText: string) => noteAutocompleteService.autocompleteSourceForCKEditor(queryText),
feed: (queryText: string) => noteAutocompleteService.autocompleteSourceForCKEditor(queryText, SuggestionMode.SuggestCreateAndLink),
itemRenderer: (item) => {
const suggestion = item as Suggestion;
const itemElement = document.createElement("button");

View File

@ -29,7 +29,14 @@ export default function MobileDetailMenu() {
],
selectMenuItemHandler: async ({ command }) => {
if (command === "insertChildNote") {
note_create.createNote(appContext.tabManager.getActiveContextNotePath() ?? undefined);
const parentNoteUrl = appContext.tabManager.getActiveContextNotePath();
if (parentNoteUrl) {
note_create.createNote({
target: "into",
parentNoteLink: parentNoteUrl,
});
}
} else if (command === "delete") {
const notePath = appContext.tabManager.getActiveContextNotePath();
if (!notePath) {

View File

@ -224,7 +224,13 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
} else if (target.classList.contains("add-note-button")) {
const node = $.ui.fancytree.getNode(e as unknown as Event);
const parentNotePath = treeService.getNotePath(node);
noteCreateService.createNote(parentNotePath, { isProtected: node.data.isProtected });
noteCreateService.createNote(
{
target: "into",
parentNoteLink: parentNotePath,
isProtected: node.data.isProtected
},
);
} else if (target.classList.contains("enter-workspace-button")) {
const node = $.ui.fancytree.getNode(e as unknown as Event);
this.triggerCommand("hoistNote", { noteId: node.data.noteId });
@ -508,7 +514,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
(data.hitMode === "over" && node.data.noteType === "search") ||
(["after", "before"].includes(data.hitMode) && (node.data.noteId === hoistedNoteService.getHoistedNoteId() || node.getParent().data.noteType === "search"))
) {
await dialogService.info("Dropping notes into this location is not allowed.");
await dialogService.info(t("note_tree.dropping-not-allowed"));
return;
}
@ -1403,10 +1409,10 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
let node: Fancytree.FancytreeNode | null | undefined = await this.expandToNote(activeNotePath, false);
if (node && node.data.noteId !== treeService.getNoteIdFromUrl(activeNotePath)) {
if (node && node.data.noteId !== treeService.getNoteIdFromLink(activeNotePath)) {
// if the active note has been moved elsewhere then it won't be found by the path,
// so we switch to the alternative of trying to find it by noteId
const noteId = treeService.getNoteIdFromUrl(activeNotePath);
const noteId = treeService.getNoteIdFromLink(activeNotePath);
if (noteId) {
const notesById = this.getNodesByNoteId(noteId);
@ -1836,9 +1842,13 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
const node = this.getActiveNode();
if (!node) return;
const notePath = treeService.getNotePath(node);
noteCreateService.createNote(notePath, {
isProtected: node.data.isProtected
});
noteCreateService.createNote(
{
target: "into",
parentNoteLink: notePath,
isProtected: node.data.isProtected
}
)
}
}),
new TouchBar.TouchBarButton({

View File

@ -2,7 +2,7 @@ import { MutableRef, useEffect, useImperativeHandle, useMemo, useRef, useState }
import { AttributeEditor as CKEditorAttributeEditor, MentionFeed, ModelElement, ModelNode, ModelPosition } from "@triliumnext/ckeditor5";
import { t } from "../../../services/i18n";
import server from "../../../services/server";
import note_autocomplete, { Suggestion } from "../../../services/note_autocomplete";
import note_autocomplete, { SuggestionMode, Suggestion } from "../../../services/note_autocomplete.js";
import CKEditor, { CKEditorApi } from "../../react/CKEditor";
import { useLegacyImperativeHandlers, useLegacyWidget, useTooltip, useTriliumEvent, useTriliumOption } from "../../react/hooks";
import FAttribute from "../../../entities/fattribute";
@ -20,6 +20,7 @@ import type { CommandData, FilteredCommandNames } from "../../../components/app_
import { AttributeType } from "@triliumnext/commons";
import attributes from "../../../services/attributes";
import note_create from "../../../services/note_create";
import { CreateNoteAction } from "@triliumnext/commons";
type AttributeCommandNames = FilteredCommandNames<CommandData>;
@ -33,7 +34,7 @@ const HELP_TEXT = `
const mentionSetup: MentionFeed[] = [
{
marker: "@",
feed: (queryText) => note_autocomplete.autocompleteSourceForCKEditor(queryText),
feed: (queryText) => note_autocomplete.autocompleteSourceForCKEditor(queryText, SuggestionMode.SuggestCreateAndLink),
itemRenderer: (_item) => {
const item = _item as Suggestion;
const itemElement = document.createElement("button");
@ -247,16 +248,18 @@ export default function AttributeEditor({ api, note, componentId, notePath, ntxI
$el.text(title);
},
createNoteForReferenceLink: async (title: string) => {
let result;
if (notePath) {
result = await note_create.createNoteWithTypePrompt(notePath, {
activate: false,
title: title
});
}
return result?.note?.getBestNotePathString();
createNoteFromCkEditor: async (
title: string,
parentNotePath: string | undefined,
action: CreateNoteAction
): Promise<string> => {
const { note } = await note_create.createNoteFromAction(
action,
true,
title,
parentNotePath,
);
return note?.getBestNotePathString() ?? "";
}
}), [ notePath ]));

View File

@ -4,7 +4,7 @@ import FormGroup from "../react/FormGroup";
import NoteAutocomplete from "../react/NoteAutocomplete";
import "./Empty.css";
import { ParentComponent, refToJQuerySelector } from "../react/react_utils";
import note_autocomplete from "../../services/note_autocomplete";
import note_autocomplete, { SuggestionMode } from "../../services/note_autocomplete";
import appContext from "../../components/app_context";
import FNote from "../../entities/fnote";
import search from "../../services/search";
@ -38,7 +38,7 @@ function NoteSearch() {
inputRef={autocompleteRef}
opts={{
hideGoToSelectedNoteButton: true,
allowCreatingNotes: true,
suggestionMode: SuggestionMode.SuggestCreateOnly,
allowJumpToSearchNotes: true,
}}
onChange={suggestion => {

View File

@ -16,7 +16,8 @@ import note_create from "../../../services/note_create";
import TouchBar, { TouchBarButton, TouchBarGroup, TouchBarSegmentedControl } from "../../react/TouchBar";
import { RefObject } from "preact";
import { buildSelectedBackgroundColor } from "../../../components/touch_bar";
import { deferred } from "@triliumnext/commons";
import { CreateNoteAction, deferred } from "@triliumnext/commons";
import { t } from "../../../services/i18n";
/**
* The editor can operate into two distinct modes:
@ -106,17 +107,18 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
},
loadIncludedNote,
// Creating notes in @-completion
async createNoteForReferenceLink(title: string) {
const notePath = noteContext?.notePath;
if (!notePath) return;
const resp = await note_create.createNoteWithTypePrompt(notePath, {
activate: false,
title: title
});
if (!resp || !resp.note) return;
return resp.note.getBestNotePathString();
async createNoteFromCkEditor (
title: string,
parentNotePath: string | undefined,
action: CreateNoteAction
): Promise<string> {
const { note }= await note_create.createNoteFromAction(
action,
true,
title,
parentNotePath,
)
return note?.getBestNotePathString() ?? "";
},
// Keyboard shortcut
async followLinkUnderCursorCommand() {
@ -153,7 +155,9 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
// without await as this otherwise causes deadlock through component mutex
const parentNotePath = appContext.tabManager.getActiveContextNotePath();
if (noteContext && parentNotePath) {
note_create.createNote(parentNotePath, {
note_create.createNote({
parentNoteLink: parentNotePath,
target: "into",
isProtected: note.isProtected,
saveSelection: true,
textEditor: await noteContext?.getTextEditor()
@ -279,7 +283,7 @@ function onWatchdogStateChange(watchdog: EditorWatchdog) {
logError(`CKEditor crash logs: ${JSON.stringify(watchdog.crashes, null, 4)}`);
if (currentState === "crashedPermanently") {
dialog.info(`Editing component keeps crashing. Please try restarting Trilium. If problem persists, consider creating a bug report.`);
dialog.info(t("editable-text.keeps-crashing"));
watchdog.editor?.enableReadOnlyMode("crashed-editor");
}
}

View File

@ -7,7 +7,7 @@ import emojiDefinitionsUrl from "@triliumnext/ckeditor5/src/emoji_definitions/en
import { copyTextWithToast } from "../../../services/clipboard_ext.js";
import { t } from "../../../services/i18n.js";
import { getMermaidConfig } from "../../../services/mermaid.js";
import noteAutocompleteService, { type Suggestion } from "../../../services/note_autocomplete.js";
import noteAutocompleteService, { SuggestionMode, type Suggestion } from "../../../services/note_autocomplete.js";
import mimeTypesService from "../../../services/mime_types.js";
import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons";
import { buildToolbarConfig } from "./toolbar.js";
@ -181,7 +181,7 @@ export async function buildConfig(opts: BuildEditorOptions): Promise<EditorConfi
feeds: [
{
marker: "@",
feed: (queryText: string) => noteAutocompleteService.autocompleteSourceForCKEditor(queryText),
feed: (queryText: string) => noteAutocompleteService.autocompleteSourceForCKEditor(queryText, SuggestionMode.SuggestCreateAndLink),
itemRenderer: (item) => {
const itemElement = document.createElement("button");

View File

@ -35,7 +35,7 @@
"@triliumnext/commons": "workspace:*",
"@triliumnext/server": "workspace:*",
"copy-webpack-plugin": "13.0.1",
"electron": "38.7.1",
"electron": "38.7.2",
"@electron-forge/cli": "7.10.2",
"@electron-forge/maker-deb": "7.10.2",
"@electron-forge/maker-dmg": "7.10.2",

View File

@ -12,7 +12,7 @@
"@triliumnext/desktop": "workspace:*",
"@types/fs-extra": "11.0.4",
"copy-webpack-plugin": "13.0.1",
"electron": "38.7.1",
"electron": "38.7.2",
"fs-extra": "11.3.2"
},
"scripts": {

View File

@ -8,6 +8,7 @@ interface GotoOpts {
}
const BASE_URL = "http://127.0.0.1:8082";
const NUM_OF_CREATE_NOTE_OPTIONS = 2;
interface DropdownLocator extends Locator {
selectOptionByText: (text: string) => Promise<void>;
@ -73,7 +74,8 @@ export default class App {
const resultsSelector = this.currentNoteSplit.locator(".note-detail-empty-results");
await expect(resultsSelector).toContainText(noteTitle);
await resultsSelector.locator(".aa-suggestion", { hasText: noteTitle })
.nth(1) // Select the second one, as the first one is "Create a new note"
// Select the n+1 one, as the first one is "Create a new note"
.nth(NUM_OF_CREATE_NOTE_OPTIONS)
.click();
}

View File

@ -80,7 +80,7 @@
"debounce": "3.0.0",
"debug": "4.4.3",
"ejs": "3.1.10",
"electron": "38.7.1",
"electron": "38.7.2",
"electron-debug": "4.1.0",
"electron-window-state": "5.0.3",
"escape-html": "1.0.3",

View File

@ -5,69 +5,50 @@
Keyboard shortcuts. Using <code>global:</code> prefix, you can assign a shortcut
which will work even without Trilium being in focus (requires app restart
to take effect).</p>
<h2>Tree</h2>
<p>See the corresponding section:&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/Vc8PjrjAGuOp/oPVyFC7WL2Lp/_help_DvdZhoQZY9Yd">Keyboard shortcuts</a>
</p>
<h2>Note navigation</h2>
<ul>
<li><kbd><span></span></kbd>, <kbd><span></span></kbd> - go up/down in the
list of notes, <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd><span></span></kbd> and <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd><span></span></kbd> &nbsp;work
also from editor</li>
<li><kbd><span></span></kbd>, <kbd><span></span></kbd> - collapse/expand node</li>
<li><kbd>Alt</kbd> + <kbd><span></span></kbd>, <kbd>Alt</kbd> + <kbd><span></span></kbd> -
<li data-list-item-id="ed8fd9c2ab08ae80ea76c1ae5dc943e90"><kbd>Alt</kbd> + <kbd><span></span></kbd>, <kbd>Alt</kbd> + <kbd><span></span></kbd>
go back / forwards in the history</li>
<li><kbd>Ctrl</kbd> + <kbd>J</kbd> - show <a href="#root/_help_MMiBEQljMQh2">"Jump to" dialog</a>
<li data-list-item-id="eff3c5760b3d985e7808f1524982fcb9b"><kbd>Ctrl</kbd> + <kbd>J</kbd> show <a href="#root/_help_MMiBEQljMQh2">"Jump to" dialog</a>
</li>
<li><kbd>Ctrl</kbd> + <kbd>.</kbd> - scroll to current note (useful when you
<li data-list-item-id="e1fdee08a424868922b0579e78584279c"><kbd>Ctrl</kbd> + <kbd>.</kbd> scroll to current note (useful when you
scroll away from your note or your focus is currently in the editor)</li>
<li><kbd><span>Backspace</span></kbd> - jumps to parent note</li>
<li><kbd>Alt</kbd> + <kbd>C</kbd> - collapse whole note tree</li>
<li><kbd>Alt</kbd> + <kbd>-</kbd> (alt with minus sign) - collapse subtree (if
some subtree takes too much space on tree pane you can collapse it)</li>
<li>you can define a <a href="#root/_help_zEY4DaJG4YT5">label</a> <code>#keyboardShortcut</code> with
e.g. value <kbd>Ctrl</kbd> + <kbd>I</kbd> . Pressing this keyboard combination
will then bring you to the note on which it is defined. Note that Trilium
must be reloaded/restarted (<kbd>Ctrl</kbd> + <kbd>R</kbd> ) for changes to
be in effect.</li>
<li
data-list-item-id="e9bbc51f19a729c10997010a915779d07"><kbd><span>Backspace</span></kbd> jumps to parent note</li>
<li data-list-item-id="eaaa0f36b2e561d4a24358552e633d924"><kbd>Alt</kbd> + <kbd>C</kbd> collapse whole note tree</li>
<li data-list-item-id="ee625a141f5298dbd52ecb6e56693e647"><kbd>Alt</kbd> + <kbd>-</kbd> (alt with minus sign) collapse subtree (if
some subtree takes too much space on tree pane you can collapse it)</li>
<li
data-list-item-id="ec1bf00840a017ea798880470e419f3d9">you can define a <a href="#root/_help_zEY4DaJG4YT5">label</a> <code>#keyboardShortcut</code> with
e.g. value <kbd>Ctrl</kbd> + <kbd>I</kbd> . Pressing this keyboard combination
will then bring you to the note on which it is defined. Note that Trilium
must be reloaded/restarted (<kbd>Ctrl</kbd> + <kbd>R</kbd> ) for changes to
be in effect.</li>
</ul>
<p>See demo of some of these features in <a href="#root/_help_MMiBEQljMQh2">note navigation</a>.</p>
<h2>Tabs</h2>
<ul>
<li><kbd>Ctrl</kbd> + <kbd>🖱 Left click</kbd> - (or middle mouse click) on note
<li data-list-item-id="e6a9d460427c0394177000c8a0eecfca4"><kbd>Ctrl</kbd> + <kbd>🖱 Left click</kbd> (or middle mouse click) on note
link opens note in a new tab</li>
</ul>
<p>Only in desktop (electron build):</p>
<ul>
<li><kbd>Ctrl</kbd> + <kbd>T</kbd> - opens empty tab</li>
<li><kbd>Ctrl</kbd> + <kbd>W</kbd> - closes active tab</li>
<li><kbd>Ctrl</kbd> + <kbd>Tab</kbd> - activates next tab</li>
<li><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Tab</kbd> - activates previous tab</li>
<li data-list-item-id="e745e6690db1a4bee718faa94b272013e"><kbd>Ctrl</kbd> + <kbd>T</kbd> opens empty tab</li>
<li data-list-item-id="ec34c224c2c0dd74367753a6aff4f9721"><kbd>Ctrl</kbd> + <kbd>W</kbd> closes active tab</li>
<li data-list-item-id="e4b9a2163cccc3ab7dbdcf6fb7f149315"><kbd>Ctrl</kbd> + <kbd>Tab</kbd> activates next tab</li>
<li data-list-item-id="eeeabd750227ec42c30b282b9b8ab5c8d"><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Tab</kbd> activates previous tab</li>
</ul>
<h2>Creating notes</h2>
<ul>
<li><code>CTRL+O</code> - creates new note after the current note</li>
<li><code>CTRL+P</code> - creates new sub-note into current note</li>
<li><code>F2</code> - edit <a href="#root/_help_MMiBEQljMQh2">prefix</a> of current
note clone</li>
</ul>
<h2>Moving / cloning notes</h2>
<ul>
<li><kbd>Ctrl</kbd> + <kbd><span></span></kbd> , Ctrl + <kbd><span></span></kbd> -
move note up/down in the note list</li>
<li><kbd>Ctrl</kbd> + <kbd><span></span></kbd> - move note up in the note tree</li>
<li><kbd>Ctrl</kbd>+<kbd><span></span></kbd> - move note down in the note
tree</li>
<li><kbd>Shift</kbd>+<kbd><span></span></kbd>, <kbd>Shift</kbd><code>+</code><kbd><span></span></kbd> -
multi-select note above/below</li>
<li><kbd>Ctrl</kbd>+<kbd>A</kbd> - select all notes in the current level</li>
<li><kbd>Shift</kbd>+<kbd>🖱 Left click</kbd> - multi select note which you
clicked on</li>
<li><kbd>Ctrl</kbd>+<kbd>C</kbd> - copies current note (or current selection)
into clipboard (used for <a href="#root/_help_IakOLONlIfGI">cloning</a>
</li>
<li><kbd>Ctrl</kbd>+<kbd>X</kbd> - cuts current (or current selection) note
into clipboard (used for moving notes)</li>
<li><kbd>Ctrl</kbd>+<kbd>V</kbd> - pastes note(s) as sub-note into current
note (which is either move or clone depending on whether it was copied
or cut into clipboard)</li>
<li><kbd>Del</kbd> - delete note / sub-tree</li>
<li data-list-item-id="e90a7441e67297c921f8bb2145829dd55"><kbd>CTRL</kbd>+<kbd>O</kbd> creates new note after the current note</li>
<li
data-list-item-id="e6064f6dd7b09083448cfb52247c94baa"><kbd>CTRL</kbd>+<kbd>P</kbd> creates new sub-note into current note</li>
<li
data-list-item-id="e191cb0e7231c4439632d70da65dcf800"><kbd>F2</kbd> edit&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/BFs8mudNFgCS/IakOLONlIfGI/_help_TBwsyfadTA18">Branch prefix</a>&nbsp;of
current note clone</li>
</ul>
<h2>Editing notes</h2>
<aside class="admonition note">
@ -77,30 +58,32 @@
class="reference-link" href="#root/_help_QrtTYPmdd1qq">Markdown-like formatting</a>.</p>
</aside>
<ul>
<li><kbd>Enter</kbd> in tree pane switches from tree pane into note title.
<li data-list-item-id="eea3611b470b2482ccf07e8844e4f66b9"><kbd>Enter</kbd> in tree pane switches from tree pane into note title.
Enter from note title switches focus to text editor. <kbd>Ctrl</kbd>+<kbd>.</kbd> switches
back from editor to tree pane.</li>
<li><kbd>Ctrl</kbd>+<kbd>.</kbd> - jump away from the editor to tree pane and
<li data-list-item-id="e5dab831910ac694ccef7bc474b2e67fc"><kbd>Ctrl</kbd>+<kbd>.</kbd> jump away from the editor to tree pane and
scroll to current note</li>
</ul>
<h2>Runtime shortcuts</h2>
<p>These are hooked in Electron to be similar to native browser keyboard
shortcuts.</p>
<ul>
<li><kbd>F5</kbd>, <kbd>Ctrl</kbd>-<kbd>R</kbd> - reloads Trilium front-end</li>
<li><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>I</kbd> - show developer tools</li>
<li><kbd>Ctrl</kbd>+<kbd>F</kbd> - show search dialog</li>
<li><kbd>Ctrl</kbd>+<kbd>-</kbd> - zoom out</li>
<li><kbd>Ctrl</kbd>+<kbd>=</kbd> - zoom in</li>
<li data-list-item-id="e1a17ce297e78109362180536b7eabd68"><kbd>F5</kbd>, <kbd>Ctrl</kbd>+<kbd>R</kbd> reloads Trilium front-end</li>
<li
data-list-item-id="e07d1b25dc46ce0b0bd76a8db13373198"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>I</kbd> show developer tools</li>
<li
data-list-item-id="e7dc66078ba520c48364952f2ac48aa79"><kbd>Ctrl</kbd>+<kbd>F</kbd> show search dialog</li>
<li data-list-item-id="e63161bd165a51e19fd04dd1223173e68"><kbd>Ctrl</kbd>+<kbd>-</kbd> zoom out</li>
<li data-list-item-id="e961144d0a57b51792830a2182459c8cf"><kbd>Ctrl</kbd>+<kbd>=</kbd> zoom in</li>
</ul>
<h2>Other</h2>
<ul>
<li><kbd>Alt</kbd>+<kbd>O</kbd> - show SQL console (use only if you know what
<li data-list-item-id="eb007c4ea2f2cd6eefbc8972d538c724c"><kbd>Alt</kbd> + <kbd>O</kbd> show SQL console (use only if you know what
you're doing)</li>
<li><kbd>Alt</kbd>+<kbd>M</kbd> - distraction-free mode - display only note
<li data-list-item-id="e9caedb43e6c66fc7c57b4899bd6d5d76"><kbd>Alt</kbd> + <kbd>M</kbd> distraction-free mode - display only note
editor, everything else is hidden</li>
<li><kbd>F11</kbd> - toggle full screen</li>
<li><kbd>Ctrl</kbd> + <kbd>S</kbd> - toggle <a href="#root/_help_eIg8jdvaoNNd">search</a> form
<li data-list-item-id="ec55bd0e5ff7da0c488a5378c0bdabed5"><kbd>F11</kbd> toggle full screen</li>
<li data-list-item-id="e8d4ec0d76155371de5d060ad661cb19e"><kbd>Ctrl</kbd> + <kbd>S</kbd> toggle <a href="#root/_help_eIg8jdvaoNNd">search</a> form
in tree pane</li>
<li><kbd>Alt</kbd> +<kbd>A</kbd> - show note <a href="#root/_help_zEY4DaJG4YT5">attributes</a> dialog</li>
<li data-list-item-id="eb938081f527f44b158be7c3ed4af4925"><kbd>Alt</kbd> +<kbd>A</kbd> show note <a href="#root/_help_zEY4DaJG4YT5">attributes</a> dialog</li>
</ul>

View File

@ -1,33 +1,53 @@
<p>The&nbsp;<a class="reference-link" href="#root/_help_oPVyFC7WL2Lp">Note Tree</a>&nbsp;comes
with multiple keyboard shortcuts to make editing faster:</p>
<h2>Navigation within the tree</h2>
<ul>
<li>Opening notes:
<ul>
<li><kbd>Click</kbd> to open the note in the current tab.</li>
<li><kbd>Ctrl</kbd>+<kbd>Click</kbd> or <kbd>Middle click</kbd> to open the note
in a new tab.</li>
<li><kbd>Ctrl</kbd>+<kbd>Right click</kbd> to open the note in&nbsp;<a class="reference-link"
href="#root/_help_ZjLYv08Rp3qC">Quick edit</a>.</li>
</ul>
</li>
<li>Navigation within the tree:
<ul>
<li><kbd>Up</kbd> and <kbd>Down</kbd> to navigate between notes.</li>
<li><kbd>Left</kbd> to collapse a note, or <kbd>Right</kbd> to expand it.</li>
</ul>
</li>
<li>Clipboard management:
<ul>
<li><kbd>Ctrl</kbd>+<kbd>C</kbd> to copy a note.</li>
<li><kbd>Ctrl</kbd>+<kbd>X</kbd> to cut a note.</li>
<li><kbd>Ctrl</kbd>+<kbd>V</kbd> to paste it somewhere.</li>
</ul>
</li>
<li>For&nbsp;<a class="reference-link" href="#root/_help_yTjUdsOi4CIE">Multiple selection</a>:
<ul>
<li><kbd>Alt</kbd>+<kbd>Click</kbd>to add a single note to the current selection.</li>
<li><kbd>Shift</kbd>+<kbd>Click</kbd>to select a range of notes, starting
from the current note (the highlighted one) to the one that is being clicked.</li>
</ul>
</li>
<li data-list-item-id="eede1a5721dab5213153c6bb25bad38c9"><kbd><span></span></kbd> and <kbd><span></span></kbd> to navigate between
notes.</li>
<li data-list-item-id="ec4c4ab60720b34a95f73e93223ed3628"><kbd><span></span></kbd> to collapse a note with children, or <kbd><span></span></kbd> to
expand it.</li>
<li data-list-item-id="eb5ad59d78e70611d0233ffbb5ede3b96"><kbd><span></span></kbd> on a note with no children to navigate to its
parent.</li>
</ul>
<h2>Opening notes</h2>
<ul>
<li data-list-item-id="e3d92e8c3a1e5b9d6f2efe5067004ef5c"><kbd>Click</kbd> to open the note in the current tab.</li>
<li data-list-item-id="e8ae44ff429a0da1d529c627874f54908"><kbd>Ctrl</kbd>+<kbd>Click</kbd> or <kbd>Middle click</kbd> to open the note
in a new tab.</li>
<li data-list-item-id="e183b1a014e2bd563450dac0c8913c6f0"><kbd>Ctrl</kbd>+<kbd>Right click</kbd> to open the note in&nbsp;<a class="reference-link"
href="#root/_help_ZjLYv08Rp3qC">Quick edit</a>.</li>
</ul>
<h2>Clipboard management</h2>
<ul>
<li data-list-item-id="e28fb424bcc0d06b97ddcbcbc5145c350"><kbd>Ctrl</kbd>+<kbd>C</kbd> to copy one or more notes based on selection
(see&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/BFs8mudNFgCS/_help_IakOLONlIfGI">Cloning Notes</a>).</li>
<li
data-list-item-id="e11c4c9fcdfeb566a58d9319a340ff893"><kbd>Ctrl</kbd>+<kbd>X</kbd> to cut one or more notes (for moving them).</li>
<li
data-list-item-id="e242519cf16b3414242c4d11f20688b5b"><kbd>Ctrl</kbd>+<kbd>V</kbd> to paste them somewhere (which results in
a copy or move based on the shortcut used).</li>
</ul>
<h2>Moving notes</h2>
<ul>
<li data-list-item-id="ee2d0e5633e0ab23d0fcde7b968731794"><kbd>Ctrl</kbd> + <kbd><span></span></kbd> , <kbd>Ctrl</kbd> + <kbd><span></span></kbd> -
move note up/down in the note list.</li>
<li data-list-item-id="e14146e7aacfc92aa7daf8215ce4b379c"><kbd>Ctrl</kbd> + <kbd><span></span></kbd> - move note up in the note tree.</li>
<li
data-list-item-id="e21a7f5ab9d62af04b6ab81b0cc4cf8c7"><kbd>Ctrl</kbd>+<kbd><span></span></kbd> - move note down in the note
tree.</li>
<li data-list-item-id="e99f4b0aef9693ad25ca0ce62c5b67418"><kbd>Del</kbd> - deletes note and optionally its subtree (asked in the
dialog).</li>
</ul>
<h2>Multiple selection</h2>
<p>See&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/Vc8PjrjAGuOp/oPVyFC7WL2Lp/_help_yTjUdsOi4CIE">Multiple selection</a>&nbsp;for
more information about how selection works.</p>
<ul>
<li data-list-item-id="ebe4907d702229ab599e50f753d23cfb6"><kbd>Alt</kbd>+<kbd>Click</kbd> add a single note to the current selection.</li>
<li
data-list-item-id="ecf6bb49f8d993d376382dcab4e4a7ee8"><kbd>Shift</kbd>+<kbd>Click</kbd> select a range of notes, starting from
the current note (the highlighted one) to the one that is being clicked.</li>
<li
data-list-item-id="eb1398c2cf85b53eafc3b7ab7a0974668"><kbd>Shift</kbd>+<kbd><span></span></kbd>, <kbd>Shift</kbd>+<kbd><span></span></kbd>
multi-select not above/below.</li>
<li data-list-item-id="ebc1274f576f67d08a6d665a7318d80a8"><kbd>Ctrl</kbd>+<kbd>A</kbd> select all notes in the current level</li>
</ul>

View File

@ -12,9 +12,9 @@
as a single continuous document.</p>
<h2>Interaction</h2>
<ul>
<li data-list-item-id="e8a9709d9f325dab560cb24289d5ab231">Each note can be expanded or collapsed by clicking on the arrow to the
<li>Each note can be expanded or collapsed by clicking on the arrow to the
left of the title.</li>
<li data-list-item-id="e38647a2388fb38e1c6de17b617db9e76">In the&nbsp;<a class="reference-link" href="#root/_help_BlN9DFI679QC">Ribbon</a>,
<li>In the&nbsp;<a class="reference-link" href="#root/_help_BlN9DFI679QC">Ribbon</a>,
in the <em>Collection</em> tab there are options to expand and to collapse
all notes easily.</li>
</ul>
@ -25,16 +25,15 @@
<p>If exported to PDF within the desktop application, there is additional
functionality:</p>
<ul>
<li data-list-item-id="e06095ff0a3876a29bdc11f1a2f18dfdc">The table of contents of the PDF will reflect the structure of the notes.</li>
<li
data-list-item-id="e656526a5aa019d58af324ae5c3d39216">Reference and inline links to other notes within the same hierarchy will
<li>The table of contents of the PDF will reflect the structure of the notes.</li>
<li>Reference and inline links to other notes within the same hierarchy will
be functional (will jump to the corresponding page). If a link refers to
a note that is not in the printed hierarchy, it will be unlinked.</li>
</ul>
<h2>Expanding and collapsing multiple notes at once</h2>
<p>Apart from individually expanding or collapsing notes, it's also possible
to expand or collapse them all at once. To do so, go to the <em>Collection Properties</em> tab
in the&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/Vc8PjrjAGuOp/_help_BlN9DFI679QC">Ribbon</a>&nbsp;and
in the&nbsp;<a class="reference-link" href="#root/_help_BlN9DFI679QC">Ribbon</a>&nbsp;and
look for the corresponding button.</p>
<p>By default, the <em>Expand</em> button will only expand the direct children
(first level) of the collection. Starting with v0.100.0, it's possible
@ -45,7 +44,7 @@
<aside class="admonition tip">
<p>By design, the UI provides only a handful of levels of depth for expanding
notes (direct children, 2-5, all levels). It's also possible to specify
any desired depth by manually setting the <a href="#root/pOsGYCXsbNQG/tC7s2alapj8V/zEY4DaJG4YT5/_help_HI6GBBIduIgv">corresponding label</a>.
any desired depth by manually setting the <a href="#root/_help_HI6GBBIduIgv">corresponding label</a>.
For example: <code>#expanded=100</code> to expand up to 100 levels of depth.</p>
</aside>
<aside class="admonition note">

View File

@ -19,6 +19,94 @@
"move-note-up": "Posunout poznámku nahoru",
"move-note-down": "Posunout poznámku dolů",
"move-note-up-in-hierarchy": "Přesunout poznámku o úroveň výše",
"move-note-down-in-hierarchy": "Přesunout poznámku ve struktuře níže"
"move-note-down-in-hierarchy": "Přesunout poznámku ve struktuře níže",
"edit-note-title": "Přejděte ze stromu k podrobnostem poznámky a upravte název",
"edit-branch-prefix": "Zobrazit dialogové okno „Upravit předponu větve“",
"add-note-above-to-the-selection": "Přidat poznámku nad výběr",
"add-note-below-to-selection": "Přidejte poznámku pod výběr",
"clone-notes-to": "Klonovat vybrané poznámky",
"move-notes-to": "Přemístit vybrané poznámky",
"note-clipboard": "Schránka na poznámky",
"copy-notes-to-clipboard": "Zkopírujte vybrané poznámky do schránky",
"paste-notes-from-clipboard": "Vložit poznámku ze schránky do aktivní poznámky",
"cut-notes-to-clipboard": "Vyjměte vybrané poznámky do schránky",
"select-all-notes-in-parent": "Vybrat všechny poznámky na aktuální úrovni poznámek",
"duplicate-subtree": "Duplikovat podstrom",
"tabs-and-windows": "Záložky a okna",
"open-new-tab": "Otevřít novou záložku",
"close-active-tab": "Zavřít aktivní záložku",
"reopen-last-tab": "Znovu otevřít poslední zavřenou záložku",
"activate-next-tab": "Aktivní záložka napravo",
"activate-previous-tab": "Aktivní záložka nalevo",
"open-new-window": "Otevřít nové prázdné okno",
"toggle-tray": "Zobrazit/skrýt aplikaci z oznamovací oblasti systému",
"first-tab": "Přejít na první záložku v seznamu",
"second-tab": "Přejít na druhou záložku v seznamu",
"third-tab": "Přejít na třetí záložku v seznamu",
"fourth-tab": "Přejít na čtvrtou záložku v seznamu",
"fifth-tab": "Přejít na pátou záložku v seznamu",
"sixth-tab": "Přejít na šestou záložku v seznamu",
"seventh-tab": "Přejít na sedmou záložku v seznamu",
"eight-tab": "Přejít na osmou záložku v seznamu",
"ninth-tab": "Přejít na devátou záložku v seznamu",
"last-tab": "Přejít na poslední záložku v seznamu",
"show-options": "Otevřít stránku „Nastavení“",
"show-sql-console": "Otevřít stránku „SQL Konzole“",
"show-backend-log": "Otevřít stránku „Backend Log“",
"show-help": "Otevřít vestavěného uživatelského průvodce",
"show-recent-changes": "Ukázat dialog „Poslední změny“",
"show-note-source": "Ukázat dialog „Zdroj poznámky“",
"edit-readonly-note": "Upravit poznámku pouze pro čtení",
"other": "Ostatní",
"run-active-note": "Spustit aktivní kód JavaScript (frontend/backend) poznámky",
"open-dev-tools": "Otevřít vývojářské nástroje",
"zoom-out": "Oddálit",
"zoom-in": "Přiblížit",
"text-note-operations": "Operace textových poznámek",
"show-cheatsheet": "Zobrazit modal s běžnými operacemi klávesnice",
"add-new-label": "Vytvořít nový štítek",
"insert-date-and-time-to-text": "Vložit do textu současné datum a čas",
"dialogs": "Dialogy",
"show-revisions": "Ukázat dialog „Revize poznámky“",
"add-link-to-text": "Otevřít dialog pro přidání odkazu do textu",
"follow-link-under-cursor": "Následujte odkaz, na kterém je umístěna kurzorová šipka",
"paste-markdown-into-text": "Vložit Markdown ze schránky do poznámky",
"cut-into-note": "Vyjmout výběr z aktuální poznámky a vytvořit podpoznámku s vybraným textem",
"add-include-note-to-text": "Otevřít dialog pro vložení poznámky",
"attributes-labels-and-relations": "Atributy (štítky a vazby)",
"create-new-relation": "Vytvořit novou vazbu",
"ribbon-tabs": "Karty pásu záložek",
"print-active-note": "Vytiskonout aktiivní poznámku",
"render-active-note": "Vykreslit (znovu vykreslit) aktivní poznámku",
"open-note-externally": "Otevřít poznámku jako soubor ve výchozí aplikaci",
"reload-frontend-app": "Znovu načíst frontend",
"unhoist": "Odpojit všude",
"note-navigation": "Navigace v poznámce",
"reset-zoom-level": "Resetovat úroveň přiblížení",
"copy-without-formatting": "Kopírovat vybraný text bez formátování",
"force-save-revision": "Vynutit vytvoření / uložení nové revize aktivní poznámky",
"export-as-pdf": "Exportovat současnou poznámku jako PDF",
"toggle-zen-mode": "Zapnout/vypnout režim zen (minimalistické uživatelské rozhraní pro soustředěnější úpravy)"
},
"keyboard_action_names": {
"jump-to-note": "Přejít na...",
"quick-search": "Rychlé hledání",
"move-note-up": "Posunout poznámku výše",
"move-note-down": "Posunout poznámku níže",
"move-note-up-in-hierarchy": "Posunout poznámku výše v hierarchii",
"move-note-down-in-hierarchy": "Posunout poznámku níže v hierarchii",
"edit-note-title": "Upravit nadpis poznámky",
"clone-notes-to": "Klonovat poznámku do",
"move-notes-to": "Přemístit poznámku do",
"copy-notes-to-clipboard": "Kopírovat poznámky do schránky",
"back-in-note-history": "Zpět v historii poznámky",
"forward-in-note-history": "Vpřed v historii poznámky",
"command-palette": "Paleta příkazů",
"scroll-to-active-note": "Posunout na aktivní poznámku",
"search-in-subtree": "Hledat v podstromu",
"expand-subtree": "Otevřít podstrom",
"collapse-tree": "Zavřít strom",
"collapse-subtree": "Zavřít podstrom",
"sort-child-notes": "Seřadit dceřiné poznámky"
}
}

View File

@ -256,7 +256,9 @@
"multi-factor-authentication-title": "MFA",
"ai-llm-title": "AI/LLM",
"localization": "Sprache & Region",
"inbox-title": "Posteingang"
"inbox-title": "Posteingang",
"zen-mode": "Zen-Modus",
"command-palette": "Befehlspalette öffnen"
},
"notes": {
"new-note": "Neue Notiz",
@ -302,7 +304,7 @@
"end-time": "Endzeit",
"geolocation": "Geolokation",
"built-in-templates": "Integrierte Vorlagen",
"board": "Tafel",
"board": "Kanban-Board",
"status": "Status",
"board_note_first": "Erste Notiz",
"board_note_second": "Zweite Notiz",

View File

@ -27,7 +27,8 @@ async function register(app: express.Application) {
appType: "custom",
cacheDir: path.join(srcRoot, "../../.cache/vite"),
base: `/${assetUrlFragment}/`,
root: clientDir
root: clientDir,
css: { devSourcemap: true }
});
app.use(`/${assetUrlFragment}/`, (req, res, next) => {
req.url = `/${assetUrlFragment}` + req.url;

View File

@ -3,10 +3,137 @@
"title": "Začínáme",
"desktop_title": "Stažení aplikace pro osobní počítače (v{{version}})",
"architecture": "Architektura:",
"older_releases": "Starší vydání"
"older_releases": "Starší vydání",
"server_title": "Nastavte server pro přístup z více zařízení"
},
"hero_section": {
"get_started": "Start",
"github": "GitHub"
"github": "GitHub",
"title": "Uspořádejte si myšlenky. Vytvořte si osobní znalostní bázi.",
"subtitle": "Trilium je open-source řešení pro pořizování poznámek a organizaci osobní znalostní báze. Používejte jej lokálně na svém počítači nebo jej synchronizujte se svým vlastním serverem, abyste měli své poznámky vždy po ruce, ať jste kdekoli.",
"dockerhub": "Docker Hub",
"screenshot_alt": "Snímek obrazovky desktopové aplikace Trilium Notes"
},
"organization_benefits": {
"title": "Organizace",
"note_structure_title": "Struktura poznámek",
"note_structure_description": "Poznámky lze uspořádat hierarchicky. Není třeba používat složky, protože každá poznámka může obsahovat podpoznámky. Jednu poznámku lze přidat na více míst v hierarchii.",
"attributes_title": "Poznámky k štítkům a vztahům",
"attributes_description": "Využijte vztahy mezi poznámkami nebo přidejte štítky pro snadnou kategorizaci. Pomocí propagovaných atributů zadejte strukturované informace, které lze použít v tabulkách.",
"hoisting_title": "Pracovní prostředí a hoisting",
"hoisting_description": "Snadno oddělte své osobní a pracovní poznámky tím, že je seskupíte do pracovního prostoru, který zaměří strom poznámek tak, aby zobrazoval pouze konkrétní sadu poznámek."
},
"productivity_benefits": {
"title": "Produktivita a bezpečnost",
"revisions_title": "Revize poznámek",
"revisions_content": "Poznámky se pravidelně ukládají na pozadí a revize lze použít k přezkoumání nebo ke zrušení náhodných změn. Revize lze také vytvářet na požádání.",
"search_content": "Nebo vyhledávejte text uvnitř poznámek a zúžte vyhledávání filtrováním podle nadřazené poznámky nebo podle hloubky.",
"web_clipper_title": "Webový výstřižek",
"web_clipper_content": "Zachyťte webové stránky (nebo snímky obrazovky) a vložte je přímo do Trilium pomocí rozšíření prohlížeče Webového výstřižku.",
"sync_title": "Synchoronizace",
"sync_content": "Pomocí vlastní nebo cloudové instance můžete snadno synchronizovat své poznámky mezi více zařízeními a přistupovat k nim ze svého mobilního telefonu pomocí PWA.",
"protected_notes_title": "Chráněné poznámky",
"protected_notes_content": "Chraňte citlivé osobní údaje šifrováním poznámek a jejich uzamčením za heslem chráněnou relací.",
"jump_to_title": "Rychlé hledání a příkazy",
"jump_to_content": "Rychle přejděte k poznámkám nebo příkazům uživatelského rozhraní v celé hierarchii pomocí vyhledávání podle názvu, přičemž fuzzy vyhledávání zohledňuje překlepy nebo drobné rozdíly.",
"search_title": "Výkonné vyhledávání"
},
"note_types": {
"title": "Několik způsobů, jak prezentovat vaše informace",
"text_title": "Textová poznámka",
"text_description": "Poznámky se upravují pomocí vizuálního editoru (WYSIWYG) s podporou tabulek, obrázků, matematických výrazů a bloků kódu se zvýrazněním syntaxe. Text lze rychle formátovat pomocí syntaxe podobné Markdownu nebo pomocí příkazů s lomítkem.",
"code_title": "Poznámka kódu",
"code_description": "Velké vzorky zdrojového kódu nebo skriptů používají speciální editor s barevným zvýrazněním syntaxe pro mnoho programovacích jazyků a s různými barevnými motivy.",
"file_title": "Souborové poznámky",
"file_description": "Vložte multimediální soubory, jako jsou PDF, obrázky, videa, s náhledem v aplikaci.",
"canvas_title": "Plátno",
"canvas_description": "Uspořádejte tvary, obrázky a text na nekonečném plátně pomocí stejné technologie, jaká se používá na webu excalidraw.com. Ideální pro diagramy, náčrtky a vizuální plánování.",
"mermaid_title": "Mermaid diagramy",
"mermaid_description": "Vytvářejte diagramy, jako jsou vývojové diagramy, diagramy tříd a sekvencí, Ganttovy diagramy a mnoho dalších, pomocí syntaxe Mermaid.",
"mindmap_title": "Myšlenková mapa",
"mindmap_description": "Zorganizujte si myšlenky vizuálně nebo uspořádejte brainstorming.",
"others_list": "a další: <0>mapa poznámek</0>, <1>mapa vztahů</1>, <2>uložená vyhledávání</2>, <3>zobrazení poznámky</3> a <4>webové zobrazení</4>."
},
"extensibility_benefits": {
"title": "Sdílení a rozšiřitelnost",
"import_export_title": "Import/export",
"import_export_description": "Snadná interakce s jinými aplikacemi pomocí formátů Markdown, ENEX a OML.",
"share_title": "Sdílet poznámky na webu",
"share_description": "Pokud máte server, můžete jej použít ke sdílení části svých poznámek s ostatními lidmi.",
"scripting_title": "Pokročilé skriptování",
"scripting_description": "Vytvořte si vlastní integrace v rámci Trilium pomocí přizpůsobených widgetů nebo logiky na straně serveru.",
"api_title": "REST API",
"api_description": "Komunikujte s Trilium programově pomocí jeho vestavěného REST API."
},
"collections": {
"title": "Kolekce",
"calendar_title": "Kalendář",
"calendar_description": "Organizujte své osobní nebo pracovní události pomocí kalendáře, který podporuje celodenní i vícedenní události. Zobrazte si své události na první pohled v týdenním, měsíčním a ročním přehledu. Snadná interakce pro přidávání nebo přetahování událostí.",
"table_title": "Tabulka",
"table_description": "Zobrazujte a upravujte informace o poznámkách v tabulkové struktuře s různými typy sloupců, jako jsou text, čísla, zaškrtávací políčka, datum a čas, odkazy a barvy, a podporou vztahů. Volitelně můžete poznámky zobrazit v hierarchické struktuře stromu uvnitř tabulky.",
"board_title": "Kanbanová tabule",
"board_description": "Uspořádejte si úkoly nebo stav projektu do tabule Kanban, kde můžete snadno vytvářet nové položky a sloupce a jednoduše měnit jejich stav přetahováním po tabuli.",
"geomap_title": "Geomapa",
"geomap_description": "Naplánujte si dovolenou nebo si označte místa, která vás zajímají, přímo na geografické mapě pomocí přizpůsobitelných značek. Zobrazte zaznamenané trasy GPX a sledujte itineráře.",
"presentation_title": "Prezentace",
"presentation_description": "Uspořádejte informace do snímků a prezentujte je na celé obrazovce s plynulými přechody. Snímky lze také exportovat do formátu PDF pro snadné sdílení."
},
"faq": {
"title": "Často kladené otázky",
"mobile_question": "Existuje mobilní aplikace?",
"mobile_answer": "V současné době neexistuje žádná oficiální mobilní aplikace. Pokud však máte instanci serveru, můžete k ní přistupovat pomocí webového prohlížeče a dokonce ji nainstalovat jako PWA. Pro Android existuje neoficiální aplikace s názvem TriliumDroid, která funguje i offline (stejně jako desktopový klient).",
"database_question": "Kde jsou má data uložena?",
"database_answer": "Všechny vaše poznámky budou uloženy v databázi SQLite ve složce aplikace. Důvodem, proč Trilium používá databázi namísto prostých textových souborů, je jak výkon, tak i skutečnost, že některé funkce by byly mnohem obtížnější implementovat, například klony (stejná poznámka na více místech ve stromu). Chcete-li najít složku aplikace, stačí přejít do okna O aplikaci.",
"server_question": "Potřebuju server pro používání Trilium?",
"server_answer": "Ne, server umožňuje přístup přes webový prohlížeč a spravuje synchronizaci, pokud máte více zařízení. Chcete-li začít, stačí si stáhnout desktopovou aplikaci a začít ji používat.",
"scaling_question": "Jak dobře se aplikace přizpůsobuje velkému množství poznámek?",
"scaling_answer": "V závislosti na použití by aplikace měla být schopna bez problémů zpracovat alespoň 100 000 poznámek. Upozorňujeme, že proces synchronizace může někdy selhat, pokud nahráváte mnoho velkých souborů (1 GB na soubor), protože Trilium je spíše aplikací pro správu znalostí než úložištěm souborů (jako například NextCloud).",
"network_share_question": "Mohu sdílet svou databázi přes síťový disk?",
"network_share_answer": "Ne, sdílení databáze SQLite přes síťový disk obecně není dobrý nápad. I když to někdy může fungovat, existuje riziko, že se databáze poškodí kvůli nedokonalému zamykání souborů v síti.",
"security_question": "Jak jsou má data chráněna?",
"security_answer": "Ve výchozím nastavení nejsou poznámky šifrovány a lze je číst přímo z databáze. Jakmile je poznámka označena jako šifrovaná, je zašifrována pomocí AES-128-CBC."
},
"final_cta": {
"title": "Jste připraveni začít používat Trilium Notes?",
"description": "Vytvořte si svou osobní znalostní bázi s výkonnými funkcemi a plným soukromím.",
"get_started": "Začít"
},
"components": {
"link_learn_more": "Zjistit více..."
},
"download_now": {
"text": "Stáhnout nyní ",
"platform_big": "v{{version}} pro{{platform}}",
"platform_small": "pro {{platform}}",
"linux_big": "v{{version}} pro Linux",
"linux_small": "pro Linux",
"more_platforms": "Další platformy a nastavení serveru"
},
"header": {
"get-started": "Začít",
"documentation": "Dokumentace",
"support-us": "Podpořte nás"
},
"footer": {
"copyright_and_the": " a ",
"copyright_community": "komunita"
},
"social_buttons": {
"github": "GitHub",
"github_discussions": "GitHub diskuze",
"matrix": "Matrix",
"reddit": "Reddit"
},
"support_us": {
"title": "Podpořte nás",
"financial_donations_title": "Finanční dary",
"financial_donations_description": "Trilium je vyvíjeno a udržováno díky <Link>stovkám hodin práce</Link>. Vaše podpora zajišťuje, že zůstane open-source, vylepšuje jeho funkce a pokrývá náklady, jako je hosting.",
"financial_donations_cta": "Zvažte podporu hlavního vývojáře (<Link>eliandoran</Link>) aplikace prostřednictvím:",
"github_sponsors": "Sponzoři GitHubu",
"paypal": "PayPal",
"buy_me_a_coffee": "Buy Me A Coffee"
},
"contribute": {
"title": "Další způsoby, jak přispět"
}
}

View File

@ -36,7 +36,9 @@
"code_title": "Code Notizen",
"canvas_title": "Canvas",
"mermaid_title": "Mermaid Diagramm",
"mindmap_title": "Mind Map"
"mindmap_title": "Mind Map",
"text_description": "Die Notizen werden mit einem visuellen Editor (WYSIWYG) bearbeitet, der Tabellen, Bilder, mathematische Ausdrücke und Code-Blöcke mit Syntaxhervorhebung unterstützt. Formatieren Sie den Text schnell mit einer Markdown-ähnlichen Syntax oder mit Slash-Befehlen.",
"code_description": "Große Quellcode- oder Skriptdateien werden mit einem speziellen Editor bearbeitet, der Syntaxhervorhebung für viele Programmiersprachen und diverse Farbschemata bietet."
},
"extensibility_benefits": {
"import_export_title": "Import/Export",
@ -45,5 +47,41 @@
},
"collections": {
"calendar_title": "Kalender"
},
"download_helper_desktop_macos": {
"quick_start": "Installieren mit Homebrew:",
"download_dmg": "Installer (.dmg) herunterladen",
"download_zip": "Portable (.zip)",
"download_homebrew_cask": "Die Homebrew Cask",
"description_arm64": "Für Apple Silicon Macs, beispielsweise mit M1-, M2-, M3- oder M4-Chips.",
"description_x64": "Für Intel-Macs ab macOS Monterey und neuer.",
"title_x64": "macOS für Intel",
"title_arm64": "macOS für Apple Silicon"
},
"download_helper_server_docker": {
"title": "Self-hosted mit Docker",
"description": "Schnelle Installation auf Windows, Linux oder macOS mit einem Docker-Container.",
"download_dockerhub": "Docker-Hub",
"download_ghcr": "ghcr.io"
},
"download_helper_desktop_linux": {
"download_aur": "AUR",
"download_nixpkgs": "nixpkgs",
"download_zip": "Portable (.zip)",
"download_flatpak": ".flatpak",
"download_rpm": ".rpm"
},
"download_helper_server_linux": {
"title": "Self-hosted auf Linux",
"description": "Trilium Notes auf Ihrem eigenen Server oder VPS bereitstellen kompatibel mit den meisten Linux-Distributionen.",
"download_tar_x64": "x64 (.tar.xz)",
"download_tar_arm64": "ARM (.tar.xz)",
"download_nixos": "NixOS Module"
},
"download_helper_server_hosted": {
"title": "Kostenpflichtiges Hosting",
"description": "Trilium Notes wird auf PikaPods gehostet, einem kostenpflichtigen Dienst für einfachen Zugriff und Verwaltung. Es besteht keine direkte Verbindung zum Trilium-Team.",
"download_pikapod": "Auf PikaPods installieren",
"download_triliumcc": "Alternativ siehe trilium.cc"
}
}

View File

@ -5,5 +5,13 @@
"architecture": "Mimari:",
"older_releases": "Eski sürümleri görüntüle",
"server_title": "Birden fazla cihazdan erişim için bir sunucu kurun"
},
"hero_section": {
"title": "Düşüncelerinizi organize edin. Kişisel bilgi birikiminizi oluşturun.",
"subtitle": "Trilium, not tutma ve kişisel bir bilgi tabanını düzenleme için açık kaynaklı bir çözümdür. Bunu masaüstünü bilgisayarınızda kullanabilir veya kendi barındırdığınız sunucuyla senkronize ederek notlarınızı gittiğiniz her yerde yanınızda bulundurabilirsiniz.",
"get_started": "Başlayın",
"github": "GitHub",
"dockerhub": "Docker Hub",
"screenshot_alt": "Trilium Notes masaüstü uygulamasının ekran görüntüsü"
}
}

View File

@ -1,5 +1,5 @@
# Documentation
There are multiple types of documentation for Trilium:<img class="image-style-align-right" src="api/images/VUKpkCok5Zh4/Documentation_image.png" width="205" height="162">
There are multiple types of documentation for Trilium:<img class="image-style-align-right" src="api/images/Xtlv3JlumknM/Documentation_image.png" width="205" height="162">
* The _User Guide_ represents the user-facing documentation. This documentation can be browsed by users directly from within Trilium, by pressing <kbd>F1</kbd>.
* The _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers.

125
docs/README-cs.md vendored
View File

@ -11,14 +11,14 @@
# Trilium Notes
![GitHub Sponsors](https://img.shields.io/github/sponsors/eliandoran)
![LiberaPay patrons](https://img.shields.io/liberapay/patrons/ElianDoran)\
![Sponzoři GitHubu](https://img.shields.io/github/sponsors/eliandoran) ![Patroni
LiberaPay](https://img.shields.io/liberapay/patrons/ElianDoran)\
![Docker Pulls](https://img.shields.io/docker/pulls/triliumnext/trilium)
![GitHub Downloads (all assets, all
releases)](https://img.shields.io/github/downloads/triliumnext/trilium/total)\
![Stahování GitHubu (všechny soubory, všechna
vydání)](https://img.shields.io/github/downloads/triliumnext/trilium/total)\
[![RelativeCI](https://badges.relative-ci.com/badges/Di5q7dz9daNDZ9UXi0Bp?branch=develop)](https://app.relative-ci.com/projects/Di5q7dz9daNDZ9UXi0Bp)
[![Translation
status](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted.weblate.org/engage/trilium/)
[![Stav
překladu](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted.weblate.org/engage/trilium/)
[Angličtina](./README.md) | [Čínština (Zjednodušená)](./docs/README-ZH_CN.md) |
[Čínština (Tradiční)](./docs/README-ZH_TW.md) | [Ruština](./docs/README-ru.md) |
@ -28,8 +28,8 @@ status](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted
Trilium Notes je open-source, cross-platform aplikace pro hierarchiální psaní
poznámek.
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for
quick overview:
Pro rychlý přehled viz
[screenshot](https://triliumnext.github.io/Docs/Wiki/screenshot-tour):
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
@ -37,8 +37,7 @@ quick overview:
- [Nejnovější verze](https://github.com/TriliumNext/Trilium/releases/latest)
stabilní verze, doporučena pro většinu uživatelů.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
nestabilní vývojová verze, denně aktualizovaná o nejnovější funkce a opravy.
## 📚 Dokumentace
@ -61,62 +60,64 @@ Naše dokumenatce je dostupná ve vícero formátech:
Dockeru](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation/1.%20Installing%20the%20server/Using%20Docker.md)
- [Aktualizování
TriliumNext](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Upgrading%20TriliumNext.md)
- [Basic Concepts and
Features](./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)
- [Základní pojmy a
funkce](./docs/User%20Guide/User%20Guide/Basic%20Concepts%20and%20Features/Notes.md)
- [Vzory osobní znalostní
báze](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge)
## 🎁 Funkce
* 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
* Poznámky lze uspořádat do libovolně hlubokého stromu. Jedna poznámka může být
umístěna na více místech ve stromu (viz
[klonování](https://triliumnext.github.io/Docs/Wiki/cloning-notes))
* Bohatý editor poznámek WYSIWYG zahrnující např. tabulky, obrázky a
[math](https://triliumnext.github.io/Docs/Wiki/text-notes) s automatickým
formátováním
[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
* Podpora pro úpravy [poznámek se zdrojovým
kódem](https://triliumnext.github.io/Docs/Wiki/code-notes), včetně zvýraznění
syntaxe
* Rychlá a snadná [navigace mezi
poznámkami](https://triliumnext.github.io/Docs/Wiki/note-navigation),
vyhledávání v plném textu a [zvedání
poznámek](https://triliumnext.github.io/Docs/Wiki/note-hoisting)
* Bezproblémová [poznámka k
verzím](https://triliumnext.github.io/Docs/Wiki/note-revisions)
* Poznámka [atributy](https://triliumnext.github.io/Docs/Wiki/attributes) lze
použít pro organizaci poznámek, dotazování a pokročilé
[skriptování](https://triliumnext.github.io/Docs/Wiki/scripts)
* Uživatelské rozhraní je k dispozici v angličtině, češtině, němčině,
španělštině, francouzštině, rumunštině a čínštině (zjednodušené a tradiční)
* Přímá integrace [OpenID a
TOTP](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Server%20Installation/Multi-Factor%20Authentication.md)
pro bezpečnější přihlášení
* [Synchronizace](https://triliumnext.github.io/Docs/Wiki/synchronization) s
vlastním synchronizačním serverem
* existuje [služba třetí strany pro hostování synchronizačního
serveru](https://trilium.cc/paid-hosting)
* [Sdílení](https://triliumnext.github.io/Docs/Wiki/sharing) (zveřejňování)
poznámek na veřejném internetu
* Silné [šifrování
poznámek](https://triliumnext.github.io/Docs/Wiki/protected-notes) s
granularitou na úrovni jednotlivých poznámek
* Náčrt diagramů na základě [Excalidraw](https://excalidraw.com/) (poznámka typu
„plátno“)
* [Mapy vztahů](https://triliumnext.github.io/Docs/Wiki/relation-map) a [mapy
odkazů](https://triliumnext.github.io/Docs/Wiki/link-map) pro vizualizaci
poznámek a jejich vztahů
* Myšlenkové mapy založené na [Mind Elixir](https://docs.mind-elixir.com/)
* [Geo mapy](./docs/User%20Guide/User%20Guide/Note%20Types/Geo%20Map.md) s
lokalizačními značkami a trasami GPX
* [Skriptování](https://triliumnext.github.io/Docs/Wiki/scripts) viz
[Pokročilé ukázky](https://triliumnext.github.io/Docs/Wiki/advanced-showcases)
* [REST API](https://triliumnext.github.io/Docs/Wiki/etapi) pro automatizaci
* Dobře škálovatelný jak z hlediska použitelnosti, tak výkonu až do 100 000
poznámek
* Optimalizované pro dotykové ovládání [mobilní
rozhraní](https://triliumnext.github.io/Docs/Wiki/mobile-frontend) pro
smartphony a tablety
* Vestavěný [tmavý motiv](https://triliumnext.github.io/Docs/Wiki/themes),
podpora uživatelských motivů
* [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

18
docs/README-tr.md vendored
View File

@ -34,19 +34,19 @@ görüntülerine](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) bakı
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
## İndir
- [Son sürüm](https://github.com/TriliumNext/Trilium/releases/latest) stabil
versiyon, standart kullanıcılar için tavsiye edilir.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
kararsız geliştirme sürümü, son özellikler ve iyileştirmelerle günlük olarak
güncellenir.
## 📚 Documentation
## Dokümantasyon
**Visit our comprehensive documentation at
[docs.triliumnotes.org](https://docs.triliumnotes.org/)**
**Kapsamlı dokümanlarımızı [docs.triliumnotes.org] adresinden ziyaret
edin(https://docs.triliumnotes.org/)**
Our documentation is available in multiple formats:
Dokümantasyonumuz birden fazla formatta mevcuttur:
- **Online Documentation**: Browse the full documentation at
[docs.triliumnotes.org](https://docs.triliumnotes.org/)
- **In-App Help**: Press `F1` within Trilium to access the same documentation

View File

@ -2380,13 +2380,6 @@
"isInheritable": false,
"position": 20
},
{
"type": "relation",
"name": "internalLink",
"value": "yTjUdsOi4CIE",
"isInheritable": false,
"position": 30
},
{
"type": "label",
"name": "iconClass",
@ -2400,6 +2393,20 @@
"value": "keyboard-shortcuts",
"isInheritable": false,
"position": 40
},
{
"type": "relation",
"name": "internalLink",
"value": "IakOLONlIfGI",
"isInheritable": false,
"position": 50
},
{
"type": "relation",
"name": "internalLink",
"value": "yTjUdsOi4CIE",
"isInheritable": false,
"position": 60
}
],
"format": "markdown",
@ -5211,13 +5218,6 @@
"isInheritable": false,
"position": 20
},
{
"type": "relation",
"name": "internalLink",
"value": "IakOLONlIfGI",
"isInheritable": false,
"position": 30
},
{
"type": "relation",
"name": "internalLink",
@ -5259,6 +5259,20 @@
"value": "bx bxs-keyboard",
"isInheritable": false,
"position": 80
},
{
"type": "relation",
"name": "internalLink",
"value": "DvdZhoQZY9Yd",
"isInheritable": false,
"position": 90
},
{
"type": "relation",
"name": "internalLink",
"value": "TBwsyfadTA18",
"isInheritable": false,
"position": 100
}
],
"format": "markdown",
@ -10576,6 +10590,13 @@
"isInheritable": false,
"position": 30
},
{
"type": "relation",
"name": "internalLink",
"value": "HI6GBBIduIgv",
"isInheritable": false,
"position": 40
},
{
"type": "label",
"name": "iconClass",
@ -10589,13 +10610,6 @@
"value": "list",
"isInheritable": false,
"position": 30
},
{
"type": "relation",
"name": "internalLink",
"value": "HI6GBBIduIgv",
"isInheritable": false,
"position": 40
}
],
"format": "markdown",

View File

@ -3,49 +3,38 @@ This is supposed to be a complete list of keyboard shortcuts. Note that some of
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).
## Tree
See the corresponding section: <a class="reference-link" href="UI%20Elements/Note%20Tree/Keyboard%20shortcuts.md">Keyboard shortcuts</a>
## Note navigation
* <kbd><span></span></kbd>, <kbd><span></span></kbd> - go up/down in the list of notes, <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd><span></span></kbd> and <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd><span></span></kbd>  work also from editor
* <kbd><span></span></kbd>, <kbd><span></span></kbd> - collapse/expand node
* <kbd>Alt</kbd> + <kbd><span></span></kbd>, <kbd>Alt</kbd> + <kbd><span></span></kbd> - go back / forwards in the history
* <kbd>Ctrl</kbd> + <kbd>J</kbd> - show ["Jump to" dialog](Navigation/Note%20Navigation.md)
* <kbd>Ctrl</kbd> + <kbd>.</kbd> - scroll to current note (useful when you scroll away from your note or your focus is currently in the editor)
* <kbd><span>Backspace</span></kbd> - jumps to parent note
* <kbd>Alt</kbd> + <kbd>C</kbd> - collapse whole note tree
* <kbd>Alt</kbd> + <kbd>-</kbd> (alt with minus sign) - collapse subtree (if some subtree takes too much space on tree pane you can collapse it)
* <kbd>Alt</kbd> + <kbd><span></span></kbd>, <kbd>Alt</kbd> + <kbd><span></span></kbd> go back / forwards in the history
* <kbd>Ctrl</kbd> + <kbd>J</kbd> show ["Jump to" dialog](Navigation/Note%20Navigation.md)
* <kbd>Ctrl</kbd> + <kbd>.</kbd> scroll to current note (useful when you scroll away from your note or your focus is currently in the editor)
* <kbd><span>Backspace</span></kbd> jumps to parent note
* <kbd>Alt</kbd> + <kbd>C</kbd> collapse whole note tree
* <kbd>Alt</kbd> + <kbd>-</kbd> (alt with minus sign) collapse subtree (if some subtree takes too much space on tree pane you can collapse it)
* you can define a [label](../Advanced%20Usage/Attributes.md) `#keyboardShortcut` with e.g. value <kbd>Ctrl</kbd> + <kbd>I</kbd> . Pressing this keyboard combination will then bring you to the note on which it is defined. Note that Trilium must be reloaded/restarted (<kbd>Ctrl</kbd> + <kbd>R</kbd> ) for changes to be in effect.
See demo of some of these features in [note navigation](Navigation/Note%20Navigation.md).
## Tabs
* <kbd>Ctrl</kbd> + <kbd>🖱 Left click</kbd> - (or middle mouse click) on note link opens note in a new tab
* <kbd>Ctrl</kbd> + <kbd>🖱 Left click</kbd> (or middle mouse click) on note link opens note in a new tab
Only in desktop (electron build):
* <kbd>Ctrl</kbd> + <kbd>T</kbd> - opens empty tab
* <kbd>Ctrl</kbd> + <kbd>W</kbd> - closes active tab
* <kbd>Ctrl</kbd> + <kbd>Tab</kbd> - activates next tab
* <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Tab</kbd> - activates previous tab
* <kbd>Ctrl</kbd> + <kbd>T</kbd> opens empty tab
* <kbd>Ctrl</kbd> + <kbd>W</kbd> closes active tab
* <kbd>Ctrl</kbd> + <kbd>Tab</kbd> activates next tab
* <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Tab</kbd> activates previous tab
## Creating notes
* `CTRL+O` - creates new note after the current note
* `CTRL+P` - creates new sub-note into current note
* `F2` - edit [prefix](Navigation/Note%20Navigation.md) of current note clone
## Moving / cloning notes
* <kbd>Ctrl</kbd> + <kbd><span></span></kbd> , Ctrl + <kbd><span></span></kbd> - move note up/down in the note list
* <kbd>Ctrl</kbd> + <kbd><span></span></kbd> - move note up in the note tree
* <kbd>Ctrl</kbd>+<kbd><span></span></kbd> - move note down in the note tree
* <kbd>Shift</kbd>+<kbd><span></span></kbd>, <kbd>Shift</kbd>`+`<kbd><span></span></kbd> - multi-select note above/below
* <kbd>Ctrl</kbd>+<kbd>A</kbd> - select all notes in the current level
* <kbd>Shift</kbd>+<kbd>🖱 Left click</kbd> - multi select note which you clicked on
* <kbd>Ctrl</kbd>+<kbd>C</kbd> - copies current note (or current selection) into clipboard (used for [cloning](Notes/Cloning%20Notes.md)
* <kbd>Ctrl</kbd>+<kbd>X</kbd> - cuts current (or current selection) note into clipboard (used for moving notes)
* <kbd>Ctrl</kbd>+<kbd>V</kbd> - pastes note(s) as sub-note into current note (which is either move or clone depending on whether it was copied or cut into clipboard)
* <kbd>Del</kbd> - delete note / sub-tree
* <kbd>CTRL</kbd>+<kbd>O</kbd> creates new note after the current note
* <kbd>CTRL</kbd>+<kbd>P</kbd> creates new sub-note into current note
* <kbd>F2</kbd> edit <a class="reference-link" href="Notes/Cloning%20Notes/Branch%20prefix.md">Branch prefix</a> of current note clone
## Editing notes
@ -53,22 +42,22 @@ Only in desktop (electron build):
> For keyboard shortcuts specific to <a class="reference-link" href="../Note%20Types/Text.md">Text</a> notes, refer to <a class="reference-link" href="../Note%20Types/Text/Keyboard%20shortcuts.md">Keyboard shortcuts</a> and <a class="reference-link" href="../Note%20Types/Text/Markdown-like%20formatting.md">Markdown-like formatting</a>.
* <kbd>Enter</kbd> in tree pane switches from tree pane into note title. Enter from note title switches focus to text editor. <kbd>Ctrl</kbd>+<kbd>.</kbd> switches back from editor to tree pane.
* <kbd>Ctrl</kbd>+<kbd>.</kbd> - jump away from the editor to tree pane and scroll to current note
* <kbd>Ctrl</kbd>+<kbd>.</kbd> jump away from the editor to tree pane and scroll to current note
## Runtime shortcuts
These are hooked in Electron to be similar to native browser keyboard shortcuts.
* <kbd>F5</kbd>, <kbd>Ctrl</kbd>\-<kbd>R</kbd> - reloads Trilium front-end
* <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>I</kbd> - show developer tools
* <kbd>Ctrl</kbd>+<kbd>F</kbd> - show search dialog
* <kbd>Ctrl</kbd>+<kbd>-</kbd> - zoom out
* <kbd>Ctrl</kbd>+<kbd>=</kbd> - zoom in
* <kbd>F5</kbd>, <kbd>Ctrl</kbd>+<kbd>R</kbd> reloads Trilium front-end
* <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>I</kbd> show developer tools
* <kbd>Ctrl</kbd>+<kbd>F</kbd> show search dialog
* <kbd>Ctrl</kbd>+<kbd>-</kbd> zoom out
* <kbd>Ctrl</kbd>+<kbd>=</kbd> zoom in
## Other
* <kbd>Alt</kbd>+<kbd>O</kbd> - show SQL console (use only if you know what you're doing)
* <kbd>Alt</kbd>+<kbd>M</kbd> - distraction-free mode - display only note editor, everything else is hidden
* <kbd>F11</kbd> - toggle full screen
* <kbd>Ctrl</kbd> + <kbd>S</kbd> - toggle [search](Navigation/Search.md) form in tree pane
* <kbd>Alt</kbd> +<kbd>A</kbd> - show note [attributes](../Advanced%20Usage/Attributes.md) dialog
* <kbd>Alt</kbd> + <kbd>O</kbd> show SQL console (use only if you know what you're doing)
* <kbd>Alt</kbd> + <kbd>M</kbd> distraction-free mode - display only note editor, everything else is hidden
* <kbd>F11</kbd> toggle full screen
* <kbd>Ctrl</kbd> + <kbd>S</kbd> toggle [search](Navigation/Search.md) form in tree pane
* <kbd>Alt</kbd> +<kbd>A</kbd> show note [attributes](../Advanced%20Usage/Attributes.md) dialog

View File

@ -1,17 +1,36 @@
# Keyboard shortcuts
The <a class="reference-link" href="../Note%20Tree.md">Note Tree</a> comes with multiple keyboard shortcuts to make editing faster:
* Opening notes:
* <kbd>Click</kbd> to open the note in the current tab.
* <kbd>Ctrl</kbd>+<kbd>Click</kbd> or <kbd>Middle click</kbd> to open the note in a new tab.
* <kbd>Ctrl</kbd>+<kbd>Right click</kbd> to open the note in <a class="reference-link" href="../../Navigation/Quick%20edit.md">Quick edit</a>.
* Navigation within the tree:
* <kbd>Up</kbd> and <kbd>Down</kbd> to navigate between notes.
* <kbd>Left</kbd> to collapse a note, or <kbd>Right</kbd> to expand it.
* Clipboard management:
* <kbd>Ctrl</kbd>+<kbd>C</kbd> to copy a note.
* <kbd>Ctrl</kbd>+<kbd>X</kbd> to cut a note.
* <kbd>Ctrl</kbd>+<kbd>V</kbd> to paste it somewhere.
* For <a class="reference-link" href="Multiple%20selection.md">Multiple selection</a>:
* <kbd>Alt</kbd>+<kbd>Click</kbd>to add a single note to the current selection.
* <kbd>Shift</kbd>+<kbd>Click</kbd>to select a range of notes, starting from the current note (the highlighted one) to the one that is being clicked.
## Navigation within the tree
* <kbd><span></span></kbd> and <kbd><span></span></kbd> to navigate between notes.
* <kbd><span></span></kbd> to collapse a note with children, or <kbd><span></span></kbd> to expand it.
* <kbd><span></span></kbd> on a note with no children to navigate to its parent.
## Opening notes
* <kbd>Click</kbd> to open the note in the current tab.
* <kbd>Ctrl</kbd>+<kbd>Click</kbd> or <kbd>Middle click</kbd> to open the note in a new tab.
* <kbd>Ctrl</kbd>+<kbd>Right click</kbd> to open the note in <a class="reference-link" href="../../Navigation/Quick%20edit.md">Quick edit</a>.
## Clipboard management
* <kbd>Ctrl</kbd>+<kbd>C</kbd> to copy one or more notes based on selection (see <a class="reference-link" href="../../Notes/Cloning%20Notes.md">Cloning Notes</a>).
* <kbd>Ctrl</kbd>+<kbd>X</kbd> to cut one or more notes (for moving them).
* <kbd>Ctrl</kbd>+<kbd>V</kbd> to paste them somewhere (which results in a copy or move based on the shortcut used).
## Moving notes
* <kbd>Ctrl</kbd> + <kbd><span></span></kbd> , <kbd>Ctrl</kbd> + <kbd><span></span></kbd> - move note up/down in the note list.
* <kbd>Ctrl</kbd> + <kbd><span></span></kbd> - move note up in the note tree.
* <kbd>Ctrl</kbd>+<kbd><span></span></kbd> - move note down in the note tree.
* <kbd>Del</kbd> - deletes note and optionally its subtree (asked in the dialog).
## Multiple selection
See <a class="reference-link" href="Multiple%20selection.md">Multiple selection</a> for more information about how selection works.
* <kbd>Alt</kbd>+<kbd>Click</kbd> add a single note to the current selection.
* <kbd>Shift</kbd>+<kbd>Click</kbd> select a range of notes, starting from the current note (the highlighted one) to the one that is being clicked.
* <kbd>Shift</kbd>+<kbd><span></span></kbd>, <kbd>Shift</kbd>+<kbd><span></span></kbd> multi-select not above/below.
* <kbd>Ctrl</kbd>+<kbd>A</kbd> select all notes in the current level

View File

@ -84,7 +84,7 @@
"url": "https://github.com/TriliumNext/Trilium/issues"
},
"homepage": "https://triliumnotes.org",
"packageManager": "pnpm@10.23.0",
"packageManager": "pnpm@10.24.0",
"pnpm": {
"patchedDependencies": {
"@ckeditor/ckeditor5-mention": "patches/@ckeditor__ckeditor5-mention.patch",

View File

@ -1,4 +1,5 @@
import "ckeditor5";
import { type CreateNoteAction } from "@triliumnext/commons"
declare global {
interface Component {
@ -7,7 +8,8 @@ declare global {
interface EditorComponent extends Component {
loadReferenceLinkTitle($el: JQuery<HTMLElement>, href: string): Promise<void>;
createNoteForReferenceLink(title: string): Promise<string>;
// Must Return Note Path
createNoteFromCkEditor(title: string, parentNotePath: string | undefined, action: CreateNoteAction): Promise<string>;
loadIncludedNote(noteId: string, $el: JQuery<HTMLElement>): void;
}

View File

@ -1,4 +1,5 @@
import { Command, Mention, Plugin, ModelRange, type ModelSelectable } from "ckeditor5";
import { CreateNoteAction } from "@triliumnext/commons"
/**
* Overrides the actions taken by the Mentions plugin (triggered by `@` in the text editor, or `~` & `#` in the attribute editor):
@ -9,11 +10,11 @@ import { Command, Mention, Plugin, ModelRange, type ModelSelectable } from "cked
*/
export default class MentionCustomization extends Plugin {
static get requires() {
static get requires() {
return [ Mention ];
}
public static get pluginName() {
public static get pluginName() {
return "MentionCustomization" as const;
}
@ -25,20 +26,21 @@ export default class MentionCustomization extends Plugin {
}
interface MentionOpts {
mention: string | {
id: string;
[key: string]: unknown;
};
marker: string;
text?: string;
range?: ModelRange;
mention: string | {
id: string;
[key: string]: unknown;
};
marker: string;
text?: string;
range?: ModelRange;
}
interface MentionAttribute {
id: string;
action?: "create-note";
noteTitle: string;
notePath: string;
id: string;
action?: CreateNoteAction;
noteTitle: string;
notePath: string;
parentNoteId?: string;
}
class CustomMentionCommand extends Command {
@ -56,14 +58,27 @@ class CustomMentionCommand extends Command {
model.insertContent( writer.createText( mention.id, {} ), range );
});
}
else if (mention.action === 'create-note') {
const editorEl = this.editor.editing.view.getDomRoot();
const component = glob.getComponentByEl<EditorComponent>(editorEl);
else if (
mention.action === CreateNoteAction.CreateNote ||
mention.action === CreateNoteAction.CreateChildNote ||
mention.action === CreateNoteAction.CreateAndLinkNote ||
mention.action === CreateNoteAction.CreateAndLinkChildNote
) {
const editorEl = this.editor.editing.view.getDomRoot();
const component = glob.getComponentByEl<EditorComponent>(editorEl);
component.createNoteForReferenceLink(mention.noteTitle).then(notePath => {
this.insertReference(range, notePath);
});
}
// use parentNoteId as fallback when notePath is missing
const parentNotePath = mention.notePath || mention.parentNoteId;
component
.createNoteFromCkEditor(mention.noteTitle, parentNotePath, mention.action)
.then(notePath => {
if (notePath) {
this.insertReference(range, notePath);
}
})
.catch(err => console.error("Error creating note from CKEditor mention:", err));
}
else {
this.insertReference(range, mention.notePath);
}

View File

@ -2,9 +2,14 @@
* https://github.com/TriliumNext/Trilium/issues/1002
*/
import { Command, ModelDocumentSelection, ModelElement, ModelNode, Plugin, ModelRange } from 'ckeditor5';
export default class MoveBlockUpDownPlugin extends Plugin {
import { Command, ModelDocumentSelection, ModelElement, ModelNode, Plugin, ModelRange, _isMac, Editor } from 'ckeditor5';
const keyMap = {
ArrowUp: 'moveBlockUp',
ArrowDown: 'moveBlockDown'
};
export default class MoveBlockUpDownPlugin extends Plugin {
init() {
const editor = this.editor;
@ -21,17 +26,14 @@ export default class MoveBlockUpDownPlugin extends Plugin {
const domRoot = editor.editing.view.getDomRoot();
if (!domRoot) return;
const isMac = _isMac(navigator.userAgent.toLowerCase());
const handleKeydown = (e: KeyboardEvent) => {
const keyMap = {
ArrowUp: 'moveBlockUp',
ArrowDown: 'moveBlockDown'
};
const command = keyMap[e.key];
const isCtrl = e.ctrlKey || e.metaKey;
const hasModifier = (isCtrl || e.altKey) && !(isCtrl && e.altKey);
if (!command) return;
const isOnlyMeta = (!e.ctrlKey && !e.altKey && e.metaKey);
const isOnlyAlt = (!e.ctrlKey && e.altKey && !e.metaKey);
if (command && hasModifier) {
if ((!isMac && isOnlyMeta) || isOnlyAlt) {
e.preventDefault();
e.stopImmediatePropagation();
editor.execute(command);
@ -100,8 +102,7 @@ abstract class MoveBlockUpDownCommand extends Command {
}
writer.setSelection(range);
this.editor.editing.view.focus();
this.scrollToSelection();
scrollToSelection(this.editor);
});
}
@ -129,13 +130,6 @@ abstract class MoveBlockUpDownCommand extends Command {
// Deduplicate adjacent duplicates (e.g., nested selections resolving to same block)
return resolved.filter((blk, idx) => idx === 0 || blk !== resolved[idx - 1]);
}
scrollToSelection() {
// Ensure scroll happens in sync with DOM updates
requestAnimationFrame(() => {
this.editor.editing.view.scrollToTheSelection();
});
};
}
class MoveBlockUpCommand extends MoveBlockUpDownCommand {
@ -162,3 +156,10 @@ class MoveBlockDownCommand extends MoveBlockUpDownCommand {
return "after" as const;
}
}
function scrollToSelection(editor: Editor) {
// Ensure scroll happens in sync with DOM updates
requestAnimationFrame(() => {
editor.editing.view.scrollToTheSelection();
});
};

View File

@ -10,4 +10,5 @@ export * from "./lib/server_api.js";
export * from "./lib/shared_constants.js";
export * from "./lib/ws_api.js";
export * from "./lib/attribute_names.js";
export * from "./lib/create_note_actions.js";
export * from "./lib/utils.js";

View File

@ -0,0 +1,6 @@
export enum CreateNoteAction {
CreateNote = "create-note",
CreateChildNote = "create-child-note",
CreateAndLinkNote = "create-and-link-note",
CreateAndLinkChildNote = "create-and-link-child-note"
}

122
pnpm-lock.yaml generated
View File

@ -90,7 +90,7 @@ importers:
version: 7.0.1(eslint@9.39.1(jiti@2.6.1))
happy-dom:
specifier: ~20.0.0
version: 20.0.10
version: 20.0.11
http-server:
specifier: 14.1.1
version: 14.1.1
@ -129,7 +129,7 @@ importers:
version: 4.5.4(@types/node@24.10.1)(rollup@4.52.0)(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
vitest:
specifier: 4.0.14
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
apps/build-docs:
devDependencies:
@ -339,8 +339,8 @@ importers:
specifier: 13.0.1
version: 13.0.1(webpack@5.101.3(esbuild@0.27.0))
happy-dom:
specifier: 20.0.10
version: 20.0.10
specifier: 20.0.11
version: 20.0.11
script-loader:
specifier: 0.7.2
version: 0.7.2
@ -367,7 +367,7 @@ importers:
dependencies:
'@electron/remote':
specifier: 2.1.3
version: 2.1.3(electron@38.7.1)
version: 2.1.3(electron@38.7.2)
better-sqlite3:
specifier: 12.4.6
version: 12.4.6
@ -424,8 +424,8 @@ importers:
specifier: 13.0.1
version: 13.0.1(webpack@5.101.3(esbuild@0.27.0))
electron:
specifier: 38.7.1
version: 38.7.1
specifier: 38.7.2
version: 38.7.2
prebuild-install:
specifier: 7.1.3
version: 7.1.3
@ -480,8 +480,8 @@ importers:
specifier: 13.0.1
version: 13.0.1(webpack@5.101.3(esbuild@0.27.0))
electron:
specifier: 38.7.1
version: 38.7.1
specifier: 38.7.2
version: 38.7.2
fs-extra:
specifier: 11.3.2
version: 11.3.2
@ -506,7 +506,7 @@ importers:
version: 7.1.1
'@electron/remote':
specifier: 2.1.3
version: 2.1.3(electron@38.7.1)
version: 2.1.3(electron@38.7.2)
'@preact/preset-vite':
specifier: 2.10.2
version: 2.10.2(@babel/core@7.28.0)(preact@10.27.2)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
@ -649,8 +649,8 @@ importers:
specifier: 3.1.10
version: 3.1.10
electron:
specifier: 38.7.1
version: 38.7.1
specifier: 38.7.2
version: 38.7.2
electron-debug:
specifier: 4.1.0
version: 4.1.0
@ -840,7 +840,7 @@ importers:
version: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vitest:
specifier: 4.0.14
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
packages/ckeditor5:
dependencies:
@ -931,7 +931,7 @@ importers:
version: 2.0.0(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
vitest:
specifier: 4.0.14
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
webdriverio:
specifier: 9.20.1
version: 9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)
@ -991,7 +991,7 @@ importers:
version: 2.0.0(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
vitest:
specifier: 4.0.14
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
webdriverio:
specifier: 9.20.1
version: 9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)
@ -1051,7 +1051,7 @@ importers:
version: 2.0.0(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
vitest:
specifier: 4.0.14
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
webdriverio:
specifier: 9.20.1
version: 9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)
@ -1118,7 +1118,7 @@ importers:
version: 2.0.0(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
vitest:
specifier: 4.0.14
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
webdriverio:
specifier: 9.20.1
version: 9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)
@ -1185,7 +1185,7 @@ importers:
version: 2.0.0(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
vitest:
specifier: 4.0.14
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
webdriverio:
specifier: 9.20.1
version: 9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)
@ -2336,11 +2336,11 @@ packages:
engines: {node: '>=14.14'}
hasBin: true
'@emnapi/core@1.7.0':
resolution: {integrity: sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw==}
'@emnapi/core@1.7.1':
resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==}
'@emnapi/runtime@1.7.0':
resolution: {integrity: sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==}
'@emnapi/runtime@1.7.1':
resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==}
'@emnapi/wasi-threads@1.1.0':
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
@ -5448,6 +5448,9 @@ packages:
'@types/node@20.19.24':
resolution: {integrity: sha512-FE5u0ezmi6y9OZEzlJfg37mqqf6ZDSF2V/NLjUyGrR9uTZ7Sb9F7bLNZ03S4XVUNRWGA7Ck4c1kK+YnuWjl+DA==}
'@types/node@20.19.25':
resolution: {integrity: sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==}
'@types/node@22.15.21':
resolution: {integrity: sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==}
@ -5463,6 +5466,9 @@ packages:
'@types/node@22.18.8':
resolution: {integrity: sha512-pAZSHMiagDR7cARo/cch1f3rXy0AEXwsVsVH09FcyeJVAzCnGgmYis7P3JidtTUjyadhTeSo8TgRPswstghDaw==}
'@types/node@22.19.1':
resolution: {integrity: sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==}
'@types/node@24.10.1':
resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==}
@ -7242,6 +7248,9 @@ packages:
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
custom-event@1.0.1:
resolution: {integrity: sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==}
@ -7827,8 +7836,8 @@ packages:
resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==}
engines: {node: '>=8.0.0'}
electron@38.7.1:
resolution: {integrity: sha512-mdFVpL80nZvIvajtl1Xz+2Q/a9tFGVnPO0YW/N+MqQUyZG8D9r3wrWoaEVBXTc1jI+Vkg77Eqqwh5FLiaYRI+A==}
electron@38.7.2:
resolution: {integrity: sha512-BcjR0IHqp3uv4ytVQwW2/9zAWo17Rjwrydn6RS+g+vqhpcPTzmBHDCHKaEcqheSl/7zzKPgFZdvT21BoSfrxRQ==}
engines: {node: '>= 12.20.55'}
hasBin: true
@ -8807,8 +8816,8 @@ packages:
engines: {node: '>=0.4.7'}
hasBin: true
happy-dom@20.0.10:
resolution: {integrity: sha512-6umCCHcjQrhP5oXhrHQQvLB0bwb1UzHAHdsXy+FjtKoYjUhmNZsQL8NivwM1vDvNEChJabVrUYxUnp/ZdYmy2g==}
happy-dom@20.0.11:
resolution: {integrity: sha512-QsCdAUHAmiDeKeaNojb1OHOPF7NjcWPBR7obdu3NwH2a/oyQaLg5d0aaCy/9My6CdPChYF07dvz5chaXBGaD4g==}
engines: {node: '>=20.0.0'}
has-bigints@1.1.0:
@ -15769,6 +15778,8 @@ snapshots:
'@ckeditor/ckeditor5-core': 47.2.0
'@ckeditor/ckeditor5-utils': 47.2.0
ckeditor5: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-code-block@47.2.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)':
dependencies:
@ -16029,6 +16040,8 @@ snapshots:
'@ckeditor/ckeditor5-utils': 47.2.0
ckeditor5: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-editor-multi-root@47.2.0':
dependencies:
@ -16051,6 +16064,8 @@ snapshots:
'@ckeditor/ckeditor5-table': 47.2.0
'@ckeditor/ckeditor5-utils': 47.2.0
ckeditor5: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-emoji@47.2.0':
dependencies:
@ -16076,8 +16091,6 @@ snapshots:
'@ckeditor/ckeditor5-core': 47.2.0
'@ckeditor/ckeditor5-engine': 47.2.0
'@ckeditor/ckeditor5-utils': 47.2.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-essentials@47.2.0':
dependencies:
@ -16537,6 +16550,8 @@ snapshots:
'@ckeditor/ckeditor5-ui': 47.2.0
'@ckeditor/ckeditor5-utils': 47.2.0
ckeditor5: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-restricted-editing@47.2.0':
dependencies:
@ -17381,9 +17396,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@electron/remote@2.1.3(electron@38.7.1)':
'@electron/remote@2.1.3(electron@38.7.2)':
dependencies:
electron: 38.7.1
electron: 38.7.2
'@electron/universal@2.0.2':
dependencies:
@ -17407,13 +17422,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@emnapi/core@1.7.0':
'@emnapi/core@1.7.1':
dependencies:
'@emnapi/wasi-threads': 1.1.0
tslib: 2.8.1
optional: true
'@emnapi/runtime@1.7.0':
'@emnapi/runtime@1.7.1':
dependencies:
tslib: 2.8.1
optional: true
@ -18122,7 +18137,7 @@ snapshots:
'@inquirer/figures': 1.0.13
'@inquirer/type': 2.0.0
'@types/mute-stream': 0.0.4
'@types/node': 22.18.13
'@types/node': 22.19.1
'@types/wrap-ansi': 3.0.0
ansi-escapes: 4.3.2
cli-width: 4.1.0
@ -18700,8 +18715,8 @@ snapshots:
'@napi-rs/wasm-runtime@1.0.7':
dependencies:
'@emnapi/core': 1.7.0
'@emnapi/runtime': 1.7.0
'@emnapi/core': 1.7.1
'@emnapi/runtime': 1.7.1
'@tybys/wasm-util': 0.10.1
optional: true
@ -20706,7 +20721,7 @@ snapshots:
'@types/mute-stream@0.0.4':
dependencies:
'@types/node': 24.10.1
'@types/node': 22.19.1
'@types/node-forge@1.3.14':
dependencies:
@ -20718,6 +20733,10 @@ snapshots:
dependencies:
undici-types: 6.21.0
'@types/node@20.19.25':
dependencies:
undici-types: 6.21.0
'@types/node@22.15.21':
dependencies:
undici-types: 6.21.0
@ -20738,6 +20757,10 @@ snapshots:
dependencies:
undici-types: 6.21.0
'@types/node@22.19.1':
dependencies:
undici-types: 6.21.0
'@types/node@24.10.1':
dependencies:
undici-types: 7.16.0
@ -20761,7 +20784,7 @@ snapshots:
'@types/react@19.1.7':
dependencies:
csstype: 3.1.3
csstype: 3.2.3
optional: true
'@types/readdir-glob@1.1.5':
@ -20887,7 +20910,7 @@ snapshots:
'@types/yauzl@2.10.3':
dependencies:
'@types/node': 24.10.1
'@types/node': 22.18.13
optional: true
'@typescript-eslint/eslint-plugin@8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)':
@ -21117,7 +21140,7 @@ snapshots:
'@vitest/browser-webdriverio@4.0.14(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14)(webdriverio@9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5))':
dependencies:
'@vitest/browser': 4.0.14(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14)
vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
webdriverio: 9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)
transitivePeerDependencies:
- bufferutil
@ -21134,7 +21157,7 @@ snapshots:
pngjs: 7.0.0
sirv: 3.0.2
tinyrainbow: 3.0.3
vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)
transitivePeerDependencies:
- bufferutil
@ -21153,7 +21176,7 @@ snapshots:
magicast: 0.5.1
obug: 2.1.1
tinyrainbow: 3.0.3
vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
transitivePeerDependencies:
- supports-color
@ -21170,7 +21193,7 @@ snapshots:
obug: 2.1.1
std-env: 3.10.0
tinyrainbow: 3.0.3
vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
optionalDependencies:
'@vitest/browser': 4.0.14(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14)
transitivePeerDependencies:
@ -21220,7 +21243,7 @@ snapshots:
sirv: 3.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.0.3
vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
vitest: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
'@vitest/utils@4.0.14':
dependencies:
@ -23086,6 +23109,9 @@ snapshots:
csstype@3.1.3: {}
csstype@3.2.3:
optional: true
custom-event@1.0.1: {}
cytoscape-cose-bilkent@4.1.0(cytoscape@3.31.2):
@ -23747,7 +23773,7 @@ snapshots:
- supports-color
optional: true
electron@38.7.1:
electron@38.7.2:
dependencies:
'@electron/get': 2.0.3
'@types/node': 22.18.13
@ -25186,9 +25212,9 @@ snapshots:
optionalDependencies:
uglify-js: 3.19.3
happy-dom@20.0.10:
happy-dom@20.0.11:
dependencies:
'@types/node': 20.19.24
'@types/node': 20.19.25
'@types/whatwg-mimetype': 3.0.2
whatwg-mimetype: 3.0.0
@ -31767,7 +31793,7 @@ snapshots:
tsx: 4.20.6
yaml: 2.8.1
vitest@4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1):
vitest@4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-webdriverio@4.0.14)(@vitest/ui@4.0.14)(happy-dom@20.0.11)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(less@4.1.3)(lightningcss@1.30.1)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1):
dependencies:
'@vitest/expect': 4.0.14
'@vitest/mocker': 4.0.14(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))
@ -31794,7 +31820,7 @@ snapshots:
'@types/node': 24.10.1
'@vitest/browser-webdriverio': 4.0.14(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.10.1)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.14)(webdriverio@9.20.1(bufferutil@4.0.9)(utf-8-validate@6.0.5))
'@vitest/ui': 4.0.14(vitest@4.0.14)
happy-dom: 20.0.10
happy-dom: 20.0.11
jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)
transitivePeerDependencies:
- jiti