Compare commits

..

271 Commits

Author SHA1 Message Date
perf3ct
66074ddbc9 fix(docs): try to fix more docs links... 2025-09-07 22:30:10 -07:00
Elian Doran
61ec341c27 Revert "fix: close context menu when clicking items with submenus"
This reverts commit 2f93af4d6f.
2025-09-07 22:57:27 +03:00
Elian Doran
22835108be fix: add left-click check for tree button handlers (#6903) 2025-09-07 22:53:42 +03:00
SiriusXT
617548f6b6 Merge branch 'main' into sirius_tree_patch 2025-09-07 19:18:23 +08:00
SiriusXT
2f93af4d6f fix: close context menu when clicking items with submenus 2025-09-07 17:15:09 +08:00
Elian Doran
145f89eded fix(shortcuts): try to fix ime composition checks (#6851) 2025-09-07 11:17:35 +03:00
Elian Doran
6c0e4b6a48 Merge branch 'main' into fix/ime-shortcut-input-fix 2025-09-07 11:13:18 +03:00
Elian Doran
87d1eefc86 chore(deps): update softprops/action-gh-release action to v2.3.3 (#6915) 2025-09-07 11:07:52 +03:00
Elian Doran
a87ec6f2e7 Translations update from Hosted Weblate (#6916) 2025-09-07 11:01:48 +03:00
donut
a9d5478bcd Translated using Weblate (Polish)
Currently translated at 37.8% (143 of 378 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/pl/
2025-09-07 09:59:34 +02:00
Elian Doran
5eae51a1b4 Apply note wrapper on mobile (#6847) 2025-09-07 10:59:28 +03:00
Elian Doran
ac94ab6914 feat: Make splits resizable (#6866) 2025-09-07 10:48:37 +03:00
Elian Doran
38673a85c9 feat: show source diff between note and revision (#6887) 2025-09-07 10:42:21 +03:00
renovate[bot]
d75951c869 chore(deps): update softprops/action-gh-release action to v2.3.3 2025-09-07 07:24:01 +00:00
Elian Doran
67d36a9e28 fix(deps): update dependency mind-elixir to v5.1.1 (#6914) 2025-09-07 10:02:35 +03:00
renovate[bot]
de8e8915ff fix(deps): update dependency mind-elixir to v5.1.1 2025-09-07 01:22:19 +00:00
Elian Doran
2161816ef4 fix(deps): update ckeditor monorepo to v46.0.3 (#6895) 2025-09-06 23:15:09 +03:00
renovate[bot]
d046bdec65 fix(deps): update ckeditor monorepo to v46.0.3 2025-09-06 20:05:18 +00:00
Elian Doran
cddd7d1562 fix(deps): update dependency ckeditor5 to v46.0.3 [security] (#6885) 2025-09-06 23:01:30 +03:00
renovate[bot]
15a3104904 fix(deps): update dependency ckeditor5 to v46.0.3 [security] 2025-09-06 19:53:33 +00:00
Elian Doran
e1ca6eca0f chore(deps): update dependency vite to v7.1.4 (#6893) 2025-09-06 22:52:01 +03:00
Elian Doran
cc0137bdc9 fix(deps): update dependency @mermaid-js/layout-elk to v0.2.0 (#6899) 2025-09-06 22:42:06 +03:00
Elian Doran
86a620bc08 Add an option to disable smooth scrolling for the Electron app (#6912) 2025-09-06 22:41:26 +03:00
Elian Doran
3ba9c3b4a8 Merge branch 'main' into history_diff 2025-09-06 22:37:55 +03:00
Elian Doran
8dc5ada553 Style: improve window background effects (#6913) 2025-09-06 22:36:59 +03:00
Elian Doran
9fe744c545 chore(deps): update actions/setup-node action to v5 (#6902) 2025-09-06 22:36:15 +03:00
Elian Doran
cc29eb0f9b chore(deps): update svelte monorepo (#6892) 2025-09-06 22:27:17 +03:00
renovate[bot]
901edde634 chore(deps): update dependency vite to v7.1.4 2025-09-06 19:24:39 +00:00
Elian Doran
44dd6d499d fix(deps): update dependency eslint-linter-browserify to v9.35.0 (#6905) 2025-09-06 22:24:05 +03:00
renovate[bot]
375f09cbaf fix(deps): update dependency @mermaid-js/layout-elk to v0.2.0 2025-09-06 19:23:04 +00:00
Elian Doran
d4e5a31de4 chore(deps): update tailwindcss monorepo to v4.1.13 (#6894) 2025-09-06 22:22:25 +03:00
Elian Doran
f3fa3864b2 chore(deps): update dependency node to v22 (#6891) 2025-09-06 22:21:44 +03:00
Elian Doran
1c978c2497 chore(deps): update dependency @types/leaflet-gpx to v1.3.8 (#6890) 2025-09-06 22:21:05 +03:00
Elian Doran
0f4ec2b3e2 chore(deps): update dependency @anthropic-ai/sdk to v0.61.0 (#6896) 2025-09-06 22:20:02 +03:00
Elian Doran
e30b1abaa4 chore(deps): update dependency @smithy/middleware-retry to v4.2.0 (#6897) 2025-09-06 22:19:26 +03:00
renovate[bot]
16cbee1fb2 chore(deps): update svelte monorepo 2025-09-06 19:18:48 +00:00
Elian Doran
56932f2b56 chore(deps): update dependency express-rate-limit to v8.1.0 (#6898) 2025-09-06 22:18:40 +03:00
Elian Doran
6a8f6b8370 fix(deps): update dependency i18next to v25.5.2 (#6900) 2025-09-06 22:17:19 +03:00
Elian Doran
7fa8e65015 fix(deps): update dependency mermaid to v11.11.0 (#6901) 2025-09-06 22:16:53 +03:00
Elian Doran
4f50b8c7d5 fix(deps): update eslint monorepo to v9.35.0 (#6907) 2025-09-06 22:15:36 +03:00
Elian Doran
eca85d9978 chore(deps): update actions/setup-python action to v6 (#6909) 2025-09-06 22:15:10 +03:00
Elian Doran
f0ea2eb39b fix(deps): update dependency force-graph to v1.51.0 (#6906) 2025-09-06 22:14:42 +03:00
Elian Doran
4c5b229680 chore(deps): update actions/github-script action to v8 (#6908) 2025-09-06 22:13:07 +03:00
Elian Doran
83251cbc43 Merge branch 'main' into feat/performance/disable-smooth-scroll 2025-09-06 22:12:19 +03:00
Adorian Doran
c2f20cce32 Merge branch 'main' into feat/electron-app/background-effects-improvements 2025-09-06 22:02:47 +03:00
Adorian Doran
ec5ab44519 style/background effects: tweak launcher pane colors 2025-09-06 22:00:16 +03:00
renovate[bot]
ed6d21a05a chore(deps): update dependency node to v22 2025-09-06 18:58:17 +00:00
renovate[bot]
a2f3913fe5 chore(deps): update actions/setup-python action to v6 2025-09-06 18:57:17 +00:00
renovate[bot]
d66c0ef308 chore(deps): update actions/setup-node action to v5 2025-09-06 18:57:14 +00:00
renovate[bot]
0f9f6746ed chore(deps): update actions/github-script action to v8 2025-09-06 18:57:10 +00:00
renovate[bot]
9b534a0dc1 fix(deps): update eslint monorepo to v9.35.0 2025-09-06 18:57:07 +00:00
renovate[bot]
1ce73c1238 fix(deps): update dependency mermaid to v11.11.0 2025-09-06 18:56:11 +00:00
renovate[bot]
3b5b7ca01d fix(deps): update dependency i18next to v25.5.2 2025-09-06 18:55:40 +00:00
renovate[bot]
ce64a7816d fix(deps): update dependency force-graph to v1.51.0 2025-09-06 18:55:09 +00:00
renovate[bot]
37e095a93c fix(deps): update dependency eslint-linter-browserify to v9.35.0 2025-09-06 18:54:39 +00:00
Adorian Doran
300f6a103f style/background effects: tweak launcher pane colors 2025-09-06 21:53:47 +03:00
renovate[bot]
e7cb5a6b92 chore(deps): update dependency express-rate-limit to v8.1.0 2025-09-06 18:53:07 +00:00
renovate[bot]
67296fabf7 chore(deps): update dependency @smithy/middleware-retry to v4.2.0 2025-09-06 18:52:37 +00:00
renovate[bot]
d868f7fb26 chore(deps): update dependency @anthropic-ai/sdk to v0.61.0 2025-09-06 18:52:08 +00:00
renovate[bot]
1555d98f7d chore(deps): update tailwindcss monorepo to v4.1.13 2025-09-06 18:51:05 +00:00
renovate[bot]
3a02941b38 chore(deps): update dependency @types/leaflet-gpx to v1.3.8 2025-09-06 18:49:37 +00:00
Elian Doran
f25de1ffbe chore(ci): bring back typecheck 2025-09-06 21:43:48 +03:00
Adorian Doran
008e90324f style/background effects: tweak launcher pane colors 2025-09-06 21:43:09 +03:00
Adorian Doran
73dcc2eb26 style/background effects: convert the tree action button background color to a transparent color 2025-09-06 21:32:31 +03:00
Adorian Doran
eae2540a31 style/background effects: convert the tree item hover color to a transparent color 2025-09-06 21:21:43 +03:00
Adorian Doran
2a7fc8edb6 style/background effects: extract color overrides as theme variables 2025-09-06 21:13:09 +03:00
Adorian Doran
25698f5d9b electron app: display the smooth scrolling setting only on the Electron app 2025-09-06 19:31:45 +03:00
Adorian Doran
c729731c7e electron app: mention that a restart is required for the smooth scrolling setting to take effect 2025-09-06 19:24:32 +03:00
Adorian Doran
dcc2f28079 electron app: add Romanian translation 2025-09-06 19:05:20 +03:00
Adorian Doran
97aa00e18b electron app: add an option to disable smooth scrolling 2025-09-06 19:00:45 +03:00
Elian Doran
5d8f789791 fix(desktop): background effects causing issues on Win10 2025-09-06 17:47:13 +03:00
Elian Doran
4faabb7770 Translations update from Hosted Weblate (#6911) 2025-09-06 17:34:54 +03:00
donut
8f9b3df681 Translated using Weblate (Polish)
Currently translated at 37.3% (141 of 378 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/pl/
2025-09-06 14:08:09 +00:00
Mik Piet
449575e0f7 Translated using Weblate (Polish)
Currently translated at 7.3% (115 of 1566 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-09-06 14:08:08 +00:00
donut
b7d47779d6 Translated using Weblate (Polish)
Currently translated at 7.3% (115 of 1566 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-09-06 14:08:08 +00:00
Elian Doran
fe443c8a89 fix(next): window border cut-off on macOS 2025-09-06 17:07:56 +03:00
perf3ct
3bf1a77381 feat(docs): also deploy docs upon README change 2025-09-05 19:52:03 +00:00
perf3ct
c4d430c62d feat(docs): use readme as index.md in mkdocs deployment 2025-09-05 19:40:59 +00:00
perf3ct
d583ee2de3 feat(docs): just remove the other language READMEs from the hide list 2025-09-05 19:34:54 +00:00
perf3ct
406a381ef4 feat(docs): try to continue fixing the links in the mkdocs 2025-09-05 19:18:14 +00:00
Elian Doran
1d82308c43 feat(docs): create docs.triliumnotes.org as additional place to serve user-facing docs (#6889) 2025-09-05 21:49:36 +03:00
perf3ct
5c1595b1fd feat(docs): remove unused python 2025-09-05 15:15:12 +00:00
perf3ct
667cfb999b feat(docs): oops forgot to add it to the package.json 2025-09-05 15:11:48 +00:00
perf3ct
9b0e817635 feat(docs): transition from python to ts 2025-09-05 15:09:27 +00:00
SiriusXT
7f3c34178b fix: add left-click check for tree button handlers 2025-09-05 19:32:42 +08:00
perf3ct
e8ca443697 feat(docs): try to fix local doc links 2025-09-04 22:16:43 -07:00
perf3ct
94089113ef feat(docs): try to handle moved files too in script 2025-09-04 21:55:28 -07:00
perf3ct
1847fc2060 feat(docs): fix nav and scripts 2025-09-04 23:50:22 +00:00
perf3ct
7ca21b52a0 feat(docs): fix references to zadam 2025-09-04 23:46:50 +00:00
perf3ct
444beb4908 feat(docs): get images to work now 2025-09-04 23:39:40 +00:00
perf3ct
791869ca9e feat(docs): try to capture all pages 2025-09-04 23:30:20 +00:00
perf3ct
33c8406b8a feat(docs): try to make pnpm happy for mkdocs
asfd

asdf
2025-09-04 21:57:26 +00:00
perf3ct
b6212c4e98 feat(docs): try to get wrangler to work...
feat(docs)asdf

asdf
2025-09-04 21:32:32 +00:00
perf3ct
fcd2409ee3 feat(docs): try to get mkdocs to work again 2025-09-04 21:20:01 +00:00
perf3ct
dad060d0c9 feat(docs): let's try to deploy our stuff to mkdocs 2025-09-04 21:13:12 +00:00
SiriusXT
5e572a8c6a fix: remove unnecessary line breaks 2025-09-04 22:07:04 +08:00
SiriusXT
c60c738c7e feat: show source diff between note and revision 2025-09-04 21:34:13 +08:00
SiriusXT
1c451fb98a fix: adapt diff highlight for dark theme 2025-09-04 18:47:14 +08:00
SiriusXT
7eeb43a83b Merge branch 'main' into history_diff 2025-09-04 17:37:00 +08:00
SiriusXT
fa2188f087 fix: improve <pre> tag regex handling when formatting HTML strings 2025-09-04 17:36:19 +08:00
Elian Doran
df1b87e3ac chore(dx/nix): fix flake partially 2025-09-04 12:12:23 +03:00
Elian Doran
62a0a44049 chore(dx): have electron-rebuild read from path on NixOS too 2025-09-04 09:26:16 +03:00
SiriusXT
0ae25d2212 feat: show source diff between note and revision 2025-09-04 10:53:46 +08:00
Elian Doran
88aa76bcab Improve development experience (#6842) 2025-09-03 22:13:17 +03:00
Elian Doran
401120fa28 Merge remote-tracking branch 'origin/main' into feature/dx_improvement 2025-09-03 21:24:51 +03:00
Elian Doran
534113b303 fix(dx/share): ckcontent for share theme not preserved 2025-09-03 21:09:56 +03:00
Elian Doran
53df7835d3 Revert "chore(dx/server): remove dependency on CKEditor for now"
This reverts commit 4739e2e3b2.
2025-09-03 20:24:23 +03:00
Elian Doran
ee9afb7fa0 fix(next): 1px border on tab when background effects are on 2025-09-03 20:09:19 +03:00
Elian Doran
6163ab8c42 refactor(dx): remove unused .env files 2025-09-03 20:08:29 +03:00
Elian Doran
e73724a576 chore(dx/desktop): integrate e2e tests in same project 2025-09-03 20:08:17 +03:00
Elian Doran
e71284d887 chore(dx): get rid of references to NX 2025-09-03 18:23:47 +03:00
Elian Doran
11d95b89e1 chore(dx/edit-docs): de-nxify 2025-09-03 18:16:03 +03:00
Elian Doran
ee7052ebc2 chore(deps): update dependency dotenv to v17.2.2 (#6876) 2025-09-03 18:02:23 +03:00
renovate[bot]
9059642738 chore(deps): update dependency dotenv to v17.2.2 2025-09-03 14:14:24 +00:00
Elian Doran
fe8e3b4489 chore(deps): update svelte monorepo (#6874) 2025-09-03 17:11:58 +03:00
Elian Doran
4e00e5b995 chore(deps): update dependency dotenv to v17.2.2 (#6875) 2025-09-03 17:11:45 +03:00
Elian Doran
05ae0ca9d7 chore(deps): update dependency @anthropic-ai/sdk to v0.61.0 (#6877) 2025-09-03 17:11:38 +03:00
Elian Doran
ac0116109b chore(deps): update typescript-eslint monorepo to v8.42.0 (#6878) 2025-09-03 17:11:28 +03:00
renovate[bot]
710ed9dd0e chore(deps): update svelte monorepo 2025-09-03 12:45:44 +00:00
Elian Doran
c75d2435fa fix(dx/share): ckcontent missing 2025-09-03 15:23:32 +03:00
Elian Doran
050aa40e20 fix(dx/share): templates and script not accessible 2025-09-03 12:12:01 +03:00
Elian Doran
cb6d87302d fix(dx/client): doc notes not working 2025-09-03 12:00:06 +03:00
Elian Doran
f9e725bcf8 chore(dx): add aliases to desktop 2025-09-03 11:56:44 +03:00
Elian Doran
a56d622df7 chore(dx): address self-review 2025-09-03 10:55:40 +03:00
Adorian Doran
267f5105b2 Theme tweaks (#6832) 2025-09-03 10:53:57 +03:00
SiriusXT
4e2ffad70d Merge branch 'main' into siriusxt_split 2025-09-03 14:05:08 +08:00
Elian Doran
7db3bde933 chore(e2e): merge .env in playwright config + add retry 2025-09-03 09:02:10 +03:00
Adorian Doran
a9564f8f38 style/launchbar buttons: fix broken hover state when background effects are enabled 2025-09-03 05:25:26 +03:00
Adorian Doran
9c5a130ab4 style/text editor/forms: restyle text areas 2025-09-03 04:38:37 +03:00
Adorian Doran
c40398df5d style/text editor/forms: tweak text boxes 2025-09-03 04:29:02 +03:00
Adorian Doran
27fdd9e715 style/text editor/find and replace: add style for the "replace" buttons 2025-09-03 04:13:29 +03:00
renovate[bot]
59697095b1 chore(deps): update typescript-eslint monorepo to v8.42.0 2025-09-03 00:40:09 +00:00
renovate[bot]
a16f5f5505 chore(deps): update dependency @anthropic-ai/sdk to v0.61.0 2025-09-03 00:38:49 +00:00
renovate[bot]
922d484a33 chore(deps): update dependency dotenv to v17.2.2 2025-09-03 00:37:18 +00:00
Elian Doran
f63f24ac9d feat(server/e2e): upload test report if it fails 2025-09-02 22:51:57 +03:00
Elian Doran
e7521fe30c chore(server/e2e): increase timeout of a flaky test 2025-09-02 22:30:09 +03:00
Elian Doran
f6579ac434 fix(e2e/server): data dir not working 2025-09-02 21:45:59 +03:00
Elian Doran
e1b4a0b720 fix(deps): update dependency @codemirror/view to v6.38.2 (#6860) 2025-09-02 21:33:12 +03:00
Elian Doran
9c43d661be fix(desktop): forge building for the wrong arch 2025-09-02 21:13:32 +03:00
Elian Doran
d2d8bff9f7 fix(e2e/server): wrong database dir 2025-09-02 21:06:41 +03:00
Elian Doran
a1beb13094 chore(ci): add logs for electron-forge flatpak build 2025-09-02 20:46:44 +03:00
Elian Doran
37d66848d6 Merge remote-tracking branch 'origin/main' into feature/dx_improvement
; Conflicts:
;	pnpm-lock.yaml
2025-09-02 20:43:43 +03:00
Elian Doran
991399fe4f Merge branch 'main' into renovate/codemirror 2025-09-02 20:41:41 +03:00
Elian Doran
27855456a0 chore(deps): update dependency lint-staged to v16.1.6 (#6856) 2025-09-02 20:40:55 +03:00
Elian Doran
0687ed9ec4 chore(deps): update dependency typedoc to v0.28.12 (#6857) 2025-09-02 20:40:42 +03:00
Elian Doran
632976e71f chore(deps): update pnpm to v10.15.1 (#6859) 2025-09-02 20:40:25 +03:00
Elian Doran
98addef614 fix(deps): update dependency dayjs to v1.11.18 (#6861) 2025-09-02 20:40:10 +03:00
Elian Doran
c72c9934b5 fix(deps): update dependency react-i18next to v15.7.3 (#6862) 2025-09-02 20:39:54 +03:00
Elian Doran
6362f24ae9 chore(deps): update dependency @stylistic/eslint-plugin to v5.3.1 (#6863) 2025-09-02 20:39:41 +03:00
Elian Doran
dc2d2fe25b chore(deps): update dependency vite to v7.1.4 (#6858) 2025-09-02 20:39:20 +03:00
renovate[bot]
bbc007e6cf chore(deps): update dependency vite to v7.1.4 2025-09-02 17:36:12 +00:00
Elian Doran
3dfd195630 chore(deps): update dependency @sveltejs/kit to v2.37.0 (#6864) 2025-09-02 20:34:24 +03:00
Elian Doran
e3f72baab3 chore(deps): update node.js to v22.19.0 (#6865) 2025-09-02 20:33:23 +03:00
Elian Doran
1bb19d0d9e Translations update from Hosted Weblate (#6871) 2025-09-02 20:31:45 +03:00
Микола Копитін
bc1b69a836 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1566 of 1566 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/uk/
2025-09-02 17:03:22 +00:00
Elian Doran
26c7f0b017 feat(dx/desktop): improve rebuilding experience on NixOS 2025-09-02 19:56:27 +03:00
Elian Doran
d058dbe9af chore(dx/desktop): clean up env 2025-09-02 19:56:18 +03:00
Elian Doran
c1c237402a chore(dx/desktop): clean up package.json 2025-09-02 19:49:36 +03:00
Elian Doran
bb20de6c24 chore(dx/env): remove unnecessary nx config 2025-09-02 19:44:38 +03:00
Elian Doran
8d7af7b01d chore(dx/server): de-nxify 2025-09-02 19:44:28 +03:00
Elian Doran
fd1c122cd4 chore(dx/apps): build db-compare & dump-db 2025-09-02 19:29:38 +03:00
Elian Doran
3925ba3eef chore(dx/ci): fix sequential/parallel tests 2025-09-02 19:16:49 +03:00
Elian Doran
4306072ca7 chore(dx/ci): sequential/parallel tests 2025-09-02 19:09:45 +03:00
Elian Doran
15fba23ad7 chore(dx/ci): denx-ify playwright 2025-09-02 19:00:49 +03:00
Elian Doran
04753226e5 chore(dx/ci): fix package command 2025-09-02 18:42:30 +03:00
Elian Doran
3fda97a9bd chore(dx/client): allocate more memory for the build 2025-09-02 18:38:50 +03:00
Elian Doran
26afdd105f chore(dx/server): get tests to run 2025-09-02 18:33:22 +03:00
Elian Doran
7c50251c37 chore(dx): clean up global package.json 2025-09-02 18:32:03 +03:00
Elian Doran
3de9d07769 chore: update lock 2025-09-02 17:54:05 +03:00
Elian Doran
d60899e362 chore(dx): remove unnecessary nx configs 2025-09-02 17:43:32 +03:00
Elian Doran
7c8019ac5b chore(dx/ci): get rid of nx-specific workflows 2025-09-02 17:38:24 +03:00
Elian Doran
1258d0cf7d chore(dx/desktop): read electron version from package.json 2025-09-02 17:37:57 +03:00
SiriusXT
2264369e9e feat: Make splits resizable 2025-09-02 22:05:26 +08:00
Elian Doran
e18a8556c1 chore(dx/ci): remove most references to NX, apart from unit test 2025-09-02 16:40:52 +03:00
SiriusXT
5436011f8e feat: Make splits resizable 2025-09-02 20:17:01 +08:00
Elian Doran
ce0fd3cec2 chore(dx/desktop): get forge to run 2025-09-02 13:59:09 +03:00
Elian Doran
bd349f5abc feat(dx/desktop): support raw NixOS via LD_LIBRARY_PATH injection 2025-09-02 12:18:22 +03:00
Elian Doran
7fdea613ff feat(dx/desktop): perfect way to override bettersqlite native 2025-09-02 11:50:58 +03:00
Elian Doran
16beeb2e88 fix(dx): broken imports after changing hoisting 2025-09-02 11:03:24 +03:00
Elian Doran
ae74f8ea83 feat(dx/desktop): isolate node_modules dependency 2025-09-02 10:45:42 +03:00
SiriusXT
88b748e67b Merge branch 'main' into siriusxt_split 2025-09-02 09:36:06 +08:00
SiriusXT
3254069999 feat: Make splits resizable 2025-09-02 09:28:53 +08:00
renovate[bot]
0bfa9f0c58 chore(deps): update node.js to v22.19.0 2025-09-02 01:18:18 +00:00
renovate[bot]
498ffa806d chore(deps): update dependency @sveltejs/kit to v2.37.0 2025-09-02 01:18:13 +00:00
renovate[bot]
9bfed2a80d chore(deps): update dependency @stylistic/eslint-plugin to v5.3.1 2025-09-02 01:17:37 +00:00
renovate[bot]
ec902c5762 fix(deps): update dependency react-i18next to v15.7.3 2025-09-02 01:17:32 +00:00
renovate[bot]
bb1d31f877 fix(deps): update dependency dayjs to v1.11.18 2025-09-02 01:16:58 +00:00
renovate[bot]
09f938fb72 fix(deps): update dependency @codemirror/view to v6.38.2 2025-09-02 01:16:21 +00:00
renovate[bot]
a3e9192998 chore(deps): update pnpm to v10.15.1 2025-09-02 01:15:40 +00:00
renovate[bot]
80b7c0b4c9 chore(deps): update dependency typedoc to v0.28.12 2025-09-02 01:14:46 +00:00
renovate[bot]
f01d6938f3 chore(deps): update dependency lint-staged to v16.1.6 2025-09-02 01:14:40 +00:00
Adorian Doran
ab95d707a3 style/text editor/forms: refactor 2025-09-02 02:43:11 +03:00
Adorian Doran
6475b4029a style/text editor/forms: restyle number inputs 2025-09-02 02:42:05 +03:00
Adorian Doran
f646b3dc5c style/text editor/color selector dropdown: fix layout 2025-09-02 02:14:43 +03:00
Adorian Doran
bcef0802e4 style/text editor/insert emoji flyout: fix the spacing of the skin tone dropdown items 2025-09-02 02:08:04 +03:00
Adorian Doran
47099cc77b style/text editor/insert math flyout: fix layout 2025-09-02 02:03:49 +03:00
Elian Doran
793102f3ad chore(dx/electron): fix tray icons 2025-09-01 22:55:53 +03:00
Elian Doran
6f29bdf355 chore(dx/electron): different window icon 2025-09-01 22:25:06 +03:00
Elian Doran
edf53c8a0f chore(dx/desktop): configure dev & start-prod 2025-09-01 21:16:10 +03:00
Elian Doran
24859e33c1 chore(dx/desktop): generate prod package.json 2025-09-01 21:15:44 +03:00
Elian Doran
ebcf4315f7 chore(dx/desktop): remote main not working in dist build 2025-09-01 21:15:17 +03:00
Elian Doran
135e2bb10e chore(dx/desktop): get prod build 2025-09-01 20:50:22 +03:00
Elian Doran
72a256eccf refactor(dx/server): simplify build script even further 2025-09-01 20:29:34 +03:00
Elian Doran
1e991c0526 refactor(dx/server): extract basic build commands to separate file 2025-09-01 19:36:14 +03:00
Elian Doran
978e6b9dde chore(dx/server): unnecessary import 2025-09-01 19:22:46 +03:00
perf3ct
a2acb3cbb7 fix(shortcuts): try to fix ime composition checks 2025-09-01 16:21:58 +00:00
Papierkorb2292
623fcce3d1 Also update note context in other note context events in note wrapper so it works with tabs 2025-09-01 11:33:15 +02:00
Papierkorb2292
c99ef4a549 Make note wrapper widget aware of note context on mobile 2025-09-01 11:01:29 +02:00
Papierkorb2292
c629ce6ef8 Add note wrapper widget in mobile_layout.tsx 2025-09-01 11:01:08 +02:00
Elian Doran
35743de0df fix(dx/client): client not starting due to duplicate config 2025-09-01 11:53:17 +03:00
Elian Doran
5cf182cf98 fix(dx/client): not serving Vite due to NODE_ENV 2025-09-01 11:50:41 +03:00
Elian Doran
01022546e8 fix(dx/client): insert math not working due to icon import 2025-09-01 11:33:18 +03:00
Elian Doran
83be42f4ea Translations update from Hosted Weblate (#6843) 2025-09-01 09:10:52 +03:00
Mik Piet
ab9fec0186 Translated using Weblate (Polish)
Currently translated at 7.0% (111 of 1566 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pl/
2025-09-01 06:02:00 +02:00
Flowerlywind
c6dd32ea7b Translated using Weblate (Vietnamese)
Currently translated at 2.5% (40 of 1566 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/vi/
2025-09-01 06:01:58 +02:00
Kuzma Simonov
1d4cd538ac Translated using Weblate (Russian)
Currently translated at 100.0% (1566 of 1566 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ru/
2025-09-01 06:01:57 +02:00
rodrigomescua
dc99f725f9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (1566 of 1566 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/pt_BR/
2025-09-01 06:01:55 +02:00
Newcomer1989
2f804f3eac Translated using Weblate (German)
Currently translated at 100.0% (1566 of 1566 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/de/
2025-09-01 06:01:54 +02:00
Elian Doran
4b9688af04 chore(dx/server): minify output 2025-08-31 23:19:07 +03:00
Elian Doran
897b896c11 chore(dx/server): fix vite interfering in production 2025-08-31 23:12:52 +03:00
Elian Doran
3600b46824 chore(dx/server): fix missing path to client 2025-08-31 23:04:18 +03:00
Elian Doran
9266fe63b9 chore(dx/client): disable share CSS for now 2025-08-31 23:03:38 +03:00
Elian Doran
a3ea52968f chore(dx/client): fix codemirror dep 2025-08-31 23:03:30 +03:00
Elian Doran
a06f2aeb8b chore(dx/server): trigger build of client & copy artifacts 2025-08-31 23:03:21 +03:00
Elian Doran
f4a56d4e19 chore(dx/client): get vite build to work 2025-08-31 23:02:41 +03:00
Elian Doran
f3f7ff5622 chore(dx/server): copy share templates when building 2025-08-31 22:48:50 +03:00
Elian Doran
dbf016adaf chore(dx/server): build all entrypoints with right ext 2025-08-31 22:43:21 +03:00
Elian Doran
0e5108bd08 chore(dx/server): start building & copying assets 2025-08-31 22:30:07 +03:00
Elian Doran
cf1180faa9 chore(dx/server): remove babel compacting for tiny gain in perf 2025-08-31 21:05:23 +03:00
Elian Doran
1b25275b2e fix(dx/electron): web contents not working 2025-08-31 20:43:48 +03:00
Elian Doran
886c694db7 chore(dx/server): update server:start command 2025-08-31 20:43:33 +03:00
Elian Doran
3d38a2aa14 chore(dx/desktop): get dev mode for Electron 2025-08-31 20:43:20 +03:00
Elian Doran
51d879ba6f style(client): toast sometimes going out of bounds 2025-08-31 20:42:46 +03:00
Elian Doran
91ae9d75f7 Revert "chore(dx/server): improve asset management for DB init"
This reverts commit 42559364e4.
2025-08-31 20:31:51 +03:00
Elian Doran
42559364e4 chore(dx/server): improve asset management for DB init 2025-08-31 20:28:21 +03:00
Elian Doran
9d6bb306e7 fix(electron): history navigation context menu not working 2025-08-31 19:39:54 +03:00
Elian Doran
c92860ae49 chore(dx/client): fix error when optimizing premium plugins 2025-08-31 19:27:05 +03:00
Elian Doran
b012624b67 chore(dx/client): fix emoji import error 2025-08-31 19:26:56 +03:00
Elian Doran
5f1d2f02ee chore(dx/client): fix SVG icons causing errors in CKEditor 2025-08-31 19:26:47 +03:00
Elian Doran
46cb869237 chore(dx/server): client paths not correct 2025-08-31 19:21:36 +03:00
Elian Doran
054c497678 chore(dx/client): improve startup speed by properly configuring middleware 2025-08-31 18:57:31 +03:00
Elian Doran
8362424976 chore(dx/client): fix highlightjs not working 2025-08-31 18:52:52 +03:00
Elian Doran
f7a0dc00e8 chore(dx/client): fix bootstrap CSS imports 2025-08-31 18:52:22 +03:00
Elian Doran
e49c4655a6 chore(dx/client): ckeditor5 CSS imports 2025-08-31 18:51:18 +03:00
Elian Doran
1dcb3b1529 chore(dx/server): set up cache for Vite 2025-08-31 18:28:20 +03:00
Elian Doran
cc474f39d8 chore(dx/server): basic middleware integration for vite 2025-08-31 18:24:02 +03:00
Elian Doran
113d36f5dd chore(dx/client): set paths for client dependencies 2025-08-31 18:19:03 +03:00
Elian Doran
63c0841c32 chore(dx/server): get server to run up to missing public server 2025-08-31 16:58:57 +03:00
Elian Doran
4739e2e3b2 chore(dx/server): remove dependency on CKEditor for now 2025-08-31 16:52:32 +03:00
Elian Doran
aa316091e6 chore(dx): fix cannot read properties of undefined if DB dir is missing 2025-08-31 16:41:03 +03:00
Elian Doran
2297721228 chore(dx): get rid of nx 2025-08-31 16:36:55 +03:00
Adorian Doran
03ab912495 style/text editor/forms: tweak buttons 2025-08-31 03:33:30 +03:00
Adorian Doran
d12dfabd0b style/text editor/forms: various layout fixes 2025-08-31 03:19:33 +03:00
Adorian Doran
ed748bbebd style/text editor/forms: restyle dropdowns 2025-08-31 02:58:53 +03:00
Adorian Doran
e85858d22d style/text editor/forms: fix visible focus for buttons 2025-08-31 02:30:13 +03:00
Adorian Doran
0afa9717e5 style/text editor/forms: restyle buttons 2025-08-31 02:28:24 +03:00
Adorian Doran
1e2e3498c6 style/text editor/forms: restyle text boxes 2025-08-31 01:45:12 +03:00
Adorian Doran
fcb77360e1 style/text editor/text alignment dropdown: use a horizontal toolbar instead of a vertical one 2025-08-30 19:22:27 +03:00
Adorian Doran
3d285e105e style/text editor/insert text snippet dropdown: tweak appearance 2025-08-30 18:25:44 +03:00
Adorian Doran
a94cc5bdab style/text editor/insert text snippet dropdown: tweak appearance 2025-08-30 02:55:23 +03:00
Adorian Doran
526c5a6dd8 Merge branch 'main' of https://github.com/TriliumNext/Trilium into feat/theme/improvements 2025-08-30 01:06:02 +03:00
Adorian Doran
7d3a672b55 style/toasts: prevent long text from overflowing 2025-08-29 21:36:09 +03:00
Adorian Doran
c08b30a060 style/text editor: hide icons from the text snippets dropdown 2025-08-29 21:30:04 +03:00
Adorian Doran
b147d4bdeb style: brighten the border of dropdowns 2025-08-29 21:17:43 +03:00
Adorian Doran
48faa8a813 client/quick search results: tweak the busy indicator 2025-08-29 21:06:48 +03:00
Adorian Doran
d73e84ea6c client/quick search results: tweak icon alignment 2025-08-29 18:37:02 +03:00
Adorian Doran
9464667323 client/quick search results: remove deprecated styles 2025-08-29 17:12:52 +03:00
Adorian Doran
4d82f2f22d client/quick search results: tweak footer divider margins 2025-08-29 17:11:10 +03:00
Adorian Doran
e3d28e703f client/quick search results: tweak snippet background color 2025-08-29 17:01:08 +03:00
Adorian Doran
5f39a314b5 client/quick search results: fix overflowing snippets 2025-08-29 16:58:13 +03:00
Adorian Doran
43caadc472 client/quick search results: refactor the item delimiter line 2025-08-29 16:57:02 +03:00
166 changed files with 5337 additions and 7997 deletions

1
.env
View File

@@ -1 +0,0 @@
NODE_OPTIONS=--max_old_space_size=4096

View File

@@ -86,7 +86,7 @@ runs:
APPLE_ID_PASSWORD: ${{ env.APPLE_ID_PASSWORD }}
WINDOWS_SIGN_EXECUTABLE: ${{ env.WINDOWS_SIGN_EXECUTABLE }}
TRILIUM_ARTIFACT_NAME_HINT: TriliumNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}
run: pnpm nx --project=desktop electron-forge:make -- --arch=${{ inputs.arch }} --platform=${{ inputs.forge_platform }}
run: pnpm run --filter desktop electron-forge:make --arch=${{ inputs.arch }} --platform=${{ inputs.forge_platform }}
# Add DMG signing step
- name: Sign DMG

View File

@@ -10,7 +10,7 @@ runs:
steps:
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version: 22
cache: "pnpm"
@@ -23,7 +23,7 @@ runs:
shell: bash
run: |
pnpm run chore:update-build-info
pnpm nx --project=server package
pnpm run --filter server package
- name: Prepare artifacts
shell: bash
run: |

190
.github/workflows/deploy-docs.yml vendored Normal file
View File

@@ -0,0 +1,190 @@
# GitHub Actions workflow for deploying MkDocs documentation to Cloudflare Pages
# This workflow builds and deploys your MkDocs site when changes are pushed to main
name: Deploy MkDocs Documentation
on:
# Trigger on push to main branch
push:
branches:
- main
- master # Also support master branch
# Only run when docs files change
paths:
- 'docs/**'
- 'README.md' # README is synced to docs/index.md
- 'mkdocs.yml'
- 'requirements-docs.txt'
- '.github/workflows/deploy-docs.yml'
- 'scripts/fix-mkdocs-structure.ts'
- 'validate-docs-links.ts'
# Allow manual triggering from Actions tab
workflow_dispatch:
# Run on pull requests for preview deployments
pull_request:
branches:
- main
- master
paths:
- 'docs/**'
- 'README.md' # README is synced to docs/index.md
- 'mkdocs.yml'
- 'requirements-docs.txt'
- '.github/workflows/deploy-docs.yml'
- 'scripts/fix-mkdocs-structure.ts'
- 'validate-docs-links.ts'
jobs:
build-and-deploy:
name: Build and Deploy MkDocs
runs-on: ubuntu-latest
timeout-minutes: 10
# Required permissions for deployment
permissions:
contents: read
deployments: write
pull-requests: write # For PR preview comments
id-token: write # For OIDC authentication (if needed)
steps:
- name: Checkout Repository
uses: actions/checkout@v5
with:
fetch-depth: 0 # Fetch all history for git info and mkdocs-git-revision-date plugin
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.13'
cache: 'pip'
cache-dependency-path: 'requirements-docs.txt'
- name: Install MkDocs and Dependencies
run: |
pip install --upgrade pip
pip install -r requirements-docs.txt
env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
# Setup pnpm before fixing docs structure
- name: Setup pnpm
uses: pnpm/action-setup@v4
# Setup Node.js with pnpm
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: '22'
cache: 'pnpm'
# Install Node.js dependencies for the TypeScript script
- name: Install Dependencies
run: |
pnpm install --frozen-lockfile
- name: Fix Documentation Structure
run: |
# Fix duplicate navigation entries by moving overview pages to index.md
pnpm run chore:fix-mkdocs-structure
- name: Build MkDocs Site
run: |
# Build with strict mode but allow expected warnings
mkdocs build --verbose || {
EXIT_CODE=$?
# Check if the only issue is expected warnings
if mkdocs build 2>&1 | grep -E "WARNING.*(README|not found)" && \
[ $(mkdocs build 2>&1 | grep -c "ERROR") -eq 0 ]; then
echo "✅ Build succeeded with expected warnings"
mkdocs build --verbose
else
echo "❌ Build failed with unexpected errors"
exit $EXIT_CODE
fi
}
- name: Validate Built Site
run: |
# Basic validation that important files exist
test -f site/index.html || (echo "ERROR: site/index.html not found" && exit 1)
test -f site/sitemap.xml || (echo "ERROR: site/sitemap.xml not found" && exit 1)
test -d site/assets || (echo "ERROR: site/assets directory not found" && exit 1)
echo "✅ Site validation passed"
- name: Validate Documentation Links
run: |
# Run the TypeScript link validation script
pnpm tsx validate-docs-links.ts
# Install wrangler globally to avoid workspace issues
- name: Install Wrangler
run: |
npm install -g wrangler
# Deploy using Wrangler (use pre-installed wrangler)
- name: Deploy to Cloudflare Pages
id: deploy
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy site --project-name=trilium-docs --branch=${{ github.ref_name }}
wranglerVersion: '' # Use pre-installed version
# Deploy preview for PRs
- name: Deploy Preview to Cloudflare Pages
id: preview-deployment
if: github.event_name == 'pull_request'
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy site --project-name=trilium-docs --branch=pr-${{ github.event.pull_request.number }}
wranglerVersion: '' # Use pre-installed version
# Post deployment URL as PR comment
- name: Comment PR with Preview URL
if: github.event_name == 'pull_request'
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.issue.number;
// Construct preview URL based on Cloudflare Pages pattern
const previewUrl = `https://pr-${prNumber}.trilium-docs.pages.dev`;
const mainUrl = 'https://docs.triliumnotes.org';
// Check if we already commented
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const botComment = comments.data.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('Documentation preview is ready')
);
const commentBody = `📚 Documentation preview is ready!\n\n🔗 Preview URL: ${previewUrl}\n📖 Production URL: ${mainUrl}\n\n✅ All checks passed\n\n_This preview will be updated automatically with new commits._`;
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: commentBody
});
} else {
// Create new comment
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: commentBody
});
}

View File

@@ -19,45 +19,24 @@ permissions:
pull-requests: write # for PR comments
jobs:
check-affected:
name: Check affected jobs (NX)
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v5
with:
fetch-depth: 0 # needed for https://github.com/marketplace/actions/nx-set-shas
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- uses: nrwl/nx-set-shas@v4
- name: Check affected
run: pnpm nx affected --verbose -t typecheck build rebuild-deps test-build
test_dev:
name: Test development
runs-on: ubuntu-latest
needs:
- check-affected
steps:
- name: Checkout the repository
uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version: 22
cache: "pnpm"
- run: pnpm install --frozen-lockfile
- name: Typecheck
run: pnpm typecheck
- name: Run the unit tests
run: pnpm run test:all
@@ -66,7 +45,6 @@ jobs:
runs-on: ubuntu-latest
needs:
- test_dev
- check-affected
steps:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
@@ -75,7 +53,7 @@ jobs:
- name: Update build info
run: pnpm run chore:update-build-info
- name: Trigger client build
run: pnpm nx run client:build
run: pnpm client:build
- name: Send client bundle stats to RelativeCI
if: false
uses: relative-ci/agent-action@v3
@@ -83,7 +61,7 @@ jobs:
webpackStatsFile: ./apps/client/dist/webpack-stats.json
key: ${{ secrets.RELATIVE_CI_CLIENT_KEY }}
- name: Trigger server build
run: pnpm nx run server:build
run: pnpm run server:build
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
@@ -95,7 +73,6 @@ jobs:
runs-on: ubuntu-latest
needs:
- build_docker
- check-affected
strategy:
matrix:
include:
@@ -112,7 +89,7 @@ jobs:
- name: Update build info
run: pnpm run chore:update-build-info
- name: Trigger build
run: pnpm nx run server:build
run: pnpm server:build
- name: Set IMAGE_NAME to lowercase
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV

View File

@@ -44,7 +44,7 @@ jobs:
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version: 22
cache: "pnpm"
@@ -82,7 +82,7 @@ jobs:
require-healthy: true
- name: Run Playwright tests
run: TRILIUM_DOCKER=1 TRILIUM_PORT=8082 pnpm exec nx run server-e2e:e2e
run: TRILIUM_DOCKER=1 TRILIUM_PORT=8082 pnpm --filter=server-e2e e2e
- name: Upload Playwright trace
if: failure()
@@ -144,7 +144,7 @@ jobs:
uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version: 22
cache: 'pnpm'

View File

@@ -51,13 +51,12 @@ jobs:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version: 22
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- uses: nrwl/nx-set-shas@v4
- name: Update nightly version
run: npm run chore:ci-update-nightly-version
- name: Run the build
@@ -79,7 +78,7 @@ jobs:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
- name: Publish release
uses: softprops/action-gh-release@v2.3.2
uses: softprops/action-gh-release@v2.3.3
if: ${{ github.event_name != 'pull_request' }}
with:
make_latest: false
@@ -120,7 +119,7 @@ jobs:
arch: ${{ matrix.arch }}
- name: Publish release
uses: softprops/action-gh-release@v2.3.2
uses: softprops/action-gh-release@v2.3.3
if: ${{ github.event_name != 'pull_request' }}
with:
make_latest: false

View File

@@ -19,14 +19,8 @@ jobs:
filter: tree:0
fetch-depth: 0
# This enables task distribution via Nx Cloud
# Run this command as early as possible, before dependencies are installed
# Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun
# Connect your workspace by running "nx connect" and uncomment this line to enable task distribution
# - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="e2e-ci"
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v5
with:
node-version: 22
cache: 'pnpm'
@@ -34,10 +28,12 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
- run: pnpm exec playwright install --with-deps
- uses: nrwl/nx-set-shas@v4
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
# - run: npx nx-cloud record -- echo Hello World
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
# When you enable task distribution, run the e2e-ci task instead of e2e
- run: pnpm exec nx affected -t e2e --exclude desktop-e2e
- run: pnpm --filter server-e2e e2e
- name: Upload test report
if: failure()
uses: actions/upload-artifact@v4
with:
name: e2e report
path: apps/server-e2e/test-output

View File

@@ -35,13 +35,12 @@ jobs:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version: 22
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- uses: nrwl/nx-set-shas@v4
- name: Run the build
uses: ./.github/actions/build-electron
with:
@@ -115,7 +114,7 @@ jobs:
path: upload
- name: Publish stable release
uses: softprops/action-gh-release@v2.3.2
uses: softprops/action-gh-release@v2.3.3
with:
draft: false
body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md

13
.gitignore vendored
View File

@@ -1,6 +1,5 @@
# See https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
.github/instructions/nx.instructions.md
/.cache
# compiled output
dist
@@ -34,14 +33,11 @@ testem.log
.DS_Store
Thumbs.db
.nx/cache
.nx/workspace-data
vite.config.*.timestamp*
vitest.config.*.timestamp*
test-output
apps/*/data
apps/*/data*
apps/*/out
upload
@@ -49,4 +45,7 @@ upload
*.tsbuildinfo
/result
.svelte-kit
.svelte-kit
# docs
site/

2
.nvmrc
View File

@@ -1 +1 @@
22.18.0
22.19.0

View File

@@ -5,7 +5,6 @@
"lokalise.i18n-ally",
"ms-azuretools.vscode-docker",
"ms-playwright.playwright",
"nrwl.angular-console",
"redhat.vscode-yaml",
"tobermory.es6-string-html",
"vitest.explorer",

View File

@@ -35,6 +35,5 @@
"docs/**/*.png": true,
"apps/server/src/assets/doc_notes/**": true,
"apps/edit-docs/demo/**": true
},
"nxConsole.generateAiAgentRules": true
}
}

View File

@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Overview
Trilium Notes is a hierarchical note-taking application with advanced features like synchronization, scripting, and rich text editing. It's built as a TypeScript monorepo using NX, with multiple applications and shared packages.
Trilium Notes is a hierarchical note-taking application with advanced features like synchronization, scripting, and rich text editing. It's built as a TypeScript monorepo using pnpm, with multiple applications and shared packages.
## Development Commands
@@ -14,12 +14,9 @@ Trilium Notes is a hierarchical note-taking application with advanced features l
### Running Applications
- `pnpm run server:start` - Start development server (http://localhost:8080)
- `pnpm nx run server:serve` - Alternative server start command
- `pnpm nx run desktop:serve` - Run desktop Electron app
- `pnpm run server:start-prod` - Run server in production mode
### Building
- `pnpm nx build <project>` - Build specific project (server, client, desktop, etc.)
- `pnpm run client:build` - Build client application
- `pnpm run server:build` - Build server application
- `pnpm run electron:build` - Build desktop application
@@ -28,13 +25,8 @@ Trilium Notes is a hierarchical note-taking application with advanced features l
- `pnpm test:all` - Run all tests (parallel + sequential)
- `pnpm test:parallel` - Run tests that can run in parallel
- `pnpm test:sequential` - Run tests that must run sequentially (server, ckeditor5-mermaid, ckeditor5-math)
- `pnpm nx test <project>` - Run tests for specific project
- `pnpm coverage` - Generate coverage reports
### Linting & Type Checking
- `pnpm nx run <project>:lint` - Lint specific project
- `pnpm nx run <project>:typecheck` - Type check specific project
## Architecture Overview
### Monorepo Structure
@@ -94,7 +86,6 @@ Frontend uses a widget system (`apps/client/src/widgets/`):
- `apps/server/src/assets/db/schema.sql` - Core database structure
4. **Configuration**:
- `nx.json` - NX workspace configuration
- `package.json` - Project dependencies and scripts
## Note Types and Features
@@ -154,7 +145,7 @@ Trilium provides powerful user scripting capabilities:
- Update schema in `apps/server/src/assets/db/schema.sql`
## Build System Notes
- Uses NX for monorepo management with build caching
- Uses pnpm for monorepo management
- Vite for fast development builds
- ESBuild for production optimization
- pnpm workspaces for dependency management

View File

@@ -142,7 +142,7 @@ Download the repository, install dependencies using `pnpm` and then run the envi
git clone https://github.com/TriliumNext/Trilium.git
cd Trilium
pnpm install
pnpm nx run edit-docs:edit-docs
pnpm edit-docs:edit-docs
```
### Building the Executable
@@ -151,7 +151,7 @@ Download the repository, install dependencies using `pnpm` and then build the de
git clone https://github.com/TriliumNext/Trilium.git
cd Trilium
pnpm install
pnpm nx --project=desktop electron-forge:make -- --arch=x64 --platform=win32
pnpm run --filter desktop electron-forge:make --arch=x64 --platform=win32
```
For more details, see the [development docs](https://github.com/TriliumNext/Trilium/tree/main/docs/Developer%20Guide/Developer%20Guide).

View File

@@ -36,12 +36,12 @@
},
"devDependencies": {
"@playwright/test": "1.55.0",
"@stylistic/eslint-plugin": "5.2.3",
"@stylistic/eslint-plugin": "5.3.1",
"@types/express": "5.0.3",
"@types/node": "22.18.0",
"@types/node": "22.18.1",
"@types/yargs": "17.0.33",
"@vitest/coverage-v8": "3.2.4",
"eslint": "9.34.0",
"eslint": "9.35.0",
"eslint-plugin-simple-import-sort": "12.1.1",
"esm": "3.2.25",
"jsdoc": "4.0.4",
@@ -49,7 +49,7 @@
"rcedit": "4.0.1",
"rimraf": "6.0.1",
"tslib": "2.8.1",
"typedoc": "0.28.11",
"typedoc": "0.28.12",
"typedoc-plugin-missing-exports": "4.1.0"
},
"optionalDependencies": {

View File

@@ -9,8 +9,13 @@
"email": "contact@eliandoran.me",
"url": "https://github.com/TriliumNext/Notes"
},
"scripts": {
"build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 vite build",
"test": "vitest",
"circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
},
"dependencies": {
"@eslint/js": "9.34.0",
"@eslint/js": "9.35.0",
"@excalidraw/excalidraw": "0.18.0",
"@fullcalendar/core": "6.1.19",
"@fullcalendar/daygrid": "6.1.19",
@@ -19,7 +24,7 @@
"@fullcalendar/multimonth": "6.1.19",
"@fullcalendar/timegrid": "6.1.19",
"@maplibre/maplibre-gl-leaflet": "0.1.3",
"@mermaid-js/layout-elk": "0.1.9",
"@mermaid-js/layout-elk": "0.2.0",
"@mind-elixir/node-menu": "5.0.0",
"@popperjs/core": "2.11.8",
"@triliumnext/ckeditor5": "workspace:*",
@@ -30,13 +35,13 @@
"autocomplete.js": "0.38.1",
"bootstrap": "5.3.8",
"boxicons": "2.1.4",
"dayjs": "1.11.14",
"dayjs": "1.11.18",
"dayjs-plugin-utc": "0.1.2",
"debounce": "2.2.0",
"draggabilly": "3.0.0",
"force-graph": "1.50.1",
"force-graph": "1.51.0",
"globals": "16.3.0",
"i18next": "25.4.2",
"i18next": "25.5.2",
"i18next-http-backend": "3.0.2",
"jquery": "3.7.1",
"jquery.fancytree": "2.38.5",
@@ -47,12 +52,12 @@
"leaflet-gpx": "2.2.0",
"mark.js": "8.11.1",
"marked": "16.2.1",
"mermaid": "11.10.1",
"mind-elixir": "5.0.6",
"mermaid": "11.11.0",
"mind-elixir": "5.1.1",
"normalize.css": "8.0.1",
"panzoom": "9.4.3",
"preact": "10.27.1",
"react-i18next": "15.7.2",
"react-i18next": "15.7.3",
"split.js": "1.6.5",
"svg-pan-zoom": "3.6.2",
"tabulator-tables": "6.3.1",
@@ -64,23 +69,12 @@
"@types/bootstrap": "5.2.10",
"@types/jquery": "3.5.33",
"@types/leaflet": "1.9.20",
"@types/leaflet-gpx": "1.3.7",
"@types/leaflet-gpx": "1.3.8",
"@types/mark.js": "8.11.12",
"@types/tabulator-tables": "6.2.10",
"copy-webpack-plugin": "13.0.1",
"happy-dom": "18.0.1",
"script-loader": "0.7.2",
"vite-plugin-static-copy": "3.1.2"
},
"nx": {
"name": "client",
"targets": {
"serve": {
"dependsOn": []
},
"circular-deps": {
"command": "pnpx dpdm -T {projectRoot}/src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
}
}
}
}

View File

@@ -10,7 +10,7 @@ import { t } from "./services/i18n.js";
import options from "./services/options.js";
import type ElectronRemote from "@electron/remote";
import type Electron from "electron";
import "./stylesheets/bootstrap.scss";
import "bootstrap/dist/css/bootstrap.min.css";
import "boxicons/css/boxicons.min.css";
import "autocomplete.js/index_jquery.js";

View File

@@ -22,6 +22,7 @@ import FloatingButtons from "../widgets/FloatingButtons.jsx";
import { MOBILE_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
import ToggleSidebarButton from "../widgets/mobile_widgets/toggle_sidebar_button.jsx";
import CloseZenModeButton from "../widgets/close_zen_button.js";
import NoteWrapperWidget from "../widgets/note_wrapper.js";
import MobileDetailMenu from "../widgets/mobile_widgets/mobile_detail_menu.js";
const MOBILE_CSS = `
@@ -131,30 +132,33 @@ export default class MobileLayout {
.child(new FlexContainer("column").filling().id("mobile-sidebar-wrapper").child(new QuickSearchWidget()).child(new NoteTreeWidget().cssBlock(FANCYTREE_CSS)))
)
.child(
new ScreenContainer("detail", "column")
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 FlexContainer("row")
.contentSized()
.css("font-size", "larger")
.css("align-items", "center")
.child(<ToggleSidebarButton />)
.child(<NoteTitleWidget />)
.child(<MobileDetailMenu />)
new NoteWrapperWidget()
.child(
new FlexContainer("row")
.contentSized()
.css("font-size", "larger")
.css("align-items", "center")
.child(<ToggleSidebarButton />)
.child(<NoteTitleWidget />)
.child(<MobileDetailMenu />)
)
.child(<SharedInfoWidget />)
.child(<FloatingButtons items={MOBILE_FLOATING_BUTTONS} />)
.child(new PromotedAttributesWidget())
.child(
new ScrollingContainer()
.filling()
.contentSized()
.child(new NoteDetailWidget())
.child(new NoteListWidget(false))
.child(<FilePropertiesWrapper />)
)
.child(<MobileEditorToolbar />)
)
.child(<SharedInfoWidget />)
.child(<FloatingButtons items={MOBILE_FLOATING_BUTTONS} />)
.child(new PromotedAttributesWidget())
.child(
new ScrollingContainer()
.filling()
.contentSized()
.child(new NoteDetailWidget())
.child(new NoteListWidget(false))
.child(<FilePropertiesWrapper />)
)
.child(<MobileEditorToolbar />)
)
)
.child(

View File

@@ -1,4 +1,4 @@
import "./stylesheets/bootstrap.scss";
import "bootstrap/dist/css/bootstrap.min.css";
// @ts-ignore - module = undefined
// Required for correct loading of scripts in Electron

View File

@@ -1,7 +1,7 @@
import appContext from "./components/app_context.js";
import noteAutocompleteService from "./services/note_autocomplete.js";
import glob from "./services/glob.js";
import "./stylesheets/bootstrap.scss";
import "bootstrap/dist/css/bootstrap.min.css";
import "boxicons/css/boxicons.min.css";
import "autocomplete.js/index_jquery.js";

View File

@@ -48,6 +48,6 @@ function getUrl(docNameValue: string, language: string) {
// Cannot have spaces in the URL due to how JQuery.load works.
docNameValue = docNameValue.replaceAll(" ", "%20");
const basePath = window.glob.isDev ? new URL(window.glob.assetPath).pathname : window.glob.assetPath;
const basePath = window.glob.isDev ? window.glob.assetPath + "/.." : window.glob.assetPath;
return `${basePath}/doc_notes/${language}/${docNameValue}.html`;
}

View File

@@ -10,6 +10,10 @@ let leftInstance: ReturnType<typeof Split> | null;
let rightPaneWidth: number;
let rightInstance: ReturnType<typeof Split> | null;
const noteSplitMap = new Map<string[], ReturnType<typeof Split> | undefined>(); // key: a group of ntxIds, value: the corresponding Split instance
const noteSplitRafMap = new Map<string[], number>();
let splitNoteContainer: HTMLElement | undefined;
function setupLeftPaneResizer(leftPaneVisible: boolean) {
if (leftInstance) {
leftInstance.destroy();
@@ -83,7 +87,86 @@ function setupRightPaneResizer() {
}
}
function findKeyByNtxId(ntxId: string): string[] | undefined {
// Find the corresponding key in noteSplitMap based on ntxId
for (const key of noteSplitMap.keys()) {
if (key.includes(ntxId)) return key;
}
return undefined;
}
function setupNoteSplitResizer(ntxIds: string[]) {
let targetNtxIds: string[] | undefined;
for (const ntxId of ntxIds) {
targetNtxIds = findKeyByNtxId(ntxId);
if (targetNtxIds) break;
}
if (targetNtxIds) {
noteSplitMap.get(targetNtxIds)?.destroy();
for (const id of ntxIds) {
if (!targetNtxIds.includes(id)) {
targetNtxIds.push(id)
};
}
} else {
targetNtxIds = [...ntxIds];
}
noteSplitMap.set(targetNtxIds, undefined);
createSplitInstance(targetNtxIds);
}
function delNoteSplitResizer(ntxIds: string[]) {
let targetNtxIds = findKeyByNtxId(ntxIds[0]);
if (!targetNtxIds) {
return;
}
noteSplitMap.get(targetNtxIds)?.destroy();
noteSplitMap.delete(targetNtxIds);
targetNtxIds = targetNtxIds.filter(id => !ntxIds.includes(id));
if (targetNtxIds.length >= 2) {
noteSplitMap.set(targetNtxIds, undefined);
createSplitInstance(targetNtxIds);
}
}
function moveNoteSplitResizer(ntxId: string) {
const targetNtxIds = findKeyByNtxId(ntxId);
if (!targetNtxIds) {
return;
}
noteSplitMap.get(targetNtxIds)?.destroy();
noteSplitMap.set(targetNtxIds, undefined);
createSplitInstance(targetNtxIds);
}
function createSplitInstance(targetNtxIds: string[]) {
const prevRafId = noteSplitRafMap.get(targetNtxIds);
if (prevRafId) {
cancelAnimationFrame(prevRafId);
}
const rafId = requestAnimationFrame(() => {
splitNoteContainer = splitNoteContainer ?? $("#center-pane").find(".split-note-container-widget")[0];
const splitPanels = [...splitNoteContainer.querySelectorAll<HTMLElement>(':scope > .note-split')]
.filter(el => targetNtxIds.includes(el.getAttribute('data-ntx-id') ?? ""));
const splitInstance = Split(splitPanels, {
gutterSize: DEFAULT_GUTTER_SIZE,
minSize: 150,
});
noteSplitMap.set(targetNtxIds, splitInstance);
noteSplitRafMap.delete(targetNtxIds);
});
noteSplitRafMap.set(targetNtxIds, rafId);
}
export default {
setupLeftPaneResizer,
setupRightPaneResizer
setupRightPaneResizer,
setupNoteSplitResizer,
delNoteSplitResizer,
moveNoteSplitResizer
};

View File

@@ -1,5 +1,5 @@
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
import shortcuts, { keyMatches, matchesShortcut } from "./shortcuts.js";
import shortcuts, { keyMatches, matchesShortcut, isIMEComposing } from "./shortcuts.js";
// Mock utils module
vi.mock("./utils.js", () => ({
@@ -320,4 +320,36 @@ describe("shortcuts", () => {
expect(event.preventDefault).not.toHaveBeenCalled();
});
});
describe('isIMEComposing', () => {
it('should return true when event.isComposing is true', () => {
const event = { isComposing: true, keyCode: 65 } as KeyboardEvent;
expect(isIMEComposing(event)).toBe(true);
});
it('should return true when keyCode is 229', () => {
const event = { isComposing: false, keyCode: 229 } as KeyboardEvent;
expect(isIMEComposing(event)).toBe(true);
});
it('should return true when both isComposing is true and keyCode is 229', () => {
const event = { isComposing: true, keyCode: 229 } as KeyboardEvent;
expect(isIMEComposing(event)).toBe(true);
});
it('should return false for normal keys', () => {
const event = { isComposing: false, keyCode: 65 } as KeyboardEvent;
expect(isIMEComposing(event)).toBe(false);
});
it('should return false when isComposing is undefined and keyCode is not 229', () => {
const event = { keyCode: 13 } as KeyboardEvent;
expect(isIMEComposing(event)).toBe(false);
});
it('should handle null/undefined events gracefully', () => {
expect(isIMEComposing(null as any)).toBe(false);
expect(isIMEComposing(undefined as any)).toBe(false);
});
});
});

View File

@@ -40,6 +40,24 @@ for (let i = 1; i <= 19; i++) {
keyMap[`f${i}`] = [`F${i}`];
}
/**
* Check if IME (Input Method Editor) is composing
* This is used to prevent keyboard shortcuts from firing during IME composition
* @param e - The keyboard event to check
* @returns true if IME is currently composing, false otherwise
*/
export function isIMEComposing(e: KeyboardEvent): boolean {
// Handle null/undefined events gracefully
if (!e) {
return false;
}
// Standard check for composition state
// e.isComposing is true when IME is actively composing
// e.keyCode === 229 is a fallback for older browsers where 229 indicates IME processing
return e.isComposing || e.keyCode === 229;
}
function removeGlobalShortcut(namespace: string) {
bindGlobalShortcut("", null, namespace);
}
@@ -68,6 +86,13 @@ function bindElShortcut($el: JQuery<ElementType | Element>, keyboardShortcut: st
}
const e = evt as KeyboardEvent;
// Skip processing if IME is composing to prevent shortcuts from
// interfering with text input in CJK languages
if (isIMEComposing(e)) {
return;
}
if (matchesShortcut(e, keyboardShortcut)) {
e.preventDefault();
e.stopPropagation();

View File

@@ -297,6 +297,54 @@ function isHtmlEmpty(html: string) {
);
}
function formatHtml(html: string) {
let indent = "\n";
const tab = "\t";
let i = 0;
let pre: { indent: string; tag: string }[] = [];
html = html
.replace(new RegExp("<pre>([\\s\\S]+?)?</pre>"), function (x) {
pre.push({ indent: "", tag: x });
return "<--TEMPPRE" + i++ + "/-->";
})
.replace(new RegExp("<[^<>]+>[^<]?", "g"), function (x) {
let ret;
const tagRegEx = /<\/?([^\s/>]+)/.exec(x);
let tag = tagRegEx ? tagRegEx[1] : "";
let p = new RegExp("<--TEMPPRE(\\d+)/-->").exec(x);
if (p) {
const pInd = parseInt(p[1]);
pre[pInd].indent = indent;
}
if (["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr"].indexOf(tag) >= 0) {
// self closing tag
ret = indent + x;
} else {
if (x.indexOf("</") < 0) {
//open tag
if (x.charAt(x.length - 1) !== ">") ret = indent + x.substr(0, x.length - 1) + indent + tab + x.substr(x.length - 1, x.length);
else ret = indent + x;
!p && (indent += tab);
} else {
//close tag
indent = indent.substr(0, indent.length - 1);
if (x.charAt(x.length - 1) !== ">") ret = indent + x.substr(0, x.length - 1) + indent + x.substr(x.length - 1, x.length);
else ret = indent + x;
}
}
return ret;
});
for (i = pre.length; i--;) {
html = html.replace("<--TEMPPRE" + i + "/-->", pre[i].tag.replace("<pre>", "<pre>\n").replace("</pre>", pre[i].indent + "</pre>"));
}
return html.charAt(0) === "\n" ? html.substr(1, html.length - 1) : html;
}
export async function clearBrowserCache() {
if (isElectron()) {
const win = dynamicRequire("@electron/remote").getCurrentWindow();
@@ -855,6 +903,7 @@ export default {
getNoteTypeClass,
getMimeTypeClass,
isHtmlEmpty,
formatHtml,
clearBrowserCache,
copySelectionToClipboard,
dynamicRequire,

View File

@@ -1,4 +1,4 @@
import "./stylesheets/bootstrap.scss";
import "bootstrap/dist/css/bootstrap.min.css";
import "./stylesheets/auth.css";
// @TriliumNextTODO: is this even needed anymore?

View File

@@ -1,7 +1,7 @@
import "jquery";
import utils from "./services/utils.js";
import ko from "knockout";
import "./stylesheets/bootstrap.scss";
import "bootstrap/dist/css/bootstrap.min.css";
// TriliumNextTODO: properly make use of below types
// type SetupModelSetupType = "new-document" | "sync-from-desktop" | "sync-from-server" | "";

View File

@@ -1,6 +1,6 @@
import "normalize.css";
import "boxicons/css/boxicons.min.css";
import "@triliumnext/ckeditor5/content.css";
import "@triliumnext/ckeditor5/src/theme/ck-content.css";
import "@triliumnext/share-theme/styles/index.css";
import "@triliumnext/share-theme/scripts/index.js";

View File

@@ -1,2 +0,0 @@
/* Import all of Bootstrap's CSS */
@use "bootstrap/scss/bootstrap";

View File

@@ -1134,6 +1134,7 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
.toast-body {
white-space: preserve-breaks;
overflow: hidden;
}
.ck-mentions .ck-button {
@@ -1242,6 +1243,10 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
cursor: row-resize;
}
.hidden-ext.note-split + .gutter {
display: none;
}
#context-menu-cover.show {
position: fixed;
top: 0;
@@ -1463,7 +1468,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
cursor: pointer;
border: none;
color: var(--launcher-pane-text-color);
background-color: var(--launcher-pane-background-color);
background: transparent;
flex-shrink: 0;
}
@@ -1771,7 +1776,6 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
}
.note-split {
flex-basis: 0; /* so that each split has same width */
margin-left: auto;
margin-right: auto;
}
@@ -2366,3 +2370,21 @@ footer.webview-footer button {
content: "\ec24";
transform: rotate(180deg);
}
/* CK Edito */
/* Insert text snippet: limit the width of the listed items to avoid overly long names */
:root body.desktop div.ck-template-form li.ck-list__item .ck-template-form__text-part > span {
max-width: 25vw;
overflow: hidden;
text-overflow: ellipsis;
}
.revision-diff-added {
background: rgba(100, 200, 100, 0.5);
}
.revision-diff-removed {
background: rgba(255, 100, 100, 0.5);
text-decoration: line-through;
}

View File

@@ -13,12 +13,13 @@
--theme-style: dark;
--native-titlebar-background: #00000000;
--window-background-color-bgfx: transparent; /* When background effects enabled */
--main-background-color: #272727;
--main-text-color: #ccc;
--main-border-color: #454545;
--subtle-border-color: #313131;
--dropdown-border-color: #292929;
--dropdown-border-color: #404040;
--dropdown-shadow-opacity: 0.6;
--dropdown-item-icon-destructive-color: #de6e5b;
--disabled-tooltip-icon-color: #7fd2ef;
@@ -147,6 +148,7 @@
--launcher-pane-vert-button-hover-background: #ffffff1c;
--launcher-pane-vert-button-hover-shadow: 4px 4px 4px rgba(0, 0, 0, 0.2);
--launcher-pane-vert-button-focus-outline-color: var(--input-focus-outline-color);
--launcher-pane-vert-background-color-bgfx: #00000026; /* When background effects enabled */
--launcher-pane-horiz-border-color: rgb(22, 22, 22);
--launcher-pane-horiz-background-color: #282828;
@@ -155,6 +157,8 @@
--launcher-pane-horiz-button-hover-background: #ffffff1c;
--launcher-pane-horiz-button-hover-shadow: unset;
--launcher-pane-horiz-button-focus-outline-color: var(--input-focus-outline-color);
--launcher-pane-horiz-background-color-bgfx: #ffffff17; /* When background effects enabled */
--launcher-pane-horiz-border-color-bgfx: #00000080; /* When background effects enabled */
--protected-session-active-icon-color: #8edd8e;
--sync-status-error-pulse-color: #f47871;

View File

@@ -13,6 +13,7 @@
--theme-style: light;
--native-titlebar-background: #ffffff00;
--window-background-color-bgfx: transparent; /* When background effects enabled */
--main-background-color: white;
--main-text-color: black;
@@ -115,17 +116,17 @@
--quick-search-focus-border: #00000029;
--quick-search-focus-background: #ffffff80;
--quick-search-focus-color: #000;
--quick-search-result-content-background: #00000017;
--quick-search-result-content-background: #0000000f;
--quick-search-result-highlight-color: #c65050;
--left-pane-collapsed-border-color: #0000000d;
--left-pane-background-color: #f2f2f2;
--left-pane-text-color: #383838;
--left-pane-item-hover-background: #eaeaea;
--left-pane-item-hover-background: rgba(0, 0, 0, 0.032);
--left-pane-item-selected-background: white;
--left-pane-item-selected-color: black;
--left-pane-item-selected-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
--left-pane-item-action-button-background: #d7d7d7;
--left-pane-item-action-button-background: rgba(0, 0, 0, 0.11);
--left-pane-item-action-button-color: inherit;
--left-pane-item-action-button-hover-background: white;
--left-pane-item-action-button-hover-shadow: 2px 2px 3px rgba(0, 0, 0, 0.15);
@@ -141,6 +142,7 @@
--launcher-pane-vert-button-hover-background: white;
--launcher-pane-vert-button-hover-shadow: 4px 4px 4px rgba(0, 0, 0, 0.075);
--launcher-pane-vert-button-focus-outline-color: var(--input-focus-outline-color);
--launcher-pane-vert-background-color-bgfx: #00000009; /* When background effects enabled */
--launcher-pane-horiz-border-color: rgba(0, 0, 0, 0.1);
--launcher-pane-horiz-background-color: #fafafa;
@@ -148,6 +150,8 @@
--launcher-pane-horiz-button-hover-background: var(--icon-button-hover-background);
--launcher-pane-horiz-button-hover-shadow: unset;
--launcher-pane-horiz-button-focus-outline-color: var(--input-focus-outline-color);
--launcher-pane-horiz-background-color-bgfx: #ffffffb3; /* When background effects enabled */
--launcher-pane-horiz-border-color-bgfx: #00000026; /* When background effects enabled */
--protected-session-active-icon-color: #16b516;
--sync-status-error-pulse-color: #ff5528;

View File

@@ -329,6 +329,8 @@ body.mobile .dropdown-menu .dropdown-item.submenu-open .dropdown-toggle::after {
#toast-container .toast .toast-body {
flex-grow: 1;
overflow: hidden;
text-overflow: ellipsis;
}
/*

View File

@@ -5,7 +5,8 @@
button.btn.btn-primary,
button.btn.btn-secondary,
button.btn.btn-sm:not(.select-button),
button.btn.btn-success {
button.btn.btn-success,
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text {
display: inline-flex;
align-items: center;
justify-content: center;
@@ -21,7 +22,8 @@ button.btn.btn-success {
button.btn.btn-primary:hover,
button.btn.btn-secondary:hover,
button.btn.btn-sm:not(.select-button):hover,
button.btn.btn-success:hover {
button.btn.btn-success:hover,
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text:not(.ck-disabled):hover {
background: var(--cmd-button-hover-background-color);
color: var(--cmd-button-hover-text-color);
}
@@ -29,7 +31,8 @@ button.btn.btn-success:hover {
button.btn.btn-primary:active,
button.btn.btn-secondary:active,
button.btn.btn-sm:not(.select-button):active,
button.btn.btn-success:active {
button.btn.btn-success:active,
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text:not(.ck-disabled):active {
opacity: 0.85;
box-shadow: unset;
background: var(--cmd-button-background-color) !important;
@@ -40,14 +43,16 @@ button.btn.btn-success:active {
button.btn.btn-primary:disabled,
button.btn.btn-secondary:disabled,
button.btn.btn-sm:not(.select-button):disabled,
button.btn.btn-success:disabled {
button.btn.btn-success:disabled,
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text.ck-disabled {
opacity: var(--cmd-button-disabled-opacity);
}
button.btn.btn-primary:focus-visible,
button.btn.btn-secondary:focus-visible,
button.btn.btn-sm:not(.select-button):focus-visible,
button.btn.btn-success:focus-visible {
button.btn.btn-success:focus-visible,
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text:not(.ck-disabled):focus-visible {
outline: 2px solid var(--input-focus-outline-color);
}
@@ -149,8 +154,11 @@ input[type="password"],
input[type="date"],
input[type="time"],
input[type="datetime-local"],
:root input.ck.ck-input-text,
:root input.ck.ck-input-number,
textarea.form-control,
textarea,
:root textarea.ck.ck-textarea,
.tn-input-field {
outline: 3px solid transparent;
outline-offset: 6px;
@@ -167,8 +175,11 @@ input[type="password"]:hover,
input[type="date"]:hover,
input[type="time"]:hover,
input[type="datetime-local"]:hover,
:root input.ck.ck-input-text:not([readonly="true"]):hover,
:root input.ck.ck-input-number:not([readonly="true"]):hover,
textarea.form-control:hover,
textarea:hover,
:root textarea.ck.ck-textarea:hover,
.tn-input-field:hover {
background: var(--input-hover-background);
color: var(--input-hover-color);
@@ -181,8 +192,11 @@ input[type="password"]:focus,
input[type="date"]:focus,
input[type="time"]:focus,
input[type="datetime-local"]:focus,
:root input.ck.ck-input-text:focus,
:root input.ck.ck-input-number:focus,
textarea.form-control:focus,
textarea:focus,
:root textarea.ck.ck-textarea:focus,
.tn-input-field:focus,
.tn-input-field:focus-within {
box-shadow: unset;

View File

@@ -4,6 +4,7 @@
:root {
--ck-font-face: var(--main-font-family);
--ck-input-label-height: 1.5em;
}
/*
@@ -307,6 +308,11 @@
fill: black !important;
}
/* Hex color input box prefix */
:root .ck.ck-color-selector .ck-color-picker__hash-view {
margin-top: var(--ck-input-label-height);
}
/* Numbered list */
:root .ck.ck-list-properties_with-numbered-properties .ck.ck-list-styles-list {
@@ -363,19 +369,86 @@
color: var(--accent);
}
/* Action buttons */
/* Text snippet dropdown */
:root .ck-link-actions button.ck-button,
:root .ck-link-form button.ck-button {
--ck-border-radius: 6px;
background: transparent;
box-shadow: unset;
div.ck-template-form {
padding: 8px;
}
:root .ck-link-actions button.ck-button:hover,
:root .ck-link-form button.ck-button:hover {
background: var(--hover-item-background-color);
div.ck-template-form .ck-labeled-field-view {
margin-bottom: 8px;
}
/* Template item */
:root div.ck-template-form li.ck-list__item button.ck-template-button {
padding: 4px 8px;
}
/* Template icon */
:root .ck-template-form .ck-button__icon {
--ck-spacing-medium: 2px;
}
:root div.ck-template-form .note-icon {
color: var(--menu-item-icon-color);
}
/* Template name */
div.ck-template-form .ck-template-form__text-part {
color: var(--hover-item-text-color);
font-size: .9rem;
}
div.ck-template-form .ck-template-form__text-part mark {
background: unset;
color: var(--quick-search-result-highlight-color);
font-weight: bold;
}
/* Template description */
:root div.ck-template-form .ck-template-form__description {
opacity: .5;
font-size: .9em;
}
/* Messages */
div.ck-template-form .ck-search__info > span {
line-height: initial;
color: var(--muted-text-color);
}
div.ck-template-form .ck-search__info span:nth-child(2) {
display: block;
opacity: .5;
margin-top: 8px;
font-size: .9em;
}
/* Link dropdown */
:root .ck.ck-form.ck-link-form ul.ck-link-form__providers-list {
border-top: none;
}
/* Math popup */
.ck-math-form .ck-labeled-field-view {
--ck-input-label-height: 0;
margin-inline-end: 8px;
}
/* Emoji dropdown */
.ck-emoji-picker-form .ck-emoji__search .ck-button_with-text:not(.ck-list-item-button) {
margin-top: var(--ck-input-label-height);
}
/* Find and replace dialog */
.ck-find-and-replace-form .ck-find-and-replace-form__inputs button {
margin-top: var(--ck-input-label-height);
}
/* Mention list (the autocompletion list for emojis, labels and relations) */
@@ -392,6 +465,58 @@
background: transparent;
}
/*
* FORMS
*/
/*
* Buttons
*/
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel).ck-button_with-text {
--ck-color-text: var(--cmd-button-text-color);
min-width: 60px;
font-weight: 500;
}
/*
* Text boxes
*/
.ck.ck-labeled-field-view {
padding-top: var(--ck-input-label-height) !important; /* Create space for the label */
}
.ck.ck-labeled-field-view > .ck.ck-labeled-field-view__input-wrapper > label.ck.ck-label {
/* Move the label above the text box regardless of the text box state */
transform: translate(0, calc(-.2em - var(--ck-input-label-height))) !important;
padding-left: 0 !important;
background: transparent;
font-size: .85em;
font-weight: 600;
}
:root input.ck.ck-input-text[readonly="true"] {
cursor: not-allowed;
background: var(--input-background-color);
}
/* Forms */
:root .ck.ck-form__row.ck-form__row_with-submit > :not(:first-child) {
margin-inline-start: 16px;
}
.ck.ck-form__row_with-submit button {
margin-top: var(--ck-input-label-height);
}
.ck.ck-form__header {
border-bottom: none;
}
/*
* EDITOR'S CONTENT
*/

View File

@@ -36,32 +36,23 @@ body.mobile {
/* #region Mica */
body.background-effects.platform-win32 {
--launcher-pane-horiz-border-color: rgba(0, 0, 0, 0.15);
--launcher-pane-horiz-background-color: rgba(255, 255, 255, 0.7);
--launcher-pane-vert-background-color: rgba(255, 255, 255, 0.055);
--tab-background-color: transparent;
--new-tab-button-background: transparent;
--active-tab-background-color: var(--launcher-pane-horiz-background-color);
--background-material: tabbed;
}
@media (prefers-color-scheme: dark) {
body.background-effects.platform-win32 {
--launcher-pane-horiz-border-color: rgba(0, 0, 0, 0.5);
--launcher-pane-horiz-background-color: rgba(255, 255, 255, 0.09);
}
--launcher-pane-horiz-border-color: var(--launcher-pane-horiz-border-color-bgfx);
--launcher-pane-horiz-background-color: var(--launcher-pane-horiz-background-color-bgfx);
--launcher-pane-vert-background-color: var(--launcher-pane-vert-background-color-bgfx);
--tab-background-color: var(--window-background-color-bgfx);
--new-tab-button-background: var(--window-background-color-bgfx);
--active-tab-background-color: var(--launcher-pane-horiz-background-color);
}
body.background-effects.platform-win32.layout-vertical {
--left-pane-background-color: transparent;
--left-pane-item-hover-background: rgba(127, 127, 127, 0.05);
--left-pane-background-color: var(--window-background-color-bgfx);
--background-material: mica;
}
body.background-effects.platform-win32,
body.background-effects.platform-win32 #root-widget,
body.background-effects.platform-win32 #launcher-pane .launcher-button {
background: transparent !important;
body.background-effects.platform-win32 #root-widget {
background: var(--window-background-color-bgfx) !important;
}
body.background-effects.platform-win32.layout-horizontal #horizontal-main-container,
@@ -90,7 +81,7 @@ body.background-effects.zen #root-widget {
* Gutter
*/
.gutter {
.gutter {
background: var(--gutter-color) !important;
transition: background 150ms ease-out;
}
@@ -575,31 +566,20 @@ div.quick-search .search-button.show {
* Quick search results
*/
div.quick-search .dropdown-menu {
--quick-search-item-delimiter-color: transparent;
--menu-item-icon-vert-offset: -.065em;
}
/* Item */
.quick-search .dropdown-menu *.dropdown-item {
padding: 8px 12px !important;
}
/* Note icon */
.quick-search .dropdown-menu .dropdown-item > .bx {
position: relative;
top: 1px;
}
.quick-search .quick-search-item-icon {
vertical-align: text-bottom;
}
/* Note title */
.quick-search .dropdown-menu .dropdown-item > a {
color: var(--menu-text-color);
}
.quick-search .dropdown-menu .dropdown-item > a:hover {
--hover-item-background-color: transparent;
text-decoration: underline;
}
/* Note path */
.quick-search .dropdown-menu small {
display: block;
@@ -622,9 +602,8 @@ div.quick-search .search-button.show {
font-weight: 600;
}
/* Divider line */
.quick-search .dropdown-item::after {
display: none;
.quick-search div.dropdown-divider {
margin: 8px 0;
}
/*
@@ -899,6 +878,80 @@ body.layout-horizontal .tab-row-container {
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
body.electron.background-effects.layout-horizontal .tab-row-container {
border-bottom: unset !important;
}
body.electron.background-effects.layout-horizontal .note-tab-wrapper {
top: 1px;
}
body.electron.background-effects.layout-horizontal .tab-row-container .toggle-button {
position: relative;
}
body.electron.background-effects.layout-horizontal .tab-row-container .toggle-button:after {
content: "";
position: absolute;
bottom: 0;
left: -10px;
right: -10px;
top: 29px;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-left,
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-right {
position: relative;
}
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-left:after,
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-right:after {
content: "";
position: absolute;
bottom: 0;
left: 0px;
right: 0px;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
body.electron.background-effects.layout-horizontal .tab-row-container .note-tab[active]:before {
content: "";
position: absolute;
bottom: 0;
left: -32768px;
top: var(--tab-height);
right: calc(100% - 1px);
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
body.electron.background-effects.layout-horizontal .tab-row-container .note-tab[active]:after {
content: "";
position: absolute;
bottom: 0;
left: 100%;
top: var(--tab-height);
right: 0;
width: 100vw;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
body.electron.background-effects.layout-horizontal .tab-row-container .note-new-tab:before {
content: "";
position: absolute;
bottom: 0;
left: -4px;
top: calc(var(--tab-height), -1);
right: 0;
width: 100vw;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
body.layout-vertical.electron.platform-darwin .tab-row-container {
border-bottom: 1px solid var(--subtle-border-color);
}
@@ -1114,6 +1167,11 @@ body.layout-vertical .tab-row-widget-is-sorting .note-tab.note-tab-is-dragging .
/* will-change: opacity; -- causes some weird artifacts to the note menu in split view */
}
.split-note-container-widget > .gutter {
background: var(--root-background) !important;
transition: background 150ms ease-out;
}
/*
* Ribbon & note header
*/
@@ -1122,10 +1180,6 @@ body.layout-vertical .tab-row-widget-is-sorting .note-tab.note-tab-is-dragging .
margin-bottom: 0 !important;
}
.note-split:not(.hidden-ext) + .note-split:not(.hidden-ext) {
border-left: 4px solid var(--root-background);
}
@keyframes note-entrance {
from {
opacity: 0;

View File

@@ -1404,8 +1404,8 @@
"open-in-popup": "Schnellbearbeitung"
},
"shared_info": {
"shared_publicly": "Diese Notiz ist öffentlich geteilt auf {{- link}}",
"shared_locally": "Diese Notiz ist lokal geteilt auf {{- link}}",
"shared_publicly": "Diese Notiz ist öffentlich geteilt auf {{- link}}.",
"shared_locally": "Diese Notiz ist lokal geteilt auf {{- link}}.",
"help_link": "Für Hilfe besuche <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>."
},
"note_types": {
@@ -1484,7 +1484,8 @@
"hoist-this-note-workspace": "Diese Notiz fokussieren (Arbeitsbereich)",
"refresh-saved-search-results": "Gespeicherte Suchergebnisse aktualisieren",
"create-child-note": "Unternotiz anlegen",
"unhoist": "Fokus verlassen"
"unhoist": "Fokus verlassen",
"toggle-sidebar": "Seitenleiste ein-/ausblenden"
},
"title_bar_buttons": {
"window-on-top": "Dieses Fenster immer oben halten"

View File

@@ -263,6 +263,11 @@
"confirm_delete_all": "Do you want to delete all revisions of this note?",
"no_revisions": "No revisions for this note yet...",
"restore_button": "Restore",
"diff_on": "Show diff",
"diff_off": "Show content",
"diff_on_hint": "Click to show note source diff",
"diff_off_hint": "Click to show note content",
"diff_not_available": "Diff isn't available.",
"confirm_restore": "Do you want to restore this revision? This will overwrite the current title and content of the note with this revision.",
"delete_button": "Delete",
"confirm_delete": "Do you want to delete this revision?",
@@ -1118,7 +1123,9 @@
"title": "Performance",
"enable-motion": "Enable transitions and animations",
"enable-shadows": "Enable shadows",
"enable-backdrop-effects": "Enable background effects for menus, popups and panels"
"enable-backdrop-effects": "Enable background effects for menus, popups and panels",
"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",

View File

@@ -13,29 +13,131 @@
"critical-error": {
"title": "Błąd krytyczny",
"message": "Wystąpił krytyczny błąd uniemożliwiający uruchomienie aplikacji:\n\n{{message}}\n\nJest to spowodowane najprawdopodobniej niespodziewanym błędem skryptu. Spróbuj uruchomić aplikację ponownie w trybie bezpiecznym i zaadresuj problem."
},
"widget-error": {
"title": "Nie udało się zainicjować widżetu",
"message-custom": "Niestandardowy widżet z notatki o identyfikatorze \"{{id}}\", i tytule \"{{title}}\" nie mógł zostać zainicjowany z powodu:\n\n{{message}}",
"message-unknown": "Nieznany widżet nie mógł być zainicjowany z powodu:\n\n{{message}}"
},
"bundle-error": {
"title": "Nie udało się załadować niestandardowego skryptu",
"message": "Skrypt z notatki o identyfikatorze \"{{id}}\", tytule \"{{title}}: nie został uruchomiony z powodu:\n\n{{message}}"
}
},
"add_link": {
"add_link": "Dodaj link"
"add_link": "Dodaj link",
"note": "Notatka",
"search_note": "Wyszukaj notatkę po nazwie",
"link_title_arbitrary": "Tytuł linku można dowolnie zmieniać",
"link_title": "Tytuł linku",
"button_add_link": "Dodaj link",
"help_on_links": "Pomoc dotycząca linków",
"link_title_mirrors": "tytuł linku odzwierciedla tytuł obecnej notatki"
},
"branch_prefix": {
"save": "Zapisz"
"save": "Zapisz",
"edit_branch_prefix": "Edytuj prefiks gałęzi",
"prefix": "Prefiks: ",
"branch_prefix_saved": "Zapisano prefiks gałęzi.",
"help_on_tree_prefix": "Pomoc dotycząca prefiksu drzewa"
},
"bulk_actions": {
"labels": "Etykiety",
"notes": "Notatki",
"other": "Inne",
"relations": "Powiązania"
"relations": "Powiązania",
"bulk_actions": "Działania zbiorcze",
"include_descendants": "Uwzględnia rozwinięcia wybranych notatek",
"available_actions": "Dostępne działania",
"chosen_actions": "Wybrane działania",
"execute_bulk_actions": "Wykonaj zbiór działań",
"bulk_actions_executed": "Zbiór działań został wykonany prawidłowo.",
"none_yet": "Brak zaznaczonych działań... dodaj działanie poprzez kliknięcie jednej z dostępnych opcji powyżej."
},
"confirm": {
"ok": "OK",
"cancel": "Anuluj"
"cancel": "Anuluj",
"confirmation": "Potwierdzenie",
"are_you_sure_remove_note": "Czy napewno chcesz usunąć notatkę \"{{title}}\" z mapy powiązań? ",
"if_you_dont_check": "Jeśli nie zaznaczysz tej opcji, notatka zostanie usunięta jedynie z mapy powiązań.",
"also_delete_note": "Usuń dodatkowo notatkę"
},
"delete_notes": {
"cancel": "Anuluj",
"close": "Zamknij"
"close": "Zamknij",
"delete_notes_preview": "Usuń podgląd notatek",
"delete_all_clones_description": "Usuń również wszystkie sklonowania (działanie może zostać cofnięte w ostatnich zmianach)",
"erase_notes_description": "Normalne (miękkie) usuwanie zaznacza jedynie notatki jako usunięte i można je przywrócić (w oknie dialogowym ostatnich zmian) przez wyznaczony okres czasu. Zaznaczenie tej opcji spowoduje natychmiastowe usunięcie notatek, bez możliwości ich przywrócenia.",
"erase_notes_warning": "Usuń notatki permanentnie (bez opcji ich przywrócenia), włączając wszystkie kopie. Działanie to wymaga ponownego uruchomienia aplikacji.",
"notes_to_be_deleted": "Następujące notatki zostaną usunięte ({{notesCount}})",
"no_note_to_delete": "Żadne notatki nie zostaną usunięte (jedynie kopie).",
"broken_relations_to_be_deleted": "Następujące powiązania zostaną uszkodzone i usunięte ({{ relationCount}})",
"ok": "OK",
"deleted_relation_text": "Notatka {{- note}} (do usunięcia) jest powiązana przez relację {{- relation}} pochodzącą z {{- source}}."
},
"export": {
"close": "Zamknij"
"close": "Zamknij",
"export_note_title": "Eksportuj notatkę",
"export_type_subtree": "Ta notatka oraz wszystkie podrzędne",
"format_html": "HTML - rekomendowany jako zachowujący całość formatowania",
"format_html_zip": "HTML w archiwum ZIP - rekomendowany jako zachowujący całość formatowania.",
"format_markdown": "Markdown - zachowuje większość formatowania.",
"format_opml": "OPML - format wymiany danych dla outlinerów zawierający tylko tekst. Formatowanie, obrazy i pliki nie są uwzględnione.",
"opml_version_1": "OPML v1.0 - tylko zwykły tekst",
"opml_version_2": "OPML v2.0 - umożliwia również HTML",
"export_type_single": "Tylko ta notatka, bez elementów podrzędnych",
"export": "Eksportuj",
"choose_export_type": "Wybierz najpierw rodzaj pliku do eksportu",
"export_status": "Status eksportu",
"export_in_progress": "Postęp eksportowania: {{progressCount}}",
"export_finished_successfully": "Eksportowanie zakończone.",
"format_pdf": "PDF - w celu drukowania lub udostępniania."
},
"clone_to": {
"clone_notes_to": "Sklonuj notatki do...",
"notes_to_clone": "Notatki do sklonowania",
"search_for_note_by_its_name": "Wyszukaj notatkę po jej nazwie",
"cloned_note_prefix_title": "Sklonowana notatka zostanie wyświetlona w drzewie notatki z podanym prefiksem",
"prefix_optional": "Prefiks (opcjonalne)",
"clone_to_selected_note": "Sklonuj do wybranej notatki",
"no_path_to_clone_to": "Brak ścieżki do sklonowania.",
"note_cloned": "Notatka \"{{clonedTitle}}\" została sklonowana do \"{{targetTitle}}\"",
"help_on_links": "Pomoc dotycząca linków"
},
"help": {
"title": "Ściągawka",
"noteNavigation": "Nawigacja po notatkach",
"goUpDown": "przewijanie w górę/w dół w liście notatek",
"collapseExpand": "zwiń/rozwiń zbiór",
"notSet": "niezdefiniowany",
"goBackForwards": "przewijaj do tyłu/do przodu w historii",
"showJumpToNoteDialog": "pokaż <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"przejdź do dialogu</a>",
"scrollToActiveNote": "przewiń do aktywnej notatki",
"jumpToParentNote": "przejdź do głównej notatki",
"collapseWholeTree": "zwiń całe drzewko notatki",
"collapseSubTree": "zwiń gałąź notatki",
"tabShortcuts": "Skóry kart",
"newTabNoteLink": "link notatki otwiera notatkę w nowej karcie",
"newTabWithActivationNoteLink": "link notatki otwiera i aktywuje notatkę w nowej karcie",
"onlyInDesktop": "Tylko na komputerze stacjonarnym (wersja Electron)",
"openEmptyTab": "Otwórz pustą kartę",
"closeActiveTab": "zamknij aktywną kartę",
"activateNextTab": "aktywuj następną kartę",
"activatePreviousTab": "aktywuj poprzednią kartę",
"creatingNotes": "Tworzenie notatek",
"createNoteAfter": "Utwórz nową notatkę obok obecnie aktywnej",
"createNoteInto": "Utwórz nową podnotatkę w obecnie otwartej",
"editBranchPrefix": "edytuj <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/tree-concepts.html#prefix\">prefiks</a> aktywnej kopii notatki",
"movingCloningNotes": "Przenoszenie / kopiowanie notatek",
"moveNoteUpDown": "Przenieś notatkę w górę/w dół na liście notatek",
"moveNoteUpHierarchy": "Przenieś notatkę w górę w hierarchii",
"multiSelectNote": "Zaznacz wiele notatek powyżej/poniżej",
"selectAllNotes": "Wybierz wszystkie notatki na obecnym poziomie",
"selectNote": "Wybierz notatkę",
"copyNotes": "skopiuj obecną notatkę (lub obecną sekcję) do schowka (zastosowanie dla<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">klonowania</a>)",
"cutNotes": "przytnij obecną notatkę (lub obecną sekcję) do schowka (zastosowanie dla przenoszenia notatek)",
"pasteNotes": "wklej notatkę jako podnotatka w obecnej notatce (rozumiane jako przenieś lub skopiuj, w zależności czy notatka była skopiowana czy wycięta)",
"deleteNotes": "usuń notatkę / gałąź",
"editingNotes": "Edytowanie notatek"
}
}

View File

@@ -994,7 +994,7 @@
"invalid_view_type": "Tipo de visualização inválido '{{type}}'",
"calendar": "Calendário",
"table": "Tabela",
"geo-map": "Geo Map",
"geo-map": "Mapa geográfico",
"board": "Quadro"
},
"edited_notes": {
@@ -1278,7 +1278,7 @@
"handwriting-system-fonts": "Fontes de escrita à mão de sistema",
"serif": "Serifa",
"sans-serif": "Sem Serifa",
"monospace": "Monospace",
"monospace": "Monoespaçado",
"system-default": "Padrão do Sistema",
"note_tree_and_detail_font_sizing": "Note que o tamanho da fonte da árvore e dos detalhes é relativo à configuração principal do tamanho de fonte."
},
@@ -1518,7 +1518,7 @@
"doc": "Documento",
"widget": "Widget",
"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": "Geo Map",
"geo-map": "Mapa geográfico",
"beta-feature": "Beta",
"ai-chat": "Chat IA",
"task-list": "Lista de Tarefas",
@@ -1579,7 +1579,8 @@
"hoist-this-note-workspace": "Fixar esta nota (workspace)",
"refresh-saved-search-results": "Atualizar resultados de pesquisa salvos",
"create-child-note": "Criar nota filha",
"unhoist": "Desafixar"
"unhoist": "Desafixar",
"toggle-sidebar": "Alternar barra lateral"
},
"title_bar_buttons": {
"window-on-top": "Manter Janela no Topo"
@@ -2022,6 +2023,8 @@
"handshake_failed": "Falha no handshake com o servidor de sincronização, erro: {{message}}"
},
"shared_info": {
"help_link": "Para ajuda, visite a <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>."
"help_link": "Para ajuda, visite a <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>.",
"shared_publicly": "Esta nota é compartilhada publicamente em {{- link}}.",
"shared_locally": "Esta nota é compartilhada localmente em {{- link}}."
}
}

View File

@@ -2013,7 +2013,9 @@
"title": "Setări de performanță",
"enable-motion": "Activează tranzițiile și animațiile",
"enable-shadows": "Activează umbrirea elementelor",
"enable-backdrop-effects": "Activează efectele de fundal pentru meniuri, popup-uri și panouri"
"enable-backdrop-effects": "Activează efectele de fundal pentru meniuri, popup-uri și panouri",
"enable-smooth-scroll": "Activează derularea lină",
"app-restart-required": "(este necesară repornirea aplicației pentru ca modificarea să aibă efect)"
},
"settings": {
"related_settings": "Setări similare"

View File

@@ -742,7 +742,8 @@
"save-changes": "Сохранить и применить изменения",
"saved-search-note-refreshed": "Сохраненная поисковая заметка обновлена.",
"refresh-saved-search-results": "Обновить сохраненные результаты поиска",
"automatically-collapse-notes-title": "Заметки будут свернуты после определенного периода бездействия, чтобы навести порядок в дереве."
"automatically-collapse-notes-title": "Заметки будут свернуты после определенного периода бездействия, чтобы навести порядок в дереве.",
"toggle-sidebar": "Переключить боковую панель"
},
"quick-search": {
"no-results": "Результаты не найдены",
@@ -1974,8 +1975,8 @@
},
"shared_info": {
"help_link": "Для получения справки посетите <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">вики</a>.",
"shared_locally": "Заметка общедоступна локально в {{- link}}",
"shared_publicly": "Заметка общедоступна публично в {{- link}}"
"shared_locally": "Заметка общедоступна локально в {{- link}}.",
"shared_publicly": "Заметка общедоступна публично в {{- link}}."
},
"note_create": {
"duplicated": "Создан дубль заметки \"{{title}}\"."

View File

@@ -844,7 +844,8 @@
"note_type": "Тип нотатки",
"editable": "Редагув.",
"basic_properties": "Основні Властивості",
"language": "Мова"
"language": "Мова",
"configure_code_notes": "Конфігурація нотатки з кодом..."
},
"book_properties": {
"view_type": "Тип перегляду",
@@ -1586,7 +1587,8 @@
"hoist-this-note-workspace": "Закріпити цю нотатку (робочий простір)",
"refresh-saved-search-results": "Оновити збережені результати пошуку",
"create-child-note": "Створити дочірню нотатку",
"unhoist": "Відкріпити"
"unhoist": "Відкріпити",
"toggle-sidebar": "Перемикання бічної панелі"
},
"title_bar_buttons": {
"window-on-top": "Тримати вікно зверху"
@@ -1909,8 +1911,8 @@
"open-in-popup": "Швидке редагування"
},
"shared_info": {
"shared_publicly": "Ця нотатка опублікована на {{- link}}",
"shared_locally": "Цю нотатку опубліковано локально на {{- link}}",
"shared_publicly": "Ця нотатка опублікована на {{- link}}.",
"shared_locally": "Цю нотатку опубліковано локально на {{- link}}.",
"help_link": "Щоб отримати допомогу, відвідайте <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">вікі</a>."
},
"note_types": {
@@ -2018,5 +2020,11 @@
},
"units": {
"percentage": "%"
},
"ui-performance": {
"title": "Продуктивність",
"enable-motion": "Увімкнути переходи та анімацію",
"enable-shadows": "Увімкнути тіні",
"enable-backdrop-effects": "Увімкнути фонові ефекти для меню, спливаючих вікон та панелей"
}
}

View File

@@ -1,7 +1,10 @@
{
"about": {
"homepage": "Trang chủ:",
"title": "Về Trilium Notes"
"title": "Về Trilium Notes",
"app_version": "Phiên bản:",
"db_version": "Phiên bản DB:",
"sync_version": "Phiên bản liên kết:"
},
"add_link": {
"add_link": "Thêm liên kết",
@@ -26,7 +29,8 @@
"close": "Đóng"
},
"help": {
"other": "Khác"
"other": "Khác",
"notSet": "chưa được đặt"
},
"toast": {
"critical-error": {
@@ -69,12 +73,16 @@
"add_label": {
"add_label": "Thêm nhãn",
"label_name_placeholder": "tên nhãn",
"help_text_item2": "hoặc thay đổi giá trị của nhãn có sẵn"
"help_text_item2": "hoặc thay đổi giá trị của nhãn có sẵn",
"new_value_placeholder": "giá trị mới"
},
"rename_label": {
"rename_label": "Đặt lại tên nhãn"
},
"call_to_action": {
"dismiss": "Bỏ qua"
},
"abstract_search_option": {
"remove_this_search_option": "Xoá lựa chọn tìm kiếm này"
}
}

View File

@@ -1,16 +1,11 @@
import utils from "../../services/utils.js";
import contextMenu from "../../menus/context_menu.js";
import contextMenu, { MenuCommandItem } from "../../menus/context_menu.js";
import treeService from "../../services/tree.js";
import ButtonFromNoteWidget from "./button_from_note.js";
import type FNote from "../../entities/fnote.js";
import type { CommandNames } from "../../components/app_context.js";
import type { WebContents } from "electron";
interface ContextMenuItem {
title: string;
idx: string;
uiIcon: string;
}
import link from "../../services/link.js";
export default class HistoryNavigationButton extends ButtonFromNoteWidget {
private webContents?: WebContents;
@@ -47,24 +42,20 @@ export default class HistoryNavigationButton extends ButtonFromNoteWidget {
return;
}
let items: ContextMenuItem[] = [];
let items: MenuCommandItem<string>[] = [];
const history = this.webContents.navigationHistory;
const activeIndex = history.getActiveIndex();
const history = this.webContents.navigationHistory.getAllEntries();
const activeIndex = this.webContents.navigationHistory.getActiveIndex();
for (const idx in history) {
const url = history[idx];
const parts = url.split("#");
if (parts.length < 2) continue;
const notePathWithTab = parts[1];
const notePath = notePathWithTab.split("-")[0];
const { notePath } = link.parseNavigationStateFromUrl(history[idx].url);
if (!notePath) continue;
const title = await treeService.getNotePathTitle(notePath);
items.push({
title,
idx,
command: idx,
uiIcon:
parseInt(idx) === activeIndex
? "bx bx-radio-circle-marked" // compare with type coercion!
@@ -84,9 +75,10 @@ export default class HistoryNavigationButton extends ButtonFromNoteWidget {
x: e.pageX,
y: e.pageY,
items,
selectMenuItemHandler: (item: any) => {
if (item && item.idx && this.webContents) {
this.webContents.goToIndex(item.idx);
selectMenuItemHandler: (item: MenuCommandItem<string>) => {
if (item && item.command && this.webContents) {
const idx = parseInt(item.command, 10);
this.webContents.navigationHistory.goToIndex(idx);
}
}
});

View File

@@ -3,7 +3,7 @@ import appContext, { type CommandData, type CommandListenerData, type EventData,
import type BasicWidget from "../basic_widget.js";
import type NoteContext from "../../components/note_context.js";
import Component from "../../components/component.js";
import splitService from "../../services/resizer.js";
interface NoteContextEvent {
noteContext: NoteContext;
}
@@ -52,6 +52,10 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
await widget.handleEvent("setNoteContext", { noteContext });
this.child(widget);
if (noteContext.mainNtxId && noteContext.ntxId) {
splitService.setupNoteSplitResizer([noteContext.mainNtxId,noteContext.ntxId]);
}
}
async openNewNoteSplitEvent({ ntxId, notePath, hoistedNoteId, viewScope }: EventData<"openNewNoteSplit">) {
@@ -95,9 +99,9 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
}
}
closeThisNoteSplitCommand({ ntxId }: CommandListenerData<"closeThisNoteSplit">) {
async closeThisNoteSplitCommand({ ntxId }: CommandListenerData<"closeThisNoteSplit">) {
if (ntxId) {
appContext.tabManager.removeNoteContext(ntxId);
await appContext.tabManager.removeNoteContext(ntxId);
}
}
@@ -137,6 +141,8 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
// activate context that now contains the original note
await appContext.tabManager.activateNoteContext(isMovingLeft ? ntxIds[leftIndex + 1] : ntxIds[leftIndex]);
splitService.moveNoteSplitResizer(ntxIds[leftIndex]);
}
activeContextChangedEvent() {
@@ -157,6 +163,8 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
recursiveCleanup(widget);
delete this.widgets[ntxId];
}
splitService.delNoteSplitResizer(ntxIds);
}
contextsReopenedEvent({ ntxId, afterNtxId }: EventData<"contextsReopened">) {

View File

@@ -7,6 +7,7 @@ import { t } from "../../services/i18n";
import server from "../../services/server";
import toast from "../../services/toast";
import Button from "../react/Button";
import FormToggle from "../react/FormToggle";
import Modal from "../react/Modal";
import FormList, { FormListItem } from "../react/FormList";
import utils from "../../services/utils";
@@ -18,12 +19,15 @@ import open from "../../services/open";
import ActionButton from "../react/ActionButton";
import options from "../../services/options";
import { useTriliumEvent } from "../react/hooks";
import { diffWords } from "diff";
export default function RevisionsDialog() {
const [ note, setNote ] = useState<FNote>();
const [ noteContent, setNoteContent ] = useState<string>();
const [ revisions, setRevisions ] = useState<RevisionItem[]>();
const [ currentRevision, setCurrentRevision ] = useState<RevisionItem>();
const [ shown, setShown ] = useState(false);
const [ showDiff, setShowDiff ] = useState(false);
const [ refreshCounter, setRefreshCounter ] = useState(0);
useTriliumEvent("showRevisions", async ({ noteId }) => {
@@ -37,8 +41,10 @@ export default function RevisionsDialog() {
useEffect(() => {
if (note?.noteId) {
server.get<RevisionItem[]>(`notes/${note.noteId}/revisions`).then(setRevisions);
note.getContent().then(setNoteContent);
} else {
setRevisions(undefined);
setNoteContent(undefined);
}
}, [ note?.noteId, refreshCounter ]);
@@ -54,22 +60,42 @@ export default function RevisionsDialog() {
helpPageId="vZWERwf8U3nx"
bodyStyle={{ display: "flex", height: "80vh" }}
header={
(!!revisions?.length && <Button text={t("revisions.delete_all_revisions")} size="small" style={{ padding: "0 10px" }}
onClick={async () => {
const text = t("revisions.confirm_delete_all");
!!revisions?.length && (
<>
{["text", "code", "mermaid"].includes(currentRevision?.type ?? "") && (
<FormToggle
currentValue={showDiff}
onChange={(newValue) => setShowDiff(newValue)}
switchOnName={t("revisions.diff_on")}
switchOffName={t("revisions.diff_off")}
switchOnTooltip={t("revisions.diff_on_hint")}
switchOffTooltip={t("revisions.diff_off_hint")}
/>
)}
&nbsp;
<Button
text={t("revisions.delete_all_revisions")}
size="small"
style={{ padding: "0 10px" }}
onClick={async () => {
const text = t("revisions.confirm_delete_all");
if (note && await dialog.confirm(text)) {
await server.remove(`notes/${note.noteId}/revisions`);
setRevisions([]);
setCurrentRevision(undefined);
toast.showMessage(t("revisions.revisions_deleted"));
}
}}/>)
if (note && await dialog.confirm(text)) {
await server.remove(`notes/${note.noteId}/revisions`);
setRevisions([]);
setCurrentRevision(undefined);
toast.showMessage(t("revisions.revisions_deleted"));
}
}}
/>
</>
)
}
footer={<RevisionFooter note={note} />}
footerStyle={{ paddingTop: 0, paddingBottom: 0 }}
onHidden={() => {
setShown(false);
setShowDiff(false);
setNote(undefined);
setCurrentRevision(undefined);
setRevisions(undefined);
@@ -92,10 +118,13 @@ export default function RevisionsDialog() {
marginLeft: "20px",
display: "flex",
flexDirection: "column",
maxWidth: "calc(100% - 150px)",
minWidth: 0
}}>
<RevisionPreview
revisionItem={currentRevision}
noteContent={noteContent}
revisionItem={currentRevision}
showDiff={showDiff}
setShown={setShown}
onRevisionDeleted={() => {
setRefreshCounter(c => c + 1);
@@ -121,8 +150,10 @@ function RevisionsList({ revisions, onSelect, currentRevision }: { revisions: Re
</FormList>);
}
function RevisionPreview({ revisionItem, setShown, onRevisionDeleted }: {
revisionItem?: RevisionItem,
function RevisionPreview({noteContent, revisionItem, showDiff, setShown, onRevisionDeleted }: {
noteContent?: string,
revisionItem?: RevisionItem,
showDiff: boolean,
setShown: Dispatch<StateUpdater<boolean>>,
onRevisionDeleted?: () => void
}) {
@@ -179,7 +210,7 @@ function RevisionPreview({ revisionItem, setShown, onRevisionDeleted }: {
</div>)}
</div>
<div className="revision-content use-tn-links" style={{ overflow: "auto", wordBreak: "break-word" }}>
<RevisionContent revisionItem={revisionItem} fullRevision={fullRevision} />
<RevisionContent noteContent={noteContent} revisionItem={revisionItem} fullRevision={fullRevision} showDiff={showDiff}/>
</div>
</>
);
@@ -197,12 +228,15 @@ const CODE_STYLE: CSSProperties = {
whiteSpace: "pre-wrap"
};
function RevisionContent({ revisionItem, fullRevision }: { revisionItem?: RevisionItem, fullRevision?: RevisionPojo }) {
function RevisionContent({ noteContent, revisionItem, fullRevision, showDiff }: { noteContent?:string, revisionItem?: RevisionItem, fullRevision?: RevisionPojo, showDiff: boolean}) {
const content = fullRevision?.content;
if (!revisionItem || !content) {
return <></>;
}
if (showDiff) {
return <RevisionContentDiff noteContent={noteContent} itemContent={content} itemType={revisionItem.type}/>
}
switch (revisionItem.type) {
case "text":
return <RevisionContentText content={content} />
@@ -267,6 +301,48 @@ function RevisionContentText({ content }: { content: string | Buffer<ArrayBuffer
return <div ref={contentRef} className="ck-content" dangerouslySetInnerHTML={{ __html: content as string }}></div>
}
function RevisionContentDiff({ noteContent, itemContent, itemType }: {
noteContent?: string,
itemContent: string | Buffer<ArrayBufferLike> | undefined,
itemType: string
}) {
const contentRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!noteContent || typeof itemContent !== "string") {
if (contentRef.current) {
contentRef.current.textContent = t("revisions.diff_not_available");
}
return;
}
let processedNoteContent = noteContent;
let processedItemContent = itemContent;
if (itemType === "text") {
processedNoteContent = utils.formatHtml(noteContent);
processedItemContent = utils.formatHtml(itemContent);
}
const diff = diffWords(processedNoteContent, processedItemContent);
const diffHtml = diff.map(part => {
if (part.added) {
return `<span class="revision-diff-added">${utils.escapeHtml(part.value)}</span>`;
} else if (part.removed) {
return `<span class="revision-diff-removed">${utils.escapeHtml(part.value)}</span>`;
} else {
return utils.escapeHtml(part.value);
}
}).join("");
if (contentRef.current) {
contentRef.current.innerHTML = diffHtml;
}
}, [noteContent, itemContent, itemType]);
return <div ref={contentRef} className="ck-content" style={{ whiteSpace: "pre-wrap" }}></div>;
}
function RevisionFooter({ note }: { note?: FNote }) {
if (!note) {
return <></>;

View File

@@ -8,6 +8,7 @@ import NoteContextAwareWidget from "./note_context_aware_widget.js";
import attributeService from "../services/attributes.js";
import FindInText from "./find_in_text.js";
import FindInCode from "./find_in_code.js";
import { isIMEComposing } from "../services/shortcuts.js";
import FindInHtml from "./find_in_html.js";
import type { EventData } from "../components/app_context.js";
@@ -162,6 +163,11 @@ export default class FindWidget extends NoteContextAwareWidget {
this.$replaceButton.on("click", () => this.replace());
this.$input.on("keydown", async (e) => {
// Skip processing during IME composition
if (isIMEComposing(e.originalEvent as KeyboardEvent)) {
return;
}
if ((e.metaKey || e.ctrlKey) && (e.key === "F" || e.key === "f")) {
// If ctrl+f is pressed when the findbox is shown, select the
// whole input to find

View File

@@ -8,6 +8,7 @@ import "./note_title.css";
import { isLaunchBarConfig } from "../services/utils";
import appContext from "../components/app_context";
import branches from "../services/branches";
import { isIMEComposing } from "../services/shortcuts";
export default function NoteTitleWidget() {
const { note, noteId, componentId, viewScope, noteContext, parentComponent } = useNoteContext();
@@ -78,6 +79,12 @@ export default function NoteTitleWidget() {
spacedUpdate.scheduleUpdate();
}}
onKeyDown={(e) => {
// Skip processing if IME is composing to prevent interference
// with text input in CJK languages
if (isIMEComposing(e)) {
return;
}
// Focus on the note content when pressing enter.
if (e.key === "Enter") {
e.preventDefault();

View File

@@ -219,21 +219,22 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
this.$tree = this.$widget.find(".tree");
this.$treeActions = this.$widget.find(".tree-actions");
this.$tree.on("mousedown", ".unhoist-button", () => hoistedNoteService.unhoist());
this.$tree.on("mousedown", ".refresh-search-button", (e) => this.refreshSearch(e));
this.$tree.on("mousedown", ".add-note-button", (e) => {
const node = $.ui.fancytree.getNode(e as unknown as Event);
const parentNotePath = treeService.getNotePath(node);
this.$tree.on("mousedown", (e: JQuery.MouseDownEvent) => {
const target = e.target as HTMLElement;
if (e.button !== 0) return;
noteCreateService.createNote(parentNotePath, {
isProtected: node.data.isProtected
});
});
this.$tree.on("mousedown", ".enter-workspace-button", (e) => {
const node = $.ui.fancytree.getNode(e as unknown as Event);
this.triggerCommand("hoistNote", { noteId: node.data.noteId });
if (target.classList.contains("unhoist-button")) {
hoistedNoteService.unhoist();
} else if (target.classList.contains("refresh-search-button")) {
this.refreshSearch(e);
} else if (target.classList.contains("add-note-button")) {
const node = $.ui.fancytree.getNode(e as unknown as Event);
const parentNotePath = treeService.getNotePath(node);
noteCreateService.createNote(parentNotePath, { isProtected: node.data.isProtected });
} else if (target.classList.contains("enter-workspace-button")) {
const node = $.ui.fancytree.getNode(e as unknown as Event);
this.triggerCommand("hoistNote", { noteId: node.data.noteId });
}
});
// fancytree doesn't support middle click, so this is a way to support it

View File

@@ -23,15 +23,21 @@ export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
this.refresh();
}
noteSwitchedAndActivatedEvent() {
noteSwitchedAndActivatedEvent({ noteContext }: EventData<"setNoteContext">) {
this.noteContext = noteContext;
this.refresh();
}
noteSwitchedEvent() {
noteSwitchedEvent({ noteContext }: EventData<"setNoteContext">) {
this.noteContext = noteContext;
this.refresh();
}
activeContextChangedEvent() {
activeContextChangedEvent({ noteContext }: EventData<"setNoteContext">) {
this.noteContext = noteContext;
this.refresh();
}

View File

@@ -4,7 +4,7 @@ import linkService from "../services/link.js";
import froca from "../services/froca.js";
import utils from "../services/utils.js";
import appContext from "../components/app_context.js";
import shortcutService from "../services/shortcuts.js";
import shortcutService, { isIMEComposing } from "../services/shortcuts.js";
import { t } from "../services/i18n.js";
import { Dropdown, Tooltip } from "bootstrap";
@@ -15,13 +15,15 @@ const TPL = /*html*/`
padding: 10px 10px 10px 0px;
height: 50px;
}
.quick-search button, .quick-search input {
border: 0;
font-size: 100% !important;
}
.quick-search .dropdown-menu {
--quick-search-item-delimiter-color: var(--dropdown-border-color);
max-height: 80vh;
min-width: 400px;
max-width: 720px;
@@ -38,14 +40,14 @@ const TPL = /*html*/`
position: relative;
}
.quick-search .dropdown-item:not(:last-child)::after {
.quick-search .dropdown-item + .dropdown-item::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
top: 0;
width: 100%;
height: 1px;
background: var(--dropdown-border-color);
border-bottom: 1px solid var(--quick-search-item-delimiter-color);
}
.quick-search .dropdown-item:last-child::after {
@@ -92,6 +94,8 @@ const TPL = /*html*/`
background-color: var(--accented-background-color);
color: var(--main-text-color);
font-size: .85em;
overflow: hidden;
text-overflow: ellipsis;
}
/* Search result highlighting */
@@ -106,6 +110,10 @@ const TPL = /*html*/`
margin: 0;
}
.quick-search .bx-loader {
margin-inline-end: 4px;
}
</style>
<div class="input-group-prepend">
@@ -172,6 +180,14 @@ export default class QuickSearchWidget extends BasicWidget {
if (utils.isMobile()) {
this.$searchString.keydown((e) => {
// Skip processing if IME is composing to prevent interference
// with text input in CJK languages
// Note: jQuery wraps the native event, so we access originalEvent
const originalEvent = e.originalEvent as KeyboardEvent;
if (originalEvent && isIMEComposing(originalEvent)) {
return;
}
if (e.which === 13) {
if (this.$dropdownMenu.is(":visible")) {
this.search(); // just update already visible dropdown
@@ -220,7 +236,11 @@ export default class QuickSearchWidget extends BasicWidget {
this.isLoadingMore = false;
this.$dropdownMenu.empty();
this.$dropdownMenu.append(`<span class="dropdown-item disabled"><span class="bx bx-loader bx-spin"></span>${t("quick-search.searching")}</span>`);
this.$dropdownMenu.append(`
<span class="dropdown-item disabled">
<span class="bx bx-loader bx-spin"></span>
${t("quick-search.searching")}
</span>`);
const { searchResultNoteIds, searchResults, error } = await server.get<QuickSearchResponse>(`quick-search/${encodeURIComponent(searchString)}`);

View File

@@ -13,6 +13,7 @@ import attribute_parser, { Attribute } from "../../../services/attribute_parser"
import ActionButton from "../../react/ActionButton";
import { escapeQuotes, getErrorMessage } from "../../../services/utils";
import link from "../../../services/link";
import { isIMEComposing } from "../../../services/shortcuts";
import froca from "../../../services/froca";
import contextMenu from "../../../menus/context_menu";
import type { CommandData, FilteredCommandNames } from "../../../components/app_context";
@@ -287,6 +288,11 @@ export default function AttributeEditor({ api, note, componentId, notePath, ntxI
ref={wrapperRef}
style="position: relative; padding-top: 10px; padding-bottom: 10px"
onKeyDown={(e) => {
// Skip processing during IME composition
if (isIMEComposing(e)) {
return;
}
if (e.key === "Enter") {
// allow autocomplete to fill the result textarea
setTimeout(() => save(), 100);

View File

@@ -388,7 +388,7 @@ async function setupFonts() {
if (!glob.isDev) {
path = `${window.location.pathname}/node_modules/@excalidraw/excalidraw/dist/prod`;
} else {
path = (await import("../../../node_modules/@excalidraw/excalidraw/dist/prod/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2?url")).default;
path = (await import("../../../../../node_modules/@excalidraw/excalidraw/dist/prod/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2?url")).default;
let pathComponents = path.split("/");
path = pathComponents.slice(0, pathComponents.length - 2).join("/");
}

View File

@@ -4,7 +4,7 @@ import { buildExtraCommands, type EditorConfig, PREMIUM_PLUGINS } from "@trilium
import { getHighlightJsNameForMime } from "../../../services/mime_types.js";
import options from "../../../services/options.js";
import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js";
import emojiDefinitionsUrl from "@triliumnext/ckeditor5/emoji_definitions/en.json?url";
import emojiDefinitionsUrl from "@triliumnext/ckeditor5/src/emoji_definitions/en.json?url";
import { copyTextWithToast } from "../../../services/clipboard_ext.js";
import getTemplates from "./snippets.js";
import { t } from "../../../services/i18n.js";

View File

@@ -1,5 +1,6 @@
import utils from "../../../services/utils.js";
import options from "../../../services/options.js";
import IconAlignCenter from "@ckeditor/ckeditor5-icons/theme/icons/align-center.svg?raw";
const TEXT_FORMATTING_GROUP = {
label: "Text formatting",
@@ -77,7 +78,7 @@ export function buildClassicToolbar(multilineToolbar: boolean) {
items: ["imageUpload", "|", "link", "bookmark", "internallink", "includeNote", "|", "specialCharacters", "emoji", "math", "mermaid", "horizontalLine", "pageBreak", "dateTime"]
},
"|",
"alignment",
buildAlignmentToolbar(),
"outdent",
"indent",
"|",
@@ -134,7 +135,7 @@ export function buildFloatingToolbar() {
items: ["link", "bookmark", "internallink", "includeNote", "|", "math", "mermaid", "horizontalLine", "pageBreak", "dateTime"]
},
"|",
"alignment",
buildAlignmentToolbar(),
"outdent",
"indent",
"|",
@@ -147,3 +148,11 @@ export function buildFloatingToolbar() {
]
};
}
function buildAlignmentToolbar() {
return {
label: "Alignment",
icon: IconAlignCenter,
items: ["alignment:left", "alignment:center", "alignment:right", "|", "alignment:justify"]
};
}

View File

@@ -12,7 +12,6 @@ import { buildSelectedBackgroundColor } from "../../components/touch_bar.js";
import { buildConfig, BuildEditorOptions, OPEN_SOURCE_LICENSE_KEY } from "./ckeditor/config.js";
import type FNote from "../../entities/fnote.js";
import { PopupEditor, ClassicEditor, EditorWatchdog, type CKTextEditor, type MentionFeed, type WatchdogConfig, EditorConfig } from "@triliumnext/ckeditor5";
import "@triliumnext/ckeditor5/index.css";
import { updateTemplateCache } from "./ckeditor/snippets.js";
const TPL = /*html*/`

View File

@@ -266,9 +266,20 @@ function Performance() {
label={t("ui-performance.enable-backdrop-effects")}
currentValue={backdropEffectsEnabled} onChange={setBackdropEffectsEnabled}
/>
{isElectron() && <SmoothScrollEnabledOption />}
</OptionsSection>
}
function SmoothScrollEnabledOption() {
const [ smoothScrollEnabled, setSmoothScrollEnabled ] = useTriliumOptionBool("smoothScrollEnabled");
return <FormCheckbox
label={`${t("ui-performance.enable-smooth-scroll")} ${t("ui-performance.app-restart-required")}`}
currentValue={smoothScrollEnabled} onChange={setSmoothScrollEnabled}
/>
}
function MaxContentWidth() {
const [ maxContentWidth, setMaxContentWidth ] = useTriliumOption("maxContentWidth");

View File

@@ -1,6 +1,7 @@
import type { EventData } from "../../components/app_context.js";
import type FNote from "../../entities/fnote.js";
import AbstractCodeTypeWidget from "./abstract_code_type_widget.js";
import utils from "../../services/utils.js";
const TPL = /*html*/`
<div class="note-detail-readonly-code note-detail-printable">
@@ -33,7 +34,7 @@ export default class ReadOnlyCodeTypeWidget extends AbstractCodeTypeWidget {
if (!blob) return;
const isFormattable = note.type === "text" && this.noteContext?.viewScope?.viewMode === "source";
const content = isFormattable ? this.format(blob.content) : blob.content;
const content = isFormattable ? utils.formatHtml(blob.content) : blob.content;
this._update(note, content);
this.show();
@@ -54,52 +55,4 @@ export default class ReadOnlyCodeTypeWidget extends AbstractCodeTypeWidget {
resolve(this.$editor);
}
format(html: string) {
let indent = "\n";
const tab = "\t";
let i = 0;
let pre: { indent: string; tag: string }[] = [];
html = html
.replace(new RegExp("<pre>((.|\\t|\\n|\\r)+)?</pre>"), function (x) {
pre.push({ indent: "", tag: x });
return "<--TEMPPRE" + i++ + "/-->";
})
.replace(new RegExp("<[^<>]+>[^<]?", "g"), function (x) {
let ret;
const tagRegEx = /<\/?([^\s/>]+)/.exec(x);
let tag = tagRegEx ? tagRegEx[1] : "";
let p = new RegExp("<--TEMPPRE(\\d+)/-->").exec(x);
if (p) {
const pInd = parseInt(p[1]);
pre[pInd].indent = indent;
}
if (["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr"].indexOf(tag) >= 0) {
// self closing tag
ret = indent + x;
} else {
if (x.indexOf("</") < 0) {
//open tag
if (x.charAt(x.length - 1) !== ">") ret = indent + x.substr(0, x.length - 1) + indent + tab + x.substr(x.length - 1, x.length);
else ret = indent + x;
!p && (indent += tab);
} else {
//close tag
indent = indent.substr(0, indent.length - 1);
if (x.charAt(x.length - 1) !== ">") ret = indent + x.substr(0, x.length - 1) + indent + x.substr(x.length - 1, x.length);
else ret = indent + x;
}
}
return ret;
});
for (i = pre.length; i--;) {
html = html.replace("<--TEMPPRE" + i + "/-->", pre[i].tag.replace("<pre>", "<pre>\n").replace("</pre>", pre[i].indent + "</pre>"));
}
return html.charAt(0) === "\n" ? html.substr(1, html.length - 1) : html;
}
}

View File

@@ -2,26 +2,23 @@
import { join, resolve } from 'path';
import { defineConfig, type Plugin } from 'vite';
import { viteStaticCopy } from 'vite-plugin-static-copy'
import asset_path from './src/asset_path';
import webpackStatsPlugin from 'rollup-plugin-webpack-stats';
import preact from "@preact/preset-vite";
const assets = [ "assets", "stylesheets", "fonts", "translations" ];
export default defineConfig(() => ({
root: __dirname,
cacheDir: '../../node_modules/.vite/apps/client',
base: process.env.NODE_ENV === "production" ? "" : asset_path,
server: {
port: 4200,
host: 'localhost',
},
preview: {
port: 4300,
host: 'localhost',
},
plugins: [
preact(),
const isDev = process.env.NODE_ENV === "development";
let plugins: any = [
preact({
babel: {
compact: !isDev
}
})
];
if (!isDev) {
plugins = [
...plugins,
viteStaticCopy({
targets: assets.map((asset) => ({
src: `src/${asset}/*`,
@@ -32,13 +29,20 @@ export default defineConfig(() => ({
structured: true,
targets: [
{
src: "node_modules/@excalidraw/excalidraw/dist/prod/fonts/*",
src: "../../node_modules/@excalidraw/excalidraw/dist/prod/fonts/*",
dest: "",
}
]
}),
webpackStatsPlugin()
] as Plugin[],
]
}
export default defineConfig(() => ({
root: __dirname,
cacheDir: '../../node_modules/.vite/apps/client',
base: "",
plugins,
resolve: {
alias: [
{
@@ -58,10 +62,6 @@ export default defineConfig(() => ({
"preact/hooks"
]
},
// Uncomment this if you are using workers.
// worker: {
// plugins: [ nxViteTsPaths() ],
// },
build: {
target: "esnext",
outDir: './dist',
@@ -100,18 +100,6 @@ export default defineConfig(() => ({
"./src/test/setup.ts"
]
},
optimizeDeps: {
exclude: [
"@triliumnext/highlightjs"
]
},
css: {
preprocessorOptions: {
scss: {
quietDeps: true
}
}
},
commonjsOptions: {
transformMixedEsModules: true,
},

View File

@@ -6,12 +6,12 @@
To build and run manually:
```sh
nx build db-compare
pnpm build db-compare
node ./apps/db-compare/dist/compare.js
```
To serve development build with arguments:
```sh
nx serve db-compare --args "apps/server/spec/db/document_v214.db" --args "apps/server/spec/db/document_v214_migrated.db"
pnpm dev --args "apps/server/spec/db/document_v214.db" --args "apps/server/spec/db/document_v214_migrated.db"
```

View File

@@ -9,63 +9,8 @@
"sqlite": "5.1.1",
"sqlite3": "5.1.7"
},
"nx": {
"name": "db-compare",
"targets": {
"build": {
"executor": "@nx/esbuild:esbuild",
"outputs": [
"{options.outputPath}"
],
"defaultConfiguration": "production",
"options": {
"platform": "node",
"outputPath": "apps/db-compare/dist",
"format": [
"cjs"
],
"bundle": false,
"main": "apps/db-compare/src/compare.ts",
"tsConfig": "apps/db-compare/tsconfig.app.json",
"assets": [],
"esbuildOptions": {
"sourcemap": true,
"outExtension": {
".js": ".js"
}
}
},
"configurations": {
"development": {},
"production": {
"esbuildOptions": {
"sourcemap": false,
"outExtension": {
".js": ".js"
}
}
}
}
},
"serve": {
"executor": "@nx/js:node",
"defaultConfiguration": "development",
"dependsOn": [
"build"
],
"options": {
"buildTarget": "db-compare:build",
"runBuildTargetDependencies": false
},
"configurations": {
"development": {
"buildTarget": "db-compare:build:development"
},
"production": {
"buildTarget": "db-compare:build:production"
}
}
}
}
"scripts": {
"dev": "tsx src/compare.ts",
"build": "esbuild --platform=node --format=cjs --outdir=dist src/compare.ts"
}
}

View File

@@ -1,3 +0,0 @@
TRILIUM_INTEGRATION_TEST=memory-no-store
TRILIUM_PORT=8082
TRILIUM_DATA_DIR=data

View File

@@ -1,15 +0,0 @@
import playwright from "eslint-plugin-playwright";
import baseConfig from "../../eslint.config.mjs";
export default [
playwright.configs["flat/recommended"],
...baseConfig,
{
files: [
"**/*.ts",
"**/*.js"
],
// Override or add rules here
rules: {}
}
];

View File

@@ -1,24 +0,0 @@
{
"name": "@triliumnext/desktop-e2e",
"version": "0.0.1",
"private": true,
"nx": {
"name": "desktop-e2e",
"implicitDependencies": [
"client",
"desktop"
],
"targets": {
"e2e": {
"dependsOn": [
"desktop:build",
"desktop:rebuild-deps"
]
}
}
},
"devDependencies": {
"dotenv": "17.2.1",
"electron": "37.4.0"
}
}

View File

@@ -1,25 +0,0 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"allowJs": true,
"outDir": "out-tsc/playwright",
"sourceMap": false
},
"include": [
"**/*.ts",
"**/*.js",
"playwright.config.ts",
"src/**/*.spec.ts",
"src/**/*.spec.js",
"src/**/*.test.ts",
"src/**/*.test.js",
"src/**/*.d.ts"
],
"exclude": [
"out-tsc",
"test-output",
"eslint.config.js",
"eslint.config.mjs",
"eslint.config.cjs"
]
}

View File

@@ -1 +0,0 @@
node-linker = hoisted

View File

@@ -1 +0,0 @@
TRILIUM_PORT=37743

View File

@@ -1,3 +0,0 @@
TRILIUM_PORT=37741
TRILIUM_DATA_DIR=../data
NODE_OPTIONS=--enable-source-maps

View File

@@ -60,7 +60,7 @@ test('First setup', async () => {
// Verify the shared link is valid
const requestContext = await request.newContext();
const response = await requestContext.get(linkUrl!);
expect(response).toBeOK();
await expect(response).toBeOK();
await mainWindow.waitForTimeout(5000);
});

View File

@@ -3,7 +3,23 @@
"version": "0.98.1",
"description": "Build your personal knowledge base with Trilium Notes",
"private": true,
"main": "main.cjs",
"main": "src/main.ts",
"license": "AGPL-3.0-only",
"author": {
"name": "Trilium Notes Team",
"email": "contact@eliandoran.me",
"url": "https://github.com/TriliumNext/Notes"
},
"scripts": {
"dev": "cross-env TRILIUM_PORT=37741 TRILIUM_DATA_DIR=data tsx ../../scripts/electron-start.mts src/main.ts",
"start-no-dir": "cross-env TRILIUM_PORT=37743 tsx ../../scripts/electron-start.mts src/main.ts",
"build": "tsx scripts/build.ts",
"start-prod": "pnpm build && cross-env TRILIUM_DATA_DIR=data TRILIUM_PORT=37841 ELECTRON_IS_DEV=0 electron dist",
"electron-forge:make": "pnpm build && cross-env electron-forge make dist",
"electron-forge:package": "pnpm build && electron-forge package dist",
"electron-forge:start": "pnpm build && electron-forge start dist",
"e2e": "pnpm build && cross-env TRILIUM_INTEGRATION_TEST=memory-no-store TRILIUM_PORT=8082 TRILIUM_DATA_DIR=data-e2e ELECTRON_IS_DEV=0 playwright test"
},
"dependencies": {
"@electron/remote": "2.1.3",
"better-sqlite3": "^12.0.0",
@@ -15,6 +31,7 @@
},
"devDependencies": {
"@types/electron-squirrel-startup": "1.0.2",
"@triliumnext/commons": "workspace:*",
"@triliumnext/server": "workspace:*",
"copy-webpack-plugin": "13.0.1",
"electron": "37.4.0",
@@ -27,174 +44,5 @@
"@electron-forge/maker-zip": "7.8.3",
"@electron-forge/plugin-auto-unpack-natives": "7.8.3",
"prebuild-install": "^7.1.1"
},
"config": {
"forge": "./electron-forge/forge.config.ts"
},
"scripts": {
"start-prod": "nx build desktop && cross-env TRILIUM_DATA_DIR=data TRILIUM_RESOURCE_DIR=dist TRILIUM_PORT=37841 electron dist/main.js"
},
"license": "AGPL-3.0-only",
"author": {
"name": "Trilium Notes Team",
"email": "contact@eliandoran.me",
"url": "https://github.com/TriliumNext/Notes"
},
"nx": {
"name": "desktop",
"targets": {
"build": {
"executor": "@nx/esbuild:esbuild",
"outputs": [
"{options.outputPath}"
],
"defaultConfiguration": "production",
"configurations": {
"production": {
"minify": true,
"sourcemap": false
},
"development": {
"minify": false,
"sourcemap": true
}
},
"options": {
"main": "apps/desktop/src/electron-main.ts",
"outputPath": "apps/desktop/dist",
"outputFileName": "main.js",
"tsConfig": "apps/desktop/tsconfig.app.json",
"platform": "node",
"external": [
"electron",
"@electron/remote",
"better-sqlite3",
"./xhr-sync-worker.js"
],
"format": [
"cjs"
],
"thirdParty": true,
"declaration": false,
"esbuildOptions": {
"splitting": false,
"loader": {
".css": "text"
}
},
"assets": [
{
"glob": "**/*",
"input": "apps/server/dist/node_modules",
"output": "node_modules"
},
{
"glob": "**/*",
"input": "apps/desktop/node_modules/@electron/remote",
"output": "node_modules/@electron/remote"
},
{
"glob": "**/*",
"input": "apps/server/dist/assets",
"output": "assets"
},
{
"glob": "**/*",
"input": "packages/share-theme/src/templates",
"output": "share-theme/templates"
},
{
"glob": "**/*",
"input": "apps/desktop/src/assets",
"output": "assets"
},
{
"glob": "**/*",
"input": "apps/server/dist/public",
"output": "public"
},
{
"glob": "xhr-sync-worker.js",
"input": "apps/server/node_modules/jsdom/lib/jsdom/living/xhr",
"output": ""
}
],
"declarationRootDir": "apps/desktop/src"
}
},
"rebuild-deps": {
"executor": "nx:run-commands",
"dependsOn": [
"build"
],
"defaultConfiguration": "default",
"cache": false,
"configurations": {
"default": {
"command": "cross-env DEBUG=* tsx scripts/electron-rebuild.mts {projectRoot}/dist"
},
"nixos": {
"command": "cross-env DEBUG=* tsx scripts/electron-rebuild.mts {projectRoot}/dist $(nix-shell -p electron_35 --run \"electron --version\")"
}
}
},
"serve": {
"executor": "nx:run-commands",
"dependsOn": [
"rebuild-deps"
],
"defaultConfiguration": "default",
"configurations": {
"default": {
"command": "electron main.cjs",
"cwd": "{projectRoot}/dist"
},
"nixos": {
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.cjs\"",
"cwd": ".",
"forwardAllArgs": false
}
}
},
"serve-nodir": {
"executor": "nx:run-commands",
"dependsOn": [
"rebuild-deps"
],
"defaultConfiguration": "default",
"configurations": {
"default": {
"command": "electron main.cjs",
"cwd": "{projectRoot}/dist"
},
"nixos": {
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.cjs\"",
"cwd": ".",
"forwardAllArgs": false
}
}
},
"electron-forge:make": {
"dependsOn": [
"build",
"rebuild-deps"
],
"command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm electron-forge make dist"
},
"electron-forge:package": {
"dependsOn": [
"build",
"rebuild-deps"
],
"command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm electron-forge package dist"
},
"electron-forge:start": {
"dependsOn": [
"build",
"rebuild-deps"
],
"command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm TRILIUM_DATA_DIR=./data electron-forge start dist"
}
}
}
}
}

View File

@@ -1,10 +1,5 @@
import { defineConfig, devices } from '@playwright/test';
require('dotenv').config({
path: __dirname + "/" + ".env"
});
/**
* See https://playwright.dev/docs/test-configuration.
*/
@@ -14,6 +9,8 @@ export default defineConfig({
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},
testDir: "e2e",
outputDir: "test-output",
projects: [
{
name: "chromium",

View File

@@ -0,0 +1,46 @@
import { join } from "path";
import BuildHelper from "../../../scripts/build-utils";
import originalPackageJson from "../package.json" with { type: "json" };
import { writeFileSync } from "fs";
const build = new BuildHelper("apps/desktop");
async function main() {
await build.buildBackend([ "src/main.ts"]);
// Copy assets.
build.copy("src/assets", "assets/");
build.copy("/apps/server/src/assets", "assets/");
build.copy("/packages/share-theme/src/templates", "share-theme/templates/");
// Copy node modules dependencies
build.copyNodeModules([ "better-sqlite3", "bindings", "file-uri-to-path", "@electron/remote" ]);
build.copy("/node_modules/jsdom/lib/jsdom/living/xhr/xhr-sync-worker.js", "xhr-sync-worker.js");
// Integrate the client.
build.triggerBuildAndCopyTo("apps/client", "public/");
build.deleteFromOutput("public/webpack-stats.json");
generatePackageJson();
}
function generatePackageJson() {
const { version, author, license, description, dependencies, devDependencies } = originalPackageJson;
const packageJson = {
name: "trilium",
main: "main.cjs",
version, author, license, description,
dependencies: {
"better-sqlite3": dependencies["better-sqlite3"],
},
devDependencies: {
electron: devDependencies.electron
},
config: {
forge: "../electron-forge/forge.config.ts"
}
};
writeFileSync(join(build.outDir, "package.json"), JSON.stringify(packageJson, null, "\t"), "utf-8");
}
main();

View File

@@ -25,6 +25,12 @@ async function main() {
// needed for excalidraw export https://github.com/zadam/trilium/issues/4271
electron.app.commandLine.appendSwitch("enable-experimental-web-platform-features");
electron.app.commandLine.appendSwitch("lang", options.getOptionOrNull("formattingLocale") ?? "en");
// Disable smooth scroll if the option is set
const smoothScrollEnabled = options.getOptionOrNull("smoothScrollEnabled");
if (smoothScrollEnabled === "false") {
electron.app.commandLine.appendSwitch("disable-smooth-scrolling");
}
// Electron 36 crashes with "Using GTK 2/3 and GTK 4 in the same process is not supported" on some distributions.
// See https://github.com/electron/electron/issues/46538 for more info.

View File

@@ -15,65 +15,8 @@
"@types/mime-types": "^3.0.0",
"@types/yargs": "^17.0.33"
},
"nx": {
"name": "dump-db",
"targets": {
"build": {
"executor": "@nx/esbuild:esbuild",
"outputs": [
"{options.outputPath}"
],
"defaultConfiguration": "production",
"options": {
"platform": "node",
"outputPath": "apps/dump-db/dist",
"format": [
"cjs"
],
"bundle": false,
"main": "apps/dump-db/src/main.ts",
"tsConfig": "apps/dump-db/tsconfig.app.json",
"assets": [
"apps/dump-db/src/assets"
],
"esbuildOptions": {
"sourcemap": true,
"outExtension": {
".js": ".js"
}
}
},
"configurations": {
"development": {},
"production": {
"esbuildOptions": {
"sourcemap": false,
"outExtension": {
".js": ".js"
}
}
}
}
},
"serve": {
"executor": "@nx/js:node",
"defaultConfiguration": "development",
"dependsOn": [
"build"
],
"options": {
"buildTarget": "dump-db:build",
"runBuildTargetDependencies": false
},
"configurations": {
"development": {
"buildTarget": "dump-db:build:development"
},
"production": {
"buildTarget": "dump-db:build:production"
}
}
}
}
"scripts": {
"dev": "tsx src/main.ts",
"build": "esbuild --platform=node --format=cjs --outdir=dist src/main.ts"
}
}

View File

@@ -1,7 +0,0 @@
TRILIUM_DATA_DIR=../data
TRILIUM_INTEGRATION_TEST=memory-no-store
TRILIUM_PORT=37741
# Paths are relative to dist root
DOCS_ROOT=../../../docs
USER_GUIDE_ROOT=../../../apps/server/src/assets/doc_notes/en/User Guide

View File

@@ -15,120 +15,8 @@
"electron": "37.4.0",
"fs-extra": "11.3.1"
},
"nx": {
"name": "edit-docs",
"implicitDependencies": [
"server"
],
"targets": {
"build": {
"executor": "@nx/esbuild:esbuild",
"outputs": [
"{options.outputPath}"
],
"options": {
"main": "apps/edit-docs/src/edit-docs.ts",
"outputPath": "apps/edit-docs/dist",
"tsConfig": "apps/edit-docs/tsconfig.app.json",
"platform": "node",
"additionalEntryPoints": [
"apps/edit-docs/src/edit-demo.ts"
],
"external": [
"electron",
"@electron/remote",
"better-sqlite3",
"./xhr-sync-worker.js"
],
"format": [
"cjs"
],
"minify": false,
"thirdParty": true,
"declaration": false,
"esbuildOptions": {
"splitting": false,
"loader": {
".css": "text"
}
},
"assets": [
{
"glob": "**/*",
"input": "apps/server/dist/node_modules",
"output": "node_modules"
},
{
"glob": "**/*",
"input": "apps/server/dist/assets",
"output": "assets"
},
{
"glob": "**/*",
"input": "apps/server/dist/public",
"output": "public"
},
{
"glob": "xhr-sync-worker.js",
"input": "apps/server/node_modules/jsdom/lib/jsdom/living/xhr",
"output": ""
}
],
"declarationRootDir": "apps/edit-docs/src"
}
},
"rebuild-deps": {
"executor": "nx:run-commands",
"dependsOn": [
"build"
],
"defaultConfiguration": "default",
"cache": true,
"configurations": {
"default": {
"command": "cross-env DEBUG=* tsx scripts/electron-rebuild.mts {projectRoot}/dist"
},
"nixos": {
"command": "cross-env DEBUG=* tsx scripts/electron-rebuild.mts {projectRoot}/dist $(nix-shell -p electron_35 --run \"electron --version\")"
}
}
},
"edit-docs": {
"executor": "nx:run-commands",
"dependsOn": [
"rebuild-deps"
],
"defaultConfiguration": "default",
"configurations": {
"default": {
"command": "electron edit-docs.cjs",
"cwd": "{projectRoot}/dist"
},
"nixos": {
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/edit-docs.cjs\"",
"cwd": ".",
"forwardAllArgs": false
}
}
},
"edit-demo": {
"executor": "nx:run-commands",
"dependsOn": [
"rebuild-deps"
],
"defaultConfiguration": "default",
"configurations": {
"default": {
"command": "electron edit-demo.cjs",
"cwd": "{projectRoot}/dist"
},
"nixos": {
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/edit-demo.cjs\"",
"cwd": ".",
"forwardAllArgs": false
}
}
}
}
}
"scripts": {
"edit-docs": "cross-env TRILIUM_PORT=37741 TRILIUM_DATA_DIR=data TRILIUM_INTEGRATION_TEST=memory-no-store DOCS_ROOT=../../../docs USER_GUIDE_ROOT=\"../../server/src/assets/doc_notes/en/User Guide\" tsx ../../scripts/electron-start.mts src/edit-docs.ts",
"edit-demo": "cross-env TRILIUM_PORT=37741 TRILIUM_DATA_DIR=data TRILIUM_INTEGRATION_TEST=memory-no-store DOCS_ROOT=../../../docs USER_GUIDE_ROOT=\"../../server/src/assets/doc_notes/en/User Guide\" tsx ../../scripts/electron-start.mts src/edit-demo.ts"
}
}

View File

@@ -1,3 +0,0 @@
TRILIUM_INTEGRATION_TEST=memory
TRILIUM_PORT=8082
TRILIUM_DATA_DIR=apps/server/spec/db

View File

@@ -2,21 +2,10 @@
"name": "@triliumnext/server-e2e",
"version": "0.0.1",
"private": true,
"nx": {
"name": "server-e2e",
"implicitDependencies": [
"client",
"server"
],
"targets": {
"e2e": {
"dependsOn": [
"server:build"
]
}
}
"scripts": {
"e2e": "playwright test"
},
"devDependencies": {
"dotenv": "17.2.1"
"dotenv": "17.2.2"
}
}

View File

@@ -1,68 +1,44 @@
import { defineConfig, devices } from '@playwright/test';
import { nxE2EPreset } from '@nx/playwright/preset';
import { workspaceRoot } from '@nx/devkit';
require('dotenv').config({
path: __dirname + "/" + ".env"
});
import { join } from 'path';
// For CI, you may want to set BASE_URL to the deployed application.
const port = process.env['TRILIUM_PORT'];
const port = process.env['TRILIUM_PORT'] ?? "8082";
const baseURL = process.env['BASE_URL'] || `http://127.0.0.1:${port}`;
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
...nxE2EPreset(__filename, { testDir: './src' }),
testDir: "src",
reporter: [["list"], ["html", { outputFolder: "test-output" }]],
outputDir: "test-output",
retries: 3,
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
baseURL,
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},
/* Run your local dev server before starting the tests */
webServer: !process.env.TRILIUM_DOCKER ? {
command: 'pnpm server:start-prod',
command: 'pnpm start-prod-no-dir',
url: baseURL,
reuseExistingServer: !process.env.CI,
cwd: workspaceRoot,
cwd: join(__dirname, "../server"),
env: {
TRILIUM_DATA_DIR: "spec/db",
TRILIUM_PORT: port,
TRILIUM_INTEGRATION_TEST: "memory"
},
timeout: 5 * 60 * 1000
} : undefined,
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
// {
// name: "firefox",
// use: { ...devices["Desktop Firefox"] },
// },
// {
// name: "webkit",
// use: { ...devices["Desktop Safari"] },
// },
// Uncomment for mobile browsers support
/* {
name: 'Mobile Chrome',
use: { ...devices['Pixel 5'] },
},
{
name: 'Mobile Safari',
use: { ...devices['iPhone 12'] },
}, */
// Uncomment for branded browsers
/* {
name: 'Microsoft Edge',
use: { ...devices['Desktop Edge'], channel: 'msedge' },
},
{
name: 'Google Chrome',
use: { ...devices['Desktop Chrome'], channel: 'chrome' },
} */
],
}
]
});

View File

@@ -79,7 +79,7 @@ test("Tabs are restored in right order", async ({ page, context }) => {
// Refresh the page and check the order.
await app.goto( { preserveTabs: true });
await expect(app.getTab(0)).toContainText("Code notes");
await expect(app.getTab(0)).toContainText("Code notes", { timeout: 15_000 });
await expect(app.getTab(1)).toContainText("Text notes");
await expect(app.getTab(2)).toContainText("Mermaid");

View File

@@ -1,6 +0,0 @@
TRILIUM_ENV=dev
TRILIUM_DATA_DIR=./apps/server/spec/db
TRILIUM_RESOURCE_DIR=./apps/server/dist
TRILIUM_PUBLIC_SERVER=http://localhost:4200
TRILIUM_PORT=8086
TRILIUM_INTEGRATION_TEST=edit

View File

@@ -1,3 +0,0 @@
TRILIUM_ENV=dev
TRILIUM_RESOURCE_DIR=./apps/server/dist
TRILIUM_PUBLIC_SERVER=http://localhost:4200

View File

@@ -1,4 +0,0 @@
TRILIUM_ENV=dev
TRILIUM_DATA_DIR=./apps/server/data
TRILIUM_RESOURCE_DIR=./apps/server/src
TRILIUM_PUBLIC_SERVER=http://localhost:4200

View File

@@ -1,3 +0,0 @@
TRILIUM_ENV=production
TRILIUM_DATA_DIR=./apps/server/data
TRILIUM_PORT=8082

View File

@@ -1,4 +0,0 @@
TRILIUM_ENV=dev
TRILIUM_DATA_DIR=./spec/db
TRILIUM_PUBLIC_SERVER=http://localhost:4200
TRILIUM_INTEGRATION_TEST=memory

View File

@@ -1,4 +1,4 @@
FROM node:22.18.0-bullseye-slim AS builder
FROM node:22.19.0-bullseye-slim AS builder
RUN corepack enable
# Install native dependencies since we might be building cross-platform.
@@ -7,7 +7,7 @@ COPY ./docker/package.json ./docker/pnpm-workspace.yaml /usr/src/app/
# We have to use --no-frozen-lockfile due to CKEditor patches
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
FROM node:22.18.0-bullseye-slim
FROM node:22.19.0-bullseye-slim
# Install only runtime dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \

View File

@@ -1,4 +1,4 @@
FROM node:22.18.0-alpine AS builder
FROM node:22.19.0-alpine AS builder
RUN corepack enable
# Install native dependencies since we might be building cross-platform.
@@ -7,7 +7,7 @@ COPY ./docker/package.json ./docker/pnpm-workspace.yaml /usr/src/app/
# We have to use --no-frozen-lockfile due to CKEditor patches
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
FROM node:22.18.0-alpine
FROM node:22.19.0-alpine
# Install runtime dependencies
RUN apk add --no-cache su-exec shadow

View File

@@ -1,4 +1,4 @@
FROM node:22.18.0-alpine AS builder
FROM node:22.19.0-alpine AS builder
RUN corepack enable
# Install native dependencies since we might be building cross-platform.
@@ -7,7 +7,7 @@ COPY ./docker/package.json ./docker/pnpm-workspace.yaml /usr/src/app/
# We have to use --no-frozen-lockfile due to CKEditor patches
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
FROM node:22.18.0-alpine
FROM node:22.19.0-alpine
# Create a non-root user with configurable UID/GID
ARG USER=trilium
ARG UID=1001

View File

@@ -1,4 +1,4 @@
FROM node:22.18.0-bullseye-slim AS builder
FROM node:22.19.0-bullseye-slim AS builder
RUN corepack enable
# Install native dependencies since we might be building cross-platform.
@@ -7,7 +7,7 @@ COPY ./docker/package.json ./docker/pnpm-workspace.yaml /usr/src/app/
# We have to use --no-frozen-lockfile due to CKEditor patches
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
FROM node:22.18.0-bullseye-slim
FROM node:22.19.0-bullseye-slim
# Create a non-root user with configurable UID/GID
ARG USER=trilium
ARG UID=1001

View File

@@ -3,11 +3,38 @@
"version": "0.98.1",
"description": "The server-side component of TriliumNext, which exposes the client via the web, allows for sync and provides a REST API for both internal and external use.",
"private": true,
"main": "./src/main.ts",
"scripts": {
"dev": "cross-env NODE_ENV=development TRILIUM_ENV=dev TRILIUM_DATA_DIR=data TRILIUM_RESOURCE_DIR=src tsx watch --ignore '../client/node_modules/.vite-temp' ./src/main.ts",
"start-no-dir": "cross-env NODE_ENV=development TRILIUM_ENV=dev TRILIUM_RESOURCE_DIR=src tsx watch --ignore '../client/node_modules/.vite-temp' ./src/main.ts",
"edit-integration-db": "cross-env NODE_ENV=development TRILIUM_PORT=8086 TRILIUM_ENV=dev TRILIUM_DATA_DIR=spec/db TRILIUM_INTEGRATION_TEST=edit TRILIUM_RESOURCE_DIR=src tsx watch --ignore '../client/node_modules/.vite-temp' ./src/main.ts",
"build": "tsx scripts/build.ts",
"package": "pnpm build && bash scripts/build-server.sh",
"test": "vitest",
"test-build": "vitest --config vitest.build.config.mts",
"start-prod": "cross-env TRILIUM_DATA_DIR=data pnpm start-prod-no-dir",
"start-prod-no-dir": "pnpm build && cross-env TRILIUM_ENV=production TRILIUM_PORT=8082 node dist/main.cjs",
"circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular",
"docker-build-debian": "pnpm build && docker build . -t triliumnext-debian -f Dockerfile",
"docker-build-alpine": "pnpm build && docker build . -t triliumnext-alpine -f Dockerfile.alpine",
"docker-build-rootless-debian": "pnpm build && docker build . -t triliumnext-rootless-debian -f Dockerfile.rootless",
"docker-build-rootless-alpine": "pnpm build && docker build . -t triliumnext-rootless-alpine -f Dockerfile.alpine.rootless",
"docker-start-debian": "pnpm docker-build-debian && docker run -p 8081:8080 triliumnext-debian",
"docker-start-alpine": "pnpm docker-build-alpine && docker run -p 8081:8080 triliumnext-alpine",
"docker-start-rootless-debian": "pnpm docker-build-rootless-debian && docker run -p 8081:8080 triliumnext-rootless-debian",
"docker-start-rootless-alpine": "pnpm docker-build-rootless-alpine && docker run -p 8081:8080 triliumnext-rootless-alpine"
},
"dependencies": {
"better-sqlite3": "12.2.0"
},
"devDependencies": {
"@anthropic-ai/sdk": "0.61.0",
"@braintree/sanitize-url": "7.1.1",
"@electron/remote": "2.1.3",
"@preact/preset-vite": "2.10.2",
"@triliumnext/commons": "workspace:*",
"@triliumnext/express-partial-content": "workspace:*",
"@triliumnext/turndown-plugin-gfm": "workspace:*",
"@types/archiver": "6.0.3",
"@types/better-sqlite3": "7.6.13",
"@types/cls-hooked": "4.3.9",
@@ -38,16 +65,11 @@
"@types/turndown": "5.0.5",
"@types/ws": "8.18.1",
"@types/xml2js": "0.4.14",
"express-http-proxy": "2.1.1",
"@anthropic-ai/sdk": "0.60.0",
"@braintree/sanitize-url": "7.1.1",
"@triliumnext/commons": "workspace:*",
"@triliumnext/express-partial-content": "workspace:*",
"@triliumnext/turndown-plugin-gfm": "workspace:*",
"archiver": "7.0.1",
"async-mutex": "0.5.0",
"axios": "1.11.0",
"bindings": "1.5.0",
"bootstrap": "5.3.8",
"chardet": "2.1.0",
"cheerio": "1.1.2",
"chokidar": "4.0.3",
@@ -55,7 +77,7 @@
"compression": "1.8.1",
"cookie-parser": "1.4.7",
"csrf-csrf": "3.2.2",
"dayjs": "1.11.14",
"dayjs": "1.11.18",
"debounce": "2.2.0",
"debug": "4.4.1",
"ejs": "3.1.10",
@@ -64,8 +86,9 @@
"electron-window-state": "5.0.3",
"escape-html": "1.0.3",
"express": "5.1.0",
"express-http-proxy": "2.1.1",
"express-openid-connect": "^2.17.1",
"express-rate-limit": "8.0.1",
"express-rate-limit": "8.1.0",
"express-session": "1.18.2",
"file-uri-to-path": "2.0.0",
"fs-extra": "11.3.1",
@@ -74,7 +97,7 @@
"html2plaintext": "2.1.4",
"http-proxy-agent": "7.0.2",
"https-proxy-agent": "7.0.6",
"i18next": "25.4.2",
"i18next": "25.5.2",
"i18next-fs-backend": "2.6.0",
"image-type": "6.0.0",
"ini": "5.0.0",
@@ -105,270 +128,9 @@
"tmp": "0.2.5",
"turndown": "7.2.1",
"unescape": "1.0.1",
"vite": "^7.1.3",
"ws": "8.18.3",
"xml2js": "0.6.2",
"yauzl": "3.2.0"
},
"nx": {
"name": "server",
"implicitDependencies": [
"share-theme"
],
"targets": {
"serve": {
"executor": "nx:run-commands",
"dependsOn": [
{
"projects": [
"client"
],
"target": "serve"
}
],
"continuous": true,
"options": {
"command": "tsx watch --conditions development {projectRoot}/src/main.ts"
}
},
"serve-nodir": {
"executor": "@nx/js:node",
"dependsOn": [
{
"projects": [
"client"
],
"target": "serve"
},
"build-without-client"
],
"continuous": true,
"options": {
"buildTarget": "server:build-without-client:development",
"runBuildTargetDependencies": false
}
},
"edit-integration-db": {
"executor": "@nx/js:node",
"dependsOn": [
{
"projects": [
"client"
],
"target": "serve"
},
"build-without-client"
],
"continuous": true,
"options": {
"buildTarget": "server:build-without-client:development",
"runBuildTargetDependencies": false
}
},
"package": {
"dependsOn": [
"build"
],
"command": "bash apps/server/scripts/build-server.sh"
},
"start-prod": {
"dependsOn": [
"build"
],
"command": "node apps/server/dist/main.cjs"
},
"docker-build": {
"dependsOn": [
"build"
],
"options": {
"cwd": "{projectRoot}"
},
"executor": "nx:run-commands",
"defaultConfiguration": "alpine",
"configurations": {
"debian": {
"command": "docker build . -t triliumnext-debian -f Dockerfile"
},
"alpine": {
"command": "docker build . -t triliumnext-alpine -f Dockerfile.alpine"
},
"rootless-debian": {
"command": "docker build . -t triliumnext-rootless-debian -f Dockerfile.rootless"
},
"rootless-alpine": {
"command": "docker build . -t triliumnext-rootless-alpine -f Dockerfile.alpine.rootless"
}
}
},
"docker-start": {
"dependsOn": [
"docker-build"
],
"executor": "nx:run-commands",
"defaultConfiguration": "alpine",
"configurations": {
"debian": {
"command": "docker run -p 8081:8080 triliumnext-debian"
},
"alpine": {
"command": "docker run -p 8081:8080 triliumnext-alpine"
},
"rootless-debian": {
"command": "docker run -p 8081:8080 triliumnext-rootless-debian"
},
"rootless-alpine": {
"command": "docker run -p 8081:8080 triliumnext-rootless-alpine"
}
}
},
"build-without-client": {
"executor": "@nx/esbuild:esbuild",
"outputs": [
"{options.outputPath}"
],
"options": {
"main": "apps/server/src/main.ts",
"outputPath": "apps/server/dist",
"outputFileName": "main.js",
"tsConfig": "apps/server/tsconfig.app.json",
"platform": "node",
"format": [
"cjs"
],
"esbuildOptions": {
"loader": {
".css": "text",
".ejs": "text"
}
},
"declarationRootDir": "apps/server/src",
"minify": false,
"sourcemap": true,
"assets": [
{
"glob": "**/*",
"input": "apps/server/src/assets",
"output": "assets"
},
{
"glob": "**/*",
"input": "packages/share-theme/src/templates",
"output": "share-theme/templates"
}
]
}
},
"build": {
"executor": "@nx/esbuild:esbuild",
"outputs": [
"{options.outputPath}"
],
"dependsOn": [
"^build",
"client:build"
],
"defaultConfiguration": "production",
"configurations": {
"production": {
"minify": true,
"sourcemap": false
},
"development": {
"minify": false,
"sourcemap": true
}
},
"options": {
"main": "apps/server/src/main.ts",
"outputPath": "apps/server/dist",
"tsConfig": "apps/server/tsconfig.app.json",
"platform": "node",
"external": [
"electron",
"@electron/remote",
"better-sqlite3",
"./xhr-sync-worker.js"
],
"format": [
"cjs"
],
"declarationRootDir": "apps/server/src",
"thirdParty": true,
"declaration": false,
"esbuildOptions": {
"splitting": false,
"loader": {
".css": "text",
".ejs": "text"
}
},
"additionalEntryPoints": [
"apps/server/src/docker_healthcheck.ts"
],
"assets": [
{
"glob": "**/*",
"input": "apps/server/src/assets",
"output": "assets"
},
{
"glob": "**/*",
"input": "packages/share-theme/src/templates",
"output": "share-theme/templates"
},
{
"glob": "**/*",
"input": "apps/client/dist",
"output": "public",
"ignore": [
"webpack-stats.json"
]
},
{
"glob": "**/*",
"input": "apps/server/node_modules/better-sqlite3",
"output": "node_modules/better-sqlite3"
},
{
"glob": "**/*",
"input": "apps/server/node_modules/bindings",
"output": "node_modules/bindings"
},
{
"glob": "**/*",
"input": "apps/server/node_modules/file-uri-to-path",
"output": "node_modules/file-uri-to-path"
},
{
"glob": "xhr-sync-worker.js",
"input": "apps/server/node_modules/jsdom/lib/jsdom/living/xhr",
"output": ""
}
]
}
},
"test-build": {
"dependsOn": [
"build"
],
"command": "vitest --config {projectRoot}/vitest.build.config.mts"
},
"circular-deps": {
"command": "pnpx dpdm -T {projectRoot}/src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
}
}
},
"exports": {
"./package.json": "./package.json",
"./src/*": "./src/*",
".": {
"development": "./src/main.ts",
"types": "./dist/main.d.ts",
"import": "./dist/main.js",
"default": "./dist/main.js"
}
},
"types": "./dist/main.d.ts",
"module": "./dist/main.js",
"main": "./dist/main.js"
}
}

View File

@@ -0,0 +1,22 @@
import BuildHelper from "../../../scripts/build-utils";
const build = new BuildHelper("apps/server");
async function main() {
await build.buildBackend([ "src/main.ts", "src/docker_healthcheck.ts" ])
// Copy assets
build.copy("src/assets", "assets/");
build.copy("/packages/share-theme/src/templates", "share-theme/templates/");
// Copy node modules dependencies
build.copyNodeModules([ "better-sqlite3", "bindings", "file-uri-to-path" ]);
build.copy("/node_modules/jsdom/lib/jsdom/living/xhr/xhr-sync-worker.js", "xhr-sync-worker.js");
build.copy("/node_modules/ckeditor5/dist/ckeditor5-content.css", "ckeditor5-content.css");
// Integrate the client.
build.triggerBuildAndCopyTo("apps/client", "public/");
build.deleteFromOutput("public/webpack-stats.json");
}
main();

View File

@@ -30,5 +30,5 @@ describe("etapi/import", () => {
.expect(201);
expect(response.body.note.title).toStrictEqual("Journal");
expect(response.body.branch.parentNoteId).toStrictEqual("root");
});
}, 10_000);
});

View File

@@ -74,7 +74,10 @@
"zoom-out": "Pomniejsz",
"zoom-in": "Powiększ",
"print-active-note": "Drukuj aktywną notatkę",
"toggle-full-screen": "Przełącz pełny ekran"
"toggle-full-screen": "Przełącz pełny ekran",
"cut-into-note": "Wycina zaznaczony tekst i tworzy podrzędną notatkę z tym tekstem",
"edit-readonly-note": "Edytuj notatkę tylko do odczytu",
"other": "Inne"
},
"keyboard_action_names": {
"zoom-in": "Powiększ",

View File

@@ -65,6 +65,7 @@ const ALLOWED_OPTIONS = new Set<OptionNames>([
"monthlyBackupEnabled",
"motionEnabled",
"shadowsEnabled",
"smoothScrollEnabled",
"backdropEffectsEnabled",
"maxContentWidth",
"compressImages",

View File

@@ -3,7 +3,6 @@ import path from "path";
import express from "express";
import { getResourceDir, isDev } from "../services/utils.js";
import type serveStatic from "serve-static";
import proxy from "express-http-proxy";
import { existsSync } from "fs";
const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOptions<express.Response<unknown, Record<string, unknown>>>) => {
@@ -17,17 +16,22 @@ const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOp
};
async function register(app: express.Application) {
const srcRoot = path.join(__dirname, "..");
const srcRoot = path.join(__dirname, "..", "..");
const resourceDir = getResourceDir();
if (isDev) {
const publicUrl = process.env.TRILIUM_PUBLIC_SERVER;
if (!publicUrl) {
throw new Error("Missing TRILIUM_PUBLIC_SERVER");
}
app.use("/" + assetUrlFragment + `/@fs`, proxy(publicUrl, {
proxyReqPathResolver: (req) => "/" + assetUrlFragment + `/@fs` + req.url
}));
if (process.env.NODE_ENV === "development") {
const { createServer: createViteServer } = await import("vite");
const vite = await createViteServer({
server: { middlewareMode: true },
appType: "custom",
cacheDir: path.join(srcRoot, "../../.cache/vite"),
base: `/${assetUrlFragment}/`,
root: path.join(srcRoot, "../client")
});
app.use(`/${assetUrlFragment}/`, (req, res, next) => {
req.url = `/${assetUrlFragment}` + req.url;
vite.middlewares(req, res, next);
});
} else {
const publicDir = path.join(resourceDir, "public");
if (!existsSync(publicDir)) {

View File

@@ -5,7 +5,7 @@ import attributeService from "../services/attributes.js";
import config from "../services/config.js";
import optionService from "../services/options.js";
import log from "../services/log.js";
import { isDev, isElectron } from "../services/utils.js";
import { isDev, isElectron, isWindows11 } from "../services/utils.js";
import protectedSessionService from "../services/protected_session.js";
import packageJson from "../../package.json" with { type: "json" };
import assetPath from "../services/asset_path.js";
@@ -42,7 +42,7 @@ function index(req: Request, res: Response) {
platform: process.platform,
isElectron,
hasNativeTitleBar: isElectron && options.nativeTitleBarVisible === "true",
hasBackgroundEffects: isElectron && options.backgroundEffects === "true",
hasBackgroundEffects: isElectron && isWindows11 && options.backgroundEffects === "true",
mainFontSize: parseInt(options.mainFontSize),
treeFontSize: parseInt(options.treeFontSize),
detailFontSize: parseInt(options.detailFontSize),

View File

@@ -1,3 +1,4 @@
import assetPath from "./asset_path.js";
import { isDev } from "./utils.js";
export default assetPath + "/src";
export default isDev ? assetPath : assetPath + "/src";

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