Compare commits
2055 Commits
pre-monore
...
shared-ins
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96782b52cd | ||
|
|
aae00e1312 | ||
|
|
24e90f0a54 | ||
|
|
f5208a85b0 | ||
|
|
8db4b3f83b | ||
|
|
33ad04d036 | ||
|
|
4bcdb3f495 | ||
|
|
70979172b0 | ||
|
|
493b9a3975 | ||
|
|
5a21a67d46 | ||
|
|
ff72c906ba | ||
|
|
907b1f67ed | ||
|
|
72cbe7f905 | ||
|
|
deb16aa7ab | ||
|
|
d0efa44c9e | ||
|
|
d321843c02 | ||
|
|
2b44b145cb | ||
|
|
9f5606889e | ||
|
|
417f2a8b91 | ||
|
|
d3a7bf967e | ||
|
|
db145cd8ad | ||
|
|
7d614f7ac5 | ||
|
|
c7a2a3e29b | ||
|
|
3b966c03ee | ||
|
|
66d943d391 | ||
|
|
f5f876e458 | ||
|
|
27c3439120 | ||
|
|
f212d04261 | ||
|
|
06f01aa85c | ||
|
|
5f48dc08a9 | ||
|
|
e81e056758 | ||
|
|
2d95ff0830 | ||
|
|
81d921d625 | ||
|
|
e988513ed7 | ||
|
|
783d4f82d9 | ||
|
|
b5011f458f | ||
|
|
5d0e4366d2 | ||
|
|
8643dc02dd | ||
|
|
7c4dcb2817 | ||
|
|
6b64fdafcb | ||
|
|
185dd47668 | ||
|
|
f165665a35 | ||
|
|
ad38749f98 | ||
|
|
7825dd64ca | ||
|
|
f6af620643 | ||
|
|
b5aeef7ebf | ||
|
|
f5a201dd94 | ||
|
|
72dab12033 | ||
|
|
ce4b4ba41d | ||
|
|
945206153d | ||
|
|
9f977d082b | ||
|
|
4a2ec0c40c | ||
|
|
70bf61a645 | ||
|
|
674f4b1095 | ||
|
|
3304070034 | ||
|
|
19ca5f08c6 | ||
|
|
5605910ac8 | ||
|
|
b1eda435a5 | ||
|
|
e88ca8430e | ||
|
|
d39db02a73 | ||
|
|
86a64ca929 | ||
|
|
5ea0f7d4c7 | ||
|
|
b3fa2fa6d2 | ||
|
|
999dc640bc | ||
|
|
9be9658ffb | ||
|
|
595d5362f6 | ||
|
|
f212fcf892 | ||
|
|
8c1c5572c0 | ||
|
|
31d151638a | ||
|
|
fb6b41630c | ||
|
|
6ab806cbde | ||
|
|
c0267f7746 | ||
|
|
a54b6dc7b9 | ||
|
|
9ec43ebe70 | ||
|
|
486cd68bf7 | ||
|
|
98c050e7e9 | ||
|
|
25fcee984b | ||
|
|
86922c4547 | ||
|
|
7bbdfd25cd | ||
|
|
b8ad22a6fb | ||
|
|
8dd955563e | ||
|
|
663ab83b08 | ||
|
|
c143929b69 | ||
|
|
1b73d248b3 | ||
|
|
cc22a92daf | ||
|
|
39f0408929 | ||
|
|
e66f46a464 | ||
|
|
9243296197 | ||
|
|
26ce83f8f1 | ||
|
|
907ef38189 | ||
|
|
a7d4001b00 | ||
|
|
e3a3379615 | ||
|
|
356a06e694 | ||
|
|
fce516a76f | ||
|
|
42ade0fbd1 | ||
|
|
ba07f5dad4 | ||
|
|
cc89e0f3f1 | ||
|
|
0e14d3f9c1 | ||
|
|
ff7975773e | ||
|
|
6716e2277d | ||
|
|
f986dc5d11 | ||
|
|
570a4096f9 | ||
|
|
c88bfbb5f0 | ||
|
|
d302795512 | ||
|
|
115acce80c | ||
|
|
a8731b0ca2 | ||
|
|
fd596bf418 | ||
|
|
ef7cfffeb6 | ||
|
|
ac9bcabd9c | ||
|
|
5bb961f16b | ||
|
|
a46677832b | ||
|
|
624abf0df4 | ||
|
|
e81a4ade97 | ||
|
|
9708685506 | ||
|
|
28b6bf8603 | ||
|
|
2713f0e610 | ||
|
|
f7d1cd2a4f | ||
|
|
3b8963fad0 | ||
|
|
060682a1ac | ||
|
|
95cd48571e | ||
|
|
3d619e6a98 | ||
|
|
edb7e5f323 | ||
|
|
0221034b60 | ||
|
|
9500384100 | ||
|
|
0b31f2eb41 | ||
|
|
b3a6393c91 | ||
|
|
5b5599128a | ||
|
|
cb0f03ca9c | ||
|
|
2e35f3608b | ||
|
|
16c5a5a3a6 | ||
|
|
2e7db502a9 | ||
|
|
d29b71ec45 | ||
|
|
9cd0af914a | ||
|
|
4a575393f0 | ||
|
|
76c93c767d | ||
|
|
e69337a1fc | ||
|
|
50734af6cd | ||
|
|
81b0922c93 | ||
|
|
d4f8fff7af | ||
|
|
bd61f5d591 | ||
|
|
016c3d779b | ||
|
|
acf26940d6 | ||
|
|
4bafae881f | ||
|
|
8311451420 | ||
|
|
4b75cb8357 | ||
|
|
bf16d360af | ||
|
|
38d95b4faf | ||
|
|
b06e7d3cf4 | ||
|
|
9e7ea82f94 | ||
|
|
d74fc8a5d5 | ||
|
|
4a43b45a99 | ||
|
|
d6a72fbfc4 | ||
|
|
396f737612 | ||
|
|
2dd8d5a119 | ||
|
|
656c5b61cc | ||
|
|
9fd0f6834a | ||
|
|
58dac27186 | ||
|
|
c8befb6843 | ||
|
|
fafd47fd90 | ||
|
|
e0990910f6 | ||
|
|
599f23c8aa | ||
|
|
a0bd011b80 | ||
|
|
157c27c20d | ||
|
|
4d0407a3b3 | ||
|
|
f73ed1213f | ||
|
|
679ffbcce7 | ||
|
|
daabe11d11 | ||
|
|
aaf125cfca | ||
|
|
161fc6bb68 | ||
|
|
1afed9f256 | ||
|
|
e8d6c15fee | ||
|
|
8686b28c28 | ||
|
|
d68251ad4b | ||
|
|
a02b4ae08f | ||
|
|
9ed1dd714b | ||
|
|
95dc6c66d9 | ||
|
|
e91c76c10c | ||
|
|
9deddbbe7c | ||
|
|
2d416d491c | ||
|
|
a19ce0458a | ||
|
|
3fca24e6fd | ||
|
|
6f956e0423 | ||
|
|
637a923e84 | ||
|
|
bb3ce9fbc6 | ||
|
|
06f2340569 | ||
|
|
510c29cc71 | ||
|
|
807aa04807 | ||
|
|
c84e2e0537 | ||
|
|
1f8d569b79 | ||
|
|
93ae24e707 | ||
|
|
910e219c0e | ||
|
|
3a4843fb46 | ||
|
|
1b3744baa2 | ||
|
|
7dd340f0b6 | ||
|
|
1d0d8d7fbe | ||
|
|
c7d8c8b104 | ||
|
|
a380d39865 | ||
|
|
34d3310eae | ||
|
|
6de8d2684a | ||
|
|
9763a43943 | ||
|
|
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 | ||
|
|
60edbcd5f0 | ||
|
|
dab284f339 | ||
|
|
df76d9a50a | ||
|
|
abec2e48d4 | ||
|
|
0f2ddb452c | ||
|
|
6fa1acc461 | ||
|
|
9502639447 | ||
|
|
ef4acb1b66 | ||
|
|
8cb72d306b | ||
|
|
1ef8bf4690 | ||
|
|
22779c9dbc | ||
|
|
b52467b6d6 | ||
|
|
d33a0cd589 | ||
|
|
a04cb54d86 | ||
|
|
10785f156f | ||
|
|
4736fb8e32 | ||
|
|
531e7ec73d | ||
|
|
ff946b4f2f | ||
|
|
68f0e68343 | ||
|
|
12a3520563 | ||
|
|
e84426a4f9 | ||
|
|
8b80934f77 | ||
|
|
b6618f81f8 | ||
|
|
0ae1e40d79 | ||
|
|
34d931573c | ||
|
|
721365578a | ||
|
|
7be02318e0 | ||
|
|
88db79188c | ||
|
|
8a0329b23d | ||
|
|
02ebe59d2f | ||
|
|
6e8e053b88 | ||
|
|
fc3056b0e0 | ||
|
|
4274a8ed68 | ||
|
|
8b16cd1b36 | ||
|
|
bd49d6bd89 | ||
|
|
61fd6f1741 | ||
|
|
05d45d9aab | ||
|
|
612eb64a83 | ||
|
|
e0a9e62d84 | ||
|
|
5db5f2251f | ||
|
|
34fd9d29c8 | ||
|
|
5148e27448 | ||
|
|
c6d8476963 | ||
|
|
608e55c01f | ||
|
|
b8963d272a | ||
|
|
beaaed6613 | ||
|
|
6bbd8c9b16 | ||
|
|
872ffa02ce | ||
|
|
1d9fe0c03d | ||
|
|
5b2d36e976 | ||
|
|
547135f7d2 | ||
|
|
15f1416f52 | ||
|
|
b2709aa816 | ||
|
|
9775d4e74d | ||
|
|
f5661af1f4 | ||
|
|
b933202694 | ||
|
|
611bec38b4 | ||
|
|
49cf0c8a9a | ||
|
|
83ccf4928f | ||
|
|
28b0d34bff | ||
|
|
5a166d2455 | ||
|
|
6808d270a7 | ||
|
|
9dc68611a1 | ||
|
|
e932f38160 | ||
|
|
9014835880 | ||
|
|
00328d04cd | ||
|
|
5b1850e161 | ||
|
|
60727656c9 | ||
|
|
372d021062 | ||
|
|
9c4421bfe0 | ||
|
|
5f85af76cd | ||
|
|
4c2565826f | ||
|
|
ae2d83c8aa | ||
|
|
3b0216ca7e | ||
|
|
0a0837ea02 | ||
|
|
a0aa350a08 | ||
|
|
1abfb175b5 | ||
|
|
a771695348 | ||
|
|
decfcb6c27 | ||
|
|
730913bec4 | ||
|
|
f8f037196e | ||
|
|
fe3e4edb04 | ||
|
|
364a4faa75 | ||
|
|
e2ffeab8fa | ||
|
|
331787fe43 | ||
|
|
9484a7237c | ||
|
|
04d834187b | ||
|
|
96063969ae | ||
|
|
cb1c8be870 | ||
|
|
33b2a94d90 | ||
|
|
ce3b024fea | ||
|
|
a02aa7586b | ||
|
|
5ea71da181 | ||
|
|
dda469d10e | ||
|
|
9f6e033c53 | ||
|
|
15f44adf3b | ||
|
|
e9483cb242 | ||
|
|
5243d8bedf | ||
|
|
ed731fd7a6 | ||
|
|
07f5422132 | ||
|
|
5aa1764848 | ||
|
|
4973ee555b | ||
|
|
d5107f2ef6 | ||
|
|
5b63b0b398 | ||
|
|
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 | ||
|
|
fc577241bd | ||
|
|
bb8a0e596c | ||
|
|
2a63b703f9 | ||
|
|
bfeff78164 | ||
|
|
4826289020 | ||
|
|
0aebf37ef8 | ||
|
|
2fb63dcfb1 | ||
|
|
0adb7685f6 | ||
|
|
1cbe99a0d8 | ||
|
|
d1a09d0b95 | ||
|
|
7b00003958 | ||
|
|
4483bb147c | ||
|
|
fa83da6085 | ||
|
|
ef31c0c0da | ||
|
|
1392c16f12 | ||
|
|
d6393653e1 | ||
|
|
a75de51198 | ||
|
|
a21869ec9b | ||
|
|
f534e4ee37 | ||
|
|
9add661a5b | ||
|
|
76c885f080 | ||
|
|
f16e93bd3a | ||
|
|
05d2a96900 | ||
|
|
81948a5c29 | ||
|
|
5924154a62 | ||
|
|
354bfe58cd | ||
|
|
c5974a8575 | ||
|
|
c0275addb0 | ||
|
|
9c70c35669 | ||
|
|
c85baf7fd0 | ||
|
|
39e5778bd0 | ||
|
|
a3b77bb37f | ||
|
|
9d54c41a2b | ||
|
|
660cf0c1e4 | ||
|
|
3464fbb2e8 | ||
|
|
11020c4545 | ||
|
|
e93bf02e3a | ||
|
|
d51d6517be | ||
|
|
a629d7f048 | ||
|
|
5f6cc1281e | ||
|
|
683b0f5c48 | ||
|
|
42a80a41ca | ||
|
|
035fc69060 | ||
|
|
34baf44534 | ||
|
|
9dcb90a9cf | ||
|
|
c3448033de | ||
|
|
aee9b6a951 | ||
|
|
1af0aa3f57 | ||
|
|
35c9338220 | ||
|
|
2e8fa0f6c5 | ||
|
|
931aeda17f | ||
|
|
a037d24b0f | ||
|
|
75e5bec962 | ||
|
|
59c269c8d0 | ||
|
|
1fa556cd00 | ||
|
|
82e9ad8a20 | ||
|
|
541022cdc3 | ||
|
|
d893765b24 | ||
|
|
527521328f | ||
|
|
917b89e44f | ||
|
|
87862f3e23 | ||
|
|
10eed05d87 | ||
|
|
f5802fee31 | ||
|
|
1108b0264e | ||
|
|
cf9c8cbb4f | ||
|
|
4f060579ca | ||
|
|
1940c6e1ba | ||
|
|
f199ecf8e9 | ||
|
|
e754f6c234 | ||
|
|
d19dbbfe7e | ||
|
|
3a735ea0ce | ||
|
|
e319d19a54 | ||
|
|
3bdd551d40 | ||
|
|
4a7936a51d | ||
|
|
5f075e4936 | ||
|
|
76e00c2432 | ||
|
|
b46f3bf2c4 | ||
|
|
f7b4b782bf | ||
|
|
60c535e861 | ||
|
|
d59c522f7f | ||
|
|
9f798559cf | ||
|
|
f939e59463 | ||
|
|
50e89ad98b | ||
|
|
c0c5978028 | ||
|
|
abbeed394e | ||
|
|
f5b8c15388 | ||
|
|
f53b6b550f | ||
|
|
00e55b1874 | ||
|
|
90954dac49 | ||
|
|
6217523cc8 | ||
|
|
27ccd3dfa8 | ||
|
|
235f4f10ef | ||
|
|
d6ba3f3adf | ||
|
|
b453e2cf1a | ||
|
|
2d14e5682d | ||
|
|
945e5a2dc3 | ||
|
|
4b6a2685d0 | ||
|
|
1f58aebb2b | ||
|
|
6d70ced93a | ||
|
|
e76b6c3bde | ||
|
|
4630d175d7 | ||
|
|
27055b96e3 | ||
|
|
0ef96c0bca | ||
|
|
b2be4a7d67 | ||
|
|
a70df067bc | ||
|
|
2d92b08404 | ||
|
|
4bbc57b0dc | ||
|
|
756c14d988 | ||
|
|
b3b55210f7 | ||
|
|
58093a9438 | ||
|
|
ed33dd2127 | ||
|
|
accc53c5dd | ||
|
|
d4f9c97cca | ||
|
|
f731c1080d | ||
|
|
fd18185ef0 | ||
|
|
0efbbed5e2 | ||
|
|
bad350e49b | ||
|
|
172b93d07f | ||
|
|
ade8c162cd | ||
|
|
79e634316d | ||
|
|
e4cb8b71dd | ||
|
|
dfba6c7c91 | ||
|
|
f6eff090e7 | ||
|
|
e06a77af28 | ||
|
|
61a2c362b9 | ||
|
|
74973e73e6 | ||
|
|
cbcee037a7 | ||
|
|
de2e4a9c7f | ||
|
|
0ba0a5bcd8 | ||
|
|
70cc409402 | ||
|
|
160ca610ae | ||
|
|
2f1aa95f4c | ||
|
|
ac07ac5234 | ||
|
|
3eead128a6 | ||
|
|
4c22a73ff3 | ||
|
|
a78f58de92 | ||
|
|
fcda48903b | ||
|
|
3f9805ac56 | ||
|
|
2131fed0bb | ||
|
|
baa5d2fcac | ||
|
|
7cf9b76eb5 | ||
|
|
200648275e | ||
|
|
f4880d0519 | ||
|
|
375f992a0c | ||
|
|
a7584d62c7 | ||
|
|
74e6caf633 | ||
|
|
f1f531cbfa | ||
|
|
b5a275ad07 | ||
|
|
5051ad91ff | ||
|
|
06d6cb6d19 | ||
|
|
92116273b0 | ||
|
|
6169ff99a2 | ||
|
|
67f77d027a | ||
|
|
39e1a803a1 | ||
|
|
ba159e1a3e | ||
|
|
a60b77121a | ||
|
|
810f0104be | ||
|
|
07489fb405 | ||
|
|
82f0bdfc18 | ||
|
|
ae1c5342f2 | ||
|
|
66154b30c1 | ||
|
|
bf5d391d53 | ||
|
|
591ce0894e | ||
|
|
1c18563dfb | ||
|
|
b60e781767 | ||
|
|
ca54544b82 | ||
|
|
9c3ff71ce4 | ||
|
|
fd82ec7659 | ||
|
|
97ccb7df94 | ||
|
|
a818199b5a | ||
|
|
6fe1fa3455 | ||
|
|
aab95444a8 | ||
|
|
40f28be3b4 | ||
|
|
911d442340 | ||
|
|
d5594b03e3 | ||
|
|
23ccaacdee | ||
|
|
89f1ddf4d7 | ||
|
|
39a4297168 | ||
|
|
6cfd4637db | ||
|
|
544111846c | ||
|
|
79bdea0441 | ||
|
|
c056c4e79e | ||
|
|
19828e9070 | ||
|
|
8231c736ca | ||
|
|
85f639b1f0 | ||
|
|
c471b6d66c | ||
|
|
a363efccfb | ||
|
|
871a17a108 | ||
|
|
16a39b364c | ||
|
|
8803e11945 | ||
|
|
b1ca2cc2b6 | ||
|
|
91f79d2be0 | ||
|
|
9932fe5055 | ||
|
|
c296597427 | ||
|
|
97cb5bc12c | ||
|
|
7c596d6bf1 | ||
|
|
b68799e2d1 | ||
|
|
9a8f3d7bad | ||
|
|
a3d4db9fc1 | ||
|
|
9d0e762f36 | ||
|
|
8369330053 | ||
|
|
46a6fee81d | ||
|
|
b2c75130ce | ||
|
|
ef444f2a6f | ||
|
|
36f0871f69 | ||
|
|
5adf27d345 | ||
|
|
5e4c261332 | ||
|
|
6fb04e23ad | ||
|
|
2c850a612d | ||
|
|
e555c4d083 | ||
|
|
cb32cca6aa | ||
|
|
abf4cd71ba | ||
|
|
d66270eef0 | ||
|
|
ffb491a61f | ||
|
|
4ecba93a25 | ||
|
|
52ec1d09b8 | ||
|
|
3d2e2e2278 | ||
|
|
f9a9ece320 | ||
|
|
ffc46d6a48 | ||
|
|
ce458642af | ||
|
|
820d3ef426 | ||
|
|
145386b6a7 | ||
|
|
a708cf7f69 | ||
|
|
c70ebb6cce | ||
|
|
07ecd13554 | ||
|
|
a260b6eac4 | ||
|
|
0ab17e1ec8 | ||
|
|
d1a0cd1173 | ||
|
|
f1ff88f452 | ||
|
|
d92272ffa0 | ||
|
|
3955b973ef | ||
|
|
dfa43f3c5a | ||
|
|
259c5ef3d0 | ||
|
|
a1b59d4545 | ||
|
|
fcfa508cbc | ||
|
|
58a61051b9 | ||
|
|
a6766ef1c0 | ||
|
|
606b5ac5ab | ||
|
|
9acc463c7f | ||
|
|
c4ddd08b0a | ||
|
|
5c7dd10769 | ||
|
|
3fa86cb441 | ||
|
|
4a74ee0d72 | ||
|
|
8a8759b0d4 | ||
|
|
f259072136 | ||
|
|
3fd74292ef | ||
|
|
f37c4293df | ||
|
|
b9248553be | ||
|
|
475d434e98 | ||
|
|
05d568d1c1 | ||
|
|
51777c3f33 | ||
|
|
3767e9fae9 | ||
|
|
4bbfc8ccc5 | ||
|
|
531b8214c0 | ||
|
|
28b63bac38 | ||
|
|
5cab618bf7 | ||
|
|
fc64719bb8 | ||
|
|
3380f4d11c | ||
|
|
4bf030993a | ||
|
|
323a74eef3 | ||
|
|
bd4da4f365 | ||
|
|
f65f949a36 | ||
|
|
2864abd8c2 | ||
|
|
9bd2cb3c7e | ||
|
|
35cd277fcf | ||
|
|
ae7f7e9bd6 | ||
|
|
57b1932b5e | ||
|
|
e6818023a3 | ||
|
|
35a541f99b | ||
|
|
5fb00a947c | ||
|
|
6288f679b9 | ||
|
|
b88e63d133 | ||
|
|
a85255df5a | ||
|
|
15c02e9e91 | ||
|
|
ec35392cd1 | ||
|
|
b14b977bca | ||
|
|
54f55d44dc | ||
|
|
568dc1625e | ||
|
|
259b239e16 | ||
|
|
3033387ffc | ||
|
|
d500c29493 | ||
|
|
799d8003eb | ||
|
|
5d34af6ac5 | ||
|
|
dca5b9f197 | ||
|
|
75e075ef8e | ||
|
|
9895976128 | ||
|
|
133367ddb5 | ||
|
|
57964282ee | ||
|
|
51b07fc0c3 | ||
|
|
d8f33641a5 | ||
|
|
a7c7234589 | ||
|
|
e766759b8c | ||
|
|
f22f1971cb | ||
|
|
28a5806492 | ||
|
|
df98167706 | ||
|
|
06cc40055a | ||
|
|
66b47c08e6 | ||
|
|
40cb8db1fc | ||
|
|
2454a03c2b | ||
|
|
0a59a06121 | ||
|
|
a7191e8efb | ||
|
|
e1f4d791ae | ||
|
|
c1d28381e8 | ||
|
|
2fa8371bae | ||
|
|
a1cfdf1a5b | ||
|
|
806fcb6ed2 | ||
|
|
467b0fa988 | ||
|
|
a420d5b203 | ||
|
|
e9c7f5d664 | ||
|
|
c85f12fe2c | ||
|
|
13e5644c89 | ||
|
|
5be3aec7d4 | ||
|
|
5e25a4a00e | ||
|
|
810cf9ab2c | ||
|
|
eac029aef4 | ||
|
|
2a11de7571 | ||
|
|
12543be913 | ||
|
|
cfbf08dbf5 | ||
|
|
3649573ba1 | ||
|
|
0fdc02d5e9 | ||
|
|
0ffe8ef102 | ||
|
|
ce995812d4 | ||
|
|
cd22e1779d | ||
|
|
fbb50d8fb6 | ||
|
|
27172c2a19 | ||
|
|
f453dff438 | ||
|
|
a437a40eee | ||
|
|
70a173a16d | ||
|
|
7724fc74e5 | ||
|
|
6023c08554 | ||
|
|
2de56065af | ||
|
|
a5195920fa | ||
|
|
5676a13290 | ||
|
|
d11f0e864e | ||
|
|
df83fcc5b9 | ||
|
|
f21c756793 | ||
|
|
4b07ee2fa8 | ||
|
|
ae3a39ee65 | ||
|
|
e9f5bd4ac1 | ||
|
|
f5cf1ca08c | ||
|
|
1f4ad732fd | ||
|
|
37a1e67579 | ||
|
|
a372cbbf52 | ||
|
|
5637d37ee1 | ||
|
|
c370da2fef | ||
|
|
d168209721 | ||
|
|
ca0468b8d5 | ||
|
|
a67cf44453 | ||
|
|
039d26feeb | ||
|
|
a4bead1bde | ||
|
|
0d15024bd2 | ||
|
|
6509d726b3 | ||
|
|
a132f0f41d | ||
|
|
7c2ea3dcfd | ||
|
|
706c6d46da | ||
|
|
04915cc65a | ||
|
|
e2fb8827a7 | ||
|
|
10e7b66f38 | ||
|
|
05fda903c6 | ||
|
|
91e1eff763 | ||
|
|
2c4ffcfa7c | ||
|
|
34d63f3557 | ||
|
|
4bb47d7e01 | ||
|
|
a5613ebb10 | ||
|
|
ec80c2b9db | ||
|
|
a89418e33b | ||
|
|
0d88ff8dae | ||
|
|
4bdf9bff3a | ||
|
|
7fbb8838e7 | ||
|
|
1a2b45eebd | ||
|
|
366ea63209 | ||
|
|
6c0ad7fe1a | ||
|
|
ef9c90a43a | ||
|
|
239214ef92 | ||
|
|
65791a58e9 | ||
|
|
6e0f22323b | ||
|
|
4c8c35a25a | ||
|
|
a149f06f58 | ||
|
|
42f97f63d5 | ||
|
|
227652de2e | ||
|
|
dd205e849c | ||
|
|
b0057b130e | ||
|
|
05d994889d | ||
|
|
4b381049c3 | ||
|
|
33f3479569 | ||
|
|
6b940ed675 | ||
|
|
247be0c11f | ||
|
|
14b0e8875d | ||
|
|
bd51741b01 | ||
|
|
afd60b8a16 | ||
|
|
6e0659af4c | ||
|
|
6de1fa0878 | ||
|
|
61e00f1620 | ||
|
|
d64c043838 | ||
|
|
c8c75b38c3 | ||
|
|
2bdd0a0e8d | ||
|
|
dd3599f5b3 | ||
|
|
4131ad5016 | ||
|
|
4f74b3fafe | ||
|
|
177a487ead | ||
|
|
99a4966786 | ||
|
|
db9279a6e5 | ||
|
|
3036f43b75 | ||
|
|
f4560bd7d8 | ||
|
|
0d56127758 | ||
|
|
97b9ec5cc7 | ||
|
|
cdab3d0eff | ||
|
|
de991041c4 | ||
|
|
776c16cd49 | ||
|
|
d9f8746438 | ||
|
|
20d1c4d242 | ||
|
|
6edac37031 | ||
|
|
cea5a18a7a | ||
|
|
bf615303f1 | ||
|
|
ea043517c5 | ||
|
|
b84d9c5d55 | ||
|
|
063585f563 | ||
|
|
01304e807a | ||
|
|
d275b3fd08 | ||
|
|
66364354da | ||
|
|
48203aedf9 | ||
|
|
a6ca893ec5 | ||
|
|
d55f1163a2 | ||
|
|
80530012b8 | ||
|
|
d98a6adfb3 | ||
|
|
6c628afe5d | ||
|
|
abc99c7e69 | ||
|
|
fe25cd3bec | ||
|
|
ae3a35816e | ||
|
|
8ca4be5ac0 | ||
|
|
1c814946d5 | ||
|
|
1db59fc052 | ||
|
|
273a69258a | ||
|
|
3b0dc2195d | ||
|
|
bbb2539ace | ||
|
|
03cfe9bf62 | ||
|
|
e29a4d79ba | ||
|
|
4243bf9ba8 | ||
|
|
2eb51edfb6 | ||
|
|
715d564028 | ||
|
|
989b704efc | ||
|
|
7ae9627a79 | ||
|
|
097a1cc799 | ||
|
|
0bfaeb8521 | ||
|
|
625511d28b | ||
|
|
b6a58ee845 | ||
|
|
a349aed94c | ||
|
|
3db00534c2 | ||
|
|
82b96d1a14 | ||
|
|
b85ddd1a53 | ||
|
|
732f88ff51 | ||
|
|
c08139b812 | ||
|
|
a6a6e73b04 | ||
|
|
9971201004 | ||
|
|
e99b0f8052 | ||
|
|
7a59b2b25d | ||
|
|
b713b324f9 | ||
|
|
521e21072e | ||
|
|
f34845fd7d | ||
|
|
29ccadbd43 | ||
|
|
ffb4b395d0 | ||
|
|
19eba9526a | ||
|
|
09ed76904b | ||
|
|
22932241bd | ||
|
|
afc95d99cb | ||
|
|
5fde3c53b8 | ||
|
|
1135852f25 | ||
|
|
e892f0cb45 | ||
|
|
de56374c4d | ||
|
|
6512dbae1c | ||
|
|
3afda71349 | ||
|
|
568e5a9bb8 | ||
|
|
89e56ae279 | ||
|
|
339ac05443 | ||
|
|
9d92b8cc6d | ||
|
|
d9b3ba0ff2 | ||
|
|
4be6b11c1e | ||
|
|
6794da0738 | ||
|
|
5527170fab | ||
|
|
72cfa683cf | ||
|
|
e732eed98a | ||
|
|
5244642dee | ||
|
|
b329a44fef | ||
|
|
3a6b9f04f9 | ||
|
|
59f24df294 | ||
|
|
c93632421d | ||
|
|
97e0fd9f43 | ||
|
|
ea536c5537 | ||
|
|
970c906c97 | ||
|
|
fe738da633 | ||
|
|
5c559af936 | ||
|
|
bb80505b76 | ||
|
|
5e3da71ce4 | ||
|
|
a0cccb299e | ||
|
|
a560f6e9f6 | ||
|
|
95ae981698 | ||
|
|
e56974f4b2 | ||
|
|
fd28da2a3b | ||
|
|
257b35e4ae | ||
|
|
4398563b85 | ||
|
|
969eb67217 | ||
|
|
e23ace1bb0 | ||
|
|
0dfebbad9d | ||
|
|
f87f4bd8cc | ||
|
|
352caa85da | ||
|
|
8f61e9876f | ||
|
|
2ef333c66d | ||
|
|
c6ee44010c | ||
|
|
71d770e679 | ||
|
|
cf17b93201 | ||
|
|
08f284ce29 | ||
|
|
4336aeb0ad | ||
|
|
5fd3a45c64 | ||
|
|
77f8bfcf25 | ||
|
|
509a97e532 | ||
|
|
604683efd5 | ||
|
|
c731515b94 | ||
|
|
8d85158f91 | ||
|
|
0736f372dc | ||
|
|
fd19bb7cd5 | ||
|
|
0c2e9137a2 | ||
|
|
bf5a25a96f | ||
|
|
aa84f21fde | ||
|
|
b9de2b4b58 | ||
|
|
9754f2d1c5 | ||
|
|
f66fc06b4f | ||
|
|
79ceb56c60 | ||
|
|
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 | ||
|
|
7605df1bd9 | ||
|
|
f874941e4d | ||
|
|
b91ec48178 | ||
|
|
3c2f144795 | ||
|
|
437b2ab30a | ||
|
|
0271337f8e | ||
|
|
630a71c46c | ||
|
|
dcc2a5afe0 | ||
|
|
078e952f30 | ||
|
|
2d2fe4983c | ||
|
|
29ddc04f7b | ||
|
|
aac2da70cf | ||
|
|
f5cbe0c4fe | ||
|
|
ab28d0a9b3 | ||
|
|
6aaf4ed9d9 | ||
|
|
1b81a1f4a6 | ||
|
|
e838fe30de | ||
|
|
150329dd4a | ||
|
|
6d9779a497 | ||
|
|
130ece3d2e | ||
|
|
d63a794848 | ||
|
|
ba220abbbf | ||
|
|
3825575f70 | ||
|
|
8d69961130 | ||
|
|
740357d120 | ||
|
|
5638f0f24b | ||
|
|
c8a30e793a | ||
|
|
2264281e4d | ||
|
|
ce38d4ff6b | ||
|
|
59d7bce518 | ||
|
|
3c1e3cd38e | ||
|
|
a2eb0bf9fe | ||
|
|
74773ade62 | ||
|
|
3faf777db1 | ||
|
|
09e880a90d | ||
|
|
5d48ecf86a | ||
|
|
d5785e87e8 | ||
|
|
d4a43bf051 | ||
|
|
00d09aa01e | ||
|
|
9afdc55416 | ||
|
|
76c0432f96 | ||
|
|
4434796aab | ||
|
|
0faa24d5d3 | ||
|
|
2c942c8809 | ||
|
|
c15acc4ce3 | ||
|
|
b056610eaa | ||
|
|
8eb9fb1834 | ||
|
|
7ec518b41c | ||
|
|
dc15914a85 | ||
|
|
6c3b87c9b9 | ||
|
|
2fb31f5944 | ||
|
|
8be42e78de | ||
|
|
6d242ee6c3 | ||
|
|
6c910d2b5f | ||
|
|
3b22f59988 | ||
|
|
afdab0300e | ||
|
|
0caa56e618 | ||
|
|
e5dc843d6a | ||
|
|
26533c47e7 | ||
|
|
3efd1ee325 | ||
|
|
56a1367322 | ||
|
|
544aba53dc | ||
|
|
d68bbbf9a1 | ||
|
|
df3aeed291 | ||
|
|
489737274a | ||
|
|
867ba7b68f | ||
|
|
4c1fabffc3 | ||
|
|
6a52d03329 | ||
|
|
17f00e6fea | ||
|
|
c67bc33c23 | ||
|
|
bb80dcb4e4 | ||
|
|
8fff3e5389 | ||
|
|
233109d23e | ||
|
|
a6aa78e3b6 | ||
|
|
7536322e53 | ||
|
|
b690e3d149 | ||
|
|
aabf270144 | ||
|
|
61a4f15e53 | ||
|
|
de212322e2 | ||
|
|
cda18fb957 | ||
|
|
011ba5056a | ||
|
|
44c871270b | ||
|
|
9f6b0e1018 | ||
|
|
2d9293732b | ||
|
|
d4a131ad31 | ||
|
|
fa2316fb28 | ||
|
|
6e5d1fb613 | ||
|
|
e45f0f0299 | ||
|
|
62125d0284 | ||
|
|
d5ffede5ea | ||
|
|
1679a3f844 | ||
|
|
212bb33142 | ||
|
|
1d8c80c062 | ||
|
|
e8e11257d2 | ||
|
|
1611049623 | ||
|
|
7d195367a8 | ||
|
|
b4236b9a95 | ||
|
|
d2b1404907 | ||
|
|
88a4f25689 | ||
|
|
161dee89ec | ||
|
|
34af33607b | ||
|
|
5bb188a822 | ||
|
|
f11aab6c19 | ||
|
|
1f133dbcd0 | ||
|
|
60bb6f105d | ||
|
|
df4680ee09 | ||
|
|
879576b613 | ||
|
|
6aaab09601 | ||
|
|
5da42575fd | ||
|
|
7a105a1538 | ||
|
|
fe256d6a62 | ||
|
|
5f175141e1 | ||
|
|
983e2df065 | ||
|
|
7408d7bc95 | ||
|
|
1d9820a7c9 | ||
|
|
c536f7d342 | ||
|
|
6d9dfb5deb | ||
|
|
a3d469a101 | ||
|
|
16d5a70c08 | ||
|
|
b7e2d7fb8e | ||
|
|
fb5f7a336d | ||
|
|
78dc5f4bf4 | ||
|
|
45dbf5393f | ||
|
|
97ecb0a5d6 | ||
|
|
6f58e9e7bb | ||
|
|
0de19a09ad | ||
|
|
17a56189dc | ||
|
|
520f9801be | ||
|
|
03a6b0311f | ||
|
|
9fed1cde25 | ||
|
|
5c7b175e90 | ||
|
|
30b29de8ce | ||
|
|
a5f9331023 | ||
|
|
d8b9d8431e | ||
|
|
91a2ce2b3f | ||
|
|
4da1871567 | ||
|
|
e809f77461 | ||
|
|
1a922d41df | ||
|
|
050f8f3c81 | ||
|
|
5fc32c7b85 | ||
|
|
e96d23cc3f | ||
|
|
964fa69fb4 | ||
|
|
c34e2ab3e1 | ||
|
|
f1a33db800 | ||
|
|
820519b4f7 | ||
|
|
2e3b56c52f | ||
|
|
8f137cf49d | ||
|
|
34688852a4 | ||
|
|
de170ebdd2 | ||
|
|
e5ae1db49c | ||
|
|
151f28081a | ||
|
|
63035196af | ||
|
|
213a64b1ff | ||
|
|
e08d803a33 | ||
|
|
df1a939798 | ||
|
|
f259d81249 | ||
|
|
848f0db3d1 | ||
|
|
9e2d47eab5 | ||
|
|
589761bfd9 | ||
|
|
88fa103acb | ||
|
|
9849bc055c | ||
|
|
1cf75a7169 | ||
|
|
e297dff0d4 | ||
|
|
aafd7ed21f | ||
|
|
ab2c31aa8a | ||
|
|
18fde86a20 | ||
|
|
47111819e7 | ||
|
|
ddd3f7c196 | ||
|
|
1738f92ce2 | ||
|
|
074695b50c | ||
|
|
ba28bc94d3 | ||
|
|
da19a07943 | ||
|
|
95ac136720 | ||
|
|
ecced27853 | ||
|
|
e86aa6b541 | ||
|
|
91f74b44a0 | ||
|
|
35d8e28b8c | ||
|
|
26a6af4ab2 | ||
|
|
20785926e2 | ||
|
|
ecc500fc91 | ||
|
|
c22ac1e60a | ||
|
|
55d9aa2a4c | ||
|
|
1d391e68e5 | ||
|
|
0429c44d18 | ||
|
|
2c1bcaafc1 | ||
|
|
35891c74cd | ||
|
|
2ca6e67b37 | ||
|
|
66d0ee8156 | ||
|
|
6e72be54cb | ||
|
|
6138b060d7 | ||
|
|
308d661d7e | ||
|
|
4e106c2355 | ||
|
|
456160fa29 | ||
|
|
07edb998e4 | ||
|
|
b553ac58d3 | ||
|
|
2c26f43035 | ||
|
|
3e52f804a7 | ||
|
|
1b49844012 | ||
|
|
75b7583832 | ||
|
|
75d45e8907 | ||
|
|
d754eb74f7 | ||
|
|
b78bd5d6fd | ||
|
|
5d53344b75 | ||
|
|
7cd58bd534 | ||
|
|
9826bf67c2 | ||
|
|
350fe124d0 | ||
|
|
20aac83e5e | ||
|
|
9d1c822ba1 | ||
|
|
b8d46e2863 | ||
|
|
cd2f2d42a3 | ||
|
|
60252267d5 | ||
|
|
4bfab89292 | ||
|
|
1d3e8aedcd | ||
|
|
b25af641e2 | ||
|
|
75c41644c6 | ||
|
|
3e221f3b6a | ||
|
|
e7c3f8bf47 | ||
|
|
4c1dca73c4 | ||
|
|
0bbb6b91fe | ||
|
|
ee93d9b495 | ||
|
|
535abdc481 | ||
|
|
3684126250 | ||
|
|
bf8ac214a1 | ||
|
|
d3fc34c824 | ||
|
|
8769b5d1b5 | ||
|
|
59bb132dd7 | ||
|
|
8a53fa0aab | ||
|
|
71f42e405d | ||
|
|
64b89dd226 | ||
|
|
27d6b855b8 | ||
|
|
9c7b34d5e6 | ||
|
|
20c4f0dc10 | ||
|
|
7c166d85e1 | ||
|
|
093080894b | ||
|
|
76c0fa2fe2 | ||
|
|
ac3a17b178 | ||
|
|
9a2243da9f | ||
|
|
0f5aa9f8d9 | ||
|
|
673f7a82d1 | ||
|
|
c76b527b93 | ||
|
|
ded4f95537 | ||
|
|
87251878a5 | ||
|
|
3a14f363d9 | ||
|
|
84921f04cd | ||
|
|
8272386733 | ||
|
|
33988ed3fb | ||
|
|
b16475b8bd | ||
|
|
411b8e3cb6 | ||
|
|
848e26eec6 | ||
|
|
916da16523 | ||
|
|
d165c081f7 | ||
|
|
62e86f9507 | ||
|
|
992de7d66e | ||
|
|
46ab7bbcbe | ||
|
|
b04bced37f | ||
|
|
5b306f365e | ||
|
|
ce8950da43 | ||
|
|
0e1c7cd8ed | ||
|
|
fba6dd750d | ||
|
|
e73b6bc39e | ||
|
|
fa3cbbee67 | ||
|
|
029e52eb5f | ||
|
|
13914507e8 | ||
|
|
533f0213e3 | ||
|
|
13335cadc6 | ||
|
|
95d6dac055 | ||
|
|
2001d7f02a | ||
|
|
bae5b70023 | ||
|
|
8341d343d3 | ||
|
|
278a56e580 | ||
|
|
6ab44ccf0c | ||
|
|
b864791fa6 | ||
|
|
918898d6fe | ||
|
|
566e5dea57 | ||
|
|
5d1bfa18b1 | ||
|
|
800540ce7f | ||
|
|
74ee74365e | ||
|
|
75f6235111 | ||
|
|
fe415cbd77 | ||
|
|
dc69c0d3e5 | ||
|
|
40b3f39249 | ||
|
|
a9acc55735 | ||
|
|
9c07612274 | ||
|
|
3e87d88825 | ||
|
|
e280c0c5ca | ||
|
|
6614b56298 | ||
|
|
02c3894fc9 | ||
|
|
68f7dc9512 | ||
|
|
64f750a097 | ||
|
|
48bc18017e | ||
|
|
18d1bc56fd | ||
|
|
035fa3be3f | ||
|
|
f62723c274 | ||
|
|
aca59019c1 | ||
|
|
2186ea9a90 | ||
|
|
928f6e7009 | ||
|
|
1e4d07a52c | ||
|
|
64ed5fca3b | ||
|
|
4c7fc79843 | ||
|
|
153d77359f | ||
|
|
c8a2fb92d2 | ||
|
|
dcc252b371 | ||
|
|
846aadd7c6 | ||
|
|
3c604db234 | ||
|
|
cb3efb1c1d | ||
|
|
1423db35eb | ||
|
|
1fc579e907 | ||
|
|
827c4e31ee | ||
|
|
c2a1ed926e | ||
|
|
4f86c117c3 | ||
|
|
93817ba92f | ||
|
|
18153e0fcc | ||
|
|
3123f6444f | ||
|
|
cb2a7a88fc | ||
|
|
e530111283 | ||
|
|
4e97a3b3d5 | ||
|
|
332c4a1f98 | ||
|
|
8541b95d8b | ||
|
|
e4584e3f04 | ||
|
|
134c43ad9e | ||
|
|
e74b4b35b9 | ||
|
|
16e7194dfe | ||
|
|
168ec9092a | ||
|
|
914b6c757d | ||
|
|
48d10d701e | ||
|
|
6479e94c4f | ||
|
|
fb3a9f1f29 | ||
|
|
e9d7df8862 | ||
|
|
123de56f38 | ||
|
|
8627132d6a | ||
|
|
3ef9c4c626 | ||
|
|
aec03294d6 | ||
|
|
2e6e1f4060 | ||
|
|
07f1103784 | ||
|
|
ffc8f133c9 | ||
|
|
507f2a4c7c | ||
|
|
1c9e9b9367 | ||
|
|
4d81775f8d | ||
|
|
cf042931b6 | ||
|
|
f6a931599a | ||
|
|
1b17049e94 | ||
|
|
81c039d645 | ||
|
|
932b0ccf24 | ||
|
|
e245edc843 | ||
|
|
8494ed8ac3 | ||
|
|
371f14d2e4 | ||
|
|
3e5c7f62d0 | ||
|
|
1109fbfcc3 | ||
|
|
ff88f242fa | ||
|
|
bd3dd69ae1 | ||
|
|
06780c2805 | ||
|
|
e44e227af6 | ||
|
|
4ca06a9218 | ||
|
|
9e29761581 | ||
|
|
110c389d85 | ||
|
|
d856ed89ff | ||
|
|
fa747515e9 | ||
|
|
b15c9d7655 | ||
|
|
15c3ee4af2 | ||
|
|
748248deab | ||
|
|
70671ac672 | ||
|
|
f70f670ed3 | ||
|
|
4b685716d5 | ||
|
|
252c812125 | ||
|
|
69a437a1a8 | ||
|
|
b8b36b6248 | ||
|
|
28e24cb9d6 | ||
|
|
2a0609fdb8 | ||
|
|
b3233cab71 | ||
|
|
bf19f5b9c0 | ||
|
|
08a879bbb1 | ||
|
|
405a3eda60 | ||
|
|
49acfc496b | ||
|
|
a1932fa3dc | ||
|
|
87a8706299 | ||
|
|
92ec46147b | ||
|
|
cd514285d9 | ||
|
|
2bda7566b4 | ||
|
|
43488cb57b | ||
|
|
137fbb638b | ||
|
|
782bb11894 | ||
|
|
76ed8d58fa | ||
|
|
8204139df8 | ||
|
|
7926684930 | ||
|
|
73946a4ede | ||
|
|
aa88115d45 | ||
|
|
496c08b075 | ||
|
|
2388d1782f | ||
|
|
e0e1c59d41 | ||
|
|
f2cb6ce972 | ||
|
|
ed3535e9c9 | ||
|
|
62f1830197 | ||
|
|
2fb62fe8be | ||
|
|
355689ed19 | ||
|
|
75614fb13c | ||
|
|
5c4a864680 | ||
|
|
eaeff891d6 | ||
|
|
f0ab40d748 | ||
|
|
3243cbf039 | ||
|
|
eb171ecb21 | ||
|
|
e497af4c26 | ||
|
|
43b8941f7a | ||
|
|
0b16839d7f | ||
|
|
164ba46259 | ||
|
|
b174f7a023 | ||
|
|
c9ec9f14de | ||
|
|
597c071c3d | ||
|
|
f860f57363 | ||
|
|
91d05434ca | ||
|
|
5b0aba99bb | ||
|
|
87c7d1a5f4 | ||
|
|
d841d69bd4 | ||
|
|
512bf1d013 | ||
|
|
02bf5ada89 | ||
|
|
adbd58a949 | ||
|
|
a0959d2730 | ||
|
|
f455722bed | ||
|
|
735d23c9eb | ||
|
|
0fd6a23c78 | ||
|
|
fd73d8d67e | ||
|
|
347366e8d7 | ||
|
|
eb8d4abcbe | ||
|
|
86acccebb0 | ||
|
|
8f184f76fa | ||
|
|
1daabfa3e0 | ||
|
|
90b49106f0 | ||
|
|
1a5638426c | ||
|
|
8d4da009af | ||
|
|
89571d57bd | ||
|
|
d3b578fe8f | ||
|
|
d29d910ac6 | ||
|
|
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 | ||
|
|
e7b41f9a4c | ||
|
|
dd0aed4614 | ||
|
|
b9b4f2bb7f | ||
|
|
3533d2a2cc | ||
|
|
26d9ef5398 | ||
|
|
06c210f5c8 | ||
|
|
a545c42047 | ||
|
|
da4b4de292 | ||
|
|
fd936e5bf3 | ||
|
|
a0f840bcf8 | ||
|
|
33d2a77e37 | ||
|
|
dc11340faf | ||
|
|
06d921d855 | ||
|
|
91b602341b | ||
|
|
ad853ca342 | ||
|
|
14fa3481b0 | ||
|
|
2b6fee0455 | ||
|
|
a48e6f82d1 | ||
|
|
1020904fe0 | ||
|
|
6aaced0c04 | ||
|
|
3646c0d0a3 | ||
|
|
44c8574f1b | ||
|
|
ea1ff65db7 | ||
|
|
85b7147927 | ||
|
|
6b54c342aa | ||
|
|
60720b04db | ||
|
|
323a593159 | ||
|
|
baef94f14a | ||
|
|
59b3cfee66 | ||
|
|
cbc85ca98f | ||
|
|
425c8cd1d3 | ||
|
|
1d7949ded6 | ||
|
|
2507170816 | ||
|
|
2c83425b42 | ||
|
|
80e00a80d5 | ||
|
|
1da281de8a | ||
|
|
98baab4d03 | ||
|
|
a3d5479878 | ||
|
|
a49dc04f5d | ||
|
|
d1c0c9739d | ||
|
|
7415b07586 | ||
|
|
441069aa76 | ||
|
|
8c5bf55b51 | ||
|
|
b6d6955b39 | ||
|
|
0d68b1a73e | ||
|
|
15b7c241ff | ||
|
|
de9c62617b | ||
|
|
a0e05115a3 | ||
|
|
023663b268 | ||
|
|
aaf58272f1 | ||
|
|
5ebaf5663d | ||
|
|
7dc3e6a08b | ||
|
|
5a5f817e59 | ||
|
|
b650320a34 | ||
|
|
424fd8e4d3 | ||
|
|
cfbf80fdfe | ||
|
|
9b8ced2803 | ||
|
|
630a1d42b8 | ||
|
|
b69ff6ca8a | ||
|
|
1a23b6178b | ||
|
|
de536d7305 | ||
|
|
6dcd33bbc5 | ||
|
|
c6df78eb81 | ||
|
|
d1babe27ec | ||
|
|
7596f62ca5 | ||
|
|
139e57f1eb | ||
|
|
e87d85b088 | ||
|
|
91b79b703c | ||
|
|
bdefa4a967 | ||
|
|
3883c509b9 | ||
|
|
b82efb6e3c | ||
|
|
a50e109043 | ||
|
|
8b5db12e1d | ||
|
|
f1f8163bb7 | ||
|
|
c0fac90b52 | ||
|
|
15717ddca0 | ||
|
|
a7ce9aaca5 | ||
|
|
d8df8e1033 | ||
|
|
440a35e491 | ||
|
|
dbbc6ed0bb | ||
|
|
86fbb383fd | ||
|
|
18f34b4f83 | ||
|
|
1c07a74bef | ||
|
|
2df93c2ceb | ||
|
|
6ca40afac0 | ||
|
|
36a8f044ae | ||
|
|
caed86d846 | ||
|
|
276e5453f1 | ||
|
|
459e36c027 | ||
|
|
0f81986684 | ||
|
|
bc54e536af | ||
|
|
acb57b3e9c | ||
|
|
725f8571bb | ||
|
|
b7c7c0e862 | ||
|
|
de0e30de57 | ||
|
|
3f671b918a | ||
|
|
b8b942cdae | ||
|
|
9492363b22 | ||
|
|
3ee144459f | ||
|
|
c0c80c0fdf | ||
|
|
0146a077e8 | ||
|
|
7c80b61666 | ||
|
|
a0fcf515cd | ||
|
|
1719ad81a4 | ||
|
|
51a9a7b75d | ||
|
|
d128f3e14e | ||
|
|
4498b89ac4 | ||
|
|
e576a58ead | ||
|
|
eb4375258e | ||
|
|
0cbc2001e2 | ||
|
|
6bf5dbabee | ||
|
|
6a89646e66 | ||
|
|
e91b0500c5 | ||
|
|
2a17361a90 | ||
|
|
1eca3a8603 | ||
|
|
86f37863a7 | ||
|
|
f3234a6b5e | ||
|
|
73a8c302e9 | ||
|
|
989f2d3001 | ||
|
|
2badcfa546 | ||
|
|
643cd87706 | ||
|
|
98c85441f8 | ||
|
|
1345f996da | ||
|
|
ff48f08241 | ||
|
|
b5f438aa0c | ||
|
|
384e14b32d | ||
|
|
a2266adb3f | ||
|
|
016e743653 | ||
|
|
00adf3631a | ||
|
|
09aef18999 | ||
|
|
1d86aac338 | ||
|
|
80173634a0 | ||
|
|
c9598b674c | ||
|
|
2a588d1e9a | ||
|
|
5a6c06c8a3 | ||
|
|
b2ef4e9619 | ||
|
|
9e9d6e45b4 | ||
|
|
6752457ad8 | ||
|
|
ddcb5cd4d3 | ||
|
|
a54b2db81b | ||
|
|
6740124364 | ||
|
|
157731e4f8 | ||
|
|
2dd1496ef4 | ||
|
|
d1e4e72693 | ||
|
|
77e8143290 | ||
|
|
7f791d4919 | ||
|
|
d7e0468776 | ||
|
|
f6c611bbba | ||
|
|
0990ac4fc1 | ||
|
|
e91f8f693b | ||
|
|
2a7dbda133 | ||
|
|
793e542312 | ||
|
|
240269eb25 | ||
|
|
c744dc8cc3 | ||
|
|
d596bdb454 | ||
|
|
bec54b4283 | ||
|
|
061b88f5b5 | ||
|
|
8704eff632 | ||
|
|
fb16f25b07 | ||
|
|
e8057a5c8a | ||
|
|
3c5edb6171 | ||
|
|
e36a191240 | ||
|
|
ecdfd65f50 | ||
|
|
4294081abb | ||
|
|
5218543c58 | ||
|
|
d8332a27e5 | ||
|
|
673658dfd2 | ||
|
|
6528d3d7da | ||
|
|
16af479b83 | ||
|
|
13187de97d | ||
|
|
32850f6770 | ||
|
|
4a7f4bde4a | ||
|
|
c518f373df | ||
|
|
0010119440 | ||
|
|
f4636fdca2 | ||
|
|
91065a6168 | ||
|
|
efa8d5c575 | ||
|
|
4108d7827a | ||
|
|
04998d0215 | ||
|
|
d0efa5d3fe | ||
|
|
c87e72e08e | ||
|
|
efb82847cb | ||
|
|
f37e267a5e | ||
|
|
69928219a3 | ||
|
|
5ccd40f530 | ||
|
|
8798340d48 | ||
|
|
e8d2959350 | ||
|
|
fdf8845a2f | ||
|
|
4073a7abc3 | ||
|
|
ffd9a34cf5 | ||
|
|
07226c6d21 | ||
|
|
b1bc7c1fc2 | ||
|
|
1b33f0cea9 | ||
|
|
8ece3b00f5 | ||
|
|
c9c58b65a6 | ||
|
|
66becbc4cc | ||
|
|
5b8612c919 | ||
|
|
430c22e06e | ||
|
|
76b62eda3a | ||
|
|
bc983162f3 | ||
|
|
4922598aee | ||
|
|
b2f8bb9990 | ||
|
|
9ee92fb9e9 | ||
|
|
f1d838de6b | ||
|
|
ec92a4cd34 | ||
|
|
b3b9788d37 | ||
|
|
67739e8e39 | ||
|
|
be3ed7d380 | ||
|
|
9b4d58cfe8 | ||
|
|
fb6a8d999c | ||
|
|
b2f6a06a1f | ||
|
|
f7da32702f | ||
|
|
219d2246fa | ||
|
|
979b5eb89c | ||
|
|
a58811b1bf | ||
|
|
be0e18d4b0 | ||
|
|
981bf1d56f | ||
|
|
fea6f0ce81 | ||
|
|
5859ac7a58 | ||
|
|
d2c2503cfa | ||
|
|
566833da6e | ||
|
|
d174602cc0 | ||
|
|
2a4caa856e | ||
|
|
46bc04f69f | ||
|
|
157962e42a | ||
|
|
16db28060c | ||
|
|
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 | ||
|
|
712424c339 | ||
|
|
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 | ||
|
|
15c56dfcb8 | ||
|
|
b98ad47618 | ||
|
|
4778c5f5e8 | ||
|
|
d041671dc5 | ||
|
|
bb8c0d264e | ||
|
|
c7da8c5fd3 | ||
|
|
5cab65d197 | ||
|
|
30789ff6e2 | ||
|
|
e6ece10716 | ||
|
|
ea7a255006 | ||
|
|
98df1f5312 | ||
|
|
b5bf627fb1 | ||
|
|
6104150b77 | ||
|
|
a13bae2f39 | ||
|
|
fd80e98207 | ||
|
|
f43b95f001 | ||
|
|
38802d3522 | ||
|
|
9f7813622d | ||
|
|
75d67207aa | ||
|
|
e596a8f731 | ||
|
|
5b0cc73792 | ||
|
|
2163d4465f | ||
|
|
8becf45714 | ||
|
|
2bf08787d8 | ||
|
|
853ead26ca | ||
|
|
0ccb6cb873 | ||
|
|
b8f7e4211c | ||
|
|
e46ff3de8b | ||
|
|
b581d0c44f | ||
|
|
0b613812f7 | ||
|
|
a02e08a879 | ||
|
|
4d066a762f | ||
|
|
109d7d87bd | ||
|
|
3df740702c | ||
|
|
8a30a65818 | ||
|
|
01703aff43 | ||
|
|
06bb6f7bff | ||
|
|
9d62931af9 | ||
|
|
e33738a876 | ||
|
|
f887f5dca3 | ||
|
|
257c16690a | ||
|
|
7114e88992 | ||
|
|
de7e869ca9 | ||
|
|
eaee9c9522 | ||
|
|
bee11a6d41 | ||
|
|
647e44147f | ||
|
|
4a5d46915d | ||
|
|
8ad19585cb | ||
|
|
951a33fae9 | ||
|
|
bcf174cd1e | ||
|
|
1e82909f58 | ||
|
|
33e83b8414 | ||
|
|
592c56cb20 | ||
|
|
710528c01a | ||
|
|
03cadc2604 | ||
|
|
dd73bb95a4 | ||
|
|
40e0a55378 | ||
|
|
269884d9f3 | ||
|
|
fcd548c313 | ||
|
|
140a8b6804 | ||
|
|
b5378c1296 | ||
|
|
e53d8fd4fa | ||
|
|
0dbde32ed4 | ||
|
|
1445d6ea8c | ||
|
|
5385431051 | ||
|
|
f14f4498fb | ||
|
|
d506fdb68c | ||
|
|
9c10186158 | ||
|
|
3eed51dbac | ||
|
|
1c1855f0c3 | ||
|
|
e0a277fa45 | ||
|
|
3d6c7171d2 | ||
|
|
fc2786f5e8 | ||
|
|
174dbb5e74 | ||
|
|
0fee90e4df | ||
|
|
0cced44491 | ||
|
|
f21f758591 | ||
|
|
68517c15f2 | ||
|
|
11ee142e4b | ||
|
|
51e9527d53 | ||
|
|
1e1d047e07 | ||
|
|
62f1e39e6e | ||
|
|
05756da495 | ||
|
|
fa35b2a66f | ||
|
|
268cd131dc | ||
|
|
26997ad5c3 | ||
|
|
ce1786f128 | ||
|
|
d2094e2b68 | ||
|
|
075b2df738 | ||
|
|
ec3c31a106 | ||
|
|
888057f64a | ||
|
|
3c6c4d9601 | ||
|
|
5e8bcf8faf | ||
|
|
0d6f2f93bf | ||
|
|
937b00cfcc | ||
|
|
0d4432720c | ||
|
|
0ec49643ee | ||
|
|
0d80ea4f4c | ||
|
|
d2b26124e4 | ||
|
|
343116ea24 | ||
|
|
10dc699b21 | ||
|
|
e2183c2214 | ||
|
|
4994064e6e | ||
|
|
015c5f07bc | ||
|
|
a40b9f4054 | ||
|
|
a0b6a3bed6 | ||
|
|
ee8d65977d | ||
|
|
b4ea11e55e | ||
|
|
b8d2ef1eb5 | ||
|
|
0efeffeaa3 | ||
|
|
9de5950f4d | ||
|
|
26488b793a | ||
|
|
7a86d272bb | ||
|
|
5a6c2dfcd5 | ||
|
|
4d780904d1 | ||
|
|
0a6fa65075 | ||
|
|
6440220640 | ||
|
|
4350c9a72b | ||
|
|
77feae0ab9 | ||
|
|
1261696ba2 | ||
|
|
6b35a0a527 | ||
|
|
fd33ff81c9 | ||
|
|
7e891ecb79 | ||
|
|
178b1e8bb0 | ||
|
|
12840f2428 | ||
|
|
9d50f03cb1 | ||
|
|
8c1688657a | ||
|
|
833cb99f41 | ||
|
|
bd5d84abcd | ||
|
|
d451ba9b6e | ||
|
|
14bd02a569 | ||
|
|
4beace1bb0 | ||
|
|
6996dfcd3b | ||
|
|
42c46d7d5c | ||
|
|
9b31ce83c5 | ||
|
|
cb5250527b | ||
|
|
0b160a6741 | ||
|
|
dff34a8ae2 | ||
|
|
8f780ad89e | ||
|
|
4624ef393d | ||
|
|
2ce8a890e2 | ||
|
|
90e0e9000e | ||
|
|
a6bb1c156d | ||
|
|
31db8161b5 | ||
|
|
c0d1448080 | ||
|
|
4e4f4e60b6 | ||
|
|
dcc83271af | ||
|
|
a38458c9be | ||
|
|
7934f65ae8 | ||
|
|
f0b73fd696 | ||
|
|
aea0cec061 | ||
|
|
7ac56b1a0c | ||
|
|
f5ed0b700f | ||
|
|
1ff3b83766 | ||
|
|
40eca1727e | ||
|
|
9505e68ef7 | ||
|
|
5847806a16 | ||
|
|
e427ea44aa | ||
|
|
8df8bf33a4 | ||
|
|
29d2b942e8 | ||
|
|
df5684a9f8 | ||
|
|
992cdb992a | ||
|
|
db0dc71319 | ||
|
|
2c871d1339 | ||
|
|
9673922ca1 | ||
|
|
d311870b61 | ||
|
|
8dd1ff593a | ||
|
|
0f64a769c2 | ||
|
|
a8d150db5c | ||
|
|
d7e6367ff3 | ||
|
|
7b84d8c3d5 | ||
|
|
b3f724c799 | ||
|
|
a7be6504a2 | ||
|
|
e025df0824 | ||
|
|
c3392d5386 | ||
|
|
1da5357df6 | ||
|
|
2c09e6a7c0 | ||
|
|
2a0740e135 | ||
|
|
ac65357c8a | ||
|
|
92e1847c59 | ||
|
|
0500994def | ||
|
|
07c255f7f8 | ||
|
|
da911bfeb8 | ||
|
|
578d673a4e | ||
|
|
198b3c9f1b | ||
|
|
f5c567eb90 | ||
|
|
8ca09f6384 | ||
|
|
c8e58a1e5b | ||
|
|
386dfe42d0 | ||
|
|
7445f43b1b | ||
|
|
d477874535 | ||
|
|
5b77e78662 | ||
|
|
4b0b8d4de2 | ||
|
|
da79386cc3 | ||
|
|
b7de47b6fb | ||
|
|
3434907f52 | ||
|
|
099adb3853 | ||
|
|
dd9b1c047c | ||
|
|
a4ba6d1444 | ||
|
|
6084bb15cf | ||
|
|
42b568952e | ||
|
|
ef28459b61 | ||
|
|
d3bac307bb | ||
|
|
7e488b0fa3 | ||
|
|
7d7a6191ce | ||
|
|
5c644b31ca | ||
|
|
7b4398dfee | ||
|
|
663418e943 | ||
|
|
969bec248a | ||
|
|
8f487d7d4e | ||
|
|
89ebce79b2 | ||
|
|
1ff8c908b8 | ||
|
|
34ce510fbd | ||
|
|
e966ef96e5 | ||
|
|
b05b38b269 | ||
|
|
39f29399e7 | ||
|
|
8e1f1ff2e6 | ||
|
|
680d6c20ca | ||
|
|
c886e7949e | ||
|
|
8cd4cc7d0d | ||
|
|
e0b972f6d6 | ||
|
|
25daa9f2da | ||
|
|
d0fb5c3bd5 | ||
|
|
608ab8f4ad | ||
|
|
520b12e56b | ||
|
|
e95643f198 | ||
|
|
3b1712345b | ||
|
|
5c8ffe961e | ||
|
|
7983e82b60 | ||
|
|
6effe47bcc | ||
|
|
77d35b61a9 | ||
|
|
285a97aaf8 | ||
|
|
205080a210 | ||
|
|
ad29f2477e | ||
|
|
bc998988c2 | ||
|
|
1072d1306b | ||
|
|
80b470cfd3 | ||
|
|
b8eda40937 | ||
|
|
3df2b4b7f8 | ||
|
|
6141b60294 | ||
|
|
e1cfb0cab6 | ||
|
|
9b9782ce94 | ||
|
|
5d9eb25e38 | ||
|
|
f4a518ce6b | ||
|
|
2719ae5df2 | ||
|
|
3656e6ef54 | ||
|
|
a545d7d8b1 | ||
|
|
68ee2bdcdc | ||
|
|
da654fdff5 | ||
|
|
3127f7a31b | ||
|
|
f561de200d | ||
|
|
d7f9d5a66f | ||
|
|
d85a063db8 | ||
|
|
d6bf935ceb | ||
|
|
0d6ff822e7 | ||
|
|
1c0cc8e91c | ||
|
|
c4fb7b7928 | ||
|
|
43a791db65 | ||
|
|
217311211a | ||
|
|
ca55890ad2 | ||
|
|
d6ecf5b8a9 | ||
|
|
e52edde11f | ||
|
|
2e514735ec | ||
|
|
3d32c30d2d | ||
|
|
05235f8385 | ||
|
|
cd28a75c86 | ||
|
|
34075738ea | ||
|
|
fb38573b7e | ||
|
|
8a2f45ec23 | ||
|
|
fee2eb9251 | ||
|
|
24035c4ae8 | ||
|
|
aa8215df34 | ||
|
|
eb78e3d640 | ||
|
|
f8201cd2bc | ||
|
|
f37b3ecd26 | ||
|
|
88c0b8a8f0 | ||
|
|
e6dba59ae6 | ||
|
|
a7bc6b4f36 | ||
|
|
cacc5ac803 | ||
|
|
46dc0f144b | ||
|
|
3cc5275592 | ||
|
|
a3955a1ba8 | ||
|
|
89dfaf1d5d | ||
|
|
e8bbc117e1 | ||
|
|
fc6246c5cb | ||
|
|
ce8a0cab2a | ||
|
|
b99f45874f | ||
|
|
b36b6c78a2 | ||
|
|
5232dc6485 | ||
|
|
b1d9fc6c9a | ||
|
|
0dfa378e38 | ||
|
|
80ded84f7a | ||
|
|
8394535725 | ||
|
|
adf780d25b | ||
|
|
749ae3deb3 | ||
|
|
3da0c07bcd | ||
|
|
2196b53075 | ||
|
|
a8340f37bb | ||
|
|
7b1710ee63 | ||
|
|
38b7d9724e | ||
|
|
2b1ed49e9a | ||
|
|
017cf9e464 | ||
|
|
781f0c843e | ||
|
|
e2bf474332 | ||
|
|
7e2f1c9a8b | ||
|
|
8e798dde48 | ||
|
|
c05ae6e94c | ||
|
|
ff28ea8fa8 | ||
|
|
7914e89212 | ||
|
|
558ff90e27 | ||
|
|
ee69653a83 | ||
|
|
2d7760e67c | ||
|
|
95339a8338 | ||
|
|
39b1435725 | ||
|
|
b1d3e258bd | ||
|
|
c915926e0f | ||
|
|
25203934e6 | ||
|
|
6ff7fa74e2 | ||
|
|
91305262f1 | ||
|
|
6d16b68f11 | ||
|
|
f22e4f1cc7 | ||
|
|
4b1b2878ea | ||
|
|
2851d12357 | ||
|
|
73968e4277 | ||
|
|
7a6ecd86c6 | ||
|
|
b11d5514b9 | ||
|
|
1ff2a08d19 | ||
|
|
d1efd62e7b | ||
|
|
366c95cd3c | ||
|
|
7e03f3958e | ||
|
|
e069184721 | ||
|
|
5182441cb3 | ||
|
|
0de55a8ff5 | ||
|
|
0900d7c764 | ||
|
|
8540e09ba7 | ||
|
|
6e301601f9 | ||
|
|
1bf0eab2d9 | ||
|
|
d560f656f4 | ||
|
|
0bc256aa23 | ||
|
|
ebc073a52e | ||
|
|
23503dc439 | ||
|
|
1f4985c7dd | ||
|
|
ed88d9e10d | ||
|
|
906196bac3 | ||
|
|
cb9751be04 | ||
|
|
09e03d579b | ||
|
|
9fcca2698e | ||
|
|
bba8cd9b58 | ||
|
|
c8bb30289a | ||
|
|
69f56c1eb7 | ||
|
|
adc8e23356 | ||
|
|
88005c6603 | ||
|
|
33ee4c36b4 | ||
|
|
1a142b7fe6 | ||
|
|
90373806c0 | ||
|
|
a47634bf49 | ||
|
|
e03e58323b | ||
|
|
ab1e31c0e7 | ||
|
|
aa5505d693 | ||
|
|
74f8f687cf | ||
|
|
d54500bad5 | ||
|
|
4966b4d58d | ||
|
|
b75a4667c2 | ||
|
|
14579a9320 | ||
|
|
1d92eff974 | ||
|
|
91274267e5 | ||
|
|
c49f0ede16 | ||
|
|
42a0f452b1 | ||
|
|
c24ab9831a | ||
|
|
506a68ee6a | ||
|
|
1291f792ab | ||
|
|
51cfb1903d | ||
|
|
1b1c15694a | ||
|
|
251f1941a9 | ||
|
|
625617bb20 | ||
|
|
f80f161886 | ||
|
|
4b4889d5f2 | ||
|
|
fee34ba257 | ||
|
|
c29ab25dd2 | ||
|
|
e0308a11c9 | ||
|
|
a738998c2c | ||
|
|
6be22c474d | ||
|
|
da19743ba5 |
@@ -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
|
||||||
59
.github/ISSUE_TEMPLATE/1-app-bug.yml
vendored
Normal file
@@ -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
|
||||||
52
.github/ISSUE_TEMPLATE/2-web-bug.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: 🌐 Website bug (modrinth.com)
|
||||||
|
description: Report an issue on the Modrinth website.
|
||||||
|
labels: [bug, frontend]
|
||||||
|
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
|
||||||
@@ -1,10 +1,28 @@
|
|||||||
name: Enhancement
|
name: 💡 Feature Request
|
||||||
description: Suggest an enhancement for an existing Modrinth feature
|
description: Suggest an idea
|
||||||
labels: [enhancement]
|
labels: [enhancement]
|
||||||
|
|
||||||
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 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
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Is your suggested enhancement related to a problem? Please describe.
|
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 [...]
|
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
@@ -25,4 +43,4 @@ body:
|
|||||||
label: Additional context
|
label: Additional context
|
||||||
description: Add any other context or screenshots about the suggested enhancement here.
|
description: Add any other context or screenshots about the suggested enhancement here.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
20
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -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
|
|
||||||
BIN
.github/assets/app_cover.png
vendored
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
.github/assets/monorepo_cover.png
vendored
Normal file
|
After Width: | Height: | Size: 417 KiB |
BIN
.github/assets/web_cover.png
vendored
Normal file
|
After Width: | Height: | Size: 41 KiB |
43
.github/workflows/daedalus-docker.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
name: daedalus-docker-build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
paths:
|
||||||
|
- .github/workflows/daedalus-docker.yml
|
||||||
|
- 'apps/daedalus_client/**'
|
||||||
|
pull_request:
|
||||||
|
types: [ opened, synchronize ]
|
||||||
|
paths:
|
||||||
|
- .github/workflows/daedalus-docker.yml
|
||||||
|
- 'apps/daedalus_client/**'
|
||||||
|
merge_group:
|
||||||
|
types: [ checks_requested ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Fetch docker metadata
|
||||||
|
id: docker_meta
|
||||||
|
uses: docker/metadata-action@v3
|
||||||
|
with:
|
||||||
|
images: ghcr.io/modrinth/daedalus
|
||||||
|
-
|
||||||
|
name: Login to GitHub Images
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
id: docker_build
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
file: ./apps/daedalus_client/Dockerfile
|
||||||
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||||
52
.github/workflows/daedalus-run.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: Run Meta
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '*/5 * * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run-docker:
|
||||||
|
if: github.repository_owner == 'modrinth'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Log in to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
|
||||||
|
- name: Pull Docker image from GHCR
|
||||||
|
run: docker pull ghcr.io/modrinth/daedalus:main
|
||||||
|
|
||||||
|
- name: Run Docker container
|
||||||
|
env:
|
||||||
|
BASE_URL: ${{ secrets.BASE_URL }}
|
||||||
|
S3_ACCESS_TOKEN: ${{ secrets.S3_ACCESS_TOKEN }}
|
||||||
|
S3_SECRET: ${{ secrets.S3_SECRET }}
|
||||||
|
S3_URL: ${{ secrets.S3_URL }}
|
||||||
|
S3_REGION: ${{ secrets.S3_REGION }}
|
||||||
|
S3_BUCKET_NAME: ${{ secrets.S3_BUCKET_NAME }}
|
||||||
|
CLOUDFLARE_INTEGRATION: ${{ secrets.CLOUDFLARE_INTEGRATION }}
|
||||||
|
CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }}
|
||||||
|
CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }}
|
||||||
|
run: |
|
||||||
|
docker run \
|
||||||
|
--name daedalus \
|
||||||
|
-e RUST_LOG=warn,daedalus_client=trace \
|
||||||
|
-e BASE_URL=$BASE_URL \
|
||||||
|
-e S3_ACCESS_TOKEN=$S3_ACCESS_TOKEN \
|
||||||
|
-e S3_SECRET=$S3_SECRET \
|
||||||
|
-e S3_URL=$S3_URL \
|
||||||
|
-e S3_REGION=$S3_REGION \
|
||||||
|
-e S3_BUCKET_NAME=$S3_BUCKET_NAME \
|
||||||
|
-e CLOUDFLARE_INTEGRATION=$CLOUDFLARE_INTEGRATION \
|
||||||
|
-e CLOUDFLARE_TOKEN=$CLOUDFLARE_TOKEN \
|
||||||
|
-e CLOUDFLARE_ZONE_ID=$CLOUDFLARE_ZONE_ID \
|
||||||
|
ghcr.io/modrinth/daedalus:main
|
||||||
30
.github/workflows/frontend-pages.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
name: Clear pages cache
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- prod
|
||||||
|
|
||||||
|
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'
|
||||||
|
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
|
||||||
42
.github/workflows/gui-build.yml
vendored
@@ -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
|
|
||||||
46
.github/workflows/labrinth-docker.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
name: docker-build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
paths:
|
||||||
|
- .github/workflows/labrinth-docker.yml
|
||||||
|
- 'apps/labrinth/**'
|
||||||
|
pull_request:
|
||||||
|
types: [ opened, synchronize ]
|
||||||
|
paths:
|
||||||
|
- .github/workflows/labrinth-docker.yml
|
||||||
|
- 'apps/labrinth/**'
|
||||||
|
merge_group:
|
||||||
|
types: [ checks_requested ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./apps/labrinth
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Fetch docker metadata
|
||||||
|
id: docker_meta
|
||||||
|
uses: docker/metadata-action@v3
|
||||||
|
with:
|
||||||
|
images: ghcr.io/modrinth/labrinth
|
||||||
|
-
|
||||||
|
name: Login to GitHub Images
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
id: docker_build
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: ./apps/labrinth
|
||||||
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||||
109
.github/workflows/tauri-build.yml
vendored
@@ -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, x86_64-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') }}"
|
|
||||||
155
.github/workflows/theseus-release.yml
vendored
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
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/**
|
||||||
|
!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/*.msi
|
||||||
|
!target/release/bundle/msi/*.msi.zip
|
||||||
|
!target/release/bundle/msi/*.msi.zip.sig
|
||||||
|
|
||||||
|
!target/release/bundle/nsis/*.exe
|
||||||
|
!target/release/bundle/nsis/*.nsis.zip
|
||||||
|
!target/release/bundle/nsis/*.nsis.zip.sig
|
||||||
|
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 build-essential curl wget file libxdo-dev libssl-dev pkg-config libayatana-appindicator3-dev librsvg2-dev
|
||||||
|
|
||||||
|
- 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/*.msi
|
||||||
|
target/release/bundle/msi/*.msi.zip
|
||||||
|
target/release/bundle/msi/*.msi.zip.sig
|
||||||
|
|
||||||
|
target/release/bundle/nsis/*.exe
|
||||||
|
target/release/bundle/nsis/*.nsis.zip
|
||||||
|
target/release/bundle/nsis/*.nsis.zip.sig
|
||||||
80
.github/workflows/turbo-ci.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
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
|
||||||
|
env:
|
||||||
|
SQLX_OFFLINE: true
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: pnpm lint
|
||||||
|
env:
|
||||||
|
SQLX_OFFLINE: true
|
||||||
|
|
||||||
|
- name: Start docker compose
|
||||||
|
run: docker compose up -d
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: pnpm test
|
||||||
|
env:
|
||||||
|
SQLX_OFFLINE: true
|
||||||
|
DATABASE_URL: postgresql://labrinth:labrinth@localhost/postgres
|
||||||
158
.gitignore
vendored
@@ -1,115 +1,63 @@
|
|||||||
/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/*
|
||||||
|
|
||||||
|
# soley because i need the PORT to be 3002 due to WSL stuff
|
||||||
|
.env
|
||||||
|
apps/frontend/.env
|
||||||
|
|
||||||
|
.astro
|
||||||
|
|||||||
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
15
.idea/daedalus.iml
generated
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/daedalus_client_new/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/apps/daedalus_client/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/packages/daedalus/src" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
7
.idea/discord.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DiscordProjectSettings">
|
||||||
|
<option name="show" value="PROJECT_FILES" />
|
||||||
|
<option name="description" value="" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
26
.idea/libraries/KotlinJavaRuntime.xml
generated
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="KotlinJavaRuntime" type="repository">
|
||||||
|
<properties maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0" />
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.8.0/kotlin-stdlib-jdk8-1.8.0.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.0/kotlin-stdlib-1.8.0.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.0/kotlin-stdlib-common-1.8.0.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.8.0/kotlin-stdlib-jdk7-1.8.0.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC>
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.8.0/kotlin-stdlib-jdk8-1.8.0-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.0/kotlin-stdlib-1.8.0-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.0/kotlin-stdlib-common-1.8.0-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.8.0/kotlin-stdlib-jdk7-1.8.0-javadoc.jar!/" />
|
||||||
|
</JAVADOC>
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.8.0/kotlin-stdlib-jdk8-1.8.0-sources.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.0/kotlin-stdlib-1.8.0-sources.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.0/kotlin-stdlib-common-1.8.0-sources.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.8.0/kotlin-stdlib-jdk7-1.8.0-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
|
</component>
|
||||||
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/daedalus.iml" filepath="$PROJECT_DIR$/.idea/daedalus.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
2
.npmrc
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
strict-peer-dependencies=false
|
||||||
|
auto-install-peers=true
|
||||||
3
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"recommendations": ["esbenp.prettier-vscode", "Vue.volar", "rust-lang.rust-analyzer"]
|
||||||
|
}
|
||||||
13
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"prettier.endOfLine": "lf",
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"eslint.validate": [
|
||||||
|
"javascript",
|
||||||
|
"javascriptreact",
|
||||||
|
"typescript",
|
||||||
|
"typescriptreact"
|
||||||
|
],
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": "explicit"
|
||||||
|
}
|
||||||
|
}
|
||||||
14
COPYING.md
@@ -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.
|
||||||
|
|||||||
7621
Cargo.lock
generated
30
Cargo.toml
@@ -1,24 +1,14 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = '2'
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
"theseus",
|
'./packages/app-lib',
|
||||||
"theseus_playground",
|
'./apps/app-playground',
|
||||||
"theseus_gui/src-tauri",
|
'./apps/app',
|
||||||
"theseus_macros"
|
'./apps/labrinth',
|
||||||
|
'./apps/daedalus_client',
|
||||||
|
'./packages/daedalus',
|
||||||
]
|
]
|
||||||
|
|
||||||
[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
|
||||||
@@ -26,3 +16,9 @@ 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
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
wry = { git = "https://github.com/modrinth/wry", rev = "27fb16b" }
|
||||||
|
|||||||
60
README.md
@@ -1,45 +1,39 @@
|
|||||||
<img src="https://github.com/modrinth/theseus/assets/6166773/51d1ca87-05c0-445a-bd18-ddd1117f7f12" alt="modrinth app: theseus (desktop app)">
|
# 
|
||||||
|
|
||||||
# Modrinth App
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
<img src="https://cdn-raw.modrinth.com/app-landing/app-screenshot.webp" alt="Screenshot of the Modrinth App's home page" align="right" width="50%">
|
## Modrinth Monorepo
|
||||||
|
|
||||||
The Modrinth App, codenamed theseus, is a modern launcher for Minecraft: Java Edition with a clean look, easy-to-use interface, and deep integration into Modrinth services.
|
Welcome to the Modrinth Monorepo, the primary codebase for the Modrinth web interface and app. It contains  lines of code and has  contributors!
|
||||||
|
|
||||||
### Features
|
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).
|
||||||
- One-click installation of modpacks
|
|
||||||
- Automatic management of Java versions
|
|
||||||
- Windows, Mac, and Linux[^1] support
|
|
||||||
- Import your instances from CurseForge, Prism[^2], ATLauncher, MultiMC[^2], or GDLauncher
|
|
||||||
- Supports offline play once you've authenticated with your Minecraft account at least once
|
|
||||||
- Fully open source under GPLv3[^3]!
|
|
||||||
|
|
||||||
[^1]: While Linux is supported, due to the wide range of distributions out there, your mileage may vary with how well the Modrinth App works on your system. We officially distribute `.deb` and `.AppImage` packages, but third party packages have been created for a number of other package platforms. Additionally, some have reported lag issues running on Linux, we believe this to be due to an upstream Tauri issue, which we hope improves with further development.
|
|
||||||
|
|
||||||
[^2]: Certain features of the OneSix format used by Prism and MultiMC are not yet supported, so some instances may not import correctly, primarily on older Minecraft versions or unsupported mod loaders.
|
|
||||||
|
|
||||||
[^3]: Modrinth's logos, branding, and other trademarks are not free for use, see the [licensing section](#license) for more information.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
You're welcome to help contribute to the Modrinth App if you'd like! Please review our [contribution guide](https://support.modrinth.com/en/articles/8802215-contributing-to-modrinth) before attempting to contribute or make a pull request though.
|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
To get started, install [pnpm](https://pnpm.io/), [Rust](https://www.rust-lang.org/tools/install), and the [Tauri prerequisites](https://tauri.app/v1/guides/getting-started/prerequisites/#installing) for your system. Then, run the following commands:
|
|
||||||
|
|
||||||
```
|
This repository contains two primary packages. For detailed development information, please refer to their respective READMEs:
|
||||||
cd theseus_gui
|
|
||||||
pnpm install
|
|
||||||
pnpm run tauri dev
|
|
||||||
```
|
|
||||||
|
|
||||||
Once the commands finish, you'll be viewing a Tauri window with Nuxt.js hot reloading.
|
- [Web Interface](apps/frontend/README.md)
|
||||||
|
- [Desktop App](apps/app/README.md)
|
||||||
|
|
||||||
You can use `pnpm run lint` to find any eslint problems, and `pnpm run fix` to try automatically fixing those problems.
|
## Contributing
|
||||||
|
|
||||||
|
We welcome contributions! Before submitting any contributions, please read our [contributing guidelines](https://docs.modrinth.com/contributing/getting-started/).
|
||||||
|
|
||||||
|
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
|
## License
|
||||||
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](https://github.com/modrinth/theseus/blob/master/LICENSE). However, some files are licensed under a different license.
|
|
||||||
|
|
||||||
Any files depicting the Modrinth branding, including the wrench-in-labyrinth logo, the landing image, and variations thereof, are licensed as follows:
|
All packages in this repository are licensed under their respective licenses. Refer to the LICENSE file in each package for more information.
|
||||||
> All rights reserved. © 2020-2024 Rinth, Inc.
|
|
||||||
|
|
||||||
Forking is permitted under the GPLv3, however do be aware that you must remove all Modrinth branding, including logos, brand colors, background images, or anything else that is related to trademarks or copyrights held by Rinth, Inc.
|
|
||||||
|
|||||||
1
apps/app-frontend/.prettierignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
**/dist
|
||||||
13
apps/app-frontend/COPYING.md
Normal file
@@ -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/\*
|
||||||
22
apps/app-frontend/eslint.config.mjs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { createConfigForNuxt } from '@nuxt/eslint-config/flat'
|
||||||
|
import { fixupPluginRules } from '@eslint/compat'
|
||||||
|
import turboPlugin from 'eslint-plugin-turbo'
|
||||||
|
|
||||||
|
export default createConfigForNuxt().append([
|
||||||
|
{
|
||||||
|
name: 'turbo',
|
||||||
|
plugins: {
|
||||||
|
turbo: fixupPluginRules(turboPlugin),
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'turbo/no-undeclared-env-vars': 'error',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'modrinth',
|
||||||
|
rules: {
|
||||||
|
'vue/html-self-closing': 'off',
|
||||||
|
'vue/multi-word-component-names': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
@@ -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" />
|
||||||
<title>Modrinth App</title>
|
<title>Modrinth App</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/src/assets/stylesheets/global.scss" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
54
apps/app-frontend/package.json
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"name": "@modrinth/app-frontend",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.8.9",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
|
"tsc:check": "vue-tsc --noEmit",
|
||||||
|
"lint": "eslint . && prettier --check .",
|
||||||
|
"fix": "eslint . --fix && prettier --write ."
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@modrinth/assets": "workspace:*",
|
||||||
|
"@modrinth/ui": "workspace:*",
|
||||||
|
"@modrinth/utils": "workspace:*",
|
||||||
|
"@sentry/vue": "^8.27.0",
|
||||||
|
"@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-shell": "^2.0.0-rc.0",
|
||||||
|
"@tauri-apps/plugin-updater": "^2.0.0-rc.0",
|
||||||
|
"@tauri-apps/plugin-window-state": "^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",
|
||||||
|
"posthog-js": "^1.158.2",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/compat": "^1.1.1",
|
||||||
|
"@nuxt/eslint-config": "^0.5.6",
|
||||||
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
|
"autoprefixer": "^10.4.19",
|
||||||
|
"eslint": "^9.9.1",
|
||||||
|
"eslint-config-custom": "workspace:*",
|
||||||
|
"eslint-plugin-turbo": "^2.1.1",
|
||||||
|
"postcss": "^8.4.39",
|
||||||
|
"prettier": "^3.2.5",
|
||||||
|
"sass": "^1.74.1",
|
||||||
|
"tailwindcss": "^3.4.4",
|
||||||
|
"tsconfig": "workspace:*",
|
||||||
|
"typescript": "^5.5.4",
|
||||||
|
"vite": "^5.2.8",
|
||||||
|
"vue-tsc": "^2.1.6"
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@9.4.0"
|
||||||
|
}
|
||||||
6
apps/app-frontend/postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<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,
|
HomeIcon,
|
||||||
@@ -7,12 +7,10 @@ import {
|
|||||||
LibraryIcon,
|
LibraryIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
SettingsIcon,
|
SettingsIcon,
|
||||||
FileIcon,
|
|
||||||
Button,
|
|
||||||
Notifications,
|
|
||||||
XIcon,
|
XIcon,
|
||||||
Card,
|
DownloadIcon,
|
||||||
} from 'omorphia'
|
} from '@modrinth/assets'
|
||||||
|
import { Button, Notifications } from '@modrinth/ui'
|
||||||
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 +21,171 @@ 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, restartApp } 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'
|
||||||
|
import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state'
|
||||||
|
import { renderString } from '@modrinth/utils'
|
||||||
|
import { useFetch } from '@/helpers/fetch.js'
|
||||||
|
import { check } from '@tauri-apps/plugin-updater'
|
||||||
|
|
||||||
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
|
const criticalErrorMessage = ref()
|
||||||
if (os.value !== 'MacOS') appWindow.setDecorations(native_decorations)
|
|
||||||
|
|
||||||
themeStore.setThemeState(theme)
|
onMounted(async () => {
|
||||||
themeStore.collapsedNavigation = collapsed_navigation
|
await useCheckDisableMouseover()
|
||||||
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
|
|
||||||
|
useFetch(
|
||||||
|
`https://api.modrinth.com/appCriticalAnnouncement.json?version=${version}`,
|
||||||
|
'criticalAnnouncements',
|
||||||
|
true,
|
||||||
|
).then((res) => {
|
||||||
|
if (res && res.header && res.body) {
|
||||||
|
criticalErrorMessage.value = res
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
get_opening_command().then(handleCommand)
|
||||||
|
checkUpdates()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 saveWindowState(StateFlags.ALL)
|
||||||
await TauriWindow.getCurrent().close()
|
await getCurrentWindow().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) {
|
||||||
@@ -201,15 +197,10 @@ document.querySelector('body').addEventListener('click', function (e) {
|
|||||||
['http://', 'https://', 'mailto:', 'tel:'].some((v) => target.href.startsWith(v)) &&
|
['http://', 'https://', 'mailto:', 'tel:'].some((v) => target.href.startsWith(v)) &&
|
||||||
!target.classList.contains('router-link-active') &&
|
!target.classList.contains('router-link-active') &&
|
||||||
!target.href.startsWith('http://localhost') &&
|
!target.href.startsWith('http://localhost') &&
|
||||||
!target.href.startsWith('https://tauri.localhost')
|
!target.href.startsWith('https://tauri.localhost') &&
|
||||||
|
!target.href.startsWith('http://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 +225,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 +241,26 @@ 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)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
const updateAvailable = ref(false)
|
||||||
|
async function checkUpdates() {
|
||||||
|
const update = await check()
|
||||||
|
console.log(update)
|
||||||
|
updateAvailable.value = !!update
|
||||||
|
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
checkUpdates()
|
||||||
|
},
|
||||||
|
5 * 1000 * 60,
|
||||||
|
)
|
||||||
|
}
|
||||||
</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>
|
||||||
@@ -322,6 +289,14 @@ command_listener(async (e) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings pages-list">
|
<div class="settings pages-list">
|
||||||
|
<button
|
||||||
|
v-if="updateAvailable"
|
||||||
|
v-tooltip="'Install update'"
|
||||||
|
class="btn btn-outline btn-primary icon-only collapsed-button"
|
||||||
|
@click="restartApp()"
|
||||||
|
>
|
||||||
|
<DownloadIcon />
|
||||||
|
</button>
|
||||||
<Button
|
<Button
|
||||||
v-tooltip="'Create profile'"
|
v-tooltip="'Create profile'"
|
||||||
class="sleek-primary collapsed-button"
|
class="sleek-primary collapsed-button"
|
||||||
@@ -337,6 +312,10 @@ command_listener(async (e) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="view">
|
<div class="view">
|
||||||
|
<div v-if="criticalErrorMessage" class="critical-error-banner" data-tauri-drag-region>
|
||||||
|
<h1>{{ criticalErrorMessage.header }}</h1>
|
||||||
|
<div class="markdown-body" v-html="renderString(criticalErrorMessage.body ?? '')"></div>
|
||||||
|
</div>
|
||||||
<div class="appbar-row">
|
<div class="appbar-row">
|
||||||
<div data-tauri-drag-region class="appbar">
|
<div data-tauri-drag-region class="appbar">
|
||||||
<section class="navigation-controls">
|
<section class="navigation-controls">
|
||||||
@@ -349,22 +328,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 +361,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 +415,7 @@ command_listener(async (e) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.app-container {
|
||||||
--appbar-height: 3.25rem;
|
--appbar-height: 3.25rem;
|
||||||
--sidebar-width: 4.5rem;
|
--sidebar-width: 4.5rem;
|
||||||
|
|
||||||
@@ -451,6 +428,16 @@ command_listener(async (e) => {
|
|||||||
width: calc(100% - var(--sidebar-width));
|
width: calc(100% - var(--sidebar-width));
|
||||||
background-color: var(--color-raised-bg);
|
background-color: var(--color-raised-bg);
|
||||||
|
|
||||||
|
.critical-error-banner {
|
||||||
|
margin-top: -1.25rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: rgba(203, 34, 69, 0.1);
|
||||||
|
border-left: 2px solid var(--color-red);
|
||||||
|
border-bottom: 2px solid var(--color-red);
|
||||||
|
border-right: 2px solid var(--color-red);
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.appbar {
|
.appbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -476,53 +463,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 +526,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 +536,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 +547,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>
|
||||||
|
Before Width: | Height: | Size: 952 B After Width: | Height: | Size: 952 B |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 901 B After Width: | Height: | Size: 901 B |
|
Before Width: | Height: | Size: 757 B After Width: | Height: | Size: 757 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 718 B After Width: | Height: | Size: 718 B |
|
Before Width: | Height: | Size: 962 B After Width: | Height: | Size: 962 B |
|
Before Width: | Height: | Size: 257 B After Width: | Height: | Size: 257 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 415 B After Width: | Height: | Size: 415 B |
|
Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 274 B |
|
Before Width: | Height: | Size: 706 B After Width: | Height: | Size: 706 B |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 924 B After Width: | Height: | Size: 924 B |
|
Before Width: | Height: | Size: 881 B After Width: | Height: | Size: 881 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 315 B After Width: | Height: | Size: 315 B |
|
Before Width: | Height: | Size: 427 B After Width: | Height: | Size: 427 B |
|
Before Width: | Height: | Size: 311 B After Width: | Height: | Size: 311 B |
|
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 326 B |
|
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
|
Before Width: | Height: | Size: 322 B After Width: | Height: | Size: 322 B |
|
Before Width: | Height: | Size: 253 B After Width: | Height: | Size: 253 B |
|
Before Width: | Height: | Size: 315 B After Width: | Height: | Size: 315 B |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 461 B After Width: | Height: | Size: 461 B |
|
Before Width: | Height: | Size: 405 B After Width: | Height: | Size: 405 B |
|
Before Width: | Height: | Size: 449 B After Width: | Height: | Size: 449 B |
|
Before Width: | Height: | Size: 309 B After Width: | Height: | Size: 309 B |
BIN
apps/app-frontend/src/assets/loading/cube.png
Normal file
|
After Width: | Height: | Size: 937 KiB |
@@ -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';
|
||||||
@@ -9,19 +9,16 @@ import {
|
|||||||
TrashIcon,
|
TrashIcon,
|
||||||
StopCircleIcon,
|
StopCircleIcon,
|
||||||
EyeIcon,
|
EyeIcon,
|
||||||
Card,
|
|
||||||
DropdownSelect,
|
|
||||||
SearchIcon,
|
SearchIcon,
|
||||||
XIcon,
|
XIcon,
|
||||||
Button,
|
} from '@modrinth/assets'
|
||||||
formatCategoryHeader,
|
import { 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 { duplicate, remove } from '@/helpers/profile.js'
|
import { duplicate, remove } from '@/helpers/profile.js'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
instances: {
|
instances: {
|
||||||
@@ -38,7 +35,6 @@ const props = defineProps({
|
|||||||
const instanceOptions = ref(null)
|
const instanceOptions = ref(null)
|
||||||
const instanceComponents = ref(null)
|
const instanceComponents = ref(null)
|
||||||
|
|
||||||
const themeStore = useTheming()
|
|
||||||
const currentDeleteInstance = ref(null)
|
const currentDeleteInstance = ref(null)
|
||||||
const confirmModal = ref(null)
|
const confirmModal = ref(null)
|
||||||
|
|
||||||
@@ -130,46 +126,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 +173,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 +182,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,20 +229,19 @@ const filteredResults = computed(() => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<ModalConfirm
|
<ConfirmModalWrapper
|
||||||
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."
|
||||||
:has-to-type="false"
|
:has-to-type="false"
|
||||||
proceed-label="Delete"
|
proceed-label="Delete"
|
||||||
:noblur="!themeStore.advancedRendering"
|
|
||||||
@proceed="deleteProfile"
|
@proceed="deleteProfile"
|
||||||
/>
|
/>
|
||||||
<Card class="header">
|
<Card class="header">
|
||||||
<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>
|
||||||
@@ -11,28 +11,20 @@ import {
|
|||||||
ExternalIcon,
|
ExternalIcon,
|
||||||
EyeIcon,
|
EyeIcon,
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
ModalConfirm,
|
} from '@modrinth/assets'
|
||||||
} from 'omorphia'
|
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
|
||||||
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 { trackEvent } from '@/helpers/analytics'
|
||||||
import { install as pack_install } from '@/helpers/pack.js'
|
|
||||||
import { useTheming } from '@/store/state.js'
|
|
||||||
import { mixpanel_track } from '@/helpers/mixpanel'
|
|
||||||
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,11 +50,8 @@ 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 currentDeleteInstance = ref(null)
|
const currentDeleteInstance = ref(null)
|
||||||
|
|
||||||
async function deleteProfile() {
|
async function deleteProfile() {
|
||||||
@@ -90,23 +79,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 +120,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 +160,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,13 +205,12 @@ onUnmounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ModalConfirm
|
<ConfirmModalWrapper
|
||||||
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."
|
||||||
:has-to-type="false"
|
:has-to-type="false"
|
||||||
proceed-label="Delete"
|
proceed-label="Delete"
|
||||||
:noblur="!themeStore.advancedRendering"
|
|
||||||
@proceed="deleteProfile"
|
@proceed="deleteProfile"
|
||||||
/>
|
/>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -243,7 +219,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 +234,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 +252,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 {
|
||||||
@@ -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,7 +5,7 @@
|
|||||||
v-tooltip.right="'Minecraft accounts'"
|
v-tooltip.right="'Minecraft accounts'"
|
||||||
class="button-base avatar-button"
|
class="button-base avatar-button"
|
||||||
:class="{ expanded: mode === 'expanded' }"
|
:class="{ expanded: mode === 'expanded' }"
|
||||||
@click="showCard = !showCard"
|
@click="toggleMenu"
|
||||||
>
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
:size="mode === 'expanded' ? 'xs' : 'sm'"
|
:size="mode === 'expanded' ? 'xs' : 'sm'"
|
||||||
@@ -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,9 +70,10 @@ 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'
|
||||||
|
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js'
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
mode: {
|
mode: {
|
||||||
@@ -117,7 +119,7 @@ async function login() {
|
|||||||
await refreshValues()
|
await refreshValues()
|
||||||
}
|
}
|
||||||
|
|
||||||
mixpanel_track('AccountLogIn')
|
trackEvent('AccountLogIn')
|
||||||
}
|
}
|
||||||
|
|
||||||
const logout = async (id) => {
|
const logout = async (id) => {
|
||||||
@@ -129,12 +131,12 @@ const logout = async (id) => {
|
|||||||
} else {
|
} else {
|
||||||
emit('change')
|
emit('change')
|
||||||
}
|
}
|
||||||
mixpanel_track('AccountLogOut')
|
trackEvent('AccountLogOut')
|
||||||
}
|
}
|
||||||
|
|
||||||
let showCard = ref(false)
|
const showCard = ref(false)
|
||||||
let card = ref(null)
|
const card = ref(null)
|
||||||
let button = ref(null)
|
const button = ref(null)
|
||||||
const handleClickOutside = (event) => {
|
const handleClickOutside = (event) => {
|
||||||
const elements = document.elementsFromPoint(event.clientX, event.clientY)
|
const elements = document.elementsFromPoint(event.clientX, event.clientY)
|
||||||
if (
|
if (
|
||||||
@@ -143,7 +145,20 @@ const handleClickOutside = (event) => {
|
|||||||
!elements.includes(card.value.$el) &&
|
!elements.includes(card.value.$el) &&
|
||||||
!button.value.contains(event.target)
|
!button.value.contains(event.target)
|
||||||
) {
|
) {
|
||||||
|
toggleMenu(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMenu(override = true) {
|
||||||
|
if (showCard.value || !override) {
|
||||||
|
if (showCard.value) {
|
||||||
|
show_ads_window()
|
||||||
|
}
|
||||||
|
|
||||||
showCard.value = false
|
showCard.value = false
|
||||||
|
} else {
|
||||||
|
hide_ads_window()
|
||||||
|
showCard.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
63
apps/app-frontend/src/components/ui/AddContentButton.vue
Normal file
@@ -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.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>
|
||||||
@@ -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'
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
||||||
|
import { show_ads_window, hide_ads_window } from '@/helpers/ads.js'
|
||||||
|
|
||||||
const emit = defineEmits(['menu-closed', 'option-clicked'])
|
const emit = defineEmits(['menu-closed', 'option-clicked'])
|
||||||
|
|
||||||
@@ -37,6 +38,7 @@ const shown = ref(false)
|
|||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
showMenu: (event, passedItem, passedOptions) => {
|
showMenu: (event, passedItem, passedOptions) => {
|
||||||
|
hide_ads_window()
|
||||||
item.value = passedItem
|
item.value = passedItem
|
||||||
options.value = passedOptions
|
options.value = passedOptions
|
||||||
|
|
||||||
@@ -60,15 +62,18 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
const hideContextMenu = () => {
|
const hideContextMenu = () => {
|
||||||
|
if (shown.value) {
|
||||||
|
show_ads_window()
|
||||||
|
}
|
||||||
shown.value = false
|
shown.value = false
|
||||||
emit('menu-closed')
|
emit('menu-closed')
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Modal, XIcon, IssuesIcon, LogInIcon } from 'omorphia'
|
import { XIcon, HammerIcon, LogInIcon, UpdatedIcon } from '@modrinth/assets'
|
||||||
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'
|
||||||
|
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||||
|
|
||||||
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,7 +20,9 @@ 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'
|
||||||
@@ -36,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'
|
||||||
@@ -58,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) {
|
||||||
@@ -66,10 +93,35 @@ 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">
|
<ModalWrapper 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'">
|
||||||
@@ -124,30 +176,40 @@ async function loginMinecraft() {
|
|||||||
<LogInIcon /> Try signing in again
|
<LogInIcon /> Try signing in again
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
</template>
|
||||||
<p>
|
<template v-if="errorType === 'directory_move'">
|
||||||
If nothing is working and you need help, visit
|
<template v-if="metadata.readOnly">
|
||||||
<a :href="supportLink">our support page</a>
|
<h3>Change directory permissions</h3>
|
||||||
and start a chat using the widget in the bottom right and we will be more than happy to
|
<p>
|
||||||
assist! Make sure to provide the following debug information to the agent:
|
It looks like the Modrinth App is unable to write to the directory you selected.
|
||||||
</p>
|
Please adjust the permissions of the directory and try again or cancel the directory
|
||||||
<details>
|
change.
|
||||||
<summary>Debug information</summary>
|
</p>
|
||||||
{{ error.message ?? error }}
|
</template>
|
||||||
</details>
|
<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>
|
||||||
|
</div>
|
||||||
</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
|
||||||
@@ -161,16 +223,56 @@ 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>Ensuring 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" @clicdck="errorModal.hide()"><XIcon /> Close</button>
|
<button v-if="closable" class="btn" @click="errorModal.hide()"><XIcon /> Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</ModalWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@@ -190,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 {
|
||||||
@@ -222,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>
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Button, Checkbox, Modal, XIcon, PlusIcon } from 'omorphia'
|
import { XIcon, PlusIcon } from '@modrinth/assets'
|
||||||
|
import { Button, Checkbox } 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 ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
instance: {
|
instance: {
|
||||||
@@ -22,15 +23,13 @@ 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([])
|
||||||
const folders = ref([])
|
const folders = ref([])
|
||||||
const showingFiles = ref(false)
|
const showingFiles = ref(false)
|
||||||
|
|
||||||
const themeStore = useTheming()
|
|
||||||
|
|
||||||
const initFiles = async () => {
|
const initFiles = async () => {
|
||||||
const newFolders = new Map()
|
const newFolders = new Map()
|
||||||
const sep = '/'
|
const sep = '/'
|
||||||
@@ -49,9 +48,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 !== '') {
|
||||||
@@ -105,14 +104,14 @@ const exportPack = async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal ref="exportModal" header="Export modpack" :noblur="!themeStore.advancedRendering">
|
<ModalWrapper ref="exportModal" header="Export modpack">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="labeled_input">
|
<div class="labeled_input">
|
||||||
<p>Modpack Name</p>
|
<p>Modpack Name</p>
|
||||||
<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 +121,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>
|
||||||
@@ -207,7 +206,7 @@ const exportPack = async () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</ModalWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
259
apps/app-frontend/src/components/ui/Instance.vue
Normal file
@@ -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>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Modal ref="modal" header="Create instance" :noblur="!themeStore.advancedRendering">
|
<ModalWrapper ref="modal" header="Create instance">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<Chips v-model="creationType" :items="['custom', 'from file', 'import from launcher']" />
|
<Chips v-model="creationType" :items="['custom', 'from file', 'import from launcher']" />
|
||||||
</div>
|
</div>
|
||||||
@@ -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>
|
||||||
@@ -193,42 +193,31 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</ModalWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||||
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, 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 { listen } from '@tauri-apps/api/event'
|
|
||||||
import { install_from_file } from '@/helpers/pack.js'
|
import { install_from_file } from '@/helpers/pack.js'
|
||||||
import {
|
import {
|
||||||
get_default_launcher_path,
|
get_default_launcher_path,
|
||||||
@@ -236,8 +225,7 @@ import {
|
|||||||
import_instance,
|
import_instance,
|
||||||
} from '@/helpers/import.js'
|
} from '@/helpers/import.js'
|
||||||
import ProgressBar from '@/components/ui/ProgressBar.vue'
|
import ProgressBar from '@/components/ui/ProgressBar.vue'
|
||||||
|
import { getCurrentWebview } from '@tauri-apps/api/webview'
|
||||||
const themeStore = useTheming()
|
|
||||||
|
|
||||||
const profile_name = ref('')
|
const profile_name = ref('')
|
||||||
const game_version = ref('')
|
const game_version = ref('')
|
||||||
@@ -267,20 +255,22 @@ defineExpose({
|
|||||||
isShowing.value = true
|
isShowing.value = true
|
||||||
modal.value.show()
|
modal.value.show()
|
||||||
|
|
||||||
unlistener.value = await listen('tauri://file-drop', async (event) => {
|
unlistener.value = await getCurrentWebview().onDragDropEvent(async (event) => {
|
||||||
// Only if modal is showing
|
// Only if modal is showing
|
||||||
if (!isShowing.value) return
|
if (!isShowing.value) return
|
||||||
|
if (event.payload.type !== 'drop') return
|
||||||
if (creationType.value !== 'from file') return
|
if (creationType.value !== 'from file') return
|
||||||
hide()
|
hide()
|
||||||
if (event.payload && event.payload.length > 0 && event.payload[0].endsWith('.mrpack')) {
|
const { paths } = event.payload
|
||||||
await install_from_file(event.payload[0]).catch(handleError)
|
if (paths && paths.length > 0 && paths[0].endsWith('.mrpack')) {
|
||||||
mixpanel_track('InstanceCreate', {
|
await install_from_file(paths[0]).catch(handleError)
|
||||||
|
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,
|
||||||
@@ -381,7 +371,7 @@ const create_instance = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const upload_icon = async () => {
|
const upload_icon = async () => {
|
||||||
icon.value = await open({
|
const res = await open({
|
||||||
multiple: false,
|
multiple: false,
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
@@ -391,8 +381,10 @@ const upload_icon = async () => {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
icon.value = res.path ?? res
|
||||||
|
|
||||||
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 = () => {
|
||||||
@@ -427,9 +419,9 @@ const openFile = async () => {
|
|||||||
const newProject = await open({ multiple: false })
|
const newProject = await open({ multiple: false })
|
||||||
if (!newProject) return
|
if (!newProject) return
|
||||||
hide()
|
hide()
|
||||||
await install_from_file(newProject).catch(handleError)
|
await install_from_file(newProject.path ?? newProject).catch(handleError)
|
||||||
|
|
||||||
mixpanel_track('InstanceCreate', {
|
trackEvent('InstanceCreate', {
|
||||||
source: 'CreationModalFileOpen',
|
source: 'CreationModalFileOpen',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -472,7 +464,7 @@ const promises = profileOptions.value.map(async (option) => {
|
|||||||
option.name,
|
option.name,
|
||||||
instances.map((name) => ({ name, selected: false })),
|
instances.map((name) => ({ name, selected: false })),
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Allow failure silently
|
// Allow failure silently
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Modal ref="detectJavaModal" header="Select java version" :noblur="!themeStore.advancedRendering">
|
<ModalWrapper ref="detectJavaModal" header="Select java version">
|
||||||
<div class="auto-detect-modal">
|
<div class="auto-detect-modal">
|
||||||
<div class="table">
|
<div class="table">
|
||||||
<div class="table-row table-head">
|
<div class="table-row table-head">
|
||||||
@@ -32,17 +32,16 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</ModalWrapper>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Modal, PlusIcon, CheckIcon, Button, XIcon } from 'omorphia'
|
import { PlusIcon, CheckIcon, XIcon } from '@modrinth/assets'
|
||||||
|
import { 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 { trackEvent } from '@/helpers/analytics'
|
||||||
import { useTheming } from '@/store/theme.js'
|
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||||
|
|
||||||
const themeStore = useTheming()
|
|
||||||
|
|
||||||
const chosenInstallOptions = ref([])
|
const chosenInstallOptions = ref([])
|
||||||
const detectJavaModal = ref(null)
|
const detectJavaModal = ref(null)
|
||||||
@@ -52,9 +51,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 +65,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,
|
||||||
})
|
})
|
||||||
@@ -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,
|
||||||
})
|
})
|
||||||
@@ -124,20 +124,19 @@ async function testJava() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleJavaFileInput() {
|
async function handleJavaFileInput() {
|
||||||
let filePath = await open()
|
const filePath = await open()
|
||||||
|
|
||||||
if (filePath) {
|
if (filePath) {
|
||||||
let result = await get_jre(filePath)
|
let result = await get_jre(filePath.path ?? filePath)
|
||||||
if (!result) {
|
if (!result) {
|
||||||
result = {
|
result = {
|
||||||
path: filePath,
|
path: filePath.path ?? filePath,
|
||||||
version: props.version.toString(),
|
version: props.version.toString(),
|
||||||
architecture: 'x86',
|
architecture: 'x86',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mixpanel_track('JavaManualSelect', {
|
trackEvent('JavaManualSelect', {
|
||||||
path: filePath,
|
|
||||||
version: props.version,
|
version: props.version,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -150,7 +149,7 @@ async function autoDetect() {
|
|||||||
if (!props.compact) {
|
if (!props.compact) {
|
||||||
detectJavaModal.value.show(props.version, props.modelValue)
|
detectJavaModal.value.show(props.version, props.modelValue)
|
||||||
} else {
|
} else {
|
||||||
let versions = await find_filtered_jres(props.version).catch(handleError)
|
const versions = await find_filtered_jres(props.version).catch(handleError)
|
||||||
if (versions.length > 0) {
|
if (versions.length > 0) {
|
||||||
emit('update:modelValue', versions[0])
|
emit('update:modelValue', versions[0])
|
||||||
}
|
}
|
||||||
@@ -162,7 +161,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 +169,7 @@ async function reinstallJava() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mixpanel_track('JavaReInstall', {
|
trackEvent('JavaReInstall', {
|
||||||
path: path,
|
path: path,
|
||||||
version: props.version,
|
version: props.version,
|
||||||
})
|
})
|
||||||
@@ -205,6 +203,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 {
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Button, Modal, CheckIcon, Badge } from 'omorphia'
|
import { CheckIcon } from '@modrinth/assets'
|
||||||
|
import { Button, Badge } from '@modrinth/ui'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useTheming } from '@/store/theme'
|
|
||||||
import { update_managed_modrinth_version } from '@/helpers/profile'
|
import { update_managed_modrinth_version } from '@/helpers/profile'
|
||||||
import { releaseColor } from '@/helpers/utils'
|
import { releaseColor } from '@/helpers/utils'
|
||||||
import { SwapIcon } from '@/assets/icons/index.js'
|
import { SwapIcon } from '@/assets/icons/index.js'
|
||||||
|
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
versions: {
|
versions: {
|
||||||
@@ -28,12 +29,10 @@ 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)
|
||||||
|
|
||||||
const themeStore = useTheming()
|
|
||||||
|
|
||||||
const switchVersion = async (versionId) => {
|
const switchVersion = async (versionId) => {
|
||||||
inProgress.value = true
|
inProgress.value = true
|
||||||
await update_managed_modrinth_version(props.instance.path, versionId)
|
await update_managed_modrinth_version(props.instance.path, versionId)
|
||||||
@@ -42,14 +41,13 @@ const switchVersion = async (versionId) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal
|
<ModalWrapper
|
||||||
ref="modpackVersionModal"
|
ref="modpackVersionModal"
|
||||||
class="modpack-version-modal"
|
class="modpack-version-modal"
|
||||||
header="Change modpack version"
|
header="Change modpack version"
|
||||||
: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" />
|
||||||
@@ -110,7 +108,7 @@ const switchVersion = async (versionId) => {
|
|||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</ModalWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@@ -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>
|
||||||
|
|
||||||
126
apps/app-frontend/src/components/ui/PromotionWrapper.vue
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, onUnmounted } from 'vue'
|
||||||
|
import { get as getCreds } from '@/helpers/mr_auth.js'
|
||||||
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
import { get_user } from '@/helpers/cache.js'
|
||||||
|
import { ChevronRightIcon } from '@modrinth/assets'
|
||||||
|
import { init_ads_window, open_ads_link, record_ads_click } from '@/helpers/ads.js'
|
||||||
|
import { listen } from '@tauri-apps/api/event'
|
||||||
|
|
||||||
|
const showAd = ref(true)
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
scroll() {
|
||||||
|
updateAdPosition()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const adsWrapper = ref(null)
|
||||||
|
let resizeObserver
|
||||||
|
let scrollHandler
|
||||||
|
let intersectionObserver
|
||||||
|
let mutationObserver
|
||||||
|
onMounted(() => {
|
||||||
|
if (showAd.value) {
|
||||||
|
updateAdPosition(true)
|
||||||
|
|
||||||
|
resizeObserver = new ResizeObserver(() => updateAdPosition())
|
||||||
|
resizeObserver.observe(adsWrapper.value)
|
||||||
|
|
||||||
|
intersectionObserver = new IntersectionObserver(() => updateAdPosition())
|
||||||
|
intersectionObserver.observe(adsWrapper.value)
|
||||||
|
|
||||||
|
mutationObserver = new MutationObserver(() => updateAdPosition())
|
||||||
|
mutationObserver.observe(adsWrapper.value, { attributes: true, childList: true, subtree: true })
|
||||||
|
|
||||||
|
// Add scroll event listener
|
||||||
|
scrollHandler = () => {
|
||||||
|
requestAnimationFrame(() => updateAdPosition())
|
||||||
|
}
|
||||||
|
window.addEventListener('scroll', scrollHandler, { passive: true })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function updateAdPosition(overrideShown = false) {
|
||||||
|
if (adsWrapper.value) {
|
||||||
|
const rect = adsWrapper.value.getBoundingClientRect()
|
||||||
|
|
||||||
|
let y = rect.top + window.scrollY
|
||||||
|
let height = rect.bottom - rect.top
|
||||||
|
|
||||||
|
// Prevent ad from overlaying the app bar
|
||||||
|
if (y <= 52) {
|
||||||
|
y = 52
|
||||||
|
height = rect.bottom - 52
|
||||||
|
|
||||||
|
if (height < 0) {
|
||||||
|
height = 0
|
||||||
|
y = -1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init_ads_window(rect.left + window.scrollX, y, rect.right - rect.left, height, overrideShown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openPlusLink() {
|
||||||
|
await record_ads_click()
|
||||||
|
await open_ads_link('https://modrinth.com/plus', 'https://modrinth.com')
|
||||||
|
}
|
||||||
|
|
||||||
|
const unlisten = await listen('ads-scroll', (event) => {
|
||||||
|
if (adsWrapper.value) {
|
||||||
|
adsWrapper.value.parentNode.scrollTop += event.payload.scroll
|
||||||
|
updateAdPosition()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect()
|
||||||
|
}
|
||||||
|
if (intersectionObserver) {
|
||||||
|
intersectionObserver.disconnect()
|
||||||
|
}
|
||||||
|
if (mutationObserver) {
|
||||||
|
mutationObserver.disconnect()
|
||||||
|
}
|
||||||
|
if (scrollHandler) {
|
||||||
|
window.removeEventListener('scroll', scrollHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
unlisten()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-if="showAd"
|
||||||
|
ref="adsWrapper"
|
||||||
|
class="ad-parent relative mb-3 flex w-full justify-center rounded-2xl bg-bg-raised cursor-pointer"
|
||||||
|
>
|
||||||
|
<div class="flex max-h-[250px] min-h-[250px] min-w-[300px] max-w-[300px] flex-col gap-4 p-6">
|
||||||
|
<p class="m-0 text-2xl font-bold text-contrast">75% of ad revenue goes to creators</p>
|
||||||
|
<button
|
||||||
|
class="mt-auto items-center gap-1 text-purple hover:underline bg-transparent border-none text-left cursor-pointer outline-none"
|
||||||
|
@click="openPlusLink"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Support creators and Modrinth ad-free with
|
||||||
|
<span class="font-bold">Modrinth+</span>
|
||||||
|
</span>
|
||||||
|
<ChevronRightIcon class="relative top-[3px] h-5 w-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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>
|
||||||
|
|
||||||
224
apps/app-frontend/src/components/ui/SplashScreen.vue
Normal file
@@ -1,82 +1,48 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Modal, Button } from 'omorphia'
|
import { 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'
|
import ModalWrapper from '@/components/ui/modal/ModalWrapper.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>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal ref="confirmModal" :header="`Install ${project?.title}`">
|
<ModalWrapper ref="confirmModal" :header="`Install ${project?.title}`">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<SearchCard
|
<SearchCard
|
||||||
:project="project"
|
:project="project"
|
||||||
@@ -95,8 +61,7 @@ async function install() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</ModalWrapper>
|
||||||
<ModInstallModal ref="modInstallModal" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Modal
|
<ModalWrapper ref="incompatibleModal" header="Incompatibility warning" :on-hide="onInstall">
|
||||||
ref="incompatibleModal"
|
|
||||||
header="Incompatibility warning"
|
|
||||||
:noblur="!themeStore.advancedRendering"
|
|
||||||
>
|
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>
|
<p>
|
||||||
This {{ versions?.length > 0 ? 'project' : 'version' }} is not compatible with the instance
|
This {{ versions?.length > 0 ? 'project' : 'version' }} is not compatible with the instance
|
||||||
@@ -12,13 +8,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"
|
||||||
@@ -52,50 +46,42 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</ModalWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Button, Modal, XIcon, DownloadIcon, DropdownSelect, formatCategory } from 'omorphia'
|
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||||
|
import { XIcon, DownloadIcon } from '@modrinth/assets'
|
||||||
|
import { Button, 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 } from '@/store/state.js'
|
||||||
import { mixpanel_track } from '@/helpers/mixpanel'
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
|
|
||||||
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 = () => {}
|
const 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 +89,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',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1,54 +1,56 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Button, Modal, XIcon, DownloadIcon } from 'omorphia'
|
import { XIcon, DownloadIcon } from '@modrinth/assets'
|
||||||
|
import { Button } 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 { handleError } from '@/store/state.js'
|
import { handleError } from '@/store/state.js'
|
||||||
|
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||||
|
|
||||||
const themeStore = useTheming()
|
const versionId = ref()
|
||||||
|
const project = ref()
|
||||||
const version = ref('')
|
|
||||||
const title = ref('')
|
|
||||||
const projectId = ref('')
|
|
||||||
const icon = ref('')
|
|
||||||
const confirmModal = ref(null)
|
const confirmModal = ref(null)
|
||||||
const installing = ref(false)
|
const installing = ref(false)
|
||||||
|
|
||||||
|
const 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">
|
<ModalWrapper ref="confirmModal" header="Are you sure?" :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">
|
||||||
@@ -58,7 +60,7 @@ async function install() {
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</ModalWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||