Compare commits

...

404 Commits

Author SHA1 Message Date
Elian Doran
0e052bffe8 chore(react): add backup 2026-03-05 21:03:43 +02:00
Elian Doran
3fa2673b55 chore(react): integrate mobile layout as well 2026-03-05 20:59:59 +02:00
Elian Doran
a2130f4aa3 chore(react): port desktop version of note wrapper 2026-03-05 20:17:23 +02:00
Elian Doran
6c9246bc5b chore(react): get title bar to render 2026-03-05 20:10:26 +02:00
Elian Doran
0ca179f990 ci(test): quote command 2026-03-05 18:40:24 +02:00
Elian Doran
9d104015f3 ci(test): quote command 2026-03-05 18:30:08 +02:00
Elian Doran
2c4cf2dcf1 ci(test): separate running of heavy tests to avoid OOM issues 2026-03-05 18:28:27 +02:00
Elian Doran
d2e0124962 chore(deps): update dependency fs-extra to v11.3.4 (#8907) 2026-03-05 16:51:11 +02:00
renovate[bot]
cd59c75c04 chore(deps): update dependency fs-extra to v11.3.4 2026-03-04 01:13:39 +00:00
Elian Doran
caa9143591 chore(deps): update dependency happy-dom to v20.8.3 (#8887) 2026-03-03 22:15:58 +02:00
renovate[bot]
7e53810c02 chore(deps): update dependency happy-dom to v20.8.3 2026-03-03 19:42:03 +00:00
Elian Doran
12efa8dc0b chore(deps): update dependency eslint-plugin-playwright to v2.9.0 (#8886) 2026-03-03 21:21:22 +02:00
Elian Doran
4d0ccac7b5 fix(deps): update dependency node-html-parser to v7.1.0 (#8888) 2026-03-03 21:20:21 +02:00
Elian Doran
8b023a55d0 chore(deps): update dependency copy-webpack-plugin to v14 (#8889) 2026-03-03 21:10:22 +02:00
Elian Doran
b4df5fcbd9 chore(deps): update dependency rollup-plugin-webpack-stats to v3 (#8890) 2026-03-03 20:58:24 +02:00
renovate[bot]
6fbe5718e9 chore(deps): update dependency rollup-plugin-webpack-stats to v3 2026-03-03 18:54:56 +00:00
Elian Doran
908bafca63 Translations update from Hosted Weblate (#8901) 2026-03-03 20:54:00 +02:00
Elian Doran
d7313efd67 fix(ci): migrate all the jank docker ci to use crane instead (#8869) 2026-03-03 20:48:42 +02:00
Микола Копитін
a51e15c9b8 Translated using Weblate (Ukrainian)
Currently translated at 90.0% (1508 of 1675 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/uk/
2026-03-03 18:44:20 +00:00
Hosted Weblate
37e9c7d639 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/
2026-03-03 18:44:20 +00:00
Elian Doran
2d00ac4dfb Univer Sheets v0 (#8902) 2026-03-03 20:44:06 +02:00
Elian Doran
6aec7eae00 chore(server): increase sync version to avoid data loss due to unsupported note type 2026-03-03 20:25:33 +02:00
Elian Doran
6bfbc2d35e chore(spreadsheet): use better clean up mechanism 2026-03-03 20:12:54 +02:00
Elian Doran
2ffc854ce6 chore(spreadsheet): mark note type as beta 2026-03-03 19:59:12 +02:00
Elian Doran
ddd4a374e4 chore(client): fix some whitespace issues 2026-03-03 19:52:15 +02:00
Elian Doran
0d6e2fc00f chore(client): fix typecheck 2026-03-03 19:41:51 +02:00
Elian Doran
366a8e8726 fix(spreadsheet): persistence hook on every render 2026-03-03 19:24:04 +02:00
Elian Doran
7f0aa0697a fix(spreadsheet): error due to duplicate unit IDs 2026-03-03 19:20:25 +02:00
Elian Doran
d123ce33b8 feat(spreadsheet): restore from JSON 2026-03-03 19:09:33 +02:00
Elian Doran
55588f5962 feat(spreadsheet): restore from JSON 2026-03-03 19:05:01 +02:00
Elian Doran
f32130d5c2 feat(spreadsheet): allow source to be viewed 2026-03-03 19:00:23 +02:00
Elian Doran
03f4ff9e7c feat(spreadsheet): save spreadsheet to JSON 2026-03-03 19:00:14 +02:00
Elian Doran
6de78c7154 refactor(spreadsheet): make use of hooks 2026-03-03 18:48:45 +02:00
Elian Doran
d331e418d4 feat(spreadsheet): support dark mode 2026-03-03 18:42:26 +02:00
Elian Doran
4ace74bcb8 feat(spreadsheet): make full-width 2026-03-03 18:36:17 +02:00
Elian Doran
1d4a336256 feat(spreadsheet): integrate spreadsheet with full-height 2026-03-03 18:34:46 +02:00
Elian Doran
ee6c192ab9 chore(spreadsheet): create new note type 2026-03-03 18:24:55 +02:00
Elian Doran
b220bdce9c fix(note_list): affected by floating images (closes #8899) 2026-03-03 18:14:43 +02:00
Elian Doran
4d86c6c4f1 feat(import/single): trim extension for audio files + default icon 2026-03-03 16:19:44 +02:00
Elian Doran
4fd68bf12d feat(import/single): trim extension for video files 2026-03-03 14:29:18 +02:00
Elian Doran
3ffe34964f feat(notes): add default icon for videos 2026-03-03 14:26:45 +02:00
Elian Doran
faaf26c174 fix(quick_edit): save indicator not shown 2026-03-03 14:19:24 +02:00
Elian Doran
f9c7518db2 fix(spaced_update): triggering events too often while typing 2026-03-03 14:19:24 +02:00
Elian Doran
8357c2a39c chore(pdfjs): version not updated for releases 2026-03-03 14:19:24 +02:00
renovate[bot]
793dcee562 chore(deps): update dependency copy-webpack-plugin to v14 2026-03-03 02:02:49 +00:00
renovate[bot]
00368fc131 fix(deps): update dependency node-html-parser to v7.1.0 2026-03-03 02:01:49 +00:00
renovate[bot]
f81b686f41 chore(deps): update dependency eslint-plugin-playwright to v2.9.0 2026-03-03 02:00:00 +00:00
Elian Doran
4c5aada5d3 chore(deps): update dependency @types/express-serve-static-core to v5.1.1 (#8346) 2026-03-02 22:42:10 +02:00
Elian Doran
05551cec9e chore(deps): update dependency sax to v1.5.0 (#8875) 2026-03-02 22:41:20 +02:00
Elian Doran
6300a8c8d1 chore(deps): update dependency @redocly/cli to v2.20.2 (#8853) 2026-03-02 22:34:22 +02:00
Elian Doran
ca4d15727d Merge branch 'main' into renovate/express-serve-static-core-5.x 2026-03-02 22:30:43 +02:00
renovate[bot]
2fe076086e chore(deps): update dependency sax to v1.5.0 2026-03-02 20:25:56 +00:00
Elian Doran
56b65ddfae Translations update from Hosted Weblate (#8870) 2026-03-02 22:22:37 +02:00
Hasan Kara
fcf6673825 Translated using Weblate (Turkish)
Currently translated at 16.3% (19 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/tr/
2026-03-02 20:54:15 +01:00
Hasan Kara
9eda264f52 Translated using Weblate (Turkish)
Currently translated at 5.1% (20 of 387 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/tr/
2026-03-02 20:54:14 +01:00
Hasan Kara
fe1270c679 Translated using Weblate (Turkish)
Currently translated at 4.2% (71 of 1675 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/tr/
2026-03-02 20:54:13 +01:00
Hasan Kara
679e1ac678 Translated using Weblate (Turkish)
Currently translated at 12.0% (19 of 158 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/tr/
2026-03-02 20:54:12 +01:00
ibs-allaow
e309ff2d17 Translated using Weblate (Arabic)
Currently translated at 100.0% (116 of 116 strings)

Translation: Trilium Notes/README
Translate-URL: https://hosted.weblate.org/projects/trilium/readme/ar/
2026-03-02 20:54:12 +01:00
Francis C.
c910335155 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (1675 of 1675 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hant/
2026-03-02 20:54:11 +01:00
Yatrik Patel
5606cde506 Translated using Weblate (Hindi)
Currently translated at 100.0% (1675 of 1675 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/hi/
2026-03-02 20:54:10 +01:00
Yatrik Patel
0e2f4f4e13 Translated using Weblate (Hindi)
Currently translated at 38.6% (61 of 158 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/hi/
2026-03-02 20:54:09 +01:00
renovate[bot]
1f6c6f2acd chore(deps): update dependency @redocly/cli to v2.20.2 2026-03-02 18:09:58 +00:00
Elian Doran
37d2e9f14b fix(deps): update dependency globals to v17.4.0 (#8876) 2026-03-02 16:44:44 +02:00
Adorian Doran
0fcf30a3b8 Merge branch 'main' of https://github.com/TriliumNext/Trilium 2026-03-02 11:22:08 +02:00
Adorian Doran
8712e7dd16 style/pdf viewer: fix some layout issues in toolbar 2026-03-02 11:21:47 +02:00
renovate[bot]
2ee4e9cc14 fix(deps): update dependency globals to v17.4.0 2026-03-02 01:18:53 +00:00
perfectra1n
b257b75be2 fix(ci): remove fragile jq where possible 2026-03-01 13:49:45 -08:00
perfectra1n
2de2709420 fix(ci): migrate all the jank docker ci to use crane instead 2026-03-01 13:47:18 -08:00
Elian Doran
3e0ddd90a1 chore(docker): image not properly pushed to DockerHub 2026-03-01 22:20:00 +02:00
Elian Doran
b96b004262 fix(electron-forge): wrong import 2026-03-01 20:15:04 +02:00
Elian Doran
e1ad48b42a feat(electron-forge): clear signing logs on failure 2026-03-01 20:02:08 +02:00
Elian Doran
420f0917be chore: formatting for CJS files 2026-03-01 20:00:23 +02:00
Elian Doran
31d8287e1b feat(electron-forge): introduce basic expotential back-off for signing 2026-03-01 20:00:23 +02:00
Elian Doran
4433d034db fix(ci): unblock signing not working due to bad shell & missing variable 2026-03-01 17:57:06 +02:00
Elian Doran
c96114992e fix(ci): sanity check does not account for version prefix 2026-03-01 17:43:41 +02:00
Elian Doran
b35e0b906f fix(ci): missing dependencies 2026-03-01 17:38:27 +02:00
Elian Doran
104c9ec64a fix(ci): prevent release if sanity checks fail 2026-03-01 17:34:45 +02:00
Elian Doran
6e4b18b57b fix(ci): missing pnpm 2026-03-01 17:34:05 +02:00
Elian Doran
f9460c8f41 feat(ci): unblock signing for Electron 2026-03-01 17:25:06 +02:00
Elian Doran
02601f37d8 fix(ci): version consistency missing pnpm 2026-03-01 17:21:43 +02:00
Elian Doran
0feab6d4ed chore(release): prepare for v0.102.0 2026-03-01 16:54:05 +02:00
Elian Doran
5a9d3499d8 docs(release): add v0.102.0 release notes 2026-03-01 16:49:06 +02:00
Elian Doran
dce0988409 chore(deps): update dependency lint-staged to v16.3.1 (#8860) 2026-03-01 16:37:50 +02:00
renovate[bot]
b2d378db6b chore(deps): update dependency lint-staged to v16.3.1 2026-03-01 10:43:11 +00:00
Elian Doran
7ecff88da7 chore(deps): update github artifact actions (major) (#8847) 2026-03-01 12:41:40 +02:00
Adorian Doran
b434bf8804 Merge branch 'main' of https://github.com/TriliumNext/Trilium 2026-03-01 09:01:14 +02:00
Adorian Doran
441484629a style/quick edit: fix the layout of collections 2026-03-01 09:01:04 +02:00
renovate[bot]
37a1bd6b25 chore(deps): update github artifact actions 2026-02-28 21:15:12 +00:00
Elian Doran
fe3dfc418f test(client): broken test due to circular dependency 2026-02-28 21:47:02 +02:00
Elian Doran
34ca7912fc Merge remote-tracking branch 'origin/main' into renovate/express-serve-static-core-5.x 2026-02-28 19:11:57 +02:00
Adorian Doran
1d698106da Merge branch 'main' of https://github.com/TriliumNext/Trilium 2026-02-28 19:03:35 +02:00
Adorian Doran
b9ce83165f client/content renderer/pdf: make the container element full height 2026-02-28 19:03:25 +02:00
Elian Doran
34670dd69c Add Support for Recurrence In Calendar Collection (#8799) 2026-02-28 19:01:30 +02:00
Elian Doran
54be58ba1f feat(client/menus): add Copy as Markdown (#8808) 2026-02-28 18:59:40 +02:00
Elian Doran
b9abdcb189 chore(electron_context_menu): use upper case for Markdown 2026-02-28 18:58:25 +02:00
Adorian Doran
9f0f9b8315 style/list view: tweak the size of the PDF preview 2026-02-28 18:57:53 +02:00
Adorian Doran
63ee60ffc7 client/pdf viewer: add a rudimentary support for a read-only view 2026-02-28 18:51:36 +02:00
Adorian Doran
3b2cd5dca1 style/note paths: fix the border radius for a single item listing 2026-02-28 18:47:17 +02:00
Adorian Doran
388a6943e9 Merge branch 'main' of https://github.com/TriliumNext/Trilium 2026-02-28 18:43:59 +02:00
Adorian Doran
50301be093 client/pdf viewer: add a rudimentary support for a read-only view 2026-02-28 18:43:51 +02:00
Elian Doran
123e1ada90 Merge branch 'main' into main 2026-02-28 18:41:48 +02:00
Elian Doran
5c42dbba12 chore(deps): update dependency @types/node to v24.11.0 (#8844) 2026-02-28 18:36:43 +02:00
Elian Doran
a549fd228e chore(deps): update pnpm to v10.30.3 (#8845) 2026-02-28 18:36:33 +02:00
Elian Doran
6e352e5b22 chore(deps): update dependency axios to v1.13.6 (#8851) 2026-02-28 18:36:16 +02:00
Elian Doran
1d3df69bb7 fix(deps): update dependency codemirror-lang-elixir to v4.0.1 (#8852) 2026-02-28 18:35:53 +02:00
Elian Doran
c6394698fa chore(deps): update dependency eslint-plugin-playwright to v2.8.0 (#8854) 2026-02-28 18:35:45 +02:00
Elian Doran
d94f2ac093 chore(deps): update dependency multer to v2.1.0 (#8855) 2026-02-28 18:35:32 +02:00
Elian Doran
740974fbfd fix(next): tab bar offset on horizontal layout 2026-02-28 18:35:15 +02:00
Elian Doran
f0b9e0e48b Translations update from Hosted Weblate (#8849) 2026-02-28 18:35:04 +02:00
Elian Doran
deee50f2b4 Apply suggestion from @gemini-code-assist[bot]
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-28 18:34:54 +02:00
BeatLink
2c9d5368a1 Merge branch 'main' into main 2026-02-28 09:45:53 -05:00
Luk On
819432b4ab Translated using Weblate (Polish)
Currently translated at 100.0% (1674 of 1674 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2026-02-28 15:42:25 +01:00
Giovi
7efbb4d945 Translated using Weblate (Italian)
Currently translated at 100.0% (1674 of 1674 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2026-02-28 15:42:24 +01:00
Adorian Doran
64d1b33a4c UI: restyle PDF viewer (#8857) 2026-02-28 16:42:10 +02:00
Adorian Doran
326adc0196 style/pdf viewer: fixes 2026-02-28 16:35:51 +02:00
Adorian Doran
b1b9a4461e style/pdf viewer: several tweaks 2026-02-28 14:45:35 +02:00
Adorian Doran
d70f5d3ed6 style/pdf viewer: several tweaks 2026-02-28 13:33:48 +02:00
Adorian Doran
d1fac8f0e2 client/pdf viewer: remove the CSS variable whitelist 2026-02-28 10:18:25 +02:00
Adorian Doran
5f7c26eed3 style/pdf viewer: tweak document properties dialog button 2026-02-28 08:56:42 +02:00
Adorian Doran
bf748cee24 style/pdf viewer: tweak toolbar 2026-02-28 08:44:50 +02:00
Adorian Doran
79439f6435 style/pdf viewer: tweak the find bar 2026-02-28 08:28:37 +02:00
Adorian Doran
2a875f8386 style/pdf viewer: restyle text boxes 2026-02-28 08:03:27 +02:00
Adorian Doran
08e69d405c style/pdf viewer: tweak the find bar 2026-02-28 07:38:49 +02:00
renovate[bot]
471f380756 chore(deps): update dependency @types/node to v24.11.0 2026-02-28 04:53:58 +00:00
renovate[bot]
700edbe2c8 chore(deps): update dependency multer to v2.1.0 2026-02-28 01:31:50 +00:00
renovate[bot]
d60c117c62 chore(deps): update dependency eslint-plugin-playwright to v2.8.0 2026-02-28 01:30:58 +00:00
renovate[bot]
4ae395ded5 fix(deps): update dependency codemirror-lang-elixir to v4.0.1 2026-02-28 01:29:07 +00:00
renovate[bot]
f311db1cb4 chore(deps): update dependency axios to v1.13.6 2026-02-28 01:28:18 +00:00
BeatLink
40be94804c Merge branch 'main' into main 2026-02-27 18:09:22 -05:00
BeatLink
5719819947 Update Recurrence Docs 2026-02-27 18:08:13 -05:00
BeatLink
c938bcc657 Remove unnecessary error checks 2026-02-27 18:01:23 -05:00
BeatLink
e029379194 Add recurrence testing, use dayjs for calendar 2026-02-27 17:39:12 -05:00
Adorian Doran
d56f106964 UI: general improvements (#8837) 2026-02-27 22:47:22 +02:00
Adorian Doran
676dea33e1 client: fix different issues 2026-02-27 22:45:52 +02:00
Adorian Doran
945b00030b style/pdf viewer: restyle UI 2026-02-27 22:37:07 +02:00
Adorian Doran
a47de6c65c Merge branch 'main' of https://github.com/TriliumNext/Trilium into feat/ui/general-improvements 2026-02-27 19:34:41 +02:00
Adorian Doran
7c89c66526 style/pdf viewer: restyle UI 2026-02-27 19:34:26 +02:00
BeatLink
8554dc249c Fix recurrence error management 2026-02-27 11:43:23 -05:00
BeatLink
bfcbfac5bb Add recurrence error handling 2026-02-27 10:47:56 -05:00
Zexin Yuan
59d8a98eea feat(client/menus): add Copy as Markdown to electron context menu 2026-02-27 14:22:04 +08:00
renovate[bot]
c7d74e8b00 chore(deps): update pnpm to v10.30.3 2026-02-27 01:08:42 +00:00
Elian Doran
dc3de5bf36 chore(server): address requested changes 2026-02-27 00:05:54 +02:00
Elian Doran
680cd8118f fix(desktop+server): use exec in launcher scripts (#8809) 2026-02-26 23:38:14 +02:00
Elian Doran
1041bf70e1 test(express-partial-content): fix type errors 2026-02-26 21:11:22 +02:00
Elian Doran
0c6326b678 refactor(server): use strong typing for routes 2026-02-26 21:08:54 +02:00
Adorian Doran
f4d91e48ba style/pdf viewer: fix color scheme 2026-02-26 20:46:55 +02:00
renovate[bot]
fd805a5279 chore(deps): update dependency @types/express-serve-static-core to v5.1.1 2026-02-26 18:18:55 +00:00
Elian Doran
9374694a0c Merge branch 'main' into exec-in-launcher-scripts 2026-02-26 20:17:53 +02:00
Elian Doran
61460daaea chore(deps): update dependency stylelint to v17.4.0 (#8835) 2026-02-26 20:17:04 +02:00
Elian Doran
d64c1f6b0e chore(deps): update dependency @types/node to v24.10.14 (#8833) 2026-02-26 20:16:47 +02:00
Elian Doran
0334166029 feat(turndown-plugin-gfm): adopt MD060 compact style for table cells (#8840) 2026-02-26 20:15:27 +02:00
Adorian Doran
7fac172ce2 style: remove redundant style 2026-02-26 19:54:42 +02:00
Adorian Doran
3b9f765c24 style/tree items: display a fallback icon when the specified icon pack is missing 2026-02-26 19:52:20 +02:00
Adorian Doran
655b016efa Merge branch 'main' of https://github.com/TriliumNext/Trilium into feat/ui/general-improvements 2026-02-26 19:18:09 +02:00
Adorian Doran
aa247ef06c Theming: include the current theme ID as an attribute for the body element (#8842) 2026-02-26 19:14:37 +02:00
Zexin Yuan
9e653a87b8 feat(turndown-plugin-gfm): adopt MD060 compact style for table cells
Style compact avoids extra padding with a single space around cell
content:

| Character | Meaning |
| --- | --- |
| Y | Yes |
| N | No |

Closes #8795
2026-02-27 00:23:04 +08:00
Adorian Doran
dfb44def2b client/theming: include the current theme ID as an attribute on the body element 2026-02-26 17:50:23 +02:00
Elian Doran
f0e8c0f79d chore(deps): update dependency @types/supertest to v7 (#8836) 2026-02-26 16:18:12 +02:00
Adorian Doran
28fe73911f Theming: color scheme selectors (#8839) 2026-02-26 16:16:52 +02:00
Adorian Doran
a971640ffc client: add some documentation 2026-02-26 16:14:39 +02:00
Adorian Doran
44dc8cf00d Close #7932 2026-02-26 15:52:27 +02:00
Adorian Doran
59ca270880 Merge branch 'main' into feat/ui/general-improvements 2026-02-26 10:43:34 +02:00
Adorian Doran
abb5fe5b0f style/tree items: restyle the bulk actions button 2026-02-26 10:27:13 +02:00
Adorian Doran
af0e4088a6 style/tree items: fix hover color for the active item 2026-02-26 09:35:29 +02:00
Adorian Doran
6b82943871 style/tree items: restyle selection 2026-02-26 09:31:39 +02:00
renovate[bot]
d7aa744bad chore(deps): update dependency @types/supertest to v7 2026-02-26 01:54:26 +00:00
renovate[bot]
f417a2e126 chore(deps): update dependency stylelint to v17.4.0 2026-02-26 01:53:38 +00:00
renovate[bot]
b937f474e4 chore(deps): update dependency @types/node to v24.10.14 2026-02-26 01:52:41 +00:00
Elian Doran
6a3c4fec98 Mobile fixes (#8832) 2026-02-25 23:17:50 +02:00
Elian Doran
6bda7837d6 chore(deps): update dependency @redocly/cli to v2.19.2 (#8826) 2026-02-25 23:07:13 +02:00
Elian Doran
ab9144972b Merge branch 'main' into feature/mobile_fixes 2026-02-25 23:06:23 +02:00
Elian Doran
bcb646f42b chore(deps): update dependency @smithy/middleware-retry to v4.4.37 (#8827) 2026-02-25 23:02:37 +02:00
Elian Doran
0db75a6cdb chore(deps): update dependency electron to v40.6.1 (#8828) 2026-02-25 23:01:37 +02:00
Elian Doran
76c7b8692d fix(deps): update dependency mind-elixir to v5.9.1 (#8829) 2026-02-25 23:00:36 +02:00
Elian Doran
1061aba212 chore(deps): update node.js to v24.14.0 (#8830) 2026-02-25 22:55:03 +02:00
Elian Doran
d4eb6f07bd chore(deps): update dependency @wxt-dev/auto-icons to v1.1.1 (#8800) 2026-02-25 22:54:42 +02:00
Elian Doran
f1a83124a8 Merge branch 'main' into feature/mobile_fixes 2026-02-25 22:42:41 +02:00
Elian Doran
2ad30c6a3d Other bugfixes (#8824) 2026-02-25 22:35:29 +02:00
Elian Doran
0f1533d0a0 chore(mobile): remove redundant style 2026-02-25 20:57:20 +02:00
Elian Doran
bf5caaebb5 fix(mobile/text): formatting toolbar doesn't go back to the right position on iOS 2026-02-25 20:36:37 +02:00
Adorian Doran
b24d2c65a1 style: tweak layout 2026-02-25 20:33:33 +02:00
Elian Doran
2d989dcfe3 fix(mobile/text): formatting toolbar wrongly positioned if dragging on it 2026-02-25 20:18:04 +02:00
Elian Doran
8e8e6f9ed1 fix(mobile/text): floating toolbar mispositioned on iOS 2026-02-25 20:15:07 +02:00
Elian Doran
e1de98c4ae fix(mobile/text): formatting toolbar missing background on iOS 2026-02-25 20:02:15 +02:00
Adorian Doran
aba7f35d9f style/text: tweak dividers 2026-02-25 19:34:31 +02:00
Adorian Doran
8c9ad575ef style: tweak layout 2026-02-25 19:26:06 +02:00
Elian Doran
fc59ee6e93 chore(mobile): fix warnings in mobile_editor_toolbar 2026-02-25 19:14:32 +02:00
Elian Doran
5ec9770b07 fix(mobile): confusing shift when opening keyboard in split on iOS 2026-02-25 19:08:20 +02:00
Elian Doran
1c1895b2eb fix(mobile): confusing shift when opening keyboard in split on iOS 2026-02-25 19:05:01 +02:00
Adorian Doran
7861bc41f9 style/calendar: tweak layout 2026-02-25 18:56:24 +02:00
Adorian Doran
843e4d45e6 style: tweak layout 2026-02-25 18:55:57 +02:00
Elian Doran
416825c9c2 fix(mobile): toast not respecting safe area 2026-02-25 18:54:42 +02:00
Elian Doran
6762539b4d fix(client): note context active indicator disappears after typing 2026-02-25 18:47:00 +02:00
Elian Doran
ae9827c436 fix(mobile): virtual keyboard detection not working on Android 2026-02-25 18:35:01 +02:00
Adorian Doran
4b4b427d2b style: tweak layout 2026-02-25 18:33:53 +02:00
Elian Doran
33622cd3fe fix(hooks): unnecessary recreation of media listener 2026-02-25 18:21:53 +02:00
Adorian Doran
807b054a95 UI: grid view extra improvements (#8831) 2026-02-25 18:21:35 +02:00
Adorian Doran
b223b931ab ui/grid view/tables: fix scroll direction 2026-02-25 11:35:39 +02:00
Adorian Doran
6759fef827 ui/grid view/tables: tweak 2026-02-25 11:04:26 +02:00
Adorian Doran
896d50b1f8 ui/grid view: hide the scrollbar of tables 2026-02-25 11:01:45 +02:00
Adorian Doran
2049c49fdb ui/grid view: horizontally scroll tables 2026-02-25 10:58:38 +02:00
Adorian Doran
b3c397e847 ui/grid view: fade out overflowing content 2026-02-25 09:40:05 +02:00
renovate[bot]
e69b85a988 chore(deps): update node.js to v24.14.0 2026-02-25 00:56:05 +00:00
renovate[bot]
aabc9ec4df fix(deps): update dependency mind-elixir to v5.9.1 2026-02-25 00:55:58 +00:00
renovate[bot]
598501e3f6 chore(deps): update dependency electron to v40.6.1 2026-02-25 00:55:05 +00:00
renovate[bot]
bfa344a839 chore(deps): update dependency @smithy/middleware-retry to v4.4.37 2026-02-25 00:54:08 +00:00
renovate[bot]
c466d7ee9f chore(deps): update dependency @redocly/cli to v2.19.2 2026-02-25 00:53:13 +00:00
renovate[bot]
2e9c07d3d6 chore(deps): update dependency @wxt-dev/auto-icons to v1.1.1 2026-02-24 20:24:58 +00:00
Elian Doran
9651ca99f3 chore(deps): update dependency @smithy/middleware-retry to v4.4.36 (#8813) 2026-02-24 22:22:53 +02:00
Elian Doran
a6e87f5724 chore(deps): update dependency eslint to v10.0.2 (#8815) 2026-02-24 22:22:25 +02:00
renovate[bot]
cf994dac5a chore(deps): update dependency eslint to v10.0.2 2026-02-24 17:49:42 +00:00
Elian Doran
95c9c375c9 chore(deps): update dependency wxt to v0.20.18 (#8801) 2026-02-24 19:45:35 +02:00
renovate[bot]
f9804eda8e chore(deps): update dependency @smithy/middleware-retry to v4.4.36 2026-02-24 17:44:47 +00:00
Elian Doran
88c2bedbd7 chore(deps): update dependency eslint-plugin-playwright to v2.7.1 (#8816) 2026-02-24 19:44:34 +02:00
Elian Doran
49bf49c967 chore(deps): update pnpm to v10.30.2 (#8817) 2026-02-24 19:44:13 +02:00
Elian Doran
506b5c44af chore(deps): update typescript-eslint monorepo to v8.56.1 (#8818) 2026-02-24 19:43:38 +02:00
Elian Doran
22ea59a63b fix(deps): update dependency eslint-linter-browserify to v10.0.2 (#8819) 2026-02-24 19:43:17 +02:00
Elian Doran
934aaaf045 chore(deps): update dependency @types/jquery to v4 (#8820) 2026-02-24 19:42:37 +02:00
Elian Doran
c6bfcea79f Translations update from Hosted Weblate (#8823) 2026-02-24 19:42:19 +02:00
Aindriú Mac Giolla Eoin
6e39fb12e2 Translated using Weblate (Irish)
Currently translated at 100.0% (1674 of 1674 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ga/
2026-02-24 17:14:11 +00:00
Elian Doran
dbe534d8f8 Translations update from Hosted Weblate (#8811) 2026-02-24 19:14:01 +02:00
Elian Doran
04e5197d00 Apply suggestion from @gemini-code-assist[bot]
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-24 19:13:42 +02:00
Elian Doran
3a15878629 fix(mindmap): not reacting to switch between light/dark mode 2026-02-24 18:46:46 +02:00
Elian Doran
021a908c9c fix(canvas): not reacting to switch between light/dark mode 2026-02-24 18:35:36 +02:00
Elian Doran
c09ef3af80 fix(note_title): help pages have editable title 2026-02-24 18:14:13 +02:00
Elian Doran
3151e6dafc fix(client/layout): scroll padding enabled when note is protected 2026-02-24 18:10:51 +02:00
noobhjy
e9dc97daf8 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1674 of 1674 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2026-02-24 09:16:45 +01:00
green
3a3cc565ea Translated using Weblate (Japanese)
Currently translated at 100.0% (1674 of 1674 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2026-02-24 09:16:45 +01:00
Toto Yullian
fcf4ffb445 Translated using Weblate (Indonesian)
Currently translated at 4.6% (78 of 1674 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/id/
2026-02-24 09:16:44 +01:00
Giovi
b34c27af1f Translated using Weblate (Italian)
Currently translated at 100.0% (1674 of 1674 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/it/
2026-02-24 09:16:44 +01:00
Adorian Doran
64371a6b9c UI: tweak grid & list collections (#8804) 2026-02-24 10:16:39 +02:00
Adorian Doran
182afab12c Merge branch 'main' into feat/ui/tweak-list-and-grid-collections 2026-02-24 10:16:17 +02:00
Adorian Doran
57e888911d ui/list & grid view: refactor 2026-02-24 10:15:51 +02:00
Adorian Doran
535054b2d2 style/card: fix hover color on nested items 2026-02-24 10:07:26 +02:00
Adorian Doran
d40191257c ui/grid view: tweak the height of video previews 2026-02-24 09:53:35 +02:00
Adorian Doran
87ee1185f2 ui/list & grid view: add bottom margin if the pager is not visible 2026-02-24 09:33:28 +02:00
Adorian Doran
f4b0f810bd ui/list & grid view: increase content entrance transition duration 2026-02-24 09:24:55 +02:00
renovate[bot]
0934e33af7 chore(deps): update dependency @types/jquery to v4 2026-02-24 01:55:37 +00:00
renovate[bot]
b3e88f5a44 fix(deps): update dependency eslint-linter-browserify to v10.0.2 2026-02-24 01:54:41 +00:00
renovate[bot]
2f23db0c64 chore(deps): update typescript-eslint monorepo to v8.56.1 2026-02-24 01:53:41 +00:00
renovate[bot]
ca2f39bacd chore(deps): update pnpm to v10.30.2 2026-02-24 01:52:45 +00:00
renovate[bot]
e38b89996a chore(deps): update dependency eslint-plugin-playwright to v2.7.1 2026-02-24 01:52:34 +00:00
Christian Barcenas
8efbb8819b fix(server): use exec in launcher script 2026-02-24 00:22:49 +01:00
Christian Barcenas
e03bd3d716 fix(desktop): use exec in launcher scripts 2026-02-24 00:22:49 +01:00
Elian Doran
cfb56cb143 fix(deps): update dependency katex to v0.16.33 (#8802) 2026-02-23 21:38:38 +02:00
renovate[bot]
477e516473 fix(deps): update dependency katex to v0.16.33 2026-02-23 18:59:39 +00:00
Elian Doran
fd601eac5b add generic debugging/dap launch.json for client, server and vitest (#8668) 2026-02-23 20:56:34 +02:00
Elian Doran
df4fa42acd fix(desktop): protected session not refreshing while app is in background (closes #7761) 2026-02-23 19:56:03 +02:00
Elian Doran
b06d390df5 chore(server): use purple icon in dev mode 2026-02-23 18:59:07 +02:00
Elian Doran
7f013a58f5 fix(backend_log): not scrollable 2026-02-23 18:55:19 +02:00
Elian Doran
1fd0fb03fa chore(ckeditor): remove unnecessary priority
See https://github.com/ckeditor/ckeditor5/pull/19115#issuecomment-3944720307
2026-02-23 18:46:09 +02:00
Elian Doran
7ec718218e fix(hidden_subtree): attribute of wrong type (relation vs label) causing issues 2026-02-23 18:45:20 +02:00
misch334
b5300e5b86 make browser reference platform-agnostic and reliant on defaults 2026-02-23 12:29:29 +01:00
Adorian Doran
19d2f02694 ui/list & grid view: fix some issues 2026-02-23 12:29:28 +02:00
Adorian Doran
fec929dfee ui/list & grid view: refactor 2026-02-23 12:21:07 +02:00
Adorian Doran
d7339ff14d ui/collection properties: apply the correct inline padding 2026-02-23 11:40:02 +02:00
Adorian Doran
422bc00ade ui/list & grid view: add block margin for the bottom pager 2026-02-23 11:36:04 +02:00
Adorian Doran
8edf5483a6 ui/pager: add support for custom CSS class 2026-02-23 11:28:35 +02:00
Adorian Doran
00046d4145 ui/grid view: do not show the item menu for the options root 2026-02-23 11:15:35 +02:00
Adorian Doran
25e67f62d5 ui/list & grid view: use background effects 2026-02-23 11:10:39 +02:00
Adorian Doran
8d233e66e1 Grid collections: enhance the grid view (#8770) 2026-02-23 10:39:08 +02:00
Adorian Doran
39e0d5b629 ui/grid view: fix some issues 2026-02-23 10:16:04 +02:00
Adorian Doran
90844d5bc2 ui/grid view card: tweak style 2026-02-23 10:11:52 +02:00
Adorian Doran
29df06626b ui/grid view card: tweak CSS 2026-02-23 10:06:11 +02:00
Adorian Doran
d28661fee3 ui/grid view card: use tinted background 2026-02-23 09:55:47 +02:00
Adorian Doran
dc8c10e531 ui/grid view card: refactor CSS 2026-02-23 09:34:08 +02:00
Adorian Doran
538e1f0fdd ui/grid view card: tweak layout 2026-02-23 09:21:52 +02:00
Adorian Doran
eaf0c690e1 ui/grid view card: tweak layout 2026-02-23 09:19:01 +02:00
Adorian Doran
a4a3d6a82c ui/grid view card: restyle the button bar 2026-02-23 09:08:54 +02:00
renovate[bot]
e5eab3952b chore(deps): update dependency wxt to v0.20.18 2026-02-23 00:55:07 +00:00
BeatLink
9b45639148 Update apps/client/src/widgets/collections/calendar/event_builder.ts
Replace end with duration if recurrence set. Make duration calculation clearer

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-22 18:43:18 -05:00
BeatLink
e53cd7443a Add Docs for Recurrence 2026-02-22 18:22:21 -05:00
BeatLink
60b74f5959 Add Recurrence Support for Calendar 2026-02-22 18:13:08 -05:00
Elian Doran
a3e4044fec Translations update from Hosted Weblate (#8796) 2026-02-22 21:46:05 +02:00
Elian Doran
f380df9c01 feat(i18n): add support for Hindi 2026-02-22 21:35:14 +02:00
Hosted Weblate
83fc82a615 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/
2026-02-22 18:13:20 +00:00
Hosted Weblate
eaf3632fc9 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/
2026-02-22 18:13:06 +00:00
Vedansh Bodkhe
1d947f26ff Translated using Weblate (Hindi)
Currently translated at 100.0% (1809 of 1809 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/hi/
2026-02-22 18:13:02 +00:00
Elian Doran
34a08be4cd feat(dev): remove ai/llm features (#8678) 2026-02-22 20:12:49 +02:00
Adorian Doran
f84a4c4856 ui/grid view: do not animate the card when pressing the item menu button 2026-02-22 19:48:58 +02:00
Adorian Doran
47aa24d0f4 ui/list view: use card frame component instead of a custom styled element 2026-02-22 19:43:25 +02:00
Adorian Doran
e6e132e905 ui/card frame: add support for arbitrary HTML attributes and event handlers 2026-02-22 19:42:08 +02:00
Adorian Doran
ad2df957c7 ui/cards: create a card frame component 2026-02-22 19:25:30 +02:00
Elian Doran
818ca2c2ab e2e(server): fix flaky test 2026-02-22 18:54:51 +02:00
Elian Doran
72c34eb491 docs(user): mention changes to LLM 2026-02-22 16:03:27 +02:00
Elian Doran
22341bf0b1 fix(server): LLM launcher & option still not removed 2026-02-22 15:46:56 +02:00
Elian Doran
c735870b95 test(server): reduce num workers temporarily 2026-02-22 14:33:14 +02:00
Elian Doran
56f796bf80 Fix searching with orderby and parentheses / increased expression level (#8717) 2026-02-22 12:34:59 +02:00
Elian Doran
225693fa79 chore(server): update integration DB to latest migration 2026-02-22 12:01:20 +02:00
Elian Doran
7f760bff17 Merge remote-tracking branch 'origin/main' into feat/remove-ai-llm 2026-02-22 11:51:57 +02:00
Elian Doran
6b4da33729 chore(launch_bar): log warnings instead of crashing on a bad launcher 2026-02-22 11:35:46 +02:00
Elian Doran
82cae8ffbf fix(hidden_subtree): clean up LLM launch item 2026-02-22 11:13:37 +02:00
Elian Doran
31dbbb1881 Translations update from Hosted Weblate (#8793) 2026-02-22 10:49:33 +02:00
green
31de1e007a Translated using Weblate (Japanese)
Currently translated at 100.0% (1809 of 1809 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2026-02-22 09:49:13 +01:00
Elian Doran
a2d0655a75 fix(deps): update dependency eslint-linter-browserify to v10.0.1 (#8788) 2026-02-22 10:49:01 +02:00
Elian Doran
269209dd31 fix(deps): update dependency mind-elixir to v5.9.0 (#8789) 2026-02-22 10:48:22 +02:00
Elian Doran
32082927b2 Translations update from Hosted Weblate (#8792) 2026-02-22 10:47:32 +02:00
Elian Doran
c10d0b6349 Apply suggestion from @gemini-code-assist[bot]
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-22 10:46:31 +02:00
Vedansh Bodkhe
11ff1266e5 Translated using Weblate (Hindi)
Currently translated at 4.9% (89 of 1809 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/hi/
2026-02-22 04:49:25 +01:00
Marcel
8b5717ff7f Translated using Weblate (German)
Currently translated at 100.0% (1809 of 1809 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/de/
2026-02-22 04:49:25 +01:00
Marcel
e69f6bef2c Translated using Weblate (German)
Currently translated at 100.0% (389 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/de/
2026-02-22 04:49:24 +01:00
renovate[bot]
2a17a322c2 fix(deps): update dependency mind-elixir to v5.9.0 2026-02-22 00:59:30 +00:00
renovate[bot]
26ddb76338 fix(deps): update dependency eslint-linter-browserify to v10.0.1 2026-02-22 00:58:07 +00:00
Elian Doran
f62f156c93 fix(editor): resolve strange stuck indent when a Note has images (#8520) 2026-02-22 00:01:07 +02:00
Elian Doran
f4b6c65bad fix(ckeditor5): cursor jumping on Tab for other widgets such as separators or footnote 2026-02-21 21:30:57 +02:00
Elian Doran
0a08399d9e feat(share-theme): align mobile/desktop UI with unified header (#8484) 2026-02-21 20:36:26 +02:00
Elian Doran
df1adaad3a Merge branch 'main' into share-theme-improvements 2026-02-21 20:12:37 +02:00
Elian Doran
33b1490de0 Fix week note title error when cross year (#8431) 2026-02-21 20:09:14 +02:00
Elian Doran
286720bdbf Improve no results for search (#8786) 2026-02-21 19:55:40 +02:00
Elian Doran
1441ac67ab chore(search): use translation for button 2026-02-21 19:21:09 +02:00
Elian Doran
d245fdd1b8 chore(search): reuse search command 2026-02-21 19:20:06 +02:00
Elian Doran
e9c9b456e0 feat(search): add button to search now 2026-02-21 19:15:42 +02:00
Elian Doran
d9eafff7df style(client): improve no items size and alignment 2026-02-21 19:02:29 +02:00
Elian Doran
94eb19d879 feat(search): center no results vertically 2026-02-21 18:59:13 +02:00
Elian Doran
d7b585230a fix(search): double scrollbars 2026-02-21 18:56:07 +02:00
Elian Doran
16ed14f85a feat(search): use NoItems for not executed & no results 2026-02-21 18:51:25 +02:00
Elian Doran
93e59cc3b6 fix(search): "no results" item not shown 2026-02-21 18:49:55 +02:00
Elian Doran
c38220892b Merge branch 'main' into fix_parens_orderby 2026-02-21 17:31:33 +02:00
Elian Doran
4ef72fb35b fix(breadcrumb): note title update (#8784) 2026-02-21 17:23:32 +02:00
Elian Doran
3f23ce095c Various bugfixes for the release (#8785) 2026-02-21 16:41:19 +02:00
JYC333
0ead246ce7 Merge branch 'main' into week-note 2026-02-21 14:10:19 +00:00
Elian Doran
0f8259fdf7 docs(user): align collection creation, hiding subtree & collection properties 2026-02-21 13:11:05 +02:00
Elian Doran
ebb180b0ab chore(hidden_subtree): disable hiding subtree by default for now 2026-02-21 12:45:24 +02:00
Elian Doran
c03f50583e chore(server): address requested changes 2026-02-21 12:33:30 +02:00
Elian Doran
b8a6cf0099 fix(calendar): wrong parent when creating day note from unhoisted workspace calendar root 2026-02-21 12:16:55 +02:00
Elian Doran
ad3cdc3364 chore(status_bar): fix inherited attribute key and useEffect deps 2026-02-21 12:00:02 +02:00
Elian Doran
d924d3fa4f fix(promoted_attributes): auto-complete interfering with value 2026-02-21 11:41:59 +02:00
Elian Doran
dd4a8c08c8 fix(promoted_attributes): multiple autocomplete instances 2026-02-21 11:34:04 +02:00
Vedansh Bodkhe
52f2e800e7 Update apps/client/src/widgets/react/hooks.tsx
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-21 15:01:29 +05:30
Vedansh Bodkhe
8d94b62db0 fix(breadcrumb): note title update 2026-02-21 14:53:06 +05:30
Elian Doran
c3eb483224 chore(promoted_attributes): unnecessary use of .entries() 2026-02-21 11:02:42 +02:00
Elian Doran
e7b1e0a81f fix(promoted_attributes): typing sometimes affects the value 2026-02-21 11:01:57 +02:00
Elian Doran
ca672c68a3 fix(export/zip): hidden note appears in tree (closes #8714) 2026-02-21 10:02:42 +02:00
Elian Doran
416e11a32b chore(share): write meta file for analysis 2026-02-21 09:57:05 +02:00
Elian Doran
bbaa2db377 docs: update SECURITY.MD (closes #8767) 2026-02-21 09:43:55 +02:00
Elian Doran
cf4e412ab8 fix(geomap): read-only map pin click broken (closes #8755) 2026-02-21 09:37:35 +02:00
Elian Doran
48ac88dbfe fix(geomap): collection properties overlapping with mobile backdrop 2026-02-21 09:16:29 +02:00
Elian Doran
4980e9a15b fix(desktop): window not draggable on legacy theme in vertical layout (closes #8402) 2026-02-21 09:10:00 +02:00
Elian Doran
290a2ab902 fix(deps): update dependency i18next to v25.8.13 (#8781) 2026-02-21 09:02:02 +02:00
Elian Doran
6a04d8fce1 chore(deps): update pnpm to v10.30.1 (#8779) 2026-02-21 09:01:47 +02:00
Elian Doran
7286ac743f chore(deps): update dependency eslint to v10.0.1 (#8778) 2026-02-21 08:57:32 +02:00
Elian Doran
41b6b5f615 fix(deps): update dependency @codemirror/view to v6.39.15 (#8780) 2026-02-21 08:57:17 +02:00
Elian Doran
d0572f7691 fix(deps): update dependency preact-render-to-string to v6.6.6 (#8782) 2026-02-21 08:57:01 +02:00
Elian Doran
a8210844cb chore(deps): update dependency happy-dom to v20.7.0 (#8783) 2026-02-21 08:56:43 +02:00
renovate[bot]
c5c39cedc4 chore(deps): update dependency happy-dom to v20.7.0 2026-02-21 01:40:07 +00:00
renovate[bot]
8d6ae2da82 fix(deps): update dependency preact-render-to-string to v6.6.6 2026-02-21 01:39:11 +00:00
renovate[bot]
9eea6b3645 fix(deps): update dependency i18next to v25.8.13 2026-02-21 01:38:19 +00:00
renovate[bot]
6d9638970d fix(deps): update dependency @codemirror/view to v6.39.15 2026-02-21 01:37:27 +00:00
renovate[bot]
ecd3638298 chore(deps): update pnpm to v10.30.1 2026-02-21 01:36:12 +00:00
renovate[bot]
bbde0e4d24 chore(deps): update dependency eslint to v10.0.1 2026-02-21 01:35:51 +00:00
Elian Doran
299f694aa9 chore: disable support notice for i18next
Signed-off-by: Elian Doran <contact@eliandoran.me>
2026-02-20 23:39:55 +02:00
Elian Doran
2675698d3a feat: enhance build-docs utility with pnpm and Nix support (#8574) 2026-02-20 23:13:05 +02:00
Elian Doran
3056f3cfcf fix(deps): update dependency preact to v10.28.4 (#8772) 2026-02-20 18:32:24 +02:00
Elian Doran
7310d8af30 Merge remote-tracking branch 'origin/main' into feat/remove-ai-llm 2026-02-20 15:31:34 +02:00
Elian Doran
b62f40f8c9 chore(server): format translations to avoid merge issues 2026-02-20 15:28:57 +02:00
Elian Doran
ae1aac02ae chore(client): format translations to avoid merge issues 2026-02-20 15:26:13 +02:00
Elian Doran
e19f344dc1 Translations update from Hosted Weblate (#8777) 2026-02-20 15:17:24 +02:00
손상모
1525ecdb05 Translated using Weblate (Korean)
Currently translated at 5.8% (105 of 1808 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ko/
2026-02-20 13:12:07 +00:00
손상모
4f6a13b2c4 Translated using Weblate (Korean)
Currently translated at 31.8% (124 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ko/
2026-02-20 13:12:06 +00:00
Ulices
4747297adc Translated using Weblate (Spanish)
Currently translated at 100.0% (1808 of 1808 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/es/
2026-02-20 13:12:05 +00:00
Hosted Weblate
f753974800 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/
2026-02-20 13:12:05 +00:00
Elian Doran
bd4002529c chore(deps): update dependency @anthropic-ai/sdk to v0.78.0 (#8773) 2026-02-20 15:11:38 +02:00
Elian Doran
00588eb099 chore(deps): update dependency electron to v40.6.0 (#8774) 2026-02-20 15:11:28 +02:00
Elian Doran
81420b6168 chore(deps): update dependency jsonc-eslint-parser to v3 (#8775) 2026-02-20 15:09:08 +02:00
renovate[bot]
fe74d2aec9 chore(deps): update dependency jsonc-eslint-parser to v3 2026-02-20 09:52:34 +00:00
renovate[bot]
6514701c6a chore(deps): update dependency electron to v40.6.0 2026-02-20 00:02:14 +00:00
renovate[bot]
9e206ce7ea chore(deps): update dependency @anthropic-ai/sdk to v0.78.0 2026-02-20 00:01:39 +00:00
renovate[bot]
b32ad68e4f fix(deps): update dependency preact to v10.28.4 2026-02-20 00:01:06 +00:00
Adorian Doran
dfb5322b1a ui/list view: fix a regression 2026-02-19 23:49:59 +02:00
Adorian Doran
47859d401e ui/grid view: refactor CSS 2026-02-19 22:46:01 +02:00
Adorian Doran
4b098e2008 ui/list & grid view: correct attribute name 2026-02-19 22:20:18 +02:00
Adorian Doran
b4cd66db50 ui/grid view: fix some issues 2026-02-19 22:18:55 +02:00
Adorian Doran
8b5d88bf2b ui/grid view: fix CSS selector 2026-02-19 20:05:42 +02:00
Adorian Doran
5588042ab6 ui/grid view: refactor CSS 2026-02-19 19:52:40 +02:00
Adorian Doran
60ae094d3b ui/grid view: reveal the content using a fade in transition 2026-02-19 19:26:51 +02:00
Adorian Doran
f200ac898a ui/grid view: add support for search view 2026-02-19 19:14:01 +02:00
Adorian Doran
419e87b0de ui/grid view: add support for colored notes 2026-02-18 10:29:41 +02:00
Adorian Doran
75c7d55e01 ui/grid view: tweak style 2026-02-18 10:08:50 +02:00
Adorian Doran
e006550b9f ui/grid view: add a menu button for grid items 2026-02-18 09:51:18 +02:00
Adorian Doran
2a424f8dc4 ui/grid view: refactor 2026-02-18 09:31:03 +02:00
Adorian Doran
5036518458 ui/grid view: hide attributes 2026-02-18 09:20:00 +02:00
Adorian Doran
297cbbd8b3 ui/grid view: reuse some styles from list view 2026-02-18 09:15:38 +02:00
Adorian Doran
516f0052ef ui/grid view: use flex gap instead of margins for cards 2026-02-17 20:36:01 +02:00
misch334
e29b238161 fix orderby in combination with parentheses / increased expression level 2026-02-14 14:50:10 +01:00
misch334
4c36a9cca9 add client and compound launch entry 2026-02-12 16:11:21 +01:00
perfectra1n
f3d415a3a7 merge main into branch 2026-02-11 10:01:49 -08:00
misch334
fd8ab990bd add autoAttachChildProcesses to launch server config 2026-02-11 07:25:58 +01:00
misch334
5c007cdebc adjust vi launch.json to be based on vitest.dev/guide/debugging 2026-02-10 18:45:56 +01:00
misch334
ef6c733f93 add options recommended by tsx.is docs 2026-02-10 18:15:51 +01:00
misch334
e7d6658c7a add generic launch.json for debugging/dap 2026-02-10 17:34:00 +01:00
perfectra1n
d7d411caf9 feat(dev): remove ai/llm features 2026-02-07 13:04:37 -08:00
Jin
19781bb14c Merge branch 'main' into week-note 2026-02-01 14:29:45 +00:00
Jin
7fd2bc30cc test: add test for week number with different first day of week setting 2026-02-01 14:26:11 +00:00
Wael Nasreddine
07f273fda4 feat: enhance build-docs utility with pnpm and Nix support
This enhances the `build-docs` utility to allow running it via pnpm and
packaging it as a Nix application. Changes include:

- Added `build` and `cli` scripts to `apps/build-docs/package.json`.
- Implemented a standalone CLI wrapper for documentation generation.
- Added a `trilium-build-docs` package to the Nix flake for use in other projects.
- Integrated `apps/build-docs` into the Nix workspace and build pipeline.

These changes make the documentation build process more portable and easier
to integrate into CI/CD pipelines outside of the main repository.
2026-02-01 00:32:51 -08:00
Wael Nasreddine
b08126ec2b feat(share-theme): add borders to tables matching the dark/light theme 2026-01-30 02:13:38 -08:00
Wael Nasreddine
e0824a5426 feat(share-theme): Increase the max-body to 1600px 2026-01-30 02:13:12 -08:00
Wael Nasreddine
c4f5471e13 feat(share-theme): align mobile/desktop UI with unified header 2026-01-30 02:13:02 -08:00
Wael Nasreddine
99215c272c feat(share-theme): set minimum width for table cells to improve readability 2026-01-30 01:15:14 -08:00
perfectra1n
51325e2f4a fix(editor): resolve strange stuck indent when a Note has images 2026-01-26 17:03:42 -08:00
Jin
bd7e47d8f0 refactor: clear calendar code 2026-01-19 21:15:18 +00:00
Jin
457a7a03fb test: add test for week notes utils 2026-01-19 21:01:07 +00:00
Jin
6e486c64f1 fix: move calendar to use common week note utils 2026-01-19 20:59:15 +00:00
Jin
4f3575d765 fix: move date_notes to use common week note utils 2026-01-19 20:56:52 +00:00
Jin
f5f1b27754 fix: add common week note utils 2026-01-19 20:56:12 +00:00
511 changed files with 12665 additions and 43356 deletions

View File

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

View File

@@ -85,6 +85,7 @@ runs:
APPLE_ID: ${{ env.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ env.APPLE_ID_PASSWORD }}
WINDOWS_SIGN_EXECUTABLE: ${{ env.WINDOWS_SIGN_EXECUTABLE }}
WINDOWS_SIGN_ERROR_LOG: ${{ env.WINDOWS_SIGN_ERROR_LOG }}
TRILIUM_ARTIFACT_NAME_HINT: TriliumNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}
TARGET_ARCH: ${{ inputs.arch }}
run: pnpm run --filter desktop electron-forge:make --arch=${{ inputs.arch }} --platform=${{ inputs.forge_platform }}

View File

@@ -37,8 +37,14 @@ jobs:
- name: Typecheck
run: pnpm typecheck
- name: Run the unit tests
run: pnpm run test:all
- name: Run the client-side tests
run: pnpm run --filter=client test
- name: Run the server-side tests
run: pnpm run --filter=server test
- name: Run the rest of the tests
run: pnpm run --filter=\!client --filter=\!server test"
build_docker:
name: Build Docker image

View File

@@ -86,12 +86,12 @@ jobs:
- name: Upload Playwright trace
if: failure()
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: Playwright trace (${{ matrix.dockerfile }})
path: test-output/playwright/output
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
if: ${{ !cancelled() }}
with:
name: Playwright report (${{ matrix.dockerfile }})
@@ -166,9 +166,7 @@ jobs:
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}
images: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
@@ -189,13 +187,6 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to DockerHub
uses: docker/login-action@v3
with:
registry: ${{ env.DOCKERHUB_REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
@@ -213,7 +204,7 @@ jobs:
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: digests-${{ env.PLATFORM_PAIR }}-${{ matrix.dockerfile }}
path: /tmp/digests/*
@@ -227,7 +218,7 @@ jobs:
- build
steps:
- name: Download digests
uses: actions/download-artifact@v7
uses: actions/download-artifact@v8
with:
path: /tmp/digests
pattern: digests-*
@@ -237,18 +228,8 @@ jobs:
- name: Set TEST_TAG to lowercase
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: |
latest=false
- name: Set up crane
uses: imjasonh/setup-crane@v0.4
- name: Login to GHCR
uses: docker/login-action@v3
@@ -264,48 +245,69 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Create manifest list and push
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha
flavor: |
latest=false
- name: Verify digests exist on GHCR
working-directory: /tmp/digests
run: |
# Extract the branch or tag name from the ref
REF_NAME=$(echo "${GITHUB_REF}" | sed 's/refs\/heads\///' | sed 's/refs\/tags\///')
echo "Verifying all digests are available on GHCR..."
for DIGEST_FILE in *; do
DIGEST="sha256:${DIGEST_FILE}"
echo -n " ${DIGEST}: "
crane manifest "${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@${DIGEST}" > /dev/null
echo "OK"
done
# Create and push the manifest list with both the branch/tag name and the commit SHA
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME} \
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
- name: Create and push multi-arch manifest
working-directory: /tmp/digests
run: |
GHCR_IMAGE="${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}"
DOCKERHUB_IMAGE="${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}"
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME} \
$(printf '${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
# Build -m flags for crane index append from digest files
MANIFEST_ARGS=""
for d in *; do
MANIFEST_ARGS="${MANIFEST_ARGS} -m ${GHCR_IMAGE}@sha256:${d}"
done
# If the ref is a tag, also tag the image as stable as this is part of a 'release'
# and only go in the `if` if there is NOT a `-` in the tag's name, due to tagging of `-alpha`, `-beta`, etc...
# Create multi-arch manifest for each tag from metadata, plus copy to DockerHub
while IFS= read -r TAG; do
echo "Creating manifest: ${TAG}"
crane index append ${MANIFEST_ARGS} -t "${TAG}"
SUFFIX="${TAG#*:}"
echo "Copying to DockerHub: ${DOCKERHUB_IMAGE}:${SUFFIX}"
crane copy "${TAG}" "${DOCKERHUB_IMAGE}:${SUFFIX}"
done <<< "${{ steps.meta.outputs.tags }}"
# For stable releases (tags without hyphens), also create stable + latest
REF_NAME="${GITHUB_REF#refs/tags/}"
if [[ "${GITHUB_REF}" == refs/tags/* && ! "${REF_NAME}" =~ - ]]; then
# First create stable tags
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:stable \
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:stable \
$(printf '${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
# Small delay to ensure stable tag is fully propagated
sleep 5
# Now update latest tags
docker buildx imagetools create \
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:stable
docker buildx imagetools create \
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:stable
echo "Creating stable tags..."
crane index append ${MANIFEST_ARGS} -t "${GHCR_IMAGE}:stable"
crane copy "${GHCR_IMAGE}:stable" "${DOCKERHUB_IMAGE}:stable"
echo "Creating latest tags..."
crane copy "${GHCR_IMAGE}:stable" "${GHCR_IMAGE}:latest"
crane copy "${GHCR_IMAGE}:latest" "${DOCKERHUB_IMAGE}:latest"
fi
- name: Inspect image
- name: Inspect manifests
run: |
docker buildx imagetools inspect ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
docker buildx imagetools inspect ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
REF_NAME="${GITHUB_REF#refs/heads/}"
REF_NAME="${REF_NAME#refs/tags/}"
echo "=== GHCR ==="
crane manifest "${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME}"
echo ""
echo "=== DockerHub ==="
crane manifest "${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME}"

View File

@@ -87,6 +87,7 @@ jobs:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
WINDOWS_SIGN_EXECUTABLE: ${{ vars.WINDOWS_SIGN_EXECUTABLE }}
WINDOWS_SIGN_ERROR_LOG: ${{ vars.WINDOWS_SIGN_ERROR_LOG }}
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
- name: Publish release
@@ -102,7 +103,7 @@ jobs:
name: Nightly Build
- name: Publish artifacts
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
if: ${{ github.event_name == 'pull_request' }}
with:
name: TriliumNotes ${{ matrix.os.name }} ${{ matrix.arch }}

View File

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

View File

@@ -17,10 +17,22 @@ jobs:
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v6
with:
node-version: 24
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --filter source --frozen-lockfile --ignore-scripts
- name: Check version consistency
run: pnpm tsx ${{ github.workspace }}/scripts/check-version-consistency.ts ${{ github.ref_name }}
make-electron:
name: Make Electron
needs:
- sanity-check
strategy:
fail-fast: false
matrix:
@@ -78,16 +90,19 @@ jobs:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
WINDOWS_SIGN_EXECUTABLE: ${{ vars.WINDOWS_SIGN_EXECUTABLE }}
WINDOWS_SIGN_ERROR_LOG: ${{ vars.WINDOWS_SIGN_ERROR_LOG }}
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
- name: Upload the artifact
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: release-desktop-${{ matrix.os.name }}-${{ matrix.arch }}
path: apps/desktop/upload/*.*
build_server:
name: Build Linux Server
needs:
- sanity-check
strategy:
fail-fast: false
matrix:
@@ -108,7 +123,7 @@ jobs:
arch: ${{ matrix.arch }}
- name: Upload the artifact
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: release-server-linux-${{ matrix.arch }}
path: upload/*.*
@@ -128,7 +143,7 @@ jobs:
docs/Release Notes
- name: Download all artifacts
uses: actions/download-artifact@v7
uses: actions/download-artifact@v8
with:
merge-multiple: true
pattern: release-*

View File

@@ -48,7 +48,7 @@ jobs:
pnpm --filter web-clipper zip:firefox
- name: Upload build artifacts
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
if: ${{ !startsWith(github.ref, 'refs/tags/web-clipper-v') }}
with:
name: web-clipper-extension

2
.nvmrc
View File

@@ -1 +1 @@
24.13.1
24.14.0

57
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,57 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch client (Chrome)",
"request": "launch",
"type": "chrome",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}/apps/client"
},
{
"name": "Launch server",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/apps/server/src/main.ts",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/tsx",
"env": {
"NODE_ENV": "development",
"TRILIUM_ENV": "dev",
"TRILIUM_DATA_DIR": "${input:trilium_data_dir}",
"TRILIUM_RESOURCE_DIR": "${workspaceFolder}/apps/server/src"
},
"autoAttachChildProcesses": true,
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": ["<node_internals>/**", "${workspaceFolder}/node_modules/**"]
},
{
"name": "Launch Vitest with current test file",
"type": "node",
"request": "launch",
"autoAttachChildProcesses": true,
"program": "${workspaceFolder}/node_modules/vitest/vitest.mjs",
"args": ["run", "${relativeFile}"],
"smartStep": true,
"console": "integratedTerminal",
"skipFiles": ["<node_internals>/**", "**/node_modules/**"],
"cwd": "${workspaceFolder}"
}
],
"compounds": [
{
"name": "Launch client (Chrome) and server",
"configurations": ["Launch server","Launch client (Chrome)"],
"stopAll": true
}
],
"inputs": [
{
"id": "trilium_data_dir",
"type": "promptString",
"description": "Select Trilum Notes data directory",
"default": "${workspaceFolder}/apps/server/data"
}
]
}

View File

@@ -10,4 +10,5 @@ Description above is a general rule and may be altered on case by case basis.
## Reporting a Vulnerability
You can report low severity vulnerabilities as GitHub issues, more severe vulnerabilities should be reported to the email [contact@eliandoran.me](mailto:contact@eliandoran.me)
* For low severity vulnerabilities, they can be reported as GitHub issues.
* For severe vulnerabilities, please report it using [GitHub Security Advisories](https://github.com/TriliumNext/Trilium/security/advisories).

View File

@@ -1,19 +1,25 @@
{
"name": "build-docs",
"version": "1.0.0",
"description": "",
"description": "Build documentation from Trilium notes",
"main": "src/main.ts",
"bin": {
"trilium-build-docs": "dist/cli.js"
},
"scripts": {
"start": "tsx ."
"start": "tsx .",
"cli": "tsx src/cli.ts",
"build": "tsx scripts/build.ts"
},
"keywords": [],
"author": "Elian Doran <contact@eliandoran.me>",
"license": "AGPL-3.0-only",
"packageManager": "pnpm@10.30.0",
"packageManager": "pnpm@10.30.3",
"devDependencies": {
"@redocly/cli": "2.19.1",
"@redocly/cli": "2.20.2",
"archiver": "7.0.1",
"fs-extra": "11.3.3",
"fs-extra": "11.3.4",
"js-yaml": "4.1.1",
"react": "19.2.4",
"react-dom": "19.2.4",
"typedoc": "0.28.17",

View File

@@ -0,0 +1,23 @@
import BuildHelper from "../../../scripts/build-utils";
const build = new BuildHelper("apps/build-docs");
async function main() {
// Build the CLI and other TypeScript files
await build.buildBackend([
"src/cli.ts",
"src/main.ts",
"src/build-docs.ts",
"src/swagger.ts",
"src/script-api.ts",
"src/context.ts"
]);
// Copy HTML template
build.copy("src/index.html", "index.html");
// Copy node modules dependencies if needed
build.copyNodeModules([ "better-sqlite3", "bindings", "file-uri-to-path" ]);
}
main();

View File

@@ -13,8 +13,12 @@
* Make sure to keep in line with backend's `script_context.ts`.
*/
export type { default as AbstractBeccaEntity } from "../../server/src/becca/entities/abstract_becca_entity.js";
export type { default as BAttachment } from "../../server/src/becca/entities/battachment.js";
export type {
default as AbstractBeccaEntity
} from "../../server/src/becca/entities/abstract_becca_entity.js";
export type {
default as BAttachment
} from "../../server/src/becca/entities/battachment.js";
export type { default as BAttribute } from "../../server/src/becca/entities/battribute.js";
export type { default as BBranch } from "../../server/src/becca/entities/bbranch.js";
export type { default as BEtapiToken } from "../../server/src/becca/entities/betapi_token.js";
@@ -31,6 +35,7 @@ export type { Api };
const fakeNote = new BNote();
/**
* The `api` global variable allows access to the backend script API, which is documented in {@link Api}.
* The `api` global variable allows access to the backend script API,
* which is documented in {@link Api}.
*/
export const api: Api = new BackendScriptApi(fakeNote, {});

View File

@@ -1,19 +1,90 @@
process.env.TRILIUM_INTEGRATION_TEST = "memory-no-store";
process.env.TRILIUM_RESOURCE_DIR = "../server/src";
// Only set TRILIUM_RESOURCE_DIR if not already set (e.g., by Nix wrapper)
if (!process.env.TRILIUM_RESOURCE_DIR) {
process.env.TRILIUM_RESOURCE_DIR = "../server/src";
}
process.env.NODE_ENV = "development";
import cls from "@triliumnext/server/src/services/cls.js";
import { dirname, join, resolve } from "path";
import archiver from "archiver";
import { execSync } from "child_process";
import { WriteStream } from "fs";
import * as fs from "fs/promises";
import * as fsExtra from "fs-extra";
import archiver from "archiver";
import { WriteStream } from "fs";
import { execSync } from "child_process";
import yaml from "js-yaml";
import { dirname, join, resolve } from "path";
import BuildContext from "./context.js";
interface NoteMapping {
rootNoteId: string;
path: string;
format: "markdown" | "html" | "share";
ignoredFiles?: string[];
exportOnly?: boolean;
}
interface Config {
baseUrl: string;
noteMappings: NoteMapping[];
}
const DOCS_ROOT = "../../../docs";
const OUTPUT_DIR = "../../site";
// Load configuration from edit-docs-config.yaml
async function loadConfig(configPath?: string): Promise<Config | null> {
const pathsToTry = configPath
? [resolve(configPath)]
: [
join(process.cwd(), "edit-docs-config.yaml"),
join(__dirname, "../../../edit-docs-config.yaml")
];
for (const path of pathsToTry) {
try {
const configContent = await fs.readFile(path, "utf-8");
const config = yaml.load(configContent) as Config;
// Resolve all paths relative to the config file's directory
const CONFIG_DIR = dirname(path);
config.noteMappings = config.noteMappings.map((mapping) => ({
...mapping,
path: resolve(CONFIG_DIR, mapping.path)
}));
return config;
} catch (error) {
if (error.code !== "ENOENT") {
throw error; // rethrow unexpected errors
}
}
}
return null; // No config file found
}
async function exportDocs(
noteId: string,
format: "markdown" | "html" | "share",
outputPath: string,
ignoredFiles?: string[]
) {
const zipFilePath = `output-${noteId}.zip`;
try {
const { exportToZipFile } = (await import("@triliumnext/server/src/services/export/zip.js"))
.default;
await exportToZipFile(noteId, format, zipFilePath, {});
const ignoredSet = ignoredFiles ? new Set(ignoredFiles) : undefined;
await extractZip(zipFilePath, outputPath, ignoredSet);
} finally {
if (await fsExtra.exists(zipFilePath)) {
await fsExtra.rm(zipFilePath);
}
}
}
async function importAndExportDocs(sourcePath: string, outputSubDir: string) {
const note = await importData(sourcePath);
@@ -21,15 +92,18 @@ async function importAndExportDocs(sourcePath: string, outputSubDir: string) {
const zipName = outputSubDir || "user-guide";
const zipFilePath = `output-${zipName}.zip`;
try {
const { exportToZip } = (await import("@triliumnext/server/src/services/export/zip.js")).default;
const { exportToZip } = (await import("@triliumnext/server/src/services/export/zip.js"))
.default;
const branch = note.getParentBranches()[0];
const taskContext = new (await import("@triliumnext/server/src/services/task_context.js")).default(
"no-progress-reporting",
"export",
null
);
const taskContext = new (await import("@triliumnext/server/src/services/task_context.js"))
.default(
"no-progress-reporting",
"export",
null
);
const fileOutputStream = fsExtra.createWriteStream(zipFilePath);
await exportToZip(taskContext, branch, "share", fileOutputStream);
const { waitForStreamToFinish } = await import("@triliumnext/server/src/services/utils.js");
await waitForStreamToFinish(fileOutputStream);
// Output to root directory if outputSubDir is empty, otherwise to subdirectory
@@ -42,7 +116,7 @@ async function importAndExportDocs(sourcePath: string, outputSubDir: string) {
}
}
async function buildDocsInner() {
async function buildDocsInner(config?: Config) {
const i18n = await import("@triliumnext/server/src/services/i18n.js");
await i18n.initializeTranslations();
@@ -53,18 +127,49 @@ async function buildDocsInner() {
const beccaLoader = await import("../../server/src/becca/becca_loader.js");
await beccaLoader.beccaLoaded;
// Build User Guide
console.log("Building User Guide...");
await importAndExportDocs(join(__dirname, DOCS_ROOT, "User Guide"), "user-guide");
if (config) {
// Config-based build (reads from edit-docs-config.yaml)
console.log("Building documentation from config file...");
// Build Developer Guide
console.log("Building Developer Guide...");
await importAndExportDocs(join(__dirname, DOCS_ROOT, "Developer Guide"), "developer-guide");
// Import all non-export-only mappings
for (const mapping of config.noteMappings) {
if (!mapping.exportOnly) {
console.log(`Importing from ${mapping.path}...`);
await importData(mapping.path);
}
}
// Copy favicon.
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "favicon.ico"));
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "user-guide", "favicon.ico"));
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "developer-guide", "favicon.ico"));
// Export all mappings
for (const mapping of config.noteMappings) {
if (mapping.exportOnly) {
console.log(`Exporting ${mapping.format} to ${mapping.path}...`);
await exportDocs(
mapping.rootNoteId,
mapping.format,
mapping.path,
mapping.ignoredFiles
);
}
}
} else {
// Legacy hardcoded build (for backward compatibility)
console.log("Building User Guide...");
await importAndExportDocs(join(__dirname, DOCS_ROOT, "User Guide"), "user-guide");
console.log("Building Developer Guide...");
await importAndExportDocs(
join(__dirname, DOCS_ROOT, "Developer Guide"),
"developer-guide"
);
// Copy favicon.
await fs.copyFile("../../apps/website/src/assets/favicon.ico",
join(OUTPUT_DIR, "favicon.ico"));
await fs.copyFile("../../apps/website/src/assets/favicon.ico",
join(OUTPUT_DIR, "user-guide", "favicon.ico"));
await fs.copyFile("../../apps/website/src/assets/favicon.ico",
join(OUTPUT_DIR, "developer-guide", "favicon.ico"));
}
console.log("Documentation built successfully!");
}
@@ -91,12 +196,13 @@ async function createImportZip(path: string) {
zlib: { level: 0 }
});
console.log("Archive path is ", resolve(path))
console.log("Archive path is ", resolve(path));
archive.directory(path, "/");
const outputStream = fsExtra.createWriteStream(inputFile);
archive.pipe(outputStream);
archive.finalize();
const { waitForStreamToFinish } = await import("@triliumnext/server/src/services/utils.js");
await waitForStreamToFinish(outputStream);
try {
@@ -106,15 +212,15 @@ async function createImportZip(path: string) {
}
}
function waitForStreamToFinish(stream: WriteStream) {
return new Promise<void>((res, rej) => {
stream.on("finish", () => res());
stream.on("error", (err) => rej(err));
});
}
export async function extractZip(zipFilePath: string, outputPath: string, ignoredFiles?: Set<string>) {
const { readZipFile, readContent } = (await import("@triliumnext/server/src/services/import/zip.js"));
export async function extractZip(
zipFilePath: string,
outputPath: string,
ignoredFiles?: Set<string>
) {
const { readZipFile, readContent } = (await import(
"@triliumnext/server/src/services/import/zip.js"
));
await readZipFile(await fs.readFile(zipFilePath), async (zip, entry) => {
// We ignore directories since they can appear out of order anyway.
if (!entry.fileName.endsWith("/") && !ignoredFiles?.has(entry.fileName)) {
@@ -129,6 +235,27 @@ export async function extractZip(zipFilePath: string, outputPath: string, ignore
});
}
export async function buildDocsFromConfig(configPath?: string, gitRootDir?: string) {
const config = await loadConfig(configPath);
if (gitRootDir) {
// Build the share theme if we have a gitRootDir (for Trilium project)
execSync(`pnpm run --filter share-theme build`, {
stdio: "inherit",
cwd: gitRootDir
});
}
// Trigger the actual build.
await new Promise((res, rej) => {
cls.init(() => {
buildDocsInner(config ?? undefined)
.catch(rej)
.then(res);
});
});
}
export default async function buildDocs({ gitRootDir }: BuildContext) {
// Build the share theme.
execSync(`pnpm run --filter share-theme build`, {

View File

@@ -0,0 +1,89 @@
#!/usr/bin/env node
import packageJson from "../package.json" with { type: "json" };
import { buildDocsFromConfig } from "./build-docs.js";
// Parse command-line arguments
function parseArgs() {
const args = process.argv.slice(2);
let configPath: string | undefined;
let showHelp = false;
let showVersion = false;
for (let i = 0; i < args.length; i++) {
if (args[i] === "--config" || args[i] === "-c") {
configPath = args[i + 1];
if (!configPath) {
console.error("Error: --config/-c requires a path argument");
process.exit(1);
}
i++; // Skip the next argument as it's the value
} else if (args[i] === "--help" || args[i] === "-h") {
showHelp = true;
} else if (args[i] === "--version" || args[i] === "-v") {
showVersion = true;
}
}
return { configPath, showHelp, showVersion };
}
function getVersion(): string {
return packageJson.version;
}
function printHelp() {
const version = getVersion();
console.log(`
Usage: trilium-build-docs [options]
Options:
-c, --config <path> Path to the configuration file
(default: edit-docs-config.yaml in current directory)
-h, --help Display this help message
-v, --version Display version information
Description:
Builds documentation from Trilium note structure and exports to various formats.
Configuration file should be in YAML format with the following structure:
baseUrl: "https://example.com"
noteMappings:
- rootNoteId: "noteId123"
path: "docs"
format: "markdown"
- rootNoteId: "noteId456"
path: "public/docs"
format: "share"
exportOnly: true
Version: ${version}
`);
}
function printVersion() {
const version = getVersion();
console.log(version);
}
async function main() {
const { configPath, showHelp, showVersion } = parseArgs();
if (showHelp) {
printHelp();
process.exit(0);
} else if (showVersion) {
printVersion();
process.exit(0);
}
try {
await buildDocsFromConfig(configPath);
process.exit(0);
} catch (error) {
console.error("Error building documentation:", error);
process.exit(1);
}
}
main();

View File

@@ -13,16 +13,19 @@
* Make sure to keep in line with frontend's `script_context.ts`.
*/
export type { default as BasicWidget } from "../../client/src/widgets/basic_widget.js";
export type { default as FAttachment } from "../../client/src/entities/fattachment.js";
export type { default as FAttribute } from "../../client/src/entities/fattribute.js";
export type { default as FBranch } from "../../client/src/entities/fbranch.js";
export type { default as FNote } from "../../client/src/entities/fnote.js";
export type { Api } from "../../client/src/services/frontend_script_api.js";
export type { default as NoteContextAwareWidget } from "../../client/src/widgets/note_context_aware_widget.js";
export type { default as BasicWidget } from "../../client/src/widgets/basic_widget.js";
export type {
default as NoteContextAwareWidget
} from "../../client/src/widgets/note_context_aware_widget.js";
export type { default as RightPanelWidget } from "../../client/src/widgets/right_panel_widget.js";
import FrontendScriptApi, { type Api } from "../../client/src/services/frontend_script_api.js";
//@ts-expect-error
// @ts-expect-error - FrontendScriptApi is not directly exportable as Api without this simulation.
export const api: Api = new FrontendScriptApi();

View File

@@ -1,9 +1,10 @@
import { join } from "path";
import BuildContext from "./context";
import buildSwagger from "./swagger";
import { cpSync, existsSync, mkdirSync, rmSync } from "fs";
import { join } from "path";
import buildDocs from "./build-docs";
import BuildContext from "./context";
import buildScriptApi from "./script-api";
import buildSwagger from "./swagger";
const context: BuildContext = {
gitRootDir: join(__dirname, "../../../"),

View File

@@ -1,7 +1,8 @@
import { execSync } from "child_process";
import BuildContext from "./context";
import { join } from "path";
import BuildContext from "./context";
export default function buildScriptApi({ baseDir, gitRootDir }: BuildContext) {
// Generate types
execSync(`pnpm typecheck`, { stdio: "inherit", cwd: gitRootDir });

View File

@@ -1,7 +1,8 @@
import BuildContext from "./context";
import { join } from "path";
import { execSync } from "child_process";
import { mkdirSync } from "fs";
import { join } from "path";
import BuildContext from "./context";
interface BuildInfo {
specPath: string;
@@ -27,6 +28,9 @@ export default function buildSwagger({ baseDir, gitRootDir }: BuildContext) {
const absSpecPath = join(gitRootDir, specPath);
const targetDir = join(baseDir, outDir);
mkdirSync(targetDir, { recursive: true });
execSync(`pnpm redocly build-docs ${absSpecPath} -o ${targetDir}/index.html`, { stdio: "inherit" });
execSync(
`pnpm redocly build-docs ${absSpecPath} -o ${targetDir}/index.html`,
{ stdio: "inherit" }
);
}
}

View File

@@ -1,6 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"include": [],
"include": [
"scripts/**/*.ts"
],
"references": [
{
"path": "../server"

View File

@@ -4,6 +4,7 @@
"entryPoints": [
"src/backend_script_entrypoint.ts"
],
"tsconfig": "tsconfig.app.json",
"plugin": [
"typedoc-plugin-missing-exports"
]

View File

@@ -4,6 +4,7 @@
"entryPoints": [
"src/frontend_script_entrypoint.ts"
],
"tsconfig": "tsconfig.app.json",
"plugin": [
"typedoc-plugin-missing-exports"
]

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/client",
"version": "0.101.3",
"version": "0.102.0",
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
"private": true,
"license": "AGPL-3.0-only",
@@ -22,6 +22,7 @@
"@fullcalendar/interaction": "6.1.20",
"@fullcalendar/list": "6.1.20",
"@fullcalendar/multimonth": "6.1.20",
"@fullcalendar/rrule": "6.1.20",
"@fullcalendar/timegrid": "6.1.20",
"@maplibre/maplibre-gl-leaflet": "0.1.3",
"@mermaid-js/layout-elk": "0.2.0",
@@ -34,6 +35,8 @@
"@triliumnext/highlightjs": "workspace:*",
"@triliumnext/share-theme": "workspace:*",
"@triliumnext/split.js": "workspace:*",
"@univerjs/preset-sheets-core": "0.16.1",
"@univerjs/presets": "0.16.1",
"@zumer/snapdom": "2.0.2",
"autocomplete.js": "0.38.1",
"bootstrap": "5.3.8",
@@ -43,26 +46,27 @@
"debounce": "3.0.0",
"draggabilly": "3.0.0",
"force-graph": "1.51.1",
"globals": "17.3.0",
"i18next": "25.8.11",
"globals": "17.4.0",
"i18next": "25.8.13",
"i18next-http-backend": "3.0.2",
"jquery": "4.0.0",
"jquery.fancytree": "2.38.5",
"jsplumb": "2.15.6",
"katex": "0.16.28",
"katex": "0.16.33",
"knockout": "3.5.1",
"leaflet": "1.9.4",
"leaflet-gpx": "2.2.0",
"mark.js": "8.11.1",
"marked": "17.0.3",
"mermaid": "11.12.3",
"mind-elixir": "5.8.3",
"mind-elixir": "5.9.1",
"normalize.css": "8.0.1",
"panzoom": "9.4.3",
"preact": "10.28.3",
"preact": "10.28.4",
"react-i18next": "16.5.4",
"react-window": "2.2.7",
"reveal.js": "5.2.1",
"rrule": "2.8.1",
"svg-pan-zoom": "3.6.2",
"tabulator-tables": "6.3.1",
"vanilla-js-wheel-zoom": "9.0.4"
@@ -71,14 +75,14 @@
"@ckeditor/ckeditor5-inspector": "5.0.0",
"@prefresh/vite": "2.4.12",
"@types/bootstrap": "5.2.10",
"@types/jquery": "3.5.33",
"@types/jquery": "4.0.0",
"@types/leaflet": "1.9.21",
"@types/leaflet-gpx": "1.3.8",
"@types/mark.js": "8.11.12",
"@types/reveal.js": "5.2.2",
"@types/tabulator-tables": "6.3.1",
"copy-webpack-plugin": "13.0.1",
"happy-dom": "20.6.3",
"copy-webpack-plugin": "14.0.0",
"happy-dom": "20.8.3",
"lightningcss": "1.31.1",
"script-loader": "0.7.2",
"vite-plugin-static-copy": "3.2.0"

View File

@@ -101,8 +101,6 @@ export type CommandMappings = {
showRevisions: CommandData & {
noteId?: string | null;
};
showLlmChat: CommandData;
createAiChat: CommandData;
showOptions: CommandData & {
section: string;
};

View File

@@ -1,10 +1,8 @@
import dateNoteService from "../services/date_notes.js";
import froca from "../services/froca.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";
@@ -248,34 +246,4 @@ export default class RootCommandExecutor extends Component {
}
}
async createAiChatCommand() {
try {
// Create a new AI Chat note at the root level
const rootNoteId = "root";
const result = await noteCreateService.createNote(rootNoteId, {
title: "New AI Chat",
type: "aiChat",
content: JSON.stringify({
messages: [],
title: "New AI Chat"
})
});
if (!result.note) {
toastService.showError("Failed to create AI Chat note");
return;
}
await appContext.tabManager.openTabWithNoteWithHoisting(result.note.noteId, {
activate: true
});
toastService.showMessage("Created new AI Chat note");
}
catch (e) {
console.error("Error creating AI Chat note:", e);
toastService.showError(`Failed to create AI Chat note: ${(e as Error).message}`);
}
}
}

View File

@@ -18,7 +18,7 @@ const RELATION = "relation";
* end user. Those types should be used only for checking against, they are
* not for direct use.
*/
export type NoteType = "file" | "image" | "search" | "noteMap" | "launcher" | "doc" | "contentWidget" | "text" | "relationMap" | "render" | "canvas" | "mermaid" | "book" | "webView" | "code" | "mindMap" | "aiChat";
export type NoteType = "file" | "image" | "search" | "noteMap" | "launcher" | "doc" | "contentWidget" | "text" | "relationMap" | "render" | "canvas" | "mermaid" | "book" | "webView" | "code" | "mindMap" | "spreadsheet";
export interface NotePathRecord {
isArchived: boolean;

View File

@@ -3,54 +3,29 @@ 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 ClosePaneButton from "../widgets/buttons/close_pane_button.js";
import CreatePaneButton from "../widgets/buttons/create_pane_button.js";
import GlobalMenu from "../widgets/buttons/global_menu.jsx";
import LeftPaneToggle from "../widgets/buttons/left_pane_toggle.js";
import MovePaneButton from "../widgets/buttons/move_pane_button.js";
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 ContentHeader from "../widgets/containers/content_header.js";
import FlexContainer from "../widgets/containers/flex_container.js";
import LeftPaneContainer from "../widgets/containers/left_pane_container.js";
import RightPaneContainer from "../widgets/containers/right_pane_container.js";
import RootContainer from "../widgets/containers/root_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 NoteWrapperWidget from "../widgets/NoteWrapper.js";
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 SearchResult from "../widgets/search_result.jsx";
import SharedInfo from "../widgets/shared_info.jsx";
import RightPanelContainer from "../widgets/sidebar/RightPanelContainer.jsx";
import TabRowWidget from "../widgets/tab_row.js";
import TabHistoryNavigationButtons from "../widgets/TabHistoryNavigationButtons.jsx";
import TitleBarButtons from "../widgets/title_bar_buttons.jsx";
import TocWidget from "../widgets/toc.js";
import WatchedFileUpdateStatusWidget from "../widgets/watched_file_update_status.js";
import { applyModals } from "./layout_commons.js";
export default class DesktopLayout {
@@ -133,44 +108,7 @@ export default class DesktopLayout {
.filling()
.collapsible()
.id("center-pane")
.child(
new SplitNoteContainer(() =>
new NoteWrapperWidget()
.child(new FlexContainer("row")
.class("title-row note-split-title")
.cssBlock(".title-row > * { margin: 5px; }")
.child(<NoteIconWidget />)
.child(<NoteTitleWidget />)
.optChild(isNewLayout, <NoteBadges />)
.child(<SpacerWidget baseSize={0} growthFactor={1} />)
.optChild(!isNewLayout, <MovePaneButton direction="left" />)
.optChild(!isNewLayout, <MovePaneButton direction="right" />)
.optChild(!isNewLayout, <ClosePaneButton />)
.optChild(!isNewLayout, <CreatePaneButton />)
.optChild(isNewLayout, <NoteActions />))
.optChild(!isNewLayout, <Ribbon />)
.child(new WatchedFileUpdateStatusWidget())
.optChild(!isNewLayout, <FloatingButtons items={DESKTOP_FLOATING_BUTTONS} />)
.child(
new ScrollingContainer()
.filling()
.optChild(isNewLayout, <InlineTitle />)
.optChild(isNewLayout, <NoteTitleActions />)
.optChild(!isNewLayout, new ContentHeader()
.child(<ReadOnlyNoteInfoBar />)
.child(<SharedInfo />)
)
.optChild(!isNewLayout, <PromotedAttributes />)
.child(<NoteDetail />)
.child(<NoteList media="screen" />)
.child(<SearchResult />)
.child(<ScrollPadding />)
)
.child(<ApiLog />)
.child(new FindWidget())
.child(...this.customWidgets.get("note-detail-pane"))
)
)
.child(new SplitNoteContainer(() => <NoteWrapperWidget />))
.child(...this.customWidgets.get("center-pane"))
)

View File

@@ -3,29 +3,15 @@ import "./mobile_layout.css";
import type AppContext from "../components/app_context.js";
import GlobalMenuWidget from "../widgets/buttons/global_menu.js";
import CloseZenModeButton from "../widgets/close_zen_button.js";
import NoteList from "../widgets/collections/NoteList.jsx";
import FlexContainer from "../widgets/containers/flex_container.js";
import RootContainer from "../widgets/containers/root_container.js";
import ScrollingContainer from "../widgets/containers/scrolling_container.js";
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
import FindWidget from "../widgets/find.js";
import LauncherContainer from "../widgets/launch_bar/LauncherContainer.jsx";
import InlineTitle from "../widgets/layout/InlineTitle.jsx";
import NoteBadges from "../widgets/layout/NoteBadges.jsx";
import NoteTitleActions from "../widgets/layout/NoteTitleActions.jsx";
import MobileDetailMenu from "../widgets/mobile_widgets/mobile_detail_menu.js";
import ScreenContainer from "../widgets/mobile_widgets/screen_container.js";
import SidebarContainer from "../widgets/mobile_widgets/sidebar_container.js";
import ToggleSidebarButton from "../widgets/mobile_widgets/toggle_sidebar_button.jsx";
import NoteIconWidget from "../widgets/note_icon.jsx";
import NoteTitleWidget from "../widgets/note_title.js";
import NoteTreeWidget from "../widgets/note_tree.js";
import NoteWrapperWidget from "../widgets/note_wrapper.js";
import NoteDetail from "../widgets/NoteDetail.jsx";
import NoteWrapperWidget from "../widgets/NoteWrapper";
import QuickSearchWidget from "../widgets/quick_search.js";
import ScrollPadding from "../widgets/scroll_padding";
import SearchResult from "../widgets/search_result.jsx";
import MobileEditorToolbar from "../widgets/type_widgets/text/mobile_editor_toolbar.jsx";
import { applyModals } from "./layout_commons.js";
export default class MobileLayout {
@@ -52,35 +38,7 @@ export default class MobileLayout {
new ScreenContainer("detail", "row")
.id("detail-container")
.class("d-sm-flex d-md-flex d-lg-flex d-xl-flex col-12 col-sm-7 col-md-8 col-lg-9")
.child(
new SplitNoteContainer(() =>
new NoteWrapperWidget()
.child(
new FlexContainer("row")
.class("title-row note-split-title")
.contentSized()
.css("align-items", "center")
.child(<ToggleSidebarButton />)
.child(<NoteIconWidget />)
.child(<NoteTitleWidget />)
.child(<NoteBadges />)
.child(<MobileDetailMenu />)
)
.child(
new ScrollingContainer()
.filling()
.contentSized()
.child(<InlineTitle />)
.child(<NoteTitleActions />)
.child(<NoteDetail />)
.child(<NoteList media="screen" />)
.child(<SearchResult />)
.child(<ScrollPadding />)
)
.child(<MobileEditorToolbar />)
.child(new FindWidget())
)
)
.child(new SplitNoteContainer(() => <NoteWrapperWidget />))
)
)
.child(

View File

@@ -3,6 +3,8 @@ import options from "../services/options.js";
import zoomService from "../components/zoom.js";
import contextMenu, { type MenuItem } from "./context_menu.js";
import { t } from "../services/i18n.js";
import server from "../services/server.js";
import * as clipboardExt from "../services/clipboard_ext.js";
import type { BrowserWindow } from "electron";
import type { CommandNames, AppContext } from "../components/app_context.js";
@@ -60,6 +62,33 @@ function setupContextMenu() {
uiIcon: "bx bx-copy",
handler: () => webContents.copy()
});
items.push({
enabled: hasText,
title: t("electron_context_menu.copy-as-markdown"),
uiIcon: "bx bx-copy-alt",
handler: async () => {
const selection = window.getSelection();
if (!selection || !selection.rangeCount) return '';
const range = selection.getRangeAt(0);
const div = document.createElement('div');
div.appendChild(range.cloneContents());
const htmlContent = div.innerHTML;
if (htmlContent) {
try {
const { markdownContent } = await server.post<{ markdownContent: string }>(
"other/to-markdown",
{ htmlContent }
);
await clipboardExt.copyTextWithToast(markdownContent);
} catch (error) {
console.error("Failed to copy as markdown:", error);
}
}
}
});
}
if (!["", "javascript:", "about:blank#blocked"].includes(params.linkURL) && params.mediaType === "none") {

View File

@@ -1,6 +1,7 @@
import "./content_renderer.css";
import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons";
import { h, render } from "preact";
import WheelZoom from 'vanilla-js-wheel-zoom';
import FAttachment from "../entities/fattachment.js";
@@ -56,7 +57,7 @@ export async function getRenderedContent(this: {} | { ctx: string }, entity: FNo
} else if (["image", "canvas", "mindMap"].includes(type)) {
renderImage(entity, $renderedContent, options);
} else if (!options.tooltip && ["file", "pdf", "audio", "video"].includes(type)) {
renderFile(entity, type, $renderedContent);
await renderFile(entity, type, $renderedContent);
} else if (type === "mermaid") {
await renderMermaid(entity, $renderedContent);
} else if (type === "render" && entity instanceof FNote) {
@@ -179,7 +180,7 @@ function renderImage(entity: FNote | FAttachment, $renderedContent: JQuery<HTMLE
imageContextMenuService.setupContextMenu($img);
}
function renderFile(entity: FNote | FAttachment, type: string, $renderedContent: JQuery<HTMLElement>) {
async function renderFile(entity: FNote | FAttachment, type: string, $renderedContent: JQuery<HTMLElement>) {
let entityType, entityId;
if (entity instanceof FNote) {
@@ -192,13 +193,17 @@ function renderFile(entity: FNote | FAttachment, type: string, $renderedContent:
throw new Error(`Can't recognize entity type of '${entity}'`);
}
const $content = $('<div style="display: flex; flex-direction: column; height: 100%;">');
const $content = $('<div style="display: flex; flex-direction: column; height: 100%; justify-content: end;">');
if (type === "pdf") {
const $pdfPreview = $('<iframe class="pdf-preview" style="width: 100%; flex-grow: 100;"></iframe>');
$pdfPreview.attr("src", openService.getUrlForDownload(`pdfjs/web/viewer.html?file=../../api/${entityType}/${entityId}/open`));
const url = `../../api/${entityType}/${entityId}/open`;
const $viewer = $(`<div style="height: 100%">`);
const PdfViewer = (await import("../widgets/type_widgets/file/PdfViewer")).default;
render(h(PdfViewer, {pdfUrl: url, editable: false}), $viewer.get(0)!);
$content.append($viewer);
$content.append($pdfPreview);
} else if (type === "audio") {
const $audioPreview = $("<audio controls></audio>")
.attr("src", openService.getUrlForDownload(`api/${entityType}/${entityId}/open-partial`))

View File

@@ -120,7 +120,6 @@ async function renderChildrenList($renderedContent: JQuery<HTMLElement>, note: F
return;
}
$renderedContent.css("padding", "10px");
$renderedContent.addClass("text-with-ellipsis");
// just load the first 10 child notes

View File

@@ -1,4 +1,5 @@
import { dayjs } from "@triliumnext/commons";
import type { FNoteRow } from "../entities/fnote.js";
import froca from "./froca.js";
import server from "./server.js";
@@ -14,8 +15,13 @@ async function getTodayNote() {
return await getDayNote(dayjs().format("YYYY-MM-DD"));
}
async function getDayNote(date: string) {
const note = await server.get<FNoteRow>(`special-notes/days/${date}`, "date-note");
async function getDayNote(date: string, calendarRootId?: string) {
let url = `special-notes/days/${date}`;
if (calendarRootId) {
url += `?calendarRootId=${calendarRootId}`;
}
const note = await server.get<FNoteRow>(url, "date-note");
await ws.waitForMaxKnownEntityChangeId();

View File

@@ -24,7 +24,8 @@ export async function initLocale() {
backend: {
loadPath: `${window.glob.assetPath}/translations/{{lng}}/{{ns}}.json`
},
returnEmptyString: false
returnEmptyString: false,
showSupportNotice: false
});
await setDayjsLocale(locale);

View File

@@ -1,4 +1,5 @@
import { NoteType } from "@triliumnext/commons";
import FNote from "../entities/fnote";
import { ViewTypeOptions } from "../widgets/collections/interface";
@@ -18,7 +19,7 @@ export const byNoteType: Record<Exclude<NoteType, "book">, string | null> = {
search: null,
text: null,
webView: null,
aiChat: null
spreadsheet: null
};
export const byBookType: Record<ViewTypeOptions, string | null> = {
@@ -39,6 +40,6 @@ export function getHelpUrlForNote(note: FNote | null | undefined) {
} else if (note?.hasLabel("textSnippet")) {
return "pwc194wlRzcH";
} else if (note && note.type === "book") {
return byBookType[note.getAttributeValue("label", "viewType") as ViewTypeOptions ?? ""]
return byBookType[note.getAttributeValue("label", "viewType") as ViewTypeOptions ?? ""];
}
}

View File

@@ -1,20 +1,20 @@
import treeService from "./tree.js";
import linkService from "./link.js";
import froca from "./froca.js";
import utils from "./utils.js";
import attributeRenderer from "./attribute_renderer.js";
import contentRenderer from "./content_renderer.js";
import appContext from "../components/app_context.js";
import type FNote from "../entities/fnote.js";
import attributeRenderer from "./attribute_renderer.js";
import contentRenderer from "./content_renderer.js";
import froca from "./froca.js";
import { t } from "./i18n.js";
import linkService from "./link.js";
import treeService from "./tree.js";
import utils from "./utils.js";
// Track all elements that open tooltips
let openTooltipElements: JQuery<HTMLElement>[] = [];
let dismissTimer: ReturnType<typeof setTimeout>;
function setupGlobalTooltip() {
$(document).on("mouseenter", "a:not(.no-tooltip-preview)", mouseEnterHandler);
$(document).on("mouseenter", "[data-href]:not(.no-tooltip-preview)", mouseEnterHandler);
$(document).on("pointerenter", "a:not(.no-tooltip-preview)", mouseEnterHandler);
$(document).on("pointerenter", "[data-href]:not(.no-tooltip-preview)", mouseEnterHandler);
// close any note tooltip after click, this fixes the problem that sometimes tooltips remained on the screen
$(document).on("click", (e) => {
@@ -37,10 +37,12 @@ function dismissAllTooltips() {
}
function setupElementTooltip($el: JQuery<HTMLElement>) {
$el.on("mouseenter", mouseEnterHandler);
$el.on("pointerenter", mouseEnterHandler);
}
async function mouseEnterHandler(this: HTMLElement) {
async function mouseEnterHandler<T>(this: HTMLElement, e: JQuery.TriggeredEvent<T, undefined, T, T>) {
if (e.pointerType !== "mouse") return;
const $link = $(this);
if ($link.hasClass("no-tooltip-preview") || $link.hasClass("disabled")) {
@@ -91,7 +93,7 @@ async function mouseEnterHandler(this: HTMLElement) {
}
const html = `<div class="note-tooltip-content">${content}</div>`;
const tooltipClass = "tooltip-" + Math.floor(Math.random() * 999_999_999);
const tooltipClass = `tooltip-${ Math.floor(Math.random() * 999_999_999)}`;
// we need to check if we're still hovering over the element
// since the operation to get tooltip content was async, it is possible that
@@ -224,7 +226,7 @@ function renderFootnoteOrAnchor($link: JQuery<HTMLElement>, url: string) {
}
let footnoteContent = $targetContent.html();
footnoteContent = `<div class="ck-content">${footnoteContent}</div>`
footnoteContent = `<div class="ck-content">${footnoteContent}</div>`;
return footnoteContent || "";
}

View File

@@ -1,9 +1,9 @@
import { t } from "./i18n.js";
import froca from "./froca.js";
import server from "./server.js";
import type { MenuCommandItem, MenuItem, MenuItemBadge, MenuSeparatorItem } from "../menus/context_menu.js";
import type { NoteType } from "../entities/fnote.js";
import type { MenuCommandItem, MenuItem, MenuItemBadge, MenuSeparatorItem } from "../menus/context_menu.js";
import type { TreeCommandNames } from "../menus/tree_context_menu.js";
import froca from "./froca.js";
import { t } from "./i18n.js";
import server from "./server.js";
export interface NoteTypeMapping {
type: NoteType;
@@ -26,6 +26,7 @@ export const NOTE_TYPES: NoteTypeMapping[] = [
// The default note type (always the first item)
{ type: "text", mime: "text/html", title: t("note_types.text"), icon: "bx-note" },
{ type: "spreadsheet", mime: "application/json", title: t("note_types.spreadsheet"), icon: "bx-table", isBeta: true },
// Text notes group
{ type: "book", mime: "", title: t("note_types.book"), icon: "bx-book" },
@@ -53,7 +54,6 @@ export const NOTE_TYPES: NoteTypeMapping[] = [
{ type: "file", title: t("note_types.file"), reserved: true },
{ type: "image", title: t("note_types.image"), reserved: true },
{ type: "launcher", mime: "", title: t("note_types.launcher"), reserved: true },
{ type: "aiChat", mime: "application/json", title: t("note_types.ai-chat"), reserved: true }
];
/** The maximum age in days for a template to be marked with the "New" badge */
@@ -97,9 +97,9 @@ function getBlankNoteTypes(command?: TreeCommandNames): MenuItem<TreeCommandName
title: nt.title,
command,
type: nt.type,
uiIcon: "bx " + nt.icon,
uiIcon: `bx ${nt.icon}`,
badges: []
}
};
if (nt.isNew) {
menuItem.badges?.push(NEW_BADGE);
@@ -131,7 +131,7 @@ async function getUserTemplates(command?: TreeCommandNames) {
const item: MenuItem<TreeCommandNames> = {
title: templateNote.title,
uiIcon: templateNote.getIcon(),
command: command,
command,
type: templateNote.type,
templateNoteId: templateNote.noteId
};
@@ -160,7 +160,7 @@ async function getBuiltInTemplates(title: string | null, command: TreeCommandNam
const items: MenuItem<TreeCommandNames>[] = [];
if (title) {
items.push({
title: title,
title,
kind: "header"
});
} else {
@@ -176,7 +176,7 @@ async function getBuiltInTemplates(title: string | null, command: TreeCommandNam
const item: MenuItem<TreeCommandNames> = {
title: templateNote.title,
uiIcon: templateNote.getIcon(),
command: command,
command,
type: templateNote.type,
templateNoteId: templateNote.noteId
};
@@ -194,7 +194,7 @@ async function isNewTemplate(templateNoteId) {
if (rootCreationDate === undefined) {
// Retrieve the root note creation date
try {
let rootNoteInfo: any = await server.get("notes/root");
const rootNoteInfo: any = await server.get("notes/root");
if ("dateCreated" in rootNoteInfo) {
rootCreationDate = new Date(rootNoteInfo.dateCreated);
}
@@ -209,7 +209,7 @@ async function isNewTemplate(templateNoteId) {
if (creationDate === undefined) {
// The creation date isn't available in the cache, try to retrieve it from the server
try {
const noteInfo: any = await server.get("notes/" + templateNoteId);
const noteInfo: any = await server.get(`notes/${templateNoteId}`);
if ("dateCreated" in noteInfo) {
creationDate = new Date(noteInfo.dateCreated);
creationDateCache.set(templateNoteId, creationDate);
@@ -231,9 +231,8 @@ async function isNewTemplate(templateNoteId) {
const age = (new Date().getTime() - creationDate.getTime()) / DAY_LENGTH;
// Return true if the template is at most NEW_TEMPLATE_MAX_AGE days old
return (age <= NEW_TEMPLATE_MAX_AGE);
} else {
return false;
}
return false;
}
export default {

View File

@@ -12,6 +12,7 @@ export default class SpacedUpdate {
private updateInterval: number;
private changeForbidden?: boolean;
private stateCallback?: StateCallback;
private lastState: SaveState = "saved";
constructor(updater: Callback, updateInterval = 1000, stateCallback?: StateCallback) {
this.updater = updater;
@@ -24,7 +25,7 @@ export default class SpacedUpdate {
scheduleUpdate() {
if (!this.changeForbidden) {
this.changed = true;
this.stateCallback?.("unsaved");
this.onStateChanged("unsaved");
setTimeout(() => this.triggerUpdate());
}
}
@@ -34,12 +35,12 @@ export default class SpacedUpdate {
this.changed = false; // optimistic...
try {
this.stateCallback?.("saving");
this.onStateChanged("saving");
await this.updater();
this.stateCallback?.("saved");
this.onStateChanged("saved");
} catch (e) {
this.changed = true;
this.stateCallback?.("error");
this.onStateChanged("error");
logError(getErrorMessage(e));
throw e;
}
@@ -76,13 +77,13 @@ export default class SpacedUpdate {
}
if (Date.now() - this.lastUpdated > this.updateInterval) {
this.stateCallback?.("saving");
this.onStateChanged("saving");
try {
await this.updater();
this.stateCallback?.("saved");
this.onStateChanged("saved");
this.changed = false;
} catch (e) {
this.stateCallback?.("error");
this.onStateChanged("error");
logError(getErrorMessage(e));
}
this.lastUpdated = Date.now();
@@ -92,6 +93,13 @@ export default class SpacedUpdate {
}
}
onStateChanged(state: SaveState) {
if (state === this.lastState) return;
this.stateCallback?.(state);
this.lastState = state;
}
async allowUpdateWithoutChange(callback: Callback) {
this.changeForbidden = true;

View File

@@ -14,7 +14,9 @@ export function reloadFrontendApp(reason?: string) {
}
if (isElectron()) {
dynamicRequire("@electron/remote").BrowserWindow.getFocusedWindow()?.reload();
for (const window of dynamicRequire("@electron/remote").BrowserWindow.getAllWindows()) {
window.reload();
}
} else {
window.location.reload();
}

View File

@@ -133,49 +133,6 @@ async function handleMessage(event: MessageEvent<any>) {
appContext.triggerEvent("apiLogMessages", { noteId: message.noteId, messages: message.messages });
} else if (message.type === "toast") {
toastService.showMessage(message.message);
} else if (message.type === "llm-stream") {
// ENHANCED LOGGING FOR DEBUGGING
console.log(`[WS-CLIENT] >>> RECEIVED LLM STREAM MESSAGE <<<`);
console.log(`[WS-CLIENT] Message details: sessionId=${message.sessionId}, hasContent=${!!message.content}, contentLength=${message.content ? message.content.length : 0}, hasThinking=${!!message.thinking}, hasToolExecution=${!!message.toolExecution}, isDone=${!!message.done}`);
if (message.content) {
console.log(`[WS-CLIENT] CONTENT PREVIEW: "${message.content.substring(0, 50)}..."`);
}
// Create the event with detailed logging
console.log(`[WS-CLIENT] Creating CustomEvent 'llm-stream-message'`);
const llmStreamEvent = new CustomEvent('llm-stream-message', { detail: message });
// Dispatch to multiple targets to ensure delivery
try {
console.log(`[WS-CLIENT] Dispatching event to window`);
window.dispatchEvent(llmStreamEvent);
console.log(`[WS-CLIENT] Event dispatched to window`);
// Also try document for completeness
console.log(`[WS-CLIENT] Dispatching event to document`);
document.dispatchEvent(new CustomEvent('llm-stream-message', { detail: message }));
console.log(`[WS-CLIENT] Event dispatched to document`);
} catch (err) {
console.error(`[WS-CLIENT] Error dispatching event:`, err);
}
// Debug current listeners (though we can't directly check for specific event listeners)
console.log(`[WS-CLIENT] Active event listeners should receive this message now`);
// Detailed logging based on message type
if (message.content) {
console.log(`[WS-CLIENT] Content message: ${message.content.length} chars`);
} else if (message.thinking) {
console.log(`[WS-CLIENT] Thinking update: "${message.thinking}"`);
} else if (message.toolExecution) {
console.log(`[WS-CLIENT] Tool execution: action=${message.toolExecution.action}, tool=${message.toolExecution.tool || 'unknown'}`);
if (message.toolExecution.result) {
console.log(`[WS-CLIENT] Tool result preview: "${String(message.toolExecution.result).substring(0, 50)}..."`);
}
} else if (message.done) {
console.log(`[WS-CLIENT] Completion signal received`);
}
} else if (message.type === "execute-script") {
// TODO: Remove after porting the file
// @ts-ignore

View File

@@ -1,450 +0,0 @@
/* LLM Chat Panel Styles */
.note-context-chat {
background-color: var(--main-background-color);
}
/* Message Styling */
.chat-message {
margin-bottom: 1rem;
}
.message-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
font-size: 1.25rem;
flex-shrink: 0;
}
.user-avatar {
background-color: var(--input-background-color);
color: var(--cmd-button-icon-color);
}
.assistant-avatar {
background-color: var(--subtle-border-color, var(--main-border-color));
color: var(--hover-item-text-color);
}
.message-content {
max-width: calc(100% - 50px);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
color: var(--main-text-color);
}
.user-content {
border-radius: 0.5rem 0.5rem 0 0.5rem !important;
background-color: var(--input-background-color) !important;
}
.assistant-content {
border-radius: 0.5rem 0.5rem 0.5rem 0 !important;
background-color: var(--main-background-color);
border: 1px solid var(--subtle-border-color, var(--main-border-color));
}
/* Tool Execution Styling */
.tool-execution-info {
margin-top: 0.75rem;
margin-bottom: 1.5rem;
border: 1px solid var(--subtle-border-color);
border-radius: 0.5rem;
overflow: hidden;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
background-color: var(--main-background-color);
/* Add a subtle transition effect */
transition: all 0.2s ease-in-out;
}
.tool-execution-status {
background-color: var(--accented-background-color, rgba(0, 0, 0, 0.03)) !important;
border-radius: 0 !important;
padding: 0.5rem !important;
max-height: 250px !important;
overflow-y: auto;
}
.tool-execution-status .d-flex {
border-bottom: 1px solid var(--subtle-border-color);
padding-bottom: 0.5rem;
margin-bottom: 0.5rem;
}
.tool-step {
padding: 0.5rem;
margin-bottom: 0.75rem;
border-radius: 0.375rem;
background-color: var(--main-background-color);
border: 1px solid var(--subtle-border-color);
transition: background-color 0.2s ease;
}
.tool-step:hover {
background-color: rgba(0, 0, 0, 0.01);
}
.tool-step:last-child {
margin-bottom: 0;
}
/* Tool step specific styling */
.tool-step.executing {
background-color: rgba(0, 123, 255, 0.05);
border-color: rgba(0, 123, 255, 0.2);
}
.tool-step.result {
background-color: rgba(40, 167, 69, 0.05);
border-color: rgba(40, 167, 69, 0.2);
}
.tool-step.error {
background-color: rgba(220, 53, 69, 0.05);
border-color: rgba(220, 53, 69, 0.2);
}
/* Tool result formatting */
.tool-result pre {
margin: 0.5rem 0;
padding: 0.5rem;
background-color: rgba(0, 0, 0, 0.03);
border-radius: 0.25rem;
overflow: auto;
max-height: 300px;
}
.tool-result code {
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 0.9em;
}
.tool-args code {
display: block;
padding: 0.5rem;
background-color: rgba(0, 0, 0, 0.03);
border-radius: 0.25rem;
margin-top: 0.25rem;
font-size: 0.85em;
color: var(--muted-text-color);
white-space: pre-wrap;
overflow: auto;
max-height: 100px;
}
/* Tool Execution in Chat Styling */
.chat-tool-execution {
padding: 0 0 0 36px; /* Aligned with message content, accounting for avatar width */
width: 100%;
margin-bottom: 1rem;
}
.tool-execution-container {
background-color: var(--accented-background-color, rgba(245, 247, 250, 0.7));
border: 1px solid var(--subtle-border-color);
border-radius: 0.375rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
overflow: hidden;
max-width: calc(100% - 20px);
transition: all 0.3s ease;
}
.tool-execution-container.collapsed {
display: none;
}
.tool-execution-header {
background-color: var(--main-background-color);
border-bottom: 1px solid var(--subtle-border-color);
margin-bottom: 0.5rem;
color: var(--muted-text-color);
font-weight: 500;
padding: 0.6rem 0.8rem;
cursor: pointer;
transition: background-color 0.2s ease;
}
.tool-execution-header:hover {
background-color: var(--hover-item-background-color, rgba(0, 0, 0, 0.03));
}
.tool-execution-toggle {
color: var(--muted-text-color) !important;
background: transparent !important;
padding: 0.2rem 0.4rem !important;
transition: transform 0.2s ease;
}
.tool-execution-toggle:hover {
color: var(--main-text-color) !important;
}
.tool-execution-toggle i.bx-chevron-down {
transform: rotate(0deg);
transition: transform 0.3s ease;
}
.tool-execution-toggle i.bx-chevron-right {
transform: rotate(-90deg);
transition: transform 0.3s ease;
}
.tool-execution-chat-steps {
padding: 0.5rem;
max-height: 300px;
overflow-y: auto;
}
/* Make error text more visible */
.text-danger {
color: #dc3545 !important;
}
/* Sources Styling */
.sources-container {
background-color: var(--accented-background-color, var(--main-background-color));
border-top: 1px solid var(--main-border-color);
color: var(--main-text-color);
}
.source-item {
transition: all 0.2s ease;
background-color: var(--main-background-color);
border-color: var(--subtle-border-color, var(--main-border-color)) !important;
}
.source-item:hover {
background-color: var(--link-hover-background, var(--hover-item-background-color));
}
.source-link {
color: var(--link-color, var(--hover-item-text-color));
text-decoration: none;
display: block;
width: 100%;
}
.source-link:hover {
color: var(--link-hover-color, var(--hover-item-text-color));
}
/* Input Area Styling */
.note-context-chat-form {
background-color: var(--main-background-color);
border-top: 1px solid var(--main-border-color);
}
.context-option-container {
padding: 0.5rem 0;
border-bottom: 1px solid var(--subtle-border-color, var(--main-border-color));
color: var(--main-text-color);
}
.chat-input-container {
padding-top: 0.5rem;
}
.note-context-chat-input {
border-color: var(--subtle-border-color, var(--main-border-color));
background-color: var(--input-background-color) !important;
color: var(--input-text-color) !important;
resize: none;
transition: all 0.2s ease;
min-height: 50px;
max-height: 150px;
}
.note-context-chat-input:focus {
border-color: var(--input-focus-outline-color, var(--main-border-color));
box-shadow: 0 0 0 0.25rem var(--input-focus-outline-color, rgba(13, 110, 253, 0.25));
}
.note-context-chat-send-button {
width: 40px;
height: 40px;
align-self: flex-end;
background-color: var(--cmd-button-background-color) !important;
color: var(--cmd-button-text-color) !important;
}
/* Loading Indicator */
.loading-indicator {
align-items: center;
justify-content: center;
padding: 1rem;
color: var(--muted-text-color);
}
/* Thinking display styles */
.llm-thinking-container {
margin: 1rem 0;
animation: fadeInUp 0.3s ease-out;
}
.thinking-bubble {
background-color: var(--accented-background-color, var(--main-background-color));
border: 1px solid var(--subtle-border-color, var(--main-border-color));
border-radius: 0.75rem;
padding: 0.75rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
position: relative;
overflow: hidden;
transition: all 0.2s ease;
}
.thinking-bubble:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.thinking-bubble::before {
content: '';
position: absolute;
top: 0;
inset-inline-start: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, var(--hover-item-background-color, rgba(0, 0, 0, 0.03)), transparent);
animation: shimmer 2s infinite;
opacity: 0.5;
}
.thinking-header {
cursor: pointer;
transition: all 0.2s ease;
border-radius: 0.375rem;
}
.thinking-header:hover {
background-color: var(--hover-item-background-color, rgba(0, 0, 0, 0.03));
padding: 0.25rem;
margin: -0.25rem;
}
.thinking-dots {
display: flex;
gap: 3px;
align-items: center;
}
.thinking-dots span {
width: 6px;
height: 6px;
background-color: var(--link-color, var(--hover-item-text-color));
border-radius: 50%;
animation: thinkingPulse 1.4s infinite ease-in-out;
}
.thinking-dots span:nth-child(1) {
animation-delay: -0.32s;
}
.thinking-dots span:nth-child(2) {
animation-delay: -0.16s;
}
.thinking-dots span:nth-child(3) {
animation-delay: 0s;
}
.thinking-label {
font-weight: 500;
color: var(--link-color, var(--hover-item-text-color)) !important;
}
.thinking-toggle {
color: var(--muted-text-color) !important;
transition: transform 0.2s ease;
background: transparent !important;
border: none !important;
}
.thinking-toggle:hover {
color: var(--main-text-color) !important;
}
.thinking-toggle.expanded {
transform: rotate(180deg);
}
.thinking-content {
margin-top: 0.75rem;
padding-top: 0.75rem;
border-top: 1px solid var(--subtle-border-color, var(--main-border-color));
animation: expandDown 0.3s ease-out;
}
.thinking-text {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
font-size: 0.875rem;
line-height: 1.5;
color: var(--main-text-color);
white-space: pre-wrap;
word-wrap: break-word;
background-color: var(--input-background-color);
padding: 0.75rem;
border-radius: 0.5rem;
border: 1px solid var(--subtle-border-color, var(--main-border-color));
max-height: 300px;
overflow-y: auto;
transition: border-color 0.2s ease;
}
.thinking-text:hover {
border-color: var(--main-border-color);
}
/* Animations */
@keyframes thinkingPulse {
0%, 80%, 100% {
transform: scale(0.8);
opacity: 0.6;
}
40% {
transform: scale(1);
opacity: 1;
}
}
@keyframes shimmer {
0% {
inset-inline-start: -100%;
}
100% {
inset-inline-start: 100%;
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes expandDown {
from {
opacity: 0;
max-height: 0;
}
to {
opacity: 1;
max-height: 300px;
}
}
/* Responsive adjustments */
@media (max-width: 768px) {
.thinking-bubble {
margin: 0.5rem 0;
padding: 0.5rem;
}
.thinking-text {
font-size: 0.8rem;
padding: 0.5rem;
max-height: 200px;
}
}

View File

@@ -2630,7 +2630,7 @@ iframe.print-iframe {
}
}
#root-widget.virtual-keyboard-opened .note-split:not(.active) {
body:not(.ios) #root-widget.virtual-keyboard-opened .note-split:not(.active) {
max-height: 80px;
opacity: 0.4;
}

View File

@@ -314,7 +314,8 @@
*/
#left-pane .fancytree-node.tinted,
.nested-note-list-item.use-note-color {
.nested-note-list-item.use-note-color,
.note-book-card .note-book-header.use-note-color {
--custom-color: var(--dark-theme-custom-color);
/* The background color of the active item in the note tree.
@@ -365,7 +366,8 @@ body .todo-list input[type="checkbox"]:not(:checked):before {
.note-split.with-hue,
.quick-edit-dialog-wrapper.with-hue,
.nested-note-list-item.with-hue {
.nested-note-list-item.with-hue,
.note-book-card.with-hue .note-book-header {
--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%);
@@ -375,3 +377,8 @@ body .todo-list input[type="checkbox"]:not(:checked):before {
.quick-edit-dialog-wrapper.with-hue *::selection {
--selection-background-color: hsl(var(--custom-color-hue), 49.2%, 35%);
}
.note-book-card.with-hue {
--card-background-color: hsl(var(--custom-color-hue), 6%, 21%);
--card-background-hover-color: hsl(var(--custom-color-hue), 8%, 25%);
}

View File

@@ -308,7 +308,8 @@
}
#left-pane .fancytree-node.tinted,
.nested-note-list-item.use-note-color {
.nested-note-list-item.use-note-color,
.note-book-card .note-book-header.use-note-color {
--custom-color: var(--light-theme-custom-color);
/* The background color of the active item in the note tree.
@@ -335,7 +336,8 @@
.note-split.with-hue,
.quick-edit-dialog-wrapper.with-hue,
.nested-note-list-item.with-hue {
.nested-note-list-item.with-hue,
.note-book-card.with-hue .note-book-header {
--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%);
@@ -345,3 +347,8 @@
.quick-edit-dialog-wrapper.with-hue *::selection {
--selection-background-color: hsl(var(--custom-color-hue), 60%, 90%);
}
.note-book-card.with-hue {
--card-background-color: hsl(var(--custom-color-hue), 21%, 94%);
--card-background-hover-color: hsl(var(--custom-color-hue), 21%, 87%);
}

View File

@@ -643,139 +643,6 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
transform: translateY(4%);
}
/*
* NOTE LIST
*/
.note-list .note-book-card {
--note-list-horizontal-padding: 22px;
--note-list-vertical-padding: 15px;
background-color: var(--card-background-color);
border: 1px solid var(--card-border-color) !important;
border-radius: 12px;
user-select: none;
padding: 0;
margin: 5px 10px 5px 0;
}
:root .note-list .note-book-card:hover {
background-color: var(--card-background-hover-color);
transition: background-color 200ms ease-out;
}
:root .note-list.grid-view .note-book-card:active {
transform: scale(.98);
}
.note-list.list-view .note-book-card {
box-shadow: 0 0 3px var(--card-shadow-color);
}
.note-list.list-view .note-book-card .note-book-header .note-icon {
vertical-align: middle;
}
.note-list-wrapper .note-book-card a {
color: inherit !important;
}
.note-list-wrapper .note-book-card .note-book-header {
font-size: 1em;
font-weight: bold;
padding: 0.5em 1rem;
border-bottom-color: var(--card-border-color);
}
.note-list-wrapper .note-book-card .note-book-header .note-icon {
font-size: 17px;
vertical-align: text-bottom;
}
.note-list-wrapper .note-book-card .note-book-header .note-book-title {
font-size: 1em;
color: var(--active-item-text-color);
vertical-align: middle;
}
.note-list-wrapper .note-book-card .note-book-header .rendered-note-attributes {
font-size: 0.7em;
font-weight: normal;
margin-bottom: 0;
}
.note-list-wrapper .note-book-card .note-book-header:last-child {
border-bottom: 0;
}
.note-list-wrapper .note-book-card .note-book-content {
padding: 0 !important;
font-size: 0.8rem;
}
.note-list-wrapper .note-book-card .note-book-content .rendered-content {
padding: 1rem;
}
.note-list-wrapper .note-book-card .note-book-content.type-image .rendered-content,
.note-list-wrapper .note-book-card .note-book-content.type-pdf .rendered-content {
padding: 0;
}
.note-list-wrapper .note-book-card .note-book-content .rendered-content.text-with-ellipsis {
padding: 1rem !important;
}
.note-list-wrapper .note-book-card .note-book-content h1,
.note-list-wrapper .note-book-card .note-book-content h2,
.note-list-wrapper .note-book-card .note-book-content h3,
.note-list-wrapper .note-book-card .note-book-content h4,
.note-list-wrapper .note-book-card .note-book-content h5,
.note-list-wrapper .note-book-card .note-book-content h6 {
font-size: 1rem;
color: var(--active-item-text-color);
}
.note-list-wrapper .note-book-card .note-book-content p:last-child {
margin-bottom: 0;
}
.note-list-wrapper .note-book-card .note-book-content.type-canvas .rendered-content,
.note-list-wrapper .note-book-card .note-book-content.type-mindMap .rendered-content,
.note-list-wrapper .note-book-card .note-book-content.type-code .rendered-content,
.note-list-wrapper .note-book-card .note-book-content.type-video .rendered-content {
padding: 0;
}
.note-list-wrapper .note-book-card .note-book-content.type-code {
height: 100%;
}
.note-list-wrapper .note-book-card .note-book-content.type-code pre {
height: 100%;
padding: 1em;
margin-bottom: 0;
}
.note-list-wrapper .note-book-card .tn-icon {
color: var(--left-pane-icon-color) !important;
}
.note-list.grid-view .note-book-card:hover {
filter: contrast(105%);
}
.note-list.grid-view .ck-content {
line-height: 1.3;
}
.note-list.grid-view .ck-content p {
margin-bottom: 0.5em;
}
.note-list.grid-view .ck-content figure.image {
width: 25%;
}
/*
* NOTE SEARCH SUGGESTIONS
*/

View File

@@ -1,122 +0,0 @@
/* LLM Chat Launcher Widget Styles */
.note-context-chat {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
.note-context-chat-container {
flex-grow: 1;
overflow-y: auto;
padding: 15px;
}
.chat-message {
display: flex;
margin-bottom: 15px;
max-width: 85%;
}
.chat-message.user-message {
margin-inline-start: auto;
}
.chat-message.assistant-message {
margin-inline-end: auto;
}
.message-avatar {
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-inline-end: 8px;
}
.user-message .message-avatar {
background-color: var(--primary-color);
color: white;
}
.assistant-message .message-avatar {
background-color: var(--secondary-color);
color: white;
}
.message-content {
background-color: var(--more-accented-background-color);
border-radius: 12px;
padding: 10px 15px;
max-width: calc(100% - 40px);
}
.user-message .message-content {
background-color: var(--accented-background-color);
}
.message-content pre {
background-color: var(--code-background-color);
border-radius: 5px;
padding: 10px;
overflow-x: auto;
max-width: 100%;
}
.message-content code {
background-color: var(--code-background-color);
padding: 2px 4px;
border-radius: 3px;
}
.loading-indicator {
display: flex;
align-items: center;
margin: 10px 0;
color: var(--muted-text-color);
}
.sources-container {
background-color: var(--accented-background-color);
border-top: 1px solid var(--main-border-color);
padding: 8px;
}
.sources-list {
font-size: 0.9em;
}
.source-item {
padding: 4px 0;
}
.source-link {
color: var(--link-color);
text-decoration: none;
}
.source-link:hover {
text-decoration: underline;
}
.note-context-chat-form {
display: flex;
background-color: var(--main-background-color);
border-top: 1px solid var(--main-border-color);
padding: 10px;
}
.note-context-chat-input {
resize: vertical;
min-height: 44px;
max-height: 200px;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.chat-message {
max-width: 95%;
}
}

View File

@@ -647,10 +647,10 @@ html .note-detail-editable-text :not(figure, .include-note, hr):first-child {
font-weight: 600;
}
.ck-content hr {
margin: 5px 0;
height: 1px;
background-color: var(--main-border-color);
:root .ck-content hr {
margin-block: 5px;
height: 0;
border: thin solid var(--main-border-color);
opacity: 1;
}

View File

@@ -372,10 +372,6 @@ body[dir=ltr] #launcher-container {
.calendar-dropdown-widget .calendar-header [data-calendar-input="month"] {
--input-background-color: transparent;
--menu-background-color: transparent;
text-align: center;
font-size: 1.4em;
font-weight: 300;
}
.calendar-dropdown-widget .calendar-header input:not(:focus) {
@@ -425,8 +421,6 @@ body[dir=ltr] #launcher-container {
}
.calendar-dropdown-widget .calendar-week span {
font-size: 0.85em;
font-weight: 500;
color: var(--calendar-weekday-labels-color);
}
@@ -689,9 +683,10 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
padding-inline-start: 12px;
}
#left-pane span.fancytree-node.fancytree-active {
#left-pane span.fancytree-node.fancytree-active,
#left-pane span.fancytree-node.fancytree-active:hover {
position: relative;
background: transparent !important;
background: transparent;
color: var(--custom-color, var(--left-pane-item-selected-color));
}
@@ -704,6 +699,14 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
}
}
/*
* .fancytree-node pseudo-elements:
*
* - ::before: the active tree item decorator.
* - ::after: the selected tree item background. A pseudo-element is used instead of the
* element's background color, to allow alpha compositing for the hover state.
*/
#left-pane span.fancytree-node.fancytree-active::before {
position: absolute;
content: "";
@@ -718,6 +721,24 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
z-index: -1;
}
#left-pane span.fancytree-node.fancytree-selected {
--left-pane-item-selected-shadow-size: 4px;
position: relative;
background-color: transparent;
border-radius: 0;
}
#left-pane span.fancytree-node.fancytree-selected::after {
display: block;
position: absolute;
z-index: -2;
content: "";
inset: 0;
background: var(--selection-background-color);
animation: left-pane-item-select 100ms ease-out;
}
#left-pane span.fancytree-node.protected > span.fancytree-custom-icon {
position: relative;
filter: unset !important;
@@ -780,7 +801,8 @@ body[dir=rtl] #left-pane span.fancytree-node.protected > span.fancytree-custom-i
opacity: 0.5;
}
#left-pane .tree-item-button {
#left-pane .tree-item-button,
#left-pane span.fancytree-node.fancytree-selected .fancytree-custom-icon {
margin-inline-end: 6px;
border: unset;
border-radius: 50%;
@@ -791,7 +813,8 @@ body[dir=rtl] #left-pane span.fancytree-node.protected > span.fancytree-custom-i
box-shadow 200ms ease-out;
}
#left-pane .tree-item-button:hover {
#left-pane .tree-item-button:hover,
#left-pane span.fancytree-node.fancytree-selected .fancytree-custom-icon:hover {
background: var(--left-pane-item-action-button-hover-background);
box-shadow: var(--left-pane-item-action-button-hover-shadow);
transition:
@@ -799,10 +822,41 @@ body[dir=rtl] #left-pane span.fancytree-node.protected > span.fancytree-custom-i
box-shadow 100ms ease-in;
}
#left-pane span.fancytree-node.fancytree-active .tree-item-button:hover {
#left-pane span.fancytree-node.fancytree-active .tree-item-button:hover,
#left-pane span.fancytree-node.fancytree-active.fancytree-selected .fancytree-custom-icon:hover {
box-shadow: var(--left-pane-item-selected-action-button-hover-shadow);
}
/* Selected item bulk action button */
@keyframes bulk-action-button-blink {
from {
opacity: 1;
}
to {
opacity: .3;
}
}
#left-pane span.fancytree-node.fancytree-selected .fancytree-custom-icon {
margin: 0;
}
#left-pane span.fancytree-node.fancytree-selected .fancytree-custom-icon::before {
border: 0;
font-size: .65em;
}
#left-pane span.fancytree-node.fancytree-selected:hover .fancytree-custom-icon:not(:hover)::before {
animation: bulk-action-button-blink 500ms linear infinite alternate;
}
#left-pane span.fancytree-node.fancytree-selected.protected .fancytree-custom-icon::after {
/* Protected note indicator */
display: none;
}
#context-menu-container {
/* The context menu of the tree */
--menu-item-icon-vert-offset: -1px;
@@ -1033,7 +1087,7 @@ body.layout-vertical.electron.platform-darwin .tab-row-container {
height: var(--tab-height) !important;
}
.tab-row-widget > * {
body.layout-vertical .tab-row-widget > * {
margin-top: calc((var(--tab-bar-height) - var(--tab-height)) / 2);
}

View File

@@ -140,10 +140,22 @@ ul.fancytree-container {
background-color: inherit;
}
.fancytree-custom-icon {
display: flex;
justify-content: center;
align-items: center;
width: 1em;
height: 1em;
font-size: 1.2em;
}
/* Fallback icon */
:where(.fancytree-custom-icon)::before {
content: "?";
}
/* Protected note icon badge */
span.fancytree-node.protected > span.fancytree-custom-icon {
filter: drop-shadow(2px 2px 2px var(--main-text-color));
}
@@ -185,7 +197,7 @@ span.fancytree-node.fancytree-active-clone:not(.fancytree-active) .fancytree-tit
span.fancytree-active {
color: var(--active-item-text-color);
background-color: var(--active-item-background-color) !important;
background-color: var(--active-item-background-color);
border-color: transparent; /* invisible border */
border-radius: 5px;
}
@@ -195,20 +207,15 @@ span.fancytree-active .fancytree-title {
border: 0;
}
span.fancytree-selected {
border-color: var(--main-border-color) !important;
border-radius: 5px;
}
span.fancytree-selected .fancytree-title {
text-decoration: underline;
font-style: italic;
span.fancytree-node.fancytree-selected {
background-color: var(--selection-background-color);
border-radius: 0;
}
span.fancytree-selected .fancytree-custom-icon::before {
font-family: "boxicons";
content: "\eb43";
border: 1px solid var(--main-border-color);
content: "\ef05";
border: 1px solid var(--main-text-color);
border-radius: 3px;
}

View File

@@ -566,113 +566,6 @@
"enable-smooth-scroll": "تمكين التمرير السلس",
"enable-motion": "تمكين الانتقالات والرسوم المتحركة"
},
"ai_llm": {
"progress": "تقدم",
"openai_tab": "OpenAI",
"actions": "أجراءات",
"retry": "أعد المحاولة",
"reprocessing_index": "جار اعادة البناء...",
"never": "ابدٱ",
"agent": {
"processing": "جار المعالجة...",
"thinking": "جار التفكير...",
"loading": "جار التحميل...",
"generating": "جار الانشاء..."
},
"name": "الذكاء الأصطناعي",
"openai": "OpenAI",
"sources": "مصادر",
"temperature": "درجة الحرارة",
"model": "نموذج",
"refreshing_models": "جار التحديث...",
"error": "خطأ",
"refreshing": "جار التحديث...",
"ollama_tab": "Ollama",
"anthropic_tab": "انتروبيك",
"not_started": "لم يبدأ بعد",
"title": "اعدادات AI",
"processed_notes": "الملاحظات المعالجة",
"total_notes": "الملاحظات الكلية",
"queued_notes": "الملاحظات في قائمة الانتظار",
"failed_notes": "الملاحظات الفاشلة",
"last_processed": "اخر معالجة",
"refresh_stats": "تحديث الاحصائيات",
"voyage_tab": "استكشاف AI",
"provider_precedence": "اولوية المزود",
"system_prompt": "موجه النظام",
"openai_configuration": "اعدادات OpenAI",
"openai_settings": "اعدادات OpenAI",
"api_key": "مفتاح واجهة برمجة التطبيقات",
"url": "عنوان URL الاساسي",
"default_model": "النموذج الافتراضي",
"base_url": "عنوان URL الأساسي",
"openai_url_description": "افتراضيا: https://api.openai.com/v1",
"anthropic_settings": "اعدادات انتروبيك",
"ollama_settings": "اعدادات Ollama",
"anthropic_configuration": "تهيئة انتروبيك",
"voyage_url_description": "افتراضيا: https://api.voyageai.com/v1",
"ollama_configuration": "تهيئة Ollama",
"enable_ollama": "تمكين Ollama",
"last_attempt": "اخر محاولة",
"active_providers": "المزودون النشطون",
"disabled_providers": "المزودون المعطلون",
"similarity_threshold": "عتبة التشابه",
"complete": "اكتمل (100%)",
"ai_settings": "اعدادات AI",
"show_thinking": "عرض التفكير",
"index_status": "حالة الفهرس",
"indexed_notes": "الملاحظات المفهرسة",
"indexing_stopped": "تم ايقاف الفهرسة",
"last_indexed": "اخر فهرسة",
"note_chat": "دردشة الملاحظة",
"start_indexing": "بدء الفهرسة",
"chat": {
"root_note_title": "دردشات AI",
"new_chat_title": "دردشة جديدة",
"create_new_ai_chat": "انشاء دردشة AI جديدة"
},
"selected_provider": "المزود المحدد",
"select_model": "اختر النموذج...",
"select_provider": "اختر المزود...",
"ollama_model": "نموذج Ollama",
"refresh_models": "تحديث النماذج",
"rebuild_index": "اعادة بناء الفهرس",
"note_title": "عنوان الملاحظة",
"processing": "جاري المعالجة ({{percentage}}%)",
"incomplete": "غير مكتمل ({{percentage}}%)",
"ollama_url": "عنوان URL الخاص ب Ollama",
"provider_configuration": "تكوين موفر AI",
"voyage_settings": "استكشاف اعدادات AI",
"enable_automatic_indexing": "تمكين الفهرسة التلقائية",
"index_rebuild_progress": "تقدم اعادة انشاء الفهرس",
"index_rebuild_complete": "اكتملت عملية تحسين الفهرس",
"use_enhanced_context": "استخدام السياق المحسن",
"enter_message": "ادخل رسالتك...",
"index_all_notes": "فهرسة جميع الملاحظات",
"indexing_in_progress": "جار فهرسة الملاحظات...",
"use_advanced_context": "استخدم السياق المتقدم",
"ai_enabled": "تمكين مميزات AI",
"ai_disabled": "الغاء تمكين مميزات AI",
"enable_ai_features": "تمكين خصائص AI/LLM",
"enable_ai": "تمكين خصائص AI/LLM",
"reprocess_index": "اعادة بناء فهرس البحث",
"index_rebuilding": "جار تحسين الفهرس {{percentage}}",
"voyage_configuration": "اعدادت Voyage AI",
"openai_model_description": "الامثلة: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"partial": "{{ percentage }} % مكتمل",
"retry_queued": "تم جدولة الملاحظة لاعادة المحاولة",
"max_notes_per_llm_query": "اكبر عدد للملاحظات لكل استعلام",
"remove_provider": "احذف المزود من البحث",
"restore_provider": "استعادة المزود الى البحث",
"reprocess_index_error": "حدث خطأ اثناء اعادة بناء فهرس البحث",
"auto_refresh_notice": "تحديث تلقائي كل {{seconds}} ثانية",
"note_queued_for_retry": "الملاحظة جاهزة لاعادة المحاولة لاحقا",
"failed_to_retry_note": "‎فشل في اعادة محاولة معالجة المحاولة",
"failed_to_retry_all": "فشل في اعادة محاولة معالجة الملاحظة",
"error_generating_response": "‌فشل في توليد استجابة من ال AI",
"create_new_ai_chat": "انشاء دردشة AI جديدة",
"error_fetching": "فشل في استرجاع النماذج: {{error}}"
},
"code_auto_read_only_size": {
"unit": "حروف",
"title": "الحجم التلقائي للقراءه فقط"
@@ -910,7 +803,6 @@
"web-view": "عرض الويب",
"mind-map": "خريطة ذهنية",
"geo-map": "خريطة جغرافية",
"ai-chat": "دردشة AI",
"task-list": "قائمة المهام"
},
"shared_switch": {
@@ -990,6 +882,7 @@
"electron_context_menu": {
"cut": "قص",
"copy": "نسخ",
"copy-as-markdown": "نسخ كـ Markdown",
"paste": "لصق",
"copy-link": "نسخ الرابط",
"add-term-to-dictionary": "اضافة \"{{term}}\" الى القاموس",

View File

@@ -1532,10 +1532,10 @@
"geo-map": "地理地图",
"beta-feature": "测试版",
"task-list": "任务列表",
"ai-chat": "AI聊天",
"new-feature": "新建",
"collections": "集合",
"book": "集合"
"book": "集合",
"ai-chat": "AI聊天"
},
"protect_note": {
"toggle-on": "保护笔记",
@@ -1631,7 +1631,8 @@
},
"search_result": {
"no_notes_found": "没有找到符合搜索条件的笔记。",
"search_not_executed": "尚未执行搜索。请点击上方的\"搜索\"按钮查看结果。"
"search_not_executed": "尚未执行搜索。",
"search_now": "立即搜索"
},
"spacer": {
"configure_launchbar": "配置启动栏"
@@ -1759,6 +1760,7 @@
"add-term-to-dictionary": "将 \"{{term}}\" 添加到字典",
"cut": "剪切",
"copy": "复制",
"copy-as-markdown": "复制为 Markdown",
"copy-link": "复制链接",
"paste": "粘贴",
"paste-as-plain-text": "以纯文本粘贴",
@@ -1839,149 +1841,6 @@
"yesterday": "昨天"
}
},
"ai_llm": {
"not_started": "未开始",
"title": "AI设置",
"processed_notes": "已处理笔记",
"total_notes": "笔记总数",
"progress": "进度",
"queued_notes": "排队中笔记",
"failed_notes": "失败笔记",
"last_processed": "最后处理时间",
"refresh_stats": "刷新统计数据",
"enable_ai_features": "启用AI/LLM功能",
"enable_ai_description": "启用笔记摘要、内容生成等AI功能及其他LLM能力",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "启用AI/LLM功能",
"enable_ai_desc": "启用笔记摘要、内容生成等AI功能及其他LLM能力",
"provider_configuration": "AI提供商配置",
"provider_precedence": "提供商优先级",
"provider_precedence_description": "按优先级排序的提供商列表(用逗号分隔,例如:'openai,anthropic,ollama'",
"temperature": "温度参数",
"temperature_description": "控制响应的随机性0 = 确定性输出2 = 最大随机性)",
"system_prompt": "系统提示词",
"system_prompt_description": "所有AI交互使用的默认系统提示词",
"openai_configuration": "OpenAI配置",
"openai_settings": "OpenAI设置",
"api_key": "API密钥",
"url": "基础URL",
"model": "模型",
"openai_api_key_description": "用于访问OpenAI服务的API密钥",
"anthropic_api_key_description": "用于访问Claude模型的Anthropic API密钥",
"default_model": "默认模型",
"openai_model_description": "示例gpt-4o、gpt-4-turbo、gpt-3.5-turbo",
"base_url": "基础URL",
"openai_url_description": "默认https://api.openai.com/v1",
"anthropic_settings": "Anthropic设置",
"anthropic_url_description": "Anthropic API的基础URL默认https://api.anthropic.com",
"anthropic_model_description": "用于聊天补全的Anthropic Claude模型",
"voyage_settings": "Voyage AI设置",
"ollama_settings": "Ollama设置",
"ollama_url_description": "Ollama API的URL默认http://localhost:11434",
"ollama_model_description": "用于聊天补全的 Ollama 模型",
"anthropic_configuration": "Anthropic配置",
"voyage_configuration": "Voyage AI配置",
"voyage_url_description": "默认https://api.voyageai.com/v1",
"ollama_configuration": "Ollama配置",
"enable_ollama": "启用Ollama",
"enable_ollama_description": "启用Ollama以使用本地AI模型",
"ollama_url": "Ollama URL",
"ollama_model": "Ollama模型",
"refresh_models": "刷新模型",
"refreshing_models": "刷新中...",
"enable_automatic_indexing": "启用自动索引",
"rebuild_index": "重建索引",
"rebuild_index_error": "启动索引重建失败。请查看日志了解详情。",
"note_title": "笔记标题",
"error": "错误",
"last_attempt": "最后尝试时间",
"actions": "操作",
"retry": "重试",
"partial": "{{ percentage }}% 已完成",
"retry_queued": "笔记已加入重试队列",
"retry_failed": "笔记加入重试队列失败",
"max_notes_per_llm_query": "每次查询的最大笔记数",
"max_notes_per_llm_query_description": "AI上下文包含的最大相似笔记数量",
"active_providers": "活跃提供商",
"disabled_providers": "已禁用提供商",
"remove_provider": "从搜索中移除提供商",
"restore_provider": "将提供商恢复到搜索中",
"similarity_threshold": "相似度阈值",
"similarity_threshold_description": "纳入LLM查询上下文的笔记最低相似度分数0-1",
"reprocess_index": "重建搜索索引",
"reprocessing_index": "重建中...",
"reprocess_index_started": "搜索索引优化已在后台启动",
"reprocess_index_error": "重建搜索索引失败",
"index_rebuild_progress": "索引重建进度",
"index_rebuilding": "正在优化索引({{percentage}}%",
"index_rebuild_complete": "索引优化完成",
"index_rebuild_status_error": "检查索引重建状态失败",
"never": "从未",
"processing": "处理中({{percentage}}%",
"incomplete": "未完成({{percentage}}%",
"complete": "已完成100%",
"refreshing": "刷新中...",
"auto_refresh_notice": "每 {{seconds}} 秒自动刷新",
"note_queued_for_retry": "笔记已加入重试队列",
"failed_to_retry_note": "重试笔记失败",
"all_notes_queued_for_retry": "所有失败笔记已加入重试队列",
"failed_to_retry_all": "重试笔记失败",
"ai_settings": "AI设置",
"api_key_tooltip": "用于访问服务的API密钥",
"empty_key_warning": {
"anthropic": "Anthropic API密钥为空。请输入有效的API密钥。",
"openai": "OpenAI API密钥为空。请输入有效的API密钥。",
"voyage": "Voyage API密钥为空。请输入有效的API密钥。",
"ollama": "Ollama API密钥为空。请输入有效的API密钥。"
},
"agent": {
"processing": "处理中...",
"thinking": "思考中...",
"loading": "加载中...",
"generating": "生成中..."
},
"name": "AI",
"openai": "OpenAI",
"use_enhanced_context": "使用增强上下文",
"enhanced_context_description": "为AI提供来自笔记及其相关笔记的更多上下文以获得更好的响应",
"show_thinking": "显示思考过程",
"show_thinking_description": "显示AI的思维链过程",
"enter_message": "输入你的消息...",
"error_contacting_provider": "联系AI提供商失败。请检查你的设置和网络连接。",
"error_generating_response": "生成AI响应失败",
"index_all_notes": "为所有笔记建立索引",
"index_status": "索引状态",
"indexed_notes": "已索引笔记",
"indexing_stopped": "索引已停止",
"indexing_in_progress": "索引进行中...",
"last_indexed": "最后索引时间",
"note_chat": "笔记聊天",
"sources": "来源",
"start_indexing": "开始索引",
"use_advanced_context": "使用高级上下文",
"ollama_no_url": "Ollama 未配置。请输入有效的URL。",
"chat": {
"root_note_title": "AI聊天记录",
"root_note_content": "此笔记包含你保存的AI聊天对话。",
"new_chat_title": "新聊天",
"create_new_ai_chat": "创建新的AI聊天"
},
"create_new_ai_chat": "创建新的AI聊天",
"configuration_warnings": "你的AI配置存在一些问题。请检查你的设置。",
"experimental_warning": "LLM功能目前处于实验阶段 - 特此提醒。",
"selected_provider": "已选提供商",
"selected_provider_description": "选择用于聊天和补全功能的AI提供商",
"select_model": "选择模型...",
"select_provider": "选择提供商...",
"ai_enabled": "已启用 AI 功能",
"ai_disabled": "已禁用 AI 功能",
"no_models_found_online": "找不到模型。请检查您的 API 密钥及设置。",
"no_models_found_ollama": "找不到 Ollama 模型。请确认 Ollama 是否正在运行。",
"error_fetching": "获取模型失败:{{error}}"
},
"code-editor-options": {
"title": "编辑器"
},
@@ -2149,7 +2008,9 @@
"app-restart-required": "(需重启程序以应用更改)"
},
"pagination": {
"total_notes": "{{count}} 篇笔记"
"total_notes": "{{count}} 篇笔记",
"prev_page": "上一页",
"next_page": "下一页"
},
"collections": {
"rendering_error": "出现错误无法显示内容。"

View File

@@ -428,9 +428,9 @@
"run_on_note_content_change": "Wird ausgeführt, wenn der Inhalt einer Notiz geändert wird (einschließlich der Erstellung von Notizen).",
"run_on_note_change": "Wird ausgeführt, wenn eine Notiz geändert wird (einschließlich der Erstellung von Notizen). Enthält keine Inhaltsänderungen",
"run_on_note_deletion": "Wird ausgeführt, wenn eine Notiz gelöscht wird",
"run_on_branch_creation": "wird ausgeführt, wenn ein Zweig erstellt wird. Der Zweig ist eine Verbindung zwischen der übergeordneten Notiz und der untergeordneten Notiz und wird z. B. erstellt. beim Klonen oder Verschieben von Notizen.",
"run_on_branch_creation": "wird ausgeführt, wenn ein Zweig erstellt wird. Der Zweig ist eine Verbindung zwischen der übergeordneten und der untergeordneten Notiz und wird z. B. beim Klonen oder Verschieben von Notizen erstellt.",
"run_on_branch_change": "wird ausgeführt, wenn ein Zweig aktualisiert wird.",
"run_on_branch_deletion": "wird ausgeführt, wenn ein Zweig gelöscht wird. Der Zweig ist eine Verknüpfung zwischen der übergeordneten Notiz und der untergeordneten Notiz und wird z. B. gelöscht. beim Verschieben der Notiz (alter Zweig/Link wird gelöscht).",
"run_on_branch_deletion": "wird ausgeführt, wenn ein Zweig gelöscht wird. Der Zweig ist eine Verknüpfung zwischen der übergeordneten und der untergeordneten Notiz und wird z. B. beim Verschieben der Notiz gelöscht (alter Zweig/Link wird gelöscht).",
"run_on_attribute_creation": "wird ausgeführt, wenn für die Notiz ein neues Attribut erstellt wird, das diese Beziehung definiert",
"run_on_attribute_change": " wird ausgeführt, wenn das Attribut einer Notiz geändert wird, die diese Beziehung definiert. Dies wird auch ausgelöst, wenn das Attribut gelöscht wird",
"relation_template": "Die Attribute der Notiz werden auch ohne eine Hierarchische-Beziehung vererbt. Der Inhalt und der Zweig werden den Instanznotizen hinzugefügt, wenn sie leer sind. Einzelheiten findest du in der Dokumentation.",
@@ -801,7 +801,7 @@
"expand_tooltip": "Erweitert die direkten Unterelemente dieser Sammlung (eine Ebene tiefer). Für weitere Optionen auf den Pfeil rechts klicken.",
"expand_first_level": "Direkte Unterelemente erweitern",
"expand_nth_level": "{{depth}} Ebenen erweitern",
"hide_child_notes": "Unternotizen im Baum ausblenden"
"hide_child_notes": "Untergeordnete Notizen im Baum ausblenden"
},
"edited_notes": {
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
@@ -1007,7 +1007,7 @@
"no_attachments": "Diese Notiz enthält keine Anhänge."
},
"book": {
"no_children_help": "Diese Sammlung enthält keineUnternotizen, daher gibt es nichts anzuzeigen.",
"no_children_help": "Diese Sammlung enthält keine untergeordnete Notizen, daher gibt es nichts anzuzeigen.",
"drag_locked_title": "Für Bearbeitung gesperrt",
"drag_locked_message": "Das Ziehen ist nicht möglich, da die Sammlung für die Bearbeitung gesperrt ist."
},
@@ -1187,7 +1187,7 @@
"tooltip_code_note_syntax": "Code-Notizen"
},
"vim_key_bindings": {
"use_vim_keybindings_in_code_notes": "Verwende VIM-Tastenkombinationen in Codenotizen (kein Ex-Modus)",
"use_vim_keybindings_in_code_notes": "Vim Tastenbelegung",
"enable_vim_keybindings": "Aktiviere Vim-Tastenkombinationen"
},
"wrap_lines": {
@@ -1439,7 +1439,7 @@
"open-in-a-new-tab": "In neuem Tab öffnen",
"open-in-a-new-split": "In neuem Split öffnen",
"insert-note-after": "Notiz dahinter einfügen",
"insert-child-note": "Unternotiz einfügen",
"insert-child-note": "Untergeordnete Notiz einfügen",
"delete": "Löschen",
"search-in-subtree": "Im Zweig suchen",
"hoist-note": "Notiz-Fokus setzen",
@@ -1558,7 +1558,7 @@
"saved-search-note-refreshed": "Gespeicherte Such-Notiz wurde aktualisiert.",
"hoist-this-note-workspace": "Diese Notiz fokussieren (Arbeitsbereich)",
"refresh-saved-search-results": "Gespeicherte Suchergebnisse aktualisieren",
"create-child-note": "Unternotiz anlegen",
"create-child-note": "Untergeordnete Notiz anlegen",
"unhoist": "Fokus verlassen",
"toggle-sidebar": "Seitenleiste ein-/ausblenden",
"dropping-not-allowed": "Ablegen von Notizen an dieser Stelle ist nicht zulässig.",
@@ -1569,7 +1569,7 @@
"subtree-hidden-tooltip_one": "{{count}} untergeordnete Notiz, die im Baum ausgeblendet ist",
"subtree-hidden-tooltip_other": "{{count}} untergeordnete Notizen, die im Baum ausgeblendet sind",
"subtree-hidden-moved-title": "Zu {{title}} hinzugefügt",
"subtree-hidden-moved-description-collection": "Diese Sammlung blendet ihre Unternotizen im Baum aus.",
"subtree-hidden-moved-description-collection": "Diese Sammlung blendet ihre untergeordneten Notizen im Baum aus.",
"subtree-hidden-moved-description-other": "Untergeordnete Notizen sind im Baum für diese Notiz ausgeblendet."
},
"title_bar_buttons": {
@@ -1600,7 +1600,8 @@
},
"search_result": {
"no_notes_found": "Es wurden keine Notizen mit den angegebenen Suchparametern gefunden.",
"search_not_executed": "Die Suche wurde noch nicht ausgeführt. Klicke oben auf „Suchen“, um die Ergebnisse anzuzeigen."
"search_not_executed": "Die Suche wurde noch nicht ausgeführt.",
"search_now": "Jetzt suchen"
},
"spacer": {
"configure_launchbar": "Starterleiste konfigurieren"
@@ -1728,6 +1729,7 @@
"add-term-to-dictionary": "Begriff \"{{term}}\" zum Wörterbuch hinzufügen",
"cut": "Ausschneiden",
"copy": "Kopieren",
"copy-as-markdown": "Als Markdown kopieren",
"copy-link": "Link kopieren",
"paste": "Einfügen",
"paste-as-plain-text": "Als unformatierten Text einfügen",
@@ -1756,7 +1758,7 @@
},
"note_autocomplete": {
"search-for": "Suche nach \"{{term}}\"",
"create-note": "Erstelle und verlinke Unternotiz \"{{term}}\"",
"create-note": "Erstelle und verlinke untergeordnete Notiz \"{{term}}\"",
"insert-external-link": "Einfügen von Externen Link zu \"{{term}}\"",
"clear-text-field": "Textfeldinhalt löschen",
"show-recent-notes": "Aktuelle Notizen anzeigen",
@@ -1767,7 +1769,7 @@
"quick-edit": "Schnellbearbeitung"
},
"geo-map": {
"create-child-note-title": "Neue Unternotiz anlegen und zur Karte hinzufügen",
"create-child-note-title": "Neue untergeordnete Notiz anlegen und zur Karte hinzufügen",
"create-child-note-instruction": "Auf die Karte klicken, um eine neue Notiz an der Stelle zu erstellen oder Escape drücken um abzubrechen.",
"unable-to-load-map": "Karte konnte nicht geladen werden.",
"create-child-note-text": "Marker hinzufügen"
@@ -1794,149 +1796,6 @@
"close": "Schließen",
"help_title": "Zeige mehr Informationen zu diesem Fenster"
},
"ai_llm": {
"not_started": "Nicht gestartet",
"title": "KI Einstellungen",
"processed_notes": "Verarbeitete Notizen",
"total_notes": "Gesamt Notizen",
"progress": "Fortschritt",
"queued_notes": "Eingereihte Notizen",
"failed_notes": "Fehlgeschlagenen Notizen",
"last_processed": "Zuletzt verarbeitet",
"refresh_stats": "Statistiken neu laden",
"enable_ai_features": "Aktiviere KI/LLM Funktionen",
"enable_ai_description": "Aktiviere KI-Funktionen wie Notizzusammenfassungen, Inhaltserzeugung und andere LLM-Funktionen",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Aktiviere KI/LLM Funktionen",
"enable_ai_desc": "Aktiviere KI-Funktionen wie Notizzusammenfassungen, Inhaltserzeugung und andere LLM-Funktionen",
"provider_configuration": "KI-Anbieterkonfiguration",
"provider_precedence": "Anbieter Priorität",
"provider_precedence_description": "Komma-getrennte Liste von Anbieter in der Reihenfolge ihrer Priorität (z.B. 'openai, anthropic,ollama')",
"temperature": "Temperatur",
"temperature_description": "Regelt die Zufälligkeit in Antworten (0 = deterministisch, 2 = maximale Zufälligkeit)",
"system_prompt": "Systemaufforderung",
"system_prompt_description": "Standard Systemaufforderung für alle KI-Interaktionen",
"openai_configuration": "OpenAI Konfiguration",
"openai_settings": "OpenAI Einstellungen",
"api_key": "API Schlüssel",
"url": "Basis-URL",
"model": "Modell",
"anthropic_settings": "Anthropic Einstellungen",
"partial": "{{ percentage }}% verarbeitet",
"anthropic_api_key_description": "Dein Anthropic API-Key für den Zugriff auf Claude Modelle",
"anthropic_model_description": "Anthropic Claude Modell für Chat-Vervollständigung",
"voyage_settings": "Einstellungen für Voyage AI",
"ollama_url_description": "URL für die Ollama API (Standard: http://localhost:11434)",
"ollama_model_description": "Ollama Modell für Chat-Vervollständigung",
"anthropic_configuration": "Anthropic Konfiguration",
"voyage_configuration": "Voyage AI Konfiguration",
"voyage_url_description": "Standard: https://api.voyageai.com/v1",
"ollama_configuration": "Ollama Konfiguration",
"enable_ollama": "Aktiviere Ollama",
"enable_ollama_description": "Aktiviere Ollama für lokale KI Modell Nutzung",
"ollama_url": "Ollama URL",
"ollama_model": "Ollama Modell",
"refresh_models": "Aktualisiere Modelle",
"refreshing_models": "Aktualisiere...",
"enable_automatic_indexing": "Aktiviere automatische Indizierung",
"rebuild_index": "Index neu aufbauen",
"rebuild_index_error": "Fehler beim Neuaufbau des Index. Prüfe Log für mehr Informationen.",
"retry_failed": "Fehler: Notiz konnte nicht erneut eingereiht werden",
"max_notes_per_llm_query": "Max. Notizen je Abfrage",
"max_notes_per_llm_query_description": "Maximale Anzahl ähnlicher Notizen zum Einbinden als KI Kontext",
"active_providers": "Aktive Anbieter",
"disabled_providers": "Inaktive Anbieter",
"remove_provider": "Entferne Anbieter von Suche",
"restore_provider": "Anbieter zur Suche wiederherstellen",
"similarity_threshold": "Ähnlichkeitsschwelle",
"similarity_threshold_description": "Mindestähnlichkeitswert (0-1) für Notizen, die im Kontext für LLM-Abfragen berücksichtigt werden sollen",
"reprocess_index": "Suchindex neu erstellen",
"reprocessing_index": "Neuerstellung...",
"reprocess_index_started": "Suchindex-Optimierung wurde im Hintergrund gestartet",
"reprocess_index_error": "Fehler beim Wiederaufbau des Suchindex",
"index_rebuild_progress": "Fortschritt der Index-Neuerstellung",
"index_rebuilding": "Optimierung Index ({{percentage}}%)",
"index_rebuild_complete": "Index Optimierung abgeschlossen",
"index_rebuild_status_error": "Fehler bei Überprüfung Status Index Neuerstellung",
"never": "Niemals",
"processing": "Verarbeitung ({{percentage}}%)",
"refreshing": "Aktualisiere...",
"incomplete": "Unvollständig ({{percentage}}%)",
"complete": "Abgeschlossen (100%)",
"auto_refresh_notice": "Auto-Aktualisierung alle {{seconds}} Sekunden",
"note_queued_for_retry": "Notiz in Warteschlange für erneuten Versuch hinzugefügt",
"failed_to_retry_note": "Wiederholungsversuch fehlgeschlagen für Notiz",
"ai_settings": "KI Einstellungen",
"agent": {
"processing": "Verarbeite...",
"thinking": "Nachdenken...",
"loading": "Lade...",
"generating": "Generiere..."
},
"name": "KI",
"openai": "OpenAI",
"use_enhanced_context": "Benutze verbesserten Kontext",
"openai_api_key_description": "Dein OpenAPI-Key für den Zugriff auf den KI-Dienst",
"default_model": "Standardmodell",
"openai_model_description": "Beispiele: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "Basis URL",
"openai_url_description": "Standard: https://api.openai.com/v1",
"anthropic_url_description": "Basis URL für Anthropic API (Standard: https://api.anthropic.com)",
"ollama_settings": "Ollama Einstellungen",
"note_title": "Notiz Titel",
"error": "Fehler",
"last_attempt": "Letzter Versuch",
"actions": "Aktionen",
"retry": "Erneut versuchen",
"retry_queued": "Notiz für weiteren Versuch eingereiht",
"empty_key_warning": {
"anthropic": "Anthropic API-Key ist leer. Bitte gültigen API-Key eingeben.",
"openai": "OpenAI API-Key ist leer. Bitte gültigen API-Key eingeben.",
"voyage": "Voyage API-Key ist leer. Bitte gültigen API-Key eingeben.",
"ollama": "Ollama API-Key ist leer. Bitte gültigen API-Key eingeben."
},
"api_key_tooltip": "API-Key für den Zugriff auf den Dienst",
"failed_to_retry_all": "Wiederholungsversuch für Notizen fehlgeschlagen",
"all_notes_queued_for_retry": "Alle fehlgeschlagenen Notizen wurden zur Wiederholung in die Warteschlange gestellt",
"enhanced_context_description": "Versorgt die KI mit mehr Kontext aus der Notiz und den zugehörigen Notizen, um bessere Antworten zu ermöglichen",
"show_thinking": "Zeige Denkprozess",
"show_thinking_description": "Zeige den Denkprozess der KI",
"enter_message": "Geben Sie Ihre Nachricht ein...",
"error_contacting_provider": "Fehler beim Kontaktieren des KI-Anbieters. Bitte überprüfe die Einstellungen und die Internetverbindung.",
"error_generating_response": "Fehler beim Generieren der KI Antwort",
"index_all_notes": "Indiziere alle Notizen",
"index_status": "Indizierungsstatus",
"indexed_notes": "Indizierte Notizen",
"indexing_stopped": "Indizierung gestoppt",
"indexing_in_progress": "Indizierung in Bearbeitung...",
"last_indexed": "Zuletzt Indiziert",
"note_chat": "Notizen-Chat",
"sources": "Quellen",
"start_indexing": "Starte Indizierung",
"use_advanced_context": "Benutze erweiterten Kontext",
"ollama_no_url": "Ollama ist nicht konfiguriert. Bitte trage eine gültige URL ein.",
"chat": {
"root_note_title": "KI Chats",
"root_note_content": "Diese Notiz enthält gespeicherte KI-Chat-Unterhaltungen.",
"new_chat_title": "Neuer Chat",
"create_new_ai_chat": "Erstelle neuen KI Chat"
},
"create_new_ai_chat": "Erstelle neuen KI Chat",
"configuration_warnings": "Es wurden Probleme mit der KI Konfiguration festgestellt. Bitte überprüfe die Einstellungen.",
"experimental_warning": "Die LLM-Funktionen sind aktuell experimentell - sei an dieser Stelle gewarnt.",
"selected_provider": "Ausgewählter Anbieter",
"selected_provider_description": "Wähle einen KI-Anbieter für Chat- und Vervollständigungsfunktionen",
"select_model": "Wähle Modell...",
"select_provider": "Wähle Anbieter...",
"ai_enabled": "KI Funktionen aktiviert",
"ai_disabled": "KI Funktionen deaktiviert",
"no_models_found_online": "Keine Modelle gefunden. Bitte überprüfe den API-Key und die Einstellungen.",
"no_models_found_ollama": "Kein Ollama Modell gefunden. Bitte prüfe, ob Ollama gerade läuft.",
"error_fetching": "Fehler beim Abrufen der Modelle: {{error}}"
},
"zen_mode": {
"button_exit": "Verlasse Zen Modus"
},
@@ -1971,7 +1830,7 @@
"no_totp_secret_warning": "Um TOTP zu aktivieren, muss zunächst ein TOTP Geheimnis generiert werden.",
"totp_secret_description_warning": "Nach der Generierung des TOTP Geheimnisses ist eine Neuanmeldung mit dem TOTP Geheimnis erforderlich.",
"totp_secret_generated": "TOTP Geheimnis generiert",
"totp_secret_warning": "Bitte speichere das TOTP Geheimnis an einem sicheren Ort. Es wird nicht noch einmal angezeigt.",
"totp_secret_warning": "Bitte speichere das generierte Geheimnis an einem sicheren Ort. Es wird nicht noch einmal angezeigt.",
"totp_secret_regenerate_confirm": "Möchten Sie das TOTP-Geheimnis wirklich neu generieren? Dadurch werden das bisherige TOTP-Geheimnis und alle vorhandenen Wiederherstellungscodes ungültig.",
"recovery_keys_title": "Einmalige Wiederherstellungsschlüssel",
"recovery_keys_description": "Einmalige Wiederherstellungsschlüssel werden verwendet, um sich anzumelden, falls Sie keinen Zugriff auf Ihre Authentifizierungscodes haben.",
@@ -2069,7 +1928,7 @@
"show-hide-columns": "Zeige/verberge Spalten",
"row-insert-above": "Zeile oberhalb einfügen",
"row-insert-below": "Zeile unterhalb einfügen",
"row-insert-child": "Unternotiz einfügen",
"row-insert-child": "Untergeordnete Notiz einfügen",
"add-column-to-the-left": "Spalte links einfügen",
"add-column-to-the-right": "Spalte rechts einfügen",
"edit-column": "Spalte editieren",
@@ -2154,7 +2013,9 @@
"percentage": "%"
},
"pagination": {
"total_notes": "{{count}} Notizen"
"total_notes": "{{count}} Notizen",
"prev_page": "Vorherige Seite",
"next_page": "Nächste Seite"
},
"collections": {
"rendering_error": "Aufgrund eines Fehlers können keine Inhalte angezeigt werden."
@@ -2200,7 +2061,7 @@
"hoisted_badge_title": "Abgesenkt",
"workspace_badge": "Arbeitsfläche",
"scroll_to_top_title": "Zum Anfang der Notiz springen",
"create_new_note": "Neue Unternotiz erstellen",
"create_new_note": "Neue untergeordnete Notiz erstellen",
"empty_hide_archived_notes": "Archivierte Notizen ausblenden"
},
"breadcrumb_badges": {

View File

@@ -47,11 +47,6 @@
"attachment_detail_2": {
"unrecognized_role": "Unrecognised attachment role '{{role}}'."
},
"ai_llm": {
"reprocess_index_started": "Search index optimisation started in the background",
"index_rebuilding": "Optimising index ({{percentage}}%)",
"index_rebuild_complete": "Index optimisation complete"
},
"highlighting": {
"color-scheme": "Colour Scheme"
},

View File

@@ -1204,149 +1204,6 @@
"enable-smooth-scroll": "Enable smooth scrolling",
"app-restart-required": "(a restart of the application is required for the change to take effect)"
},
"ai_llm": {
"not_started": "Not started",
"title": "AI Settings",
"processed_notes": "Processed Notes",
"total_notes": "Total Notes",
"progress": "Progress",
"queued_notes": "Queued Notes",
"failed_notes": "Failed Notes",
"last_processed": "Last Processed",
"refresh_stats": "Refresh Statistics",
"enable_ai_features": "Enable AI/LLM features",
"enable_ai_description": "Enable AI features like note summarization, content generation, and other LLM capabilities",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Enable AI/LLM features",
"enable_ai_desc": "Enable AI features like note summarization, content generation, and other LLM capabilities",
"provider_configuration": "AI Provider Configuration",
"provider_precedence": "Provider Precedence",
"provider_precedence_description": "Comma-separated list of providers in order of precedence (e.g., 'openai,anthropic,ollama')",
"temperature": "Temperature",
"temperature_description": "Controls randomness in responses (0 = deterministic, 2 = maximum randomness)",
"system_prompt": "System Prompt",
"system_prompt_description": "Default system prompt used for all AI interactions",
"openai_configuration": "OpenAI Configuration",
"openai_settings": "OpenAI Settings",
"api_key": "API Key",
"url": "Base URL",
"model": "Model",
"openai_api_key_description": "Your OpenAI API key for accessing their AI services",
"anthropic_api_key_description": "Your Anthropic API key for accessing Claude models",
"default_model": "Default Model",
"openai_model_description": "Examples: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "Base URL",
"openai_url_description": "Default: https://api.openai.com/v1",
"anthropic_settings": "Anthropic Settings",
"anthropic_url_description": "Base URL for the Anthropic API (default: https://api.anthropic.com)",
"anthropic_model_description": "Anthropic Claude models for chat completion",
"voyage_settings": "Voyage AI Settings",
"ollama_settings": "Ollama Settings",
"ollama_url_description": "URL for the Ollama API (default: http://localhost:11434)",
"ollama_model_description": "Ollama model to use for chat completion",
"anthropic_configuration": "Anthropic Configuration",
"voyage_configuration": "Voyage AI Configuration",
"voyage_url_description": "Default: https://api.voyageai.com/v1",
"ollama_configuration": "Ollama Configuration",
"enable_ollama": "Enable Ollama",
"enable_ollama_description": "Enable Ollama for local AI model usage",
"ollama_url": "Ollama URL",
"ollama_model": "Ollama Model",
"refresh_models": "Refresh Models",
"refreshing_models": "Refreshing...",
"enable_automatic_indexing": "Enable Automatic Indexing",
"rebuild_index": "Rebuild Index",
"rebuild_index_error": "Error starting index rebuild. Check logs for details.",
"note_title": "Note Title",
"error": "Error",
"last_attempt": "Last Attempt",
"actions": "Actions",
"retry": "Retry",
"partial": "{{ percentage }}% completed",
"retry_queued": "Note queued for retry",
"retry_failed": "Failed to queue note for retry",
"max_notes_per_llm_query": "Max Notes Per Query",
"max_notes_per_llm_query_description": "Maximum number of similar notes to include in AI context",
"active_providers": "Active Providers",
"disabled_providers": "Disabled Providers",
"remove_provider": "Remove provider from search",
"restore_provider": "Restore provider to search",
"similarity_threshold": "Similarity Threshold",
"similarity_threshold_description": "Minimum similarity score (0-1) for notes to be included in context for LLM queries",
"reprocess_index": "Rebuild Search Index",
"reprocessing_index": "Rebuilding...",
"reprocess_index_started": "Search index optimization started in the background",
"reprocess_index_error": "Error rebuilding search index",
"index_rebuild_progress": "Index Rebuild Progress",
"index_rebuilding": "Optimizing index ({{percentage}}%)",
"index_rebuild_complete": "Index optimization complete",
"index_rebuild_status_error": "Error checking index rebuild status",
"never": "Never",
"processing": "Processing ({{percentage}}%)",
"incomplete": "Incomplete ({{percentage}}%)",
"complete": "Complete (100%)",
"refreshing": "Refreshing...",
"auto_refresh_notice": "Auto-refreshes every {{seconds}} seconds",
"note_queued_for_retry": "Note queued for retry",
"failed_to_retry_note": "Failed to retry note",
"all_notes_queued_for_retry": "All failed notes queued for retry",
"failed_to_retry_all": "Failed to retry notes",
"ai_settings": "AI Settings",
"api_key_tooltip": "API key for accessing the service",
"empty_key_warning": {
"anthropic": "Anthropic API key is empty. Please enter a valid API key.",
"openai": "OpenAI API key is empty. Please enter a valid API key.",
"voyage": "Voyage API key is empty. Please enter a valid API key.",
"ollama": "Ollama API key is empty. Please enter a valid API key."
},
"agent": {
"processing": "Processing...",
"thinking": "Thinking...",
"loading": "Loading...",
"generating": "Generating..."
},
"name": "AI",
"openai": "OpenAI",
"use_enhanced_context": "Use enhanced context",
"enhanced_context_description": "Provides the AI with more context from the note and its related notes for better responses",
"show_thinking": "Show thinking",
"show_thinking_description": "Show the AI's chain of thought process",
"enter_message": "Enter your message...",
"error_contacting_provider": "Error contacting AI provider. Please check your settings and internet connection.",
"error_generating_response": "Error generating AI response",
"index_all_notes": "Index All Notes",
"index_status": "Index Status",
"indexed_notes": "Indexed Notes",
"indexing_stopped": "Indexing stopped",
"indexing_in_progress": "Indexing in progress...",
"last_indexed": "Last Indexed",
"note_chat": "Note Chat",
"sources": "Sources",
"start_indexing": "Start Indexing",
"use_advanced_context": "Use Advanced Context",
"ollama_no_url": "Ollama is not configured. Please enter a valid URL.",
"chat": {
"root_note_title": "AI Chats",
"root_note_content": "This note contains your saved AI chat conversations.",
"new_chat_title": "New Chat",
"create_new_ai_chat": "Create new AI Chat"
},
"create_new_ai_chat": "Create new AI Chat",
"configuration_warnings": "There are some issues with your AI configuration. Please check your settings.",
"experimental_warning": "The LLM feature is currently experimental - you have been warned.",
"selected_provider": "Selected Provider",
"selected_provider_description": "Choose the AI provider for chat and completion features",
"select_model": "Select model...",
"select_provider": "Select provider...",
"ai_enabled": "AI features enabled",
"ai_disabled": "AI features disabled",
"no_models_found_online": "No models found. Please check your API key and settings.",
"no_models_found_ollama": "No Ollama models found. Please check if Ollama is running.",
"error_fetching": "Error fetching models: {{error}}"
},
"zoom_factor": {
"title": "Zoom Factor (desktop build only)",
"description": "Zooming can be controlled with CTRL+- and CTRL+= shortcuts as well."
@@ -1725,7 +1582,8 @@
"ai-chat": "AI Chat",
"task-list": "Task List",
"new-feature": "New",
"collections": "Collections"
"collections": "Collections",
"spreadsheet": "Spreadsheet"
},
"protect_note": {
"toggle-on": "Protect the note",
@@ -1824,7 +1682,8 @@
},
"search_result": {
"no_notes_found": "No notes have been found for given search parameters.",
"search_not_executed": "Search has not been executed yet. Click on \"Search\" button above to see the results."
"search_not_executed": "Search has not been executed yet.",
"search_now": "Search now"
},
"spacer": {
"configure_launchbar": "Configure Launchbar"
@@ -1952,6 +1811,7 @@
"add-term-to-dictionary": "Add \"{{term}}\" to dictionary",
"cut": "Cut",
"copy": "Copy",
"copy-as-markdown": "Copy as Markdown",
"copy-link": "Copy link",
"paste": "Paste",
"paste-as-plain-text": "Paste as plain text",

View File

@@ -669,7 +669,7 @@
"button_exit": "Salir del modo Zen"
},
"sync_status": {
"unknown": "<p>El estado de sincronización será conocido una vez que el siguiente intento de sincronización comience.</p><p>Dé clic para activar la sincronización ahora</p>",
"unknown": "<p>El estado de sincronización será conocido una vez que el siguiente intento de sincronización comience.</p><p>Dé clic para activar la sincronización ahora.</p>",
"connected_with_changes": "<p>Conectado al servidor de sincronización. <br>Hay cambios pendientes que aún no se han sincronizado.</p><p>Dé clic para activar la sincronización.</p>",
"connected_no_changes": "<p>Conectado al servidor de sincronización.<br>Todos los cambios ya han sido sincronizados.</p><p>Dé clic para activar la sincronización.</p>",
"disconnected_with_changes": "<p>El establecimiento de la conexión con el servidor de sincronización no ha tenido éxito.<br>Hay algunos cambios pendientes que aún no se han sincronizado.</p><p>Dé clic para activar la sincronización.</p>",
@@ -760,7 +760,7 @@
"mobile_detail_menu": {
"insert_child_note": "Insertar subnota",
"delete_this_note": "Eliminar esta nota",
"error_cannot_get_branch_id": "No se puede obtener el branchID del notePath '{{notePath}}'",
"error_cannot_get_branch_id": "No se puede obtener el branchId del notePath '{{notePath}}'",
"error_unrecognized_command": "Comando no reconocido {{command}}",
"note_revisions": "Revisiones de notas",
"backlinks": "Vínculos de retroceso",
@@ -1012,7 +1012,7 @@
"no_attachments": "Esta nota no tiene archivos adjuntos."
},
"book": {
"no_children_help": "Esta nota de tipo libro no tiene ninguna subnota así que no hay nada que mostrar. Véa la <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> para más detalles.",
"no_children_help": "Esta colección no tiene ninguna subnota así que no hay nada que mostrar.",
"drag_locked_title": "Bloqueado para edición",
"drag_locked_message": "No se permite Arrastrar pues la colección está bloqueada para edición."
},
@@ -1175,149 +1175,6 @@
"light_theme": "Heredado (Claro)",
"dark_theme": "Heredado (Oscuro)"
},
"ai_llm": {
"not_started": "No iniciado",
"title": "IA y ajustes de embeddings",
"processed_notes": "Notas procesadas",
"total_notes": "Notas totales",
"progress": "Progreso",
"queued_notes": "Notas en fila",
"failed_notes": "Notas fallidas",
"last_processed": "Última procesada",
"refresh_stats": "Recargar estadísticas",
"enable_ai_features": "Habilitar características IA/LLM",
"enable_ai_description": "Habilitar características de IA como resumen de notas, generación de contenido y otras capacidades LLM",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Habilitar características IA/LLM",
"enable_ai_desc": "Habilitar características de IA como resumen de notas, generación de contenido y otras capacidades LLM",
"provider_configuration": "Configuración de proveedor de IA",
"provider_precedence": "Precedencia de proveedor",
"provider_precedence_description": "Lista de proveedores en orden de precedencia separada por comas (p.e., 'openai,anthropic,ollama')",
"temperature": "Temperatura",
"temperature_description": "Controla la aleatoriedad de las respuestas (0 = determinista, 2 = aleatoriedad máxima)",
"system_prompt": "Mensaje de sistema",
"system_prompt_description": "Mensaje de sistema predeterminado utilizado para todas las interacciones de IA",
"openai_configuration": "Configuración de OpenAI",
"openai_settings": "Ajustes de OpenAI",
"api_key": "Clave API",
"url": "URL base",
"model": "Modelo",
"openai_api_key_description": "Tu clave API de OpenAI para acceder a sus servicios de IA",
"anthropic_api_key_description": "Tu clave API de Anthropic para acceder a los modelos Claude",
"default_model": "Modelo por defecto",
"openai_model_description": "Ejemplos: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "URL base",
"openai_url_description": "Por defecto: https://api.openai.com/v1",
"anthropic_settings": "Ajustes de Anthropic",
"anthropic_url_description": "URL base para la API de Anthropic (por defecto: https://api.anthropic.com)",
"anthropic_model_description": "Modelos Claude de Anthropic para el completado de chat",
"voyage_settings": "Ajustes de Voyage AI",
"ollama_settings": "Ajustes de Ollama",
"ollama_url_description": "URL para la API de Ollama (por defecto: http://localhost:11434)",
"ollama_model_description": "Modelo de Ollama a usar para el completado de chat",
"anthropic_configuration": "Configuración de Anthropic",
"voyage_configuration": "Configuración de Voyage AI",
"voyage_url_description": "Por defecto: https://api.voyageai.com/v1",
"ollama_configuration": "Configuración de Ollama",
"enable_ollama": "Habilitar Ollama",
"enable_ollama_description": "Habilitar Ollama para uso de modelo de IA local",
"ollama_url": "URL de Ollama",
"ollama_model": "Modelo de Ollama",
"refresh_models": "Refrescar modelos",
"refreshing_models": "Refrescando...",
"enable_automatic_indexing": "Habilitar indexado automático",
"rebuild_index": "Recrear índice",
"rebuild_index_error": "Error al comenzar la reconstrucción del índice. Consulte los registros para más detalles.",
"note_title": "Título de nota",
"error": "Error",
"last_attempt": "Último intento",
"actions": "Acciones",
"retry": "Reintentar",
"partial": "{{ percentage }}% completado",
"retry_queued": "Nota en la cola para reintento",
"retry_failed": "Hubo un fallo al poner en la cola a la nota para reintento",
"max_notes_per_llm_query": "Máximo de notas por consulta",
"max_notes_per_llm_query_description": "Número máximo de notas similares a incluir en el contexto IA",
"active_providers": "Proveedores activos",
"disabled_providers": "Proveedores deshabilitados",
"remove_provider": "Eliminar proveedor de la búsqueda",
"restore_provider": "Restaurar proveedor a la búsqueda",
"similarity_threshold": "Bias de similaridad",
"similarity_threshold_description": "Puntuación de similaridad mínima (0-1) para incluir notas en el contexto para consultas LLM",
"reprocess_index": "Reconstruir el índice de búsqueda",
"reprocessing_index": "Reconstruyendo...",
"reprocess_index_started": "La optimización de índice de búsqueda comenzó en segundo plano",
"reprocess_index_error": "Error al reconstruir el índice de búsqueda",
"index_rebuild_progress": "Progreso de reconstrucción de índice",
"index_rebuilding": "Optimizando índice ({{percentage}}%)",
"index_rebuild_complete": "Optimización de índice completa",
"index_rebuild_status_error": "Error al comprobar el estado de reconstrucción del índice",
"never": "Nunca",
"processing": "Procesando ({{percentage}}%)",
"incomplete": "Incompleto ({{percentage}}%)",
"complete": "Completo (100%)",
"refreshing": "Refrescando...",
"auto_refresh_notice": "Refrescar automáticamente cada {{seconds}} segundos",
"note_queued_for_retry": "Nota en la cola para reintento",
"failed_to_retry_note": "Hubo un fallo al reintentar nota",
"all_notes_queued_for_retry": "Todas las notas con fallo agregadas a la cola para reintento",
"failed_to_retry_all": "Hubo un fallo al reintentar notas",
"ai_settings": "Ajustes de IA",
"api_key_tooltip": "Clave API para acceder al servicio",
"empty_key_warning": {
"anthropic": "La clave API de Anthropic está vacía. Por favor, ingrese una clave API válida.",
"openai": "La clave API de OpenAI está vacía. Por favor, ingrese una clave API válida.",
"voyage": "La clave API de Voyage está vacía. Por favor, ingrese una clave API válida.",
"ollama": "La clave API de Ollama está vacía. Por favor, ingrese una clave API válida."
},
"agent": {
"processing": "Procesando...",
"thinking": "Pensando...",
"loading": "Cargando...",
"generating": "Generando..."
},
"name": "IA",
"openai": "OpenAI",
"use_enhanced_context": "Utilizar contexto mejorado",
"enhanced_context_description": "Provee a la IA con más contexto de la nota y sus notas relacionadas para obtener mejores respuestas",
"show_thinking": "Mostrar pensamiento",
"show_thinking_description": "Mostrar la cadena del proceso de pensamiento de la IA",
"enter_message": "Ingrese su mensaje...",
"error_contacting_provider": "Error al contactar con su proveedor de IA. Por favor compruebe sus ajustes y conexión a internet.",
"error_generating_response": "Error al generar respuesta de IA",
"index_all_notes": "Indexar todas las notas",
"index_status": "Estado de índice",
"indexed_notes": "Notas indexadas",
"indexing_stopped": "Indexado detenido",
"indexing_in_progress": "Indexado en progreso...",
"last_indexed": "Último indexado",
"note_chat": "Chat de nota",
"sources": "Fuentes",
"start_indexing": "Comenzar indexado",
"use_advanced_context": "Usar contexto avanzado",
"ollama_no_url": "Ollama no está configurado. Por favor ingrese una URL válida.",
"chat": {
"root_note_title": "Chats de IA",
"root_note_content": "Esta nota contiene tus conversaciones de chat de IA guardadas.",
"new_chat_title": "Nuevo chat",
"create_new_ai_chat": "Crear nuevo chat de IA"
},
"create_new_ai_chat": "Crear nuevo chat de IA",
"configuration_warnings": "Hay algunos problemas con su configuración de IA. Por favor compruebe sus ajustes.",
"experimental_warning": "La característica de LLM aún es experimental - ha sido advertido.",
"selected_provider": "Proveedor seleccionado",
"selected_provider_description": "Elija el proveedor de IA para el chat y características de completado",
"select_model": "Seleccionar modelo...",
"select_provider": "Seleccionar proveedor...",
"ai_enabled": "Características de IA activadas",
"ai_disabled": "Características de IA desactivadas",
"no_models_found_online": "No se encontraron modelos. Por favor, comprueba tu clave de API y la configuración.",
"no_models_found_ollama": "No se encontraron modelos de Ollama. Por favor, comprueba si Ollama se está ejecutando.",
"error_fetching": "Error al obtener los modelos: {{error}}"
},
"zoom_factor": {
"title": "Factor de zoom (solo versión de escritorio)",
"description": "El zoom también se puede controlar con los atajos CTRL+- y CTRL+=."
@@ -1560,7 +1417,7 @@
"shortcuts": {
"keyboard_shortcuts": "Atajos de teclado",
"multiple_shortcuts": "Varios atajos para la misma acción se pueden separar mediante comas.",
"electron_documentation": "Véa la <a href=\"https://www.electronjs.org/docs/latest/api/accelerator\">documentación de Electron </a> para los modificadores y códigos de tecla disponibles.",
"electron_documentation": "Consulte la <a href=\"https://www.electronjs.org/docs/latest/api/accelerator\">documentación de Electron</a> para los modificadores y códigos de tecla disponibles.",
"type_text_to_filter": "Escriba texto para filtrar los accesos directos...",
"action_name": "Nombre de la acción",
"shortcuts": "Atajos",
@@ -1826,7 +1683,7 @@
"no_headings": "Sin encabezados."
},
"watched_file_update_status": {
"file_last_modified": "Archivo <code class=\"file-path\"></code> ha sido modificado por última vez en<span class=\"file-last-modified\"></span>.",
"file_last_modified": "El archivo <code class=\"file-path\"></code> ha sido modificado por última vez en <span class=\"file-last-modified\"></span>.",
"upload_modified_file": "Subir archivo modificado",
"ignore_this_change": "Ignorar este cambio"
},
@@ -1921,6 +1778,7 @@
"add-term-to-dictionary": "Agregar \"{{term}}\" al diccionario",
"cut": "Cortar",
"copy": "Copiar",
"copy-as-markdown": "Copiar como markdown",
"copy-link": "Copiar enlace",
"paste": "Pegar",
"paste-as-plain-text": "Pegar como texto plano",
@@ -2050,7 +1908,8 @@
"max-nesting-depth": "Máxima profundidad de anidamiento:",
"vector_light": "Vector (claro)",
"vector_dark": "Vector (oscuro)",
"raster": "Trama"
"raster": "Trama",
"show-labels": "Mostrar nombres de marcadores"
},
"table_context_menu": {
"delete_row": "Eliminar fila"
@@ -2158,7 +2017,9 @@
"percentage": "%"
},
"pagination": {
"total_notes": "{{count}} notas"
"total_notes": "{{count}} notas",
"prev_page": "Página anterior",
"next_page": "Página siguiente"
},
"presentation_view": {
"edit-slide": "Editar este slide",

View File

@@ -1485,7 +1485,6 @@
"beta-feature": "Beta",
"task-list": "Liste de tâches",
"book": "Collection",
"ai-chat": "Chat IA",
"new-feature": "Nouveau",
"collections": "Collections"
},
@@ -1690,6 +1689,7 @@
"add-term-to-dictionary": "Ajouter «{{term}}» au dictionnaire",
"cut": "Couper",
"copy": "Copier",
"copy-as-markdown": "Copier en markdown",
"copy-link": "Copier le lien",
"paste": "Coller",
"paste-as-plain-text": "Coller comme texte brut",
@@ -1798,149 +1798,6 @@
"close": "Fermer",
"help_title": "Afficher plus d'informations sur cet écran"
},
"ai_llm": {
"not_started": "Non démarré",
"title": "Paramètres IA",
"processed_notes": "Notes traitées",
"anthropic_url_description": "URL de base pour l'API Anthropic (par défaut : https ://api.anthropic.com)",
"anthropic_model_description": "Modèles Anthropic Claude pour la complétion",
"voyage_settings": "Réglages d'IA Voyage",
"ollama_settings": "Réglages Ollama",
"ollama_url_description": "URL pour l'API Ollama (par défaut: http://localhost:11434)",
"ollama_model_description": "Model Ollama utilisé pour la complétion",
"anthropic_configuration": "Configuration Anthropic",
"voyage_configuration": "Configuration IA Voyage",
"voyage_url_description": "Défaut: https://api.voyageai.com/v1",
"ollama_configuration": "Configuration Ollama",
"total_notes": "Notes totales",
"progress": "Progrès",
"queued_notes": "Notes dans la file d'attente",
"refresh_stats": "Rafraîchir les statistiques",
"enable_ai_features": "Activer les fonctionnalités IA/LLM",
"enable_ai_description": "Activer les fonctionnalités IA telles que le résumé des notes, la génération de contenu et autres fonctionnalités LLM",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Activer les fonctionnalités IA/LLM",
"enable_ai_desc": "Activer les fonctionnalités IA telles que le résumé des notes, la génération de contenu et autres fonctionnalités LLM",
"provider_configuration": "Configuration du fournisseur IA",
"provider_precedence_description": "Liste de fournisseurs séparés par virgule, par ordre de préférence (ex. 'openai,anthopic,ollama')",
"temperature": "Température",
"temperature_description": "Contrôle de l'aléatoirité dans les réponses (0 = déterministe, 2 = hasard maximum)",
"system_prompt": "Prompt système",
"system_prompt_description": "Prompt système par défaut pour toutes les intéractions IA",
"openai_configuration": "Configuration OpenAI",
"openai_settings": "Options OpenAI",
"api_key": "Clef API",
"url": "URL de base",
"model": "Modèle",
"openai_api_key_description": "Votre clef API OpenAI pour accéder à leurs services IA",
"anthropic_api_key_description": "Votre clef API Anthropic pour accéder aux modèles Claude",
"default_model": "Modèle par défaut",
"openai_model_description": "Exemples : gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "URL de base",
"openai_url_description": "Défaut : https://api.openai.com/v1",
"anthropic_settings": "Réglages Anthropic",
"enable_ollama": "Activer Ollama",
"enable_ollama_description": "Activer Ollama comme modèle d'IA local",
"ollama_url": "URL Ollama",
"ollama_model": "Modèle Ollama",
"refresh_models": "Rafraîchir les modèles",
"refreshing_models": "Mise à jour...",
"enable_automatic_indexing": "Activer l'indexage automatique",
"rebuild_index": "Rafraîchir l'index",
"rebuild_index_error": "Erreur dans le démarrage du rafraichissement de l'index. Veuillez consulter les logs pour plus de détails.",
"note_title": "Titre de la note",
"error": "Erreur",
"last_attempt": "Dernier essai",
"actions": "Actions",
"retry": "Réessayer",
"partial": "Complété à {{ percentage }}%",
"retry_queued": "Note ajoutée à la file d'attente",
"retry_failed": "Echec de l'ajout de la note à la file d'attente",
"max_notes_per_llm_query": "Notes maximum par requête",
"max_notes_per_llm_query_description": "Nombre maximum de notes similaires à inclure dans le contexte IA",
"active_providers": "Fournisseurs actifs",
"disabled_providers": "Fournisseurs désactivés",
"remove_provider": "Retirer le fournisseur de la recherche",
"similarity_threshold": "Seuil de similarité",
"similarity_threshold_description": "Seuil de similarité minimum (0-1) pour que inclure les notes dans le contexte d'une requête IA",
"reprocess_index": "Rafraîchir l'index de recherche",
"reprocessing_index": "Mise à jour...",
"reprocess_index_started": "L'optimisation de l'indice de recherche à commencer en arrière-plan",
"reprocess_index_error": "Erreur dans le rafraichissement de l'indice de recherche",
"failed_notes": "Notes en erreur",
"last_processed": "Dernier traitement",
"restore_provider": "Restaurer le fournisseur de recherche",
"index_rebuild_progress": "Progression de la reconstruction de l'index",
"index_rebuilding": "Optimisation de l'index ({{percentage}}%)",
"index_rebuild_complete": "Optimisation de l'index terminée",
"index_rebuild_status_error": "Erreur lors de la vérification de l'état de reconstruction de l'index",
"provider_precedence": "Priorité du fournisseur",
"never": "Jamais",
"processing": "Traitement en cours ({{percentage}}%)",
"incomplete": "Incomplet ({{percentage}}%)",
"complete": "Terminé (100%)",
"refreshing": "Mise à jour...",
"auto_refresh_notice": "Actualisation automatique toutes les {{seconds}} secondes",
"note_queued_for_retry": "Note mise en file d'attente pour une nouvelle tentative",
"failed_to_retry_note": "Échec de la nouvelle tentative de note",
"all_notes_queued_for_retry": "Toutes les notes ayant échoué sont mises en file d'attente pour une nouvelle tentative",
"failed_to_retry_all": "Échec du ré essai des notes",
"ai_settings": "Paramètres IA",
"api_key_tooltip": "Clé API pour accéder au service",
"empty_key_warning": {
"anthropic": "La clé API Anthropic est vide. Veuillez saisir une clé API valide.",
"openai": "La clé API OpenAI est vide. Veuillez saisir une clé API valide.",
"voyage": "La clé API Voyage est vide. Veuillez saisir une clé API valide.",
"ollama": "La clé API Ollama est vide. Veuillez saisir une clé API valide."
},
"agent": {
"processing": "Traitement...",
"thinking": "Réflexion...",
"loading": "Chargement...",
"generating": "Génération..."
},
"name": "IA",
"openai": "OpenAI",
"use_enhanced_context": "Utiliser un contexte amélioré",
"enhanced_context_description": "Fournit à l'IA plus de contexte à partir de la note et de ses notes associées pour de meilleures réponses",
"show_thinking": "Montrer la réflexion",
"show_thinking_description": "Montrer la chaîne de pensée de l'IA",
"enter_message": "Entrez votre message...",
"error_contacting_provider": "Erreur lors de la connexion au fournisseur d'IA. Veuillez vérifier vos paramètres et votre connexion Internet.",
"error_generating_response": "Erreur lors de la génération de la réponse de l'IA",
"index_all_notes": "Indexer toutes les notes",
"index_status": "Statut de l'index",
"indexed_notes": "Notes indexées",
"indexing_stopped": "Arrêt de l'indexation",
"indexing_in_progress": "Indexation en cours...",
"last_indexed": "Dernière indexée",
"note_chat": "Note discussion",
"sources": "Sources",
"start_indexing": "Démarrage de l'indexation",
"use_advanced_context": "Utiliser le contexte avancé",
"ollama_no_url": "Ollama n'est pas configuré. Veuillez saisir une URL valide.",
"chat": {
"root_note_title": "Discussions IA",
"root_note_content": "Cette note contient vos conversations de chat IA enregistrées.",
"new_chat_title": "Nouvelle discussion",
"create_new_ai_chat": "Créer une nouvelle discussion IA"
},
"create_new_ai_chat": "Créer une nouvelle discussion IA",
"configuration_warnings": "Il y a quelques problèmes avec la configuration de votre IA. Veuillez vérifier vos paramètres.",
"experimental_warning": "La fonctionnalité LLM est actuellement expérimentale vous êtes prévenu.",
"selected_provider": "Fournisseur sélectionné",
"selected_provider_description": "Choisissez le fournisseur dIA pour les fonctionnalités de discussion et de complétion",
"select_model": "Sélectionner le modèle...",
"select_provider": "Sélectionnez un fournisseur...",
"ai_enabled": "Fonctionnalités d'IA activées",
"ai_disabled": "Fonctionnalités d'IA désactivées",
"no_models_found_online": "Aucun modèle trouvé. Veuillez vérifier votre clé API et vos paramètres.",
"no_models_found_ollama": "Aucun modèle Ollama trouvé. Veuillez vérifier si Ollama est en cours d'exécution.",
"error_fetching": "Erreur lors de la récupération des modèles : {{error}}"
},
"ui-performance": {
"title": "Performance",
"enable-motion": "Activer les transitions et animations",

View File

@@ -1193,149 +1193,6 @@
"enable-smooth-scroll": "Cumasaigh scrollú réidh",
"app-restart-required": "(tá atosú an fheidhmchláir ag teastáil chun an t-athrú a chur i bhfeidhm)"
},
"ai_llm": {
"not_started": "Níor tosaíodh",
"title": "Socruithe AI",
"processed_notes": "Nótaí Próiseáilte",
"total_notes": "Nótaí Iomlána",
"progress": "Dul Chun Cinn",
"queued_notes": "Nótaí i gCiú",
"failed_notes": "Nótaí Theipthe",
"last_processed": "Próiseáilte Deiridh",
"refresh_stats": "Athnuachan Staitisticí",
"enable_ai_features": "Cumasaigh gnéithe AI/LLM",
"enable_ai_description": "Cumasaigh gnéithe AI cosúil le achoimre nótaí, giniúint ábhair, agus cumais LLM eile",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Cumasaigh gnéithe AI/LLM",
"enable_ai_desc": "Cumasaigh gnéithe AI cosúil le achoimre nótaí, giniúint ábhair, agus cumais LLM eile",
"provider_configuration": "Cumraíocht Soláthraí AI",
"provider_precedence": "Tosaíocht Soláthraí",
"provider_precedence_description": "Liosta soláthraithe scartha le camóga in ord tosaíochta (m.sh., 'openai, anthropic, ollama')",
"temperature": "Teocht",
"temperature_description": "Rialaíonn randamacht i bhfreagraí (0 = cinntitheach, 2 = uasmhéid randamachta)",
"system_prompt": "Pras Córais",
"system_prompt_description": "Leid réamhshocraithe an chórais a úsáidtear le haghaidh gach idirghníomhaíocht AI",
"openai_configuration": "Cumraíocht OpenAI",
"openai_settings": "Socruithe OpenAI",
"api_key": "Eochair API",
"url": "Bun-URL",
"model": "Samhail",
"openai_api_key_description": "D'eochair API OpenAI chun rochtain a fháil ar a gcuid seirbhísí AI",
"anthropic_api_key_description": "D'eochair API Anthropic chun rochtain a fháil ar mhúnlaí Claude",
"default_model": "Samhail Réamhshocraithe",
"openai_model_description": "Samplaí: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "Bun-URL",
"openai_url_description": "Réamhshocrú: https://api.openai.com/v1",
"anthropic_settings": "Socruithe Anthropic",
"anthropic_url_description": "Bun-URL don Anthropic API (réamhshocraithe: https://api.anthropic.com)",
"anthropic_model_description": "Samhlacha Anthropic Claude le haghaidh comhlánú comhrá",
"voyage_settings": "Socruithe Voyage AI",
"ollama_settings": "Socruithe Ollama",
"ollama_url_description": "URL don Ollama API (réamhshocrú: http://localhost:11434)",
"ollama_model_description": "Samhail Ollama le húsáid le haghaidh comhrá a chríochnú",
"anthropic_configuration": "Cumraíocht Anthropic",
"voyage_configuration": "Cumraíocht AI Voyage",
"voyage_url_description": "Réamhshocrú: https://api.voyageai.com/v1",
"ollama_configuration": "Cumraíocht Ollama",
"enable_ollama": "Cumasaigh Ollama",
"enable_ollama_description": "Cumasaigh Ollama le haghaidh úsáide áitiúla samhail AI",
"ollama_url": "URL Ollama",
"ollama_model": "Samhail Ollama",
"refresh_models": "Athnuachan Samhlacha",
"refreshing_models": "Ag athnuachan...",
"enable_automatic_indexing": "Cumasaigh Innéacsú Uathoibríoch",
"rebuild_index": "Innéacs Athchóirithe",
"rebuild_index_error": "Earráid ag tosú atógáil an innéacs. Seiceáil na logaí le haghaidh sonraí.",
"note_title": "Teideal an Nóta",
"error": "Earráid",
"last_attempt": "Iarracht Dheiridh",
"actions": "Gníomhartha",
"retry": "Déan iarracht eile",
"partial": "{{ percentage }}% críochnaithe",
"retry_queued": "Nóta curtha i scuaine le haghaidh athiarrachta",
"retry_failed": "Theip ar an nóta a chur sa scuaine le haghaidh athiarrachta",
"max_notes_per_llm_query": "Uasmhéid Nótaí In Aghaidh an Fhiosrúcháin",
"max_notes_per_llm_query_description": "Uasmhéid nótaí comhchosúla le cur san áireamh i gcomhthéacs na hintleachta saorga",
"active_providers": "Soláthraithe Gníomhacha",
"disabled_providers": "Soláthraithe faoi Mhíchumas",
"remove_provider": "Bain an soláthraí as an gcuardach",
"restore_provider": "Athchóirigh soláthraí chuig an gcuardach",
"similarity_threshold": "Tairseach Cosúlachta",
"similarity_threshold_description": "Scór cosúlachta íosta (0-1) le go n-áireofar nótaí i gcomhthéacs fiosrúcháin LLM",
"reprocess_index": "Athchruthaigh Innéacs Cuardaigh",
"reprocessing_index": "Atógáil...",
"reprocess_index_started": "Cuireadh tús le hoptamú innéacs cuardaigh sa chúlra",
"reprocess_index_error": "Earráid ag atógáil innéacs cuardaigh",
"index_rebuild_progress": "Dul Chun Cinn Athchóirithe Innéacs",
"index_rebuilding": "Innéacs optamaithe ({{percentage}}%)",
"index_rebuild_complete": "Uasmhéadú innéacs críochnaithe",
"index_rebuild_status_error": "Earráid ag seiceáil stádas athchóirithe innéacs",
"never": "Choíche",
"processing": "Próiseáil ({{percentage}}%)",
"incomplete": "Neamhchríochnaithe ({{percentage}}%)",
"complete": "Críochnaithe (100%)",
"refreshing": "Ag athnuachan...",
"auto_refresh_notice": "Athnuachan uathoibríoch gach {{seconds}} soicind",
"note_queued_for_retry": "Nóta curtha i scuaine le haghaidh athiarrachta",
"failed_to_retry_note": "Theip ar an nóta a athdhéanamh",
"all_notes_queued_for_retry": "Gach nóta nár éirigh leo curtha i scuaine le haghaidh athiarrachta",
"failed_to_retry_all": "Theip ar athiarracht nótaí",
"ai_settings": "Socruithe AI",
"api_key_tooltip": "Eochair API chun rochtain a fháil ar an tseirbhís",
"empty_key_warning": {
"anthropic": "Tá eochair API Anthropic folamh. Cuir isteach eochair API bhailí le do thoil.",
"openai": "Tá eochair API OpenAI folamh. Cuir isteach eochair API bhailí le do thoil.",
"voyage": "Tá eochair API Voyage folamh. Cuir isteach eochair API bhailí le do thoil.",
"ollama": "Tá eochair API Ollama folamh. Cuir isteach eochair API bhailí le do thoil."
},
"agent": {
"processing": "Ag próiseáil...",
"thinking": "Ag smaoineamh...",
"loading": "Ag lódáil...",
"generating": "Ag giniúint..."
},
"name": "Intleacht Shaorga",
"openai": "OpenAI",
"use_enhanced_context": "Úsáid comhthéacs feabhsaithe",
"enhanced_context_description": "Tugann sé níos mó comhthéacs don AI ón nóta agus a nótaí gaolmhara le haghaidh freagraí níos fearr",
"show_thinking": "Taispeáin smaointeoireacht",
"show_thinking_description": "Taispeáin slabhra phróiseas smaointeoireachta na hintleachta saorga",
"enter_message": "Cuir isteach do theachtaireacht...",
"error_contacting_provider": "Earráid ag teacht i dteagmháil leis an soláthraí AI. Seiceáil do shocruithe agus do nasc idirlín le do thoil.",
"error_generating_response": "Earráid ag giniúint freagra AI",
"index_all_notes": "Innéacs na Nótaí Uile",
"index_status": "Stádas Innéacs",
"indexed_notes": "Nótaí Innéacsaithe",
"indexing_stopped": "Stopadh an innéacsú",
"indexing_in_progress": "Innéacsú ar siúl...",
"last_indexed": "Innéacsaithe Deiridh",
"note_chat": "Comhrá Nótaí",
"sources": "Foinsí",
"start_indexing": "Tosaigh ag Innéacsú",
"use_advanced_context": "Úsáid Comhthéacs Ardleibhéil",
"ollama_no_url": "Níl Ollama cumraithe. Cuir isteach URL bailí le do thoil.",
"chat": {
"root_note_title": "Comhráite AI",
"root_note_content": "Tá do chomhráite comhrá AI sábháilte sa nóta seo.",
"new_chat_title": "Comhrá Nua",
"create_new_ai_chat": "Cruthaigh Comhrá AI nua"
},
"create_new_ai_chat": "Cruthaigh Comhrá AI nua",
"configuration_warnings": "Tá roinnt fadhbanna le do chumraíocht AI. Seiceáil do shocruithe le do thoil.",
"experimental_warning": "Tá an ghné LLM turgnamhach faoi láthair - tugadh rabhadh duit.",
"selected_provider": "Soláthraí Roghnaithe",
"selected_provider_description": "Roghnaigh an soláthraí AI le haghaidh gnéithe comhrá agus comhlánaithe",
"select_model": "Roghnaigh samhail...",
"select_provider": "Roghnaigh soláthraí...",
"ai_enabled": "Gnéithe AI cumasaithe",
"ai_disabled": "Gnéithe AI díchumasaithe",
"no_models_found_online": "Níor aimsíodh aon mhúnlaí. Seiceáil deochair API agus do shocruithe le do thoil.",
"no_models_found_ollama": "Níor aimsíodh aon mhúnlaí Ollama. Seiceáil le do thoil an bhfuil Ollama ag rith.",
"error_fetching": "Earráid ag fáil samhlacha: {{error}}"
},
"zoom_factor": {
"title": "Fachtóir Súmáil (leagan deisce amháin)",
"description": "Is féidir súmáil a rialú le haicearraí CTRL+- agus CTRL+= chomh maith."
@@ -1822,7 +1679,8 @@
},
"search_result": {
"no_notes_found": "Ní bhfuarthas aon nótaí do na paraiméadair chuardaigh tugtha.",
"search_not_executed": "Níl an cuardach curtha i gcrích fós. Cliceáil ar an gcnaipe \"Cuardaigh\" thuas chun na torthaí a fheiceáil."
"search_not_executed": "Níl an cuardach curtha i gcrích fós.",
"search_now": "Cuardaigh anois"
},
"spacer": {
"configure_launchbar": "Cumraigh an Barra Seoladh"
@@ -1950,6 +1808,7 @@
"add-term-to-dictionary": "Cuir \"{{term}}\" leis an bhfoclóir",
"cut": "Gearr",
"copy": "Cóipeáil",
"copy-as-markdown": "Cóipeáil mar markdown",
"copy-link": "Cóipeáil nasc",
"paste": "Greamaigh",
"paste-as-plain-text": "Greamaigh mar théacs simplí",

File diff suppressed because it is too large Load Diff

View File

@@ -83,7 +83,10 @@
"erase_notes_warning": "Hapus catatan secara permanen (tidak bisa dikembalikan), termasuk semua duplikat. Aksi akan memaksa aplikasi untuk mengulang kembali.",
"notes_to_be_deleted": "Catatan-catatan berikut akan dihapuskan ({{notesCount}})",
"no_note_to_delete": "Tidak ada Catatan yang akan dihapus (hanya duplikat).",
"broken_relations_to_be_deleted": "Hubungan berikut akan diputus dan dihapus ({{ relationCount}})"
"broken_relations_to_be_deleted": "Hubungan berikut akan diputus dan dihapus ({{ relationCount}})",
"cancel": "Batalkan",
"ok": "Setuju",
"deleted_relation_text": "Catatan {{- note}} (yang akan dihapus) dirujuk oleh relasi {{- relation}} yang berasal dari {{- source}}."
},
"clone_to": {
"clone_notes_to": "Duplikat catatan ke…",
@@ -96,5 +99,12 @@
"clone_to_selected_note": "Salin ke catatan yang dipilih",
"no_path_to_clone_to": "Tidak ada jalur untuk digandakan.",
"note_cloned": "Catatan \"{{clonedTitle}}\" telah digandakan ke dalam \"{{targetTitle}}\""
},
"search_result": {
"search_now": "Cari sekarang"
},
"export": {
"export_note_title": "Mengeluarkan catatan",
"close": "Tutup"
}
}

View File

@@ -118,7 +118,7 @@
"export_type_subtree": "Questa nota e tutti i suoi discendenti",
"format_html": "HTML - raccomandato in quanto mantiene tutti i formati",
"format_html_zip": "HTML in archivio ZIP - questo è raccomandato in quanto conserva tutta la formattazione.",
"format_markdown": "MArkdown - questo conserva la maggior parte della formattazione.",
"format_markdown": "Markdown: preserva la maggior parte della formattazione.",
"export_type_single": "Solo questa nota, senza le sottostanti",
"format_opml": "OPML - formato per scambio informazioni outline. Formattazione, immagini e files non sono inclusi.",
"opml_version_1": "OPML v.1.0 - solo testo semplice",
@@ -334,6 +334,7 @@
"electron_context_menu": {
"cut": "Taglia",
"copy": "Copia",
"copy-as-markdown": "Copia come markdown",
"paste": "Incolla",
"copy-link": "Copia collegamento",
"paste-as-plain-text": "Incolla come testo semplice",
@@ -519,7 +520,7 @@
"custom_name_label": "Nome del motore di ricerca personalizzato",
"custom_name_placeholder": "Personalizza il nome del motore di ricerca",
"custom_url_label": "L'URL del motore di ricerca personalizzato deve includere {keyword} come segnaposto per il termine di ricerca.",
"custom_url_placeholder": "Personalizza l'URL del motore di ricerca"
"custom_url_placeholder": "Personalizza l'URL del motore di ricerca"
},
"sql_table_schemas": {
"tables": "Tabelle"
@@ -592,7 +593,7 @@
"collapseExpand": "collassa/espande il nodo",
"notSet": "non impostato",
"goBackForwards": "indietro/avanti nella cronologia",
"showJumpToNoteDialog": "mostra <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">finestra di dialogo “Vai a</a>",
"showJumpToNoteDialog": "mostra <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">finestra \"Vai a\"</a>",
"title": "Scheda riassuntiva",
"noteNavigation": "Nota navigazione",
"scrollToActiveNote": "scorri fino alla nota attiva",
@@ -663,149 +664,6 @@
"thursday": "Giovedì",
"friday": "Venerdì"
},
"ai_llm": {
"not_started": "Non iniziato",
"title": "Impostazioni AI",
"processed_notes": "Note elaborate",
"total_notes": "Note totali",
"progress": "Progressi",
"queued_notes": "Note in coda",
"failed_notes": "Note non riuscite",
"last_processed": "Ultimo elaborato",
"refresh_stats": "Aggiorna statistiche",
"enable_ai_features": "Abilita le funzionalità AI/LLM",
"enable_ai_description": "Abilita funzionalità di intelligenza artificiale come il riepilogo delle note, la generazione di contenuti e altre funzionalità LLM",
"openai_tab": "OpenAI",
"anthropic_tab": "Antropico",
"voyage_tab": "Viaggio AI",
"ollama_tab": "Ollama",
"enable_ai": "Abilita le funzionalità AI/LLM",
"enable_ai_desc": "Abilita funzionalità di intelligenza artificiale come il riepilogo delle note, la generazione di contenuti e altre funzionalità LLM",
"provider_configuration": "Configurazione del fornitore di intelligenza artificiale",
"provider_precedence": "Precedenza del fornitore",
"provider_precedence_description": "Elenco dei provider separati da virgole in ordine di precedenza (ad esempio, 'openai,anthropic,ollama')",
"temperature": "Temperatura",
"temperature_description": "Controlla la casualità nelle risposte (0 = deterministico, 2 = casualità massima)",
"system_prompt": "Prompt di sistema",
"system_prompt_description": "Prompt di sistema predefinito utilizzato per tutte le interazioni con l'IA",
"openai_configuration": "Configurazione OpenAI",
"openai_settings": "Impostazioni OpenAI",
"api_key": "Chiave API",
"url": "URL di base",
"model": "Modello",
"openai_api_key_description": "La tua chiave API OpenAI per accedere ai loro servizi di intelligenza artificiale",
"anthropic_api_key_description": "La tua chiave API Anthropic per accedere ai modelli Claude",
"default_model": "Modello predefinito",
"openai_model_description": "Esempi: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "URL di base",
"openai_url_description": "Predefinito: https://api.openai.com/v1",
"anthropic_settings": "Ambientazioni antropiche",
"anthropic_url_description": "URL di base per l'API Anthropic (predefinito: https://api.anthropic.com)",
"anthropic_model_description": "Modelli di Anthropic Claude per il completamento della chat",
"voyage_settings": "Impostazioni AI di Voyage",
"ollama_settings": "Impostazioni Ollama",
"ollama_url_description": "URL per l'API Ollama (predefinito: http://localhost:11434)",
"ollama_model_description": "Modello Ollama da utilizzare per il completamento della chat",
"anthropic_configuration": "Configurazione antropica",
"voyage_configuration": "Configurazione AI di viaggio",
"voyage_url_description": "Predefinito: https://api.voyageai.com/v1",
"ollama_configuration": "Configurazione Ollama",
"enable_ollama": "Abilita Ollama",
"enable_ollama_description": "Abilita Ollama per l'utilizzo del modello AI locale",
"ollama_url": "URL di Ollama",
"ollama_model": "Modello Ollama",
"refresh_models": "Aggiorna modelli",
"refreshing_models": "Rinfrescante...",
"enable_automatic_indexing": "Abilita l'indicizzazione automatica",
"rebuild_index": "Ricostruisci indice",
"rebuild_index_error": "Errore durante l'avvio della ricostruzione dell'indice. Controllare i log per i dettagli.",
"note_title": "Titolo della nota",
"error": "Errore",
"last_attempt": "Ultimo tentativo",
"actions": "Azioni",
"retry": "Riprova",
"partial": "{{ percentage }}% completato",
"retry_queued": "Nota in coda per un nuovo tentativo",
"retry_failed": "Impossibile mettere in coda la nota per un nuovo tentativo",
"max_notes_per_llm_query": "Numero massimo di note per query",
"max_notes_per_llm_query_description": "Numero massimo di note simili da includere nel contesto AI",
"active_providers": "Fornitori attivi",
"disabled_providers": "Fornitori disabili",
"remove_provider": "Rimuovi il fornitore dalla ricerca",
"restore_provider": "Ripristina il provider per la ricerca",
"similarity_threshold": "Soglia di similarità",
"similarity_threshold_description": "Punteggio minimo di similarità (0-1) per le note da includere nel contesto per le query LLM",
"reprocess_index": "Ricostruisci l'indice di ricerca",
"reprocessing_index": "Ricostruzione...",
"reprocess_index_started": "Ottimizzazione dell'indice di ricerca avviata in background",
"reprocess_index_error": "Errore durante la ricostruzione dell'indice di ricerca",
"index_rebuild_progress": "Progresso nella ricostruzione dell'indice",
"index_rebuilding": "Indice di ottimizzazione ({{percentage}}%)",
"index_rebuild_complete": "Ottimizzazione dell'indice completata",
"index_rebuild_status_error": "Errore durante il controllo dello stato di ricostruzione dell'indice",
"never": "Mai",
"processing": "Elaborazione ({{percentage}}%)",
"incomplete": "Incompleto ({{percentage}}%)",
"complete": "Completato (100%)",
"refreshing": "Rinfrescante...",
"auto_refresh_notice": "Si aggiorna automaticamente ogni {{seconds}} secondi",
"note_queued_for_retry": "Nota in coda per un nuovo tentativo",
"failed_to_retry_note": "Impossibile riprovare nota",
"all_notes_queued_for_retry": "Tutte le note non riuscite sono in coda per un nuovo tentativo",
"failed_to_retry_all": "Impossibile riprovare le note",
"ai_settings": "Impostazioni AI",
"api_key_tooltip": "Chiave API per accedere al servizio",
"empty_key_warning": {
"anthropic": "La chiave API di Anthropic è vuota. Inserisci una chiave API valida.",
"openai": "La chiave API di OpenAI è vuota. Inserisci una chiave API valida.",
"voyage": "La chiave API di Voyage è vuota. Inserisci una chiave API valida.",
"ollama": "La chiave API di Ollama è vuota. Inserisci una chiave API valida."
},
"agent": {
"processing": "Elaborazione in corso...",
"thinking": "Pensiero...",
"loading": "Caricamento...",
"generating": "Generazione in corso..."
},
"name": "intelligenza artificiale",
"openai": "OpenAI",
"use_enhanced_context": "Utilizzare il contesto avanzato",
"enhanced_context_description": "Fornisce all'IA più contesto dalla nota e dalle note correlate per risposte migliori",
"show_thinking": "Mostra il pensiero",
"show_thinking_description": "Mostra la catena del processo di pensiero dell'IA",
"enter_message": "Inserisci il tuo messaggio...",
"error_contacting_provider": "Errore durante la connessione al fornitore dell'IA. Controlla le impostazioni e la connessione Internet.",
"error_generating_response": "Errore durante la generazione della risposta AI",
"index_all_notes": "Indice Tutte le note",
"index_status": "Stato dell'indice",
"indexed_notes": "Note indicizzate",
"indexing_stopped": "Indicizzazione interrotta",
"indexing_in_progress": "Indicizzazione in corso...",
"last_indexed": "Ultimo indicizzato",
"note_chat": "Nota Chat",
"sources": "Fonti",
"start_indexing": "Avvia l'indicizzazione",
"use_advanced_context": "Usa contesto avanzato",
"ollama_no_url": "Ollama non è configurato. Inserisci un URL valido.",
"chat": {
"root_note_title": "Chat AI",
"root_note_content": "Questa nota contiene le conversazioni della chat AI salvate.",
"new_chat_title": "Nuova chat",
"create_new_ai_chat": "Crea una nuova chat AI"
},
"create_new_ai_chat": "Crea una nuova chat AI",
"configuration_warnings": "Ci sono alcuni problemi con la configurazione dell'IA. Controlla le impostazioni.",
"experimental_warning": "La funzionalità LLM è attualmente sperimentale: sei stato avvisato.",
"selected_provider": "Fornitore selezionato",
"selected_provider_description": "Scegli il fornitore di intelligenza artificiale per le funzionalità di chat e completamento",
"select_model": "Seleziona il modello...",
"select_provider": "Seleziona il fornitore...",
"ai_enabled": "Funzionalità AI abilitate",
"ai_disabled": "Funzionalità AI disabilitate",
"no_models_found_online": "Nessun modello trovato. Controlla la tua chiave API e le impostazioni.",
"no_models_found_ollama": "Nessun modello Ollama trovato. Controlla se Ollama è in esecuzione.",
"error_fetching": "Errore durante il recupero dei modelli: {{error}}"
},
"import": {
"importIntoNote": "Importa nella nota",
"chooseImportFile": "Scegli file di importazione",
@@ -1856,10 +1714,10 @@
"confirm-change": "Si sconsiglia di cambiare tipo di nota quando il contenuto della nota non è vuoto. Vuoi continuare comunque?",
"geo-map": "Mappa geografica",
"beta-feature": "Beta",
"ai-chat": "Chat AI",
"task-list": "Elenco delle attività",
"new-feature": "Nuovo",
"collections": "Collezioni"
"collections": "Collezioni",
"ai-chat": "Chat con IA"
},
"protect_note": {
"toggle-on": "Proteggi la nota",
@@ -1937,7 +1795,8 @@
},
"search_result": {
"no_notes_found": "Non sono state trovate note per i parametri di ricerca specificati.",
"search_not_executed": "La ricerca non è stata ancora eseguita. Clicca sul pulsante \"Cerca\" qui sopra per visualizzare i risultati."
"search_not_executed": "La ricerca non è stata ancora eseguita.",
"search_now": "Cerca ora"
},
"spacer": {
"configure_launchbar": "Configura Launchbar"
@@ -2164,7 +2023,9 @@
"percentage": "%"
},
"pagination": {
"total_notes": "{{count}} note"
"total_notes": "{{count}} note",
"prev_page": "Pagina precedente",
"next_page": "Pagina successiva"
},
"collections": {
"rendering_error": "Impossibile mostrare il contenuto a causa di un errore."

View File

@@ -597,10 +597,10 @@
"widget": "ウィジェット",
"confirm-change": "ノートの内容が空ではない場合、ノートタイプを変更することは推奨されません。続行しますか?",
"beta-feature": "Beta",
"ai-chat": "AI チャット",
"task-list": "タスクリスト",
"new-feature": "New",
"collections": "コレクション"
"collections": "コレクション",
"ai-chat": "AI チャット"
},
"edited_notes": {
"no_edited_notes_found": "この日の編集されたノートはまだありません...",
@@ -1283,7 +1283,8 @@
},
"search_result": {
"no_notes_found": "指定された検索パラメータに該当するノートは見つかりませんでした。",
"search_not_executed": "検索はまだ実行されていません。上の「検索」ボタンをクリックすると、検索結果が表示されます。"
"search_not_executed": "検索はまだ実行されていません。",
"search_now": "今すぐ検索"
},
"sql_result": {
"no_rows": "このクエリでは行が返されませんでした",
@@ -1352,6 +1353,7 @@
"add-term-to-dictionary": "辞書に \"{{term}}\" を追加",
"cut": "切り取り",
"copy": "コピー",
"copy-as-markdown": "Markdownとしてコピー",
"copy-link": "リンクをコピー",
"paste": "貼り付け",
"paste-as-plain-text": "プレーンテキストで貼り付け",
@@ -1424,149 +1426,6 @@
"content_renderer": {
"open_externally": "外部で開く"
},
"ai_llm": {
"title": "AI 設定",
"enable_ai_features": "AI/LLM 機能を有効化",
"enable_ai_description": "ートの要約、コンテンツ生成、その他のLLM機能などのAI機能を有効にする",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "AI/LLM 機能を有効化",
"enable_ai_desc": "ートの要約、コンテンツ生成、その他のLLM機能などのAI機能を有効にする",
"provider_configuration": "AI プロバイダーの設定",
"provider_precedence": "プロバイダーの優先順位",
"provider_precedence_description": "カンマで区切られたプロバイダーの優先順位リスト(例: 'openai,anthropic,ollama'",
"temperature_description": "応答のランダム性を制御する0 = 決定的、2 = 最大ランダム性)",
"system_prompt_description": "すべてのAIとの対話に使用されるデフォルトのシステムプロンプト",
"system_prompt": "システムプロンプト",
"openai_configuration": "OpenAIの設定",
"openai_settings": "OpenAIの設定",
"api_key": "APIキー",
"model": "モデル",
"openai_api_key_description": "OpenAIのAIサービスにアクセスするためのAPIキー",
"anthropic_api_key_description": "AnthropicのClaudeモデルにアクセスするためのAPIキー",
"default_model": "デフォルトモデル",
"openai_model_description": "例: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"openai_url_description": "デフォルト: https://api.openai.com/v1",
"anthropic_settings": "Anthropicの設定",
"anthropic_model_description": "チャット補完用のAnthropic Claudeモデル",
"voyage_settings": "Voyage AIの設定",
"ollama_settings": "Ollamaの設定",
"ollama_url_description": "Ollama API の URLデフォルト: http://localhost:11434",
"anthropic_url_description": "Anthropic APIのベースURLデフォルト: https://api.anthropic.com",
"ollama_model_description": "チャット補完用のOllamaモデル",
"anthropic_configuration": "Anthropicの設定",
"voyage_configuration": "Voyage AIの設定",
"voyage_url_description": "デフォルト: https://api.voyageai.com/v1",
"ollama_configuration": "Ollamaの設定",
"enable_ollama": "Ollamaを有効",
"enable_ollama_description": "ローカルAIモデルを利用するためOllamaを有効にする",
"ollama_url": "Ollama URL",
"ollama_model": "Ollamaモデル",
"refresh_models": "モデルを更新",
"refreshing_models": "更新中...",
"error": "エラー",
"retry": "再試行",
"partial": "{{ percentage }}%完了",
"processing": "処理中({{percentage}}%",
"complete": "完了100%",
"refreshing": "更新中...",
"auto_refresh_notice": "{{seconds}}秒ごとに自動更新",
"ai_settings": "AI 設定",
"api_key_tooltip": "サービスにアクセスするためのAPIキー",
"empty_key_warning": {
"anthropic": "Anthropic APIキーが空です。有効な APIキーを入力してください。",
"openai": "OpenAI APIキーが空です。有効なAPIキーを入力してください。",
"voyage": "Voyage APIキーが空です。有効なAPIキーを入力してください。",
"ollama": "Ollama APIキーが空です。有効なAPIキーを入力してください。"
},
"agent": {
"processing": "処理中...",
"loading": "読み込み中...",
"generating": "生成中...",
"thinking": "考え中..."
},
"name": "AI",
"openai": "OpenAI",
"error_contacting_provider": "AIプロバイダーへの接続中にエラーが発生しました。設定とインターネット接続をご確認ください。",
"ollama_no_url": "Ollamaは設定されていません。有効なURLを入力してください。",
"chat": {
"root_note_title": "AIチャット",
"root_note_content": "このートには、保存されたAIチャットの会話が含まれています。",
"new_chat_title": "新しいチャット",
"create_new_ai_chat": "新しいAIチャットを作成"
},
"create_new_ai_chat": "新しいAIチャットを作成",
"configuration_warnings": "AIの設定に問題があります。設定を確認してください。",
"experimental_warning": "LLM機能は現在実験的です - ご注意ください。",
"selected_provider_description": "チャットおよび補完機能のAIプロバイダーを選択する",
"selected_provider": "プロバイダーを選択",
"select_model": "モデルを選択...",
"select_provider": "プロバイダーを選択...",
"not_started": "開始されていません",
"processed_notes": "処理済みノート",
"total_notes": "ノートの総数",
"progress": "進行状況",
"queued_notes": "キューに登録されたノート",
"failed_notes": "失敗したノート",
"last_processed": "最終処理日時",
"refresh_stats": "統計情報を更新",
"temperature": "Temperature温度",
"url": "ベースURL",
"base_url": "ベースURL",
"enable_automatic_indexing": "自動インデックス作成を有効にする",
"rebuild_index": "インデックスの再構築",
"rebuild_index_error": "インデックスの再構築開始時にエラーが発生しました。詳細はログをご確認ください。",
"note_title": "ノートのタイトル",
"last_attempt": "最終試行日時",
"actions": "アクション",
"retry_queued": "ノートが再試行キューに追加されました",
"retry_failed": "ノートを再試行キューに追加できませんでした",
"max_notes_per_llm_query": "クエリあたりの最大ノート数",
"max_notes_per_llm_query_description": "AIコンテキストに含める類似ートの最大数",
"active_providers": "アクティブなプロバイダー",
"disabled_providers": "無効なプロバイダー",
"remove_provider": "検索からプロバイダーを削除",
"restore_provider": "検索にプロバイダーを復元",
"similarity_threshold": "類似度のしきい値",
"similarity_threshold_description": "LLMクエリのコンテキストに含めるートの最小類似度スコア01",
"reprocess_index": "検索インデックスを再構築",
"reprocessing_index": "再構築中...",
"reprocess_index_started": "検索インデックスの最適化がバックグラウンドで開始されました",
"reprocess_index_error": "検索インデックスの再構築中にエラーが発生しました",
"index_rebuild_progress": "インデックスの再構築の進行状況",
"index_rebuilding": "インデックスの最適化中({{percentage}}%",
"index_rebuild_complete": "インデックスの最適化が完了しました",
"index_rebuild_status_error": "インデックスの再構築ステータスの確認中にエラーが発生しました",
"never": "なし",
"incomplete": "未完了 ({{percentage}}%)",
"note_queued_for_retry": "ノートが再試行キューに追加されました",
"failed_to_retry_note": "ノートの再試行に失敗しました",
"all_notes_queued_for_retry": "失敗したすべてのノートは再試行のためにキューに入れられました",
"failed_to_retry_all": "ノートの再試行に失敗しました",
"use_enhanced_context": "拡張されたコンテキストを使用する",
"enhanced_context_description": "ートとその関連ートからより多くのコンテキストをAIに提供し、より良い応答を実現します",
"show_thinking": "思考を表示",
"show_thinking_description": "AIの思考プロセスをチェーン表示",
"enter_message": "メッセージを入力...",
"error_generating_response": "AI応答の生成中にエラーが発生しました",
"index_all_notes": "すべてのノートをインデックスに登録",
"index_status": "インデックスのステータス",
"indexed_notes": "インデックス登録済みのノート",
"indexing_stopped": "インデックス登録を停止しました",
"indexing_in_progress": "インデックス登録中です...",
"last_indexed": "最終インデックス作成日時",
"note_chat": "ノートチャット",
"sources": "ソース",
"start_indexing": "インデックス作成を開始",
"use_advanced_context": "高度なコンテキストを使用",
"ai_enabled": "AI 機能が有効",
"ai_disabled": "AI 機能が無効",
"no_models_found_online": "モデルが見つかりません。API キーと設定を確認してください。",
"no_models_found_ollama": "Ollama モデルが見つかりません。Ollama が実行中かどうかを確認してください。",
"error_fetching": "モデルの取得エラー: {{error}}"
},
"add_label": {
"add_label": "ラベルを追加",
"label_name_placeholder": "ラベル名",

View File

@@ -81,13 +81,17 @@
"search_for_note_by_its_name": "이름으로 노트 검색하기",
"no_path_to_clone_to": "클론할 경로가 존재하지 않습니다.",
"note_cloned": "노트 \"{{clonedTitle}}\"이(가) \"{{targetTitle}}\"로 클론되었습니다",
"cloned_note_prefix_title": "클론된 노트는 지정된 접두사와 함께 노트 트리에 표시됩니다"
"cloned_note_prefix_title": "클론된 노트는 지정된 접두사와 함께 노트 트리에 표시됩니다",
"prefix_optional": "접두사 (선택 사항)",
"clone_to_selected_note": "선택한 노트에 클론"
},
"confirm": {
"confirmation": "확인",
"cancel": "취소",
"ok": "OK",
"are_you_sure_remove_note": "관계 맵에서 \"{{title}}\" 노트를 정말로 제거하시겠습니까? "
"are_you_sure_remove_note": "관계 맵에서 \"{{title}}\" 노트를 정말로 제거하시겠습니까? ",
"if_you_dont_check": "이 항목을 선택하지 않으면 해당 노트는 관계 맵에서만 제거됩니다.",
"also_delete_note": "노트를 함께 삭제"
},
"delete_notes": {
"erase_notes_description": "일반(소프트) 삭제는 메모를 삭제된 것으로 표시하는 것일 뿐이며, 일정 시간 동안 (최근 변경 내용 대화 상자에서) 복구할 수 있습니다. 이 옵션을 선택하면 메모가 즉시 삭제되며 복구할 수 없습니다.",
@@ -97,7 +101,10 @@
"broken_relations_to_be_deleted": "다음 관계가 끊어지고 삭제됩니다({{ relationCount}})",
"cancel": "취소",
"ok": "OK",
"deleted_relation_text": "삭제 예정인 노트 {{- note}} (은)는 {{- source}}에서 시작된 관계 {{- relation}}에 의해 참조되고 있습니다."
"deleted_relation_text": "삭제 예정인 노트 {{- note}} (은)는 {{- source}}에서 시작된 관계 {{- relation}}에 의해 참조되고 있습니다.",
"delete_notes_preview": "노트 미리보기 삭제",
"close": "닫기",
"delete_all_clones_description": "모든 복제본 삭제(최근 변경 사항에서 되돌릴 수 있습니다)"
},
"export": {
"export_note_title": "노트 내보내기",
@@ -108,10 +115,25 @@
"export_in_progress": "내보내기 진행 중: {{progressCount}}",
"export_finished_successfully": "내보내기를 성공적으로 완료했습니다.",
"format_pdf": "PDF - 인쇄 또는 공유용",
"share-format": "웹 게시용 HTML - 공유 노트에 사용되는 것과 동일한 테마를 사용하지만 정적 웹사이트로 게시할 수 있습니다."
"share-format": "웹 게시용 HTML - 공유 노트에 사용되는 것과 동일한 테마를 사용하지만 정적 웹사이트로 게시할 수 있습니다.",
"close": "닫기",
"export_type_subtree": "이 노트와 모든 후손 노트",
"format_html": "HTML - 모든 형식 유지됨, 권장",
"format_html_zip": "HTML(ZIP 아카이브) - 모든 서식이 유지됨, 권장.",
"format_markdown": "마크다운 - 대부분의 서식이 유지됩니다.",
"format_opml": "OPML은 텍스트 전용 아웃라이너 교환 형식입니다. 서식, 이미지 및 파일은 포함되지 않습니다.",
"opml_version_1": "OPML v1.0 - 일반 텍스트만",
"opml_version_2": "OPML v2.0 - HTML 지원"
},
"help": {
"title": "치트 시트",
"editShortcuts": "키보드 단축키 편집"
"editShortcuts": "키보드 단축키 편집",
"noteNavigation": "노트 내비게이션",
"goUpDown": "노트 목록에서 위/아래로 이동",
"collapseExpand": "노트 접기/펼치기",
"notSet": "미설정",
"goBackForwards": "히스토리에서 뒤로/앞으로 이동",
"showJumpToNoteDialog": "<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"노트로 이동\" 대화 상자</a> 표시",
"scrollToActiveNote": "활성화된 노트로 스크롤 이동"
}
}

View File

@@ -261,7 +261,9 @@
"percentage": "%"
},
"pagination": {
"total_notes": "{{count}} notatek"
"total_notes": "{{count}} notatek",
"prev_page": "Poprzednia strona",
"next_page": "Następna strona"
},
"collections": {
"rendering_error": "Nie można wyświetlić zawartości z powodu błędu."
@@ -612,6 +614,7 @@
"electron_context_menu": {
"cut": "Wytnij",
"copy": "Kopiuj",
"copy-as-markdown": "Kopiuj jako markdown",
"copy-link": "Kopiuj link",
"paste": "Wklej",
"paste-as-plain-text": "Wklej jako zwykły tekst",
@@ -737,7 +740,8 @@
"raster": "Raster",
"vector_light": "Wektor (Jasny)",
"vector_dark": "Wektor (Ciemny)",
"show-scale": "Pokaż skalę"
"show-scale": "Pokaż skalę",
"show-labels": "Pokaż nazwy znaczników"
},
"table_context_menu": {
"delete_row": "Usuń wiersz"
@@ -773,149 +777,6 @@
"target_note": "notatka docelowa",
"create_relation_on_all_matched_notes": "Na wszystkich dopasowanych notatkach utwórz podaną relację."
},
"ai_llm": {
"actions": "Akcje",
"retry": "Ponów",
"partial": "{{ percentage }}% ukończono",
"retry_queued": "Notatka zakolejkowana do ponowienia",
"retry_failed": "Nie udało się zakolejkować notatki do ponowienia",
"max_notes_per_llm_query": "Maks. notatek na zapytanie",
"index_all_notes": "Indeksuj wszystkie notatki",
"index_status": "Status indeksu",
"indexed_notes": "Zaindeksowane notatki",
"indexing_stopped": "Indeksowanie zatrzymane",
"indexing_in_progress": "Indeksowanie w toku...",
"last_indexed": "Ostatnio zaindeksowane",
"note_chat": "Czat notatki",
"note_title": "Tytuł notatki",
"error": "Błąd",
"last_attempt": "Ostatnia próba",
"queued_notes": "Notatki w kolejce",
"failed_notes": "Notatki nieudane",
"last_processed": "Ostatnio przetworzone",
"refresh_stats": "Odśwież statystyki",
"enable_ai_features": "Włącz funkcje AI/LLM",
"enable_ai_description": "Włącz funkcje AI, takie jak podsumowywanie notatek, generowanie treści i inne możliwości LLM",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Włącz funkcje AI/LLM",
"enable_ai_desc": "Włącz funkcje AI, takie jak podsumowywanie notatek, generowanie treści i inne możliwości LLM",
"provider_configuration": "Konfiguracja dostawcy AI",
"provider_precedence": "Kolejność dostawców",
"provider_precedence_description": "Lista dostawców oddzielona przecinkami w kolejności pierwszeństwa (np. 'openai,anthropic,ollama')",
"temperature": "Temperatura",
"temperature_description": "Kontroluje losowość w odpowiedziach (0 = deterministyczne, 2 = maksymalna losowość)",
"system_prompt": "Prompt systemowy",
"system_prompt_description": "Domyślny prompt systemowy używany dla wszystkich interakcji AI",
"openai_configuration": "Konfiguracja OpenAI",
"openai_settings": "Ustawienia OpenAI",
"api_key": "Klucz API",
"url": "Bazowy URL",
"model": "Model",
"openai_api_key_description": "Twój klucz API OpenAI do dostępu do ich usług AI",
"anthropic_api_key_description": "Twój klucz API Anthropic do dostępu do modeli Claude",
"default_model": "Domyślny model",
"openai_model_description": "Przykłady: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "Bazowy URL",
"openai_url_description": "Domyślnie: https://api.openai.com/v1",
"anthropic_settings": "Ustawienia Anthropic",
"anthropic_url_description": "Bazowy URL dla API Anthropic (domyślnie: https://api.anthropic.com)",
"anthropic_model_description": "Modele Anthropic Claude do czatu",
"voyage_settings": "Ustawienia Voyage AI",
"ollama_settings": "Ustawienia Ollama",
"ollama_url_description": "URL dla API Ollama (domyślnie: http://localhost:11434)",
"ollama_model_description": "Model Ollama do użycia w czacie",
"anthropic_configuration": "Konfiguracja Anthropic",
"voyage_configuration": "Konfiguracja Voyage AI",
"voyage_url_description": "Domyślnie: https://api.voyageai.com/v1",
"ollama_configuration": "Konfiguracja Ollama",
"enable_ollama": "Włącz Ollama",
"enable_ollama_description": "Włącz Ollama do lokalnego użycia modeli AI",
"ollama_url": "URL Ollama",
"ollama_model": "Model Ollama",
"refresh_models": "Odśwież modele",
"refreshing_models": "Odświeżanie...",
"enable_automatic_indexing": "Włącz automatyczne indeksowanie",
"rebuild_index": "Przebuduj indeks",
"rebuild_index_error": "Błąd podczas rozpoczynania przebudowy indeksu. Sprawdź logi po szczegóły.",
"max_notes_per_llm_query_description": "Maksymalna liczba podobnych notatek do uwzględnienia w kontekście AI",
"active_providers": "Aktywni dostawcy",
"disabled_providers": "Wyłączeni dostawcy",
"remove_provider": "Usuń dostawcę z wyszukiwania",
"restore_provider": "Przywróć dostawcę do wyszukiwania",
"similarity_threshold": "Próg podobieństwa",
"not_started": "Nie rozpoczęto",
"title": "Ustawienia AI",
"processed_notes": "Przetworzone notatki",
"total_notes": "Łącznie notatek",
"progress": "Postęp",
"similarity_threshold_description": "Minimalny wynik podobieństwa (0-1) dla notatek, które mają być uwzględnione w kontekście zapytań LLM",
"reprocess_index": "Przebuduj indeks wyszukiwania",
"reprocessing_index": "Przebudowywanie...",
"reprocess_index_started": "Optymalizacja indeksu wyszukiwania rozpoczęta w tle",
"reprocess_index_error": "Błąd podczas przebudowy indeksu wyszukiwania",
"index_rebuild_progress": "Postęp przebudowy indeksu",
"index_rebuilding": "Optymalizacja indeksu ({{percentage}}%)",
"index_rebuild_complete": "Optymalizacja indeksu zakończona",
"index_rebuild_status_error": "Błąd podczas sprawdzania statusu przebudowy indeksu",
"never": "Nigdy",
"processing": "Przetwarzanie ({{percentage}}%)",
"incomplete": "Niekompletne ({{percentage}}%)",
"complete": "Zakończone (100%)",
"refreshing": "Odświeżanie...",
"auto_refresh_notice": "Automatyczne odświeżanie co {{seconds}} sekund",
"note_queued_for_retry": "Notatka zakolejkowana do ponowienia",
"failed_to_retry_note": "Nie udało się ponowić notatki",
"all_notes_queued_for_retry": "Wszystkie nieudane notatki zakolejkowane do ponowienia",
"failed_to_retry_all": "Nie udało się ponowić notatek",
"ai_settings": "Ustawienia AI",
"api_key_tooltip": "Klucz API do dostępu do usługi",
"empty_key_warning": {
"anthropic": "Klucz API Anthropic jest pusty. Proszę wprowadzić poprawny klucz API.",
"openai": "Klucz API OpenAI jest pusty. Proszę wprowadzić poprawny klucz API.",
"voyage": "Klucz API Voyage jest pusty. Proszę wprowadzić poprawny klucz API.",
"ollama": "Klucz API Ollama jest pusty. Proszę wprowadzić poprawny klucz API."
},
"agent": {
"processing": "Przetwarzanie...",
"thinking": "Myślę...",
"loading": "Ładowanie...",
"generating": "Generowanie..."
},
"name": "AI",
"openai": "OpenAI",
"use_enhanced_context": "Użyj rozszerzonego kontekstu",
"enhanced_context_description": "Dostarcza AI więcej kontekstu z notatki i jej powiązanych notatek dla lepszych odpowiedzi",
"show_thinking": "Pokaż proces myślenia",
"show_thinking_description": "Pokaż ciąg myślowy AI",
"enter_message": "Wpisz swoją wiadomość...",
"error_contacting_provider": "Błąd połączenia z dostawcą AI. Sprawdź swoje ustawienia i połączenie internetowe.",
"error_generating_response": "Błąd generowania odpowiedzi AI",
"sources": "Źródła",
"start_indexing": "Rozpocznij indeksowanie",
"use_advanced_context": "Użyj zaawansowanego kontekstu",
"ollama_no_url": "Ollama nie jest skonfigurowana. Proszę wprowadzić poprawny URL.",
"chat": {
"root_note_title": "Czaty AI",
"root_note_content": "Ta notatka zawiera twoje zapisane rozmowy czatu AI.",
"new_chat_title": "Nowy czat",
"create_new_ai_chat": "Utwórz nowy czat AI"
},
"create_new_ai_chat": "Utwórz nowy czat AI",
"configuration_warnings": "Istnieją pewne problemy z twoją konfiguracją AI. Proszę sprawdzić ustawienia.",
"experimental_warning": "Funkcja LLM jest obecnie eksperymentalna - zostałeś ostrzeżony.",
"selected_provider": "Wybrany dostawca",
"selected_provider_description": "Wybierz dostawcę AI dla funkcji czatu i uzupełniania",
"select_model": "Wybierz model...",
"select_provider": "Wybierz dostawcę...",
"ai_enabled": "Funkcje AI włączone",
"ai_disabled": "Funkcje AI wyłączone",
"no_models_found_online": "Nie znaleziono modeli. Proszę sprawdzić klucz API i ustawienia.",
"no_models_found_ollama": "Nie znaleziono modeli Ollama. Proszę sprawdzić, czy Ollama jest uruchomiona.",
"error_fetching": "Błąd pobierania modeli: {{error}}"
},
"prompt": {
"title": "Monit",
"ok": "OK",
@@ -1375,7 +1236,7 @@
"no_attachments": "Ta notatka nie ma załączników."
},
"book": {
"no_children_help": "Ta kolekcja nie posiada żadnych notatek podrzędnych, więc nie ma nic do wyświetlenia. Zobacz <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> po szczegóły.",
"no_children_help": "Ta kolekcja nie zawiera notatek podrzędnych, więc nie ma nic do wyświetlenia.",
"drag_locked_title": "Zablokowane do edycji",
"drag_locked_message": "Przeciąganie niedozwolone, ponieważ kolekcja jest zablokowana do edycji."
},
@@ -1796,7 +1657,8 @@
"description": "Opis",
"reload_app": "Przeładuj aplikację, aby zastosować zmiany",
"set_all_to_default": "Ustaw wszystkie skróty na domyślne",
"confirm_reset": "Czy na pewno chcesz zresetować wszystkie skróty klawiszowe do domyślnych?"
"confirm_reset": "Czy na pewno chcesz zresetować wszystkie skróty klawiszowe do domyślnych?",
"no_results": "Nie znaleziono skrótów pasujących do '{{filter}}'"
},
"spellcheck": {
"title": "Sprawdzanie pisowni",
@@ -2003,7 +1865,9 @@
"print_report_collection_content_few": "Nie można wydrukować {{count}} notatek w kolekcji, ponieważ nie są one obsługiwane lub są chronione.",
"print_report_collection_content_many": "Nie można wydrukować {{count}} notatek w kolekcji, ponieważ nie są one obsługiwane lub są chronione.",
"print_report_collection_details_button": "Zobacz szczegóły",
"print_report_collection_details_ignored_notes": "Zignorowane notatki"
"print_report_collection_details_ignored_notes": "Zignorowane notatki",
"print_report_error_title": "Nie udało się wydrukować",
"print_report_stack_trace": "Ślad stosu"
},
"note_title": {
"placeholder": "wpisz tytuł notatki tutaj...",
@@ -2018,7 +1882,8 @@
},
"search_result": {
"no_notes_found": "Nie znaleziono notatek dla podanych parametrów wyszukiwania.",
"search_not_executed": "Wyszukiwanie nie zostało jeszcze wykonane. Kliknij przycisk \"Szukaj\" powyżej, aby zobaczyć wyniki."
"search_not_executed": "Nie przeprowadzono jeszcze wyszukiwania.",
"search_now": "Szukaj teraz"
},
"spacer": {
"configure_launchbar": "Konfiguruj pasek szybkiego dostępu"
@@ -2288,5 +2153,49 @@
},
"bookmark_buttons": {
"bookmarks": "Zakładki"
},
"render": {
"setup_title": "Wyświetl własny kod HTML lub Preact JSX w tej notatce",
"setup_create_sample_preact": "Stwórz przykładową notatkę z użyciem Preact",
"setup_create_sample_html": "Stwórz przykładową notatkę z użyciem HTML",
"setup_sample_created": "Utworzono przykładową notatkę jako notatkę podrzędną.",
"disabled_description": "Ta notatka pochodzi z zewnętrznego źródła. Ze względów bezpieczeństwa funkcja ta nie jest domyślnie włączona. Upewnij się, że ufasz źródłu, zanim ją aktywujesz.",
"disabled_button_enable": "Włącz renderowanie notatki"
},
"web_view_setup": {
"title": "Utwórz podgląd strony na żywo bezpośrednio w Trilium",
"url_placeholder": "Wpisz lub wklej adres strony internetowej, na przykład https://triliumnotes.org",
"create_button": "Utwórz widok strony",
"invalid_url_title": "Nieprawidłowy adres",
"invalid_url_message": "Wprowadź prawidłowy adres strony, na przykład https://triliumnotes.org.",
"disabled_description": "Ten widok strony został zaimportowany z zewnętrznego źródła. Aby chronić Cię przed phishingiem lub szkodliwą zawartością, nie jest on ładowany automatycznie. Możesz go włączyć, jeśli ufasz źródłu.",
"disabled_button_enable": "Włącz widok strony"
},
"active_content_badges": {
"type_icon_pack": "Pakiet ikon",
"type_backend_script": "Skrypt po stronie serwera",
"type_frontend_script": "Skrypt po stronie klienta",
"type_widget": "Widżet",
"type_app_css": "Niestandardowy CSS",
"type_render_note": "Renderuj notatkę",
"type_web_view": "Widok strony",
"type_app_theme": "Własny motyw",
"toggle_tooltip_enable_tooltip": "Kliknij, aby włączyć {{type}}.",
"toggle_tooltip_disable_tooltip": "Kliknij, aby wyłączyć {{type}}.",
"menu_docs": "Otwórz dokumentację",
"menu_execute_now": "Uruchom skrypt teraz",
"menu_run": "Uruchamiaj automatycznie",
"menu_run_disabled": "Ręcznie",
"menu_run_backend_startup": "Podczas uruchamiania backendu",
"menu_run_hourly": "Co godzinę",
"menu_run_daily": "Codziennie",
"menu_run_frontend_startup": "Podczas uruchamiania desktopowego frontendu",
"menu_run_mobile_startup": "Podczas uruchamiania mobilnego frontendu",
"menu_change_to_widget": "Zmień na widżet",
"menu_change_to_frontend_script": "Zmień na skrypt frontendowy",
"menu_theme_base": "Baza motywu"
},
"setup_form": {
"more_info": "Dowiedz się więcej"
}
}

View File

@@ -1179,149 +1179,6 @@
"enable-smooth-scroll": "Activar deslocamento suave",
"app-restart-required": "(é necessário reiniciar a aplicação para aplicar as alterações)"
},
"ai_llm": {
"not_started": "Não iniciado",
"title": "Configurações de IA",
"processed_notes": "Notas Processadas",
"total_notes": "Total de Notas",
"progress": "Andamento",
"queued_notes": "Notas Enfileiradas",
"failed_notes": "Notas com Falha",
"last_processed": "Últimas Processadas",
"refresh_stats": "Atualizar Estatísticas",
"enable_ai_features": "Ativar recurso IA/LLM",
"enable_ai_description": "Ativar recursos IA como sumarização de notas, geração de conteúdo e outras capacidades de LLM",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Ativar recursos IA/LLM",
"enable_ai_desc": "Ativar recursos de IA como sumarização de notas, geração de conteúdo e outras capacidades de LLM",
"provider_configuration": "Configuração de Provedor de IA",
"provider_precedence": "Prioridade de provedor",
"provider_precedence_description": "Lista de provedores em ordem de prioridade, separados por vírgula (por exemplo, 'openai, anthropic, ollama')",
"temperature": "Temperatura",
"temperature_description": "Controla a aleatoriedade em respostas (0 = determinística, 2 = aleatoriedade máxima)",
"system_prompt": "Prompt de Sistema",
"system_prompt_description": "Prompt padrão de sistema usado para todas as interações de IA",
"openai_configuration": "Configuração OpenAI",
"openai_settings": "Opções OpenAI",
"api_key": "Chave de API",
"url": "URL Base",
"model": "Modelo",
"openai_api_key_description": "A sua API Key da OpenAI para aceder os serviços de IA",
"anthropic_api_key_description": "A sua API Key da Anthropic para aceder os modelos Claude",
"default_model": "Modelo Padrão",
"openai_model_description": "Exemplos: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "URL Base",
"openai_url_description": "Padrão: https://api.openai.com/v1",
"anthropic_settings": "Configurações Anthropic",
"anthropic_url_description": "URL Base da API Anthropic (padrão: https://api.anthropic.com)",
"anthropic_model_description": "Modelos Claude da Anthropic para completar conversas",
"voyage_settings": "Configurações Voyage AI",
"ollama_settings": "Configurações do Ollama",
"ollama_url_description": "URL para a API Ollama (padrão: http://localhost:11434)",
"ollama_model_description": "Modelo Ollama usado para complementação de chat",
"anthropic_configuration": "Configuração da Anthropic",
"voyage_configuration": "Configuração da Voyage IA",
"voyage_url_description": "Padrão: https://api.voyageai.com/v1",
"ollama_configuration": "Configuração da Ollama",
"enable_ollama": "Ativar Ollama",
"enable_ollama_description": "Ativar Ollama para uso do modelo local de IA",
"ollama_url": "URL da Ollama",
"ollama_model": "Modelo do Ollama",
"refresh_models": "Atualizar Modelos",
"refreshing_models": "A atualizar…",
"enable_automatic_indexing": "Ativar indexação automática",
"rebuild_index": "Reconstruir Índice",
"rebuild_index_error": "Ocorreu um erro ao iniciar a reconstrução do índice. Verifique os logs para obter pormenores.",
"note_title": "Título da nota",
"error": "Erro",
"last_attempt": "Última Tentativa",
"actions": "Ações",
"retry": "Tentar novamente",
"partial": "{{ percentage }}% concluído",
"retry_queued": "Nota enfileirada para nova tentativa",
"retry_failed": "Falha ao enfileirar nota para nova tentativa",
"max_notes_per_llm_query": "Máximo de Notas por Consulta",
"max_notes_per_llm_query_description": "Quantidade máxima de notas similares para incluir no contexto da IA",
"active_providers": "Provedores Ativos",
"disabled_providers": "Provedores Desativados",
"remove_provider": "Remover provedor da pesquisa",
"restore_provider": "Restaurar provedor na pesquisa",
"similarity_threshold": "Tolerância de Similaridade",
"similarity_threshold_description": "Pontuação máxima de similaridade (0-1) para notas a serem incluídas no contexto das consultas de LLM",
"reprocess_index": "Reconstruir Índice de Pesquisa",
"reprocessing_index": "A reconstruir…",
"reprocess_index_started": "Otimiação do índice de pesquisa iniciado em plano de fundo",
"reprocess_index_error": "Erro ao reconstruir índice de pesquisa",
"index_rebuild_progress": "Andamento da Reconstrução do Índice",
"index_rebuilding": "A otimizar índice ({{percentage}}%)",
"index_rebuild_complete": "Otimização de índice finalizada",
"index_rebuild_status_error": "Erro ao verificar o estado da reconstrução do índice",
"never": "Nunca",
"processing": "A processar ({{percentage}}%)",
"incomplete": "Incompleto ({{percentage}}%)",
"complete": "Completo (100%)",
"refreshing": "A atualizar…",
"auto_refresh_notice": "A atualizar automaticamente a cada {{seconds}} segundos",
"note_queued_for_retry": "Nota enfileirada para nova tentativa",
"failed_to_retry_note": "Falha ao retentar nota",
"all_notes_queued_for_retry": "Todas as notas com falha enfileiradas para nova tentativa",
"failed_to_retry_all": "Falha ao retentar notas",
"ai_settings": "Configurações IA",
"api_key_tooltip": "Chave de API para aceder o serviço",
"empty_key_warning": {
"anthropic": "A chave de API Anthropic está vazia. Por favor, digite uma chave de API válida.",
"openai": "A chave de API OpenAI está vazia. Por favor, digite uma chave de API válida.",
"voyage": "A chave de API da Voyage API está vazia. Por favor, digite uma chave de API válida.",
"ollama": "A chave de API da Ollama API está vazia. Por favor, digite uma chave de API válida."
},
"agent": {
"processing": "A processar…",
"thinking": "A pensar…",
"loading": "A carregar…",
"generating": "A gerir…"
},
"name": "IA",
"openai": "OpenAI",
"use_enhanced_context": "Usar contexto aprimorado",
"enhanced_context_description": "Alimentar IA com mais contexto sobre a nota e as suas notas relacionadas para melhores respostas",
"show_thinking": "Exibir pensamento",
"show_thinking_description": "Exibir o processo de linha de raciocínio da AI",
"enter_message": "Digite a sua mensagem…",
"error_contacting_provider": "Erro ao contactar o provedor de IA. Por favor, verifique as suas configurações e a sua conexão à internet.",
"error_generating_response": "Erro ao gerar resposta da IA",
"index_all_notes": "Indexar Todas as Notas",
"index_status": "Estado do Índice",
"indexed_notes": "Notas Indexadas",
"indexing_stopped": "Indexação interrompida",
"indexing_in_progress": "Indexação em andamento…",
"last_indexed": "Última Indexada",
"note_chat": "Conversa de Nota",
"sources": "Origens",
"start_indexing": "Iniciar Indexação",
"use_advanced_context": "Usar Contexto Avançado",
"ollama_no_url": "Ollama não está configurado. Por favor, digite uma URL válida.",
"chat": {
"root_note_title": "Conversas IA",
"root_note_content": "Esta nota contém as suas conversas com IA gravdas.",
"new_chat_title": "Nova Conversa",
"create_new_ai_chat": "Criar Conversa IA"
},
"create_new_ai_chat": "Criar Conversa IA",
"configuration_warnings": "Há problemas com a sua configuração de IA. Por favor, verifique as suas configurações.",
"experimental_warning": "O recurso de LLM atualmente é experimental - você foi avisado.",
"selected_provider": "Provedor Selecionado",
"selected_provider_description": "Escolha o provedor de IA para conversas e recursos de completar",
"select_model": "Selecionar modelo…",
"select_provider": "Selecionar provedor…",
"ai_enabled": "Recursos de IA ativados",
"ai_disabled": "Recursos de IA desativados",
"no_models_found_online": "Nenhum modelo encontrado. Por favor, verifique a sua chave de API e as configurações.",
"no_models_found_ollama": "Nenhum modelo Ollama encontrado. Por favor, verifique se o Ollama está em execução.",
"error_fetching": "Erro ao obter modelos: {{error}}"
},
"zoom_factor": {
"title": "Fator do Zoom (apenas versão de área de trabalho)",
"description": "O zoom também pode ser controlado com atalhos CTRL+- e CTRL+=."
@@ -1691,7 +1548,6 @@
"confirm-change": "Não é recomentado alterar o tipo da nota quando o conteúdo da nota não está vazio. Quer continuar assim mesmo?",
"geo-map": "Mapa geográfico",
"beta-feature": "Beta",
"ai-chat": "Chat IA",
"task-list": "Lista de Tarefas",
"new-feature": "Novo",
"collections": "Coleções"
@@ -1918,6 +1774,7 @@
"add-term-to-dictionary": "Adicionar \"{{term}}\" ao dicionário",
"cut": "Cortar",
"copy": "Copiar",
"copy-as-markdown": "Copiar como markdown",
"copy-link": "Copiar ligação",
"paste": "Colar",
"paste-as-plain-text": "Colar como texto sem formatação",

View File

@@ -85,149 +85,6 @@
"clone_to_selected_note": "Clonar para a nota selecionada",
"note_cloned": "A nota \"{{clonedTitle}}\" foi clonada para \"{{targetTitle}}\""
},
"ai_llm": {
"temperature": "Temperatura",
"retry_queued": "Nota enfileirada para nova tentativa",
"queued_notes": "Notas Enfileiradas",
"empty_key_warning": {
"voyage": "A chave de API da Voyage API está vazia. Por favor, digite uma chave de API válida.",
"ollama": "A chave de API da Ollama API está vazia. Por favor, digite uma chave de API válida.",
"anthropic": "A chave de API Anthropic está vazia. Por favor, digite uma chave de API válida.",
"openai": "A chave de API OpenAI está vazia. Por favor, digite uma chave de API válida."
},
"not_started": "Não iniciado",
"title": "Configurações de IA",
"processed_notes": "Notas Processadas",
"total_notes": "Total de Notas",
"progress": "Andamento",
"failed_notes": "Notas com Falha",
"last_processed": "Últimas Processadas",
"refresh_stats": "Atualizar Estatísticas",
"enable_ai_features": "Ativar recurso IA/LLM",
"enable_ai_description": "Ativar recursos IA como sumarização de notas, geração de conteúdo, e outras capacidades de LLM",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"enable_ai": "Ativar recursos IA/LLM",
"provider_configuration": "Configuração de Provedor de IA",
"system_prompt": "Prompt de Sistema",
"system_prompt_description": "Prompt padrão de sistema usado para todas as interações de IA",
"openai_configuration": "Configuração OpenAI",
"openai_settings": "Opções OpenAI",
"api_key": "Chave de API",
"url": "URL Base",
"model": "Modelo",
"openai_api_key_description": "Sua API Key da OpenAI para acessar os serviços de IA",
"anthropic_api_key_description": "Sua API Key da Anthropic para acessar os modelos Claude",
"default_model": "Modelo Padrão",
"openai_model_description": "Exemplos: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "URL Base",
"openai_url_description": "Padrão: https://api.openai.com/v1",
"anthropic_settings": "Configurações Anthropic",
"anthropic_url_description": "URL Base da API Anthropic (padrão: https://api.anthropic.com)",
"anthropic_model_description": "Modelos Claude da Anthropic para completar conversas",
"voyage_settings": "Configurações Voyage AI",
"retry": "Tentar novamente",
"retry_failed": "Falha ao enfileirar nota para nova tentativa",
"max_notes_per_llm_query": "Máximo de Notas por Consulta",
"max_notes_per_llm_query_description": "Número máximo de notas similares para incluir no contexto da IA",
"active_providers": "Provedores Ativos",
"disabled_providers": "Provedores Desativados",
"remove_provider": "Remover provedor da pesquisa",
"restore_provider": "Restaurar provedor na pesquisa",
"similarity_threshold": "Tolerância de Similaridade",
"similarity_threshold_description": "Pontuação máxima de similaridade (0-1) para notas a serem incluídas no contexto das consultas de LLM",
"reprocess_index": "Reconstruir Índice de Pesquisa",
"reprocessing_index": "Reconstruindo…",
"reprocess_index_started": "Otimiação do índice de pesquisa iniciado em plano de fundo",
"reprocess_index_error": "Erro ao reconstruir índice de pesquisa",
"index_rebuild_progress": "Andamento da Reconstrução do Índice",
"index_rebuilding": "Otimizando índice ({{percentage}}%)",
"index_rebuild_complete": "Otimização de índice finalizada",
"index_rebuild_status_error": "Erro ao verificar o estado da reconstrução do índice",
"never": "Nunca",
"processing": "Processando ({{percentage}}%)",
"incomplete": "Incompleto ({{percentage}}%)",
"complete": "Completo (100%)",
"refreshing": "Atualizando…",
"auto_refresh_notice": "Atualizando automaticamente a cada {{seconds}} segundos",
"note_queued_for_retry": "Nota enfileirada para nova tentativa",
"failed_to_retry_note": "Falha ao retentar nota",
"all_notes_queued_for_retry": "Todas as notas com falha enfileiradas para nova tentativa",
"failed_to_retry_all": "Falha ao retentar notas",
"ai_settings": "Configurações IA",
"api_key_tooltip": "Chave de API para acessar o serviço",
"agent": {
"processing": "Processando…",
"thinking": "Pensando…",
"loading": "Carregando…",
"generating": "Gerando…"
},
"name": "IA",
"openai": "OpenAI",
"use_enhanced_context": "Usar contexto aprimorado",
"enhanced_context_description": "Alimentar IA com mais contexto sobre a nota e suas notas relacionadas para melhores respostas",
"show_thinking": "Exibir pensamento",
"enter_message": "Digite sua mensagem…",
"error_contacting_provider": "Erro ao contatar o provedor de IA. Por favor, verifique suas configurações e sua conexão de internet.",
"error_generating_response": "Erro ao gerar resposta da IA",
"index_all_notes": "Indexar Todas as Notas",
"index_status": "Estado do Índice",
"indexed_notes": "Notas Indexadas",
"indexing_stopped": "Indexação interrompida",
"indexing_in_progress": "Indexação em andamento…",
"last_indexed": "Última Indexada",
"note_chat": "Conversa de Nota",
"sources": "Origens",
"start_indexing": "Iniciar Indexação",
"use_advanced_context": "Usar Contexto Avançado",
"ollama_no_url": "Ollama não está configurado. Por favor, digite uma URL válida.",
"chat": {
"root_note_title": "Conversas IA",
"root_note_content": "Esta nota contém suas conversas com IA salvas.",
"new_chat_title": "Nova Conversa",
"create_new_ai_chat": "Criar nova Conversa IA"
},
"create_new_ai_chat": "Criar nova Conversa IA",
"configuration_warnings": "Existem alguns problemas com sua configuração de IA. Por fovor, verifique suas configurações.",
"experimental_warning": "O recurso de LLM atualmente é experimental - você foi avisado.",
"selected_provider": "Provedor Selecionado",
"selected_provider_description": "Escolha o provedor de IA para conversas e recursos de completar",
"select_model": "Selecionar modelo…",
"select_provider": "Selecionar provedor…",
"ai_enabled": "Recursos de IA habilitados",
"ai_disabled": "Recursos de IA desabilitados",
"no_models_found_online": "Nenhum modelo encontrado. Por favor, verifique sua chave de API e as configurações.",
"no_models_found_ollama": "Nenhum modelo Ollama encontrado. Por favor, verifique se o Ollama está em execução.",
"error_fetching": "Erro ao obter modelos: {{error}}",
"ollama_tab": "Ollama",
"enable_ai_desc": "Habilitar recursos de IA como sumarização de notas, geração de conteúdo, e outras capacidades de LLM",
"provider_precedence": "Prioridade de provedor",
"provider_precedence_description": "Lista de provedores em ordem de prioridade, separados por vírgula (por exemplo, 'openai, anthropic, ollama')",
"temperature_description": "Controla a aleatoriedade em respostas (0 = determinística, 2 = aleatoriedade máxima)",
"ollama_settings": "Configurações do Ollama",
"ollama_url_description": "URL para a API Ollama (padrão: http://localhost:11434)",
"ollama_model_description": "Modelo Ollama usado para complementação de chat",
"anthropic_configuration": "Configuração da Anthropic",
"voyage_configuration": "Configuração da Voyage IA",
"voyage_url_description": "Padrão: https://api.voyageai.com/v1",
"ollama_configuration": "Configuração da Ollama",
"enable_ollama": "Habilitar Ollama",
"enable_ollama_description": "Habilitar Ollama para uso do modelo local de IA",
"ollama_url": "URL da Ollama",
"ollama_model": "Modelo do Ollama",
"refresh_models": "Atualizar Modelos",
"refreshing_models": "Atualizando…",
"enable_automatic_indexing": "Habilitar indexação automática",
"rebuild_index": "Reconstruir Índice",
"rebuild_index_error": "Ocorreu um erro ao iniciar a reconstrução do índice. Verifique os logs para obter detalhes.",
"note_title": "Título da nota",
"error": "Erro",
"last_attempt": "Última Tentativa",
"actions": "Ações",
"partial": "{{ percentage }}% concluído",
"show_thinking_description": "Exibir o processo de linha de raciocínio da AI"
},
"confirm": {
"confirmation": "Confirmação",
"cancel": "Cancelar",
@@ -1575,7 +1432,6 @@
"confirm-change": "Não é recomentado alterar o tipo da nota quando o conteúdo da nota não está vazio. Quer continuar assim mesmo?",
"geo-map": "Mapa geográfico",
"beta-feature": "Beta",
"ai-chat": "Chat IA",
"task-list": "Lista de Tarefas",
"new-feature": "Novo",
"collections": "Coleções",
@@ -1781,6 +1637,7 @@
"add-term-to-dictionary": "Adicionar \"{{term}}\" ao dicionário",
"cut": "Cortar",
"copy": "Copiar",
"copy-as-markdown": "Copiar como markdown",
"copy-link": "Copiar link",
"paste": "Colar",
"paste-as-plain-text": "Colar como texto sem formatação",

View File

@@ -1457,7 +1457,6 @@
"geo-map": "Hartă geografică",
"beta-feature": "Beta",
"task-list": "Listă de sarcini",
"ai-chat": "Discuție cu AI-ul",
"new-feature": "Nou",
"collections": "Colecții"
},
@@ -1725,6 +1724,7 @@
"electron_context_menu": {
"add-term-to-dictionary": "Adaugă „{{term}}” în dicționar",
"copy": "Copiază",
"copy-as-markdown": "Copiază ca markdown",
"copy-link": "Copiază legătura",
"cut": "Decupează",
"paste": "Lipește",
@@ -1835,149 +1835,6 @@
"lock-editing": "Blochează editarea",
"unlock-editing": "Deblochează editarea"
},
"ai_llm": {
"not_started": "Nu s-a pornit",
"title": "Setări AI",
"processed_notes": "Notițe procesate",
"total_notes": "Totalul de notițe",
"progress": "Progres",
"queued_notes": "Notițe în curs de procesare",
"failed_notes": "Notițe ce au eșuat",
"last_processed": "Ultima procesare",
"refresh_stats": "Reîmprospătare statistici",
"enable_ai_features": "Activează funcțiile AI/LLM",
"enable_ai_description": "Activează funcțiile AI precum sumarizarea notițelor, generarea de conținut și alte capabilități ale LLM-ului",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Activează funcții AI/LLM",
"enable_ai_desc": "Activează funcțiile AI precum sumarizarea notițelor, generarea de conținut și alte capabilități ale LLM-ului",
"provider_configuration": "Setările furnizorului de AI",
"provider_precedence": "Ordinea de precedență a furnizorilor",
"provider_precedence_description": "Lista de furnizori în ordinea de precedență, separate de virgulă (ex. „openai,anthropic,ollama”)",
"temperature": "Temperatură",
"temperature_description": "Controlează aleatoritatea din răspunsuri (0 = deterministic, 2 = maxim aleator)",
"system_prompt": "Prompt-ul de sistem",
"system_prompt_description": "Prompt-ul de sistem folosit pentru toate interacțiunile cu AI-ul",
"openai_configuration": "Configurația OpenAI",
"openai_settings": "Setările OpenAI",
"api_key": "Cheie API",
"url": "URL de bază",
"model": "Model",
"openai_api_key_description": "Cheia de API din OpenAI pentru a putea accesa serviciile de AI",
"anthropic_api_key_description": "Cheia de API din Anthropic pentru a accesa modelele Claude",
"default_model": "Modelul implicit",
"openai_model_description": "Exemple: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "URL de bază",
"openai_url_description": "Implicit: https://api.openai.com/v1",
"anthropic_settings": "Setări Anthropic",
"anthropic_url_description": "URL de bază pentru API-ul Anthropic (implicit: https://api.anthropic.com)",
"anthropic_model_description": "Modele Anthropic Claude pentru auto-completare",
"voyage_settings": "Setări Voyage AI",
"ollama_settings": "Setări Ollama",
"ollama_url_description": "URL pentru API-ul Ollama (implicit: http://localhost:11434)",
"ollama_model_description": "Modelul Ollama pentru auto-completare",
"anthropic_configuration": "Configurația Anthropic",
"voyage_configuration": "Configurația Voyage AI",
"voyage_url_description": "Implicit: https://api.voyageai.com/v1",
"ollama_configuration": "Configurația Ollama",
"enable_ollama": "Activează Ollama",
"enable_ollama_description": "Activează Ollama pentru a putea utiliza modele AI locale",
"ollama_url": "URL Ollama",
"ollama_model": "Model Ollama",
"refresh_models": "Reîmprospătează modelele",
"refreshing_models": "Reîmprospătare...",
"enable_automatic_indexing": "Activează indexarea automată",
"rebuild_index": "Reconstruire index",
"rebuild_index_error": "Eroare la reconstruirea indexului. Verificați logurile pentru mai multe detalii.",
"note_title": "Titlul notiței",
"error": "Eroare",
"last_attempt": "Ultima încercare",
"actions": "Acțiuni",
"retry": "Reîncercare",
"partial": "{{ percentage }}% finalizat",
"retry_queued": "Notiță pusă în coadă pentru reîncercare",
"retry_failed": "Nu s-a putut pune notița în coada pentru reîncercare",
"max_notes_per_llm_query": "Număr maximum de notițe per interogare",
"max_notes_per_llm_query_description": "Numărul maxim de notițe similare incluse în contextul pentru AI",
"active_providers": "Furnizori activi",
"disabled_providers": "Furnizori dezactivați",
"remove_provider": "Șterge furnizorul din căutare",
"restore_provider": "Restaurează furnizorul pentru căutare",
"similarity_threshold": "Prag de similaritate",
"similarity_threshold_description": "Scorul minim de similaritate (0-1) pentru a include notițele în contextul interogărilor LLM",
"reprocess_index": "Reconstruiește indexul de căutare",
"reprocessing_index": "Reconstruire...",
"reprocess_index_started": "S-a pornit în fundal optimizarea indexului de căutare",
"reprocess_index_error": "Eroare la reconstruirea indexului de căutare",
"index_rebuild_progress": "Reconstruire index în curs",
"index_rebuilding": "Optimizare index ({{percentage}}%)",
"index_rebuild_complete": "Optimizarea indexului a avut loc cu succes",
"index_rebuild_status_error": "Eroare la verificarea stării reconstruirii indexului",
"never": "Niciodată",
"processing": "Procesare ({{percentage}}%)",
"incomplete": "Incomplet ({{percentage}}%)",
"complete": "Complet (100%)",
"refreshing": "Reîmprospătare...",
"auto_refresh_notice": "Reîmprospătare automată la fiecare {{seconds}} secunde",
"note_queued_for_retry": "Notiță pusă în coadă pentru reîncercare",
"failed_to_retry_note": "Eroare la reîncercarea notiței",
"all_notes_queued_for_retry": "Toate notițele eșuate au fost puse în coada de reîncercare",
"failed_to_retry_all": "Eroare la reîncercarea notițelor",
"ai_settings": "Setări AI",
"api_key_tooltip": "Cheia API pentru accesarea serviciului",
"empty_key_warning": {
"anthropic": "Cheia API pentru Anthropic lipsește. Introduceți o cheie API validă.",
"openai": "Cheia API pentru OpenAI lipsește. Introduceți o cheie API validă.",
"voyage": "Cheia API pentru Voyage lipsește. Introduceți o cheie API validă.",
"ollama": "Cheia API pentru Ollama lipsește. Introduceți o cheie API validă."
},
"agent": {
"processing": "Procesare...",
"thinking": "Raționalizare...",
"loading": "Încărcare...",
"generating": "Generare..."
},
"name": "AI",
"openai": "OpenAI",
"use_enhanced_context": "Folosește context îmbogățit",
"enhanced_context_description": "Oferă AI-ului mai multe informații de context din notiță și notițele similare pentru răspunsuri mai bune",
"show_thinking": "Afișează procesul de raționalizare",
"show_thinking_description": "Afișează lanțul de acțiuni din procesul de gândire al AI-ului",
"enter_message": "Introduceți mesajul...",
"error_contacting_provider": "Eroare la contactarea furnizorului de AI. Verificați setările și conexiunea la internet.",
"error_generating_response": "Eroare la generarea răspunsului AI",
"index_all_notes": "Indexează toate notițele",
"index_status": "Starea indexării",
"indexed_notes": "Notițe indexate",
"indexing_stopped": "Indexarea s-a oprit",
"indexing_in_progress": "Indexare în curs...",
"last_indexed": "Ultima indexare",
"note_chat": "Discuție pe baza notițelor",
"sources": "Surse",
"start_indexing": "Indexează",
"use_advanced_context": "Folosește context îmbogățit",
"ollama_no_url": "Ollama nu este configurat. Introduceți un URL corect.",
"chat": {
"root_note_title": "Discuții cu AI-ul",
"root_note_content": "Această notiță stochează conversația cu AI-ul.",
"new_chat_title": "Discuție nouă",
"create_new_ai_chat": "Crează o nouă discuție cu AI-ul"
},
"create_new_ai_chat": "Crează o nouă discuție cu AI-ul",
"configuration_warnings": "Sunt câteva probleme la configurația AI-ului. Verificați setările.",
"experimental_warning": "Funcția LLM este experimentală.",
"selected_provider": "Furnizor selectat",
"selected_provider_description": "Selectați furnizorul de AI pentru funcțiile de discuție și completare",
"select_model": "Selectați modelul...",
"select_provider": "Selectați furnizorul...",
"ai_enabled": "Funcționalitățile AI au fost activate",
"ai_disabled": "Funcționalitățile AI au fost dezactivate",
"no_models_found_online": "Nu s-a găsit niciun model. Verificați cheia API și configurația.",
"no_models_found_ollama": "Nu s-a găsit niciun model Ollama. Verificați dacă Ollama rulează.",
"error_fetching": "Eroare la obținerea modelelor: {{error}}"
},
"custom_date_time_format": {
"title": "Format dată/timp personalizat",
"description": "Personalizați formatul de dată și timp inserat prin <shortcut /> sau din bara de unelte. Vedeți <doc>Documentația Day.js</doc> pentru câmpurile de formatare disponibile.",

View File

@@ -708,6 +708,7 @@
"paste": "Вставить",
"copy-link": "Скопировать ссылку",
"copy": "Скопировать",
"copy-as-markdown": "Копировать как Markdown",
"cut": "Вырезать",
"search_online": "Поиск \"{{term}}\" в {{searchEngine}}",
"add-term-to-dictionary": "Добавить \"{{term}}\" в словарь",
@@ -824,7 +825,6 @@
"web-view": "Веб-страница",
"mind-map": "Mind Map",
"geo-map": "Географическая карта",
"ai-chat": "ИИ Чат",
"task-list": "Список задач",
"confirm-change": "Не рекомендуется менять тип заметки, если её содержимое не пустое. Вы всё равно хотите продолжить?"
},
@@ -1257,149 +1257,6 @@
"disabled": "выключено",
"title": "Системная панель заголовка (требует перезапуска приложения)"
},
"ai_llm": {
"progress": "Прогресс",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"ollama_tab": "Ollama",
"temperature": "Температура",
"model": "Модель",
"refreshing_models": "Обновление...",
"error": "Ошибка",
"actions": "Действия",
"retry": "Повторить",
"never": "Никогда",
"refreshing": "Обновление...",
"agent": {
"processing": "Обработка...",
"thinking": "Думаю...",
"loading": "Загрузка...",
"generating": "Создание..."
},
"name": "AI",
"openai": "OpenAI",
"sources": "Источники",
"reprocessing_index": "Перестройка индекса...",
"processed_notes": "Обработанные заметки",
"total_notes": "Всего заметок",
"queued_notes": "Заметок в очереди",
"failed_notes": "Заметки с ошибками обработки",
"last_processed": "Последние обработанные",
"refresh_stats": "Обновить статистику",
"voyage_tab": "Voyage AI",
"system_prompt": "Системный промпт",
"openai_configuration": "Конфигурация OpenAI",
"openai_settings": "Настройки OpenAI",
"api_key": "Ключ API",
"url": "Базовый URL",
"default_model": "Модель по умолчанию",
"base_url": "Базовый URL",
"openai_url_description": "По умолчанию: https://api.openai.com/v1",
"anthropic_settings": "Настройки Anthropic",
"ollama_settings": "Настройки Ollama",
"anthropic_configuration": "Конфигурация Anthropic",
"voyage_url_description": "По умолчанию: https://api.voyageai.com/v1",
"ollama_configuration": "Конфигурация Ollama",
"enable_ollama": "Включить Ollama",
"ollama_url": "URL Ollama",
"ollama_model": "Модель Ollama",
"refresh_models": "Обновить модели",
"rebuild_index": "Пересобрать индекс",
"note_title": "Название заметки",
"last_attempt": "Последняя попытка",
"active_providers": "Активные провайдеры",
"disabled_providers": "Отключенные провайдеры",
"similarity_threshold": "Порок сходства",
"processing": "Обработка ({{percentage}}%)",
"incomplete": "Не завершено ({{percentage}}%)",
"complete": "Завершено (100%)",
"ai_settings": "Настройки AI",
"show_thinking": "Отображать размышление",
"index_status": "Статус индексирования",
"indexed_notes": "Проиндексированные заметки",
"indexing_stopped": "Индексирование остановлено",
"last_indexed": "Индексировано в последний раз",
"note_chat": "Чат по заметке",
"start_indexing": "Начать индексирование",
"chat": {
"root_note_title": "Чаты с AI",
"new_chat_title": "Новый чат",
"create_new_ai_chat": "Создать новый чат с ИИ",
"root_note_content": "В этой заметке содержатся сохраненные вами разговоры в чате ИИ."
},
"selected_provider": "Выбранный провайдер",
"select_model": "Выбрать модель...",
"select_provider": "Выбрать провайдера...",
"title": "Настройки AI",
"voyage_settings": "Настройки Voyage AI",
"error_contacting_provider": "Ошибка подключения к провайдеру AI. Проверьте настройки и подключение к интернету.",
"configuration_warnings": "Возникли проблемы с конфигурацией AI. Проверьте настройки.",
"selected_provider_description": "Выберите провайдер AI для функций чата и автодополнения",
"provider_configuration": "Конфигурация провайдера AI",
"ollama_url_description": "URL для API Ollama (по умолчанию: http://localhost:11434)",
"ollama_model_description": "Модель Ollama для автодополнения чата",
"temperature_description": "Контролирует случайность ответов (0 = детерминированный, 2 = максимальная случайность)",
"system_prompt_description": "Системный промпт по умолчанию, используемый для всех взаимодействий с ИИ",
"empty_key_warning": {
"openai": "Ключ API OpenAI пуст. Введите действительный ключ API.",
"ollama": "API-ключ Ollama пуст. Введите действительный API-ключ.",
"voyage": "Ключ API Voyage пуст. Введите действительный ключ API.",
"anthropic": "Ключ API Anthropic пуст. Введите действительный ключ API."
},
"openai_api_key_description": "Ваш ключ API OpenAI для доступа к их службам ИИ",
"provider_precedence_description": "Список провайдеров, разделенных запятыми, в порядке приоритета (например, \"openai,anthropic,ollama\")",
"remove_provider": "Удалить провайдер из поиска",
"not_started": "Не запущено",
"provider_precedence": "Приоритет провайдера",
"enable_ai_features": "Включить функции AI/LLM",
"enable_ai": "Включить функции AI/LLM",
"voyage_configuration": "Конфигурация Voyage AI",
"enable_automatic_indexing": "Включить автоматическое индексирование",
"reprocess_index": "Перестроить индекс поиска",
"index_rebuild_progress": "Прогресс перестройки индекса",
"index_rebuilding": "Оптимизация индекса ({{percentage}}%)",
"index_rebuild_complete": "Оптимизация индекса завершена",
"use_enhanced_context": "Использовать улучшенный контекст",
"enter_message": "Введите ваше сообщение...",
"index_all_notes": "Индексировать все заметки",
"indexing_in_progress": "Индексация в процессе...",
"use_advanced_context": "Использовать расширенный контекст",
"openai_model_description": "Примеры: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"partial": "{{ percentage }}% завершено",
"retry_queued": "Примечание поставлено в очередь на повторную попытку",
"max_notes_per_llm_query": "Макс. количество заметок на запрос",
"reprocess_index_error": "Ошибка перестройки поискового индекса",
"auto_refresh_notice": "Автоматически обновляется каждые {{seconds}} секунд",
"note_queued_for_retry": "Заметка поставлена в очередь на повторную попытку",
"failed_to_retry_note": "Не удалось повторить попытку",
"failed_to_retry_all": "Не удалось повторить попытку",
"error_generating_response": "Ошибка генерации ответа ИИ",
"create_new_ai_chat": "Создать новый чат с ИИ",
"ai_enabled": "Возможности ИИ активны",
"ai_disabled": "Возможности ИИ неактивны",
"restore_provider": "Восстановить значение провайдера",
"error_fetching": "Ошибка получения списка моделей: {{error}}",
"index_rebuild_status_error": "Ошибка проверки статуса перестроения индекса",
"enhanced_context_description": "Предоставляет ИИ больше контекста из заметки и связанных с ней заметок для более точных ответов",
"no_models_found_ollama": "Модели Ollama не найдены. Проверьте, запущена ли Ollama.",
"no_models_found_online": "Модели не найдены. Проверьте ваш ключ API и настройки.",
"experimental_warning": "Функция LLM в настоящее время является экспериментальной — вы предупреждены.",
"ollama_no_url": "Ollama не настроена. Введите корректный URL-адрес.",
"show_thinking_description": "Показать цепочку мыслительного процесса ИИ",
"api_key_tooltip": "API-ключ для доступа к сервису",
"all_notes_queued_for_retry": "Все неудачные заметки поставлены в очередь на повторную попытку",
"reprocess_index_started": "Оптимизация поискового индекса запущена в фоновом режиме",
"similarity_threshold_description": "Минимальный показатель сходства (similarity score, 01) для заметок, которые следует включить в контекст запросов LLM",
"max_notes_per_llm_query_description": "Максимальное количество похожих заметок для включения в контекст ИИ",
"retry_failed": "Не удалось поставить заметку в очередь для повторной попытки",
"rebuild_index_error": "Ошибка при запуске перестроения индекса. Подробности смотрите в логах.",
"enable_ollama_description": "Включить Ollama для использования локальной модели ИИ",
"anthropic_model_description": "Модели Anthropic Claude для автодополнения чата",
"anthropic_url_description": "Базовый URL для Anthropic API (по умолчанию: https://api.anthropic.com)",
"anthropic_api_key_description": "Ваш ключ Anthropic API для доступа к моделям Claude",
"enable_ai_desc": "Включить функции ИИ, такие как резюмирование заметок, генерация контента и другие возможности LLM",
"enable_ai_description": "Включить функции ИИ, такие как резюмирование заметок, генерация контента и другие возможности LLM"
},
"code-editor-options": {
"title": "Редактор"
},

View File

@@ -1,9 +1,9 @@
{
"about": {
"title": "Podrobnosti Trilium Notes",
"homepage": "Domača stran:",
"app_version": "Verzija aplikacije:",
"db_version": "Verzija DB:",
"sync_version": "Verzija Sync:"
}
"about": {
"title": "Podrobnosti Trilium Notes",
"homepage": "Domača stran:",
"app_version": "Verzija aplikacije:",
"db_version": "Verzija DB:",
"sync_version": "Verzija Sync:"
}
}

View File

@@ -50,8 +50,15 @@
},
"bundle-error": {
"title": "Özel bir betik yüklenemedi",
"message": "ID'si \"{{id}}\" ve başlığı \"{{title}}\" olan nottan alınan komut dosyası şunun nedeniyle yürütülemedi:\n\n{{message}}"
}
"message": "Komut şu nedenle yürütülemedi:\n\n{{message}}"
},
"widget-list-error": {
"title": "Sunucudan widget listesi alınamadı"
},
"widget-render-error": {
"title": "Özel React widget'ı çizilirken sorun yaşandı"
},
"scripting-error": "Kullanıcı tanımlı betik hatası: {{title}}"
},
"add_link": {
"add_link": "Bağlantı ekle",

View File

@@ -1493,10 +1493,10 @@
"book": "集合",
"geo-map": "地理地圖",
"beta-feature": "Beta",
"ai-chat": "AI 聊天",
"task-list": "任務列表",
"new-feature": "新增",
"collections": "集合"
"collections": "集合",
"ai-chat": "AI 聊天"
},
"protect_note": {
"toggle-on": "保護筆記",
@@ -1595,7 +1595,8 @@
},
"search_result": {
"no_notes_found": "沒有找到符合搜尋條件的筆記。",
"search_not_executed": "尚未執行搜尋。請點擊上方的「搜尋」按鈕查看結果。"
"search_not_executed": "尚未執行搜尋。",
"search_now": "立即搜尋"
},
"spacer": {
"configure_launchbar": "設定啟動欄"
@@ -1723,6 +1724,7 @@
"add-term-to-dictionary": "將 \"{{term}}\" 新增至字典",
"cut": "剪下",
"copy": "複製",
"copy-as-markdown": "複製為 Markdown",
"copy-link": "複製連結",
"paste": "貼上",
"paste-as-plain-text": "以純文字貼上",
@@ -1743,149 +1745,6 @@
"zen_mode": {
"button_exit": "退出禪模式"
},
"ai_llm": {
"not_started": "未開始",
"title": "AI 設定",
"processed_notes": "已處理筆記",
"total_notes": "筆記總數",
"progress": "進度",
"queued_notes": "隊列中筆記",
"failed_notes": "失敗筆記",
"last_processed": "最後處理時間",
"refresh_stats": "更新統計資料",
"enable_ai_features": "啟用 AI/LLM 功能",
"enable_ai_description": "啟用筆記摘要、內容生成等 AI 功能及其他 LLM 能力",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "啟用 AI/LLM 功能",
"enable_ai_desc": "啟用筆記摘要、內容生成等 AI 功能及其他 LLM 能力",
"provider_configuration": "AI 提供者設定",
"provider_precedence": "提供者優先級",
"provider_precedence_description": "依優先級排序的提供者列表(用逗號分隔,例如:'openai,anthropic,ollama'",
"temperature": "溫度",
"temperature_description": "控制回應的隨機性0 = 確定性2 = 最大隨機性)",
"system_prompt": "系統提示詞",
"system_prompt_description": "所有 AI 互動的預設系統提示詞",
"openai_configuration": "OpenAI 設定",
"openai_settings": "OpenAI 設定",
"api_key": "API 金鑰",
"url": "基礎 URL",
"model": "模型",
"openai_api_key_description": "用於存取 OpenAI 服務的 API 金鑰",
"anthropic_api_key_description": "用於存取 Claude 模型的 Anthropic API 金鑰",
"default_model": "預設模型",
"openai_model_description": "範例gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "基礎 URL",
"openai_url_description": "預設https://api.openai.com/v1",
"anthropic_settings": "Anthropic 設定",
"anthropic_url_description": "Anthropic API 的基礎 URL預設https://api.anthropic.com",
"anthropic_model_description": "用於聊天補全的 Anthropic Claude 模型",
"voyage_settings": "Voyage AI 設定",
"ollama_settings": "Ollama 設定",
"ollama_url_description": "Ollama API URL預設http://localhost:11434",
"ollama_model_description": "用於聊天補全的 Ollama 模型",
"anthropic_configuration": "Anthropic 設定",
"voyage_configuration": "Voyage AI 設定",
"voyage_url_description": "預設https://api.voyageai.com/v1",
"ollama_configuration": "Ollama 設定",
"enable_ollama": "啟用 Ollama",
"enable_ollama_description": "啟用 Ollama 以使用本地 AI 模型",
"ollama_url": "Ollama URL",
"ollama_model": "Ollama 模型",
"refresh_models": "重新整理模型",
"refreshing_models": "正在重新整理…",
"enable_automatic_indexing": "啟用自動索引",
"rebuild_index": "重建索引",
"rebuild_index_error": "啟動索引重建失敗。請查看日誌了解詳情。",
"note_title": "筆記標題",
"error": "錯誤",
"last_attempt": "最後嘗試時間",
"actions": "操作",
"retry": "重試",
"partial": "已完成 {{ percentage }}%",
"retry_queued": "筆記已加入重試隊列",
"retry_failed": "筆記加入重試隊列失敗",
"max_notes_per_llm_query": "每次查詢的最大筆記數",
"max_notes_per_llm_query_description": "AI 上下文包含的最大相似筆記數量",
"active_providers": "活躍提供者",
"disabled_providers": "已禁用的提供者",
"remove_provider": "從搜尋中移除提供者",
"restore_provider": "將提供者還原至搜尋中",
"similarity_threshold": "相似度閾值",
"similarity_threshold_description": "要包含在 LLM 查詢上下文中筆記的最低相似度分數0-1",
"reprocess_index": "重建搜尋索引",
"reprocessing_index": "正在重建…",
"reprocess_index_started": "搜尋索引最佳化已在背景啟動",
"reprocess_index_error": "重建搜尋索引失敗",
"index_rebuild_progress": "索引重建進度",
"index_rebuilding": "正在最佳化索引({{percentage}}%",
"index_rebuild_complete": "完成索引最佳化",
"index_rebuild_status_error": "檢查索引重建狀態失敗",
"never": "從未",
"processing": "正在處理({{percentage}}%",
"incomplete": "未完成({{percentage}}%",
"complete": "已完成100%",
"refreshing": "正在重新整理…",
"auto_refresh_notice": "每 {{seconds}} 秒自動重新整理",
"note_queued_for_retry": "筆記已加入重試隊列",
"failed_to_retry_note": "重試筆記失敗",
"all_notes_queued_for_retry": "所有失敗筆記已加入重試隊列",
"failed_to_retry_all": "重試筆記失敗",
"ai_settings": "AI 設定",
"api_key_tooltip": "用於存取服務的 API 金鑰",
"empty_key_warning": {
"anthropic": "Anthropic API 金鑰為空。請輸入有效的 API 金鑰。",
"openai": "OpenAI API 金鑰為空。請輸入有效的 API 金鑰。",
"voyage": "Voyage API 金鑰為空。請輸入有效的 API 金鑰。",
"ollama": "Ollama API 金鑰為空。請輸入有效的 API 金鑰。"
},
"agent": {
"processing": "正在處理…",
"thinking": "正在思考…",
"loading": "正在載入…",
"generating": "正在生成…"
},
"name": "AI",
"openai": "OpenAI",
"use_enhanced_context": "使用增強的上下文",
"enhanced_context_description": "提供 AI 更多來自筆記及其相關筆記的內容,以獲得更好的回應",
"show_thinking": "顯示思考過程",
"show_thinking_description": "顯示 AI 的思維鏈過程",
"enter_message": "輸入您的訊息…",
"error_contacting_provider": "聯繫 AI 提供者失敗。請檢查您的設定和網路連接。",
"error_generating_response": "生成 AI 回應失敗",
"index_all_notes": "為所有筆記建立索引",
"index_status": "索引狀態",
"indexed_notes": "已索引筆記",
"indexing_stopped": "已停止索引",
"indexing_in_progress": "正在進行索引…",
"last_indexed": "最後索引時間",
"note_chat": "筆記聊天",
"sources": "來源",
"start_indexing": "開始索引",
"use_advanced_context": "使用進階上下文",
"ollama_no_url": "尚未設定 Ollama。請輸入有效的 URL。",
"chat": {
"root_note_title": "AI 聊天記錄",
"root_note_content": "此筆記包含您儲存的 AI 聊天對話。",
"new_chat_title": "新聊天",
"create_new_ai_chat": "建立新的 AI 聊天"
},
"create_new_ai_chat": "建立新的 AI 聊天",
"configuration_warnings": "您的 AI 配置存在一些問題。請檢查您的設定。",
"experimental_warning": "特此提醒LLM 功能目前正處於實驗階段。",
"selected_provider": "已選提供者",
"selected_provider_description": "選擇用於聊天和補全功能的 AI 提供者",
"select_model": "選擇模型…",
"select_provider": "選擇提供者…",
"ai_enabled": "已啟用 AI 功能",
"ai_disabled": "已禁用 AI 功能",
"no_models_found_online": "找不到模型。請檢查您的 API 金鑰及設定。",
"no_models_found_ollama": "找不到 Ollama 模型。請確認 Ollama 是否正在執行。",
"error_fetching": "獲取模型失敗:{{error}}"
},
"code-editor-options": {
"title": "編輯器"
},
@@ -2154,7 +2013,9 @@
"app-restart-required": "(需要重啟程式以套用更改)"
},
"pagination": {
"total_notes": "{{count}} 筆記"
"total_notes": "{{count}} 筆記",
"prev_page": "上一頁",
"next_page": "下一頁"
},
"collections": {
"rendering_error": "發現錯誤,無法顯示內容。"

View File

@@ -55,7 +55,10 @@
"show_help": "Показати Довідку",
"logout": "Вийти",
"show-cheatsheet": "Показати Шпаргалку",
"toggle-zen-mode": "Дзен-режим"
"toggle-zen-mode": "Дзен-режим",
"new-version-available": "Доступне оновлення",
"download-update": "Отримати версію {{latest Version}}",
"search_notes": "Пошук нотаток"
},
"modal": {
"help_title": "Показати більше інформації про це вікно",
@@ -293,7 +296,8 @@
},
"import-status": "Статус Імпорту",
"in-progress": "Триває Імпорт: {{progress}}",
"successful": "Імпорт успішно завершено."
"successful": "Імпорт успішно завершено.",
"importZipRecommendation": "Під час імпорту ZIP-файлу ієрархія нотаток відображатиме структуру підкаталогів в архіві."
},
"prompt": {
"title": "Запит(prompt)",
@@ -355,7 +359,8 @@
"info": {
"modalTitle": "Інформаційне повідомлення",
"closeButton": "Закрити",
"okButton": "ОК"
"okButton": "ОК",
"copy_to_clipboard": "Копіювати в буфер обміну"
},
"jump_to_note": {
"search_placeholder": "Пошук нотатки за її назвою або типом > для команд...",
@@ -805,7 +810,14 @@
"convert_into_attachment_failed": "Не вдалося конвертувати нотатку '{{title}}'.",
"convert_into_attachment_successful": "Нотатку '{{title}}' перетворено на вкладення.",
"convert_into_attachment_prompt": "Ви впевнені, що хочете перетворити нотатку '{{title}}' на вкладення батьківської нотатки?",
"print_pdf": "Експортувати як PDF..."
"print_pdf": "Експортувати як PDF...",
"open_note_on_server": "Відкрити нотатку на сервері",
"view_revisions": "Ревізії нотатки...",
"advanced": "Розширені",
"export_as_image": "Експортувати як зображення",
"export_as_image_png": "PNG (растровий)",
"export_as_image_svg": "SVG (векторний)",
"note_map": "Карта нотатки"
},
"onclick_button": {
"no_click_handler": "Віджет кнопки '{{componentId}}' не має визначеного обробника кліків"
@@ -858,7 +870,10 @@
"insert_child_note": "Вставити дочірню нотатку",
"delete_this_note": "Видалити цю нотатку",
"error_cannot_get_branch_id": "Не вдається отримати branchId для notePath '{{notePath}}'",
"error_unrecognized_command": "Нерозпізнана команда {{command}}"
"error_unrecognized_command": "Нерозпізнана команда {{command}}",
"note_revisions": "Ревізії нотатки",
"backlinks": "Зворотні посилання",
"content_language_switcher": "Мова контенту: {{language}}"
},
"note_icon": {
"change_note_icon": "Змінити значок нотатки",
@@ -866,7 +881,13 @@
"reset-default": "Скинути значок до стандартного значення",
"search_placeholder_one": "Пошук {{number}} значка у {{count}} пакеті",
"search_placeholder_few": "Пошук {{number}} значків у {{count}} пакетах",
"search_placeholder_many": "Пошук {{number}} значків у {{count}} пакетах"
"search_placeholder_many": "Пошук {{number}} значків у {{count}} пакетах",
"search_placeholder_filtered": "Пошук {{number}} іконок у {{name}}",
"filter": "Фільтр",
"filter-none": "Всі іконки",
"filter-default": "Іконки за замовчуванням",
"icon_tooltip": "{{name}}\nПакет іконок: {{iconPack}}",
"no_results": "Іконки не знайдено"
},
"basic_properties": {
"note_type": "Тип нотатки",
@@ -888,7 +909,13 @@
"table": "Таблиця",
"geo-map": "Географічна карта",
"board": "Дошка",
"include_archived_notes": "Показати архівовані нотатки"
"include_archived_notes": "Показати архівовані нотатки",
"expand_tooltip": "Розгортає безпосередні дочірні елементи цієї колекції (на один рівень у глибину). Щоб переглянути більше параметрів, натисніть стрілку праворуч.",
"expand_first_level": "Розгорнути прямі дочірні елементи",
"expand_nth_level": "Розгорнути {{depth}} рівнів",
"expand_all_levels": "Розгорнути всі рівні",
"presentation": "Презентація",
"hide_child_notes": "Приховати дочірні нотатки в дереві"
},
"edited_notes": {
"no_edited_notes_found": "Цього дня ще немає редагованих нотаток...",
@@ -921,7 +948,8 @@
},
"inherited_attribute_list": {
"title": "Успадковані Атрибути",
"no_inherited_attributes": "Немає успадкованих атрибутів."
"no_inherited_attributes": "Немає успадкованих атрибутів.",
"none": "пусто"
},
"note_info_widget": {
"note_id": "ID Нотатки",
@@ -932,7 +960,9 @@
"note_size_info": "Розмір нотатки надає приблизну оцінку вимог до зберігання для цієї нотатки. Він враховує вміст нотатки та вміст її версій.",
"calculate": "обчислити",
"subtree_size": "(розмір піддерева: {{size}} у {{count}} нотатках)",
"title": "Інформація про нотатку"
"title": "Інформація про нотатку",
"mime": "Тип MIME",
"show_similar_notes": "Показати схожі нотатки"
},
"note_map": {
"open_full": "Розгорнути на повний розмір",
@@ -995,7 +1025,9 @@
"search_parameters": "Параметри пошуку",
"unknown_search_option": "Невідомий параметр пошуку {{searchOptionName}}",
"actions_executed": "Дії виконано.",
"search_note_saved": "Нотатка з пошуку збережена у {{- notePathTitle}}"
"search_note_saved": "Нотатка з пошуку збережена у {{- notePathTitle}}",
"option": "опції",
"view_options": "Опції перегляду:"
},
"similar_notes": {
"title": "Схожі нотатки",
@@ -1089,7 +1121,13 @@
},
"editable_text": {
"placeholder": "Введіть тут вміст вашої нотатки...",
"auto-detect-language": "Автовизначено"
"auto-detect-language": "Автовизначено",
"editor_crashed_title": "Збій текстового редактора",
"editor_crashed_content": "Ваш контент успішно відновлено, але деякі з ваших останніх змін могли бути не збережені.",
"editor_crashed_details_button": "Переглянути більше деталей...",
"editor_crashed_details_intro": "Якщо ви стикаєтеся з цією помилкою кілька разів, подумайте про те, щоб повідомити про неї на GitHub, вставивши наведену нижче інформацію.",
"editor_crashed_details_title": "Технічна інформація",
"keeps-crashing": "Компонент редагування постійно аварійно завершує роботу. Спробуйте перезапустити Trilium. Якщо проблема не зникає, спробуйте створити звіт про помилку."
},
"empty": {
"open_note_instruction": "Відкрийте нотатку, ввівши її заголовок в поле нижче, або виберіть нотатку в дереві.",
@@ -1236,149 +1274,6 @@
"layout-vertical-description": "Панель запуску знаходиться ліворуч (за замовчуванням)",
"layout-horizontal-description": "Панель запуску знаходиться під панеллю вкладок, панель вкладок тепер має повну ширину."
},
"ai_llm": {
"not_started": "Не розпочато",
"title": "Параметри AI",
"processed_notes": "Оброблені нотатки",
"total_notes": "Всього нотаток",
"progress": "Прогрес",
"queued_notes": "Черга нотаток",
"failed_notes": "Невдалі нотатки",
"last_processed": "Остання обробка",
"refresh_stats": "Оновити статистику",
"enable_ai_features": "Увімкнути функції AI/LLM",
"enable_ai_description": "Увімкніть функції AI, такі як підсумовування нотаток, генерація контенту та інші можливості LLM",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Увімкнути функції AI/LLM",
"enable_ai_desc": "Увімкнути функції AI, такі як підсумовування нотаток, генерація контенту та інші можливості LLM",
"provider_configuration": "Конфігурація постачальника AI",
"provider_precedence": "Пріоритет постачальника",
"provider_precedence_description": "Список постачальників, розділених комами, у порядку пріоритету (наприклад, «openai,anthropic,ollama»)",
"temperature": "Температура",
"temperature_description": "Контролює випадковість відповідей (0 = детермінований, 2 = максимальна випадковість)",
"system_prompt": "Системний Запит (Prompt)",
"system_prompt_description": "Системний запит (prompt) за замовчуванням використовується для всіх взаємодій з AI",
"openai_configuration": "Конфігурація OpenAI",
"openai_settings": "Налаштування OpenAI",
"api_key": "API Key",
"url": "Base URL",
"model": "Модель",
"openai_api_key_description": "Ваш ключ OpenAI API для доступу до служб AI",
"anthropic_api_key_description": "Ваш ключ Anthropic API для доступу до моделей Claude",
"default_model": "Модель за замовчуванням",
"openai_model_description": "Наприклад: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "Base URL",
"openai_url_description": "За замовчуванням: https://api.openai.com/v1",
"anthropic_settings": "Налаштування Anthropic",
"anthropic_url_description": "Базова URL-адреса для Anthropic API (за замовчуванням: https://api.anthropic.com)",
"anthropic_model_description": "Моделі Anthropic Claude для чату",
"voyage_settings": "Налаштування Voyage AI",
"ollama_settings": "Налаштування Ollama",
"ollama_url_description": "URL для Ollama API (default: http://localhost:11434)",
"ollama_model_description": "Модель Ollama для чату",
"anthropic_configuration": "Конфігурація Anthropic",
"voyage_configuration": "Конфігурація Voyage AI",
"voyage_url_description": "За замовчуванням: https://api.voyageai.com/v1",
"ollama_configuration": "Конфігурація Ollama",
"enable_ollama": "Увімкнути Ollama",
"enable_ollama_description": "Увімкнути Ollama для локальної моделі AI",
"ollama_url": "Ollama URL",
"ollama_model": "Модель Ollama",
"refresh_models": "Оновити моделі",
"refreshing_models": "Оновлення...",
"enable_automatic_indexing": "Увімкнути автоматичне індексування",
"rebuild_index": "Перебудувати індекс",
"rebuild_index_error": "Помилка початку перебудови індексу. Перегляньте logs для інформації.",
"note_title": "Заголовок нотатки",
"error": "Помилка",
"last_attempt": "Остання спроба",
"actions": "Дії",
"retry": "Повторити спробу",
"partial": "{{ percentage }}% completed",
"retry_queued": "Нотатка в черзі на повторну спробу",
"retry_failed": "Не вдалося додати нотатку до черги для повторної спроби",
"max_notes_per_llm_query": "Максимальна кількість нотаток на запит",
"max_notes_per_llm_query_description": "Максимальна кількість схожих нотаток для включення в контекст AI",
"active_providers": "Активні постачальники",
"disabled_providers": "Вимкнути постачальників",
"remove_provider": "Видалити постачальника з пошуку",
"restore_provider": "Відновити постачальника для пошуку",
"similarity_threshold": "Поріг схожості",
"similarity_threshold_description": "Мінімальна оцінка схожості (0-1) для нотаток, що включатимуться в контекст для запитів LLM",
"reprocess_index": "Перебудувати індекс пошуку",
"reprocessing_index": "Відбудова...",
"reprocess_index_started": "Оптимізація пошукового індексу розпочата у фоновому режимі",
"reprocess_index_error": "Помилка відбудови індексу пошуку",
"index_rebuild_progress": "Прогрес відбудови індексу",
"index_rebuilding": "Індекс оптимізації ({{percentage}}%)",
"index_rebuild_complete": "Оптимізацію індексу завершено",
"index_rebuild_status_error": "Помилка перевірки стану перебудови індексу",
"never": "Ніколи",
"processing": "Обробка ({{percentage}}%)",
"incomplete": "Незавершено ({{percentage}}%)",
"complete": "Завершено (100%)",
"refreshing": "Оновлення...",
"auto_refresh_notice": "Автоматичне оновлення кожні {{seconds}} секунд",
"note_queued_for_retry": "Нотатка в черзі на повторну спробу",
"failed_to_retry_note": "Не вдалося повторити спробу",
"all_notes_queued_for_retry": "Усі невдалі нотатки поставлені в чергу на повторну спробу",
"failed_to_retry_all": "Не вдалося повторити спробу",
"ai_settings": "Налаштування AI",
"api_key_tooltip": "Ключ API для доступу до сервісу",
"empty_key_warning": {
"anthropic": "Ключ API Anthropic порожній. Будь ласка, введіть дійсний ключ API.",
"openai": "Ключ API OpenAI порожній. Будь ласка, введіть дійсний ключ API.",
"voyage": "Ключ Voyage API подорожі порожній. Будь ласка, введіть дійсний ключ API.",
"ollama": "Ключ API Ollama порожній. Будь ласка, введіть дійсний ключ API."
},
"agent": {
"processing": "Обробка...",
"thinking": "Думаю...",
"loading": "Завантаження...",
"generating": "Генерування..."
},
"name": "AI",
"openai": "OpenAI",
"use_enhanced_context": "Використовувати покращений контекст",
"enhanced_context_description": "Надає AI більше контексту з нотатки та пов'язаних з нею нотаток для кращих відповідей",
"show_thinking": "Показати міркування",
"show_thinking_description": "Показати ланцюжок міркувань AI",
"enter_message": "Введіть ваше повідомлення...",
"error_contacting_provider": "Помилка зв’язку з постачальником AI. Перевірте налаштування та підключення до Інтернету.",
"error_generating_response": "Помилка створення відповіді AI",
"index_all_notes": "Індексація усіх нотаток",
"index_status": "Статус індексації",
"indexed_notes": "Індексовані нотатки",
"indexing_stopped": "Індексацію зупинено",
"indexing_in_progress": "Триває індексація...",
"last_indexed": "Остання індексація",
"note_chat": "Нотатка Чат",
"sources": "Джерела",
"start_indexing": "Почати індексацію",
"use_advanced_context": "Використовувати розширений контекст",
"ollama_no_url": "Ollama не налаштовано. Будь ласка, введіть дійсну URL-адресу.",
"chat": {
"root_note_title": "AI Чати",
"root_note_content": "Ця нотатка містить ваші збережені розмови в чаті з AI.",
"new_chat_title": "Новий Чат",
"create_new_ai_chat": "Створити новий AI Чат"
},
"create_new_ai_chat": "Створити новий AI Чат",
"configuration_warnings": "Виникли деякі проблеми з конфігурацією AI. Перевірте налаштування.",
"experimental_warning": "Функція LLM наразі є експериментальною вас попередили.",
"selected_provider": "Вибраний постачальник",
"selected_provider_description": "Вибрати постачальника послуг AI для функцій чату та автозаповнення",
"select_model": "Виберіть модель...",
"select_provider": "Виберіть постачальника...",
"ai_enabled": "Функції AI увімкнено",
"ai_disabled": "Функції AI вимкнено",
"no_models_found_online": "Моделей не знайдено. Будь ласка, перевірте свій ключ API та налаштування.",
"no_models_found_ollama": "Моделей Ollama не знайдено. Перевірте, чи працює Ollama.",
"error_fetching": "Помилка отримання моделей: {{error}}"
},
"backup": {
"automatic_backup": "Автоматичне резервне копіювання",
"automatic_backup_description": "Trilium може автоматично створювати резервні копії бази даних:",
@@ -1676,6 +1571,7 @@
"add-term-to-dictionary": "Додати \"{{term}}\" до словника",
"cut": "Вирізати",
"copy": "Копіювати",
"copy-as-markdown": "Копіювати як Markdown",
"copy-link": "Копіювати посилання",
"paste": "Вставити",
"paste-as-plain-text": "Вставити як звичайний текст",
@@ -1957,7 +1853,6 @@
"confirm-change": "Не рекомендується змінювати тип нотатки, якщо її вміст не порожній. Ви все одно хочете продовжити?",
"geo-map": "Географічна карта",
"beta-feature": "Бета",
"ai-chat": "Чат AI",
"task-list": "Список завдань",
"new-feature": "Нова",
"collections": "Колекції",
@@ -2098,5 +1993,11 @@
"pages_one": "{{count}} сторінка",
"pages_few": "{{count}} сторінки",
"pages_many": "{{count}} сторінок"
},
"render": {
"setup_title": "Відображати власний HTML або Preact JSX у цій нотатці",
"setup_create_sample_preact": "Створіть зразок нотатки за допомогою Preact",
"setup_create_sample_html": "Створити зразок нотатки за допомогою HTML",
"setup_sample_created": "Зразок нотатки було створено як дочірню нотатку."
}
}

View File

@@ -1,7 +1,6 @@
import "./NoteDetail.css";
import clsx from "clsx";
import { note } from "mermaid/dist/rendering-util/rendering-elements/shapes/note.js";
import { isValidElement, VNode } from "preact";
import { useEffect, useRef, useState } from "preact/hooks";

View File

@@ -1,22 +1,16 @@
import FlexContainer from "./containers/flex_container.js";
import utils from "../services/utils.js";
import attributeService from "../services/attributes.js";
import type BasicWidget from "./basic_widget.js";
import type { EventData } from "../components/app_context.js";
import type NoteContext from "../components/note_context.js";
import type FNote from "../entities/fnote.js";
import attributeService from "../services/attributes.js";
import { getLocaleById } from "../services/i18n.js";
import utils from "../services/utils.js";
import type BasicWidget from "./basic_widget.js";
import FlexContainer from "./containers/flex_container.js";
export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
private noteContext?: NoteContext;
constructor() {
super("column");
this.css("flex-grow", "1").collapsible();
}
setNoteContextEvent({ noteContext }: EventData<"setNoteContext">) {
this.noteContext = noteContext;
@@ -43,12 +37,15 @@ export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
refresh() {
const isHiddenExt = this.isHiddenExt(); // preserve through class reset
const isActive = this.$widget.hasClass("active");
this.$widget.removeClass();
this.toggleExt(!isHiddenExt);
this.$widget.addClass("component note-split");
if (isActive) {
this.$widget.addClass("active");
}
const note = this.noteContext?.note;
if (!note) {
@@ -74,7 +71,7 @@ export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
}
#isFullWidthNote(note: FNote) {
if (["code", "image", "mermaid", "book", "render", "canvas", "webView", "mindMap"].includes(note.type)) {
if (["code", "image", "mermaid", "book", "render", "canvas", "webView", "mindMap", "spreadsheet"].includes(note.type)) {
return true;
}
@@ -92,7 +89,12 @@ export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
#hasBackgroundEffects(note: FNote): boolean {
const MIME_TYPES_WITH_BACKGROUND_EFFECTS = [
"application/pdf"
]
];
const COLLECTIONS_WITH_BACKGROUND_EFFECTS = [
"grid",
"list"
];
if (note.isOptions()) {
return true;
@@ -102,6 +104,10 @@ export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
return true;
}
if (note.type === "book" && COLLECTIONS_WITH_BACKGROUND_EFFECTS.includes(note.getLabelValue("viewType") ?? "none")) {
return true;
}
return false;
}

View File

@@ -0,0 +1,16 @@
.component.note-split {
display: flex;
flex-grow: 1;
flex-direction: column;
contain: none;
> .title-row {
display: flex;
flex-direction: row;
contain: none;
}
}
body.desktop .component.note-split > .title-row > * {
margin: 5px;
}

View File

@@ -0,0 +1,96 @@
import "./NoteWrapper.css";
import { isExperimentalFeatureEnabled } from "../services/experimental_features";
import { isDesktop } from "../services/utils";
import ApiLog from "./api_log";
import ClosePaneButton from "./buttons/close_pane_button";
import CreatePaneButton from "./buttons/create_pane_button";
import MovePaneButton from "./buttons/move_pane_button";
import NoteList from "./collections/NoteList";
import ScrollingContainer from "./containers/ScrollingContainer";
import FindWidget from "./find";
import FloatingButtons from "./FloatingButtons";
import { DESKTOP_FLOATING_BUTTONS } from "./FloatingButtonsDefinitions";
import { LegacyWidgetRenderer } from "./launch_bar/LauncherDefinitions";
import SpacerWidget from "./launch_bar/SpacerWidget";
import InlineTitle from "./layout/InlineTitle";
import NoteBadges from "./layout/NoteBadges";
import NoteTitleActions from "./layout/NoteTitleActions";
import MobileDetailMenu from "./mobile_widgets/mobile_detail_menu";
import ToggleSidebarButton from "./mobile_widgets/toggle_sidebar_button";
import NoteIcon from "./note_icon";
import NoteTitleWidget from "./note_title";
import NoteDetail from "./NoteDetail";
import PromotedAttributes from "./PromotedAttributes";
import ReadOnlyNoteInfoBar from "./ReadOnlyNoteInfoBar";
import NoteActions from "./ribbon/NoteActions";
import Ribbon from "./ribbon/Ribbon";
import ScrollPadding from "./scroll_padding";
import SearchResult from "./search_result";
import SharedInfo from "./shared_info";
import MobileEditorToolbar from "./type_widgets/text/mobile_editor_toolbar";
import WatchedFileUpdateStatusWidget from "./watched_file_update_status";
const isNewLayout = isExperimentalFeatureEnabled("new-layout");
const cachedIsDesktop = isDesktop();
const cachedIsMobile = !cachedIsDesktop;
export default function NoteWrapper() {
return (
<div className="component note-split">
<TitleRow />
{!isNewLayout && <Ribbon />}
{cachedIsDesktop && <LegacyWidgetRenderer widget={new WatchedFileUpdateStatusWidget()} />}
{!isNewLayout && <FloatingButtons items={DESKTOP_FLOATING_BUTTONS} />}
<ScrollingContainer>
{isNewLayout ? (
<>
<InlineTitle />
<NoteTitleActions />
</>
) : (
<>
<ReadOnlyNoteInfoBar />
<SharedInfo />
</>
)}
{!isNewLayout && <PromotedAttributes />}
<NoteDetail />
<NoteList media="screen" />
<SearchResult />
<ScrollPadding />
</ScrollingContainer>
<ApiLog />
{cachedIsMobile && <MobileEditorToolbar />}
<LegacyWidgetRenderer widget={new FindWidget()} />
</div>
);
}
function TitleRow() {
return (
<div className="component title-row note-split-title">
{cachedIsMobile && <ToggleSidebarButton />}
<NoteIcon />
<NoteTitleWidget />
{isNewLayout && <NoteBadges />}
{cachedIsDesktop ? (
<>
<SpacerWidget baseSize={0} growthFactor={1} />
{!isNewLayout ? (
<>
<MovePaneButton direction="left" />
<MovePaneButton direction="right" />
<ClosePaneButton />
<CreatePaneButton />
</>
) : (
<NoteActions />
)}
</>
) : (
<MobileDetailMenu />
)}
</div>
);
}

View File

@@ -3,14 +3,13 @@ import "./PromotedAttributes.css";
import { UpdateAttributeResponse } from "@triliumnext/commons";
import clsx from "clsx";
import { ComponentChild, HTMLInputTypeAttribute, InputHTMLAttributes, MouseEventHandler, TargetedEvent, TargetedInputEvent } from "preact";
import { Dispatch, StateUpdater, useEffect, useRef, useState } from "preact/hooks";
import { Dispatch, StateUpdater, useCallback, useEffect, useRef, useState } from "preact/hooks";
import NoteContext from "../components/note_context";
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 { DefinitionObject, extractAttributeDefinitionTypeAndName, LabelType } from "../services/promoted_attribute_definition_parser";
import server from "../services/server";
@@ -38,7 +37,7 @@ interface CellProps {
}
type OnChangeEventData = TargetedEvent<HTMLInputElement, Event> | InputEvent | JQuery.TriggeredEvent<HTMLInputElement, undefined, HTMLInputElement, HTMLInputElement>;
type OnChangeListener = (e: OnChangeEventData) => Promise<void>;
type OnChangeListener = (e: OnChangeEventData) => void | Promise<void>;
export default function PromotedAttributes() {
const { note, componentId, noteContext } = useNoteContext();
@@ -110,7 +109,7 @@ export function usePromotedAttributeData(note: FNote | null | undefined, compone
valueAttrs = valueAttrs.slice(0, 1);
}
for (const [ i, valueAttr ] of valueAttrs.entries()) {
for (const valueAttr of valueAttrs) {
const definition = definitionAttr.getDefinition();
// if not owned, we'll force creation of a new attribute instead of updating the inherited one
@@ -183,19 +182,34 @@ const LABEL_MAPPINGS: Record<LabelType, HTMLInputTypeAttribute> = {
url: "url"
};
function LabelInput({ inputId, ...props }: CellProps & { inputId: string }) {
const { valueName, valueAttr, definition, definitionAttr } = props.cell;
const onChangeListener = buildPromotedAttributeLabelChangedListener({...props});
function LabelInput(props: CellProps & { inputId: string }) {
const { inputId, note, cell, componentId, setCells } = props;
const { valueName, valueAttr, definition, definitionAttr } = cell;
const [ valueDraft, setDraft ] = useState(valueAttr.value);
const onChangeListener = useCallback(async (e: OnChangeEventData) => {
const inputEl = e.target as HTMLInputElement;
let value: string;
if (inputEl.type === "checkbox") {
value = inputEl.checked ? "true" : "false";
} else {
value = inputEl.value;
}
await updateAttribute(note, cell, componentId, value, setCells);
}, [ cell, componentId, note, setCells ]);
const extraInputProps: InputHTMLAttributes = {};
useEffect(() => {
if (definition.labelType === "text") {
const el = document.getElementById(inputId);
if (el) {
setupTextLabelAutocomplete(el as HTMLInputElement, valueAttr, onChangeListener);
}
useTextLabelAutocomplete(inputId, valueAttr, definition, (e) => {
if (e.currentTarget instanceof HTMLInputElement) {
setDraft(e.currentTarget.value);
}
}, [ inputId, valueAttr, onChangeListener ]);
});
// React to model changes.
useEffect(() => {
setDraft(valueAttr.value);
}, [ valueAttr.value ]);
switch (definition.labelType) {
case "number": {
@@ -217,13 +231,13 @@ function LabelInput({ inputId, ...props }: CellProps & { inputId: string }) {
tabIndex={200 + definitionAttr.position}
id={inputId}
type={LABEL_MAPPINGS[definition.labelType ?? "text"]}
value={valueAttr.value}
value={valueDraft}
checked={definition.labelType === "boolean" ? valueAttr.value === "true" : undefined}
placeholder={t("promoted_attributes.unset-field-placeholder")}
data-attribute-id={valueAttr.attributeId}
data-attribute-type={valueAttr.type}
data-attribute-name={valueAttr.name}
onChange={onChangeListener}
onBlur={onChangeListener}
{...extraInputProps}
/>;
@@ -399,16 +413,27 @@ function InputButton({ icon, className, title, onClick }: {
);
}
function setupTextLabelAutocomplete(el: HTMLInputElement, valueAttr: Attribute, onChangeListener: OnChangeListener) {
// no need to await for this, can be done asynchronously
const $input = $(el);
server.get<string[]>(`attribute-values/${encodeURIComponent(valueAttr.name)}`).then((_attributeValues) => {
if (_attributeValues.length === 0) {
function useTextLabelAutocomplete(inputId: string, valueAttr: Attribute, definition: DefinitionObject, onChangeListener: OnChangeListener) {
const [ attributeValues, setAttributeValues ] = useState<{ value: string }[] | null>(null);
// Obtain data.
useEffect(() => {
if (definition.labelType !== "text") {
return;
}
const attributeValues = _attributeValues.map((attribute) => ({ value: attribute }));
server.get<string[]>(`attribute-values/${encodeURIComponent(valueAttr.name)}`).then((_attributesValues) => {
setAttributeValues(_attributesValues.map((attribute) => ({ value: attribute })));
});
}, [ definition.labelType, valueAttr.name ]);
// Initialize autocomplete.
useEffect(() => {
if (attributeValues?.length === 0) return;
const el = document.getElementById(inputId) as HTMLInputElement | null;
if (!el) return;
const $input = $(el);
$input.autocomplete(
{
appendTo: document.querySelector("body"),
@@ -424,7 +449,7 @@ function setupTextLabelAutocomplete(el: HTMLInputElement, valueAttr: Attribute,
source (term, cb) {
term = term.toLowerCase();
const filtered = attributeValues.filter((attr) => attr.value.toLowerCase().includes(term));
const filtered = (attributeValues ?? []).filter((attr) => attr.value.toLowerCase().includes(term));
cb(filtered);
}
@@ -434,27 +459,13 @@ function setupTextLabelAutocomplete(el: HTMLInputElement, valueAttr: Attribute,
$input.off("autocomplete:selected");
$input.on("autocomplete:selected", onChangeListener);
});
}
function buildPromotedAttributeLabelChangedListener({ note, cell, componentId, setCells }: CellProps): OnChangeListener {
async function onChange(e: OnChangeEventData) {
const inputEl = e.target as HTMLInputElement;
let value: string;
if (inputEl.type === "checkbox") {
value = inputEl.checked ? "true" : "false";
} else {
value = inputEl.value;
}
await updateAttribute(note, cell, componentId, value, setCells);
}
return debounce(onChange, 250);
return () => $input.autocomplete("destroy");
}, [ inputId, attributeValues, onChangeListener ]);
}
async function updateAttribute(note: FNote, cell: Cell, componentId: string, value: string | undefined, setCells: Dispatch<StateUpdater<Cell[] | undefined>>) {
if (value === cell.valueAttr.value) return;
const { attributeId } = await server.put<UpdateAttributeResponse>(
`notes/${note.noteId}/attribute`,
{

View File

@@ -5,7 +5,7 @@
align-items: center;
position: absolute;
width: 100%;
top: 20px;
top: calc(env(safe-area-inset-top) + 20px);
pointer-events: none;
contain: none;
}

View File

@@ -4,6 +4,7 @@
overflow: visible;
contain: none !important;
clear: both;
&.full-height {
overflow: auto;

View File

@@ -9,7 +9,8 @@ import Button from "../react/Button";
import "./Pagination.css";
import clsx from "clsx";
interface PaginationContext {
export interface PaginationContext {
className?: string;
page: number;
setPage: Dispatch<StateUpdater<number>>;
pageNotes?: FNote[];
@@ -18,11 +19,11 @@ interface PaginationContext {
totalNotes: number;
}
export function Pager({ page, pageSize, setPage, pageCount, totalNotes }: Omit<PaginationContext, "pageNotes">) {
export function Pager({ className, page, pageSize, setPage, pageCount, totalNotes }: Omit<PaginationContext, "pageNotes">) {
if (pageCount < 2) return;
return (
<div className="note-list-pager-container">
<div className={clsx("note-list-pager-container", className)}>
<div className="note-list-pager">
<ActionButton
icon="bx bx-chevron-left"

View File

@@ -14,7 +14,7 @@
height: 100%;
display: flex;
gap: 1em;
padding-inline: 12px;
margin-inline: var(--content-margin-inline);
padding-block: 4px;
align-items: flex-start;
overflow-x: auto;

View File

@@ -1,4 +1,4 @@
import { describe, expect, it } from "vitest";
import { describe, expect, it, vi } from "vitest";
import { buildNote, buildNotes } from "../../../test/easy-froca.js";
import { buildEvent, buildEvents } from "./event_builder.js";
import { LOCALE_MAPPINGS } from "./index.js";
@@ -148,7 +148,7 @@ describe("Promoted attributes", () => {
expect(event).toHaveLength(1);
expect(event[0]?.promotedAttributes).toMatchObject([
[ "assignee", "Target note" ]
])
]);
});
it("supports start time and end time", async () => {
@@ -177,6 +177,86 @@ describe("Promoted attributes", () => {
});
describe("Recurrence", () => {
it("supports valid recurrence without end date", async () => {
const noteIds = buildNotes([
{
title: "Recurring Event",
"#startDate": "2025-05-05",
"#recurrence": "FREQ=DAILY;COUNT=5"
}
]);
const events = await buildEvents(noteIds);
expect(events).toHaveLength(1);
expect(events[0]).toMatchObject({
title: "Recurring Event",
start: "2025-05-05",
});
expect(events[0].rrule).toContain("DTSTART:20250505");
expect(events[0].rrule).toContain("FREQ=DAILY;COUNT=5");
expect(events[0].end).toBeUndefined();
});
it("supports recurrence with start and end time (duration calculated)", async () => {
const noteIds = buildNotes([
{
title: "Timed Recurring Event",
"#startDate": "2025-05-05",
"#startTime": "13:00",
"#endTime": "15:30",
"#recurrence": "FREQ=WEEKLY;COUNT=3"
}
]);
const events = await buildEvents(noteIds);
expect(events).toHaveLength(1);
expect(events[0]).toMatchObject({
title: "Timed Recurring Event",
start: "2025-05-05T13:00:00",
duration: "02:30"
});
expect(events[0].rrule).toContain("DTSTART:20250505T130000");
expect(events[0].end).toBeUndefined();
});
it("removes end date when recurrence is valid", async () => {
const noteIds = buildNotes([
{
title: "Recurring With End",
"#startDate": "2025-05-05",
"#endDate": "2025-05-07",
"#recurrence": "FREQ=DAILY;COUNT=2"
}
]);
const events = await buildEvents(noteIds);
expect(events).toHaveLength(1);
expect(events[0].rrule).toBeDefined();
expect(events[0].end).toBeUndefined();
});
it("writes to console on invalid recurrence rule", async () => {
const noteIds = buildNotes([
{
title: "Invalid Recurrence",
"#startDate": "2025-05-05",
"#recurrence": "RRULE:FREQ=INVALID"
}
]);
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
await buildEvents(noteIds);
const calledWithInvalid = consoleSpy.mock.calls.some(call =>
call[0].includes("has an invalid #recurrence string")
);
expect(calledWithInvalid).toBe(true);
consoleSpy.mockRestore();
});
});
describe("Building locales", () => {
it("every language has a locale defined", async () => {
for (const { id, contentOnly } of LOCALES) {

View File

@@ -1,17 +1,22 @@
import { EventInput, EventSourceFuncArg, EventSourceInput } from "@fullcalendar/core/index.js";
import { dayjs } from "@triliumnext/commons";
import clsx from "clsx";
import { start } from "repl";
import * as rruleLib from 'rrule';
import FNote from "../../../entities/fnote";
import froca from "../../../services/froca";
import server from "../../../services/server";
import { formatDateToLocalISO, getCustomisableLabel, getMonthsInDateRange, offsetDate } from "./utils";
import toastService from "../../../services/toast";
import { getCustomisableLabel, getMonthsInDateRange } from "./utils";
interface Event {
startDate: string,
endDate?: string | null,
startTime?: string | null,
endTime?: string | null,
isArchived?: boolean;
isArchived?: boolean,
recurrence?: string | null;
}
export async function buildEvents(noteIds: string[]) {
@@ -28,8 +33,17 @@ export async function buildEvents(noteIds: string[]) {
const endDate = getCustomisableLabel(note, "endDate", "calendar:endDate");
const startTime = getCustomisableLabel(note, "startTime", "calendar:startTime");
const endTime = getCustomisableLabel(note, "endTime", "calendar:endTime");
const recurrence = getCustomisableLabel(note, "recurrence", "calendar:recurrence");
const isArchived = note.hasLabel("archived");
events.push(await buildEvent(note, { startDate, endDate, startTime, endTime, isArchived }));
try {
events.push(await buildEvent(note, { startDate, endDate, startTime, endTime, recurrence, isArchived }));
} catch (error) {
if (error instanceof Error) {
const errorMessage = error.message;
toastService.showError(errorMessage);
console.error(errorMessage);
}
}
}
return events.flat();
@@ -59,6 +73,7 @@ export async function buildEventsForCalendar(note: FNote, e: EventSourceFuncArg)
events.push(await buildEvent(dateNote, { startDate }));
if (dateNote.hasChildren()) {
const childNoteIds = await dateNote.getSubtreeNoteIds();
for (const childNoteId of childNoteIds) {
@@ -79,7 +94,7 @@ export async function buildEventsForCalendar(note: FNote, e: EventSourceFuncArg)
return events.flat();
}
export async function buildEvent(note: FNote, { startDate, endDate, startTime, endTime, isArchived }: Event) {
export async function buildEvent(note: FNote, { startDate, endDate, startTime, endTime, recurrence, isArchived }: Event) {
const customTitleAttributeName = note.getLabelValue("calendar:title");
const titles = await parseCustomTitle(customTitleAttributeName, note);
const colorClass = note.getColorClass();
@@ -98,9 +113,10 @@ export async function buildEvent(note: FNote, { startDate, endDate, startTime, e
startDate = (startTime ? `${startDate}T${startTime}:00` : startDate);
if (!startTime) {
const endDateOffset = offsetDate(endDate ?? startDate, 1);
if (endDateOffset) {
endDate = formatDateToLocalISO(endDateOffset);
if (endDate) {
endDate = dayjs(endDate).add(1, "day").format("YYYY-MM-DD");
} else if (startDate) {
endDate = dayjs(startDate).add(1, "day").format("YYYY-MM-DD");
}
}
@@ -118,6 +134,30 @@ export async function buildEvent(note: FNote, { startDate, endDate, startTime, e
if (endDate) {
eventData.end = endDate;
}
if (recurrence) {
// Generate rrule string
const rruleString = `DTSTART:${dayjs(startDate).format("YYYYMMDD[T]HHmmss")}\n${recurrence}`;
// Validate rrule string
let rruleValid = true;
try {
rruleLib.rrulestr(rruleString, { forceset: true }) as rruleLib.RRuleSet;
} catch {
rruleValid = false;
}
if (rruleValid) {
delete eventData.end;
eventData.rrule = rruleString;
if (endDate){
const duration = dayjs.duration(dayjs(endDate).diff(dayjs(startDate)));
eventData.duration = duration.format("HH:mm");
}
} else {
throw new Error(`Note "${note.noteId} ${note.title}" has an invalid #recurrence string ${recurrence}. Excluding...`);
}
}
events.push(eventData);
}
return events;

View File

@@ -52,7 +52,7 @@
--fc-border-color: var(--main-border-color);
--fc-neutral-bg-color: var(--launcher-pane-background-color);
--fc-list-event-hover-bg-color: var(--left-pane-item-hover-background);
padding: 0 12px;
padding: 0 var(--content-margin-inline);
}
.calendar-container .fc-list-sticky .fc-list-day > * {

View File

@@ -79,6 +79,7 @@ export const LOCALE_MAPPINGS: Record<DISPLAYABLE_LOCALE_IDS, (() => Promise<{ de
es: () => import("@fullcalendar/core/locales/es"),
fr: () => import("@fullcalendar/core/locales/fr"),
it: () => import("@fullcalendar/core/locales/it"),
hi: () => import("@fullcalendar/core/locales/hi"),
ga: null,
cn: () => import("@fullcalendar/core/locales/zh-cn"),
tw: () => import("@fullcalendar/core/locales/zh-tw"),
@@ -251,6 +252,7 @@ function usePlugins(isEditable: boolean, isCalendarRoot: boolean) {
plugins.push((await import("@fullcalendar/timegrid")).default);
plugins.push((await import("@fullcalendar/list")).default);
plugins.push((await import("@fullcalendar/multimonth")).default);
plugins.push((await import("@fullcalendar/rrule")).default);
if (isEditable || isCalendarRoot) {
plugins.push((await import("@fullcalendar/interaction")).default);
}
@@ -307,11 +309,11 @@ function useEditing(note: FNote, isEditable: boolean, isCalendarRoot: boolean, c
// Called upon when clicking the day number in the calendar, opens or creates the day note but only if in a calendar root.
const onDateClick = useCallback(async (e: DateClickArg) => {
const eventNote = await date_notes.getDayNote(e.dateStr);
const eventNote = await date_notes.getDayNote(e.dateStr, note.noteId);
if (eventNote) {
appContext.triggerCommand("openInPopup", { noteIdOrPath: eventNote.noteId });
}
}, []);
}, [ note ]);
return {
select: onCalendarSelection,

View File

@@ -7,14 +7,9 @@
> .collection-properties {
position: relative;
z-index: 998;
}
}
body.mobile .geo-view > .collection-properties {
z-index: 2500;
}
.geo-map-container {
height: 100%;
overflow: hidden;

View File

@@ -2,142 +2,40 @@
overflow: visible;
position: relative;
height: 100%;
.note-list-wrapper {
height: 100%;
overflow: auto;
}
&.grid-view .note-list-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.note-list-bottom-pager {
margin-block: 8px;
}
&:not(:has(.note-list-bottom-pager)) {
margin-bottom: 48px;
}
}
.note-book-card {
border-radius: 10px;
background-color: var(--accented-background-color);
padding: 10px 15px 15px 8px;
margin: 5px 5px 5px 5px;
overflow: hidden;
display: flex;
flex-direction: column;
flex-shrink: 0;
flex-grow: 1;
}
/* #region List view / Grid view common styles */
.note-book-card.archived {
opacity: 0.5;
}
.note-book-card:not(.expanded) .note-book-content {
padding: 10px
}
.note-book-card.expanded .note-book-content {
display: block;
min-height: 0;
height: 100%;
padding-top: 10px;
}
.note-book-content .rendered-content {
height: 100%;
}
.note-book-header {
border-bottom: 1px solid var(--main-border-color);
margin-bottom: 0;
padding-bottom: .5rem;
word-break: break-all;
flex-shrink: 0;
}
/* not-expanded title is limited to one line only */
.note-book-card:not(.expanded) .note-book-header {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.note-book-header .rendered-note-attributes {
font-size: medium;
}
.note-book-header .rendered-note-attributes:before {
content: "\00a0\00a0";
}
.note-book-header .note-icon {
font-size: 100%;
display: inline-block;
padding-inline-end: 7px;
position: relative;
}
.note-book-card .note-book-card {
border: 1px solid var(--main-border-color);
}
.note-book-content.type-image, .note-book-content.type-file, .note-book-content.type-protectedSession {
.nested-note-list-item h5,
.note-book-card .note-book-header {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 10px;
flex-grow: 1;
}
.note-book-content.type-image img, .note-book-content.type-canvas svg {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.note-book-card.type-image .note-book-content img,
.note-book-card.type-text .note-book-content img,
.note-book-card.type-canvas .note-book-content img {
max-width: 100%;
max-height: 100%;
}
.note-book-header {
flex-grow: 0;
}
.note-list-wrapper {
height: 100%;
overflow: auto;
}
/* #region List view */
@keyframes note-preview-show {
from {
opacity: 0;
} to {
opacity: 1;
}
}
.nested-note-list {
--card-nested-section-indent: 25px;
&.search-results {
--card-nested-section-indent: 32px;
}
}
/* List item */
.nested-note-list-item {
h5 {
display: flex;
align-items: center;
font-size: 1em;
font-weight: normal;
margin: 0;
}
.note-expander {
margin-inline-end: 4px;
font-size: x-large;
cursor: pointer;
}
font-size: 1em;
font-weight: normal;
margin: 0;
.tn-icon {
margin-inline-end: 8px;
color: var(--note-list-view-icon-color);
font-size: 1.2em;
margin-inline-end: 8px;
}
.note-book-title {
@@ -147,52 +45,24 @@
font-weight: normal;
}
.note-path {
margin-left: 0.5em;
vertical-align: middle;
opacity: 0.5;
}
.note-list-attributes {
flex-grow: 1;
margin-inline-start: 1em;
text-align: right;
font-size: .75em;
opacity: .75;
}
.nested-note-list-item-menu {
.note-book-item-menu {
margin-inline-start: 8px;
flex-shrink: 0;
}
&.archived {
span.tn-icon + span,
.tn-icon {
opacity: .6;
}
}
&.use-note-color {
span.tn-icon + span,
.nested-note-list:not(.search-results) & .tn-icon,
.rendered-note-attributes {
color: var(--custom-color);
}
}
}
.nested-note-list:not(.search-results) h5 {
.nested-note-list-item.use-note-color,
.note-book-card.use-note-color .note-book-header {
span.tn-icon + span,
.note-list-attributes {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.tn-icon,
.rendered-note-attributes {
color: var(--custom-color);
}
}
/* List item (search results view) */
.nested-note-list.search-results .nested-note-list-item {
/* Search result view */
.nested-note-list.search-results .nested-note-list-item,
.note-list-container.search-results .note-book-card .note-book-header {
span.tn-icon + span > span {
display: flex;
flex-direction: column-reverse;
@@ -204,6 +74,7 @@
}
.note-path {
opacity: 0.5;
margin-left: 0;
font-size: .85em;
line-height: .85em;
@@ -225,7 +96,7 @@
color: var(--note-icon-custom-color, var(--note-list-view-large-icon-color));
}
h5 .ck-find-result {
.ck-find-result {
background: var(--note-list-view-search-result-highlight-background);
color: var(--note-list-view-search-result-highlight-color);
font-weight: 600;
@@ -233,21 +104,114 @@
}
}
@keyframes note-preview-show {
from {
opacity: 0;
} to {
opacity: 1;
}
}
.nested-note-list .note-book-content,
.note-list-container .note-book-content {
display: none;
animation: note-preview-show .35s ease-out;
will-change: opacity;
&.note-book-content-ready {
display: block;
}
.ck-find-result {
outline: 2px solid var(--note-list-view-content-search-result-highlight-background);
border-radius: 4px;
background: var(--note-list-view-content-search-result-highlight-background);
color: var(--note-list-view-content-search-result-highlight-color);
}
}
.note-book-content {
height: 100%;
&.type-image, &.type-file, &.type-protectedSession {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 10px;
flex-grow: 1;
}
&.type-image img, &.type-canvas svg {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
}
.note-content-preview:has(.note-book-content:empty) {
display: none;
}
/* #endregion */
/* #region List view */
.nested-note-list {
--card-nested-section-indent: 25px;
&.search-results {
--card-nested-section-indent: 32px;
}
}
/* List item */
.nested-note-list-item {
.note-expander {
margin-inline-end: 4px;
font-size: x-large;
cursor: pointer;
}
.tn-icon {
color: var(--note-list-view-icon-color);
}
.note-list-attributes {
flex-grow: 1;
margin-inline-start: 1em;
text-align: right;
font-size: .75em;
opacity: .75;
}
&.archived {
span.tn-icon + span,
.tn-icon {
opacity: .6;
}
}
}
.nested-note-list:not(.search-results) h5,
.note-book-card:not(.search-results) h5 {
span.tn-icon + span,
.note-list-attributes {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
/* Note content preview */
.nested-note-list .note-book-content {
display: none;
outline: 1px solid var(--note-list-view-content-background);
border-radius: 8px;
background-color: var(--note-list-view-content-background);
overflow: hidden;
user-select: text;
font-size: .85rem;
animation: note-preview-show .25s ease-out;
will-change: opacity;
&.note-book-content-ready {
display: block;
}
> .rendered-content > *:last-child {
margin-bottom: 0;
@@ -270,7 +234,7 @@
}
&.type-pdf {
iframe {
div {
height: 50vh;
}
@@ -285,54 +249,190 @@
justify-content: center;
min-height: 50vh;
}
.ck-find-result {
outline: 2px solid var(--note-list-view-content-search-result-highlight-background);
border-radius: 4px;
background: var(--note-list-view-content-search-result-highlight-background);
color: var(--note-list-view-content-search-result-highlight-color);
}
}
.note-content-preview:has(.note-book-content:empty) {
display: none;
}
/* #endregion */
/* #region Grid view */
.note-list.grid-view .note-list-container {
.note-list .note-book-card {
--note-list-horizontal-padding: 22px;
--note-list-vertical-padding: 15px;
display: flex;
flex-wrap: wrap;
}
.note-list.grid-view .note-book-card {
flex-direction: column;
flex-shrink: 0;
flex-grow: 1;
flex-basis: 300px;
border: 1px solid transparent;
}
body.mobile .note-list.grid-view .note-book-card {
flex-basis: 150px;
}
.note-list.grid-view .note-book-card {
max-height: 300px;
padding: 0;
overflow: hidden;
user-select: none;
body.mobile & {
flex-basis: 150px;
}
&:hover {
background-color: var(--card-background-hover-color);
filter: contrast(105%);
transition: background-color 200ms ease-out;
}
&:not(:has(:is(.note-book-item-menu:active, .btn-primary:active))):active {
transform: scale(.98);
}
&.archived {
opacity: 0.5;
}
.note-book-header {
margin-bottom: 0;
border-bottom: 1px solid var(--card-border-color, var(--main-border-color));
padding-bottom: .5rem;
word-break: break-all;
flex-shrink: 0;
padding: .5rem 1rem;
padding-inline-end: 8px;
.tn-icon + span {
flex-grow: 1;
a {
font-weight: 500;
}
}
}
& .note-book-content {
&.type-image .note-book-content img,
&.type-text .note-book-content img,
&.type-canvas .note-book-content img {
max-width: 100%;
max-height: 100%;
}
.rendered-content {
height: 100%;
}
.rendered-content:has(.file-footer) {
padding: 0;
}
img {
max-height: 220px;
object-fit: contain;
}
.file-footer {
display: flex;
gap: 8px;
justify-content: space-between;
padding: 0;
.btn.btn-primary {
flex: 1;
margin: 0;
box-shadow: unset;
background: transparent;
border: 0;
border-radius: 0;
padding: 8px;
color: var(--main-text-color);
&:hover {
background: var(--more-accented-background-color);
}
&:active {
transform: none;
}
}
}
}
}
.note-list.grid-view .note-book-card img {
max-height: 220px;
object-fit: contain;
.note-book-card .note-book-content {
padding: 0;
flex: 1;
overflow: hidden;
font-size: 0.8rem;
&.note-book-content-overflowing {
mask-image: linear-gradient(to bottom, black calc(100% - 75px), transparent 100%);
mask-repeat: no-repeat;
mask-size: 100% 100%;
}
.ck-content p {
margin-bottom: 0.5em;
line-height: 1.3;
}
.ck-content figure.image {
width: 25%;
}
.ck-content .table {
display: flex;
flex-direction: column-reverse;
overflow-x: scroll;
--scrollbar-thickness: 0;
scrollbar-width: none;
table {
width: max-content;
table-layout: auto;
}
figcaption {
display: block;
position: sticky;
left: 0;
width: 100%;
}
}
.rendered-content,
.rendered-content.text-with-ellipsis {
padding: .5rem 1rem 1rem 1rem;
}
&.type-image .rendered-content,
&.type-pdf .rendered-content {
padding: 0;
}
&.type-video video {
max-height: 200px;
}
h1, h2, h3, h4, h5, h6 {
font-size: 1rem;
color: var(--active-item-text-color);
}
p:last-child {
margin-bottom: 0;
}
&.type-canvas .rendered-content,
&.type-mindMap .rendered-content,
&.type-code .rendered-content,
&.type-video .rendered-content {
padding: 0;
}
&.type-code {
height: 100%;
}
&.type-code pre {
height: 100%;
padding: 1em;
margin-bottom: 0;
}
}
.note-list.grid-view .note-book-card:hover {
cursor: pointer;
border: 1px solid var(--main-border-color);
background: var(--more-accented-background-color);
}
.note-list.grid-view .note-path {
margin-left: 0.5em;
vertical-align: middle;
opacity: 0.5;
}
/* #endregion */
/* #endregion */

View File

@@ -1,7 +1,7 @@
import "./ListOrGridView.css";
import { Card, CardSection } from "../../react/Card";
import { Card, CardFrame, CardSection } from "../../react/Card";
import { useEffect, useRef, useState } from "preact/hooks";
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
import FNote from "../../../entities/fnote";
import attribute_renderer from "../../../services/attribute_renderer";
@@ -13,13 +13,15 @@ import { useImperativeSearchHighlighlighting, useNoteLabel, useNoteLabelBoolean,
import Icon from "../../react/Icon";
import NoteLink from "../../react/NoteLink";
import { ViewModeProps } from "../interface";
import { Pager, usePagination } from "../Pagination";
import { Pager, usePagination, PaginationContext } from "../Pagination";
import { filterChildNotes, useFilteredNoteIds } from "./utils";
import { JSX } from "preact/jsx-runtime";
import { clsx } from "clsx";
import ActionButton from "../../react/ActionButton";
import linkContextMenuService from "../../../menus/link_context_menu";
import { TargetedMouseEvent } from "preact";
import { ComponentChildren, TargetedMouseEvent } from "preact";
const contentSizeObserver = new ResizeObserver(onContentResized);
export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) {
const expandDepth = useExpansionDepth(note);
@@ -27,32 +29,18 @@ export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }
const { pageNotes, ...pagination } = usePagination(note, noteIds);
const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived");
const noteType = useNoteProperty(note, "type");
const hasCollectionProperties = [ "book", "search" ].includes(noteType ?? "");
return (
<div class="note-list list-view">
<CollectionProperties
note={note}
centerChildren={<Pager {...pagination} />}
/>
{ noteIds.length > 0 && <div class="note-list-wrapper">
{!hasCollectionProperties && <Pager {...pagination} />}
<Card className={clsx("nested-note-list", {"search-results": (noteType === "search")})}>
{pageNotes?.map(childNote => (
<ListNoteCard
key={childNote.noteId}
note={childNote} parentNote={note}
expandDepth={expandDepth} highlightedTokens={highlightedTokens}
currentLevel={1} includeArchived={includeArchived} />
))}
</Card>
<Pager {...pagination} />
</div>}
</div>
);
return <NoteList note={note} viewMode="list-view" noteIds={noteIds} pagination={pagination}>
<Card className={clsx("nested-note-list", {"search-results": (noteType === "search")})}>
{pageNotes?.map(childNote => (
<ListNoteCard
key={childNote.noteId}
note={childNote} parentNote={note}
expandDepth={expandDepth} highlightedTokens={highlightedTokens}
currentLevel={1} includeArchived={includeArchived} />
))}
</Card>
</NoteList>;
}
export function GridView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) {
@@ -60,28 +48,47 @@ export function GridView({ note, noteIds: unfilteredNoteIds, highlightedTokens }
const { pageNotes, ...pagination } = usePagination(note, noteIds);
const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived");
const noteType = useNoteProperty(note, "type");
const hasCollectionProperties = [ "book", "search" ].includes(noteType ?? "");
return (
<div class="note-list grid-view">
<CollectionProperties
note={note}
centerChildren={<Pager {...pagination} />}
/>
<div class="note-list-wrapper">
{!hasCollectionProperties && <Pager {...pagination} />}
<div class="note-list-container use-tn-links">
{pageNotes?.map(childNote => (
<GridNoteCard note={childNote} parentNote={note} highlightedTokens={highlightedTokens} includeArchived={includeArchived} />
))}
</div>
<Pager {...pagination} />
</div>
return <NoteList note={note} viewMode="grid-view" noteIds={noteIds} pagination={pagination}>
<div className={clsx("note-list-container use-tn-links", {"search-results": (noteType === "search")})}>
{pageNotes?.map(childNote => (
<GridNoteCard key={childNote.noteId}
note={childNote}
parentNote={note}
highlightedTokens={highlightedTokens}
includeArchived={includeArchived} />
))}
</div>
);
</NoteList>
}
interface NoteListProps {
note: FNote,
viewMode: "list-view" | "grid-view",
noteIds: string[],
pagination: PaginationContext,
children: ComponentChildren
}
function NoteList(props: NoteListProps) {
const noteType = useNoteProperty(props.note, "type");
const hasCollectionProperties = ["book", "search"].includes(noteType ?? "");
return <div className={clsx("note-list", props.viewMode)}>
<CollectionProperties
note={props.note}
centerChildren={<Pager className="note-list-top-pager" {...props.pagination} />}
/>
{props.noteIds.length > 0 && <div className="note-list-wrapper">
{!hasCollectionProperties && <Pager {...props.pagination} />}
{props.children}
<Pager className="note-list-bottom-pager" {...props.pagination} />
</div>}
</div>
}
function ListNoteCard({ note, parentNote, highlightedTokens, currentLevel, expandDepth, includeArchived }: {
@@ -139,39 +146,47 @@ function ListNoteCard({ note, parentNote, highlightedTokens, currentLevel, expan
showNotePath={parentNote.type === "search"}
highlightedTokens={highlightedTokens} />
<NoteAttributes note={note} />
<ActionButton className="nested-note-list-item-menu"
icon="bx bx-dots-vertical-rounded" text=""
onClick={(e) => openNoteMenu(notePath, e)}
/>
<NoteMenuButton notePath={notePath} />
</h5>
</CardSection>
);
}
function GridNoteCard({ note, parentNote, highlightedTokens, includeArchived }: { note: FNote, parentNote: FNote, highlightedTokens: string[] | null | undefined, includeArchived: boolean }) {
const titleRef = useRef<HTMLSpanElement>(null);
const [ noteTitle, setNoteTitle ] = useState<string>();
const notePath = getNotePath(parentNote, note);
interface GridNoteCardProps {
note: FNote;
parentNote: FNote;
highlightedTokens: string[] | null | undefined;
includeArchived: boolean;
}
function GridNoteCard(props: GridNoteCardProps) {
const notePath = getNotePath(props.parentNote, props.note);
return (
<div
className={`note-book-card no-tooltip-preview block-link ${note.isArchived ? "archived" : ""}`}
data-href={`#${notePath}`}
data-note-id={note.noteId}
onClick={(e) => link.goToLink(e)}
<CardFrame className={clsx("note-book-card", "no-tooltip-preview", "block-link", props.note.getColorClass(), {
"archived": props.note.isArchived
})}
data-href={`#${notePath}`}
data-note-id={props.note.noteId}
onClick={(e) => link.goToLink(e)}
>
<h5 className="note-book-header">
<Icon className="note-icon" icon={note.getIcon()} />
<NoteLink className="note-book-title" notePath={notePath} noPreview showNotePath={parentNote.type === "search"} highlightedTokens={highlightedTokens} />
<NoteAttributes note={note} />
<h5 className={clsx("note-book-header")}>
<Icon className="note-icon" icon={props.note.getIcon()} />
<NoteLink className="note-book-title"
notePath={notePath}
noPreview
showNotePath={props.parentNote.type === "search"}
highlightedTokens={props.highlightedTokens}
/>
{!props.note.isOptions() && <NoteMenuButton notePath={notePath} />}
</h5>
<NoteContent
note={note}
trim
highlightedTokens={highlightedTokens}
includeArchivedNotes={includeArchived}
<NoteContent note={props.note}
trim
highlightedTokens={props.highlightedTokens}
includeArchivedNotes={props.includeArchived}
/>
</div>
</CardFrame>
);
}
@@ -199,6 +214,17 @@ export function NoteContent({ note, trim, noChildrenList, highlightedTokens, inc
const [ready, setReady] = useState(false);
const [noteType, setNoteType] = useState<string>("none");
useEffect(() => {
const contentElement = contentRef.current;
if (!contentElement) return;
contentSizeObserver.observe(contentElement);
return () => {
contentSizeObserver.unobserve(contentElement);
}
}, []);
useEffect(() => {
content_renderer.getRenderedContent(note, {
trim,
@@ -252,6 +278,18 @@ function NoteChildren({ note, parentNote, highlightedTokens, currentLevel, expan
/>);
}
function NoteMenuButton(props: {notePath: string}) {
const openMenu = useCallback((e: TargetedMouseEvent<HTMLElement>) => {
linkContextMenuService.openContextMenu(props.notePath, e);
e.stopPropagation()
}, [props.notePath]);
return <ActionButton className="note-book-item-menu"
icon="bx bx-dots-vertical-rounded" text=""
onClick={openMenu}
/>
}
function getNotePath(parentNote: FNote, childNote: FNote) {
if (parentNote.type === "search") {
// for search note parent, we want to display a non-search path
@@ -275,7 +313,9 @@ function useExpansionDepth(note: FNote) {
}
function openNoteMenu(notePath, e: TargetedMouseEvent<HTMLElement>) {
linkContextMenuService.openContextMenu(notePath, e);
e.stopPropagation()
}
function onContentResized(entries: ResizeObserverEntry[], observer: ResizeObserver): void {
for (const contentElement of entries) {
const isOverflowing = ((contentElement.target.scrollHeight > contentElement.target.clientHeight))
contentElement.target.classList.toggle("note-book-content-overflowing", isOverflowing);
}
}

View File

@@ -13,6 +13,7 @@
.table-view-container {
height: 100%;
margin-inline-start: var(--content-margin-inline);
}
.search-result-widget-content .table-view {

View File

@@ -10,8 +10,6 @@ export default class ScrollingContainer extends Container<BasicWidget> {
constructor() {
super();
this.class("scrolling-container");
}
setNoteContextEvent({ noteContext }: EventData<"setNoteContext">) {

View File

@@ -4,6 +4,7 @@
overflow: auto;
scroll-behavior: smooth;
position: relative;
flex-grow: 1;
> .note-detail > .note-detail-editable-text > .note-detail-editable-text-editor,
> .note-list-widget:not(.full-height) .note-list-wrapper {

View File

@@ -0,0 +1,9 @@
import { ComponentChildren } from "preact";
export default function ScrollingContainer({ children }: { children: ComponentChildren }) {
return (
<div className="scrolling-container">
{children}
</div>
);
}

View File

@@ -3,7 +3,7 @@ import { LOCALES } from "@triliumnext/commons";
import { EventData } from "../../components/app_context.js";
import { getEnabledExperimentalFeatureIds } from "../../services/experimental_features.js";
import options from "../../services/options.js";
import utils, { isMobile } from "../../services/utils.js";
import utils, { isIOS, isMobile } from "../../services/utils.js";
import { readCssVar } from "../../utils/css-var.js";
import type BasicWidget from "../basic_widget.js";
import FlexContainer from "./flex_container.js";
@@ -13,15 +13,20 @@ import FlexContainer from "./flex_container.js";
*
* For convenience, the root container has a few class selectors that can be used to target some global state:
*
* - `#root-container.light-theme`, indicates whether the current color scheme is light.
* - `#root-container.dark-theme`, indicates whether the current color scheme is dark.
* - `#root-container.virtual-keyboard-opened`, on mobile devices if the virtual keyboard is open.
* - `#root-container.horizontal-layout`, if the current layout is horizontal.
* - `#root-container.vertical-layout`, if the current layout is horizontal.
*/
export default class RootContainer extends FlexContainer<BasicWidget> {
private originalWindowHeight: number;
constructor(isHorizontalLayout: boolean) {
super(isHorizontalLayout ? "column" : "row");
this.originalWindowHeight = window.innerHeight ?? 0;
this.id("root-widget");
this.css("height", "100dvh");
}
@@ -31,6 +36,8 @@ export default class RootContainer extends FlexContainer<BasicWidget> {
window.visualViewport?.addEventListener("resize", () => this.#onMobileResize());
}
this.#initTheme();
this.#setDeviceSpecificClasses();
this.#setMaxContentWidth();
this.#setMotion();
this.#setShadows();
@@ -63,9 +70,24 @@ export default class RootContainer extends FlexContainer<BasicWidget> {
}
}
#initTheme() {
const colorSchemeChangeObserver = matchMedia("(prefers-color-scheme: dark)")
colorSchemeChangeObserver.addEventListener("change", () => this.#updateColorScheme());
this.#updateColorScheme();
document.body.setAttribute("data-theme-id", options.get("theme"));
}
#updateColorScheme() {
const colorScheme = readCssVar(document.body, "theme-style").asString();
document.body.classList.toggle("light-theme", colorScheme === "light");
document.body.classList.toggle("dark-theme", colorScheme === "dark");
}
#onMobileResize() {
const viewportHeight = window.visualViewport?.height ?? window.innerHeight;
const windowHeight = window.innerHeight;
const windowHeight = Math.max(window.innerHeight, this.originalWindowHeight); // inner height changes when keyboard is opened, we need to compare with the original height to detect it.
// If viewport is significantly smaller, keyboard is likely open
const isKeyboardOpened = windowHeight - viewportHeight > 150;
@@ -117,6 +139,12 @@ export default class RootContainer extends FlexContainer<BasicWidget> {
document.body.dir = correspondingLocale?.rtl ? "rtl" : "ltr";
}
#setDeviceSpecificClasses() {
if (isIOS()) {
document.body.classList.add("ios");
}
}
#initPWATopbarColor() {
if (!utils.isPWA()) return;
const tracker = $("#background-color-tracker");

View File

@@ -1,9 +1,12 @@
import { VNode } from "preact";
import appContext, { type CommandData, type CommandListenerData, type EventData, type EventNames, type NoteSwitchedContext } from "../../components/app_context.js";
import Component from "../../components/component.js";
import NoteContext from "../../components/note_context.js";
import splitService from "../../services/resizer.js";
import { isMobile } from "../../services/utils.js";
import type BasicWidget from "../basic_widget.js";
import { wrapReactWidgets } from "../basic_widget.js";
import NoteContextAwareWidget from "../note_context_aware_widget.js";
import FlexContainer from "./flex_container.js";
@@ -12,7 +15,7 @@ interface SplitNoteWidget extends BasicWidget {
ntxId?: string;
}
type WidgetFactory = () => SplitNoteWidget;
type WidgetFactory = () => (SplitNoteWidget | VNode);
export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
@@ -31,7 +34,7 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
}
async newNoteContextCreatedEvent({ noteContext }: EventData<"newNoteContextCreated">) {
const widget = this.widgetFactory();
const widget = wrapReactWidgets([ this.widgetFactory() ])[0];
const $renderedWidget = widget.render();

View File

@@ -118,3 +118,11 @@ body.mobile .modal.popup-editor-dialog .modal-dialog {
border-radius: 0;
}
}
.modal.popup-editor-dialog .note-list-widget {
--content-margin-inline: 12px;
&:not(.full-height) .note-list-wrapper {
margin-inline: var(--content-margin-inline);
}
}

View File

@@ -54,6 +54,8 @@ export default function PopupEditor() {
}
});
// Events triggered at note context level (e.g. the save indicator) would not work since the note context has no parent component. Propagate events to parent component so that they can be handled properly.
noteContext.triggerEvent = (name, data) => parentComponent?.handleEventInChildren(name, data);
setNoteContext(noteContext);
setShown(true);
});

View File

@@ -3,7 +3,7 @@ import clsx from "clsx";
import server from "../../services/server";
import { TargetedMouseEvent, VNode } from "preact";
import { useEffect, useState } from "preact/hooks";
import { Dayjs } from "@triliumnext/commons";
import { Dayjs, getWeekInfo, WeekSettings } from "@triliumnext/commons";
import { t } from "../../services/i18n";
interface DateNotesForMonth {
@@ -22,6 +22,7 @@ const DAYS_OF_WEEK = [
interface DateRangeInfo {
weekNumbers: number[];
weekYears: number[];
dates: Dayjs[];
}
@@ -36,19 +37,27 @@ export interface CalendarArgs {
export default function Calendar(args: CalendarArgs) {
const [ rawFirstDayOfWeek ] = useTriliumOptionInt("firstDayOfWeek");
const [ firstWeekOfYear ] = useTriliumOptionInt("firstWeekOfYear");
const [ minDaysInFirstWeek ] = useTriliumOptionInt("minDaysInFirstWeek");
const firstDayOfWeekISO = (rawFirstDayOfWeek === 0 ? 7 : rawFirstDayOfWeek);
const weekSettings = {
firstDayOfWeek: firstDayOfWeekISO,
firstWeekOfYear: firstWeekOfYear ?? 0,
minDaysInFirstWeek: minDaysInFirstWeek ?? 4
};
const date = args.date;
const firstDay = date.startOf('month');
const firstDayISO = firstDay.isoWeekday();
const monthInfo = getMonthInformation(date, firstDayISO, firstDayOfWeekISO);
const monthInfo = getMonthInformation(date, firstDayISO, weekSettings);
return (
<>
<CalendarWeekHeader rawFirstDayOfWeek={rawFirstDayOfWeek} />
<div className="calendar-body" data-calendar-area="month">
{firstDayISO !== firstDayOfWeekISO && <PreviousMonthDays info={monthInfo.prevMonth} {...args} />}
<CurrentMonthDays firstDayOfWeekISO={firstDayOfWeekISO} {...args} />
{firstDayISO !== firstDayOfWeekISO && <PreviousMonthDays info={monthInfo.prevMonth} weekSettings={weekSettings} {...args} />}
<CurrentMonthDays weekSettings={weekSettings} {...args} />
<NextMonthDays dates={monthInfo.nextMonth.dates} {...args} />
</div>
</>
@@ -67,7 +76,7 @@ function CalendarWeekHeader({ rawFirstDayOfWeek }: { rawFirstDayOfWeek: number }
)
}
function PreviousMonthDays({ date, info: { dates, weekNumbers }, ...args }: { date: Dayjs, info: DateRangeInfo } & CalendarArgs) {
function PreviousMonthDays({ date, info: { dates, weekNumbers, weekYears }, weekSettings, ...args }: { date: Dayjs, info: DateRangeInfo, weekSettings: WeekSettings } & CalendarArgs) {
const prevMonth = date.subtract(1, 'month').format('YYYY-MM');
const [ dateNotesForPrevMonth, setDateNotesForPrevMonth ] = useState<DateNotesForMonth>();
@@ -77,27 +86,28 @@ function PreviousMonthDays({ date, info: { dates, weekNumbers }, ...args }: { da
return (
<>
<CalendarWeek date={date} weekNumber={weekNumbers[0]} {...args} />
<CalendarWeek date={date} weekNumber={weekNumbers[0]} weekYear={weekYears[0]} {...args} />
{dates.map(date => <CalendarDay key={date.toISOString()} date={date} dateNotesForMonth={dateNotesForPrevMonth} className="calendar-date-prev-month" {...args} />)}
</>
)
}
function CurrentMonthDays({ date, firstDayOfWeekISO, ...args }: { date: Dayjs, firstDayOfWeekISO: number } & CalendarArgs) {
function CurrentMonthDays({ date, weekSettings, ...args }: { date: Dayjs, weekSettings: WeekSettings } & CalendarArgs) {
let dateCursor = date;
const currentMonth = date.month();
const items: VNode[] = [];
const curMonthString = date.format('YYYY-MM');
const [ dateNotesForCurMonth, setDateNotesForCurMonth ] = useState<DateNotesForMonth>();
const { firstDayOfWeek, firstWeekOfYear, minDaysInFirstWeek } = weekSettings;
useEffect(() => {
server.get<DateNotesForMonth>(`special-notes/notes-for-month/${curMonthString}`).then(setDateNotesForCurMonth);
}, [ date ]);
while (dateCursor.month() === currentMonth) {
const weekNumber = getWeekNumber(dateCursor, firstDayOfWeekISO);
if (dateCursor.isoWeekday() === firstDayOfWeekISO) {
items.push(<CalendarWeek key={`${dateCursor.year()}-W${weekNumber}`} date={dateCursor} weekNumber={weekNumber} {...args}/>)
const { weekYear, weekNumber } = getWeekInfo(dateCursor, weekSettings);
if (dateCursor.isoWeekday() === firstDayOfWeek) {
items.push(<CalendarWeek key={`${weekYear}-W${weekNumber}`} date={dateCursor} weekNumber={weekNumber} weekYear={weekYear} {...args}/>)
}
items.push(<CalendarDay key={dateCursor.toISOString()} date={dateCursor} dateNotesForMonth={dateNotesForCurMonth} {...args} />)
@@ -141,14 +151,8 @@ function CalendarDay({ date, dateNotesForMonth, className, activeDate, todaysDat
);
}
function CalendarWeek({ date, weekNumber, weekNotes, onWeekClicked }: { weekNumber: number, weekNotes: string[] } & Pick<CalendarArgs, "date" | "onWeekClicked">) {
const localDate = date.local();
// Handle case where week is in between years.
let year = localDate.year();
if (localDate.month() === 11 && weekNumber === 1) year++;
const weekString = `${year}-W${String(weekNumber).padStart(2, '0')}`;
function CalendarWeek({ date, weekNumber, weekYear, weekNotes, onWeekClicked }: { weekNumber: number, weekYear: number, weekNotes: string[] } & Pick<CalendarArgs, "date" | "onWeekClicked">) {
const weekString = `${weekYear}-W${String(weekNumber).padStart(2, '0')}`;
if (onWeekClicked) {
return (
@@ -169,33 +173,33 @@ function CalendarWeek({ date, weekNumber, weekNotes, onWeekClicked }: { weekNumb
>{weekNumber}</span>);
}
export function getMonthInformation(date: Dayjs, firstDayISO: number, firstDayOfWeekISO: number) {
export function getMonthInformation(date: Dayjs, firstDayISO: number, weekSettings: WeekSettings) {
return {
prevMonth: getPrevMonthDays(date, firstDayISO, firstDayOfWeekISO),
nextMonth: getNextMonthDays(date, firstDayOfWeekISO)
prevMonth: getPrevMonthDays(date, firstDayISO, weekSettings),
nextMonth: getNextMonthDays(date, weekSettings.firstDayOfWeek)
}
}
function getPrevMonthDays(date: Dayjs, firstDayISO: number, firstDayOfWeekISO: number): DateRangeInfo {
function getPrevMonthDays(date: Dayjs, firstDayISO: number, weekSettings: WeekSettings): DateRangeInfo {
const prevMonthLastDay = date.subtract(1, 'month').endOf('month');
const daysToAdd = (firstDayISO - firstDayOfWeekISO + 7) % 7;
const daysToAdd = (firstDayISO - weekSettings.firstDayOfWeek + 7) % 7;
const dates: Dayjs[] = [];
const firstDay = date.startOf('month');
const weekNumber = getWeekNumber(firstDay, firstDayOfWeekISO);
const { weekYear, weekNumber } = getWeekInfo(firstDay, weekSettings);
// Get dates from previous month
for (let i = daysToAdd - 1; i >= 0; i--) {
dates.push(prevMonthLastDay.subtract(i, 'day'));
}
return { weekNumbers: [ weekNumber ], dates };
return { weekNumbers: [ weekNumber ], weekYears: [ weekYear ], dates };
}
function getNextMonthDays(date: Dayjs, firstDayOfWeekISO: number): DateRangeInfo {
function getNextMonthDays(date: Dayjs, firstDayOfWeek: number): DateRangeInfo {
const lastDayOfMonth = date.endOf('month');
const lastDayISO = lastDayOfMonth.isoWeekday();
const lastDayOfUserWeek = ((firstDayOfWeekISO + 6 - 1) % 7) + 1;
const lastDayOfUserWeek = ((firstDayOfWeek + 6 - 1) % 7) + 1;
const nextMonthFirstDay = date.add(1, 'month').startOf('month');
const dates: Dayjs[] = [];
@@ -206,16 +210,5 @@ function getNextMonthDays(date: Dayjs, firstDayOfWeekISO: number): DateRangeInfo
dates.push(nextMonthFirstDay.add(i, 'day'));
}
}
return { weekNumbers: [], dates };
}
export function getWeekNumber(date: Dayjs, firstDayOfWeekISO: number): number {
const weekStart = getWeekStartDate(date, firstDayOfWeekISO);
return weekStart.isoWeek();
}
function getWeekStartDate(date: Dayjs, firstDayOfWeekISO: number): Dayjs {
const currentISO = date.isoWeekday();
const diff = (currentISO - firstDayOfWeekISO + 7) % 7;
return date.clone().subtract(diff, "day").startOf("day");
return { weekNumbers: [], weekYears: [], dates };
}

View File

@@ -35,7 +35,7 @@
.calendar-dropdown-widget .calendar-header {
align-items: center;
display: flex;
padding: 0 0.5rem 0.5rem 0.5rem;
padding: 0 0.5rem 1rem 0.5rem;
}
.calendar-dropdown-widget .calendar-header>div {
@@ -65,8 +65,13 @@
border: 0;
border-inline-start: unset;
background-color: var(--menu-background-color);
font-weight: bold;
outline: 0;
font-weight: 300;
font-size: 1.4em;
}
.calendar-dropdown-widget .calendar-header .dropdown-toggle {
justify-content: center;
}
.calendar-dropdown-widget .calendar-header .dropdown-toggle::after {
@@ -82,18 +87,20 @@
.calendar-dropdown-widget .calendar-week span {
flex-direction: column;
flex: 0 0 12.5%;
font-size: 1rem;
font-weight: bold;
max-width: 12.5%;
padding-top: 5px;
padding-bottom: 5px;
text-align: center;
text-transform: uppercase;
font-size: .85em;
font-weight: 500;
}
.calendar-dropdown-widget .calendar-body {
display: flex;
flex-wrap: wrap;
min-height: 250px;
align-items: center;
}
.calendar-dropdown-widget .calendar-week-number {

View File

@@ -10,7 +10,7 @@ import BookmarkButtons from "./BookmarkButtons";
import CalendarWidget from "./CalendarWidget";
import HistoryNavigationButton from "./HistoryNavigation";
import { LaunchBarContext } from "./launch_bar_widgets";
import { AiChatButton, CommandButton, CustomWidget, NoteLauncher, QuickSearchLauncherWidget, ScriptLauncher, TodayLauncher } from "./LauncherDefinitions";
import { CommandButton, CustomWidget, NoteLauncher, QuickSearchLauncherWidget, ScriptLauncher, TodayLauncher } from "./LauncherDefinitions";
import ProtectedSessionStatusWidget from "./ProtectedSessionStatusWidget";
import SpacerWidget from "./SpacerWidget";
import SyncStatus from "./SyncStatus";
@@ -67,7 +67,7 @@ function Launcher({ note, isHorizontalLayout }: { note: FNote, isHorizontalLayou
case "builtinWidget":
return initBuiltinWidget(note, isHorizontalLayout);
default:
throw new Error(`Unrecognized launcher type '${launcherType}' for launcher '${note.noteId}' title '${note.title}'`);
console.warn(`Unrecognized launcher type '${launcherType}' for launcher '${note.noteId}' title '${note.title}'`);
}
}
@@ -96,12 +96,10 @@ function initBuiltinWidget(note: FNote, isHorizontalLayout: boolean) {
return <TodayLauncher launcherNote={note} />;
case "quickSearch":
return <QuickSearchLauncherWidget />;
case "aiChatLauncher":
return <AiChatButton launcherNote={note} />;
case "mobileTabSwitcher":
return <TabSwitcher />;
default:
throw new Error(`Unrecognized builtin widget ${builtinWidget} for launcher ${note.noteId} "${note.title}"`);
console.warn(`Unrecognized builtin widget ${builtinWidget} for launcher ${note.noteId} "${note.title}"`);
}
}

View File

@@ -11,7 +11,7 @@ import { getErrorMessage, isMobile } from "../../services/utils";
import BasicWidget from "../basic_widget";
import NoteContextAwareWidget from "../note_context_aware_widget";
import QuickSearchWidget from "../quick_search";
import { useGlobalShortcut, useLegacyWidget, useNoteLabel, useNoteRelationTarget, useTriliumOptionBool } from "../react/hooks";
import { useGlobalShortcut, useLegacyWidget, useNoteLabel, useNoteRelationTarget } from "../react/hooks";
import { ParentComponent } from "../react/react_utils";
import { CustomNoteLauncher } from "./GenericButtons";
import { LaunchBarActionButton, LaunchBarContext, LauncherNoteProps, useLauncherIconAndTitle } from "./launch_bar_widgets";
@@ -81,19 +81,6 @@ export function ScriptLauncher({ launcherNote }: LauncherNoteProps) {
);
}
export function AiChatButton({ launcherNote }: LauncherNoteProps) {
const [ aiEnabled ] = useTriliumOptionBool("aiEnabled");
const { icon, title } = useLauncherIconAndTitle(launcherNote);
return aiEnabled && (
<LaunchBarActionButton
icon={icon}
text={title}
triggerCommand="createAiChat"
/>
);
}
export function TodayLauncher({ launcherNote }: LauncherNoteProps) {
return (
<CustomNoteLauncher

View File

@@ -7,7 +7,7 @@ import { t } from "../../services/i18n";
import { goToLinkExt } from "../../services/link";
import { Badge, BadgeWithDropdown } from "../react/Badge";
import { FormDropdownDivider, FormListItem } from "../react/FormList";
import { useGetContextData, useIsNoteReadOnly, useNoteContext, useNoteLabel, useNoteLabelBoolean } from "../react/hooks";
import { useGetContextDataFrom, useIsNoteReadOnly, useNoteContext, useNoteLabel, useNoteLabelBoolean } from "../react/hooks";
import { useShareState } from "../ribbon/BasicPropertiesTab";
import { useShareInfo } from "../shared_info";
import { ActiveContentBadges } from "./ActiveContentBadges";
@@ -112,7 +112,8 @@ function ExecuteBadge() {
}
export function SaveStatusBadge() {
const saveState = useGetContextData("saveState");
const { noteContext} = useNoteContext();
const saveState = useGetContextDataFrom(noteContext, "saveState");
if (!saveState) return;
const stateConfig = {

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