Compare commits
564 Commits
v0.92.0-be
...
v0.92.3-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6e7f98f69 | ||
|
|
e76601cd21 | ||
|
|
e252b491ba | ||
|
|
555dcc956e | ||
|
|
3958312651 | ||
|
|
eb19e31fc3 | ||
|
|
9d05fedc69 | ||
|
|
cbd6278a0b | ||
|
|
f6b52f5ce9 | ||
|
|
efc57e383c | ||
|
|
40d6a28751 | ||
|
|
73791211c5 | ||
|
|
b0f86af57e | ||
|
|
4c6556cf18 | ||
|
|
3465bc3f1a | ||
|
|
c1c9bf9122 | ||
|
|
02b50703b2 | ||
|
|
ab104af9ac | ||
|
|
178a58375a | ||
|
|
313d418345 | ||
|
|
633369b5bd | ||
|
|
06d5abded4 | ||
|
|
41368db8b6 | ||
|
|
4ff3b87f23 | ||
|
|
a40dc2047b | ||
|
|
00e576b052 | ||
|
|
ee7b97ae56 | ||
|
|
89767d0135 | ||
|
|
79cc1cbf17 | ||
|
|
1ba6104e36 | ||
|
|
f209e4f14d | ||
|
|
a162fbfe42 | ||
|
|
e795caa2f3 | ||
|
|
ddd0c3a878 | ||
|
|
7c5430ba49 | ||
|
|
c155702d91 | ||
|
|
ab578f9379 | ||
|
|
ebaa909488 | ||
|
|
c463106ccc | ||
|
|
283d192fe8 | ||
|
|
fbba1021cc | ||
|
|
a3a34cfab0 | ||
|
|
77d6cdc546 | ||
|
|
deb5d82c02 | ||
|
|
ca757b20d5 | ||
|
|
15075c8626 | ||
|
|
07dbacb61f | ||
|
|
1976fe6729 | ||
|
|
c99c4a4302 | ||
|
|
8d60429b9c | ||
|
|
84c480c4c6 | ||
|
|
01f9ddaea7 | ||
|
|
07b1f69f7a | ||
|
|
dd28ce9e5d | ||
|
|
e514396c42 | ||
|
|
f2d1726852 | ||
|
|
6b9311f9ef | ||
|
|
9ced699751 | ||
|
|
c217d1c037 | ||
|
|
a9938cbf7d | ||
|
|
3d600c885a | ||
|
|
24c2b54bc9 | ||
|
|
8e2517459f | ||
|
|
25c9f52cf4 | ||
|
|
4a75f9f48b | ||
|
|
51813099b3 | ||
|
|
93e2515190 | ||
|
|
883a67bcfe | ||
|
|
17e3bd9f6d | ||
|
|
d4fe8cf4b9 | ||
|
|
4c0ecc4df9 | ||
|
|
2b0cb8225f | ||
|
|
3d7798859f | ||
|
|
f8c8b9eb3f | ||
|
|
33eb8fe820 | ||
|
|
d8ea415b84 | ||
|
|
7bcbf29f21 | ||
|
|
ea3364ab09 | ||
|
|
115c3bbeb0 | ||
|
|
f150ec15bc | ||
|
|
d582fdea02 | ||
|
|
775fd3f22b | ||
|
|
9f6b97cdfa | ||
|
|
d31ba6f47c | ||
|
|
b150a05a55 | ||
|
|
4c89a2ac27 | ||
|
|
951f4c4921 | ||
|
|
856410120c | ||
|
|
427b7fe992 | ||
|
|
c6b3c1bf88 | ||
|
|
42d3334c9d | ||
|
|
3546ac6ded | ||
|
|
b81fd69981 | ||
|
|
bb42b5fb19 | ||
|
|
598586f735 | ||
|
|
bccfeed431 | ||
|
|
dbea35f9f3 | ||
|
|
acc76f9b74 | ||
|
|
5b4d323936 | ||
|
|
fd652ea7a5 | ||
|
|
642b84ce6b | ||
|
|
c0c85e96ce | ||
|
|
2c7a25b7fc | ||
|
|
6a5e622637 | ||
|
|
b2ac5b6337 | ||
|
|
40144fc171 | ||
|
|
1e599af480 | ||
|
|
744a0b8042 | ||
|
|
0d66f9d4eb | ||
|
|
aed835b6c2 | ||
|
|
ce2961ebd6 | ||
|
|
b03c75c09b | ||
|
|
77c4b50215 | ||
|
|
901d2d72ae | ||
|
|
6555add2aa | ||
|
|
c4d2c2b8de | ||
|
|
f1ecab84d9 | ||
|
|
f1f55fd4f8 | ||
|
|
a97c8087a1 | ||
|
|
ee40bb3b33 | ||
|
|
5543650166 | ||
|
|
dcea67fa9d | ||
|
|
3d2801096f | ||
|
|
c41fbe8e45 | ||
|
|
3855f0e75f | ||
|
|
3f641c98fb | ||
|
|
9ca43aceed | ||
|
|
0e81f086c0 | ||
|
|
5289f94553 | ||
|
|
d779cc1854 | ||
|
|
3b16ad508e | ||
|
|
cf554fc4af | ||
|
|
1b76442367 | ||
|
|
2213c500c2 | ||
|
|
3c290c9fc5 | ||
|
|
8e66dc300f | ||
|
|
ef9eebc030 | ||
|
|
65a51153b3 | ||
|
|
741a4af570 | ||
|
|
2a4d3b71f2 | ||
|
|
0d5bef422a | ||
|
|
605d99a7e8 | ||
|
|
e930ae5f40 | ||
|
|
4d6e115208 | ||
|
|
495a394d79 | ||
|
|
e55708f79f | ||
|
|
c7e9963db1 | ||
|
|
ad711ff00c | ||
|
|
125eef234b | ||
|
|
45a50f3aa1 | ||
|
|
8e0b9d17a4 | ||
|
|
b99ead6a84 | ||
|
|
e7d2be4663 | ||
|
|
2efc1a0e2e | ||
|
|
2beaaa95bf | ||
|
|
bc787213f4 | ||
|
|
73daec6644 | ||
|
|
43d8affcc8 | ||
|
|
67509bc92f | ||
|
|
1ca485e4b5 | ||
|
|
16ad054d2a | ||
|
|
b4310b5275 | ||
|
|
f04e747786 | ||
|
|
a80c3e32f1 | ||
|
|
01ff3d396d | ||
|
|
49a22bce80 | ||
|
|
436788cf96 | ||
|
|
c8a7f893e1 | ||
|
|
17884558ad | ||
|
|
8e4530293d | ||
|
|
072b5b2035 | ||
|
|
455b2bf338 | ||
|
|
9a5c08f117 | ||
|
|
038e3a15cd | ||
|
|
6c67c9a41f | ||
|
|
d6b164413e | ||
|
|
259ce440c5 | ||
|
|
2a75819734 | ||
|
|
4211e4e11c | ||
|
|
f76f679800 | ||
|
|
e7d06fceba | ||
|
|
a8b119e4df | ||
|
|
f953f6514f | ||
|
|
ca7cff45c9 | ||
|
|
6f2a0f9ee1 | ||
|
|
5b9bfac1f8 | ||
|
|
f674ba0d4a | ||
|
|
5731cb9b4d | ||
|
|
d83b2a6a38 | ||
|
|
ad18916973 | ||
|
|
2531e5617f | ||
|
|
f646e0f724 | ||
|
|
7a34a2f59c | ||
|
|
85882d843b | ||
|
|
f60667b618 | ||
|
|
c8c7680a10 | ||
|
|
6df588da22 | ||
|
|
423037b9d6 | ||
|
|
2c714afa21 | ||
|
|
83d25964c7 | ||
|
|
e58a61051b | ||
|
|
77c0bfe93b | ||
|
|
9826256e29 | ||
|
|
a3d9b04d96 | ||
|
|
c67445f511 | ||
|
|
a99c86ea9f | ||
|
|
23553692ac | ||
|
|
1450e57a6a | ||
|
|
d3283746fc | ||
|
|
f3148bf478 | ||
|
|
b60f22c6b9 | ||
|
|
559517ace1 | ||
|
|
49a2eb0ccf | ||
|
|
06a439e95d | ||
|
|
a615b473a7 | ||
|
|
1a9c28f9bd | ||
|
|
93d5b20362 | ||
|
|
6501b95eac | ||
|
|
b0fa70870c | ||
|
|
74fc5562b2 | ||
|
|
c033ad261c | ||
|
|
fe7f2e43be | ||
|
|
5435b3c8fd | ||
|
|
7d5b0f825c | ||
|
|
fd66da95f3 | ||
|
|
8e5762b125 | ||
|
|
bee1df4fdf | ||
|
|
4df76fafe1 | ||
|
|
3d36d6d121 | ||
|
|
995d963450 | ||
|
|
5d61f9fb12 | ||
|
|
09f7645925 | ||
|
|
2ea85dc238 | ||
|
|
d0c703515b | ||
|
|
d73c9308a9 | ||
|
|
89eab387ba | ||
|
|
6f9fd76465 | ||
|
|
7ea3cb71f3 | ||
|
|
fa60295ab2 | ||
|
|
ab5df9e010 | ||
|
|
e330d91df2 | ||
|
|
07c2342b7b | ||
|
|
9cc3598095 | ||
|
|
0f1b4614fb | ||
|
|
f1f5839ea2 | ||
|
|
ba84c694b2 | ||
|
|
5109f865c7 | ||
|
|
47f84fe4b4 | ||
|
|
1056176624 | ||
|
|
634b57ce5d | ||
|
|
6fcd229b52 | ||
|
|
bd933dde28 | ||
|
|
ef736edf09 | ||
|
|
909a74e8ac | ||
|
|
180c02d647 | ||
|
|
d92959e23a | ||
|
|
3c8a42ed73 | ||
|
|
43b1b8a306 | ||
|
|
bb8277d035 | ||
|
|
9d188f9ecc | ||
|
|
f04d749440 | ||
|
|
631a4ed9b2 | ||
|
|
1a0c35f43d | ||
|
|
0aa1d602a1 | ||
|
|
d28dfc2b64 | ||
|
|
8b2788fa8c | ||
|
|
ea04457c06 | ||
|
|
c935cb65a0 | ||
|
|
e7601f65bb | ||
|
|
64647df043 | ||
|
|
5838ac3bca | ||
|
|
7bc9114976 | ||
|
|
637ba78100 | ||
|
|
fcd7b986aa | ||
|
|
84e8559401 | ||
|
|
06831ddc76 | ||
|
|
cd78955080 | ||
|
|
175852f6cb | ||
|
|
4149ebdc69 | ||
|
|
6d52d7943b | ||
|
|
8e4aead110 | ||
|
|
d434b416f3 | ||
|
|
ac050bca3b | ||
|
|
194640db66 | ||
|
|
05975a02fb | ||
|
|
7345cddc0a | ||
|
|
a01da98b37 | ||
|
|
c80ec03126 | ||
|
|
cd5df24e6a | ||
|
|
1be92baf4a | ||
|
|
16b58a58a3 | ||
|
|
34762236d1 | ||
|
|
4240af6c43 | ||
|
|
d85c670d7b | ||
|
|
23d01ec351 | ||
|
|
7874e88b4a | ||
|
|
9d6caa84cd | ||
|
|
36ce2a3342 | ||
|
|
65804f9c2a | ||
|
|
28ed616fa6 | ||
|
|
675a5e96e6 | ||
|
|
8ab0084e10 | ||
|
|
2ab22e7b0e | ||
|
|
147c340529 | ||
|
|
87e687147d | ||
|
|
b88980ea49 | ||
|
|
fe93ee90c7 | ||
|
|
e9d4356492 | ||
|
|
226cf8dfd7 | ||
|
|
b91b243432 | ||
|
|
0ba4c9b9c7 | ||
|
|
31fcf7ea60 | ||
|
|
24c02e013b | ||
|
|
d319eede1f | ||
|
|
143b91936c | ||
|
|
95e6919dcf | ||
|
|
07147bf857 | ||
|
|
249c42e781 | ||
|
|
2578d480a8 | ||
|
|
937a314260 | ||
|
|
560b7ebe35 | ||
|
|
4883debd8d | ||
|
|
637845c396 | ||
|
|
d16026f8e6 | ||
|
|
e5aed0a3fc | ||
|
|
8a08664dd5 | ||
|
|
b9f30fc501 | ||
|
|
70af260f0f | ||
|
|
474b44608b | ||
|
|
12f7119427 | ||
|
|
223a1fb203 | ||
|
|
fb0487ca36 | ||
|
|
add6f80aeb | ||
|
|
5d4dc91cc3 | ||
|
|
99e520cbbc | ||
|
|
1e7dee51fc | ||
|
|
4ddc36f6b8 | ||
|
|
3f2ae81fe4 | ||
|
|
d99a44867c | ||
|
|
8f643c62e3 | ||
|
|
f6785f7980 | ||
|
|
bf15192b25 | ||
|
|
70756fe795 | ||
|
|
31170744d1 | ||
|
|
1dfa4a8bc2 | ||
|
|
e9f5272d98 | ||
|
|
07443042a1 | ||
|
|
4523307ead | ||
|
|
755b20bbab | ||
|
|
49b52d3124 | ||
|
|
da69ee3285 | ||
|
|
9fb95585f5 | ||
|
|
2380d0af85 | ||
|
|
f6224d9ec4 | ||
|
|
58a8821c22 | ||
|
|
fc27c4fc7b | ||
|
|
0b11f4d9c7 | ||
|
|
50d491b432 | ||
|
|
2492bf60df | ||
|
|
49550e8e69 | ||
|
|
a0442ded58 | ||
|
|
cdb988ff64 | ||
|
|
899ad6450a | ||
|
|
8390807212 | ||
|
|
60da367570 | ||
|
|
36b0970835 | ||
|
|
3bea6af20e | ||
|
|
e7d204dfd2 | ||
|
|
1ded78975e | ||
|
|
55bdd4fffc | ||
|
|
0b4f5e998e | ||
|
|
dde24785b8 | ||
|
|
f6d9b42911 | ||
|
|
f78a6ed14b | ||
|
|
837697c503 | ||
|
|
1b309675c8 | ||
|
|
ac53079a39 | ||
|
|
19e19ca052 | ||
|
|
5361161433 | ||
|
|
762c7dab83 | ||
|
|
ba3599911f | ||
|
|
fc6b9e00bc | ||
|
|
17860e6715 | ||
|
|
ad8adeda0a | ||
|
|
bc28f323b8 | ||
|
|
4f171fd966 | ||
|
|
65ad4c3a2b | ||
|
|
cc1a01955a | ||
|
|
cf11be7f35 | ||
|
|
3c83112240 | ||
|
|
4e876ed24d | ||
|
|
94ce01bbc2 | ||
|
|
411e3dfa0e | ||
|
|
a1bfc6aae7 | ||
|
|
97bc103e76 | ||
|
|
9da1f55409 | ||
|
|
017fba518d | ||
|
|
63584c153c | ||
|
|
a4a2e55415 | ||
|
|
4a1691ac31 | ||
|
|
a3fbf15902 | ||
|
|
5a8d5c59f5 | ||
|
|
a9cebe312f | ||
|
|
43f79ca813 | ||
|
|
5c1db3cab2 | ||
|
|
bc4d820cb0 | ||
|
|
f4e6edd19e | ||
|
|
530340f753 | ||
|
|
fcc1068b06 | ||
|
|
6d19e315f4 | ||
|
|
7269c1b0aa | ||
|
|
8e69cf79a6 | ||
|
|
46f543ad54 | ||
|
|
38dbf6efcd | ||
|
|
8e68ddafd5 | ||
|
|
0c43b387ce | ||
|
|
8aa560eb82 | ||
|
|
3a2b8e9791 | ||
|
|
468b3b6027 | ||
|
|
f872073f65 | ||
|
|
ef4fc0a180 | ||
|
|
1d47df5f28 | ||
|
|
77264b5385 | ||
|
|
41e925dc94 | ||
|
|
789178061b | ||
|
|
8011969b9d | ||
|
|
9ab2fe85bd | ||
|
|
6c818427fc | ||
|
|
7dab171a0c | ||
|
|
c680c3476b | ||
|
|
bf0b6ce554 | ||
|
|
bedc61c3d0 | ||
|
|
c925ae5f15 | ||
|
|
77ee7f96c1 | ||
|
|
cadd78524c | ||
|
|
fd4f35e879 | ||
|
|
39f00bd568 | ||
|
|
ee2d4c6830 | ||
|
|
e93d47f664 | ||
|
|
0c88c4c3ee | ||
|
|
81bdd57398 | ||
|
|
fe5182ebc6 | ||
|
|
42d46bdb72 | ||
|
|
710cf68c06 | ||
|
|
300bb561bb | ||
|
|
96961898ca | ||
|
|
1520913686 | ||
|
|
0e5b8af3a4 | ||
|
|
6fae7a98f5 | ||
|
|
57dc168c26 | ||
|
|
946d9aee40 | ||
|
|
16b16927ef | ||
|
|
c2e4def523 | ||
|
|
1e11625f14 | ||
|
|
5495677fc2 | ||
|
|
2cefdf8b9f | ||
|
|
57b3035559 | ||
|
|
4f84ad8b81 | ||
|
|
1626767f30 | ||
|
|
91003af092 | ||
|
|
860de346a7 | ||
|
|
324a3d0d8b | ||
|
|
f9e4ae7210 | ||
|
|
bdd6395a76 | ||
|
|
1c118f2aa9 | ||
|
|
4010cb2789 | ||
|
|
f83beafd76 | ||
|
|
366264f3a9 | ||
|
|
ba91ed1855 | ||
|
|
ef487f46d1 | ||
|
|
2734e230ab | ||
|
|
ca1d5207d8 | ||
|
|
f6b6b2e740 | ||
|
|
c255af67c9 | ||
|
|
34b4e6d069 | ||
|
|
4e01534d76 | ||
|
|
a433c9c189 | ||
|
|
fa05f15753 | ||
|
|
68c7df797d | ||
|
|
587a051430 | ||
|
|
04a6175630 | ||
|
|
bf6c5dfb20 | ||
|
|
19816493d6 | ||
|
|
cecde349b7 | ||
|
|
1a80a379dc | ||
|
|
739eaf9fc0 | ||
|
|
7f173b287a | ||
|
|
62c96fc95e | ||
|
|
c0d3e8d834 | ||
|
|
bb822126cd | ||
|
|
034b93c99c | ||
|
|
f743f634b4 | ||
|
|
9ed075b675 | ||
|
|
7f0df441b5 | ||
|
|
2de46eb5d2 | ||
|
|
2a3546edd5 | ||
|
|
7c0b43db85 | ||
|
|
d4ef15212f | ||
|
|
ad492619f5 | ||
|
|
35af12b6e7 | ||
|
|
0baa804544 | ||
|
|
575ef5e10e | ||
|
|
5a6c3ae426 | ||
|
|
6b5d905ebe | ||
|
|
61f2e35717 | ||
|
|
4a34d5b2df | ||
|
|
549917c1f1 | ||
|
|
4ed3a28e29 | ||
|
|
c261bf7f7a | ||
|
|
62c9e865f5 | ||
|
|
bd75a26803 | ||
|
|
9a1d26e129 | ||
|
|
bf41c54bd0 | ||
|
|
28148b32d2 | ||
|
|
eb08a976dd | ||
|
|
eeb99cf37c | ||
|
|
a0c2715980 | ||
|
|
e35ff07b9b | ||
|
|
ce1f418aa7 | ||
|
|
fbc4206908 | ||
|
|
bb4c3ae6ff | ||
|
|
0332ade13c | ||
|
|
2d968b8e9c | ||
|
|
fd2c65dcc0 | ||
|
|
0b8e3b976f | ||
|
|
373e0b45f2 | ||
|
|
c00505cd7b | ||
|
|
fc1ee7c6f0 | ||
|
|
7cba5a7c7d | ||
|
|
1024733252 | ||
|
|
17f9fa7e89 | ||
|
|
98dff61305 | ||
|
|
c0e42e23a6 | ||
|
|
aab35955bf | ||
|
|
bcb40b531f | ||
|
|
32bb43f9c1 | ||
|
|
86ab2d4008 | ||
|
|
657638ee54 | ||
|
|
50d37bbcb1 | ||
|
|
6706332be3 | ||
|
|
2ec2d784ec | ||
|
|
16caae191e | ||
|
|
c7d75b759c | ||
|
|
b837c57d06 | ||
|
|
ef3a75d58e | ||
|
|
59b474df35 | ||
|
|
fd47412d51 | ||
|
|
237f2ead73 | ||
|
|
558bee72e9 | ||
|
|
ed082f34d5 | ||
|
|
fabafeac86 | ||
|
|
d26d668741 | ||
|
|
fc8f805b28 | ||
|
|
ed8b8e50a4 | ||
|
|
bc66e98533 | ||
|
|
7af4e52766 | ||
|
|
ccbed7bbc3 | ||
|
|
10ba467202 | ||
|
|
793b0c9fe8 | ||
|
|
35a3d326f7 | ||
|
|
f672054441 | ||
|
|
e0e530b219 | ||
|
|
c0714a92d5 | ||
|
|
565989dd4c |
195
.github/actions/build-electron/action.yml
vendored
@@ -1,3 +1,6 @@
|
||||
name: "Build Electron App"
|
||||
description: "Builds and packages the Electron app for different platforms"
|
||||
|
||||
inputs:
|
||||
os:
|
||||
description: "One of the supported platforms: macos, linux, windows"
|
||||
@@ -6,15 +9,47 @@ inputs:
|
||||
description: "The architecture to build for: x64, arm64"
|
||||
required: true
|
||||
extension:
|
||||
description: "Platform specific extensions to copy in the output: dmg, deb, rpm, exe"
|
||||
description: "Platform specific extensions to copy in the output: dmg, deb, rpm, exe, zip"
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Set up Python for appdmg to be installed
|
||||
# Certificate setup
|
||||
- name: Import Apple certificates
|
||||
if: inputs.os == 'macos'
|
||||
uses: apple-actions/import-codesign-certs@v3
|
||||
with:
|
||||
p12-file-base64: ${{ env.APPLE_APP_CERTIFICATE_BASE64 }}
|
||||
p12-password: ${{ env.APPLE_APP_CERTIFICATE_PASSWORD }}
|
||||
keychain: build
|
||||
keychain-password: ${{ github.run_id }}
|
||||
|
||||
- name: Install Installer certificate
|
||||
if: inputs.os == 'macos'
|
||||
uses: apple-actions/import-codesign-certs@v3
|
||||
with:
|
||||
p12-file-base64: ${{ env.APPLE_INSTALLER_CERTIFICATE_BASE64 }}
|
||||
p12-password: ${{ env.APPLE_INSTALLER_CERTIFICATE_PASSWORD }}
|
||||
keychain: build
|
||||
keychain-password: ${{ github.run_id }}
|
||||
# We don't need to create a keychain here because we're using the build keychain that was created in the previous step
|
||||
create-keychain: false
|
||||
|
||||
- name: Verify certificates
|
||||
if: inputs.os == 'macos'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Available signing identities:"
|
||||
security find-identity -v -p codesigning build.keychain
|
||||
|
||||
- name: Set up Python and other macOS dependencies
|
||||
if: ${{ inputs.os == 'macos' }}
|
||||
shell: bash
|
||||
run: brew install python-setuptools
|
||||
run: |
|
||||
brew install python-setuptools
|
||||
brew install create-dmg
|
||||
|
||||
- name: Install dependencies for RPM and Flatpak package building
|
||||
if: ${{ inputs.os == 'linux' }}
|
||||
shell: bash
|
||||
@@ -24,25 +59,155 @@ runs:
|
||||
FLATPAK_ARCH=$(if [[ ${{ inputs.arch }} = 'arm64' ]]; then echo 'aarch64'; else echo 'x86_64'; fi)
|
||||
FLATPAK_VERSION='24.08'
|
||||
flatpak install --user --no-deps --arch $FLATPAK_ARCH --assumeyes runtime/org.freedesktop.Platform/$FLATPAK_ARCH/$FLATPAK_VERSION runtime/org.freedesktop.Sdk/$FLATPAK_ARCH/$FLATPAK_VERSION org.electronjs.Electron2.BaseApp/$FLATPAK_ARCH/$FLATPAK_VERSION
|
||||
|
||||
# Build setup
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: npm ci
|
||||
- name: Temporary Flatpak arm64 workaround till https://github.com/electron/forge/pull/3839 is merged
|
||||
if: ${{ inputs.os == 'linux' && inputs.arch == 'arm64' }}
|
||||
shell: bash
|
||||
run: sed -e "s/case 'armv7l'/case 'arm64'/g" -e "s/return 'arm'/return 'aarch64'/g" -i node_modules/@electron-forge/maker-flatpak/dist/MakerFlatpak.js
|
||||
|
||||
- name: Update build info
|
||||
shell: bash
|
||||
run: npm run chore:update-build-info
|
||||
- name: Run electron-forge
|
||||
|
||||
# Critical debugging configuration
|
||||
- name: Run electron-forge build with enhanced logging
|
||||
shell: bash
|
||||
run: npm run electron-forge:make -- --arch=${{ inputs.arch }}
|
||||
env:
|
||||
# Pass through required environment variables for signing and notarization
|
||||
APPLE_TEAM_ID: ${{ env.APPLE_TEAM_ID }}
|
||||
APPLE_ID: ${{ env.APPLE_ID }}
|
||||
APPLE_ID_PASSWORD: ${{ env.APPLE_ID_PASSWORD }}
|
||||
run: |
|
||||
# Map OS names to Electron Forge platform names
|
||||
if [ "${{ inputs.os }}" = "macos" ]; then
|
||||
PLATFORM="darwin"
|
||||
elif [ "${{ inputs.os }}" = "windows" ]; then
|
||||
PLATFORM="win32"
|
||||
else
|
||||
PLATFORM="${{ inputs.os }}"
|
||||
fi
|
||||
|
||||
npm run electron-forge:make -- \
|
||||
--arch=${{ inputs.arch }} \
|
||||
--platform=$PLATFORM
|
||||
|
||||
# Add DMG signing step
|
||||
- name: Sign DMG
|
||||
if: inputs.os == 'macos'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Signing DMG file..."
|
||||
dmg_file=$(find out -name "*.dmg" -print -quit)
|
||||
if [ -n "$dmg_file" ]; then
|
||||
echo "Found DMG: $dmg_file"
|
||||
# Get the first valid signing identity from the keychain
|
||||
SIGNING_IDENTITY=$(security find-identity -v -p codesigning build.keychain | grep "Developer ID Application" | head -1 | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [ -z "$SIGNING_IDENTITY" ]; then
|
||||
echo "Error: No valid Developer ID Application certificate found in keychain"
|
||||
exit 1
|
||||
fi
|
||||
echo "Using signing identity: $SIGNING_IDENTITY"
|
||||
# Sign the DMG
|
||||
codesign --force --sign "$SIGNING_IDENTITY" --options runtime --timestamp "$dmg_file"
|
||||
# Notarize the DMG
|
||||
xcrun notarytool submit "$dmg_file" --apple-id "$APPLE_ID" --password "$APPLE_ID_PASSWORD" --team-id "$APPLE_TEAM_ID" --wait
|
||||
# Staple the notarization ticket
|
||||
xcrun stapler staple "$dmg_file"
|
||||
else
|
||||
echo "No DMG found to sign"
|
||||
fi
|
||||
|
||||
- name: Verify code signing
|
||||
if: inputs.os == 'macos'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Verifying code signing for all artifacts..."
|
||||
|
||||
# First check the .app bundle
|
||||
echo "Looking for .app bundle..."
|
||||
app_bundle=$(find out -name "*.app" -print -quit)
|
||||
if [ -n "$app_bundle" ]; then
|
||||
echo "Found app bundle: $app_bundle"
|
||||
echo "Verifying app bundle signing..."
|
||||
codesign --verify --deep --strict --verbose=2 "$app_bundle"
|
||||
echo "Displaying app bundle signing info..."
|
||||
codesign --display --verbose=2 "$app_bundle"
|
||||
|
||||
echo "Checking entitlements..."
|
||||
codesign --display --entitlements :- "$app_bundle"
|
||||
|
||||
echo "Checking notarization status..."
|
||||
xcrun stapler validate "$app_bundle" || echo "Warning: App bundle not notarized yet"
|
||||
else
|
||||
echo "No .app bundle found to verify"
|
||||
fi
|
||||
|
||||
# Then check DMG if it exists
|
||||
echo "Looking for DMG..."
|
||||
dmg_file=$(find out -name "*.dmg" -print -quit)
|
||||
if [ -n "$dmg_file" ]; then
|
||||
echo "Found DMG: $dmg_file"
|
||||
echo "Verifying DMG signing..."
|
||||
codesign --verify --deep --strict --verbose=2 "$dmg_file"
|
||||
echo "Displaying DMG signing info..."
|
||||
codesign --display --verbose=2 "$dmg_file"
|
||||
|
||||
echo "Checking DMG notarization..."
|
||||
xcrun stapler validate "$dmg_file" || echo "Warning: DMG not notarized yet"
|
||||
else
|
||||
echo "No DMG found to verify"
|
||||
fi
|
||||
|
||||
# Finally check ZIP if it exists
|
||||
echo "Looking for ZIP..."
|
||||
zip_file=$(find out -name "*.zip" -print -quit)
|
||||
if [ -n "$zip_file" ]; then
|
||||
echo "Found ZIP: $zip_file"
|
||||
echo "Note: ZIP files are not code signed, but their contents should be"
|
||||
fi
|
||||
|
||||
- name: Prepare artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p upload;
|
||||
for ext in ${{ inputs.extension }};
|
||||
do
|
||||
file=$(find out/make -name "*.$ext" -print -quit);
|
||||
cp "$file" "upload/TriliumNextNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}.$ext";
|
||||
done
|
||||
mkdir -p upload
|
||||
|
||||
if [ "${{ inputs.os }}" = "macos" ]; then
|
||||
# For macOS, we need to look in specific directories based on the maker
|
||||
echo "Collecting macOS artifacts..."
|
||||
|
||||
# Look for DMG files recursively
|
||||
echo "Looking for DMG files..."
|
||||
dmg_file=$(find out -name "*.dmg" -print -quit)
|
||||
if [ -n "$dmg_file" ]; then
|
||||
echo "Found DMG: $dmg_file"
|
||||
cp "$dmg_file" "upload/TriliumNextNotes-${{ github.ref_name }}-macos-${{ inputs.arch }}.dmg"
|
||||
else
|
||||
echo "Warning: No DMG file found"
|
||||
fi
|
||||
|
||||
# Look for ZIP files recursively
|
||||
echo "Looking for ZIP files..."
|
||||
zip_file=$(find out -name "*.zip" -print -quit)
|
||||
if [ -n "$zip_file" ]; then
|
||||
echo "Found ZIP: $zip_file"
|
||||
cp "$zip_file" "upload/TriliumNextNotes-${{ github.ref_name }}-macos-${{ inputs.arch }}.zip"
|
||||
else
|
||||
echo "Warning: No ZIP file found"
|
||||
fi
|
||||
else
|
||||
# For other platforms, use the existing logic but with better error handling
|
||||
echo "Collecting artifacts for ${{ inputs.os }}..."
|
||||
for ext in ${{ inputs.extension }}; do
|
||||
echo "Looking for .$ext files..."
|
||||
file=$(find out -name "*.$ext" -print -quit)
|
||||
if [ -n "$file" ]; then
|
||||
echo "Found $file for extension $ext"
|
||||
cp "$file" "upload/TriliumNextNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}.$ext"
|
||||
else
|
||||
echo "Warning: No file found with extension .$ext"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Final contents of upload directory:"
|
||||
ls -la upload/
|
||||
|
||||
3
.github/actions/build-server/action.yml
vendored
@@ -1,4 +1,7 @@
|
||||
inputs:
|
||||
os:
|
||||
description: "One of the supported platforms: windows"
|
||||
required: true
|
||||
arch:
|
||||
description: "The architecture to build for: x64, arm64"
|
||||
required: true
|
||||
|
||||
20
.github/workflows/dev.yml
vendored
@@ -33,6 +33,10 @@ jobs:
|
||||
|
||||
- name: Run the TypeScript build
|
||||
run: npx tsc
|
||||
|
||||
- name: Run the unit tests
|
||||
run: npm run test
|
||||
|
||||
build_docker:
|
||||
name: Build Docker image
|
||||
runs-on: ubuntu-latest
|
||||
@@ -45,7 +49,7 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- run: npm ci
|
||||
- name: Run the TypeScript build
|
||||
run: npx tsc
|
||||
- name: Create server-package.json
|
||||
@@ -55,7 +59,7 @@ jobs:
|
||||
with:
|
||||
context: .
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
cache-to: type=gha,mode=max
|
||||
test_docker:
|
||||
name: Check Docker build
|
||||
runs-on: ubuntu-latest
|
||||
@@ -69,7 +73,7 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
|
||||
- name: Set IMAGE_NAME to lowercase
|
||||
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV
|
||||
- name: Set TEST_TAG to lowercase
|
||||
@@ -83,12 +87,12 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
|
||||
|
||||
- run: npm ci
|
||||
|
||||
|
||||
- name: Run the TypeScript build
|
||||
run: npx tsc
|
||||
|
||||
|
||||
- name: Create server-package.json
|
||||
run: cat package.json | grep -v electron > server-package.json
|
||||
|
||||
@@ -101,12 +105,12 @@ jobs:
|
||||
tags: ${{ env.TEST_TAG }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
|
||||
- name: Validate container run output
|
||||
run: |
|
||||
CONTAINER_ID=$(docker run -d --log-driver=journald --rm --name trilium_local ${{ env.TEST_TAG }})
|
||||
echo "Container ID: $CONTAINER_ID"
|
||||
|
||||
|
||||
- name: Wait for the healthchecks to pass
|
||||
uses: stringbean/docker-healthcheck-action@v3
|
||||
with:
|
||||
|
||||
73
.github/workflows/main-docker.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
|
||||
- name: Set IMAGE_NAME to lowercase
|
||||
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV
|
||||
- name: Set TEST_TAG to lowercase
|
||||
@@ -47,16 +47,16 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
|
||||
|
||||
- name: Install npm dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps
|
||||
|
||||
|
||||
- name: Run the TypeScript build
|
||||
run: npx tsc
|
||||
|
||||
|
||||
- name: Create server-package.json
|
||||
run: cat package.json | grep -v electron > server-package.json
|
||||
|
||||
@@ -69,12 +69,12 @@ jobs:
|
||||
tags: ${{ env.TEST_TAG }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
|
||||
- name: Validate container run output
|
||||
run: |
|
||||
CONTAINER_ID=$(docker run -d --log-driver=journald --rm --network=host -e TRILIUM_PORT=8082 --volume ./integration-tests/db:/home/node/trilium-data --name trilium_local ${{ env.TEST_TAG }})
|
||||
echo "Container ID: $CONTAINER_ID"
|
||||
|
||||
|
||||
- name: Wait for the healthchecks to pass
|
||||
uses: stringbean/docker-healthcheck-action@v3
|
||||
with:
|
||||
@@ -82,7 +82,7 @@ jobs:
|
||||
wait-time: 50
|
||||
require-status: running
|
||||
require-healthy: true
|
||||
|
||||
|
||||
- name: Run Playwright tests
|
||||
run: TRILIUM_DOCKER=1 npx playwright test
|
||||
- uses: actions/upload-artifact@v4
|
||||
@@ -100,7 +100,20 @@ jobs:
|
||||
|
||||
build:
|
||||
name: Build Docker images
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- dockerfile: Dockerfile.alpine
|
||||
platform: linux/amd64
|
||||
image: ubuntu-latest
|
||||
- dockerfile: Dockerfile
|
||||
platform: linux/arm64
|
||||
image: ubuntu-24.04-arm
|
||||
- dockerfile: Dockerfile
|
||||
platform: linux/arm/v7
|
||||
image: ubuntu-24.04-arm
|
||||
runs-on: ${{ matrix.image }}
|
||||
needs:
|
||||
- test_docker
|
||||
permissions:
|
||||
@@ -108,16 +121,6 @@ jobs:
|
||||
packages: write
|
||||
attestations: write
|
||||
id-token: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- dockerfile: Dockerfile.alpine
|
||||
platform: linux/amd64
|
||||
- dockerfile: Dockerfile
|
||||
platform: linux/arm64
|
||||
- dockerfile: Dockerfile
|
||||
platform: linux/arm/v7
|
||||
steps:
|
||||
- name: Prepare
|
||||
run: |
|
||||
@@ -144,13 +147,13 @@ jobs:
|
||||
type=sha
|
||||
flavor: |
|
||||
latest=false
|
||||
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
|
||||
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
@@ -169,14 +172,14 @@ jobs:
|
||||
registry: ${{ env.GHCR_REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKERHUB_REGISTRY }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
@@ -186,13 +189,13 @@ jobs:
|
||||
platforms: ${{ matrix.platform }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
outputs: type=image,name=${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
|
||||
- name: Export digest
|
||||
run: |
|
||||
mkdir -p /tmp/digests
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@@ -220,7 +223,7 @@ jobs:
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
@@ -237,14 +240,14 @@ jobs:
|
||||
registry: ${{ env.GHCR_REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKERHUB_REGISTRY }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
|
||||
- name: Create manifest list and push
|
||||
working-directory: /tmp/digests
|
||||
run: |
|
||||
@@ -255,7 +258,7 @@ jobs:
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME} \
|
||||
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
||||
|
||||
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME} \
|
||||
$(printf '${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
||||
@@ -267,25 +270,25 @@ jobs:
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:stable \
|
||||
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
||||
|
||||
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:stable \
|
||||
$(printf '${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
||||
|
||||
|
||||
# Small delay to ensure stable tag is fully propagated
|
||||
sleep 5
|
||||
|
||||
|
||||
# Now update latest tags
|
||||
docker buildx imagetools create \
|
||||
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
|
||||
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:stable
|
||||
|
||||
|
||||
docker buildx imagetools create \
|
||||
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
|
||||
${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:stable
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
|
||||
|
||||
17
.github/workflows/main.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
extension: [deb, rpm, zip, flatpak]
|
||||
- name: windows
|
||||
image: windows-latest
|
||||
extension: exe
|
||||
extension: [exe, zip]
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -43,6 +43,21 @@ jobs:
|
||||
os: ${{ matrix.os.name }}
|
||||
arch: ${{ matrix.arch }}
|
||||
extension: ${{ matrix.os.extension }}
|
||||
env:
|
||||
APPLE_APP_CERTIFICATE_BASE64: ${{ secrets.APPLE_APP_CERTIFICATE_BASE64 }}
|
||||
APPLE_APP_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_APP_CERTIFICATE_PASSWORD }}
|
||||
APPLE_INSTALLER_CERTIFICATE_BASE64: ${{ secrets.APPLE_INSTALLER_CERTIFICATE_BASE64 }}
|
||||
APPLE_INSTALLER_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_INSTALLER_CERTIFICATE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
|
||||
# Clean up keychain after build
|
||||
- name: Clean up keychain
|
||||
if: matrix.os.name == 'macos' && always()
|
||||
run: |
|
||||
security delete-keychain build.keychain
|
||||
|
||||
- name: Publish artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
||||
13
.github/workflows/nightly.yml
vendored
@@ -2,7 +2,7 @@ name: Nightly Release
|
||||
on:
|
||||
# This can be used to automatically publish nightlies at UTC nighttime
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # run at 2 AM UTC
|
||||
- cron: "0 2 * * *" # run at 2 AM UTC
|
||||
# This can be used to allow manually triggering nightlies from the web interface
|
||||
workflow_dispatch:
|
||||
env:
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
extension: [deb, rpm, zip, flatpak]
|
||||
- name: windows
|
||||
image: windows-latest
|
||||
extension: exe
|
||||
extension: [exe, zip]
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -45,6 +45,14 @@ jobs:
|
||||
os: ${{ matrix.os.name }}
|
||||
arch: ${{ matrix.arch }}
|
||||
extension: ${{ join(matrix.os.extension, ' ') }}
|
||||
env:
|
||||
APPLE_APP_CERTIFICATE_BASE64: ${{ secrets.APPLE_APP_CERTIFICATE_BASE64 }}
|
||||
APPLE_APP_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_APP_CERTIFICATE_PASSWORD }}
|
||||
APPLE_INSTALLER_CERTIFICATE_BASE64: ${{ secrets.APPLE_INSTALLER_CERTIFICATE_BASE64 }}
|
||||
APPLE_INSTALLER_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_INSTALLER_CERTIFICATE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
|
||||
- name: Publish release
|
||||
uses: softprops/action-gh-release@v2
|
||||
@@ -75,6 +83,7 @@ jobs:
|
||||
- name: Run the build
|
||||
uses: ./.github/actions/build-server
|
||||
with:
|
||||
os: linux
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
- name: Publish release
|
||||
|
||||
12
.github/workflows/release.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
extension: [deb, rpm, zip, flatpak]
|
||||
- name: windows
|
||||
image: windows-latest
|
||||
extension: exe
|
||||
extension: [exe, zip]
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -40,6 +40,15 @@ jobs:
|
||||
os: ${{ matrix.os.name }}
|
||||
arch: ${{ matrix.arch }}
|
||||
extension: ${{ join(matrix.os.extension, ' ') }}
|
||||
env:
|
||||
APPLE_APP_CERTIFICATE_BASE64: ${{ secrets.APPLE_APP_CERTIFICATE_BASE64 }}
|
||||
APPLE_APP_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_APP_CERTIFICATE_PASSWORD }}
|
||||
APPLE_INSTALLER_CERTIFICATE_BASE64: ${{ secrets.APPLE_INSTALLER_CERTIFICATE_BASE64 }}
|
||||
APPLE_INSTALLER_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_INSTALLER_CERTIFICATE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
|
||||
- name: Publish release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
@@ -65,6 +74,7 @@ jobs:
|
||||
- name: Run the build
|
||||
uses: ./.github/actions/build-server
|
||||
with:
|
||||
os: linux
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
- name: Publish release
|
||||
|
||||
1
.gitignore
vendored
@@ -11,6 +11,7 @@ po-*/
|
||||
.flatpak-builder/
|
||||
|
||||
*.db
|
||||
!test/**/*.db
|
||||
!integration-tests/db/document.db
|
||||
!integration-tests/db/config.ini
|
||||
integration-tests/db/log
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
*.md
|
||||
*.yml
|
||||
libraries/*
|
||||
docs/*
|
||||
docs/*
|
||||
src/public/app/doc_notes/**/*
|
||||
6
.vscode/extensions.json
vendored
@@ -1,3 +1,7 @@
|
||||
{
|
||||
"recommendations": ["lokalise.i18n-ally", "editorconfig.editorconfig"]
|
||||
"recommendations": [
|
||||
"lokalise.i18n-ally",
|
||||
"editorconfig.editorconfig",
|
||||
"vitest.explorer"
|
||||
]
|
||||
}
|
||||
|
||||
9
.vscode/settings.json
vendored
@@ -19,5 +19,12 @@
|
||||
"[css]": {
|
||||
"editor.defaultFormatter": "vscode.css-language-features"
|
||||
},
|
||||
"npm.exclude": ["**/build", "**/dist", "**/out/**"]
|
||||
"npm.exclude": [
|
||||
"**/build",
|
||||
"**/dist",
|
||||
"**/out/**"
|
||||
],
|
||||
"[xml]": {
|
||||
"editor.defaultFormatter": "redhat.vscode-xml"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,6 @@ chmod 755 $PKG_DIR/trilium.sh
|
||||
cp bin/tpl/anonymize-database.sql $PKG_DIR/
|
||||
|
||||
cp -r translations $PKG_DIR/
|
||||
cp -r dump-db $PKG_DIR/
|
||||
rm -rf $PKG_DIR/dump-db/node_modules
|
||||
|
||||
VERSION=`jq -r ".version" package.json`
|
||||
|
||||
|
||||
@@ -95,7 +95,6 @@ const copy = async () => {
|
||||
"node_modules/mark.js/dist/",
|
||||
"node_modules/normalize.css/",
|
||||
"node_modules/jquery.fancytree/dist/",
|
||||
"node_modules/bootstrap/dist/",
|
||||
"node_modules/autocomplete.js/dist/",
|
||||
"node_modules/codemirror/lib/",
|
||||
"node_modules/codemirror/addon/",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { fileURLToPath } from "url";
|
||||
import { dirname, join } from "path";
|
||||
import swaggerJsdoc from 'swagger-jsdoc';
|
||||
import swaggerJsdoc from "swagger-jsdoc";
|
||||
import fs from "fs";
|
||||
|
||||
/*
|
||||
@@ -11,28 +11,30 @@ import fs from "fs";
|
||||
*/
|
||||
|
||||
const options = {
|
||||
definition: {
|
||||
openapi: '3.1.1',
|
||||
info: {
|
||||
title: 'Trilium Notes - Sync server API',
|
||||
version: '0.96.6',
|
||||
description: "This is the internal sync server API used by Trilium Notes / TriliumNext Notes.\n\n_If you're looking for the officially supported External Trilium API, see [here](https://triliumnext.github.io/Docs/Wiki/etapi.html)._\n\nThis page does not yet list all routes. For a full list, see the [route controller](https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/routes.ts).",
|
||||
contact: {
|
||||
name: "TriliumNext issue tracker",
|
||||
url: "https://github.com/TriliumNext/Notes/issues",
|
||||
},
|
||||
license: {
|
||||
name: "GNU Free Documentation License 1.3 (or later)",
|
||||
url: "https://www.gnu.org/licenses/fdl-1.3",
|
||||
},
|
||||
definition: {
|
||||
openapi: "3.1.1",
|
||||
info: {
|
||||
title: "Trilium Notes - Sync server API",
|
||||
version: "0.96.6",
|
||||
description:
|
||||
"This is the internal sync server API used by Trilium Notes / TriliumNext Notes.\n\n_If you're looking for the officially supported External Trilium API, see [here](https://triliumnext.github.io/Docs/Wiki/etapi.html)._\n\nThis page does not yet list all routes. For a full list, see the [route controller](https://github.com/TriliumNext/Notes/blob/v0.91.6/src/routes/routes.ts).",
|
||||
contact: {
|
||||
name: "TriliumNext issue tracker",
|
||||
url: "https://github.com/TriliumNext/Notes/issues"
|
||||
},
|
||||
license: {
|
||||
name: "GNU Free Documentation License 1.3 (or later)",
|
||||
url: "https://www.gnu.org/licenses/fdl-1.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
apis: [
|
||||
// Put individual files here to have them ordered first.
|
||||
'./src/routes/api/setup.ts',
|
||||
// all other files
|
||||
'./src/routes/api/*.ts', './bin/generate-openapi.js'
|
||||
],
|
||||
apis: [
|
||||
// Put individual files here to have them ordered first.
|
||||
"./src/routes/api/setup.ts",
|
||||
// all other files
|
||||
"./src/routes/api/*.ts",
|
||||
"./bin/generate-openapi.js"
|
||||
]
|
||||
};
|
||||
|
||||
const openapiSpecification = swaggerJsdoc(options);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
export GITHUB_REPO=trilium
|
||||
set -e
|
||||
|
||||
if [[ $# -eq 0 ]] ; then
|
||||
echo "Missing argument of new version"
|
||||
@@ -40,10 +40,18 @@ TAG=v$VERSION
|
||||
|
||||
echo "Committing package.json version change"
|
||||
|
||||
git commit -m "release $VERSION"
|
||||
git commit -m "chore(release): $VERSION"
|
||||
git push
|
||||
|
||||
echo "Tagging commit with $TAG"
|
||||
|
||||
git tag $TAG
|
||||
git push origin $TAG
|
||||
|
||||
echo "Updating master"
|
||||
|
||||
git fetch
|
||||
git checkout master
|
||||
git reset --hard origin/master
|
||||
git merge origin/develop
|
||||
git push
|
||||
@@ -1,11 +1,24 @@
|
||||
module.exports = () => {
|
||||
const sql = require("../../src/services/sql");
|
||||
const utils = require("../../src/services/utils");
|
||||
import sql from "../../src/services/sql";
|
||||
import utils from "../../src/services/utils";
|
||||
|
||||
interface NoteContentsRow {
|
||||
noteId: string;
|
||||
content: string | Buffer;
|
||||
dateModified: string;
|
||||
utcDateModified: string;
|
||||
}
|
||||
|
||||
interface NoteRevisionContents {
|
||||
noteRevisionId: string;
|
||||
content: string | Buffer;
|
||||
utcDateModified: string;
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const existingBlobIds = new Set();
|
||||
|
||||
for (const noteId of sql.getColumn(`SELECT noteId FROM note_contents`)) {
|
||||
const row = sql.getRow(`SELECT noteId, content, dateModified, utcDateModified FROM note_contents WHERE noteId = ?`, [noteId]);
|
||||
for (const noteId of sql.getColumn<string>(`SELECT noteId FROM note_contents`)) {
|
||||
const row = sql.getRow<NoteContentsRow>(`SELECT noteId, content, dateModified, utcDateModified FROM note_contents WHERE noteId = ?`, [noteId]);
|
||||
const blobId = utils.hashedBlobId(row.content);
|
||||
|
||||
if (!existingBlobIds.has(blobId)) {
|
||||
@@ -28,7 +41,7 @@ module.exports = () => {
|
||||
}
|
||||
|
||||
for (const noteRevisionId of sql.getColumn(`SELECT noteRevisionId FROM note_revision_contents`)) {
|
||||
const row = sql.getRow(`SELECT noteRevisionId, content, utcDateModified FROM note_revision_contents WHERE noteRevisionId = ?`, [noteRevisionId]);
|
||||
const row = sql.getRow<NoteRevisionContents>(`SELECT noteRevisionId, content, utcDateModified FROM note_revision_contents WHERE noteRevisionId = ?`, [noteRevisionId]);
|
||||
const blobId = utils.hashedBlobId(row.content);
|
||||
|
||||
if (!existingBlobIds.has(blobId)) {
|
||||
@@ -44,7 +57,7 @@ module.exports = () => {
|
||||
sql.execute("UPDATE entity_changes SET entityName = 'blobs', entityId = ? WHERE entityName = 'note_revision_contents' AND entityId = ?", [blobId, row.noteRevisionId]);
|
||||
} else {
|
||||
// duplicates
|
||||
sql.execute("DELETE FROM entity_changes WHERE entityName = 'note_revision_contents' AND entityId = ?", [row.noteId]);
|
||||
sql.execute("DELETE FROM entity_changes WHERE entityName = 'note_revision_contents' AND entityId = ?", [row.noteRevisionId]);
|
||||
}
|
||||
|
||||
sql.execute("UPDATE note_revisions SET blobId = ? WHERE noteRevisionId = ?", [blobId, row.noteRevisionId]);
|
||||
@@ -1,15 +1,15 @@
|
||||
module.exports = () => {
|
||||
const beccaLoader = require("../../src/becca/becca_loader");
|
||||
const becca = require("../../src/becca/becca");
|
||||
const cls = require("../../src/services/cls");
|
||||
const log = require("../../src/services/log");
|
||||
const sql = require("../../src/services/sql");
|
||||
import becca from "../../src/becca/becca";
|
||||
import becca_loader from "../../src/becca/becca_loader";
|
||||
import cls from "../../src/services/cls";
|
||||
import log from "../../src/services/log";
|
||||
import sql from "../../src/services/sql";
|
||||
|
||||
export default () => {
|
||||
cls.init(() => {
|
||||
// emergency disabling of image compression since it appears to make problems in migration to 0.61
|
||||
sql.execute(`UPDATE options SET value = 'false' WHERE name = 'compressImages'`);
|
||||
|
||||
beccaLoader.load();
|
||||
becca_loader.load();
|
||||
|
||||
for (const note of Object.values(becca.notes)) {
|
||||
try {
|
||||
@@ -11,16 +11,14 @@ test("Displays translation on desktop", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
|
||||
await expect(page.locator("#left-pane .quick-search input"))
|
||||
.toHaveAttribute("placeholder", "Quick search");
|
||||
await expect(page.locator("#left-pane .quick-search input")).toHaveAttribute("placeholder", "Quick search");
|
||||
});
|
||||
|
||||
test("Displays translation on mobile", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto({ isMobile: true });
|
||||
|
||||
await expect(page.locator("#mobile-sidebar-wrapper .quick-search input"))
|
||||
.toHaveAttribute("placeholder", "Quick search");
|
||||
await expect(page.locator("#mobile-sidebar-wrapper .quick-search input")).toHaveAttribute("placeholder", "Quick search");
|
||||
});
|
||||
|
||||
test("Displays translations in Settings", async ({ page, context }) => {
|
||||
@@ -44,14 +42,16 @@ test("User can change language from settings", async ({ page, context }) => {
|
||||
|
||||
// Check that the default value (English) is set.
|
||||
await expect(app.currentNoteSplit).toContainText("Theme");
|
||||
const languageCombobox = await app.currentNoteSplit.getByRole("combobox").first();
|
||||
const languageCombobox = app.currentNoteSplit.getByRole("combobox").first();
|
||||
await expect(languageCombobox).toHaveValue("en");
|
||||
|
||||
// Select Chinese and ensure the translation is set.
|
||||
await languageCombobox.selectOption("cn");
|
||||
await expect(app.currentNoteSplit).toContainText("主题", { timeout: 15000 });
|
||||
await expect(languageCombobox).toHaveValue("cn");
|
||||
|
||||
// Select English again.
|
||||
await languageCombobox.selectOption("en");
|
||||
await expect(app.currentNoteSplit).toContainText("Language", { timeout: 15000 });
|
||||
await expect(languageCombobox).toHaveValue("en");
|
||||
});
|
||||
|
||||
@@ -19,13 +19,13 @@ test("Can drag tabs around", async ({ page, context }) => {
|
||||
let tab = app.getTab(0);
|
||||
|
||||
// Drag the first tab at the end
|
||||
await tab.dragTo(app.getTab(2), { targetPosition: { x: 50, y: 0 }});
|
||||
await tab.dragTo(app.getTab(2), { targetPosition: { x: 50, y: 0 } });
|
||||
|
||||
tab = app.getTab(2);
|
||||
await expect(tab).toContainText(NOTE_TITLE);
|
||||
|
||||
// Drag the tab to the left
|
||||
await tab.dragTo(app.getTab(0), { targetPosition: { x: 50, y: 0 }});
|
||||
await tab.dragTo(app.getTab(0), { targetPosition: { x: 50, y: 0 } });
|
||||
await expect(app.getTab(0)).toContainText(NOTE_TITLE);
|
||||
});
|
||||
|
||||
|
||||
@@ -39,7 +39,9 @@ test("Displays lint errors for backend script", async ({ page, context }) => {
|
||||
});
|
||||
|
||||
async function expectTooltip(page: Page, tooltip: string) {
|
||||
await expect(page.locator(".CodeMirror-lint-tooltip:visible", {
|
||||
"hasText": tooltip
|
||||
})).toBeVisible();
|
||||
await expect(
|
||||
page.locator(".CodeMirror-lint-tooltip:visible", {
|
||||
hasText: tooltip
|
||||
})
|
||||
).toBeVisible();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ import App from "../support/app";
|
||||
|
||||
test("renders ELK flowchart", async ({ page, context }) => {
|
||||
await testAriaSnapshot({
|
||||
page, context,
|
||||
page,
|
||||
context,
|
||||
noteTitle: "Flowchart ELK on",
|
||||
snapshot: `
|
||||
- document:
|
||||
@@ -22,12 +23,13 @@ test("renders ELK flowchart", async ({ page, context }) => {
|
||||
- paragraph: Guarantee
|
||||
- text: Interfaces for B
|
||||
`
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
test("renders standard flowchart", async ({ page, context }) => {
|
||||
await testAriaSnapshot({
|
||||
page, context,
|
||||
page,
|
||||
context,
|
||||
noteTitle: "Flowchart ELK off",
|
||||
snapshot: `
|
||||
- document:
|
||||
@@ -46,7 +48,7 @@ test("renders standard flowchart", async ({ page, context }) => {
|
||||
- paragraph: C
|
||||
- text: Interfaces for B
|
||||
`
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
interface AriaTestOpts {
|
||||
|
||||
@@ -44,8 +44,8 @@ test("Highlights list is displayed", async ({ page, context }) => {
|
||||
|
||||
await expect(app.sidebar).toContainText("Highlights List");
|
||||
const rootList = app.sidebar.locator(".highlights-list ol");
|
||||
let index=0;
|
||||
for (const highlightedEl of [ "Bold 1", "Italic 1", "Underline 1", "Colored text 1", "Background text 1", "Bold 2", "Italic 2", "Underline 2", "Colored text 2", "Background text 2" ]) {
|
||||
let index = 0;
|
||||
for (const highlightedEl of ["Bold 1", "Italic 1", "Underline 1", "Colored text 1", "Background text 1", "Bold 2", "Italic 2", "Underline 2", "Colored text 2", "Background text 2"]) {
|
||||
await expect(rootList.locator("li").nth(index++)).toContainText(highlightedEl);
|
||||
}
|
||||
});
|
||||
@@ -54,7 +54,7 @@ test("Displays math popup", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
await app.goToNoteInNewTab("Empty text");
|
||||
const noteContent = app.currentNoteSplit.locator(".note-detail-editable-text-editor")
|
||||
const noteContent = app.currentNoteSplit.locator(".note-detail-editable-text-editor");
|
||||
await noteContent.fill("Hello world");
|
||||
await noteContent.press("ControlOrMeta+M");
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export default class App {
|
||||
this.tabBar = page.locator(".tab-row-widget-container");
|
||||
this.noteTree = page.locator(".tree-wrapper");
|
||||
this.launcherBar = page.locator("#launcher-container");
|
||||
this.currentNoteSplit = page.locator(".note-split:not(.hidden-ext)")
|
||||
this.currentNoteSplit = page.locator(".note-split:not(.hidden-ext)");
|
||||
this.sidebar = page.locator("#right-pane");
|
||||
}
|
||||
|
||||
@@ -42,12 +42,11 @@ export default class App {
|
||||
url = "/";
|
||||
}
|
||||
|
||||
await this.page.goto(url, { waitUntil: "networkidle" });
|
||||
await this.page.goto(url, { waitUntil: "networkidle", timeout: 30_000 });
|
||||
|
||||
// Wait for the page to load.
|
||||
if (url === "/") {
|
||||
await expect(this.page.locator(".tree"))
|
||||
.toContainText("Trilium Integration Test");
|
||||
await expect(this.page.locator(".tree")).toContainText("Trilium Integration Test");
|
||||
await this.closeAllTabs();
|
||||
}
|
||||
}
|
||||
@@ -109,11 +108,12 @@ export default class App {
|
||||
});
|
||||
|
||||
expect(csrfToken).toBeTruthy();
|
||||
await expect(await this.page.request.put(`${BASE_URL}/api/options/${key}/${value}`, {
|
||||
headers: {
|
||||
"x-csrf-token": csrfToken
|
||||
}
|
||||
})).toBeOK();
|
||||
await expect(
|
||||
await this.page.request.put(`${BASE_URL}/api/options/${key}/${value}`, {
|
||||
headers: {
|
||||
"x-csrf-token": csrfToken
|
||||
}
|
||||
})
|
||||
).toBeOK();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
26
electron-docs-main.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import cls from "./src/services/cls.js";
|
||||
import sql_init from "./src/services/sql_init.js";
|
||||
|
||||
async function startElectron() {
|
||||
await import("./electron-main.js");
|
||||
}
|
||||
|
||||
async function initializeDb() {
|
||||
return new Promise<void>((resolve) => {
|
||||
cls.init(async () => {
|
||||
await sql_init.createInitialDatabase();
|
||||
sql_init.setDbAsInitialized();
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
async function main() {
|
||||
if (!sql_init.isDbInitialized()) {
|
||||
initializeDb();
|
||||
}
|
||||
|
||||
await startElectron();
|
||||
}
|
||||
|
||||
await main();
|
||||
10
entitlements.plist
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
43
eslint.config.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import eslint from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
// consider using rules below, once we have a full TS codebase and can be more strict
|
||||
// tseslint.configs.strictTypeChecked,
|
||||
// tseslint.configs.stylisticTypeChecked,
|
||||
// tseslint.configs.recommendedTypeChecked,
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
// add rule overrides here
|
||||
"no-undef": "off",
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"argsIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_",
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
ignores: [
|
||||
"build/*",
|
||||
"dist/*",
|
||||
"docs/*",
|
||||
"libraries/*",
|
||||
"src/public/app-dist/*",
|
||||
"src/public/app/doc_notes/*"
|
||||
]
|
||||
}
|
||||
);
|
||||
@@ -17,33 +17,39 @@ module.exports = {
|
||||
overwrite: true,
|
||||
asar: true,
|
||||
icon: "./images/app-icons/icon",
|
||||
osxSign: {},
|
||||
osxNotarize: {
|
||||
appleId: process.env.APPLE_ID,
|
||||
appleIdPassword: process.env.APPLE_ID_PASSWORD,
|
||||
teamId: process.env.APPLE_TEAM_ID
|
||||
},
|
||||
extraResource: [
|
||||
// Moved to root
|
||||
...extraResourcesForPlatform,
|
||||
// All resources should stay in Resources directory for macOS
|
||||
...(process.platform === "darwin" ? [] : extraResourcesForPlatform),
|
||||
|
||||
// Moved to resources (TriliumNext Notes.app/Contents/Resources on macOS)
|
||||
// These always go in Resources
|
||||
"translations/",
|
||||
"node_modules/@highlightjs/cdn-assets/styles"
|
||||
],
|
||||
afterComplete: [
|
||||
(buildPath, _electronVersion, platform, _arch, callback) => {
|
||||
for (const resource of extraResourcesForPlatform) {
|
||||
const baseName = path.basename(resource);
|
||||
// Only move resources on non-macOS platforms
|
||||
if (platform !== "darwin") {
|
||||
for (const resource of extraResourcesForPlatform) {
|
||||
const baseName = path.basename(resource);
|
||||
const sourcePath = path.join(buildPath, "resources", baseName);
|
||||
|
||||
// prettier-ignore
|
||||
const sourcePath = (platform === "darwin")
|
||||
? path.join(buildPath, `${APP_NAME}.app`, "Contents", "Resources", baseName)
|
||||
: path.join(buildPath, "resources", baseName);
|
||||
// prettier-ignore
|
||||
const destPath = (baseName !== "256x256.png")
|
||||
? path.join(buildPath, baseName)
|
||||
: path.join(buildPath, "icon.png");
|
||||
|
||||
// prettier-ignore
|
||||
const destPath = (baseName !== "256x256.png")
|
||||
? path.join(buildPath, baseName)
|
||||
: path.join(buildPath, "icon.png");
|
||||
|
||||
// Copy files from resources folder to root
|
||||
fs.move(sourcePath, destPath)
|
||||
.then(() => callback())
|
||||
.catch((err) => callback(err));
|
||||
fs.move(sourcePath, destPath)
|
||||
.then(() => callback())
|
||||
.catch((err) => callback(err));
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -6,7 +6,7 @@ instanceName=
|
||||
noAuthentication=true
|
||||
|
||||
# set to true to disable backups (e.g. because of limited space on server)
|
||||
noBackup=false
|
||||
noBackup=true
|
||||
|
||||
# Disable automatically generating desktop icon
|
||||
# noDesktopIcon=true
|
||||
|
||||
3369
package-lock.json
generated
105
package.json
@@ -2,7 +2,7 @@
|
||||
"name": "trilium",
|
||||
"productName": "TriliumNext Notes",
|
||||
"description": "Build your personal knowledge base with TriliumNext Notes",
|
||||
"version": "0.92.0-beta",
|
||||
"version": "0.92.3-beta",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "./dist/electron-main.js",
|
||||
"author": {
|
||||
@@ -26,41 +26,39 @@
|
||||
"server:start-test": "npm run server:switch && rimraf ./data-test && cross-env TRILIUM_DATA_DIR=./data-test TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev TRILIUM_PORT=9999 nodemon src/main.ts",
|
||||
"server:qstart": "npm run server:switch && npm run server:start",
|
||||
"server:switch": "rimraf ./node_modules/better-sqlite3 && npm install",
|
||||
|
||||
"electron:start": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron ./electron-main.ts --inspect=5858 .",
|
||||
"electron:start-no-dir": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_ENV=dev electron --inspect=5858 .",
|
||||
"electron:start-nix": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./electron-main.ts --inspect=5858 .\"",
|
||||
"electron:start-nix": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev nix-shell -p electron_34 --run \"electron ./electron-main.ts --inspect=5858 .\"",
|
||||
"electron:start-nix-no-dir": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./electron-main.ts --inspect=5858 .\"",
|
||||
"electron:start-prod": "npm run build:prepare-dist && cross-env TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron ./dist/electron-main.js --inspect=5858 .",
|
||||
"electron:start-prod-no-dir": "npm run build:prepare-dist && cross-env TRILIUM_ENV=dev electron --inspect=5858 .",
|
||||
"electron:start-prod": "npm run build:prepare-dist && cross-env TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=prod electron ./dist/electron-main.js --inspect=5858 .",
|
||||
"electron:start-prod-no-dir": "npm run build:prepare-dist && cross-env TRILIUM_ENV=prod electron --inspect=5858 .",
|
||||
"electron:start-prod-nix": "electron-rebuild --version 33.3.1 && npm run build:prepare-dist && cross-env TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./dist/electron-main.js --inspect=5858 .\"",
|
||||
"electron:start-prod-nix-no-dir": "electron-rebuild --version 33.3.1 && npm run build:prepare-dist && cross-env TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./dist/electron-main.js --inspect=5858 .\"",
|
||||
"electron:qstart": "npm run electron:switch && npm run electron:start",
|
||||
"electron:switch": "electron-rebuild",
|
||||
|
||||
"docs:edit": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data-docs TRILIUM_ENV=dev electron ./electron-docs-main.ts .",
|
||||
"electron-forge:start": "npm run build:prepare-dist && electron-forge start",
|
||||
"electron-forge:make": "npm run build:prepare-dist && electron-forge make",
|
||||
"electron-forge:package": "npm run build:prepare-dist && electron-forge package",
|
||||
|
||||
"docs:build-backend": "rimraf ./docs/backend_api && typedoc ./docs/backend_api src/becca/entities/*.ts src/services/backend_script_api.ts src/services/sql.ts",
|
||||
"docs:build-frontend": "rimraf ./docs/frontend_api && jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/basic_widget.js src/public/app/widgets/note_context_aware_widget.js src/public/app/widgets/right_panel_widget.js",
|
||||
"docs:build": "npm run docs:build-backend && npm run docs:build-frontend",
|
||||
|
||||
"build:webpack": "tsx node_modules/webpack/bin/webpack.js -c webpack.config.ts",
|
||||
"build:prepare-dist": "npm run build:webpack && rimraf ./dist && tsc && tsx ./bin/copy-dist.ts",
|
||||
|
||||
"test": "cross-env TRILIUM_DATA_DIR=./integration-tests/db vitest",
|
||||
"test:coverage": "cross-env TRILIUM_DATA_DIR=./integration-tests/db vitest --coverage",
|
||||
"test:playwright": "playwright test",
|
||||
|
||||
"test": "npm run client:test && npm run server:test",
|
||||
"server:test": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest",
|
||||
"server:coverage": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest --coverage",
|
||||
"client:test": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest --root src/public/app",
|
||||
"client:coverage": "cross-env TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db TRILIUM_INTEGRATION_TEST=memory vitest --root src/public/app --coverage",
|
||||
"test:playwright": "playwright test --workers 1",
|
||||
"test:integration-edit-db": "cross-env TRILIUM_INTEGRATION_TEST=edit TRILIUM_PORT=8081 TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
|
||||
"test:integration-mem-db": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
|
||||
"test:integration-mem-db-dev": "cross-env TRILIUM_INTEGRATION_TEST=memory TRILIUM_PORT=8082 TRILIUM_ENV=dev TRILIUM_DATA_DIR=./integration-tests/db nodemon src/main.ts",
|
||||
|
||||
"dev:watch-dist": "tsx ./bin/watch-dist.ts",
|
||||
"dev:prettier-check": "prettier . --check",
|
||||
"dev:prettier-fix": "prettier . --write",
|
||||
|
||||
"dev:linter-check": "eslint .",
|
||||
"dev:linter-fix": "eslint . --fix",
|
||||
"chore:update-build-info": "tsx bin/update-build-info.ts",
|
||||
"chore:ci-update-nightly-version": "tsx ./bin/update-nightly-version.ts",
|
||||
"chore:generate-document": "cross-env nodemon ./bin/generate_document.ts 1000",
|
||||
@@ -78,17 +76,13 @@
|
||||
"@mermaid-js/layout-elk": "0.1.7",
|
||||
"@mind-elixir/node-menu": "1.0.4",
|
||||
"@triliumnext/express-partial-content": "1.0.1",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/leaflet": "1.9.16",
|
||||
"@types/react-dom": "18.3.5",
|
||||
"@types/swagger-ui-express": "4.1.7",
|
||||
"archiver": "7.0.1",
|
||||
"async-mutex": "0.5.0",
|
||||
"autocomplete.js": "0.38.1",
|
||||
"axios": "1.7.9",
|
||||
"axios": "1.8.2",
|
||||
"better-sqlite3": "11.8.1",
|
||||
"bootstrap": "5.3.3",
|
||||
"boxicons": "2.1.4",
|
||||
"chardet": "2.1.0",
|
||||
"cheerio": "1.0.0",
|
||||
"chokidar": "4.0.3",
|
||||
"cls-hooked": "4.2.2",
|
||||
@@ -109,7 +103,7 @@
|
||||
"express": "4.21.2",
|
||||
"express-rate-limit": "7.5.0",
|
||||
"express-session": "1.18.1",
|
||||
"force-graph": "1.49.0",
|
||||
"force-graph": "1.49.3",
|
||||
"fs-extra": "11.3.0",
|
||||
"helmet": "8.0.0",
|
||||
"html": "1.0.0",
|
||||
@@ -118,7 +112,6 @@
|
||||
"https-proxy-agent": "7.0.6",
|
||||
"i18next": "24.2.2",
|
||||
"i18next-fs-backend": "2.6.0",
|
||||
"i18next-http-backend": "3.0.2",
|
||||
"image-type": "5.2.0",
|
||||
"ini": "5.0.0",
|
||||
"is-animated": "2.0.2",
|
||||
@@ -131,14 +124,13 @@
|
||||
"jsdom": "26.0.0",
|
||||
"jsplumb": "2.15.6",
|
||||
"katex": "0.16.21",
|
||||
"knockout": "3.5.1",
|
||||
"leaflet": "1.9.4",
|
||||
"leaflet-gpx": "2.1.2",
|
||||
"mark.js": "8.11.1",
|
||||
"marked": "15.0.7",
|
||||
"mermaid": "11.4.1",
|
||||
"mime-types": "2.1.35",
|
||||
"mind-elixir": "4.3.7",
|
||||
"mind-elixir": "4.4.1",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"normalize-strings": "1.1.1",
|
||||
"normalize.css": "8.0.1",
|
||||
@@ -153,30 +145,31 @@
|
||||
"serve-favicon": "2.5.0",
|
||||
"session-file-store": "1.5.0",
|
||||
"source-map-support": "0.5.21",
|
||||
"split.js": "1.6.5",
|
||||
"stream-throttle": "0.1.3",
|
||||
"strip-bom": "5.0.0",
|
||||
"striptags": "3.2.0",
|
||||
"swagger-ui-express": "5.0.1",
|
||||
"tmp": "0.2.3",
|
||||
"ts-loader": "9.5.2",
|
||||
"turndown": "7.2.0",
|
||||
"unescape": "1.0.1",
|
||||
"vanilla-js-wheel-zoom": "9.0.4",
|
||||
"ws": "8.18.0",
|
||||
"ws": "8.18.1",
|
||||
"xml2js": "0.6.2",
|
||||
"yauzl": "3.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-forge/cli": "7.6.1",
|
||||
"@electron-forge/maker-deb": "7.6.1",
|
||||
"@electron-forge/maker-dmg": "7.6.1",
|
||||
"@electron-forge/maker-flatpak": "7.6.1",
|
||||
"@electron-forge/maker-rpm": "7.6.1",
|
||||
"@electron-forge/maker-squirrel": "7.6.1",
|
||||
"@electron-forge/maker-zip": "7.6.1",
|
||||
"@electron-forge/plugin-auto-unpack-natives": "7.6.1",
|
||||
"@electron-forge/cli": "7.7.0",
|
||||
"@electron-forge/maker-deb": "7.7.0",
|
||||
"@electron-forge/maker-dmg": "7.7.0",
|
||||
"@electron-forge/maker-flatpak": "7.7.0",
|
||||
"@electron-forge/maker-rpm": "7.7.0",
|
||||
"@electron-forge/maker-squirrel": "7.7.0",
|
||||
"@electron-forge/maker-zip": "7.7.0",
|
||||
"@electron-forge/plugin-auto-unpack-natives": "7.7.0",
|
||||
"@electron/rebuild": "3.7.1",
|
||||
"@playwright/test": "1.50.1",
|
||||
"@eslint/js": "9.21.0",
|
||||
"@playwright/test": "1.51.0",
|
||||
"@popperjs/core": "2.11.8",
|
||||
"@types/archiver": "6.0.3",
|
||||
"@types/better-sqlite3": "7.6.12",
|
||||
"@types/bootstrap": "5.2.10",
|
||||
@@ -194,12 +187,15 @@
|
||||
"@types/html": "1.0.4",
|
||||
"@types/ini": "4.1.1",
|
||||
"@types/jquery": "3.5.32",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/jsdom": "21.1.7",
|
||||
"@types/leaflet": "1.9.16",
|
||||
"@types/leaflet-gpx": "1.3.7",
|
||||
"@types/mime-types": "2.1.4",
|
||||
"@types/multer": "1.4.12",
|
||||
"@types/node": "22.13.4",
|
||||
"@types/node": "22.13.9",
|
||||
"@types/react": "18.3.18",
|
||||
"@types/react-dom": "18.3.5",
|
||||
"@types/safe-compare": "1.1.2",
|
||||
"@types/sanitize-html": "2.13.0",
|
||||
"@types/sax": "1.2.7",
|
||||
@@ -207,27 +203,44 @@
|
||||
"@types/session-file-store": "1.2.5",
|
||||
"@types/source-map-support": "0.5.10",
|
||||
"@types/stream-throttle": "0.1.4",
|
||||
"@types/supertest": "6.0.2",
|
||||
"@types/swagger-ui-express": "4.1.8",
|
||||
"@types/tmp": "0.2.6",
|
||||
"@types/turndown": "5.0.5",
|
||||
"@types/ws": "8.5.14",
|
||||
"@types/ws": "8.18.0",
|
||||
"@types/xml2js": "0.4.14",
|
||||
"@types/yargs": "17.0.33",
|
||||
"@vitest/coverage-v8": "3.0.5",
|
||||
"@vitest/coverage-v8": "3.0.8",
|
||||
"autoprefixer": "10.4.20",
|
||||
"bootstrap": "5.3.3",
|
||||
"cross-env": "7.0.3",
|
||||
"electron": "34.2.0",
|
||||
"css-loader": "7.1.2",
|
||||
"electron": "34.3.1",
|
||||
"eslint": "9.21.0",
|
||||
"esm": "3.2.25",
|
||||
"happy-dom": "17.3.0",
|
||||
"i18next-http-backend": "3.0.2",
|
||||
"jsdoc": "4.0.4",
|
||||
"knockout": "3.5.1",
|
||||
"lorem-ipsum": "2.0.8",
|
||||
"mini-css-extract-plugin": "2.9.2",
|
||||
"nodemon": "3.1.9",
|
||||
"prettier": "3.5.1",
|
||||
"postcss-loader": "8.1.1",
|
||||
"prettier": "3.5.3",
|
||||
"rcedit": "4.0.1",
|
||||
"rimraf": "6.0.1",
|
||||
"sass": "1.85.1",
|
||||
"sass-loader": "16.0.5",
|
||||
"split.js": "1.6.5",
|
||||
"supertest": "7.0.0",
|
||||
"swagger-jsdoc": "6.2.8",
|
||||
"ts-loader": "9.5.2",
|
||||
"tslib": "2.8.1",
|
||||
"tsx": "4.19.2",
|
||||
"typedoc": "0.27.7",
|
||||
"typescript": "5.7.3",
|
||||
"vitest": "3.0.5",
|
||||
"tsx": "4.19.3",
|
||||
"typedoc": "0.27.9",
|
||||
"typescript": "5.8.2",
|
||||
"typescript-eslint": "8.26.0",
|
||||
"vitest": "3.0.8",
|
||||
"webpack": "5.98.0",
|
||||
"webpack-cli": "6.0.1",
|
||||
"webpack-dev-middleware": "7.4.2"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
import { defineConfig, devices } from "@playwright/test";
|
||||
|
||||
const SERVER_URL = 'http://127.0.0.1:8082';
|
||||
const SERVER_URL = "http://127.0.0.1:8082";
|
||||
|
||||
/**
|
||||
* Read environment variables from file.
|
||||
@@ -14,68 +14,70 @@ const SERVER_URL = 'http://127.0.0.1:8082';
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: './e2e',
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: 'html',
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
baseURL: SERVER_URL,
|
||||
testDir: "./e2e",
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: "html",
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
baseURL: SERVER_URL,
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: "on-first-retry"
|
||||
},
|
||||
|
||||
// {
|
||||
// name: 'firefox',
|
||||
// use: { ...devices['Desktop Firefox'] },
|
||||
// },
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: { ...devices["Desktop Chrome"] }
|
||||
}
|
||||
|
||||
// {
|
||||
// name: 'webkit',
|
||||
// use: { ...devices['Desktop Safari'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'firefox',
|
||||
// use: { ...devices['Desktop Firefox'] },
|
||||
// },
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'webkit',
|
||||
// use: { ...devices['Desktop Safari'] },
|
||||
// },
|
||||
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// },
|
||||
],
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
webServer: !process.env.TRILIUM_DOCKER ? {
|
||||
command: 'npm run test:integration-mem-db-dev',
|
||||
url: SERVER_URL,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
} : undefined,
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// },
|
||||
],
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
webServer: !process.env.TRILIUM_DOCKER
|
||||
? {
|
||||
command: "npm run test:integration-mem-db-dev",
|
||||
url: SERVER_URL,
|
||||
reuseExistingServer: !process.env.CI
|
||||
}
|
||||
: undefined
|
||||
});
|
||||
|
||||
@@ -6,4 +6,4 @@ etapi.describeEtapi("app_info", () => {
|
||||
expect(appInfo.clipperProtocolVersion).toEqual("1.0");
|
||||
});
|
||||
});
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -7,4 +7,4 @@ etapi.describeEtapi("backup", () => {
|
||||
expect(response.status).toEqual(204);
|
||||
});
|
||||
});
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -23,4 +23,4 @@ etapi.describeEtapi("import", () => {
|
||||
expect(content).toContain("test export content");
|
||||
});
|
||||
});
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -100,4 +100,4 @@ etapi.describeEtapi("notes", () => {
|
||||
expect(error.message).toEqual(`Note '${note.noteId}' not found.`);
|
||||
});
|
||||
});
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,35 @@
|
||||
/**
|
||||
* Reads the level of indentation of the first line and trims the identation for all the text by that amount.
|
||||
*
|
||||
* For example, for:
|
||||
*
|
||||
* ```json
|
||||
* {
|
||||
* "hello": "world"
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* it results in:
|
||||
*
|
||||
* ```json
|
||||
* {
|
||||
* "hello": "world"
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* This is meant to be used as a template string, where it allows the indentation of the template without affecting whitespace changes.
|
||||
*
|
||||
* @example const html = trimIndentation`\
|
||||
* <h1>Heading 1</h1>
|
||||
* <h2>Heading 2</h2>
|
||||
* <h3>Heading 3</h3>
|
||||
* <h4>Heading 4</h4>
|
||||
* <h5>Heading 5</h5>
|
||||
* <h6>Heading 6</h6>
|
||||
* `;
|
||||
* @param strings
|
||||
* @returns
|
||||
*/
|
||||
export function trimIndentation(strings: TemplateStringsArray) {
|
||||
const str = strings.toString();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// TODO: Booleans should probably be numbers instead (as SQLite does not have booleans.);
|
||||
// TODO: check against schema.sql which properties really are "optional"
|
||||
|
||||
export interface AttachmentRow {
|
||||
attachmentId?: string;
|
||||
@@ -12,6 +13,8 @@ export interface AttachmentRow {
|
||||
dateModified?: string;
|
||||
utcDateModified?: string;
|
||||
utcDateScheduledForErasureSince?: string;
|
||||
isDeleted?: boolean;
|
||||
deleteId?: string;
|
||||
contentLength?: number;
|
||||
content?: Buffer | string;
|
||||
}
|
||||
|
||||
@@ -18,13 +18,13 @@ import type NoteDetailWidget from "../widgets/note_detail.js";
|
||||
import type { ResolveOptions } from "../widgets/dialogs/delete_notes.js";
|
||||
import type { PromptDialogOptions } from "../widgets/dialogs/prompt.js";
|
||||
import type { ConfirmWithMessageOptions, ConfirmWithTitleOptions } from "../widgets/dialogs/confirm.js";
|
||||
import type { Node } from "../services/tree.js";
|
||||
import type LoadResults from "../services/load_results.js";
|
||||
import type { Attribute } from "../services/attribute_parser.js";
|
||||
import type NoteTreeWidget from "../widgets/note_tree.js";
|
||||
import type { default as NoteContext, GetTextEditorCallback } from "./note_context.js";
|
||||
import type { ContextMenuEvent } from "../menus/context_menu.js";
|
||||
import type TypeWidget from "../widgets/type_widgets/type_widget.js";
|
||||
import type EditableTextTypeWidget from "../widgets/type_widgets/editable_text.js";
|
||||
|
||||
interface Layout {
|
||||
getRootWidget: (appContext: AppContext) => RootWidget;
|
||||
@@ -49,21 +49,21 @@ export interface CommandData {
|
||||
* Represents a set of commands that are triggered from the context menu, providing information such as the selected note.
|
||||
*/
|
||||
export interface ContextMenuCommandData extends CommandData {
|
||||
node: Node;
|
||||
notePath: string;
|
||||
node: Fancytree.FancytreeNode;
|
||||
notePath?: string;
|
||||
noteId?: string;
|
||||
selectedOrActiveBranchIds: any; // TODO: Remove any once type is defined
|
||||
selectedOrActiveBranchIds?: any; // TODO: Remove any once type is defined
|
||||
selectedOrActiveNoteIds: any; // TODO: Remove any once type is defined
|
||||
}
|
||||
|
||||
export interface NoteCommandData extends CommandData {
|
||||
notePath: string;
|
||||
notePath?: string;
|
||||
hoistedNoteId?: string;
|
||||
viewScope?: ViewScope;
|
||||
}
|
||||
|
||||
export interface ExecuteCommandData<T> extends CommandData {
|
||||
resolve: (data: T) => void
|
||||
resolve: (data: T) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,7 +71,8 @@ export interface ExecuteCommandData<T> extends CommandData {
|
||||
*/
|
||||
export type CommandMappings = {
|
||||
"api-log-messages": CommandData;
|
||||
focusTree: CommandData,
|
||||
focusTree: CommandData;
|
||||
focusOnTitle: CommandData;
|
||||
focusOnDetail: CommandData;
|
||||
focusOnSearchDefinition: Required<CommandData>;
|
||||
searchNotes: CommandData & {
|
||||
@@ -79,6 +80,7 @@ export type CommandMappings = {
|
||||
ancestorNoteId?: string | null;
|
||||
};
|
||||
closeTocCommand: CommandData;
|
||||
closeHlt: CommandData;
|
||||
showLaunchBarSubtree: CommandData;
|
||||
showRevisions: CommandData;
|
||||
showOptions: CommandData & {
|
||||
@@ -106,13 +108,18 @@ export type CommandMappings = {
|
||||
showPromptDialog: PromptDialogOptions;
|
||||
showInfoDialog: ConfirmWithMessageOptions;
|
||||
showConfirmDialog: ConfirmWithMessageOptions;
|
||||
showRecentChanges: CommandData & { ancestorNoteId: string };
|
||||
showImportDialog: CommandData & { noteId: string };
|
||||
openNewNoteSplit: NoteCommandData;
|
||||
openInWindow: NoteCommandData;
|
||||
openNoteInNewTab: CommandData;
|
||||
openNoteInNewSplit: CommandData;
|
||||
openNoteInNewWindow: CommandData;
|
||||
openAboutDialog: CommandData;
|
||||
hideFloatingButtons: {};
|
||||
hideLeftPane: CommandData;
|
||||
showLeftPane: CommandData;
|
||||
hoistNote: CommandData & { noteId: string };
|
||||
leaveProtectedSession: CommandData;
|
||||
enterProtectedSession: CommandData;
|
||||
|
||||
@@ -122,9 +129,14 @@ export type CommandMappings = {
|
||||
insertNoteAfter: ContextMenuCommandData;
|
||||
insertChildNote: ContextMenuCommandData;
|
||||
delete: ContextMenuCommandData;
|
||||
editNoteTitle: ContextMenuCommandData;
|
||||
protectSubtree: ContextMenuCommandData;
|
||||
unprotectSubtree: ContextMenuCommandData;
|
||||
openBulkActionsDialog: ContextMenuCommandData;
|
||||
openBulkActionsDialog:
|
||||
| ContextMenuCommandData
|
||||
| {
|
||||
selectedOrActiveNoteIds?: string[];
|
||||
};
|
||||
editBranchPrefix: ContextMenuCommandData;
|
||||
convertNoteToAttachment: ContextMenuCommandData;
|
||||
duplicateSubtree: ContextMenuCommandData;
|
||||
@@ -143,6 +155,11 @@ export type CommandMappings = {
|
||||
importIntoNote: ContextMenuCommandData;
|
||||
exportNote: ContextMenuCommandData;
|
||||
searchInSubtree: ContextMenuCommandData;
|
||||
moveNoteUp: ContextMenuCommandData;
|
||||
moveNoteDown: ContextMenuCommandData;
|
||||
moveNoteUpInHierarchy: ContextMenuCommandData;
|
||||
moveNoteDownInHierarchy: ContextMenuCommandData;
|
||||
selectAllNotesInParent: ContextMenuCommandData;
|
||||
|
||||
addNoteLauncher: ContextMenuCommandData;
|
||||
addScriptLauncher: ContextMenuCommandData;
|
||||
@@ -175,6 +192,7 @@ export type CommandMappings = {
|
||||
importMarkdownInline: CommandData;
|
||||
showPasswordNotSet: CommandData;
|
||||
showProtectedSessionPasswordDialog: CommandData;
|
||||
showUploadAttachmentsDialog: CommandData & { noteId: string };
|
||||
closeProtectedSessionPasswordDialog: CommandData;
|
||||
copyImageReferenceToClipboard: CommandData;
|
||||
copyImageToClipboard: CommandData;
|
||||
@@ -198,6 +216,7 @@ export type CommandMappings = {
|
||||
screen: Screen;
|
||||
};
|
||||
closeTab: CommandData;
|
||||
closeToc: CommandData;
|
||||
closeOtherTabs: CommandData;
|
||||
closeRightTabs: CommandData;
|
||||
closeAllTabs: CommandData;
|
||||
@@ -205,26 +224,34 @@ export type CommandMappings = {
|
||||
moveTabToNewWindow: CommandData;
|
||||
copyTabToNewWindow: CommandData;
|
||||
closeActiveTab: CommandData & {
|
||||
$el: JQuery<HTMLElement>
|
||||
},
|
||||
$el: JQuery<HTMLElement>;
|
||||
};
|
||||
setZoomFactorAndSave: {
|
||||
zoomFactor: string;
|
||||
}
|
||||
};
|
||||
|
||||
reEvaluateRightPaneVisibility: CommandData;
|
||||
runActiveNote: CommandData;
|
||||
scrollContainerToCommand: CommandData & {
|
||||
position: number;
|
||||
};
|
||||
moveThisNoteSplit: CommandData & {
|
||||
isMovingLeft: boolean;
|
||||
};
|
||||
scrollToEnd: CommandData;
|
||||
closeThisNoteSplit: CommandData;
|
||||
moveThisNoteSplit: CommandData & { isMovingLeft: boolean };
|
||||
|
||||
// Geomap
|
||||
deleteFromMap: { noteId: string },
|
||||
openGeoLocation: { noteId: string, event: JQuery.MouseDownEvent }
|
||||
deleteFromMap: { noteId: string };
|
||||
openGeoLocation: { noteId: string; event: JQuery.MouseDownEvent };
|
||||
|
||||
toggleZenMode: CommandData;
|
||||
|
||||
updateAttributeList: CommandData & { attributes: Attribute[] };
|
||||
saveAttributes: CommandData;
|
||||
reloadAttributes: CommandData;
|
||||
refreshNoteList: CommandData & { noteId: string };
|
||||
|
||||
refreshResults: {};
|
||||
refreshSearchDefinition: {};
|
||||
};
|
||||
|
||||
type EventMappings = {
|
||||
@@ -288,6 +315,13 @@ type EventMappings = {
|
||||
showHighlightsListWidget: {
|
||||
noteId: string;
|
||||
};
|
||||
showTocWidget: {
|
||||
noteId: string;
|
||||
};
|
||||
showSearchError: {
|
||||
error: string;
|
||||
};
|
||||
searchRefreshed: { ntxId?: string | null };
|
||||
hoistedNoteChanged: {
|
||||
noteId: string;
|
||||
ntxId: string | null;
|
||||
@@ -317,17 +351,23 @@ type EventMappings = {
|
||||
ntxId: string | null | undefined; // TODO: deduplicate ntxId
|
||||
};
|
||||
tabReorder: {
|
||||
ntxIdsInOrder: string[]
|
||||
ntxIdsInOrder: string[];
|
||||
};
|
||||
refreshNoteList: {
|
||||
noteId: string;
|
||||
};
|
||||
showToc: {
|
||||
noteId: string;
|
||||
};
|
||||
scrollToEnd: { ntxId: string };
|
||||
noteTypeMimeChanged: { noteId: string };
|
||||
zenModeChanged: { isEnabled: boolean };
|
||||
relationMapCreateChildNote: { ntxId: string | null | undefined };
|
||||
relationMapResetPanZoom: { ntxId: string | null | undefined };
|
||||
relationMapResetZoomIn: { ntxId: string | null | undefined };
|
||||
relationMapResetZoomOut: { ntxId: string | null | undefined };
|
||||
activeNoteChangedEvent: {};
|
||||
showAddLinkDialog: {
|
||||
textTypeWidget: EditableTextTypeWidget;
|
||||
text: string;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
export type EventListener<T extends EventNames> = {
|
||||
@@ -365,6 +405,8 @@ class AppContext extends Component {
|
||||
layout?: Layout;
|
||||
noteTreeWidget?: NoteTreeWidget;
|
||||
|
||||
lastSearchString?: string;
|
||||
|
||||
constructor(isMainWindow: boolean) {
|
||||
super();
|
||||
|
||||
@@ -509,10 +551,12 @@ $(window).on("beforeunload", () => {
|
||||
});
|
||||
|
||||
$(window).on("hashchange", function () {
|
||||
const { notePath, ntxId, viewScope } = linkService.parseNavigationStateFromUrl(window.location.href);
|
||||
const { notePath, ntxId, viewScope, searchString } = linkService.parseNavigationStateFromUrl(window.location.href);
|
||||
|
||||
if (notePath || ntxId) {
|
||||
appContext.tabManager.switchToNoteContext(ntxId, notePath, viewScope);
|
||||
} else if (searchString) {
|
||||
appContext.triggerCommand("searchNotes", { searchString });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
|
||||
children: ChildT[];
|
||||
initialized: Promise<void> | null;
|
||||
parent?: TypedComponent<any>;
|
||||
position!: number;
|
||||
_position!: number;
|
||||
|
||||
constructor() {
|
||||
this.componentId = `${this.sanitizedClassName}-${utils.randomString(8)}`;
|
||||
@@ -31,6 +31,14 @@ export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
|
||||
return this.constructor.name.replace(/[^A-Z0-9]/gi, "_");
|
||||
}
|
||||
|
||||
get position() {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
set position(newPosition: number) {
|
||||
this._position = newPosition;
|
||||
}
|
||||
|
||||
setParent(parent: TypedComponent<any>) {
|
||||
this.parent = parent;
|
||||
return this;
|
||||
@@ -80,8 +88,7 @@ export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
|
||||
return promises.length > 0 ? Promise.all(promises) : null;
|
||||
}
|
||||
|
||||
triggerCommand<K extends CommandNames>(name: string, _data?: CommandMappings[K]): Promise<unknown> | undefined | null {
|
||||
const data = _data || {};
|
||||
triggerCommand<K extends CommandNames>(name: K, data?: CommandMappings[K]): Promise<unknown> | undefined | null {
|
||||
const fun = (this as any)[`${name}Command`];
|
||||
|
||||
if (fun) {
|
||||
|
||||
@@ -11,7 +11,7 @@ import type { ViewScope } from "../services/link.js";
|
||||
import type FNote from "../entities/fnote.js";
|
||||
import type TypeWidget from "../widgets/type_widgets/type_widget.js";
|
||||
|
||||
interface SetNoteOpts {
|
||||
export interface SetNoteOpts {
|
||||
triggerSwitchEvent?: unknown;
|
||||
viewScope?: ViewScope;
|
||||
}
|
||||
@@ -369,7 +369,8 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
||||
|
||||
const { note, viewScope } = this;
|
||||
|
||||
let title = viewScope?.viewMode === "default" ? note.title : `${note.title}: ${viewScope?.viewMode}`;
|
||||
const isNormalView = (viewScope?.viewMode === "default" || viewScope?.viewMode === "contextual-help");
|
||||
let title = (isNormalView ? note.title : `${note.title}: ${viewScope?.viewMode}`);
|
||||
|
||||
if (viewScope?.attachmentId) {
|
||||
// assuming the attachment has been already loaded
|
||||
|
||||
@@ -17,7 +17,7 @@ export default class ShortcutComponent extends Component implements EventListene
|
||||
}
|
||||
|
||||
bindNoteShortcutHandler(labelOrRow: AttributeRow) {
|
||||
const handler = () => appContext.tabManager.getActiveContext().setNote(labelOrRow.noteId);
|
||||
const handler = () => appContext.tabManager.getActiveContext()?.setNote(labelOrRow.noteId);
|
||||
const namespace = labelOrRow.attributeId;
|
||||
|
||||
if (labelOrRow.isDeleted) {
|
||||
|
||||
@@ -248,7 +248,7 @@ export default class TabManager extends Component {
|
||||
await noteContext.setEmpty();
|
||||
}
|
||||
|
||||
async openEmptyTab(ntxId = null, hoistedNoteId = "root", mainNtxId = null) {
|
||||
async openEmptyTab(ntxId = null, hoistedNoteId = "root", mainNtxId) {
|
||||
const noteContext = new NoteContext(ntxId, hoistedNoteId, mainNtxId);
|
||||
|
||||
const existingNoteContext = this.children.find((nc) => nc.ntxId === noteContext.ntxId);
|
||||
|
||||
@@ -10,6 +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";
|
||||
|
||||
await appContext.earlyInit();
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
@@ -1,94 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="../../../style.css">
|
||||
<base target="_parent">
|
||||
<title data-trilium-title>Creating a custom theme</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="content">
|
||||
<h1 data-trilium-h1>Creating a custom theme</h1>
|
||||
|
||||
<div class="ck-content">
|
||||
<h2>Step 1. Find a place to place the themes</h2>
|
||||
<p>Organization is an important aspect of managing a knowledge base. When
|
||||
developing a new theme or importing an existing one it's a good idea to
|
||||
keep them into one place.</p>
|
||||
<p>As such, the first step is to create a new note to gather all the themes.</p>
|
||||
<p>
|
||||
<img src="5_Creating a custom theme_im.png" width="181" height="84">
|
||||
</p>
|
||||
<h2>Step 2. Create the theme</h2>
|
||||
<figure class="table" style="width:100%;">
|
||||
<table class="ck-table-resized">
|
||||
<colgroup>
|
||||
<col style="width:32.47%;">
|
||||
<col style="width:67.53%;">
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<figure class="image">
|
||||
<img style="aspect-ratio:651/220;" src="3_Creating a custom theme_im.png"
|
||||
width="651" height="220">
|
||||
</figure>
|
||||
</td>
|
||||
<td style="vertical-align:top;">Themes are code notes with a special attribute. Start by creating a new
|
||||
code note.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<figure class="image">
|
||||
<img style="aspect-ratio:302/349;" src="1_Creating a custom theme_im.png"
|
||||
width="302" height="349">
|
||||
</figure>
|
||||
</td>
|
||||
<td style="vertical-align:top;">Then change the note type to a CSS code.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<figure class="image">
|
||||
<img style="aspect-ratio:316/133;" src="Creating a custom theme_im.png"
|
||||
width="316" height="133">
|
||||
</figure>
|
||||
</td>
|
||||
<td style="vertical-align:top;">In the <i>Owned Attributes</i> section define the <code>#appTheme</code> attribute
|
||||
to point to any desired name. This is the name that will show up in the
|
||||
appearance section in settings.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</figure>
|
||||
<h2>Step 3. Define the theme's CSS</h2>
|
||||
<p>As a very simple example we will change the background color of the launcher
|
||||
pane to a shade of blue.</p>
|
||||
<p>To alter the different variables of the theme:</p><pre><code class="language-text-css">:root {
|
||||
--launcher-pane-background-color: #0d6efd;
|
||||
}</code></pre>
|
||||
<h2>Step 4. Activating the theme</h2>
|
||||
<p>Refresh the application (Ctrl+Shift+R is a good way to do so) and go to
|
||||
settings. You should see the newly created theme:</p>
|
||||
<p>
|
||||
<img src="2_Creating a custom theme_im.png" width="631" height="481">
|
||||
</p>
|
||||
<p>Afterwards the application will refresh itself with the new theme:</p>
|
||||
<p>
|
||||
<img src="4_Creating a custom theme_im.png" width="653" height="554">
|
||||
</p>
|
||||
<p>Do note that the theme will be based off of the legacy theme. To override
|
||||
that and base the theme on the new TriliumNext theme, see: <a class="reference-link"
|
||||
href="Customize%20the%20Next%20theme.html">Theme base (legacy vs. next)</a>
|
||||
</p>
|
||||
<h2>Step 5. Making changes</h2>
|
||||
<p>Simply go back to the note and change according to needs. To apply the
|
||||
changes to the current window, press Ctrl+Shift+R to refresh.</p>
|
||||
<p>It's a good idea to keep two windows, one for editing and the other one
|
||||
for previewing the changes.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,36 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="../../../style.css">
|
||||
<base target="_parent">
|
||||
<title data-trilium-title>Customize the Next theme</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="content">
|
||||
<h1 data-trilium-h1>Customize the Next theme</h1>
|
||||
|
||||
<div class="ck-content">
|
||||
<p>By default, any custom theme will be based on the legacy light theme.
|
||||
To use the TriliumNext theme instead, add the <code>#appThemeBase=next</code> attribute
|
||||
onto the existing theme. The <code>appTheme</code> attribute must also be
|
||||
present.</p>
|
||||
<p>
|
||||
<img src="Customize the Next theme_i.png" width="424" height="140">
|
||||
</p>
|
||||
<p>When <code>appThemeBase</code> is set to <code>next</code> it will use the
|
||||
“TriliumNext (auto)” theme. Any other value is ignored and will use the
|
||||
legacy white theme instead.</p>
|
||||
<h2>Overrides</h2>
|
||||
<p>Do note that the TriliumNext theme has a few more overrides than the legacy
|
||||
theme, so you might need to suffix <code>!important</code> if the style changes
|
||||
are not applied.</p><pre><code class="language-text-css">:root {
|
||||
--launcher-pane-background-color: #0d6efd !important;
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 14 KiB |
@@ -1,180 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="../../../style.css">
|
||||
<base target="_parent">
|
||||
<title data-trilium-title>Reference</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="content">
|
||||
<h1 data-trilium-h1>Reference</h1>
|
||||
|
||||
<div class="ck-content">
|
||||
<h2>Detecting mobile vs. desktop</h2>
|
||||
<p>The mobile layout is different than the one on the desktop. Use <code>body.mobile</code> and <code>body.desktop</code> to
|
||||
differentiate between them.</p><pre><code class="language-text-css">body.mobile #root-widget {
|
||||
/* Do something on mobile */
|
||||
}
|
||||
|
||||
body.desktop #root-widget {
|
||||
/* Do something on desktop */
|
||||
}</code></pre>
|
||||
<p>Do note that there is also a “tablet mode” in the mobile layout. For that
|
||||
particular case media queries are required:</p><pre><code class="language-text-css">@media (max-width: 991px) {
|
||||
|
||||
#launcher-pane {
|
||||
|
||||
/* Do something on mobile layout */
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media (min-width: 992px) {
|
||||
|
||||
#launcher-pane {
|
||||
|
||||
/* Do something on mobile tablet + desktop layout */
|
||||
|
||||
}
|
||||
|
||||
}</code></pre>
|
||||
<h2>Detecting horizontal vs. vertical layout</h2>
|
||||
<p>The user can select between vertical layout (the classical one, where
|
||||
the launcher bar is on the left) and a horizontal layout (where the launcher
|
||||
bar is on the top and tabs are full-width).</p>
|
||||
<p>Different styles can be applied by using classes at <code>body</code> level:</p><pre><code class="language-text-x-trilium-auto">body.layout-vertical #left-pane {
|
||||
/* Do something */
|
||||
}
|
||||
|
||||
body.layout-horizontal #center-pane {
|
||||
/* Do something else */
|
||||
}</code></pre>
|
||||
<p>The two different layouts use different containers (but they are present
|
||||
in the DOM regardless of the user's choice), for example <code>#horizontal-main-container</code> and <code>#vertical-main-container</code> can
|
||||
be used to customize the background of the content section.</p>
|
||||
<h2>Detecting platform (Windows, macOS) or Electron</h2>
|
||||
<p>It is possible to add particular styles that only apply to a given platform
|
||||
by using the classes in <code>body</code>:</p>
|
||||
<figure class="table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Windows</th>
|
||||
<th>macOS</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><pre><code class="language-text-x-trilium-auto">body.platform-win32 {
|
||||
background: red;
|
||||
}</code></pre>
|
||||
</td>
|
||||
<td><pre><code class="language-text-x-trilium-auto">body.platform-darwin {
|
||||
background: red;
|
||||
}</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</figure>
|
||||
<p>It is also possible to only apply a style if running under Electron (desktop
|
||||
application):</p><pre><code class="language-text-x-trilium-auto">body.electron {
|
||||
background: blue;
|
||||
}</code></pre>
|
||||
<h3>Native title bar</h3>
|
||||
<p>It's possible to detect if the user has selected the native title bar
|
||||
or the custom title bar by querying against <code>body</code>:</p><pre><code class="language-text-x-trilium-auto">body.electron.native-titlebar {
|
||||
/* Do something */
|
||||
}
|
||||
|
||||
body.electron:not(.native-titlebar) {
|
||||
/* Do something else */
|
||||
}</code></pre>
|
||||
<h3>Native window buttons</h3>
|
||||
<p>When running under Electron with native title bar off, a feature was introduced
|
||||
to use the platform-specific window buttons such as the semaphore on macOS.</p>
|
||||
<p>See <a href="https://github.com/TriliumNext/Notes/pull/702">Native title bar buttons by eliandoran · Pull Request #702 · TriliumNext/Notes</a> for
|
||||
the original implementation of this feature, including screenshots.</p>
|
||||
<h4>On Windows</h4>
|
||||
<p>The colors of the native window button area can be adjusted using a RGB
|
||||
hex color:</p><pre><code class="language-text-x-trilium-auto">body {
|
||||
--native-titlebar-foreground: #ffffff;
|
||||
--native-titlebar-background: #ff0000;
|
||||
}</code></pre>
|
||||
<p>It is also possible to use transparency at the cost of reduced hover colors
|
||||
using a RGBA hex color:</p><pre><code class="language-text-x-trilium-auto">body {
|
||||
--native-titlebar-background: #ff0000aa;
|
||||
}</code></pre>
|
||||
<p>Note that the value is read when the window is initialized and then it
|
||||
is refreshed only when the user changes their light/dark mode preference.</p>
|
||||
<h4>On macOS</h4>
|
||||
<p>On macOS the semaphore window buttons are enabled by default when the
|
||||
native title bar is disabled. The offset of the buttons can be adjusted
|
||||
using:</p><pre><code class="language-text-css">body {
|
||||
--native-titlebar-darwin-x-offset: 12;
|
||||
--native-titlebar-darwin-y-offset: 14 !important;
|
||||
}</code></pre>
|
||||
<h3>Background/transparency effects on Windows (Mica)</h3>
|
||||
<p>Windows 11 offers a special background/transparency effect called Mica,
|
||||
which can be enabled by themes by setting the <code>--background-material</code> variable
|
||||
at <code>body</code> level:</p><pre><code class="language-text-css">body.electron.platform-win32 {
|
||||
--background-material: tabbed;
|
||||
}</code></pre>
|
||||
<p>The value can be either <code>tabbed</code> (especially useful for the horizontal
|
||||
layout) or <code>mica</code> (ideal for the vertical layout).</p>
|
||||
<p>Do note that the Mica effect is applied at <code>body</code> level and the
|
||||
theme needs to make the entire hierarchy (semi-)transparent in order for
|
||||
it to be visible. Use the TrilumNext theme as an inspiration.</p>
|
||||
<h2>Note icons, tab workspace accent color</h2>
|
||||
<p>Theme capabilities are small adjustments done through CSS variables that
|
||||
can affect the layout or the visual aspect of the application.</p>
|
||||
<p>In the tab bar, to display the icons of notes instead of the icon of the
|
||||
workspace:</p><pre><code class="language-text-css">:root {
|
||||
--tab-note-icons: true;
|
||||
}</code></pre>
|
||||
<p>When a workspace is hoisted for a given tab, it is possible to get the
|
||||
background color of that workspace, for example to apply a small strip
|
||||
on the tab instead of the whole background color:</p><pre><code class="language-text-css">.note-tab .note-tab-wrapper {
|
||||
--tab-background-color: initial !important;
|
||||
}
|
||||
|
||||
.note-tab .note-tab-wrapper::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 3px;
|
||||
background-color: var(--workspace-tab-background-color);
|
||||
}</code></pre>
|
||||
<h2>Custom fonts</h2>
|
||||
<p>Currently the only way to include a custom font is to use <a class="reference-link"
|
||||
href="../Custom%20resource%20providers.html">Custom resource providers</a>.
|
||||
Basically import a font into Trilium and assign it <code>#customResourceProvider=fonts/myfont.ttf</code> and
|
||||
then import the font in CSS via <code>/custom/fonts/myfont.ttf</code>.</p>
|
||||
<h2>Dark and light themes</h2>
|
||||
<p>A light theme needs to have the following CSS:</p><pre><code class="language-text-css">:root {
|
||||
--theme-style: light;
|
||||
}</code></pre>
|
||||
<p>if the theme is dark, then <code>--theme-style</code> needs to be <code>dark</code>.</p>
|
||||
<p>If the theme is auto (e.g. supports both light or dark based on <code>prefers-color-scheme</code>)
|
||||
it must also declare (in addition to setting <code>--theme-style</code> to
|
||||
either <code>light</code> or <code>dark</code>):</p><pre><code class="language-text-css">:root {
|
||||
|
||||
--theme-style-auto: true;
|
||||
|
||||
}</code></pre>
|
||||
<p>This will affect the behavior of the Electron application by informing
|
||||
the operating system of the color preference (e.g. background effects will
|
||||
appear correct on Windows).</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 340 B After Width: | Height: | Size: 340 B |
|
After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
@@ -23,7 +23,7 @@
|
||||
as PDF. On the server or PWA (mobile), the option is not available due
|
||||
to technical constraints and it will be hidden.</p>
|
||||
<p>To print a note, select the
|
||||
<img src="2_Export as PDF_image.png" width="29"
|
||||
<img src="1_Export as PDF_image.png" width="29"
|
||||
height="31">button to the right of the note and select <i>Export as PDF</i>.</p>
|
||||
<p>Afterwards you will be prompted to select where to save the PDF file.
|
||||
Upon confirmation, the resulting PDF will be opened automatically using
|
||||
@@ -33,7 +33,7 @@
|
||||
<a
|
||||
href="#root/OeKBfN6JbMIq/jRV1MPt4mNSP/hrC6xn7hnDq5">report the issue</a>. In this case, it's best to offer a sample note (click
|
||||
on the
|
||||
<img src="2_Export as PDF_image.png" width="29" height="31">button, select Export note → This note and all of its descendants → HTML
|
||||
<img src="1_Export as PDF_image.png" width="29" height="31">button, select Export note → This note and all of its descendants → HTML
|
||||
in ZIP archive). Make sure not to accidentally leak any personal information.</p>
|
||||
<h2>Landscape mode</h2>
|
||||
<p>When exporting to PDF, there are no customizable settings such as page
|
||||
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
@@ -0,0 +1,56 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="../../style.css">
|
||||
<base target="_parent">
|
||||
<title data-trilium-title>Right-to-left text notes</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="content">
|
||||
<h1 data-trilium-h1>Right-to-left text notes</h1>
|
||||
|
||||
<div class="ck-content">
|
||||
<p>Trilium now has basic support for right-to-left text, at note level.</p>
|
||||
<figure
|
||||
class="table">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<figure class="image">
|
||||
<img style="aspect-ratio:906/557;" src="3_Right-to-left text notes_i.png"
|
||||
width="906" height="557">
|
||||
</figure>
|
||||
</td>
|
||||
<td>
|
||||
<figure class="image">
|
||||
<img style="aspect-ratio:906/557;" src="2_Right-to-left text notes_i.png"
|
||||
width="906" height="557">
|
||||
</figure>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</figure>
|
||||
<p>Note that only the Text note type supports this.</p>
|
||||
<p>The list of languages is configurable via the a new dedicated settings
|
||||
page:</p>
|
||||
<figure class="image">
|
||||
<img style="aspect-ratio:1248/635;" src="4_Right-to-left text notes_i.png"
|
||||
width="1248" height="635">
|
||||
</figure>
|
||||
<p>To select the corresponding language of the text, go to “Basic Properties”
|
||||
and select your desired language.</p>
|
||||
<p>
|
||||
<img src="1_Right-to-left text notes_i.png" width="635" height="492">
|
||||
</p>
|
||||
<p>Feel free to report any issues regarding right to left support.</p>
|
||||
<p> </p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 260 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 323 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 323 KiB After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 191 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 515 KiB |
|
Before Width: | Height: | Size: 515 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 397 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 397 KiB After Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 9.7 KiB |