Compare commits
1226
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75f9fa5daf | ||
|
|
c9d34feab7 | ||
|
|
bf16d360af | ||
|
|
38d95b4faf | ||
|
|
b06e7d3cf4 | ||
|
|
9e7ea82f94 | ||
|
|
d74fc8a5d5 | ||
|
|
4a43b45a99 | ||
|
|
d6a72fbfc4 | ||
|
|
396f737612 | ||
|
|
2dd8d5a119 | ||
|
|
656c5b61cc | ||
|
|
9fd0f6834a | ||
|
|
58dac27186 | ||
|
|
c8befb6843 | ||
|
|
fafd47fd90 | ||
|
|
e0990910f6 | ||
|
|
599f23c8aa | ||
|
|
a0bd011b80 | ||
|
|
157c27c20d | ||
|
|
4d0407a3b3 | ||
|
|
f73ed1213f | ||
|
|
daabe11d11 | ||
|
|
aaf125cfca | ||
|
|
161fc6bb68 | ||
|
|
1afed9f256 | ||
|
|
e8d6c15fee | ||
|
|
8686b28c28 | ||
|
|
d68251ad4b | ||
|
|
a02b4ae08f | ||
|
|
9ed1dd714b | ||
|
|
95dc6c66d9 | ||
|
|
e91c76c10c | ||
|
|
9deddbbe7c | ||
|
|
2d416d491c | ||
|
|
a19ce0458a | ||
|
|
3fca24e6fd | ||
|
|
6f956e0423 | ||
|
|
bb3ce9fbc6 | ||
|
|
06f2340569 | ||
|
|
510c29cc71 | ||
|
|
807aa04807 | ||
|
|
c84e2e0537 | ||
|
|
910e219c0e | ||
|
|
3a4843fb46 | ||
|
|
1b3744baa2 | ||
|
|
c7d8c8b104 | ||
|
|
a380d39865 | ||
|
|
34d3310eae | ||
|
|
f328eec26d | ||
|
|
7684a54678 | ||
|
|
51f3174609 | ||
|
|
4fcd518b0a | ||
|
|
1e0d7c7e28 | ||
|
|
984da93a7b | ||
|
|
c2c7eda799 | ||
|
|
04b85630b9 | ||
|
|
ae4f3759c2 | ||
|
|
a238dcc5e6 | ||
|
|
57ba84107c | ||
|
|
ca913cafbc | ||
|
|
7032421096 | ||
|
|
06ac959496 | ||
|
|
41c15f8c96 | ||
|
|
5cad3dfbae | ||
|
|
49a20a303a | ||
|
|
90f74427d9 | ||
|
|
ba9dc6ce26 | ||
|
|
3a73994ad4 | ||
|
|
797e1f1f21 | ||
|
|
f1713647cf | ||
|
|
8704d3acb3 | ||
|
|
ce4250281f | ||
|
|
aecbc714c4 | ||
|
|
c20242cf1c | ||
|
|
04ba76aac8 | ||
|
|
d1bc65c266 | ||
|
|
dab284f339 | ||
|
|
df76d9a50a | ||
|
|
abec2e48d4 | ||
|
|
0f2ddb452c | ||
|
|
6fa1acc461 | ||
|
|
9502639447 | ||
|
|
ef4acb1b66 | ||
|
|
8cb72d306b | ||
|
|
1ef8bf4690 | ||
|
|
22779c9dbc | ||
|
|
b52467b6d6 | ||
|
|
d33a0cd589 | ||
|
|
a04cb54d86 | ||
|
|
10785f156f | ||
|
|
4736fb8e32 | ||
|
|
531e7ec73d | ||
|
|
ff946b4f2f | ||
|
|
68f0e68343 | ||
|
|
12a3520563 | ||
|
|
e84426a4f9 | ||
|
|
8b80934f77 | ||
|
|
b6618f81f8 | ||
|
|
8140db32dd | ||
|
|
13db5f4423 | ||
|
|
bd49d6bd89 | ||
|
|
61fd6f1741 | ||
|
|
05d45d9aab | ||
|
|
612eb64a83 | ||
|
|
e0a9e62d84 | ||
|
|
5db5f2251f | ||
|
|
34fd9d29c8 | ||
|
|
c6d8476963 | ||
|
|
1d9fe0c03d | ||
|
|
5b2d36e976 | ||
|
|
547135f7d2 | ||
|
|
15f1416f52 | ||
|
|
b2709aa816 | ||
|
|
9775d4e74d | ||
|
|
f5661af1f4 | ||
|
|
7394fdc162 | ||
|
|
a4f133eb46 | ||
|
|
53007465cd | ||
|
|
e1a748016a | ||
|
|
611bec38b4 | ||
|
|
89c7adfbcd | ||
|
|
4de64d9a43 | ||
|
|
deedf4fc8b | ||
|
|
5a166d2455 | ||
|
|
6808d270a7 | ||
|
|
9dc68611a1 | ||
|
|
e932f38160 | ||
|
|
9014835880 | ||
|
|
00328d04cd | ||
|
|
5b1850e161 | ||
|
|
60727656c9 | ||
|
|
372d021062 | ||
|
|
9c4421bfe0 | ||
|
|
5f85af76cd | ||
|
|
4c2565826f | ||
|
|
ae2d83c8aa | ||
|
|
3b0216ca7e | ||
|
|
1abfb175b5 | ||
|
|
a771695348 | ||
|
|
fe3e4edb04 | ||
|
|
364a4faa75 | ||
|
|
331787fe43 | ||
|
|
9484a7237c | ||
|
|
96063969ae | ||
|
|
cb1c8be870 | ||
|
|
5ea71da181 | ||
|
|
dda469d10e | ||
|
|
9f6e033c53 | ||
|
|
15f44adf3b | ||
|
|
e9483cb242 | ||
|
|
5243d8bedf | ||
|
|
ed731fd7a6 | ||
|
|
07f5422132 | ||
|
|
5aa1764848 | ||
|
|
4973ee555b | ||
|
|
4bfccba4c0 | ||
|
|
5ddad8ebc2 | ||
|
|
b5921897d6 | ||
|
|
53a46b88b8 | ||
|
|
da977ccace | ||
|
|
7b9a2167ad | ||
|
|
fc16771355 | ||
|
|
3ef3fbfd0e | ||
|
|
415a0aaf75 | ||
|
|
5a4a9b570e | ||
|
|
2df60d6387 | ||
|
|
9c176013ab | ||
|
|
036d251e15 | ||
|
|
925060689a | ||
|
|
f0631d734e | ||
|
|
52b299315d | ||
|
|
0195e94aa7 | ||
|
|
75f0b2b82c | ||
|
|
f26f283c1f | ||
|
|
7c387b2aee | ||
|
|
071ecb284e | ||
|
|
03242942c2 | ||
|
|
a476927595 | ||
|
|
ec6e1704be | ||
|
|
d2f189607e | ||
|
|
c13777e68d | ||
|
|
2fb63dcfb1 | ||
|
|
0adb7685f6 | ||
|
|
1cbe99a0d8 | ||
|
|
fa83da6085 | ||
|
|
1392c16f12 | ||
|
|
d6393653e1 | ||
|
|
a75de51198 | ||
|
|
a21869ec9b | ||
|
|
f534e4ee37 | ||
|
|
9add661a5b | ||
|
|
81948a5c29 | ||
|
|
5924154a62 | ||
|
|
354bfe58cd | ||
|
|
c5974a8575 | ||
|
|
c0275addb0 | ||
|
|
c85baf7fd0 | ||
|
|
39e5778bd0 | ||
|
|
a3b77bb37f | ||
|
|
660cf0c1e4 | ||
|
|
11020c4545 | ||
|
|
e93bf02e3a | ||
|
|
a629d7f048 | ||
|
|
683b0f5c48 | ||
|
|
42a80a41ca | ||
|
|
9dcb90a9cf | ||
|
|
1af0aa3f57 | ||
|
|
35c9338220 | ||
|
|
2e8fa0f6c5 | ||
|
|
931aeda17f | ||
|
|
a037d24b0f | ||
|
|
1fa556cd00 | ||
|
|
82e9ad8a20 | ||
|
|
d893765b24 | ||
|
|
1108b0264e | ||
|
|
4f060579ca | ||
|
|
1940c6e1ba | ||
|
|
e754f6c234 | ||
|
|
d19dbbfe7e | ||
|
|
3a735ea0ce | ||
|
|
e319d19a54 | ||
|
|
5f075e4936 | ||
|
|
d6ba3f3adf | ||
|
|
b453e2cf1a | ||
|
|
2d14e5682d | ||
|
|
1f58aebb2b | ||
|
|
6d70ced93a | ||
|
|
accc53c5dd | ||
|
|
e4cb8b71dd | ||
|
|
f6eff090e7 | ||
|
|
61a2c362b9 | ||
|
|
cbcee037a7 | ||
|
|
de2e4a9c7f | ||
|
|
0ba0a5bcd8 | ||
|
|
70cc409402 | ||
|
|
160ca610ae | ||
|
|
2f1aa95f4c | ||
|
|
3eead128a6 | ||
|
|
4c22a73ff3 | ||
|
|
a78f58de92 | ||
|
|
fcda48903b | ||
|
|
3f9805ac56 | ||
|
|
2131fed0bb | ||
|
|
baa5d2fcac | ||
|
|
7cf9b76eb5 | ||
|
|
200648275e | ||
|
|
a7584d62c7 | ||
|
|
74e6caf633 | ||
|
|
f1f531cbfa | ||
|
|
b5a275ad07 | ||
|
|
5051ad91ff | ||
|
|
06d6cb6d19 | ||
|
|
92116273b0 | ||
|
|
6169ff99a2 | ||
|
|
67f77d027a | ||
|
|
39e1a803a1 | ||
|
|
ba159e1a3e | ||
|
|
a60b77121a | ||
|
|
810f0104be | ||
|
|
07489fb405 | ||
|
|
82f0bdfc18 | ||
|
|
66154b30c1 | ||
|
|
bf5d391d53 | ||
|
|
591ce0894e | ||
|
|
1c18563dfb | ||
|
|
b60e781767 | ||
|
|
ca54544b82 | ||
|
|
9c3ff71ce4 | ||
|
|
fd82ec7659 | ||
|
|
23ccaacdee | ||
|
|
39a4297168 | ||
|
|
544111846c | ||
|
|
79bdea0441 | ||
|
|
c056c4e79e | ||
|
|
19828e9070 | ||
|
|
8231c736ca | ||
|
|
85f639b1f0 | ||
|
|
c471b6d66c | ||
|
|
a363efccfb | ||
|
|
871a17a108 | ||
|
|
16a39b364c | ||
|
|
91f79d2be0 | ||
|
|
9932fe5055 | ||
|
|
c296597427 | ||
|
|
97cb5bc12c | ||
|
|
7c596d6bf1 | ||
|
|
b68799e2d1 | ||
|
|
a3d4db9fc1 | ||
|
|
8369330053 | ||
|
|
46a6fee81d | ||
|
|
b2c75130ce | ||
|
|
ef444f2a6f | ||
|
|
36f0871f69 | ||
|
|
5adf27d345 | ||
|
|
5e4c261332 | ||
|
|
6fb04e23ad | ||
|
|
2c850a612d | ||
|
|
e555c4d083 | ||
|
|
cb32cca6aa | ||
|
|
ffb491a61f | ||
|
|
4ecba93a25 | ||
|
|
52ec1d09b8 | ||
|
|
3d2e2e2278 | ||
|
|
f9a9ece320 | ||
|
|
ffc46d6a48 | ||
|
|
ce458642af | ||
|
|
820d3ef426 | ||
|
|
145386b6a7 | ||
|
|
a708cf7f69 | ||
|
|
c70ebb6cce | ||
|
|
a260b6eac4 | ||
|
|
0ab17e1ec8 | ||
|
|
d1a0cd1173 | ||
|
|
3955b973ef | ||
|
|
fcfa508cbc | ||
|
|
a6766ef1c0 | ||
|
|
606b5ac5ab | ||
|
|
9acc463c7f | ||
|
|
c4ddd08b0a | ||
|
|
5c7dd10769 | ||
|
|
3fa86cb441 | ||
|
|
4a74ee0d72 | ||
|
|
8a8759b0d4 | ||
|
|
f259072136 | ||
|
|
3fd74292ef | ||
|
|
f37c4293df | ||
|
|
b9248553be | ||
|
|
475d434e98 | ||
|
|
05d568d1c1 | ||
|
|
28b63bac38 | ||
|
|
fc64719bb8 | ||
|
|
323a74eef3 | ||
|
|
bd4da4f365 | ||
|
|
ae7f7e9bd6 | ||
|
|
b88e63d133 | ||
|
|
a85255df5a | ||
|
|
15c02e9e91 | ||
|
|
ec35392cd1 | ||
|
|
b14b977bca | ||
|
|
54f55d44dc | ||
|
|
568dc1625e | ||
|
|
259b239e16 | ||
|
|
3033387ffc | ||
|
|
d500c29493 | ||
|
|
799d8003eb | ||
|
|
5d34af6ac5 | ||
|
|
dca5b9f197 | ||
|
|
75e075ef8e | ||
|
|
9895976128 | ||
|
|
133367ddb5 | ||
|
|
57964282ee | ||
|
|
51b07fc0c3 | ||
|
|
d8f33641a5 | ||
|
|
a7c7234589 | ||
|
|
f22f1971cb | ||
|
|
28a5806492 | ||
|
|
df98167706 | ||
|
|
06cc40055a | ||
|
|
66b47c08e6 | ||
|
|
40cb8db1fc | ||
|
|
2454a03c2b | ||
|
|
0a59a06121 | ||
|
|
a7191e8efb | ||
|
|
e1f4d791ae | ||
|
|
806fcb6ed2 | ||
|
|
467b0fa988 | ||
|
|
a420d5b203 | ||
|
|
5be3aec7d4 | ||
|
|
5e25a4a00e | ||
|
|
810cf9ab2c | ||
|
|
2a11de7571 | ||
|
|
12543be913 | ||
|
|
cfbf08dbf5 | ||
|
|
3649573ba1 | ||
|
|
0fdc02d5e9 | ||
|
|
0ffe8ef102 | ||
|
|
ce995812d4 | ||
|
|
cd22e1779d | ||
|
|
fbb50d8fb6 | ||
|
|
27172c2a19 | ||
|
|
f453dff438 | ||
|
|
a437a40eee | ||
|
|
70a173a16d | ||
|
|
7724fc74e5 | ||
|
|
6023c08554 | ||
|
|
2de56065af | ||
|
|
f5cf1ca08c | ||
|
|
37a1e67579 | ||
|
|
a372cbbf52 | ||
|
|
a67cf44453 | ||
|
|
a4bead1bde | ||
|
|
0d15024bd2 | ||
|
|
6509d726b3 | ||
|
|
a132f0f41d | ||
|
|
7c2ea3dcfd | ||
|
|
706c6d46da | ||
|
|
04915cc65a | ||
|
|
e2fb8827a7 | ||
|
|
05fda903c6 | ||
|
|
91e1eff763 | ||
|
|
2c4ffcfa7c | ||
|
|
34d63f3557 | ||
|
|
a5613ebb10 | ||
|
|
1a2b45eebd | ||
|
|
65791a58e9 | ||
|
|
6e0f22323b | ||
|
|
4c8c35a25a | ||
|
|
a149f06f58 | ||
|
|
42f97f63d5 | ||
|
|
227652de2e | ||
|
|
dd205e849c | ||
|
|
05d994889d | ||
|
|
4b381049c3 | ||
|
|
33f3479569 | ||
|
|
6b940ed675 | ||
|
|
247be0c11f | ||
|
|
14b0e8875d | ||
|
|
bd51741b01 | ||
|
|
afd60b8a16 | ||
|
|
6e0659af4c | ||
|
|
6de1fa0878 | ||
|
|
61e00f1620 | ||
|
|
c8c75b38c3 | ||
|
|
2bdd0a0e8d | ||
|
|
4131ad5016 | ||
|
|
4f74b3fafe | ||
|
|
177a487ead | ||
|
|
99a4966786 | ||
|
|
db9279a6e5 | ||
|
|
3036f43b75 | ||
|
|
f4560bd7d8 | ||
|
|
97b9ec5cc7 | ||
|
|
cdab3d0eff | ||
|
|
de991041c4 | ||
|
|
776c16cd49 | ||
|
|
d9f8746438 | ||
|
|
20d1c4d242 | ||
|
|
6edac37031 | ||
|
|
cea5a18a7a | ||
|
|
bf615303f1 | ||
|
|
063585f563 | ||
|
|
01304e807a | ||
|
|
d275b3fd08 | ||
|
|
66364354da | ||
|
|
48203aedf9 | ||
|
|
a6ca893ec5 | ||
|
|
d55f1163a2 | ||
|
|
80530012b8 | ||
|
|
d98a6adfb3 | ||
|
|
ae3a35816e | ||
|
|
8ca4be5ac0 | ||
|
|
1c814946d5 | ||
|
|
1db59fc052 | ||
|
|
273a69258a | ||
|
|
3b0dc2195d | ||
|
|
bbb2539ace | ||
|
|
03cfe9bf62 | ||
|
|
e29a4d79ba | ||
|
|
4243bf9ba8 | ||
|
|
7ae9627a79 | ||
|
|
097a1cc799 | ||
|
|
625511d28b | ||
|
|
b6a58ee845 | ||
|
|
a349aed94c | ||
|
|
82b96d1a14 | ||
|
|
b85ddd1a53 | ||
|
|
732f88ff51 | ||
|
|
c08139b812 | ||
|
|
a6a6e73b04 | ||
|
|
9971201004 | ||
|
|
e99b0f8052 | ||
|
|
7a59b2b25d | ||
|
|
521e21072e | ||
|
|
f34845fd7d | ||
|
|
29ccadbd43 | ||
|
|
ffb4b395d0 | ||
|
|
19eba9526a | ||
|
|
09ed76904b | ||
|
|
22932241bd | ||
|
|
afc95d99cb | ||
|
|
5fde3c53b8 | ||
|
|
1135852f25 | ||
|
|
e892f0cb45 | ||
|
|
de56374c4d | ||
|
|
9d92b8cc6d | ||
|
|
d9b3ba0ff2 | ||
|
|
4be6b11c1e | ||
|
|
6794da0738 | ||
|
|
5527170fab | ||
|
|
e732eed98a | ||
|
|
5244642dee | ||
|
|
b329a44fef | ||
|
|
c93632421d | ||
|
|
97e0fd9f43 | ||
|
|
ea536c5537 | ||
|
|
970c906c97 | ||
|
|
fe738da633 | ||
|
|
5e3da71ce4 | ||
|
|
a0cccb299e | ||
|
|
e56974f4b2 | ||
|
|
fd28da2a3b | ||
|
|
257b35e4ae | ||
|
|
4398563b85 | ||
|
|
e23ace1bb0 | ||
|
|
2ef333c66d | ||
|
|
c6ee44010c | ||
|
|
71d770e679 | ||
|
|
cf17b93201 | ||
|
|
08f284ce29 | ||
|
|
4336aeb0ad | ||
|
|
5fd3a45c64 | ||
|
|
77f8bfcf25 | ||
|
|
509a97e532 | ||
|
|
604683efd5 | ||
|
|
c731515b94 | ||
|
|
8d85158f91 | ||
|
|
0736f372dc | ||
|
|
a37210b22e | ||
|
|
ccf81ff7b9 | ||
|
|
a4c1a65f10 | ||
|
|
6bdea219bf | ||
|
|
02a82e1e59 | ||
|
|
d238b0b9f2 | ||
|
|
40026fbf53 | ||
|
|
4193818259 | ||
|
|
78840157ef | ||
|
|
f3d69a29b9 | ||
|
|
1ae6709b26 | ||
|
|
8cc44b3958 | ||
|
|
70e894c268 | ||
|
|
9ff3ab1a2b | ||
|
|
8167f6f232 | ||
|
|
de844e9b23 | ||
|
|
7214b71c29 | ||
|
|
be5df46803 | ||
|
|
25bd61558b | ||
|
|
41961de619 | ||
|
|
1ca3f6ef8a | ||
|
|
f97c94832a | ||
|
|
4ae7786362 | ||
|
|
d3d553ad5a | ||
|
|
4faab006e3 | ||
|
|
80621f598e | ||
|
|
eaf689fe2f | ||
|
|
211e3304f3 | ||
|
|
d4c3b70f15 | ||
|
|
f874941e4d | ||
|
|
437b2ab30a | ||
|
|
dcc2a5afe0 | ||
|
|
078e952f30 | ||
|
|
2d2fe4983c | ||
|
|
29ddc04f7b | ||
|
|
aac2da70cf | ||
|
|
f5cbe0c4fe | ||
|
|
ab28d0a9b3 | ||
|
|
6aaf4ed9d9 | ||
|
|
1b81a1f4a6 | ||
|
|
e838fe30de | ||
|
|
6d9779a497 | ||
|
|
130ece3d2e | ||
|
|
d63a794848 | ||
|
|
ba220abbbf | ||
|
|
3825575f70 | ||
|
|
8d69961130 | ||
|
|
740357d120 | ||
|
|
5638f0f24b | ||
|
|
c8a30e793a | ||
|
|
2264281e4d | ||
|
|
ce38d4ff6b | ||
|
|
74773ade62 | ||
|
|
3faf777db1 | ||
|
|
09e880a90d | ||
|
|
d5785e87e8 | ||
|
|
d4a43bf051 | ||
|
|
76c0432f96 | ||
|
|
4434796aab | ||
|
|
0faa24d5d3 | ||
|
|
6c3b87c9b9 | ||
|
|
2fb31f5944 | ||
|
|
8be42e78de | ||
|
|
6d242ee6c3 | ||
|
|
6c910d2b5f | ||
|
|
0caa56e618 | ||
|
|
e5dc843d6a | ||
|
|
3efd1ee325 | ||
|
|
56a1367322 | ||
|
|
544aba53dc | ||
|
|
d68bbbf9a1 | ||
|
|
489737274a | ||
|
|
4c1fabffc3 | ||
|
|
6a52d03329 | ||
|
|
17f00e6fea | ||
|
|
c67bc33c23 | ||
|
|
bb80dcb4e4 | ||
|
|
8fff3e5389 | ||
|
|
233109d23e | ||
|
|
a6aa78e3b6 | ||
|
|
7536322e53 | ||
|
|
b690e3d149 | ||
|
|
aabf270144 | ||
|
|
61a4f15e53 | ||
|
|
de212322e2 | ||
|
|
cda18fb957 | ||
|
|
011ba5056a | ||
|
|
44c871270b | ||
|
|
9f6b0e1018 | ||
|
|
2d9293732b | ||
|
|
d4a131ad31 | ||
|
|
fa2316fb28 | ||
|
|
6e5d1fb613 | ||
|
|
e45f0f0299 | ||
|
|
62125d0284 | ||
|
|
d5ffede5ea | ||
|
|
212bb33142 | ||
|
|
1d8c80c062 | ||
|
|
e8e11257d2 | ||
|
|
b4236b9a95 | ||
|
|
d2b1404907 | ||
|
|
f11aab6c19 | ||
|
|
1f133dbcd0 | ||
|
|
879576b613 | ||
|
|
7a105a1538 | ||
|
|
7408d7bc95 | ||
|
|
1d9820a7c9 | ||
|
|
c536f7d342 | ||
|
|
6d9dfb5deb | ||
|
|
a3d469a101 | ||
|
|
97ecb0a5d6 | ||
|
|
6f58e9e7bb | ||
|
|
0de19a09ad | ||
|
|
17a56189dc | ||
|
|
520f9801be | ||
|
|
03a6b0311f | ||
|
|
1a922d41df | ||
|
|
050f8f3c81 | ||
|
|
5fc32c7b85 | ||
|
|
964fa69fb4 | ||
|
|
f1a33db800 | ||
|
|
2e3b56c52f | ||
|
|
8f137cf49d | ||
|
|
de170ebdd2 | ||
|
|
e5ae1db49c | ||
|
|
63035196af | ||
|
|
e08d803a33 | ||
|
|
df1a939798 | ||
|
|
848f0db3d1 | ||
|
|
9e2d47eab5 | ||
|
|
88fa103acb | ||
|
|
9849bc055c | ||
|
|
1cf75a7169 | ||
|
|
e297dff0d4 | ||
|
|
aafd7ed21f | ||
|
|
ab2c31aa8a | ||
|
|
47111819e7 | ||
|
|
ddd3f7c196 | ||
|
|
1738f92ce2 | ||
|
|
074695b50c | ||
|
|
95ac136720 | ||
|
|
ecced27853 | ||
|
|
e86aa6b541 | ||
|
|
91f74b44a0 | ||
|
|
35d8e28b8c | ||
|
|
26a6af4ab2 | ||
|
|
20785926e2 | ||
|
|
66d0ee8156 | ||
|
|
6138b060d7 | ||
|
|
308d661d7e | ||
|
|
4e106c2355 | ||
|
|
456160fa29 | ||
|
|
b553ac58d3 | ||
|
|
2c26f43035 | ||
|
|
1b49844012 | ||
|
|
75d45e8907 | ||
|
|
b78bd5d6fd | ||
|
|
5d53344b75 | ||
|
|
7cd58bd534 | ||
|
|
9826bf67c2 | ||
|
|
350fe124d0 | ||
|
|
20aac83e5e | ||
|
|
9d1c822ba1 | ||
|
|
b8d46e2863 | ||
|
|
cd2f2d42a3 | ||
|
|
4bfab89292 | ||
|
|
1d3e8aedcd | ||
|
|
75c41644c6 | ||
|
|
3e221f3b6a | ||
|
|
535abdc481 | ||
|
|
3684126250 | ||
|
|
d3fc34c824 | ||
|
|
8769b5d1b5 | ||
|
|
59bb132dd7 | ||
|
|
8a53fa0aab | ||
|
|
71f42e405d | ||
|
|
64b89dd226 | ||
|
|
27d6b855b8 | ||
|
|
20c4f0dc10 | ||
|
|
7c166d85e1 | ||
|
|
093080894b | ||
|
|
9a2243da9f | ||
|
|
0f5aa9f8d9 | ||
|
|
673f7a82d1 | ||
|
|
87251878a5 | ||
|
|
3a14f363d9 | ||
|
|
84921f04cd | ||
|
|
b16475b8bd | ||
|
|
848e26eec6 | ||
|
|
62e86f9507 | ||
|
|
5b306f365e | ||
|
|
ce8950da43 | ||
|
|
0e1c7cd8ed | ||
|
|
fba6dd750d | ||
|
|
e73b6bc39e | ||
|
|
fa3cbbee67 | ||
|
|
029e52eb5f | ||
|
|
13914507e8 | ||
|
|
533f0213e3 | ||
|
|
95d6dac055 | ||
|
|
2001d7f02a | ||
|
|
bae5b70023 | ||
|
|
8341d343d3 | ||
|
|
278a56e580 | ||
|
|
6ab44ccf0c | ||
|
|
918898d6fe | ||
|
|
566e5dea57 | ||
|
|
5d1bfa18b1 | ||
|
|
800540ce7f | ||
|
|
74ee74365e | ||
|
|
75f6235111 | ||
|
|
fe415cbd77 | ||
|
|
dc69c0d3e5 | ||
|
|
40b3f39249 | ||
|
|
a9acc55735 | ||
|
|
9c07612274 | ||
|
|
3e87d88825 | ||
|
|
e280c0c5ca | ||
|
|
64f750a097 | ||
|
|
48bc18017e | ||
|
|
035fa3be3f | ||
|
|
f62723c274 | ||
|
|
aca59019c1 | ||
|
|
2186ea9a90 | ||
|
|
928f6e7009 | ||
|
|
64ed5fca3b | ||
|
|
4c7fc79843 | ||
|
|
153d77359f | ||
|
|
c8a2fb92d2 | ||
|
|
dcc252b371 | ||
|
|
846aadd7c6 | ||
|
|
3c604db234 | ||
|
|
cb3efb1c1d | ||
|
|
1423db35eb | ||
|
|
cb2a7a88fc | ||
|
|
e530111283 | ||
|
|
332c4a1f98 | ||
|
|
8541b95d8b | ||
|
|
e4584e3f04 | ||
|
|
168ec9092a | ||
|
|
914b6c757d | ||
|
|
48d10d701e | ||
|
|
6479e94c4f | ||
|
|
fb3a9f1f29 | ||
|
|
e9d7df8862 | ||
|
|
123de56f38 | ||
|
|
8627132d6a | ||
|
|
3ef9c4c626 | ||
|
|
aec03294d6 | ||
|
|
2e6e1f4060 | ||
|
|
07f1103784 | ||
|
|
ffc8f133c9 | ||
|
|
507f2a4c7c | ||
|
|
1c9e9b9367 | ||
|
|
4d81775f8d | ||
|
|
cf042931b6 | ||
|
|
f6a931599a | ||
|
|
1b17049e94 | ||
|
|
81c039d645 | ||
|
|
e245edc843 | ||
|
|
8494ed8ac3 | ||
|
|
371f14d2e4 | ||
|
|
1109fbfcc3 | ||
|
|
ff88f242fa | ||
|
|
bd3dd69ae1 | ||
|
|
06780c2805 | ||
|
|
e44e227af6 | ||
|
|
4ca06a9218 | ||
|
|
9e29761581 | ||
|
|
110c389d85 | ||
|
|
d856ed89ff | ||
|
|
fa747515e9 | ||
|
|
b15c9d7655 | ||
|
|
15c3ee4af2 | ||
|
|
748248deab | ||
|
|
70671ac672 | ||
|
|
f70f670ed3 | ||
|
|
4b685716d5 | ||
|
|
252c812125 | ||
|
|
69a437a1a8 | ||
|
|
b8b36b6248 | ||
|
|
28e24cb9d6 | ||
|
|
2a0609fdb8 | ||
|
|
b3233cab71 | ||
|
|
405a3eda60 | ||
|
|
49acfc496b | ||
|
|
a1932fa3dc | ||
|
|
87a8706299 | ||
|
|
92ec46147b | ||
|
|
2bda7566b4 | ||
|
|
43488cb57b | ||
|
|
137fbb638b | ||
|
|
76ed8d58fa | ||
|
|
8204139df8 | ||
|
|
7926684930 | ||
|
|
73946a4ede | ||
|
|
aa88115d45 | ||
|
|
496c08b075 | ||
|
|
2388d1782f | ||
|
|
e0e1c59d41 | ||
|
|
f2cb6ce972 | ||
|
|
ed3535e9c9 | ||
|
|
62f1830197 | ||
|
|
2fb62fe8be | ||
|
|
3243cbf039 | ||
|
|
eb171ecb21 | ||
|
|
43b8941f7a | ||
|
|
0b16839d7f | ||
|
|
164ba46259 | ||
|
|
b174f7a023 | ||
|
|
c9ec9f14de | ||
|
|
597c071c3d | ||
|
|
91d05434ca | ||
|
|
5b0aba99bb | ||
|
|
87c7d1a5f4 | ||
|
|
d841d69bd4 | ||
|
|
512bf1d013 | ||
|
|
adbd58a949 | ||
|
|
a0959d2730 | ||
|
|
f455722bed | ||
|
|
735d23c9eb | ||
|
|
0fd6a23c78 | ||
|
|
fd73d8d67e | ||
|
|
347366e8d7 | ||
|
|
eb8d4abcbe | ||
|
|
86acccebb0 | ||
|
|
8f184f76fa | ||
|
|
1daabfa3e0 | ||
|
|
90b49106f0 | ||
|
|
1a5638426c | ||
|
|
8d4da009af | ||
|
|
89571d57bd | ||
|
|
5d4e06074a | ||
|
|
98522cf6e4 | ||
|
|
7cdb751606 | ||
|
|
4ffc90f963 | ||
|
|
8da6572074 | ||
|
|
ee64aad670 | ||
|
|
92cee2321f | ||
|
|
7f969b1252 | ||
|
|
a02e2e1fa1 | ||
|
|
d690e1b37a | ||
|
|
3300c2302c | ||
|
|
685470cf23 | ||
|
|
c545a959ac | ||
|
|
a7832ef40f | ||
|
|
3e941999d5 | ||
|
|
bebdfc259c | ||
|
|
d31a920eb7 | ||
|
|
ec87821bcd | ||
|
|
21df0e32c4 | ||
|
|
afaa235c75 | ||
|
|
8d97e7136f | ||
|
|
89ac422929 | ||
|
|
d8d55f032e | ||
|
|
c83d694c7a | ||
|
|
ea55650d45 | ||
|
|
ec1aee60a1 | ||
|
|
3a7a0918d3 | ||
|
|
8bf90714da | ||
|
|
d8b59925b0 | ||
|
|
d37fd6bea0 | ||
|
|
0f6263d82e | ||
|
|
e7c70945e6 | ||
|
|
095a936891 | ||
|
|
c49ce91fac | ||
|
|
dd52727055 | ||
|
|
b48068c63c | ||
|
|
c39d04e8a5 | ||
|
|
0eff8e4bc8 | ||
|
|
178551a467 | ||
|
|
720739e50a | ||
|
|
46d1537d8f | ||
|
|
63b2bb55a1 | ||
|
|
06c210f5c8 | ||
|
|
a545c42047 | ||
|
|
da4b4de292 | ||
|
|
fd936e5bf3 | ||
|
|
dc11340faf | ||
|
|
06d921d855 | ||
|
|
91b602341b | ||
|
|
ad853ca342 | ||
|
|
14fa3481b0 | ||
|
|
2b6fee0455 | ||
|
|
a48e6f82d1 | ||
|
|
1020904fe0 | ||
|
|
6aaced0c04 | ||
|
|
3646c0d0a3 | ||
|
|
44c8574f1b | ||
|
|
ea1ff65db7 | ||
|
|
85b7147927 | ||
|
|
6b54c342aa | ||
|
|
60720b04db | ||
|
|
323a593159 | ||
|
|
baef94f14a | ||
|
|
59b3cfee66 | ||
|
|
cbc85ca98f | ||
|
|
425c8cd1d3 | ||
|
|
1d7949ded6 | ||
|
|
2507170816 | ||
|
|
2c83425b42 | ||
|
|
1da281de8a | ||
|
|
98baab4d03 | ||
|
|
441069aa76 | ||
|
|
8c5bf55b51 | ||
|
|
b6d6955b39 | ||
|
|
0d68b1a73e | ||
|
|
15b7c241ff | ||
|
|
de9c62617b | ||
|
|
a0e05115a3 | ||
|
|
aaf58272f1 | ||
|
|
5ebaf5663d | ||
|
|
7dc3e6a08b | ||
|
|
5a5f817e59 | ||
|
|
b650320a34 | ||
|
|
424fd8e4d3 | ||
|
|
cfbf80fdfe | ||
|
|
9b8ced2803 | ||
|
|
630a1d42b8 | ||
|
|
b69ff6ca8a | ||
|
|
1a23b6178b | ||
|
|
de536d7305 | ||
|
|
6dcd33bbc5 | ||
|
|
c6df78eb81 | ||
|
|
d1babe27ec | ||
|
|
7596f62ca5 | ||
|
|
139e57f1eb | ||
|
|
e87d85b088 | ||
|
|
91b79b703c | ||
|
|
bdefa4a967 | ||
|
|
b82efb6e3c | ||
|
|
a50e109043 | ||
|
|
8b5db12e1d | ||
|
|
f1f8163bb7 | ||
|
|
c0fac90b52 | ||
|
|
15717ddca0 | ||
|
|
a7ce9aaca5 | ||
|
|
d8df8e1033 | ||
|
|
440a35e491 | ||
|
|
dbbc6ed0bb | ||
|
|
86fbb383fd | ||
|
|
1c07a74bef | ||
|
|
2df93c2ceb | ||
|
|
6ca40afac0 | ||
|
|
36a8f044ae | ||
|
|
276e5453f1 | ||
|
|
0f81986684 | ||
|
|
bc54e536af | ||
|
|
acb57b3e9c | ||
|
|
de0e30de57 | ||
|
|
b8b942cdae | ||
|
|
0146a077e8 | ||
|
|
a0fcf515cd | ||
|
|
1719ad81a4 | ||
|
|
51a9a7b75d | ||
|
|
e91b0500c5 | ||
|
|
2a17361a90 | ||
|
|
1eca3a8603 | ||
|
|
86f37863a7 | ||
|
|
643cd87706 | ||
|
|
98c85441f8 | ||
|
|
1345f996da | ||
|
|
ff48f08241 | ||
|
|
b5f438aa0c | ||
|
|
a2266adb3f | ||
|
|
c518f373df | ||
|
|
f4636fdca2 | ||
|
|
4108d7827a | ||
|
|
5ccd40f530 | ||
|
|
8798340d48 | ||
|
|
e8d2959350 | ||
|
|
f1d838de6b | ||
|
|
ec92a4cd34 | ||
|
|
b3b9788d37 | ||
|
|
67739e8e39 | ||
|
|
be3ed7d380 | ||
|
|
9b4d58cfe8 | ||
|
|
fb6a8d999c | ||
|
|
b2f6a06a1f | ||
|
|
f7da32702f | ||
|
|
219d2246fa | ||
|
|
979b5eb89c | ||
|
|
a58811b1bf | ||
|
|
be0e18d4b0 | ||
|
|
fea6f0ce81 | ||
|
|
5859ac7a58 | ||
|
|
566833da6e | ||
|
|
d174602cc0 | ||
|
|
46bc04f69f | ||
|
|
bb8fd5500d | ||
|
|
d0df105dda | ||
|
|
a061fb5421 | ||
|
|
fd17e5a4c0 | ||
|
|
cd8bc7a7a1 | ||
|
|
e22a586a41 | ||
|
|
5017c5a5f1 | ||
|
|
03cbab5267 | ||
|
|
2c22837d9f | ||
|
|
4d64df37f5 | ||
|
|
b224f1d78d | ||
|
|
52e018989d | ||
|
|
eb14193b23 | ||
|
|
001c2c88cd | ||
|
|
98ab83976e | ||
|
|
9cd5bf2992 | ||
|
|
e876712af5 | ||
|
|
9fc8d66601 | ||
|
|
12d86493bf | ||
|
|
c97cba69b9 | ||
|
|
63ed7a734b | ||
|
|
0e338ef453 | ||
|
|
d914b38f9f | ||
|
|
3ee00a4824 | ||
|
|
5198c69f6b | ||
|
|
40704c4549 | ||
|
|
83df59e5f1 | ||
|
|
246602e275 | ||
|
|
d3449609da | ||
|
|
a872058704 | ||
|
|
3033376028 | ||
|
|
0bda636113 | ||
|
|
28092d6862 | ||
|
|
cecafb726c | ||
|
|
8418c21096 | ||
|
|
c4ace1972a | ||
|
|
862df1d2df | ||
|
|
487c1a58d6 | ||
|
|
c06c3d48d2 | ||
|
|
7d3ad5a639 | ||
|
|
03b2d02742 | ||
|
|
103ce44ba9 | ||
|
|
22219af133 | ||
|
|
7d7377ab15 | ||
|
|
af8fc53704 | ||
|
|
e80a5d82a4 | ||
|
|
2b73e745da | ||
|
|
e61a1080f7 | ||
|
|
464f336790 | ||
|
|
1dc6e085cc | ||
|
|
8594ff0c23 | ||
|
|
e58963410e | ||
|
|
1e0d118930 | ||
|
|
723e6dd13f | ||
|
|
e941af0905 | ||
|
|
24c8e29691 | ||
|
|
8911bdf966 | ||
|
|
0834759e1a | ||
|
|
bb8c0d264e | ||
|
|
c7da8c5fd3 | ||
|
|
30789ff6e2 | ||
|
|
e6ece10716 | ||
|
|
ea7a255006 | ||
|
|
98df1f5312 | ||
|
|
2bf08787d8 | ||
|
|
b8f7e4211c | ||
|
|
b581d0c44f | ||
|
|
0b613812f7 | ||
|
|
4d066a762f | ||
|
|
8a30a65818 | ||
|
|
01703aff43 | ||
|
|
9d62931af9 | ||
|
|
e53d8fd4fa | ||
|
|
0dbde32ed4 | ||
|
|
d506fdb68c | ||
|
|
9c10186158 | ||
|
|
3eed51dbac | ||
|
|
1c1855f0c3 | ||
|
|
e0a277fa45 | ||
|
|
3d6c7171d2 | ||
|
|
0fee90e4df | ||
|
|
0cced44491 | ||
|
|
f21f758591 | ||
|
|
51e9527d53 | ||
|
|
268cd131dc | ||
|
|
26997ad5c3 | ||
|
|
ce1786f128 | ||
|
|
888057f64a | ||
|
|
3c6c4d9601 | ||
|
|
5e8bcf8faf | ||
|
|
0d6f2f93bf | ||
|
|
937b00cfcc | ||
|
|
0d4432720c | ||
|
|
0ec49643ee | ||
|
|
0d80ea4f4c | ||
|
|
d2b26124e4 | ||
|
|
343116ea24 | ||
|
|
10dc699b21 | ||
|
|
015c5f07bc | ||
|
|
a0b6a3bed6 | ||
|
|
9de5950f4d | ||
|
|
26488b793a | ||
|
|
5a6c2dfcd5 | ||
|
|
7e891ecb79 | ||
|
|
12840f2428 | ||
|
|
0b160a6741 | ||
|
|
dff34a8ae2 | ||
|
|
8f780ad89e | ||
|
|
4624ef393d | ||
|
|
2ce8a890e2 | ||
|
|
90e0e9000e | ||
|
|
a6bb1c156d | ||
|
|
31db8161b5 | ||
|
|
c0d1448080 | ||
|
|
4e4f4e60b6 | ||
|
|
dcc83271af | ||
|
|
a38458c9be | ||
|
|
7934f65ae8 | ||
|
|
aea0cec061 | ||
|
|
7ac56b1a0c | ||
|
|
f5ed0b700f | ||
|
|
1ff3b83766 | ||
|
|
40eca1727e | ||
|
|
9505e68ef7 | ||
|
|
5847806a16 | ||
|
|
e427ea44aa | ||
|
|
8df8bf33a4 | ||
|
|
29d2b942e8 | ||
|
|
992cdb992a | ||
|
|
db0dc71319 | ||
|
|
2c871d1339 | ||
|
|
9673922ca1 | ||
|
|
d311870b61 | ||
|
|
8dd1ff593a | ||
|
|
0f64a769c2 | ||
|
|
a8d150db5c | ||
|
|
d7e6367ff3 | ||
|
|
7b84d8c3d5 | ||
|
|
e025df0824 | ||
|
|
c3392d5386 | ||
|
|
2c09e6a7c0 | ||
|
|
2a0740e135 | ||
|
|
ac65357c8a | ||
|
|
07c255f7f8 | ||
|
|
198b3c9f1b | ||
|
|
f5c567eb90 | ||
|
|
8ca09f6384 | ||
|
|
386dfe42d0 | ||
|
|
7445f43b1b | ||
|
|
5b77e78662 | ||
|
|
4b0b8d4de2 | ||
|
|
b7de47b6fb | ||
|
|
3434907f52 | ||
|
|
099adb3853 | ||
|
|
dd9b1c047c | ||
|
|
6084bb15cf | ||
|
|
42b568952e | ||
|
|
d3bac307bb | ||
|
|
7e488b0fa3 | ||
|
|
7d7a6191ce | ||
|
|
5c644b31ca | ||
|
|
7b4398dfee | ||
|
|
663418e943 | ||
|
|
969bec248a | ||
|
|
8f487d7d4e | ||
|
|
89ebce79b2 | ||
|
|
34ce510fbd | ||
|
|
39f29399e7 | ||
|
|
8cd4cc7d0d | ||
|
|
608ab8f4ad | ||
|
|
e95643f198 | ||
|
|
3b1712345b | ||
|
|
6effe47bcc | ||
|
|
205080a210 | ||
|
|
bc998988c2 | ||
|
|
80b470cfd3 | ||
|
|
3df2b4b7f8 | ||
|
|
6141b60294 | ||
|
|
e1cfb0cab6 | ||
|
|
9b9782ce94 | ||
|
|
5d9eb25e38 | ||
|
|
f4a518ce6b | ||
|
|
3656e6ef54 | ||
|
|
a545d7d8b1 | ||
|
|
3127f7a31b | ||
|
|
f561de200d | ||
|
|
d85a063db8 | ||
|
|
d6bf935ceb | ||
|
|
0d6ff822e7 | ||
|
|
1c0cc8e91c | ||
|
|
fb38573b7e | ||
|
|
8a2f45ec23 | ||
|
|
fee2eb9251 | ||
|
|
24035c4ae8 | ||
|
|
aa8215df34 | ||
|
|
eb78e3d640 | ||
|
|
f8201cd2bc | ||
|
|
f37b3ecd26 | ||
|
|
e6dba59ae6 | ||
|
|
a7bc6b4f36 | ||
|
|
cacc5ac803 | ||
|
|
46dc0f144b | ||
|
|
3cc5275592 | ||
|
|
a3955a1ba8 | ||
|
|
89dfaf1d5d | ||
|
|
fc6246c5cb | ||
|
|
ce8a0cab2a | ||
|
|
b36b6c78a2 | ||
|
|
5232dc6485 | ||
|
|
b1d9fc6c9a | ||
|
|
80ded84f7a | ||
|
|
8394535725 | ||
|
|
adf780d25b | ||
|
|
749ae3deb3 | ||
|
|
2d7760e67c | ||
|
|
c915926e0f | ||
|
|
25203934e6 | ||
|
|
4b1b2878ea | ||
|
|
b11d5514b9 |
No files matched your search
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
# Windows has stack overflows when calling from Tauri, so we increase compiler size
|
# Windows has stack overflows when calling from Tauri, so we increase compiler size
|
||||||
[target.'cfg(windows)']
|
[target.'cfg(windows)']
|
||||||
rustflags = ["-C", "link-args=/STACK:16777220"]
|
rustflags = ["-C", "link-args=/STACK:16777220"]
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
|
# Editor configuration, see http://editorconfig.org
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
|
charset = utf-8
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
max_line_length = 100
|
max_line_length = 100
|
||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.rs]
|
||||||
|
indent_size = 4
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
name: 🎮 Modrinth App bug
|
||||||
|
description: Report an issue in the Modrinth Launcher.
|
||||||
|
labels: [bug, app]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Please confirm the following.
|
||||||
|
options:
|
||||||
|
- label: I checked the [existing issues](https://github.com/modrinth/code/issues) for duplicate problems
|
||||||
|
required: true
|
||||||
|
- label: I have tried resolving the issue using the [support portal](https://support.modrinth.com)
|
||||||
|
required: true
|
||||||
|
- label: I have ensured my Modrinth App installation is up to date
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: What version of the Modrinth App are you using?
|
||||||
|
description: Find this in ⚙️ Settings (bottom right) -> About -> App version.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: oses
|
||||||
|
attributes:
|
||||||
|
label: What operating systems are you seeing the problem on?
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- Windows
|
||||||
|
- MacOS
|
||||||
|
- Linux
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Describe the bug
|
||||||
|
description: A clear and concise description of what the bug is. Include screenshots if applicable.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
description: Steps to reproduce the behavior.
|
||||||
|
placeholder: |
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '...'
|
||||||
|
3. Scroll down to '...'
|
||||||
|
4. See error
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Expected behavior
|
||||||
|
description: A clear and concise description of what you expected to happen.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional context
|
||||||
|
description: Add any other context about the problem here.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
name: 🌐 Website bug (modrinth.com)
|
||||||
|
description: Report an issue on the Modrinth website.
|
||||||
|
labels: [bug, web]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Please confirm the following.
|
||||||
|
options:
|
||||||
|
- label: I checked the [existing issues](https://github.com/modrinth/code/issues) for duplicate problems
|
||||||
|
required: true
|
||||||
|
- label: I have tried resolving the issue using the [support portal](https://support.modrinth.com)
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: browsers
|
||||||
|
attributes:
|
||||||
|
label: What browsers are you seeing the problem on?
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- Chrome (including Arc, Brave, Opera, Vivaldi)
|
||||||
|
- Microsoft Edge
|
||||||
|
- Firefox
|
||||||
|
- Safari
|
||||||
|
- Other (please specify)
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Describe the bug
|
||||||
|
description: A clear and concise description of what the bug is. Include screenshots if applicable.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
description: Steps to reproduce the behavior.
|
||||||
|
placeholder: |
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '...'
|
||||||
|
3. Scroll down to '...'
|
||||||
|
4. See error
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Expected behavior
|
||||||
|
description: A clear and concise description of what you expected to happen.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional context
|
||||||
|
description: Add any other context about the problem here.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
@@ -1,11 +1,19 @@
|
|||||||
name: Bug report
|
name: 🛠️ API issue (api.modrinth.com)
|
||||||
description: Create a report to help us improve Modrinth
|
description: Report an issue regarding the Modrinth API.
|
||||||
labels: [bug]
|
labels: [bug, api]
|
||||||
body:
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Please confirm the following.
|
||||||
|
options:
|
||||||
|
- label: I checked the [existing issues](https://github.com/modrinth/code/issues) for duplicate problems
|
||||||
|
required: true
|
||||||
|
- label: I have tried resolving the issue using the [support portal](https://support.modrinth.com)
|
||||||
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Describe the bug
|
label: Describe the bug
|
||||||
description: A clear and concise description of what the bug is.
|
description: A clear and concise description of what the bug is. Include screenshots if applicable.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: textarea
|
||||||
@@ -25,13 +33,9 @@ body:
|
|||||||
description: A clear and concise description of what you expected to happen.
|
description: A clear and concise description of what you expected to happen.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: System information
|
|
||||||
description: Add any information about what OS you are on (like Windows or Mac), and what version of the app you are using.
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Additional context
|
label: Additional context
|
||||||
description: Add any other context about the problem here. This might include logs, screenshots, etc. The more the merrier!
|
description: Add any other context about the problem here.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
name: 💡 Feature Request
|
||||||
|
description: Suggest an idea
|
||||||
|
labels: [enhancement]
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Please confirm the following.
|
||||||
|
options:
|
||||||
|
- label: I checked the [existing issues](https://github.com/modrinth/code/issues) for duplicate feature requests
|
||||||
|
required: true
|
||||||
|
- label: I checked the [existing discussions](https://github.com/orgs/modrinth/discussions) for duplicate feature requests
|
||||||
|
required: true
|
||||||
|
- label: I have checked that this feature request is not on our [roadmap](https://roadmap.modrinth.com)
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: projects
|
||||||
|
attributes:
|
||||||
|
label: What parts of Modrinth is your feature request related too?
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- App
|
||||||
|
- Website
|
||||||
|
- API
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Is your suggested feature related to a problem? Please describe.
|
||||||
|
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Describe the solution you'd like
|
||||||
|
description: A clear and concise description of what you want to happen.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Describe alternatives you've considered
|
||||||
|
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional context
|
||||||
|
description: Add any other context or screenshots about the suggested enhancement here.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
@@ -1,16 +1,14 @@
|
|||||||
blank_issues_enabled: true
|
blank_issues_enabled: true
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Discord
|
- name: 🫶 Support Portal
|
||||||
about: Ask questions on our Discord Server.
|
about: Get support using through our portal.
|
||||||
|
url: https://support.modrinth.com
|
||||||
|
- name: 💬 Chat
|
||||||
|
about: Join our Discord server to chat about Modrinth.
|
||||||
url: https://discord.modrinth.com
|
url: https://discord.modrinth.com
|
||||||
- name: Roadmap
|
- name: 🛣️ Roadmap
|
||||||
about: View our Roadmap. Please do not open issues for items on our roadmap.
|
about: View our Roadmap. Please do not open issues for items on our roadmap.
|
||||||
url: https://roadmap.modrinth.com
|
url: https://roadmap.modrinth.com
|
||||||
- name: Discussions (Feature requests)
|
- name: 📚 Documentation
|
||||||
about: |
|
about: Useful documentation about Modrinth's API
|
||||||
Please use Issues for reporting bugs and suggesting enhancements to existing features.
|
url: https://docs.modrinth.com
|
||||||
Suggestions for new features should be made as a Discussion.
|
|
||||||
url: https://github.com/orgs/modrinth/discussions/categories/feature-requests
|
|
||||||
- name: Documentation
|
|
||||||
about: Useful documentation about Modrinth, its API, and how you can contribute.
|
|
||||||
url: https://docs.modrinth.com
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
name: Enhancement
|
|
||||||
description: Suggest an enhancement for an existing Modrinth feature
|
|
||||||
labels: [enhancement]
|
|
||||||
body:
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Is your suggested enhancement related to a problem? Please describe.
|
|
||||||
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Describe the solution you'd like
|
|
||||||
description: A clear and concise description of what you want to happen.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Describe alternatives you've considered
|
|
||||||
description: A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional context
|
|
||||||
description: Add any other context or screenshots about the suggested enhancement here.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 417 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
@@ -0,0 +1,131 @@
|
|||||||
|
name: 'Modrinth App build'
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
paths:
|
||||||
|
- .github/workflows/app-release.yml
|
||||||
|
- 'apps/app/**'
|
||||||
|
- 'apps/app-frontend/**'
|
||||||
|
- 'packages/app-lib/**'
|
||||||
|
- 'packages/app-macros/**'
|
||||||
|
- 'packages/assets/**'
|
||||||
|
- 'packages/ui/**'
|
||||||
|
- 'packages/utils/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
platform: [macos-latest, windows-latest, ubuntu-22.04]
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.platform }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Rust setup (mac)
|
||||||
|
if: startsWith(matrix.platform, 'macos')
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
components: rustfmt, clippy
|
||||||
|
targets: aarch64-apple-darwin, x86_64-apple-darwin
|
||||||
|
|
||||||
|
- name: Rust setup
|
||||||
|
if: "!startsWith(matrix.platform, 'macos')"
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- name: Setup rust cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: target/**
|
||||||
|
key: ${{ runner.os }}-rust-target-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-rust-target-
|
||||||
|
|
||||||
|
- name: Use Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Install pnpm via corepack
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
corepack enable
|
||||||
|
corepack prepare --activate
|
||||||
|
|
||||||
|
- name: Get pnpm store directory
|
||||||
|
id: pnpm-cache
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Setup pnpm cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||||
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pnpm-store-
|
||||||
|
|
||||||
|
- name: install dependencies (ubuntu only)
|
||||||
|
if: startsWith(matrix.platform, 'ubuntu')
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libssl-dev sqlite3
|
||||||
|
|
||||||
|
- name: Install frontend dependencies
|
||||||
|
run: pnpm install
|
||||||
|
|
||||||
|
- name: build app (macos)
|
||||||
|
run: pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config "tauri-release.conf.json"
|
||||||
|
if: startsWith(matrix.platform, 'macos')
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
|
||||||
|
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||||
|
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||||
|
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||||
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||||
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||||
|
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||||
|
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
|
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
|
|
||||||
|
- name: build app
|
||||||
|
run: pnpm --filter=@modrinth/app run tauri build --config "tauri-release.conf.json"
|
||||||
|
id: build_os
|
||||||
|
if: "!startsWith(matrix.platform, 'macos')"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
|
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
|
|
||||||
|
- name: upload ${{ matrix.platform }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.platform }}
|
||||||
|
path: |
|
||||||
|
target/*/release/bundle/*/*.dmg
|
||||||
|
target/*/release/bundle/*/*.app.tar.gz
|
||||||
|
target/*/release/bundle/*/*.app.tar.gz.sig
|
||||||
|
target/release/bundle/*/*.dmg
|
||||||
|
target/release/bundle/*/*.app.tar.gz
|
||||||
|
target/release/bundle/*/*.app.tar.gz.sig
|
||||||
|
|
||||||
|
target/release/bundle/*/*.AppImage
|
||||||
|
target/release/bundle/*/*.AppImage.tar.gz
|
||||||
|
target/release/bundle/*/*.AppImage.tar.gz.sig
|
||||||
|
target/release/bundle/*/*.deb
|
||||||
|
target/release/bundle/*/*.rpm
|
||||||
|
|
||||||
|
target/release/bundle/*/*.msi
|
||||||
|
target/release/bundle/*/*.msi.zip
|
||||||
|
target/release/bundle/*/*.msi.zip.sig
|
||||||
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize]
|
||||||
|
merge_group:
|
||||||
|
types: [ checks_requested ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build, Test, and Lint
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- name: Cache turbo build setup
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: .turbo
|
||||||
|
key: ${{ runner.os }}-turbo-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-turbo-
|
||||||
|
|
||||||
|
- name: Install build dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
|
||||||
|
|
||||||
|
- name: Setup Node.JS environment
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Install pnpm via corepack
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
corepack enable
|
||||||
|
corepack prepare --activate
|
||||||
|
|
||||||
|
- name: Get pnpm store directory
|
||||||
|
id: pnpm-cache
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
name: Setup pnpm cache
|
||||||
|
with:
|
||||||
|
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||||
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pnpm-store-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: pnpm build
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: pnpm lint
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: pnpm test
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
name: Deploy frontend
|
||||||
|
|
||||||
|
on: push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
wait:
|
||||||
|
if: github.repository_owner == 'modrinth'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
deployments: write
|
||||||
|
steps:
|
||||||
|
- name: Cloudflare Pages deployment
|
||||||
|
uses: WalshyDev/cf-pages-await@v1
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CF_API_TOKEN }}
|
||||||
|
accountId: '9ddae624c98677d68d93df6e524a6061'
|
||||||
|
project: 'frontend'
|
||||||
|
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
commitHash: ${{ steps.push-changes.outputs.commit-hash }}
|
||||||
|
- name: Purge cache
|
||||||
|
if: github.ref == 'refs/heads/prod'
|
||||||
|
run: |
|
||||||
|
curl -X POST \
|
||||||
|
-H "Authorization: Bearer ${{ secrets.CF_API_TOKEN }}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
--data '{"hosts": ["modrinth.com", "www.modrinth.com"]}' \
|
||||||
|
https://api.cloudflare.com/client/v4/zones/e39df17b9c4ef44cbce2646346ee6d33/purge_cache
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
name: GUI Build + Lint
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [master]
|
|
||||||
pull_request:
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: ./theseus_gui
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Use Node.js
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18.x
|
|
||||||
- name: Install pnpm via corepack
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
corepack enable
|
|
||||||
corepack prepare --activate
|
|
||||||
- name: Get pnpm store directory
|
|
||||||
id: pnpm-cache
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
|
||||||
- name: Setup pnpm cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
|
||||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-pnpm-store-
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install
|
|
||||||
- name: Run Lint
|
|
||||||
run: pnpm lint
|
|
||||||
- name: Build
|
|
||||||
run: pnpm build
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
name: 'Tauri GUI Build'
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
jobs:
|
|
||||||
test-tauri:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
platform: [macos-latest, windows-latest, ubuntu-20.04, ubuntu-22.04]
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: ./theseus_gui
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Rust setup (mac)
|
|
||||||
if: startsWith(matrix.platform, 'macos')
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
with:
|
|
||||||
components: rustfmt, clippy
|
|
||||||
targets: aarch64-apple-darwin
|
|
||||||
|
|
||||||
- name: Rust setup
|
|
||||||
if: "!startsWith(matrix.platform, 'macos')"
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
with:
|
|
||||||
components: rustfmt, clippy
|
|
||||||
|
|
||||||
- name: Rust cache
|
|
||||||
uses: swatinem/rust-cache@v2
|
|
||||||
with:
|
|
||||||
workspaces: './src-tauri -> target'
|
|
||||||
|
|
||||||
- name: Use Node.js
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18.x
|
|
||||||
- name: Install pnpm via corepack
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
corepack enable
|
|
||||||
corepack prepare --activate
|
|
||||||
- name: Get pnpm store directory
|
|
||||||
id: pnpm-cache
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
|
||||||
- name: Setup pnpm cache
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
|
||||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-pnpm-store-
|
|
||||||
|
|
||||||
- name: install dependencies (ubuntu only)
|
|
||||||
if: startsWith(matrix.platform, 'ubuntu')
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf libselinux1
|
|
||||||
|
|
||||||
- name: Install frontend dependencies
|
|
||||||
run: pnpm install
|
|
||||||
|
|
||||||
- name: build app (macos)
|
|
||||||
uses: tauri-apps/tauri-action@v0
|
|
||||||
id: build_os_mac
|
|
||||||
if: startsWith(matrix.platform, 'macos')
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
|
|
||||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
|
||||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
||||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
|
||||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
||||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
||||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
|
||||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
|
||||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
|
||||||
with:
|
|
||||||
args: --target universal-apple-darwin
|
|
||||||
|
|
||||||
- name: build app
|
|
||||||
uses: tauri-apps/tauri-action@v0
|
|
||||||
id: build_os
|
|
||||||
if: "!startsWith(matrix.platform, 'macos')"
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
|
||||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
|
||||||
|
|
||||||
- name: upload ${{ matrix.platform }}
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
if: startsWith(matrix.platform, 'macos')
|
|
||||||
with:
|
|
||||||
name: ${{ matrix.platform }}
|
|
||||||
path: "${{ join(fromJSON(steps.build_os_mac.outputs.artifactPaths), '\n') }}"
|
|
||||||
|
|
||||||
- name: upload ${{ matrix.platform }}
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
if: "!startsWith(matrix.platform, 'macos')"
|
|
||||||
with:
|
|
||||||
name: ${{ matrix.platform }}
|
|
||||||
path: "${{ join(fromJSON(steps.build_os.outputs.artifactPaths), '\n') }}"
|
|
||||||
+47
-105
@@ -1,115 +1,57 @@
|
|||||||
/target
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
node_modules/
|
|
||||||
.svelte-kit/
|
|
||||||
theseus_gui/build/
|
|
||||||
theseus_gui/generated/
|
|
||||||
WixTools
|
|
||||||
.direnv/
|
|
||||||
.DS_Store
|
|
||||||
.pnpm-debug.log
|
|
||||||
|
|
||||||
minecraft
|
# compiled output
|
||||||
config
|
dist
|
||||||
|
tmp
|
||||||
|
/out-tsc
|
||||||
|
|
||||||
[#]*[#]
|
# dependencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
# TEMPORARY: ignore my test instance and metadata
|
# IDEs and editors
|
||||||
theseus_cli/foo
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
### Intellij+all ###
|
# IDE - VSCode
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
|
||||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
|
||||||
|
|
||||||
# User-specific stuff
|
|
||||||
.idea/**/workspace.xml
|
|
||||||
.idea/**/tasks.xml
|
|
||||||
.idea/**/usage.statistics.xml
|
|
||||||
.idea/**/dictionaries
|
|
||||||
.idea/**/shelf
|
|
||||||
|
|
||||||
# AWS User-specific
|
|
||||||
.idea/**/aws.xml
|
|
||||||
|
|
||||||
# Generated files
|
|
||||||
.idea/**/contentModel.xml
|
|
||||||
|
|
||||||
# Sensitive or high-churn files
|
|
||||||
.idea/**/dataSources/
|
|
||||||
.idea/**/dataSources.ids
|
|
||||||
.idea/**/dataSources.local.xml
|
|
||||||
.idea/**/sqlDataSources.xml
|
|
||||||
.idea/**/dynamic.xml
|
|
||||||
.idea/**/uiDesigner.xml
|
|
||||||
.idea/**/dbnavigator.xml
|
|
||||||
|
|
||||||
# Gradle
|
|
||||||
.idea/**/gradle.xml
|
|
||||||
.idea/**/libraries
|
|
||||||
|
|
||||||
# Gradle and Maven with auto-import
|
|
||||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
|
||||||
# since they will be recreated, and may cause churn. Uncomment if using
|
|
||||||
# auto-import.
|
|
||||||
# .idea/artifacts
|
|
||||||
# .idea/compiler.xml
|
|
||||||
# .idea/jarRepositories.xml
|
|
||||||
# .idea/modules.xml
|
|
||||||
# .idea/*.iml
|
|
||||||
# .idea/modules
|
|
||||||
# *.iml
|
|
||||||
# *.ipr
|
|
||||||
|
|
||||||
# CMake
|
|
||||||
cmake-build-*/
|
|
||||||
|
|
||||||
# Mongo Explorer plugin
|
|
||||||
.idea/**/mongoSettings.xml
|
|
||||||
|
|
||||||
# File-based project format
|
|
||||||
*.iws
|
|
||||||
|
|
||||||
# IntelliJ
|
|
||||||
out/
|
|
||||||
|
|
||||||
# mpeltonen/sbt-idea plugin
|
|
||||||
.idea_modules/
|
|
||||||
|
|
||||||
# JIRA plugin
|
|
||||||
atlassian-ide-plugin.xml
|
|
||||||
|
|
||||||
# Cursive Clojure plugin
|
|
||||||
.idea/replstate.xml
|
|
||||||
|
|
||||||
# SonarLint plugin
|
|
||||||
.idea/sonarlint/
|
|
||||||
|
|
||||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
|
||||||
com_crashlytics_export_strings.xml
|
|
||||||
crashlytics.properties
|
|
||||||
crashlytics-build.properties
|
|
||||||
fabric.properties
|
|
||||||
|
|
||||||
# Editor-based Rest Client
|
|
||||||
.idea/httpRequests
|
|
||||||
|
|
||||||
# Android studio 3.1+ serialized cache file
|
|
||||||
.idea/caches/build_file_checksums.ser
|
|
||||||
|
|
||||||
### Intellij+all Patch ###
|
|
||||||
# Ignore everything but code style settings and run configurations
|
|
||||||
# that are supposed to be shared within teams.
|
|
||||||
|
|
||||||
.idea/*
|
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
|
||||||
!.idea/codeStyles
|
# misc
|
||||||
!.idea/runConfigurations
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
# These are backup files generated by rustfmt
|
# System Files
|
||||||
**/*.rs.bk
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
# Nuxt dev/build outputs
|
||||||
*.pdb
|
.output
|
||||||
|
.data
|
||||||
|
.nuxt
|
||||||
|
.nitro
|
||||||
|
.cache
|
||||||
|
|
||||||
theseus.iml
|
# frontend generated files
|
||||||
|
apps/frontend/src/generated
|
||||||
|
|
||||||
|
.turbo
|
||||||
|
target
|
||||||
|
generated
|
||||||
|
.env
|
||||||
|
|
||||||
|
# app testing dir
|
||||||
|
app-playground-data/*
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"recommendations": ["esbenp.prettier-vscode", "Vue.volar", "rust-lang.rust-analyzer"]
|
||||||
|
}
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"prettier.endOfLine": "lf",
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"eslint.validate": [
|
||||||
|
"javascript",
|
||||||
|
"javascriptreact",
|
||||||
|
"typescript",
|
||||||
|
"typescriptreact"
|
||||||
|
],
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": "explicit"
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-7
@@ -1,13 +1,13 @@
|
|||||||
# Copying
|
# Copying Guidelines
|
||||||
|
|
||||||
The source code of the theseus repository is licensed under the GNU General Public License, Version 3 only, which is provided in the file [LICENSE](./LICENSE). However, some files listed below are licensed under a different license.
|
All packages in this repository are licensed under their respective licenses. For more information, refer to the LICENSE file in each package.
|
||||||
|
|
||||||
## Modrinth logo
|
For detailed information, consult each package's COPYING.md file, if available.
|
||||||
|
|
||||||
Any files depicting the Modrinth branding, including the wrench-in-labyrinth logo, the landing image, and variations thereof, are licensed as follows:
|
## Modrinth Branding
|
||||||
|
|
||||||
> All rights reserved. © 2020-2023 Rinth, Inc.
|
The use of Modrinth branding elements, including but not limited to the wrench-in-labyrinth logo, the landing image, and any variations thereof, is strictly prohibited without explicit written permission from Rinth, Inc. This includes trademarks, logos, or other branding elements.
|
||||||
|
|
||||||
This includes, but may not be limited to, the following files:
|
All rights reserved. © 2020-2024 Rinth, Inc.
|
||||||
|
|
||||||
- theseus_gui/src-tauri/icons/*
|
If you fork this repository, you must remove all Modrinth branding assets from your fork.
|
||||||
Generated
+2396
-1942
File diff suppressed because it is too large.
Load diff
+7
-16
@@ -1,23 +1,11 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
|
resolver = '2'
|
||||||
members = [
|
members = [
|
||||||
"theseus",
|
'./packages/app-lib',
|
||||||
"theseus_playground",
|
'./apps/app-playground',
|
||||||
"theseus_gui/src-tauri",
|
'./apps/app'
|
||||||
"theseus_macros"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.dev]
|
|
||||||
opt-level = 0
|
|
||||||
debug = true
|
|
||||||
debug-assertions = true
|
|
||||||
overflow-checks = true
|
|
||||||
lto = false
|
|
||||||
panic = 'unwind'
|
|
||||||
incremental = true
|
|
||||||
codegen-units = 256
|
|
||||||
rpath = false
|
|
||||||
|
|
||||||
# Optimize for speed and reduce size on release builds
|
# Optimize for speed and reduce size on release builds
|
||||||
[profile.release]
|
[profile.release]
|
||||||
panic = "abort" # Strip expensive panic clean-up logic
|
panic = "abort" # Strip expensive panic clean-up logic
|
||||||
@@ -25,3 +13,6 @@ codegen-units = 1 # Compile crates one after another so the compiler can optimiz
|
|||||||
lto = true # Enables link to optimizations
|
lto = true # Enables link to optimizations
|
||||||
opt-level = "s" # Optimize for binary size
|
opt-level = "s" # Optimize for binary size
|
||||||
strip = true # Remove debug symbols
|
strip = true # Remove debug symbols
|
||||||
|
|
||||||
|
[profile.dev.package.sqlx-macros]
|
||||||
|
opt-level = 3
|
||||||
@@ -1,9 +1,39 @@
|
|||||||
# theseus
|
# 
|
||||||
A game launcher which can be used as a CLI, GUI, and a library for creating and playing modrinth projects
|
|
||||||
|
|
||||||
Theseus aims to provide three components:
|

|
||||||
- A library (theseus)
|

|
||||||
- A CLI (theseus-cli)
|

|
||||||
- A GUI (theseus-gui)
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
Feel free to contribute!
|
## Modrinth Monorepo
|
||||||
|
|
||||||
|
Welcome to the Modrinth Monorepo, the primary codebase for the Modrinth web interface and app. It contains  lines of code and has  contributors!
|
||||||
|
|
||||||
|
If you're not a developer and you've stumbled upon this repository, you can access the web interface on the [Modrinth website](https://modrinth.com) and download the latest release of the app [here](https://modrinth.com/app).
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
This repository contains two primary packages. For detailed development information, please refer to their respective READMEs:
|
||||||
|
|
||||||
|
- [Web Interface](apps/frontend/README.md)
|
||||||
|
- [Desktop App](apps/app/README.md)
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We welcome contributions! Before submitting any contributions, please read our [contributing guidelines](https://support.modrinth.com/en/articles/8802215-contributing-to-modrinth).
|
||||||
|
|
||||||
|
If you plan to fork this repository for your own purposes, please review our [copying guidelines](COPYING.md).
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
If you discover a security vulnerability within our codebase, please follow our [responsible disclosure guidelines](https://modrinth.com/legal/security).
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
If you need help with the Modrinth web interface or app, please visit our [support page](https://support.modrinth.com). For general inquiries, you can also join our [Discord server](https://discord.modrinth.com).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
All packages in this repository are licensed under their respective licenses. Refer to the LICENSE file in each package for more information.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
extends: ['custom/vue'],
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
**/dist
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Copying
|
||||||
|
|
||||||
|
The source code of the theseus repository is licensed under the GNU General Public License, Version 3 only, which is provided in the file [LICENSE](./LICENSE). However, some files listed below are licensed under a different license.
|
||||||
|
|
||||||
|
## Modrinth logo
|
||||||
|
|
||||||
|
The use of Modrinth branding elements, including but not limited to the wrench-in-labyrinth logo, the landing image, and any variations thereof, is strictly prohibited without explicit written permission from Rinth, Inc. This includes trademarks, logos, or other branding elements.
|
||||||
|
|
||||||
|
> All rights reserved. © 2020-2023 Rinth, Inc.
|
||||||
|
|
||||||
|
This includes, but may not be limited to, the following files:
|
||||||
|
|
||||||
|
- theseus_gui/src-tauri/icons/\*
|
||||||
File renamed without changes.
@@ -1,10 +1,12 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en" class="dark-mode">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Modrinth App</title>
|
<title>Modrinth App</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/src/assets/stylesheets/global.scss" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"name": "@modrinth/app-frontend",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.8.3-1",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"lint": "eslint . && prettier --check .",
|
||||||
|
"fix": "eslint . --fix && prettier --write ."
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@modrinth/assets": "workspace:*",
|
||||||
|
"@modrinth/ui": "workspace:*",
|
||||||
|
"@modrinth/utils": "workspace:*",
|
||||||
|
"@tauri-apps/api": "^2.0.0-rc.3",
|
||||||
|
"@tauri-apps/plugin-dialog": "^2.0.0-rc.0",
|
||||||
|
"@tauri-apps/plugin-os": "^2.0.0-rc.0",
|
||||||
|
"@tauri-apps/plugin-window-state": "^2.0.0-rc.0",
|
||||||
|
"@tauri-apps/plugin-shell": "^2.0.0-rc.0",
|
||||||
|
"@vintl/vintl": "^4.4.1",
|
||||||
|
"dayjs": "^1.11.10",
|
||||||
|
"floating-vue": "^5.2.2",
|
||||||
|
"ofetch": "^1.3.4",
|
||||||
|
"pinia": "^2.1.7",
|
||||||
|
"vite-svg-loader": "^5.1.0",
|
||||||
|
"vue": "^3.4.21",
|
||||||
|
"vue-multiselect": "3.0.0",
|
||||||
|
"vue-router": "4.3.0",
|
||||||
|
"vue-virtual-scroller": "v2.0.0-beta.8",
|
||||||
|
"posthog-js": "^1.158.2",
|
||||||
|
"@sentry/vue": "^8.27.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tauri-apps/cli": "^2.0.0-rc",
|
||||||
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
|
"autoprefixer": "^10.4.19",
|
||||||
|
"eslint": "^8.57.0",
|
||||||
|
"eslint-config-custom": "workspace:*",
|
||||||
|
"postcss": "^8.4.39",
|
||||||
|
"prettier": "^3.2.5",
|
||||||
|
"sass": "^1.74.1",
|
||||||
|
"tailwindcss": "^3.4.4",
|
||||||
|
"tsconfig": "workspace:*",
|
||||||
|
"vite": "^5.2.8"
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@9.4.0"
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -1,18 +1,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, onMounted } from 'vue'
|
||||||
import { RouterView, RouterLink, useRouter, useRoute } from 'vue-router'
|
import { RouterView, RouterLink, useRouter, useRoute } from 'vue-router'
|
||||||
import {
|
import { HomeIcon, SearchIcon, LibraryIcon, PlusIcon, SettingsIcon, XIcon } from '@modrinth/assets'
|
||||||
HomeIcon,
|
import { Button, Notifications } from '@modrinth/ui'
|
||||||
SearchIcon,
|
|
||||||
LibraryIcon,
|
|
||||||
PlusIcon,
|
|
||||||
SettingsIcon,
|
|
||||||
FileIcon,
|
|
||||||
Button,
|
|
||||||
Notifications,
|
|
||||||
XIcon,
|
|
||||||
Card,
|
|
||||||
} from 'omorphia'
|
|
||||||
import { useLoading, useTheming } from '@/store/state'
|
import { useLoading, useTheming } from '@/store/state'
|
||||||
import AccountsCard from '@/components/ui/AccountsCard.vue'
|
import AccountsCard from '@/components/ui/AccountsCard.vue'
|
||||||
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
|
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
|
||||||
@@ -23,173 +13,153 @@ import SplashScreen from '@/components/ui/SplashScreen.vue'
|
|||||||
import ErrorModal from '@/components/ui/ErrorModal.vue'
|
import ErrorModal from '@/components/ui/ErrorModal.vue'
|
||||||
import ModrinthLoadingIndicator from '@/components/modrinth-loading-indicator'
|
import ModrinthLoadingIndicator from '@/components/modrinth-loading-indicator'
|
||||||
import { handleError, useNotifications } from '@/store/notifications.js'
|
import { handleError, useNotifications } from '@/store/notifications.js'
|
||||||
import { offline_listener, command_listener, warning_listener } from '@/helpers/events.js'
|
import { command_listener, warning_listener } from '@/helpers/events.js'
|
||||||
import { MinimizeIcon, MaximizeIcon, ChatIcon } from '@/assets/icons'
|
import { MinimizeIcon, MaximizeIcon } from '@/assets/icons'
|
||||||
import { type } from '@tauri-apps/api/os'
|
import { type } from '@tauri-apps/plugin-os'
|
||||||
import { appWindow } from '@tauri-apps/api/window'
|
import { isDev, getOS } from '@/helpers/utils.js'
|
||||||
import { isDev, getOS, isOffline, showLauncherLogsFolder } from '@/helpers/utils.js'
|
import { initAnalytics, debugAnalytics, optOutAnalytics, trackEvent } from '@/helpers/analytics'
|
||||||
import {
|
import { getCurrentWindow } from '@tauri-apps/api/window'
|
||||||
mixpanel_track,
|
|
||||||
mixpanel_init,
|
|
||||||
mixpanel_opt_out_tracking,
|
|
||||||
mixpanel_is_loaded,
|
|
||||||
} from '@/helpers/mixpanel'
|
|
||||||
import { saveWindowState, StateFlags } from 'tauri-plugin-window-state-api'
|
|
||||||
import { getVersion } from '@tauri-apps/api/app'
|
import { getVersion } from '@tauri-apps/api/app'
|
||||||
import { window as TauriWindow } from '@tauri-apps/api'
|
|
||||||
import { TauriEvent } from '@tauri-apps/api/event'
|
|
||||||
import { await_sync, check_safe_loading_bars_complete } from './helpers/state'
|
|
||||||
import { confirm } from '@tauri-apps/api/dialog'
|
|
||||||
import URLConfirmModal from '@/components/ui/URLConfirmModal.vue'
|
import URLConfirmModal from '@/components/ui/URLConfirmModal.vue'
|
||||||
import OnboardingScreen from '@/components/ui/tutorial/OnboardingScreen.vue'
|
|
||||||
import { install_from_file } from './helpers/pack'
|
import { install_from_file } from './helpers/pack'
|
||||||
import { useError } from '@/store/error.js'
|
import { useError } from '@/store/error.js'
|
||||||
|
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
|
||||||
|
import ModInstallModal from '@/components/ui/install_flow/ModInstallModal.vue'
|
||||||
|
import IncompatibilityWarningModal from '@/components/ui/install_flow/IncompatibilityWarningModal.vue'
|
||||||
|
import InstallConfirmModal from '@/components/ui/install_flow/InstallConfirmModal.vue'
|
||||||
|
import { useInstall } from '@/store/install.js'
|
||||||
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
|
import { open } from '@tauri-apps/plugin-shell'
|
||||||
|
import { get_opening_command, initialize_state } from '@/helpers/state'
|
||||||
|
|
||||||
const themeStore = useTheming()
|
const themeStore = useTheming()
|
||||||
const urlModal = ref(null)
|
|
||||||
const isLoading = ref(true)
|
|
||||||
|
|
||||||
const offline = ref(false)
|
const urlModal = ref(null)
|
||||||
|
|
||||||
|
const offline = ref(!navigator.onLine)
|
||||||
|
window.addEventListener('offline', () => {
|
||||||
|
offline.value = true
|
||||||
|
})
|
||||||
|
window.addEventListener('online', () => {
|
||||||
|
offline.value = false
|
||||||
|
})
|
||||||
|
|
||||||
const showOnboarding = ref(false)
|
const showOnboarding = ref(false)
|
||||||
const nativeDecorations = ref(false)
|
const nativeDecorations = ref(false)
|
||||||
|
|
||||||
const onboardingVideo = ref()
|
|
||||||
|
|
||||||
const failureText = ref(null)
|
|
||||||
const os = ref('')
|
const os = ref('')
|
||||||
|
|
||||||
defineExpose({
|
const stateInitialized = ref(false)
|
||||||
initialize: async () => {
|
|
||||||
isLoading.value = false
|
|
||||||
const {
|
|
||||||
native_decorations,
|
|
||||||
theme,
|
|
||||||
opt_out_analytics,
|
|
||||||
collapsed_navigation,
|
|
||||||
advanced_rendering,
|
|
||||||
fully_onboarded,
|
|
||||||
} = await get()
|
|
||||||
// video should play if the user is not on linux, and has not onboarded
|
|
||||||
os.value = await getOS()
|
|
||||||
const dev = await isDev()
|
|
||||||
const version = await getVersion()
|
|
||||||
showOnboarding.value = !fully_onboarded
|
|
||||||
|
|
||||||
nativeDecorations.value = native_decorations
|
onMounted(async () => {
|
||||||
if (os.value !== 'MacOS') appWindow.setDecorations(native_decorations)
|
await useCheckDisableMouseover()
|
||||||
|
|
||||||
themeStore.setThemeState(theme)
|
|
||||||
themeStore.collapsedNavigation = collapsed_navigation
|
|
||||||
themeStore.advancedRendering = advanced_rendering
|
|
||||||
|
|
||||||
mixpanel_init('014c7d6a336d0efaefe3aca91063748d', { debug: dev, persistence: 'localStorage' })
|
|
||||||
if (opt_out_analytics) {
|
|
||||||
mixpanel_opt_out_tracking()
|
|
||||||
}
|
|
||||||
mixpanel_track('Launched', { version, dev, fully_onboarded })
|
|
||||||
|
|
||||||
if (!dev) document.addEventListener('contextmenu', (event) => event.preventDefault())
|
|
||||||
|
|
||||||
if ((await type()) === 'Darwin') {
|
|
||||||
document.getElementsByTagName('html')[0].classList.add('mac')
|
|
||||||
} else {
|
|
||||||
document.getElementsByTagName('html')[0].classList.add('windows')
|
|
||||||
}
|
|
||||||
|
|
||||||
offline.value = await isOffline()
|
|
||||||
await offline_listener((b) => {
|
|
||||||
offline.value = b
|
|
||||||
})
|
|
||||||
|
|
||||||
await warning_listener((e) =>
|
|
||||||
notificationsWrapper.value.addNotification({
|
|
||||||
title: 'Warning',
|
|
||||||
text: e.message,
|
|
||||||
type: 'warn',
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (showOnboarding.value) {
|
|
||||||
onboardingVideo.value.play()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
failure: async (e) => {
|
|
||||||
isLoading.value = false
|
|
||||||
failureText.value = e
|
|
||||||
os.value = await getOS()
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const confirmClose = async () => {
|
async function setupApp() {
|
||||||
const confirmed = await confirm(
|
stateInitialized.value = true
|
||||||
'An action is currently in progress. Are you sure you want to exit?',
|
const {
|
||||||
{
|
native_decorations,
|
||||||
title: 'Modrinth',
|
theme,
|
||||||
type: 'warning',
|
telemetry,
|
||||||
},
|
collapsed_navigation,
|
||||||
|
advanced_rendering,
|
||||||
|
onboarded,
|
||||||
|
default_page,
|
||||||
|
} = await get()
|
||||||
|
|
||||||
|
if (default_page && default_page !== 'Home') {
|
||||||
|
await router.push({ name: default_page })
|
||||||
|
}
|
||||||
|
|
||||||
|
os.value = await getOS()
|
||||||
|
const dev = await isDev()
|
||||||
|
const version = await getVersion()
|
||||||
|
showOnboarding.value = !onboarded
|
||||||
|
|
||||||
|
nativeDecorations.value = native_decorations
|
||||||
|
if (os.value !== 'MacOS') await getCurrentWindow().setDecorations(native_decorations)
|
||||||
|
|
||||||
|
themeStore.setThemeState(theme)
|
||||||
|
themeStore.collapsedNavigation = collapsed_navigation
|
||||||
|
themeStore.advancedRendering = advanced_rendering
|
||||||
|
|
||||||
|
initAnalytics()
|
||||||
|
if (!telemetry) {
|
||||||
|
optOutAnalytics()
|
||||||
|
}
|
||||||
|
if (dev) debugAnalytics()
|
||||||
|
trackEvent('Launched', { version, dev, onboarded })
|
||||||
|
|
||||||
|
if (!dev) document.addEventListener('contextmenu', (event) => event.preventDefault())
|
||||||
|
|
||||||
|
const osType = await type()
|
||||||
|
if (osType === 'macos') {
|
||||||
|
document.getElementsByTagName('html')[0].classList.add('mac')
|
||||||
|
} else {
|
||||||
|
document.getElementsByTagName('html')[0].classList.add('windows')
|
||||||
|
}
|
||||||
|
|
||||||
|
await warning_listener((e) =>
|
||||||
|
notificationsWrapper.value.addNotification({
|
||||||
|
title: 'Warning',
|
||||||
|
text: e.message,
|
||||||
|
type: 'warn',
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
return confirmed
|
|
||||||
|
get_opening_command().then(handleCommand)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stateFailed = ref(false)
|
||||||
|
initialize_state()
|
||||||
|
.then(() => {
|
||||||
|
setupApp().catch((err) => {
|
||||||
|
stateFailed.value = true
|
||||||
|
console.error(err)
|
||||||
|
error.showError(err, null, false, 'state_init')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
stateFailed.value = true
|
||||||
|
console.error('Failed to initialize app', err)
|
||||||
|
error.showError(err, null, false, 'state_init')
|
||||||
|
})
|
||||||
|
|
||||||
const handleClose = async () => {
|
const handleClose = async () => {
|
||||||
if (failureText.value != null) {
|
await getCurrentWindow().close()
|
||||||
await TauriWindow.getCurrent().close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// State should respond immeiately if it's safe to close
|
|
||||||
// If not, code is deadlocked or worse, so wait 2 seconds and then ask the user to confirm closing
|
|
||||||
// (Exception: if the user is changing config directory, which takes control of the state, and it's taking a significant amount of time for some reason)
|
|
||||||
const isSafe = await Promise.race([
|
|
||||||
check_safe_loading_bars_complete(),
|
|
||||||
new Promise((r) => setTimeout(r, 2000)),
|
|
||||||
])
|
|
||||||
if (!isSafe) {
|
|
||||||
const response = await confirmClose()
|
|
||||||
if (!response) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await await_sync()
|
|
||||||
await TauriWindow.getCurrent().close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const openSupport = async () => {
|
|
||||||
window.__TAURI_INVOKE__('tauri', {
|
|
||||||
__tauriModule: 'Shell',
|
|
||||||
message: {
|
|
||||||
cmd: 'open',
|
|
||||||
path: 'https://discord.gg/modrinth',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
TauriWindow.getCurrent().listen(TauriEvent.WINDOW_CLOSE_REQUESTED, async () => {
|
|
||||||
await handleClose()
|
|
||||||
})
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
router.afterEach((to, from, failure) => {
|
router.afterEach((to, from, failure) => {
|
||||||
if (mixpanel_is_loaded()) {
|
trackEvent('PageView', { path: to.path, fromPath: from.path, failed: failure })
|
||||||
mixpanel_track('PageView', { path: to.path, fromPath: from.path, failed: failure })
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const isOnBrowse = computed(() => route.path.startsWith('/browse'))
|
const isOnBrowse = computed(() => route.path.startsWith('/browse'))
|
||||||
|
|
||||||
const loading = useLoading()
|
const loading = useLoading()
|
||||||
|
loading.setEnabled(false)
|
||||||
|
|
||||||
const notifications = useNotifications()
|
const notifications = useNotifications()
|
||||||
const notificationsWrapper = ref()
|
const notificationsWrapper = ref()
|
||||||
|
|
||||||
watch(notificationsWrapper, () => {
|
|
||||||
notifications.setNotifs(notificationsWrapper.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
const error = useError()
|
const error = useError()
|
||||||
const errorModal = ref()
|
const errorModal = ref()
|
||||||
|
|
||||||
watch(errorModal, () => {
|
const install = useInstall()
|
||||||
|
const modInstallModal = ref()
|
||||||
|
const installConfirmModal = ref()
|
||||||
|
const incompatibilityWarningModal = ref()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
invoke('show_window')
|
||||||
|
|
||||||
|
notifications.setNotifs(notificationsWrapper.value)
|
||||||
|
|
||||||
error.setErrorModal(errorModal.value)
|
error.setErrorModal(errorModal.value)
|
||||||
|
|
||||||
|
install.setIncompatibilityWarningModal(incompatibilityWarningModal)
|
||||||
|
install.setInstallConfirmModal(installConfirmModal)
|
||||||
|
install.setModInstallModal(modInstallModal)
|
||||||
})
|
})
|
||||||
|
|
||||||
document.querySelector('body').addEventListener('click', function (e) {
|
document.querySelector('body').addEventListener('click', function (e) {
|
||||||
@@ -203,13 +173,7 @@ document.querySelector('body').addEventListener('click', function (e) {
|
|||||||
!target.href.startsWith('http://localhost') &&
|
!target.href.startsWith('http://localhost') &&
|
||||||
!target.href.startsWith('https://tauri.localhost')
|
!target.href.startsWith('https://tauri.localhost')
|
||||||
) {
|
) {
|
||||||
window.__TAURI_INVOKE__('tauri', {
|
open(target.href)
|
||||||
__tauriModule: 'Shell',
|
|
||||||
message: {
|
|
||||||
cmd: 'open',
|
|
||||||
path: target.href,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
break
|
break
|
||||||
@@ -234,12 +198,15 @@ document.querySelector('body').addEventListener('auxclick', function (e) {
|
|||||||
|
|
||||||
const accounts = ref(null)
|
const accounts = ref(null)
|
||||||
|
|
||||||
command_listener(async (e) => {
|
command_listener(handleCommand)
|
||||||
|
async function handleCommand(e) {
|
||||||
|
if (!e) return
|
||||||
|
|
||||||
if (e.event === 'RunMRPack') {
|
if (e.event === 'RunMRPack') {
|
||||||
// RunMRPack should directly install a local mrpack given a path
|
// RunMRPack should directly install a local mrpack given a path
|
||||||
if (e.path.endsWith('.mrpack')) {
|
if (e.path.endsWith('.mrpack')) {
|
||||||
await install_from_file(e.path).catch(handleError)
|
await install_from_file(e.path).catch(handleError)
|
||||||
mixpanel_track('InstanceCreate', {
|
trackEvent('InstanceCreate', {
|
||||||
source: 'CreationModalFileDrop',
|
source: 'CreationModalFileDrop',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -247,53 +214,12 @@ command_listener(async (e) => {
|
|||||||
// Other commands are URL-based (deep linking)
|
// Other commands are URL-based (deep linking)
|
||||||
urlModal.value.show(e)
|
urlModal.value.show(e)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="failureText" class="failure dark-mode">
|
<SplashScreen v-if="!stateFailed" ref="splashScreen" data-tauri-drag-region />
|
||||||
<div class="appbar-failure dark-mode">
|
<div v-if="stateInitialized" class="app-container">
|
||||||
<Button v-if="os != 'MacOS'" icon-only @click="TauriWindow.getCurrent().close()">
|
|
||||||
<XIcon />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div class="error-view dark-mode">
|
|
||||||
<Card class="error-text">
|
|
||||||
<div class="label">
|
|
||||||
<h3>
|
|
||||||
<span class="label__title size-card-header">Failed to initialize</span>
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div class="error-div">
|
|
||||||
Modrinth App failed to load correctly. This may be because of a corrupted file, or because
|
|
||||||
the app is missing crucial files.
|
|
||||||
</div>
|
|
||||||
<div class="error-div">You may be able to fix it one of the following ways:</div>
|
|
||||||
<ul class="error-div">
|
|
||||||
<li>Ennsuring you are connected to the internet, then try restarting the app.</li>
|
|
||||||
<li>Redownloading the app.</li>
|
|
||||||
</ul>
|
|
||||||
<div class="error-div">
|
|
||||||
If it still does not work, you can seek support using the link below. You should provide
|
|
||||||
the following error, as well as any recent launcher logs in the folder below.
|
|
||||||
</div>
|
|
||||||
<div class="error-div">The following error was provided:</div>
|
|
||||||
|
|
||||||
<Card class="error-message">
|
|
||||||
{{ failureText.message }}
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
<div class="button-row push-right">
|
|
||||||
<Button @click="showLauncherLogsFolder"><FileIcon />Open launcher logs</Button>
|
|
||||||
|
|
||||||
<Button @click="openSupport"><ChatIcon />Get support</Button>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<SplashScreen v-else-if="isLoading" app-loading />
|
|
||||||
<OnboardingScreen v-else-if="showOnboarding" :finish="() => (showOnboarding = false)" />
|
|
||||||
<div v-else class="container">
|
|
||||||
<div class="nav-container">
|
<div class="nav-container">
|
||||||
<div class="nav-section">
|
<div class="nav-section">
|
||||||
<suspense>
|
<suspense>
|
||||||
@@ -349,22 +275,17 @@ command_listener(async (e) => {
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<section v-if="!nativeDecorations" class="window-controls">
|
<section v-if="!nativeDecorations" class="window-controls">
|
||||||
<Button class="titlebar-button" icon-only @click="() => appWindow.minimize()">
|
<Button class="titlebar-button" icon-only @click="() => getCurrentWindow().minimize()">
|
||||||
<MinimizeIcon />
|
<MinimizeIcon />
|
||||||
</Button>
|
</Button>
|
||||||
<Button class="titlebar-button" icon-only @click="() => appWindow.toggleMaximize()">
|
<Button
|
||||||
|
class="titlebar-button"
|
||||||
|
icon-only
|
||||||
|
@click="() => getCurrentWindow().toggleMaximize()"
|
||||||
|
>
|
||||||
<MaximizeIcon />
|
<MaximizeIcon />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button class="titlebar-button close" icon-only @click="handleClose">
|
||||||
class="titlebar-button close"
|
|
||||||
icon-only
|
|
||||||
@click="
|
|
||||||
() => {
|
|
||||||
saveWindowState(StateFlags.ALL)
|
|
||||||
handleClose()
|
|
||||||
}
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<XIcon />
|
<XIcon />
|
||||||
</Button>
|
</Button>
|
||||||
</section>
|
</section>
|
||||||
@@ -387,6 +308,9 @@ command_listener(async (e) => {
|
|||||||
<URLConfirmModal ref="urlModal" />
|
<URLConfirmModal ref="urlModal" />
|
||||||
<Notifications ref="notificationsWrapper" />
|
<Notifications ref="notificationsWrapper" />
|
||||||
<ErrorModal ref="errorModal" />
|
<ErrorModal ref="errorModal" />
|
||||||
|
<ModInstallModal ref="modInstallModal" />
|
||||||
|
<IncompatibilityWarningModal ref="incompatibilityWarningModal" />
|
||||||
|
<InstallConfirmModal ref="installConfirmModal" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -438,7 +362,7 @@ command_listener(async (e) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.app-container {
|
||||||
--appbar-height: 3.25rem;
|
--appbar-height: 3.25rem;
|
||||||
--sidebar-width: 4.5rem;
|
--sidebar-width: 4.5rem;
|
||||||
|
|
||||||
@@ -476,53 +400,6 @@ command_listener(async (e) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.failure {
|
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
background-color: var(--color-bg);
|
|
||||||
|
|
||||||
.appbar-failure {
|
|
||||||
display: flex; /* Change to flex to align items horizontally */
|
|
||||||
justify-content: flex-end; /* Align items to the right */
|
|
||||||
height: 3.25rem;
|
|
||||||
//no select
|
|
||||||
user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-view {
|
|
||||||
display: flex; /* Change to flex to align items horizontally */
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--color-bg);
|
|
||||||
|
|
||||||
color: var(--color-base);
|
|
||||||
|
|
||||||
.card {
|
|
||||||
background-color: var(--color-raised-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-text {
|
|
||||||
display: flex;
|
|
||||||
max-width: 60%;
|
|
||||||
gap: 0.25rem;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.error-div {
|
|
||||||
// spaced out
|
|
||||||
margin: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-message {
|
|
||||||
margin: 0.5rem;
|
|
||||||
background-color: var(--color-button-bg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-container {
|
.nav-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -586,55 +463,6 @@ command_listener(async (e) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.instance-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
width: 70%;
|
|
||||||
margin: 0.4rem;
|
|
||||||
|
|
||||||
p:nth-child(1) {
|
|
||||||
font-size: 0.6rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > p {
|
|
||||||
color: var(--color-base);
|
|
||||||
margin: 0.8rem 0;
|
|
||||||
font-size: 0.7rem;
|
|
||||||
line-height: 0.8125rem;
|
|
||||||
font-weight: 500;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-section {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 4.375rem;
|
|
||||||
|
|
||||||
section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
text-align: left;
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.username {
|
|
||||||
margin-bottom: 0.3rem;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1.25rem;
|
|
||||||
color: var(--color-contrast);
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: 400;
|
|
||||||
color: var(--color-secondary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-section {
|
.nav-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -645,14 +473,6 @@ command_listener(async (e) => {
|
|||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video {
|
|
||||||
margin-top: 2.25rem;
|
|
||||||
width: 100vw;
|
|
||||||
height: calc(100vh - 2.25rem);
|
|
||||||
object-fit: cover;
|
|
||||||
border-radius: var(--radius-md);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-row {
|
.button-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@@ -664,3 +484,33 @@ command_listener(async (e) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<style>
|
||||||
|
.mac {
|
||||||
|
.nav-container {
|
||||||
|
padding-top: calc(var(--gap-md) + 1.75rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-card,
|
||||||
|
.card-section {
|
||||||
|
top: calc(var(--gap-md) + 1.75rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.windows {
|
||||||
|
.fake-appbar {
|
||||||
|
height: 2.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-controls {
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card {
|
||||||
|
right: 8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-card {
|
||||||
|
right: 8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File renamed without changes.
File renamed without changes.
Vendored
File renamed without changes.
File renamed without changes.
Vendored
File renamed without changes.
Vendored
File renamed without changes.
Vendored
File renamed without changes.
File renamed without changes.
File renamed without changes.
Vendored
File renamed without changes.
Vendored
File renamed without changes.
Vendored
File renamed without changes.
File renamed without changes.
Vendored
File renamed without changes.
Vendored
File renamed without changes.
Vendored
File renamed without changes.
Vendored
File renamed without changes.
Vendored
File renamed without changes.
Vendored
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file not shown.
|
After Width: | Height: | Size: 937 KiB |
+9
-32
@@ -1,3 +1,7 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
font-family: var(--font-standard);
|
font-family: var(--font-standard);
|
||||||
color-scheme: dark;
|
color-scheme: dark;
|
||||||
@@ -69,44 +73,15 @@ input {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mac {
|
|
||||||
.nav-container {
|
|
||||||
padding-top: calc(var(--gap-md) + 1.75rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-card,
|
|
||||||
.card-section {
|
|
||||||
top: calc(var(--gap-md) + 1.75rem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.windows {
|
|
||||||
.fake-appbar {
|
|
||||||
height: 2.5rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-controls {
|
|
||||||
display: flex !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-card {
|
|
||||||
right: 8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-card {
|
|
||||||
right: 8rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
scrollbar-width: auto;
|
scrollbar-width: auto;
|
||||||
scrollbar-color: var(--color-button-bg) var(--color-bg);
|
scrollbar-color: var(--color-scrollbar) var(--color-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Chrome, Edge, and Safari */
|
/* Chrome, Edge, and Safari */
|
||||||
*::-webkit-scrollbar {
|
*::-webkit-scrollbar {
|
||||||
width: var(--gap-md);
|
width: var(--gap-md);
|
||||||
border: 3px solid var(--color-bg);
|
border: 3px solid var(--color-scrollbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar-track {
|
*::-webkit-scrollbar-track {
|
||||||
@@ -115,7 +90,7 @@ input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar-thumb {
|
*::-webkit-scrollbar-thumb {
|
||||||
background-color: var(--color-button-bg);
|
background-color: var(--color-scrollbar);
|
||||||
border-radius: var(--radius-lg);
|
border-radius: var(--radius-lg);
|
||||||
border: 3px solid var(--color-bg);
|
border: 3px solid var(--color-bg);
|
||||||
}
|
}
|
||||||
@@ -135,3 +110,5 @@ img {
|
|||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@import '@modrinth/assets/omorphia.scss';
|
||||||
File renamed without changes.
+20
-23
@@ -9,14 +9,11 @@ import {
|
|||||||
TrashIcon,
|
TrashIcon,
|
||||||
StopCircleIcon,
|
StopCircleIcon,
|
||||||
EyeIcon,
|
EyeIcon,
|
||||||
Card,
|
|
||||||
DropdownSelect,
|
|
||||||
SearchIcon,
|
SearchIcon,
|
||||||
XIcon,
|
XIcon,
|
||||||
Button,
|
} from '@modrinth/assets'
|
||||||
formatCategoryHeader,
|
import { ConfirmModal, Button, Card, DropdownSelect } from '@modrinth/ui'
|
||||||
ModalConfirm,
|
import { formatCategoryHeader } from '@modrinth/utils'
|
||||||
} from 'omorphia'
|
|
||||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { useTheming } from '@/store/theme.js'
|
import { useTheming } from '@/store/theme.js'
|
||||||
@@ -130,46 +127,46 @@ const sortBy = ref('Name')
|
|||||||
|
|
||||||
const filteredResults = computed(() => {
|
const filteredResults = computed(() => {
|
||||||
let instances = props.instances.filter((instance) => {
|
let instances = props.instances.filter((instance) => {
|
||||||
return instance.metadata.name.toLowerCase().includes(search.value.toLowerCase())
|
return instance.name.toLowerCase().includes(search.value.toLowerCase())
|
||||||
})
|
})
|
||||||
|
|
||||||
if (sortBy.value === 'Name') {
|
if (sortBy.value === 'Name') {
|
||||||
instances.sort((a, b) => {
|
instances.sort((a, b) => {
|
||||||
return a.metadata.name.localeCompare(b.metadata.name)
|
return a.name.localeCompare(b.name)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sortBy.value === 'Game version') {
|
if (sortBy.value === 'Game version') {
|
||||||
instances.sort((a, b) => {
|
instances.sort((a, b) => {
|
||||||
return a.metadata.game_version.localeCompare(b.metadata.game_version)
|
return a.game_version.localeCompare(b.game_version)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sortBy.value === 'Last played') {
|
if (sortBy.value === 'Last played') {
|
||||||
instances.sort((a, b) => {
|
instances.sort((a, b) => {
|
||||||
return dayjs(b.metadata.last_played ?? 0).diff(dayjs(a.metadata.last_played ?? 0))
|
return dayjs(b.last_played ?? 0).diff(dayjs(a.last_played ?? 0))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sortBy.value === 'Date created') {
|
if (sortBy.value === 'Date created') {
|
||||||
instances.sort((a, b) => {
|
instances.sort((a, b) => {
|
||||||
return dayjs(b.metadata.date_created).diff(dayjs(a.metadata.date_created))
|
return dayjs(b.date_created).diff(dayjs(a.date_created))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sortBy.value === 'Date modified') {
|
if (sortBy.value === 'Date modified') {
|
||||||
instances.sort((a, b) => {
|
instances.sort((a, b) => {
|
||||||
return dayjs(b.metadata.date_modified).diff(dayjs(a.metadata.date_modified))
|
return dayjs(b.date_modified).diff(dayjs(a.date_modified))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.value === 'Custom instances') {
|
if (filters.value === 'Custom instances') {
|
||||||
instances = instances.filter((instance) => {
|
instances = instances.filter((instance) => {
|
||||||
return !instance.metadata?.linked_data
|
return !instance.linked_data
|
||||||
})
|
})
|
||||||
} else if (filters.value === 'Downloaded modpacks') {
|
} else if (filters.value === 'Downloaded modpacks') {
|
||||||
instances = instances.filter((instance) => {
|
instances = instances.filter((instance) => {
|
||||||
return instance.metadata?.linked_data
|
return instance.linked_data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +174,7 @@ const filteredResults = computed(() => {
|
|||||||
|
|
||||||
if (group.value === 'Loader') {
|
if (group.value === 'Loader') {
|
||||||
instances.forEach((instance) => {
|
instances.forEach((instance) => {
|
||||||
const loader = formatCategoryHeader(instance.metadata.loader)
|
const loader = formatCategoryHeader(instance.loader)
|
||||||
if (!instanceMap.has(loader)) {
|
if (!instanceMap.has(loader)) {
|
||||||
instanceMap.set(loader, [])
|
instanceMap.set(loader, [])
|
||||||
}
|
}
|
||||||
@@ -186,19 +183,19 @@ const filteredResults = computed(() => {
|
|||||||
})
|
})
|
||||||
} else if (group.value === 'Game version') {
|
} else if (group.value === 'Game version') {
|
||||||
instances.forEach((instance) => {
|
instances.forEach((instance) => {
|
||||||
if (!instanceMap.has(instance.metadata.game_version)) {
|
if (!instanceMap.has(instance.game_version)) {
|
||||||
instanceMap.set(instance.metadata.game_version, [])
|
instanceMap.set(instance.game_version, [])
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceMap.get(instance.metadata.game_version).push(instance)
|
instanceMap.get(instance.game_version).push(instance)
|
||||||
})
|
})
|
||||||
} else if (group.value === 'Category') {
|
} else if (group.value === 'Category') {
|
||||||
instances.forEach((instance) => {
|
instances.forEach((instance) => {
|
||||||
if (instance.metadata.groups.length === 0) {
|
if (instance.groups.length === 0) {
|
||||||
instance.metadata.groups.push('None')
|
instance.groups.push('None')
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const category of instance.metadata.groups) {
|
for (const category of instance.groups) {
|
||||||
if (!instanceMap.has(category)) {
|
if (!instanceMap.has(category)) {
|
||||||
instanceMap.set(category, [])
|
instanceMap.set(category, [])
|
||||||
}
|
}
|
||||||
@@ -233,7 +230,7 @@ const filteredResults = computed(() => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<ModalConfirm
|
<ConfirmModal
|
||||||
ref="confirmModal"
|
ref="confirmModal"
|
||||||
title="Are you sure you want to delete this instance?"
|
title="Are you sure you want to delete this instance?"
|
||||||
description="If you proceed, all data for your instance will be removed. You will not be able to recover it."
|
description="If you proceed, all data for your instance will be removed. You will not be able to recover it."
|
||||||
@@ -246,7 +243,7 @@ const filteredResults = computed(() => {
|
|||||||
<div class="iconified-input">
|
<div class="iconified-input">
|
||||||
<SearchIcon />
|
<SearchIcon />
|
||||||
<input v-model="search" type="text" placeholder="Search" class="search-input" />
|
<input v-model="search" type="text" placeholder="Search" class="search-input" />
|
||||||
<Button @click="() => (search = '')">
|
<Button class="r-btn" @click="() => (search = '')">
|
||||||
<XIcon />
|
<XIcon />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
+37
-62
@@ -11,28 +11,21 @@ import {
|
|||||||
ExternalIcon,
|
ExternalIcon,
|
||||||
EyeIcon,
|
EyeIcon,
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
ModalConfirm,
|
} from '@modrinth/assets'
|
||||||
} from 'omorphia'
|
import { ConfirmModal } from '@modrinth/ui'
|
||||||
import Instance from '@/components/ui/Instance.vue'
|
import Instance from '@/components/ui/Instance.vue'
|
||||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||||
import ProjectCard from '@/components/ui/ProjectCard.vue'
|
import ProjectCard from '@/components/ui/ProjectCard.vue'
|
||||||
import InstallConfirmModal from '@/components/ui/InstallConfirmModal.vue'
|
import { get_by_profile_path } from '@/helpers/process.js'
|
||||||
import ModInstallModal from '@/components/ui/ModInstallModal.vue'
|
|
||||||
import {
|
|
||||||
get_all_running_profile_paths,
|
|
||||||
get_uuids_by_profile_path,
|
|
||||||
kill_by_uuid,
|
|
||||||
} from '@/helpers/process.js'
|
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import { duplicate, remove, run } from '@/helpers/profile.js'
|
import { duplicate, kill, remove, run } from '@/helpers/profile.js'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { showProfileInFolder } from '@/helpers/utils.js'
|
import { showProfileInFolder } from '@/helpers/utils.js'
|
||||||
import { useFetch } from '@/helpers/fetch.js'
|
|
||||||
import { install as pack_install } from '@/helpers/pack.js'
|
|
||||||
import { useTheming } from '@/store/state.js'
|
import { useTheming } from '@/store/state.js'
|
||||||
import { mixpanel_track } from '@/helpers/mixpanel'
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
import { handleSevereError } from '@/store/error.js'
|
import { handleSevereError } from '@/store/error.js'
|
||||||
|
import { install as installVersion } from '@/store/install.js'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
@@ -58,9 +51,7 @@ const modsRow = ref(null)
|
|||||||
const instanceOptions = ref(null)
|
const instanceOptions = ref(null)
|
||||||
const instanceComponents = ref(null)
|
const instanceComponents = ref(null)
|
||||||
const rows = ref(null)
|
const rows = ref(null)
|
||||||
const confirmModal = ref(null)
|
|
||||||
const deleteConfirmModal = ref(null)
|
const deleteConfirmModal = ref(null)
|
||||||
const modInstallModal = ref(null)
|
|
||||||
|
|
||||||
const themeStore = useTheming()
|
const themeStore = useTheming()
|
||||||
const currentDeleteInstance = ref(null)
|
const currentDeleteInstance = ref(null)
|
||||||
@@ -90,23 +81,24 @@ const handleInstanceRightClick = async (event, passedInstance) => {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const running = await get_all_running_profile_paths().catch(handleError)
|
const runningProcesses = await get_by_profile_path(passedInstance.path).catch(handleError)
|
||||||
|
|
||||||
const options = running.includes(passedInstance.path)
|
const options =
|
||||||
? [
|
runningProcesses.length > 0
|
||||||
{
|
? [
|
||||||
name: 'stop',
|
{
|
||||||
color: 'danger',
|
name: 'stop',
|
||||||
},
|
color: 'danger',
|
||||||
...baseOptions,
|
},
|
||||||
]
|
...baseOptions,
|
||||||
: [
|
]
|
||||||
{
|
: [
|
||||||
name: 'play',
|
{
|
||||||
color: 'primary',
|
name: 'play',
|
||||||
},
|
color: 'primary',
|
||||||
...baseOptions,
|
},
|
||||||
]
|
...baseOptions,
|
||||||
|
]
|
||||||
|
|
||||||
instanceOptions.value.showMenu(event, passedInstance, options)
|
instanceOptions.value.showMenu(event, passedInstance, options)
|
||||||
}
|
}
|
||||||
@@ -130,24 +122,24 @@ const handleProjectClick = (event, passedInstance) => {
|
|||||||
const handleOptionsClick = async (args) => {
|
const handleOptionsClick = async (args) => {
|
||||||
switch (args.option) {
|
switch (args.option) {
|
||||||
case 'play':
|
case 'play':
|
||||||
await run(args.item.path).catch(handleSevereError)
|
await run(args.item.path).catch((err) =>
|
||||||
mixpanel_track('InstanceStart', {
|
handleSevereError(err, { profilePath: args.item.path }),
|
||||||
loader: args.item.metadata.loader,
|
)
|
||||||
game_version: args.item.metadata.game_version,
|
trackEvent('InstanceStart', {
|
||||||
|
loader: args.item.loader,
|
||||||
|
game_version: args.item.game_version,
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
case 'stop':
|
case 'stop':
|
||||||
for (const u of await get_uuids_by_profile_path(args.item.path).catch(handleError)) {
|
await kill(args.item.path).catch(handleError)
|
||||||
await kill_by_uuid(u).catch(handleError)
|
trackEvent('InstanceStop', {
|
||||||
}
|
loader: args.item.loader,
|
||||||
mixpanel_track('InstanceStop', {
|
game_version: args.item.game_version,
|
||||||
loader: args.item.metadata.loader,
|
|
||||||
game_version: args.item.metadata.game_version,
|
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
case 'add_content':
|
case 'add_content':
|
||||||
await router.push({
|
await router.push({
|
||||||
path: `/browse/${args.item.metadata.loader === 'vanilla' ? 'datapack' : 'mod'}`,
|
path: `/browse/${args.item.loader === 'vanilla' ? 'datapack' : 'mod'}`,
|
||||||
query: { i: args.item.path },
|
query: { i: args.item.path },
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
@@ -170,21 +162,8 @@ const handleOptionsClick = async (args) => {
|
|||||||
await navigator.clipboard.writeText(args.item.path)
|
await navigator.clipboard.writeText(args.item.path)
|
||||||
break
|
break
|
||||||
case 'install': {
|
case 'install': {
|
||||||
const versions = await useFetch(
|
await installVersion(args.item.project_id, null, null, 'ProjectCardContextMenu')
|
||||||
`https://api.modrinth.com/v2/project/${args.item.project_id}/version`,
|
|
||||||
'project versions',
|
|
||||||
)
|
|
||||||
|
|
||||||
if (args.item.project_type === 'modpack') {
|
|
||||||
await pack_install(
|
|
||||||
args.item.project_id,
|
|
||||||
versions[0].id,
|
|
||||||
args.item.title,
|
|
||||||
args.item.icon_url,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
modInstallModal.value.show(args.item.project_id, versions)
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'open_link':
|
case 'open_link':
|
||||||
@@ -228,7 +207,7 @@ onUnmounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ModalConfirm
|
<ConfirmModal
|
||||||
ref="deleteConfirmModal"
|
ref="deleteConfirmModal"
|
||||||
title="Are you sure you want to delete this instance?"
|
title="Are you sure you want to delete this instance?"
|
||||||
description="If you proceed, all data for your instance will be removed. You will not be able to recover it."
|
description="If you proceed, all data for your instance will be removed. You will not be able to recover it."
|
||||||
@@ -243,7 +222,7 @@ onUnmounted(() => {
|
|||||||
<router-link :to="row.route">{{ row.label }}</router-link>
|
<router-link :to="row.route">{{ row.label }}</router-link>
|
||||||
<ChevronRightIcon />
|
<ChevronRightIcon />
|
||||||
</div>
|
</div>
|
||||||
<section v-if="row.instances[0].metadata" ref="modsRow" class="instances">
|
<section v-if="row.instance" ref="modsRow" class="instances">
|
||||||
<Instance
|
<Instance
|
||||||
v-for="instance in row.instances.slice(0, maxInstancesPerRow)"
|
v-for="instance in row.instances.slice(0, maxInstancesPerRow)"
|
||||||
:key="(instance?.project_id || instance?.id) + instance.install_stage"
|
:key="(instance?.project_id || instance?.id) + instance.install_stage"
|
||||||
@@ -258,8 +237,6 @@ onUnmounted(() => {
|
|||||||
ref="instanceComponents"
|
ref="instanceComponents"
|
||||||
class="item"
|
class="item"
|
||||||
:project="project"
|
:project="project"
|
||||||
:confirm-modal="confirmModal"
|
|
||||||
:mod-install-modal="modInstallModal"
|
|
||||||
@contextmenu.prevent.stop="(event) => handleProjectClick(event, project)"
|
@contextmenu.prevent.stop="(event) => handleProjectClick(event, project)"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
@@ -278,8 +255,6 @@ onUnmounted(() => {
|
|||||||
<template #open_link> <GlobeIcon /> Open in Modrinth <ExternalIcon /> </template>
|
<template #open_link> <GlobeIcon /> Open in Modrinth <ExternalIcon /> </template>
|
||||||
<template #copy_link> <ClipboardCopyIcon /> Copy link </template>
|
<template #copy_link> <ClipboardCopyIcon /> Copy link </template>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
<InstallConfirmModal ref="confirmModal" />
|
|
||||||
<ModInstallModal ref="modInstallModal" />
|
|
||||||
</template>
|
</template>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.content {
|
.content {
|
||||||
+6
-4
@@ -40,10 +40,12 @@ export default defineComponent({
|
|||||||
const loading = useLoading()
|
const loading = useLoading()
|
||||||
|
|
||||||
watch(loading, (newValue) => {
|
watch(loading, (newValue) => {
|
||||||
if (newValue.loading) {
|
if (newValue.barEnabled) {
|
||||||
indicator.start()
|
if (newValue.loading) {
|
||||||
} else {
|
indicator.start()
|
||||||
indicator.finish()
|
} else {
|
||||||
|
indicator.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
+5
-4
@@ -59,7 +59,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Avatar, Button, Card, PlusIcon, TrashIcon, LogInIcon } from 'omorphia'
|
import { PlusIcon, TrashIcon, LogInIcon } from '@modrinth/assets'
|
||||||
|
import { Avatar, Button, Card } from '@modrinth/ui'
|
||||||
import { ref, computed, onMounted, onBeforeUnmount, onUnmounted } from 'vue'
|
import { ref, computed, onMounted, onBeforeUnmount, onUnmounted } from 'vue'
|
||||||
import {
|
import {
|
||||||
users,
|
users,
|
||||||
@@ -69,7 +70,7 @@ import {
|
|||||||
get_default_user,
|
get_default_user,
|
||||||
} from '@/helpers/auth'
|
} from '@/helpers/auth'
|
||||||
import { handleError } from '@/store/state.js'
|
import { handleError } from '@/store/state.js'
|
||||||
import { mixpanel_track } from '@/helpers/mixpanel'
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
import { process_listener } from '@/helpers/events'
|
import { process_listener } from '@/helpers/events'
|
||||||
import { handleSevereError } from '@/store/error.js'
|
import { handleSevereError } from '@/store/error.js'
|
||||||
|
|
||||||
@@ -117,7 +118,7 @@ async function login() {
|
|||||||
await refreshValues()
|
await refreshValues()
|
||||||
}
|
}
|
||||||
|
|
||||||
mixpanel_track('AccountLogIn')
|
trackEvent('AccountLogIn')
|
||||||
}
|
}
|
||||||
|
|
||||||
const logout = async (id) => {
|
const logout = async (id) => {
|
||||||
@@ -129,7 +130,7 @@ const logout = async (id) => {
|
|||||||
} else {
|
} else {
|
||||||
emit('change')
|
emit('change')
|
||||||
}
|
}
|
||||||
mixpanel_track('AccountLogOut')
|
trackEvent('AccountLogOut')
|
||||||
}
|
}
|
||||||
|
|
||||||
let showCard = ref(false)
|
let showCard = ref(false)
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { DropdownIcon, FolderOpenIcon, SearchIcon } from '@modrinth/assets'
|
||||||
|
import { Button, OverflowMenu } from '@modrinth/ui'
|
||||||
|
import { open } from '@tauri-apps/plugin-dialog'
|
||||||
|
import { add_project_from_path } from '@/helpers/profile.js'
|
||||||
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
instance: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const handleAddContentFromFile = async () => {
|
||||||
|
const newProject = await open({ multiple: true })
|
||||||
|
if (!newProject) return
|
||||||
|
|
||||||
|
for (const project of newProject) {
|
||||||
|
await add_project_from_path(props.instance.path, project).catch(handleError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSearchContent = async () => {
|
||||||
|
await router.push({
|
||||||
|
path: `/browse/${props.instance.loader === 'vanilla' ? 'datapack' : 'mod'}`,
|
||||||
|
query: { i: props.instance.path },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="joined-buttons">
|
||||||
|
<Button color="primary" @click="handleSearchContent"><SearchIcon /> Add content </Button>
|
||||||
|
|
||||||
|
<OverflowMenu
|
||||||
|
:options="[
|
||||||
|
{
|
||||||
|
id: 'search',
|
||||||
|
action: handleSearchContent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'from_file',
|
||||||
|
action: handleAddContentFromFile,
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
class="btn btn-primary btn-dropdown-animation icon-only"
|
||||||
|
>
|
||||||
|
<DropdownIcon />
|
||||||
|
<template #search>
|
||||||
|
<SearchIcon />
|
||||||
|
<span class="no-wrap"> Search </span>
|
||||||
|
</template>
|
||||||
|
<template #from_file>
|
||||||
|
<FolderOpenIcon />
|
||||||
|
<span class="no-wrap"> Add from file </span>
|
||||||
|
</template>
|
||||||
|
</OverflowMenu>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
+2
-1
@@ -31,7 +31,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ChevronRightIcon, Button, ChevronLeftIcon } from 'omorphia'
|
import { ChevronRightIcon, ChevronLeftIcon } from '@modrinth/assets'
|
||||||
|
import { Button } from '@modrinth/ui'
|
||||||
import { useBreadcrumbs } from '@/store/breadcrumbs'
|
import { useBreadcrumbs } from '@/store/breadcrumbs'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
+2
-2
@@ -60,9 +60,9 @@ defineExpose({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const isLinkedData = (item) => {
|
const isLinkedData = (item) => {
|
||||||
if (item.instance != undefined && item.instance.metadata.linked_data) {
|
if (item.instance != undefined && item.instance.linked_data) {
|
||||||
return true
|
return true
|
||||||
} else if (item.metadata != undefined && item.metadata.linked_data) {
|
} else if (item != undefined && item.linked_data) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
+152
-43
@@ -1,14 +1,18 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Modal, XIcon, IssuesIcon, LogInIcon } from 'omorphia'
|
import { XIcon, HammerIcon, LogInIcon, UpdatedIcon } from '@modrinth/assets'
|
||||||
|
import { Modal } from '@modrinth/ui'
|
||||||
import { ChatIcon } from '@/assets/icons'
|
import { ChatIcon } from '@/assets/icons'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { login as login_flow, set_default_user } from '@/helpers/auth.js'
|
import { login as login_flow, set_default_user } from '@/helpers/auth.js'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import mixpanel from 'mixpanel-browser'
|
|
||||||
import { handleSevereError } from '@/store/error.js'
|
import { handleSevereError } from '@/store/error.js'
|
||||||
|
import { cancel_directory_change } from '@/helpers/settings.js'
|
||||||
|
import { install } from '@/helpers/profile.js'
|
||||||
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
|
|
||||||
const errorModal = ref()
|
const errorModal = ref()
|
||||||
const error = ref()
|
const error = ref()
|
||||||
|
const closable = ref(true)
|
||||||
|
|
||||||
const title = ref('An error occurred')
|
const title = ref('An error occurred')
|
||||||
const errorType = ref('unknown')
|
const errorType = ref('unknown')
|
||||||
@@ -16,14 +20,19 @@ const supportLink = ref('https://support.modrinth.com')
|
|||||||
const metadata = ref({})
|
const metadata = ref({})
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
async show(errorVal) {
|
async show(errorVal, context, canClose = true, source = null) {
|
||||||
|
closable.value = canClose
|
||||||
|
|
||||||
if (errorVal.message && errorVal.message.includes('Minecraft authentication error:')) {
|
if (errorVal.message && errorVal.message.includes('Minecraft authentication error:')) {
|
||||||
title.value = 'Unable to sign in to Minecraft'
|
title.value = 'Unable to sign in to Minecraft'
|
||||||
errorType.value = 'minecraft_auth'
|
errorType.value = 'minecraft_auth'
|
||||||
supportLink.value =
|
supportLink.value =
|
||||||
'https://support.modrinth.com/en/articles/9038231-minecraft-sign-in-issues'
|
'https://support.modrinth.com/en/articles/9038231-minecraft-sign-in-issues'
|
||||||
|
|
||||||
if (errorVal.message.includes('existing connection was forcibly closed')) {
|
if (
|
||||||
|
errorVal.message.includes('existing connection was forcibly closed') ||
|
||||||
|
errorVal.message.includes('error sending request for url')
|
||||||
|
) {
|
||||||
metadata.value.network = true
|
metadata.value.network = true
|
||||||
}
|
}
|
||||||
if (errorVal.message.includes('because the target machine actively refused it')) {
|
if (errorVal.message.includes('because the target machine actively refused it')) {
|
||||||
@@ -33,6 +42,27 @@ defineExpose({
|
|||||||
title.value = 'Sign in to Minecraft'
|
title.value = 'Sign in to Minecraft'
|
||||||
errorType.value = 'minecraft_sign_in'
|
errorType.value = 'minecraft_sign_in'
|
||||||
supportLink.value = 'https://support.modrinth.com'
|
supportLink.value = 'https://support.modrinth.com'
|
||||||
|
} else if (errorVal.message && errorVal.message.includes('Move directory error:')) {
|
||||||
|
title.value = 'Could not change app directory'
|
||||||
|
errorType.value = 'directory_move'
|
||||||
|
supportLink.value = 'https://support.modrinth.com'
|
||||||
|
|
||||||
|
if (errorVal.message.includes('directory is not writeable')) {
|
||||||
|
metadata.value.readOnly = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorVal.message.includes('Not enough space')) {
|
||||||
|
metadata.value.notEnoughSpace = true
|
||||||
|
}
|
||||||
|
} else if (errorVal.message && errorVal.message.includes('No loader version selected for')) {
|
||||||
|
title.value = 'No loader selected'
|
||||||
|
errorType.value = 'no_loader_version'
|
||||||
|
supportLink.value = 'https://support.modrinth.com'
|
||||||
|
metadata.value.profilePath = context.profilePath
|
||||||
|
} else if (source === 'state_init') {
|
||||||
|
title.value = 'Error initializing Modrinth App'
|
||||||
|
errorType.value = 'state_init'
|
||||||
|
supportLink.value = 'https://support.modrinth.com'
|
||||||
} else {
|
} else {
|
||||||
title.value = 'An error occurred'
|
title.value = 'An error occurred'
|
||||||
errorType.value = 'unknown'
|
errorType.value = 'unknown'
|
||||||
@@ -55,7 +85,7 @@ async function loginMinecraft() {
|
|||||||
await set_default_user(loggedIn.id).catch(handleError)
|
await set_default_user(loggedIn.id).catch(handleError)
|
||||||
}
|
}
|
||||||
|
|
||||||
await mixpanel.track('AccountLogIn')
|
await trackEvent('AccountLogIn', { source: 'ErrorModal' })
|
||||||
loadingMinecraft.value = false
|
loadingMinecraft.value = false
|
||||||
errorModal.value.hide()
|
errorModal.value.hide()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -63,17 +93,38 @@ async function loginMinecraft() {
|
|||||||
handleSevereError(err)
|
handleSevereError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function cancelDirectoryChange() {
|
||||||
|
try {
|
||||||
|
await cancel_directory_change()
|
||||||
|
window.location.reload()
|
||||||
|
} catch (err) {
|
||||||
|
handleError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function retryDirectoryChange() {
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadingRepair = ref(false)
|
||||||
|
async function repairInstance() {
|
||||||
|
loadingRepair.value = true
|
||||||
|
try {
|
||||||
|
await install(metadata.value.profilePath, false)
|
||||||
|
errorModal.value.hide()
|
||||||
|
} catch (err) {
|
||||||
|
handleSevereError(err)
|
||||||
|
}
|
||||||
|
loadingRepair.value = false
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal ref="errorModal" :header="title">
|
<Modal ref="errorModal" :header="title" :closable="closable">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="markdown-body">
|
<div class="markdown-body">
|
||||||
<template v-if="errorType === 'minecraft_auth'">
|
<template v-if="errorType === 'minecraft_auth'">
|
||||||
<p>
|
|
||||||
Signing into Microsoft account is a complex task for the launchers, and there are a lot
|
|
||||||
of things can go wrong.
|
|
||||||
</p>
|
|
||||||
<template v-if="metadata.network">
|
<template v-if="metadata.network">
|
||||||
<h3>Network issues</h3>
|
<h3>Network issues</h3>
|
||||||
<p>
|
<p>
|
||||||
@@ -103,49 +154,62 @@ async function loginMinecraft() {
|
|||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<h3>Make sure you are signing into the right Microsoft account</h3>
|
<h3>Try another Microsoft account</h3>
|
||||||
<p>
|
<p>
|
||||||
More often than not, this error is caused by you signing into an incorrect Microsoft
|
Double check you've signed in with the right account. You may own Minecraft on a
|
||||||
account which isn't linked to Minecraft. Double check and try again!
|
different Microsoft account.
|
||||||
</p>
|
</p>
|
||||||
<h3>Try signing in and launching through the official launcher first</h3>
|
<div class="cta-button">
|
||||||
|
<button class="btn btn-primary" :disabled="loadingMinecraft" @click="loginMinecraft">
|
||||||
|
<LogInIcon /> Try another account
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<h3>Using PC Game Pass, coming from Bedrock, or just bought the game?</h3>
|
||||||
<p>
|
<p>
|
||||||
If you just bought Minecraft, are coming from the Bedrock Edition world and have never
|
Try signing in with the
|
||||||
played Java before, or just subscribed to PC Game Pass, you would need to start the
|
<a href="https://www.minecraft.net/en-us/download">official Minecraft Launcher</a>
|
||||||
game at least once using the
|
first. Once you're done, come back here and sign in!
|
||||||
<a href="https://www.minecraft.net/en-us/download">official Minecraft Launcher</a>.
|
|
||||||
Once you're done, come back here and sign in!
|
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
<div class="cta-button">
|
<div class="cta-button">
|
||||||
<button class="btn btn-primary" :disabled="loadingMinecraft" @click="loginMinecraft">
|
<button class="btn btn-primary" :disabled="loadingMinecraft" @click="loginMinecraft">
|
||||||
<LogInIcon /> Sign in to Minecraft
|
<LogInIcon /> Try signing in again
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="errorType === 'directory_move'">
|
||||||
|
<template v-if="metadata.readOnly">
|
||||||
|
<h3>Change directory permissions</h3>
|
||||||
|
<p>
|
||||||
|
It looks like the Modrinth App is unable to write to the directory you selected.
|
||||||
|
Please adjust the permissions of the directory and try again or cancel the directory
|
||||||
|
change.
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="metadata.notEnoughSpace">
|
||||||
|
<h3>Not enough space</h3>
|
||||||
|
<p>
|
||||||
|
It looks like there is not enough space on the disk containing the dirctory you
|
||||||
|
selected Please free up some space and try again or cancel the directory change.
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<p>
|
||||||
|
The Modrinth App is unable to migrate to the new directory you selected. Please
|
||||||
|
contact support for help or cancel the directory change.
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="cta-button">
|
||||||
|
<button class="btn" @click="retryDirectoryChange">
|
||||||
|
<UpdatedIcon /> Retry directory change
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-danger" @click="cancelDirectoryChange">
|
||||||
|
<XIcon /> Cancel directory change
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
|
||||||
<p>
|
|
||||||
If nothing is working and you need help, visit
|
|
||||||
<a :href="supportLink">our support page</a>
|
|
||||||
and start a chat using the widget in the bottom right and we will be more than happy to
|
|
||||||
assist!
|
|
||||||
</p>
|
|
||||||
<details>
|
|
||||||
<summary>Debug info</summary>
|
|
||||||
{{ error.message ?? error }}
|
|
||||||
</details>
|
|
||||||
</template>
|
</template>
|
||||||
<div v-else-if="errorType === 'minecraft_sign_in'">
|
<div v-else-if="errorType === 'minecraft_sign_in'">
|
||||||
<div class="warning-banner">
|
|
||||||
<div class="warning-banner__title">
|
|
||||||
<IssuesIcon />
|
|
||||||
<span>Installed the app before April 23rd, 2024?</span>
|
|
||||||
</div>
|
|
||||||
<div class="warning-banner__description">
|
|
||||||
Modrinth has updated our sign-in workflow to allow for better stability, security, and
|
|
||||||
performance. You must sign in again so your credentials can be upgraded to this new
|
|
||||||
flow.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p>
|
<p>
|
||||||
To play this instance, you must sign in through Microsoft below. If you don't have a
|
To play this instance, you must sign in through Microsoft below. If you don't have a
|
||||||
Minecraft account, you can purchase the game on the
|
Minecraft account, you can purchase the game on the
|
||||||
@@ -159,13 +223,53 @@ async function loginMinecraft() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<template v-else-if="errorType === 'state_init'">
|
||||||
|
<p>
|
||||||
|
Modrinth App failed to load correctly. This may be because of a corrupted file, or
|
||||||
|
because the app is missing crucial files.
|
||||||
|
</p>
|
||||||
|
<p>You may be able to fix it through one of the following ways:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Ennsuring you are connected to the internet, then try restarting the app.</li>
|
||||||
|
<li>Redownloading the app.</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="errorType === 'no_loader_version'">
|
||||||
|
<p>The Modrinth App failed to find the loader version for this instance.</p>
|
||||||
|
<p>To resolve this, you need to repair the instance. Click the button below to do so.</p>
|
||||||
|
<div class="cta-button">
|
||||||
|
<button class="btn btn-primary" :disabled="loadingRepair" @click="repairInstance">
|
||||||
|
<HammerIcon /> Repair instance
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ error.message ?? error }}
|
{{ error.message ?? error }}
|
||||||
</template>
|
</template>
|
||||||
|
<template
|
||||||
|
v-if="
|
||||||
|
errorType === 'directory_move' ||
|
||||||
|
errorType === 'minecraft_auth' ||
|
||||||
|
errorType === 'state_init' ||
|
||||||
|
errorType === 'no_loader_version'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<hr />
|
||||||
|
<p>
|
||||||
|
If nothing is working and you need help, visit
|
||||||
|
<a :href="supportLink">our support page</a>
|
||||||
|
and start a chat using the widget in the bottom right and we will be more than happy to
|
||||||
|
assist! Make sure to provide the following debug information to the agent:
|
||||||
|
</p>
|
||||||
|
<details>
|
||||||
|
<summary>Debug information</summary>
|
||||||
|
{{ error.message ?? error }}
|
||||||
|
</details>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group push-right">
|
<div class="input-group push-right">
|
||||||
<a :href="supportLink" class="btn" @click="errorModal.hide()"><ChatIcon /> Get support</a>
|
<a :href="supportLink" class="btn" @click="errorModal.hide()"><ChatIcon /> Get support</a>
|
||||||
<button class="btn" @click="errorModal.hide()"><XIcon /> Close</button>
|
<button v-if="closable" class="btn" @click="errorModal.hide()"><XIcon /> Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
@@ -188,6 +292,7 @@ async function loginMinecraft() {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning-banner {
|
.warning-banner {
|
||||||
@@ -220,4 +325,8 @@ async function loginMinecraft() {
|
|||||||
gap: var(--gap-md);
|
gap: var(--gap-md);
|
||||||
padding: var(--gap-lg);
|
padding: var(--gap-lg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.markdown-body {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
+8
-7
@@ -1,9 +1,10 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Button, Checkbox, Modal, XIcon, PlusIcon } from 'omorphia'
|
import { XIcon, PlusIcon } from '@modrinth/assets'
|
||||||
|
import { Button, Checkbox, Modal } from '@modrinth/ui'
|
||||||
import { PackageIcon, VersionIcon } from '@/assets/icons'
|
import { PackageIcon, VersionIcon } from '@/assets/icons'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { export_profile_mrpack, get_pack_export_candidates } from '@/helpers/profile.js'
|
import { export_profile_mrpack, get_pack_export_candidates } from '@/helpers/profile.js'
|
||||||
import { open } from '@tauri-apps/api/dialog'
|
import { open } from '@tauri-apps/plugin-dialog'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import { useTheming } from '@/store/theme'
|
import { useTheming } from '@/store/theme'
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ defineExpose({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const exportModal = ref(null)
|
const exportModal = ref(null)
|
||||||
const nameInput = ref(props.instance.metadata.name)
|
const nameInput = ref(props.instance.name)
|
||||||
const exportDescription = ref('')
|
const exportDescription = ref('')
|
||||||
const versionInput = ref('1.0.0')
|
const versionInput = ref('1.0.0')
|
||||||
const files = ref([])
|
const files = ref([])
|
||||||
@@ -49,9 +50,9 @@ const initFiles = async () => {
|
|||||||
disabled:
|
disabled:
|
||||||
folder === 'profile.json' ||
|
folder === 'profile.json' ||
|
||||||
folder.startsWith('modrinth_logs') ||
|
folder.startsWith('modrinth_logs') ||
|
||||||
folder.startsWith('.fabric') ||
|
folder.startsWith('.fabric'),
|
||||||
folder.includes('.DS_Store'),
|
|
||||||
}))
|
}))
|
||||||
|
.filter((pathData) => !pathData.path.includes('.DS_Store'))
|
||||||
.forEach((pathData) => {
|
.forEach((pathData) => {
|
||||||
const parent = pathData.path.split(sep).slice(0, -1).join(sep)
|
const parent = pathData.path.split(sep).slice(0, -1).join(sep)
|
||||||
if (parent !== '') {
|
if (parent !== '') {
|
||||||
@@ -112,7 +113,7 @@ const exportPack = async () => {
|
|||||||
<div class="iconified-input">
|
<div class="iconified-input">
|
||||||
<PackageIcon />
|
<PackageIcon />
|
||||||
<input v-model="nameInput" type="text" placeholder="Modpack name" class="input" />
|
<input v-model="nameInput" type="text" placeholder="Modpack name" class="input" />
|
||||||
<Button @click="nameInput = ''">
|
<Button class="r-btn" @click="nameInput = ''">
|
||||||
<XIcon />
|
<XIcon />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -122,7 +123,7 @@ const exportPack = async () => {
|
|||||||
<div class="iconified-input">
|
<div class="iconified-input">
|
||||||
<VersionIcon />
|
<VersionIcon />
|
||||||
<input v-model="versionInput" type="text" placeholder="1.0.0" class="input" />
|
<input v-model="versionInput" type="text" placeholder="1.0.0" class="input" />
|
||||||
<Button @click="versionInput = ''">
|
<Button class="r-btn" @click="versionInput = ''">
|
||||||
<XIcon />
|
<XIcon />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onUnmounted, ref, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { StopCircleIcon, PlayIcon } from '@modrinth/assets'
|
||||||
|
import { Card, Avatar, AnimatedLogo } from '@modrinth/ui'
|
||||||
|
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||||
|
import { kill, run } from '@/helpers/profile'
|
||||||
|
import { get_by_profile_path } from '@/helpers/process'
|
||||||
|
import { process_listener } from '@/helpers/events'
|
||||||
|
import { handleError } from '@/store/state.js'
|
||||||
|
import { showProfileInFolder } from '@/helpers/utils.js'
|
||||||
|
import { handleSevereError } from '@/store/error.js'
|
||||||
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
instance: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const playing = ref(false)
|
||||||
|
|
||||||
|
const modLoading = computed(() => props.instance.install_stage !== 'installed')
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const seeInstance = async () => {
|
||||||
|
await router.push(`/instance/${encodeURIComponent(props.instance.path)}/`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkProcess = async () => {
|
||||||
|
const runningProcesses = await get_by_profile_path(props.instance.path).catch(handleError)
|
||||||
|
|
||||||
|
playing.value = runningProcesses.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const play = async (e, context) => {
|
||||||
|
e?.stopPropagation()
|
||||||
|
modLoading.value = true
|
||||||
|
await run(props.instance.path).catch((err) =>
|
||||||
|
handleSevereError(err, { profilePath: props.instance.path }),
|
||||||
|
)
|
||||||
|
modLoading.value = false
|
||||||
|
|
||||||
|
trackEvent('InstancePlay', {
|
||||||
|
loader: props.instance.loader,
|
||||||
|
game_version: props.instance.game_version,
|
||||||
|
source: context,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const stop = async (e, context) => {
|
||||||
|
e?.stopPropagation()
|
||||||
|
playing.value = false
|
||||||
|
|
||||||
|
await kill(props.instance.path).catch(handleError)
|
||||||
|
|
||||||
|
trackEvent('InstanceStop', {
|
||||||
|
loader: props.instance.loader,
|
||||||
|
game_version: props.instance.game_version,
|
||||||
|
source: context,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const openFolder = async () => {
|
||||||
|
await showProfileInFolder(props.instance.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
const addContent = async () => {
|
||||||
|
await router.push({
|
||||||
|
path: `/browse/${props.instance.loader === 'vanilla' ? 'datapack' : 'mod'}`,
|
||||||
|
query: { i: props.instance.path },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
play,
|
||||||
|
stop,
|
||||||
|
seeInstance,
|
||||||
|
openFolder,
|
||||||
|
addContent,
|
||||||
|
instance: props.instance,
|
||||||
|
})
|
||||||
|
|
||||||
|
const unlisten = await process_listener((e) => {
|
||||||
|
if (e.event === 'finished' && e.profile_path_id === props.instance.path) playing.value = false
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => unlisten())
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="instance">
|
||||||
|
<Card class="instance-card-item button-base" @click="seeInstance" @mouseenter="checkProcess">
|
||||||
|
<Avatar
|
||||||
|
size="lg"
|
||||||
|
:src="props.instance.icon_path ? convertFileSrc(props.instance.icon_path) : null"
|
||||||
|
alt="Mod card"
|
||||||
|
class="mod-image"
|
||||||
|
/>
|
||||||
|
<div class="project-info">
|
||||||
|
<p class="title">{{ props.instance.name }}</p>
|
||||||
|
<p
|
||||||
|
v-if="
|
||||||
|
props.instance.install_stage === 'installing' ||
|
||||||
|
props.instance.install_stage === 'not_installed' ||
|
||||||
|
props.instance.install_stage === 'pack_installing'
|
||||||
|
"
|
||||||
|
class="description"
|
||||||
|
>
|
||||||
|
Installing...
|
||||||
|
</p>
|
||||||
|
<p v-else class="description">
|
||||||
|
{{ props.instance.loader }}
|
||||||
|
{{ props.instance.game_version }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
<div
|
||||||
|
v-if="playing === true"
|
||||||
|
class="stop cta button-base"
|
||||||
|
@click="(e) => stop(e, 'InstanceCard')"
|
||||||
|
@mousehover="checkProcess"
|
||||||
|
>
|
||||||
|
<StopCircleIcon />
|
||||||
|
</div>
|
||||||
|
<div v-else-if="modLoading === true && playing === false" class="cta loading-cta">
|
||||||
|
<AnimatedLogo class="loading-indicator" />
|
||||||
|
</div>
|
||||||
|
<div v-else class="install cta button-base" @click="(e) => play(e, 'InstanceCard')">
|
||||||
|
<PlayIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.loading-indicator {
|
||||||
|
width: 2.5rem !important;
|
||||||
|
height: 2.5rem !important;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 2.5rem !important;
|
||||||
|
height: 2.5rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.instance {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.cta {
|
||||||
|
opacity: 1;
|
||||||
|
bottom: calc(var(--gap-md) + 4.25rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
z-index: 1;
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
right: calc(var(--gap-md) * 2);
|
||||||
|
bottom: 3.25rem;
|
||||||
|
opacity: 0;
|
||||||
|
transition:
|
||||||
|
0.2s ease-in-out bottom,
|
||||||
|
0.2s ease-in-out opacity,
|
||||||
|
0.1s ease-in-out filter !important;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: var(--shadow-floating);
|
||||||
|
|
||||||
|
svg {
|
||||||
|
color: var(--color-accent-contrast);
|
||||||
|
width: 1.5rem !important;
|
||||||
|
height: 1.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.install {
|
||||||
|
background: var(--color-brand);
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.stop {
|
||||||
|
background: var(--color-red);
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.loading-cta {
|
||||||
|
background: hsl(220, 11%, 10%) !important;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.instance-card-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: var(--gap-md);
|
||||||
|
transition: 0.1s ease-in-out all !important; /* overrides Omorphia defaults */
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
.mod-image {
|
||||||
|
--size: 100%;
|
||||||
|
|
||||||
|
width: 100% !important;
|
||||||
|
height: auto !important;
|
||||||
|
max-width: unset !important;
|
||||||
|
max-height: unset !important;
|
||||||
|
aspect-ratio: 1 / 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-info {
|
||||||
|
margin-top: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: var(--color-contrast);
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 110%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
color: var(--color-base);
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.775rem;
|
||||||
|
line-height: 125%;
|
||||||
|
margin: 0.25rem 0 0;
|
||||||
|
text-transform: capitalize;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+16
-26
@@ -110,7 +110,7 @@
|
|||||||
placeholder="Path to launcher"
|
placeholder="Path to launcher"
|
||||||
@change="setPath"
|
@change="setPath"
|
||||||
/>
|
/>
|
||||||
<Button @click="() => (selectedLauncherPath = '')">
|
<Button class="r-btn" @click="() => (selectedLauncherPath = '')">
|
||||||
<XIcon />
|
<XIcon />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -198,35 +198,25 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
Avatar,
|
|
||||||
Button,
|
|
||||||
Chips,
|
|
||||||
Modal,
|
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
UploadIcon,
|
UploadIcon,
|
||||||
XIcon,
|
XIcon,
|
||||||
CodeIcon,
|
CodeIcon,
|
||||||
Checkbox,
|
|
||||||
FolderOpenIcon,
|
FolderOpenIcon,
|
||||||
InfoIcon,
|
InfoIcon,
|
||||||
FolderSearchIcon,
|
FolderSearchIcon,
|
||||||
UpdatedIcon,
|
UpdatedIcon,
|
||||||
} from 'omorphia'
|
} from '@modrinth/assets'
|
||||||
|
import { Avatar, Button, Chips, Modal, Checkbox } from '@modrinth/ui'
|
||||||
import { computed, onUnmounted, ref, shallowRef } from 'vue'
|
import { computed, onUnmounted, ref, shallowRef } from 'vue'
|
||||||
import { get_loaders } from '@/helpers/tags'
|
import { get_loaders } from '@/helpers/tags'
|
||||||
import { create } from '@/helpers/profile'
|
import { create } from '@/helpers/profile'
|
||||||
import { open } from '@tauri-apps/api/dialog'
|
import { open } from '@tauri-apps/plugin-dialog'
|
||||||
import { tauri } from '@tauri-apps/api'
|
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||||
import {
|
import { get_game_versions, get_loader_versions } from '@/helpers/metadata'
|
||||||
get_game_versions,
|
|
||||||
get_fabric_versions,
|
|
||||||
get_forge_versions,
|
|
||||||
get_quilt_versions,
|
|
||||||
get_neoforge_versions,
|
|
||||||
} from '@/helpers/metadata'
|
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import Multiselect from 'vue-multiselect'
|
import Multiselect from 'vue-multiselect'
|
||||||
import { mixpanel_track } from '@/helpers/mixpanel'
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
import { useTheming } from '@/store/state.js'
|
import { useTheming } from '@/store/state.js'
|
||||||
import { listen } from '@tauri-apps/api/event'
|
import { listen } from '@tauri-apps/api/event'
|
||||||
import { install_from_file } from '@/helpers/pack.js'
|
import { install_from_file } from '@/helpers/pack.js'
|
||||||
@@ -274,13 +264,13 @@ defineExpose({
|
|||||||
hide()
|
hide()
|
||||||
if (event.payload && event.payload.length > 0 && event.payload[0].endsWith('.mrpack')) {
|
if (event.payload && event.payload.length > 0 && event.payload[0].endsWith('.mrpack')) {
|
||||||
await install_from_file(event.payload[0]).catch(handleError)
|
await install_from_file(event.payload[0]).catch(handleError)
|
||||||
mixpanel_track('InstanceCreate', {
|
trackEvent('InstanceCreate', {
|
||||||
source: 'CreationModalFileDrop',
|
source: 'CreationModalFileDrop',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
mixpanel_track('InstanceCreateStart', { source: 'CreationModal' })
|
trackEvent('InstanceCreateStart', { source: 'CreationModal' })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -308,10 +298,10 @@ const [
|
|||||||
all_game_versions,
|
all_game_versions,
|
||||||
loaders,
|
loaders,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
get_fabric_versions().then(shallowRef).catch(handleError),
|
get_loader_versions('fabric').then(shallowRef).catch(handleError),
|
||||||
get_forge_versions().then(shallowRef).catch(handleError),
|
get_loader_versions('forge').then(shallowRef).catch(handleError),
|
||||||
get_quilt_versions().then(shallowRef).catch(handleError),
|
get_loader_versions('quilt').then(shallowRef).catch(handleError),
|
||||||
get_neoforge_versions().then(shallowRef).catch(handleError),
|
get_loader_versions('neo').then(shallowRef).catch(handleError),
|
||||||
get_game_versions().then(shallowRef).catch(handleError),
|
get_game_versions().then(shallowRef).catch(handleError),
|
||||||
get_loaders()
|
get_loaders()
|
||||||
.then((value) =>
|
.then((value) =>
|
||||||
@@ -370,7 +360,7 @@ const create_instance = async () => {
|
|||||||
icon.value,
|
icon.value,
|
||||||
).catch(handleError)
|
).catch(handleError)
|
||||||
|
|
||||||
mixpanel_track('InstanceCreate', {
|
trackEvent('InstanceCreate', {
|
||||||
profile_name: profile_name.value,
|
profile_name: profile_name.value,
|
||||||
game_version: game_version.value,
|
game_version: game_version.value,
|
||||||
loader: loader.value,
|
loader: loader.value,
|
||||||
@@ -392,7 +382,7 @@ const upload_icon = async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!icon.value) return
|
if (!icon.value) return
|
||||||
display_icon.value = tauri.convertFileSrc(icon.value)
|
display_icon.value = convertFileSrc(icon.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const reset_icon = () => {
|
const reset_icon = () => {
|
||||||
@@ -429,7 +419,7 @@ const openFile = async () => {
|
|||||||
hide()
|
hide()
|
||||||
await install_from_file(newProject).catch(handleError)
|
await install_from_file(newProject).catch(handleError)
|
||||||
|
|
||||||
mixpanel_track('InstanceCreate', {
|
trackEvent('InstanceCreate', {
|
||||||
source: 'CreationModalFileOpen',
|
source: 'CreationModalFileOpen',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
+4
-6
@@ -35,12 +35,13 @@
|
|||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Modal, PlusIcon, CheckIcon, Button, XIcon } from 'omorphia'
|
import { PlusIcon, CheckIcon, XIcon } from '@modrinth/assets'
|
||||||
|
import { Modal, Button } from '@modrinth/ui'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { find_filtered_jres } from '@/helpers/jre.js'
|
import { find_filtered_jres } from '@/helpers/jre.js'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import { mixpanel_track } from '@/helpers/mixpanel'
|
|
||||||
import { useTheming } from '@/store/theme.js'
|
import { useTheming } from '@/store/theme.js'
|
||||||
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
|
|
||||||
const themeStore = useTheming()
|
const themeStore = useTheming()
|
||||||
|
|
||||||
@@ -52,9 +53,6 @@ defineExpose({
|
|||||||
show: async (version, currentSelectedJava) => {
|
show: async (version, currentSelectedJava) => {
|
||||||
chosenInstallOptions.value = await find_filtered_jres(version).catch(handleError)
|
chosenInstallOptions.value = await find_filtered_jres(version).catch(handleError)
|
||||||
|
|
||||||
console.log(chosenInstallOptions.value)
|
|
||||||
console.log(version)
|
|
||||||
|
|
||||||
currentSelected.value = currentSelectedJava
|
currentSelected.value = currentSelectedJava
|
||||||
if (!currentSelected.value) {
|
if (!currentSelected.value) {
|
||||||
currentSelected.value = { path: '', version: '' }
|
currentSelected.value = { path: '', version: '' }
|
||||||
@@ -69,7 +67,7 @@ const emit = defineEmits(['submit'])
|
|||||||
function setJavaInstall(javaInstall) {
|
function setJavaInstall(javaInstall) {
|
||||||
emit('submit', javaInstall)
|
emit('submit', javaInstall)
|
||||||
detectJavaModal.value.hide()
|
detectJavaModal.value.hide()
|
||||||
mixpanel_track('JavaAutoDetect', {
|
trackEvent('JavaAutoDetect', {
|
||||||
path: javaInstall.path,
|
path: javaInstall.path,
|
||||||
version: javaInstall.version,
|
version: javaInstall.version,
|
||||||
})
|
})
|
||||||
+11
-8
@@ -53,20 +53,20 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
SearchIcon,
|
SearchIcon,
|
||||||
PlayIcon,
|
PlayIcon,
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
XIcon,
|
XIcon,
|
||||||
FolderSearchIcon,
|
FolderSearchIcon,
|
||||||
DownloadIcon,
|
DownloadIcon,
|
||||||
} from 'omorphia'
|
} from '@modrinth/assets'
|
||||||
|
import { Button } from '@modrinth/ui'
|
||||||
import { auto_install_java, find_filtered_jres, get_jre, test_jre } from '@/helpers/jre.js'
|
import { auto_install_java, find_filtered_jres, get_jre, test_jre } from '@/helpers/jre.js'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { open } from '@tauri-apps/api/dialog'
|
import { open } from '@tauri-apps/plugin-dialog'
|
||||||
import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue'
|
import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue'
|
||||||
import { mixpanel_track } from '@/helpers/mixpanel'
|
|
||||||
import { handleError } from '@/store/state.js'
|
import { handleError } from '@/store/state.js'
|
||||||
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
version: {
|
version: {
|
||||||
@@ -113,7 +113,7 @@ async function testJava() {
|
|||||||
)
|
)
|
||||||
testingJava.value = false
|
testingJava.value = false
|
||||||
|
|
||||||
mixpanel_track('JavaTest', {
|
trackEvent('JavaTest', {
|
||||||
path: props.modelValue ? props.modelValue.path : '',
|
path: props.modelValue ? props.modelValue.path : '',
|
||||||
success: testingJavaSuccess.value,
|
success: testingJavaSuccess.value,
|
||||||
})
|
})
|
||||||
@@ -136,7 +136,7 @@ async function handleJavaFileInput() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mixpanel_track('JavaManualSelect', {
|
trackEvent('JavaManualSelect', {
|
||||||
path: filePath,
|
path: filePath,
|
||||||
version: props.version,
|
version: props.version,
|
||||||
})
|
})
|
||||||
@@ -162,7 +162,6 @@ async function reinstallJava() {
|
|||||||
const path = await auto_install_java(props.version).catch(handleError)
|
const path = await auto_install_java(props.version).catch(handleError)
|
||||||
let result = await get_jre(path)
|
let result = await get_jre(path)
|
||||||
|
|
||||||
console.log('java result ' + result)
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
result = {
|
result = {
|
||||||
path: path,
|
path: path,
|
||||||
@@ -171,7 +170,7 @@ async function reinstallJava() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mixpanel_track('JavaReInstall', {
|
trackEvent('JavaReInstall', {
|
||||||
path: path,
|
path: path,
|
||||||
version: props.version,
|
version: props.version,
|
||||||
})
|
})
|
||||||
@@ -205,6 +204,10 @@ async function reinstallJava() {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: max-content;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.test-success {
|
.test-success {
|
||||||
+4
-3
@@ -1,5 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Button, Modal, CheckIcon, Badge } from 'omorphia'
|
import { CheckIcon } from '@modrinth/assets'
|
||||||
|
import { Button, Modal, Badge } from '@modrinth/ui'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useTheming } from '@/store/theme'
|
import { useTheming } from '@/store/theme'
|
||||||
import { update_managed_modrinth_version } from '@/helpers/profile'
|
import { update_managed_modrinth_version } from '@/helpers/profile'
|
||||||
@@ -28,7 +29,7 @@ const filteredVersions = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const modpackVersionModal = ref(null)
|
const modpackVersionModal = ref(null)
|
||||||
const installedVersion = computed(() => props.instance?.metadata?.linked_data?.version_id)
|
const installedVersion = computed(() => props.instance?.linked_data?.version_id)
|
||||||
const installing = computed(() => props.instance.install_stage !== 'installed')
|
const installing = computed(() => props.instance.install_stage !== 'installed')
|
||||||
const inProgress = ref(false)
|
const inProgress = ref(false)
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ const switchVersion = async (versionId) => {
|
|||||||
:noblur="!themeStore.advancedRendering"
|
:noblur="!themeStore.advancedRendering"
|
||||||
>
|
>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<Card v-if="instance.metadata.linked_data" class="mod-card">
|
<Card v-if="instance.linked_data" class="mod-card">
|
||||||
<div class="table">
|
<div class="table">
|
||||||
<div class="table-row with-columns table-head">
|
<div class="table-row with-columns table-head">
|
||||||
<div class="table-cell table-text download-cell" />
|
<div class="table-cell table-text download-cell" />
|
||||||
File renamed without changes.
+13
-59
@@ -1,22 +1,13 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import { Card, Avatar, Button } from '@modrinth/ui'
|
||||||
Card,
|
import { DownloadIcon, HeartIcon, CalendarIcon } from '@modrinth/assets'
|
||||||
Avatar,
|
import { formatNumber, formatCategory } from '@modrinth/utils'
|
||||||
Button,
|
|
||||||
formatNumber,
|
|
||||||
formatCategory,
|
|
||||||
DownloadIcon,
|
|
||||||
HeartIcon,
|
|
||||||
CalendarIcon,
|
|
||||||
} from 'omorphia'
|
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useFetch } from '@/helpers/fetch.js'
|
import { install as installVersion } from '@/store/install.js'
|
||||||
import { list } from '@/helpers/profile.js'
|
|
||||||
import { handleError } from '@/store/notifications.js'
|
|
||||||
import { install as pack_install } from '@/helpers/pack.js'
|
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -29,18 +20,6 @@ const props = defineProps({
|
|||||||
return {}
|
return {}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
confirmModal: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
modInstallModal: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const toColor = computed(() => {
|
const toColor = computed(() => {
|
||||||
@@ -72,40 +51,15 @@ const toTransparent = computed(() => {
|
|||||||
const install = async (e) => {
|
const install = async (e) => {
|
||||||
e?.stopPropagation()
|
e?.stopPropagation()
|
||||||
installing.value = true
|
installing.value = true
|
||||||
const versions = await useFetch(
|
await installVersion(
|
||||||
`https://api.modrinth.com/v2/project/${props.project.project_id}/version`,
|
props.project.project_id,
|
||||||
'project versions',
|
null,
|
||||||
)
|
props.instance ? props.instance.path : null,
|
||||||
|
'ProjectCard',
|
||||||
if (props.project.project_type === 'modpack') {
|
() => {
|
||||||
const packs = Object.values(await list(true).catch(handleError))
|
|
||||||
|
|
||||||
if (
|
|
||||||
packs.length === 0 ||
|
|
||||||
!packs
|
|
||||||
.map((value) => value.metadata)
|
|
||||||
.find((pack) => pack.linked_data?.project_id === props.project.project_id)
|
|
||||||
) {
|
|
||||||
installing.value = true
|
|
||||||
await pack_install(
|
|
||||||
props.project.project_id,
|
|
||||||
versions[0].id,
|
|
||||||
props.project.title,
|
|
||||||
props.project.icon_url,
|
|
||||||
).catch(handleError)
|
|
||||||
installing.value = false
|
installing.value = false
|
||||||
} else
|
},
|
||||||
props.confirmModal.show(
|
)
|
||||||
props.project.project_id,
|
|
||||||
versions[0].id,
|
|
||||||
props.project.title,
|
|
||||||
props.project.icon_url,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
props.modInstallModal.show(props.project.project_id, versions)
|
|
||||||
}
|
|
||||||
|
|
||||||
installing.value = false
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Promotion } from '@modrinth/ui'
|
||||||
|
import { get as getCreds } from '@/helpers/mr_auth.js'
|
||||||
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
import { get_user } from '@/helpers/cache.js'
|
||||||
|
|
||||||
|
const showAd = ref(true)
|
||||||
|
|
||||||
|
const creds = await getCreds().catch(handleError)
|
||||||
|
if (creds && creds.user_id) {
|
||||||
|
const user = await get_user(creds.user_id).catch(handleError)
|
||||||
|
|
||||||
|
const MIDAS_BITFLAG = 1 << 0
|
||||||
|
if (user && (user.badges & MIDAS_BITFLAG) === MIDAS_BITFLAG) {
|
||||||
|
showAd.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Promotion v-if="showAd" :external="false" query-param="?r=launcher" />
|
||||||
|
</template>
|
||||||
+60
-57
@@ -15,15 +15,15 @@
|
|||||||
</Button>
|
</Button>
|
||||||
<div v-if="offline" class="status">
|
<div v-if="offline" class="status">
|
||||||
<span class="circle stopped" />
|
<span class="circle stopped" />
|
||||||
<div class="running-text clickable" @click="refreshInternet()">
|
<div class="running-text">
|
||||||
<span> Offline </span>
|
<span> Offline </span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedProfile" class="status">
|
<div v-if="selectedProcess" class="status">
|
||||||
<span class="circle running" />
|
<span class="circle running" />
|
||||||
<div ref="profileButton" class="running-text">
|
<div ref="profileButton" class="running-text">
|
||||||
<router-link :to="`/instance/${encodeURIComponent(selectedProfile.path)}`">
|
<router-link :to="`/instance/${encodeURIComponent(selectedProcess.profile.path)}`">
|
||||||
{{ selectedProfile.metadata.name }}
|
{{ selectedProcess.profile.name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<div
|
<div
|
||||||
v-if="currentProcesses.length > 1"
|
v-if="currentProcesses.length > 1"
|
||||||
@@ -34,7 +34,12 @@
|
|||||||
<DropdownIcon />
|
<DropdownIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button v-tooltip="'Stop instance'" icon-only class="icon-button stop" @click="stop()">
|
<Button
|
||||||
|
v-tooltip="'Stop instance'"
|
||||||
|
icon-only
|
||||||
|
class="icon-button stop"
|
||||||
|
@click="stop(selectedProcess)"
|
||||||
|
>
|
||||||
<StopCircleIcon />
|
<StopCircleIcon />
|
||||||
</Button>
|
</Button>
|
||||||
<Button v-tooltip="'View logs'" icon-only class="icon-button" @click="goToTerminal()">
|
<Button v-tooltip="'View logs'" icon-only class="icon-button" @click="goToTerminal()">
|
||||||
@@ -75,17 +80,17 @@
|
|||||||
class="profile-card"
|
class="profile-card"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
v-for="profile in currentProcesses"
|
v-for="process in currentProcesses"
|
||||||
:key="profile.id"
|
:key="process.uuid"
|
||||||
class="profile-button"
|
class="profile-button"
|
||||||
@click="selectProfile(profile)"
|
@click="selectProcess(process)"
|
||||||
>
|
>
|
||||||
<div class="text"><span class="circle running" /> {{ profile.metadata.name }}</div>
|
<div class="text"><span class="circle running" /> {{ process.profile.name }}</div>
|
||||||
<Button
|
<Button
|
||||||
v-tooltip="'Stop instance'"
|
v-tooltip="'Stop instance'"
|
||||||
icon-only
|
icon-only
|
||||||
class="icon-button stop"
|
class="icon-button stop"
|
||||||
@click.stop="stop(profile.path)"
|
@click.stop="stop(process)"
|
||||||
>
|
>
|
||||||
<StopCircleIcon />
|
<StopCircleIcon />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -93,7 +98,7 @@
|
|||||||
v-tooltip="'View logs'"
|
v-tooltip="'View logs'"
|
||||||
icon-only
|
icon-only
|
||||||
class="icon-button"
|
class="icon-button"
|
||||||
@click.stop="goToTerminal(profile.path)"
|
@click.stop="goToTerminal(process.profile.path)"
|
||||||
>
|
>
|
||||||
<TerminalSquareIcon />
|
<TerminalSquareIcon />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -103,28 +108,18 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import { DownloadIcon, StopCircleIcon, TerminalSquareIcon, DropdownIcon } from '@modrinth/assets'
|
||||||
Button,
|
import { Button, Card } from '@modrinth/ui'
|
||||||
DownloadIcon,
|
|
||||||
Card,
|
|
||||||
StopCircleIcon,
|
|
||||||
TerminalSquareIcon,
|
|
||||||
DropdownIcon,
|
|
||||||
} from 'omorphia'
|
|
||||||
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
||||||
import {
|
import { get_all as getRunningProcesses, kill as killProcess } from '@/helpers/process'
|
||||||
get_all_running_profiles as getRunningProfiles,
|
import { loading_listener, process_listener } from '@/helpers/events'
|
||||||
kill_by_uuid as killProfile,
|
|
||||||
get_uuids_by_profile_path as getProfileProcesses,
|
|
||||||
} from '@/helpers/process'
|
|
||||||
import { loading_listener, process_listener, offline_listener } from '@/helpers/events'
|
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { progress_bars_list } from '@/helpers/state.js'
|
import { progress_bars_list } from '@/helpers/state.js'
|
||||||
import { refreshOffline, isOffline } from '@/helpers/utils.js'
|
|
||||||
import ProgressBar from '@/components/ui/ProgressBar.vue'
|
import ProgressBar from '@/components/ui/ProgressBar.vue'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import { mixpanel_track } from '@/helpers/mixpanel'
|
|
||||||
import { ChatIcon } from '@/assets/icons'
|
import { ChatIcon } from '@/assets/icons'
|
||||||
|
import { get_many } from '@/helpers/profile.js'
|
||||||
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const card = ref(null)
|
const card = ref(null)
|
||||||
@@ -135,38 +130,43 @@ const showCard = ref(false)
|
|||||||
|
|
||||||
const showProfiles = ref(false)
|
const showProfiles = ref(false)
|
||||||
|
|
||||||
const currentProcesses = ref(await getRunningProfiles().catch(handleError))
|
const currentProcesses = ref([])
|
||||||
const selectedProfile = ref(currentProcesses.value[0])
|
const selectedProcess = ref()
|
||||||
|
|
||||||
const offline = ref(await isOffline().catch(handleError))
|
const refresh = async () => {
|
||||||
const refreshInternet = async () => {
|
const processes = await getRunningProcesses().catch(handleError)
|
||||||
offline.value = await refreshOffline().catch(handleError)
|
const profiles = await get_many(processes.map((x) => x.profile_path)).catch(handleError)
|
||||||
|
|
||||||
|
currentProcesses.value = processes.map((x) => ({
|
||||||
|
profile: profiles.find((prof) => x.profile_path === prof.path),
|
||||||
|
...x,
|
||||||
|
}))
|
||||||
|
if (!selectedProcess.value || !currentProcesses.value.includes(selectedProcess.value)) {
|
||||||
|
selectedProcess.value = currentProcesses.value[0]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await refresh()
|
||||||
|
|
||||||
|
const offline = ref(!navigator.onLine)
|
||||||
|
window.addEventListener('offline', () => {
|
||||||
|
offline.value = true
|
||||||
|
})
|
||||||
|
window.addEventListener('online', () => {
|
||||||
|
offline.value = false
|
||||||
|
})
|
||||||
|
|
||||||
const unlistenProcess = await process_listener(async () => {
|
const unlistenProcess = await process_listener(async () => {
|
||||||
await refresh()
|
await refresh()
|
||||||
})
|
})
|
||||||
|
|
||||||
const unlistenRefresh = await offline_listener(async (b) => {
|
const stop = async (process) => {
|
||||||
offline.value = b
|
|
||||||
await refresh()
|
|
||||||
})
|
|
||||||
|
|
||||||
const refresh = async () => {
|
|
||||||
currentProcesses.value = await getRunningProfiles().catch(handleError)
|
|
||||||
if (!currentProcesses.value.includes(selectedProfile.value)) {
|
|
||||||
selectedProfile.value = currentProcesses.value[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const stop = async (path) => {
|
|
||||||
try {
|
try {
|
||||||
const processes = await getProfileProcesses(path ?? selectedProfile.value.path)
|
await killProcess(process.uuid).catch(handleError)
|
||||||
await killProfile(processes[0])
|
|
||||||
|
|
||||||
mixpanel_track('InstanceStop', {
|
trackEvent('InstanceStop', {
|
||||||
loader: currentProcesses.value[0].metadata.loader,
|
loader: process.profile.loader,
|
||||||
game_version: currentProcesses.value[0].metadata.game_version,
|
game_version: process.profile.game_version,
|
||||||
source: 'AppBar',
|
source: 'AppBar',
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -176,7 +176,7 @@ const stop = async (path) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const goToTerminal = (path) => {
|
const goToTerminal = (path) => {
|
||||||
router.push(`/instance/${encodeURIComponent(path ?? selectedProfile.value.path)}/logs`)
|
router.push(`/instance/${encodeURIComponent(path ?? selectedProcess.value.profile.path)}/logs`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentLoadingBars = ref([])
|
const currentLoadingBars = ref([])
|
||||||
@@ -188,8 +188,8 @@ const refreshInfo = async () => {
|
|||||||
if (x.bar_type.type === 'java_download') {
|
if (x.bar_type.type === 'java_download') {
|
||||||
x.title = 'Downloading Java ' + x.bar_type.version
|
x.title = 'Downloading Java ' + x.bar_type.version
|
||||||
}
|
}
|
||||||
if (x.bar_type.profile_name) {
|
if (x.bar_type.profile_path) {
|
||||||
x.title = x.bar_type.profile_name
|
x.title = x.bar_type.profile_path
|
||||||
}
|
}
|
||||||
if (x.bar_type.pack_name) {
|
if (x.bar_type.pack_name) {
|
||||||
x.title = x.bar_type.pack_name
|
x.title = x.bar_type.pack_name
|
||||||
@@ -221,8 +221,8 @@ const unlistenLoading = await loading_listener(async () => {
|
|||||||
await refreshInfo()
|
await refreshInfo()
|
||||||
})
|
})
|
||||||
|
|
||||||
const selectProfile = (profile) => {
|
const selectProcess = (process) => {
|
||||||
selectedProfile.value = profile
|
selectedProcess.value = process
|
||||||
showProfiles.value = false
|
showProfiles.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +273,6 @@ onBeforeUnmount(() => {
|
|||||||
window.removeEventListener('click', handleClickOutsideProfile)
|
window.removeEventListener('click', handleClickOutsideProfile)
|
||||||
unlistenProcess()
|
unlistenProcess()
|
||||||
unlistenLoading()
|
unlistenLoading()
|
||||||
unlistenRefresh()
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -341,8 +340,12 @@ onBeforeUnmount(() => {
|
|||||||
width: 1.25rem !important;
|
width: 1.25rem !important;
|
||||||
height: 1.25rem !important;
|
height: 1.25rem !important;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
min-width: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
&.stop {
|
&.stop {
|
||||||
--text-color: var(--color-red) !important;
|
color: var(--color-red);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+15
-117
@@ -63,29 +63,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import { DownloadIcon, HeartIcon, CalendarIcon, CheckIcon, StarIcon } from '@modrinth/assets'
|
||||||
Avatar,
|
import { Avatar, Card, Categories, EnvironmentIndicator, Button } from '@modrinth/ui'
|
||||||
Card,
|
import { formatNumber, formatCategory } from '@modrinth/utils'
|
||||||
Categories,
|
|
||||||
EnvironmentIndicator,
|
|
||||||
Button,
|
|
||||||
DownloadIcon,
|
|
||||||
formatNumber,
|
|
||||||
formatCategory,
|
|
||||||
HeartIcon,
|
|
||||||
CalendarIcon,
|
|
||||||
CheckIcon,
|
|
||||||
StarIcon,
|
|
||||||
} from 'omorphia'
|
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { add_project_from_version as installMod, list } from '@/helpers/profile.js'
|
import { install as installVersion } from '@/store/install.js'
|
||||||
import { install as packInstall } from '@/helpers/pack.js'
|
|
||||||
import { installVersionDependencies } from '@/helpers/utils.js'
|
|
||||||
import { useFetch } from '@/helpers/fetch.js'
|
|
||||||
import { handleError } from '@/store/notifications.js'
|
|
||||||
import { mixpanel_track } from '@/helpers/mixpanel'
|
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -105,18 +89,6 @@ const props = defineProps({
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
confirmModal: {
|
|
||||||
type: Object,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
modInstallModal: {
|
|
||||||
type: Object,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
incompatibilityWarningModal: {
|
|
||||||
type: Object,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
featured: {
|
featured: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
@@ -134,93 +106,19 @@ const installed = ref(props.installed)
|
|||||||
|
|
||||||
async function install() {
|
async function install() {
|
||||||
installing.value = true
|
installing.value = true
|
||||||
const versions = await useFetch(
|
await installVersion(
|
||||||
`https://api.modrinth.com/v2/project/${props.project.project_id}/version`,
|
props.project.project_id,
|
||||||
'project versions',
|
null,
|
||||||
)
|
props.instance ? props.instance.path : null,
|
||||||
let queuedVersionData
|
'SearchCard',
|
||||||
|
(version) => {
|
||||||
if (!props.instance) {
|
|
||||||
queuedVersionData = versions[0]
|
|
||||||
} else {
|
|
||||||
queuedVersionData = versions.find(
|
|
||||||
(v) =>
|
|
||||||
v.game_versions.includes(props.instance.metadata.game_version) &&
|
|
||||||
(props.project.project_type !== 'mod' ||
|
|
||||||
v.loaders.includes(props.instance.metadata.loader)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.project.project_type === 'modpack') {
|
|
||||||
const packs = Object.values(await list().catch(handleError))
|
|
||||||
if (
|
|
||||||
packs.length === 0 ||
|
|
||||||
!packs
|
|
||||||
.map((value) => value.metadata)
|
|
||||||
.find((pack) => pack.linked_data?.project_id === props.project.project_id)
|
|
||||||
) {
|
|
||||||
await packInstall(
|
|
||||||
props.project.project_id,
|
|
||||||
queuedVersionData.id,
|
|
||||||
props.project.title,
|
|
||||||
props.project.icon_url,
|
|
||||||
).catch(handleError)
|
|
||||||
|
|
||||||
mixpanel_track('PackInstall', {
|
|
||||||
id: props.project.project_id,
|
|
||||||
version_id: queuedVersionData.id,
|
|
||||||
title: props.project.title,
|
|
||||||
source: 'SearchCard',
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
props.confirmModal.show(
|
|
||||||
props.project.project_id,
|
|
||||||
queuedVersionData.id,
|
|
||||||
props.project.title,
|
|
||||||
props.project.icon_url,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (props.instance) {
|
|
||||||
if (!queuedVersionData) {
|
|
||||||
props.incompatibilityWarningModal.show(
|
|
||||||
props.instance,
|
|
||||||
props.project.title,
|
|
||||||
versions,
|
|
||||||
() => (installed.value = true),
|
|
||||||
props.project.project_id,
|
|
||||||
props.project.project_type,
|
|
||||||
)
|
|
||||||
installing.value = false
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
await installMod(props.instance.path, queuedVersionData.id).catch(handleError)
|
|
||||||
await installVersionDependencies(props.instance, queuedVersionData)
|
|
||||||
|
|
||||||
mixpanel_track('ProjectInstall', {
|
|
||||||
loader: props.instance.metadata.loader,
|
|
||||||
game_version: props.instance.metadata.game_version,
|
|
||||||
id: props.project.project_id,
|
|
||||||
project_type: props.project.project_type,
|
|
||||||
version_id: queuedVersionData.id,
|
|
||||||
title: props.project.title,
|
|
||||||
source: 'SearchCard',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
props.modInstallModal.show(
|
|
||||||
props.project.project_id,
|
|
||||||
versions,
|
|
||||||
props.project.title,
|
|
||||||
props.project.project_type,
|
|
||||||
)
|
|
||||||
installing.value = false
|
installing.value = false
|
||||||
return
|
|
||||||
}
|
|
||||||
if (props.instance) installed.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
installing.value = false
|
if (props.instance && version) {
|
||||||
|
installed.value = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="!hidden" class="splash-screen dark" :class="{ 'fade-out': doneLoading }">
|
||||||
|
<div v-if="os !== 'MacOS'" class="app-buttons">
|
||||||
|
<button class="btn icon-only transparent" icon-only @click="() => getCurrent().minimize()">
|
||||||
|
<MinimizeIcon />
|
||||||
|
</button>
|
||||||
|
<button class="btn icon-only transparent" @click="() => getCurrent().toggleMaximize()">
|
||||||
|
<MaximizeIcon />
|
||||||
|
</button>
|
||||||
|
<button class="btn icon-only transparent" @click="handleClose">
|
||||||
|
<XIcon />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="app-logo-wrapper" data-tauri-drag-region>
|
||||||
|
<svg
|
||||||
|
class="app-logo"
|
||||||
|
viewBox="0 0 1215 175"
|
||||||
|
xml:space="preserve"
|
||||||
|
style="fill-rule: evenodd; clip-rule: evenodd; stroke-linejoin: round; stroke-miterlimit: 2"
|
||||||
|
color="var(--color-contrast)"
|
||||||
|
>
|
||||||
|
<g transform="matrix(1,0,0,1,-3395.45,-1175)">
|
||||||
|
<g transform="matrix(0.632704,0,0,0.161619,3395.45,1175)">
|
||||||
|
<rect
|
||||||
|
id="modrinth-app-logo"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="1920"
|
||||||
|
height="1080"
|
||||||
|
style="fill: none"
|
||||||
|
/>
|
||||||
|
<g id="modrinth-app-logo1">
|
||||||
|
<g transform="matrix(1.26353,0,0,3.23025,-514.757,-837.171)">
|
||||||
|
<g transform="matrix(1.25087,0,0,1.91545,-240.84,-608.008)">
|
||||||
|
<g transform="matrix(0.273005,0,0,0.273005,523.782,459.389)">
|
||||||
|
<path
|
||||||
|
d="M1053.02,205.51C1088.61,205.51 1117.29,215.61 1138,236.32C1158.72,257.57 1169.34,288.37 1169.34,329.8L1169.34,492.33L1102.94,492.33L1102.94,338.3C1102.94,313.34 1097.64,294.75 1086.48,282C1075.33,269.78 1059.93,263.4 1039.21,263.4C1016.91,263.4 998.84,270.85 985.56,285.19C972.29,300.06 965.38,321.3 965.38,348.39L965.38,492.33L898.98,492.33L898.98,338.3C898.98,313.34 893.68,294.75 882.52,282C871.37,269.78 855.96,263.4 835.25,263.4C812.41,263.4 794.88,270.85 781.6,285.19C768.33,299.53 761.42,320.77 761.42,348.39L761.42,492.33L695.02,492.33L695.02,208.7L758.23,208.7L758.23,244.82C768.86,232.07 782.13,222.52 798.07,215.61C814,208.71 831.53,205.51 851.18,205.51C872.43,205.51 891.55,209.23 908.02,217.2C924.48,225.7 937.23,237.38 946.79,252.79C958.48,237.91 973.35,226.23 991.94,217.73C1010.53,209.76 1030.71,205.51 1053.02,205.51ZM1382.86,496.05C1354.18,496.05 1328.16,489.68 1305.32,477.46C1282.84,465.588 1264.22,447.523 1251.67,425.41C1238.39,403.63 1232.02,378.67 1232.02,350.51C1232.02,322.37 1238.39,297.41 1251.67,275.63C1264.39,253.783 1282.98,235.93 1305.32,224.1C1328.16,211.89 1354.18,205.51 1382.86,205.51C1412.08,205.51 1438.1,211.89 1460.94,224.11C1483.78,236.32 1501.84,253.85 1515.12,275.63C1527.87,297.4 1534.24,322.37 1534.24,350.52C1534.24,378.67 1527.87,403.63 1515.12,425.41C1501.84,447.71 1483.78,465.24 1460.94,477.46C1438.1,489.68 1412.08,496.06 1382.86,496.06L1382.86,496.05ZM1382.86,439.22C1407.3,439.22 1427.48,431.25 1443.41,414.79C1459.35,398.32 1467.31,377.07 1467.31,350.52C1467.31,323.96 1459.35,302.72 1443.41,286.25C1427.48,269.78 1407.3,261.82 1382.86,261.82C1358.43,261.82 1338.25,269.78 1322.84,286.25C1306.91,302.71 1298.94,323.96 1298.94,350.52C1298.94,377.07 1306.91,398.32 1322.84,414.79C1338.24,431.25 1358.44,439.22 1382.86,439.22ZM1874.18,98.22L1874.18,492.33L1810.44,492.33L1810.44,455.68C1799.56,468.819 1785.73,479.196 1770.07,485.96C1753.61,492.86 1736.07,496.06 1716.42,496.06C1689.34,496.06 1664.9,490.21 1643.12,477.99C1621.35,465.78 1603.82,448.78 1591.6,426.47C1579.39,404.69 1573.01,379.2 1573.01,350.52C1573.01,321.84 1579.39,296.34 1591.61,274.56C1603.82,252.79 1621.35,235.79 1643.13,223.57C1664.9,211.36 1689.33,205.51 1716.43,205.51C1735.02,205.51 1752.54,208.71 1767.95,215.07C1783.28,221.396 1796.92,231.222 1807.78,243.76L1807.78,98.22L1874.18,98.22ZM1724.39,439.22C1740.33,439.22 1754.67,435.5 1767.42,428.06C1780.16,421.16 1790.25,410.54 1797.69,397.26C1805.13,383.98 1808.84,368.05 1808.84,350.52C1808.84,332.99 1805.13,317.06 1797.69,303.78C1790.25,290.5 1780.16,279.88 1767.42,272.44C1754.67,265.54 1740.32,261.82 1724.39,261.82C1708.46,261.82 1694.12,265.53 1681.37,272.44C1668.62,279.87 1658.53,290.5 1651.09,303.78C1643.66,317.06 1639.94,332.98 1639.94,350.52C1639.94,368.05 1643.66,383.98 1651.09,397.26C1658.53,410.54 1668.62,421.16 1681.37,428.06C1694.12,435.5 1708.46,439.22 1724.39,439.22ZM2022.9,250.13C2042.02,220.39 2075.48,205.51 2123.82,205.51L2123.82,268.72C2118.75,267.715 2113.59,267.18 2108.42,267.12C2082.39,267.12 2062.2,274.56 2047.86,289.44C2033.52,304.84 2026.08,326.62 2026.08,354.77L2026.08,492.33L1959.69,492.33L1959.69,208.7L2022.89,208.7L2022.89,250.13L2022.9,250.13ZM2178.52,208.7L2244.92,208.7L2244.92,492.33L2178.52,492.33L2178.52,208.7ZM2211.99,161.96C2199.77,161.96 2189.68,158.24 2181.71,150.28C2173.8,143.08 2169.35,132.817 2169.5,122.12C2169.5,110.97 2173.75,101.41 2181.71,93.44C2189.68,86.01 2199.77,82.29 2211.99,82.29C2224.2,82.29 2234.29,86.01 2242.26,92.91C2250.23,100.35 2254.48,109.38 2254.48,120.53C2254.48,132.22 2250.76,141.78 2242.79,149.74C2234.83,157.71 2224.2,161.96 2211.99,161.96ZM2491.37,205.51C2526.96,205.51 2555.64,216.14 2577.42,236.85C2599.2,257.57 2609.82,288.9 2609.82,329.8L2609.82,492.33L2543.42,492.33L2543.42,338.3C2543.42,313.34 2537.58,294.75 2525.9,282C2514.21,269.78 2497.75,263.4 2475.97,263.4C2451.54,263.4 2432.42,270.85 2418.07,285.19C2403.73,300.06 2396.83,321.3 2396.83,348.92L2396.83,492.33L2330.43,492.33L2330.43,208.7L2393.64,208.7L2393.64,245.35C2404.8,232.07 2418.61,222.51 2435.07,215.61C2451.54,208.71 2470.66,205.51 2491.37,205.51ZM2863.18,476.93C2854.87,483.572 2845.29,488.451 2835.03,491.27C2823.44,494.492 2811.46,496.101 2799.43,496.05C2768.1,496.05 2744.2,488.08 2727.2,471.62C2710.2,455.15 2701.7,431.78 2701.7,400.45L2701.7,263.94L2654.97,263.94L2654.97,210.83L2701.71,210.83L2701.71,146.03L2768.11,146.03L2768.11,210.83L2844.06,210.83L2844.06,263.94L2768.1,263.94L2768.1,398.85C2768.1,412.66 2771.29,423.28 2778.2,430.19C2785.1,437.63 2794.66,441.34 2807.4,441.34C2822.28,441.34 2834.5,437.63 2844.59,429.66L2863.18,476.93ZM3077.23,205.51C3112.82,205.51 3141.5,216.14 3163.28,236.85C3185.05,257.57 3195.68,288.9 3195.68,329.8L3195.68,492.33L3129.28,492.33L3129.28,338.3C3129.28,313.34 3123.44,294.75 3111.75,282C3100.07,269.78 3083.6,263.4 3061.83,263.4C3037.39,263.4 3018.27,270.85 3003.93,285.19C2989.59,300.06 2982.69,321.3 2982.69,348.92L2982.69,492.33L2916.29,492.33L2916.29,98.23L2982.69,98.23L2982.69,241.Line truncated
|
||||||
|
style="fill: currentColor; fill-rule: nonzero"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(0.273005,0,0,0.273005,523.782,459.389)">
|
||||||
|
<path
|
||||||
|
d="M29,424.4L217.2,311.45L200.05,265.97L253.8,210.76L321.73,196.12L341.4,220.33L310.08,252.05L282.78,260.65L263.26,280.7L272.82,307.3L292.22,327.9L319.58,320.62L339.05,299.24L381.56,285.77L394.23,314.27L350.36,368.05L276.86,391.32L243.89,354.62L55.06,467.94C46.1,456.41 35.67,440.08 29,424.4ZM572.03,194.15L422.53,234.47C430.77,256.39 433.48,269.27 435.76,283.47L584.99,243.21C582.61,227.27 578.34,211.04 572.03,194.15Z"
|
||||||
|
style="fill: var(--color-brand)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M51.28,316.13C61.87,441.13 166.82,539.43 294.55,539.43C391.06,539.43 474.57,483.31 514.18,401.97L562.79,418.8C516.01,520.14 413.44,590.55 294.55,590.55C138.6,590.55 10.71,469.38 0,316.13L51.28,316.13ZM0.78,265.24C15.86,116.36 141.73,0 294.56,0C457.53,0 589.84,132.31 589.84,295.28C589.84,321.42 586.44,346.77 580.04,370.91L531.56,354.13C536.324,334.876 538.725,315.114 538.71,295.28C538.71,160.53 429.31,51.13 294.56,51.13C169.98,51.13 67.07,144.63 52.24,265.24L0.78,265.24Z"
|
||||||
|
style="fill: var(--color-brand)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M293.77,153.17C215.28,153.24 151.57,217 151.57,295.51C151.57,374.07 215.36,437.85 293.92,437.85C297.9,437.85 301.85,437.69 305.75,437.36L319.97,487.12C311.335,488.282 302.632,488.864 293.92,488.86C187.2,488.86 100.56,402.22 100.56,295.51C100.56,188.79 187.2,102.16 293.92,102.16C296.56,102.16 299.2,102.21 301.82,102.32L293.77,153.17ZM351.97,111.04C430.36,135.71 487.27,209.02 487.27,295.51C487.27,375.58 438.5,444.34 369.07,473.69L354.9,424.14C402.98,401.29 436.26,352.25 436.26,295.51C436.26,234.52 397.82,182.44 343.87,162.19L351.97,111.04Z"
|
||||||
|
style="fill: var(--color-brand)"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.25498,0,0,1.92174,1126.78,-2077.58)">
|
||||||
|
<path
|
||||||
|
d="M411.597,1355.36L411.597,1339.8L410.589,1336.49L410.589,1309.28C410.589,1304 409.005,1299.89 405.837,1296.96C402.669,1294.04 397.869,1292.57 391.437,1292.57C387.117,1292.57 382.869,1293.24 378.693,1294.59C374.517,1295.93 370.989,1297.8 368.109,1300.2L361.053,1287.1C365.181,1283.93 370.101,1281.56 375.813,1279.97C381.525,1278.39 387.453,1277.6 393.597,1277.6C404.733,1277.6 413.349,1280.26 419.445,1285.59C425.541,1290.91 428.589,1299.15 428.589,1310.28L428.589,1355.36L411.597,1355.36ZM387.405,1356.36C381.645,1356.36 376.605,1355.38 372.285,1353.41C367.965,1351.44 364.629,1348.71 362.277,1345.2C359.925,1341.7 358.749,1337.74 358.749,1333.32C358.749,1329 359.781,1325.12 361.845,1321.66C363.909,1318.2 367.293,1315.47 371.997,1313.45C376.701,1311.43 382.941,1310.43 390.717,1310.43L413.037,1310.43L413.037,1322.38L392.013,1322.38C385.869,1322.38 381.741,1323.36 379.629,1325.33C377.517,1327.3 376.461,1329.72 376.461,1332.6C376.461,1335.87 377.757,1338.46 380.349,1340.38C382.941,1342.3 386.541,1343.26 391.149,1343.26C395.565,1343.26 399.525,1342.25 403.029,1340.24C406.533,1338.22 409.053,1335.24 410.589,1331.31L413.613,1342.11C411.885,1346.62 408.789,1350.12 404.325,1352.62C399.861,1355.12 394.221,1356.36 387.405,1356.36Z"
|
||||||
|
style="fill: var(--color-brand); fill-rule: nonzero"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M494.253,1356.36C488.013,1356.36 482.325,1354.92 477.189,1352.04C472.053,1349.16 467.973,1344.82 464.949,1339.01C461.925,1333.2 460.413,1325.84 460.413,1316.91C460.413,1307.88 461.877,1300.49 464.805,1294.73C467.733,1288.97 471.741,1284.67 476.829,1281.84C481.917,1279.01 487.725,1277.6 494.253,1277.6C501.837,1277.6 508.533,1279.23 514.341,1282.49C520.149,1285.76 524.757,1290.32 528.165,1296.17C531.573,1302.03 533.277,1308.94 533.277,1316.91C533.277,1324.88 531.573,1331.81 528.165,1337.71C524.757,1343.62 520.149,1348.2 514.341,1351.47C508.533,1354.73 501.837,1356.36 494.253,1356.36ZM451.629,1383.29L451.629,1278.46L468.765,1278.46L468.765,1296.6L468.189,1317.05L469.629,1337.5L469.629,1383.29L451.629,1383.29ZM492.237,1340.95C496.557,1340.95 500.421,1340 503.829,1338.08C507.237,1336.15 509.949,1333.37 511.965,1329.72C513.981,1326.08 514.989,1321.8 514.989,1316.91C514.989,1311.91 513.981,1307.62 511.965,1304.02C509.949,1300.42 507.237,1297.66 503.829,1295.74C500.421,1293.82 496.557,1292.86 492.237,1292.86C487.917,1292.86 484.029,1293.82 480.573,1295.74C477.117,1297.66 474.381,1300.42 472.365,1304.02C470.349,1307.62 469.341,1311.91 469.341,1316.91C469.341,1321.8 470.349,1326.08 472.365,1329.72C474.381,1333.37 477.117,1336.15 480.573,1338.08C484.029,1340 487.917,1340.95 492.237,1340.95Z"
|
||||||
|
style="fill: var(--color-brand); fill-rule: nonzero"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M593.037,1356.36C586.797,1356.36 581.109,1354.92 575.973,1352.04C570.837,1349.16 566.757,1344.82 563.733,1339.01C560.709,1333.2 559.197,1325.84 559.197,1316.91C559.197,1307.88 560.661,1300.49 563.589,1294.73C566.517,1288.97 570.525,1284.67 575.613,1281.84C580.701,1279.01 586.509,1277.6 593.037,1277.6C600.621,1277.6 607.317,1279.23 613.125,1282.49C618.933,1285.76 623.541,1290.32 626.949,1296.17C630.357,1302.03 632.061,1308.94 632.061,1316.91C632.061,1324.88 630.357,1331.81 626.949,1337.71C623.541,1343.62 618.933,1348.2 613.125,1351.47C607.317,1354.73 600.621,1356.36 593.037,1356.36ZM550.413,1383.29L550.413,1278.46L567.549,1278.46L567.549,1296.6L566.973,1317.05L568.413,1337.5L568.413,1383.29L550.413,1383.29ZM591.021,1340.95C595.341,1340.95 599.205,1340 602.613,1338.08C606.021,1336.15 608.733,1333.37 610.749,1329.72C612.765,1326.08 613.773,1321.8 613.773,1316.91C613.773,1311.91 612.765,1307.62 610.749,1304.02C608.733,1300.42 606.021,1297.66 602.613,1295.74C599.205,1293.82 595.341,1292.86 591.021,1292.86C586.701,1292.86 582.813,1293.82 579.357,1295.74C575.901,1297.66 573.165,1300.42 571.149,1304.02C569.133,1307.62 568.125,1311.91 568.125,1316.91C568.125,1321.8 569.133,1326.08 571.149,1329.72C573.165,1333.37 575.901,1336.15 579.357,1338.08C582.813,1340 586.701,1340.95 591.021,1340.95Z"
|
||||||
|
style="fill: var(--color-brand); fill-rule: nonzero"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<ProgressBar class="loading-bar" :progress="loadingProgress" />
|
||||||
|
<span v-if="message">{{ message }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="gradient-bg" data-tauri-drag-region></div>
|
||||||
|
<div class="cube-bg"></div>
|
||||||
|
<div class="base-bg"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
import ProgressBar from '@/components/ui/ProgressBar.vue'
|
||||||
|
import { loading_listener } from '@/helpers/events.js'
|
||||||
|
import { getCurrentWindow } from '@tauri-apps/api/window'
|
||||||
|
import { XIcon } from '@modrinth/assets'
|
||||||
|
import { MaximizeIcon, MinimizeIcon } from '@/assets/icons/index.js'
|
||||||
|
import { TauriEvent } from '@tauri-apps/api/event'
|
||||||
|
import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state'
|
||||||
|
import { getOS } from '@/helpers/utils.js'
|
||||||
|
import { useLoading } from '@/store/loading.js'
|
||||||
|
|
||||||
|
const doneLoading = ref(false)
|
||||||
|
const loadingProgress = ref(0)
|
||||||
|
const hidden = ref(false)
|
||||||
|
const message = ref()
|
||||||
|
|
||||||
|
const loading = useLoading()
|
||||||
|
|
||||||
|
watch(loading, (newValue) => {
|
||||||
|
if (!newValue.barEnabled) {
|
||||||
|
if (loading.loading) {
|
||||||
|
loadingProgress.value = 0
|
||||||
|
fakeLoadingIncrease()
|
||||||
|
} else {
|
||||||
|
loadingProgress.value = 100
|
||||||
|
doneLoading.value = true
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
hidden.value = true
|
||||||
|
loading.setEnabled(true)
|
||||||
|
}, 250)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function fakeLoadingIncrease() {
|
||||||
|
if (loadingProgress.value < 95) {
|
||||||
|
setTimeout(() => {
|
||||||
|
loadingProgress.value += 1
|
||||||
|
fakeLoadingIncrease()
|
||||||
|
}, 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const os = ref('')
|
||||||
|
getOS().then((x) => (os.value = x))
|
||||||
|
|
||||||
|
loading_listener(async (e) => {
|
||||||
|
if (e.event.type === 'directory_move') {
|
||||||
|
loadingProgress.value = 100 * (e.fraction ?? 1)
|
||||||
|
message.value = 'Updating app directory...'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleClose = async () => {
|
||||||
|
await getCurrentWindow().close()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.splash-screen {
|
||||||
|
transition: opacity 0.25s ease-in-out;
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
&.fade-out {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-buttons {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-logo-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
z-index: 9998;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-logo {
|
||||||
|
height: 2.25rem;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-bar {
|
||||||
|
max-width: 20rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient-bg {
|
||||||
|
position: absolute;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
background: linear-gradient(180deg, rgba(66, 131, 92, 0.275) 0%, rgba(17, 35, 43, 0.5) 97.29%),
|
||||||
|
linear-gradient(0deg, rgba(22, 24, 28, 0.64), rgba(22, 24, 28, 0.64));
|
||||||
|
z-index: 9997;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cube-bg {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
|
||||||
|
width: 180vw;
|
||||||
|
height: 180vh;
|
||||||
|
opacity: 0.8;
|
||||||
|
background: #16181c url('@/assets/loading/cube.png') center no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
|
||||||
|
z-index: 9996;
|
||||||
|
}
|
||||||
|
|
||||||
|
.base-bg {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--color-bg);
|
||||||
|
z-index: 9995;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+12
-48
@@ -1,77 +1,42 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Modal, Button } from 'omorphia'
|
import { Modal, Button } from '@modrinth/ui'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useFetch } from '@/helpers/fetch.js'
|
|
||||||
import SearchCard from '@/components/ui/SearchCard.vue'
|
import SearchCard from '@/components/ui/SearchCard.vue'
|
||||||
import { get_categories } from '@/helpers/tags.js'
|
import { get_categories } from '@/helpers/tags.js'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import { install as packInstall } from '@/helpers/pack.js'
|
import { get_version, get_project } from '@/helpers/cache.js'
|
||||||
import mixpanel from 'mixpanel-browser'
|
import { install as installVersion } from '@/store/install.js'
|
||||||
import ModInstallModal from '@/components/ui/ModInstallModal.vue'
|
|
||||||
|
|
||||||
const confirmModal = ref(null)
|
const confirmModal = ref(null)
|
||||||
const project = ref(null)
|
const project = ref(null)
|
||||||
const version = ref(null)
|
const version = ref(null)
|
||||||
const categories = ref(null)
|
const categories = ref(null)
|
||||||
const installing = ref(false)
|
const installing = ref(false)
|
||||||
const modInstallModal = ref(null)
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
async show(event) {
|
async show(event) {
|
||||||
if (event.event === 'InstallVersion') {
|
if (event.event === 'InstallVersion') {
|
||||||
version.value = await useFetch(
|
version.value = await get_version(event.id, 'must_revalidate').catch(handleError)
|
||||||
`https://api.modrinth.com/v2/version/${encodeURIComponent(event.id)}`,
|
project.value = await get_project(version.value.project_id, 'must_revalidate').catch(
|
||||||
'version',
|
handleError,
|
||||||
)
|
|
||||||
project.value = await useFetch(
|
|
||||||
`https://api.modrinth.com/v2/project/${encodeURIComponent(version.value.project_id)}`,
|
|
||||||
'project',
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
project.value = await useFetch(
|
project.value = await get_project(event.id, 'must_revalidate').catch(handleError)
|
||||||
`https://api.modrinth.com/v2/project/${encodeURIComponent(event.id)}`,
|
version.value = await get_version(
|
||||||
'project',
|
project.value.versions[project.value.versions.length - 1],
|
||||||
)
|
'must_revalidate',
|
||||||
version.value = await useFetch(
|
).catch(handleError)
|
||||||
`https://api.modrinth.com/v2/version/${encodeURIComponent(project.value.versions[0])}`,
|
|
||||||
'version',
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
categories.value = (await get_categories().catch(handleError)).filter(
|
categories.value = (await get_categories().catch(handleError)).filter(
|
||||||
(cat) => project.value.categories.includes(cat.name) && cat.project_type === 'mod',
|
(cat) => project.value.categories.includes(cat.name) && cat.project_type === 'mod',
|
||||||
)
|
)
|
||||||
confirmModal.value.show()
|
confirmModal.value.show()
|
||||||
categories.value = (await get_categories().catch(handleError)).filter(
|
|
||||||
(cat) => project.value.categories.includes(cat.name) && cat.project_type === 'mod',
|
|
||||||
)
|
|
||||||
confirmModal.value.show()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
async function install() {
|
async function install() {
|
||||||
confirmModal.value.hide()
|
confirmModal.value.hide()
|
||||||
if (project.value.project_type === 'modpack') {
|
await installVersion(project.value.id, version.value.id, null, 'URLConfirmModal')
|
||||||
await packInstall(
|
|
||||||
project.value.id,
|
|
||||||
version.value.id,
|
|
||||||
project.value.title,
|
|
||||||
project.value.icon_url,
|
|
||||||
).catch(handleError)
|
|
||||||
|
|
||||||
mixpanel.track('PackInstall', {
|
|
||||||
id: project.value.id,
|
|
||||||
version_id: version.value.id,
|
|
||||||
title: project.value.title,
|
|
||||||
source: 'ProjectPage',
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
modInstallModal.value.show(
|
|
||||||
project.value.id,
|
|
||||||
[version.value],
|
|
||||||
project.value.title,
|
|
||||||
project.value.project_type,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -96,7 +61,6 @@ async function install() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
<ModInstallModal ref="modInstallModal" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
+23
-31
@@ -3,6 +3,7 @@
|
|||||||
ref="incompatibleModal"
|
ref="incompatibleModal"
|
||||||
header="Incompatibility warning"
|
header="Incompatibility warning"
|
||||||
:noblur="!themeStore.advancedRendering"
|
:noblur="!themeStore.advancedRendering"
|
||||||
|
:on-hide="onInstall"
|
||||||
>
|
>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>
|
<p>
|
||||||
@@ -12,13 +13,11 @@
|
|||||||
</p>
|
</p>
|
||||||
<table>
|
<table>
|
||||||
<tr class="header">
|
<tr class="header">
|
||||||
<th>{{ instance?.metadata.name }}</th>
|
<th>{{ instance?.name }}</th>
|
||||||
<th>{{ projectTitle }}</th>
|
<th>{{ project.title }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="content">
|
<tr class="content">
|
||||||
<td class="data">
|
<td class="data">{{ instance?.loader }} {{ instance?.game_version }}</td>
|
||||||
{{ instance?.metadata.loader }} {{ instance?.metadata.game_version }}
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
<DropdownSelect
|
<DropdownSelect
|
||||||
v-if="versions?.length > 1"
|
v-if="versions?.length > 1"
|
||||||
@@ -56,46 +55,39 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Button, Modal, XIcon, DownloadIcon, DropdownSelect, formatCategory } from 'omorphia'
|
import { XIcon, DownloadIcon } from '@modrinth/assets'
|
||||||
|
import { Button, Modal, DropdownSelect } from '@modrinth/ui'
|
||||||
|
import { formatCategory } from '@modrinth/utils'
|
||||||
import { add_project_from_version as installMod } from '@/helpers/profile'
|
import { add_project_from_version as installMod } from '@/helpers/profile'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { handleError, useTheming } from '@/store/state.js'
|
import { handleError, useTheming } from '@/store/state.js'
|
||||||
import { mixpanel_track } from '@/helpers/mixpanel'
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
|
|
||||||
const themeStore = useTheming()
|
const themeStore = useTheming()
|
||||||
|
|
||||||
const instance = ref(null)
|
const instance = ref(null)
|
||||||
const project = ref(null)
|
const project = ref(null)
|
||||||
const projectType = ref(null)
|
|
||||||
const projectTitle = ref(null)
|
|
||||||
const versions = ref(null)
|
const versions = ref(null)
|
||||||
const selectedVersion = ref(null)
|
const selectedVersion = ref(null)
|
||||||
const incompatibleModal = ref(null)
|
const incompatibleModal = ref(null)
|
||||||
const installing = ref(false)
|
const installing = ref(false)
|
||||||
|
|
||||||
let markInstalled = () => {}
|
let onInstall = ref(() => {})
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
show: (
|
show: (instanceVal, projectVal, projectVersions, callback) => {
|
||||||
instanceVal,
|
|
||||||
projectTitleVal,
|
|
||||||
selectedVersions,
|
|
||||||
extMarkInstalled,
|
|
||||||
projectIdVal,
|
|
||||||
projectTypeVal,
|
|
||||||
) => {
|
|
||||||
instance.value = instanceVal
|
instance.value = instanceVal
|
||||||
projectTitle.value = projectTitleVal
|
versions.value = projectVersions
|
||||||
versions.value = selectedVersions
|
selectedVersion.value = projectVersions[0]
|
||||||
selectedVersion.value = selectedVersions[0]
|
|
||||||
|
|
||||||
project.value = projectIdVal
|
project.value = projectVal
|
||||||
projectType.value = projectTypeVal
|
|
||||||
|
onInstall.value = callback
|
||||||
|
installing.value = false
|
||||||
|
|
||||||
incompatibleModal.value.show()
|
incompatibleModal.value.show()
|
||||||
markInstalled = extMarkInstalled
|
|
||||||
|
|
||||||
mixpanel_track('ProjectInstallStart', { source: 'ProjectIncompatibilityWarningModal' })
|
trackEvent('ProjectInstallStart', { source: 'ProjectIncompatibilityWarningModal' })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -103,16 +95,16 @@ const install = async () => {
|
|||||||
installing.value = true
|
installing.value = true
|
||||||
await installMod(instance.value.path, selectedVersion.value.id).catch(handleError)
|
await installMod(instance.value.path, selectedVersion.value.id).catch(handleError)
|
||||||
installing.value = false
|
installing.value = false
|
||||||
markInstalled()
|
onInstall.value(selectedVersion.value.id)
|
||||||
incompatibleModal.value.hide()
|
incompatibleModal.value.hide()
|
||||||
|
|
||||||
mixpanel_track('ProjectInstall', {
|
trackEvent('ProjectInstall', {
|
||||||
loader: instance.value.metadata.loader,
|
loader: instance.value.loader,
|
||||||
game_version: instance.value.metadata.game_version,
|
game_version: instance.value.game_version,
|
||||||
id: project.value,
|
id: project.value,
|
||||||
version_id: selectedVersion.value.id,
|
version_id: selectedVersion.value.id,
|
||||||
project_type: projectType.value,
|
project_type: project.value.project_type,
|
||||||
title: projectTitle.value,
|
title: project.value.title,
|
||||||
source: 'ProjectIncompatibilityWarningModal',
|
source: 'ProjectIncompatibilityWarningModal',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
+31
-22
@@ -1,54 +1,63 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Button, Modal, XIcon, DownloadIcon } from 'omorphia'
|
import { XIcon, DownloadIcon } from '@modrinth/assets'
|
||||||
|
import { Button, Modal } from '@modrinth/ui'
|
||||||
import { install as pack_install } from '@/helpers/pack'
|
import { install as pack_install } from '@/helpers/pack'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { mixpanel_track } from '@/helpers/mixpanel'
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
import { useTheming } from '@/store/theme.js'
|
import { useTheming } from '@/store/theme.js'
|
||||||
import { handleError } from '@/store/state.js'
|
import { handleError } from '@/store/state.js'
|
||||||
|
|
||||||
const themeStore = useTheming()
|
const themeStore = useTheming()
|
||||||
|
|
||||||
const version = ref('')
|
const versionId = ref()
|
||||||
const title = ref('')
|
const project = ref()
|
||||||
const projectId = ref('')
|
|
||||||
const icon = ref('')
|
|
||||||
const confirmModal = ref(null)
|
const confirmModal = ref(null)
|
||||||
const installing = ref(false)
|
const installing = ref(false)
|
||||||
|
|
||||||
|
let onInstall = ref(() => {})
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
show: (projectIdVal, versionId, projectTitle, projectIcon) => {
|
show: (projectVal, versionIdVal, callback) => {
|
||||||
projectId.value = projectIdVal
|
project.value = projectVal
|
||||||
version.value = versionId
|
versionId.value = versionIdVal
|
||||||
title.value = projectTitle
|
|
||||||
icon.value = projectIcon
|
|
||||||
installing.value = false
|
installing.value = false
|
||||||
confirmModal.value.show()
|
confirmModal.value.show()
|
||||||
|
|
||||||
mixpanel_track('PackInstallStart')
|
onInstall.value = callback
|
||||||
|
|
||||||
|
trackEvent('PackInstallStart')
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
async function install() {
|
async function install() {
|
||||||
installing.value = true
|
installing.value = true
|
||||||
console.log(`Installing ${projectId.value} ${version.value} ${title.value} ${icon.value}`)
|
|
||||||
confirmModal.value.hide()
|
confirmModal.value.hide()
|
||||||
|
|
||||||
await pack_install(
|
await pack_install(
|
||||||
projectId.value,
|
project.value.id,
|
||||||
version.value,
|
versionId.value,
|
||||||
title.value,
|
project.value.title,
|
||||||
icon.value ? icon.value : null,
|
project.value.icon_url,
|
||||||
).catch(handleError)
|
).catch(handleError)
|
||||||
mixpanel_track('PackInstall', {
|
trackEvent('PackInstall', {
|
||||||
id: projectId.value,
|
id: project.value.id,
|
||||||
version_id: version.value,
|
version_id: versionId.value,
|
||||||
title: title.value,
|
title: project.value.title,
|
||||||
source: 'ConfirmModal',
|
source: 'ConfirmModal',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onInstall.value(versionId.value)
|
||||||
|
installing.value = false
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal ref="confirmModal" header="Are you sure?" :noblur="!themeStore.advancedRendering">
|
<Modal
|
||||||
|
ref="confirmModal"
|
||||||
|
header="Are you sure?"
|
||||||
|
:noblur="!themeStore.advancedRendering"
|
||||||
|
:on-hide="onInstall"
|
||||||
|
>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>You already have this modpack installed. Are you sure you want to install it again?</p>
|
<p>You already have this modpack installed. Are you sure you want to install it again?</p>
|
||||||
<div class="input-group push-right">
|
<div class="input-group push-right">
|
||||||
+89
-97
@@ -1,42 +1,38 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
Avatar,
|
|
||||||
Modal,
|
|
||||||
Button,
|
|
||||||
DownloadIcon,
|
DownloadIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
Card,
|
|
||||||
UploadIcon,
|
UploadIcon,
|
||||||
XIcon,
|
XIcon,
|
||||||
RightArrowIcon,
|
RightArrowIcon,
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
} from 'omorphia'
|
} from '@modrinth/assets'
|
||||||
|
import { Avatar, Modal, Button, Card } from '@modrinth/ui'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import {
|
import {
|
||||||
add_project_from_version as installMod,
|
add_project_from_version as installMod,
|
||||||
check_installed,
|
check_installed,
|
||||||
get,
|
get,
|
||||||
list,
|
list,
|
||||||
|
create,
|
||||||
} from '@/helpers/profile'
|
} from '@/helpers/profile'
|
||||||
import { open } from '@tauri-apps/api/dialog'
|
import { open } from '@tauri-apps/plugin-dialog'
|
||||||
import { create } from '@/helpers/profile'
|
import { installVersionDependencies } from '@/store/install.js'
|
||||||
import { installVersionDependencies } from '@/helpers/utils'
|
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import { mixpanel_track } from '@/helpers/mixpanel'
|
|
||||||
import { useTheming } from '@/store/theme.js'
|
import { useTheming } from '@/store/theme.js'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { tauri } from '@tauri-apps/api'
|
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||||
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
|
|
||||||
const themeStore = useTheming()
|
const themeStore = useTheming()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const versions = ref([])
|
const versions = ref()
|
||||||
const project = ref('')
|
const project = ref()
|
||||||
const projectTitle = ref('')
|
|
||||||
const projectType = ref('')
|
|
||||||
|
|
||||||
const installModal = ref(null)
|
const installModal = ref()
|
||||||
const searchFilter = ref('')
|
const searchFilter = ref('')
|
||||||
|
|
||||||
const showCreation = ref(false)
|
const showCreation = ref(false)
|
||||||
const icon = ref(null)
|
const icon = ref(null)
|
||||||
const name = ref(null)
|
const name = ref(null)
|
||||||
@@ -45,33 +41,65 @@ const loader = ref(null)
|
|||||||
const gameVersion = ref(null)
|
const gameVersion = ref(null)
|
||||||
const creatingInstance = ref(false)
|
const creatingInstance = ref(false)
|
||||||
|
|
||||||
defineExpose({
|
const profiles = ref([])
|
||||||
show: async (projectId, selectedVersions, title, type) => {
|
|
||||||
project.value = projectId
|
|
||||||
versions.value = selectedVersions
|
|
||||||
projectTitle.value = title
|
|
||||||
projectType.value = type
|
|
||||||
|
|
||||||
installModal.value.show()
|
const shownProfiles = computed(() =>
|
||||||
|
profiles.value
|
||||||
|
.filter((profile) => {
|
||||||
|
return profile.name.toLowerCase().includes(searchFilter.value.toLowerCase())
|
||||||
|
})
|
||||||
|
.filter((profile) => {
|
||||||
|
let loaders = versions.value.flatMap((v) => v.loaders)
|
||||||
|
|
||||||
|
return (
|
||||||
|
versions.value.flatMap((v) => v.game_versions).includes(profile.game_version) &&
|
||||||
|
(project.value.project_type === 'mod'
|
||||||
|
? loaders.includes(profile.loader) || loaders.includes('minecraft')
|
||||||
|
: true)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
let onInstall = ref(() => {})
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show: async (projectVal, versionsVal, callback) => {
|
||||||
|
project.value = projectVal
|
||||||
|
versions.value = versionsVal
|
||||||
searchFilter.value = ''
|
searchFilter.value = ''
|
||||||
|
|
||||||
profiles.value = await getData()
|
showCreation.value = false
|
||||||
|
name.value = null
|
||||||
|
icon.value = null
|
||||||
|
display_icon.value = null
|
||||||
|
gameVersion.value = null
|
||||||
|
loader.value = null
|
||||||
|
|
||||||
mixpanel_track('ProjectInstallStart', { source: 'ProjectInstallModal' })
|
onInstall.value = callback
|
||||||
|
|
||||||
|
const profilesVal = await list().catch(handleError)
|
||||||
|
for (let profile of profilesVal) {
|
||||||
|
profile.installing = false
|
||||||
|
profile.installedMod = await check_installed(profile.path, project.value.id).catch(
|
||||||
|
handleError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
profiles.value = profilesVal
|
||||||
|
|
||||||
|
installModal.value.show()
|
||||||
|
|
||||||
|
trackEvent('ProjectInstallStart', { source: 'ProjectInstallModal' })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const profiles = ref([])
|
|
||||||
|
|
||||||
async function install(instance) {
|
async function install(instance) {
|
||||||
instance.installing = true
|
instance.installing = true
|
||||||
const version = versions.value.find((v) => {
|
const version = versions.value.find((v) => {
|
||||||
return (
|
return (
|
||||||
v.game_versions.includes(instance.metadata.game_version) &&
|
v.game_versions.includes(instance.game_version) &&
|
||||||
(v.loaders.includes(instance.metadata.loader) ||
|
(project.value.project_type === 'mod'
|
||||||
v.loaders.includes('minecraft') ||
|
? v.loaders.includes(instance.loader) || v.loaders.includes('minecraft')
|
||||||
v.loaders.includes('iris') ||
|
: true)
|
||||||
v.loaders.includes('optifine'))
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -87,46 +115,19 @@ async function install(instance) {
|
|||||||
instance.installedMod = true
|
instance.installedMod = true
|
||||||
instance.installing = false
|
instance.installing = false
|
||||||
|
|
||||||
mixpanel_track('ProjectInstall', {
|
trackEvent('ProjectInstall', {
|
||||||
loader: instance.metadata.loader,
|
loader: instance.loader,
|
||||||
game_version: instance.metadata.game_version,
|
game_version: instance.game_version,
|
||||||
id: project.value,
|
id: project.value.id,
|
||||||
version_id: version.id,
|
version_id: version.id,
|
||||||
project_type: projectType.value,
|
project_type: project.value.project_type,
|
||||||
title: projectTitle.value,
|
title: project.value.title,
|
||||||
source: 'ProjectInstallModal',
|
source: 'ProjectInstallModal',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onInstall.value(version.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getData() {
|
|
||||||
const projects = await list(true).then(Object.values).catch(handleError)
|
|
||||||
|
|
||||||
const filtered = projects
|
|
||||||
.filter((profile) => {
|
|
||||||
return profile.metadata.name.toLowerCase().includes(searchFilter.value.toLowerCase())
|
|
||||||
})
|
|
||||||
.filter((profile) => {
|
|
||||||
return (
|
|
||||||
versions.value.flatMap((v) => v.game_versions).includes(profile.metadata.game_version) &&
|
|
||||||
versions.value
|
|
||||||
.flatMap((v) => v.loaders)
|
|
||||||
.some(
|
|
||||||
(value) =>
|
|
||||||
value === profile.metadata.loader ||
|
|
||||||
['minecraft', 'iris', 'optifine'].includes(value),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
for (let profile of filtered) {
|
|
||||||
profile.installing = false
|
|
||||||
profile.installedMod = await check_installed(profile.path, project.value).catch(handleError)
|
|
||||||
}
|
|
||||||
|
|
||||||
return filtered
|
|
||||||
}
|
|
||||||
|
|
||||||
const alreadySentCreation = ref(false)
|
|
||||||
const toggleCreation = () => {
|
const toggleCreation = () => {
|
||||||
showCreation.value = !showCreation.value
|
showCreation.value = !showCreation.value
|
||||||
name.value = null
|
name.value = null
|
||||||
@@ -135,9 +136,8 @@ const toggleCreation = () => {
|
|||||||
gameVersion.value = null
|
gameVersion.value = null
|
||||||
loader.value = null
|
loader.value = null
|
||||||
|
|
||||||
if (!alreadySentCreation.value) {
|
if (showCreation.value) {
|
||||||
alreadySentCreation.value = false
|
trackEvent('InstanceCreateStart', { source: 'ProjectInstallModal' })
|
||||||
mixpanel_track('InstanceCreateStart', { source: 'ProjectInstallModal' })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ const upload_icon = async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!icon.value) return
|
if (!icon.value) return
|
||||||
display_icon.value = tauri.convertFileSrc(icon.value)
|
display_icon.value = convertFileSrc(icon.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const reset_icon = () => {
|
const reset_icon = () => {
|
||||||
@@ -186,7 +186,7 @@ const createInstance = async () => {
|
|||||||
const instance = await get(id, true)
|
const instance = await get(id, true)
|
||||||
await installVersionDependencies(instance, versions.value[0])
|
await installVersionDependencies(instance, versions.value[0])
|
||||||
|
|
||||||
mixpanel_track('InstanceCreate', {
|
trackEvent('InstanceCreate', {
|
||||||
profile_name: name.value,
|
profile_name: name.value,
|
||||||
game_version: versions.value[0].game_versions[0],
|
game_version: versions.value[0].game_versions[0],
|
||||||
loader: loader,
|
loader: loader,
|
||||||
@@ -195,23 +195,21 @@ const createInstance = async () => {
|
|||||||
source: 'ProjectInstallModal',
|
source: 'ProjectInstallModal',
|
||||||
})
|
})
|
||||||
|
|
||||||
mixpanel_track('ProjectInstall', {
|
trackEvent('ProjectInstall', {
|
||||||
loader: loader,
|
loader: loader,
|
||||||
game_version: versions.value[0].game_versions[0],
|
game_version: versions.value[0].game_versions[0],
|
||||||
id: project.value,
|
id: project.value,
|
||||||
version_id: versions.value[0].id,
|
version_id: versions.value[0].id,
|
||||||
project_type: projectType.value,
|
project_type: project.value.project_type,
|
||||||
title: projectTitle.value,
|
title: project.value.title,
|
||||||
source: 'ProjectInstallModal',
|
source: 'ProjectInstallModal',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onInstall.value(versions.value[0].id)
|
||||||
|
|
||||||
if (installModal.value) installModal.value.hide()
|
if (installModal.value) installModal.value.hide()
|
||||||
creatingInstance.value = false
|
creatingInstance.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const check_valid = computed(() => {
|
|
||||||
return name.value
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -219,6 +217,7 @@ const check_valid = computed(() => {
|
|||||||
ref="installModal"
|
ref="installModal"
|
||||||
header="Install project to instance"
|
header="Install project to instance"
|
||||||
:noblur="!themeStore.advancedRendering"
|
:noblur="!themeStore.advancedRendering"
|
||||||
|
:on-hide="onInstall"
|
||||||
>
|
>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<input
|
<input
|
||||||
@@ -229,34 +228,27 @@ const check_valid = computed(() => {
|
|||||||
placeholder="Search for an instance"
|
placeholder="Search for an instance"
|
||||||
/>
|
/>
|
||||||
<div class="profiles" :class="{ 'hide-creation': !showCreation }">
|
<div class="profiles" :class="{ 'hide-creation': !showCreation }">
|
||||||
<div v-for="profile in profiles" :key="profile.metadata.name" class="option">
|
<div v-for="profile in shownProfiles" :key="profile.name" class="option">
|
||||||
<Button
|
<router-link
|
||||||
color="raised"
|
class="btn btn-transparent profile-button"
|
||||||
class="profile-button"
|
:to="`/instance/${encodeURIComponent(profile.path)}`"
|
||||||
@click="$router.push(`/instance/${encodeURIComponent(profile.path)}`)"
|
@click="installModal.hide()"
|
||||||
>
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
:src="
|
:src="profile.icon_path ? tauri.convertFileSrc(profile.icon_path) : null"
|
||||||
!profile.metadata.icon ||
|
|
||||||
(profile.metadata.icon && profile.metadata.icon.startsWith('http'))
|
|
||||||
? profile.metadata.icon
|
|
||||||
: tauri.convertFileSrc(profile.metadata?.icon)
|
|
||||||
"
|
|
||||||
class="profile-image"
|
class="profile-image"
|
||||||
/>
|
/>
|
||||||
{{ profile.metadata.name }}
|
{{ profile.name }}
|
||||||
</Button>
|
</router-link>
|
||||||
<div
|
<div
|
||||||
v-tooltip="
|
v-tooltip="
|
||||||
profile.metadata.linked_data?.locked && !profile.installedMod
|
profile.linked_data?.locked && !profile.installedMod
|
||||||
? 'Unpair or unlock an instance to add mods.'
|
? 'Unpair or unlock an instance to add mods.'
|
||||||
: ''
|
: ''
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
:disabled="
|
:disabled="profile.installedMod || profile.installing || profile.linked_data?.locked"
|
||||||
profile.installedMod || profile.installing || profile.metadata.linked_data?.locked
|
|
||||||
"
|
|
||||||
@click="install(profile)"
|
@click="install(profile)"
|
||||||
>
|
>
|
||||||
<DownloadIcon v-if="!profile.installedMod && !profile.installing" />
|
<DownloadIcon v-if="!profile.installedMod && !profile.installing" />
|
||||||
@@ -266,7 +258,7 @@ const check_valid = computed(() => {
|
|||||||
? 'Installing...'
|
? 'Installing...'
|
||||||
: profile.installedMod
|
: profile.installedMod
|
||||||
? 'Installed'
|
? 'Installed'
|
||||||
: profile.metadata.linked_data && profile.metadata.linked_data.locked
|
: profile.linked_data && profile.linked_data.locked
|
||||||
? 'Paired'
|
? 'Paired'
|
||||||
: 'Install'
|
: 'Install'
|
||||||
}}
|
}}
|
||||||
@@ -297,7 +289,7 @@ const check_valid = computed(() => {
|
|||||||
placeholder="Name"
|
placeholder="Name"
|
||||||
class="creation-input"
|
class="creation-input"
|
||||||
/>
|
/>
|
||||||
<Button :disabled="creatingInstance === true || !check_valid" @click="createInstance()">
|
<Button :disabled="creatingInstance === true || !name" @click="createInstance()">
|
||||||
<RightArrowIcon />
|
<RightArrowIcon />
|
||||||
{{ creatingInstance ? 'Creating...' : 'Create' }}
|
{{ creatingInstance ? 'Creating...' : 'Create' }}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -0,0 +1,367 @@
|
|||||||
|
<script setup>
|
||||||
|
import { UserIcon, LockIcon, MailIcon } from '@modrinth/assets'
|
||||||
|
import { Button, Card, Checkbox, Modal } from '@modrinth/ui'
|
||||||
|
import {
|
||||||
|
DiscordIcon,
|
||||||
|
GithubIcon,
|
||||||
|
MicrosoftIcon,
|
||||||
|
GoogleIcon,
|
||||||
|
SteamIcon,
|
||||||
|
GitLabIcon,
|
||||||
|
} from '@/assets/external'
|
||||||
|
import { login, login_2fa, create_account, login_pass } from '@/helpers/mr_auth.js'
|
||||||
|
import { handleError, useNotifications } from '@/store/state.js'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { handleSevereError } from '@/store/error.js'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
callback: {
|
||||||
|
type: Function,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const modal = ref()
|
||||||
|
const turnstileToken = ref()
|
||||||
|
const widgetId = ref()
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show: () => {
|
||||||
|
modal.value.show()
|
||||||
|
|
||||||
|
if (window.turnstile === null || !window.turnstile) {
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.src =
|
||||||
|
'https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback'
|
||||||
|
script.async = true
|
||||||
|
script.defer = true
|
||||||
|
document.head.appendChild(script)
|
||||||
|
|
||||||
|
window.onloadTurnstileCallback = loadWidget
|
||||||
|
} else {
|
||||||
|
loadWidget()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
function loadWidget() {
|
||||||
|
widgetId.value = window.turnstile.render('#turnstile-container', {
|
||||||
|
sitekey: '0x4AAAAAAAW3guHM6Eunbgwu',
|
||||||
|
callback: (token) => (turnstileToken.value = token),
|
||||||
|
expiredCallback: () => (turnstileToken.value = null),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeWidget() {
|
||||||
|
if (widgetId.value) {
|
||||||
|
window.turnstile.remove(widgetId.value)
|
||||||
|
widgetId.value = null
|
||||||
|
turnstileToken.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loggingIn = ref(true)
|
||||||
|
const twoFactorFlow = ref(null)
|
||||||
|
const twoFactorCode = ref('')
|
||||||
|
|
||||||
|
const email = ref('')
|
||||||
|
const username = ref('')
|
||||||
|
const password = ref('')
|
||||||
|
const confirmPassword = ref('')
|
||||||
|
const subscribe = ref(true)
|
||||||
|
|
||||||
|
async function signInOauth(provider) {
|
||||||
|
const creds = await login(provider).catch(handleSevereError)
|
||||||
|
|
||||||
|
if (creds && creds.type === 'two_factor_required') {
|
||||||
|
twoFactorFlow.value = creds.flow
|
||||||
|
} else if (creds && creds.session) {
|
||||||
|
props.callback()
|
||||||
|
modal.value.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function signIn2fa() {
|
||||||
|
const creds = await login_2fa(twoFactorCode.value, twoFactorFlow.value).catch(handleError)
|
||||||
|
|
||||||
|
if (creds && creds.session) {
|
||||||
|
props.callback()
|
||||||
|
modal.value.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function signIn() {
|
||||||
|
const creds = await login_pass(username.value, password.value, turnstileToken.value).catch(
|
||||||
|
handleError,
|
||||||
|
)
|
||||||
|
window.turnstile.reset(widgetId.value)
|
||||||
|
|
||||||
|
if (creds && creds.type === 'two_factor_required') {
|
||||||
|
twoFactorFlow.value = creds.flow
|
||||||
|
} else if (creds && creds.session) {
|
||||||
|
props.callback()
|
||||||
|
modal.value.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createAccount() {
|
||||||
|
if (password.value !== confirmPassword.value) {
|
||||||
|
const notifs = useNotifications()
|
||||||
|
notifs.addNotification({
|
||||||
|
title: 'An error occurred',
|
||||||
|
text: 'Passwords do not match!',
|
||||||
|
type: 'error',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const creds = await create_account(
|
||||||
|
username.value,
|
||||||
|
email.value,
|
||||||
|
password.value,
|
||||||
|
turnstileToken.value,
|
||||||
|
subscribe.value,
|
||||||
|
).catch(handleError)
|
||||||
|
window.turnstile.reset(widgetId.value)
|
||||||
|
|
||||||
|
if (creds && creds.session) {
|
||||||
|
props.callback()
|
||||||
|
modal.value.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal ref="modal" :on-hide="removeWidget">
|
||||||
|
<Card>
|
||||||
|
<template v-if="twoFactorFlow">
|
||||||
|
<h1>Enter two-factor code</h1>
|
||||||
|
<p>Please enter a two-factor code to proceed.</p>
|
||||||
|
<input v-model="twoFactorCode" maxlength="11" type="text" placeholder="Enter code..." />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<h1 v-if="loggingIn">Login to Modrinth</h1>
|
||||||
|
<h1 v-else>Create an account</h1>
|
||||||
|
<div class="button-grid">
|
||||||
|
<Button class="discord" large @click="signInOauth('discord')">
|
||||||
|
<DiscordIcon />
|
||||||
|
Discord
|
||||||
|
</Button>
|
||||||
|
<Button class="github" large @click="signInOauth('github')">
|
||||||
|
<GithubIcon />
|
||||||
|
Github
|
||||||
|
</Button>
|
||||||
|
<Button class="white" large @click="signInOauth('microsoft')">
|
||||||
|
<MicrosoftIcon />
|
||||||
|
Microsoft
|
||||||
|
</Button>
|
||||||
|
<Button class="google" large @click="signInOauth('google')">
|
||||||
|
<GoogleIcon />
|
||||||
|
Google
|
||||||
|
</Button>
|
||||||
|
<Button class="white" large @click="signInOauth('steam')">
|
||||||
|
<SteamIcon />
|
||||||
|
Steam
|
||||||
|
</Button>
|
||||||
|
<Button class="gitlab" large @click="signInOauth('gitlab')">
|
||||||
|
<GitLabIcon />
|
||||||
|
GitLab
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div class="divider">
|
||||||
|
<hr />
|
||||||
|
<p>Or</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="!loggingIn" class="iconified-input username">
|
||||||
|
<MailIcon />
|
||||||
|
<input v-model="email" type="text" placeholder="Email" />
|
||||||
|
</div>
|
||||||
|
<div class="iconified-input username">
|
||||||
|
<UserIcon />
|
||||||
|
<input
|
||||||
|
v-model="username"
|
||||||
|
type="text"
|
||||||
|
:placeholder="loggingIn ? 'Email or username' : 'Username'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="iconified-input" :class="{ username: !loggingIn }">
|
||||||
|
<LockIcon />
|
||||||
|
<input v-model="password" type="password" placeholder="Password" />
|
||||||
|
</div>
|
||||||
|
<div v-if="!loggingIn" class="iconified-input username">
|
||||||
|
<LockIcon />
|
||||||
|
<input v-model="confirmPassword" type="password" placeholder="Confirm password" />
|
||||||
|
</div>
|
||||||
|
<div class="turnstile">
|
||||||
|
<div id="turnstile-container"></div>
|
||||||
|
<div id="turnstile-container-2"></div>
|
||||||
|
</div>
|
||||||
|
<Checkbox
|
||||||
|
v-if="!loggingIn"
|
||||||
|
v-model="subscribe"
|
||||||
|
class="subscribe-btn"
|
||||||
|
label="Subscribe to updates about Modrinth"
|
||||||
|
/>
|
||||||
|
<div class="link-row">
|
||||||
|
<a v-if="loggingIn" class="button-base" @click="loggingIn = false"> Create account </a>
|
||||||
|
<a v-else class="button-base" @click="loggingIn = true">Sign in</a>
|
||||||
|
<a class="button-base" href="https://modrinth.com/auth/reset-password">
|
||||||
|
Forgot password?
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="button-row">
|
||||||
|
<Button class="transparent" large>Close</Button>
|
||||||
|
<Button v-if="twoFactorCode" color="primary" large @click="signIn2fa"> Login </Button>
|
||||||
|
<Button
|
||||||
|
v-else-if="loggingIn"
|
||||||
|
color="primary"
|
||||||
|
large
|
||||||
|
@click="signIn"
|
||||||
|
:disabled="!turnstileToken"
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</Button>
|
||||||
|
<Button v-else color="primary" large @click="createAccount" :disabled="!turnstileToken">
|
||||||
|
Create account
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
:deep(.modal-container) {
|
||||||
|
.modal-body {
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
width: 25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-gap: var(--gap-md);
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discord {
|
||||||
|
background-color: #5865f2;
|
||||||
|
color: var(--color-contrast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.github {
|
||||||
|
background-color: #8740f1;
|
||||||
|
color: var(--color-contrast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.white {
|
||||||
|
background-color: var(--color-contrast);
|
||||||
|
color: var(--color-accent-contrast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.google {
|
||||||
|
background-color: #4285f4;
|
||||||
|
color: var(--color-contrast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gitlab {
|
||||||
|
background-color: #fc6d26;
|
||||||
|
color: var(--color-contrast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin: var(--gap-md) 0;
|
||||||
|
|
||||||
|
p {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background-color: var(--color-raised-bg);
|
||||||
|
padding: 0 1rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 2px solid var(--color-button-bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconified-input {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
flex-basis: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
margin-bottom: var(--gap-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin: var(--gap-md) 0;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-blue);
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
flex-basis: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transparent {
|
||||||
|
padding: var(--gap-md) 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.checkbox) {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turnstile {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
border: 2px solid var(--color-button-bg);
|
||||||
|
height: 66px;
|
||||||
|
margin-top: var(--gap-md);
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
margin: -1px;
|
||||||
|
min-width: calc(100% + 2px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
|
import cssContent from '@/assets/stylesheets/macFix.css?inline'
|
||||||
|
|
||||||
|
export async function useCheckDisableMouseover() {
|
||||||
|
try {
|
||||||
|
// Fetch the CSS content from the Rust backend
|
||||||
|
let should_disable_mouseover = await invoke('plugin:utils|should_disable_mouseover')
|
||||||
|
|
||||||
|
if (should_disable_mouseover) {
|
||||||
|
// Create a style element and set its content
|
||||||
|
const styleElement = document.createElement('style')
|
||||||
|
styleElement.innerHTML = cssContent
|
||||||
|
|
||||||
|
// Append the style element to the document's head
|
||||||
|
document.head.appendChild(styleElement)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error checking OS version from Rust backend', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { posthog } from 'posthog-js'
|
||||||
|
|
||||||
|
export const initAnalytics = () => {
|
||||||
|
posthog.init('phc_hm2ihMpTAoE86xIm7XzsCB8RPiTRKivViK5biiHedm', {
|
||||||
|
persistence: 'localStorage',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const debugAnalytics = () => {
|
||||||
|
posthog.debug()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const optOutAnalytics = () => {
|
||||||
|
posthog.opt_out_capturing()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const optInAnalytics = () => {
|
||||||
|
posthog.opt_in_capturing()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const trackEvent = (eventName, properties) => {
|
||||||
|
posthog.capture(eventName, properties)
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* All theseus API calls return serialized values (both return values and errors);
|
||||||
|
* So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
|
||||||
|
* and deserialized into a usable JS object.
|
||||||
|
*/
|
||||||
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
|
|
||||||
|
// Example function:
|
||||||
|
// User goes to auth_url to complete flow, and when completed, authenticate_await_completion() returns the credentials
|
||||||
|
// export async function authenticate() {
|
||||||
|
// const auth_url = await authenticate_begin_flow()
|
||||||
|
// console.log(auth_url)
|
||||||
|
// await authenticate_await_completion()
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate a user with Hydra - part 1.
|
||||||
|
* This begins the authentication flow quasi-synchronously.
|
||||||
|
*
|
||||||
|
* @returns {Promise<DeviceLoginSuccess>} A DeviceLoginSuccess object with two relevant fields:
|
||||||
|
* @property {string} verification_uri - The URL to go to complete the flow.
|
||||||
|
* @property {string} user_code - The code to enter on the verification_uri page.
|
||||||
|
*/
|
||||||
|
export async function login() {
|
||||||
|
return await invoke('plugin:auth|login')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the default user
|
||||||
|
* @return {Promise<UUID | undefined>}
|
||||||
|
*/
|
||||||
|
export async function get_default_user() {
|
||||||
|
return await invoke('plugin:auth|get_default_user')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the default user
|
||||||
|
* @param {UUID} user
|
||||||
|
*/
|
||||||
|
export async function set_default_user(user) {
|
||||||
|
return await invoke('plugin:auth|set_default_user', { user })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a user account from the database
|
||||||
|
* @param {UUID} user
|
||||||
|
*/
|
||||||
|
export async function remove_user(user) {
|
||||||
|
return await invoke('plugin:auth|remove_user', { user })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of users
|
||||||
|
* @returns {Promise<Credential[]>}
|
||||||
|
*/
|
||||||
|
export async function users() {
|
||||||
|
return await invoke('plugin:auth|get_users')
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
|
|
||||||
|
export async function get_project(id, cacheBehaviour) {
|
||||||
|
return await invoke('plugin:cache|get_project', { id, cacheBehaviour })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get_project_many(ids, cacheBehaviour) {
|
||||||
|
return await invoke('plugin:cache|get_project_many', { ids, cacheBehaviour })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get_version(id, cacheBehaviour) {
|
||||||
|
return await invoke('plugin:cache|get_version', { id, cacheBehaviour })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get_version_many(ids, cacheBehaviour) {
|
||||||
|
return await invoke('plugin:cache|get_version_many', { ids, cacheBehaviour })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get_user(id, cacheBehaviour) {
|
||||||
|
return await invoke('plugin:cache|get_user', { id, cacheBehaviour })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get_user_many(ids, cacheBehaviour) {
|
||||||
|
return await invoke('plugin:cache|get_user_many', { ids, cacheBehaviour })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get_team(id, cacheBehaviour) {
|
||||||
|
return await invoke('plugin:cache|get_team', { id, cacheBehaviour })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get_team_many(ids, cacheBehaviour) {
|
||||||
|
return await invoke('plugin:cache|get_team_many', { ids, cacheBehaviour })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get_organization(id, cacheBehaviour) {
|
||||||
|
return await invoke('plugin:cache|get_organization', { id, cacheBehaviour })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get_organization_many(ids, cacheBehaviour) {
|
||||||
|
return await invoke('plugin:cache|get_organization_many', { ids, cacheBehaviour })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get_search_results(id, cacheBehaviour) {
|
||||||
|
return await invoke('plugin:cache|get_search_results', { id, cacheBehaviour })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function get_search_results_many(ids, cacheBehaviour) {
|
||||||
|
return await invoke('plugin:cache|get_search_results_many', { ids, cacheBehaviour })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function purge_cache_types(cacheTypes) {
|
||||||
|
return await invoke('plugin:cache|purge_cache_types', { cacheTypes })
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
// event.payload is the payload object
|
// event.payload is the payload object
|
||||||
console.log(event)
|
console.log(event)
|
||||||
})
|
})
|
||||||
|
|
||||||
Putting that in a script will print any emitted signal from rust
|
Putting that in a script will print any emitted signal from rust
|
||||||
*/
|
*/
|
||||||
import { listen } from '@tauri-apps/api/event'
|
import { listen } from '@tauri-apps/api/event'
|
||||||
@@ -93,15 +93,3 @@ export async function command_listener(callback) {
|
|||||||
export async function warning_listener(callback) {
|
export async function warning_listener(callback) {
|
||||||
return await listen('warning', (event) => callback(event.payload))
|
return await listen('warning', (event) => callback(event.payload))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Payload for the 'offline' event
|
|
||||||
/*
|
|
||||||
OfflinePayload {
|
|
||||||
offline: bool, true or false
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
export async function offline_listener(callback) {
|
|
||||||
return await listen('offline', (event) => {
|
|
||||||
return callback(event.payload)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
File renamed without changes.
Loaded 100 of 953 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user