mirror of
https://github.com/zadam/trilium.git
synced 2026-05-06 22:17:01 +02:00
Compare commits
2274 Commits
feat/extra
...
autocomple
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a820d1d6ef | ||
|
|
69af1f6e82 | ||
|
|
a8408fbc68 | ||
|
|
8828df733a | ||
|
|
4413566e14 | ||
|
|
c1c98a6955 | ||
|
|
6e222bb901 | ||
|
|
82b8601e0b | ||
|
|
47e515bc77 | ||
|
|
eef35c3a5f | ||
|
|
a18d0484c5 | ||
|
|
4eaa3d7ac1 | ||
|
|
ad24cf9ab9 | ||
|
|
5467d7719d | ||
|
|
875b3a3f9a | ||
|
|
4ab6a66c75 | ||
|
|
53e157567d | ||
|
|
5725680d3a | ||
|
|
07fe884fd8 | ||
|
|
8d57a593d8 | ||
|
|
fb9f33b9ff | ||
|
|
2c690d4dd2 | ||
|
|
7db7dc287f | ||
|
|
dece273c2b | ||
|
|
bf7449bc90 | ||
|
|
6f3c9e2883 | ||
|
|
49248a636a | ||
|
|
f51b0eb4de | ||
|
|
f0d06815ec | ||
|
|
070701ee9e | ||
|
|
57fefaae1d | ||
|
|
1d109f592b | ||
|
|
29b01c3fe6 | ||
|
|
6cd263a897 | ||
|
|
c9ca1de271 | ||
|
|
c369ba416c | ||
|
|
4b3d923d29 | ||
|
|
64c3d0b36d | ||
|
|
0fdc3590dc | ||
|
|
26fd6a573d | ||
|
|
59d8961111 | ||
|
|
9b733849a9 | ||
|
|
133b847b15 | ||
|
|
ecdbed6bac | ||
|
|
d1deccc23c | ||
|
|
c71d8a87b9 | ||
|
|
0614d92597 | ||
|
|
9ab7e8e2b7 | ||
|
|
0a5543cc72 | ||
|
|
6d000d7b7c | ||
|
|
ac4ca16e85 | ||
|
|
e248d93e29 | ||
|
|
acd786da67 | ||
|
|
ef19d6260c | ||
|
|
638e1ebd1d | ||
|
|
0c5efc3dcb | ||
|
|
a774218429 | ||
|
|
e305be9e75 | ||
|
|
f267dd5fc1 | ||
|
|
6ba736b83f | ||
|
|
5eb8715295 | ||
|
|
7654be5132 | ||
|
|
3f4358a422 | ||
|
|
b3ca412bbd | ||
|
|
d1f60840a2 | ||
|
|
a337ace856 | ||
|
|
0b6f6dee7f | ||
|
|
93f1743432 | ||
|
|
3fb4ab1a31 | ||
|
|
8970d02404 | ||
|
|
b671aa6204 | ||
|
|
7ffb8b0202 | ||
|
|
6564ea2738 | ||
|
|
0a673d2f1b | ||
|
|
05eea0d1f1 | ||
|
|
1215fbf3e1 | ||
|
|
ea206116cb | ||
|
|
7d87c89668 | ||
|
|
b0431f2338 | ||
|
|
d1cb56de71 | ||
|
|
e6c5df30d7 | ||
|
|
4f7cf741ab | ||
|
|
76fc9eaeb0 | ||
|
|
a4b7f54c64 | ||
|
|
53192d202d | ||
|
|
6896ed2c70 | ||
|
|
5a96b9c48d | ||
|
|
6113bfc57f | ||
|
|
9d7bc20f26 | ||
|
|
79788937b9 | ||
|
|
66873f16f2 | ||
|
|
532e001ef0 | ||
|
|
17991bf31f | ||
|
|
2b21b1f75e | ||
|
|
dae1f9302c | ||
|
|
33365cdaf1 | ||
|
|
3ac66ffe72 | ||
|
|
81baf13720 | ||
|
|
e0e96350d6 | ||
|
|
c539c21ced | ||
|
|
3f7f6cf982 | ||
|
|
271d87ae33 | ||
|
|
533a77e606 | ||
|
|
77cf2d4dd9 | ||
|
|
890cb247c1 | ||
|
|
8d7f4dd0fa | ||
|
|
00c4933344 | ||
|
|
cd9b46e1c7 | ||
|
|
b356b355ca | ||
|
|
d1aebb7bb0 | ||
|
|
6cbb595ae8 | ||
|
|
fcf238bc35 | ||
|
|
8c82468ecc | ||
|
|
965905ce00 | ||
|
|
ed280775bd | ||
|
|
8834899012 | ||
|
|
55dea474e9 | ||
|
|
bc74455a64 | ||
|
|
2d0b28367f | ||
|
|
7d8a3e2811 | ||
|
|
79e5d9595a | ||
|
|
1f0fa57218 | ||
|
|
0310626025 | ||
|
|
fefbb40c03 | ||
|
|
12f89078b8 | ||
|
|
8d873c5869 | ||
|
|
27f4ac1d03 | ||
|
|
d533360903 | ||
|
|
49f5dc1c26 | ||
|
|
16419ed4ac | ||
|
|
1595d1b5c9 | ||
|
|
50eb11997c | ||
|
|
d974dfbc31 | ||
|
|
e9b63e50d4 | ||
|
|
b6efb7c9ab | ||
|
|
f84479b1c2 | ||
|
|
8597fa560b | ||
|
|
b29ab93fd5 | ||
|
|
225cdaff46 | ||
|
|
61dfba8c32 | ||
|
|
4fee91d219 | ||
|
|
12e4f76a8b | ||
|
|
ec30598397 | ||
|
|
f65ddb08a0 | ||
|
|
22507f75bd | ||
|
|
915c49b472 | ||
|
|
aa58ad2812 | ||
|
|
17609799da | ||
|
|
f6201d8581 | ||
|
|
5b77152fdf | ||
|
|
b419602d74 | ||
|
|
2c9a0ed682 | ||
|
|
59ebd0f122 | ||
|
|
334c8cbea3 | ||
|
|
5adc79f867 | ||
|
|
d1fc4780b7 | ||
|
|
99937bd8f4 | ||
|
|
03a9685c96 | ||
|
|
39408f2b22 | ||
|
|
eeb917ea97 | ||
|
|
5ea355a587 | ||
|
|
e4ad356a02 | ||
|
|
ff939071ac | ||
|
|
3f97516d98 | ||
|
|
f06dd3cfea | ||
|
|
0dee06262b | ||
|
|
3ac2e2785d | ||
|
|
9869d29146 | ||
|
|
a1b51e1de8 | ||
|
|
cd7fb3d584 | ||
|
|
b92a5d1188 | ||
|
|
530e606ddb | ||
|
|
b6dea44460 | ||
|
|
a5445d35cb | ||
|
|
128fa63e7e | ||
|
|
8a4a06e656 | ||
|
|
0ca54396aa | ||
|
|
3a6606b9ac | ||
|
|
1614ccf6f6 | ||
|
|
27a7a157d5 | ||
|
|
d5b496e597 | ||
|
|
06f2aa1fd8 | ||
|
|
3328266cae | ||
|
|
6dd5352f40 | ||
|
|
eaf89c63a1 | ||
|
|
34ce5ebcbb | ||
|
|
c7980f42fe | ||
|
|
fdd2cc77e6 | ||
|
|
6f5c618bcd | ||
|
|
8041112414 | ||
|
|
40ab2bc798 | ||
|
|
3a3029cf3a | ||
|
|
e7d1c75cdb | ||
|
|
bc907ee6ad | ||
|
|
0bff3f1fbc | ||
|
|
377864b2c6 | ||
|
|
3db13df245 | ||
|
|
a2e09b40fa | ||
|
|
aa590753d5 | ||
|
|
1c8519d7ec | ||
|
|
686a614bfa | ||
|
|
01261220e3 | ||
|
|
1bf92ab19a | ||
|
|
c0d0d1868d | ||
|
|
da2dec16cc | ||
|
|
787ef7d513 | ||
|
|
dcb0ce79e6 | ||
|
|
9d8202539d | ||
|
|
c46af4bca9 | ||
|
|
610f6652df | ||
|
|
b33635381b | ||
|
|
f20af8cac9 | ||
|
|
29f3b987aa | ||
|
|
e9987b40e6 | ||
|
|
1990a990c3 | ||
|
|
d1159d3af9 | ||
|
|
723dada78a | ||
|
|
0e089af677 | ||
|
|
f4aed5d012 | ||
|
|
860f953962 | ||
|
|
ded692ead7 | ||
|
|
4f5413ebbe | ||
|
|
8f3e210740 | ||
|
|
783cb8b4e9 | ||
|
|
2b94d96930 | ||
|
|
ca349e03f2 | ||
|
|
5b5222b846 | ||
|
|
850f8ad939 | ||
|
|
50e5f89e9a | ||
|
|
603b47f9b0 | ||
|
|
92227c364e | ||
|
|
10ac18a7cc | ||
|
|
e06123e4bd | ||
|
|
b44bd544cd | ||
|
|
4c3a448330 | ||
|
|
7f07c249af | ||
|
|
51958d2ac0 | ||
|
|
67f474d794 | ||
|
|
e6e8ebd881 | ||
|
|
b138fedd35 | ||
|
|
a92d846b57 | ||
|
|
7a544482d1 | ||
|
|
53739ee8d4 | ||
|
|
495145e033 | ||
|
|
6701d09df5 | ||
|
|
e36d7121f1 | ||
|
|
9290a60b23 | ||
|
|
761de79a8c | ||
|
|
b8e9beff1b | ||
|
|
5b13e0ba4f | ||
|
|
b0bab18d00 | ||
|
|
b4fa1392de | ||
|
|
4e58002e13 | ||
|
|
adc149aac8 | ||
|
|
4c02773ddc | ||
|
|
892abe1d70 | ||
|
|
71c23d33ff | ||
|
|
9c110e896e | ||
|
|
afe7a748e1 | ||
|
|
325e582593 | ||
|
|
ccebe6a423 | ||
|
|
f7c92fa4b2 | ||
|
|
d07c2d118f | ||
|
|
94a09edd1d | ||
|
|
f6f939c245 | ||
|
|
0d889426e8 | ||
|
|
c8a546ef1e | ||
|
|
693919b21a | ||
|
|
7c1a2039b1 | ||
|
|
c66e4e0475 | ||
|
|
6bdfbf0d7d | ||
|
|
61393bca90 | ||
|
|
c41b649bff | ||
|
|
ba87487714 | ||
|
|
3e73f38ae2 | ||
|
|
51dd55c3fd | ||
|
|
de49ca37b9 | ||
|
|
8d8080ee09 | ||
|
|
f3613ccb25 | ||
|
|
ad7b5700f3 | ||
|
|
0d17c62d02 | ||
|
|
826690982a | ||
|
|
b438ff9c62 | ||
|
|
43fb9d1a23 | ||
|
|
fb17ce8c8a | ||
|
|
3a8e12535e | ||
|
|
ce0caa3f6d | ||
|
|
00a0315f12 | ||
|
|
da38d56dc7 | ||
|
|
83e47cba2c | ||
|
|
f4d1eebed4 | ||
|
|
f27b394099 | ||
|
|
a66c9ccc1f | ||
|
|
0bc6a830c8 | ||
|
|
f3008b29af | ||
|
|
5b16ff8be1 | ||
|
|
86621e3388 | ||
|
|
1beb0668c3 | ||
|
|
34b09f90fb | ||
|
|
a6f964925b | ||
|
|
196416bb9f | ||
|
|
1535db9f7d | ||
|
|
ae38ac4de8 | ||
|
|
e0aa8d8ecf | ||
|
|
23c1eacf2b | ||
|
|
10e28789e2 | ||
|
|
940f7f77f5 | ||
|
|
83f8b4fcb4 | ||
|
|
42dc801ddf | ||
|
|
5e6e5bfbec | ||
|
|
28fc99dd45 | ||
|
|
9ef501c399 | ||
|
|
6bba908654 | ||
|
|
d423e43312 | ||
|
|
91718f218b | ||
|
|
e623e91a82 | ||
|
|
dce9f50911 | ||
|
|
5f1486cf6a | ||
|
|
2c6bdc79af | ||
|
|
a6b89cfa30 | ||
|
|
21d1cd395b | ||
|
|
981466cbe8 | ||
|
|
0209573fce | ||
|
|
92f8459f28 | ||
|
|
da193b456b | ||
|
|
6c151afca3 | ||
|
|
aba6750c18 | ||
|
|
b9a8e4e4ba | ||
|
|
4134c4ddd0 | ||
|
|
72038fb2ec | ||
|
|
069d8b1ae4 | ||
|
|
ce71068f6d | ||
|
|
dc298a44e1 | ||
|
|
306bfd7673 | ||
|
|
25cf23f507 | ||
|
|
096d5f7c65 | ||
|
|
0e2dee1609 | ||
|
|
ec927d25a9 | ||
|
|
7c8aefb4ef | ||
|
|
e840769dd6 | ||
|
|
4a5d3f01b8 | ||
|
|
71d975f339 | ||
|
|
a4051fc372 | ||
|
|
359b2a68b8 | ||
|
|
8124e4e589 | ||
|
|
5f699996f8 | ||
|
|
c7c0bc4185 | ||
|
|
d422ac7bc5 | ||
|
|
0bd912d18a | ||
|
|
252f2fe72c | ||
|
|
7f29c347e2 | ||
|
|
7a3dc824d6 | ||
|
|
8550c62771 | ||
|
|
66cd657cd8 | ||
|
|
beac80e175 | ||
|
|
5ae9952ba1 | ||
|
|
d4bc1ec444 | ||
|
|
d52f529b24 | ||
|
|
9a9cfdec2b | ||
|
|
6ab421ffa0 | ||
|
|
53b0aafb98 | ||
|
|
6b02ad8421 | ||
|
|
242ebfccc0 | ||
|
|
545cc0782f | ||
|
|
bf6a2917cd | ||
|
|
eaba2a8395 | ||
|
|
c581fb17bc | ||
|
|
9b05b95d77 | ||
|
|
b3ba18ddd0 | ||
|
|
bb2a633ba7 | ||
|
|
913efdef03 | ||
|
|
bf0bea18b1 | ||
|
|
cdebd1f63a | ||
|
|
a6a2635836 | ||
|
|
024b57c2b4 | ||
|
|
6fbc85cbc7 | ||
|
|
5f8a0aee13 | ||
|
|
0c67b292ef | ||
|
|
ba663e6162 | ||
|
|
14925266cf | ||
|
|
702e29bd8c | ||
|
|
27ac3e58c5 | ||
|
|
86e268c06d | ||
|
|
6e4b231319 | ||
|
|
041eff6cbd | ||
|
|
1a3471a516 | ||
|
|
57c8727bb1 | ||
|
|
bd451d0738 | ||
|
|
ced062842d | ||
|
|
a1bf7bfa08 | ||
|
|
2a67c93c20 | ||
|
|
b51bfdfb33 | ||
|
|
9aa84877ee | ||
|
|
9e99670b19 | ||
|
|
744b93dd98 | ||
|
|
5abb77242c | ||
|
|
4ab3b0dd2b | ||
|
|
a6a1594265 | ||
|
|
b06cdd442d | ||
|
|
f7067fb968 | ||
|
|
cf0f5ba4c4 | ||
|
|
309a81a0fe | ||
|
|
caa428c1a2 | ||
|
|
517c721664 | ||
|
|
a8cdaa69f7 | ||
|
|
53d221ef34 | ||
|
|
5450fde472 | ||
|
|
808446cef5 | ||
|
|
921c663199 | ||
|
|
1b8a75b615 | ||
|
|
f78ced5bc3 | ||
|
|
81bf5f4f3b | ||
|
|
aaed368670 | ||
|
|
5e8de14721 | ||
|
|
634ab5b5c0 | ||
|
|
906889a035 | ||
|
|
ab9d50b905 | ||
|
|
e61b7c7cfc | ||
|
|
1c628fba4c | ||
|
|
f8b4c6cb15 | ||
|
|
3edd8f6c5a | ||
|
|
7777f72893 | ||
|
|
9af85b767b | ||
|
|
73260b91eb | ||
|
|
2858f63873 | ||
|
|
15ca328727 | ||
|
|
5b3fbecc0f | ||
|
|
365d0f0aac | ||
|
|
e86d84c463 | ||
|
|
6b974c2ac7 | ||
|
|
d2afcbb98d | ||
|
|
68a122fcf5 | ||
|
|
92f0144b48 | ||
|
|
a5a345728c | ||
|
|
23890e64e9 | ||
|
|
3de712aca4 | ||
|
|
cb5b4d870f | ||
|
|
f81aef2de5 | ||
|
|
06aed16ea1 | ||
|
|
aa2d8af15c | ||
|
|
dc7b91433b | ||
|
|
72951386b1 | ||
|
|
db8df01d82 | ||
|
|
98713ed111 | ||
|
|
3e88fecb15 | ||
|
|
fe4255f2fc | ||
|
|
c046a57654 | ||
|
|
d8fc0d45a8 | ||
|
|
567b96cfb4 | ||
|
|
d25849d280 | ||
|
|
d4d73995db | ||
|
|
f4657b5da9 | ||
|
|
614f43cb8a | ||
|
|
ca2fbf8dba | ||
|
|
a421513442 | ||
|
|
a9599c471a | ||
|
|
415bcac641 | ||
|
|
9527017314 | ||
|
|
1d3d7c77f8 | ||
|
|
e868615fd5 | ||
|
|
80493a52be | ||
|
|
3fed2ba42e | ||
|
|
82592ada54 | ||
|
|
5528701744 | ||
|
|
0ca665fb85 | ||
|
|
7eb452ed8b | ||
|
|
d81dec94a9 | ||
|
|
6631a4a806 | ||
|
|
12f817c896 | ||
|
|
87229600d2 | ||
|
|
471a46a030 | ||
|
|
41220eebd5 | ||
|
|
755872277b | ||
|
|
2cb54d7021 | ||
|
|
5a16bafbbf | ||
|
|
fc6e9d89d9 | ||
|
|
8af35da279 | ||
|
|
7107fec1a4 | ||
|
|
4bb662c5fb | ||
|
|
89297b92f8 | ||
|
|
e019271e74 | ||
|
|
f6d61eefcc | ||
|
|
fabc07be42 | ||
|
|
bccfa7956c | ||
|
|
42a05f411b | ||
|
|
7ba7b98f5f | ||
|
|
2132c2ab38 | ||
|
|
2ce4d512e7 | ||
|
|
1258d32820 | ||
|
|
db763ba229 | ||
|
|
951fdaec70 | ||
|
|
4303f3687e | ||
|
|
540b0e0b83 | ||
|
|
08a0326cb0 | ||
|
|
8b0a45e4fd | ||
|
|
0e0ad2ed73 | ||
|
|
4c73f31aca | ||
|
|
6b2ae8fd12 | ||
|
|
88d84fae1e | ||
|
|
cdc46faaad | ||
|
|
24dbc79961 | ||
|
|
8cb58dcc45 | ||
|
|
fe70b8aee6 | ||
|
|
00f66cfb49 | ||
|
|
3a4b080765 | ||
|
|
41269ef987 | ||
|
|
e521c6a386 | ||
|
|
1c35a557c1 | ||
|
|
99eb8389c5 | ||
|
|
c5e560ef5b | ||
|
|
a7d7a078b1 | ||
|
|
a06fa5222f | ||
|
|
8d3e40a28a | ||
|
|
8e32f99790 | ||
|
|
57bce62e48 | ||
|
|
1c873394d5 | ||
|
|
d652f67364 | ||
|
|
5e54d098c5 | ||
|
|
ec95303c31 | ||
|
|
07aafe7e89 | ||
|
|
dc7acbb70e | ||
|
|
0dcb8b3ff8 | ||
|
|
e4ddff01ca | ||
|
|
015c1161d4 | ||
|
|
ca0c6076c5 | ||
|
|
80a02f88be | ||
|
|
430833bedb | ||
|
|
dc80d83964 | ||
|
|
5f7ade45f4 | ||
|
|
8b36a7ab1e | ||
|
|
fd18276693 | ||
|
|
0becfc16ba | ||
|
|
d480d1f6ba | ||
|
|
f5c9a71ba0 | ||
|
|
c177a8a464 | ||
|
|
c826564c9e | ||
|
|
ccb13fa6b9 | ||
|
|
69e374138f | ||
|
|
3156b2cb59 | ||
|
|
d6217ffed4 | ||
|
|
fc90c6af9d | ||
|
|
a1118419ec | ||
|
|
8599785ee8 | ||
|
|
99ba192a44 | ||
|
|
b86d3587ac | ||
|
|
b2a0baf56a | ||
|
|
22f37817e5 | ||
|
|
6b4fe03625 | ||
|
|
f44b47ec23 | ||
|
|
8d667e838a | ||
|
|
f32385de2e | ||
|
|
90796fc4fa | ||
|
|
4960c49cb2 | ||
|
|
b112e8b56b | ||
|
|
83095130f6 | ||
|
|
d005c0ef2d | ||
|
|
c135578626 | ||
|
|
9a6e20029e | ||
|
|
39bd4ccea1 | ||
|
|
aac4774326 | ||
|
|
ea7aac2030 | ||
|
|
e7f98f08d0 | ||
|
|
8ac9daa5d3 | ||
|
|
0b506c6327 | ||
|
|
d2b62540ec | ||
|
|
64418c7fec | ||
|
|
8c1a58e64f | ||
|
|
b27fd31c1f | ||
|
|
f18a531924 | ||
|
|
3cabb4b661 | ||
|
|
5c88b1c6b8 | ||
|
|
c2adc43780 | ||
|
|
7eaa5352ba | ||
|
|
17e3e3187b | ||
|
|
2ad7cd3a49 | ||
|
|
39aa8d61c2 | ||
|
|
1a3ea977b7 | ||
|
|
4cd8f9a1e6 | ||
|
|
87ce6d1231 | ||
|
|
8fdbeacf77 | ||
|
|
f4f775a1c9 | ||
|
|
fe1154cb2d | ||
|
|
638f479ff3 | ||
|
|
70436bdb04 | ||
|
|
575ecaae07 | ||
|
|
d277e6db94 | ||
|
|
25efcd12d0 | ||
|
|
10129321be | ||
|
|
72710a8f6b | ||
|
|
6a7c5c04d8 | ||
|
|
7f32fe5ef7 | ||
|
|
5d89591dea | ||
|
|
a88bf5a87b | ||
|
|
bbe5d3506e | ||
|
|
c2993d4e7d | ||
|
|
17ba479182 | ||
|
|
a465014bbe | ||
|
|
5dfe253ef6 | ||
|
|
ae7ca6021f | ||
|
|
c389697acd | ||
|
|
c13c3e0f4a | ||
|
|
82c042d045 | ||
|
|
9145ba1690 | ||
|
|
d60653ee17 | ||
|
|
dae8613b4e | ||
|
|
2f8e2c40be | ||
|
|
d85225a0dc | ||
|
|
0cb66df2b2 | ||
|
|
92e0578cb6 | ||
|
|
2eee06786e | ||
|
|
19053dcb3b | ||
|
|
e10c30c59f | ||
|
|
c356159664 | ||
|
|
579be68ca1 | ||
|
|
a6326a682e | ||
|
|
4595a3a5dd | ||
|
|
ee21185e64 | ||
|
|
6d0676c37d | ||
|
|
1d4768a581 | ||
|
|
d086bb7fcb | ||
|
|
2607c4a32e | ||
|
|
624333a2ef | ||
|
|
d4acb37f21 | ||
|
|
6c1a1e9812 | ||
|
|
9a13641f9b | ||
|
|
699e0624c9 | ||
|
|
47ceb0d4d2 | ||
|
|
15c42f4a09 | ||
|
|
bf8401bb26 | ||
|
|
f234433c63 | ||
|
|
1b70101123 | ||
|
|
d610c63c28 | ||
|
|
5e820a407f | ||
|
|
62610979b7 | ||
|
|
700e99e854 | ||
|
|
7767116b3d | ||
|
|
0206e8247b | ||
|
|
5476fe3df9 | ||
|
|
d9a4581d37 | ||
|
|
8d9c888481 | ||
|
|
11e4b672d1 | ||
|
|
bace3daadc | ||
|
|
dee5380e60 | ||
|
|
bc6a6fd860 | ||
|
|
e928337fe9 | ||
|
|
432f86ea4b | ||
|
|
5d2daecee0 | ||
|
|
7c8eb311af | ||
|
|
4ac22678df | ||
|
|
5057c02176 | ||
|
|
d301e56216 | ||
|
|
3c22ab8c9c | ||
|
|
0212398815 | ||
|
|
db0c515bad | ||
|
|
9b4f8c5003 | ||
|
|
85d8c4c8fa | ||
|
|
5afab6938a | ||
|
|
a437169ad5 | ||
|
|
f632d3aeb6 | ||
|
|
513fffcb1a | ||
|
|
d3337eab9c | ||
|
|
8128a8192a | ||
|
|
c80bb9657c | ||
|
|
65514a6fd7 | ||
|
|
93a7f8c711 | ||
|
|
0ca179f990 | ||
|
|
9d104015f3 | ||
|
|
2c4cf2dcf1 | ||
|
|
d2e0124962 | ||
|
|
cd59c75c04 | ||
|
|
caa9143591 | ||
|
|
7e53810c02 | ||
|
|
12efa8dc0b | ||
|
|
4d0ccac7b5 | ||
|
|
8b023a55d0 | ||
|
|
b4df5fcbd9 | ||
|
|
6fbe5718e9 | ||
|
|
908bafca63 | ||
|
|
d7313efd67 | ||
|
|
a51e15c9b8 | ||
|
|
37e9c7d639 | ||
|
|
2d00ac4dfb | ||
|
|
6aec7eae00 | ||
|
|
6bfbc2d35e | ||
|
|
2ffc854ce6 | ||
|
|
ddd4a374e4 | ||
|
|
0d6e2fc00f | ||
|
|
366a8e8726 | ||
|
|
7f0aa0697a | ||
|
|
d123ce33b8 | ||
|
|
55588f5962 | ||
|
|
f32130d5c2 | ||
|
|
03f4ff9e7c | ||
|
|
6de78c7154 | ||
|
|
d331e418d4 | ||
|
|
4ace74bcb8 | ||
|
|
1d4a336256 | ||
|
|
ee6c192ab9 | ||
|
|
b220bdce9c | ||
|
|
4d86c6c4f1 | ||
|
|
4fd68bf12d | ||
|
|
3ffe34964f | ||
|
|
faaf26c174 | ||
|
|
f9c7518db2 | ||
|
|
8357c2a39c | ||
|
|
793dcee562 | ||
|
|
00368fc131 | ||
|
|
f81b686f41 | ||
|
|
4c5aada5d3 | ||
|
|
05551cec9e | ||
|
|
6300a8c8d1 | ||
|
|
ca4d15727d | ||
|
|
2fe076086e | ||
|
|
56b65ddfae | ||
|
|
fcf6673825 | ||
|
|
9eda264f52 | ||
|
|
fe1270c679 | ||
|
|
679e1ac678 | ||
|
|
e309ff2d17 | ||
|
|
c910335155 | ||
|
|
5606cde506 | ||
|
|
0e2f4f4e13 | ||
|
|
1f6c6f2acd | ||
|
|
37d2e9f14b | ||
|
|
0fcf30a3b8 | ||
|
|
8712e7dd16 | ||
|
|
2ee4e9cc14 | ||
|
|
b257b75be2 | ||
|
|
2de2709420 | ||
|
|
3e0ddd90a1 | ||
|
|
b96b004262 | ||
|
|
e1ad48b42a | ||
|
|
420f0917be | ||
|
|
31d8287e1b | ||
|
|
4433d034db | ||
|
|
c96114992e | ||
|
|
b35e0b906f | ||
|
|
104c9ec64a | ||
|
|
6e4b18b57b | ||
|
|
f9460c8f41 | ||
|
|
02601f37d8 | ||
|
|
0feab6d4ed | ||
|
|
5a9d3499d8 | ||
|
|
dce0988409 | ||
|
|
b2d378db6b | ||
|
|
7ecff88da7 | ||
|
|
b434bf8804 | ||
|
|
441484629a | ||
|
|
37a1bd6b25 | ||
|
|
fe3dfc418f | ||
|
|
34ca7912fc | ||
|
|
1d698106da | ||
|
|
b9ce83165f | ||
|
|
34670dd69c | ||
|
|
54be58ba1f | ||
|
|
b9abdcb189 | ||
|
|
9f0f9b8315 | ||
|
|
63ee60ffc7 | ||
|
|
3b2cd5dca1 | ||
|
|
388a6943e9 | ||
|
|
50301be093 | ||
|
|
123e1ada90 | ||
|
|
5c42dbba12 | ||
|
|
a549fd228e | ||
|
|
6e352e5b22 | ||
|
|
1d3df69bb7 | ||
|
|
c6394698fa | ||
|
|
d94f2ac093 | ||
|
|
740974fbfd | ||
|
|
f0b9e0e48b | ||
|
|
deee50f2b4 | ||
|
|
2c9d5368a1 | ||
|
|
819432b4ab | ||
|
|
7efbb4d945 | ||
|
|
64d1b33a4c | ||
|
|
326adc0196 | ||
|
|
b1b9a4461e | ||
|
|
d70f5d3ed6 | ||
|
|
d1fac8f0e2 | ||
|
|
5f7c26eed3 | ||
|
|
bf748cee24 | ||
|
|
79439f6435 | ||
|
|
2a875f8386 | ||
|
|
08e69d405c | ||
|
|
471f380756 | ||
|
|
700edbe2c8 | ||
|
|
d60c117c62 | ||
|
|
4ae395ded5 | ||
|
|
f311db1cb4 | ||
|
|
40be94804c | ||
|
|
5719819947 | ||
|
|
c938bcc657 | ||
|
|
e029379194 | ||
|
|
d56f106964 | ||
|
|
676dea33e1 | ||
|
|
945b00030b | ||
|
|
a47de6c65c | ||
|
|
7c89c66526 | ||
|
|
8554dc249c | ||
|
|
bfcbfac5bb | ||
|
|
59d8a98eea | ||
|
|
c7d74e8b00 | ||
|
|
dc3de5bf36 | ||
|
|
680cd8118f | ||
|
|
1041bf70e1 | ||
|
|
0c6326b678 | ||
|
|
f4d91e48ba | ||
|
|
fd805a5279 | ||
|
|
9374694a0c | ||
|
|
61460daaea | ||
|
|
d64c1f6b0e | ||
|
|
0334166029 | ||
|
|
7fac172ce2 | ||
|
|
3b9f765c24 | ||
|
|
655b016efa | ||
|
|
aa247ef06c | ||
|
|
9e653a87b8 | ||
|
|
dfb44def2b | ||
|
|
f0e8c0f79d | ||
|
|
28fe73911f | ||
|
|
a971640ffc | ||
|
|
44dc8cf00d | ||
|
|
59ca270880 | ||
|
|
abb5fe5b0f | ||
|
|
af0e4088a6 | ||
|
|
6b82943871 | ||
|
|
d7aa744bad | ||
|
|
f417a2e126 | ||
|
|
b937f474e4 | ||
|
|
6a3c4fec98 | ||
|
|
6bda7837d6 | ||
|
|
ab9144972b | ||
|
|
bcb646f42b | ||
|
|
0db75a6cdb | ||
|
|
76c7b8692d | ||
|
|
1061aba212 | ||
|
|
d4eb6f07bd | ||
|
|
f1a83124a8 | ||
|
|
2ad30c6a3d | ||
|
|
0f1533d0a0 | ||
|
|
bf5caaebb5 | ||
|
|
b24d2c65a1 | ||
|
|
2d989dcfe3 | ||
|
|
8e8e6f9ed1 | ||
|
|
e1de98c4ae | ||
|
|
aba7f35d9f | ||
|
|
8c9ad575ef | ||
|
|
fc59ee6e93 | ||
|
|
5ec9770b07 | ||
|
|
1c1895b2eb | ||
|
|
7861bc41f9 | ||
|
|
843e4d45e6 | ||
|
|
416825c9c2 | ||
|
|
6762539b4d | ||
|
|
ae9827c436 | ||
|
|
4b4b427d2b | ||
|
|
33622cd3fe | ||
|
|
807b054a95 | ||
|
|
b223b931ab | ||
|
|
6759fef827 | ||
|
|
896d50b1f8 | ||
|
|
2049c49fdb | ||
|
|
b3c397e847 | ||
|
|
e69b85a988 | ||
|
|
aabc9ec4df | ||
|
|
598501e3f6 | ||
|
|
bfa344a839 | ||
|
|
c466d7ee9f | ||
|
|
2e9c07d3d6 | ||
|
|
9651ca99f3 | ||
|
|
a6e87f5724 | ||
|
|
cf994dac5a | ||
|
|
95c9c375c9 | ||
|
|
f9804eda8e | ||
|
|
88c2bedbd7 | ||
|
|
49bf49c967 | ||
|
|
506b5c44af | ||
|
|
22ea59a63b | ||
|
|
934aaaf045 | ||
|
|
c6bfcea79f | ||
|
|
6e39fb12e2 | ||
|
|
dbe534d8f8 | ||
|
|
04e5197d00 | ||
|
|
3a15878629 | ||
|
|
021a908c9c | ||
|
|
c09ef3af80 | ||
|
|
3151e6dafc | ||
|
|
e9dc97daf8 | ||
|
|
3a3cc565ea | ||
|
|
fcf4ffb445 | ||
|
|
b34c27af1f | ||
|
|
64371a6b9c | ||
|
|
182afab12c | ||
|
|
57e888911d | ||
|
|
535054b2d2 | ||
|
|
d40191257c | ||
|
|
87ee1185f2 | ||
|
|
f4b0f810bd | ||
|
|
0934e33af7 | ||
|
|
b3e88f5a44 | ||
|
|
2f23db0c64 | ||
|
|
ca2f39bacd | ||
|
|
e38b89996a | ||
|
|
8efbb8819b | ||
|
|
e03bd3d716 | ||
|
|
cfb56cb143 | ||
|
|
477e516473 | ||
|
|
fd601eac5b | ||
|
|
df4fa42acd | ||
|
|
b06d390df5 | ||
|
|
7f013a58f5 | ||
|
|
1fd0fb03fa | ||
|
|
7ec718218e | ||
|
|
b5300e5b86 | ||
|
|
19d2f02694 | ||
|
|
fec929dfee | ||
|
|
d7339ff14d | ||
|
|
422bc00ade | ||
|
|
8edf5483a6 | ||
|
|
00046d4145 | ||
|
|
25e67f62d5 | ||
|
|
8d233e66e1 | ||
|
|
39e0d5b629 | ||
|
|
90844d5bc2 | ||
|
|
29df06626b | ||
|
|
d28661fee3 | ||
|
|
dc8c10e531 | ||
|
|
538e1f0fdd | ||
|
|
eaf0c690e1 | ||
|
|
a4a3d6a82c | ||
|
|
e5eab3952b | ||
|
|
9b45639148 | ||
|
|
e53cd7443a | ||
|
|
60b74f5959 | ||
|
|
a3e4044fec | ||
|
|
f380df9c01 | ||
|
|
83fc82a615 | ||
|
|
eaf3632fc9 | ||
|
|
1d947f26ff | ||
|
|
34a08be4cd | ||
|
|
f84a4c4856 | ||
|
|
47aa24d0f4 | ||
|
|
e6e132e905 | ||
|
|
ad2df957c7 | ||
|
|
818ca2c2ab | ||
|
|
72c34eb491 | ||
|
|
22341bf0b1 | ||
|
|
c735870b95 | ||
|
|
56f796bf80 | ||
|
|
225693fa79 | ||
|
|
7f760bff17 | ||
|
|
6b4da33729 | ||
|
|
82cae8ffbf | ||
|
|
31dbbb1881 | ||
|
|
31de1e007a | ||
|
|
a2d0655a75 | ||
|
|
269209dd31 | ||
|
|
32082927b2 | ||
|
|
c10d0b6349 | ||
|
|
11ff1266e5 | ||
|
|
8b5717ff7f | ||
|
|
e69f6bef2c | ||
|
|
2a17a322c2 | ||
|
|
26ddb76338 | ||
|
|
f62f156c93 | ||
|
|
f4b6c65bad | ||
|
|
0a08399d9e | ||
|
|
df1adaad3a | ||
|
|
33b1490de0 | ||
|
|
286720bdbf | ||
|
|
1441ac67ab | ||
|
|
d245fdd1b8 | ||
|
|
e9c9b456e0 | ||
|
|
d9eafff7df | ||
|
|
94eb19d879 | ||
|
|
d7b585230a | ||
|
|
16ed14f85a | ||
|
|
93e59cc3b6 | ||
|
|
c38220892b | ||
|
|
4ef72fb35b | ||
|
|
3f23ce095c | ||
|
|
0ead246ce7 | ||
|
|
0f8259fdf7 | ||
|
|
ebb180b0ab | ||
|
|
c03f50583e | ||
|
|
b8a6cf0099 | ||
|
|
ad3cdc3364 | ||
|
|
d924d3fa4f | ||
|
|
dd4a8c08c8 | ||
|
|
52f2e800e7 | ||
|
|
8d94b62db0 | ||
|
|
c3eb483224 | ||
|
|
e7b1e0a81f | ||
|
|
ca672c68a3 | ||
|
|
416e11a32b | ||
|
|
bbaa2db377 | ||
|
|
cf4e412ab8 | ||
|
|
48ac88dbfe | ||
|
|
4980e9a15b | ||
|
|
290a2ab902 | ||
|
|
6a04d8fce1 | ||
|
|
7286ac743f | ||
|
|
41b6b5f615 | ||
|
|
d0572f7691 | ||
|
|
a8210844cb | ||
|
|
c5c39cedc4 | ||
|
|
8d6ae2da82 | ||
|
|
9eea6b3645 | ||
|
|
6d9638970d | ||
|
|
ecd3638298 | ||
|
|
bbde0e4d24 | ||
|
|
299f694aa9 | ||
|
|
2675698d3a | ||
|
|
3056f3cfcf | ||
|
|
7310d8af30 | ||
|
|
b62f40f8c9 | ||
|
|
ae1aac02ae | ||
|
|
e19f344dc1 | ||
|
|
1525ecdb05 | ||
|
|
4f6a13b2c4 | ||
|
|
4747297adc | ||
|
|
f753974800 | ||
|
|
bd4002529c | ||
|
|
00588eb099 | ||
|
|
81420b6168 | ||
|
|
fe74d2aec9 | ||
|
|
6514701c6a | ||
|
|
9e206ce7ea | ||
|
|
b32ad68e4f | ||
|
|
dfb5322b1a | ||
|
|
47859d401e | ||
|
|
5da90f9e16 | ||
|
|
4b098e2008 | ||
|
|
b4cd66db50 | ||
|
|
4847f4094a | ||
|
|
3fb34e6ae1 | ||
|
|
135ed32374 | ||
|
|
9b1fc77d56 | ||
|
|
5b751fd6e2 | ||
|
|
39ece711d9 | ||
|
|
a77b5601be | ||
|
|
8b5d88bf2b | ||
|
|
1f602f9cad | ||
|
|
5588042ab6 | ||
|
|
bc89bc8270 | ||
|
|
60ae094d3b | ||
|
|
a9facc7ce2 | ||
|
|
f200ac898a | ||
|
|
56ce25b8e8 | ||
|
|
4d5d9b4b70 | ||
|
|
b97ab913bf | ||
|
|
9fe7bdf79b | ||
|
|
4ebc4ece34 | ||
|
|
0110b3c4a2 | ||
|
|
fb20d4998a | ||
|
|
bd06c530e4 | ||
|
|
cd4505bcf0 | ||
|
|
173f4a23a5 | ||
|
|
b33d4e64b9 | ||
|
|
a4c95132bb | ||
|
|
095e797a02 | ||
|
|
aaec171d94 | ||
|
|
42b28993b2 | ||
|
|
09a39379ef | ||
|
|
29f7370c72 | ||
|
|
a07dcef2c4 | ||
|
|
6e696e1123 | ||
|
|
f0b1aa914d | ||
|
|
ce1ae2c9bd | ||
|
|
29597ddb48 | ||
|
|
1c1421fe3a | ||
|
|
918a52005e | ||
|
|
a3564b879f | ||
|
|
b78f3bbaa7 | ||
|
|
4cbdb5a073 | ||
|
|
758021e10c | ||
|
|
374e3560c3 | ||
|
|
57a3524cc3 | ||
|
|
9af4773b45 | ||
|
|
6942773965 | ||
|
|
734b3ee519 | ||
|
|
1b80fa8df2 | ||
|
|
afd6a05e0f | ||
|
|
5a4bd1933d | ||
|
|
a25dfce410 | ||
|
|
fc0490bc6a | ||
|
|
29cdd1d028 | ||
|
|
419e87b0de | ||
|
|
75c7d55e01 | ||
|
|
e006550b9f | ||
|
|
2a424f8dc4 | ||
|
|
5036518458 | ||
|
|
297cbbd8b3 | ||
|
|
87a89f709a | ||
|
|
6f1991e20e | ||
|
|
700de58686 | ||
|
|
57e1208c27 | ||
|
|
b33fe2ca3a | ||
|
|
3c3e73edae | ||
|
|
ec4fd371b5 | ||
|
|
555b138a90 | ||
|
|
c139ff776c | ||
|
|
0c6b5e3b8e | ||
|
|
1138f9a0e9 | ||
|
|
4955bd782b | ||
|
|
516f0052ef | ||
|
|
f4e82acc67 | ||
|
|
a5806c0d1d | ||
|
|
bf302a84a9 | ||
|
|
fcc740d592 | ||
|
|
cee16dc3dc | ||
|
|
47601cd1da | ||
|
|
092a60fdd9 | ||
|
|
e8e7568bdc | ||
|
|
4caca56e3b | ||
|
|
e4432e6feb | ||
|
|
d8275e7ea8 | ||
|
|
952dc634b4 | ||
|
|
7dceca475d | ||
|
|
62a78bc272 | ||
|
|
6aaf277b45 | ||
|
|
a1c61768c4 | ||
|
|
8e4c88c10c | ||
|
|
b57780519c | ||
|
|
c07c4013be | ||
|
|
768211cc26 | ||
|
|
b4a31503ee | ||
|
|
6c2b3e238c | ||
|
|
f2ff834b9c | ||
|
|
86e1688358 | ||
|
|
d259eb1f9d | ||
|
|
568a668e9f | ||
|
|
0621dfbac7 | ||
|
|
827bb9a32f | ||
|
|
fd08654dd5 | ||
|
|
e5d750722e | ||
|
|
b43c4ad666 | ||
|
|
c9f93a4706 | ||
|
|
a38834f7e2 | ||
|
|
fcfc6f6476 | ||
|
|
b23a5348b5 | ||
|
|
782cd59407 | ||
|
|
7964bd3be4 | ||
|
|
3d41ce13b1 | ||
|
|
6f0881ab8a | ||
|
|
a6309715f3 | ||
|
|
5a06193e65 | ||
|
|
4912834537 | ||
|
|
d64f2c72b7 | ||
|
|
358d06a402 | ||
|
|
5deabe4260 | ||
|
|
1b1162e26e | ||
|
|
30ad5d531c | ||
|
|
99efc73e93 | ||
|
|
17c0071dd1 | ||
|
|
a26bec047f | ||
|
|
748e7cc1df | ||
|
|
f653c86965 | ||
|
|
58a41e58ee | ||
|
|
309a55f276 | ||
|
|
df96c6b9fa | ||
|
|
d779e078c7 | ||
|
|
ae224151a0 | ||
|
|
9f11717b69 | ||
|
|
ea25477e3d | ||
|
|
82576c9703 | ||
|
|
80f1fc4c7c | ||
|
|
41cd4bcef6 | ||
|
|
46a414e155 | ||
|
|
70a903f811 | ||
|
|
52db410c82 | ||
|
|
08da8d73e0 | ||
|
|
81a572af25 | ||
|
|
23c50f34fe | ||
|
|
70aa115933 | ||
|
|
0b8cba78d5 | ||
|
|
d8806eaa04 | ||
|
|
b8bc85856b | ||
|
|
cc097c5414 | ||
|
|
7551d0e044 | ||
|
|
489a88b8da | ||
|
|
48013dc264 | ||
|
|
4ee9d45dfc | ||
|
|
e00150a876 | ||
|
|
71668f8f8d | ||
|
|
b71424d239 | ||
|
|
d1a3bceaa6 | ||
|
|
483c57029a | ||
|
|
7e6daf5b36 | ||
|
|
b658253687 | ||
|
|
80b488deec | ||
|
|
10cf1a371e | ||
|
|
81445901fa | ||
|
|
f645d9d721 | ||
|
|
900bfdff9d | ||
|
|
108ca5afb5 | ||
|
|
3df03a551c | ||
|
|
6ffbe19667 | ||
|
|
e3172ebf1c | ||
|
|
9b2876a8ff | ||
|
|
3db2c910e0 | ||
|
|
2799e4392f | ||
|
|
61963fcfda | ||
|
|
b0a3d54276 | ||
|
|
2135412c84 | ||
|
|
7a534c3ea7 | ||
|
|
a6e596a5e3 | ||
|
|
8b3e3c2c3a | ||
|
|
ec8b0a3801 | ||
|
|
197b769838 | ||
|
|
1ba498c0e3 | ||
|
|
5550cb7b95 | ||
|
|
06a005acec | ||
|
|
2103be9d28 | ||
|
|
a02f3c4440 | ||
|
|
4b8d341e00 | ||
|
|
964633f426 | ||
|
|
d11fb38280 | ||
|
|
04f4530990 | ||
|
|
5a77318a9e | ||
|
|
9ed2894a0c | ||
|
|
e0766ad439 | ||
|
|
67acfaab62 | ||
|
|
10b5d29107 | ||
|
|
297dd41170 | ||
|
|
1364223599 | ||
|
|
a6b7761dfa | ||
|
|
2e6290c514 | ||
|
|
78f4928611 | ||
|
|
d044fce9c1 | ||
|
|
11fa815e13 | ||
|
|
8d917eb970 | ||
|
|
e411e5f2cf | ||
|
|
fea8de89c6 | ||
|
|
48773636ca | ||
|
|
5a3c7355c1 | ||
|
|
4afbabb977 | ||
|
|
afa9fe3063 | ||
|
|
178ac088b4 | ||
|
|
b2ebaf111f | ||
|
|
ffd5ebbe79 | ||
|
|
6b78bfecb4 | ||
|
|
9c2b01e3c9 | ||
|
|
dca201ce42 | ||
|
|
d3c0a44c00 | ||
|
|
33ea2de231 | ||
|
|
43ebbfc321 | ||
|
|
1e5b294eb3 | ||
|
|
29855112c8 | ||
|
|
8af7b3c81a | ||
|
|
b72b82ff1a | ||
|
|
1588c8103c | ||
|
|
15e569dcea | ||
|
|
3774ea3768 | ||
|
|
0a9c6a3119 | ||
|
|
a6cbde88bb | ||
|
|
4bdb407404 | ||
|
|
4568cedcd3 | ||
|
|
f290317acc | ||
|
|
645279c8fa | ||
|
|
09436f8d65 | ||
|
|
b616e0e5f9 | ||
|
|
f06a0852a1 | ||
|
|
9e688138be | ||
|
|
5d46970a38 | ||
|
|
ecc441c074 | ||
|
|
f2ce3678c4 | ||
|
|
c9ad390647 | ||
|
|
92acc7accd | ||
|
|
9c13f36ca0 | ||
|
|
fe4a11c5ad | ||
|
|
e29b238161 | ||
|
|
2ef4eb7eae | ||
|
|
7b230706cb | ||
|
|
5a2b04adba | ||
|
|
50dcd3ba44 | ||
|
|
740b02952f | ||
|
|
5d3d42ffdd | ||
|
|
866d3110da | ||
|
|
7a3e7fccec | ||
|
|
3107bc8840 | ||
|
|
2d34cdef5e | ||
|
|
bd1f0909a2 | ||
|
|
ef75de63fe | ||
|
|
a739d28563 | ||
|
|
66ff009b72 | ||
|
|
a68e82c1c8 | ||
|
|
46556c1c14 | ||
|
|
7be637798f | ||
|
|
9b3396349e | ||
|
|
ccff210b4c | ||
|
|
a2264847b6 | ||
|
|
7d103f8c50 | ||
|
|
f3dccc0aec | ||
|
|
311b1d8a64 | ||
|
|
f3094e3079 | ||
|
|
f3b37b16d5 | ||
|
|
5f16ecf02d | ||
|
|
8b75287827 | ||
|
|
bb38e806cd | ||
|
|
8cbc15f1b0 | ||
|
|
870524f9cf | ||
|
|
218343ca14 | ||
|
|
61953fd713 | ||
|
|
62ddf3a11b | ||
|
|
be12658864 | ||
|
|
b618e5a00f | ||
|
|
5da9963f31 | ||
|
|
34e885812f | ||
|
|
a9ac11452d | ||
|
|
04b91308b1 | ||
|
|
b09ef222f5 | ||
|
|
2d0ed06d50 | ||
|
|
8dd7cf6085 | ||
|
|
4999bd4f1e | ||
|
|
22f408addb | ||
|
|
9ca1dbe638 | ||
|
|
26662952e3 | ||
|
|
f0c9fa4ca3 | ||
|
|
b51aa1dd71 | ||
|
|
846253c9e3 | ||
|
|
6ab6ea97ac | ||
|
|
bf41f70b98 | ||
|
|
67ddbedd08 | ||
|
|
2573e219dc | ||
|
|
7e368678ab | ||
|
|
4a9fcf7ab6 | ||
|
|
65856c61c5 | ||
|
|
b5a97bffab | ||
|
|
e6d728715f | ||
|
|
54a52f0589 | ||
|
|
badfa23f86 | ||
|
|
4c36a9cca9 | ||
|
|
30ccd3487a | ||
|
|
75e012f2c9 | ||
|
|
5ecb1d1e2d | ||
|
|
f8c24c838a | ||
|
|
4ad9cfcdf4 | ||
|
|
a57253dd35 | ||
|
|
222e65bd45 | ||
|
|
3192ea3383 | ||
|
|
3a27f873cd | ||
|
|
e8fb279036 | ||
|
|
21ec7078d2 | ||
|
|
94937e9fa4 | ||
|
|
36401a20b8 | ||
|
|
8d1c4e4661 | ||
|
|
14362060c8 | ||
|
|
de47e94f62 | ||
|
|
c78ed78bf6 | ||
|
|
7674c95124 | ||
|
|
ec522c20b2 | ||
|
|
81f9578526 | ||
|
|
20bca751d4 | ||
|
|
49b5c49776 | ||
|
|
5d514fae61 | ||
|
|
9e17e93dd7 | ||
|
|
7f70c641dc | ||
|
|
7e3af4b7bc | ||
|
|
59ff4c0aef | ||
|
|
875e6b8e53 | ||
|
|
fafc44de7c | ||
|
|
e0d7eb10d5 | ||
|
|
ae01eb28a3 | ||
|
|
637c66c04f | ||
|
|
1c061e4428 | ||
|
|
cbe0626572 | ||
|
|
86dc98174a | ||
|
|
f0ac8ea977 | ||
|
|
35d4c2cdfc | ||
|
|
394f7c0d09 | ||
|
|
b83eee9bdc | ||
|
|
e41b2e8d31 | ||
|
|
d93cec2bfd | ||
|
|
9eb87a39cd | ||
|
|
07818ec1df | ||
|
|
d4052dbe37 | ||
|
|
656f5e0a7f | ||
|
|
f3d415a3a7 | ||
|
|
fd8ab990bd | ||
|
|
0cc5e4dac3 | ||
|
|
8bbfff3cb2 | ||
|
|
93059798b0 | ||
|
|
33fae88cad | ||
|
|
4feb23e9ca | ||
|
|
c2b6b7ba72 | ||
|
|
fb76aee258 | ||
|
|
320b1829cc | ||
|
|
601f0255a4 | ||
|
|
b6cc2b227a | ||
|
|
cc7da4b948 | ||
|
|
1ae3be2fda | ||
|
|
5b4d35ea86 | ||
|
|
00735e6c8e | ||
|
|
66a42a38c9 | ||
|
|
05af1fba80 | ||
|
|
3b2dd0f5e9 | ||
|
|
1493a66a36 | ||
|
|
b4bf103fd8 | ||
|
|
94286becfd | ||
|
|
a68aade58c | ||
|
|
014201edf4 | ||
|
|
8ae6297148 | ||
|
|
5e0300aa8e | ||
|
|
80a7e18413 | ||
|
|
5c007cdebc | ||
|
|
ef6c733f93 | ||
|
|
e7d6658c7a | ||
|
|
43be0a1a3f | ||
|
|
5eb32744c3 | ||
|
|
89d39f5f2b | ||
|
|
1f4900dd1e | ||
|
|
1c561c1483 | ||
|
|
6baaf60b67 | ||
|
|
dde73f6c2b | ||
|
|
f445a49b34 | ||
|
|
29016d1cf5 | ||
|
|
c06435046b | ||
|
|
134422802f | ||
|
|
5e00d6a305 | ||
|
|
b5f0137d8e | ||
|
|
081d041cbc | ||
|
|
95e733a67c | ||
|
|
a664057312 | ||
|
|
5b1a2d93bf | ||
|
|
0323f95828 | ||
|
|
375838449f | ||
|
|
4562de8c2c | ||
|
|
68d21669e7 | ||
|
|
625e0cf159 | ||
|
|
551ef00c61 | ||
|
|
10518f6364 | ||
|
|
1eafda36a9 | ||
|
|
871ecf0158 | ||
|
|
429000bdcb | ||
|
|
607940ed60 | ||
|
|
46f61a4311 | ||
|
|
3721df0502 | ||
|
|
11add681ec | ||
|
|
6e36eea6c8 | ||
|
|
6a82e7a24c | ||
|
|
5f625fa9f3 | ||
|
|
a95527674f | ||
|
|
f6149c67dc | ||
|
|
00c2a07e33 | ||
|
|
bc49b22c32 | ||
|
|
fe1b1c8bc3 | ||
|
|
a2825a06d6 | ||
|
|
3c33b5b169 | ||
|
|
639b81b228 | ||
|
|
0c552eb0c0 | ||
|
|
ae723f9557 | ||
|
|
34d691341b | ||
|
|
8574a11cf7 | ||
|
|
3742cd4a51 | ||
|
|
934a867c83 | ||
|
|
a36337fba8 | ||
|
|
b3bd53bdd0 | ||
|
|
55518d4a8e | ||
|
|
2949c330d7 | ||
|
|
7ec056dbe0 | ||
|
|
983b60a8b9 | ||
|
|
d7d411caf9 | ||
|
|
000c31b66c | ||
|
|
2cd3d4bfb7 | ||
|
|
9d9065c801 | ||
|
|
10e7fe56ab | ||
|
|
c832e62389 | ||
|
|
328e488322 | ||
|
|
fd5a43cdb4 | ||
|
|
fd7780abb0 | ||
|
|
11c23e0b5e | ||
|
|
1170cfd4a7 | ||
|
|
2eddaa954e | ||
|
|
2c472fd03f | ||
|
|
16019a787e | ||
|
|
717d0a75f4 | ||
|
|
cc9487bae8 | ||
|
|
5ed9ec8f46 | ||
|
|
6ca37ca7f4 | ||
|
|
1007b8b15d | ||
|
|
be3a95fd54 | ||
|
|
109cb6cc3f | ||
|
|
fe1509dcfc | ||
|
|
1797e33989 | ||
|
|
6c504eeb3e | ||
|
|
d4b16fcdd1 | ||
|
|
9a08c079b5 | ||
|
|
98e75a7d6c | ||
|
|
675fd13391 | ||
|
|
e4f042aba4 | ||
|
|
19527845d1 | ||
|
|
3aa981649c | ||
|
|
330d48f70d | ||
|
|
90e14aae99 | ||
|
|
77e2ed7e01 | ||
|
|
f720f921c3 | ||
|
|
328740909b | ||
|
|
c8a981e8d6 | ||
|
|
faac45784c | ||
|
|
25667e84b7 | ||
|
|
72e0d77be5 | ||
|
|
9ac4b9ed4f | ||
|
|
b3b89ba05c | ||
|
|
00dc04df25 | ||
|
|
21d47c3fef | ||
|
|
66de94f050 | ||
|
|
1917adb322 | ||
|
|
3360b29354 | ||
|
|
646d281759 | ||
|
|
e268d92d52 | ||
|
|
fa81db2f03 | ||
|
|
830199ba3a | ||
|
|
ea8dc506d3 | ||
|
|
c95483ed94 | ||
|
|
d9cb4480b2 | ||
|
|
c69afd6074 | ||
|
|
f541790ab4 | ||
|
|
707ac4ec36 | ||
|
|
cd55133e96 | ||
|
|
37a91f8529 | ||
|
|
0ed0fa37a1 | ||
|
|
26728b79b2 | ||
|
|
f7c8723539 | ||
|
|
c313916771 | ||
|
|
f0b30c5e91 | ||
|
|
73e3196124 | ||
|
|
8a7bcc316e | ||
|
|
a2921cb982 | ||
|
|
29ce004974 | ||
|
|
026ba5ddce | ||
|
|
ab0585609a | ||
|
|
14a8bdb0c0 | ||
|
|
397d04dd88 | ||
|
|
fbb0bb7491 | ||
|
|
ee987dae99 | ||
|
|
720281a8db | ||
|
|
ff0c89e5a3 | ||
|
|
442937f540 | ||
|
|
dc01b787c1 | ||
|
|
c709b5d34c | ||
|
|
f8b386e42d | ||
|
|
f6b454cb9a | ||
|
|
a82f8ce3ad | ||
|
|
529d45b762 | ||
|
|
d31135bf21 | ||
|
|
75a77acefe | ||
|
|
715f42b6c3 | ||
|
|
199bfc8a37 | ||
|
|
e82ae762f0 | ||
|
|
f90cc9aff7 | ||
|
|
ec915177ad | ||
|
|
5adee3e217 | ||
|
|
278d82645e | ||
|
|
e66f13b471 | ||
|
|
0e2955b57e | ||
|
|
2a4d5ec1ec | ||
|
|
07ce63de69 | ||
|
|
b539862eef | ||
|
|
ac4be3f8a8 | ||
|
|
0dc2d07b58 | ||
|
|
b097f9dc21 | ||
|
|
8aa4a97480 | ||
|
|
3e54d0ceae | ||
|
|
e1cec3404a | ||
|
|
9a2b7fbda1 | ||
|
|
e0b4ebed93 | ||
|
|
e00e3999c5 | ||
|
|
2cbe96d815 | ||
|
|
ac3b289c9e | ||
|
|
62534e0e93 | ||
|
|
b802c3174c | ||
|
|
aee1a6e1f0 | ||
|
|
46f1cd38e0 | ||
|
|
7f891ef523 | ||
|
|
06af5e15cd | ||
|
|
af89a0a883 | ||
|
|
fa72eb2edb | ||
|
|
c1ea94423b | ||
|
|
1e70d066bd | ||
|
|
ab89f16e7c | ||
|
|
8c848a4cb5 | ||
|
|
e021a54d2d | ||
|
|
70523574b0 | ||
|
|
66e0f1ab19 | ||
|
|
671a05470e | ||
|
|
99eec0c41e | ||
|
|
48d06dcb06 | ||
|
|
e38df0c731 | ||
|
|
0f3f49915e | ||
|
|
416144265b | ||
|
|
2e7ced8e60 | ||
|
|
563463782c | ||
|
|
fe02871e91 | ||
|
|
bb05aeeaf7 | ||
|
|
846358ccb0 | ||
|
|
dabc779727 | ||
|
|
08fd2ec64b | ||
|
|
c42c06d048 | ||
|
|
e951d60800 | ||
|
|
0d8453f6a7 | ||
|
|
52b41b1bb0 | ||
|
|
c7265017b3 | ||
|
|
634e0b6d30 | ||
|
|
1c260f5890 | ||
|
|
177aedeaae | ||
|
|
3f6f3d2565 | ||
|
|
38489dbfeb | ||
|
|
ff2a3d6a28 | ||
|
|
2c74697fb1 | ||
|
|
110e9200b9 | ||
|
|
6e792f9735 | ||
|
|
51d8b13a81 | ||
|
|
a05691fd07 | ||
|
|
d25e7915d9 | ||
|
|
1a025dfef3 | ||
|
|
84cc4194aa | ||
|
|
331a56277c | ||
|
|
bc2915adb9 | ||
|
|
703fe9a71b | ||
|
|
6c50664046 | ||
|
|
673cbc97e1 | ||
|
|
3e83766099 | ||
|
|
b453589077 | ||
|
|
654fa18ab1 | ||
|
|
7b0d91534c | ||
|
|
8d4801bb6f | ||
|
|
9e36f4f625 | ||
|
|
d83a824812 | ||
|
|
ca128f2fa9 | ||
|
|
c02642d0f9 | ||
|
|
7340709111 | ||
|
|
56d0383372 | ||
|
|
49d33ea19a | ||
|
|
979fa0359a | ||
|
|
c7381d058a | ||
|
|
5db298f031 | ||
|
|
171d948a00 | ||
|
|
facd56cdf4 | ||
|
|
ba17ec4be4 | ||
|
|
6c163b5479 | ||
|
|
79649805b8 | ||
|
|
220ca8a570 | ||
|
|
348c00f86d | ||
|
|
12b641b522 | ||
|
|
6855bc1de6 | ||
|
|
a9c5b99ae8 | ||
|
|
76f36e2fd3 | ||
|
|
afe710321c | ||
|
|
0d444daaca | ||
|
|
c8a0c9fd23 | ||
|
|
79f07ae923 | ||
|
|
c77e7a568b | ||
|
|
ff9ec2057b | ||
|
|
6a313b99e4 | ||
|
|
8a92370042 | ||
|
|
411a59ec54 | ||
|
|
2d4022044d | ||
|
|
bbc5ebd76b | ||
|
|
e9c90fcde8 | ||
|
|
911f78867f | ||
|
|
5507cc5abc | ||
|
|
0e5aa401ef | ||
|
|
d48473ab87 | ||
|
|
734efaf40c | ||
|
|
f89718d88a | ||
|
|
aa4942a0da | ||
|
|
90bb162a88 | ||
|
|
0382a4b30e | ||
|
|
490d940cd1 | ||
|
|
b090eb9359 | ||
|
|
cb9e67ce84 | ||
|
|
c4d131dd23 | ||
|
|
2667f266bf | ||
|
|
8258936d6c | ||
|
|
e4e7449078 | ||
|
|
11b020e859 | ||
|
|
72d6b83ec5 | ||
|
|
fbe5152cb3 | ||
|
|
6bef01f755 | ||
|
|
f0d4b4a6d9 | ||
|
|
a54fe62643 | ||
|
|
eb4bbd49fb | ||
|
|
ab4f1bd4f4 | ||
|
|
f8b414c354 | ||
|
|
82a21624c3 | ||
|
|
1b212ac720 | ||
|
|
c36ce3ea14 | ||
|
|
841fab77a8 | ||
|
|
fd6f910824 | ||
|
|
ce9ca1917d | ||
|
|
c702fb273c | ||
|
|
4c72d8691b | ||
|
|
35ac5fc514 | ||
|
|
92991cc03c | ||
|
|
76492475e3 | ||
|
|
e2363d860c | ||
|
|
c06a90913a | ||
|
|
e88c0f7326 | ||
|
|
2a4280b5bf | ||
|
|
d3c733c57f | ||
|
|
f91add3cd4 | ||
|
|
90e3f7508a | ||
|
|
5e981da4df | ||
|
|
2ddd5d75fc | ||
|
|
88f509cbb6 | ||
|
|
ca161bc881 | ||
|
|
676ca44cdf | ||
|
|
5d0c91202f | ||
|
|
a166f049d5 | ||
|
|
0dc4692dfc | ||
|
|
996607d096 | ||
|
|
bd907ea008 | ||
|
|
b1573b1f3b | ||
|
|
246849ce94 | ||
|
|
2c2c68261a | ||
|
|
e38a0361bf | ||
|
|
cbf879bd32 | ||
|
|
808625e564 | ||
|
|
19781bb14c | ||
|
|
7fd2bc30cc | ||
|
|
c3b4c2f7d4 | ||
|
|
14f521fdd7 | ||
|
|
087831df5a | ||
|
|
07f273fda4 | ||
|
|
6b0542a5bf | ||
|
|
ac57856f00 | ||
|
|
2ab1587df0 | ||
|
|
632aa6e003 | ||
|
|
9142f2df4b | ||
|
|
eea4cbbd6c | ||
|
|
bb31c20282 | ||
|
|
f8ab206744 | ||
|
|
4129b3a96e | ||
|
|
0de704bd3e | ||
|
|
5f20ce87a7 | ||
|
|
ff80154fda | ||
|
|
0d99cf9fb9 | ||
|
|
a5306b2067 | ||
|
|
e9b826e498 | ||
|
|
e7f356b87c | ||
|
|
d2abde714f | ||
|
|
20eaa79079 | ||
|
|
3cb74bb844 | ||
|
|
a72d4f425a | ||
|
|
8f3545624e | ||
|
|
8f6cfe8a04 | ||
|
|
bec7943e05 | ||
|
|
a486f5951e | ||
|
|
e8158aadec | ||
|
|
b6f107b85b | ||
|
|
5abd27f252 | ||
|
|
39648b6df8 | ||
|
|
0a7b2e3304 | ||
|
|
48db6e1756 | ||
|
|
2a38af5db6 | ||
|
|
740b1093d7 | ||
|
|
6b70412f6e | ||
|
|
43f147ec60 | ||
|
|
bf0fc57493 | ||
|
|
325b8b886c | ||
|
|
a02bbdc550 | ||
|
|
4285fd7708 | ||
|
|
96fa6eac44 | ||
|
|
05fa1ef2fb | ||
|
|
13aebc060e | ||
|
|
1aae4098d6 | ||
|
|
3367bb2e5b | ||
|
|
49fc5e1559 | ||
|
|
3a9b448a83 | ||
|
|
a45fb975c0 | ||
|
|
e070fc2f52 | ||
|
|
5f8aac31e1 | ||
|
|
07f2e2eafc | ||
|
|
2b41fb7108 | ||
|
|
81c18f1869 | ||
|
|
61fd2fe87d | ||
|
|
054cb974f1 | ||
|
|
50a19ecd74 | ||
|
|
1232909a3b | ||
|
|
9ba0e076a6 | ||
|
|
ede91c645d | ||
|
|
b6a91723e7 | ||
|
|
fddd73fdb1 | ||
|
|
ffbe8f9dc4 | ||
|
|
f80763ffb4 | ||
|
|
f65aa1b875 | ||
|
|
0c4de9a5e0 | ||
|
|
1822970e23 | ||
|
|
80615d0382 | ||
|
|
c1002ed52a | ||
|
|
83e585ed35 | ||
|
|
0e164b9daa | ||
|
|
1c9f8a2540 | ||
|
|
88ba4451eb | ||
|
|
305f195539 | ||
|
|
fbc6b853ed | ||
|
|
f3bcab813a | ||
|
|
2fa9b2e4dd | ||
|
|
fc756ba46e | ||
|
|
85a82124b1 | ||
|
|
b5cfbc92af | ||
|
|
e4f260e242 | ||
|
|
7c6c0c1fbd | ||
|
|
2f5f4dbebd | ||
|
|
94adc6af95 | ||
|
|
e3ea703f3d | ||
|
|
a14753e5f3 | ||
|
|
2ffd55c2d8 | ||
|
|
ad0ee8da32 | ||
|
|
e5cfe37b17 | ||
|
|
9247dd8b17 | ||
|
|
2f69b1d6e1 | ||
|
|
9c43930e7b | ||
|
|
f18ecfa524 | ||
|
|
b6f7453ed9 | ||
|
|
4a0b77dabb | ||
|
|
de7687b3ab | ||
|
|
85f2ec9d92 | ||
|
|
ed6b8dfc9b | ||
|
|
1539a6eabc | ||
|
|
6424d96703 | ||
|
|
15f6ac8e89 | ||
|
|
f9803a4694 | ||
|
|
b08126ec2b | ||
|
|
e0824a5426 | ||
|
|
c4f5471e13 | ||
|
|
13de9975e3 | ||
|
|
99215c272c | ||
|
|
a64c4ef66f | ||
|
|
36e85eb3a7 | ||
|
|
20ffe7e082 | ||
|
|
ea1dc58b9a | ||
|
|
cd292ad605 | ||
|
|
03d9a6c0e5 | ||
|
|
fa54a2e67c | ||
|
|
7f2530470d | ||
|
|
a284934136 | ||
|
|
2ca6606508 | ||
|
|
bb1c691b34 | ||
|
|
19d3e1b11c | ||
|
|
e35e64caaa | ||
|
|
a3cf72c76c | ||
|
|
710e95bdee | ||
|
|
d281fb7065 | ||
|
|
e669d5041b | ||
|
|
d8d91451c8 | ||
|
|
b0910baaf0 | ||
|
|
ce3f70adc3 | ||
|
|
c0d5c26f0c | ||
|
|
1bf8a76cc3 | ||
|
|
7b1f74a413 | ||
|
|
3d2fde77a5 | ||
|
|
e4cc3bef73 | ||
|
|
f384c422c4 | ||
|
|
a373d2e7e0 | ||
|
|
1aaf630979 | ||
|
|
b7ac3aba72 | ||
|
|
ed89250624 | ||
|
|
d9a7f0c7fe | ||
|
|
a07405bec3 | ||
|
|
4c6efeb0d8 | ||
|
|
501b380d5e | ||
|
|
ddc4e34dcd | ||
|
|
d668d9f24d | ||
|
|
0ec4423ad4 | ||
|
|
51313ff0d5 | ||
|
|
37381b7c36 | ||
|
|
6de632d117 | ||
|
|
4a8fa7293b | ||
|
|
b75a2e9592 | ||
|
|
c45c1b0f93 | ||
|
|
af7057f062 | ||
|
|
85bf1eb4ec | ||
|
|
bd45043a36 | ||
|
|
fbb41168a2 | ||
|
|
674fe4fa20 | ||
|
|
4db86f9322 | ||
|
|
5c814155d2 | ||
|
|
c08fb9af16 | ||
|
|
1dac4fea9c | ||
|
|
ac19000ad0 | ||
|
|
221182389a | ||
|
|
5d5947f676 | ||
|
|
8fc889ae08 | ||
|
|
ff46493775 | ||
|
|
a1cb3b8371 | ||
|
|
51131433d3 | ||
|
|
eaccd641ed | ||
|
|
3e2b647f06 | ||
|
|
0fbf9bafbc | ||
|
|
924a5e3110 | ||
|
|
be71a4b5c4 | ||
|
|
1cb5a13ea4 | ||
|
|
e145cd80a9 | ||
|
|
58ea661d4b | ||
|
|
ba317eff3f | ||
|
|
ead0e14118 | ||
|
|
d3dd20b50f | ||
|
|
d621fb4105 | ||
|
|
a239604dad | ||
|
|
f7986b9049 | ||
|
|
0a34ca031a | ||
|
|
ce63fec413 | ||
|
|
719451bf23 | ||
|
|
10a27cbe86 | ||
|
|
51325e2f4a | ||
|
|
3c8a066f76 | ||
|
|
6856a98d50 | ||
|
|
120b767a68 | ||
|
|
8c0d4cde86 | ||
|
|
bbf090edf0 | ||
|
|
fc925a5db5 | ||
|
|
fb76ca09bd | ||
|
|
af6c54bac7 | ||
|
|
a854b04300 | ||
|
|
5d73556127 | ||
|
|
82ea4c1a04 | ||
|
|
537d92421c | ||
|
|
c97c69900b | ||
|
|
ab519a4caa | ||
|
|
bbbdab42ca | ||
|
|
810563b3f9 | ||
|
|
63cf055a0d | ||
|
|
442aac0466 | ||
|
|
7c9499ad7e | ||
|
|
a6e8e2a127 | ||
|
|
671e05421a | ||
|
|
d8c7c919d1 | ||
|
|
5629b9a161 | ||
|
|
3ba853dbad | ||
|
|
be8dda8523 | ||
|
|
2e86166400 | ||
|
|
784ea240ca | ||
|
|
5b10e33e72 | ||
|
|
fbcf974c73 | ||
|
|
d844111187 | ||
|
|
4cac419a26 | ||
|
|
1c21519960 | ||
|
|
6a70c52bd1 | ||
|
|
a0e6023810 | ||
|
|
a24ab7ca06 | ||
|
|
4979a1b224 | ||
|
|
4cdf6d8292 | ||
|
|
4c51c8e8f8 | ||
|
|
1ab7b91f2e | ||
|
|
7af4fbfcce | ||
|
|
494e23b69f | ||
|
|
a487a502f5 | ||
|
|
2b7a7a8767 | ||
|
|
0c72bd1539 | ||
|
|
9462ccc650 | ||
|
|
81d964d3e8 | ||
|
|
27bf41e0ce | ||
|
|
78b0773a28 | ||
|
|
3b76239f65 | ||
|
|
edd11d847a | ||
|
|
0df0f8a4c9 | ||
|
|
0f5ee0888a | ||
|
|
30ead4080a | ||
|
|
9224029a16 | ||
|
|
4ce841dc8a | ||
|
|
d639de03c3 | ||
|
|
0cf34fb874 | ||
|
|
241147c762 | ||
|
|
99eb481ed4 | ||
|
|
2d126c9cec | ||
|
|
7aec858ade | ||
|
|
ac7a107a9a | ||
|
|
c2c9b6819c | ||
|
|
7159ea5927 | ||
|
|
44bf837310 | ||
|
|
28368a3e0d | ||
|
|
1a92eeac69 | ||
|
|
411c062463 | ||
|
|
18d1b8cbfe | ||
|
|
8322e4278a | ||
|
|
4b70bb6778 | ||
|
|
c9c9daf30c | ||
|
|
b26d9c0303 | ||
|
|
376e6dc6d7 | ||
|
|
34d3c318d6 | ||
|
|
6cbed20d5c | ||
|
|
96acd7f921 | ||
|
|
7439b9ca65 | ||
|
|
9eb24c6fc2 | ||
|
|
595d30feb7 | ||
|
|
836b5feaae | ||
|
|
5ca0830b88 | ||
|
|
46057fa03b | ||
|
|
ba46ba77b4 | ||
|
|
e348a9b907 | ||
|
|
aaaf8c1e2b | ||
|
|
41a85a78db | ||
|
|
554aa1cd64 | ||
|
|
853822ec8a | ||
|
|
087dfa179e | ||
|
|
65a769c5bd | ||
|
|
0bbb4ddb21 | ||
|
|
cb0eeee8cc | ||
|
|
75d35e3ade | ||
|
|
99e22a5636 | ||
|
|
b7b367b5a3 | ||
|
|
4927b01d96 | ||
|
|
e2e5d485d7 | ||
|
|
ada22e4966 | ||
|
|
1cf93ff0de | ||
|
|
199962233b | ||
|
|
743a6f3466 | ||
|
|
625062a268 | ||
|
|
cb0fabf273 | ||
|
|
4c978d8622 | ||
|
|
d0f441ec74 | ||
|
|
9d347ff3d9 | ||
|
|
c2a758dd4a | ||
|
|
bba69e98ae | ||
|
|
53e3d65c52 | ||
|
|
a2a37a0b54 | ||
|
|
1fb360e34f | ||
|
|
680817d81c | ||
|
|
bf736977ab | ||
|
|
28ed93dcdc | ||
|
|
785ace64ad | ||
|
|
ac109c2ece | ||
|
|
1e82043999 | ||
|
|
e37487a1cf | ||
|
|
a9b8ffd94c | ||
|
|
4011771b64 | ||
|
|
266494ba8c | ||
|
|
2e144fac5e | ||
|
|
423038100e | ||
|
|
75e88c69bd | ||
|
|
f0b1319f95 | ||
|
|
59f2fc8d03 | ||
|
|
5d07a079ef | ||
|
|
b5ff71b1a0 | ||
|
|
c0a2ae99cf | ||
|
|
5600a707d3 | ||
|
|
17f906fb65 | ||
|
|
276b3f834b | ||
|
|
a9218960e9 | ||
|
|
957590523c | ||
|
|
22308a101e | ||
|
|
ab95f6dcc2 | ||
|
|
cb8b968637 | ||
|
|
e4d319c7a1 | ||
|
|
f8e5f31970 | ||
|
|
5113e2ab97 | ||
|
|
6ae1cc18e2 | ||
|
|
256ad05d2d | ||
|
|
1b0a53a441 | ||
|
|
430ef62a2d | ||
|
|
cd7daee771 | ||
|
|
50aeda8ee8 | ||
|
|
1520c696a3 | ||
|
|
f63f6244a1 | ||
|
|
8611d4a67a | ||
|
|
c48bd9a5c3 | ||
|
|
dba985b308 | ||
|
|
a51a831fe8 | ||
|
|
44142e980d | ||
|
|
7f83226f84 | ||
|
|
e3fdae8932 | ||
|
|
78c62be823 | ||
|
|
e51cea88bf | ||
|
|
d7409bec49 | ||
|
|
17b1f599ff | ||
|
|
81c85d712e | ||
|
|
2eae8bbb64 | ||
|
|
2a61f51e06 | ||
|
|
3e3c3e3bb4 | ||
|
|
7b41a89b8e | ||
|
|
36429da6da | ||
|
|
30f6ab5976 | ||
|
|
99a46f2a85 | ||
|
|
6754b1f2e1 | ||
|
|
122ad2b771 | ||
|
|
714e8ade1a | ||
|
|
4a6ea38be0 | ||
|
|
8bc7f0b71f | ||
|
|
9a912c16ad | ||
|
|
10a84a1356 | ||
|
|
901201a7af | ||
|
|
a57a1dfc47 | ||
|
|
577780cb90 | ||
|
|
b45eef9140 | ||
|
|
907853bbba | ||
|
|
17f3ffd00c | ||
|
|
8b86e17ac8 | ||
|
|
d6b6832a1d | ||
|
|
9dfc1cdc4c | ||
|
|
673c39d798 | ||
|
|
8ca84d183c | ||
|
|
9577aa2abe | ||
|
|
280697f2f7 | ||
|
|
0650be664d | ||
|
|
60c61f553a | ||
|
|
022c967781 | ||
|
|
227be184ac | ||
|
|
d677f65eeb | ||
|
|
92f86bcca2 | ||
|
|
2015068d9e | ||
|
|
8a280c2f9d | ||
|
|
34fd6f9502 | ||
|
|
02acb36e47 | ||
|
|
280c0e0348 | ||
|
|
8528f0d848 | ||
|
|
917e881faa | ||
|
|
96b1efcfdc | ||
|
|
794e03b2cb | ||
|
|
a285c46b97 | ||
|
|
4da6294ef2 | ||
|
|
16ed9a7e8e | ||
|
|
798efbc22f | ||
|
|
60c789b6c7 | ||
|
|
f83d95136d | ||
|
|
f96ed0af26 | ||
|
|
1539664026 | ||
|
|
8aff775d0e | ||
|
|
94248eafe9 | ||
|
|
02335bba3f | ||
|
|
dad9578b83 | ||
|
|
c043788b09 | ||
|
|
e5bc416b46 | ||
|
|
bd7e47d8f0 | ||
|
|
457a7a03fb | ||
|
|
6e486c64f1 | ||
|
|
4f3575d765 | ||
|
|
f5f1b27754 | ||
|
|
c97f52da36 | ||
|
|
1661c3292a | ||
|
|
4e80c07630 | ||
|
|
d43309947e | ||
|
|
c7cc702c4a | ||
|
|
c304753ffc | ||
|
|
da59c14231 | ||
|
|
e0b3e41c9e | ||
|
|
5d1a63bce0 | ||
|
|
84cf4ef4a3 | ||
|
|
ec4b6f0a90 | ||
|
|
60dbdbeb71 | ||
|
|
418a546583 | ||
|
|
e6380b87b6 | ||
|
|
1d3d214101 | ||
|
|
a38067560b | ||
|
|
eac7235199 | ||
|
|
4c55e857b8 | ||
|
|
e33950e000 | ||
|
|
fc0ccbfcf5 | ||
|
|
4a82bbb035 | ||
|
|
57d894e765 | ||
|
|
97dfad419c | ||
|
|
bfc521fdc0 | ||
|
|
197fa90176 | ||
|
|
0844914e11 | ||
|
|
c376b0bbe2 | ||
|
|
4491086c55 | ||
|
|
791697369d | ||
|
|
28d0bfd229 | ||
|
|
8182a04eae | ||
|
|
711828d6b4 | ||
|
|
69e88c1d9f | ||
|
|
748b87da9a | ||
|
|
94dca4cd87 | ||
|
|
7179701e0f | ||
|
|
af5061646c | ||
|
|
9c4163ad3a | ||
|
|
46c3f5296a | ||
|
|
ebadcfd844 | ||
|
|
b7d4947462 | ||
|
|
a599526dea | ||
|
|
c4f166fe12 | ||
|
|
a8ae91aa3b | ||
|
|
82b3692acb | ||
|
|
432c054b68 | ||
|
|
dcd8bfa255 | ||
|
|
c287a2ae97 | ||
|
|
8fdadb3798 | ||
|
|
3fce4fc66c | ||
|
|
d83d7ed106 | ||
|
|
1b812f1886 | ||
|
|
56fcc7adcc | ||
|
|
fb0c7359f1 | ||
|
|
4c4e5b85e9 | ||
|
|
476247beb5 | ||
|
|
2c87f609f3 | ||
|
|
bc79ff6845 | ||
|
|
f10373d54f | ||
|
|
630d16b722 | ||
|
|
769f3db21c | ||
|
|
c6896a4b33 | ||
|
|
7c18025098 | ||
|
|
6ae74b3181 | ||
|
|
2ecfbbf284 | ||
|
|
781de9a1fb | ||
|
|
6972a4b901 | ||
|
|
52ed1750ac | ||
|
|
9010e0b1ce | ||
|
|
5053e74447 | ||
|
|
f294276849 | ||
|
|
0740788cc8 | ||
|
|
9bac07ce62 | ||
|
|
3d8289d394 | ||
|
|
5a60fdad8a | ||
|
|
62cca5a96b | ||
|
|
74548d638e | ||
|
|
e0ccf30f4f | ||
|
|
d2c6081537 | ||
|
|
bd933f2c4c | ||
|
|
1d898d618e | ||
|
|
11c8e5b3b2 | ||
|
|
fe4c3ffecb | ||
|
|
334a96186e | ||
|
|
34b2df705b | ||
|
|
5a7fc1c8b6 | ||
|
|
fabab6abb1 | ||
|
|
0c9c20c0c5 | ||
|
|
67cc1113b1 | ||
|
|
3aacd255f4 | ||
|
|
ccfda21413 | ||
|
|
46c88506cc | ||
|
|
51157e1979 | ||
|
|
bfb6d975ff | ||
|
|
aa01bc1457 | ||
|
|
5600f1b7b1 | ||
|
|
a169db807c | ||
|
|
f40348daff | ||
|
|
f63042ef87 | ||
|
|
d148c9d1c6 | ||
|
|
f72929ca13 | ||
|
|
cc3e3ca4d4 | ||
|
|
8fad664a6d | ||
|
|
f1946c1386 | ||
|
|
ea8bd0136f | ||
|
|
4a3f72ae50 | ||
|
|
c944762ef6 | ||
|
|
f6924d7fda | ||
|
|
3a0880fcd6 | ||
|
|
df62dc87b2 | ||
|
|
d42679315e | ||
|
|
2a19be5ab6 | ||
|
|
33bbe994d7 | ||
|
|
04c598caea | ||
|
|
3577688bf9 | ||
|
|
e0439655df | ||
|
|
84f944f78a | ||
|
|
022b6df959 | ||
|
|
9e3e92669f | ||
|
|
35b96a71fc | ||
|
|
4b78de6726 | ||
|
|
4771e02909 | ||
|
|
03dffdb65f | ||
|
|
859a3948cd | ||
|
|
161aa625e6 | ||
|
|
28fd945e80 | ||
|
|
748fb0bf05 | ||
|
|
98e1d0afd9 | ||
|
|
9c61ce1835 | ||
|
|
c3a5705be0 | ||
|
|
9d0fa9f7ca | ||
|
|
cc4ceb975e | ||
|
|
8a6495a0bd | ||
|
|
1d95392d22 | ||
|
|
93dd08d629 | ||
|
|
a1c0314334 | ||
|
|
3ecdcd9ea0 | ||
|
|
a3a3b3cb5c | ||
|
|
d4aaf4ca9b | ||
|
|
e7450b5143 | ||
|
|
fd90454eb6 | ||
|
|
f327b54c0e | ||
|
|
f38105ef05 | ||
|
|
6f6041ee7b | ||
|
|
2c1517d259 |
@@ -1,6 +1,6 @@
|
|||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*.{js,ts,tsx,css}]
|
[*.{js,cjs,ts,tsx,css}]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|||||||
1
.github/actions/build-electron/action.yml
vendored
1
.github/actions/build-electron/action.yml
vendored
@@ -85,6 +85,7 @@ runs:
|
|||||||
APPLE_ID: ${{ env.APPLE_ID }}
|
APPLE_ID: ${{ env.APPLE_ID }}
|
||||||
APPLE_ID_PASSWORD: ${{ env.APPLE_ID_PASSWORD }}
|
APPLE_ID_PASSWORD: ${{ env.APPLE_ID_PASSWORD }}
|
||||||
WINDOWS_SIGN_EXECUTABLE: ${{ env.WINDOWS_SIGN_EXECUTABLE }}
|
WINDOWS_SIGN_EXECUTABLE: ${{ env.WINDOWS_SIGN_EXECUTABLE }}
|
||||||
|
WINDOWS_SIGN_ERROR_LOG: ${{ env.WINDOWS_SIGN_ERROR_LOG }}
|
||||||
TRILIUM_ARTIFACT_NAME_HINT: TriliumNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}
|
TRILIUM_ARTIFACT_NAME_HINT: TriliumNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}
|
||||||
TARGET_ARCH: ${{ inputs.arch }}
|
TARGET_ARCH: ${{ inputs.arch }}
|
||||||
run: pnpm run --filter desktop electron-forge:make --arch=${{ inputs.arch }} --platform=${{ inputs.forge_platform }}
|
run: pnpm run --filter desktop electron-forge:make --arch=${{ inputs.arch }} --platform=${{ inputs.forge_platform }}
|
||||||
|
|||||||
2
.github/actions/build-server/action.yml
vendored
2
.github/actions/build-server/action.yml
vendored
@@ -8,7 +8,7 @@ inputs:
|
|||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
- name: Set up node & dependencies
|
- name: Set up node & dependencies
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
2
.github/actions/report-size/action.yml
vendored
2
.github/actions/report-size/action.yml
vendored
@@ -69,7 +69,7 @@ runs:
|
|||||||
|
|
||||||
# Post github action comment
|
# Post github action comment
|
||||||
- name: Post comment
|
- name: Post comment
|
||||||
uses: marocchino/sticky-pull-request-comment@v2
|
uses: marocchino/sticky-pull-request-comment@v3
|
||||||
if: ${{ steps.bundleSize.outputs.hasDifferences == 'true' }} # post only in case of changes
|
if: ${{ steps.bundleSize.outputs.hasDifferences == 'true' }} # post only in case of changes
|
||||||
with:
|
with:
|
||||||
number: ${{ github.event.pull_request.number }}
|
number: ${{ github.event.pull_request.number }}
|
||||||
|
|||||||
2
.github/workflows/checks.yml
vendored
2
.github/workflows/checks.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Check if PRs have conflicts
|
- name: Check if PRs have conflicts
|
||||||
uses: eps1lon/actions-label-merge-conflict@v3
|
uses: eps1lon/actions-label-merge-conflict@v3
|
||||||
if: github.repository == ${{ vars.REPO_MAIN }}
|
if: ${{ github.repository == vars.REPO_MAIN }}
|
||||||
with:
|
with:
|
||||||
dirtyLabel: "merge-conflicts"
|
dirtyLabel: "merge-conflicts"
|
||||||
repoToken: "${{ secrets.MERGE_CONFLICT_LABEL_PAT }}"
|
repoToken: "${{ secrets.MERGE_CONFLICT_LABEL_PAT }}"
|
||||||
|
|||||||
4
.github/workflows/deploy-docs.yml
vendored
4
.github/workflows/deploy-docs.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v5
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
@@ -67,7 +67,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Deploy
|
- name: Deploy
|
||||||
uses: ./.github/actions/deploy-to-cloudflare-pages
|
uses: ./.github/actions/deploy-to-cloudflare-pages
|
||||||
if: github.repository == ${{ vars.REPO_MAIN }}
|
if: ${{ github.repository == vars.REPO_MAIN }}
|
||||||
with:
|
with:
|
||||||
project_name: "trilium-docs"
|
project_name: "trilium-docs"
|
||||||
comment_body: "📚 Documentation preview is ready"
|
comment_body: "📚 Documentation preview is ready"
|
||||||
|
|||||||
45
.github/workflows/dev.yml
vendored
45
.github/workflows/dev.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
|||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
- name: Set up node & dependencies
|
- name: Set up node & dependencies
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
@@ -37,8 +37,35 @@ jobs:
|
|||||||
- name: Typecheck
|
- name: Typecheck
|
||||||
run: pnpm typecheck
|
run: pnpm typecheck
|
||||||
|
|
||||||
- name: Run the unit tests
|
- name: Run the client-side tests
|
||||||
run: pnpm run test:all
|
run: pnpm run --filter=client test
|
||||||
|
|
||||||
|
- name: Upload client test report
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: client-test-report
|
||||||
|
path: apps/client/test-output/vitest/html/
|
||||||
|
retention-days: 30
|
||||||
|
|
||||||
|
- name: Run the server-side tests
|
||||||
|
run: pnpm run --filter=server test
|
||||||
|
|
||||||
|
- name: Upload server test report
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: server-test-report
|
||||||
|
path: apps/server/test-output/vitest/html/
|
||||||
|
retention-days: 30
|
||||||
|
|
||||||
|
- name: Run CKEditor e2e tests
|
||||||
|
run: |
|
||||||
|
pnpm run --filter=ckeditor5-mermaid test
|
||||||
|
pnpm run --filter=ckeditor5-math test
|
||||||
|
|
||||||
|
- name: Run the rest of the tests
|
||||||
|
run: pnpm run --filter=\!client --filter=\!server --filter=\!ckeditor5-mermaid --filter=\!ckeditor5-math test
|
||||||
|
|
||||||
build_docker:
|
build_docker:
|
||||||
name: Build Docker image
|
name: Build Docker image
|
||||||
@@ -47,7 +74,7 @@ jobs:
|
|||||||
- test_dev
|
- test_dev
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
- name: Update build info
|
- name: Update build info
|
||||||
@@ -62,8 +89,8 @@ jobs:
|
|||||||
key: ${{ secrets.RELATIVE_CI_CLIENT_KEY }}
|
key: ${{ secrets.RELATIVE_CI_CLIENT_KEY }}
|
||||||
- name: Trigger server build
|
- name: Trigger server build
|
||||||
run: pnpm run server:build
|
run: pnpm run server:build
|
||||||
- uses: docker/setup-buildx-action@v3
|
- uses: docker/setup-buildx-action@v4
|
||||||
- uses: docker/build-push-action@v6
|
- uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: apps/server
|
context: apps/server
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
@@ -82,7 +109,7 @@ jobs:
|
|||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
@@ -97,10 +124,10 @@ jobs:
|
|||||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Build and export to Docker
|
- name: Build and export to Docker
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: apps/server
|
context: apps/server
|
||||||
file: apps/server/${{ matrix.dockerfile }}
|
file: apps/server/${{ matrix.dockerfile }}
|
||||||
|
|||||||
2
.github/workflows/i18n.yml
vendored
2
.github/workflows/i18n.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
- name: Set up node & dependencies
|
- name: Set up node & dependencies
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
146
.github/workflows/main-docker.yml
vendored
146
.github/workflows/main-docker.yml
vendored
@@ -40,9 +40,9 @@ jobs:
|
|||||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
- name: Set up node & dependencies
|
- name: Set up node & dependencies
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
@@ -59,7 +59,7 @@ jobs:
|
|||||||
run: pnpm run server:build
|
run: pnpm run server:build
|
||||||
|
|
||||||
- name: Build and export to Docker
|
- name: Build and export to Docker
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: apps/server
|
context: apps/server
|
||||||
file: apps/server/${{ matrix.dockerfile }}
|
file: apps/server/${{ matrix.dockerfile }}
|
||||||
@@ -86,12 +86,12 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload Playwright trace
|
- name: Upload Playwright trace
|
||||||
if: failure()
|
if: failure()
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: Playwright trace (${{ matrix.dockerfile }})
|
name: Playwright trace (${{ matrix.dockerfile }})
|
||||||
path: test-output/playwright/output
|
path: test-output/playwright/output
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v6
|
- uses: actions/upload-artifact@v7
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
with:
|
with:
|
||||||
name: Playwright report (${{ matrix.dockerfile }})
|
name: Playwright report (${{ matrix.dockerfile }})
|
||||||
@@ -142,7 +142,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
- name: Set up node & dependencies
|
- name: Set up node & dependencies
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
@@ -164,11 +164,9 @@ jobs:
|
|||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
with:
|
with:
|
||||||
images: |
|
images: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
tags: |
|
tags: |
|
||||||
type=ref,event=branch
|
type=ref,event=branch
|
||||||
type=ref,event=tag
|
type=ref,event=tag
|
||||||
@@ -177,28 +175,21 @@ jobs:
|
|||||||
latest=false
|
latest=false
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Login to GHCR
|
- name: Login to GHCR
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.GHCR_REGISTRY }}
|
registry: ${{ env.GHCR_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Build and push by digest
|
||||||
id: build
|
id: build
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: apps/server
|
context: apps/server
|
||||||
file: apps/server/${{ matrix.dockerfile }}
|
file: apps/server/${{ matrix.dockerfile }}
|
||||||
@@ -213,7 +204,7 @@ jobs:
|
|||||||
touch "/tmp/digests/${digest#sha256:}"
|
touch "/tmp/digests/${digest#sha256:}"
|
||||||
|
|
||||||
- name: Upload digest
|
- name: Upload digest
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: digests-${{ env.PLATFORM_PAIR }}-${{ matrix.dockerfile }}
|
name: digests-${{ env.PLATFORM_PAIR }}-${{ matrix.dockerfile }}
|
||||||
path: /tmp/digests/*
|
path: /tmp/digests/*
|
||||||
@@ -227,7 +218,7 @@ jobs:
|
|||||||
- build
|
- build
|
||||||
steps:
|
steps:
|
||||||
- name: Download digests
|
- name: Download digests
|
||||||
uses: actions/download-artifact@v7
|
uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
path: /tmp/digests
|
path: /tmp/digests
|
||||||
pattern: digests-*
|
pattern: digests-*
|
||||||
@@ -237,75 +228,86 @@ jobs:
|
|||||||
- name: Set TEST_TAG to lowercase
|
- name: Set TEST_TAG to lowercase
|
||||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up crane
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: imjasonh/setup-crane@v0.5
|
||||||
|
|
||||||
- name: Docker meta
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: |
|
|
||||||
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
flavor: |
|
|
||||||
latest=false
|
|
||||||
|
|
||||||
- name: Login to GHCR
|
- name: Login to GHCR
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.GHCR_REGISTRY }}
|
registry: ${{ env.GHCR_REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.DOCKERHUB_REGISTRY }}
|
registry: ${{ env.DOCKERHUB_REGISTRY }}
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Create manifest list and push
|
- name: Docker meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v6
|
||||||
|
with:
|
||||||
|
images: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
tags: |
|
||||||
|
type=ref,event=branch
|
||||||
|
type=ref,event=tag
|
||||||
|
type=sha
|
||||||
|
flavor: |
|
||||||
|
latest=false
|
||||||
|
|
||||||
|
- name: Verify digests exist on GHCR
|
||||||
working-directory: /tmp/digests
|
working-directory: /tmp/digests
|
||||||
run: |
|
run: |
|
||||||
# Extract the branch or tag name from the ref
|
echo "Verifying all digests are available on GHCR..."
|
||||||
REF_NAME=$(echo "${GITHUB_REF}" | sed 's/refs\/heads\///' | sed 's/refs\/tags\///')
|
for DIGEST_FILE in *; do
|
||||||
|
DIGEST="sha256:${DIGEST_FILE}"
|
||||||
|
echo -n " ${DIGEST}: "
|
||||||
|
crane manifest "${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@${DIGEST}" > /dev/null
|
||||||
|
echo "OK"
|
||||||
|
done
|
||||||
|
|
||||||
# Create and push the manifest list with both the branch/tag name and the commit SHA
|
- name: Create and push multi-arch manifest
|
||||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
working-directory: /tmp/digests
|
||||||
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME} \
|
run: |
|
||||||
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
GHCR_IMAGE="${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}"
|
||||||
|
DOCKERHUB_IMAGE="${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}"
|
||||||
|
|
||||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
# Build -m flags for crane index append from digest files
|
||||||
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME} \
|
MANIFEST_ARGS=""
|
||||||
$(printf '${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
for d in *; do
|
||||||
|
MANIFEST_ARGS="${MANIFEST_ARGS} -m ${GHCR_IMAGE}@sha256:${d}"
|
||||||
|
done
|
||||||
|
|
||||||
# If the ref is a tag, also tag the image as stable as this is part of a 'release'
|
# Create multi-arch manifest for each tag from metadata, plus copy to DockerHub
|
||||||
# and only go in the `if` if there is NOT a `-` in the tag's name, due to tagging of `-alpha`, `-beta`, etc...
|
while IFS= read -r TAG; do
|
||||||
|
echo "Creating manifest: ${TAG}"
|
||||||
|
crane index append ${MANIFEST_ARGS} -t "${TAG}"
|
||||||
|
|
||||||
|
SUFFIX="${TAG#*:}"
|
||||||
|
echo "Copying to DockerHub: ${DOCKERHUB_IMAGE}:${SUFFIX}"
|
||||||
|
crane copy "${TAG}" "${DOCKERHUB_IMAGE}:${SUFFIX}"
|
||||||
|
done <<< "${{ steps.meta.outputs.tags }}"
|
||||||
|
|
||||||
|
# For stable releases (tags without hyphens), also create stable + latest
|
||||||
|
REF_NAME="${GITHUB_REF#refs/tags/}"
|
||||||
if [[ "${GITHUB_REF}" == refs/tags/* && ! "${REF_NAME}" =~ - ]]; then
|
if [[ "${GITHUB_REF}" == refs/tags/* && ! "${REF_NAME}" =~ - ]]; then
|
||||||
# First create stable tags
|
echo "Creating stable tags..."
|
||||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
crane index append ${MANIFEST_ARGS} -t "${GHCR_IMAGE}:stable"
|
||||||
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:stable \
|
crane copy "${GHCR_IMAGE}:stable" "${DOCKERHUB_IMAGE}:stable"
|
||||||
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
|
||||||
|
|
||||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
|
||||||
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:stable \
|
|
||||||
$(printf '${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
|
||||||
|
|
||||||
# Small delay to ensure stable tag is fully propagated
|
|
||||||
sleep 5
|
|
||||||
|
|
||||||
# Now update latest tags
|
|
||||||
docker buildx imagetools create \
|
|
||||||
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
|
|
||||||
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:stable
|
|
||||||
|
|
||||||
docker buildx imagetools create \
|
|
||||||
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
|
|
||||||
${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:stable
|
|
||||||
|
|
||||||
|
echo "Creating latest tags..."
|
||||||
|
crane copy "${GHCR_IMAGE}:stable" "${GHCR_IMAGE}:latest"
|
||||||
|
crane copy "${GHCR_IMAGE}:latest" "${DOCKERHUB_IMAGE}:latest"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Inspect image
|
- name: Inspect manifests
|
||||||
run: |
|
run: |
|
||||||
docker buildx imagetools inspect ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
|
REF_NAME="${GITHUB_REF#refs/heads/}"
|
||||||
docker buildx imagetools inspect ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
|
REF_NAME="${REF_NAME#refs/tags/}"
|
||||||
|
echo "=== GHCR ==="
|
||||||
|
crane manifest "${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME}"
|
||||||
|
echo ""
|
||||||
|
echo "=== DockerHub ==="
|
||||||
|
crane manifest "${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME}"
|
||||||
|
|||||||
13
.github/workflows/nightly.yml
vendored
13
.github/workflows/nightly.yml
vendored
@@ -26,7 +26,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
nightly-electron:
|
nightly-electron:
|
||||||
if: github.repository == ${{ vars.REPO_MAIN }}
|
if: ${{ github.repository == vars.REPO_MAIN }}
|
||||||
name: Deploy nightly
|
name: Deploy nightly
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -61,7 +61,7 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os.image }}
|
runs-on: ${{ matrix.os.image }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
- name: Set up node & dependencies
|
- name: Set up node & dependencies
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
@@ -87,10 +87,11 @@ jobs:
|
|||||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||||
WINDOWS_SIGN_EXECUTABLE: ${{ vars.WINDOWS_SIGN_EXECUTABLE }}
|
WINDOWS_SIGN_EXECUTABLE: ${{ vars.WINDOWS_SIGN_EXECUTABLE }}
|
||||||
|
WINDOWS_SIGN_ERROR_LOG: ${{ vars.WINDOWS_SIGN_ERROR_LOG }}
|
||||||
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
|
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
|
||||||
|
|
||||||
- name: Publish release
|
- name: Publish release
|
||||||
uses: softprops/action-gh-release@v2.5.0
|
uses: softprops/action-gh-release@v2.6.1
|
||||||
if: ${{ github.event_name != 'pull_request' }}
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
with:
|
with:
|
||||||
make_latest: false
|
make_latest: false
|
||||||
@@ -102,14 +103,14 @@ jobs:
|
|||||||
name: Nightly Build
|
name: Nightly Build
|
||||||
|
|
||||||
- name: Publish artifacts
|
- name: Publish artifacts
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
with:
|
with:
|
||||||
name: TriliumNotes ${{ matrix.os.name }} ${{ matrix.arch }}
|
name: TriliumNotes ${{ matrix.os.name }} ${{ matrix.arch }}
|
||||||
path: apps/desktop/upload
|
path: apps/desktop/upload
|
||||||
|
|
||||||
nightly-server:
|
nightly-server:
|
||||||
if: github.repository == ${{ vars.REPO_MAIN }}
|
if: ${{ github.repository == vars.REPO_MAIN }}
|
||||||
name: Deploy server nightly
|
name: Deploy server nightly
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -131,7 +132,7 @@ jobs:
|
|||||||
arch: ${{ matrix.arch }}
|
arch: ${{ matrix.arch }}
|
||||||
|
|
||||||
- name: Publish release
|
- name: Publish release
|
||||||
uses: softprops/action-gh-release@v2.5.0
|
uses: softprops/action-gh-release@v2.6.1
|
||||||
if: ${{ github.event_name != 'pull_request' }}
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
with:
|
with:
|
||||||
make_latest: false
|
make_latest: false
|
||||||
|
|||||||
4
.github/workflows/playwright.yml
vendored
4
.github/workflows/playwright.yml
vendored
@@ -38,7 +38,7 @@ jobs:
|
|||||||
filter: tree:0
|
filter: tree:0
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
@@ -77,7 +77,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload test report
|
- name: Upload test report
|
||||||
if: failure()
|
if: failure()
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: e2e report ${{ matrix.arch }}
|
name: e2e report ${{ matrix.arch }}
|
||||||
path: apps/server-e2e/test-output
|
path: apps/server-e2e/test-output
|
||||||
|
|||||||
25
.github/workflows/release.yml
vendored
25
.github/workflows/release.yml
vendored
@@ -17,10 +17,22 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- uses: pnpm/action-setup@v5
|
||||||
|
- name: Set up node & dependencies
|
||||||
|
uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: 24
|
||||||
|
cache: 'pnpm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --filter source --frozen-lockfile --ignore-scripts
|
||||||
|
|
||||||
- name: Check version consistency
|
- name: Check version consistency
|
||||||
run: pnpm tsx ${{ github.workspace }}/scripts/check-version-consistency.ts ${{ github.ref_name }}
|
run: pnpm tsx ${{ github.workspace }}/scripts/check-version-consistency.ts ${{ github.ref_name }}
|
||||||
make-electron:
|
make-electron:
|
||||||
name: Make Electron
|
name: Make Electron
|
||||||
|
needs:
|
||||||
|
- sanity-check
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -54,7 +66,7 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os.image }}
|
runs-on: ${{ matrix.os.image }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
- name: Set up node & dependencies
|
- name: Set up node & dependencies
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
@@ -78,16 +90,19 @@ jobs:
|
|||||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||||
WINDOWS_SIGN_EXECUTABLE: ${{ vars.WINDOWS_SIGN_EXECUTABLE }}
|
WINDOWS_SIGN_EXECUTABLE: ${{ vars.WINDOWS_SIGN_EXECUTABLE }}
|
||||||
|
WINDOWS_SIGN_ERROR_LOG: ${{ vars.WINDOWS_SIGN_ERROR_LOG }}
|
||||||
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
|
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
|
||||||
|
|
||||||
- name: Upload the artifact
|
- name: Upload the artifact
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: release-desktop-${{ matrix.os.name }}-${{ matrix.arch }}
|
name: release-desktop-${{ matrix.os.name }}-${{ matrix.arch }}
|
||||||
path: apps/desktop/upload/*.*
|
path: apps/desktop/upload/*.*
|
||||||
|
|
||||||
build_server:
|
build_server:
|
||||||
name: Build Linux Server
|
name: Build Linux Server
|
||||||
|
needs:
|
||||||
|
- sanity-check
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -108,7 +123,7 @@ jobs:
|
|||||||
arch: ${{ matrix.arch }}
|
arch: ${{ matrix.arch }}
|
||||||
|
|
||||||
- name: Upload the artifact
|
- name: Upload the artifact
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: release-server-linux-${{ matrix.arch }}
|
name: release-server-linux-${{ matrix.arch }}
|
||||||
path: upload/*.*
|
path: upload/*.*
|
||||||
@@ -128,14 +143,14 @@ jobs:
|
|||||||
docs/Release Notes
|
docs/Release Notes
|
||||||
|
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
uses: actions/download-artifact@v7
|
uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
pattern: release-*
|
pattern: release-*
|
||||||
path: upload
|
path: upload
|
||||||
|
|
||||||
- name: Publish stable release
|
- name: Publish stable release
|
||||||
uses: softprops/action-gh-release@v2.5.0
|
uses: softprops/action-gh-release@v2.6.1
|
||||||
with:
|
with:
|
||||||
draft: false
|
draft: false
|
||||||
body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md
|
body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md
|
||||||
|
|||||||
69
.github/workflows/web-clipper.yml
vendored
Normal file
69
.github/workflows/web-clipper.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
name: Deploy web clipper extension
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "apps/web-clipper/**"
|
||||||
|
tags:
|
||||||
|
- "web-clipper-v*"
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "apps/web-clipper/**"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
discussions: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Build web clipper extension
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
deployments: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: pnpm/action-setup@v5
|
||||||
|
- name: Set up node & dependencies
|
||||||
|
uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: 24
|
||||||
|
cache: "pnpm"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --filter web-clipper --frozen-lockfile --ignore-scripts
|
||||||
|
|
||||||
|
- name: Build the web clipper extension
|
||||||
|
run: |
|
||||||
|
pnpm --filter web-clipper zip
|
||||||
|
pnpm --filter web-clipper zip:firefox
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
if: ${{ !startsWith(github.ref, 'refs/tags/web-clipper-v') }}
|
||||||
|
with:
|
||||||
|
name: web-clipper-extension
|
||||||
|
path: apps/web-clipper/.output/*.zip
|
||||||
|
include-hidden-files: true
|
||||||
|
if-no-files-found: error
|
||||||
|
compression-level: 0
|
||||||
|
|
||||||
|
- name: Release web clipper extension
|
||||||
|
uses: softprops/action-gh-release@v2.6.1
|
||||||
|
if: ${{ startsWith(github.ref, 'refs/tags/web-clipper-v') }}
|
||||||
|
with:
|
||||||
|
draft: false
|
||||||
|
fail_on_unmatched_files: true
|
||||||
|
files: apps/web-clipper/.output/*.zip
|
||||||
|
discussion_category_name: Releases
|
||||||
|
make_latest: false
|
||||||
|
token: ${{ secrets.RELEASE_PAT }}
|
||||||
2
.github/workflows/website.yml
vendored
2
.github/workflows/website.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
- name: Set up node & dependencies
|
- name: Set up node & dependencies
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -46,7 +46,6 @@ upload
|
|||||||
|
|
||||||
/.direnv
|
/.direnv
|
||||||
/result
|
/result
|
||||||
.svelte-kit
|
|
||||||
|
|
||||||
# docs
|
# docs
|
||||||
site/
|
site/
|
||||||
|
|||||||
57
.vscode/launch.json
vendored
Normal file
57
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch client (Chrome)",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "chrome",
|
||||||
|
"url": "http://localhost:8080",
|
||||||
|
"webRoot": "${workspaceFolder}/apps/client"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Launch server",
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/apps/server/src/main.ts",
|
||||||
|
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/tsx",
|
||||||
|
"env": {
|
||||||
|
"NODE_ENV": "development",
|
||||||
|
"TRILIUM_ENV": "dev",
|
||||||
|
"TRILIUM_DATA_DIR": "${input:trilium_data_dir}",
|
||||||
|
"TRILIUM_RESOURCE_DIR": "${workspaceFolder}/apps/server/src"
|
||||||
|
},
|
||||||
|
"autoAttachChildProcesses": true,
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"internalConsoleOptions": "neverOpen",
|
||||||
|
"skipFiles": ["<node_internals>/**", "${workspaceFolder}/node_modules/**"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Launch Vitest with current test file",
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"autoAttachChildProcesses": true,
|
||||||
|
"program": "${workspaceFolder}/node_modules/vitest/vitest.mjs",
|
||||||
|
"args": ["run", "${relativeFile}"],
|
||||||
|
"smartStep": true,
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"skipFiles": ["<node_internals>/**", "**/node_modules/**"],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"compounds": [
|
||||||
|
{
|
||||||
|
"name": "Launch client (Chrome) and server",
|
||||||
|
"configurations": ["Launch server","Launch client (Chrome)"],
|
||||||
|
"stopAll": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"id": "trilium_data_dir",
|
||||||
|
"type": "promptString",
|
||||||
|
"description": "Select Trilum Notes data directory",
|
||||||
|
"default": "${workspaceFolder}/apps/server/data"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -42,5 +42,8 @@
|
|||||||
},
|
},
|
||||||
"eslint.rules.customizations": [
|
"eslint.rules.customizations": [
|
||||||
{ "rule": "*", "severity": "warn" }
|
{ "rule": "*", "severity": "warn" }
|
||||||
|
],
|
||||||
|
"cSpell.words": [
|
||||||
|
"Trilium"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -10,4 +10,5 @@ Description above is a general rule and may be altered on case by case basis.
|
|||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
You can report low severity vulnerabilities as GitHub issues, more severe vulnerabilities should be reported to the email [contact@eliandoran.me](mailto:contact@eliandoran.me)
|
* For low severity vulnerabilities, they can be reported as GitHub issues.
|
||||||
|
* For severe vulnerabilities, please report it using [GitHub Security Advisories](https://github.com/TriliumNext/Trilium/security/advisories).
|
||||||
|
|||||||
@@ -1,22 +1,28 @@
|
|||||||
{
|
{
|
||||||
"name": "build-docs",
|
"name": "build-docs",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "Build documentation from Trilium notes",
|
||||||
"main": "src/main.ts",
|
"main": "src/main.ts",
|
||||||
|
"bin": {
|
||||||
|
"trilium-build-docs": "dist/cli.js"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "tsx ."
|
"start": "tsx .",
|
||||||
|
"cli": "tsx src/cli.ts",
|
||||||
|
"build": "tsx scripts/build.ts"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "Elian Doran <contact@eliandoran.me>",
|
"author": "Elian Doran <contact@eliandoran.me>",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"packageManager": "pnpm@10.28.0",
|
"packageManager": "pnpm@10.33.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@redocly/cli": "2.14.5",
|
"@redocly/cli": "2.25.1",
|
||||||
"archiver": "7.0.1",
|
"archiver": "7.0.1",
|
||||||
"fs-extra": "11.3.3",
|
"fs-extra": "11.3.4",
|
||||||
"react": "19.2.3",
|
"js-yaml": "4.1.1",
|
||||||
"react-dom": "19.2.3",
|
"react": "19.2.4",
|
||||||
"typedoc": "0.28.16",
|
"react-dom": "19.2.4",
|
||||||
|
"typedoc": "0.28.18",
|
||||||
"typedoc-plugin-missing-exports": "4.1.2"
|
"typedoc-plugin-missing-exports": "4.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
apps/build-docs/scripts/build.ts
Normal file
23
apps/build-docs/scripts/build.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import BuildHelper from "../../../scripts/build-utils";
|
||||||
|
|
||||||
|
const build = new BuildHelper("apps/build-docs");
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// Build the CLI and other TypeScript files
|
||||||
|
await build.buildBackend([
|
||||||
|
"src/cli.ts",
|
||||||
|
"src/main.ts",
|
||||||
|
"src/build-docs.ts",
|
||||||
|
"src/swagger.ts",
|
||||||
|
"src/script-api.ts",
|
||||||
|
"src/context.ts"
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Copy HTML template
|
||||||
|
build.copy("src/index.html", "index.html");
|
||||||
|
|
||||||
|
// Copy node modules dependencies if needed
|
||||||
|
build.copyNodeModules([ "better-sqlite3", "bindings", "file-uri-to-path" ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -13,8 +13,12 @@
|
|||||||
* Make sure to keep in line with backend's `script_context.ts`.
|
* Make sure to keep in line with backend's `script_context.ts`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export type { default as AbstractBeccaEntity } from "../../server/src/becca/entities/abstract_becca_entity.js";
|
export type {
|
||||||
export type { default as BAttachment } from "../../server/src/becca/entities/battachment.js";
|
default as AbstractBeccaEntity
|
||||||
|
} from "../../server/src/becca/entities/abstract_becca_entity.js";
|
||||||
|
export type {
|
||||||
|
default as BAttachment
|
||||||
|
} from "../../server/src/becca/entities/battachment.js";
|
||||||
export type { default as BAttribute } from "../../server/src/becca/entities/battribute.js";
|
export type { default as BAttribute } from "../../server/src/becca/entities/battribute.js";
|
||||||
export type { default as BBranch } from "../../server/src/becca/entities/bbranch.js";
|
export type { default as BBranch } from "../../server/src/becca/entities/bbranch.js";
|
||||||
export type { default as BEtapiToken } from "../../server/src/becca/entities/betapi_token.js";
|
export type { default as BEtapiToken } from "../../server/src/becca/entities/betapi_token.js";
|
||||||
@@ -31,6 +35,7 @@ export type { Api };
|
|||||||
const fakeNote = new BNote();
|
const fakeNote = new BNote();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `api` global variable allows access to the backend script API, which is documented in {@link Api}.
|
* The `api` global variable allows access to the backend script API,
|
||||||
|
* which is documented in {@link Api}.
|
||||||
*/
|
*/
|
||||||
export const api: Api = new BackendScriptApi(fakeNote, {});
|
export const api: Api = new BackendScriptApi(fakeNote, {});
|
||||||
|
|||||||
@@ -1,19 +1,90 @@
|
|||||||
process.env.TRILIUM_INTEGRATION_TEST = "memory-no-store";
|
process.env.TRILIUM_INTEGRATION_TEST = "memory-no-store";
|
||||||
process.env.TRILIUM_RESOURCE_DIR = "../server/src";
|
// Only set TRILIUM_RESOURCE_DIR if not already set (e.g., by Nix wrapper)
|
||||||
|
if (!process.env.TRILIUM_RESOURCE_DIR) {
|
||||||
|
process.env.TRILIUM_RESOURCE_DIR = "../server/src";
|
||||||
|
}
|
||||||
process.env.NODE_ENV = "development";
|
process.env.NODE_ENV = "development";
|
||||||
|
|
||||||
import cls from "@triliumnext/server/src/services/cls.js";
|
import cls from "@triliumnext/server/src/services/cls.js";
|
||||||
import { dirname, join, resolve } from "path";
|
import archiver from "archiver";
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
import { WriteStream } from "fs";
|
||||||
import * as fs from "fs/promises";
|
import * as fs from "fs/promises";
|
||||||
import * as fsExtra from "fs-extra";
|
import * as fsExtra from "fs-extra";
|
||||||
import archiver from "archiver";
|
import yaml from "js-yaml";
|
||||||
import { WriteStream } from "fs";
|
import { dirname, join, resolve } from "path";
|
||||||
import { execSync } from "child_process";
|
|
||||||
import BuildContext from "./context.js";
|
import BuildContext from "./context.js";
|
||||||
|
|
||||||
|
interface NoteMapping {
|
||||||
|
rootNoteId: string;
|
||||||
|
path: string;
|
||||||
|
format: "markdown" | "html" | "share";
|
||||||
|
ignoredFiles?: string[];
|
||||||
|
exportOnly?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Config {
|
||||||
|
baseUrl: string;
|
||||||
|
noteMappings: NoteMapping[];
|
||||||
|
}
|
||||||
|
|
||||||
const DOCS_ROOT = "../../../docs";
|
const DOCS_ROOT = "../../../docs";
|
||||||
const OUTPUT_DIR = "../../site";
|
const OUTPUT_DIR = "../../site";
|
||||||
|
|
||||||
|
// Load configuration from edit-docs-config.yaml
|
||||||
|
async function loadConfig(configPath?: string): Promise<Config | null> {
|
||||||
|
const pathsToTry = configPath
|
||||||
|
? [resolve(configPath)]
|
||||||
|
: [
|
||||||
|
join(process.cwd(), "edit-docs-config.yaml"),
|
||||||
|
join(__dirname, "../../../edit-docs-config.yaml")
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const path of pathsToTry) {
|
||||||
|
try {
|
||||||
|
const configContent = await fs.readFile(path, "utf-8");
|
||||||
|
const config = yaml.load(configContent) as Config;
|
||||||
|
|
||||||
|
// Resolve all paths relative to the config file's directory
|
||||||
|
const CONFIG_DIR = dirname(path);
|
||||||
|
config.noteMappings = config.noteMappings.map((mapping) => ({
|
||||||
|
...mapping,
|
||||||
|
path: resolve(CONFIG_DIR, mapping.path)
|
||||||
|
}));
|
||||||
|
|
||||||
|
return config;
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code !== "ENOENT") {
|
||||||
|
throw error; // rethrow unexpected errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null; // No config file found
|
||||||
|
}
|
||||||
|
|
||||||
|
async function exportDocs(
|
||||||
|
noteId: string,
|
||||||
|
format: "markdown" | "html" | "share",
|
||||||
|
outputPath: string,
|
||||||
|
ignoredFiles?: string[]
|
||||||
|
) {
|
||||||
|
const zipFilePath = `output-${noteId}.zip`;
|
||||||
|
try {
|
||||||
|
const { exportToZipFile } = (await import("@triliumnext/server/src/services/export/zip.js"))
|
||||||
|
.default;
|
||||||
|
await exportToZipFile(noteId, format, zipFilePath, {});
|
||||||
|
|
||||||
|
const ignoredSet = ignoredFiles ? new Set(ignoredFiles) : undefined;
|
||||||
|
await extractZip(zipFilePath, outputPath, ignoredSet);
|
||||||
|
} finally {
|
||||||
|
if (await fsExtra.exists(zipFilePath)) {
|
||||||
|
await fsExtra.rm(zipFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function importAndExportDocs(sourcePath: string, outputSubDir: string) {
|
async function importAndExportDocs(sourcePath: string, outputSubDir: string) {
|
||||||
const note = await importData(sourcePath);
|
const note = await importData(sourcePath);
|
||||||
|
|
||||||
@@ -21,15 +92,18 @@ async function importAndExportDocs(sourcePath: string, outputSubDir: string) {
|
|||||||
const zipName = outputSubDir || "user-guide";
|
const zipName = outputSubDir || "user-guide";
|
||||||
const zipFilePath = `output-${zipName}.zip`;
|
const zipFilePath = `output-${zipName}.zip`;
|
||||||
try {
|
try {
|
||||||
const { exportToZip } = (await import("@triliumnext/server/src/services/export/zip.js")).default;
|
const { exportToZip } = (await import("@triliumnext/server/src/services/export/zip.js"))
|
||||||
|
.default;
|
||||||
const branch = note.getParentBranches()[0];
|
const branch = note.getParentBranches()[0];
|
||||||
const taskContext = new (await import("@triliumnext/server/src/services/task_context.js")).default(
|
const taskContext = new (await import("@triliumnext/server/src/services/task_context.js"))
|
||||||
"no-progress-reporting",
|
.default(
|
||||||
"export",
|
"no-progress-reporting",
|
||||||
null
|
"export",
|
||||||
);
|
null
|
||||||
|
);
|
||||||
const fileOutputStream = fsExtra.createWriteStream(zipFilePath);
|
const fileOutputStream = fsExtra.createWriteStream(zipFilePath);
|
||||||
await exportToZip(taskContext, branch, "share", fileOutputStream);
|
await exportToZip(taskContext, branch, "share", fileOutputStream);
|
||||||
|
const { waitForStreamToFinish } = await import("@triliumnext/server/src/services/utils.js");
|
||||||
await waitForStreamToFinish(fileOutputStream);
|
await waitForStreamToFinish(fileOutputStream);
|
||||||
|
|
||||||
// Output to root directory if outputSubDir is empty, otherwise to subdirectory
|
// Output to root directory if outputSubDir is empty, otherwise to subdirectory
|
||||||
@@ -42,7 +116,7 @@ async function importAndExportDocs(sourcePath: string, outputSubDir: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildDocsInner() {
|
async function buildDocsInner(config?: Config) {
|
||||||
const i18n = await import("@triliumnext/server/src/services/i18n.js");
|
const i18n = await import("@triliumnext/server/src/services/i18n.js");
|
||||||
await i18n.initializeTranslations();
|
await i18n.initializeTranslations();
|
||||||
|
|
||||||
@@ -53,18 +127,49 @@ async function buildDocsInner() {
|
|||||||
const beccaLoader = await import("../../server/src/becca/becca_loader.js");
|
const beccaLoader = await import("../../server/src/becca/becca_loader.js");
|
||||||
await beccaLoader.beccaLoaded;
|
await beccaLoader.beccaLoaded;
|
||||||
|
|
||||||
// Build User Guide
|
if (config) {
|
||||||
console.log("Building User Guide...");
|
// Config-based build (reads from edit-docs-config.yaml)
|
||||||
await importAndExportDocs(join(__dirname, DOCS_ROOT, "User Guide"), "user-guide");
|
console.log("Building documentation from config file...");
|
||||||
|
|
||||||
// Build Developer Guide
|
// Import all non-export-only mappings
|
||||||
console.log("Building Developer Guide...");
|
for (const mapping of config.noteMappings) {
|
||||||
await importAndExportDocs(join(__dirname, DOCS_ROOT, "Developer Guide"), "developer-guide");
|
if (!mapping.exportOnly) {
|
||||||
|
console.log(`Importing from ${mapping.path}...`);
|
||||||
|
await importData(mapping.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Copy favicon.
|
// Export all mappings
|
||||||
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "favicon.ico"));
|
for (const mapping of config.noteMappings) {
|
||||||
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "user-guide", "favicon.ico"));
|
if (mapping.exportOnly) {
|
||||||
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "developer-guide", "favicon.ico"));
|
console.log(`Exporting ${mapping.format} to ${mapping.path}...`);
|
||||||
|
await exportDocs(
|
||||||
|
mapping.rootNoteId,
|
||||||
|
mapping.format,
|
||||||
|
mapping.path,
|
||||||
|
mapping.ignoredFiles
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Legacy hardcoded build (for backward compatibility)
|
||||||
|
console.log("Building User Guide...");
|
||||||
|
await importAndExportDocs(join(__dirname, DOCS_ROOT, "User Guide"), "user-guide");
|
||||||
|
|
||||||
|
console.log("Building Developer Guide...");
|
||||||
|
await importAndExportDocs(
|
||||||
|
join(__dirname, DOCS_ROOT, "Developer Guide"),
|
||||||
|
"developer-guide"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Copy favicon.
|
||||||
|
await fs.copyFile("../../apps/website/src/assets/favicon.ico",
|
||||||
|
join(OUTPUT_DIR, "favicon.ico"));
|
||||||
|
await fs.copyFile("../../apps/website/src/assets/favicon.ico",
|
||||||
|
join(OUTPUT_DIR, "user-guide", "favicon.ico"));
|
||||||
|
await fs.copyFile("../../apps/website/src/assets/favicon.ico",
|
||||||
|
join(OUTPUT_DIR, "developer-guide", "favicon.ico"));
|
||||||
|
}
|
||||||
|
|
||||||
console.log("Documentation built successfully!");
|
console.log("Documentation built successfully!");
|
||||||
}
|
}
|
||||||
@@ -91,12 +196,13 @@ async function createImportZip(path: string) {
|
|||||||
zlib: { level: 0 }
|
zlib: { level: 0 }
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Archive path is ", resolve(path))
|
console.log("Archive path is ", resolve(path));
|
||||||
archive.directory(path, "/");
|
archive.directory(path, "/");
|
||||||
|
|
||||||
const outputStream = fsExtra.createWriteStream(inputFile);
|
const outputStream = fsExtra.createWriteStream(inputFile);
|
||||||
archive.pipe(outputStream);
|
archive.pipe(outputStream);
|
||||||
archive.finalize();
|
archive.finalize();
|
||||||
|
const { waitForStreamToFinish } = await import("@triliumnext/server/src/services/utils.js");
|
||||||
await waitForStreamToFinish(outputStream);
|
await waitForStreamToFinish(outputStream);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -106,15 +212,15 @@ async function createImportZip(path: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function waitForStreamToFinish(stream: WriteStream) {
|
|
||||||
return new Promise<void>((res, rej) => {
|
|
||||||
stream.on("finish", () => res());
|
|
||||||
stream.on("error", (err) => rej(err));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function extractZip(zipFilePath: string, outputPath: string, ignoredFiles?: Set<string>) {
|
export async function extractZip(
|
||||||
const { readZipFile, readContent } = (await import("@triliumnext/server/src/services/import/zip.js"));
|
zipFilePath: string,
|
||||||
|
outputPath: string,
|
||||||
|
ignoredFiles?: Set<string>
|
||||||
|
) {
|
||||||
|
const { readZipFile, readContent } = (await import(
|
||||||
|
"@triliumnext/server/src/services/import/zip.js"
|
||||||
|
));
|
||||||
await readZipFile(await fs.readFile(zipFilePath), async (zip, entry) => {
|
await readZipFile(await fs.readFile(zipFilePath), async (zip, entry) => {
|
||||||
// We ignore directories since they can appear out of order anyway.
|
// We ignore directories since they can appear out of order anyway.
|
||||||
if (!entry.fileName.endsWith("/") && !ignoredFiles?.has(entry.fileName)) {
|
if (!entry.fileName.endsWith("/") && !ignoredFiles?.has(entry.fileName)) {
|
||||||
@@ -129,6 +235,27 @@ export async function extractZip(zipFilePath: string, outputPath: string, ignore
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function buildDocsFromConfig(configPath?: string, gitRootDir?: string) {
|
||||||
|
const config = await loadConfig(configPath);
|
||||||
|
|
||||||
|
if (gitRootDir) {
|
||||||
|
// Build the share theme if we have a gitRootDir (for Trilium project)
|
||||||
|
execSync(`pnpm run --filter share-theme build`, {
|
||||||
|
stdio: "inherit",
|
||||||
|
cwd: gitRootDir
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger the actual build.
|
||||||
|
await new Promise((res, rej) => {
|
||||||
|
cls.init(() => {
|
||||||
|
buildDocsInner(config ?? undefined)
|
||||||
|
.catch(rej)
|
||||||
|
.then(res);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default async function buildDocs({ gitRootDir }: BuildContext) {
|
export default async function buildDocs({ gitRootDir }: BuildContext) {
|
||||||
// Build the share theme.
|
// Build the share theme.
|
||||||
execSync(`pnpm run --filter share-theme build`, {
|
execSync(`pnpm run --filter share-theme build`, {
|
||||||
|
|||||||
89
apps/build-docs/src/cli.ts
Normal file
89
apps/build-docs/src/cli.ts
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import packageJson from "../package.json" with { type: "json" };
|
||||||
|
import { buildDocsFromConfig } from "./build-docs.js";
|
||||||
|
|
||||||
|
// Parse command-line arguments
|
||||||
|
function parseArgs() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
let configPath: string | undefined;
|
||||||
|
let showHelp = false;
|
||||||
|
let showVersion = false;
|
||||||
|
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
if (args[i] === "--config" || args[i] === "-c") {
|
||||||
|
configPath = args[i + 1];
|
||||||
|
if (!configPath) {
|
||||||
|
console.error("Error: --config/-c requires a path argument");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
i++; // Skip the next argument as it's the value
|
||||||
|
} else if (args[i] === "--help" || args[i] === "-h") {
|
||||||
|
showHelp = true;
|
||||||
|
} else if (args[i] === "--version" || args[i] === "-v") {
|
||||||
|
showVersion = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { configPath, showHelp, showVersion };
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVersion(): string {
|
||||||
|
return packageJson.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printHelp() {
|
||||||
|
const version = getVersion();
|
||||||
|
console.log(`
|
||||||
|
Usage: trilium-build-docs [options]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-c, --config <path> Path to the configuration file
|
||||||
|
(default: edit-docs-config.yaml in current directory)
|
||||||
|
-h, --help Display this help message
|
||||||
|
-v, --version Display version information
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Builds documentation from Trilium note structure and exports to various formats.
|
||||||
|
Configuration file should be in YAML format with the following structure:
|
||||||
|
|
||||||
|
baseUrl: "https://example.com"
|
||||||
|
noteMappings:
|
||||||
|
- rootNoteId: "noteId123"
|
||||||
|
path: "docs"
|
||||||
|
format: "markdown"
|
||||||
|
- rootNoteId: "noteId456"
|
||||||
|
path: "public/docs"
|
||||||
|
format: "share"
|
||||||
|
exportOnly: true
|
||||||
|
|
||||||
|
Version: ${version}
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function printVersion() {
|
||||||
|
const version = getVersion();
|
||||||
|
console.log(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const { configPath, showHelp, showVersion } = parseArgs();
|
||||||
|
|
||||||
|
if (showHelp) {
|
||||||
|
printHelp();
|
||||||
|
process.exit(0);
|
||||||
|
} else if (showVersion) {
|
||||||
|
printVersion();
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await buildDocsFromConfig(configPath);
|
||||||
|
process.exit(0);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error building documentation:", error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -13,16 +13,19 @@
|
|||||||
* Make sure to keep in line with frontend's `script_context.ts`.
|
* Make sure to keep in line with frontend's `script_context.ts`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export type { default as BasicWidget } from "../../client/src/widgets/basic_widget.js";
|
|
||||||
export type { default as FAttachment } from "../../client/src/entities/fattachment.js";
|
export type { default as FAttachment } from "../../client/src/entities/fattachment.js";
|
||||||
export type { default as FAttribute } from "../../client/src/entities/fattribute.js";
|
export type { default as FAttribute } from "../../client/src/entities/fattribute.js";
|
||||||
export type { default as FBranch } from "../../client/src/entities/fbranch.js";
|
export type { default as FBranch } from "../../client/src/entities/fbranch.js";
|
||||||
export type { default as FNote } from "../../client/src/entities/fnote.js";
|
export type { default as FNote } from "../../client/src/entities/fnote.js";
|
||||||
export type { Api } from "../../client/src/services/frontend_script_api.js";
|
export type { Api } from "../../client/src/services/frontend_script_api.js";
|
||||||
export type { default as NoteContextAwareWidget } from "../../client/src/widgets/note_context_aware_widget.js";
|
export type { default as BasicWidget } from "../../client/src/widgets/basic_widget.js";
|
||||||
|
export type {
|
||||||
|
default as NoteContextAwareWidget
|
||||||
|
} from "../../client/src/widgets/note_context_aware_widget.js";
|
||||||
export type { default as RightPanelWidget } from "../../client/src/widgets/right_panel_widget.js";
|
export type { default as RightPanelWidget } from "../../client/src/widgets/right_panel_widget.js";
|
||||||
|
|
||||||
import FrontendScriptApi, { type Api } from "../../client/src/services/frontend_script_api.js";
|
import FrontendScriptApi, { type Api } from "../../client/src/services/frontend_script_api.js";
|
||||||
|
|
||||||
//@ts-expect-error
|
|
||||||
|
// @ts-expect-error - FrontendScriptApi is not directly exportable as Api without this simulation.
|
||||||
export const api: Api = new FrontendScriptApi();
|
export const api: Api = new FrontendScriptApi();
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { join } from "path";
|
|
||||||
import BuildContext from "./context";
|
|
||||||
import buildSwagger from "./swagger";
|
|
||||||
import { cpSync, existsSync, mkdirSync, rmSync } from "fs";
|
import { cpSync, existsSync, mkdirSync, rmSync } from "fs";
|
||||||
|
import { join } from "path";
|
||||||
|
|
||||||
import buildDocs from "./build-docs";
|
import buildDocs from "./build-docs";
|
||||||
|
import BuildContext from "./context";
|
||||||
import buildScriptApi from "./script-api";
|
import buildScriptApi from "./script-api";
|
||||||
|
import buildSwagger from "./swagger";
|
||||||
|
|
||||||
const context: BuildContext = {
|
const context: BuildContext = {
|
||||||
gitRootDir: join(__dirname, "../../../"),
|
gitRootDir: join(__dirname, "../../../"),
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { execSync } from "child_process";
|
import { execSync } from "child_process";
|
||||||
import BuildContext from "./context";
|
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
|
||||||
|
import BuildContext from "./context";
|
||||||
|
|
||||||
export default function buildScriptApi({ baseDir, gitRootDir }: BuildContext) {
|
export default function buildScriptApi({ baseDir, gitRootDir }: BuildContext) {
|
||||||
// Generate types
|
// Generate types
|
||||||
execSync(`pnpm typecheck`, { stdio: "inherit", cwd: gitRootDir });
|
execSync(`pnpm typecheck`, { stdio: "inherit", cwd: gitRootDir });
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import BuildContext from "./context";
|
|
||||||
import { join } from "path";
|
|
||||||
import { execSync } from "child_process";
|
import { execSync } from "child_process";
|
||||||
import { mkdirSync } from "fs";
|
import { mkdirSync } from "fs";
|
||||||
|
import { join } from "path";
|
||||||
|
|
||||||
|
import BuildContext from "./context";
|
||||||
|
|
||||||
interface BuildInfo {
|
interface BuildInfo {
|
||||||
specPath: string;
|
specPath: string;
|
||||||
@@ -27,6 +28,9 @@ export default function buildSwagger({ baseDir, gitRootDir }: BuildContext) {
|
|||||||
const absSpecPath = join(gitRootDir, specPath);
|
const absSpecPath = join(gitRootDir, specPath);
|
||||||
const targetDir = join(baseDir, outDir);
|
const targetDir = join(baseDir, outDir);
|
||||||
mkdirSync(targetDir, { recursive: true });
|
mkdirSync(targetDir, { recursive: true });
|
||||||
execSync(`pnpm redocly build-docs ${absSpecPath} -o ${targetDir}/index.html`, { stdio: "inherit" });
|
execSync(
|
||||||
|
`pnpm redocly build-docs ${absSpecPath} -o ${targetDir}/index.html`,
|
||||||
|
{ stdio: "inherit" }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.base.json",
|
"extends": "../../tsconfig.base.json",
|
||||||
"include": [],
|
"include": [
|
||||||
|
"scripts/**/*.ts"
|
||||||
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../server"
|
"path": "../server"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
"src/backend_script_entrypoint.ts"
|
"src/backend_script_entrypoint.ts"
|
||||||
],
|
],
|
||||||
|
"tsconfig": "tsconfig.app.json",
|
||||||
"plugin": [
|
"plugin": [
|
||||||
"typedoc-plugin-missing-exports"
|
"typedoc-plugin-missing-exports"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
"src/frontend_script_entrypoint.ts"
|
"src/frontend_script_entrypoint.ts"
|
||||||
],
|
],
|
||||||
|
"tsconfig": "tsconfig.app.json",
|
||||||
"plugin": [
|
"plugin": [
|
||||||
"typedoc-plugin-missing-exports"
|
"typedoc-plugin-missing-exports"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -13,13 +13,14 @@
|
|||||||
<body id="trilium-app">
|
<body id="trilium-app">
|
||||||
<noscript>Trilium requires JavaScript to be enabled.</noscript>
|
<noscript>Trilium requires JavaScript to be enabled.</noscript>
|
||||||
|
|
||||||
|
<div id="context-menu-cover"></div>
|
||||||
<div class="dropdown-menu dropdown-menu-sm" id="context-menu-container" style="display: none"></div>
|
<div class="dropdown-menu dropdown-menu-sm" id="context-menu-container" style="display: none"></div>
|
||||||
|
|
||||||
<!-- Required to match the PWA's top bar color with the theme -->
|
<!-- Required to match the PWA's top bar color with the theme -->
|
||||||
<!-- This works even when the user directly changes --root-background in CSS -->
|
<!-- This works even when the user directly changes --root-background in CSS -->
|
||||||
<div id="background-color-tracker" style="position: absolute; visibility: hidden; color: var(--root-background); transition: color 1ms;"></div>
|
<div id="background-color-tracker" style="position: absolute; visibility: hidden; color: var(--root-background); transition: color 1ms;"></div>
|
||||||
|
|
||||||
<script src="./index.ts" type="module"></script>
|
<script src="./src/index.ts" type="module"></script>
|
||||||
|
|
||||||
<!-- Required for correct loading of scripts in Electron -->
|
<!-- Required for correct loading of scripts in Electron -->
|
||||||
<script>
|
<script>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@triliumnext/client",
|
"name": "@triliumnext/client",
|
||||||
"version": "0.101.3",
|
"version": "0.102.1",
|
||||||
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
|
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
@@ -16,71 +16,79 @@
|
|||||||
"circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
|
"circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@algolia/autocomplete-js": "1.19.6",
|
||||||
"@excalidraw/excalidraw": "0.18.0",
|
"@excalidraw/excalidraw": "0.18.0",
|
||||||
"@fullcalendar/core": "6.1.20",
|
"@fullcalendar/core": "6.1.20",
|
||||||
"@fullcalendar/daygrid": "6.1.20",
|
"@fullcalendar/daygrid": "6.1.20",
|
||||||
"@fullcalendar/interaction": "6.1.20",
|
"@fullcalendar/interaction": "6.1.20",
|
||||||
"@fullcalendar/list": "6.1.20",
|
"@fullcalendar/list": "6.1.20",
|
||||||
"@fullcalendar/multimonth": "6.1.20",
|
"@fullcalendar/multimonth": "6.1.20",
|
||||||
|
"@fullcalendar/rrule": "6.1.20",
|
||||||
"@fullcalendar/timegrid": "6.1.20",
|
"@fullcalendar/timegrid": "6.1.20",
|
||||||
"@maplibre/maplibre-gl-leaflet": "0.1.3",
|
"@maplibre/maplibre-gl-leaflet": "0.1.3",
|
||||||
"@mermaid-js/layout-elk": "0.2.0",
|
"@mermaid-js/layout-elk": "0.2.1",
|
||||||
"@mind-elixir/node-menu": "5.0.1",
|
"@mind-elixir/node-menu": "5.0.1",
|
||||||
"@popperjs/core": "2.11.8",
|
"@popperjs/core": "2.11.8",
|
||||||
"@preact/signals": "2.5.1",
|
"@preact/signals": "2.8.2",
|
||||||
"@triliumnext/ckeditor5": "workspace:*",
|
"@triliumnext/ckeditor5": "workspace:*",
|
||||||
"@triliumnext/codemirror": "workspace:*",
|
"@triliumnext/codemirror": "workspace:*",
|
||||||
"@triliumnext/commons": "workspace:*",
|
"@triliumnext/commons": "workspace:*",
|
||||||
"@triliumnext/highlightjs": "workspace:*",
|
"@triliumnext/highlightjs": "workspace:*",
|
||||||
"@triliumnext/share-theme": "workspace:*",
|
"@triliumnext/share-theme": "workspace:*",
|
||||||
"@triliumnext/split.js": "workspace:*",
|
"@triliumnext/split.js": "workspace:*",
|
||||||
"@zumer/snapdom": "2.0.1",
|
"@univerjs/preset-sheets-conditional-formatting": "0.18.0",
|
||||||
"autocomplete.js": "0.38.1",
|
"@univerjs/preset-sheets-core": "0.18.0",
|
||||||
|
"@univerjs/preset-sheets-data-validation": "0.18.0",
|
||||||
|
"@univerjs/preset-sheets-filter": "0.18.0",
|
||||||
|
"@univerjs/preset-sheets-find-replace": "0.18.0",
|
||||||
|
"@univerjs/preset-sheets-note": "0.18.0",
|
||||||
|
"@univerjs/preset-sheets-sort": "0.18.0",
|
||||||
|
"@univerjs/presets": "0.18.0",
|
||||||
|
"@zumer/snapdom": "2.5.0",
|
||||||
"bootstrap": "5.3.8",
|
"bootstrap": "5.3.8",
|
||||||
"boxicons": "2.1.4",
|
"boxicons": "2.1.4",
|
||||||
"clsx": "2.1.1",
|
"clsx": "2.1.1",
|
||||||
"color": "5.0.3",
|
"color": "5.0.3",
|
||||||
"debounce": "3.0.0",
|
"debounce": "3.0.0",
|
||||||
"draggabilly": "3.0.0",
|
"draggabilly": "3.0.0",
|
||||||
"force-graph": "1.51.0",
|
"force-graph": "1.51.2",
|
||||||
"globals": "17.0.0",
|
"globals": "17.4.0",
|
||||||
"i18next": "25.7.4",
|
"i18next": "25.10.10",
|
||||||
"i18next-http-backend": "3.0.2",
|
"i18next-http-backend": "3.0.2",
|
||||||
"jquery": "3.7.1",
|
"jquery": "4.0.0",
|
||||||
"jquery.fancytree": "2.38.5",
|
"jquery.fancytree": "2.38.5",
|
||||||
"jsplumb": "2.15.6",
|
"jsplumb": "2.15.6",
|
||||||
"katex": "0.16.27",
|
"katex": "0.16.43",
|
||||||
"knockout": "3.5.1",
|
|
||||||
"leaflet": "1.9.4",
|
"leaflet": "1.9.4",
|
||||||
"leaflet-gpx": "2.2.0",
|
"leaflet-gpx": "2.2.0",
|
||||||
"mark.js": "8.11.1",
|
"mark.js": "8.11.1",
|
||||||
"marked": "17.0.1",
|
"marked": "17.0.5",
|
||||||
"mermaid": "11.12.2",
|
"mermaid": "11.13.0",
|
||||||
"mind-elixir": "5.5.0",
|
"mind-elixir": "5.9.3",
|
||||||
"normalize.css": "8.0.1",
|
"normalize.css": "8.0.1",
|
||||||
"panzoom": "9.4.3",
|
"panzoom": "9.4.4",
|
||||||
"preact": "10.28.2",
|
"preact": "10.29.0",
|
||||||
"react-i18next": "16.5.3",
|
"react-i18next": "16.6.6",
|
||||||
"react-window": "2.2.5",
|
"react-window": "2.2.7",
|
||||||
"reveal.js": "5.2.1",
|
"reveal.js": "6.0.0",
|
||||||
|
"rrule": "2.8.1",
|
||||||
"svg-pan-zoom": "3.6.2",
|
"svg-pan-zoom": "3.6.2",
|
||||||
"tabulator-tables": "6.3.1",
|
"tabulator-tables": "6.4.0",
|
||||||
"vanilla-js-wheel-zoom": "9.0.4"
|
"vanilla-js-wheel-zoom": "9.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ckeditor/ckeditor5-inspector": "5.0.0",
|
"@ckeditor/ckeditor5-inspector": "5.0.0",
|
||||||
"@prefresh/vite": "2.4.11",
|
"@prefresh/vite": "2.4.12",
|
||||||
"@types/bootstrap": "5.2.10",
|
"@types/bootstrap": "5.2.10",
|
||||||
"@types/jquery": "3.5.33",
|
"@types/jquery": "4.0.0",
|
||||||
"@types/leaflet": "1.9.21",
|
"@types/leaflet": "1.9.21",
|
||||||
"@types/leaflet-gpx": "1.3.8",
|
"@types/leaflet-gpx": "1.3.8",
|
||||||
"@types/mark.js": "8.11.12",
|
"@types/mark.js": "8.11.12",
|
||||||
"@types/reveal.js": "5.2.2",
|
|
||||||
"@types/tabulator-tables": "6.3.1",
|
"@types/tabulator-tables": "6.3.1",
|
||||||
"copy-webpack-plugin": "13.0.1",
|
"copy-webpack-plugin": "14.0.0",
|
||||||
"happy-dom": "20.1.0",
|
"happy-dom": "20.8.9",
|
||||||
"lightningcss": "1.30.2",
|
"lightningcss": "1.32.0",
|
||||||
"script-loader": "0.7.2",
|
"script-loader": "0.7.2",
|
||||||
"vite-plugin-static-copy": "3.1.4"
|
"vite-plugin-static-copy": "3.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { CKTextEditor } from "@triliumnext/ckeditor5";
|
import type { CKTextEditor } from "@triliumnext/ckeditor5";
|
||||||
import type CodeMirror from "@triliumnext/codemirror";
|
import type CodeMirror from "@triliumnext/codemirror";
|
||||||
import { SqlExecuteResults } from "@triliumnext/commons";
|
import { SqlExecuteResponse } from "@triliumnext/commons";
|
||||||
import type { NativeImage, TouchBar } from "electron";
|
import type { NativeImage, TouchBar } from "electron";
|
||||||
import { ColumnComponent } from "tabulator-tables";
|
import { ColumnComponent } from "tabulator-tables";
|
||||||
|
|
||||||
@@ -101,8 +101,6 @@ export type CommandMappings = {
|
|||||||
showRevisions: CommandData & {
|
showRevisions: CommandData & {
|
||||||
noteId?: string | null;
|
noteId?: string | null;
|
||||||
};
|
};
|
||||||
showLlmChat: CommandData;
|
|
||||||
createAiChat: CommandData;
|
|
||||||
showOptions: CommandData & {
|
showOptions: CommandData & {
|
||||||
section: string;
|
section: string;
|
||||||
};
|
};
|
||||||
@@ -410,7 +408,7 @@ type EventMappings = {
|
|||||||
addNewLabel: CommandData;
|
addNewLabel: CommandData;
|
||||||
addNewRelation: CommandData;
|
addNewRelation: CommandData;
|
||||||
sqlQueryResults: CommandData & {
|
sqlQueryResults: CommandData & {
|
||||||
results: SqlExecuteResults;
|
response: SqlExecuteResponse;
|
||||||
};
|
};
|
||||||
readOnlyTemporarilyDisabled: {
|
readOnlyTemporarilyDisabled: {
|
||||||
noteContext: NoteContext;
|
noteContext: NoteContext;
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import utils from "../services/utils.js";
|
import { CreateChildrenResponse, SqlExecuteResponse } from "@triliumnext/commons";
|
||||||
|
|
||||||
|
import { closeAllHeadlessAutocompletes } from "../services/autocomplete_core.js";
|
||||||
|
import bundleService from "../services/bundle.js";
|
||||||
import dateNoteService from "../services/date_notes.js";
|
import dateNoteService from "../services/date_notes.js";
|
||||||
|
import froca from "../services/froca.js";
|
||||||
|
import { t } from "../services/i18n.js";
|
||||||
|
import linkService from "../services/link.js";
|
||||||
import protectedSessionHolder from "../services/protected_session_holder.js";
|
import protectedSessionHolder from "../services/protected_session_holder.js";
|
||||||
import server from "../services/server.js";
|
import server from "../services/server.js";
|
||||||
|
import toastService from "../services/toast.js";
|
||||||
|
import utils from "../services/utils.js";
|
||||||
|
import ws from "../services/ws.js";
|
||||||
import appContext, { type NoteCommandData } from "./app_context.js";
|
import appContext, { type NoteCommandData } from "./app_context.js";
|
||||||
import Component from "./component.js";
|
import Component from "./component.js";
|
||||||
import toastService from "../services/toast.js";
|
|
||||||
import ws from "../services/ws.js";
|
|
||||||
import bundleService from "../services/bundle.js";
|
|
||||||
import froca from "../services/froca.js";
|
|
||||||
import linkService from "../services/link.js";
|
|
||||||
import { t } from "../services/i18n.js";
|
|
||||||
import { CreateChildrenResponse, SqlExecuteResponse } from "@triliumnext/commons";
|
|
||||||
|
|
||||||
export default class Entrypoints extends Component {
|
export default class Entrypoints extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -187,13 +189,8 @@ export default class Entrypoints extends Component {
|
|||||||
} else if (note.mime.endsWith("env=backend")) {
|
} else if (note.mime.endsWith("env=backend")) {
|
||||||
await server.post(`script/run/${note.noteId}`);
|
await server.post(`script/run/${note.noteId}`);
|
||||||
} else if (note.mime === "text/x-sqlite;schema=trilium") {
|
} else if (note.mime === "text/x-sqlite;schema=trilium") {
|
||||||
const resp = await server.post<SqlExecuteResponse>(`sql/execute/${note.noteId}`);
|
const response = await server.post<SqlExecuteResponse>(`sql/execute/${note.noteId}`);
|
||||||
|
await appContext.triggerEvent("sqlQueryResults", { ntxId, response });
|
||||||
if (!resp.success) {
|
|
||||||
toastService.showError(t("entrypoints.sql-error", { message: resp.error }));
|
|
||||||
}
|
|
||||||
|
|
||||||
await appContext.triggerEvent("sqlQueryResults", { ntxId: ntxId, results: resp.results });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toastService.showMessage(t("entrypoints.note-executed"));
|
toastService.showMessage(t("entrypoints.note-executed"));
|
||||||
@@ -201,7 +198,7 @@ export default class Entrypoints extends Component {
|
|||||||
|
|
||||||
hideAllPopups() {
|
hideAllPopups() {
|
||||||
if (utils.isDesktop()) {
|
if (utils.isDesktop()) {
|
||||||
$(".aa-input").autocomplete("close");
|
closeAllHeadlessAutocompletes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -381,6 +381,10 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
|||||||
|
|
||||||
// Collections must always display a note list, even if no children.
|
// Collections must always display a note list, even if no children.
|
||||||
if (note.type === "book") {
|
if (note.type === "book") {
|
||||||
|
if (note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const viewType = note.getLabelValue("viewType") ?? "grid";
|
const viewType = note.getLabelValue("viewType") ?? "grid";
|
||||||
if (!["list", "grid"].includes(viewType)) {
|
if (!["list", "grid"].includes(viewType)) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import dateNoteService from "../services/date_notes.js";
|
import dateNoteService from "../services/date_notes.js";
|
||||||
import froca from "../services/froca.js";
|
import froca from "../services/froca.js";
|
||||||
import noteCreateService from "../services/note_create.js";
|
|
||||||
import openService from "../services/open.js";
|
import openService from "../services/open.js";
|
||||||
import options from "../services/options.js";
|
import options from "../services/options.js";
|
||||||
import protectedSessionService from "../services/protected_session.js";
|
import protectedSessionService from "../services/protected_session.js";
|
||||||
import toastService from "../services/toast.js";
|
|
||||||
import treeService from "../services/tree.js";
|
import treeService from "../services/tree.js";
|
||||||
import utils, { openInReusableSplit } from "../services/utils.js";
|
import utils, { openInReusableSplit } from "../services/utils.js";
|
||||||
import appContext, { type CommandListenerData } from "./app_context.js";
|
import appContext, { type CommandListenerData } from "./app_context.js";
|
||||||
@@ -248,34 +246,4 @@ export default class RootCommandExecutor extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async createAiChatCommand() {
|
|
||||||
try {
|
|
||||||
// Create a new AI Chat note at the root level
|
|
||||||
const rootNoteId = "root";
|
|
||||||
|
|
||||||
const result = await noteCreateService.createNote(rootNoteId, {
|
|
||||||
title: "New AI Chat",
|
|
||||||
type: "aiChat",
|
|
||||||
content: JSON.stringify({
|
|
||||||
messages: [],
|
|
||||||
title: "New AI Chat"
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result.note) {
|
|
||||||
toastService.showError("Failed to create AI Chat note");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await appContext.tabManager.openTabWithNoteWithHoisting(result.note.noteId, {
|
|
||||||
activate: true
|
|
||||||
});
|
|
||||||
|
|
||||||
toastService.showMessage("Created new AI Chat note");
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error("Error creating AI Chat note:", e);
|
|
||||||
toastService.showError(`Failed to create AI Chat note: ${(e as Error).message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import Component from "./component.js";
|
|
||||||
import SpacedUpdate from "../services/spaced_update.js";
|
|
||||||
import server from "../services/server.js";
|
|
||||||
import options from "../services/options.js";
|
|
||||||
import froca from "../services/froca.js";
|
|
||||||
import treeService from "../services/tree.js";
|
|
||||||
import NoteContext from "./note_context.js";
|
|
||||||
import appContext from "./app_context.js";
|
|
||||||
import Mutex from "../utils/mutex.js";
|
|
||||||
import linkService from "../services/link.js";
|
|
||||||
import type { EventData } from "./app_context.js";
|
|
||||||
import type FNote from "../entities/fnote.js";
|
import type FNote from "../entities/fnote.js";
|
||||||
|
import { closeAllHeadlessAutocompletes } from "../services/autocomplete_core.js";
|
||||||
|
import froca from "../services/froca.js";
|
||||||
|
import linkService from "../services/link.js";
|
||||||
|
import options from "../services/options.js";
|
||||||
|
import server from "../services/server.js";
|
||||||
|
import SpacedUpdate from "../services/spaced_update.js";
|
||||||
|
import treeService from "../services/tree.js";
|
||||||
|
import Mutex from "../utils/mutex.js";
|
||||||
|
import type { EventData } from "./app_context.js";
|
||||||
|
import appContext from "./app_context.js";
|
||||||
|
import Component from "./component.js";
|
||||||
|
import NoteContext from "./note_context.js";
|
||||||
|
|
||||||
interface TabState {
|
interface TabState {
|
||||||
contexts: NoteContext[];
|
contexts: NoteContext[];
|
||||||
@@ -429,10 +430,7 @@ export default class TabManager extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// close dangling autocompletes after closing the tab
|
// close dangling autocompletes after closing the tab
|
||||||
const $autocompleteEl = $(".aa-input");
|
closeAllHeadlessAutocompletes();
|
||||||
if ("autocomplete" in $autocompleteEl) {
|
|
||||||
$autocompleteEl.autocomplete("close");
|
|
||||||
}
|
|
||||||
|
|
||||||
// close dangling tooltips
|
// close dangling tooltips
|
||||||
$("body > div.tooltip").remove();
|
$("body > div.tooltip").remove();
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import "autocomplete.js/index_jquery.js";
|
|
||||||
|
|
||||||
import type ElectronRemote from "@electron/remote";
|
import type ElectronRemote from "@electron/remote";
|
||||||
import type Electron from "electron";
|
import type Electron from "electron";
|
||||||
|
|
||||||
@@ -46,10 +44,6 @@ if (utils.isElectron()) {
|
|||||||
electronContextMenu.setupContextMenu();
|
electronContextMenu.setupContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utils.isPWA()) {
|
|
||||||
initPWATopbarColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
function initOnElectron() {
|
function initOnElectron() {
|
||||||
const electron: typeof Electron = utils.dynamicRequire("electron");
|
const electron: typeof Electron = utils.dynamicRequire("electron");
|
||||||
electron.ipcRenderer.on("globalShortcut", async (event, actionName) => appContext.triggerCommand(actionName));
|
electron.ipcRenderer.on("globalShortcut", async (event, actionName) => appContext.triggerCommand(actionName));
|
||||||
@@ -99,15 +93,22 @@ function initFullScreenDetection(currentWindow: Electron.BrowserWindow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initTransparencyEffects(style: CSSStyleDeclaration, currentWindow: Electron.BrowserWindow) {
|
function initTransparencyEffects(style: CSSStyleDeclaration, currentWindow: Electron.BrowserWindow) {
|
||||||
|
const material = style.getPropertyValue("--background-material").trim();
|
||||||
if (window.glob.platform === "win32") {
|
if (window.glob.platform === "win32") {
|
||||||
const material = style.getPropertyValue("--background-material");
|
|
||||||
// TriliumNextTODO: find a nicer way to make TypeScript happy – unfortunately TS did not like Array.includes here
|
|
||||||
const bgMaterialOptions = ["auto", "none", "mica", "acrylic", "tabbed"] as const;
|
const bgMaterialOptions = ["auto", "none", "mica", "acrylic", "tabbed"] as const;
|
||||||
const foundBgMaterialOption = bgMaterialOptions.find((bgMaterialOption) => material === bgMaterialOption);
|
const foundBgMaterialOption = bgMaterialOptions.find((bgMaterialOption) => material === bgMaterialOption);
|
||||||
if (foundBgMaterialOption) {
|
if (foundBgMaterialOption) {
|
||||||
currentWindow.setBackgroundMaterial(foundBgMaterialOption);
|
currentWindow.setBackgroundMaterial(foundBgMaterialOption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window.glob.platform === "darwin") {
|
||||||
|
const bgMaterialOptions = [ "popover", "tooltip", "titlebar", "selection", "menu", "sidebar", "header", "sheet", "window", "hud", "fullscreen-ui", "content", "under-window", "under-page" ] as const;
|
||||||
|
const foundBgMaterialOption = bgMaterialOptions.find((bgMaterialOption) => material === bgMaterialOption);
|
||||||
|
if (foundBgMaterialOption) {
|
||||||
|
currentWindow.setVibrancy(foundBgMaterialOption);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,20 +128,3 @@ function initDarkOrLightMode(style: CSSStyleDeclaration) {
|
|||||||
const { nativeTheme } = utils.dynamicRequire("@electron/remote") as typeof ElectronRemote;
|
const { nativeTheme } = utils.dynamicRequire("@electron/remote") as typeof ElectronRemote;
|
||||||
nativeTheme.themeSource = themeSource;
|
nativeTheme.themeSource = themeSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
function initPWATopbarColor() {
|
|
||||||
const tracker = $("#background-color-tracker");
|
|
||||||
|
|
||||||
if (tracker.length) {
|
|
||||||
const applyThemeColor = () => {
|
|
||||||
let meta = $("meta[name='theme-color']");
|
|
||||||
if (!meta.length) {
|
|
||||||
meta = $(`<meta name="theme-color">`).appendTo($("head"));
|
|
||||||
}
|
|
||||||
meta.attr("content", tracker.css("color"));
|
|
||||||
};
|
|
||||||
|
|
||||||
tracker.on("transitionend", applyThemeColor);
|
|
||||||
applyThemeColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { MIME_TYPES_DICT } from "@triliumnext/commons";
|
import { getNoteIcon } from "@triliumnext/commons";
|
||||||
|
|
||||||
import cssClassManager from "../services/css_class_manager.js";
|
import cssClassManager from "../services/css_class_manager.js";
|
||||||
import type { Froca } from "../services/froca-interface.js";
|
import type { Froca } from "../services/froca-interface.js";
|
||||||
@@ -13,31 +13,12 @@ import type { AttributeType, default as FAttribute } from "./fattribute.js";
|
|||||||
const LABEL = "label";
|
const LABEL = "label";
|
||||||
const RELATION = "relation";
|
const RELATION = "relation";
|
||||||
|
|
||||||
export const NOTE_TYPE_ICONS = {
|
|
||||||
file: "bx bx-file",
|
|
||||||
image: "bx bx-image",
|
|
||||||
code: "bx bx-code",
|
|
||||||
render: "bx bx-extension",
|
|
||||||
search: "bx bx-file-find",
|
|
||||||
relationMap: "bx bxs-network-chart",
|
|
||||||
book: "bx bx-book",
|
|
||||||
noteMap: "bx bxs-network-chart",
|
|
||||||
mermaid: "bx bx-selection",
|
|
||||||
canvas: "bx bx-pen",
|
|
||||||
webView: "bx bx-globe-alt",
|
|
||||||
launcher: "bx bx-link",
|
|
||||||
doc: "bx bxs-file-doc",
|
|
||||||
contentWidget: "bx bxs-widget",
|
|
||||||
mindMap: "bx bx-sitemap",
|
|
||||||
aiChat: "bx bx-bot"
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There are many different Note types, some of which are entirely opaque to the
|
* There are many different Note types, some of which are entirely opaque to the
|
||||||
* end user. Those types should be used only for checking against, they are
|
* end user. Those types should be used only for checking against, they are
|
||||||
* not for direct use.
|
* not for direct use.
|
||||||
*/
|
*/
|
||||||
export type NoteType = "file" | "image" | "search" | "noteMap" | "launcher" | "doc" | "contentWidget" | "text" | "relationMap" | "render" | "canvas" | "mermaid" | "book" | "webView" | "code" | "mindMap" | "aiChat";
|
export type NoteType = "file" | "image" | "search" | "noteMap" | "launcher" | "doc" | "contentWidget" | "text" | "relationMap" | "render" | "canvas" | "mermaid" | "book" | "webView" | "code" | "mindMap" | "spreadsheet";
|
||||||
|
|
||||||
export interface NotePathRecord {
|
export interface NotePathRecord {
|
||||||
isArchived: boolean;
|
isArchived: boolean;
|
||||||
@@ -582,32 +563,18 @@ export default class FNote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getIcon() {
|
getIcon() {
|
||||||
return `tn-icon ${this.#getIconInternal()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
#getIconInternal() {
|
|
||||||
const iconClassLabels = this.getLabels("iconClass");
|
const iconClassLabels = this.getLabels("iconClass");
|
||||||
const workspaceIconClass = this.getWorkspaceIconClass();
|
const workspaceIconClass = this.getWorkspaceIconClass();
|
||||||
|
|
||||||
if (iconClassLabels && iconClassLabels.length > 0) {
|
const icon = getNoteIcon({
|
||||||
return iconClassLabels[0].value;
|
noteId: this.noteId,
|
||||||
} else if (workspaceIconClass) {
|
type: this.type,
|
||||||
return workspaceIconClass;
|
mime: this.mime,
|
||||||
} else if (this.noteId === "root") {
|
iconClass: iconClassLabels.length > 0 ? iconClassLabels[0].value : undefined,
|
||||||
return "bx bx-home-alt-2";
|
workspaceIconClass,
|
||||||
}
|
isFolder: this.isFolder.bind(this)
|
||||||
if (this.noteId === "_share") {
|
});
|
||||||
return "bx bx-share-alt";
|
return `tn-icon ${icon}`;
|
||||||
} else if (this.type === "text") {
|
|
||||||
if (this.isFolder()) {
|
|
||||||
return "bx bx-folder";
|
|
||||||
}
|
|
||||||
return "bx bx-note";
|
|
||||||
} else if (this.type === "code") {
|
|
||||||
const correspondingMimeType = MIME_TYPES_DICT.find(m => m.mime === this.mime);
|
|
||||||
return correspondingMimeType?.icon ?? NOTE_TYPE_ICONS.code;
|
|
||||||
}
|
|
||||||
return NOTE_TYPE_ICONS[this.type];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getColorClass() {
|
getColorClass() {
|
||||||
@@ -733,6 +700,15 @@ export default class FNote {
|
|||||||
return this.hasAttribute(LABEL, name);
|
return this.hasAttribute(LABEL, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if the note has a label with the given name (same as {@link hasOwnedLabel}), or it has a label with the `disabled:` prefix (for example due to a safe import).
|
||||||
|
* @param name the name of the label to look for.
|
||||||
|
* @returns `true` if the label exists, or its version with the `disabled:` prefix.
|
||||||
|
*/
|
||||||
|
hasLabelOrDisabled(name: string) {
|
||||||
|
return this.hasLabel(name) || this.hasLabel(`disabled:${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name - label name
|
* @param name - label name
|
||||||
* @returns true if label exists (including inherited) and does not have "false" value.
|
* @returns true if label exists (including inherited) and does not have "false" value.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ async function initJQuery() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function setupGlob() {
|
async function setupGlob() {
|
||||||
const response = await fetch(`/bootstrap${window.location.search}`);
|
const response = await fetch(`./bootstrap${window.location.search}`);
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
|
|
||||||
window.global = globalThis; /* fixes https://github.com/webpack/webpack/issues/10035 */
|
window.global = globalThis; /* fixes https://github.com/webpack/webpack/issues/10035 */
|
||||||
@@ -39,22 +39,25 @@ async function loadBootstrapCss() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadStylesheets() {
|
function loadStylesheets() {
|
||||||
const { assetPath, themeCssUrl, themeUseNextAsBase } = window.glob;
|
const { device, assetPath, themeCssUrl, themeUseNextAsBase } = window.glob;
|
||||||
|
|
||||||
const cssToLoad: string[] = [];
|
const cssToLoad: string[] = [];
|
||||||
cssToLoad.push(`${assetPath}/stylesheets/ckeditor-theme.css`);
|
if (device !== "print") {
|
||||||
cssToLoad.push(`api/fonts`);
|
cssToLoad.push(`${assetPath}/stylesheets/ckeditor-theme.css`);
|
||||||
cssToLoad.push(`${assetPath}/stylesheets/theme-light.css`);
|
cssToLoad.push(`api/fonts`);
|
||||||
if (themeCssUrl) {
|
cssToLoad.push(`${assetPath}/stylesheets/theme-light.css`);
|
||||||
cssToLoad.push(themeCssUrl);
|
if (themeCssUrl) {
|
||||||
|
cssToLoad.push(themeCssUrl);
|
||||||
|
}
|
||||||
|
if (themeUseNextAsBase === "next") {
|
||||||
|
cssToLoad.push(`${assetPath}/stylesheets/theme-next.css`);
|
||||||
|
} else if (themeUseNextAsBase === "next-dark") {
|
||||||
|
cssToLoad.push(`${assetPath}/stylesheets/theme-next-dark.css`);
|
||||||
|
} else if (themeUseNextAsBase === "next-light") {
|
||||||
|
cssToLoad.push(`${assetPath}/stylesheets/theme-next-light.css`);
|
||||||
|
}
|
||||||
|
cssToLoad.push(`${assetPath}/stylesheets/style.css`);
|
||||||
}
|
}
|
||||||
if (themeUseNextAsBase === "next") {
|
|
||||||
cssToLoad.push(`${assetPath}/stylesheets/theme-next.css`);
|
|
||||||
} else if (themeUseNextAsBase === "next-dark") {
|
|
||||||
cssToLoad.push(`${assetPath}/stylesheets/theme-next-dark.css`);
|
|
||||||
} else if (themeUseNextAsBase === "next-light") {
|
|
||||||
cssToLoad.push(`${assetPath}/stylesheets/theme-next-light.css`);
|
|
||||||
}
|
|
||||||
cssToLoad.push(`${assetPath}/stylesheets/style.css`);
|
|
||||||
|
|
||||||
for (const href of cssToLoad) {
|
for (const href of cssToLoad) {
|
||||||
const linkEl = document.createElement("link");
|
const linkEl = document.createElement("link");
|
||||||
@@ -91,10 +94,17 @@ function setBodyAttributes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadScripts() {
|
async function loadScripts() {
|
||||||
if (glob.device === "mobile") {
|
switch (glob.device) {
|
||||||
await import("./mobile.js");
|
case "mobile":
|
||||||
} else {
|
await import("./mobile.js");
|
||||||
await import("./desktop.js");
|
break;
|
||||||
|
case "print":
|
||||||
|
await import("./print.js");
|
||||||
|
break;
|
||||||
|
case "desktop":
|
||||||
|
default:
|
||||||
|
await import("./desktop.js");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,8 +46,6 @@ import ScrollPadding from "../widgets/scroll_padding.js";
|
|||||||
import SearchResult from "../widgets/search_result.jsx";
|
import SearchResult from "../widgets/search_result.jsx";
|
||||||
import SharedInfo from "../widgets/shared_info.jsx";
|
import SharedInfo from "../widgets/shared_info.jsx";
|
||||||
import RightPanelContainer from "../widgets/sidebar/RightPanelContainer.jsx";
|
import RightPanelContainer from "../widgets/sidebar/RightPanelContainer.jsx";
|
||||||
import SqlResults from "../widgets/sql_result.js";
|
|
||||||
import SqlTableSchemas from "../widgets/sql_table_schemas.js";
|
|
||||||
import TabRowWidget from "../widgets/tab_row.js";
|
import TabRowWidget from "../widgets/tab_row.js";
|
||||||
import TabHistoryNavigationButtons from "../widgets/TabHistoryNavigationButtons.jsx";
|
import TabHistoryNavigationButtons from "../widgets/TabHistoryNavigationButtons.jsx";
|
||||||
import TitleBarButtons from "../widgets/title_bar_buttons.jsx";
|
import TitleBarButtons from "../widgets/title_bar_buttons.jsx";
|
||||||
@@ -163,11 +161,9 @@ export default class DesktopLayout {
|
|||||||
.child(<SharedInfo />)
|
.child(<SharedInfo />)
|
||||||
)
|
)
|
||||||
.optChild(!isNewLayout, <PromotedAttributes />)
|
.optChild(!isNewLayout, <PromotedAttributes />)
|
||||||
.child(<SqlTableSchemas />)
|
|
||||||
.child(<NoteDetail />)
|
.child(<NoteDetail />)
|
||||||
.child(<NoteList media="screen" />)
|
.child(<NoteList media="screen" />)
|
||||||
.child(<SearchResult />)
|
.child(<SearchResult />)
|
||||||
.child(<SqlResults />)
|
|
||||||
.child(<ScrollPadding />)
|
.child(<ScrollPadding />)
|
||||||
)
|
)
|
||||||
.child(<ApiLog />)
|
.child(<ApiLog />)
|
||||||
|
|||||||
76
apps/client/src/layouts/mobile_layout.css
Normal file
76
apps/client/src/layouts/mobile_layout.css
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#background-color-tracker {
|
||||||
|
color: var(--main-background-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.keyboard-shortcut,
|
||||||
|
kbd {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
font-size: larger;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1.25em;
|
||||||
|
padding-inline-start: 0.5em;
|
||||||
|
padding-inline-end: 0.5em;
|
||||||
|
color: var(--main-text-color);
|
||||||
|
}
|
||||||
|
.quick-search {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.quick-search .dropdown-menu {
|
||||||
|
max-width: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #region Tree */
|
||||||
|
.tree-wrapper {
|
||||||
|
max-height: 100%;
|
||||||
|
margin-top: 0px;
|
||||||
|
overflow-y: auto;
|
||||||
|
contain: content;
|
||||||
|
padding-inline-start: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fancytree-title {
|
||||||
|
margin-inline-start: 0.6em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fancytree-node {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.fancytree-expander {
|
||||||
|
width: 24px !important;
|
||||||
|
margin-inline-end: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fancytree-loading span.fancytree-expander {
|
||||||
|
width: 24px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fancytree-loading span.fancytree-expander:after {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin-top: 4px;
|
||||||
|
border-width: 2px;
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-wrapper .collapse-tree-button,
|
||||||
|
.tree-wrapper .scroll-to-active-note-button,
|
||||||
|
.tree-wrapper .tree-settings-button {
|
||||||
|
position: fixed;
|
||||||
|
margin-inline-end: 16px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-wrapper .unhoist-button {
|
||||||
|
font-size: 200%;
|
||||||
|
}
|
||||||
|
/* #endregion */
|
||||||
@@ -1,128 +1,38 @@
|
|||||||
|
import "./mobile_layout.css";
|
||||||
|
|
||||||
import type AppContext from "../components/app_context.js";
|
import type AppContext from "../components/app_context.js";
|
||||||
import GlobalMenuWidget from "../widgets/buttons/global_menu.js";
|
import GlobalMenuWidget from "../widgets/buttons/global_menu.js";
|
||||||
import CloseZenModeButton from "../widgets/close_zen_button.js";
|
import CloseZenModeButton from "../widgets/close_zen_button.js";
|
||||||
import NoteList from "../widgets/collections/NoteList.jsx";
|
import NoteList from "../widgets/collections/NoteList.jsx";
|
||||||
import ContentHeader from "../widgets/containers/content_header.js";
|
|
||||||
import FlexContainer from "../widgets/containers/flex_container.js";
|
import FlexContainer from "../widgets/containers/flex_container.js";
|
||||||
import RootContainer from "../widgets/containers/root_container.js";
|
import RootContainer from "../widgets/containers/root_container.js";
|
||||||
import ScrollingContainer from "../widgets/containers/scrolling_container.js";
|
import ScrollingContainer from "../widgets/containers/scrolling_container.js";
|
||||||
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
|
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
|
||||||
import FloatingButtons from "../widgets/FloatingButtons.jsx";
|
import FindWidget from "../widgets/find.js";
|
||||||
import { MOBILE_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
|
|
||||||
import LauncherContainer from "../widgets/launch_bar/LauncherContainer.jsx";
|
import LauncherContainer from "../widgets/launch_bar/LauncherContainer.jsx";
|
||||||
|
import InlineTitle from "../widgets/layout/InlineTitle.jsx";
|
||||||
|
import NoteBadges from "../widgets/layout/NoteBadges.jsx";
|
||||||
|
import NoteTitleActions from "../widgets/layout/NoteTitleActions.jsx";
|
||||||
import MobileDetailMenu from "../widgets/mobile_widgets/mobile_detail_menu.js";
|
import MobileDetailMenu from "../widgets/mobile_widgets/mobile_detail_menu.js";
|
||||||
import ScreenContainer from "../widgets/mobile_widgets/screen_container.js";
|
import ScreenContainer from "../widgets/mobile_widgets/screen_container.js";
|
||||||
import SidebarContainer from "../widgets/mobile_widgets/sidebar_container.js";
|
import SidebarContainer from "../widgets/mobile_widgets/sidebar_container.js";
|
||||||
import ToggleSidebarButton from "../widgets/mobile_widgets/toggle_sidebar_button.jsx";
|
import ToggleSidebarButton from "../widgets/mobile_widgets/toggle_sidebar_button.jsx";
|
||||||
|
import NoteIconWidget from "../widgets/note_icon.jsx";
|
||||||
import NoteTitleWidget from "../widgets/note_title.js";
|
import NoteTitleWidget from "../widgets/note_title.js";
|
||||||
import NoteTreeWidget from "../widgets/note_tree.js";
|
import NoteTreeWidget from "../widgets/note_tree.js";
|
||||||
import NoteWrapperWidget from "../widgets/note_wrapper.js";
|
import NoteWrapperWidget from "../widgets/note_wrapper.js";
|
||||||
import NoteDetail from "../widgets/NoteDetail.jsx";
|
import NoteDetail from "../widgets/NoteDetail.jsx";
|
||||||
import PromotedAttributes from "../widgets/PromotedAttributes.jsx";
|
|
||||||
import QuickSearchWidget from "../widgets/quick_search.js";
|
import QuickSearchWidget from "../widgets/quick_search.js";
|
||||||
import { useNoteContext } from "../widgets/react/hooks.jsx";
|
import ScrollPadding from "../widgets/scroll_padding";
|
||||||
import ReadOnlyNoteInfoBar from "../widgets/ReadOnlyNoteInfoBar.jsx";
|
|
||||||
import StandaloneRibbonAdapter from "../widgets/ribbon/components/StandaloneRibbonAdapter.jsx";
|
|
||||||
import FilePropertiesTab from "../widgets/ribbon/FilePropertiesTab.jsx";
|
|
||||||
import SearchDefinitionTab from "../widgets/ribbon/SearchDefinitionTab.jsx";
|
|
||||||
import SearchResult from "../widgets/search_result.jsx";
|
import SearchResult from "../widgets/search_result.jsx";
|
||||||
import SharedInfoWidget from "../widgets/shared_info.js";
|
|
||||||
import TabRowWidget from "../widgets/tab_row.js";
|
|
||||||
import MobileEditorToolbar from "../widgets/type_widgets/text/mobile_editor_toolbar.jsx";
|
import MobileEditorToolbar from "../widgets/type_widgets/text/mobile_editor_toolbar.jsx";
|
||||||
import { applyModals } from "./layout_commons.js";
|
import { applyModals } from "./layout_commons.js";
|
||||||
|
|
||||||
const MOBILE_CSS = `
|
|
||||||
<style>
|
|
||||||
span.keyboard-shortcut,
|
|
||||||
kbd {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-menu {
|
|
||||||
font-size: larger;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-button {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 1.25em;
|
|
||||||
padding-inline-start: 0.5em;
|
|
||||||
padding-inline-end: 0.5em;
|
|
||||||
color: var(--main-text-color);
|
|
||||||
}
|
|
||||||
.quick-search {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.quick-search .dropdown-menu {
|
|
||||||
max-width: 350px;
|
|
||||||
}
|
|
||||||
</style>`;
|
|
||||||
|
|
||||||
const FANCYTREE_CSS = `
|
|
||||||
<style>
|
|
||||||
.tree-wrapper {
|
|
||||||
max-height: 100%;
|
|
||||||
margin-top: 0px;
|
|
||||||
overflow-y: auto;
|
|
||||||
contain: content;
|
|
||||||
padding-inline-start: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fancytree-custom-icon {
|
|
||||||
font-size: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fancytree-title {
|
|
||||||
font-size: 1.5em;
|
|
||||||
margin-inline-start: 0.6em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fancytree-node {
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fancytree-node .fancytree-expander:before {
|
|
||||||
font-size: 2em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.fancytree-expander {
|
|
||||||
width: 24px !important;
|
|
||||||
margin-inline-end: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fancytree-loading span.fancytree-expander {
|
|
||||||
width: 24px;
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fancytree-loading span.fancytree-expander:after {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin-top: 4px;
|
|
||||||
border-width: 2px;
|
|
||||||
border-style: solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-wrapper .collapse-tree-button,
|
|
||||||
.tree-wrapper .scroll-to-active-note-button,
|
|
||||||
.tree-wrapper .tree-settings-button {
|
|
||||||
position: fixed;
|
|
||||||
margin-inline-end: 16px;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-wrapper .unhoist-button {
|
|
||||||
font-size: 200%;
|
|
||||||
}
|
|
||||||
</style>`;
|
|
||||||
|
|
||||||
export default class MobileLayout {
|
export default class MobileLayout {
|
||||||
getRootWidget(appContext: typeof AppContext) {
|
getRootWidget(appContext: typeof AppContext) {
|
||||||
const rootContainer = new RootContainer(true)
|
const rootContainer = new RootContainer(true)
|
||||||
.setParent(appContext)
|
.setParent(appContext)
|
||||||
.class("horizontal-layout")
|
.class("horizontal-layout")
|
||||||
.cssBlock(MOBILE_CSS)
|
|
||||||
.child(new FlexContainer("column").id("mobile-sidebar-container"))
|
.child(new FlexContainer("column").id("mobile-sidebar-container"))
|
||||||
.child(
|
.child(
|
||||||
new FlexContainer("row")
|
new FlexContainer("row")
|
||||||
@@ -136,7 +46,7 @@ export default class MobileLayout {
|
|||||||
.css("padding-inline-start", "0")
|
.css("padding-inline-start", "0")
|
||||||
.css("padding-inline-end", "0")
|
.css("padding-inline-end", "0")
|
||||||
.css("contain", "content")
|
.css("contain", "content")
|
||||||
.child(new FlexContainer("column").filling().id("mobile-sidebar-wrapper").child(new QuickSearchWidget()).child(new NoteTreeWidget().cssBlock(FANCYTREE_CSS)))
|
.child(new FlexContainer("column").filling().id("mobile-sidebar-wrapper").child(new QuickSearchWidget()).child(new NoteTreeWidget()))
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
new ScreenContainer("detail", "row")
|
new ScreenContainer("detail", "row")
|
||||||
@@ -147,30 +57,28 @@ export default class MobileLayout {
|
|||||||
new NoteWrapperWidget()
|
new NoteWrapperWidget()
|
||||||
.child(
|
.child(
|
||||||
new FlexContainer("row")
|
new FlexContainer("row")
|
||||||
|
.class("title-row note-split-title")
|
||||||
.contentSized()
|
.contentSized()
|
||||||
.css("font-size", "larger")
|
|
||||||
.css("align-items", "center")
|
.css("align-items", "center")
|
||||||
.child(<ToggleSidebarButton />)
|
.child(<ToggleSidebarButton />)
|
||||||
|
.child(<NoteIconWidget />)
|
||||||
.child(<NoteTitleWidget />)
|
.child(<NoteTitleWidget />)
|
||||||
|
.child(<NoteBadges />)
|
||||||
.child(<MobileDetailMenu />)
|
.child(<MobileDetailMenu />)
|
||||||
)
|
)
|
||||||
.child(<FloatingButtons items={MOBILE_FLOATING_BUTTONS} />)
|
|
||||||
.child(<PromotedAttributes />)
|
|
||||||
.child(
|
.child(
|
||||||
new ScrollingContainer()
|
new ScrollingContainer()
|
||||||
.filling()
|
.filling()
|
||||||
.contentSized()
|
.contentSized()
|
||||||
.child(new ContentHeader()
|
.child(<InlineTitle />)
|
||||||
.child(<ReadOnlyNoteInfoBar />)
|
.child(<NoteTitleActions />)
|
||||||
.child(<SharedInfoWidget />)
|
|
||||||
)
|
|
||||||
.child(<NoteDetail />)
|
.child(<NoteDetail />)
|
||||||
.child(<NoteList media="screen" />)
|
.child(<NoteList media="screen" />)
|
||||||
.child(<StandaloneRibbonAdapter component={SearchDefinitionTab} />)
|
|
||||||
.child(<SearchResult />)
|
.child(<SearchResult />)
|
||||||
.child(<FilePropertiesWrapper />)
|
.child(<ScrollPadding />)
|
||||||
)
|
)
|
||||||
.child(<MobileEditorToolbar />)
|
.child(<MobileEditorToolbar />)
|
||||||
|
.child(new FindWidget())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -179,7 +87,6 @@ export default class MobileLayout {
|
|||||||
new FlexContainer("column")
|
new FlexContainer("column")
|
||||||
.contentSized()
|
.contentSized()
|
||||||
.id("mobile-bottom-bar")
|
.id("mobile-bottom-bar")
|
||||||
.child(new TabRowWidget().css("height", "40px"))
|
|
||||||
.child(new FlexContainer("row")
|
.child(new FlexContainer("row")
|
||||||
.class("horizontal")
|
.class("horizontal")
|
||||||
.css("height", "53px")
|
.css("height", "53px")
|
||||||
@@ -192,13 +99,3 @@ export default class MobileLayout {
|
|||||||
return rootContainer;
|
return rootContainer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function FilePropertiesWrapper() {
|
|
||||||
const { note, ntxId } = useNoteContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{note?.type === "file" && <FilePropertiesTab note={note} ntxId={ntxId} />}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { KeyboardActionNames } from "@triliumnext/commons";
|
import { KeyboardActionNames } from "@triliumnext/commons";
|
||||||
|
import { h, JSX, render } from "preact";
|
||||||
|
|
||||||
import keyboardActionService, { getActionSync } from "../services/keyboard_actions.js";
|
import keyboardActionService, { getActionSync } from "../services/keyboard_actions.js";
|
||||||
import note_tooltip from "../services/note_tooltip.js";
|
import note_tooltip from "../services/note_tooltip.js";
|
||||||
import utils from "../services/utils.js";
|
import utils from "../services/utils.js";
|
||||||
import { h, JSX, render } from "preact";
|
|
||||||
|
|
||||||
export interface ContextMenuOptions<T> {
|
export interface ContextMenuOptions<T> {
|
||||||
x: number;
|
x: number;
|
||||||
@@ -62,17 +63,17 @@ export type ContextMenuEvent = PointerEvent | MouseEvent | JQuery.ContextMenuEve
|
|||||||
|
|
||||||
class ContextMenu {
|
class ContextMenu {
|
||||||
private $widget: JQuery<HTMLElement>;
|
private $widget: JQuery<HTMLElement>;
|
||||||
private $cover: JQuery<HTMLElement>;
|
private $cover?: JQuery<HTMLElement>;
|
||||||
private options?: ContextMenuOptions<any>;
|
private options?: ContextMenuOptions<any>;
|
||||||
private isMobile: boolean;
|
private isMobile: boolean;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.$widget = $("#context-menu-container");
|
this.$widget = $("#context-menu-container");
|
||||||
this.$cover = $("#context-menu-cover");
|
|
||||||
this.$widget.addClass("dropend");
|
this.$widget.addClass("dropend");
|
||||||
this.isMobile = utils.isMobile();
|
this.isMobile = utils.isMobile();
|
||||||
|
|
||||||
if (this.isMobile) {
|
if (this.isMobile) {
|
||||||
|
this.$cover = $("#context-menu-cover");
|
||||||
this.$cover.on("click", () => this.hide());
|
this.$cover.on("click", () => this.hide());
|
||||||
} else {
|
} else {
|
||||||
$(document).on("click", (e) => this.hide());
|
$(document).on("click", (e) => this.hide());
|
||||||
@@ -91,7 +92,7 @@ class ContextMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.$widget.toggleClass("mobile-bottom-menu", !this.options.forcePositionOnMobile);
|
this.$widget.toggleClass("mobile-bottom-menu", !this.options.forcePositionOnMobile);
|
||||||
this.$cover.addClass("show");
|
this.$cover?.addClass("show");
|
||||||
$("body").addClass("context-menu-shown");
|
$("body").addClass("context-menu-shown");
|
||||||
|
|
||||||
this.$widget.empty();
|
this.$widget.empty();
|
||||||
@@ -140,16 +141,14 @@ class ContextMenu {
|
|||||||
} else {
|
} else {
|
||||||
left = this.options.x - contextMenuWidth + CONTEXT_MENU_OFFSET;
|
left = this.options.x - contextMenuWidth + CONTEXT_MENU_OFFSET;
|
||||||
}
|
}
|
||||||
|
} else if (contextMenuWidth && this.options.x + contextMenuWidth - CONTEXT_MENU_OFFSET > clientWidth - CONTEXT_MENU_PADDING) {
|
||||||
|
// Overflow: right
|
||||||
|
left = clientWidth - contextMenuWidth - CONTEXT_MENU_PADDING;
|
||||||
|
} else if (this.options.x - CONTEXT_MENU_OFFSET < CONTEXT_MENU_PADDING) {
|
||||||
|
// Overflow: left
|
||||||
|
left = CONTEXT_MENU_PADDING;
|
||||||
} else {
|
} else {
|
||||||
if (contextMenuWidth && this.options.x + contextMenuWidth - CONTEXT_MENU_OFFSET > clientWidth - CONTEXT_MENU_PADDING) {
|
left = this.options.x - CONTEXT_MENU_OFFSET;
|
||||||
// Overflow: right
|
|
||||||
left = clientWidth - contextMenuWidth - CONTEXT_MENU_PADDING;
|
|
||||||
} else if (this.options.x - CONTEXT_MENU_OFFSET < CONTEXT_MENU_PADDING) {
|
|
||||||
// Overflow: left
|
|
||||||
left = CONTEXT_MENU_PADDING;
|
|
||||||
} else {
|
|
||||||
left = this.options.x - CONTEXT_MENU_OFFSET;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$widget
|
this.$widget
|
||||||
@@ -249,7 +248,7 @@ class ContextMenu {
|
|||||||
if ("uiIcon" in item || "checked" in item) {
|
if ("uiIcon" in item || "checked" in item) {
|
||||||
const icon = (item.checked ? "bx bx-check" : item.uiIcon);
|
const icon = (item.checked ? "bx bx-check" : item.uiIcon);
|
||||||
if (icon) {
|
if (icon) {
|
||||||
$icon.addClass(icon);
|
$icon.addClass([icon, "tn-icon"]);
|
||||||
} else {
|
} else {
|
||||||
$icon.append(" ");
|
$icon.append(" ");
|
||||||
}
|
}
|
||||||
@@ -261,7 +260,7 @@ class ContextMenu {
|
|||||||
.append(item.title);
|
.append(item.title);
|
||||||
|
|
||||||
if ("badges" in item && item.badges) {
|
if ("badges" in item && item.badges) {
|
||||||
for (let badge of item.badges) {
|
for (const badge of item.badges) {
|
||||||
const badgeElement = $(`<span class="badge">`).text(badge.title);
|
const badgeElement = $(`<span class="badge">`).text(badge.title);
|
||||||
|
|
||||||
if (badge.className) {
|
if (badge.className) {
|
||||||
@@ -352,7 +351,7 @@ class ContextMenu {
|
|||||||
async hide() {
|
async hide() {
|
||||||
this.options?.onHide?.();
|
this.options?.onHide?.();
|
||||||
this.$widget.removeClass("show");
|
this.$widget.removeClass("show");
|
||||||
this.$cover.removeClass("show");
|
this.$cover?.removeClass("show");
|
||||||
$("body").removeClass("context-menu-shown");
|
$("body").removeClass("context-menu-shown");
|
||||||
this.$widget.hide();
|
this.$widget.hide();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import options from "../services/options.js";
|
|||||||
import zoomService from "../components/zoom.js";
|
import zoomService from "../components/zoom.js";
|
||||||
import contextMenu, { type MenuItem } from "./context_menu.js";
|
import contextMenu, { type MenuItem } from "./context_menu.js";
|
||||||
import { t } from "../services/i18n.js";
|
import { t } from "../services/i18n.js";
|
||||||
|
import server from "../services/server.js";
|
||||||
|
import * as clipboardExt from "../services/clipboard_ext.js";
|
||||||
import type { BrowserWindow } from "electron";
|
import type { BrowserWindow } from "electron";
|
||||||
import type { CommandNames, AppContext } from "../components/app_context.js";
|
import type { CommandNames, AppContext } from "../components/app_context.js";
|
||||||
|
|
||||||
@@ -60,6 +62,33 @@ function setupContextMenu() {
|
|||||||
uiIcon: "bx bx-copy",
|
uiIcon: "bx bx-copy",
|
||||||
handler: () => webContents.copy()
|
handler: () => webContents.copy()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
enabled: hasText,
|
||||||
|
title: t("electron_context_menu.copy-as-markdown"),
|
||||||
|
uiIcon: "bx bx-copy-alt",
|
||||||
|
handler: async () => {
|
||||||
|
const selection = window.getSelection();
|
||||||
|
if (!selection || !selection.rangeCount) return '';
|
||||||
|
|
||||||
|
const range = selection.getRangeAt(0);
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.appendChild(range.cloneContents());
|
||||||
|
|
||||||
|
const htmlContent = div.innerHTML;
|
||||||
|
if (htmlContent) {
|
||||||
|
try {
|
||||||
|
const { markdownContent } = await server.post<{ markdownContent: string }>(
|
||||||
|
"other/to-markdown",
|
||||||
|
{ htmlContent }
|
||||||
|
);
|
||||||
|
await clipboardExt.copyTextWithToast(markdownContent);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to copy as markdown:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!["", "javascript:", "about:blank#blocked"].includes(params.linkURL) && params.mediaType === "none") {
|
if (!["", "javascript:", "about:blank#blocked"].includes(params.linkURL) && params.mediaType === "none") {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import treeService from "../services/tree.js";
|
import type { ContextMenuCommandData,FilteredCommandNames } from "../components/app_context.js";
|
||||||
import froca from "../services/froca.js";
|
|
||||||
import contextMenu, { type MenuCommandItem, type MenuItem } from "./context_menu.js";
|
|
||||||
import dialogService from "../services/dialog.js";
|
|
||||||
import server from "../services/server.js";
|
|
||||||
import { t } from "../services/i18n.js";
|
|
||||||
import type { SelectMenuItemEventListener } from "../components/events.js";
|
import type { SelectMenuItemEventListener } from "../components/events.js";
|
||||||
|
import dialogService from "../services/dialog.js";
|
||||||
|
import froca from "../services/froca.js";
|
||||||
|
import { t } from "../services/i18n.js";
|
||||||
|
import server from "../services/server.js";
|
||||||
|
import treeService from "../services/tree.js";
|
||||||
import type NoteTreeWidget from "../widgets/note_tree.js";
|
import type NoteTreeWidget from "../widgets/note_tree.js";
|
||||||
import type { FilteredCommandNames, ContextMenuCommandData } from "../components/app_context.js";
|
import contextMenu, { type MenuCommandItem, type MenuItem } from "./context_menu.js";
|
||||||
|
|
||||||
type LauncherCommandNames = FilteredCommandNames<ContextMenuCommandData>;
|
type LauncherCommandNames = FilteredCommandNames<ContextMenuCommandData>;
|
||||||
|
|
||||||
@@ -32,8 +32,8 @@ export default class LauncherContextMenu implements SelectMenuItemEventListener<
|
|||||||
const note = this.node.data.noteId ? await froca.getNote(this.node.data.noteId) : null;
|
const note = this.node.data.noteId ? await froca.getNote(this.node.data.noteId) : null;
|
||||||
const parentNoteId = this.node.getParent().data.noteId;
|
const parentNoteId = this.node.getParent().data.noteId;
|
||||||
|
|
||||||
const isVisibleRoot = note?.noteId === "_lbVisibleLaunchers";
|
const isVisibleRoot = note?.noteId === "_lbVisibleLaunchers" || note?.noteId === "_lbMobileVisibleLaunchers";
|
||||||
const isAvailableRoot = note?.noteId === "_lbAvailableLaunchers";
|
const isAvailableRoot = note?.noteId === "_lbAvailableLaunchers" || note?.noteId === "_lbMobileAvailableLaunchers";
|
||||||
const isVisibleItem = parentNoteId === "_lbVisibleLaunchers" || parentNoteId === "_lbMobileVisibleLaunchers";
|
const isVisibleItem = parentNoteId === "_lbVisibleLaunchers" || parentNoteId === "_lbMobileVisibleLaunchers";
|
||||||
const isAvailableItem = parentNoteId === "_lbAvailableLaunchers" || parentNoteId === "_lbMobileAvailableLaunchers";
|
const isAvailableItem = parentNoteId === "_lbAvailableLaunchers" || parentNoteId === "_lbMobileAvailableLaunchers";
|
||||||
const isItem = isVisibleItem || isAvailableItem;
|
const isItem = isVisibleItem || isAvailableItem;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import "autocomplete.js/index_jquery.js";
|
|
||||||
|
|
||||||
import appContext from "./components/app_context.js";
|
import appContext from "./components/app_context.js";
|
||||||
import glob from "./services/glob.js";
|
import glob from "./services/glob.js";
|
||||||
import noteAutocompleteService from "./services/note_autocomplete.js";
|
import noteAutocompleteService from "./services/note_autocomplete.js";
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ export type PrintReport = {
|
|||||||
} | {
|
} | {
|
||||||
type: "collection";
|
type: "collection";
|
||||||
ignoredNoteIds: string[];
|
ignoredNoteIds: string[];
|
||||||
|
} | {
|
||||||
|
type: "error";
|
||||||
|
message: string;
|
||||||
|
stack?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
@@ -29,7 +33,9 @@ async function main() {
|
|||||||
const froca = (await import("./services/froca")).default;
|
const froca = (await import("./services/froca")).default;
|
||||||
const note = await froca.getNote(noteId);
|
const note = await froca.getNote(noteId);
|
||||||
|
|
||||||
render(<App note={note} noteId={noteId} />, document.body);
|
const bodyWrapper = document.createElement("div");
|
||||||
|
render(<App note={note} noteId={noteId} />, bodyWrapper);
|
||||||
|
document.body.appendChild(bodyWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
function App({ note, noteId }: { note: FNote | null | undefined, noteId: string }) {
|
function App({ note, noteId }: { note: FNote | null | undefined, noteId: string }) {
|
||||||
|
|||||||
47
apps/client/src/services/attribute_autocomplete.spec.ts
Normal file
47
apps/client/src/services/attribute_autocomplete.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { shouldAutocompleteHandleEnterKey } from "./attribute_autocomplete.js";
|
||||||
|
|
||||||
|
describe("attribute autocomplete enter handling", () => {
|
||||||
|
it("delegates plain Enter when the panel is open and an item is active", () => {
|
||||||
|
expect(shouldAutocompleteHandleEnterKey(
|
||||||
|
{ key: "Enter", ctrlKey: false, metaKey: false },
|
||||||
|
{ isPanelOpen: true, hasActiveItem: true }
|
||||||
|
)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not delegate plain Enter when there is no active suggestion", () => {
|
||||||
|
expect(shouldAutocompleteHandleEnterKey(
|
||||||
|
{ key: "Enter", ctrlKey: false, metaKey: false },
|
||||||
|
{ isPanelOpen: true, hasActiveItem: false }
|
||||||
|
)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not delegate plain Enter when the panel is closed", () => {
|
||||||
|
expect(shouldAutocompleteHandleEnterKey(
|
||||||
|
{ key: "Enter", ctrlKey: false, metaKey: false },
|
||||||
|
{ isPanelOpen: false, hasActiveItem: false }
|
||||||
|
)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not delegate Ctrl+Enter even when an item is active", () => {
|
||||||
|
expect(shouldAutocompleteHandleEnterKey(
|
||||||
|
{ key: "Enter", ctrlKey: true, metaKey: false },
|
||||||
|
{ isPanelOpen: true, hasActiveItem: true }
|
||||||
|
)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not delegate Cmd+Enter even when an item is active", () => {
|
||||||
|
expect(shouldAutocompleteHandleEnterKey(
|
||||||
|
{ key: "Enter", ctrlKey: false, metaKey: true },
|
||||||
|
{ isPanelOpen: true, hasActiveItem: true }
|
||||||
|
)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores non-Enter keys", () => {
|
||||||
|
expect(shouldAutocompleteHandleEnterKey(
|
||||||
|
{ key: "ArrowDown", ctrlKey: false, metaKey: false },
|
||||||
|
{ isPanelOpen: false, hasActiveItem: false }
|
||||||
|
)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,114 +1,450 @@
|
|||||||
|
import type { AutocompleteApi as CoreAutocompleteApi, BaseItem } from "@algolia/autocomplete-core";
|
||||||
|
import { createAutocomplete } from "@algolia/autocomplete-core";
|
||||||
|
|
||||||
import type { AttributeType } from "../entities/fattribute.js";
|
import type { AttributeType } from "../entities/fattribute.js";
|
||||||
|
import { bindAutocompleteInput, createHeadlessPanelController, registerHeadlessAutocompleteCloser, withHeadlessSourceDefaults } from "./autocomplete_core.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
|
|
||||||
interface InitOptions {
|
// ---------------------------------------------------------------------------
|
||||||
|
// Types
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
interface NameItem extends BaseItem {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldAutocompleteHandleEnterKey(
|
||||||
|
event: Pick<KeyboardEvent, "key" | "ctrlKey" | "metaKey">,
|
||||||
|
{ isPanelOpen, hasActiveItem }: { isPanelOpen: boolean; hasActiveItem: boolean }
|
||||||
|
) {
|
||||||
|
if (event.key !== "Enter") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.ctrlKey || event.metaKey) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isPanelOpen && hasActiveItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InitAttributeNameOptions {
|
||||||
|
/** The <input> element where the user types */
|
||||||
$el: JQuery<HTMLElement>;
|
$el: JQuery<HTMLElement>;
|
||||||
attributeType?: AttributeType | (() => AttributeType);
|
attributeType?: AttributeType | (() => AttributeType);
|
||||||
open: boolean;
|
open: boolean;
|
||||||
nameCallback?: () => string;
|
/** Called when the user selects a value or the panel closes */
|
||||||
|
onValueChange?: (value: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// ---------------------------------------------------------------------------
|
||||||
* @param $el - element on which to init autocomplete
|
// Instance tracking
|
||||||
* @param attributeType - "relation" or "label" or callback providing one of those values as a type of autocompleted attributes
|
// ---------------------------------------------------------------------------
|
||||||
* @param open - should the autocomplete be opened after init?
|
|
||||||
*/
|
|
||||||
function initAttributeNameAutocomplete({ $el, attributeType, open }: InitOptions) {
|
|
||||||
if (!$el.hasClass("aa-input")) {
|
|
||||||
$el.autocomplete(
|
|
||||||
{
|
|
||||||
appendTo: document.querySelector("body"),
|
|
||||||
hint: false,
|
|
||||||
openOnFocus: true,
|
|
||||||
minLength: 0,
|
|
||||||
tabAutocomplete: false
|
|
||||||
},
|
|
||||||
[
|
|
||||||
{
|
|
||||||
displayKey: "name",
|
|
||||||
// disabling cache is important here because otherwise cache can stay intact when switching between attribute type which will lead to autocomplete displaying attribute names for incorrect attribute type
|
|
||||||
cache: false,
|
|
||||||
source: async (term, cb) => {
|
|
||||||
const type = typeof attributeType === "function" ? attributeType() : attributeType;
|
|
||||||
|
|
||||||
const names = await server.get<string[]>(`attribute-names/?type=${type}&query=${encodeURIComponent(term)}`);
|
interface ManagedInstance {
|
||||||
const result = names.map((name) => ({ name }));
|
autocomplete: CoreAutocompleteApi<NameItem>;
|
||||||
|
panelEl: HTMLElement;
|
||||||
|
cleanup: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
cb(result);
|
const instanceMap = new WeakMap<HTMLElement, ManagedInstance>();
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
$el.on("autocomplete:opened", () => {
|
function renderItems(
|
||||||
if ($el.attr("readonly")) {
|
panelEl: HTMLElement,
|
||||||
$el.autocomplete("close");
|
items: NameItem[],
|
||||||
|
activeItemId: number | null,
|
||||||
|
onSelect: (item: NameItem) => void,
|
||||||
|
onActivate: (index: number) => void,
|
||||||
|
onDeactivate: () => void
|
||||||
|
): void {
|
||||||
|
panelEl.innerHTML = "";
|
||||||
|
if (items.length === 0) {
|
||||||
|
panelEl.style.display = "none";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const list = document.createElement("ul");
|
||||||
|
list.className = "aa-core-list";
|
||||||
|
items.forEach((item, index) => {
|
||||||
|
const li = document.createElement("li");
|
||||||
|
li.className = "aa-core-item";
|
||||||
|
if (index === activeItemId) {
|
||||||
|
li.classList.add("aa-core-item--active");
|
||||||
|
}
|
||||||
|
li.textContent = item.name;
|
||||||
|
li.addEventListener("mousemove", () => {
|
||||||
|
if (activeItemId === index) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onActivate(index);
|
||||||
});
|
});
|
||||||
}
|
li.addEventListener("mouseleave", (event) => {
|
||||||
|
const relatedTarget = event.relatedTarget;
|
||||||
|
if (relatedTarget instanceof HTMLElement && li.contains(relatedTarget)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (open) {
|
onDeactivate();
|
||||||
$el.autocomplete("open");
|
});
|
||||||
}
|
li.addEventListener("mousedown", (e) => {
|
||||||
|
e.preventDefault(); // prevent input blur
|
||||||
|
e.stopPropagation();
|
||||||
|
onSelect(item);
|
||||||
|
});
|
||||||
|
list.appendChild(li);
|
||||||
|
});
|
||||||
|
panelEl.appendChild(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function initLabelValueAutocomplete({ $el, open, nameCallback }: InitOptions) {
|
// ---------------------------------------------------------------------------
|
||||||
if ($el.hasClass("aa-input")) {
|
// Attribute name autocomplete — new (autocomplete-core, headless)
|
||||||
// we reinit every time because autocomplete seems to have a bug where it retains state from last
|
// ---------------------------------------------------------------------------
|
||||||
// open even though the value was reset
|
|
||||||
$el.autocomplete("destroy");
|
|
||||||
}
|
|
||||||
|
|
||||||
let attributeName = "";
|
function initAttributeNameAutocomplete({ $el, attributeType, open, onValueChange }: InitAttributeNameOptions) {
|
||||||
if (nameCallback) {
|
const inputEl = $el[0] as HTMLInputElement;
|
||||||
attributeName = nameCallback();
|
const syncQueryFromInputValue = (autocomplete: CoreAutocompleteApi<NameItem>) => {
|
||||||
}
|
autocomplete.setQuery(inputEl.value || "");
|
||||||
|
};
|
||||||
|
|
||||||
if (attributeName.trim() === "") {
|
// Already initialized — just open if requested
|
||||||
|
if (instanceMap.has(inputEl)) {
|
||||||
|
if (open) {
|
||||||
|
const inst = instanceMap.get(inputEl)!;
|
||||||
|
syncQueryFromInputValue(inst.autocomplete);
|
||||||
|
inst.autocomplete.setIsOpen(true);
|
||||||
|
inst.autocomplete.refresh();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const attributeValues = (await server.get<string[]>(`attribute-values/${encodeURIComponent(attributeName)}`)).map((attribute) => ({ value: attribute }));
|
const panelController = createHeadlessPanelController({ inputEl });
|
||||||
|
const { panelEl } = panelController;
|
||||||
|
|
||||||
if (attributeValues.length === 0) {
|
let isPanelOpen = false;
|
||||||
return;
|
let hasActiveItem = false;
|
||||||
}
|
|
||||||
|
|
||||||
$el.autocomplete(
|
const autocomplete = createAutocomplete<NameItem>({
|
||||||
{
|
openOnFocus: true,
|
||||||
appendTo: document.querySelector("body"),
|
defaultActiveItemId: 0,
|
||||||
hint: false,
|
shouldPanelOpen() {
|
||||||
openOnFocus: false, // handled manually
|
return true;
|
||||||
minLength: 0,
|
|
||||||
tabAutocomplete: false
|
|
||||||
},
|
},
|
||||||
[
|
|
||||||
{
|
|
||||||
displayKey: "value",
|
|
||||||
cache: false,
|
|
||||||
source: async function (term, cb) {
|
|
||||||
term = term.toLowerCase();
|
|
||||||
|
|
||||||
const filtered = attributeValues.filter((attr) => attr.value.toLowerCase().includes(term));
|
getSources({ query }) {
|
||||||
|
return [
|
||||||
|
withHeadlessSourceDefaults({
|
||||||
|
sourceId: "attribute-names",
|
||||||
|
getItems() {
|
||||||
|
const type = typeof attributeType === "function" ? attributeType() : attributeType;
|
||||||
|
return server
|
||||||
|
.get<string[]>(`attribute-names/?type=${type}&query=${encodeURIComponent(query)}`)
|
||||||
|
.then((names) => names.map((name) => ({ name })));
|
||||||
|
},
|
||||||
|
getItemInputValue({ item }) {
|
||||||
|
return item.name;
|
||||||
|
},
|
||||||
|
onSelect({ item }) {
|
||||||
|
inputEl.value = item.name;
|
||||||
|
autocomplete.setQuery(item.name);
|
||||||
|
autocomplete.setIsOpen(false);
|
||||||
|
onValueChange?.(item.name);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
cb(filtered);
|
onStateChange({ state }) {
|
||||||
}
|
isPanelOpen = state.isOpen;
|
||||||
|
hasActiveItem = state.activeItemId !== null;
|
||||||
|
|
||||||
|
// Render items
|
||||||
|
const collections = state.collections;
|
||||||
|
const items = collections.length > 0 ? (collections[0].items as NameItem[]) : [];
|
||||||
|
const activeId = state.activeItemId ?? null;
|
||||||
|
|
||||||
|
if (state.isOpen && items.length > 0) {
|
||||||
|
renderItems(
|
||||||
|
panelEl,
|
||||||
|
items,
|
||||||
|
activeId,
|
||||||
|
(item) => {
|
||||||
|
inputEl.value = item.name;
|
||||||
|
autocomplete.setQuery(item.name);
|
||||||
|
autocomplete.setIsOpen(false);
|
||||||
|
onValueChange?.(item.name);
|
||||||
|
},
|
||||||
|
(index) => {
|
||||||
|
autocomplete.setActiveItemId(index);
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
autocomplete.setActiveItemId(null);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
panelController.startPositioning();
|
||||||
|
} else {
|
||||||
|
panelController.hide();
|
||||||
}
|
}
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
$el.on("autocomplete:opened", () => {
|
if (!state.isOpen) {
|
||||||
if ($el.attr("readonly")) {
|
panelController.hide();
|
||||||
$el.autocomplete("close");
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const unregisterGlobalCloser = registerHeadlessAutocompleteCloser(() => {
|
||||||
|
autocomplete.setIsOpen(false);
|
||||||
|
panelController.hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
const cleanupInputBindings = bindAutocompleteInput<NameItem>({
|
||||||
|
inputEl,
|
||||||
|
autocomplete,
|
||||||
|
onInput(e, handlers) {
|
||||||
|
handlers.onChange(e as any);
|
||||||
|
},
|
||||||
|
onFocus(e, handlers) {
|
||||||
|
syncQueryFromInputValue(autocomplete);
|
||||||
|
handlers.onFocus(e as any);
|
||||||
|
},
|
||||||
|
onBlur() {
|
||||||
|
// Delay to allow mousedown on panel items
|
||||||
|
setTimeout(() => {
|
||||||
|
autocomplete.setIsOpen(false);
|
||||||
|
panelController.hide();
|
||||||
|
onValueChange?.(inputEl.value);
|
||||||
|
}, 50);
|
||||||
|
},
|
||||||
|
onKeyDown(e, handlers) {
|
||||||
|
if (!shouldAutocompleteHandleEnterKey(e, { isPanelOpen, hasActiveItem })) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
// Prevent the enter key from propagating to parent dialogs
|
||||||
|
// (which might interpret it as "submit" or "save and close")
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers.onKeyDown(e as any);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const cleanup = () => {
|
||||||
|
unregisterGlobalCloser();
|
||||||
|
cleanupInputBindings();
|
||||||
|
panelController.destroy();
|
||||||
|
};
|
||||||
|
|
||||||
|
instanceMap.set(inputEl, { autocomplete, panelEl, cleanup });
|
||||||
|
|
||||||
if (open) {
|
if (open) {
|
||||||
$el.autocomplete("open");
|
syncQueryFromInputValue(autocomplete);
|
||||||
|
autocomplete.setIsOpen(true);
|
||||||
|
autocomplete.refresh();
|
||||||
|
panelController.startPositioning();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Label value autocomplete (headless autocomplete-core)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
interface LabelValueInitOptions {
|
||||||
|
$el: JQuery<HTMLElement>;
|
||||||
|
open: boolean;
|
||||||
|
nameCallback?: () => string;
|
||||||
|
onValueChange?: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initLabelValueAutocomplete({ $el, open, nameCallback, onValueChange }: LabelValueInitOptions) {
|
||||||
|
const inputEl = $el[0] as HTMLInputElement;
|
||||||
|
const syncQueryFromInputValue = (autocomplete: CoreAutocompleteApi<NameItem>) => {
|
||||||
|
autocomplete.setQuery(inputEl.value || "");
|
||||||
|
};
|
||||||
|
|
||||||
|
if (instanceMap.has(inputEl)) {
|
||||||
|
if (open) {
|
||||||
|
const inst = instanceMap.get(inputEl)!;
|
||||||
|
syncQueryFromInputValue(inst.autocomplete);
|
||||||
|
inst.autocomplete.setIsOpen(true);
|
||||||
|
inst.autocomplete.refresh();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const panelController = createHeadlessPanelController({ inputEl });
|
||||||
|
const { panelEl } = panelController;
|
||||||
|
|
||||||
|
let isPanelOpen = false;
|
||||||
|
let hasActiveItem = false;
|
||||||
|
let isSelecting = false;
|
||||||
|
|
||||||
|
let cachedAttributeName = "";
|
||||||
|
let cachedAttributeValues: NameItem[] = [];
|
||||||
|
|
||||||
|
const handleSelect = (item: NameItem) => {
|
||||||
|
isSelecting = true;
|
||||||
|
inputEl.value = item.name;
|
||||||
|
inputEl.dispatchEvent(new Event("input", { bubbles: true }));
|
||||||
|
autocomplete.setQuery(item.name);
|
||||||
|
autocomplete.setIsOpen(false);
|
||||||
|
onValueChange?.(item.name);
|
||||||
|
isSelecting = false;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// Preserve the legacy contract: several consumers still commit the
|
||||||
|
// selected value from their existing Enter key handlers instead of
|
||||||
|
// listening to the autocomplete selection event directly.
|
||||||
|
inputEl.dispatchEvent(new KeyboardEvent("keydown", {
|
||||||
|
key: "Enter",
|
||||||
|
code: "Enter",
|
||||||
|
keyCode: 13,
|
||||||
|
which: 13,
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true
|
||||||
|
}));
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const autocomplete = createAutocomplete<NameItem>({
|
||||||
|
openOnFocus: true,
|
||||||
|
defaultActiveItemId: null,
|
||||||
|
shouldPanelOpen() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
getSources({ query }) {
|
||||||
|
return [
|
||||||
|
withHeadlessSourceDefaults({
|
||||||
|
sourceId: "attribute-values",
|
||||||
|
async getItems() {
|
||||||
|
const attributeName = nameCallback ? nameCallback() : "";
|
||||||
|
if (!attributeName.trim()) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributeName !== cachedAttributeName || cachedAttributeValues.length === 0) {
|
||||||
|
cachedAttributeName = attributeName;
|
||||||
|
const values = await server.get<string[]>(`attribute-values/${encodeURIComponent(attributeName)}`);
|
||||||
|
cachedAttributeValues = values.map((name) => ({ name }));
|
||||||
|
}
|
||||||
|
|
||||||
|
const q = query.toLowerCase();
|
||||||
|
return cachedAttributeValues.filter((attr) => attr.name.toLowerCase().includes(q));
|
||||||
|
},
|
||||||
|
getItemInputValue({ item }) {
|
||||||
|
return item.name;
|
||||||
|
},
|
||||||
|
onSelect({ item }) {
|
||||||
|
handleSelect(item);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
onStateChange({ state }) {
|
||||||
|
isPanelOpen = state.isOpen;
|
||||||
|
hasActiveItem = state.activeItemId !== null;
|
||||||
|
|
||||||
|
const collections = state.collections;
|
||||||
|
const items = collections.length > 0 ? (collections[0].items as NameItem[]) : [];
|
||||||
|
const activeId = state.activeItemId ?? null;
|
||||||
|
|
||||||
|
if (state.isOpen && items.length > 0) {
|
||||||
|
renderItems(
|
||||||
|
panelEl,
|
||||||
|
items,
|
||||||
|
activeId,
|
||||||
|
handleSelect,
|
||||||
|
(index) => {
|
||||||
|
autocomplete.setActiveItemId(index);
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
autocomplete.setActiveItemId(null);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
panelController.startPositioning();
|
||||||
|
} else {
|
||||||
|
panelController.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state.isOpen) {
|
||||||
|
panelController.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const unregisterGlobalCloser = registerHeadlessAutocompleteCloser(() => {
|
||||||
|
autocomplete.setIsOpen(false);
|
||||||
|
panelController.hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
const cleanupInputBindings = bindAutocompleteInput<NameItem>({
|
||||||
|
inputEl,
|
||||||
|
autocomplete,
|
||||||
|
onInput(e, handlers) {
|
||||||
|
if (!isSelecting) {
|
||||||
|
handlers.onChange(e as any);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onFocus(e, handlers) {
|
||||||
|
const attributeName = nameCallback ? nameCallback() : "";
|
||||||
|
if (attributeName !== cachedAttributeName) {
|
||||||
|
cachedAttributeName = "";
|
||||||
|
cachedAttributeValues = [];
|
||||||
|
}
|
||||||
|
syncQueryFromInputValue(autocomplete);
|
||||||
|
handlers.onFocus(e as any);
|
||||||
|
},
|
||||||
|
onBlur() {
|
||||||
|
setTimeout(() => {
|
||||||
|
autocomplete.setIsOpen(false);
|
||||||
|
panelController.hide();
|
||||||
|
onValueChange?.(inputEl.value);
|
||||||
|
}, 50);
|
||||||
|
},
|
||||||
|
onKeyDown(e, handlers) {
|
||||||
|
if (!shouldAutocompleteHandleEnterKey(e, { isPanelOpen, hasActiveItem })) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers.onKeyDown(e as any);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const cleanup = () => {
|
||||||
|
unregisterGlobalCloser();
|
||||||
|
cleanupInputBindings();
|
||||||
|
panelController.destroy();
|
||||||
|
};
|
||||||
|
|
||||||
|
instanceMap.set(inputEl, { autocomplete, panelEl, cleanup });
|
||||||
|
|
||||||
|
if (open) {
|
||||||
|
syncQueryFromInputValue(autocomplete);
|
||||||
|
autocomplete.setIsOpen(true);
|
||||||
|
autocomplete.refresh();
|
||||||
|
panelController.startPositioning();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function destroyAutocomplete($el: JQuery<HTMLElement> | HTMLElement) {
|
||||||
|
const inputEl = $el instanceof HTMLElement ? $el : $el[0] as HTMLInputElement;
|
||||||
|
const instance = instanceMap.get(inputEl);
|
||||||
|
if (instance) {
|
||||||
|
instance.cleanup();
|
||||||
|
instanceMap.delete(inputEl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
initAttributeNameAutocomplete,
|
initAttributeNameAutocomplete,
|
||||||
initLabelValueAutocomplete
|
destroyAutocomplete,
|
||||||
|
initLabelValueAutocomplete,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ describe("Set boolean with inheritance", () => {
|
|||||||
name: "foo",
|
name: "foo",
|
||||||
value: "",
|
value: "",
|
||||||
isInheritable: false
|
isInheritable: false
|
||||||
});
|
}, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("removes boolean normally without inheritance", async () => {
|
it("removes boolean normally without inheritance", async () => {
|
||||||
@@ -91,7 +91,7 @@ describe("Set boolean with inheritance", () => {
|
|||||||
name: "foo",
|
name: "foo",
|
||||||
value: "false",
|
value: "false",
|
||||||
isInheritable: false
|
isInheritable: false
|
||||||
});
|
}, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("overrides boolean with inherited false", async () => {
|
it("overrides boolean with inherited false", async () => {
|
||||||
@@ -112,7 +112,7 @@ describe("Set boolean with inheritance", () => {
|
|||||||
name: "foo",
|
name: "foo",
|
||||||
value: "",
|
value: "",
|
||||||
isInheritable: false
|
isInheritable: false
|
||||||
});
|
}, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("deletes override boolean with inherited false with already existing value", async () => {
|
it("deletes override boolean with inherited false with already existing value", async () => {
|
||||||
@@ -134,6 +134,6 @@ describe("Set boolean with inheritance", () => {
|
|||||||
name: "foo",
|
name: "foo",
|
||||||
value: "",
|
value: "",
|
||||||
isInheritable: false
|
isInheritable: false
|
||||||
});
|
}, undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ async function addLabel(noteId: string, name: string, value: string = "", isInhe
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setLabel(noteId: string, name: string, value: string = "", isInheritable = false) {
|
export async function setLabel(noteId: string, name: string, value: string = "", isInheritable = false, componentId?: string) {
|
||||||
await server.put(`notes/${noteId}/set-attribute`, {
|
await server.put(`notes/${noteId}/set-attribute`, {
|
||||||
type: "label",
|
type: "label",
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
isInheritable
|
isInheritable,
|
||||||
});
|
}, componentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setRelation(noteId: string, name: string, value: string = "", isInheritable = false) {
|
export async function setRelation(noteId: string, name: string, value: string = "", isInheritable = false) {
|
||||||
@@ -117,15 +117,15 @@ function removeOwnedRelationByName(note: FNote, relationName: string) {
|
|||||||
* @param name the name of the attribute to set.
|
* @param name the name of the attribute to set.
|
||||||
* @param value the value of the attribute to set.
|
* @param value the value of the attribute to set.
|
||||||
*/
|
*/
|
||||||
export async function setAttribute(note: FNote, type: "label" | "relation", name: string, value: string | null | undefined) {
|
export async function setAttribute(note: FNote, type: "label" | "relation", name: string, value: string | null | undefined, componentId?: string) {
|
||||||
if (value !== null && value !== undefined) {
|
if (value !== null && value !== undefined) {
|
||||||
// Create or update the attribute.
|
// Create or update the attribute.
|
||||||
await server.put(`notes/${note.noteId}/set-attribute`, { type, name, value });
|
await server.put(`notes/${note.noteId}/set-attribute`, { type, name, value }, componentId);
|
||||||
} else {
|
} else {
|
||||||
// Remove the attribute if it exists on the server but we don't define a value for it.
|
// Remove the attribute if it exists on the server but we don't define a value for it.
|
||||||
const attributeId = note.getAttribute(type, name)?.attributeId;
|
const attributeId = note.getAttribute(type, name)?.attributeId;
|
||||||
if (attributeId) {
|
if (attributeId) {
|
||||||
await server.remove(`notes/${note.noteId}/attributes/${attributeId}`);
|
await server.remove(`notes/${note.noteId}/attributes/${attributeId}`, componentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,6 +168,49 @@ function isAffecting(attrRow: AttributeRow, affectedNote: FNote | null | undefin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles whether a dangerous attribute is enabled or not. When an attribute is disabled, its name is prefixed with `disabled:`.
|
||||||
|
*
|
||||||
|
* Note that this work for non-dangerous attributes as well.
|
||||||
|
*
|
||||||
|
* If there are multiple attributes with the same name, all of them will be toggled at the same time.
|
||||||
|
*
|
||||||
|
* @param note the note whose attribute to change.
|
||||||
|
* @param type the type of dangerous attribute (label or relation).
|
||||||
|
* @param name the name of the dangerous attribute.
|
||||||
|
* @param willEnable whether to enable or disable the attribute.
|
||||||
|
* @returns a promise that will resolve when the request to the server completes.
|
||||||
|
*/
|
||||||
|
async function toggleDangerousAttribute(note: FNote, type: "label" | "relation", name: string, willEnable: boolean) {
|
||||||
|
const attrs = [
|
||||||
|
...note.getOwnedAttributes(type, name),
|
||||||
|
...note.getOwnedAttributes(type, `disabled:${name}`)
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const attr of attrs) {
|
||||||
|
const baseName = getNameWithoutDangerousPrefix(attr.name);
|
||||||
|
const newName = willEnable ? baseName : `disabled:${baseName}`;
|
||||||
|
if (newName === attr.name) continue;
|
||||||
|
|
||||||
|
// We are adding and removing afterwards to avoid a flicker (because for a moment there would be no active content attribute anymore) because the operations are done in sequence and not atomically.
|
||||||
|
if (attr.type === "label") {
|
||||||
|
await setLabel(note.noteId, newName, attr.value);
|
||||||
|
} else {
|
||||||
|
await setRelation(note.noteId, newName, attr.value);
|
||||||
|
}
|
||||||
|
await removeAttributeById(note.noteId, attr.attributeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of an attribute without the `disabled:` prefix, or the same name if it's not disabled.
|
||||||
|
* @param name the name of an attribute.
|
||||||
|
* @returns the name without the `disabled:` prefix.
|
||||||
|
*/
|
||||||
|
function getNameWithoutDangerousPrefix(name: string) {
|
||||||
|
return name.startsWith("disabled:") ? name.substring(9) : name;
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
addLabel,
|
addLabel,
|
||||||
setLabel,
|
setLabel,
|
||||||
@@ -177,5 +220,7 @@ export default {
|
|||||||
removeAttributeById,
|
removeAttributeById,
|
||||||
removeOwnedLabelByName,
|
removeOwnedLabelByName,
|
||||||
removeOwnedRelationByName,
|
removeOwnedRelationByName,
|
||||||
isAffecting
|
isAffecting,
|
||||||
|
toggleDangerousAttribute,
|
||||||
|
getNameWithoutDangerousPrefix
|
||||||
};
|
};
|
||||||
|
|||||||
93
apps/client/src/services/autocomplete_core.spec.ts
Normal file
93
apps/client/src/services/autocomplete_core.spec.ts
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import $ from "jquery";
|
||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const {
|
||||||
|
showSpy,
|
||||||
|
hideSpy,
|
||||||
|
updateDisplayedShortcutsSpy,
|
||||||
|
saveFocusedElementSpy,
|
||||||
|
focusSavedElementSpy
|
||||||
|
} = vi.hoisted(() => ({
|
||||||
|
showSpy: vi.fn(),
|
||||||
|
hideSpy: vi.fn(),
|
||||||
|
updateDisplayedShortcutsSpy: vi.fn(),
|
||||||
|
saveFocusedElementSpy: vi.fn(),
|
||||||
|
focusSavedElementSpy: vi.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("bootstrap", () => ({
|
||||||
|
Modal: {
|
||||||
|
getOrCreateInstance: vi.fn(() => ({
|
||||||
|
show: showSpy,
|
||||||
|
hide: hideSpy
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("./keyboard_actions.js", () => ({
|
||||||
|
default: {
|
||||||
|
updateDisplayedShortcuts: updateDisplayedShortcutsSpy
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("./focus.js", () => ({
|
||||||
|
saveFocusedElement: saveFocusedElementSpy,
|
||||||
|
focusSavedElement: focusSavedElementSpy
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { closeAllHeadlessAutocompletes, registerHeadlessAutocompleteCloser } from "./autocomplete_core.js";
|
||||||
|
import { openDialog } from "./dialog.js";
|
||||||
|
|
||||||
|
describe("headless autocomplete closing", () => {
|
||||||
|
const unregisterClosers: Array<() => void> = [];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
(window as any).glob = {
|
||||||
|
...(window as any).glob,
|
||||||
|
activeDialog: null
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
while (unregisterClosers.length > 0) {
|
||||||
|
unregisterClosers.pop()?.();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("closes every registered closer and skips unregistered ones", () => {
|
||||||
|
const closer1 = vi.fn();
|
||||||
|
const closer2 = vi.fn();
|
||||||
|
const closer3 = vi.fn();
|
||||||
|
|
||||||
|
unregisterClosers.push(registerHeadlessAutocompleteCloser(closer1));
|
||||||
|
const unregister2 = registerHeadlessAutocompleteCloser(closer2);
|
||||||
|
unregisterClosers.push(unregister2);
|
||||||
|
unregisterClosers.push(registerHeadlessAutocompleteCloser(closer3));
|
||||||
|
|
||||||
|
unregister2();
|
||||||
|
|
||||||
|
closeAllHeadlessAutocompletes();
|
||||||
|
|
||||||
|
expect(closer1).toHaveBeenCalledTimes(1);
|
||||||
|
expect(closer2).not.toHaveBeenCalled();
|
||||||
|
expect(closer3).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("closes registered autocompletes when a dialog finishes hiding", async () => {
|
||||||
|
const closer = vi.fn();
|
||||||
|
unregisterClosers.push(registerHeadlessAutocompleteCloser(closer));
|
||||||
|
|
||||||
|
const dialogEl = document.createElement("div");
|
||||||
|
const $dialog = $(dialogEl);
|
||||||
|
|
||||||
|
await openDialog($dialog, false);
|
||||||
|
$dialog.trigger("hidden.bs.modal");
|
||||||
|
|
||||||
|
expect(showSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(updateDisplayedShortcutsSpy).toHaveBeenCalledWith($dialog);
|
||||||
|
expect(saveFocusedElementSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(closer).toHaveBeenCalledTimes(1);
|
||||||
|
expect(focusSavedElementSpy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
195
apps/client/src/services/autocomplete_core.ts
Normal file
195
apps/client/src/services/autocomplete_core.ts
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
import type { AutocompleteApi, AutocompleteSource, BaseItem } from "@algolia/autocomplete-core";
|
||||||
|
|
||||||
|
export const HEADLESS_AUTOCOMPLETE_PANEL_SELECTOR = ".aa-core-panel";
|
||||||
|
|
||||||
|
type HeadlessSourceDefaults = Required<Pick<AutocompleteSource<any>, "getItemUrl" | "onActive" | "onResolve">>;
|
||||||
|
|
||||||
|
const headlessAutocompleteClosers = new Set<() => void>();
|
||||||
|
|
||||||
|
export function withHeadlessSourceDefaults<TSource extends AutocompleteSource<any>>(
|
||||||
|
source: TSource
|
||||||
|
): TSource & HeadlessSourceDefaults {
|
||||||
|
return {
|
||||||
|
getItemUrl() {
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
onActive() {
|
||||||
|
// Headless consumers handle highlight side effects themselves.
|
||||||
|
},
|
||||||
|
onResolve() {
|
||||||
|
// Headless consumers resolve and render items manually.
|
||||||
|
},
|
||||||
|
...source
|
||||||
|
} as TSource & HeadlessSourceDefaults;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerHeadlessAutocompleteCloser(close: () => void) {
|
||||||
|
headlessAutocompleteClosers.add(close);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
headlessAutocompleteClosers.delete(close);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeAllHeadlessAutocompletes() {
|
||||||
|
for (const close of Array.from(headlessAutocompleteClosers)) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HeadlessPanelControllerOptions {
|
||||||
|
inputEl: HTMLElement;
|
||||||
|
container?: HTMLElement | null;
|
||||||
|
className?: string;
|
||||||
|
containedClassName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createHeadlessPanelController({
|
||||||
|
inputEl,
|
||||||
|
container,
|
||||||
|
className = "aa-core-panel",
|
||||||
|
containedClassName = "aa-core-panel--contained"
|
||||||
|
}: HeadlessPanelControllerOptions) {
|
||||||
|
const panelEl = document.createElement("div");
|
||||||
|
panelEl.className = className;
|
||||||
|
|
||||||
|
const isContained = Boolean(container);
|
||||||
|
if (isContained) {
|
||||||
|
panelEl.classList.add(containedClassName);
|
||||||
|
container!.appendChild(panelEl);
|
||||||
|
} else {
|
||||||
|
document.body.appendChild(panelEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
panelEl.style.display = "none";
|
||||||
|
|
||||||
|
let rafId: number | null = null;
|
||||||
|
|
||||||
|
const positionPanel = () => {
|
||||||
|
if (isContained) {
|
||||||
|
panelEl.style.position = "static";
|
||||||
|
panelEl.style.top = "";
|
||||||
|
panelEl.style.left = "";
|
||||||
|
panelEl.style.width = "100%";
|
||||||
|
panelEl.style.display = "block";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rect = inputEl.getBoundingClientRect();
|
||||||
|
panelEl.style.position = "fixed";
|
||||||
|
panelEl.style.top = `${rect.bottom}px`;
|
||||||
|
panelEl.style.left = `${rect.left}px`;
|
||||||
|
panelEl.style.width = `${rect.width}px`;
|
||||||
|
panelEl.style.display = "block";
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopPositioning = () => {
|
||||||
|
if (rafId !== null) {
|
||||||
|
cancelAnimationFrame(rafId);
|
||||||
|
rafId = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const startPositioning = () => {
|
||||||
|
if (isContained) {
|
||||||
|
positionPanel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rafId !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const update = () => {
|
||||||
|
positionPanel();
|
||||||
|
rafId = requestAnimationFrame(update);
|
||||||
|
};
|
||||||
|
|
||||||
|
update();
|
||||||
|
};
|
||||||
|
|
||||||
|
const hide = () => {
|
||||||
|
panelEl.style.display = "none";
|
||||||
|
stopPositioning();
|
||||||
|
};
|
||||||
|
|
||||||
|
const destroy = () => {
|
||||||
|
hide();
|
||||||
|
panelEl.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
panelEl,
|
||||||
|
hide,
|
||||||
|
destroy,
|
||||||
|
startPositioning,
|
||||||
|
stopPositioning
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type InputHandlers<TItem extends BaseItem> = ReturnType<AutocompleteApi<TItem>["getInputProps"]>;
|
||||||
|
|
||||||
|
interface InputBinding<TEvent extends Event = Event> {
|
||||||
|
type: string;
|
||||||
|
listener: (event: TEvent) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BindAutocompleteInputOptions<TItem extends BaseItem> {
|
||||||
|
inputEl: HTMLInputElement;
|
||||||
|
autocomplete: AutocompleteApi<TItem>;
|
||||||
|
onInput?: (event: Event, handlers: InputHandlers<TItem>) => void;
|
||||||
|
onFocus?: (event: Event, handlers: InputHandlers<TItem>) => void;
|
||||||
|
onBlur?: (event: Event, handlers: InputHandlers<TItem>) => void;
|
||||||
|
onKeyDown?: (event: KeyboardEvent, handlers: InputHandlers<TItem>) => void;
|
||||||
|
extraBindings?: InputBinding[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bindAutocompleteInput<TItem extends BaseItem>({
|
||||||
|
inputEl,
|
||||||
|
autocomplete,
|
||||||
|
onInput,
|
||||||
|
onFocus,
|
||||||
|
onBlur,
|
||||||
|
onKeyDown,
|
||||||
|
extraBindings = []
|
||||||
|
}: BindAutocompleteInputOptions<TItem>) {
|
||||||
|
const handlers = autocomplete.getInputProps({ inputElement: inputEl });
|
||||||
|
|
||||||
|
const bindings: InputBinding[] = [
|
||||||
|
{
|
||||||
|
type: "input",
|
||||||
|
listener: (event: Event) => {
|
||||||
|
onInput?.(event, handlers);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "focus",
|
||||||
|
listener: (event: Event) => {
|
||||||
|
onFocus?.(event, handlers);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "blur",
|
||||||
|
listener: (event: Event) => {
|
||||||
|
onBlur?.(event, handlers);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "keydown",
|
||||||
|
listener: (event: Event) => {
|
||||||
|
onKeyDown?.(event as KeyboardEvent, handlers);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...extraBindings
|
||||||
|
];
|
||||||
|
|
||||||
|
bindings.forEach(({ type, listener }) => {
|
||||||
|
inputEl.addEventListener(type, listener as EventListener);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
bindings.forEach(({ type, listener }) => {
|
||||||
|
inputEl.removeEventListener(type, listener as EventListener);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -103,7 +103,7 @@ async function moveToParentNote(branchIdsToMove: string[], newParentBranchId: st
|
|||||||
* @param moveToParent whether to automatically go to the parent note path after a succesful delete. Usually makes sense if deleting the active note(s).
|
* @param moveToParent whether to automatically go to the parent note path after a succesful delete. Usually makes sense if deleting the active note(s).
|
||||||
* @returns promise that returns false if the operation was cancelled or there was nothing to delete, true if the operation succeeded.
|
* @returns promise that returns false if the operation was cancelled or there was nothing to delete, true if the operation succeeded.
|
||||||
*/
|
*/
|
||||||
async function deleteNotes(branchIdsToDelete: string[], forceDeleteAllClones = false, moveToParent = true) {
|
async function deleteNotes(branchIdsToDelete: string[], forceDeleteAllClones = false, moveToParent = true, componentId?: string) {
|
||||||
branchIdsToDelete = filterRootNote(branchIdsToDelete);
|
branchIdsToDelete = filterRootNote(branchIdsToDelete);
|
||||||
|
|
||||||
if (branchIdsToDelete.length === 0) {
|
if (branchIdsToDelete.length === 0) {
|
||||||
@@ -139,9 +139,9 @@ async function deleteNotes(branchIdsToDelete: string[], forceDeleteAllClones = f
|
|||||||
const branch = froca.getBranch(branchIdToDelete);
|
const branch = froca.getBranch(branchIdToDelete);
|
||||||
|
|
||||||
if (deleteAllClones && branch) {
|
if (deleteAllClones && branch) {
|
||||||
await server.remove(`notes/${branch.noteId}${query}`);
|
await server.remove(`notes/${branch.noteId}${query}`, componentId);
|
||||||
} else {
|
} else {
|
||||||
await server.remove(`branches/${branchIdToDelete}${query}`);
|
await server.remove(`branches/${branchIdToDelete}${query}`, componentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { h, VNode } from "preact";
|
|||||||
|
|
||||||
import BasicWidget, { ReactWrappedWidget } from "../widgets/basic_widget.js";
|
import BasicWidget, { ReactWrappedWidget } from "../widgets/basic_widget.js";
|
||||||
import RightPanelWidget from "../widgets/right_panel_widget.js";
|
import RightPanelWidget from "../widgets/right_panel_widget.js";
|
||||||
import froca from "./froca.js";
|
|
||||||
import type { Entity } from "./frontend_script_api.js";
|
import type { Entity } from "./frontend_script_api.js";
|
||||||
import { WidgetDefinitionWithType } from "./frontend_script_api_preact.js";
|
import { WidgetDefinitionWithType } from "./frontend_script_api_preact.js";
|
||||||
import { t } from "./i18n.js";
|
import { t } from "./i18n.js";
|
||||||
@@ -38,15 +37,18 @@ async function getAndExecuteBundle(noteId: string, originEntity = null, script =
|
|||||||
|
|
||||||
export type ParentName = "left-pane" | "center-pane" | "note-detail-pane" | "right-pane";
|
export type ParentName = "left-pane" | "center-pane" | "note-detail-pane" | "right-pane";
|
||||||
|
|
||||||
export async function executeBundle(bundle: Bundle, originEntity?: Entity | null, $container?: JQuery<HTMLElement>) {
|
export async function executeBundleWithoutErrorHandling(bundle: Bundle, originEntity?: Entity | null, $container?: JQuery<HTMLElement>) {
|
||||||
const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity, $container);
|
const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity, $container);
|
||||||
|
return await function () {
|
||||||
|
return eval(`const apiContext = this; (async function() { ${bundle.script}\r\n})()`);
|
||||||
|
}.call(apiContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function executeBundle(bundle: Bundle, originEntity?: Entity | null, $container?: JQuery<HTMLElement>) {
|
||||||
try {
|
try {
|
||||||
return await function () {
|
return await executeBundleWithoutErrorHandling(bundle, originEntity, $container);
|
||||||
return eval(`const apiContext = this; (async function() { ${bundle.script}\r\n})()`);
|
} catch (e: unknown) {
|
||||||
}.call(apiContext);
|
showErrorForScriptNote(bundle.noteId, t("toast.bundle-error.message", { message: getErrorMessage(e) }));
|
||||||
} catch (e: any) {
|
|
||||||
showErrorForScriptNote(bundle.noteId, t("toast.bundle-error.message", { message: e.message }));
|
|
||||||
logError("Widget initialization failed: ", e);
|
logError("Widget initialization failed: ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
apps/client/src/services/content_renderer.css
Normal file
9
apps/client/src/services/content_renderer.css
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
.rendered-content.no-preview > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 500%;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import "./content_renderer.css";
|
||||||
|
|
||||||
import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons";
|
import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons";
|
||||||
|
import { h, render } from "preact";
|
||||||
import WheelZoom from 'vanilla-js-wheel-zoom';
|
import WheelZoom from 'vanilla-js-wheel-zoom';
|
||||||
|
|
||||||
import FAttachment from "../entities/fattachment.js";
|
import FAttachment from "../entities/fattachment.js";
|
||||||
@@ -13,7 +16,7 @@ import protectedSessionService from "./protected_session.js";
|
|||||||
import protectedSessionHolder from "./protected_session_holder.js";
|
import protectedSessionHolder from "./protected_session_holder.js";
|
||||||
import renderService from "./render.js";
|
import renderService from "./render.js";
|
||||||
import { applySingleBlockSyntaxHighlight } from "./syntax_highlight.js";
|
import { applySingleBlockSyntaxHighlight } from "./syntax_highlight.js";
|
||||||
import utils from "./utils.js";
|
import utils, { getErrorMessage } from "./utils.js";
|
||||||
|
|
||||||
let idCounter = 1;
|
let idCounter = 1;
|
||||||
|
|
||||||
@@ -51,16 +54,19 @@ export async function getRenderedContent(this: {} | { ctx: string }, entity: FNo
|
|||||||
await renderText(entity, $renderedContent, options);
|
await renderText(entity, $renderedContent, options);
|
||||||
} else if (type === "code") {
|
} else if (type === "code") {
|
||||||
await renderCode(entity, $renderedContent);
|
await renderCode(entity, $renderedContent);
|
||||||
} else if (["image", "canvas", "mindMap"].includes(type)) {
|
} else if (["image", "canvas", "mindMap", "spreadsheet"].includes(type)) {
|
||||||
renderImage(entity, $renderedContent, options);
|
renderImage(entity, $renderedContent, options);
|
||||||
} else if (!options.tooltip && ["file", "pdf", "audio", "video"].includes(type)) {
|
} else if (!options.tooltip && ["file", "pdf", "audio", "video"].includes(type)) {
|
||||||
renderFile(entity, type, $renderedContent);
|
await renderFile(entity, type, $renderedContent);
|
||||||
} else if (type === "mermaid") {
|
} else if (type === "mermaid") {
|
||||||
await renderMermaid(entity, $renderedContent);
|
await renderMermaid(entity, $renderedContent);
|
||||||
} else if (type === "render" && entity instanceof FNote) {
|
} else if (type === "render" && entity instanceof FNote) {
|
||||||
const $content = $("<div>");
|
const $content = $("<div>");
|
||||||
|
|
||||||
await renderService.render(entity, $content);
|
await renderService.render(entity, $content, (e) => {
|
||||||
|
const $error = $("<div>").addClass("admonition caution").text(typeof e === "string" ? e : getErrorMessage(e));
|
||||||
|
$content.empty().append($error);
|
||||||
|
});
|
||||||
|
|
||||||
$renderedContent.append($content);
|
$renderedContent.append($content);
|
||||||
} else if (type === "doc" && "noteId" in entity) {
|
} else if (type === "doc" && "noteId" in entity) {
|
||||||
@@ -71,18 +77,9 @@ export async function getRenderedContent(this: {} | { ctx: string }, entity: FNo
|
|||||||
|
|
||||||
$renderedContent.append($("<div>").append("<div>This note is protected and to access it you need to enter password.</div>").append("<br/>").append($button));
|
$renderedContent.append($("<div>").append("<div>This note is protected and to access it you need to enter password.</div>").append("<br/>").append($button));
|
||||||
} else if (entity instanceof FNote) {
|
} else if (entity instanceof FNote) {
|
||||||
$renderedContent
|
$renderedContent.addClass("no-preview");
|
||||||
.css("display", "flex")
|
|
||||||
.css("flex-direction", "column");
|
|
||||||
$renderedContent.append(
|
$renderedContent.append(
|
||||||
$("<div>")
|
$("<div>").append($("<span>").addClass(entity.getIcon()))
|
||||||
.css("display", "flex")
|
|
||||||
.css("justify-content", "space-around")
|
|
||||||
.css("align-items", "center")
|
|
||||||
.css("height", "100%")
|
|
||||||
.css("font-size", "500%")
|
|
||||||
.css("flex-grow", "1")
|
|
||||||
.append($("<span>").addClass(entity.getIcon()))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (entity.type === "webView" && entity.hasLabel("webViewSrc")) {
|
if (entity.type === "webView" && entity.hasLabel("webViewSrc")) {
|
||||||
@@ -183,7 +180,7 @@ function renderImage(entity: FNote | FAttachment, $renderedContent: JQuery<HTMLE
|
|||||||
imageContextMenuService.setupContextMenu($img);
|
imageContextMenuService.setupContextMenu($img);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFile(entity: FNote | FAttachment, type: string, $renderedContent: JQuery<HTMLElement>) {
|
async function renderFile(entity: FNote | FAttachment, type: string, $renderedContent: JQuery<HTMLElement>) {
|
||||||
let entityType, entityId;
|
let entityType, entityId;
|
||||||
|
|
||||||
if (entity instanceof FNote) {
|
if (entity instanceof FNote) {
|
||||||
@@ -196,13 +193,17 @@ function renderFile(entity: FNote | FAttachment, type: string, $renderedContent:
|
|||||||
throw new Error(`Can't recognize entity type of '${entity}'`);
|
throw new Error(`Can't recognize entity type of '${entity}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const $content = $('<div style="display: flex; flex-direction: column; height: 100%;">');
|
const $content = $('<div style="display: flex; flex-direction: column; height: 100%; justify-content: end;">');
|
||||||
|
|
||||||
if (type === "pdf") {
|
if (type === "pdf") {
|
||||||
const $pdfPreview = $('<iframe class="pdf-preview" style="width: 100%; flex-grow: 100;"></iframe>');
|
const url = `../../api/${entityType}/${entityId}/open`;
|
||||||
$pdfPreview.attr("src", openService.getUrlForDownload(`pdfjs/web/viewer.html?file=../../api/${entityType}/${entityId}/open`));
|
const $viewer = $(`<div style="height: 100%">`);
|
||||||
|
const PdfViewer = (await import("../widgets/type_widgets/file/PdfViewer")).default;
|
||||||
|
render(h(PdfViewer, {pdfUrl: url, editable: false}), $viewer.get(0)!);
|
||||||
|
|
||||||
|
$content.append($viewer);
|
||||||
|
|
||||||
|
|
||||||
$content.append($pdfPreview);
|
|
||||||
} else if (type === "audio") {
|
} else if (type === "audio") {
|
||||||
const $audioPreview = $("<audio controls></audio>")
|
const $audioPreview = $("<audio controls></audio>")
|
||||||
.attr("src", openService.getUrlForDownload(`api/${entityType}/${entityId}/open-partial`))
|
.attr("src", openService.getUrlForDownload(`api/${entityType}/${entityId}/open-partial`))
|
||||||
@@ -292,10 +293,11 @@ function getRenderingType(entity: FNote | FAttachment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mime = "mime" in entity && entity.mime;
|
const mime = "mime" in entity && entity.mime;
|
||||||
|
const isIconPack = entity instanceof FNote && entity.hasLabel("iconPack");
|
||||||
|
|
||||||
if (type === "file" && mime === "application/pdf") {
|
if (type === "file" && mime === "application/pdf") {
|
||||||
type = "pdf";
|
type = "pdf";
|
||||||
} else if ((type === "file" || type === "viewConfig") && mime && CODE_MIME_TYPES.has(mime)) {
|
} else if ((type === "file" || type === "viewConfig") && mime && CODE_MIME_TYPES.has(mime) && !isIconPack) {
|
||||||
type = "code";
|
type = "code";
|
||||||
} else if (type === "file" && mime && mime.startsWith("audio/")) {
|
} else if (type === "file" && mime && mime.startsWith("audio/")) {
|
||||||
type = "audio";
|
type = "audio";
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ async function renderChildrenList($renderedContent: JQuery<HTMLElement>, note: F
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$renderedContent.css("padding", "10px");
|
|
||||||
$renderedContent.addClass("text-with-ellipsis");
|
$renderedContent.addClass("text-with-ellipsis");
|
||||||
|
|
||||||
// just load the first 10 child notes
|
// just load the first 10 child notes
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ function createClassForColor(colorString: string | null) {
|
|||||||
return clsx("use-note-color", className, colorsWithHue.has(className) && "with-hue");
|
return clsx("use-note-color", className, colorsWithHue.has(className) && "with-hue");
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseColor(color: string) {
|
export function parseColor(color: string) {
|
||||||
try {
|
try {
|
||||||
return Color(color.toLowerCase());
|
return Color(color.toLowerCase());
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
@@ -77,7 +77,7 @@ function adjustColorLightness(color: ColorInstance, lightThemeMaxLightness: numb
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the hue of the specified color, or undefined if the color is grayscale. */
|
/** Returns the hue of the specified color, or undefined if the color is grayscale. */
|
||||||
function getHue(color: ColorInstance) {
|
export function getHue(color: ColorInstance) {
|
||||||
const hslColor = color.hsl();
|
const hslColor = color.hsl();
|
||||||
if (hslColor.saturationl() > 0) {
|
if (hslColor.saturationl() > 0) {
|
||||||
return hslColor.hue();
|
return hslColor.hue();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { dayjs } from "@triliumnext/commons";
|
import { dayjs } from "@triliumnext/commons";
|
||||||
|
|
||||||
import type { FNoteRow } from "../entities/fnote.js";
|
import type { FNoteRow } from "../entities/fnote.js";
|
||||||
import froca from "./froca.js";
|
import froca from "./froca.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
@@ -14,8 +15,13 @@ async function getTodayNote() {
|
|||||||
return await getDayNote(dayjs().format("YYYY-MM-DD"));
|
return await getDayNote(dayjs().format("YYYY-MM-DD"));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getDayNote(date: string) {
|
async function getDayNote(date: string, calendarRootId?: string) {
|
||||||
const note = await server.get<FNoteRow>(`special-notes/days/${date}`, "date-note");
|
let url = `special-notes/days/${date}`;
|
||||||
|
if (calendarRootId) {
|
||||||
|
url += `?calendarRootId=${calendarRootId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const note = await server.get<FNoteRow>(url, "date-note");
|
||||||
|
|
||||||
await ws.waitForMaxKnownEntityChangeId();
|
await ws.waitForMaxKnownEntityChangeId();
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { Modal } from "bootstrap";
|
import { Modal } from "bootstrap";
|
||||||
|
|
||||||
import appContext from "../components/app_context.js";
|
import appContext from "../components/app_context.js";
|
||||||
import type { ConfirmDialogOptions, ConfirmDialogResult, ConfirmWithMessageOptions, MessageType } from "../widgets/dialogs/confirm.js";
|
import type { ConfirmDialogOptions, ConfirmDialogResult, ConfirmWithMessageOptions, MessageType } from "../widgets/dialogs/confirm.js";
|
||||||
import type { PromptDialogOptions } from "../widgets/dialogs/prompt.js";
|
|
||||||
import { focusSavedElement, saveFocusedElement } from "./focus.js";
|
|
||||||
import { InfoExtraProps } from "../widgets/dialogs/info.jsx";
|
import { InfoExtraProps } from "../widgets/dialogs/info.jsx";
|
||||||
|
import type { PromptDialogOptions } from "../widgets/dialogs/prompt.js";
|
||||||
|
import { closeAllHeadlessAutocompletes } from "./autocomplete_core.js";
|
||||||
|
import { focusSavedElement, saveFocusedElement } from "./focus.js";
|
||||||
|
|
||||||
export async function openDialog($dialog: JQuery<HTMLElement>, closeActDialog = true, config?: Partial<Modal.Options>) {
|
export async function openDialog($dialog: JQuery<HTMLElement>, closeActDialog = true, config?: Partial<Modal.Options>) {
|
||||||
if (closeActDialog) {
|
if (closeActDialog) {
|
||||||
@@ -15,10 +17,7 @@ export async function openDialog($dialog: JQuery<HTMLElement>, closeActDialog =
|
|||||||
Modal.getOrCreateInstance($dialog[0], config).show();
|
Modal.getOrCreateInstance($dialog[0], config).show();
|
||||||
|
|
||||||
$dialog.on("hidden.bs.modal", () => {
|
$dialog.on("hidden.bs.modal", () => {
|
||||||
const $autocompleteEl = $(".aa-input");
|
closeAllHeadlessAutocompletes();
|
||||||
if ("autocomplete" in $autocompleteEl) {
|
|
||||||
$autocompleteEl.autocomplete("close");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!glob.activeDialog || glob.activeDialog === $dialog) {
|
if (!glob.activeDialog || glob.activeDialog === $dialog) {
|
||||||
focusSavedElement();
|
focusSavedElement();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { t } from "./i18n";
|
import { t } from "./i18n";
|
||||||
import options from "./options";
|
import options from "./options";
|
||||||
|
import { isMobile } from "./utils";
|
||||||
|
|
||||||
export interface ExperimentalFeature {
|
export interface ExperimentalFeature {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -21,7 +22,7 @@ let enabledFeatures: Set<ExperimentalFeatureId> | null = null;
|
|||||||
|
|
||||||
export function isExperimentalFeatureEnabled(featureId: ExperimentalFeatureId): boolean {
|
export function isExperimentalFeatureEnabled(featureId: ExperimentalFeatureId): boolean {
|
||||||
if (featureId === "new-layout") {
|
if (featureId === "new-layout") {
|
||||||
return options.is("newLayout");
|
return (isMobile() || options.is("newLayout"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return getEnabledFeatures().has(featureId);
|
return getEnabledFeatures().has(featureId);
|
||||||
@@ -29,7 +30,7 @@ export function isExperimentalFeatureEnabled(featureId: ExperimentalFeatureId):
|
|||||||
|
|
||||||
export function getEnabledExperimentalFeatureIds() {
|
export function getEnabledExperimentalFeatureIds() {
|
||||||
const values = [ ...getEnabledFeatures().values() ];
|
const values = [ ...getEnabledFeatures().values() ];
|
||||||
if (options.is("newLayout")) {
|
if (isMobile() || options.is("newLayout")) {
|
||||||
values.push("new-layout");
|
values.push("new-layout");
|
||||||
}
|
}
|
||||||
return values;
|
return values;
|
||||||
|
|||||||
@@ -110,7 +110,12 @@ function processNoteChange(loadResults: LoadResults, ec: EntityChange) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ec.componentId) {
|
// Only register as a content change if the protection status didn't change.
|
||||||
|
// When isProtected changes, the blobId change is a side effect of re-encryption,
|
||||||
|
// not a content edit. Registering it as content would cause the tree's content-only
|
||||||
|
// filter to incorrectly skip the note update (since both changes share the same
|
||||||
|
// componentId).
|
||||||
|
if (ec.componentId && note.isProtected === (ec.entity as FNoteRow).isProtected) {
|
||||||
loadResults.addNoteContent(note.noteId, ec.componentId);
|
loadResults.addNoteContent(note.noteId, ec.componentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export async function initLocale() {
|
|||||||
backend: {
|
backend: {
|
||||||
loadPath: `${window.glob.assetPath}/translations/{{lng}}/{{ns}}.json`
|
loadPath: `${window.glob.assetPath}/translations/{{lng}}/{{ns}}.json`
|
||||||
},
|
},
|
||||||
returnEmptyString: false
|
returnEmptyString: false,
|
||||||
|
showSupportNotice: false
|
||||||
});
|
});
|
||||||
|
|
||||||
await setDayjsLocale(locale);
|
await setDayjsLocale(locale);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { NoteType } from "@triliumnext/commons";
|
import { NoteType } from "@triliumnext/commons";
|
||||||
|
|
||||||
import FNote from "../entities/fnote";
|
import FNote from "../entities/fnote";
|
||||||
import { ViewTypeOptions } from "../widgets/collections/interface";
|
import { ViewTypeOptions } from "../widgets/collections/interface";
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ export const byNoteType: Record<Exclude<NoteType, "book">, string | null> = {
|
|||||||
search: null,
|
search: null,
|
||||||
text: null,
|
text: null,
|
||||||
webView: null,
|
webView: null,
|
||||||
aiChat: null
|
spreadsheet: null
|
||||||
};
|
};
|
||||||
|
|
||||||
export const byBookType: Record<ViewTypeOptions, string | null> = {
|
export const byBookType: Record<ViewTypeOptions, string | null> = {
|
||||||
@@ -39,6 +40,6 @@ export function getHelpUrlForNote(note: FNote | null | undefined) {
|
|||||||
} else if (note?.hasLabel("textSnippet")) {
|
} else if (note?.hasLabel("textSnippet")) {
|
||||||
return "pwc194wlRzcH";
|
return "pwc194wlRzcH";
|
||||||
} else if (note && note.type === "book") {
|
} else if (note && note.type === "book") {
|
||||||
return byBookType[note.getAttributeValue("label", "viewType") as ViewTypeOptions ?? ""]
|
return byBookType[note.getAttributeValue("label", "viewType") as ViewTypeOptions ?? ""];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import server from "./server.js";
|
|
||||||
import appContext from "../components/app_context.js";
|
|
||||||
import shortcutService, { ShortcutBinding } from "./shortcuts.js";
|
|
||||||
import type Component from "../components/component.js";
|
|
||||||
import type { ActionKeyboardShortcut } from "@triliumnext/commons";
|
import type { ActionKeyboardShortcut } from "@triliumnext/commons";
|
||||||
|
|
||||||
|
import appContext from "../components/app_context.js";
|
||||||
|
import type Component from "../components/component.js";
|
||||||
|
import server from "./server.js";
|
||||||
|
import shortcutService, { ShortcutBinding } from "./shortcuts.js";
|
||||||
|
|
||||||
const keyboardActionRepo: Record<string, ActionKeyboardShortcut> = {};
|
const keyboardActionRepo: Record<string, ActionKeyboardShortcut> = {};
|
||||||
|
|
||||||
const keyboardActionsLoaded = server.get<ActionKeyboardShortcut[]>("keyboard-actions").then((actions) => {
|
const keyboardActionsLoaded = server.get<ActionKeyboardShortcut[]>("keyboard-actions").then((actions) => {
|
||||||
@@ -51,7 +52,10 @@ async function setupActionsForElement(scope: string, $el: JQuery<HTMLElement>, c
|
|||||||
getActionsForScope("window").then((actions) => {
|
getActionsForScope("window").then((actions) => {
|
||||||
for (const action of actions) {
|
for (const action of actions) {
|
||||||
for (const shortcut of action.effectiveShortcuts ?? []) {
|
for (const shortcut of action.effectiveShortcuts ?? []) {
|
||||||
shortcutService.bindGlobalShortcut(shortcut, () => appContext.triggerCommand(action.actionName, { ntxId: appContext.tabManager.activeNtxId }));
|
shortcutService.bindGlobalShortcut(shortcut, () => {
|
||||||
|
const ntxId = appContext.tabManager?.activeNtxId ?? null;
|
||||||
|
appContext.triggerCommand(action.actionName, { ntxId });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,17 @@
|
|||||||
|
import type { CKTextEditor } from "@triliumnext/ckeditor5";
|
||||||
|
import { AttributeRow } from "@triliumnext/commons";
|
||||||
|
|
||||||
import appContext from "../components/app_context.js";
|
import appContext from "../components/app_context.js";
|
||||||
|
import type FBranch from "../entities/fbranch.js";
|
||||||
|
import type FNote from "../entities/fnote.js";
|
||||||
|
import type { ChooseNoteTypeResponse } from "../widgets/dialogs/note_type_chooser.js";
|
||||||
|
import froca from "./froca.js";
|
||||||
|
import { t } from "./i18n.js";
|
||||||
import protectedSessionHolder from "./protected_session_holder.js";
|
import protectedSessionHolder from "./protected_session_holder.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
import ws from "./ws.js";
|
|
||||||
import froca from "./froca.js";
|
|
||||||
import treeService from "./tree.js";
|
|
||||||
import toastService from "./toast.js";
|
import toastService from "./toast.js";
|
||||||
import { t } from "./i18n.js";
|
import treeService from "./tree.js";
|
||||||
import type FNote from "../entities/fnote.js";
|
import ws from "./ws.js";
|
||||||
import type FBranch from "../entities/fbranch.js";
|
|
||||||
import type { ChooseNoteTypeResponse } from "../widgets/dialogs/note_type_chooser.js";
|
|
||||||
import type { CKTextEditor } from "@triliumnext/ckeditor5";
|
|
||||||
|
|
||||||
export interface CreateNoteOpts {
|
export interface CreateNoteOpts {
|
||||||
isProtected?: boolean;
|
isProtected?: boolean;
|
||||||
@@ -24,6 +26,8 @@ export interface CreateNoteOpts {
|
|||||||
target?: string;
|
target?: string;
|
||||||
targetBranchId?: string;
|
targetBranchId?: string;
|
||||||
textEditor?: CKTextEditor;
|
textEditor?: CKTextEditor;
|
||||||
|
/** Attributes to be set on the note. These are set atomically on note creation, so entity changes are not sent for attributes defined here. */
|
||||||
|
attributes?: Omit<AttributeRow, "noteId" | "attributeId">[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Response {
|
interface Response {
|
||||||
@@ -37,7 +41,7 @@ interface DuplicateResponse {
|
|||||||
note: FNote;
|
note: FNote;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createNote(parentNotePath: string | undefined, options: CreateNoteOpts = {}) {
|
async function createNote(parentNotePath: string | undefined, options: CreateNoteOpts = {}, componentId?: string) {
|
||||||
options = Object.assign(
|
options = Object.assign(
|
||||||
{
|
{
|
||||||
activate: true,
|
activate: true,
|
||||||
@@ -63,22 +67,15 @@ async function createNote(parentNotePath: string | undefined, options: CreateNot
|
|||||||
|
|
||||||
const parentNoteId = treeService.getNoteIdFromUrl(parentNotePath);
|
const parentNoteId = treeService.getNoteIdFromUrl(parentNotePath);
|
||||||
|
|
||||||
if (options.type === "mermaid" && !options.content && !options.templateNoteId) {
|
|
||||||
options.content = `graph TD;
|
|
||||||
A-->B;
|
|
||||||
A-->C;
|
|
||||||
B-->D;
|
|
||||||
C-->D;`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { note, branch } = await server.post<Response>(`notes/${parentNoteId}/children?target=${options.target}&targetBranchId=${options.targetBranchId || ""}`, {
|
const { note, branch } = await server.post<Response>(`notes/${parentNoteId}/children?target=${options.target}&targetBranchId=${options.targetBranchId || ""}`, {
|
||||||
title: options.title,
|
title: options.title,
|
||||||
content: options.content || "",
|
content: options.content || "",
|
||||||
isProtected: options.isProtected,
|
isProtected: options.isProtected,
|
||||||
type: options.type,
|
type: options.type,
|
||||||
mime: options.mime,
|
mime: options.mime,
|
||||||
templateNoteId: options.templateNoteId
|
templateNoteId: options.templateNoteId,
|
||||||
});
|
attributes: options.attributes
|
||||||
|
}, componentId);
|
||||||
|
|
||||||
if (options.saveSelection) {
|
if (options.saveSelection) {
|
||||||
// we remove the selection only after it was saved to server to make sure we don't lose anything
|
// we remove the selection only after it was saved to server to make sure we don't lose anything
|
||||||
@@ -140,9 +137,8 @@ function parseSelectedHtml(selectedHtml: string) {
|
|||||||
const content = selectedHtml.replace(dom[0].outerHTML, "");
|
const content = selectedHtml.replace(dom[0].outerHTML, "");
|
||||||
|
|
||||||
return [title, content];
|
return [title, content];
|
||||||
} else {
|
|
||||||
return [null, selectedHtml];
|
|
||||||
}
|
}
|
||||||
|
return [null, selectedHtml];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function duplicateSubtree(noteId: string, parentNotePath: string) {
|
async function duplicateSubtree(noteId: string, parentNotePath: string) {
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import treeService from "./tree.js";
|
|
||||||
import linkService from "./link.js";
|
|
||||||
import froca from "./froca.js";
|
|
||||||
import utils from "./utils.js";
|
|
||||||
import attributeRenderer from "./attribute_renderer.js";
|
|
||||||
import contentRenderer from "./content_renderer.js";
|
|
||||||
import appContext from "../components/app_context.js";
|
import appContext from "../components/app_context.js";
|
||||||
import type FNote from "../entities/fnote.js";
|
import type FNote from "../entities/fnote.js";
|
||||||
|
import attributeRenderer from "./attribute_renderer.js";
|
||||||
|
import contentRenderer from "./content_renderer.js";
|
||||||
|
import froca from "./froca.js";
|
||||||
import { t } from "./i18n.js";
|
import { t } from "./i18n.js";
|
||||||
|
import linkService from "./link.js";
|
||||||
|
import treeService from "./tree.js";
|
||||||
|
import utils from "./utils.js";
|
||||||
|
|
||||||
// Track all elements that open tooltips
|
// Track all elements that open tooltips
|
||||||
let openTooltipElements: JQuery<HTMLElement>[] = [];
|
let openTooltipElements: JQuery<HTMLElement>[] = [];
|
||||||
let dismissTimer: ReturnType<typeof setTimeout>;
|
let dismissTimer: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
function setupGlobalTooltip() {
|
function setupGlobalTooltip() {
|
||||||
$(document).on("mouseenter", "a:not(.no-tooltip-preview)", mouseEnterHandler);
|
$(document).on("pointerenter", "a:not(.no-tooltip-preview)", mouseEnterHandler);
|
||||||
$(document).on("mouseenter", "[data-href]:not(.no-tooltip-preview)", mouseEnterHandler);
|
$(document).on("pointerenter", "[data-href]:not(.no-tooltip-preview)", mouseEnterHandler);
|
||||||
|
|
||||||
// close any note tooltip after click, this fixes the problem that sometimes tooltips remained on the screen
|
// close any note tooltip after click, this fixes the problem that sometimes tooltips remained on the screen
|
||||||
$(document).on("click", (e) => {
|
$(document).on("click", (e) => {
|
||||||
@@ -37,10 +37,12 @@ function dismissAllTooltips() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setupElementTooltip($el: JQuery<HTMLElement>) {
|
function setupElementTooltip($el: JQuery<HTMLElement>) {
|
||||||
$el.on("mouseenter", mouseEnterHandler);
|
$el.on("pointerenter", mouseEnterHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function mouseEnterHandler(this: HTMLElement) {
|
async function mouseEnterHandler<T>(this: HTMLElement, e: JQuery.TriggeredEvent<T, undefined, T, T>) {
|
||||||
|
if (e.pointerType !== "mouse") return;
|
||||||
|
|
||||||
const $link = $(this);
|
const $link = $(this);
|
||||||
|
|
||||||
if ($link.hasClass("no-tooltip-preview") || $link.hasClass("disabled")) {
|
if ($link.hasClass("no-tooltip-preview") || $link.hasClass("disabled")) {
|
||||||
@@ -91,7 +93,7 @@ async function mouseEnterHandler(this: HTMLElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const html = `<div class="note-tooltip-content">${content}</div>`;
|
const html = `<div class="note-tooltip-content">${content}</div>`;
|
||||||
const tooltipClass = "tooltip-" + Math.floor(Math.random() * 999_999_999);
|
const tooltipClass = `tooltip-${ Math.floor(Math.random() * 999_999_999)}`;
|
||||||
|
|
||||||
// we need to check if we're still hovering over the element
|
// we need to check if we're still hovering over the element
|
||||||
// since the operation to get tooltip content was async, it is possible that
|
// since the operation to get tooltip content was async, it is possible that
|
||||||
@@ -224,7 +226,7 @@ function renderFootnoteOrAnchor($link: JQuery<HTMLElement>, url: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let footnoteContent = $targetContent.html();
|
let footnoteContent = $targetContent.html();
|
||||||
footnoteContent = `<div class="ck-content">${footnoteContent}</div>`
|
footnoteContent = `<div class="ck-content">${footnoteContent}</div>`;
|
||||||
return footnoteContent || "";
|
return footnoteContent || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { t } from "./i18n.js";
|
|
||||||
import froca from "./froca.js";
|
|
||||||
import server from "./server.js";
|
|
||||||
import type { MenuCommandItem, MenuItem, MenuItemBadge, MenuSeparatorItem } from "../menus/context_menu.js";
|
|
||||||
import type { NoteType } from "../entities/fnote.js";
|
import type { NoteType } from "../entities/fnote.js";
|
||||||
|
import type { MenuCommandItem, MenuItem, MenuItemBadge, MenuSeparatorItem } from "../menus/context_menu.js";
|
||||||
import type { TreeCommandNames } from "../menus/tree_context_menu.js";
|
import type { TreeCommandNames } from "../menus/tree_context_menu.js";
|
||||||
|
import froca from "./froca.js";
|
||||||
|
import { t } from "./i18n.js";
|
||||||
|
import server from "./server.js";
|
||||||
|
|
||||||
export interface NoteTypeMapping {
|
export interface NoteTypeMapping {
|
||||||
type: NoteType;
|
type: NoteType;
|
||||||
@@ -26,6 +26,7 @@ export const NOTE_TYPES: NoteTypeMapping[] = [
|
|||||||
|
|
||||||
// The default note type (always the first item)
|
// The default note type (always the first item)
|
||||||
{ type: "text", mime: "text/html", title: t("note_types.text"), icon: "bx-note" },
|
{ type: "text", mime: "text/html", title: t("note_types.text"), icon: "bx-note" },
|
||||||
|
{ type: "spreadsheet", mime: "application/json", title: t("note_types.spreadsheet"), icon: "bx-table", isBeta: true },
|
||||||
|
|
||||||
// Text notes group
|
// Text notes group
|
||||||
{ type: "book", mime: "", title: t("note_types.book"), icon: "bx-book" },
|
{ type: "book", mime: "", title: t("note_types.book"), icon: "bx-book" },
|
||||||
@@ -53,7 +54,6 @@ export const NOTE_TYPES: NoteTypeMapping[] = [
|
|||||||
{ type: "file", title: t("note_types.file"), reserved: true },
|
{ type: "file", title: t("note_types.file"), reserved: true },
|
||||||
{ type: "image", title: t("note_types.image"), reserved: true },
|
{ type: "image", title: t("note_types.image"), reserved: true },
|
||||||
{ type: "launcher", mime: "", title: t("note_types.launcher"), reserved: true },
|
{ type: "launcher", mime: "", title: t("note_types.launcher"), reserved: true },
|
||||||
{ type: "aiChat", mime: "application/json", title: t("note_types.ai-chat"), reserved: true }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/** The maximum age in days for a template to be marked with the "New" badge */
|
/** The maximum age in days for a template to be marked with the "New" badge */
|
||||||
@@ -97,9 +97,9 @@ function getBlankNoteTypes(command?: TreeCommandNames): MenuItem<TreeCommandName
|
|||||||
title: nt.title,
|
title: nt.title,
|
||||||
command,
|
command,
|
||||||
type: nt.type,
|
type: nt.type,
|
||||||
uiIcon: "bx " + nt.icon,
|
uiIcon: `bx ${nt.icon}`,
|
||||||
badges: []
|
badges: []
|
||||||
}
|
};
|
||||||
|
|
||||||
if (nt.isNew) {
|
if (nt.isNew) {
|
||||||
menuItem.badges?.push(NEW_BADGE);
|
menuItem.badges?.push(NEW_BADGE);
|
||||||
@@ -131,7 +131,7 @@ async function getUserTemplates(command?: TreeCommandNames) {
|
|||||||
const item: MenuItem<TreeCommandNames> = {
|
const item: MenuItem<TreeCommandNames> = {
|
||||||
title: templateNote.title,
|
title: templateNote.title,
|
||||||
uiIcon: templateNote.getIcon(),
|
uiIcon: templateNote.getIcon(),
|
||||||
command: command,
|
command,
|
||||||
type: templateNote.type,
|
type: templateNote.type,
|
||||||
templateNoteId: templateNote.noteId
|
templateNoteId: templateNote.noteId
|
||||||
};
|
};
|
||||||
@@ -160,7 +160,7 @@ async function getBuiltInTemplates(title: string | null, command: TreeCommandNam
|
|||||||
const items: MenuItem<TreeCommandNames>[] = [];
|
const items: MenuItem<TreeCommandNames>[] = [];
|
||||||
if (title) {
|
if (title) {
|
||||||
items.push({
|
items.push({
|
||||||
title: title,
|
title,
|
||||||
kind: "header"
|
kind: "header"
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -176,7 +176,7 @@ async function getBuiltInTemplates(title: string | null, command: TreeCommandNam
|
|||||||
const item: MenuItem<TreeCommandNames> = {
|
const item: MenuItem<TreeCommandNames> = {
|
||||||
title: templateNote.title,
|
title: templateNote.title,
|
||||||
uiIcon: templateNote.getIcon(),
|
uiIcon: templateNote.getIcon(),
|
||||||
command: command,
|
command,
|
||||||
type: templateNote.type,
|
type: templateNote.type,
|
||||||
templateNoteId: templateNote.noteId
|
templateNoteId: templateNote.noteId
|
||||||
};
|
};
|
||||||
@@ -194,7 +194,7 @@ async function isNewTemplate(templateNoteId) {
|
|||||||
if (rootCreationDate === undefined) {
|
if (rootCreationDate === undefined) {
|
||||||
// Retrieve the root note creation date
|
// Retrieve the root note creation date
|
||||||
try {
|
try {
|
||||||
let rootNoteInfo: any = await server.get("notes/root");
|
const rootNoteInfo: any = await server.get("notes/root");
|
||||||
if ("dateCreated" in rootNoteInfo) {
|
if ("dateCreated" in rootNoteInfo) {
|
||||||
rootCreationDate = new Date(rootNoteInfo.dateCreated);
|
rootCreationDate = new Date(rootNoteInfo.dateCreated);
|
||||||
}
|
}
|
||||||
@@ -209,7 +209,7 @@ async function isNewTemplate(templateNoteId) {
|
|||||||
if (creationDate === undefined) {
|
if (creationDate === undefined) {
|
||||||
// The creation date isn't available in the cache, try to retrieve it from the server
|
// The creation date isn't available in the cache, try to retrieve it from the server
|
||||||
try {
|
try {
|
||||||
const noteInfo: any = await server.get("notes/" + templateNoteId);
|
const noteInfo: any = await server.get(`notes/${templateNoteId}`);
|
||||||
if ("dateCreated" in noteInfo) {
|
if ("dateCreated" in noteInfo) {
|
||||||
creationDate = new Date(noteInfo.dateCreated);
|
creationDate = new Date(noteInfo.dateCreated);
|
||||||
creationDateCache.set(templateNoteId, creationDate);
|
creationDateCache.set(templateNoteId, creationDate);
|
||||||
@@ -231,9 +231,8 @@ async function isNewTemplate(templateNoteId) {
|
|||||||
const age = (new Date().getTime() - creationDate.getTime()) / DAY_LENGTH;
|
const age = (new Date().getTime() - creationDate.getTime()) / DAY_LENGTH;
|
||||||
// Return true if the template is at most NEW_TEMPLATE_MAX_AGE days old
|
// Return true if the template is at most NEW_TEMPLATE_MAX_AGE days old
|
||||||
return (age <= NEW_TEMPLATE_MAX_AGE);
|
return (age <= NEW_TEMPLATE_MAX_AGE);
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export type LabelType = "text" | "number" | "boolean" | "date" | "datetime" | "time" | "url" | "color";
|
export type LabelType = "text" | "textarea" | "number" | "boolean" | "date" | "datetime" | "time" | "url" | "color";
|
||||||
type Multiplicity = "single" | "multi";
|
type Multiplicity = "single" | "multi";
|
||||||
|
|
||||||
export interface DefinitionObject {
|
export interface DefinitionObject {
|
||||||
@@ -17,7 +17,7 @@ function parse(value: string) {
|
|||||||
for (const token of tokens) {
|
for (const token of tokens) {
|
||||||
if (token === "promoted") {
|
if (token === "promoted") {
|
||||||
defObj.isPromoted = true;
|
defObj.isPromoted = true;
|
||||||
} else if (["text", "number", "boolean", "date", "datetime", "time", "url", "color"].includes(token)) {
|
} else if (["text", "textarea", "number", "boolean", "date", "datetime", "time", "url", "color"].includes(token)) {
|
||||||
defObj.labelType = token as LabelType;
|
defObj.labelType = token as LabelType;
|
||||||
} else if (["single", "multi"].includes(token)) {
|
} else if (["single", "multi"].includes(token)) {
|
||||||
defObj.multiplicity = token as Multiplicity;
|
defObj.multiplicity = token as Multiplicity;
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
import { h, VNode } from "preact";
|
|
||||||
|
|
||||||
import type FNote from "../entities/fnote.js";
|
|
||||||
import { renderReactWidgetAtElement } from "../widgets/react/react_utils.jsx";
|
|
||||||
import bundleService, { type Bundle } from "./bundle.js";
|
|
||||||
import froca from "./froca.js";
|
|
||||||
import server from "./server.js";
|
|
||||||
|
|
||||||
async function render(note: FNote, $el: JQuery<HTMLElement>) {
|
|
||||||
const relations = note.getRelations("renderNote");
|
|
||||||
const renderNoteIds = relations.map((rel) => rel.value).filter((noteId) => noteId);
|
|
||||||
|
|
||||||
$el.empty().toggle(renderNoteIds.length > 0);
|
|
||||||
|
|
||||||
for (const renderNoteId of renderNoteIds) {
|
|
||||||
const bundle = await server.post<Bundle>(`script/bundle/${renderNoteId}`);
|
|
||||||
|
|
||||||
const $scriptContainer = $("<div>");
|
|
||||||
$el.append($scriptContainer);
|
|
||||||
|
|
||||||
$scriptContainer.append(bundle.html);
|
|
||||||
|
|
||||||
// async so that scripts cannot block trilium execution
|
|
||||||
bundleService.executeBundle(bundle, note, $scriptContainer).then(result => {
|
|
||||||
// Render JSX
|
|
||||||
if (bundle.html === "") {
|
|
||||||
renderIfJsx(bundle, result, $el);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return renderNoteIds.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function renderIfJsx(bundle: Bundle, result: unknown, $el: JQuery<HTMLElement>) {
|
|
||||||
// Ensure the root script note is actually a JSX.
|
|
||||||
const rootScriptNoteId = await froca.getNote(bundle.noteId);
|
|
||||||
if (rootScriptNoteId?.mime !== "text/jsx") return;
|
|
||||||
|
|
||||||
// Ensure the output is a valid el.
|
|
||||||
if (typeof result !== "function") return;
|
|
||||||
|
|
||||||
// Obtain the parent component.
|
|
||||||
const closestComponent = glob.getComponentByEl($el.closest(".component")[0]);
|
|
||||||
if (!closestComponent) return;
|
|
||||||
|
|
||||||
// Render the element.
|
|
||||||
const el = h(result as () => VNode, {});
|
|
||||||
renderReactWidgetAtElement(closestComponent, el, $el[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
render
|
|
||||||
};
|
|
||||||
86
apps/client/src/services/render.tsx
Normal file
86
apps/client/src/services/render.tsx
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import { Component, h, VNode } from "preact";
|
||||||
|
|
||||||
|
import type FNote from "../entities/fnote.js";
|
||||||
|
import { renderReactWidgetAtElement } from "../widgets/react/react_utils.jsx";
|
||||||
|
import { type Bundle, executeBundleWithoutErrorHandling } from "./bundle.js";
|
||||||
|
import froca from "./froca.js";
|
||||||
|
import server from "./server.js";
|
||||||
|
|
||||||
|
type ErrorHandler = (e: unknown) => void;
|
||||||
|
|
||||||
|
async function render(note: FNote, $el: JQuery<HTMLElement>, onError?: ErrorHandler) {
|
||||||
|
const relations = note.getRelations("renderNote");
|
||||||
|
const renderNoteIds = relations.map((rel) => rel.value).filter((noteId) => noteId);
|
||||||
|
|
||||||
|
$el.empty().toggle(renderNoteIds.length > 0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (const renderNoteId of renderNoteIds) {
|
||||||
|
const bundle = await server.postWithSilentInternalServerError<Bundle>(`script/bundle/${renderNoteId}`);
|
||||||
|
|
||||||
|
const $scriptContainer = $("<div>");
|
||||||
|
$el.append($scriptContainer);
|
||||||
|
|
||||||
|
$scriptContainer.append(bundle.html);
|
||||||
|
|
||||||
|
// async so that scripts cannot block trilium execution
|
||||||
|
executeBundleWithoutErrorHandling(bundle, note, $scriptContainer)
|
||||||
|
.catch(onError)
|
||||||
|
.then(result => {
|
||||||
|
// Render JSX
|
||||||
|
if (bundle.html === "") {
|
||||||
|
renderIfJsx(bundle, result, $el, onError).catch(onError);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderNoteIds.length > 0;
|
||||||
|
} catch (e) {
|
||||||
|
if (typeof e === "string" && e.startsWith("{") && e.endsWith("}")) {
|
||||||
|
try {
|
||||||
|
onError?.(JSON.parse(e));
|
||||||
|
} catch (e) {
|
||||||
|
onError?.(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onError?.(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function renderIfJsx(bundle: Bundle, result: unknown, $el: JQuery<HTMLElement>, onError?: ErrorHandler) {
|
||||||
|
// Ensure the root script note is actually a JSX.
|
||||||
|
const rootScriptNoteId = await froca.getNote(bundle.noteId);
|
||||||
|
if (rootScriptNoteId?.mime !== "text/jsx") return;
|
||||||
|
|
||||||
|
// Ensure the output is a valid el.
|
||||||
|
if (typeof result !== "function") return;
|
||||||
|
|
||||||
|
// Obtain the parent component.
|
||||||
|
const closestComponent = glob.getComponentByEl($el.closest(".component")[0]);
|
||||||
|
if (!closestComponent) return;
|
||||||
|
|
||||||
|
// Render the element.
|
||||||
|
const UserErrorBoundary = class UserErrorBoundary extends Component {
|
||||||
|
constructor(props: object) {
|
||||||
|
super(props);
|
||||||
|
this.state = { error: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidCatch(error: unknown) {
|
||||||
|
onError?.(error);
|
||||||
|
this.setState({ error });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if ("error" in this.state && this.state?.error) return null;
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const el = h(UserErrorBoundary, {}, h(result as () => VNode, {}));
|
||||||
|
renderReactWidgetAtElement(closestComponent, el, $el[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
render
|
||||||
|
};
|
||||||
@@ -73,6 +73,10 @@ async function post<T>(url: string, data?: unknown, componentId?: string) {
|
|||||||
return await call<T>("POST", url, componentId, { data });
|
return await call<T>("POST", url, componentId, { data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function postWithSilentInternalServerError<T>(url: string, data?: unknown, componentId?: string) {
|
||||||
|
return await call<T>("POST", url, componentId, { data, silentInternalServerError: true });
|
||||||
|
}
|
||||||
|
|
||||||
async function put<T>(url: string, data?: unknown, componentId?: string) {
|
async function put<T>(url: string, data?: unknown, componentId?: string) {
|
||||||
return await call<T>("PUT", url, componentId, { data });
|
return await call<T>("PUT", url, componentId, { data });
|
||||||
}
|
}
|
||||||
@@ -85,21 +89,33 @@ async function remove<T>(url: string, componentId?: string) {
|
|||||||
return await call<T>("DELETE", url, componentId);
|
return await call<T>("DELETE", url, componentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function upload(url: string, fileToUpload: File, componentId?: string) {
|
async function upload(url: string, fileToUpload: File, componentId?: string, method = "PUT") {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("upload", fileToUpload);
|
formData.append("upload", fileToUpload);
|
||||||
|
|
||||||
return await $.ajax({
|
const doUpload = async () => $.ajax({
|
||||||
url: window.glob.baseApiUrl + url,
|
url: window.glob.baseApiUrl + url,
|
||||||
headers: await getHeaders(componentId ? {
|
headers: await getHeaders(componentId ? {
|
||||||
"trilium-component-id": componentId
|
"trilium-component-id": componentId
|
||||||
} : undefined),
|
} : undefined),
|
||||||
data: formData,
|
data: formData,
|
||||||
type: "PUT",
|
type: method,
|
||||||
timeout: 60 * 60 * 1000,
|
timeout: 60 * 60 * 1000,
|
||||||
contentType: false, // NEEDED, DON'T REMOVE THIS
|
contentType: false, // NEEDED, DON'T REMOVE THIS
|
||||||
processData: false // NEEDED, DON'T REMOVE THIS
|
processData: false // NEEDED, DON'T REMOVE THIS
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await doUpload();
|
||||||
|
} catch (e: unknown) {
|
||||||
|
// jQuery rejects with the jqXHR object
|
||||||
|
const jqXhr = e as JQuery.jqXHR;
|
||||||
|
if (jqXhr?.status && isCsrfError(jqXhr.status, jqXhr.responseText)) {
|
||||||
|
await refreshCsrfToken();
|
||||||
|
return await doUpload();
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let idCounter = 1;
|
let idCounter = 1;
|
||||||
@@ -108,11 +124,55 @@ const idToRequestMap: Record<string, RequestData> = {};
|
|||||||
|
|
||||||
let maxKnownEntityChangeId = 0;
|
let maxKnownEntityChangeId = 0;
|
||||||
|
|
||||||
|
let csrfRefreshInProgress: Promise<void> | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-fetches /bootstrap to obtain a fresh CSRF token. This is needed when the
|
||||||
|
* server session expires (e.g. mobile tab backgrounded for a long time) and the
|
||||||
|
* existing CSRF token is no longer valid.
|
||||||
|
*
|
||||||
|
* Coalesces concurrent calls so only one bootstrap request is in-flight at a time.
|
||||||
|
*/
|
||||||
|
async function refreshCsrfToken(): Promise<void> {
|
||||||
|
if (csrfRefreshInProgress) {
|
||||||
|
return csrfRefreshInProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
csrfRefreshInProgress = (async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`./bootstrap${window.location.search}`, { cache: "no-store" });
|
||||||
|
if (response.ok) {
|
||||||
|
const json = await response.json();
|
||||||
|
glob.csrfToken = json.csrfToken;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
csrfRefreshInProgress = null;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
return csrfRefreshInProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCsrfError(status: number, responseText: string): boolean {
|
||||||
|
if (status !== 403) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const body = JSON.parse(responseText);
|
||||||
|
return body.message === "Invalid CSRF token";
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface CallOptions {
|
interface CallOptions {
|
||||||
data?: unknown;
|
data?: unknown;
|
||||||
silentNotFound?: boolean;
|
silentNotFound?: boolean;
|
||||||
|
silentInternalServerError?: boolean;
|
||||||
// If `true`, the value will be returned as a string instead of a JavaScript object if JSON, XMLDocument if XML, etc.
|
// If `true`, the value will be returned as a string instead of a JavaScript object if JSON, XMLDocument if XML, etc.
|
||||||
raw?: boolean;
|
raw?: boolean;
|
||||||
|
/** Used internally to prevent infinite retry loops on CSRF refresh. */
|
||||||
|
csrfRetried?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function call<T>(method: string, url: string, componentId?: string, options: CallOptions = {}) {
|
async function call<T>(method: string, url: string, componentId?: string, options: CallOptions = {}) {
|
||||||
@@ -143,7 +203,7 @@ async function call<T>(method: string, url: string, componentId?: string, option
|
|||||||
});
|
});
|
||||||
})) as any;
|
})) as any;
|
||||||
} else {
|
} else {
|
||||||
resp = await ajax(url, method, data, headers, !!options.silentNotFound, options.raw);
|
resp = await ajax(url, method, data, headers, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxEntityChangeIdStr = resp.headers["trilium-max-entity-change-id"];
|
const maxEntityChangeIdStr = resp.headers["trilium-max-entity-change-id"];
|
||||||
@@ -155,17 +215,14 @@ async function call<T>(method: string, url: string, componentId?: string, option
|
|||||||
return resp.body as T;
|
return resp.body as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function ajax(url: string, method: string, data: unknown, headers: Headers, opts: CallOptions): Promise<Response> {
|
||||||
* @param raw if `true`, the value will be returned as a string instead of a JavaScript object if JSON, XMLDocument if XML, etc.
|
|
||||||
*/
|
|
||||||
function ajax(url: string, method: string, data: unknown, headers: Headers, silentNotFound: boolean, raw?: boolean): Promise<Response> {
|
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
const options: JQueryAjaxSettings = {
|
const options: JQueryAjaxSettings = {
|
||||||
url: window.glob.baseApiUrl + url,
|
url: window.glob.baseApiUrl + url,
|
||||||
type: method,
|
type: method,
|
||||||
headers,
|
headers,
|
||||||
timeout: 60000,
|
timeout: 60000,
|
||||||
success: (body, textStatus, jqXhr) => {
|
success: (body, _textStatus, jqXhr) => {
|
||||||
const respHeaders: Headers = {};
|
const respHeaders: Headers = {};
|
||||||
|
|
||||||
jqXhr
|
jqXhr
|
||||||
@@ -190,7 +247,27 @@ function ajax(url: string, method: string, data: unknown, headers: Headers, sile
|
|||||||
// don't report requests that are rejected by the browser, usually when the user is refreshing or going to a different page.
|
// don't report requests that are rejected by the browser, usually when the user is refreshing or going to a different page.
|
||||||
rej("rejected by browser");
|
rej("rejected by browser");
|
||||||
return;
|
return;
|
||||||
} else if (silentNotFound && jqXhr.status === 404) {
|
}
|
||||||
|
|
||||||
|
// If the CSRF token is stale (e.g. session expired while tab was backgrounded),
|
||||||
|
// refresh it and retry the request once.
|
||||||
|
if (!opts.csrfRetried && isCsrfError(jqXhr.status, jqXhr.responseText)) {
|
||||||
|
try {
|
||||||
|
await refreshCsrfToken();
|
||||||
|
// Rebuild headers so the fresh glob.csrfToken is picked up
|
||||||
|
const retryHeaders = await getHeaders({ "trilium-component-id": headers["trilium-component-id"] });
|
||||||
|
const retryResult = await ajax(url, method, data, retryHeaders, { ...opts, csrfRetried: true });
|
||||||
|
res(retryResult);
|
||||||
|
return;
|
||||||
|
} catch (retryErr) {
|
||||||
|
rej(retryErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.silentNotFound && jqXhr.status === 404) {
|
||||||
|
// report nothing
|
||||||
|
} else if (opts.silentInternalServerError && jqXhr.status === 500) {
|
||||||
// report nothing
|
// report nothing
|
||||||
} else {
|
} else {
|
||||||
await reportError(method, url, jqXhr.status, jqXhr.responseText);
|
await reportError(method, url, jqXhr.status, jqXhr.responseText);
|
||||||
@@ -200,7 +277,7 @@ function ajax(url: string, method: string, data: unknown, headers: Headers, sile
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (raw) {
|
if (opts.raw) {
|
||||||
options.dataType = "text";
|
options.dataType = "text";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,6 +376,7 @@ export default {
|
|||||||
get,
|
get,
|
||||||
getWithSilentNotFound,
|
getWithSilentNotFound,
|
||||||
post,
|
post,
|
||||||
|
postWithSilentInternalServerError,
|
||||||
put,
|
put,
|
||||||
patch,
|
patch,
|
||||||
remove,
|
remove,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import shortcuts, { keyMatches, matchesShortcut, isIMEComposing } from "./shortcuts.js";
|
|
||||||
|
import shortcuts, { isIMEComposing, keyMatches, matchesShortcut } from "./shortcuts.js";
|
||||||
|
|
||||||
// Mock utils module
|
// Mock utils module
|
||||||
vi.mock("./utils.js", () => ({
|
vi.mock("./utils.js", () => ({
|
||||||
@@ -61,9 +62,10 @@ describe("shortcuts", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("keyMatches", () => {
|
describe("keyMatches", () => {
|
||||||
const createKeyboardEvent = (key: string, code?: string) => ({
|
const createKeyboardEvent = (key: string, code?: string, extraProps: Partial<KeyboardEvent> = {}) => ({
|
||||||
key,
|
key,
|
||||||
code: code || `Key${key.toUpperCase()}`
|
code: code || `Key${key.toUpperCase()}`,
|
||||||
|
...extraProps
|
||||||
} as KeyboardEvent);
|
} as KeyboardEvent);
|
||||||
|
|
||||||
it("should match regular letter keys using key code", () => {
|
it("should match regular letter keys using key code", () => {
|
||||||
@@ -101,17 +103,23 @@ describe("shortcuts", () => {
|
|||||||
consoleSpy.mockRestore();
|
consoleSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should match azerty keys", () => {
|
||||||
|
const event = createKeyboardEvent("A", "KeyQ");
|
||||||
|
expect(keyMatches(event, "a")).toBe(true);
|
||||||
|
expect(keyMatches(event, "q")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
it("should match letter keys using code when key is a special character (macOS Alt behavior)", () => {
|
it("should match letter keys using code when key is a special character (macOS Alt behavior)", () => {
|
||||||
// On macOS, pressing Option/Alt + A produces 'å' as the key, but code is still 'KeyA'
|
// On macOS, pressing Option/Alt + A produces 'å' as the key, but code is still 'KeyA'
|
||||||
const macOSAltAEvent = createKeyboardEvent("å", "KeyA");
|
const macOSAltAEvent = createKeyboardEvent("å", "KeyA", { altKey: true });
|
||||||
expect(keyMatches(macOSAltAEvent, "a")).toBe(true);
|
expect(keyMatches(macOSAltAEvent, "a")).toBe(true);
|
||||||
|
|
||||||
// Option + H produces '˙'
|
// Option + H produces '˙'
|
||||||
const macOSAltHEvent = createKeyboardEvent("˙", "KeyH");
|
const macOSAltHEvent = createKeyboardEvent("˙", "KeyH", { altKey: true });
|
||||||
expect(keyMatches(macOSAltHEvent, "h")).toBe(true);
|
expect(keyMatches(macOSAltHEvent, "h")).toBe(true);
|
||||||
|
|
||||||
// Option + S produces 'ß'
|
// Option + S produces 'ß'
|
||||||
const macOSAltSEvent = createKeyboardEvent("ß", "KeyS");
|
const macOSAltSEvent = createKeyboardEvent("ß", "KeyS", { altKey: true });
|
||||||
expect(keyMatches(macOSAltSEvent, "s")).toBe(true);
|
expect(keyMatches(macOSAltSEvent, "s")).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -215,6 +223,15 @@ describe("shortcuts", () => {
|
|||||||
consoleSpy.mockRestore();
|
consoleSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("matches azerty", () => {
|
||||||
|
const event = createKeyboardEvent({
|
||||||
|
key: "a",
|
||||||
|
code: "KeyQ",
|
||||||
|
ctrlKey: true
|
||||||
|
});
|
||||||
|
expect(matchesShortcut(event, "Ctrl+A")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("should match Alt+letter shortcuts on macOS where key is a special character", () => {
|
it("should match Alt+letter shortcuts on macOS where key is a special character", () => {
|
||||||
// On macOS, pressing Option/Alt + A produces 'å' but code remains 'KeyA'
|
// On macOS, pressing Option/Alt + A produces 'å' but code remains 'KeyA'
|
||||||
const macOSAltAEvent = createKeyboardEvent({
|
const macOSAltAEvent = createKeyboardEvent({
|
||||||
|
|||||||
@@ -215,9 +215,12 @@ export function keyMatches(e: KeyboardEvent, key: string): boolean {
|
|||||||
// For letter keys, use the physical key code for consistency
|
// For letter keys, use the physical key code for consistency
|
||||||
// On macOS, Option/Alt key produces special characters, so we must use e.code
|
// On macOS, Option/Alt key produces special characters, so we must use e.code
|
||||||
if (key.length === 1 && key >= 'a' && key <= 'z') {
|
if (key.length === 1 && key >= 'a' && key <= 'z') {
|
||||||
// e.code is like "KeyA", "KeyB", etc.
|
if (e.altKey) {
|
||||||
const expectedCode = `Key${key.toUpperCase()}`;
|
// e.code is like "KeyA", "KeyB", etc.
|
||||||
return e.code === expectedCode || e.key.toLowerCase() === key.toLowerCase();
|
const expectedCode = `Key${key.toUpperCase()}`;
|
||||||
|
return e.code === expectedCode || e.key.toLowerCase() === key.toLowerCase();
|
||||||
|
}
|
||||||
|
return e.key.toLowerCase() === key.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
// For regular keys, check both key and code as fallback
|
// For regular keys, check both key and code as fallback
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export default class SpacedUpdate {
|
|||||||
private updateInterval: number;
|
private updateInterval: number;
|
||||||
private changeForbidden?: boolean;
|
private changeForbidden?: boolean;
|
||||||
private stateCallback?: StateCallback;
|
private stateCallback?: StateCallback;
|
||||||
|
private lastState: SaveState = "saved";
|
||||||
|
|
||||||
constructor(updater: Callback, updateInterval = 1000, stateCallback?: StateCallback) {
|
constructor(updater: Callback, updateInterval = 1000, stateCallback?: StateCallback) {
|
||||||
this.updater = updater;
|
this.updater = updater;
|
||||||
@@ -24,7 +25,7 @@ export default class SpacedUpdate {
|
|||||||
scheduleUpdate() {
|
scheduleUpdate() {
|
||||||
if (!this.changeForbidden) {
|
if (!this.changeForbidden) {
|
||||||
this.changed = true;
|
this.changed = true;
|
||||||
this.stateCallback?.("unsaved");
|
this.onStateChanged("unsaved");
|
||||||
setTimeout(() => this.triggerUpdate());
|
setTimeout(() => this.triggerUpdate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,12 +35,12 @@ export default class SpacedUpdate {
|
|||||||
this.changed = false; // optimistic...
|
this.changed = false; // optimistic...
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.stateCallback?.("saving");
|
this.onStateChanged("saving");
|
||||||
await this.updater();
|
await this.updater();
|
||||||
this.stateCallback?.("saved");
|
this.onStateChanged("saved");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.changed = true;
|
this.changed = true;
|
||||||
this.stateCallback?.("error");
|
this.onStateChanged("error");
|
||||||
logError(getErrorMessage(e));
|
logError(getErrorMessage(e));
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@@ -76,13 +77,13 @@ export default class SpacedUpdate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Date.now() - this.lastUpdated > this.updateInterval) {
|
if (Date.now() - this.lastUpdated > this.updateInterval) {
|
||||||
this.stateCallback?.("saving");
|
this.onStateChanged("saving");
|
||||||
try {
|
try {
|
||||||
await this.updater();
|
await this.updater();
|
||||||
this.stateCallback?.("saved");
|
this.onStateChanged("saved");
|
||||||
this.changed = false;
|
this.changed = false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.stateCallback?.("error");
|
this.onStateChanged("error");
|
||||||
logError(getErrorMessage(e));
|
logError(getErrorMessage(e));
|
||||||
}
|
}
|
||||||
this.lastUpdated = Date.now();
|
this.lastUpdated = Date.now();
|
||||||
@@ -92,6 +93,13 @@ export default class SpacedUpdate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onStateChanged(state: SaveState) {
|
||||||
|
if (state === this.lastState) return;
|
||||||
|
|
||||||
|
this.stateCallback?.(state);
|
||||||
|
this.lastState = state;
|
||||||
|
}
|
||||||
|
|
||||||
async allowUpdateWithoutChange(callback: Callback) {
|
async allowUpdateWithoutChange(callback: Callback) {
|
||||||
this.changeForbidden = true;
|
this.changeForbidden = true;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { ensureMimeTypes, highlight, highlightAuto, loadTheme, Themes, type AutoHighlightResult, type HighlightResult, type Theme } from "@triliumnext/highlightjs";
|
import { MimeType } from "@triliumnext/commons";
|
||||||
|
import { type AutoHighlightResult, ensureMimeTypes, highlight, highlightAuto, type HighlightResult, loadTheme, type Theme,Themes } from "@triliumnext/highlightjs";
|
||||||
|
|
||||||
|
import { copyText, copyTextWithToast } from "./clipboard_ext.js";
|
||||||
|
import { t } from "./i18n.js";
|
||||||
import mime_types from "./mime_types.js";
|
import mime_types from "./mime_types.js";
|
||||||
import options from "./options.js";
|
import options from "./options.js";
|
||||||
import { t } from "./i18n.js";
|
|
||||||
import { copyText, copyTextWithToast } from "./clipboard_ext.js";
|
|
||||||
import { isShare } from "./utils.js";
|
import { isShare } from "./utils.js";
|
||||||
import { MimeType } from "@triliumnext/commons";
|
|
||||||
|
|
||||||
let highlightingLoaded = false;
|
let highlightingLoaded = false;
|
||||||
|
|
||||||
@@ -76,13 +77,15 @@ export async function applySingleBlockSyntaxHighlight($codeBlock: JQuery<HTMLEle
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function ensureMimeTypesForHighlighting(mimeTypeHint?: string) {
|
export async function ensureMimeTypesForHighlighting(mimeTypeHint?: string) {
|
||||||
if (highlightingLoaded) {
|
if (!mimeTypeHint && highlightingLoaded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load theme.
|
// Load theme.
|
||||||
const currentThemeName = String(options.get("codeBlockTheme"));
|
if (!highlightingLoaded) {
|
||||||
await loadHighlightingTheme(currentThemeName);
|
const currentThemeName = String(options.get("codeBlockTheme"));
|
||||||
|
await loadHighlightingTheme(currentThemeName);
|
||||||
|
}
|
||||||
|
|
||||||
// Load mime types.
|
// Load mime types.
|
||||||
let mimeTypes: MimeType[];
|
let mimeTypes: MimeType[];
|
||||||
@@ -94,7 +97,7 @@ export async function ensureMimeTypesForHighlighting(mimeTypeHint?: string) {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
mime: mimeTypeHint.replace("-", "/")
|
mime: mimeTypeHint.replace("-", "/")
|
||||||
}
|
}
|
||||||
]
|
];
|
||||||
} else {
|
} else {
|
||||||
mimeTypes = mime_types.getMimeTypes();
|
mimeTypes = mime_types.getMimeTypes();
|
||||||
}
|
}
|
||||||
@@ -124,9 +127,9 @@ export function isSyntaxHighlightEnabled() {
|
|||||||
if (!isShare) {
|
if (!isShare) {
|
||||||
const theme = options.get("codeBlockTheme");
|
const theme = options.get("codeBlockTheme");
|
||||||
return !!theme && theme !== "none";
|
return !!theme && theme !== "none";
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ export function reloadFrontendApp(reason?: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isElectron()) {
|
if (isElectron()) {
|
||||||
dynamicRequire("@electron/remote").BrowserWindow.getFocusedWindow()?.reload();
|
for (const window of dynamicRequire("@electron/remote").BrowserWindow.getAllWindows()) {
|
||||||
|
window.reload();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,49 +133,6 @@ async function handleMessage(event: MessageEvent<any>) {
|
|||||||
appContext.triggerEvent("apiLogMessages", { noteId: message.noteId, messages: message.messages });
|
appContext.triggerEvent("apiLogMessages", { noteId: message.noteId, messages: message.messages });
|
||||||
} else if (message.type === "toast") {
|
} else if (message.type === "toast") {
|
||||||
toastService.showMessage(message.message);
|
toastService.showMessage(message.message);
|
||||||
} else if (message.type === "llm-stream") {
|
|
||||||
// ENHANCED LOGGING FOR DEBUGGING
|
|
||||||
console.log(`[WS-CLIENT] >>> RECEIVED LLM STREAM MESSAGE <<<`);
|
|
||||||
console.log(`[WS-CLIENT] Message details: sessionId=${message.sessionId}, hasContent=${!!message.content}, contentLength=${message.content ? message.content.length : 0}, hasThinking=${!!message.thinking}, hasToolExecution=${!!message.toolExecution}, isDone=${!!message.done}`);
|
|
||||||
|
|
||||||
if (message.content) {
|
|
||||||
console.log(`[WS-CLIENT] CONTENT PREVIEW: "${message.content.substring(0, 50)}..."`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the event with detailed logging
|
|
||||||
console.log(`[WS-CLIENT] Creating CustomEvent 'llm-stream-message'`);
|
|
||||||
const llmStreamEvent = new CustomEvent('llm-stream-message', { detail: message });
|
|
||||||
|
|
||||||
// Dispatch to multiple targets to ensure delivery
|
|
||||||
try {
|
|
||||||
console.log(`[WS-CLIENT] Dispatching event to window`);
|
|
||||||
window.dispatchEvent(llmStreamEvent);
|
|
||||||
console.log(`[WS-CLIENT] Event dispatched to window`);
|
|
||||||
|
|
||||||
// Also try document for completeness
|
|
||||||
console.log(`[WS-CLIENT] Dispatching event to document`);
|
|
||||||
document.dispatchEvent(new CustomEvent('llm-stream-message', { detail: message }));
|
|
||||||
console.log(`[WS-CLIENT] Event dispatched to document`);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`[WS-CLIENT] Error dispatching event:`, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug current listeners (though we can't directly check for specific event listeners)
|
|
||||||
console.log(`[WS-CLIENT] Active event listeners should receive this message now`);
|
|
||||||
|
|
||||||
// Detailed logging based on message type
|
|
||||||
if (message.content) {
|
|
||||||
console.log(`[WS-CLIENT] Content message: ${message.content.length} chars`);
|
|
||||||
} else if (message.thinking) {
|
|
||||||
console.log(`[WS-CLIENT] Thinking update: "${message.thinking}"`);
|
|
||||||
} else if (message.toolExecution) {
|
|
||||||
console.log(`[WS-CLIENT] Tool execution: action=${message.toolExecution.action}, tool=${message.toolExecution.tool || 'unknown'}`);
|
|
||||||
if (message.toolExecution.result) {
|
|
||||||
console.log(`[WS-CLIENT] Tool result preview: "${String(message.toolExecution.result).substring(0, 50)}..."`);
|
|
||||||
}
|
|
||||||
} else if (message.done) {
|
|
||||||
console.log(`[WS-CLIENT] Completion signal received`);
|
|
||||||
}
|
|
||||||
} else if (message.type === "execute-script") {
|
} else if (message.type === "execute-script") {
|
||||||
// TODO: Remove after porting the file
|
// TODO: Remove after porting the file
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
@@ -1,66 +1,107 @@
|
|||||||
import "jquery";
|
import "jquery";
|
||||||
|
|
||||||
import utils from "./services/utils.js";
|
import utils from "./services/utils.js";
|
||||||
import ko from "knockout";
|
|
||||||
|
|
||||||
// TriliumNextTODO: properly make use of below types
|
type SetupStep = "sync-in-progress" | "setup-type" | "new-document-in-progress" | "sync-from-desktop" | "sync-from-server";
|
||||||
// type SetupModelSetupType = "new-document" | "sync-from-desktop" | "sync-from-server" | "";
|
type SetupType = "new-document" | "sync-from-desktop" | "sync-from-server" | "";
|
||||||
// type SetupModelStep = "sync-in-progress" | "setup-type" | "new-document-in-progress" | "sync-from-desktop";
|
|
||||||
|
|
||||||
class SetupModel {
|
class SetupController {
|
||||||
syncInProgress: boolean;
|
private step: SetupStep;
|
||||||
step: ko.Observable<string>;
|
private setupType: SetupType = "";
|
||||||
setupType: ko.Observable<string>;
|
private syncPollIntervalId: number | null = null;
|
||||||
setupNewDocument: ko.Observable<boolean>;
|
private rootNode: HTMLElement;
|
||||||
setupSyncFromDesktop: ko.Observable<boolean>;
|
private setupTypeForm: HTMLFormElement;
|
||||||
setupSyncFromServer: ko.Observable<boolean>;
|
private syncFromServerForm: HTMLFormElement;
|
||||||
syncServerHost: ko.Observable<string | undefined>;
|
private setupTypeNextButton: HTMLButtonElement;
|
||||||
syncProxy: ko.Observable<string | undefined>;
|
private setupTypeInputs: HTMLInputElement[];
|
||||||
password: ko.Observable<string | undefined>;
|
private syncServerHostInput: HTMLInputElement;
|
||||||
|
private syncProxyInput: HTMLInputElement;
|
||||||
|
private passwordInput: HTMLInputElement;
|
||||||
|
private sections: Record<SetupStep, HTMLElement>;
|
||||||
|
|
||||||
constructor(syncInProgress: boolean) {
|
constructor(rootNode: HTMLElement, syncInProgress: boolean) {
|
||||||
this.syncInProgress = syncInProgress;
|
this.rootNode = rootNode;
|
||||||
this.step = ko.observable(syncInProgress ? "sync-in-progress" : "setup-type");
|
this.step = syncInProgress ? "sync-in-progress" : "setup-type";
|
||||||
this.setupType = ko.observable("");
|
this.setupTypeForm = mustGetElement("setup-type-form", HTMLFormElement);
|
||||||
this.setupNewDocument = ko.observable(false);
|
this.syncFromServerForm = mustGetElement("sync-from-server-form", HTMLFormElement);
|
||||||
this.setupSyncFromDesktop = ko.observable(false);
|
this.setupTypeNextButton = mustGetElement("setup-type-next", HTMLButtonElement);
|
||||||
this.setupSyncFromServer = ko.observable(false);
|
this.setupTypeInputs = Array.from(document.querySelectorAll<HTMLInputElement>("input[name='setup-type']"));
|
||||||
this.syncServerHost = ko.observable();
|
this.syncServerHostInput = mustGetElement("sync-server-host", HTMLInputElement);
|
||||||
this.syncProxy = ko.observable();
|
this.syncProxyInput = mustGetElement("sync-proxy", HTMLInputElement);
|
||||||
this.password = ko.observable();
|
this.passwordInput = mustGetElement("password", HTMLInputElement);
|
||||||
|
this.sections = {
|
||||||
|
"setup-type": mustGetElement("setup-type-section", HTMLElement),
|
||||||
|
"new-document-in-progress": mustGetElement("new-document-in-progress-section", HTMLElement),
|
||||||
|
"sync-from-desktop": mustGetElement("sync-from-desktop-section", HTMLElement),
|
||||||
|
"sync-from-server": mustGetElement("sync-from-server-section", HTMLElement),
|
||||||
|
"sync-in-progress": mustGetElement("sync-in-progress-section", HTMLElement)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (this.syncInProgress) {
|
init() {
|
||||||
setInterval(checkOutstandingSyncs, 1000);
|
this.setupTypeForm.addEventListener("submit", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
void this.selectSetupType();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.syncFromServerForm.addEventListener("submit", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
void this.finish();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const input of this.setupTypeInputs) {
|
||||||
|
input.addEventListener("change", () => {
|
||||||
|
this.setupType = input.value as SetupType;
|
||||||
|
this.render();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const backButton of document.querySelectorAll<HTMLElement>("[data-action='back']")) {
|
||||||
|
backButton.addEventListener("click", () => {
|
||||||
|
this.back();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const serverAddress = `${location.protocol}//${location.host}`;
|
const serverAddress = `${location.protocol}//${location.host}`;
|
||||||
$("#current-host").html(serverAddress);
|
$("#current-host").html(serverAddress);
|
||||||
|
|
||||||
|
if (this.step === "sync-in-progress") {
|
||||||
|
this.startSyncPolling();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.render();
|
||||||
|
this.rootNode.style.display = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is called in setup.ejs
|
private async selectSetupType() {
|
||||||
setupTypeSelected() {
|
if (this.setupType === "new-document") {
|
||||||
return !!this.setupType();
|
this.setStep("new-document-in-progress");
|
||||||
}
|
|
||||||
|
|
||||||
selectSetupType() {
|
await $.post("api/setup/new-document");
|
||||||
if (this.setupType() === "new-document") {
|
window.location.replace("./setup");
|
||||||
this.step("new-document-in-progress");
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$.post("api/setup/new-document").then(() => {
|
if (this.setupType) {
|
||||||
window.location.replace("./setup");
|
this.setStep(this.setupType);
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.step(this.setupType());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
back() {
|
private back() {
|
||||||
this.step("setup-type");
|
this.setStep("setup-type");
|
||||||
this.setupType("");
|
this.setupType = "";
|
||||||
|
|
||||||
|
for (const input of this.setupTypeInputs) {
|
||||||
|
input.checked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
async finish() {
|
private async finish() {
|
||||||
const syncServerHost = this.syncServerHost();
|
const syncServerHost = this.syncServerHostInput.value.trim();
|
||||||
const syncProxy = this.syncProxy();
|
const syncProxy = this.syncProxyInput.value.trim();
|
||||||
const password = this.password();
|
const password = this.passwordInput.value;
|
||||||
|
|
||||||
if (!syncServerHost) {
|
if (!syncServerHost) {
|
||||||
showAlert("Trilium server address can't be empty");
|
showAlert("Trilium server address can't be empty");
|
||||||
@@ -74,21 +115,44 @@ class SetupModel {
|
|||||||
|
|
||||||
// not using server.js because it loads too many dependencies
|
// not using server.js because it loads too many dependencies
|
||||||
const resp = await $.post("api/setup/sync-from-server", {
|
const resp = await $.post("api/setup/sync-from-server", {
|
||||||
syncServerHost: syncServerHost,
|
syncServerHost,
|
||||||
syncProxy: syncProxy,
|
syncProxy,
|
||||||
password: password
|
password
|
||||||
});
|
});
|
||||||
|
|
||||||
if (resp.result === "success") {
|
if (resp.result === "success") {
|
||||||
this.step("sync-in-progress");
|
|
||||||
|
|
||||||
setInterval(checkOutstandingSyncs, 1000);
|
|
||||||
|
|
||||||
hideAlert();
|
hideAlert();
|
||||||
|
this.setStep("sync-in-progress");
|
||||||
|
this.startSyncPolling();
|
||||||
} else {
|
} else {
|
||||||
showAlert(`Sync setup failed: ${resp.error}`);
|
showAlert(`Sync setup failed: ${resp.error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private setStep(step: SetupStep) {
|
||||||
|
this.step = step;
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
private render() {
|
||||||
|
for (const [step, section] of Object.entries(this.sections) as [SetupStep, HTMLElement][]) {
|
||||||
|
section.style.display = step === this.step ? "" : "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setupTypeNextButton.disabled = !this.setupType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSelectedSetupType(): SetupType {
|
||||||
|
return (this.setupTypeInputs.find((input) => input.checked)?.value ?? "") as SetupType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private startSyncPolling() {
|
||||||
|
if (this.syncPollIntervalId !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.syncPollIntervalId = window.setInterval(checkOutstandingSyncs, 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkOutstandingSyncs() {
|
async function checkOutstandingSyncs() {
|
||||||
@@ -122,7 +186,19 @@ function getSyncInProgress() {
|
|||||||
return !!parseInt(el.content);
|
return !!parseInt(el.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mustGetElement<T extends typeof HTMLElement>(id: string, ctor: T): InstanceType<T> {
|
||||||
|
const element = document.getElementById(id);
|
||||||
|
|
||||||
|
if (!element || !(element instanceof ctor)) {
|
||||||
|
throw new Error(`Expected element #${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return element as InstanceType<T>;
|
||||||
|
}
|
||||||
|
|
||||||
addEventListener("DOMContentLoaded", (event) => {
|
addEventListener("DOMContentLoaded", (event) => {
|
||||||
ko.applyBindings(new SetupModel(getSyncInProgress()), document.getElementById("setup-dialog"));
|
const rootNode = document.getElementById("setup-dialog");
|
||||||
$("#setup-dialog").show();
|
if (!rootNode || !(rootNode instanceof HTMLElement)) return;
|
||||||
|
|
||||||
|
new SetupController(rootNode, getSyncInProgress()).init();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,450 +0,0 @@
|
|||||||
/* LLM Chat Panel Styles */
|
|
||||||
.note-context-chat {
|
|
||||||
background-color: var(--main-background-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Message Styling */
|
|
||||||
.chat-message {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-avatar {
|
|
||||||
width: 36px;
|
|
||||||
height: 36px;
|
|
||||||
border-radius: 50%;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-avatar {
|
|
||||||
background-color: var(--input-background-color);
|
|
||||||
color: var(--cmd-button-icon-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.assistant-avatar {
|
|
||||||
background-color: var(--subtle-border-color, var(--main-border-color));
|
|
||||||
color: var(--hover-item-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-content {
|
|
||||||
max-width: calc(100% - 50px);
|
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
||||||
color: var(--main-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-content {
|
|
||||||
border-radius: 0.5rem 0.5rem 0 0.5rem !important;
|
|
||||||
background-color: var(--input-background-color) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.assistant-content {
|
|
||||||
border-radius: 0.5rem 0.5rem 0.5rem 0 !important;
|
|
||||||
background-color: var(--main-background-color);
|
|
||||||
border: 1px solid var(--subtle-border-color, var(--main-border-color));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tool Execution Styling */
|
|
||||||
.tool-execution-info {
|
|
||||||
margin-top: 0.75rem;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
border: 1px solid var(--subtle-border-color);
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
overflow: hidden;
|
|
||||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
|
|
||||||
background-color: var(--main-background-color);
|
|
||||||
/* Add a subtle transition effect */
|
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-execution-status {
|
|
||||||
background-color: var(--accented-background-color, rgba(0, 0, 0, 0.03)) !important;
|
|
||||||
border-radius: 0 !important;
|
|
||||||
padding: 0.5rem !important;
|
|
||||||
max-height: 250px !important;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-execution-status .d-flex {
|
|
||||||
border-bottom: 1px solid var(--subtle-border-color);
|
|
||||||
padding-bottom: 0.5rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-step {
|
|
||||||
padding: 0.5rem;
|
|
||||||
margin-bottom: 0.75rem;
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
background-color: var(--main-background-color);
|
|
||||||
border: 1px solid var(--subtle-border-color);
|
|
||||||
transition: background-color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-step:hover {
|
|
||||||
background-color: rgba(0, 0, 0, 0.01);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-step:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tool step specific styling */
|
|
||||||
.tool-step.executing {
|
|
||||||
background-color: rgba(0, 123, 255, 0.05);
|
|
||||||
border-color: rgba(0, 123, 255, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-step.result {
|
|
||||||
background-color: rgba(40, 167, 69, 0.05);
|
|
||||||
border-color: rgba(40, 167, 69, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-step.error {
|
|
||||||
background-color: rgba(220, 53, 69, 0.05);
|
|
||||||
border-color: rgba(220, 53, 69, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tool result formatting */
|
|
||||||
.tool-result pre {
|
|
||||||
margin: 0.5rem 0;
|
|
||||||
padding: 0.5rem;
|
|
||||||
background-color: rgba(0, 0, 0, 0.03);
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
overflow: auto;
|
|
||||||
max-height: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-result code {
|
|
||||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-args code {
|
|
||||||
display: block;
|
|
||||||
padding: 0.5rem;
|
|
||||||
background-color: rgba(0, 0, 0, 0.03);
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
margin-top: 0.25rem;
|
|
||||||
font-size: 0.85em;
|
|
||||||
color: var(--muted-text-color);
|
|
||||||
white-space: pre-wrap;
|
|
||||||
overflow: auto;
|
|
||||||
max-height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tool Execution in Chat Styling */
|
|
||||||
.chat-tool-execution {
|
|
||||||
padding: 0 0 0 36px; /* Aligned with message content, accounting for avatar width */
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-execution-container {
|
|
||||||
background-color: var(--accented-background-color, rgba(245, 247, 250, 0.7));
|
|
||||||
border: 1px solid var(--subtle-border-color);
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
||||||
overflow: hidden;
|
|
||||||
max-width: calc(100% - 20px);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-execution-container.collapsed {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-execution-header {
|
|
||||||
background-color: var(--main-background-color);
|
|
||||||
border-bottom: 1px solid var(--subtle-border-color);
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
color: var(--muted-text-color);
|
|
||||||
font-weight: 500;
|
|
||||||
padding: 0.6rem 0.8rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-execution-header:hover {
|
|
||||||
background-color: var(--hover-item-background-color, rgba(0, 0, 0, 0.03));
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-execution-toggle {
|
|
||||||
color: var(--muted-text-color) !important;
|
|
||||||
background: transparent !important;
|
|
||||||
padding: 0.2rem 0.4rem !important;
|
|
||||||
transition: transform 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-execution-toggle:hover {
|
|
||||||
color: var(--main-text-color) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-execution-toggle i.bx-chevron-down {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
transition: transform 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-execution-toggle i.bx-chevron-right {
|
|
||||||
transform: rotate(-90deg);
|
|
||||||
transition: transform 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-execution-chat-steps {
|
|
||||||
padding: 0.5rem;
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make error text more visible */
|
|
||||||
.text-danger {
|
|
||||||
color: #dc3545 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sources Styling */
|
|
||||||
.sources-container {
|
|
||||||
background-color: var(--accented-background-color, var(--main-background-color));
|
|
||||||
border-top: 1px solid var(--main-border-color);
|
|
||||||
color: var(--main-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.source-item {
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
background-color: var(--main-background-color);
|
|
||||||
border-color: var(--subtle-border-color, var(--main-border-color)) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.source-item:hover {
|
|
||||||
background-color: var(--link-hover-background, var(--hover-item-background-color));
|
|
||||||
}
|
|
||||||
|
|
||||||
.source-link {
|
|
||||||
color: var(--link-color, var(--hover-item-text-color));
|
|
||||||
text-decoration: none;
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.source-link:hover {
|
|
||||||
color: var(--link-hover-color, var(--hover-item-text-color));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Input Area Styling */
|
|
||||||
.note-context-chat-form {
|
|
||||||
background-color: var(--main-background-color);
|
|
||||||
border-top: 1px solid var(--main-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-option-container {
|
|
||||||
padding: 0.5rem 0;
|
|
||||||
border-bottom: 1px solid var(--subtle-border-color, var(--main-border-color));
|
|
||||||
color: var(--main-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-input-container {
|
|
||||||
padding-top: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-context-chat-input {
|
|
||||||
border-color: var(--subtle-border-color, var(--main-border-color));
|
|
||||||
background-color: var(--input-background-color) !important;
|
|
||||||
color: var(--input-text-color) !important;
|
|
||||||
resize: none;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
min-height: 50px;
|
|
||||||
max-height: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-context-chat-input:focus {
|
|
||||||
border-color: var(--input-focus-outline-color, var(--main-border-color));
|
|
||||||
box-shadow: 0 0 0 0.25rem var(--input-focus-outline-color, rgba(13, 110, 253, 0.25));
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-context-chat-send-button {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
align-self: flex-end;
|
|
||||||
background-color: var(--cmd-button-background-color) !important;
|
|
||||||
color: var(--cmd-button-text-color) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Loading Indicator */
|
|
||||||
.loading-indicator {
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 1rem;
|
|
||||||
color: var(--muted-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Thinking display styles */
|
|
||||||
.llm-thinking-container {
|
|
||||||
margin: 1rem 0;
|
|
||||||
animation: fadeInUp 0.3s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-bubble {
|
|
||||||
background-color: var(--accented-background-color, var(--main-background-color));
|
|
||||||
border: 1px solid var(--subtle-border-color, var(--main-border-color));
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
padding: 0.75rem;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-bubble:hover {
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-bubble::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
inset-inline-start: -100%;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: linear-gradient(90deg, transparent, var(--hover-item-background-color, rgba(0, 0, 0, 0.03)), transparent);
|
|
||||||
animation: shimmer 2s infinite;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-header {
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-header:hover {
|
|
||||||
background-color: var(--hover-item-background-color, rgba(0, 0, 0, 0.03));
|
|
||||||
padding: 0.25rem;
|
|
||||||
margin: -0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-dots {
|
|
||||||
display: flex;
|
|
||||||
gap: 3px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-dots span {
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
background-color: var(--link-color, var(--hover-item-text-color));
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: thinkingPulse 1.4s infinite ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-dots span:nth-child(1) {
|
|
||||||
animation-delay: -0.32s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-dots span:nth-child(2) {
|
|
||||||
animation-delay: -0.16s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-dots span:nth-child(3) {
|
|
||||||
animation-delay: 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-label {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--link-color, var(--hover-item-text-color)) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-toggle {
|
|
||||||
color: var(--muted-text-color) !important;
|
|
||||||
transition: transform 0.2s ease;
|
|
||||||
background: transparent !important;
|
|
||||||
border: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-toggle:hover {
|
|
||||||
color: var(--main-text-color) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-toggle.expanded {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-content {
|
|
||||||
margin-top: 0.75rem;
|
|
||||||
padding-top: 0.75rem;
|
|
||||||
border-top: 1px solid var(--subtle-border-color, var(--main-border-color));
|
|
||||||
animation: expandDown 0.3s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-text {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: var(--main-text-color);
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-wrap: break-word;
|
|
||||||
background-color: var(--input-background-color);
|
|
||||||
padding: 0.75rem;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
border: 1px solid var(--subtle-border-color, var(--main-border-color));
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
transition: border-color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-text:hover {
|
|
||||||
border-color: var(--main-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Animations */
|
|
||||||
@keyframes thinkingPulse {
|
|
||||||
0%, 80%, 100% {
|
|
||||||
transform: scale(0.8);
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
40% {
|
|
||||||
transform: scale(1);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes shimmer {
|
|
||||||
0% {
|
|
||||||
inset-inline-start: -100%;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
inset-inline-start: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeInUp {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(10px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes expandDown {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
max-height: 0;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
max-height: 300px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Responsive adjustments */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.thinking-bubble {
|
|
||||||
margin: 0.5rem 0;
|
|
||||||
padding: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thinking-text {
|
|
||||||
font-size: 0.8rem;
|
|
||||||
padding: 0.5rem;
|
|
||||||
max-height: 200px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
--bs-body-color: var(--main-text-color) !important;
|
--bs-body-color: var(--main-text-color) !important;
|
||||||
--bs-body-bg: var(--main-background-color) !important;
|
--bs-body-bg: var(--main-background-color) !important;
|
||||||
--ck-mention-list-max-height: 500px;
|
--ck-mention-list-max-height: 500px;
|
||||||
--tn-modal-max-height: 90vh;
|
--tn-modal-max-height: 90svh;
|
||||||
|
|
||||||
--tree-item-light-theme-max-color-lightness: 50;
|
--tree-item-light-theme-max-color-lightness: 50;
|
||||||
--tree-item-dark-theme-min-color-lightness: 75;
|
--tree-item-dark-theme-min-color-lightness: 75;
|
||||||
@@ -111,6 +111,7 @@ body.mobile #root-widget.virtual-keyboard-opened #mobile-bottom-bar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#mobile-bottom-bar {
|
#mobile-bottom-bar {
|
||||||
|
border-top: 1px solid var(--main-border-color);
|
||||||
padding-bottom: var(--mobile-bottom-offset);
|
padding-bottom: var(--mobile-bottom-offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,6 +153,11 @@ textarea,
|
|||||||
background: var(--input-background-color);
|
background: var(--input-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-control:disabled {
|
||||||
|
background-color: var(--input-background-color);
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
.form-control:focus {
|
.form-control:focus {
|
||||||
color: var(--input-text-color);
|
color: var(--input-text-color);
|
||||||
background: var(--input-background-color);
|
background: var(--input-background-color);
|
||||||
@@ -224,10 +230,6 @@ body.mobile .modal .modal-dialog {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.mobile .modal .modal-content {
|
|
||||||
border-radius: var(--bs-modal-border-radius) var(--bs-modal-border-radius) 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.component {
|
.component {
|
||||||
contain: size;
|
contain: size;
|
||||||
}
|
}
|
||||||
@@ -413,6 +415,7 @@ body.desktop .tabulator-popup-container,
|
|||||||
|
|
||||||
.dropdown-menu.static {
|
.dropdown-menu.static {
|
||||||
box-shadow: unset;
|
box-shadow: unset;
|
||||||
|
backdrop-filter: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropend .dropdown-toggle::after {
|
.dropend .dropdown-toggle::after {
|
||||||
@@ -458,7 +461,7 @@ body.desktop .tabulator-popup-container,
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.desktop .dropdown-menu:not(#context-menu-container) .dropdown-item,
|
.dropdown-menu:not(#context-menu-container) .dropdown-item,
|
||||||
body.desktop .dropdown-menu .dropdown-toggle,
|
body.desktop .dropdown-menu .dropdown-toggle,
|
||||||
body #context-menu-container .dropdown-item > span,
|
body #context-menu-container .dropdown-item > span,
|
||||||
body.mobile .dropdown .dropdown-submenu > span {
|
body.mobile .dropdown .dropdown-submenu > span {
|
||||||
@@ -466,6 +469,15 @@ body.mobile .dropdown .dropdown-submenu > span {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
body.mobile .dropdown .dropdown-submenu {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.dropdown-item span.keyboard-shortcut,
|
.dropdown-item span.keyboard-shortcut,
|
||||||
.dropdown-item *:not(.keyboard-shortcut) > kbd {
|
.dropdown-item *:not(.keyboard-shortcut) > kbd {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
@@ -880,33 +892,6 @@ table.promoted-attributes-in-tooltip th {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.algolia-autocomplete {
|
|
||||||
width: calc(100% - 30px);
|
|
||||||
z-index: 2000 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.algolia-autocomplete-container .aa-dropdown-menu {
|
|
||||||
position: inherit !important;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.algolia-autocomplete .aa-input,
|
|
||||||
.algolia-autocomplete .aa-hint {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.algolia-autocomplete .aa-dropdown-menu {
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--main-background-color);
|
|
||||||
border: 1px solid var(--main-border-color);
|
|
||||||
border-top: none;
|
|
||||||
z-index: 2000 !important;
|
|
||||||
max-height: 500px;
|
|
||||||
overflow: auto;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aa-dropdown-menu .aa-suggestion {
|
.aa-dropdown-menu .aa-suggestion {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 6px 16px;
|
padding: 6px 16px;
|
||||||
@@ -935,6 +920,7 @@ table.promoted-attributes-in-tooltip th {
|
|||||||
color: var(--muted-text-color);
|
color: var(--muted-text-color);
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.aa-dropdown-menu .aa-suggestion p {
|
.aa-dropdown-menu .aa-suggestion p {
|
||||||
@@ -947,6 +933,153 @@ table.promoted-attributes-in-tooltip th {
|
|||||||
background-color: var(--active-item-background-color);
|
background-color: var(--active-item-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== @algolia/autocomplete-core (headless, custom panel) ===== */
|
||||||
|
|
||||||
|
.aa-core-panel {
|
||||||
|
z-index: 10000;
|
||||||
|
background-color: var(--main-background-color);
|
||||||
|
border: 1px solid var(--main-border-color);
|
||||||
|
border-top: none;
|
||||||
|
max-height: 500px;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-panel.aa-dropdown-menu {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-panel--contained {
|
||||||
|
position: static !important;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 7px 16px;
|
||||||
|
margin: 0;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item--active {
|
||||||
|
color: var(--active-item-text-color);
|
||||||
|
background-color: var(--active-item-background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .note-suggestion {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .icon,
|
||||||
|
.aa-core-item .command-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .text {
|
||||||
|
min-width: 0;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .aa-core-primary-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .search-result-title {
|
||||||
|
display: block;
|
||||||
|
min-width: 0;
|
||||||
|
line-height: 1.35;
|
||||||
|
word-break: break-word;
|
||||||
|
font-size: 1.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .search-result-attributes {
|
||||||
|
display: block;
|
||||||
|
margin-top: 1px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: var(--muted-text-color);
|
||||||
|
opacity: 0.65;
|
||||||
|
line-height: 1.2;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .search-result-attributes {
|
||||||
|
padding-inline-start: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .aa-core-shortcut,
|
||||||
|
.aa-core-item kbd.command-shortcut {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--muted-text-color);
|
||||||
|
font-family: inherit !important;
|
||||||
|
font-size: 0.8em;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .command-suggestion {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .command-content {
|
||||||
|
flex-grow: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .command-name {
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .command-description {
|
||||||
|
font-size: 0.8em;
|
||||||
|
line-height: 1.3;
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .search-result-title b,
|
||||||
|
.aa-core-item .search-result-path b,
|
||||||
|
.aa-core-item .search-result-attributes b,
|
||||||
|
.aa-core-item .command-name b,
|
||||||
|
.aa-core-item .command-description b {
|
||||||
|
color: var(--admonition-warning-accent-color);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-core-item .aa-core-separator {
|
||||||
|
padding: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jump-to-note-results .aa-core-panel--contained {
|
||||||
|
max-height: calc(80vh - 200px);
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
.help-button {
|
.help-button {
|
||||||
float: inline-end;
|
float: inline-end;
|
||||||
background: none;
|
background: none;
|
||||||
@@ -1255,7 +1388,7 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
|
|||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
inset-inline-end: 0;
|
inset-inline-end: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 1000;
|
z-index: 2500;
|
||||||
background: rgba(0, 0, 0, 0.1);
|
background: rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1329,15 +1462,12 @@ body.desktop .dropdown-submenu > .dropdown-menu {
|
|||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-submenu.dropstart > .dropdown-menu {
|
.dropdown-submenu.dropstart > .dropdown-menu,
|
||||||
|
body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
||||||
inset-inline-start: auto;
|
inset-inline-start: auto;
|
||||||
inset-inline-end: calc(100% - 2px);
|
inset-inline-end: calc(100% - 2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
|
||||||
inset-inline-start: calc(-100% + 10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.right-dropdown-widget {
|
.right-dropdown-widget {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
@@ -1534,7 +1664,8 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
|||||||
|
|
||||||
@media (max-width: 991px) {
|
@media (max-width: 991px) {
|
||||||
body.mobile #launcher-pane .dropdown.global-menu > .dropdown-menu.show,
|
body.mobile #launcher-pane .dropdown.global-menu > .dropdown-menu.show,
|
||||||
body.mobile #launcher-container .dropdown > .dropdown-menu.show {
|
body.mobile #launcher-container .dropdown > .dropdown-menu.show,
|
||||||
|
body.mobile .dropdown-menu.mobile-bottom-menu.show {
|
||||||
--dropdown-bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size));
|
--dropdown-bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size));
|
||||||
position: fixed !important;
|
position: fixed !important;
|
||||||
bottom: var(--dropdown-bottom) !important;
|
bottom: var(--dropdown-bottom) !important;
|
||||||
@@ -1546,6 +1677,16 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
|||||||
max-height: calc(var(--tn-modal-max-height) - var(--dropdown-bottom));
|
max-height: calc(var(--tn-modal-max-height) - var(--dropdown-bottom));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body.mobile #launcher-container .dropdown > .dropdown-menu.show {
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mobile .dropdown-menu.mobile-bottom-menu.show {
|
||||||
|
--dropdown-bottom: 0px;
|
||||||
|
padding-bottom: calc(max(var(--menu-padding-size), env(safe-area-inset-bottom))) !important;
|
||||||
|
}
|
||||||
|
|
||||||
#mobile-sidebar-container {
|
#mobile-sidebar-container {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -1566,7 +1707,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
bottom: 0;
|
height: 100dvh;
|
||||||
width: 85vw;
|
width: 85vw;
|
||||||
padding-top: env(safe-area-inset-top);
|
padding-top: env(safe-area-inset-top);
|
||||||
transition: transform 250ms ease-in-out;
|
transition: transform 250ms ease-in-out;
|
||||||
@@ -1591,11 +1732,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body.mobile #launcher-container {
|
body.mobile #launcher-container {
|
||||||
justify-content: center;
|
justify-content: space-evenly;
|
||||||
}
|
|
||||||
|
|
||||||
body.mobile #launcher-container button {
|
|
||||||
margin: 0 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body.mobile .modal.show {
|
body.mobile .modal.show {
|
||||||
@@ -1614,6 +1751,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
|||||||
|
|
||||||
body.mobile .modal-content {
|
body.mobile .modal-content {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
border-radius: var(--bs-modal-border-radius) var(--bs-modal-border-radius) 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.mobile .modal-footer {
|
body.mobile .modal-footer {
|
||||||
@@ -1629,13 +1767,27 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.mobile .jump-to-note-dialog .modal-content {
|
body.mobile .jump-to-note-dialog {
|
||||||
overflow-y: auto;
|
.modal-header {
|
||||||
}
|
padding-bottom: 0.75rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
body.mobile .jump-to-note-dialog .modal-dialog .aa-dropdown-menu {
|
.modal-content {
|
||||||
max-height: unset;
|
padding-bottom: 0 !important;
|
||||||
overflow: auto;
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-dropdown-menu {
|
||||||
|
max-height: unset;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-suggestion {
|
||||||
|
padding-inline: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body.mobile .modal-dialog .dropdown-menu {
|
body.mobile .modal-dialog .dropdown-menu {
|
||||||
@@ -1669,39 +1821,16 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
|||||||
#detail-container {
|
#detail-container {
|
||||||
background: var(--main-background-color);
|
background: var(--main-background-color);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 991px) {
|
body.mobile {
|
||||||
body.mobile.force-fixed-tree #mobile-sidebar-wrapper {
|
.modal-dialog {
|
||||||
padding-top: 0;
|
margin: var(--bs-modal-margin);
|
||||||
position: static;
|
max-width: 80%;
|
||||||
height: 40vh;
|
}
|
||||||
width: 100vw;
|
|
||||||
transform: none !important;
|
|
||||||
background-color: var(--left-pane-background-color) !important;
|
|
||||||
border-bottom: 0.5px solid var(--main-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
body.mobile.force-fixed-tree #mobile-sidebar-container {
|
.modal-content {
|
||||||
display: none !important;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.mobile.force-fixed-tree #mobile-sidebar-wrapper .quick-search {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.mobile.force-fixed-tree .component > button.bx-sidebar {
|
|
||||||
visibility: hidden;
|
|
||||||
padding: 0;
|
|
||||||
width: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.mobile.force-fixed-tree #mobile-rest-container {
|
|
||||||
flex-direction: column !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.mobile.force-fixed-tree #detail-container {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2617,14 +2746,14 @@ iframe.print-iframe {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#root-widget.virtual-keyboard-opened .note-split:not(:focus-within) {
|
body:not(.ios) #root-widget.virtual-keyboard-opened .note-split:not(.active) {
|
||||||
max-height: 80px;
|
max-height: 80px;
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body.desktop .title-row {
|
.title-row {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -40,10 +40,42 @@
|
|||||||
border-bottom: var(--col-header-bottom-border);
|
border-bottom: var(--col-header-bottom-border);
|
||||||
background: var(--col-header-background-color);
|
background: var(--col-header-background-color);
|
||||||
color: var(--col-header-text-color);
|
color: var(--col-header-text-color);
|
||||||
}
|
font-weight: normal;
|
||||||
|
|
||||||
.tabulator .tabulator-col-content {
|
.tabulator-col.tabulator-range-highlight {
|
||||||
padding: 8px 4px !important;
|
background: inherit;
|
||||||
|
color: inherit;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabulator-col-content {
|
||||||
|
padding: 0 !important;
|
||||||
|
|
||||||
|
.tabulator-col-title-holder {
|
||||||
|
padding: 8px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:has(.tabulator-header-filter) {
|
||||||
|
.tabulator-col-title-holder {
|
||||||
|
padding: 4px;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabulator-header-filter {
|
||||||
|
background: var(--main-background-color);
|
||||||
|
padding: 2px 1px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
background: var(--main-background-color);
|
||||||
|
color: var(--main-text-color);
|
||||||
|
border: 1px solid var(--button-border-color);
|
||||||
|
border-radius: 3px;
|
||||||
|
outline: none;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (hover: hover) and (pointer: fine) {
|
@media (hover: hover) and (pointer: fine) {
|
||||||
@@ -80,7 +112,6 @@
|
|||||||
|
|
||||||
.tabulator-tableholder {
|
.tabulator-tableholder {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
height: unset !important; /* Don't extend on the full height */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rows */
|
/* Rows */
|
||||||
@@ -99,6 +130,14 @@
|
|||||||
border-top: none;
|
border-top: none;
|
||||||
border-bottom: 1px solid var(--row-delimiter-color);
|
border-bottom: 1px solid var(--row-delimiter-color);
|
||||||
color: var(--row-text-color);
|
color: var(--row-text-color);
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.tabulator-range-highlight > .tabulator-cell.tabulator-frozen {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabulator-row.tabulator-row-odd {
|
.tabulator-row.tabulator-row-odd {
|
||||||
@@ -120,11 +159,14 @@
|
|||||||
margin-inline-end: var(--cell-editing-border-width);
|
margin-inline-end: var(--cell-editing-border-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left,
|
|
||||||
.tabulator-row .tabulator-cell {
|
.tabulator-row .tabulator-cell {
|
||||||
border-inline-end-color: transparent;
|
border-inline-end-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left {
|
||||||
|
border-inline-end-color: var(--main-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
.tabulator-row .tabulator-cell:not(.tabulator-editable) {
|
.tabulator-row .tabulator-cell:not(.tabulator-editable) {
|
||||||
color: var(--cell-read-only-text-color);
|
color: var(--cell-read-only-text-color);
|
||||||
}
|
}
|
||||||
@@ -174,10 +216,6 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabulator .tabulator-footer {
|
|
||||||
color: var(--main-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Context menus */
|
/* Context menus */
|
||||||
|
|
||||||
.tabulator-popup-container {
|
.tabulator-popup-container {
|
||||||
@@ -192,8 +230,27 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Footer */
|
/* Footer */
|
||||||
|
|
||||||
:root .tabulator .tabulator-footer {
|
:root .tabulator .tabulator-footer {
|
||||||
border-top: unset;
|
background: transparent;
|
||||||
|
color: var(--main-text-color);
|
||||||
|
border-top: 1px solid var(--main-border-color);
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
|
|
||||||
|
.tabulator-page {
|
||||||
|
background: var(--button-background-color);
|
||||||
|
color: var(--button-text-color);
|
||||||
|
border: 1px solid var(--button-border-color);
|
||||||
|
border-radius: var(--button-border-radius);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--hover-item-border-color);
|
||||||
|
color: var(--button-text-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
background: var(--button-background-color);
|
||||||
|
color: var(--input-text-color);
|
||||||
|
border: 1px solid var(--button-border-color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -134,6 +134,7 @@
|
|||||||
--left-pane-collapsed-border-color: #0009;
|
--left-pane-collapsed-border-color: #0009;
|
||||||
--left-pane-background-color: #1f1f1f;
|
--left-pane-background-color: #1f1f1f;
|
||||||
--left-pane-text-color: #aaaaaa;
|
--left-pane-text-color: #aaaaaa;
|
||||||
|
--left-pane-icon-color: #c5c5c5;
|
||||||
--left-pane-item-hover-background: #ffffff0d;
|
--left-pane-item-hover-background: #ffffff0d;
|
||||||
--left-pane-item-selected-background: #ffffff25;
|
--left-pane-item-selected-background: #ffffff25;
|
||||||
--left-pane-item-selected-color: #dfdfdf;
|
--left-pane-item-selected-color: #dfdfdf;
|
||||||
@@ -209,6 +210,7 @@
|
|||||||
--badge-share-background-color: #4d4d4d;
|
--badge-share-background-color: #4d4d4d;
|
||||||
--badge-clipped-note-background-color: #295773;
|
--badge-clipped-note-background-color: #295773;
|
||||||
--badge-execute-background-color: #604180;
|
--badge-execute-background-color: #604180;
|
||||||
|
--badge-active-content-background-color: rgb(12, 68, 70);
|
||||||
|
|
||||||
--note-icon-background-color: #444444;
|
--note-icon-background-color: #444444;
|
||||||
--note-icon-color: #d4d4d4;
|
--note-icon-color: #d4d4d4;
|
||||||
@@ -289,6 +291,15 @@
|
|||||||
--ck-editor-toolbar-button-on-shadow: 1px 1px 2px rgba(0, 0, 0, .75);
|
--ck-editor-toolbar-button-on-shadow: 1px 1px 2px rgba(0, 0, 0, .75);
|
||||||
--ck-editor-toolbar-dropdown-button-open-background: #ffffff14;
|
--ck-editor-toolbar-dropdown-button-open-background: #ffffff14;
|
||||||
|
|
||||||
|
--note-list-view-icon-color: var(--left-pane-icon-color);
|
||||||
|
--note-list-view-large-icon-background: var(--note-icon-background-color);
|
||||||
|
--note-list-view-large-icon-color: var(--note-icon-color);
|
||||||
|
--note-list-view-search-result-highlight-background: transparent;
|
||||||
|
--note-list-view-search-result-highlight-color: var(--quick-search-result-highlight-color);
|
||||||
|
--note-list-view-content-background: rgba(0, 0, 0, .2);
|
||||||
|
--note-list-view-content-search-result-highlight-background: var(--quick-search-result-highlight-color);
|
||||||
|
--note-list-view-content-search-result-highlight-color: black;
|
||||||
|
|
||||||
--calendar-coll-event-background-saturation: 25%;
|
--calendar-coll-event-background-saturation: 25%;
|
||||||
--calendar-coll-event-background-lightness: 20%;
|
--calendar-coll-event-background-lightness: 20%;
|
||||||
--calendar-coll-event-background-color: #3c3c3c;
|
--calendar-coll-event-background-color: #3c3c3c;
|
||||||
@@ -302,7 +313,9 @@
|
|||||||
* Dark color scheme tweaks
|
* Dark color scheme tweaks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#left-pane .fancytree-node.tinted {
|
#left-pane .fancytree-node.tinted,
|
||||||
|
.nested-note-list-item.use-note-color,
|
||||||
|
.note-book-card .note-book-header.use-note-color {
|
||||||
--custom-color: var(--dark-theme-custom-color);
|
--custom-color: var(--dark-theme-custom-color);
|
||||||
|
|
||||||
/* The background color of the active item in the note tree.
|
/* The background color of the active item in the note tree.
|
||||||
@@ -336,12 +349,25 @@ body .todo-list input[type="checkbox"]:not(:checked):before {
|
|||||||
--promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 13.2%, 20.8%);
|
--promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 13.2%, 20.8%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal.tab-bar-modal .tabs .tab-card.with-hue {
|
||||||
|
background-color: hsl(var(--bg-hue), 8.8%, 11.2%);
|
||||||
|
border-color: hsl(var(--bg-hue), 9.4%, 25.1%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal.tab-bar-modal .tabs .tab-card.active.with-hue {
|
||||||
|
background-color: hsl(var(--bg-hue), 8.8%, 16.2%);
|
||||||
|
border-color: hsl(var(--bg-hue), 9.4%, 25.1%);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.use-note-color {
|
.use-note-color {
|
||||||
--custom-color: var(--dark-theme-custom-color);
|
--custom-color: var(--dark-theme-custom-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-split.with-hue,
|
.note-split.with-hue,
|
||||||
.quick-edit-dialog-wrapper.with-hue {
|
.quick-edit-dialog-wrapper.with-hue,
|
||||||
|
.nested-note-list-item.with-hue,
|
||||||
|
.note-book-card.with-hue .note-book-header {
|
||||||
--note-icon-custom-background-color: hsl(var(--custom-color-hue), 15.8%, 30.9%);
|
--note-icon-custom-background-color: hsl(var(--custom-color-hue), 15.8%, 30.9%);
|
||||||
--note-icon-custom-color: hsl(var(--custom-color-hue), 100%, 76.5%);
|
--note-icon-custom-color: hsl(var(--custom-color-hue), 100%, 76.5%);
|
||||||
--note-icon-hover-custom-background-color: hsl(var(--custom-color-hue), 28.3%, 36.7%);
|
--note-icon-hover-custom-background-color: hsl(var(--custom-color-hue), 28.3%, 36.7%);
|
||||||
@@ -351,3 +377,8 @@ body .todo-list input[type="checkbox"]:not(:checked):before {
|
|||||||
.quick-edit-dialog-wrapper.with-hue *::selection {
|
.quick-edit-dialog-wrapper.with-hue *::selection {
|
||||||
--selection-background-color: hsl(var(--custom-color-hue), 49.2%, 35%);
|
--selection-background-color: hsl(var(--custom-color-hue), 49.2%, 35%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.note-book-card.with-hue {
|
||||||
|
--card-background-color: hsl(var(--custom-color-hue), 6%, 21%);
|
||||||
|
--card-background-hover-color: hsl(var(--custom-color-hue), 8%, 25%);
|
||||||
|
}
|
||||||
@@ -127,6 +127,7 @@
|
|||||||
--left-pane-collapsed-border-color: #0000000d;
|
--left-pane-collapsed-border-color: #0000000d;
|
||||||
--left-pane-background-color: #f2f2f2;
|
--left-pane-background-color: #f2f2f2;
|
||||||
--left-pane-text-color: #383838;
|
--left-pane-text-color: #383838;
|
||||||
|
--left-pane-icon-color: currentColor;
|
||||||
--left-pane-item-hover-background: rgba(0, 0, 0, 0.032);
|
--left-pane-item-hover-background: rgba(0, 0, 0, 0.032);
|
||||||
--left-pane-item-selected-background: white;
|
--left-pane-item-selected-background: white;
|
||||||
--left-pane-item-selected-color: black;
|
--left-pane-item-selected-color: black;
|
||||||
@@ -201,6 +202,7 @@
|
|||||||
--badge-share-background-color: #6b6b6b;
|
--badge-share-background-color: #6b6b6b;
|
||||||
--badge-clipped-note-background-color: #2284c0;
|
--badge-clipped-note-background-color: #2284c0;
|
||||||
--badge-execute-background-color: #7b47af;
|
--badge-execute-background-color: #7b47af;
|
||||||
|
--badge-active-content-background-color: rgb(27, 164, 168);
|
||||||
|
|
||||||
--note-icon-background-color: #4f4f4f;
|
--note-icon-background-color: #4f4f4f;
|
||||||
--note-icon-color: white;
|
--note-icon-color: white;
|
||||||
@@ -287,6 +289,15 @@
|
|||||||
--ck-editor-toolbar-button-on-shadow: none;
|
--ck-editor-toolbar-button-on-shadow: none;
|
||||||
--ck-editor-toolbar-dropdown-button-open-background: #0000000f;
|
--ck-editor-toolbar-dropdown-button-open-background: #0000000f;
|
||||||
|
|
||||||
|
--note-list-view-icon-color: var(--left-pane-icon-color);
|
||||||
|
--note-list-view-large-icon-background: var(--note-icon-background-color);
|
||||||
|
--note-list-view-large-icon-color: var(--note-icon-color);
|
||||||
|
--note-list-view-search-result-highlight-background: transparent;
|
||||||
|
--note-list-view-search-result-highlight-color: var(--quick-search-result-highlight-color);
|
||||||
|
--note-list-view-content-background: #b1b1b133;
|
||||||
|
--note-list-view-content-search-result-highlight-background: var(--quick-search-result-highlight-color);
|
||||||
|
--note-list-view-content-search-result-highlight-color: white;
|
||||||
|
|
||||||
--calendar-coll-event-background-lightness: 95%;
|
--calendar-coll-event-background-lightness: 95%;
|
||||||
--calendar-coll-event-background-saturation: 80%;
|
--calendar-coll-event-background-saturation: 80%;
|
||||||
--calendar-coll-event-background-color: #eaeaea;
|
--calendar-coll-event-background-color: #eaeaea;
|
||||||
@@ -296,7 +307,9 @@
|
|||||||
--calendar-coll-today-background-color: #00000006;
|
--calendar-coll-today-background-color: #00000006;
|
||||||
}
|
}
|
||||||
|
|
||||||
#left-pane .fancytree-node.tinted {
|
#left-pane .fancytree-node.tinted,
|
||||||
|
.nested-note-list-item.use-note-color,
|
||||||
|
.note-book-card .note-book-header.use-note-color {
|
||||||
--custom-color: var(--light-theme-custom-color);
|
--custom-color: var(--light-theme-custom-color);
|
||||||
|
|
||||||
/* The background color of the active item in the note tree.
|
/* The background color of the active item in the note tree.
|
||||||
@@ -311,8 +324,20 @@
|
|||||||
--promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 40%, 88%);
|
--promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 40%, 88%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal.tab-bar-modal .tabs .tab-card.with-hue {
|
||||||
|
background-color: hsl(var(--bg-hue), 56%, 96%);
|
||||||
|
border-color: hsl(var(--bg-hue), 33%, 41%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal.tab-bar-modal .tabs .tab-card.active.with-hue {
|
||||||
|
background-color: hsl(var(--bg-hue), 86%, 96%);
|
||||||
|
border-color: hsl(var(--bg-hue), 33%, 41%);
|
||||||
|
}
|
||||||
|
|
||||||
.note-split.with-hue,
|
.note-split.with-hue,
|
||||||
.quick-edit-dialog-wrapper.with-hue {
|
.quick-edit-dialog-wrapper.with-hue,
|
||||||
|
.nested-note-list-item.with-hue,
|
||||||
|
.note-book-card.with-hue .note-book-header {
|
||||||
--note-icon-custom-background-color: hsl(var(--custom-color-hue), 44.5%, 43.1%);
|
--note-icon-custom-background-color: hsl(var(--custom-color-hue), 44.5%, 43.1%);
|
||||||
--note-icon-custom-color: hsl(var(--custom-color-hue), 91.3%, 91%);
|
--note-icon-custom-color: hsl(var(--custom-color-hue), 91.3%, 91%);
|
||||||
--note-icon-hover-custom-background-color: hsl(var(--custom-color-hue), 55.1%, 50.2%);
|
--note-icon-hover-custom-background-color: hsl(var(--custom-color-hue), 55.1%, 50.2%);
|
||||||
@@ -322,3 +347,8 @@
|
|||||||
.quick-edit-dialog-wrapper.with-hue *::selection {
|
.quick-edit-dialog-wrapper.with-hue *::selection {
|
||||||
--selection-background-color: hsl(var(--custom-color-hue), 60%, 90%);
|
--selection-background-color: hsl(var(--custom-color-hue), 60%, 90%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.note-book-card.with-hue {
|
||||||
|
--card-background-color: hsl(var(--custom-color-hue), 21%, 94%);
|
||||||
|
--card-background-hover-color: hsl(var(--custom-color-hue), 21%, 87%);
|
||||||
|
}
|
||||||
@@ -643,139 +643,6 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
|
|||||||
transform: translateY(4%);
|
transform: translateY(4%);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE LIST
|
|
||||||
*/
|
|
||||||
|
|
||||||
.note-list .note-book-card {
|
|
||||||
--note-list-horizontal-padding: 22px;
|
|
||||||
--note-list-vertical-padding: 15px;
|
|
||||||
background-color: var(--card-background-color);
|
|
||||||
border: 1px solid var(--card-border-color) !important;
|
|
||||||
border-radius: 12px;
|
|
||||||
user-select: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 5px 10px 5px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root .note-list .note-book-card:hover {
|
|
||||||
background-color: var(--card-background-hover-color);
|
|
||||||
transition: background-color 200ms ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root .note-list.grid-view .note-book-card:active {
|
|
||||||
transform: scale(.98);
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list.list-view .note-book-card {
|
|
||||||
box-shadow: 0 0 3px var(--card-shadow-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list.list-view .note-book-card .note-book-header .note-icon {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card a {
|
|
||||||
color: inherit !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-header {
|
|
||||||
font-size: 1em;
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 0.5em 1rem;
|
|
||||||
border-bottom-color: var(--card-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-header .note-icon {
|
|
||||||
font-size: 17px;
|
|
||||||
vertical-align: text-bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-header .note-book-title {
|
|
||||||
font-size: 1em;
|
|
||||||
color: var(--active-item-text-color);
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-header .rendered-note-attributes {
|
|
||||||
font-size: 0.7em;
|
|
||||||
font-weight: normal;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-header:last-child {
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content {
|
|
||||||
padding: 0 !important;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content .rendered-content {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content.type-image .rendered-content,
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content.type-pdf .rendered-content {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content .rendered-content.text-with-ellipsis {
|
|
||||||
padding: 1rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content h1,
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content h2,
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content h3,
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content h4,
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content h5,
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content h6 {
|
|
||||||
font-size: 1rem;
|
|
||||||
color: var(--active-item-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content p:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content.type-canvas .rendered-content,
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content.type-mindMap .rendered-content,
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content.type-code .rendered-content,
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content.type-video .rendered-content {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content.type-code {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .note-book-content.type-code pre {
|
|
||||||
height: 100%;
|
|
||||||
padding: 1em;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list-wrapper .note-book-card .tn-icon {
|
|
||||||
color: var(--left-pane-icon-color) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list.grid-view .note-book-card:hover {
|
|
||||||
filter: contrast(105%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list.grid-view .ck-content {
|
|
||||||
line-height: 1.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list.grid-view .ck-content p {
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-list.grid-view .ck-content figure.image {
|
|
||||||
width: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE SEARCH SUGGESTIONS
|
* NOTE SEARCH SUGGESTIONS
|
||||||
*/
|
*/
|
||||||
@@ -800,3 +667,19 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
|
|||||||
background: var(--hover-item-background-color);
|
background: var(--hover-item-background-color);
|
||||||
color: var(--hover-item-text-color);
|
color: var(--hover-item-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Alert bars
|
||||||
|
*/
|
||||||
|
|
||||||
|
div.alert {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
background: var(--alert-bar-background) !important;
|
||||||
|
color: var(--main-text-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: .85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.alert p + p {
|
||||||
|
margin-block: 1em 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -84,6 +84,22 @@ button.btn.btn-success kbd {
|
|||||||
letter-spacing: 0.5pt;
|
letter-spacing: 0.5pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Low profile buttons
|
||||||
|
*/
|
||||||
|
|
||||||
|
button.tn-low-profile {
|
||||||
|
appearance: none;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.tn-low-profile:hover {
|
||||||
|
background-color: var(--icon-button-hover-background);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Icon buttons
|
* Icon buttons
|
||||||
*/
|
*/
|
||||||
@@ -129,6 +145,10 @@ button.btn.btn-success kbd {
|
|||||||
font-size: calc(var(--icon-button-size) * var(--icon-button-icon-ratio));
|
font-size: calc(var(--icon-button-size) * var(--icon-button-icon-ratio));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:root .icon-action.disabled::before {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
:root .icon-action:not(.global-menu-button):hover,
|
:root .icon-action:not(.global-menu-button):hover,
|
||||||
:root .icon-action:not(.global-menu-button).show,
|
:root .icon-action:not(.global-menu-button).show,
|
||||||
:root .tn-tool-button:hover,
|
:root .tn-tool-button:hover,
|
||||||
@@ -794,3 +814,35 @@ input[type="range"] {
|
|||||||
scrollbar-width: unset;
|
scrollbar-width: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Centered forms
|
||||||
|
*/
|
||||||
|
|
||||||
|
.tn-centered-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tn-centered-form .form-group {
|
||||||
|
text-align: center;
|
||||||
|
color: var(--muted-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tn-centered-form .form-icon {
|
||||||
|
font-size: 140px;
|
||||||
|
color: var(--main-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tn-centered-form .protected-session-password {
|
||||||
|
margin-inline: auto;
|
||||||
|
max-width: 350px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tn-centered-form .input-group,
|
||||||
|
.tn-centered-form button {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,122 +0,0 @@
|
|||||||
/* LLM Chat Launcher Widget Styles */
|
|
||||||
.note-context-chat {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-context-chat-container {
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-message {
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
max-width: 85%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-message.user-message {
|
|
||||||
margin-inline-start: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-message.assistant-message {
|
|
||||||
margin-inline-end: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-avatar {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-inline-end: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-message .message-avatar {
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.assistant-message .message-avatar {
|
|
||||||
background-color: var(--secondary-color);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-content {
|
|
||||||
background-color: var(--more-accented-background-color);
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 10px 15px;
|
|
||||||
max-width: calc(100% - 40px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-message .message-content {
|
|
||||||
background-color: var(--accented-background-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-content pre {
|
|
||||||
background-color: var(--code-background-color);
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 10px;
|
|
||||||
overflow-x: auto;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-content code {
|
|
||||||
background-color: var(--code-background-color);
|
|
||||||
padding: 2px 4px;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-indicator {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin: 10px 0;
|
|
||||||
color: var(--muted-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sources-container {
|
|
||||||
background-color: var(--accented-background-color);
|
|
||||||
border-top: 1px solid var(--main-border-color);
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sources-list {
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.source-item {
|
|
||||||
padding: 4px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.source-link {
|
|
||||||
color: var(--link-color);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.source-link:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-context-chat-form {
|
|
||||||
display: flex;
|
|
||||||
background-color: var(--main-background-color);
|
|
||||||
border-top: 1px solid var(--main-border-color);
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-context-chat-input {
|
|
||||||
resize: vertical;
|
|
||||||
min-height: 44px;
|
|
||||||
max-height: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Responsive adjustments */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.chat-message {
|
|
||||||
max-width: 95%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -47,9 +47,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* The toolbar show / hide button for the current text block */
|
/* The toolbar show / hide button for the current text block */
|
||||||
.ck.ck-block-toolbar-button {
|
:root .ck.ck-block-toolbar-button {
|
||||||
|
--ck-color-block-toolbar-button: var(--muted-text-color);
|
||||||
--ck-color-button-on-background: transparent;
|
--ck-color-button-on-background: transparent;
|
||||||
--ck-color-button-on-color: currentColor;
|
--ck-color-button-on-color: var(--ck-editor-toolbar-button-on-color);
|
||||||
|
translate: -40% 0;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0;
|
||||||
|
z-index: 1600;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root .ck.ck-toolbar .ck-button:not(.ck-disabled):active,
|
:root .ck.ck-toolbar .ck-button:not(.ck-disabled):active,
|
||||||
@@ -517,6 +522,10 @@ button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel).ck
|
|||||||
* EDITOR'S CONTENT
|
* EDITOR'S CONTENT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.note-detail-editable-text-editor > .ck-placeholder {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Code Blocks
|
* Code Blocks
|
||||||
*/
|
*/
|
||||||
@@ -638,10 +647,10 @@ html .note-detail-editable-text :not(figure, .include-note, hr):first-child {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ck-content hr {
|
:root .ck-content hr {
|
||||||
margin: 5px 0;
|
margin-block: 5px;
|
||||||
height: 1px;
|
height: 0;
|
||||||
background-color: var(--main-border-color);
|
border: thin solid var(--main-border-color);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Button bar */
|
/* Button bar */
|
||||||
.search-definition-widget .search-setting-table tbody:last-child div {
|
.search-definition-widget .search-setting-table .search-actions-container {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
@@ -128,8 +128,8 @@
|
|||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The search results list */
|
/* The headless autocomplete panel rendered into the empty-note results container */
|
||||||
.note-detail-empty span.aa-dropdown-menu {
|
.note-detail-empty .aa-core-panel--contained {
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
border: unset;
|
border: unset;
|
||||||
}
|
}
|
||||||
@@ -156,6 +156,10 @@
|
|||||||
--preferred-max-content-width: var(--options-card-max-width);
|
--preferred-max-content-width: var(--options-card-max-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.note-split.options .collection-properties {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a gap at the top of the option pages */
|
/* Create a gap at the top of the option pages */
|
||||||
.note-detail-content-widget-content.options>*:first-child {
|
.note-detail-content-widget-content.options>*:first-child {
|
||||||
margin-top: var(--options-first-item-top-margin, 1em);
|
margin-top: var(--options-first-item-top-margin, 1em);
|
||||||
@@ -261,13 +265,6 @@ body.desktop .options-section:not(.tn-no-card) {
|
|||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.options-section .alert {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
background: var(--alert-bar-background) !important;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-size: .85em;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav.options-section-tabs {
|
nav.options-section-tabs {
|
||||||
min-width: var(--options-card-min-width);
|
min-width: var(--options-card-min-width);
|
||||||
max-width: var(--options-card-max-width);
|
max-width: var(--options-card-max-width);
|
||||||
|
|||||||
@@ -40,13 +40,30 @@ body.mobile {
|
|||||||
|
|
||||||
/* #region Mica */
|
/* #region Mica */
|
||||||
|
|
||||||
|
/* Quirk: --background-material is read before "theme-supports-background-effects" class
|
||||||
|
* is applied. Apply the matterial even if the theme doesn't support it. */
|
||||||
body.background-effects.platform-win32 {
|
body.background-effects.platform-win32 {
|
||||||
/* Quirk: --background-material is read before "theme-supports-background-effects" class
|
&.layout-vertical {
|
||||||
* is applied. Apply the matterial even if the theme doesn't support it. */
|
--background-material: mica;
|
||||||
--background-material: tabbed;
|
}
|
||||||
|
|
||||||
|
&.layout-horizontal {
|
||||||
|
--background-material: tabbed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body.background-effects.theme-supports-background-effects.platform-win32 {
|
body.background-effects.platform-darwin {
|
||||||
|
/** Reference: https://developer.apple.com/documentation/appkit/nsvisualeffectview?preferredLanguage=objc **/
|
||||||
|
&.layout-vertical {
|
||||||
|
--background-material: under-window;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.layout-horizontal {
|
||||||
|
--background-material: hud;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body.background-effects.theme-supports-background-effects {
|
||||||
--launcher-pane-horiz-border-color: var(--launcher-pane-horiz-border-color-bgfx);
|
--launcher-pane-horiz-border-color: var(--launcher-pane-horiz-border-color-bgfx);
|
||||||
--launcher-pane-horiz-background-color: var(--launcher-pane-horiz-background-color-bgfx);
|
--launcher-pane-horiz-background-color: var(--launcher-pane-horiz-background-color-bgfx);
|
||||||
--launcher-pane-vert-background-color: var(--launcher-pane-vert-background-color-bgfx);
|
--launcher-pane-vert-background-color: var(--launcher-pane-vert-background-color-bgfx);
|
||||||
@@ -56,33 +73,29 @@ body.background-effects.theme-supports-background-effects.platform-win32 {
|
|||||||
--root-background: transparent;
|
--root-background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.background-effects.platform-win32.layout-vertical {
|
body.background-effects.theme-supports-background-effects.layout-vertical {
|
||||||
--background-material: mica;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.background-effects.theme-supports-background-effects.platform-win32.layout-vertical {
|
|
||||||
--left-pane-background-color: var(--window-background-color-bgfx);
|
--left-pane-background-color: var(--window-background-color-bgfx);
|
||||||
--center-pane-background-color-bgfx: var(--center-pane-vert-layout-background-color-bgfx);
|
--center-pane-background-color-bgfx: var(--center-pane-vert-layout-background-color-bgfx);
|
||||||
--right-pane-background-color: var(--right-pane-background-color-bgfx);
|
--right-pane-background-color: var(--right-pane-background-color-bgfx);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.background-effects.theme-supports-background-effects.platform-win32.layout-horizontal {
|
body.background-effects.theme-supports-background-effects.layout-horizontal {
|
||||||
--center-pane-background-color-bgfx: var(--center-pane-horiz-layout-background-color-bgfx);
|
--center-pane-background-color-bgfx: var(--center-pane-horiz-layout-background-color-bgfx);
|
||||||
--gutter-color: var(--left-pane-background-color);
|
--gutter-color: var(--left-pane-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.background-effects.theme-supports-background-effects.platform-win32,
|
body.background-effects.theme-supports-background-effects,
|
||||||
body.background-effects.theme-supports-background-effects.platform-win32 #root-widget {
|
body.background-effects.theme-supports-background-effects #root-widget {
|
||||||
background: var(--window-background-color-bgfx) !important;
|
background: var(--window-background-color-bgfx) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.background-effects.theme-supports-background-effects.platform-win32.layout-horizontal #horizontal-main-container,
|
body.background-effects.theme-supports-background-effects.layout-horizontal #horizontal-main-container,
|
||||||
body.background-effects.theme-supports-background-effects.platform-win32.layout-vertical #vertical-main-container {
|
body.background-effects.theme-supports-background-effects.layout-vertical #vertical-main-container {
|
||||||
background-color: var(--root-background);
|
background-color: var(--root-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note split with background effects */
|
/* Note split with background effects */
|
||||||
body.background-effects.theme-supports-background-effects.platform-win32 #center-pane .note-split.bgfx {
|
body.background-effects.theme-supports-background-effects #center-pane .note-split.bgfx {
|
||||||
--note-split-background-color: var(--center-pane-background-color-bgfx);
|
--note-split-background-color: var(--center-pane-background-color-bgfx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,10 +372,6 @@ body[dir=ltr] #launcher-container {
|
|||||||
.calendar-dropdown-widget .calendar-header [data-calendar-input="month"] {
|
.calendar-dropdown-widget .calendar-header [data-calendar-input="month"] {
|
||||||
--input-background-color: transparent;
|
--input-background-color: transparent;
|
||||||
--menu-background-color: transparent;
|
--menu-background-color: transparent;
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1.4em;
|
|
||||||
font-weight: 300;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-dropdown-widget .calendar-header input:not(:focus) {
|
.calendar-dropdown-widget .calendar-header input:not(:focus) {
|
||||||
@@ -412,8 +421,6 @@ body[dir=ltr] #launcher-container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.calendar-dropdown-widget .calendar-week span {
|
.calendar-dropdown-widget .calendar-week span {
|
||||||
font-size: 0.85em;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--calendar-weekday-labels-color);
|
color: var(--calendar-weekday-labels-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,9 +683,10 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
|
|||||||
padding-inline-start: 12px;
|
padding-inline-start: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#left-pane span.fancytree-node.fancytree-active {
|
#left-pane span.fancytree-node.fancytree-active,
|
||||||
|
#left-pane span.fancytree-node.fancytree-active:hover {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: transparent !important;
|
background: transparent;
|
||||||
color: var(--custom-color, var(--left-pane-item-selected-color));
|
color: var(--custom-color, var(--left-pane-item-selected-color));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -691,6 +699,14 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* .fancytree-node pseudo-elements:
|
||||||
|
*
|
||||||
|
* - ::before: the active tree item decorator.
|
||||||
|
* - ::after: the selected tree item background. A pseudo-element is used instead of the
|
||||||
|
* element's background color, to allow alpha compositing for the hover state.
|
||||||
|
*/
|
||||||
|
|
||||||
#left-pane span.fancytree-node.fancytree-active::before {
|
#left-pane span.fancytree-node.fancytree-active::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
content: "";
|
content: "";
|
||||||
@@ -705,6 +721,24 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
|
|||||||
z-index: -1;
|
z-index: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#left-pane span.fancytree-node.fancytree-selected {
|
||||||
|
--left-pane-item-selected-shadow-size: 4px;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#left-pane span.fancytree-node.fancytree-selected::after {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
z-index: -2;
|
||||||
|
content: "";
|
||||||
|
inset: 0;
|
||||||
|
background: var(--selection-background-color);
|
||||||
|
animation: left-pane-item-select 100ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
#left-pane span.fancytree-node.protected > span.fancytree-custom-icon {
|
#left-pane span.fancytree-node.protected > span.fancytree-custom-icon {
|
||||||
position: relative;
|
position: relative;
|
||||||
filter: unset !important;
|
filter: unset !important;
|
||||||
@@ -726,39 +760,35 @@ body[dir=rtl] #left-pane span.fancytree-node.protected > span.fancytree-custom-i
|
|||||||
transform: translateX(-25%);
|
transform: translateX(-25%);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.mobile .fancytree-expander::before,
|
|
||||||
body.mobile .fancytree-title,
|
|
||||||
body.mobile .fancytree-node > span {
|
|
||||||
font-size: 1rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 991px) {
|
@media (max-width: 991px) {
|
||||||
body.mobile #mobile-sidebar-container {
|
body.mobile #mobile-sidebar-container {
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.mobile:not(.force-fixed-tree) #mobile-sidebar-wrapper {
|
body.mobile #mobile-sidebar-wrapper {
|
||||||
border-top-right-radius: 12px;
|
border-top-right-radius: 12px;
|
||||||
border-bottom-right-radius: 12px;
|
border-bottom-right-radius: 12px;
|
||||||
border-inline-end: 1px solid var(--subtle-border-color);
|
border-inline-end: 1px solid var(--subtle-border-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#left-pane .fancytree-expander {
|
#left-pane .fancytree-expander,
|
||||||
|
.nested-note-list-item .note-expander {
|
||||||
opacity: 0.65;
|
opacity: 0.65;
|
||||||
transition: opacity 150ms ease-in;
|
transition: opacity 150ms ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
#left-pane .fancytree-expander:hover {
|
#left-pane .fancytree-expander:hover,
|
||||||
|
.nested-note-list-item .note-expander:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: opacity 300ms ease-out;
|
transition: opacity 300ms ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#left-pane .fancytree-custom-icon {
|
#left-pane .fancytree-custom-icon {
|
||||||
margin-top: 0; /* Use this to align the icon with the tree view item's caption */
|
margin-top: 0; /* Use this to align the icon with the tree view item's caption */
|
||||||
|
color: var(--custom-color, var(--left-pane-icon-color));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#left-pane span.fancytree-active .fancytree-title {
|
#left-pane span.fancytree-active .fancytree-title {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
@@ -771,7 +801,8 @@ body.mobile .fancytree-node > span {
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
#left-pane .tree-item-button {
|
#left-pane .tree-item-button,
|
||||||
|
#left-pane span.fancytree-node.fancytree-selected .fancytree-custom-icon {
|
||||||
margin-inline-end: 6px;
|
margin-inline-end: 6px;
|
||||||
border: unset;
|
border: unset;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@@ -782,7 +813,8 @@ body.mobile .fancytree-node > span {
|
|||||||
box-shadow 200ms ease-out;
|
box-shadow 200ms ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#left-pane .tree-item-button:hover {
|
#left-pane .tree-item-button:hover,
|
||||||
|
#left-pane span.fancytree-node.fancytree-selected .fancytree-custom-icon:hover {
|
||||||
background: var(--left-pane-item-action-button-hover-background);
|
background: var(--left-pane-item-action-button-hover-background);
|
||||||
box-shadow: var(--left-pane-item-action-button-hover-shadow);
|
box-shadow: var(--left-pane-item-action-button-hover-shadow);
|
||||||
transition:
|
transition:
|
||||||
@@ -790,10 +822,41 @@ body.mobile .fancytree-node > span {
|
|||||||
box-shadow 100ms ease-in;
|
box-shadow 100ms ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
#left-pane span.fancytree-node.fancytree-active .tree-item-button:hover {
|
#left-pane span.fancytree-node.fancytree-active .tree-item-button:hover,
|
||||||
|
#left-pane span.fancytree-node.fancytree-active.fancytree-selected .fancytree-custom-icon:hover {
|
||||||
box-shadow: var(--left-pane-item-selected-action-button-hover-shadow);
|
box-shadow: var(--left-pane-item-selected-action-button-hover-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Selected item bulk action button */
|
||||||
|
|
||||||
|
@keyframes bulk-action-button-blink {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: .3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#left-pane span.fancytree-node.fancytree-selected .fancytree-custom-icon {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#left-pane span.fancytree-node.fancytree-selected .fancytree-custom-icon::before {
|
||||||
|
border: 0;
|
||||||
|
font-size: .65em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#left-pane span.fancytree-node.fancytree-selected:hover .fancytree-custom-icon:not(:hover)::before {
|
||||||
|
animation: bulk-action-button-blink 500ms linear infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
#left-pane span.fancytree-node.fancytree-selected.protected .fancytree-custom-icon::after {
|
||||||
|
/* Protected note indicator */
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#context-menu-container {
|
#context-menu-container {
|
||||||
/* The context menu of the tree */
|
/* The context menu of the tree */
|
||||||
--menu-item-icon-vert-offset: -1px;
|
--menu-item-icon-vert-offset: -1px;
|
||||||
@@ -1024,7 +1087,7 @@ body.layout-vertical.electron.platform-darwin .tab-row-container {
|
|||||||
height: var(--tab-height) !important;
|
height: var(--tab-height) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-row-widget > * {
|
body.layout-vertical .tab-row-widget > * {
|
||||||
margin-top: calc((var(--tab-bar-height) - var(--tab-height)) / 2);
|
margin-top: calc((var(--tab-bar-height) - var(--tab-height)) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1054,7 +1117,7 @@ body.layout-horizontal .tab-row-widget-container {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.desktop:not(.background-effects.platform-win32) #root-widget.horizontal-layout {
|
body.desktop:not(.background-effects) #root-widget.horizontal-layout {
|
||||||
background-color: var(--root-background) !important;
|
background-color: var(--root-background) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1259,7 +1322,7 @@ body.layout-horizontal #rest-pane > .classic-toolbar-widget {
|
|||||||
#center-pane .note-split {
|
#center-pane .note-split {
|
||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
background-color: var(--note-split-background-color, var(--main-background-color));
|
background-color: var(--note-split-background-color, var(--main-background-color));
|
||||||
transition: border-color 250ms ease-in;
|
transition: border-color 150ms ease-out;
|
||||||
border: 2px solid transparent;
|
border: 2px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1309,7 +1372,7 @@ body.mobile .note-title {
|
|||||||
margin-inline-start: 0;
|
margin-inline-start: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-row {
|
body.desktop .title-row {
|
||||||
/* Aligns the "Create new split" button with the note menu button (the three dots button) */
|
/* Aligns the "Create new split" button with the note menu button (the three dots button) */
|
||||||
padding-inline-end: 3px;
|
padding-inline-end: 3px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,10 +140,22 @@ ul.fancytree-container {
|
|||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.fancytree-custom-icon {
|
.fancytree-custom-icon {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fallback icon */
|
||||||
|
:where(.fancytree-custom-icon)::before {
|
||||||
|
content: "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Protected note icon badge */
|
||||||
span.fancytree-node.protected > span.fancytree-custom-icon {
|
span.fancytree-node.protected > span.fancytree-custom-icon {
|
||||||
filter: drop-shadow(2px 2px 2px var(--main-text-color));
|
filter: drop-shadow(2px 2px 2px var(--main-text-color));
|
||||||
}
|
}
|
||||||
@@ -185,7 +197,7 @@ span.fancytree-node.fancytree-active-clone:not(.fancytree-active) .fancytree-tit
|
|||||||
|
|
||||||
span.fancytree-active {
|
span.fancytree-active {
|
||||||
color: var(--active-item-text-color);
|
color: var(--active-item-text-color);
|
||||||
background-color: var(--active-item-background-color) !important;
|
background-color: var(--active-item-background-color);
|
||||||
border-color: transparent; /* invisible border */
|
border-color: transparent; /* invisible border */
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
@@ -195,19 +207,15 @@ span.fancytree-active .fancytree-title {
|
|||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.fancytree-selected {
|
span.fancytree-node.fancytree-selected {
|
||||||
border-color: var(--main-border-color) !important;
|
background-color: var(--selection-background-color);
|
||||||
border-radius: 5px;
|
border-radius: 0;
|
||||||
}
|
|
||||||
|
|
||||||
span.fancytree-selected .fancytree-title {
|
|
||||||
text-decoration: underline;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
span.fancytree-selected .fancytree-custom-icon::before {
|
span.fancytree-selected .fancytree-custom-icon::before {
|
||||||
content: "\eb43";
|
font-family: "boxicons";
|
||||||
border: 1px solid var(--main-border-color);
|
content: "\ef05";
|
||||||
|
border: 1px solid var(--main-text-color);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,9 @@
|
|||||||
"widget-render-error": {
|
"widget-render-error": {
|
||||||
"title": "فشل عرض عنصر واجهة مستخدم React مخصص"
|
"title": "فشل عرض عنصر واجهة مستخدم React مخصص"
|
||||||
},
|
},
|
||||||
"widget-missing-parent": "لا تحتوي الأداة المخصصة على خاصية إلزامية '{{property}}'.\n\nإذا كان من المفترض تشغيل هذا البرنامج النصي بدون عنصر واجهة مستخدم، فاستخدم '#run=frontendStartup' بدلاً من ذلك."
|
"widget-missing-parent": "لا تحتوي الأداة المخصصة على خاصية إلزامية '{{property}}'.\n\nإذا كان من المفترض تشغيل هذا البرنامج النصي بدون عنصر واجهة مستخدم، فاستخدم '#run=frontendStartup' بدلاً من ذلك.",
|
||||||
|
"open-script-note": "فتح ملاحظة برمجية",
|
||||||
|
"scripting-error": "خطأ في النص البرمجي المخصص: {{title}}"
|
||||||
},
|
},
|
||||||
"add_link": {
|
"add_link": {
|
||||||
"add_link": "أضافة رابط",
|
"add_link": "أضافة رابط",
|
||||||
@@ -37,14 +39,19 @@
|
|||||||
"search_note": "البحث عن الملاحظة بالاسم",
|
"search_note": "البحث عن الملاحظة بالاسم",
|
||||||
"link_title": "عنوان الرابط",
|
"link_title": "عنوان الرابط",
|
||||||
"button_add_link": "اضافة رابط",
|
"button_add_link": "اضافة رابط",
|
||||||
"help_on_links": "مساعدة حول الارتباطات التشعبية"
|
"help_on_links": "مساعدة حول الارتباطات التشعبية",
|
||||||
|
"link_title_mirrors": "عنوان الرابط يعكس العنوان الحالي للملاحظة",
|
||||||
|
"link_title_arbitrary": "يمكن تغيير عنوان الرابط حسب الرغبة"
|
||||||
},
|
},
|
||||||
"branch_prefix": {
|
"branch_prefix": {
|
||||||
"edit_branch_prefix": "تعديل بادئة الفرع",
|
"edit_branch_prefix": "تعديل بادئة الفرع",
|
||||||
"prefix": "البادئة: ",
|
"prefix": "البادئة: ",
|
||||||
"save": "حفظ",
|
"save": "حفظ",
|
||||||
"help_on_tree_prefix": "مساعدة حول بادئة الشجرة",
|
"help_on_tree_prefix": "مساعدة حول بادئة الشجرة",
|
||||||
"branch_prefix_saved": "تم حفظ بادئة الفرع."
|
"branch_prefix_saved": "تم حفظ بادئة الفرع.",
|
||||||
|
"edit_branch_prefix_multiple": "تعديل البادئة لـ {{count}} من تفرعات الملاحظات",
|
||||||
|
"branch_prefix_saved_multiple": "تم حفظ بادئة التفرع لـ {{count}} من التفرعات.",
|
||||||
|
"affected_branches": "الفروع المتأثرة ({{count}}):"
|
||||||
},
|
},
|
||||||
"bulk_actions": {
|
"bulk_actions": {
|
||||||
"bulk_actions": "اجراءات جماعية",
|
"bulk_actions": "اجراءات جماعية",
|
||||||
@@ -559,113 +566,6 @@
|
|||||||
"enable-smooth-scroll": "تمكين التمرير السلس",
|
"enable-smooth-scroll": "تمكين التمرير السلس",
|
||||||
"enable-motion": "تمكين الانتقالات والرسوم المتحركة"
|
"enable-motion": "تمكين الانتقالات والرسوم المتحركة"
|
||||||
},
|
},
|
||||||
"ai_llm": {
|
|
||||||
"progress": "تقدم",
|
|
||||||
"openai_tab": "OpenAI",
|
|
||||||
"actions": "أجراءات",
|
|
||||||
"retry": "أعد المحاولة",
|
|
||||||
"reprocessing_index": "جار اعادة البناء...",
|
|
||||||
"never": "ابدٱ",
|
|
||||||
"agent": {
|
|
||||||
"processing": "جار المعالجة...",
|
|
||||||
"thinking": "جار التفكير...",
|
|
||||||
"loading": "جار التحميل...",
|
|
||||||
"generating": "جار الانشاء..."
|
|
||||||
},
|
|
||||||
"name": "الذكاء الأصطناعي",
|
|
||||||
"openai": "OpenAI",
|
|
||||||
"sources": "مصادر",
|
|
||||||
"temperature": "درجة الحرارة",
|
|
||||||
"model": "نموذج",
|
|
||||||
"refreshing_models": "جار التحديث...",
|
|
||||||
"error": "خطأ",
|
|
||||||
"refreshing": "جار التحديث...",
|
|
||||||
"ollama_tab": "Ollama",
|
|
||||||
"anthropic_tab": "انتروبيك",
|
|
||||||
"not_started": "لم يبدأ بعد",
|
|
||||||
"title": "اعدادات AI",
|
|
||||||
"processed_notes": "الملاحظات المعالجة",
|
|
||||||
"total_notes": "الملاحظات الكلية",
|
|
||||||
"queued_notes": "الملاحظات في قائمة الانتظار",
|
|
||||||
"failed_notes": "الملاحظات الفاشلة",
|
|
||||||
"last_processed": "اخر معالجة",
|
|
||||||
"refresh_stats": "تحديث الاحصائيات",
|
|
||||||
"voyage_tab": "استكشاف AI",
|
|
||||||
"provider_precedence": "اولوية المزود",
|
|
||||||
"system_prompt": "موجه النظام",
|
|
||||||
"openai_configuration": "اعدادات OpenAI",
|
|
||||||
"openai_settings": "اعدادات OpenAI",
|
|
||||||
"api_key": "مفتاح واجهة برمجة التطبيقات",
|
|
||||||
"url": "عنوان URL الاساسي",
|
|
||||||
"default_model": "النموذج الافتراضي",
|
|
||||||
"base_url": "عنوان URL الأساسي",
|
|
||||||
"openai_url_description": "افتراضيا: https://api.openai.com/v1",
|
|
||||||
"anthropic_settings": "اعدادات انتروبيك",
|
|
||||||
"ollama_settings": "اعدادات Ollama",
|
|
||||||
"anthropic_configuration": "تهيئة انتروبيك",
|
|
||||||
"voyage_url_description": "افتراضيا: https://api.voyageai.com/v1",
|
|
||||||
"ollama_configuration": "تهيئة Ollama",
|
|
||||||
"enable_ollama": "تمكين Ollama",
|
|
||||||
"last_attempt": "اخر محاولة",
|
|
||||||
"active_providers": "المزودون النشطون",
|
|
||||||
"disabled_providers": "المزودون المعطلون",
|
|
||||||
"similarity_threshold": "عتبة التشابه",
|
|
||||||
"complete": "اكتمل (100%)",
|
|
||||||
"ai_settings": "اعدادات AI",
|
|
||||||
"show_thinking": "عرض التفكير",
|
|
||||||
"index_status": "حالة الفهرس",
|
|
||||||
"indexed_notes": "الملاحظات المفهرسة",
|
|
||||||
"indexing_stopped": "تم ايقاف الفهرسة",
|
|
||||||
"last_indexed": "اخر فهرسة",
|
|
||||||
"note_chat": "دردشة الملاحظة",
|
|
||||||
"start_indexing": "بدء الفهرسة",
|
|
||||||
"chat": {
|
|
||||||
"root_note_title": "دردشات AI",
|
|
||||||
"new_chat_title": "دردشة جديدة",
|
|
||||||
"create_new_ai_chat": "انشاء دردشة AI جديدة"
|
|
||||||
},
|
|
||||||
"selected_provider": "المزود المحدد",
|
|
||||||
"select_model": "اختر النموذج...",
|
|
||||||
"select_provider": "اختر المزود...",
|
|
||||||
"ollama_model": "نموذج Ollama",
|
|
||||||
"refresh_models": "تحديث النماذج",
|
|
||||||
"rebuild_index": "اعادة بناء الفهرس",
|
|
||||||
"note_title": "عنوان الملاحظة",
|
|
||||||
"processing": "جاري المعالجة ({{percentage}}%)",
|
|
||||||
"incomplete": "غير مكتمل ({{percentage}}%)",
|
|
||||||
"ollama_url": "عنوان URL الخاص ب Ollama",
|
|
||||||
"provider_configuration": "تكوين موفر AI",
|
|
||||||
"voyage_settings": "استكشاف اعدادات AI",
|
|
||||||
"enable_automatic_indexing": "تمكين الفهرسة التلقائية",
|
|
||||||
"index_rebuild_progress": "تقدم اعادة انشاء الفهرس",
|
|
||||||
"index_rebuild_complete": "اكتملت عملية تحسين الفهرس",
|
|
||||||
"use_enhanced_context": "استخدام السياق المحسن",
|
|
||||||
"enter_message": "ادخل رسالتك...",
|
|
||||||
"index_all_notes": "فهرسة جميع الملاحظات",
|
|
||||||
"indexing_in_progress": "جار فهرسة الملاحظات...",
|
|
||||||
"use_advanced_context": "استخدم السياق المتقدم",
|
|
||||||
"ai_enabled": "تمكين مميزات AI",
|
|
||||||
"ai_disabled": "الغاء تمكين مميزات AI",
|
|
||||||
"enable_ai_features": "تمكين خصائص AI/LLM",
|
|
||||||
"enable_ai": "تمكين خصائص AI/LLM",
|
|
||||||
"reprocess_index": "اعادة بناء فهرس البحث",
|
|
||||||
"index_rebuilding": "جار تحسين الفهرس {{percentage}}",
|
|
||||||
"voyage_configuration": "اعدادت Voyage AI",
|
|
||||||
"openai_model_description": "الامثلة: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
|
|
||||||
"partial": "{{ percentage }} % مكتمل",
|
|
||||||
"retry_queued": "تم جدولة الملاحظة لاعادة المحاولة",
|
|
||||||
"max_notes_per_llm_query": "اكبر عدد للملاحظات لكل استعلام",
|
|
||||||
"remove_provider": "احذف المزود من البحث",
|
|
||||||
"restore_provider": "استعادة المزود الى البحث",
|
|
||||||
"reprocess_index_error": "حدث خطأ اثناء اعادة بناء فهرس البحث",
|
|
||||||
"auto_refresh_notice": "تحديث تلقائي كل {{seconds}} ثانية",
|
|
||||||
"note_queued_for_retry": "الملاحظة جاهزة لاعادة المحاولة لاحقا",
|
|
||||||
"failed_to_retry_note": "فشل في اعادة محاولة معالجة المحاولة",
|
|
||||||
"failed_to_retry_all": "فشل في اعادة محاولة معالجة الملاحظة",
|
|
||||||
"error_generating_response": "فشل في توليد استجابة من ال AI",
|
|
||||||
"create_new_ai_chat": "انشاء دردشة AI جديدة",
|
|
||||||
"error_fetching": "فشل في استرجاع النماذج: {{error}}"
|
|
||||||
},
|
|
||||||
"code_auto_read_only_size": {
|
"code_auto_read_only_size": {
|
||||||
"unit": "حروف",
|
"unit": "حروف",
|
||||||
"title": "الحجم التلقائي للقراءه فقط"
|
"title": "الحجم التلقائي للقراءه فقط"
|
||||||
@@ -903,13 +803,13 @@
|
|||||||
"web-view": "عرض الويب",
|
"web-view": "عرض الويب",
|
||||||
"mind-map": "خريطة ذهنية",
|
"mind-map": "خريطة ذهنية",
|
||||||
"geo-map": "خريطة جغرافية",
|
"geo-map": "خريطة جغرافية",
|
||||||
"ai-chat": "دردشة AI",
|
"task-list": "قائمة المهام",
|
||||||
"task-list": "قائمة المهام"
|
"spreadsheet": "جدول البيانات"
|
||||||
},
|
},
|
||||||
"shared_switch": {
|
"shared_switch": {
|
||||||
"shared": "مشترك",
|
"shared": "مشترك",
|
||||||
"toggle-on-title": "مشاركة الملاحظة",
|
"toggle-on-title": "مشاركة الملاحظة",
|
||||||
"toggle-off-title": "الغاء مشاركة الملاحظة"
|
"toggle-off-title": "إلغاء مشاركة الملاحظة"
|
||||||
},
|
},
|
||||||
"template_switch": {
|
"template_switch": {
|
||||||
"template": "قالب"
|
"template": "قالب"
|
||||||
@@ -983,6 +883,7 @@
|
|||||||
"electron_context_menu": {
|
"electron_context_menu": {
|
||||||
"cut": "قص",
|
"cut": "قص",
|
||||||
"copy": "نسخ",
|
"copy": "نسخ",
|
||||||
|
"copy-as-markdown": "نسخ كـ Markdown",
|
||||||
"paste": "لصق",
|
"paste": "لصق",
|
||||||
"copy-link": "نسخ الرابط",
|
"copy-link": "نسخ الرابط",
|
||||||
"add-term-to-dictionary": "اضافة \"{{term}}\" الى القاموس",
|
"add-term-to-dictionary": "اضافة \"{{term}}\" الى القاموس",
|
||||||
@@ -1168,14 +1069,10 @@
|
|||||||
"rename_note": "اعادة تسمية الملاحظة",
|
"rename_note": "اعادة تسمية الملاحظة",
|
||||||
"remove_relation": "حذف العلاقة",
|
"remove_relation": "حذف العلاقة",
|
||||||
"default_new_note_title": "ملاحظة جديدة",
|
"default_new_note_title": "ملاحظة جديدة",
|
||||||
"open_in_new_tab": "فتح في تبويب جديد",
|
|
||||||
"enter_new_title": "ادخل عنوان ملاحظة جديدة:",
|
"enter_new_title": "ادخل عنوان ملاحظة جديدة:",
|
||||||
"note_not_found": "الملاحظة {{noteId}} غير موجودة!",
|
"note_not_found": "الملاحظة {{noteId}} غير موجودة!",
|
||||||
"cannot_match_transform": "تعذر مطابقة التحويل: {{transform}}"
|
"cannot_match_transform": "تعذر مطابقة التحويل: {{transform}}"
|
||||||
},
|
},
|
||||||
"web_view": {
|
|
||||||
"web_view": "عرض الويب"
|
|
||||||
},
|
|
||||||
"consistency_checks": {
|
"consistency_checks": {
|
||||||
"title": "فحوصات التناسق"
|
"title": "فحوصات التناسق"
|
||||||
},
|
},
|
||||||
@@ -1389,8 +1286,10 @@
|
|||||||
"search-for": "بحث ل \"{{term}}\""
|
"search-for": "بحث ل \"{{term}}\""
|
||||||
},
|
},
|
||||||
"protect_note": {
|
"protect_note": {
|
||||||
"toggle-off": "ازالة الحماية عن الملاحظة",
|
"toggle-off": "إزالة الحماية عن الملاحظة",
|
||||||
"toggle-on": "حماية الملاحظة"
|
"toggle-on": "حماية الملاحظة",
|
||||||
|
"toggle-on-hint": "الملاحظة غير محمة، انقر لحمايتها",
|
||||||
|
"toggle-off-hint": "الملاحظة محمية، انقر لإزالة الحماية منها"
|
||||||
},
|
},
|
||||||
"open-help-page": "فتح صفحة المساعدة",
|
"open-help-page": "فتح صفحة المساعدة",
|
||||||
"empty": {
|
"empty": {
|
||||||
|
|||||||
@@ -93,7 +93,10 @@
|
|||||||
"digits": "dígits",
|
"digits": "dígits",
|
||||||
"inheritable": "Heretable",
|
"inheritable": "Heretable",
|
||||||
"delete": "Suprimeix",
|
"delete": "Suprimeix",
|
||||||
"color_type": "Color"
|
"color_type": "Color",
|
||||||
|
"textarea": "Text multi linia",
|
||||||
|
"date_time": "Data i hora",
|
||||||
|
"precision_title": "Quants dígits han d'estar disponibles per a coma flotant a la interfície de configuració."
|
||||||
},
|
},
|
||||||
"rename_label": {
|
"rename_label": {
|
||||||
"to": "Per"
|
"to": "Per"
|
||||||
|
|||||||
@@ -446,7 +446,8 @@
|
|||||||
"and_more": "... 以及另外 {{count}} 个。",
|
"and_more": "... 以及另外 {{count}} 个。",
|
||||||
"print_landscape": "导出为 PDF 时,将页面方向更改为横向而不是纵向。",
|
"print_landscape": "导出为 PDF 时,将页面方向更改为横向而不是纵向。",
|
||||||
"print_page_size": "导出为 PDF 时,更改页面大小。支持的值:<code>A0</code>、<code>A1</code>、<code>A2</code>、<code>A3</code>、<code>A4</code>、<code>A5</code>、<code>A6</code>、<code>Legal</code>、<code>Letter</code>、<code>Tabloid</code>、<code>Ledger</code>。",
|
"print_page_size": "导出为 PDF 时,更改页面大小。支持的值:<code>A0</code>、<code>A1</code>、<code>A2</code>、<code>A3</code>、<code>A4</code>、<code>A5</code>、<code>A6</code>、<code>Legal</code>、<code>Letter</code>、<code>Tabloid</code>、<code>Ledger</code>。",
|
||||||
"color_type": "颜色"
|
"color_type": "颜色",
|
||||||
|
"textarea": "多行文本"
|
||||||
},
|
},
|
||||||
"attribute_editor": {
|
"attribute_editor": {
|
||||||
"help_text_body1": "要添加标签,只需输入例如 <code>#rock</code> 或者如果您还想添加值,则例如 <code>#year = 2020</code>",
|
"help_text_body1": "要添加标签,只需输入例如 <code>#rock</code> 或者如果您还想添加值,则例如 <code>#year = 2020</code>",
|
||||||
@@ -662,7 +663,8 @@
|
|||||||
"show-cheatsheet": "显示快捷帮助",
|
"show-cheatsheet": "显示快捷帮助",
|
||||||
"toggle-zen-mode": "禅模式",
|
"toggle-zen-mode": "禅模式",
|
||||||
"new-version-available": "新更新可用",
|
"new-version-available": "新更新可用",
|
||||||
"download-update": "取得版本 {{latestVersion}}"
|
"download-update": "取得版本 {{latestVersion}}",
|
||||||
|
"search_notes": "搜索笔记"
|
||||||
},
|
},
|
||||||
"zen_mode": {
|
"zen_mode": {
|
||||||
"button_exit": "退出禅模式"
|
"button_exit": "退出禅模式"
|
||||||
@@ -745,7 +747,7 @@
|
|||||||
"button_title": "导出SVG格式图片"
|
"button_title": "导出SVG格式图片"
|
||||||
},
|
},
|
||||||
"relation_map_buttons": {
|
"relation_map_buttons": {
|
||||||
"create_child_note_title": "创建新的子笔记并添加到关系图",
|
"create_child_note_title": "创建子笔记并添加到图",
|
||||||
"reset_pan_zoom_title": "重置平移和缩放到初始坐标和放大倍率",
|
"reset_pan_zoom_title": "重置平移和缩放到初始坐标和放大倍率",
|
||||||
"zoom_in_title": "放大",
|
"zoom_in_title": "放大",
|
||||||
"zoom_out_title": "缩小"
|
"zoom_out_title": "缩小"
|
||||||
@@ -759,7 +761,9 @@
|
|||||||
"delete_this_note": "删除此笔记",
|
"delete_this_note": "删除此笔记",
|
||||||
"error_cannot_get_branch_id": "无法获取 notePath '{{notePath}}' 的 branchId",
|
"error_cannot_get_branch_id": "无法获取 notePath '{{notePath}}' 的 branchId",
|
||||||
"error_unrecognized_command": "无法识别的命令 {{command}}",
|
"error_unrecognized_command": "无法识别的命令 {{command}}",
|
||||||
"note_revisions": "笔记历史版本"
|
"note_revisions": "笔记历史版本",
|
||||||
|
"backlinks": "反链",
|
||||||
|
"content_language_switcher": "内容语言: {{language}}"
|
||||||
},
|
},
|
||||||
"note_icon": {
|
"note_icon": {
|
||||||
"change_note_icon": "更改笔记图标",
|
"change_note_icon": "更改笔记图标",
|
||||||
@@ -910,7 +914,8 @@
|
|||||||
"unknown_search_option": "未知的搜索选项 {{searchOptionName}}",
|
"unknown_search_option": "未知的搜索选项 {{searchOptionName}}",
|
||||||
"search_note_saved": "搜索笔记已保存到 {{- notePathTitle}}",
|
"search_note_saved": "搜索笔记已保存到 {{- notePathTitle}}",
|
||||||
"actions_executed": "操作已执行。",
|
"actions_executed": "操作已执行。",
|
||||||
"view_options": "查看选项:"
|
"view_options": "查看选项:",
|
||||||
|
"option": "选项"
|
||||||
},
|
},
|
||||||
"similar_notes": {
|
"similar_notes": {
|
||||||
"title": "相似笔记",
|
"title": "相似笔记",
|
||||||
@@ -1004,7 +1009,7 @@
|
|||||||
"no_attachments": "此笔记没有附件。"
|
"no_attachments": "此笔记没有附件。"
|
||||||
},
|
},
|
||||||
"book": {
|
"book": {
|
||||||
"no_children_help": "此类型为书籍的笔记没有任何子笔记,因此没有内容显示。请参阅 <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> 了解详情。",
|
"no_children_help": "此集合没有任何子笔记,因此没有内容显示。",
|
||||||
"drag_locked_title": "锁定编辑",
|
"drag_locked_title": "锁定编辑",
|
||||||
"drag_locked_message": "无法拖拽,因为集合已被锁定编辑。"
|
"drag_locked_message": "无法拖拽,因为集合已被锁定编辑。"
|
||||||
},
|
},
|
||||||
@@ -1043,7 +1048,6 @@
|
|||||||
"unprotecting-title": "解除保护状态"
|
"unprotecting-title": "解除保护状态"
|
||||||
},
|
},
|
||||||
"relation_map": {
|
"relation_map": {
|
||||||
"open_in_new_tab": "在新标签页中打开",
|
|
||||||
"remove_note": "删除笔记",
|
"remove_note": "删除笔记",
|
||||||
"edit_title": "编辑标题",
|
"edit_title": "编辑标题",
|
||||||
"rename_note": "重命名笔记",
|
"rename_note": "重命名笔记",
|
||||||
@@ -1060,15 +1064,6 @@
|
|||||||
"default_new_note_title": "新笔记",
|
"default_new_note_title": "新笔记",
|
||||||
"click_on_canvas_to_place_new_note": "点击画布以放置新笔记"
|
"click_on_canvas_to_place_new_note": "点击画布以放置新笔记"
|
||||||
},
|
},
|
||||||
"render": {
|
|
||||||
"note_detail_render_help_1": "之所以显示此帮助说明,是因为这个类型为渲染 HTML 的笔记没有正常工作所需的关系。",
|
|
||||||
"note_detail_render_help_2": "渲染 HTML 笔记类型用于<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/scripts.html\">编写脚本</a>。简而言之,您有一份 HTML 代码笔记(可包含一些 JavaScript),然后这个笔记会把页面渲染出来。要使其正常工作,您需要定义一个名为 \"renderNote\" 的<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/attributes.html\">关系</a>指向要渲染的 HTML 笔记。"
|
|
||||||
},
|
|
||||||
"web_view": {
|
|
||||||
"web_view": "网页视图",
|
|
||||||
"embed_websites": "网页视图类型的笔记允许您将网站嵌入到 Trilium 中。",
|
|
||||||
"create_label": "首先,请创建一个带有您要嵌入的 URL 地址的标签,例如 #webViewSrc=\"https://www.bing.com\""
|
|
||||||
},
|
|
||||||
"backend_log": {
|
"backend_log": {
|
||||||
"refresh": "刷新"
|
"refresh": "刷新"
|
||||||
},
|
},
|
||||||
@@ -1417,7 +1412,8 @@
|
|||||||
"description": "描述",
|
"description": "描述",
|
||||||
"reload_app": "重载应用以应用更改",
|
"reload_app": "重载应用以应用更改",
|
||||||
"set_all_to_default": "将所有快捷键重置为默认值",
|
"set_all_to_default": "将所有快捷键重置为默认值",
|
||||||
"confirm_reset": "您确定要将所有键盘快捷键重置为默认值吗?"
|
"confirm_reset": "您确定要将所有键盘快捷键重置为默认值吗?",
|
||||||
|
"no_results": "未找到与“{{filter}}”匹配的快捷方式"
|
||||||
},
|
},
|
||||||
"spellcheck": {
|
"spellcheck": {
|
||||||
"title": "拼写检查",
|
"title": "拼写检查",
|
||||||
@@ -1536,10 +1532,11 @@
|
|||||||
"geo-map": "地理地图",
|
"geo-map": "地理地图",
|
||||||
"beta-feature": "测试版",
|
"beta-feature": "测试版",
|
||||||
"task-list": "任务列表",
|
"task-list": "任务列表",
|
||||||
"ai-chat": "AI聊天",
|
|
||||||
"new-feature": "新建",
|
"new-feature": "新建",
|
||||||
"collections": "集合",
|
"collections": "集合",
|
||||||
"book": "集合"
|
"book": "集合",
|
||||||
|
"ai-chat": "AI聊天",
|
||||||
|
"spreadsheet": "电子表格"
|
||||||
},
|
},
|
||||||
"protect_note": {
|
"protect_note": {
|
||||||
"toggle-on": "保护笔记",
|
"toggle-on": "保护笔记",
|
||||||
@@ -1618,7 +1615,9 @@
|
|||||||
"print_report_title": "打印报告",
|
"print_report_title": "打印报告",
|
||||||
"print_report_collection_content_other": "集合中的 {{count}} 篇笔记无法打印,因为它们不受支持或受到保护。",
|
"print_report_collection_content_other": "集合中的 {{count}} 篇笔记无法打印,因为它们不受支持或受到保护。",
|
||||||
"print_report_collection_details_button": "查看详情",
|
"print_report_collection_details_button": "查看详情",
|
||||||
"print_report_collection_details_ignored_notes": "忽略的笔记"
|
"print_report_collection_details_ignored_notes": "忽略的笔记",
|
||||||
|
"print_report_error_title": "打印失败",
|
||||||
|
"print_report_stack_trace": "堆栈跟踪"
|
||||||
},
|
},
|
||||||
"note_title": {
|
"note_title": {
|
||||||
"placeholder": "请输入笔记标题...",
|
"placeholder": "请输入笔记标题...",
|
||||||
@@ -1633,13 +1632,18 @@
|
|||||||
},
|
},
|
||||||
"search_result": {
|
"search_result": {
|
||||||
"no_notes_found": "没有找到符合搜索条件的笔记。",
|
"no_notes_found": "没有找到符合搜索条件的笔记。",
|
||||||
"search_not_executed": "尚未执行搜索。请点击上方的\"搜索\"按钮查看结果。"
|
"search_not_executed": "尚未执行搜索。",
|
||||||
|
"search_now": "立即搜索"
|
||||||
},
|
},
|
||||||
"spacer": {
|
"spacer": {
|
||||||
"configure_launchbar": "配置启动栏"
|
"configure_launchbar": "配置启动栏"
|
||||||
},
|
},
|
||||||
"sql_result": {
|
"sql_result": {
|
||||||
"no_rows": "此查询没有返回任何数据"
|
"no_rows": "此查询没有返回任何数据",
|
||||||
|
"not_executed": "查询尚未执行。",
|
||||||
|
"failed": "SQL 查询执行失败",
|
||||||
|
"execute_now": "立即执行",
|
||||||
|
"statement_result": "执行结果"
|
||||||
},
|
},
|
||||||
"sql_table_schemas": {
|
"sql_table_schemas": {
|
||||||
"tables": "表"
|
"tables": "表"
|
||||||
@@ -1757,6 +1761,7 @@
|
|||||||
"add-term-to-dictionary": "将 \"{{term}}\" 添加到字典",
|
"add-term-to-dictionary": "将 \"{{term}}\" 添加到字典",
|
||||||
"cut": "剪切",
|
"cut": "剪切",
|
||||||
"copy": "复制",
|
"copy": "复制",
|
||||||
|
"copy-as-markdown": "复制为 Markdown",
|
||||||
"copy-link": "复制链接",
|
"copy-link": "复制链接",
|
||||||
"paste": "粘贴",
|
"paste": "粘贴",
|
||||||
"paste-as-plain-text": "以纯文本粘贴",
|
"paste-as-plain-text": "以纯文本粘贴",
|
||||||
@@ -1778,8 +1783,8 @@
|
|||||||
"desktop-application": "桌面应用程序",
|
"desktop-application": "桌面应用程序",
|
||||||
"native-title-bar": "原生标题栏",
|
"native-title-bar": "原生标题栏",
|
||||||
"native-title-bar-description": "对于 Windows 和 macOS,关闭原生标题栏可使应用程序看起来更紧凑。在 Linux 上,保留原生标题栏可以更好地与系统集成。",
|
"native-title-bar-description": "对于 Windows 和 macOS,关闭原生标题栏可使应用程序看起来更紧凑。在 Linux 上,保留原生标题栏可以更好地与系统集成。",
|
||||||
"background-effects": "启用背景效果(仅适用于 Windows 11)",
|
"background-effects": "启用背景效果",
|
||||||
"background-effects-description": "Mica 效果为应用窗口添加模糊且时尚的背景,营造出深度感和现代外观。「原生标题栏」必須被禁用。",
|
"background-effects-description": "为应用窗口添加模糊且时尚的背景,营造出深度感和现代外观。「原生标题栏」必須被禁用。",
|
||||||
"restart-app-button": "重启应用程序以查看更改",
|
"restart-app-button": "重启应用程序以查看更改",
|
||||||
"zoom-factor": "缩放系数"
|
"zoom-factor": "缩放系数"
|
||||||
},
|
},
|
||||||
@@ -1798,7 +1803,8 @@
|
|||||||
"geo-map": {
|
"geo-map": {
|
||||||
"create-child-note-title": "创建一个新的子笔记并将其添加到地图中",
|
"create-child-note-title": "创建一个新的子笔记并将其添加到地图中",
|
||||||
"create-child-note-instruction": "单击地图以在该位置创建新笔记,或按 Escape 以取消。",
|
"create-child-note-instruction": "单击地图以在该位置创建新笔记,或按 Escape 以取消。",
|
||||||
"unable-to-load-map": "无法加载地图。"
|
"unable-to-load-map": "无法加载地图。",
|
||||||
|
"create-child-note-text": "添加标记"
|
||||||
},
|
},
|
||||||
"geo-map-context": {
|
"geo-map-context": {
|
||||||
"open-location": "打开位置",
|
"open-location": "打开位置",
|
||||||
@@ -1836,149 +1842,6 @@
|
|||||||
"yesterday": "昨天"
|
"yesterday": "昨天"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ai_llm": {
|
|
||||||
"not_started": "未开始",
|
|
||||||
"title": "AI设置",
|
|
||||||
"processed_notes": "已处理笔记",
|
|
||||||
"total_notes": "笔记总数",
|
|
||||||
"progress": "进度",
|
|
||||||
"queued_notes": "排队中笔记",
|
|
||||||
"failed_notes": "失败笔记",
|
|
||||||
"last_processed": "最后处理时间",
|
|
||||||
"refresh_stats": "刷新统计数据",
|
|
||||||
"enable_ai_features": "启用AI/LLM功能",
|
|
||||||
"enable_ai_description": "启用笔记摘要、内容生成等AI功能及其他LLM能力",
|
|
||||||
"openai_tab": "OpenAI",
|
|
||||||
"anthropic_tab": "Anthropic",
|
|
||||||
"voyage_tab": "Voyage AI",
|
|
||||||
"ollama_tab": "Ollama",
|
|
||||||
"enable_ai": "启用AI/LLM功能",
|
|
||||||
"enable_ai_desc": "启用笔记摘要、内容生成等AI功能及其他LLM能力",
|
|
||||||
"provider_configuration": "AI提供商配置",
|
|
||||||
"provider_precedence": "提供商优先级",
|
|
||||||
"provider_precedence_description": "按优先级排序的提供商列表(用逗号分隔,例如:'openai,anthropic,ollama')",
|
|
||||||
"temperature": "温度参数",
|
|
||||||
"temperature_description": "控制响应的随机性(0 = 确定性输出,2 = 最大随机性)",
|
|
||||||
"system_prompt": "系统提示词",
|
|
||||||
"system_prompt_description": "所有AI交互使用的默认系统提示词",
|
|
||||||
"openai_configuration": "OpenAI配置",
|
|
||||||
"openai_settings": "OpenAI设置",
|
|
||||||
"api_key": "API密钥",
|
|
||||||
"url": "基础URL",
|
|
||||||
"model": "模型",
|
|
||||||
"openai_api_key_description": "用于访问OpenAI服务的API密钥",
|
|
||||||
"anthropic_api_key_description": "用于访问Claude模型的Anthropic API密钥",
|
|
||||||
"default_model": "默认模型",
|
|
||||||
"openai_model_description": "示例:gpt-4o、gpt-4-turbo、gpt-3.5-turbo",
|
|
||||||
"base_url": "基础URL",
|
|
||||||
"openai_url_description": "默认:https://api.openai.com/v1",
|
|
||||||
"anthropic_settings": "Anthropic设置",
|
|
||||||
"anthropic_url_description": "Anthropic API的基础URL(默认:https://api.anthropic.com)",
|
|
||||||
"anthropic_model_description": "用于聊天补全的Anthropic Claude模型",
|
|
||||||
"voyage_settings": "Voyage AI设置",
|
|
||||||
"ollama_settings": "Ollama设置",
|
|
||||||
"ollama_url_description": "Ollama API的URL(默认:http://localhost:11434)",
|
|
||||||
"ollama_model_description": "用于聊天补全的 Ollama 模型",
|
|
||||||
"anthropic_configuration": "Anthropic配置",
|
|
||||||
"voyage_configuration": "Voyage AI配置",
|
|
||||||
"voyage_url_description": "默认:https://api.voyageai.com/v1",
|
|
||||||
"ollama_configuration": "Ollama配置",
|
|
||||||
"enable_ollama": "启用Ollama",
|
|
||||||
"enable_ollama_description": "启用Ollama以使用本地AI模型",
|
|
||||||
"ollama_url": "Ollama URL",
|
|
||||||
"ollama_model": "Ollama模型",
|
|
||||||
"refresh_models": "刷新模型",
|
|
||||||
"refreshing_models": "刷新中...",
|
|
||||||
"enable_automatic_indexing": "启用自动索引",
|
|
||||||
"rebuild_index": "重建索引",
|
|
||||||
"rebuild_index_error": "启动索引重建失败。请查看日志了解详情。",
|
|
||||||
"note_title": "笔记标题",
|
|
||||||
"error": "错误",
|
|
||||||
"last_attempt": "最后尝试时间",
|
|
||||||
"actions": "操作",
|
|
||||||
"retry": "重试",
|
|
||||||
"partial": "{{ percentage }}% 已完成",
|
|
||||||
"retry_queued": "笔记已加入重试队列",
|
|
||||||
"retry_failed": "笔记加入重试队列失败",
|
|
||||||
"max_notes_per_llm_query": "每次查询的最大笔记数",
|
|
||||||
"max_notes_per_llm_query_description": "AI上下文包含的最大相似笔记数量",
|
|
||||||
"active_providers": "活跃提供商",
|
|
||||||
"disabled_providers": "已禁用提供商",
|
|
||||||
"remove_provider": "从搜索中移除提供商",
|
|
||||||
"restore_provider": "将提供商恢复到搜索中",
|
|
||||||
"similarity_threshold": "相似度阈值",
|
|
||||||
"similarity_threshold_description": "纳入LLM查询上下文的笔记最低相似度分数(0-1)",
|
|
||||||
"reprocess_index": "重建搜索索引",
|
|
||||||
"reprocessing_index": "重建中...",
|
|
||||||
"reprocess_index_started": "搜索索引优化已在后台启动",
|
|
||||||
"reprocess_index_error": "重建搜索索引失败",
|
|
||||||
"index_rebuild_progress": "索引重建进度",
|
|
||||||
"index_rebuilding": "正在优化索引({{percentage}}%)",
|
|
||||||
"index_rebuild_complete": "索引优化完成",
|
|
||||||
"index_rebuild_status_error": "检查索引重建状态失败",
|
|
||||||
"never": "从未",
|
|
||||||
"processing": "处理中({{percentage}}%)",
|
|
||||||
"incomplete": "未完成({{percentage}}%)",
|
|
||||||
"complete": "已完成(100%)",
|
|
||||||
"refreshing": "刷新中...",
|
|
||||||
"auto_refresh_notice": "每 {{seconds}} 秒自动刷新",
|
|
||||||
"note_queued_for_retry": "笔记已加入重试队列",
|
|
||||||
"failed_to_retry_note": "重试笔记失败",
|
|
||||||
"all_notes_queued_for_retry": "所有失败笔记已加入重试队列",
|
|
||||||
"failed_to_retry_all": "重试笔记失败",
|
|
||||||
"ai_settings": "AI设置",
|
|
||||||
"api_key_tooltip": "用于访问服务的API密钥",
|
|
||||||
"empty_key_warning": {
|
|
||||||
"anthropic": "Anthropic API密钥为空。请输入有效的API密钥。",
|
|
||||||
"openai": "OpenAI API密钥为空。请输入有效的API密钥。",
|
|
||||||
"voyage": "Voyage API密钥为空。请输入有效的API密钥。",
|
|
||||||
"ollama": "Ollama API密钥为空。请输入有效的API密钥。"
|
|
||||||
},
|
|
||||||
"agent": {
|
|
||||||
"processing": "处理中...",
|
|
||||||
"thinking": "思考中...",
|
|
||||||
"loading": "加载中...",
|
|
||||||
"generating": "生成中..."
|
|
||||||
},
|
|
||||||
"name": "AI",
|
|
||||||
"openai": "OpenAI",
|
|
||||||
"use_enhanced_context": "使用增强上下文",
|
|
||||||
"enhanced_context_description": "为AI提供来自笔记及其相关笔记的更多上下文,以获得更好的响应",
|
|
||||||
"show_thinking": "显示思考过程",
|
|
||||||
"show_thinking_description": "显示AI的思维链过程",
|
|
||||||
"enter_message": "输入你的消息...",
|
|
||||||
"error_contacting_provider": "联系AI提供商失败。请检查你的设置和网络连接。",
|
|
||||||
"error_generating_response": "生成AI响应失败",
|
|
||||||
"index_all_notes": "为所有笔记建立索引",
|
|
||||||
"index_status": "索引状态",
|
|
||||||
"indexed_notes": "已索引笔记",
|
|
||||||
"indexing_stopped": "索引已停止",
|
|
||||||
"indexing_in_progress": "索引进行中...",
|
|
||||||
"last_indexed": "最后索引时间",
|
|
||||||
"note_chat": "笔记聊天",
|
|
||||||
"sources": "来源",
|
|
||||||
"start_indexing": "开始索引",
|
|
||||||
"use_advanced_context": "使用高级上下文",
|
|
||||||
"ollama_no_url": "Ollama 未配置。请输入有效的URL。",
|
|
||||||
"chat": {
|
|
||||||
"root_note_title": "AI聊天记录",
|
|
||||||
"root_note_content": "此笔记包含你保存的AI聊天对话。",
|
|
||||||
"new_chat_title": "新聊天",
|
|
||||||
"create_new_ai_chat": "创建新的AI聊天"
|
|
||||||
},
|
|
||||||
"create_new_ai_chat": "创建新的AI聊天",
|
|
||||||
"configuration_warnings": "你的AI配置存在一些问题。请检查你的设置。",
|
|
||||||
"experimental_warning": "LLM功能目前处于实验阶段 - 特此提醒。",
|
|
||||||
"selected_provider": "已选提供商",
|
|
||||||
"selected_provider_description": "选择用于聊天和补全功能的AI提供商",
|
|
||||||
"select_model": "选择模型...",
|
|
||||||
"select_provider": "选择提供商...",
|
|
||||||
"ai_enabled": "已启用 AI 功能",
|
|
||||||
"ai_disabled": "已禁用 AI 功能",
|
|
||||||
"no_models_found_online": "找不到模型。请检查您的 API 密钥及设置。",
|
|
||||||
"no_models_found_ollama": "找不到 Ollama 模型。请确认 Ollama 是否正在运行。",
|
|
||||||
"error_fetching": "获取模型失败:{{error}}"
|
|
||||||
},
|
|
||||||
"code-editor-options": {
|
"code-editor-options": {
|
||||||
"title": "编辑器"
|
"title": "编辑器"
|
||||||
},
|
},
|
||||||
@@ -2066,7 +1929,8 @@
|
|||||||
"raster": "栅格",
|
"raster": "栅格",
|
||||||
"vector_light": "矢量(浅色)",
|
"vector_light": "矢量(浅色)",
|
||||||
"vector_dark": "矢量(深色)",
|
"vector_dark": "矢量(深色)",
|
||||||
"show-scale": "显示比例尺"
|
"show-scale": "显示比例尺",
|
||||||
|
"show-labels": "显示标记名称"
|
||||||
},
|
},
|
||||||
"table_context_menu": {
|
"table_context_menu": {
|
||||||
"delete_row": "删除行"
|
"delete_row": "删除行"
|
||||||
@@ -2113,7 +1977,7 @@
|
|||||||
},
|
},
|
||||||
"call_to_action": {
|
"call_to_action": {
|
||||||
"background_effects_title": "背景效果现已推出稳定版本",
|
"background_effects_title": "背景效果现已推出稳定版本",
|
||||||
"background_effects_message": "在 Windows 装置上,背景效果现在已完全稳定。背景效果通过模糊背后的背景,为使用者界面增添一抹色彩。此技术也用于其他应用程序,例如 Windows 资源管理器。",
|
"background_effects_message": "在 Windows 和 macOS 设备上,背景效果现在已稳定。背景效果通过模糊背后的背景,为使用者界面增添一抹色彩。",
|
||||||
"background_effects_button": "启用背景效果",
|
"background_effects_button": "启用背景效果",
|
||||||
"next_theme_title": "试用新 Trilium 主题",
|
"next_theme_title": "试用新 Trilium 主题",
|
||||||
"next_theme_message": "当前使用旧版主题,要试用新主题吗?",
|
"next_theme_message": "当前使用旧版主题,要试用新主题吗?",
|
||||||
@@ -2145,8 +2009,9 @@
|
|||||||
"app-restart-required": "(需重启程序以应用更改)"
|
"app-restart-required": "(需重启程序以应用更改)"
|
||||||
},
|
},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"page_title": "第 {{startIndex}} 页 - 第 {{endIndex}} 页",
|
"total_notes": "{{count}} 篇笔记",
|
||||||
"total_notes": "{{count}} 篇笔记"
|
"prev_page": "上一页",
|
||||||
|
"next_page": "下一页"
|
||||||
},
|
},
|
||||||
"collections": {
|
"collections": {
|
||||||
"rendering_error": "出现错误无法显示内容。"
|
"rendering_error": "出现错误无法显示内容。"
|
||||||
@@ -2249,5 +2114,106 @@
|
|||||||
"pages_alt": "第{{pageNumber}}页",
|
"pages_alt": "第{{pageNumber}}页",
|
||||||
"pages_loading": "加载中...",
|
"pages_loading": "加载中...",
|
||||||
"layers_other": "{{count}} 层"
|
"layers_other": "{{count}} 层"
|
||||||
|
},
|
||||||
|
"platform_indicator": {
|
||||||
|
"available_on": "在 {{platform}} 上可用"
|
||||||
|
},
|
||||||
|
"mobile_tab_switcher": {
|
||||||
|
"title_other": "{{count}} 选项卡",
|
||||||
|
"more_options": "更多选项"
|
||||||
|
},
|
||||||
|
"bookmark_buttons": {
|
||||||
|
"bookmarks": "书签"
|
||||||
|
},
|
||||||
|
"web_view_setup": {
|
||||||
|
"title": "直接在 Trilium 中创建网页的实时视图",
|
||||||
|
"url_placeholder": "输入或粘贴网站地址,例如 https://triliumnotes.org",
|
||||||
|
"create_button": "创建网页视图",
|
||||||
|
"invalid_url_title": "无效的地址",
|
||||||
|
"invalid_url_message": "请输入有效的网址,例如 https://triliumnotes.org。",
|
||||||
|
"disabled_description": "此网页视图来自外部来源。为保护您免受网络钓鱼或恶意内容侵害,该视图不会自动加载。若您信任该来源,可手动启用加载功能。",
|
||||||
|
"disabled_button_enable": "启用网页视图"
|
||||||
|
},
|
||||||
|
"render": {
|
||||||
|
"setup_title": "在此笔记中显示自定义 HTML 或 Preact JSX",
|
||||||
|
"setup_create_sample_preact": "使用 Preact 建立范例笔记",
|
||||||
|
"setup_create_sample_html": "使用 HTML 建立范例笔记",
|
||||||
|
"setup_sample_created": "已建立一个范例笔记作为子笔记。",
|
||||||
|
"disabled_description": "此渲染笔记来自外部来源。为保护您免受恶意内容侵害,该功能默认处于禁用状态。启用前请确保您信任该来源。",
|
||||||
|
"disabled_button_enable": "启用渲染笔记"
|
||||||
|
},
|
||||||
|
"active_content_badges": {
|
||||||
|
"type_icon_pack": "图标包",
|
||||||
|
"type_backend_script": "后端脚本",
|
||||||
|
"type_frontend_script": "前端脚本",
|
||||||
|
"type_widget": "小部件",
|
||||||
|
"type_app_css": "自定义 CSS",
|
||||||
|
"type_render_note": "渲染笔记",
|
||||||
|
"type_web_view": "网页视图",
|
||||||
|
"type_app_theme": "自定义主题",
|
||||||
|
"toggle_tooltip_enable_tooltip": "点击以启用此 {{type}}。",
|
||||||
|
"toggle_tooltip_disable_tooltip": "点击以禁用此 {{type}}。",
|
||||||
|
"menu_docs": "打开文档",
|
||||||
|
"menu_execute_now": "立即执行脚本",
|
||||||
|
"menu_run": "自动执行",
|
||||||
|
"menu_run_disabled": "手动",
|
||||||
|
"menu_run_backend_startup": "当后端启动时",
|
||||||
|
"menu_run_hourly": "每小时",
|
||||||
|
"menu_run_daily": "每日",
|
||||||
|
"menu_run_frontend_startup": "当桌面前端启动时",
|
||||||
|
"menu_run_mobile_startup": "当移动前端启动时",
|
||||||
|
"menu_change_to_widget": "更改为小部件",
|
||||||
|
"menu_change_to_frontend_script": "更改为前端脚本",
|
||||||
|
"menu_theme_base": "主题基底"
|
||||||
|
},
|
||||||
|
"setup_form": {
|
||||||
|
"more_info": "了解更多"
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"play": "播放(空格)",
|
||||||
|
"pause": "暂停(空格)",
|
||||||
|
"back-10s": "后退10秒(左箭头键)",
|
||||||
|
"forward-30s": "前进30秒",
|
||||||
|
"mute": "静音(M)",
|
||||||
|
"unmute": "取消静音(M)",
|
||||||
|
"playback-speed": "播放速度",
|
||||||
|
"loop": "循环播放",
|
||||||
|
"disable-loop": "禁用循环播放",
|
||||||
|
"rotate": "旋转",
|
||||||
|
"picture-in-picture": "画中画",
|
||||||
|
"exit-picture-in-picture": "退出画中画",
|
||||||
|
"fullscreen": "全屏(F)",
|
||||||
|
"exit-fullscreen": "退出全屏",
|
||||||
|
"unsupported-format": "此文件格式不支持媒体预览:\n{{mime}}",
|
||||||
|
"zoom-to-fit": "缩放以填充",
|
||||||
|
"zoom-reset": "重置缩放以填充"
|
||||||
|
},
|
||||||
|
"mermaid": {
|
||||||
|
"sample_diagrams": "示例图:",
|
||||||
|
"sample_flowchart": "流程图",
|
||||||
|
"sample_class": "类图",
|
||||||
|
"sample_sequence": "时序图",
|
||||||
|
"sample_entity_relationship": "实体关系图",
|
||||||
|
"sample_state": "状态图",
|
||||||
|
"sample_mindmap": "思维导图",
|
||||||
|
"sample_architecture": "架构图",
|
||||||
|
"sample_block": "模块图",
|
||||||
|
"sample_c4": "C4 图",
|
||||||
|
"sample_gantt": "甘特图",
|
||||||
|
"sample_git": "Git 流程图",
|
||||||
|
"sample_kanban": "看板图",
|
||||||
|
"sample_packet": "数据包图",
|
||||||
|
"sample_pie": "饼图",
|
||||||
|
"sample_quadrant": "象限图",
|
||||||
|
"sample_radar": "雷达图",
|
||||||
|
"sample_requirement": "需求图",
|
||||||
|
"sample_sankey": "桑基图",
|
||||||
|
"sample_timeline": "时间轴图",
|
||||||
|
"sample_treemap": "树形图",
|
||||||
|
"sample_user_journey": "用户旅程图",
|
||||||
|
"sample_xy": "散点图",
|
||||||
|
"sample_venn": "韦恩图",
|
||||||
|
"sample_ishikawa": "鱼骨图",
|
||||||
|
"placeholder": "输入你的美人鱼图的内容,或者使用下面的示例图之一。"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"about": {
|
"about": {
|
||||||
"title": "Über Trilium Notizen",
|
"title": "Über Trilium Notes",
|
||||||
"homepage": "Startseite:",
|
"homepage": "Startseite:",
|
||||||
"app_version": "App-Version:",
|
"app_version": "App-Version:",
|
||||||
"db_version": "DB-Version:",
|
"db_version": "DB-Version:",
|
||||||
@@ -28,9 +28,9 @@
|
|||||||
},
|
},
|
||||||
"open-script-note": "Script-Notiz öffnen",
|
"open-script-note": "Script-Notiz öffnen",
|
||||||
"widget-render-error": {
|
"widget-render-error": {
|
||||||
"title": "Eine externe React Integration konnte nicht dargestellt werden"
|
"title": "Benutzerdefiniertes React-Widget konnte nicht dargestellt werden"
|
||||||
},
|
},
|
||||||
"widget-missing-parent": "Der externen Integration fehlt die erforderliche Eigenschaft '{{property}}'\n\nFalls dieses Skript ohne UI-Element ausgeführt werden soll, benutze stattdessen '#run=frontendStartup'.",
|
"widget-missing-parent": "Benutzerdefiniertes Widget hat die erforderliche '{{property}}'-Eigenschaft nicht korrekt definiert.\n\nFalls dieses Skript ohne UI-Element ausgeführt werden soll, benutze stattdessen '#run=frontendStartup'.",
|
||||||
"scripting-error": "Benutzerdefinierter Skriptfehler: {{title}}"
|
"scripting-error": "Benutzerdefinierter Skriptfehler: {{title}}"
|
||||||
},
|
},
|
||||||
"add_link": {
|
"add_link": {
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
"scrollToActiveNote": "Scrolle zur aktiven Notiz",
|
"scrollToActiveNote": "Scrolle zur aktiven Notiz",
|
||||||
"jumpToParentNote": "Zur übergeordneten Notiz springen",
|
"jumpToParentNote": "Zur übergeordneten Notiz springen",
|
||||||
"collapseWholeTree": "Reduziere den gesamten Notizbaum",
|
"collapseWholeTree": "Reduziere den gesamten Notizbaum",
|
||||||
"collapseSubTree": "Teilbaum einklappen",
|
"collapseSubTree": "Zweig einklappen",
|
||||||
"tabShortcuts": "Tab-Tastenkürzel",
|
"tabShortcuts": "Tab-Tastenkürzel",
|
||||||
"newTabNoteLink": "auf den Notizlink öffnet die Notiz in einem neuen Tab",
|
"newTabNoteLink": "auf den Notizlink öffnet die Notiz in einem neuen Tab",
|
||||||
"onlyInDesktop": "Nur im Desktop (Electron Build)",
|
"onlyInDesktop": "Nur im Desktop (Electron Build)",
|
||||||
@@ -230,7 +230,7 @@
|
|||||||
"move_to": {
|
"move_to": {
|
||||||
"dialog_title": "Notizen verschieben nach ...",
|
"dialog_title": "Notizen verschieben nach ...",
|
||||||
"notes_to_move": "Notizen zum Verschieben",
|
"notes_to_move": "Notizen zum Verschieben",
|
||||||
"target_parent_note": "Ziel-Elternnotiz",
|
"target_parent_note": "Übergeordnete Notiz bestimmen",
|
||||||
"search_placeholder": "Suche nach einer Notiz anhand ihres Namens",
|
"search_placeholder": "Suche nach einer Notiz anhand ihres Namens",
|
||||||
"move_button": "Zur ausgewählten Notiz wechseln",
|
"move_button": "Zur ausgewählten Notiz wechseln",
|
||||||
"error_no_path": "Kein Weg, auf den man sich bewegen kann.",
|
"error_no_path": "Kein Weg, auf den man sich bewegen kann.",
|
||||||
@@ -333,8 +333,8 @@
|
|||||||
"target_note_title": "Eine Beziehung ist eine benannte Verbindung zwischen Quellnotiz und Zielnotiz.",
|
"target_note_title": "Eine Beziehung ist eine benannte Verbindung zwischen Quellnotiz und Zielnotiz.",
|
||||||
"target_note": "Zielnotiz",
|
"target_note": "Zielnotiz",
|
||||||
"promoted_title": "Das heraufgestufte Attribut wird deutlich in der Notiz angezeigt.",
|
"promoted_title": "Das heraufgestufte Attribut wird deutlich in der Notiz angezeigt.",
|
||||||
"promoted": "Gefördert",
|
"promoted": "Hervorgehoben",
|
||||||
"promoted_alias_title": "Der Name, der in der Benutzeroberfläche für heraufgestufte Attribute angezeigt werden soll.",
|
"promoted_alias_title": "Der Name, der in der Benutzeroberfläche für hervorgehobene Attribute angezeigt werden soll.",
|
||||||
"promoted_alias": "Alias",
|
"promoted_alias": "Alias",
|
||||||
"multiplicity_title": "Multiplizität definiert, wie viele Attribute mit demselben Namen erstellt werden können – maximal 1 oder mehr als 1.",
|
"multiplicity_title": "Multiplizität definiert, wie viele Attribute mit demselben Namen erstellt werden können – maximal 1 oder mehr als 1.",
|
||||||
"multiplicity": "Vielzahl",
|
"multiplicity": "Vielzahl",
|
||||||
@@ -367,7 +367,7 @@
|
|||||||
"disable_versioning": "deaktiviert die automatische Versionierung. Nützlich z.B. große, aber unwichtige Notizen – z.B. große JS-Bibliotheken, die für die Skripterstellung verwendet werden",
|
"disable_versioning": "deaktiviert die automatische Versionierung. Nützlich z.B. große, aber unwichtige Notizen – z.B. große JS-Bibliotheken, die für die Skripterstellung verwendet werden",
|
||||||
"calendar_root": "Markiert eine Notiz, die als Basis für Tagesnotizen verwendet werden soll. Nur einer sollte als solcher gekennzeichnet sein.",
|
"calendar_root": "Markiert eine Notiz, die als Basis für Tagesnotizen verwendet werden soll. Nur einer sollte als solcher gekennzeichnet sein.",
|
||||||
"archived": "Notizen mit dieser Bezeichnung werden standardmäßig nicht in den Suchergebnissen angezeigt (auch nicht in den Dialogen „Springen zu“, „Link hinzufügen“ usw.).",
|
"archived": "Notizen mit dieser Bezeichnung werden standardmäßig nicht in den Suchergebnissen angezeigt (auch nicht in den Dialogen „Springen zu“, „Link hinzufügen“ usw.).",
|
||||||
"exclude_from_export": "Notizen (mit ihrem Unterbaum) werden nicht in den Notizexport einbezogen",
|
"exclude_from_export": "Notizen (mit ihrem Unterbaum) werden nicht im Notizexport inkludiert",
|
||||||
"run": "Definiert, bei welchen Ereignissen das Skript ausgeführt werden soll. Mögliche Werte sind:\n<ul>\n<li>frontendStartup - wenn das Trilium-Frontend startet (oder aktualisiert wird), außer auf mobilen Geräten.</li>\n<li>mobileStartup - wenn das Trilium-Frontend auf einem mobilen Gerät startet (oder aktualisiert wird).</li>\n<li>backendStartup - wenn das Trilium-Backend startet</li>\n<li>hourly - einmal pro Stunde ausführen. Du kannst das zusätzliche Label <code>runAtHour</code> verwenden, um die genaue Stunde festzulegen.</li>\n<li>daily - einmal pro Tag ausführen</li>\n</ul>",
|
"run": "Definiert, bei welchen Ereignissen das Skript ausgeführt werden soll. Mögliche Werte sind:\n<ul>\n<li>frontendStartup - wenn das Trilium-Frontend startet (oder aktualisiert wird), außer auf mobilen Geräten.</li>\n<li>mobileStartup - wenn das Trilium-Frontend auf einem mobilen Gerät startet (oder aktualisiert wird).</li>\n<li>backendStartup - wenn das Trilium-Backend startet</li>\n<li>hourly - einmal pro Stunde ausführen. Du kannst das zusätzliche Label <code>runAtHour</code> verwenden, um die genaue Stunde festzulegen.</li>\n<li>daily - einmal pro Tag ausführen</li>\n</ul>",
|
||||||
"run_on_instance": "Definiere, auf welcher Trilium-Instanz dies ausgeführt werden soll. Standardmäßig alle Instanzen.",
|
"run_on_instance": "Definiere, auf welcher Trilium-Instanz dies ausgeführt werden soll. Standardmäßig alle Instanzen.",
|
||||||
"run_at_hour": "Zu welcher Stunde soll das laufen? Sollte zusammen mit <code>#runu003dhourly</code> verwendet werden. Kann für mehr Läufe im Laufe des Tages mehrfach definiert werden.",
|
"run_at_hour": "Zu welcher Stunde soll das laufen? Sollte zusammen mit <code>#runu003dhourly</code> verwendet werden. Kann für mehr Läufe im Laufe des Tages mehrfach definiert werden.",
|
||||||
@@ -376,7 +376,7 @@
|
|||||||
"sort_direction": "ASC (Standard) oder DESC",
|
"sort_direction": "ASC (Standard) oder DESC",
|
||||||
"sort_folders_first": "Ordner (Notizen mit Unternotizen) sollten oben sortiert werden",
|
"sort_folders_first": "Ordner (Notizen mit Unternotizen) sollten oben sortiert werden",
|
||||||
"top": "Behalte die angegebene Notiz oben in der übergeordneten Notiz (gilt nur für sortierte übergeordnete Notizen)",
|
"top": "Behalte die angegebene Notiz oben in der übergeordneten Notiz (gilt nur für sortierte übergeordnete Notizen)",
|
||||||
"hide_promoted_attributes": "Heraufgestufte Attribute für diese Notiz ausblenden",
|
"hide_promoted_attributes": "Hervorgehobene Attribute für diese Notiz ausblenden",
|
||||||
"read_only": "Der Editor befindet sich im schreibgeschützten Modus. Funktioniert nur für Text- und Codenotizen.",
|
"read_only": "Der Editor befindet sich im schreibgeschützten Modus. Funktioniert nur für Text- und Codenotizen.",
|
||||||
"auto_read_only_disabled": "Text-/Codenotizen können automatisch in den Lesemodus versetzt werden, wenn sie zu groß sind. Du kannst dieses Verhalten für jede einzelne Notiz deaktivieren, indem du diese Beschriftung zur Notiz hinzufügst",
|
"auto_read_only_disabled": "Text-/Codenotizen können automatisch in den Lesemodus versetzt werden, wenn sie zu groß sind. Du kannst dieses Verhalten für jede einzelne Notiz deaktivieren, indem du diese Beschriftung zur Notiz hinzufügst",
|
||||||
"app_css": "markiert CSS-Notizen, die in die Trilium-Anwendung geladen werden und somit zur Änderung des Aussehens von Trilium verwendet werden können.",
|
"app_css": "markiert CSS-Notizen, die in die Trilium-Anwendung geladen werden und somit zur Änderung des Aussehens von Trilium verwendet werden können.",
|
||||||
@@ -416,25 +416,25 @@
|
|||||||
"toc": "<code>#toc</code> oder <code>#tocu003dshow</code> erzwingen die Anzeige des Inhaltsverzeichnisses, <code>#tocu003dhide</code> erzwingt das Ausblenden. Wenn die Bezeichnung nicht vorhanden ist, wird die globale Einstellung beachtet",
|
"toc": "<code>#toc</code> oder <code>#tocu003dshow</code> erzwingen die Anzeige des Inhaltsverzeichnisses, <code>#tocu003dhide</code> erzwingt das Ausblenden. Wenn die Bezeichnung nicht vorhanden ist, wird die globale Einstellung beachtet",
|
||||||
"color": "Definiert die Farbe der Notiz im Notizbaum, in Links usw. Verwende einen beliebigen gültigen CSS-Farbwert wie „rot“ oder #a13d5f",
|
"color": "Definiert die Farbe der Notiz im Notizbaum, in Links usw. Verwende einen beliebigen gültigen CSS-Farbwert wie „rot“ oder #a13d5f",
|
||||||
"keyboard_shortcut": "Definiert eine Tastenkombination, die sofort zu dieser Notiz springt. Beispiel: „Strg+Alt+E“. Erfordert ein Neuladen des Frontends, damit die Änderung wirksam wird.",
|
"keyboard_shortcut": "Definiert eine Tastenkombination, die sofort zu dieser Notiz springt. Beispiel: „Strg+Alt+E“. Erfordert ein Neuladen des Frontends, damit die Änderung wirksam wird.",
|
||||||
"keep_current_hoisting": "Das Öffnen dieses Links ändert das Hochziehen nicht, selbst wenn die Notiz im aktuell hochgezogenen Unterbaum nicht angezeigt werden kann.",
|
"keep_current_hoisting": "Das Öffnen dieses Links ändert das Hochziehen nicht, selbst wenn die Notiz im aktuell hochgezogenen Zweig nicht angezeigt werden kann.",
|
||||||
"execute_button": "Titel der Schaltfläche, welche die aktuelle Codenotiz ausführt",
|
"execute_button": "Titel der Schaltfläche, welche die aktuelle Codenotiz ausführt",
|
||||||
"execute_description": "Längere Beschreibung der aktuellen Codenotiz, die zusammen mit der Schaltfläche „Ausführen“ angezeigt wird",
|
"execute_description": "Längere Beschreibung der aktuellen Codenotiz, die zusammen mit der Schaltfläche „Ausführen“ angezeigt wird",
|
||||||
"exclude_from_note_map": "Notizen mit dieser Bezeichnung werden in der Notizenkarte ausgeblendet",
|
"exclude_from_note_map": "Notizen mit dieser Bezeichnung werden in der Notizenkarte ausgeblendet",
|
||||||
"new_notes_on_top": "Neue Notizen werden oben in der übergeordneten Notiz erstellt, nicht unten.",
|
"new_notes_on_top": "Neue Notizen werden oben in der übergeordneten Notiz erstellt, nicht unten.",
|
||||||
"hide_highlight_widget": "Widget „Hervorhebungsliste“ ausblenden",
|
"hide_highlight_widget": "Widget „Markierungsliste“ ausblenden",
|
||||||
"run_on_note_creation": "Wird ausgeführt, wenn eine Notiz im Backend erstellt wird. Verwende diese Beziehung, wenn du das Skript für alle Notizen ausführen möchtest, die unter einer bestimmten Unternotiz erstellt wurden. Erstelle es in diesem Fall auf der Unternotiz-Stammnotiz und mache es vererbbar. Eine neue Notiz, die innerhalb der Unternotiz (beliebige Tiefe) erstellt wird, löst das Skript aus.",
|
"run_on_note_creation": "Wird ausgeführt, wenn eine Notiz im Backend erstellt wird. Verwende diese Beziehung, wenn du das Skript für alle Notizen ausführen möchtest, die unter einem bestimmten Zweig erstellt wurden. Erstelle es in diesem Fall auf der Stammnotiz und mache es vererbbar. Eine neue Notiz, die innerhalb des Zweigs (beliebige Tiefe) erstellt wird, löst das Skript aus.",
|
||||||
"run_on_child_note_creation": "Wird ausgeführt, wenn eine neue Notiz unter der Notiz erstellt wird, in der diese Beziehung definiert ist",
|
"run_on_child_note_creation": "Wird ausgeführt, wenn eine neue Notiz unter der Notiz erstellt wird, in der diese Beziehung definiert ist",
|
||||||
"run_on_note_title_change": "Wird ausgeführt, wenn der Notiztitel geändert wird (einschließlich der Notizerstellung)",
|
"run_on_note_title_change": "Wird ausgeführt, wenn der Notiztitel geändert wird (einschließlich der Notizerstellung)",
|
||||||
"run_on_note_content_change": "Wird ausgeführt, wenn der Inhalt einer Notiz geändert wird (einschließlich der Erstellung von Notizen).",
|
"run_on_note_content_change": "Wird ausgeführt, wenn der Inhalt einer Notiz geändert wird (einschließlich der Erstellung von Notizen).",
|
||||||
"run_on_note_change": "Wird ausgeführt, wenn eine Notiz geändert wird (einschließlich der Erstellung von Notizen). Enthält keine Inhaltsänderungen",
|
"run_on_note_change": "Wird ausgeführt, wenn eine Notiz geändert wird (einschließlich der Erstellung von Notizen). Enthält keine Inhaltsänderungen",
|
||||||
"run_on_note_deletion": "Wird ausgeführt, wenn eine Notiz gelöscht wird",
|
"run_on_note_deletion": "Wird ausgeführt, wenn eine Notiz gelöscht wird",
|
||||||
"run_on_branch_creation": "wird ausgeführt, wenn ein Zweig erstellt wird. Der Zweig ist eine Verbindung zwischen der übergeordneten Notiz und der untergeordneten Notiz und wird z. B. erstellt. beim Klonen oder Verschieben von Notizen.",
|
"run_on_branch_creation": "wird ausgeführt, wenn ein Zweig erstellt wird. Der Zweig ist eine Verbindung zwischen der übergeordneten und der untergeordneten Notiz und wird z. B. beim Klonen oder Verschieben von Notizen erstellt.",
|
||||||
"run_on_branch_change": "wird ausgeführt, wenn ein Zweig aktualisiert wird.",
|
"run_on_branch_change": "wird ausgeführt, wenn ein Zweig aktualisiert wird.",
|
||||||
"run_on_branch_deletion": "wird ausgeführt, wenn ein Zweig gelöscht wird. Der Zweig ist eine Verknüpfung zwischen der übergeordneten Notiz und der untergeordneten Notiz und wird z. B. gelöscht. beim Verschieben der Notiz (alter Zweig/Link wird gelöscht).",
|
"run_on_branch_deletion": "wird ausgeführt, wenn ein Zweig gelöscht wird. Der Zweig ist eine Verknüpfung zwischen der übergeordneten und der untergeordneten Notiz und wird z. B. beim Verschieben der Notiz gelöscht (alter Zweig/Link wird gelöscht).",
|
||||||
"run_on_attribute_creation": "wird ausgeführt, wenn für die Notiz ein neues Attribut erstellt wird, das diese Beziehung definiert",
|
"run_on_attribute_creation": "wird ausgeführt, wenn für die Notiz ein neues Attribut erstellt wird, das diese Beziehung definiert",
|
||||||
"run_on_attribute_change": " wird ausgeführt, wenn das Attribut einer Notiz geändert wird, die diese Beziehung definiert. Dies wird auch ausgelöst, wenn das Attribut gelöscht wird",
|
"run_on_attribute_change": " wird ausgeführt, wenn das Attribut einer Notiz geändert wird, die diese Beziehung definiert. Dies wird auch ausgelöst, wenn das Attribut gelöscht wird",
|
||||||
"relation_template": "Die Attribute der Notiz werden auch ohne eine Eltern-Kind-Beziehung vererbt. Der Inhalt und der Unterbaum der Notiz werden den Instanznotizen hinzugefügt, wenn sie leer sind. Einzelheiten findest du in der Dokumentation.",
|
"relation_template": "Die Attribute der Notiz werden auch ohne eine Hierarchische-Beziehung vererbt. Der Inhalt und der Zweig werden den Instanznotizen hinzugefügt, wenn sie leer sind. Einzelheiten findest du in der Dokumentation.",
|
||||||
"inherit": "Die Attribute einer Notiz werden auch ohne eine Eltern-Kind-Beziehung vererbt. Ein ähnliches Konzept findest du unter Vorlagenbeziehung. Siehe Attributvererbung in der Dokumentation.",
|
"inherit": "Die Attribute einer Notiz werden auch ohne eine Hierarchische-Beziehung vererbt. Ein ähnliches Konzept findest du unter Vorlagenbeziehung. Siehe Attributsvererbung in der Dokumentation.",
|
||||||
"render_note": "Notizen vom Typ \"HTML-Notiz rendern\" werden mit einer Code-Notiz (HTML oder Skript) gerendert, und es ist notwendig, über diese Beziehung anzugeben, welche Notiz gerendert werden soll",
|
"render_note": "Notizen vom Typ \"HTML-Notiz rendern\" werden mit einer Code-Notiz (HTML oder Skript) gerendert, und es ist notwendig, über diese Beziehung anzugeben, welche Notiz gerendert werden soll",
|
||||||
"widget_relation": "Das Ziel dieser Beziehung wird ausgeführt und als Widget in der Seitenleiste gerendert",
|
"widget_relation": "Das Ziel dieser Beziehung wird ausgeführt und als Widget in der Seitenleiste gerendert",
|
||||||
"share_css": "CSS-Hinweis, der in die Freigabeseite eingefügt wird. Die CSS-Notiz muss sich ebenfalls im gemeinsamen Unterbaum befinden. Erwäge auch die Verwendung von „share_hidden_from_tree“ und „share_omit_default_css“.",
|
"share_css": "CSS-Hinweis, der in die Freigabeseite eingefügt wird. Die CSS-Notiz muss sich ebenfalls im gemeinsamen Unterbaum befinden. Erwäge auch die Verwendung von „share_hidden_from_tree“ und „share_omit_default_css“.",
|
||||||
@@ -446,7 +446,8 @@
|
|||||||
"and_more": "... und {{count}} mehr.",
|
"and_more": "... und {{count}} mehr.",
|
||||||
"print_landscape": "Beim Export als PDF, wird die Seitenausrichtung Querformat anstatt Hochformat verwendet.",
|
"print_landscape": "Beim Export als PDF, wird die Seitenausrichtung Querformat anstatt Hochformat verwendet.",
|
||||||
"print_page_size": "Beim Export als PDF, wird die Größe der Seite angepasst. Unterstützte Größen: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.",
|
"print_page_size": "Beim Export als PDF, wird die Größe der Seite angepasst. Unterstützte Größen: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.",
|
||||||
"color_type": "Farbe"
|
"color_type": "Farbe",
|
||||||
|
"textarea": "Mehrzeilen-Text"
|
||||||
},
|
},
|
||||||
"attribute_editor": {
|
"attribute_editor": {
|
||||||
"help_text_body1": "Um ein Label hinzuzufügen, gebe einfach z.B. ein. <code>#rock</code> oder wenn du auch einen Wert hinzufügen möchten, dann z.B. <code>#year = 2024</code>",
|
"help_text_body1": "Um ein Label hinzuzufügen, gebe einfach z.B. ein. <code>#rock</code> oder wenn du auch einen Wert hinzufügen möchten, dann z.B. <code>#year = 2024</code>",
|
||||||
@@ -632,7 +633,7 @@
|
|||||||
"show_toc": "Inhaltsverzeichnis anzeigen"
|
"show_toc": "Inhaltsverzeichnis anzeigen"
|
||||||
},
|
},
|
||||||
"show_highlights_list_widget_button": {
|
"show_highlights_list_widget_button": {
|
||||||
"show_highlights_list": "Hervorhebungen anzeigen"
|
"show_highlights_list": "Markierungsliste anzeigen"
|
||||||
},
|
},
|
||||||
"global_menu": {
|
"global_menu": {
|
||||||
"menu": "Menü",
|
"menu": "Menü",
|
||||||
@@ -645,8 +646,8 @@
|
|||||||
"zoom_out": "Herauszoomen",
|
"zoom_out": "Herauszoomen",
|
||||||
"reset_zoom_level": "Zoomstufe zurücksetzen",
|
"reset_zoom_level": "Zoomstufe zurücksetzen",
|
||||||
"zoom_in": "Hineinzoomen",
|
"zoom_in": "Hineinzoomen",
|
||||||
"configure_launchbar": "Konfiguriere die Launchbar",
|
"configure_launchbar": "Konfiguriere die Starterleiste",
|
||||||
"show_shared_notes_subtree": "Unterbaum „Freigegebene Notizen“ anzeigen",
|
"show_shared_notes_subtree": "Zweig „Freigegebene Notizen“ anzeigen",
|
||||||
"advanced": "Erweitert",
|
"advanced": "Erweitert",
|
||||||
"open_dev_tools": "Öffne die Entwicklungstools",
|
"open_dev_tools": "Öffne die Entwicklungstools",
|
||||||
"open_sql_console": "Öffne die SQL-Konsole",
|
"open_sql_console": "Öffne die SQL-Konsole",
|
||||||
@@ -655,14 +656,15 @@
|
|||||||
"show_backend_log": "Backend-Protokoll anzeigen",
|
"show_backend_log": "Backend-Protokoll anzeigen",
|
||||||
"reload_hint": "Ein Neuladen kann bei einigen visuellen Störungen Abhilfe schaffen, ohne die gesamte App neu starten zu müssen.",
|
"reload_hint": "Ein Neuladen kann bei einigen visuellen Störungen Abhilfe schaffen, ohne die gesamte App neu starten zu müssen.",
|
||||||
"reload_frontend": "Frontend neu laden",
|
"reload_frontend": "Frontend neu laden",
|
||||||
"show_hidden_subtree": "Versteckten Teilbaum anzeigen",
|
"show_hidden_subtree": "Versteckten Zweig anzeigen",
|
||||||
"show_help": "Hilfe anzeigen",
|
"show_help": "Hilfe anzeigen",
|
||||||
"about": "Über Trilium Notes",
|
"about": "Über Trilium Notes",
|
||||||
"logout": "Abmelden",
|
"logout": "Abmelden",
|
||||||
"show-cheatsheet": "Cheatsheet anzeigen",
|
"show-cheatsheet": "Cheatsheet anzeigen",
|
||||||
"toggle-zen-mode": "Zen Modus",
|
"toggle-zen-mode": "Zen Modus",
|
||||||
"new-version-available": "Neues Update verfügbar",
|
"new-version-available": "Neues Update verfügbar",
|
||||||
"download-update": "Version {{latestVersion}} herunterladen"
|
"download-update": "Version {{latestVersion}} herunterladen",
|
||||||
|
"search_notes": "Notizen durchsuchen"
|
||||||
},
|
},
|
||||||
"sync_status": {
|
"sync_status": {
|
||||||
"unknown": "<p>Der Synchronisations-Status wird bekannt, sobald der nächste Synchronisierungsversuch gestartet wird.</p><p>Klicke, um eine Synchronisierung jetzt auszulösen.</p>",
|
"unknown": "<p>Der Synchronisations-Status wird bekannt, sobald der nächste Synchronisierungsversuch gestartet wird.</p><p>Klicke, um eine Synchronisierung jetzt auszulösen.</p>",
|
||||||
@@ -703,8 +705,8 @@
|
|||||||
"export_as_image_png": "PNG (Raster)",
|
"export_as_image_png": "PNG (Raster)",
|
||||||
"export_as_image_svg": "SVG (Vektor)",
|
"export_as_image_svg": "SVG (Vektor)",
|
||||||
"note_map": "Notizen Karte",
|
"note_map": "Notizen Karte",
|
||||||
"view_revisions": "Änderungshistorie...",
|
"view_revisions": "Notizrevisionen...",
|
||||||
"advanced": "Fortgeschritten"
|
"advanced": "Erweitert"
|
||||||
},
|
},
|
||||||
"onclick_button": {
|
"onclick_button": {
|
||||||
"no_click_handler": "Das Schaltflächen-Widget „{{componentId}}“ hat keinen definierten Klick-Handler"
|
"no_click_handler": "Das Schaltflächen-Widget „{{componentId}}“ hat keinen definierten Klick-Handler"
|
||||||
@@ -720,7 +722,7 @@
|
|||||||
"update_available": "Update verfügbar"
|
"update_available": "Update verfügbar"
|
||||||
},
|
},
|
||||||
"note_launcher": {
|
"note_launcher": {
|
||||||
"this_launcher_doesnt_define_target_note": "Dieser Launcher definiert keine Zielnotiz."
|
"this_launcher_doesnt_define_target_note": "Dieser Starter definiert keine Zielnotiz."
|
||||||
},
|
},
|
||||||
"code_buttons": {
|
"code_buttons": {
|
||||||
"execute_button_title": "Skript ausführen",
|
"execute_button_title": "Skript ausführen",
|
||||||
@@ -742,7 +744,7 @@
|
|||||||
"button_title": "Diagramm als SVG exportieren"
|
"button_title": "Diagramm als SVG exportieren"
|
||||||
},
|
},
|
||||||
"relation_map_buttons": {
|
"relation_map_buttons": {
|
||||||
"create_child_note_title": "Erstelle eine neue untergeordnete Notiz und füge sie dieser Beziehungskarte hinzu",
|
"create_child_note_title": "Erstelle eine untergeordnete Notiz und füge sie dieser Karte hinzu",
|
||||||
"reset_pan_zoom_title": "Schwenken und Zoomen auf die ursprünglichen Koordinaten und Vergrößerung zurücksetzen",
|
"reset_pan_zoom_title": "Schwenken und Zoomen auf die ursprünglichen Koordinaten und Vergrößerung zurücksetzen",
|
||||||
"zoom_in_title": "Hineinzoom",
|
"zoom_in_title": "Hineinzoom",
|
||||||
"zoom_out_title": "Herauszoomen"
|
"zoom_out_title": "Herauszoomen"
|
||||||
@@ -757,14 +759,16 @@
|
|||||||
"delete_this_note": "Diese Notiz löschen",
|
"delete_this_note": "Diese Notiz löschen",
|
||||||
"error_cannot_get_branch_id": "BranchId für notePath „{{notePath}}“ kann nicht abgerufen werden",
|
"error_cannot_get_branch_id": "BranchId für notePath „{{notePath}}“ kann nicht abgerufen werden",
|
||||||
"error_unrecognized_command": "Unbekannter Befehl {{command}}",
|
"error_unrecognized_command": "Unbekannter Befehl {{command}}",
|
||||||
"note_revisions": "Notiz Revisionen"
|
"note_revisions": "Notiz Revisionen",
|
||||||
|
"backlinks": "Rücklinks",
|
||||||
|
"content_language_switcher": "Inhaltssprache: {{language}}"
|
||||||
},
|
},
|
||||||
"note_icon": {
|
"note_icon": {
|
||||||
"change_note_icon": "Notiz-Icon ändern",
|
"change_note_icon": "Notiz-Icon ändern",
|
||||||
"search": "Suche:",
|
"search": "Suche:",
|
||||||
"reset-default": "Standard wiederherstellen",
|
"reset-default": "Standard wiederherstellen",
|
||||||
"search_placeholder_one": "Suche {{number}} Icons über {{count}} Pakete",
|
"search_placeholder_one": "Suche {{number}} Symbole über {{count}} Pakete",
|
||||||
"search_placeholder_other": "Suche {{number}} Icons über {{count}} Pakete",
|
"search_placeholder_other": "Suche {{number}} Symbole über {{count}} Pakete",
|
||||||
"search_placeholder_filtered": "Suche {{number}} Icons in {{name}}",
|
"search_placeholder_filtered": "Suche {{number}} Icons in {{name}}",
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"filter-none": "Alle Icons",
|
"filter-none": "Alle Icons",
|
||||||
@@ -798,7 +802,7 @@
|
|||||||
"expand_tooltip": "Erweitert die direkten Unterelemente dieser Sammlung (eine Ebene tiefer). Für weitere Optionen auf den Pfeil rechts klicken.",
|
"expand_tooltip": "Erweitert die direkten Unterelemente dieser Sammlung (eine Ebene tiefer). Für weitere Optionen auf den Pfeil rechts klicken.",
|
||||||
"expand_first_level": "Direkte Unterelemente erweitern",
|
"expand_first_level": "Direkte Unterelemente erweitern",
|
||||||
"expand_nth_level": "{{depth}} Ebenen erweitern",
|
"expand_nth_level": "{{depth}} Ebenen erweitern",
|
||||||
"hide_child_notes": "Unterknoten im Baum ausblenden"
|
"hide_child_notes": "Untergeordnete Notizen im Baum ausblenden"
|
||||||
},
|
},
|
||||||
"edited_notes": {
|
"edited_notes": {
|
||||||
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
|
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
|
||||||
@@ -842,7 +846,7 @@
|
|||||||
"note_size": "Notengröße",
|
"note_size": "Notengröße",
|
||||||
"note_size_info": "Die Notizgröße bietet eine grobe Schätzung des Speicherbedarfs für diese Notiz. Es berücksichtigt den Inhalt der Notiz und den Inhalt ihrer Notizrevisionen.",
|
"note_size_info": "Die Notizgröße bietet eine grobe Schätzung des Speicherbedarfs für diese Notiz. Es berücksichtigt den Inhalt der Notiz und den Inhalt ihrer Notizrevisionen.",
|
||||||
"calculate": "berechnen",
|
"calculate": "berechnen",
|
||||||
"subtree_size": "(Teilbaumgröße: {{size}} in {{count}} Notizen)",
|
"subtree_size": "(Zweiggröße: {{size}} in {{count}} Notizen)",
|
||||||
"title": "Notizinfo",
|
"title": "Notizinfo",
|
||||||
"mime": "MIME Typ",
|
"mime": "MIME Typ",
|
||||||
"show_similar_notes": "Zeige ähnliche Notizen"
|
"show_similar_notes": "Zeige ähnliche Notizen"
|
||||||
@@ -871,7 +875,7 @@
|
|||||||
"owned_attributes": "Eigene Attribute"
|
"owned_attributes": "Eigene Attribute"
|
||||||
},
|
},
|
||||||
"promoted_attributes": {
|
"promoted_attributes": {
|
||||||
"promoted_attributes": "Übergebene Attribute",
|
"promoted_attributes": "Hervorgehobene Attribute",
|
||||||
"url_placeholder": "http://website...",
|
"url_placeholder": "http://website...",
|
||||||
"open_external_link": "Externen Link öffnen",
|
"open_external_link": "Externen Link öffnen",
|
||||||
"unknown_label_type": "Unbekannter Labeltyp „{{type}}“",
|
"unknown_label_type": "Unbekannter Labeltyp „{{type}}“",
|
||||||
@@ -909,7 +913,8 @@
|
|||||||
"unknown_search_option": "Unbekannte Suchoption {{searchOptionName}}",
|
"unknown_search_option": "Unbekannte Suchoption {{searchOptionName}}",
|
||||||
"search_note_saved": "Suchnotiz wurde in {{-notePathTitle}} gespeichert",
|
"search_note_saved": "Suchnotiz wurde in {{-notePathTitle}} gespeichert",
|
||||||
"actions_executed": "Aktionen wurden ausgeführt.",
|
"actions_executed": "Aktionen wurden ausgeführt.",
|
||||||
"view_options": "Optionen anzeigen:"
|
"view_options": "Optionen anzeigen:",
|
||||||
|
"option": "Option"
|
||||||
},
|
},
|
||||||
"similar_notes": {
|
"similar_notes": {
|
||||||
"title": "Ähnliche Notizen",
|
"title": "Ähnliche Notizen",
|
||||||
@@ -1003,7 +1008,7 @@
|
|||||||
"no_attachments": "Diese Notiz enthält keine Anhänge."
|
"no_attachments": "Diese Notiz enthält keine Anhänge."
|
||||||
},
|
},
|
||||||
"book": {
|
"book": {
|
||||||
"no_children_help": "Diese Notiz mit dem Notiztyp Buch besitzt keine Unternotizen, deshalb ist nichts zum Anzeigen vorhanden. Siehe <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">Wiki</a> für mehr Details.",
|
"no_children_help": "Diese Sammlung enthält keine untergeordnete Notizen, daher gibt es nichts anzuzeigen.",
|
||||||
"drag_locked_title": "Für Bearbeitung gesperrt",
|
"drag_locked_title": "Für Bearbeitung gesperrt",
|
||||||
"drag_locked_message": "Das Ziehen ist nicht möglich, da die Sammlung für die Bearbeitung gesperrt ist."
|
"drag_locked_message": "Das Ziehen ist nicht möglich, da die Sammlung für die Bearbeitung gesperrt ist."
|
||||||
},
|
},
|
||||||
@@ -1042,7 +1047,6 @@
|
|||||||
"unprotecting-title": "Ungeschützt-Status"
|
"unprotecting-title": "Ungeschützt-Status"
|
||||||
},
|
},
|
||||||
"relation_map": {
|
"relation_map": {
|
||||||
"open_in_new_tab": "In neuem Tab öffnen",
|
|
||||||
"remove_note": "Notiz entfernen",
|
"remove_note": "Notiz entfernen",
|
||||||
"edit_title": "Titel bearbeiten",
|
"edit_title": "Titel bearbeiten",
|
||||||
"rename_note": "Notiz umbenennen",
|
"rename_note": "Notiz umbenennen",
|
||||||
@@ -1059,15 +1063,6 @@
|
|||||||
"default_new_note_title": "neue Notiz",
|
"default_new_note_title": "neue Notiz",
|
||||||
"click_on_canvas_to_place_new_note": "Klicke auf den Canvas, um eine neue Notiz zu platzieren"
|
"click_on_canvas_to_place_new_note": "Klicke auf den Canvas, um eine neue Notiz zu platzieren"
|
||||||
},
|
},
|
||||||
"render": {
|
|
||||||
"note_detail_render_help_1": "Diese Hilfesnotiz wird angezeigt, da diese Notiz vom Typ „HTML rendern“ nicht über die erforderliche Beziehung verfügt, um ordnungsgemäß zu funktionieren.",
|
|
||||||
"note_detail_render_help_2": "Render-HTML-Notiztyp wird benutzt für <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/scripts.html\">scripting</a>. Kurzgesagt, du hast ein HTML-Code-Notiz (optional mit JavaScript) und diese Notiz rendert es. Damit es funktioniert, musst du eine a <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/attributes.html\">Beziehung</a> namens \"renderNote\" zeigend auf die HTML-Notiz zum rendern definieren."
|
|
||||||
},
|
|
||||||
"web_view": {
|
|
||||||
"web_view": "Webansicht",
|
|
||||||
"embed_websites": "Notiz vom Typ Web View ermöglicht das Einbetten von Websites in Trilium.",
|
|
||||||
"create_label": "Um zu beginnen, erstelle bitte ein Label mit einer URL-Adresse, die eingebettet werden soll, z. B. #webViewSrc=\"https://www.google.com\""
|
|
||||||
},
|
|
||||||
"backend_log": {
|
"backend_log": {
|
||||||
"refresh": "Aktualisieren"
|
"refresh": "Aktualisieren"
|
||||||
},
|
},
|
||||||
@@ -1115,7 +1110,7 @@
|
|||||||
"vacuum_database": {
|
"vacuum_database": {
|
||||||
"title": "Datenbank aufräumen",
|
"title": "Datenbank aufräumen",
|
||||||
"description": "Dadurch wird die Datenbank neu erstellt, was normalerweise zu einer kleineren Datenbankdatei führt. Es werden keine Daten tatsächlich geändert.",
|
"description": "Dadurch wird die Datenbank neu erstellt, was normalerweise zu einer kleineren Datenbankdatei führt. Es werden keine Daten tatsächlich geändert.",
|
||||||
"button_text": "Vakuumdatenbank",
|
"button_text": "Datenbank aufräumen",
|
||||||
"vacuuming_database": "Datenbank wird geleert...",
|
"vacuuming_database": "Datenbank wird geleert...",
|
||||||
"database_vacuumed": "Die Datenbank wurde geleert"
|
"database_vacuumed": "Die Datenbank wurde geleert"
|
||||||
},
|
},
|
||||||
@@ -1156,7 +1151,7 @@
|
|||||||
},
|
},
|
||||||
"ribbon": {
|
"ribbon": {
|
||||||
"widgets": "Multifunktionsleisten-Widgets",
|
"widgets": "Multifunktionsleisten-Widgets",
|
||||||
"promoted_attributes_message": "Die Multifunktionsleisten-Registerkarte „Heraufgestufte Attribute“ wird automatisch geöffnet, wenn in der Notiz heraufgestufte Attribute vorhanden sind",
|
"promoted_attributes_message": "Die „Hervorgehobene Attribute“-Leiste wird automatisch geöffnet, wenn in der Notiz hervorgehobene Attribute vorhanden sind",
|
||||||
"edited_notes_message": "Die Multifunktionsleisten-Registerkarte „Bearbeitete Notizen“ wird bei Tagesnotizen automatisch geöffnet"
|
"edited_notes_message": "Die Multifunktionsleisten-Registerkarte „Bearbeitete Notizen“ wird bei Tagesnotizen automatisch geöffnet"
|
||||||
},
|
},
|
||||||
"theme": {
|
"theme": {
|
||||||
@@ -1169,7 +1164,7 @@
|
|||||||
"layout": "Layout",
|
"layout": "Layout",
|
||||||
"layout-vertical-title": "Vertikal",
|
"layout-vertical-title": "Vertikal",
|
||||||
"layout-horizontal-title": "Horizontal",
|
"layout-horizontal-title": "Horizontal",
|
||||||
"layout-vertical-description": "Startleiste ist auf der linken Seite (standard)",
|
"layout-vertical-description": "Startleiste ist auf der linken Seite (Standard)",
|
||||||
"layout-horizontal-description": "Startleiste ist unter der Tableiste. Die Tableiste wird dadurch auf die ganze Breite erweitert.",
|
"layout-horizontal-description": "Startleiste ist unter der Tableiste. Die Tableiste wird dadurch auf die ganze Breite erweitert.",
|
||||||
"auto_theme": "Alt (Folge dem Farbschema des Systems)",
|
"auto_theme": "Alt (Folge dem Farbschema des Systems)",
|
||||||
"light_theme": "Alt (Hell)",
|
"light_theme": "Alt (Hell)",
|
||||||
@@ -1177,7 +1172,7 @@
|
|||||||
},
|
},
|
||||||
"zoom_factor": {
|
"zoom_factor": {
|
||||||
"title": "Zoomfaktor (nur Desktop-Build)",
|
"title": "Zoomfaktor (nur Desktop-Build)",
|
||||||
"description": "Das Zoomen kann auch mit den Tastenkombinationen STRG+- und STRG+u003d gesteuert werden."
|
"description": "Das Zoomen kann auch mit den Tastenkombinationen Strg+- und Strg+= gesteuert werden."
|
||||||
},
|
},
|
||||||
"code_auto_read_only_size": {
|
"code_auto_read_only_size": {
|
||||||
"title": "Automatische schreibgeschützte Größe",
|
"title": "Automatische schreibgeschützte Größe",
|
||||||
@@ -1192,7 +1187,7 @@
|
|||||||
"tooltip_code_note_syntax": "Code-Notizen"
|
"tooltip_code_note_syntax": "Code-Notizen"
|
||||||
},
|
},
|
||||||
"vim_key_bindings": {
|
"vim_key_bindings": {
|
||||||
"use_vim_keybindings_in_code_notes": "Verwende VIM-Tastenkombinationen in Codenotizen (kein Ex-Modus)",
|
"use_vim_keybindings_in_code_notes": "Vim Tastenbelegung",
|
||||||
"enable_vim_keybindings": "Aktiviere Vim-Tastenkombinationen"
|
"enable_vim_keybindings": "Aktiviere Vim-Tastenkombinationen"
|
||||||
},
|
},
|
||||||
"wrap_lines": {
|
"wrap_lines": {
|
||||||
@@ -1266,16 +1261,16 @@
|
|||||||
"markdown": "Markdown-Stil"
|
"markdown": "Markdown-Stil"
|
||||||
},
|
},
|
||||||
"highlights_list": {
|
"highlights_list": {
|
||||||
"title": "Highlights-Liste",
|
"title": "Markierungsliste",
|
||||||
"description": "Du kannst die im rechten Bereich angezeigte Highlights-Liste anpassen:",
|
"description": "Du kannst die im rechten Bereich angezeigte Markierungsliste anpassen:",
|
||||||
"bold": "Fettgedruckter Text",
|
"bold": "Fettgedruckter Text",
|
||||||
"italic": "Kursiver Text",
|
"italic": "Kursiver Text",
|
||||||
"underline": "Unterstrichener Text",
|
"underline": "Unterstrichener Text",
|
||||||
"color": "Farbiger Text",
|
"color": "Farbiger Text",
|
||||||
"bg_color": "Text mit Hintergrundfarbe",
|
"bg_color": "Text mit Hintergrundfarbe",
|
||||||
"visibility_title": "Sichtbarkeit der Highlights-Liste",
|
"visibility_title": "Sichtbarkeit der Markierungsliste",
|
||||||
"visibility_description": "Du kannst das Hervorhebungs-Widget pro Notiz ausblenden, indem du die Beschriftung #hideHighlightWidget hinzufügst.",
|
"visibility_description": "Du kannst das Markierungs-Widget pro Notiz ausblenden, indem du die Beschriftung #hideHighlightWidget hinzufügst.",
|
||||||
"shortcut_info": "Du kannst eine Tastenkombination zum schnellen Umschalten des rechten Bereichs (einschließlich Hervorhebungen) in den Optionen -> Tastenkombinationen konfigurieren (Name „toggleRightPane“)."
|
"shortcut_info": "Du kannst eine Tastenkombination zum schnellen Umschalten des rechten Bereichs (einschließlich Markierungen) in den Optionen -> Tastenkombinationen konfigurieren (Name „toggleRightPane“)."
|
||||||
},
|
},
|
||||||
"table_of_contents": {
|
"table_of_contents": {
|
||||||
"title": "Inhaltsverzeichnis",
|
"title": "Inhaltsverzeichnis",
|
||||||
@@ -1383,7 +1378,8 @@
|
|||||||
"description": "Beschreibung",
|
"description": "Beschreibung",
|
||||||
"reload_app": "Lade die App neu, um die Änderungen zu übernehmen",
|
"reload_app": "Lade die App neu, um die Änderungen zu übernehmen",
|
||||||
"set_all_to_default": "Setze alle Verknüpfungen auf die Standardeinstellungen",
|
"set_all_to_default": "Setze alle Verknüpfungen auf die Standardeinstellungen",
|
||||||
"confirm_reset": "Möchtest du wirklich alle Tastaturkürzel auf die Standardeinstellungen zurücksetzen?"
|
"confirm_reset": "Möchtest du wirklich alle Tastaturkürzel auf die Standardeinstellungen zurücksetzen?",
|
||||||
|
"no_results": "Keine Tastenkürzel für '{{filter}}' gefunden"
|
||||||
},
|
},
|
||||||
"spellcheck": {
|
"spellcheck": {
|
||||||
"title": "Rechtschreibprüfung",
|
"title": "Rechtschreibprüfung",
|
||||||
@@ -1443,21 +1439,21 @@
|
|||||||
"open-in-a-new-tab": "In neuem Tab öffnen",
|
"open-in-a-new-tab": "In neuem Tab öffnen",
|
||||||
"open-in-a-new-split": "In neuem Split öffnen",
|
"open-in-a-new-split": "In neuem Split öffnen",
|
||||||
"insert-note-after": "Notiz dahinter einfügen",
|
"insert-note-after": "Notiz dahinter einfügen",
|
||||||
"insert-child-note": "Unternotiz einfügen",
|
"insert-child-note": "Untergeordnete Notiz einfügen",
|
||||||
"delete": "Löschen",
|
"delete": "Löschen",
|
||||||
"search-in-subtree": "Im Notizbaum suchen",
|
"search-in-subtree": "Im Zweig suchen",
|
||||||
"hoist-note": "Notiz-Fokus setzen",
|
"hoist-note": "Notiz-Fokus setzen",
|
||||||
"unhoist-note": "Notiz-Fokus aufheben",
|
"unhoist-note": "Notiz-Fokus aufheben",
|
||||||
"edit-branch-prefix": "Zweig-Präfix bearbeiten",
|
"edit-branch-prefix": "Zweig-Präfix bearbeiten",
|
||||||
"advanced": "Erweitert",
|
"advanced": "Erweitert",
|
||||||
"expand-subtree": "Unterzweig aufklappen",
|
"expand-subtree": "Zweig aufklappen",
|
||||||
"collapse-subtree": "Notizbaum einklappen",
|
"collapse-subtree": "Zweig einklappen",
|
||||||
"sort-by": "Sortieren nach...",
|
"sort-by": "Sortieren nach...",
|
||||||
"recent-changes-in-subtree": "Kürzliche Änderungen im Notizbaum",
|
"recent-changes-in-subtree": "Kürzliche Änderungen im Zweig",
|
||||||
"convert-to-attachment": "Als Anhang konvertieren",
|
"convert-to-attachment": "Als Anhang konvertieren",
|
||||||
"copy-note-path-to-clipboard": "Notiz-Pfad in die Zwischenablage kopieren",
|
"copy-note-path-to-clipboard": "Notiz-Pfad in die Zwischenablage kopieren",
|
||||||
"protect-subtree": "Notizbaum schützen",
|
"protect-subtree": "Zweig schützen",
|
||||||
"unprotect-subtree": "Notizenbaum-Schutz aufheben",
|
"unprotect-subtree": "Zweig-Schutz aufheben",
|
||||||
"copy-clone": "Kopieren / Klonen",
|
"copy-clone": "Kopieren / Klonen",
|
||||||
"clone-to": "Klonen nach...",
|
"clone-to": "Klonen nach...",
|
||||||
"cut": "Ausschneiden",
|
"cut": "Ausschneiden",
|
||||||
@@ -1474,12 +1470,12 @@
|
|||||||
"archive": "Archiviere",
|
"archive": "Archiviere",
|
||||||
"unarchive": "Entarchivieren",
|
"unarchive": "Entarchivieren",
|
||||||
"open-in-a-new-window": "In neuem Fenster öffnen",
|
"open-in-a-new-window": "In neuem Fenster öffnen",
|
||||||
"hide-subtree": "Teilbaum ausblenden",
|
"hide-subtree": "Zweig ausblenden",
|
||||||
"show-subtree": "Teilbaum anzeigen"
|
"show-subtree": "Zweig anzeigen"
|
||||||
},
|
},
|
||||||
"shared_info": {
|
"shared_info": {
|
||||||
"shared_publicly": "Diese Notiz ist öffentlich geteilt auf {{- link}}.",
|
"shared_publicly": "Diese Notiz ist öffentlich freigegeben über {{- link}}.",
|
||||||
"shared_locally": "Diese Notiz ist lokal geteilt auf {{- link}}.",
|
"shared_locally": "Diese Notiz ist lokal freigegeben über {{- link}}.",
|
||||||
"help_link": "Für Hilfe besuche <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>."
|
"help_link": "Für Hilfe besuche <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>."
|
||||||
},
|
},
|
||||||
"note_types": {
|
"note_types": {
|
||||||
@@ -1490,22 +1486,23 @@
|
|||||||
"note-map": "Notizkarte",
|
"note-map": "Notizkarte",
|
||||||
"render-note": "Render Notiz",
|
"render-note": "Render Notiz",
|
||||||
"mermaid-diagram": "Mermaid Diagramm",
|
"mermaid-diagram": "Mermaid Diagramm",
|
||||||
"canvas": "Canvas",
|
"canvas": "Leinwand",
|
||||||
"web-view": "Webansicht",
|
"web-view": "Webansicht",
|
||||||
"mind-map": "Mind Map",
|
"mind-map": "Mindmap",
|
||||||
"file": "Datei",
|
"file": "Datei",
|
||||||
"image": "Bild",
|
"image": "Bild",
|
||||||
"launcher": "Launcher",
|
"launcher": "Starter",
|
||||||
"doc": "Dokument",
|
"doc": "Dokument",
|
||||||
"widget": "Widget",
|
"widget": "Widget",
|
||||||
"confirm-change": "Es is nicht empfehlenswert den Notiz-Typ zu ändern, wenn der Inhalt der Notiz nicht leer ist. Möchtest du dennoch fortfahren?",
|
"confirm-change": "Es ist nicht empfehlenswert den Notiz-Typ zu ändern, wenn der Inhalt der Notiz nicht leer ist. Möchtest du dennoch fortfahren?",
|
||||||
"geo-map": "Geo-Karte",
|
"geo-map": "Geo-Karte",
|
||||||
"beta-feature": "Beta",
|
"beta-feature": "Beta",
|
||||||
"book": "Sammlung",
|
"book": "Sammlung",
|
||||||
"ai-chat": "KI Chat",
|
"ai-chat": "KI-Chat",
|
||||||
"task-list": "Aufgabenliste",
|
"task-list": "Aufgabenliste",
|
||||||
"new-feature": "Neu",
|
"new-feature": "Neu",
|
||||||
"collections": "Sammlungen"
|
"collections": "Sammlungen",
|
||||||
|
"spreadsheet": "Tabelle"
|
||||||
},
|
},
|
||||||
"protect_note": {
|
"protect_note": {
|
||||||
"toggle-on": "Notiz schützen",
|
"toggle-on": "Notiz schützen",
|
||||||
@@ -1514,10 +1511,10 @@
|
|||||||
"toggle-off-hint": "Notiz ist geschützt, klicken, um den Schutz aufzuheben"
|
"toggle-off-hint": "Notiz ist geschützt, klicken, um den Schutz aufzuheben"
|
||||||
},
|
},
|
||||||
"shared_switch": {
|
"shared_switch": {
|
||||||
"shared": "Teilen",
|
"shared": "Freigegeben",
|
||||||
"toggle-on-title": "Notiz teilen",
|
"toggle-on-title": "Notiz freigeben",
|
||||||
"toggle-off-title": "Notiz-Freigabe aufheben",
|
"toggle-off-title": "Notiz-Freigabe aufheben",
|
||||||
"shared-branch": "Diese Notiz existiert nur als geteilte Notiz, das Aufheben der Freigabe würde sie löschen. Möchtest du fortfahren und die Notiz damit löschen?",
|
"shared-branch": "Diese Notiz existiert nur als freigegebene Notiz, das Aufheben der Freigabe würde sie löschen. Möchtest du fortfahren und die Notiz damit löschen?",
|
||||||
"inherited": "Die Notiz kann hier nicht von der Freigabe entfernt werden, da sie über Vererbung von einer übergeordneten Notiz geteilt wird."
|
"inherited": "Die Notiz kann hier nicht von der Freigabe entfernt werden, da sie über Vererbung von einer übergeordneten Notiz geteilt wird."
|
||||||
},
|
},
|
||||||
"template_switch": {
|
"template_switch": {
|
||||||
@@ -1535,13 +1532,13 @@
|
|||||||
"replace_all": "Alle Ersetzen"
|
"replace_all": "Alle Ersetzen"
|
||||||
},
|
},
|
||||||
"highlights_list_2": {
|
"highlights_list_2": {
|
||||||
"title": "Hervorhebungs-Liste",
|
"title": "Markierungsliste",
|
||||||
"options": "Optionen",
|
"options": "Optionen",
|
||||||
"title_with_count_one": "{{count}} Highlight",
|
"title_with_count_one": "{{count}} Markierung",
|
||||||
"title_with_count_other": "{{count}} Highlights",
|
"title_with_count_other": "{{count}} Markierungen",
|
||||||
"modal_title": "Highlight Liste konfigurieren",
|
"modal_title": "Markierungsliste konfigurieren",
|
||||||
"menu_configure": "Highlight Liste konfigurieren…",
|
"menu_configure": "Markierungsliste konfigurieren…",
|
||||||
"no_highlights": "Keine Highlights gefunden."
|
"no_highlights": "Keine Markierungen gefunden."
|
||||||
},
|
},
|
||||||
"quick-search": {
|
"quick-search": {
|
||||||
"placeholder": "Schnellsuche",
|
"placeholder": "Schnellsuche",
|
||||||
@@ -1562,19 +1559,19 @@
|
|||||||
"saved-search-note-refreshed": "Gespeicherte Such-Notiz wurde aktualisiert.",
|
"saved-search-note-refreshed": "Gespeicherte Such-Notiz wurde aktualisiert.",
|
||||||
"hoist-this-note-workspace": "Diese Notiz fokussieren (Arbeitsbereich)",
|
"hoist-this-note-workspace": "Diese Notiz fokussieren (Arbeitsbereich)",
|
||||||
"refresh-saved-search-results": "Gespeicherte Suchergebnisse aktualisieren",
|
"refresh-saved-search-results": "Gespeicherte Suchergebnisse aktualisieren",
|
||||||
"create-child-note": "Unternotiz anlegen",
|
"create-child-note": "Untergeordnete Notiz anlegen",
|
||||||
"unhoist": "Fokus verlassen",
|
"unhoist": "Fokus verlassen",
|
||||||
"toggle-sidebar": "Seitenleiste ein-/ausblenden",
|
"toggle-sidebar": "Seitenleiste ein-/ausblenden",
|
||||||
"dropping-not-allowed": "Ablegen von Notizen an dieser Stelle ist nicht zulässig.",
|
"dropping-not-allowed": "Ablegen von Notizen an dieser Stelle ist nicht zulässig.",
|
||||||
"clone-indicator-tooltip": "Diese Notiz hat {{- count}} Elterknoten: {{- parents}}",
|
"clone-indicator-tooltip": "Diese Notiz hat {{- count}} übergeordnete Knoten: {{- parents}}",
|
||||||
"clone-indicator-tooltip-single": "Diese Notiz ist geklont (1 weiterer Elternknoten: {{- parent}})",
|
"clone-indicator-tooltip-single": "Diese Notiz ist geklont (1 weitere Quelle: {{- parent}})",
|
||||||
"shared-indicator-tooltip": "Diese Notiz ist öffentlich einsehbar",
|
"shared-indicator-tooltip": "Diese Notiz ist öffentlich freigegeben",
|
||||||
"shared-indicator-tooltip-with-url": "Diese Notiz ist unter {{- url}} öffentlich einsehbar",
|
"shared-indicator-tooltip-with-url": "Diese Notiz ist öffentlich freigegeben unter: {{- url}}",
|
||||||
"subtree-hidden-tooltip_one": "{{count}} Unterknoten, der im Baum ausgeblendet ist",
|
"subtree-hidden-tooltip_one": "{{count}} untergeordnete Notiz, die im Baum ausgeblendet ist",
|
||||||
"subtree-hidden-tooltip_other": "{{count}} Unterknoten, die im Baum ausgeblendet sind",
|
"subtree-hidden-tooltip_other": "{{count}} untergeordnete Notizen, die im Baum ausgeblendet sind",
|
||||||
"subtree-hidden-moved-title": "Zu {{title}} hinzugefügt",
|
"subtree-hidden-moved-title": "Zu {{title}} hinzugefügt",
|
||||||
"subtree-hidden-moved-description-collection": "Diese Sammlung blendet ihre Unternotizem im Baum aus.",
|
"subtree-hidden-moved-description-collection": "Diese Sammlung blendet ihre untergeordneten Notizen im Baum aus.",
|
||||||
"subtree-hidden-moved-description-other": "Diese Sammlung blendet ihre Unterknoten im Baum aus."
|
"subtree-hidden-moved-description-other": "Untergeordnete Notizen sind im Baum für diese Notiz ausgeblendet."
|
||||||
},
|
},
|
||||||
"title_bar_buttons": {
|
"title_bar_buttons": {
|
||||||
"window-on-top": "Dieses Fenster immer oben halten"
|
"window-on-top": "Dieses Fenster immer oben halten"
|
||||||
@@ -1586,8 +1583,10 @@
|
|||||||
"print_report_title": "Druckreport",
|
"print_report_title": "Druckreport",
|
||||||
"print_report_collection_details_button": "Details anzeigen",
|
"print_report_collection_details_button": "Details anzeigen",
|
||||||
"print_report_collection_details_ignored_notes": "Ignorierte Notizen",
|
"print_report_collection_details_ignored_notes": "Ignorierte Notizen",
|
||||||
"print_report_collection_content_one": "{{count}} Notiz in der Sammlung konnte nicht gedruckt werden, weil sie nicht unterstützt ist oder geschützt ist.",
|
"print_report_collection_content_one": "{{count}} Notiz in der Sammlung konnte nicht gedruckt werden, weil sie nicht unterstützt oder geschützt ist.",
|
||||||
"print_report_collection_content_other": "{{count}} Notizen in der Sammlung konnten nicht gedruckt werden, weil sie nicht unterstützt sind oder geschützt sind."
|
"print_report_collection_content_other": "{{count}} Notizen in der Sammlung konnten nicht gedruckt werden, weil sie nicht unterstützt oder geschützt sind.",
|
||||||
|
"print_report_error_title": "Druck fehlgeschlagen",
|
||||||
|
"print_report_stack_trace": "Stapelzurückverfolgung"
|
||||||
},
|
},
|
||||||
"note_title": {
|
"note_title": {
|
||||||
"placeholder": "Titel der Notiz hier eingeben…",
|
"placeholder": "Titel der Notiz hier eingeben…",
|
||||||
@@ -1595,20 +1594,25 @@
|
|||||||
"last_modified": "Bearbeitet am <Value />",
|
"last_modified": "Bearbeitet am <Value />",
|
||||||
"note_type_switcher_label": "Ändere von {{type}} zu:",
|
"note_type_switcher_label": "Ändere von {{type}} zu:",
|
||||||
"note_type_switcher_others": "Andere Notizart",
|
"note_type_switcher_others": "Andere Notizart",
|
||||||
"note_type_switcher_templates": "Template",
|
"note_type_switcher_templates": "Vorlage",
|
||||||
"note_type_switcher_collection": "Sammlung",
|
"note_type_switcher_collection": "Sammlung",
|
||||||
"edited_notes": "Notizen, bearbeitet an diesem Tag",
|
"edited_notes": "Notizen, bearbeitet an diesem Tag",
|
||||||
"promoted_attributes": "Hervorgehobene Attribute"
|
"promoted_attributes": "Hervorgehobene Attribute"
|
||||||
},
|
},
|
||||||
"search_result": {
|
"search_result": {
|
||||||
"no_notes_found": "Es wurden keine Notizen mit den angegebenen Suchparametern gefunden.",
|
"no_notes_found": "Es wurden keine Notizen mit den angegebenen Suchparametern gefunden.",
|
||||||
"search_not_executed": "Die Suche wurde noch nicht ausgeführt. Klicke oben auf „Suchen“, um die Ergebnisse anzuzeigen."
|
"search_not_executed": "Die Suche wurde noch nicht ausgeführt.",
|
||||||
|
"search_now": "Jetzt suchen"
|
||||||
},
|
},
|
||||||
"spacer": {
|
"spacer": {
|
||||||
"configure_launchbar": "Startleiste konfigurieren"
|
"configure_launchbar": "Starterleiste konfigurieren"
|
||||||
},
|
},
|
||||||
"sql_result": {
|
"sql_result": {
|
||||||
"no_rows": "Es wurden keine Zeilen für diese Abfrage zurückgegeben"
|
"no_rows": "Es wurden keine Zeilen für diese Abfrage zurückgegeben",
|
||||||
|
"not_executed": "Die Abfrage wurde noch nicht ausgeführt.",
|
||||||
|
"failed": "SQL-Abfrage ist fehlgeschlagen",
|
||||||
|
"execute_now": "Jetzt ausführen",
|
||||||
|
"statement_result": "Abfrageergebnis"
|
||||||
},
|
},
|
||||||
"sql_table_schemas": {
|
"sql_table_schemas": {
|
||||||
"tables": "Tabellen"
|
"tables": "Tabellen"
|
||||||
@@ -1679,16 +1683,16 @@
|
|||||||
"confirm_unhoisting": "Die angeforderte Notiz ‚{{requestedNote}}‘ befindet sich außerhalb des hoisted Bereichs der Notiz ‚{{hoistedNote}}‘. Du musst sie unhoisten, um auf die Notiz zuzugreifen. Möchtest du mit dem Unhoisting fortfahren?"
|
"confirm_unhoisting": "Die angeforderte Notiz ‚{{requestedNote}}‘ befindet sich außerhalb des hoisted Bereichs der Notiz ‚{{hoistedNote}}‘. Du musst sie unhoisten, um auf die Notiz zuzugreifen. Möchtest du mit dem Unhoisting fortfahren?"
|
||||||
},
|
},
|
||||||
"launcher_context_menu": {
|
"launcher_context_menu": {
|
||||||
"reset_launcher_confirm": "Möchtest du „{{title}}“ wirklich zurücksetzen? Alle Daten / Einstellungen in dieser Notiz (und ihren Unternotizen) gehen verloren und der Launcher wird an seinen ursprünglichen Standort zurückgesetzt.",
|
"reset_launcher_confirm": "Möchtest du „{{title}}“ wirklich zurücksetzen? Alle Daten / Einstellungen in dieser Notiz (und ihren Unternotizen) gehen verloren und der Starter wird an seinen ursprünglichen Standort zurückgesetzt.",
|
||||||
"add-note-launcher": "Launcher für Notiz hinzufügen",
|
"add-note-launcher": "Notiz-Starter hinzufügen",
|
||||||
"add-script-launcher": "Launcher für Skript hinzufügen",
|
"add-script-launcher": "Skript-Starter hinzufügen",
|
||||||
"add-custom-widget": "Benutzerdefiniertes Widget hinzufügen",
|
"add-custom-widget": "Benutzerdefiniertes Widget hinzufügen",
|
||||||
"add-spacer": "Spacer hinzufügen",
|
"add-spacer": "Abstandhalter hinzufügen",
|
||||||
"delete": "Löschen <kbd data-command=\"deleteNotes\"></kbd>",
|
"delete": "Löschen <kbd data-command=\"deleteNotes\"></kbd>",
|
||||||
"reset": "Zurücksetzen",
|
"reset": "Zurücksetzen",
|
||||||
"move-to-visible-launchers": "Zu sichtbaren Launchern verschieben",
|
"move-to-visible-launchers": "Zu sichtbaren Startern verschieben",
|
||||||
"move-to-available-launchers": "Zu verfügbaren Launchern verschieben",
|
"move-to-available-launchers": "Zu verfügbaren Startern verschieben",
|
||||||
"duplicate-launcher": "Launcher duplizieren <kbd data-command=\"duplicateSubtree\">"
|
"duplicate-launcher": "Starter duplizieren <kbd data-command=\"duplicateSubtree\">"
|
||||||
},
|
},
|
||||||
"highlighting": {
|
"highlighting": {
|
||||||
"description": "Steuert die Syntaxhervorhebung für Codeblöcke in Textnotizen, Code-Notizen sind nicht betroffen.",
|
"description": "Steuert die Syntaxhervorhebung für Codeblöcke in Textnotizen, Code-Notizen sind nicht betroffen.",
|
||||||
@@ -1697,7 +1701,7 @@
|
|||||||
},
|
},
|
||||||
"code_block": {
|
"code_block": {
|
||||||
"word_wrapping": "Wortumbruch",
|
"word_wrapping": "Wortumbruch",
|
||||||
"theme_none": "Keine Syntax-Hervorhebung",
|
"theme_none": "Keine Syntaxhervorhebung",
|
||||||
"theme_group_light": "Helle Themen",
|
"theme_group_light": "Helle Themen",
|
||||||
"theme_group_dark": "Dunkle Themen",
|
"theme_group_dark": "Dunkle Themen",
|
||||||
"copy_title": "Kopiere in Zwischenablage"
|
"copy_title": "Kopiere in Zwischenablage"
|
||||||
@@ -1726,6 +1730,7 @@
|
|||||||
"add-term-to-dictionary": "Begriff \"{{term}}\" zum Wörterbuch hinzufügen",
|
"add-term-to-dictionary": "Begriff \"{{term}}\" zum Wörterbuch hinzufügen",
|
||||||
"cut": "Ausschneiden",
|
"cut": "Ausschneiden",
|
||||||
"copy": "Kopieren",
|
"copy": "Kopieren",
|
||||||
|
"copy-as-markdown": "Als Markdown kopieren",
|
||||||
"copy-link": "Link kopieren",
|
"copy-link": "Link kopieren",
|
||||||
"paste": "Einfügen",
|
"paste": "Einfügen",
|
||||||
"paste-as-plain-text": "Als unformatierten Text einfügen",
|
"paste-as-plain-text": "Als unformatierten Text einfügen",
|
||||||
@@ -1747,14 +1752,14 @@
|
|||||||
"desktop-application": "Desktop Anwendung",
|
"desktop-application": "Desktop Anwendung",
|
||||||
"native-title-bar": "Native Anwendungsleiste",
|
"native-title-bar": "Native Anwendungsleiste",
|
||||||
"native-title-bar-description": "In Windows und macOS, sorgt das Deaktivieren der nativen Anwendungsleiste für ein kompakteres Aussehen. Unter Linux, sorgt das Aktivieren der nativen Anwendungsleiste für eine bessere Integration mit anderen Teilen des Systems.",
|
"native-title-bar-description": "In Windows und macOS, sorgt das Deaktivieren der nativen Anwendungsleiste für ein kompakteres Aussehen. Unter Linux, sorgt das Aktivieren der nativen Anwendungsleiste für eine bessere Integration mit anderen Teilen des Systems.",
|
||||||
"background-effects": "Hintergrundeffekte aktivieren (nur Windows 11)",
|
"background-effects": "Hintergrundeffekte aktivieren",
|
||||||
"background-effects-description": "Der Mica Effekt fügt einen unscharfen, stylischen Hintergrund in Anwendungsfenstern ein. Dieser erzeugt Tiefe und ein modernes Auftreten. \"Native Titelleiste\" muss deaktiviert sein.",
|
"background-effects-description": "Fügt einen unscharfen, stylischen Hintergrund in das Anwendungsfenstern ein. Dies erzeugt Tiefe und ein modernes Auftreten. \"Native Titelleiste\" muss deaktiviert sein.",
|
||||||
"restart-app-button": "Anwendung neustarten um Änderungen anzuwenden",
|
"restart-app-button": "Anwendung neustarten um Änderungen anzuwenden",
|
||||||
"zoom-factor": "Zoomfaktor"
|
"zoom-factor": "Zoomfaktor"
|
||||||
},
|
},
|
||||||
"note_autocomplete": {
|
"note_autocomplete": {
|
||||||
"search-for": "Suche nach \"{{term}}\"",
|
"search-for": "Suche nach \"{{term}}\"",
|
||||||
"create-note": "Erstelle und verlinke Unternotiz \"{{term}}\"",
|
"create-note": "Erstelle und verlinke untergeordnete Notiz \"{{term}}\"",
|
||||||
"insert-external-link": "Einfügen von Externen Link zu \"{{term}}\"",
|
"insert-external-link": "Einfügen von Externen Link zu \"{{term}}\"",
|
||||||
"clear-text-field": "Textfeldinhalt löschen",
|
"clear-text-field": "Textfeldinhalt löschen",
|
||||||
"show-recent-notes": "Aktuelle Notizen anzeigen",
|
"show-recent-notes": "Aktuelle Notizen anzeigen",
|
||||||
@@ -1765,9 +1770,10 @@
|
|||||||
"quick-edit": "Schnellbearbeitung"
|
"quick-edit": "Schnellbearbeitung"
|
||||||
},
|
},
|
||||||
"geo-map": {
|
"geo-map": {
|
||||||
"create-child-note-title": "Neue Unternotiz anlegen und zur Karte hinzufügen",
|
"create-child-note-title": "Neue untergeordnete Notiz anlegen und zur Karte hinzufügen",
|
||||||
"create-child-note-instruction": "Auf die Karte klicken, um eine neue Notiz an der Stelle zu erstellen oder Escape drücken um abzubrechen.",
|
"create-child-note-instruction": "Auf die Karte klicken, um eine neue Notiz an der Stelle zu erstellen oder Escape drücken um abzubrechen.",
|
||||||
"unable-to-load-map": "Karte konnte nicht geladen werden."
|
"unable-to-load-map": "Karte konnte nicht geladen werden.",
|
||||||
|
"create-child-note-text": "Marker hinzufügen"
|
||||||
},
|
},
|
||||||
"geo-map-context": {
|
"geo-map-context": {
|
||||||
"open-location": "Ort öffnen",
|
"open-location": "Ort öffnen",
|
||||||
@@ -1791,149 +1797,6 @@
|
|||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
"help_title": "Zeige mehr Informationen zu diesem Fenster"
|
"help_title": "Zeige mehr Informationen zu diesem Fenster"
|
||||||
},
|
},
|
||||||
"ai_llm": {
|
|
||||||
"not_started": "Nicht gestartet",
|
|
||||||
"title": "KI Einstellungen",
|
|
||||||
"processed_notes": "Verarbeitete Notizen",
|
|
||||||
"total_notes": "Gesamt Notizen",
|
|
||||||
"progress": "Fortschritt",
|
|
||||||
"queued_notes": "Eingereihte Notizen",
|
|
||||||
"failed_notes": "Fehlgeschlagenen Notizen",
|
|
||||||
"last_processed": "Zuletzt verarbeitet",
|
|
||||||
"refresh_stats": "Statistiken neu laden",
|
|
||||||
"enable_ai_features": "Aktiviere KI/LLM Funktionen",
|
|
||||||
"enable_ai_description": "Aktiviere KI-Funktionen wie Notizzusammenfassungen, Inhaltserzeugung und andere LLM-Funktionen",
|
|
||||||
"openai_tab": "OpenAI",
|
|
||||||
"anthropic_tab": "Anthropic",
|
|
||||||
"voyage_tab": "Voyage AI",
|
|
||||||
"ollama_tab": "Ollama",
|
|
||||||
"enable_ai": "Aktiviere KI/LLM Funktionen",
|
|
||||||
"enable_ai_desc": "Aktiviere KI-Funktionen wie Notizzusammenfassungen, Inhaltserzeugung und andere LLM-Funktionen",
|
|
||||||
"provider_configuration": "KI-Anbieterkonfiguration",
|
|
||||||
"provider_precedence": "Anbieter Priorität",
|
|
||||||
"provider_precedence_description": "Komma-getrennte Liste von Anbieter in der Reihenfolge ihrer Priorität (z.B. 'openai, anthropic,ollama')",
|
|
||||||
"temperature": "Temperatur",
|
|
||||||
"temperature_description": "Regelt die Zufälligkeit in Antworten (0 = deterministisch, 2 = maximale Zufälligkeit)",
|
|
||||||
"system_prompt": "Systemaufforderung",
|
|
||||||
"system_prompt_description": "Standard Systemaufforderung für alle KI-Interaktionen",
|
|
||||||
"openai_configuration": "OpenAI Konfiguration",
|
|
||||||
"openai_settings": "OpenAI Einstellungen",
|
|
||||||
"api_key": "API Schlüssel",
|
|
||||||
"url": "Basis-URL",
|
|
||||||
"model": "Modell",
|
|
||||||
"anthropic_settings": "Anthropic Einstellungen",
|
|
||||||
"partial": "{{ percentage }}% verarbeitet",
|
|
||||||
"anthropic_api_key_description": "Dein Anthropic API-Key für den Zugriff auf Claude Modelle",
|
|
||||||
"anthropic_model_description": "Anthropic Claude Modell für Chat-Vervollständigung",
|
|
||||||
"voyage_settings": "Einstellungen für Voyage AI",
|
|
||||||
"ollama_url_description": "URL für die Ollama API (Standard: http://localhost:11434)",
|
|
||||||
"ollama_model_description": "Ollama Modell für Chat-Vervollständigung",
|
|
||||||
"anthropic_configuration": "Anthropic Konfiguration",
|
|
||||||
"voyage_configuration": "Voyage AI Konfiguration",
|
|
||||||
"voyage_url_description": "Standard: https://api.voyageai.com/v1",
|
|
||||||
"ollama_configuration": "Ollama Konfiguration",
|
|
||||||
"enable_ollama": "Aktiviere Ollama",
|
|
||||||
"enable_ollama_description": "Aktiviere Ollama für lokale KI Modell Nutzung",
|
|
||||||
"ollama_url": "Ollama URL",
|
|
||||||
"ollama_model": "Ollama Modell",
|
|
||||||
"refresh_models": "Aktualisiere Modelle",
|
|
||||||
"refreshing_models": "Aktualisiere...",
|
|
||||||
"enable_automatic_indexing": "Aktiviere automatische Indizierung",
|
|
||||||
"rebuild_index": "Index neu aufbauen",
|
|
||||||
"rebuild_index_error": "Fehler beim Neuaufbau des Index. Prüfe Log für mehr Informationen.",
|
|
||||||
"retry_failed": "Fehler: Notiz konnte nicht erneut eingereiht werden",
|
|
||||||
"max_notes_per_llm_query": "Max. Notizen je Abfrage",
|
|
||||||
"max_notes_per_llm_query_description": "Maximale Anzahl ähnlicher Notizen zum Einbinden als KI Kontext",
|
|
||||||
"active_providers": "Aktive Anbieter",
|
|
||||||
"disabled_providers": "Inaktive Anbieter",
|
|
||||||
"remove_provider": "Entferne Anbieter von Suche",
|
|
||||||
"restore_provider": "Anbieter zur Suche wiederherstellen",
|
|
||||||
"similarity_threshold": "Ähnlichkeitsschwelle",
|
|
||||||
"similarity_threshold_description": "Mindestähnlichkeitswert (0-1) für Notizen, die im Kontext für LLM-Abfragen berücksichtigt werden sollen",
|
|
||||||
"reprocess_index": "Suchindex neu erstellen",
|
|
||||||
"reprocessing_index": "Neuerstellung...",
|
|
||||||
"reprocess_index_started": "Suchindex-Optimierung wurde im Hintergrund gestartet",
|
|
||||||
"reprocess_index_error": "Fehler beim Wiederaufbau des Suchindex",
|
|
||||||
"index_rebuild_progress": "Fortschritt der Index-Neuerstellung",
|
|
||||||
"index_rebuilding": "Optimierung Index ({{percentage}}%)",
|
|
||||||
"index_rebuild_complete": "Index Optimierung abgeschlossen",
|
|
||||||
"index_rebuild_status_error": "Fehler bei Überprüfung Status Index Neuerstellung",
|
|
||||||
"never": "Niemals",
|
|
||||||
"processing": "Verarbeitung ({{percentage}}%)",
|
|
||||||
"refreshing": "Aktualisiere...",
|
|
||||||
"incomplete": "Unvollständig ({{percentage}}%)",
|
|
||||||
"complete": "Abgeschlossen (100%)",
|
|
||||||
"auto_refresh_notice": "Auto-Aktualisierung alle {{seconds}} Sekunden",
|
|
||||||
"note_queued_for_retry": "Notiz in Warteschlange für erneuten Versuch hinzugefügt",
|
|
||||||
"failed_to_retry_note": "Wiederholungsversuch fehlgeschlagen für Notiz",
|
|
||||||
"ai_settings": "KI Einstellungen",
|
|
||||||
"agent": {
|
|
||||||
"processing": "Verarbeite...",
|
|
||||||
"thinking": "Nachdenken...",
|
|
||||||
"loading": "Lade...",
|
|
||||||
"generating": "Generiere..."
|
|
||||||
},
|
|
||||||
"name": "KI",
|
|
||||||
"openai": "OpenAI",
|
|
||||||
"use_enhanced_context": "Benutze verbesserten Kontext",
|
|
||||||
"openai_api_key_description": "Dein OpenAPI-Key für den Zugriff auf den KI-Dienst",
|
|
||||||
"default_model": "Standardmodell",
|
|
||||||
"openai_model_description": "Beispiele: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
|
|
||||||
"base_url": "Basis URL",
|
|
||||||
"openai_url_description": "Standard: https://api.openai.com/v1",
|
|
||||||
"anthropic_url_description": "Basis URL für Anthropic API (Standard: https://api.anthropic.com)",
|
|
||||||
"ollama_settings": "Ollama Einstellungen",
|
|
||||||
"note_title": "Notiz Titel",
|
|
||||||
"error": "Fehler",
|
|
||||||
"last_attempt": "Letzter Versuch",
|
|
||||||
"actions": "Aktionen",
|
|
||||||
"retry": "Erneut versuchen",
|
|
||||||
"retry_queued": "Notiz für weiteren Versuch eingereiht",
|
|
||||||
"empty_key_warning": {
|
|
||||||
"anthropic": "Anthropic API-Key ist leer. Bitte gültigen API-Key eingeben.",
|
|
||||||
"openai": "OpenAI API-Key ist leer. Bitte gültigen API-Key eingeben.",
|
|
||||||
"voyage": "Voyage API-Key ist leer. Bitte gültigen API-Key eingeben.",
|
|
||||||
"ollama": "Ollama API-Key ist leer. Bitte gültigen API-Key eingeben."
|
|
||||||
},
|
|
||||||
"api_key_tooltip": "API-Key für den Zugriff auf den Dienst",
|
|
||||||
"failed_to_retry_all": "Wiederholungsversuch für Notizen fehlgeschlagen",
|
|
||||||
"all_notes_queued_for_retry": "Alle fehlgeschlagenen Notizen wurden zur Wiederholung in die Warteschlange gestellt",
|
|
||||||
"enhanced_context_description": "Versorgt die KI mit mehr Kontext aus der Notiz und den zugehörigen Notizen, um bessere Antworten zu ermöglichen",
|
|
||||||
"show_thinking": "Zeige Denkprozess",
|
|
||||||
"show_thinking_description": "Zeige den Denkprozess der KI",
|
|
||||||
"enter_message": "Geben Sie Ihre Nachricht ein...",
|
|
||||||
"error_contacting_provider": "Fehler beim Kontaktieren des KI-Anbieters. Bitte überprüfe die Einstellungen und die Internetverbindung.",
|
|
||||||
"error_generating_response": "Fehler beim Generieren der KI Antwort",
|
|
||||||
"index_all_notes": "Indiziere alle Notizen",
|
|
||||||
"index_status": "Indizierungsstatus",
|
|
||||||
"indexed_notes": "Indizierte Notizen",
|
|
||||||
"indexing_stopped": "Indizierung gestoppt",
|
|
||||||
"indexing_in_progress": "Indizierung in Bearbeitung...",
|
|
||||||
"last_indexed": "Zuletzt Indiziert",
|
|
||||||
"note_chat": "Notizen-Chat",
|
|
||||||
"sources": "Quellen",
|
|
||||||
"start_indexing": "Starte Indizierung",
|
|
||||||
"use_advanced_context": "Benutze erweiterten Kontext",
|
|
||||||
"ollama_no_url": "Ollama ist nicht konfiguriert. Bitte trage eine gültige URL ein.",
|
|
||||||
"chat": {
|
|
||||||
"root_note_title": "KI Chats",
|
|
||||||
"root_note_content": "Diese Notiz enthält gespeicherte KI-Chat-Unterhaltungen.",
|
|
||||||
"new_chat_title": "Neuer Chat",
|
|
||||||
"create_new_ai_chat": "Erstelle neuen KI Chat"
|
|
||||||
},
|
|
||||||
"create_new_ai_chat": "Erstelle neuen KI Chat",
|
|
||||||
"configuration_warnings": "Es wurden Probleme mit der KI Konfiguration festgestellt. Bitte überprüfe die Einstellungen.",
|
|
||||||
"experimental_warning": "Die LLM-Funktionen sind aktuell experimentell - sei an dieser Stelle gewarnt.",
|
|
||||||
"selected_provider": "Ausgewählter Anbieter",
|
|
||||||
"selected_provider_description": "Wähle einen KI-Anbieter für Chat- und Vervollständigungsfunktionen",
|
|
||||||
"select_model": "Wähle Modell...",
|
|
||||||
"select_provider": "Wähle Anbieter...",
|
|
||||||
"ai_enabled": "KI Funktionen aktiviert",
|
|
||||||
"ai_disabled": "KI Funktionen deaktiviert",
|
|
||||||
"no_models_found_online": "Keine Modelle gefunden. Bitte überprüfe den API-Key und die Einstellungen.",
|
|
||||||
"no_models_found_ollama": "Kein Ollama Modell gefunden. Bitte prüfe, ob Ollama gerade läuft.",
|
|
||||||
"error_fetching": "Fehler beim Abrufen der Modelle: {{error}}"
|
|
||||||
},
|
|
||||||
"zen_mode": {
|
"zen_mode": {
|
||||||
"button_exit": "Verlasse Zen Modus"
|
"button_exit": "Verlasse Zen Modus"
|
||||||
},
|
},
|
||||||
@@ -1968,7 +1831,7 @@
|
|||||||
"no_totp_secret_warning": "Um TOTP zu aktivieren, muss zunächst ein TOTP Geheimnis generiert werden.",
|
"no_totp_secret_warning": "Um TOTP zu aktivieren, muss zunächst ein TOTP Geheimnis generiert werden.",
|
||||||
"totp_secret_description_warning": "Nach der Generierung des TOTP Geheimnisses ist eine Neuanmeldung mit dem TOTP Geheimnis erforderlich.",
|
"totp_secret_description_warning": "Nach der Generierung des TOTP Geheimnisses ist eine Neuanmeldung mit dem TOTP Geheimnis erforderlich.",
|
||||||
"totp_secret_generated": "TOTP Geheimnis generiert",
|
"totp_secret_generated": "TOTP Geheimnis generiert",
|
||||||
"totp_secret_warning": "Bitte speichere das TOTP Geheimnis an einem sicheren Ort. Es wird nicht noch einmal angezeigt.",
|
"totp_secret_warning": "Bitte speichere das generierte Geheimnis an einem sicheren Ort. Es wird nicht noch einmal angezeigt.",
|
||||||
"totp_secret_regenerate_confirm": "Möchten Sie das TOTP-Geheimnis wirklich neu generieren? Dadurch werden das bisherige TOTP-Geheimnis und alle vorhandenen Wiederherstellungscodes ungültig.",
|
"totp_secret_regenerate_confirm": "Möchten Sie das TOTP-Geheimnis wirklich neu generieren? Dadurch werden das bisherige TOTP-Geheimnis und alle vorhandenen Wiederherstellungscodes ungültig.",
|
||||||
"recovery_keys_title": "Einmalige Wiederherstellungsschlüssel",
|
"recovery_keys_title": "Einmalige Wiederherstellungsschlüssel",
|
||||||
"recovery_keys_description": "Einmalige Wiederherstellungsschlüssel werden verwendet, um sich anzumelden, falls Sie keinen Zugriff auf Ihre Authentifizierungscodes haben.",
|
"recovery_keys_description": "Einmalige Wiederherstellungsschlüssel werden verwendet, um sich anzumelden, falls Sie keinen Zugriff auf Ihre Authentifizierungscodes haben.",
|
||||||
@@ -1996,7 +1859,7 @@
|
|||||||
"check_share_root": "Status des Freigabe-Roots prüfen",
|
"check_share_root": "Status des Freigabe-Roots prüfen",
|
||||||
"share_root_found": "Freigabe-Root-Notiz '{{noteTitle}}' ist bereit",
|
"share_root_found": "Freigabe-Root-Notiz '{{noteTitle}}' ist bereit",
|
||||||
"share_root_not_found": "Keine Notiz mit #shareRoot Label gefunden",
|
"share_root_not_found": "Keine Notiz mit #shareRoot Label gefunden",
|
||||||
"share_root_not_shared": "Notiz '{{noteTitle}}' hat das #shareRoot Label, wurde jedoch noch nicht geteilt"
|
"share_root_not_shared": "Notiz '{{noteTitle}}' hat das #shareRoot Label, wurde jedoch noch nicht freigegeben"
|
||||||
},
|
},
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"due": {
|
"due": {
|
||||||
@@ -2066,7 +1929,7 @@
|
|||||||
"show-hide-columns": "Zeige/verberge Spalten",
|
"show-hide-columns": "Zeige/verberge Spalten",
|
||||||
"row-insert-above": "Zeile oberhalb einfügen",
|
"row-insert-above": "Zeile oberhalb einfügen",
|
||||||
"row-insert-below": "Zeile unterhalb einfügen",
|
"row-insert-below": "Zeile unterhalb einfügen",
|
||||||
"row-insert-child": "Unternotiz einfügen",
|
"row-insert-child": "Untergeordnete Notiz einfügen",
|
||||||
"add-column-to-the-left": "Spalte links einfügen",
|
"add-column-to-the-left": "Spalte links einfügen",
|
||||||
"add-column-to-the-right": "Spalte rechts einfügen",
|
"add-column-to-the-right": "Spalte rechts einfügen",
|
||||||
"edit-column": "Spalte editieren",
|
"edit-column": "Spalte editieren",
|
||||||
@@ -2083,7 +1946,8 @@
|
|||||||
"raster": "Raster",
|
"raster": "Raster",
|
||||||
"vector_light": "Vektor (Hell)",
|
"vector_light": "Vektor (Hell)",
|
||||||
"vector_dark": "Vektor (Dunkel)",
|
"vector_dark": "Vektor (Dunkel)",
|
||||||
"show-scale": "Zeige Skalierung"
|
"show-scale": "Zeige Skalierung",
|
||||||
|
"show-labels": "Zeige Markierungsnamen"
|
||||||
},
|
},
|
||||||
"table_context_menu": {
|
"table_context_menu": {
|
||||||
"delete_row": "Zeile entfernen"
|
"delete_row": "Zeile entfernen"
|
||||||
@@ -2114,8 +1978,8 @@
|
|||||||
"show_attachments_description": "Notizanhänge anzeigen",
|
"show_attachments_description": "Notizanhänge anzeigen",
|
||||||
"search_notes_title": "Suche Notiz",
|
"search_notes_title": "Suche Notiz",
|
||||||
"search_notes_description": "Öffne erweiterte Suche",
|
"search_notes_description": "Öffne erweiterte Suche",
|
||||||
"search_subtree_title": "Im Unterzweig suchen",
|
"search_subtree_title": "Im Zweig suchen",
|
||||||
"search_subtree_description": "Im aktuellen Unterzweig suchen",
|
"search_subtree_description": "Im aktuellen Zweig suchen",
|
||||||
"search_history_title": "Zeige Suchhistorie",
|
"search_history_title": "Zeige Suchhistorie",
|
||||||
"search_history_description": "Zeige vorherige Suchen",
|
"search_history_description": "Zeige vorherige Suchen",
|
||||||
"configure_launch_bar_title": "Startleiste anpassen",
|
"configure_launch_bar_title": "Startleiste anpassen",
|
||||||
@@ -2129,7 +1993,7 @@
|
|||||||
"next_theme_message": "Es wird aktuell das alte Design verwendet. Möchten Sie das neue Design ausprobieren?",
|
"next_theme_message": "Es wird aktuell das alte Design verwendet. Möchten Sie das neue Design ausprobieren?",
|
||||||
"next_theme_button": "Teste das neue Design",
|
"next_theme_button": "Teste das neue Design",
|
||||||
"background_effects_title": "Hintergrundeffekte sind jetzt zuverlässig nutzbar",
|
"background_effects_title": "Hintergrundeffekte sind jetzt zuverlässig nutzbar",
|
||||||
"background_effects_message": "Auf Windows-Geräten sind die Hintergrundeffekte nun vollständig stabil. Die Hintergrundeffekte verleihen der Benutzeroberfläche einen Farbakzent, indem der Hintergrund dahinter weichgezeichnet wird. Diese Technik wird auch in anderen Anwendungen wie dem Windows-Explorer eingesetzt.",
|
"background_effects_message": "Auf Windows- und macOS-Geräten sind die Hintergrundeffekte nun stabil. Die Hintergrundeffekte verleihen der Benutzeroberfläche einen Farbakzent, indem der Hintergrund dahinter weichgezeichnet wird.",
|
||||||
"background_effects_button": "Aktiviere Hintergrundeffekte",
|
"background_effects_button": "Aktiviere Hintergrundeffekte",
|
||||||
"dismiss": "Ablehnen",
|
"dismiss": "Ablehnen",
|
||||||
"new_layout_title": "Neues Layout",
|
"new_layout_title": "Neues Layout",
|
||||||
@@ -2150,8 +2014,9 @@
|
|||||||
"percentage": "%"
|
"percentage": "%"
|
||||||
},
|
},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"page_title": "Seite {{startIndex}} von {{endIndex}}",
|
"total_notes": "{{count}} Notizen",
|
||||||
"total_notes": "{{count}} Notizen"
|
"prev_page": "Vorherige Seite",
|
||||||
|
"next_page": "Nächste Seite"
|
||||||
},
|
},
|
||||||
"collections": {
|
"collections": {
|
||||||
"rendering_error": "Aufgrund eines Fehlers können keine Inhalte angezeigt werden."
|
"rendering_error": "Aufgrund eines Fehlers können keine Inhalte angezeigt werden."
|
||||||
@@ -2184,9 +2049,9 @@
|
|||||||
"new_layout_description": "Probiere das neue Layout für eine modernere Darstellung und verbesserte Benutzbarkeit aus. Kann sich in Zukunft stark ändern."
|
"new_layout_description": "Probiere das neue Layout für eine modernere Darstellung und verbesserte Benutzbarkeit aus. Kann sich in Zukunft stark ändern."
|
||||||
},
|
},
|
||||||
"server": {
|
"server": {
|
||||||
"unknown_http_error_title": "Bei der Kommunikation mit dem Server ist ein Fehler aufgetreten",
|
"unknown_http_error_title": "Kommunikationsfehler mit dem Server",
|
||||||
"unknown_http_error_content": "Statuscode: {{statusCode}}\nURL: {{method}} {{url}}\nNachricht: {{message}}",
|
"unknown_http_error_content": "Statuscode: {{statusCode}}\nURL: {{method}} {{url}}\nNachricht: {{message}}",
|
||||||
"traefik_blocks_requests": "Der Traefik Reverse-Proxy hat ein fatales Update bekommen, welche die Kommunikation mit dem Server stört."
|
"traefik_blocks_requests": "Der Traefik Reverse-Proxy hat eine Änderung erfahren, welches die Kommunikation mit dem Server beeinflusst."
|
||||||
},
|
},
|
||||||
"tab_history_navigation_buttons": {
|
"tab_history_navigation_buttons": {
|
||||||
"go-back": "Zur vorherigen Notiz zurück kehren",
|
"go-back": "Zur vorherigen Notiz zurück kehren",
|
||||||
@@ -2197,34 +2062,34 @@
|
|||||||
"hoisted_badge_title": "Abgesenkt",
|
"hoisted_badge_title": "Abgesenkt",
|
||||||
"workspace_badge": "Arbeitsfläche",
|
"workspace_badge": "Arbeitsfläche",
|
||||||
"scroll_to_top_title": "Zum Anfang der Notiz springen",
|
"scroll_to_top_title": "Zum Anfang der Notiz springen",
|
||||||
"create_new_note": "Neue Unternotiz erstellen",
|
"create_new_note": "Neue untergeordnete Notiz erstellen",
|
||||||
"empty_hide_archived_notes": "Archivierte Notizen ausblenden"
|
"empty_hide_archived_notes": "Archivierte Notizen ausblenden"
|
||||||
},
|
},
|
||||||
"breadcrumb_badges": {
|
"breadcrumb_badges": {
|
||||||
"read_only_explicit": "Nicht Änderbar",
|
"read_only_explicit": "Schreibgeschützt",
|
||||||
"read_only_explicit_description": "Diese Notiz wurde händisch als nicht änderbar markiert.\nKlicke hier um sie temporär zu bearbeiten.",
|
"read_only_explicit_description": "Diese Notiz wurde händisch schreibgeschützt.\nKlicke hier um sie temporär zu bearbeiten.",
|
||||||
"read_only_auto": "Automatisch nicht änderbar",
|
"read_only_auto": "Automatisch schreibgeschützt",
|
||||||
"read_only_auto_description": "Diese Notiz wurde automatisch aus Leistungsgründen als nicht änderbar markiert. Dieses automatische Limit kann in den Einstellungen angepasst werden.\n\nKlicke hier, um sie temporär zu bearbeiten.",
|
"read_only_auto_description": "Diese Notiz wurde automatisch aus Leistungsgründen als schreibgeschützt markiert. Dieses automatische Limit kann in den Einstellungen angepasst werden.\n\nKlicke hier, um sie temporär zu bearbeiten.",
|
||||||
"read_only_temporarily_disabled": "Temporär bearbeitbar",
|
"read_only_temporarily_disabled": "Temporär bearbeitbar",
|
||||||
"read_only_temporarily_disabled_description": "Diese Notiz ist aktuell bearbeitbar, ist aber normalerweise nicht änderbar. Sobald du zu einer anderen Notiz navigierst, kehrt diese Notiz in ihren Normalzustand zurück.\n\nKlicke hier, um die Notiz wieder nicht änderbar zu machen.",
|
"read_only_temporarily_disabled_description": "Diese Notiz ist aktuell bearbeitbar, ist aber normalerweise schreibgeschützt. Sobald du zu einer anderen Notiz navigierst wird diese wieder schreibgeschützt.\n\nKlicke hier, um die Notiz wieder schreibgeschützt zu machen.",
|
||||||
"shared_publicly": "Öffentlich geteilt",
|
"shared_publicly": "Öffentlich freigegeben",
|
||||||
"shared_locally": "Lokal geteilt",
|
"shared_locally": "Lokal freigegeben",
|
||||||
"shared_copy_to_clipboard": "Link in die Zwischenablage kopieren",
|
"shared_copy_to_clipboard": "Link in die Zwischenablage kopieren",
|
||||||
"shared_open_in_browser": "Link öffnen",
|
"shared_open_in_browser": "Link im Browser öffnen",
|
||||||
"shared_unshare": "Teilen aufheben",
|
"shared_unshare": "Freigabe aufheben",
|
||||||
"clipped_note": "Internetschnellverweis",
|
"clipped_note": "Internetschnellverweis",
|
||||||
"clipped_note_description": "Diese Notiz wurde von {{url}} übernommen.\n\nKlicke hier, um zum Ursprung zu gehen.",
|
"clipped_note_description": "Diese Notiz wurde von {{url}} übernommen.\n\nKlicke hier, um zur Quelle zu gehen.",
|
||||||
"execute_script": "Skript ausführen",
|
"execute_script": "Skript ausführen",
|
||||||
"execute_script_description": "Diese Notiz ist eine Skriptnotiz. Klicke hier, um das Skript auszuführen.",
|
"execute_script_description": "Diese Notiz ist eine Skriptnotiz. Klicke hier, um das Skript auszuführen.",
|
||||||
"execute_sql": "SQL ausführen",
|
"execute_sql": "SQL ausführen",
|
||||||
"execute_sql_description": "Diese Notiz ist eine SQL-Notiz. Klicke hier, um die SQL-Abfrage auszuführen.",
|
"execute_sql_description": "Diese Notiz ist eine SQL-Notiz. Klicke hier, um die SQL-Abfrage auszuführen.",
|
||||||
"save_status_saved": "Gespeichert",
|
"save_status_saved": "Gespeichert",
|
||||||
"save_status_saving": "Speichern...",
|
"save_status_saving": "Speichere...",
|
||||||
"save_status_unsaved": "Nicht gespeichert",
|
"save_status_unsaved": "Nicht gespeichert",
|
||||||
"save_status_error": "Speichern fehlgeschlagen",
|
"save_status_error": "Speichern fehlgeschlagen",
|
||||||
"save_status_saving_tooltip": "Änderungen werden gespeichert.",
|
"save_status_saving_tooltip": "Änderungen werden gespeichert.",
|
||||||
"save_status_unsaved_tooltip": "Es gibt ungespeicherte Änderungen, welche gleich automatisch gespeichert werden.",
|
"save_status_unsaved_tooltip": "Es gibt ungespeicherte Änderungen, welche gleich automatisch gespeichert werden.",
|
||||||
"save_status_error_tooltip": "Beim speichern der Notiz ist ein Fehler aufgetreten. Wenn möglich, versuche die Notiz woandershin zu kopieren und die Applikation neu zu laden."
|
"save_status_error_tooltip": "Beim speichern der Notiz ist ein Fehler aufgetreten. Wenn möglich, versuche die Notiz woandershin zu kopieren und die Anwendung neu zu laden."
|
||||||
},
|
},
|
||||||
"status_bar": {
|
"status_bar": {
|
||||||
"language_title": "Inhaltssprache ändern",
|
"language_title": "Inhaltssprache ändern",
|
||||||
@@ -2237,22 +2102,22 @@
|
|||||||
"attachments_other": "{{count}} Anhänge",
|
"attachments_other": "{{count}} Anhänge",
|
||||||
"attachments_title_one": "Anhang in einem neuen Tab öffnen",
|
"attachments_title_one": "Anhang in einem neuen Tab öffnen",
|
||||||
"attachments_title_other": "Anhänge in einem neuen Tab öffnen",
|
"attachments_title_other": "Anhänge in einem neuen Tab öffnen",
|
||||||
"attributes_one": "{{count}} Eigenschaft",
|
"attributes_one": "{{count}} Attribut",
|
||||||
"attributes_other": "{{count}} Eigenschaften",
|
"attributes_other": "{{count}} Attribute",
|
||||||
"attributes_title": "Eigene und gererbte Eigenschaften",
|
"attributes_title": "Eigene und geerbte Attribute",
|
||||||
"note_paths_one": "{{count}} Pfad",
|
"note_paths_one": "{{count}} Pfad",
|
||||||
"note_paths_other": "{{count}} Pfade",
|
"note_paths_other": "{{count}} Pfade",
|
||||||
"note_paths_title": "Notizpfade",
|
"note_paths_title": "Notizpfade",
|
||||||
"code_note_switcher": "Sprachmodus ändern"
|
"code_note_switcher": "Sprachmodus ändern"
|
||||||
},
|
},
|
||||||
"attributes_panel": {
|
"attributes_panel": {
|
||||||
"title": "Notizeigenschaften"
|
"title": "Notizattribute"
|
||||||
},
|
},
|
||||||
"right_pane": {
|
"right_pane": {
|
||||||
"empty_message": "Für diese Notiz gibt es nichts anzuzeigen",
|
"empty_message": "Für diese Notiz gibt es nichts anzuzeigen",
|
||||||
"empty_button": "Anzeige ausblenden",
|
"empty_button": "Leiste ausblenden",
|
||||||
"toggle": "Rechte Anzeige umschalten",
|
"toggle": "Rechte Leiste umschalten",
|
||||||
"custom_widget_go_to_source": "Zum Ursprungscode"
|
"custom_widget_go_to_source": "Zum Quellcode"
|
||||||
},
|
},
|
||||||
"pdf": {
|
"pdf": {
|
||||||
"attachments_one": "{{count}} Anhang",
|
"attachments_one": "{{count}} Anhang",
|
||||||
@@ -2262,6 +2127,108 @@
|
|||||||
"pages_one": "{{count}} Seite",
|
"pages_one": "{{count}} Seite",
|
||||||
"pages_other": "{{count}} Seiten",
|
"pages_other": "{{count}} Seiten",
|
||||||
"pages_alt": "Seite {{pageNumber}}",
|
"pages_alt": "Seite {{pageNumber}}",
|
||||||
"pages_loading": "Laden..."
|
"pages_loading": "Lädt..."
|
||||||
|
},
|
||||||
|
"platform_indicator": {
|
||||||
|
"available_on": "Verfügbar auf {{platform}}"
|
||||||
|
},
|
||||||
|
"mobile_tab_switcher": {
|
||||||
|
"title_one": "{{count}} Tab",
|
||||||
|
"title_other": "{{count}} Tabs",
|
||||||
|
"more_options": "Weitere Optionen"
|
||||||
|
},
|
||||||
|
"bookmark_buttons": {
|
||||||
|
"bookmarks": "Lesezeichen"
|
||||||
|
},
|
||||||
|
"web_view_setup": {
|
||||||
|
"title": "Erstelle eine Live-Ansicht einer Webseite direkt in Trilium",
|
||||||
|
"url_placeholder": "Gib oder füge die Adresse der Webseite ein, zum Beispiel https://triliumnotes.org",
|
||||||
|
"create_button": "Erstelle Web Ansicht",
|
||||||
|
"invalid_url_title": "Ungültige Adresse",
|
||||||
|
"invalid_url_message": "Füge eine valide Webadresse ein, zum Beispiel https://triliumnotes.org.",
|
||||||
|
"disabled_description": "Diese Webansicht wurde von einer externen Quelle importiert. Um Sie vor Phishing oder schädlichen Inhalten zu schützen, wird sie nicht automatisch geladen. Sie können sie aktivieren, wenn Sie der Quelle vertrauen.",
|
||||||
|
"disabled_button_enable": "Webansicht aktivieren"
|
||||||
|
},
|
||||||
|
"render": {
|
||||||
|
"setup_create_sample_html": "Eine Beispielnotiz mit HTML erstellen",
|
||||||
|
"setup_create_sample_preact": "Eine Beispielnotiz mit Preact erstellen",
|
||||||
|
"setup_title": "Benutzerdefiniertes HTML oder Preact JSX in dieser Notiz anzeigen",
|
||||||
|
"setup_sample_created": "Eine Beispielnotiz wurde als untergeordnete Notiz erstellt.",
|
||||||
|
"disabled_description": "Diese Rendering-Notizen stammen aus einer externen Quelle. Um Sie vor schädlichen Inhalten zu schützen, ist diese Funktion standardmäßig deaktiviert. Stellen Sie sicher, dass Sie der Quelle vertrauen, bevor Sie sie aktivieren.",
|
||||||
|
"disabled_button_enable": "Rendering-Notiz aktivieren"
|
||||||
|
},
|
||||||
|
"active_content_badges": {
|
||||||
|
"type_icon_pack": "Icon-Paket",
|
||||||
|
"type_backend_script": "Backend-Skript",
|
||||||
|
"type_frontend_script": "Frontend-Skript",
|
||||||
|
"type_widget": "Widget",
|
||||||
|
"type_app_css": "Benutzerdefiniertes CSS",
|
||||||
|
"type_render_note": "Rendering-Notiz",
|
||||||
|
"type_web_view": "Webansicht",
|
||||||
|
"type_app_theme": "Benutzerdefiniertes Thema",
|
||||||
|
"toggle_tooltip_enable_tooltip": "Klicken, um diesen {{type}} zu aktivieren.",
|
||||||
|
"toggle_tooltip_disable_tooltip": "Klicken, um diesen {{type}} zu deaktivieren.",
|
||||||
|
"menu_docs": "Dokumentation öffnen",
|
||||||
|
"menu_execute_now": "Skript jetzt ausführen",
|
||||||
|
"menu_run": "Automatisch ausführen",
|
||||||
|
"menu_run_disabled": "Manuell",
|
||||||
|
"menu_run_backend_startup": "Wenn das Backend startet",
|
||||||
|
"menu_run_hourly": "Stündlich",
|
||||||
|
"menu_run_daily": "Täglich",
|
||||||
|
"menu_run_frontend_startup": "Wenn das Desktop-Frontend startet",
|
||||||
|
"menu_run_mobile_startup": "Wenn das mobile Frontend startet",
|
||||||
|
"menu_change_to_widget": "Zum Widget wechseln",
|
||||||
|
"menu_change_to_frontend_script": "Zum Frontend-Skript wechseln",
|
||||||
|
"menu_theme_base": "Themenbasis"
|
||||||
|
},
|
||||||
|
"setup_form": {
|
||||||
|
"more_info": "Mehr erfahren"
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"play": "Abspielen (Arbeitsbereich)",
|
||||||
|
"pause": "Pausieren (Arbeitsbereich)",
|
||||||
|
"back-10s": "10 s zurück (Linke Pfeiltaste)",
|
||||||
|
"forward-30s": "30 s vorwärts",
|
||||||
|
"mute": "Stumm (M)",
|
||||||
|
"unmute": "Stummschaltung aufheben (M)",
|
||||||
|
"playback-speed": "Wiedergabegeschwindigkeit",
|
||||||
|
"loop": "Schleife",
|
||||||
|
"disable-loop": "Schleife deaktivieren",
|
||||||
|
"rotate": "Rotieren",
|
||||||
|
"picture-in-picture": "Bild-in-Bild",
|
||||||
|
"exit-picture-in-picture": "Bild-in-Bild verlassen",
|
||||||
|
"fullscreen": "Vollbild (F)",
|
||||||
|
"exit-fullscreen": "Vollbild verlassen",
|
||||||
|
"unsupported-format": "Medienvorschau ist für dieses Format nicht verfügbar:\n{{mime}}",
|
||||||
|
"zoom-to-fit": "Zoomen um auszufüllen",
|
||||||
|
"zoom-reset": "Zoomen um auszufüllen zurücksetzen"
|
||||||
|
},
|
||||||
|
"mermaid": {
|
||||||
|
"placeholder": "Geben den Inhalt des Mermaid-Diagramms ein oder verwenden eine der folgenden Beispieldiagramme.",
|
||||||
|
"sample_diagrams": "Beispieldiagramme:",
|
||||||
|
"sample_flowchart": "Flussdiagramm",
|
||||||
|
"sample_class": "Klasse",
|
||||||
|
"sample_sequence": "Abfolge",
|
||||||
|
"sample_entity_relationship": "Entität Beziehung",
|
||||||
|
"sample_state": "Zustandsübergangsdiagramm",
|
||||||
|
"sample_mindmap": "Mindmap",
|
||||||
|
"sample_architecture": "Architektur",
|
||||||
|
"sample_block": "Block",
|
||||||
|
"sample_c4": "C4",
|
||||||
|
"sample_gantt": "Gantt",
|
||||||
|
"sample_git": "GitGraph",
|
||||||
|
"sample_kanban": "Kanban",
|
||||||
|
"sample_packet": "Paket",
|
||||||
|
"sample_pie": "Kuchen",
|
||||||
|
"sample_quadrant": "Quadrant",
|
||||||
|
"sample_radar": "Radar",
|
||||||
|
"sample_requirement": "Anforderung",
|
||||||
|
"sample_sankey": "Sankey",
|
||||||
|
"sample_timeline": "Zeitstrahl",
|
||||||
|
"sample_treemap": "Kachel",
|
||||||
|
"sample_user_journey": "Benutzererfahrung",
|
||||||
|
"sample_xy": "XY",
|
||||||
|
"sample_venn": "Mengen",
|
||||||
|
"sample_ishikawa": "Ursache-Wirkung"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"about": {
|
"about": {
|
||||||
"title": "Πληροφορίες για το Trilium Notes",
|
"title": "Σχετικά με το Trilium Notes",
|
||||||
"homepage": "Αρχική Σελίδα:",
|
"homepage": "Αρχική Σελίδα:",
|
||||||
"app_version": "Έκδοση εφαρμογής:",
|
"app_version": "Έκδοση εφαρμογής:",
|
||||||
"db_version": "Έκδοση βάσης δεδομένων:",
|
"db_version": "Έκδοση βάσης δεδομένων:",
|
||||||
@@ -13,6 +13,61 @@
|
|||||||
"critical-error": {
|
"critical-error": {
|
||||||
"title": "Κρίσιμο σφάλμα",
|
"title": "Κρίσιμο σφάλμα",
|
||||||
"message": "Συνέβη κάποιο κρίσιμο σφάλμα, το οποίο δεν επιτρέπει στην εφαρμογή χρήστη να ξεκινήσει:\n\n{{message}}\n\nΤο πιθανότερο είναι να προκλήθηκε από κάποιο script που απέτυχε απρόοπτα. Δοκιμάστε να ξεκινήσετε την εφαρμογή σε ασφαλή λειτουργία για να λύσετε το πρόβλημα."
|
"message": "Συνέβη κάποιο κρίσιμο σφάλμα, το οποίο δεν επιτρέπει στην εφαρμογή χρήστη να ξεκινήσει:\n\n{{message}}\n\nΤο πιθανότερο είναι να προκλήθηκε από κάποιο script που απέτυχε απρόοπτα. Δοκιμάστε να ξεκινήσετε την εφαρμογή σε ασφαλή λειτουργία για να λύσετε το πρόβλημα."
|
||||||
}
|
},
|
||||||
|
"widget-error": {
|
||||||
|
"title": "Δεν ήταν δυνατή η αρχικοποίηση του widget",
|
||||||
|
"message-custom": "Προσαρμοσμένο widget της σημείωσης με ID \"{{id}}\", με τίτλο \"{{title}}\", δεν ήταν δυνατό να αρχικοποιηθεί λόγω:\n\n{{message}}",
|
||||||
|
"message-unknown": "Άγνωστο widget δεν ήταν δυνατό να αρχικοποιηθεί λόγω:\n\n{{message}}"
|
||||||
|
},
|
||||||
|
"bundle-error": {
|
||||||
|
"title": "Δεν ήταν δυνατή η φόρτωση προσαρμοσμένου script",
|
||||||
|
"message": "Το script δεν ήταν δυνατό να εκτελεστεί λόγω:\n\n{{message}}"
|
||||||
|
},
|
||||||
|
"widget-list-error": {
|
||||||
|
"title": "Δεν ήταν δυνατή η λήψη της λίστας των widgets από τον server"
|
||||||
|
},
|
||||||
|
"widget-render-error": {
|
||||||
|
"title": "Δεν ήταν δυνατή η απόδοση προσαρμοσμένου React widget"
|
||||||
|
},
|
||||||
|
"widget-missing-parent": "Το προσαρμοσμένο widget δεν έχει ορισμένη την υποχρεωτική ιδιότητα '{{property}}'.\n\nΕάν το script προορίζεται για εκτέλεση χωρίς UI element, χρησιμοποιήστε '#run=frontendStartup' αντί για αυτό.",
|
||||||
|
"open-script-note": "Άνοιγμα σημείωσης script",
|
||||||
|
"scripting-error": "Σφάλμα προσαρμοσμένου script: {{title}}"
|
||||||
|
},
|
||||||
|
"bookmark_buttons": {
|
||||||
|
"bookmarks": "Σελιδοδείκτες"
|
||||||
|
},
|
||||||
|
"add_link": {
|
||||||
|
"add_link": "Προσθήκη συνδέσμου",
|
||||||
|
"help_on_links": "Βοήθεια για συνδέσμους",
|
||||||
|
"note": "Σημείωση",
|
||||||
|
"search_note": "Αναζήτηση σημείωσης με βάση το όνομά της",
|
||||||
|
"link_title_mirrors": "Ο τίτλος του συνδέσμου αντικατοπτρίζει τον τρέχοντα τίτλο της σημείωσης",
|
||||||
|
"link_title_arbitrary": "Ο τίτλος του συνδέσμου μπορεί να τροποποιηθεί ελεύθερα",
|
||||||
|
"link_title": "Τίτλος συνδέσμου",
|
||||||
|
"button_add_link": "Προσθήκη συνδέσμου"
|
||||||
|
},
|
||||||
|
"branch_prefix": {
|
||||||
|
"edit_branch_prefix": "Επεξεργασία προθέματος κλάδου",
|
||||||
|
"edit_branch_prefix_multiple": "Επεξεργασία προθέματος κλάδου για {{count}} κλάδους",
|
||||||
|
"help_on_tree_prefix": "Βοήθεια για πρόθεμα δέντρου",
|
||||||
|
"prefix": "Πρόθεμα: ",
|
||||||
|
"save": "Αποθήκευση",
|
||||||
|
"branch_prefix_saved": "Το πρόθεμα κλάδου αποθηκεύτηκε.",
|
||||||
|
"branch_prefix_saved_multiple": "Το πρόθεμα κλάδου αποθηκεύτηκε για {{count}} κλάδους.",
|
||||||
|
"affected_branches": "Επηρεαζόμενοι κλάδοι ({{count}}):"
|
||||||
|
},
|
||||||
|
"bulk_actions": {
|
||||||
|
"bulk_actions": "Μαζικές ενέργειες",
|
||||||
|
"affected_notes": "Επηρεαζόμενες σημειώσεις",
|
||||||
|
"include_descendants": "Συμπερίληψη απογόνων των επιλεγμένων σημειώσεων",
|
||||||
|
"available_actions": "Διαθέσιμες ενέργειες",
|
||||||
|
"chosen_actions": "Επιλεγμένες ενέργειες",
|
||||||
|
"execute_bulk_actions": "Εκτέλεση μαζικών ενεργειών",
|
||||||
|
"bulk_actions_executed": "Οι μαζικές ενέργειες εκτελέστηκαν επιτυχώς.",
|
||||||
|
"none_yet": "Καμία ακόμη… προσθέστε μια ενέργεια επιλέγοντας μία από τις διαθέσιμες παραπάνω.",
|
||||||
|
"labels": "Ετικέτες",
|
||||||
|
"relations": "Συσχετίσεις",
|
||||||
|
"notes": "Σημειώσεις",
|
||||||
|
"other": "Λοιπά"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user