Compare commits

...

484 Commits

Author SHA1 Message Date
Elian Doran
bd243e36e5 chore(release): prepare for 0.99.2 2025-10-21 07:55:43 +03:00
Elian Doran
ad8135c2a9 chore(client/import): rephrase ZIP import recommendation 2025-10-20 20:40:34 +03:00
Elian Doran
bcb2daf9b6 feat(client/import): clarify importing from zip (closes #7429) 2025-10-20 20:34:57 +03:00
Elian Doran
8fc7a20220 fix(client/import): file remains from previous instance (closes #7428) 2025-10-20 20:24:43 +03:00
Elian Doran
00720ae58f docs(user): mention printing PDF manually from browser 2025-10-20 19:42:06 +03:00
Elian Doran
51f559b332 feat(client/search): apply full-width for collection view 2025-10-20 19:37:19 +03:00
Elian Doran
a7a8f806e8 fix(client): search results taking up space when not needed 2025-10-20 19:30:44 +03:00
Elian Doran
25e1c45562 style(search): decrease opacity of note path 2025-10-20 18:59:44 +03:00
Elian Doran
d90e02d8f4 fix(search): note path not visible in search (closes #7404) 2025-10-20 18:56:28 +03:00
Elian Doran
d4a46ed4da fix(settings): max content width forces minimum when typing (closes #7423) 2025-10-20 18:34:57 +03:00
Elian Doran
a664a58076 Merge branch 'main' of https://github.com/TriliumNext/Trilium 2025-10-20 18:23:10 +03:00
Elian Doran
ca2cc38bad fix(website): wrong docker command (closes #7426) 2025-10-20 18:23:08 +03:00
Elian Doran
1c6b3fba03 Translations update from Hosted Weblate (#7424) 2025-10-20 18:20:34 +03:00
kamykO
77b0d541b1 Translated using Weblate (Polish)
Currently translated at 29.4% (477 of 1620 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-10-20 15:17:06 +00:00
green
e72dc5c5c3 Translated using Weblate (Japanese)
Currently translated at 100.0% (387 of 387 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ja/
2025-10-20 15:17:05 +00:00
green
d81fcef1f3 Translated using Weblate (Japanese)
Currently translated at 100.0% (1620 of 1620 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-10-20 15:17:04 +00:00
Francis C
77ac0bfbdd Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (387 of 387 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/zh_Hant/
2025-10-20 15:17:04 +00:00
Francis C
434e3f6035 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (1620 of 1620 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hant/
2025-10-20 15:17:03 +00:00
Luk On
0d2dc86fb9 Translated using Weblate (Polish)
Currently translated at 29.4% (476 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-10-20 15:17:02 +00:00
Manfred Manni
fa57966b01 Translated using Weblate (German)
Currently translated at 99.8% (1616 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/de/
2025-10-20 15:17:01 +00:00
Elian Doran
29682cef49 docs(user): update documentation on search in collections 2025-10-20 18:16:28 +03:00
Elian Doran
b224267e3b fix(ribbon): wrong default view type in search 2025-10-20 18:03:55 +03:00
Elian Doran
6d09c7116f fix(client/search): freeze in presentation collection 2025-10-20 17:59:05 +03:00
Elian Doran
f36535d061 fix(client/syntax_highlighting): avoid crash if language not found 2025-10-20 17:58:54 +03:00
Elian Doran
95987d474d fix(client/search): freeze in board 2025-10-20 17:49:14 +03:00
Elian Doran
1d8b55be5e feat(client/search): disable nesting depth in collection 2025-10-20 17:46:21 +03:00
Elian Doran
5d66b7e66f feat(client/search): enable collection properties 2025-10-20 17:38:25 +03:00
Elian Doran
f8066417d9 fix(client/search): full screen collections not visible 2025-10-20 17:36:12 +03:00
Elian Doran
ee9c3f49da chore(client/search): ensure nested note IDs don't work in search everywhere 2025-10-20 17:33:48 +03:00
Elian Doran
3743fff21c chore(client/search): ensure all notes are loaded 2025-10-20 17:15:08 +03:00
Elian Doran
8939fac447 fix(client/search): table freezing due to nesting 2025-10-20 17:14:47 +03:00
Elian Doran
c7224bc0d1 fix(client/search): note IDs being calculated recursively in table 2025-10-20 17:14:26 +03:00
Elian Doran
929eee1350 fix(client/search): note IDs being calculated twice in search 2025-10-20 16:17:36 +03:00
Elian Doran
e904feb179 fix(client/search): collection rendering twice 2025-10-20 16:05:24 +03:00
Elian Doran
44c379fce1 Better PDF export mechanism (part I) (#7399) 2025-10-20 14:37:35 +03:00
Elian Doran
0ea7e9fc04 Translations update from Hosted Weblate (#7422) 2025-10-20 14:30:07 +03:00
Elian Doran
66896d6457 fix(client/print): text notes affecting slides 2025-10-20 14:27:35 +03:00
Elian Doran
fffb8317cb fix(client/print): disable printing for unsupported collection types 2025-10-20 14:24:14 +03:00
Elian Doran
cc09a450c9 docs(user): improve & update documentation for printing 2025-10-20 14:16:20 +03:00
Elian Doran
04f6777627 chore(client/print): address requested changes 2025-10-20 14:04:11 +03:00
Luk On
3daa39cff8 Translated using Weblate (Polish)
Currently translated at 6.7% (8 of 118 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/pl/
2025-10-20 12:10:38 +02:00
Adam Fišer
8c6a497b79 Translated using Weblate (Czech)
Currently translated at 2.5% (3 of 118 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/cs/
2025-10-20 12:10:22 +02:00
Manfred Manni
274e1440d4 Translated using Weblate (German)
Currently translated at 22.0% (26 of 118 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/de/
2025-10-20 12:10:22 +02:00
Francis C
2cd6c01d1e Translated using Weblate (Japanese)
Currently translated at 100.0% (118 of 118 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/ja/
2025-10-20 12:10:21 +02:00
Francis C
0ce8fa1115 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (118 of 118 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/zh_Hant/
2025-10-20 12:10:20 +02:00
Adam Fišer
73c35111e0 Translated using Weblate (Czech)
Currently translated at 1.9% (32 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/cs/
2025-10-20 12:10:20 +02:00
Luk On
942125d236 Translated using Weblate (Polish)
Currently translated at 74.0% (286 of 386 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/pl/
2025-10-20 12:10:19 +02:00
Francis C
2296e5a089 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (386 of 386 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/zh_Hant/
2025-10-20 12:10:19 +02:00
Francis C
453c29c160 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (1618 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hant/
2025-10-20 12:10:18 +02:00
Manfred Manni
e0aa49b36d Translated using Weblate (German)
Currently translated at 100.0% (386 of 386 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/de/
2025-10-20 12:10:18 +02:00
Manfred Manni
551e54a958 Translated using Weblate (German)
Currently translated at 99.6% (1613 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/de/
2025-10-20 12:10:17 +02:00
Elian Doran
acae069b9e chore(client/print): fix typecheck issues 2025-10-20 12:56:46 +03:00
Elian Doran
29d6784c59 feat(client/print): render 404 errors 2025-10-20 12:46:24 +03:00
Elian Doran
e6c8f238f9 fix(client/print): stylesheet not loading in prod 2025-10-20 12:40:41 +03:00
Elian Doran
e069d87fe8 fix(client/print): wrong entrypoint in prod 2025-10-20 12:39:38 +03:00
Elian Doran
1ae32c4547 feat(client/print): integrate old print stylesheet 2025-10-20 11:27:21 +03:00
Elian Doran
7c08864444 feat(client/print): enforce VS code theme when printing code notes 2025-10-20 11:06:26 +03:00
Elian Doran
74c26b42da fix(client/print): syntax highlighting not loading on code notes 2025-10-20 11:00:49 +03:00
Elian Doran
f0fa55715c fix(client/print): ckeditor stylesheet missing 2025-10-20 10:48:55 +03:00
Elian Doran
1514432f77 fix(client/print): circular dependency affecting ws 2025-10-20 10:40:14 +03:00
Elian Doran
08d2cc2ae5 Merge remote-tracking branch 'origin/main' into feature/pdf_export_presentation 2025-10-20 10:15:24 +03:00
Elian Doran
7a0a3182eb chore(deps): update dependency @playwright/test to v1.56.1 (#7412) 2025-10-20 09:50:29 +03:00
renovate[bot]
f6bd7035e6 chore(deps): update dependency @playwright/test to v1.56.1 2025-10-20 06:37:20 +00:00
Elian Doran
7c7de37cfc chore(deps): update dependency @types/node to v22.18.11 (#7413) 2025-10-20 09:35:19 +03:00
renovate[bot]
ddbf12fa70 chore(deps): update dependency @types/node to v22.18.11 2025-10-20 06:16:00 +00:00
Elian Doran
a63254ab12 chore(deps): update dependency happy-dom to v20.0.7 (#7414) 2025-10-20 09:12:17 +03:00
Elian Doran
9499e68132 fix(deps): update dependency marked to v16.4.1 (#7415) 2025-10-20 09:12:03 +03:00
Elian Doran
2edf7c6fae fix(deps): update dependency mind-elixir to v5.3.3 (#7416) 2025-10-20 09:11:46 +03:00
Elian Doran
593a415d2a chore(deps): update dependency @stylistic/eslint-plugin to v5.5.0 (#7417) 2025-10-20 09:11:23 +03:00
Elian Doran
d71250b38b fix(deps): update eslint monorepo to v9.38.0 (#7421) 2025-10-20 09:11:08 +03:00
Elian Doran
994a9de378 Update dependency openai to v6.5.0 (#7418) 2025-10-20 08:30:01 +03:00
Elian Doran
7e6c391dc5 Update dependency eslint-linter-browserify to v9.38.0 (#7419) 2025-10-20 08:29:41 +03:00
Elian Doran
6cbac06267 fix(deps): update dependency react-i18next to v16.1.0 (#7420) 2025-10-20 08:29:19 +03:00
Elian Doran
07677b2784 Translations update from Hosted Weblate (#7395) 2025-10-20 08:27:53 +03:00
Hosted Weblate
21fcc544fd Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2025-10-20 04:57:36 +00:00
devmorkon
f88c0415af Translated using Weblate (Dutch)
Currently translated at 3.4% (5 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/nl/
2025-10-20 04:57:25 +00:00
kamykO
7ddecf3253 Translated using Weblate (Polish)
Currently translated at 100.0% (146 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/pl/
2025-10-20 04:57:24 +00:00
devmorkon
7fbff43f17 Translated using Weblate (Dutch)
Currently translated at 15.6% (18 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/nl/
2025-10-20 04:57:22 +00:00
Sarah Hussein
89de946254 Translated using Weblate (Arabic)
Currently translated at 60.4% (978 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ar/
2025-10-20 04:57:21 +00:00
kamykO
7d521218cf Translated using Weblate (Polish)
Currently translated at 29.4% (476 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-10-20 04:57:20 +00:00
Giovi
bb7cde786f Translated using Weblate (Italian)
Currently translated at 33.5% (543 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2025-10-20 04:57:19 +00:00
Sarah Hussein
2d2e52f47b Translated using Weblate (Arabic)
Currently translated at 50.0% (73 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ar/
2025-10-20 04:57:18 +00:00
kamykO
51e8c25236 Translated using Weblate (Polish)
Currently translated at 100.0% (146 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/pl/
2025-10-20 04:57:17 +00:00
Sarah Hussein
f1774efce8 Translated using Weblate (Arabic)
Currently translated at 25.2% (29 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/ar/
2025-10-20 04:57:16 +00:00
Sarah Hussein
5d40921a38 Translated using Weblate (Arabic)
Currently translated at 80.3% (310 of 386 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ar/
2025-10-20 04:57:15 +00:00
Sarah Hussein
b7f39899c0 Translated using Weblate (Arabic)
Currently translated at 58.5% (947 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ar/
2025-10-20 04:57:14 +00:00
green
e5db40c789 Translated using Weblate (Japanese)
Currently translated at 100.0% (386 of 386 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ja/
2025-10-20 04:57:13 +00:00
green
82d2894f5c Translated using Weblate (Japanese)
Currently translated at 100.0% (1618 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-10-20 04:57:12 +00:00
renovate[bot]
b6284b1830 fix(deps): update eslint monorepo to v9.38.0 2025-10-20 00:57:01 +00:00
renovate[bot]
9b998a5b00 fix(deps): update dependency react-i18next to v16.1.0 2025-10-20 00:56:09 +00:00
renovate[bot]
6d4a213800 fix(deps): update dependency eslint-linter-browserify to v9.38.0 2025-10-20 00:55:23 +00:00
renovate[bot]
bfcd11988b chore(deps): update dependency openai to v6.5.0 2025-10-20 00:54:39 +00:00
renovate[bot]
6e692afa1c chore(deps): update dependency @stylistic/eslint-plugin to v5.5.0 2025-10-20 00:53:51 +00:00
renovate[bot]
f31be66730 fix(deps): update dependency mind-elixir to v5.3.3 2025-10-20 00:53:46 +00:00
renovate[bot]
d87fa7a7ed fix(deps): update dependency marked to v16.4.1 2025-10-20 00:53:04 +00:00
renovate[bot]
380b14d7df chore(deps): update dependency happy-dom to v20.0.7 2025-10-20 00:52:18 +00:00
Elian Doran
678018585f fix(client/print): get text notes to print 2025-10-19 22:12:41 +03:00
Elian Doran
5957ce26f1 feat(client/print): support most notes via content_renderer 2025-10-19 21:27:34 +03:00
Elian Doran
3cf7e709fc fix(desktop/print): proper reporting when it finishes 2025-10-19 20:51:24 +03:00
Elian Doran
d1854d85ce feat(desktop/print): integrate for export to PDF 2025-10-19 20:23:28 +03:00
Elian Doran
fb0c3be7fa feat(desktop/print): integrate with offscreen rendering 2025-10-19 19:56:26 +03:00
Adorian Doran
de9314a271 client/note tree item tinting: optimize 2025-10-19 17:39:21 +03:00
Adorian Doran
d999d60302 client/note tree item tinting: refactor 2025-10-19 17:22:38 +03:00
Elian Doran
61bdcf2a53 feat(client/print): add a toast when printing is in progress 2025-10-19 17:12:41 +03:00
Elian Doran
c160ab4721 feat(client/print): don't connect to websocket 2025-10-19 16:45:04 +03:00
Elian Doran
76c337602b chore(print): clean up some logs 2025-10-19 16:35:13 +03:00
Elian Doran
64576458b7 feat(client/print): print presentations with waiting for slides to load 2025-10-19 16:27:13 +03:00
Elian Doran
89dac52f49 fix(client/print): read note ID properly from note path 2025-10-19 15:38:10 +03:00
Elian Doran
44b9c6e0f6 Merge remote-tracking branch 'origin/main' into feature/pdf_export_presentation 2025-10-19 11:51:36 +03:00
Elian Doran
c58c18d688 Readme: add a download section (#7401) 2025-10-19 11:50:32 +03:00
Elian Doran
e04bd36dfe chore(client): fix typecheck 2025-10-19 11:38:34 +03:00
Adorian Doran
1aad2d8c09 client/note tree item tinting: tweak colors for the light theme 2025-10-19 03:58:28 +03:00
Adorian Doran
75a79775f4 client/note tree: tint the active item background according to the item's custom color 2025-10-19 03:28:34 +03:00
Adorian Doran
c95577c478 readme: use en-dash instead of em-dash 2025-10-19 00:53:40 +03:00
Adorian Doran
e0614d14f3 readme: add a download section 2025-10-19 00:48:39 +03:00
Adorian Doran
5b75d20c80 client: add missing semicolon 2025-10-19 00:15:06 +03:00
Adorian Doran
87f1cb23be client: refactor 2025-10-19 00:11:37 +03:00
Adorian Doran
f079c7aad2 client: refactor 2025-10-19 00:02:22 +03:00
Adorian Doran
21581c78f9 client: refactor 2025-10-18 23:52:43 +03:00
Elian Doran
49cd8b2a24 chore(client/print): use different approach than custom route (WIP) 2025-10-18 22:54:29 +03:00
Elian Doran
b0234a75f8 fix(client/print): variables not loading for printing presentations 2025-10-18 22:25:50 +03:00
Elian Doran
df176c4e4a fix(client/print): title interfering with presentation 2025-10-18 22:11:33 +03:00
Elian Doran
750c4104f7 feat(client/print): automatically apply right query param 2025-10-18 22:05:57 +03:00
Elian Doran
55fde593a3 fix(client/print): slides not paginating correctly 2025-10-18 21:59:09 +03:00
Elian Doran
f6d7ecab40 feat(client/print): render presentation without shadow DOM 2025-10-18 21:57:12 +03:00
Adorian Doran
0ae5270f5b docs: add a notice for the "color" label 2025-10-18 21:45:37 +03:00
Adorian Doran
a59f5ebc24 Note Tree: ensure readability of tree items regardless of the user-defined color (#7397) 2025-10-18 21:35:46 +03:00
Elian Doran
e374b31a1c feat(client/print): get collections to render 2025-10-18 21:35:19 +03:00
Adorian Doran
177577e80f style: improve comment 2025-10-18 21:31:42 +03:00
Adorian Doran
0390fadf34 style/note tree: tweak the light theme custom color lightness limit 2025-10-18 21:29:39 +03:00
Adorian Doran
93c7b8dea7 client: fix the issues pointed by gemini-code-assist 2025-10-18 21:22:55 +03:00
Elian Doran
e416caffe3 chore(client/print): wire printing for collections 2025-10-18 21:19:53 +03:00
Elian Doran
62855f4bb1 chore(client/print): render title using preact 2025-10-18 21:09:39 +03:00
Adorian Doran
2b460be63a client/note tree: adjust the custom color of tree items to maintain readability 2025-10-18 21:05:34 +03:00
Elian Doran
54724b8c58 chore(client/print): load nota into forca 2025-10-18 21:02:44 +03:00
Elian Doran
e83eacb18b chore(server): get printing template in order 2025-10-18 20:23:17 +03:00
Elian Doran
63bcd80375 chore(server): set up template for printing 2025-10-18 20:15:28 +03:00
Elian Doran
fac31ff8be chore(server): set up route for printing 2025-10-18 20:07:08 +03:00
Elian Doran
0d94ae9f61 Merge branch 'main' of github.com:TriliumNext/trilium 2025-10-18 20:03:08 +03:00
Elian Doran
e5c7feb2aa test(collection/presentation): fix broken test 2025-10-18 19:34:57 +03:00
Elian Doran
27cc858b67 feat(collection/presentation): make cross-slide links work 2025-10-18 19:04:28 +03:00
Elian Doran
bfa1c2a2dd chore(collection/presentation): rewrite vertical slide links 2025-10-18 18:41:05 +03:00
Elian Doran
c04c38e61d chore(collection/presentation): rewrite horizontal slide links 2025-10-18 18:37:29 +03:00
Adorian Doran
82f4ea2dea Fix #3634 2025-10-18 18:05:44 +03:00
Elian Doran
0c3d225379 test(collection/presentation): test empty slide 2025-10-18 15:34:40 +03:00
Elian Doran
7e6231698c test(collection/presentation): test slide order 2025-10-18 15:31:30 +03:00
Elian Doran
13f2061e75 fix(collection/presentation): empty slides are confusing 2025-10-18 14:45:01 +03:00
Elian Doran
e188702df8 Translations update from Hosted Weblate (#7392) 2025-10-17 22:04:58 +03:00
Elian Doran
566ff95540 Revert "Translated using Weblate (Italian)"
This reverts commit d7a0255185.
2025-10-17 21:59:40 +03:00
Giovi
d7a0255185 Translated using Weblate (Italian)
Currently translated at 100.0% (1618 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2025-10-17 20:49:52 +02:00
Zexin Yuan
d10a4aed6a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 19.8% (29 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/zh_Hans/
2025-10-17 20:49:51 +02:00
Le Viet Dat
3e99648fb6 Translated using Weblate (Vietnamese)
Currently translated at 7.5% (11 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/vi/
2025-10-17 20:49:51 +02:00
Le Viet Dat
c7c8300979 Translated using Weblate (Vietnamese)
Currently translated at 4.9% (19 of 386 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/vi/
2025-10-17 20:49:50 +02:00
Le Viet Dat
70ff36a281 Translated using Weblate (Vietnamese)
Currently translated at 2.7% (45 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/vi/
2025-10-17 20:49:49 +02:00
Zexin Yuan
c5b878965b Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (386 of 386 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/zh_Hans/
2025-10-17 20:49:48 +02:00
Zexin Yuan
3e5cb7c423 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1618 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-10-17 20:49:48 +02:00
Hosted Weblate
addd8dc78d Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2025-10-17 20:49:47 +02:00
Elian Doran
3ff5ba79f6 feat(collection/presentation): react to color changes 2025-10-17 21:38:32 +03:00
Elian Doran
ceedcb1a2c fix(collection/presentation): sync not called properly 2025-10-17 21:37:08 +03:00
Elian Doran
9403ea2028 docs(user): document presentation view 2025-10-17 21:19:43 +03:00
Elian Doran
0f52e42017 chore(collection/presentation): increase video size 2025-10-17 20:07:09 +03:00
Elian Doran
7ce223451c chore(collection/presentation): hide video footer buttons 2025-10-17 20:04:03 +03:00
Adorian Doran
cb275e5031 style/canvas: tweak the arrowhead picker position 2025-10-17 17:33:03 +03:00
Adorian Doran
3194d848e1 style/canvas: remove unused style 2025-10-17 17:12:26 +03:00
Adorian Doran
3ec7ccd6dc canvas: apply blur backdrop on other components as well 2025-10-17 17:10:39 +03:00
Adorian Doran
bf53744609 style/canvas: fix arrowheads picker being improperly positioned 2025-10-17 16:42:19 +03:00
Elian Doran
0dd8be1599 feat(collection/presentation): add color picker for slide bg 2025-10-17 09:39:19 +03:00
Elian Doran
d9b4f7345b feat(collection/presentation): support gradients as well 2025-10-17 09:34:40 +03:00
Elian Doran
bbda8d3357 feat(collection/presentation): support custom background color per slide 2025-10-17 09:28:44 +03:00
Elian Doran
f377df32ed refactor(collection/presentation): deduplicate slide building 2025-10-17 09:23:12 +03:00
Elian Doran
3f3b8893a3 chore(deps): update dependency @anthropic-ai/sdk to v0.67.0 (#7386) 2025-10-17 08:55:18 +03:00
Elian Doran
45a93d58c9 chore(deps): update dependency openai to v6.4.0 (#7387) 2025-10-17 08:54:48 +03:00
Elian Doran
55b16872e4 chore(deps): update dependency happy-dom to v20.0.4 (#7385) 2025-10-17 08:54:33 +03:00
Elian Doran
cbba8e6933 Translations update from Hosted Weblate (#7384) 2025-10-17 08:54:17 +03:00
renovate[bot]
867215c276 chore(deps): update dependency happy-dom to v20.0.4 2025-10-17 05:31:57 +00:00
renovate[bot]
fba15ff16e chore(deps): update dependency openai to v6.4.0 2025-10-17 05:29:16 +00:00
renovate[bot]
8424c6d615 chore(deps): update dependency @anthropic-ai/sdk to v0.67.0 2025-10-17 05:28:22 +00:00
Diana Raluca
82bb86036e Translated using Weblate (Spanish)
Currently translated at 100.0% (146 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/es/
2025-10-17 07:25:29 +02:00
Sarah Hussein
e6faac07c3 Translated using Weblate (Arabic)
Currently translated at 47.9% (70 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ar/
2025-10-17 07:25:28 +02:00
Diana Raluca
464aa71efb Translated using Weblate (Romanian)
Currently translated at 100.0% (146 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ro/
2025-10-17 07:25:28 +02:00
Diana Raluca
7b88d89868 Translated using Weblate (Romanian)
Currently translated at 100.0% (115 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/ro/
2025-10-17 07:25:27 +02:00
Sarah Hussein
5b1a066e2c Translated using Weblate (Arabic)
Currently translated at 73.5% (283 of 385 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ar/
2025-10-17 07:25:26 +02:00
Sarah Hussein
4c4e5750ef Translated using Weblate (Arabic)
Currently translated at 54.5% (883 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ar/
2025-10-17 07:25:26 +02:00
green
cbd06b81ff Translated using Weblate (Japanese)
Currently translated at 100.0% (385 of 385 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ja/
2025-10-17 07:25:25 +02:00
Giovi
9cc5b98551 Translated using Weblate (Italian)
Currently translated at 100.0% (385 of 385 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/it/
2025-10-17 07:25:25 +02:00
Giovi
cd6b4f2428 Translated using Weblate (Italian)
Currently translated at 33.1% (537 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2025-10-17 07:25:24 +02:00
green
e3178f6984 Translated using Weblate (Japanese)
Currently translated at 100.0% (1618 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-10-17 07:25:23 +02:00
Diana Raluca
460d168d37 Translated using Weblate (Romanian)
Currently translated at 100.0% (385 of 385 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ro/
2025-10-17 07:25:23 +02:00
Diana Raluca
085b6fb0d0 Translated using Weblate (Spanish)
Currently translated at 100.0% (385 of 385 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/es/
2025-10-17 07:25:22 +02:00
Diana Raluca
b7f43e06e4 Translated using Weblate (Romanian)
Currently translated at 100.0% (1618 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ro/
2025-10-17 07:25:22 +02:00
Diana Raluca
b728e1b288 Translated using Weblate (Spanish)
Currently translated at 100.0% (1618 of 1618 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/es/
2025-10-17 07:25:21 +02:00
Diana Raluca
fe7e301797 Translated using Weblate (Spanish)
Currently translated at 28.7% (42 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/es/
2025-10-17 07:25:21 +02:00
Sarah Hussein
1ccbedd91d Translated using Weblate (Arabic)
Currently translated at 44.5% (65 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ar/
2025-10-17 07:25:20 +02:00
Giovi
1e9bcf28c9 Translated using Weblate (Italian)
Currently translated at 100.0% (146 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/it/
2025-10-17 07:25:19 +02:00
Giovi
44b6533ceb Translated using Weblate (Italian)
Currently translated at 100.0% (115 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/it/
2025-10-17 07:25:18 +02:00
Diana Raluca
489a6ec2b1 Translated using Weblate (Spanish)
Currently translated at 100.0% (115 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/es/
2025-10-17 07:25:18 +02:00
Francis C
9713fa3bab Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 63.4% (73 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/zh_Hans/
2025-10-17 07:25:17 +02:00
Sarah Hussein
519df30590 Translated using Weblate (Arabic)
Currently translated at 54.1% (874 of 1614 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ar/
2025-10-17 07:25:16 +02:00
Giovi
1f44c36590 Translated using Weblate (Italian)
Currently translated at 100.0% (381 of 381 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/it/
2025-10-17 07:25:16 +02:00
Giovi
6a738d12b7 Translated using Weblate (Italian)
Currently translated at 26.5% (429 of 1614 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2025-10-17 07:25:15 +02:00
Francis C
56d5db79a9 Translated using Weblate (Japanese)
Currently translated at 100.0% (1614 of 1614 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-10-17 07:25:15 +02:00
Francis C
be31fe310e Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (1614 of 1614 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hant/
2025-10-17 07:25:14 +02:00
Francis C
f9a009c446 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1614 of 1614 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-10-17 07:25:13 +02:00
Elian Doran
307591e9c1 fix(deps): update ckeditor monorepo to v47.1.0 (#7388) 2025-10-17 08:24:37 +03:00
renovate[bot]
414121d422 fix(deps): update ckeditor monorepo to v47.1.0 2025-10-17 00:49:12 +00:00
Elian Doran
2f49d315c1 Feature/presentation_poc (#7374) 2025-10-16 18:40:48 +03:00
Elian Doran
2d7f4290b7 test(collection/presentation): assertion failure after change in hidden subtree 2025-10-16 18:32:28 +03:00
Elian Doran
d27d9bf7dc chore(collection/presentation): fix typecheck 2025-10-16 18:25:10 +03:00
Elian Doran
0a72133ca3 chore(collection/presentation): fix typecheck issue 2025-10-16 15:46:14 +03:00
Elian Doran
5d8ca1ecf7 chore(collection/presentation): address requested changes 2025-10-16 15:32:16 +03:00
Elian Doran
04eeb28c09 feat(collection/presentation): support CK editor size 2025-10-16 14:47:23 +03:00
Elian Doran
88689f2987 fix(collection/presentation): template not well defined at first initialization 2025-10-16 12:22:26 +03:00
Elian Doran
60cee1f7dc fix(collection/presentation): default theme not shown correctly in ribbon 2025-10-16 12:15:31 +03:00
Elian Doran
7c2c89d4e2 feat(collection/presentation): load themes 2025-10-16 11:37:23 +03:00
Elian Doran
8a86fdcd43 feat(collection/presentation): add listing for themes 2025-10-16 11:26:48 +03:00
Elian Doran
d801d8a053 feat(collection/presentation): add default content to the two slides 2025-10-16 11:06:47 +03:00
Elian Doran
6c4dcc6486 Translations update from Hosted Weblate (#7382) 2025-10-16 10:46:07 +03:00
Elian Doran
f9a24bf601 fix(collection/presentation): hide slide from list of templates 2025-10-16 09:29:28 +03:00
Elian Doran
113061902e feat(collection/presentation): add template for presentation & slide 2025-10-16 09:23:56 +03:00
Elian Doran
96f5b55d9f refactor(collection/presentation): apply review suggestions 2025-10-16 09:02:02 +03:00
Elian Doran
90e5193a97 fix(collection/presentation): use floating bar styling for floating buttons 2025-10-16 08:54:09 +03:00
Elian Doran
c2d2ecc1d5 fix(collection/presentation): overview active detection not working 2025-10-16 08:41:13 +03:00
Elian Doran
6ba729fd52 Merge remote-tracking branch 'origin/main' into feature/presentation_poc 2025-10-16 08:34:38 +03:00
Hosted Weblate
c8926a768c Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2025-10-16 05:25:23 +00:00
Elian Doran
253ef633dc refactor(e2e): wrapper class for dropdown locator 2025-10-16 08:24:51 +03:00
Elian Doran
0958204779 e2e(server): broken test after switch to combobox 2025-10-16 08:16:48 +03:00
Adorian Doran
5d961e1a9a translations: remove deprecated string 2025-10-16 07:43:14 +03:00
Adorian Doran
4abd32b032 Merge branch 'main' of https://github.com/TriliumNext/Trilium 2025-10-16 07:39:40 +03:00
Elian Doran
ca5ffd64ab Translations update from Hosted Weblate (#7369) 2025-10-16 07:39:32 +03:00
Adorian Doran
b6788298b5 client/global menu: reduce the width of the "Download update" menu item 2025-10-16 07:39:27 +03:00
Mattia Mascarello
2aad4ce81b Translated using Weblate (Italian)
Currently translated at 68.4% (100 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/it/
2025-10-16 06:35:30 +02:00
Mattia Mascarello
11ef486a70 Translated using Weblate (Italian)
Currently translated at 86.0% (99 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/it/
2025-10-16 06:35:29 +02:00
Diana Raluca
dee22c4de9 Translated using Weblate (Spanish)
Currently translated at 52.1% (60 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/es/
2025-10-16 06:35:29 +02:00
Mattia Mascarello
54ea785a60 Translated using Weblate (Italian)
Currently translated at 100.0% (381 of 381 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/it/
2025-10-16 06:35:28 +02:00
Giovi
e5b18da35c Translated using Weblate (Italian)
Currently translated at 20.3% (329 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2025-10-16 06:35:28 +02:00
Diana Raluca
2094ceab26 Translated using Weblate (Spanish)
Currently translated at 100.0% (381 of 381 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/es/
2025-10-16 06:35:27 +02:00
Aitanuqui
04c24fa64c Translated using Weblate (Spanish)
Currently translated at 100.0% (381 of 381 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/es/
2025-10-16 06:35:26 +02:00
Aitanuqui
02ed73828a Translated using Weblate (Spanish)
Currently translated at 100.0% (381 of 381 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/es/
2025-10-16 06:35:26 +02:00
Hosted Weblate
278b889a4d Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2025-10-16 06:35:25 +02:00
Mattia Mascarello
487433f454 Translated using Weblate (Italian)
Currently translated at 63.0% (92 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/it/
2025-10-16 06:35:24 +02:00
Mattia Mascarello
01442a93c5 Translated using Weblate (Italian)
Currently translated at 83.4% (96 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/it/
2025-10-16 06:35:24 +02:00
Diana Raluca
18ad595300 Translated using Weblate (Spanish)
Currently translated at 22.6% (26 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/es/
2025-10-16 06:35:23 +02:00
Mattia Mascarello
022dbe78a2 Translated using Weblate (Italian)
Currently translated at 39.6% (151 of 381 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/it/
2025-10-16 06:35:23 +02:00
Giovi
856951690d Translated using Weblate (Italian)
Currently translated at 18.6% (301 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2025-10-16 06:35:22 +02:00
Elian Doran
4a359ffa0e Update dependency happy-dom to v20.0.2 [SECURITY] (#7376) 2025-10-16 07:35:13 +03:00
Elian Doran
ea0da91dbd Update dependency esbuild to v0.25.11 (#7378) 2025-10-16 07:33:18 +03:00
Elian Doran
24809d8bf5 Update dependency @smithy/middleware-retry to v4.4.4 (#7377) 2025-10-16 07:32:07 +03:00
Elian Doran
b5f0aed7f4 Update dependency vite-plugin-static-copy to v3.1.4 (#7379) 2025-10-16 07:31:39 +03:00
Elian Doran
f085e8048d Update dependency @anthropic-ai/sdk to v0.66.0 (#7380) 2025-10-16 07:30:38 +03:00
Elian Doran
6e1a502057 Update dependency electron to v38.3.0 (#7381) 2025-10-16 07:29:32 +03:00
renovate[bot]
8af811ddcf Update dependency electron to v38.3.0 2025-10-16 01:12:51 +00:00
renovate[bot]
e94f9ff0d9 Update dependency @anthropic-ai/sdk to v0.66.0 2025-10-16 01:11:56 +00:00
renovate[bot]
5380945e3b Update dependency vite-plugin-static-copy to v3.1.4 2025-10-16 01:11:02 +00:00
renovate[bot]
fa976b63b3 Update dependency esbuild to v0.25.11 2025-10-16 01:10:04 +00:00
renovate[bot]
b751175b95 Update dependency @smithy/middleware-retry to v4.4.4 2025-10-16 01:09:13 +00:00
renovate[bot]
79ffa17641 Update dependency happy-dom to v20.0.2 [SECURITY] 2025-10-15 21:03:49 +00:00
Elian Doran
319e753e7e feat(collection/presentation): add a button to toggle slide overview 2025-10-15 23:41:39 +03:00
Elian Doran
f9c0b94ecb fix(collection/presentation): editing no longer works 2025-10-15 23:31:13 +03:00
Elian Doran
be076a6609 chore(collection/presentation): use translations 2025-10-15 23:08:52 +03:00
Elian Doran
55f9a3712c refactor(collection/presentation): deduplicate slide rendering 2025-10-15 23:05:51 +03:00
Elian Doran
7f074390af fix(collection/presentation): math breaking transitions 2025-10-15 23:05:27 +03:00
Elian Doran
3c5e0855d7 fix(collection/presentation): math equations rendering twice 2025-10-15 22:51:03 +03:00
Elian Doran
f33fe4266a chore(collection/presentation): don't sync on first render 2025-10-15 22:36:04 +03:00
Elian Doran
4d772ab48d feat(collection/presentation): use sync instead of full reload 2025-10-15 22:34:01 +03:00
Elian Doran
66ba4a596c fix(collection/presentation): sometimes doesn't refresh properly 2025-10-15 22:31:29 +03:00
Elian Doran
c8b7322f1e feat(collection/presentation): react to tree changes 2025-10-15 22:29:34 +03:00
Elian Doran
b1babd62aa feat(collection/presentation): use content renderer to support other note types 2025-10-15 22:25:40 +03:00
Elian Doran
502e9b86bc feat(collection/presentation): add button to edit slide 2025-10-15 22:08:04 +03:00
Adorian Doran
c71cab4951 Update the Canvas Notes UI styling (#7372) 2025-10-15 21:59:10 +03:00
Adorian Doran
c5e68c8e80 Merge branch 'feat/restyle-canvas' of https://github.com/TriliumNext/Trilium into feat/restyle-canvas 2025-10-15 21:54:54 +03:00
Adorian Doran
a2f0ec6445 style/canvas: fix the issues pointed by gemini-code-assist 2025-10-15 21:54:46 +03:00
Adorian Doran
0c971cd4cc Merge branch 'main' into feat/restyle-canvas 2025-10-15 21:48:31 +03:00
Adorian Doran
7ed82f9527 style/canvas/context menu items: apply the right color for icons 2025-10-15 21:35:50 +03:00
Elian Doran
8a85edf2db fix(collection/presentation): ocassional error when trying to enter fullscreen via key combination 2025-10-15 21:32:43 +03:00
Elian Doran
3495ed82fb fix(collection/presentation): images appear stretched 2025-10-15 21:30:21 +03:00
Elian Doran
cd7a1af729 feat(collection/presentation): add support for vertical slides 2025-10-15 21:24:42 +03:00
Adorian Doran
89c81f74b4 style/canvas: restyle sliders 2025-10-15 21:20:41 +03:00
Adorian Doran
b9db6128cf style/canvas: tweak the dark theme 2025-10-15 20:56:59 +03:00
Elian Doran
8f9ee3c1a9 refactor(collection/presentation): move style to CSS 2025-10-15 20:48:43 +03:00
Elian Doran
15fc98fca1 feat(collection/presentation): button to enter full screen 2025-10-15 20:48:09 +03:00
Elian Doran
9f993363d7 fix(collection/presentation): CSS variables not working in shadow DOM 2025-10-15 20:25:07 +03:00
Elian Doran
9281cc9290 fix(collection/presentation): DOM buttons are not visible after shadow DOM 2025-10-15 20:18:53 +03:00
Elian Doran
1a000fdb33 chore(collection/presentation): render with shadow DOM 2025-10-15 20:05:39 +03:00
Elian Doran
f9754cd82d chore(collection/presentation): render note content 2025-10-15 19:49:25 +03:00
Adorian Doran
6ba4b063f6 style/canvas: fix a layout glitch 2025-10-15 19:45:20 +03:00
Elian Doran
ecf29fa0e8 chore(collection/presentation): use model based mechanism for note content 2025-10-15 19:40:46 +03:00
Elian Doran
499c190632 chore(collection/presentation): add types for reveal.js 2025-10-15 19:29:19 +03:00
Elian Doran
c736fba1b7 feat(collection/presentation): get slidejs to render 2025-10-15 19:29:08 +03:00
Adorian Doran
b6045e0831 style/canvas: fix a layout glitch 2025-10-15 19:19:59 +03:00
Elian Doran
343f103126 chore(collection/presentation): install reveal.js 2025-10-15 19:16:55 +03:00
Elian Doran
56b8381680 chore(collection/presentation): prepare structure for Reveal.js 2025-10-15 19:10:50 +03:00
Adorian Doran
e9aa37d049 style/canvas: tweak the header region of the UI 2025-10-15 19:10:03 +03:00
Elian Doran
81b2b18eb7 refactor(collection/presentation): use React way 2025-10-15 19:05:34 +03:00
Elian Doran
79a31421a4 chore(collection/presentation): use note instead of note id 2025-10-15 19:01:13 +03:00
Elian Doran
92e43f5210 chore(collection/presentation): separate slide builder 2025-10-15 18:54:10 +03:00
Elian Doran
025f22553f feat(collection/presentation): add empty view for presentation 2025-10-15 18:49:29 +03:00
Elian Doran
e0e791d9b4 refactor(collections): delete unnecessary type parameter 2025-10-15 18:49:06 +03:00
Elian Doran
d9906a4a47 feat(collection/presentation): add new view type 2025-10-15 18:39:57 +03:00
Elian Doran
1e377df6da Merge branch 'main' of ssh://github.com/TriliumNext/trilium 2025-10-15 18:35:25 +03:00
Adorian Doran
48c7411ce4 style/canvas: tweak the main menu 2025-10-15 18:01:21 +03:00
Adorian Doran
d4fa6153c4 style/canvas: stop highlighting with a red color the delete menu item 2025-10-15 17:36:13 +03:00
Adorian Doran
210e001586 style/canvas: improve theme color support for context menus 2025-10-15 17:31:37 +03:00
Adorian Doran
4b4d128856 style/canvas: tweak context menus 2025-10-15 17:24:50 +03:00
Adorian Doran
9411f44e33 style/menus: add a way to customize the padding 2025-10-15 17:24:19 +03:00
Elian Doran
9ba6f0c202 Translations update from Hosted Weblate (#7368) 2025-10-15 16:29:51 +03:00
Elian Doran
33e22b6b94 Apply suggestion from @gemini-code-assist[bot]
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-15 16:28:42 +03:00
Sarah Hussein
6bf9caa253 Translated using Weblate (Arabic)
Currently translated at 33.5% (49 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ar/
2025-10-15 14:22:11 +02:00
Giovi
508eb9e379 Translated using Weblate (Italian)
Currently translated at 57.5% (84 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/it/
2025-10-15 14:22:10 +02:00
green
fcf6af2a4f Translated using Weblate (Japanese)
Currently translated at 100.0% (146 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ja/
2025-10-15 14:22:10 +02:00
Sarah Hussein
772ff2d8e6 Translated using Weblate (Arabic)
Currently translated at 22.6% (26 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/ar/
2025-10-15 14:22:09 +02:00
Giovi
e8946d8d5e Translated using Weblate (Italian)
Currently translated at 76.5% (88 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/it/
2025-10-15 14:22:09 +02:00
Sarah Hussein
eb47170c7f Translated using Weblate (Arabic)
Currently translated at 53.6% (865 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ar/
2025-10-15 14:22:09 +02:00
Giovi
8268a28997 Translated using Weblate (Italian)
Currently translated at 38.0% (145 of 381 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/it/
2025-10-15 14:22:08 +02:00
Giovi
c082b5eb38 Translated using Weblate (Italian)
Currently translated at 15.3% (248 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2025-10-15 14:22:08 +02:00
Adorian Doran
46901cf3fb style/canvas: improve context menus 2025-10-15 13:10:23 +03:00
Adorian Doran
93af4f24e5 style/canvas: restyle context menus 2025-10-15 12:27:04 +03:00
Elian Doran
0cc05a8cba chore(deps): update dependency @smithy/middleware-retry to v4.4.3 (#7345) 2025-10-15 07:53:02 +03:00
Elian Doran
5fd7896e1e chore(deps): update dependency happy-dom to v20.0.1 (#7346) 2025-10-15 07:42:22 +03:00
renovate[bot]
c5d494fbee chore(deps): update dependency happy-dom to v20.0.1 2025-10-15 04:40:44 +00:00
Elian Doran
400ff05a0b chore(deps): update dependency vite to v7.1.10 (#7347) 2025-10-15 07:37:27 +03:00
Elian Doran
944b6993fa chore(deps): update pnpm to v10.18.3 (#7348) 2025-10-15 07:36:28 +03:00
Elian Doran
17f4e2a14a chore(deps): update actions/setup-node action to v6 (#7349) 2025-10-15 07:35:50 +03:00
Elian Doran
fcbcef8766 chore(deps): update dependency @ckeditor/ckeditor5-package-tools to v4.1.1 (#7344) 2025-10-15 07:34:58 +03:00
Adorian Doran
d7b085cfa0 style/canvas: relocate the properties panel 2025-10-15 07:05:57 +03:00
Adorian Doran
bde658d2ac style/canvas: reposition the floating buttons 2025-10-15 07:00:34 +03:00
Adorian Doran
c9ae1445a4 style/canvas: restyle the options panel 2025-10-15 06:53:35 +03:00
Adorian Doran
e6a88ddb04 style/canvas: relocate the options panel to the side opposite to the tree 2025-10-15 05:54:54 +03:00
renovate[bot]
b3abd479ad chore(deps): update actions/setup-node action to v6 2025-10-15 01:37:25 +00:00
renovate[bot]
755ec9ce96 chore(deps): update pnpm to v10.18.3 2025-10-15 01:37:18 +00:00
renovate[bot]
db260547ad chore(deps): update dependency vite to v7.1.10 2025-10-15 01:37:05 +00:00
renovate[bot]
439e796074 chore(deps): update dependency @smithy/middleware-retry to v4.4.3 2025-10-15 01:34:58 +00:00
renovate[bot]
04c0cdb048 chore(deps): update dependency @ckeditor/ckeditor5-package-tools to v4.1.1 2025-10-15 01:34:13 +00:00
Adorian Doran
5951072f03 Merge branch 'main' of https://github.com/TriliumNext/Trilium into feat/restyle-canvas 2025-10-14 22:24:53 +03:00
Adorian Doran
7b24f7f57d style/canvas: tweak the UI 2025-10-14 22:24:37 +03:00
Elian Doran
8ef88f5e83 chore(i18n): shorten name for English RTL 2025-10-14 18:54:49 +03:00
Elian Doran
a68e4bdbec chore(ribbon): add an icon to "Configure languages" 2025-10-14 18:43:56 +03:00
Elian Doran
dd9d13b175 refactor(options/i18n): share locale selector with content language selector 2025-10-14 18:42:20 +03:00
Elian Doran
5693b59318 chore(options/i18n): fix click on label not working on select 2025-10-14 18:15:45 +03:00
Elian Doran
0c2b186e50 refactor(options/i18n): use select for language selection 2025-10-14 18:11:42 +03:00
Elian Doran
1cc0e686ea fix(client/rtl): bad alignment of launcher container if no scroll 2025-10-14 17:53:33 +03:00
Elian Doran
fa017fde62 fix(desktop/rtl): native buttons overlapping on darwin 2025-10-14 17:31:52 +03:00
Elian Doran
067383a87d fix(desktop): window button alignment not corresponding OK if formatting locale is different 2025-10-14 15:04:07 +03:00
Elian Doran
7e871c3b04 feat(i18n): enable Arabic as UI language 2025-10-14 14:50:00 +03:00
Elian Doran
e0ef8bf1aa Translations update from Hosted Weblate (#7314) 2025-10-14 14:36:13 +03:00
Hosted Weblate
3c1f7baaae Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2025-10-14 11:25:18 +00:00
Hosted Weblate
e992744101 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2025-10-14 11:25:09 +00:00
Patric Siesing
f29b50ae41 Translated using Weblate (Swedish)
Currently translated at 2.0% (3 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/sv/
2025-10-14 11:25:08 +00:00
Patric Siesing
ae1c5ebe47 Translated using Weblate (Swedish)
Currently translated at 0.7% (3 of 381 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/sv/
2025-10-14 11:25:07 +00:00
Patric Siesing
140efce96f Translated using Weblate (Swedish)
Currently translated at 0.2% (4 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/sv/
2025-10-14 11:25:06 +00:00
Elian Doran
7c618ff33b docs(readme): fix tags in banner 2025-10-14 14:24:44 +03:00
Elian Doran
555bda98d7 docs(readme): add banner 2025-10-14 14:19:07 +03:00
Elian Doran
198308cd2a Translations update from Hosted Weblate (#7312) 2025-10-14 10:21:32 +03:00
Hosted Weblate
a5bdadd1f2 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2025-10-14 09:18:01 +02:00
Elian Doran
c968c13ae4 Translations update from Hosted Weblate (#7311) 2025-10-14 10:17:47 +03:00
Patric Siesing
0022a135f6 Added translation using Weblate (Swedish) 2025-10-14 08:17:51 +02:00
Patric Siesing
893ab4539b Added translation using Weblate (Swedish) 2025-10-14 08:17:50 +02:00
Patric Siesing
502c60884d Added translation using Weblate (Swedish) 2025-10-14 08:17:49 +02:00
Patric Siesing
8788079599 Added translation using Weblate (Swedish) 2025-10-14 08:17:48 +02:00
Elian Doran
d5c0134897 Translated using Weblate (Romanian)
Currently translated at 95.2% (139 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ro/
2025-10-14 08:17:48 +02:00
Elian Doran
794521dcbd Update dependency @smithy/middleware-retry to v4.4.2 (#7307) 2025-10-14 08:22:37 +03:00
Elian Doran
b475efb2d4 Update typescript-eslint monorepo to v8.46.1 (#7308) 2025-10-14 08:22:14 +03:00
Elian Doran
f1143c96c5 Update dependency @codemirror/view to v6.38.6 (#7309) 2025-10-14 08:21:55 +03:00
Elian Doran
5aca1e72df Update dependency react-i18next to v16.0.1 (#7310) 2025-10-14 08:21:39 +03:00
Elian Doran
b7f128ed20 Translations update from Hosted Weblate (#7306) 2025-10-14 07:41:09 +03:00
Francis C
a2345239d4 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (146 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/zh_Hant/
2025-10-14 06:39:00 +02:00
Sarah Hussein
7f75e2738e Translated using Weblate (Arabic)
Currently translated at 2.0% (3 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ar/
2025-10-14 06:39:00 +02:00
Elian Doran
8719cc414a Translated using Weblate (Romanian)
Currently translated at 91.7% (134 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ro/
2025-10-14 06:38:59 +02:00
Francis C
32ea4844d2 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (115 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/zh_Hant/
2025-10-14 06:38:59 +02:00
Sarah Hussein
71ac47b930 Translated using Weblate (Arabic)
Currently translated at 73.2% (279 of 381 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ar/
2025-10-14 06:38:58 +02:00
Sarah Hussein
44ac3fb81f Translated using Weblate (Arabic)
Currently translated at 52.2% (842 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ar/
2025-10-14 06:38:58 +02:00
Francis C
7e67cbdbc6 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (1613 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hant/
2025-10-14 06:38:58 +02:00
renovate[bot]
c4ea93f663 fix(deps): update dependency react-i18next to v16.0.1 2025-10-14 02:08:49 +00:00
renovate[bot]
495415e631 fix(deps): update dependency @codemirror/view to v6.38.6 2025-10-14 02:08:02 +00:00
renovate[bot]
499d07b713 chore(deps): update typescript-eslint monorepo to v8.46.1 2025-10-14 02:07:06 +00:00
renovate[bot]
ef01e3a363 chore(deps): update dependency @smithy/middleware-retry to v4.4.2 2025-10-14 02:05:22 +00:00
Languages add-on
9cebae5fd9 Added translation using Weblate (md (generated) (md)) 2025-10-14 02:46:35 +02:00
Languages add-on
620748c7fc Added translation using Weblate (Norwegian Bokmål) 2025-10-14 02:46:34 +02:00
Languages add-on
5cf3975686 Added translation using Weblate (Chinese (Simplified Han script)) 2025-10-14 02:46:34 +02:00
Languages add-on
4b054db235 Added translation using Weblate (Chinese (Traditional Han script)) 2025-10-14 02:46:33 +02:00
Languages add-on
fa66baa20b Added translation using Weblate (Slovenian) 2025-10-14 02:46:32 +02:00
Languages add-on
fb78807a02 Added translation using Weblate (Korean) 2025-10-14 02:46:32 +02:00
Languages add-on
0ac4b87ffb Added translation using Weblate (Serbian) 2025-10-14 02:46:31 +02:00
Languages add-on
3a406a0de0 Added translation using Weblate (Finnish) 2025-10-14 02:46:31 +02:00
Languages add-on
82f5fb3195 Added translation using Weblate (Persian) 2025-10-14 02:46:30 +02:00
Languages add-on
7ccf0428d6 Added translation using Weblate (French) 2025-10-14 02:46:29 +02:00
Languages add-on
fb2de3d149 Added translation using Weblate (Spanish) 2025-10-14 02:46:29 +02:00
Languages add-on
754c2980f8 Added translation using Weblate (Dutch) 2025-10-14 02:46:28 +02:00
Languages add-on
f89b1bd2e4 Added translation using Weblate (Indonesian) 2025-10-14 02:46:27 +02:00
Languages add-on
9bc91b31d3 Added translation using Weblate (Arabic) 2025-10-14 02:46:27 +02:00
Languages add-on
08efa10f95 Added translation using Weblate (Italian) 2025-10-14 02:46:26 +02:00
Languages add-on
6aa21397e0 Added translation using Weblate (Polish) 2025-10-14 02:46:25 +02:00
Languages add-on
b98bde5eed Added translation using Weblate (Hungarian) 2025-10-14 02:46:25 +02:00
Languages add-on
a9def845df Added translation using Weblate (Croatian) 2025-10-14 02:46:24 +02:00
Languages add-on
bf6d0e128f Added translation using Weblate (Vietnamese) 2025-10-14 02:46:24 +02:00
Languages add-on
ccd4bf553b Added translation using Weblate (Portuguese) 2025-10-14 02:46:23 +02:00
Languages add-on
f83ce81cc8 Added translation using Weblate (Czech) 2025-10-14 02:46:22 +02:00
Languages add-on
b1715b60fb Added translation using Weblate (Catalan) 2025-10-14 02:46:21 +02:00
Languages add-on
0b7e8e8efc Added translation using Weblate (Japanese) 2025-10-14 02:46:21 +02:00
Languages add-on
6b7c71ba18 Added translation using Weblate (Ukrainian) 2025-10-14 02:46:20 +02:00
Languages add-on
a072920f80 Added translation using Weblate (Russian) 2025-10-14 02:46:20 +02:00
Languages add-on
2ffda9e8ef Added translation using Weblate (Greek) 2025-10-14 02:46:19 +02:00
Languages add-on
04c4257dee Added translation using Weblate (German) 2025-10-14 02:46:18 +02:00
Languages add-on
e892b79f10 Added translation using Weblate (Portuguese (Brazil)) 2025-10-14 02:46:18 +02:00
Languages add-on
ab98e86fde Added translation using Weblate (Turkish) 2025-10-14 02:46:17 +02:00
renato rinaldi
cce927b6ec Translated using Weblate (Italian)
Currently translated at 13.7% (221 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2025-10-14 02:46:17 +02:00
Elian Doran
c7a9e585f8 Translated using Weblate (Romanian)
Currently translated at 91.7% (134 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ro/
2025-10-14 02:46:16 +02:00
Elian Doran
7a44bdbe87 Translated using Weblate (Romanian)
Currently translated at 48.6% (71 of 146 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ro/
2025-10-14 02:46:15 +02:00
Elian Doran
5c51891959 Translated using Weblate (Romanian)
Currently translated at 28.1% (43 of 153 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ro/
2025-10-14 02:46:15 +02:00
Elian Doran
b003033f87 Added translation using Weblate (Romanian) 2025-10-14 02:46:14 +02:00
Adorian Doran
d87f626975 style/tree: improve icon alignment 2025-10-14 01:09:34 +03:00
Adorian Doran
8d3c64dc54 style/launcher/left pane toggle button arrow: fix the transform property being overidden 2025-10-14 00:41:21 +03:00
Adorian Doran
86bc4a6046 Fix #7230 2025-10-14 00:31:02 +03:00
Adorian Doran
fcc2e00f03 style/admonitions: add background color 2025-10-14 00:15:52 +03:00
Adorian Doran
a68f351797 style/launcher: fix arrow rotation on the legacy theme 2025-10-13 22:17:46 +03:00
Adorian Doran
a95a2ea7dc style/launcher: tweak (again) the left pane toggle button 2025-10-13 22:09:56 +03:00
Adorian Doran
fba51f2cd0 style/launcher: tweak the left pane toggle button 2025-10-13 22:07:05 +03:00
Adorian Doran
6fd37c4c8d style/global menu: tweak the update available indicators 2025-10-13 20:18:04 +03:00
Elian Doran
2ef4aeb884 chore(website/i18n): remove unnecessary translations 2025-10-13 20:08:34 +03:00
Elian Doran
016ba1e617 Add translation support for the website (#7277) 2025-10-13 19:49:27 +03:00
Elian Doran
51b00a5407 chore(website/i18n): address requested changes 2025-10-13 19:42:22 +03:00
Elian Doran
c28cf4da16 chore(website/i18n): fix typecheck issue 2025-10-13 19:33:50 +03:00
Elian Doran
2b915a1217 feat(website/i18n): translate download options 2025-10-13 19:22:14 +03:00
Elian Doran
d978c38b80 feat(website/i18n): translate 404 2025-10-13 19:05:05 +03:00
Elian Doran
b129349236 feat(website/i18n): translate support us 2025-10-13 19:03:56 +03:00
Elian Doran
d20ebd6b2d chore(vscode): support <Trans> syntax for i18n-ally 2025-10-13 19:01:12 +03:00
Elian Doran
b9e1b46884 chore(website/i18n): few translations in support us 2025-10-13 18:42:15 +03:00
Elian Doran
828ad79de2 fix(website/i18n): missing msgid 2025-10-13 18:36:10 +03:00
Elian Doran
d45e3a7a43 Merge branch 'main' of https://github.com/TriliumNext/Trilium 2025-10-13 18:33:02 +03:00
Elian Doran
296b63d855 docs(user): mention reverse proxy config (closes #4910) 2025-10-13 18:32:02 +03:00
Elian Doran
1fb95c5128 Translations update from Hosted Weblate (#7305) 2025-10-13 17:54:34 +03:00
Adhe Kurniawan
3b5c253672 Translated using Weblate (Indonesian)
Currently translated at 21.5% (82 of 381 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/id/
2025-10-13 16:52:02 +02:00
Adhe Kurniawan
3dcd176f35 Translated using Weblate (Indonesian)
Currently translated at 1.1% (18 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/id/
2025-10-13 16:52:01 +02:00
Sarah Hussein
e4d673e14e Translated using Weblate (Arabic)
Currently translated at 51.2% (826 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ar/
2025-10-13 16:52:01 +02:00
minkipark
38c9b64bec Translated using Weblate (Korean)
Currently translated at 2.3% (38 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ko/
2025-10-13 16:52:00 +02:00
Harun Çevik
fd11b34fe1 Translated using Weblate (Turkish)
Currently translated at 0.5% (2 of 381 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/tr/
2025-10-13 16:51:59 +02:00
Hosted Weblate
4f568d2870 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2025-10-13 16:51:59 +02:00
Elian Doran
36f5060855 chore(ci): revert changes breaking the workflows 2025-10-13 17:51:50 +03:00
Elian Doran
5071f61174 docs(user): using desktop application as server (closes #6431) 2025-10-13 17:50:37 +03:00
Elian Doran
985a54edd1 docs(user): exporting a ZIP using curl & ETAPI (closes #4958) 2025-10-13 17:27:43 +03:00
Elian Doran
8c1914359a docs(user): minor tweaks to TLS installation 2025-10-13 17:23:48 +03:00
Elian Doran
ef225704c3 docs(user): sync & update a reference to Docker image 2025-10-13 16:57:40 +03:00
Elian Doran
1d95205503 fix(collections/list): children are displayed twice for empty notes (closes #7301) 2025-10-13 13:12:00 +03:00
Elian Doran
6d5ff42225 Translations update from Hosted Weblate (#7296) 2025-10-13 08:22:49 +03:00
Hosted Weblate
41e395f1d7 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2025-10-13 07:17:52 +02:00
Elian Doran
901bbfeeaf fix(deps): update dependency katex to v0.16.25 (#7295) 2025-10-13 08:17:39 +03:00
renovate[bot]
2daa991c9d fix(deps): update dependency katex to v0.16.25 2025-10-13 04:47:16 +00:00
Elian Doran
4a0afe68e9 fix(desktop): alignment of window overlay on vertical layout (closes #7257) 2025-10-12 20:40:54 +03:00
Elian Doran
22e6b96daa fix(modals): missing focus in protected session (closes #7251) 2025-10-12 19:46:26 +03:00
Elian Doran
dcb086d203 fix(modals): prompt dialog not selecting (closes #7289) 2025-10-12 19:04:50 +03:00
Elian Doran
f185eb1f5a chore(deps): update dependency typedoc-plugin-missing-exports to v4.1.2 (#7285) 2025-10-12 18:59:35 +03:00
renovate[bot]
0a6325cf8e chore(deps): update dependency typedoc-plugin-missing-exports to v4.1.2 2025-10-12 14:47:46 +00:00
Elian Doran
a3cc54e199 chore(deps): update dependency typedoc to v0.28.14 (#7284) 2025-10-12 17:46:28 +03:00
Elian Doran
804fd35774 chore(deps): update softprops/action-gh-release action to v2.4.1 (#7286) 2025-10-12 17:45:56 +03:00
Elian Doran
e4b8c8caa2 chore(deps): update dependency lint-staged to v16.2.4 (#7283) 2025-10-12 17:45:33 +03:00
Elian Doran
5c2f5e92eb chore(deps): update dependency @types/node to v22.18.10 (#7282) 2025-10-12 17:45:14 +03:00
Elian Doran
76ad386c70 chore(deps): update dependency @types/leaflet to v1.9.21 (#7281) 2025-10-12 08:18:47 +03:00
Elian Doran
c6b2044492 Translations update from Hosted Weblate (#7280) 2025-10-12 08:18:19 +03:00
renovate[bot]
4a953fad72 chore(deps): update softprops/action-gh-release action to v2.4.1 2025-10-12 01:45:40 +00:00
renovate[bot]
f06d8f27a1 chore(deps): update dependency typedoc to v0.28.14 2025-10-12 01:45:30 +00:00
renovate[bot]
ffd4201a73 chore(deps): update dependency lint-staged to v16.2.4 2025-10-12 01:45:24 +00:00
renovate[bot]
bc529e7089 chore(deps): update dependency @types/node to v22.18.10 2025-10-12 01:44:28 +00:00
renovate[bot]
f143cac61e chore(deps): update dependency @types/leaflet to v1.9.21 2025-10-12 01:43:32 +00:00
AndreR
e7657d4eb1 Translated using Weblate (German)
Currently translated at 9.5% (11 of 115 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/de/
2025-10-12 00:08:09 +02:00
Sarah Hussein
b6ad98e9ff Translated using Weblate (Arabic)
Currently translated at 69.5% (265 of 381 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ar/
2025-10-12 00:08:08 +02:00
Sarah Hussein
128120ad12 Translated using Weblate (Arabic)
Currently translated at 50.0% (807 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ar/
2025-10-12 00:08:08 +02:00
green
efa8fef4cf Translated using Weblate (Japanese)
Currently translated at 100.0% (1613 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-10-12 00:08:07 +02:00
CactusTrebleFraming
f5db38950a Translated using Weblate (French)
Currently translated at 85.5% (1380 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/fr/
2025-10-12 00:08:07 +02:00
Newcomer1989
d187da46a0 Translated using Weblate (German)
Currently translated at 100.0% (1613 of 1613 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/de/
2025-10-12 00:08:07 +02:00
Elian Doran
fb2afb5794 feat(website/i18n): translate footer 2025-10-11 22:45:37 +03:00
Elian Doran
6fe261836e feat(website/i18n): translate download button 2025-10-11 22:35:31 +03:00
Elian Doran
fc9f2bceb0 feat(website/i18n): translate final call-to-action 2025-10-11 22:27:15 +03:00
Elian Doran
ce88afee1b feat(website/i18n): translate FAQ section 2025-10-11 22:26:10 +03:00
Elian Doran
07eb3f64e3 feat(website/i18n): translate collections 2025-10-11 22:19:08 +03:00
Elian Doran
e32ba61a3c feat(website/i18n): translate extensibility benefits 2025-10-11 22:16:01 +03:00
Elian Doran
43e66fa4a6 Translations update from Hosted Weblate (#7276) 2025-10-11 22:10:07 +03:00
Elian Doran
ee9de82203 feat(website/i18n): translate note types 2025-10-11 22:08:53 +03:00
Hosted Weblate
df3baf1a67 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2025-10-11 19:01:58 +00:00
Elian Doran
6968d213bd Translations update from Hosted Weblate (#7275) 2025-10-11 22:01:42 +03:00
Elian Doran
ffaa011c3e feat(website/i18n): translate first three sections in the home page 2025-10-11 21:00:03 +03:00
Elian Doran
d56debaa9f feat(website/i18n): use translations in get-started 2025-10-11 20:46:41 +03:00
Elian Doran
2c71e995f2 feat(website/i18n): set up 2025-10-11 20:46:29 +03:00
Hosted Weblate
4da47979d1 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/
2025-10-11 19:02:49 +02:00
Elian Doran
2751aecab9 fix(deps): update dependency i18next to v25.6.0 (#7273) 2025-10-11 20:02:32 +03:00
renovate[bot]
1dccb6da31 fix(deps): update dependency i18next to v25.6.0 2025-10-11 01:31:47 +00:00
275 changed files with 12131 additions and 4578 deletions

View File

@@ -10,7 +10,7 @@ runs:
steps:
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 22
cache: "pnpm"

View File

@@ -12,7 +12,7 @@ jobs:
steps:
- name: Check if PRs have conflicts
uses: eps1lon/actions-label-merge-conflict@v3
if: github.repository == ${{ vars.REPO_MAIN }} && ${{secrets.MERGE_CONFLICT_LABEL_PAT}}
if: github.repository == ${{ vars.REPO_MAIN }}
with:
dirtyLabel: "merge-conflicts"
repoToken: "${{ secrets.MERGE_CONFLICT_LABEL_PAT }}"

View File

@@ -72,7 +72,7 @@ jobs:
# Setup Node.js with pnpm
- name: Setup Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'pnpm'
@@ -118,7 +118,7 @@ jobs:
- name: Deploy
uses: ./.github/actions/deploy-to-cloudflare-pages
if: github.repository == ${{ vars.REPO_MAIN }} && ${{secrets.CLOUDFLARE_API_TOKEN}}
if: github.repository == ${{ vars.REPO_MAIN }}
with:
project_name: "trilium-docs"
comment_body: "📚 Documentation preview is ready"

View File

@@ -28,7 +28,7 @@ jobs:
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 22
cache: "pnpm"

View File

@@ -44,7 +44,7 @@ jobs:
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 22
cache: "pnpm"
@@ -144,7 +144,7 @@ jobs:
uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 22
cache: 'pnpm'

View File

@@ -50,7 +50,7 @@ jobs:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 22
cache: 'pnpm'
@@ -77,7 +77,7 @@ jobs:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
- name: Publish release
uses: softprops/action-gh-release@v2.4.0
uses: softprops/action-gh-release@v2.4.1
if: ${{ github.event_name != 'pull_request' }}
with:
make_latest: false
@@ -118,7 +118,7 @@ jobs:
arch: ${{ matrix.arch }}
- name: Publish release
uses: softprops/action-gh-release@v2.4.0
uses: softprops/action-gh-release@v2.4.1
if: ${{ github.event_name != 'pull_request' }}
with:
make_latest: false

View File

@@ -22,7 +22,7 @@ jobs:
fetch-depth: 0
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v5
- uses: actions/setup-node@v6
with:
node-version: 22
cache: 'pnpm'

View File

@@ -48,7 +48,7 @@ jobs:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 22
cache: 'pnpm'
@@ -127,7 +127,7 @@ jobs:
path: upload
- name: Publish stable release
uses: softprops/action-gh-release@v2.4.0
uses: softprops/action-gh-release@v2.4.1
with:
draft: false
body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md

View File

@@ -28,7 +28,7 @@ jobs:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 22
cache: "pnpm"

View File

@@ -14,6 +14,7 @@ usageMatchRegex:
# the `{key}` will be placed by a proper keypath matching regex,
# you can ignore it and use your own matching rules as well
- "[^\\w\\d]t\\(['\"`]({key})['\"`]"
- <Trans\s*i18nKey="({key})"[^>]*>
# A RegEx to set a custom scope range. This scope will be used as a prefix when detecting keys
# and works like how the i18next framework identifies the namespace scope from the

View File

@@ -5,7 +5,8 @@
"i18n-ally.keystyle": "nested",
"i18n-ally.localesPaths": [
"apps/server/src/assets/translations",
"apps/client/src/translations"
"apps/client/src/translations",
"apps/website/public/translations"
],
"npm.exclude": [
"**/dist",

View File

@@ -1,3 +1,14 @@
<div align="center">
<sup>Special thanks to:</sup><br />
<a href="https://go.warp.dev/Trilium" target="_blank">
<img alt="Warp sponsorship" width="400" src="https://github.com/warpdotdev/brand-assets/blob/main/Github/Sponsor/Warp-Github-LG-03.png"><br />
Warp, built for coding with multiple AI agents<br />
</a>
<sup>Available for macOS, Linux and Windows</sup>
</div>
<hr />
# Trilium Notes
![GitHub Sponsors](https://img.shields.io/github/sponsors/eliandoran) ![LiberaPay patrons](https://img.shields.io/liberapay/patrons/ElianDoran)
@@ -13,6 +24,10 @@ See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for q
<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.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly) unstable development version, updated daily with the latest features and fixes.
## 📚 Documentation
**Visit our comprehensive documentation at [docs.triliumnotes.org](https://docs.triliumnotes.org/)**

View File

@@ -35,13 +35,13 @@
"chore:generate-openapi": "tsx bin/generate-openapi.js"
},
"devDependencies": {
"@playwright/test": "1.56.0",
"@stylistic/eslint-plugin": "5.4.0",
"@playwright/test": "1.56.1",
"@stylistic/eslint-plugin": "5.5.0",
"@types/express": "5.0.3",
"@types/node": "22.18.9",
"@types/node": "22.18.11",
"@types/yargs": "17.0.33",
"@vitest/coverage-v8": "3.2.4",
"eslint": "9.37.0",
"eslint": "9.38.0",
"eslint-plugin-simple-import-sort": "12.1.1",
"esm": "3.2.25",
"jsdoc": "4.0.5",
@@ -49,8 +49,8 @@
"rcedit": "4.0.1",
"rimraf": "6.0.1",
"tslib": "2.8.1",
"typedoc": "0.28.13",
"typedoc-plugin-missing-exports": "4.1.0"
"typedoc": "0.28.14",
"typedoc-plugin-missing-exports": "4.1.2"
},
"optionalDependencies": {
"appdmg": "0.6.6"

View File

@@ -1,4 +1,3 @@
import type child_process from "child_process";
import { describe, beforeAll, afterAll } from "vitest";
let etapiAuthToken: string | undefined;
@@ -12,8 +11,6 @@ type SpecDefinitionsFunc = () => void;
function describeEtapi(description: string, specDefinitions: SpecDefinitionsFunc): void {
describe(description, () => {
let appProcess: ReturnType<typeof child_process.spawn>;
beforeAll(async () => {});
afterAll(() => {});

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/client",
"version": "0.99.1",
"version": "0.99.2",
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
"private": true,
"license": "AGPL-3.0-only",
@@ -15,7 +15,7 @@
"circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
},
"dependencies": {
"@eslint/js": "9.37.0",
"@eslint/js": "9.38.0",
"@excalidraw/excalidraw": "0.18.0",
"@fullcalendar/core": "6.1.19",
"@fullcalendar/daygrid": "6.1.19",
@@ -35,29 +35,31 @@
"autocomplete.js": "0.38.1",
"bootstrap": "5.3.8",
"boxicons": "2.1.4",
"color": "5.0.2",
"dayjs": "1.11.18",
"dayjs-plugin-utc": "0.1.2",
"debounce": "2.2.0",
"draggabilly": "3.0.0",
"force-graph": "1.51.0",
"globals": "16.4.0",
"i18next": "25.5.3",
"i18next": "25.6.0",
"i18next-http-backend": "3.0.2",
"jquery": "3.7.1",
"jquery.fancytree": "2.38.5",
"jsplumb": "2.15.6",
"katex": "0.16.23",
"katex": "0.16.25",
"knockout": "3.5.1",
"leaflet": "1.9.4",
"leaflet-gpx": "2.2.0",
"mark.js": "8.11.1",
"marked": "16.4.0",
"marked": "16.4.1",
"mermaid": "11.12.0",
"mind-elixir": "5.3.2",
"mind-elixir": "5.3.3",
"normalize.css": "8.0.1",
"panzoom": "9.4.3",
"preact": "10.27.2",
"react-i18next": "16.0.0",
"react-i18next": "16.1.0",
"reveal.js": "5.2.1",
"split.js": "1.6.5",
"svg-pan-zoom": "3.6.2",
"tabulator-tables": "6.3.1",
@@ -68,13 +70,14 @@
"@preact/preset-vite": "2.10.2",
"@types/bootstrap": "5.2.10",
"@types/jquery": "3.5.33",
"@types/leaflet": "1.9.20",
"@types/leaflet": "1.9.21",
"@types/leaflet-gpx": "1.3.8",
"@types/mark.js": "8.11.12",
"@types/reveal.js": "5.2.1",
"@types/tabulator-tables": "6.2.11",
"copy-webpack-plugin": "13.0.1",
"happy-dom": "20.0.0",
"happy-dom": "20.0.7",
"script-loader": "0.7.2",
"vite-plugin-static-copy": "3.1.3"
"vite-plugin-static-copy": "3.1.4"
}
}

View File

@@ -326,9 +326,11 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
}
// Collections must always display a note list, even if no children.
const viewType = note.getLabelValue("viewType") ?? "grid";
if (!["list", "grid"].includes(viewType)) {
return true;
if (note.type === "book") {
const viewType = note.getLabelValue("viewType") ?? "grid";
if (!["list", "grid"].includes(viewType)) {
return true;
}
}
if (!note.hasChildren()) {
@@ -438,4 +440,22 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
}
}
export function openInCurrentNoteContext(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDownEvent | React.PointerEvent<HTMLCanvasElement> | null, notePath: string, viewScope?: ViewScope) {
const ntxId = $(evt?.target as Element)
.closest("[data-ntx-id]")
.attr("data-ntx-id");
const noteContext = ntxId ? appContext.tabManager.getNoteContextById(ntxId) : appContext.tabManager.getActiveContext();
if (noteContext) {
noteContext.setNote(notePath, { viewScope }).then(() => {
if (noteContext !== appContext.tabManager.getActiveContext()) {
appContext.tabManager.activateNoteContext(noteContext.ntxId);
}
});
} else {
appContext.tabManager.openContextWithNote(notePath, { viewScope, activate: true });
}
}
export default NoteContext;

View File

@@ -1,6 +1,5 @@
import server from "../services/server.js";
import noteAttributeCache from "../services/note_attribute_cache.js";
import ws from "../services/ws.js";
import protectedSessionHolder from "../services/protected_session_holder.js";
import cssClassManager from "../services/css_class_manager.js";
import type { Froca } from "../services/froca-interface.js";
@@ -586,7 +585,7 @@ export default class FNote {
let childBranches = this.getChildBranches();
if (!childBranches) {
ws.logError(`No children for '${this.noteId}'. This shouldn't happen.`);
console.error(`No children for '${this.noteId}'. This shouldn't happen.`);
return [];
}

View File

@@ -138,7 +138,7 @@ export default class DesktopLayout {
.child(new PromotedAttributesWidget())
.child(<SqlTableSchemas />)
.child(new NoteDetailWidget())
.child(<NoteList />)
.child(<NoteList media="screen" />)
.child(<SearchResult />)
.child(<SqlResults />)
.child(<ScrollPadding />)

View File

@@ -66,6 +66,6 @@ export function applyModals(rootContainer: RootContainer) {
.child(<PopupEditorFormattingToolbar />)
.child(new PromotedAttributesWidget())
.child(new NoteDetailWidget())
.child(<NoteList displayOnlyCollections />))
.child(<NoteList media="screen" displayOnlyCollections />))
.child(<CallToActionDialog />);
}

View File

@@ -154,7 +154,7 @@ export default class MobileLayout {
.filling()
.contentSized()
.child(new NoteDetailWidget())
.child(<NoteList />)
.child(<NoteList media="screen" />)
.child(<FilePropertiesWrapper />)
)
.child(<MobileEditorToolbar />)

155
apps/client/src/print.css Normal file
View File

@@ -0,0 +1,155 @@
:root {
--print-font-size: 11pt;
--ck-content-color-image-caption-background: transparent !important;
}
html,
body {
width: 100%;
height: 100%;
color: black;
}
@page {
margin: 2cm;
}
.note-list-widget.full-height,
.note-list-widget.full-height .note-list-widget-content {
height: unset !important;
}
.component {
contain: none !important;
}
body[data-note-type="text"] .ck-content {
font-size: var(--print-font-size);
text-align: justify;
}
.ck-content figcaption {
font-style: italic;
}
.ck-content a {
text-decoration: none;
}
.ck-content a:not([href^="#root/"]) {
text-decoration: underline;
color: #374a75;
}
.ck-content .todo-list__label * {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
@supports selector(.todo-list__label__description:has(*)) and (height: 1lh) {
.ck-content .todo-list__label__description {
/* The percentage of the line height that the check box occupies */
--box-ratio: 0.75;
/* The size of the gap between the check box and the caption */
--box-text-gap: 0.25em;
--box-size: calc(1lh * var(--box-ratio));
--box-vert-offset: calc((1lh - var(--box-size)) / 2);
display: inline-block;
padding-inline-start: calc(var(--box-size) + var(--box-text-gap));
/* Source: https://pictogrammers.com/library/mdi/icon/checkbox-blank-outline/ */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5C3.89%2c3 3%2c3.89 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5C21%2c3.89 20.1%2c3 19%2c3M19%2c5V19H5V5H19Z' /%3e%3c/svg%3e");
background-position: 0 var(--box-vert-offset);
background-size: var(--box-size);
background-repeat: no-repeat;
}
.ck-content .todo-list__label:has(input[type="checkbox"]:checked) .todo-list__label__description {
/* Source: https://pictogrammers.com/library/mdi/icon/checkbox-outline/ */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5A2%2c2 0 0%2c0 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5A2%2c2 0 0%2c0 19%2c3M19%2c5V19H5V5H19M10%2c17L6%2c13L7.41%2c11.58L10%2c14.17L16.59%2c7.58L18%2c9' /%3e%3c/svg%3e");
}
.ck-content .todo-list__label input[type="checkbox"] {
display: none !important;
}
}
/* #region Footnotes */
.footnote-reference a,
.footnote-back-link a {
text-decoration: none !important;
}
li.footnote-item {
position: relative;
width: fit-content;
}
.ck-content .footnote-back-link {
margin-right: 0.25em;
}
.ck-content .footnote-content {
display: inline-block;
width: unset;
}
/* #endregion */
/* #region Widows and orphans */
p,
blockquote {
widows: 4;
orphans: 4;
}
pre > code {
widows: 6;
orphans: 6;
overflow: auto;
white-space: pre-wrap !important;
}
h1,
h2,
h3,
h4,
h5,
h6 {
page-break-after: avoid;
break-after: avoid;
}
/* #endregion */
/* #region Tables */
.table thead th,
.table td,
.table th {
/* Fix center vertical alignment of table cells */
vertical-align: middle;
}
pre {
box-shadow: unset !important;
border: 0.75pt solid gray !important;
border-radius: 2pt !important;
}
th,
span[style] {
print-color-adjust: exact;
-webkit-print-color-adjust: exact;
}
/* #endregion */
/* #region Page breaks */
.page-break {
page-break-after: always;
break-after: always;
}
.page-break > *,
.page-break::after {
display: none !important;
}
/* #endregion */

92
apps/client/src/print.tsx Normal file
View File

@@ -0,0 +1,92 @@
import FNote from "./entities/fnote";
import { render } from "preact";
import { CustomNoteList } from "./widgets/collections/NoteList";
import { useCallback, useLayoutEffect, useRef } from "preact/hooks";
import content_renderer from "./services/content_renderer";
interface RendererProps {
note: FNote;
onReady: () => void;
}
async function main() {
const notePath = window.location.hash.substring(1);
const noteId = notePath.split("/").at(-1);
if (!noteId) return;
await import("./print.css");
const froca = (await import("./services/froca")).default;
const note = await froca.getNote(noteId);
render(<App note={note} noteId={noteId} />, document.body);
}
function App({ note, noteId }: { note: FNote | null | undefined, noteId: string }) {
const sentReadyEvent = useRef(false);
const onReady = useCallback(() => {
if (sentReadyEvent.current) return;
window.dispatchEvent(new Event("note-ready"));
window._noteReady = true;
sentReadyEvent.current = true;
}, []);
const props: RendererProps | undefined | null = note && { note, onReady };
if (!note || !props) return <Error404 noteId={noteId} />
useLayoutEffect(() => {
document.body.dataset.noteType = note.type;
}, [ note ]);
return (
<>
{note.type === "book"
? <CollectionRenderer {...props} />
: <SingleNoteRenderer {...props} />
}
</>
);
}
function SingleNoteRenderer({ note, onReady }: RendererProps) {
const containerRef = useRef<HTMLDivElement>(null);
useLayoutEffect(() => {
async function load() {
if (note.type === "text") {
await import("@triliumnext/ckeditor5/src/theme/ck-content.css");
}
const { $renderedContent } = await content_renderer.getRenderedContent(note, { noChildrenList: true });
containerRef.current?.replaceChildren(...$renderedContent);
}
load().then(() => requestAnimationFrame(onReady))
}, [ note ]);
return <>
<h1>{note.title}</h1>
<main ref={containerRef} />
</>;
}
function CollectionRenderer({ note, onReady }: RendererProps) {
return <CustomNoteList
isEnabled
note={note}
notePath={note.getBestNotePath().join("/")}
ntxId="print"
highlightedTokens={null}
media="print"
onReady={onReady}
/>;
}
function Error404({ noteId }: { noteId: string }) {
return (
<main>
<p>The note you are trying to print could not be found.</p>
<small>{noteId}</small>
</main>
)
}
main();

View File

@@ -23,11 +23,13 @@ interface Options {
tooltip?: boolean;
trim?: boolean;
imageHasZoom?: boolean;
/** If enabled, it will prevent the default behavior in which an empty note would display a list of children. */
noChildrenList?: boolean;
}
const CODE_MIME_TYPES = new Set(["application/json"]);
async function getRenderedContent(this: {} | { ctx: string }, entity: FNote | FAttachment, options: Options = {}) {
export async function getRenderedContent(this: {} | { ctx: string }, entity: FNote | FAttachment, options: Options = {}) {
options = Object.assign(
{
@@ -42,7 +44,7 @@ async function getRenderedContent(this: {} | { ctx: string }, entity: FNote | FA
const $renderedContent = $('<div class="rendered-content">');
if (type === "text" || type === "book") {
await renderText(entity, $renderedContent);
await renderText(entity, $renderedContent, options);
} else if (type === "code") {
await renderCode(entity, $renderedContent);
} else if (["image", "canvas", "mindMap"].includes(type)) {
@@ -114,7 +116,7 @@ async function getRenderedContent(this: {} | { ctx: string }, entity: FNote | FA
};
}
async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HTMLElement>) {
async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HTMLElement>, options: Options = {}) {
// entity must be FNote
const blob = await note.getBlob();
@@ -135,7 +137,7 @@ async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HT
}
await formatCodeBlocks($renderedContent);
} else if (note instanceof FNote) {
} else if (note instanceof FNote && !options.noChildrenList) {
await renderChildrenList($renderedContent, note);
}
}

View File

@@ -1,21 +1,39 @@
import {readCssVar} from "../utils/css-var";
import Color, { ColorInstance } from "color";
const registeredClasses = new Set<string>();
function createClassForColor(color: string | null) {
if (!color?.trim()) {
return "";
}
// Read the color lightness limits defined in the theme as CSS variables
const normalizedColorName = color.replace(/[^a-z0-9]/gi, "");
const lightThemeColorMaxLightness = readCssVar(
document.documentElement,
"tree-item-light-theme-max-color-lightness"
).asNumber(70);
if (!normalizedColorName.trim()) {
return "";
}
const darkThemeColorMinLightness = readCssVar(
document.documentElement,
"tree-item-dark-theme-min-color-lightness"
).asNumber(50);
const className = `color-${normalizedColorName}`;
function createClassForColor(colorString: string | null) {
if (!colorString?.trim()) return "";
const color = parseColor(colorString);
if (!color) return "";
const className = `color-${color.hex().substring(1)}`;
if (!registeredClasses.has(className)) {
// make the active fancytree selector more specific than the normal color setting
$("head").append(`<style>.${className}, span.fancytree-active.${className} { color: ${color} !important; }</style>`);
const adjustedColor = adjustColorLightness(color, lightThemeColorMaxLightness!,
darkThemeColorMinLightness!);
$("head").append(`<style>
.${className}, span.fancytree-active.${className} {
--light-theme-custom-color: ${adjustedColor.lightThemeColor};
--dark-theme-custom-color: ${adjustedColor.darkThemeColor};
--custom-color-hue: ${getHue(color) ?? 'unset'};
}
</style>`);
registeredClasses.add(className);
}
@@ -23,6 +41,41 @@ function createClassForColor(color: string | null) {
return className;
}
function parseColor(color: string) {
try {
return Color(color);
} catch (ex) {
console.error(ex);
}
}
/**
* Returns a pair of colors — one optimized for light themes and the other for dark themes, derived
* from the specified color to maintain sufficient contrast with each theme.
* The adjustment is performed by limiting the colors lightness in the CIELAB color space,
* according to the lightThemeMaxLightness and darkThemeMinLightness parameters.
*/
function adjustColorLightness(color: ColorInstance, lightThemeMaxLightness: number, darkThemeMinLightness: number) {
const labColor = color.lab();
const lightness = labColor.l();
// For the light theme, limit the maximum lightness
const lightThemeColor = labColor.l(Math.min(lightness, lightThemeMaxLightness)).hex();
// For the dark theme, limit the minimum lightness
const darkThemeColor = labColor.l(Math.max(lightness, darkThemeMinLightness)).hex();
return {lightThemeColor, darkThemeColor};
}
/** Returns the hue of the specified color, or undefined if the color is grayscale. */
function getHue(color: ColorInstance) {
const hslColor = color.hsl();
if (hslColor.saturationl() > 0) {
return hslColor.hue();
}
}
export default {
createClassForColor
};

View File

@@ -40,20 +40,23 @@ class FrocaImpl implements Froca {
constructor() {
this.initializedPromise = this.loadInitialTree();
this.#clear();
}
async loadInitialTree() {
const resp = await server.get<SubtreeResponse>("tree");
// clear the cache only directly before adding new content which is important for e.g., switching to protected session
this.#clear();
this.addResp(resp);
}
#clear() {
this.notes = {};
this.branches = {};
this.attributes = {};
this.attachments = {};
this.blobPromises = {};
this.addResp(resp);
}
async loadSubTree(subTreeNoteId: string) {

View File

@@ -27,7 +27,8 @@ export const byBookType: Record<ViewTypeOptions, string | null> = {
calendar: "xWbu3jpNWapp",
table: "2FvYrpmOXm29",
geoMap: "81SGnPGMk7Xc",
board: "CtBQqbwXDx1w"
board: "CtBQqbwXDx1w",
presentation: null
};
export function getHelpUrlForNote(note: FNote | null | undefined) {

View File

@@ -4,6 +4,7 @@ import appContext, { type NoteCommandData } from "../components/app_context.js";
import froca from "./froca.js";
import utils from "./utils.js";
import { ALLOWED_PROTOCOLS } from "@triliumnext/commons";
import { openInCurrentNoteContext } from "../components/note_context.js";
function getNotePathFromUrl(url: string) {
const notePathMatch = /#(root[A-Za-z0-9_/]*)$/.exec(url);
@@ -316,21 +317,7 @@ function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDownEvent
viewScope
});
} else if (isLeftClick) {
const ntxId = $(evt?.target as any)
.closest("[data-ntx-id]")
.attr("data-ntx-id");
const noteContext = ntxId ? appContext.tabManager.getNoteContextById(ntxId) : appContext.tabManager.getActiveContext();
if (noteContext) {
noteContext.setNote(notePath, { viewScope }).then(() => {
if (noteContext !== appContext.tabManager.getActiveContext()) {
appContext.tabManager.activateNoteContext(noteContext.ntxId);
}
});
} else {
appContext.tabManager.openContextWithNote(notePath, { viewScope, activate: true });
}
openInCurrentNoteContext(evt, notePath, viewScope);
}
} else if (hrefLink) {
const withinEditLink = $link?.hasClass("ck-link-actions__preview");

View File

@@ -168,7 +168,8 @@ async function getBuiltInTemplates(title: string | null, command: TreeCommandNam
}
for (const templateNote of childNotes) {
if (templateNote.hasLabel("collection") !== filterCollections) {
if (templateNote.hasLabel("collection") !== filterCollections ||
!templateNote.hasLabel("template")) {
continue;
}

View File

@@ -61,7 +61,11 @@ export async function applySingleBlockSyntaxHighlight($codeBlock: JQuery<HTMLEle
highlightedText = highlightAuto(text);
} else if (normalizedMimeType) {
await ensureMimeTypesForHighlighting(normalizedMimeType);
highlightedText = highlight(text, { language: normalizedMimeType });
try {
highlightedText = highlight(text, { language: normalizedMimeType });
} catch (e) {
console.warn("Unable to apply syntax highlight.", e);
}
}
if (highlightedText) {
@@ -76,7 +80,7 @@ export async function ensureMimeTypesForHighlighting(mimeTypeHint?: string) {
// Load theme.
const currentThemeName = String(options.get("codeBlockTheme"));
loadHighlightingTheme(currentThemeName);
await loadHighlightingTheme(currentThemeName);
// Load mime types.
let mimeTypes: MimeType[];
@@ -98,17 +102,16 @@ export async function ensureMimeTypesForHighlighting(mimeTypeHint?: string) {
highlightingLoaded = true;
}
export function loadHighlightingTheme(themeName: string) {
export async function loadHighlightingTheme(themeName: string) {
const themePrefix = "default:";
let theme: Theme | null = null;
if (themeName.includes(themePrefix)) {
if (glob.device === "print") {
theme = Themes.vs;
} else if (themeName.includes(themePrefix)) {
theme = Themes[themeName.substring(themePrefix.length)];
}
if (!theme) {
theme = Themes.default;
}
loadTheme(theme);
await loadTheme(theme ?? Themes.default);
}
/**

View File

@@ -304,6 +304,8 @@ async function sendPing() {
}
setTimeout(() => {
if (glob.device === "print") return;
ws = connectWebSocket();
lastPingTs = Date.now();

View File

@@ -1,322 +0,0 @@
:root {
--main-background-color: white;
--root-background: var(--main-background-color);
--launcher-pane-background-color: var(--main-background-color);
--main-text-color: black;
--input-text-color: var(--main-text-color);
--print-font-size: 11pt;
}
@page {
margin: 2cm;
}
.ck-content {
font-size: var(--print-font-size);
text-align: justify;
}
.note-detail-readonly-text {
padding: 0 !important;
}
.no-print,
.no-print *,
.tab-row-container,
.tab-row-widget,
.title-bar-buttons,
#launcher-pane,
#left-pane,
#center-pane > *:not(.split-note-container-widget),
#right-pane,
.title-row .note-icon-widget,
.title-row .icon-action,
.ribbon-container,
.promoted-attributes-widget,
.scroll-padding-widget,
.note-list-widget,
.spacer {
display: none !important;
}
body.mobile #mobile-sidebar-wrapper,
body.mobile .classic-toolbar-widget,
body.mobile .action-button {
display: none !important;
}
body.mobile #detail-container {
max-height: unset;
}
body.mobile .note-title-widget {
padding: 0 !important;
}
body,
#root-widget,
#rest-pane > div.component:first-child,
.note-detail-printable,
.note-detail-editable-text-editor {
height: unset !important;
overflow: auto;
}
.ck.ck-editor__editable_inline {
overflow: hidden !important;
}
.note-title-widget input,
.note-detail-editable-text,
.note-detail-editable-text-editor {
padding: 0 !important;
}
html,
body {
width: unset !important;
height: unset !important;
overflow: visible;
position: unset;
/* https://github.com/zadam/trilium/issues/3202 */
color: black;
}
#root-widget,
#horizontal-main-container,
#rest-pane,
#vertical-main-container,
#center-pane,
.split-note-container-widget,
.note-split:not(.hidden-ext),
body.mobile #mobile-rest-container {
display: block !important;
overflow: auto;
border-radius: 0 !important;
}
#center-pane,
#rest-pane,
.note-split,
body.mobile #detail-container {
width: unset !important;
max-width: unset !important;
}
.component {
contain: none !important;
}
/* Respect page breaks */
.page-break {
page-break-after: always;
break-after: always;
}
.page-break > * {
display: none !important;
}
.relation-map-wrapper {
height: 100vh !important;
}
.table thead th,
.table td,
.table th {
/* Fix center vertical alignment of table cells */
vertical-align: middle;
}
pre {
box-shadow: unset !important;
border: 0.75pt solid gray !important;
border-radius: 2pt !important;
}
th,
span[style] {
print-color-adjust: exact;
-webkit-print-color-adjust: exact;
}
/*
* Text note specific fixes
*/
.ck-widget {
outline: none !important;
}
.ck-placeholder,
.ck-widget__type-around,
.ck-widget__selection-handle {
display: none !important;
}
.ck-widget.table td.ck-editor__nested-editable.ck-editor__nested-editable_focused,
.ck-widget.table td.ck-editor__nested-editable:focus,
.ck-widget.table th.ck-editor__nested-editable.ck-editor__nested-editable_focused,
.ck-widget.table th.ck-editor__nested-editable:focus {
background: unset !important;
outline: unset !important;
}
.include-note .include-note-content {
max-height: unset !important;
overflow: unset !important;
}
/* TODO: This will break once we translate the language */
.ck-content pre[data-language="Auto-detected"]:after {
display: none !important;
}
/*
* Code note specific fixes.
*/
.note-detail-code pre {
border: unset !important;
border-radius: unset !important;
}
/*
* Links
*/
.note-detail-printable a {
text-decoration: none;
}
.note-detail-printable a:not([href^="#root/"]) {
text-decoration: underline;
color: #374a75;
}
.note-detail-printable a::after {
/* Hide the external link trailing arrow */
display: none !important;
}
/*
* TODO list check boxes
*/
.note-detail-printable .todo-list__label * {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
@supports selector(.todo-list__label__description:has(*)) and (height: 1lh) {
.note-detail-printable .todo-list__label__description {
/* The percentage of the line height that the check box occupies */
--box-ratio: 0.75;
/* The size of the gap between the check box and the caption */
--box-text-gap: 0.25em;
--box-size: calc(1lh * var(--box-ratio));
--box-vert-offset: calc((1lh - var(--box-size)) / 2);
display: inline-block;
padding-inline-start: calc(var(--box-size) + var(--box-text-gap));
/* Source: https://pictogrammers.com/library/mdi/icon/checkbox-blank-outline/ */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5C3.89%2c3 3%2c3.89 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5C21%2c3.89 20.1%2c3 19%2c3M19%2c5V19H5V5H19Z' /%3e%3c/svg%3e");
background-position: 0 var(--box-vert-offset);
background-size: var(--box-size);
background-repeat: no-repeat;
}
.note-detail-printable .todo-list__label:has(input[type="checkbox"]:checked) .todo-list__label__description {
/* Source: https://pictogrammers.com/library/mdi/icon/checkbox-outline/ */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5A2%2c2 0 0%2c0 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5A2%2c2 0 0%2c0 19%2c3M19%2c5V19H5V5H19M10%2c17L6%2c13L7.41%2c11.58L10%2c14.17L16.59%2c7.58L18%2c9' /%3e%3c/svg%3e");
}
.note-detail-printable .todo-list__label input[type="checkbox"] {
display: none !important;
}
}
/*
* Blockquotes
*/
.note-detail-printable blockquote {
box-shadow: unset;
}
/*
* Figures
*/
.note-detail-printable figcaption {
--accented-background-color: transparent;
font-style: italic;
}
/*
* Footnotes
*/
.note-detail-printable .footnote-reference a,
.footnote-back-link a {
text-decoration: none;
}
/* Make the "^" link cover the whole area of the footnote item */
.footnote-section {
clear: both;
}
.note-detail-printable li.footnote-item {
position: relative;
width: fit-content;
}
.note-detail-printable .footnote-back-link,
.note-detail-printable .footnote-back-link *,
.note-detail-printable .footnote-back-link a {
display: block;
position: absolute;
top: 0;
inset-inline-start: 0;
width: 100%;
height: 100%;
}
.note-detail-printable .footnote-back-link a {
color: transparent;
}
.note-detail-printable .footnote-content {
display: inline-block;
width: unset;
}
/*
* Widows and orphans
*/
p,
blockquote {
widows: 4;
orphans: 4;
}
pre > code {
widows: 6;
orphans: 6;
overflow: auto;
white-space: pre-wrap !important;
}
h1,
h2,
h3,
h4,
h5,
h6 {
page-break-after: avoid;
break-after: avoid;
}

View File

@@ -360,7 +360,8 @@ button kbd {
}
.dropdown-menu,
.tabulator-popup-container {
.tabulator-popup-container,
:root .excalidraw .popover {
color: var(--menu-text-color) !important;
font-size: inherit;
background: var(--menu-background-color) !important;
@@ -371,7 +372,9 @@ button kbd {
}
body.desktop .dropdown-menu,
body.desktop .tabulator-popup-container {
body.desktop .tabulator-popup-container,
:root .excalidraw .dropdown-menu .dropdown-menu-container,
:root .excalidraw .popover {
border: 1px solid var(--dropdown-border-color);
column-rule: 1px solid var(--dropdown-border-color);
box-shadow: 0px 10px 20px rgba(0, 0, 0, var(--dropdown-shadow-opacity));
@@ -416,7 +419,8 @@ body.desktop .tabulator-popup-container {
.dropdown-menu a:hover:not(.disabled),
.dropdown-item:hover:not(.disabled, .dropdown-container-item),
.tabulator-menu-item:hover {
.tabulator-menu-item:hover,
:root .excalidraw .context-menu .context-menu-item:hover {
color: var(--hover-item-text-color) !important;
background-color: var(--hover-item-background-color) !important;
border-color: var(--hover-item-border-color) !important;
@@ -457,7 +461,8 @@ body #context-menu-container .dropdown-item > span {
}
.dropdown-item,
.dropdown-header {
.dropdown-header,
:root .excalidraw .context-menu .context-menu-item:hover {
color: var(--menu-text-color) !important;
border: 1px solid transparent !important;
}
@@ -1008,7 +1013,7 @@ svg.ck-icon .note-icon {
--ck-content-line-height: var(--bs-body-line-height);
}
.ck-content .table table th {
:root .ck-content .table table:not(.layout-table) th {
background-color: var(--accented-background-color);
}
@@ -1978,6 +1983,10 @@ 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 {
width: 80px;
}
.tab-row-widget {
padding-inline-end: calc(100vw - env(titlebar-area-width, 100vw));
}
@@ -2277,9 +2286,8 @@ footer.webview-footer button {
.admonition {
--accent-color: var(--card-border-color);
background: color-mix(in srgb, var(--accent-color) 15%, transparent);
border: 1px solid var(--accent-color);
box-shadow: var(--card-box-shadow);
background: var(--card-background-color);
border-radius: 0.5em;
padding: 1em;
margin: 1.25em 0;
@@ -2414,4 +2422,14 @@ footer.webview-footer button {
.revision-diff-removed {
background: rgba(255, 100, 100, 0.5);
text-decoration: line-through;
}
iframe.print-iframe {
position: absolute;
top: 0;
left: -600px;
right: -600px;
bottom: 0;
width: 0;
height: 0;
}

View File

@@ -82,6 +82,10 @@ body ::-webkit-calendar-picker-indicator {
filter: invert(1);
}
#left-pane .fancytree-node.tinted {
--custom-color: var(--dark-theme-custom-color);
}
.excalidraw.theme--dark {
--theme-filter: invert(80%) hue-rotate(180deg) !important;
}

View File

@@ -81,3 +81,7 @@ html {
--mermaid-theme: default;
--native-titlebar-background: #ffffff00;
}
#left-pane .fancytree-node.tinted {
--custom-color: var(--light-theme-custom-color);
}

View File

@@ -160,6 +160,9 @@
--launcher-pane-horiz-background-color-bgfx: #ffffff17; /* When background effects enabled */
--launcher-pane-horiz-border-color-bgfx: #00000080; /* When background effects enabled */
--global-menu-update-available-badge-background-color: #7dbe61;
--global-menu-update-available-badge-color: black;
--protected-session-active-icon-color: #8edd8e;
--sync-status-error-pulse-color: #f47871;
@@ -265,6 +268,15 @@
* Dark color scheme tweaks
*/
#left-pane .fancytree-node.tinted {
--custom-color: var(--dark-theme-custom-color);
/* The background color of the active item in the note tree.
* The --custom-color-hue variable contains the hue of the user-selected note color.
* This value is unset for gray tones. */
--custom-bg-color: hsl(var(--custom-color-hue), 20%, 33%, 0.4);
}
body ::-webkit-calendar-picker-indicator {
filter: invert(1);
}
@@ -275,4 +287,4 @@ body ::-webkit-calendar-picker-indicator {
body .todo-list input[type="checkbox"]:not(:checked):before {
border-color: var(--muted-text-color) !important;
}
}

View File

@@ -127,7 +127,7 @@
--left-pane-item-selected-color: black;
--left-pane-item-selected-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
--left-pane-item-action-button-background: rgba(0, 0, 0, 0.11);
--left-pane-item-action-button-color: inherit;
--left-pane-item-action-button-color: var(--left-pane-text-color);
--left-pane-item-action-button-hover-background: white;
--left-pane-item-action-button-hover-shadow: 2px 2px 3px rgba(0, 0, 0, 0.15);
--left-pane-item-selected-action-button-hover-shadow: 2px 2px 10px rgba(0, 0, 0, 0.25);
@@ -153,6 +153,9 @@
--launcher-pane-horiz-background-color-bgfx: #ffffffb3; /* When background effects enabled */
--launcher-pane-horiz-border-color-bgfx: #00000026; /* When background effects enabled */
--global-menu-update-available-badge-background-color: #4fa450;
--global-menu-update-available-badge-color: white;
--protected-session-active-icon-color: #16b516;
--sync-status-error-pulse-color: #ff5528;
@@ -258,5 +261,13 @@
--ck-editor-toolbar-button-on-color: black;
--ck-editor-toolbar-button-on-shadow: none;
--ck-editor-toolbar-dropdown-button-open-background: #0000000f;
}
#left-pane .fancytree-node.tinted {
--custom-color: var(--light-theme-custom-color);
/* The background color of the active item in the note tree.
* The --custom-color-hue variable contains the hue of the user-selected note color.
* This value is unset for gray tones. */
--custom-bg-color: hsl(var(--custom-color-hue), 37%, 89%, 1);
}

View File

@@ -4,6 +4,7 @@
@import url(./pages.css);
@import url(./ribbon.css);
@import url(./notes/text.css);
@import url(./notes/canvas.css);
@import url(./notes/collections/table.css);
@font-face {
@@ -81,6 +82,20 @@
/* Theme capabilities */
--tab-note-icons: true;
/* To ensure that a tree item's custom color remains sufficiently contrasted and readable,
* the color is adjusted based on the current color scheme (light or dark). The lightness
* component of the color represented in the CIELAB color space, will be
* constrained to a certain percentage defined below.
*
* Note: the tree background may vary when background effects are enabled, so it is recommended
* to maintain a higher contrast margin than on the usual note tree solid background. */
/* The maximum perceptual lightness for the custom color in the light theme (%): */
--tree-item-light-theme-max-color-lightness: 60;
/* The minimum perceptual lightness for the custom color in the dark theme (%): */
--tree-item-dark-theme-min-color-lightness: 65;
}
body.backdrop-effects-disabled {
@@ -96,9 +111,10 @@ body.backdrop-effects-disabled {
* supported when this class is used.
*/
.dropdown-menu:not(.static) {
.dropdown-menu:not(.static),
:root .excalidraw .popover {
border-radius: var(--dropdown-border-radius);
padding: var(--menu-padding-size) !important;
padding: var(--padding, var(--menu-padding-size)) !important;
font-size: 0.9rem !important;
}
@@ -114,7 +130,8 @@ body.mobile .dropdown-menu .dropdown-menu {
}
body.desktop .dropdown-menu::before,
:root .ck.ck-dropdown__panel::before {
:root .ck.ck-dropdown__panel::before,
:root .excalidraw .popover::before {
content: "";
backdrop-filter: var(--dropdown-backdrop-filter);
border-radius: var(--dropdown-border-radius);
@@ -148,9 +165,17 @@ body.desktop .dropdown-submenu .dropdown-menu {
}
.dropdown-item,
body.mobile .dropdown-submenu .dropdown-toggle {
padding: 2px 2px 2px 8px !important;
padding-inline-end: 22px !important;
body.mobile .dropdown-submenu .dropdown-toggle,
.excalidraw .context-menu .context-menu-item {
--menu-item-start-padding: 8px;
--menu-item-end-padding: 22px;
--menu-item-vertical-padding: 2px;
padding-top: var(--menu-item-vertical-padding) !important;
padding-bottom: var(--menu-item-vertical-padding) !important;
padding-inline-start: var(--menu-item-start-padding) !important;
padding-inline-end: var(--menu-item-end-padding) !important;
/* Note: the right padding should also accommodate the submenu arrow. */
border-radius: 6px;
cursor: default !important;
@@ -202,7 +227,8 @@ html body .dropdown-item[disabled] {
}
/* Menu item keyboard shortcut */
.dropdown-item kbd {
.dropdown-item kbd,
.excalidraw .context-menu-item__shortcut {
font-family: unset !important;
font-size: unset !important;
color: var(--menu-item-keyboard-shortcut-color) !important;
@@ -214,13 +240,15 @@ html body .dropdown-item[disabled] {
margin-inline-start: 16px;
}
.dropdown-divider {
.dropdown-divider,
.excalidraw .context-menu hr {
position: relative;
border-color: transparent !important;
overflow: visible;
}
.dropdown-divider::after {
.dropdown-divider::after,
.excalidraw .context-menu hr::before {
position: absolute;
content: "";
top: -1px;
@@ -253,7 +281,9 @@ body[dir=rtl] .dropdown-menu:not([data-popper-placement="bottom-start"]) .dropdo
/* Menu item group heading */
/* The heading body */
.dropdown-menu h6 {
.dropdown-menu h6,
.excalidraw .dropdown-menu-container .dropdown-menu-group-title,
.excalidraw .dropdown-menu-container div[data-testid="canvas-background-label"] {
position: relative;
background: transparent;
padding: 1em 8px 14px 8px;
@@ -264,7 +294,9 @@ body[dir=rtl] .dropdown-menu:not([data-popper-placement="bottom-start"]) .dropdo
}
/* The delimiter line */
.dropdown-menu h6::before {
.dropdown-menu h6::before,
.excalidraw .dropdown-menu-container .dropdown-menu-group-title::before,
.excalidraw .dropdown-menu-container div[data-testid="canvas-background-label"]::before {
content: "";
position: absolute;
bottom: 8px;

View File

@@ -0,0 +1,261 @@
:root .excalidraw {
--ui-font: var(--main-font-family);
/* Button hover background color */
--button-hover-bg: var(--hover-item-background-color);
--color-surface-high: var(--hover-item-background-color);
--button-active-border: transparent;
--color-brand-active: transparent;
--color-surface-mid: transparent;
--color-surface-low: transparent;
/* Slider colors */
--color-slider-track: var(--menu-item-delimiter-color);
--color-slider-thumb: var(--muted-text-color);
/* Selected button icon fill color */
--color-on-primary-container: var(--ck-editor-toolbar-button-on-color);
--color-primary: var(--ck-editor-toolbar-button-on-color);
/* Selected button icon background color */
--color-surface-primary-container: var(--ck-editor-toolbar-button-on-background);
--color-primary-light: var(--ck-editor-toolbar-button-on-background);
--island-bg-color: var(--floating-button-background-color);
}
/* Dark theme tweaks */
:root body .excalidraw.theme--dark {
--color-surface-high: transparent;
--color-brand-hover: transparent;
}
:root .excalidraw.theme--dark.excalidraw .App-mobile-menu,
:root .excalidraw.theme--dark.excalidraw .App-menu__left {
--button-hover-bg: var(--hover-item-background-color);
}
:root .excalidraw.theme--dark.excalidraw .dropdown-menu-button:hover {
--background: var(--hover-item-background-color);
}
/* Backdrop blur pseudo-element */
.Island:not(.App-menu__left)::before,
.excalidraw .picker::before,
:root .App-menu__left > .panelColumn > fieldset::before,
:root .App-menu__left > .panelColumn > label::before,
:root .App-menu__left > .panelColumn > div:has(> *)::before {
display: block;
position: absolute;
content: "";
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: inherit;
backdrop-filter: blur(10px) saturate(6);
z-index: -1;
}
/* Note's root */
:root .type-canvas {
--floating-buttons-vert-offset: 20px;
}
/* Context menus */
/* Context menu - outer wrapper */
:root .excalidraw .popover {
--padding: 0;
max-width: unset;
overflow: hidden;
font-family: var(--main-font-family);
}
/* Context menu - inner wrapper */
:root .excalidraw .popover > .context-menu {
margin: 0;
padding: 8px !important;
overflow-y: auto;
overflow-x: hidden;
height: 100%;
border: none;
padding: 0;
box-shadow: none;
background: transparent;
}
/* Context menu item */
:root .excalidraw .context-menu .context-menu-item {
--menu-item-start-padding: 22px;
border: 1px solid transparent;
}
/* Context menu item icon */
:root .excalidraw .dropdown-menu-item__icon {
color: var(--menu-item-icon-color);
}
/* Context menu item label */
:root .excalidraw .context-menu-item__label,
:root .excalidraw .context-menu-item.dangerous .context-menu-item__label {
color: var(--menu-text-color);
}
:root .excalidraw .context-menu-item:hover .context-menu-item__label {
color: var(--hover-item-text-color);
}
/* Context menu item keyboard shortcut */
:root .excalidraw .context-menu-item__shortcut {
padding: 0;
opacity: 1;
}
/* Context menu separator */
.excalidraw .context-menu .context-menu-item-separator {
margin: 8px 0;
opacity: 1;
}
/* Main menu */
/* Hide separators - no longer needed as the menu group headers feature a delimiter line */
.excalidraw .Island.dropdown-menu-container>div:not(:has(>*)) {
display: none;
}
/* Menu group header */
.excalidraw .dropdown-menu-container .dropdown-menu-group-title,
.excalidraw .Island.dropdown-menu-container div[data-testid="canvas-background-label"] {
margin: 0 !important;
}
/* Header */
.excalidraw .App-menu.App-menu_top {
align-items: center;
}
.excalidraw .App-menu.App-menu_top .App-menu_top__left {
/* Fixes a layout glitch with the header when the options panel is visbile */
--gap: 0 !important;
}
/* The parent element of the "Library" button */
.excalidraw .App-menu.App-menu_top > div:nth-child(3) {
flex-direction: row-reverse;
}
/* Panels */
.excalidraw .zoom-actions,
.undo-redo-buttons {
box-shadow: 1px 1px 1px var(--floating-button-shadow-color);
backdrop-filter: blur(10px) saturate(6);
}
:root .excalidraw .main-menu-trigger,
:root .excalidraw .sidebar-trigger,
:root .excalidraw .help-icon {
box-shadow: none;
}
/* Selected color outline */
:root .excalidraw .color-picker__button.active .color-picker__button-outline {
box-shadow: 0 0 0 2px var(--input-focus-outline-color);
}
:root .excalidraw .buttonList label.active {
border-color: transparent;
}
/* Options panel */
.excalidraw .Island.App-menu__left {
box-shadow: none;
background: transparent;
backdrop-filter: none;
width: 13.2em;
}
body[dir=ltr] .excalidraw .Island.App-menu__left {
right: 0;
}
body[dir=rtl] .excalidraw .Island.App-menu__left {
left: 0;
}
:root .App-menu__left > .panelColumn {
row-gap: 5px;
}
/* Options panel card */
:root .App-menu__left > .panelColumn > fieldset,
:root .App-menu__left > .panelColumn > label,
:root .App-menu__left > .panelColumn > div:has(> *) {
position: relative;
margin: 0;
border-radius: 4px;
box-shadow: 1px 1px 1px var(--floating-button-shadow-color);
background: var(--floating-button-background-color);
padding: 8px 12px;
/* backdrop: blur() creates a new stacking context that prevents some popovers like the
* arrowheads picker from being positioned correctly. To workaround this, the backdrop blur
* effect is applyed using a pseudo-element instead. */
}
/* Options panel card title */
:root .App-menu__left fieldset > legend,
:root .App-menu__left div > h3,
:root .App-menu__left > .panelColumn > label {
text-transform: uppercase;
font-size: .65rem;
letter-spacing: 1pt;
color: var(--muted-text-color);
}
/* Options panel button bar */
:root .excalidraw .App-menu__left .buttonList {
padding: 0;
}
/* Picker */
body[dir=ltr] .excalidraw .App-menu__left .buttonList .picker {
translate: -80% 0;
}
/* Properties panel */
body[dir=ltr] .excalidraw .exc-stats {
left: 0;
}
body[dir=rtl] .excalidraw .exc-stats {
right: 0;
}
/* Sidebar */
.split-note-container-widget > .component.type-canvas:has(.excalidraw-container > .Island.default-sidebar) > .floating-buttons {
/* Hide the floating buttons when the sidebar is open */
display: none;
}
/* Pickers */
.excalidraw .picker {
position: relative;
}

View File

@@ -354,6 +354,7 @@
align-items: center;
width: 100%;
margin: 4px;
background: color-mix(in srgb, var(--accent) 15%, var(--main-background-color));
padding-inline-end: 2em;
border: 1px solid var(--accent);
border-radius: 6px;

View File

@@ -18,7 +18,7 @@
body {
--native-titlebar-darwin-x-offset: 10;
--native-titlebar-darwin-y-offset: 17 !important;
--native-titlebar-darwin-y-offset: 12 !important;
}
body.layout-horizontal {
@@ -100,7 +100,7 @@ body.layout-horizontal > .horizontal {
align-items: center;
}
#launcher-container {
body[dir=ltr] #launcher-container {
scrollbar-gutter: stable both-edges;
}
@@ -279,14 +279,11 @@ body.layout-horizontal > .horizontal {
animation: sync-status-pulse 1s ease-in-out alternate-reverse infinite;
}
#launcher-pane .global-menu-button {
--hover-item-background-color: transparent;
}
#launcher-pane button.global-menu-button {
--update-badge-x-offset: 3%;
--update-badge-y-offset: -12%;
#launcher-pane.horizontal .global-menu-button .global-menu-button-update-available {
inset-inline-end: -23px;
bottom: -22px;
transform: scale(0.85);
--hover-item-background-color: transparent;
}
.tooltip .tooltip-arrow {
@@ -642,7 +639,7 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
#left-pane span.fancytree-node.fancytree-active {
position: relative;
background: transparent !important;
color: var(--left-pane-item-selected-color) !important;
color: var(--custom-color, var(--left-pane-item-selected-color));
}
@keyframes left-pane-item-select {
@@ -661,7 +658,7 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
inset-inline-start: var(--left-pane-item-selected-shadow-size);
bottom: var(--left-pane-item-selected-shadow-size);
inset-inline-end: var(--left-pane-item-selected-shadow-size);
background: var(--left-pane-item-selected-background) !important;
background: var(--custom-bg-color, var(--left-pane-item-selected-background)) !important;
box-shadow: var(--left-pane-item-selected-shadow);
border-radius: 6px;
animation: left-pane-item-select 200ms ease-out;
@@ -721,9 +718,6 @@ body.mobile .fancytree-node > span {
margin-top: 0; /* Use this to align the icon with the tree view item's caption */
}
#left-pane span .fancytree-title {
margin-top: -5px;
}
#left-pane span.fancytree-active .fancytree-title {
font-weight: normal;
@@ -1790,10 +1784,6 @@ div.find-replace-widget div.find-widget-found-wrapper > span {
--border-radius-lg: 6px;
}
.excalidraw .Island {
backdrop-filter: var(--dropdown-backdrop-filter);
}
.excalidraw .Island.App-toolbar {
--island-bg-color: var(--floating-button-background-color);
--shadow-island: 1px 1px 1px var(--floating-button-shadow-color);

View File

@@ -17,8 +17,6 @@ span.fancytree-node.fancytree-hide {
overflow: hidden;
margin-inline-start: 7px;
outline: none;
position: relative;
top: 2px;
}
.fancytree-expander {
@@ -42,6 +40,7 @@ span.fancytree-node.fancytree-hide {
text-overflow: ellipsis;
user-select: none !important;
-webkit-user-select: none !important;
color: var(--custom-color, inherit);
}
.fancytree-node:not(.fancytree-loading) .fancytree-expander {
@@ -181,7 +180,7 @@ span.fancytree-node.fancytree-active-clone:not(.fancytree-active) .fancytree-tit
}
span.fancytree-active {
color: var(--active-item-text-color) !important;
color: var(--active-item-text-color);
background-color: var(--active-item-background-color) !important;
border-color: transparent; /* invisible border */
border-radius: 5px;

View File

@@ -3,6 +3,8 @@ import FNote from "../entities/fnote.js";
import froca from "../services/froca.js";
import FAttribute from "../entities/fattribute.js";
import noteAttributeCache from "../services/note_attribute_cache.js";
import FBranch from "../entities/fbranch.js";
import FBlob from "../entities/fblob.js";
type AttributeDefinitions = { [key in `#${string}`]: string; };
type RelationDefinitions = { [key in `~${string}`]: string; };
@@ -10,6 +12,8 @@ type RelationDefinitions = { [key in `~${string}`]: string; };
interface NoteDefinition extends AttributeDefinitions, RelationDefinitions {
id?: string | undefined;
title: string;
children?: NoteDefinition[];
content?: string;
}
/**
@@ -47,6 +51,38 @@ export function buildNote(noteDef: NoteDefinition) {
blobId: ""
});
froca.notes[note.noteId] = note;
let childNotePosition = 0;
// Manage content.
const content = noteDef.content ?? "";
note.getContent = async () => content;
const blob = new FBlob({
blobId: utils.randomString(10),
content,
contentLength: content.length,
dateModified: new Date().toISOString(),
utcDateModified: new Date().toISOString()
});
note.getBlob = async () => blob;
// Manage children.
if (noteDef.children) {
for (const childDef of noteDef.children) {
const childNote = buildNote(childDef);
const branchId = `${note.noteId}_${childNote.noteId}`;
const branch = new FBranch(froca, {
branchId,
noteId: childNote.noteId,
parentNoteId: note.noteId,
notePosition: childNotePosition,
fromSearchNote: false
});
froca.branches[branchId] = branch;
note.addChild(childNote.noteId, branchId, false);
childNotePosition += 10;
}
}
let position = 0;
for (const [ key, value ] of Object.entries(noteDef)) {

File diff suppressed because it is too large Load Diff

View File

@@ -646,7 +646,9 @@
"about": "关于 TriliumNext 笔记",
"logout": "登出",
"show-cheatsheet": "显示快捷帮助",
"toggle-zen-mode": "禅模式"
"toggle-zen-mode": "禅模式",
"new-version-available": "新更新可用",
"download-update": "取得版本 {{latestVersion}}"
},
"zen_mode": {
"button_exit": "退出禅模式"
@@ -736,7 +738,8 @@
"insert_child_note": "插入子笔记",
"delete_this_note": "删除此笔记",
"error_cannot_get_branch_id": "无法获取 notePath '{{notePath}}' 的 branchId",
"error_unrecognized_command": "无法识别的命令 {{command}}"
"error_unrecognized_command": "无法识别的命令 {{command}}",
"note_revisions": "笔记历史版本"
},
"note_icon": {
"change_note_icon": "更改笔记图标",
@@ -749,7 +752,7 @@
"editable": "可编辑",
"basic_properties": "基本属性",
"language": "语言",
"configure_code_notes": "配置代码注释..."
"configure_code_notes": "配置代码笔记…"
},
"book_properties": {
"view_type": "视图类型",
@@ -765,7 +768,8 @@
"table": "表格",
"geo-map": "地理地图",
"board": "看板",
"include_archived_notes": "展示归档笔记"
"include_archived_notes": "展示归档笔记",
"presentation": "演示"
},
"edited_notes": {
"no_edited_notes_found": "今天还没有编辑过的笔记...",
@@ -1258,7 +1262,13 @@
"min-days-in-first-week": "第一周的最小天数",
"first-week-info": "第一周包含一年的第一个周四,基于 <a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a> 标准。",
"first-week-warning": "更改第一周选项可能会导致与现有周笔记重复,已创建的周笔记将不会相应更新。",
"formatting-locale": "日期和数字格式"
"formatting-locale": "日期和数字格式",
"tuesday": "周二",
"wednesday": "周三",
"thursday": "周四",
"friday": "周五",
"saturday": "周六",
"formatting-locale-auto": "依应用的语言设置"
},
"backup": {
"automatic_backup": "自动备份",
@@ -2065,5 +2075,10 @@
},
"collections": {
"rendering_error": "出现错误无法显示内容。"
},
"presentation_view": {
"edit-slide": "编辑此幻灯片",
"start-presentation": "开始演示",
"slide-overview": "切换幻灯片概览"
}
}

View File

@@ -4,7 +4,7 @@
"homepage": "Domovská stránka:",
"app_version": "Verze aplikace:",
"db_version": "Verze DB:",
"sync_version": "Verze sync:",
"sync_version": "Verze synchronizace:",
"build_date": "Datum sestavení:",
"build_revision": "Revize sestavení:",
"data_directory": "Datový adresář:"
@@ -36,6 +36,29 @@
"add_link": "Přidat odkaz",
"help_on_links": "Nápověda k odkazům",
"note": "Poznámka",
"search_note": "hledat poznámku podle názvu"
"search_note": "hledat poznámku podle názvu",
"link_title": "Název odkazu",
"button_add_link": "Přidat odkaz"
},
"branch_prefix": {
"prefix": "Prefix: ",
"save": "Uložit"
},
"bulk_actions": {
"bulk_actions": "Hromadné akce",
"affected_notes": "Ovlivněné poznámky",
"notes": "Poznámky"
},
"confirm": {
"cancel": "Zrušit",
"ok": "OK"
},
"delete_notes": {
"cancel": "Zrušit",
"ok": "OK",
"close": "Zavřít"
},
"export": {
"close": "Zavřít"
}
}

View File

@@ -646,7 +646,8 @@
"about": "Über Trilium Notes",
"logout": "Abmelden",
"show-cheatsheet": "Cheatsheet anzeigen",
"toggle-zen-mode": "Zen Modus"
"toggle-zen-mode": "Zen Modus",
"new-version-available": "Neues Update verfügbar"
},
"sync_status": {
"unknown": "<p>Der Synchronisations-Status wird bekannt, sobald der nächste Synchronisierungsversuch gestartet wird.</p><p>Klicke, um eine Synchronisierung jetzt auszulösen.</p>",
@@ -733,7 +734,8 @@
"insert_child_note": "Untergeordnete Notiz einfügen",
"delete_this_note": "Diese Notiz löschen",
"error_cannot_get_branch_id": "BranchId für notePath „{{notePath}}“ kann nicht abgerufen werden",
"error_unrecognized_command": "Unbekannter Befehl {{command}}"
"error_unrecognized_command": "Unbekannter Befehl {{command}}",
"note_revisions": "Notiz Revisionen"
},
"note_icon": {
"change_note_icon": "Notiz-Icon ändern",
@@ -762,7 +764,8 @@
"table": "Tabelle",
"geo-map": "Weltkarte",
"board": "Tafel",
"include_archived_notes": "Zeige archivierte Notizen"
"include_archived_notes": "Zeige archivierte Notizen",
"presentation": "Präsentation"
},
"edited_notes": {
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
@@ -1255,7 +1258,13 @@
"min-days-in-first-week": "Mindestanzahl an Tagen in erster Woche",
"first-week-info": "Die erste Woche, die den ersten Donnerstag des Jahres enthält, basiert auf dem Standard <a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a>.",
"first-week-warning": "Das Ändern der Optionen für die erste Woche kann zu Duplikaten mit bestehenden Wochen-Notizen führen. Bestehende Wochen-Notizen werden nicht entsprechend aktualisiert.",
"formatting-locale": "Datums- und Zahlenformat"
"formatting-locale": "Datums- und Zahlenformat",
"tuesday": "Dienstag",
"wednesday": "Mittwoch",
"thursday": "Donnerstag",
"friday": "Freitag",
"saturday": "Samstag",
"formatting-locale-auto": "Basierend auf die Anwendungssprache"
},
"backup": {
"automatic_backup": "Automatische Sicherung",
@@ -2067,5 +2076,9 @@
},
"collections": {
"rendering_error": "Aufgrund eines Fehlers können keine Inhalte angezeigt werden."
},
"presentation_view": {
"edit-slide": "Diese Folie bearbeiten",
"start-presentation": "Präsentation starten"
}
}

View File

@@ -164,6 +164,7 @@
"importIntoNote": "Import into note",
"chooseImportFile": "Choose import file",
"importDescription": "Content of the selected file(s) will be imported as child note(s) into",
"importZipRecommendation": "When importing a ZIP file, the note hierarchy will reflect the subdirectory structure within the archive.",
"options": "Options",
"safeImportTooltip": "Trilium <code>.zip</code> export files can contain executable scripts which may contain harmful behavior. Safe import will deactivate automatic execution of all imported scripts. Uncheck \"Safe import\" only if the imported archive is supposed to contain executable scripts and you completely trust the contents of the import file.",
"safeImport": "Safe import",
@@ -647,7 +648,8 @@
"logout": "Logout",
"show-cheatsheet": "Show Cheatsheet",
"toggle-zen-mode": "Zen Mode",
"update_available": "Version {{latestVersion}} is available, click to download."
"new-version-available": "New Update Available",
"download-update": "Get Version {{latestVersion}}"
},
"zen_mode": {
"button_exit": "Exit Zen Mode"
@@ -767,6 +769,7 @@
"table": "Table",
"geo-map": "Geo Map",
"board": "Board",
"presentation": "Presentation",
"include_archived_notes": "Show archived notes"
},
"edited_notes": {
@@ -1720,7 +1723,9 @@
"window-on-top": "Keep Window on Top"
},
"note_detail": {
"could_not_find_typewidget": "Could not find typeWidget for type '{{type}}'"
"could_not_find_typewidget": "Could not find typeWidget for type '{{type}}'",
"printing": "Printing in progress...",
"printing_pdf": "Exporting to PDF in progress..."
},
"note_title": {
"placeholder": "type note's title here..."
@@ -2028,6 +2033,11 @@
"edit-note-title": "Click to edit note title",
"edit-column-title": "Click to edit column title"
},
"presentation_view": {
"edit-slide": "Edit this slide",
"start-presentation": "Start presentation",
"slide-overview": "Toggle an overview of the slides"
},
"command_palette": {
"tree-action-name": "Tree: {{name}}",
"export_note_title": "Export Note",

View File

@@ -354,7 +354,7 @@
"calendar_root": "marca la nota que debe usarse como raíz para las notas del día. Sólo uno debe estar marcado como tal.",
"archived": "las notas con esta etiqueta no serán visibles de forma predeterminada en los resultados de búsqueda (tampoco en los cuadros de diálogo Saltar a, Agregar vínculo, etc.).",
"exclude_from_export": "las notas (con su subárbol) no se incluirán en ninguna exportación de notas",
"run": "define en qué eventos debe ejecutarse el script. Los valores posibles son:\n<ul>\n<li>frontendStartup - cuando el frontend de Trilium inicia (o es recargado), pero no en dispositivos móviles. </li>\n<li>backendStartup - cuando el backend de Trilium se inicia </li>\n<li>hourly - se ejecuta una vez cada hora. Puede usar etiqueta adicional <code>runAtHour</code> para especificar a la hora. </li>\n<li>daily - ejecutar una vez al día </li>\n</ul>",
"run": "define en qué eventos debe ejecutarse el script. Los valores posibles son:\n<ul>\n<li>frontendStartup - cuando Trilium frontend se inicia (o se actualiza), pero no en móvil.</li>\n<li>mobileStartup - cuando Trilium frontend se inicia (o se actualiza), en móvil.</li>\n<li>backendStartup - cuando Trilium backend se inicia</li>\n<li>hourly - se ejecuta una vez por hora. Se puede usar la etiqueta adicional <code>runAtHour</code> para especificar a qué hora.</li>\n<li>daily - se ejecuta una vez al día</li>\n</ul>",
"run_on_instance": "Definir en qué instancia de Trilium se debe ejecutar esto. Predeterminado para todas las instancias.",
"run_at_hour": "¿A qué hora debería funcionar? Debe usarse junto con <code>#run=hourly</code>. Se puede definir varias veces para varias ejecuciones durante el día.",
"disable_inclusion": "los scripts con esta etiqueta no se incluirán en la ejecución del script principal.",
@@ -384,7 +384,7 @@
"inbox": "ubicación predeterminada de la bandeja de entrada para nuevas notas - cuando crea una nota usando el botón \"nueva nota\" en la barra lateral, las notas serán creadas como subnotas de la nota marcada con la etiqueta <code>#inbox</code>.",
"workspace_inbox": "ubicación predeterminada de la bandeja de entrada para nuevas notas cuando se anclan a algún antecesor de esta nota del espacio de trabajo",
"sql_console_home": "ubicación predeterminada de las notas de la consola SQL",
"bookmark_folder": "la nota con esta etiqueta aparecerá en los marcadores como carpeta (permitiendo el acceso a sus elementos hijos).",
"bookmark_folder": "la nota con esta etiqueta aparecerá en los marcadores como carpeta (permitiendo el acceso a sus elementos hijos)",
"share_hidden_from_tree": "esta nota está oculta en el árbol de navegación izquierdo, pero aún se puede acceder a ella con su URL",
"share_external_link": "la nota actuará como un enlace a un sitio web externo en el árbol compartido",
"share_alias": "define un alias que al usar la nota va a estar disponible en https://your_trilium_host/share/[tu_alias]",
@@ -646,7 +646,9 @@
"about": "Acerca de Trilium Notes",
"logout": "Cerrar sesión",
"show-cheatsheet": "Mostrar hoja de trucos",
"toggle-zen-mode": "Modo Zen"
"toggle-zen-mode": "Modo Zen",
"new-version-available": "Nueva actualización disponible",
"download-update": "Obtener versión {{latestVersion}}"
},
"zen_mode": {
"button_exit": "Salir del modo Zen"
@@ -736,7 +738,8 @@
"insert_child_note": "Insertar subnota",
"delete_this_note": "Eliminar esta nota",
"error_cannot_get_branch_id": "No se puede obtener el branchID del notePath '{{notePath}}'",
"error_unrecognized_command": "Comando no reconocido {{command}}"
"error_unrecognized_command": "Comando no reconocido {{command}}",
"note_revisions": "Revisiones de notas"
},
"note_icon": {
"change_note_icon": "Cambiar icono de nota",
@@ -765,7 +768,8 @@
"table": "Tabla",
"geo-map": "Mapa Geo",
"board": "Tablero",
"include_archived_notes": "Mostrar notas archivadas"
"include_archived_notes": "Mostrar notas archivadas",
"presentation": "Presentación"
},
"edited_notes": {
"no_edited_notes_found": "Aún no hay notas editadas en este día...",
@@ -1010,7 +1014,7 @@
"start_dragging_relations": "Empiece a arrastrar relaciones desde aquí y suéltelas en otra nota.",
"note_not_found": "¡Nota {{noteId}} no encontrada!",
"cannot_match_transform": "No se puede coincidir con la transformación: {{transform}}",
"note_already_in_diagram": "Note \"{{title}}\" is already in the diagram.",
"note_already_in_diagram": "La nota \"{{title}}\" ya está en el diagrama.",
"enter_title_of_new_note": "Ingrese el título de la nueva nota",
"default_new_note_title": "nueva nota",
"click_on_canvas_to_place_new_note": "Haga clic en el lienzo para colocar una nueva nota"
@@ -1252,8 +1256,9 @@
"indexing_stopped": "Indexado detenido",
"indexing_in_progress": "Indexado en progreso...",
"last_indexed": "Último indexado",
"n_notes_queued": "{{ count }} nota agregada a la cola para indexado",
"n_notes_queued_plural": "{{ count }} notas agregadas a la cola para indexado",
"n_notes_queued_0": "{{ count }} nota agregada a la cola para indexar",
"n_notes_queued_1": "{{ count }} notas agregadas a la cola para indexar",
"n_notes_queued_2": "",
"note_chat": "Chat de nota",
"notes_indexed": "{{ count }} nota indexada",
"notes_indexed_plural": "{{ count }} notas indexadas",
@@ -1414,7 +1419,13 @@
"min-days-in-first-week": "Días mínimos en la primer semana",
"first-week-info": "Primer semana que contiene al primer jueves del año está basado en el estándar<a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a>.",
"first-week-warning": "Cambiar las opciones de primer semana puede causar duplicados con las Notas Semanales existentes y las Notas Semanales existentes no serán actualizadas respectivamente.",
"formatting-locale": "Fecha y formato de número"
"formatting-locale": "Fecha y formato de número",
"tuesday": "Martes",
"wednesday": "Miércoles",
"thursday": "Jueves",
"friday": "Viernes",
"saturday": "Sábado",
"formatting-locale-auto": "Basado en el idioma de la aplicación"
},
"backup": {
"automatic_backup": "Copia de seguridad automática",
@@ -1507,7 +1518,7 @@
"recovery_keys_used": "Usado: {{date}}",
"recovery_keys_unused": "El código de recuperación {{index}} está sin usar",
"oauth_title": "OAuth/OpenID",
"oauth_description": "OpenID es una forma estandarizada de permitirle iniciar sesión en sitios web utilizando una cuenta de otro servicio, como Google, para verificar su identidad. Siga estas <a href = \"https://developers.google.com/identity/openid-connect/openid-connect\">instrucciones</a> para configurar un servicio OpenID a través de Google.",
"oauth_description": "OpenID es un método estandarizado que permite iniciar sesión en sitios web usando una cuenta de otro servicio, como Google, para verificar tu identidad. El emisor predeterminado es Google, pero se puede cambiar a cualquier otro proveedor de OpenID. Consulta <a href=\"#root/_hidden/_help/_help_Otzi9La2YAUX/_help_WOcw2SLH6tbX/_help_7DAiwaf8Z7Rz\">aquí</a> para más información. Sigue estas <a href=\"https://developers.google.com/identity/openid-connect/openid-connect\">instrucciones</a> para configurar un servicio OpenID a través de Google.",
"oauth_description_warning": "Para habilitar OAuth/OpenID, necesita establecer la URL base de OAuth/OpenID, ID de cliente y secreto de cliente en el archivo config.ini y reiniciar la aplicación. Si desea establecerlas desde variables de ambiente, por favor establezca TRILIUM_OAUTH_BASE_URL, TRILIUM_OAUTH_CLIENT_ID y TRILIUM_OAUTH_CLIENT_SECRET.",
"oauth_missing_vars": "Ajustes faltantes: {{-variables}}",
"oauth_user_account": "Cuenta de usuario: ",
@@ -1617,8 +1628,8 @@
"unarchive": "Desarchivar"
},
"shared_info": {
"shared_publicly": "Esta nota está compartida públicamente en {{- link}}",
"shared_locally": "Esta nota está compartida localmente en {{- link}}",
"shared_publicly": "Esta nota está compartida públicamente en {{- link}}.",
"shared_locally": "Esta nota está compartida localmente en {{- link}}.",
"help_link": "Para obtener ayuda visite <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>."
},
"note_types": {
@@ -1980,7 +1991,8 @@
"new-item-placeholder": "Ingresar título de la nota...",
"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"
"edit-column-title": "Haga clic para editar el título de la columna",
"remove-from-board": "Eliminar del tablero"
},
"content_renderer": {
"open_externally": "Abrir externamente"
@@ -2035,7 +2047,7 @@
},
"call_to_action": {
"next_theme_title": "Prueba el nuevo tema de Trilium",
"next_theme_message": "Estas usando actualmente el tema heredado, ¿Te gustaría probar el nuevo tema?",
"next_theme_message": "Estás usando actualmente el tema heredado. ¿Te gustaría probar el nuevo tema?",
"next_theme_button": "Prueba el nuevo tema",
"background_effects_title": "Los efectos de fondo son ahora estables",
"background_effects_message": "En los dispositivos Windows, los efectos de fondo ya son totalmente estables. Los efectos de fondo añaden un toque de color a la interfaz de usuario difuminando el fondo que hay detrás. Esta técnica también se utiliza en otras aplicaciones como el Explorador de Windows.",
@@ -2063,5 +2075,13 @@
"pagination": {
"total_notes": "{{count}} notas",
"page_title": "Página de {{startIndex}} - {{endIndex}}"
},
"presentation_view": {
"edit-slide": "Editar este slide",
"start-presentation": "Iniciar presentación",
"slide-overview": "Alternar vista general de los slides"
},
"collections": {
"rendering_error": "No se puede mostrar contenido debido a un error."
}
}

View File

@@ -276,7 +276,12 @@
"preview": "Aperçu :",
"preview_not_available": "L'aperçu n'est pas disponible pour ce type de note.",
"restore_button": "Restaurer",
"delete_button": "Supprimer"
"delete_button": "Supprimer",
"diff_on": "Afficher les différences",
"diff_off": "Afficher le contenu",
"diff_on_hint": "Cliquez pour afficher les différences de la note d'origine",
"diff_off_hint": "Cliquez pour afficher le contenu de la note",
"diff_not_available": "La comparaison n'est pas disponible."
},
"sort_child_notes": {
"sort_children_by": "Trier les enfants par...",
@@ -731,7 +736,8 @@
"insert_child_note": "Insérer une note enfant",
"delete_this_note": "Supprimer cette note",
"error_cannot_get_branch_id": "Impossible d'obtenir branchId pour notePath '{{notePath}}'",
"error_unrecognized_command": "Commande non reconnue {{command}}"
"error_unrecognized_command": "Commande non reconnue {{command}}",
"note_revisions": "Révision de la note"
},
"note_icon": {
"change_note_icon": "Changer l'icône de note",
@@ -1625,7 +1631,8 @@
"link_context_menu": {
"open_note_in_new_tab": "Ouvrir la note dans un nouvel onglet",
"open_note_in_new_split": "Ouvrir la note dans une nouvelle division",
"open_note_in_new_window": "Ouvrir la note dans une nouvelle fenêtre"
"open_note_in_new_window": "Ouvrir la note dans une nouvelle fenêtre",
"open_note_in_popup": "Édition rapide"
},
"electron_integration": {
"desktop-application": "Application de bureau",
@@ -1763,7 +1770,14 @@
"reprocess_index": "Rafraîchir l'index de recherche",
"reprocessing_index": "Mise à jour...",
"reprocess_index_started": "L'optimisation de l'indice de recherche à commencer en arrière-plan",
"reprocess_index_error": "Erreur dans le rafraichissement de l'indice de recherche"
"reprocess_index_error": "Erreur dans le rafraichissement de l'indice de recherche",
"failed_notes": "Notes échouées",
"last_processed": "Dernier traitement",
"restore_provider": "Restaurer le fournisseur de la recherche",
"index_rebuild_progress": "Progression de la reconstruction de l'index",
"index_rebuilding": "Optimisation de l'index ({{percentage}}%)",
"index_rebuild_complete": "Optimisation de l'index terminée",
"index_rebuild_status_error": "Erreur lors de la vérification de l'état de reconstruction de l'index"
},
"ui-performance": {
"title": "Performance",

View File

@@ -3,6 +3,30 @@
"title": "Tentang Trilium Notes",
"homepage": "Halaman utama:",
"app_version": "Versi Aplikasi:",
"db_version": "Versi DB:"
"db_version": "Versi DB:",
"sync_version": "Versi sinkronisasi:",
"build_date": "Tanggal pembuatan:",
"build_revision": "Revisi pembuatan:",
"data_directory": "Direktori data:"
},
"toast": {
"critical-error": {
"title": "Kesalahan kritis",
"message": "Telah terjadi kesalahan kritis yang mencegah aplikasi klien untuk memulai:\n\n{{message}}\n\nHal ini kemungkinan besar disebabkan oleh skrip yang gagal secara tidak terduga. Coba jalankan aplikasi dalam mode aman dan atasi masalahnya."
},
"widget-error": {
"title": "Gagal menginisialisasi widget",
"message-custom": "Widget kustom dari catatan dengan ID \"{{id}}\", berjudul \"{{title}}\" tidak dapat diinisialisasi karena:\n\n{{message}}",
"message-unknown": "Widget tidak dikenal tidak dapat diinisialisasi karena:\n\n{{message}}"
},
"bundle-error": {
"title": "Gagal memuat skrip kustom",
"message": "Skrip dari catatan dengan ID \"{{id}}\", berjudul \"{{title}}\" tidak dapat dijalankan karena:\n\n{{message}}"
}
},
"add_link": {
"add_link": "Tambah tautan",
"help_on_links": "Bantuan pada tautan",
"note": "Catatan"
}
}

View File

@@ -20,7 +20,7 @@
},
"widget-error": {
"title": "Impossibile inizializzare un widget",
"message-custom": "Il widget personalizzato della nota con ID \"{{id}}\", dal titolo \"{{title}}\" non è stato inizializzato a causa di:\n\n{{message}}",
"message-custom": "Il widget personalizzato dalla nota con ID {{id}}”, intitolato “{{title}}”, non è stato possibile inizializzare a causa di:\n\n{{message}}",
"message-unknown": "Un widget sconosciuto non è stato inizializzato a causa di:\n\n{{message}}"
}
},
@@ -83,14 +83,15 @@
"erase_notes_description": "L'eliminazione normale (soft) marca le note come eliminate e potranno essere recuperate entro un certo lasso di tempo (dalla finestra dei cambiamenti recenti). Selezionando questa opzione le note si elimineranno immediatamente e non sarà possibile recuperarle.",
"erase_notes_warning": "Elimina le note in modo permanente (non potrà essere disfatto), compresi tutti i cloni. Ciò forzerà un nuovo caricamento dell'applicazione.",
"cancel": "Annulla",
"notes_to_be_deleted": "Le seguenti note saranno eliminate ({{- noteCount}})",
"notes_to_be_deleted": "Le seguenti note saranno eliminate ({{notesCount}})",
"no_note_to_delete": "Nessuna nota sarà eliminata (solo i cloni).",
"broken_relations_to_be_deleted": "Le seguenti relazioni saranno interrotte ed eliminate ({{- relationCount}})",
"broken_relations_to_be_deleted": "Le seguenti relazioni saranno interrotte ed eliminate ({{relationCount}})",
"deleted_relation_text": "La nota {{- note}} (da eliminare) è referenziata dalla relazione {{- relation}} originata da {{- source}}."
},
"info": {
"okButton": "OK",
"closeButton": "Chiudi"
"closeButton": "Chiudi",
"modalTitle": "Messaggio informativo"
},
"export": {
"close": "Chiudi",
@@ -112,17 +113,23 @@
},
"password_not_set": {
"body1": "Le note protette sono crittografate utilizzando una password utente, ma la password non è stata ancora impostata.",
"body2": "Per proteggere le note, fare clic su <a class=\"open-password-options-button\" href=\"javascript:\">qui</a> per aprire la finestra di dialogo Opzioni e impostare la password."
"body2": "Per proteggere le note, clicca sul pulsante sottostante per aprire la finestra di dialogo Opzioni e impostare la tua password.",
"title": "La password non è impostata",
"go_to_password_options": "Vai alle opzioni della password"
},
"protected_session_password": {
"close_label": "Chiudi"
"close_label": "Chiudi",
"modal_title": "Sessione protetta",
"help_title": "Aiuto sulle note protette",
"form_label": "Per procedere con lazione richiesta, è necessario avviare una sessione protetta inserendo la password:",
"start_button": "Avvia sessione protetta"
},
"abstract_bulk_action": {
"remove_this_search_action": "Rimuovi questa azione di ricerca"
},
"etapi": {
"new_token_title": "Nuovo token ETAPI",
"new_token_message": "Inserire il nuovo nome del token"
"new_token_message": "Inserisci il nome del nuovo token"
},
"electron_integration": {
"zoom-factor": "Fattore di ingrandimento",
@@ -130,7 +137,7 @@
},
"note_autocomplete": {
"search-for": "Cerca \"{{term}}\"",
"create-note": "Crea e collega la nota figlia \"{{term}}\"",
"create-note": "Crea e collega la nota secondaria {{term}}",
"insert-external-link": "Inserisci il collegamento esterno a \"{{term}}\"",
"clear-text-field": "Pulisci il campo di testo",
"show-recent-notes": "Mostra le note recenti",
@@ -155,20 +162,20 @@
},
"database_anonymization": {
"light_anonymization": "Anonimizzazione parziale",
"title": "Anonimizzazione del Database",
"title": "Anonimizzazione dei database",
"full_anonymization": "Anonimizzazione completa",
"full_anonymization_description": "Questa azione creerà una nuova copia del database e lo anonimizzerà (rimuove tutti i contenuti delle note, lasciando solo la struttura e qualche metadato non sensibile) per condividerlo online allo scopo di debugging, senza paura di far trapelare i tuoi dati personali.",
"save_fully_anonymized_database": "Salva il database completamente anonimizzato",
"full_anonymization_description": "Questa azione creerà una nuova copia del database e la renderà anonima (rimuovendo tutto il contenuto delle note e lasciando solo la struttura e alcuni metadati non sensibili) per poterla condividere online a scopo di debug senza timore di divulgare i tuoi dati personali.",
"save_fully_anonymized_database": "Salva database completamente anonimizzato",
"light_anonymization_description": "Questa azione creerà una nuova copia del database e lo anonimizzerà in parzialmente — in particolare, solo il contenuto delle note sarà rimosso, ma i titoli e gli attributi rimarranno. Inoltre, note con script personalizzati JS di frontend/backend e widget personalizzati lasciando rimarranno. Ciò mette a disposizione più contesto per il debug dei problemi.",
"choose_anonymization": "Puoi decidere da solo se fornire un database completamente o parzialmente anonimizzato. Anche un database completamente anonimizzato è molto utile, sebbene in alcuni casi i database parzialmente anonimizzati possono accelerare il processo di identificazione dei bug e la loro correzione.",
"no_anonymized_database_yet": "Nessun database ancora anonimizzato.",
"save_lightly_anonymized_database": "Salva il database parzialmente anonimizzato",
"no_anonymized_database_yet": "Ancora nessun database anonimizzato.",
"save_lightly_anonymized_database": "Salva database leggermente anonimizzato",
"successfully_created_fully_anonymized_database": "Database completamente anonimizzato creato in {{anonymizedFilePath}}",
"successfully_created_lightly_anonymized_database": "Database parzialmente anonimizzato creato in {{anonymizedFilePath}}"
},
"cpu_arch_warning": {
"title": "Per favore scarica la versione ARM64",
"continue_anyway": "Continua Comunque",
"continue_anyway": "Continua comunque",
"dont_show_again": "Non mostrare più questo avviso",
"download_link": "Scarica la Versione Nativa"
},
@@ -248,7 +255,7 @@
"debug": "debug",
"action": "azione",
"add_search_option": "Aggiungi un opzione di ricerca:",
"search_string": "cerca la stringa",
"search_string": "stringa di ricerca",
"limit": "limite"
},
"modal": {
@@ -269,8 +276,10 @@
"date-and-time": "Data e ora",
"path": "Percorso",
"database_backed_up_to": "Il database è stato archiviato in {{backupFilePath}}",
"enable_daily_backup": "Abilita le archiviazioni giornaliere",
"no_backup_yet": "Ancora nessuna archiviazione"
"enable_daily_backup": "Abilita i backup giornalieri",
"no_backup_yet": "Ancora nessuna archiviazione",
"automatic_backup": "Backup Automatico",
"automatic_backup_description": "Trilium può eseguire automaticamente il backup del database:"
},
"backend_log": {
"refresh": "Aggiorna"
@@ -331,12 +340,12 @@
},
"heading_style": {
"title": "Stile dell'Intestazione",
"plain": "Normale",
"plain": "Semplice",
"underline": "Sottolineato",
"markdown": "Stile Markdown"
},
"highlights_list": {
"title": "Punti salienti"
"title": "Elenco dei punti salienti"
},
"highlights_list_2": {
"title": "Punti salienti",
@@ -351,6 +360,346 @@
"collapseExpand": "collassa/espande il nodo",
"notSet": "non impostato",
"goBackForwards": "indietro/avanti nella cronologia",
"showJumpToNoteDialog": "mostra <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">la finestra di dialogo \"Salta alla nota\"<a>"
"showJumpToNoteDialog": "mostra <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">finestra di dialogo “Vai a”</a>",
"title": "Scheda riassuntiva",
"noteNavigation": "Nota navigazione",
"scrollToActiveNote": "scorri fino alla nota attiva",
"jumpToParentNote": "vai alla nota principale",
"collapseWholeTree": "comprimi l'intero albero delle note",
"collapseSubTree": "comprimi sottoalbero",
"tabShortcuts": "Scorciatoie delle schede",
"newTabNoteLink": "Il link alla nota apre la nota in una nuova scheda",
"newTabWithActivationNoteLink": "Il link alla nota si apre e attiva la nota in una nuova scheda",
"onlyInDesktop": "Solo nella versione desktop (Electron build)",
"openEmptyTab": "apri scheda vuota",
"closeActiveTab": "chiudi scheda attiva",
"activateNextTab": "attiva la scheda successiva",
"activatePreviousTab": "attiva la scheda precedente",
"creatingNotes": "Creazione di note",
"createNoteAfter": "crea una nuova nota dopo quella attiva",
"createNoteInto": "crea una nuova sotto-nota nella nota attiva",
"editBranchPrefix": "modifica <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/tree-concepts.html#prefix\">prefisso</a> del clone della nota attiva",
"movingCloningNotes": "Spostamento / clonazione delle note",
"moveNoteUpDown": "spostare la nota verso l'alto/verso il basso nell'elenco delle note",
"moveNoteUpHierarchy": "spostare la nota verso l'alto nella gerarchia",
"multiSelectNote": "nota multi-selezione sopra/sotto",
"selectAllNotes": "seleziona tutte le note del livello corrente",
"selectNote": "seleziona nota",
"copyNotes": "copia la nota attiva (o la selezione corrente) negli appunti (utilizzata per la <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">clonazione</a>)",
"cutNotes": "taglia la nota corrente (o la selezione corrente) negli appunti (utilizzato per spostare le note)",
"pasteNotes": "Incolla le note come sotto-note nella nota attiva (che viene spostata o clonata a seconda che sia stata copiata o tagliata negli appunti)",
"deleteNotes": "eliminazione nota / sottoalbero",
"editingNotes": "Modifica delle note",
"editNoteTitle": "nel riquadro ad albero passa dal riquadro ad albero al titolo della nota. Premendo Invio dal titolo della nota, il focus passerà all'editor di testo. <kbd>Ctrl+.</kbd> riporterà il focus dall'editor al riquadro ad albero.",
"createEditLink": "crea / modifica collegamento esterno",
"createInternalLink": "creare un collegamento interno",
"followLink": "segui il link sotto il cursore",
"insertDateTime": "inserisci la data e l'ora correnti nella posizione del cursore",
"jumpToTreePane": "passa al riquadro dell'albero e scorri fino alla nota attiva",
"markdownAutoformat": "Formattazione automatica simile a Markdown",
"headings": "<code>##</code>, <code>###</code>, <code>####</code> ecc. seguiti da uno spazio per i titoli",
"bulletList": "<code>*</code> o <code>-</code> seguito da uno spazio per un elenco puntato",
"numberedList": "<code>1.</code> o <code>1)</code> seguito da uno spazio per un elenco numerato",
"blockQuote": "inizia una riga con <code>></code> seguito da uno spazio per il blocco di citazione",
"troubleshooting": "Risoluzione dei problemi",
"reloadFrontend": "ricarica il frontend Trilium",
"showDevTools": "mostra strumenti di sviluppo",
"showSQLConsole": "mostra console SQL",
"other": "Altro",
"quickSearch": "concentrati sull'input della ricerca rapida",
"inPageSearch": "ricerca all'interno della pagina"
},
"i18n": {
"saturday": "Sabato",
"sunday": "Domenica",
"first-week-of-the-year": "Prima settimana dell'anno",
"first-week-contains-first-day": "La prima settimana contiene il primo giorno dell'anno",
"first-week-contains-first-thursday": "La prima settimana contiene il primo giovedì dell'anno",
"first-week-has-minimum-days": "La prima settimana ha giorni ridotti",
"min-days-in-first-week": "Giorni minimi nella prima settimana",
"first-week-info": "La prima settimana che contiene il primo giovedì dell'anno si basa su <a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a> standard.",
"first-week-warning": "La modifica delle opzioni della prima settimana può causare duplicati con le note settimanali esistenti e queste ultime non verranno aggiornate di conseguenza.",
"formatting-locale": "Formato data e numero",
"formatting-locale-auto": "In base alla lingua dell'applicazione"
},
"ai_llm": {
"n_notes_queued_0": "{{ count }} nota in coda per l'indicizzazione",
"n_notes_queued_1": "{{ count }} note in coda per l'indicizzazione",
"n_notes_queued_2": "{{ count }} note in coda per l'indicizzazione",
"notes_indexed_0": "{{ count }} nota indicizzata",
"notes_indexed_1": "{{ count }} note indicizzate",
"notes_indexed_2": "{{ count }} note indicizzate"
},
"import": {
"importIntoNote": "Importa nella nota",
"chooseImportFile": "Scegli file di importazione",
"importDescription": "Il contenuto dei file selezionati verranno importati come note secondarie in",
"options": "Opzioni",
"safeImportTooltip": "I file di esportazione Trilium <code>.zip</code> possono contenere script eseguibili che potrebbero avere comportamenti dannosi. L'importazione sicura disattiverà l'esecuzione automatica di tutti gli script importati. Deseleziona “Importazione sicura” solo se l'archivio importato dovrebbe contenere script eseguibili e ti fidi completamente del contenuto del file di importazione.",
"safeImport": "Importazione sicura",
"explodeArchivesTooltip": "Se questa opzione è selezionata, Trilium leggerà i file <code>.zip</code>, <code>.enex</code> e <code>.opml</code> e creerà delle note dai file contenuti in tali archivi. Se l'opzione non è selezionata, Trilium allegherà gli archivi stessi alla nota.",
"shrinkImages": "Riduci immagini",
"explodeArchives": "Leggi il contenuto degli archivi <code>.zip</code>, <code>.enex</code> e <code>.opml</code> .",
"html_import_tags": {
"title": "Tag di importazione HTML",
"description": "Configura quali tag HTML devono essere mantenuti durante l'importazione delle note. I tag che non sono presenti in questo elenco verranno rimossi durante l'importazione. Alcuni tag (come 'script') vengono sempre rimossi per motivi di sicurezza.",
"placeholder": "Inserisci i tag HTML, uno per riga",
"reset_button": "Ripristina elenco predefinito"
},
"import-status": "Stato importazione",
"in-progress": "Importazione in corso: {{progress}}",
"successful": "Importazione completata con successo.",
"shrinkImagesTooltip": "<p>Se selezioni questa opzione, Trilium tenterà di ridurre le immagini importate tramite ridimensionamento e ottimizzazione, il che potrebbe influire sulla qualità percepita dellimmagine. Se non selezionata, le immagini verranno importate senza modifiche.</p><p>Questo non si applica alle importazioni <code>.zip</code> con metadati, poiché si presume che questi file siano già ottimizzati.</p>",
"textImportedAsText": "Importa HTML, Markdown e TXT come note di testo se non è chiaro dai metadati",
"codeImportedAsCode": "Importa i file di codice riconosciuti (ad esempio <code>.json</code>) come note di codice se non è chiaro dai metadati",
"replaceUnderscoresWithSpaces": "Sostituisci i trattini bassi con spazi nei nomi delle note importate",
"import": "Importa",
"failed": "Importazione fallita: {{message}}."
},
"include_note": {
"dialog_title": "Includi nota",
"label_note": "Note",
"placeholder_search": "cerca una nota per nome",
"box_size_prompt": "Dimensione della casella della nota inclusa:",
"box_size_small": "piccola (~ 10 righe)",
"box_size_medium": "media (~ 30 righe)",
"box_size_full": "completa (la casella mostra il testo completo)",
"button_include": "Includi nota"
},
"jump_to_note": {
"search_placeholder": "Cerca una nota per nome oppure digita > per i comandi...",
"search_button": "Cerca nel testo completo"
},
"markdown_import": {
"dialog_title": "Importazione Markdown",
"modal_body_text": "A causa del sandbox del browser non è possibile leggere direttamente gli appunti tramite JavaScript. Incolla il Markdown da importare nell'area di testo sottostante e clicca sul pulsante Importa",
"import_button": "Importa",
"import_success": "Il contenuto Markdown è stato importato nel documento."
},
"move_to": {
"target_parent_note": "Nota principale di destinazione",
"dialog_title": "Sposta note in ...",
"notes_to_move": "Note da spostare",
"search_placeholder": "cerca una nota per nome",
"move_button": "Sposta nella nota selezionata",
"error_no_path": "Nessun percorso in cui spostarsi.",
"move_success_message": "Le note selezionate sono state spostate in "
},
"note_type_chooser": {
"change_path_prompt": "Cambia dove creare la nuova nota:",
"search_placeholder": "cerca percorso per nome (predefinito se vuoto)",
"modal_title": "Scegli il tipo di nota",
"modal_body": "Scegli il tipo / modello della nuova nota:",
"templates": "Modelli",
"builtin_templates": "Modelli incorporati"
},
"prompt": {
"title": "Richiesta",
"ok": "OK",
"defaultTitle": "Richiesta"
},
"recent_changes": {
"title": "Modifiche recenti",
"erase_notes_button": "Cancella ora le note eliminate",
"deleted_notes_message": "Le note eliminate sono state cancellate.",
"no_changes_message": "Nessuna modifica ancora...",
"undelete_link": "ripristinare",
"confirm_undelete": "Vuoi ripristinare questa nota e le sue sotto-note?"
},
"revisions": {
"note_revisions": "Note Revisioni",
"delete_all_revisions": "Elimina tutte le revisioni di questa nota",
"delete_all_button": "Elimina tutte le revisioni",
"help_title": "Aiuto sulle revisioni delle note",
"revision_last_edited": "Questa revisione è stata modificata l'ultima volta il {{date}}",
"confirm_delete_all": "Vuoi eliminare tutte le revisioni di questa nota?",
"no_revisions": "Ancora nessuna revisione per questa nota...",
"restore_button": "Ripristina",
"diff_on": "Mostra differenze",
"diff_off": "Mostra contenuto",
"diff_on_hint": "Clicca per mostrare la fonte della nota diff",
"diff_off_hint": "Clicca per visualizzare il contenuto della nota",
"diff_not_available": "Diff non è disponibile.",
"confirm_restore": "Vuoi ripristinare questa revisione? Questo sovrascriverà il titolo e il contenuto attuali della nota con questa revisione.",
"delete_button": "Elimina",
"confirm_delete": "Vuoi eliminare questa revisione?",
"revisions_deleted": "Le revisioni delle note sono state eliminate.",
"revision_restored": "La revisione della nota è stata ripristinata.",
"revision_deleted": "La revisione della nota è stata eliminata.",
"snapshot_interval": "Nota Intervallo di revisione istantanea: {{seconds}}.",
"maximum_revisions": "Nota Limite istantaneo di revisione: {{number}}.",
"settings": "Nota Impostazioni di revisione",
"download_button": "Scarica",
"mime": "MIME: ",
"file_size": "Dimensione del file:",
"preview": "Anteprima:",
"preview_not_available": "L'anteprima non è disponibile per questo tipo di nota."
},
"sort_child_notes": {
"sort_children_by": "Ordina i bambini per...",
"sorting_criteria": "Criteri di ordinamento",
"title": "titolo",
"date_created": "data di creazione",
"date_modified": "data di modifica",
"sorting_direction": "Direzione",
"ascending": "ascendente",
"descending": "discendente",
"folders": "Cartelle",
"sort_folders_at_top": "ordina le cartelle in alto",
"natural_sort": "Ordinamento naturale",
"sort_with_respect_to_different_character_sorting": "ordinare in base alle diverse regole di ordinamento e collazione dei caratteri nelle diverse lingue o regioni.",
"natural_sort_language": "Linguaggio di ordinamento naturale",
"the_language_code_for_natural_sort": "Il codice lingua per l'ordinamento naturale, ad esempio \"zh-CN\" per il cinese.",
"sort": "Ordina"
},
"upload_attachments": {
"upload_attachments_to_note": "Carica allegati alla nota",
"choose_files": "Scegli i file",
"files_will_be_uploaded": "I file saranno caricati come allegati in {{noteTitle}}",
"options": "Opzioni",
"shrink_images": "Riduci immagini",
"upload": "Carica",
"tooltip": "Se selezioni questa opzione, Trilium tenterà di ridurre le immagini caricate tramite ridimensionamento e ottimizzazione, il che potrebbe influire sulla qualità percepita delle immagini. Se non selezionata, le immagini verranno caricate senza modifiche."
},
"attribute_detail": {
"attr_detail_title": "Titolo dettagli attributo",
"close_button_title": "Annulla modifiche e chiudi",
"attr_is_owned_by": "L'attributo è di proprietà di",
"attr_name_title": "Il nome dell'attributo può essere composto solo da caratteri alfanumerici, due punti e trattino basso",
"name": "Nome",
"app_theme_base": "impostare su \"next\", \"next-light\" o \"next-dark\" per utilizzare il tema TriliumNext corrispondente (automatico, chiaro o scuro) come base per un tema personalizzato, invece di quello precedente.",
"css_class": "Il valore di questa etichetta viene quindi aggiunto come classe CSS al nodo che rappresenta una determinata nota nell'albero. Ciò può essere utile per la personalizzazione avanzata dei temi. Può essere utilizzato nelle note dei modelli.",
"icon_class": "Il valore di questa etichetta viene aggiunto come classe CSS all'icona sull'albero, il che può aiutare a distinguere visivamente le note nell'albero. Un esempio potrebbe essere bx bx-home - le icone sono prese da boxicons. Può essere utilizzato nelle note del modello.",
"page_size": "numero di elementi per pagina nell'elenco delle note",
"custom_request_handler": "vedi <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Gestore richieste personalizzato</a>",
"custom_resource_provider": "vedi <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Gestore richieste personalizzato</a>",
"widget": "contrassegna questa nota come widget personalizzato che verrà aggiunto all'albero dei componenti Trilium",
"workspace": "contrassegna questa nota come area di lavoro che consente un facile ancoraggio",
"workspace_icon_class": "definisce la classe CSS dell'icona della casella che verrà utilizzata nella scheda quando viene sollevata su questa nota",
"workspace_tab_background_color": "Colore CSS utilizzato nella scheda delle note quando viene sollevato su questa nota",
"workspace_calendar_root": "Definisce la radice del calendario per ogni area di lavoro",
"workspace_template": "Questa nota apparirà nella selezione dei modelli disponibili quando si crea una nuova nota, ma solo se inserita in un'area di lavoro che contiene questo modello",
"search_home": "verranno create nuove note di ricerca come sottovoci di questa nota",
"value": "Valore",
"target_note_title": "La relazione è una connessione denominata tra la nota di origine e la nota di destinazione.",
"target_note": "Nota obiettivo",
"promoted_title": "L'attributo promosso viene visualizzato in modo ben visibile sulla nota.",
"promoted": "Promosso",
"promoted_alias_title": "Il nome da visualizzare nell'interfaccia utente degli attributi promossi.",
"promoted_alias": "Alias",
"multiplicity_title": "La molteplicità definisce quanti attributi con lo stesso nome possono essere creati: al massimo 1 o più di 1.",
"multiplicity": "Molteplicità",
"single_value": "Valore singolo",
"multi_value": "Valore multiplo",
"label_type_title": "Il tipo di etichetta aiuterà Trilium a scegliere l'interfaccia adatta per inserire il valore dell'etichetta.",
"label_type": "Tipo",
"text": "Testo",
"number": "Numero",
"boolean": "Booleano",
"date": "Data",
"date_time": "Data e Ora",
"time": "Ora",
"url": "URL",
"precision_title": "Quante cifre dopo la virgola mobile dovrebbero essere disponibili nell'interfaccia di impostazione del valore.",
"precision": "Precisione",
"digits": "cifre",
"inverse_relation_title": "Impostazione facoltativa per definire a quale relazione è opposta questa. Esempio: padre e figlio sono relazioni inverse l'una rispetto all'altra.",
"inheritable": "Ereditabile",
"inverse_relation": "Relazione inversa",
"inheritable_title": "L'attributo ereditario verrà ereditato da tutti i discendenti sotto questo albero.",
"save_and_close": "Salva e chiudi <kbd>Ctrl+Enter</kbd>",
"delete": "Eliminazione",
"related_notes_title": "Altre note con questa etichetta",
"more_notes": "Altre note",
"label": "Dettagli etichetta",
"label_definition": "Dettagli definizione etichetta",
"relation": "Dettagli relazione",
"relation_definition": "Dettagli definizione relazione",
"disable_versioning": "disabilita il versioning automatico. Utile ad esempio per note di grandi dimensioni ma non importanti, come le grandi librerie JS utilizzate per lo scripting",
"calendar_root": "segna le note che devono essere utilizzate come note principali per le note giornaliere. Solo una deve essere contrassegnata come tale.",
"archived": "Le note con questa etichetta non saranno visibili per impostazione predefinita nei risultati di ricerca (anche nelle finestre di dialogo Vai a, Aggiungi collegamento ecc.).",
"run_on_instance": "Definire su quale istanza di Trilium eseguire questa operazione. L'impostazione predefinita è tutte le istanze.",
"exclude_from_export": "le note (con la loro sottostruttura) non saranno incluse in nessuna esportazione di note",
"run": "definisce su quali eventi deve essere eseguito lo script. I valori possibili sono:\n<ul>\n<li>frontendStartup - quando il frontend Trilium viene avviato (o aggiornato), ma non su dispositivi mobili.</li>\n<li>mobileStartup - quando il frontend Trilium viene avviato (o aggiornato) su dispositivi mobili.</li>\n<li>backendStartup - quando viene avviato il backend Trilium</li>\n<li>hourly - eseguire una volta all'ora. È possibile utilizzare l'etichetta aggiuntiva <code>runAtHour</code> per specificare a che ora.</li>\n<li>daily - eseguire una volta al giorno</li>\n</ul>",
"run_at_hour": "A che ora deve essere eseguito. Deve essere utilizzato insieme a <code>#run=hourly</code>. Può essere definito più volte per più esecuzioni durante il giorno.",
"disable_inclusion": "gli script con questa etichetta non saranno inclusi nell'esecuzione dello script principale.",
"sorted": "mantiene le note figlie ordinate alfabeticamente per titolo",
"sort_direction": "ASC (impostazione predefinita) o DESC",
"sort_folders_first": "Le cartelle (note con figlie) devono essere ordinate in cima",
"top": "mantieni la nota in cima al suo genitore (si applica solo ai genitori ordinati)",
"hide_promoted_attributes": "Nascondi gli attributi promossi in questa nota",
"read_only": "L'editor è in modalità di sola lettura. Funziona solo per note di testo e codice.",
"auto_read_only_disabled": "Le note di testo/codice possono essere impostate automaticamente in modalità di lettura quando sono troppo grandi. È possibile disabilitare questo comportamento per ogni singola nota aggiungendo questa etichetta alla nota",
"app_css": "contrassegna le note CSS che vengono caricate nell'applicazione Trilium e possono quindi essere utilizzate per modificare l'aspetto di Trilium.",
"app_theme": "contrassegna le note CSS che sono temi Trilium completi e sono quindi disponibili nelle opzioni Trilium.",
"workspace_search_home": "nuove note di ricerca verranno create come figlie di questa nota quando sollevate a qualche antenato di questa nota dell'area di lavoro",
"inbox": "Posizione predefinita della casella di posta in arrivo per le nuove note: quando crei una nota utilizzando il pulsante \"Nuova nota\" nella barra laterale, le note verranno create come note secondarie nella nota contrassegnata con l'etichetta <code>#inbox</code>.",
"workspace_inbox": "posizione predefinita della casella di posta in arrivo per le nuove note quando vengono trasferite a un antenato di questa nota dell'area di lavoro",
"sql_console_home": "posizione predefinita delle note della console SQL",
"bookmark_folder": "le note con questa etichetta appariranno nei segnalibri come cartelle (consentendo l'accesso ai loro elementi secondari)",
"share_hidden_from_tree": "questa nota è nascosta dall'albero di navigazione a sinistra, ma è comunque accessibile tramite il suo URL",
"share_external_link": "La nota fungerà da collegamento a un sito web esterno nell'albero di condivisione",
"share_alias": "definisci un alias con cui la nota sarà disponibile all'indirizzo https://your_trilium_host/share/[your_alias]",
"share_omit_default_css": "Il CSS predefinito della pagina di condivisione verrà omesso. Utilizzarlo quando si apportano modifiche stilistiche significative.",
"keep_current_hoisting": "L'apertura di questo link non modificherà l'ancoraggio anche se la nota non è visualizzabile nell'attuale sottoalbero ancorato.",
"share_description": "definire il testo da aggiungere al meta tag HTML per la descrizione",
"share_raw": "La nota verrà visualizzata nel suo formato originale, senza wrapper HTML",
"share_disallow_robot_indexing": "impedirà l'indicizzazione robotica di questa nota tramite l'intestazione <code>X-Robots-Tag: noindex</code>",
"share_credentials": "richiedono credenziali per accedere a questa nota condivisa. Il valore deve essere nel formato 'username:password'. Non dimenticare di renderlo ereditabile affinché si applichi alle note/immagini secondarie.",
"share_index": "La nota con questa etichetta elencherà tutte le radici delle note condivise",
"display_relations": "nomi delle relazioni delimitati da virgola che devono essere visualizzati. Tutti gli altri saranno nascosti.",
"hide_relations": "nomi delle relazioni delimitati da virgola che devono essere nascosti. Tutti gli altri saranno visualizzati.",
"title_template": "titolo predefinito delle note create come figlie di questa nota. Il valore viene valutato come stringa JavaScript. \n e quindi può essere arricchito con contenuti dinamici tramite le variabili <code>now</code> e <code>parentNote</code> inserite. Esempi:\n \n <ul>\n <li><code>${parentNote.getLabelValue('authorName')}'s opere letterarie</code></li>\n <li><code>Log per ${now.format('YYYY-MM-DD HH:mm:ss')}</code></li>\n </ul>\n \n Per ulteriori dettagli, consultare <a href=\"https://triliumnext.github.io/Docs/Wiki/default-note-title.html\">wiki con i dettagli</a>, la documentazione API per <a href=\"https://zadam.github.io/trilium/backend_api/Note.html\">parentNote</a> e <a href=\"https://day.js.org/docs/en/display/format\">now</a>.",
"template": "Questa nota apparirà nella selezione dei modelli disponibili durante la creazione di una nuova nota",
"toc": "<code>#toc</code> o <code>#toc=show</code> forzeranno la visualizzazione del sommario, mentre <code>#toc=hide</code> ne forzerà la non visualizzazione. Se l'etichetta non esiste, verrà applicata l'impostazione globale",
"color": "definisce il colore della nota nell'albero delle note, nei link ecc. Utilizza qualsiasi valore di colore CSS valido come \"red\" o #a13d5f",
"keyboard_shortcut": "Definisce una scorciatoia da tastiera che consentirà di passare immediatamente a questa nota. Esempio: \"ctrl+alt+e\". Per rendere effettiva la modifica è necessario ricaricare il frontend.",
"execute_button": "Titolo del pulsante che eseguirà il codice della nota corrente",
"execute_description": "Descrizione più dettagliata della nota di codice corrente visualizzata insieme al pulsante di esecuzione",
"exclude_from_note_map": "Le note con questa etichetta saranno nascoste dalla mappa delle note",
"new_notes_on_top": "Le nuove note verranno create nella parte superiore della nota principale, non nella parte inferiore.",
"hide_highlight_widget": "Nascondi widget Elenco evidenziazioni",
"run_on_note_creation": "Viene eseguito quando viene creata una nota sul backend. Utilizza questa relazione se desideri eseguire lo script per tutte le note create in una sottostruttura specifica. In tal caso, crealo sulla nota radice della sottostruttura e rendilo ereditabile. Una nuova nota creata all'interno della sottostruttura (a qualsiasi profondità) attiverà lo script.",
"run_on_child_note_creation": "viene eseguito quando viene creata una nuova nota sotto la nota in cui è definita questa relazione",
"run_on_note_title_change": "viene eseguito quando viene modificato il titolo della nota (include anche la creazione della nota)",
"run_on_note_content_change": "Viene eseguito quando il contenuto della nota viene modificato (compresa la creazione della nota).",
"run_on_note_change": "Viene eseguito quando la nota viene modificata (compresa la creazione della nota). Non include le modifiche al contenuto",
"run_on_note_deletion": "viene eseguito quando la nota viene eliminata",
"run_on_branch_creation": "Viene eseguito quando viene creato un ramo. Il ramo è un collegamento tra la nota principale e la nota secondaria e viene creato, ad esempio, quando si clona o si sposta una nota.",
"run_on_branch_change": "viene eseguito quando un ramo viene aggiornato.",
"run_on_branch_deletion": "Viene eseguito quando viene eliminato un ramo. Il ramo è un collegamento tra una nota padre e una nota figlio e viene eliminato, ad esempio, quando si sposta una nota (il vecchio ramo/collegamento viene eliminato).",
"run_on_attribute_creation": "viene eseguito quando viene creato un nuovo attributo per la nota che definisce questa relazione",
"run_on_attribute_change": " viene eseguito quando viene modificato l'attributo di una nota che definisce questa relazione. Viene attivato anche quando l'attributo viene eliminato",
"relation_template": "Gli attributi della nota saranno ereditati anche senza una relazione padre-figlio, mentre il contenuto e la sottostruttura della nota saranno aggiunti alle note dell'istanza se vuote. Per ulteriori dettagli, consultare la documentazione.",
"inherit": "Gli attributi della nota saranno ereditati anche senza una relazione padre-figlio. Vedi relazione modello per un concetto simile. Vedi eredità degli attributi nella documentazione.",
"render_note": "le note di tipo \"renderizza nota HTML\" saranno renderizzate utilizzando una nota codice (HTML o script) ed è necessario indicare utilizzando questa relazione quale nota deve essere renderizzata",
"widget_relation": "L'obiettivo di questa relazione verrà eseguito e visualizzato come widget nella barra laterale",
"share_css": "Nota CSS che verrà inserita nella pagina condivisa. Anche la nota CSS deve trovarsi nella sottostruttura condivisa. Valuta anche l'utilizzo di 'share_hidden_from_tree' e 'share_omit_default_css'.",
"share_js": "Nota JavaScript che verrà inserita nella pagina di condivisione. Anche la nota JS deve trovarsi nella sottostruttura condivisa. Valuta l'utilizzo di 'share_hidden_from_tree'.",
"share_template": "Nota JavaScript incorporata che verrà utilizzata come modello per la visualizzazione della nota condivisa. Se non disponibile, verrà utilizzato il modello predefinito. Si consiglia di utilizzare 'share_hidden_from_tree'.",
"share_favicon": "Nota Favicon da impostare nella pagina condivisa. In genere è preferibile impostarla su \"condivisione radice\" e renderla ereditabile. Anche la nota Favicon deve trovarsi nella sottostruttura condivisa. Valutare l'utilizzo di 'share_hidden_from_tree'.",
"is_owned_by_note": "è di proprietà di nota",
"other_notes_with_name": "Altre note con {{attributeType}} nome \"{{attributeName}}\"",
"and_more": "... e altri {{count}}.",
"print_landscape": "Quando si esporta in PDF, cambia l'orientamento della pagina da verticale a orizzontale.",
"print_page_size": "Quando si esporta in PDF, modifica le dimensioni della pagina. Valori supportati: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.",
"color_type": "Colore",
"share_root": "segna la nota che viene servita su /share root."
},
"attribute_editor": {
"help_text_body1": "Per aggiungere un'etichetta, basta digitare ad esempio <code>#rock</code> oppure, se si desidera aggiungere anche un valore, ad esempio <code>#year = 2020</code>",
"help_text_body2": "Per la relazione, digita <code>~author = @</code>, che dovrebbe far apparire un completamento automatico in cui puoi cercare la nota desiderata.",
"help_text_body3": "In alternativa, è possibile aggiungere etichette e relazioni utilizzando il pulsante <code>+</code> sul lato destro.",
"save_attributes": "Salva attributi <enter>",
"add_a_new_attribute": "Aggiungi un nuovo attributo",
"add_new_label": "Aggiungi nuova etichetta <kbd data-command=\"addNewLabel\"></kbd>",
"add_new_relation": "Aggiungi nuova relazione <kbd data-command=\"addNewRelation\"></kbd>",
"add_new_relation_definition": "Aggiungi una nuova definizione di relazione",
"placeholder": "Digitare qui le etichette e le relazioni"
},
"execute_script": {
"execute_script": "Esegui script",
"help_text": "È possibile eseguire semplici script sulle note abbinate.",
"example_1": "Ad esempio, per aggiungere una stringa al titolo di una nota, utilizzare questo piccolo script:"
}
}

View File

@@ -68,7 +68,8 @@
"switch_to_desktop_version": "デスクトップ版に切り替え",
"configure_launchbar": "ランチャーバーの設定",
"show_shared_notes_subtree": "共有ノートのサブツリーを表示",
"update_available": "バージョン {{latestVersion}} が利用可能です。クリックしてダウンロードしてください。"
"new-version-available": "新しいアップデートが利用可能",
"download-update": "{{latestVersion}} をバージョンを入手"
},
"left_pane_toggle": {
"show_panel": "パネルを表示",
@@ -164,7 +165,12 @@
"first-week-info": "最初の週は、その年の最初の木曜日を含む週を指し、<a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a>規格に基づいています。",
"first-week-warning": "最初の週のオプションを変更すると、既存のウィークノートと重複する可能性があり、既存のウィークノートはそれに応じて更新されません。",
"formatting-locale": "日付と数値のフォーマット",
"formatting-locale-auto": "アプリケーションの言語に基づいて"
"formatting-locale-auto": "アプリケーションの言語に基づいて",
"tuesday": "火曜日",
"wednesday": "水曜日",
"thursday": "木曜日",
"friday": "金曜日",
"saturday": "土曜日"
},
"tab_row": {
"close_tab": "タブを閉じる",
@@ -276,8 +282,8 @@
"selectAllNotes": "現在のレベルのノートをすべて選択",
"selectNote": "ノートを選択",
"copyNotes": "アクティブなノート(または現在の選択範囲)をクリップボードにコピーする(<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">クローン</a>に使用)",
"cutNotes": "アクティブなノート(または現在の選択範囲)をクリップボードにカットする(ノートの移動に使用)",
"pasteNotes": "ノートをサブノートとしてアクティブノートに貼り付ける(コピーされたかカットされたかに よって、移動またはクローンになる)",
"cutNotes": "アクティブなノート(または現在の選択範囲)をクリップボードに切り取り(ノートの移動に使用)",
"pasteNotes": "ノートをサブノートとしてアクティブノートに貼り付ける(コピーされたか切り取りされたかに よって、移動またはクローンになる)",
"deleteNotes": "ノート/サブツリーを削除",
"editingNotes": "ノート編集",
"editNoteTitle": "押下するとツリーペインからタイトルの編集に移ります。タイトルの編集からEnterキーを押すと、本文の編集に移動します。<kbd>Ctrl+.</kbd> で本文の編集からツリーペインに戻ります。",
@@ -296,7 +302,7 @@
"showDevTools": "開発者ツールを表示",
"showSQLConsole": "SQLコンソールを表示",
"other": "その他",
"quickSearch": "クイックサーチにフォーカス",
"quickSearch": "クイック検索にフォーカス",
"inPageSearch": "ページ内検索",
"showJumpToNoteDialog": "<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">「ジャンプ先」ダイアログ</a>を表示",
"moveNoteUpDown": "ノートリストでノートを上/下に移動",
@@ -399,7 +405,7 @@
"unprotect-subtree": "サブツリーの保護を解除",
"copy-clone": "コピー/クローン",
"clone-to": "クローン先...",
"cut": "カット",
"cut": "切り取り",
"move-to": "移動先...",
"paste-into": "貼り付け",
"paste-after": "後ろに貼り付け",
@@ -528,7 +534,8 @@
"table": "テーブル",
"geo-map": "ジオマップ",
"board": "ボード",
"include_archived_notes": "アーカイブされたノートを表示"
"include_archived_notes": "アーカイブされたノートを表示",
"presentation": "プレゼンテーション"
},
"note_types": {
"geo-map": "ジオマップ",
@@ -1182,7 +1189,7 @@
"options": "オプション"
},
"quick-search": {
"placeholder": "クイックサーチ",
"placeholder": "クイック検索",
"searching": "検索中...",
"no-results": "結果は見つかりませんでした",
"more-results": "... および {{number}} 件の他の結果。",
@@ -1238,7 +1245,7 @@
"duplicated": "ノート \"{{title}}\" は複製されました。"
},
"clipboard": {
"cut": "ノートはクリップボードにカットされました。",
"cut": "ノートはクリップボードに切り取りとられました。",
"copied": "ノートはクリップボードにコピーされました。",
"copy_failed": "権限の問題で、クリップボードにコピーできません。",
"copy_success": "クリップボードにコピーしました。"
@@ -1289,7 +1296,7 @@
},
"electron_context_menu": {
"add-term-to-dictionary": "辞書に \"{{term}}\" を追加",
"cut": "カット",
"cut": "切り取り",
"copy": "コピー",
"copy-link": "リンクをコピー",
"paste": "貼り付け",
@@ -1875,7 +1882,9 @@
"window-on-top": "ウィンドウを最前面に維持"
},
"note_detail": {
"could_not_find_typewidget": "タイプ {{type}} の typeWidget が見つかりませんでした"
"could_not_find_typewidget": "タイプ {{type}} の typeWidget が見つかりませんでした",
"printing": "印刷中です...",
"printing_pdf": "PDF へのエクスポート中です..."
},
"watched_file_update_status": {
"ignore_this_change": "この変更を無視する",
@@ -2068,5 +2077,10 @@
"role_and_size": "ロール: {{role}},サイズ: {{size}}",
"link_copied": "添付ファイルのリンクをクリップボードにコピーしました。",
"unrecognized_role": "添付ファイルのロール「{{role}}」は認識されません。"
},
"presentation_view": {
"edit-slide": "このスライドを編集",
"start-presentation": "プレゼンテーションを開始",
"slide-overview": "スライドの概要を切り替え"
}
}

View File

@@ -49,5 +49,11 @@
"chosen_actions": "선택한 액션들",
"execute_bulk_actions": "대량 액션들 실행",
"bulk_actions_executed": "대량 액션들이 성공적으로 실행되었습니다."
},
"i18n": {
"saturday": "토요일",
"sunday": "일요일",
"first-week-of-the-year": "일년의 첫째 주",
"first-week-contains-first-day": "첫 번째 주에는 올해의 첫날이 포함됩니다"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -289,7 +289,8 @@
"table": "Tabel",
"geo-map": "Hartă geografică",
"board": "Tablă Kanban",
"include_archived_notes": "Afișează notițele arhivate"
"include_archived_notes": "Afișează notițele arhivate",
"presentation": "Prezentare"
},
"bookmark_switch": {
"bookmark": "Semn de carte",
@@ -611,7 +612,9 @@
"zoom_in": "Mărește",
"zoom_out": "Micșorează",
"show-cheatsheet": "Afișează ghidul rapid",
"toggle-zen-mode": "Mod zen"
"toggle-zen-mode": "Mod zen",
"new-version-available": "Actualizare nouă disponibilă",
"download-update": "Obțineți versiunea {{latestVersion}}"
},
"heading_style": {
"markdown": "Stil Markdown",
@@ -701,7 +704,13 @@
"first-week-has-minimum-days": "Prima săptămână are numărul minim de zile",
"min-days-in-first-week": "Numărul minim de zile pentru prima săptămână",
"first-week-info": "Opțiunea de prima săptămână conține prima zi de joi din an este bazată pe standardul <a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a>.",
"first-week-warning": "Schimbarea opțiunii primei săptămâni poate cauza duplicate cu notițele săptămânale existente deoarece acestea nu vor fi actualizate retroactiv."
"first-week-warning": "Schimbarea opțiunii primei săptămâni poate cauza duplicate cu notițele săptămânale existente deoarece acestea nu vor fi actualizate retroactiv.",
"tuesday": "Marți",
"wednesday": "Miercuri",
"thursday": "Joi",
"friday": "Vineri",
"saturday": "Sâmbătă",
"formatting-locale-auto": "În funcție de limba aplicației"
},
"image_properties": {
"copy_reference_to_clipboard": "Copiază referință în clipboard",
@@ -803,7 +812,8 @@
"delete_this_note": "Șterge această notiță",
"error_cannot_get_branch_id": "Nu s-a putut obține branchId-ul pentru calea „{{notePath}}”",
"error_unrecognized_command": "Comandă nerecunoscută „{{command}}”",
"insert_child_note": "Inserează subnotiță"
"insert_child_note": "Inserează subnotiță",
"note_revisions": "Revizuiri ale notițelor"
},
"move_note": {
"clone_note_new_parent": "clonează notița la noul părinte dacă notița are mai multe clone/ramuri (când nu este clar care ramură trebuie ștearsă)",
@@ -2069,5 +2079,10 @@
},
"collections": {
"rendering_error": "Nu a putut fi afișat conținutul din cauza unei erori."
},
"presentation_view": {
"edit-slide": "Editați acest slide",
"start-presentation": "Începeți prezentarea",
"slide-overview": "Afișați o imagine de ansamblu a slide-urilor"
}
}

View File

@@ -0,0 +1,8 @@
{
"about": {
"title": "Om Trilium Notes",
"homepage": "Hemsida:",
"app_version": "App version:",
"db_version": "DB version:"
}
}

View File

@@ -646,7 +646,9 @@
"about": "關於 TriliumNext 筆記",
"logout": "登出",
"show-cheatsheet": "顯示快捷鍵說明",
"toggle-zen-mode": "禪模式"
"toggle-zen-mode": "禪模式",
"new-version-available": "發現新更新",
"download-update": "取得版本 {{latestVersion}}"
},
"sync_status": {
"unknown": "<p>同步狀態將在下一次同步嘗試開始後顯示。</p><p>點擊以立即觸發同步。</p>",
@@ -733,7 +735,8 @@
"insert_child_note": "插入子筆記",
"delete_this_note": "刪除此筆記",
"error_cannot_get_branch_id": "無法獲取 notePath '{{notePath}}' 的 branchId",
"error_unrecognized_command": "無法識別的命令 {{command}}"
"error_unrecognized_command": "無法識別的命令 {{command}}",
"note_revisions": "筆記歷史版本"
},
"note_icon": {
"change_note_icon": "更改筆記圖標",
@@ -746,7 +749,7 @@
"editable": "可編輯",
"basic_properties": "基本屬性",
"language": "語言",
"configure_code_notes": "配寘代碼注釋..."
"configure_code_notes": "設定程式碼筆記…"
},
"book_properties": {
"view_type": "視圖類型",
@@ -762,7 +765,8 @@
"table": "表格",
"geo-map": "地理地圖",
"board": "看板",
"include_archived_notes": "顯示已封存筆記"
"include_archived_notes": "顯示已封存筆記",
"presentation": "簡報"
},
"edited_notes": {
"no_edited_notes_found": "今天還沒有編輯過的筆記...",
@@ -1250,7 +1254,13 @@
"min-days-in-first-week": "第一週的最少天數",
"first-week-info": "年度第一週包含第一個週四是基於 <a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a> 標準。",
"first-week-warning": "變更第一週選項可能導致與現有的「週筆記」重複,現有的「週筆記」將不會相應更新。",
"formatting-locale": "日期和數字格式"
"formatting-locale": "日期和數字格式",
"tuesday": "週二",
"wednesday": "週三",
"thursday": "週四",
"friday": "週五",
"saturday": "週六",
"formatting-locale-auto": "根據應用程式的語言設定"
},
"backup": {
"automatic_backup": "自動備份",
@@ -1431,7 +1441,7 @@
"relation-map": "關聯圖",
"note-map": "筆記地圖",
"render-note": "渲染筆記",
"mermaid-diagram": "美人魚圖Mermaid",
"mermaid-diagram": "美人魚圖",
"canvas": "畫布",
"web-view": "網頁顯示",
"mind-map": "心智圖",
@@ -1507,7 +1517,9 @@
"window-on-top": "保持此視窗置頂"
},
"note_detail": {
"could_not_find_typewidget": "找不到類型為 '{{type}}' 的 typeWidget"
"could_not_find_typewidget": "找不到類型為 '{{type}}' 的 typeWidget",
"printing": "正在列印…",
"printing_pdf": "正在匯出為 PDF…"
},
"note_title": {
"placeholder": "請輸入筆記標題..."
@@ -1627,7 +1639,7 @@
"label": "格式工具欄",
"floating": {
"title": "浮動",
"description": "編輯工具出現在標附近;"
"description": "編輯工具出現在標附近"
},
"fixed": {
"title": "固定",
@@ -2065,5 +2077,10 @@
},
"collections": {
"rendering_error": "發現錯誤,無法顯示內容。"
},
"presentation_view": {
"edit-slide": "編輯此投影片",
"start-presentation": "開始簡報",
"slide-overview": "切換投影片概覽"
}
}

View File

@@ -4,7 +4,10 @@
"title": "Về Trilium Notes",
"app_version": "Phiên bản:",
"db_version": "Phiên bản DB:",
"sync_version": "Phiên bản liên kết:"
"sync_version": "Phiên bản liên kết:",
"build_date": "Ngày build:",
"build_revision": "Xây dựng bản sửa đổi:",
"data_directory": "Đường dẫn dữ liệu:"
},
"add_link": {
"add_link": "Thêm liên kết",
@@ -34,7 +37,11 @@
},
"toast": {
"critical-error": {
"title": "Lỗi nghiêm trọng"
"title": "Lỗi nghiêm trọng",
"message": "Đã xảy ra lỗi nghiêm trọng ngăn ứng dụng client khởi động\n\n{{message}}\n\nĐiều này có khả năng bị gây ra bởi một script hoạt động không như mong đợi. Hãy thử khởi động ứng dụng ở chế độ an toàn và giải quyết vấn đề."
},
"widget-error": {
"title": "Khởi tạo widget thất bại"
}
},
"import": {

View File

@@ -16,7 +16,7 @@ interface ElectronProcess {
interface CustomGlobals {
isDesktop: typeof utils.isDesktop;
isMobile: typeof utils.isMobile;
device: "mobile" | "desktop";
device: "mobile" | "desktop" | "print";
getComponentByEl: typeof appContext.getComponentByEl;
getHeaders: typeof server.getHeaders;
getReferenceLinkTitle: (href: string) => Promise<string>;
@@ -59,6 +59,9 @@ declare global {
process?: ElectronProcess;
glob?: CustomGlobals;
/** On the printing endpoint, set to true when the note has fully loaded and is ready to be printed/exported as PDF. */
_noteReady?: boolean;
EXCALIDRAW_ASSET_PATH?: string;
}

View File

@@ -0,0 +1,45 @@
export function readCssVar(element: HTMLElement, varName: string) {
return new CssVarReader(getComputedStyle(element).getPropertyValue("--" + varName));
}
export class CssVarReader {
protected value: string;
constructor(rawValue: string) {
this.value = rawValue;
}
asString(defaultValue?: string) {
return (this.value) ? this.value : defaultValue;
}
asNumber(defaultValue?: number) {
let number: Number = NaN;
if (this.value) {
number = parseFloat(this.value);
}
return (!isNaN(number.valueOf()) ? number.valueOf() : defaultValue)
}
asEnum<T>(enumType: T, defaultValue?: T[keyof T]): T[keyof T] | undefined {
let result: T[keyof T] | undefined;
result = enumType[this.value as keyof T];
if (result === undefined) {
result = defaultValue;
}
return result;
}
asArray(delimiter: string = " "): CssVarReader[] {
// Note: ignoring delimiters inside quotation marks is currently unsupported
let values = this.value.split(delimiter);
return values.map((v) => new CssVarReader(v));
}
}

View File

@@ -9,6 +9,9 @@
}
button.global-menu-button {
--update-badge-x-offset: 4%;
--update-badge-y-offset: -16%;
position: relative;
width: 100% !important;
height: 100% !important;
@@ -55,13 +58,26 @@ button.global-menu-button {
.global-menu-button-update-available {
position: absolute;
inset-inline-end: -30px;
bottom: -30px;
width: 100%;
height: 100%;
display: flex;
width: 16px;
height: 16px;
right: calc(0px - var(--update-badge-x-offset));
bottom: calc(0px - var(--update-badge-y-offset));
justify-content: center;
align-items: center;
border-radius: 50%;
background: var(--global-menu-update-available-badge-background-color, var(--admonition-tip-accent-color));
color: var(--global-menu-update-available-badge-color, var(--main-background-color));
font-size: 16px;
transition: transform 200ms ease-in-out;
pointer-events: none;
}
.global-menu-button.show .global-menu-button-update-available {
transform: scale(.75);
transform-origin: center;
}
.global-menu .zoom-container {
display: flex;
flex-direction: row;
@@ -99,21 +115,6 @@ button.global-menu-button {
margin-inline-end: 6px;
}
/* #region Update available */
.global-menu-button-update-available-button {
width: 21px !important;
height: 21px !important;
padding: 0 !important;
border-radius: var(--button-border-radius);
transform: scale(0.9);
border: none;
opacity: 0.8;
display: flex;
align-items: center;
justify-content: center;
}
.global-menu-button-wrapper:hover .global-menu-button-update-available-button {
opacity: 1;

View File

@@ -3,7 +3,7 @@ import "./global_menu.css";
import { useStaticTooltip, useStaticTooltipWithKeyboardShortcut, useTriliumOption, useTriliumOptionBool, useTriliumOptionInt } from "../react/hooks";
import { useContext, useEffect, useRef, useState } from "preact/hooks";
import { t } from "../../services/i18n";
import { FormDropdownDivider, FormDropdownSubmenu, FormListItem } from "../react/FormList";
import { FormDropdownDivider, FormDropdownSubmenu, FormListHeader, FormListItem } from "../react/FormList";
import { CommandNames } from "../../components/app_context";
import KeyboardShortcut from "../react/KeyboardShortcut";
import { KeyboardActionNames } from "@triliumnext/commons";
@@ -26,7 +26,7 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
const isVerticalLayout = !isHorizontalLayout;
const parentComponent = useContext(ParentComponent);
const { isUpdateAvailable, latestVersion } = useTriliumUpdateStatus();
return (
<Dropdown
className="global-menu"
@@ -34,7 +34,7 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
text={<>
{isVerticalLayout && <VerticalLayoutIcon />}
{isUpdateAvailable && <div class="global-menu-button-update-available">
<span className="bx bx-sync global-menu-button-update-available-button" title={t("update_available.update_available")}></span>
<span className="bx bxs-down-arrow-alt global-menu-button-update-available-button" title={t("update_available.update_available")}></span>
</div>}
</>}
noDropdownListStyle
@@ -58,7 +58,14 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
<KeyboardActionMenuItem command="showHelp" icon="bx bx-help-circle" text={t("global_menu.show_help")} />
<KeyboardActionMenuItem command="showCheatsheet" icon="bx bxs-keyboard" text={t("global_menu.show-cheatsheet")} />
<MenuItem command="openAboutDialog" icon="bx bx-info-circle" text={t("global_menu.about")} />
{isUpdateAvailable && <MenuItem command={() => window.open("https://github.com/TriliumNext/Trilium/releases/latest")} icon="bx bx-sync" text={t("global_menu.update_available", { latestVersion })} /> }
{isUpdateAvailable && <>
<FormListHeader text={t("global_menu.new-version-available")} />
<MenuItem command={() => window.open("https://github.com/TriliumNext/Trilium/releases/latest")}
icon="bx bx-download"
text={t("global_menu.download-update", {latestVersion})} />
</>}
{!isElectron() && <BrowserOnlyOptions />}
</Dropdown>
)

View File

@@ -0,0 +1,29 @@
@keyframes left-pane-toggle-button-expand {
from {
rotate: 0deg;
} to {
rotate: 180deg;
}
}
@keyframes left-pane-toggle-button-collapse {
from {
rotate: 180deg;
} to {
rotate: 360deg;
}
}
.layout-vertical .left-pane-toggle-button::before {
display: block;
}
.layout-vertical .left-pane-toggle-button.action-collapse::before {
rotate: 360deg;
animation: left-pane-toggle-button-collapse 600ms ease-in-out;
}
.layout-vertical .left-pane-toggle-button.action-expand::before {
rotate: 180deg;
animation: left-pane-toggle-button-expand 600ms ease-in-out;
}

View File

@@ -1,3 +1,4 @@
import "./left_pane_toggle.css";
import { useEffect, useState } from "preact/hooks";
import ActionButton from "../react/ActionButton";
import options from "../../services/options";
@@ -18,12 +19,10 @@ export default function LeftPaneToggle({ isHorizontalLayout }: { isHorizontalLay
return (
<ActionButton
className={`${isHorizontalLayout ? "toggle-button" : "launcher-button"}`}
className={`${isHorizontalLayout ? "toggle-button" : "launcher-button"} left-pane-toggle-button ${currentLeftPaneVisible ? "action-collapse" : "action-expand"}`}
text={currentLeftPaneVisible ? t("left_pane_toggle.hide_panel") : t("left_pane_toggle.show_panel")}
triggerCommand={currentLeftPaneVisible ? "hideLeftPane" : "showLeftPane"}
icon={isHorizontalLayout
? "bx bx-sidebar"
: (currentLeftPaneVisible ? "bx bx-chevrons-left" : "bx bx-chevrons-right" )}
icon={isHorizontalLayout ? "bx bx-sidebar" : "bx bx-chevrons-left"}
/>
)
}

View File

@@ -1,4 +1,4 @@
import { allViewTypes, ViewModeProps, ViewTypeOptions } from "./interface";
import { allViewTypes, ViewModeMedia, ViewModeProps, ViewTypeOptions } from "./interface";
import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useTriliumEvent } from "../react/hooks";
import FNote from "../../entities/fnote";
import "./NoteList.css";
@@ -12,8 +12,9 @@ import BoardView from "./board";
import { subscribeToMessages, unsubscribeToMessage as unsubscribeFromMessage } from "../../services/ws";
import { WebSocketMessage } from "@triliumnext/commons";
import froca from "../../services/froca";
import PresentationView from "./presentation";
interface NoteListProps<T extends object> {
interface NoteListProps {
note: FNote | null | undefined;
notePath: string | null | undefined;
highlightedTokens?: string[] | null;
@@ -21,22 +22,24 @@ interface NoteListProps<T extends object> {
displayOnlyCollections?: boolean;
isEnabled: boolean;
ntxId: string | null | undefined;
media: ViewModeMedia;
onReady?: () => void;
}
export default function NoteList<T extends object>(props: Pick<NoteListProps<T>, "displayOnlyCollections">) {
export default function NoteList<T extends object>(props: Pick<NoteListProps, "displayOnlyCollections" | "media" | "onReady">) {
const { note, noteContext, notePath, ntxId } = useNoteContext();
const isEnabled = noteContext?.hasNoteList();
return <CustomNoteList note={note} isEnabled={!!isEnabled} notePath={notePath} ntxId={ntxId} {...props} />
}
export function SearchNoteList<T extends object>(props: Omit<NoteListProps<T>, "isEnabled">) {
export function SearchNoteList<T extends object>(props: Omit<NoteListProps, "isEnabled">) {
return <CustomNoteList {...props} isEnabled={true} />
}
function CustomNoteList<T extends object>({ note, isEnabled: shouldEnable, notePath, highlightedTokens, displayOnlyCollections, ntxId }: NoteListProps<T>) {
export function CustomNoteList<T extends object>({ note, isEnabled: shouldEnable, notePath, highlightedTokens, displayOnlyCollections, ntxId, onReady, ...restProps }: NoteListProps) {
const widgetRef = useRef<HTMLDivElement>(null);
const viewType = useNoteViewType(note);
const noteIds = useNoteIds(note, viewType, ntxId);
const noteIds = useNoteIds(shouldEnable ? note : null, viewType, ntxId);
const isFullHeight = (viewType && viewType !== "list" && viewType !== "grid");
const [ isIntersecting, setIsIntersecting ] = useState(false);
const shouldRender = (isFullHeight || isIntersecting || note?.type === "book");
@@ -75,12 +78,14 @@ function CustomNoteList<T extends object>({ note, isEnabled: shouldEnable, noteP
note, noteIds, notePath,
highlightedTokens,
viewConfig: viewModeConfig[0],
saveConfig: viewModeConfig[1]
saveConfig: viewModeConfig[1],
onReady: onReady ?? (() => {}),
...restProps
}
}
return (
<div ref={widgetRef} className={`note-list-widget component ${isFullHeight ? "full-height" : ""}`}>
<div ref={widgetRef} className={`note-list-widget component ${isFullHeight && isEnabled ? "full-height" : ""}`}>
{props && isEnabled && (
<div className="note-list-widget-content">
{getComponentByViewType(viewType, props)}
@@ -104,6 +109,8 @@ function getComponentByViewType(viewType: ViewTypeOptions, props: ViewModeProps<
return <TableView {...props} />
case "board":
return <BoardView {...props} />
case "presentation":
return <PresentationView {...props} />
}
}
@@ -120,7 +127,7 @@ function useNoteViewType(note?: FNote | null): ViewTypeOptions | undefined {
}
}
function useNoteIds(note: FNote | null | undefined, viewType: ViewTypeOptions | undefined, ntxId: string | null | undefined) {
export function useNoteIds(note: FNote | null | undefined, viewType: ViewTypeOptions | undefined, ntxId: string | null | undefined) {
const [ noteIds, setNoteIds ] = useState<string[]>([]);
const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived");
@@ -133,7 +140,7 @@ function useNoteIds(note: FNote | null | undefined, viewType: ViewTypeOptions |
}
async function getNoteIds(note: FNote) {
if (viewType === "list" || viewType === "grid") {
if (viewType === "list" || viewType === "grid" || viewType === "table" || note.type === "search") {
return note.getChildNoteIds();
} else {
return await note.getSubtreeNoteIds(includeArchived);
@@ -184,7 +191,7 @@ function useNoteIds(note: FNote | null | undefined, viewType: ViewTypeOptions |
return noteIds;
}
function useViewModeConfig<T extends object>(note: FNote | null | undefined, viewType: ViewTypeOptions | undefined) {
export function useViewModeConfig<T extends object>(note: FNote | null | undefined, viewType: ViewTypeOptions | undefined) {
const [ viewConfig, setViewConfig ] = useState<[T | undefined, (data: T) => void]>();
useEffect(() => {

View File

@@ -66,7 +66,7 @@ async function recursiveGroupBy(branches: FBranch[], byColumn: ColumnMap, groupB
const note = await branch.getNote();
if (!note || (!includeArchived && note.isArchived)) continue;
if (note.hasChildren()) {
if (note.type !== "search" && note.hasChildren()) {
await recursiveGroupBy(note.getChildBranches(), byColumn, groupByColumn, includeArchived);
}

View File

@@ -1,8 +1,10 @@
import FNote from "../../entities/fnote";
export const allViewTypes = ["list", "grid", "calendar", "table", "geoMap", "board"] as const;
export const allViewTypes = ["list", "grid", "calendar", "table", "geoMap", "board", "presentation"] as const;
export type ViewTypeOptions = typeof allViewTypes[number];
export type ViewModeMedia = "screen" | "print";
export interface ViewModeProps<T extends object> {
note: FNote;
notePath: string;
@@ -13,4 +15,6 @@ export interface ViewModeProps<T extends object> {
highlightedTokens: string[] | null | undefined;
viewConfig: T | undefined;
saveConfig(newConfig: T): void;
media: ViewModeMedia;
onReady(): void;
}

View File

@@ -106,6 +106,12 @@
text-align: center;
}
.note-list.list-view .note-path {
margin-left: 0.5em;
vertical-align: middle;
opacity: 0.5;
}
/* #region Grid view */
.note-list.grid-view .note-list-container {
display: flex;

View File

@@ -74,12 +74,12 @@ function ListNoteCard({ note, parentNote, expand, highlightedTokens }: { note: F
/>
<Icon className="note-icon" icon={note.getIcon()} />
<NoteLink className="note-book-title" notePath={notePath} noPreview showNotePath={note.type === "search"} highlightedTokens={highlightedTokens} />
<NoteLink className="note-book-title" notePath={notePath} noPreview showNotePath={parentNote.type === "search"} highlightedTokens={highlightedTokens} />
<NoteAttributes note={note} />
</h5>
{isExpanded && <>
<NoteContent note={note} highlightedTokens={highlightedTokens} />
<NoteContent note={note} highlightedTokens={highlightedTokens} noChildrenList />
<NoteChildren note={note} parentNote={parentNote} highlightedTokens={highlightedTokens} />
</>}
</div>
@@ -110,7 +110,11 @@ function GridNoteCard({ note, parentNote, highlightedTokens }: { note: FNote, pa
<span ref={titleRef} className="note-book-title">{noteTitle}</span>
<NoteAttributes note={note} />
</h5>
<NoteContent note={note} trim highlightedTokens={highlightedTokens} />
<NoteContent
note={note}
trim
highlightedTokens={highlightedTokens}
/>
</div>
)
}
@@ -126,12 +130,15 @@ function NoteAttributes({ note }: { note: FNote }) {
return <span className="note-list-attributes" ref={ref} />
}
function NoteContent({ note, trim, highlightedTokens }: { note: FNote, trim?: boolean, highlightedTokens }) {
function NoteContent({ note, trim, noChildrenList, highlightedTokens }: { note: FNote, trim?: boolean, noChildrenList?: boolean, highlightedTokens: string[] | null | undefined }) {
const contentRef = useRef<HTMLDivElement>(null);
const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens);
useEffect(() => {
content_renderer.getRenderedContent(note, { trim })
content_renderer.getRenderedContent(note, {
trim,
noChildrenList
})
.then(({ $renderedContent, type }) => {
if (!contentRef.current) return;
contentRef.current.replaceChildren(...$renderedContent);

View File

@@ -0,0 +1,10 @@
.presentation-button-bar {
position: absolute;
top: 1em;
right: 1em;
}
.presentation-container {
width: 100%;
height: 100%;
}

View File

@@ -0,0 +1,245 @@
import { ViewModeMedia, ViewModeProps } from "../interface";
import { useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
import Reveal from "reveal.js";
import slideBaseStylesheet from "reveal.js/dist/reveal.css?raw";
import slideCustomStylesheet from "./slidejs.css?raw";
import { buildPresentationModel, PresentationModel, PresentationSlideBaseModel } from "./model";
import ShadowDom from "../../react/ShadowDom";
import ActionButton from "../../react/ActionButton";
import "./index.css";
import { RefObject } from "preact";
import { openInCurrentNoteContext } from "../../../components/note_context";
import { useNoteLabelWithDefault, useTriliumEvent } from "../../react/hooks";
import { t } from "../../../services/i18n";
import { DEFAULT_THEME, loadPresentationTheme } from "./themes";
import FNote from "../../../entities/fnote";
export default function PresentationView({ note, noteIds, media, onReady }: ViewModeProps<{}>) {
const [ presentation, setPresentation ] = useState<PresentationModel>();
const containerRef = useRef<HTMLDivElement>(null);
const [ api, setApi ] = useState<Reveal.Api>();
const stylesheets = usePresentationStylesheets(note, media);
function refresh() {
buildPresentationModel(note).then(setPresentation);
}
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
if (loadResults.getNoteIds().find(noteId => noteIds.includes(noteId)) ||
loadResults.getAttributeRows().find(attr => attr.noteId && attr.name?.startsWith("slide:") && noteIds.includes(attr.noteId))) {
refresh();
}
});
useLayoutEffect(refresh, [ note, noteIds ]);
useEffect(() => {
// We need to wait for Reveal.js to initialize (by setting api) and for the presentation to become available.
if (api && presentation) {
// Timeout is necessary because it otherwise can cause flakiness by rendering only the first slide.
setTimeout(onReady, 200);
}
}, [ api, presentation ]);
if (!presentation || !stylesheets) return;
const content = (
<>
{stylesheets.map(stylesheet => <style>{stylesheet}</style>)}
<Presentation presentation={presentation} setApi={setApi} />
</>
);
if (media === "screen") {
return (
<>
<ShadowDom
className="presentation-container"
containerRef={containerRef}
>{content}</ShadowDom>
<ButtonOverlay containerRef={containerRef} api={api} />
</>
)
} else if (media === "print") {
// Printing needs a query parameter that is read by Reveal.js.
const url = new URL(window.location.href);
url.searchParams.set("print-pdf", "");
window.history.replaceState({}, '', url);
// Shadow DOM doesn't work well with Reveal.js's PDF printing mechanism.
return content;
}
}
function usePresentationStylesheets(note: FNote, media: ViewModeMedia) {
const [ themeName ] = useNoteLabelWithDefault(note, "presentation:theme", DEFAULT_THEME);
const [ stylesheets, setStylesheets ] = useState<string[]>();
useLayoutEffect(() => {
loadPresentationTheme(themeName).then((themeStylesheet) => {
let stylesheets = [
slideBaseStylesheet,
themeStylesheet,
slideCustomStylesheet
];
if (media === "screen") {
// We are rendering in the shadow DOM, so the global variables are not set correctly.
stylesheets = stylesheets.map(stylesheet => stylesheet.replace(/:root/g, ":host"));
}
setStylesheets(stylesheets);
});
}, [ themeName ]);
return stylesheets;
}
function ButtonOverlay({ containerRef, api }: { containerRef: RefObject<HTMLDivElement>, api: Reveal.Api | undefined }) {
const [ isOverviewActive, setIsOverviewActive ] = useState(false);
useEffect(() => {
if (!api) return;
setIsOverviewActive(api.isOverview());
const onEnabled = () => setIsOverviewActive(true);
const onDisabled = () => setIsOverviewActive(false);
api.on("overviewshown", onEnabled);
api.on("overviewhidden", onDisabled);
return () => {
api.off("overviewshown", onEnabled);
api.off("overviewhidden", onDisabled);
};
}, [ api ]);
return (
<div className="presentation-button-bar">
<div className="floating-buttons-children">
<ActionButton
className="floating-button"
icon="bx bx-edit"
text={t("presentation_view.edit-slide")}
noIconActionClass
onClick={e => {
const currentSlide = api?.getCurrentSlide();
const noteId = getNoteIdFromSlide(currentSlide);
if (noteId) {
openInCurrentNoteContext(e, noteId);
}
}}
/>
<ActionButton
className="floating-button"
icon="bx bx-grid-horizontal"
text={t("presentation_view.slide-overview")}
active={isOverviewActive}
noIconActionClass
onClick={() => api?.toggleOverview()}
/>
<ActionButton
className="floating-button"
icon="bx bx-fullscreen"
text={t("presentation_view.start-presentation")}
noIconActionClass
onClick={() => containerRef.current?.requestFullscreen()}
/>
</div>
</div>
)
}
function Presentation({ presentation, setApi } : { presentation: PresentationModel, setApi: (api: Reveal.Api | undefined) => void }) {
const containerRef = useRef<HTMLDivElement>(null);
const [revealApi, setRevealApi] = useState<Reveal.Api>();
useEffect(() => {
if (!containerRef.current) return;
const api = new Reveal(containerRef.current, {
transition: "slide",
embedded: true,
pdfMaxPagesPerSlide: 1,
keyboardCondition(event) {
// Full-screen requests sometimes fail, we rely on the UI button instead.
if (event.key === "f") {
return false;
}
return true;
},
});
api.initialize().then(() => {
setRevealApi(api);
setApi(api);
if (containerRef.current) {
rewireLinks(containerRef.current, api);
}
});
return () => {
api.destroy();
setRevealApi(undefined);
setApi(undefined);
}
}, []);
useEffect(() => {
revealApi?.sync();
}, [ presentation, revealApi ]);
return (
<div ref={containerRef} className="reveal">
<div className="slides">
{presentation.slides?.map(slide => {
if (!slide.verticalSlides) {
return <Slide key={slide.noteId} slide={slide} />
} else {
return (
<section>
<Slide key={slide.noteId} slide={slide} />
{slide.verticalSlides.map(slide => <Slide key={slide.noteId} slide={slide} /> )}
</section>
);
}
})}
</div>
</div>
)
}
function Slide({ slide }: { slide: PresentationSlideBaseModel }) {
return (
<section
id={`slide-${slide.noteId}`}
data-note-id={slide.noteId}
data-background-color={slide.backgroundColor}
data-background-gradient={slide.backgroundGradient}
dangerouslySetInnerHTML={slide.content}
/>
);
}
function getNoteIdFromSlide(slide: HTMLElement | undefined) {
if (!slide) return;
return slide.dataset.noteId;
}
function rewireLinks(container: HTMLElement, api: Reveal.Api) {
const links = container.querySelectorAll<HTMLLinkElement>("a.reference-link");
for (const link of links) {
link.addEventListener("click", () => {
/**
* Reveal.js has built-in navigation by either index or ID. However, the ID-based navigation doesn't work because it tries to look
* outside the shadom DOM (via document.getElementById).
*/
const url = new URL(link.href);
if (!url.hash.startsWith("#/slide-")) return;
const targetId = url.hash.substring(8);
const slide = container.querySelector<HTMLElement>(`#slide-${targetId}`);
if (!slide) return;
const { h, v, f } = api.getIndices(slide);
api.slide(h, v, f);
});
}
}

View File

@@ -0,0 +1,83 @@
import { beforeAll, describe, expect, it } from "vitest";
import { buildNote } from "../../../test/easy-froca";
import FNote from "../../../entities/fnote";
import { buildPresentationModel, PresentationModel } from "./model";
let presentationNote!: FNote;
let data!: PresentationModel;
describe("Presentation model", () => {
beforeAll(async () => {
presentationNote = buildNote({
title: "Presentation",
id: "presentation",
"#viewType": "presentation",
"children": [
{
id: "slide1",
title: "First slide",
children: [
{
id: "slide2",
title: "First-sub",
content: `<p>Go to&nbsp;<a class="reference-link" href="#root/other">Other note</a>.</p>`
}
]
},
{
title: "Second slide",
id: "slide3",
content: `<p>Go to&nbsp;<a class="reference-link" href="#root/presentation/slide1">First slide</a>.</p>`,
children: [
{
id: "slide4",
title: "Second-sub",
content: `<p>Go to&nbsp;<a class="reference-link" href="#root/presentation/slide2">First-sub</a>.</p>`,
}
]
}
]
});
buildNote({
id: "other",
title: "Other note"
});
data = await buildPresentationModel(presentationNote);
});
it("it correctly maps horizontal and vertical slides", () => {
expect(data).toMatchObject({
slides: [
{
noteId: "slide1",
verticalSlides: [
{
noteId: "slide2"
}
]
},
{
noteId: "slide3",
verticalSlides: [
{
noteId: "slide4"
}
]
}
]
})
});
it("empty slides don't render children", () => {
expect(data.slides[0].content.__html).toStrictEqual("");
});
it("rewrites links to other slides", () => {
expect(data.slides[1].content.__html).toStrictEqual(`<div class="ck-content"><p>Go to&nbsp;<a class="reference-link" href="#/slide-slide1"><span class="bx bx-folder"></span>First slide</a>.</p></div>`);
expect(data.slides[1].verticalSlides![0].content.__html).toStrictEqual(`<div class="ck-content"><p>Go to&nbsp;<a class="reference-link" href="#/slide-slide2"><span class="bx bx-note"></span>First-sub</a>.</p></div>`);
});
it("rewrites links even if they are not part of the slideshow", () => {
expect(data.slides[0].verticalSlides![0].content.__html).toStrictEqual(`<div class="ck-content"><p>Go to&nbsp;<a class="reference-link" href="#/slide-other"><span class="bx bx-note"></span>Other note</a>.</p></div>`);
});
});

View File

@@ -0,0 +1,73 @@
import { NoteType } from "@triliumnext/commons";
import FNote from "../../../entities/fnote";
import contentRenderer from "../../../services/content_renderer";
type DangerouslySetInnerHTML = { __html: string; };
/** A top-level slide with optional vertical slides. */
interface PresentationSlideModel extends PresentationSlideBaseModel {
verticalSlides: PresentationSlideBaseModel[] | undefined;
}
/** Either a top-level slide or a vertical slide. */
export interface PresentationSlideBaseModel {
noteId: string;
type: NoteType;
content: DangerouslySetInnerHTML;
backgroundColor?: string;
backgroundGradient?: string;
}
export interface PresentationModel {
slides: PresentationSlideModel[];
}
export async function buildPresentationModel(note: FNote): Promise<PresentationModel> {
const slideNotes = await note.getChildNotes();
const slides: PresentationSlideModel[] = await Promise.all(slideNotes.map(async slideNote => ({
...(await buildSlideModel(slideNote)),
verticalSlides: note.type !== "search" ? await buildVerticalSlides(slideNote) : undefined
})));
postProcessSlides(slides);
return { slides };
}
async function buildVerticalSlides(parentSlideNote: FNote): Promise<undefined | PresentationSlideBaseModel[]> {
const children = await parentSlideNote.getChildNotes();
if (!children.length) return;
const slides: PresentationSlideBaseModel[] = await Promise.all(children.map(buildSlideModel));
return slides;
}
async function buildSlideModel(note: FNote): Promise<PresentationSlideBaseModel> {
const slideBackground = note.getLabelValue("slide:background") ?? undefined;
const isGradient = slideBackground?.includes("gradient(");
return {
noteId: note.noteId,
type: note.type,
content: await processContent(note),
backgroundColor: !isGradient ? slideBackground : undefined,
backgroundGradient: isGradient ? slideBackground : undefined
}
}
async function processContent(note: FNote): Promise<DangerouslySetInnerHTML> {
const { $renderedContent } = await contentRenderer.getRenderedContent(note, {
noChildrenList: true
});
return { __html: $renderedContent.html() };
}
async function postProcessSlides(slides: (PresentationSlideModel | PresentationSlideBaseModel)[]) {
for (const slide of slides) {
if (slide.type !== "text") continue;
slide.content.__html = slide.content.__html.replaceAll(/href="[^"]*#root[a-zA-Z0-9_\/]*\/([a-zA-Z0-9_]+)[^"]*"/g, `href="#/slide-$1"`);
if ("verticalSlides" in slide && slide.verticalSlides) {
postProcessSlides(slide.verticalSlides);
}
}
}

View File

@@ -0,0 +1,29 @@
figure img {
aspect-ratio: unset !important;
height: auto !important;
}
span.katex-html {
display: none !important;
}
p:has(span.text-tiny),
p:has(span.text-small),
p:has(span.text-big),
p:has(span.text-huge) {
line-height: unset !important;
}
span.text-tiny { font-size: 0.5em; }
span.text-small { font-size: 0.75em; }
span.text-big { font-size: 1.5em; }
span.text-huge { font-size: 2em; }
footer.file-footer {
display: none !important;
}
.reveal video {
max-width: unset;
max-height: unset;
}

View File

@@ -0,0 +1,10 @@
import { it, describe } from "vitest";
import { getPresentationThemes, loadPresentationTheme } from "./themes";
describe("Presentation themes", () => {
it("can load all themes", async () => {
const themes = getPresentationThemes();
await Promise.all(themes.map(theme => loadPresentationTheme(theme.id)));
});
});

View File

@@ -0,0 +1,58 @@
export const DEFAULT_THEME = "white";
const themes = {
black: {
name: "Black",
loadTheme: () => import("reveal.js/dist/theme/black.css?raw")
},
white: {
name: "White",
loadTheme: () => import("reveal.js/dist/theme/white.css?raw")
},
beige: {
name: "Beige",
loadTheme: () => import("reveal.js/dist/theme/beige.css?raw")
},
serif: {
name: "Serif",
loadTheme: () => import("reveal.js/dist/theme/serif.css?raw")
},
simple: {
name: "Simple",
loadTheme: () => import("reveal.js/dist/theme/simple.css?raw")
},
solarized: {
name: "Solarized",
loadTheme: () => import("reveal.js/dist/theme/solarized.css?raw")
},
moon: {
name: "Moon",
loadTheme: () => import("reveal.js/dist/theme/moon.css?raw")
},
dracula: {
name: "Dracula",
loadTheme: () => import("reveal.js/dist/theme/dracula.css?raw")
},
sky: {
name: "Sky",
loadTheme: () => import("reveal.js/dist/theme/sky.css?raw")
},
blood: {
name: "Blood",
loadTheme: () => import("reveal.js/dist/theme/blood.css?raw")
}
} as const;
export function getPresentationThemes() {
return Object.entries(themes).map(([ id, theme ]) => ({
id: id,
name: theme.name
}));
}
export async function loadPresentationTheme(name: keyof typeof themes | string) {
let theme = themes[name];
if (!theme) theme = themes[DEFAULT_THEME];
return (await theme.loadTheme()).default;
}

View File

@@ -2,7 +2,7 @@ import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "p
import { ViewModeProps } from "../interface";
import { buildColumnDefinitions } from "./columns";
import getAttributeDefinitionInformation, { buildRowDefinitions, TableData } from "./rows";
import { useLegacyWidget, useNoteLabelBoolean, useNoteLabelInt, useSpacedUpdate, useTriliumEvent } from "../../react/hooks";
import { useLegacyWidget, useNoteLabelBoolean, useNoteLabelInt, useTriliumEvent } from "../../react/hooks";
import Tabulator from "./tabulator";
import { Tabulator as VanillaTabulator, SortModule, FormatModule, InteractionModule, EditModule, ResizeColumnsModule, FrozenColumnsModule, PersistenceModule, MoveColumnsModule, MoveRowsModule, ColumnDefinition, DataTreeModule, Options, RowComponent} from 'tabulator-tables';
import { useContextMenu } from "./context_menu";
@@ -17,6 +17,7 @@ import AttributeDetailWidget from "../../attribute_widgets/attribute_detail";
import attributes from "../../../services/attributes";
import { RefObject } from "preact";
import SpacedUpdate from "../../../services/spaced_update";
import froca from "../../../services/froca";
interface TableConfig {
tableData: {
@@ -132,25 +133,27 @@ function useData(note: FNote, noteIds: string[], viewConfig: TableConfig | undef
const [ isSorted ] = useNoteLabelBoolean(note, "sorted");
const [ movableRows, setMovableRows ] = useState(false);
function refresh() {
async function refresh() {
const info = getAttributeDefinitionInformation(note);
buildRowDefinitions(note, info, includeArchived, maxDepth).then(({ definitions: rowData, hasSubtree: hasChildren, rowNumber }) => {
const columnDefs = buildColumnDefinitions({
info,
movableRows,
existingColumnData: viewConfig?.tableData?.columns,
rowNumberHint: rowNumber,
position: newAttributePosition.current ?? undefined
});
setColumnDefs(columnDefs);
setRowData(rowData);
setHasChildren(hasChildren);
resetNewAttributePosition();
// Ensure all note IDs are loaded.
await froca.getNotes(noteIds);
const { definitions: rowData, hasSubtree: hasChildren, rowNumber } = await buildRowDefinitions(note, info, includeArchived, maxDepth);
const columnDefs = buildColumnDefinitions({
info,
movableRows,
existingColumnData: viewConfig?.tableData?.columns,
rowNumberHint: rowNumber,
position: newAttributePosition.current ?? undefined
});
setColumnDefs(columnDefs);
setRowData(rowData);
setHasChildren(hasChildren);
resetNewAttributePosition();
}
useEffect(refresh, [ note, noteIds, maxDepth, movableRows ]);
useEffect(() => { refresh() }, [ note, noteIds, maxDepth, movableRows ]);
useTriliumEvent("entitiesReloaded", ({ loadResults}) => {
// React to column changes.

View File

@@ -20,6 +20,10 @@ export async function buildRowDefinitions(parentNote: FNote, infos: AttributeDef
let hasSubtree = false;
let rowNumber = childBranches.length;
if (parentNote.type === "search") {
maxDepth = 0;
}
for (const branch of childBranches) {
const note = await branch.getNote();
if (!note || (!includeArchived && note.isArchived)) {

View File

@@ -37,7 +37,7 @@ export default function ImportDialog() {
onSubmit={async () => {
if (!files || !parentNoteId) {
return;
}
}
const options: UploadFilesOptions = {
safeImport: boolToString(safeImport),
@@ -51,11 +51,19 @@ export default function ImportDialog() {
setShown(false);
await importService.uploadFiles("notes", parentNoteId, Array.from(files), options);
}}
onHidden={() => setShown(false)}
onHidden={() => {
setShown(false);
setFiles(null);
}}
footer={<Button text={t("import.import")} primary disabled={!files} />}
show={shown}
>
<FormGroup name="files" label={t("import.chooseImportFile")} description={<>{t("import.importDescription")} <strong>{ noteTitle }</strong></>}>
<FormGroup name="files" label={t("import.chooseImportFile")} description={
<>
{t("import.importDescription")} <strong>{ noteTitle }</strong>.<br />
{t("import.importZipRecommendation")}
</>
}>
<FormFileUpload multiple onChange={setFiles} />
</FormGroup>
@@ -82,7 +90,7 @@ export default function ImportDialog() {
currentValue={codeImportedAsCode} onChange={setCodeImportedAsCode}
/>
<FormCheckbox
name="replace-underscores-with-spaces" label={t("import.replaceUnderscoresWithSpaces")}
name="replace-underscores-with-spaces" label={t("import.replaceUnderscoresWithSpaces")}
currentValue={replaceUnderscoresWithSpaces} onChange={setReplaceUnderscoresWithSpaces}
/>
</FormMultiGroup>
@@ -92,4 +100,4 @@ export default function ImportDialog() {
function boolToString(value: boolean) {
return value ? "true" : "false";
}
}

View File

@@ -26,7 +26,7 @@ export interface PromptDialogOptions {
readOnly?: boolean;
}
export default function PromptDialog() {
export default function PromptDialog() {
const modalRef = useRef<HTMLDivElement>(null);
const formRef = useRef<HTMLFormElement>(null);
const labelRef = useRef<HTMLLabelElement>(null);
@@ -35,7 +35,7 @@ export default function PromptDialog() {
const [ value, setValue ] = useState("");
const [ shown, setShown ] = useState(false);
const submitValue = useRef<string>(null);
useTriliumEvent("showPromptDialog", (newOpts) => {
opts.current = newOpts;
setValue(newOpts.defaultValue ?? "");
@@ -48,7 +48,7 @@ export default function PromptDialog() {
title={opts.current?.title ?? t("prompt.title")}
size="lg"
zIndex={2000}
modalRef={modalRef} formRef={formRef}
modalRef={modalRef} formRef={formRef}
onShown={() => {
opts.current?.shown?.({
$dialog: refToJQuerySelector(modalRef),
@@ -57,6 +57,7 @@ export default function PromptDialog() {
$form: refToJQuerySelector(formRef)
});
answerRef.current?.focus();
answerRef.current?.select();
}}
onSubmit={() => {
submitValue.current = value;

View File

@@ -28,6 +28,7 @@ export default function ProtectedSessionPasswordDialog() {
>
<label htmlFor="protected-session-password" className="col-form-label">{t("protected_session_password.form_label")}</label>
<FormTextBox
inputRef={inputRef}
id="protected-session-password"
name="protected-session-password"
type="password"

View File

@@ -40,14 +40,17 @@ export default function UploadAttachmentsDialog() {
if (!files || !parentNoteId) {
return;
}
setIsUploading(true);
const filesCopy = Array.from(files);
await importService.uploadFiles("attachments", parentNoteId, filesCopy, { shrinkImages });
setIsUploading(false);
setShown(false);
}}
onHidden={() => setShown(false)}
onHidden={() => {
setShown(false);
setFiles(null);
}}
show={shown}
>
<FormGroup name="files" label={t("upload_attachments.choose_files")} description={description}>
@@ -55,7 +58,7 @@ export default function UploadAttachmentsDialog() {
</FormGroup>
<FormGroup name="shrink-images" label={t("upload_attachments.options")}>
<FormCheckbox
<FormCheckbox
hint={t("upload_attachments.tooltip")} label={t("upload_attachments.shrink_images")}
currentValue={shrinkImages} onChange={setShrinkImages}
/>

View File

@@ -28,11 +28,12 @@ import ContentWidgetTypeWidget from "./type_widgets/content_widget.js";
import AttachmentListTypeWidget from "./type_widgets/attachment_list.js";
import AttachmentDetailTypeWidget from "./type_widgets/attachment_detail.js";
import MindMapWidget from "./type_widgets/mind_map.js";
import utils from "../services/utils.js";
import utils, { isElectron } from "../services/utils.js";
import type { NoteType } from "../entities/fnote.js";
import type TypeWidget from "./type_widgets/type_widget.js";
import { MermaidTypeWidget } from "./type_widgets/mermaid.js";
import AiChatTypeWidget from "./type_widgets/ai_chat.js";
import toast from "../services/toast.js";
const TPL = /*html*/`
<div class="note-detail">
@@ -140,6 +141,13 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
doRender() {
this.$widget = $(TPL);
this.contentSized();
if (utils.isElectron()) {
const { ipcRenderer } = utils.dynamicRequire("electron");
ipcRenderer.on("print-done", () => {
toast.closePersistent("printing");
});
}
}
async refresh() {
@@ -297,18 +305,53 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
return;
}
// Trigger in timeout to dismiss the menu while printing.
setTimeout(window.print, 0);
toast.showPersistent({
icon: "bx bx-loader-circle bx-spin",
message: t("note_detail.printing"),
id: "printing"
});
if (isElectron()) {
const { ipcRenderer } = utils.dynamicRequire("electron");
ipcRenderer.send("print-note", {
notePath: this.notePath
});
} else {
const iframe = document.createElement('iframe');
iframe.src = `?print#${this.notePath}`;
iframe.className = "print-iframe";
document.body.appendChild(iframe);
iframe.onload = () => {
if (!iframe.contentWindow) {
toast.closePersistent("printing");
document.body.removeChild(iframe);
return;
}
iframe.contentWindow.addEventListener("note-ready", () => {
toast.closePersistent("printing");
iframe.contentWindow?.print();
document.body.removeChild(iframe);
});
};
}
}
async exportAsPdfEvent() {
if (!this.noteContext?.isActive() || !this.note) {
if (!this.noteContext?.isActive() || !this.note || !this.notePath) {
return;
}
toast.showPersistent({
icon: "bx bx-loader-circle bx-spin",
message: t("note_detail.printing_pdf"),
id: "printing"
});
const { ipcRenderer } = utils.dynamicRequire("electron");
ipcRenderer.send("export-as-pdf", {
title: this.note.title,
notePath: this.notePath,
pageSize: this.note.getAttributeValue("label", "printPageSize") ?? "Letter",
landscape: this.note.hasAttribute("label", "printLandscape")
});

View File

@@ -905,7 +905,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
const colorClass = note.getColorClass();
if (colorClass) {
extraClasses.push(colorClass);
extraClasses.push(...["tinted", colorClass]);
}
return extraClasses.join(" ");

View File

@@ -78,6 +78,10 @@ export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
return true;
}
if (note.type === "search" && ![ "grid", "list" ].includes(note.getLabelValue("viewType") ?? "list")) {
return true;
}
return !!note?.isLabelTruthy("fullContentWidth");
}
@@ -87,7 +91,7 @@ export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
const noteId = this.noteContext?.noteId;
if (
loadResults.isNoteReloaded(noteId) ||
loadResults.getAttributeRows().find((attr) => attr.type === "label" && ["cssClass", "language"].includes(attr.name ?? "") && attributeService.isAffecting(attr, this.noteContext?.note))
loadResults.getAttributeRows().find((attr) => attr.type === "label" && ["cssClass", "language", "viewType"].includes(attr.name ?? "") && attributeService.isAffecting(attr, this.noteContext?.note))
) {
this.refresh();
}

View File

@@ -5,16 +5,18 @@ import keyboard_actions from "../../services/keyboard_actions";
export interface ActionButtonProps {
text: string;
titlePosition?: "bottom" | "left";
titlePosition?: "top" | "right" | "bottom" | "left";
icon: string;
className?: string;
onClick?: (e: MouseEvent) => void;
triggerCommand?: CommandNames;
noIconActionClass?: boolean;
frame?: boolean;
active?: boolean;
disabled?: boolean;
}
export default function ActionButton({ text, icon, className, onClick, triggerCommand, titlePosition, noIconActionClass, frame }: ActionButtonProps) {
export default function ActionButton({ text, icon, className, onClick, triggerCommand, titlePosition, noIconActionClass, frame, active, disabled }: ActionButtonProps) {
const buttonRef = useRef<HTMLButtonElement>(null);
const [ keyboardShortcut, setKeyboardShortcut ] = useState<string[]>();
@@ -32,8 +34,9 @@ export default function ActionButton({ text, icon, className, onClick, triggerCo
return <button
ref={buttonRef}
class={`${className ?? ""} ${!noIconActionClass ? "icon-action" : "btn"} ${icon} ${frame ? "btn btn-primary" : ""}`}
class={`${className ?? ""} ${!noIconActionClass ? "icon-action" : "btn"} ${icon} ${frame ? "btn btn-primary" : ""} ${disabled ? "disabled" : ""} ${active ? "active" : ""}`}
onClick={onClick}
data-trigger-command={triggerCommand}
disabled={disabled}
/>;
}

View File

@@ -1,11 +1,10 @@
import { Dropdown as BootstrapDropdown } from "bootstrap";
import { ComponentChildren } from "preact";
import { CSSProperties } from "preact/compat";
import { CSSProperties, HTMLProps } from "preact/compat";
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
import { useUniqueName } from "./hooks";
export interface DropdownProps {
className?: string;
export interface DropdownProps extends Pick<HTMLProps<HTMLDivElement>, "id" | "className"> {
buttonClassName?: string;
isStatic?: boolean;
children: ComponentChildren;
@@ -22,7 +21,7 @@ export interface DropdownProps {
forceShown?: boolean;
}
export default function Dropdown({ className, buttonClassName, isStatic, children, title, text, dropdownContainerStyle, dropdownContainerClassName, hideToggleArrow, iconAction, disabled, noSelectButtonStyle, noDropdownListStyle, forceShown }: DropdownProps) {
export default function Dropdown({ id, className, buttonClassName, isStatic, children, title, text, dropdownContainerStyle, dropdownContainerClassName, hideToggleArrow, iconAction, disabled, noSelectButtonStyle, noDropdownListStyle, forceShown }: DropdownProps) {
const dropdownRef = useRef<HTMLDivElement | null>(null);
const triggerRef = useRef<HTMLButtonElement | null>(null);
@@ -74,7 +73,7 @@ export default function Dropdown({ className, buttonClassName, isStatic, childre
aria-haspopup="true"
aria-expanded="false"
title={title}
id={ariaId}
id={id ?? ariaId}
disabled={disabled}
>
{text}

View File

@@ -1,6 +1,6 @@
import { Ref } from "preact";
import Button, { ButtonProps } from "./Button";
import { useRef } from "preact/hooks";
import { useEffect, useRef } from "preact/hooks";
interface FormFileUploadProps {
name?: string;
@@ -11,6 +11,11 @@ interface FormFileUploadProps {
}
export default function FormFileUpload({ inputRef, name, onChange, multiple, hidden }: FormFileUploadProps) {
// Prevent accidental reuse of a file selected in a previous instance of the upload form.
useEffect(() => {
onChange(null);
}, []);
return (
<label class="tn-file-input tn-input-field" style={hidden ? { display: "none" } : undefined}>
<input
@@ -18,7 +23,7 @@ export default function FormFileUpload({ inputRef, name, onChange, multiple, hid
name={name}
type="file"
class="form-control-file"
multiple={multiple}
multiple={multiple}
onChange={e => onChange((e.target as HTMLInputElement).files)} />
</label>
)
@@ -26,7 +31,7 @@ export default function FormFileUpload({ inputRef, name, onChange, multiple, hid
/**
* Combination of a button with a hidden file upload field.
*
*
* @param param the change listener for the file upload and the properties for the button.
*/
export function FormFileUploadButton({ onChange, ...buttonProps }: Omit<ButtonProps, "onClick"> & Pick<FormFileUploadProps, "onChange">) {
@@ -39,10 +44,10 @@ export function FormFileUploadButton({ onChange, ...buttonProps }: Omit<ButtonPr
onClick={() => inputRef.current?.click()}
/>
<FormFileUpload
inputRef={inputRef}
inputRef={inputRef}
hidden
onChange={onChange}
/>
</>
)
}
}

View File

@@ -9,22 +9,26 @@ interface FormTextBoxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "
}
export default function FormTextBox({ inputRef, className, type, currentValue, onChange, onBlur, autoFocus, ...rest}: FormTextBoxProps) {
if (type === "number" && currentValue) {
const { min, max } = rest;
const currentValueNum = parseInt(currentValue, 10);
if (min && currentValueNum < parseInt(String(min), 10)) {
currentValue = String(min);
} else if (max && currentValueNum > parseInt(String(max), 10)) {
currentValue = String(max);
}
}
useEffect(() => {
if (autoFocus) {
inputRef?.current?.focus();
}
}, []);
function applyLimits(value: string) {
if (type === "number") {
const { min, max } = rest;
const currentValueNum = parseInt(value, 10);
if (min && currentValueNum < parseInt(String(min), 10)) {
return String(min);
} else if (max && currentValueNum > parseInt(String(max), 10)) {
return String(max);
}
}
return value;
}
return (
<input
ref={inputRef}
@@ -33,11 +37,13 @@ export default function FormTextBox({ inputRef, className, type, currentValue, o
value={currentValue}
onInput={onChange && (e => {
const target = e.currentTarget;
onChange?.(target.value, target.validity);
const currentValue = applyLimits(e.currentTarget.value);
onChange?.(currentValue, target.validity);
})}
onBlur={onBlur && (e => {
const target = e.currentTarget;
onBlur(target.value);
onBlur={(e => {
const currentValue = applyLimits(e.currentTarget.value);
e.currentTarget.value = currentValue;
onBlur?.(currentValue);
})}
{...rest}
/>
@@ -49,6 +55,6 @@ export function FormTextBoxWithUnit(props: FormTextBoxProps & { unit: string })
<label class="input-group tn-number-unit-pair">
<FormTextBox {...props} />
<span class="input-group-text">{props.unit}</span>
</label>
</label>
)
}
}

View File

@@ -0,0 +1,28 @@
import { ComponentChildren, HTMLAttributes, JSX, RefObject, render } from "preact";
import { useEffect, useState } from "preact/hooks";
import { useSyncedRef } from "./hooks";
interface ShadowDomProps extends Omit<HTMLAttributes<HTMLDivElement>, "ref"> {
children: ComponentChildren;
containerRef?: RefObject<HTMLDivElement>;
}
export default function ShadowDom({ children, containerRef: externalContainerRef, ...containerProps }: ShadowDomProps) {
const containerRef = useSyncedRef<HTMLDivElement>(externalContainerRef, null);
const [ shadowRoot, setShadowRoot ] = useState<ShadowRoot | null>(null);
// Create the shadow root.
useEffect(() => {
if (!containerRef.current) return;
const shadow = containerRef.current.attachShadow({ mode: "open" });
setShadowRoot(shadow);
}, []);
// Render the child elements.
useEffect(() => {
if (!shadowRoot) return;
render(<>{children}</>, shadowRoot);
}, [ shadowRoot, children ]);
return <div ref={containerRef} {...containerProps} />
}

View File

@@ -5,7 +5,7 @@ import { FormDropdownDivider, FormListBadge, FormListItem } from "../react/FormL
import { getAvailableLocales, t } from "../../services/i18n";
import { useNoteLabel, useNoteLabelBoolean, useNoteProperty, useTriliumEvent, useTriliumOption } from "../react/hooks";
import mime_types from "../../services/mime_types";
import { Locale, NoteType, ToggleInParentResponse } from "@triliumnext/commons";
import { Locale, LOCALES, NoteType, ToggleInParentResponse } from "@triliumnext/commons";
import server from "../../services/server";
import dialog from "../../services/dialog";
import FormToggle from "../react/FormToggle";
@@ -20,6 +20,7 @@ import { TabContext } from "./ribbon-interface";
import Modal from "../react/Modal";
import { CodeMimeTypesList } from "../type_widgets/options/code_notes";
import { ContentLanguagesList } from "../type_widgets/options/i18n";
import { LocaleSelector } from "../type_widgets/options/components/LocaleSelector";
export default function BasicPropertiesTab({ note }: TabContext) {
return (
@@ -290,68 +291,31 @@ function NoteLanguageSwitch({ note }: { note?: FNote | null }) {
id: "",
name: t("note_language.not_set")
};
const [ currentNoteLanguage, setCurrentNoteLanguage ] = useNoteLabel(note, "language");
const [ modalShown, setModalShown ] = useState(false);
const locales = useMemo(() => {
const enabledLanguages = JSON.parse(languages ?? "[]") as string[];
const filteredLanguages = getAvailableLocales().filter((l) => typeof l !== "object" || enabledLanguages.includes(l.id));
const leftToRightLanguages = filteredLanguages.filter((l) => !l.rtl);
const rightToLeftLanguages = filteredLanguages.filter((l) => l.rtl);
let locales: ("---" | Locale)[] = [
DEFAULT_LOCALE
];
if (leftToRightLanguages.length > 0) {
locales = [
...locales,
"---",
...leftToRightLanguages
];
}
if (rightToLeftLanguages.length > 0) {
locales = [
...locales,
"---",
...rightToLeftLanguages
];
}
// This will separate the list of languages from the "Configure languages" button.
// If there is at least one language.
locales.push("---");
return locales;
return filteredLanguages;
}, [ languages ]);
const currentLocale = useMemo(() => {
return locales.find(locale => typeof locale === "object" && locale.id === currentNoteLanguage) as Locale | undefined;
}, [ currentNoteLanguage ]);
return (
<div className="note-language-container">
<span>{t("basic_properties.language")}:</span>
&nbsp;
<Dropdown text={currentLocale?.name ?? DEFAULT_LOCALE.name}>
{locales.map(locale => {
if (typeof locale === "object") {
const checked = locale.id === (currentNoteLanguage ?? "");
return <FormListItem
rtl={locale.rtl}
checked={checked}
onClick={() => setCurrentNoteLanguage(locale.id || null)}
>{locale.name}</FormListItem>
} else {
return <FormDropdownDivider />
}
})}
<LocaleSelector
locales={locales}
defaultLocale={DEFAULT_LOCALE}
currentValue={currentNoteLanguage ?? ""} onChange={setCurrentNoteLanguage}
extraChildren={(
<FormListItem
onClick={() => setModalShown(true)}
icon="bx bx-cog"
>{t("note_language.configure-languages")}</FormListItem>
)}
>
<FormListItem
onClick={() => setModalShown(true)}
>{t("note_language.configure-languages")}</FormListItem>
</Dropdown>
</LocaleSelector>
<HelpButton helpPage="B0lcI9xz1r8K" style={{ marginInlineStart: "4px" }} />
@@ -364,7 +328,7 @@ function NoteLanguageSwitch({ note }: { note?: FNote | null }) {
<ContentLanguagesList />
</Modal>
</div>
)
);
}
function findTypeTitle(type?: NoteType, mime?: string | null) {

View File

@@ -19,12 +19,14 @@ const VIEW_TYPE_MAPPINGS: Record<ViewTypeOptions, string> = {
calendar: t("book_properties.calendar"),
table: t("book_properties.table"),
geoMap: t("book_properties.geo-map"),
board: t("book_properties.board")
board: t("book_properties.board"),
presentation: t("book_properties.presentation")
};
export default function CollectionPropertiesTab({ note }: TabContext) {
const [ viewType, setViewType ] = useNoteLabel(note, "viewType");
const viewTypeWithDefault = (viewType ?? "grid") as ViewTypeOptions;
const defaultViewType = (note?.type === "search" ? "list" : "grid");
const viewTypeWithDefault = (viewType ?? defaultViewType) as ViewTypeOptions;
const properties = bookPropertiesConfig[viewTypeWithDefault].properties;
return (
@@ -120,6 +122,7 @@ function CheckboxPropertyView({ note, property }: { note: FNote, property: Check
function NumberPropertyView({ note, property }: { note: FNote, property: NumberProperty }) {
//@ts-expect-error Interop with text box which takes in string values even for numbers.
const [ value, setValue ] = useNoteLabel(note, property.bindToLabel);
const disabled = property.disabled?.(note);
return (
<LabelledEntry label={property.label}>
@@ -128,6 +131,7 @@ function NumberPropertyView({ note, property }: { note: FNote, property: NumberP
currentValue={value ?? ""} onChange={setValue}
style={{ width: (property.width ?? 100) + "px" }}
min={property.min ?? 0}
disabled={disabled}
/>
</LabelledEntry>
)

View File

@@ -47,11 +47,11 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
const canBeConvertedToAttachment = note?.isEligibleForConversionToAttachment();
const isSearchable = ["text", "code", "book", "mindMap", "doc"].includes(note.type);
const isInOptions = note.noteId.startsWith("_options");
const isPrintable = ["text", "code"].includes(note.type);
const isPrintable = ["text", "code"].includes(note.type) || (note.type === "book" && note.getLabelValue("viewType") === "presentation");
const isElectron = getIsElectron();
const isMac = getIsMac();
const hasSource = ["text", "code", "relationMap", "mermaid", "canvas", "mindMap"].includes(note.type);
const isSearchOrBook = ["search", "book"].includes(note.type);
const isSearchOrBook = ["search", "book"].includes(note.type);
return (
<Dropdown
@@ -74,7 +74,7 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
<CommandItem icon="bx bx-export" text={t("note_actions.export_note")}
disabled={isInOptions || note.noteId === "_backendLog"}
command={() => noteContext?.notePath && parentComponent?.triggerCommand("showExportDialog", {
notePath: noteContext.notePath,
notePath: noteContext.notePath,
defaultType: "single"
})} />
<FormDropdownDivider />
@@ -133,4 +133,4 @@ function ConvertToAttachment({ note }: { note: FNote }) {
}}
>{t("note_actions.convert_into_attachment")}</FormListItem>
)
}
}

View File

@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks";
import { t } from "../../services/i18n";
import { useNoteContext, useNoteProperty, useStaticTooltip, useStaticTooltipWithKeyboardShortcut, useTooltip, useTriliumEvent, useTriliumEvents } from "../react/hooks";
import { useNoteContext, useNoteProperty, useStaticTooltipWithKeyboardShortcut, useTriliumEvents } from "../react/hooks";
import "./style.css";
import { VNode } from "preact";
import BasicPropertiesTab from "./BasicPropertiesTab";
@@ -24,7 +24,6 @@ import InheritedAttributesTab from "./InheritedAttributesTab";
import CollectionPropertiesTab from "./CollectionPropertiesTab";
import SearchDefinitionTab from "./SearchDefinitionTab";
import NoteActions from "./NoteActions";
import keyboard_actions from "../../services/keyboard_actions";
import { KeyboardActionNames } from "@triliumnext/commons";
interface TitleContext {
@@ -81,7 +80,7 @@ const TAB_CONFIGURATION = numberObjectsInPlace<TabConfiguration>([
title: t("book_properties.book_properties"),
icon: "bx bx-book",
content: CollectionPropertiesTab,
show: ({ note }) => note?.type === "book",
show: ({ note }) => note?.type === "book" || note?.type === "search",
toggleCommand: "toggleRibbonTabBookProperties"
},
{

View File

@@ -5,6 +5,7 @@ import NoteContextAwareWidget from "../note_context_aware_widget";
import { DEFAULT_MAP_LAYER_NAME, MAP_LAYERS, type MapLayer } from "../collections/geomap/map_layer";
import { ViewTypeOptions } from "../collections/interface";
import { FilterLabelsByType } from "@triliumnext/commons";
import { DEFAULT_THEME, getPresentationThemes } from "../collections/presentation/themes";
interface BookConfig {
properties: BookProperty[];
@@ -30,6 +31,7 @@ export interface NumberProperty {
bindToLabel: FilterLabelsByType<number>;
width?: number;
min?: number;
disabled?: (note: FNote) => boolean;
}
interface ComboBoxItem {
@@ -153,12 +155,27 @@ export const bookPropertiesConfig: Record<ViewTypeOptions, BookConfig> = {
label: t("book_properties_config.max-nesting-depth"),
type: "number",
bindToLabel: "maxNestingDepth",
width: 65
width: 65,
disabled: (note) => note.type === "search"
}
]
},
board: {
properties: []
},
presentation: {
properties: [
{
label: "Theme",
type: "combobox",
bindToLabel: "presentation:theme",
defaultValue: DEFAULT_THEME,
options: getPresentationThemes().map(theme => ({
value: theme.id,
label: theme.name
}))
}
]
}
};

View File

@@ -1,7 +1,7 @@
.search-result-widget {
flex-grow: 100000;
flex-shrink: 100000;
min-height: 0;
height: 100%;
overflow: auto;
contain: none !important;
}

View File

@@ -4,7 +4,6 @@ import Alert from "./react/Alert";
import { useNoteContext, useTriliumEvent } from "./react/hooks";
import "./search_result.css";
import { SearchNoteList } from "./collections/NoteList";
// import NoteListRenderer from "../services/note_list_renderer";
enum SearchResultState {
NO_RESULTS,
@@ -43,7 +42,7 @@ export default function SearchResult() {
});
return (
<div className="search-result-widget">
<div className={`search-result-widget ${!state ? "hidden-ext" : ""}`}>
{state === SearchResultState.NOT_EXECUTED && (
<Alert type="info" className="search-not-executed-yet">{t("search_result.search_not_executed")}</Alert>
)}
@@ -54,6 +53,7 @@ export default function SearchResult() {
{state === SearchResultState.GOT_RESULTS && (
<SearchNoteList
media="screen"
note={note}
notePath={notePath}
highlightedTokens={highlightedTokens}

View File

@@ -294,7 +294,7 @@ function MaxContentWidth() {
<FormGroup name="max-content-width" label={t("max_content_width.max_width_label")}>
<FormTextBoxWithUnit
type="number" min={MIN_CONTENT_WIDTH} step="10"
currentValue={maxContentWidth} onChange={setMaxContentWidth}
currentValue={maxContentWidth} onBlur={setMaxContentWidth}
unit={t("max_content_width.max_width_unit")}
/>
</FormGroup>

View File

@@ -0,0 +1,63 @@
import { Locale } from "@triliumnext/commons";
import Dropdown from "../../../react/Dropdown";
import { FormDropdownDivider, FormListItem } from "../../../react/FormList";
import { ComponentChildren } from "preact";
import { useMemo, useState } from "preact/hooks";
export function LocaleSelector({ id, locales, currentValue, onChange, defaultLocale, extraChildren }: {
id?: string;
locales: Locale[],
currentValue: string,
onChange: (newLocale: string) => void,
defaultLocale?: Locale,
extraChildren?: ComponentChildren
}) {
const [ activeLocale, setActiveLocale ] = useState(defaultLocale?.id === currentValue ? defaultLocale : locales.find(l => l.id === currentValue));
console.log("defaultLocale ", defaultLocale, currentValue, activeLocale)
const processedLocales = useMemo(() => {
const leftToRightLanguages = locales.filter((l) => !l.rtl);
const rightToLeftLanguages = locales.filter((l) => l.rtl);
let items: ("---" | Locale)[] = [];
if (defaultLocale) items.push(defaultLocale);
if (leftToRightLanguages.length > 0) {
if (items.length > 0) items.push("---");
items = [ ...items, ...leftToRightLanguages ];
}
if (rightToLeftLanguages.length > 0) {
items = [
...items,
"---",
...rightToLeftLanguages
];
}
if (extraChildren) {
items.push("---");
}
return items;
}, [ locales ]);
return (
<Dropdown id={id} text={activeLocale?.name}>
{processedLocales.map(locale => {
if (typeof locale === "object") {
return <FormListItem
rtl={locale.rtl}
checked={locale.id === currentValue}
onClick={() => {
setActiveLocale(locale);
onChange(locale.id);
}}
>{locale.name}</FormListItem>
} else {
return <FormDropdownDivider />
}
})}
{extraChildren}
</Dropdown>
)
}

View File

@@ -10,10 +10,16 @@
margin-bottom: 0 !important;
}
.option-row > select {
.option-row > select,
.option-row > .dropdown {
width: 60%;
}
.option-row > .dropdown button {
width: 100%;
text-align: start;
}
.option-row:last-of-type {
border-bottom: unset;
}

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