Compare commits

...

1070 Commits

Author SHA1 Message Date
Elian Doran
c4f55395a9 feat(client/jsx): disable debug info 2025-12-21 13:31:44 +02:00
Elian Doran
444c0c6107 chore(client/jsx): fix errors in API 2025-12-21 13:19:42 +02:00
Elian Doran
4da5cb43fc fet(client/jsx): expose basic React widgets 2025-12-21 13:16:05 +02:00
Elian Doran
e6b79e83c4 fet(client/jsx): basic support for JSX render notes 2025-12-21 11:18:42 +02:00
Elian Doran
6e67da7b1f chore(deps): revert sucrase from client 2025-12-21 10:32:54 +02:00
Elian Doran
9071e54bfe chore(client/jsx): use different method for launcher widget defs 2025-12-21 10:26:20 +02:00
Elian Doran
783b5ac8e3 feat(client/jsx): support launcher widgets 2025-12-21 10:23:34 +02:00
Elian Doran
f3f491d141 feat(client/bundle): respect position for TSX widgets 2025-12-21 10:02:13 +02:00
Elian Doran
f8bf301d12 feat(client/bundle): use new toast for script errors with known note ID 2025-12-20 23:34:36 +02:00
Elian Doran
2c25786fa2 feat(client/bundle): expose Trilium hooks 2025-12-20 23:26:10 +02:00
Elian Doran
1093acfe45 feat(client/bundle): make Preact custom widgets content-sized by default 2025-12-20 23:17:30 +02:00
Elian Doran
76f054bbd5 feat(client/bundle): support rendering in other places 2025-12-20 23:16:19 +02:00
Elian Doran
c558255450 feat(client/bundle): add button to open script note 2025-12-20 22:51:04 +02:00
Elian Doran
1e94125133 feat(client/bundle): display toast when parent is missing 2025-12-20 22:45:58 +02:00
Elian Doran
64a770175f refactor(client/bundle): use type for parent name 2025-12-20 22:40:03 +02:00
Elian Doran
e0416097e1 feat(script/jsx): support import syntax for api 2025-12-20 22:23:25 +02:00
Elian Doran
6c1b327f5f feat(script/jsx): support import syntax for preact 2025-12-20 22:14:45 +02:00
Elian Doran
284b66acd2 feat(script/jsx): support export default syntax 2025-12-20 21:59:03 +02:00
Elian Doran
dcd73ff9f9 test(script/jsx): JSX fragment 2025-12-20 21:37:41 +02:00
Elian Doran
645557b505 test(script/jsx): basic JSX processing 2025-12-20 21:35:52 +02:00
Elian Doran
22a83d9f82 refactor(script/jsx): "react-widget" -> "preact-widget" 2025-12-20 21:26:01 +02:00
Elian Doran
f64de3acca chore(script/jsx): move defineWidget into Preact API 2025-12-20 21:25:36 +02:00
Elian Doran
34d5793888 chore(script/jsx): expose RightPanelWidget 2025-12-20 21:19:53 +02:00
Elian Doran
44ca9f457c feat(script/jsx): add support for React hooks 2025-12-20 20:29:03 +02:00
Elian Doran
4d7e5bc8f6 chore(script/jsx): move Preact API in dedicated object 2025-12-20 20:10:19 +02:00
Elian Doran
644ff07a50 feat(script/jsx): get right panel widgets to actually render 2025-12-20 19:49:24 +02:00
Elian Doran
41220a9d1d fix(script/jsx): cannot find preact hydration function 2025-12-20 19:45:44 +02:00
Elian Doran
88945788d6 fix(script/jsx): critical crash if widget fails to render 2025-12-20 19:41:48 +02:00
Elian Doran
fe8f033409 chore(script/jsx): get widgets to be interpreted 2025-12-20 19:36:02 +02:00
Elian Doran
eee7c49f6e fix(script/jsx): module not defined 2025-12-20 19:28:26 +02:00
Elian Doran
d036bf0870 fix(client): full crash if server fails to obtain list of widgets 2025-12-20 19:18:50 +02:00
Elian Doran
fa8ff4bfbf chore(script/jsx): basic client-side logic to render bundles 2025-12-20 19:01:29 +02:00
Elian Doran
3619c0c3e4 feat(script/jsx): compile JSX on server side 2025-12-20 18:46:15 +02:00
Elian Doran
883e32f5c9 chore(script): install sucrase 2025-12-20 18:03:45 +02:00
Elian Doran
8722ed405e docs(user): add missing share aliases 2025-12-20 17:56:18 +02:00
Adorian Doran
201c3a6eba style: tint the text selection according to the note's custom color 2025-12-20 16:13:38 +02:00
Adorian Doran
5a46f6ad04 style/classic toolbar: tweak 2025-12-20 15:51:55 +02:00
Adorian Doran
4f20ffe933 Tweak the classic formatting toolbar (#8123) 2025-12-20 15:33:17 +02:00
Adorian Doran
061b0966bb rollback: style/tab bar: visually merge the tab bar with the center panel 2025-12-20 15:28:46 +02:00
Elian Doran
bd799823b8 docs(user): add troubleshooting on content-sized 2025-12-20 13:54:50 +02:00
Elian Doran
c581ee7252 docs(user): improve examples for right pane widgets 2025-12-20 13:29:38 +02:00
Elian Doran
666c434c74 docs(user): mention changes to sidebar 2025-12-20 13:17:01 +02:00
Elian Doran
78ac59581e New layout: Right panel (sidebar) (#8095) 2025-12-20 13:09:59 +02:00
Elian Doran
d7b370253d chore(right_pane): fix regression in highlights_list 2025-12-20 13:00:13 +02:00
Elian Doran
1e885625f6 chore(right_pane): address requested changes 2025-12-20 12:58:06 +02:00
Adorian Doran
8cf6a6b9ae style: make the center panel border radius apply over the classic formatting toolbar if required 2025-12-20 12:51:43 +02:00
Elian Doran
f1ca8881a1 chore(right_pane): fix typecheck 2025-12-20 12:32:20 +02:00
Elian Doran
ea76fd797c chore(right_pane): address requested changes 2025-12-20 12:29:43 +02:00
Elian Doran
b248805905 feat(right_pane): add count to highlights list 2025-12-20 12:25:43 +02:00
Adorian Doran
7af5c77bcb style/tab bar: tweak margin 2025-12-20 12:18:11 +02:00
Elian Doran
35afd60d00 feat(right_pane): respect position 2025-12-20 12:17:14 +02:00
Elian Doran
2b827991ef feat(right_pane): only grow table of contents & highlights 2025-12-20 11:52:40 +02:00
Elian Doran
bc8c852a4d chore(right_pane): align collapse icon with menu item 2025-12-20 11:48:47 +02:00
Elian Doran
cd49c36529 chore(right_pane): decrease context menu size slightly 2025-12-20 11:45:08 +02:00
Elian Doran
a0577dc202 chore(right_pane): use menu instead of button for highlights list 2025-12-20 11:42:21 +02:00
Elian Doran
dced799976 feat(right_pane): add context menu with go to source for custom widgets 2025-12-20 11:39:46 +02:00
Elian Doran
eeea96b98c chore(right_pane): missing key for custom widgets 2025-12-20 11:17:29 +02:00
Elian Doran
e82e92c22c fix(right_pane): custom widgets not aware of note context 2025-12-20 11:16:41 +02:00
Elian Doran
e1df65adce fix(right_pane): custom widgets not rendering after being expanded 2025-12-20 11:09:59 +02:00
Adorian Doran
b7b7610f4d style/classic toolbar: allow customizing the background color via a CSS variable 2025-12-20 11:05:14 +02:00
Adorian Doran
37ea1584c9 style/tab bar: visually merge the tab bar with the center panel 2025-12-20 10:42:13 +02:00
Elian Doran
aac4316fb8 feat(right_pane): render title bar 2025-12-20 10:33:28 +02:00
Elian Doran
fb96b3f80a Translations update from Hosted Weblate (#8120) 2025-12-20 09:04:25 +02:00
Maxime
243d8158cf Translated using Weblate (French)
Currently translated at 100.0% (152 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/fr/
2025-12-20 07:03:32 +00:00
Eugene
6861a61cac Translated using Weblate (Russian)
Currently translated at 100.0% (152 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ru/
2025-12-20 07:03:31 +00:00
Kuzma Simonov
d3299d8aa4 Translated using Weblate (Russian)
Currently translated at 100.0% (152 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ru/
2025-12-20 07:03:30 +00:00
Maxime
0be5581fe5 Translated using Weblate (French)
Currently translated at 99.7% (388 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/fr/
2025-12-20 07:03:30 +00:00
Kuzma Simonov
60572a28ff Translated using Weblate (Russian)
Currently translated at 100.0% (389 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ru/
2025-12-20 07:03:29 +00:00
Maxime
422c391c82 Translated using Weblate (French)
Currently translated at 95.9% (1640 of 1709 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/fr/
2025-12-20 07:03:28 +00:00
Kuzma Simonov
457d30cd80 Translated using Weblate (Russian)
Currently translated at 100.0% (1709 of 1709 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ru/
2025-12-20 07:03:27 +00:00
Hosted Weblate
9caa058b18 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-12-20 07:03:26 +00:00
Elian Doran
33bde688c1 chore(deps): update dependency @redocly/cli to v2.14.0 (#8118) 2025-12-20 09:03:18 +02:00
Elian Doran
e79da6b0f3 chore(deps): update pnpm to v10.26.1 (#8117) 2025-12-20 09:02:39 +02:00
Elian Doran
3e527b9f5c chore(deps): update dependency openai to v6.15.0 (#8119) 2025-12-20 09:01:46 +02:00
renovate[bot]
ba242a6169 chore(deps): update dependency openai to v6.15.0 2025-12-20 01:00:35 +00:00
renovate[bot]
489113f582 chore(deps): update dependency @redocly/cli to v2.14.0 2025-12-20 00:59:47 +00:00
renovate[bot]
0fa6335d0f chore(deps): update pnpm to v10.26.1 2025-12-20 00:58:53 +00:00
Elian Doran
8f1614f603 chore(right_pane_widget): basic support for custom widgets 2025-12-20 00:01:21 +02:00
Elian Doran
a5f322617d chore(script): remove node-detail-pane 2025-12-19 23:44:19 +02:00
Elian Doran
6da42fac20 feat(right_pane_widget): handle zero headings 2025-12-19 23:32:58 +02:00
Elian Doran
fad6414e1d feat(right_pane_widget): handle zero highlights 2025-12-19 23:29:52 +02:00
Elian Doran
c0cd9e36d9 feat(right_pane_widget): hide highlights if disabled in settings 2025-12-19 23:25:58 +02:00
Elian Doran
e94704ce64 chore(right_pane_widget): respect highlight settings 2025-12-19 23:18:28 +02:00
Elian Doran
7a5d24f968 feat(right_pane_widget): options modal for highlight list 2025-12-19 23:02:32 +02:00
Elian Doran
9d351ae479 chore(options/text_notes): adapt to new layout sidebar 2025-12-19 22:33:26 +02:00
Elian Doran
01d4fa8afd chore(right_pane_widget): add padding to no items 2025-12-19 22:26:17 +02:00
Elian Doran
7d386c249a fix(right_pane_widget): toggle button clipped on desktop 2025-12-19 22:23:46 +02:00
Elian Doran
45dd47d039 feat(layout): button to toggle right pane on vertical layout 2025-12-19 21:20:36 +02:00
Elian Doran
06ad0bfa90 feat(hooks): react faster to setting options 2025-12-19 21:12:49 +02:00
Elian Doran
3d9efb23ec chore(right_pane): make right pane collapsible 2025-12-19 21:11:46 +02:00
Elian Doran
9acef4d502 feat(layout): button to toggle right pane on horizontal layout 2025-12-19 21:05:21 +02:00
Elian Doran
d22583457f style(right_pane): left-align title 2025-12-19 20:51:27 +02:00
Elian Doran
290469d1df Translations update from Hosted Weblate (#8115) 2025-12-19 14:28:57 +02:00
Kuzma Simonov
de5b766d0c Translated using Weblate (Russian)
Currently translated at 17.7% (27 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ru/
2025-12-19 12:26:27 +01:00
Kuzma Simonov
cbeb5dfb58 Translated using Weblate (Russian)
Currently translated at 98.0% (1676 of 1709 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ru/
2025-12-19 12:26:27 +01:00
Kuzma Simonov
be5448eba2 Translated using Weblate (Russian)
Currently translated at 65.5% (76 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/ru/
2025-12-19 12:26:24 +01:00
Kuzma Simonov
200e5d04a4 Translated using Weblate (Russian)
Currently translated at 97.6% (380 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ru/
2025-12-19 12:26:24 +01:00
Elian Doran
c7bbf709a1 Translations update from Hosted Weblate (#8108) 2025-12-19 08:39:18 +02:00
Elian Doran
23c2a59eba chore(deps): update dependency fs-extra to v11.3.3 (#8103) 2025-12-19 08:38:40 +02:00
Hosted Weblate
bf74c40f73 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-12-19 07:38:21 +01:00
Elian Doran
2af1ceda0b fix(deps): update dependency preact-iso to v2.11.1 (#8105) 2025-12-19 08:38:15 +02:00
renovate[bot]
44ae60005c chore(deps): update dependency fs-extra to v11.3.3 2025-12-19 06:38:07 +00:00
Elian Doran
3d591922bb chore(deps): update dependency @redocly/cli to v2.13.0 (#8106) 2025-12-19 08:37:41 +02:00
Elian Doran
31b2aba44c fix(deps): update dependency @codemirror/commands to v6.10.1 (#8104) 2025-12-19 08:37:01 +02:00
Elian Doran
df1c6196bf chore(deps): update dependency esbuild to v0.27.2 (#8102) 2025-12-19 08:36:18 +02:00
Elian Doran
96f4567ba1 chore(deps): update dependency @smithy/middleware-retry to v4.4.17 (#8101) 2025-12-19 08:32:52 +02:00
Adorian Doran
3e783817b6 style/quick edit dialog: tweak title 2025-12-19 02:51:04 +02:00
Adorian Doran
f7f3f707f1 client/note title row: use distinct style when used as a note split title 2025-12-19 02:46:50 +02:00
Adorian Doran
5ce81f1a32 client/note title widget: add support for custom CSS class name 2025-12-19 02:30:46 +02:00
renovate[bot]
53df319aeb chore(deps): update dependency @redocly/cli to v2.13.0 2025-12-19 00:17:52 +00:00
renovate[bot]
c56a253e49 fix(deps): update dependency preact-iso to v2.11.1 2025-12-19 00:17:17 +00:00
renovate[bot]
551b2aa33a fix(deps): update dependency @codemirror/commands to v6.10.1 2025-12-19 00:16:42 +00:00
Adorian Doran
8e245ccad8 Note header: apply note custom colors over the note icons (#8100) 2025-12-19 02:15:30 +02:00
renovate[bot]
03cea8b702 chore(deps): update dependency esbuild to v0.27.2 2025-12-19 00:15:28 +00:00
renovate[bot]
c94b5bc6c9 chore(deps): update dependency @smithy/middleware-retry to v4.4.17 2025-12-19 00:14:36 +00:00
Adorian Doran
69dc1ba68f Merge branch 'main' into feat/note-header/custom-colors 2025-12-19 02:12:25 +02:00
Adorian Doran
32f7ae1edd client: refactor 2025-12-19 02:12:00 +02:00
Adorian Doran
0de05ed16e style/note icon: apply note custom colors over the icons of the quick edit dialog as well 2025-12-19 02:01:03 +02:00
Adorian Doran
58e24c98ed style/note icon: fix the parent note color being applied over note links and board items 2025-12-19 01:55:52 +02:00
Adorian Doran
46da118749 style/note icon: cleanup 2025-12-19 01:43:11 +02:00
Adorian Doran
3f7514c9c7 style/note icon: tweak dark mode colors 2025-12-19 01:39:36 +02:00
Adorian Doran
5123f7b678 style/note icon: fix broken hover color for monochrome icons 2025-12-19 01:38:34 +02:00
Adorian Doran
b8af961690 style/note icon: refactor variable names 2025-12-19 01:23:56 +02:00
Adorian Doran
5bcec9fcfd style/note icon: add hover effect for custom colors 2025-12-19 01:21:52 +02:00
Elian Doran
0a2d4131d7 feat(docs): improve link docs organization (#8057) 2025-12-19 00:26:09 +02:00
Elian Doran
9ef4ab9983 fix(search): add null check for canvas elements in fulltext search (#8090) 2025-12-19 00:22:43 +02:00
Elian Doran
2a237e9a49 Translations update from Hosted Weblate (#8081) 2025-12-19 00:20:30 +02:00
Elian Doran
29115f5e61 Translated using Weblate (Dutch)
Currently translated at 25.8% (30 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/nl/
2025-12-18 23:19:45 +01:00
noobhjy
3411ed79d8 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1709 of 1709 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-12-18 23:14:32 +01:00
green
b9c6cae5b4 Translated using Weblate (Japanese)
Currently translated at 100.0% (1709 of 1709 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-18 23:14:31 +01:00
Luk On
cc84d09230 Translated using Weblate (Polish)
Currently translated at 100.0% (1709 of 1709 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-12-18 23:14:30 +01:00
Luk On
a82b12a599 Translated using Weblate (Polish)
Currently translated at 100.0% (1703 of 1703 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-12-18 23:14:29 +01:00
noobhjy
65ebbc71f5 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1703 of 1703 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-12-18 23:14:29 +01:00
green
77c1a00831 Translated using Weblate (Japanese)
Currently translated at 100.0% (1703 of 1703 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-18 23:14:28 +01:00
Hosted Weblate
8eb6bf402d 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-12-18 23:14:27 +01:00
Elian Doran
e45beb541e Fix translation text for database cleaning button (#8080) 2025-12-19 00:14:19 +02:00
Elian Doran
334c31e79d fix(right_pane): table of contents no longer visible 2025-12-18 17:00:11 +02:00
Elian Doran
a986c84ce7 chore(right_pane): remove redundant check for note type 2025-12-18 16:59:40 +02:00
Elian Doran
9b21e042ec feat(floating_buttons): handle case when empty 2025-12-18 16:58:15 +02:00
Elian Doran
c44bb6c203 chore(floating_buttons): revert changes due to new layout 2025-12-18 16:33:12 +02:00
Elian Doran
ddb6b3ea8a feat(right_pane): store expansion state 2025-12-18 16:29:35 +02:00
Elian Doran
a4024d17ba fix(highlights_list): empty results 2025-12-18 16:18:31 +02:00
Elian Doran
57081a1bfb feat(right_pane): make whole title clickable 2025-12-18 16:16:52 +02:00
Elian Doran
7af063e7cd feat(right_pane): simplify collapsing mechanism 2025-12-18 16:15:21 +02:00
Elian Doran
7b04ca8cc7 style(right_pane): improve header space slightly 2025-12-18 15:57:48 +02:00
Elian Doran
02294206ec chore(right_pane): revert note data store 2025-12-18 15:42:44 +02:00
Elian Doran
7f7ec5d858 chore(right_pane): make the gutter slightly bigger 2025-12-18 15:40:09 +02:00
Elian Doran
ea3222cf12 chore(right_pane): more advanced expand/collapse 2025-12-18 14:57:42 +02:00
Elian Doran
5dacfd3ac6 chore(right_pane): basic expand support 2025-12-18 14:52:22 +02:00
Elian Doran
682c61305c chore(right_pane): basic collapse support 2025-12-18 14:43:54 +02:00
Elian Doran
b5bfb02d96 chore(right_pane): experiment with resizable sections 2025-12-18 14:12:28 +02:00
Elian Doran
fc3692333a chore(right_pane): improve style slightly 2025-12-18 14:10:16 +02:00
Elian Doran
28d9d98964 fix(highlights_list): unable to scroll to text fragments 2025-12-18 13:45:45 +02:00
Elian Doran
751a874c51 chore(highlights_list): improve performance by matching fewer elements 2025-12-18 13:38:52 +02:00
Elian Doran
d18ac0c613 fix(highlights_list): displaying non-highlighted attributes 2025-12-18 13:33:08 +02:00
Elian Doran
cd9654cd5f chore(highlights_list): reintroduce support for read-only notes 2025-12-18 13:29:36 +02:00
Elian Doran
925049357a fix(highlights_list): missing key 2025-12-18 13:20:04 +02:00
Elian Doran
d920da9e6f chore(highlights_list): render highlights 2025-12-18 13:17:41 +02:00
Elian Doran
b42a4dcb36 chore(highlights_list): react to changes 2025-12-18 13:13:05 +02:00
Elian Doran
7085e62cfc chore(highlights_list): reintroduce navigation 2025-12-18 13:09:53 +02:00
Elian Doran
73f2f56932 chore(highlights_list): read highlights from CK 2025-12-18 12:52:22 +02:00
Elian Doran
dbf29ed23f chore(highlights_list): start from scratch 2025-12-18 12:38:45 +02:00
Elian Doran
b0e1751dc7 chore(toc): reintroduce navigation in readonly text notes 2025-12-18 12:09:05 +02:00
Elian Doran
bf5c56a61a chore(toc): reintroduce navigation in editable text notes 2025-12-18 12:04:42 +02:00
Elian Doran
96ccb1e67e fix(toc): sometimes not reacting to read-only note switching 2025-12-18 11:46:21 +02:00
Elian Doran
704dcd011e feat(toc): basic support for docs 2025-12-18 11:46:13 +02:00
Elian Doran
b93c80fe7b feat(toc): basic support for read-only text 2025-12-18 11:12:36 +02:00
Elian Doran
41751c205c refactor(toc): reorder according to purpose 2025-12-18 10:58:25 +02:00
Elian Doran
852398426e chore(toc): add unique keys to headings 2025-12-18 10:56:44 +02:00
Elian Doran
73f1b91d34 chore(toc): reintroduce basic collapse support 2025-12-18 10:49:33 +02:00
Xen0r
28da93fc65 Merge branch 'main' into main 2025-12-18 09:36:55 +01:00
Elian Doran
87a98201b4 chore(toc): reintroduce hierarchy 2025-12-18 10:30:39 +02:00
Elian Doran
60342c0f6f fix(toc): not working on note switch 2025-12-18 10:08:10 +02:00
Elian Doran
97a3e439d2 refactor(toc): decouple CKEditor TOC 2025-12-18 09:58:10 +02:00
Jason Wasem
ee6f988c35 refactor(search): simplify null check and use join for text concatenation
根据代码审查建议优化代码:
- 移除多余的 `elements &&` 检查,因为 Array.isArray() 本身可处理 null/undefined
- 使用 `join(" ")` 替代 `toString()` 以确保文本元素用空格分隔,更适合全文搜索
- 移除显式类型声明,让 TypeScript 自动推断

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 10:01:13 +08:00
Adorian Doran
7cfc67cf9f style/note icon: tweak colors 2025-12-18 03:14:21 +02:00
Adorian Doran
ea2dd0293f style/note icon: tweak colors 2025-12-18 02:05:49 +02:00
Adorian Doran
76c16f3a62 style/note icon: apply the note custom color on the icon 2025-12-18 00:53:09 +02:00
Elian Doran
094f77b1af chore(toc): react to changes 2025-12-18 00:38:40 +02:00
Elian Doran
b2bcbdde3f style(attachment): top padding not matching side padding 2025-12-18 00:25:16 +02:00
Elian Doran
eceb7179b8 style(attachment): code block cuts off card 2025-12-18 00:20:48 +02:00
Elian Doran
3a46a9fbc3 chore(toc): attempt to read using CKEditor API 2025-12-18 00:16:03 +02:00
Elian Doran
2e484a11e6 feat(layout/right_pane): basic store to read content without blob 2025-12-17 23:40:25 +02:00
Elian Doran
98ed442d27 chore(layout/right_pane): empty table of contents 2025-12-17 23:19:42 +02:00
Elian Doran
dac923e45d chore(layout/right_pane): bring back resizer 2025-12-17 23:17:25 +02:00
Elian Doran
f46de50f17 refactor(layout/right_pane): CSS for container 2025-12-17 23:03:57 +02:00
Elian Doran
616af1502f feat(layout/right_pane): create empty container 2025-12-17 23:01:44 +02:00
Adorian Doran
c9fae88a86 style/note: add custom note color CSS variables on the split containers 2025-12-17 22:48:47 +02:00
Elian Doran
9872a3d522 feat(call_to_action): add more info button for new layout 2025-12-17 22:46:25 +02:00
Elian Doran
851169e061 fix(edited_notes): no message if there are no edited notes on a day 2025-12-17 22:39:24 +02:00
Elian Doran
f3b274650e docs(user): mark new layout in feature highlights 2025-12-17 22:34:01 +02:00
Elian Doran
3293ed2ce0 docs(user): document the new layout 2025-12-17 22:34:01 +02:00
Elian Doran
231ec39025 New layout refinement (#8088) 2025-12-17 18:51:38 +02:00
Jason Wasem
ecb972c71c fix(search): add null check for canvas elements in fulltext search
添加对 Canvas 笔记 elements 字段的空值检查,防止当 elements 为 null 或非数组时搜索功能报错。

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 00:42:12 +08:00
Elian Doran
c7f1e46b26 e2e(server): disable new layout and call-to-action for now 2025-12-17 18:05:39 +02:00
Elian Doran
b9c39d757b style(next): match attachment code border radius with context menu 2025-12-17 17:42:03 +02:00
Elian Doran
ea4a3b7f07 chore(client): address requested changes 2025-12-17 17:24:15 +02:00
Elian Doran
cbecc24999 feat(call_to_action): inform about the layout change 2025-12-17 16:05:55 +02:00
Elian Doran
261c1f77cf fix(layout): 2px margin in code notes 2025-12-17 15:47:11 +02:00
Elian Doran
87d99aaffa fix(layout): experimental styles not applied 2025-12-17 15:46:00 +02:00
Elian Doran
d0b0a13b6d chore(options/appearance): use translations 2025-12-17 15:44:01 +02:00
Elian Doran
1ed83b3598 Merge remote-tracking branch 'origin/main' into layout/refinement 2025-12-17 15:43:51 +02:00
Elian Doran
2759beb5d0 feat(options/appearance): improve new layout 2025-12-17 15:34:44 +02:00
Elian Doran
d623b2ffa0 feat(options/appearance): switch between layouts 2025-12-17 15:17:54 +02:00
Elian Doran
3ed613cf1d style(options/appearance): improve layout slightly 2025-12-17 12:40:36 +02:00
Elian Doran
948a6f84d6 feat(options/appearance): add basic illustration for old layout 2025-12-17 12:37:12 +02:00
Xen0r
334024b2d1 Merge branch 'main' into main 2025-12-17 10:28:53 +01:00
Elian Doran
6aa14d17d7 chore(deps): update dependency openai to v6.14.0 (#8086) 2025-12-17 11:26:29 +02:00
Elian Doran
e1da74d4d1 fix(deps): update dependency mind-elixir to v5.3.8 (#8085) 2025-12-17 11:26:15 +02:00
Elian Doran
a6012283da fix(deps): update dependency lodash-es to v4.17.22 (#8084) 2025-12-17 11:25:23 +02:00
Elian Doran
e450e0299f chore(deps): update vitest monorepo to v4.0.16 (#8083) 2025-12-17 11:25:03 +02:00
Xen0r
816f851709 Update translation.json 2025-12-17 10:22:13 +01:00
Xen0r
514ded5b8d Merge branch 'main' into main 2025-12-17 10:20:10 +01:00
renovate[bot]
304fd37ce2 chore(deps): update dependency openai to v6.14.0 2025-12-17 00:03:10 +00:00
renovate[bot]
51ef473964 fix(deps): update dependency mind-elixir to v5.3.8 2025-12-17 00:02:27 +00:00
Adorian Doran
96f148a870 Tweak note title and icon (#8082) 2025-12-17 02:01:58 +02:00
renovate[bot]
150bc07d28 fix(deps): update dependency lodash-es to v4.17.22 2025-12-17 00:01:46 +00:00
renovate[bot]
dcec780846 chore(deps): update vitest monorepo to v4.0.16 2025-12-17 00:01:03 +00:00
Adorian Doran
03602addc5 Merge branch 'main' into feat/tweak/note-title-and-icon-widgets 2025-12-17 01:59:07 +02:00
Adorian Doran
fc9f47a801 style/note title & icon: fix an issue pointed by gemini-code-assist 2025-12-17 01:58:20 +02:00
Adorian Doran
3b6a823556 style/note title & icon: tweak icon size 2025-12-17 01:48:35 +02:00
Adorian Doran
b8ceb10e68 style/note title & icon: update the colors for the dark color scheme 2025-12-17 01:39:14 +02:00
Adorian Doran
ddca68eafa style/note title & icon: add support for both dark and light color schemes 2025-12-17 01:33:23 +02:00
Adorian Doran
468d4a4369 style/inline title: fix (again) icon hover color 2025-12-17 01:15:35 +02:00
Adorian Doran
c31f35dbd7 style/inline title: handle empty icons when the icon selection is disabled 2025-12-17 01:11:23 +02:00
Elian Doran
b5129402be chore(deps): update dependency vite to v7.3.0 (#8071) 2025-12-17 01:05:15 +02:00
Elian Doran
f38dfb035a chore(deps): update typescript-eslint monorepo to v8.50.0 (#8073) 2025-12-17 01:04:19 +02:00
Elian Doran
c2bee1a968 chore(deps): update dependency @ckeditor/ckeditor5-dev-build-tools to v54 (#8074) 2025-12-17 01:03:46 +02:00
Adorian Doran
84f7ae9f05 style/inline title: fix icon hover color 2025-12-17 01:03:01 +02:00
Elian Doran
c4df640ea4 chore(deps): update pnpm to v10.26.0 (#8072) 2025-12-17 01:01:04 +02:00
Elian Doran
fe5e1eb066 chore(deps): update dependency openai to v6.13.0 (#8070) 2025-12-17 01:00:32 +02:00
Elian Doran
6abc5a777f fix(deps): update dependency i18next to v25.7.3 (#8069) 2025-12-17 01:00:14 +02:00
Adorian Doran
08730dd821 style/inline title: add an intro animation for the note type selector 2025-12-17 01:00:07 +02:00
Elian Doran
b08ea33eb0 chore(deps): update dependency @smithy/middleware-retry to v4.4.16 (#8068) 2025-12-17 00:59:52 +02:00
Elian Doran
f389fc3414 chore(deps): update dependency @redocly/cli to v2.12.7 (#8067) 2025-12-17 00:59:27 +02:00
Elian Doran
cb024d0455 Translations update from Hosted Weblate (#8066) 2025-12-17 00:59:02 +02:00
Adorian Doran
286d2e8e5b style/inline title: tweak the layout of the note type selector 2025-12-17 00:52:47 +02:00
Adorian Doran
5446d8a932 style/inline title: improve the note icon focus indicator 2025-12-17 00:33:33 +02:00
Adorian Doran
07dcdf3078 style/inline title: replace the hover effect of the note icon 2025-12-17 00:16:45 +02:00
Adorian Doran
143b1827e6 style/inline title: tweak appearance 2025-12-17 00:09:15 +02:00
Adorian Doran
6f494e3e38 style/inline title: use a better layout 2025-12-16 23:33:57 +02:00
Xen0r
e88623e9fa Fix translation text for database cleaning button 2025-12-16 22:00:21 +01:00
Adorian Doran
cad86d4b21 style/note title & icon: tweak appearance 2025-12-16 22:54:55 +02:00
Adorian Doran
5ffae303c4 style/forms/buttons: add a generic class for focusable buttons 2025-12-16 22:54:12 +02:00
Adorian Doran
35218aca71 style/note title & icon: add a circular background for the note icon 2025-12-16 22:34:42 +02:00
Adorian Doran
9542c9776a style/note title & icon: use CSS variables to adjust size, improve the layout on different sizes 2025-12-16 20:30:58 +02:00
Elian Doran
af02685f2f chore(options): fix misalignment in options row 2025-12-16 20:14:21 +02:00
Elian Doran
737e5b85b4 fix(badges): "temporarily editable" remaining after changing editability 2025-12-16 19:40:24 +02:00
Elian Doran
90a7217b32 feat(layout): preserve newlines in tooltips 2025-12-16 19:29:59 +02:00
Elian Doran
77b92385cb feat(layout): keyboard shortcut for promoted attributes 2025-12-16 19:21:50 +02:00
Elian Doran
22e0776049 fix(layout): toggleRibbonTabNoteMap not working in old layout 2025-12-16 19:12:42 +02:00
Elian Doran
db51198449 feat(layout): keyboard shortcut for similar notes 2025-12-16 19:01:03 +02:00
Elian Doran
998a16ab87 feat(layout): keyboard shortcut for note paths 2025-12-16 18:59:36 +02:00
Elian Doran
4f1c19f1e2 feat(layout): keyboard shortcut for note info 2025-12-16 18:57:25 +02:00
Elian Doran
1835676d09 feat(layout): keyboard shortcut for owned & inherited attributes 2025-12-16 18:54:15 +02:00
Elian Doran
2eaa4ef206 fix(note_info): fixed note types do not have icon 2025-12-16 18:43:04 +02:00
Elian Doran
a5fcee500e feat(layout): keyboard shortcut for image properties 2025-12-16 18:40:37 +02:00
Elian Doran
613764d423 feat(layout): keyboard shortcut for file properties 2025-12-16 18:39:31 +02:00
Elian Doran
0518e64576 feat(layout): keyboard shortcut for collection properties 2025-12-16 18:32:33 +02:00
Elian Doran
713900b2b3 feat(layout): focus exactly on basic properties 2025-12-16 18:29:46 +02:00
Elian Doran
c0eb34927f feat(layout): keyboard shortcut for basic properties 2025-12-16 18:23:14 +02:00
Elian Doran
ec3c9a9ae5 feat(layout): keyboard shortcut for formatting toolbar 2025-12-16 18:16:05 +02:00
noobhjy
70374b622e Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1700 of 1700 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-12-16 17:02:40 +01:00
green
7fcc0ae290 Translated using Weblate (Japanese)
Currently translated at 99.8% (1697 of 1700 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-16 17:02:40 +01:00
Luk On
1de4db1a08 Translated using Weblate (Polish)
Currently translated at 100.0% (1700 of 1700 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-12-16 17:02:40 +01:00
Hosted Weblate
74ac58d3a6 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/
2025-12-16 17:02:40 +01:00
Luk On
993f56976e Translated using Weblate (Polish)
Currently translated at 99.9% (1698 of 1699 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-12-16 17:02:40 +01:00
Giovi
94859f2303 Translated using Weblate (Italian)
Currently translated at 100.0% (1699 of 1699 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2025-12-16 17:02:40 +01:00
Elian Doran
db116981b8 fix(note_info): MIME type entry shown even when empty 2025-12-16 17:53:05 +02:00
Elian Doran
2e563b0a1f feat(note_info): display user-friendly note type name & icon 2025-12-16 17:53:05 +02:00
Elian Doran
7222b233f0 feat(note_info): separate note type from mime type 2025-12-16 17:53:05 +02:00
Adorian Doran
bea15c46e5 style/new layout: fix the title actions container wasting vertical space when empty 2025-12-16 17:49:17 +02:00
Elian Doran
d96157de47 New layout: Power breadcrumbs (#8077) 2025-12-16 17:43:19 +02:00
Elian Doran
120b5c678d chore(client): fix typecheck 2025-12-16 17:27:29 +02:00
Elian Doran
8c008e2e3a chore(breadcrumb): address requested changes 2025-12-16 17:17:58 +02:00
Elian Doran
7e07280eb3 feat(breadcrumb): relocate copy note path to empty area 2025-12-16 16:14:08 +02:00
Elian Doran
d28c3f0851 feat(breadcrumb): hide archived notes if needed 2025-12-16 16:08:41 +02:00
Elian Doran
0390fd3174 fix(breadcrumb): hiding archived notes doesn't update tree 2025-12-16 16:03:09 +02:00
Elian Doran
193c9d8fa6 feat(breadcrumb): option to hide archived notes 2025-12-16 16:00:23 +02:00
Elian Doran
3a4cff6529 feat(breadcrumb): allow creating notes from separator menu 2025-12-16 15:35:14 +02:00
Elian Doran
5449d033bf feat(breadcrumb): indicate archived in separator menu 2025-12-16 15:05:33 +02:00
Elian Doran
66ed88c409 fix(breadcrumb): archived not respected by last item 2025-12-16 15:03:47 +02:00
Elian Doran
94df5c9126 feat(breadcrumb): respect note color class in context menu 2025-12-16 15:02:16 +02:00
Elian Doran
181ea31c1c chore(client): improve error handling message in events 2025-12-16 14:06:12 +02:00
Elian Doran
f235839d03 feat(breadcrumb): indicate archived notes 2025-12-16 13:50:53 +02:00
Elian Doran
d97b68fcd7 feat(breadcrumb): maintain note color on hover 2025-12-16 13:44:35 +02:00
Elian Doran
79d1a509e5 feat(breadcrumb): respect note color in last item 2025-12-16 13:42:41 +02:00
Elian Doran
0af5fa9f0c feat(breadcrumb): respect note color 2025-12-16 13:40:22 +02:00
Elian Doran
2693b18ee6 refactor(breadcrumb): use new component for rendering note links 2025-12-16 13:36:50 +02:00
Elian Doran
34343ce356 fix(server): autocomplete shows empty name for hoisted note 2025-12-16 12:53:51 +02:00
Elian Doran
c9025f2304 fix(breadcrumb): not reacting to changes in note path 2025-12-16 12:43:26 +02:00
Elian Doran
ec22fd9e99 refactor(breadcrumb): use existing function to parse note path 2025-12-16 10:56:00 +02:00
Elian Doran
15f9b2cadf feat(breadcrumb): add context menu on last item 2025-12-16 10:52:03 +02:00
Elian Doran
7c85fe1c37 feat(breadcrumb): add search in subtree 2025-12-16 10:46:56 +02:00
Elian Doran
d1820a6bc3 feat(breadcrumb): color selector 2025-12-16 10:43:56 +02:00
Elian Doran
d1575a28ad feat(breadcrumb): add duplicate/archive/delete options 2025-12-16 10:34:43 +02:00
Elian Doran
d13e19cf59 feat(breadcrumb): copy note path to clipboard & recent changes in subtree options 2025-12-16 10:26:46 +02:00
Elian Doran
0b7ffdf109 chore(breadcrumb): remove keyboard shortcuts 2025-12-16 10:20:15 +02:00
Elian Doran
e91cb1a198 feat(breadcrumb): add clone to/move to options 2025-12-16 10:16:09 +02:00
Elian Doran
51fcda646d feat(breadcrumb): add hoist option 2025-12-16 10:09:10 +02:00
Elian Doran
cb8e35c4dc feat(breadcrumb): get link menu items 2025-12-16 10:03:28 +02:00
Elian Doran
9d581347f1 Revert "feat(breadcrumb): get tree menu to show"
This reverts commit 96a6ea4c7a.
2025-12-16 09:56:21 +02:00
Elian Doran
96a6ea4c7a feat(breadcrumb): get tree menu to show 2025-12-16 09:35:19 +02:00
Elian Doran
587ea42700 chore(breadcrumb): get a menu to render on note link 2025-12-16 09:27:40 +02:00
renovate[bot]
8a5c7b3551 chore(deps): update dependency @ckeditor/ckeditor5-dev-build-tools to v54 2025-12-16 01:20:12 +00:00
renovate[bot]
f1fa44feb6 chore(deps): update typescript-eslint monorepo to v8.50.0 2025-12-16 01:19:39 +00:00
renovate[bot]
569cb6bf53 chore(deps): update pnpm to v10.26.0 2025-12-16 01:19:08 +00:00
renovate[bot]
3445b594e8 chore(deps): update dependency vite to v7.3.0 2025-12-16 01:18:58 +00:00
renovate[bot]
676595dd6b chore(deps): update dependency openai to v6.13.0 2025-12-16 01:18:25 +00:00
renovate[bot]
f8c84602f4 fix(deps): update dependency i18next to v25.7.3 2025-12-16 01:17:51 +00:00
renovate[bot]
d41842bc2a chore(deps): update dependency @smithy/middleware-retry to v4.4.16 2025-12-16 01:17:16 +00:00
renovate[bot]
ced47e64db chore(deps): update dependency @redocly/cli to v2.12.7 2025-12-16 01:16:41 +00:00
Elian Doran
16a6344687 fix(layout/badges): not reacting to changes in share 2025-12-16 00:10:42 +02:00
Elian Doran
7bac0b25ce feat(layout/badges): interactive share badge 2025-12-16 00:07:19 +02:00
Elian Doran
6094f738f2 New layout refinements (#8064) 2025-12-15 17:47:03 +02:00
Elian Doran
c3a6d1bba8 feat(badge): bigger dropdown arrow 2025-12-15 17:17:01 +02:00
Elian Doran
1feeb350ce chore(client): address requested changes 2025-12-15 17:14:00 +02:00
Elian Doran
f21ba207fe feat(inline_title): improve fit on small splits 2025-12-15 16:50:26 +02:00
Elian Doran
07c8ff4571 chore(note_type_switcher): shorten last modified date 2025-12-15 16:49:09 +02:00
Elian Doran
71d8588091 feat(note_type_switcher): use arrows next to dropdowns 2025-12-15 16:47:53 +02:00
Elian Doran
3c41b7e5a9 feat(note_type_switcher): use singular form 2025-12-15 16:45:56 +02:00
Elian Doran
41b7a295b9 feat(breadcrumb): add tooltip about jumping to top 2025-12-15 16:40:36 +02:00
Elian Doran
ca8e889e1e feat(breadcrumb): respect workspace color 2025-12-15 16:37:33 +02:00
Elian Doran
6d4e52c928 feat(breadcrumb): prefer workspace icon class 2025-12-15 16:31:43 +02:00
Elian Doran
e2fac8ab05 feat(breadcrumb): distinguish between workspace and hoisted notes 2025-12-15 16:26:25 +02:00
Elian Doran
af3883fdac feat(breadcrumb): react to hosted note ID change 2025-12-15 16:20:17 +02:00
Elian Doran
83777d7ea0 feat(breadcrumb): unhoist badge 2025-12-15 16:02:31 +02:00
Elian Doran
c6854c84b9 feat(breadcrumb): use different approach for displaying workspace icon 2025-12-15 15:52:55 +02:00
Elian Doran
eb99352fff Revert "feat(breadcrumb): display workspace text"
This reverts commit 441958028d.
2025-12-15 15:29:53 +02:00
Elian Doran
7dac5d424b Translations update from Hosted Weblate (#8061) 2025-12-15 15:24:27 +02:00
Elian Doran
441958028d feat(breadcrumb): display workspace text 2025-12-15 15:10:37 +02:00
Elian Doran
80b61a35a9 feat(breadcrumb): display correct icon for first note when hoisted 2025-12-15 15:10:37 +02:00
Elian Doran
61df0f3d31 feat(breadcrumb): trim path when hoisted 2025-12-15 15:10:37 +02:00
green
23ece9fc86 Translated using Weblate (Japanese)
Currently translated at 100.0% (1695 of 1695 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-15 13:15:48 +01:00
Kuzma Simonov
220e3d7195 Translated using Weblate (Russian)
Currently translated at 95.0% (1602 of 1686 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ru/
2025-12-15 13:15:47 +01:00
Kuzma Simonov
392c0311e5 Translated using Weblate (Russian)
Currently translated at 17.1% (26 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ru/
2025-12-15 13:15:46 +01:00
Adorian Doran
3abdcfa7a5 style/status bar/breadcrumb: tweak the last segment 2025-12-15 14:15:36 +02:00
Elian Doran
4896042fc4 fix(layout): classic toolbar not appearing after making a note temporarily editable 2025-12-15 12:45:27 +02:00
Elian Doran
7edfd5d7b4 fix(layout): classic toolbar in zen mode 2025-12-15 12:41:34 +02:00
Elian Doran
ad8e52f744 feat(layout): disable transition when promoted attributes are shown by default 2025-12-15 12:14:44 +02:00
Elian Doran
455dc5dc11 feat(layout): automatically collapse promoted attributes in full-height notes 2025-12-15 12:10:12 +02:00
Elian Doran
158f5ac310 feat(layout): use collapsible for promoted attributes 2025-12-15 12:10:12 +02:00
Elian Doran
fb70029091 fix(icon-list): border-left icon regular missing 2025-12-15 12:10:12 +02:00
Elian Doran
b370512893 fix(status_bar): unable to dismiss panes 2025-12-15 12:10:12 +02:00
Elian Doran
764607314c feat(tree): change icon for note paths 2025-12-15 12:10:12 +02:00
Adorian Doran
dbcf9b01c5 style/status bar/note paths flyout: document 2025-12-15 12:06:32 +02:00
Adorian Doran
93ce77438f style/status bar/note paths flyout: tweak the current path arrow 2025-12-15 12:04:39 +02:00
Adorian Doran
14c30661e6 Restyle the backlinks flyout (#8063) 2025-12-15 12:01:48 +02:00
Adorian Doran
37efc44f43 Merge branch 'main' into feat/restyle/backlinks-panel 2025-12-15 11:54:03 +02:00
Adorian Doran
6aaade846a style/status bar/backlinks flyout: restyle 2025-12-15 11:52:04 +02:00
Elian Doran
bd2402396b New layout: Remove floating buttons (#8059) 2025-12-15 11:11:18 +02:00
Elian Doran
a9b3479216 fix(mermaid): preview not 100% height on vertical layout 2025-12-15 10:54:39 +02:00
Adorian Doran
05e98877b0 style/status bar/backlinks flyout: rename HTML tag 2025-12-15 10:52:14 +02:00
Elian Doran
862ddf3a71 fix(mermaid): 1px border visible in read-only mode 2025-12-15 10:51:54 +02:00
Elian Doran
c1df2c45de fix(context_menu): regression on mobile sub-menu 2025-12-15 10:47:28 +02:00
Elian Doran
065e97c940 chore(layout/note_actions): address requested changes 2025-12-15 10:41:58 +02:00
Elian Doran
adae7fa03b feat(layout/note_actions): integrate in-app help button 2025-12-15 10:24:24 +02:00
Elian Doran
b725dbea7e feat(layout/note_actions): export as image 2025-12-15 10:06:01 +02:00
Elian Doran
4b80eec000 feat(layout/note_actions): integrate geo map add button 2025-12-15 09:14:19 +02:00
Elian Doran
d7722a1e05 feat(layout/note_actions): integrate add child for relation map 2025-12-15 09:07:45 +02:00
Elian Doran
35cfcc59f6 feat(layout/note_actions): integrate zoom buttons into relation map 2025-12-15 09:04:31 +02:00
Elian Doran
192190d685 fix(layout/note_actions): save to note not disappearing after save 2025-12-15 08:46:27 +02:00
Elian Doran
d6cc4bfa9c fix(layout/note_actions): buttons not reacting to mime type changes 2025-12-15 08:34:40 +02:00
Elian Doran
ed284fbc5f feat(layout/note_actions): integrate open API docs 2025-12-15 08:33:15 +02:00
Elian Doran
cb0efe25f5 feat(layout/note_actions): integrate save to note button 2025-12-15 08:24:59 +02:00
Elian Doran
906fe4f8da feat(layout/note_actions): integrate execute script button 2025-12-15 08:19:40 +02:00
Elian Doran
04a641199b feat(layout/note_actions): prevent layout shift by disabling button 2025-12-15 08:17:01 +02:00
Elian Doran
50cbad22d0 feat(layout/note_actions): integrate toggle read-only button 2025-12-15 08:15:00 +02:00
Elian Doran
4cfe59271f feat(layout/note_actions): integrate switch split orientation 2025-12-15 08:12:39 +02:00
Elian Doran
ba7969dad4 style(backend-log): remove extra padding & decrease font size 2025-12-15 08:08:45 +02:00
Elian Doran
43b6440bf9 style: borderless and paddingless code editor 2025-12-15 08:05:18 +02:00
Elian Doran
3e19a163c2 feat(layout/note_actions): integrate refresh backend log 2025-12-15 08:00:03 +02:00
Elian Doran
ca39282269 fix(global_menu): alignment of advanced button 2025-12-15 07:53:34 +02:00
Elian Doran
016389df68 fix(context_menu): clicking on a submenu dismisses it 2025-12-15 07:51:53 +02:00
Elian Doran
17db2a6b38 Revert "fix(context_menu): clicking submenu dismisses the menu"
This reverts commit 34bc444b18.
2025-12-15 07:46:36 +02:00
Elian Doran
bc8f17ee5c New layout refinement (#8053) 2025-12-15 07:36:58 +02:00
Elian Doran
0c8944ab8e chore(layout): address requested changes 2025-12-15 07:27:55 +02:00
Elian Doran
0960b585bd fix(layout): note actions button duplicated in old layout 2025-12-15 07:25:49 +02:00
Chris Cavalluzzi
55649c3750 fix(docs): mismatching phrasing in reference link notes 2025-12-14 21:17:59 -07:00
Chris Cavalluzzi
51bbf71577 feat(docs): improve link docs organization 2025-12-14 19:30:21 -07:00
Adorian Doran
728fab1dda Tweak note info (#8056) 2025-12-15 02:24:41 +02:00
Adorian Doran
d5ec80d85d client/status bar/note info: fix an issue pointed by gemini-code-assist 2025-12-15 02:23:57 +02:00
Adorian Doran
15ef93d7e6 style/status bar/note info: tweak appearance 2025-12-15 02:07:14 +02:00
Adorian Doran
9711b22ea9 style/status bar/note info: replace the "calculate" button with a link 2025-12-15 01:55:43 +02:00
Adorian Doran
b9c7d2b01d Tweak note paths (#8055) 2025-12-15 01:48:03 +02:00
Adorian Doran
9834846a23 client/status bar/note paths: fix the issues pointed by gemini-code-assist 2025-12-15 01:43:36 +02:00
Adorian Doran
65f425df2c style/status bar/note paths: fix an issue pointed by gemini-code-assist 2025-12-15 01:37:36 +02:00
Adorian Doran
a551dfe4d6 style/status bar/note paths: fix the final path segment color when icons are displayed 2025-12-15 01:18:35 +02:00
Adorian Doran
e9bfacdb7c style/status bar/note paths: highlight the current path 2025-12-15 01:12:51 +02:00
Adorian Doran
3ba7b7d439 style/status bar/note paths: refactor 2025-12-15 00:49:25 +02:00
Adorian Doran
381943818d client/status bar/note paths: improve appearance 2025-12-15 00:37:23 +02:00
Adorian Doran
d1ae2db587 client/status bar/note paths: replace the "Clone note to new location" button with a link 2025-12-15 00:31:36 +02:00
Elian Doran
8fa6e38382 refactor(ribbon): decouple completely from new layout 2025-12-14 23:50:40 +02:00
Elian Doran
749074ea94 chore(layout/status_bar): enforce single pane opened at a time 2025-12-14 23:35:16 +02:00
Elian Doran
f1bb786a49 chore(layout): support for similar notes in the status bar 2025-12-14 23:29:01 +02:00
Elian Doran
42bde3873b fix(layout): extra spacing between badges when no custom actions are available 2025-12-14 23:02:24 +02:00
Elian Doran
4877238015 refactor(layout): integrate copy image reference to button to all supported note types 2025-12-14 22:56:39 +02:00
Elian Doran
16374aaf1d refactor(layout): use note.isContentAvailable() 2025-12-14 22:51:50 +02:00
Elian Doran
19709f749a feat(layout): integrate copy reference to clipboard button 2025-12-14 22:50:26 +02:00
Elian Doran
09c7affc16 feat(layout): integrate file-similar options to image 2025-12-14 22:45:23 +02:00
Elian Doran
01e197fd46 feat(layout): integrate original file name into status bar 2025-12-14 22:34:13 +02:00
Elian Doran
0fe129ac16 feat(layout): add a margin for custom note action buttons 2025-12-14 22:22:41 +02:00
Elian Doran
3c52ceb4e6 refactor(layout): extract file actions to separate file 2025-12-14 22:16:54 +02:00
Elian Doran
8ba2357d91 feat(layout/file): upload new revision button 2025-12-14 22:14:05 +02:00
Elian Doran
20f4990d48 feat(layout/file): open externally & download buttons 2025-12-14 22:07:25 +02:00
Elian Doran
8c793bf0fe fix(layout): title area gets wrong note context 2025-12-14 21:58:10 +02:00
Elian Doran
12a0eebafe refactor(layout): handle note actions differently 2025-12-14 21:57:16 +02:00
Elian Doran
092c7dff6b fix(layout): extra padding when no note title actions 2025-12-14 21:38:02 +02:00
Elian Doran
7a1ff42d67 feat(layout/search_properties): expand search properties 2025-12-14 21:29:10 +02:00
Elian Doran
5a09a80902 feat(layout): basic ARIA & some padding 2025-12-14 21:20:55 +02:00
Elian Doran
a7ca839afb feat(layout/search_definition): integrate view options directly in search parameters 2025-12-14 20:48:50 +02:00
Elian Doran
6b9b9a96c3 feat(layout): integrate search parameters ribbon tab 2025-12-14 20:34:55 +02:00
Elian Doran
272888acab refactor(ribbon): format SearchDefinitionTab 2025-12-14 20:27:34 +02:00
Elian Doran
283e3c9de1 style(layout/edited_notes): increase vertical padding slighly 2025-12-14 20:23:08 +02:00
Elian Doran
859087b850 feat(layout/edited_notes): respect choice to auto-open 2025-12-14 20:21:30 +02:00
Elian Doran
f7b911dc0b feat(layout): make edited notes collapsible 2025-12-14 20:15:17 +02:00
Elian Doran
9d7e2855d3 feat(layout): edited notes underneath title details 2025-12-14 19:39:55 +02:00
Elian Doran
8e6ea87754 fix(context_menu): regressions on mobile 2025-12-14 12:02:40 +02:00
Elian Doran
34bc444b18 fix(context_menu): clicking submenu dismisses the menu 2025-12-14 12:02:32 +02:00
Elian Doran
860a903336 feat(breadcrumb): hide note paths if only one 2025-12-14 11:49:16 +02:00
Elian Doran
be923ad2b7 chore(breadcrumb): add text span for hiding them at some point 2025-12-14 11:47:18 +02:00
Elian Doran
d2da1ed1e7 feat(breadcrumb): make tooltips shorter 2025-12-14 11:26:09 +02:00
Elian Doran
1c05f5e5c3 feat(breadcrumb): disable tooltip animation for faster input 2025-12-14 11:21:27 +02:00
Elian Doran
e043f30cc6 feat(breadcrumb): add text for all items 2025-12-14 11:20:24 +02:00
Elian Doran
e1611d83a3 fix(breadcrumb): tree displayed in root navigation 2025-12-14 11:12:14 +02:00
Elian Doran
58e2111a8f chore(nix): update flake lock 2025-12-14 11:01:25 +02:00
Elian Doran
c5e4c484dc chore(deps): update react monorepo to v19.2.3 (#8033) 2025-12-14 10:58:02 +02:00
Elian Doran
75a6dece7a Translations update from Hosted Weblate (#8052) 2025-12-14 10:57:37 +02:00
Hosted Weblate
5c0e7736d6 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-12-14 09:52:47 +01:00
Elian Doran
2562ecd055 feat(renovate): enable nix 2025-12-14 10:52:29 +02:00
Elian Doran
aaaa47b575 Translations update from Hosted Weblate (#8049) 2025-12-14 10:33:29 +02:00
green
21d82ec1d7 Translated using Weblate (Japanese)
Currently translated at 100.0% (1686 of 1686 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-14 09:21:46 +01:00
Luk On
5af8444cac Translated using Weblate (Polish)
Currently translated at 100.0% (116 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/pl/
2025-12-14 09:21:46 +01:00
Wojciech O
cd82c34b93 Translated using Weblate (Polish)
Currently translated at 100.0% (389 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/pl/
2025-12-14 09:21:45 +01:00
noobhjy
d182659d62 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1686 of 1686 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-12-14 09:21:44 +01:00
Mik Piet
171f428b9d Translated using Weblate (Polish)
Currently translated at 100.0% (1686 of 1686 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-12-14 09:21:43 +01:00
kamykO
da4ca9c804 Translated using Weblate (Polish)
Currently translated at 100.0% (1686 of 1686 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-12-14 09:21:43 +01:00
Luk On
c019341503 Translated using Weblate (Polish)
Currently translated at 100.0% (1686 of 1686 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-12-14 09:21:42 +01:00
Hosted Weblate
7234f04b56 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-12-14 09:21:42 +01:00
Elian Doran
1998cbc005 chore(deps): update dependency @types/node to v24.10.4 (#8050) 2025-12-14 10:21:26 +02:00
renovate[bot]
5914073c3f chore(deps): update dependency @types/node to v24.10.4 2025-12-14 02:09:59 +00:00
Elian Doran
d5aadf2604 chore: add dev shell and direnv support (#8011) 2025-12-13 22:49:35 +02:00
renovate[bot]
1fe22f940b chore(deps): update react monorepo to v19.2.3 2025-12-13 20:46:52 +00:00
Elian Doran
0cdaf70efe chore(deps): update dependency electron to v39.2.7 (#8030) 2025-12-13 22:46:30 +02:00
Elian Doran
8174c65243 chore(deps): update dependency eslint to v9.39.2 (#8031) 2025-12-13 22:45:31 +02:00
Elian Doran
2645801277 chore(deps): update dependency vite to v7.2.7 (#8032) 2025-12-13 22:44:45 +02:00
Elian Doran
fb8c31cb9c fix(deps): update dependency i18next to v25.7.2 (#8035) 2025-12-13 22:44:05 +02:00
Elian Doran
7287dbd64f fix(deps): update dependency preact-render-to-string to v6.6.4 (#8036) 2025-12-13 22:43:19 +02:00
renovate[bot]
6569d64931 fix(deps): update dependency preact-render-to-string to v6.6.4 2025-12-13 19:24:56 +00:00
renovate[bot]
e9f3216926 fix(deps): update dependency i18next to v25.7.2 2025-12-13 19:24:28 +00:00
renovate[bot]
ca0af9646d chore(deps): update dependency vite to v7.2.7 2025-12-13 19:23:33 +00:00
renovate[bot]
92dfafd1ff chore(deps): update dependency eslint to v9.39.2 2025-12-13 19:23:05 +00:00
renovate[bot]
d04dde3b97 chore(deps): update dependency electron to v39.2.7 2025-12-13 19:22:36 +00:00
Elian Doran
4c520c6df3 e2e(server): broken test after submenu 2025-12-13 21:10:59 +02:00
Adorian Doran
65d6ed1cdc Merge branch 'main' of https://github.com/TriliumNext/Trilium 2025-12-13 20:42:24 +02:00
Adorian Doran
3352a92445 style/new layout/inline title: tweak 2025-12-13 20:42:16 +02:00
Elian Doran
bc8c55b8fb Translations update from Hosted Weblate (#8047) 2025-12-13 20:37:28 +02:00
Elian Doran
7660914eb8 Merge branch 'main' into weblate-trilium-client 2025-12-13 20:34:04 +02:00
Elian Doran
869aec778c New layout: Shared formatting toolbar (#8046) 2025-12-13 20:15:43 +02:00
noobhjy
255726dcc4 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1685 of 1685 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-12-13 18:09:10 +00:00
Adorian Doran
9969000807 style/new layout/note title: tweak 2025-12-13 20:08:57 +02:00
Elian Doran
3b909fd739 chore(layout/formatting_toolbar): address requested changes 2025-12-13 19:59:45 +02:00
Elian Doran
ad08fb8132 chore(formatting_toolbar): address self-review 2025-12-13 19:32:44 +02:00
Elian Doran
8d536a6040 fix(formatting_toolbar): view mode check not working in multi-split 2025-12-13 19:29:13 +02:00
Elian Doran
2b1bc8e2b9 feat(inline_title): in split, avoid layout shift by maintaining the toolbar 2025-12-13 16:54:04 +02:00
Adorian Doran
563194ff6c client/note menu: localize string 2025-12-13 16:45:09 +02:00
Elian Doran
0c9ff4dae4 chore(inline_title): fix type error 2025-12-13 16:43:27 +02:00
Elian Doran
b10e7f1811 fix(inline_title): some badges not visible in split 2025-12-13 16:42:06 +02:00
Elian Doran
f93ad499e2 feat(layout/formatting_toolbar): move above sidebar 2025-12-13 16:35:48 +02:00
Adorian Doran
87a51251ca client/layout/status bar: replace some icons 2025-12-13 16:33:33 +02:00
Elian Doran
b56e5b2483 fix(inline_title): note type switcher visible for options 2025-12-13 16:33:33 +02:00
Elian Doran
476c162016 fix(layout/formatting_toolbar): memory leak for closed tabs 2025-12-13 16:31:19 +02:00
Elian Doran
4182f6043a feat(layout/formatting_toolbar): render cached components 2025-12-13 16:26:01 +02:00
Elian Doran
aa528c65b7 chore(layout/formatting_toolbar): render without adapter 2025-12-13 16:05:11 +02:00
Elian Doran
4998560e31 chore(layout/inline_title): show note type switcher for code notes as well 2025-12-13 15:55:56 +02:00
Elian Doran
86f36922c4 Translations update from Hosted Weblate (#8025) 2025-12-13 15:42:54 +02:00
Hosted Weblate
4f617b86d3 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/
2025-12-13 13:34:47 +00:00
noobhjy
b28527e10d Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1683 of 1683 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-12-13 13:34:46 +00:00
green
fbb8924ebf Translated using Weblate (Japanese)
Currently translated at 100.0% (1683 of 1683 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-13 13:34:45 +00:00
Hosted Weblate
f68c9b751f Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/
2025-12-13 13:34:45 +00:00
Luk On
8091f02b16 Translated using Weblate (Polish)
Currently translated at 100.0% (1677 of 1677 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-12-13 13:34:44 +00:00
noobhjy
f4c68d115b Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1677 of 1677 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-12-13 13:34:43 +00:00
Luk On
6c70d6b9ae Translated using Weblate (Polish)
Currently translated at 100.0% (152 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/pl/
2025-12-13 13:34:43 +00:00
Luk On
1ea12567a3 Translated using Weblate (Polish)
Currently translated at 100.0% (116 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/pl/
2025-12-13 13:34:42 +00:00
Luk On
2d16ab7a70 Translated using Weblate (Polish)
Currently translated at 100.0% (389 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/pl/
2025-12-13 13:34:41 +00:00
Luk On
a228ba5273 Translated using Weblate (Polish)
Currently translated at 100.0% (1677 of 1677 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-12-13 13:34:41 +00:00
Luk On
d0477e9ebf Translated using Weblate (Polish)
Currently translated at 100.0% (152 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/pl/
2025-12-13 13:34:40 +00:00
Luk On
c99907972d Translated using Weblate (Polish)
Currently translated at 11.2% (13 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/pl/
2025-12-13 13:34:39 +00:00
Luk On
b9ebc7d7ea Translated using Weblate (Polish)
Currently translated at 100.0% (389 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/pl/
2025-12-13 13:34:39 +00:00
green
4f9e2c5eca Translated using Weblate (Japanese)
Currently translated at 100.0% (389 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ja/
2025-12-13 13:34:38 +00:00
green
ab1f8ee5ae Translated using Weblate (Japanese)
Currently translated at 100.0% (152 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ja/
2025-12-13 13:34:37 +00:00
green
89276ad51a Translated using Weblate (Japanese)
Currently translated at 100.0% (1677 of 1677 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-13 13:34:36 +00:00
green
eca533a517 Translated using Weblate (Japanese)
Currently translated at 100.0% (116 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/ja/
2025-12-13 13:34:36 +00:00
Elian Doran
0be578c517 chore(deps): update dependency @electron/rebuild to v4.0.2 (#8028) 2025-12-13 15:34:09 +02:00
Elian Doran
198b315602 chore(deps): update dependency @redocly/cli to v2.12.6 (#8029) 2025-12-13 15:33:28 +02:00
Elian Doran
6474abc983 fix(deps): update dependency eslint-linter-browserify to v9.39.2 (#8034) 2025-12-13 15:32:33 +02:00
Elian Doran
2137dbe849 chore(deps): update node.js to v24.12.0 (#8037) 2025-12-13 15:32:07 +02:00
Elian Doran
b7b46703d9 chore(deps): update pnpm to v10.25.0 (#8038) 2025-12-13 15:31:13 +02:00
Elian Doran
d2d96a1421 chore(deps): update typescript-eslint monorepo to v8.49.0 (#8039) 2025-12-13 15:30:26 +02:00
Elian Doran
cfcc309e5a fix(deps): update dependency @codemirror/view to v6.39.4 (#8040) 2025-12-13 15:28:35 +02:00
Elian Doran
7d87ec942e fix(deps): update dependency react-i18next to v16.5.0 (#8041) 2025-12-13 15:26:40 +02:00
Elian Doran
4def13272f chore(deps): update github artifact actions (major) (#8042) 2025-12-13 15:25:59 +02:00
Elian Doran
c4f914bb7b New layout: Title bar & inline title (#8044) 2025-12-13 15:09:30 +02:00
Elian Doran
6bf213a0b0 fix(layout/status_bar): some popups not dismissing 2025-12-13 15:02:16 +02:00
Elian Doran
694cd2bc7c chore(layout/title_bar): address LLM review 2025-12-13 14:58:11 +02:00
Elian Doran
3851a94400 fix(layout/title_bar): badges not collapsing 2025-12-13 14:51:58 +02:00
Elian Doran
e296416a54 fix(layout/inline-title): title not shown when switching to other types of notes 2025-12-13 14:38:58 +02:00
Elian Doran
0bd89a659c chore(layout/inline-title): disable pointer events while hidden 2025-12-13 14:00:27 +02:00
Elian Doran
0ada6523a8 feat(layout/inline-title): add transition 2025-12-13 13:58:20 +02:00
Elian Doran
56570d7ba1 fix(layout/inline-title): text displayed even when note is not empty 2025-12-13 13:46:28 +02:00
Elian Doran
0ffdedcfa6 feat(layout/inline-title): dropdown for collections 2025-12-13 13:45:34 +02:00
Elian Doran
f391bb8eec feat(layout/inline-title): support built-in templates 2025-12-13 13:35:32 +02:00
Elian Doran
7000076961 feat(layout/inline-title): react to template add/remove 2025-12-13 13:26:48 +02:00
Elian Doran
e0f6ba808c feat(layout/inline-title): template switcher 2025-12-13 13:24:32 +02:00
Elian Doran
4c2fe8a846 feat(layout/inline-title): group some note types 2025-12-13 13:12:03 +02:00
Elian Doran
2ea23368bc feat(vscode): eslint on save 2025-12-13 12:59:32 +02:00
Elian Doran
87666005a6 feat(layout/inline-title): add an intro text 2025-12-13 12:57:33 +02:00
Elian Doran
7666f44b7a fix(layout/inline-title): hide note type switcher on other note types 2025-12-13 12:49:51 +02:00
Elian Doran
470f6e5334 feat(layout/inline-title): hide note type switcher when empty 2025-12-13 12:48:20 +02:00
Elian Doran
a2b007874b feat(layout/inline-title): not reacting to note type changes 2025-12-13 12:43:15 +02:00
Elian Doran
9946d8c6b9 fix(layout/statusbar): code note switcher displayed for other note types 2025-12-13 12:29:59 +02:00
Elian Doran
02fab16475 feat(layout/inline-title): add icons 2025-12-13 12:28:22 +02:00
Elian Doran
5145ce2d23 feat(layout/inline-title): horizontal scroll via wheel 2025-12-13 12:27:45 +02:00
Elian Doran
e06abe6e5b fix(layout/inline-title): current note type displayed in switcher 2025-12-13 12:26:02 +02:00
Elian Doran
50a847777e feat(layout/inline-title): basic note type switcher 2025-12-13 12:25:01 +02:00
Elian Doran
4473f80d73 refactor(layout): remove floating title bar experiment 2025-12-13 12:02:17 +02:00
Elian Doran
70c918c9c6 feat(layout/inline-title): support in options as well 2025-12-13 12:01:06 +02:00
Elian Doran
0939975631 style(layout/inline-title): use muted text color 2025-12-13 11:58:35 +02:00
Elian Doran
0ef90c6165 fix(layout/inline-title): hide in attachments and other view scopes 2025-12-13 11:57:53 +02:00
Elian Doran
cef14a3b19 feat(layout/inline-title): support code 2025-12-13 11:51:57 +02:00
Elian Doran
61d3141bce refactor(layout/inline-title): extract specific styles 2025-12-13 11:49:05 +02:00
Elian Doran
f040a0b6d1 refactor(layout/inline-title): separate old title details into title actions 2025-12-13 11:46:42 +02:00
Elian Doran
e9dfec88c9 feat(layout/inline-title): bring back creation and modification date 2025-12-13 11:43:27 +02:00
Elian Doran
6fa97c845a fix(layout/inline-title): still visible in other note types 2025-12-13 11:37:56 +02:00
Elian Doran
f686d9ecd0 feat(layout/inline-title): keep header bar visible 2025-12-13 11:34:29 +02:00
Elian Doran
621ebe4396 feat(layout/inline-title): title and icon 2025-12-13 11:33:02 +02:00
Adorian Doran
ac2a566685 client/note menu: reorganize menu items 2025-12-13 11:29:39 +02:00
Elian Doran
ac3d57d5da chore(layout): remove ribbon border 2025-12-13 11:28:52 +02:00
Elian Doran
9ab5eef984 feat(layout/inline-title): intersection observer 2025-12-13 11:26:42 +02:00
Elian Doran
912f90accf feat(layout/inline-title): collapse title for text notes 2025-12-13 11:17:39 +02:00
Elian Doran
6463b0dcaa chore(layout/inline-title): placeholder for the title 2025-12-13 11:08:34 +02:00
Elian Doran
0b45fb6764 feat(layout/title): hide note badges while editing title 2025-12-13 10:57:34 +02:00
Elian Doran
330d71847b refactor(layout/title): rename to note badges 2025-12-13 10:54:19 +02:00
Elian Doran
60c8f0c78b refactor(layout/title): relocate badges to layouts dir 2025-12-13 10:47:46 +02:00
Elian Doran
fcbd1ab0b1 chore(layout/title): remove spacer 2025-12-13 10:44:33 +02:00
Elian Doran
3549bfb328 feat(layout/title): collapse badges and note title while constrained in size 2025-12-13 10:43:32 +02:00
Elian Doran
c97038fffd chore(layout): revert breadcrumb row 2025-12-13 10:26:25 +02:00
Elian Doran
15b5885982 New layout: status bar (#8021) 2025-12-13 10:23:12 +02:00
renovate[bot]
6aa8d9fbf9 chore(deps): update github artifact actions 2025-12-13 01:19:13 +00:00
renovate[bot]
eccf4620ac fix(deps): update dependency react-i18next to v16.5.0 2025-12-13 01:19:08 +00:00
renovate[bot]
f08fbe9bb2 fix(deps): update dependency @codemirror/view to v6.39.4 2025-12-13 01:18:39 +00:00
renovate[bot]
bfa87af489 chore(deps): update typescript-eslint monorepo to v8.49.0 2025-12-13 01:18:08 +00:00
renovate[bot]
a7899b7505 chore(deps): update pnpm to v10.25.0 2025-12-13 01:17:37 +00:00
renovate[bot]
e80b5cddcd chore(deps): update node.js to v24.12.0 2025-12-13 01:17:27 +00:00
renovate[bot]
db12f9b8dc fix(deps): update dependency eslint-linter-browserify to v9.39.2 2025-12-13 01:15:42 +00:00
renovate[bot]
f4c95195c9 chore(deps): update dependency @redocly/cli to v2.12.6 2025-12-13 01:12:39 +00:00
renovate[bot]
e2cbff7b3a chore(deps): update dependency @electron/rebuild to v4.0.2 2025-12-13 01:11:53 +00:00
Elian Doran
98a3c8150c feat(breadcrumb): replace title editing with jump to top 2025-12-13 01:45:02 +02:00
Elian Doran
447e09fec1 feat(note_actions): hide code notes from new layout 2025-12-13 01:24:37 +02:00
Elian Doran
7d2a1bb2e5 feat(status_bar): modal for configuring list of code languages 2025-12-13 01:19:20 +02:00
Elian Doran
40fcf79778 fix(status_bar): code mime not updating between notes 2025-12-13 01:14:50 +02:00
Elian Doran
88a779bbdb feat(status_bar): indicate selected code mime in menu 2025-12-13 01:10:38 +02:00
Elian Doran
db04514769 fix(status_bar): code mime switcher is clipped 2025-12-13 01:07:30 +02:00
Elian Doran
23062470f5 feat(status_bar): code mime switcher 2025-12-13 01:03:57 +02:00
Elian Doran
5bad043ed5 chore(status_bar): address requested changes 2025-12-13 00:43:00 +02:00
Elian Doran
4ab8af0995 feat(status_bar): keep button active when dropdown is shown 2025-12-13 00:37:29 +02:00
Elian Doran
1a65c5e13e feat(status_bar): hide note paths in hidden notes 2025-12-13 00:30:22 +02:00
Elian Doran
fc08946038 chore(status_bar): avoid shifting due to language switcher 2025-12-13 00:27:51 +02:00
Elian Doran
4d6dba06ad refactor(ribbon): remove left-over logic for calculating ribbon height 2025-12-13 00:24:05 +02:00
Elian Doran
d7887fe25f chore(layout): hide ribbon in new layout 2025-12-13 00:22:34 +02:00
Elian Doran
81dd50e752 fix(status_bar): wrong font size for language selector text 2025-12-13 00:13:06 +02:00
Elian Doran
fe13065ef8 lint: status bar 2025-12-13 00:11:28 +02:00
Elian Doran
eb02330fdf feat(status_bar): integrate note paths widget 2025-12-13 00:05:33 +02:00
Elian Doran
738fa6fd0e lint: note paths 2025-12-12 23:51:03 +02:00
Elian Doran
0c1c7e4f8e feat(status_bar): note paths (no interaction yet) 2025-12-12 23:47:31 +02:00
Elian Doran
9eb9b66398 fix(status_bar): keyboard shortcuts to add attributes not working 2025-12-12 23:34:26 +02:00
Elian Doran
9db046b401 fix(status_bar): attributes not editable from modal 2025-12-12 23:29:59 +02:00
Elian Doran
914272eee0 style(status_bar): improve layout and spacing slightly 2025-12-12 23:13:31 +02:00
Elian Doran
2b7e203bcc refactor(status_bar): remove wrapper container for breadcrumb 2025-12-12 23:07:57 +02:00
Elian Doran
a61ddedc0b refactor(status_bar): remove old breadcrumb styles 2025-12-12 23:06:47 +02:00
Elian Doran
60fc34ffac feat(status_bar): functional attribute toggle button 2025-12-12 21:57:42 +02:00
Elian Doran
685109556c chore(ribbon): hide inherited & owned attributes on new layout 2025-12-12 21:49:42 +02:00
Elian Doran
45927053f3 fix(ribbon): links in inherited attributes not visible 2025-12-12 21:48:11 +02:00
Elian Doran
5d438a877b feat(status_bar): improve alignment of attribute editor 2025-12-12 21:44:27 +02:00
Elian Doran
870499bc3a feat(status_bar): basic integration of inherited attributes 2025-12-12 21:41:05 +02:00
Elian Doran
c6d97e3d4b feat(status_bar): basic integration of attribute editor 2025-12-12 21:30:32 +02:00
Elian Doran
efff38b116 feat(status_bar): attribute button (not yet interactive) 2025-12-12 21:19:23 +02:00
Elian Doran
1b725175c6 refactor(status_bar): solve warnings 2025-12-12 20:59:57 +02:00
Elian Doran
6eff62f73f feat(status_bar): add new attachment count 2025-12-12 20:55:54 +02:00
Elian Doran
95d2160c76 feat(status_bar): integrate backlinks 2025-12-12 20:31:19 +02:00
Elian Doran
2b195155ed fix(note_details): appearing in options 2025-12-12 20:21:55 +02:00
Elian Doran
28e9abc8bb chore(status_bar): re-order icons to avoid layout shifting 2025-12-12 20:19:37 +02:00
Elian Doran
0162b9d441 fix(status_bar): language selector appearing for non-text notes 2025-12-12 20:18:50 +02:00
Elian Doran
0545b929e1 fix(status_bar): react to active note context 2025-12-12 20:17:53 +02:00
Elian Doran
d2b32ff5af feat(status_bar): relocate to outside split area 2025-12-12 19:47:47 +02:00
Elian Doran
2d3776cd5f feat(status_bar): integrate note info badge 2025-12-12 19:31:00 +02:00
Elian Doran
2638963171 feat(status_bar/language): add tooltip 2025-12-12 18:58:54 +02:00
Elian Doran
24ed97f65d feat(status_bar/language): improve display of more languages 2025-12-12 18:53:54 +02:00
Elian Doran
c099634e39 feat(status_bar/language): improve display of Asian languages 2025-12-12 18:50:48 +02:00
Elian Doran
12be14e6cf feat(status_bar/language): display icon 2025-12-12 18:47:34 +02:00
Elian Doran
4dc773c1a3 refactor(status_bar/language): stop reusing UI for greater customisibility 2025-12-12 18:29:40 +02:00
Elian Doran
31c5323fd9 feat(status_bar/language): compact locale name 2025-12-12 18:05:10 +02:00
Elian Doran
74b6e7bf63 fix(breadcrumb): some dropdowns not visible 2025-12-12 17:55:22 +02:00
Elian Doran
34025fa646 fix(global_menu): dev menu wrongly positioned on horizontal layout 2025-12-12 14:41:10 +02:00
Elian Doran
df9554194a feat(layout/status_bar): integrate language selector basically 2025-12-12 00:34:47 +02:00
Elian Doran
4e1188484d refactor(layout/status_bar): move breadcrumbs into layout dir 2025-12-12 00:24:30 +02:00
Elian Doran
2f44b9dc59 feat(layout/status_bar): integrate breadcrumbs 2025-12-12 00:21:40 +02:00
Elian Doran
9ee3c48485 chore(layout): relocate ribbon on the top temporarily 2025-12-12 00:15:58 +02:00
Elian Doran
78b9c94829 chore(layout/status_bar): create empty component 2025-12-12 00:13:38 +02:00
Elian Doran
4c8225ed73 Translations update from Hosted Weblate (#8020) 2025-12-11 23:58:41 +02:00
noobhjy
88aad6d351 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1668 of 1668 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-12-11 20:38:41 +00:00
Elian Doran
d99d701095 feat(global_menu): add support for all experimental options 2025-12-11 22:38:22 +02:00
Elian Doran
61fe27abbe feat(layout): extract floating titlebar into its own experimental feature 2025-12-11 22:29:22 +02:00
Elian Doran
24cd5006d5 chore(note_map): open in reusable split 2025-12-11 22:14:08 +02:00
Elian Doran
726d6aad65 feat(layout): integrate note map 2025-12-11 22:01:22 +02:00
Elian Doran
bd9fe14a6c chore(layout): remove title extra spacing for now 2025-12-11 21:08:36 +02:00
Elian Doran
792a10ace5 New layout: Integrate small ribbon categories + collection properties (#8018) 2025-12-11 20:59:31 +02:00
Elian Doran
e9ac69b8e5 chore(note_bars/collection): address change request 2025-12-11 20:33:52 +02:00
Elian Doran
c76ff2d371 feat(note_bars/collection): add a help button 2025-12-11 20:19:06 +02:00
Elian Doran
8ab9e30404 chore(note_bars/collection): disable ribbon tab 2025-12-11 20:13:04 +02:00
Elian Doran
53b7d93efb feat(note_bars/collection): support comboboxes 2025-12-11 20:09:25 +02:00
Elian Doran
00df3c3d1f feat(note_bars/collection): support number fields 2025-12-11 19:51:40 +02:00
Elian Doran
e766b82418 feat(note_bars/collection): add icon to checkboxes 2025-12-11 19:44:22 +02:00
Elian Doran
9f4757af5b chore(note_bars/collection): put archived notes at the end 2025-12-11 19:39:07 +02:00
Elian Doran
1a9fb34a6e feat(note_bars/collection): support dropdown menu click action 2025-12-11 19:37:04 +02:00
Elian Doran
a1513a3567 feat(note_bars/collection): support split button properties 2025-12-11 19:34:22 +02:00
Elian Doran
0de67b6a69 feat(note_bars/collection): support button properties 2025-12-11 19:29:27 +02:00
Elian Doran
fec5ee9335 feat(note_bars/collection): integrate show archived notes 2025-12-11 19:21:51 +02:00
Elian Doran
b540111fa4 feat(note_bars): add icons to view type switcher 2025-12-11 18:59:28 +02:00
Elian Doran
0eed72b888 feat(note_bars): view type switcher 2025-12-11 18:53:48 +02:00
Elian Doran
0856d3dbdf fix(layout): note title padding on full-height note 2025-12-11 18:02:52 +02:00
Elian Doran
a9b453c27a feat(breadcrumb_badges): integrate query/script tab 2025-12-11 17:43:00 +02:00
Elian Doran
fa8287269f feat(breadcrumb_badges): integrate note properties tab 2025-12-11 17:34:04 +02:00
Elian Doran
1eee471018 fix(breadcrumb_badges): temporarily editable showing up always in popup editor 2025-12-11 17:20:28 +02:00
Elian Doran
c3829f82ab New layout: Note info (#8015) 2025-12-11 17:18:19 +02:00
Elian Doran
a51820f5df chore(note_info): address requested changes 2025-12-11 16:57:04 +02:00
Elian Doran
68591fb511 feat(note_info): hide ribbon on new layout 2025-12-11 16:48:49 +02:00
Elian Doran
3795ce2143 feat(note_info): integrate near the note title 2025-12-11 16:47:44 +02:00
Elian Doran
3561a4f14d feat(note_info): add back tooltip for note size 2025-12-11 16:38:31 +02:00
Elian Doran
84cda001aa feat(note_info): improve layout slightly 2025-12-11 16:33:18 +02:00
Elian Doran
481127a560 docs(user): mention version for board custom attributes 2025-12-11 10:57:30 +02:00
Elian Doran
c708e7cd61 Translations update from Hosted Weblate (#8016) 2025-12-11 10:49:33 +02:00
Elian Doran
fee0268792 Translated using Weblate (Romanian)
Currently translated at 100.0% (116 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/ro/
2025-12-11 09:47:52 +01:00
green
953593c9d4 Translated using Weblate (Japanese)
Currently translated at 100.0% (1668 of 1668 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-11 09:47:52 +01:00
Elian Doran
5ff60e53cb Translated using Weblate (Romanian)
Currently translated at 100.0% (1668 of 1668 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ro/
2025-12-11 09:47:51 +01:00
Giovi
b38ee36fae Translated using Weblate (Italian)
Currently translated at 100.0% (1668 of 1668 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2025-12-11 09:47:49 +01:00
Hosted Weblate
38a415faf0 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-12-11 09:32:25 +01:00
Elian Doran
1e26864842 Translations update from Hosted Weblate (#8006) 2025-12-11 10:32:09 +02:00
Elian Doran
4b74ad5577 feat(breadcrumb/note_info): note size 2025-12-11 00:34:25 +02:00
Elian Doran
e5696713de feat(breadcrumb/note_info): modification/creation date 2025-12-11 00:23:32 +02:00
Elian Doran
2e44397c88 feat(breadcrumb/note_info): get basic dropdown 2025-12-11 00:18:56 +02:00
Francis C.
5d19881981 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (1658 of 1658 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hant/
2025-12-10 22:38:11 +01:00
Tomas Adamek
1711384eaa Translated using Weblate (Czech)
Currently translated at 35.3% (41 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/cs/
2025-12-10 22:38:11 +01:00
Tomas Adamek
9897efe4af Translated using Weblate (Czech)
Currently translated at 5.3% (88 of 1658 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/cs/
2025-12-10 22:38:10 +01:00
Francis C.
884578ea95 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (116 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/zh_Hans/
2025-12-10 22:38:09 +01:00
Francis C.
e404e76299 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (116 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/zh_Hant/
2025-12-10 22:38:09 +01:00
green
1db54cba3e Translated using Weblate (Japanese)
Currently translated at 100.0% (1658 of 1658 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-10 22:38:08 +01:00
Francis C.
77e3cc4021 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1658 of 1658 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-12-10 22:38:07 +01:00
pythaac
242c63dfb4 Translated using Weblate (Korean)
Currently translated at 65.1% (99 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ko/
2025-12-10 22:38:06 +01:00
Abdulmajeed Alaskar
f5440576b5 Translated using Weblate (Arabic)
Currently translated at 53.9% (82 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ar/
2025-12-10 22:38:06 +01:00
Abdulmajeed Alaskar
b020365af4 Translated using Weblate (Arabic)
Currently translated at 29.3% (34 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/ar/
2025-12-10 22:38:05 +01:00
green
25e5bf0b86 Translated using Weblate (Japanese)
Currently translated at 100.0% (1648 of 1648 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-10 22:38:05 +01:00
Elian Doran
19b32dd3a6 New layout: Integrate Basic properties (#8014) 2025-12-10 23:37:54 +02:00
Elian Doran
1ab89d0db0 fix(status_bar): language selector not updating properly 2025-12-10 23:36:47 +02:00
Elian Doran
6e8e10323f chore(client): address requested changes 2025-12-10 23:19:17 +02:00
Elian Doran
58bc5dc66a chore(ribbon): hide basic properties from the ribbon on new layout 2025-12-10 23:07:35 +02:00
Elian Doran
db42bb603b feat(status_bar): add help item 2025-12-10 23:04:32 +02:00
Elian Doran
cb382c9537 fix(global_menu): layout switcher sometimes fails 2025-12-10 22:57:52 +02:00
Elian Doran
a4b79a2dc9 fix(ribbon): content code modal hidden behind backdrop 2025-12-10 22:56:29 +02:00
Elian Doran
0f867e02c4 fix(ribbon): content languages modal hidden behind backdrop 2025-12-10 22:52:13 +02:00
Elian Doran
ab1b4b37f4 feat(global_menu): add an option to switch layouts 2025-12-10 22:51:47 +02:00
Elian Doran
5a1d138f29 feat(status_bar): language selector 2025-12-10 22:39:07 +02:00
Elian Doran
06a5298efa feat(note_actions): hide options in attachments 2025-12-10 22:27:56 +02:00
Elian Doran
db720acc18 feat(note_actions): hide options in help pages 2025-12-10 22:25:09 +02:00
Elian Doran
8d8ff25bae feat(note_actions): reintroduce help pages 2025-12-10 22:21:15 +02:00
Elian Doran
6f85b7cc09 feat(note_actions): integrate note type 2025-12-10 21:54:17 +02:00
Elian Doran
77f5770bff feat(note_actions): protect note switch 2025-12-10 20:57:15 +02:00
Elian Doran
14cda5b921 fix(note_actions): editability context menu is too narrow 2025-12-10 20:46:58 +02:00
Elian Doran
36b1182565 feat(widgets/toggle): disable if going too fast 2025-12-10 20:33:30 +02:00
Elian Doran
483327c808 fix(widgets/toggle): double event triggering when in menu 2025-12-10 20:30:55 +02:00
Elian Doran
efb2f9a048 chore(note_actions): reintroduce disabled logic for toggles 2025-12-10 20:20:21 +02:00
Elian Doran
01978dabf0 fix(breadcrumb_badges): doesn't refresh when switching editability 2025-12-10 19:05:33 +02:00
Elian Doran
cfbd2bf53a feat(note_actions): integrate editability menu into new layout 2025-12-10 18:58:46 +02:00
Elian Doran
9262f94190 feat(note_actions): integrate template switch into new layout 2025-12-10 18:43:34 +02:00
Elian Doran
b36a0bd10b feat(note_actions): integrate shared switch into new layout 2025-12-10 18:40:56 +02:00
Elian Doran
2dc8948f33 chore(breadcrumb_badges): chagne icon for shared locally 2025-12-10 18:35:29 +02:00
Elian Doran
9f2ed2f9d4 feat(widgets/toggle): disable transitions on first render 2025-12-10 18:33:29 +02:00
Elian Doran
e0f7d65f77 feat(widgets): toggle from label 2025-12-10 18:24:31 +02:00
Elian Doran
f18ac3a923 feat(note_actions): integrate bookmark into new layout 2025-12-10 18:20:36 +02:00
Elian Doran
b39a6bcc97 feat(widgets): prevent clicks in toggle from dismissing menu 2025-12-10 18:17:39 +02:00
Elian Doran
8fa9c25f2a feat(widgets): menu item with toggle 2025-12-10 18:07:38 +02:00
Elian Doran
84bde62e05 New layout improvements (#8012) 2025-12-10 17:50:31 +02:00
Elian Doran
5bb4621097 chore(layout): address requested changes 2025-12-10 17:42:08 +02:00
Elian Doran
f1edf84f4d fix(layout): title background for code notes 2025-12-10 17:13:52 +02:00
Elian Doran
f7955a9040 fix(client/dropdown): tooltip flickering due to child elements 2025-12-10 17:02:11 +02:00
Elian Doran
7c5df21685 feat(note_actions): group development options 2025-12-10 16:51:07 +02:00
Elian Doran
2060bb8cdd feat(breadcrumb): show note preview 2025-12-10 16:14:40 +02:00
Elian Doran
a9b4e7b1e2 style(layout): apply heavy padding to title only in normal view 2025-12-10 16:11:17 +02:00
Elian Doran
82528c4478 style(layout): slightly smaller note title in full-height note type 2025-12-10 15:23:42 +02:00
Zexin Yuan
4dcfc3e0bc chore: add dev shell and direnv support 2025-12-10 21:17:11 +08:00
Elian Doran
999315d3c6 feat(breadcrumb): basic rename note support 2025-12-10 15:16:45 +02:00
Elian Doran
aef0b03c34 feat(breadcrumb_row): collapse badges sooner 2025-12-10 13:38:15 +02:00
Elian Doran
49f008c46f feat(breadcrumb_row): improve button fit on constrained width 2025-12-10 13:37:07 +02:00
Elian Doran
bd81db4117 feat(breadcrumb_row): improve badge fit on constrained width 2025-12-10 13:33:33 +02:00
Elian Doran
9f274883e3 feat(breadcrumb_badges): basic shrink support 2025-12-10 13:06:25 +02:00
Elian Doran
07b76b80f4 feat(layout): hide note details in attachment view 2025-12-10 12:52:03 +02:00
Elian Doran
0014f0a88d feat(layout): minor improvements to title/icon alignment 2025-12-10 12:50:05 +02:00
Elian Doran
63f7a78d31 chore(note_actions): use dedicated translation for note revisions 2025-12-10 12:46:23 +02:00
Elian Doran
e556c090ff fix(ribbon): attribute details not shown in new layout 2025-12-10 12:40:06 +02:00
Elian Doran
c4f483c250 feat(options/advanced): automatically refresh 2025-12-10 12:29:12 +02:00
Elian Doran
4031332b98 feat(note_title_details): tooltips for values 2025-12-10 12:25:38 +02:00
Elian Doran
10cb7c8d6a feat(note_title_details): hide creation dates on hidden notes 2025-12-10 12:10:32 +02:00
Elian Doran
be190bfe33 feat(layout): improve layout for full-height notes 2025-12-10 12:06:05 +02:00
Elian Doran
4d7d642952 fix(layout): floating toolbar displayed in attachments 2025-12-10 11:58:17 +02:00
Elian Doran
737711e5eb fix(layout): weird title in full-width & attachments 2025-12-10 11:56:34 +02:00
Elian Doran
42fc128f97 chore(breadcrumb_badges/backlinks): display actual count of backlinks 2025-12-10 11:51:09 +02:00
Elian Doran
b03e6c3b19 chore(breadcrumb_badges/backlinks): display list of backlinks on click 2025-12-10 11:41:14 +02:00
Elian Doran
66008489c4 chore(breadcrumb_badges): fake backlink widget 2025-12-10 11:21:06 +02:00
Elian Doran
3262e3490a feat(breadcrumb_badges): integrate into quick edit 2025-12-10 11:10:26 +02:00
Elian Doran
16a73b0848 fix(popup_editor): wrong margin for title 2025-12-10 11:03:12 +02:00
Elian Doran
52bb4d7a0e feat(breadcrumb_badges): make badge not wrap-around 2025-12-10 09:52:46 +02:00
Elian Doran
40b5e4d549 feat(breadcrumb_badges): proper link handling support 2025-12-10 09:47:05 +02:00
Elian Doran
b014ea8950 feat(breadcrumb_badges): add colors to the badges 2025-12-10 09:38:55 +02:00
Elian Doran
61592716f9 feat(breadcrumb_badges): add tooltips for the badges 2025-12-10 09:27:44 +02:00
Elian Doran
efe7fc0ee7 chore(layout): hide breadcrumb badges if not on new layout 2025-12-10 09:12:57 +02:00
Elian Doran
a810db3641 feat(breadcrumb_badges): display badge when editing is unlocked 2025-12-10 09:11:28 +02:00
Elian Doran
f8b292dfa3 Experimental layout (#8005) 2025-12-09 23:35:15 +02:00
Elian Doran
fc2ab91280 feat(options/advanced): add description for experimental 2025-12-09 23:16:30 +02:00
Elian Doran
668ee219c6 chore(layout): use translation for badges 2025-12-09 23:02:21 +02:00
Elian Doran
ee6512a1a6 refactor(layout): align name for breadcrumb badges 2025-12-09 23:00:41 +02:00
Elian Doran
fe1f590286 chore(layout): use translations for note title details 2025-12-09 23:00:02 +02:00
Elian Doran
876e8f843a chore(layout): use i18n for options 2025-12-09 22:58:16 +02:00
Elian Doran
a45c1a1dc8 chore(layout): fix regressions after merge 2025-12-09 22:57:36 +02:00
Elian Doran
f8377169e6 Merge remote-tracking branch 'origin/main' into feature/new_layout 2025-12-09 22:46:18 +02:00
Elian Doran
a197a33d35 chore(experimental_features): address review 2025-12-09 22:43:39 +02:00
Elian Doran
3060207d04 feat(layout): created & modification date 2025-12-09 22:22:28 +02:00
Elian Doran
28c1d0b3f5 feat(layout): indicate clickable badges 2025-12-09 21:50:38 +02:00
Elian Doran
644d051477 feat(layout): add shared badge 2025-12-09 21:44:39 +02:00
Elian Doran
f42031c8de feat(layout): add icon to the badge 2025-12-09 21:11:30 +02:00
Elian Doran
6b50d9b087 feat(layout): implement read-only badge 2025-12-09 21:06:28 +02:00
Elian Doran
a0f0da64b4 feat(layout): new icon for note actions & fix padding 2025-12-09 20:59:28 +02:00
Elian Doran
1e72ebd104 feat(layout): move revisions button to note actions 2025-12-09 20:48:54 +02:00
Elian Doran
1184a95697 style(layout): missed bottom border in ribbon buttons 2025-12-09 20:44:58 +02:00
Elian Doran
cd0e4a5678 feat(layout): move fixed formatting toolbar above 2025-12-09 20:36:48 +02:00
Elian Doran
394f6c3110 feat(layout): respect content width for title 2025-12-09 20:22:31 +02:00
Elian Doran
e2b6d0c256 feat(layout): move the note title into the scrollable region 2025-12-09 20:09:06 +02:00
Elian Doran
fe7ca210dd feat(layout): move the note actions into the breadcrumb area 2025-12-09 20:05:42 +02:00
Elian Doran
e58d6bf2a3 feat(layout): reverse the layout of the ribbon 2025-12-09 19:51:53 +02:00
Elian Doran
460d20d6b2 feat(layout): move ribbon to the bottom as experimental layout 2025-12-09 19:42:37 +02:00
Elian Doran
ae154212fe feat(client/server): basic support for experimental features 2025-12-09 19:34:03 +02:00
Elian Doran
28bb4edbac chore(layout): revert work on floating panel 2025-12-09 19:18:48 +02:00
Elian Doran
1ceed1b47b chore(layout): revert work on floating panel 2025-12-09 19:11:27 +02:00
Elian Doran
9445e64c2e Translations update from Hosted Weblate (#8004) 2025-12-09 17:49:32 +02:00
Matheus Fongaro (MatioZG)
e6fba03ba7 Translated using Weblate (Portuguese (Brazil))
Currently translated at 3.2% (5 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/pt_BR/
2025-12-09 16:16:40 +01:00
green
b027ca5c09 Translated using Weblate (Japanese)
Currently translated at 100.0% (1646 of 1646 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-09 16:16:39 +01:00
Elian Doran
e98df30500 fix(popup-editor): broken title bar layout 2025-12-09 17:16:29 +02:00
Elian Doran
111c44dadf fix(content_header): z-index issues 2025-12-09 17:11:28 +02:00
Elian Doran
cb31c25e6c fix(content_header): note icon dropdown broken when scrolling 2025-12-09 17:08:03 +02:00
Elian Doran
5d59c953c2 fix(layout): title row background in settings 2025-12-09 16:39:31 +02:00
Elian Doran
a2cff42981 fix(layout): scrollbar design in code note 2025-12-09 16:31:47 +02:00
Elian Doran
cae892a971 fix(layout): title not visible on dark code theme 2025-12-09 16:27:19 +02:00
Elian Doran
f8447d923e feat(ribbon): hide when in options 2025-12-09 16:22:03 +02:00
Elian Doran
3b8dabc9d2 Back/forward navigation in tab bar (#8003) 2025-12-09 16:11:17 +02:00
Elian Doran
cda39e967c chore(tab_navigation): address requested changes 2025-12-09 16:02:24 +02:00
Elian Doran
7da9367dc9 fix(tab_navigation): affecting server and mobile views 2025-12-09 15:59:15 +02:00
Elian Doran
82d97ef26f feat(tab_navigation): hide buttons if launcher ones are used 2025-12-09 15:30:46 +02:00
Elian Doran
9e094f1d96 feat(tab_navigation): add it to horizontal layout as well 2025-12-09 15:14:13 +02:00
Elian Doran
da7e15c268 refactor(tab_navigation): sort imports 2025-12-09 15:06:54 +02:00
Elian Doran
24806a810c feat(tab_navigation): display note icon in history navigation 2025-12-09 15:02:52 +02:00
Elian Doran
a2ace4510a Translations update from Hosted Weblate (#8000) 2025-12-09 15:00:26 +02:00
Elian Doran
5c8132088f feat(client): use chevrons to display note path 2025-12-09 14:49:19 +02:00
Elian Doran
7ee060b228 feat(tab_navigation): improve indicator for current item in context menu 2025-12-09 14:41:17 +02:00
Elian Doran
4b2a4b8f7b feat(tab_navigation): reflect state of history by disabling the buttons 2025-12-09 14:29:45 +02:00
Elian Doran
5a668ede01 chore(tab_navigation): reintroduce history cleaning 2025-12-09 14:24:39 +02:00
Elian Doran
9e099444b6 feat(tab_navigation): functional context menu 2025-12-09 14:23:06 +02:00
Elian Doran
e3f5b3535a feat(tab_navigation): functional back/forward buttons 2025-12-09 14:10:11 +02:00
Elian Doran
346ad1e8a3 feat(tab_navigation): add the buttons on vertical layout 2025-12-09 14:06:57 +02:00
Elian Doran
2a9558e9c5 style(ribbon): make icons slightly bigger 2025-12-09 13:18:25 +02:00
Hosted Weblate
c324f66aef 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-12-09 12:15:20 +01:00
Elian Doran
e688f2cdb6 Add breadcrumbs to navigation (#7995) 2025-12-09 13:15:03 +02:00
Elian Doran
2ff8762a22 chore(client): fix typecheck 2025-12-09 13:07:41 +02:00
Elian Doran
4d75221938 chore(breadcrumbs): address requested changes 2025-12-09 12:41:54 +02:00
Elian Doran
658b699b71 fix(collections/geomap): fake floating buttons mispositioned 2025-12-09 12:24:28 +02:00
Elian Doran
72b0d03546 chore(layout): remove some title margins 2025-12-09 12:23:05 +02:00
Elian Doran
19980807f2 style(ribbon): fix some alignment issues & decrease button size 2025-12-09 12:20:27 +02:00
Elian Doran
3514e3d057 fix(floating_buttons): wrong position when at the top of the note 2025-12-09 11:46:16 +02:00
Elian Doran
fb6c82740c chore(ribbon): remove top transition completely 2025-12-09 11:38:04 +02:00
Elian Doran
8df5a010c9 fix(ribbon): note buttons cut off 2025-12-09 11:36:00 +02:00
Elian Doran
895e9b8bf0 chore(client/layout): reduce transitions 2025-12-09 11:30:18 +02:00
Elian Doran
bfcf85e0d2 fix(client/layout): content header height not properly resized when switching notes 2025-12-09 11:27:05 +02:00
Elian Doran
5770222304 fix(client/floating_buttons): clipped by floating content header 2025-12-09 11:08:28 +02:00
Elian Doran
d5d2815bdf fix(client/floating_buttons): clipped by ribbon 2025-12-09 09:20:31 +02:00
Elian Doran
7fc3d413e5 fix(client): 1px scroll in full-height note 2025-12-09 09:13:18 +02:00
Elian Doran
474228b630 style(client): remove bottom border & box-shadow for content header 2025-12-09 08:22:51 +02:00
Elian Doran
0805e077a1 feat(ribbon): basic implementation for scroll pinning 2025-12-09 08:18:27 +02:00
Elian Doran
6b059a9a75 feat(ribbon): context menu for root item 2025-12-09 08:01:52 +02:00
Elian Doran
7377e4e34d chore(ribbon): improve paddings slightly 2025-12-09 07:58:59 +02:00
Elian Doran
6fac947d9c chore(ribbon): address requested changes 2025-12-09 07:50:21 +02:00
Elian Doran
5973e5ca26 chore(ribbon): remove label for the root entirely 2025-12-09 07:46:46 +02:00
Elian Doran
6570a55e7e Translations update from Hosted Weblate (#7993) 2025-12-08 23:56:13 +02:00
Elian Doran
608ab53933 chore(ribbon): reduce note title padding 2025-12-08 23:41:17 +02:00
Elian Doran
05679f7a8d feat(ribbon): prototype sticky ribbon 2025-12-08 23:33:55 +02:00
noobhjy
f4838bb3b5 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.1% (115 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/zh_Hans/
2025-12-08 21:21:24 +00:00
pythaac
edb2a65196 Translated using Weblate (Korean)
Currently translated at 61.8% (94 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ko/
2025-12-08 21:21:23 +00:00
Hosted Weblate
fd721cac51 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-12-08 21:21:23 +00:00
pythaac
a1ff3cc8f7 Translated using Weblate (Korean)
Currently translated at 57.2% (87 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ko/
2025-12-08 21:21:21 +00:00
Adorian Doran
3fa6b264e5 style/note colors: include the original custom color 2025-12-08 23:18:14 +02:00
Elian Doran
fcf51ec6da chore(eslint): apply to .tsx as well 2025-12-08 23:14:09 +02:00
Elian Doran
d15b5f8cbc style(next): basic styling of ribbon as a floating toolbar 2025-12-08 23:13:58 +02:00
Elian Doran
ef3cbcac6d refactor(breadcrumb): fix eslint issues 2025-12-08 23:09:00 +02:00
Elian Doran
b16893c4d2 feat(breadcrumb): collapse items if the list is too big 2025-12-08 23:03:31 +02:00
Elian Doran
a365814aaa feat(breadcrumb): improve overflow slightly 2025-12-08 22:54:31 +02:00
Elian Doran
eca2116adc feat(breadcrumb): make the root note clickable 2025-12-08 22:46:04 +02:00
Elian Doran
4cfa403657 feat(breadcrumb): apply ellipsis to dropdown 2025-12-08 22:40:37 +02:00
Elian Doran
70ded4c2cd chore(breadcrumb): use bold for highlighting active entry 2025-12-08 22:38:06 +02:00
Elian Doran
3fe45db6ef feat(breadcrumb): improve overflow support 2025-12-08 22:17:49 +02:00
Elian Doran
11467775b6 feat(breadcrumb): basic overflow support 2025-12-08 22:09:46 +02:00
Elian Doran
1e5fcf635e feat(breadcrumb): show root title if it's the one active 2025-12-08 22:05:09 +02:00
Elian Doran
223ba4643f fix(breadcrumb): breadcrumb shown if there are no children 2025-12-08 21:57:51 +02:00
Elian Doran
200fd76929 feat(breadcrumb): display a checkbox for the current note 2025-12-08 21:52:36 +02:00
Elian Doran
c5c4ecd6e6 feat(breadcrumb): show current item 2025-12-08 17:04:08 +02:00
Elian Doran
bedca9f82c feat(breadcrumb): hide root icon 2025-12-08 16:45:26 +02:00
Elian Doran
adc356eff3 fix(breadcrumb): navigation on first level not working 2025-12-08 16:41:06 +02:00
Elian Doran
c4285772b3 feat(breadcrumb): basic navigation in separator 2025-12-08 16:34:40 +02:00
Elian Doran
a02235f2bd feat(breadcrumb): set up dropdown 2025-12-08 16:03:12 +02:00
Elian Doran
5f215b14c2 feat(breadcrumb): start implementing interactive breadcrumbs 2025-12-08 16:01:34 +02:00
Elian Doran
6e29fe8d58 feat(breadcrumb): hide preview 2025-12-08 15:56:03 +02:00
Elian Doran
43ceb1982d feat(breadcrumb): hide last note 2025-12-08 15:53:17 +02:00
Elian Doran
d02ec47d77 feat(breadcrumb): get breadcrumb to render 2025-12-08 15:16:06 +02:00
Elian Doran
9942950710 feat(layout): relocate title into scrollable region 2025-12-08 14:54:57 +02:00
Elian Doran
a6682be251 fix(webview): layout issues when when no webviewSrc 2025-12-08 14:21:59 +02:00
Elian Doran
baee2cd6b2 chore(scripts): add proper typechecking 2025-12-08 14:13:18 +02:00
Elian Doran
3ee8eac635 chore(readme): order languages alphabetically 2025-12-08 14:13:17 +02:00
Elian Doran
ce5a775160 Translations update from Hosted Weblate (#7991) 2025-12-08 13:22:19 +02:00
Elian Doran
2cf66d1c53 Delete CNAME 2025-12-08 12:59:39 +02:00
Hosted Weblate
eaee67d742 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-12-08 11:59:30 +01:00
Elian Doran
c681496b1b chore(readme): fix links to old docs 2025-12-08 12:58:48 +02:00
Elian Doran
829d3e046d chore(readme): fix links to docs 2025-12-08 12:51:07 +02:00
Elian Doran
5c8df540db chore(readme): fix language switcher links (closes #7246) 2025-12-08 12:43:00 +02:00
Elian Doran
8920e6e448 chore(readme): disable translation for language switcher 2025-12-08 12:00:30 +02:00
Elian Doran
3cb860232e Translations update from Hosted Weblate (#7990) 2025-12-08 11:57:43 +02:00
Hosted Weblate
d588518ba1 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-12-08 10:55:07 +01:00
Elian Doran
d6f727d17a Translations update from Hosted Weblate (#7989) 2025-12-08 11:54:51 +02:00
Wen QI
82c40302bd Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1646 of 1646 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-12-08 10:53:50 +01:00
Andreas H.
c40c62a247 Translated using Weblate (German)
Currently translated at 99.2% (1634 of 1646 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/de/
2025-12-08 10:53:50 +01:00
Wen QI
8048b5ebca Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 99.4% (1637 of 1646 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hant/
2025-12-08 10:53:49 +01:00
green
03ba43df5d Translated using Weblate (Japanese)
Currently translated at 100.0% (1646 of 1646 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-08 10:53:49 +01:00
Elian Doran
a4b95b45ec chore(readme): rewrite links 2025-12-08 11:52:28 +02:00
Elian Doran
59513962fe chore(readme): add script to copy README into docs 2025-12-08 11:49:12 +02:00
Elian Doran
a201b43cde fix(launch_bar): sync status not correctly rendered 2025-12-08 11:30:33 +02:00
Elian Doran
f98c77bd16 Translations update from Hosted Weblate (#7988) 2025-12-08 09:44:13 +02:00
green
2596359b25 Translated using Weblate (Japanese)
Currently translated at 100.0% (1646 of 1646 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-08 08:30:46 +01:00
minkipark
e0a0263607 Translated using Weblate (Korean)
Currently translated at 3.0% (50 of 1646 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ko/
2025-12-08 08:30:45 +01:00
green
2d3feedb07 Translated using Weblate (Japanese)
Currently translated at 100.0% (152 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ja/
2025-12-08 08:30:45 +01:00
Hosted Weblate
af392fad3d 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-12-08 08:30:44 +01:00
Elian Doran
ef74490c44 chore(deps): update dependency jsonc-eslint-parser to v2.4.2 (#7982) 2025-12-08 09:30:31 +02:00
Elian Doran
b6856e18a8 fix(deps): update dependency katex to v0.16.27 (#7983) 2025-12-08 09:30:08 +02:00
renovate[bot]
de1d4424d9 fix(deps): update dependency katex to v0.16.27 2025-12-08 01:03:42 +00:00
renovate[bot]
5ec45bb575 chore(deps): update dependency jsonc-eslint-parser to v2.4.2 2025-12-08 01:02:52 +00:00
Elian Doran
cb3aced2ed docs(script): clarify originEntity and activeContext 2025-12-07 23:58:02 +02:00
Elian Doran
2f13a1ad21 fix(mind-map): show text in links between nodes on export (#7938) 2025-12-07 23:20:18 +02:00
Elian Doran
045127adee chore(vscode): add errorlens to recommendations 2025-12-07 23:11:07 +02:00
Elian Doran
db1a0c0362 i18n(client): update renamed key 2025-12-07 23:07:30 +02:00
Elian Doran
dcaf91a878 CKEditor stability improvements (#7979) 2025-12-07 22:40:52 +02:00
Elian Doran
a9209f5103 chore(ckeditor/watchdog): accidental comment 2025-12-07 22:32:06 +02:00
Elian Doran
ea613986c2 chore(server): add OpenAPI spec for to-markdown 2025-12-07 22:26:21 +02:00
Elian Doran
1ed46bd47c refactor(server): add validation for HTML/Markdown rendering 2025-12-07 22:24:14 +02:00
Elian Doran
f1ee79e75a refactor(client): inconsistent prefix for messages 2025-12-07 22:23:19 +02:00
Elian Doran
cd27160905 chore(ckeditor/watchdog): fix typecheck issues 2025-12-07 22:09:30 +02:00
Elian Doran
9ddf4a1308 feat(ckeditor/watchdog): ignore model out of bounds (closes #7739) 2025-12-07 22:00:10 +02:00
Elian Doran
a1c5ed9eb5 feat(ckeditor/watchdog): ignore parent check (closes #5776) 2025-12-07 21:59:52 +02:00
Elian Doran
7a4f19eada chore(ckeditor): revert breaking change 2025-12-07 21:34:10 +02:00
Elian Doran
397fb785d6 feat(ckeditor/watchdog): functional copy to clipboard button 2025-12-07 21:21:55 +02:00
Elian Doran
75a1fcc933 chore(dialog): fix mandatory parameter 2025-12-07 21:06:56 +02:00
Elian Doran
292cbf1383 feat(ckeditor/watchdog): add a title to the details screen 2025-12-07 21:03:39 +02:00
Elian Doran
37a14fefb3 feat(ckeditor/watchdog): improve layout of info dialog 2025-12-07 21:01:56 +02:00
Elian Doran
f424633d8c feat(ckeditor/watchdog): improve dialog size 2025-12-07 20:59:53 +02:00
Elian Doran
048258d2d1 feat(toast): improve button layout 2025-12-07 20:59:41 +02:00
Elian Doran
f779108b6c feat(ckeditor/watchdog): add a more details button 2025-12-07 20:40:29 +02:00
Elian Doran
522f3ae0a1 feat(toast): support buttons 2025-12-07 20:39:27 +02:00
Elian Doran
3fc7067c59 feat(dialog): support React nodes in info dialog 2025-12-07 20:39:11 +02:00
Elian Doran
c600e8ef89 feat(ckeditor/watchdog): add a toast to indicate the error 2025-12-07 20:16:34 +02:00
Elian Doran
5ad267fe1b chore(ckeditor): try to disable watchdog timer 2025-12-07 20:09:56 +02:00
Elian Doran
d8b3e438f8 chore(ckeditor): solve a few eslint warnings 2025-12-07 19:46:06 +02:00
Elian Doran
2834af66e9 feat(ckeditor/watchdog): restore focus after crash 2025-12-07 19:36:46 +02:00
Elian Doran
1bbf86fbeb feat(ckeditor/watchdog): use data stored in the spaced update 2025-12-07 19:30:35 +02:00
Elian Doran
f662b95dc9 chore(vscode): remove now unnecessary extension recommendations 2025-12-07 19:03:05 +02:00
Elian Doran
9ad4b725ac chore(eslint): report missing semicolons 2025-12-07 00:42:25 +02:00
Elian Doran
0182c61aec chore(vscode): mark all eslint rules as warnings 2025-12-07 00:42:00 +02:00
Elian Doran
78362535c7 chore(eslint): downgrade import sorting to warning 2025-12-07 00:36:39 +02:00
Elian Doran
ae7b31f343 chore(dx): trim trailing whitespace in CSS 2025-12-07 00:35:28 +02:00
Elian Doran
f16441bba4 Port toast to React (#7975) 2025-12-07 00:34:25 +02:00
Elian Doran
d3f9bb6def chore(toast): address requested changes 2025-12-07 00:33:37 +02:00
Elian Doran
e02440aa59 fix(toast): persistent toasts no longer working 2025-12-07 00:20:56 +02:00
Elian Doran
f1d87c29d3 chore(toast): fix typecheck issues 2025-12-07 00:15:00 +02:00
Elian Doran
21335b1b00 refactor(toast): get rid of autohide 2025-12-07 00:07:43 +02:00
Elian Doran
7463570e76 refactor(toast): rename delay to timeout 2025-12-07 00:06:42 +02:00
Elian Doran
da17a63ef5 refactor(toast): get rid of closeAfter in favor of delay 2025-12-07 00:04:12 +02:00
Elian Doran
eb8f2021cb fix(toast): add fallback if icon doesn't start with bx- 2025-12-06 23:49:56 +02:00
Elian Doran
888ff33be1 fix(toast): missing message icon 2025-12-06 23:46:21 +02:00
Elian Doran
b46850e86e refactor(toast): relocate styles into own file 2025-12-06 23:38:40 +02:00
Elian Doran
f053587f09 chore(toast): port toast to react 2025-12-06 23:37:56 +02:00
Elian Doran
7a3092a23b fix(read-only-bar): button shrinks when window is small 2025-12-06 23:00:57 +02:00
Elian Doran
d95450ae07 feat(client): detect communication errors with Traefik 2025-12-06 22:57:13 +02:00
Elian Doran
230def10fe feat(client): improve error message for HTTP errors 2025-12-06 22:12:06 +02:00
Elian Doran
036f8e49a4 docs(server/proxy): breaking change in Traefik 3.6.4 2025-12-06 21:51:56 +02:00
Elian Doran
4eca8a5640 feat(dx): add a way to run traefik reverse proxy 2025-12-06 21:37:24 +02:00
Elian Doran
08f96a91f3 docs(readme): fix a space 2025-12-06 19:37:25 +02:00
Elian Doran
2e915eccd6 Clean up _regroup (#7970) 2025-12-06 19:27:15 +02:00
Elian Doran
c05c58c82b Merge remote-tracking branch 'origin/main' into chore/cleanup_regroup 2025-12-06 19:18:23 +02:00
Elian Doran
572feed918 chore(regroup): address requested changes 2025-12-06 19:17:56 +02:00
Elian Doran
d30d207ab5 test(server): solve some local timeouts 2025-12-06 19:08:19 +02:00
Elian Doran
2a6b91dd04 chore(regroup): reintroduce code coverage 2025-12-06 19:08:03 +02:00
Elian Doran
3dee1725b3 chore(regroup): reintroduce old e2e tests 2025-12-06 18:54:38 +02:00
Elian Doran
f7ac465e67 chore(eslint): integrate preact config 2025-12-06 15:31:38 +02:00
Elian Doran
912f14549c chore(eslint): integrate playwright e2e 2025-12-06 15:20:05 +02:00
Elian Doran
21079335e7 chore(eslint): remove unnecessary files 2025-12-06 14:58:38 +02:00
Elian Doran
85741240f1 chore(eslint): reintegrate simple import sort 2025-12-06 14:50:41 +02:00
Elian Doran
3df9a87b29 chore(eslint): clean up unnecessary dependency in client 2025-12-06 14:48:00 +02:00
Elian Doran
acd60007ac chore(eslint): integrate formatter config 2025-12-06 14:43:08 +02:00
Elian Doran
f66c9630e3 chore(deps): update dependency vite to v7.2.6 (#7951) 2025-12-06 12:25:52 +02:00
Elian Doran
50a5892a31 chore(deps): update typescript-eslint monorepo to v8.48.1 (#7953) 2025-12-06 12:25:14 +02:00
renovate[bot]
c5f58437b1 chore(deps): update typescript-eslint monorepo to v8.48.1 2025-12-06 10:10:32 +00:00
Elian Doran
a915424d9a chore(deps): update softprops/action-gh-release action to v2.5.0 (#7958) 2025-12-06 12:10:09 +02:00
renovate[bot]
be7699c600 chore(deps): update dependency vite to v7.2.6 2025-12-06 10:09:14 +00:00
Elian Doran
a7c946ddae fix(deps): update codemirror themes (#7955) 2025-12-06 12:08:43 +02:00
Elian Doran
4b741a9434 chore(deps): update dependency openai to v6.10.0 (#7957) 2025-12-06 12:07:52 +02:00
Elian Doran
cd963272d4 chore(deps): update vitest monorepo to v4.0.15 (#7954) 2025-12-06 12:07:11 +02:00
Elian Doran
9de17ead91 Translations update from Hosted Weblate (#7966) 2025-12-06 12:05:21 +02:00
pythaac
d98b133d63 Translated using Weblate (Korean)
Currently translated at 52.6% (80 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ko/
2025-12-06 11:04:27 +01:00
Elian Doran
361e8e0066 chore(deps): update dependency electron to v39 (#7536) 2025-12-06 12:04:20 +02:00
Elian Doran
523c44b796 fix(deps): update dependency mermaid to v11.12.2 (#7956) 2025-12-06 11:53:14 +02:00
Elian Doran
4bd60ed6a1 chore(deps): update react monorepo to v19.2.1 (#7952) 2025-12-06 11:52:11 +02:00
Elian Doran
7d57f08baf chore(deps): update dependency express to v5.2.1 (#7950) 2025-12-06 11:35:10 +02:00
Elian Doran
5e7f54dbc3 chore(deps): update dependency esbuild to v0.27.1 (#7949) 2025-12-06 11:34:36 +02:00
Elian Doran
dfb9ce990d chore(eslint): basic config 2025-12-06 11:05:34 +02:00
Elian Doran
e87a368e87 chore(regroup): remove some redundant files 2025-12-06 10:52:41 +02:00
Elian Doran
44506057fd chore(regroup): clean bin dir 2025-12-06 10:50:42 +02:00
Elian Doran
ff08eadb23 fix(server/scripts): generate-document failing (closes #5422) 2025-12-06 10:49:14 +02:00
Elian Doran
ebb1a3feb2 chore(regroup): integrate generate_document 2025-12-06 10:35:57 +02:00
Elian Doran
81bc85b8e4 chore(regroup): adapt export-schema script 2025-12-06 10:29:08 +02:00
Elian Doran
4a749f52e9 chore(regroup): remove old release scripts 2025-12-06 10:11:28 +02:00
Elian Doran
25e37ddd78 chore(regroup): relocate icon scripts 2025-12-06 10:07:23 +02:00
renovate[bot]
46a9cfcc67 chore(deps): update react monorepo to v19.2.1 2025-12-06 08:00:01 +00:00
Elian Doran
66ff944660 chore(deps): update dependency @types/reveal.js to v5.2.2 (#7948) 2025-12-06 09:58:15 +02:00
Elian Doran
988db59197 chore(deps): update dependency @smithy/middleware-retry to v4.4.14 (#7947) 2025-12-06 09:57:54 +02:00
Elian Doran
34e321407a chore(deps): update dependency @redocly/cli to v2.12.3 (#7946) 2025-12-06 09:57:31 +02:00
Elian Doran
44c0028a51 chore(regroup): clean up translation scripts 2025-12-06 09:43:54 +02:00
Elian Doran
264b75cd68 chore(regroup): clean up migration scripts 2025-12-06 09:43:02 +02:00
renovate[bot]
cf9ccdcab6 chore(deps): update dependency electron to v39 2025-12-06 07:36:35 +00:00
renovate[bot]
48e18e533c chore(deps): update dependency openai to v6.10.0 2025-12-06 07:35:53 +00:00
renovate[bot]
12ef778bf4 fix(deps): update dependency mermaid to v11.12.2 2025-12-06 07:35:15 +00:00
Elian Doran
6c31a1788a Port launch bar to React (#7934) 2025-12-06 09:35:06 +02:00
renovate[bot]
aa7c6da8ef fix(deps): update codemirror themes 2025-12-06 07:34:30 +00:00
renovate[bot]
1ff40cace0 chore(deps): update vitest monorepo to v4.0.15 2025-12-06 07:33:52 +00:00
renovate[bot]
0a1dadbea1 chore(deps): update dependency express to v5.2.1 2025-12-06 07:30:48 +00:00
renovate[bot]
24edbdba5e chore(deps): update dependency esbuild to v0.27.1 2025-12-06 07:30:09 +00:00
renovate[bot]
db504eff88 chore(deps): update dependency @types/reveal.js to v5.2.2 2025-12-06 07:29:26 +00:00
renovate[bot]
5e09925659 chore(deps): update dependency @smithy/middleware-retry to v4.4.14 2025-12-06 07:28:42 +00:00
renovate[bot]
d1b2b351c8 chore(deps): update dependency @redocly/cli to v2.12.3 2025-12-06 07:28:02 +00:00
Elian Doran
50b0dc178e chore(regroup): clean up old ETAPI tests
They are already integrated in apps/server/spec/etapi.
2025-12-06 09:27:56 +02:00
Elian Doran
b34118e395 fix(deps): update ckeditor monorepo to v47.3.0 (#7959) 2025-12-06 09:26:03 +02:00
Elian Doran
e6436f9021 fix(text): code block background not correct 2025-12-06 09:16:20 +02:00
Elian Doran
831d1b4f3a chore(text): remove workaround for superscript icon 2025-12-06 09:15:40 +02:00
renovate[bot]
0456d1ca29 fix(deps): update ckeditor monorepo to v47.3.0 2025-12-06 07:04:27 +00:00
Elian Doran
fcd151022e fix(deps): update dependency i18next to v25.7.1 (#7960) 2025-12-06 08:59:19 +02:00
Elian Doran
0c1998002e fix(deps): update dependency preact to v10.28.0 (#7961) 2025-12-06 08:58:33 +02:00
Elian Doran
b8c33ce7fa e2e(server): locator failing due to removal of "visible" 2025-12-06 08:54:35 +02:00
Elian Doran
454cd633e8 fix(read_only_text): missing padding in <pre> without <code> 2025-12-06 08:46:44 +02:00
renovate[bot]
53cb9a6e10 fix(deps): update dependency preact to v10.28.0 2025-12-06 06:43:06 +00:00
renovate[bot]
8d6ff763d6 fix(deps): update dependency i18next to v25.7.1 2025-12-06 06:42:29 +00:00
Elian Doran
ecf15af3a0 fix(deps): update dependency react-i18next to v16.4.0 (#7962) 2025-12-06 08:38:20 +02:00
Elian Doran
716823789d chore(deps): update apple-actions/import-codesign-certs action to v6 (#7963) 2025-12-06 08:37:58 +02:00
Elian Doran
3c192badce chore(deps): update dependency @anthropic-ai/sdk to v0.71.2 (#7945) 2025-12-06 08:37:04 +02:00
renovate[bot]
d94b611d10 chore(deps): update apple-actions/import-codesign-certs action to v6 2025-12-06 02:54:20 +00:00
renovate[bot]
e2ce329b6c fix(deps): update dependency react-i18next to v16.4.0 2025-12-06 02:54:16 +00:00
renovate[bot]
ef902fc706 chore(deps): update softprops/action-gh-release action to v2.5.0 2025-12-06 02:51:28 +00:00
renovate[bot]
a7fc94c303 chore(deps): update dependency @anthropic-ai/sdk to v0.71.2 2025-12-06 02:42:34 +00:00
Elian Doran
c8c6d1bb1e docs(user): document launch bar widgets 2025-12-05 23:24:18 +02:00
Elian Doran
a205108681 chore(react/launch_bar): address requested changes 2025-12-05 22:57:07 +02:00
Elian Doran
31561879b3 chore(launch_bar): address requested changes 2025-12-05 19:40:36 +02:00
Elian Doran
fdb6677153 chore(launch_bar): reintroduce keyboard shortcuts 2025-12-05 19:23:40 +02:00
Elian Doran
17241be4bc fix(launch_bar): note context not properly set for legacy widgets 2025-12-05 18:01:46 +02:00
Elian Doran
3bf6de9c76 fix(launch_bar): calendar month selector dropdown wrongly positioned 2025-12-05 17:36:04 +02:00
Elian Doran
a53322e7cb refactor(launch_bar): deduplicate launcher note props 2025-12-05 17:16:55 +02:00
Elian Doran
a107c126e4 fix(launch_bar): dynamic dropdown not repositioning 2025-12-05 17:11:53 +02:00
Elian Doran
3a8dcae53a fix(launch_bar): wrong position of dropdown 2025-12-05 16:45:38 +02:00
Elian Doran
b99d4532df fix(react): duplicate tooltips on focus vs hover 2025-12-05 16:39:55 +02:00
Elian Doran
6e8f8ea357 fix(launch_bar): horizontal launch bar scrolling with dropdown open 2025-12-05 15:53:17 +02:00
Elian Doran
83838bbe76 fix(launch_bar): calendar month selector not actually working 2025-12-05 15:50:25 +02:00
Elian Doran
66620aabe2 fix(launch_bar): calendar dropdown hiding on month selection 2025-12-05 15:43:44 +02:00
Elian Doran
74fcf8270d chore(launch_bar): improve positioning of the month dropdown 2025-12-05 15:31:14 +02:00
Elian Doran
91b4e32a38 fix(launch_bar): calendar month selector clipped 2025-12-05 15:29:25 +02:00
Elian Doran
3f0c114f24 fix(launch_bar): handle week number wrap-around for next year in calendar 2025-12-05 15:17:51 +02:00
Elian Doran
30fe6b93c4 chore(launch_bar): remove now redundant file 2025-12-05 15:10:48 +02:00
Elian Doran
ec99242314 fix(launch_bar): dropdown tooltip visible when hovering popup 2025-12-05 15:06:55 +02:00
Elian Doran
9149fb7a85 fix(launch_bar): tooltip error for dropdowns 2025-12-05 15:02:13 +02:00
Elian Doran
3c919d9a8a fix(launch_bar): global menu size 2025-12-05 14:52:57 +02:00
Elian Doran
22f9ce1e2e Merge remote-tracking branch 'origin/main' into react/launch_bar 2025-12-05 12:22:36 +02:00
Elian Doran
72b01cec70 Merge branch 'stable' 2025-12-05 12:22:14 +02:00
Elian Doran
57b8bc2645 feat(launch_bar): faster tooltips 2025-12-05 12:12:02 +02:00
Elian Doran
3ad4ca3943 fix(launch_bar): bootstrap tooltip for dropdown 2025-12-05 12:06:53 +02:00
Elian Doran
237ffeff52 fix(launch_bar): title position of action buttons 2025-12-05 12:04:26 +02:00
Elian Doran
fb491d9790 Fix (NoteMap): map overflows when switching type in ribbon (#7939) 2025-12-05 11:59:08 +02:00
Elian Doran
facd03b6ad feat(launch_bar): horizontal scroll using mouse wheel 2025-12-05 11:54:31 +02:00
Elian Doran
f5f38ca670 refactor(widgets): relocate AI chat button 2025-12-05 11:53:38 +02:00
Elian Doran
83e599f0e9 refactor(widgets): relocate note launcher & command button 2025-12-05 11:52:52 +02:00
Elian Doran
48cd06f37e feat(bundle): improve error handling message 2025-12-05 11:49:09 +02:00
Elian Doran
aac9d2d1c4 fix(toast): icon missing for error messages 2025-12-05 11:45:02 +02:00
Elian Doran
7e2e1c12b9 chore(widgets): fix error icon in toast & improve message reporting 2025-12-05 11:42:56 +02:00
Elian Doran
3410dd4eba chore(react/launch_bar): bring back reporting widget that failed 2025-12-05 11:40:50 +02:00
Elian Doran
d511085db3 chore(react/launch_bar): port launcher container & launcher 2025-12-05 11:31:52 +02:00
Elian Doran
caaa3583a7 chore(react/launch_bar): port sync status 2025-12-05 10:22:34 +02:00
Elian Doran
185e5691a4 chore(react/launch_bar): bring back week highlighting 2025-12-05 09:52:46 +02:00
Elian Doran
20f44cc64f chore(react/launch_bar): reimplement week notes 2025-12-05 09:36:21 +02:00
SiriusXT
07ef94afd9 Merge branch 'main' into fix/note_map 2025-12-05 15:21:30 +08:00
SiriusXT
2d33b8a958 fix(note_map): initialize map state when switching map type in ribbon 2025-12-05 15:21:06 +08:00
Elian Doran
d283f5dbb4 chore(react/launch_bar): hide dropdown when selecting date 2025-12-05 09:15:01 +02:00
Elian Doran
1af76c4d06 chore(react/launch_bar): clicking on calendar days 2025-12-05 09:11:50 +02:00
Elian Doran
07498c6bef chore(react/launch_bar): add link to existing days 2025-12-05 09:02:51 +02:00
Elian Doran
18f9ebbc4f chore(react/launch_bar): reintroduce day highlighting 2025-12-05 08:56:35 +02:00
SiriusXT
85b4f652f4 chore(note_map): improve the icon for expanding/collapsing the map 2025-12-05 11:21:44 +08:00
SiriusXT
eec6f7336c fix (note_map): map overflows when switching map type in ribbon 2025-12-05 11:21:33 +08:00
Lucas
f976dd8d30 Apply suggestions from code review
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-12-04 13:08:28 -08:00
Lucas
2d3aa3a96e Merge branch 'main' into main 2025-12-04 13:04:24 -08:00
Elian Doran
1195cbd772 Translations update from Hosted Weblate (#7937) 2025-12-04 22:59:00 +02:00
Hosted Weblate
cebfa674ef 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-12-04 21:56:39 +01:00
Elian Doran
3ed596496d Merge branch 'main' of github.com:TriliumNext/Trilium 2025-12-04 22:56:20 +02:00
Elian Doran
d99ef78348 fix(client): find and replace in floating toolbar 2025-12-04 22:56:15 +02:00
lzinga
2666c1e196 feat(snapdom): update screenshot generation options for SVG and PNG exports 2025-12-04 12:52:01 -08:00
Lucas
4b8c8888ee Merge branch 'TriliumNext:main' into main 2025-12-04 12:49:37 -08:00
lzinga
ce1fd64aa9 feat(export): enhance SVG and PNG export functionality with snapdom integration 2025-12-04 12:49:10 -08:00
Elian Doran
bd1479b14a Translations update from Hosted Weblate (#7935) 2025-12-04 22:32:47 +02:00
Elian Doran
baee9520d1 Apply suggestion from @gemini-code-assist[bot]
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-12-04 22:32:08 +02:00
green
adb30a526e Translated using Weblate (Japanese)
Currently translated at 100.0% (1636 of 1636 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2025-12-04 21:27:44 +01:00
noobhjy
60c40457fc Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1636 of 1636 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2025-12-04 21:27:43 +01:00
noobhjy
a6df457c9c Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (1636 of 1636 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hant/
2025-12-04 21:27:42 +01:00
Francis C.
3fd8fb0308 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (1636 of 1636 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hant/
2025-12-04 21:27:41 +01:00
Elian Doran
7d4a7d4ab6 feat(dev): option to crash CKEditor 2025-12-04 22:15:13 +02:00
Elian Doran
4571b95683 chore(react/launch_bar): fix style for month selector 2025-12-04 21:37:02 +02:00
Elian Doran
a65d2a1bba chore(react/launch_bar): reintroduce year selector 2025-12-04 21:24:35 +02:00
lzinga
5c9503732d fix(mind-map): show text in links between nodes on export 2025-12-04 11:08:44 -08:00
Elian Doran
2dbbf7f350 chore(react/launch_bar): reintroduce month dropdown 2025-12-04 20:13:46 +02:00
Elian Doran
e1cce220b3 chore(react/launch_bar): add back icons for previous/next month 2025-12-04 19:56:44 +02:00
Elian Doran
e0aed26f63 refactor(react/launch_bar): extract calendar impl into single file 2025-12-04 19:46:25 +02:00
Elian Doran
62fd07258e chore(react/launch_bar): get days of the week to render 2025-12-04 19:43:47 +02:00
Elian Doran
0d8127140f chore(react/launch_bar): get week numbers to render 2025-12-04 19:38:56 +02:00
Elian Doran
bab5326d7c refactor(react/launch_bar): use different mechanism for gathering calendar info 2025-12-04 19:22:28 +02:00
Elian Doran
5c8445f3fe chore(react/launch_bar): get calendar to render days 2025-12-04 19:03:28 +02:00
Elian Doran
604488b166 chore(react/launch_bar): port custom widget 2025-12-04 17:55:38 +02:00
Elian Doran
b7d7fc8b67 chore(react/launch_bar): remove an old file 2025-12-04 17:17:41 +02:00
Elian Doran
1f4872f72b chore(react/launch_bar): port script launcher 2025-12-04 17:16:47 +02:00
Elian Doran
f89c40cde6 fix(react/launch_bar): type error in bookmarks 2025-12-04 17:07:13 +02:00
Elian Doran
670edbc22a chore(react/launch_bar): port quick search launcher 2025-12-04 17:01:35 +02:00
Elian Doran
54f70c8158 chore(react/launch_bar): port today launcher 2025-12-04 16:53:05 +02:00
Elian Doran
0d6bcba023 chore(react/launch_bar): port note launcher 2025-12-04 16:33:58 +02:00
Elian Doran
06a9f95979 chore(react/launch_bar): remove old file 2025-12-04 16:23:14 +02:00
Elian Doran
03cdfc259e refactor(react/launch_bar): deduplicate launcher icon and title 2025-12-04 16:22:46 +02:00
Elian Doran
1963b5732a refactor(react/launch_bar): extract note launcher from bookmark button 2025-12-04 16:13:16 +02:00
Elian Doran
1e05dc937c refactor(react/launch_bar): port command buttons 2025-12-04 16:04:14 +02:00
Elian Doran
c3b22ff737 refactor(react/launch_bar): port protected session status widget 2025-12-04 15:54:27 +02:00
Elian Doran
991f07e148 refactor(react/launch_bar): port ai chat button 2025-12-04 15:47:42 +02:00
Elian Doran
8efb849391 refactor(react/launch_bar): port history navigation 2025-12-04 15:44:10 +02:00
Elian Doran
5b310f3e46 refactor(react/launch_bar): port spacer 2025-12-04 15:02:46 +02:00
Elian Doran
5f54e42a43 refactor(react/launch_bar): extract icon class 2025-12-04 14:47:30 +02:00
Elian Doran
a83f20e454 refactor(react/launch_bar): extract dropdown & button style 2025-12-04 14:46:23 +02:00
Elian Doran
cdab86bd83 chore(react/launch_bar): port bookmark_folder 2025-12-04 14:41:07 +02:00
Elian Doran
48cbb80e79 chore(react/launch_bar): port open_note_button_widget 2025-12-04 14:18:04 +02:00
Elian Doran
1af6200655 chore(react/launch_bar): get launch bar to render React widgets 2025-12-04 13:24:47 +02:00
Elian Doran
b8585594cd fix(text): duplicate search dialogs (closes #5735) 2025-12-04 13:03:08 +02:00
431 changed files with 23000 additions and 12096 deletions

View File

@@ -1,6 +1,6 @@
root = true root = true
[*.{js,ts,tsx}] [*.{js,ts,tsx,css}]
charset = utf-8 charset = utf-8
end_of_line = lf end_of_line = lf
indent_size = 4 indent_size = 4

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

View File

@@ -21,7 +21,7 @@ runs:
# Certificate setup # Certificate setup
- name: Import Apple certificates - name: Import Apple certificates
if: inputs.os == 'macos' if: inputs.os == 'macos'
uses: apple-actions/import-codesign-certs@v5 uses: apple-actions/import-codesign-certs@v6
with: with:
p12-file-base64: ${{ env.APPLE_APP_CERTIFICATE_BASE64 }} p12-file-base64: ${{ env.APPLE_APP_CERTIFICATE_BASE64 }}
p12-password: ${{ env.APPLE_APP_CERTIFICATE_PASSWORD }} p12-password: ${{ env.APPLE_APP_CERTIFICATE_PASSWORD }}
@@ -30,7 +30,7 @@ runs:
- name: Install Installer certificate - name: Install Installer certificate
if: inputs.os == 'macos' if: inputs.os == 'macos'
uses: apple-actions/import-codesign-certs@v5 uses: apple-actions/import-codesign-certs@v6
with: with:
p12-file-base64: ${{ env.APPLE_INSTALLER_CERTIFICATE_BASE64 }} p12-file-base64: ${{ env.APPLE_INSTALLER_CERTIFICATE_BASE64 }}
p12-password: ${{ env.APPLE_INSTALLER_CERTIFICATE_PASSWORD }} p12-password: ${{ env.APPLE_INSTALLER_CERTIFICATE_PASSWORD }}

View File

@@ -86,12 +86,12 @@ jobs:
- name: Upload Playwright trace - name: Upload Playwright trace
if: failure() if: failure()
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
with: with:
name: Playwright trace (${{ matrix.dockerfile }}) name: Playwright trace (${{ matrix.dockerfile }})
path: test-output/playwright/output path: test-output/playwright/output
- uses: actions/upload-artifact@v5 - uses: actions/upload-artifact@v6
if: ${{ !cancelled() }} if: ${{ !cancelled() }}
with: with:
name: Playwright report (${{ matrix.dockerfile }}) name: Playwright report (${{ matrix.dockerfile }})
@@ -213,7 +213,7 @@ jobs:
touch "/tmp/digests/${digest#sha256:}" touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest - name: Upload digest
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
with: with:
name: digests-${{ env.PLATFORM_PAIR }}-${{ matrix.dockerfile }} name: digests-${{ env.PLATFORM_PAIR }}-${{ matrix.dockerfile }}
path: /tmp/digests/* path: /tmp/digests/*
@@ -227,7 +227,7 @@ jobs:
- build - build
steps: steps:
- name: Download digests - name: Download digests
uses: actions/download-artifact@v6 uses: actions/download-artifact@v7
with: with:
path: /tmp/digests path: /tmp/digests
pattern: digests-* pattern: digests-*

View File

@@ -90,7 +90,7 @@ jobs:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }} GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
- name: Publish release - name: Publish release
uses: softprops/action-gh-release@v2.4.2 uses: softprops/action-gh-release@v2.5.0
if: ${{ github.event_name != 'pull_request' }} if: ${{ github.event_name != 'pull_request' }}
with: with:
make_latest: false make_latest: false
@@ -102,7 +102,7 @@ jobs:
name: Nightly Build name: Nightly Build
- name: Publish artifacts - name: Publish artifacts
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
if: ${{ github.event_name == 'pull_request' }} if: ${{ github.event_name == 'pull_request' }}
with: with:
name: TriliumNotes ${{ matrix.os.name }} ${{ matrix.arch }} name: TriliumNotes ${{ matrix.os.name }} ${{ matrix.arch }}
@@ -131,7 +131,7 @@ jobs:
arch: ${{ matrix.arch }} arch: ${{ matrix.arch }}
- name: Publish release - name: Publish release
uses: softprops/action-gh-release@v2.4.2 uses: softprops/action-gh-release@v2.5.0
if: ${{ github.event_name != 'pull_request' }} if: ${{ github.event_name != 'pull_request' }}
with: with:
make_latest: false make_latest: false

View File

@@ -77,7 +77,7 @@ jobs:
- name: Upload test report - name: Upload test report
if: failure() if: failure()
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
with: with:
name: e2e report ${{ matrix.arch }} name: e2e report ${{ matrix.arch }}
path: apps/server-e2e/test-output path: apps/server-e2e/test-output

View File

@@ -73,7 +73,7 @@ jobs:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }} GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
- name: Upload the artifact - name: Upload the artifact
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
with: with:
name: release-desktop-${{ matrix.os.name }}-${{ matrix.arch }} name: release-desktop-${{ matrix.os.name }}-${{ matrix.arch }}
path: apps/desktop/upload/*.* path: apps/desktop/upload/*.*
@@ -100,7 +100,7 @@ jobs:
arch: ${{ matrix.arch }} arch: ${{ matrix.arch }}
- name: Upload the artifact - name: Upload the artifact
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
with: with:
name: release-server-linux-${{ matrix.arch }} name: release-server-linux-${{ matrix.arch }}
path: upload/*.* path: upload/*.*
@@ -120,14 +120,14 @@ jobs:
docs/Release Notes docs/Release Notes
- name: Download all artifacts - name: Download all artifacts
uses: actions/download-artifact@v6 uses: actions/download-artifact@v7
with: with:
merge-multiple: true merge-multiple: true
pattern: release-* pattern: release-*
path: upload path: upload
- name: Publish stable release - name: Publish stable release
uses: softprops/action-gh-release@v2.4.2 uses: softprops/action-gh-release@v2.5.0
with: with:
draft: false draft: false
body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md

2
.gitignore vendored
View File

@@ -44,8 +44,10 @@ upload
.rollup.cache .rollup.cache
*.tsbuildinfo *.tsbuildinfo
/.direnv
/result /result
.svelte-kit .svelte-kit
# docs # docs
site/ site/
apps/*/coverage

2
.nvmrc
View File

@@ -1 +1 @@
24.11.1 24.12.0

View File

@@ -9,7 +9,6 @@
"tobermory.es6-string-html", "tobermory.es6-string-html",
"vitest.explorer", "vitest.explorer",
"yzhang.markdown-all-in-one", "yzhang.markdown-all-in-one",
"svelte.svelte-vscode", "usernamehw.errorlens"
"bradlc.vscode-tailwindcss"
] ]
} }

View File

@@ -36,5 +36,11 @@
"docs/**/*.png": true, "docs/**/*.png": true,
"apps/server/src/assets/doc_notes/**": true, "apps/server/src/assets/doc_notes/**": true,
"apps/edit-docs/demo/**": true "apps/edit-docs/demo/**": true
} },
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.rules.customizations": [
{ "rule": "*", "severity": "warn" }
]
} }

View File

@@ -16,13 +16,14 @@
![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/triliumnext/trilium/total) ![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/triliumnext/trilium/total)
[![RelativeCI](https://badges.relative-ci.com/badges/Di5q7dz9daNDZ9UXi0Bp?branch=develop)](https://app.relative-ci.com/projects/Di5q7dz9daNDZ9UXi0Bp) [![Translation status](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted.weblate.org/engage/trilium/) [![RelativeCI](https://badges.relative-ci.com/badges/Di5q7dz9daNDZ9UXi0Bp?branch=develop)](https://app.relative-ci.com/projects/Di5q7dz9daNDZ9UXi0Bp) [![Translation status](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted.weblate.org/engage/trilium/)
[English](./README.md) | [Chinese (Simplified)](./docs/README-ZH_CN.md) | [Chinese (Traditional)](./docs/README-ZH_TW.md) | [Russian](./docs/README-ru.md) | [Japanese](./docs/README-ja.md) | [Italian](./docs/README-it.md) | [Spanish](./docs/README-es.md) <!-- translate:off -->
<!-- LANGUAGE SWITCHER -->
[Chinese (Simplified Han script)](./docs/README-ZH_CN.md) | [Chinese (Traditional Han script)](./docs/README-ZH_TW.md) | [English](./docs/README.md) | [French](./docs/README-fr.md) | [German](./docs/README-de.md) | [Greek](./docs/README-el.md) | [Italian](./docs/README-it.md) | [Japanese](./docs/README-ja.md) | [Romanian](./docs/README-ro.md) | [Spanish](./docs/README-es.md)
<!-- translate:on -->
Trilium Notes is a free and open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases. Trilium Notes is a free and open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases.
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for quick overview: <img src="./docs/app.png" alt="Trilium Screenshot" width="1000">
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download ## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest) stable version, recommended for most users. - [Latest release](https://github.com/TriliumNext/Trilium/releases/latest) stable version, recommended for most users.
@@ -39,39 +40,39 @@ Our documentation is available in multiple formats:
### Quick Links ### Quick Links
- [Getting Started Guide](https://docs.triliumnotes.org/) - [Getting Started Guide](https://docs.triliumnotes.org/)
- [Installation Instructions](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation.md) - [Installation Instructions](https://docs.triliumnotes.org/user-guide/setup)
- [Docker Setup](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation/1.%20Installing%20the%20server/Using%20Docker.md) - [Docker Setup](https://docs.triliumnotes.org/user-guide/setup/server/installation/docker)
- [Upgrading TriliumNext](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Upgrading%20TriliumNext.md) - [Upgrading TriliumNext](https://docs.triliumnotes.org/user-guide/setup/upgrading)
- [Basic Concepts and Features](./docs/User%20Guide/User%20Guide/Basic%20Concepts%20and%20Features/Notes.md) - [Basic Concepts and Features](https://docs.triliumnotes.org/user-guide/concepts/notes)
- [Patterns of Personal Knowledge Base](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge) - [Patterns of Personal Knowledge Base](https://docs.triliumnotes.org/user-guide/misc/patterns-of-personal-knowledge)
## 🎁 Features ## 🎁 Features
* Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://triliumnext.github.io/Docs/Wiki/cloning-notes)) * Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://docs.triliumnotes.org/user-guide/concepts/notes/cloning))
* Rich WYSIWYG note editor including e.g. tables, images and [math](https://triliumnext.github.io/Docs/Wiki/text-notes) with markdown [autoformat](https://triliumnext.github.io/Docs/Wiki/text-notes#autoformat) * Rich WYSIWYG note editor including e.g. tables, images and [math](https://docs.triliumnotes.org/user-guide/note-types/text) with markdown [autoformat](https://docs.triliumnotes.org/user-guide/note-types/text/markdown-formatting)
* Support for editing [notes with source code](https://triliumnext.github.io/Docs/Wiki/code-notes), including syntax highlighting * Support for editing [notes with source code](https://docs.triliumnotes.org/user-guide/note-types/code), including syntax highlighting
* Fast and easy [navigation between notes](https://triliumnext.github.io/Docs/Wiki/note-navigation), full text search and [note hoisting](https://triliumnext.github.io/Docs/Wiki/note-hoisting) * Fast and easy [navigation between notes](https://docs.triliumnotes.org/user-guide/concepts/navigation/note-navigation), full text search and [note hoisting](https://docs.triliumnotes.org/user-guide/concepts/navigation/note-hoisting)
* Seamless [note versioning](https://triliumnext.github.io/Docs/Wiki/note-revisions) * Seamless [note versioning](https://docs.triliumnotes.org/user-guide/concepts/notes/note-revisions)
* Note [attributes](https://triliumnext.github.io/Docs/Wiki/attributes) can be used for note organization, querying and advanced [scripting](https://triliumnext.github.io/Docs/Wiki/scripts) * Note [attributes](https://docs.triliumnotes.org/user-guide/advanced-usage/attributes) can be used for note organization, querying and advanced [scripting](https://docs.triliumnotes.org/user-guide/scripts)
* UI available in English, German, Spanish, French, Romanian, and Chinese (simplified and traditional) * UI available in English, German, Spanish, French, Romanian, and Chinese (simplified and traditional)
* Direct [OpenID and TOTP integration](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Server%20Installation/Multi-Factor%20Authentication.md) for more secure login * Direct [OpenID and TOTP integration](https://docs.triliumnotes.org/user-guide/setup/server/mfa) for more secure login
* [Synchronization](https://triliumnext.github.io/Docs/Wiki/synchronization) with self-hosted sync server * [Synchronization](https://docs.triliumnotes.org/user-guide/setup/synchronization) with self-hosted sync server
* there's a [3rd party service for hosting synchronisation server](https://trilium.cc/paid-hosting) * there are [3rd party services for hosting synchronisation server](https://docs.triliumnotes.org/user-guide/setup/server/cloud-hosting)
* [Sharing](https://triliumnext.github.io/Docs/Wiki/sharing) (publishing) notes to public internet * [Sharing](https://docs.triliumnotes.org/user-guide/advanced-usage/sharing) (publishing) notes to public internet
* Strong [note encryption](https://triliumnext.github.io/Docs/Wiki/protected-notes) with per-note granularity * Strong [note encryption](https://docs.triliumnotes.org/user-guide/concepts/notes/protected-notes) with per-note granularity
* Sketching diagrams, based on [Excalidraw](https://excalidraw.com/) (note type "canvas") * Sketching diagrams, based on [Excalidraw](https://excalidraw.com/) (note type "canvas")
* [Relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map) and [link maps](https://triliumnext.github.io/Docs/Wiki/link-map) for visualizing notes and their relations * [Relation maps](https://docs.triliumnotes.org/user-guide/note-types/relation-map) and [note/link maps](https://docs.triliumnotes.org/user-guide/note-types/note-map) for visualizing notes and their relations
* Mind maps, based on [Mind Elixir](https://docs.mind-elixir.com/) * Mind maps, based on [Mind Elixir](https://docs.mind-elixir.com/)
* [Geo maps](./docs/User%20Guide/User%20Guide/Note%20Types/Geo%20Map.md) with location pins and GPX tracks * [Geo maps](https://docs.triliumnotes.org/user-guide/collections/geomap) with location pins and GPX tracks
* [Scripting](https://triliumnext.github.io/Docs/Wiki/scripts) - see [Advanced showcases](https://triliumnext.github.io/Docs/Wiki/advanced-showcases) * [Scripting](https://docs.triliumnotes.org/user-guide/scripts) - see [Advanced showcases](https://docs.triliumnotes.org/user-guide/advanced-usage/advanced-showcases)
* [REST API](https://triliumnext.github.io/Docs/Wiki/etapi) for automation * [REST API](https://docs.triliumnotes.org/user-guide/advanced-usage/etapi) for automation
* Scales well in both usability and performance upwards of 100 000 notes * Scales well in both usability and performance upwards of 100 000 notes
* Touch optimized [mobile frontend](https://triliumnext.github.io/Docs/Wiki/mobile-frontend) for smartphones and tablets * Touch optimized [mobile frontend](https://docs.triliumnotes.org/user-guide/setup/mobile-frontend) for smartphones and tablets
* Built-in [dark theme](https://triliumnext.github.io/Docs/Wiki/themes), support for user themes * Built-in [dark theme](https://docs.triliumnotes.org/user-guide/concepts/themes), support for user themes
* [Evernote](https://triliumnext.github.io/Docs/Wiki/evernote-import) and [Markdown import & export](https://triliumnext.github.io/Docs/Wiki/markdown) * [Evernote](https://docs.triliumnotes.org/user-guide/concepts/import-export/evernote) and [Markdown import & export](https://docs.triliumnotes.org/user-guide/concepts/import-export/markdown)
* [Web Clipper](https://triliumnext.github.io/Docs/Wiki/web-clipper) for easy saving of web content * [Web Clipper](https://docs.triliumnotes.org/user-guide/setup/web-clipper) for easy saving of web content
* Customizable UI (sidebar buttons, user-defined widgets, ...) * Customizable UI (sidebar buttons, user-defined widgets, ...)
* [Metrics](./docs/User%20Guide/User%20Guide/Advanced%20Usage/Metrics.md), along with a [Grafana Dashboard](./docs/User%20Guide/User%20Guide/Advanced%20Usage/Metrics/grafana-dashboard.json) * [Metrics](https://docs.triliumnotes.org/user-guide/advanced-usage/metrics), along with a Grafana Dashboard.
✨ Check out the following third-party resources/communities for more TriliumNext related goodies: ✨ Check out the following third-party resources/communities for more TriliumNext related goodies:
@@ -131,7 +132,7 @@ Note: It is best to disable automatic updates on your server installation (see b
### Server ### Server
To install TriliumNext on your own server (including via Docker from [Dockerhub](https://hub.docker.com/r/triliumnext/trilium)) follow [the server installation docs](https://triliumnext.github.io/Docs/Wiki/server-installation). To install TriliumNext on your own server (including via Docker from [Dockerhub](https://hub.docker.com/r/triliumnext/trilium)) follow [the server installation docs](https://docs.triliumnotes.org/user-guide/setup/server).
## 💻 Contribute ## 💻 Contribute
@@ -198,7 +199,7 @@ Trilium would not be possible without the technologies behind it:
* [Leaflet](https://github.com/Leaflet/Leaflet) - for rendering geographical maps. * [Leaflet](https://github.com/Leaflet/Leaflet) - for rendering geographical maps.
* [Tabulator](https://github.com/olifolkerd/tabulator) - for the interactive table used in collections. * [Tabulator](https://github.com/olifolkerd/tabulator) - for the interactive table used in collections.
* [FancyTree](https://github.com/mar10/fancytree) - feature-rich tree library without real competition. * [FancyTree](https://github.com/mar10/fancytree) - feature-rich tree library without real competition.
* [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library. Used in [relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map.html) and [link maps](https://triliumnext.github.io/Docs/Wiki/note-map.html#link-map) * [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library. Used in [relation maps](https://docs.triliumnotes.org/user-guide/note-types/relation-map) and [link maps](https://docs.triliumnotes.org/user-guide/advanced-usage/note-map#link-map)
## 🤝 Support ## 🤝 Support

View File

@@ -1,7 +0,0 @@
#!/usr/bin/env node
import anonymizationService from "../src/services/anonymization.js";
import fs from "fs";
import path from "path";
fs.writeFileSync(path.resolve(__dirname, "tpl", "anonymize-database.sql"), anonymizationService.getFullAnonymizationScript());

View File

@@ -1,7 +0,0 @@
#!/usr/bin/env bash
SCHEMA_FILE_PATH=db/schema.sql
sqlite3 ./data/document.db .schema | grep -v "sqlite_sequence" > "$SCHEMA_FILE_PATH"
echo "DB schema exported to $SCHEMA_FILE_PATH"

View File

@@ -1,16 +0,0 @@
#!/usr/bin/env bash
if [[ $# -eq 0 ]] ; then
echo "Missing argument of new version"
exit 1
fi
VERSION=$1
SERIES=${VERSION:0:4}-latest
docker push zadam/trilium:$VERSION
docker push zadam/trilium:$SERIES
if [[ $1 != *"beta"* ]]; then
docker push zadam/trilium:latest
fi

View File

@@ -1,57 +0,0 @@
#!/usr/bin/env bash
if [[ $# -eq 0 ]] ; then
echo "Missing argument of new version"
exit 1
fi
VERSION=$1
if ! [[ ${VERSION} =~ ^[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}(-.+)?$ ]] ;
then
echo "Version ${VERSION} isn't in format X.Y.Z"
exit 1
fi
VERSION_DATE=$(git log -1 --format=%aI "v${VERSION}" | cut -c -10)
VERSION_COMMIT=$(git rev-list -n 1 "v${VERSION}")
# expecting the directory at a specific path
cd ~/trilium-flathub || exit
if ! git diff-index --quiet HEAD --; then
echo "There are uncommitted changes"
exit 1
fi
BASE_BRANCH=main
if [[ "$VERSION" == *"beta"* ]]; then
BASE_BRANCH=beta
fi
git switch "${BASE_BRANCH}"
git pull
BRANCH=b${VERSION}
git branch "${BRANCH}"
git switch "${BRANCH}"
echo "Updating files with version ${VERSION}, date ${VERSION_DATE} and commit ${VERSION_COMMIT}"
flatpak-node-generator npm ../trilium/package-lock.json
xmlstarlet ed --inplace --update "/component/releases/release/@version" --value "${VERSION}" --update "/component/releases/release/@date" --value "${VERSION_DATE}" ./com.github.zadam.trilium.metainfo.xml
yq --inplace "(.modules[0].sources[0].tag = \"v${VERSION}\") | (.modules[0].sources[0].commit = \"${VERSION_COMMIT}\")" ./com.github.zadam.trilium.yml
git add ./generated-sources.json
git add ./com.github.zadam.trilium.metainfo.xml
git add ./com.github.zadam.trilium.yml
git commit -m "release $VERSION"
git push --set-upstream origin "${BRANCH}"
gh pr create --fill -B "${BASE_BRANCH}"
gh pr merge --auto --merge --delete-branch

View File

@@ -1,49 +0,0 @@
#!/usr/bin/env bash
set -e
if [[ $# -eq 0 ]] ; then
echo "Missing argument of new version"
exit 1
fi
if ! command -v jq &> /dev/null; then
echo "Missing command: jq"
exit 1
fi
VERSION=$1
if ! [[ ${VERSION} =~ ^[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}(-.+)?$ ]] ;
then
echo "Version ${VERSION} isn't in format X.Y.Z"
exit 1
fi
if ! git diff-index --quiet HEAD --; then
echo "There are uncommitted changes"
exit 1
fi
echo "Releasing Trilium $VERSION"
jq '.version = "'$VERSION'"' package.json > package.json.tmp
mv package.json.tmp package.json
git add package.json
npm run chore:update-build-info
git add src/services/build.ts
TAG=v$VERSION
echo "Committing package.json version change"
git commit -m "chore(release): $VERSION"
git push
echo "Tagging commit with $TAG"
git tag $TAG
git push origin $TAG

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>

View File

@@ -1,51 +0,0 @@
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import simpleImportSort from "eslint-plugin-simple-import-sort";
export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.recommended,
// consider using rules below, once we have a full TS codebase and can be more strict
// tseslint.configs.strictTypeChecked,
// tseslint.configs.stylisticTypeChecked,
// tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname
}
}
},
{
plugins: {
"simple-import-sort": simpleImportSort
}
},
{
rules: {
// add rule overrides here
"no-undef": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
],
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error"
}
},
{
ignores: [
"build/*",
"dist/*",
"docs/*",
"demo/*",
"src/public/app-dist/*",
"src/public/app/doc_notes/*"
]
}
);

View File

@@ -1,47 +0,0 @@
import stylistic from "@stylistic/eslint-plugin";
import tsParser from "@typescript-eslint/parser";
// eslint config just for formatting rules
// potentially to be merged with the linting rules into one single config,
// once we have fixed the majority of lint errors
// Go to https://eslint.style/rules/default/${rule_without_prefix} to check the rule details
export const stylisticRules = {
"@stylistic/indent": [ "error", 4 ],
"@stylistic/quotes": [ "error", "double", { avoidEscape: true, allowTemplateLiterals: "always" } ],
"@stylistic/semi": [ "error", "always" ],
"@stylistic/quote-props": [ "error", "consistent-as-needed" ],
"@stylistic/max-len": [ "error", { code: 100 } ],
"@stylistic/comma-dangle": [ "error", "never" ],
"@stylistic/linebreak-style": [ "error", "unix" ],
"@stylistic/array-bracket-spacing": [ "error", "always" ],
"@stylistic/object-curly-spacing": [ "error", "always" ],
"@stylistic/padded-blocks": [ "error", { classes: "always" } ]
};
export default [
{
files: [ "**/*.{js,ts,mjs,cjs}" ],
languageOptions: {
parser: tsParser
},
plugins: {
"@stylistic": stylistic
},
rules: {
...stylisticRules
}
},
{
ignores: [
"build/*",
"dist/*",
"docs/*",
"demo/*",
// TriliumNextTODO: check if we want to format packages here as well - for now skipping it
"packages/*",
"src/public/app-dist/*",
"src/public/app/doc_notes/*"
]
}
];

View File

@@ -1,17 +0,0 @@
import { test as setup, expect } from "@playwright/test";
const authFile = "playwright/.auth/user.json";
const ROOT_URL = "http://localhost:8082";
const LOGIN_PASSWORD = "demo1234";
// Reference: https://playwright.dev/docs/auth#basic-shared-account-in-all-tests
setup("authenticate", async ({ page }) => {
await page.goto(ROOT_URL);
await expect(page).toHaveURL(`${ROOT_URL}/login`);
await page.getByRole("textbox", { name: "Password" }).fill(LOGIN_PASSWORD);
await page.getByRole("button", { name: "Login" }).click();
await page.context().storageState({ path: authFile });
});

View File

@@ -1,9 +0,0 @@
import { test, expect } from "@playwright/test";
test("Can duplicate note with broken links", async ({ page }) => {
await page.goto(`http://localhost:8082/#2VammGGdG6Ie`);
await page.locator(".tree-wrapper .fancytree-active").getByText("Note map").click({ button: "right" });
await page.getByText("Duplicate subtree").click();
await expect(page.locator(".toast-body")).toBeHidden();
await expect(page.locator(".tree-wrapper").getByText("Note map (dup)")).toBeVisible();
});

View File

@@ -1,18 +0,0 @@
import { test, expect } from "@playwright/test";
test("has title", async ({ page }) => {
await page.goto("https://playwright.dev/");
// Expect a title "to contain" a substring.
await expect(page).toHaveTitle(/Playwright/);
});
test("get started link", async ({ page }) => {
await page.goto("https://playwright.dev/");
// Click the get started link.
await page.getByRole("link", { name: "Get started" }).click();
// Expects page to have a heading with the name of Installation.
await expect(page.getByRole("heading", { name: "Installation" })).toBeVisible();
});

View File

@@ -1,21 +0,0 @@
import test, { expect } from "@playwright/test";
test("Native Title Bar not displayed on web", async ({ page }) => {
await page.goto("http://localhost:8082/#root/_hidden/_options/_optionsAppearance");
await expect(page.getByRole("heading", { name: "Theme" })).toBeVisible();
await expect(page.getByRole("heading", { name: "Native Title Bar (requires" })).toBeHidden();
});
test("Tray settings not displayed on web", async ({ page }) => {
await page.goto("http://localhost:8082/#root/_hidden/_options/_optionsOther");
await expect(page.getByRole("heading", { name: "Note Erasure Timeout" })).toBeVisible();
await expect(page.getByRole("heading", { name: "Tray" })).toBeHidden();
});
test("Spellcheck settings not displayed on web", async ({ page }) => {
await page.goto("http://localhost:8082/#root/_hidden/_options/_optionsSpellcheck");
await expect(page.getByRole("heading", { name: "Spell Check" })).toBeVisible();
await expect(page.getByRole("heading", { name: "Tray" })).toBeHidden();
await expect(page.getByText("These options apply only for desktop builds")).toBeVisible();
await expect(page.getByText("Enable spellcheck")).toBeHidden();
});

View File

@@ -1,18 +0,0 @@
import test, { expect } from "@playwright/test";
test("Renders on desktop", async ({ page, context }) => {
await page.goto("http://localhost:8082");
await expect(page.locator(".tree")).toContainText("Trilium Integration Test");
});
test("Renders on mobile", async ({ page, context }) => {
await context.addCookies([
{
url: "http://localhost:8082",
name: "trilium-device",
value: "mobile"
}
]);
await page.goto("http://localhost:8082");
await expect(page.locator(".tree")).toContainText("Trilium Integration Test");
});

View File

@@ -1,12 +0,0 @@
import { test, expect } from "@playwright/test";
const expectedVersion = "0.90.3";
test("Displays update badge when there is a version available", async ({ page }) => {
await page.goto("http://localhost:8080");
await page.getByRole("button", { name: "" }).click();
await page.getByText(`Version ${expectedVersion} is available,`).click();
const page1 = await page.waitForEvent("popup");
expect(page1.url()).toBe(`https://github.com/TriliumNext/Trilium/releases/tag/v${expectedVersion}`);
});

View File

@@ -1,56 +0,0 @@
{
"main": "./electron-main.js",
"bin": {
"trilium": "src/main.js"
},
"type": "module",
"scripts": {
"server:start-safe": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev nodemon src/main.ts",
"server:start-no-dir": "cross-env TRILIUM_ENV=dev nodemon src/main.ts",
"server:start-test": "npm run server:switch && rimraf ./data-test && cross-env TRILIUM_DATA_DIR=./data-test TRILIUM_ENV=dev TRILIUM_PORT=9999 nodemon src/main.ts",
"server:qstart": "npm run server:switch && npm run server:start",
"server:switch": "rimraf ./node_modules/better-sqlite3 && npm install",
"electron:start-no-dir": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_ENV=dev TRILIUM_PORT=37742 electron --inspect=5858 .",
"electron:start-nix": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./electron-main.ts --inspect=5858 .\"",
"electron:start-nix-no-dir": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_ENV=dev TRILIUM_PORT=37742 nix-shell -p electron_33 --run \"electron ./electron-main.ts --inspect=5858 .\"",
"electron:start-prod-no-dir": "npm run build:prepare-dist && cross-env TRILIUM_ENV=prod electron --inspect=5858 .",
"electron:start-prod-nix": "electron-rebuild --version 33.3.1 && npm run build:prepare-dist && cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./dist/electron-main.js --inspect=5858 .\"",
"electron:start-prod-nix-no-dir": "electron-rebuild --version 33.3.1 && npm run build:prepare-dist && cross-env TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./dist/electron-main.js --inspect=5858 .\"",
"electron:qstart": "npm run electron:switch && npm run electron:start",
"electron:switch": "electron-rebuild",
"docs:build": "typedoc",
"test": "npm run client:test && npm run server:test",
"client:test": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest --root src/public/app",
"client:coverage": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest --root src/public/app --coverage",
"test:playwright": "playwright test --workers 1",
"test:integration-edit-db": "cross-env TRILIUM_INTEGRATION_TEST=edit TRILIUM_PORT=8081 TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
"test:integration-mem-db": "cross-env nodemon src/main.ts",
"test:integration-mem-db-dev": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
"dev:watch-dist": "tsx ./bin/watch-dist.ts",
"dev:format-check": "eslint -c eslint.format.config.js .",
"dev:format-fix": "eslint -c eslint.format.config.js . --fix",
"dev:linter-check": "eslint .",
"dev:linter-fix": "eslint . --fix",
"chore:generate-document": "cross-env nodemon ./bin/generate_document.ts 1000",
"chore:generate-openapi": "tsx bin/generate-openapi.js"
},
"devDependencies": {
"@playwright/test": "1.57.0",
"@stylistic/eslint-plugin": "5.6.1",
"@types/express": "5.0.5",
"@types/node": "24.10.1",
"@types/yargs": "17.0.35",
"@vitest/coverage-v8": "4.0.14",
"eslint": "9.39.1",
"eslint-plugin-simple-import-sort": "12.1.1",
"esm": "3.2.25",
"jsdoc": "4.0.5",
"lorem-ipsum": "2.0.8",
"rcedit": "5.0.2",
"rimraf": "6.1.2",
"tslib": "2.8.1"
},
"optionalDependencies": {
"appdmg": "0.6.6"
}
}

View File

@@ -1,9 +0,0 @@
import etapi from "../support/etapi.js";
/* TriliumNextTODO: port to Vitest
etapi.describeEtapi("app_info", () => {
it("get", async () => {
const appInfo = await etapi.getEtapi("app-info");
expect(appInfo.clipperProtocolVersion).toEqual("1.0");
});
});
*/

View File

@@ -1,10 +0,0 @@
import etapi from "../support/etapi.js";
/* TriliumNextTODO: port to Vitest
etapi.describeEtapi("backup", () => {
it("create", async () => {
const response = await etapi.putEtapiContent("backup/etapi_test");
expect(response.status).toEqual(204);
});
});
*/

View File

@@ -1,26 +0,0 @@
import etapi from "../support/etapi.js";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
/* TriliumNextTODO: port to Vitest
etapi.describeEtapi("import", () => {
// temporarily skip this test since test-export.zip is missing
xit("import", async () => {
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
const zipFileBuffer = fs.readFileSync(path.resolve(scriptDir, "test-export.zip"));
const response = await etapi.postEtapiContent("notes/root/import", zipFileBuffer);
expect(response.status).toEqual(201);
const { note, branch } = await response.json();
expect(note.title).toEqual("test-export");
expect(branch.parentNoteId).toEqual("root");
const content = await (await etapi.getEtapiContent(`notes/${note.noteId}/content`)).text();
expect(content).toContain("test export content");
});
});
*/

View File

@@ -1,103 +0,0 @@
import crypto from "crypto";
import etapi from "../support/etapi.js";
/* TriliumNextTODO: port to Vitest
etapi.describeEtapi("notes", () => {
it("create", async () => {
const { note, branch } = await etapi.postEtapi("create-note", {
parentNoteId: "root",
type: "text",
title: "Hello World!",
content: "Content",
prefix: "Custom prefix"
});
expect(note.title).toEqual("Hello World!");
expect(branch.parentNoteId).toEqual("root");
expect(branch.prefix).toEqual("Custom prefix");
const rNote = await etapi.getEtapi(`notes/${note.noteId}`);
expect(rNote.title).toEqual("Hello World!");
const rContent = await (await etapi.getEtapiContent(`notes/${note.noteId}/content`)).text();
expect(rContent).toEqual("Content");
const rBranch = await etapi.getEtapi(`branches/${branch.branchId}`);
expect(rBranch.parentNoteId).toEqual("root");
expect(rBranch.prefix).toEqual("Custom prefix");
});
it("patch", async () => {
const { note } = await etapi.postEtapi("create-note", {
parentNoteId: "root",
type: "text",
title: "Hello World!",
content: "Content"
});
await etapi.patchEtapi(`notes/${note.noteId}`, {
title: "new title",
type: "code",
mime: "text/apl",
dateCreated: "2000-01-01 12:34:56.999+0200",
utcDateCreated: "2000-01-01 10:34:56.999Z"
});
const rNote = await etapi.getEtapi(`notes/${note.noteId}`);
expect(rNote.title).toEqual("new title");
expect(rNote.type).toEqual("code");
expect(rNote.mime).toEqual("text/apl");
expect(rNote.dateCreated).toEqual("2000-01-01 12:34:56.999+0200");
expect(rNote.utcDateCreated).toEqual("2000-01-01 10:34:56.999Z");
});
it("update content", async () => {
const { note } = await etapi.postEtapi("create-note", {
parentNoteId: "root",
type: "text",
title: "Hello World!",
content: "Content"
});
await etapi.putEtapiContent(`notes/${note.noteId}/content`, "new content");
const rContent = await (await etapi.getEtapiContent(`notes/${note.noteId}/content`)).text();
expect(rContent).toEqual("new content");
});
it("create / update binary content", async () => {
const { note } = await etapi.postEtapi("create-note", {
parentNoteId: "root",
type: "file",
title: "Hello World!",
content: "ZZZ"
});
const updatedContent = crypto.randomBytes(16);
await etapi.putEtapiContent(`notes/${note.noteId}/content`, updatedContent);
const rContent = await (await etapi.getEtapiContent(`notes/${note.noteId}/content`)).arrayBuffer();
expect(Buffer.from(new Uint8Array(rContent))).toEqual(updatedContent);
});
it("delete note", async () => {
const { note } = await etapi.postEtapi("create-note", {
parentNoteId: "root",
type: "text",
title: "Hello World!",
content: "Content"
});
await etapi.deleteEtapi(`notes/${note.noteId}`);
const resp = await etapi.getEtapiResponse(`notes/${note.noteId}`);
expect(resp.status).toEqual(404);
const error = await resp.json();
expect(error.status).toEqual(404);
expect(error.code).toEqual("NOTE_NOT_FOUND");
expect(error.message).toEqual(`Note '${note.noteId}' not found.`);
});
});
*/

View File

@@ -1,152 +0,0 @@
import { describe, beforeAll, afterAll } from "vitest";
let etapiAuthToken: string | undefined;
const getEtapiAuthorizationHeader = (): string => "Basic " + Buffer.from(`etapi:${etapiAuthToken}`).toString("base64");
const PORT: string = "9999";
const HOST: string = "http://localhost:" + PORT;
type SpecDefinitionsFunc = () => void;
function describeEtapi(description: string, specDefinitions: SpecDefinitionsFunc): void {
describe(description, () => {
beforeAll(async () => {});
afterAll(() => {});
specDefinitions();
});
}
async function getEtapiResponse(url: string): Promise<Response> {
return await fetch(`${HOST}/etapi/${url}`, {
method: "GET",
headers: {
Authorization: getEtapiAuthorizationHeader()
}
});
}
async function getEtapi(url: string): Promise<any> {
const response = await getEtapiResponse(url);
return await processEtapiResponse(response);
}
async function getEtapiContent(url: string): Promise<Response> {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: "GET",
headers: {
Authorization: getEtapiAuthorizationHeader()
}
});
checkStatus(response);
return response;
}
async function postEtapi(url: string, data: Record<string, unknown> = {}): Promise<any> {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: getEtapiAuthorizationHeader()
},
body: JSON.stringify(data)
});
return await processEtapiResponse(response);
}
async function postEtapiContent(url: string, data: BodyInit): Promise<Response> {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: "POST",
headers: {
"Content-Type": "application/octet-stream",
Authorization: getEtapiAuthorizationHeader()
},
body: data
});
checkStatus(response);
return response;
}
async function putEtapi(url: string, data: Record<string, unknown> = {}): Promise<any> {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: getEtapiAuthorizationHeader()
},
body: JSON.stringify(data)
});
return await processEtapiResponse(response);
}
async function putEtapiContent(url: string, data?: BodyInit): Promise<Response> {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: "PUT",
headers: {
"Content-Type": "application/octet-stream",
Authorization: getEtapiAuthorizationHeader()
},
body: data
});
checkStatus(response);
return response;
}
async function patchEtapi(url: string, data: Record<string, unknown> = {}): Promise<any> {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
Authorization: getEtapiAuthorizationHeader()
},
body: JSON.stringify(data)
});
return await processEtapiResponse(response);
}
async function deleteEtapi(url: string): Promise<any> {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: "DELETE",
headers: {
Authorization: getEtapiAuthorizationHeader()
}
});
return await processEtapiResponse(response);
}
async function processEtapiResponse(response: Response): Promise<any> {
const text = await response.text();
if (response.status < 200 || response.status >= 300) {
throw new Error(`ETAPI error ${response.status}: ${text}`);
}
return text?.trim() ? JSON.parse(text) : null;
}
function checkStatus(response: Response): void {
if (response.status < 200 || response.status >= 300) {
throw new Error(`ETAPI error ${response.status}`);
}
}
export default {
describeEtapi,
getEtapi,
getEtapiResponse,
getEtapiContent,
postEtapi,
postEtapiContent,
putEtapi,
putEtapiContent,
patchEtapi,
deleteEtapi
};

View File

@@ -1,22 +0,0 @@
{
"compilerOptions": {
"module": "NodeNext",
"declaration": false,
"sourceMap": true,
"outDir": "./build",
"strict": true,
"noImplicitAny": true,
"resolveJsonModule": true,
"lib": ["ES2023"],
"downlevelIteration": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowJs": true
},
"include": ["./src/public/app/**/*"],
"files": [
"./src/public/app/types.d.ts",
"./src/public/app/types-lib.d.ts",
"./src/types.d.ts"
]
}

View File

@@ -9,13 +9,13 @@
"keywords": [], "keywords": [],
"author": "Elian Doran <contact@eliandoran.me>", "author": "Elian Doran <contact@eliandoran.me>",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"packageManager": "pnpm@10.24.0", "packageManager": "pnpm@10.26.1",
"devDependencies": { "devDependencies": {
"@redocly/cli": "2.12.0", "@redocly/cli": "2.14.0",
"archiver": "7.0.1", "archiver": "7.0.1",
"fs-extra": "11.3.2", "fs-extra": "11.3.3",
"react": "19.2.0", "react": "19.2.3",
"react-dom": "19.2.0", "react-dom": "19.2.3",
"typedoc": "0.28.15", "typedoc": "0.28.15",
"typedoc-plugin-missing-exports": "4.1.2" "typedoc-plugin-missing-exports": "4.1.2"
} }

View File

@@ -1,5 +0,0 @@
import baseConfig from "../../eslint.config.mjs";
export default [
...baseConfig
];

View File

@@ -12,10 +12,10 @@
"scripts": { "scripts": {
"build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 vite build", "build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 vite build",
"test": "vitest", "test": "vitest",
"coverage": "vitest --coverage",
"circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular" "circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
}, },
"dependencies": { "dependencies": {
"@eslint/js": "9.39.1",
"@excalidraw/excalidraw": "0.18.0", "@excalidraw/excalidraw": "0.18.0",
"@fullcalendar/core": "6.1.19", "@fullcalendar/core": "6.1.19",
"@fullcalendar/daygrid": "6.1.19", "@fullcalendar/daygrid": "6.1.19",
@@ -27,12 +27,14 @@
"@mermaid-js/layout-elk": "0.2.0", "@mermaid-js/layout-elk": "0.2.0",
"@mind-elixir/node-menu": "5.0.1", "@mind-elixir/node-menu": "5.0.1",
"@popperjs/core": "2.11.8", "@popperjs/core": "2.11.8",
"@preact/signals": "2.5.1",
"@triliumnext/ckeditor5": "workspace:*", "@triliumnext/ckeditor5": "workspace:*",
"@triliumnext/codemirror": "workspace:*", "@triliumnext/codemirror": "workspace:*",
"@triliumnext/commons": "workspace:*", "@triliumnext/commons": "workspace:*",
"@triliumnext/highlightjs": "workspace:*", "@triliumnext/highlightjs": "workspace:*",
"@triliumnext/share-theme": "workspace:*", "@triliumnext/share-theme": "workspace:*",
"@triliumnext/split.js": "workspace:*", "@triliumnext/split.js": "workspace:*",
"@zumer/snapdom": "2.0.1",
"autocomplete.js": "0.38.1", "autocomplete.js": "0.38.1",
"bootstrap": "5.3.8", "bootstrap": "5.3.8",
"boxicons": "2.1.4", "boxicons": "2.1.4",
@@ -42,23 +44,23 @@
"draggabilly": "3.0.0", "draggabilly": "3.0.0",
"force-graph": "1.51.0", "force-graph": "1.51.0",
"globals": "16.5.0", "globals": "16.5.0",
"i18next": "25.6.3", "i18next": "25.7.3",
"i18next-http-backend": "3.0.2", "i18next-http-backend": "3.0.2",
"jquery": "3.7.1", "jquery": "3.7.1",
"jquery.fancytree": "2.38.5", "jquery.fancytree": "2.38.5",
"jsplumb": "2.15.6", "jsplumb": "2.15.6",
"katex": "0.16.25", "katex": "0.16.27",
"knockout": "3.5.1", "knockout": "3.5.1",
"leaflet": "1.9.4", "leaflet": "1.9.4",
"leaflet-gpx": "2.2.0", "leaflet-gpx": "2.2.0",
"mark.js": "8.11.1", "mark.js": "8.11.1",
"marked": "17.0.1", "marked": "17.0.1",
"mermaid": "11.12.1", "mermaid": "11.12.2",
"mind-elixir": "5.3.7", "mind-elixir": "5.3.8",
"normalize.css": "8.0.1", "normalize.css": "8.0.1",
"panzoom": "9.4.3", "panzoom": "9.4.3",
"preact": "10.27.2", "preact": "10.28.0",
"react-i18next": "16.3.5", "react-i18next": "16.5.0",
"reveal.js": "5.2.1", "reveal.js": "5.2.1",
"svg-pan-zoom": "3.6.2", "svg-pan-zoom": "3.6.2",
"tabulator-tables": "6.3.1", "tabulator-tables": "6.3.1",
@@ -72,7 +74,7 @@
"@types/leaflet": "1.9.21", "@types/leaflet": "1.9.21",
"@types/leaflet-gpx": "1.3.8", "@types/leaflet-gpx": "1.3.8",
"@types/mark.js": "8.11.12", "@types/mark.js": "8.11.12",
"@types/reveal.js": "5.2.1", "@types/reveal.js": "5.2.2",
"@types/tabulator-tables": "6.3.0", "@types/tabulator-tables": "6.3.0",
"copy-webpack-plugin": "13.0.1", "copy-webpack-plugin": "13.0.1",
"happy-dom": "20.0.11", "happy-dom": "20.0.11",

View File

@@ -1,39 +1,41 @@
import froca from "../services/froca.js";
import RootCommandExecutor from "./root_command_executor.js";
import Entrypoints from "./entrypoints.js";
import options from "../services/options.js";
import utils, { hasTouchBar } from "../services/utils.js";
import zoomComponent from "./zoom.js";
import TabManager from "./tab_manager.js";
import Component from "./component.js";
import keyboardActionsService from "../services/keyboard_actions.js";
import linkService, { type ViewScope } from "../services/link.js";
import MobileScreenSwitcherExecutor, { type Screen } from "./mobile_screen_switcher.js";
import MainTreeExecutors from "./main_tree_executors.js";
import toast from "../services/toast.js";
import ShortcutComponent from "./shortcut_component.js";
import { t, initLocale } from "../services/i18n.js";
import type { ResolveOptions } from "../widgets/dialogs/delete_notes.js";
import type { PromptDialogOptions } from "../widgets/dialogs/prompt.js";
import type { ConfirmWithMessageOptions, ConfirmWithTitleOptions } from "../widgets/dialogs/confirm.js";
import type LoadResults from "../services/load_results.js";
import type { Attribute } from "../services/attribute_parser.js";
import type NoteTreeWidget from "../widgets/note_tree.js";
import type { default as NoteContext, GetTextEditorCallback } from "./note_context.js";
import type { NativeImage, TouchBar } from "electron";
import TouchBarComponent from "./touch_bar.js";
import type { CKTextEditor } from "@triliumnext/ckeditor5"; import type { CKTextEditor } from "@triliumnext/ckeditor5";
import type CodeMirror from "@triliumnext/codemirror"; import type CodeMirror from "@triliumnext/codemirror";
import { StartupChecks } from "./startup_checks.js";
import type { CreateNoteOpts } from "../services/note_create.js";
import { ColumnComponent } from "tabulator-tables";
import { ChooseNoteTypeCallback } from "../widgets/dialogs/note_type_chooser.jsx";
import type RootContainer from "../widgets/containers/root_container.js";
import { SqlExecuteResults } from "@triliumnext/commons"; import { SqlExecuteResults } from "@triliumnext/commons";
import { AddLinkOpts } from "../widgets/dialogs/add_link.jsx"; import type { NativeImage, TouchBar } from "electron";
import { IncludeNoteOpts } from "../widgets/dialogs/include_note.jsx"; import { ColumnComponent } from "tabulator-tables";
import type { Attribute } from "../services/attribute_parser.js";
import froca from "../services/froca.js";
import { initLocale,t } from "../services/i18n.js";
import keyboardActionsService from "../services/keyboard_actions.js";
import linkService, { type ViewScope } from "../services/link.js";
import type LoadResults from "../services/load_results.js";
import type { CreateNoteOpts } from "../services/note_create.js";
import options from "../services/options.js";
import toast from "../services/toast.js";
import utils, { hasTouchBar } from "../services/utils.js";
import { ReactWrappedWidget } from "../widgets/basic_widget.js"; import { ReactWrappedWidget } from "../widgets/basic_widget.js";
import type RootContainer from "../widgets/containers/root_container.js";
import { AddLinkOpts } from "../widgets/dialogs/add_link.jsx";
import type { ConfirmWithMessageOptions, ConfirmWithTitleOptions } from "../widgets/dialogs/confirm.js";
import type { ResolveOptions } from "../widgets/dialogs/delete_notes.js";
import { IncludeNoteOpts } from "../widgets/dialogs/include_note.jsx";
import type { InfoProps } from "../widgets/dialogs/info.jsx";
import type { MarkdownImportOpts } from "../widgets/dialogs/markdown_import.jsx"; import type { MarkdownImportOpts } from "../widgets/dialogs/markdown_import.jsx";
import { ChooseNoteTypeCallback } from "../widgets/dialogs/note_type_chooser.jsx";
import type { PromptDialogOptions } from "../widgets/dialogs/prompt.js";
import type NoteTreeWidget from "../widgets/note_tree.js";
import Component from "./component.js";
import Entrypoints from "./entrypoints.js";
import MainTreeExecutors from "./main_tree_executors.js";
import MobileScreenSwitcherExecutor, { type Screen } from "./mobile_screen_switcher.js";
import type { default as NoteContext, GetTextEditorCallback } from "./note_context.js";
import RootCommandExecutor from "./root_command_executor.js";
import ShortcutComponent from "./shortcut_component.js";
import { StartupChecks } from "./startup_checks.js";
import TabManager from "./tab_manager.js";
import TouchBarComponent from "./touch_bar.js";
import zoomComponent from "./zoom.js";
interface Layout { interface Layout {
getRootWidget: (appContext: AppContext) => RootContainer; getRootWidget: (appContext: AppContext) => RootContainer;
@@ -124,7 +126,7 @@ export type CommandMappings = {
isNewNote?: boolean; isNewNote?: boolean;
}; };
showPromptDialog: PromptDialogOptions; showPromptDialog: PromptDialogOptions;
showInfoDialog: ConfirmWithMessageOptions; showInfoDialog: InfoProps;
showConfirmDialog: ConfirmWithMessageOptions; showConfirmDialog: ConfirmWithMessageOptions;
showRecentChanges: CommandData & { ancestorNoteId: string }; showRecentChanges: CommandData & { ancestorNoteId: string };
showImportDialog: CommandData & { noteId: string }; showImportDialog: CommandData & { noteId: string };
@@ -264,7 +266,7 @@ export type CommandMappings = {
reEvaluateRightPaneVisibility: CommandData; reEvaluateRightPaneVisibility: CommandData;
runActiveNote: CommandData; runActiveNote: CommandData;
scrollContainerToCommand: CommandData & { scrollContainerTo: CommandData & {
position: number; position: number;
}; };
scrollToEnd: CommandData; scrollToEnd: CommandData;
@@ -446,6 +448,7 @@ type EventMappings = {
}; };
searchRefreshed: { ntxId?: string | null }; searchRefreshed: { ntxId?: string | null };
textEditorRefreshed: { ntxId?: string | null, editor: CKTextEditor }; textEditorRefreshed: { ntxId?: string | null, editor: CKTextEditor };
contentElRefreshed: { ntxId?: string | null, contentEl: HTMLElement };
hoistedNoteChanged: { hoistedNoteChanged: {
noteId: string; noteId: string;
ntxId: string | null; ntxId: string | null;
@@ -694,12 +697,10 @@ $(window).on("beforeunload", () => {
console.log(`Component ${component.componentId} is not finished saving its state.`); console.log(`Component ${component.componentId} is not finished saving its state.`);
allSaved = false; allSaved = false;
} }
} else { } else if (!listener()) {
if (!listener()) {
allSaved = false; allSaved = false;
} }
} }
}
if (!allSaved) { if (!allSaved) {
toast.showMessage(t("app_context.please_wait_for_save"), 10000); toast.showMessage(t("app_context.please_wait_for_save"), 10000);
@@ -707,7 +708,7 @@ $(window).on("beforeunload", () => {
} }
}); });
$(window).on("hashchange", function () { $(window).on("hashchange", () => {
const { notePath, ntxId, viewScope, searchString } = linkService.parseNavigationStateFromUrl(window.location.href); const { notePath, ntxId, viewScope, searchString } = linkService.parseNavigationStateFromUrl(window.location.href);
if (notePath || ntxId) { if (notePath || ntxId) {

View File

@@ -65,8 +65,8 @@ export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
// don't create promises if not needed (optimization) // don't create promises if not needed (optimization)
return callMethodPromise && childrenPromise ? Promise.all([callMethodPromise, childrenPromise]) : callMethodPromise || childrenPromise; return callMethodPromise && childrenPromise ? Promise.all([callMethodPromise, childrenPromise]) : callMethodPromise || childrenPromise;
} catch (e: any) { } catch (e: unknown) {
console.error(`Handling of event '${name}' failed in ${this.constructor.name} with error ${e.message} ${e.stack}`); console.error(`Handling of event '${name}' failed in ${this.constructor.name} with error`, e);
return null; return null;
} }

View File

@@ -1,18 +1,19 @@
import protectedSessionHolder from "../services/protected_session_holder.js";
import server from "../services/server.js";
import utils from "../services/utils.js";
import appContext, { type EventData, type EventListener } from "./app_context.js";
import treeService from "../services/tree.js";
import Component from "./component.js";
import froca from "../services/froca.js";
import hoistedNoteService from "../services/hoisted_note.js";
import options from "../services/options.js";
import type { ViewScope } from "../services/link.js";
import type FNote from "../entities/fnote.js";
import type { CKTextEditor } from "@triliumnext/ckeditor5"; import type { CKTextEditor } from "@triliumnext/ckeditor5";
import type CodeMirror from "@triliumnext/codemirror"; import type CodeMirror from "@triliumnext/codemirror";
import type FNote from "../entities/fnote.js";
import { closeActiveDialog } from "../services/dialog.js"; import { closeActiveDialog } from "../services/dialog.js";
import froca from "../services/froca.js";
import hoistedNoteService from "../services/hoisted_note.js";
import type { ViewScope } from "../services/link.js";
import options from "../services/options.js";
import protectedSessionHolder from "../services/protected_session_holder.js";
import server from "../services/server.js";
import treeService from "../services/tree.js";
import utils from "../services/utils.js";
import { ReactWrappedWidget } from "../widgets/basic_widget.js"; import { ReactWrappedWidget } from "../widgets/basic_widget.js";
import appContext, { type EventData, type EventListener } from "./app_context.js";
import Component from "./component.js";
export interface SetNoteOpts { export interface SetNoteOpts {
triggerSwitchEvent?: unknown; triggerSwitchEvent?: unknown;
@@ -389,7 +390,7 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
* If no content could be determined `null` is returned instead. * If no content could be determined `null` is returned instead.
*/ */
async getContentElement() { async getContentElement() {
return this.timeout<JQuery<HTMLElement>>( return this.timeout<JQuery<HTMLElement> | null>(
new Promise((resolve) => new Promise((resolve) =>
appContext.triggerCommand("executeWithContentElement", { appContext.triggerCommand("executeWithContentElement", {
resolve, resolve,

View File

@@ -1,14 +1,14 @@
import Component from "./component.js";
import appContext, { type CommandData, type CommandListenerData } from "./app_context.js";
import dateNoteService from "../services/date_notes.js"; import dateNoteService from "../services/date_notes.js";
import treeService from "../services/tree.js";
import openService from "../services/open.js";
import protectedSessionService from "../services/protected_session.js";
import options from "../services/options.js";
import froca from "../services/froca.js"; import froca from "../services/froca.js";
import utils from "../services/utils.js";
import toastService from "../services/toast.js";
import noteCreateService from "../services/note_create.js"; import noteCreateService from "../services/note_create.js";
import openService from "../services/open.js";
import options from "../services/options.js";
import protectedSessionService from "../services/protected_session.js";
import toastService from "../services/toast.js";
import treeService from "../services/tree.js";
import utils, { openInReusableSplit } from "../services/utils.js";
import appContext, { type CommandListenerData } from "./app_context.js";
import Component from "./component.js";
export default class RootCommandExecutor extends Component { export default class RootCommandExecutor extends Component {
editReadOnlyNoteCommand() { editReadOnlyNoteCommand() {
@@ -193,6 +193,19 @@ export default class RootCommandExecutor extends Component {
appContext.triggerEvent("zenModeChanged", { isEnabled }); appContext.triggerEvent("zenModeChanged", { isEnabled });
} }
async toggleRibbonTabNoteMapCommand(data: CommandListenerData<"toggleRibbonTabNoteMap">) {
const { isExperimentalFeatureEnabled } = await import("../services/experimental_features.js");
const isNewLayout = isExperimentalFeatureEnabled("new-layout");
if (!isNewLayout) {
this.triggerEvent("toggleRibbonTabNoteMap", data);
return;
}
const activeContext = appContext.tabManager.getActiveContext();
if (!activeContext?.notePath) return;
openInReusableSplit(activeContext.notePath, "note-map");
}
firstTabCommand() { firstTabCommand() {
this.#goToTab(1); this.#goToTab(1);
} }
@@ -262,7 +275,7 @@ export default class RootCommandExecutor extends Component {
} }
catch (e) { catch (e) {
console.error("Error creating AI Chat note:", e); console.error("Error creating AI Chat note:", e);
toastService.showError("Failed to create AI Chat note: " + (e as Error).message); toastService.showError(`Failed to create AI Chat note: ${(e as Error).message}`);
} }
} }
} }

View File

@@ -22,6 +22,7 @@ bundleService.getWidgetBundlesByParent().then(async (widgetBundles) => {
appContext.setLayout(new DesktopLayout(widgetBundles)); appContext.setLayout(new DesktopLayout(widgetBundles));
appContext.start().catch((e) => { appContext.start().catch((e) => {
toastService.showPersistent({ toastService.showPersistent({
id: "critical-error",
title: t("toast.critical-error.title"), title: t("toast.critical-error.title"),
icon: "alert", icon: "alert",
message: t("toast.critical-error.message", { message: e.message }) message: t("toast.critical-error.message", { message: e.message })
@@ -63,6 +64,9 @@ function initOnElectron() {
if (options.get("nativeTitleBarVisible") !== "true") { if (options.get("nativeTitleBarVisible") !== "true") {
initTitleBarButtons(style, currentWindow); initTitleBarButtons(style, currentWindow);
} }
// Clear navigation history on frontend refresh.
currentWindow.webContents.navigationHistory.clear();
} }
function initTitleBarButtons(style: CSSStyleDeclaration, currentWindow: Electron.BrowserWindow) { function initTitleBarButtons(style: CSSStyleDeclaration, currentWindow: Electron.BrowserWindow) {

View File

@@ -1,17 +1,17 @@
import server from "../services/server.js";
import noteAttributeCache from "../services/note_attribute_cache.js";
import protectedSessionHolder from "../services/protected_session_holder.js";
import cssClassManager from "../services/css_class_manager.js"; import cssClassManager from "../services/css_class_manager.js";
import type { Froca } from "../services/froca-interface.js"; import type { Froca } from "../services/froca-interface.js";
import type FAttachment from "./fattachment.js"; import noteAttributeCache from "../services/note_attribute_cache.js";
import type { default as FAttribute, AttributeType } from "./fattribute.js"; import protectedSessionHolder from "../services/protected_session_holder.js";
import utils from "../services/utils.js";
import search from "../services/search.js"; import search from "../services/search.js";
import server from "../services/server.js";
import utils from "../services/utils.js";
import type FAttachment from "./fattachment.js";
import type { AttributeType,default as FAttribute } from "./fattribute.js";
const LABEL = "label"; const LABEL = "label";
const RELATION = "relation"; const RELATION = "relation";
const NOTE_TYPE_ICONS = { export const NOTE_TYPE_ICONS = {
file: "bx bx-file", file: "bx bx-file",
image: "bx bx-image", image: "bx bx-image",
code: "bx bx-code", code: "bx bx-code",
@@ -268,13 +268,12 @@ export default class FNote {
} }
} }
return results; return results;
} else {
return this.children;
} }
return this.children;
} }
async getSubtreeNoteIds(includeArchived = false) { async getSubtreeNoteIds(includeArchived = false) {
let noteIds: (string | string[])[] = []; const noteIds: (string | string[])[] = [];
for (const child of await this.getChildNotes()) { for (const child of await this.getChildNotes()) {
if (child.isArchived && !includeArchived) continue; if (child.isArchived && !includeArchived) continue;
@@ -471,9 +470,8 @@ export default class FNote {
return a.isHidden ? 1 : -1; return a.isHidden ? 1 : -1;
} else if (a.isSearch !== b.isSearch) { } else if (a.isSearch !== b.isSearch) {
return a.isSearch ? 1 : -1; return a.isSearch ? 1 : -1;
} else {
return a.notePath.length - b.notePath.length;
} }
return a.notePath.length - b.notePath.length;
}); });
return notePaths; return notePaths;
@@ -597,14 +595,12 @@ export default class FNote {
} else if (this.type === "text") { } else if (this.type === "text") {
if (this.isFolder()) { if (this.isFolder()) {
return "bx bx-folder"; return "bx bx-folder";
} else {
return "bx bx-note";
} }
return "bx bx-note";
} else if (this.type === "code" && this.mime.startsWith("text/x-sql")) { } else if (this.type === "code" && this.mime.startsWith("text/x-sql")) {
return "bx bx-data"; return "bx bx-data";
} else {
return NOTE_TYPE_ICONS[this.type];
} }
return NOTE_TYPE_ICONS[this.type];
} }
getColorClass() { getColorClass() {
@@ -617,7 +613,7 @@ export default class FNote {
} }
getFilteredChildBranches() { getFilteredChildBranches() {
let childBranches = this.getChildBranches(); const childBranches = this.getChildBranches();
if (!childBranches) { if (!childBranches) {
console.error(`No children for '${this.noteId}'. This shouldn't happen.`); console.error(`No children for '${this.noteId}'. This shouldn't happen.`);
@@ -811,9 +807,9 @@ export default class FNote {
return this.getLabelValue(nameWithPrefix.substring(1)); return this.getLabelValue(nameWithPrefix.substring(1));
} else if (nameWithPrefix.startsWith("~")) { } else if (nameWithPrefix.startsWith("~")) {
return this.getRelationValue(nameWithPrefix.substring(1)); return this.getRelationValue(nameWithPrefix.substring(1));
} else {
return this.getLabelValue(nameWithPrefix);
} }
return this.getLabelValue(nameWithPrefix);
} }
/** /**
@@ -878,10 +874,10 @@ export default class FNote {
promotedAttrs.sort((a, b) => { promotedAttrs.sort((a, b) => {
if (a.noteId === b.noteId) { if (a.noteId === b.noteId) {
return a.position < b.position ? -1 : 1; return a.position < b.position ? -1 : 1;
} else { }
// inherited promoted attributes should stay grouped: https://github.com/zadam/trilium/issues/3761 // inherited promoted attributes should stay grouped: https://github.com/zadam/trilium/issues/3761
return a.noteId < b.noteId ? -1 : 1; return a.noteId < b.noteId ? -1 : 1;
}
}); });
return promotedAttrs; return promotedAttrs;
@@ -993,6 +989,10 @@ export default class FNote {
); );
} }
isJsx() {
return (this.type === "code" && this.mime === "text/jsx");
}
/** @returns true if this note is HTML */ /** @returns true if this note is HTML */
isHtml() { isHtml() {
return (this.type === "code" || this.type === "file" || this.type === "render") && this.mime === "text/html"; return (this.type === "code" || this.type === "file" || this.type === "render") && this.mime === "text/html";
@@ -1000,7 +1000,7 @@ export default class FNote {
/** @returns JS script environment - either "frontend" or "backend" */ /** @returns JS script environment - either "frontend" or "backend" */
getScriptEnv() { getScriptEnv() {
if (this.isHtml() || (this.isJavaScript() && this.mime.endsWith("env=frontend"))) { if (this.isHtml() || (this.isJavaScript() && this.mime.endsWith("env=frontend")) || this.isJsx()) {
return "frontend"; return "frontend";
} }
@@ -1022,7 +1022,7 @@ export default class FNote {
* @returns a promise that resolves when the script has been run. Additionally, for front-end notes, the promise will contain the value that is returned by the script. * @returns a promise that resolves when the script has been run. Additionally, for front-end notes, the promise will contain the value that is returned by the script.
*/ */
async executeScript() { async executeScript() {
if (!this.isJavaScript()) { if (!(this.isJavaScript() || this.isJsx())) {
throw new Error(`Note ${this.noteId} is of type ${this.type} and mime ${this.mime} and thus cannot be executed`); throw new Error(`Note ${this.noteId} is of type ${this.type} and mime ${this.mime} and thus cannot be executed`);
} }

View File

@@ -1,50 +1,59 @@
import { applyModals } from "./layout_commons.js"; import type { AppContext } from "../components/app_context.js";
import { DESKTOP_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx"; import type { WidgetsByParent } from "../services/bundle.js";
import { isExperimentalFeatureEnabled } from "../services/experimental_features.js";
import options from "../services/options.js";
import utils from "../services/utils.js";
import ApiLog from "../widgets/api_log.jsx"; import ApiLog from "../widgets/api_log.jsx";
import ClosePaneButton from "../widgets/buttons/close_pane_button.js"; import ClosePaneButton from "../widgets/buttons/close_pane_button.js";
import CloseZenModeButton from "../widgets/close_zen_button.jsx";
import ContentHeader from "../widgets/containers/content_header.js";
import CreatePaneButton from "../widgets/buttons/create_pane_button.js"; import CreatePaneButton from "../widgets/buttons/create_pane_button.js";
import FindWidget from "../widgets/find.js";
import FlexContainer from "../widgets/containers/flex_container.js";
import FloatingButtons from "../widgets/FloatingButtons.jsx";
import GlobalMenu from "../widgets/buttons/global_menu.jsx"; import GlobalMenu from "../widgets/buttons/global_menu.jsx";
import HighlightsListWidget from "../widgets/highlights_list.js";
import LauncherContainer from "../widgets/containers/launcher_container.js";
import LeftPaneContainer from "../widgets/containers/left_pane_container.js";
import LeftPaneToggle from "../widgets/buttons/left_pane_toggle.js"; import LeftPaneToggle from "../widgets/buttons/left_pane_toggle.js";
import MovePaneButton from "../widgets/buttons/move_pane_button.js"; import MovePaneButton from "../widgets/buttons/move_pane_button.js";
import NoteIconWidget from "../widgets/note_icon.jsx"; import RightPaneToggle from "../widgets/buttons/right_pane_toggle.jsx";
import CloseZenModeButton from "../widgets/close_zen_button.jsx";
import NoteList from "../widgets/collections/NoteList.jsx"; import NoteList from "../widgets/collections/NoteList.jsx";
import NoteTitleWidget from "../widgets/note_title.jsx"; import ContentHeader from "../widgets/containers/content_header.js";
import NoteTreeWidget from "../widgets/note_tree.js"; import FlexContainer from "../widgets/containers/flex_container.js";
import NoteWrapperWidget from "../widgets/note_wrapper.js"; import LeftPaneContainer from "../widgets/containers/left_pane_container.js";
import options from "../services/options.js";
import PasswordNoteSetDialog from "../widgets/dialogs/password_not_set.js";
import QuickSearchWidget from "../widgets/quick_search.js";
import ReadOnlyNoteInfoBar from "../widgets/ReadOnlyNoteInfoBar.jsx";
import Ribbon from "../widgets/ribbon/Ribbon.jsx";
import RightPaneContainer from "../widgets/containers/right_pane_container.js"; import RightPaneContainer from "../widgets/containers/right_pane_container.js";
import RootContainer from "../widgets/containers/root_container.js"; import RootContainer from "../widgets/containers/root_container.js";
import ScrollingContainer from "../widgets/containers/scrolling_container.js"; import ScrollingContainer from "../widgets/containers/scrolling_container.js";
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
import PasswordNoteSetDialog from "../widgets/dialogs/password_not_set.js";
import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js";
import FindWidget from "../widgets/find.js";
import FloatingButtons from "../widgets/FloatingButtons.jsx";
import { DESKTOP_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
import HighlightsListWidget from "../widgets/highlights_list.js";
import LauncherContainer from "../widgets/launch_bar/LauncherContainer.jsx";
import SpacerWidget from "../widgets/launch_bar/SpacerWidget.jsx";
import InlineTitle from "../widgets/layout/InlineTitle.jsx";
import NoteBadges from "../widgets/layout/NoteBadges.jsx";
import NoteTitleActions from "../widgets/layout/NoteTitleActions.jsx";
import StatusBar from "../widgets/layout/StatusBar.jsx";
import NoteIconWidget from "../widgets/note_icon.jsx";
import NoteTitleWidget from "../widgets/note_title.jsx";
import NoteTreeWidget from "../widgets/note_tree.js";
import NoteWrapperWidget from "../widgets/note_wrapper.js";
import NoteDetail from "../widgets/NoteDetail.jsx";
import PromotedAttributes from "../widgets/PromotedAttributes.jsx";
import QuickSearchWidget from "../widgets/quick_search.js";
import ReadOnlyNoteInfoBar from "../widgets/ReadOnlyNoteInfoBar.jsx";
import { FixedFormattingToolbar } from "../widgets/ribbon/FormattingToolbar.jsx";
import NoteActions from "../widgets/ribbon/NoteActions.jsx";
import Ribbon from "../widgets/ribbon/Ribbon.jsx";
import ScrollPadding from "../widgets/scroll_padding.js"; import ScrollPadding from "../widgets/scroll_padding.js";
import SearchResult from "../widgets/search_result.jsx"; import SearchResult from "../widgets/search_result.jsx";
import SharedInfo from "../widgets/shared_info.jsx"; import SharedInfo from "../widgets/shared_info.jsx";
import SpacerWidget from "../widgets/spacer.js"; import RightPanelContainer from "../widgets/sidebar/RightPanelContainer.jsx";
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
import SqlResults from "../widgets/sql_result.js"; import SqlResults from "../widgets/sql_result.js";
import SqlTableSchemas from "../widgets/sql_table_schemas.js"; import SqlTableSchemas from "../widgets/sql_table_schemas.js";
import TabRowWidget from "../widgets/tab_row.js"; import TabRowWidget from "../widgets/tab_row.js";
import TabHistoryNavigationButtons from "../widgets/TabHistoryNavigationButtons.jsx";
import TitleBarButtons from "../widgets/title_bar_buttons.jsx"; import TitleBarButtons from "../widgets/title_bar_buttons.jsx";
import TocWidget from "../widgets/toc.js"; import TocWidget from "../widgets/toc.js";
import type { AppContext } from "../components/app_context.js";
import type { WidgetsByParent } from "../services/bundle.js";
import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js";
import utils from "../services/utils.js";
import WatchedFileUpdateStatusWidget from "../widgets/watched_file_update_status.js"; import WatchedFileUpdateStatusWidget from "../widgets/watched_file_update_status.js";
import NoteDetail from "../widgets/NoteDetail.jsx"; import { applyModals } from "./layout_commons.js";
import RightPanelWidget from "../widgets/sidebar/RightPanelWidget.jsx";
import PromotedAttributes from "../widgets/PromotedAttributes.jsx";
export default class DesktopLayout { export default class DesktopLayout {
@@ -70,17 +79,20 @@ export default class DesktopLayout {
*/ */
const fullWidthTabBar = launcherPaneIsHorizontal || (isElectron && !hasNativeTitleBar && isMac); const fullWidthTabBar = launcherPaneIsHorizontal || (isElectron && !hasNativeTitleBar && isMac);
const customTitleBarButtons = !hasNativeTitleBar && !isMac && !isWindows; const customTitleBarButtons = !hasNativeTitleBar && !isMac && !isWindows;
const isNewLayout = isExperimentalFeatureEnabled("new-layout");
const rootContainer = new RootContainer(true) const rootContainer = new RootContainer(true)
.setParent(appContext) .setParent(appContext)
.class((launcherPaneIsHorizontal ? "horizontal" : "vertical") + "-layout") .class(`${launcherPaneIsHorizontal ? "horizontal" : "vertical" }-layout`)
.optChild( .optChild(
fullWidthTabBar, fullWidthTabBar,
new FlexContainer("row") new FlexContainer("row")
.class("tab-row-container") .class("tab-row-container")
.child(new FlexContainer("row").id("tab-row-left-spacer")) .child(new FlexContainer("row").id("tab-row-left-spacer"))
.optChild(launcherPaneIsHorizontal, <LeftPaneToggle isHorizontalLayout={true} />) .optChild(launcherPaneIsHorizontal, <LeftPaneToggle isHorizontalLayout={true} />)
.child(<TabHistoryNavigationButtons />)
.child(new TabRowWidget().class("full-width")) .child(new TabRowWidget().class("full-width"))
.optChild(launcherPaneIsHorizontal && isNewLayout, <RightPaneToggle />)
.optChild(customTitleBarButtons, <TitleBarButtons />) .optChild(customTitleBarButtons, <TitleBarButtons />)
.css("height", "40px") .css("height", "40px")
.css("background-color", "var(--launcher-pane-background-color)") .css("background-color", "var(--launcher-pane-background-color)")
@@ -102,7 +114,17 @@ export default class DesktopLayout {
new FlexContainer("column") new FlexContainer("column")
.id("rest-pane") .id("rest-pane")
.css("flex-grow", "1") .css("flex-grow", "1")
.optChild(!fullWidthTabBar, new FlexContainer("row").child(new TabRowWidget()).optChild(customTitleBarButtons, <TitleBarButtons />).css("height", "40px")) .optChild(!fullWidthTabBar,
new FlexContainer("row")
.class("tab-row-container")
.child(<TabHistoryNavigationButtons />)
.child(new TabRowWidget())
.optChild(isNewLayout, <RightPaneToggle />)
.optChild(customTitleBarButtons, <TitleBarButtons />)
.css("height", "40px")
.css("align-items", "center")
)
.optChild(isNewLayout, <FixedFormattingToolbar />)
.child( .child(
new FlexContainer("row") new FlexContainer("row")
.filling() .filling()
@@ -116,32 +138,31 @@ export default class DesktopLayout {
.child( .child(
new SplitNoteContainer(() => new SplitNoteContainer(() =>
new NoteWrapperWidget() new NoteWrapperWidget()
.child( .child(new FlexContainer("row")
new FlexContainer("row") .class("title-row note-split-title")
.class("title-row")
.css("height", "50px")
.css("min-height", "50px")
.css("align-items", "center")
.cssBlock(".title-row > * { margin: 5px; }") .cssBlock(".title-row > * { margin: 5px; }")
.child(<NoteIconWidget />) .child(<NoteIconWidget />)
.child(<NoteTitleWidget />) .child(<NoteTitleWidget />)
.child(new SpacerWidget(0, 1)) .optChild(isNewLayout, <NoteBadges />)
.child(<MovePaneButton direction="left" />) .child(<SpacerWidget baseSize={0} growthFactor={1} />)
.child(<MovePaneButton direction="right" />) .optChild(!isNewLayout, <MovePaneButton direction="left" />)
.child(<ClosePaneButton />) .optChild(!isNewLayout, <MovePaneButton direction="right" />)
.child(<CreatePaneButton />) .optChild(!isNewLayout, <ClosePaneButton />)
) .optChild(!isNewLayout, <CreatePaneButton />)
.child(<Ribbon />) .optChild(isNewLayout, <NoteActions />))
.optChild(!isNewLayout, <Ribbon />)
.child(new WatchedFileUpdateStatusWidget()) .child(new WatchedFileUpdateStatusWidget())
.child(<FloatingButtons items={DESKTOP_FLOATING_BUTTONS} />) .optChild(!isNewLayout, <FloatingButtons items={DESKTOP_FLOATING_BUTTONS} />)
.child( .child(
new ScrollingContainer() new ScrollingContainer()
.filling() .filling()
.child(new ContentHeader() .optChild(isNewLayout, <InlineTitle />)
.optChild(isNewLayout, <NoteTitleActions />)
.optChild(!isNewLayout, new ContentHeader()
.child(<ReadOnlyNoteInfoBar />) .child(<ReadOnlyNoteInfoBar />)
.child(<SharedInfo />) .child(<SharedInfo />)
) )
.child(<PromotedAttributes />) .optChild(!isNewLayout, <PromotedAttributes />)
.child(<SqlTableSchemas />) .child(<SqlTableSchemas />)
.child(<NoteDetail />) .child(<NoteDetail />)
.child(<NoteList media="screen" />) .child(<NoteList media="screen" />)
@@ -151,23 +172,24 @@ export default class DesktopLayout {
) )
.child(<ApiLog />) .child(<ApiLog />)
.child(new FindWidget()) .child(new FindWidget())
.child( .child(...this.customWidgets.get("note-detail-pane"))
...this.customWidgets.get("node-detail-pane"), // typo, let's keep it for a while as BC
...this.customWidgets.get("note-detail-pane")
)
) )
) )
.child(...this.customWidgets.get("center-pane")) .child(...this.customWidgets.get("center-pane"))
) )
.child( .optChild(!isNewLayout,
new RightPaneContainer() new RightPaneContainer()
.child(new TocWidget()) .child(new TocWidget())
.child(new HighlightsListWidget()) .child(new HighlightsListWidget())
.child(...this.customWidgets.get("right-pane")) .child(...this.customWidgets.get("right-pane"))
) )
.optChild(isNewLayout, <RightPanelContainer widgetsByParent={this.customWidgets} />)
)
.optChild(!launcherPaneIsHorizontal && isNewLayout, <StatusBar />)
) )
) )
) .optChild(launcherPaneIsHorizontal && isNewLayout, <StatusBar />)
.child(<CloseZenModeButton />) .child(<CloseZenModeButton />)
// Desktop-specific dialogs. // Desktop-specific dialogs.
@@ -185,14 +207,14 @@ export default class DesktopLayout {
launcherPane = new FlexContainer("row") launcherPane = new FlexContainer("row")
.css("height", "53px") .css("height", "53px")
.class("horizontal") .class("horizontal")
.child(new LauncherContainer(true)) .child(<LauncherContainer isHorizontalLayout={true} />)
.child(<GlobalMenu isHorizontalLayout={true} />); .child(<GlobalMenu isHorizontalLayout={true} />);
} else { } else {
launcherPane = new FlexContainer("column") launcherPane = new FlexContainer("column")
.css("width", "53px") .css("width", "53px")
.class("vertical") .class("vertical")
.child(<GlobalMenu isHorizontalLayout={false} />) .child(<GlobalMenu isHorizontalLayout={false} />)
.child(new LauncherContainer(false)) .child(<LauncherContainer isHorizontalLayout={false} />)
.child(<LeftPaneToggle isHorizontalLayout={false} />); .child(<LeftPaneToggle isHorizontalLayout={false} />);
} }

View File

@@ -24,6 +24,7 @@ import InfoDialog from "../widgets/dialogs/info.js";
import IncorrectCpuArchDialog from "../widgets/dialogs/incorrect_cpu_arch.js"; import IncorrectCpuArchDialog from "../widgets/dialogs/incorrect_cpu_arch.js";
import CallToActionDialog from "../widgets/dialogs/call_to_action.jsx"; import CallToActionDialog from "../widgets/dialogs/call_to_action.jsx";
import PopupEditorDialog from "../widgets/dialogs/PopupEditor.jsx"; import PopupEditorDialog from "../widgets/dialogs/PopupEditor.jsx";
import ToastContainer from "../widgets/Toast.jsx";
export function applyModals(rootContainer: RootContainer) { export function applyModals(rootContainer: RootContainer) {
rootContainer rootContainer
@@ -50,5 +51,6 @@ export function applyModals(rootContainer: RootContainer) {
.child(<PromptDialog />) .child(<PromptDialog />)
.child(<IncorrectCpuArchDialog />) .child(<IncorrectCpuArchDialog />)
.child(<PopupEditorDialog />) .child(<PopupEditorDialog />)
.child(<CallToActionDialog />); .child(<CallToActionDialog />)
.child(<ToastContainer />);
} }

View File

@@ -6,7 +6,6 @@ import FilePropertiesTab from "../widgets/ribbon/FilePropertiesTab.jsx";
import FlexContainer from "../widgets/containers/flex_container.js"; import FlexContainer from "../widgets/containers/flex_container.js";
import FloatingButtons from "../widgets/FloatingButtons.jsx"; import FloatingButtons from "../widgets/FloatingButtons.jsx";
import GlobalMenuWidget from "../widgets/buttons/global_menu.js"; import GlobalMenuWidget from "../widgets/buttons/global_menu.js";
import LauncherContainer from "../widgets/containers/launcher_container.js";
import MobileDetailMenu from "../widgets/mobile_widgets/mobile_detail_menu.js"; import MobileDetailMenu from "../widgets/mobile_widgets/mobile_detail_menu.js";
import NoteList from "../widgets/collections/NoteList.jsx"; import NoteList from "../widgets/collections/NoteList.jsx";
import NoteTitleWidget from "../widgets/note_title.js"; import NoteTitleWidget from "../widgets/note_title.js";
@@ -30,6 +29,7 @@ import NoteDetail from "../widgets/NoteDetail.jsx";
import MobileEditorToolbar from "../widgets/type_widgets/text/mobile_editor_toolbar.jsx"; import MobileEditorToolbar from "../widgets/type_widgets/text/mobile_editor_toolbar.jsx";
import PromotedAttributes from "../widgets/PromotedAttributes.jsx"; import PromotedAttributes from "../widgets/PromotedAttributes.jsx";
import SplitNoteContainer from "../widgets/containers/split_note_container.js"; import SplitNoteContainer from "../widgets/containers/split_note_container.js";
import LauncherContainer from "../widgets/launch_bar/LauncherContainer.jsx";
const MOBILE_CSS = ` const MOBILE_CSS = `
<style> <style>
@@ -183,7 +183,7 @@ export default class MobileLayout {
.child(new FlexContainer("row") .child(new FlexContainer("row")
.class("horizontal") .class("horizontal")
.css("height", "53px") .css("height", "53px")
.child(new LauncherContainer(true)) .child(<LauncherContainer isHorizontalLayout />)
.child(<GlobalMenuWidget isHorizontalLayout />) .child(<GlobalMenuWidget isHorizontalLayout />)
.id("launcher-pane")) .id("launcher-pane"))
) )

View File

@@ -1,10 +1,11 @@
import { t } from "../services/i18n.js"; import type { LeafletMouseEvent } from "leaflet";
import contextMenu, { type ContextMenuEvent, type MenuItem } from "./context_menu.js";
import appContext, { type CommandNames } from "../components/app_context.js"; import appContext, { type CommandNames } from "../components/app_context.js";
import { t } from "../services/i18n.js";
import type { ViewScope } from "../services/link.js"; import type { ViewScope } from "../services/link.js";
import utils, { isMobile } from "../services/utils.js"; import utils, { isMobile } from "../services/utils.js";
import { getClosestNtxId } from "../widgets/widget_utils.js"; import { getClosestNtxId } from "../widgets/widget_utils.js";
import type { LeafletMouseEvent } from "leaflet"; import contextMenu, { type ContextMenuEvent, type MenuItem } from "./context_menu.js";
function openContextMenu(notePath: string, e: ContextMenuEvent, viewScope: ViewScope = {}, hoistedNoteId: string | null = null) { function openContextMenu(notePath: string, e: ContextMenuEvent, viewScope: ViewScope = {}, hoistedNoteId: string | null = null) {
contextMenu.show({ contextMenu.show({
@@ -34,15 +35,21 @@ function handleLinkContextMenuItem(command: string | undefined, e: ContextMenuEv
if (command === "openNoteInNewTab") { if (command === "openNoteInNewTab") {
appContext.tabManager.openContextWithNote(notePath, { hoistedNoteId, viewScope }); appContext.tabManager.openContextWithNote(notePath, { hoistedNoteId, viewScope });
return true;
} else if (command === "openNoteInNewSplit") { } else if (command === "openNoteInNewSplit") {
const ntxId = getNtxId(e); const ntxId = getNtxId(e);
if (!ntxId) return; if (!ntxId) return false;
appContext.triggerCommand("openNewNoteSplit", { ntxId, notePath, hoistedNoteId, viewScope }); appContext.triggerCommand("openNewNoteSplit", { ntxId, notePath, hoistedNoteId, viewScope });
return true;
} else if (command === "openNoteInNewWindow") { } else if (command === "openNoteInNewWindow") {
appContext.triggerCommand("openInWindow", { notePath, hoistedNoteId, viewScope }); appContext.triggerCommand("openInWindow", { notePath, hoistedNoteId, viewScope });
return true;
} else if (command === "openNoteInPopup") { } else if (command === "openNoteInPopup") {
appContext.triggerCommand("openInPopup", { noteIdOrPath: notePath }) appContext.triggerCommand("openInPopup", { noteIdOrPath: notePath });
return true;
} }
return false;
} }
function getNtxId(e: ContextMenuEvent | LeafletMouseEvent) { function getNtxId(e: ContextMenuEvent | LeafletMouseEvent) {
@@ -52,9 +59,9 @@ function getNtxId(e: ContextMenuEvent | LeafletMouseEvent) {
return subContexts[subContexts.length - 1].ntxId; return subContexts[subContexts.length - 1].ntxId;
} else if (e.target instanceof HTMLElement) { } else if (e.target instanceof HTMLElement) {
return getClosestNtxId(e.target); return getClosestNtxId(e.target);
} else {
return null;
} }
return null;
} }
export default { export default {

View File

@@ -1,6 +1,6 @@
import utils from "./utils.js"; import utils from "./utils.js";
import server from "./server.js"; import server from "./server.js";
import toastService, { type ToastOptions } from "./toast.js"; import toastService, { type ToastOptionsWithRequiredId } from "./toast.js";
import froca from "./froca.js"; import froca from "./froca.js";
import hoistedNoteService from "./hoisted_note.js"; import hoistedNoteService from "./hoisted_note.js";
import ws from "./ws.js"; import ws from "./ws.js";
@@ -195,11 +195,11 @@ function filterRootNote(branchIds: string[]) {
}); });
} }
function makeToast(id: string, message: string): ToastOptions { function makeToast(id: string, message: string): ToastOptionsWithRequiredId {
return { return {
id: id, id,
title: t("branches.delete-status"), title: t("branches.delete-status"),
message: message, message,
icon: "trash" icon: "trash"
}; };
} }
@@ -216,7 +216,7 @@ ws.subscribeToMessages(async (message) => {
toastService.showPersistent(makeToast(message.taskId, t("branches.delete-notes-in-progress", { count: message.progressCount }))); toastService.showPersistent(makeToast(message.taskId, t("branches.delete-notes-in-progress", { count: message.progressCount })));
} else if (message.type === "taskSucceeded") { } else if (message.type === "taskSucceeded") {
const toast = makeToast(message.taskId, t("branches.delete-finished-successfully")); const toast = makeToast(message.taskId, t("branches.delete-finished-successfully"));
toast.closeAfter = 5000; toast.timeout = 5000;
toastService.showPersistent(toast); toastService.showPersistent(toast);
} }
@@ -234,7 +234,7 @@ ws.subscribeToMessages(async (message) => {
toastService.showPersistent(makeToast(message.taskId, t("branches.undeleting-notes-in-progress", { count: message.progressCount }))); toastService.showPersistent(makeToast(message.taskId, t("branches.undeleting-notes-in-progress", { count: message.progressCount })));
} else if (message.type === "taskSucceeded") { } else if (message.type === "taskSucceeded") {
const toast = makeToast(message.taskId, t("branches.undeleting-notes-finished-successfully")); const toast = makeToast(message.taskId, t("branches.undeleting-notes-finished-successfully"));
toast.closeAfter = 5000; toast.timeout = 5000;
toastService.showPersistent(toast); toastService.showPersistent(toast);
} }
@@ -242,7 +242,7 @@ ws.subscribeToMessages(async (message) => {
async function cloneNoteToBranch(childNoteId: string, parentBranchId: string, prefix?: string) { async function cloneNoteToBranch(childNoteId: string, parentBranchId: string, prefix?: string) {
const resp = await server.put<Response>(`notes/${childNoteId}/clone-to-branch/${parentBranchId}`, { const resp = await server.put<Response>(`notes/${childNoteId}/clone-to-branch/${parentBranchId}`, {
prefix: prefix prefix
}); });
if (!resp.success) { if (!resp.success) {
@@ -252,7 +252,7 @@ async function cloneNoteToBranch(childNoteId: string, parentBranchId: string, pr
async function cloneNoteToParentNote(childNoteId: string, parentNoteId: string, prefix?: string) { async function cloneNoteToParentNote(childNoteId: string, parentNoteId: string, prefix?: string) {
const resp = await server.put<Response>(`notes/${childNoteId}/clone-to-note/${parentNoteId}`, { const resp = await server.put<Response>(`notes/${childNoteId}/clone-to-note/${parentNoteId}`, {
prefix: prefix prefix
}); });
if (!resp.success) { if (!resp.success) {

View File

@@ -1,10 +1,16 @@
import { h, VNode } from "preact";
import Component from "../components/component.js";
import BasicWidget, { ReactWrappedWidget } from "../widgets/basic_widget.js";
import RightPanelWidget from "../widgets/right_panel_widget.js";
import froca from "./froca.js";
import type { Entity } from "./frontend_script_api.js";
import { WidgetDefinitionWithType } from "./frontend_script_api_preact.js";
import { t } from "./i18n.js";
import ScriptContext from "./script_context.js"; import ScriptContext from "./script_context.js";
import server from "./server.js"; import server from "./server.js";
import toastService, { showError } from "./toast.js"; import toastService, { showErrorForScriptNote } from "./toast.js";
import froca from "./froca.js"; import utils, { getErrorMessage } from "./utils.js";
import utils from "./utils.js";
import { t } from "./i18n.js";
import type { Entity } from "./frontend_script_api.js";
// TODO: Deduplicate with server. // TODO: Deduplicate with server.
export interface Bundle { export interface Bundle {
@@ -14,9 +20,12 @@ export interface Bundle {
allNoteIds: string[]; allNoteIds: string[];
} }
interface Widget { type LegacyWidget = (BasicWidget | RightPanelWidget) & {
parentWidget?: string; parentWidget?: string;
} };
export type Widget = (LegacyWidget | WidgetDefinitionWithType) & {
_noteId: string;
};
async function getAndExecuteBundle(noteId: string, originEntity = null, script = null, params = null) { async function getAndExecuteBundle(noteId: string, originEntity = null, script = null, params = null) {
const bundle = await server.post<Bundle>(`script/bundle/${noteId}`, { const bundle = await server.post<Bundle>(`script/bundle/${noteId}`, {
@@ -27,6 +36,8 @@ async function getAndExecuteBundle(noteId: string, originEntity = null, script =
return await executeBundle(bundle, originEntity); return await executeBundle(bundle, originEntity);
} }
export type ParentName = "left-pane" | "center-pane" | "note-detail-pane" | "right-pane";
export async function executeBundle(bundle: Bundle, originEntity?: Entity | null, $container?: JQuery<HTMLElement>) { export async function executeBundle(bundle: Bundle, originEntity?: Entity | null, $container?: JQuery<HTMLElement>) {
const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity, $container); const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity, $container);
@@ -36,16 +47,23 @@ export async function executeBundle(bundle: Bundle, originEntity?: Entity | null
}.call(apiContext); }.call(apiContext);
} catch (e: any) { } catch (e: any) {
const note = await froca.getNote(bundle.noteId); const note = await froca.getNote(bundle.noteId);
toastService.showPersistent({
const message = `Execution of JS note "${note?.title}" with ID ${bundle.noteId} failed with error: ${e?.message}`; id: `custom-script-failure-${note?.noteId}`,
showError(message); title: t("toast.bundle-error.title"),
logError(message); icon: "bx bx-error-circle",
message: t("toast.bundle-error.message", {
id: note?.noteId,
title: note?.title,
message: e.message
})
});
logError("Widget initialization failed: ", e);
} }
} }
async function executeStartupBundles() { async function executeStartupBundles() {
const isMobile = utils.isMobile(); const isMobile = utils.isMobile();
const scriptBundles = await server.get<Bundle[]>("script/startup" + (isMobile ? "?mobile=true" : "")); const scriptBundles = await server.get<Bundle[]>(`script/startup${ isMobile ? "?mobile=true" : ""}`);
for (const bundle of scriptBundles) { for (const bundle of scriptBundles) {
await executeBundle(bundle); await executeBundle(bundle);
@@ -53,42 +71,75 @@ async function executeStartupBundles() {
} }
export class WidgetsByParent { export class WidgetsByParent {
private byParent: Record<string, Widget[]>; private legacyWidgets: Record<string, LegacyWidget[]>;
private preactWidgets: Record<string, WidgetDefinitionWithType[]>;
constructor() { constructor() {
this.byParent = {}; this.legacyWidgets = {};
this.preactWidgets = {};
} }
add(widget: Widget) { add(widget: Widget) {
if (!widget.parentWidget) { let hasParentWidget = false;
console.log(`Custom widget does not have mandatory 'parentWidget' property defined`); let isPreact = false;
return; if ("type" in widget && widget.type === "preact-widget") {
// React-based script.
const reactWidget = widget as WidgetDefinitionWithType;
this.preactWidgets[reactWidget.parent] = this.preactWidgets[reactWidget.parent] || [];
this.preactWidgets[reactWidget.parent].push(reactWidget);
isPreact = true;
hasParentWidget = !!reactWidget.parent;
} else if ("parentWidget" in widget && widget.parentWidget) {
this.legacyWidgets[widget.parentWidget] = this.legacyWidgets[widget.parentWidget] || [];
this.legacyWidgets[widget.parentWidget].push(widget);
hasParentWidget = !!widget.parentWidget;
} }
this.byParent[widget.parentWidget] = this.byParent[widget.parentWidget] || []; if (!hasParentWidget) {
this.byParent[widget.parentWidget].push(widget); showErrorForScriptNote(widget._noteId, t("toast.widget-missing-parent", {
property: isPreact ? "parent" : "parentWidget"
}));
}
} }
get(parentName: string) { get(parentName: ParentName) {
if (!this.byParent[parentName]) { const widgets: (Component | VNode)[] = this.getLegacyWidgets(parentName);
return []; for (const preactWidget of this.getPreactWidgets(parentName)) {
const el = h(preactWidget.render, {});
const widget = new ReactWrappedWidget(el);
widget.contentSized();
if (preactWidget.position) {
widget.position = preactWidget.position;
} }
widgets.push(widget);
}
return widgets;
}
getLegacyWidgets(parentName: ParentName): (BasicWidget | RightPanelWidget)[] {
if (!this.legacyWidgets[parentName]) return [];
return ( return (
this.byParent[parentName] this.legacyWidgets[parentName]
// previously, custom widgets were provided as a single instance, but that has the disadvantage // previously, custom widgets were provided as a single instance, but that has the disadvantage
// for splits where we actually need multiple instaces and thus having a class to instantiate is better // for splits where we actually need multiple instaces and thus having a class to instantiate is better
// https://github.com/zadam/trilium/issues/4274 // https://github.com/zadam/trilium/issues/4274
.map((w: any) => (w.prototype ? new w() : w)) .map((w: any) => (w.prototype ? new w() : w))
); );
} }
getPreactWidgets(parentName: ParentName) {
return this.preactWidgets[parentName] ?? [];
}
} }
async function getWidgetBundlesByParent() { async function getWidgetBundlesByParent() {
const scriptBundles = await server.get<Bundle[]>("script/widgets");
const widgetsByParent = new WidgetsByParent(); const widgetsByParent = new WidgetsByParent();
try {
const scriptBundles = await server.get<Bundle[]>("script/widgets");
for (const bundle of scriptBundles) { for (const bundle of scriptBundles) {
let widget; let widget;
@@ -102,8 +153,9 @@ async function getWidgetBundlesByParent() {
const noteId = bundle.noteId; const noteId = bundle.noteId;
const note = await froca.getNote(noteId); const note = await froca.getNote(noteId);
toastService.showPersistent({ toastService.showPersistent({
id: `custom-script-failure-${noteId}`,
title: t("toast.bundle-error.title"), title: t("toast.bundle-error.title"),
icon: "alert", icon: "bx bx-error-circle",
message: t("toast.bundle-error.message", { message: t("toast.bundle-error.message", {
id: noteId, id: noteId,
title: note?.title, title: note?.title,
@@ -115,6 +167,13 @@ async function getWidgetBundlesByParent() {
continue; continue;
} }
} }
} catch (e) {
toastService.showPersistent({
title: t("toast.widget-list-error.title"),
message: getErrorMessage(e),
icon: "bx bx-error-circle"
});
}
return widgetsByParent; return widgetsByParent;
} }

View File

@@ -32,6 +32,7 @@ function createClassForColor(colorString: string | null) {
$("head").append(`<style> $("head").append(`<style>
.${className}, span.fancytree-active.${className} { .${className}, span.fancytree-active.${className} {
--original-custom-color: ${color.hex()};
--light-theme-custom-color: ${adjustedColor.lightThemeColor}; --light-theme-custom-color: ${adjustedColor.lightThemeColor};
--dark-theme-custom-color: ${adjustedColor.darkThemeColor}; --dark-theme-custom-color: ${adjustedColor.darkThemeColor};
--custom-color-hue: ${hue ?? 'unset'}; --custom-color-hue: ${hue ?? 'unset'};

View File

@@ -1,8 +1,9 @@
import { Modal } from "bootstrap"; import { Modal } from "bootstrap";
import appContext from "../components/app_context.js"; import appContext from "../components/app_context.js";
import type { ConfirmDialogOptions, ConfirmDialogResult, ConfirmWithMessageOptions } from "../widgets/dialogs/confirm.js"; import type { ConfirmDialogOptions, ConfirmDialogResult, ConfirmWithMessageOptions, MessageType } from "../widgets/dialogs/confirm.js";
import type { PromptDialogOptions } from "../widgets/dialogs/prompt.js"; import type { PromptDialogOptions } from "../widgets/dialogs/prompt.js";
import { focusSavedElement, saveFocusedElement } from "./focus.js"; import { focusSavedElement, saveFocusedElement } from "./focus.js";
import { InfoExtraProps } from "../widgets/dialogs/info.jsx";
export async function openDialog($dialog: JQuery<HTMLElement>, closeActDialog = true, config?: Partial<Modal.Options>) { export async function openDialog($dialog: JQuery<HTMLElement>, closeActDialog = true, config?: Partial<Modal.Options>) {
if (closeActDialog) { if (closeActDialog) {
@@ -37,8 +38,8 @@ export function closeActiveDialog() {
} }
} }
async function info(message: string) { async function info(message: MessageType, extraProps?: InfoExtraProps) {
return new Promise((res) => appContext.triggerCommand("showInfoDialog", { message, callback: res })); return new Promise((res) => appContext.triggerCommand("showInfoDialog", { ...extraProps, message, callback: res }));
} }
/** /**

View File

@@ -0,0 +1,59 @@
import { t } from "./i18n";
import options from "./options";
export interface ExperimentalFeature {
id: string;
name: string;
description: string;
}
export const experimentalFeatures = [
{
id: "new-layout",
name: t("experimental_features.new_layout_name"),
description: t("experimental_features.new_layout_description"),
}
] as const satisfies ExperimentalFeature[];
export type ExperimentalFeatureId = typeof experimentalFeatures[number]["id"];
let enabledFeatures: Set<ExperimentalFeatureId> | null = null;
export function isExperimentalFeatureEnabled(featureId: ExperimentalFeatureId): boolean {
if (featureId === "new-layout") {
return options.is("newLayout");
}
return getEnabledFeatures().has(featureId);
}
export function getEnabledExperimentalFeatureIds() {
const values = [ ...getEnabledFeatures().values() ];
if (options.is("newLayout")) {
values.push("new-layout");
}
return values;
}
export async function toggleExperimentalFeature(featureId: ExperimentalFeatureId, enable: boolean) {
const features = new Set(getEnabledFeatures());
if (enable) {
features.add(featureId);
} else {
features.delete(featureId);
}
await options.save("experimentalFeatures", JSON.stringify(Array.from(features)));
}
function getEnabledFeatures() {
if (!enabledFeatures) {
let features: ExperimentalFeatureId[] = [];
try {
features = JSON.parse(options.get("experimentalFeatures")) as ExperimentalFeatureId[];
} catch (e) {
console.warn("Failed to parse experimental features from options:", e);
}
enabledFeatures = new Set(features);
}
return enabledFeatures;
}

View File

@@ -1,26 +1,27 @@
import server from "./server.js"; import { dayjs, formatLogMessage } from "@triliumnext/commons";
import utils from "./utils.js";
import toastService from "./toast.js"; import appContext from "../components/app_context.js";
import linkService from "./link.js"; import type Component from "../components/component.js";
import type NoteContext from "../components/note_context.js";
import type FNote from "../entities/fnote.js";
import BasicWidget, { ReactWrappedWidget } from "../widgets/basic_widget.js";
import NoteContextAwareWidget from "../widgets/note_context_aware_widget.js";
import RightPanelWidget from "../widgets/right_panel_widget.js";
import dateNotesService from "./date_notes.js";
import dialogService from "./dialog.js";
import froca from "./froca.js"; import froca from "./froca.js";
import { preactAPI } from "./frontend_script_api_preact.js";
import { t } from "./i18n.js";
import linkService from "./link.js";
import noteTooltipService from "./note_tooltip.js"; import noteTooltipService from "./note_tooltip.js";
import protectedSessionService from "./protected_session.js"; import protectedSessionService from "./protected_session.js";
import dateNotesService from "./date_notes.js";
import searchService from "./search.js"; import searchService from "./search.js";
import RightPanelWidget from "../widgets/right_panel_widget.js"; import server from "./server.js";
import ws from "./ws.js";
import appContext from "../components/app_context.js";
import NoteContextAwareWidget from "../widgets/note_context_aware_widget.js";
import BasicWidget, { ReactWrappedWidget } from "../widgets/basic_widget.js";
import SpacedUpdate from "./spaced_update.js";
import shortcutService from "./shortcuts.js"; import shortcutService from "./shortcuts.js";
import dialogService from "./dialog.js"; import SpacedUpdate from "./spaced_update.js";
import type FNote from "../entities/fnote.js"; import toastService from "./toast.js";
import { t } from "./i18n.js"; import utils from "./utils.js";
import { dayjs } from "@triliumnext/commons"; import ws from "./ws.js";
import type NoteContext from "../components/note_context.js";
import type Component from "../components/component.js";
import { formatLogMessage } from "@triliumnext/commons";
/** /**
* A whole number * A whole number
@@ -77,6 +78,10 @@ export interface Api {
/** /**
* Entity whose event triggered this execution. * Entity whose event triggered this execution.
*
* <p>
* For front-end scripts, generally there's no origin entity specified since the scripts are run by the user or automatically by the UI (widgets).
* If there is an origin entity specified, then it's going to be a note entity.
*/ */
originEntity: unknown | null; originEntity: unknown | null;
@@ -278,12 +283,16 @@ export interface Api {
getActiveContextNote(): FNote; getActiveContextNote(): FNote;
/** /**
* @returns returns active context (split) * Obtains the currently active/focused split in the current tab.
*
* Note that this method does not return the note context of the "Quick edit" panel, it will return the note context behind it.
*/ */
getActiveContext(): NoteContext; getActiveContext(): NoteContext;
/** /**
* @returns returns active main context (first split in a tab, represents the tab as a whole) * Obtains the main context of the current tab. This is the left-most split.
*
* Note that this method does not return the note context of the "Quick edit" panel, it will return the note context behind it.
*/ */
getActiveMainContext(): NoteContext; getActiveMainContext(): NoteContext;
@@ -456,6 +465,8 @@ export interface Api {
* Log given message to the log pane in UI * Log given message to the log pane in UI
*/ */
log(message: string | object): void; log(message: string | object): void;
preact: typeof preactAPI;
} }
/** /**
@@ -525,9 +536,9 @@ function FrontendScriptApi(this: Api, startNote: FNote, currentNote: FNote, orig
return params.map((p) => { return params.map((p) => {
if (typeof p === "function") { if (typeof p === "function") {
return `!@#Function: ${p.toString()}`; return `!@#Function: ${p.toString()}`;
} else {
return p;
} }
return p;
}); });
} }
@@ -554,9 +565,9 @@ function FrontendScriptApi(this: Api, startNote: FNote, currentNote: FNote, orig
await ws.waitForMaxKnownEntityChangeId(); await ws.waitForMaxKnownEntityChangeId();
return ret.executionResult; return ret.executionResult;
} else {
throw new Error(`server error: ${ret.error}`);
} }
throw new Error(`server error: ${ret.error}`);
}; };
this.runOnBackend = async (func, params = []) => { this.runOnBackend = async (func, params = []) => {
@@ -713,6 +724,8 @@ function FrontendScriptApi(this: Api, startNote: FNote, currentNote: FNote, orig
this.logMessages[noteId].push(message); this.logMessages[noteId].push(message);
this.logSpacedUpdates[noteId].scheduleUpdate(); this.logSpacedUpdates[noteId].scheduleUpdate();
}; };
this.preact = preactAPI;
} }
export default FrontendScriptApi as any as { export default FrontendScriptApi as any as {

View File

@@ -0,0 +1,101 @@
import { Fragment, h, VNode } from "preact";
import * as hooks from "preact/hooks";
import ActionButton from "../widgets/react/ActionButton";
import Admonition from "../widgets/react/Admonition";
import Button from "../widgets/react/Button";
import CKEditor from "../widgets/react/CKEditor";
import Collapsible from "../widgets/react/Collapsible";
import Dropdown from "../widgets/react/Dropdown";
import FormCheckbox from "../widgets/react/FormCheckbox";
import FormDropdownList from "../widgets/react/FormDropdownList";
import { FormFileUploadActionButton,FormFileUploadButton } from "../widgets/react/FormFileUpload";
import FormGroup from "../widgets/react/FormGroup";
import { FormDropdownDivider, FormDropdownSubmenu,FormListItem } from "../widgets/react/FormList";
import FormRadioGroup from "../widgets/react/FormRadioGroup";
import FormText from "../widgets/react/FormText";
import FormTextArea from "../widgets/react/FormTextArea";
import FormTextBox from "../widgets/react/FormTextBox";
import FormToggle from "../widgets/react/FormToggle";
import * as triliumHooks from "../widgets/react/hooks";
import Icon from "../widgets/react/Icon";
import LinkButton from "../widgets/react/LinkButton";
import LoadingSpinner from "../widgets/react/LoadingSpinner";
import Modal from "../widgets/react/Modal";
import NoteAutocomplete from "../widgets/react/NoteAutocomplete";
import NoteLink from "../widgets/react/NoteLink";
import RawHtml from "../widgets/react/RawHtml";
import Slider from "../widgets/react/Slider";
import RightPanelWidget from "../widgets/sidebar/RightPanelWidget";
export interface WidgetDefinition {
parent: "right-pane",
render: () => VNode,
position?: number,
}
export interface WidgetDefinitionWithType extends WidgetDefinition {
type: "preact-widget"
}
export interface LauncherWidgetDefinitionWithType {
type: "preact-launcher-widget"
render: () => VNode
}
export const preactAPI = Object.freeze({
// Core
h,
Fragment,
/**
* Method that must be run for widget scripts that run on Preact, using JSX. The method just returns the same definition, reserved for future typechecking and perhaps validation purposes.
*
* @param definition the widget definition.
*/
defineWidget(definition: WidgetDefinition) {
return {
type: "preact-widget",
...definition
};
},
defineLauncherWidget(definition: Omit<LauncherWidgetDefinitionWithType, "type">) {
return {
type: "preact-launcher-widget",
...definition
};
},
// Basic widgets
ActionButton,
Admonition,
Button,
CKEditor,
Collapsible,
Dropdown,
FormCheckbox,
FormDropdownList,
FormFileUploadButton, FormFileUploadActionButton,
FormGroup,
FormListItem, FormDropdownDivider, FormDropdownSubmenu,
FormRadioGroup,
FormText,
FormTextArea,
FormTextBox,
FormToggle,
Icon,
LinkButton,
LoadingSpinner,
Modal,
NoteAutocomplete,
NoteLink,
RawHtml,
Slider,
// Specialized widgets
RightPanelWidget,
...hooks,
...triliumHooks
});

View File

@@ -1,4 +1,4 @@
import toastService, { type ToastOptions } from "./toast.js"; import toastService, { type ToastOptionsWithRequiredId } from "./toast.js";
import server from "./server.js"; import server from "./server.js";
import ws from "./ws.js"; import ws from "./ws.js";
import utils from "./utils.js"; import utils from "./utils.js";
@@ -57,11 +57,11 @@ export async function uploadFiles(entityType: string, parentNoteId: string, file
} }
} }
function makeToast(id: string, message: string): ToastOptions { function makeToast(id: string, message: string): ToastOptionsWithRequiredId {
return { return {
id: id, id,
title: t("import.import-status"), title: t("import.import-status"),
message: message, message,
icon: "plus" icon: "plus"
}; };
} }
@@ -78,7 +78,7 @@ ws.subscribeToMessages(async (message) => {
toastService.showPersistent(makeToast(message.taskId, t("import.in-progress", { progress: message.progressCount }))); toastService.showPersistent(makeToast(message.taskId, t("import.in-progress", { progress: message.progressCount })));
} else if (message.type === "taskSucceeded") { } else if (message.type === "taskSucceeded") {
const toast = makeToast(message.taskId, t("import.successful")); const toast = makeToast(message.taskId, t("import.successful"));
toast.closeAfter = 5000; toast.timeout = 5000;
toastService.showPersistent(toast); toastService.showPersistent(toast);
@@ -100,7 +100,7 @@ ws.subscribeToMessages(async (message: WebSocketMessage) => {
toastService.showPersistent(makeToast(message.taskId, t("import.in-progress", { progress: message.progressCount }))); toastService.showPersistent(makeToast(message.taskId, t("import.in-progress", { progress: message.progressCount })));
} else if (message.type === "taskSucceeded") { } else if (message.type === "taskSucceeded") {
const toast = makeToast(message.taskId, t("import.successful")); const toast = makeToast(message.taskId, t("import.successful"));
toast.closeAfter = 5000; toast.timeout = 5000;
toastService.showPersistent(toast); toastService.showPersistent(toast);

View File

@@ -1,10 +1,11 @@
import treeService from "./tree.js";
import linkContextMenuService from "../menus/link_context_menu.js";
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 { ALLOWED_PROTOCOLS } from "@triliumnext/commons";
import appContext, { type NoteCommandData } from "../components/app_context.js";
import { openInCurrentNoteContext } from "../components/note_context.js"; import { openInCurrentNoteContext } from "../components/note_context.js";
import linkContextMenuService from "../menus/link_context_menu.js";
import froca from "./froca.js";
import treeService from "./tree.js";
import utils from "./utils.js";
function getNotePathFromUrl(url: string) { function getNotePathFromUrl(url: string) {
const notePathMatch = /#(root[A-Za-z0-9_/]*)$/.exec(url); const notePathMatch = /#(root[A-Za-z0-9_/]*)$/.exec(url);
@@ -27,7 +28,7 @@ async function getLinkIcon(noteId: string, viewMode: ViewMode | undefined) {
return icon; return icon;
} }
export type ViewMode = "default" | "source" | "attachments" | "contextual-help"; export type ViewMode = "default" | "source" | "attachments" | "contextual-help" | "note-map";
export interface ViewScope { export interface ViewScope {
/** /**
@@ -99,7 +100,7 @@ async function createLink(notePath: string | undefined, options: CreateLinkOptio
const viewMode = viewScope.viewMode || "default"; const viewMode = viewScope.viewMode || "default";
let linkTitle = options.title; let linkTitle = options.title;
if (!linkTitle) { if (linkTitle === undefined) {
if (viewMode === "attachments" && viewScope.attachmentId) { if (viewMode === "attachments" && viewScope.attachmentId) {
const attachment = await froca.getAttachment(viewScope.attachmentId); const attachment = await froca.getAttachment(viewScope.attachmentId);
@@ -122,7 +123,7 @@ async function createLink(notePath: string | undefined, options: CreateLinkOptio
const $container = $("<span>"); const $container = $("<span>");
if (showNoteIcon) { if (showNoteIcon) {
let icon = await getLinkIcon(noteId, viewMode); const icon = await getLinkIcon(noteId, viewMode);
if (icon) { if (icon) {
$container.append($("<span>").addClass(`bx ${icon}`)).append(" "); $container.append($("<span>").addClass(`bx ${icon}`)).append(" ");
@@ -131,7 +132,7 @@ async function createLink(notePath: string | undefined, options: CreateLinkOptio
const hash = calculateHash({ const hash = calculateHash({
notePath, notePath,
viewScope: viewScope viewScope
}); });
const $noteLink = $("<a>", { const $noteLink = $("<a>", {
@@ -171,11 +172,11 @@ async function createLink(notePath: string | undefined, options: CreateLinkOptio
return $container; return $container;
} }
function calculateHash({ notePath, ntxId, hoistedNoteId, viewScope = {} }: NoteCommandData) { export function calculateHash({ notePath, ntxId, hoistedNoteId, viewScope = {} }: NoteCommandData) {
notePath = notePath || ""; notePath = notePath || "";
const params = [ const params = [
ntxId ? { ntxId: ntxId } : null, ntxId ? { ntxId } : null,
hoistedNoteId && hoistedNoteId !== "root" ? { hoistedNoteId: hoistedNoteId } : null, hoistedNoteId && hoistedNoteId !== "root" ? { hoistedNoteId } : null,
viewScope.viewMode && viewScope.viewMode !== "default" ? { viewMode: viewScope.viewMode } : null, viewScope.viewMode && viewScope.viewMode !== "default" ? { viewMode: viewScope.viewMode } : null,
viewScope.attachmentId ? { attachmentId: viewScope.attachmentId } : null viewScope.attachmentId ? { attachmentId: viewScope.attachmentId } : null
].filter((p) => !!p); ].filter((p) => !!p);
@@ -219,7 +220,7 @@ export function parseNavigationStateFromUrl(url: string | undefined) {
} }
const hash = url.substr(hashIdx + 1); // strip also the initial '#' const hash = url.substr(hashIdx + 1); // strip also the initial '#'
let [notePath, paramString] = hash.split("?"); const [notePath, paramString] = hash.split("?");
const viewScope: ViewScope = { const viewScope: ViewScope = {
viewMode: "default" viewMode: "default"
@@ -252,7 +253,7 @@ export function parseNavigationStateFromUrl(url: string | undefined) {
} }
if (searchString) { if (searchString) {
return { searchString } return { searchString };
} }
if (!notePath.match(/^[_a-z0-9]{4,}(\/[_a-z0-9]{4,})*$/i)) { if (!notePath.match(/^[_a-z0-9]{4,}(\/[_a-z0-9]{4,})*$/i)) {
@@ -334,7 +335,7 @@ export function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDo
window.open(hrefLink, "_blank"); window.open(hrefLink, "_blank");
} else { } else {
// Enable protocols supported by CKEditor 5 to be clickable. // Enable protocols supported by CKEditor 5 to be clickable.
if (ALLOWED_PROTOCOLS.some((protocol) => hrefLink.toLowerCase().startsWith(protocol + ":"))) { if (ALLOWED_PROTOCOLS.some((protocol) => hrefLink.toLowerCase().startsWith(`${protocol}:`))) {
if ( utils.isElectron()) { if ( utils.isElectron()) {
const electron = utils.dynamicRequire("electron"); const electron = utils.dynamicRequire("electron");
electron.shell.openExternal(hrefLink); electron.shell.openExternal(hrefLink);
@@ -395,7 +396,7 @@ async function loadReferenceLinkTitle($el: JQuery<HTMLElement>, href: string | n
href = href || $link.attr("href"); href = href || $link.attr("href");
if (!href) { if (!href) {
console.warn("Empty URL for parsing: " + $el[0].outerHTML); console.warn(`Empty URL for parsing: ${$el[0].outerHTML}`);
return; return;
} }
@@ -438,9 +439,9 @@ async function getReferenceLinkTitle(href: string) {
const attachment = await note.getAttachmentById(viewScope.attachmentId); const attachment = await note.getAttachmentById(viewScope.attachmentId);
return attachment ? attachment.title : "[missing attachment]"; return attachment ? attachment.title : "[missing attachment]";
} else {
return note.title;
} }
return note.title;
} }
function getReferenceLinkTitleSync(href: string) { function getReferenceLinkTitleSync(href: string) {
@@ -462,9 +463,9 @@ function getReferenceLinkTitleSync(href: string) {
const attachment = note.attachments.find((att) => att.attachmentId === viewScope.attachmentId); const attachment = note.attachments.find((att) => att.attachmentId === viewScope.attachmentId);
return attachment ? attachment.title : "[missing attachment]"; return attachment ? attachment.title : "[missing attachment]";
} else {
return note.title;
} }
return note.title;
} }
if (glob.device !== "print") { if (glob.device !== "print") {

View File

@@ -1,7 +1,7 @@
import server from "./server.js"; import server from "./server.js";
import protectedSessionHolder from "./protected_session_holder.js"; import protectedSessionHolder from "./protected_session_holder.js";
import toastService from "./toast.js"; import toastService from "./toast.js";
import type { ToastOptions } from "./toast.js"; import type { ToastOptionsWithRequiredId } from "./toast.js";
import ws from "./ws.js"; import ws from "./ws.js";
import appContext from "../components/app_context.js"; import appContext from "../components/app_context.js";
import froca from "./froca.js"; import froca from "./froca.js";
@@ -97,7 +97,7 @@ async function protectNote(noteId: string, protect: boolean, includingSubtree: b
await server.put(`notes/${noteId}/protect/${protect ? 1 : 0}?subtree=${includingSubtree ? 1 : 0}`); await server.put(`notes/${noteId}/protect/${protect ? 1 : 0}?subtree=${includingSubtree ? 1 : 0}`);
} }
function makeToast(message: Message, title: string, text: string): ToastOptions { function makeToast(message: Message, title: string, text: string): ToastOptionsWithRequiredId {
return { return {
id: message.taskId, id: message.taskId,
title, title,
@@ -124,7 +124,7 @@ ws.subscribeToMessages(async (message) => {
} else if (message.type === "taskSucceeded") { } else if (message.type === "taskSucceeded") {
const text = isProtecting ? t("protected_session.protecting-finished-successfully") : t("protected_session.unprotecting-finished-successfully"); const text = isProtecting ? t("protected_session.protecting-finished-successfully") : t("protected_session.unprotecting-finished-successfully");
const toast = makeToast(message, title, text); const toast = makeToast(message, title, text);
toast.closeAfter = 3000; toast.timeout = 3000;
toastService.showPersistent(toast); toastService.showPersistent(toast);
} }

View File

@@ -1,6 +1,10 @@
import server from "./server.js"; import { h, VNode } from "preact";
import bundleService, { type Bundle } from "./bundle.js";
import type FNote from "../entities/fnote.js"; import type FNote from "../entities/fnote.js";
import { renderReactWidgetAtElement } from "../widgets/react/react_utils.jsx";
import bundleService, { type Bundle } from "./bundle.js";
import froca from "./froca.js";
import server from "./server.js";
async function render(note: FNote, $el: JQuery<HTMLElement>) { async function render(note: FNote, $el: JQuery<HTMLElement>) {
const relations = note.getRelations("renderNote"); const relations = note.getRelations("renderNote");
@@ -17,12 +21,34 @@ async function render(note: FNote, $el: JQuery<HTMLElement>) {
$scriptContainer.append(bundle.html); $scriptContainer.append(bundle.html);
// async so that scripts cannot block trilium execution // async so that scripts cannot block trilium execution
bundleService.executeBundle(bundle, note, $scriptContainer); bundleService.executeBundle(bundle, note, $scriptContainer).then(result => {
// Render JSX
if (bundle.html === "") {
renderIfJsx(bundle, result, $el);
}
});
} }
return renderNoteIds.length > 0; return renderNoteIds.length > 0;
} }
async function renderIfJsx(bundle: Bundle, result: unknown, $el: JQuery<HTMLElement>) {
// Ensure the root script note is actually a JSX.
const rootScriptNoteId = await froca.getNote(bundle.noteId);
if (rootScriptNoteId?.mime !== "text/jsx") return;
// Ensure the output is a valid el.
if (typeof result !== "function") return;
// Obtain the parent component.
const closestComponent = glob.getComponentByEl($el.closest(".component")[0]);
if (!closestComponent) return;
// Render the element.
const el = h(result as () => VNode, {});
renderReactWidgetAtElement(closestComponent, el, $el[0]);
}
export default { export default {
render render
}; };

View File

@@ -133,11 +133,11 @@ async function call<T>(method: string, url: string, componentId?: string, option
}; };
ipc.send("server-request", { ipc.send("server-request", {
requestId: requestId, requestId,
headers: headers, headers,
method: method, method,
url: `/${window.glob.baseApiUrl}${url}`, url: `/${window.glob.baseApiUrl}${url}`,
data: data data
}); });
})) as any; })) as any;
} else { } else {
@@ -161,7 +161,7 @@ function ajax(url: string, method: string, data: unknown, headers: Headers, sile
const options: JQueryAjaxSettings = { const options: JQueryAjaxSettings = {
url: window.glob.baseApiUrl + url, url: window.glob.baseApiUrl + url,
type: method, type: method,
headers: headers, headers,
timeout: 60000, timeout: 60000,
success: (body, textStatus, jqXhr) => { success: (body, textStatus, jqXhr) => {
const respHeaders: Headers = {}; const respHeaders: Headers = {};
@@ -263,7 +263,7 @@ async function reportError(method: string, url: string, statusCode: number, resp
const toastService = (await import("./toast.js")).default; const toastService = (await import("./toast.js")).default;
const messageStr = typeof message === "string" ? message : JSON.stringify(message); const messageStr = (typeof message === "string" ? message : JSON.stringify(message)) || "-";
if ([400, 404].includes(statusCode) && response && typeof response === "object") { if ([400, 404].includes(statusCode) && response && typeof response === "object") {
toastService.showError(messageStr); toastService.showError(messageStr);
@@ -274,10 +274,22 @@ async function reportError(method: string, url: string, statusCode: number, resp
...response ...response
}); });
} else { } else {
const title = `${statusCode} ${method} ${url}`; const { t } = await import("./i18n.js");
toastService.showErrorTitleAndMessage(title, messageStr); if (statusCode === 400 && (url.includes("%23") || url.includes("%2F"))) {
const { throwError } = await import("./ws.js"); toastService.showPersistent({
throwError(`${title} - ${message}`); id: "trafik-blocked",
icon: "bx bx-unlink",
title: t("server.unknown_http_error_title"),
message: t("server.traefik_blocks_requests")
});
} else {
toastService.showErrorTitleAndMessage(
t("server.unknown_http_error_title"),
t("server.unknown_http_error_content", { statusCode, method, url, message: messageStr }),
15_000);
}
const { logError } = await import("./ws.js");
logError(`${statusCode} ${method} ${url} - ${message}`);
} }
} }

View File

@@ -1,7 +1,7 @@
import utils from "./utils.js"; import utils from "./utils.js";
type ElementType = HTMLElement | Document; type ElementType = HTMLElement | Document;
type Handler = (e: KeyboardEvent) => void; export type Handler = (e: KeyboardEvent) => void;
export interface ShortcutBinding { export interface ShortcutBinding {
element: HTMLElement | Document; element: HTMLElement | Document;

View File

@@ -1,3 +1,8 @@
import { signal } from "@preact/signals";
import appContext from "../components/app_context.js";
import froca from "./froca.js";
import { t } from "./i18n.js";
import utils from "./utils.js"; import utils from "./utils.js";
export interface ToastOptions { export interface ToastOptions {
@@ -5,117 +10,102 @@ export interface ToastOptions {
icon: string; icon: string;
title?: string; title?: string;
message: string; message: string;
delay?: number; timeout?: number;
autohide?: boolean;
closeAfter?: number;
progress?: number; progress?: number;
buttons?: {
text: string;
onClick: (api: { dismissToast: () => void }) => void;
}[];
} }
function toast({ title, icon, message, id, delay, autohide, progress }: ToastOptions) { export type ToastOptionsWithRequiredId = Omit<ToastOptions, "id"> & Required<Pick<ToastOptions, "id">>;
const $toast = $(title
? `\
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="me-auto">
<span class="bx bx-${icon}"></span>
<span class="toast-title"></span>
</strong>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body"></div>
<div class="toast-progress"></div>
</div>`
: `
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-icon">
<span class="bx bx-${icon}"></span>
</div>
<div class="toast-body"></div>
<div class="toast-header">
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-progress"></div>
</div>`
);
$toast.toggleClass("no-title", !title); function showPersistent(options: ToastOptionsWithRequiredId) {
$toast.find(".toast-title").text(title ?? ""); const existingToast = toasts.value.find(toast => toast.id === options.id);
$toast.find(".toast-body").html(message); if (existingToast) {
$toast.find(".toast-progress").css("width", `${(progress ?? 0) * 100}%`); updateToast(options.id, options);
if (id) {
$toast.attr("id", `toast-${id}`);
}
$("#toast-container").append($toast);
$toast.toast({
delay: delay || 3000,
autohide: !!autohide
});
$toast.on("hidden.bs.toast", (e) => e.target.remove());
$toast.toast("show");
return $toast;
}
function showPersistent(options: ToastOptions) {
let $toast = $(`#toast-${options.id}`);
if ($toast.length > 0) {
$toast.find(".toast-body").html(options.message);
$toast.find(".toast-progress").css("width", `${(options.progress ?? 0) * 100}%`);
} else { } else {
options.autohide = false; addToast(options);
$toast = toast(options);
}
if (options.closeAfter) {
setTimeout(() => $toast.remove(), options.closeAfter);
} }
} }
function closePersistent(id: string) { function closePersistent(id: string) {
$(`#toast-${id}`).remove(); removeToastFromStore(id);
} }
function showMessage(message: string, delay = 2000, icon = "check") { function showMessage(message: string, timeout = 2000, icon = "bx bx-check") {
console.debug(utils.now(), "message:", message); console.debug(utils.now(), "message:", message);
toast({ addToast({
icon, icon,
message: message, message,
autohide: true, timeout
delay
}); });
} }
export function showError(message: string, delay = 10000) { export function showError(message: string, timeout = 10000) {
console.log(utils.now(), "error: ", message); console.log(utils.now(), "error: ", message);
toast({ addToast({
icon: "alert", icon: "bx bx-error-circle",
message: message, message,
autohide: true, timeout
delay
}); });
} }
function showErrorTitleAndMessage(title: string, message: string, delay = 10000) { function showErrorTitleAndMessage(title: string, message: string, timeout = 10000) {
console.log(utils.now(), "error: ", message); console.log(utils.now(), "error: ", message);
toast({ addToast({
title: title, title,
icon: "alert", icon: "bx bx-error-circle",
message: message, message,
autohide: true, timeout
delay
}); });
} }
export async function showErrorForScriptNote(noteId: string, message: string) {
const note = await froca.getNote(noteId, true);
showPersistent({
id: `custom-widget-failure-${noteId}`,
title: note?.title ?? "",
icon: note?.getIcon() ?? "bx bx-error-circle",
message,
timeout: 15_000,
buttons: [
{
text: t("toast.open-script-note"),
onClick: () => appContext.tabManager.openInNewTab(noteId, null, true)
}
]
});
}
//#region Toast store
export const toasts = signal<ToastOptionsWithRequiredId[]>([]);
function addToast(opts: ToastOptions) {
const id = opts.id ?? crypto.randomUUID();
const toast = { ...opts, id };
toasts.value = [ ...toasts.value, toast ];
return id;
}
function updateToast(id: string, partial: Partial<ToastOptions>) {
toasts.value = toasts.value.map(toast => {
if (toast.id === id) {
return { ...toast, ...partial };
}
return toast;
});
}
export function removeToastFromStore(id: string) {
toasts.value = toasts.value.filter(toast => toast.id !== id);
}
//#endregion
export default { export default {
showMessage, showMessage,
showError, showError,

View File

@@ -4,6 +4,8 @@ import froca from "./froca.js";
import hoistedNoteService from "./hoisted_note.js"; import hoistedNoteService from "./hoisted_note.js";
import appContext from "../components/app_context.js"; import appContext from "../components/app_context.js";
export const NOTE_PATH_TITLE_SEPARATOR = " ";
async function resolveNotePath(notePath: string, hoistedNoteId = "root") { async function resolveNotePath(notePath: string, hoistedNoteId = "root") {
const runPath = await resolveNotePathToSegments(notePath, hoistedNoteId); const runPath = await resolveNotePathToSegments(notePath, hoistedNoteId);
@@ -254,7 +256,7 @@ async function getNotePathTitle(notePath: string) {
const titlePath = await getNotePathTitleComponents(notePath); const titlePath = await getNotePathTitleComponents(notePath);
return titlePath.join(" / "); return titlePath.join(NOTE_PATH_TITLE_SEPARATOR);
} }
async function getNoteTitleWithPathAsSuffix(notePath: string) { async function getNoteTitleWithPathAsSuffix(notePath: string) {

View File

@@ -1,6 +1,7 @@
import { dayjs } from "@triliumnext/commons"; import { dayjs } from "@triliumnext/commons";
import type { ViewScope } from "./link.js"; import type { ViewMode, ViewScope } from "./link.js";
import FNote from "../entities/fnote"; import FNote from "../entities/fnote";
import { snapdom } from "@zumer/snapdom";
const SVG_MIME = "image/svg+xml"; const SVG_MIME = "image/svg+xml";
@@ -150,7 +151,7 @@ export function isMac() {
export const hasTouchBar = (isMac() && isElectron()); export const hasTouchBar = (isMac() && isElectron());
function isCtrlKey(evt: KeyboardEvent | MouseEvent | JQuery.ClickEvent | JQuery.ContextMenuEvent | JQuery.TriggeredEvent | React.PointerEvent<HTMLCanvasElement> | JQueryEventObject) { export function isCtrlKey(evt: KeyboardEvent | MouseEvent | JQuery.ClickEvent | JQuery.ContextMenuEvent | JQuery.TriggeredEvent | React.PointerEvent<HTMLCanvasElement> | JQueryEventObject) {
return (!isMac() && evt.ctrlKey) || (isMac() && evt.metaKey); return (!isMac() && evt.ctrlKey) || (isMac() && evt.metaKey);
} }
@@ -236,7 +237,7 @@ export function isIOS() {
return /iPad|iPhone|iPod/.test(navigator.userAgent); return /iPad|iPhone|iPod/.test(navigator.userAgent);
} }
function isDesktop() { export function isDesktop() {
return ( return (
window.glob?.device === "desktop" || window.glob?.device === "desktop" ||
// window.glob.device is not available in setup // window.glob.device is not available in setup
@@ -438,7 +439,20 @@ async function openInAppHelp($button: JQuery<HTMLElement>) {
* @param inAppHelpPage the ID of the help note (excluding the `_help_` prefix). * @param inAppHelpPage the ID of the help note (excluding the `_help_` prefix).
* @returns a promise that resolves once the help has been opened. * @returns a promise that resolves once the help has been opened.
*/ */
export async function openInAppHelpFromUrl(inAppHelpPage: string) { export function openInAppHelpFromUrl(inAppHelpPage: string) {
return openInReusableSplit(`_help_${inAppHelpPage}`, "contextual-help");
}
/**
* Similar to opening a new note in a split, but re-uses an existing split if there is already one open with the same view mode.
*
* @param targetNoteId the note ID to open in the split.
* @param targetViewMode the view mode of the split to open the note in.
* @param openOpts additional options for opening the note.
*/
export async function openInReusableSplit(targetNoteId: string, targetViewMode: ViewMode, openOpts: {
hoistedNoteId?: string;
} = {}) {
// Dynamic import to avoid import issues in tests. // Dynamic import to avoid import issues in tests.
const appContext = (await import("../components/app_context.js")).default; const appContext = (await import("../components/app_context.js")).default;
const activeContext = appContext.tabManager.getActiveContext(); const activeContext = appContext.tabManager.getActiveContext();
@@ -446,23 +460,20 @@ export async function openInAppHelpFromUrl(inAppHelpPage: string) {
return; return;
} }
const subContexts = activeContext.getSubContexts(); const subContexts = activeContext.getSubContexts();
const targetNote = `_help_${inAppHelpPage}`; const existingSubcontext = subContexts.find((s) => s.viewScope?.viewMode === targetViewMode);
const helpSubcontext = subContexts.find((s) => s.viewScope?.viewMode === "contextual-help"); const viewScope: ViewScope = { viewMode: targetViewMode };
const viewScope: ViewScope = { if (!existingSubcontext) {
viewMode: "contextual-help", // The target split is not already open, open a new split with it.
};
if (!helpSubcontext) {
// The help is not already open, open a new split with it.
const { ntxId } = subContexts[subContexts.length - 1]; const { ntxId } = subContexts[subContexts.length - 1];
appContext.triggerCommand("openNewNoteSplit", { appContext.triggerCommand("openNewNoteSplit", {
ntxId, ntxId,
notePath: targetNote, notePath: targetNoteId,
hoistedNoteId: "_help", hoistedNoteId: openOpts.hoistedNoteId,
viewScope viewScope
}) });
} else { } else {
// There is already a help window open, make sure it opens on the right note. // There is already a target split open, make sure it opens on the right note.
helpSubcontext.setNote(targetNote, { viewScope }); existingSubcontext.setNote(targetNoteId, { viewScope });
} }
} }
@@ -628,16 +639,69 @@ export function createImageSrcUrl(note: FNote) {
return `api/images/${note.noteId}/${encodeURIComponent(note.title)}?timestamp=${Date.now()}`; return `api/images/${note.noteId}/${encodeURIComponent(note.title)}?timestamp=${Date.now()}`;
} }
/** /**
* Given a string representation of an SVG, triggers a download of the file on the client device. * Helper function to prepare an element for snapdom rendering.
* Handles string parsing and temporary DOM attachment for style computation.
*
* @param source - Either an SVG/HTML string to be parsed, or an existing SVG/HTML element.
* @returns An object containing the prepared element and a cleanup function.
* The cleanup function removes temporarily attached elements from the DOM,
* or is a no-op if the element was already in the DOM.
*/
function prepareElementForSnapdom(source: string | SVGElement | HTMLElement): {
element: SVGElement | HTMLElement;
cleanup: () => void;
} {
if (typeof source === 'string') {
const parser = new DOMParser();
// Detect if content is SVG or HTML
const isSvg = source.trim().startsWith('<svg');
const mimeType = isSvg ? SVG_MIME : 'text/html';
const doc = parser.parseFromString(source, mimeType);
const element = doc.documentElement;
// Temporarily attach to DOM for proper style computation
element.style.position = 'absolute';
element.style.left = '-9999px';
element.style.top = '-9999px';
document.body.appendChild(element);
return {
element,
cleanup: () => document.body.removeChild(element)
};
}
return {
element: source,
cleanup: () => {} // No-op for existing elements
};
}
/**
* Downloads an SVG using snapdom for proper rendering. Can accept either an SVG string, an SVG element, or an HTML element.
* *
* @param nameWithoutExtension the name of the file. The .svg suffix is automatically added to it. * @param nameWithoutExtension the name of the file. The .svg suffix is automatically added to it.
* @param svgContent the content of the SVG file download. * @param svgSource either an SVG string, an SVGElement, or an HTMLElement to be downloaded.
*/ */
function downloadSvg(nameWithoutExtension: string, svgContent: string) { async function downloadAsSvg(nameWithoutExtension: string, svgSource: string | SVGElement | HTMLElement) {
const filename = `${nameWithoutExtension}.svg`; const { element, cleanup } = prepareElementForSnapdom(svgSource);
const dataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgContent)}`;
triggerDownload(filename, dataUrl); try {
const result = await snapdom(element, {
backgroundColor: "transparent",
scale: 2
});
triggerDownload(`${nameWithoutExtension}.svg`, result.url);
} finally {
cleanup();
}
} }
/** /**
@@ -658,62 +722,26 @@ function triggerDownload(fileName: string, dataUrl: string) {
document.body.removeChild(element); document.body.removeChild(element);
} }
/** /**
* Given a string representation of an SVG, renders the SVG to PNG and triggers a download of the file on the client device. * Downloads an SVG as PNG using snapdom. Can accept either an SVG string, an SVG element, or an HTML element.
*
* Note that the SVG must specify its width and height as attributes in order for it to be rendered.
* *
* @param nameWithoutExtension the name of the file. The .png suffix is automatically added to it. * @param nameWithoutExtension the name of the file. The .png suffix is automatically added to it.
* @param svgContent the content of the SVG file download. * @param svgSource either an SVG string, an SVGElement, or an HTMLElement to be converted to PNG.
* @returns a promise which resolves if the operation was successful, or rejects if it failed (permissions issue or some other issue).
*/ */
function downloadSvgAsPng(nameWithoutExtension: string, svgContent: string) { async function downloadAsPng(nameWithoutExtension: string, svgSource: string | SVGElement | HTMLElement) {
return new Promise<void>((resolve, reject) => { const { element, cleanup } = prepareElementForSnapdom(svgSource);
// First, we need to determine the width and the height from the input SVG.
const result = getSizeFromSvg(svgContent);
if (!result) {
reject();
return;
}
// Convert the image to a blob.
const { width, height } = result;
// Create an image element and load the SVG.
const imageEl = new Image();
imageEl.width = width;
imageEl.height = height;
imageEl.crossOrigin = "anonymous";
imageEl.onload = () => {
try { try {
// Draw the image with a canvas. const result = await snapdom(element, {
const canvasEl = document.createElement("canvas"); backgroundColor: "transparent",
canvasEl.width = imageEl.width; scale: 2
canvasEl.height = imageEl.height;
document.body.appendChild(canvasEl);
const ctx = canvasEl.getContext("2d");
if (!ctx) {
reject();
}
ctx?.drawImage(imageEl, 0, 0);
const imgUri = canvasEl.toDataURL("image/png")
triggerDownload(`${nameWithoutExtension}.png`, imgUri);
document.body.removeChild(canvasEl);
resolve();
} catch (e) {
console.warn(e);
reject();
}
};
imageEl.onerror = (e) => reject(e);
imageEl.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgContent)}`;
}); });
const pngImg = await result.toPng();
await triggerDownload(`${nameWithoutExtension}.png`, pngImg.src);
} finally {
cleanup();
}
} }
export function getSizeFromSvg(svgContent: string) { export function getSizeFromSvg(svgContent: string) {
const svgDocument = (new DOMParser()).parseFromString(svgContent, SVG_MIME); const svgDocument = (new DOMParser()).parseFromString(svgContent, SVG_MIME);
@@ -925,8 +953,8 @@ export default {
areObjectsEqual, areObjectsEqual,
copyHtmlToClipboard, copyHtmlToClipboard,
createImageSrcUrl, createImageSrcUrl,
downloadSvg, downloadAsSvg,
downloadSvgAsPng, downloadAsPng,
compareVersions, compareVersions,
isUpdateAvailable, isUpdateAvailable,
isLaunchBarConfig isLaunchBarConfig

View File

@@ -423,16 +423,16 @@ body.desktop .tabulator-popup-container,
pointer-events: none; pointer-events: none;
} }
.dropdown-menu .disabled .disabled-tooltip { .dropdown-menu .disabled .contextual-help {
pointer-events: all; pointer-events: all;
margin-inline-start: 8px; margin-inline-start: 8px;
font-size: 0.75rem; font-size: 0.75rem;
color: var(--disabled-tooltip-icon-color); color: var(--contextual-help-icon-color);
cursor: help; cursor: help;
opacity: 0.75; opacity: 0.75;
} }
.dropdown-menu .disabled .disabled-tooltip:hover { .dropdown-menu .disabled .contextual-help:hover {
opacity: 1; opacity: 1;
} }
@@ -521,9 +521,7 @@ body.mobile .dropdown .dropdown-submenu > span {
.cm-editor { .cm-editor {
height: 100%; height: 100%;
outline: none !important; outline: none !important;
border-radius: 6px;
overflow: hidden; overflow: hidden;
margin: 4px;
font-size: var(--monospace-font-size); font-size: var(--monospace-font-size);
} }
@@ -629,6 +627,11 @@ pre:not(.hljs) {
padding: var(--padding-size); padding: var(--padding-size);
} }
pre:has(> .cm-editor) {
padding: 0;
margin: 0;
}
pre > button.copy-button { pre > button.copy-button {
position: absolute; position: absolute;
top: var(--copy-button-margin-size); top: var(--copy-button-margin-size);
@@ -714,12 +717,17 @@ table.promoted-attributes-in-tooltip th {
.tooltip { .tooltip {
font-size: var(--main-font-size) !important; font-size: var(--main-font-size) !important;
z-index: calc(var(--ck-z-panel) - 1) !important; z-index: calc(var(--ck-z-panel) - 1) !important;
white-space: pre-wrap;
} }
.tooltip.tooltip-top { .tooltip.tooltip-top {
z-index: 32767 !important; z-index: 32767 !important;
} }
.pre-wrap-text {
white-space: pre-wrap;
}
.bs-tooltip-bottom .tooltip-arrow::before { .bs-tooltip-bottom .tooltip-arrow::before {
border-bottom-color: var(--main-border-color) !important; border-bottom-color: var(--main-border-color) !important;
} }
@@ -1015,16 +1023,10 @@ div[data-notify="container"] {
font-family: var(--monospace-font-family); font-family: var(--monospace-font-family);
} }
svg.ck-icon { svg.ck-icon.note-icon {
&.ck-icon_inherit-color path[fill="#333"] {
fill: currentColor;
}
&.note-icon {
color: var(--main-text-color); color: var(--main-text-color);
font-size: 20px; font-size: 20px;
} }
}
.ck-content { .ck-content {
--ck-content-font-family: var(--detail-font-family); --ck-content-font-family: var(--detail-font-family);
@@ -1141,61 +1143,6 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
margin: 0 12px; margin: 0 12px;
} }
#toast-container {
position: absolute;
width: 100%;
top: 20px;
pointer-events: none;
}
.toast {
--bs-toast-bg: var(--accented-background-color);
--bs-toast-color: var(--main-text-color);
z-index: 9999999999 !important;
pointer-events: all;
overflow: hidden;
}
.toast-header {
background-color: var(--more-accented-background-color) !important;
color: var(--main-text-color) !important;
}
.toast-body {
white-space: preserve-breaks;
overflow: hidden;
}
.toast.no-title {
display: flex;
flex-direction: row;
}
.toast.no-title .toast-icon {
display: flex;
align-items: center;
padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x);
}
.toast.no-title .toast-body {
padding-inline-start: 0;
padding-inline-end: 0;
}
.toast.no-title .toast-header {
background-color: unset !important;
}
.toast .toast-progress {
position: absolute;
bottom: 0;
inset-inline-start: 0;
inset-inline-end: 0;
background-color: var(--toast-text-color) !important;
height: 4px;
transition: width 0.1s linear;
}
.ck-mentions .ck-button { .ck-mentions .ck-button {
font-size: var(--detail-font-size) !important; font-size: var(--detail-font-size) !important;
padding: 5px; padding: 5px;
@@ -1376,12 +1323,21 @@ body.desktop li.dropdown-submenu:hover > ul.dropdown-menu {
top: 0; top: 0;
inset-inline-start: calc(100% - 2px); /* -2px, otherwise there's a small gap between menu and submenu where the hover can disappear */ inset-inline-start: calc(100% - 2px); /* -2px, otherwise there's a small gap between menu and submenu where the hover can disappear */
margin-top: -10px; margin-top: -10px;
min-width: 15rem;
/* to make submenu scrollable https://github.com/zadam/trilium/issues/3136 */ /* to make submenu scrollable https://github.com/zadam/trilium/issues/3136 */
max-height: 600px; max-height: 600px;
overflow: auto; overflow: auto;
} }
body.desktop .dropdown-submenu > .dropdown-menu {
min-width: max-content;
max-width: 300px;
}
.dropdown-submenu.dropstart > .dropdown-menu {
inset-inline-start: auto;
inset-inline-end: calc(100% - 2px);
}
body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu { body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
inset-inline-start: calc(-100% + 10px); inset-inline-start: calc(-100% + 10px);
} }
@@ -1428,6 +1384,10 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
background-color: var(--scrollbar-background-color); background-color: var(--scrollbar-background-color);
} }
::-webkit-scrollbar-button {
display: none;
}
::-webkit-scrollbar-corner { ::-webkit-scrollbar-corner {
background-color: inherit; background-color: inherit;
} }
@@ -2001,7 +1961,7 @@ body.electron.platform-darwin:not(.native-titlebar):not(.full-screen) #tab-row-l
width: 80px; width: 80px;
} }
.tab-row-widget { .tab-row-container {
padding-inline-end: calc(100vw - env(titlebar-area-width, 100vw)); padding-inline-end: calc(100vw - env(titlebar-area-width, 100vw));
} }
@@ -2161,7 +2121,8 @@ body.zen:not(.backdrop-effects-disabled) .note-split.type-text .scrolling-contai
/* Fixed formatting toolbar */ /* Fixed formatting toolbar */
body.zen .note-split .ribbon-container { body.zen:not(.experimental-feature-new-layout) {
.note-split .ribbon-container {
position: fixed; position: fixed;
left: 0; left: 0;
bottom: 20px; bottom: 20px;
@@ -2172,15 +2133,15 @@ body.zen .note-split .ribbon-container {
transition: opacity 100ms linear; transition: opacity 100ms linear;
} }
body.zen .note-split:focus-within .ribbon-container { .note-split:focus-within .ribbon-container {
opacity: 1; /* Show when the note split is focused */ opacity: 1; /* Show when the note split is focused */
} }
body.zen .note-split .ribbon-container .ribbon-body { .note-split .ribbon-container .ribbon-body {
border: 0; border: 0;
} }
body.zen .note-split .ribbon-container .classic-toolbar-widget { .note-split .ribbon-container .classic-toolbar-widget {
margin: auto; margin: auto;
width: fit-content; width: fit-content;
box-shadow: 0px 10px 20px rgba(0, 0, 0, .1); box-shadow: 0px 10px 20px rgba(0, 0, 0, .1);
@@ -2190,31 +2151,78 @@ body.zen .note-split .ribbon-container .classic-toolbar-widget {
background: var(--menu-background-color); background: var(--menu-background-color);
} }
body.zen .note-split .ribbon-container .classic-toolbar-widget:not(:has(> .ck-toolbar)) { .note-split .ribbon-container .classic-toolbar-widget:not(:has(> .ck-toolbar)) {
/* Hide the toolbar wrapper if the toolbar is missing */ /* Hide the toolbar wrapper if the toolbar is missing */
display: none; display: none;
} }
body.zen .note-split:focus-within .ribbon-container .classic-toolbar-widget { .note-split:focus-within .ribbon-container .classic-toolbar-widget {
pointer-events: all; pointer-events: all;
} }
@media (max-width: 1300px) { @media (max-width: 1300px) {
body.zen .note-split .ribbon-container .classic-toolbar-widget { .note-split .ribbon-container .classic-toolbar-widget {
/* Set the toolbar to full with */ /* Set the toolbar to full with */
width: 100%; width: 100%;
} }
body.zen .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se, .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se,
body.zen .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw, .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw,
body.zen .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_smw, .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_smw,
body.zen .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sme, .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sme,
body.zen .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_s { .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_s {
/* Force toolbar items overflow dropdowns open upwards */ /* Force toolbar items overflow dropdowns open upwards */
top: auto; top: auto;
bottom: 100%; bottom: 100%;
} }
} }
}
body.zen.experimental-feature-new-layout {
.status-bar {
display: none;
}
.classic-toolbar-widget {
position: fixed;
left: 50%;
bottom: 20px;
z-index: 1000;
opacity: 0; /* Hidden unless the current note split is focused */
pointer-events: none;
transition: opacity 100ms linear;
width: fit-content;
box-shadow: 0px 10px 20px rgba(0, 0, 0, .1);
border-radius: 8px;
border: 1px solid var(--main-border-color);
padding: 4px;
background: var(--menu-background-color);
transform: translateX(-50%);
}
#root-widget:has(.note-split.type-text:focus-within) .classic-toolbar-widget,
.classic-toolbar-widget:focus-within {
opacity: 1; /* Show when the note split is focused */
pointer-events: all;
}
@media (max-width: 1300px) {
.classic-toolbar-widget {
/* Set the toolbar to full with */
width: 100%;
}
.classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se,
.classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw,
.classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_smw,
.classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sme,
.classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_s {
/* Force toolbar items overflow dropdowns open upwards */
top: auto;
bottom: 100%;
}
}
}
/* Content renderer */ /* Content renderer */
@@ -2519,6 +2527,11 @@ footer.webview-footer button {
inset-inline-start: 10px; inset-inline-start: 10px;
} }
.content-floating-buttons.top-right {
top: 10px;
inset-inline-end: 10px;
}
.content-floating-buttons.bottom-left { .content-floating-buttons.bottom-left {
bottom: 10px; bottom: 10px;
inset-inline-start: 10px; inset-inline-start: 10px;
@@ -2585,6 +2598,7 @@ iframe.print-iframe {
position: relative; position: relative;
flex-grow: 1; flex-grow: 1;
width: 100%; width: 100%;
overflow: hidden;
} }
/* Calendar collection */ /* Calendar collection */
@@ -2615,3 +2629,9 @@ iframe.print-iframe {
} }
} }
} }
body.desktop .title-row {
height: 50px;
min-height: 50px;
align-items: center;
}

View File

@@ -19,7 +19,7 @@
--dropdown-border-color: #555; --dropdown-border-color: #555;
--dropdown-shadow-opacity: 0.4; --dropdown-shadow-opacity: 0.4;
--dropdown-item-icon-destructive-color: #de6e5b; --dropdown-item-icon-destructive-color: #de6e5b;
--disabled-tooltip-icon-color: #7fd2ef; --contextual-help-icon-color: #7fd2ef;
--accented-background-color: #555; --accented-background-color: #555;
--more-accented-background-color: #777; --more-accented-background-color: #777;

View File

@@ -23,7 +23,7 @@ html {
--dropdown-border-color: #ccc; --dropdown-border-color: #ccc;
--dropdown-shadow-opacity: 0.2; --dropdown-shadow-opacity: 0.2;
--dropdown-item-icon-destructive-color: #ec5138; --dropdown-item-icon-destructive-color: #ec5138;
--disabled-tooltip-icon-color: #004382; --contextual-help-icon-color: #004382;
--accented-background-color: #f5f5f5; --accented-background-color: #f5f5f5;
--more-accented-background-color: #ddd; --more-accented-background-color: #ddd;
@@ -89,10 +89,10 @@ html {
--custom-color: var(--light-theme-custom-color); --custom-color: var(--light-theme-custom-color);
} }
:root .reference-link, :root .reference-link.use-note-color,
:root .reference-link:hover, :root .reference-link.use-note-color:hover,
.ck-content a.reference-link > span, .ck-content a.reference-link.use-note-color > span,
.board-note { .board-note.use-note-color {
color: var(--light-theme-custom-color, inherit); color: var(--light-theme-custom-color, inherit);
} }

View File

@@ -22,7 +22,7 @@
--dropdown-border-color: #404040; --dropdown-border-color: #404040;
--dropdown-shadow-opacity: 0.6; --dropdown-shadow-opacity: 0.6;
--dropdown-item-icon-destructive-color: #de6e5b; --dropdown-item-icon-destructive-color: #de6e5b;
--disabled-tooltip-icon-color: #7fd2ef; --contextual-help-icon-color: #7fd2ef;
--accented-background-color: #555; --accented-background-color: #555;
@@ -170,6 +170,9 @@
--protected-session-active-icon-color: #8edd8e; --protected-session-active-icon-color: #8edd8e;
--sync-status-error-pulse-color: #f47871; --sync-status-error-pulse-color: #f47871;
--classic-toolbar-vert-layout-background-color: var(--main-background-color);
--classic-toolbar-horiz-layout-background-color: var(--main-background-color);
--center-pane-vert-layout-background-color-bgfx: #0c0c0c69; --center-pane-vert-layout-background-color-bgfx: #0c0c0c69;
--center-pane-horiz-layout-background-color-bgfx: #1e1e1ec7; --center-pane-horiz-layout-background-color-bgfx: #1e1e1ec7;
@@ -199,6 +202,10 @@
--badge-background-color: #ffffff1a; --badge-background-color: #ffffff1a;
--badge-text-color: var(--muted-text-color); --badge-text-color: var(--muted-text-color);
--note-icon-background-color: #444444;
--note-icon-color: #d4d4d4;
--note-icon-hover-background-color: #555555;
--promoted-attribute-card-background-color: #ffffff21; --promoted-attribute-card-background-color: #ffffff21;
--promoted-attribute-card-shadow: none; --promoted-attribute-card-shadow: none;
@@ -293,10 +300,10 @@
--custom-bg-color: hsl(var(--custom-color-hue), 20%, 33%, 0.4); --custom-bg-color: hsl(var(--custom-color-hue), 20%, 33%, 0.4);
} }
:root .reference-link, :root .reference-link.use-note-color,
:root .reference-link:hover, :root .reference-link.use-note-color:hover,
.ck-content a.reference-link > span, .ck-content a.reference-link.use-note-color > span,
.board-note { .board-note.use-note-color {
color: var(--dark-theme-custom-color, inherit); color: var(--dark-theme-custom-color, inherit);
} }
@@ -321,3 +328,15 @@ body .todo-list input[type="checkbox"]:not(:checked):before {
.use-note-color { .use-note-color {
--custom-color: var(--dark-theme-custom-color); --custom-color: var(--dark-theme-custom-color);
} }
.note-split.with-hue,
.quick-edit-dialog-wrapper.with-hue {
--note-icon-custom-background-color: hsl(var(--custom-color-hue), 15.8%, 30.9%);
--note-icon-custom-color: hsl(var(--custom-color-hue), 100%, 76.5%);
--note-icon-hover-custom-background-color: hsl(var(--custom-color-hue), 28.3%, 36.7%);
}
.note-split.with-hue *::selection,
.quick-edit-dialog-wrapper.with-hue *::selection {
background: hsl(var(--custom-color-hue), 49.2%, 35%);
}

View File

@@ -22,7 +22,7 @@
--dropdown-border-color: #ccc; --dropdown-border-color: #ccc;
--dropdown-shadow-opacity: 0.2; --dropdown-shadow-opacity: 0.2;
--dropdown-item-icon-destructive-color: #ec5138; --dropdown-item-icon-destructive-color: #ec5138;
--disabled-tooltip-icon-color: #004382; --contextual-help-icon-color: #004382;
--accented-background-color: #f5f5f5; --accented-background-color: #f5f5f5;
@@ -162,6 +162,9 @@
--protected-session-active-icon-color: #16b516; --protected-session-active-icon-color: #16b516;
--sync-status-error-pulse-color: #ff5528; --sync-status-error-pulse-color: #ff5528;
--classic-toolbar-vert-layout-background-color: #ffffffa1;
--classic-toolbar-horiz-layout-background-color: var(--main-background-color);
--center-pane-vert-layout-background-color-bgfx: #ffffff75; --center-pane-vert-layout-background-color-bgfx: #ffffff75;
--center-pane-horiz-layout-background-color-bgfx: #ffffffd6; --center-pane-horiz-layout-background-color-bgfx: #ffffffd6;
@@ -191,6 +194,10 @@
--badge-background-color: #00000011; --badge-background-color: #00000011;
--badge-text-color: var(--muted-text-color); --badge-text-color: var(--muted-text-color);
--note-icon-background-color: #4f4f4f;
--note-icon-color: white;
--note-icon-hover-background-color: #737373;
--promoted-attribute-card-background-color: #00000014; --promoted-attribute-card-background-color: #00000014;
--promoted-attribute-card-shadow: none; --promoted-attribute-card-shadow: none;
@@ -292,3 +299,15 @@
--modal-border-color: hsl(var(--custom-color-hue), 33%, 41%); --modal-border-color: hsl(var(--custom-color-hue), 33%, 41%);
--promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 40%, 88%); --promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 40%, 88%);
} }
.note-split.with-hue,
.quick-edit-dialog-wrapper.with-hue {
--note-icon-custom-background-color: hsl(var(--custom-color-hue), 44.5%, 43.1%);
--note-icon-custom-color: hsl(var(--custom-color-hue), 91.3%, 91%);
--note-icon-hover-custom-background-color: hsl(var(--custom-color-hue), 55.1%, 50.2%);
}
.note-split.with-hue *::selection,
.quick-edit-dialog-wrapper.with-hue *::selection {
background: hsl(var(--custom-color-hue), 60%, 90%);
}

View File

@@ -50,7 +50,7 @@
--tab-bar-height: 50px; --tab-bar-height: 50px;
--tab-height: 36px; --tab-height: 36px;
--tab-first-item-horiz-offset: 1px; --tab-first-item-horiz-offset: 0;
--new-tab-button-size: 24px; --new-tab-button-size: 24px;
--center-pane-border-radius: 10px; --center-pane-border-radius: 10px;
@@ -166,14 +166,32 @@ body.desktop .dropdown-submenu .dropdown-menu {
--menu-item-end-padding: 22px; --menu-item-end-padding: 22px;
--menu-item-vertical-padding: 2px; --menu-item-vertical-padding: 2px;
/* Note: the right padding should also accommodate the submenu arrow. */
border-radius: 6px;
cursor: default !important;
}
.dropdown-item:not(.dropdown-submenu),
body.desktop .dropdown-item.dropdown-submenu .dropdown-toggle,
.excalidraw .context-menu .context-menu-item {
padding-top: var(--menu-item-vertical-padding) !important; padding-top: var(--menu-item-vertical-padding) !important;
padding-bottom: 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-start: var(--menu-item-start-padding) !important;
padding-inline-end: var(--menu-item-end-padding) !important; padding-inline-end: var(--menu-item-end-padding) !important;
}
/* Note: the right padding should also accommodate the submenu arrow. */ .dropdown-item.dropdown-submenu {
border-radius: 6px; padding: 0 !important;
cursor: default !important;
.dropdown-toggle {
flex-grow: 1;
}
}
body.desktop .dropdown-menu:has(> .dropdown-submenu.dropstart) > .dropdown-item:not(.dropdown-submenu),
body.desktop .dropdown-menu:has(> .dropdown-submenu.dropstart) > .dropdown-item.dropdown-submenu .dropdown-toggle {
padding-inline-end: var(--menu-item-start-padding) !important;
padding-inline-start: var(--menu-item-end-padding) !important;
} }
:root .dropdown-item:focus-visible { :root .dropdown-item:focus-visible {
@@ -249,7 +267,8 @@ html body .dropdown-item[disabled] {
} }
/* Menu item arrow */ /* Menu item arrow */
.dropdown-menu .dropdown-toggle::after { body.mobile .dropdown-submenu .dropdown-toggle::after,
body.desktop .dropdown-submenu:not(.dropstart) .dropdown-toggle::after {
content: "\ed3b" !important; content: "\ed3b" !important;
position: absolute; position: absolute;
display: flex !important; display: flex !important;
@@ -265,6 +284,26 @@ html body .dropdown-item[disabled] {
color: var(--menu-item-arrow-color) !important; color: var(--menu-item-arrow-color) !important;
} }
body.mobile .dropdown-submenu.dropstart .dropdown-toggle::before {
content: unset;
}
body.desktop .dropdown-submenu.dropstart .dropdown-toggle::before {
content: "\ea4d" !important;
position: absolute;
display: flex !important;
align-items: center;
justify-content: center;
top: 0;
inset-inline-start: 0;
margin: unset !important;
border: unset !important;
padding: 0 4px;
font-family: boxicons;
font-size: 1.2em;
color: var(--menu-item-arrow-color) !important;
}
body[dir=rtl] .dropdown-menu:not([data-popper-placement="bottom-start"]) .dropdown-toggle::after { body[dir=rtl] .dropdown-menu:not([data-popper-placement="bottom-start"]) .dropdown-toggle::after {
content: "\ea4d" !important; content: "\ea4d" !important;
} }

View File

@@ -56,7 +56,8 @@ button.btn.btn-primary:focus-visible,
button.btn.btn-secondary:focus-visible, button.btn.btn-secondary:focus-visible,
button.btn.btn-sm:not(.select-button):focus-visible, button.btn.btn-sm:not(.select-button):focus-visible,
button.btn.btn-success:focus-visible, button.btn.btn-success:focus-visible,
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text:not(.ck-disabled):focus-visible { button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text:not(.ck-disabled):focus-visible,
.tn-focusable-button:focus-visible {
outline: 2px solid var(--input-focus-outline-color); outline: 2px solid var(--input-focus-outline-color);
} }
@@ -399,7 +400,8 @@ button.select-button.dropdown-toggle.btn:active {
select:focus, select:focus,
select.form-select:focus, select.form-select:focus,
select.form-control:focus, select.form-control:focus,
.select-button.dropdown-toggle.btn:focus { .select-button.dropdown-toggle.btn:focus,
.select-button.focus-outline:focus {
box-shadow: unset; box-shadow: unset;
outline: 3px solid var(--input-focus-outline-color); outline: 3px solid var(--input-focus-outline-color);
outline-offset: 0; outline-offset: 0;

View File

@@ -527,10 +527,17 @@ button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel).ck
border: 0; border: 0;
border-radius: 6px; border-radius: 6px;
box-shadow: var(--code-block-box-shadow); box-shadow: var(--code-block-box-shadow);
padding: 0;
margin-top: 2px !important; margin-top: 2px !important;
} }
.attachment-content-wrapper pre {
border-radius: var(--dropdown-border-radius);
}
:root .ck-content pre:has(> code) {
padding: 0;
}
:root .ck-content pre { :root .ck-content pre {
--icon-button-size: 1.8em; --icon-button-size: 1.8em;
--copy-button-width: var(--icon-button-size); --copy-button-width: var(--icon-button-size);

View File

@@ -168,12 +168,6 @@ ul.editability-dropdown li.dropdown-item > div {
* Note info * Note info
*/ */
:root .note-info-widget-table button.calculate-button {
min-width: 0;
padding: 4px 10px !important;
font-size: 0.8em;
}
/* Narrow width layout */ /* Narrow width layout */
.note-info-widget { .note-info-widget {
container: info-section / inline-size; container: info-section / inline-size;

View File

@@ -212,7 +212,8 @@ body[dir=ltr] #launcher-container {
} }
#launcher-pane .launcher-button, #launcher-pane .launcher-button,
#launcher-pane .dropdown { #launcher-pane .right-dropdown-widget,
#launcher-pane .global-menu {
width: calc(var(--launcher-pane-size) - (var(--launcher-pane-button-margin) * 2)) !important; width: calc(var(--launcher-pane-size) - (var(--launcher-pane-button-margin) * 2)) !important;
height: calc(var(--launcher-pane-size) - (var(--launcher-pane-button-margin) * 2)) !important; height: calc(var(--launcher-pane-size) - (var(--launcher-pane-button-margin) * 2)) !important;
margin: var(--launcher-pane-button-gap) var(--launcher-pane-button-margin); margin: var(--launcher-pane-button-gap) var(--launcher-pane-button-margin);
@@ -944,12 +945,26 @@ body.electron.background-effects.layout-horizontal .tab-row-container .toggle-bu
position: absolute; position: absolute;
bottom: 0; bottom: 0;
inset-inline-start: -10px; inset-inline-start: -10px;
inset-inline-end: -10px; inset-inline-end: -6px;
top: 32px; top: 32px;
height: 1px; height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color); border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
} }
body.electron.background-effects.layout-horizontal .tab-row-container .tab-history-navigation-buttons {
position: relative;
&:after {
content: "";
position: absolute;
bottom: 0;
inset-inline-start: 0;
inset-inline-end: -7px;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
}
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-left, body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-left,
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-right { body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-right {
position: relative; position: relative;
@@ -1014,7 +1029,7 @@ body.layout-vertical.electron.platform-darwin .tab-row-container {
} }
body.layout-horizontal .tab-row-container { body.layout-horizontal .tab-row-container {
padding-top: calc((var(--tab-bar-height) - var(--tab-height))); padding-top: calc(var(--tab-bar-height) - var(--tab-height));
} }
/* Define extra drag areas for Electron windows */ /* Define extra drag areas for Electron windows */
@@ -1054,8 +1069,9 @@ body.desktop:not(.background-effects.platform-win32) #root-widget.horizontal-lay
border-bottom-color: transparent; border-bottom-color: transparent;
} }
.tab-row-widget .note-tab .note-tab-wrapper { :root div.tab-row-widget div.note-tab div.note-tab-wrapper {
height: var(--tab-height) !important; height: var(--tab-height) !important;
border-radius: 8px;
transition: transition:
background 75ms ease-in, background 75ms ease-in,
box-shadow 75ms ease-in; box-shadow 75ms ease-in;
@@ -1206,13 +1222,38 @@ body.layout-vertical .tab-row-widget-is-sorting .note-tab.note-tab-is-dragging .
top: 0; top: 0;
} }
/*
* CLASSIC FORMATTING TOOLBAR
*/
#rest-pane > .classic-toolbar-widget {
margin-bottom: 2px;
}
body.vertical-layout #rest-pane > .classic-toolbar-widget {
border-start-start-radius: var(--center-pane-border-radius);
}
body.layout-vertical #rest-pane > .classic-toolbar-widget {
background: var(--classic-toolbar-vert-layout-background-color);
}
body.layout-horizontal #rest-pane > .classic-toolbar-widget {
background: var(--classic-toolbar-horiz-layout-background-color);
}
.classic-toolbar-widget:not(.hidden-ext) + #vertical-main-container {
/* Remove the center panel border radius when the toolbar is visible */
--center-pane-border-radius: 0;
}
/* /*
* CENTER PANE * CENTER PANE
*/ */
/* The first visible note split */ /* The first visible note split */
.vertical-layout #center-pane .note-split:not(.visible ~ .visible) { .vertical-layout #center-pane .note-split:not(.visible ~ .visible) {
border-radius: var(--center-pane-border-radius) 0 0 0; border-start-start-radius: var(--center-pane-border-radius);
} }
#center-pane .note-split { #center-pane .note-split {

View File

@@ -160,6 +160,11 @@ span.fancytree-node.multiple-parents .fancytree-title::after {
content: " \eb3d"; /* lookup code for "link-alt" in boxicons.css */ content: " \eb3d"; /* lookup code for "link-alt" in boxicons.css */
} }
body.experimental-feature-new-layout span.fancytree-node.multiple-parents .fancytree-title::after {
content: " \ed82";
opacity: 0.5;
}
span.fancytree-node.shared .fancytree-title::after { span.fancytree-node.shared .fancytree-title::after {
font-family: "boxicons" !important; font-family: "boxicons" !important;
font-size: smaller; font-size: smaller;

View File

@@ -1,10 +1,12 @@
import utils from "../services/utils.js"; import { NoteType } from "@triliumnext/commons";
import FAttribute from "../entities/fattribute.js";
import FBlob from "../entities/fblob.js";
import FBranch from "../entities/fbranch.js";
import FNote from "../entities/fnote.js"; import FNote from "../entities/fnote.js";
import froca from "../services/froca.js"; import froca from "../services/froca.js";
import FAttribute from "../entities/fattribute.js";
import noteAttributeCache from "../services/note_attribute_cache.js"; import noteAttributeCache from "../services/note_attribute_cache.js";
import FBranch from "../entities/fbranch.js"; import utils from "../services/utils.js";
import FBlob from "../entities/fblob.js";
type AttributeDefinitions = { [key in `#${string}`]: string; }; type AttributeDefinitions = { [key in `#${string}`]: string; };
type RelationDefinitions = { [key in `~${string}`]: string; }; type RelationDefinitions = { [key in `~${string}`]: string; };
@@ -12,6 +14,7 @@ type RelationDefinitions = { [key in `~${string}`]: string; };
interface NoteDefinition extends AttributeDefinitions, RelationDefinitions { interface NoteDefinition extends AttributeDefinitions, RelationDefinitions {
id?: string | undefined; id?: string | undefined;
title: string; title: string;
type?: NoteType;
children?: NoteDefinition[]; children?: NoteDefinition[];
content?: string; content?: string;
} }
@@ -45,7 +48,7 @@ export function buildNote(noteDef: NoteDefinition) {
const note = new FNote(froca, { const note = new FNote(froca, {
noteId: noteDef.id ?? utils.randomString(12), noteId: noteDef.id ?? utils.randomString(12),
title: noteDef.title, title: noteDef.title,
type: "text", type: noteDef.type ?? "text",
mime: "text/html", mime: "text/html",
isProtected: false, isProtected: false,
blobId: "" blobId: ""

View File

@@ -948,7 +948,7 @@
"move-to-available-launchers": "نقل الى المشغلات المتوفرة", "move-to-available-launchers": "نقل الى المشغلات المتوفرة",
"duplicate-launcher": "تكرار المشغل <kbd data-command=\"duplicateSubtree\">" "duplicate-launcher": "تكرار المشغل <kbd data-command=\"duplicateSubtree\">"
}, },
"editable-text": { "editable_text": {
"auto-detect-language": "تم اكتشافه تلقائيا" "auto-detect-language": "تم اكتشافه تلقائيا"
}, },
"classic_editor_toolbar": { "classic_editor_toolbar": {

View File

@@ -205,7 +205,8 @@
"info": { "info": {
"modalTitle": "信息消息", "modalTitle": "信息消息",
"closeButton": "关闭", "closeButton": "关闭",
"okButton": "确定" "okButton": "确定",
"copy_to_clipboard": "复制到剪切板"
}, },
"jump_to_note": { "jump_to_note": {
"search_button": "全文搜索", "search_button": "全文搜索",
@@ -692,7 +693,13 @@
"convert_into_attachment_successful": "笔记 '{{title}}' 已成功转换为附件。", "convert_into_attachment_successful": "笔记 '{{title}}' 已成功转换为附件。",
"convert_into_attachment_prompt": "确定要将笔记 '{{title}}' 转换为父笔记的附件吗?", "convert_into_attachment_prompt": "确定要将笔记 '{{title}}' 转换为父笔记的附件吗?",
"print_pdf": "导出为 PDF...", "print_pdf": "导出为 PDF...",
"open_note_on_server": "在服务器上打开笔记" "open_note_on_server": "在服务器上打开笔记",
"view_revisions": "笔记修订...",
"note_map": "笔记地图",
"advanced": "高级",
"export_as_image": "导出为图像",
"export_as_image_png": "PNG栅格",
"export_as_image_svg": "SVG矢量图"
}, },
"onclick_button": { "onclick_button": {
"no_click_handler": "按钮组件'{{componentId}}'没有定义点击处理程序" "no_click_handler": "按钮组件'{{componentId}}'没有定义点击处理程序"
@@ -790,7 +797,7 @@
"file_type": "文件类型", "file_type": "文件类型",
"file_size": "文件大小", "file_size": "文件大小",
"download": "下载", "download": "下载",
"open": "打开", "open": "用外部程序打开",
"upload_new_revision": "上传新修订版本", "upload_new_revision": "上传新修订版本",
"upload_success": "新文件修订版本已上传。", "upload_success": "新文件修订版本已上传。",
"upload_failed": "新文件修订版本上传失败。", "upload_failed": "新文件修订版本上传失败。",
@@ -821,7 +828,9 @@
"note_size_info": "笔记大小提供了该笔记存储需求的粗略估计。它考虑了笔记的内容及其笔记修订历史的内容。", "note_size_info": "笔记大小提供了该笔记存储需求的粗略估计。它考虑了笔记的内容及其笔记修订历史的内容。",
"calculate": "计算", "calculate": "计算",
"subtree_size": "(子树大小: {{size}}, 共计 {{count}} 个笔记)", "subtree_size": "(子树大小: {{size}}, 共计 {{count}} 个笔记)",
"title": "笔记信息" "title": "笔记信息",
"show_similar_notes": "显示相似的笔记",
"mime": "文件类型"
}, },
"note_map": { "note_map": {
"open_full": "展开显示", "open_full": "展开显示",
@@ -884,7 +893,8 @@
"search_parameters": "搜索参数", "search_parameters": "搜索参数",
"unknown_search_option": "未知的搜索选项 {{searchOptionName}}", "unknown_search_option": "未知的搜索选项 {{searchOptionName}}",
"search_note_saved": "搜索笔记已保存到 {{- notePathTitle}}", "search_note_saved": "搜索笔记已保存到 {{- notePathTitle}}",
"actions_executed": "操作已执行。" "actions_executed": "操作已执行。",
"view_options": "查看选项:"
}, },
"similar_notes": { "similar_notes": {
"title": "相似笔记", "title": "相似笔记",
@@ -986,7 +996,14 @@
"placeholder": "在这里输入您的代码笔记内容..." "placeholder": "在这里输入您的代码笔记内容..."
}, },
"editable_text": { "editable_text": {
"placeholder": "在这里输入您的笔记内容..." "placeholder": "在这里输入您的笔记内容...",
"auto-detect-language": "自动检测",
"keeps-crashing": "编辑组件时持续崩溃。请尝试重启 Trilium。如果问题仍然存在请考虑提交错误报告。",
"editor_crashed_title": "文本编辑器崩溃",
"editor_crashed_content": "您的内容已经成功恢复,但是某些最近的内容可能没有保存。",
"editor_crashed_details_button": "浏览更多明细...",
"editor_crashed_details_intro": "如果您多次经历此错误考虑在Github上提交这些信息。",
"editor_crashed_details_title": "技术信息"
}, },
"empty": { "empty": {
"open_note_instruction": "通过在下面的输入框中输入笔记标题或在树中选择笔记来打开笔记。", "open_note_instruction": "通过在下面的输入框中输入笔记标题或在树中选择笔记来打开笔记。",
@@ -1469,7 +1486,7 @@
"import-into-note": "导入到笔记", "import-into-note": "导入到笔记",
"apply-bulk-actions": "应用批量操作", "apply-bulk-actions": "应用批量操作",
"converted-to-attachments": "{{count}} 个笔记已被转换为附件。", "converted-to-attachments": "{{count}} 个笔记已被转换为附件。",
"convert-to-attachment-confirm": "确定要将选中的笔记转换为其父笔记的附件吗?", "convert-to-attachment-confirm": "确定要将选中的笔记转换为其父笔记的附件吗?此操作仅适用于图像笔记,其他笔记将被跳过。",
"duplicate": "复制", "duplicate": "复制",
"open-in-popup": "快速编辑", "open-in-popup": "快速编辑",
"archive": "归档", "archive": "归档",
@@ -1569,7 +1586,14 @@
"printing_pdf": "正在导出为PDF…" "printing_pdf": "正在导出为PDF…"
}, },
"note_title": { "note_title": {
"placeholder": "请输入笔记标题..." "placeholder": "请输入笔记标题...",
"created_on": "建立于 <Value />",
"last_modified": "修改于 <Value />",
"note_type_switcher_label": "从 {{type}} 切换到:",
"note_type_switcher_others": "其他笔记类型",
"note_type_switcher_templates": "模板",
"note_type_switcher_collection": "集合",
"edited_notes": "编辑过的笔记"
}, },
"search_result": { "search_result": {
"no_notes_found": "没有找到符合搜索条件的笔记。", "no_notes_found": "没有找到符合搜索条件的笔记。",
@@ -1660,10 +1684,6 @@
"move-to-available-launchers": "移动到可用启动器", "move-to-available-launchers": "移动到可用启动器",
"duplicate-launcher": "复制启动器 <kbd data-command=\"duplicateSubtree\">" "duplicate-launcher": "复制启动器 <kbd data-command=\"duplicateSubtree\">"
}, },
"editable-text": {
"auto-detect-language": "自动检测",
"keeps-crashing": "编辑组件时持续崩溃。请尝试重启 Trilium。如果问题仍然存在请考虑提交错误报告。"
},
"highlighting": { "highlighting": {
"title": "代码块", "title": "代码块",
"description": "控制文本笔记中代码块的语法高亮,代码笔记不会受到影响。", "description": "控制文本笔记中代码块的语法高亮,代码笔记不会受到影响。",
@@ -1714,7 +1734,8 @@
"open_note_in_new_tab": "在新标签页中打开笔记", "open_note_in_new_tab": "在新标签页中打开笔记",
"open_note_in_new_split": "在新分屏中打开笔记", "open_note_in_new_split": "在新分屏中打开笔记",
"open_note_in_new_window": "在新窗口中打开笔记", "open_note_in_new_window": "在新窗口中打开笔记",
"open_note_in_popup": "快速编辑" "open_note_in_popup": "快速编辑",
"open_note_in_other_split": "在另一个分屏中打开笔记"
}, },
"electron_integration": { "electron_integration": {
"desktop-application": "桌面应用程序", "desktop-application": "桌面应用程序",
@@ -1934,8 +1955,9 @@
"unknown_widget": "未知组件:\"{{id}}\"." "unknown_widget": "未知组件:\"{{id}}\"."
}, },
"note_language": { "note_language": {
"not_set": "设置", "not_set": "设置语言",
"configure-languages": "设置语言..." "configure-languages": "设置语言...",
"help-on-languages": "内容语言帮助..."
}, },
"content_language": { "content_language": {
"title": "内容语言", "title": "内容语言",
@@ -1953,7 +1975,8 @@
"button_title": "将图表导出为PNG" "button_title": "将图表导出为PNG"
}, },
"svg": { "svg": {
"export_to_png": "无法将图表导出为PNG。" "export_to_png": "无法将图表导出为PNG。",
"export_to_svg": "此图像无法导出为SVG。"
}, },
"code_theme": { "code_theme": {
"title": "外观", "title": "外观",
@@ -2001,7 +2024,7 @@
"book_properties_config": { "book_properties_config": {
"hide-weekends": "隐藏周末", "hide-weekends": "隐藏周末",
"display-week-numbers": "显示周数", "display-week-numbers": "显示周数",
"map-style": "地图样式", "map-style": "地图样式",
"max-nesting-depth": "最大嵌套深度:", "max-nesting-depth": "最大嵌套深度:",
"raster": "栅格", "raster": "栅格",
"vector_light": "矢量(浅色)", "vector_light": "矢量(浅色)",
@@ -2045,7 +2068,7 @@
"configure_launch_bar_description": "打开启动栏配置,添加或移除项目。" "configure_launch_bar_description": "打开启动栏配置,添加或移除项目。"
}, },
"content_renderer": { "content_renderer": {
"open_externally": "外部打开" "open_externally": "外部程序打开"
}, },
"modal": { "modal": {
"close": "关闭", "close": "关闭",
@@ -2058,14 +2081,20 @@
"next_theme_title": "试用新 Trilium 主题", "next_theme_title": "试用新 Trilium 主题",
"next_theme_message": "当前使用旧版主题,要试用新主题吗?", "next_theme_message": "当前使用旧版主题,要试用新主题吗?",
"next_theme_button": "试用新主题", "next_theme_button": "试用新主题",
"dismiss": "关闭" "dismiss": "关闭",
"new_layout_message": "我们为 Trilium 引入了现代化的布局。Ribbon 界面已被移除并无缝集成到主界面中,新的状态栏和可展开部分(例如“已提升属性”)取代了其主要功能。\n\n新布局默认启用您可以通过“选项”→“外观”暂时禁用它。",
"new_layout_button": "更多信息",
"new_layout_title": "新布局"
}, },
"settings": { "settings": {
"related_settings": "相关设置" "related_settings": "相关设置"
}, },
"settings_appearance": { "settings_appearance": {
"related_code_blocks": "文本笔记中代码块的色彩方案", "related_code_blocks": "文本笔记中代码块的色彩方案",
"related_code_notes": "代码笔记的色彩方案" "related_code_notes": "代码笔记的色彩方案",
"ui": "用户界面",
"ui_old_layout": "旧布局",
"ui_new_layout": "新布局"
}, },
"units": { "units": {
"percentage": "%" "percentage": "%"
@@ -2080,7 +2109,7 @@
}, },
"pagination": { "pagination": {
"page_title": "第 {{startIndex}} 页 - 第 {{endIndex}} 页", "page_title": "第 {{startIndex}} 页 - 第 {{endIndex}} 页",
"total_notes": "{{count}} 笔记" "total_notes": "{{count}} 笔记"
}, },
"collections": { "collections": {
"rendering_error": "出现错误无法显示内容。" "rendering_error": "出现错误无法显示内容。"
@@ -2105,5 +2134,60 @@
}, },
"popup-editor": { "popup-editor": {
"maximize": "切换至完整编辑器" "maximize": "切换至完整编辑器"
},
"server": {
"unknown_http_error_title": "与服务器通讯错误",
"unknown_http_error_content": "状态码: {{statusCode}}\n地址: {{method}} {{url}}\n信息: {{message}}",
"traefik_blocks_requests": "如果您使用 Traefik 反向代理,它引入了一项影响与服务器的通信重大更改。"
},
"experimental_features": {
"title": "实验选项",
"disclaimer": "这些选项处于实验阶段,可能导致系统不稳定。请谨慎使用。",
"new_layout_name": "新布局",
"new_layout_description": "尝试全新布局,呈现更现代的外观并提升易用性。后续版本将进行重大调整。"
},
"tab_history_navigation_buttons": {
"go-back": "返回前一笔记",
"go-forward": "前往下一笔记"
},
"breadcrumb_badges": {
"read_only_explicit": "只读",
"read_only_auto": "自动只读",
"shared_publicly": "公开共享",
"shared_locally": "本地共享",
"read_only_explicit_description": "此笔记已被手动设置为只读。\n点击可临时编辑。",
"read_only_auto_description": "出于性能原因,此笔记已被自动设置为只读模式。此自动限制可以在设置中调整。\n\n点击可临时编辑。",
"read_only_temporarily_disabled": "临时编辑",
"read_only_temporarily_disabled_description": "此笔记当前可编辑,但通常是只读的。一旦你切换到其他笔记,该笔记将恢复为只读模式。\n\n点击以重新启用只读模式。",
"clipped_note": "网页剪辑",
"clipped_note_description": "此笔记最初来自 {{url}}。\n\n点击即可跳转至源网页。",
"execute_script": "运行脚本",
"execute_script_description": "这是一篇脚本笔记。点击即可执行脚本。",
"execute_sql": "运行SQL",
"execute_sql_description": "这是一篇 SQL 笔记。点击即可执行 SQL 查询。",
"shared_copy_to_clipboard": "复制链接到剪贴板",
"shared_open_in_browser": "在浏览器中打开链接",
"shared_unshare": "取消共享"
},
"status_bar": {
"language_title": "更改内容语言",
"note_info_title": "查看笔记信息(例如日期,笔记大小)",
"backlinks_title_other": "查看反链",
"attachments_title_other": "在新标签页中查看附件",
"attributes_other": "{{count}} 个属性",
"attributes_title": "拥有的属性和继承的属性",
"note_paths_title": "笔记路径",
"code_note_switcher": "更改语言模式",
"backlinks_other": "{{count}} 个反链",
"attachments_other": "{{count}} 个附件",
"note_paths_other": "{{count}} 条路径"
},
"breadcrumb": {
"workspace_badge": "工作空间",
"scroll_to_top_title": "跳转到笔记开始",
"hoisted_badge_title": "取消聚焦",
"hoisted_badge": "聚焦",
"create_new_note": "新建子笔记",
"empty_hide_archived_notes": "隐藏已存档的笔记"
} }
} }

View File

@@ -108,6 +108,11 @@
"cloned_note_prefix_title": "Klonovaná poznámka se zobrazí ve stromu poznámek s danou předponou", "cloned_note_prefix_title": "Klonovaná poznámka se zobrazí ve stromu poznámek s danou předponou",
"clone_to_selected_note": "Klonovat vybranou poznámku", "clone_to_selected_note": "Klonovat vybranou poznámku",
"no_path_to_clone_to": "Žádná cest pro klonování.", "no_path_to_clone_to": "Žádná cest pro klonování.",
"note_cloned": "Poznámka: „{{clonedTitle}}“ bylo naklonováno do „{{targetTitle}}“" "note_cloned": "Poznámka „{{clonedTitle}}“ bylo naklonována do „{{targetTitle}}“"
},
"zpetne_odkazy": {
"backlink_one": "{{count}} zpětný odkaz",
"backlink_few": "{{count}} zpětné odkazy",
"backlink_other": "{{count}} zpětných odkazů"
} }
} }

View File

@@ -162,7 +162,8 @@
"quickSearch": "Fokus auf schnelle Sucheingabe", "quickSearch": "Fokus auf schnelle Sucheingabe",
"inPageSearch": "Auf-der-Seite-Suche", "inPageSearch": "Auf-der-Seite-Suche",
"newTabWithActivationNoteLink": "auf einen Notiz-Link öffnet und aktiviert die Notiz in einem neuen Tab", "newTabWithActivationNoteLink": "auf einen Notiz-Link öffnet und aktiviert die Notiz in einem neuen Tab",
"title": "Spickzettel" "title": "Spickzettel",
"editShortcuts": "Tastenkürzel bearbeiten"
}, },
"import": { "import": {
"importIntoNote": "In Notiz importieren", "importIntoNote": "In Notiz importieren",
@@ -983,7 +984,9 @@
"placeholder": "Gebe hier den Inhalt deiner Codenotiz ein..." "placeholder": "Gebe hier den Inhalt deiner Codenotiz ein..."
}, },
"editable_text": { "editable_text": {
"placeholder": "Gebe hier den Inhalt deiner Notiz ein..." "placeholder": "Gebe hier den Inhalt deiner Notiz ein...",
"auto-detect-language": "Automatisch erkannt",
"keeps-crashing": "Die Bearbeitungskomponente stürzt immer wieder ab. Bitte starten Sie Trilium neu. Wenn das Problem weiterhin besteht, erstellen Sie einen Fehlerbericht."
}, },
"empty": { "empty": {
"open_note_instruction": "Öffne eine Notiz, indem du den Titel der Notiz in die Eingabe unten eingibst oder eine Notiz in der Baumstruktur auswählst.", "open_note_instruction": "Öffne eine Notiz, indem du den Titel der Notiz in die Eingabe unten eingibst oder eine Notiz in der Baumstruktur auswählst.",
@@ -1624,10 +1627,6 @@
"move-to-available-launchers": "Zu verfügbaren Launchern verschieben", "move-to-available-launchers": "Zu verfügbaren Launchern verschieben",
"duplicate-launcher": "Launcher duplizieren <kbd data-command=\"duplicateSubtree\">" "duplicate-launcher": "Launcher duplizieren <kbd data-command=\"duplicateSubtree\">"
}, },
"editable-text": {
"auto-detect-language": "Automatisch erkannt",
"keeps-crashing": "Die Bearbeitungskomponente stürzt immer wieder ab. Bitte starten Sie Trilium neu. Wenn das Problem weiterhin besteht, erstellen Sie einen Fehlerbericht."
},
"highlighting": { "highlighting": {
"description": "Steuert die Syntaxhervorhebung für Codeblöcke in Textnotizen, Code-Notizen sind nicht betroffen.", "description": "Steuert die Syntaxhervorhebung für Codeblöcke in Textnotizen, Code-Notizen sind nicht betroffen.",
"color-scheme": "Farbschema", "color-scheme": "Farbschema",
@@ -2102,5 +2101,8 @@
"clear-color": "Notizfarbe entfernen", "clear-color": "Notizfarbe entfernen",
"set-color": "Notizfarbe wählen", "set-color": "Notizfarbe wählen",
"set-custom-color": "Eigene Notizfarbe wählen" "set-custom-color": "Eigene Notizfarbe wählen"
},
"popup-editor": {
"maximize": "Wechsele zum vollständigen Editor"
} }
} }

View File

@@ -22,7 +22,15 @@
"bundle-error": { "bundle-error": {
"title": "Failed to load a custom script", "title": "Failed to load a custom script",
"message": "Script from note with ID \"{{id}}\", titled \"{{title}}\" could not be executed due to:\n\n{{message}}" "message": "Script from note with ID \"{{id}}\", titled \"{{title}}\" could not be executed due to:\n\n{{message}}"
} },
"widget-list-error": {
"title": "Failed to obtain the list of widgets from the server"
},
"widget-render-error": {
"title": "Failed to render a custom React widget"
},
"widget-missing-parent": "Custom widget does not have mandatory '{{property}}' property defined.",
"open-script-note": "Open script note"
}, },
"add_link": { "add_link": {
"add_link": "Add link", "add_link": "Add link",
@@ -205,7 +213,8 @@
"info": { "info": {
"modalTitle": "Info message", "modalTitle": "Info message",
"closeButton": "Close", "closeButton": "Close",
"okButton": "OK" "okButton": "OK",
"copy_to_clipboard": "Copy to clipboard"
}, },
"jump_to_note": { "jump_to_note": {
"search_placeholder": "Search for note by its name or type > for commands...", "search_placeholder": "Search for note by its name or type > for commands...",
@@ -688,11 +697,17 @@
"export_note": "Export note", "export_note": "Export note",
"delete_note": "Delete note", "delete_note": "Delete note",
"print_note": "Print note", "print_note": "Print note",
"view_revisions": "Note revisions...",
"save_revision": "Save revision", "save_revision": "Save revision",
"advanced": "Advanced",
"convert_into_attachment_failed": "Converting note '{{title}}' failed.", "convert_into_attachment_failed": "Converting note '{{title}}' failed.",
"convert_into_attachment_successful": "Note '{{title}}' has been converted to attachment.", "convert_into_attachment_successful": "Note '{{title}}' has been converted to attachment.",
"convert_into_attachment_prompt": "Are you sure you want to convert note '{{title}}' into an attachment of the parent note?", "convert_into_attachment_prompt": "Are you sure you want to convert note '{{title}}' into an attachment of the parent note?",
"print_pdf": "Export as PDF..." "print_pdf": "Export as PDF...",
"export_as_image": "Export as image",
"export_as_image_png": "PNG (raster)",
"export_as_image_svg": "SVG (vector)",
"note_map": "Note map"
}, },
"onclick_button": { "onclick_button": {
"no_click_handler": "Button widget '{{componentId}}' has no defined click handler" "no_click_handler": "Button widget '{{componentId}}' has no defined click handler"
@@ -791,7 +806,7 @@
"file_type": "File type", "file_type": "File type",
"file_size": "File size", "file_size": "File size",
"download": "Download", "download": "Download",
"open": "Open", "open": "Open externally",
"upload_new_revision": "Upload new revision", "upload_new_revision": "Upload new revision",
"upload_success": "New file revision has been uploaded.", "upload_success": "New file revision has been uploaded.",
"upload_failed": "Upload of a new file revision failed.", "upload_failed": "Upload of a new file revision failed.",
@@ -818,11 +833,13 @@
"created": "Created", "created": "Created",
"modified": "Modified", "modified": "Modified",
"type": "Type", "type": "Type",
"mime": "MIME type",
"note_size": "Note size", "note_size": "Note size",
"note_size_info": "Note size provides rough estimate of storage requirements for this note. It takes into account note's content and content of its note revisions.", "note_size_info": "Note size provides rough estimate of storage requirements for this note. It takes into account note's content and content of its note revisions.",
"calculate": "calculate", "calculate": "calculate",
"subtree_size": "(subtree size: {{size}} in {{count}} notes)", "subtree_size": "(subtree size: {{size}} in {{count}} notes)",
"title": "Note Info" "title": "Note Info",
"show_similar_notes": "Show similar notes"
}, },
"note_map": { "note_map": {
"open_full": "Expand to full", "open_full": "Expand to full",
@@ -885,7 +902,8 @@
"search_parameters": "Search Parameters", "search_parameters": "Search Parameters",
"unknown_search_option": "Unknown search option {{searchOptionName}}", "unknown_search_option": "Unknown search option {{searchOptionName}}",
"search_note_saved": "Search note has been saved into {{- notePathTitle}}", "search_note_saved": "Search note has been saved into {{- notePathTitle}}",
"actions_executed": "Actions have been executed." "actions_executed": "Actions have been executed.",
"view_options": "View options:"
}, },
"similar_notes": { "similar_notes": {
"title": "Similar Notes", "title": "Similar Notes",
@@ -987,7 +1005,14 @@
"placeholder": "Type the content of your code note here..." "placeholder": "Type the content of your code note here..."
}, },
"editable_text": { "editable_text": {
"placeholder": "Type the content of your note here..." "placeholder": "Type the content of your note here...",
"editor_crashed_title": "The text editor crashed",
"editor_crashed_content": "Your content was recovered successfully, but a few of your most recent changes may not have been saved.",
"editor_crashed_details_button": "View more details...",
"editor_crashed_details_intro": "If you experience this error several times, consider reporting it on GitHub by pasting the information below.",
"editor_crashed_details_title": "Technical information",
"auto-detect-language": "Auto-detected",
"keeps-crashing": "Editing component keeps crashing. Please try restarting Trilium. If problem persists, consider creating a bug report."
}, },
"empty": { "empty": {
"open_note_instruction": "Open a note by typing the note's title into the input below or choose a note in the tree.", "open_note_instruction": "Open a note by typing the note's title into the input below or choose a note in the tree.",
@@ -1088,6 +1113,12 @@
"vacuuming_database": "Vacuuming database...", "vacuuming_database": "Vacuuming database...",
"database_vacuumed": "Database has been vacuumed" "database_vacuumed": "Database has been vacuumed"
}, },
"experimental_features": {
"title": "Experimental Options",
"disclaimer": "These options are experimental and may cause instability. Use with caution.",
"new_layout_name": "New Layout",
"new_layout_description": "Try out the new layout for a more modern look and improved usability. Subject to heavy change in the upcoming releases."
},
"fonts": { "fonts": {
"theme_defined": "Theme defined", "theme_defined": "Theme defined",
"fonts": "Fonts", "fonts": "Fonts",
@@ -1700,7 +1731,12 @@
}, },
"highlights_list_2": { "highlights_list_2": {
"title": "Highlights List", "title": "Highlights List",
"options": "Options" "title_with_count_one": "{{count}} highlight",
"title_with_count_other": "{{count}} highlights",
"options": "Options",
"modal_title": "Configure Highlights List",
"menu_configure": "Configure highlights list...",
"no_highlights": "No highlights found."
}, },
"quick-search": { "quick-search": {
"placeholder": "Quick search", "placeholder": "Quick search",
@@ -1735,7 +1771,14 @@
"printing_pdf": "Exporting to PDF in progress..." "printing_pdf": "Exporting to PDF in progress..."
}, },
"note_title": { "note_title": {
"placeholder": "type note's title here..." "placeholder": "type note's title here...",
"created_on": "Created on <Value />",
"last_modified": "Modified on <Value />",
"note_type_switcher_label": "Switch from {{type}} to:",
"note_type_switcher_others": "Other note type",
"note_type_switcher_templates": "Template",
"note_type_switcher_collection": "Collection",
"edited_notes": "Edited notes"
}, },
"search_result": { "search_result": {
"no_notes_found": "No notes have been found for given search parameters.", "no_notes_found": "No notes have been found for given search parameters.",
@@ -1764,7 +1807,8 @@
}, },
"toc": { "toc": {
"table_of_contents": "Table of Contents", "table_of_contents": "Table of Contents",
"options": "Options" "options": "Options",
"no_headings": "No headings."
}, },
"watched_file_update_status": { "watched_file_update_status": {
"file_last_modified": "File <code class=\"file-path\"></code> has been last modified on <span class=\"file-last-modified\"></span>.", "file_last_modified": "File <code class=\"file-path\"></code> has been last modified on <span class=\"file-last-modified\"></span>.",
@@ -1826,10 +1870,6 @@
"move-to-available-launchers": "Move to available launchers", "move-to-available-launchers": "Move to available launchers",
"duplicate-launcher": "Duplicate launcher <kbd data-command=\"duplicateSubtree\">" "duplicate-launcher": "Duplicate launcher <kbd data-command=\"duplicateSubtree\">"
}, },
"editable-text": {
"auto-detect-language": "Auto-detected",
"keeps-crashing": "Editing component keeps crashing. Please try restarting Trilium. If problem persists, consider creating a bug report."
},
"highlighting": { "highlighting": {
"title": "Code Blocks", "title": "Code Blocks",
"description": "Controls the syntax highlighting for code blocks inside text notes, code notes will not be affected.", "description": "Controls the syntax highlighting for code blocks inside text notes, code notes will not be affected.",
@@ -1949,8 +1989,9 @@
"unknown_widget": "Unknown widget for \"{{id}}\"." "unknown_widget": "Unknown widget for \"{{id}}\"."
}, },
"note_language": { "note_language": {
"not_set": "Not set", "not_set": "No language set",
"configure-languages": "Configure languages..." "configure-languages": "Configure languages...",
"help-on-languages": "Help on content languages..."
}, },
"content_language": { "content_language": {
"title": "Content languages", "title": "Content languages",
@@ -1968,7 +2009,8 @@
"button_title": "Export diagram as PNG" "button_title": "Export diagram as PNG"
}, },
"svg": { "svg": {
"export_to_png": "The diagram could not be exported to PNG." "export_to_png": "The diagram could not be exported to PNG.",
"export_to_svg": "The diagram could not be exported to SVG."
}, },
"code_theme": { "code_theme": {
"title": "Appearance", "title": "Appearance",
@@ -2016,7 +2058,7 @@
"book_properties_config": { "book_properties_config": {
"hide-weekends": "Hide weekends", "hide-weekends": "Hide weekends",
"display-week-numbers": "Display week numbers", "display-week-numbers": "Display week numbers",
"map-style": "Map style:", "map-style": "Map style",
"max-nesting-depth": "Max nesting depth:", "max-nesting-depth": "Max nesting depth:",
"raster": "Raster", "raster": "Raster",
"vector_light": "Vector (Light)", "vector_light": "Vector (Light)",
@@ -2081,6 +2123,9 @@
"background_effects_title": "Background effects are now stable", "background_effects_title": "Background effects are now stable",
"background_effects_message": "On Windows devices, background effects are now fully stable. The background effects adds a touch of color to the user interface by blurring the background behind it. This technique is also used in other applications such as Windows Explorer.", "background_effects_message": "On Windows devices, background effects are now fully stable. The background effects adds a touch of color to the user interface by blurring the background behind it. This technique is also used in other applications such as Windows Explorer.",
"background_effects_button": "Enable background effects", "background_effects_button": "Enable background effects",
"new_layout_title": "New layout",
"new_layout_message": "Weve introduced a modernized layout for Trilium. The ribbon has been removed and seamlessly integrated into the main interface, with a new status bar and expandable sections (such as promoted attributes) taking over key functions.\n\nThe new layout is enabled by default, and can be temporarily disabled via Options → Appearance.",
"new_layout_button": "More info",
"dismiss": "Dismiss" "dismiss": "Dismiss"
}, },
"settings": { "settings": {
@@ -2088,7 +2133,10 @@
}, },
"settings_appearance": { "settings_appearance": {
"related_code_blocks": "Color scheme for code blocks in text notes", "related_code_blocks": "Color scheme for code blocks in text notes",
"related_code_notes": "Color scheme for code notes" "related_code_notes": "Color scheme for code notes",
"ui": "User interface",
"ui_old_layout": "Old layout",
"ui_new_layout": "New layout"
}, },
"units": { "units": {
"percentage": "%" "percentage": "%"
@@ -2107,5 +2155,66 @@
}, },
"popup-editor": { "popup-editor": {
"maximize": "Switch to full editor" "maximize": "Switch to full editor"
},
"server": {
"unknown_http_error_title": "Communication error with the server",
"unknown_http_error_content": "Status code: {{statusCode}}\nURL: {{method}} {{url}}\nMessage: {{message}}",
"traefik_blocks_requests": "If you are using the Traefik reverse proxy, it introduced a breaking change which affects the communication with the server."
},
"tab_history_navigation_buttons": {
"go-back": "Go back to previous note",
"go-forward": "Go forward to next note"
},
"breadcrumb": {
"hoisted_badge": "Hoisted",
"hoisted_badge_title": "Unhoist",
"workspace_badge": "Workspace",
"scroll_to_top_title": "Jump to the beginning of the note",
"create_new_note": "Create new child note",
"empty_hide_archived_notes": "Hide archived notes"
},
"breadcrumb_badges": {
"read_only_explicit": "Read-only",
"read_only_explicit_description": "This note has been manually set to read-only.\nClick to edit it temporarily.",
"read_only_auto": "Auto read-only",
"read_only_auto_description": "This note was set automatically to read-only mode for performance reasons. This automatic limit is adjustable from settings.\n\nClick to edit it temporarily.",
"read_only_temporarily_disabled": "Temporarily editable",
"read_only_temporarily_disabled_description": "This note is currently editable, but it is normally read-only. The note will go back to being read-only as soon as you navigate to another note.\n\nClick to re-enable read-only mode.",
"shared_publicly": "Shared publicly",
"shared_locally": "Shared locally",
"shared_copy_to_clipboard": "Copy link to clipboard",
"shared_open_in_browser": "Open link in browser",
"shared_unshare": "Remove share",
"clipped_note": "Web clip",
"clipped_note_description": "This note was originally taken from {{url}}.\n\nClick to navigate to the source webpage.",
"execute_script": "Run script",
"execute_script_description": "This note is a script note. Click to execute the script.",
"execute_sql": "Run SQL",
"execute_sql_description": "This note is a SQL note. Click to execute the SQL query."
},
"status_bar": {
"language_title": "Change content language",
"note_info_title": "View note info (e.g., dates, note size)",
"backlinks_one": "{{count}} backlink",
"backlinks_other": "{{count}} backlinks",
"backlinks_title_one": "View backlink",
"backlinks_title_other": "View backlinks",
"attachments_one": "{{count}} attachment",
"attachments_other": "{{count}} attachments",
"attachments_title_one": "View attachment in a new tab",
"attachments_title_other": "View attachments in a new tab",
"attributes_one": "{{count}} attribute",
"attributes_other": "{{count}} attributes",
"attributes_title": "Owned attributes and inherited attributes",
"note_paths_one": "{{count}} path",
"note_paths_other": "{{count}} paths",
"note_paths_title": "Note paths",
"code_note_switcher": "Change language mode"
},
"right_pane": {
"empty_message": "Nothing to show for this note",
"empty_button": "Hide the panel",
"toggle": "Toggle right panel",
"custom_widget_go_to_source": "Go to source code"
} }
} }

View File

@@ -987,7 +987,8 @@
"placeholder": "Escriba el contenido de su nota de código aquí..." "placeholder": "Escriba el contenido de su nota de código aquí..."
}, },
"editable_text": { "editable_text": {
"placeholder": "Escribe aquí el contenido de tu nota..." "placeholder": "Escribe aquí el contenido de tu nota...",
"auto-detect-language": "Detectado automáticamente"
}, },
"empty": { "empty": {
"open_note_instruction": "Abra una nota escribiendo el título de la nota en la entrada a continuación o elija una nota en el árbol.", "open_note_instruction": "Abra una nota escribiendo el título de la nota en la entrada a continuación o elija una nota en el árbol.",
@@ -1812,9 +1813,6 @@
"move-to-available-launchers": "Mover a lanzadores disponibles", "move-to-available-launchers": "Mover a lanzadores disponibles",
"duplicate-launcher": "Duplicar lanzador <kbd data-command=\"duplicateSubtree\">" "duplicate-launcher": "Duplicar lanzador <kbd data-command=\"duplicateSubtree\">"
}, },
"editable-text": {
"auto-detect-language": "Detectado automáticamente"
},
"highlighting": { "highlighting": {
"title": "Bloques de código", "title": "Bloques de código",
"description": "Controla el resaltado de sintaxis para bloques de código dentro de las notas de texto, las notas de código no serán afectadas.", "description": "Controla el resaltado de sintaxis para bloques de código dentro de las notas de texto, las notas de código no serán afectadas.",

View File

@@ -107,7 +107,8 @@
"export_status": "Statut d'exportation", "export_status": "Statut d'exportation",
"export_in_progress": "Exportation en cours : {{progressCount}}", "export_in_progress": "Exportation en cours : {{progressCount}}",
"export_finished_successfully": "L'exportation s'est terminée avec succès.", "export_finished_successfully": "L'exportation s'est terminée avec succès.",
"format_pdf": "PDF - pour l'impression ou le partage de documents." "format_pdf": "PDF - pour l'impression ou le partage de documents.",
"share-format": "HTML pour la publication Web - utilise le même thème que celui utilisé pour les notes partagées, mais peut être publié sous forme de site Web statique."
}, },
"help": { "help": {
"noteNavigation": "Navigation dans les notes", "noteNavigation": "Navigation dans les notes",
@@ -161,7 +162,8 @@
"quickSearch": "aller à la recherche rapide", "quickSearch": "aller à la recherche rapide",
"inPageSearch": "recherche sur la page", "inPageSearch": "recherche sur la page",
"title": "Aide-mémoire", "title": "Aide-mémoire",
"newTabWithActivationNoteLink": "Lorsquon clique sur un lien de note, celle-ci souvre et devient active dans un nouvel onglet" "newTabWithActivationNoteLink": "Lorsquon clique sur un lien de note, celle-ci souvre et devient active dans un nouvel onglet",
"editShortcuts": "Modifier les raccourcis clavier"
}, },
"import": { "import": {
"importIntoNote": "Importer dans la note", "importIntoNote": "Importer dans la note",
@@ -203,7 +205,8 @@
"info": { "info": {
"modalTitle": "Message d'information", "modalTitle": "Message d'information",
"closeButton": "Fermer", "closeButton": "Fermer",
"okButton": "OK" "okButton": "OK",
"copy_to_clipboard": "Copier dans le presse-papiers"
}, },
"jump_to_note": { "jump_to_note": {
"search_button": "Rechercher dans le texte intégral", "search_button": "Rechercher dans le texte intégral",
@@ -689,7 +692,13 @@
"convert_into_attachment_failed": "La conversion de la note '{{title}}' a échoué.", "convert_into_attachment_failed": "La conversion de la note '{{title}}' a échoué.",
"convert_into_attachment_successful": "La note '{{title}}' a été convertie en pièce jointe.", "convert_into_attachment_successful": "La note '{{title}}' a été convertie en pièce jointe.",
"convert_into_attachment_prompt": "Êtes-vous sûr de vouloir convertir la note '{{title}}' en une pièce jointe de la note parente ?", "convert_into_attachment_prompt": "Êtes-vous sûr de vouloir convertir la note '{{title}}' en une pièce jointe de la note parente ?",
"print_pdf": "Exporter en PDF..." "print_pdf": "Exporter en PDF...",
"open_note_on_server": "Ouvrir la note sur le serveur",
"view_revisions": "Révisions...",
"advanced": "Avancé",
"export_as_image": "Exporter en tant qu'image",
"export_as_image_png": "PNG",
"export_as_image_svg": "SVG (vectoriel)"
}, },
"onclick_button": { "onclick_button": {
"no_click_handler": "Le widget bouton '{{componentId}}' n'a pas de gestionnaire de clic défini" "no_click_handler": "Le widget bouton '{{componentId}}' n'a pas de gestionnaire de clic défini"
@@ -772,7 +781,11 @@
"geo-map": "Carte géographique", "geo-map": "Carte géographique",
"board": "Tableau de bord", "board": "Tableau de bord",
"include_archived_notes": "Afficher les notes archivées", "include_archived_notes": "Afficher les notes archivées",
"presentation": "Présentation" "presentation": "Présentation",
"expand_tooltip": "Développe les éléments enfants directs de cette collection (à un niveau). Pour plus d'options, appuyez sur la flèche à droite.",
"expand_first_level": "Développer les enfants directs",
"expand_nth_level": "Développer sur {{depth}} niveaux",
"expand_all_levels": "Développer tous les niveaux"
}, },
"edited_notes": { "edited_notes": {
"no_edited_notes_found": "Aucune note modifiée ce jour-là...", "no_edited_notes_found": "Aucune note modifiée ce jour-là...",
@@ -816,7 +829,9 @@
"note_size_info": "La taille de la note fournit une estimation approximative des besoins de stockage pour cette note. Il prend en compte le contenu de la note et de ses versions.", "note_size_info": "La taille de la note fournit une estimation approximative des besoins de stockage pour cette note. Il prend en compte le contenu de la note et de ses versions.",
"calculate": "calculer", "calculate": "calculer",
"subtree_size": "(taille du sous-arbre : {{size}} pour {{count}} notes)", "subtree_size": "(taille du sous-arbre : {{size}} pour {{count}} notes)",
"title": "Infos sur la Note" "title": "Infos sur la Note",
"mime": "type MIME",
"show_similar_notes": "Afficher des notes similaires"
}, },
"note_map": { "note_map": {
"open_full": "Développer au maximum", "open_full": "Développer au maximum",
@@ -879,7 +894,8 @@
"search_parameters": "Paramètres de recherche", "search_parameters": "Paramètres de recherche",
"unknown_search_option": "Option de recherche inconnue {{searchOptionName}}", "unknown_search_option": "Option de recherche inconnue {{searchOptionName}}",
"search_note_saved": "La note de recherche a été enregistrée dans {{- notePathTitle}}", "search_note_saved": "La note de recherche a été enregistrée dans {{- notePathTitle}}",
"actions_executed": "Les actions ont été exécutées." "actions_executed": "Les actions ont été exécutées.",
"view_options": "Afficher les options:"
}, },
"similar_notes": { "similar_notes": {
"title": "Notes similaires", "title": "Notes similaires",
@@ -981,7 +997,14 @@
"placeholder": "Saisir le contenu de votre note de code ici..." "placeholder": "Saisir le contenu de votre note de code ici..."
}, },
"editable_text": { "editable_text": {
"placeholder": "Saisir le contenu de votre note ici..." "placeholder": "Saisir le contenu de votre note ici...",
"auto-detect-language": "Détecté automatiquement",
"editor_crashed_title": "L'éditeur de texte a cessé de fonctionner",
"editor_crashed_content": "Votre contenu a été récupéré avec succès, mais certaines de vos modifications les plus récentes n'ont peut-être pas été enregistrées.",
"editor_crashed_details_button": "Afficher plus de détails...",
"editor_crashed_details_intro": "Si cette erreur se produit plusieurs fois, pensez à la signaler sur GitHub en collant les informations ci-dessous.",
"editor_crashed_details_title": "Informations techniques",
"keeps-crashing": "Le composant d'édition cesse de fonctionner. Veuillez essayer de redémarrer Trilium. Si le problème persiste, envisager de créer un rapport de bogue."
}, },
"empty": { "empty": {
"open_note_instruction": "Ouvrez une note en tapant son titre dans la zone ci-dessous ou choisissez une note dans l'arborescence.", "open_note_instruction": "Ouvrez une note en tapant son titre dans la zone ci-dessous ou choisissez une note dans l'arborescence.",
@@ -1076,9 +1099,9 @@
"failed": "Échec de la synchronisation : {{message}}" "failed": "Échec de la synchronisation : {{message}}"
}, },
"vacuum_database": { "vacuum_database": {
"title": "Nettoyage la base de donnée", "title": "Nettoyage de la base de données",
"description": "Cela reconstruira la base de données, ce qui générera un fichier de base de données généralement plus petit. Aucune donnée ne sera réellement modifiée.", "description": "Cela reconstruira la base de données, ce qui générera un fichier de base de données généralement plus petit. Aucune donnée ne sera réellement modifiée.",
"button_text": "Nettoyer de la base de donnée", "button_text": "Nettoyer la base de données",
"vacuuming_database": "Nettoyage de la base de données en cours...", "vacuuming_database": "Nettoyage de la base de données en cours...",
"database_vacuumed": "La base de données a été nettoyée" "database_vacuumed": "La base de données a été nettoyée"
}, },
@@ -1109,7 +1132,8 @@
"title": "Largeur du contenu", "title": "Largeur du contenu",
"default_description": "Trilium limite par défaut la largeur maximale du contenu pour améliorer la lisibilité sur des écrans larges.", "default_description": "Trilium limite par défaut la largeur maximale du contenu pour améliorer la lisibilité sur des écrans larges.",
"max_width_label": "Largeur maximale du contenu en pixels", "max_width_label": "Largeur maximale du contenu en pixels",
"max_width_unit": "Pixels" "max_width_unit": "Pixels",
"centerContent": "Garder le contenu centré"
}, },
"native_title_bar": { "native_title_bar": {
"title": "Barre de titre native (nécessite le redémarrage de l'application)", "title": "Barre de titre native (nécessite le redémarrage de l'application)",
@@ -1148,7 +1172,10 @@
"unit": "caractères" "unit": "caractères"
}, },
"code_mime_types": { "code_mime_types": {
"title": "Types MIME disponibles dans la liste déroulante" "title": "Types MIME disponibles dans la liste déroulante",
"tooltip_syntax_highlighting": "Souligner la syntaxe",
"tooltip_code_block_syntax": "Blocs de code dans les notes de texte",
"tooltip_code_note_syntax": "Notes de code"
}, },
"vim_key_bindings": { "vim_key_bindings": {
"use_vim_keybindings_in_code_notes": "Raccourcis clavier Vim", "use_vim_keybindings_in_code_notes": "Raccourcis clavier Vim",
@@ -1617,9 +1644,6 @@
"move-to-available-launchers": "Déplacer vers les raccourcis disponibles", "move-to-available-launchers": "Déplacer vers les raccourcis disponibles",
"duplicate-launcher": "Dupliquer le raccourci <kbd data-command=\"duplicateSubtree\">" "duplicate-launcher": "Dupliquer le raccourci <kbd data-command=\"duplicateSubtree\">"
}, },
"editable-text": {
"auto-detect-language": "Détecté automatiquement"
},
"highlighting": { "highlighting": {
"description": "Contrôle la coloration syntaxique des blocs de code à l'intérieur des notes texte, les notes de code ne seront pas affectées.", "description": "Contrôle la coloration syntaxique des blocs de code à l'intérieur des notes texte, les notes de code ne seront pas affectées.",
"color-scheme": "Jeu de couleurs", "color-scheme": "Jeu de couleurs",
@@ -2076,5 +2100,15 @@
"note_completion_description": "Si cette option est activée, des liens vers des notes peuvent être créés en tapant `@` suivi du titre d'une note.", "note_completion_description": "Si cette option est activée, des liens vers des notes peuvent être créés en tapant `@` suivi du titre d'une note.",
"slash_commands_enabled": "Activer les commandes slash", "slash_commands_enabled": "Activer les commandes slash",
"slash_commands_description": "Si cette option est activée, les commandes d'édition telles que l'insertion de sauts de ligne ou d'en-têtes peuvent être activées en tapant `/`." "slash_commands_description": "Si cette option est activée, les commandes d'édition telles que l'insertion de sauts de ligne ou d'en-têtes peuvent être activées en tapant `/`."
},
"experimental_features": {
"title": "Options expérimentales",
"disclaimer": "Ces options sont expérimentales et peuvent provoquer une instabilité. Utilisez avec prudence.",
"new_layout_name": "Nouvelle mise en page",
"new_layout_description": "Essayez la nouvelle mise en page pour un look plus moderne et un usage améliorée. Sous réserve de changements importants dans les prochaines versions."
},
"read-only-info": {
"read-only-note": "Vous consultez actuellement une note en lecture seule.",
"auto-read-only-note": "Cette note s'affiche en mode lecture seule pour un chargement plus rapide."
} }
} }

View File

@@ -94,7 +94,8 @@
"info": { "info": {
"okButton": "OK", "okButton": "OK",
"closeButton": "Chiudi", "closeButton": "Chiudi",
"modalTitle": "Messaggio informativo" "modalTitle": "Messaggio informativo",
"copy_to_clipboard": "Copia negli appunti"
}, },
"export": { "export": {
"close": "Chiudi", "close": "Chiudi",
@@ -314,7 +315,7 @@
"import-into-note": "Importa nella nota", "import-into-note": "Importa nella nota",
"apply-bulk-actions": "Applica azioni in blocco", "apply-bulk-actions": "Applica azioni in blocco",
"converted-to-attachments": "{{count}} note sono state convertite in allegati.", "converted-to-attachments": "{{count}} note sono state convertite in allegati.",
"convert-to-attachment-confirm": "Sei sicuro di voler convertire le note selezionate in allegati delle note padre?", "convert-to-attachment-confirm": "Sei sicuro di voler convertire le note selezionate in allegati delle note principali? Questa operazione si applica solo alle note immagine, le altre note verranno ignorate.",
"open-in-popup": "Modifica rapida" "open-in-popup": "Modifica rapida"
}, },
"electron_context_menu": { "electron_context_menu": {
@@ -408,7 +409,8 @@
"search_parameters": "Parametri di ricerca", "search_parameters": "Parametri di ricerca",
"unknown_search_option": "Opzione di ricerca sconosciuta {{searchOptionName}}", "unknown_search_option": "Opzione di ricerca sconosciuta {{searchOptionName}}",
"search_note_saved": "La nota di ricerca è stata salvata in {{- notePathTitle}}", "search_note_saved": "La nota di ricerca è stata salvata in {{- notePathTitle}}",
"actions_executed": "Le azioni sono state eseguite." "actions_executed": "Le azioni sono state eseguite.",
"view_options": "Opzioni di visualizzazione:"
}, },
"modal": { "modal": {
"close": "Chiudi", "close": "Chiudi",
@@ -1260,7 +1262,13 @@
"convert_into_attachment_successful": "Nota '{{title}}' è stato convertito in allegato.", "convert_into_attachment_successful": "Nota '{{title}}' è stato convertito in allegato.",
"convert_into_attachment_prompt": "Sei sicuro di voler convertire la nota '{{title}}' in un allegato della nota padre?", "convert_into_attachment_prompt": "Sei sicuro di voler convertire la nota '{{title}}' in un allegato della nota padre?",
"print_pdf": "Esporta come PDF...", "print_pdf": "Esporta come PDF...",
"open_note_on_server": "Apri una nota sul server" "open_note_on_server": "Apri una nota sul server",
"view_revisions": "Revisioni...",
"advanced": "Avanzato",
"export_as_image": "Esporta come immagine",
"export_as_image_png": "PNG (raster)",
"export_as_image_svg": "SVG (vector)",
"note_map": "Mappa"
}, },
"onclick_button": { "onclick_button": {
"no_click_handler": "Il widget pulsante '{{componentId}}' non ha un gestore di clic definito" "no_click_handler": "Il widget pulsante '{{componentId}}' non ha un gestore di clic definito"
@@ -1360,7 +1368,7 @@
"file_type": "Tipo di file", "file_type": "Tipo di file",
"file_size": "Dimensione del file", "file_size": "Dimensione del file",
"download": "Scaricamento", "download": "Scaricamento",
"open": "Aprire", "open": "Aprire esternamente",
"upload_new_revision": "Carica nuova revisione", "upload_new_revision": "Carica nuova revisione",
"upload_success": "È stata caricata una nuova revisione del file.", "upload_success": "È stata caricata una nuova revisione del file.",
"upload_failed": "Caricamento di una nuova revisione del file non riuscito.", "upload_failed": "Caricamento di una nuova revisione del file non riuscito.",
@@ -1391,7 +1399,8 @@
"note_size_info": "La dimensione della nota fornisce una stima approssimativa dei requisiti di archiviazione per questa nota. Tiene conto del contenuto della nota e del contenuto delle sue revisioni.", "note_size_info": "La dimensione della nota fornisce una stima approssimativa dei requisiti di archiviazione per questa nota. Tiene conto del contenuto della nota e del contenuto delle sue revisioni.",
"calculate": "calcolare", "calculate": "calcolare",
"subtree_size": "(dimensione del sottoalbero: {{size}} in {{count}} note)", "subtree_size": "(dimensione del sottoalbero: {{size}} in {{count}} note)",
"title": "Nota informativa" "title": "Nota informativa",
"show_similar_notes": "Mostra note simili"
}, },
"note_map": { "note_map": {
"open_full": "Espandi completamente", "open_full": "Espandi completamente",
@@ -1491,7 +1500,14 @@
"placeholder": "Digita qui il contenuto della tua nota di codice..." "placeholder": "Digita qui il contenuto della tua nota di codice..."
}, },
"editable_text": { "editable_text": {
"placeholder": "Digita qui il contenuto della tua nota..." "placeholder": "Digita qui il contenuto della tua nota...",
"auto-detect-language": "Rilevato automaticamente",
"keeps-crashing": "Il componente di modifica continua a bloccarsi. Prova a riavviare Trilium. Se il problema persiste, valuta la possibilità di creare una segnalazione di bug.",
"editor_crashed_title": "L'editor di testo si è bloccato",
"editor_crashed_content": "I tuoi contenuti sono stati recuperati con successo, ma alcune delle modifiche più recenti potrebbero non essere state salvate.",
"editor_crashed_details_button": "Visualizza ulteriori dettagli...",
"editor_crashed_details_intro": "Se questo errore si verifica più volte, valuta la possibilità di segnalarlo su GitHub incollando le informazioni riportate di seguito.",
"editor_crashed_details_title": "Informazioni tecniche"
}, },
"empty": { "empty": {
"open_note_instruction": "Apri una nota digitandone il titolo nel campo sottostante oppure scegli una nota nell'albero.", "open_note_instruction": "Apri una nota digitandone il titolo nel campo sottostante oppure scegli una nota nell'albero.",
@@ -1865,7 +1881,14 @@
"printing_pdf": "Esportazione in PDF in corso..." "printing_pdf": "Esportazione in PDF in corso..."
}, },
"note_title": { "note_title": {
"placeholder": "scrivi qui il titolo della nota..." "placeholder": "scrivi qui il titolo della nota...",
"created_on": "Creato il <Value />",
"last_modified": "Modificato il <Value />",
"note_type_switcher_label": "Passa da {{type}} a:",
"note_type_switcher_others": "Altro tipo di nota",
"note_type_switcher_templates": "Modello",
"note_type_switcher_collection": "Collezione",
"edited_notes": "Note modificate"
}, },
"search_result": { "search_result": {
"no_notes_found": "Non sono state trovate note per i parametri di ricerca specificati.", "no_notes_found": "Non sono state trovate note per i parametri di ricerca specificati.",
@@ -1937,10 +1960,6 @@
"move-to-available-launchers": "Passa ai launcher disponibili", "move-to-available-launchers": "Passa ai launcher disponibili",
"duplicate-launcher": "Duplica il launcher <kbd data-command=\"duplicateSubtree\">" "duplicate-launcher": "Duplica il launcher <kbd data-command=\"duplicateSubtree\">"
}, },
"editable-text": {
"auto-detect-language": "Rilevato automaticamente",
"keeps-crashing": "Il componente di modifica continua a bloccarsi. Prova a riavviare Trilium. Se il problema persiste, valuta la possibilità di creare una segnalazione di bug."
},
"highlighting": { "highlighting": {
"title": "Blocchi di codice", "title": "Blocchi di codice",
"description": "Controlla l'evidenziazione della sintassi per i blocchi di codice all'interno delle note di testo; le note di codice non saranno interessate.", "description": "Controlla l'evidenziazione della sintassi per i blocchi di codice all'interno delle note di testo; le note di codice non saranno interessate.",
@@ -2005,8 +2024,9 @@
"unknown_widget": "Widget sconosciuto per \"{{id}}\"." "unknown_widget": "Widget sconosciuto per \"{{id}}\"."
}, },
"note_language": { "note_language": {
"not_set": "Non impostato", "not_set": "Nessuna lingua impostata",
"configure-languages": "Configura le lingue..." "configure-languages": "Configura le lingue...",
"help-on-languages": "Aiuto sulle lingue dei contenuti..."
}, },
"content_language": { "content_language": {
"title": "Lingue dei contenuti", "title": "Lingue dei contenuti",
@@ -2024,7 +2044,8 @@
"button_title": "Esporta diagramma come PNG" "button_title": "Esporta diagramma come PNG"
}, },
"svg": { "svg": {
"export_to_png": "Non è stato possibile esportare il diagramma in formato PNG." "export_to_png": "Non è stato possibile esportare il diagramma in formato PNG.",
"export_to_svg": "Il diagramma non può essere esportato in formato SVG."
}, },
"code_theme": { "code_theme": {
"title": "Aspetto", "title": "Aspetto",
@@ -2034,7 +2055,7 @@
"book_properties_config": { "book_properties_config": {
"hide-weekends": "Nascondi i fine settimana", "hide-weekends": "Nascondi i fine settimana",
"display-week-numbers": "Visualizza i numeri delle settimane", "display-week-numbers": "Visualizza i numeri delle settimane",
"map-style": "Stile mappa:", "map-style": "Stile mappa",
"max-nesting-depth": "Profondità massima di nidificazione:", "max-nesting-depth": "Profondità massima di nidificazione:",
"raster": "Trama", "raster": "Trama",
"vector_light": "Vettore (Luce)", "vector_light": "Vettore (Luce)",
@@ -2108,5 +2129,67 @@
}, },
"popup-editor": { "popup-editor": {
"maximize": "Passa all'editor completo" "maximize": "Passa all'editor completo"
},
"experimental_features": {
"title": "Opzioni sperimentali",
"disclaimer": "Queste opzioni sono sperimentali e potrebbero causare instabilità. Usare con cautela.",
"new_layout_name": "Nuovo layout",
"new_layout_description": "Prova il nuovo layout per un look più moderno e una maggiore usabilità. Soggetto a modifiche significative nelle prossime versioni."
},
"server": {
"unknown_http_error_title": "Errore di comunicazione con il server",
"unknown_http_error_content": "Codice di stato: {{statusCode}}\nURL: {{method}} {{url}}\nMessaggio: {{message}}",
"traefik_blocks_requests": "Se si utilizza il proxy inverso Traefik, è stata introdotta una modifica sostanziale che influisce sulla comunicazione con il server."
},
"tab_history_navigation_buttons": {
"go-back": "Torna alla nota precedente",
"go-forward": "Passa alla nota successiva"
},
"breadcrumb_badges": {
"read_only_explicit": "Sola lettura",
"read_only_explicit_description": "Questa nota è stata impostata manualmente come di sola lettura.\nClicca per modificarla temporaneamente.",
"read_only_auto": "Solo lettura automatica",
"read_only_auto_description": "Questa nota è stata impostata automaticamente in modalità di sola lettura per motivi di prestazioni. Questo limite automatico è modificabile dalle impostazioni.\n\nClicca per modificarla temporaneamente.",
"read_only_temporarily_disabled": "Modificabile temporaneamente",
"read_only_temporarily_disabled_description": "Questa nota è attualmente modificabile, ma normalmente è di sola lettura. La nota tornerà ad essere di sola lettura non appena passerai a un'altra nota.\n\nClicca per riattivare la modalità di sola lettura.",
"shared_publicly": "Condiviso pubblicamente",
"shared_locally": "Condiviso localmente",
"clipped_note": "Clip web",
"clipped_note_description": "Questa nota è stata originariamente presa da {{url}}.\n\nClicca per andare alla pagina web di origine.",
"execute_script": "Esegui script",
"execute_script_description": "Questa nota è una nota di script. Clicca per eseguire lo script.",
"execute_sql": "Esegui SQL",
"execute_sql_description": "Questa nota è una nota SQL. Clicca per eseguire la query SQL."
},
"breadcrumb": {
"workspace_badge": "Area di lavoro",
"scroll_to_top_title": "Vai all'inizio della nota",
"hoisted_badge": "Sollevato",
"hoisted_badge_title": "Abbassato"
},
"status_bar": {
"language_title": "Cambia lingua dei contenuti",
"note_info_title": "Visualizza informazioni sulla nota (ad es. date, dimensioni della nota)",
"backlinks_one": "{{count}} backlink",
"backlinks_many": "{{count}} backlinks",
"backlinks_other": "{{count}} backlinks",
"backlinks_title_one": "Visualizza backlink",
"backlinks_title_many": "Visualizza backlinks",
"backlinks_title_other": "Visualizza backlinks",
"attachments_one": "{{count}} allegato",
"attachments_many": "{{count}} allegati",
"attachments_other": "{{count}} allegati",
"attachments_title_one": "Visualizza allegato in una nuova scheda",
"attachments_title_many": "Visualizza allegati in una nuova scheda",
"attachments_title_other": "Visualizza allegati in una nuova scheda",
"attributes_one": "{{count}} attributo",
"attributes_many": "{{count}} attributi",
"attributes_other": "{{count}} attributi",
"attributes_title": "Attributi posseduti e attributi ereditati",
"note_paths_one": "{{count}} percorso",
"note_paths_many": "{{count}} percorsi",
"note_paths_other": "{{count}} percorsi",
"note_paths_title": "Nota percorsi",
"code_note_switcher": "Cambia modalità lingua"
} }
} }

View File

@@ -218,7 +218,8 @@
"unknown_search_option": "不明な検索オプション {{searchOptionName}}", "unknown_search_option": "不明な検索オプション {{searchOptionName}}",
"search_note_saved": "検索ノートが {{- notePathTitle}} に保存されました", "search_note_saved": "検索ノートが {{- notePathTitle}} に保存されました",
"actions_executed": "アクションが実行されました。", "actions_executed": "アクションが実行されました。",
"ancestor": "祖先:" "ancestor": "祖先:",
"view_options": "表示オプション:"
}, },
"shortcuts": { "shortcuts": {
"multiple_shortcuts": "同じアクションに対して複数のショートカットを設定する場合、カンマで区切ることができます。", "multiple_shortcuts": "同じアクションに対して複数のショートカットを設定する場合、カンマで区切ることができます。",
@@ -258,7 +259,7 @@
"export_in_progress": "エクスポート処理中: {{progressCount}}", "export_in_progress": "エクスポート処理中: {{progressCount}}",
"export_finished_successfully": "エクスポートが正常に完了しました。", "export_finished_successfully": "エクスポートが正常に完了しました。",
"format_pdf": "PDF - 印刷または共有目的に。", "format_pdf": "PDF - 印刷または共有目的に。",
"share-format": "Web 公開用の HTML - 共有ノートで使用されるのと同じテーマを使用しますが、静的 Web サイトとして公開できます。" "share-format": "web 公開用の HTML - 共有ノートで使用されるのと同じテーマを使用しますが、静的 web サイトとして公開できます。"
}, },
"help": { "help": {
"title": "チートシート", "title": "チートシート",
@@ -290,7 +291,7 @@
"pasteNotes": "ノートをサブノートとしてアクティブノートに貼り付ける(コピーされたか切り取りされたかに よって、移動またはクローンになる)", "pasteNotes": "ノートをサブノートとしてアクティブノートに貼り付ける(コピーされたか切り取りされたかに よって、移動またはクローンになる)",
"deleteNotes": "ノート/サブツリーを削除", "deleteNotes": "ノート/サブツリーを削除",
"editingNotes": "ノート編集", "editingNotes": "ノート編集",
"editNoteTitle": "ツリーペインでEnterキーを押すと、ツリーペインからートタイトルに切り替わります。ートタイトルだとテキストエディタにフォーカスが切り替わります。<kbd>Ctrl+.</kbd> を押すと、エディタからツリーペインに戻ります。", "editNoteTitle": "ツリーペインでEnterキーを押すと、ツリーペインからートタイトルに切り替わります。ートタイトルだとテキストエディタにフォーカスが切り替わります。<kbd>Ctrl+.</kbd> を押すと、エディタからツリーペインに戻ります。",
"createEditLink": "外部リンクの作成/編集", "createEditLink": "外部リンクの作成/編集",
"createInternalLink": "内部リンクの作成", "createInternalLink": "内部リンクの作成",
"followLink": "カーソル下のリンクをたどる", "followLink": "カーソル下のリンクをたどる",
@@ -421,10 +422,10 @@
"apply-bulk-actions": "一括操作の適用", "apply-bulk-actions": "一括操作の適用",
"converted-to-attachments": "{{count}}ノートが添付ファイルに変換されました。", "converted-to-attachments": "{{count}}ノートが添付ファイルに変換されました。",
"convert-to-attachment": "添付ファイルに変換", "convert-to-attachment": "添付ファイルに変換",
"convert-to-attachment-confirm": "選択したノートを親ノートの添付ファイルに変換しますか?", "convert-to-attachment-confirm": "選択したノートを親ノートの添付ファイルに変換してもよろしいですか?この操作は画像ノートにのみ適用され、その他のノートはスキップされます。",
"open-in-popup": "クイック編集", "open-in-popup": "クイック編集",
"hoist-note": "ホイストノート", "hoist-note": "ホイストノート",
"unhoist-note": "ノートホイストしない", "unhoist-note": "ノートホイストを解除",
"edit-branch-prefix": "ブランチの接頭辞を編集", "edit-branch-prefix": "ブランチの接頭辞を編集",
"archive": "アーカイブ", "archive": "アーカイブ",
"unarchive": "アーカイブ解除" "unarchive": "アーカイブ解除"
@@ -458,7 +459,13 @@
"convert_into_attachment_successful": "ノート '{{title}}' は添付ファイルに変換されました。", "convert_into_attachment_successful": "ノート '{{title}}' は添付ファイルに変換されました。",
"convert_into_attachment_prompt": "本当にノート '{{title}}' を親ノートの添付ファイルに変換しますか?", "convert_into_attachment_prompt": "本当にノート '{{title}}' を親ノートの添付ファイルに変換しますか?",
"note_attachments": "ノートの添付ファイル", "note_attachments": "ノートの添付ファイル",
"open_note_on_server": "サーバー上のノートを開く" "open_note_on_server": "サーバー上のノートを開く",
"view_revisions": "ノートの変更履歴...",
"note_map": "ノートマップ",
"advanced": "高度",
"export_as_image": "画像としてエクスポート",
"export_as_image_png": "PNG (raster)",
"export_as_image_svg": "SVG (vector)"
}, },
"command_palette": { "command_palette": {
"export_note_title": "ノートをエクスポート", "export_note_title": "ノートをエクスポート",
@@ -526,7 +533,7 @@
"button_title": "ボタンを表示" "button_title": "ボタンを表示"
}, },
"svg_export_button": { "svg_export_button": {
"button_title": "図をSVGとしてエクスポート" "button_title": "図をSVG形式でエクスポート"
}, },
"book_properties": { "book_properties": {
"grid": "グリッド", "grid": "グリッド",
@@ -583,7 +590,7 @@
"file_type": "ファイルタイプ", "file_type": "ファイルタイプ",
"file_size": "ファイルサイズ", "file_size": "ファイルサイズ",
"download": "ダウンロード", "download": "ダウンロード",
"open": "開く", "open": "外部で開く",
"title": "ファイル", "title": "ファイル",
"upload_new_revision": "編集履歴をアップロード", "upload_new_revision": "編集履歴をアップロード",
"original_file_name": "元のファイル名", "original_file_name": "元のファイル名",
@@ -599,7 +606,9 @@
"calculate": "計算", "calculate": "計算",
"subtree_size": "(サブツリーサイズ: {{size}}、ノード数: {{count}}", "subtree_size": "(サブツリーサイズ: {{size}}、ノード数: {{count}}",
"title": "ノート情報", "title": "ノート情報",
"note_size_info": "ノートのサイズは、このノートに必要なストレージの概算を示します。これは、ノートの内容とそのノートの編集履歴の内容を考慮したものです。" "note_size_info": "ノートのサイズは、このノートに必要なストレージの概算を示します。これは、ノートの内容とそのノートの編集履歴の内容を考慮したものです。",
"show_similar_notes": "類似のノートを表示",
"mime": "MIME タイプ"
}, },
"image_properties": { "image_properties": {
"file_type": "ファイルタイプ", "file_type": "ファイルタイプ",
@@ -799,7 +808,7 @@
}, },
"web_view": { "web_view": {
"web_view": "Web ビュー", "web_view": "Web ビュー",
"embed_websites": "Web ビュータイプでは、ウェブサイトをTriliumに埋め込むことができます。", "embed_websites": "Web ビュータイプでは、web サイトを Trilium に埋め込むことができます。",
"create_label": "まず始めに、埋め込みたいURLアドレスのラベルを作成してください。例: #webViewSrc=\"https://www.google.com\"" "create_label": "まず始めに、埋め込みたいURLアドレスのラベルを作成してください。例: #webViewSrc=\"https://www.google.com\""
}, },
"backend_log": { "backend_log": {
@@ -961,7 +970,7 @@
"password": { "password": {
"wiki": "wiki", "wiki": "wiki",
"heading": "パスワード", "heading": "パスワード",
"alert_message": "新しいパスワードは大切に保管してください。パスワードはウェブインターフェースへのログインや、保護されたノートの暗号化に使用されます。パスワードを忘れると、保護されたノートはすべて永久に失われます。", "alert_message": "新しいパスワードは大切に保管してください。パスワードは web インターフェースへのログインや、保護されたノートの暗号化に使用されます。パスワードを忘れると、保護されたノートはすべて永久に失われます。",
"reset_link": "リセットするにはここをクリック。", "reset_link": "リセットするにはここをクリック。",
"old_password": "旧パスワード", "old_password": "旧パスワード",
"new_password": "新パスワード", "new_password": "新パスワード",
@@ -1011,7 +1020,8 @@
"info": { "info": {
"closeButton": "閉じる", "closeButton": "閉じる",
"modalTitle": "情報メッセージ", "modalTitle": "情報メッセージ",
"okButton": "OK" "okButton": "OK",
"copy_to_clipboard": "クリップボードにコピー"
}, },
"protected_session_password": { "protected_session_password": {
"close_label": "閉じる", "close_label": "閉じる",
@@ -1106,7 +1116,7 @@
"sql_console_home": "SQLコンソールートのデフォルトの場所", "sql_console_home": "SQLコンソールートのデフォルトの場所",
"bookmark_folder": "このラベルの付いたノートは、ブックマークにフォルダとして表示されます(子フォルダへのアクセスを許可します)", "bookmark_folder": "このラベルの付いたノートは、ブックマークにフォルダとして表示されます(子フォルダへのアクセスを許可します)",
"share_hidden_from_tree": "このートは左側のナビゲーションツリーには表示されていませんが、URL からアクセスできます", "share_hidden_from_tree": "このートは左側のナビゲーションツリーには表示されていませんが、URL からアクセスできます",
"share_external_link": "ノートは共有ツリー内で外部ウェブサイトへのリンクとして機能します", "share_external_link": "ノートは共有ツリー内で外部 web サイトへのリンクとして機能します",
"share_alias": "https://your_trilium_host/share/[your_alias] でノートを利用できるようにエイリアスを定義します", "share_alias": "https://your_trilium_host/share/[your_alias] でノートを利用できるようにエイリアスを定義します",
"share_omit_default_css": "デフォルトの共有ページのCSSは省略されます。スタイルを大幅に変更する場合に使用してください。", "share_omit_default_css": "デフォルトの共有ページのCSSは省略されます。スタイルを大幅に変更する場合に使用してください。",
"share_root": "/share root で提供されるノートをマークする。", "share_root": "/share root で提供されるノートをマークする。",
@@ -1232,7 +1242,14 @@
"none_yet": "アクションを上のリストからクリックして追加。" "none_yet": "アクションを上のリストからクリックして追加。"
}, },
"note_title": { "note_title": {
"placeholder": "ここにノートのタイトルを入力..." "placeholder": "ここにノートのタイトルを入力...",
"created_on": "<Value /> に作成",
"last_modified": "<Value /> に変更",
"note_type_switcher_label": "{{type}} から切り替え:",
"note_type_switcher_others": "その他のノートタイプ",
"note_type_switcher_templates": "テンプレート",
"note_type_switcher_collection": "コレクション",
"edited_notes": "編集済みノート"
}, },
"search_result": { "search_result": {
"no_notes_found": "指定された検索パラメータに該当するノートは見つかりませんでした。", "no_notes_found": "指定された検索パラメータに該当するノートは見つかりませんでした。",
@@ -1268,10 +1285,6 @@
"duplicate-launcher": "ランチャーの複製 <kbd data-command=\"duplicateSubtree\">", "duplicate-launcher": "ランチャーの複製 <kbd data-command=\"duplicateSubtree\">",
"reset_launcher_confirm": "本当に「{{title}}」をリセットしますか? このノート(およびその子ノート)のすべてのデータと設定が失われ、ランチャーは元の場所に戻ります。" "reset_launcher_confirm": "本当に「{{title}}」をリセットしますか? このノート(およびその子ノート)のすべてのデータと設定が失われ、ランチャーは元の場所に戻ります。"
}, },
"editable-text": {
"auto-detect-language": "自動検出",
"keeps-crashing": "編集コンポーネントがクラッシュし続けます。Trilium を再起動してください。問題が解決しない場合は、バグレポートの作成をご検討ください。"
},
"highlighting": { "highlighting": {
"title": "コードブロック", "title": "コードブロック",
"description": "テキストノート内のコードブロックのシンタックスハイライトを制御します。コードノートには影響しません。", "description": "テキストノート内のコードブロックのシンタックスハイライトを制御します。コードノートには影響しません。",
@@ -1333,8 +1346,9 @@
"minimum_input": "入力された時間値は {{minimumSeconds}} 秒以上である必要があります。" "minimum_input": "入力された時間値は {{minimumSeconds}} 秒以上である必要があります。"
}, },
"note_language": { "note_language": {
"not_set": "未設定", "not_set": "言語が設定されていません",
"configure-languages": "言語を設定..." "configure-languages": "言語を設定...",
"help-on-languages": "コンテンツの言語に関するヘルプ..."
}, },
"content_language": { "content_language": {
"title": "コンテンツの言語", "title": "コンテンツの言語",
@@ -1344,7 +1358,8 @@
"button_title": "図をPNG形式でエクスポート" "button_title": "図をPNG形式でエクスポート"
}, },
"svg": { "svg": {
"export_to_png": "図をPNG形式でエクスポートできませんでした。" "export_to_png": "図をPNG形式でエクスポートできませんでした。",
"export_to_svg": "図をSVG形式でエクスポートできませんでした。"
}, },
"code_theme": { "code_theme": {
"title": "外観", "title": "外観",
@@ -1622,7 +1637,7 @@
"remove_this_attribute": "この属性を削除", "remove_this_attribute": "この属性を削除",
"remove_color": "このカラーラベルを削除", "remove_color": "このカラーラベルを削除",
"promoted_attributes": "プロモート属性", "promoted_attributes": "プロモート属性",
"url_placeholder": "http://ウェブサイト..." "url_placeholder": "http://web サイト..."
}, },
"relation_map": { "relation_map": {
"open_in_new_tab": "新しいタブで開く", "open_in_new_tab": "新しいタブで開く",
@@ -1778,7 +1793,14 @@
"placeholder": "ここにコードノートの内容を入力..." "placeholder": "ここにコードノートの内容を入力..."
}, },
"editable_text": { "editable_text": {
"placeholder": "ここにノートの内容を入力..." "placeholder": "ここにノートの内容を入力...",
"auto-detect-language": "自動検出",
"keeps-crashing": "編集コンポーネントがクラッシュし続けます。Trilium を再起動してください。問題が解決しない場合は、バグレポートの作成をご検討ください。",
"editor_crashed_title": "テキストエディターがクラッシュしました",
"editor_crashed_content": "コンテンツは正常に復元されましたが、最近の変更の一部が保存されていない可能性があります。",
"editor_crashed_details_button": "詳細を見る...",
"editor_crashed_details_intro": "このエラーが何度も発生する場合は、以下の情報を貼り付けて GitHub に報告することを検討してください。",
"editor_crashed_details_title": "技術情報"
}, },
"empty": { "empty": {
"open_note_instruction": "以下の入力欄にノートのタイトルを入力するか、ツリー内のノートを選択してノートを開きます。", "open_note_instruction": "以下の入力欄にノートのタイトルを入力するか、ツリー内のノートを選択してノートを開きます。",
@@ -1969,7 +1991,7 @@
"book_properties_config": { "book_properties_config": {
"hide-weekends": "週末を非表示", "hide-weekends": "週末を非表示",
"display-week-numbers": "週番号を表示", "display-week-numbers": "週番号を表示",
"map-style": "マップスタイル:", "map-style": "マップスタイル",
"max-nesting-depth": "最大階層の深さ:", "max-nesting-depth": "最大階層の深さ:",
"show-scale": "スケールを表示", "show-scale": "スケールを表示",
"raster": "Raster", "raster": "Raster",
@@ -1983,14 +2005,20 @@
"background_effects_title": "背景効果が安定しました", "background_effects_title": "背景効果が安定しました",
"background_effects_message": "Windowsデバイスでは、背景効果が完全に安定しました。背景効果は、背景をぼかすことでユーザーインターフェースに彩りを添えます。この技術は、Windowsエクスプローラーなどの他のアプリケーションでも使用されています。", "background_effects_message": "Windowsデバイスでは、背景効果が完全に安定しました。背景効果は、背景をぼかすことでユーザーインターフェースに彩りを添えます。この技術は、Windowsエクスプローラーなどの他のアプリケーションでも使用されています。",
"background_effects_button": "背景効果を有効にする", "background_effects_button": "背景効果を有効にする",
"dismiss": "却下" "dismiss": "却下",
"new_layout_title": "新しいレイアウト",
"new_layout_message": "Trilium のレイアウトを刷新しました。リボンは廃止され、メインインターフェースにシームレスに統合されました。主要な機能は、新しいステータスバーと展開可能なセクション(プロモート属性など)に集約されています。\n\n新しいレイアウトはデフォルトで有効になっていますが、「オプション」→「外観」から一時的に無効にすることもできます。",
"new_layout_button": "詳細情報"
}, },
"settings": { "settings": {
"related_settings": "関連設定" "related_settings": "関連設定"
}, },
"settings_appearance": { "settings_appearance": {
"related_code_blocks": "テキストノート内のコードブロックの配色", "related_code_blocks": "テキストノート内のコードブロックの配色",
"related_code_notes": "コードノートの配色" "related_code_notes": "コードノートの配色",
"ui": "ユーザーインターフェース",
"ui_old_layout": "旧レイアウト",
"ui_new_layout": "新しいレイアウト"
}, },
"units": { "units": {
"percentage": "%" "percentage": "%"
@@ -2064,7 +2092,7 @@
"recovery_keys_used": "使用日: {{date}}", "recovery_keys_used": "使用日: {{date}}",
"recovery_keys_unused": "回復コード {{index}} は未使用です", "recovery_keys_unused": "回復コード {{index}} は未使用です",
"oauth_title": "OAuth/OpenID", "oauth_title": "OAuth/OpenID",
"oauth_description": "OpenIDは、Googleなどの他のサービスのアカウントを使用してウェブサイトにログインし、本人確認を行うための標準化された方法です。デフォルトの発行者はGoogleですが、他のOpenIDプロバイダに変更できます。詳しくは<a href=\"#root/_hidden/_help/_help_Otzi9La2YAUX/_help_WOcw2SLH6tbX/_help_7DAiwaf8Z7Rz\">こちら</a>をご覧ください。Google経由でOpenIDサービスを設定するには、<a href=\"https://developers.google.com/identity/openid-connect/openid-connect\">こちらの手順</a>に従ってください。", "oauth_description": "OpenIDは、Googleなどの他のサービスのアカウントを使用して web サイトにログインし、本人確認を行うための標準化された方法です。デフォルトの発行者はGoogleですが、他のOpenIDプロバイダに変更できます。詳しくは<a href=\"#root/_hidden/_help/_help_Otzi9La2YAUX/_help_WOcw2SLH6tbX/_help_7DAiwaf8Z7Rz\">こちら</a>をご覧ください。Google経由でOpenIDサービスを設定するには、<a href=\"https://developers.google.com/identity/openid-connect/openid-connect\">こちらの手順</a>に従ってください。",
"oauth_description_warning": "OAuth/OpenIDを有効にするには、config.iniファイルにOAuth/OpenIDのベースURL、クライアントID、クライアントシークレットを設定し、アプリケーションを再起動する必要があります。環境変数から設定する場合は、TRILIUM_OAUTH_BASE_URL, TRILIUM_OAUTH_CLIENT_ID and TRILIUM_OAUTH_CLIENT_SECRET を設定してください。", "oauth_description_warning": "OAuth/OpenIDを有効にするには、config.iniファイルにOAuth/OpenIDのベースURL、クライアントID、クライアントシークレットを設定し、アプリケーションを再起動する必要があります。環境変数から設定する場合は、TRILIUM_OAUTH_BASE_URL, TRILIUM_OAUTH_CLIENT_ID and TRILIUM_OAUTH_CLIENT_SECRET を設定してください。",
"oauth_missing_vars": "設定がありません: {{-variables}}", "oauth_missing_vars": "設定がありません: {{-variables}}",
"oauth_user_account": "ユーザーアカウント: ", "oauth_user_account": "ユーザーアカウント: ",
@@ -2106,5 +2134,60 @@
}, },
"popup-editor": { "popup-editor": {
"maximize": "フルエディターに切り替え" "maximize": "フルエディターに切り替え"
},
"server": {
"unknown_http_error_title": "サーバーとの通信エラー",
"unknown_http_error_content": "ステータスコード: {{statusCode}}\nURL: {{method}} {{url}}\nメッセージ: {{message}}",
"traefik_blocks_requests": "Traefik リバース プロキシを使用している場合、サーバーとの通信に影響する重大な変更が導入されました。"
},
"tab_history_navigation_buttons": {
"go-back": "前のノートに戻る",
"go-forward": "次のノートに進む"
},
"experimental_features": {
"title": "実験オプション",
"disclaimer": "これらのオプションは試験的なもので、動作が不安定になる可能性があります。注意してご使用ください。",
"new_layout_name": "新しいレイアウト",
"new_layout_description": "よりモダンな外観と使いやすさが向上した新しいレイアウトをお試しください。今後のリリースで大幅な変更が加えられる可能性があります。"
},
"breadcrumb_badges": {
"read_only_explicit": "読み取り専用",
"read_only_auto": "自動的に読み取り専用",
"shared_publicly": "公開で共有",
"shared_locally": "ローカルで共有",
"read_only_explicit_description": "このノートは手動で読み取り専用に設定されています。\nクリックすると一時的に編集できます。",
"read_only_temporarily_disabled": "一時的に編集可能",
"read_only_auto_description": "このノートはパフォーマンス上の理由により、自動的に読み取り専用モードに設定されました。この自動制限は設定から調整できます。\n\n一時的に編集するにはクリックしてください。",
"read_only_temporarily_disabled_description": "このノートは現在編集可能ですが、通常は読み取り専用です。別のノートに移動すると読み取り専用に戻ります。\n\nクリックすると読み取り専用モードが再度有効になります。",
"clipped_note": "Web クリップ",
"clipped_note_description": "このノートは {{url}} から取得されました。\n\nクリックすると元の web ページに移動します。",
"execute_script": "スクリプトを実行",
"execute_script_description": "このノートはスクリプトノートです。クリックするとスクリプトが実行されます。",
"execute_sql": "SQL を実行",
"execute_sql_description": "このノートは SQL ノートです。クリックすると SQL クエリが実行されます。",
"shared_copy_to_clipboard": "リンクをクリップボードにコピー",
"shared_open_in_browser": "ブラウザでリンクを開く",
"shared_unshare": "共有を削除"
},
"status_bar": {
"language_title": "コンテンツの言語を変更",
"note_info_title": "ノート情報を表示(例: 日付、ノートのサイズなど)",
"backlinks_title_other": "バックリンクを表示",
"attachments_title_other": "添付ファイルを新しいタブで表示",
"attributes_other": "{{count}} 個の属性",
"attributes_title": "所有属性と継承属性",
"note_paths_title": "ノートパス",
"code_note_switcher": "言語モードを変更",
"backlinks_other": "{{count}} バックリンク",
"attachments_other": "{{count}} 件の添付ファイル",
"note_paths_other": "{{count}} 個のパス"
},
"breadcrumb": {
"hoisted_badge": "ホイスト",
"hoisted_badge_title": "ホイスト解除",
"workspace_badge": "ワークスペース",
"scroll_to_top_title": "ノートの先頭にジャンプ",
"create_new_note": "新しい子ノートを作成",
"empty_hide_archived_notes": "アーカイブされたノートを非表示"
} }
} }

View File

@@ -50,12 +50,24 @@
"available_actions": "가능한 액션들", "available_actions": "가능한 액션들",
"chosen_actions": "선택한 액션들", "chosen_actions": "선택한 액션들",
"execute_bulk_actions": "대량 액션들 실행", "execute_bulk_actions": "대량 액션들 실행",
"bulk_actions_executed": "대량 액션들이 성공적으로 실행되었습니다." "bulk_actions_executed": "대량 액션들이 성공적으로 실행되었습니다.",
"none_yet": "아직 없습니다... 위에 있는 가능한 작업 중 하나를 클릭하여 작업을 추가하세요.",
"labels": "라벨",
"relations": "관계",
"notes": "노트",
"other": "기타"
}, },
"i18n": { "i18n": {
"saturday": "토요일", "saturday": "토요일",
"sunday": "일요일", "sunday": "일요일",
"first-week-of-the-year": "일년의 첫째 주", "first-week-of-the-year": "일년의 첫째 주",
"first-week-contains-first-day": "첫 번째 주에는 올해의 첫날이 포함됩니다" "first-week-contains-first-day": "첫 번째 주에는 올해의 첫날이 포함됩니다"
},
"clone_to": {
"clone_notes_to": "~로 노트 복제",
"help_on_links": "링크에 대한 도움말",
"notes_to_clone": "노트 클론 생성",
"target_parent_note": "부모 노트 타겟",
"search_for_note_by_its_name": "이름으로 노트 검색하기"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -954,7 +954,8 @@
"placeholder": "Digite o conteúdo da sua nota de código aqui…" "placeholder": "Digite o conteúdo da sua nota de código aqui…"
}, },
"editable_text": { "editable_text": {
"placeholder": "Digite o conteúdo da sua nota aqui…" "placeholder": "Digite o conteúdo da sua nota aqui…",
"auto-detect-language": "Detetado automaticamente"
}, },
"empty": { "empty": {
"open_note_instruction": "Abra uma nota a digitar o título da nota no campo abaixo ou escolha uma nota na árvore.", "open_note_instruction": "Abra uma nota a digitar o título da nota no campo abaixo ou escolha uma nota na árvore.",
@@ -1768,9 +1769,6 @@
"move-to-available-launchers": "Mover para lançadores disponíveis", "move-to-available-launchers": "Mover para lançadores disponíveis",
"duplicate-launcher": "Duplicar o lançador <kbd data-command=\"duplicateSubtree\">" "duplicate-launcher": "Duplicar o lançador <kbd data-command=\"duplicateSubtree\">"
}, },
"editable-text": {
"auto-detect-language": "Detetado automaticamente"
},
"highlighting": { "highlighting": {
"title": "Blocos de Código", "title": "Blocos de Código",
"description": "Controla o destaque de sintaxe para blocos de código dentro de notas de texto, notas de código não serão afetadas.", "description": "Controla o destaque de sintaxe para blocos de código dentro de notas de texto, notas de código não serão afetadas.",

View File

@@ -1191,7 +1191,8 @@
"placeholder": "Digite o conteúdo da sua nota de código aqui…" "placeholder": "Digite o conteúdo da sua nota de código aqui…"
}, },
"editable_text": { "editable_text": {
"placeholder": "Digite o conteúdo da sua nota aqui…" "placeholder": "Digite o conteúdo da sua nota aqui…",
"auto-detect-language": "Detectado automaticamente"
}, },
"empty": { "empty": {
"search_placeholder": "buscar uma nota pelo nome", "search_placeholder": "buscar uma nota pelo nome",
@@ -1689,9 +1690,6 @@
"move-to-available-launchers": "Mover para lançadores disponíveis", "move-to-available-launchers": "Mover para lançadores disponíveis",
"duplicate-launcher": "Duplicar o lançador <kbd data-command=\"duplicateSubtree\">" "duplicate-launcher": "Duplicar o lançador <kbd data-command=\"duplicateSubtree\">"
}, },
"editable-text": {
"auto-detect-language": "Detectado automaticamente"
},
"highlighting": { "highlighting": {
"title": "Blocos de Código", "title": "Blocos de Código",
"description": "Controla o destaque de sintaxe para blocos de código dentro de notas de texto, notas de código não serão afetadas.", "description": "Controla o destaque de sintaxe para blocos de código dentro de notas de texto, notas de código não serão afetadas.",

View File

@@ -491,7 +491,14 @@
"placeholder": "Scrieți conținutul notiței de cod aici..." "placeholder": "Scrieți conținutul notiței de cod aici..."
}, },
"editable_text": { "editable_text": {
"placeholder": "Scrieți conținutul notiței aici..." "placeholder": "Scrieți conținutul notiței aici...",
"auto-detect-language": "Automat",
"keeps-crashing": "Componenta de editare se blochează în continuu. Încercați să reporniți Trilium. Dacă problema persistă, luați în considerare să raportați această problemă.",
"editor_crashed_title": "Editorul text a avut o eroare",
"editor_crashed_content": "Conținutul a fost recuperat cu succes, dar este posibil ca o parte din cele mai recente modificări ale dvs. să nu se fi salvat.",
"editor_crashed_details_button": "Mai multe detalii...",
"editor_crashed_details_intro": "Dacă întâmpinați frecvent această eroare, considerați să o raportați pe GitHub copiând informația de mai jos.",
"editor_crashed_details_title": "Informații tehnice"
}, },
"edited_notes": { "edited_notes": {
"deleted": "(șters)", "deleted": "(șters)",
@@ -783,7 +790,8 @@
"info": { "info": {
"closeButton": "Închide", "closeButton": "Închide",
"modalTitle": "Mesaj informativ", "modalTitle": "Mesaj informativ",
"okButton": "OK" "okButton": "OK",
"copy_to_clipboard": "Copiază în clipboard"
}, },
"inherited_attribute_list": { "inherited_attribute_list": {
"no_inherited_attributes": "Niciun atribut moștenit.", "no_inherited_attributes": "Niciun atribut moștenit.",
@@ -865,12 +873,14 @@
"print_note": "Imprimare notiță", "print_note": "Imprimare notiță",
"re_render_note": "Reinterpretare notiță", "re_render_note": "Reinterpretare notiță",
"save_revision": "Salvează o nouă revizie", "save_revision": "Salvează o nouă revizie",
"advanced": "Advansat",
"search_in_note": "Caută în notiță", "search_in_note": "Caută în notiță",
"convert_into_attachment_failed": "Nu s-a putut converti notița „{{title}}”.", "convert_into_attachment_failed": "Nu s-a putut converti notița „{{title}}”.",
"convert_into_attachment_successful": "Notița „{{title}}” a fost convertită în atașament.", "convert_into_attachment_successful": "Notița „{{title}}” a fost convertită în atașament.",
"convert_into_attachment_prompt": "Doriți convertirea notiței „{{title}}” într-un atașament al notiței părinte?", "convert_into_attachment_prompt": "Doriți convertirea notiței „{{title}}” într-un atașament al notiței părinte?",
"print_pdf": "Exportare ca PDF...", "print_pdf": "Exportare ca PDF...",
"open_note_on_server": "Deschide notița pe server" "open_note_on_server": "Deschide notița pe server",
"view_revisions": "Revizii ale notițelor..."
}, },
"note_erasure_timeout": { "note_erasure_timeout": {
"deleted_notes_erased": "Notițele șterse au fost eliminate permanent.", "deleted_notes_erased": "Notițele șterse au fost eliminate permanent.",
@@ -1405,7 +1415,7 @@
"hoist-note": "Focalizează notița", "hoist-note": "Focalizează notița",
"unhoist-note": "Defocalizează notița", "unhoist-note": "Defocalizează notița",
"converted-to-attachments": "{{count}} notițe au fost convertite în atașamente.", "converted-to-attachments": "{{count}} notițe au fost convertite în atașamente.",
"convert-to-attachment-confirm": "Doriți convertirea notițelor selectate în atașamente ale notiței părinte?", "convert-to-attachment-confirm": "Doriți convertirea notițelor selectate în atașamente ale notiței părinte? Această operațiune se aplică doar notițelor de tip imagine, celelalte vor fi ignorate.",
"open-in-popup": "Editare rapidă", "open-in-popup": "Editare rapidă",
"archive": "Arhivează", "archive": "Arhivează",
"unarchive": "Dezarhivează" "unarchive": "Dezarhivează"
@@ -1524,7 +1534,9 @@
"printing_pdf": "Exportare ca PDF în curs..." "printing_pdf": "Exportare ca PDF în curs..."
}, },
"note_title": { "note_title": {
"placeholder": "introduceți titlul notiței aici..." "placeholder": "introduceți titlul notiței aici...",
"created_on": "Creată la <Value />",
"last_modified": "Modificată la <Value />"
}, },
"revisions_snapshot_limit": { "revisions_snapshot_limit": {
"erase_excess_revision_snapshots": "Șterge acum reviziile excesive", "erase_excess_revision_snapshots": "Șterge acum reviziile excesive",
@@ -1626,10 +1638,6 @@
"move-to-visible-launchers": "Mută în Lansatoare vizibile", "move-to-visible-launchers": "Mută în Lansatoare vizibile",
"reset": "Resetează" "reset": "Resetează"
}, },
"editable-text": {
"auto-detect-language": "Automat",
"keeps-crashing": "Componenta de editare se blochează în continuu. Încercați să reporniți Trilium. Dacă problema persistă, luați în considerare să raportați această problemă."
},
"highlighting": { "highlighting": {
"color-scheme": "Temă de culori", "color-scheme": "Temă de culori",
"description": "Controlează evidențierea de sintaxă pentru blocurile de cod în interiorul notițelor text, notițele de tip cod nu vor fi afectate de aceste setări.", "description": "Controlează evidențierea de sintaxă pentru blocurile de cod în interiorul notițelor text, notițele de tip cod nu vor fi afectate de aceste setări.",
@@ -1760,7 +1768,8 @@
}, },
"note_language": { "note_language": {
"configure-languages": "Configurează limbile...", "configure-languages": "Configurează limbile...",
"not_set": "Nedefinită" "not_set": "Nicio limbă setată",
"help-on-languages": "Informații despre limba conținutului..."
}, },
"png_export_button": { "png_export_button": {
"button_title": "Exportă diagrama ca PNG" "button_title": "Exportă diagrama ca PNG"
@@ -1956,7 +1965,8 @@
"oauth_user_not_logged_in": "Neautentificat!" "oauth_user_not_logged_in": "Neautentificat!"
}, },
"svg": { "svg": {
"export_to_png": "Diagrama nu a putut fi exportată în PNG." "export_to_png": "Diagrama nu a putut fi exportată în PNG.",
"export_to_svg": "Diagrama nu a putut fi exportată în SVG."
}, },
"code_theme": { "code_theme": {
"title": "Afișare", "title": "Afișare",
@@ -2108,5 +2118,30 @@
}, },
"popup-editor": { "popup-editor": {
"maximize": "Comută la editorul principal" "maximize": "Comută la editorul principal"
},
"experimental_features": {
"title": "Opțiuni experimentale",
"disclaimer": "Aceste opțiuni sunt experimentale și pot cauza instabilitate. Folosiți cu prudență.",
"new_layout_name": "Aspect nou",
"new_layout_description": "Încercați noul aspect pentru un design mai modern și mai ușor de utilizat. Poate surveni modificări semnificative în următoarele release-uri."
},
"server": {
"unknown_http_error_title": "Eroare de comunicare cu server-ul",
"unknown_http_error_content": "Cod: {{statusCode}}\nURL: {{method}} {{url}}\nMesaj: {{message}}",
"traefik_blocks_requests": "Dacă utilizați reverse proxy-ul Traefik, acesta a introdus o schimbare majoră ce afectează comunicarea cu server-ul."
},
"tab_history_navigation_buttons": {
"go-back": "Înapoi la notița anterioară",
"go-forward": "Înainte către notița următoare"
},
"breadcrumb_badges": {
"read_only_explicit": "Mod citire",
"read_only_explicit_description": "Această notiță a fost setată explicit să fie doar în citire.\nClick pentru a o edita temporar.",
"read_only_auto": "Mod citire auto",
"read_only_auto_description": "Această notița a fost setată automată să fie în mod doar de citire din motive de performanță. Această limită automată este ajustabilă din setări.\n\nClick pentru a o edita temporar.",
"read_only_temporarily_disabled": "Editabilă temporar",
"read_only_temporarily_disabled_description": "Această notiță se poate modifica, deși în mod normal ea este doar în citire. Notița va reveni la modul doar în citire imediat ce navigați către altă notiță.\n\nClick pentru a re-activa modul doar în citire.",
"shared_publicly": "Partajată public",
"shared_locally": "Partajată local"
} }
} }

View File

@@ -39,7 +39,10 @@
"edit_branch_prefix": "Редактировать префикс ветки", "edit_branch_prefix": "Редактировать префикс ветки",
"prefix": "Префикс: ", "prefix": "Префикс: ",
"branch_prefix_saved": "Префикс ветки сохранен.", "branch_prefix_saved": "Префикс ветки сохранен.",
"help_on_tree_prefix": "Помощь по префиксу дерева" "help_on_tree_prefix": "Помощь по префиксу дерева",
"affected_branches": "Затронутые ветки ({{count}}):",
"branch_prefix_saved_multiple": "Префикс сохранен для {{count}} ветвей.",
"edit_branch_prefix_multiple": "Изменить префикс для {{count}} ветвей"
}, },
"bulk_actions": { "bulk_actions": {
"available_actions": "Доступные действия", "available_actions": "Доступные действия",
@@ -236,7 +239,8 @@
"export_status": "Статус экспорта", "export_status": "Статус экспорта",
"export_in_progress": "Экспорт: {{progressCount}}", "export_in_progress": "Экспорт: {{progressCount}}",
"export_finished_successfully": "Экспорт завершился успешно.", "export_finished_successfully": "Экспорт завершился успешно.",
"format_pdf": "PDF - для печати или обмена." "format_pdf": "PDF - для печати или обмена.",
"share-format": "HTML для веб-публикаций — использует ту же тему оформления, что и общие заметки, но может быть опубликован как статический веб-сайт."
}, },
"help": { "help": {
"noteNavigation": "Навигация по заметке", "noteNavigation": "Навигация по заметке",
@@ -290,7 +294,8 @@
"blockQuote": "начните строку с <code>></code>, а затем пробела для блока цитаты", "blockQuote": "начните строку с <code>></code>, а затем пробела для блока цитаты",
"quickSearch": "сфокусироваться на поле ввода быстрого поиска", "quickSearch": "сфокусироваться на поле ввода быстрого поиска",
"editNoteTitle": "в области дерева переключится с области дерева на заголовок заметки. Сочетание клавиш Enter из области заголовка заметки переключит фокус на текстовый редактор. <kbd>Ctrl+.</kbd> переключит обратно с редактора на область дерева.", "editNoteTitle": "в области дерева переключится с области дерева на заголовок заметки. Сочетание клавиш Enter из области заголовка заметки переключит фокус на текстовый редактор. <kbd>Ctrl+.</kbd> переключит обратно с редактора на область дерева.",
"title": "Справка" "title": "Справка",
"editShortcuts": "Редактировать сочетания клавиш"
}, },
"modal": { "modal": {
"close": "Закрыть", "close": "Закрыть",
@@ -472,11 +477,11 @@
"app_css": "отмечает заметки CSS, которые загружаются в приложение Trilium и, таким образом, могут использоваться для изменения внешнего вида Trilium.", "app_css": "отмечает заметки CSS, которые загружаются в приложение Trilium и, таким образом, могут использоваться для изменения внешнего вида Trilium.",
"app_theme_base": "установите значение \"next\", \"next-light\" или \"next-dark\", чтобы использовать соответствующую тему TriliumNext (автоматическую, светлую или темную) в качестве основы для пользовательской темы вместо устаревшей.", "app_theme_base": "установите значение \"next\", \"next-light\" или \"next-dark\", чтобы использовать соответствующую тему TriliumNext (автоматическую, светлую или темную) в качестве основы для пользовательской темы вместо устаревшей.",
"exclude_from_note_map": "Заметки с этой меткой будут скрыты на карте заметок", "exclude_from_note_map": "Заметки с этой меткой будут скрыты на карте заметок",
"workspace": "отмечает эту заметку как рабочее пространство, для удобного закрепления", "workspace": "отмечает эту заметку как рабочее пространство, для удобной установки фокуса",
"workspace_icon_class": "определяет CSS-класс значка поля, который будет использоваться во вкладке при закреплении этой заметки", "workspace_icon_class": "определяет CSS-класс значка поля, который будет использоваться во вкладке при установке фокуса на этой заметке",
"workspace_tab_background_color": "Цвет CSS, используемый во вкладке заметки при ее закреплении", "workspace_tab_background_color": "Цвет CSS, используемый во вкладке заметки при установке на нее фокуса",
"workspace_template": "Эта заметка появится в списке доступных шаблонов при создании новой заметки, но только если она будет перемещена в рабочую область, содержащую этот шаблон", "workspace_template": "Эта заметка появится в списке доступных шаблонов при создании новой заметки, но только если будет установлен фокус на рабочую область с этим шаблоном",
"workspace_search_home": "новые заметки поиска будут созданы как дочерние записи этой заметки при перемещении их к какому-либо предку этой заметки рабочей области", "workspace_search_home": "новые заметки поиска будут созданы как дочерние записи этой заметки, когда установлен фокус на какую-либо родительскую заметку этого рабочего пространство",
"workspace_calendar_root": "Определяет корень календаря для каждого рабочего пространства", "workspace_calendar_root": "Определяет корень календаря для каждого рабочего пространства",
"hide_highlight_widget": "Скрыть виджет «Выделенное»", "hide_highlight_widget": "Скрыть виджет «Выделенное»",
"is_owned_by_note": "принадлежит заметке", "is_owned_by_note": "принадлежит заметке",
@@ -503,7 +508,7 @@
"custom_resource_provider": "см. <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Пользовательский обработчик запросов</a>", "custom_resource_provider": "см. <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Пользовательский обработчик запросов</a>",
"widget": "отмечает эту заметку как пользовательский виджет, который будет добавлен в дерево компонентов Trilium", "widget": "отмечает эту заметку как пользовательский виджет, который будет добавлен в дерево компонентов Trilium",
"search_home": "новые заметки поиска будут созданы как дочерние записи этой заметки", "search_home": "новые заметки поиска будут созданы как дочерние записи этой заметки",
"workspace_inbox": "расположение в папке «Входящие» по умолчанию для новых заметок при перемещении их в некую родственную папку этой заметки в рабочей области", "workspace_inbox": "расположение в папке «Входящие» по умолчанию для новых заметок, когда установлен фокус на какую-либо родительскую заметку этого рабочего пространство",
"sql_console_home": "расположение заметок консоли SQL по умолчанию", "sql_console_home": "расположение заметок консоли SQL по умолчанию",
"css_class": "значение этой метки затем добавляется как CSS-класс к узлу, представляющему данную заметку в дереве. Это может быть полезно для изменения внешнего вида заметки. Может использоваться в шаблонах заметок.", "css_class": "значение этой метки затем добавляется как CSS-класс к узлу, представляющему данную заметку в дереве. Это может быть полезно для изменения внешнего вида заметки. Может использоваться в шаблонах заметок.",
"bookmark_folder": "заметка с этой меткой появится в закладках как папка (с предоставлением доступа к ее дочерним элементам)", "bookmark_folder": "заметка с этой меткой появится в закладках как папка (с предоставлением доступа к ее дочерним элементам)",
@@ -519,7 +524,7 @@
"share_index": "заметка с этой меткой будет содержать список всех корневых узлов общедоступных заметок", "share_index": "заметка с этой меткой будет содержать список всех корневых узлов общедоступных заметок",
"toc": "<code>#toc</code> или <code>#toc=show</code> принудительно отобразят оглавление, <code>#toc=hide</code> — скроют его. Если метка отсутствует, применяется глобальная настройка", "toc": "<code>#toc</code> или <code>#toc=show</code> принудительно отобразят оглавление, <code>#toc=hide</code> — скроют его. Если метка отсутствует, применяется глобальная настройка",
"color": "определяет цвет заметки в дереве заметок, ссылках и т. д. Используйте любое допустимое значение цвета CSS, например «red» или #a13d5f", "color": "определяет цвет заметки в дереве заметок, ссылках и т. д. Используйте любое допустимое значение цвета CSS, например «red» или #a13d5f",
"keep_current_hoisting": "Открытие этой ссылки не изменит закрепление, даже если заметка не отображается в текущем закрепленном поддереве.", "keep_current_hoisting": "Открытие этой ссылки не изменит фокус, даже если заметка не отображается в текущем закрепленном поддереве.",
"execute_description": "Более подробное описание текущей заметки типа \"Код\", отображаемое вместе с кнопкой \"Выполнить\"", "execute_description": "Более подробное описание текущей заметки типа \"Код\", отображаемое вместе с кнопкой \"Выполнить\"",
"run_on_note_creation": "выполняется при создании заметки на сервере. Используйте это отношение, если хотите запустить скрипт для всех заметок, созданных в определённом поддереве. В этом случае создайте его в корневой заметке поддерева и сделайте его наследуемым. Новая заметка, созданная в поддереве (любой глубины), запустит скрипт.", "run_on_note_creation": "выполняется при создании заметки на сервере. Используйте это отношение, если хотите запустить скрипт для всех заметок, созданных в определённом поддереве. В этом случае создайте его в корневой заметке поддерева и сделайте его наследуемым. Новая заметка, созданная в поддереве (любой глубины), запустит скрипт.",
"run_on_child_note_creation": "выполняется, когда создается новая заметка под заметкой, в которой определено это отношение", "run_on_child_note_creation": "выполняется, когда создается новая заметка под заметкой, в которой определено это отношение",
@@ -567,7 +572,8 @@
"edit-column-title": "Нажмите, чтобы изменить заголовок столбца", "edit-column-title": "Нажмите, чтобы изменить заголовок столбца",
"edit-note-title": "Нажмите, чтобы изменить название заметки", "edit-note-title": "Нажмите, чтобы изменить название заметки",
"add-column-placeholder": "Введите имя столбца...", "add-column-placeholder": "Введите имя столбца...",
"new-item-placeholder": "Введите название заметки..." "new-item-placeholder": "Введите название заметки...",
"column-already-exists": "Такая колонка уже добавлена на доску."
}, },
"table_context_menu": { "table_context_menu": {
"delete_row": "Удалить строку" "delete_row": "Удалить строку"
@@ -576,7 +582,7 @@
"vector_dark": "Vector (Темная)", "vector_dark": "Vector (Темная)",
"vector_light": "Vector (Светлая)", "vector_light": "Vector (Светлая)",
"max-nesting-depth": "Максимальная глубина вложенности:", "max-nesting-depth": "Максимальная глубина вложенности:",
"map-style": "Стиль карты:", "map-style": "Стиль карты",
"display-week-numbers": "Отображать номера недель", "display-week-numbers": "Отображать номера недель",
"hide-weekends": "Скрыть выходные", "hide-weekends": "Скрыть выходные",
"raster": "Растр", "raster": "Растр",
@@ -606,7 +612,8 @@
"title": "Внешний вид" "title": "Внешний вид"
}, },
"svg": { "svg": {
"export_to_png": "Диаграмму не может быть экспортирована в PNG." "export_to_png": "Диаграмму не может быть экспортирована в PNG.",
"export_to_svg": "Не удалось экспортировать диаграмму в SVG."
}, },
"png_export_button": { "png_export_button": {
"button_title": "Экспортировать диаграмму как PNG" "button_title": "Экспортировать диаграмму как PNG"
@@ -621,7 +628,8 @@
}, },
"note_language": { "note_language": {
"configure-languages": "Настроить языки...", "configure-languages": "Настроить языки...",
"not_set": "Не установлен" "not_set": "Язык не установлен",
"help-on-languages": "Помощь по языкам содержимого..."
}, },
"time_selector": { "time_selector": {
"invalid_input": "Введенное значение времени не является допустимым числом.", "invalid_input": "Введенное значение времени не является допустимым числом.",
@@ -679,7 +687,8 @@
"open_note_in_popup": "Быстрое редактирование", "open_note_in_popup": "Быстрое редактирование",
"open_note_in_new_window": "Открыть заметку в новом окне", "open_note_in_new_window": "Открыть заметку в новом окне",
"open_note_in_new_tab": "Открыть заметку в новой вкладке", "open_note_in_new_tab": "Открыть заметку в новой вкладке",
"open_note_in_new_split": "Открыть заметку в новой панели" "open_note_in_new_split": "Открыть заметку в новой панели",
"open_note_in_other_split": "Открыть заметку в другой панели"
}, },
"image_context_menu": { "image_context_menu": {
"copy_image_to_clipboard": "Копировать изображение в буфер обмена", "copy_image_to_clipboard": "Копировать изображение в буфер обмена",
@@ -692,7 +701,8 @@
"copy": "Скопировать", "copy": "Скопировать",
"cut": "Вырезать", "cut": "Вырезать",
"search_online": "Поиск \"{{term}}\" в {{searchEngine}}", "search_online": "Поиск \"{{term}}\" в {{searchEngine}}",
"add-term-to-dictionary": "Добавить \"{{term}}\" в словарь" "add-term-to-dictionary": "Добавить \"{{term}}\" в словарь",
"search_in_trilium": "Искать \"{{term}}\" в Trilium"
}, },
"editing": { "editing": {
"editor_type": { "editor_type": {
@@ -726,9 +736,6 @@
"title": "Блоки кода", "title": "Блоки кода",
"description": "Управляет подсветкой синтаксиса для блоков кода внутри текстовых заметок. Заметки с типом \"Код\" не будут затронуты." "description": "Управляет подсветкой синтаксиса для блоков кода внутри текстовых заметок. Заметки с типом \"Код\" не будут затронуты."
}, },
"editable-text": {
"auto-detect-language": "Определен автоматически"
},
"launcher_context_menu": { "launcher_context_menu": {
"reset": "Сбросить", "reset": "Сбросить",
"add-spacer": "Добавить разделитель", "add-spacer": "Добавить разделитель",
@@ -749,17 +756,18 @@
"hide-archived-notes": "Скрыть архивные заметки", "hide-archived-notes": "Скрыть архивные заметки",
"automatically-collapse-notes": "Автоматически сворачивать заметки", "automatically-collapse-notes": "Автоматически сворачивать заметки",
"tree-settings-title": "Настройки дерева", "tree-settings-title": "Настройки дерева",
"unhoist": "Открепить", "unhoist": "Убрать фокус",
"scroll-active-title": "Прокрутить к активной заметке", "scroll-active-title": "Прокрутить к активной заметке",
"collapse-title": "Свернуть дерево", "collapse-title": "Свернуть дерево",
"hoist-this-note-workspace": "Закрепить заметку (рабочая область)", "hoist-this-note-workspace": "Фокус на заметке (рабочая область)",
"auto-collapsing-notes-after-inactivity": "Автоматическое сворачивание заметок после бездействия...", "auto-collapsing-notes-after-inactivity": "Автоматическое сворачивание заметок после бездействия...",
"create-child-note": "Создать дочернюю заметку", "create-child-note": "Создать дочернюю заметку",
"save-changes": "Сохранить и применить изменения", "save-changes": "Сохранить и применить изменения",
"saved-search-note-refreshed": "Сохраненная поисковая заметка обновлена.", "saved-search-note-refreshed": "Сохраненная поисковая заметка обновлена.",
"refresh-saved-search-results": "Обновить сохраненные результаты поиска", "refresh-saved-search-results": "Обновить сохраненные результаты поиска",
"automatically-collapse-notes-title": "Заметки будут свернуты после определенного периода бездействия, чтобы навести порядок в дереве.", "automatically-collapse-notes-title": "Заметки будут свернуты после определенного периода бездействия, чтобы навести порядок в дереве.",
"toggle-sidebar": "Переключить боковую панель" "toggle-sidebar": "Переключить боковую панель",
"dropping-not-allowed": "Перетаскивание заметок в эту область не разрешено."
}, },
"quick-search": { "quick-search": {
"no-results": "Результаты не найдены", "no-results": "Результаты не найдены",
@@ -796,7 +804,7 @@
"text": "Текст", "text": "Текст",
"launcher": "Лаунчер", "launcher": "Лаунчер",
"doc": "Документация", "doc": "Документация",
"relation-map": "Карта отношений", "relation-map": "Карта связей",
"note-map": "Карта заметок", "note-map": "Карта заметок",
"render-note": "Рендеринг заметки", "render-note": "Рендеринг заметки",
"web-view": "Веб-страница", "web-view": "Веб-страница",
@@ -815,8 +823,8 @@
"export": "Экспорт", "export": "Экспорт",
"open-in-a-new-tab": "Открыть в новой вкладке", "open-in-a-new-tab": "Открыть в новой вкладке",
"open-in-a-new-split": "Открыть в новой панели", "open-in-a-new-split": "Открыть в новой панели",
"unhoist-note": "Открепить заметку", "unhoist-note": "Снять фокус",
"hoist-note": "Закрепить заметку", "hoist-note": "Фокус на заметке",
"protect-subtree": "Защитить поддерево", "protect-subtree": "Защитить поддерево",
"unprotect-subtree": "Снять защиту с поддерева", "unprotect-subtree": "Снять защиту с поддерева",
"copy-clone": "Скопировать / Склонировать", "copy-clone": "Скопировать / Склонировать",
@@ -836,7 +844,7 @@
"apply-bulk-actions": "Применить массовые действия", "apply-bulk-actions": "Применить массовые действия",
"recent-changes-in-subtree": "Последние изменения в поддереве", "recent-changes-in-subtree": "Последние изменения в поддереве",
"copy-note-path-to-clipboard": "Копировать путь к заметке в буфер обмена", "copy-note-path-to-clipboard": "Копировать путь к заметке в буфер обмена",
"convert-to-attachment-confirm": "Вы уверены, что хотите преобразовать выбранные заметки во вложения их родительских заметок?", "convert-to-attachment-confirm": "Вы уверены, что хотите преобразовать выбранные заметки во вложения их родительских заметок? Эта операция применяется только к заметкам в виде изображений; другие заметки будут пропущены.",
"converted-to-attachments": "{{count}} заметок были преобразованы во вложения.", "converted-to-attachments": "{{count}} заметок были преобразованы во вложения.",
"archive": "Архивировать", "archive": "Архивировать",
"unarchive": "Разархивировать" "unarchive": "Разархивировать"
@@ -844,7 +852,8 @@
"info": { "info": {
"closeButton": "Закрыть", "closeButton": "Закрыть",
"okButton": "ОК", "okButton": "ОК",
"modalTitle": "Информация" "modalTitle": "Информация",
"copy_to_clipboard": "Скопировать в буфер обмена"
}, },
"jump_to_note": { "jump_to_note": {
"search_placeholder": "Найдите заметку по ее названию или введите > для команд...", "search_placeholder": "Найдите заметку по ее названию или введите > для команд...",
@@ -981,13 +990,14 @@
"show_shared_notes_subtree": "Поддерево общедоступных заметок", "show_shared_notes_subtree": "Поддерево общедоступных заметок",
"switch_to_mobile_version": "Перейти на мобильную версию", "switch_to_mobile_version": "Перейти на мобильную версию",
"switch_to_desktop_version": "Переключиться на версию для ПК", "switch_to_desktop_version": "Переключиться на версию для ПК",
"new-version-available": "Доступно обновление" "new-version-available": "Доступно обновление",
"download-update": "Обновить до {{latestVersion}}"
}, },
"zpetne_odkazy": { "zpetne_odkazy": {
"relation": "отношение", "relation": "отношение",
"backlink_one": "{{count}} ссылки", "backlink_one": "{{count}} обратная ссылка",
"backlink_few": "", "backlink_few": "{{count}} обратные ссылки",
"backlink_many": "{{count}} ссылок" "backlink_many": "{{count}} обратных ссылок"
}, },
"note_icon": { "note_icon": {
"category": "Категория:", "category": "Категория:",
@@ -1015,7 +1025,12 @@
"geo-map": "Карта", "geo-map": "Карта",
"invalid_view_type": "Недопустимый тип представления '{{type}}'", "invalid_view_type": "Недопустимый тип представления '{{type}}'",
"collapse_all_notes": "Свернуть все заметки", "collapse_all_notes": "Свернуть все заметки",
"include_archived_notes": "Показать заархивированные заметки" "include_archived_notes": "Показать заархивированные заметки",
"presentation": "Презентация",
"expand_all_levels": "Развернуть все вложенные уровни",
"expand_nth_level": "Развернуть уровни: {{depth}} шт.",
"expand_first_level": "Развернуть прямые дочерние уровни",
"expand_tooltip": "Разщвернуть дочерние элементы этой коллекции (на один уровень вложенности). Для получения дополнительных параметров нажмите стрелку справа."
}, },
"edited_notes": { "edited_notes": {
"deleted": "(удалено)", "deleted": "(удалено)",
@@ -1055,7 +1070,9 @@
"title": "Информация", "title": "Информация",
"calculate": "подсчитать", "calculate": "подсчитать",
"note_size_info": "Размер заметки позволяет приблизительно оценить требования к объёму хранилища для данной заметки. Он учитывает её содержание и содержание её сохраненных версий.", "note_size_info": "Размер заметки позволяет приблизительно оценить требования к объёму хранилища для данной заметки. Он учитывает её содержание и содержание её сохраненных версий.",
"subtree_size": "(размер поддерева: {{size}} в {{count}} заметках)" "subtree_size": "(размер поддерева: {{size}} в {{count}} заметках)",
"mime": "MIME тип",
"show_similar_notes": "Похожие заметки"
}, },
"note_paths": { "note_paths": {
"search": "Поиск", "search": "Поиск",
@@ -1063,7 +1080,7 @@
"clone_button": "Клонировать заметку в новое место...", "clone_button": "Клонировать заметку в новое место...",
"intro_placed": "Эта заметка размещена по следующим путям:", "intro_placed": "Эта заметка размещена по следующим путям:",
"intro_not_placed": "Эта заметка еще не помещена в дерево заметок.", "intro_not_placed": "Эта заметка еще не помещена в дерево заметок.",
"outside_hoisted": "Этот путь находится за пределами закрепленной заметки, и вам придется снять закрепление.", "outside_hoisted": "Этот путь находится за пределами сфокусированной заметки, и вам придется снять фокус.",
"archived": "Архивировано" "archived": "Архивировано"
}, },
"note_properties": { "note_properties": {
@@ -1108,7 +1125,8 @@
"save_to_note": "Сохранить в заметку", "save_to_note": "Сохранить в заметку",
"search_note_saved": "Заметка с настройкой поиска сохранена в {{- notePathTitle}}", "search_note_saved": "Заметка с настройкой поиска сохранена в {{- notePathTitle}}",
"unknown_search_option": "Неизвестный параметр поиска {{searchOptionName}}", "unknown_search_option": "Неизвестный параметр поиска {{searchOptionName}}",
"actions_executed": "Действия выполнены." "actions_executed": "Действия выполнены.",
"view_options": "Просмотреть опции:"
}, },
"ancestor": { "ancestor": {
"depth_label": "глубина", "depth_label": "глубина",
@@ -1204,7 +1222,8 @@
"max_width_unit": "пикселей", "max_width_unit": "пикселей",
"title": "Ширина контентной области", "title": "Ширина контентной области",
"default_description": "Trilium по умолчанию ограничивает максимальную ширину контента, чтобы улучшить читаемость на широких экранах.", "default_description": "Trilium по умолчанию ограничивает максимальную ширину контента, чтобы улучшить читаемость на широких экранах.",
"max_width_label": "Максимальная ширина контентной области" "max_width_label": "Максимальная ширина контентной области",
"centerContent": "Размещать контент по центру"
}, },
"native_title_bar": { "native_title_bar": {
"enabled": "включено", "enabled": "включено",
@@ -1412,7 +1431,13 @@
"min-days-in-first-week": "Минимальное количество дней в первой неделе", "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-info": "Первая неделя содержит первый четверг года в соответствии со стандартом <a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a>.",
"first-week-warning": "Изменение параметров первой недели может привести к дублированию существующих недельных заметок, и существующие недельные заметки не будут обновлены соответствующим образом.", "first-week-warning": "Изменение параметров первой недели может привести к дублированию существующих недельных заметок, и существующие недельные заметки не будут обновлены соответствующим образом.",
"formatting-locale": "Формат даты и числа" "formatting-locale": "Формат даты и числа",
"formatting-locale-auto": "Выбирать на основе языка приложения",
"saturday": "Суббота",
"friday": "Пятница",
"thursday": "Четверг",
"wednesday": "Среда",
"tuesday": "Вторник"
}, },
"backup": { "backup": {
"path": "Путь", "path": "Путь",
@@ -1612,7 +1637,14 @@
"convert_into_attachment_failed": "Не удалось преобразовать заметку '{{title}}'.", "convert_into_attachment_failed": "Не удалось преобразовать заметку '{{title}}'.",
"open_note_externally_title": "Файл будет открыт во внешнем приложении и отслеживается на наличие изменений. После этого вы сможете загрузить изменённую версию обратно в Trilium.", "open_note_externally_title": "Файл будет открыт во внешнем приложении и отслеживается на наличие изменений. После этого вы сможете загрузить изменённую версию обратно в Trilium.",
"open_note_externally": "Открыть заметку вне приложения", "open_note_externally": "Открыть заметку вне приложения",
"open_note_custom": "Открыть заметку как..." "open_note_custom": "Открыть заметку как...",
"export_as_image_svg": "SVG (вектор)",
"export_as_image_png": "PNG (растр)",
"export_as_image": "Экспорт изображения",
"open_note_on_server": "Открыть заметку на сервере",
"view_revisions": "История изменений...",
"note_map": "Карта заметок",
"advanced": "Дополнительно"
}, },
"revisions_button": { "revisions_button": {
"note_revisions": "Версии заметки" "note_revisions": "Версии заметки"
@@ -1637,7 +1669,7 @@
"zoom_in_title": "Увеличить масштаб", "zoom_in_title": "Увеличить масштаб",
"zoom_out_title": "Уменьшить масштаб", "zoom_out_title": "Уменьшить масштаб",
"reset_pan_zoom_title": "Сбросить панорамирование и масштабирование", "reset_pan_zoom_title": "Сбросить панорамирование и масштабирование",
"create_child_note_title": "Создать новую дочернюю заметку и добавить ее в эту карту отношений" "create_child_note_title": "Создать новую дочернюю заметку и добавить ее в эту карту связей"
}, },
"code_auto_read_only_size": { "code_auto_read_only_size": {
"unit": "символов", "unit": "символов",
@@ -1692,7 +1724,7 @@
"remove_relation": "Удалить отношение", "remove_relation": "Удалить отношение",
"default_new_note_title": "новая заметка", "default_new_note_title": "новая заметка",
"open_in_new_tab": "Открыть в новой вкладке", "open_in_new_tab": "Открыть в новой вкладке",
"confirm_remove_relation": "Вы уверены, что хотите удалить отношение?", "confirm_remove_relation": "Вы уверены, что хотите удалить связь?",
"enter_new_title": "Введите новое название заметки:", "enter_new_title": "Введите новое название заметки:",
"note_not_found": "Заметка {{noteId}} не найдена!", "note_not_found": "Заметка {{noteId}} не найдена!",
"cannot_match_transform": "Невозможно сопоставить преобразование: {{transform}}", "cannot_match_transform": "Невозможно сопоставить преобразование: {{transform}}",
@@ -1700,7 +1732,7 @@
"click_on_canvas_to_place_new_note": "Щелкните по холсту, чтобы разместить новую заметку", "click_on_canvas_to_place_new_note": "Щелкните по холсту, чтобы разместить новую заметку",
"note_already_in_diagram": "Заметка \"{{title}}\" уже есть на диаграмме.", "note_already_in_diagram": "Заметка \"{{title}}\" уже есть на диаграмме.",
"connection_exists": "Связь '{{name}}' между этими заметками уже существует.", "connection_exists": "Связь '{{name}}' между этими заметками уже существует.",
"specify_new_relation_name": "Укажите новое имя отношения (допустимые символы: буквы, цифры, двоеточие и подчеркивание):", "specify_new_relation_name": "Укажите новое имя связи (допустимые символы: буквы, цифры, двоеточие и подчеркивание):",
"start_dragging_relations": "Начните перетягивать отношения отсюда на другую заметку." "start_dragging_relations": "Начните перетягивать отношения отсюда на другую заметку."
}, },
"vacuum_database": { "vacuum_database": {
@@ -1788,7 +1820,8 @@
"error_unrecognized_command": "Нераспознанная команда {{command}}", "error_unrecognized_command": "Нераспознанная команда {{command}}",
"error_cannot_get_branch_id": "Невозможно получить branchId для notePath '{{notePath}}'", "error_cannot_get_branch_id": "Невозможно получить branchId для notePath '{{notePath}}'",
"delete_this_note": "Удалить эту заметку", "delete_this_note": "Удалить эту заметку",
"insert_child_note": "Вставить дочернюю заметку" "insert_child_note": "Вставить дочернюю заметку",
"note_revisions": "История изменений"
}, },
"svg_export_button": { "svg_export_button": {
"button_title": "Экспортировать диаграмму как SVG" "button_title": "Экспортировать диаграмму как SVG"
@@ -1845,7 +1878,10 @@
"next_theme_button": "Попробовать новую тему", "next_theme_button": "Попробовать новую тему",
"background_effects_message": "На устройствах Windows фоновые эффекты теперь полностью стабильны. Они добавляют цвет в пользовательский интерфейс, размывая фон за ним. Этот приём также используется в других приложениях, например, в проводнике Windows.", "background_effects_message": "На устройствах Windows фоновые эффекты теперь полностью стабильны. Они добавляют цвет в пользовательский интерфейс, размывая фон за ним. Этот приём также используется в других приложениях, например, в проводнике Windows.",
"background_effects_title": "Фоновые эффекты теперь стабильны", "background_effects_title": "Фоновые эффекты теперь стабильны",
"next_theme_title": "Попробуйте новую тему Trilium" "next_theme_title": "Попробуйте новую тему Trilium",
"new_layout_button": "Подробнее",
"new_layout_message": "Мы обновили интерфейс Trilium. Старая лента инструментов была удалена и органично интегрирована в основной интерфейс, а ключевые функции теперь выполняет новая строка состояния и разворачиваемые разделы.\n\nНовый интерфейс включен по умолчанию и может быть временно отключен через «Параметры» → «Внешний вид».",
"new_layout_title": "Новый дизайн"
}, },
"zoom_factor": { "zoom_factor": {
"description": "Масштабированием также можно управлять с помощью сочетаний клавиш CTRL+- и CTRL+=.", "description": "Масштабированием также можно управлять с помощью сочетаний клавиш CTRL+- и CTRL+=.",
@@ -1855,7 +1891,10 @@
"show_toc": "Показать оглавление" "show_toc": "Показать оглавление"
}, },
"code_mime_types": { "code_mime_types": {
"title": "Доступные типы в выпадающем списке" "title": "Доступные типы в выпадающем списке",
"tooltip_syntax_highlighting": "Подсветка синтаксиса",
"tooltip_code_note_syntax": "Заметки с кодом",
"tooltip_code_block_syntax": "Блоки кода в текстовых заметках"
}, },
"search_result": { "search_result": {
"no_notes_found": "По заданным параметрам поиска заметки не найдены.", "no_notes_found": "По заданным параметрам поиска заметки не найдены.",
@@ -1978,7 +2017,14 @@
"deletion_reason": ", поскольку вложение не связано с содержимым заметки. Чтобы предотвратить удаление, добавьте ссылку на вложение обратно в содержимое или преобразуйте вложение в заметку." "deletion_reason": ", поскольку вложение не связано с содержимым заметки. Чтобы предотвратить удаление, добавьте ссылку на вложение обратно в содержимое или преобразуйте вложение в заметку."
}, },
"note_title": { "note_title": {
"placeholder": "введите здесь название заметки..." "placeholder": "введите здесь название заметки...",
"edited_notes": "Измененные заметки",
"note_type_switcher_collection": "Коллекция",
"note_type_switcher_templates": "Шаблон",
"note_type_switcher_others": "Другой тип заметки",
"note_type_switcher_label": "Переключить с {{type}} на:",
"last_modified": "Изменена <Value />",
"created_on": "Создана в <Value />"
}, },
"units": { "units": {
"percentage": "%" "percentage": "%"
@@ -2017,7 +2063,10 @@
}, },
"settings_appearance": { "settings_appearance": {
"related_code_blocks": "Цветовая схема для блоков кода в текстовых заметках", "related_code_blocks": "Цветовая схема для блоков кода в текстовых заметках",
"related_code_notes": "Цветовая схема для заметок типа \"Код\"" "related_code_notes": "Цветовая схема для заметок типа \"Код\"",
"ui_new_layout": "Новый дизайн",
"ui_old_layout": "Старый дизайн",
"ui": "Пользовательский интерфейс"
}, },
"sql_result": { "sql_result": {
"no_rows": "По этому запросу не возвращено ни одной строки" "no_rows": "По этому запросу не возвращено ни одной строки"
@@ -2026,17 +2075,26 @@
"placeholder": "Введите содержимое для заметки с кодом..." "placeholder": "Введите содержимое для заметки с кодом..."
}, },
"editable_text": { "editable_text": {
"placeholder": "Введите содержимое для заметки..." "placeholder": "Введите содержимое для заметки...",
"auto-detect-language": "Определен автоматически",
"keeps-crashing": "Компонент редактирования вылетает. Пожалуйста, попробуйте перезапустить Trilium. Если проблема сохраняется, пожалуйста, создайте отчет об ошибке.",
"editor_crashed_details_title": "Техническая информация",
"editor_crashed_details_intro": "Если эта ошибка возникает несколько раз, пожалуйста, сообщите о ней на GitHub, сопроводив информаций ниже.",
"editor_crashed_content": "Ваши данные были успешно восстановлены, но некоторые из последних изменений могли не быть сохранены.",
"editor_crashed_details_button": "Подробнее...",
"editor_crashed_title": "Возникла ошибка в текстовом редакторе"
}, },
"hoisted_note": { "hoisted_note": {
"confirm_unhoisting": "Запрошенная заметка «{{requestedNote}}» находится за пределами поддерева закрепленной заметки \"{{hoistedNote}}\", и для доступа к ней необходимо снять закрепление. Открепить заметку?" "confirm_unhoisting": "Запрошенная заметка «{{requestedNote}}» находится за пределами поддерева закрепленной заметки \"{{hoistedNote}}\", и для доступа к ней необходимо снять фокус. Снять фокус с заметки?"
}, },
"frontend_script_api": { "frontend_script_api": {
"sync_warning": "Вы передаете синхронную функцию в `api.runAsyncOnBackendWithManualTransactionHandling()`, \\nхотя вместо этого вам, скорее всего, следует использовать `api.runOnBackend()`.", "sync_warning": "Вы передаете синхронную функцию в `api.runAsyncOnBackendWithManualTransactionHandling()`, \\nхотя вместо этого вам, скорее всего, следует использовать `api.runOnBackend()`.",
"async_warning": "Вы передаете асинхронную функцию в `api.runOnBackend()`, которая, скорее всего, не будет работать так, как вы предполагали.\\nЛибо сделайте функцию синхронной (удалив ключевое слово `async`), либо используйте `api.runAsyncOnBackendWithManualTransactionHandling()`." "async_warning": "Вы передаете асинхронную функцию в `api.runOnBackend()`, которая, скорее всего, не будет работать так, как вы предполагали.\\nЛибо сделайте функцию синхронной (удалив ключевое слово `async`), либо используйте `api.runAsyncOnBackendWithManualTransactionHandling()`."
}, },
"note_detail": { "note_detail": {
"could_not_find_typewidget": "Не удалось найти typeWidget для типа '{{type}}'" "could_not_find_typewidget": "Не удалось найти typeWidget для типа '{{type}}'",
"printing_pdf": "Выполняется экспорт PDF...",
"printing": "Выполняется печать..."
}, },
"book": { "book": {
"no_children_help": "В этой коллекции нет дочерних заметок, поэтому отображать нечего. Подробности см. в <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a>.", "no_children_help": "В этой коллекции нет дочерних заметок, поэтому отображать нечего. Подробности см. в <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a>.",
@@ -2057,5 +2115,93 @@
"pagination": { "pagination": {
"total_notes": "{{count}} заметок", "total_notes": "{{count}} заметок",
"page_title": "Страница {{startIndex}} - {{endIndex}}" "page_title": "Страница {{startIndex}} - {{endIndex}}"
},
"status_bar": {
"attributes_one": "{{count}} атрибут",
"attributes_few": "{{count}} атрибута",
"attributes_many": "{{count}} атрибутов",
"note_info_title": "Просмотр информации о заметке, (даты, размер)",
"language_title": "Изменить язык содержимого",
"code_note_switcher": "Изменить режим языка",
"note_paths_title": "Расположения заметки",
"note_paths_one": "{{count}} место",
"note_paths_few": "{{count}} места",
"note_paths_many": "{{count}} мест",
"attributes_title": "Собственные и унаследованные атрибуты",
"attachments_title_one": "Открыть вложение в новой вкладке",
"attachments_title_few": "Открыть вложения в новой вкладке",
"attachments_title_many": "Открыть вложения в новой вкладке",
"attachments_one": "{{count}} вложение",
"attachments_few": "{{count}} вложения",
"attachments_many": "{{count}} вложений",
"backlinks_one": "{{count}} обратная ссылка",
"backlinks_few": "{{count}} обратные ссылки",
"backlinks_many": "{{count}} обратных ссылок",
"backlinks_title_one": "Обратная ссылка",
"backlinks_title_few": "Обратные ссылки",
"backlinks_title_many": "Обратные ссылки"
},
"breadcrumb_badges": {
"execute_sql_description": "Эта заметка - SQL-запрос. Нажмите, чтобы выполнить его.",
"execute_sql": "Выполнить SQL",
"execute_script_description": "Это заметка содержит скрипт. Нажмите, чтобы выполнить его.",
"execute_script": "Выполнить скрипт",
"clipped_note_description": "Эта заметка первоначально взята с сайта {{url}}.\n\nНажмите, чтобы перейти на исходную веб-страницу.",
"shared_publicly": "Доступно публично",
"shared_locally": "Доступно локально",
"clipped_note": "Web фрагмент",
"shared_unshare": "Убрать публичный доступ",
"shared_open_in_browser": "Открыть ссылку в браузере",
"shared_copy_to_clipboard": "Скопировать ссылку",
"read_only_temporarily_disabled_description": "В данный момент эта заметка доступна для редактирования, но обычно она находится только в режиме чтения. Заметка снова станет доступна только для чтения, как только вы перейдете к другой заметке.\n\nНажмите, чтобы снова включить режим только для чтения.",
"read_only_temporarily_disabled": "Временное редактирование",
"read_only_auto_description": "Эта заметка была автоматически переведена в режим только для чтения по соображениям производительности. Это автоматическое ограничение можно изменить в настройках.\n\nНажмите, чтобы временно отредактировать её.",
"read_only_auto": "Автоматический режим \"только для чтения\"",
"read_only_explicit_description": "Эта заметка была вручную установлена в режим «только для чтения».\nНажмите, чтобы временно отредактировать её.",
"read_only_explicit": "Только для чтения"
},
"breadcrumb": {
"hoisted_badge_title": "Снять фокус",
"hoisted_badge": "Фокус",
"empty_hide_archived_notes": "Скрыть заметки в архиве",
"create_new_note": "Новая дочерняя заметка",
"scroll_to_top_title": "К началу заметки",
"workspace_badge": "Рабочее пространство"
},
"tab_history_navigation_buttons": {
"go-forward": "Перейти к следующей заметке",
"go-back": "Перейти к предыдущей заметке"
},
"server": {
"traefik_blocks_requests": "Если вы используете обратный прокси-сервер Traefik, то следует учитывать, что в него внесены критические изменения, влияющие на связь с сервером.",
"unknown_http_error_content": "Код: {{statusCode}}\nURL: {{method}} {{url}}\nСообщение: {{message}}",
"unknown_http_error_title": "Ошибка связи с сервером"
},
"note-color": {
"set-color": "Установить цвет заметки",
"clear-color": "Убрать цвет заметки",
"set-custom-color": "Установить другой цвет"
},
"calendar_view": {
"delete_note": "Удалить заметку..."
},
"presentation_view": {
"start-presentation": "Начать презентацию",
"edit-slide": "Редактировать слайд",
"slide-overview": "Переключить общий просмотр слайдов"
},
"read-only-info": {
"edit-note": "Изменить заметку",
"auto-read-only-note": "Заметка отображена в режиме \"только для чтения\" для быстрой загрузки.",
"read-only-note": "Заметка отображается в режиме \"только для чтения\"."
},
"experimental_features": {
"new_layout_description": "Попробуйте новый современный и удобный дизайн. В будущих обновлениях возможны его существенные изменения.",
"new_layout_name": "Новый дизайн",
"title": "Экспериментальные параметры",
"disclaimer": "Эти параметры экспериментальные и могут повлиять на стабильность. Используйте с осторожностью."
},
"popup-editor": {
"maximize": "Переключить на полный редактор"
} }
} }

View File

@@ -205,7 +205,8 @@
"info": { "info": {
"modalTitle": "資訊消息", "modalTitle": "資訊消息",
"closeButton": "關閉", "closeButton": "關閉",
"okButton": "確定" "okButton": "確定",
"copy_to_clipboard": "複製到剪貼簿"
}, },
"jump_to_note": { "jump_to_note": {
"search_button": "全文搜尋", "search_button": "全文搜尋",
@@ -734,7 +735,8 @@
}, },
"zpetne_odkazy": { "zpetne_odkazy": {
"relation": "關聯", "relation": "關聯",
"backlink_one": "{{count}} 個反連結" "backlink_one": "{{count}} 個反連結",
"backlink_other": "{{count}} 個反連結"
}, },
"mobile_detail_menu": { "mobile_detail_menu": {
"insert_child_note": "插入子筆記", "insert_child_note": "插入子筆記",
@@ -983,7 +985,14 @@
"placeholder": "在這裡輸入您的程式碼筆記內容…" "placeholder": "在這裡輸入您的程式碼筆記內容…"
}, },
"editable_text": { "editable_text": {
"placeholder": "在這裡輸入您的筆記內容…" "placeholder": "在這裡輸入您的筆記內容…",
"auto-detect-language": "自動檢測",
"keeps-crashing": "編輯元件持續發生崩潰。請嘗試重新啟動 Trilium。若問題仍存在請考慮提交錯誤報告。",
"editor_crashed_title": "文字編輯器崩潰",
"editor_crashed_content": "您的內容已成功恢復,但最近的幾項變更可能未被儲存。",
"editor_crashed_details_button": "檢視更多資訊⋯",
"editor_crashed_details_intro": "若您多次遇到此錯誤,請考慮在 GitHub 回報以下資訊。",
"editor_crashed_details_title": "技術資訊"
}, },
"empty": { "empty": {
"open_note_instruction": "透過在下面的輸入框中輸入筆記標題或在樹中選擇筆記來打開筆記。", "open_note_instruction": "透過在下面的輸入框中輸入筆記標題或在樹中選擇筆記來打開筆記。",
@@ -1428,7 +1437,7 @@
"import-into-note": "匯入至筆記", "import-into-note": "匯入至筆記",
"apply-bulk-actions": "套用批次操作", "apply-bulk-actions": "套用批次操作",
"converted-to-attachments": "{{count}} 個筆記已被轉換為附件。", "converted-to-attachments": "{{count}} 個筆記已被轉換為附件。",
"convert-to-attachment-confirm": "確定要將所選的筆記轉換為其父級筆記的附件嗎?", "convert-to-attachment-confirm": "確定要將所選的筆記轉換為其父級筆記的附件嗎?此操作僅適用於圖像筆記,其他筆記將被跳過。",
"duplicate": "複製副本", "duplicate": "複製副本",
"open-in-popup": "快速編輯", "open-in-popup": "快速編輯",
"archive": "封存", "archive": "封存",
@@ -1528,7 +1537,9 @@
"printing_pdf": "正在匯出為 PDF…" "printing_pdf": "正在匯出為 PDF…"
}, },
"note_title": { "note_title": {
"placeholder": "請輸入筆記標題..." "placeholder": "請輸入筆記標題...",
"created_on": "建立於 {{date}}",
"last_modified": "最後修改於 {{date}}"
}, },
"search_result": { "search_result": {
"no_notes_found": "沒有找到符合搜尋條件的筆記。", "no_notes_found": "沒有找到符合搜尋條件的筆記。",
@@ -1619,10 +1630,6 @@
"move-to-available-launchers": "移動至可用啟動器", "move-to-available-launchers": "移動至可用啟動器",
"duplicate-launcher": "複製啟動器 <kbd data-command=\"duplicateSubtree\">" "duplicate-launcher": "複製啟動器 <kbd data-command=\"duplicateSubtree\">"
}, },
"editable-text": {
"auto-detect-language": "自動檢測",
"keeps-crashing": "編輯元件持續發生崩潰。請嘗試重新啟動 Trilium。若問題仍存在請考慮提交錯誤報告。"
},
"highlighting": { "highlighting": {
"description": "控制文字筆記程式碼區塊中的語法高亮,程式碼筆記不會受到影響。", "description": "控制文字筆記程式碼區塊中的語法高亮,程式碼筆記不會受到影響。",
"color-scheme": "配色方案", "color-scheme": "配色方案",
@@ -1673,7 +1680,8 @@
"open_note_in_new_tab": "在新分頁中打開筆記", "open_note_in_new_tab": "在新分頁中打開筆記",
"open_note_in_new_split": "在新頁面分割中打開筆記", "open_note_in_new_split": "在新頁面分割中打開筆記",
"open_note_in_new_window": "在新視窗中打開筆記", "open_note_in_new_window": "在新視窗中打開筆記",
"open_note_in_popup": "快速編輯" "open_note_in_popup": "快速編輯",
"open_note_in_other_split": "在另一個頁面分割中打開筆記"
}, },
"zen_mode": { "zen_mode": {
"button_exit": "退出禪模式" "button_exit": "退出禪模式"
@@ -1953,7 +1961,8 @@
"button_title": "將圖表匯出為 PNG" "button_title": "將圖表匯出為 PNG"
}, },
"svg": { "svg": {
"export_to_png": "無法將圖表匯出為 PNG。" "export_to_png": "無法將圖表匯出為 PNG。",
"export_to_svg": "此绘图无法导出为SVG格式。"
}, },
"code_theme": { "code_theme": {
"title": "外觀", "title": "外觀",
@@ -2105,5 +2114,26 @@
}, },
"popup-editor": { "popup-editor": {
"maximize": "切換至完整編輯器" "maximize": "切換至完整編輯器"
},
"experimental_features": {
"title": "實驗性選項",
"disclaimer": "這些選項屬實驗性質,可能導致系統不穩定。請謹慎使用。",
"new_layout_name": "新版面配置",
"new_layout_description": "體驗全新版面配置,呈現更現代的外觀與更佳的使用體驗。在未來版本將進行大幅調整。"
},
"server": {
"unknown_http_error_title": "與伺服器通訊錯誤",
"unknown_http_error_content": "狀態碼:{{statusCode}}\n網址{{method}} {{url}}\n訊息{{message}}",
"traefik_blocks_requests": "若您正在使用 Traefik 反向代理,該代理已引入一項重大變更影響與伺服器的通訊。"
},
"tab_history_navigation_buttons": {
"go-back": "返回前一筆記",
"go-forward": "前往下一筆記"
},
"breadcrumb_badges": {
"read_only_explicit": "唯讀",
"read_only_auto": "自動唯讀",
"shared_publicly": "公開分享",
"shared_locally": "本地分享"
} }
} }

View File

@@ -130,9 +130,6 @@
"move-to-available-launchers": "Перейти до доступних лаунчерів", "move-to-available-launchers": "Перейти до доступних лаунчерів",
"duplicate-launcher": "Дублікат програми запуску <kbd data-command=\"duplicateSubtree\">" "duplicate-launcher": "Дублікат програми запуску <kbd data-command=\"duplicateSubtree\">"
}, },
"editable-text": {
"auto-detect-language": "Автовизначено"
},
"highlighting": { "highlighting": {
"color-scheme": "Схема кольорів", "color-scheme": "Схема кольорів",
"title": "Блоки коду", "title": "Блоки коду",
@@ -1076,7 +1073,8 @@
"placeholder": "Введіть тут вміст вашої нотатки з кодом..." "placeholder": "Введіть тут вміст вашої нотатки з кодом..."
}, },
"editable_text": { "editable_text": {
"placeholder": "Введіть тут вміст вашої нотатки..." "placeholder": "Введіть тут вміст вашої нотатки...",
"auto-detect-language": "Автовизначено"
}, },
"empty": { "empty": {
"open_note_instruction": "Відкрийте нотатку, ввівши її заголовок в поле нижче, або виберіть нотатку в дереві.", "open_note_instruction": "Відкрийте нотатку, ввівши її заголовок в поле нижче, або виберіть нотатку в дереві.",

View File

@@ -1,25 +1,27 @@
import { BacklinkCountResponse, BacklinksResponse, SaveSqlConsoleResponse } from "@triliumnext/commons";
import { VNode } from "preact"; import { VNode } from "preact";
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
import appContext, { EventData, EventNames } from "../components/app_context"; import appContext, { EventData, EventNames } from "../components/app_context";
import Component from "../components/component"; import Component from "../components/component";
import NoteContext from "../components/note_context"; import NoteContext from "../components/note_context";
import FNote from "../entities/fnote"; import FNote from "../entities/fnote";
import ActionButton, { ActionButtonProps } from "./react/ActionButton"; import attributes from "../services/attributes";
import { useIsNoteReadOnly, useNoteLabelBoolean, useTriliumEvent, useTriliumOption, useWindowSize } from "./react/hooks"; import { isExperimentalFeatureEnabled } from "../services/experimental_features";
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks"; import froca from "../services/froca";
import { createImageSrcUrl, openInAppHelpFromUrl } from "../services/utils";
import server from "../services/server";
import { BacklinkCountResponse, BacklinksResponse, SaveSqlConsoleResponse } from "@triliumnext/commons";
import toast from "../services/toast";
import { t } from "../services/i18n"; import { t } from "../services/i18n";
import { copyImageReferenceToClipboard } from "../services/image"; import { copyImageReferenceToClipboard } from "../services/image";
import tree from "../services/tree";
import { getHelpUrlForNote } from "../services/in_app_help"; import { getHelpUrlForNote } from "../services/in_app_help";
import froca from "../services/froca"; import LoadResults from "../services/load_results";
import server from "../services/server";
import toast from "../services/toast";
import tree from "../services/tree";
import { createImageSrcUrl, openInAppHelpFromUrl } from "../services/utils";
import { ViewTypeOptions } from "./collections/interface";
import ActionButton, { ActionButtonProps } from "./react/ActionButton";
import { useIsNoteReadOnly, useNoteLabelBoolean, useTriliumEvent, useTriliumOption, useWindowSize } from "./react/hooks";
import NoteLink from "./react/NoteLink"; import NoteLink from "./react/NoteLink";
import RawHtml from "./react/RawHtml"; import RawHtml from "./react/RawHtml";
import { ViewTypeOptions } from "./collections/interface";
import attributes from "../services/attributes";
import LoadResults from "../services/load_results";
export interface FloatingButtonContext { export interface FloatingButtonContext {
parentComponent: Component; parentComponent: Component;
@@ -37,7 +39,7 @@ function FloatingButton({ className, ...props }: ActionButtonProps) {
className={`floating-button ${className ?? ""}`} className={`floating-button ${className ?? ""}`}
noIconActionClass noIconActionClass
{...props} {...props}
/> />;
} }
export type FloatingButtonsList = ((context: FloatingButtonContext) => false | VNode)[]; export type FloatingButtonsList = ((context: FloatingButtonContext) => false | VNode)[];
@@ -82,7 +84,7 @@ function RefreshBackendLogButton({ note, parentComponent, noteContext, isDefault
text={t("backend_log.refresh")} text={t("backend_log.refresh")}
icon="bx bx-refresh" icon="bx bx-refresh"
onClick={() => parentComponent.triggerEvent("refreshData", { ntxId: noteContext.ntxId })} onClick={() => parentComponent.triggerEvent("refreshData", { ntxId: noteContext.ntxId })}
/> />;
} }
function SwitchSplitOrientationButton({ note, isReadOnly, isDefaultViewMode }: FloatingButtonContext) { function SwitchSplitOrientationButton({ note, isReadOnly, isDefaultViewMode }: FloatingButtonContext) {
@@ -94,7 +96,7 @@ function SwitchSplitOrientationButton({ note, isReadOnly, isDefaultViewMode }: F
text={upcomingOrientation === "vertical" ? t("switch_layout_button.title_vertical") : t("switch_layout_button.title_horizontal")} text={upcomingOrientation === "vertical" ? t("switch_layout_button.title_vertical") : t("switch_layout_button.title_horizontal")}
icon={upcomingOrientation === "vertical" ? "bx bxs-dock-bottom" : "bx bxs-dock-left"} icon={upcomingOrientation === "vertical" ? "bx bxs-dock-bottom" : "bx bxs-dock-left"}
onClick={() => setSplitEditorOrientation(upcomingOrientation)} onClick={() => setSplitEditorOrientation(upcomingOrientation)}
/> />;
} }
function ToggleReadOnlyButton({ note, viewType, isDefaultViewMode }: FloatingButtonContext) { function ToggleReadOnlyButton({ note, viewType, isDefaultViewMode }: FloatingButtonContext) {
@@ -106,7 +108,7 @@ function ToggleReadOnlyButton({ note, viewType, isDefaultViewMode }: FloatingBut
text={isReadOnly ? t("toggle_read_only_button.unlock-editing") : t("toggle_read_only_button.lock-editing")} text={isReadOnly ? t("toggle_read_only_button.unlock-editing") : t("toggle_read_only_button.lock-editing")}
icon={isReadOnly ? "bx bx-lock-open-alt" : "bx bx-lock-alt"} icon={isReadOnly ? "bx bx-lock-open-alt" : "bx bx-lock-alt"}
onClick={() => setReadOnly(!isReadOnly)} onClick={() => setReadOnly(!isReadOnly)}
/> />;
} }
function EditButton({ note, noteContext }: FloatingButtonContext) { function EditButton({ note, noteContext }: FloatingButtonContext) {
@@ -129,7 +131,7 @@ function EditButton({ note, noteContext }: FloatingButtonContext) {
icon="bx bx-pencil" icon="bx bx-pencil"
className={animationClass} className={animationClass}
onClick={() => enableEditing()} onClick={() => enableEditing()}
/> />;
} }
function ShowTocWidgetButton({ note, noteContext, isDefaultViewMode }: FloatingButtonContext) { function ShowTocWidgetButton({ note, noteContext, isDefaultViewMode }: FloatingButtonContext) {
@@ -147,7 +149,7 @@ function ShowTocWidgetButton({ note, noteContext, isDefaultViewMode }: FloatingB
appContext.triggerEvent("showTocWidget", { noteId: noteContext.noteId }); appContext.triggerEvent("showTocWidget", { noteId: noteContext.noteId });
} }
}} }}
/> />;
} }
function ShowHighlightsListWidgetButton({ note, noteContext, isDefaultViewMode }: FloatingButtonContext) { function ShowHighlightsListWidgetButton({ note, noteContext, isDefaultViewMode }: FloatingButtonContext) {
@@ -165,16 +167,16 @@ function ShowHighlightsListWidgetButton({ note, noteContext, isDefaultViewMode }
appContext.triggerEvent("showHighlightsListWidget", { noteId: noteContext.noteId }); appContext.triggerEvent("showHighlightsListWidget", { noteId: noteContext.noteId });
} }
}} }}
/> />;
} }
function RunActiveNoteButton({ note }: FloatingButtonContext) { function RunActiveNoteButton({ note }: FloatingButtonContext) {
const isEnabled = note.mime.startsWith("application/javascript") || note.mime === "text/x-sqlite;schema=trilium"; const isEnabled = (note.mime.startsWith("application/javascript") || note.mime === "text/x-sqlite;schema=trilium");
return isEnabled && <FloatingButton return isEnabled && <FloatingButton
icon="bx bx-play" icon="bx bx-play"
text={t("code_buttons.execute_button_title")} text={t("code_buttons.execute_button_title")}
triggerCommand="runActiveNote" triggerCommand="runActiveNote"
/> />;
} }
function OpenTriliumApiDocsButton({ note }: FloatingButtonContext) { function OpenTriliumApiDocsButton({ note }: FloatingButtonContext) {
@@ -183,7 +185,7 @@ function OpenTriliumApiDocsButton({ note }: FloatingButtonContext) {
icon="bx bx-help-circle" icon="bx bx-help-circle"
text={t("code_buttons.trilium_api_docs_button_title")} text={t("code_buttons.trilium_api_docs_button_title")}
onClick={() => openInAppHelpFromUrl(note.mime.endsWith("frontend") ? "Q2z6av6JZVWm" : "MEtfsqa5VwNi")} onClick={() => openInAppHelpFromUrl(note.mime.endsWith("frontend") ? "Q2z6av6JZVWm" : "MEtfsqa5VwNi")}
/> />;
} }
function SaveToNoteButton({ note }: FloatingButtonContext) { function SaveToNoteButton({ note }: FloatingButtonContext) {
@@ -191,7 +193,12 @@ function SaveToNoteButton({ note }: FloatingButtonContext) {
return isEnabled && <FloatingButton return isEnabled && <FloatingButton
icon="bx bx-save" icon="bx bx-save"
text={t("code_buttons.save_to_note_button_title")} text={t("code_buttons.save_to_note_button_title")}
onClick={async (e) => { onClick={buildSaveSqlToNoteHandler(note)}
/>;
}
export function buildSaveSqlToNoteHandler(note: FNote) {
return async (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
const { notePath } = await server.post<SaveSqlConsoleResponse>("special-notes/save-sql-console", { sqlConsoleNoteId: note.noteId }); const { notePath } = await server.post<SaveSqlConsoleResponse>("special-notes/save-sql-console", { sqlConsoleNoteId: note.noteId });
if (notePath) { if (notePath) {
@@ -200,8 +207,7 @@ function SaveToNoteButton({ note }: FloatingButtonContext) {
//await ws.waitForMaxKnownEntityChangeId(); //await ws.waitForMaxKnownEntityChangeId();
await appContext.tabManager.getActiveContext()?.setNote(notePath); await appContext.tabManager.getActiveContext()?.setNote(notePath);
} }
}} };
/>
} }
function RelationMapButtons({ note, isDefaultViewMode, triggerEvent }: FloatingButtonContext) { function RelationMapButtons({ note, isDefaultViewMode, triggerEvent }: FloatingButtonContext) {
@@ -234,7 +240,7 @@ function RelationMapButtons({ note, isDefaultViewMode, triggerEvent }: FloatingB
/> />
</div> </div>
</> </>
) );
} }
function GeoMapButtons({ triggerEvent, viewType, isReadOnly }: FloatingButtonContext) { function GeoMapButtons({ triggerEvent, viewType, isReadOnly }: FloatingButtonContext) {
@@ -250,8 +256,10 @@ function GeoMapButtons({ triggerEvent, viewType, isReadOnly }: FloatingButtonCon
function CopyImageReferenceButton({ note, isDefaultViewMode }: FloatingButtonContext) { function CopyImageReferenceButton({ note, isDefaultViewMode }: FloatingButtonContext) {
const hiddenImageCopyRef = useRef<HTMLDivElement>(null); const hiddenImageCopyRef = useRef<HTMLDivElement>(null);
const isEnabled = ["mermaid", "canvas", "mindMap", "image"].includes(note?.type ?? "") const isEnabled = (
&& note?.isContentAvailable() && isDefaultViewMode; ["mermaid", "canvas", "mindMap", "image"].includes(note?.type ?? "")
&& note?.isContentAvailable() && isDefaultViewMode
);
return isEnabled && ( return isEnabled && (
<> <>
@@ -272,7 +280,7 @@ function CopyImageReferenceButton({ note, isDefaultViewMode }: FloatingButtonCon
position: "absolute" // Take out of the the hidden image from flexbox to prevent the layout being affected position: "absolute" // Take out of the the hidden image from flexbox to prevent the layout being affected
}} /> }} />
</> </>
) );
} }
function ExportImageButtons({ note, triggerEvent, isDefaultViewMode }: FloatingButtonContext) { function ExportImageButtons({ note, triggerEvent, isDefaultViewMode }: FloatingButtonContext) {
@@ -292,38 +300,26 @@ function ExportImageButtons({ note, triggerEvent, isDefaultViewMode }: FloatingB
onClick={() => triggerEvent("exportPng")} onClick={() => triggerEvent("exportPng")}
/> />
</> </>
) );
} }
function InAppHelpButton({ note }: FloatingButtonContext) { function InAppHelpButton({ note }: FloatingButtonContext) {
const helpUrl = getHelpUrlForNote(note); const helpUrl = getHelpUrlForNote(note);
const isEnabled = !!helpUrl;
return !!helpUrl && ( return isEnabled && (
<FloatingButton <FloatingButton
icon="bx bx-help-circle" icon="bx bx-help-circle"
text={t("help-button.title")} text={t("help-button.title")}
onClick={() => helpUrl && openInAppHelpFromUrl(helpUrl)} onClick={() => helpUrl && openInAppHelpFromUrl(helpUrl)}
/> />
) );
} }
function Backlinks({ note, isDefaultViewMode }: FloatingButtonContext) { function Backlinks({ note, isDefaultViewMode }: FloatingButtonContext) {
let [ backlinkCount, setBacklinkCount ] = useState(0); const [ popupOpen, setPopupOpen ] = useState(false);
let [ popupOpen, setPopupOpen ] = useState(false);
const backlinksContainerRef = useRef<HTMLDivElement>(null); const backlinksContainerRef = useRef<HTMLDivElement>(null);
const backlinkCount = useBacklinkCount(note, isDefaultViewMode);
function refresh() {
if (!isDefaultViewMode) return;
server.get<BacklinkCountResponse>(`note-map/${note.noteId}/backlink-count`).then(resp => {
setBacklinkCount(resp.count);
});
}
useEffect(() => refresh(), [ note ]);
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
if (needsRefresh(note, loadResults)) refresh();
});
// Determine the max height of the container. // Determine the max height of the container.
const { windowHeight } = useWindowSize(); const { windowHeight } = useWindowSize();
@@ -355,7 +351,26 @@ function Backlinks({ note, isDefaultViewMode }: FloatingButtonContext) {
); );
} }
function BacklinksList({ note }: { note: FNote }) { export function useBacklinkCount(note: FNote | null | undefined, isDefaultViewMode: boolean) {
const [ backlinkCount, setBacklinkCount ] = useState(0);
const refresh = useCallback(() => {
if (!note || !isDefaultViewMode) return;
server.get<BacklinkCountResponse>(`note-map/${note.noteId}/backlink-count`).then(resp => {
setBacklinkCount(resp.count);
});
}, [ isDefaultViewMode, note ]);
useEffect(() => refresh(), [ refresh ]);
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
if (note && needsRefresh(note, loadResults)) refresh();
});
return backlinkCount;
}
export function BacklinksList({ note }: { note: FNote }) {
const [ backlinks, setBacklinks ] = useState<BacklinksResponse>([]); const [ backlinks, setBacklinks ] = useState<BacklinksResponse>([]);
function refresh() { function refresh() {
@@ -375,7 +390,7 @@ function BacklinksList({ note }: { note: FNote }) {
}); });
return backlinks.map(backlink => ( return backlinks.map(backlink => (
<div> <li>
<NoteLink <NoteLink
notePath={backlink.noteId} notePath={backlink.noteId}
showNotePath showNoteIcon showNotePath showNoteIcon
@@ -389,7 +404,7 @@ function BacklinksList({ note }: { note: FNote }) {
<RawHtml html={excerpt} /> <RawHtml html={excerpt} />
)) ))
)} )}
</div> </li>
)); ));
} }

View File

@@ -1,16 +1,18 @@
import { useNoteContext, useTriliumEvent } from "./react/hooks"
import FNote from "../entities/fnote";
import protected_session_holder from "../services/protected_session_holder";
import { useEffect, useRef, useState } from "preact/hooks";
import NoteContext from "../components/note_context";
import { isValidElement, VNode } from "preact";
import { TypeWidgetProps } from "./type_widgets/type_widget";
import "./NoteDetail.css"; import "./NoteDetail.css";
import { isValidElement, VNode } from "preact";
import { useEffect, useRef, useState } from "preact/hooks";
import NoteContext from "../components/note_context";
import FNote from "../entities/fnote";
import attributes from "../services/attributes"; import attributes from "../services/attributes";
import { ExtendedNoteType, TYPE_MAPPINGS, TypeWidget } from "./note_types";
import { dynamicRequire, isElectron, isMobile } from "../services/utils";
import toast from "../services/toast.js";
import { t } from "../services/i18n"; import { t } from "../services/i18n";
import protected_session_holder from "../services/protected_session_holder";
import toast from "../services/toast.js";
import { dynamicRequire, isElectron, isMobile } from "../services/utils";
import { ExtendedNoteType, TYPE_MAPPINGS, TypeWidget } from "./note_types";
import { useNoteContext, useTriliumEvent } from "./react/hooks";
import { TypeWidgetProps } from "./type_widgets/type_widget";
/** /**
* The note detail is in charge of rendering the content of a note, by determining its type (e.g. text, code) and using the appropriate view widget. * The note detail is in charge of rendering the content of a note, by determining its type (e.g. text, code) and using the appropriate view widget.
@@ -80,7 +82,7 @@ export default function NoteDetail() {
parentComponent.handleEvent("noteTypeMimeChanged", { noteId: note.noteId }); parentComponent.handleEvent("noteTypeMimeChanged", { noteId: note.noteId });
} else if (note.noteId } else if (note.noteId
&& loadResults.isNoteReloaded(note.noteId, parentComponent.componentId) && loadResults.isNoteReloaded(note.noteId, parentComponent.componentId)
&& (type !== (await getWidgetType(note, noteContext)) || mime !== note?.mime)) { && (type !== (await getExtendedWidgetType(note, noteContext)) || mime !== note?.mime)) {
// this needs to have a triggerEvent so that e.g., note type (not in the component subtree) is updated // this needs to have a triggerEvent so that e.g., note type (not in the component subtree) is updated
parentComponent.triggerEvent("noteTypeMimeChanged", { noteId: note.noteId }); parentComponent.triggerEvent("noteTypeMimeChanged", { noteId: note.noteId });
} else { } else {
@@ -212,7 +214,7 @@ export default function NoteDetail() {
isVisible={type === itemType} isVisible={type === itemType}
isFullHeight={isFullHeight} isFullHeight={isFullHeight}
props={props} props={props}
/> />;
})} })}
</div> </div>
); );
@@ -254,7 +256,7 @@ function useNoteInfo() {
const [ mime, setMime ] = useState<string>(); const [ mime, setMime ] = useState<string>();
function refresh() { function refresh() {
getWidgetType(actualNote, noteContext).then(type => { getExtendedWidgetType(actualNote, noteContext).then(type => {
setNote(actualNote); setNote(actualNote);
setType(type); setType(type);
setMime(actualNote?.mime); setMime(actualNote?.mime);
@@ -282,12 +284,12 @@ async function getCorrespondingWidget(type: ExtendedNoteType): Promise<null | Ty
} else if (isValidElement(result)) { } else if (isValidElement(result)) {
// Direct VNode provided. // Direct VNode provided.
return result; return result;
} else {
return result;
} }
return result;
} }
async function getWidgetType(note: FNote | null | undefined, noteContext: NoteContext | undefined): Promise<ExtendedNoteType | undefined> { export async function getExtendedWidgetType(note: FNote | null | undefined, noteContext: NoteContext | undefined): Promise<ExtendedNoteType | undefined> {
if (!noteContext) return undefined; if (!noteContext) return undefined;
if (!note) { if (!note) {
// If the note is null, then it's a new tab. If it's undefined, then it's not loaded yet. // If the note is null, then it's a new tab. If it's undefined, then it's not loaded yet.
@@ -299,8 +301,10 @@ async function getWidgetType(note: FNote | null | undefined, noteContext: NoteCo
if (noteContext?.viewScope?.viewMode === "source") { if (noteContext?.viewScope?.viewMode === "source") {
resultingType = "readOnlyCode"; resultingType = "readOnlyCode";
} else if (noteContext?.viewScope && noteContext.viewScope.viewMode === "attachments") { } else if (noteContext.viewScope?.viewMode === "attachments") {
resultingType = noteContext.viewScope.attachmentId ? "attachmentDetail" : "attachmentList"; resultingType = noteContext.viewScope.attachmentId ? "attachmentDetail" : "attachmentList";
} else if (noteContext.viewScope?.viewMode === "note-map") {
resultingType = "noteMap";
} else if (type === "text" && (await noteContext?.isReadOnly())) { } else if (type === "text" && (await noteContext?.isReadOnly())) {
resultingType = "readOnlyText"; resultingType = "readOnlyText";
} else if ((type === "code" || type === "mermaid") && (await noteContext?.isReadOnly())) { } else if ((type === "code" || type === "mermaid") && (await noteContext?.isReadOnly())) {
@@ -322,7 +326,7 @@ async function getWidgetType(note: FNote | null | undefined, noteContext: NoteCo
return resultingType; return resultingType;
} }
function checkFullHeight(noteContext: NoteContext | undefined, type: ExtendedNoteType | undefined) { export function checkFullHeight(noteContext: NoteContext | undefined, type: ExtendedNoteType | undefined) {
if (!noteContext) return false; if (!noteContext) return false;
// https://github.com/zadam/trilium/issues/2522 // https://github.com/zadam/trilium/issues/2522

View File

@@ -1,19 +1,21 @@
import { Dispatch, StateUpdater, useEffect, useRef, useState } from "preact/hooks";
import "./PromotedAttributes.css"; import "./PromotedAttributes.css";
import { useNoteContext, useNoteLabel, useTriliumEvent, useUniqueName } from "./react/hooks";
import { Attribute } from "../services/attribute_parser"; import { UpdateAttributeResponse } from "@triliumnext/commons";
import FAttribute from "../entities/fattribute";
import clsx from "clsx"; import clsx from "clsx";
import { ComponentChild, HTMLInputTypeAttribute, InputHTMLAttributes, MouseEventHandler, TargetedEvent, TargetedInputEvent } from "preact";
import { Dispatch, StateUpdater, useEffect, useRef, useState } from "preact/hooks";
import FAttribute from "../entities/fattribute";
import FNote from "../entities/fnote";
import { Attribute } from "../services/attribute_parser";
import attributes from "../services/attributes";
import debounce from "../services/debounce";
import { t } from "../services/i18n"; import { t } from "../services/i18n";
import { DefinitionObject, extractAttributeDefinitionTypeAndName, LabelType } from "../services/promoted_attribute_definition_parser"; import { DefinitionObject, extractAttributeDefinitionTypeAndName, LabelType } from "../services/promoted_attribute_definition_parser";
import server from "../services/server"; import server from "../services/server";
import FNote from "../entities/fnote";
import { ComponentChild, HTMLInputTypeAttribute, InputHTMLAttributes, MouseEventHandler, TargetedEvent, TargetedInputEvent } from "preact";
import NoteAutocomplete from "./react/NoteAutocomplete";
import ws from "../services/ws"; import ws from "../services/ws";
import { UpdateAttributeResponse } from "@triliumnext/commons"; import { useNoteContext, useNoteLabel, useTriliumEvent, useUniqueName } from "./react/hooks";
import attributes from "../services/attributes"; import NoteAutocomplete from "./react/NoteAutocomplete";
import debounce from "../services/debounce";
interface Cell { interface Cell {
uniqueId: string; uniqueId: string;
@@ -39,6 +41,15 @@ type OnChangeListener = (e: OnChangeEventData) => Promise<void>;
export default function PromotedAttributes() { export default function PromotedAttributes() {
const { note, componentId } = useNoteContext(); const { note, componentId } = useNoteContext();
const [ cells, setCells ] = usePromotedAttributeData(note, componentId); const [ cells, setCells ] = usePromotedAttributeData(note, componentId);
return <PromotedAttributesContent note={note} componentId={componentId} cells={cells} setCells={setCells} />;
}
export function PromotedAttributesContent({ note, componentId, cells, setCells }: {
note: FNote | null | undefined;
componentId: string;
cells: Cell[] | undefined;
setCells: Dispatch<StateUpdater<Cell[] | undefined>>;
}) {
const [ cellToFocus, setCellToFocus ] = useState<Cell>(); const [ cellToFocus, setCellToFocus ] = useState<Cell>();
return ( return (
@@ -62,7 +73,7 @@ export default function PromotedAttributes() {
* *
* The cells are returned as a state since they can also be altered internally if needed, for example to add a new empty cell. * The cells are returned as a state since they can also be altered internally if needed, for example to add a new empty cell.
*/ */
function usePromotedAttributeData(note: FNote | null | undefined, componentId: string): [ Cell[] | undefined, Dispatch<StateUpdater<Cell[] | undefined>> ] { export function usePromotedAttributeData(note: FNote | null | undefined, componentId: string): [ Cell[] | undefined, Dispatch<StateUpdater<Cell[] | undefined>> ] {
const [ viewType ] = useNoteLabel(note, "viewType"); const [ viewType ] = useNoteLabel(note, "viewType");
const [ cells, setCells ] = useState<Cell[]>(); const [ cells, setCells ] = useState<Cell[]>();
@@ -156,7 +167,7 @@ function PromotedAttributeCell(props: CellProps) {
{correspondingInput} {correspondingInput}
<MultiplicityCell {...props} /> <MultiplicityCell {...props} />
</div> </div>
) );
} }
const LABEL_MAPPINGS: Record<LabelType, HTMLInputTypeAttribute> = { const LABEL_MAPPINGS: Record<LabelType, HTMLInputTypeAttribute> = {
@@ -219,8 +230,8 @@ function LabelInput({ inputId, ...props }: CellProps & { inputId: string }) {
<label className="tn-checkbox">{inputNode}</label> <label className="tn-checkbox">{inputNode}</label>
</div> </div>
<label for={inputId}>{definition.promotedAlias ?? valueName}</label> <label for={inputId}>{definition.promotedAlias ?? valueName}</label>
</> </>;
} else { }
return ( return (
<div className="input-group"> <div className="input-group">
{inputNode} {inputNode}
@@ -241,7 +252,7 @@ function LabelInput({ inputId, ...props }: CellProps & { inputId: string }) {
)} )}
</div> </div>
); );
}
} }
@@ -282,7 +293,7 @@ function ColorPicker({ cell, onChange, inputId }: CellProps & {
}} }}
/> />
</> </>
) );
} }
function RelationInput({ inputId, ...props }: CellProps & { inputId: string }) { function RelationInput({ inputId, ...props }: CellProps & { inputId: string }) {
@@ -295,7 +306,7 @@ function RelationInput({ inputId, ...props }: CellProps & { inputId: string }) {
await updateAttribute(note, cell, componentId, value, setCells); await updateAttribute(note, cell, componentId, value, setCells);
}} }}
/> />
) );
} }
function MultiplicityCell({ cell, cells, setCells, setCellToFocus, note, componentId }: CellProps) { function MultiplicityCell({ cell, cells, setCells, setCellToFocus, note, componentId }: CellProps) {
@@ -346,13 +357,13 @@ function MultiplicityCell({ cell, cells, setCells, setCellToFocus, note, compone
name: cell.valueName, name: cell.valueName,
value: "" value: ""
} }
}) });
} }
setCells(cells.toSpliced(index, 1, ...newOnesToInsert)); setCells(cells.toSpliced(index, 1, ...newOnesToInsert));
}} }}
/> />
</td> </td>
) );
} }
function PromotedActionButton({ icon, title, onClick }: { function PromotedActionButton({ icon, title, onClick }: {
@@ -366,7 +377,7 @@ function PromotedActionButton({ icon, title, onClick }: {
title={title} title={title}
onClick={onClick} onClick={onClick}
/> />
) );
} }
function InputButton({ icon, className, title, onClick }: { function InputButton({ icon, className, title, onClick }: {
@@ -381,7 +392,7 @@ function InputButton({ icon, className, title, onClick }: {
title={title} title={title}
onClick={onClick} onClick={onClick}
/> />
) );
} }
function setupTextLabelAutocomplete(el: HTMLInputElement, valueAttr: Attribute, onChangeListener: OnChangeListener) { function setupTextLabelAutocomplete(el: HTMLInputElement, valueAttr: Attribute, onChangeListener: OnChangeListener) {
@@ -406,7 +417,7 @@ function setupTextLabelAutocomplete(el: HTMLInputElement, valueAttr: Attribute,
[ [
{ {
displayKey: "value", displayKey: "value",
source: function (term, cb) { source (term, cb) {
term = term.toLowerCase(); term = term.toLowerCase();
const filtered = attributeValues.filter((attr) => attr.value.toLowerCase().includes(term)); const filtered = attributeValues.filter((attr) => attr.value.toLowerCase().includes(term));

View File

@@ -16,4 +16,5 @@ body.zen div.read-only-note-info-bar-widget {
:root div.read-only-note-info-bar-widget button { :root div.read-only-note-info-bar-widget button {
white-space: nowrap; white-space: nowrap;
padding: 2px 8px; padding: 2px 8px;
flex-shrink: 0;
} }

View File

@@ -0,0 +1,7 @@
.component.tab-history-navigation-buttons {
contain: none;
flex-shrink: 0;
display: flex;
align-items: center;
margin-inline-end: 0.5em;
}

View File

@@ -0,0 +1,64 @@
import "./TabHistoryNavigationButtons.css";
import { useEffect, useMemo, useState } from "preact/hooks";
import { t } from "../services/i18n";
import { dynamicRequire, isElectron } from "../services/utils";
import { handleHistoryContextMenu } from "./launch_bar/HistoryNavigation";
import ActionButton from "./react/ActionButton";
import { useLauncherVisibility } from "./react/hooks";
export default function TabHistoryNavigationButtons() {
const webContents = useMemo(() => isElectron() ? dynamicRequire("@electron/remote").getCurrentWebContents() : undefined, []);
const onContextMenu = webContents ? handleHistoryContextMenu(webContents) : undefined;
const { canGoBack, canGoForward } = useBackForwardState(webContents);
const legacyBackVisible = useLauncherVisibility("_lbBackInHistory");
const legacyForwardVisible = useLauncherVisibility("_lbForwardInHistory");
return (isElectron() &&
<div className="tab-history-navigation-buttons">
{!legacyBackVisible && <ActionButton
icon="bx bx-left-arrow-alt"
text={t("tab_history_navigation_buttons.go-back")}
triggerCommand="backInNoteHistory"
onContextMenu={onContextMenu}
disabled={!canGoBack}
/>}
{!legacyForwardVisible && <ActionButton
icon="bx bx-right-arrow-alt"
text={t("tab_history_navigation_buttons.go-forward")}
triggerCommand="forwardInNoteHistory"
onContextMenu={onContextMenu}
disabled={!canGoForward}
/>}
</div>
);
}
function useBackForwardState(webContents: Electron.WebContents | undefined) {
const [ canGoBack, setCanGoBack ] = useState(webContents?.navigationHistory.canGoBack());
const [ canGoForward, setCanGoForward ] = useState(webContents?.navigationHistory.canGoForward());
useEffect(() => {
if (!webContents) return;
const updateNavigationState = () => {
setCanGoBack(webContents.navigationHistory.canGoBack());
setCanGoForward(webContents.navigationHistory.canGoForward());
};
webContents.on("did-navigate", updateNavigationState);
webContents.on("did-navigate-in-page", updateNavigationState);
return () => {
webContents.removeListener("did-navigate", updateNavigationState);
webContents.removeListener("did-navigate-in-page", updateNavigationState);
};
}, [ webContents ]);
if (!webContents) {
return { canGoBack: true, canGoForward: true };
}
return { canGoBack, canGoForward };
}

View File

@@ -0,0 +1,69 @@
#toast-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: absolute;
width: 100%;
top: 20px;
pointer-events: none;
contain: none;
}
.toast {
--bs-toast-bg: var(--accented-background-color);
--bs-toast-color: var(--main-text-color);
z-index: 9999999999 !important;
pointer-events: all;
overflow: hidden;
}
.toast-header {
background-color: var(--more-accented-background-color) !important;
color: var(--main-text-color) !important;
}
.toast-body {
white-space: preserve-breaks;
overflow: hidden;
}
.toast.no-title {
display: flex;
flex-direction: row;
}
.toast.no-title .toast-icon {
display: flex;
align-items: center;
padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x);
}
.toast.no-title .toast-body {
padding-inline-start: 0;
padding-inline-end: 0;
}
.toast.no-title .toast-header {
background-color: unset !important;
}
.toast {
.toast-buttons {
padding: 0 1em 1em 1em;
display: flex;
gap: 1em;
justify-content: space-between;
}
.toast-progress {
position: absolute;
bottom: 0;
inset-inline-start: 0;
inset-inline-end: 0;
background-color: var(--toast-text-color) !important;
height: 4px;
transition: width 0.1s linear;
}
}

View File

@@ -0,0 +1,75 @@
import "./Toast.css";
import clsx from "clsx";
import { useEffect } from "preact/hooks";
import { removeToastFromStore, ToastOptionsWithRequiredId, toasts } from "../services/toast";
import Icon from "./react/Icon";
import { RawHtmlBlock } from "./react/RawHtml";
import Button from "./react/Button";
export default function ToastContainer() {
return (
<div id="toast-container">
{toasts.value.map(toast => <Toast key={toast.id} {...toast} />)}
</div>
)
}
function Toast({ id, title, timeout, progress, message, icon, buttons }: ToastOptionsWithRequiredId) {
// Autohide.
useEffect(() => {
if (!timeout || timeout <= 0) return;
const timerId = setTimeout(() => removeToastFromStore(id), timeout);
return () => clearTimeout(timerId);
}, [ id, timeout ]);
function dismissToast() {
removeToastFromStore(id);
}
const closeButton = (
<button
type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"
onClick={dismissToast}
/>
);
const toastIcon = <Icon icon={icon.startsWith("bx ") ? icon : `bx bx-${icon}`} />;
return (
<div
class={clsx("toast", !title && "no-title")}
role="alert" aria-live="assertive" aria-atomic="true"
id={`toast-${id}`}
>
{title ? (
<div class="toast-header">
<strong class="me-auto">
{toastIcon}
<span class="toast-title">{title}</span>
</strong>
{closeButton}
</div>
) : (
<div class="toast-icon">{toastIcon}</div>
)}
<RawHtmlBlock className="toast-body" html={message} />
{!title && <div class="toast-header">{closeButton}</div>}
{buttons && (
<div class="toast-buttons">
{buttons.map(({ text, onClick }) => (
<Button text={text} onClick={() => onClick({ dismissToast })} />
))}
</div>
)}
<div
class="toast-progress"
style={{ width: `${(progress ?? 0) * 100}%` }}
/>
</div>
)
}

View File

@@ -12,6 +12,7 @@ import shortcutService from "../../services/shortcuts.js";
import appContext from "../../components/app_context.js"; import appContext from "../../components/app_context.js";
import type { Attribute } from "../../services/attribute_parser.js"; import type { Attribute } from "../../services/attribute_parser.js";
import { focusSavedElement, saveFocusedElement } from "../../services/focus.js"; import { focusSavedElement, saveFocusedElement } from "../../services/focus.js";
import { isExperimentalFeatureEnabled } from "../../services/experimental_features.js";
const TPL = /*html*/` const TPL = /*html*/`
<div class="attr-detail tn-tool-dialog"> <div class="attr-detail tn-tool-dialog">
@@ -309,6 +310,8 @@ interface SearchRelatedResponse {
count: number; count: number;
} }
const isNewLayout = isExperimentalFeatureEnabled("new-layout");
export default class AttributeDetailWidget extends NoteContextAwareWidget { export default class AttributeDetailWidget extends NoteContextAwareWidget {
private $title!: JQuery<HTMLElement>; private $title!: JQuery<HTMLElement>;
private $inputName!: JQuery<HTMLElement>; private $inputName!: JQuery<HTMLElement>;
@@ -579,6 +582,13 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget {
.css("top", y - offset.top + 70) .css("top", y - offset.top + 70)
.css("max-height", outerHeight + y > height - 50 ? height - y - 50 : 10000); .css("max-height", outerHeight + y > height - 50 ? height - y - 50 : 10000);
if (isNewLayout) {
this.$widget
.css("top", "unset")
.css("bottom", 70)
.css("max-height", "80vh");
}
if (focus === "name") { if (focus === "name") {
this.$inputName.trigger("focus").trigger("select"); this.$inputName.trigger("focus").trigger("select");
} }

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