mirror of
https://github.com/zadam/trilium.git
synced 2025-12-15 12:49:53 +01:00
Compare commits
834 Commits
migrate_pa
...
stable
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
982fb212e4 | ||
|
|
9fcee9cc53 | ||
|
|
d173cc982c | ||
|
|
471c57b3ed | ||
|
|
093d7d783b | ||
|
|
7cc20600e7 | ||
|
|
559c654fbb | ||
|
|
01a03e3e97 | ||
|
|
dd3233a556 | ||
|
|
c4a426566f | ||
|
|
c081a596df | ||
|
|
6b07908cf7 | ||
|
|
2985bd0a1c | ||
|
|
975e8487fc | ||
|
|
54408d3ec8 | ||
|
|
8b3afc1f49 | ||
|
|
e15bc5a232 | ||
|
|
8fdda59440 | ||
|
|
d5cbf362f8 | ||
|
|
6f85d3370c | ||
|
|
8c324cd185 | ||
|
|
f7f7fda040 | ||
|
|
74c11f4d4e | ||
|
|
0525cfab79 | ||
|
|
2d73627908 | ||
|
|
94d015789d | ||
|
|
af2f6246e8 | ||
|
|
ebbdf0294a | ||
|
|
5df539f0a4 | ||
|
|
4f6dfeb773 | ||
|
|
52bb83e878 | ||
|
|
286a8626d1 | ||
|
|
aa62dc3f32 | ||
|
|
045e7977d5 | ||
|
|
e0dc25ad23 | ||
|
|
9d0499a306 | ||
|
|
b971e002ce | ||
|
|
5fd488e210 | ||
|
|
eb84da4c51 | ||
|
|
49243148a2 | ||
|
|
276241cdff | ||
|
|
6772453b3a | ||
|
|
18e2f1f90c | ||
|
|
67d2175ce9 | ||
|
|
8a3283f1ea | ||
|
|
2fb47fc186 | ||
|
|
4530c9a40c | ||
|
|
a867a25d5f | ||
|
|
10910ac2ed | ||
|
|
514f5a0c81 | ||
|
|
6b18ed6477 | ||
|
|
e07b6cc409 | ||
|
|
5ae67fda7f | ||
|
|
1a03c0ca9f | ||
|
|
dc211b4d00 | ||
|
|
2e767ffde1 | ||
|
|
9f74a54c0d | ||
|
|
a7870495ac | ||
|
|
a8ec323ea8 | ||
|
|
4b7d243406 | ||
|
|
1855588270 | ||
|
|
e545e0c3a5 | ||
|
|
b24a0f1595 | ||
|
|
3f2bfc3050 | ||
|
|
66f100d534 | ||
|
|
e641d5ba0f | ||
|
|
6f8cebf954 | ||
|
|
2d2f2457cb | ||
|
|
68fa243af4 | ||
|
|
9cb133c8a6 | ||
|
|
33f6c75917 | ||
|
|
49acd5e8c2 | ||
|
|
85266adf20 | ||
|
|
27edea8380 | ||
|
|
dccddb8d43 | ||
|
|
5f9d7a223a | ||
|
|
29b71262d6 | ||
|
|
0cfcbcf5df | ||
|
|
e1258384d8 | ||
|
|
8837eddd40 | ||
|
|
f919d46e9a | ||
|
|
98094fac63 | ||
|
|
f94ccee252 | ||
|
|
7c4b338539 | ||
|
|
d88431f9e3 | ||
|
|
5f86068489 | ||
|
|
36bc226674 | ||
|
|
7947745218 | ||
|
|
19697aabfb | ||
|
|
87af23598d | ||
|
|
4ed7966a5a | ||
|
|
8d86b5c7e6 | ||
|
|
cdf9458962 | ||
|
|
83df37c2d1 | ||
|
|
bc7b3165c8 | ||
|
|
c332e9764a | ||
|
|
004d48d36c | ||
|
|
28b263a445 | ||
|
|
e0e9310907 | ||
|
|
68b9159b2b | ||
|
|
f5940cbf70 | ||
|
|
bfb143bb51 | ||
|
|
64662d5215 | ||
|
|
31cedad976 | ||
|
|
9682df6240 | ||
|
|
a718908385 | ||
|
|
12ac5147d3 | ||
|
|
17291ff61d | ||
|
|
f3e334470e | ||
|
|
9407051f1e | ||
|
|
08a6d36153 | ||
|
|
f906fb9b4c | ||
|
|
b4a6356724 | ||
|
|
8eca14069a | ||
|
|
1af0477ac0 | ||
|
|
43920f12ae | ||
|
|
5a0beec6cb | ||
|
|
98241fb54b | ||
|
|
3051664228 | ||
|
|
1ed774365c | ||
|
|
f2e33dfd58 | ||
|
|
90b5282b39 | ||
|
|
d520fc46b9 | ||
|
|
e69b5988ec | ||
|
|
3cdc1ba794 | ||
|
|
25e1008c5c | ||
|
|
a093862311 | ||
|
|
53057ea9fc | ||
|
|
94db96de3e | ||
|
|
60e4fbbf75 | ||
|
|
d35dd67632 | ||
|
|
8813985c68 | ||
|
|
538c98b587 | ||
|
|
389c7029cf | ||
|
|
d47f9e1131 | ||
|
|
c0a8d29756 | ||
|
|
668fd34af6 | ||
|
|
8aa08cf8fe | ||
|
|
16c04f5ae4 | ||
|
|
32c16021c4 | ||
|
|
7713c1173a | ||
|
|
8018f400c3 | ||
|
|
79c8293881 | ||
|
|
db5652623b | ||
|
|
0f7a48b323 | ||
|
|
309fbab2e6 | ||
|
|
99da145d65 | ||
|
|
415d2826c6 | ||
|
|
7787e7085e | ||
|
|
4ab8417168 | ||
|
|
a77e76d5c6 | ||
|
|
ca6660e2ff | ||
|
|
af94410c55 | ||
|
|
b47bc50147 | ||
|
|
5ff77c16ab | ||
|
|
11618260cf | ||
|
|
63f9006d17 | ||
|
|
7779acc7bc | ||
|
|
aacd92eee3 | ||
|
|
1bf8be2874 | ||
|
|
66f2d0c7dc | ||
|
|
597d952254 | ||
|
|
288595ce5d | ||
|
|
c89e8c78d3 | ||
|
|
81a37e3fc4 | ||
|
|
368c590976 | ||
|
|
6e982e646d | ||
|
|
030582b2d5 | ||
|
|
7dd4b10a96 | ||
|
|
b055e79b4c | ||
|
|
ba980aa93f | ||
|
|
15baf04ce9 | ||
|
|
4dc2587817 | ||
|
|
d5e046c289 | ||
|
|
ef8073ac58 | ||
|
|
38c9d25214 | ||
|
|
e2f0e4089f | ||
|
|
80ce2c04ed | ||
|
|
4ebd82beeb | ||
|
|
8cc43cd9a6 | ||
|
|
15190abb69 | ||
|
|
0b28159e8e | ||
|
|
d9e8f8e69b | ||
|
|
fa224e46bc | ||
|
|
06320953e8 | ||
|
|
2163334c4f | ||
|
|
f5d180af6b | ||
|
|
d676084cb3 | ||
|
|
0cb5941be0 | ||
|
|
732494dfc5 | ||
|
|
b8748b856a | ||
|
|
cc71f15700 | ||
|
|
124ef640b1 | ||
|
|
f5e3df0cd2 | ||
|
|
c8431181c8 | ||
|
|
07fb5ab017 | ||
|
|
6735b257b4 | ||
|
|
cef242a9ce | ||
|
|
2923d917e5 | ||
|
|
1d1639e5e1 | ||
|
|
6ab05fdb76 | ||
|
|
91ae8c0aaf | ||
|
|
fcb69c0190 | ||
|
|
2cf6fe4352 | ||
|
|
e3a2623a53 | ||
|
|
e0c0a423c1 | ||
|
|
fd99246c49 | ||
|
|
d247edd870 | ||
|
|
9a76a9069c | ||
|
|
8e1d796870 | ||
|
|
8b0d4e5c3b | ||
|
|
b9e257a39d | ||
|
|
e7eaa5fd58 | ||
|
|
c9aa992e73 | ||
|
|
f325930f68 | ||
|
|
1346ffb77e | ||
|
|
3378746530 | ||
|
|
ce2d94f04e | ||
|
|
b3c2a1e6c5 | ||
|
|
dbf63787da | ||
|
|
88a7ebef69 | ||
|
|
a716151dd9 | ||
|
|
7462f1b7a5 | ||
|
|
ec76b9dc5c | ||
|
|
79cd96ade9 | ||
|
|
a5b84406be | ||
|
|
8c1a04c4b2 | ||
|
|
ee81037173 | ||
|
|
453349be26 | ||
|
|
81a9e06b23 | ||
|
|
7d8af0f252 | ||
|
|
a68cd7526b | ||
|
|
470ca3b6dc | ||
|
|
e8bae61afc | ||
|
|
c1f663a200 | ||
|
|
22b2e21df0 | ||
|
|
5f19710791 | ||
|
|
d3f3ff4eab | ||
|
|
5af7425cae | ||
|
|
fe10c9f8c8 | ||
|
|
cd2a085d00 | ||
|
|
3c61626370 | ||
|
|
351fe5848f | ||
|
|
ca7bbefbdc | ||
|
|
7094f71e32 | ||
|
|
88b5e9db87 | ||
|
|
b4ab07bd78 | ||
|
|
fd6ad6dce3 | ||
|
|
ab97068a1d | ||
|
|
70fe3b9773 | ||
|
|
1fe8079fd5 | ||
|
|
80627997d1 | ||
|
|
12abdcaf6c | ||
|
|
a6ed4d92c9 | ||
|
|
0471640f54 | ||
|
|
4cf3e82fb5 | ||
|
|
fbbe999806 | ||
|
|
76af488d35 | ||
|
|
a54d2a5f22 | ||
|
|
a1df075194 | ||
|
|
4de2182b40 | ||
|
|
6fa88123f1 | ||
|
|
f81dbde15e | ||
|
|
484fbc6b9d | ||
|
|
8ba30135a1 | ||
|
|
ba5a72fdad | ||
|
|
70b39ddadf | ||
|
|
8200c0b0ab | ||
|
|
59ebfa6cc7 | ||
|
|
57b694162d | ||
|
|
2e6bdc225f | ||
|
|
8ced689432 | ||
|
|
53a8f6b4c0 | ||
|
|
9ae1a55896 | ||
|
|
5ecafe214f | ||
|
|
8baf0ad6af | ||
|
|
3cc64b5764 | ||
|
|
19cf07564f | ||
|
|
5847ce5c14 | ||
|
|
a7ad45635e | ||
|
|
781215394e | ||
|
|
0aafdca999 | ||
|
|
18d3cb6f0c | ||
|
|
263a96e8b7 | ||
|
|
27d5009486 | ||
|
|
4d1a91baa6 | ||
|
|
1898efa282 | ||
|
|
648ab4d736 | ||
|
|
407cac588a | ||
|
|
210dcfb989 | ||
|
|
2e431b1135 | ||
|
|
e2ec27250c | ||
|
|
1228eda5ea | ||
|
|
435794df73 | ||
|
|
7e3d0639f7 | ||
|
|
86b0005821 | ||
|
|
2fb78275f7 | ||
|
|
98f421c697 | ||
|
|
a5572b7d45 | ||
|
|
fdecbaaa6a | ||
|
|
c6afd7fa24 | ||
|
|
5cad522a60 | ||
|
|
82f64677cb | ||
|
|
3ee086a063 | ||
|
|
13da444a69 | ||
|
|
b51ceaaadc | ||
|
|
2024c72209 | ||
|
|
b5959c55e1 | ||
|
|
16f0ac97f4 | ||
|
|
073c02ee0c | ||
|
|
786f0db4bb | ||
|
|
6958e4b74f | ||
|
|
22c4fba665 | ||
|
|
f7c0e56cec | ||
|
|
5f423cd22e | ||
|
|
282b3a109c | ||
|
|
dddb051d8b | ||
|
|
63d3706003 | ||
|
|
22ca2494f5 | ||
|
|
a0f02b6877 | ||
|
|
487fcff61f | ||
|
|
bfb8897188 | ||
|
|
ce1ccf378a | ||
|
|
96d5ee3d46 | ||
|
|
6f3771e7cd | ||
|
|
e6b00b05a2 | ||
|
|
148d0afe81 | ||
|
|
c5d63dbdb9 | ||
|
|
1af072b059 | ||
|
|
a6a8fdd2f8 | ||
|
|
8836021ff9 | ||
|
|
915803c5be | ||
|
|
cd95d43457 | ||
|
|
35af5fd13c | ||
|
|
35e602f75f | ||
|
|
b4f0a1acc0 | ||
|
|
7b7e9f6868 | ||
|
|
de3892950c | ||
|
|
5c53826da3 | ||
|
|
d358073081 | ||
|
|
d2d7fd7c4c | ||
|
|
706da768e2 | ||
|
|
408073ee19 | ||
|
|
2695b7fc38 | ||
|
|
c32b6393af | ||
|
|
abbb4e793f | ||
|
|
e4fae2d660 | ||
|
|
dc572c3815 | ||
|
|
c65b03db41 | ||
|
|
45d2e1f5e2 | ||
|
|
b658f5bd0e | ||
|
|
f199d85d5b | ||
|
|
445dfaaeb4 | ||
|
|
cccd4122c5 | ||
|
|
1fcbe828bd | ||
|
|
e94b78a37b | ||
|
|
af7cecb667 | ||
|
|
4068e9c6b8 | ||
|
|
185c1fcdac | ||
|
|
29c5d35c08 | ||
|
|
0117f54ef8 | ||
|
|
56d41916c4 | ||
|
|
fddf73b1bb | ||
|
|
d670c2ae5e | ||
|
|
6f5c9eb600 | ||
|
|
49c416c90d | ||
|
|
8fef468eb9 | ||
|
|
976b1e1e0f | ||
|
|
d6de7cca96 | ||
|
|
fb02751bdd | ||
|
|
3fb5c52af1 | ||
|
|
18d17570f6 | ||
|
|
fa5eb16054 | ||
|
|
b1c77b508a | ||
|
|
b982ca2c5b | ||
|
|
219753039d | ||
|
|
c16f9af6a9 | ||
|
|
a544b0dc19 | ||
|
|
a398f07f9f | ||
|
|
7ecdee7a89 | ||
|
|
24361ccd97 | ||
|
|
3afe6df9f2 | ||
|
|
df7f79004d | ||
|
|
405bce9f82 | ||
|
|
b9ef7af791 | ||
|
|
761891abe9 | ||
|
|
6a52637695 | ||
|
|
b4b957d2c3 | ||
|
|
dda4a0a887 | ||
|
|
b069a936ab | ||
|
|
15c088ec21 | ||
|
|
015d70afb6 | ||
|
|
2158f69c09 | ||
|
|
c49c5fd58c | ||
|
|
26be131b4b | ||
|
|
f8533eb2c6 | ||
|
|
4cc545659b | ||
|
|
70a0b5c22f | ||
|
|
a2976d9ad5 | ||
|
|
01b05f186e | ||
|
|
79a4da9db8 | ||
|
|
84890fd5ad | ||
|
|
29f9d0c1cd | ||
|
|
95169bbc84 | ||
|
|
9a2979e577 | ||
|
|
9f381a7b30 | ||
|
|
c07ad348bd | ||
|
|
d7ae2e4307 | ||
|
|
71b86b3cbc | ||
|
|
621e8078d9 | ||
|
|
7155ab8bdc | ||
|
|
0a3e788d21 | ||
|
|
f83c46d1c7 | ||
|
|
11932353f7 | ||
|
|
ed373107c2 | ||
|
|
1cca15ca5d | ||
|
|
11e59a970e | ||
|
|
5abb69d022 | ||
|
|
dc1d497ff3 | ||
|
|
7f909fa098 | ||
|
|
320f064775 | ||
|
|
c9b1691998 | ||
|
|
08ade8371c | ||
|
|
081ac2d109 | ||
|
|
3fde546b83 | ||
|
|
a12b3cb51a | ||
|
|
6160945b9e | ||
|
|
6a126009a8 | ||
|
|
891e71aec6 | ||
|
|
cd164049b7 | ||
|
|
709a47bc6b | ||
|
|
9c6cd80867 | ||
|
|
832d9a2ab8 | ||
|
|
8d4e30a2e4 | ||
|
|
baf41eb104 | ||
|
|
7f0fe1681b | ||
|
|
49189bc63e | ||
|
|
87f30ed3d5 | ||
|
|
aca390ee19 | ||
|
|
598bb6d742 | ||
|
|
33b19e40e0 | ||
|
|
5b9401fafe | ||
|
|
9bed6b7e22 | ||
|
|
aca003c554 | ||
|
|
3c806558eb | ||
|
|
d195d46f8f | ||
|
|
755abc6487 | ||
|
|
718282bae3 | ||
|
|
8cc4d08eae | ||
|
|
0bcc02dfab | ||
|
|
33c3fb7de0 | ||
|
|
d99b8f5864 | ||
|
|
98bf63e94b | ||
|
|
2d8b1299b3 | ||
|
|
5edc4abfb4 | ||
|
|
26f7264f3c | ||
|
|
56c82d7f0f | ||
|
|
6946da3571 | ||
|
|
2985c762e6 | ||
|
|
8001d940eb | ||
|
|
2f440eba37 | ||
|
|
bb9cb2fb75 | ||
|
|
5531c15126 | ||
|
|
29f049c411 | ||
|
|
31180afbd1 | ||
|
|
435b856b72 | ||
|
|
af62526b92 | ||
|
|
beb7d09aee | ||
|
|
b4b1b7a3fa | ||
|
|
d0342598c4 | ||
|
|
4a71b00b71 | ||
|
|
268bbf3b9e | ||
|
|
24cdeb06e8 | ||
|
|
6b64d85db0 | ||
|
|
08e542dfb3 | ||
|
|
8b997cffdd | ||
|
|
33aece6f96 | ||
|
|
6040eea3bd | ||
|
|
9b3ca65492 | ||
|
|
c76f368fa0 | ||
|
|
664d28f105 | ||
|
|
7daee36d3e | ||
|
|
5fc10fe041 | ||
|
|
6692de33b1 | ||
|
|
494bd425af | ||
|
|
135ce2285d | ||
|
|
be2e82788f | ||
|
|
e84fb63343 | ||
|
|
97422c1d7a | ||
|
|
66cc739bb2 | ||
|
|
790454f194 | ||
|
|
d751966078 | ||
|
|
a8e9f7b445 | ||
|
|
144afc346d | ||
|
|
63854156eb | ||
|
|
7800e76b26 | ||
|
|
1e5b95f64a | ||
|
|
097e36677a | ||
|
|
7e6e10e3ef | ||
|
|
f72ce697a7 | ||
|
|
e6843bc3e0 | ||
|
|
5c0cf09c42 | ||
|
|
ab14bdbb18 | ||
|
|
8dc43dab59 | ||
|
|
0c5a6a7548 | ||
|
|
779e2f4633 | ||
|
|
644e3e200d | ||
|
|
670cc474a4 | ||
|
|
c43820776f | ||
|
|
749740242e | ||
|
|
f864746b54 | ||
|
|
42dcd4750a | ||
|
|
cb0c6a344f | ||
|
|
d1d652495d | ||
|
|
4b574cecf7 | ||
|
|
e7dbaf78b5 | ||
|
|
6f83b932b0 | ||
|
|
4552b2b158 | ||
|
|
5b708e77aa | ||
|
|
a3f1e46107 | ||
|
|
097808752d | ||
|
|
39be268969 | ||
|
|
6023d53506 | ||
|
|
1a6e653600 | ||
|
|
586c707e51 | ||
|
|
6ca941e8e9 | ||
|
|
b83675cdd0 | ||
|
|
1a583913a7 | ||
|
|
d98a644b75 | ||
|
|
11c0c93fe2 | ||
|
|
6d78867d69 | ||
|
|
54813b8b93 | ||
|
|
6ab31c67fc | ||
|
|
69af2ff7e8 | ||
|
|
b505a2a94d | ||
|
|
6a5fd0d6f0 | ||
|
|
e21557645b | ||
|
|
28cab146f3 | ||
|
|
43df4ae0e7 | ||
|
|
5037027030 | ||
|
|
5e11684665 | ||
|
|
c7793beb0f | ||
|
|
33b9e6d0c1 | ||
|
|
d87e8b729f | ||
|
|
0db08f4c62 | ||
|
|
e9796c9a35 | ||
|
|
36350bd71a | ||
|
|
e53a2255a9 | ||
|
|
d42f911df9 | ||
|
|
1b2d922c3f | ||
|
|
a5c5486474 | ||
|
|
926f0f85f3 | ||
|
|
63d430c3d9 | ||
|
|
26a009b397 | ||
|
|
be115c74c3 | ||
|
|
049721bbfe | ||
|
|
8b4e76832f | ||
|
|
25a51a71a0 | ||
|
|
f4d6e98d61 | ||
|
|
eee496a050 | ||
|
|
89a83a625b | ||
|
|
c17df24a19 | ||
|
|
bbcc2f4be4 | ||
|
|
5e63d9015f | ||
|
|
4958b89636 | ||
|
|
f4b6e9c25a | ||
|
|
a59d407f12 | ||
|
|
c95cb79672 | ||
|
|
73e7fa0f85 | ||
|
|
7f81b83955 | ||
|
|
a42ae62042 | ||
|
|
165357f444 | ||
|
|
e4c928ae87 | ||
|
|
d51e3de674 | ||
|
|
b0476c7017 | ||
|
|
1de9f715fa | ||
|
|
f15e048763 | ||
|
|
422b324f7c | ||
|
|
fb163367d4 | ||
|
|
c91eec8b3e | ||
|
|
c16eee79d4 | ||
|
|
1e86d85035 | ||
|
|
abfc2fea3e | ||
|
|
991d61600d | ||
|
|
0f4713bddc | ||
|
|
51205fffa0 | ||
|
|
9f4fd92452 | ||
|
|
354fccab8b | ||
|
|
a6ba87c2f8 | ||
|
|
ae8aa0374f | ||
|
|
dc5e073715 | ||
|
|
8c68ff5419 | ||
|
|
bc10408729 | ||
|
|
96b059f657 | ||
|
|
4db2ae53cb | ||
|
|
f7308f53d3 | ||
|
|
17fbd78b97 | ||
|
|
3ad03ebc1d | ||
|
|
32e4e69930 | ||
|
|
b20f7aca53 | ||
|
|
e72ee606fd | ||
|
|
1386d1ae32 | ||
|
|
903d678f30 | ||
|
|
828a786414 | ||
|
|
3ee8e7b755 | ||
|
|
0d0448d86b | ||
|
|
5da4762f40 | ||
|
|
36bcb2ce92 | ||
|
|
151d7c1ba5 | ||
|
|
19d444e387 | ||
|
|
e41c718bb3 | ||
|
|
2e5d91a5bc | ||
|
|
ae184ab894 | ||
|
|
1ceedf2372 | ||
|
|
416c05ed3b | ||
|
|
623da7eade | ||
|
|
84b3d6db76 | ||
|
|
25a27c9b11 | ||
|
|
456d59f582 | ||
|
|
1d641cdf82 | ||
|
|
4420d7962e | ||
|
|
21e6e3df3f | ||
|
|
7e04098971 | ||
|
|
24df4dd0c1 | ||
|
|
8ed87e77be | ||
|
|
10c0ce26dc | ||
|
|
3a38b59dad | ||
|
|
24820b914c | ||
|
|
97339fd45d | ||
|
|
a1314d645b | ||
|
|
571a4dca7a | ||
|
|
36f5e62537 | ||
|
|
a21b716d0a | ||
|
|
c25859cee9 | ||
|
|
79dc5e4344 | ||
|
|
c81aef6d05 | ||
|
|
c744e36f3b | ||
|
|
9d96b3d1d0 | ||
|
|
b246c638fd | ||
|
|
15dd8dfe8c | ||
|
|
50859fd661 | ||
|
|
eada994a82 | ||
|
|
3da2046fa0 | ||
|
|
989ca08c94 | ||
|
|
e9ccd7120d | ||
|
|
c15ae293aa | ||
|
|
50501aef56 | ||
|
|
45747183e7 | ||
|
|
c9424d6f8d | ||
|
|
5ecd8b41e5 | ||
|
|
01d6dee9fc | ||
|
|
12865ac7cc | ||
|
|
362f0b2fe5 | ||
|
|
9f800df5ad | ||
|
|
e937f1b601 | ||
|
|
5b387a0b11 | ||
|
|
9226b165bd | ||
|
|
a6586c9d1c | ||
|
|
0a36d759e4 | ||
|
|
328bcd0532 | ||
|
|
ec76e9cf2a | ||
|
|
88ae996694 | ||
|
|
d1d1d05ce7 | ||
|
|
c62a03c97b | ||
|
|
65cc57ec03 | ||
|
|
806c9a57fc | ||
|
|
3a18ce0cf9 | ||
|
|
4fde6e1293 | ||
|
|
31b43301a4 | ||
|
|
6a77e412fa | ||
|
|
53a6424348 | ||
|
|
c8d933469a | ||
|
|
e456373671 | ||
|
|
afdb806083 | ||
|
|
02c63dd22f | ||
|
|
529f9a2fb9 | ||
|
|
6b0bcf93d3 | ||
|
|
13afe33244 | ||
|
|
d441bccf8b | ||
|
|
e6847355e7 | ||
|
|
72051c8660 | ||
|
|
87afc64f16 | ||
|
|
870fef3ea6 | ||
|
|
e5ac8a0a67 | ||
|
|
87fcc0afe6 | ||
|
|
79830870dd | ||
|
|
69ad40c27f | ||
|
|
1ac7ce00fb | ||
|
|
e239bca0f2 | ||
|
|
8729fe48c3 | ||
|
|
441c55eb31 | ||
|
|
5291a6856e | ||
|
|
e011f99161 | ||
|
|
64a756cc04 | ||
|
|
f57e90b35c | ||
|
|
5a5d242ea0 | ||
|
|
4afea27fa5 | ||
|
|
fc8042aa25 | ||
|
|
2b6220beb8 | ||
|
|
78426a6c7b | ||
|
|
620e53c255 | ||
|
|
753fc6c769 | ||
|
|
3d6e1dfc0a | ||
|
|
d92431ad65 | ||
|
|
be19d1f5b5 | ||
|
|
ca08a52998 | ||
|
|
e54822f3b0 | ||
|
|
3863e657ef | ||
|
|
341ef79b49 | ||
|
|
335f34b824 | ||
|
|
c864863be4 | ||
|
|
c3ebef0dde | ||
|
|
7b7058c77b | ||
|
|
192cf9bc26 | ||
|
|
1cccbcfabe | ||
|
|
a85b37985a | ||
|
|
8b6b1ee315 | ||
|
|
021c655a1a | ||
|
|
8af8968b49 | ||
|
|
17298edfcc | ||
|
|
5281e8e5b4 | ||
|
|
cc0e30e3f5 | ||
|
|
497bb35209 | ||
|
|
7d1453ffbd | ||
|
|
89228f264f | ||
|
|
a10d99f938 | ||
|
|
d014ae4fcf | ||
|
|
a22687e2d8 | ||
|
|
44475853df | ||
|
|
bbcc670655 | ||
|
|
ae58b4af35 | ||
|
|
fbc2ffac59 | ||
|
|
f279839e6f | ||
|
|
1844a7d666 | ||
|
|
c9f648fcb8 | ||
|
|
948688a4ea | ||
|
|
35ca295d48 | ||
|
|
cacc4ad01d | ||
|
|
b12085f61f | ||
|
|
39dacafa82 | ||
|
|
57deb36027 | ||
|
|
2840df82f4 | ||
|
|
3d971108b8 | ||
|
|
5bcdce72ef | ||
|
|
398329a219 | ||
|
|
754a06343f | ||
|
|
55a79e5fbf | ||
|
|
c78a97fed1 | ||
|
|
13c8ff5cb3 | ||
|
|
9e34d3a668 | ||
|
|
57f220e64c | ||
|
|
a89756a76c | ||
|
|
88c1aa163e | ||
|
|
d2184682e5 | ||
|
|
63cc5b21b4 | ||
|
|
b7703fc4df | ||
|
|
254d3a1c8e | ||
|
|
8d3892757a | ||
|
|
a8992d08b3 | ||
|
|
5e35aa8079 | ||
|
|
df8da0fd4f | ||
|
|
f820c6f23b | ||
|
|
0c616fecdf | ||
|
|
092a84693f | ||
|
|
d1e80815d5 | ||
|
|
0f000ccd93 | ||
|
|
f90e0767cb | ||
|
|
ad6d61f1f7 | ||
|
|
47f7968dc4 | ||
|
|
455b190a5b | ||
|
|
0bc8584c35 | ||
|
|
da39cdb27f | ||
|
|
769c2e9b4e | ||
|
|
783d2b8843 | ||
|
|
baca0a17c3 | ||
|
|
f48d47bac5 | ||
|
|
14fa5d2723 | ||
|
|
70845611a4 | ||
|
|
7be11da85f | ||
|
|
f2f4b0e75b | ||
|
|
491cd27f2d | ||
|
|
7b62881113 | ||
|
|
22f46919f9 | ||
|
|
1ef7fd401f | ||
|
|
5f1dbc23b4 | ||
|
|
8d750417ec | ||
|
|
52f30052d5 | ||
|
|
655e6bafd1 | ||
|
|
d4dfb0cb53 | ||
|
|
8d08973d48 | ||
|
|
9b1b56a381 | ||
|
|
f709c27329 | ||
|
|
02859039ec | ||
|
|
e6810ef753 | ||
|
|
ef86e195c6 | ||
|
|
d69dd2a83f | ||
|
|
5dd21ac539 | ||
|
|
bd6575982b | ||
|
|
80313527c5 | ||
|
|
78901e03d7 | ||
|
|
01c1b19601 | ||
|
|
1d837092a2 | ||
|
|
bde04919fe | ||
|
|
0dd0416346 | ||
|
|
711dd64093 | ||
|
|
db7b4829b5 | ||
|
|
f97c63fe93 | ||
|
|
cb5fe95768 | ||
|
|
34359dd7b6 | ||
|
|
476d1d274e | ||
|
|
c52265c046 | ||
|
|
4fbf3d79c7 | ||
|
|
e8cc92db95 | ||
|
|
40e969bab9 | ||
|
|
3df2105016 | ||
|
|
0aa3cc3d6f | ||
|
|
666f26f516 | ||
|
|
7662dde294 | ||
|
|
d28dda876c | ||
|
|
309d7e704c | ||
|
|
ecf9ce586c | ||
|
|
d0de9e5e21 | ||
|
|
2154a5e1db | ||
|
|
dbe51ccaf3 | ||
|
|
993d53ed97 | ||
|
|
730e2da932 | ||
|
|
18a198496b | ||
|
|
5eb791fd65 | ||
|
|
27cc022fb8 | ||
|
|
35f244cf50 | ||
|
|
fa30bfc04b | ||
|
|
a072466f75 | ||
|
|
ae5c898537 | ||
|
|
921a37f4a2 |
2
.github/actions/report-size/action.yml
vendored
2
.github/actions/report-size/action.yml
vendored
@@ -44,7 +44,7 @@ runs:
|
||||
steps:
|
||||
# Checkout branch to compare to [required]
|
||||
- name: Checkout base branch
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ inputs.branch }}
|
||||
path: br-base
|
||||
|
||||
334
.github/copilot-instructions.md
vendored
Normal file
334
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
# Trilium Notes - AI Coding Agent Instructions
|
||||
|
||||
## Project Overview
|
||||
|
||||
Trilium Notes is a hierarchical note-taking application with advanced features like synchronization, scripting, and rich text editing. Built as a TypeScript monorepo using pnpm, it implements a three-layer caching architecture (Becca/Froca/Shaca) with a widget-based UI system and supports extensive user scripting capabilities.
|
||||
|
||||
## Essential Architecture Patterns
|
||||
|
||||
### Three-Layer Cache System (Critical to Understand)
|
||||
- **Becca** (`apps/server/src/becca/`): Server-side entity cache, primary data source
|
||||
- **Froca** (`apps/client/src/services/froca.ts`): Client-side mirror synchronized via WebSocket
|
||||
- **Shaca** (`apps/server/src/share/`): Optimized cache for public/shared notes
|
||||
|
||||
**Key insight**: Never bypass these caches with direct DB queries. Always use `becca.notes[noteId]`, `froca.getNote()`, or equivalent cache methods.
|
||||
|
||||
### Entity Relationship Model
|
||||
Notes use a **multi-parent tree** via branches:
|
||||
- `BNote` - The note content and metadata
|
||||
- `BBranch` - Tree relationships (one note can have multiple parents via cloning)
|
||||
- `BAttribute` - Key-value metadata attached to notes (labels and relations)
|
||||
|
||||
### Entity Change System & Sync
|
||||
Every entity modification (notes, branches, attributes) creates an `EntityChange` record that drives synchronization:
|
||||
|
||||
```typescript
|
||||
// Entity changes are automatically tracked
|
||||
note.title = "New Title";
|
||||
note.save(); // Creates EntityChange record with changeId
|
||||
|
||||
// Sync protocol via WebSocket
|
||||
ws.sendMessage({ type: 'sync-pull-in-progress', ... });
|
||||
```
|
||||
|
||||
**Critical**: This is why you must use Becca/Froca methods instead of direct DB writes - they create the change tracking records needed for sync.
|
||||
|
||||
### Entity Lifecycle & Events
|
||||
The event system (`apps/server/src/services/events.ts`) broadcasts entity lifecycle events:
|
||||
|
||||
```typescript
|
||||
// Subscribe to events in widgets or services
|
||||
eventService.subscribe('noteChanged', ({ noteId }) => {
|
||||
// React to note changes
|
||||
});
|
||||
|
||||
// Common events: noteChanged, branchChanged, attributeChanged, noteDeleted
|
||||
// Widget method: entitiesReloadedEvent({loadResults}) for handling reloads
|
||||
```
|
||||
|
||||
**Becca loader priorities**: Events are emitted in order (notes → branches → attributes) during initial load to ensure referential integrity.
|
||||
|
||||
### TaskContext for Long Operations
|
||||
Use `TaskContext` for operations with progress reporting (imports, exports, bulk operations):
|
||||
|
||||
```typescript
|
||||
const taskContext = new TaskContext("task-id", "import", "Import Notes");
|
||||
taskContext.increaseProgressCount();
|
||||
|
||||
// WebSocket messages: { type: 'taskProgressCount', taskId, taskType, data, progressCount }
|
||||
|
||||
**Pattern**: All long-running operations (delete note trees, export, import) use TaskContext to send WebSocket updates to the frontend.
|
||||
|
||||
### Protected Session Handling
|
||||
Protected notes require an active encryption session:
|
||||
|
||||
```typescript
|
||||
// Always check before accessing protected content
|
||||
if (note.isContentAvailable()) {
|
||||
const content = note.getContent(); // Safe
|
||||
} else {
|
||||
const title = note.getTitleOrProtected(); // Returns "[protected]"
|
||||
}
|
||||
|
||||
// Protected session management
|
||||
protectedSessionService.isProtectedSessionAvailable() // Check session
|
||||
protectedSessionService.startProtectedSession() // After password entry
|
||||
```
|
||||
|
||||
**Session timeout**: Protected sessions expire after inactivity. The encryption key is kept in memory only.
|
||||
|
||||
### Attribute Inheritance Patterns
|
||||
Attributes can be inherited through three mechanisms:
|
||||
|
||||
```typescript
|
||||
// 1. Standard inheritance (#hidePromotedAttributes ~hidePromotedAttributes)
|
||||
note.getInheritableAttributes() // Walks up parent tree
|
||||
|
||||
// 2. Child prefix inheritance (child:label copies to children)
|
||||
parentNote.setLabel("child:icon", "book") // All children inherit this
|
||||
|
||||
// 3. Template relation inheritance (#template=templateNoteId)
|
||||
note.setRelation("template", templateNoteId)
|
||||
note.getInheritedAttributes() // Includes template's inheritable attributes
|
||||
```
|
||||
|
||||
**Cycle prevention**: Inheritance tracking prevents infinite loops when notes reference each other.
|
||||
|
||||
### Widget-Based UI Architecture
|
||||
All UI components extend from widget base classes (`apps/client/src/widgets/`):
|
||||
|
||||
```typescript
|
||||
// Right panel widget (sidebar)
|
||||
class MyWidget extends RightPanelWidget {
|
||||
get position() { return 100; } // Order in panel
|
||||
get parentWidget() { return 'right-pane'; }
|
||||
isEnabled() { return this.note && this.note.hasLabel('myLabel'); }
|
||||
async refreshWithNote(note) { /* Update UI */ }
|
||||
}
|
||||
|
||||
// Note-aware widget (responds to note changes)
|
||||
class MyNoteWidget extends NoteContextAwareWidget {
|
||||
async refreshWithNote(note) { /* Refresh when note changes */ }
|
||||
async entitiesReloadedEvent({loadResults}) { /* Handle entity updates */ }
|
||||
}
|
||||
```
|
||||
|
||||
**Important**: Widgets use jQuery (`this.$widget`) for DOM manipulation. Don't mix React patterns here.
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Running & Testing
|
||||
```bash
|
||||
# From root directory
|
||||
pnpm install # Install dependencies
|
||||
corepack enable # Enable pnpm if not available
|
||||
pnpm server:start # Dev server (http://localhost:8080)
|
||||
pnpm server:start-prod # Production mode server
|
||||
pnpm desktop:start # Desktop app development
|
||||
pnpm server:test spec/etapi/search.spec.ts # Run specific test
|
||||
pnpm test:parallel # Client tests (can run parallel)
|
||||
pnpm test:sequential # Server tests (sequential due to shared DB)
|
||||
pnpm test:all # All tests (parallel + sequential)
|
||||
pnpm coverage # Generate coverage reports
|
||||
pnpm typecheck # Type check all projects
|
||||
```
|
||||
|
||||
### Building
|
||||
```bash
|
||||
pnpm client:build # Build client application
|
||||
pnpm server:build # Build server application
|
||||
pnpm desktop:build # Build desktop application
|
||||
```
|
||||
|
||||
### Test Organization
|
||||
- **Server tests** (`apps/server/spec/`): Must run sequentially (shared database state)
|
||||
- **Client tests** (`apps/client/src/`): Can run in parallel
|
||||
- **E2E tests** (`apps/server-e2e/`): Use Playwright for integration testing
|
||||
- **ETAPI tests** (`apps/server/spec/etapi/`): External API contract tests
|
||||
|
||||
**Pattern**: When adding new API endpoints, add tests in `spec/etapi/` following existing patterns (see `search.spec.ts`).
|
||||
|
||||
### Monorepo Navigation
|
||||
```
|
||||
apps/
|
||||
client/ # Frontend (shared by server & desktop)
|
||||
server/ # Node.js backend with REST API
|
||||
desktop/ # Electron wrapper
|
||||
web-clipper/ # Browser extension for saving web content
|
||||
db-compare/ # Database comparison tool
|
||||
dump-db/ # Database export utility
|
||||
edit-docs/ # Documentation editing tools
|
||||
packages/
|
||||
commons/ # Shared types and utilities
|
||||
ckeditor5/ # Custom rich text editor with Trilium-specific plugins
|
||||
codemirror/ # Code editor integration
|
||||
highlightjs/ # Syntax highlighting
|
||||
share-theme/ # Theme for shared/published notes
|
||||
ckeditor5-admonition/ # Admonition blocks plugin
|
||||
ckeditor5-footnotes/ # Footnotes plugin
|
||||
ckeditor5-math/ # Math equations plugin
|
||||
ckeditor5-mermaid/ # Mermaid diagrams plugin
|
||||
```
|
||||
|
||||
**Filter commands**: Use `pnpm --filter server test` to run commands in specific packages.
|
||||
|
||||
## Critical Code Patterns
|
||||
|
||||
### ETAPI Backwards Compatibility
|
||||
When adding query parameters to ETAPI endpoints (`apps/server/src/etapi/`), maintain backwards compatibility by checking if new params exist before changing response format.
|
||||
|
||||
**Pattern**: ETAPI consumers expect specific response shapes. Always check for breaking changes.
|
||||
|
||||
### Frontend-Backend Communication
|
||||
- **REST API**: `apps/server/src/routes/api/` - Internal endpoints (no auth required when `noAuthentication=true`)
|
||||
- **ETAPI**: `apps/server/src/etapi/` - External API with authentication
|
||||
- **WebSocket**: Real-time sync via `apps/server/src/services/ws.ts`
|
||||
|
||||
**Auth note**: ETAPI uses basic auth with tokens. Internal API endpoints trust the frontend.
|
||||
|
||||
### Database Migrations
|
||||
- Add scripts in `apps/server/src/migrations/YYMMDD_HHMM__description.sql`
|
||||
- Update schema in `apps/server/src/assets/db/schema.sql`
|
||||
- Never bypass Becca cache after migrations
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Never bypass the cache layers** - Always use `becca.notes[noteId]`, `froca.getNote()`, or equivalent cache methods. Direct database queries will cause sync issues between Becca/Froca/Shaca and won't create EntityChange records needed for synchronization.
|
||||
|
||||
2. **Protected notes require session check** - Before accessing `note.title` or `note.getContent()` on protected notes, check `note.isContentAvailable()` or use `note.getTitleOrProtected()` which handles this automatically.
|
||||
|
||||
3. **Widget lifecycle matters** - Override `refreshWithNote()` for note changes, `doRenderBody()` for initial render, `entitiesReloadedEvent()` for entity updates. Widgets use jQuery (`this.$widget`) - don't mix React patterns.
|
||||
|
||||
4. **Tests run differently** - Server tests must run sequentially (shared database state), client tests can run in parallel. Use `pnpm test:sequential` for backend, `pnpm test:parallel` for frontend.
|
||||
|
||||
5. **ETAPI requires authentication** - ETAPI endpoints use basic auth with tokens. Internal API endpoints (`apps/server/src/routes/api/`) trust the frontend when `noAuthentication=true`.
|
||||
|
||||
6. **Search expressions are evaluated in memory** - The search service loads all matching notes, scores them in JavaScript, then sorts. You cannot add SQL-level LIMIT/OFFSET without losing scoring functionality.
|
||||
|
||||
7. **Documentation edits have rules** - `docs/Script API/` is auto-generated (never edit directly). `docs/User Guide/` should be edited via `pnpm edit-docs:edit-docs`, not manually. Only `docs/Developer Guide/` and `docs/Release Notes/` are safe for direct Markdown editing.
|
||||
|
||||
8. **pnpm workspace filtering** - Use `pnpm --filter server <command>` or shorthand `pnpm server:test` defined in root `package.json`. Note the `--filter` syntax, not `-F` or other shortcuts.
|
||||
|
||||
9. **Event subscription cleanup** - When subscribing to events in widgets, unsubscribe in `cleanup()` or `doDestroy()` to prevent memory leaks.
|
||||
|
||||
10. **Attribute inheritance can be complex** - When checking for labels/relations, use `note.getOwnedAttribute()` for direct attributes or `note.getAttribute()` for inherited ones. Don't assume attributes are directly on the note.
|
||||
|
||||
## TypeScript Configuration
|
||||
|
||||
- **Project references**: Monorepo uses TypeScript project references (`tsconfig.json`)
|
||||
- **Path mapping**: Use relative imports, not path aliases
|
||||
- **Build order**: `pnpm typecheck` builds all projects in dependency order
|
||||
- **Build system**: Uses Vite for fast development, ESBuild for production optimization
|
||||
- **Patches**: Custom patches in `patches/` directory for CKEditor and other dependencies
|
||||
|
||||
## Key Files for Context
|
||||
|
||||
- `apps/server/src/becca/entities/bnote.ts` - Note entity methods
|
||||
- `apps/client/src/services/froca.ts` - Frontend cache API
|
||||
- `apps/server/src/services/search/services/search.ts` - Search implementation
|
||||
- `apps/server/src/routes/routes.ts` - API route registration
|
||||
- `apps/client/src/widgets/basic_widget.ts` - Widget base class
|
||||
- `apps/server/src/main.ts` - Server startup entry point
|
||||
- `apps/client/src/desktop.ts` - Client initialization
|
||||
- `apps/server/src/services/backend_script_api.ts` - Scripting API
|
||||
- `apps/server/src/assets/db/schema.sql` - Database schema
|
||||
|
||||
## Note Types and Features
|
||||
|
||||
Trilium supports multiple note types with specialized widgets in `apps/client/src/widgets/type_widgets/`:
|
||||
- **Text**: Rich text with CKEditor5 (markdown import/export)
|
||||
- **Code**: Syntax-highlighted code editing with CodeMirror
|
||||
- **File**: Binary file attachments
|
||||
- **Image**: Image display with editing capabilities
|
||||
- **Canvas**: Drawing/diagramming with Excalidraw
|
||||
- **Mermaid**: Diagram generation
|
||||
- **Relation Map**: Visual note relationship mapping
|
||||
- **Web View**: Embedded web pages
|
||||
- **Doc/Book**: Hierarchical documentation structure
|
||||
|
||||
### Collections
|
||||
Notes can be marked with the `#collection` label to enable collection view modes. Collections support multiple view types:
|
||||
- **List**: Standard list view
|
||||
- **Grid**: Card/grid layout
|
||||
- **Calendar**: Calendar-based view
|
||||
- **Table**: Tabular data view
|
||||
- **GeoMap**: Geographic map view
|
||||
- **Board**: Kanban-style board
|
||||
- **Presentation**: Slideshow presentation mode
|
||||
|
||||
View types are configured via `#viewType` label (e.g., `#viewType=table`). Each view mode stores its configuration in a separate attachment (e.g., `table.json`). Collections are organized separately from regular note type templates in the note creation menu.
|
||||
|
||||
## Common Development Tasks
|
||||
|
||||
### Adding New Note Types
|
||||
1. Create widget in `apps/client/src/widgets/type_widgets/`
|
||||
2. Register in `apps/client/src/services/note_types.ts`
|
||||
3. Add backend handling in `apps/server/src/services/notes.ts`
|
||||
|
||||
### Extending Search
|
||||
- Search expressions handled in `apps/server/src/services/search/`
|
||||
- Add new search operators in search context files
|
||||
- Remember: scoring happens in-memory, not at database level
|
||||
|
||||
### Custom CKEditor Plugins
|
||||
- Create new package in `packages/` following existing plugin structure
|
||||
- Register in `packages/ckeditor5/src/plugins.ts`
|
||||
- See `ckeditor5-admonition`, `ckeditor5-footnotes`, `ckeditor5-math`, `ckeditor5-mermaid` for examples
|
||||
|
||||
### Database Migrations
|
||||
- Add migration scripts in `apps/server/src/migrations/YYMMDD_HHMM__description.sql`
|
||||
- Update schema in `apps/server/src/assets/db/schema.sql`
|
||||
- Never bypass Becca cache after migrations
|
||||
|
||||
## Security & Features
|
||||
|
||||
### Security Considerations
|
||||
- Per-note encryption with granular protected sessions
|
||||
- CSRF protection for API endpoints
|
||||
- OpenID and TOTP authentication support
|
||||
- Sanitization of user-generated content
|
||||
|
||||
### Scripting System
|
||||
Trilium provides powerful user scripting capabilities:
|
||||
- **Frontend scripts**: Run in browser context with UI access
|
||||
- **Backend scripts**: Run in Node.js context with full API access
|
||||
- Script API documentation in `docs/Script API/`
|
||||
- Backend API available via `api` object in script context
|
||||
|
||||
### Internationalization
|
||||
- Translation files in `apps/client/src/translations/`
|
||||
- Use translation system via `t()` function
|
||||
- Automatic pluralization: Add `_other` suffix to translation keys (e.g., `item` and `item_other` for singular/plural)
|
||||
|
||||
## Testing Conventions
|
||||
|
||||
```typescript
|
||||
// ETAPI test pattern
|
||||
describe("etapi/feature", () => {
|
||||
beforeAll(async () => {
|
||||
config.General.noAuthentication = false;
|
||||
app = await buildApp();
|
||||
token = await login(app);
|
||||
});
|
||||
|
||||
it("should test feature", async () => {
|
||||
const response = await supertest(app)
|
||||
.get("/etapi/notes?search=test")
|
||||
.auth(USER, token, { type: "basic" })
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.results).toBeDefined();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Questions to Verify Understanding
|
||||
|
||||
Before implementing significant changes, confirm:
|
||||
- Is this touching the cache layer? (Becca/Froca/Shaca must stay in sync via EntityChange records)
|
||||
- Does this change API response shape? (Check backwards compatibility for ETAPI)
|
||||
- Are you adding search features? (Understand expression-based architecture and in-memory scoring first)
|
||||
- Is this a new widget? (Know which base class and lifecycle methods to use)
|
||||
- Does this involve protected notes? (Check `isContentAvailable()` before accessing content)
|
||||
- Is this a long-running operation? (Use TaskContext for progress reporting)
|
||||
- Are you working with attributes? (Understand inheritance patterns: direct, child-prefix, template)
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# Add any setup steps before running the `github/codeql-action/init` action.
|
||||
# This includes steps like installing compilers or runtimes (`actions/setup-node`
|
||||
|
||||
2
.github/workflows/deploy-docs.yml
vendored
2
.github/workflows/deploy-docs.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
6
.github/workflows/dev.yml
vendored
6
.github/workflows/dev.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Set up node & dependencies
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
needs:
|
||||
- test_dev
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
- dockerfile: Dockerfile
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Install dependencies
|
||||
|
||||
8
.github/workflows/main-docker.yml
vendored
8
.github/workflows/main-docker.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- dockerfile: Dockerfile
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set IMAGE_NAME to lowercase
|
||||
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV
|
||||
@@ -141,7 +141,7 @@ jobs:
|
||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v6
|
||||
@@ -155,6 +155,10 @@ jobs:
|
||||
- name: Update build info
|
||||
run: pnpm run chore:update-build-info
|
||||
|
||||
- name: Update nightly version
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
|
||||
run: pnpm run chore:ci-update-nightly-version
|
||||
|
||||
- name: Run the TypeScript build
|
||||
run: pnpm run server:build
|
||||
|
||||
|
||||
19
.github/workflows/nightly.yml
vendored
19
.github/workflows/nightly.yml
vendored
@@ -45,9 +45,22 @@ jobs:
|
||||
image: win-signing
|
||||
shell: cmd
|
||||
forge_platform: win32
|
||||
# Exclude ARM64 Linux from default matrix to use native runner
|
||||
exclude:
|
||||
- arch: arm64
|
||||
os:
|
||||
name: linux
|
||||
# Add ARM64 Linux with native ubuntu-24.04-arm runner for better-sqlite3 compatibility
|
||||
include:
|
||||
- arch: arm64
|
||||
os:
|
||||
name: linux
|
||||
image: ubuntu-24.04-arm
|
||||
shell: bash
|
||||
forge_platform: linux
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v6
|
||||
@@ -57,7 +70,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Update nightly version
|
||||
run: npm run chore:ci-update-nightly-version
|
||||
run: pnpm run chore:ci-update-nightly-version
|
||||
- name: Run the build
|
||||
uses: ./.github/actions/build-electron
|
||||
with:
|
||||
@@ -109,7 +122,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Run the build
|
||||
uses: ./.github/actions/build-server
|
||||
|
||||
4
.github/workflows/playwright.yml
vendored
4
.github/workflows/playwright.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
TRILIUM_DATA_DIR: "${{ github.workspace }}/apps/server/spec/db"
|
||||
TRILIUM_INTEGRATION_TEST: memory
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
filter: tree:0
|
||||
fetch-depth: 0
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: e2e report
|
||||
name: e2e report ${{ matrix.arch }}
|
||||
path: apps/server-e2e/test-output
|
||||
|
||||
- name: Kill the server
|
||||
|
||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
forge_platform: linux
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v6
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Run the build
|
||||
uses: ./.github/actions/build-server
|
||||
@@ -114,7 +114,7 @@ jobs:
|
||||
steps:
|
||||
- run: mkdir upload
|
||||
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
sparse-checkout: |
|
||||
docs/Release Notes
|
||||
|
||||
2
.github/workflows/website.yml
vendored
2
.github/workflows/website.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
pull-requests: write # For PR preview comments
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v6
|
||||
|
||||
@@ -35,19 +35,19 @@
|
||||
"chore:generate-openapi": "tsx bin/generate-openapi.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.56.1",
|
||||
"@stylistic/eslint-plugin": "5.5.0",
|
||||
"@playwright/test": "1.57.0",
|
||||
"@stylistic/eslint-plugin": "5.6.1",
|
||||
"@types/express": "5.0.5",
|
||||
"@types/node": "24.10.1",
|
||||
"@types/yargs": "17.0.34",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"@types/yargs": "17.0.35",
|
||||
"@vitest/coverage-v8": "4.0.14",
|
||||
"eslint": "9.39.1",
|
||||
"eslint-plugin-simple-import-sort": "12.1.1",
|
||||
"esm": "3.2.25",
|
||||
"jsdoc": "4.0.5",
|
||||
"lorem-ipsum": "2.0.8",
|
||||
"rcedit": "5.0.0",
|
||||
"rimraf": "6.1.0",
|
||||
"rcedit": "5.0.2",
|
||||
"rimraf": "6.1.2",
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
"keywords": [],
|
||||
"author": "Elian Doran <contact@eliandoran.me>",
|
||||
"license": "AGPL-3.0-only",
|
||||
"packageManager": "pnpm@10.22.0",
|
||||
"packageManager": "pnpm@10.24.0",
|
||||
"devDependencies": {
|
||||
"@redocly/cli": "2.11.1",
|
||||
"@redocly/cli": "2.12.0",
|
||||
"archiver": "7.0.1",
|
||||
"fs-extra": "11.3.2",
|
||||
"react": "19.2.0",
|
||||
"react-dom": "19.2.0",
|
||||
"typedoc": "0.28.14",
|
||||
"typedoc": "0.28.15",
|
||||
"typedoc-plugin-missing-exports": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@triliumnext/client",
|
||||
"version": "0.99.5",
|
||||
"version": "0.100.0",
|
||||
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0-only",
|
||||
@@ -25,7 +25,7 @@
|
||||
"@fullcalendar/timegrid": "6.1.19",
|
||||
"@maplibre/maplibre-gl-leaflet": "0.1.3",
|
||||
"@mermaid-js/layout-elk": "0.2.0",
|
||||
"@mind-elixir/node-menu": "5.0.0",
|
||||
"@mind-elixir/node-menu": "5.0.1",
|
||||
"@popperjs/core": "2.11.8",
|
||||
"@triliumnext/ckeditor5": "workspace:*",
|
||||
"@triliumnext/codemirror": "workspace:*",
|
||||
@@ -36,14 +36,13 @@
|
||||
"autocomplete.js": "0.38.1",
|
||||
"bootstrap": "5.3.8",
|
||||
"boxicons": "2.1.4",
|
||||
"color": "5.0.2",
|
||||
"dayjs": "1.11.19",
|
||||
"dayjs-plugin-utc": "0.1.2",
|
||||
"clsx": "2.1.1",
|
||||
"color": "5.0.3",
|
||||
"debounce": "3.0.0",
|
||||
"draggabilly": "3.0.0",
|
||||
"force-graph": "1.51.0",
|
||||
"globals": "16.5.0",
|
||||
"i18next": "25.6.2",
|
||||
"i18next": "25.6.3",
|
||||
"i18next-http-backend": "3.0.2",
|
||||
"jquery": "3.7.1",
|
||||
"jquery.fancytree": "2.38.5",
|
||||
@@ -53,13 +52,13 @@
|
||||
"leaflet": "1.9.4",
|
||||
"leaflet-gpx": "2.2.0",
|
||||
"mark.js": "8.11.1",
|
||||
"marked": "16.4.2",
|
||||
"marked": "17.0.1",
|
||||
"mermaid": "11.12.1",
|
||||
"mind-elixir": "5.3.5",
|
||||
"mind-elixir": "5.3.7",
|
||||
"normalize.css": "8.0.1",
|
||||
"panzoom": "9.4.3",
|
||||
"preact": "10.27.2",
|
||||
"react-i18next": "16.3.1",
|
||||
"react-i18next": "16.3.5",
|
||||
"reveal.js": "5.2.1",
|
||||
"svg-pan-zoom": "3.6.2",
|
||||
"tabulator-tables": "6.3.1",
|
||||
@@ -76,7 +75,7 @@
|
||||
"@types/reveal.js": "5.2.1",
|
||||
"@types/tabulator-tables": "6.3.0",
|
||||
"copy-webpack-plugin": "13.0.1",
|
||||
"happy-dom": "20.0.10",
|
||||
"happy-dom": "20.0.11",
|
||||
"script-loader": "0.7.2",
|
||||
"vite-plugin-static-copy": "3.1.4"
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@ type EventMappings = {
|
||||
error: string;
|
||||
};
|
||||
searchRefreshed: { ntxId?: string | null };
|
||||
textEditorRefreshed: { ntxId?: string | null, editor: CKTextEditor };
|
||||
hoistedNoteChanged: {
|
||||
noteId: string;
|
||||
ntxId: string | null;
|
||||
@@ -486,7 +487,7 @@ type EventMappings = {
|
||||
relationMapResetPanZoom: { ntxId: string | null | undefined };
|
||||
relationMapResetZoomIn: { ntxId: string | null | undefined };
|
||||
relationMapResetZoomOut: { ntxId: string | null | undefined };
|
||||
activeNoteChanged: {};
|
||||
activeNoteChanged: {ntxId: string | null | undefined};
|
||||
showAddLinkDialog: AddLinkOpts;
|
||||
showIncludeDialog: IncludeNoteOpts;
|
||||
openBulkActionsDialog: {
|
||||
|
||||
@@ -321,6 +321,10 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
||||
return false;
|
||||
}
|
||||
|
||||
if (note.type === "search") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!["default", "contextual-help"].includes(this.viewScope?.viewMode ?? "")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ export default class TabManager extends Component {
|
||||
const activeNoteContext = this.getActiveContext();
|
||||
this.updateDocumentTitle(activeNoteContext);
|
||||
|
||||
this.triggerEvent("activeNoteChanged", {}); // trigger this even in on popstate event
|
||||
this.triggerEvent("activeNoteChanged", {ntxId:activeNoteContext?.ntxId}); // trigger this even in on popstate event
|
||||
}
|
||||
|
||||
calculateHash(): string {
|
||||
@@ -647,7 +647,32 @@ export default class TabManager extends Component {
|
||||
...this.noteContexts.slice(-noteContexts.length),
|
||||
...this.noteContexts.slice(lastClosedTab.position, -noteContexts.length)
|
||||
];
|
||||
this.noteContextReorderEvent({ ntxIdsInOrder: ntxsInOrder.map((nc) => nc.ntxId).filter((id) => id !== null) });
|
||||
|
||||
// Update mainNtxId if the restored pane is the main pane in the split pane
|
||||
const { oldMainNtxId, newMainNtxId } = (() => {
|
||||
if (noteContexts.length !== 1) {
|
||||
return { oldMainNtxId: undefined, newMainNtxId: undefined };
|
||||
}
|
||||
|
||||
const mainNtxId = noteContexts[0]?.mainNtxId;
|
||||
const index = this.noteContexts.findIndex(c => c.ntxId === mainNtxId);
|
||||
|
||||
// No need to update if the restored position is after mainNtxId
|
||||
if (index === -1 || lastClosedTab.position > index) {
|
||||
return { oldMainNtxId: undefined, newMainNtxId: undefined };
|
||||
}
|
||||
|
||||
return {
|
||||
oldMainNtxId: this.noteContexts[index].ntxId ?? undefined,
|
||||
newMainNtxId: noteContexts[0]?.ntxId ?? undefined
|
||||
};
|
||||
})();
|
||||
|
||||
this.triggerCommand("noteContextReorder", {
|
||||
ntxIdsInOrder: ntxsInOrder.map((nc) => nc.ntxId).filter((id) => id !== null),
|
||||
oldMainNtxId,
|
||||
newMainNtxId
|
||||
});
|
||||
|
||||
let mainNtx = noteContexts.find((nc) => nc.isMainContext());
|
||||
if (mainNtx) {
|
||||
|
||||
@@ -58,6 +58,7 @@ function initOnElectron() {
|
||||
|
||||
initDarkOrLightMode(style);
|
||||
initTransparencyEffects(style, currentWindow);
|
||||
initFullScreenDetection(currentWindow);
|
||||
|
||||
if (options.get("nativeTitleBarVisible") !== "true") {
|
||||
initTitleBarButtons(style, currentWindow);
|
||||
@@ -87,6 +88,11 @@ function initTitleBarButtons(style: CSSStyleDeclaration, currentWindow: Electron
|
||||
}
|
||||
}
|
||||
|
||||
function initFullScreenDetection(currentWindow: Electron.BrowserWindow) {
|
||||
currentWindow.on("enter-full-screen", () => document.body.classList.add("full-screen"));
|
||||
currentWindow.on("leave-full-screen", () => document.body.classList.remove("full-screen"));
|
||||
}
|
||||
|
||||
function initTransparencyEffects(style: CSSStyleDeclaration, currentWindow: Electron.BrowserWindow) {
|
||||
if (window.glob.platform === "win32") {
|
||||
const material = style.getPropertyValue("--background-material");
|
||||
|
||||
@@ -240,7 +240,7 @@ export default class FNote {
|
||||
|
||||
const aNote = this.froca.getNoteFromCache(aNoteId);
|
||||
|
||||
if (aNote.isArchived || aNote.isHiddenCompletely()) {
|
||||
if (!aNote || aNote.isArchived || aNote.isHiddenCompletely()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -257,7 +257,9 @@ export default class FNote {
|
||||
}
|
||||
|
||||
async getChildNoteIdsWithArchiveFiltering(includeArchived = false) {
|
||||
if (!includeArchived) {
|
||||
const isHiddenNote = this.noteId.startsWith("_");
|
||||
const isSearchNote = this.type === "search";
|
||||
if (!includeArchived && !isHiddenNote && !isSearchNote) {
|
||||
const unorderedIds = new Set(await search.searchForNoteIds(`note.parents.noteId="${this.noteId}" #!archived`));
|
||||
const results: string[] = [];
|
||||
for (const id of this.children) {
|
||||
@@ -804,6 +806,16 @@ export default class FNote {
|
||||
return this.getAttributeValue(LABEL, name);
|
||||
}
|
||||
|
||||
getLabelOrRelation(nameWithPrefix: string) {
|
||||
if (nameWithPrefix.startsWith("#")) {
|
||||
return this.getLabelValue(nameWithPrefix.substring(1));
|
||||
} else if (nameWithPrefix.startsWith("~")) {
|
||||
return this.getRelationValue(nameWithPrefix.substring(1));
|
||||
} else {
|
||||
return this.getLabelValue(nameWithPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name - relation name
|
||||
* @returns relation value if relation exists, null otherwise
|
||||
|
||||
@@ -21,7 +21,6 @@ import NoteTreeWidget from "../widgets/note_tree.js";
|
||||
import NoteWrapperWidget from "../widgets/note_wrapper.js";
|
||||
import options from "../services/options.js";
|
||||
import PasswordNoteSetDialog from "../widgets/dialogs/password_not_set.js";
|
||||
import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
|
||||
import QuickSearchWidget from "../widgets/quick_search.js";
|
||||
import ReadOnlyNoteInfoBar from "../widgets/ReadOnlyNoteInfoBar.jsx";
|
||||
import Ribbon from "../widgets/ribbon/Ribbon.jsx";
|
||||
@@ -31,7 +30,6 @@ import ScrollingContainer from "../widgets/containers/scrolling_container.js";
|
||||
import ScrollPadding from "../widgets/scroll_padding.js";
|
||||
import SearchResult from "../widgets/search_result.jsx";
|
||||
import SharedInfo from "../widgets/shared_info.jsx";
|
||||
import OriginInfo from "../widgets/note_origin.jsx";
|
||||
import SpacerWidget from "../widgets/spacer.js";
|
||||
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
|
||||
import SqlResults from "../widgets/sql_result.js";
|
||||
@@ -45,6 +43,8 @@ import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js";
|
||||
import utils from "../services/utils.js";
|
||||
import WatchedFileUpdateStatusWidget from "../widgets/watched_file_update_status.js";
|
||||
import NoteDetail from "../widgets/NoteDetail.jsx";
|
||||
import RightPanelWidget from "../widgets/sidebar/RightPanelWidget.jsx";
|
||||
import PromotedAttributes from "../widgets/PromotedAttributes.jsx";
|
||||
|
||||
export default class DesktopLayout {
|
||||
|
||||
@@ -139,10 +139,9 @@ export default class DesktopLayout {
|
||||
.filling()
|
||||
.child(new ContentHeader()
|
||||
.child(<ReadOnlyNoteInfoBar />)
|
||||
.child(<OriginInfo />)
|
||||
.child(<SharedInfo />)
|
||||
)
|
||||
.child(new PromotedAttributesWidget())
|
||||
.child(<PromotedAttributes />)
|
||||
.child(<SqlTableSchemas />)
|
||||
.child(<NoteDetail />)
|
||||
.child(<NoteList media="screen" />)
|
||||
|
||||
@@ -22,16 +22,8 @@ import RevisionsDialog from "../widgets/dialogs/revisions.js";
|
||||
import DeleteNotesDialog from "../widgets/dialogs/delete_notes.js";
|
||||
import InfoDialog from "../widgets/dialogs/info.js";
|
||||
import IncorrectCpuArchDialog from "../widgets/dialogs/incorrect_cpu_arch.js";
|
||||
import PopupEditorDialog from "../widgets/dialogs/popup_editor.js";
|
||||
import FlexContainer from "../widgets/containers/flex_container.js";
|
||||
import NoteIconWidget from "../widgets/note_icon";
|
||||
import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
|
||||
import CallToActionDialog from "../widgets/dialogs/call_to_action.jsx";
|
||||
import NoteTitleWidget from "../widgets/note_title.jsx";
|
||||
import FormattingToolbar from "../widgets/ribbon/FormattingToolbar.js";
|
||||
import NoteList from "../widgets/collections/NoteList.jsx";
|
||||
import NoteDetail from "../widgets/NoteDetail.jsx";
|
||||
import StandaloneRibbonAdapter from "../widgets/ribbon/components/StandaloneRibbonAdapter.jsx";
|
||||
import PopupEditorDialog from "../widgets/dialogs/PopupEditor.jsx";
|
||||
|
||||
export function applyModals(rootContainer: RootContainer) {
|
||||
rootContainer
|
||||
@@ -57,16 +49,6 @@ export function applyModals(rootContainer: RootContainer) {
|
||||
.child(<ConfirmDialog />)
|
||||
.child(<PromptDialog />)
|
||||
.child(<IncorrectCpuArchDialog />)
|
||||
.child(new PopupEditorDialog()
|
||||
.child(new FlexContainer("row")
|
||||
.class("title-row")
|
||||
.css("align-items", "center")
|
||||
.cssBlock(".title-row > * { margin: 5px; }")
|
||||
.child(<NoteIconWidget />)
|
||||
.child(<NoteTitleWidget />))
|
||||
.child(<StandaloneRibbonAdapter component={FormattingToolbar} />)
|
||||
.child(new PromotedAttributesWidget())
|
||||
.child(<NoteDetail />)
|
||||
.child(<NoteList media="screen" displayOnlyCollections />))
|
||||
.child(<PopupEditorDialog />)
|
||||
.child(<CallToActionDialog />);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import NoteTitleWidget from "../widgets/note_title.js";
|
||||
import ContentHeader from "../widgets/containers/content_header.js";
|
||||
import NoteTreeWidget from "../widgets/note_tree.js";
|
||||
import NoteWrapperWidget from "../widgets/note_wrapper.js";
|
||||
import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
|
||||
import QuickSearchWidget from "../widgets/quick_search.js";
|
||||
import ReadOnlyNoteInfoBar from "../widgets/ReadOnlyNoteInfoBar.jsx";
|
||||
import RootContainer from "../widgets/containers/root_container.js";
|
||||
@@ -29,9 +28,12 @@ import ToggleSidebarButton from "../widgets/mobile_widgets/toggle_sidebar_button
|
||||
import type AppContext from "../components/app_context.js";
|
||||
import NoteDetail from "../widgets/NoteDetail.jsx";
|
||||
import MobileEditorToolbar from "../widgets/type_widgets/text/mobile_editor_toolbar.jsx";
|
||||
import PromotedAttributes from "../widgets/PromotedAttributes.jsx";
|
||||
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
|
||||
|
||||
const MOBILE_CSS = `
|
||||
<style>
|
||||
span.keyboard-shortcut,
|
||||
kbd {
|
||||
display: none;
|
||||
}
|
||||
@@ -141,33 +143,35 @@ export default class MobileLayout {
|
||||
.id("detail-container")
|
||||
.class("d-sm-flex d-md-flex d-lg-flex d-xl-flex col-12 col-sm-7 col-md-8 col-lg-9")
|
||||
.child(
|
||||
new NoteWrapperWidget()
|
||||
.child(
|
||||
new FlexContainer("row")
|
||||
.contentSized()
|
||||
.css("font-size", "larger")
|
||||
.css("align-items", "center")
|
||||
.child(<ToggleSidebarButton />)
|
||||
.child(<NoteTitleWidget />)
|
||||
.child(<MobileDetailMenu />)
|
||||
)
|
||||
.child(<FloatingButtons items={MOBILE_FLOATING_BUTTONS} />)
|
||||
.child(new PromotedAttributesWidget())
|
||||
.child(
|
||||
new ScrollingContainer()
|
||||
.filling()
|
||||
.contentSized()
|
||||
.child(new ContentHeader()
|
||||
.child(<ReadOnlyNoteInfoBar />)
|
||||
.child(<SharedInfoWidget />)
|
||||
)
|
||||
.child(<NoteDetail />)
|
||||
.child(<NoteList media="screen" />)
|
||||
.child(<StandaloneRibbonAdapter component={SearchDefinitionTab} />)
|
||||
.child(<SearchResult />)
|
||||
.child(<FilePropertiesWrapper />)
|
||||
)
|
||||
.child(<MobileEditorToolbar />)
|
||||
new SplitNoteContainer(() =>
|
||||
new NoteWrapperWidget()
|
||||
.child(
|
||||
new FlexContainer("row")
|
||||
.contentSized()
|
||||
.css("font-size", "larger")
|
||||
.css("align-items", "center")
|
||||
.child(<ToggleSidebarButton />)
|
||||
.child(<NoteTitleWidget />)
|
||||
.child(<MobileDetailMenu />)
|
||||
)
|
||||
.child(<FloatingButtons items={MOBILE_FLOATING_BUTTONS} />)
|
||||
.child(<PromotedAttributes />)
|
||||
.child(
|
||||
new ScrollingContainer()
|
||||
.filling()
|
||||
.contentSized()
|
||||
.child(new ContentHeader()
|
||||
.child(<ReadOnlyNoteInfoBar />)
|
||||
.child(<SharedInfoWidget />)
|
||||
)
|
||||
.child(<NoteDetail />)
|
||||
.child(<NoteList media="screen" />)
|
||||
.child(<StandaloneRibbonAdapter component={SearchDefinitionTab} />)
|
||||
.child(<SearchResult />)
|
||||
.child(<FilePropertiesWrapper />)
|
||||
)
|
||||
.child(<MobileEditorToolbar />)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@ import { KeyboardActionNames } from "@triliumnext/commons";
|
||||
import keyboardActionService, { getActionSync } from "../services/keyboard_actions.js";
|
||||
import note_tooltip from "../services/note_tooltip.js";
|
||||
import utils from "../services/utils.js";
|
||||
import { should } from "vitest";
|
||||
import { h, JSX, render } from "preact";
|
||||
|
||||
export interface ContextMenuOptions<T> {
|
||||
x: number;
|
||||
@@ -15,6 +15,11 @@ export interface ContextMenuOptions<T> {
|
||||
onHide?: () => void;
|
||||
}
|
||||
|
||||
export interface CustomMenuItem {
|
||||
kind: "custom",
|
||||
componentFn: () => JSX.Element | null;
|
||||
}
|
||||
|
||||
export interface MenuSeparatorItem {
|
||||
kind: "separator";
|
||||
}
|
||||
@@ -51,7 +56,7 @@ export interface MenuCommandItem<T> {
|
||||
columns?: number;
|
||||
}
|
||||
|
||||
export type MenuItem<T> = MenuCommandItem<T> | MenuSeparatorItem | MenuHeader;
|
||||
export type MenuItem<T> = MenuCommandItem<T> | CustomMenuItem | MenuSeparatorItem | MenuHeader;
|
||||
export type MenuHandler<T> = (item: MenuCommandItem<T>, e: JQuery.MouseDownEvent<HTMLElement, undefined, HTMLElement, HTMLElement>) => void;
|
||||
export type ContextMenuEvent = PointerEvent | MouseEvent | JQuery.ContextMenuEvent;
|
||||
|
||||
@@ -160,16 +165,19 @@ class ContextMenu {
|
||||
let $group = $parent; // The current group or parent element to which items are being appended
|
||||
let shouldStartNewGroup = false; // If true, the next item will start a new group
|
||||
let shouldResetGroup = false; // If true, the next item will be the last one from the group
|
||||
let prevItemKind: string = "";
|
||||
|
||||
for (let index = 0; index < items.length; index++) {
|
||||
const item = items[index];
|
||||
const itemKind = ("kind" in item) ? item.kind : "";
|
||||
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the current item is a header, start a new group. This group will contain the
|
||||
// header and the next item that follows the header.
|
||||
if ("kind" in item && item.kind === "header") {
|
||||
if (itemKind === "header") {
|
||||
if (multicolumn && !shouldResetGroup) {
|
||||
shouldStartNewGroup = true;
|
||||
}
|
||||
@@ -195,125 +203,25 @@ class ContextMenu {
|
||||
shouldStartNewGroup = false;
|
||||
}
|
||||
|
||||
if ("kind" in item && item.kind === "separator") {
|
||||
if (itemKind === "separator") {
|
||||
if (prevItemKind === "separator") {
|
||||
// Skip consecutive separators
|
||||
continue;
|
||||
}
|
||||
$group.append($("<div>").addClass("dropdown-divider"));
|
||||
shouldResetGroup = true; // End the group after the next item
|
||||
} else if ("kind" in item && item.kind === "header") {
|
||||
$group.append($("<h6>").addClass("dropdown-header").text(item.title));
|
||||
} else if (itemKind === "header") {
|
||||
$group.append($("<h6>").addClass("dropdown-header").text((item as MenuHeader).title));
|
||||
shouldResetGroup = true;
|
||||
} else {
|
||||
const $icon = $("<span>");
|
||||
|
||||
if ("uiIcon" in item || "checked" in item) {
|
||||
const icon = (item.checked ? "bx bx-check" : item.uiIcon);
|
||||
if (icon) {
|
||||
$icon.addClass(icon);
|
||||
} else {
|
||||
$icon.append(" ");
|
||||
}
|
||||
if (itemKind === "custom") {
|
||||
// Custom menu item
|
||||
$group.append(this.createCustomMenuItem(item as CustomMenuItem));
|
||||
} else {
|
||||
// Standard menu item
|
||||
$group.append(this.createMenuItem(item as MenuCommandItem<any>));
|
||||
}
|
||||
|
||||
const $link = $("<span>")
|
||||
.append($icon)
|
||||
.append(" ") // some space between icon and text
|
||||
.append(item.title);
|
||||
|
||||
if ("badges" in item && item.badges) {
|
||||
for (let badge of item.badges) {
|
||||
const badgeElement = $(`<span class="badge">`).text(badge.title);
|
||||
|
||||
if (badge.className) {
|
||||
badgeElement.addClass(badge.className);
|
||||
}
|
||||
|
||||
$link.append(badgeElement);
|
||||
}
|
||||
}
|
||||
|
||||
if ("keyboardShortcut" in item && item.keyboardShortcut) {
|
||||
const shortcuts = getActionSync(item.keyboardShortcut).effectiveShortcuts;
|
||||
if (shortcuts) {
|
||||
const allShortcuts: string[] = [];
|
||||
for (const effectiveShortcut of shortcuts) {
|
||||
allShortcuts.push(effectiveShortcut.split("+")
|
||||
.map(key => `<kbd>${key}</kbd>`)
|
||||
.join("+"));
|
||||
}
|
||||
|
||||
if (allShortcuts.length) {
|
||||
const container = $("<span>").addClass("keyboard-shortcut");
|
||||
container.append($(allShortcuts.join(",")));
|
||||
$link.append(container);
|
||||
}
|
||||
}
|
||||
} else if ("shortcut" in item && item.shortcut) {
|
||||
$link.append($("<kbd>").text(item.shortcut));
|
||||
}
|
||||
|
||||
const $item = $("<li>")
|
||||
.addClass("dropdown-item")
|
||||
.append($link)
|
||||
.on("contextmenu", (e) => false)
|
||||
// important to use mousedown instead of click since the former does not change focus
|
||||
// (especially important for focused text for spell check)
|
||||
.on("mousedown", (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (e.which !== 1) {
|
||||
// only left click triggers menu items
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isMobile && "items" in item && item.items) {
|
||||
const $item = $(e.target).closest(".dropdown-item");
|
||||
|
||||
$item.toggleClass("submenu-open");
|
||||
$item.find("ul.dropdown-menu").toggleClass("show");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("handler" in item && item.handler) {
|
||||
item.handler(item, e);
|
||||
}
|
||||
|
||||
this.options?.selectMenuItemHandler(item, e);
|
||||
|
||||
// it's important to stop the propagation especially for sub-menus, otherwise the event
|
||||
// might be handled again by top-level menu
|
||||
return false;
|
||||
});
|
||||
|
||||
$item.on("mouseup", (e) => {
|
||||
// Prevent submenu from failing to expand on mobile
|
||||
if (!this.isMobile || !("items" in item && item.items)) {
|
||||
e.stopPropagation();
|
||||
// Hide the content menu on mouse up to prevent the mouse event from propagating to the elements below.
|
||||
this.hide();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if ("enabled" in item && item.enabled !== undefined && !item.enabled) {
|
||||
$item.addClass("disabled");
|
||||
}
|
||||
|
||||
if ("items" in item && item.items) {
|
||||
$item.addClass("dropdown-submenu");
|
||||
$link.addClass("dropdown-toggle");
|
||||
|
||||
const $subMenu = $("<ul>").addClass("dropdown-menu");
|
||||
const hasColumns = !!item.columns && item.columns > 1;
|
||||
if (!this.isMobile && hasColumns) {
|
||||
$subMenu.css("column-count", item.columns!);
|
||||
}
|
||||
|
||||
this.addItems($subMenu, item.items, hasColumns);
|
||||
|
||||
$item.append($subMenu);
|
||||
}
|
||||
|
||||
$group.append($item);
|
||||
|
||||
// After adding a menu item, if the previous item was a separator or header,
|
||||
// reset the group so that the next item will be appended directly to the parent.
|
||||
if (shouldResetGroup) {
|
||||
@@ -321,9 +229,126 @@ class ContextMenu {
|
||||
shouldResetGroup = false;
|
||||
};
|
||||
}
|
||||
|
||||
prevItemKind = itemKind;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private createCustomMenuItem(item: CustomMenuItem) {
|
||||
const element = document.createElement("li");
|
||||
element.classList.add("dropdown-custom-item");
|
||||
element.onclick = () => this.hide();
|
||||
render(h(item.componentFn, {}), element);
|
||||
return element;
|
||||
}
|
||||
|
||||
private createMenuItem(item: MenuCommandItem<any>) {
|
||||
const $icon = $("<span>");
|
||||
|
||||
if ("uiIcon" in item || "checked" in item) {
|
||||
const icon = (item.checked ? "bx bx-check" : item.uiIcon);
|
||||
if (icon) {
|
||||
$icon.addClass(icon);
|
||||
} else {
|
||||
$icon.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
const $link = $("<span>")
|
||||
.append($icon)
|
||||
.append(" ") // some space between icon and text
|
||||
.append(item.title);
|
||||
|
||||
if ("badges" in item && item.badges) {
|
||||
for (let badge of item.badges) {
|
||||
const badgeElement = $(`<span class="badge">`).text(badge.title);
|
||||
|
||||
if (badge.className) {
|
||||
badgeElement.addClass(badge.className);
|
||||
}
|
||||
|
||||
$link.append(badgeElement);
|
||||
}
|
||||
}
|
||||
|
||||
if ("keyboardShortcut" in item && item.keyboardShortcut) {
|
||||
const shortcuts = getActionSync(item.keyboardShortcut).effectiveShortcuts;
|
||||
if (shortcuts) {
|
||||
const allShortcuts: string[] = [];
|
||||
for (const effectiveShortcut of shortcuts) {
|
||||
allShortcuts.push(effectiveShortcut.split("+")
|
||||
.map(key => `<kbd>${key}</kbd>`)
|
||||
.join("+"));
|
||||
}
|
||||
|
||||
if (allShortcuts.length) {
|
||||
const container = $("<span>").addClass("keyboard-shortcut");
|
||||
container.append($(allShortcuts.join(",")));
|
||||
$link.append(container);
|
||||
}
|
||||
}
|
||||
} else if ("shortcut" in item && item.shortcut) {
|
||||
$link.append($("<kbd>").text(item.shortcut));
|
||||
}
|
||||
|
||||
const $item = $("<li>")
|
||||
.addClass("dropdown-item")
|
||||
.append($link)
|
||||
.on("contextmenu", (e) => false)
|
||||
// important to use mousedown instead of click since the former does not change focus
|
||||
// (especially important for focused text for spell check)
|
||||
.on("mousedown", (e) => {
|
||||
if (e.which !== 1) {
|
||||
// only left click triggers menu items
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isMobile && "items" in item && item.items) {
|
||||
const $item = $(e.target).closest(".dropdown-item");
|
||||
|
||||
$item.toggleClass("submenu-open");
|
||||
$item.find("ul.dropdown-menu").toggleClass("show");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prevent submenu from failing to expand on mobile
|
||||
if (!("items" in item && item.items)) {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
if ("handler" in item && item.handler) {
|
||||
item.handler(item, e);
|
||||
}
|
||||
|
||||
this.options?.selectMenuItemHandler(item, e);
|
||||
|
||||
// it's important to stop the propagation especially for sub-menus, otherwise the event
|
||||
// might be handled again by top-level menu
|
||||
return false;
|
||||
});
|
||||
|
||||
if ("enabled" in item && item.enabled !== undefined && !item.enabled) {
|
||||
$item.addClass("disabled");
|
||||
}
|
||||
|
||||
if ("items" in item && item.items) {
|
||||
$item.addClass("dropdown-submenu");
|
||||
$link.addClass("dropdown-toggle");
|
||||
|
||||
const $subMenu = $("<ul>").addClass("dropdown-menu");
|
||||
const hasColumns = !!item.columns && item.columns > 1;
|
||||
if (!this.isMobile && hasColumns) {
|
||||
$subMenu.css("column-count", item.columns!);
|
||||
}
|
||||
|
||||
this.addItems($subMenu, item.items, hasColumns);
|
||||
|
||||
$item.append($subMenu);
|
||||
}
|
||||
return $item;
|
||||
}
|
||||
|
||||
async hide() {
|
||||
this.options?.onHide?.();
|
||||
this.$widget.removeClass("show");
|
||||
|
||||
21
apps/client/src/menus/context_menu_utils.ts
Normal file
21
apps/client/src/menus/context_menu_utils.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { t } from "../services/i18n"
|
||||
import attributes from "../services/attributes"
|
||||
import FNote from "../entities/fnote"
|
||||
|
||||
export function getArchiveMenuItem(note: FNote) {
|
||||
if (!note.isArchived) {
|
||||
return {
|
||||
title: t("board_view.archive-note"),
|
||||
uiIcon: "bx bx-archive",
|
||||
handler: () => attributes.addLabel(note.noteId, "archived")
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
title: t("board_view.unarchive-note"),
|
||||
uiIcon: "bx bx-archive-out",
|
||||
handler: async () => {
|
||||
attributes.removeOwnedLabelByName(note, "archived")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
86
apps/client/src/menus/custom-items/NoteColorPicker.css
Normal file
86
apps/client/src/menus/custom-items/NoteColorPicker.css
Normal file
@@ -0,0 +1,86 @@
|
||||
:root {
|
||||
--note-color-picker-clear-color-cell-background: var(--primary-button-background-color);
|
||||
--note-color-picker-clear-color-cell-color: var(--main-background-color);
|
||||
--note-color-picker-clear-color-cell-selection-outline-color: var(--primary-button-border-color);
|
||||
}
|
||||
|
||||
.note-color-picker {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.note-color-picker .color-cell {
|
||||
--color-picker-cell-size: 14px;
|
||||
|
||||
width: var(--color-picker-cell-size);
|
||||
height: var(--color-picker-cell-size);
|
||||
border-radius: 4px;
|
||||
background-color: var(--color);
|
||||
}
|
||||
|
||||
.note-color-picker .color-cell:not(.selected):hover {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.note-color-picker .color-cell.disabled-color-cell {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.note-color-picker .color-cell.selected {
|
||||
outline: 2px solid var(--outline-color, var(--color));
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/*
|
||||
* RESET COLOR CELL
|
||||
*/
|
||||
|
||||
.note-color-picker .color-cell-reset {
|
||||
--color: var(--note-color-picker-clear-color-cell-background);
|
||||
--outline-color: var(--note-color-picker-clear-color-cell-selection-outline-color);
|
||||
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.note-color-picker .color-cell-reset svg {
|
||||
width: var(--color-picker-cell-size);
|
||||
height: var(--color-picker-cell-size);
|
||||
fill: var(--note-color-picker-clear-color-cell-color);
|
||||
}
|
||||
|
||||
/*
|
||||
* CUSTOM COLOR CELL
|
||||
*/
|
||||
|
||||
.note-color-picker .custom-color-cell::before {
|
||||
position: absolute;
|
||||
content: "\ed35";
|
||||
display: flex;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
font-size: calc(var(--color-picker-cell-size) * 1.3);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: boxicons;
|
||||
font-size: 16px;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.note-color-picker .custom-color-cell {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.note-color-picker .custom-color-cell.custom-color-cell-empty {
|
||||
background-image: url(./custom-color.png);
|
||||
background-size: cover;
|
||||
--foreground: transparent;
|
||||
}
|
||||
204
apps/client/src/menus/custom-items/NoteColorPicker.tsx
Normal file
204
apps/client/src/menus/custom-items/NoteColorPicker.tsx
Normal file
@@ -0,0 +1,204 @@
|
||||
import "./NoteColorPicker.css";
|
||||
import { t } from "../../services/i18n";
|
||||
import { useCallback, useEffect, useRef, useState} from "preact/hooks";
|
||||
import {ComponentChildren} from "preact";
|
||||
import attributes from "../../services/attributes";
|
||||
import clsx from "clsx";
|
||||
import Color, { ColorInstance } from "color";
|
||||
import Debouncer from "../../utils/debouncer";
|
||||
import FNote from "../../entities/fnote";
|
||||
import froca from "../../services/froca";
|
||||
import { isMobile } from "../../services/utils";
|
||||
|
||||
const COLOR_PALETTE = [
|
||||
"#e64d4d", "#e6994d", "#e5e64d", "#99e64d", "#4de64d", "#4de699",
|
||||
"#4de5e6", "#4d99e6", "#4d4de6", "#994de6", "#e64db3"
|
||||
];
|
||||
|
||||
export interface NoteColorPickerProps {
|
||||
/** The target Note instance or its ID string. */
|
||||
note: FNote | string | null;
|
||||
}
|
||||
|
||||
export default function NoteColorPicker(props: NoteColorPickerProps) {
|
||||
if (!props.note) return null;
|
||||
|
||||
const [note, setNote] = useState<FNote | null>(null);
|
||||
const [currentColor, setCurrentColor] = useState<string | null>(null);
|
||||
const [isCustomColor, setIsCustomColor] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
const retrieveNote = async (noteId: string) => {
|
||||
const noteInstance = await froca.getNote(noteId, true);
|
||||
if (noteInstance) {
|
||||
setNote(noteInstance);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof props.note === "string") {
|
||||
retrieveNote(props.note); // Get the note from the given ID string
|
||||
} else {
|
||||
setNote(props.note);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const colorLabel = note?.getLabel("color")?.value ?? null;
|
||||
if (colorLabel) {
|
||||
let color = tryParseColor(colorLabel);
|
||||
if (color) {
|
||||
setCurrentColor(color.hex().toLowerCase());
|
||||
}
|
||||
}
|
||||
}, [note]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsCustomColor(currentColor !== null && COLOR_PALETTE.indexOf(currentColor) === -1);
|
||||
}, [currentColor])
|
||||
|
||||
const onColorCellClicked = useCallback((color: string | null) => {
|
||||
if (note) {
|
||||
if (color !== null) {
|
||||
attributes.setLabel(note.noteId, "color", color);
|
||||
} else {
|
||||
attributes.removeOwnedLabelByName(note, "color");
|
||||
}
|
||||
|
||||
setCurrentColor(color);
|
||||
}
|
||||
}, [note, currentColor]);
|
||||
|
||||
return <div className="note-color-picker">
|
||||
|
||||
<ColorCell className="color-cell-reset"
|
||||
tooltip={t("note-color.clear-color")}
|
||||
color={null}
|
||||
isSelected={(currentColor === null)}
|
||||
isDisabled={(note === null)}
|
||||
onSelect={onColorCellClicked}>
|
||||
|
||||
{/* https://pictogrammers.com/library/mdi/icon/close/ */}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" />
|
||||
</svg>
|
||||
</ColorCell>
|
||||
|
||||
|
||||
{COLOR_PALETTE.map((color) => (
|
||||
<ColorCell key={color}
|
||||
tooltip={t("note-color.set-color")}
|
||||
color={color}
|
||||
isSelected={(color === currentColor)}
|
||||
isDisabled={(note === null)}
|
||||
onSelect={onColorCellClicked} />
|
||||
))}
|
||||
|
||||
<CustomColorCell tooltip={t("note-color.set-custom-color")}
|
||||
color={currentColor}
|
||||
isSelected={isCustomColor}
|
||||
isDisabled={(note === null)}
|
||||
onSelect={onColorCellClicked} />
|
||||
</div>
|
||||
}
|
||||
|
||||
interface ColorCellProps {
|
||||
children?: ComponentChildren,
|
||||
className?: string,
|
||||
tooltip?: string,
|
||||
color: string | null,
|
||||
isSelected: boolean,
|
||||
isDisabled?: boolean,
|
||||
onSelect?: (color: string | null) => void
|
||||
}
|
||||
|
||||
function ColorCell(props: ColorCellProps) {
|
||||
return <div className={clsx(props.className, {
|
||||
"color-cell": true,
|
||||
"selected": props.isSelected,
|
||||
"disabled-color-cell": props.isDisabled
|
||||
})}
|
||||
style={`${(props.color !== null) ? `--color: ${props.color}` : ""}`}
|
||||
title={props.tooltip}
|
||||
onClick={() => props.onSelect?.(props.color)}>
|
||||
{props.children}
|
||||
</div>;
|
||||
}
|
||||
|
||||
function CustomColorCell(props: ColorCellProps) {
|
||||
const [pickedColor, setPickedColor] = useState<string | null>(null);
|
||||
const colorInput = useRef<HTMLInputElement>(null);
|
||||
const colorInputDebouncer = useRef<Debouncer<string | null> | null>(null);
|
||||
const callbackRef = useRef(props.onSelect);
|
||||
|
||||
useEffect(() => {
|
||||
colorInputDebouncer.current = new Debouncer(250, (color) => {
|
||||
callbackRef.current?.(color);
|
||||
setPickedColor(color);
|
||||
});
|
||||
|
||||
return () => {
|
||||
colorInputDebouncer.current?.destroy();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.isSelected && pickedColor === null) {
|
||||
setPickedColor(props.color);
|
||||
}
|
||||
}, [props.isSelected])
|
||||
|
||||
useEffect(() => {
|
||||
callbackRef.current = props.onSelect;
|
||||
}, [props.onSelect]);
|
||||
|
||||
const onSelect = useCallback(() => {
|
||||
if (pickedColor !== null) {
|
||||
callbackRef.current?.(pickedColor);
|
||||
}
|
||||
|
||||
colorInput.current?.click();
|
||||
}, [pickedColor]);
|
||||
|
||||
return <div style={`--foreground: ${getForegroundColor(props.color)};`}
|
||||
onClick={isMobile() ? (e) => {
|
||||
// The color picker dropdown will close on some browser if the parent context menu is
|
||||
// dismissed, so stop the click propagation to prevent dismissing the menu.
|
||||
e.stopPropagation();
|
||||
} : undefined}>
|
||||
<ColorCell {...props}
|
||||
color={pickedColor}
|
||||
className={clsx("custom-color-cell", {
|
||||
"custom-color-cell-empty": (pickedColor === null)
|
||||
})}
|
||||
onSelect={onSelect}>
|
||||
|
||||
<input ref={colorInput}
|
||||
type="color"
|
||||
value={pickedColor ?? props.color ?? "#40bfbf"}
|
||||
onChange={() => {colorInputDebouncer.current?.updateValue(colorInput.current?.value ?? null)}}
|
||||
style="width: 0; height: 0; opacity: 0" />
|
||||
</ColorCell>
|
||||
</div>
|
||||
}
|
||||
|
||||
function getForegroundColor(backgroundColor: string | null) {
|
||||
if (backgroundColor === null) return "inherit";
|
||||
|
||||
const colorHsl = tryParseColor(backgroundColor)?.hsl();
|
||||
if (colorHsl) {
|
||||
let l = colorHsl.lightness();
|
||||
return colorHsl.saturationl(0).lightness(l >= 50 ? 0 : 100).hex();
|
||||
} else {
|
||||
return "inherit";
|
||||
}
|
||||
}
|
||||
|
||||
function tryParseColor(colorStr: string): ColorInstance | null {
|
||||
try {
|
||||
return new Color(colorStr);
|
||||
} catch(ex) {
|
||||
console.error(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
BIN
apps/client/src/menus/custom-items/custom-color.png
Normal file
BIN
apps/client/src/menus/custom-items/custom-color.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
@@ -4,7 +4,7 @@ import zoomService from "../components/zoom.js";
|
||||
import contextMenu, { type MenuItem } from "./context_menu.js";
|
||||
import { t } from "../services/i18n.js";
|
||||
import type { BrowserWindow } from "electron";
|
||||
import type { CommandNames } from "../components/app_context.js";
|
||||
import type { CommandNames, AppContext } from "../components/app_context.js";
|
||||
|
||||
function setupContextMenu() {
|
||||
const electron = utils.dynamicRequire("electron");
|
||||
@@ -13,6 +13,8 @@ function setupContextMenu() {
|
||||
// FIXME: Remove typecast once Electron is properly integrated.
|
||||
const { webContents } = remote.getCurrentWindow() as BrowserWindow;
|
||||
|
||||
let appContext: AppContext;
|
||||
|
||||
webContents.on("context-menu", (event, params) => {
|
||||
const { editFlags } = params;
|
||||
const hasText = params.selectionText.trim().length > 0;
|
||||
@@ -119,6 +121,20 @@ function setupContextMenu() {
|
||||
uiIcon: "bx bx-search-alt",
|
||||
handler: () => electron.shell.openExternal(searchUrl)
|
||||
});
|
||||
|
||||
items.push({
|
||||
title: t("electron_context_menu.search_in_trilium", { term: shortenedSelection }),
|
||||
uiIcon: "bx bx-search",
|
||||
handler: async () => {
|
||||
if (!appContext) {
|
||||
appContext = (await import("../components/app_context.js")).default;
|
||||
}
|
||||
|
||||
await appContext.triggerCommand("searchNotes", {
|
||||
searchString: params.selectionText
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (items.length === 0) {
|
||||
|
||||
@@ -2,26 +2,32 @@ import { t } from "../services/i18n.js";
|
||||
import contextMenu, { type ContextMenuEvent, type MenuItem } from "./context_menu.js";
|
||||
import appContext, { type CommandNames } from "../components/app_context.js";
|
||||
import type { ViewScope } from "../services/link.js";
|
||||
import utils, { isMobile } from "../services/utils.js";
|
||||
import { getClosestNtxId } from "../widgets/widget_utils.js";
|
||||
import type { LeafletMouseEvent } from "leaflet";
|
||||
|
||||
function openContextMenu(notePath: string, e: ContextMenuEvent, viewScope: ViewScope = {}, hoistedNoteId: string | null = null) {
|
||||
contextMenu.show({
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
items: getItems(),
|
||||
selectMenuItemHandler: ({ command }) => handleLinkContextMenuItem(command, notePath, viewScope, hoistedNoteId)
|
||||
items: getItems(e),
|
||||
selectMenuItemHandler: ({ command }) => handleLinkContextMenuItem(command, e, notePath, viewScope, hoistedNoteId)
|
||||
});
|
||||
}
|
||||
|
||||
function getItems(): MenuItem<CommandNames>[] {
|
||||
function getItems(e: ContextMenuEvent | LeafletMouseEvent): MenuItem<CommandNames>[] {
|
||||
const ntxId = getNtxId(e);
|
||||
const isMobileSplitOpen = isMobile() && appContext.tabManager.getNoteContextById(ntxId).getMainContext().getSubContexts().length > 1;
|
||||
|
||||
return [
|
||||
{ title: t("link_context_menu.open_note_in_new_tab"), command: "openNoteInNewTab", uiIcon: "bx bx-link-external" },
|
||||
{ title: t("link_context_menu.open_note_in_new_split"), command: "openNoteInNewSplit", uiIcon: "bx bx-dock-right" },
|
||||
{ title: !isMobileSplitOpen ? t("link_context_menu.open_note_in_new_split") : t("link_context_menu.open_note_in_other_split"), command: "openNoteInNewSplit", uiIcon: "bx bx-dock-right" },
|
||||
{ title: t("link_context_menu.open_note_in_new_window"), command: "openNoteInNewWindow", uiIcon: "bx bx-window-open" },
|
||||
{ title: t("link_context_menu.open_note_in_popup"), command: "openNoteInPopup", uiIcon: "bx bx-edit" }
|
||||
];
|
||||
}
|
||||
|
||||
function handleLinkContextMenuItem(command: string | undefined, notePath: string, viewScope = {}, hoistedNoteId: string | null = null) {
|
||||
function handleLinkContextMenuItem(command: string | undefined, e: ContextMenuEvent | LeafletMouseEvent, notePath: string, viewScope = {}, hoistedNoteId: string | null = null) {
|
||||
if (!hoistedNoteId) {
|
||||
hoistedNoteId = appContext.tabManager.getActiveContext()?.hoistedNoteId ?? null;
|
||||
}
|
||||
@@ -29,15 +35,8 @@ function handleLinkContextMenuItem(command: string | undefined, notePath: string
|
||||
if (command === "openNoteInNewTab") {
|
||||
appContext.tabManager.openContextWithNote(notePath, { hoistedNoteId, viewScope });
|
||||
} else if (command === "openNoteInNewSplit") {
|
||||
const subContexts = appContext.tabManager.getActiveContext()?.getSubContexts();
|
||||
|
||||
if (!subContexts) {
|
||||
logError("subContexts is null");
|
||||
return;
|
||||
}
|
||||
|
||||
const { ntxId } = subContexts[subContexts.length - 1];
|
||||
|
||||
const ntxId = getNtxId(e);
|
||||
if (!ntxId) return;
|
||||
appContext.triggerCommand("openNewNoteSplit", { ntxId, notePath, hoistedNoteId, viewScope });
|
||||
} else if (command === "openNoteInNewWindow") {
|
||||
appContext.triggerCommand("openInWindow", { notePath, hoistedNoteId, viewScope });
|
||||
@@ -46,6 +45,18 @@ function handleLinkContextMenuItem(command: string | undefined, notePath: string
|
||||
}
|
||||
}
|
||||
|
||||
function getNtxId(e: ContextMenuEvent | LeafletMouseEvent) {
|
||||
if (utils.isDesktop()) {
|
||||
const subContexts = appContext.tabManager.getActiveContext()?.getSubContexts();
|
||||
if (!subContexts) return null;
|
||||
return subContexts[subContexts.length - 1].ntxId;
|
||||
} else if (e.target instanceof HTMLElement) {
|
||||
return getClosestNtxId(e.target);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
getItems,
|
||||
handleLinkContextMenuItem,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import NoteColorPicker from "./custom-items/NoteColorPicker.jsx";
|
||||
import treeService from "../services/tree.js";
|
||||
import froca from "../services/froca.js";
|
||||
import clipboard from "../services/clipboard.js";
|
||||
@@ -139,7 +140,13 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
|
||||
uiIcon: "bx bx-rename",
|
||||
enabled: isNotRoot && parentNotSearch && notOptionsOrHelp
|
||||
},
|
||||
{ title: t("tree-context-menu.convert-to-attachment"), command: "convertNoteToAttachment", uiIcon: "bx bx-paperclip", enabled: isNotRoot && !isHoisted && notOptionsOrHelp },
|
||||
{
|
||||
title:
|
||||
t("tree-context-menu.convert-to-attachment"),
|
||||
command: "convertNoteToAttachment",
|
||||
uiIcon: "bx bx-paperclip",
|
||||
enabled: isNotRoot && !isHoisted && notOptionsOrHelp && selectedNotes.some(note => note.isEligibleForConversionToAttachment())
|
||||
},
|
||||
|
||||
{ kind: "separator" },
|
||||
|
||||
@@ -241,6 +248,15 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
|
||||
enabled: isNotRoot && !isHoisted && parentNotSearch && notOptionsOrHelp
|
||||
},
|
||||
|
||||
{ kind: "separator"},
|
||||
|
||||
(notOptionsOrHelp && selectedNotes.length === 1) ? {
|
||||
kind: "custom",
|
||||
componentFn: () => {
|
||||
return NoteColorPicker({note});
|
||||
}
|
||||
} : null,
|
||||
|
||||
{ kind: "separator" },
|
||||
|
||||
{ title: t("tree-context-menu.import-into-note"), command: "importIntoNote", uiIcon: "bx bx-import", enabled: notSearch && noSelectedNotes && notOptionsOrHelp },
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import FNote from "./entities/fnote";
|
||||
import { render } from "preact";
|
||||
import { CustomNoteList } from "./widgets/collections/NoteList";
|
||||
import { CustomNoteList, useNoteViewType } from "./widgets/collections/NoteList";
|
||||
import { useCallback, useLayoutEffect, useRef } from "preact/hooks";
|
||||
import content_renderer from "./services/content_renderer";
|
||||
import { dynamicRequire, isElectron } from "./services/utils";
|
||||
import { applyInlineMermaid } from "./services/content_renderer_text";
|
||||
|
||||
interface RendererProps {
|
||||
note: FNote;
|
||||
onReady: () => void;
|
||||
onProgressChanged?: (progress: number) => void;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
@@ -23,13 +26,21 @@ async function main() {
|
||||
|
||||
function App({ note, noteId }: { note: FNote | null | undefined, noteId: string }) {
|
||||
const sentReadyEvent = useRef(false);
|
||||
const onProgressChanged = useCallback((progress: number) => {
|
||||
if (isElectron()) {
|
||||
const { ipcRenderer } = dynamicRequire('electron');
|
||||
ipcRenderer.send("print-progress", progress);
|
||||
} else {
|
||||
window.dispatchEvent(new CustomEvent("note-load-progress", { detail: { progress } }));
|
||||
}
|
||||
}, []);
|
||||
const onReady = useCallback(() => {
|
||||
if (sentReadyEvent.current) return;
|
||||
window.dispatchEvent(new Event("note-ready"));
|
||||
window._noteReady = true;
|
||||
sentReadyEvent.current = true;
|
||||
}, []);
|
||||
const props: RendererProps | undefined | null = note && { note, onReady };
|
||||
const props: RendererProps | undefined | null = note && { note, onReady, onProgressChanged };
|
||||
|
||||
if (!note || !props) return <Error404 noteId={noteId} />
|
||||
|
||||
@@ -71,6 +82,11 @@ function SingleNoteRenderer({ note, onReady }: RendererProps) {
|
||||
})
|
||||
);
|
||||
|
||||
// Initialize mermaid.
|
||||
if (note.type === "text") {
|
||||
await applyInlineMermaid(container);
|
||||
}
|
||||
|
||||
// Check custom CSS.
|
||||
await loadCustomCss(note);
|
||||
}
|
||||
@@ -84,8 +100,10 @@ function SingleNoteRenderer({ note, onReady }: RendererProps) {
|
||||
</>;
|
||||
}
|
||||
|
||||
function CollectionRenderer({ note, onReady }: RendererProps) {
|
||||
function CollectionRenderer({ note, onReady, onProgressChanged }: RendererProps) {
|
||||
const viewType = useNoteViewType(note);
|
||||
return <CustomNoteList
|
||||
viewType={viewType}
|
||||
isEnabled
|
||||
note={note}
|
||||
notePath={note.getBestNotePath().join("/")}
|
||||
@@ -96,6 +114,7 @@ function CollectionRenderer({ note, onReady }: RendererProps) {
|
||||
await loadCustomCss(note);
|
||||
onReady();
|
||||
}}
|
||||
onProgressChanged={onProgressChanged}
|
||||
/>;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,15 @@ export async function setLabel(noteId: string, name: string, value: string = "",
|
||||
});
|
||||
}
|
||||
|
||||
export async function setRelation(noteId: string, name: string, value: string = "", isInheritable = false) {
|
||||
await server.put(`notes/${noteId}/set-attribute`, {
|
||||
type: "relation",
|
||||
name: name,
|
||||
value: value,
|
||||
isInheritable
|
||||
});
|
||||
}
|
||||
|
||||
async function removeAttributeById(noteId: string, attributeId: string) {
|
||||
await server.remove(`notes/${noteId}/attributes/${attributeId}`);
|
||||
}
|
||||
@@ -51,6 +60,23 @@ function removeOwnedLabelByName(note: FNote, labelName: string) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a relation identified by its name from the given note, if it exists. Note that the relation must be owned, i.e.
|
||||
* it will not remove inherited attributes.
|
||||
*
|
||||
* @param note the note from which to remove the relation.
|
||||
* @param relationName the name of the relation to remove.
|
||||
* @returns `true` if an attribute was identified and removed, `false` otherwise.
|
||||
*/
|
||||
function removeOwnedRelationByName(note: FNote, relationName: string) {
|
||||
const relation = note.getOwnedRelation(relationName);
|
||||
if (relation) {
|
||||
removeAttributeById(note.noteId, relation.attributeId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the attribute of the given note to the provided value if its truthy, or removes the attribute if the value is falsy.
|
||||
* For an attribute with an empty value, pass an empty string instead.
|
||||
@@ -100,9 +126,7 @@ function isAffecting(attrRow: AttributeRow, affectedNote: FNote | null | undefin
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This doesn't seem right.
|
||||
//@ts-ignore
|
||||
if (this.isInheritable) {
|
||||
if (attrRow.isInheritable) {
|
||||
for (const owningNote of owningNotes) {
|
||||
if (owningNote.hasAncestor(attrNote.noteId, true)) {
|
||||
return true;
|
||||
@@ -116,8 +140,10 @@ function isAffecting(attrRow: AttributeRow, affectedNote: FNote | null | undefin
|
||||
export default {
|
||||
addLabel,
|
||||
setLabel,
|
||||
setRelation,
|
||||
setAttribute,
|
||||
removeAttributeById,
|
||||
removeOwnedLabelByName,
|
||||
removeOwnedRelationByName,
|
||||
isAffecting
|
||||
};
|
||||
|
||||
@@ -176,11 +176,6 @@ async function moveNodeUpInHierarchy(node: Fancytree.FancytreeNode) {
|
||||
toastService.showError(resp.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hoistedNoteService.isTopLevelNode(node) && node.getParent().getChildren().length <= 1) {
|
||||
node.getParent().folder = false;
|
||||
node.getParent().renderTitle();
|
||||
}
|
||||
}
|
||||
|
||||
function filterSearchBranches(branchIds: string[]) {
|
||||
|
||||
44
apps/client/src/services/bundle.spec.ts
Normal file
44
apps/client/src/services/bundle.spec.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { Bundle, executeBundle } from "./bundle";
|
||||
import { buildNote } from "../test/easy-froca";
|
||||
|
||||
describe("Script bundle", () => {
|
||||
it("dayjs is available", async () => {
|
||||
const script = /* js */`return api.dayjs().format("YYYY-MM-DD");`;
|
||||
const bundle = getBundle(script);
|
||||
const result = await executeBundle(bundle, null, $());
|
||||
expect(result).toMatch(/^\d{4}-\d{2}-\d{2}$/);
|
||||
});
|
||||
|
||||
it("dayjs is-same-or-before plugin exists", async () => {
|
||||
const script = /* js */`return api.dayjs("2023-10-01").isSameOrBefore(api.dayjs("2023-10-02"));`;
|
||||
const bundle = getBundle(script);
|
||||
const result = await executeBundle(bundle, null, $());
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
function getBundle(script: string) {
|
||||
const id = buildNote({
|
||||
title: "Script note"
|
||||
}).noteId;
|
||||
const bundle: Bundle = {
|
||||
script: [
|
||||
'',
|
||||
`apiContext.modules['${id}'] = { exports: {} };`,
|
||||
`return await ((async function(exports, module, require, api) {`,
|
||||
`try {`,
|
||||
`${script}`,
|
||||
`;`,
|
||||
`} catch (e) { throw new Error(\"Load of script note \\\"Client\\\" (${id}) failed with: \" + e.message); }`,
|
||||
`for (const exportKey in exports) module.exports[exportKey] = exports[exportKey];`,
|
||||
`return module.exports;`,
|
||||
`}).call({}, {}, apiContext.modules['${id}'], apiContext.require([]), apiContext.apis['${id}']));`,
|
||||
''
|
||||
].join('\n'),
|
||||
html: "",
|
||||
noteId: id,
|
||||
allNoteIds: [ id ]
|
||||
};
|
||||
return bundle;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ async function getAndExecuteBundle(noteId: string, originEntity = null, script =
|
||||
return await executeBundle(bundle, originEntity);
|
||||
}
|
||||
|
||||
async function executeBundle(bundle: Bundle, originEntity?: Entity | null, $container?: JQuery<HTMLElement>) {
|
||||
export async function executeBundle(bundle: Bundle, originEntity?: Entity | null, $container?: JQuery<HTMLElement>) {
|
||||
const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity, $container);
|
||||
|
||||
try {
|
||||
|
||||
@@ -2,24 +2,21 @@ import renderService from "./render.js";
|
||||
import protectedSessionService from "./protected_session.js";
|
||||
import protectedSessionHolder from "./protected_session_holder.js";
|
||||
import openService from "./open.js";
|
||||
import froca from "./froca.js";
|
||||
import utils from "./utils.js";
|
||||
import linkService from "./link.js";
|
||||
import treeService from "./tree.js";
|
||||
import FNote from "../entities/fnote.js";
|
||||
import FAttachment from "../entities/fattachment.js";
|
||||
import imageContextMenuService from "../menus/image_context_menu.js";
|
||||
import { applySingleBlockSyntaxHighlight, formatCodeBlocks } from "./syntax_highlight.js";
|
||||
import { applySingleBlockSyntaxHighlight } from "./syntax_highlight.js";
|
||||
import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js";
|
||||
import renderDoc from "./doc_renderer.js";
|
||||
import { t } from "../services/i18n.js";
|
||||
import WheelZoom from 'vanilla-js-wheel-zoom';
|
||||
import { renderMathInElement } from "./math.js";
|
||||
import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons";
|
||||
import renderText from "./content_renderer_text.js";
|
||||
|
||||
let idCounter = 1;
|
||||
|
||||
interface Options {
|
||||
export interface RenderOptions {
|
||||
tooltip?: boolean;
|
||||
trim?: boolean;
|
||||
imageHasZoom?: boolean;
|
||||
@@ -29,7 +26,7 @@ interface Options {
|
||||
|
||||
const CODE_MIME_TYPES = new Set(["application/json"]);
|
||||
|
||||
export async function getRenderedContent(this: {} | { ctx: string }, entity: FNote | FAttachment, options: Options = {}) {
|
||||
export async function getRenderedContent(this: {} | { ctx: string }, entity: FNote | FAttachment, options: RenderOptions = {}) {
|
||||
|
||||
options = Object.assign(
|
||||
{
|
||||
@@ -116,32 +113,6 @@ export async function getRenderedContent(this: {} | { ctx: string }, entity: FNo
|
||||
};
|
||||
}
|
||||
|
||||
async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HTMLElement>, options: Options = {}) {
|
||||
// entity must be FNote
|
||||
const blob = await note.getBlob();
|
||||
|
||||
if (blob && !utils.isHtmlEmpty(blob.content)) {
|
||||
$renderedContent.append($('<div class="ck-content">').html(blob.content));
|
||||
|
||||
if ($renderedContent.find("span.math-tex").length > 0) {
|
||||
renderMathInElement($renderedContent[0], { trust: true });
|
||||
}
|
||||
|
||||
const getNoteIdFromLink = (el: HTMLElement) => treeService.getNoteIdFromUrl($(el).attr("href") || "");
|
||||
const referenceLinks = $renderedContent.find("a.reference-link");
|
||||
const noteIdsToPrefetch = referenceLinks.map((i, el) => getNoteIdFromLink(el));
|
||||
await froca.getNotes(noteIdsToPrefetch);
|
||||
|
||||
for (const el of referenceLinks) {
|
||||
await linkService.loadReferenceLinkTitle($(el));
|
||||
}
|
||||
|
||||
await formatCodeBlocks($renderedContent);
|
||||
} else if (note instanceof FNote && !options.noChildrenList) {
|
||||
await renderChildrenList($renderedContent, note);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a code note, by displaying its content and applying syntax highlighting based on the selected MIME type.
|
||||
*/
|
||||
@@ -163,7 +134,7 @@ async function renderCode(note: FNote | FAttachment, $renderedContent: JQuery<HT
|
||||
await applySingleBlockSyntaxHighlight($codeBlock, normalizeMimeTypeForCKEditor(note.mime));
|
||||
}
|
||||
|
||||
function renderImage(entity: FNote | FAttachment, $renderedContent: JQuery<HTMLElement>, options: Options = {}) {
|
||||
function renderImage(entity: FNote | FAttachment, $renderedContent: JQuery<HTMLElement>, options: RenderOptions = {}) {
|
||||
const encodedTitle = encodeURIComponent(entity.title);
|
||||
|
||||
let url;
|
||||
@@ -305,40 +276,6 @@ async function renderMermaid(note: FNote | FAttachment, $renderedContent: JQuery
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {jQuery} $renderedContent
|
||||
* @param {FNote} note
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function renderChildrenList($renderedContent: JQuery<HTMLElement>, note: FNote) {
|
||||
let childNoteIds = note.getChildNoteIds();
|
||||
|
||||
if (!childNoteIds.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
$renderedContent.css("padding", "10px");
|
||||
$renderedContent.addClass("text-with-ellipsis");
|
||||
|
||||
if (childNoteIds.length > 10) {
|
||||
childNoteIds = childNoteIds.slice(0, 10);
|
||||
}
|
||||
|
||||
// just load the first 10 child notes
|
||||
const childNotes = await froca.getNotes(childNoteIds);
|
||||
|
||||
for (const childNote of childNotes) {
|
||||
$renderedContent.append(
|
||||
await linkService.createLink(`${note.noteId}/${childNote.noteId}`, {
|
||||
showTooltip: false,
|
||||
showNoteIcon: true
|
||||
})
|
||||
);
|
||||
|
||||
$renderedContent.append("<br>");
|
||||
}
|
||||
}
|
||||
|
||||
function getRenderingType(entity: FNote | FAttachment) {
|
||||
let type: string = "";
|
||||
if ("type" in entity) {
|
||||
|
||||
126
apps/client/src/services/content_renderer_text.ts
Normal file
126
apps/client/src/services/content_renderer_text.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import { formatCodeBlocks } from "./syntax_highlight.js";
|
||||
import { getMermaidConfig } from "./mermaid.js";
|
||||
import { renderMathInElement } from "./math.js";
|
||||
import FNote from "../entities/fnote.js";
|
||||
import FAttachment from "../entities/fattachment.js";
|
||||
import tree from "./tree.js";
|
||||
import froca from "./froca.js";
|
||||
import link from "./link.js";
|
||||
import { isHtmlEmpty } from "./utils.js";
|
||||
import { default as content_renderer, type RenderOptions } from "./content_renderer.js";
|
||||
|
||||
export default async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HTMLElement>, options: RenderOptions = {}) {
|
||||
// entity must be FNote
|
||||
const blob = await note.getBlob();
|
||||
|
||||
if (blob && !isHtmlEmpty(blob.content)) {
|
||||
$renderedContent.append($('<div class="ck-content">').html(blob.content));
|
||||
await renderIncludedNotes($renderedContent[0]);
|
||||
|
||||
if ($renderedContent.find("span.math-tex").length > 0) {
|
||||
renderMathInElement($renderedContent[0], { trust: true });
|
||||
}
|
||||
|
||||
const getNoteIdFromLink = (el: HTMLElement) => tree.getNoteIdFromUrl($(el).attr("href") || "");
|
||||
const referenceLinks = $renderedContent.find("a.reference-link");
|
||||
const noteIdsToPrefetch = referenceLinks.map((i, el) => getNoteIdFromLink(el));
|
||||
await froca.getNotes(noteIdsToPrefetch);
|
||||
|
||||
for (const el of referenceLinks) {
|
||||
await link.loadReferenceLinkTitle($(el));
|
||||
}
|
||||
|
||||
await rewriteMermaidDiagramsInContainer($renderedContent[0] as HTMLDivElement);
|
||||
await formatCodeBlocks($renderedContent);
|
||||
} else if (note instanceof FNote && !options.noChildrenList) {
|
||||
await renderChildrenList($renderedContent, note);
|
||||
}
|
||||
}
|
||||
|
||||
async function renderIncludedNotes(contentEl: HTMLElement) {
|
||||
// TODO: Consider duplicating with server's share/content_renderer.ts.
|
||||
const includeNoteEls = contentEl.querySelectorAll("section.include-note");
|
||||
|
||||
// Gather the list of items to load.
|
||||
const noteIds: string[] = [];
|
||||
for (const includeNoteEl of includeNoteEls) {
|
||||
const noteId = includeNoteEl.getAttribute("data-note-id");
|
||||
if (noteId) {
|
||||
noteIds.push(noteId);
|
||||
}
|
||||
}
|
||||
|
||||
// Load the required notes.
|
||||
await froca.getNotes(noteIds);
|
||||
|
||||
// Render and integrate the notes.
|
||||
for (const includeNoteEl of includeNoteEls) {
|
||||
const noteId = includeNoteEl.getAttribute("data-note-id");
|
||||
if (!noteId) continue;
|
||||
|
||||
const note = froca.getNoteFromCache(noteId);
|
||||
if (!note) {
|
||||
console.warn(`Unable to include ${noteId} because it could not be found.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const renderedContent = (await content_renderer.getRenderedContent(note)).$renderedContent;
|
||||
includeNoteEl.replaceChildren(...renderedContent);
|
||||
}
|
||||
}
|
||||
|
||||
/** Rewrite the code block from <pre><code> to <div> in order not to apply a codeblock style to it. */
|
||||
export async function rewriteMermaidDiagramsInContainer(container: HTMLDivElement) {
|
||||
const mermaidBlocks = container.querySelectorAll('pre:has(code[class="language-mermaid"])');
|
||||
if (!mermaidBlocks.length) return;
|
||||
const nodes: HTMLElement[] = [];
|
||||
|
||||
for (const mermaidBlock of mermaidBlocks) {
|
||||
const div = document.createElement("div");
|
||||
div.classList.add("mermaid-diagram");
|
||||
div.innerHTML = mermaidBlock.querySelector("code")?.innerHTML ?? "";
|
||||
mermaidBlock.replaceWith(div);
|
||||
nodes.push(div);
|
||||
}
|
||||
}
|
||||
|
||||
export async function applyInlineMermaid(container: HTMLDivElement) {
|
||||
// Initialize mermaid
|
||||
const mermaid = (await import("mermaid")).default;
|
||||
mermaid.initialize(getMermaidConfig());
|
||||
const nodes = Array.from(container.querySelectorAll<HTMLElement>("div.mermaid-diagram"));
|
||||
try {
|
||||
await mermaid.run({ nodes });
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
async function renderChildrenList($renderedContent: JQuery<HTMLElement>, note: FNote) {
|
||||
let childNoteIds = note.getChildNoteIds();
|
||||
|
||||
if (!childNoteIds.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
$renderedContent.css("padding", "10px");
|
||||
$renderedContent.addClass("text-with-ellipsis");
|
||||
|
||||
if (childNoteIds.length > 10) {
|
||||
childNoteIds = childNoteIds.slice(0, 10);
|
||||
}
|
||||
|
||||
// just load the first 10 child notes
|
||||
const childNotes = await froca.getNotes(childNoteIds);
|
||||
|
||||
for (const childNote of childNotes) {
|
||||
$renderedContent.append(
|
||||
await link.createLink(`${note.noteId}/${childNote.noteId}`, {
|
||||
showTooltip: false,
|
||||
showNoteIcon: true
|
||||
})
|
||||
);
|
||||
|
||||
$renderedContent.append("<br>");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import clsx from "clsx";
|
||||
import {readCssVar} from "../utils/css-var";
|
||||
import Color, { ColorInstance } from "color";
|
||||
|
||||
const registeredClasses = new Set<string>();
|
||||
const colorsWithHue = new Set<string>();
|
||||
|
||||
// Read the color lightness limits defined in the theme as CSS variables
|
||||
|
||||
@@ -26,19 +28,23 @@ function createClassForColor(colorString: string | null) {
|
||||
if (!registeredClasses.has(className)) {
|
||||
const adjustedColor = adjustColorLightness(color, lightThemeColorMaxLightness!,
|
||||
darkThemeColorMinLightness!);
|
||||
const hue = getHue(color);
|
||||
|
||||
$("head").append(`<style>
|
||||
.${className}, span.fancytree-active.${className} {
|
||||
--light-theme-custom-color: ${adjustedColor.lightThemeColor};
|
||||
--dark-theme-custom-color: ${adjustedColor.darkThemeColor};
|
||||
--custom-color-hue: ${getHue(color) ?? 'unset'};
|
||||
--custom-color-hue: ${hue ?? 'unset'};
|
||||
}
|
||||
</style>`);
|
||||
|
||||
registeredClasses.add(className);
|
||||
if (hue !== undefined) {
|
||||
colorsWithHue.add(className);
|
||||
}
|
||||
}
|
||||
|
||||
return className;
|
||||
return clsx("use-note-color", className, colorsWithHue.has(className) && "with-hue");
|
||||
}
|
||||
|
||||
function parseColor(color: string) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import dayjs from "dayjs";
|
||||
import { dayjs } from "@triliumnext/commons";
|
||||
import type { FNoteRow } from "../entities/fnote.js";
|
||||
import froca from "./froca.js";
|
||||
import server from "./server.js";
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* @param whether to execute at the beginning (`false`)
|
||||
* @api public
|
||||
*/
|
||||
function debounce<T>(func: (...args: unknown[]) => T, waitMs: number, immediate: boolean = false) {
|
||||
function debounce<T>(func: (...args: any[]) => T, waitMs: number, immediate: boolean = false) {
|
||||
let timeout: any; // TODO: fix once we split client and server.
|
||||
let args: unknown[] | null;
|
||||
let context: unknown;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type FNote from "../entities/fnote.js";
|
||||
import { applyReferenceLinks } from "../widgets/type_widgets/text/read_only_helper.js";
|
||||
import { getCurrentLanguage } from "./i18n.js";
|
||||
import { formatCodeBlocks } from "./syntax_highlight.js";
|
||||
|
||||
@@ -10,18 +11,18 @@ export default function renderDoc(note: FNote) {
|
||||
if (docName) {
|
||||
// find doc based on language
|
||||
const url = getUrl(docName, getCurrentLanguage());
|
||||
$content.load(url, (response, status) => {
|
||||
$content.load(url, async (response, status) => {
|
||||
// fallback to english doc if no translation available
|
||||
if (status === "error") {
|
||||
const fallbackUrl = getUrl(docName, "en");
|
||||
$content.load(fallbackUrl, () => {
|
||||
processContent(fallbackUrl, $content)
|
||||
$content.load(fallbackUrl, async () => {
|
||||
await processContent(fallbackUrl, $content)
|
||||
resolve($content);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
processContent(url, $content);
|
||||
await processContent(url, $content);
|
||||
resolve($content);
|
||||
});
|
||||
} else {
|
||||
@@ -32,7 +33,7 @@ export default function renderDoc(note: FNote) {
|
||||
});
|
||||
}
|
||||
|
||||
function processContent(url: string, $content: JQuery<HTMLElement>) {
|
||||
async function processContent(url: string, $content: JQuery<HTMLElement>) {
|
||||
const dir = url.substring(0, url.lastIndexOf("/"));
|
||||
|
||||
// Images are relative to the docnote but that will not work when rendered in the application since the path breaks.
|
||||
@@ -42,6 +43,9 @@ function processContent(url: string, $content: JQuery<HTMLElement>) {
|
||||
});
|
||||
|
||||
formatCodeBlocks($content);
|
||||
|
||||
// Apply reference links.
|
||||
await applyReferenceLinks($content[0]);
|
||||
}
|
||||
|
||||
function getUrl(docNameValue: string, language: string) {
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface Froca {
|
||||
|
||||
getBlob(entityType: string, entityId: string): Promise<FBlob | null>;
|
||||
getNote(noteId: string, silentNotFoundError?: boolean): Promise<FNote | null>;
|
||||
getNoteFromCache(noteId: string): FNote;
|
||||
getNoteFromCache(noteId: string): FNote | undefined;
|
||||
getNotesFromCache(noteIds: string[], silentNotFoundError?: boolean): FNote[];
|
||||
getNotes(noteIds: string[], silentNotFoundError?: boolean): Promise<FNote[]>;
|
||||
|
||||
|
||||
@@ -288,7 +288,7 @@ class FrocaImpl implements Froca {
|
||||
return (await this.getNotes([noteId], silentNotFoundError))[0];
|
||||
}
|
||||
|
||||
getNoteFromCache(noteId: string) {
|
||||
getNoteFromCache(noteId: string): FNote | undefined {
|
||||
if (!noteId) {
|
||||
throw new Error("Empty noteId");
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import shortcutService from "./shortcuts.js";
|
||||
import dialogService from "./dialog.js";
|
||||
import type FNote from "../entities/fnote.js";
|
||||
import { t } from "./i18n.js";
|
||||
import dayjs from "dayjs";
|
||||
import { dayjs } from "@triliumnext/commons";
|
||||
import type NoteContext from "../components/note_context.js";
|
||||
import type Component from "../components/component.js";
|
||||
import { formatLogMessage } from "@triliumnext/commons";
|
||||
|
||||
@@ -2,7 +2,7 @@ import options from "./options.js";
|
||||
import i18next from "i18next";
|
||||
import i18nextHttpBackend from "i18next-http-backend";
|
||||
import server from "./server.js";
|
||||
import type { Locale } from "@triliumnext/commons";
|
||||
import { LOCALE_IDS, setDayjsLocale, type Locale } from "@triliumnext/commons";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
|
||||
let locales: Locale[] | null;
|
||||
@@ -13,7 +13,7 @@ let locales: Locale[] | null;
|
||||
export let translationsInitializedPromise = $.Deferred();
|
||||
|
||||
export async function initLocale() {
|
||||
const locale = (options.get("locale") as string) || "en";
|
||||
const locale = ((options.get("locale") as string) || "en") as LOCALE_IDS;
|
||||
|
||||
locales = await server.get<Locale[]>("options/locales");
|
||||
|
||||
@@ -27,6 +27,7 @@ export async function initLocale() {
|
||||
returnEmptyString: false
|
||||
});
|
||||
|
||||
await setDayjsLocale(locale);
|
||||
translationsInitializedPromise.resolve();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,13 +28,17 @@ async function getActionsForScope(scope: string) {
|
||||
return actions.filter((action) => action.scope === scope);
|
||||
}
|
||||
|
||||
async function setupActionsForElement(scope: string, $el: JQuery<HTMLElement>, component: Component) {
|
||||
async function setupActionsForElement(scope: string, $el: JQuery<HTMLElement>, component: Component, ntxId: string | null | undefined) {
|
||||
if (!$el[0]) return [];
|
||||
|
||||
const actions = await getActionsForScope(scope);
|
||||
const bindings: ShortcutBinding[] = [];
|
||||
|
||||
for (const action of actions) {
|
||||
for (const shortcut of action.effectiveShortcuts ?? []) {
|
||||
const binding = shortcutService.bindElShortcut($el, shortcut, () => component.triggerCommand(action.actionName, { ntxId: appContext.tabManager.activeNtxId }));
|
||||
const binding = shortcutService.bindElShortcut($el, shortcut, () => {
|
||||
component.triggerCommand(action.actionName, { ntxId });
|
||||
});
|
||||
if (binding) {
|
||||
bindings.push(binding);
|
||||
}
|
||||
|
||||
@@ -150,11 +150,16 @@ async function createLink(notePath: string | undefined, options: CreateLinkOptio
|
||||
$container.append($noteLink);
|
||||
|
||||
if (showNotePath) {
|
||||
const resolvedPathSegments = (await treeService.resolveNotePathToSegments(notePath)) || [];
|
||||
resolvedPathSegments.pop(); // Remove last element
|
||||
let pathSegments: string[];
|
||||
if (notePath == "root") {
|
||||
pathSegments = ["⌂"];
|
||||
} else {
|
||||
const resolvedPathSegments = (await treeService.resolveNotePathToSegments(notePath)) || [];
|
||||
resolvedPathSegments.pop(); // Remove last element
|
||||
|
||||
const resolvedPath = resolvedPathSegments.join("/");
|
||||
const pathSegments = await treeService.getNotePathTitleComponents(resolvedPath);
|
||||
const resolvedPath = resolvedPathSegments.join("/");
|
||||
pathSegments = await treeService.getNotePathTitleComponents(resolvedPath);
|
||||
}
|
||||
|
||||
if (pathSegments) {
|
||||
if (pathSegments.length) {
|
||||
@@ -302,7 +307,8 @@ export function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDo
|
||||
// Right click is handled separately.
|
||||
const isMiddleClick = evt && "which" in evt && evt.which === 2;
|
||||
const targetIsBlank = ($link?.attr("target") === "_blank");
|
||||
const openInNewTab = (isLeftClick && ctrlKey) || isMiddleClick || targetIsBlank;
|
||||
const isDoubleClick = isLeftClick && evt?.type === "dblclick";
|
||||
const openInNewTab = (isLeftClick && ctrlKey) || isDoubleClick || isMiddleClick || targetIsBlank;
|
||||
const activate = (isLeftClick && ctrlKey && shiftKey) || (isMiddleClick && shiftKey);
|
||||
const openInNewWindow = isLeftClick && evt?.shiftKey && !ctrlKey;
|
||||
|
||||
@@ -323,16 +329,18 @@ export function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDo
|
||||
const withinEditLink = $link?.hasClass("ck-link-actions__preview");
|
||||
const outsideOfCKEditor = !$link || $link.closest("[contenteditable]").length === 0;
|
||||
|
||||
if (openInNewTab || (withinEditLink && (isLeftClick || isMiddleClick)) || (outsideOfCKEditor && (isLeftClick || isMiddleClick))) {
|
||||
if (openInNewTab || openInNewWindow || (isLeftClick && (withinEditLink || outsideOfCKEditor))) {
|
||||
if (hrefLink.toLowerCase().startsWith("http") || hrefLink.startsWith("api/")) {
|
||||
window.open(hrefLink, "_blank");
|
||||
} else if ((hrefLink.toLowerCase().startsWith("file:") || hrefLink.toLowerCase().startsWith("geo:")) && utils.isElectron()) {
|
||||
const electron = utils.dynamicRequire("electron");
|
||||
electron.shell.openPath(hrefLink);
|
||||
} else {
|
||||
// Enable protocols supported by CKEditor 5 to be clickable.
|
||||
if (ALLOWED_PROTOCOLS.some((protocol) => hrefLink.toLowerCase().startsWith(protocol + ":"))) {
|
||||
window.open(hrefLink, "_blank");
|
||||
if ( utils.isElectron()) {
|
||||
const electron = utils.dynamicRequire("electron");
|
||||
electron.shell.openExternal(hrefLink);
|
||||
} else {
|
||||
window.open(hrefLink, "_blank");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -459,37 +467,30 @@ function getReferenceLinkTitleSync(href: string) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check why the event is not supported.
|
||||
//@ts-ignore
|
||||
$(document).on("click", "a", goToLink);
|
||||
// TODO: Check why the event is not supported.
|
||||
//@ts-ignore
|
||||
$(document).on("auxclick", "a", goToLink); // to handle the middle button
|
||||
// TODO: Check why the event is not supported.
|
||||
//@ts-ignore
|
||||
$(document).on("contextmenu", "a", linkContextMenu);
|
||||
$(document).on("dblclick", "a", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (glob.device !== "print") {
|
||||
// TODO: Check why the event is not supported.
|
||||
//@ts-ignore
|
||||
$(document).on("click", "a", goToLink);
|
||||
// TODO: Check why the event is not supported.
|
||||
//@ts-ignore
|
||||
$(document).on("auxclick", "a", goToLink); // to handle the middle button
|
||||
// TODO: Check why the event is not supported.
|
||||
//@ts-ignore
|
||||
$(document).on("contextmenu", "a", linkContextMenu);
|
||||
// TODO: Check why the event is not supported.
|
||||
//@ts-ignore
|
||||
$(document).on("dblclick", "a", goToLink);
|
||||
|
||||
const $link = $(e.target).closest("a");
|
||||
|
||||
const address = $link.attr("href");
|
||||
|
||||
if (address && address.startsWith("http")) {
|
||||
window.open(address, "_blank");
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("mousedown", "a", (e) => {
|
||||
if (e.which === 2) {
|
||||
// prevent paste on middle click
|
||||
// https://github.com/zadam/trilium/issues/2995
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Element/auxclick_event#preventing_default_actions
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
$(document).on("mousedown", "a", (e) => {
|
||||
if (e.which === 2) {
|
||||
// prevent paste on middle click
|
||||
// https://github.com/zadam/trilium/issues/2995
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Element/auxclick_event#preventing_default_actions
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
getNotePathFromUrl,
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
import type { AttachmentRow, EtapiTokenRow, OptionNames } from "@triliumnext/commons";
|
||||
import type { AttachmentRow, EtapiTokenRow, NoteType, OptionNames } from "@triliumnext/commons";
|
||||
import type { AttributeType } from "../entities/fattribute.js";
|
||||
import type { EntityChange } from "../server_types.js";
|
||||
|
||||
// TODO: Deduplicate with server.
|
||||
|
||||
interface NoteRow {
|
||||
blobId: string;
|
||||
dateCreated: string;
|
||||
dateModified: string;
|
||||
isDeleted?: boolean;
|
||||
isProtected?: boolean;
|
||||
mime: string;
|
||||
noteId: string;
|
||||
title: string;
|
||||
type: NoteType;
|
||||
utcDateCreated: string;
|
||||
utcDateModified: string;
|
||||
}
|
||||
|
||||
// TODO: Deduplicate with BranchRow from `rows.ts`/
|
||||
|
||||
@@ -41,6 +41,17 @@ function parse(value: string) {
|
||||
return defObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* For an attribute definition name (e.g. `label:TEST:TEST1`), extracts its type (label) and name (TEST:TEST1).
|
||||
* @param definitionAttrName the attribute definition name, without the leading `#` (e.g. `label:TEST:TEST1`)
|
||||
* @return a tuple of [type, name].
|
||||
*/
|
||||
export function extractAttributeDefinitionTypeAndName(definitionAttrName: string): [ "label" | "relation", string ] {
|
||||
const valueType = definitionAttrName.startsWith("label:") ? "label" : "relation";
|
||||
const valueName = definitionAttrName.substring(valueType.length + 1);
|
||||
return [ valueType, valueName ];
|
||||
}
|
||||
|
||||
export default {
|
||||
parse
|
||||
};
|
||||
|
||||
@@ -8,46 +8,50 @@ export interface ToastOptions {
|
||||
delay?: number;
|
||||
autohide?: boolean;
|
||||
closeAfter?: number;
|
||||
progress?: number;
|
||||
}
|
||||
|
||||
function toast(options: ToastOptions) {
|
||||
const $toast = $(options.title
|
||||
function toast({ title, icon, message, id, delay, autohide, progress }: ToastOptions) {
|
||||
const $toast = $(title
|
||||
? `\
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header">
|
||||
<strong class="me-auto">
|
||||
<span class="bx bx-${options.icon}"></span>
|
||||
<span class="bx bx-${icon}"></span>
|
||||
<span class="toast-title"></span>
|
||||
</strong>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body"></div>
|
||||
<div class="toast-progress"></div>
|
||||
</div>`
|
||||
: `
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-icon">
|
||||
<span class="bx bx-${options.icon}"></span>
|
||||
<span class="bx bx-${icon}"></span>
|
||||
</div>
|
||||
<div class="toast-body"></div>
|
||||
<div class="toast-header">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-progress"></div>
|
||||
</div>`
|
||||
);
|
||||
|
||||
$toast.toggleClass("no-title", !options.title);
|
||||
$toast.find(".toast-title").text(options.title ?? "");
|
||||
$toast.find(".toast-body").html(options.message);
|
||||
$toast.toggleClass("no-title", !title);
|
||||
$toast.find(".toast-title").text(title ?? "");
|
||||
$toast.find(".toast-body").html(message);
|
||||
$toast.find(".toast-progress").css("width", `${(progress ?? 0) * 100}%`);
|
||||
|
||||
if (options.id) {
|
||||
$toast.attr("id", `toast-${options.id}`);
|
||||
if (id) {
|
||||
$toast.attr("id", `toast-${id}`);
|
||||
}
|
||||
|
||||
$("#toast-container").append($toast);
|
||||
|
||||
$toast.toast({
|
||||
delay: options.delay || 3000,
|
||||
autohide: !!options.autohide
|
||||
delay: delay || 3000,
|
||||
autohide: !!autohide
|
||||
});
|
||||
|
||||
$toast.on("hidden.bs.toast", (e) => e.target.remove());
|
||||
@@ -62,6 +66,7 @@ function showPersistent(options: ToastOptions) {
|
||||
|
||||
if ($toast.length > 0) {
|
||||
$toast.find(".toast-body").html(options.message);
|
||||
$toast.find(".toast-progress").css("width", `${(options.progress ?? 0) * 100}%`);
|
||||
} else {
|
||||
options.autohide = false;
|
||||
|
||||
@@ -77,11 +82,11 @@ function closePersistent(id: string) {
|
||||
$(`#toast-${id}`).remove();
|
||||
}
|
||||
|
||||
function showMessage(message: string, delay = 2000) {
|
||||
function showMessage(message: string, delay = 2000, icon = "check") {
|
||||
console.debug(utils.now(), "message:", message);
|
||||
|
||||
toast({
|
||||
icon: "check",
|
||||
icon,
|
||||
message: message,
|
||||
autohide: true,
|
||||
delay
|
||||
|
||||
@@ -89,7 +89,7 @@ async function resolveNotePathToSegments(notePath: string, hoistedNoteId = "root
|
||||
|
||||
effectivePathSegments.reverse();
|
||||
|
||||
if (effectivePathSegments.includes(hoistedNoteId)) {
|
||||
if (effectivePathSegments.includes(hoistedNoteId) && effectivePathSegments.includes('root')) {
|
||||
return effectivePathSegments;
|
||||
} else {
|
||||
const noteId = getNoteIdFromUrl(notePath);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import dayjs from "dayjs";
|
||||
import { dayjs } from "@triliumnext/commons";
|
||||
import type { ViewScope } from "./link.js";
|
||||
import FNote from "../entities/fnote";
|
||||
|
||||
@@ -207,7 +207,7 @@ function toObject<T, R>(array: T[], fn: (arg0: T) => [key: string, value: R]) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
function randomString(len: number) {
|
||||
export function randomString(len: number) {
|
||||
let text = "";
|
||||
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
@@ -274,7 +274,7 @@ function getMimeTypeClass(mime: string) {
|
||||
return `mime-${mime.toLowerCase().replace(/[\W_]+/g, "-")}`;
|
||||
}
|
||||
|
||||
function isHtmlEmpty(html: string) {
|
||||
export function isHtmlEmpty(html: string) {
|
||||
if (!html) {
|
||||
return true;
|
||||
} else if (typeof html !== "string") {
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.dropdown-menu:not(.static).calendar-dropdown-menu {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.calendar-dropdown-widget {
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -25,7 +25,11 @@
|
||||
--bs-body-font-weight: var(--main-font-weight) !important;
|
||||
--bs-body-color: var(--main-text-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;
|
||||
|
||||
--tree-item-light-theme-max-color-lightness: 50;
|
||||
--tree-item-dark-theme-min-color-lightness: 75;
|
||||
}
|
||||
|
||||
body#trilium-app.motion-disabled *,
|
||||
@@ -212,6 +216,16 @@ input::placeholder,
|
||||
background-color: var(--modal-backdrop-color) !important;
|
||||
}
|
||||
|
||||
body.mobile .modal .modal-dialog {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body.mobile .modal .modal-content {
|
||||
border-radius: var(--bs-modal-border-radius) var(--bs-modal-border-radius) 0 0;
|
||||
}
|
||||
|
||||
.component {
|
||||
contain: size;
|
||||
}
|
||||
@@ -243,6 +257,11 @@ button.close:hover {
|
||||
color: var(--hover-item-text-color);
|
||||
}
|
||||
|
||||
button.custom-title-bar-button {
|
||||
background: transparent;
|
||||
border: unset;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: var(--modal-background-color) !important;
|
||||
}
|
||||
@@ -439,7 +458,8 @@ body.desktop .tabulator-popup-container,
|
||||
}
|
||||
|
||||
body.desktop .dropdown-menu:not(#context-menu-container) .dropdown-item,
|
||||
body #context-menu-container .dropdown-item > span {
|
||||
body #context-menu-container .dropdown-item > span,
|
||||
body.mobile .dropdown .dropdown-submenu > span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -494,6 +514,10 @@ body #context-menu-container .dropdown-item > span {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown-menu .note-color-picker {
|
||||
padding: 4px 12px 8px 12px;
|
||||
}
|
||||
|
||||
.cm-editor {
|
||||
height: 100%;
|
||||
outline: none !important;
|
||||
@@ -576,11 +600,6 @@ button.btn-sm {
|
||||
color: var(--left-pane-text-color);
|
||||
}
|
||||
|
||||
.btn.active:not(.btn-primary) {
|
||||
background-color: var(--button-disabled-background-color) !important;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.ck.ck-block-toolbar-button {
|
||||
transform: translateX(7px);
|
||||
color: var(--muted-text-color);
|
||||
@@ -701,11 +720,6 @@ table.promoted-attributes-in-tooltip th {
|
||||
z-index: 32767 !important;
|
||||
}
|
||||
|
||||
.tooltip-trigger {
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.bs-tooltip-bottom .tooltip-arrow::before {
|
||||
border-bottom-color: var(--main-border-color) !important;
|
||||
}
|
||||
@@ -1001,9 +1015,15 @@ div[data-notify="container"] {
|
||||
font-family: var(--monospace-font-family);
|
||||
}
|
||||
|
||||
svg.ck-icon .note-icon {
|
||||
color: var(--main-text-color);
|
||||
font-size: 20px;
|
||||
svg.ck-icon {
|
||||
&.ck-icon_inherit-color path[fill="#333"] {
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
&.note-icon {
|
||||
color: var(--main-text-color);
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.ck-content {
|
||||
@@ -1112,10 +1132,6 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.note-detail-empty {
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: 0.5rem 1rem 0.5rem 1rem !important; /* make modal header padding slightly smaller */
|
||||
}
|
||||
@@ -1137,6 +1153,7 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
|
||||
--bs-toast-color: var(--main-text-color);
|
||||
z-index: 9999999999 !important;
|
||||
pointer-events: all;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.toast-header {
|
||||
@@ -1169,6 +1186,16 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
|
||||
background-color: unset !important;
|
||||
}
|
||||
|
||||
.toast .toast-progress {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
inset-inline-start: 0;
|
||||
inset-inline-end: 0;
|
||||
background-color: var(--toast-text-color) !important;
|
||||
height: 4px;
|
||||
transition: width 0.1s linear;
|
||||
}
|
||||
|
||||
.ck-mentions .ck-button {
|
||||
font-size: var(--detail-font-size) !important;
|
||||
padding: 5px;
|
||||
@@ -1300,11 +1327,11 @@ body.mobile #context-menu-container.mobile-bottom-menu {
|
||||
inset-inline-end: 0 !important;
|
||||
bottom: 0 !important;
|
||||
top: unset !important;
|
||||
max-height: 70vh;
|
||||
max-height: var(--tn-modal-max-height);
|
||||
overflow: auto !important;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
padding-bottom: env(safe-area-inset-bottom) !important;
|
||||
padding-bottom: max(env(safe-area-inset-bottom), var(--padding, var(--menu-padding-size))) !important;
|
||||
}
|
||||
|
||||
body.mobile .dropdown-menu {
|
||||
@@ -1363,6 +1390,20 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.right-dropdown-widget .right-dropdown-button {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tooltip-trigger {
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#launcher-pane.horizontal .right-dropdown-widget {
|
||||
width: 53px;
|
||||
}
|
||||
@@ -1538,12 +1579,15 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
||||
@media (max-width: 991px) {
|
||||
body.mobile #launcher-pane .dropdown.global-menu > .dropdown-menu.show,
|
||||
body.mobile #launcher-container .dropdown > .dropdown-menu.show {
|
||||
--dropdown-bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size));
|
||||
position: fixed !important;
|
||||
bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size)) !important;
|
||||
bottom: var(--dropdown-bottom) !important;
|
||||
top: unset !important;
|
||||
inset-inline-start: 0 !important;
|
||||
inset-inline-end: 0 !important;
|
||||
transform: unset !important;
|
||||
overflow-y: auto;
|
||||
max-height: calc(var(--tn-modal-max-height) - var(--dropdown-bottom));
|
||||
}
|
||||
|
||||
#mobile-sidebar-container {
|
||||
@@ -1578,6 +1622,14 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.note-split.empty-note {
|
||||
--max-content-width: var(--preferred-max-content-width);
|
||||
}
|
||||
|
||||
.note-detail-empty {
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
#mobile-sidebar-container.show #mobile-sidebar-wrapper {
|
||||
transform: translateX(0);
|
||||
}
|
||||
@@ -1640,46 +1692,6 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
||||
body.mobile .modal-dialog.modal-dialog-scrollable {
|
||||
height: unset;
|
||||
}
|
||||
|
||||
body.mobile .revisions-dialog .modal-dialog {
|
||||
height: 95vh;
|
||||
}
|
||||
|
||||
body.mobile .revisions-dialog .modal-body {
|
||||
height: 100% !important;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body.mobile .revisions-dialog .revision-list {
|
||||
height: unset;
|
||||
max-height: 20vh;
|
||||
border-bottom: 1px solid var(--main-border-color) !important;
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
body.mobile .revisions-dialog .modal-body > .revision-content-wrapper {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body.mobile .revisions-dialog .modal-body > .revision-content-wrapper > div:first-of-type {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
body.mobile .revisions-dialog .revision-title {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
body.mobile .revisions-dialog .revision-title-buttons {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
body.mobile .revisions-dialog .revision-content {
|
||||
padding: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile, tablet mode */
|
||||
@@ -1985,7 +1997,7 @@ body.electron.platform-darwin:not(.native-titlebar) .tab-row-container {
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
body.electron.platform-darwin:not(.native-titlebar) #tab-row-left-spacer {
|
||||
body.electron.platform-darwin:not(.native-titlebar):not(.full-screen) #tab-row-left-spacer {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
@@ -2434,6 +2446,15 @@ footer.webview-footer button {
|
||||
.admonition.caution::before { content: "\eac7"; }
|
||||
.admonition.warning::before { content: "\eac5"; }
|
||||
|
||||
.ck-content ul.todo-list li span.todo-list__label__description {
|
||||
transition: opacity 200ms ease;
|
||||
}
|
||||
|
||||
.ck-content ul.todo-list li:has(> span.todo-list__label input[type="checkbox"]:checked) > span.todo-list__label span.todo-list__label__description {
|
||||
text-decoration: line-through;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.chat-options-container {
|
||||
display: flex;
|
||||
margin: 5px 0;
|
||||
@@ -2559,9 +2580,38 @@ iframe.print-iframe {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.scrolling-container > .note-detail.full-height,
|
||||
.note-detail.full-height,
|
||||
.scrolling-container > .note-list-widget.full-height {
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Calendar collection */
|
||||
|
||||
.calendar-view a.fc-timegrid-event,
|
||||
.calendar-view a.fc-daygrid-event {
|
||||
/* Workaround: set font weight only if the theme-next is not active */
|
||||
font-weight: var(--root-background, 800);
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
body.mobile {
|
||||
.split-note-container-widget {
|
||||
flex-direction: column !important;
|
||||
|
||||
.note-split {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.note-split.visible + .note-split.visible {
|
||||
border-top: 1px solid var(--main-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
#root-widget.virtual-keyboard-opened .note-split:not(:focus-within) {
|
||||
max-height: 80px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,9 @@
|
||||
|
||||
--mermaid-theme: dark;
|
||||
--native-titlebar-background: #00000000;
|
||||
|
||||
--calendar-coll-event-background-saturation: 30%;
|
||||
--calendar-coll-event-background-lightness: 30%;
|
||||
}
|
||||
|
||||
body ::-webkit-calendar-picker-indicator {
|
||||
@@ -109,3 +112,6 @@ body .todo-list input[type="checkbox"]:not(:checked):before {
|
||||
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.6) !important;
|
||||
}
|
||||
|
||||
.use-note-color {
|
||||
--custom-color: var(--dark-theme-custom-color);
|
||||
}
|
||||
@@ -80,6 +80,9 @@ html {
|
||||
|
||||
--mermaid-theme: default;
|
||||
--native-titlebar-background: #ffffff00;
|
||||
|
||||
--calendar-coll-event-background-lightness: 95%;
|
||||
--calendar-coll-event-background-saturation: 80%;
|
||||
}
|
||||
|
||||
#left-pane .fancytree-node.tinted {
|
||||
@@ -91,4 +94,8 @@ html {
|
||||
.ck-content a.reference-link > span,
|
||||
.board-note {
|
||||
color: var(--light-theme-custom-color, inherit);
|
||||
}
|
||||
|
||||
.use-note-color {
|
||||
--custom-color: var(--light-theme-custom-color);
|
||||
}
|
||||
@@ -41,6 +41,9 @@
|
||||
--cmd-button-keyboard-shortcut-color: white;
|
||||
--cmd-button-disabled-opacity: 0.5;
|
||||
|
||||
--button-group-active-button-background: #ffffff4e;
|
||||
--button-group-active-button-text-color: white;
|
||||
|
||||
--icon-button-color: currentColor;
|
||||
--icon-button-hover-background: var(--hover-item-background-color);
|
||||
--icon-button-hover-color: var(--hover-item-text-color);
|
||||
@@ -98,6 +101,7 @@
|
||||
--menu-item-delimiter-color: #ffffff1c;
|
||||
--menu-item-group-header-color: #ffffff91;
|
||||
--menu-section-background-color: #fefefe08;
|
||||
--menu-submenu-mobile-background-color: rgba(0, 0, 0, 0.15);
|
||||
|
||||
--modal-backdrop-color: #000;
|
||||
--modal-shadow-color: rgba(0, 0, 0, .5);
|
||||
@@ -266,6 +270,14 @@
|
||||
--ck-editor-toolbar-button-on-color: white;
|
||||
--ck-editor-toolbar-button-on-shadow: 1px 1px 2px rgba(0, 0, 0, .75);
|
||||
--ck-editor-toolbar-dropdown-button-open-background: #ffffff14;
|
||||
|
||||
--calendar-coll-event-background-saturation: 25%;
|
||||
--calendar-coll-event-background-lightness: 20%;
|
||||
--calendar-coll-event-background-color: #3c3c3c;
|
||||
--calendar-coll-event-text-color: white;
|
||||
--calendar-coll-event-hover-filter: brightness(1.25);
|
||||
--callendar-coll-event-archived-sripe-color: #00000026;
|
||||
--calendar-coll-today-background-color: #ffffff08;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -300,8 +312,12 @@ body .todo-list input[type="checkbox"]:not(:checked):before {
|
||||
border-color: var(--muted-text-color) !important;
|
||||
}
|
||||
|
||||
.tinted-quick-edit-dialog {
|
||||
.quick-edit-dialog-wrapper.with-hue {
|
||||
--modal-background-color: hsl(var(--custom-color-hue), 8.8%, 11.2%);
|
||||
--modal-border-color: hsl(var(--custom-color-hue), 9.4%, 25.1%);
|
||||
--promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 13.2%, 20.8%);
|
||||
}
|
||||
|
||||
.use-note-color {
|
||||
--custom-color: var(--dark-theme-custom-color);
|
||||
}
|
||||
@@ -41,6 +41,9 @@
|
||||
--cmd-button-keyboard-shortcut-color: black;
|
||||
--cmd-button-disabled-opacity: 0.5;
|
||||
|
||||
--button-group-active-button-background: #00000026;
|
||||
--button-group-active-button-text-color: black;
|
||||
|
||||
--icon-button-color: currentColor;
|
||||
--icon-button-hover-background: var(--hover-item-background-color);
|
||||
--icon-button-hover-color: var(--hover-item-text-color);
|
||||
@@ -265,6 +268,14 @@
|
||||
--ck-editor-toolbar-button-on-color: black;
|
||||
--ck-editor-toolbar-button-on-shadow: none;
|
||||
--ck-editor-toolbar-dropdown-button-open-background: #0000000f;
|
||||
|
||||
--calendar-coll-event-background-lightness: 95%;
|
||||
--calendar-coll-event-background-saturation: 80%;
|
||||
--calendar-coll-event-background-color: #eaeaea;
|
||||
--calendar-coll-event-text-color: black;
|
||||
--calendar-coll-event-hover-filter: brightness(.95) saturate(1.25);
|
||||
--callendar-coll-event-archived-sripe-color: #0000000a;
|
||||
--calendar-coll-today-background-color: #00000006;
|
||||
}
|
||||
|
||||
#left-pane .fancytree-node.tinted {
|
||||
@@ -276,7 +287,7 @@
|
||||
--custom-bg-color: hsl(var(--custom-color-hue), 37%, 89%, 1);
|
||||
}
|
||||
|
||||
.tinted-quick-edit-dialog {
|
||||
.quick-edit-dialog-wrapper.with-hue {
|
||||
--modal-background-color: hsl(var(--custom-color-hue), 56%, 96%);
|
||||
--modal-border-color: hsl(var(--custom-color-hue), 33%, 41%);
|
||||
--promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 40%, 88%);
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
|
||||
--menu-padding-size: 8px;
|
||||
--menu-item-icon-vert-offset: -2px;
|
||||
--menu-submenu-mobile-background-color: rgba(255, 255, 255, 0.15);
|
||||
|
||||
--more-accented-background-color: var(--card-background-hover-color);
|
||||
|
||||
@@ -99,6 +100,14 @@
|
||||
--tree-item-dark-theme-min-color-lightness: 65;
|
||||
}
|
||||
|
||||
body {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.selectable-text {
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
body.backdrop-effects-disabled {
|
||||
/* Backdrop effects are disabled, replace the menu background color with the
|
||||
* no-backdrop fallback color */
|
||||
@@ -119,17 +128,6 @@ body.backdrop-effects-disabled {
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
|
||||
body.mobile .dropdown-menu {
|
||||
backdrop-filter: var(--dropdown-backdrop-filter);
|
||||
border-radius: var(--dropdown-border-radius);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body.mobile .dropdown-menu .dropdown-menu {
|
||||
backdrop-filter: unset !important;
|
||||
border-radius: unset !important;
|
||||
}
|
||||
|
||||
body.desktop .dropdown-menu::before,
|
||||
:root .ck.ck-dropdown__panel::before,
|
||||
:root .excalidraw .popover::before,
|
||||
@@ -157,17 +155,12 @@ body.desktop .dropdown-submenu .dropdown-menu::before {
|
||||
content: unset;
|
||||
}
|
||||
|
||||
body.mobile .dropdown-submenu .dropdown-menu {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
body.desktop .dropdown-submenu .dropdown-menu {
|
||||
backdrop-filter: var(--dropdown-backdrop-filter);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.dropdown-item,
|
||||
body.mobile .dropdown-submenu .dropdown-toggle,
|
||||
.excalidraw .context-menu .context-menu-item {
|
||||
--menu-item-start-padding: 8px;
|
||||
--menu-item-end-padding: 22px;
|
||||
@@ -201,10 +194,6 @@ body.mobile .dropdown-item:not(:last-of-type) {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
body.mobile .dropdown-submenu:hover {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
html body .dropdown-item.disabled,
|
||||
html body .dropdown-item[disabled] {
|
||||
color: var(--menu-text-color) !important;
|
||||
@@ -321,17 +310,126 @@ body.desktop .dropdown-menu.static .dropdown-item.active {
|
||||
--active-item-text-color: var(--menu-text-color);
|
||||
}
|
||||
|
||||
/* #region Mobile tweaks for dropdown menus */
|
||||
body.mobile #context-menu-cover {
|
||||
transition: background-color 150ms ease-in;
|
||||
|
||||
&.show {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
&.global-menu-cover {
|
||||
bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size));
|
||||
|
||||
@media (min-width: 992px) {
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body.mobile .dropdown-menu.mobile-bottom-menu,
|
||||
body.mobile .dropdown.global-menu .dropdown-menu {
|
||||
border-radius: var(--dropdown-border-radius) var(--dropdown-border-radius) 0 0;
|
||||
}
|
||||
|
||||
body.mobile .dropdown-menu {
|
||||
--dropdown-menu-padding-vertical: 0.7em;
|
||||
--dropdown-menu-padding-horizontal: 1em;
|
||||
--hover-item-background-color: var(--card-background-color);
|
||||
font-size: 1em !important;
|
||||
backdrop-filter: var(--dropdown-backdrop-filter);
|
||||
position: relative;
|
||||
|
||||
.dropdown-toggle::after {
|
||||
top: 0.5em;
|
||||
right: var(--dropdown-menu-padding-horizontal);
|
||||
transform: translateX(50%) rotate(90deg);
|
||||
}
|
||||
|
||||
.dropdown-item.submenu-open .dropdown-toggle::after {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
.dropdown-item,
|
||||
.dropdown-custom-item {
|
||||
margin-bottom: 0;
|
||||
padding: var(--dropdown-menu-padding-vertical) var(--dropdown-menu-padding-horizontal) !important;
|
||||
background: var(--card-background-color);
|
||||
border-bottom: 1px solid var(--menu-item-delimiter-color) !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.dropdown-item:first-of-type,
|
||||
.dropdown-divider + .dropdown-item,
|
||||
.dropdown-custom-item:first-of-type,
|
||||
.dropdown-divider + .dropdown-custom-item {
|
||||
border-top-left-radius: 6px;
|
||||
border-top-right-radius: 6px;
|
||||
}
|
||||
|
||||
.dropdown-item:last-of-type,
|
||||
.dropdown-item:has(+ .dropdown-divider),
|
||||
.dropdown-custom-item:last-of-type,
|
||||
.dropdown-custom-item:has(+ .dropdown-divider) {
|
||||
border-bottom-left-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
border-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.dropdown-divider {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.dropdown-submenu {
|
||||
padding: 0 !important;
|
||||
backdrop-filter: unset !important;
|
||||
|
||||
.dropdown-toggle {
|
||||
padding: var(--dropdown-menu-padding-vertical) var(--dropdown-menu-padding-horizontal);
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
--menu-background-color: --menu-submenu-mobile-background-color;
|
||||
--bs-dropdown-divider-margin-y: 0.25rem;
|
||||
border-radius: 0;
|
||||
max-height: 0;
|
||||
transition: max-height 100ms ease-in;
|
||||
display: block !important;
|
||||
|
||||
&.show {
|
||||
max-height: 1000px;
|
||||
padding: 0.5rem 0.75rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.submenu-open {
|
||||
.dropdown-toggle {
|
||||
padding-bottom: var(--dropdown-menu-padding-vertical);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-custom-item:has(.note-color-picker) {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.note-color-picker {
|
||||
padding: 0;
|
||||
width: fit-content;
|
||||
|
||||
.color-cell {
|
||||
--color-picker-cell-size: 26px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* #endregion */
|
||||
|
||||
body.desktop .dropdown-menu .dropdown-toggle::after {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body.mobile .dropdown-menu .dropdown-toggle::after {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
body.mobile .dropdown-menu .dropdown-item.submenu-open .dropdown-toggle::after {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
/* Dropdown item button (used in zoom buttons in global menu) */
|
||||
|
||||
@@ -347,6 +445,12 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
|
||||
outline: 2px solid var(--input-focus-outline-color) !important;
|
||||
}
|
||||
|
||||
:root .dropdown-menu .note-color-picker {
|
||||
padding: 4px 10px;
|
||||
--note-color-picker-clear-color-cell-background: var(--main-text-color);
|
||||
--note-color-picker-clear-color-cell-selection-outline-color: var(--main-text-color);
|
||||
}
|
||||
|
||||
/*
|
||||
* TOASTS
|
||||
*/
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
.modal .modal-header .btn-close,
|
||||
.modal .modal-header .help-button,
|
||||
.modal .modal-header .custom-title-bar-button,
|
||||
#toast-container .toast .toast-header .btn-close {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -55,15 +56,17 @@
|
||||
font-family: boxicons;
|
||||
}
|
||||
|
||||
.modal .modal-header .help-button {
|
||||
.modal .modal-header .help-button,
|
||||
.modal .modal-header .custom-title-bar-button {
|
||||
margin-inline-end: 0;
|
||||
font-size: calc(var(--modal-control-button-size) * .75);
|
||||
font-size: calc(var(--modal-control-button-size) * .70);
|
||||
font-family: unset;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.modal .modal-header .btn-close:hover,
|
||||
.modal .modal-header .help-button:hover,
|
||||
.modal .modal-header .custom-title-bar-button:hover,
|
||||
#toast-container .toast .toast-header .btn-close:hover {
|
||||
background: var(--modal-control-button-hover-background);
|
||||
color: var(--modal-control-button-hover-color);
|
||||
@@ -71,6 +74,7 @@
|
||||
|
||||
.modal .modal-header .btn-close:active,
|
||||
.modal .modal-header .help-button:active,
|
||||
.modal .modal-header .custom-title-bar-button:active,
|
||||
#toast-container .toast .toast-header .btn-close:active {
|
||||
transform: scale(.85);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,10 @@ button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .c
|
||||
padding: 4px 16px;
|
||||
background: var(--cmd-button-background-color);
|
||||
color: var(--cmd-button-text-color);
|
||||
|
||||
&.dropdown-toggle-split {
|
||||
min-width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
button.btn.btn-primary:hover,
|
||||
@@ -142,6 +146,14 @@ button.btn.btn-success kbd {
|
||||
outline: 2px solid var(--input-focus-outline-color);
|
||||
}
|
||||
|
||||
/* Button groups */
|
||||
|
||||
/* Active button */
|
||||
:root .btn-group button.btn.active {
|
||||
background-color: var(--button-group-active-button-background);
|
||||
color: var(--button-group-active-button-text-color);
|
||||
}
|
||||
|
||||
/*
|
||||
* Input boxes
|
||||
*/
|
||||
|
||||
@@ -643,7 +643,7 @@ html .note-detail-editable-text :not(figure, .include-note, hr):first-child {
|
||||
}
|
||||
}
|
||||
|
||||
.note-detail-printable:not(.word-wrap) pre code {
|
||||
.ck-content:not(.word-wrap) pre code {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
|
||||
@@ -124,12 +124,8 @@
|
||||
|
||||
/* The container */
|
||||
|
||||
.note-split.empty-note {
|
||||
--max-content-width: 70%;
|
||||
}
|
||||
|
||||
.note-split.empty-note div.note-detail {
|
||||
margin: 50px auto;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
/* The search results list */
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
background-color: var(--root-background);
|
||||
}
|
||||
|
||||
body.mobile #root-widget {
|
||||
background-color: var(--main-background-color);
|
||||
}
|
||||
|
||||
body {
|
||||
--native-titlebar-darwin-x-offset: 10;
|
||||
--native-titlebar-darwin-y-offset: 12 !important;
|
||||
@@ -341,7 +345,7 @@ body[dir=ltr] #launcher-container {
|
||||
*/
|
||||
|
||||
.calendar-dropdown-widget {
|
||||
padding: 12px;
|
||||
padding: 18px;
|
||||
color: var(--calendar-color);
|
||||
user-select: none;
|
||||
}
|
||||
@@ -1424,9 +1428,7 @@ div.promoted-attribute-cell .tn-checkbox {
|
||||
height: 1cap;
|
||||
}
|
||||
|
||||
/* Relocate the checkbox before the label */
|
||||
div.promoted-attribute-cell.promoted-attribute-label-boolean > div:first-of-type {
|
||||
order: -1;
|
||||
margin-inline-end: 1.5em;
|
||||
}
|
||||
|
||||
@@ -1446,12 +1448,20 @@ div.promoted-attribute-cell .multiplicity:has(span) span {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
div.promoted-attribute-cell.promoted-attribute-label-color {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
div.promoted-attribute-cell.promoted-attribute-label-color .input-group {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
* Floating buttons
|
||||
*/
|
||||
|
||||
/* Floating buttons container */
|
||||
div#center-pane .floating-buttons-children {
|
||||
.floating-buttons-children {
|
||||
opacity: 1;
|
||||
min-height: var(--floating-button-height);
|
||||
transform-origin: right;
|
||||
@@ -1463,12 +1473,12 @@ div#center-pane .floating-buttons-children {
|
||||
opacity 250ms ease-out;
|
||||
}
|
||||
|
||||
body[dir=rtl] div#center-pane .floating-buttons-children {
|
||||
body[dir=rtl] .floating-buttons-children {
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
/* Floating buttons container (collapsed) */
|
||||
div#center-pane .floating-buttons-children.temporarily-hidden {
|
||||
.floating-buttons-children.temporarily-hidden {
|
||||
display: flex !important;
|
||||
opacity: 0;
|
||||
transform: scaleX(0);
|
||||
|
||||
@@ -87,7 +87,11 @@ export function buildNote(noteDef: NoteDefinition) {
|
||||
let position = 0;
|
||||
for (const [ key, value ] of Object.entries(noteDef)) {
|
||||
const attributeId = utils.randomString(12);
|
||||
const name = key.substring(1);
|
||||
let name = key.substring(1);
|
||||
const isInheritable = key.endsWith("(inheritable)");
|
||||
if (isInheritable) {
|
||||
name = name.substring(0, name.length - "(inheritable)".length);
|
||||
}
|
||||
|
||||
let attribute: FAttribute | null = null;
|
||||
if (key.startsWith("#")) {
|
||||
@@ -98,7 +102,7 @@ export function buildNote(noteDef: NoteDefinition) {
|
||||
name,
|
||||
value,
|
||||
position,
|
||||
isInheritable: false
|
||||
isInheritable
|
||||
});
|
||||
}
|
||||
|
||||
@@ -110,7 +114,7 @@ export function buildNote(noteDef: NoteDefinition) {
|
||||
name,
|
||||
value,
|
||||
position,
|
||||
isInheritable: false
|
||||
isInheritable
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ function mockServer() {
|
||||
attributes: []
|
||||
}
|
||||
}
|
||||
|
||||
console.warn(`Unsupported GET to mocked server: ${url}`);
|
||||
},
|
||||
|
||||
async post(url: string, data: object) {
|
||||
|
||||
@@ -201,8 +201,12 @@
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"relation": "العلاقة",
|
||||
"backlink": "{{count}} رابط راجع",
|
||||
"backlinks": "{{count}} روابط راجعة"
|
||||
"backlink_zero": "",
|
||||
"backlink_one": "{{count}} رابط راجع",
|
||||
"backlink_two": "",
|
||||
"backlink_few": "",
|
||||
"backlink_many": "{{count}} روابط راجعة",
|
||||
"backlink_other": ""
|
||||
},
|
||||
"note_icon": {
|
||||
"category": "الفئة:",
|
||||
@@ -230,7 +234,6 @@
|
||||
"geo-map": "الخريطة الجغرافية",
|
||||
"collapse_all_notes": "طي كل الملاحظات",
|
||||
"include_archived_notes": "عرض الملاحظات المؤرشفة",
|
||||
"expand_all_children": "توسيع جميع العناصر الفرعية",
|
||||
"presentation": "عرض تقديمي",
|
||||
"invalid_view_type": "نوع العرض {{type}} غير صالح"
|
||||
},
|
||||
@@ -512,7 +515,7 @@
|
||||
"title": "الملاحظات المعدلة"
|
||||
},
|
||||
"note_properties": {
|
||||
"this_note_was_originally_taken_from": ""
|
||||
"info": "معلومات"
|
||||
},
|
||||
"backend_log": {
|
||||
"refresh": "تحديث"
|
||||
|
||||
@@ -1,185 +1,187 @@
|
||||
{
|
||||
"about": {
|
||||
"title": "Sobre Trilium Notes",
|
||||
"homepage": "Pàgina principal:"
|
||||
},
|
||||
"add_link": {
|
||||
"note": "Nota"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"prefix": "Prefix: ",
|
||||
"save": "Desa"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"labels": "Etiquetes",
|
||||
"relations": "Relacions",
|
||||
"notes": "Notes",
|
||||
"other": "Altres"
|
||||
},
|
||||
"confirm": {
|
||||
"confirmation": "Confirmació",
|
||||
"cancel": "Cancel·la",
|
||||
"ok": "OK"
|
||||
},
|
||||
"delete_notes": {
|
||||
"close": "Tanca",
|
||||
"cancel": "Cancel·la",
|
||||
"ok": "OK"
|
||||
},
|
||||
"export": {
|
||||
"close": "Tanca",
|
||||
"export": "Exporta"
|
||||
},
|
||||
"help": {
|
||||
"troubleshooting": "Solució de problemes",
|
||||
"other": "Altres"
|
||||
},
|
||||
"import": {
|
||||
"options": "Opcions",
|
||||
"import": "Importa"
|
||||
},
|
||||
"include_note": {
|
||||
"label_note": "Nota"
|
||||
},
|
||||
"info": {
|
||||
"closeButton": "Tanca",
|
||||
"okButton": "OK"
|
||||
},
|
||||
"note_type_chooser": {
|
||||
"templates": "Plantilles:"
|
||||
},
|
||||
"prompt": {
|
||||
"title": "Sol·licitud",
|
||||
"defaultTitle": "Sol·licitud"
|
||||
},
|
||||
"protected_session_password": {
|
||||
"close_label": "Tanca"
|
||||
},
|
||||
"recent_changes": {
|
||||
"undelete_link": "recuperar"
|
||||
},
|
||||
"revisions": {
|
||||
"restore_button": "Restaura",
|
||||
"delete_button": "Suprimeix",
|
||||
"download_button": "Descarrega",
|
||||
"mime": "MIME: ",
|
||||
"preview": "Vista prèvia:"
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"title": "títol",
|
||||
"ascending": "ascendent",
|
||||
"descending": "descendent",
|
||||
"folders": "Carpetes"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"options": "Opcions",
|
||||
"upload": "Puja"
|
||||
},
|
||||
"attribute_detail": {
|
||||
"name": "Nom",
|
||||
"value": "Valor",
|
||||
"promoted": "Destacat",
|
||||
"promoted_alias": "Àlies",
|
||||
"multiplicity": "Multiplicitat",
|
||||
"label_type": "Tipus",
|
||||
"text": "Text",
|
||||
"number": "Número",
|
||||
"boolean": "Booleà",
|
||||
"date": "Data",
|
||||
"time": "Hora",
|
||||
"url": "URL",
|
||||
"precision": "Precisió",
|
||||
"digits": "dígits",
|
||||
"inheritable": "Heretable",
|
||||
"delete": "Suprimeix",
|
||||
"color_type": "Color"
|
||||
},
|
||||
"rename_label": {
|
||||
"to": "Per"
|
||||
},
|
||||
"move_note": {
|
||||
"to": "a"
|
||||
},
|
||||
"add_relation": {
|
||||
"to": "a"
|
||||
},
|
||||
"rename_relation": {
|
||||
"to": "Per"
|
||||
},
|
||||
"update_relation_target": {
|
||||
"to": "a"
|
||||
},
|
||||
"attachments_actions": {
|
||||
"download": "Descarrega"
|
||||
},
|
||||
"calendar": {
|
||||
"mon": "Dl",
|
||||
"tue": "Dt",
|
||||
"wed": "dc",
|
||||
"thu": "Dj",
|
||||
"fri": "Dv",
|
||||
"sat": "Ds",
|
||||
"sun": "Dg",
|
||||
"january": "Gener",
|
||||
"february": "Febrer",
|
||||
"march": "Març",
|
||||
"april": "Abril",
|
||||
"may": "Maig",
|
||||
"june": "Juny",
|
||||
"july": "Juliol",
|
||||
"august": "Agost",
|
||||
"september": "Setembre",
|
||||
"october": "Octubre",
|
||||
"november": "Novembre",
|
||||
"december": "Desembre"
|
||||
},
|
||||
"global_menu": {
|
||||
"menu": "Menú",
|
||||
"options": "Opcions",
|
||||
"zoom": "Zoom",
|
||||
"advanced": "Avançat",
|
||||
"logout": "Tanca la sessió"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"relation": "relació"
|
||||
},
|
||||
"note_icon": {
|
||||
"category": "Categoria:",
|
||||
"search": "Cerca:"
|
||||
},
|
||||
"basic_properties": {
|
||||
"editable": "Editable",
|
||||
"language": "Llengua"
|
||||
},
|
||||
"book_properties": {
|
||||
"grid": "Graella",
|
||||
"list": "Llista",
|
||||
"collapse": "Replega",
|
||||
"expand": "Desplega",
|
||||
"calendar": "Calendari",
|
||||
"table": "Taula",
|
||||
"board": "Tauler"
|
||||
},
|
||||
"edited_notes": {
|
||||
"deleted": "(suprimit)"
|
||||
},
|
||||
"file_properties": {
|
||||
"download": "Descarrega",
|
||||
"open": "Obre",
|
||||
"title": "Fitxer"
|
||||
},
|
||||
"image_properties": {
|
||||
"download": "Descarrega",
|
||||
"open": "Obre",
|
||||
"title": "Imatge"
|
||||
},
|
||||
"note_info_widget": {
|
||||
"created": "Creat",
|
||||
"modified": "Modificat",
|
||||
"type": "Tipus",
|
||||
"calculate": "calcula"
|
||||
},
|
||||
"note_paths": {
|
||||
"archived": "Arxivat"
|
||||
}
|
||||
"about": {
|
||||
"title": "Sobre Trilium Notes",
|
||||
"homepage": "Pàgina principal:",
|
||||
"app_version": "Versió de l'aplicació:",
|
||||
"db_version": "Versió de la base de dades:"
|
||||
},
|
||||
"add_link": {
|
||||
"note": "Nota"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"prefix": "Prefix: ",
|
||||
"save": "Desa"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"labels": "Etiquetes",
|
||||
"relations": "Relacions",
|
||||
"notes": "Notes",
|
||||
"other": "Altres"
|
||||
},
|
||||
"confirm": {
|
||||
"confirmation": "Confirmació",
|
||||
"cancel": "Cancel·la",
|
||||
"ok": "OK"
|
||||
},
|
||||
"delete_notes": {
|
||||
"close": "Tanca",
|
||||
"cancel": "Cancel·la",
|
||||
"ok": "OK"
|
||||
},
|
||||
"export": {
|
||||
"close": "Tanca",
|
||||
"export": "Exporta"
|
||||
},
|
||||
"help": {
|
||||
"troubleshooting": "Solució de problemes",
|
||||
"other": "Altres"
|
||||
},
|
||||
"import": {
|
||||
"options": "Opcions",
|
||||
"import": "Importa"
|
||||
},
|
||||
"include_note": {
|
||||
"label_note": "Nota"
|
||||
},
|
||||
"info": {
|
||||
"closeButton": "Tanca",
|
||||
"okButton": "OK"
|
||||
},
|
||||
"note_type_chooser": {
|
||||
"templates": "Plantilles:"
|
||||
},
|
||||
"prompt": {
|
||||
"title": "Sol·licitud",
|
||||
"defaultTitle": "Sol·licitud"
|
||||
},
|
||||
"protected_session_password": {
|
||||
"close_label": "Tanca"
|
||||
},
|
||||
"recent_changes": {
|
||||
"undelete_link": "recuperar"
|
||||
},
|
||||
"revisions": {
|
||||
"restore_button": "Restaura",
|
||||
"delete_button": "Suprimeix",
|
||||
"download_button": "Descarrega",
|
||||
"mime": "MIME: ",
|
||||
"preview": "Vista prèvia:"
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"title": "títol",
|
||||
"ascending": "ascendent",
|
||||
"descending": "descendent",
|
||||
"folders": "Carpetes"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"options": "Opcions",
|
||||
"upload": "Puja"
|
||||
},
|
||||
"attribute_detail": {
|
||||
"name": "Nom",
|
||||
"value": "Valor",
|
||||
"promoted": "Destacat",
|
||||
"promoted_alias": "Àlies",
|
||||
"multiplicity": "Multiplicitat",
|
||||
"label_type": "Tipus",
|
||||
"text": "Text",
|
||||
"number": "Número",
|
||||
"boolean": "Booleà",
|
||||
"date": "Data",
|
||||
"time": "Hora",
|
||||
"url": "URL",
|
||||
"precision": "Precisió",
|
||||
"digits": "dígits",
|
||||
"inheritable": "Heretable",
|
||||
"delete": "Suprimeix",
|
||||
"color_type": "Color"
|
||||
},
|
||||
"rename_label": {
|
||||
"to": "Per"
|
||||
},
|
||||
"move_note": {
|
||||
"to": "a"
|
||||
},
|
||||
"add_relation": {
|
||||
"to": "a"
|
||||
},
|
||||
"rename_relation": {
|
||||
"to": "Per"
|
||||
},
|
||||
"update_relation_target": {
|
||||
"to": "a"
|
||||
},
|
||||
"attachments_actions": {
|
||||
"download": "Descarrega"
|
||||
},
|
||||
"calendar": {
|
||||
"mon": "Dl",
|
||||
"tue": "Dt",
|
||||
"wed": "dc",
|
||||
"thu": "Dj",
|
||||
"fri": "Dv",
|
||||
"sat": "Ds",
|
||||
"sun": "Dg",
|
||||
"january": "Gener",
|
||||
"february": "Febrer",
|
||||
"march": "Març",
|
||||
"april": "Abril",
|
||||
"may": "Maig",
|
||||
"june": "Juny",
|
||||
"july": "Juliol",
|
||||
"august": "Agost",
|
||||
"september": "Setembre",
|
||||
"october": "Octubre",
|
||||
"november": "Novembre",
|
||||
"december": "Desembre"
|
||||
},
|
||||
"global_menu": {
|
||||
"menu": "Menú",
|
||||
"options": "Opcions",
|
||||
"zoom": "Zoom",
|
||||
"advanced": "Avançat",
|
||||
"logout": "Tanca la sessió"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"relation": "relació"
|
||||
},
|
||||
"note_icon": {
|
||||
"category": "Categoria:",
|
||||
"search": "Cerca:"
|
||||
},
|
||||
"basic_properties": {
|
||||
"editable": "Editable",
|
||||
"language": "Llengua"
|
||||
},
|
||||
"book_properties": {
|
||||
"grid": "Graella",
|
||||
"list": "Llista",
|
||||
"collapse": "Replega",
|
||||
"expand": "Desplega",
|
||||
"calendar": "Calendari",
|
||||
"table": "Taula",
|
||||
"board": "Tauler"
|
||||
},
|
||||
"edited_notes": {
|
||||
"deleted": "(suprimit)"
|
||||
},
|
||||
"file_properties": {
|
||||
"download": "Descarrega",
|
||||
"open": "Obre",
|
||||
"title": "Fitxer"
|
||||
},
|
||||
"image_properties": {
|
||||
"download": "Descarrega",
|
||||
"open": "Obre",
|
||||
"title": "Imatge"
|
||||
},
|
||||
"note_info_widget": {
|
||||
"created": "Creat",
|
||||
"modified": "Modificat",
|
||||
"type": "Tipus",
|
||||
"calculate": "calcula"
|
||||
},
|
||||
"note_paths": {
|
||||
"archived": "Arxivat"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,8 @@
|
||||
"inPageSearch": "页面内搜索",
|
||||
"newTabWithActivationNoteLink": "在新标签页打开笔记链接并激活该标签页",
|
||||
"title": "资料表",
|
||||
"newTabNoteLink": "在新标签页开启链接"
|
||||
"newTabNoteLink": "在新标签页开启链接",
|
||||
"editShortcuts": "编辑键盘快捷键"
|
||||
},
|
||||
"import": {
|
||||
"importIntoNote": "导入到笔记",
|
||||
@@ -735,9 +736,8 @@
|
||||
"zoom_out_title": "缩小"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} 个反链",
|
||||
"backlinks": "{{count}} 个反链",
|
||||
"relation": "关系"
|
||||
"relation": "关系",
|
||||
"backlink_other": "{{count}} 个反链"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"insert_child_note": "插入子笔记",
|
||||
@@ -764,7 +764,6 @@
|
||||
"grid": "网格",
|
||||
"list": "列表",
|
||||
"collapse_all_notes": "折叠所有笔记",
|
||||
"expand_all_children": "展开所有子项",
|
||||
"collapse": "折叠",
|
||||
"expand": "展开",
|
||||
"invalid_view_type": "无效的查看类型 '{{type}}'",
|
||||
@@ -774,7 +773,11 @@
|
||||
"geo-map": "地理地图",
|
||||
"board": "看板",
|
||||
"include_archived_notes": "展示归档笔记",
|
||||
"presentation": "演示"
|
||||
"presentation": "演示",
|
||||
"expand_tooltip": "展开此集合的直接子代(单层深度)。点击右方箭头以查看更多选项。",
|
||||
"expand_first_level": "展开直接子代",
|
||||
"expand_nth_level": "展开 {{depth}} 层",
|
||||
"expand_all_levels": "展开所有层级"
|
||||
},
|
||||
"edited_notes": {
|
||||
"no_edited_notes_found": "今天还没有编辑过的笔记...",
|
||||
@@ -837,7 +840,8 @@
|
||||
"search": "搜索"
|
||||
},
|
||||
"note_properties": {
|
||||
"this_note_was_originally_taken_from": "笔记来源:"
|
||||
"this_note_was_originally_taken_from": "笔记来源:",
|
||||
"info": "信息"
|
||||
},
|
||||
"owned_attribute_list": {
|
||||
"owned_attributes": "拥有的属性"
|
||||
@@ -1150,7 +1154,10 @@
|
||||
"unit": "字符"
|
||||
},
|
||||
"code_mime_types": {
|
||||
"title": "下拉菜单可用的MIME文件类型"
|
||||
"title": "下拉菜单可用的MIME文件类型",
|
||||
"tooltip_syntax_highlighting": "语法高亮",
|
||||
"tooltip_code_block_syntax": "文本笔记中的代码块",
|
||||
"tooltip_code_note_syntax": "代码笔记"
|
||||
},
|
||||
"vim_key_bindings": {
|
||||
"use_vim_keybindings_in_code_notes": "Vim 快捷键",
|
||||
@@ -1550,7 +1557,8 @@
|
||||
"refresh-saved-search-results": "刷新保存的搜索结果",
|
||||
"create-child-note": "创建子笔记",
|
||||
"unhoist": "取消聚焦",
|
||||
"toggle-sidebar": "切换侧边栏"
|
||||
"toggle-sidebar": "切换侧边栏",
|
||||
"dropping-not-allowed": "不允许移动笔记到此处。"
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "保持此窗口置顶"
|
||||
@@ -1653,7 +1661,8 @@
|
||||
"duplicate-launcher": "复制启动器 <kbd data-command=\"duplicateSubtree\">"
|
||||
},
|
||||
"editable-text": {
|
||||
"auto-detect-language": "自动检测"
|
||||
"auto-detect-language": "自动检测",
|
||||
"keeps-crashing": "编辑组件时持续崩溃。请尝试重启 Trilium。如果问题仍然存在,请考虑提交错误报告。"
|
||||
},
|
||||
"highlighting": {
|
||||
"title": "代码块",
|
||||
@@ -1694,7 +1703,8 @@
|
||||
"copy-link": "复制链接",
|
||||
"paste": "粘贴",
|
||||
"paste-as-plain-text": "以纯文本粘贴",
|
||||
"search_online": "用 {{searchEngine}} 搜索 \"{{term}}\""
|
||||
"search_online": "用 {{searchEngine}} 搜索 \"{{term}}\"",
|
||||
"search_in_trilium": "在 Trilium 中搜索「{{term}}」"
|
||||
},
|
||||
"image_context_menu": {
|
||||
"copy_reference_to_clipboard": "复制引用到剪贴板",
|
||||
@@ -1887,9 +1897,7 @@
|
||||
"indexing_stopped": "索引已停止",
|
||||
"indexing_in_progress": "索引进行中...",
|
||||
"last_indexed": "最后索引时间",
|
||||
"n_notes_queued_0": "{{ count }} 条笔记已加入索引队列",
|
||||
"note_chat": "笔记聊天",
|
||||
"notes_indexed_0": "{{ count }} 条笔记已索引",
|
||||
"sources": "来源",
|
||||
"start_indexing": "开始索引",
|
||||
"use_advanced_context": "使用高级上下文",
|
||||
@@ -2018,7 +2026,8 @@
|
||||
"add-column-placeholder": "请输入列名...",
|
||||
"edit-note-title": "点击编辑笔记标题",
|
||||
"edit-column-title": "点击编辑列标题",
|
||||
"remove-from-board": "从看板上移除"
|
||||
"remove-from-board": "从看板上移除",
|
||||
"column-already-exists": "此列已在看板上。"
|
||||
},
|
||||
"command_palette": {
|
||||
"tree-action-name": "树形:{{name}}",
|
||||
@@ -2087,7 +2096,14 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "当前正在查看一个只读笔记。",
|
||||
"auto-read-only-note": "这条笔记以只读模式显示便于快速加载。",
|
||||
"auto-read-only-learn-more": "了解更多",
|
||||
"edit-note": "编辑笔记"
|
||||
},
|
||||
"note-color": {
|
||||
"clear-color": "清除笔记颜色",
|
||||
"set-color": "设置笔记颜色",
|
||||
"set-custom-color": "设置自定义笔记颜色"
|
||||
},
|
||||
"popup-editor": {
|
||||
"maximize": "切换至完整编辑器"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,41 +24,90 @@
|
||||
"message": "Uživatelský skript z poznámky s ID \"{{id}}\" a názvem \"{{title}}\" nemohl být spuštěn z důvodu: \n\n{{message}}"
|
||||
}
|
||||
},
|
||||
"ai_llm": {
|
||||
"n_notes_queued_0": "{{ count }} poznámka ve frontě k indexaci",
|
||||
"n_notes_queued_1": "{{ count }} poznámky ve frontě k indexaci",
|
||||
"n_notes_queued_2": "{{ count }} poznámek ve frontě k indexaci",
|
||||
"notes_indexed_0": "{{ count }} poznámka indexována",
|
||||
"notes_indexed_1": "{{ count }} poznámky indexovány",
|
||||
"notes_indexed_2": "{{ count }} poznámek indexováno"
|
||||
},
|
||||
"add_link": {
|
||||
"add_link": "Přidat odkaz",
|
||||
"help_on_links": "Nápověda k odkazům",
|
||||
"note": "Poznámka",
|
||||
"search_note": "hledat poznámku podle názvu",
|
||||
"link_title": "Název odkazu",
|
||||
"button_add_link": "Přidat odkaz"
|
||||
"button_add_link": "Přidat odkaz",
|
||||
"link_title_mirrors": "titulek odkazu odráží momentální titulek poznámky",
|
||||
"link_title_arbitrary": "titulek odkazu může být změněn libovolně"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"prefix": "Prefix: ",
|
||||
"save": "Uložit"
|
||||
"prefix": "Předpona: ",
|
||||
"save": "Uložit",
|
||||
"edit_branch_prefix": "Upravit prefix větve",
|
||||
"edit_branch_prefix_multiple": "Upravit prefix větve pro {{count}} větví",
|
||||
"help_on_tree_prefix": "Nápověda k prefixu stromu",
|
||||
"branch_prefix_saved": "Prefix větve byl uložen.",
|
||||
"branch_prefix_saved_multiple": "Prefix větve byl uložen pro {{count}} větví.",
|
||||
"affected_branches": "Ovlivněné větve ({{count}}):"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Hromadné akce",
|
||||
"affected_notes": "Ovlivněné poznámky",
|
||||
"notes": "Poznámky"
|
||||
"notes": "Poznámky",
|
||||
"include_descendants": "Zahrnout potomky vybraných poznámek",
|
||||
"available_actions": "Dostupné akce",
|
||||
"chosen_actions": "Vybrané akce",
|
||||
"execute_bulk_actions": "Vykonat hromadné akce",
|
||||
"bulk_actions_executed": "Hromadné akce byly úspěšně provedeny.",
|
||||
"labels": "Štítky",
|
||||
"relations": "Relace",
|
||||
"other": "Ostatní",
|
||||
"none_yet": "Zatím žádné akce... přidejte akci kliknutím na jednu z dostupných výše."
|
||||
},
|
||||
"confirm": {
|
||||
"cancel": "Zrušit",
|
||||
"ok": "OK"
|
||||
"ok": "OK",
|
||||
"confirmation": "Potvrzení",
|
||||
"are_you_sure_remove_note": "Opravdu chcete odstranit poznámku „{{title}}“ z mapy vztahů? ",
|
||||
"if_you_dont_check": "Pokud tuto možnost nezaškrtnete, poznámka bude odstraněna pouze z mapy vztahů.",
|
||||
"also_delete_note": "Odstraňte také poznámku"
|
||||
},
|
||||
"delete_notes": {
|
||||
"cancel": "Zrušit",
|
||||
"ok": "OK",
|
||||
"close": "Zavřít"
|
||||
"close": "Zavřít",
|
||||
"delete_notes_preview": "Odstranit náhled poznámek",
|
||||
"delete_all_clones_description": "Odstraňte také všechny klony (lze vrátit zpět v nedávných změnách)",
|
||||
"erase_notes_description": "Normální (měkké) smazání pouze označí poznámky jako smazané a lze je během určité doby obnovit (v dialogovém okně posledních změn). Zaškrtnutím této možnosti se poznámky okamžitě vymažou a nebude možné je obnovit.",
|
||||
"erase_notes_warning": "Trvale smažte poznámky (nelze vrátit zpět), včetně všech klonů. Tím se vynutí opětovné načtení aplikace.",
|
||||
"notes_to_be_deleted": "Následující poznámky budou smazány ({{notesCount}})",
|
||||
"no_note_to_delete": "Žádná poznámka nebude smazána (pouze klony).",
|
||||
"broken_relations_to_be_deleted": "Následující vazby budou přerušeny a smazány ({{relationCount}})",
|
||||
"deleted_relation_text": "Poznámka {{- note}} (bude smazána) je odkazována vazbou {{- relation}} pocházející z {{- source}}."
|
||||
},
|
||||
"export": {
|
||||
"close": "Zavřít"
|
||||
"close": "Zavřít",
|
||||
"export_note_title": "Exportovat poznámku",
|
||||
"export_type_subtree": "Tato poznámka a všechny její odvozené poznámky",
|
||||
"format_html": "HTML – doporučeno, protože zachovává veškeré formátování",
|
||||
"format_html_zip": "HTML v archivu ZIP – toto se doporučuje, protože se tak zachová veškeré formátování.",
|
||||
"format_markdown": "Markdown – zachovává většinu formátování.",
|
||||
"format_opml": "OPML – formát pro výměnu osnov pouze pro text. Formátování, obrázky a soubory nejsou zahrnuty.",
|
||||
"opml_version_1": "OPML v1.0 – pouze prostý text",
|
||||
"opml_version_2": "OPML v2.0 – umožňuje také HTML",
|
||||
"export_type_single": "Pouze tato poznámka bez jejích potomků",
|
||||
"export": "Exportovat",
|
||||
"choose_export_type": "Nejprve vyberte typ exportu",
|
||||
"export_status": "Stav exportu",
|
||||
"export_in_progress": "Export probíhá: {{progressCount}}",
|
||||
"export_finished_successfully": "Export byl úspěšně dokončen.",
|
||||
"format_pdf": "PDF – pro tisk nebo sdílení.",
|
||||
"share-format": "HTML pro publikování na webu – používá stejný motiv jako sdílené poznámky, ale lze jej publikovat jako statický web."
|
||||
},
|
||||
"clone_to": {
|
||||
"clone_notes_to": "Klonovat poznámky do...",
|
||||
"help_on_links": "Nápověda k odkazům",
|
||||
"notes_to_clone": "Poznámky na klonování",
|
||||
"search_for_note_by_its_name": "hledat poznámku dle jejího názvu",
|
||||
"prefix_optional": "Předpona (volitelná)",
|
||||
"target_parent_note": "Zaměřit rodičovskou poznámku",
|
||||
"cloned_note_prefix_title": "Klonovaná poznámka se zobrazí ve stromu poznámek s danou předponou",
|
||||
"clone_to_selected_note": "Klonovat vybranou poznámku",
|
||||
"no_path_to_clone_to": "Žádná cest pro klonování.",
|
||||
"note_cloned": "Poznámka: „{{clonedTitle}}“ bylo naklonováno do „{{targetTitle}}“"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"bundle-error": {
|
||||
"title": "Benutzerdefiniertes Skript konnte nicht geladen werden",
|
||||
"message": "Skript von der Notiz mit der ID \"{{id}}\", und dem Titel \"{{title}}\" konnte nicht ausgeführt werden wegen:\n\n{{message}}"
|
||||
"message": "Skript aus der Notiz \"{{title}}\" mit der ID \"{{id}}\", konnte nicht ausgeführt werden wegen:\n\n{{message}}"
|
||||
}
|
||||
},
|
||||
"add_link": {
|
||||
@@ -39,7 +39,10 @@
|
||||
"help_on_tree_prefix": "Hilfe zum Baumpräfix",
|
||||
"prefix": "Präfix: ",
|
||||
"save": "Speichern",
|
||||
"branch_prefix_saved": "Zweigpräfix wurde gespeichert."
|
||||
"branch_prefix_saved": "Zweigpräfix wurde gespeichert.",
|
||||
"branch_prefix_saved_multiple": "Der Zweigpräfix wurde für {{count}} Zweige gespeichert.",
|
||||
"edit_branch_prefix_multiple": "Branch-Präfix für {{count}} Zweige bearbeiten",
|
||||
"affected_branches": "Betroffene Zweige ({{count}}):"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Massenaktionen",
|
||||
@@ -684,7 +687,8 @@
|
||||
"convert_into_attachment_failed": "Konvertierung der Notiz '{{title}}' fehlgeschlagen.",
|
||||
"convert_into_attachment_successful": "Notiz '{{title}}' wurde als Anhang konvertiert.",
|
||||
"convert_into_attachment_prompt": "Bist du dir sicher, dass du die Notiz '{{title}}' in ein Anhang der übergeordneten Notiz konvertieren möchtest?",
|
||||
"print_pdf": "Export als PDF..."
|
||||
"print_pdf": "Export als PDF...",
|
||||
"open_note_on_server": "Öffne Notiz auf dem Server"
|
||||
},
|
||||
"onclick_button": {
|
||||
"no_click_handler": "Das Schaltflächen-Widget „{{componentId}}“ hat keinen definierten Klick-Handler"
|
||||
@@ -728,9 +732,9 @@
|
||||
"zoom_out_title": "Herauszoomen"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} Rückverlinkung",
|
||||
"backlinks": "{{count}} Rückverlinkungen",
|
||||
"relation": "Beziehung"
|
||||
"relation": "Beziehung",
|
||||
"backlink_one": "{{count}} Rückverlinkung",
|
||||
"backlink_other": "{{count}} Rückverlinkungen"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"insert_child_note": "Untergeordnete Notiz einfügen",
|
||||
@@ -757,7 +761,6 @@
|
||||
"grid": "Gitter",
|
||||
"list": "Liste",
|
||||
"collapse_all_notes": "Alle Notizen einklappen",
|
||||
"expand_all_children": "Unternotizen ausklappen",
|
||||
"collapse": "Einklappen",
|
||||
"expand": "Ausklappen",
|
||||
"invalid_view_type": "Ungültiger Ansichtstyp „{{type}}“",
|
||||
@@ -767,7 +770,11 @@
|
||||
"geo-map": "Weltkarte",
|
||||
"board": "Tafel",
|
||||
"include_archived_notes": "Zeige archivierte Notizen",
|
||||
"presentation": "Präsentation"
|
||||
"presentation": "Präsentation",
|
||||
"expand_all_levels": "Alle Ebenen erweitern",
|
||||
"expand_tooltip": "Erweitert die direkten Unterelemente dieser Sammlung (eine Ebene tiefer). Für weitere Optionen auf den Pfeil rechts klicken.",
|
||||
"expand_first_level": "Direkte Unterelemente erweitern",
|
||||
"expand_nth_level": "{{depth}} Ebenen erweitern"
|
||||
},
|
||||
"edited_notes": {
|
||||
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
|
||||
@@ -830,7 +837,8 @@
|
||||
"search": "Suchen"
|
||||
},
|
||||
"note_properties": {
|
||||
"this_note_was_originally_taken_from": "Diese Notiz stammt ursprünglich aus:"
|
||||
"this_note_was_originally_taken_from": "Diese Notiz stammt ursprünglich aus:",
|
||||
"info": "Info"
|
||||
},
|
||||
"owned_attribute_list": {
|
||||
"owned_attributes": "Eigene Attribute"
|
||||
@@ -1103,7 +1111,8 @@
|
||||
"title": "Inhaltsbreite",
|
||||
"default_description": "Trilium begrenzt standardmäßig die maximale Inhaltsbreite, um die Lesbarkeit für maximierte Bildschirme auf Breitbildschirmen zu verbessern.",
|
||||
"max_width_label": "Maximale Inhaltsbreite in Pixel",
|
||||
"max_width_unit": "Pixel"
|
||||
"max_width_unit": "Pixel",
|
||||
"centerContent": "Inhalt zentriert halten"
|
||||
},
|
||||
"native_title_bar": {
|
||||
"title": "Native Titelleiste (App-Neustart erforderlich)",
|
||||
@@ -1142,7 +1151,10 @@
|
||||
"unit": "Zeichen"
|
||||
},
|
||||
"code_mime_types": {
|
||||
"title": "Verfügbare MIME-Typen im Dropdown-Menü"
|
||||
"title": "Verfügbare MIME-Typen im Dropdown-Menü",
|
||||
"tooltip_syntax_highlighting": "Syntaxhervorhebung",
|
||||
"tooltip_code_block_syntax": "Code-Blöcke in Textnotizen",
|
||||
"tooltip_code_note_syntax": "Code-Notizen"
|
||||
},
|
||||
"vim_key_bindings": {
|
||||
"use_vim_keybindings_in_code_notes": "Verwende VIM-Tastenkombinationen in Codenotizen (kein Ex-Modus)",
|
||||
@@ -1509,7 +1521,8 @@
|
||||
"refresh-saved-search-results": "Gespeicherte Suchergebnisse aktualisieren",
|
||||
"create-child-note": "Unternotiz anlegen",
|
||||
"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."
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "Dieses Fenster immer oben halten"
|
||||
@@ -1612,7 +1625,8 @@
|
||||
"duplicate-launcher": "Launcher duplizieren <kbd data-command=\"duplicateSubtree\">"
|
||||
},
|
||||
"editable-text": {
|
||||
"auto-detect-language": "Automatisch erkannt"
|
||||
"auto-detect-language": "Automatisch erkannt",
|
||||
"keeps-crashing": "Die Bearbeitungskomponente stürzt immer wieder ab. Bitte starten Sie Trilium neu. Wenn das Problem weiterhin besteht, erstellen Sie einen Fehlerbericht."
|
||||
},
|
||||
"highlighting": {
|
||||
"description": "Steuert die Syntaxhervorhebung für Codeblöcke in Textnotizen, Code-Notizen sind nicht betroffen.",
|
||||
@@ -1653,7 +1667,8 @@
|
||||
"copy-link": "Link kopieren",
|
||||
"paste": "Einfügen",
|
||||
"paste-as-plain-text": "Als unformatierten Text einfügen",
|
||||
"search_online": "Suche nach \"{{term}}\" mit {{searchEngine}} starten"
|
||||
"search_online": "Suche nach \"{{term}}\" mit {{searchEngine}} starten",
|
||||
"search_in_trilium": "Suche nach \"{{term}}\" in Trilium"
|
||||
},
|
||||
"image_context_menu": {
|
||||
"copy_reference_to_clipboard": "Referenz in Zwischenablage kopieren",
|
||||
@@ -1714,10 +1729,6 @@
|
||||
"help_title": "Zeige mehr Informationen zu diesem Fenster"
|
||||
},
|
||||
"ai_llm": {
|
||||
"n_notes_queued": "{{ count }} Notiz zur Indizierung vorgemerkt",
|
||||
"n_notes_queued_plural": "{{ count }} Notizen zur Indizierung vorgemerkt",
|
||||
"notes_indexed": "{{ count }} Notiz indiziert",
|
||||
"notes_indexed_plural": "{{ count }} Notizen indiziert",
|
||||
"not_started": "Nicht gestartet",
|
||||
"title": "KI Einstellungen",
|
||||
"processed_notes": "Verarbeitete Notizen",
|
||||
@@ -2027,7 +2038,8 @@
|
||||
"new-item-placeholder": "Notiz Titel eingeben...",
|
||||
"add-column-placeholder": "Spaltenname eingeben...",
|
||||
"edit-note-title": "Klicke zum Editieren des Notiz-Titels",
|
||||
"edit-column-title": "Klicke zum Editieren des Spalten-Titels"
|
||||
"edit-column-title": "Klicke zum Editieren des Spalten-Titels",
|
||||
"column-already-exists": "Die Spalte ist auf dem Board bereits vorhanden."
|
||||
},
|
||||
"command_palette": {
|
||||
"tree-action-name": "Struktur: {{name}}",
|
||||
@@ -2077,5 +2089,18 @@
|
||||
"edit-slide": "Folie bearbeiten",
|
||||
"start-presentation": "Präsentation starten",
|
||||
"slide-overview": "Übersicht der Folien ein-/ausblenden"
|
||||
},
|
||||
"read-only-info": {
|
||||
"read-only-note": "Aktuelle Notiz wird im Lese-Modus angezeigt.",
|
||||
"auto-read-only-note": "Diese Notiz wird im Nur-Lesen-Modus angezeigt, um ein schnelleres Laden zu ermöglichen.",
|
||||
"edit-note": "Notiz bearbeiten"
|
||||
},
|
||||
"calendar_view": {
|
||||
"delete_note": "Notiz löschen..."
|
||||
},
|
||||
"note-color": {
|
||||
"clear-color": "Notizfarbe entfernen",
|
||||
"set-color": "Notizfarbe wählen",
|
||||
"set-custom-color": "Eigene Notizfarbe wählen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,5 @@
|
||||
"title": "Κρίσιμο σφάλμα",
|
||||
"message": "Συνέβη κάποιο κρίσιμο σφάλμα, το οποίο δεν επιτρέπει στην εφαρμογή χρήστη να ξεκινήσει:\n\n{{message}}\n\nΤο πιθανότερο είναι να προκλήθηκε από κάποιο script που απέτυχε απρόοπτα. Δοκιμάστε να ξεκινήσετε την εφαρμογή σε ασφαλή λειτουργία για να λύσετε το πρόβλημα."
|
||||
}
|
||||
},
|
||||
"ai_llm": {
|
||||
"n_notes_queued": "{{ count }} σημείωση στην ουρά για εύρεση",
|
||||
"n_notes_queued_plural": "{{ count }} σημειώσεις στην ουρά για εύρεση",
|
||||
"notes_indexed": "{{ count }} σημείωση με ευρετήριο",
|
||||
"notes_indexed_plural": "{{ count }} σημειώσεις με ευρετήριο"
|
||||
}
|
||||
}
|
||||
|
||||
73
apps/client/src/translations/en-GB/translation.json
Normal file
73
apps/client/src/translations/en-GB/translation.json
Normal file
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"import": {
|
||||
"safeImportTooltip": "Trilium <code>.zip</code> export files can contain executable scripts which may contain harmful behaviour. Safe import will deactivate automatic execution of all imported scripts. Uncheck \"Safe import\" only if the imported archive is supposed to contain executable scripts and you completely trust the contents of the import file.",
|
||||
"shrinkImagesTooltip": "<p>If you check this option, Trilium will attempt to shrink the imported images by scaling and optimisation which may affect the perceived image quality. If unchecked, images will be imported without changes.</p><p>This doesn't apply to <code>.zip</code> imports with metadata since it is assumed these files are already optimised.</p>",
|
||||
"codeImportedAsCode": "Import recognised code files (e.g. <code>.json</code>) as code notes if it's unclear from metadata"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"tooltip": "If you check this option, Trilium will attempt to shrink the uploaded images by scaling and optimisation which may affect the perceived image quality. If unchecked, images will be uploaded without changes."
|
||||
},
|
||||
"attribute_detail": {
|
||||
"auto_read_only_disabled": "text/code notes can be set automatically into read mode when they are too large. You can disable this behaviour on per-note basis by adding this label to the note",
|
||||
"workspace_tab_background_color": "CSS colour used in the note tab when hoisted to this note",
|
||||
"color": "defines colour of the note in note tree, links etc. Use any valid CSS colour value like 'red' or #a13d5f",
|
||||
"color_type": "Colour"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"error_unrecognized_command": "Unrecognised command {{command}}"
|
||||
},
|
||||
"promoted_attributes": {
|
||||
"remove_color": "Remove the colour label"
|
||||
},
|
||||
"max_content_width": {
|
||||
"centerContent": "Keep content centred"
|
||||
},
|
||||
"theme": {
|
||||
"auto_theme": "Legacy (Follow system colour scheme)",
|
||||
"triliumnext": "Trilium (Follow system colour scheme)"
|
||||
},
|
||||
"search_engine": {
|
||||
"custom_name_placeholder": "Customise search engine name",
|
||||
"custom_url_placeholder": "Customise search engine url"
|
||||
},
|
||||
"highlights_list": {
|
||||
"description": "You can customise the highlights list displayed in the right panel:",
|
||||
"color": "Coloured text",
|
||||
"bg_color": "Text with background colour"
|
||||
},
|
||||
"table_of_contents": {
|
||||
"description": "Table of contents will appear in text notes when the note has more than a defined number of headings. You can customise this number:"
|
||||
},
|
||||
"custom_date_time_format": {
|
||||
"description": "Customise the format of the date and time inserted via <shortcut /> or the toolbar. See <doc>Day.js docs</doc> for available format tokens."
|
||||
},
|
||||
"i18n": {
|
||||
"title": "Localisation"
|
||||
},
|
||||
"attachment_detail_2": {
|
||||
"unrecognized_role": "Unrecognised attachment role '{{role}}'."
|
||||
},
|
||||
"ai_llm": {
|
||||
"reprocess_index_started": "Search index optimisation started in the background",
|
||||
"index_rebuilding": "Optimising index ({{percentage}}%)",
|
||||
"index_rebuild_complete": "Index optimisation complete"
|
||||
},
|
||||
"highlighting": {
|
||||
"color-scheme": "Colour Scheme"
|
||||
},
|
||||
"code_theme": {
|
||||
"color-scheme": "Colour scheme"
|
||||
},
|
||||
"call_to_action": {
|
||||
"background_effects_message": "On Windows devices, background effects are now fully stable. The background effects adds a touch of colour to the user interface by blurring the background behind it. This technique is also used in other applications such as Windows Explorer."
|
||||
},
|
||||
"settings_appearance": {
|
||||
"related_code_blocks": "Colour scheme for code blocks in text notes",
|
||||
"related_code_notes": "Colour scheme for code notes"
|
||||
},
|
||||
"note-color": {
|
||||
"clear-color": "Clear note colour",
|
||||
"set-color": "Set note colour",
|
||||
"set-custom-color": "Set custom note colour"
|
||||
}
|
||||
}
|
||||
@@ -112,6 +112,7 @@
|
||||
},
|
||||
"help": {
|
||||
"title": "Cheatsheet",
|
||||
"editShortcuts": "Edit keyboard shortcuts",
|
||||
"noteNavigation": "Note navigation",
|
||||
"goUpDown": "go up/down in the list of notes",
|
||||
"collapseExpand": "collapse/expand node",
|
||||
@@ -735,8 +736,8 @@
|
||||
"zoom_out_title": "Zoom Out"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} Backlink",
|
||||
"backlinks": "{{count}} Backlinks",
|
||||
"backlink_one": "{{count}} Backlink",
|
||||
"backlink_other": "{{count}} Backlinks",
|
||||
"relation": "relation"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
@@ -764,9 +765,12 @@
|
||||
"grid": "Grid",
|
||||
"list": "List",
|
||||
"collapse_all_notes": "Collapse all notes",
|
||||
"expand_all_children": "Expand all children",
|
||||
"expand_tooltip": "Expands the direct children of this collection (one level deep). For more options, press the arrow on the right.",
|
||||
"collapse": "Collapse",
|
||||
"expand": "Expand",
|
||||
"expand_first_level": "Expand direct children",
|
||||
"expand_nth_level": "Expand {{depth}} levels",
|
||||
"expand_all_levels": "Expand all levels",
|
||||
"book_properties": "Collection Properties",
|
||||
"invalid_view_type": "Invalid view type '{{type}}'",
|
||||
"calendar": "Calendar",
|
||||
@@ -837,7 +841,8 @@
|
||||
"search": "Search"
|
||||
},
|
||||
"note_properties": {
|
||||
"this_note_was_originally_taken_from": "This note was originally taken from:"
|
||||
"this_note_was_originally_taken_from": "This note was originally taken from:",
|
||||
"info": "Info"
|
||||
},
|
||||
"owned_attribute_list": {
|
||||
"owned_attributes": "Owned Attributes"
|
||||
@@ -1266,11 +1271,7 @@
|
||||
"indexing_stopped": "Indexing stopped",
|
||||
"indexing_in_progress": "Indexing in progress...",
|
||||
"last_indexed": "Last Indexed",
|
||||
"n_notes_queued": "{{ count }} note queued for indexing",
|
||||
"n_notes_queued_plural": "{{ count }} notes queued for indexing",
|
||||
"note_chat": "Note Chat",
|
||||
"notes_indexed": "{{ count }} note indexed",
|
||||
"notes_indexed_plural": "{{ count }} notes indexed",
|
||||
"sources": "Sources",
|
||||
"start_indexing": "Start Indexing",
|
||||
"use_advanced_context": "Use Advanced Context",
|
||||
@@ -1308,7 +1309,10 @@
|
||||
"title": "Editor"
|
||||
},
|
||||
"code_mime_types": {
|
||||
"title": "Available MIME types in the dropdown"
|
||||
"title": "Available MIME types in the dropdown",
|
||||
"tooltip_syntax_highlighting": "Syntax highlighting",
|
||||
"tooltip_code_block_syntax": "Code blocks in Text notes",
|
||||
"tooltip_code_note_syntax": "Code notes"
|
||||
},
|
||||
"vim_key_bindings": {
|
||||
"use_vim_keybindings_in_code_notes": "Vim keybindings",
|
||||
@@ -1629,7 +1633,7 @@
|
||||
"import-into-note": "Import into note",
|
||||
"apply-bulk-actions": "Apply bulk actions",
|
||||
"converted-to-attachments": "{{count}} notes have been converted to attachments.",
|
||||
"convert-to-attachment-confirm": "Are you sure you want to convert note selected notes into attachments of their parent notes?",
|
||||
"convert-to-attachment-confirm": "Are you sure you want to convert the selected notes into attachments of their parent notes? This operation only applies to Image notes, other notes will be skipped.",
|
||||
"open-in-popup": "Quick edit"
|
||||
},
|
||||
"shared_info": {
|
||||
@@ -1640,7 +1644,6 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "Currently viewing a read-only note.",
|
||||
"auto-read-only-note": "This note is shown in a read-only mode for faster loading.",
|
||||
"auto-read-only-learn-more": "Learn more",
|
||||
"edit-note": "Edit note"
|
||||
},
|
||||
"note_types": {
|
||||
@@ -1720,7 +1723,8 @@
|
||||
"refresh-saved-search-results": "Refresh saved search results",
|
||||
"create-child-note": "Create child note",
|
||||
"unhoist": "Unhoist",
|
||||
"toggle-sidebar": "Toggle sidebar"
|
||||
"toggle-sidebar": "Toggle sidebar",
|
||||
"dropping-not-allowed": "Dropping notes into this location is not allowed."
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "Keep Window on Top"
|
||||
@@ -1823,7 +1827,8 @@
|
||||
"duplicate-launcher": "Duplicate launcher <kbd data-command=\"duplicateSubtree\">"
|
||||
},
|
||||
"editable-text": {
|
||||
"auto-detect-language": "Auto-detected"
|
||||
"auto-detect-language": "Auto-detected",
|
||||
"keeps-crashing": "Editing component keeps crashing. Please try restarting Trilium. If problem persists, consider creating a bug report."
|
||||
},
|
||||
"highlighting": {
|
||||
"title": "Code Blocks",
|
||||
@@ -1864,6 +1869,7 @@
|
||||
"copy-link": "Copy link",
|
||||
"paste": "Paste",
|
||||
"paste-as-plain-text": "Paste as plain text",
|
||||
"search_in_trilium": "Search for \"{{term}}\" in Trilium",
|
||||
"search_online": "Search for \"{{term}}\" with {{searchEngine}}"
|
||||
},
|
||||
"image_context_menu": {
|
||||
@@ -1873,6 +1879,7 @@
|
||||
"link_context_menu": {
|
||||
"open_note_in_new_tab": "Open note in a new tab",
|
||||
"open_note_in_new_split": "Open note in a new split",
|
||||
"open_note_in_other_split": "Open note in the other split",
|
||||
"open_note_in_new_window": "Open note in a new window",
|
||||
"open_note_in_popup": "Quick edit"
|
||||
},
|
||||
@@ -2034,7 +2041,8 @@
|
||||
"add-column": "Add Column",
|
||||
"add-column-placeholder": "Enter column name...",
|
||||
"edit-note-title": "Click to edit note title",
|
||||
"edit-column-title": "Click to edit column title"
|
||||
"edit-column-title": "Click to edit column title",
|
||||
"column-already-exists": "This column already exists on the board."
|
||||
},
|
||||
"presentation_view": {
|
||||
"edit-slide": "Edit this slide",
|
||||
@@ -2091,5 +2099,13 @@
|
||||
},
|
||||
"collections": {
|
||||
"rendering_error": "Unable to show content due to an error."
|
||||
},
|
||||
"note-color": {
|
||||
"clear-color": "Clear note color",
|
||||
"set-color": "Set note color",
|
||||
"set-custom-color": "Set custom note color"
|
||||
},
|
||||
"popup-editor": {
|
||||
"maximize": "Switch to full editor"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -690,7 +690,8 @@
|
||||
"convert_into_attachment_failed": "La conversión de nota '{{title}}' falló.",
|
||||
"convert_into_attachment_successful": "La nota '{{title}}' ha sido convertida a un archivo adjunto.",
|
||||
"convert_into_attachment_prompt": "¿Está seguro que desea convertir la nota '{{title}}' en un archivo adjunto de la nota padre?",
|
||||
"print_pdf": "Exportar como PDF..."
|
||||
"print_pdf": "Exportar como PDF...",
|
||||
"open_note_on_server": "Abrir nota en el servidor"
|
||||
},
|
||||
"onclick_button": {
|
||||
"no_click_handler": "El widget de botón '{{componentId}}' no tiene un controlador de clics definido"
|
||||
@@ -734,9 +735,10 @@
|
||||
"zoom_out_title": "Alejar"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} Vínculo de retroceso",
|
||||
"backlinks": "{{count}} vínculos de retroceso",
|
||||
"relation": "relación"
|
||||
"relation": "relación",
|
||||
"backlink_one": "{{count}} Vínculo de retroceso",
|
||||
"backlink_many": "",
|
||||
"backlink_other": "{{count}} vínculos de retroceso"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"insert_child_note": "Insertar subnota",
|
||||
@@ -763,7 +765,6 @@
|
||||
"grid": "Cuadrícula",
|
||||
"list": "Lista",
|
||||
"collapse_all_notes": "Contraer todas las notas",
|
||||
"expand_all_children": "Ampliar todas las subnotas",
|
||||
"collapse": "Colapsar",
|
||||
"expand": "Expandir",
|
||||
"invalid_view_type": "Tipo de vista inválida '{{type}}'",
|
||||
@@ -773,7 +774,11 @@
|
||||
"geo-map": "Mapa Geo",
|
||||
"board": "Tablero",
|
||||
"include_archived_notes": "Mostrar notas archivadas",
|
||||
"presentation": "Presentación"
|
||||
"presentation": "Presentación",
|
||||
"expand_tooltip": "Expande las notas hijas inmediatas de esta colección (un nivel). Para más opciones, pulsa la flecha a la derecha.",
|
||||
"expand_first_level": "Expandir hijos inmediatos",
|
||||
"expand_nth_level": "Expandir {{depth}} niveles",
|
||||
"expand_all_levels": "Expandir todos los niveles"
|
||||
},
|
||||
"edited_notes": {
|
||||
"no_edited_notes_found": "Aún no hay notas editadas en este día...",
|
||||
@@ -836,7 +841,8 @@
|
||||
"search": "Buscar"
|
||||
},
|
||||
"note_properties": {
|
||||
"this_note_was_originally_taken_from": "Esta nota fue tomada originalmente de:"
|
||||
"this_note_was_originally_taken_from": "Esta nota fue tomada originalmente de:",
|
||||
"info": "Información"
|
||||
},
|
||||
"owned_attribute_list": {
|
||||
"owned_attributes": "Atributos propios"
|
||||
@@ -1257,12 +1263,7 @@
|
||||
"indexing_stopped": "Indexado detenido",
|
||||
"indexing_in_progress": "Indexado en progreso...",
|
||||
"last_indexed": "Último indexado",
|
||||
"n_notes_queued_0": "{{ count }} nota agregada a la cola para indexar",
|
||||
"n_notes_queued_1": "{{ count }} notas agregadas a la cola para indexar",
|
||||
"n_notes_queued_2": "",
|
||||
"note_chat": "Chat de nota",
|
||||
"notes_indexed": "{{ count }} nota indexada",
|
||||
"notes_indexed_plural": "{{ count }} notas indexadas",
|
||||
"sources": "Fuentes",
|
||||
"start_indexing": "Comenzar indexado",
|
||||
"use_advanced_context": "Usar contexto avanzado",
|
||||
@@ -1300,7 +1301,10 @@
|
||||
"title": "Editor"
|
||||
},
|
||||
"code_mime_types": {
|
||||
"title": "Tipos MIME disponibles en el menú desplegable"
|
||||
"title": "Tipos MIME disponibles en el menú desplegable",
|
||||
"tooltip_syntax_highlighting": "Resaltado de sintaxis",
|
||||
"tooltip_code_block_syntax": "Bloques de código en notas de texto",
|
||||
"tooltip_code_note_syntax": "Notas de código"
|
||||
},
|
||||
"vim_key_bindings": {
|
||||
"use_vim_keybindings_in_code_notes": "Atajos de teclas de Vim",
|
||||
@@ -1850,7 +1854,8 @@
|
||||
"copy-link": "Copiar enlace",
|
||||
"paste": "Pegar",
|
||||
"paste-as-plain-text": "Pegar como texto plano",
|
||||
"search_online": "Buscar \"{{term}}\" con {{searchEngine}}"
|
||||
"search_online": "Buscar \"{{term}}\" con {{searchEngine}}",
|
||||
"search_in_trilium": "Buscar \"{{term}}\" en Trilium"
|
||||
},
|
||||
"image_context_menu": {
|
||||
"copy_reference_to_clipboard": "Copiar referencia al portapapeles",
|
||||
@@ -1991,7 +1996,8 @@
|
||||
"add-column-placeholder": "Ingresar título de la columna...",
|
||||
"edit-note-title": "Haga clic para editar el título de la nota",
|
||||
"edit-column-title": "Haga clic para editar el título de la columna",
|
||||
"remove-from-board": "Eliminar del tablero"
|
||||
"remove-from-board": "Eliminar del tablero",
|
||||
"column-already-exists": "Esta columna ya existe en el tablero."
|
||||
},
|
||||
"content_renderer": {
|
||||
"open_externally": "Abrir externamente"
|
||||
@@ -2086,10 +2092,14 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "Actualmente, está viendo una nota de solo lectura.",
|
||||
"auto-read-only-note": "Esta nota se muestra en modo de solo lectura para una carga más rápida.",
|
||||
"auto-read-only-learn-more": "Para saber más",
|
||||
"edit-note": "Editar nota"
|
||||
},
|
||||
"calendar_view": {
|
||||
"delete_note": "Eliminar nota..."
|
||||
},
|
||||
"note-color": {
|
||||
"clear-color": "Borrar color de nota",
|
||||
"set-color": "Asignar color de nota",
|
||||
"set-custom-color": "Asignar color de nota personalizado"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,10 @@
|
||||
"help_on_tree_prefix": "Aide sur le préfixe de l'arbre",
|
||||
"prefix": "Préfixe : ",
|
||||
"save": "Sauvegarder",
|
||||
"branch_prefix_saved": "Le préfixe de la branche a été enregistré."
|
||||
"branch_prefix_saved": "Le préfixe de la branche a été enregistré.",
|
||||
"edit_branch_prefix_multiple": "Modifier le préfixe de branche pour {{count}} branches",
|
||||
"branch_prefix_saved_multiple": "Le préfixe de la branche a été sauvegardé pour {{count}} branches.",
|
||||
"affected_branches": "Branches impactées ({{count}}):"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Actions groupées",
|
||||
@@ -730,9 +733,10 @@
|
||||
"zoom_out_title": "Zoom arrière"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} Lien inverse",
|
||||
"backlinks": "{{count}} Liens inverses",
|
||||
"relation": "relation"
|
||||
"relation": "relation",
|
||||
"backlink_one": "{{count}} Lien inverse",
|
||||
"backlink_many": "",
|
||||
"backlink_other": "{{count}} Liens inverses"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"insert_child_note": "Insérer une note enfant",
|
||||
@@ -759,7 +763,6 @@
|
||||
"grid": "Grille",
|
||||
"list": "Liste",
|
||||
"collapse_all_notes": "Réduire toutes les notes",
|
||||
"expand_all_children": "Développer tous les enfants",
|
||||
"collapse": "Réduire",
|
||||
"expand": "Développer",
|
||||
"invalid_view_type": "Type de vue non valide '{{type}}'",
|
||||
@@ -832,7 +835,8 @@
|
||||
"search": "Recherche"
|
||||
},
|
||||
"note_properties": {
|
||||
"this_note_was_originally_taken_from": "Cette note est initialement extraite de :"
|
||||
"this_note_was_originally_taken_from": "Cette note est initialement extraite de :",
|
||||
"info": "Infos"
|
||||
},
|
||||
"owned_attribute_list": {
|
||||
"owned_attributes": "Attributs propres"
|
||||
@@ -1763,12 +1767,6 @@
|
||||
"not_started": "Non démarré",
|
||||
"title": "Paramètres IA",
|
||||
"processed_notes": "Notes traitées",
|
||||
"n_notes_queued_0": "{{ count }} note en attente d’indexation",
|
||||
"n_notes_queued_1": "{{ count }} notes en attente d’indexation",
|
||||
"n_notes_queued_2": "",
|
||||
"notes_indexed_0": "{{ count }} note indexée",
|
||||
"notes_indexed_1": "{{ count }} notes indexées",
|
||||
"notes_indexed_2": "",
|
||||
"anthropic_url_description": "URL de base pour l'API Anthropic (par défaut : https ://api.anthropic.com)",
|
||||
"anthropic_model_description": "Modèles Anthropic Claude pour la complétion",
|
||||
"voyage_settings": "Réglages d'IA Voyage",
|
||||
|
||||
@@ -324,7 +324,8 @@
|
||||
"copy-link": "Copia collegamento",
|
||||
"paste-as-plain-text": "Incolla come testo semplice",
|
||||
"add-term-to-dictionary": "Aggiungi \"{{term}}\" al dizionario",
|
||||
"search_online": "Cerca \"{{term}}\" con {{searchEngine}}"
|
||||
"search_online": "Cerca \"{{term}}\" con {{searchEngine}}",
|
||||
"search_in_trilium": "Cerca \"{{term}}\" in Trilium"
|
||||
},
|
||||
"editing": {
|
||||
"editor_type": {
|
||||
@@ -428,7 +429,8 @@
|
||||
"add-column": "Aggiungi colonna",
|
||||
"add-column-placeholder": "Inserisci il nome della colonna...",
|
||||
"edit-note-title": "Fare clic per modificare il titolo della nota",
|
||||
"edit-column-title": "Fare clic per modificare il titolo della colonna"
|
||||
"edit-column-title": "Fare clic per modificare il titolo della colonna",
|
||||
"column-already-exists": "Questa colonna esiste già nella bacheca."
|
||||
},
|
||||
"backup": {
|
||||
"enable_weekly_backup": "Abilita le archiviazioni settimanali",
|
||||
@@ -613,7 +615,8 @@
|
||||
"showSQLConsole": "mostra console SQL",
|
||||
"other": "Altro",
|
||||
"quickSearch": "concentrati sull'input della ricerca rapida",
|
||||
"inPageSearch": "ricerca all'interno della pagina"
|
||||
"inPageSearch": "ricerca all'interno della pagina",
|
||||
"editShortcuts": "Modifica scorciatoie da tastiera"
|
||||
},
|
||||
"i18n": {
|
||||
"saturday": "Sabato",
|
||||
@@ -637,12 +640,6 @@
|
||||
"friday": "Venerdì"
|
||||
},
|
||||
"ai_llm": {
|
||||
"n_notes_queued_0": "{{ count }} nota in coda per l'indicizzazione",
|
||||
"n_notes_queued_1": "{{ count }} note in coda per l'indicizzazione",
|
||||
"n_notes_queued_2": "{{ count }} note in coda per l'indicizzazione",
|
||||
"notes_indexed_0": "{{ count }} nota indicizzata",
|
||||
"notes_indexed_1": "{{ count }} note indicizzate",
|
||||
"notes_indexed_2": "{{ count }} note indicizzate",
|
||||
"not_started": "Non iniziato",
|
||||
"title": "Impostazioni AI",
|
||||
"processed_notes": "Note elaborate",
|
||||
@@ -1262,7 +1259,8 @@
|
||||
"convert_into_attachment_failed": "Conversione della nota '{{title}}' fallita.",
|
||||
"convert_into_attachment_successful": "Nota '{{title}}' è stato convertito in allegato.",
|
||||
"convert_into_attachment_prompt": "Sei sicuro di voler convertire la nota '{{title}}' in un allegato della nota padre?",
|
||||
"print_pdf": "Esporta come PDF..."
|
||||
"print_pdf": "Esporta come PDF...",
|
||||
"open_note_on_server": "Apri una nota sul server"
|
||||
},
|
||||
"onclick_button": {
|
||||
"no_click_handler": "Il widget pulsante '{{componentId}}' non ha un gestore di clic definito"
|
||||
@@ -1306,9 +1304,10 @@
|
||||
"zoom_out_title": "Rimpicciolisci"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} Backlink",
|
||||
"backlinks": "{{count}} Backlinks",
|
||||
"relation": "relazione"
|
||||
"relation": "relazione",
|
||||
"backlink_one": "{{count}} Backlink",
|
||||
"backlink_many": "{{count}} Backlinks",
|
||||
"backlink_other": "{{count}} Backlinks"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"insert_child_note": "Inserisci nota secondaria",
|
||||
@@ -1335,7 +1334,6 @@
|
||||
"grid": "Griglia",
|
||||
"list": "Lista",
|
||||
"collapse_all_notes": "Comprimi tutte le note",
|
||||
"expand_all_children": "Espandi tutti i bambini",
|
||||
"collapse": "Crollo",
|
||||
"expand": "Espandere",
|
||||
"book_properties": "Proprietà della raccolta",
|
||||
@@ -1345,7 +1343,11 @@
|
||||
"geo-map": "Mappa geografica",
|
||||
"board": "Asse",
|
||||
"presentation": "Presentazione",
|
||||
"include_archived_notes": "Mostra note archiviate"
|
||||
"include_archived_notes": "Mostra note archiviate",
|
||||
"expand_tooltip": "Espande i figli diretti di questa raccolta (a un livello di profondità). Per ulteriori opzioni, premere la freccia a destra.",
|
||||
"expand_first_level": "Espandi figli diretti",
|
||||
"expand_nth_level": "Espandi {{depth}} livelli",
|
||||
"expand_all_levels": "Espandi tutti i livelli"
|
||||
},
|
||||
"edited_notes": {
|
||||
"no_edited_notes_found": "Nessuna nota modificata per questo giorno...",
|
||||
@@ -1408,7 +1410,8 @@
|
||||
"search": "Ricerca"
|
||||
},
|
||||
"note_properties": {
|
||||
"this_note_was_originally_taken_from": "Questa nota è stata originariamente tratta da:"
|
||||
"this_note_was_originally_taken_from": "Questa nota è stata originariamente tratta da:",
|
||||
"info": "Informazioni"
|
||||
},
|
||||
"owned_attribute_list": {
|
||||
"owned_attributes": "Attributi posseduti"
|
||||
@@ -1539,9 +1542,9 @@
|
||||
"create_label": "Per iniziare, crea un'etichetta con l'indirizzo URL che desideri incorporare, ad esempio #webViewSrc=\"https://www.google.com\""
|
||||
},
|
||||
"vacuum_database": {
|
||||
"title": "Database del vuoto",
|
||||
"title": "Pulizia del database",
|
||||
"description": "Questa operazione ricostruirà il database, generando in genere un file di dimensioni inferiori. In realtà, nessun dato verrà modificato.",
|
||||
"button_text": "Database del vuoto",
|
||||
"button_text": "Pulizia del database",
|
||||
"vacuuming_database": "Aspirazione del database...",
|
||||
"database_vacuumed": "Il database è stato svuotato"
|
||||
},
|
||||
@@ -1623,7 +1626,10 @@
|
||||
"title": "Redattore"
|
||||
},
|
||||
"code_mime_types": {
|
||||
"title": "Tipi MIME disponibili nel menu a discesa"
|
||||
"title": "Tipi MIME disponibili nel menu a discesa",
|
||||
"tooltip_syntax_highlighting": "Evidenziazione della sintassi",
|
||||
"tooltip_code_block_syntax": "Blocchi di codice nelle note di testo",
|
||||
"tooltip_code_note_syntax": "Note sul codice"
|
||||
},
|
||||
"vim_key_bindings": {
|
||||
"use_vim_keybindings_in_code_notes": "Combinazioni di tasti di Vim",
|
||||
@@ -1795,8 +1801,8 @@
|
||||
"relation-map": "Mappa delle relazioni",
|
||||
"note-map": "Nota Mappa",
|
||||
"render-note": "Nota di rendering",
|
||||
"book": "Collezione",
|
||||
"mermaid-diagram": "Diagramma della sirena",
|
||||
"book": "Raccolta",
|
||||
"mermaid-diagram": "Diagramma Mermaid",
|
||||
"canvas": "Tela",
|
||||
"web-view": "Visualizzazione Web",
|
||||
"mind-map": "Mappa mentale",
|
||||
@@ -1847,7 +1853,8 @@
|
||||
"refresh-saved-search-results": "Aggiorna i risultati della ricerca salvati",
|
||||
"create-child-note": "Crea nota figlio",
|
||||
"unhoist": "Sganciare",
|
||||
"toggle-sidebar": "Attiva/disattiva la barra laterale"
|
||||
"toggle-sidebar": "Attiva/disattiva la barra laterale",
|
||||
"dropping-not-allowed": "Non è consentito lasciare appunti in questa posizione."
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "Mantieni la finestra in primo piano"
|
||||
@@ -1931,7 +1938,8 @@
|
||||
"duplicate-launcher": "Duplica il launcher <kbd data-command=\"duplicateSubtree\">"
|
||||
},
|
||||
"editable-text": {
|
||||
"auto-detect-language": "Rilevato automaticamente"
|
||||
"auto-detect-language": "Rilevato automaticamente",
|
||||
"keeps-crashing": "Il componente di modifica continua a bloccarsi. Prova a riavviare Trilium. Se il problema persiste, valuta la possibilità di creare una segnalazione di bug."
|
||||
},
|
||||
"highlighting": {
|
||||
"title": "Blocchi di codice",
|
||||
@@ -1959,7 +1967,8 @@
|
||||
"open_note_in_new_tab": "Apri la nota in una nuova scheda",
|
||||
"open_note_in_new_split": "Apri nota in una nuova divisione",
|
||||
"open_note_in_new_window": "Apri la nota in una nuova finestra",
|
||||
"open_note_in_popup": "Modifica rapida"
|
||||
"open_note_in_popup": "Modifica rapida",
|
||||
"open_note_in_other_split": "Apri nota nell'altra divisione"
|
||||
},
|
||||
"help-button": {
|
||||
"title": "Apri la pagina di aiuto pertinente"
|
||||
@@ -2087,10 +2096,17 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "Stai visualizzando una nota di sola lettura.",
|
||||
"auto-read-only-note": "Questa nota viene visualizzata in modalità di sola lettura per un caricamento più rapido.",
|
||||
"auto-read-only-learn-more": "Per saperne di più",
|
||||
"edit-note": "Modifica nota"
|
||||
},
|
||||
"calendar_view": {
|
||||
"delete_note": "Eliminazione nota..."
|
||||
},
|
||||
"note-color": {
|
||||
"set-color": "Imposta colore nota",
|
||||
"set-custom-color": "Imposta colore personalizzato per le note",
|
||||
"clear-color": "Pulisci colore della nota"
|
||||
},
|
||||
"popup-editor": {
|
||||
"maximize": "Passa all'editor completo"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,7 +312,8 @@
|
||||
"moveNoteUpDown": "ノートリストでノートを上/下に移動",
|
||||
"notSet": "未設定",
|
||||
"goUpDown": "ノートのリストで上下する",
|
||||
"editBranchPrefix": "アクティブノートのクローンの <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/tree-concepts.html#prefix\">プレフィックス</a> を編集する"
|
||||
"editBranchPrefix": "アクティブノートのクローンの <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/tree-concepts.html#prefix\">プレフィックス</a> を編集する",
|
||||
"editShortcuts": "キーボードショートカットを編集"
|
||||
},
|
||||
"import": {
|
||||
"importIntoNote": "ノートにインポート",
|
||||
@@ -496,7 +497,8 @@
|
||||
"new-item-placeholder": "ノートのタイトルを入力...",
|
||||
"add-column-placeholder": "列名を入力...",
|
||||
"edit-note-title": "クリックしてノートのタイトルを編集",
|
||||
"edit-column-title": "クリックして列のタイトルを編集"
|
||||
"edit-column-title": "クリックして列のタイトルを編集",
|
||||
"column-already-exists": "この列は既にボード上に存在します。"
|
||||
},
|
||||
"code_buttons": {
|
||||
"execute_button_title": "スクリプトを実行",
|
||||
@@ -530,7 +532,6 @@
|
||||
"grid": "グリッド",
|
||||
"list": "リスト",
|
||||
"collapse_all_notes": "すべてのノートを折りたたむ",
|
||||
"expand_all_children": "すべての子を展開",
|
||||
"collapse": "折りたたむ",
|
||||
"expand": "展開",
|
||||
"book_properties": "コレクションプロパティ",
|
||||
@@ -541,7 +542,11 @@
|
||||
"geo-map": "ジオマップ",
|
||||
"board": "ボード",
|
||||
"include_archived_notes": "アーカイブされたノートを表示",
|
||||
"presentation": "プレゼンテーション"
|
||||
"presentation": "プレゼンテーション",
|
||||
"expand_tooltip": "このコレクションの直下の子(1階層下)を展開します。その他のオプションについては、右側の矢印を押してください。",
|
||||
"expand_first_level": "直下の子を展開",
|
||||
"expand_nth_level": "{{depth}} 階層下まで展開",
|
||||
"expand_all_levels": "すべての階層を展開"
|
||||
},
|
||||
"note_types": {
|
||||
"geo-map": "ジオマップ",
|
||||
@@ -688,6 +693,7 @@
|
||||
"outside_hoisted": "このパスはホイストされたノートの外側にあるため、ホイストを解除する必要があります。"
|
||||
},
|
||||
"note_properties": {
|
||||
"info": "情報",
|
||||
"this_note_was_originally_taken_from": "このノートは元々以下から引用したものです:"
|
||||
},
|
||||
"similar_notes": {
|
||||
@@ -1152,7 +1158,8 @@
|
||||
"open_note_in_popup": "クイック編集",
|
||||
"open_note_in_new_tab": "新しいタブでノートを開く",
|
||||
"open_note_in_new_split": "新しく分割してノートを開く",
|
||||
"open_note_in_new_window": "新しいウィンドウでノートを開く"
|
||||
"open_note_in_new_window": "新しいウィンドウでノートを開く",
|
||||
"open_note_in_other_split": "他の分割画面でノートを開く"
|
||||
},
|
||||
"note_tooltip": {
|
||||
"quick-edit": "クイック編集",
|
||||
@@ -1207,7 +1214,8 @@
|
||||
"unhoist": "ホイスト解除",
|
||||
"saved-search-note-refreshed": "保存した検索ノートが更新されました。",
|
||||
"refresh-saved-search-results": "保存した検索結果を更新",
|
||||
"toggle-sidebar": "サイドバーを切り替え"
|
||||
"toggle-sidebar": "サイドバーを切り替え",
|
||||
"dropping-not-allowed": "この場所にノートをドロップすることはできません。"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "一括操作",
|
||||
@@ -1261,7 +1269,8 @@
|
||||
"reset_launcher_confirm": "本当に「{{title}}」をリセットしますか? このノート(およびその子ノート)のすべてのデータと設定が失われ、ランチャーは元の場所に戻ります。"
|
||||
},
|
||||
"editable-text": {
|
||||
"auto-detect-language": "自動検出"
|
||||
"auto-detect-language": "自動検出",
|
||||
"keeps-crashing": "編集コンポーネントがクラッシュし続けます。Trilium を再起動してください。問題が解決しない場合は、バグレポートの作成をご検討ください。"
|
||||
},
|
||||
"highlighting": {
|
||||
"title": "コードブロック",
|
||||
@@ -1299,7 +1308,8 @@
|
||||
"copy-link": "リンクをコピー",
|
||||
"paste": "貼り付け",
|
||||
"paste-as-plain-text": "プレーンテキストで貼り付け",
|
||||
"search_online": "{{searchEngine}} で \"{{term}}\" を検索"
|
||||
"search_online": "{{searchEngine}} で \"{{term}}\" を検索",
|
||||
"search_in_trilium": "Triliumで「{{term}}」を検索"
|
||||
},
|
||||
"duration": {
|
||||
"seconds": "秒",
|
||||
@@ -1498,9 +1508,7 @@
|
||||
"indexing_stopped": "インデックス登録を停止しました",
|
||||
"indexing_in_progress": "インデックス登録中です...",
|
||||
"last_indexed": "最終インデックス作成日時",
|
||||
"n_notes_queued_0": "{{ count }} 件のノートがインデックス作成待ちです",
|
||||
"note_chat": "ノートチャット",
|
||||
"notes_indexed_0": "{{ count }} 件のノートをインデックスしました",
|
||||
"sources": "ソース",
|
||||
"start_indexing": "インデックス作成を開始",
|
||||
"use_advanced_context": "高度なコンテキストを使用",
|
||||
@@ -1581,9 +1589,8 @@
|
||||
"this_launcher_doesnt_define_target_note": "このランチャーはターゲットノートを定義していません。"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} バックリンク",
|
||||
"backlinks": "{{count}} バックリンク",
|
||||
"relation": "リレーション"
|
||||
"relation": "リレーション",
|
||||
"backlink_other": "{{count}} 個のバックリンク"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"delete_this_note": "このノートを削除",
|
||||
@@ -1825,7 +1832,10 @@
|
||||
"app-restart-required": "(変更を有効にするにはアプリケーションの再起動が必要です)"
|
||||
},
|
||||
"code_mime_types": {
|
||||
"title": "ドロップダウンで利用可能なMIMEタイプ"
|
||||
"title": "ドロップダウンで利用可能なMIMEタイプ",
|
||||
"tooltip_syntax_highlighting": "構文ハイライト表示",
|
||||
"tooltip_code_block_syntax": "テキストノート内のコードブロック",
|
||||
"tooltip_code_note_syntax": "コードノート"
|
||||
},
|
||||
"attachment_erasure_timeout": {
|
||||
"attachment_erasure_timeout": "添付ファイル消去のタイムアウト",
|
||||
@@ -1928,7 +1938,7 @@
|
||||
"search-for": "「{{term}}」を検索",
|
||||
"create-note": "子ノート「{{term}}」を作成してリンクする",
|
||||
"insert-external-link": "「{{term}}」への外部リンクを挿入",
|
||||
"clear-text-field": "テキストフィールドを消去",
|
||||
"clear-text-field": "テキストフィールドをクリア",
|
||||
"show-recent-notes": "最近のノートを表示",
|
||||
"full-text-search": "全文検索"
|
||||
},
|
||||
@@ -2087,7 +2097,14 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "現在、読み取り専用のノートを表示しています。",
|
||||
"auto-read-only-note": "このノートは読み込みを高速化するために読み取り専用モードで表示されています。",
|
||||
"auto-read-only-learn-more": "さらに詳しく",
|
||||
"edit-note": "ノートを編集"
|
||||
},
|
||||
"note-color": {
|
||||
"clear-color": "ノートの色をクリア",
|
||||
"set-color": "ノートの色を設定",
|
||||
"set-custom-color": "ノートの色をカスタム設定"
|
||||
},
|
||||
"popup-editor": {
|
||||
"maximize": "フルエディターに切り替え"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@
|
||||
"edit_branch_prefix": "브랜치 접두사 편집",
|
||||
"help_on_tree_prefix": "트리 접두사에 대한 도움말",
|
||||
"prefix": "접두사: ",
|
||||
"branch_prefix_saved": "브랜치 접두사가 저장되었습니다."
|
||||
"branch_prefix_saved": "브랜치 접두사가 저장되었습니다.",
|
||||
"edit_branch_prefix_multiple": "{{count}}개의 지점 접두사 편집",
|
||||
"branch_prefix_saved_multiple": "{{count}}개의 지점에 대해 지점 접두사가 저장되었습니다."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "대량 작업",
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
},
|
||||
"widget-error": {
|
||||
"title": "Starten widget mislukt",
|
||||
"message-unknown": "Onbekende widget kan niet gestart worden omdat:\n\n{{message}}"
|
||||
"message-unknown": "Onbekende widget kan niet gestart worden omdat:\n\n{{message}}",
|
||||
"message-custom": "Aangepaste widget van notitie met ID \"{{id}}\", getiteld \"{{title}}\" kon niet worden geïnitialiseerd vanwege:\n\n{{message}}"
|
||||
},
|
||||
"bundle-error": {
|
||||
"title": "Custom script laden mislukt"
|
||||
"title": "Custom script laden mislukt",
|
||||
"message": "Script van notitie met ID \"{{id}}\", getiteld \"{{title}}\" kon niet worden uitgevoerd vanwege:\n\n{{message}}"
|
||||
}
|
||||
},
|
||||
"add_link": {
|
||||
@@ -29,14 +31,17 @@
|
||||
"search_note": "zoek voor notitie op naam",
|
||||
"link_title_mirrors": "De link titel is hetzelfde als de notitie's huidige titel",
|
||||
"link_title": "Link titel",
|
||||
"button_add_link": "Link toevoegen"
|
||||
"button_add_link": "Link toevoegen",
|
||||
"link_title_arbitrary": "snelkoppelingsnaam kan willekeurig worden aangepast"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"edit_branch_prefix": "Bewerk branch prefix",
|
||||
"save": "Opslaan",
|
||||
"branch_prefix_saved": "Branch prefix is opgeslagen.",
|
||||
"help_on_tree_prefix": "Help bij boomvoorvoegsel",
|
||||
"prefix": "Voorvoegsel: "
|
||||
"prefix": "Voorvoegsel: ",
|
||||
"edit_branch_prefix_multiple": "Bewerk zijtakvoorvoegsel voor {{count}} zijtakken",
|
||||
"branch_prefix_saved_multiple": "Vertakkingsvoorvoegsel opgeslagen voor {{count}} vertakkingen."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Bulk acties",
|
||||
|
||||
@@ -165,7 +165,6 @@
|
||||
"view_type": "Typ widoku",
|
||||
"grid": "Siatka",
|
||||
"collapse_all_notes": "Zwiń wszystkie notatki",
|
||||
"expand_all_children": "Rozwiń wszystkie dzieci",
|
||||
"collapse": "Zwiń",
|
||||
"expand": "Rozwiń",
|
||||
"book_properties": "Właściwości kolekcji",
|
||||
@@ -448,7 +447,8 @@
|
||||
"search": "Szukaj"
|
||||
},
|
||||
"note_properties": {
|
||||
"this_note_was_originally_taken_from": "Ta notatka oryginalnie została wzięta z:"
|
||||
"this_note_was_originally_taken_from": "Ta notatka oryginalnie została wzięta z:",
|
||||
"info": "Info"
|
||||
},
|
||||
"owned_attribute_list": {
|
||||
"owned_attributes": "Posiadane atrybuty"
|
||||
@@ -750,9 +750,6 @@
|
||||
"indexing_stopped": "Indeksowanie zatrzymane",
|
||||
"indexing_in_progress": "Indeksowanie w trakcie...",
|
||||
"last_indexed": "Ostatnio zindeksowane",
|
||||
"n_notes_queued_0": "{{ count }} notatka zakolejkowana do indeksowania",
|
||||
"n_notes_queued_1": "{{ count }} notatek zakolejkowanych do indeksowania",
|
||||
"n_notes_queued_2": "{{ count }} notatek zakolejkowanych do indeksowania",
|
||||
"note_chat": "Czat notatki",
|
||||
"note_title": "Tytuł notatki",
|
||||
"error": "Błąd",
|
||||
@@ -860,9 +857,6 @@
|
||||
"enter_message": "Wpisz swoją wiadomość...",
|
||||
"error_contacting_provider": "Błąd kontaktu z dostawcą AI. Sprawdź ustawienia i połączenie internetowe.",
|
||||
"error_generating_response": "Błąd generowania odpowiedzi AI",
|
||||
"notes_indexed_0": "{{ count }} notatka zaindeksowana",
|
||||
"notes_indexed_1": "{{ count }} notatek zaindeksowanych",
|
||||
"notes_indexed_2": "",
|
||||
"sources": "Źródła",
|
||||
"start_indexing": "Rozpocznij indeksowanie",
|
||||
"use_advanced_context": "Użyj zaawansowanego kontekstu",
|
||||
@@ -1237,9 +1231,10 @@
|
||||
"zoom_out_title": "Pomniejsz"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} Backlink",
|
||||
"backlinks": "{{count}} Backlinków",
|
||||
"relation": "relacja"
|
||||
"relation": "relacja",
|
||||
"backlink_one": "{{count}} Backlink",
|
||||
"backlink_few": "",
|
||||
"backlink_many": "{{count}} Backlinków"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"insert_child_note": "Wstaw notatkę podrzędną",
|
||||
|
||||
@@ -711,9 +711,10 @@
|
||||
"zoom_out_title": "Reduzir"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} Ligação Reversa",
|
||||
"backlinks": "{{count}} Ligações Reversas",
|
||||
"relation": "relação"
|
||||
"relation": "relação",
|
||||
"backlink_one": "{{count}} Ligação Reversa",
|
||||
"backlink_many": "",
|
||||
"backlink_other": "{{count}} Ligações Reversas"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"insert_child_note": "Inserir nota filha",
|
||||
@@ -739,7 +740,6 @@
|
||||
"grid": "Grade",
|
||||
"list": "Lista",
|
||||
"collapse_all_notes": "Recolher todas as notas",
|
||||
"expand_all_children": "Expandir todos os filhos",
|
||||
"collapse": "Recolher",
|
||||
"expand": "Expandir",
|
||||
"book_properties": "Propriedades da Coleção",
|
||||
@@ -810,7 +810,8 @@
|
||||
"search": "Pesquisar"
|
||||
},
|
||||
"note_properties": {
|
||||
"this_note_was_originally_taken_from": "Esta nota foi originalmente obtida de:"
|
||||
"this_note_was_originally_taken_from": "Esta nota foi originalmente obtida de:",
|
||||
"info": "Informações"
|
||||
},
|
||||
"owned_attribute_list": {
|
||||
"owned_attributes": "Atributos próprios"
|
||||
@@ -1234,13 +1235,7 @@
|
||||
"indexing_stopped": "Indexação interrompida",
|
||||
"indexing_in_progress": "Indexação em andamento…",
|
||||
"last_indexed": "Última Indexada",
|
||||
"n_notes_queued_0": "{{ count }} nota enfileirada para indexação",
|
||||
"n_notes_queued_1": "{{ count }} notas enfileiradas para indexação",
|
||||
"n_notes_queued_2": "{{ count }} notas enfileiradas para indexação",
|
||||
"note_chat": "Conversa de Nota",
|
||||
"notes_indexed_0": "{{ count }} nota indexada",
|
||||
"notes_indexed_1": "{{ count }} notas indexadas",
|
||||
"notes_indexed_2": "{{ count }} notas indexadas",
|
||||
"sources": "Origens",
|
||||
"start_indexing": "Iniciar Indexação",
|
||||
"use_advanced_context": "Usar Contexto Avançado",
|
||||
|
||||
@@ -75,12 +75,6 @@
|
||||
"note_cloned": "A nota \"{{clonedTitle}}\" foi clonada para \"{{targetTitle}}\""
|
||||
},
|
||||
"ai_llm": {
|
||||
"n_notes_queued_0": "{{ count }} nota enfileirada para indexação",
|
||||
"n_notes_queued_1": "{{ count }} notas enfileiradas para indexação",
|
||||
"n_notes_queued_2": "{{ count }} notas enfileiradas para indexação",
|
||||
"notes_indexed_0": "{{ count }} nota indexada",
|
||||
"notes_indexed_1": "{{ count }} notas indexadas",
|
||||
"notes_indexed_2": "{{ count }} notas indexadas",
|
||||
"temperature": "Temperatura",
|
||||
"retry_queued": "Nota enfileirada para nova tentativa",
|
||||
"queued_notes": "Notas Enfileiradas",
|
||||
@@ -976,9 +970,10 @@
|
||||
"reset_pan_zoom_title": "Redefinir pan & zoom para coordenadas e ampliação iniciais"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} Links Reversos",
|
||||
"backlinks": "{{count}} Links Reversos",
|
||||
"relation": "relação"
|
||||
"relation": "relação",
|
||||
"backlink_one": "",
|
||||
"backlink_many": "",
|
||||
"backlink_other": "{{count}} Links Reversos"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"insert_child_note": "Inserir nota filha",
|
||||
@@ -1004,7 +999,6 @@
|
||||
"grid": "Grade",
|
||||
"list": "Lista",
|
||||
"collapse_all_notes": "Recolher todas as notas",
|
||||
"expand_all_children": "Expandir todos os filhos",
|
||||
"collapse": "Recolher",
|
||||
"expand": "Expandir",
|
||||
"book_properties": "Propriedades da Coleção",
|
||||
@@ -1076,7 +1070,8 @@
|
||||
"outside_hoisted": "Este caminho está fora de uma nota fixada e você teria que desafixar."
|
||||
},
|
||||
"note_properties": {
|
||||
"this_note_was_originally_taken_from": "Esta nota foi originalmente obtida de:"
|
||||
"this_note_was_originally_taken_from": "Esta nota foi originalmente obtida de:",
|
||||
"info": "Informações"
|
||||
},
|
||||
"promoted_attributes": {
|
||||
"promoted_attributes": "Atributos Promovidos",
|
||||
|
||||
@@ -279,7 +279,6 @@
|
||||
"collapse": "Minimizează",
|
||||
"collapse_all_notes": "Minimizează toate notițele",
|
||||
"expand": "Expandează",
|
||||
"expand_all_children": "Expandează toate subnotițele",
|
||||
"grid": "Grilă",
|
||||
"invalid_view_type": "Mod de afișare incorect „{{type}}”",
|
||||
"list": "Listă",
|
||||
@@ -290,7 +289,11 @@
|
||||
"geo-map": "Hartă geografică",
|
||||
"board": "Tablă Kanban",
|
||||
"include_archived_notes": "Afișează notițele arhivate",
|
||||
"presentation": "Prezentare"
|
||||
"presentation": "Prezentare",
|
||||
"expand_tooltip": "Expandează subnotițele directe ale acestei colecții (un singur nivel de adâncime). Pentru mai multe opțiuni, apăsați săgeata din dreapta.",
|
||||
"expand_first_level": "Expandează subnotițele directe",
|
||||
"expand_nth_level": "Expandează pe {{depth}} nivele",
|
||||
"expand_all_levels": "Expandează pe toate nivelele"
|
||||
},
|
||||
"bookmark_switch": {
|
||||
"bookmark": "Semn de carte",
|
||||
@@ -302,7 +305,10 @@
|
||||
"edit_branch_prefix": "Editează prefixul ramurii",
|
||||
"help_on_tree_prefix": "Informații despre prefixe de ierarhie",
|
||||
"prefix": "Prefix: ",
|
||||
"save": "Salvează"
|
||||
"save": "Salvează",
|
||||
"edit_branch_prefix_multiple": "Editează prefixul pentru {{count}} ramuri",
|
||||
"branch_prefix_saved_multiple": "Prefixul a fost modificat pentru {{count}} ramuri.",
|
||||
"affected_branches": "Ramuri afectate ({{count}}):"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"affected_notes": "Notițe afectate",
|
||||
@@ -381,7 +387,10 @@
|
||||
"trilium_api_docs_button_title": "Deschide documentația API pentru Trilium"
|
||||
},
|
||||
"code_mime_types": {
|
||||
"title": "Tipuri MIME disponibile în meniul derulant"
|
||||
"title": "Tipuri MIME disponibile în meniul derulant",
|
||||
"tooltip_syntax_highlighting": "Evidențiere de sintaxă",
|
||||
"tooltip_code_block_syntax": "Blocuri de cod în notițe text",
|
||||
"tooltip_code_note_syntax": "Notițe de tip cod"
|
||||
},
|
||||
"confirm": {
|
||||
"also_delete_note": "Șterge și notița",
|
||||
@@ -537,7 +546,8 @@
|
||||
"opml_version_1": "OPML v1.0 - text simplu",
|
||||
"opml_version_2": "OPML v2.0 - permite și HTML",
|
||||
"format_html": "HTML - recomandat deoarece păstrează toata formatarea",
|
||||
"format_pdf": "PDF - cu scopul de printare sau partajare."
|
||||
"format_pdf": "PDF - cu scopul de printare sau partajare.",
|
||||
"share-format": "HTML pentru publicare web - folosește aceeași temă pentru notițele partajate, dar se pot publica într-un website static."
|
||||
},
|
||||
"fast_search": {
|
||||
"description": "Căutarea rapidă dezactivează căutarea la nivel de conținut al notițelor cu scopul de a îmbunătăți performanța de căutare pentru baze de date mari.",
|
||||
@@ -670,7 +680,8 @@
|
||||
"tabShortcuts": "Scurtături pentru tab-uri",
|
||||
"troubleshooting": "Unelte pentru depanare",
|
||||
"newTabWithActivationNoteLink": "pe o legătură către o notiță deschide și activează notița într-un tab nou",
|
||||
"title": "Ghid rapid"
|
||||
"title": "Ghid rapid",
|
||||
"editShortcuts": "Editează scurtăturile de la tastatură"
|
||||
},
|
||||
"hide_floating_buttons_button": {
|
||||
"button_title": "Ascunde butoanele"
|
||||
@@ -753,7 +764,8 @@
|
||||
"placeholder": "Introduceți etichetele HTML, câte unul pe linie",
|
||||
"reset_button": "Resetează la lista implicită",
|
||||
"title": "Etichete HTML la importare"
|
||||
}
|
||||
},
|
||||
"importZipRecommendation": "Când importați un fișier ZIP, ierarhia notițelor va reflecta structura subdirectoarelor din arhivă."
|
||||
},
|
||||
"include_archived_notes": {
|
||||
"include_archived_notes": "Include notițele arhivate"
|
||||
@@ -799,7 +811,8 @@
|
||||
"default_description": "În mod implicit Trilium limitează lățimea conținutului pentru a îmbunătăți lizibilitatea pentru ferestrele maximizate pe ecrane late.",
|
||||
"max_width_label": "Lungimea maximă a conținutului",
|
||||
"max_width_unit": "pixeli",
|
||||
"title": "Lățime conținut"
|
||||
"title": "Lățime conținut",
|
||||
"centerContent": "Centrează conținutul"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"delete_this_note": "Șterge această notiță",
|
||||
@@ -856,7 +869,8 @@
|
||||
"convert_into_attachment_failed": "Nu s-a putut converti notița „{{title}}”.",
|
||||
"convert_into_attachment_successful": "Notița „{{title}}” a fost convertită în atașament.",
|
||||
"convert_into_attachment_prompt": "Doriți convertirea notiței „{{title}}” într-un atașament al notiței părinte?",
|
||||
"print_pdf": "Exportare ca PDF..."
|
||||
"print_pdf": "Exportare ca PDF...",
|
||||
"open_note_on_server": "Deschide notița pe server"
|
||||
},
|
||||
"note_erasure_timeout": {
|
||||
"deleted_notes_erased": "Notițele șterse au fost eliminate permanent.",
|
||||
@@ -897,6 +911,7 @@
|
||||
"title": "Căile notiței"
|
||||
},
|
||||
"note_properties": {
|
||||
"info": "Informații",
|
||||
"this_note_was_originally_taken_from": "Această notiță a fost preluată original de la:"
|
||||
},
|
||||
"note_type_chooser": {
|
||||
@@ -1245,11 +1260,11 @@
|
||||
"timeout_unit": "milisecunde"
|
||||
},
|
||||
"table_of_contents": {
|
||||
"description": "Tabela de conținut va apărea în notițele de tip text atunci când notița are un număr de titluri mai mare decât cel definit. Acest număr se poate personaliza:",
|
||||
"description": "Cuprinsul va apărea în notițele de tip text atunci când notița are un număr de titluri mai mare decât cel definit. Acest număr se poate personaliza:",
|
||||
"unit": "titluri",
|
||||
"disable_info": "De asemenea se poate dezactiva tabela de conținut setând o valoare foarte mare.",
|
||||
"shortcut_info": "Se poate configura și o scurtatură pentru a comuta rapid vizibilitatea panoului din dreapta (inclusiv tabela de conținut) în Opțiuni -> Scurtături (denumirea „toggleRightPane”).",
|
||||
"title": "Tabelă de conținut"
|
||||
"disable_info": "De asemenea se poate dezactiva cuprinsul setând o valoare foarte mare.",
|
||||
"shortcut_info": "Se poate configura și o scurtatură pentru a comuta rapid vizibilitatea panoului din dreapta (inclusiv cuprinsul) în Opțiuni -> Scurtături (denumirea „toggleRightPane”).",
|
||||
"title": "Cuprins"
|
||||
},
|
||||
"text_auto_read_only_size": {
|
||||
"description": "Marchează pragul în care o notiță de o anumită dimensiune va fi afișată în mod de citire (pentru motive de performanță).",
|
||||
@@ -1348,8 +1363,9 @@
|
||||
"title": "Factorul de zoom (doar pentru versiunea desktop)"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} legături de retur",
|
||||
"backlinks": "{{count}} legături de retur",
|
||||
"backlink_one": "{{count}} legătură de retur",
|
||||
"backlink_few": "{{count}} legături de retur",
|
||||
"backlink_other": "{{count}} de legături de retur",
|
||||
"relation": "relație"
|
||||
},
|
||||
"svg_export_button": {
|
||||
@@ -1496,13 +1512,16 @@
|
||||
"hoist-this-note-workspace": "Focalizează spațiul de lucru",
|
||||
"refresh-saved-search-results": "Reîmprospătează căutarea salvată",
|
||||
"unhoist": "Defocalizează notița",
|
||||
"toggle-sidebar": "Comută bara laterală"
|
||||
"toggle-sidebar": "Comută bara laterală",
|
||||
"dropping-not-allowed": "Aici nu este permisă plasarea notițelor."
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "Menține fereastra mereu vizibilă"
|
||||
},
|
||||
"note_detail": {
|
||||
"could_not_find_typewidget": "Nu s-a putut găsi widget-ul corespunzător tipului „{{type}}”"
|
||||
"could_not_find_typewidget": "Nu s-a putut găsi widget-ul corespunzător tipului „{{type}}”",
|
||||
"printing": "Imprimare în curs...",
|
||||
"printing_pdf": "Exportare ca PDF în curs..."
|
||||
},
|
||||
"note_title": {
|
||||
"placeholder": "introduceți titlul notiței aici..."
|
||||
@@ -1608,7 +1627,8 @@
|
||||
"reset": "Resetează"
|
||||
},
|
||||
"editable-text": {
|
||||
"auto-detect-language": "Automat"
|
||||
"auto-detect-language": "Automat",
|
||||
"keeps-crashing": "Componenta de editare se blochează în continuu. Încercați să reporniți Trilium. Dacă problema persistă, luați în considerare să raportați această problemă."
|
||||
},
|
||||
"highlighting": {
|
||||
"color-scheme": "Temă de culori",
|
||||
@@ -1649,7 +1669,8 @@
|
||||
"cut": "Decupează",
|
||||
"paste": "Lipește",
|
||||
"paste-as-plain-text": "Lipește doar textul",
|
||||
"search_online": "Caută „{{term}}” cu {{searchEngine}}"
|
||||
"search_online": "Caută „{{term}}” cu {{searchEngine}}",
|
||||
"search_in_trilium": "Caută „{{term}}” în Trilium"
|
||||
},
|
||||
"image_context_menu": {
|
||||
"copy_image_to_clipboard": "Copiază imaginea în clipboard",
|
||||
@@ -1659,7 +1680,8 @@
|
||||
"open_note_in_new_split": "Deschide notița într-un panou nou",
|
||||
"open_note_in_new_tab": "Deschide notița într-un tab nou",
|
||||
"open_note_in_new_window": "Deschide notița într-o fereastră nouă",
|
||||
"open_note_in_popup": "Editare rapidă"
|
||||
"open_note_in_popup": "Editare rapidă",
|
||||
"open_note_in_other_split": "Deschide notița în celălalt panou"
|
||||
},
|
||||
"note_autocomplete": {
|
||||
"clear-text-field": "Șterge conținutul casetei",
|
||||
@@ -1870,13 +1892,7 @@
|
||||
"indexing_stopped": "Indexarea s-a oprit",
|
||||
"indexing_in_progress": "Indexare în curs...",
|
||||
"last_indexed": "Ultima indexare",
|
||||
"n_notes_queued_0": "O notiță adăugată în coada de indexare",
|
||||
"n_notes_queued_1": "{{ count }} notițe adăugate în coada de indexare",
|
||||
"n_notes_queued_2": "{{ count }} de notițe adăugate în coada de indexare",
|
||||
"note_chat": "Discuție pe baza notițelor",
|
||||
"notes_indexed_0": "O notiță indexată",
|
||||
"notes_indexed_1": "{{ count }} notițe indexate",
|
||||
"notes_indexed_2": "{{ count }} de notițe indexate",
|
||||
"sources": "Surse",
|
||||
"start_indexing": "Indexează",
|
||||
"use_advanced_context": "Folosește context îmbogățit",
|
||||
@@ -2013,7 +2029,8 @@
|
||||
"new-item-placeholder": "Introduceți titlul notiței...",
|
||||
"add-column-placeholder": "Introduceți denumirea coloanei...",
|
||||
"edit-note-title": "Clic pentru a edita titlul notiței",
|
||||
"edit-column-title": "Clic pentru a edita titlul coloanei"
|
||||
"edit-column-title": "Clic pentru a edita titlul coloanei",
|
||||
"column-already-exists": "Această coloană deja există."
|
||||
},
|
||||
"command_palette": {
|
||||
"tree-action-name": "Listă de notițe: {{name}}",
|
||||
@@ -2075,5 +2092,21 @@
|
||||
"edit-slide": "Editați acest slide",
|
||||
"start-presentation": "Începeți prezentarea",
|
||||
"slide-overview": "Afișați o imagine de ansamblu a slide-urilor"
|
||||
},
|
||||
"read-only-info": {
|
||||
"read-only-note": "Vizualizați o notiță în modul doar în citire.",
|
||||
"auto-read-only-note": "Această notiță este afișată în modul doar în citire din motive de performanță.",
|
||||
"edit-note": "Editează notița"
|
||||
},
|
||||
"calendar_view": {
|
||||
"delete_note": "Șterge notița..."
|
||||
},
|
||||
"note-color": {
|
||||
"clear-color": "Înlăturați culoarea notiței",
|
||||
"set-color": "Setați culoarea notiței",
|
||||
"set-custom-color": "Setați culoare personalizată pentru notiță"
|
||||
},
|
||||
"popup-editor": {
|
||||
"maximize": "Comută la editorul principal"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -984,9 +984,10 @@
|
||||
"new-version-available": "Доступно обновление"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} ссылки",
|
||||
"backlinks": "{{count}} ссылок",
|
||||
"relation": "отношение"
|
||||
"relation": "отношение",
|
||||
"backlink_one": "{{count}} ссылки",
|
||||
"backlink_few": "",
|
||||
"backlink_many": "{{count}} ссылок"
|
||||
},
|
||||
"note_icon": {
|
||||
"category": "Категория:",
|
||||
@@ -1013,7 +1014,6 @@
|
||||
"book_properties": "Свойства коллекции",
|
||||
"geo-map": "Карта",
|
||||
"invalid_view_type": "Недопустимый тип представления '{{type}}'",
|
||||
"expand_all_children": "Развернуть все дочерние элементы",
|
||||
"collapse_all_notes": "Свернуть все заметки",
|
||||
"include_archived_notes": "Показать заархивированные заметки"
|
||||
},
|
||||
@@ -1067,6 +1067,7 @@
|
||||
"archived": "Архивировано"
|
||||
},
|
||||
"note_properties": {
|
||||
"info": "Информация",
|
||||
"this_note_was_originally_taken_from": "Эта заметка была первоначально взята из:"
|
||||
},
|
||||
"promoted_attributes": {
|
||||
@@ -1334,16 +1335,10 @@
|
||||
"error_fetching": "Ошибка получения списка моделей: {{error}}",
|
||||
"index_rebuild_status_error": "Ошибка проверки статуса перестроения индекса",
|
||||
"enhanced_context_description": "Предоставляет ИИ больше контекста из заметки и связанных с ней заметок для более точных ответов",
|
||||
"n_notes_queued_0": "{{ count }} заметка в очереди на индексирование",
|
||||
"n_notes_queued_1": "{{ count }} заметки в очереди на индексирование",
|
||||
"n_notes_queued_2": "{{ count }} заметок в очереди на индексирование",
|
||||
"no_models_found_ollama": "Модели Ollama не найдены. Проверьте, запущена ли Ollama.",
|
||||
"no_models_found_online": "Модели не найдены. Проверьте ваш ключ API и настройки.",
|
||||
"experimental_warning": "Функция LLM в настоящее время является экспериментальной — вы предупреждены.",
|
||||
"ollama_no_url": "Ollama не настроена. Введите корректный URL-адрес.",
|
||||
"notes_indexed_0": "{{ count }} заметка проиндексирована",
|
||||
"notes_indexed_1": "{{ count }} заметки проиндексировано",
|
||||
"notes_indexed_2": "{{ count }} заметок проиндексировано",
|
||||
"show_thinking_description": "Показать цепочку мыслительного процесса ИИ",
|
||||
"api_key_tooltip": "API-ключ для доступа к сервису",
|
||||
"all_notes_queued_for_retry": "Все неудачные заметки поставлены в очередь на повторную попытку",
|
||||
|
||||
@@ -1,496 +1,488 @@
|
||||
{
|
||||
"about": {
|
||||
"title": "O Trilium Belеškama",
|
||||
"homepage": "Početna stranica:",
|
||||
"app_version": "Verzija aplikacije:",
|
||||
"db_version": "Verzija baze podataka:",
|
||||
"sync_version": "Verzija sinhronizacije:",
|
||||
"build_date": "Datum izgradnje:",
|
||||
"build_revision": "Revizija izgradnje:",
|
||||
"data_directory": "Direktorijum sa podacima:"
|
||||
"about": {
|
||||
"title": "O Trilium Belеškama",
|
||||
"homepage": "Početna stranica:",
|
||||
"app_version": "Verzija aplikacije:",
|
||||
"db_version": "Verzija baze podataka:",
|
||||
"sync_version": "Verzija sinhronizacije:",
|
||||
"build_date": "Datum izgradnje:",
|
||||
"build_revision": "Revizija izgradnje:",
|
||||
"data_directory": "Direktorijum sa podacima:"
|
||||
},
|
||||
"toast": {
|
||||
"critical-error": {
|
||||
"title": "Kritična greška",
|
||||
"message": "Došlo je do kritične greške koja sprečava pokretanje klijentske aplikacije.\n\n{{message}}\n\nOva greška je najverovatnije izazvana neočekivanim problemom prilikom izvršavanja skripte. Pokušajte da pokrenete aplikaciju u bezbednom režimu i da pronađete šta izaziva grešku."
|
||||
},
|
||||
"toast": {
|
||||
"critical-error": {
|
||||
"title": "Kritična greška",
|
||||
"message": "Došlo je do kritične greške koja sprečava pokretanje klijentske aplikacije.\n\n{{message}}\n\nOva greška je najverovatnije izazvana neočekivanim problemom prilikom izvršavanja skripte. Pokušajte da pokrenete aplikaciju u bezbednom režimu i da pronađete šta izaziva grešku."
|
||||
},
|
||||
"widget-error": {
|
||||
"title": "Pokretanje vidžeta nije uspelo",
|
||||
"message-custom": "Prilagođeni viđet sa beleške sa ID-jem \"{{id}}\", nazivom \"{{title}}\" nije uspeo da se pokrene zbog:\n\n{{message}}",
|
||||
"message-unknown": "Nepoznati vidžet nije mogao da se pokrene zbog:\n\n{{message}}"
|
||||
},
|
||||
"bundle-error": {
|
||||
"title": "Pokretanje prilagođene skripte neuspešno",
|
||||
"message": "Skripta iz beleške sa ID-jem \"{{id}}\", naslovom \"{{title}}\" nije mogla da se izvrši zbog:\n\n{{message}}"
|
||||
}
|
||||
"widget-error": {
|
||||
"title": "Pokretanje vidžeta nije uspelo",
|
||||
"message-custom": "Prilagođeni viđet sa beleške sa ID-jem \"{{id}}\", nazivom \"{{title}}\" nije uspeo da se pokrene zbog:\n\n{{message}}",
|
||||
"message-unknown": "Nepoznati vidžet nije mogao da se pokrene zbog:\n\n{{message}}"
|
||||
},
|
||||
"add_link": {
|
||||
"add_link": "Dodaj link",
|
||||
"help_on_links": "Pomoć na linkovima",
|
||||
"note": "Beleška",
|
||||
"search_note": "potražite belešku po njenom imenu",
|
||||
"link_title_mirrors": "naziv linka preslikava trenutan naziv beleške",
|
||||
"link_title_arbitrary": "naziv linka se može proizvoljno menjati",
|
||||
"link_title": "Naziv linka",
|
||||
"button_add_link": "Dodaj link <kbd>enter</kbd>"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"edit_branch_prefix": "Izmeni prefiks grane",
|
||||
"help_on_tree_prefix": "Pomoć na prefiksu Drveta",
|
||||
"prefix": "Prefiks: ",
|
||||
"save": "Sačuvaj",
|
||||
"branch_prefix_saved": "Prefiks grane je sačuvan."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Grupne akcije",
|
||||
"affected_notes": "Pogođene beleške",
|
||||
"include_descendants": "Obuhvati potomke izabranih beleški",
|
||||
"available_actions": "Dostupne akcije",
|
||||
"chosen_actions": "Izabrane akcije",
|
||||
"execute_bulk_actions": "Izvrši grupne akcije",
|
||||
"bulk_actions_executed": "Grupne akcije su uspešno izvršene.",
|
||||
"none_yet": "Nijedna za sad... dodajte akciju tako što ćete pritisnuti na neku od dostupnih akcija iznad.",
|
||||
"labels": "Oznake",
|
||||
"relations": "Odnosi",
|
||||
"notes": "Beleške",
|
||||
"other": "Ostalo"
|
||||
},
|
||||
"clone_to": {
|
||||
"clone_notes_to": "Klonirajte beleške u...",
|
||||
"help_on_links": "Pomoć na linkovima",
|
||||
"notes_to_clone": "Beleške za kloniranje",
|
||||
"target_parent_note": "Ciljna nadređena beleška",
|
||||
"search_for_note_by_its_name": "potražite belešku po njenom imenu",
|
||||
"cloned_note_prefix_title": "Klonirana beleška će biti prikazana u drvetu beleški sa datim prefiksom",
|
||||
"prefix_optional": "Prefiks (opciono)",
|
||||
"clone_to_selected_note": "Kloniranje u izabranu belešku <kbd>enter</kbd>",
|
||||
"no_path_to_clone_to": "Nema putanje za kloniranje.",
|
||||
"note_cloned": "Beleška \"{{clonedTitle}}\" je klonirana u \"{{targetTitle}}\""
|
||||
},
|
||||
"confirm": {
|
||||
"confirmation": "Potvrda",
|
||||
"cancel": "Otkaži",
|
||||
"ok": "U redu",
|
||||
"are_you_sure_remove_note": "Da li ste sigurni da želite da uklonite belešku \"{{title}}\" iz mape odnosa? ",
|
||||
"if_you_dont_check": "Ako ne izaberete ovo, beleška će biti uklonjena samo sa mape odnosa.",
|
||||
"also_delete_note": "Takođe obriši belešku"
|
||||
},
|
||||
"delete_notes": {
|
||||
"delete_notes_preview": "Obriši pregled beleške",
|
||||
"close": "Zatvori",
|
||||
"delete_all_clones_description": "Obriši i sve klonove (može biti poništeno u skorašnjim izmenama)",
|
||||
"erase_notes_description": "Normalno (blago) brisanje samo označava beleške kao obrisane i one mogu biti vraćene (u dijalogu skorašnjih izmena) u određenom vremenskom periodu. Biranje ove opcije će momentalno obrisati beleške i ove beleške neće biti moguće vratiti.",
|
||||
"erase_notes_warning": "Trajno obriši beleške (ne može se opozvati), uključujući sve klonove. Ovo će prisiliti aplikaciju da se ponovo pokrene.",
|
||||
"notes_to_be_deleted": "Sledeće beleške će biti obrisane ({{- noteCount}})",
|
||||
"no_note_to_delete": "Nijedna beleška neće biti obrisana (samo klonovi).",
|
||||
"broken_relations_to_be_deleted": "Sledeći odnosi će biti prekinuti i obrisani ({{- relationCount}})",
|
||||
"cancel": "Otkaži",
|
||||
"ok": "U redu",
|
||||
"deleted_relation_text": "Beleška {{- note}} (za brisanje) je referencirana sa odnosom {{- relation}} koji potiče iz {{- source}}."
|
||||
},
|
||||
"export": {
|
||||
"export_note_title": "Izvezi belešku",
|
||||
"close": "Zatvori",
|
||||
"export_type_subtree": "Ova beleška i svi njeni potomci",
|
||||
"format_html": "HTML - preporučuje se jer čuva formatiranje",
|
||||
"format_html_zip": "HTML u ZIP arhivi - ovo se preporučuje jer se na taj način čuva celokupno formatiranje.",
|
||||
"format_markdown": "Markdown - ovo čuva većinu formatiranja.",
|
||||
"format_opml": "OPML - format za razmenu okvira samo za tekst. Formatiranje, slike i datoteke nisu uključeni.",
|
||||
"opml_version_1": "OPML v1.0 - samo običan tekst",
|
||||
"opml_version_2": "OPML v2.0 - dozvoljava i HTML",
|
||||
"export_type_single": "Samo ovu belešku bez njenih potomaka",
|
||||
"export": "Izvoz",
|
||||
"choose_export_type": "Molimo vas da prvo izaberete tip izvoza",
|
||||
"export_status": "Status izvoza",
|
||||
"export_in_progress": "Izvoz u toku: {{progressCount}}",
|
||||
"export_finished_successfully": "Izvoz je uspešno završen.",
|
||||
"format_pdf": "PDF - za namene štampanja ili deljenja."
|
||||
},
|
||||
"help": {
|
||||
"noteNavigation": "Navigacija beleški",
|
||||
"goUpDown": "<kbd>UP</kbd>, <kbd>DOWN</kbd> - kretanje gore/dole u listi sa beleškama",
|
||||
"collapseExpand": "<kbd>LEFT</kbd>, <kbd>RIGHT</kbd> - sakupi/proširi čvor",
|
||||
"notSet": "nije podešeno",
|
||||
"goBackForwards": "idi u nazad/napred kroz istoriju",
|
||||
"showJumpToNoteDialog": "prikaži <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"Idi na\" dijalog</a>",
|
||||
"scrollToActiveNote": "skroluj do aktivne beleške",
|
||||
"jumpToParentNote": "idi do nadređene beleške",
|
||||
"collapseWholeTree": "sakupi celo drvo beleški",
|
||||
"collapseSubTree": "sakupi pod-drvo",
|
||||
"tabShortcuts": "Prečice na karticama",
|
||||
"newTabNoteLink": "na link beleške otvara belešku u novoj kartici",
|
||||
"newTabWithActivationNoteLink": "na link beleške otvara i aktivira belešku u novoj kartici",
|
||||
"onlyInDesktop": "Samo na dektop-u (Electron verzija)",
|
||||
"openEmptyTab": "otvori praznu karticu",
|
||||
"closeActiveTab": "zatvori aktivnu karticu",
|
||||
"activateNextTab": "aktiviraj narednu karticu",
|
||||
"activatePreviousTab": "aktiviraj prethodnu karticu",
|
||||
"creatingNotes": "Pravljenje beleški",
|
||||
"createNoteAfter": "napravi novu belešku nakon aktivne beleške",
|
||||
"createNoteInto": "napravi novu pod-belešku u aktivnoj belešci",
|
||||
"editBranchPrefix": "izmeni <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/tree-concepts.html#prefix\">prefiks</a> klona aktivne beleške",
|
||||
"movingCloningNotes": "Premeštanje / kloniranje beleški",
|
||||
"moveNoteUpDown": "pomeri belešku gore/dole u listi beleški",
|
||||
"moveNoteUpHierarchy": "pomeri belešku na gore u hijerarhiji",
|
||||
"multiSelectNote": "višestruki izbor beleški iznad/ispod",
|
||||
"selectAllNotes": "izaberi sve beleške u trenutnom nivou",
|
||||
"selectNote": "izaberi belešku",
|
||||
"copyNotes": "kopiraj aktivnu belešku (ili trenutni izbor) u privremenu memoriju (koristi se za <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">kloniranje</a>)",
|
||||
"cutNotes": "iseci trenutnu belešku (ili trenutni izbor) u privremenu memoriju (koristi se za premeštanje beleški)",
|
||||
"pasteNotes": "nalepi belešku/e kao podbelešku u aktivnoj belešci (koja se ili premešta ili klonira u zavisnosti od toga da li je beleška kopirana ili isečena u privremenu memoriju)",
|
||||
"deleteNotes": "obriši belešku / podstablo",
|
||||
"editingNotes": "Izmena beleški",
|
||||
"editNoteTitle": "u ravni drveta će se prebaciti sa ravni drveta na naslov beleške. Ulaz sa naslova beleške će prebaciti fokus na uređivač teksta. <kbd>Ctrl+.</kbd> će se vratiti sa uređivača na ravan drveta.",
|
||||
"createEditLink": "napravi / izmeni spoljašnji link",
|
||||
"createInternalLink": "napravi unutrašnji link",
|
||||
"followLink": "prati link ispod kursora",
|
||||
"insertDateTime": "ubaci trenutan datum i vreme na poziciju kursora",
|
||||
"jumpToTreePane": "idi na ravan stabla i pomeri se do aktivne beleške",
|
||||
"markdownAutoformat": "Autoformatiranje kao u Markdown-u",
|
||||
"headings": "<code>##</code>, <code>###</code>, <code>####</code> itd. praćeno razmakom za naslove",
|
||||
"bulletList": "<code>*</code> ili <code>-</code> praćeno razmakom za listu sa tačkama",
|
||||
"numberedList": "<code>1.</code> ili <code>1)</code> praćeno razmakom za numerisanu listu",
|
||||
"blockQuote": "započnite liniju sa <code>></code> praćeno sa razmakom za blok citat",
|
||||
"troubleshooting": "Rešavanje problema",
|
||||
"reloadFrontend": "ponovo učitaj Trilium frontend",
|
||||
"showDevTools": "prikaži alate za programere",
|
||||
"showSQLConsole": "prikaži SQL konzolu",
|
||||
"other": "Ostalo",
|
||||
"quickSearch": "fokus na unos za brzu pretragu",
|
||||
"inPageSearch": "pretraga unutar stranice"
|
||||
},
|
||||
"import": {
|
||||
"importIntoNote": "Uvezi u belešku",
|
||||
"chooseImportFile": "Izaberi datoteku za uvoz",
|
||||
"importDescription": "Sadržaj izabranih datoteka će biti uvezen kao podbeleške u",
|
||||
"options": "Opcije",
|
||||
"safeImportTooltip": "Trilium <code>.zip</code> izvozne datoteke mogu da sadrže izvršne skripte koje mogu imati štetno ponašanje. Bezbedan uvoz će deaktivirati automatsko izvršavanje svih uvezenih skripti. Isključite \"Bezbedan uvoz\" samo ako uvezena arhiva treba da sadrži izvršne skripte i ako potpuno verujete sadržaju uvezene datoteke.",
|
||||
"safeImport": "Bezbedan uvoz",
|
||||
"explodeArchivesTooltip": "Ako je ovo označeno onda će Trilium pročitati <code>.zip</code>, <code>.enex</code> i <code>.opml</code> datoteke i napraviti beleške od datoteka unutar tih arhiva. Ako nije označeno, Trilium će same arhive priložiti belešci.",
|
||||
"explodeArchives": "Pročitaj sadržaj <code>.zip</code>, <code>.enex</code> i <code>.opml</code> arhiva.",
|
||||
"shrinkImagesTooltip": "<p>Ako označite ovu opciju, Trilium će pokušati da smanji uvezene slike skaliranjem i optimizacijom što će možda uticati na kvalitet slike. Ako nije označeno, slike će biti uvezene bez promena.</p><p>Ovo se ne primenjuje na <code>.zip</code> uvoze sa metapodacima jer se tada podrazumeva da su te datoteke već optimizovane.</p>",
|
||||
"shrinkImages": "Smanji slike",
|
||||
"textImportedAsText": "Uvezi HTML, Markdown i TXT kao tekstualne beleške ako je nejasno iz metapodataka",
|
||||
"codeImportedAsCode": "Uvezi prepoznate datoteke sa kodom (poput <code>.json</code>) ako beleške sa kodom ako nije jasno iz metapodataka",
|
||||
"replaceUnderscoresWithSpaces": "Zameni podvlake sa razmacima u nazivima uvezenih beleški",
|
||||
"import": "Uvezi",
|
||||
"failed": "Uvoz nije uspeo: {{message}}.",
|
||||
"html_import_tags": {
|
||||
"title": "HTML oznake za uvoz",
|
||||
"description": "Podesite koje HTML oznake trebaju biti sačuvane kada se uvoze beleške. Oznake koje se ne nalaze na listi će biti uklonjene tokom uvoza. Pojedine oznake (poput 'script') se uvek uklanjaju zbog bezbednosti.",
|
||||
"placeholder": "Unesite HTML oznake, po jednu u svaki red",
|
||||
"reset_button": "Vrati na podrazumevanu listu"
|
||||
},
|
||||
"import-status": "Status uvoza",
|
||||
"in-progress": "Uvoz u toku: {{progress}}",
|
||||
"successful": "Uvoz je uspešno završen."
|
||||
},
|
||||
"include_note": {
|
||||
"dialog_title": "Uključi belešku",
|
||||
"label_note": "Beleška",
|
||||
"placeholder_search": "pretraži belešku po njenom imenu",
|
||||
"box_size_prompt": "Veličina kutije priložene beleške:",
|
||||
"box_size_small": "mala (~ 10 redova)",
|
||||
"box_size_medium": "srednja (~ 30 redova)",
|
||||
"box_size_full": "puna (kutija prikazuje ceo tekst)",
|
||||
"button_include": "Uključi belešku"
|
||||
},
|
||||
"info": {
|
||||
"modalTitle": "Informativna poruka",
|
||||
"closeButton": "Zatvori",
|
||||
"okButton": "U redu"
|
||||
},
|
||||
"jump_to_note": {
|
||||
"search_placeholder": "Pretraži belešku po njenom imenu ili unesi > za komande...",
|
||||
"search_button": "Pretraga u punom tekstu <kbd>Ctrl+Enter</kbd>"
|
||||
},
|
||||
"markdown_import": {
|
||||
"dialog_title": "Uvoz za Markdown",
|
||||
"modal_body_text": "Zbog Sandbox-a pretraživača nije moguće direktno učitati privremenu memoriju iz JavaScript-a. Molimo vas da nalepite Markdown za uvoz u tekstualno polje ispod i kliknete na dugme za uvoz",
|
||||
"import_button": "Uvoz",
|
||||
"import_success": "Markdown sadržaj je učitan u dokument."
|
||||
},
|
||||
"move_to": {
|
||||
"dialog_title": "Premesti beleške u ...",
|
||||
"notes_to_move": "Beleške za premeštanje",
|
||||
"target_parent_note": "Ciljana nadbeleška",
|
||||
"search_placeholder": "potraži belešku po njenom imenu",
|
||||
"move_button": "Pređi na izabranu belešku",
|
||||
"error_no_path": "Nema putanje za premeštanje.",
|
||||
"move_success_message": "Izabrane beleške su premeštene u "
|
||||
},
|
||||
"note_type_chooser": {
|
||||
"change_path_prompt": "Promenite gde će se napraviti nova beleška:",
|
||||
"search_placeholder": "pretraži putanju po njenom imenu (podrazumevano ako je prazno)",
|
||||
"modal_title": "Izaberite tip beleške",
|
||||
"modal_body": "Izaberite tip beleške / šablon za novu belešku:",
|
||||
"templates": "Šabloni"
|
||||
},
|
||||
"password_not_set": {
|
||||
"title": "Lozinka nije podešena",
|
||||
"body1": "Zaštićene beleške su enkriptovane sa korisničkom lozinkom, ali lozinka još uvek nije podešena.",
|
||||
"body2": "Za biste mogli da sačuvate beleške, kliknite <a class=\"open-password-options-button\" href=\"javascript:\">ovde</a> da otvorite dijalog sa Opcijama i podesite svoju lozinku."
|
||||
},
|
||||
"prompt": {
|
||||
"title": "Upit",
|
||||
"ok": "U redu <kbd>enter</kbd>",
|
||||
"defaultTitle": "Upit"
|
||||
},
|
||||
"protected_session_password": {
|
||||
"modal_title": "Zaštićena sesija",
|
||||
"help_title": "Pomoć za Zaštićene beleške",
|
||||
"close_label": "Zatvori",
|
||||
"form_label": "Da biste nastavili sa traženom akcijom moraćete započeti zaštićenu sesiju tako što ćete uneti lozinku:",
|
||||
"start_button": "Započni zaštićenu sesiju"
|
||||
},
|
||||
"recent_changes": {
|
||||
"title": "Nedavne promene",
|
||||
"erase_notes_button": "Obriši izabrane beleške odmah",
|
||||
"deleted_notes_message": "Obrisane beleške su uklonjene.",
|
||||
"no_changes_message": "Još uvek nema izmena...",
|
||||
"undelete_link": "poništi brisanje",
|
||||
"confirm_undelete": "Da li želite da poništite brisanje ove beleške i njenih podbeleški?"
|
||||
},
|
||||
"revisions": {
|
||||
"note_revisions": "Revizije beleški",
|
||||
"delete_all_revisions": "Obriši sve revizije ove beleške",
|
||||
"delete_all_button": "Obriši sve revizije",
|
||||
"help_title": "Pomoć za Revizije beleški",
|
||||
"confirm_delete_all": "Da li želite da obrišete sve revizije ove beleške?",
|
||||
"no_revisions": "Još uvek nema revizija za ovu belešku...",
|
||||
"restore_button": "Vrati",
|
||||
"confirm_restore": "Da li želite da vratite ovu reviziju? Ovo će prepisati trenutan naslov i sadržaj beleške sa ovom revizijom.",
|
||||
"delete_button": "Obriši",
|
||||
"confirm_delete": "Da li želite da obrišete ovu reviziju?",
|
||||
"revisions_deleted": "Revizije beleške su obrisane.",
|
||||
"revision_restored": "Revizija beleške je vraćena.",
|
||||
"revision_deleted": "Revizija beleške je obrisana.",
|
||||
"snapshot_interval": "Interval snimanja revizije beleške: {{seconds}}s.",
|
||||
"maximum_revisions": "Ograničenje broja slika revizije beleške: {{number}}.",
|
||||
"settings": "Podešavanja revizija beleški",
|
||||
"download_button": "Preuzmi",
|
||||
"mime": "MIME: ",
|
||||
"file_size": "Veličina datoteke:",
|
||||
"preview": "Pregled:",
|
||||
"preview_not_available": "Pregled nije dostupan za ovaj tip beleške."
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"sort_children_by": "Sortiranje podbeleški po...",
|
||||
"sorting_criteria": "Kriterijum za sortiranje",
|
||||
"title": "naslov",
|
||||
"date_created": "datum kreiranja",
|
||||
"date_modified": "datum izmene",
|
||||
"sorting_direction": "Smer sortiranja",
|
||||
"ascending": "uzlazni",
|
||||
"descending": "silazni",
|
||||
"folders": "Fascikle",
|
||||
"sort_folders_at_top": "sortiraj fascikle na vrh",
|
||||
"natural_sort": "Prirodno sortiranje",
|
||||
"sort_with_respect_to_different_character_sorting": "sortiranje sa poštovanjem različitih pravila sortiranja karaktera i kolacija u različitim jezicima ili regionima.",
|
||||
"natural_sort_language": "Jezik za prirodno sortiranje",
|
||||
"the_language_code_for_natural_sort": "Kod jezika za prirodno sortiranje, npr. \"zh-CN\" za Kineski.",
|
||||
"sort": "Sortiraj"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"upload_attachments_to_note": "Otpremite priloge uz belešku",
|
||||
"choose_files": "Izaberite datoteke",
|
||||
"files_will_be_uploaded": "Datoteke će biti otpremljene kao prilozi u {{noteTitle}}",
|
||||
"options": "Opcije",
|
||||
"shrink_images": "Smanji slike",
|
||||
"upload": "Otpremi",
|
||||
"tooltip": "Ako je označeno, Trilium će pokušati da smanji otpremljene slike skaliranjem i optimizacijom što može uticati na kvalitet slike. Ako nije označeno, slike će biti otpremljene bez izmena."
|
||||
},
|
||||
"attribute_detail": {
|
||||
"attr_detail_title": "Naslov detalja atributa",
|
||||
"close_button_title": "Otkaži izmene i zatvori",
|
||||
"attr_is_owned_by": "Atribut je u vlasništvu",
|
||||
"attr_name_title": "Naziv atributa može biti sastavljen samo od alfanumeričkih znakova, dvotačke i donje crte",
|
||||
"name": "Naziv",
|
||||
"value": "Vrednost",
|
||||
"target_note_title": "Relacija je imenovana veza između izvorne beleške i ciljne beleške.",
|
||||
"target_note": "Ciljna beleška",
|
||||
"promoted_title": "Promovisani atribut je istaknut na belešci.",
|
||||
"promoted": "Promovisan",
|
||||
"promoted_alias_title": "Naziv koji će biti prikazan u korisničkom interfejsu promovisanih atributa.",
|
||||
"promoted_alias": "Pseudonim",
|
||||
"multiplicity_title": "Multiplicitet definiše koliko atributa sa istim nazivom se može napraviti - najviše 1 ili više od 1.",
|
||||
"multiplicity": "Multiplicitet",
|
||||
"single_value": "Jednostruka vrednost",
|
||||
"multi_value": "Višestruka vrednost",
|
||||
"label_type_title": "Tip oznake će pomoći Triliumu da izabere odgovarajući interfejs za unos vrednosti oznake.",
|
||||
"label_type": "Tip",
|
||||
"text": "Tekst",
|
||||
"number": "Broj",
|
||||
"boolean": "Boolean",
|
||||
"date": "Datum",
|
||||
"date_time": "Datum i vreme",
|
||||
"time": "Vreme",
|
||||
"url": "URL",
|
||||
"precision_title": "Broj cifara posle zareza treba biti dostupan u interfejsu za postavljanje vrednosti.",
|
||||
"precision": "Preciznost",
|
||||
"digits": "cifre",
|
||||
"inverse_relation_title": "Opciono podešavanje za definisanje kojoj relaciji je ova suprotna. Primer: Otac - Sin su inverzne relacije jedna drugoj.",
|
||||
"inverse_relation": "Inverzna relacija",
|
||||
"inheritable_title": "Atributi koji mogu da se nasleđuju će biti nasleđeni od strane svih potomaka unutar ovog stabla.",
|
||||
"inheritable": "Nasledno",
|
||||
"save_and_close": "Sačuvaj i zatvori <kbd>Ctrl+Enter</kbd>",
|
||||
"delete": "Obriši",
|
||||
"related_notes_title": "Druge beleške sa ovom oznakom",
|
||||
"more_notes": "Još beleški",
|
||||
"label": "Detalji oznake",
|
||||
"label_definition": "Detalji definicije oznake",
|
||||
"relation": "Detalji relacije",
|
||||
"relation_definition": "Detalji definicije relacije",
|
||||
"disable_versioning": "onemogućava auto-verzionisanje. Korisno za npr. velike, ali nebitne beleške - poput velikih JS biblioteka koje se koriste za skripte",
|
||||
"calendar_root": "obeležava belešku koju treba koristiti kao osnova za dnevne beleške. Samo jedna beleška treba da bude označena kao takva.",
|
||||
"archived": "beleške sa ovom oznakom neće biti podrazumevano vidljive u rezultatima pretrage (kao ni u dijalozima za Idi na, Dodaj link, itd.).",
|
||||
"exclude_from_export": "beleške (sa svojim podstablom) neće biti uključene u bilo koji izvoz beleški",
|
||||
"run": "definiše u kojim događajima se skripta pokreće. Moguće vrednosti su:\n<ul>\n<li>frontendStartup - kada se pokrene Trilium frontend (ili se osveži), ali ne na mobilnom uređaju.</li>\n<li>mobileStartup - kada se pokrene Trilium frontend (ili se osveži), na mobilnom uređaju..</li>\n<li>backendStartup - kada se Trilium backend pokrene</li>\n<li>hourly - pokreće se svaki sat. Može se koristiti dodatna oznaka <code>runAtHour</code> da se označi u kom satu.</li>\n<li>daily - pokreće se jednom dnevno</li>\n</ul>",
|
||||
"run_on_instance": "Definiše u kojoj instanci Trilium-a ovo treba da se pokreće. Podrazumevano podešavanje je na svim instancama.",
|
||||
"run_at_hour": "U kom satu ovo treba da se pokreće. Treba se koristiti zajedno sa <code>#run=hourly</code>. Može biti definisano više puta za više pokretanja u toku dana.",
|
||||
"disable_inclusion": "skripte sa ovom oznakom neće biti uključene u izvršavanju nadskripte.",
|
||||
"sorted": "čuva podbeleške sortirane alfabetski po naslovu",
|
||||
"sort_direction": "Uzlazno (podrazumevano) ili silazno",
|
||||
"sort_folders_first": "Fascikle (beleške sa podbeleškama) treba da budu sortirane na vrhu",
|
||||
"top": "zadrži datu belešku na vrhu njene nadbeleške (primenjuje se samo na sortiranim nadbeleškama)",
|
||||
"hide_promoted_attributes": "Sakrij promovisane atribute na ovoj belešci",
|
||||
"read_only": "uređivač je u režimu samo za čitanje. Radi samo za tekst i beleške sa kodom.",
|
||||
"auto_read_only_disabled": "beleške sa tekstom/kodom se mogu automatski podesiti u režim za čitanje kada su prevelike. Ovo ponašanje možete onemogućiti pojedinačno za belešku dodavanjem ove oznake na belešku",
|
||||
"app_css": "označava CSS beleške koje nisu učitane u Trilium aplikaciju i zbog toga se mogu koristiti za menjanje izgleda Triliuma.",
|
||||
"app_theme": "označava CSS beleške koje su pune Trilium teme i stoga su dostupne u Trilium podešavanjima.",
|
||||
"app_theme_base": "podesite na „sledeće“, „sledeće-svetlo“ ili „sledeće-tamno“ da biste koristili odgovarajuću TriliumNext temu (automatsku, svetlu ili tamnu) kao osnovu za prilagođenu temu, umesto podrazumevane teme.",
|
||||
"css_class": "vrednost ove oznake se zatim dodaje kao CSS klasa čvoru koji predstavlja datu belešku u stablu. Ovo može biti korisno za napredno temiranje. Može se koristiti u šablonima beleški.",
|
||||
"workspace": "označava ovu belešku kao radni prostor što omogućava lako podizanje",
|
||||
"workspace_icon_class": "definiše CSS klasu ikone okvira koja će se koristiti u kartici kada se podigne na ovoj belešci",
|
||||
"workspace_tab_background_color": "CSS boja korišćena u kartici beleške kada se prebaci na ovu belešku",
|
||||
"workspace_calendar_root": "Definiše koren kalendara za svaki radni prostor",
|
||||
"workspace_template": "Ova beleška će se pojaviti u izboru dostupnih šablona prilikom kreiranja nove beleške, ali samo kada se podigne u radni prostor koji sadrži ovaj šablon",
|
||||
"search_home": "nove beleške o pretrazi biće kreirane kao podređeni delovi ove beleške",
|
||||
"workspace_search_home": "nove beleške o pretrazi biće kreirane kao podređeni delovi ove beleške kada se podignu na nekog pretka ove beleške iz radnog prostora",
|
||||
"inbox": "podrazumevana lokacija u prijemnom sandučetu za nove beleške - kada kreirate belešku pomoću dugmeta „nova beleška“ u bočnoj traci, beleške će biti kreirane kao podbeleške u belešci označenoj sa oznakom <code>#inbox</code>.",
|
||||
"workspace_inbox": "podrazumevana lokacija prijemnog sandučeta za nove beleške kada se prebace na nekog pretka ove beleške iz radnog prostora",
|
||||
"sql_console_home": "podrazmevana lokacija beleški SQL konzole",
|
||||
"bookmark_folder": "beleška sa ovom oznakom će se pojaviti u obeleživačima kao fascikla (omogućavajući pristup njenim podređenim fasciklama)",
|
||||
"share_hidden_from_tree": "ova beleška je skrivena u levom navigacionom stablu, ali je i dalje dostupna preko svoje URL adrese",
|
||||
"share_external_link": "beleška će služiti kao veza ka eksternoj veb stranici u stablu deljenja",
|
||||
"share_alias": "definišite alias pomoću kog će beleška biti dostupna na https://your_trilium_host/share/[your_alias]",
|
||||
"share_omit_default_css": "CSS kod podrazumevane stranice za deljenje će biti izostavljen. Koristite ga kada pravite opsežne promene stila.",
|
||||
"share_root": "obeležava belešku koja se prikazuje na /share korenu.",
|
||||
"share_description": "definišite tekst koji će se dodati HTML meta oznaci za opis",
|
||||
"share_raw": "beleška će biti prikazana u svom sirovom (raw) formatu, bez HTML omotača",
|
||||
"share_disallow_robot_indexing": "zabraniće robotsko indeksiranje ove beleške putem zaglavlja <code>X-Robots-Tag: noindex</code>",
|
||||
"share_credentials": "potrebni su kredencijali za pristup ovoj deljenoj belešci. Očekuje se da vrednost bude u formatu „korisničko ime:lozinka“. Ne zaboravite da ovo označite kao nasledno da bi se primenilo na podbeleške/slike.",
|
||||
"share_index": "beleška sa ovom oznakom će izlistati sve korene deljenih beleški",
|
||||
"display_relations": "imena relacija razdvojenih zarezima koja treba da budu prikazana. Sva ostala će biti skrivena.",
|
||||
"hide_relations": "imena relacija razdvojenih zarezima koja treba da budu skrivena. Sva ostala će biti prikazana.",
|
||||
"title_template": "podrazumevani naslov beleški kreiranih kao deca ove beleške. Vrednost se procenjuje kao JavaScript string \n i stoga se može obogatiti dinamičkim sadržajem putem ubrizganih promenljivih <code>now</code> and <code>parentNote</code>. Primeri:\n \n <ul>\n <li><code>${parentNote.getLabelValue('authorName')}'s literary works</code></li>\n <li><code>Log for ${now.format('YYYY-MM-DD HH:mm:ss')}</code></li>\n </ul>\n \n Pogledati <a href=\"https://triliumnext.github.io/Docs/Wiki/default-note-title.html\">wiki sa detaljima</a>, API dokumentacija za <a href=\"https://zadam.github.io/trilium/backend_api/Note.html\">parentNote</a> i <a href=\"https://day.js.org/docs/en/display/format\">now</a> za detalje.",
|
||||
"template": "Ova beleška će biti prikazana u izboru dostupnih šablona prilikom pravljenja nove beleške",
|
||||
"toc": "<code>#toc</code> ili <code>#toc=show</code> će pristiliti Sadržaj (Table of Contents) da bude prikazan, <code>#toc=hide</code> prisiliti njegovo sakrivanje. Ako oznaka ne postoji, ponašanje će biti usklađeno sa globalnim podešavanjem",
|
||||
"color": "definiše boju beleške u stablu beleški, linkovima itd. Koristite bilo koju važeću CSS vrednost boje kao što je „crvena“ ili #a13d5f",
|
||||
"keyboard_shortcut": "Definiše prečicu na tastaturi koja će odmah preći na ovu belešku. Primer: „ctrl+alt+e“. Potrebno je ponovno učitavanje frontenda da bi promena stupila na snagu.",
|
||||
"keep_current_hoisting": "Otvaranje ove veze neće promeniti podizanje čak i ako beleška nije prikazana u trenutno podignutom podstablu.",
|
||||
"execute_button": "Naslov dugmeta koje će izvršiti trenutnu belešku sa kodom",
|
||||
"execute_description": "Duži opis trenutne beleške sa kodom prikazan je zajedno sa dugmetom za izvršavanje",
|
||||
"exclude_from_note_map": "Beleške sa ovom oznakom biće skrivene sa mape beleški",
|
||||
"new_notes_on_top": "Nove beleške će biti napravljene na vrhu matične beleške, a ne na dnu.",
|
||||
"hide_highlight_widget": "Sakrij vidžet sa listom istaknutih",
|
||||
"run_on_note_creation": "izvršava se kada se beleška napravi na serverskoj strani. Koristite ovu relaciju ako želite da pokrenete skriptu za sve beleške napravljene u okviru određenog podstabla. U tom slučaju, kreirajte je na korenu beleške podstabla i učinite je naslednom. Nova beleška napravljena unutar podstabla (bilo koje dubine) pokrenuće skriptu.",
|
||||
"run_on_child_note_creation": "izvršava se kada se napravi nova beleška ispod beleške gde je ova relacija definisana",
|
||||
"run_on_note_title_change": "izvršava se kada se promeni naslov beleške (uključuje i pravljenje beleške)",
|
||||
"run_on_note_content_change": "izvršava se kada se promeni sadržaj beleške (uključuje i pravljenje beleške).",
|
||||
"run_on_note_change": "izvršava se kada se promeni beleška (uključuje i pravljenje beleške). Ne uključuje promene sadržaja",
|
||||
"icon_class": "vrednost ove oznake se dodaje kao CSS klasa ikoni na stablu što može pomoći u vizuelnom razlikovanju beleški u stablu. Primer može biti bx bx-home - ikone su preuzete iz boxicons. Može se koristiti u šablonima beleški.",
|
||||
"page_size": "broj stavki po stranici u listi beleški",
|
||||
"custom_request_handler": "pogledajte <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Prilagođeni obrađivač zahteva</a>",
|
||||
"custom_resource_provider": "pogledajte <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Prilagođeni obrađivač zahteva</a>",
|
||||
"widget": "označava ovu belešku kao prilagođeni vidžet koji će biti dodat u stablo komponenti Trilijuma",
|
||||
"run_on_note_deletion": "izvršava se kada se beleška briše",
|
||||
"run_on_branch_creation": "izvršava se kada se pravi grana. Grana je veza između matične i podređene beleške i pravi se npr. prilikom kloniranja ili premeštanja beleške.",
|
||||
"run_on_branch_change": "izvršava se kada se grana ažurira.",
|
||||
"run_on_branch_deletion": "izvršava se kada se grana briše. Grana je veza između nadređene beleške i podređene beleške i briše se npr. prilikom premeštanja beleške (stara grana/veza se briše).",
|
||||
"run_on_attribute_creation": "izvršava se kada se pravi novi atribut za belešku koji definiše ovu relaciju",
|
||||
"run_on_attribute_change": " izvršava se kada se promeni atribut beleške koja definiše ovu relaciju. Ovo se pokreće i kada se atribut obriše",
|
||||
"relation_template": "atributi beleške će biti nasleđeni čak i bez odnosa roditelj-dete, sadržaj i podstablo beleške će biti dodati instanci beleške ako je prazna. Pogledajte dokumentaciju za detalje.",
|
||||
"inherit": "Atributi beleške će biti nasleđeni čak i bez odnosa roditelj-dete. Pogledajte relaciju šablona za sličan koncept. Pogledajte nasleđivanje atributa u dokumentaciji.",
|
||||
"render_note": "Beleške tipa „render HTML note“ će biti prikazane korišćenjem beleške za kod (HTML ili skripte) i potrebno je pomoću ove relacije ukazati na to koja beleška treba da se prikaže",
|
||||
"widget_relation": "meta ove relacije će biti izvršena i prikazana kao vidžet u bočnoj traci",
|
||||
"share_css": "CSS napomena koja će biti ubrizgana na stranicu za deljenje. CSS napomena mora biti i u deljenom podstablu. Razmotrite i korišćenje „share_hidden_from_tree“ i „share_omit_default_css“.",
|
||||
"share_js": "JavaScript beleška koja će biti ubrizgana na stranicu za deljenje. JS beleška takođe mora biti u deljenom podstablu. Razmislite o korišćenju „share_hidden_from_tree“.",
|
||||
"share_template": "Ugrađena JavaScript beleška koja će se koristiti kao šablon za prikazivanje deljene beleške. U slučaju neuspeha vraća se na podrazumevani šablon. Razmislite o korišćenju „share_hidden_from_tree“.",
|
||||
"share_favicon": "Favicon beleška koju treba postaviti na deljenu stranicu. Obično je potrebno da je podesite da deli koren i učinite je naslednom. Favicon beleška takođe mora biti u deljenom podstablu. Razmislite o korišćenju „share_hidden_from_tree“.",
|
||||
"is_owned_by_note": "je u vlasništvu beleške",
|
||||
"other_notes_with_name": "Ostale beleške sa {{attributeType}} nazivom „{{attributeName}}“",
|
||||
"and_more": "... i još {{count}}.",
|
||||
"print_landscape": "Prilikom izvoza u PDF, menja orijentaciju stranice u pejzažnu umesto uspravne.",
|
||||
"print_page_size": "Prilikom izvoza u PDF, menja veličinu stranice. Podržane vrednosti: <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": "Boja"
|
||||
},
|
||||
"ai_llm": {
|
||||
"n_notes_queued_0": "{{ count }} beleška stavljena u red za indeksiranje",
|
||||
"n_notes_queued_1": "{{ count }} beleški stavljeno u red za indeksiranje",
|
||||
"n_notes_queued_2": "{{ count }} beleški stavljeno u red za indeksiranje",
|
||||
"notes_indexed_0": "{{ count }} beleška je indeksirana",
|
||||
"notes_indexed_1": "{{ count }} beleški je indeksirano",
|
||||
"notes_indexed_2": "{{ count }} beleški je indeksirano"
|
||||
},
|
||||
"attribute_editor": {
|
||||
"help_text_body1": "Da biste dodali oznaku, samo unesite npr. <code>#rock</code> ili ako želite da dodate i vrednost, onda npr. <code>#year = 2020</code>",
|
||||
"help_text_body2": "Za relaciju, unesite <code>~author = @</code> što bi trebalo da otvori automatsko dovršavanje gde možete potražiti željenu belešku.",
|
||||
"help_text_body3": "Alternativno, možete dodati oznaku i relaciju pomoću dugmeta <code>+</code> sa desne strane.",
|
||||
"save_attributes": "Sačuvaj atribute <enter>",
|
||||
"add_a_new_attribute": "Dodajte novi atribut",
|
||||
"add_new_label": "Dodajte novu oznaku <kbd data-command=\"addNewLabel\"></kbd>",
|
||||
"add_new_relation": "Dodajte novu relaciju <kbd data-command=\"addNewRelation\"></kbd>",
|
||||
"add_new_label_definition": "Dodajte novu definiciju oznake",
|
||||
"add_new_relation_definition": "Dodajte novu definiciju relacije",
|
||||
"placeholder": "Ovde unesite oznake i relacije"
|
||||
},
|
||||
"abstract_bulk_action": {
|
||||
"remove_this_search_action": "Ukloni ovu radnju pretrage"
|
||||
},
|
||||
"execute_script": {
|
||||
"execute_script": "Izvrši skriptu",
|
||||
"help_text": "Možete izvršiti jednostavne skripte na podudarnim beleškama.",
|
||||
"example_1": "Na primer, da biste dodali string u naslov beleške, koristite ovu malu skriptu:",
|
||||
"example_2": "Složeniji primer bi bio brisanje svih atributa podudarnih beleški:"
|
||||
},
|
||||
"add_label": {
|
||||
"add_label": "Dodaj oznaku",
|
||||
"label_name_placeholder": "ime oznake",
|
||||
"label_name_title": "Alfanumerički znakovi, donja crta i dvotačka su dozvoljeni znakovi.",
|
||||
"to_value": "za vrednost",
|
||||
"new_value_placeholder": "nova vrednost",
|
||||
"help_text": "Na svim podudarnim beleškama:",
|
||||
"help_text_item1": "dodajte datu oznaku ako beleška još uvek nema jednu",
|
||||
"help_text_item2": "ili izmenite vrednost postojeće oznake",
|
||||
"help_text_note": "Takođe možete pozvati ovu metodu bez vrednosti, u tom slučaju će oznaka biti dodeljena belešci bez vrednosti."
|
||||
},
|
||||
"delete_label": {
|
||||
"delete_label": "Obriši oznaku",
|
||||
"label_name_placeholder": "ime oznake",
|
||||
"label_name_title": "Alfanumerički znakovi, donja crtica i dvotačka su dozvoljeni znakovi."
|
||||
},
|
||||
"rename_label": {
|
||||
"rename_label": "Preimenuj oznaku",
|
||||
"rename_label_from": "Preimenuj oznaku iz",
|
||||
"old_name_placeholder": "stari naziv",
|
||||
"to": "U",
|
||||
"new_name_placeholder": "novi naziv",
|
||||
"name_title": "Alfanumerički znakovi, donja crtica i dvotačka su dozvoljeni znakovi."
|
||||
},
|
||||
"update_label_value": {
|
||||
"update_label_value": "Ažuriraj vrednost oznake",
|
||||
"label_name_placeholder": "ime oznake",
|
||||
"label_name_title": "Alfanumerički znakovi, donja crtica i dvotačka su dozvoljeni znakovi.",
|
||||
"to_value": "u vrednost",
|
||||
"new_value_placeholder": "nova vrednost",
|
||||
"help_text": "Na svim podudarnim beleškama, promenite vrednost postojeće oznake.",
|
||||
"help_text_note": "Takođe možete pozvati ovu metodu bez vrednosti, u tom slučaju će oznaka biti dodeljena belešci bez vrednosti."
|
||||
},
|
||||
"delete_note": {
|
||||
"delete_note": "Obriši belešku",
|
||||
"delete_matched_notes": "Obriši podudarne beleške",
|
||||
"delete_matched_notes_description": "Ovo će obrisati podudarne beleške.",
|
||||
"undelete_notes_instruction": "Nakon brisanja, moguće ga je poništiti iz dijaloga Nedavne izmene."
|
||||
"bundle-error": {
|
||||
"title": "Pokretanje prilagođene skripte neuspešno",
|
||||
"message": "Skripta iz beleške sa ID-jem \"{{id}}\", naslovom \"{{title}}\" nije mogla da se izvrši zbog:\n\n{{message}}"
|
||||
}
|
||||
},
|
||||
"add_link": {
|
||||
"add_link": "Dodaj link",
|
||||
"help_on_links": "Pomoć na linkovima",
|
||||
"note": "Beleška",
|
||||
"search_note": "potražite belešku po njenom imenu",
|
||||
"link_title_mirrors": "naziv linka preslikava trenutan naziv beleške",
|
||||
"link_title_arbitrary": "naziv linka se može proizvoljno menjati",
|
||||
"link_title": "Naziv linka",
|
||||
"button_add_link": "Dodaj link <kbd>enter</kbd>"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"edit_branch_prefix": "Izmeni prefiks grane",
|
||||
"help_on_tree_prefix": "Pomoć na prefiksu Drveta",
|
||||
"prefix": "Prefiks: ",
|
||||
"save": "Sačuvaj",
|
||||
"branch_prefix_saved": "Prefiks grane je sačuvan."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Grupne akcije",
|
||||
"affected_notes": "Pogođene beleške",
|
||||
"include_descendants": "Obuhvati potomke izabranih beleški",
|
||||
"available_actions": "Dostupne akcije",
|
||||
"chosen_actions": "Izabrane akcije",
|
||||
"execute_bulk_actions": "Izvrši grupne akcije",
|
||||
"bulk_actions_executed": "Grupne akcije su uspešno izvršene.",
|
||||
"none_yet": "Nijedna za sad... dodajte akciju tako što ćete pritisnuti na neku od dostupnih akcija iznad.",
|
||||
"labels": "Oznake",
|
||||
"relations": "Odnosi",
|
||||
"notes": "Beleške",
|
||||
"other": "Ostalo"
|
||||
},
|
||||
"clone_to": {
|
||||
"clone_notes_to": "Klonirajte beleške u...",
|
||||
"help_on_links": "Pomoć na linkovima",
|
||||
"notes_to_clone": "Beleške za kloniranje",
|
||||
"target_parent_note": "Ciljna nadređena beleška",
|
||||
"search_for_note_by_its_name": "potražite belešku po njenom imenu",
|
||||
"cloned_note_prefix_title": "Klonirana beleška će biti prikazana u drvetu beleški sa datim prefiksom",
|
||||
"prefix_optional": "Prefiks (opciono)",
|
||||
"clone_to_selected_note": "Kloniranje u izabranu belešku <kbd>enter</kbd>",
|
||||
"no_path_to_clone_to": "Nema putanje za kloniranje.",
|
||||
"note_cloned": "Beleška \"{{clonedTitle}}\" je klonirana u \"{{targetTitle}}\""
|
||||
},
|
||||
"confirm": {
|
||||
"confirmation": "Potvrda",
|
||||
"cancel": "Otkaži",
|
||||
"ok": "U redu",
|
||||
"are_you_sure_remove_note": "Da li ste sigurni da želite da uklonite belešku \"{{title}}\" iz mape odnosa? ",
|
||||
"if_you_dont_check": "Ako ne izaberete ovo, beleška će biti uklonjena samo sa mape odnosa.",
|
||||
"also_delete_note": "Takođe obriši belešku"
|
||||
},
|
||||
"delete_notes": {
|
||||
"delete_notes_preview": "Obriši pregled beleške",
|
||||
"close": "Zatvori",
|
||||
"delete_all_clones_description": "Obriši i sve klonove (može biti poništeno u skorašnjim izmenama)",
|
||||
"erase_notes_description": "Normalno (blago) brisanje samo označava beleške kao obrisane i one mogu biti vraćene (u dijalogu skorašnjih izmena) u određenom vremenskom periodu. Biranje ove opcije će momentalno obrisati beleške i ove beleške neće biti moguće vratiti.",
|
||||
"erase_notes_warning": "Trajno obriši beleške (ne može se opozvati), uključujući sve klonove. Ovo će prisiliti aplikaciju da se ponovo pokrene.",
|
||||
"notes_to_be_deleted": "Sledeće beleške će biti obrisane ({{- noteCount}})",
|
||||
"no_note_to_delete": "Nijedna beleška neće biti obrisana (samo klonovi).",
|
||||
"broken_relations_to_be_deleted": "Sledeći odnosi će biti prekinuti i obrisani ({{- relationCount}})",
|
||||
"cancel": "Otkaži",
|
||||
"ok": "U redu",
|
||||
"deleted_relation_text": "Beleška {{- note}} (za brisanje) je referencirana sa odnosom {{- relation}} koji potiče iz {{- source}}."
|
||||
},
|
||||
"export": {
|
||||
"export_note_title": "Izvezi belešku",
|
||||
"close": "Zatvori",
|
||||
"export_type_subtree": "Ova beleška i svi njeni potomci",
|
||||
"format_html": "HTML - preporučuje se jer čuva formatiranje",
|
||||
"format_html_zip": "HTML u ZIP arhivi - ovo se preporučuje jer se na taj način čuva celokupno formatiranje.",
|
||||
"format_markdown": "Markdown - ovo čuva većinu formatiranja.",
|
||||
"format_opml": "OPML - format za razmenu okvira samo za tekst. Formatiranje, slike i datoteke nisu uključeni.",
|
||||
"opml_version_1": "OPML v1.0 - samo običan tekst",
|
||||
"opml_version_2": "OPML v2.0 - dozvoljava i HTML",
|
||||
"export_type_single": "Samo ovu belešku bez njenih potomaka",
|
||||
"export": "Izvoz",
|
||||
"choose_export_type": "Molimo vas da prvo izaberete tip izvoza",
|
||||
"export_status": "Status izvoza",
|
||||
"export_in_progress": "Izvoz u toku: {{progressCount}}",
|
||||
"export_finished_successfully": "Izvoz je uspešno završen.",
|
||||
"format_pdf": "PDF - za namene štampanja ili deljenja."
|
||||
},
|
||||
"help": {
|
||||
"noteNavigation": "Navigacija beleški",
|
||||
"goUpDown": "<kbd>UP</kbd>, <kbd>DOWN</kbd> - kretanje gore/dole u listi sa beleškama",
|
||||
"collapseExpand": "<kbd>LEFT</kbd>, <kbd>RIGHT</kbd> - sakupi/proširi čvor",
|
||||
"notSet": "nije podešeno",
|
||||
"goBackForwards": "idi u nazad/napred kroz istoriju",
|
||||
"showJumpToNoteDialog": "prikaži <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"Idi na\" dijalog</a>",
|
||||
"scrollToActiveNote": "skroluj do aktivne beleške",
|
||||
"jumpToParentNote": "idi do nadređene beleške",
|
||||
"collapseWholeTree": "sakupi celo drvo beleški",
|
||||
"collapseSubTree": "sakupi pod-drvo",
|
||||
"tabShortcuts": "Prečice na karticama",
|
||||
"newTabNoteLink": "na link beleške otvara belešku u novoj kartici",
|
||||
"newTabWithActivationNoteLink": "na link beleške otvara i aktivira belešku u novoj kartici",
|
||||
"onlyInDesktop": "Samo na dektop-u (Electron verzija)",
|
||||
"openEmptyTab": "otvori praznu karticu",
|
||||
"closeActiveTab": "zatvori aktivnu karticu",
|
||||
"activateNextTab": "aktiviraj narednu karticu",
|
||||
"activatePreviousTab": "aktiviraj prethodnu karticu",
|
||||
"creatingNotes": "Pravljenje beleški",
|
||||
"createNoteAfter": "napravi novu belešku nakon aktivne beleške",
|
||||
"createNoteInto": "napravi novu pod-belešku u aktivnoj belešci",
|
||||
"editBranchPrefix": "izmeni <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/tree-concepts.html#prefix\">prefiks</a> klona aktivne beleške",
|
||||
"movingCloningNotes": "Premeštanje / kloniranje beleški",
|
||||
"moveNoteUpDown": "pomeri belešku gore/dole u listi beleški",
|
||||
"moveNoteUpHierarchy": "pomeri belešku na gore u hijerarhiji",
|
||||
"multiSelectNote": "višestruki izbor beleški iznad/ispod",
|
||||
"selectAllNotes": "izaberi sve beleške u trenutnom nivou",
|
||||
"selectNote": "izaberi belešku",
|
||||
"copyNotes": "kopiraj aktivnu belešku (ili trenutni izbor) u privremenu memoriju (koristi se za <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">kloniranje</a>)",
|
||||
"cutNotes": "iseci trenutnu belešku (ili trenutni izbor) u privremenu memoriju (koristi se za premeštanje beleški)",
|
||||
"pasteNotes": "nalepi belešku/e kao podbelešku u aktivnoj belešci (koja se ili premešta ili klonira u zavisnosti od toga da li je beleška kopirana ili isečena u privremenu memoriju)",
|
||||
"deleteNotes": "obriši belešku / podstablo",
|
||||
"editingNotes": "Izmena beleški",
|
||||
"editNoteTitle": "u ravni drveta će se prebaciti sa ravni drveta na naslov beleške. Ulaz sa naslova beleške će prebaciti fokus na uređivač teksta. <kbd>Ctrl+.</kbd> će se vratiti sa uređivača na ravan drveta.",
|
||||
"createEditLink": "napravi / izmeni spoljašnji link",
|
||||
"createInternalLink": "napravi unutrašnji link",
|
||||
"followLink": "prati link ispod kursora",
|
||||
"insertDateTime": "ubaci trenutan datum i vreme na poziciju kursora",
|
||||
"jumpToTreePane": "idi na ravan stabla i pomeri se do aktivne beleške",
|
||||
"markdownAutoformat": "Autoformatiranje kao u Markdown-u",
|
||||
"headings": "<code>##</code>, <code>###</code>, <code>####</code> itd. praćeno razmakom za naslove",
|
||||
"bulletList": "<code>*</code> ili <code>-</code> praćeno razmakom za listu sa tačkama",
|
||||
"numberedList": "<code>1.</code> ili <code>1)</code> praćeno razmakom za numerisanu listu",
|
||||
"blockQuote": "započnite liniju sa <code>></code> praćeno sa razmakom za blok citat",
|
||||
"troubleshooting": "Rešavanje problema",
|
||||
"reloadFrontend": "ponovo učitaj Trilium frontend",
|
||||
"showDevTools": "prikaži alate za programere",
|
||||
"showSQLConsole": "prikaži SQL konzolu",
|
||||
"other": "Ostalo",
|
||||
"quickSearch": "fokus na unos za brzu pretragu",
|
||||
"inPageSearch": "pretraga unutar stranice"
|
||||
},
|
||||
"import": {
|
||||
"importIntoNote": "Uvezi u belešku",
|
||||
"chooseImportFile": "Izaberi datoteku za uvoz",
|
||||
"importDescription": "Sadržaj izabranih datoteka će biti uvezen kao podbeleške u",
|
||||
"options": "Opcije",
|
||||
"safeImportTooltip": "Trilium <code>.zip</code> izvozne datoteke mogu da sadrže izvršne skripte koje mogu imati štetno ponašanje. Bezbedan uvoz će deaktivirati automatsko izvršavanje svih uvezenih skripti. Isključite \"Bezbedan uvoz\" samo ako uvezena arhiva treba da sadrži izvršne skripte i ako potpuno verujete sadržaju uvezene datoteke.",
|
||||
"safeImport": "Bezbedan uvoz",
|
||||
"explodeArchivesTooltip": "Ako je ovo označeno onda će Trilium pročitati <code>.zip</code>, <code>.enex</code> i <code>.opml</code> datoteke i napraviti beleške od datoteka unutar tih arhiva. Ako nije označeno, Trilium će same arhive priložiti belešci.",
|
||||
"explodeArchives": "Pročitaj sadržaj <code>.zip</code>, <code>.enex</code> i <code>.opml</code> arhiva.",
|
||||
"shrinkImagesTooltip": "<p>Ako označite ovu opciju, Trilium će pokušati da smanji uvezene slike skaliranjem i optimizacijom što će možda uticati na kvalitet slike. Ako nije označeno, slike će biti uvezene bez promena.</p><p>Ovo se ne primenjuje na <code>.zip</code> uvoze sa metapodacima jer se tada podrazumeva da su te datoteke već optimizovane.</p>",
|
||||
"shrinkImages": "Smanji slike",
|
||||
"textImportedAsText": "Uvezi HTML, Markdown i TXT kao tekstualne beleške ako je nejasno iz metapodataka",
|
||||
"codeImportedAsCode": "Uvezi prepoznate datoteke sa kodom (poput <code>.json</code>) ako beleške sa kodom ako nije jasno iz metapodataka",
|
||||
"replaceUnderscoresWithSpaces": "Zameni podvlake sa razmacima u nazivima uvezenih beleški",
|
||||
"import": "Uvezi",
|
||||
"failed": "Uvoz nije uspeo: {{message}}.",
|
||||
"html_import_tags": {
|
||||
"title": "HTML oznake za uvoz",
|
||||
"description": "Podesite koje HTML oznake trebaju biti sačuvane kada se uvoze beleške. Oznake koje se ne nalaze na listi će biti uklonjene tokom uvoza. Pojedine oznake (poput 'script') se uvek uklanjaju zbog bezbednosti.",
|
||||
"placeholder": "Unesite HTML oznake, po jednu u svaki red",
|
||||
"reset_button": "Vrati na podrazumevanu listu"
|
||||
},
|
||||
"import-status": "Status uvoza",
|
||||
"in-progress": "Uvoz u toku: {{progress}}",
|
||||
"successful": "Uvoz je uspešno završen."
|
||||
},
|
||||
"include_note": {
|
||||
"dialog_title": "Uključi belešku",
|
||||
"label_note": "Beleška",
|
||||
"placeholder_search": "pretraži belešku po njenom imenu",
|
||||
"box_size_prompt": "Veličina kutije priložene beleške:",
|
||||
"box_size_small": "mala (~ 10 redova)",
|
||||
"box_size_medium": "srednja (~ 30 redova)",
|
||||
"box_size_full": "puna (kutija prikazuje ceo tekst)",
|
||||
"button_include": "Uključi belešku"
|
||||
},
|
||||
"info": {
|
||||
"modalTitle": "Informativna poruka",
|
||||
"closeButton": "Zatvori",
|
||||
"okButton": "U redu"
|
||||
},
|
||||
"jump_to_note": {
|
||||
"search_placeholder": "Pretraži belešku po njenom imenu ili unesi > za komande...",
|
||||
"search_button": "Pretraga u punom tekstu <kbd>Ctrl+Enter</kbd>"
|
||||
},
|
||||
"markdown_import": {
|
||||
"dialog_title": "Uvoz za Markdown",
|
||||
"modal_body_text": "Zbog Sandbox-a pretraživača nije moguće direktno učitati privremenu memoriju iz JavaScript-a. Molimo vas da nalepite Markdown za uvoz u tekstualno polje ispod i kliknete na dugme za uvoz",
|
||||
"import_button": "Uvoz",
|
||||
"import_success": "Markdown sadržaj je učitan u dokument."
|
||||
},
|
||||
"move_to": {
|
||||
"dialog_title": "Premesti beleške u ...",
|
||||
"notes_to_move": "Beleške za premeštanje",
|
||||
"target_parent_note": "Ciljana nadbeleška",
|
||||
"search_placeholder": "potraži belešku po njenom imenu",
|
||||
"move_button": "Pređi na izabranu belešku",
|
||||
"error_no_path": "Nema putanje za premeštanje.",
|
||||
"move_success_message": "Izabrane beleške su premeštene u "
|
||||
},
|
||||
"note_type_chooser": {
|
||||
"change_path_prompt": "Promenite gde će se napraviti nova beleška:",
|
||||
"search_placeholder": "pretraži putanju po njenom imenu (podrazumevano ako je prazno)",
|
||||
"modal_title": "Izaberite tip beleške",
|
||||
"modal_body": "Izaberite tip beleške / šablon za novu belešku:",
|
||||
"templates": "Šabloni"
|
||||
},
|
||||
"password_not_set": {
|
||||
"title": "Lozinka nije podešena",
|
||||
"body1": "Zaštićene beleške su enkriptovane sa korisničkom lozinkom, ali lozinka još uvek nije podešena.",
|
||||
"body2": "Za biste mogli da sačuvate beleške, kliknite <a class=\"open-password-options-button\" href=\"javascript:\">ovde</a> da otvorite dijalog sa Opcijama i podesite svoju lozinku."
|
||||
},
|
||||
"prompt": {
|
||||
"title": "Upit",
|
||||
"ok": "U redu <kbd>enter</kbd>",
|
||||
"defaultTitle": "Upit"
|
||||
},
|
||||
"protected_session_password": {
|
||||
"modal_title": "Zaštićena sesija",
|
||||
"help_title": "Pomoć za Zaštićene beleške",
|
||||
"close_label": "Zatvori",
|
||||
"form_label": "Da biste nastavili sa traženom akcijom moraćete započeti zaštićenu sesiju tako što ćete uneti lozinku:",
|
||||
"start_button": "Započni zaštićenu sesiju"
|
||||
},
|
||||
"recent_changes": {
|
||||
"title": "Nedavne promene",
|
||||
"erase_notes_button": "Obriši izabrane beleške odmah",
|
||||
"deleted_notes_message": "Obrisane beleške su uklonjene.",
|
||||
"no_changes_message": "Još uvek nema izmena...",
|
||||
"undelete_link": "poništi brisanje",
|
||||
"confirm_undelete": "Da li želite da poništite brisanje ove beleške i njenih podbeleški?"
|
||||
},
|
||||
"revisions": {
|
||||
"note_revisions": "Revizije beleški",
|
||||
"delete_all_revisions": "Obriši sve revizije ove beleške",
|
||||
"delete_all_button": "Obriši sve revizije",
|
||||
"help_title": "Pomoć za Revizije beleški",
|
||||
"confirm_delete_all": "Da li želite da obrišete sve revizije ove beleške?",
|
||||
"no_revisions": "Još uvek nema revizija za ovu belešku...",
|
||||
"restore_button": "Vrati",
|
||||
"confirm_restore": "Da li želite da vratite ovu reviziju? Ovo će prepisati trenutan naslov i sadržaj beleške sa ovom revizijom.",
|
||||
"delete_button": "Obriši",
|
||||
"confirm_delete": "Da li želite da obrišete ovu reviziju?",
|
||||
"revisions_deleted": "Revizije beleške su obrisane.",
|
||||
"revision_restored": "Revizija beleške je vraćena.",
|
||||
"revision_deleted": "Revizija beleške je obrisana.",
|
||||
"snapshot_interval": "Interval snimanja revizije beleške: {{seconds}}s.",
|
||||
"maximum_revisions": "Ograničenje broja slika revizije beleške: {{number}}.",
|
||||
"settings": "Podešavanja revizija beleški",
|
||||
"download_button": "Preuzmi",
|
||||
"mime": "MIME: ",
|
||||
"file_size": "Veličina datoteke:",
|
||||
"preview": "Pregled:",
|
||||
"preview_not_available": "Pregled nije dostupan za ovaj tip beleške."
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"sort_children_by": "Sortiranje podbeleški po...",
|
||||
"sorting_criteria": "Kriterijum za sortiranje",
|
||||
"title": "naslov",
|
||||
"date_created": "datum kreiranja",
|
||||
"date_modified": "datum izmene",
|
||||
"sorting_direction": "Smer sortiranja",
|
||||
"ascending": "uzlazni",
|
||||
"descending": "silazni",
|
||||
"folders": "Fascikle",
|
||||
"sort_folders_at_top": "sortiraj fascikle na vrh",
|
||||
"natural_sort": "Prirodno sortiranje",
|
||||
"sort_with_respect_to_different_character_sorting": "sortiranje sa poštovanjem različitih pravila sortiranja karaktera i kolacija u različitim jezicima ili regionima.",
|
||||
"natural_sort_language": "Jezik za prirodno sortiranje",
|
||||
"the_language_code_for_natural_sort": "Kod jezika za prirodno sortiranje, npr. \"zh-CN\" za Kineski.",
|
||||
"sort": "Sortiraj"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"upload_attachments_to_note": "Otpremite priloge uz belešku",
|
||||
"choose_files": "Izaberite datoteke",
|
||||
"files_will_be_uploaded": "Datoteke će biti otpremljene kao prilozi u {{noteTitle}}",
|
||||
"options": "Opcije",
|
||||
"shrink_images": "Smanji slike",
|
||||
"upload": "Otpremi",
|
||||
"tooltip": "Ako je označeno, Trilium će pokušati da smanji otpremljene slike skaliranjem i optimizacijom što može uticati na kvalitet slike. Ako nije označeno, slike će biti otpremljene bez izmena."
|
||||
},
|
||||
"attribute_detail": {
|
||||
"attr_detail_title": "Naslov detalja atributa",
|
||||
"close_button_title": "Otkaži izmene i zatvori",
|
||||
"attr_is_owned_by": "Atribut je u vlasništvu",
|
||||
"attr_name_title": "Naziv atributa može biti sastavljen samo od alfanumeričkih znakova, dvotačke i donje crte",
|
||||
"name": "Naziv",
|
||||
"value": "Vrednost",
|
||||
"target_note_title": "Relacija je imenovana veza između izvorne beleške i ciljne beleške.",
|
||||
"target_note": "Ciljna beleška",
|
||||
"promoted_title": "Promovisani atribut je istaknut na belešci.",
|
||||
"promoted": "Promovisan",
|
||||
"promoted_alias_title": "Naziv koji će biti prikazan u korisničkom interfejsu promovisanih atributa.",
|
||||
"promoted_alias": "Pseudonim",
|
||||
"multiplicity_title": "Multiplicitet definiše koliko atributa sa istim nazivom se može napraviti - najviše 1 ili više od 1.",
|
||||
"multiplicity": "Multiplicitet",
|
||||
"single_value": "Jednostruka vrednost",
|
||||
"multi_value": "Višestruka vrednost",
|
||||
"label_type_title": "Tip oznake će pomoći Triliumu da izabere odgovarajući interfejs za unos vrednosti oznake.",
|
||||
"label_type": "Tip",
|
||||
"text": "Tekst",
|
||||
"number": "Broj",
|
||||
"boolean": "Boolean",
|
||||
"date": "Datum",
|
||||
"date_time": "Datum i vreme",
|
||||
"time": "Vreme",
|
||||
"url": "URL",
|
||||
"precision_title": "Broj cifara posle zareza treba biti dostupan u interfejsu za postavljanje vrednosti.",
|
||||
"precision": "Preciznost",
|
||||
"digits": "cifre",
|
||||
"inverse_relation_title": "Opciono podešavanje za definisanje kojoj relaciji je ova suprotna. Primer: Otac - Sin su inverzne relacije jedna drugoj.",
|
||||
"inverse_relation": "Inverzna relacija",
|
||||
"inheritable_title": "Atributi koji mogu da se nasleđuju će biti nasleđeni od strane svih potomaka unutar ovog stabla.",
|
||||
"inheritable": "Nasledno",
|
||||
"save_and_close": "Sačuvaj i zatvori <kbd>Ctrl+Enter</kbd>",
|
||||
"delete": "Obriši",
|
||||
"related_notes_title": "Druge beleške sa ovom oznakom",
|
||||
"more_notes": "Još beleški",
|
||||
"label": "Detalji oznake",
|
||||
"label_definition": "Detalji definicije oznake",
|
||||
"relation": "Detalji relacije",
|
||||
"relation_definition": "Detalji definicije relacije",
|
||||
"disable_versioning": "onemogućava auto-verzionisanje. Korisno za npr. velike, ali nebitne beleške - poput velikih JS biblioteka koje se koriste za skripte",
|
||||
"calendar_root": "obeležava belešku koju treba koristiti kao osnova za dnevne beleške. Samo jedna beleška treba da bude označena kao takva.",
|
||||
"archived": "beleške sa ovom oznakom neće biti podrazumevano vidljive u rezultatima pretrage (kao ni u dijalozima za Idi na, Dodaj link, itd.).",
|
||||
"exclude_from_export": "beleške (sa svojim podstablom) neće biti uključene u bilo koji izvoz beleški",
|
||||
"run": "definiše u kojim događajima se skripta pokreće. Moguće vrednosti su:\n<ul>\n<li>frontendStartup - kada se pokrene Trilium frontend (ili se osveži), ali ne na mobilnom uređaju.</li>\n<li>mobileStartup - kada se pokrene Trilium frontend (ili se osveži), na mobilnom uređaju..</li>\n<li>backendStartup - kada se Trilium backend pokrene</li>\n<li>hourly - pokreće se svaki sat. Može se koristiti dodatna oznaka <code>runAtHour</code> da se označi u kom satu.</li>\n<li>daily - pokreće se jednom dnevno</li>\n</ul>",
|
||||
"run_on_instance": "Definiše u kojoj instanci Trilium-a ovo treba da se pokreće. Podrazumevano podešavanje je na svim instancama.",
|
||||
"run_at_hour": "U kom satu ovo treba da se pokreće. Treba se koristiti zajedno sa <code>#run=hourly</code>. Može biti definisano više puta za više pokretanja u toku dana.",
|
||||
"disable_inclusion": "skripte sa ovom oznakom neće biti uključene u izvršavanju nadskripte.",
|
||||
"sorted": "čuva podbeleške sortirane alfabetski po naslovu",
|
||||
"sort_direction": "Uzlazno (podrazumevano) ili silazno",
|
||||
"sort_folders_first": "Fascikle (beleške sa podbeleškama) treba da budu sortirane na vrhu",
|
||||
"top": "zadrži datu belešku na vrhu njene nadbeleške (primenjuje se samo na sortiranim nadbeleškama)",
|
||||
"hide_promoted_attributes": "Sakrij promovisane atribute na ovoj belešci",
|
||||
"read_only": "uređivač je u režimu samo za čitanje. Radi samo za tekst i beleške sa kodom.",
|
||||
"auto_read_only_disabled": "beleške sa tekstom/kodom se mogu automatski podesiti u režim za čitanje kada su prevelike. Ovo ponašanje možete onemogućiti pojedinačno za belešku dodavanjem ove oznake na belešku",
|
||||
"app_css": "označava CSS beleške koje nisu učitane u Trilium aplikaciju i zbog toga se mogu koristiti za menjanje izgleda Triliuma.",
|
||||
"app_theme": "označava CSS beleške koje su pune Trilium teme i stoga su dostupne u Trilium podešavanjima.",
|
||||
"app_theme_base": "podesite na „sledeće“, „sledeće-svetlo“ ili „sledeće-tamno“ da biste koristili odgovarajuću TriliumNext temu (automatsku, svetlu ili tamnu) kao osnovu za prilagođenu temu, umesto podrazumevane teme.",
|
||||
"css_class": "vrednost ove oznake se zatim dodaje kao CSS klasa čvoru koji predstavlja datu belešku u stablu. Ovo može biti korisno za napredno temiranje. Može se koristiti u šablonima beleški.",
|
||||
"workspace": "označava ovu belešku kao radni prostor što omogućava lako podizanje",
|
||||
"workspace_icon_class": "definiše CSS klasu ikone okvira koja će se koristiti u kartici kada se podigne na ovoj belešci",
|
||||
"workspace_tab_background_color": "CSS boja korišćena u kartici beleške kada se prebaci na ovu belešku",
|
||||
"workspace_calendar_root": "Definiše koren kalendara za svaki radni prostor",
|
||||
"workspace_template": "Ova beleška će se pojaviti u izboru dostupnih šablona prilikom kreiranja nove beleške, ali samo kada se podigne u radni prostor koji sadrži ovaj šablon",
|
||||
"search_home": "nove beleške o pretrazi biće kreirane kao podređeni delovi ove beleške",
|
||||
"workspace_search_home": "nove beleške o pretrazi biće kreirane kao podređeni delovi ove beleške kada se podignu na nekog pretka ove beleške iz radnog prostora",
|
||||
"inbox": "podrazumevana lokacija u prijemnom sandučetu za nove beleške - kada kreirate belešku pomoću dugmeta „nova beleška“ u bočnoj traci, beleške će biti kreirane kao podbeleške u belešci označenoj sa oznakom <code>#inbox</code>.",
|
||||
"workspace_inbox": "podrazumevana lokacija prijemnog sandučeta za nove beleške kada se prebace na nekog pretka ove beleške iz radnog prostora",
|
||||
"sql_console_home": "podrazmevana lokacija beleški SQL konzole",
|
||||
"bookmark_folder": "beleška sa ovom oznakom će se pojaviti u obeleživačima kao fascikla (omogućavajući pristup njenim podređenim fasciklama)",
|
||||
"share_hidden_from_tree": "ova beleška je skrivena u levom navigacionom stablu, ali je i dalje dostupna preko svoje URL adrese",
|
||||
"share_external_link": "beleška će služiti kao veza ka eksternoj veb stranici u stablu deljenja",
|
||||
"share_alias": "definišite alias pomoću kog će beleška biti dostupna na https://your_trilium_host/share/[your_alias]",
|
||||
"share_omit_default_css": "CSS kod podrazumevane stranice za deljenje će biti izostavljen. Koristite ga kada pravite opsežne promene stila.",
|
||||
"share_root": "obeležava belešku koja se prikazuje na /share korenu.",
|
||||
"share_description": "definišite tekst koji će se dodati HTML meta oznaci za opis",
|
||||
"share_raw": "beleška će biti prikazana u svom sirovom (raw) formatu, bez HTML omotača",
|
||||
"share_disallow_robot_indexing": "zabraniće robotsko indeksiranje ove beleške putem zaglavlja <code>X-Robots-Tag: noindex</code>",
|
||||
"share_credentials": "potrebni su kredencijali za pristup ovoj deljenoj belešci. Očekuje se da vrednost bude u formatu „korisničko ime:lozinka“. Ne zaboravite da ovo označite kao nasledno da bi se primenilo na podbeleške/slike.",
|
||||
"share_index": "beleška sa ovom oznakom će izlistati sve korene deljenih beleški",
|
||||
"display_relations": "imena relacija razdvojenih zarezima koja treba da budu prikazana. Sva ostala će biti skrivena.",
|
||||
"hide_relations": "imena relacija razdvojenih zarezima koja treba da budu skrivena. Sva ostala će biti prikazana.",
|
||||
"title_template": "podrazumevani naslov beleški kreiranih kao deca ove beleške. Vrednost se procenjuje kao JavaScript string \n i stoga se može obogatiti dinamičkim sadržajem putem ubrizganih promenljivih <code>now</code> and <code>parentNote</code>. Primeri:\n \n <ul>\n <li><code>${parentNote.getLabelValue('authorName')}'s literary works</code></li>\n <li><code>Log for ${now.format('YYYY-MM-DD HH:mm:ss')}</code></li>\n </ul>\n \n Pogledati <a href=\"https://triliumnext.github.io/Docs/Wiki/default-note-title.html\">wiki sa detaljima</a>, API dokumentacija za <a href=\"https://zadam.github.io/trilium/backend_api/Note.html\">parentNote</a> i <a href=\"https://day.js.org/docs/en/display/format\">now</a> za detalje.",
|
||||
"template": "Ova beleška će biti prikazana u izboru dostupnih šablona prilikom pravljenja nove beleške",
|
||||
"toc": "<code>#toc</code> ili <code>#toc=show</code> će pristiliti Sadržaj (Table of Contents) da bude prikazan, <code>#toc=hide</code> prisiliti njegovo sakrivanje. Ako oznaka ne postoji, ponašanje će biti usklađeno sa globalnim podešavanjem",
|
||||
"color": "definiše boju beleške u stablu beleški, linkovima itd. Koristite bilo koju važeću CSS vrednost boje kao što je „crvena“ ili #a13d5f",
|
||||
"keyboard_shortcut": "Definiše prečicu na tastaturi koja će odmah preći na ovu belešku. Primer: „ctrl+alt+e“. Potrebno je ponovno učitavanje frontenda da bi promena stupila na snagu.",
|
||||
"keep_current_hoisting": "Otvaranje ove veze neće promeniti podizanje čak i ako beleška nije prikazana u trenutno podignutom podstablu.",
|
||||
"execute_button": "Naslov dugmeta koje će izvršiti trenutnu belešku sa kodom",
|
||||
"execute_description": "Duži opis trenutne beleške sa kodom prikazan je zajedno sa dugmetom za izvršavanje",
|
||||
"exclude_from_note_map": "Beleške sa ovom oznakom biće skrivene sa mape beleški",
|
||||
"new_notes_on_top": "Nove beleške će biti napravljene na vrhu matične beleške, a ne na dnu.",
|
||||
"hide_highlight_widget": "Sakrij vidžet sa listom istaknutih",
|
||||
"run_on_note_creation": "izvršava se kada se beleška napravi na serverskoj strani. Koristite ovu relaciju ako želite da pokrenete skriptu za sve beleške napravljene u okviru određenog podstabla. U tom slučaju, kreirajte je na korenu beleške podstabla i učinite je naslednom. Nova beleška napravljena unutar podstabla (bilo koje dubine) pokrenuće skriptu.",
|
||||
"run_on_child_note_creation": "izvršava se kada se napravi nova beleška ispod beleške gde je ova relacija definisana",
|
||||
"run_on_note_title_change": "izvršava se kada se promeni naslov beleške (uključuje i pravljenje beleške)",
|
||||
"run_on_note_content_change": "izvršava se kada se promeni sadržaj beleške (uključuje i pravljenje beleške).",
|
||||
"run_on_note_change": "izvršava se kada se promeni beleška (uključuje i pravljenje beleške). Ne uključuje promene sadržaja",
|
||||
"icon_class": "vrednost ove oznake se dodaje kao CSS klasa ikoni na stablu što može pomoći u vizuelnom razlikovanju beleški u stablu. Primer može biti bx bx-home - ikone su preuzete iz boxicons. Može se koristiti u šablonima beleški.",
|
||||
"page_size": "broj stavki po stranici u listi beleški",
|
||||
"custom_request_handler": "pogledajte <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Prilagođeni obrađivač zahteva</a>",
|
||||
"custom_resource_provider": "pogledajte <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Prilagođeni obrađivač zahteva</a>",
|
||||
"widget": "označava ovu belešku kao prilagođeni vidžet koji će biti dodat u stablo komponenti Trilijuma",
|
||||
"run_on_note_deletion": "izvršava se kada se beleška briše",
|
||||
"run_on_branch_creation": "izvršava se kada se pravi grana. Grana je veza između matične i podređene beleške i pravi se npr. prilikom kloniranja ili premeštanja beleške.",
|
||||
"run_on_branch_change": "izvršava se kada se grana ažurira.",
|
||||
"run_on_branch_deletion": "izvršava se kada se grana briše. Grana je veza između nadređene beleške i podređene beleške i briše se npr. prilikom premeštanja beleške (stara grana/veza se briše).",
|
||||
"run_on_attribute_creation": "izvršava se kada se pravi novi atribut za belešku koji definiše ovu relaciju",
|
||||
"run_on_attribute_change": " izvršava se kada se promeni atribut beleške koja definiše ovu relaciju. Ovo se pokreće i kada se atribut obriše",
|
||||
"relation_template": "atributi beleške će biti nasleđeni čak i bez odnosa roditelj-dete, sadržaj i podstablo beleške će biti dodati instanci beleške ako je prazna. Pogledajte dokumentaciju za detalje.",
|
||||
"inherit": "Atributi beleške će biti nasleđeni čak i bez odnosa roditelj-dete. Pogledajte relaciju šablona za sličan koncept. Pogledajte nasleđivanje atributa u dokumentaciji.",
|
||||
"render_note": "Beleške tipa „render HTML note“ će biti prikazane korišćenjem beleške za kod (HTML ili skripte) i potrebno je pomoću ove relacije ukazati na to koja beleška treba da se prikaže",
|
||||
"widget_relation": "meta ove relacije će biti izvršena i prikazana kao vidžet u bočnoj traci",
|
||||
"share_css": "CSS napomena koja će biti ubrizgana na stranicu za deljenje. CSS napomena mora biti i u deljenom podstablu. Razmotrite i korišćenje „share_hidden_from_tree“ i „share_omit_default_css“.",
|
||||
"share_js": "JavaScript beleška koja će biti ubrizgana na stranicu za deljenje. JS beleška takođe mora biti u deljenom podstablu. Razmislite o korišćenju „share_hidden_from_tree“.",
|
||||
"share_template": "Ugrađena JavaScript beleška koja će se koristiti kao šablon za prikazivanje deljene beleške. U slučaju neuspeha vraća se na podrazumevani šablon. Razmislite o korišćenju „share_hidden_from_tree“.",
|
||||
"share_favicon": "Favicon beleška koju treba postaviti na deljenu stranicu. Obično je potrebno da je podesite da deli koren i učinite je naslednom. Favicon beleška takođe mora biti u deljenom podstablu. Razmislite o korišćenju „share_hidden_from_tree“.",
|
||||
"is_owned_by_note": "je u vlasništvu beleške",
|
||||
"other_notes_with_name": "Ostale beleške sa {{attributeType}} nazivom „{{attributeName}}“",
|
||||
"and_more": "... i još {{count}}.",
|
||||
"print_landscape": "Prilikom izvoza u PDF, menja orijentaciju stranice u pejzažnu umesto uspravne.",
|
||||
"print_page_size": "Prilikom izvoza u PDF, menja veličinu stranice. Podržane vrednosti: <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": "Boja"
|
||||
},
|
||||
"attribute_editor": {
|
||||
"help_text_body1": "Da biste dodali oznaku, samo unesite npr. <code>#rock</code> ili ako želite da dodate i vrednost, onda npr. <code>#year = 2020</code>",
|
||||
"help_text_body2": "Za relaciju, unesite <code>~author = @</code> što bi trebalo da otvori automatsko dovršavanje gde možete potražiti željenu belešku.",
|
||||
"help_text_body3": "Alternativno, možete dodati oznaku i relaciju pomoću dugmeta <code>+</code> sa desne strane.",
|
||||
"save_attributes": "Sačuvaj atribute <enter>",
|
||||
"add_a_new_attribute": "Dodajte novi atribut",
|
||||
"add_new_label": "Dodajte novu oznaku <kbd data-command=\"addNewLabel\"></kbd>",
|
||||
"add_new_relation": "Dodajte novu relaciju <kbd data-command=\"addNewRelation\"></kbd>",
|
||||
"add_new_label_definition": "Dodajte novu definiciju oznake",
|
||||
"add_new_relation_definition": "Dodajte novu definiciju relacije",
|
||||
"placeholder": "Ovde unesite oznake i relacije"
|
||||
},
|
||||
"abstract_bulk_action": {
|
||||
"remove_this_search_action": "Ukloni ovu radnju pretrage"
|
||||
},
|
||||
"execute_script": {
|
||||
"execute_script": "Izvrši skriptu",
|
||||
"help_text": "Možete izvršiti jednostavne skripte na podudarnim beleškama.",
|
||||
"example_1": "Na primer, da biste dodali string u naslov beleške, koristite ovu malu skriptu:",
|
||||
"example_2": "Složeniji primer bi bio brisanje svih atributa podudarnih beleški:"
|
||||
},
|
||||
"add_label": {
|
||||
"add_label": "Dodaj oznaku",
|
||||
"label_name_placeholder": "ime oznake",
|
||||
"label_name_title": "Alfanumerički znakovi, donja crta i dvotačka su dozvoljeni znakovi.",
|
||||
"to_value": "za vrednost",
|
||||
"new_value_placeholder": "nova vrednost",
|
||||
"help_text": "Na svim podudarnim beleškama:",
|
||||
"help_text_item1": "dodajte datu oznaku ako beleška još uvek nema jednu",
|
||||
"help_text_item2": "ili izmenite vrednost postojeće oznake",
|
||||
"help_text_note": "Takođe možete pozvati ovu metodu bez vrednosti, u tom slučaju će oznaka biti dodeljena belešci bez vrednosti."
|
||||
},
|
||||
"delete_label": {
|
||||
"delete_label": "Obriši oznaku",
|
||||
"label_name_placeholder": "ime oznake",
|
||||
"label_name_title": "Alfanumerički znakovi, donja crtica i dvotačka su dozvoljeni znakovi."
|
||||
},
|
||||
"rename_label": {
|
||||
"rename_label": "Preimenuj oznaku",
|
||||
"rename_label_from": "Preimenuj oznaku iz",
|
||||
"old_name_placeholder": "stari naziv",
|
||||
"to": "U",
|
||||
"new_name_placeholder": "novi naziv",
|
||||
"name_title": "Alfanumerički znakovi, donja crtica i dvotačka su dozvoljeni znakovi."
|
||||
},
|
||||
"update_label_value": {
|
||||
"update_label_value": "Ažuriraj vrednost oznake",
|
||||
"label_name_placeholder": "ime oznake",
|
||||
"label_name_title": "Alfanumerički znakovi, donja crtica i dvotačka su dozvoljeni znakovi.",
|
||||
"to_value": "u vrednost",
|
||||
"new_value_placeholder": "nova vrednost",
|
||||
"help_text": "Na svim podudarnim beleškama, promenite vrednost postojeće oznake.",
|
||||
"help_text_note": "Takođe možete pozvati ovu metodu bez vrednosti, u tom slučaju će oznaka biti dodeljena belešci bez vrednosti."
|
||||
},
|
||||
"delete_note": {
|
||||
"delete_note": "Obriši belešku",
|
||||
"delete_matched_notes": "Obriši podudarne beleške",
|
||||
"delete_matched_notes_description": "Ovo će obrisati podudarne beleške.",
|
||||
"undelete_notes_instruction": "Nakon brisanja, moguće ga je poništiti iz dijaloga Nedavne izmene."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,25 +5,32 @@
|
||||
"db_version": "Veritabanı versiyonu:",
|
||||
"title": "Trilium Notes Hakkında",
|
||||
"sync_version": "Eşleştirme versiyonu:",
|
||||
"data_directory": "Veri dizini:"
|
||||
"data_directory": "Veri dizini:",
|
||||
"build_date": "Derleme tarihi:",
|
||||
"build_revision": "Derleme revizyonu:"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"save": "Kaydet",
|
||||
"edit_branch_prefix": "Dalın önekini düzenle",
|
||||
"prefix": "Önek: ",
|
||||
"branch_prefix_saved": "Dal öneki kaydedildi."
|
||||
"branch_prefix_saved": "Dal öneki kaydedildi.",
|
||||
"edit_branch_prefix_multiple": "{{count}} dal için dal ön ekini düzenle",
|
||||
"help_on_tree_prefix": "Ağaç ön eki hakkında yardım",
|
||||
"branch_prefix_saved_multiple": "Dal ön eki, {{count}} dal için kaydedildi.",
|
||||
"affected_branches": "Etkilenen dal sayısı ({{count}}):"
|
||||
},
|
||||
"delete_notes": {
|
||||
"close": "Kapat",
|
||||
"delete_notes_preview": "Not önizlemesini sil",
|
||||
"delete_all_clones_description": "Tüm klonları da sil (son değişikliklerden geri alınabilir)"
|
||||
"delete_all_clones_description": "Tüm klonları da sil (son değişikliklerden geri alınabilir)",
|
||||
"erase_notes_description": "Normal (yazılımsal) silme işlemi, notları yalnızca silinmiş olarak işaretler ve belirli bir süre içinde (son değişiklikler iletişim kutusunda) geri alınabilir. Bu seçeneği işaretlemek, notları hemen siler ve notların geri alınması mümkün olmaz."
|
||||
},
|
||||
"export": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"import": {
|
||||
"chooseImportFile": "İçe aktarım dosyası",
|
||||
"importDescription": "Seçilen dosya(lar) alt not olarak içe aktarılacaktır"
|
||||
"importDescription": "Seçilen dosya(lar)ın içeriği, alt not(lar) olarak şuraya içe aktarılacaktır"
|
||||
},
|
||||
"info": {
|
||||
"closeButton": "Kapat"
|
||||
@@ -34,21 +41,23 @@
|
||||
"toast": {
|
||||
"critical-error": {
|
||||
"title": "Kritik hata",
|
||||
"message": "İstemci uygulamasının başlatılmasını engelleyen kritik bir hata meydana geldi\n\n{{message}}\n\nBu muhtemelen bir betiğin beklenmedik şekilde başarısız olmasından kaynaklanıyor. Uygulamayı güvenli modda başlatarak sorunu ele almayı deneyin."
|
||||
"message": "İstemci uygulamasının başlamasını engelleyen kritik bir hata oluştu:\n\n{{message}}\n\nBunun nedeni büyük olasılıkla bir komut dosyasının beklenmedik bir şekilde başarısız olmasıdır. Uygulamayı güvenli modda başlatmayı ve sorunu gidermeyi deneyin."
|
||||
},
|
||||
"widget-error": {
|
||||
"title": "Bir widget başlatılamadı",
|
||||
"message-unknown": "Bilinmeyen widget aşağıdaki sebeple başlatılamadı\n\n{{message}}"
|
||||
"message-unknown": "Bilinmeyen bir widget aşağıdaki sebeple başlatılamadı\n\n{{message}}",
|
||||
"message-custom": "ID'si \"{{id}}\" ve başlığı \"{{title}}\" olan nottan alınan özel bileşen şu sebepten başlatılamadı:\n\n{{message}}"
|
||||
},
|
||||
"bundle-error": {
|
||||
"title": "Özel bir betik yüklenemedi"
|
||||
"title": "Özel bir betik yüklenemedi",
|
||||
"message": "ID'si \"{{id}}\" ve başlığı \"{{title}}\" olan nottan alınan komut dosyası şunun nedeniyle yürütülemedi:\n\n{{message}}"
|
||||
}
|
||||
},
|
||||
"add_link": {
|
||||
"add_link": "Bağlantı ekle",
|
||||
"help_on_links": "Bağlantılar konusunda yardım",
|
||||
"note": "Not",
|
||||
"search_note": "isimle not ara",
|
||||
"search_note": "notu adına göre ara",
|
||||
"link_title_mirrors": "bağlantı adı notun şu anki adıyla aynı",
|
||||
"link_title_arbitrary": "bağlantı adı isteğe bağlı olarak değiştirilebilir",
|
||||
"link_title": "Bağlantı adı",
|
||||
@@ -85,12 +94,7 @@
|
||||
"cancel": "İptal",
|
||||
"ok": "OK",
|
||||
"are_you_sure_remove_note": "\"{{title}}\" notunu ilişki haritasından kaldırmak istediğinize emin misiniz?. ",
|
||||
"also_delete_note": "Notu da sil"
|
||||
},
|
||||
"ai_llm": {
|
||||
"n_notes_queued": "{{ count }} not dizinleme için sıraya alındı",
|
||||
"n_notes_queued_plural": "{{ count }} not dizinleme için sıraya alındı",
|
||||
"notes_indexed": "{{ count }} not dizinlendi",
|
||||
"notes_indexed_plural": "{{ count }} not dizinlendi"
|
||||
"also_delete_note": "Notu da sil",
|
||||
"if_you_dont_check": "Bunu işaretlemezseniz, not yalnızca ilişki haritasından kaldırılacaktır."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,8 @@
|
||||
"inPageSearch": "頁面內搜尋",
|
||||
"title": "列表",
|
||||
"newTabNoteLink": "在新分頁開啟筆記連結",
|
||||
"newTabWithActivationNoteLink": "在新分頁開啟並切換至筆記連結"
|
||||
"newTabWithActivationNoteLink": "在新分頁開啟並切換至筆記連結",
|
||||
"editShortcuts": "編輯鍵盤快捷鍵"
|
||||
},
|
||||
"import": {
|
||||
"importIntoNote": "匯入至筆記",
|
||||
@@ -732,9 +733,8 @@
|
||||
"zoom_out_title": "縮小"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} 個反連結",
|
||||
"backlinks": "{{count}} 個反連結",
|
||||
"relation": "關聯"
|
||||
"relation": "關聯",
|
||||
"backlink_one": "{{count}} 個反連結"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"insert_child_note": "插入子筆記",
|
||||
@@ -761,7 +761,6 @@
|
||||
"grid": "網格",
|
||||
"list": "列表",
|
||||
"collapse_all_notes": "收摺所有筆記",
|
||||
"expand_all_children": "展開所有子項",
|
||||
"collapse": "收摺",
|
||||
"expand": "展開",
|
||||
"invalid_view_type": "無效的查看類型 '{{type}}'",
|
||||
@@ -771,7 +770,11 @@
|
||||
"geo-map": "地理地圖",
|
||||
"board": "看板",
|
||||
"include_archived_notes": "顯示已封存筆記",
|
||||
"presentation": "簡報"
|
||||
"presentation": "簡報",
|
||||
"expand_tooltip": "展開此集合的直接子級(單層深度)。按下右側箭頭以查看更多選項。",
|
||||
"expand_first_level": "展開直接子級",
|
||||
"expand_nth_level": "展開 {{depth}} 層",
|
||||
"expand_all_levels": "展開所有層級"
|
||||
},
|
||||
"edited_notes": {
|
||||
"no_edited_notes_found": "今天還沒有編輯過的筆記...",
|
||||
@@ -834,7 +837,8 @@
|
||||
"search": "搜尋"
|
||||
},
|
||||
"note_properties": {
|
||||
"this_note_was_originally_taken_from": "筆記來源:"
|
||||
"this_note_was_originally_taken_from": "筆記來源:",
|
||||
"info": "資訊"
|
||||
},
|
||||
"owned_attribute_list": {
|
||||
"owned_attributes": "自有屬性"
|
||||
@@ -1147,7 +1151,10 @@
|
||||
"unit": "字元"
|
||||
},
|
||||
"code_mime_types": {
|
||||
"title": "下拉選單可用的 MIME 文件類型"
|
||||
"title": "下拉選單可用的 MIME 文件類型",
|
||||
"tooltip_syntax_highlighting": "語法高亮顯示",
|
||||
"tooltip_code_block_syntax": "文字筆記中的程式碼區塊",
|
||||
"tooltip_code_note_syntax": "程式碼筆記"
|
||||
},
|
||||
"vim_key_bindings": {
|
||||
"use_vim_keybindings_in_code_notes": "Vim 快捷鍵",
|
||||
@@ -1509,7 +1516,8 @@
|
||||
"refresh-saved-search-results": "重新整理儲存的搜尋結果",
|
||||
"create-child-note": "建立子筆記",
|
||||
"unhoist": "取消聚焦",
|
||||
"toggle-sidebar": "切換側邊欄"
|
||||
"toggle-sidebar": "切換側邊欄",
|
||||
"dropping-not-allowed": "不允許移動筆記至此處。"
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "保持此視窗置頂"
|
||||
@@ -1612,7 +1620,8 @@
|
||||
"duplicate-launcher": "複製啟動器 <kbd data-command=\"duplicateSubtree\">"
|
||||
},
|
||||
"editable-text": {
|
||||
"auto-detect-language": "自動檢測"
|
||||
"auto-detect-language": "自動檢測",
|
||||
"keeps-crashing": "編輯元件持續發生崩潰。請嘗試重新啟動 Trilium。若問題仍存在,請考慮提交錯誤報告。"
|
||||
},
|
||||
"highlighting": {
|
||||
"description": "控制文字筆記程式碼區塊中的語法高亮,程式碼筆記不會受到影響。",
|
||||
@@ -1653,7 +1662,8 @@
|
||||
"copy-link": "複製連結",
|
||||
"paste": "貼上",
|
||||
"paste-as-plain-text": "以純文字貼上",
|
||||
"search_online": "用 {{searchEngine}} 搜尋 \"{{term}}\""
|
||||
"search_online": "用 {{searchEngine}} 搜尋 \"{{term}}\"",
|
||||
"search_in_trilium": "在 Trilium 中搜尋「{{term}}」"
|
||||
},
|
||||
"image_context_menu": {
|
||||
"copy_reference_to_clipboard": "複製引用到剪貼簿",
|
||||
@@ -1787,9 +1797,7 @@
|
||||
"indexing_stopped": "已停止索引",
|
||||
"indexing_in_progress": "正在進行索引…",
|
||||
"last_indexed": "最後索引時間",
|
||||
"n_notes_queued_0": "{{ count }} 條筆記已加入索引隊列",
|
||||
"note_chat": "筆記聊天",
|
||||
"notes_indexed_0": "已索引 {{ count }} 條筆記",
|
||||
"sources": "來源",
|
||||
"start_indexing": "開始索引",
|
||||
"use_advanced_context": "使用進階上下文",
|
||||
@@ -2018,7 +2026,8 @@
|
||||
"new-item-placeholder": "輸入筆記標題…",
|
||||
"add-column-placeholder": "輸入行名…",
|
||||
"edit-note-title": "點擊以編輯筆記標題",
|
||||
"edit-column-title": "點擊以編輯行標題"
|
||||
"edit-column-title": "點擊以編輯行標題",
|
||||
"column-already-exists": "此列已在看板上。"
|
||||
},
|
||||
"command_palette": {
|
||||
"tree-action-name": "樹:{{name}}",
|
||||
@@ -2087,7 +2096,14 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "目前正在檢視唯讀筆記。",
|
||||
"auto-read-only-note": "此筆記以唯讀模式顯示以加快載入速度。",
|
||||
"auto-read-only-learn-more": "了解更多",
|
||||
"edit-note": "編輯筆記"
|
||||
},
|
||||
"note-color": {
|
||||
"clear-color": "清除筆記顏色",
|
||||
"set-color": "設定筆記顏色",
|
||||
"set-custom-color": "設定自訂筆記顏色"
|
||||
},
|
||||
"popup-editor": {
|
||||
"maximize": "切換至完整編輯器"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -839,9 +839,10 @@
|
||||
"zoom_out_title": "Зменшити масштаб"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} Зворотне посилання",
|
||||
"backlinks": "{{count}} Зворотні посилання",
|
||||
"relation": "зв'язок"
|
||||
"relation": "зв'язок",
|
||||
"backlink_one": "{{count}} Зворотне посилання",
|
||||
"backlink_few": "{{count}} Зворотні посилання",
|
||||
"backlink_many": "{{count}} Зворотні посилання"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
"insert_child_note": "Вставити дочірню нотатку",
|
||||
@@ -867,7 +868,6 @@
|
||||
"grid": "Сітка",
|
||||
"list": "Список",
|
||||
"collapse_all_notes": "Згорнути всі нотатки",
|
||||
"expand_all_children": "Розгорнути всі дочірні",
|
||||
"collapse": "Згорнути",
|
||||
"expand": "Розгорнути",
|
||||
"book_properties": "Властивості Колекції",
|
||||
@@ -939,7 +939,8 @@
|
||||
"outside_hoisted": "Цей шлях знаходиться поза межами закріпленої нотатки і вам доведеться відкріпити."
|
||||
},
|
||||
"note_properties": {
|
||||
"this_note_was_originally_taken_from": "Цю нотатку було спочатку взято з:"
|
||||
"this_note_was_originally_taken_from": "Цю нотатку було спочатку взято з:",
|
||||
"info": "Інформація"
|
||||
},
|
||||
"owned_attribute_list": {
|
||||
"owned_attributes": "Власні Атрибути"
|
||||
@@ -1350,13 +1351,7 @@
|
||||
"indexing_stopped": "Індексацію зупинено",
|
||||
"indexing_in_progress": "Триває індексація...",
|
||||
"last_indexed": "Остання індексація",
|
||||
"n_notes_queued_0": "{{ count }} нотатка в черзі на індексацію",
|
||||
"n_notes_queued_1": "{{ count }} нотатки в черзі на індексацію",
|
||||
"n_notes_queued_2": "{{ count }} нотаток в черзі на індексацію",
|
||||
"note_chat": "Нотатка Чат",
|
||||
"notes_indexed_0": "{{ count }} нотатка індексовано",
|
||||
"notes_indexed_1": "{{ count }} нотатки індексовано",
|
||||
"notes_indexed_2": "{{ count }} нотаток індексовано",
|
||||
"sources": "Джерела",
|
||||
"start_indexing": "Почати індексацію",
|
||||
"use_advanced_context": "Використовувати розширений контекст",
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
"add_link": {
|
||||
"add_link": "Thêm liên kết",
|
||||
"button_add_link": "Thêm liên kết",
|
||||
"help_on_links": "Trợ giúp về các liên kết"
|
||||
"help_on_links": "Trợ giúp về các liên kết",
|
||||
"link_title": "Đề mục liên kết"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"other": "Khác"
|
||||
@@ -30,7 +31,9 @@
|
||||
"cancel": "Huỷ"
|
||||
},
|
||||
"export": {
|
||||
"close": "Đóng"
|
||||
"close": "Đóng",
|
||||
"export": "Xuất",
|
||||
"choose_export_type": "Xin hãy chọn cách xuất trước"
|
||||
},
|
||||
"help": {
|
||||
"other": "Khác",
|
||||
@@ -98,5 +101,11 @@
|
||||
},
|
||||
"abstract_search_option": {
|
||||
"remove_this_search_option": "Xoá lựa chọn tìm kiếm này"
|
||||
},
|
||||
"add_relation": {
|
||||
"to": "tới"
|
||||
},
|
||||
"abstract_bulk_action": {
|
||||
"remove_this_search_action": "Xoá hành động tìm kiếm này"
|
||||
}
|
||||
}
|
||||
|
||||
5
apps/client/src/types.d.ts
vendored
5
apps/client/src/types.d.ts
vendored
@@ -64,6 +64,11 @@ declare global {
|
||||
EXCALIDRAW_ASSET_PATH?: string;
|
||||
}
|
||||
|
||||
interface WindowEventMap {
|
||||
"note-ready": Event;
|
||||
"note-load-progress": CustomEvent<{ progress: number }>;
|
||||
}
|
||||
|
||||
interface AutoCompleteConfig {
|
||||
appendTo?: HTMLElement | null;
|
||||
hint?: boolean;
|
||||
|
||||
35
apps/client/src/utils/debouncer.ts
Normal file
35
apps/client/src/utils/debouncer.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
export type DebouncerCallback<T> = (value: T) => void;
|
||||
|
||||
export default class Debouncer<T> {
|
||||
|
||||
private debounceInterval: number;
|
||||
private callback: DebouncerCallback<T>;
|
||||
private lastValue: T | undefined;
|
||||
private timeoutId: any | null = null;
|
||||
|
||||
constructor(debounceInterval: number, onUpdate: DebouncerCallback<T>) {
|
||||
this.debounceInterval = debounceInterval;
|
||||
this.callback = onUpdate;
|
||||
}
|
||||
|
||||
updateValue(value: T) {
|
||||
this.lastValue = value;
|
||||
if (this.timeoutId !== null) {
|
||||
clearTimeout(this.timeoutId);
|
||||
}
|
||||
this.timeoutId = setTimeout(this.reportUpdate.bind(this), this.debounceInterval);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this.timeoutId !== null) {
|
||||
this.reportUpdate();
|
||||
clearTimeout(this.timeoutId);
|
||||
}
|
||||
}
|
||||
|
||||
private reportUpdate() {
|
||||
if (this.lastValue !== undefined) {
|
||||
this.callback(this.lastValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ import froca from "../services/froca";
|
||||
import NoteLink from "./react/NoteLink";
|
||||
import RawHtml from "./react/RawHtml";
|
||||
import { ViewTypeOptions } from "./collections/interface";
|
||||
import attributes from "../services/attributes";
|
||||
import LoadResults from "../services/load_results";
|
||||
|
||||
export interface FloatingButtonContext {
|
||||
parentComponent: Component;
|
||||
@@ -64,7 +66,15 @@ export const MOBILE_FLOATING_BUTTONS: FloatingButtonsList = [
|
||||
RelationMapButtons,
|
||||
ExportImageButtons,
|
||||
Backlinks
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* Floating buttons that should be hidden in popup editor (Quick edit).
|
||||
*/
|
||||
export const POPUP_HIDDEN_FLOATING_BUTTONS: FloatingButtonsList = [
|
||||
InAppHelpButton,
|
||||
ToggleReadOnlyButton
|
||||
];
|
||||
|
||||
function RefreshBackendLogButton({ note, parentComponent, noteContext, isDefaultViewMode }: FloatingButtonContext) {
|
||||
const isEnabled = (note.noteId === "_backendLog" || note.type === "render") && isDefaultViewMode;
|
||||
@@ -102,7 +112,7 @@ function ToggleReadOnlyButton({ note, viewType, isDefaultViewMode }: FloatingBut
|
||||
function EditButton({ note, noteContext }: FloatingButtonContext) {
|
||||
const [animationClass, setAnimationClass] = useState("");
|
||||
const {isReadOnly, enableEditing} = useIsNoteReadOnly(note, noteContext);
|
||||
|
||||
|
||||
const isReadOnlyInfoBarDismissed = false; // TODO
|
||||
|
||||
useEffect(() => {
|
||||
@@ -302,13 +312,18 @@ function Backlinks({ note, isDefaultViewMode }: FloatingButtonContext) {
|
||||
let [ popupOpen, setPopupOpen ] = useState(false);
|
||||
const backlinksContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
function refresh() {
|
||||
if (!isDefaultViewMode) return;
|
||||
|
||||
server.get<BacklinkCountResponse>(`note-map/${note.noteId}/backlink-count`).then(resp => {
|
||||
setBacklinkCount(resp.count);
|
||||
});
|
||||
}, [ note ]);
|
||||
}
|
||||
|
||||
useEffect(() => refresh(), [ note ]);
|
||||
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
||||
if (needsRefresh(note, loadResults)) refresh();
|
||||
});
|
||||
|
||||
// Determine the max height of the container.
|
||||
const { windowHeight } = useWindowSize();
|
||||
@@ -333,18 +348,18 @@ function Backlinks({ note, isDefaultViewMode }: FloatingButtonContext) {
|
||||
|
||||
{popupOpen && (
|
||||
<div ref={backlinksContainerRef} className="backlinks-items dropdown-menu" style={{ display: "block" }}>
|
||||
<BacklinksList noteId={note.noteId} />
|
||||
<BacklinksList note={note} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function BacklinksList({ noteId }: { noteId: string }) {
|
||||
function BacklinksList({ note }: { note: FNote }) {
|
||||
const [ backlinks, setBacklinks ] = useState<BacklinksResponse>([]);
|
||||
|
||||
useEffect(() => {
|
||||
server.get<BacklinksResponse>(`note-map/${noteId}/backlinks`).then(async (backlinks) => {
|
||||
function refresh() {
|
||||
server.get<BacklinksResponse>(`note-map/${note.noteId}/backlinks`).then(async (backlinks) => {
|
||||
// prefetch all
|
||||
const noteIds = backlinks
|
||||
.filter(bl => "noteId" in bl)
|
||||
@@ -352,7 +367,12 @@ function BacklinksList({ noteId }: { noteId: string }) {
|
||||
await froca.getNotes(noteIds);
|
||||
setBacklinks(backlinks);
|
||||
});
|
||||
}, [ noteId ]);
|
||||
}
|
||||
|
||||
useEffect(() => refresh(), [ note ]);
|
||||
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
||||
if (needsRefresh(note, loadResults)) refresh();
|
||||
});
|
||||
|
||||
return backlinks.map(backlink => (
|
||||
<div>
|
||||
@@ -372,3 +392,9 @@ function BacklinksList({ noteId }: { noteId: string }) {
|
||||
</div>
|
||||
));
|
||||
}
|
||||
|
||||
function needsRefresh(note: FNote, loadResults: LoadResults) {
|
||||
return loadResults.getAttributeRows().some(attr =>
|
||||
attr.type === "relation" &&
|
||||
attributes.isAffecting(attr, note));
|
||||
}
|
||||
|
||||
@@ -28,8 +28,9 @@ export default function NoteDetail() {
|
||||
const { note, type, mime, noteContext, parentComponent } = useNoteInfo();
|
||||
const { ntxId, viewScope } = noteContext ?? {};
|
||||
const isFullHeight = checkFullHeight(noteContext, type);
|
||||
const noteTypesToRender = useRef<{ [ key in ExtendedNoteType ]?: (props: TypeWidgetProps) => VNode }>({});
|
||||
const [ noteTypesToRender, setNoteTypesToRender ] = useState<{ [ key in ExtendedNoteType ]?: (props: TypeWidgetProps) => VNode }>({});
|
||||
const [ activeNoteType, setActiveNoteType ] = useState<ExtendedNoteType>();
|
||||
const widgetRequestId = useRef(0);
|
||||
|
||||
const props: TypeWidgetProps = {
|
||||
note: note!,
|
||||
@@ -38,19 +39,28 @@ export default function NoteDetail() {
|
||||
parentComponent,
|
||||
noteContext
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!type) return;
|
||||
const requestId = ++widgetRequestId.current;
|
||||
|
||||
if (!noteTypesToRender.current[type]) {
|
||||
if (!noteTypesToRender[type]) {
|
||||
getCorrespondingWidget(type).then((el) => {
|
||||
if (!el) return;
|
||||
noteTypesToRender.current[type] = el;
|
||||
|
||||
// Ignore stale requests
|
||||
if (requestId !== widgetRequestId.current) return;
|
||||
|
||||
setNoteTypesToRender(prev => ({
|
||||
...prev,
|
||||
[type]: el
|
||||
}));
|
||||
setActiveNoteType(type);
|
||||
});
|
||||
} else {
|
||||
setActiveNoteType(type);
|
||||
}
|
||||
}, [ note, viewScope, type ]);
|
||||
}, [ note, viewScope, type, noteTypesToRender ]);
|
||||
|
||||
// Detect note type changes.
|
||||
useTriliumEvent("entitiesReloaded", async ({ loadResults }) => {
|
||||
@@ -95,9 +105,11 @@ export default function NoteDetail() {
|
||||
});
|
||||
|
||||
// Automatically focus the editor.
|
||||
useTriliumEvent("activeNoteChanged", () => {
|
||||
// Restore focus to the editor when switching tabs, but only if the note tree is not already focused.
|
||||
if (!document.activeElement?.classList.contains("fancytree-title")) {
|
||||
useTriliumEvent("activeNoteChanged", ({ ntxId: eventNtxId }) => {
|
||||
if (eventNtxId != ntxId) return;
|
||||
// Restore focus to the editor when switching tabs,
|
||||
// but only if the note tree and the note panel (e.g., note title or note detail) are not focused.
|
||||
if (!document.activeElement?.classList.contains("fancytree-title") && !parentComponent.$widget[0].closest(".note-split")?.contains(document.activeElement)) {
|
||||
parentComponent.triggerCommand("focusOnDetail", { ntxId });
|
||||
}
|
||||
});
|
||||
@@ -113,11 +125,14 @@ export default function NoteDetail() {
|
||||
useEffect(() => {
|
||||
if (!isElectron()) return;
|
||||
const { ipcRenderer } = dynamicRequire("electron");
|
||||
const listener = () => {
|
||||
toast.closePersistent("printing");
|
||||
const onPrintProgress = (_e: any, { progress, action }: { progress: number, action: "printing" | "exporting_pdf" }) => showToast(action, progress);
|
||||
const onPrintDone = () => toast.closePersistent("printing");
|
||||
ipcRenderer.on("print-progress", onPrintProgress);
|
||||
ipcRenderer.on("print-done", onPrintDone);
|
||||
return () => {
|
||||
ipcRenderer.off("print-progress", onPrintProgress);
|
||||
ipcRenderer.off("print-done", onPrintDone);
|
||||
};
|
||||
ipcRenderer.on("print-done", listener);
|
||||
return () => ipcRenderer.off("print-done", listener);
|
||||
}, []);
|
||||
|
||||
useTriliumEvent("executeInActiveNoteDetailWidget", ({ callback }) => {
|
||||
@@ -139,11 +154,7 @@ export default function NoteDetail() {
|
||||
useTriliumEvent("printActiveNote", () => {
|
||||
if (!noteContext?.isActive() || !note) return;
|
||||
|
||||
toast.showPersistent({
|
||||
icon: "bx bx-loader-circle bx-spin",
|
||||
message: t("note_detail.printing"),
|
||||
id: "printing"
|
||||
});
|
||||
showToast("printing");
|
||||
|
||||
if (isElectron()) {
|
||||
const { ipcRenderer } = dynamicRequire("electron");
|
||||
@@ -162,6 +173,10 @@ export default function NoteDetail() {
|
||||
return;
|
||||
}
|
||||
|
||||
iframe.contentWindow.addEventListener("note-load-progress", (e) => {
|
||||
showToast("printing", e.detail.progress);
|
||||
});
|
||||
|
||||
iframe.contentWindow.addEventListener("note-ready", () => {
|
||||
toast.closePersistent("printing");
|
||||
iframe.contentWindow?.print();
|
||||
@@ -173,11 +188,7 @@ export default function NoteDetail() {
|
||||
|
||||
useTriliumEvent("exportAsPdf", () => {
|
||||
if (!noteContext?.isActive() || !note) return;
|
||||
toast.showPersistent({
|
||||
icon: "bx bx-loader-circle bx-spin",
|
||||
message: t("note_detail.printing_pdf"),
|
||||
id: "printing"
|
||||
});
|
||||
showToast("exporting_pdf");
|
||||
|
||||
const { ipcRenderer } = dynamicRequire("electron");
|
||||
ipcRenderer.send("export-as-pdf", {
|
||||
@@ -193,7 +204,7 @@ export default function NoteDetail() {
|
||||
ref={containerRef}
|
||||
class={`note-detail ${isFullHeight ? "full-height" : ""}`}
|
||||
>
|
||||
{Object.entries(noteTypesToRender.current).map(([ itemType, Element ]) => {
|
||||
{Object.entries(noteTypesToRender).map(([ itemType, Element ]) => {
|
||||
return <NoteDetailWrapper
|
||||
Element={Element}
|
||||
key={itemType}
|
||||
@@ -322,3 +333,12 @@ function checkFullHeight(noteContext: NoteContext | undefined, type: ExtendedNot
|
||||
|| noteContext?.viewScope?.viewMode === "attachments"
|
||||
|| isBackendNote;
|
||||
}
|
||||
|
||||
function showToast(type: "printing" | "exporting_pdf", progress: number = 0) {
|
||||
toast.showPersistent({
|
||||
icon: "bx bx-loader-circle bx-spin",
|
||||
message: type === "printing" ? t("note_detail.printing") : t("note_detail.printing_pdf"),
|
||||
id: "printing",
|
||||
progress
|
||||
});
|
||||
}
|
||||
|
||||
97
apps/client/src/widgets/PromotedAttributes.css
Normal file
97
apps/client/src/widgets/PromotedAttributes.css
Normal file
@@ -0,0 +1,97 @@
|
||||
body.mobile .promoted-attributes-widget {
|
||||
/* https://github.com/zadam/trilium/issues/4468 */
|
||||
flex-shrink: 0.4;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.component.promoted-attributes-widget {
|
||||
contain: none;
|
||||
}
|
||||
|
||||
.promoted-attributes-container {
|
||||
margin: 0 1.5em;
|
||||
overflow: auto;
|
||||
max-height: 400px;
|
||||
flex-wrap: wrap;
|
||||
display: table;
|
||||
}
|
||||
|
||||
.promoted-attribute-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.promoted-attribute-cell > label {
|
||||
user-select: none;
|
||||
font-weight: bold;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.promoted-attribute-cell > * {
|
||||
display: table-cell;
|
||||
padding: 1px 0;
|
||||
}
|
||||
|
||||
.promoted-attribute-cell div.input-group {
|
||||
margin-inline-start: 10px;
|
||||
display: flex;
|
||||
min-height: 40px;
|
||||
}
|
||||
.promoted-attribute-cell strong {
|
||||
word-break:keep-all;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.promoted-attribute-cell input[type="checkbox"] {
|
||||
width: 22px !important;
|
||||
flex-grow: 0;
|
||||
width: unset;
|
||||
}
|
||||
|
||||
/* Restore default apperance */
|
||||
.promoted-attribute-cell input[type="number"],
|
||||
.promoted-attribute-cell input[type="checkbox"] {
|
||||
appearance: auto;
|
||||
}
|
||||
|
||||
.promoted-attribute-cell input[type="color"] {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-top: 2px;
|
||||
appearance: none;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: none;
|
||||
border-radius: 25% !important;
|
||||
}
|
||||
|
||||
.promoted-attribute-cell input[type="color"]::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.promoted-attribute-cell input[type="color"]::-webkit-color-swatch {
|
||||
border: none;
|
||||
border-radius: 25%;
|
||||
}
|
||||
|
||||
.promoted-attribute-label-number input {
|
||||
text-align: right;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.promoted-attribute-label-color input[type="hidden"][value=""] + input[type="color"] {
|
||||
position: relative;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.promoted-attribute-label-color input[type="hidden"][value=""] + input[type="color"]:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
inset-inline-start: 0px;
|
||||
inset-inline-end: 0;
|
||||
height: 2px;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
transform: rotate(45deg);
|
||||
pointer-events: none;
|
||||
}
|
||||
464
apps/client/src/widgets/PromotedAttributes.tsx
Normal file
464
apps/client/src/widgets/PromotedAttributes.tsx
Normal file
@@ -0,0 +1,464 @@
|
||||
import { Dispatch, StateUpdater, useEffect, useRef, useState } from "preact/hooks";
|
||||
import "./PromotedAttributes.css";
|
||||
import { useNoteContext, useNoteLabel, useTriliumEvent, useUniqueName } from "./react/hooks";
|
||||
import { Attribute } from "../services/attribute_parser";
|
||||
import FAttribute from "../entities/fattribute";
|
||||
import clsx from "clsx";
|
||||
import { t } from "../services/i18n";
|
||||
import { DefinitionObject, extractAttributeDefinitionTypeAndName, LabelType } from "../services/promoted_attribute_definition_parser";
|
||||
import server from "../services/server";
|
||||
import FNote from "../entities/fnote";
|
||||
import { ComponentChild, HTMLInputTypeAttribute, InputHTMLAttributes, MouseEventHandler, TargetedEvent, TargetedInputEvent } from "preact";
|
||||
import NoteAutocomplete from "./react/NoteAutocomplete";
|
||||
import ws from "../services/ws";
|
||||
import { UpdateAttributeResponse } from "@triliumnext/commons";
|
||||
import attributes from "../services/attributes";
|
||||
import debounce from "../services/debounce";
|
||||
|
||||
interface Cell {
|
||||
uniqueId: string;
|
||||
definitionAttr: FAttribute;
|
||||
definition: DefinitionObject;
|
||||
valueAttr: Attribute;
|
||||
valueName: string;
|
||||
}
|
||||
|
||||
interface CellProps {
|
||||
note: FNote;
|
||||
componentId: string;
|
||||
cell: Cell,
|
||||
cells: Cell[],
|
||||
shouldFocus: boolean;
|
||||
setCells: Dispatch<StateUpdater<Cell[] | undefined>>;
|
||||
setCellToFocus(cell: Cell): void;
|
||||
}
|
||||
|
||||
type OnChangeEventData = TargetedEvent<HTMLInputElement, Event> | InputEvent | JQuery.TriggeredEvent<HTMLInputElement, undefined, HTMLInputElement, HTMLInputElement>;
|
||||
type OnChangeListener = (e: OnChangeEventData) => Promise<void>;
|
||||
|
||||
export default function PromotedAttributes() {
|
||||
const { note, componentId } = useNoteContext();
|
||||
const [ cells, setCells ] = usePromotedAttributeData(note, componentId);
|
||||
const [ cellToFocus, setCellToFocus ] = useState<Cell>();
|
||||
|
||||
return (
|
||||
<div className="promoted-attributes-widget">
|
||||
{cells && cells.length > 0 && <div className="promoted-attributes-container">
|
||||
{note && cells?.map(cell => <PromotedAttributeCell
|
||||
key={cell.uniqueId}
|
||||
cell={cell}
|
||||
cells={cells} setCells={setCells}
|
||||
shouldFocus={cell === cellToFocus} setCellToFocus={setCellToFocus}
|
||||
componentId={componentId} note={note}
|
||||
/>)}
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the individual cells (instances for promoted attributes including empty attributes). Promoted attributes with "multiple" multiplicity will have
|
||||
* each value represented as a separate cell.
|
||||
*
|
||||
* The cells are returned as a state since they can also be altered internally if needed, for example to add a new empty cell.
|
||||
*/
|
||||
function usePromotedAttributeData(note: FNote | null | undefined, componentId: string): [ Cell[] | undefined, Dispatch<StateUpdater<Cell[] | undefined>> ] {
|
||||
const [ viewType ] = useNoteLabel(note, "viewType");
|
||||
const [ cells, setCells ] = useState<Cell[]>();
|
||||
|
||||
function refresh() {
|
||||
if (!note || viewType === "table") {
|
||||
setCells([]);
|
||||
return;
|
||||
}
|
||||
const promotedDefAttrs = note.getPromotedDefinitionAttributes();
|
||||
const ownedAttributes = note.getOwnedAttributes();
|
||||
// attrs are not resorted if position changes after the initial load
|
||||
// promoted attrs are sorted primarily by order of definitions, but with multi-valued promoted attrs
|
||||
// the order of attributes is important as well
|
||||
ownedAttributes.sort((a, b) => a.position - b.position);
|
||||
|
||||
const cells: Cell[] = [];
|
||||
for (const definitionAttr of promotedDefAttrs) {
|
||||
const [ valueType, valueName ] = extractAttributeDefinitionTypeAndName(definitionAttr.name);
|
||||
|
||||
let valueAttrs = ownedAttributes.filter((el) => el.name === valueName && el.type === valueType) as Attribute[];
|
||||
|
||||
if (valueAttrs.length === 0) {
|
||||
valueAttrs.push({
|
||||
attributeId: "",
|
||||
type: valueType,
|
||||
name: valueName,
|
||||
value: ""
|
||||
});
|
||||
}
|
||||
|
||||
if (definitionAttr.getDefinition().multiplicity === "single") {
|
||||
valueAttrs = valueAttrs.slice(0, 1);
|
||||
}
|
||||
|
||||
for (const [ i, valueAttr ] of valueAttrs.entries()) {
|
||||
const definition = definitionAttr.getDefinition();
|
||||
|
||||
// if not owned, we'll force creation of a new attribute instead of updating the inherited one
|
||||
if (valueAttr.noteId !== note.noteId) {
|
||||
valueAttr.attributeId = "";
|
||||
}
|
||||
|
||||
const uniqueId = `${note.noteId}-${valueAttr.name}-${i}`;
|
||||
cells.push({ definitionAttr, definition, valueAttr, valueName, uniqueId });
|
||||
}
|
||||
}
|
||||
setCells(cells);
|
||||
}
|
||||
|
||||
useEffect(refresh, [ note, viewType ]);
|
||||
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
||||
if (loadResults.getAttributeRows(componentId).find((attr) => attributes.isAffecting(attr, note))) {
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
|
||||
return [ cells, setCells ];
|
||||
}
|
||||
|
||||
function PromotedAttributeCell(props: CellProps) {
|
||||
const { valueName, valueAttr, definition } = props.cell;
|
||||
const inputId = useUniqueName(`value-${valueAttr.name}`);
|
||||
|
||||
useEffect(() => {
|
||||
if (!props.shouldFocus) return;
|
||||
const inputEl = document.getElementById(inputId);
|
||||
if (inputEl) {
|
||||
inputEl.focus();
|
||||
}
|
||||
}, [ props.shouldFocus ]);
|
||||
|
||||
let correspondingInput: ComponentChild;
|
||||
let className: string | undefined;
|
||||
switch (valueAttr.type) {
|
||||
case "label":
|
||||
correspondingInput = <LabelInput inputId={inputId} {...props} />;
|
||||
className = `promoted-attribute-label-${definition.labelType}`;
|
||||
break;
|
||||
case "relation":
|
||||
correspondingInput = <RelationInput inputId={inputId} {...props} />;
|
||||
className = "promoted-attribute-relation";
|
||||
break;
|
||||
default:
|
||||
ws.logError(t(`promoted_attributes.unknown_attribute_type`, { type: valueAttr.type }));
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={clsx("promoted-attribute-cell", className)}>
|
||||
{definition.labelType !== "boolean" && <label for={inputId}>{definition.promotedAlias ?? valueName}</label>}
|
||||
{correspondingInput}
|
||||
<MultiplicityCell {...props} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const LABEL_MAPPINGS: Record<LabelType, HTMLInputTypeAttribute> = {
|
||||
text: "text",
|
||||
number: "number",
|
||||
boolean: "checkbox",
|
||||
date: "date",
|
||||
datetime: "datetime-local",
|
||||
time: "time",
|
||||
color: "hidden", // handled separately.
|
||||
url: "url"
|
||||
};
|
||||
|
||||
function LabelInput({ inputId, ...props }: CellProps & { inputId: string }) {
|
||||
const { valueName, valueAttr, definition, definitionAttr } = props.cell;
|
||||
const onChangeListener = buildPromotedAttributeLabelChangedListener({...props});
|
||||
const extraInputProps: InputHTMLAttributes = {};
|
||||
|
||||
useEffect(() => {
|
||||
if (definition.labelType === "text") {
|
||||
const el = document.getElementById(inputId);
|
||||
if (el) {
|
||||
setupTextLabelAutocomplete(el as HTMLInputElement, valueAttr, onChangeListener);
|
||||
}
|
||||
}
|
||||
}, [ inputId, valueAttr, onChangeListener ]);
|
||||
|
||||
switch (definition.labelType) {
|
||||
case "number": {
|
||||
let step = 1;
|
||||
for (let i = 0; i < (definition.numberPrecision || 0) && i < 10; i++) {
|
||||
step /= 10;
|
||||
}
|
||||
extraInputProps.step = step;
|
||||
break;
|
||||
}
|
||||
case "url": {
|
||||
extraInputProps.placeholder = t("promoted_attributes.url_placeholder");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const inputNode = <input
|
||||
className="form-control promoted-attribute-input"
|
||||
tabIndex={200 + definitionAttr.position}
|
||||
id={inputId}
|
||||
type={LABEL_MAPPINGS[definition.labelType ?? "text"]}
|
||||
value={valueAttr.value}
|
||||
placeholder={t("promoted_attributes.unset-field-placeholder")}
|
||||
data-attribute-id={valueAttr.attributeId}
|
||||
data-attribute-type={valueAttr.type}
|
||||
data-attribute-name={valueAttr.name}
|
||||
onChange={onChangeListener}
|
||||
{...extraInputProps}
|
||||
/>;
|
||||
|
||||
if (definition.labelType === "boolean") {
|
||||
return <>
|
||||
<div>
|
||||
<label className="tn-checkbox">{inputNode}</label>
|
||||
</div>
|
||||
<label for={inputId}>{definition.promotedAlias ?? valueName}</label>
|
||||
</>
|
||||
} else {
|
||||
return (
|
||||
<div className="input-group">
|
||||
{inputNode}
|
||||
{ definition.labelType === "color" && <ColorPicker {...props} onChange={onChangeListener} inputId={inputId} />}
|
||||
{ definition.labelType === "url" && (
|
||||
<InputButton
|
||||
className="open-external-link-button"
|
||||
icon="bx bx-window-open"
|
||||
title={t("promoted_attributes.open_external_link")}
|
||||
onClick={(e) => {
|
||||
const inputEl = document.getElementById(inputId) as HTMLInputElement | null;
|
||||
const url = inputEl?.value;
|
||||
if (url) {
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// We insert a separate input since the color input does not support empty value.
|
||||
// This is a workaround to allow clearing the color input.
|
||||
function ColorPicker({ cell, onChange, inputId }: CellProps & {
|
||||
onChange: (e: TargetedEvent<HTMLInputElement, Event>) => Promise<void>,
|
||||
inputId: string;
|
||||
}) {
|
||||
const defaultColor = "#ffffff";
|
||||
const colorInputRef = useRef<HTMLInputElement>(null);
|
||||
return (
|
||||
<>
|
||||
<input
|
||||
ref={colorInputRef}
|
||||
className="form-control promoted-attribute-input"
|
||||
type="color"
|
||||
value={cell.valueAttr.value || defaultColor}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<InputButton
|
||||
icon="bx bxs-tag-x"
|
||||
title={t("promoted_attributes.remove_color")}
|
||||
onClick={(e) => {
|
||||
// Indicate to the user the color was reset.
|
||||
if (colorInputRef.current) {
|
||||
colorInputRef.current.value = defaultColor;
|
||||
}
|
||||
|
||||
// Trigger the actual attribute change by injecting it into the hidden field.
|
||||
const inputEl = document.getElementById(inputId) as HTMLInputElement | null;
|
||||
if (!inputEl) return;
|
||||
inputEl.value = "";
|
||||
onChange({
|
||||
...e,
|
||||
target: inputEl
|
||||
} as unknown as TargetedInputEvent<HTMLInputElement>);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function RelationInput({ inputId, ...props }: CellProps & { inputId: string }) {
|
||||
return (
|
||||
<NoteAutocomplete
|
||||
id={inputId}
|
||||
noteId={props.cell.valueAttr.value}
|
||||
noteIdChanged={async (value) => {
|
||||
const { note, cell, componentId, setCells } = props;
|
||||
await updateAttribute(note, cell, componentId, value, setCells);
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function MultiplicityCell({ cell, cells, setCells, setCellToFocus, note, componentId }: CellProps) {
|
||||
return (cell.definition.multiplicity === "multi" &&
|
||||
<td className="multiplicity">
|
||||
<PromotedActionButton
|
||||
icon="bx bx-plus"
|
||||
title={t("promoted_attributes.add_new_attribute")}
|
||||
onClick={() => {
|
||||
const index = cells.indexOf(cell);
|
||||
const newCell: Cell = {
|
||||
...cell,
|
||||
valueAttr: {
|
||||
attributeId: "",
|
||||
type: cell.valueAttr.type,
|
||||
name: cell.valueName,
|
||||
value: ""
|
||||
}
|
||||
};
|
||||
setCells([
|
||||
...cells.slice(0, index + 1),
|
||||
newCell,
|
||||
...cells.slice(index + 1)
|
||||
]);
|
||||
setCellToFocus(newCell);
|
||||
}}
|
||||
/>{' '}
|
||||
<PromotedActionButton
|
||||
icon="bx bx-trash"
|
||||
title={t("promoted_attributes.remove_this_attribute")}
|
||||
onClick={async () => {
|
||||
// Remove the attribute from the server if it exists.
|
||||
const { attributeId, type } = cell.valueAttr;
|
||||
const valueName = cell.valueName;
|
||||
if (attributeId) {
|
||||
await server.remove(`notes/${note.noteId}/attributes/${attributeId}`, componentId);
|
||||
}
|
||||
|
||||
const index = cells.indexOf(cell);
|
||||
const isLastOneOfType = cells.filter(c => c.valueAttr.type === type && c.valueAttr.name === valueName).length < 2;
|
||||
const newOnesToInsert: Cell[] = [];
|
||||
if (isLastOneOfType) {
|
||||
newOnesToInsert.push({
|
||||
...cell,
|
||||
valueAttr: {
|
||||
attributeId: "",
|
||||
type: cell.valueAttr.type,
|
||||
name: cell.valueName,
|
||||
value: ""
|
||||
}
|
||||
})
|
||||
}
|
||||
setCells(cells.toSpliced(index, 1, ...newOnesToInsert));
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
)
|
||||
}
|
||||
|
||||
function PromotedActionButton({ icon, title, onClick }: {
|
||||
icon: string,
|
||||
title: string,
|
||||
onClick: MouseEventHandler<HTMLSpanElement>
|
||||
}) {
|
||||
return (
|
||||
<span
|
||||
className={clsx("tn-tool-button pointer", icon)}
|
||||
title={title}
|
||||
onClick={onClick}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function InputButton({ icon, className, title, onClick }: {
|
||||
icon: string;
|
||||
className?: string;
|
||||
title: string;
|
||||
onClick: MouseEventHandler<HTMLSpanElement>;
|
||||
}) {
|
||||
return (
|
||||
<span
|
||||
className={clsx("input-group-text", className, icon)}
|
||||
title={title}
|
||||
onClick={onClick}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function setupTextLabelAutocomplete(el: HTMLInputElement, valueAttr: Attribute, onChangeListener: OnChangeListener) {
|
||||
// no need to await for this, can be done asynchronously
|
||||
const $input = $(el);
|
||||
server.get<string[]>(`attribute-values/${encodeURIComponent(valueAttr.name)}`).then((_attributeValues) => {
|
||||
if (_attributeValues.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const attributeValues = _attributeValues.map((attribute) => ({ value: attribute }));
|
||||
|
||||
$input.autocomplete(
|
||||
{
|
||||
appendTo: document.querySelector("body"),
|
||||
hint: false,
|
||||
autoselect: false,
|
||||
openOnFocus: true,
|
||||
minLength: 0,
|
||||
tabAutocomplete: false
|
||||
},
|
||||
[
|
||||
{
|
||||
displayKey: "value",
|
||||
source: function (term, cb) {
|
||||
term = term.toLowerCase();
|
||||
|
||||
const filtered = attributeValues.filter((attr) => attr.value.toLowerCase().includes(term));
|
||||
|
||||
cb(filtered);
|
||||
}
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
$input.off("autocomplete:selected");
|
||||
$input.on("autocomplete:selected", onChangeListener);
|
||||
});
|
||||
}
|
||||
|
||||
function buildPromotedAttributeLabelChangedListener({ note, cell, componentId, setCells }: CellProps): OnChangeListener {
|
||||
async function onChange(e: OnChangeEventData) {
|
||||
const inputEl = e.target as HTMLInputElement;
|
||||
let value: string;
|
||||
|
||||
if (inputEl.type === "checkbox") {
|
||||
value = inputEl.checked ? "true" : "false";
|
||||
} else {
|
||||
value = inputEl.value;
|
||||
}
|
||||
|
||||
await updateAttribute(note, cell, componentId, value, setCells);
|
||||
}
|
||||
|
||||
return debounce(onChange, 250);
|
||||
}
|
||||
|
||||
async function updateAttribute(note: FNote, cell: Cell, componentId: string, value: string | undefined, setCells: Dispatch<StateUpdater<Cell[] | undefined>>) {
|
||||
const { attributeId } = await server.put<UpdateAttributeResponse>(
|
||||
`notes/${note.noteId}/attribute`,
|
||||
{
|
||||
attributeId: cell.valueAttr.attributeId,
|
||||
type: cell.valueAttr.type,
|
||||
name: cell.valueName,
|
||||
value: value || ""
|
||||
},
|
||||
componentId
|
||||
);
|
||||
setCells(prev =>
|
||||
prev?.map(c =>
|
||||
c.uniqueId === cell.uniqueId
|
||||
? { ...c, valueAttr: {
|
||||
...c.valueAttr,
|
||||
attributeId,
|
||||
value
|
||||
} }
|
||||
: c
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -3,34 +3,33 @@ import { t } from "../services/i18n";
|
||||
import { useIsNoteReadOnly, useNoteContext, useTriliumEvent } from "./react/hooks"
|
||||
import Button from "./react/Button";
|
||||
import InfoBar from "./react/InfoBar";
|
||||
import HelpButton from "./react/HelpButton";
|
||||
|
||||
export default function ReadOnlyNoteInfoBar(props: {}) {
|
||||
const {note, noteContext} = useNoteContext();
|
||||
const {isReadOnly, enableEditing} = useIsNoteReadOnly(note, noteContext);
|
||||
const { note, noteContext } = useNoteContext();
|
||||
const { isReadOnly, enableEditing } = useIsNoteReadOnly(note, noteContext);
|
||||
const isExplicitReadOnly = note?.isLabelTruthy("readOnly");
|
||||
|
||||
return <InfoBar className="read-only-note-info-bar-widget"
|
||||
type={(isExplicitReadOnly ? "subtle" : "prominent")}
|
||||
style={{display: (!isReadOnly) ? "none" : undefined}}>
|
||||
|
||||
<div class="read-only-note-info-bar-widget-content">
|
||||
{(isExplicitReadOnly) ? (
|
||||
<div>{t("read-only-info.read-only-note")}</div>
|
||||
) : (
|
||||
<div>
|
||||
{t("read-only-info.auto-read-only-note")}
|
||||
|
||||
<a class="tn-link"
|
||||
href="https://docs.triliumnotes.org/user-guide/concepts/notes/read-only-notes#automatic-read-only-mode">
|
||||
|
||||
{t("read-only-info.auto-read-only-learn-more")}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button text={t("read-only-info.edit-note")}
|
||||
icon="bx-pencil" onClick={() => enableEditing()} />
|
||||
return (
|
||||
<InfoBar
|
||||
className="read-only-note-info-bar-widget"
|
||||
type={(isExplicitReadOnly ? "subtle" : "prominent")}
|
||||
style={{display: (!isReadOnly) ? "none" : undefined}}
|
||||
>
|
||||
<div class="read-only-note-info-bar-widget-content">
|
||||
{(isExplicitReadOnly) ? (
|
||||
<div>{t("read-only-info.read-only-note")}</div>
|
||||
) : (
|
||||
<div>
|
||||
{t("read-only-info.auto-read-only-note")}
|
||||
{" "}
|
||||
<HelpButton helpPage="CoFPLs3dRlXc" />
|
||||
</div>
|
||||
</InfoBar>
|
||||
)}
|
||||
|
||||
}
|
||||
<Button text={t("read-only-info.edit-note")}
|
||||
icon="bx-pencil" onClick={() => enableEditing()} />
|
||||
</div>
|
||||
</InfoBar>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.promoted-attributes {
|
||||
.user-attributes {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
@@ -6,7 +6,7 @@
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.promoted-attributes .promoted-attribute {
|
||||
.user-attributes .user-attribute {
|
||||
padding: 2px 10px;
|
||||
border-radius: 9999px;
|
||||
white-space: nowrap;
|
||||
@@ -17,15 +17,15 @@
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.promoted-attributes .promoted-attribute:hover {
|
||||
.user-attributes .user-attribute:hover {
|
||||
background-color: var(--chip-bg-hover, rgba(0, 0, 0, 0.12));
|
||||
border-color: var(--chip-border-hover, rgba(0, 0, 0, 0.22));
|
||||
}
|
||||
|
||||
.promoted-attributes .promoted-attribute .name {
|
||||
.user-attributes .user-attribute .name {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.promoted-attributes .promoted-attribute .value {
|
||||
.user-attributes .user-attribute .value {
|
||||
opacity: 0.9;
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
import { useState } from "preact/hooks";
|
||||
import FNote from "../../entities/fnote";
|
||||
import "./PromotedAttributesDisplay.css";
|
||||
import "./UserAttributesList.css";
|
||||
import { useTriliumEvent } from "../react/hooks";
|
||||
import attributes from "../../services/attributes";
|
||||
import { DefinitionObject } from "../../services/promoted_attribute_definition_parser";
|
||||
import { formatDateTime } from "../../utils/formatters";
|
||||
import { ComponentChild, ComponentChildren, CSSProperties } from "preact";
|
||||
import { ComponentChildren, CSSProperties } from "preact";
|
||||
import Icon from "../react/Icon";
|
||||
import NoteLink from "../react/NoteLink";
|
||||
import { getReadableTextColor } from "../../services/css_class_manager";
|
||||
|
||||
interface PromotedAttributesDisplayProps {
|
||||
interface UserAttributesListProps {
|
||||
note: FNote;
|
||||
ignoredAttributes?: string[];
|
||||
}
|
||||
@@ -23,39 +23,39 @@ interface AttributeWithDefinitions {
|
||||
def: DefinitionObject;
|
||||
}
|
||||
|
||||
export default function PromotedAttributesDisplay({ note, ignoredAttributes }: PromotedAttributesDisplayProps) {
|
||||
const promotedDefinitionAttributes = useNoteAttributesWithDefinitions(note, ignoredAttributes);
|
||||
return promotedDefinitionAttributes?.length > 0 && (
|
||||
<div className="promoted-attributes">
|
||||
{promotedDefinitionAttributes?.map(attr => buildPromotedAttribute(attr))}
|
||||
export default function UserAttributesDisplay({ note, ignoredAttributes }: UserAttributesListProps) {
|
||||
const userAttributes = useNoteAttributesWithDefinitions(note, ignoredAttributes);
|
||||
return userAttributes?.length > 0 && (
|
||||
<div className="user-attributes">
|
||||
{userAttributes?.map(attr => buildUserAttribute(attr))}
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
function useNoteAttributesWithDefinitions(note: FNote, attributesToIgnore: string[] = []): AttributeWithDefinitions[] {
|
||||
const [ promotedDefinitionAttributes, setPromotedDefinitionAttributes ] = useState<AttributeWithDefinitions[]>(getAttributesWithDefinitions(note, attributesToIgnore));
|
||||
const [ userAttributes, setUserAttributes ] = useState<AttributeWithDefinitions[]>(getAttributesWithDefinitions(note, attributesToIgnore));
|
||||
|
||||
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
||||
if (loadResults.getAttributeRows().some(attr => attributes.isAffecting(attr, note))) {
|
||||
setPromotedDefinitionAttributes(getAttributesWithDefinitions(note, attributesToIgnore));
|
||||
setUserAttributes(getAttributesWithDefinitions(note, attributesToIgnore));
|
||||
}
|
||||
});
|
||||
|
||||
return promotedDefinitionAttributes;
|
||||
return userAttributes;
|
||||
}
|
||||
|
||||
function PromotedAttribute({ attr, children, style }: { attr: AttributeWithDefinitions, children: ComponentChildren, style?: CSSProperties }) {
|
||||
function UserAttribute({ attr, children, style }: { attr: AttributeWithDefinitions, children: ComponentChildren, style?: CSSProperties }) {
|
||||
const className = `${attr.type === "label" ? "label" + " " + attr.def.labelType : "relation"}`;
|
||||
|
||||
return (
|
||||
<span key={attr.friendlyName} className={`promoted-attribute type-${className}`} style={style}>
|
||||
<span key={attr.friendlyName} className={`user-attribute type-${className}`} style={style}>
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
function buildPromotedAttribute(attr: AttributeWithDefinitions): ComponentChildren {
|
||||
function buildUserAttribute(attr: AttributeWithDefinitions): ComponentChildren {
|
||||
const defaultLabel = <><strong>{attr.friendlyName}:</strong>{" "}</>;
|
||||
let content: ComponentChildren;
|
||||
let style: CSSProperties | undefined;
|
||||
@@ -102,13 +102,13 @@ function buildPromotedAttribute(attr: AttributeWithDefinitions): ComponentChildr
|
||||
content = <>{defaultLabel}<NoteLink notePath={attr.value} showNoteIcon /></>;
|
||||
}
|
||||
|
||||
return <PromotedAttribute attr={attr} style={style}>{content}</PromotedAttribute>
|
||||
return <UserAttribute attr={attr} style={style}>{content}</UserAttribute>
|
||||
}
|
||||
|
||||
function getAttributesWithDefinitions(note: FNote, attributesToIgnore: string[] = []): AttributeWithDefinitions[] {
|
||||
const promotedDefinitionAttributes = note.getAttributeDefinitions();
|
||||
const attributeDefintions = note.getAttributeDefinitions();
|
||||
const result: AttributeWithDefinitions[] = [];
|
||||
for (const attr of promotedDefinitionAttributes) {
|
||||
for (const attr of attributeDefintions) {
|
||||
const def = attr.getDefinition();
|
||||
const [ type, name ] = attr.name.split(":", 2);
|
||||
const friendlyName = def?.promotedAlias || name;
|
||||
@@ -7,17 +7,10 @@ import toastService from "../../services/toast.js";
|
||||
import options from "../../services/options.js";
|
||||
import { Dropdown } from "bootstrap";
|
||||
import type { EventData } from "../../components/app_context.js";
|
||||
import dayjs, { Dayjs } from "dayjs";
|
||||
import isoWeek from "dayjs/plugin/isoWeek.js";
|
||||
import utc from "dayjs/plugin/utc.js";
|
||||
import isSameOrAfter from "dayjs/plugin/isSameOrAfter.js";
|
||||
import { dayjs, type Dayjs } from "@triliumnext/commons";
|
||||
import "../../stylesheets/calendar.css";
|
||||
import type { AttributeRow, OptionDefinitions } from "@triliumnext/commons";
|
||||
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(isSameOrAfter);
|
||||
dayjs.extend(isoWeek);
|
||||
|
||||
const MONTHS = [
|
||||
t("calendar.january"),
|
||||
t("calendar.february"),
|
||||
@@ -110,7 +103,7 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
|
||||
private weekNotes: string[] = [];
|
||||
|
||||
constructor(title: string = "", icon: string = "") {
|
||||
super(title, icon, DROPDOWN_TPL);
|
||||
super(title, icon, DROPDOWN_TPL, "calendar-dropdown-menu");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
@@ -211,8 +204,7 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
|
||||
const $target = $(e.target);
|
||||
|
||||
// Keep dropdown open when clicking on month select button or year selector area
|
||||
if ($target.closest('.btn.dropdown-toggle.select-button').length ||
|
||||
$target.closest('.calendar-year-selector').length) {
|
||||
if ($target.closest('.btn.dropdown-toggle.select-button').length) {
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { t } from "../../services/i18n";
|
||||
import ActionButton from "../react/ActionButton";
|
||||
import { useNoteContext, useTriliumEvent } from "../react/hooks";
|
||||
import { useNoteContext, useTriliumEvents } from "../react/hooks";
|
||||
import appContext from "../../components/app_context";
|
||||
|
||||
export default function ClosePaneButton() {
|
||||
const { noteContext, ntxId, parentComponent } = useNoteContext();
|
||||
const [ isEnabled, setIsEnabled ] = useState(false);
|
||||
const [isEnabled, setIsEnabled] = useState(false);
|
||||
|
||||
function refresh() {
|
||||
setIsEnabled(!!(noteContext && !!noteContext.mainNtxId));
|
||||
const isMainOfSomeContext = appContext.tabManager.noteContexts.some(c => c.mainNtxId === ntxId);
|
||||
setIsEnabled(!!(noteContext && (!!noteContext.mainNtxId || isMainOfSomeContext)));
|
||||
}
|
||||
|
||||
useTriliumEvent("noteContextReorder", refresh);
|
||||
useEffect(refresh, [ ntxId ]);
|
||||
useTriliumEvents(["noteContextRemoved", "noteContextReorder", "newNoteContextCreated"], refresh);
|
||||
useEffect(refresh, [ntxId]);
|
||||
|
||||
return (
|
||||
<ActionButton
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user